]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/ipxfrm.c
build netem as .so again.
[mirror_iproute2.git] / ip / ipxfrm.c
CommitLineData
c7699875 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 ip.c, 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 <sys/types.h>
32#include <sys/socket.h>
33#include <time.h>
34#include <netdb.h>
35#include <net/if.h>
36#include <linux/netlink.h>
37#include <linux/rtnetlink.h>
38#include <linux/xfrm.h>
39
40#include "utils.h"
41#include "xfrm.h"
42
43struct xfrm_filter filter;
44
45static void usage(void) __attribute__((noreturn));
46
47static void usage(void)
48{
49 fprintf(stderr,
50 "Usage: ip xfrm XFRM_OBJECT { COMMAND | help }\n"
51 "where XFRM_OBJECT := { state | policy }\n");
52 exit(-1);
53}
54
55const char *strxf_flags(__u8 flags)
56{
57 static char str[16];
58 const int sn = sizeof(flags) * 8 - 1;
59 __u8 b;
60 int i = 0;
61
62 for (b = (1 << sn); b > 0; b >>= 1)
63 str[i++] = ((b & flags) ? '1' : '0');
64 str[i] = '\0';
65
66 return str;
67}
68
69const char *strxf_share(__u8 share)
70{
71 static char str[32];
72
73 switch (share) {
74 case XFRM_SHARE_ANY:
75 strcpy(str, "any");
76 break;
77 case XFRM_SHARE_SESSION:
78 strcpy(str, "session");
79 break;
80 case XFRM_SHARE_USER:
81 strcpy(str, "user");
82 break;
83 case XFRM_SHARE_UNIQUE:
84 strcpy(str, "unique");
85 break;
86 default:
87 sprintf(str, "unknown-share(%d)", share);
88 break;
89 }
90
91 return str;
92}
93
ad273962 94const char *strxf_proto(__u8 proto)
95{
96 static char buf[32];
97 struct protoent *pp;
98 const char *p;
99
100 pp = getprotobynumber(proto);
101 if (pp)
102 p = pp->p_name;
103 else {
104 sprintf(buf, "%d", proto);
105 p = buf;
106 }
107
108 return p;
109}
110
c7699875 111void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
112 __u8 mode, __u32 reqid, __u16 family, FILE *fp,
113 const char *prefix)
114{
115 char abuf[256];
116 __u32 spi;
117 struct protoent *pp;
118 char pbuf[32];
119 char *p;
120
121 if (prefix)
122 fprintf(fp, prefix);
123
124 memset(abuf, '\0', sizeof(abuf));
ad273962 125 fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr),
126 saddr, abuf, sizeof(abuf)));
c7699875 127 memset(abuf, '\0', sizeof(abuf));
ad273962 128 fprintf(fp, "dst %s\n", rt_addr_n2a(family, sizeof(id->daddr),
129 &id->daddr, abuf, sizeof(abuf)));
c7699875 130
131 if (prefix)
132 fprintf(fp, prefix);
133 fprintf(fp, "\t");
134
135 pp = getprotobynumber(id->proto);
136 if (pp)
137 p = pp->p_name;
138 else {
139 sprintf(pbuf, "%d", id->proto);
140 p = pbuf;
141 }
ad273962 142 fprintf(fp, "proto %s ", p);
c7699875 143
ad273962 144 spi = ntohl(id->spi);
145 fprintf(fp, "spi %u", spi);
146 if (show_stats > 0)
147 fprintf(fp, "(0x%08x)", spi);
148 fprintf(fp, " ");
c7699875 149
ad273962 150 fprintf(fp, "reqid %u", reqid);
151 if (show_stats > 0)
152 fprintf(fp, "(0x%08x)", reqid);
153 fprintf(fp, " ");
c7699875 154
ad273962 155 fprintf(fp, "mode %s\n", (mode ? "tunnel" : "transport"));
c7699875 156}
157
158static const char *strxf_limit(__u64 limit)
159{
160 static char str[32];
161 if (limit == XFRM_INF)
162 strcpy(str, "(INF)");
163 else
164 sprintf(str, "%llu", limit);
165
166 return str;
167}
168
169void xfrm_stats_print(struct xfrm_stats *s, FILE *fp, const char *prefix)
170{
171 if (prefix)
172 fprintf(fp, prefix);
173 fprintf(fp, "stats:\n");
174
175 if (prefix)
176 fprintf(fp, prefix);
177 fprintf(fp, " ");
178 fprintf(fp, "replay-window %d ", s->replay_window);
179 fprintf(fp, "replay %d ", s->replay);
180 fprintf(fp, "failed %d", s->integrity_failed);
181 fprintf(fp, "\n");
182}
183
184static const char *strxf_time(__u64 time)
185{
186 static char str[32];
187 struct tm *tp;
188 time_t t;
189
190 if (time == 0) {
191 strcpy(str, "(undefined)");
192 } else {
193 /* XXX: treat time in the same manner of xfrm_{user,state}.c */
194 t = (long)time;
195 tp = localtime(&t);
196
197 sprintf(str, "%04d/%02d/%02d %02d:%02d:%02d",
198 tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday,
199 tp->tm_hour, tp->tm_min, tp->tm_sec);
200 }
201
202 return str;
203}
204
205void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
206 struct xfrm_lifetime_cur *cur,
207 FILE *fp, const char *prefix)
208{
209 if (cfg) {
210 if (prefix)
211 fprintf(fp, prefix);
212 fprintf(fp, "lifetime config:\n");
213
214 if (prefix)
215 fprintf(fp, prefix);
216 fprintf(fp, " ");
217 fprintf(fp, "limit: ");
218 fprintf(fp, "soft ");
219 fprintf(fp, strxf_limit(cfg->soft_byte_limit));
220 fprintf(fp, "(bytes), hard ");
221 fprintf(fp, strxf_limit(cfg->hard_byte_limit));
222 fprintf(fp, "(bytes)\n");
223
224 if (prefix)
225 fprintf(fp, prefix);
226 fprintf(fp, " ");
227 fprintf(fp, "limit: ");
228 fprintf(fp, "soft ");
229 fprintf(fp, strxf_limit(cfg->soft_packet_limit));
230 fprintf(fp, "(packets), hard ");
231 fprintf(fp, strxf_limit(cfg->hard_packet_limit));
232 fprintf(fp, "(packets)\n");
233
234 if (prefix)
235 fprintf(fp, prefix);
236 fprintf(fp, " ");
237 fprintf(fp, "expire add: ");
238 fprintf(fp, "soft ");
239 fprintf(fp, "%llu", cfg->soft_add_expires_seconds);
240 fprintf(fp, "(sec), hard ");
241 fprintf(fp, "%llu", cfg->hard_add_expires_seconds);
242 fprintf(fp, "(sec)\n");
243
244 if (prefix)
245 fprintf(fp, prefix);
246 fprintf(fp, " ");
247 fprintf(fp, "expire use: ");
248 fprintf(fp, "soft ");
249 fprintf(fp, "%llu", cfg->soft_use_expires_seconds);
250 fprintf(fp, "(sec), hard ");
251 fprintf(fp, "%llu", cfg->hard_use_expires_seconds);
252 fprintf(fp, "(sec)\n");
253 }
254 if (cur) {
255 if (prefix)
256 fprintf(fp, prefix);
257 fprintf(fp, "lifetime current:\n");
258
259 if (prefix)
260 fprintf(fp, prefix);
261 fprintf(fp, " ");
262 fprintf(fp, "%llu(bytes), ", cur->bytes);
263 fprintf(fp, "%llu(packets)\n", cur->packets);
264 if (prefix)
265 fprintf(fp, prefix);
266 fprintf(fp, " ");
267 fprintf(fp, "add %s ", strxf_time(cur->add_time));
268 fprintf(fp, "use %s", strxf_time(cur->use_time));
269 fprintf(fp, "\n");
270 }
271}
272
273void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
274 FILE *fp, const char *prefix)
275{
276 char abuf[256];
277 __u16 f;
278
279 f = sel->family;
280 if (f == AF_UNSPEC)
281 f = family;
282 if (f == AF_UNSPEC)
283 f = preferred_family;
284
285 if (prefix)
286 fprintf(fp, prefix);
287
288 memset(abuf, '\0', sizeof(abuf));
ad273962 289 fprintf(fp, "src %s/%d ", rt_addr_n2a(f, sizeof(sel->saddr),
290 &sel->saddr, abuf, sizeof(abuf)),
291 sel->prefixlen_s);
c7699875 292
293 memset(abuf, '\0', sizeof(abuf));
ad273962 294 fprintf(fp, "dst %s/%d", rt_addr_n2a(f, sizeof(sel->daddr),
295 &sel->daddr, abuf, sizeof(abuf)),
296 sel->prefixlen_d);
c7699875 297
298 fprintf(fp, "\n");
299
300 if (prefix)
301 fprintf(fp, prefix);
302 fprintf(fp, "\t");
303
ad273962 304 fprintf(fp, "upspec proto %u ", sel->proto);
305 fprintf(fp, "sport %u dport %u ", sel->sport, sel->dport);
c7699875 306
307 if (sel->ifindex > 0) {
308 char buf[IF_NAMESIZE];
309
310 memset(buf, '\0', sizeof(buf));
311 if_indextoname(sel->ifindex, buf);
312 fprintf(fp, "dev %s ", buf);
ad273962 313 }
c7699875 314
ad273962 315 if (show_stats > 0)
316 fprintf(fp, "uid %u", sel->user);
c7699875 317 fprintf(fp, "\n");
318}
319
320static void xfrm_algo_print(struct xfrm_algo *algo, FILE *fp,
321 const char *prefix)
322{
323 int len;
324 int i;
325
326 if (prefix)
327 fprintf(fp, prefix);
328
329 fprintf(fp, "%s", algo->alg_name);
330
331 len = algo->alg_key_len / 8;
332 for (i = 0; i < len; i ++) {
333 if (i % 4 == 0)
334 fprintf(fp, " ");
335 fprintf(fp, "%x", algo->alg_key[i]);
336 }
337
338 fprintf(fp, "\n");
339}
340
341static const char *strxf_mask(__u32 mask)
342{
343 static char str[128];
344 const int sn = sizeof(mask) * 8 - 1;
345 __u32 b;
346 int finish = 0;
347 int broken = 0;
348 int i = 0;
349
350 for (b = (1 << sn); b > 0; b >>= 1) {
351 if ((b & mask) == 0) {
352 if (!finish)
353 finish = 1;
354 } else {
355 if (!finish)
356 i ++;
357 else {
358 broken = 1;
359 break;
360 }
361 }
362 }
363
364 if (!broken)
365 sprintf(str, "%u", i);
366 else
367 sprintf(str, "broken(%u)", mask);
368
369 return str;
370}
371
372static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int ntmpls,
373 __u16 family, FILE *fp, const char *prefix)
374{
c7699875 375 int i;
376
c7699875 377 for (i = 0; i < ntmpls; i++) {
378 struct xfrm_user_tmpl *tmpl = &tmpls[i];
379
380 if (prefix)
381 fprintf(fp, prefix);
ad273962 382
383 fprintf(fp, "tmpl");
c7699875 384 xfrm_id_info_print(&tmpl->saddr, &tmpl->id, tmpl->mode,
ad273962 385 tmpl->reqid, family, fp, prefix);
c7699875 386
ad273962 387 fprintf(fp, prefix);
c7699875 388 fprintf(fp, "\t");
ad273962 389 fprintf(fp, "level ");
390 switch (tmpl->optional) {
391 case 0:
392 fprintf(fp, "required");
393 break;
394 case 1:
395 fprintf(fp, "use");
396 break;
397 default:
398 fprintf(fp, "%d", tmpl->optional);
399 break;
400 }
401 fprintf(fp, " ");
402
403 if (show_stats > 0) {
404 fprintf(fp, "share %s ", strxf_share(tmpl->share));
405 fprintf(fp, "algo-mask:");
406 fprintf(fp, "E=%s, ", strxf_mask(tmpl->ealgos));
407 fprintf(fp, "A=%s, ", strxf_mask(tmpl->aalgos));
408 fprintf(fp, "C=%s", strxf_mask(tmpl->calgos));
409 }
c7699875 410 fprintf(fp, "\n");
411 }
412}
413
414void xfrm_xfrma_print(struct rtattr *tb[], int ntb, __u16 family,
415 FILE *fp, const char *prefix)
416{
417 int i;
418
419 for (i = 0; i < ntb; i++) {
420 __u16 type = tb[i]->rta_type;
421 void *data = RTA_DATA(tb[i]);
422
423 switch (type) {
424 case XFRMA_ALG_CRYPT:
425 if (prefix)
426 fprintf(fp, prefix);
ad273962 427 xfrm_algo_print((struct xfrm_algo *)data, fp, "algo E ");
c7699875 428 break;
429 case XFRMA_ALG_AUTH:
430 if (prefix)
431 fprintf(fp, prefix);
ad273962 432 xfrm_algo_print((struct xfrm_algo *)data, fp, "algo A ");
c7699875 433 break;
434 case XFRMA_ALG_COMP:
435 if (prefix)
436 fprintf(fp, prefix);
ad273962 437 xfrm_algo_print((struct xfrm_algo *)data, fp, "algo C ");
c7699875 438 break;
439 case XFRMA_ENCAP:
440 if (prefix)
441 fprintf(fp, prefix);
442 /* XXX */
443 fprintf(fp, "encap: (not implemented yet!)\n");
444 break;
445 case XFRMA_TMPL:
446 {
447 int len = tb[i]->rta_len;
448 int ntmpls = len / sizeof(struct xfrm_user_tmpl);
449
450 xfrm_tmpl_print((struct xfrm_user_tmpl *)data,
451 ntmpls, family, fp, prefix);
452 break;
453 }
454 default:
455 if (prefix)
456 fprintf(fp, prefix);
457 fprintf(fp, "unknown rta_type: %u\n", type);
458 break;
459 }
460 }
461}
462
463int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,
464 int *argcp, char ***argvp)
465{
466 int argc = *argcp;
467 char **argv = *argvp;
468 inet_prefix dst;
469 inet_prefix src;
470 __u8 proto = 0;
471
472 memset(&dst, 0, sizeof(dst));
473 memset(&src, 0, sizeof(src));
474
475 while (1) {
476 if (strcmp(*argv, "src") == 0) {
477 NEXT_ARG();
478
479 get_prefix(&src, *argv, preferred_family);
480 if (src.family == AF_UNSPEC)
481 invarg("\"SADDR\" address family is AF_UNSPEC", *argv);
482 if (family)
483 *family = src.family;
484
485 memcpy(saddr, &src.data, sizeof(*saddr));
486
487 filter.id_src_mask = src.bitlen;
488
489 } else if (strcmp(*argv, "dst") == 0) {
490 NEXT_ARG();
491
492 get_prefix(&dst, *argv, preferred_family);
493 if (dst.family == AF_UNSPEC)
494 invarg("\"DADDR\" address family is AF_UNSPEC", *argv);
495 if (family)
496 *family = dst.family;
497
498 memcpy(&id->daddr, &dst.data, sizeof(id->daddr));
499
500 filter.id_dst_mask = dst.bitlen;
501
502 } else if (strcmp(*argv, "proto") == 0) {
503 struct protoent *pp;
504
505 NEXT_ARG();
506
507 pp = getprotobyname(*argv);
508 if (pp)
509 proto = pp->p_proto;
510 else {
511 if (get_u8(&proto, *argv, 0))
512 invarg("\"PROTO\" is invalid", *argv);
513 }
514
515 switch (proto) {
516 case IPPROTO_ESP:
517 case IPPROTO_AH:
518 case IPPROTO_COMP:
519 id->proto = proto;
520 break;
521 default:
522 invarg("\"PROTO\" is unsuppored proto", *argv);
523 }
524
525 filter.id_proto_mask = XFRM_FILTER_MASK_FULL;
526
527 } else if (strcmp(*argv, "spi") == 0) {
528 __u32 spi;
529
530 NEXT_ARG();
531 if (get_u32(&spi, *argv, 0))
532 invarg("\"SPI\" is invalid", *argv);
533
534 spi = htonl(spi);
535 id->spi = spi;
536
537 filter.id_spi_mask = XFRM_FILTER_MASK_FULL;
538
539 } else {
540 PREV_ARG(); /* back track */
541 break;
542 }
543
544 if (!NEXT_ARG_OK())
545 break;
546 NEXT_ARG();
547 }
548
549 if (src.family && dst.family && (src.family != dst.family))
550 invarg("the same address family is required between \"SADDR\" and \"DADDR\"", *argv);
551 if (proto == 0)
552 missarg("PROTO");
553
554 if (argc == *argcp)
555 missarg("ID");
556
557 *argcp = argc;
558 *argvp = argv;
559
560 return 0;
561}
562
563int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
564{
565 int argc = *argcp;
566 char **argv = *argvp;
567
568 if (matches(*argv, "transport") == 0)
569 *mode = 0;
570 else if (matches(*argv, "tunnel") == 0)
571 *mode = 1;
572 else
573 invarg("\"MODE\" is invalid", *argv);
574
575 *argcp = argc;
576 *argvp = argv;
577
578 return 0;
579}
580
581/* NOTE: reqid is used by host-byte order */
582int xfrm_reqid_parse(__u32 *reqid, int *argcp, char ***argvp)
583{
584 int argc = *argcp;
585 char **argv = *argvp;
586
587 if (get_u32(reqid, *argv, 0))
588 invarg("\"REQID\" is invalid", *argv);
589
590 *argcp = argc;
591 *argvp = argv;
592
593 return 0;
594}
595
596static int xfrm_selector_upspec_parse(struct xfrm_selector *sel,
597 int *argcp, char ***argvp)
598{
599 int argc = *argcp;
600 char **argv = *argvp;
601 __u8 upspec;
602
603 while (1) {
604 if (strcmp(*argv, "proto") == 0) {
605 NEXT_ARG();
606
607 if (strcmp(*argv, "any") == 0)
608 upspec = 0;
609 else {
610 struct protoent *pp;
611 pp = getprotobyname(*argv);
612 if (pp)
613 upspec = pp->p_proto;
614 else {
615 if (get_u8(&upspec, *argv, 0))
616 invarg("\"UPSPEC\" is invalid", *argv);
617 }
618 }
619 sel->proto = upspec;
620
621 filter.upspec_proto_mask = XFRM_FILTER_MASK_FULL;
622
623 } else if (strcmp(*argv, "sport") == 0) {
624 NEXT_ARG();
625
626 if (get_u16(&sel->sport, *argv, 0))
627 invarg("\"PORT\" is invalid", *argv);
628 sel->sport = htons(sel->sport);
629 if (sel->sport)
630 sel->sport_mask = ~((__u16)0);
631
632 filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
633
634 } else if (strcmp(*argv, "dport") == 0) {
635 NEXT_ARG();
636
637 if (get_u16(&sel->dport, *argv, 0))
638 invarg("\"PORT\" is invalid", *argv);
639 sel->dport = htons(sel->dport);
640 if (sel->dport)
641 sel->dport_mask = ~((__u16)0);
642
643 filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
644
645 } else {
646 PREV_ARG(); /* back track */
647 break;
648 }
649
650 if (!NEXT_ARG_OK())
651 break;
652 NEXT_ARG();
653 }
654 if (argc == *argcp)
655 missarg("UPSPEC");
656
657 *argcp = argc;
658 *argvp = argv;
659
660 return 0;
661}
662
663int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp)
664{
665 int argc = *argcp;
666 char **argv = *argvp;
667 inet_prefix dst;
668 inet_prefix src;
669
670 memset(&dst, 0, sizeof(dst));
671 memset(&src, 0, sizeof(src));
672
673 while (1) {
674 if (strcmp(*argv, "src") == 0) {
675 NEXT_ARG();
676
677 get_prefix(&src, *argv, preferred_family);
678 if (src.family == AF_UNSPEC)
679 invarg("\"SADDR\" address family is AF_UNSPEC", *argv);
680 sel->family = src.family;
681
682 memcpy(&sel->saddr, &src.data, sizeof(sel->saddr));
683 sel->prefixlen_s = src.bitlen;
684
685 filter.sel_src_mask = src.bitlen;
686
687 } else if (strcmp(*argv, "dst") == 0) {
688 NEXT_ARG();
689
690 get_prefix(&dst, *argv, preferred_family);
691 if (dst.family == AF_UNSPEC)
692 invarg("\"DADDR\" address family is AF_UNSPEC", *argv);
693 sel->family = dst.family;
694
695 memcpy(&sel->daddr, &dst.data, sizeof(sel->daddr));
696 sel->prefixlen_d = dst.bitlen;
697
698 filter.sel_dst_mask = dst.bitlen;
699
700 } else if (strcmp(*argv, "upspec") == 0) {
701 NEXT_ARG();
702
703 xfrm_selector_upspec_parse(sel, &argc, &argv);
704
705 } else if (strcmp(*argv, "dev") == 0) {
706 int ifindex;
707
708 NEXT_ARG();
709
710 if (strcmp(*argv, "none") == 0)
711 ifindex = 0;
712 else {
713 ifindex = if_nametoindex(*argv);
714 if (ifindex <= 0)
715 invarg("\"DEV\" is invalid", *argv);
716 }
717 sel->ifindex = ifindex;
718
719 filter.sel_dev_mask = XFRM_FILTER_MASK_FULL;
720
721 } else {
722 PREV_ARG(); /* back track */
723 break;
724 }
725
726 if (!NEXT_ARG_OK())
727 break;
728
729 NEXT_ARG();
730 }
731
732 if (src.family && dst.family && (src.family != dst.family))
733 invarg("the same address family is required between \"SADDR\" and \"DADDR\"", *argv);
734
735 if (argc == *argcp)
736 missarg("SELECTOR");
737
738 *argcp = argc;
739 *argvp = argv;
740
741 return 0;
742}
743
744int xfrm_lifetime_cfg_parse(struct xfrm_lifetime_cfg *lft,
745 int *argcp, char ***argvp)
746{
747 int argc = *argcp;
748 char **argv = *argvp;
749 int ret;
750
751 if (strcmp(*argv, "time-soft") == 0) {
752 NEXT_ARG();
753 ret = get_u64(&lft->soft_add_expires_seconds, *argv, 0);
754 if (ret)
755 invarg("\"time-soft\" value is invalid", *argv);
756 } else if (strcmp(*argv, "time-hard") == 0) {
757 NEXT_ARG();
758 ret = get_u64(&lft->hard_add_expires_seconds, *argv, 0);
759 if (ret)
760 invarg("\"time-hard\" value is invalid", *argv);
761 } else if (strcmp(*argv, "time-use-soft") == 0) {
762 NEXT_ARG();
763 ret = get_u64(&lft->soft_use_expires_seconds, *argv, 0);
764 if (ret)
765 invarg("\"time-use-soft\" value is invalid", *argv);
766 } else if (strcmp(*argv, "time-use-hard") == 0) {
767 NEXT_ARG();
768 ret = get_u64(&lft->hard_use_expires_seconds, *argv, 0);
769 if (ret)
770 invarg("\"time-use-hard\" value is invalid", *argv);
771 } else if (strcmp(*argv, "byte-soft") == 0) {
772 NEXT_ARG();
773 ret = get_u64(&lft->soft_byte_limit, *argv, 0);
774 if (ret)
775 invarg("\"byte-soft\" value is invalid", *argv);
776 } else if (strcmp(*argv, "byte-hard") == 0) {
777 NEXT_ARG();
778 ret = get_u64(&lft->hard_byte_limit, *argv, 0);
779 if (ret)
780 invarg("\"byte-hard\" value is invalid", *argv);
781 } else if (strcmp(*argv, "packet-soft") == 0) {
782 NEXT_ARG();
783 ret = get_u64(&lft->soft_packet_limit, *argv, 0);
784 if (ret)
785 invarg("\"packet-soft\" value is invalid", *argv);
786 } else if (strcmp(*argv, "packet-hard") == 0) {
787 NEXT_ARG();
788 ret = get_u64(&lft->hard_packet_limit, *argv, 0);
789 if (ret)
790 invarg("\"packet-hard\" value is invalid", *argv);
791 } else
792 invarg("\"LIMIT\" is invalid", *argv);
793
794 *argcp = argc;
795 *argvp = argv;
796
797 return 0;
798}
799
800int do_xfrm(int argc, char **argv)
801{
802 memset(&filter, 0, sizeof(filter));
803
804 if (argc < 1)
805 usage();
806
ad273962 807 if (matches(*argv, "state") == 0 ||
808 matches(*argv, "sa") == 0) {
c7699875 809 return do_xfrm_state(argc-1, argv+1);
ad273962 810 } else if (matches(*argv, "policy") == 0)
c7699875 811 return do_xfrm_policy(argc-1, argv+1);
ad273962 812 else if (matches(*argv, "help") == 0) {
c7699875 813 usage();
814 fprintf(stderr, "xfrm Object \"%s\" is unknown.\n", *argv);
815 exit(-1);
816 }
817 usage();
818}