]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/commitdiff
XFRM: Mobile IPv6 route optimization support.
authorMasahide NAKAMURA <nakam@linux-ipv6.org>
Tue, 5 Dec 2006 10:15:47 +0000 (19:15 +0900)
committerStephen Hemminger <shemminger@osdl.org>
Tue, 5 Dec 2006 18:03:32 +0000 (10:03 -0800)
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>
ip/ipxfrm.c
ip/xfrm.h
ip/xfrm_policy.c
ip/xfrm_state.c

index 79fc133199d49705f2d5048ae857087443153091..7c9fd0b63721f49d25af13e1141b7b8419023afd 100644 (file)
@@ -94,6 +94,19 @@ int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits)
        return 0;
 }
 
+int xfrm_xfrmproto_is_ipsec(__u8 proto)
+{
+       return (proto ==  IPPROTO_ESP ||
+               proto ==  IPPROTO_AH  ||
+               proto ==  IPPROTO_COMP);
+}
+
+int xfrm_xfrmproto_is_ro(__u8 proto)
+{
+       return (proto ==  IPPROTO_ROUTING ||
+               proto ==  IPPROTO_DSTOPTS);
+}
+
 struct typeent {
        const char *t_name;
        int t_type;
@@ -101,6 +114,7 @@ struct typeent {
 
 static const struct typeent xfrmproto_types[]= {
        { "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, { "comp", IPPROTO_COMP },
+       { "route2", IPPROTO_ROUTING }, { "hao", IPPROTO_DSTOPTS },
        { NULL, -1 }
 };
 
@@ -276,13 +290,19 @@ void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
 
        fprintf(fp, "mode ");
        switch (mode) {
-       case 0:
+       case XFRM_MODE_TRANSPORT:
                fprintf(fp, "transport");
                break;
-       case 1:
+       case XFRM_MODE_TUNNEL:
                fprintf(fp, "tunnel");
                break;
-       case 4:
+       case XFRM_MODE_ROUTEOPTIMIZATION:
+               fprintf(fp, "ro");
+               break;
+       case XFRM_MODE_IN_TRIGGER:
+               fprintf(fp, "in_trigger");
+               break;
+       case XFRM_MODE_BEET:
                fprintf(fp, "beet");
                break;
        default:
@@ -643,6 +663,48 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
                xfrm_tmpl_print((struct xfrm_user_tmpl *) RTA_DATA(rta),
                                RTA_PAYLOAD(rta), family, fp, prefix);
        }
+
+       if (tb[XFRMA_COADDR]) {
+               char abuf[256];
+               xfrm_address_t *coa;
+
+               if (prefix)
+                       fprintf(fp, prefix);
+               fprintf(fp, "coa ");
+
+               coa = (xfrm_address_t *)RTA_DATA(tb[XFRMA_COADDR]);
+
+               if (RTA_PAYLOAD(tb[XFRMA_COADDR]) < sizeof(*coa)) {
+                       fprintf(fp, "(ERROR truncated)");
+                       fprintf(fp, "%s", _SL_);
+                       return;
+               }
+
+               memset(abuf, '\0', sizeof(abuf));
+               fprintf(fp, "%s",
+                       rt_addr_n2a(family, sizeof(*coa), coa, 
+                                   abuf, sizeof(abuf)));
+               fprintf(fp, "%s", _SL_);
+       }
+
+       if (tb[XFRMA_LASTUSED]) {
+               __u64 lastused;
+
+               if (prefix)
+                       fprintf(fp, prefix);
+               fprintf(fp, "lastused ");
+
+               if (RTA_PAYLOAD(tb[XFRMA_LASTUSED]) < sizeof(lastused)) {
+                       fprintf(fp, "(ERROR truncated)");
+                       fprintf(fp, "%s", _SL_);
+                       return;
+               }
+
+               lastused = *(__u64 *)RTA_DATA(tb[XFRMA_LASTUSED]);
+
+               fprintf(fp, "%s", strxf_time(lastused));
+               fprintf(fp, "%s", _SL_);
+       }
 }
 
 static int xfrm_selector_iszero(struct xfrm_selector *s)
@@ -659,12 +721,13 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
                            const char *title)
 {
        char buf[STRBUF_SIZE];
+       int force_spi = xfrm_xfrmproto_is_ipsec(xsinfo->id.proto);
 
        memset(buf, '\0', sizeof(buf));
 
        xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode,
-                          xsinfo->reqid, xsinfo->family, 1, fp, prefix,
-                          title);
+                          xsinfo->reqid, xsinfo->family, force_spi, fp,
+                          prefix, title);
 
        if (prefix)
                STRBUF_CAT(buf, prefix);
@@ -680,6 +743,7 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
                fprintf(fp, "flag ");
                XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_NOECN, "noecn");
                XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_DECAP_DSCP, "decap-dscp");
+               XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_WILDRECV, "wildrecv");
                if (flags)
                        fprintf(fp, "%x", flags);
                if (show_stats > 0)
@@ -884,11 +948,15 @@ int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
        char **argv = *argvp;
 
        if (matches(*argv, "transport") == 0)
-               *mode = 0;
+               *mode = XFRM_MODE_TRANSPORT;
        else if (matches(*argv, "tunnel") == 0)
-               *mode = 1;
+               *mode = XFRM_MODE_TUNNEL;
+       else if (matches(*argv, "ro") == 0)
+               *mode = XFRM_MODE_ROUTEOPTIMIZATION;
+       else if (matches(*argv, "in_trigger") == 0)
+               *mode = XFRM_MODE_IN_TRIGGER;
        else if (matches(*argv, "beet") == 0)
-               *mode = 4;
+               *mode = XFRM_MODE_BEET;
        else
                invarg("\"MODE\" is invalid", *argv);
 
index 7a53e59c1dceb6070bbfdd72de33c5a27236c9d5..51ffa4bee4d93268400f5858cabe5883515dffa2 100644 (file)
--- a/ip/xfrm.h
+++ b/ip/xfrm.h
@@ -110,6 +110,8 @@ int do_xfrm_policy(int argc, char **argv);
 int do_xfrm_monitor(int argc, char **argv);
 
 int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits);
+int xfrm_xfrmproto_is_ipsec(__u8 proto);
+int xfrm_xfrmproto_is_ro(__u8 proto);
 int xfrm_xfrmproto_getbyname(char *name);
 int xfrm_algotype_getbyname(char *name);
 const char *strxf_xfrmproto(__u8 proto);
index 6be7bfd6c13979ad159599cb1e7a1b281ea93033..44aff796971b5aa552733ef18be4409d270bee23 100644 (file)
@@ -82,12 +82,13 @@ static void usage(void)
        fprintf(stderr, "TMPL := ID [ mode MODE ] [ reqid REQID ] [ level LEVEL ]\n");
        fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n");
 
-       //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n");
        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, " ]\n");
+       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, "MODE := [ transport | tunnel | beet ](default=transport)\n");
        //fprintf(stderr, "REQID - number(default=0)\n");
index bb073c0eb00bb99728a12654ac5c5ecd3748b0a6..57dc4b5231b7b411911c111283fe37fc22cf54bf 100644 (file)
@@ -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) {