]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/xfrm_state.c
Import patch iproute-xfrm.3
[mirror_iproute2.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_FLUSH_BUF_SIZE (4096-512)
38 #define NLMSG_FLUSH_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_DEPTH)
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
54 static void usage(void) __attribute__((noreturn));
55
56 static void usage(void)
57 {
58 fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
59 fprintf(stderr, " [ reqid REQID ] [ FLAG-LIST ] [ sel SELECTOR ] [ LIMIT-LIST ]\n");
60
61 fprintf(stderr, "Usage: ip xfrm state { delete | get } ID\n");
62 fprintf(stderr, "Usage: ip xfrm state { flush | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
63 fprintf(stderr, " [ FLAG_LIST ]\n");
64
65 fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n");
66 //fprintf(stderr, "XFRM_PROTO := [ esp | ah | ipcomp ]\n");
67 fprintf(stderr, "XFRM_PROTO := [ ");
68 fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ESP));
69 fprintf(stderr, "%s | ", strxf_proto(IPPROTO_AH));
70 fprintf(stderr, "%s", strxf_proto(IPPROTO_COMP));
71 fprintf(stderr, " ]\n");
72
73 //fprintf(stderr, "SPI - security parameter index(default=0)\n");
74
75 fprintf(stderr, "MODE := [ transport | tunnel ](default=transport)\n");
76 //fprintf(stderr, "REQID - number(default=0)\n");
77
78 fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] [ flag FLAG ]\n");
79 fprintf(stderr, "FLAG := [ noecn ]\n");
80
81 fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ algo ALGO ]\n");
82 fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY\n");
83 fprintf(stderr, "ALGO_TYPE := [ E | A | C ]\n");
84 //fprintf(stderr, "ALGO_NAME - algorithm name\n");
85 //fprintf(stderr, "ALGO_KEY - algorithm key\n");
86
87 fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ upspec UPSPEC ] [ dev DEV ]\n");
88
89 fprintf(stderr, "UPSPEC := proto PROTO [ sport PORT ] [ dport PORT ]\n");
90
91 //fprintf(stderr, "DEV - device name(default=none)\n");
92 fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] | [ limit LIMIT ]\n");
93 fprintf(stderr, "LIMIT := [ [time-soft|time-hard|time-use-soft|time-use-hard] SECONDS ] |\n");
94 fprintf(stderr, " [ [byte-soft|byte-hard] SIZE ] | [ [packet-soft|packet-hard] COUNT ]\n");
95 exit(-1);
96 }
97
98 static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
99 char *name, char *key, int max)
100 {
101 int len;
102
103 #if 1
104 /* XXX: verifying both name and key is required! */
105 fprintf(stderr, "warning: ALGONAME/ALGOKEY will send to kernel promiscuously!(verifying them isn't implemented yet)\n");
106 #endif
107
108 strncpy(alg->alg_name, name, sizeof(alg->alg_name));
109
110 if (strncmp(key, "0x", 2) == 0) {
111 /*
112 * XXX: fix me!!
113 */
114 __u64 val = 0;
115 char *p = (char *)&val;
116
117 if (get_u64(&val, key, 16))
118 invarg("\"ALGOKEY\" is invalid", key);
119
120 len = (strlen(key) - 2) / 2;
121 if (len > sizeof(val))
122 invarg("\"ALGOKEY\" is invalid: too large", key);
123
124 if (len > 0) {
125 int index = sizeof(val) - len;
126 if (len > max)
127 invarg("\"ALGOKEY\" makes buffer overflow\n", key);
128
129 memcpy(alg->alg_key, &p[index], len);
130 }
131
132 } else {
133 len = strlen(key);
134 if (len > 0) {
135 if (len > max)
136 invarg("\"ALGOKEY\" makes buffer overflow\n", key);
137
138 strncpy(alg->alg_key, key, len);
139 }
140 }
141
142 alg->alg_key_len = len * 8;
143
144 return 0;
145 }
146
147 static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
148 {
149 int argc = *argcp;
150 char **argv = *argvp;
151 int len = strlen(*argv);
152
153 if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
154 __u8 val = 0;
155
156 if (get_u8(&val, *argv, 16))
157 invarg("\"FLAG\" is invalid", *argv);
158 *flags = val;
159 } else {
160 if (strcmp(*argv, "noecn") == 0)
161 *flags |= XFRM_STATE_NOECN;
162 else
163 invarg("\"FLAG\" is invalid", *argv);
164 }
165
166 filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
167
168 *argcp = argc;
169 *argvp = argv;
170
171 return 0;
172 }
173
174 static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
175 {
176 struct rtnl_handle rth;
177 struct {
178 struct nlmsghdr n;
179 struct xfrm_usersa_info xsinfo;
180 char buf[RTA_BUF_SIZE];
181 } req;
182 char *idp = NULL;
183 char *ealgop = NULL;
184 char *aalgop = NULL;
185 char *calgop = NULL;
186
187 memset(&req, 0, sizeof(req));
188
189 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
190 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
191 req.n.nlmsg_type = cmd;
192 req.xsinfo.family = preferred_family;
193
194 req.xsinfo.lft.soft_byte_limit = XFRM_INF;
195 req.xsinfo.lft.hard_byte_limit = XFRM_INF;
196 req.xsinfo.lft.soft_packet_limit = XFRM_INF;
197 req.xsinfo.lft.hard_packet_limit = XFRM_INF;
198
199 while (argc > 0) {
200 if (strcmp(*argv, "algo") == 0) {
201 struct {
202 struct xfrm_algo alg;
203 char buf[XFRM_ALGO_KEY_BUF_SIZE];
204 } alg;
205 int len;
206 enum xfrm_attr_type_t type;
207 char *name;
208 char *key;
209
210 NEXT_ARG();
211
212 if (strcmp(*argv, "E") == 0) {
213 if (ealgop)
214 duparg("ALGOTYPE", *argv);
215 ealgop = *argv;
216 type = XFRMA_ALG_CRYPT;
217 } else if (strcmp(*argv, "A") == 0) {
218 if (aalgop)
219 duparg("ALGOTYPE", *argv);
220 aalgop = *argv;
221 type = XFRMA_ALG_AUTH;
222
223 } else if (strcmp(*argv, "C") == 0) {
224 if (calgop)
225 duparg("ALGOTYPE", *argv);
226 calgop = *argv;
227 type = XFRMA_ALG_COMP;
228 } else
229 invarg("\"ALGOTYPE\" is invalid\n", *argv);
230
231 if (!NEXT_ARG_OK())
232 missarg("ALGONAME");
233 NEXT_ARG();
234 name = *argv;
235
236 if (!NEXT_ARG_OK())
237 missarg("ALGOKEY");
238 NEXT_ARG();
239 key = *argv;
240
241 memset(&alg, 0, sizeof(alg));
242
243 xfrm_algo_parse((void *)&alg, type, name, key, sizeof(alg.buf));
244 len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len;
245
246 addattr_l(&req.n, sizeof(req.buf), type,
247 (void *)&alg, len);
248
249 } else if (strcmp(*argv, "mode") == 0) {
250 NEXT_ARG();
251 xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
252 } else if (strcmp(*argv, "reqid") == 0) {
253 NEXT_ARG();
254 xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
255 } else if (strcmp(*argv, "flag") == 0) {
256 NEXT_ARG();
257 xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
258 } else if (strcmp(*argv, "sel") == 0) {
259 NEXT_ARG();
260 xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
261
262 } else if (strcmp(*argv, "limit") == 0) {
263 NEXT_ARG();
264 xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
265 } else {
266 if (idp)
267 invarg("unknown", *argv);
268 idp = *argv;
269
270 /* ID */
271 xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
272 &req.xsinfo.family, &argc, &argv);
273 if (preferred_family == AF_UNSPEC)
274 preferred_family = req.xsinfo.family;
275 }
276 argc--; argv++;
277 }
278
279 if (!idp) {
280 fprintf(stderr, "Not enough information: \"ID\" is required\n");
281 exit(1);
282 }
283
284 if (ealgop || aalgop || calgop) {
285 if (req.xsinfo.id.proto != IPPROTO_ESP &&
286 req.xsinfo.id.proto != IPPROTO_AH &&
287 req.xsinfo.id.proto != IPPROTO_COMP) {
288 fprintf(stderr, "\"ALGO\" is invalid with proto=%d\n", req.xsinfo.id.proto);
289 exit(1);
290 }
291 } else {
292 if (req.xsinfo.id.proto == IPPROTO_ESP ||
293 req.xsinfo.id.proto == IPPROTO_AH ||
294 req.xsinfo.id.proto == IPPROTO_COMP) {
295 fprintf(stderr, "\"ALGO\" is required with proto=%d\n", req.xsinfo.id.proto);
296 exit (1);
297 }
298 }
299
300 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
301 exit(1);
302
303 if (req.xsinfo.family == AF_UNSPEC)
304 req.xsinfo.family = AF_INET;
305
306 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
307 exit(2);
308
309 rtnl_close(&rth);
310
311 return 0;
312 }
313
314 static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
315 {
316 if (!filter.use)
317 return 1;
318
319 if (filter.id_src_mask)
320 if (memcmp(&xsinfo->saddr, &filter.xsinfo.saddr,
321 filter.id_src_mask) != 0)
322 return 0;
323 if (filter.id_dst_mask)
324 if (memcmp(&xsinfo->id.daddr, &filter.xsinfo.id.daddr,
325 filter.id_dst_mask) != 0)
326 return 0;
327 if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask)
328 return 0;
329 if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask)
330 return 0;
331 if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask)
332 return 0;
333 if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask)
334 return 0;
335 if (filter.state_flags_mask)
336 if ((xsinfo->flags & filter.xsinfo.flags) == 0)
337 return 0;
338
339 return 1;
340 }
341
342 int xfrm_state_print(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
343 {
344 FILE *fp = (FILE*)arg;
345 struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
346 int len = n->nlmsg_len;
347 struct rtattr * tb[XFRMA_MAX+1];
348 int ntb;
349
350 if (n->nlmsg_type != XFRM_MSG_NEWSA &&
351 n->nlmsg_type != XFRM_MSG_DELSA) {
352 fprintf(stderr, "Not a state: %08x %08x %08x\n",
353 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
354 return 0;
355 }
356
357 len -= NLMSG_LENGTH(sizeof(*xsinfo));
358 if (len < 0) {
359 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
360 return -1;
361 }
362
363 if (!xfrm_state_filter_match(xsinfo))
364 return 0;
365
366 memset(tb, 0, sizeof(tb));
367 ntb = parse_rtattr_byindex(tb, XFRM_MAX_DEPTH, XFRMS_RTA(xsinfo), len);
368
369 if (n->nlmsg_type == XFRM_MSG_DELSA)
370 fprintf(fp, "Deleted ");
371
372 xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode,
373 xsinfo->reqid, xsinfo->family, fp, NULL);
374
375 fprintf(fp, "\t");
376 if (show_stats > 0) {
377 fprintf(fp, "seq 0x%08u ", xsinfo->seq);
378 fprintf(fp, "replay-window %d ", xsinfo->replay_window);
379 }
380 fprintf(fp, "flag 0x%s", strxf_flags(xsinfo->flags));
381 if (show_stats > 0) {
382 if (xsinfo->flags) {
383 fprintf(fp, "(");
384 if (xsinfo->flags & XFRM_STATE_NOECN)
385 fprintf(fp, "noecn");
386 fprintf(fp, ")");
387 }
388 }
389 fprintf(fp, "\n");
390
391 xfrm_xfrma_print(tb, ntb, xsinfo->family, fp, "\t");
392
393 if (show_stats > 0) {
394 fprintf(fp, "\tsel\n");
395 xfrm_selector_print(&xsinfo->sel, xsinfo->family, fp, "\t ");
396 }
397
398 if (show_stats > 0) {
399 xfrm_lifetime_print(&xsinfo->lft, &xsinfo->curlft, fp, "\t");
400 xfrm_stats_print(&xsinfo->stats, fp, "\t");
401 }
402
403 return 0;
404 }
405
406 static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
407 {
408 struct rtnl_handle rth;
409 struct {
410 struct nlmsghdr n;
411 struct xfrm_usersa_id xsid;
412 } req;
413 struct xfrm_id id;
414 char *idp = NULL;
415
416 memset(&req, 0, sizeof(req));
417
418 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid));
419 req.n.nlmsg_flags = NLM_F_REQUEST;
420 req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA;
421 req.xsid.family = preferred_family;
422
423 while (argc > 0) {
424 /*
425 * XXX: Source address is not used and ignore it to follow
426 * XXX: a manner of setkey e.g. in the case of deleting/getting
427 * XXX: message of IPsec SA.
428 */
429 xfrm_address_t ignore_saddr;
430
431 if (idp)
432 invarg("unknown", *argv);
433 idp = *argv;
434
435 /* ID */
436 memset(&id, 0, sizeof(id));
437 xfrm_id_parse(&ignore_saddr, &id, &req.xsid.family,
438 &argc, &argv);
439
440 memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
441 req.xsid.spi = id.spi;
442 req.xsid.proto = id.proto;
443
444 argc--; argv++;
445 }
446
447 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
448 exit(1);
449
450 if (req.xsid.family == AF_UNSPEC)
451 req.xsid.family = AF_INET;
452
453 if (delete) {
454 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
455 exit(2);
456 } else {
457 char buf[NLMSG_BUF_SIZE];
458 struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
459
460 memset(buf, 0, sizeof(buf));
461
462 if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
463 exit(2);
464
465 if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
466 fprintf(stderr, "An error :-)\n");
467 exit(1);
468 }
469 }
470
471 rtnl_close(&rth);
472
473 return 0;
474 }
475
476 /*
477 * With an existing state of nlmsg, make new nlmsg for deleting the state
478 * and store it to buffer.
479 */
480 int xfrm_state_keep(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
481 {
482 struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
483 struct rtnl_handle *rth = xb->rth;
484 struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
485 int len = n->nlmsg_len;
486 struct nlmsghdr *new_n;
487 struct xfrm_usersa_id *xsid;
488
489 if (n->nlmsg_type != XFRM_MSG_NEWSA) {
490 fprintf(stderr, "Not a state: %08x %08x %08x\n",
491 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
492 return 0;
493 }
494
495 len -= NLMSG_LENGTH(sizeof(*xsinfo));
496 if (len < 0) {
497 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
498 return -1;
499 }
500
501 if (!xfrm_state_filter_match(xsinfo))
502 return 0;
503
504 if (xb->offset > xb->size) {
505 fprintf(stderr, "Flush buffer overflow\n");
506 return -1;
507 }
508
509 new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
510 new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid));
511 new_n->nlmsg_flags = NLM_F_REQUEST;
512 new_n->nlmsg_type = XFRM_MSG_DELSA;
513 new_n->nlmsg_seq = ++rth->seq;
514
515 xsid = NLMSG_DATA(new_n);
516 xsid->family = xsinfo->family;
517 memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr));
518 xsid->spi = xsinfo->id.spi;
519 xsid->proto = xsinfo->id.proto;
520
521 xb->offset += new_n->nlmsg_len;
522 xb->nlmsg_count ++;
523
524 return 0;
525 }
526
527 static int xfrm_state_list_or_flush(int argc, char **argv, int flush)
528 {
529 char *idp = NULL;
530 struct rtnl_handle rth;
531
532 filter.use = 1;
533 filter.xsinfo.family = preferred_family;
534
535 while (argc > 0) {
536 if (strcmp(*argv, "mode") == 0) {
537 NEXT_ARG();
538 xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
539
540 filter.mode_mask = XFRM_FILTER_MASK_FULL;
541
542 } else if (strcmp(*argv, "reqid") == 0) {
543 NEXT_ARG();
544 xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv);
545
546 filter.reqid_mask = XFRM_FILTER_MASK_FULL;
547
548 } else if (strcmp(*argv, "flag") == 0) {
549 NEXT_ARG();
550 xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv);
551
552 filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
553
554 } else {
555 if (idp)
556 invarg("unknown", *argv);
557 idp = *argv;
558
559 /* ID */
560 xfrm_id_parse(&filter.xsinfo.saddr,
561 &filter.xsinfo.id,
562 &filter.xsinfo.family, &argc, &argv);
563 if (preferred_family == AF_UNSPEC)
564 preferred_family = filter.xsinfo.family;
565 }
566 argc--; argv++;
567 }
568
569 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
570 exit(1);
571
572 if (flush) {
573 struct xfrm_buffer xb;
574 char buf[NLMSG_FLUSH_BUF_SIZE];
575 int i;
576
577 xb.buf = buf;
578 xb.size = sizeof(buf);
579 xb.rth = &rth;
580
581 for (i = 0; ; i++) {
582 xb.offset = 0;
583 xb.nlmsg_count = 0;
584
585 if (show_stats > 1)
586 fprintf(stderr, "Flush round = %d\n", i);
587
588 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
589 perror("Cannot send dump request");
590 exit(1);
591 }
592
593 if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb, NULL, NULL) < 0) {
594 fprintf(stderr, "Flush terminated\n");
595 exit(1);
596 }
597 if (xb.nlmsg_count == 0) {
598 if (show_stats > 1)
599 fprintf(stderr, "Flush completed\n");
600 break;
601 }
602
603 if (rtnl_send(&rth, xb.buf, xb.offset) < 0) {
604 perror("Failed to send flush request\n");
605 exit(1);
606 }
607 if (show_stats > 1)
608 fprintf(stderr, "Flushed nlmsg count = %d\n", xb.nlmsg_count);
609
610 xb.offset = 0;
611 xb.nlmsg_count = 0;
612 }
613
614 } else {
615 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
616 perror("Cannot send dump request");
617 exit(1);
618 }
619
620 if (rtnl_dump_filter(&rth, xfrm_state_print, stdout, NULL, NULL) < 0) {
621 fprintf(stderr, "Dump terminated\n");
622 exit(1);
623 }
624 }
625
626 rtnl_close(&rth);
627
628 exit(0);
629 }
630
631 int do_xfrm_state(int argc, char **argv)
632 {
633 if (argc < 1)
634 return xfrm_state_list_or_flush(0, NULL, 0);
635
636 if (matches(*argv, "add") == 0)
637 return xfrm_state_modify(XFRM_MSG_NEWSA, 0,
638 argc-1, argv+1);
639 if (matches(*argv, "update") == 0)
640 return xfrm_state_modify(XFRM_MSG_UPDSA, 0,
641 argc-1, argv+1);
642 if (matches(*argv, "delete") == 0 || matches(*argv, "del") == 0)
643 return xfrm_state_get_or_delete(argc-1, argv+1, 1);
644 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
645 || matches(*argv, "lst") == 0)
646 return xfrm_state_list_or_flush(argc-1, argv+1, 0);
647 if (matches(*argv, "get") == 0)
648 return xfrm_state_get_or_delete(argc-1, argv+1, 0);
649 if (matches(*argv, "flush") == 0)
650 return xfrm_state_list_or_flush(argc-1, argv+1, 1);
651 if (matches(*argv, "help") == 0)
652 usage();
653 fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
654 exit(-1);
655 }