]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/xfrm_state.c
libnetlink: add size argument to rtnl_talk
[mirror_iproute2.git] / ip / xfrm_state.c
index 14f2fa7677b11f8bee9d66a908a936b24864241a..d2831d007ced4a1d8e45051c99c7dbfb2ae99f3e 100644 (file)
@@ -58,6 +58,7 @@ static void usage(void)
        fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
        fprintf(stderr, "        [ mark MARK [ mask MASK ] ] [ reqid REQID ] [ seq SEQ ]\n");
        fprintf(stderr, "        [ replay-window SIZE ] [ replay-seq SEQ ] [ replay-oseq SEQ ]\n");
+       fprintf(stderr, "        [ replay-seq-hi SEQ ] [ replay-oseq-hi SEQ ]\n");
        fprintf(stderr, "        [ flag FLAG-LIST ] [ sel SELECTOR ] [ LIMIT-LIST ] [ encap ENCAP ]\n");
        fprintf(stderr, "        [ coa ADDR[/PLEN] ] [ ctx CTX ] [ extra-flag EXTRA-FLAG-LIST ]\n");
        fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n");
@@ -87,7 +88,7 @@ static void usage(void)
        fprintf(stderr, " ALGO-NAME\n");
        fprintf(stderr, "MODE := transport | tunnel | beet | ro | in_trigger\n");
        fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
-       fprintf(stderr, "FLAG := noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4\n");
+       fprintf(stderr, "FLAG := noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4 | esn\n");
        fprintf(stderr, "EXTRA-FLAG-LIST := [ EXTRA-FLAG-LIST ] EXTRA-FLAG\n");
        fprintf(stderr, "EXTRA-FLAG := dont-encap-dscp\n");
        fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n");
@@ -214,6 +215,8 @@ static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
                                *flags |= XFRM_STATE_AF_UNSPEC;
                        else if (strcmp(*argv, "align4") == 0)
                                *flags |= XFRM_STATE_ALIGN4;
+                       else if (strcmp(*argv, "esn") == 0)
+                               *flags |= XFRM_STATE_ESN;
                        else {
                                PREV_ARG(); /* back track */
                                break;
@@ -268,11 +271,14 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
 {
        struct rtnl_handle rth;
        struct {
-               struct nlmsghdr         n;
+               struct nlmsghdr n;
                struct xfrm_usersa_info xsinfo;
-               char                    buf[RTA_BUF_SIZE];
+               char                    buf[RTA_BUF_SIZE];
        } req;
        struct xfrm_replay_state replay;
+       struct xfrm_replay_state_esn replay_esn;
+       __u32 replay_window = 0;
+       __u32 seq = 0, oseq = 0, seq_hi = 0, oseq_hi = 0;
        char *idp = NULL;
        char *aeadop = NULL;
        char *ealgop = NULL;
@@ -289,6 +295,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
 
        memset(&req, 0, sizeof(req));
        memset(&replay, 0, sizeof(replay));
+       memset(&replay_esn, 0, sizeof(replay_esn));
        memset(&ctx, 0, sizeof(ctx));
 
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
@@ -315,16 +322,24 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
                        xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
                } else if (strcmp(*argv, "replay-window") == 0) {
                        NEXT_ARG();
-                       if (get_u8(&req.xsinfo.replay_window, *argv, 0))
+                       if (get_u32(&replay_window, *argv, 0))
                                invarg("value after \"replay-window\" is invalid", *argv);
                } else if (strcmp(*argv, "replay-seq") == 0) {
                        NEXT_ARG();
-                       if (get_u32(&replay.seq, *argv, 0))
+                       if (get_u32(&seq, *argv, 0))
                                invarg("value after \"replay-seq\" is invalid", *argv);
+               } else if (strcmp(*argv, "replay-seq-hi") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&seq_hi, *argv, 0))
+                               invarg("value after \"replay-seq-hi\" is invalid", *argv);
                } else if (strcmp(*argv, "replay-oseq") == 0) {
                        NEXT_ARG();
-                       if (get_u32(&replay.oseq, *argv, 0))
+                       if (get_u32(&oseq, *argv, 0))
                                invarg("value after \"replay-oseq\" is invalid", *argv);
+               } else if (strcmp(*argv, "replay-oseq-hi") == 0) {
+                       NEXT_ARG();
+                       if (get_u32(&oseq_hi, *argv, 0))
+                               invarg("value after \"replay-oseq-hi\" is invalid", *argv);
                } else if (strcmp(*argv, "flag") == 0) {
                        NEXT_ARG();
                        xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
@@ -514,9 +529,39 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
                argc--; argv++;
        }
 
-       if (replay.seq || replay.oseq)
-               addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL,
-                         (void *)&replay, sizeof(replay));
+       if (req.xsinfo.flags & XFRM_STATE_ESN &&
+           replay_window == 0) {
+               fprintf(stderr, "Error: esn flag set without replay-window.\n");
+               exit(-1);
+       }
+
+       if (replay_window > XFRMA_REPLAY_ESN_MAX) {
+               fprintf(stderr,
+                       "Error: replay-window (%u) > XFRMA_REPLAY_ESN_MAX (%u).\n",
+                       replay_window, XFRMA_REPLAY_ESN_MAX);
+               exit(-1);
+       }
+
+       if (req.xsinfo.flags & XFRM_STATE_ESN ||
+           replay_window > (sizeof(replay.bitmap) * 8)) {
+               replay_esn.seq = seq;
+               replay_esn.oseq = oseq;
+               replay_esn.seq_hi = seq_hi;
+               replay_esn.oseq_hi = oseq_hi;
+               replay_esn.replay_window = replay_window;
+               replay_esn.bmp_len = (replay_window + sizeof(__u32) * 8 - 1) /
+                                    (sizeof(__u32) * 8);
+               addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_ESN_VAL,
+                         &replay_esn, sizeof(replay_esn));
+       } else {
+               if (seq || oseq) {
+                       replay.seq = seq;
+                       replay.oseq = oseq;
+                       addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL,
+                                 &replay, sizeof(replay));
+               }
+               req.xsinfo.replay_window = replay_window;
+       }
 
        if (extra_flags)
                addattr32(&req.n, sizeof(req.buf), XFRMA_SA_EXTRA_FLAGS,
@@ -643,7 +688,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
        if (req.xsinfo.family == AF_UNSPEC)
                req.xsinfo.family = AF_INET;
 
-       if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+       if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
                exit(2);
 
        rtnl_close(&rth);
@@ -655,9 +700,9 @@ static int xfrm_state_allocspi(int argc, char **argv)
 {
        struct rtnl_handle rth;
        struct {
-               struct nlmsghdr         n;
+               struct nlmsghdr n;
                struct xfrm_userspi_info xspi;
-               char                    buf[RTA_BUF_SIZE];
+               char                    buf[RTA_BUF_SIZE];
        } req;
        char *idp = NULL;
        char *minp = NULL;
@@ -780,7 +825,7 @@ static int xfrm_state_allocspi(int argc, char **argv)
                req.xspi.info.family = AF_INET;
 
 
-       if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
+       if (rtnl_talk(&rth, &req.n, res_n, sizeof(res_buf)) < 0)
                exit(2);
 
        if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
@@ -912,9 +957,9 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
 {
        struct rtnl_handle rth;
        struct {
-               struct nlmsghdr         n;
+               struct nlmsghdr n;
                struct xfrm_usersa_id   xsid;
-               char                    buf[RTA_BUF_SIZE];
+               char                    buf[RTA_BUF_SIZE];
        } req;
        struct xfrm_id id;
        char *idp = NULL;
@@ -970,7 +1015,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
                req.xsid.family = AF_INET;
 
        if (delete) {
-               if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+               if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
                        exit(2);
        } else {
                char buf[NLMSG_BUF_SIZE];
@@ -978,7 +1023,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
 
                memset(buf, 0, sizeof(buf));
 
-               if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
+               if (rtnl_talk(&rth, &req.n, res_n, sizeof(req)) < 0)
                        exit(2);
 
                if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
@@ -1103,13 +1148,23 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
                xb.rth = &rth;
 
                for (i = 0; ; i++) {
+                       struct {
+                               struct nlmsghdr n;
+                               char buf[NLMSG_BUF_SIZE];
+                       } req = {
+                               .n.nlmsg_len = NLMSG_HDRLEN,
+                               .n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+                               .n.nlmsg_type = XFRM_MSG_GETSA,
+                               .n.nlmsg_seq = rth.dump = ++rth.seq,
+                       };
+
                        xb.offset = 0;
                        xb.nlmsg_count = 0;
 
                        if (show_stats > 1)
                                fprintf(stderr, "Delete-all round = %d\n", i);
 
-                       if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
+                       if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) {
                                perror("Cannot send dump request");
                                exit(1);
                        }
@@ -1136,7 +1191,30 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
                }
 
        } else {
-               if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
+               struct xfrm_address_filter addrfilter = {
+                       .saddr = filter.xsinfo.saddr,
+                       .daddr = filter.xsinfo.id.daddr,
+                       .family = filter.xsinfo.family,
+                       .splen = filter.id_src_mask,
+                       .dplen = filter.id_dst_mask,
+               };
+               struct {
+                       struct nlmsghdr n;
+                       char buf[NLMSG_BUF_SIZE];
+               } req = {
+                       .n.nlmsg_len = NLMSG_HDRLEN,
+                       .n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
+                       .n.nlmsg_type = XFRM_MSG_GETSA,
+                       .n.nlmsg_seq = rth.dump = ++rth.seq,
+               };
+
+               if (filter.xsinfo.id.proto)
+                       addattr8(&req.n, sizeof(req), XFRMA_PROTO,
+                                filter.xsinfo.id.proto);
+               addattr_l(&req.n, sizeof(req), XFRMA_ADDRESS_FILTER,
+                         &addrfilter, sizeof(addrfilter));
+
+               if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) {
                        perror("Cannot send dump request");
                        exit(1);
                }
@@ -1188,7 +1266,7 @@ static int print_sadinfo(struct nlmsghdr *n, void *arg)
                                fprintf(fp,"BAD SAD length returned\n");
                                return -1;
                        }
-                               
+
                        si = RTA_DATA(tb[XFRMA_SAD_HINFO]);
                        fprintf(fp," (buckets ");
                        fprintf(fp,"count %d", si->sadhcnt);
@@ -1219,7 +1297,7 @@ static int xfrm_sad_getinfo(int argc, char **argv)
        if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
                exit(1);
 
-       if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+       if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
                exit(2);
 
        print_sadinfo(&req.n, (void*)stdout);
@@ -1273,7 +1351,7 @@ static int xfrm_state_flush(int argc, char **argv)
                fprintf(stderr, "Flush state with XFRM-PROTO value \"%s\"\n",
                        strxf_xfrmproto(req.xsf.proto));
 
-       if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+       if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
                exit(2);
 
        rtnl_close(&rth);