]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - ip/xfrm_state.c
iproute2: add support of flag XFRM_STATE_ALIGN4
[lisovros/iproute2_canprio.git] / ip / xfrm_state.c
1 /* $USAGI: $ */
2
3 /*
4  * Copyright (C)2004 USAGI/WIDE Project
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 /*
21  * based on iproute.c
22  */
23 /*
24  * Authors:
25  *      Masahide NAKAMURA @USAGI
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <netdb.h>
32 #include <linux/xfrm.h>
33 #include "utils.h"
34 #include "xfrm.h"
35 #include "ip_common.h"
36
37 //#define NLMSG_DELETEALL_BUF_SIZE (4096-512)
38 #define NLMSG_DELETEALL_BUF_SIZE 8192
39
40 /*
41  * Receiving buffer defines:
42  * nlmsg
43  *   data = struct xfrm_usersa_info
44  *   rtattr
45  *   rtattr
46  *   ... (max count of rtattr is XFRM_MAX+1
47  *
48  *  each rtattr data = struct xfrm_algo(dynamic size) or xfrm_address_t
49  */
50 #define NLMSG_BUF_SIZE 4096
51 #define RTA_BUF_SIZE 2048
52 #define XFRM_ALGO_KEY_BUF_SIZE 512
53 #define CTX_BUF_SIZE 256
54
55 static void usage(void) __attribute__((noreturn));
56
57 static void usage(void)
58 {
59         fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ XFRM_OPT ] [ ctx SEC_CTX ] [ mode MODE ]\n");
60         fprintf(stderr, "        [ reqid REQID ] [ seq SEQ ] [ replay-window SIZE ] [ flag FLAG-LIST ]\n");
61         fprintf(stderr, "        [ encap ENCAP ] [ sel SELECTOR ] [ replay-seq SEQ ]\n");
62         fprintf(stderr, "        [ replay-oseq SEQ ] [ LIMIT-LIST ]\n");
63         fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ reqid REQID ] [ seq SEQ ]\n");
64         fprintf(stderr, "        [ min SPI max SPI ]\n");
65         fprintf(stderr, "Usage: ip xfrm state { delete | get } ID\n");
66         fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
67         fprintf(stderr, "        [ flag FLAG-LIST ]\n");
68         fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM_PROTO ]\n");
69         fprintf(stderr, "Usage: ip xfrm state count \n");
70
71         fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ] [mark MARK [mask MASK]]\n");
72         //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n");
73         fprintf(stderr, "XFRM_PROTO := [ ");
74         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
75         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
76         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
77         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
78         fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_DSTOPTS));
79         fprintf(stderr, "]\n");
80
81         //fprintf(stderr, "SPI - security parameter index(default=0)\n");
82
83         fprintf(stderr, "MODE := [ transport | tunnel | ro | beet ](default=transport)\n");
84         //fprintf(stderr, "REQID - number(default=0)\n");
85
86         fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
87         fprintf(stderr, "FLAG := [ noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4 ]\n");
88
89         fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n");
90         fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n");
91
92         fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ ALGO ]\n");
93         fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY "
94                         "[ ALGO_ICV_LEN | ALGO_TRUNC_LEN ]\n");
95         fprintf(stderr, "ALGO_TYPE := [ ");
96         fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AEAD));
97         fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT));
98         fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AUTH));
99         fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AUTH_TRUNC));
100         fprintf(stderr, "%s ", strxf_algotype(XFRMA_ALG_COMP));
101         fprintf(stderr, "]\n");
102
103         //fprintf(stderr, "ALGO_NAME - algorithm name\n");
104         //fprintf(stderr, "ALGO_KEY - algorithm key\n");
105
106         fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ UPSPEC ] [ dev DEV ]\n");
107
108         fprintf(stderr, "UPSPEC := proto PROTO [ [ sport PORT ] [ dport PORT ] |\n");
109         fprintf(stderr, "                        [ type NUMBER ] [ code NUMBER ] ]\n");
110
111
112         //fprintf(stderr, "DEV - device name(default=none)\n");
113         fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] | [ limit LIMIT ]\n");
114         fprintf(stderr, "LIMIT := [ [time-soft|time-hard|time-use-soft|time-use-hard] SECONDS ] |\n");
115         fprintf(stderr, "         [ [byte-soft|byte-hard] SIZE ] | [ [packet-soft|packet-hard] COUNT ]\n");
116         exit(-1);
117 }
118
119 static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
120                            char *name, char *key, char *buf, int max)
121 {
122         int len;
123         int slen = strlen(key);
124
125 #if 0
126         /* XXX: verifying both name and key is required! */
127         fprintf(stderr, "warning: ALGONAME/ALGOKEY will send to kernel promiscuously!(verifying them isn't implemented yet)\n");
128 #endif
129
130         strncpy(alg->alg_name, name, sizeof(alg->alg_name));
131
132         if (slen > 2 && strncmp(key, "0x", 2) == 0) {
133                 /* split two chars "0x" from the top */
134                 char *p = key + 2;
135                 int plen = slen - 2;
136                 int i;
137                 int j;
138
139                 /* Converting hexadecimal numbered string into real key;
140                  * Convert each two chars into one char(value). If number
141                  * of the length is odd, add zero on the top for rounding.
142                  */
143
144                 /* calculate length of the converted values(real key) */
145                 len = (plen + 1) / 2;
146                 if (len > max)
147                         invarg("\"ALGOKEY\" makes buffer overflow\n", key);
148
149                 for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
150                         char vbuf[3];
151                         __u8 val;
152
153                         vbuf[0] = i >= 0 ? p[i] : '0';
154                         vbuf[1] = p[i + 1];
155                         vbuf[2] = '\0';
156
157                         if (get_u8(&val, vbuf, 16))
158                                 invarg("\"ALGOKEY\" is invalid", key);
159
160                         buf[j] = val;
161                 }
162         } else {
163                 len = slen;
164                 if (len > 0) {
165                         if (len > max)
166                                 invarg("\"ALGOKEY\" makes buffer overflow\n", key);
167
168                         strncpy(buf, key, len);
169                 }
170         }
171
172         alg->alg_key_len = len * 8;
173
174         return 0;
175 }
176
177 static int xfrm_seq_parse(__u32 *seq, int *argcp, char ***argvp)
178 {
179         int argc = *argcp;
180         char **argv = *argvp;
181
182         if (get_u32(seq, *argv, 0))
183                 invarg("\"SEQ\" is invalid", *argv);
184
185         *seq = htonl(*seq);
186
187         *argcp = argc;
188         *argvp = argv;
189
190         return 0;
191 }
192
193 static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
194 {
195         int argc = *argcp;
196         char **argv = *argvp;
197         int len = strlen(*argv);
198
199         if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
200                 __u8 val = 0;
201
202                 if (get_u8(&val, *argv, 16))
203                         invarg("\"FLAG\" is invalid", *argv);
204                 *flags = val;
205         } else {
206                 while (1) {
207                         if (strcmp(*argv, "noecn") == 0)
208                                 *flags |= XFRM_STATE_NOECN;
209                         else if (strcmp(*argv, "decap-dscp") == 0)
210                                 *flags |= XFRM_STATE_DECAP_DSCP;
211                         else if (strcmp(*argv, "nopmtudisc") == 0)
212                                 *flags |= XFRM_STATE_NOPMTUDISC;
213                         else if (strcmp(*argv, "wildrecv") == 0)
214                                 *flags |= XFRM_STATE_WILDRECV;
215                         else if (strcmp(*argv, "icmp") == 0)
216                                 *flags |= XFRM_STATE_ICMP;
217                         else if (strcmp(*argv, "af-unspec") == 0)
218                                 *flags |= XFRM_STATE_AF_UNSPEC;
219                         else if (strcmp(*argv, "align4") == 0)
220                                 *flags |= XFRM_STATE_ALIGN4;
221                         else {
222                                 PREV_ARG(); /* back track */
223                                 break;
224                         }
225
226                         if (!NEXT_ARG_OK())
227                                 break;
228                         NEXT_ARG();
229                 }
230         }
231
232         *argcp = argc;
233         *argvp = argv;
234
235         return 0;
236 }
237
238 static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
239 {
240         struct rtnl_handle rth;
241         struct {
242                 struct nlmsghdr         n;
243                 struct xfrm_usersa_info xsinfo;
244                 char                    buf[RTA_BUF_SIZE];
245         } req;
246         struct xfrm_replay_state replay;
247         char *idp = NULL;
248         char *aeadop = NULL;
249         char *ealgop = NULL;
250         char *aalgop = NULL;
251         char *calgop = NULL;
252         char *coap = NULL;
253         char *sctxp = NULL;
254         struct xfrm_mark mark = {0, 0};
255         struct {
256                 struct xfrm_user_sec_ctx sctx;
257                 char    str[CTX_BUF_SIZE];
258         } ctx;
259
260         memset(&req, 0, sizeof(req));
261         memset(&replay, 0, sizeof(replay));
262         memset(&ctx, 0, sizeof(ctx));
263
264         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
265         req.n.nlmsg_flags = NLM_F_REQUEST|flags;
266         req.n.nlmsg_type = cmd;
267         req.xsinfo.family = preferred_family;
268
269         req.xsinfo.lft.soft_byte_limit = XFRM_INF;
270         req.xsinfo.lft.hard_byte_limit = XFRM_INF;
271         req.xsinfo.lft.soft_packet_limit = XFRM_INF;
272         req.xsinfo.lft.hard_packet_limit = XFRM_INF;
273
274         while (argc > 0) {
275                 if (strcmp(*argv, "mode") == 0) {
276                         NEXT_ARG();
277                         xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
278                 } else if (strcmp(*argv, "mark") == 0) {
279                         xfrm_parse_mark(&mark, &argc, &argv);
280                 } else if (strcmp(*argv, "reqid") == 0) {
281                         NEXT_ARG();
282                         xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
283                 } else if (strcmp(*argv, "seq") == 0) {
284                         NEXT_ARG();
285                         xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
286                 } else if (strcmp(*argv, "replay-window") == 0) {
287                         NEXT_ARG();
288                         if (get_u8(&req.xsinfo.replay_window, *argv, 0))
289                                 invarg("\"replay-window\" value is invalid", *argv);
290                 } else if (strcmp(*argv, "replay-seq") == 0) {
291                         NEXT_ARG();
292                         if (get_u32(&replay.seq, *argv, 0))
293                                 invarg("\"replay-seq\" value is invalid", *argv);
294                 } else if (strcmp(*argv, "replay-oseq") == 0) {
295                         NEXT_ARG();
296                         if (get_u32(&replay.oseq, *argv, 0))
297                                 invarg("\"replay-oseq\" value is invalid", *argv);
298                 } else if (strcmp(*argv, "flag") == 0) {
299                         NEXT_ARG();
300                         xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
301                 } else if (strcmp(*argv, "sel") == 0) {
302                         NEXT_ARG();
303                         xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
304                 } else if (strcmp(*argv, "limit") == 0) {
305                         NEXT_ARG();
306                         xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
307                 } else if (strcmp(*argv, "encap") == 0) {
308                         struct xfrm_encap_tmpl encap;
309                         inet_prefix oa;
310                         NEXT_ARG();
311                         xfrm_encap_type_parse(&encap.encap_type, &argc, &argv);
312                         NEXT_ARG();
313                         if (get_u16(&encap.encap_sport, *argv, 0))
314                                 invarg("\"encap\" sport value is invalid", *argv);
315                         encap.encap_sport = htons(encap.encap_sport);
316                         NEXT_ARG();
317                         if (get_u16(&encap.encap_dport, *argv, 0))
318                                 invarg("\"encap\" dport value is invalid", *argv);
319                         encap.encap_dport = htons(encap.encap_dport);
320                         NEXT_ARG();
321                         get_addr(&oa, *argv, AF_UNSPEC);
322                         memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
323                         addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
324                                   (void *)&encap, sizeof(encap));
325                 } else if (strcmp(*argv, "coa") == 0) {
326                         inet_prefix coa;
327                         xfrm_address_t xcoa;
328
329                         if (coap)
330                                 duparg("coa", *argv);
331                         coap = *argv;
332
333                         NEXT_ARG();
334
335                         get_prefix(&coa, *argv, preferred_family);
336                         if (coa.family == AF_UNSPEC)
337                                 invarg("\"coa\" address family is AF_UNSPEC", *argv);
338                         if (coa.bytelen > sizeof(xcoa))
339                                 invarg("\"coa\" address length is too large", *argv);
340
341                         memset(&xcoa, 0, sizeof(xcoa));
342                         memcpy(&xcoa, &coa.data, coa.bytelen);
343
344                         addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR,
345                                   (void *)&xcoa, sizeof(xcoa));
346                 } else if (strcmp(*argv, "ctx") == 0) {
347                         char *context;
348
349                         if (sctxp)
350                                 duparg("ctx", *argv);
351                         sctxp = *argv;
352
353                         NEXT_ARG();
354                         context = *argv;
355
356                         xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
357                         addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX,
358                                   (void *)&ctx, ctx.sctx.len);
359                 } else {
360                         /* try to assume ALGO */
361                         int type = xfrm_algotype_getbyname(*argv);
362                         switch (type) {
363                         case XFRMA_ALG_AEAD:
364                         case XFRMA_ALG_CRYPT:
365                         case XFRMA_ALG_AUTH:
366                         case XFRMA_ALG_AUTH_TRUNC:
367                         case XFRMA_ALG_COMP:
368                         {
369                                 /* ALGO */
370                                 struct {
371                                         union {
372                                                 struct xfrm_algo alg;
373                                                 struct xfrm_algo_aead aead;
374                                                 struct xfrm_algo_auth auth;
375                                         } u;
376                                         char buf[XFRM_ALGO_KEY_BUF_SIZE];
377                                 } alg = {};
378                                 int len;
379                                 __u32 icvlen, trunclen;
380                                 char *name;
381                                 char *key;
382                                 char *buf;
383
384                                 switch (type) {
385                                 case XFRMA_ALG_AEAD:
386                                         if (aeadop)
387                                                 duparg("ALGOTYPE", *argv);
388                                         aeadop = *argv;
389                                         break;
390                                 case XFRMA_ALG_CRYPT:
391                                         if (ealgop)
392                                                 duparg("ALGOTYPE", *argv);
393                                         ealgop = *argv;
394                                         break;
395                                 case XFRMA_ALG_AUTH:
396                                 case XFRMA_ALG_AUTH_TRUNC:
397                                         if (aalgop)
398                                                 duparg("ALGOTYPE", *argv);
399                                         aalgop = *argv;
400                                         break;
401                                 case XFRMA_ALG_COMP:
402                                         if (calgop)
403                                                 duparg("ALGOTYPE", *argv);
404                                         calgop = *argv;
405                                         break;
406                                 default:
407                                         /* not reached */
408                                         invarg("\"ALGOTYPE\" is invalid\n", *argv);
409                                 }
410
411                                 if (!NEXT_ARG_OK())
412                                         missarg("ALGONAME");
413                                 NEXT_ARG();
414                                 name = *argv;
415
416                                 if (!NEXT_ARG_OK())
417                                         missarg("ALGOKEY");
418                                 NEXT_ARG();
419                                 key = *argv;
420
421                                 buf = alg.u.alg.alg_key;
422                                 len = sizeof(alg.u.alg);
423
424                                 switch (type) {
425                                 case XFRMA_ALG_AEAD:
426                                         if (!NEXT_ARG_OK())
427                                                 missarg("ALGOICVLEN");
428                                         NEXT_ARG();
429                                         if (get_u32(&icvlen, *argv, 0))
430                                                 invarg("\"aead\" ICV length is invalid",
431                                                        *argv);
432                                         alg.u.aead.alg_icv_len = icvlen;
433
434                                         buf = alg.u.aead.alg_key;
435                                         len = sizeof(alg.u.aead);
436                                         break;
437                                 case XFRMA_ALG_AUTH_TRUNC:
438                                         if (!NEXT_ARG_OK())
439                                                 missarg("ALGOTRUNCLEN");
440                                         NEXT_ARG();
441                                         if (get_u32(&trunclen, *argv, 0))
442                                                 invarg("\"auth\" trunc length is invalid",
443                                                        *argv);
444                                         alg.u.auth.alg_trunc_len = trunclen;
445
446                                         buf = alg.u.auth.alg_key;
447                                         len = sizeof(alg.u.auth);
448                                         break;
449                                 }
450
451                                 xfrm_algo_parse((void *)&alg, type, name, key,
452                                                 buf, sizeof(alg.buf));
453                                 len += alg.u.alg.alg_key_len;
454
455                                 addattr_l(&req.n, sizeof(req.buf), type,
456                                           (void *)&alg, len);
457                                 break;
458                         }
459                         default:
460                                 /* try to assume ID */
461                                 if (idp)
462                                         invarg("unknown", *argv);
463                                 idp = *argv;
464
465                                 /* ID */
466                                 xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
467                                               &req.xsinfo.family, 0, &argc, &argv);
468                                 if (preferred_family == AF_UNSPEC)
469                                         preferred_family = req.xsinfo.family;
470                         }
471                 }
472                 argc--; argv++;
473         }
474
475         if (replay.seq || replay.oseq)
476                 addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL,
477                           (void *)&replay, sizeof(replay));
478
479         if (!idp) {
480                 fprintf(stderr, "Not enough information: \"ID\" is required\n");
481                 exit(1);
482         }
483
484         if (mark.m & mark.v) {
485                 int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
486                                   (void *)&mark, sizeof(mark));
487                 if (r < 0) {
488                         fprintf(stderr, "XFRMA_MARK failed\n");
489                         exit(1);
490                 }
491         }
492
493         switch (req.xsinfo.mode) {
494         case XFRM_MODE_TRANSPORT:
495         case XFRM_MODE_TUNNEL:
496                 if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
497                         fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
498                                 strxf_xfrmproto(req.xsinfo.id.proto));
499                         exit(1);
500                 }
501                 break;
502         case XFRM_MODE_ROUTEOPTIMIZATION:
503         case XFRM_MODE_IN_TRIGGER:
504                 if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
505                         fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
506                                 strxf_xfrmproto(req.xsinfo.id.proto));
507                         exit(1);
508                 }
509                 if (req.xsinfo.id.spi != 0) {
510                         fprintf(stderr, "\"spi\" must be 0 with proto=%s\n",
511                                 strxf_xfrmproto(req.xsinfo.id.proto));
512                         exit(1);
513                 }
514                 break;
515         default:
516                 break;
517         }
518
519         if (aeadop || ealgop || aalgop || calgop) {
520                 if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
521                         fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n",
522                                 strxf_xfrmproto(req.xsinfo.id.proto));
523                         exit(1);
524                 }
525         } else {
526                 if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
527                         fprintf(stderr, "\"ALGO\" is required with proto=%s\n",
528                                 strxf_xfrmproto(req.xsinfo.id.proto));
529                         exit (1);
530                 }
531         }
532
533         if (coap) {
534                 if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
535                         fprintf(stderr, "\"coa\" is invalid with proto=%s\n",
536                                 strxf_xfrmproto(req.xsinfo.id.proto));
537                         exit(1);
538                 }
539         } else {
540                 if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
541                         fprintf(stderr, "\"coa\" is required with proto=%s\n",
542                                 strxf_xfrmproto(req.xsinfo.id.proto));
543                         exit (1);
544                 }
545         }
546
547         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
548                 exit(1);
549
550         if (req.xsinfo.family == AF_UNSPEC)
551                 req.xsinfo.family = AF_INET;
552
553         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
554                 exit(2);
555
556         rtnl_close(&rth);
557
558         return 0;
559 }
560
561 static int xfrm_state_allocspi(int argc, char **argv)
562 {
563         struct rtnl_handle rth;
564         struct {
565                 struct nlmsghdr         n;
566                 struct xfrm_userspi_info xspi;
567                 char                    buf[RTA_BUF_SIZE];
568         } req;
569         char *idp = NULL;
570         char *minp = NULL;
571         char *maxp = NULL;
572         struct xfrm_mark mark = {0, 0};
573         char res_buf[NLMSG_BUF_SIZE];
574         struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;
575
576         memset(res_buf, 0, sizeof(res_buf));
577
578         memset(&req, 0, sizeof(req));
579
580         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi));
581         req.n.nlmsg_flags = NLM_F_REQUEST;
582         req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
583         req.xspi.info.family = preferred_family;
584
585 #if 0
586         req.xsinfo.lft.soft_byte_limit = XFRM_INF;
587         req.xsinfo.lft.hard_byte_limit = XFRM_INF;
588         req.xsinfo.lft.soft_packet_limit = XFRM_INF;
589         req.xsinfo.lft.hard_packet_limit = XFRM_INF;
590 #endif
591
592         while (argc > 0) {
593                 if (strcmp(*argv, "mode") == 0) {
594                         NEXT_ARG();
595                         xfrm_mode_parse(&req.xspi.info.mode, &argc, &argv);
596                 } else if (strcmp(*argv, "mark") == 0) {
597                         xfrm_parse_mark(&mark, &argc, &argv);
598                 } else if (strcmp(*argv, "reqid") == 0) {
599                         NEXT_ARG();
600                         xfrm_reqid_parse(&req.xspi.info.reqid, &argc, &argv);
601                 } else if (strcmp(*argv, "seq") == 0) {
602                         NEXT_ARG();
603                         xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv);
604                 } else if (strcmp(*argv, "min") == 0) {
605                         if (minp)
606                                 duparg("min", *argv);
607                         minp = *argv;
608
609                         NEXT_ARG();
610
611                         if (get_u32(&req.xspi.min, *argv, 0))
612                                 invarg("\"min\" value is invalid", *argv);
613                 } else if (strcmp(*argv, "max") == 0) {
614                         if (maxp)
615                                 duparg("max", *argv);
616                         maxp = *argv;
617
618                         NEXT_ARG();
619
620                         if (get_u32(&req.xspi.max, *argv, 0))
621                                 invarg("\"max\" value is invalid", *argv);
622                 } else {
623                         /* try to assume ID */
624                         if (idp)
625                                 invarg("unknown", *argv);
626                         idp = *argv;
627
628                         /* ID */
629                         xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id,
630                                       &req.xspi.info.family, 0, &argc, &argv);
631                         if (req.xspi.info.id.spi) {
632                                 fprintf(stderr, "\"SPI\" must be zero\n");
633                                 exit(1);
634                         }
635                         if (preferred_family == AF_UNSPEC)
636                                 preferred_family = req.xspi.info.family;
637                 }
638                 argc--; argv++;
639         }
640
641         if (!idp) {
642                 fprintf(stderr, "Not enough information: \"ID\" is required\n");
643                 exit(1);
644         }
645
646         if (minp) {
647                 if (!maxp) {
648                         fprintf(stderr, "\"max\" is missing\n");
649                         exit(1);
650                 }
651                 if (req.xspi.min > req.xspi.max) {
652                         fprintf(stderr, "\"min\" valie is larger than \"max\" one\n");
653                         exit(1);
654                 }
655         } else {
656                 if (maxp) {
657                         fprintf(stderr, "\"min\" is missing\n");
658                         exit(1);
659                 }
660
661                 /* XXX: Default value defined in PF_KEY;
662                  * See kernel's net/key/af_key.c(pfkey_getspi).
663                  */
664                 req.xspi.min = 0x100;
665                 req.xspi.max = 0x0fffffff;
666
667                 /* XXX: IPCOMP spi is 16-bits;
668                  * See kernel's net/xfrm/xfrm_user(verify_userspi_info).
669                  */
670                 if (req.xspi.info.id.proto == IPPROTO_COMP)
671                         req.xspi.max = 0xffff;
672         }
673
674         if (mark.m & mark.v) {
675                 int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
676                                   (void *)&mark, sizeof(mark));
677                 if (r < 0) {
678                         fprintf(stderr, "XFRMA_MARK failed\n");
679                         exit(1);
680                 }
681         }
682
683         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
684                 exit(1);
685
686         if (req.xspi.info.family == AF_UNSPEC)
687                 req.xspi.info.family = AF_INET;
688
689
690         if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
691                 exit(2);
692
693         if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
694                 fprintf(stderr, "An error :-)\n");
695                 exit(1);
696         }
697
698         rtnl_close(&rth);
699
700         return 0;
701 }
702
703 static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
704 {
705         if (!filter.use)
706                 return 1;
707
708         if (filter.id_src_mask)
709                 if (xfrm_addr_match(&xsinfo->saddr, &filter.xsinfo.saddr,
710                                     filter.id_src_mask))
711                         return 0;
712         if (filter.id_dst_mask)
713                 if (xfrm_addr_match(&xsinfo->id.daddr, &filter.xsinfo.id.daddr,
714                                     filter.id_dst_mask))
715                         return 0;
716         if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask)
717                 return 0;
718         if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask)
719                 return 0;
720         if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask)
721                 return 0;
722         if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask)
723                 return 0;
724         if (filter.state_flags_mask)
725                 if ((xsinfo->flags & filter.xsinfo.flags) == 0)
726                         return 0;
727
728         return 1;
729 }
730
731 int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
732                      void *arg)
733 {
734         FILE *fp = (FILE*)arg;
735         struct rtattr * tb[XFRMA_MAX+1];
736         struct rtattr * rta;
737         struct xfrm_usersa_info *xsinfo = NULL;
738         struct xfrm_user_expire *xexp = NULL;
739         struct xfrm_usersa_id   *xsid = NULL;
740         int len = n->nlmsg_len;
741
742         if (n->nlmsg_type != XFRM_MSG_NEWSA &&
743             n->nlmsg_type != XFRM_MSG_DELSA &&
744             n->nlmsg_type != XFRM_MSG_UPDSA &&
745             n->nlmsg_type != XFRM_MSG_EXPIRE) {
746                 fprintf(stderr, "Not a state: %08x %08x %08x\n",
747                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
748                 return 0;
749         }
750
751         if (n->nlmsg_type == XFRM_MSG_DELSA) {
752                 /* Dont blame me for this .. Herbert made me do it */
753                 xsid = NLMSG_DATA(n);
754                 len -= NLMSG_SPACE(sizeof(*xsid));
755         } else if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
756                 xexp = NLMSG_DATA(n);
757                 xsinfo = &xexp->state;
758                 len -= NLMSG_SPACE(sizeof(*xexp));
759         } else {
760                 xexp = NULL;
761                 xsinfo = NLMSG_DATA(n);
762                 len -= NLMSG_SPACE(sizeof(*xsinfo));
763         }
764
765         if (len < 0) {
766                 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
767                 return -1;
768         }
769
770         if (xsinfo && !xfrm_state_filter_match(xsinfo))
771                 return 0;
772
773         if (n->nlmsg_type == XFRM_MSG_DELSA)
774                 fprintf(fp, "Deleted ");
775         else if (n->nlmsg_type == XFRM_MSG_UPDSA)
776                 fprintf(fp, "Updated ");
777         else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
778                 fprintf(fp, "Expired ");
779
780         if (n->nlmsg_type == XFRM_MSG_DELSA)
781                 rta = XFRMSID_RTA(xsid);
782         else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
783                 rta = XFRMEXP_RTA(xexp);
784         else
785                 rta = XFRMS_RTA(xsinfo);
786
787         parse_rtattr(tb, XFRMA_MAX, rta, len);
788
789         if (n->nlmsg_type == XFRM_MSG_DELSA) {
790                 //xfrm_policy_id_print();
791
792                 if (!tb[XFRMA_SA]) {
793                         fprintf(stderr, "Buggy XFRM_MSG_DELSA: no XFRMA_SA\n");
794                         return -1;
795                 }
796                 if (RTA_PAYLOAD(tb[XFRMA_SA]) < sizeof(*xsinfo)) {
797                         fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n");
798                         return -1;
799                 }
800                 xsinfo = RTA_DATA(tb[XFRMA_SA]);
801         }
802
803         xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL);
804
805         if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
806                 fprintf(fp, "\t");
807                 fprintf(fp, "hard %u", xexp->hard);
808                 fprintf(fp, "%s", _SL_);
809         }
810
811         if (oneline)
812                 fprintf(fp, "\n");
813         fflush(fp);
814
815         return 0;
816 }
817
818 static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
819 {
820         struct rtnl_handle rth;
821         struct {
822                 struct nlmsghdr         n;
823                 struct xfrm_usersa_id   xsid;
824                 char                    buf[RTA_BUF_SIZE];
825         } req;
826         struct xfrm_id id;
827         char *idp = NULL;
828         struct xfrm_mark mark = {0, 0};
829
830         memset(&req, 0, sizeof(req));
831
832         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid));
833         req.n.nlmsg_flags = NLM_F_REQUEST;
834         req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA;
835         req.xsid.family = preferred_family;
836
837         while (argc > 0) {
838                 xfrm_address_t saddr;
839
840                 if (strcmp(*argv, "mark") == 0) {
841                         xfrm_parse_mark(&mark, &argc, &argv);
842                 } else {
843                         if (idp)
844                                 invarg("unknown", *argv);
845                         idp = *argv;
846
847                         /* ID */
848                         memset(&id, 0, sizeof(id));
849                         memset(&saddr, 0, sizeof(saddr));
850                         xfrm_id_parse(&saddr, &id, &req.xsid.family, 0,
851                                       &argc, &argv);
852
853                         memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
854                         req.xsid.spi = id.spi;
855                         req.xsid.proto = id.proto;
856
857                         addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
858                                   (void *)&saddr, sizeof(saddr));
859                 }
860
861                 argc--; argv++;
862         }
863
864         if (mark.m & mark.v) {
865                 int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK,
866                                   (void *)&mark, sizeof(mark));
867                 if (r < 0) {
868                         fprintf(stderr, "XFRMA_MARK failed\n");
869                         exit(1);
870                 }
871         }
872
873         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
874                 exit(1);
875
876         if (req.xsid.family == AF_UNSPEC)
877                 req.xsid.family = AF_INET;
878
879         if (delete) {
880                 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
881                         exit(2);
882         } else {
883                 char buf[NLMSG_BUF_SIZE];
884                 struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
885
886                 memset(buf, 0, sizeof(buf));
887
888                 if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
889                         exit(2);
890
891                 if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
892                         fprintf(stderr, "An error :-)\n");
893                         exit(1);
894                 }
895         }
896
897         rtnl_close(&rth);
898
899         return 0;
900 }
901
902 /*
903  * With an existing state of nlmsg, make new nlmsg for deleting the state
904  * and store it to buffer.
905  */
906 static int xfrm_state_keep(const struct sockaddr_nl *who,
907                            struct nlmsghdr *n,
908                            void *arg)
909 {
910         struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
911         struct rtnl_handle *rth = xb->rth;
912         struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
913         int len = n->nlmsg_len;
914         struct nlmsghdr *new_n;
915         struct xfrm_usersa_id *xsid;
916
917         if (n->nlmsg_type != XFRM_MSG_NEWSA) {
918                 fprintf(stderr, "Not a state: %08x %08x %08x\n",
919                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
920                 return 0;
921         }
922
923         len -= NLMSG_LENGTH(sizeof(*xsinfo));
924         if (len < 0) {
925                 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
926                 return -1;
927         }
928
929         if (!xfrm_state_filter_match(xsinfo))
930                 return 0;
931
932         if (xb->offset > xb->size) {
933                 fprintf(stderr, "State buffer overflow\n");
934                 return -1;
935         }
936
937         new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
938         new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid));
939         new_n->nlmsg_flags = NLM_F_REQUEST;
940         new_n->nlmsg_type = XFRM_MSG_DELSA;
941         new_n->nlmsg_seq = ++rth->seq;
942
943         xsid = NLMSG_DATA(new_n);
944         xsid->family = xsinfo->family;
945         memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr));
946         xsid->spi = xsinfo->id.spi;
947         xsid->proto = xsinfo->id.proto;
948
949         addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr,
950                   sizeof(xsid->daddr));
951
952         xb->offset += new_n->nlmsg_len;
953         xb->nlmsg_count ++;
954
955         return 0;
956 }
957
958 static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
959 {
960         char *idp = NULL;
961         struct rtnl_handle rth;
962
963         if(argc > 0)
964                 filter.use = 1;
965         filter.xsinfo.family = preferred_family;
966
967         while (argc > 0) {
968                 if (strcmp(*argv, "mode") == 0) {
969                         NEXT_ARG();
970                         xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
971
972                         filter.mode_mask = XFRM_FILTER_MASK_FULL;
973
974                 } else if (strcmp(*argv, "reqid") == 0) {
975                         NEXT_ARG();
976                         xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv);
977
978                         filter.reqid_mask = XFRM_FILTER_MASK_FULL;
979
980                 } else if (strcmp(*argv, "flag") == 0) {
981                         NEXT_ARG();
982                         xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv);
983
984                         filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
985
986                 } else {
987                         if (idp)
988                                 invarg("unknown", *argv);
989                         idp = *argv;
990
991                         /* ID */
992                         xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id,
993                                       &filter.xsinfo.family, 1, &argc, &argv);
994                         if (preferred_family == AF_UNSPEC)
995                                 preferred_family = filter.xsinfo.family;
996                 }
997                 argc--; argv++;
998         }
999
1000         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1001                 exit(1);
1002
1003         if (deleteall) {
1004                 struct xfrm_buffer xb;
1005                 char buf[NLMSG_DELETEALL_BUF_SIZE];
1006                 int i;
1007
1008                 xb.buf = buf;
1009                 xb.size = sizeof(buf);
1010                 xb.rth = &rth;
1011
1012                 for (i = 0; ; i++) {
1013                         xb.offset = 0;
1014                         xb.nlmsg_count = 0;
1015
1016                         if (show_stats > 1)
1017                                 fprintf(stderr, "Delete-all round = %d\n", i);
1018
1019                         if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
1020                                 perror("Cannot send dump request");
1021                                 exit(1);
1022                         }
1023
1024                         if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb, NULL, NULL) < 0) {
1025                                 fprintf(stderr, "Delete-all terminated\n");
1026                                 exit(1);
1027                         }
1028                         if (xb.nlmsg_count == 0) {
1029                                 if (show_stats > 1)
1030                                         fprintf(stderr, "Delete-all completed\n");
1031                                 break;
1032                         }
1033
1034                         if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) {
1035                                 perror("Failed to send delete-all request\n");
1036                                 exit(1);
1037                         }
1038                         if (show_stats > 1)
1039                                 fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count);
1040
1041                         xb.offset = 0;
1042                         xb.nlmsg_count = 0;
1043                 }
1044
1045         } else {
1046                 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
1047                         perror("Cannot send dump request");
1048                         exit(1);
1049                 }
1050
1051                 if (rtnl_dump_filter(&rth, xfrm_state_print, stdout, NULL, NULL) < 0) {
1052                         fprintf(stderr, "Dump terminated\n");
1053                         exit(1);
1054                 }
1055         }
1056
1057         rtnl_close(&rth);
1058
1059         exit(0);
1060 }
1061
1062 int print_sadinfo(struct nlmsghdr *n, void *arg)
1063 {
1064         FILE *fp = (FILE*)arg;
1065         __u32 *f = NLMSG_DATA(n);
1066         struct rtattr *tb[XFRMA_SAD_MAX+1];
1067         struct rtattr *rta;
1068         __u32 *cnt;
1069
1070         int len = n->nlmsg_len;
1071
1072         len -= NLMSG_LENGTH(sizeof(__u32));
1073         if (len < 0) {
1074                 fprintf(stderr, "SADinfo: Wrong len %d\n", len);
1075                 return -1;
1076         }
1077
1078         rta = XFRMSAPD_RTA(f);
1079         parse_rtattr(tb, XFRMA_SAD_MAX, rta, len);
1080
1081         if (tb[XFRMA_SAD_CNT]) {
1082                 fprintf(fp,"\t SAD");
1083                 cnt = (__u32 *)RTA_DATA(tb[XFRMA_SAD_CNT]);
1084                 fprintf(fp," count %d", *cnt);
1085         } else {
1086                 fprintf(fp,"BAD SAD info returned\n");
1087                 return -1;
1088         }
1089
1090         if (show_stats) {
1091                 if (tb[XFRMA_SAD_HINFO]) {
1092                         struct xfrmu_sadhinfo *si;
1093
1094                         if (RTA_PAYLOAD(tb[XFRMA_SAD_HINFO]) < sizeof(*si)) {
1095                                 fprintf(fp,"BAD SAD length returned\n");
1096                                 return -1;
1097                         }
1098                                 
1099                         si = RTA_DATA(tb[XFRMA_SAD_HINFO]);
1100                         fprintf(fp," (buckets ");
1101                         fprintf(fp,"count %d", si->sadhcnt);
1102                         fprintf(fp," Max %d", si->sadhmcnt);
1103                         fprintf(fp,")");
1104                 }
1105         }
1106         fprintf(fp,"\n");
1107
1108         return 0;
1109 }
1110
1111 static int xfrm_sad_getinfo(int argc, char **argv)
1112 {
1113         struct rtnl_handle rth;
1114         struct {
1115                 struct nlmsghdr                 n;
1116                 __u32                           flags;
1117                 char                            ans[64];
1118         } req;
1119
1120         memset(&req, 0, sizeof(req));
1121         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags));
1122         req.n.nlmsg_flags = NLM_F_REQUEST;
1123         req.n.nlmsg_type = XFRM_MSG_GETSADINFO;
1124         req.flags = 0XFFFFFFFF;
1125
1126         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1127                 exit(1);
1128
1129         if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
1130                 exit(2);
1131
1132         print_sadinfo(&req.n, (void*)stdout);
1133
1134         rtnl_close(&rth);
1135
1136         return 0;
1137 }
1138
1139 static int xfrm_state_flush(int argc, char **argv)
1140 {
1141         struct rtnl_handle rth;
1142         struct {
1143                 struct nlmsghdr                 n;
1144                 struct xfrm_usersa_flush        xsf;
1145         } req;
1146         char *protop = NULL;
1147
1148         memset(&req, 0, sizeof(req));
1149
1150         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
1151         req.n.nlmsg_flags = NLM_F_REQUEST;
1152         req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
1153         req.xsf.proto = 0;
1154
1155         while (argc > 0) {
1156                 if (strcmp(*argv, "proto") == 0) {
1157                         int ret;
1158
1159                         if (protop)
1160                                 duparg("proto", *argv);
1161                         protop = *argv;
1162
1163                         NEXT_ARG();
1164
1165                         ret = xfrm_xfrmproto_getbyname(*argv);
1166                         if (ret < 0)
1167                                 invarg("\"XFRM_PROTO\" is invalid", *argv);
1168
1169                         req.xsf.proto = (__u8)ret;
1170                 } else
1171                         invarg("unknown", *argv);
1172
1173                 argc--; argv++;
1174         }
1175
1176         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1177                 exit(1);
1178
1179         if (show_stats > 1)
1180                 fprintf(stderr, "Flush state proto=%s\n",
1181                         strxf_xfrmproto(req.xsf.proto));
1182
1183         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
1184                 exit(2);
1185
1186         rtnl_close(&rth);
1187
1188         return 0;
1189 }
1190
1191 int do_xfrm_state(int argc, char **argv)
1192 {
1193         if (argc < 1)
1194                 return xfrm_state_list_or_deleteall(0, NULL, 0);
1195
1196         if (matches(*argv, "add") == 0)
1197                 return xfrm_state_modify(XFRM_MSG_NEWSA, 0,
1198                                          argc-1, argv+1);
1199         if (matches(*argv, "update") == 0)
1200                 return xfrm_state_modify(XFRM_MSG_UPDSA, 0,
1201                                          argc-1, argv+1);
1202         if (matches(*argv, "allocspi") == 0)
1203                 return xfrm_state_allocspi(argc-1, argv+1);
1204         if (matches(*argv, "delete") == 0)
1205                 return xfrm_state_get_or_delete(argc-1, argv+1, 1);
1206         if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0)
1207                 return xfrm_state_list_or_deleteall(argc-1, argv+1, 1);
1208         if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
1209             || matches(*argv, "lst") == 0)
1210                 return xfrm_state_list_or_deleteall(argc-1, argv+1, 0);
1211         if (matches(*argv, "get") == 0)
1212                 return xfrm_state_get_or_delete(argc-1, argv+1, 0);
1213         if (matches(*argv, "flush") == 0)
1214                 return xfrm_state_flush(argc-1, argv+1);
1215         if (matches(*argv, "count") == 0) {
1216                 return xfrm_sad_getinfo(argc, argv);
1217         }
1218         if (matches(*argv, "help") == 0)
1219                 usage();
1220         fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
1221         exit(-1);
1222 }