summaryrefslogtreecommitdiffstats
path: root/ip/xfrm_state.c
diff options
context:
space:
mode:
authorMasahide NAKAMURA <nakam@linux-ipv6.org>2006-12-05 19:15:47 +0900
committerStephen Hemminger <shemminger@osdl.org>2006-12-05 10:03:32 -0800
commit7ea4f5d33d27b23a3127b0b6ec46d0b4821d9431 (patch)
tree9faeef97144071165e47c3af880b02ca21c1a905 /ip/xfrm_state.c
parent972938e9e685156b97413d17ad8993de61fdd1b9 (diff)
XFRM: Mobile IPv6 route optimization support.
To support Mobile IPv6 RO, the following extension is included: o Use XFRM_MODE_XXX macro instead of magic number o New attribute option for all state: source address for deleting or getting message o New attribute options for RO: care-of address, last-used timestamp and wild-receive flag Note: Flush command like `ip xfrm state flush` is to remove all XFRM state. It has been effected for IPsec SAD but with this patch it flushes both IPsec SAD and Mobile IPv6 RO states. To make only IPsec SA flush, it is recommanded to specify each XFRM protocol like below: `ip x s f proto esp ; ip x s f proto ah ; ip x s f proto comp` Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org> Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Diffstat (limited to 'ip/xfrm_state.c')
-rw-r--r--ip/xfrm_state.c107
1 files changed, 87 insertions, 20 deletions
diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
index bb073c0e..57dc4b52 100644
--- a/ip/xfrm_state.c
+++ b/ip/xfrm_state.c
@@ -55,7 +55,7 @@ static void usage(void) __attribute__((noreturn));
static void usage(void)
{
- fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
+ fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ XFRM_OPT ] [ mode MODE ]\n");
fprintf(stderr, " [ reqid REQID ] [ seq SEQ ] [ replay-window SIZE ] [ flag FLAG-LIST ]\n");
fprintf(stderr, " [ encap ENCAP ] [ sel SELECTOR ] [ LIMIT-LIST ]\n");
fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ reqid REQID ] [ seq SEQ ]\n");
@@ -70,16 +70,18 @@ static void usage(void)
fprintf(stderr, "XFRM_PROTO := [ ");
fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
- fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_COMP));
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
+ fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
+ fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_DSTOPTS));
fprintf(stderr, "]\n");
//fprintf(stderr, "SPI - security parameter index(default=0)\n");
- fprintf(stderr, "MODE := [ transport | tunnel | beet ](default=transport)\n");
+ fprintf(stderr, "MODE := [ transport | tunnel | ro | beet ](default=transport)\n");
//fprintf(stderr, "REQID - number(default=0)\n");
fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
- fprintf(stderr, "FLAG := [ noecn | decap-dscp ]\n");
+ fprintf(stderr, "FLAG := [ noecn | decap-dscp | wildrecv ]\n");
fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n");
fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n");
@@ -200,6 +202,8 @@ static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
*flags |= XFRM_STATE_NOECN;
else if (strcmp(*argv, "decap-dscp") == 0)
*flags |= XFRM_STATE_DECAP_DSCP;
+ else if (strcmp(*argv, "wildrecv") == 0)
+ *flags |= XFRM_STATE_WILDRECV;
else {
PREV_ARG(); /* back track */
break;
@@ -231,6 +235,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
char *ealgop = NULL;
char *aalgop = NULL;
char *calgop = NULL;
+ char *coap = NULL;
memset(&req, 0, sizeof(req));
@@ -285,6 +290,27 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
(void *)&encap, sizeof(encap));
+ } else if (strcmp(*argv, "coa") == 0) {
+ inet_prefix coa;
+ xfrm_address_t xcoa;
+
+ if (coap)
+ duparg("coa", *argv);
+ coap = *argv;
+
+ NEXT_ARG();
+
+ get_prefix(&coa, *argv, preferred_family);
+ if (coa.family == AF_UNSPEC)
+ invarg("\"coa\" address family is AF_UNSPEC", *argv);
+ if (coa.bytelen > sizeof(xcoa))
+ invarg("\"coa\" address length is too large", *argv);
+
+ memset(&xcoa, 0, sizeof(xcoa));
+ memcpy(&xcoa, &coa.data, coa.bytelen);
+
+ addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR,
+ (void *)&xcoa, sizeof(xcoa));
} else {
/* try to assume ALGO */
int type = xfrm_algotype_getbyname(*argv);
@@ -364,18 +390,56 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
exit(1);
}
+ switch (req.xsinfo.mode) {
+ case XFRM_MODE_TRANSPORT:
+ case XFRM_MODE_TUNNEL:
+ if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit(1);
+ }
+ break;
+ case XFRM_MODE_ROUTEOPTIMIZATION:
+ case XFRM_MODE_IN_TRIGGER:
+ if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit(1);
+ }
+ if (req.xsinfo.id.spi != 0) {
+ fprintf(stderr, "\"spi\" must be 0 with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit(1);
+ }
+ break;
+ default:
+ break;
+ }
+
if (ealgop || aalgop || calgop) {
- if (req.xsinfo.id.proto != IPPROTO_ESP &&
- req.xsinfo.id.proto != IPPROTO_AH &&
- req.xsinfo.id.proto != IPPROTO_COMP) {
- fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
+ if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit(1);
+ }
+ } else {
+ if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"ALGO\" is required with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
+ exit (1);
+ }
+ }
+
+ if (coap) {
+ if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"coa\" is invalid with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
exit(1);
}
} else {
- if (req.xsinfo.id.proto == IPPROTO_ESP ||
- req.xsinfo.id.proto == IPPROTO_AH ||
- req.xsinfo.id.proto == IPPROTO_COMP) {
- fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
+ if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
+ fprintf(stderr, "\"coa\" is required with proto=%s\n",
+ strxf_xfrmproto(req.xsinfo.id.proto));
exit (1);
}
}
@@ -645,6 +709,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
struct {
struct nlmsghdr n;
struct xfrm_usersa_id xsid;
+ char buf[RTA_BUF_SIZE];
} req;
struct xfrm_id id;
char *idp = NULL;
@@ -657,12 +722,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
req.xsid.family = preferred_family;
while (argc > 0) {
- /*
- * XXX: Source address is not used and ignore it to follow
- * XXX: a manner of setkey e.g. in the case of deleting/getting
- * XXX: message of IPsec SA.
- */
- xfrm_address_t ignore_saddr;
+ xfrm_address_t saddr;
if (idp)
invarg("unknown", *argv);
@@ -670,13 +730,17 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
/* ID */
memset(&id, 0, sizeof(id));
- xfrm_id_parse(&ignore_saddr, &id, &req.xsid.family, 0,
+ memset(&saddr, 0, sizeof(saddr));
+ xfrm_id_parse(&saddr, &id, &req.xsid.family, 0,
&argc, &argv);
memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
req.xsid.spi = id.spi;
req.xsid.proto = id.proto;
+ addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
+ (void *)&saddr, sizeof(saddr));
+
argc--; argv++;
}
@@ -756,6 +820,9 @@ static int xfrm_state_keep(const struct sockaddr_nl *who,
xsid->spi = xsinfo->id.spi;
xsid->proto = xsinfo->id.proto;
+ addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr,
+ sizeof(xsid->daddr));
+
xb->offset += new_n->nlmsg_len;
xb->nlmsg_count ++;
@@ -880,7 +947,7 @@ static int xfrm_state_flush(int argc, char **argv)
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
- req.xsf.proto = IPSEC_PROTO_ANY;
+ req.xsf.proto = 0;
while (argc > 0) {
if (strcmp(*argv, "proto") == 0) {