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 <endian.h>
34#include <time.h>
35#include <netdb.h>
36#include <linux/netlink.h>
37#include <linux/rtnetlink.h>
38#include <linux/xfrm.h>
39#include <linux/in.h>
40#include <linux/in6.h>
41
42#include "utils.h"
43#include "xfrm.h"
44
45#define STRBUF_SIZE	(128)
46#define STRBUF_CAT(buf, str) \
47	do { \
48		int rest = sizeof(buf) - 1 - strlen(buf); \
49		if (rest > 0) { \
50			int len = strlen(str); \
51			if (len > rest) \
52				len = rest; \
53			strncat(buf, str, len); \
54			buf[sizeof(buf) - 1] = '\0'; \
55		} \
56	} while(0);
57
58struct xfrm_filter filter;
59
60static void usage(void) __attribute__((noreturn));
61
62static void usage(void)
63{
64	fprintf(stderr,
65		"Usage: ip xfrm XFRM-OBJECT { COMMAND | help }\n"
66		"where  XFRM-OBJECT := state | policy | monitor\n");
67	exit(-1);
68}
69
70/* This is based on utils.c(inet_addr_match) */
71int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits)
72{
73	__u32 *a1 = (__u32 *)x1;
74	__u32 *a2 = (__u32 *)x2;
75	int words = bits >> 0x05;
76
77	bits &= 0x1f;
78
79	if (words)
80		if (memcmp(a1, a2, words << 2))
81			return -1;
82
83	if (bits) {
84		__u32 w1, w2;
85		__u32 mask;
86
87		w1 = a1[words];
88		w2 = a2[words];
89
90		mask = htonl((0xffffffff) << (0x20 - bits));
91
92		if ((w1 ^ w2) & mask)
93			return 1;
94	}
95
96	return 0;
97}
98
99int xfrm_xfrmproto_is_ipsec(__u8 proto)
100{
101	return (proto ==  IPPROTO_ESP ||
102		proto ==  IPPROTO_AH  ||
103		proto ==  IPPROTO_COMP);
104}
105
106int xfrm_xfrmproto_is_ro(__u8 proto)
107{
108	return (proto ==  IPPROTO_ROUTING ||
109		proto ==  IPPROTO_DSTOPTS);
110}
111
112struct typeent {
113	const char *t_name;
114	int t_type;
115};
116
117static const struct typeent xfrmproto_types[]= {
118	{ "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, { "comp", IPPROTO_COMP },
119	{ "route2", IPPROTO_ROUTING }, { "hao", IPPROTO_DSTOPTS },
120	{ "ipsec-any", IPSEC_PROTO_ANY },
121	{ NULL, -1 }
122};
123
124int xfrm_xfrmproto_getbyname(char *name)
125{
126	int i;
127
128	for (i = 0; ; i++) {
129		const struct typeent *t = &xfrmproto_types[i];
130		if (!t->t_name || t->t_type == -1)
131			break;
132
133		if (strcmp(t->t_name, name) == 0)
134			return t->t_type;
135	}
136
137	return -1;
138}
139
140const char *strxf_xfrmproto(__u8 proto)
141{
142	static char str[16];
143	int i;
144
145	for (i = 0; ; i++) {
146		const struct typeent *t = &xfrmproto_types[i];
147		if (!t->t_name || t->t_type == -1)
148			break;
149
150		if (t->t_type == proto)
151			return t->t_name;
152	}
153
154	sprintf(str, "%u", proto);
155	return str;
156}
157
158static const struct typeent algo_types[]= {
159	{ "enc", XFRMA_ALG_CRYPT }, { "auth", XFRMA_ALG_AUTH },
160	{ "comp", XFRMA_ALG_COMP }, { "aead", XFRMA_ALG_AEAD },
161	{ "auth-trunc", XFRMA_ALG_AUTH_TRUNC },
162	{ NULL, -1 }
163};
164
165int xfrm_algotype_getbyname(char *name)
166{
167	int i;
168
169	for (i = 0; ; i++) {
170		const struct typeent *t = &algo_types[i];
171		if (!t->t_name || t->t_type == -1)
172			break;
173
174		if (strcmp(t->t_name, name) == 0)
175			return t->t_type;
176	}
177
178	return -1;
179}
180
181const char *strxf_algotype(int type)
182{
183	static char str[32];
184	int i;
185
186	for (i = 0; ; i++) {
187		const struct typeent *t = &algo_types[i];
188		if (!t->t_name || t->t_type == -1)
189			break;
190
191		if (t->t_type == type)
192			return t->t_name;
193	}
194
195	sprintf(str, "%d", type);
196	return str;
197}
198
199const char *strxf_mask8(__u8 mask)
200{
201	static char str[16];
202	const int sn = sizeof(mask) * 8 - 1;
203	__u8 b;
204	int i = 0;
205
206	for (b = (1 << sn); b > 0; b >>= 1)
207		str[i++] = ((b & mask) ? '1' : '0');
208	str[i] = '\0';
209
210	return str;
211}
212
213const char *strxf_mask32(__u32 mask)
214{
215	static char str[16];
216
217	sprintf(str, "%.8x", mask);
218
219	return str;
220}
221
222const char *strxf_share(__u8 share)
223{
224	static char str[32];
225
226	switch (share) {
227	case XFRM_SHARE_ANY:
228		strcpy(str, "any");
229		break;
230	case XFRM_SHARE_SESSION:
231		strcpy(str, "session");
232		break;
233	case XFRM_SHARE_USER:
234		strcpy(str, "user");
235		break;
236	case XFRM_SHARE_UNIQUE:
237		strcpy(str, "unique");
238		break;
239	default:
240		sprintf(str, "%u", share);
241		break;
242	}
243
244	return str;
245}
246
247const char *strxf_proto(__u8 proto)
248{
249	static char buf[32];
250	struct protoent *pp;
251	const char *p;
252
253	pp = getprotobynumber(proto);
254	if (pp)
255		p = pp->p_name;
256	else {
257		sprintf(buf, "%u", proto);
258		p = buf;
259	}
260
261	return p;
262}
263
264const char *strxf_ptype(__u8 ptype)
265{
266	static char str[16];
267
268	switch (ptype) {
269	case XFRM_POLICY_TYPE_MAIN:
270		strcpy(str, "main");
271		break;
272	case XFRM_POLICY_TYPE_SUB:
273		strcpy(str, "sub");
274		break;
275	default:
276		sprintf(str, "%u", ptype);
277		break;
278	}
279
280	return str;
281}
282
283void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
284			__u8 mode, __u32 reqid, __u16 family, int force_spi,
285			FILE *fp, const char *prefix, const char *title)
286{
287	char abuf[256];
288
289	if (title)
290		fputs(title, fp);
291
292	memset(abuf, '\0', sizeof(abuf));
293	fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr),
294					   saddr, abuf, sizeof(abuf)));
295	memset(abuf, '\0', sizeof(abuf));
296	fprintf(fp, "dst %s", rt_addr_n2a(family, sizeof(id->daddr),
297					  &id->daddr, abuf, sizeof(abuf)));
298	fprintf(fp, "%s", _SL_);
299
300	if (prefix)
301		fputs(prefix, fp);
302	fprintf(fp, "\t");
303
304	fprintf(fp, "proto %s ", strxf_xfrmproto(id->proto));
305
306	if (show_stats > 0 || force_spi || id->spi) {
307		__u32 spi = ntohl(id->spi);
308		fprintf(fp, "spi 0x%08x", spi);
309		if (show_stats > 0)
310			fprintf(fp, "(%u)", spi);
311		fprintf(fp, " ");
312	}
313
314	fprintf(fp, "reqid %u", reqid);
315	if (show_stats > 0)
316		fprintf(fp, "(0x%08x)", reqid);
317	fprintf(fp, " ");
318
319	fprintf(fp, "mode ");
320	switch (mode) {
321	case XFRM_MODE_TRANSPORT:
322		fprintf(fp, "transport");
323		break;
324	case XFRM_MODE_TUNNEL:
325		fprintf(fp, "tunnel");
326		break;
327	case XFRM_MODE_ROUTEOPTIMIZATION:
328		fprintf(fp, "ro");
329		break;
330	case XFRM_MODE_IN_TRIGGER:
331		fprintf(fp, "in_trigger");
332		break;
333	case XFRM_MODE_BEET:
334		fprintf(fp, "beet");
335		break;
336	default:
337		fprintf(fp, "%u", mode);
338		break;
339	}
340	fprintf(fp, "%s", _SL_);
341}
342
343static const char *strxf_limit(__u64 limit)
344{
345	static char str[32];
346	if (limit == XFRM_INF)
347		strcpy(str, "(INF)");
348	else
349		sprintf(str, "%llu", (unsigned long long) limit);
350
351	return str;
352}
353
354void xfrm_stats_print(struct xfrm_stats *s, FILE *fp, const char *prefix)
355{
356	if (prefix)
357		fputs(prefix, fp);
358	fprintf(fp, "stats:%s", _SL_);
359
360	if (prefix)
361		fputs(prefix, fp);
362	fprintf(fp, "  replay-window %u replay %u failed %u%s",
363		s->replay_window, s->replay, s->integrity_failed, _SL_);
364}
365
366static const char *strxf_time(__u64 time)
367{
368	static char str[32];
369
370	if (time == 0)
371		strcpy(str, "-");
372	else {
373		time_t t;
374		struct tm *tp;
375
376		/* XXX: treat time in the same manner of kernel's
377		 * net/xfrm/xfrm_{user,state}.c
378		 */
379		t = (long)time;
380		tp = localtime(&t);
381
382		strftime(str, sizeof(str), "%Y-%m-%d %T", tp);
383	}
384
385	return str;
386}
387
388void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
389			 struct xfrm_lifetime_cur *cur,
390			 FILE *fp, const char *prefix)
391{
392	if (cfg) {
393		if (prefix)
394			fputs(prefix, fp);
395		fprintf(fp, "lifetime config:%s",_SL_);
396
397		if (prefix)
398			fputs(prefix, fp);
399		fprintf(fp, "  limit: soft %s(bytes),",
400			strxf_limit(cfg->soft_byte_limit));
401		fprintf(fp, " hard %s(bytes)%s",
402			strxf_limit(cfg->hard_byte_limit), _SL_);
403
404		if (prefix)
405			fputs(prefix, fp);
406		fprintf(fp, "  limit: soft %s(packets),",
407			strxf_limit(cfg->soft_packet_limit));
408		fprintf(fp, " hard %s(packets)%s",
409			strxf_limit(cfg->hard_packet_limit), _SL_);
410
411		if (prefix)
412			fputs(prefix, fp);
413		fprintf(fp, "  expire add: soft %llu(sec), hard %llu(sec)%s",
414			(unsigned long long) cfg->soft_add_expires_seconds,
415			(unsigned long long) cfg->hard_add_expires_seconds,
416			_SL_);
417
418		if (prefix)
419			fputs(prefix, fp);
420		fprintf(fp, "  expire use: soft %llu(sec), hard %llu(sec)%s",
421			(unsigned long long) cfg->soft_use_expires_seconds,
422			(unsigned long long) cfg->hard_use_expires_seconds,
423			_SL_);
424	}
425	if (cur) {
426		if (prefix)
427			fputs(prefix, fp);
428		fprintf(fp, "lifetime current:%s", _SL_);
429
430		if (prefix)
431			fputs(prefix, fp);
432		fprintf(fp, "  %llu(bytes), %llu(packets)%s",
433			(unsigned long long) cur->bytes,
434			(unsigned long long) cur->packets,
435			 _SL_);
436
437		if (prefix)
438			fputs(prefix, fp);
439		fprintf(fp, "  add %s ", strxf_time(cur->add_time));
440		fprintf(fp, "use %s%s", strxf_time(cur->use_time), _SL_);
441	}
442}
443
444void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
445			 FILE *fp, const char *prefix)
446{
447	char abuf[256];
448	__u16 f;
449
450	f = sel->family;
451	if (f == AF_UNSPEC)
452		f = family;
453	if (f == AF_UNSPEC)
454		f = preferred_family;
455
456	if (prefix)
457		fputs(prefix, fp);
458
459	memset(abuf, '\0', sizeof(abuf));
460	fprintf(fp, "src %s/%u ", rt_addr_n2a(f, sizeof(sel->saddr),
461					      &sel->saddr, abuf, sizeof(abuf)),
462		sel->prefixlen_s);
463
464	memset(abuf, '\0', sizeof(abuf));
465	fprintf(fp, "dst %s/%u ", rt_addr_n2a(f, sizeof(sel->daddr),
466					      &sel->daddr, abuf, sizeof(abuf)),
467		sel->prefixlen_d);
468
469	if (sel->proto)
470		fprintf(fp, "proto %s ", strxf_proto(sel->proto));
471	switch (sel->proto) {
472	case IPPROTO_TCP:
473	case IPPROTO_UDP:
474	case IPPROTO_SCTP:
475	case IPPROTO_DCCP:
476	default: /* XXX */
477		if (sel->sport_mask)
478			fprintf(fp, "sport %u ", ntohs(sel->sport));
479		if (sel->dport_mask)
480			fprintf(fp, "dport %u ", ntohs(sel->dport));
481		break;
482	case IPPROTO_ICMP:
483	case IPPROTO_ICMPV6:
484		/* type/code is stored at sport/dport in selector */
485		if (sel->sport_mask)
486			fprintf(fp, "type %u ", ntohs(sel->sport));
487		if (sel->dport_mask)
488			fprintf(fp, "code %u ", ntohs(sel->dport));
489		break;
490	case IPPROTO_GRE:
491		if (sel->sport_mask || sel->dport_mask)
492			fprintf(fp, "key %u ",
493				(((__u32)ntohs(sel->sport)) << 16) +
494				ntohs(sel->dport));
495		break;
496	case IPPROTO_MH:
497		if (sel->sport_mask)
498			fprintf(fp, "type %u ", ntohs(sel->sport));
499		if (sel->dport_mask) {
500			if (show_stats > 0)
501				fprintf(fp, "(dport) 0x%.4x ", sel->dport);
502		}
503		break;
504	}
505
506	if (sel->ifindex > 0)
507		fprintf(fp, "dev %s ", ll_index_to_name(sel->ifindex));
508
509	if (show_stats > 0)
510		fprintf(fp, "uid %u", sel->user);
511
512	fprintf(fp, "%s", _SL_);
513}
514
515static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
516			      FILE *fp, const char *prefix, int newline)
517{
518	int keylen;
519	int i;
520
521	if (prefix)
522		fputs(prefix, fp);
523
524	fprintf(fp, "%s ", strxf_algotype(type));
525
526	if (len < sizeof(*algo)) {
527		fprintf(fp, "(ERROR truncated)");
528		goto fin;
529	}
530	len -= sizeof(*algo);
531
532	fprintf(fp, "%s ", algo->alg_name);
533
534	keylen = algo->alg_key_len / 8;
535	if (len < keylen) {
536		fprintf(fp, "(ERROR truncated)");
537		goto fin;
538	}
539
540	fprintf(fp, "0x");
541	for (i = 0; i < keylen; i ++)
542		fprintf(fp, "%.2x", (unsigned char)algo->alg_key[i]);
543
544	if (show_stats > 0)
545		fprintf(fp, " (%d bits)", algo->alg_key_len);
546
547 fin:
548	if (newline)
549		fprintf(fp, "%s", _SL_);
550}
551
552static inline void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
553				   FILE *fp, const char *prefix)
554{
555	return __xfrm_algo_print(algo, type, len, fp, prefix, 1);
556}
557
558static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len,
559			    FILE *fp, const char *prefix)
560{
561	struct {
562		struct xfrm_algo algo;
563		char key[algo->alg_key_len / 8];
564	} base;
565
566	memcpy(base.algo.alg_name, algo->alg_name, sizeof(base.algo.alg_name));
567	base.algo.alg_key_len = algo->alg_key_len;
568	memcpy(base.algo.alg_key, algo->alg_key, algo->alg_key_len / 8);
569
570	__xfrm_algo_print(&base.algo, XFRMA_ALG_AEAD, len, fp, prefix, 0);
571
572	fprintf(fp, " %d", algo->alg_icv_len);
573
574	fprintf(fp, "%s", _SL_);
575}
576
577static void xfrm_auth_trunc_print(struct xfrm_algo_auth *algo, int len,
578				  FILE *fp, const char *prefix)
579{
580	struct {
581		struct xfrm_algo algo;
582		char key[algo->alg_key_len / 8];
583	} base;
584
585	memcpy(base.algo.alg_name, algo->alg_name, sizeof(base.algo.alg_name));
586	base.algo.alg_key_len = algo->alg_key_len;
587	memcpy(base.algo.alg_key, algo->alg_key, algo->alg_key_len / 8);
588
589	__xfrm_algo_print(&base.algo, XFRMA_ALG_AUTH_TRUNC, len, fp, prefix, 0);
590
591	fprintf(fp, " %d", algo->alg_trunc_len);
592
593	fprintf(fp, "%s", _SL_);
594}
595
596static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int len,
597			    __u16 family, FILE *fp, const char *prefix)
598{
599	int ntmpls = len / sizeof(struct xfrm_user_tmpl);
600	int i;
601
602	if (ntmpls <= 0) {
603		if (prefix)
604			fputs(prefix, fp);
605		fprintf(fp, "(ERROR \"tmpl\" truncated)");
606		fprintf(fp, "%s", _SL_);
607		return;
608	}
609
610	for (i = 0; i < ntmpls; i++) {
611		struct xfrm_user_tmpl *tmpl = &tmpls[i];
612
613		if (prefix)
614			fputs(prefix, fp);
615
616		xfrm_id_info_print(&tmpl->saddr, &tmpl->id, tmpl->mode,
617				   tmpl->reqid, tmpl->family, 0, fp, prefix, "tmpl ");
618
619		if (show_stats > 0 || tmpl->optional) {
620			if (prefix)
621				fputs(prefix, fp);
622			fprintf(fp, "\t");
623			switch (tmpl->optional) {
624			case 0:
625				if (show_stats > 0)
626					fprintf(fp, "level required ");
627				break;
628			case 1:
629				fprintf(fp, "level use ");
630				break;
631			default:
632				fprintf(fp, "level %u ", tmpl->optional);
633				break;
634			}
635
636			if (show_stats > 0)
637				fprintf(fp, "share %s ", strxf_share(tmpl->share));
638
639			fprintf(fp, "%s", _SL_);
640		}
641
642		if (show_stats > 0) {
643			if (prefix)
644				fputs(prefix, fp);
645			fprintf(fp, "\t");
646			fprintf(fp, "%s-mask %s ",
647				strxf_algotype(XFRMA_ALG_CRYPT),
648				strxf_mask32(tmpl->ealgos));
649			fprintf(fp, "%s-mask %s ",
650				strxf_algotype(XFRMA_ALG_AUTH),
651				strxf_mask32(tmpl->aalgos));
652			fprintf(fp, "%s-mask %s",
653				strxf_algotype(XFRMA_ALG_COMP),
654				strxf_mask32(tmpl->calgos));
655
656			fprintf(fp, "%s", _SL_);
657		}
658	}
659}
660
661int xfrm_parse_mark(struct xfrm_mark *mark, int *argcp, char ***argvp)
662{
663	int argc = *argcp;
664	char **argv = *argvp;
665
666	NEXT_ARG();
667	if (get_u32(&mark->v, *argv, 0)) {
668		invarg("Illegal \"mark\" value\n", *argv);
669	}
670	if (argc > 1)
671		NEXT_ARG();
672	else { /* last entry on parse line */
673		mark->m = 0xffffffff;
674		goto done;
675	}
676
677	if (strcmp(*argv, "mask") == 0) {
678		NEXT_ARG();
679		if (get_u32(&mark->m, *argv, 0)) {
680			invarg("Illegal \"mark\" mask\n", *argv);
681		}
682	} else {
683		mark->m = 0xffffffff;
684		PREV_ARG();
685	}
686
687done:
688	*argcp = argc;
689	*argvp = argv;
690
691	return 0;
692}
693
694void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
695		      FILE *fp, const char *prefix)
696{
697	if (tb[XFRMA_MARK]) {
698		struct rtattr *rta = tb[XFRMA_MARK];
699		struct xfrm_mark *m = (struct xfrm_mark *) RTA_DATA(rta);
700		fprintf(fp, "\tmark %d/0x%x\n", m->v, m->m);
701	}
702
703	if (tb[XFRMA_ALG_AUTH] && !tb[XFRMA_ALG_AUTH_TRUNC]) {
704		struct rtattr *rta = tb[XFRMA_ALG_AUTH];
705		xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
706				XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix);
707	}
708
709	if (tb[XFRMA_ALG_AUTH_TRUNC]) {
710		struct rtattr *rta = tb[XFRMA_ALG_AUTH_TRUNC];
711		xfrm_auth_trunc_print((struct xfrm_algo_auth *) RTA_DATA(rta),
712				      RTA_PAYLOAD(rta), fp, prefix);
713	}
714
715	if (tb[XFRMA_ALG_AEAD]) {
716		struct rtattr *rta = tb[XFRMA_ALG_AEAD];
717		xfrm_aead_print((struct xfrm_algo_aead *)RTA_DATA(rta),
718				RTA_PAYLOAD(rta), fp, prefix);
719	}
720
721	if (tb[XFRMA_ALG_CRYPT]) {
722		struct rtattr *rta = tb[XFRMA_ALG_CRYPT];
723		xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
724				XFRMA_ALG_CRYPT, RTA_PAYLOAD(rta), fp, prefix);
725	}
726
727	if (tb[XFRMA_ALG_COMP]) {
728		struct rtattr *rta = tb[XFRMA_ALG_COMP];
729		xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
730				XFRMA_ALG_COMP, RTA_PAYLOAD(rta), fp, prefix);
731	}
732
733	if (tb[XFRMA_ENCAP]) {
734		struct xfrm_encap_tmpl *e;
735		char abuf[256];
736
737		if (prefix)
738			fputs(prefix, fp);
739		fprintf(fp, "encap ");
740
741		if (RTA_PAYLOAD(tb[XFRMA_ENCAP]) < sizeof(*e)) {
742			fprintf(fp, "(ERROR truncated)");
743			fprintf(fp, "%s", _SL_);
744			return;
745		}
746		e = (struct xfrm_encap_tmpl *) RTA_DATA(tb[XFRMA_ENCAP]);
747
748		fprintf(fp, "type ");
749		switch (e->encap_type) {
750		case 1:
751			fprintf(fp, "espinudp-nonike ");
752			break;
753		case 2:
754			fprintf(fp, "espinudp ");
755			break;
756		default:
757			fprintf(fp, "%u ", e->encap_type);
758			break;
759		}
760		fprintf(fp, "sport %u ", ntohs(e->encap_sport));
761		fprintf(fp, "dport %u ", ntohs(e->encap_dport));
762
763		memset(abuf, '\0', sizeof(abuf));
764		fprintf(fp, "addr %s",
765			rt_addr_n2a(family, sizeof(e->encap_oa),
766				    &e->encap_oa, abuf, sizeof(abuf)));
767		fprintf(fp, "%s", _SL_);
768	}
769
770	if (tb[XFRMA_TMPL]) {
771		struct rtattr *rta = tb[XFRMA_TMPL];
772		xfrm_tmpl_print((struct xfrm_user_tmpl *) RTA_DATA(rta),
773				RTA_PAYLOAD(rta), family, fp, prefix);
774	}
775
776	if (tb[XFRMA_COADDR]) {
777		char abuf[256];
778		xfrm_address_t *coa;
779
780		if (prefix)
781			fputs(prefix, fp);
782		fprintf(fp, "coa ");
783
784		coa = (xfrm_address_t *)RTA_DATA(tb[XFRMA_COADDR]);
785
786		if (RTA_PAYLOAD(tb[XFRMA_COADDR]) < sizeof(*coa)) {
787			fprintf(fp, "(ERROR truncated)");
788			fprintf(fp, "%s", _SL_);
789			return;
790		}
791
792		memset(abuf, '\0', sizeof(abuf));
793		fprintf(fp, "%s",
794			rt_addr_n2a(family, sizeof(*coa), coa,
795				    abuf, sizeof(abuf)));
796		fprintf(fp, "%s", _SL_);
797	}
798
799	if (tb[XFRMA_LASTUSED]) {
800		__u64 lastused;
801
802		if (prefix)
803			fputs(prefix, fp);
804		fprintf(fp, "lastused ");
805
806		if (RTA_PAYLOAD(tb[XFRMA_LASTUSED]) < sizeof(lastused)) {
807			fprintf(fp, "(ERROR truncated)");
808			fprintf(fp, "%s", _SL_);
809			return;
810		}
811
812		lastused = rta_getattr_u64(tb[XFRMA_LASTUSED]);
813
814		fprintf(fp, "%s", strxf_time(lastused));
815		fprintf(fp, "%s", _SL_);
816	}
817
818}
819
820static int xfrm_selector_iszero(struct xfrm_selector *s)
821{
822	struct xfrm_selector s0;
823
824	memset(&s0, 0, sizeof(s0));
825
826	return (memcmp(&s0, s, sizeof(s0)) == 0);
827}
828
829void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
830			    struct rtattr *tb[], FILE *fp, const char *prefix,
831			    const char *title)
832{
833	char buf[STRBUF_SIZE];
834	int force_spi = xfrm_xfrmproto_is_ipsec(xsinfo->id.proto);
835
836	memset(buf, '\0', sizeof(buf));
837
838	xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode,
839			   xsinfo->reqid, xsinfo->family, force_spi, fp,
840			   prefix, title);
841
842	if (prefix)
843		STRBUF_CAT(buf, prefix);
844	STRBUF_CAT(buf, "\t");
845
846	fputs(buf, fp);
847	fprintf(fp, "replay-window %u ", xsinfo->replay_window);
848	if (show_stats > 0)
849		fprintf(fp, "seq 0x%08u ", xsinfo->seq);
850	if (show_stats > 0 || xsinfo->flags) {
851		__u8 flags = xsinfo->flags;
852
853		fprintf(fp, "flag ");
854		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_NOECN, "noecn");
855		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_DECAP_DSCP, "decap-dscp");
856		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_NOPMTUDISC, "nopmtudisc");
857		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_WILDRECV, "wildrecv");
858		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_ICMP, "icmp");
859		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_AF_UNSPEC, "af-unspec");
860		XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_ALIGN4, "align4");
861		if (flags)
862			fprintf(fp, "%x", flags);
863	}
864	if (show_stats > 0)
865		fprintf(fp, " (0x%s)", strxf_mask8(xsinfo->flags));
866	fprintf(fp, "%s", _SL_);
867
868	xfrm_xfrma_print(tb, xsinfo->family, fp, buf);
869
870	if (!xfrm_selector_iszero(&xsinfo->sel)) {
871		char sbuf[STRBUF_SIZE];
872
873		memcpy(sbuf, buf, sizeof(sbuf));
874		STRBUF_CAT(sbuf, "sel ");
875
876		xfrm_selector_print(&xsinfo->sel, xsinfo->family, fp, sbuf);
877	}
878
879	if (show_stats > 0) {
880		xfrm_lifetime_print(&xsinfo->lft, &xsinfo->curlft, fp, buf);
881		xfrm_stats_print(&xsinfo->stats, fp, buf);
882	}
883
884	if (tb[XFRMA_SEC_CTX]) {
885		struct xfrm_user_sec_ctx *sctx;
886
887		fprintf(fp, "\tsecurity context ");
888
889		if (RTA_PAYLOAD(tb[XFRMA_SEC_CTX]) < sizeof(*sctx))
890			fprintf(fp, "(ERROR truncated)");
891
892		sctx = (struct xfrm_user_sec_ctx *)RTA_DATA(tb[XFRMA_SEC_CTX]);
893
894		fprintf(fp, "%s %s", (char *)(sctx + 1), _SL_);
895	}
896
897}
898
899void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
900			    struct rtattr *tb[], FILE *fp, const char *prefix,
901			    const char *title)
902{
903	char buf[STRBUF_SIZE];
904
905	memset(buf, '\0', sizeof(buf));
906
907	xfrm_selector_print(&xpinfo->sel, preferred_family, fp, title);
908
909	if (tb[XFRMA_SEC_CTX]) {
910		struct xfrm_user_sec_ctx *sctx;
911
912		fprintf(fp, "\tsecurity context ");
913
914		if (RTA_PAYLOAD(tb[XFRMA_SEC_CTX]) < sizeof(*sctx))
915			fprintf(fp, "(ERROR truncated)");
916
917		sctx = (struct xfrm_user_sec_ctx *)RTA_DATA(tb[XFRMA_SEC_CTX]);
918
919		fprintf(fp, "%s ", (char *)(sctx + 1));
920		fprintf(fp, "%s", _SL_);
921	}
922
923	if (prefix)
924		STRBUF_CAT(buf, prefix);
925	STRBUF_CAT(buf, "\t");
926
927	fputs(buf, fp);
928	if (xpinfo->dir >= XFRM_POLICY_MAX) {
929		xpinfo->dir -= XFRM_POLICY_MAX;
930		fprintf(fp, "socket ");
931	} else
932		fprintf(fp, "dir ");
933
934	switch (xpinfo->dir) {
935	case XFRM_POLICY_IN:
936		fprintf(fp, "in");
937		break;
938	case XFRM_POLICY_OUT:
939		fprintf(fp, "out");
940		break;
941	case XFRM_POLICY_FWD:
942		fprintf(fp, "fwd");
943		break;
944	default:
945		fprintf(fp, "%u", xpinfo->dir);
946		break;
947	}
948	fprintf(fp, " ");
949
950	switch (xpinfo->action) {
951	case XFRM_POLICY_ALLOW:
952		if (show_stats > 0)
953			fprintf(fp, "action allow ");
954		break;
955	case XFRM_POLICY_BLOCK:
956		fprintf(fp, "action block ");
957		break;
958	default:
959		fprintf(fp, "action %u ", xpinfo->action);
960		break;
961	}
962
963	if (show_stats)
964		fprintf(fp, "index %u ", xpinfo->index);
965	fprintf(fp, "priority %u ", xpinfo->priority);
966
967	if (tb[XFRMA_POLICY_TYPE]) {
968		struct xfrm_userpolicy_type *upt;
969
970		fprintf(fp, "ptype ");
971
972		if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt))
973			fprintf(fp, "(ERROR truncated)");
974
975		upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]);
976		fprintf(fp, "%s ", strxf_ptype(upt->type));
977	}
978
979	if (show_stats > 0)
980		fprintf(fp, "share %s ", strxf_share(xpinfo->share));
981
982	if (show_stats > 0 || xpinfo->flags) {
983		__u8 flags = xpinfo->flags;
984
985		fprintf(fp, "flag ");
986		XFRM_FLAG_PRINT(fp, flags, XFRM_POLICY_LOCALOK, "localok");
987		XFRM_FLAG_PRINT(fp, flags, XFRM_POLICY_ICMP, "icmp");
988		if (flags)
989			fprintf(fp, "%x", flags);
990	}
991	if (show_stats > 0)
992		fprintf(fp, " (0x%s)", strxf_mask8(xpinfo->flags));
993	fprintf(fp, "%s", _SL_);
994
995	if (show_stats > 0)
996		xfrm_lifetime_print(&xpinfo->lft, &xpinfo->curlft, fp, buf);
997
998	xfrm_xfrma_print(tb, xpinfo->sel.family, fp, buf);
999}
1000
1001int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,
1002		  int loose, int *argcp, char ***argvp)
1003{
1004	int argc = *argcp;
1005	char **argv = *argvp;
1006	inet_prefix dst;
1007	inet_prefix src;
1008
1009	memset(&dst, 0, sizeof(dst));
1010	memset(&src, 0, sizeof(src));
1011
1012	while (1) {
1013		if (strcmp(*argv, "src") == 0) {
1014			NEXT_ARG();
1015
1016			get_prefix(&src, *argv, preferred_family);
1017			if (src.family == AF_UNSPEC)
1018				invarg("\"src\" address family is AF_UNSPEC", *argv);
1019			if (family)
1020				*family = src.family;
1021
1022			memcpy(saddr, &src.data, sizeof(*saddr));
1023
1024			filter.id_src_mask = src.bitlen;
1025
1026		} else if (strcmp(*argv, "dst") == 0) {
1027			NEXT_ARG();
1028
1029			get_prefix(&dst, *argv, preferred_family);
1030			if (dst.family == AF_UNSPEC)
1031				invarg("\"dst\" address family is AF_UNSPEC", *argv);
1032			if (family)
1033				*family = dst.family;
1034
1035			memcpy(&id->daddr, &dst.data, sizeof(id->daddr));
1036
1037			filter.id_dst_mask = dst.bitlen;
1038
1039		} else if (strcmp(*argv, "proto") == 0) {
1040			int ret;
1041
1042			NEXT_ARG();
1043
1044			ret = xfrm_xfrmproto_getbyname(*argv);
1045			if (ret < 0)
1046				invarg("\"XFRM-PROTO\" is invalid", *argv);
1047
1048			id->proto = (__u8)ret;
1049
1050			filter.id_proto_mask = XFRM_FILTER_MASK_FULL;
1051
1052		} else if (strcmp(*argv, "spi") == 0) {
1053			__u32 spi;
1054
1055			NEXT_ARG();
1056			if (get_u32(&spi, *argv, 0))
1057				invarg("\"SPI\" is invalid", *argv);
1058
1059			spi = htonl(spi);
1060			id->spi = spi;
1061
1062			filter.id_spi_mask = XFRM_FILTER_MASK_FULL;
1063
1064		} else {
1065			PREV_ARG(); /* back track */
1066			break;
1067		}
1068
1069		if (!NEXT_ARG_OK())
1070			break;
1071		NEXT_ARG();
1072	}
1073
1074	if (src.family && dst.family && (src.family != dst.family))
1075		invarg("the same address family is required between \"src\" and \"dst\"", *argv);
1076
1077	if (loose == 0 && id->proto == 0)
1078		missarg("XFRM-PROTO");
1079	if (argc == *argcp)
1080		missarg("ID");
1081
1082	*argcp = argc;
1083	*argvp = argv;
1084
1085	return 0;
1086}
1087
1088int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
1089{
1090	int argc = *argcp;
1091	char **argv = *argvp;
1092
1093	if (matches(*argv, "transport") == 0)
1094		*mode = XFRM_MODE_TRANSPORT;
1095	else if (matches(*argv, "tunnel") == 0)
1096		*mode = XFRM_MODE_TUNNEL;
1097	else if (matches(*argv, "ro") == 0)
1098		*mode = XFRM_MODE_ROUTEOPTIMIZATION;
1099	else if (matches(*argv, "in_trigger") == 0)
1100		*mode = XFRM_MODE_IN_TRIGGER;
1101	else if (matches(*argv, "beet") == 0)
1102		*mode = XFRM_MODE_BEET;
1103	else
1104		invarg("\"MODE\" is invalid", *argv);
1105
1106	*argcp = argc;
1107	*argvp = argv;
1108
1109	return 0;
1110}
1111
1112int xfrm_encap_type_parse(__u16 *type, int *argcp, char ***argvp)
1113{
1114	int argc = *argcp;
1115	char **argv = *argvp;
1116
1117	if (strcmp(*argv, "espinudp-nonike") == 0)
1118		*type = 1;
1119	else if (strcmp(*argv, "espinudp") == 0)
1120		*type = 2;
1121	else
1122		invarg("\"ENCAP-TYPE\" is invalid", *argv);
1123
1124	*argcp = argc;
1125	*argvp = argv;
1126
1127	return 0;
1128}
1129
1130/* NOTE: reqid is used by host-byte order */
1131int xfrm_reqid_parse(__u32 *reqid, int *argcp, char ***argvp)
1132{
1133	int argc = *argcp;
1134	char **argv = *argvp;
1135
1136	if (get_u32(reqid, *argv, 0))
1137		invarg("\"REQID\" is invalid", *argv);
1138
1139	*argcp = argc;
1140	*argvp = argv;
1141
1142	return 0;
1143}
1144
1145static int xfrm_selector_upspec_parse(struct xfrm_selector *sel,
1146				      int *argcp, char ***argvp)
1147{
1148	int argc = *argcp;
1149	char **argv = *argvp;
1150	char *sportp = NULL;
1151	char *dportp = NULL;
1152	char *typep = NULL;
1153	char *codep = NULL;
1154	char *grekey = NULL;
1155
1156	while (1) {
1157		if (strcmp(*argv, "proto") == 0) {
1158			__u8 upspec;
1159
1160			NEXT_ARG();
1161
1162			if (strcmp(*argv, "any") == 0)
1163				upspec = 0;
1164			else {
1165				struct protoent *pp;
1166				pp = getprotobyname(*argv);
1167				if (pp)
1168					upspec = pp->p_proto;
1169				else {
1170					if (get_u8(&upspec, *argv, 0))
1171						invarg("\"PROTO\" is invalid", *argv);
1172				}
1173			}
1174			sel->proto = upspec;
1175
1176			filter.upspec_proto_mask = XFRM_FILTER_MASK_FULL;
1177
1178		} else if (strcmp(*argv, "sport") == 0) {
1179			sportp = *argv;
1180
1181			NEXT_ARG();
1182
1183			if (get_u16(&sel->sport, *argv, 0))
1184				invarg("\"PORT\" is invalid", *argv);
1185			sel->sport = htons(sel->sport);
1186			if (sel->sport)
1187				sel->sport_mask = ~((__u16)0);
1188
1189			filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
1190
1191		} else if (strcmp(*argv, "dport") == 0) {
1192			dportp = *argv;
1193
1194			NEXT_ARG();
1195
1196			if (get_u16(&sel->dport, *argv, 0))
1197				invarg("\"PORT\" is invalid", *argv);
1198			sel->dport = htons(sel->dport);
1199			if (sel->dport)
1200				sel->dport_mask = ~((__u16)0);
1201
1202			filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
1203
1204		} else if (strcmp(*argv, "type") == 0) {
1205			typep = *argv;
1206
1207			NEXT_ARG();
1208
1209			if (get_u16(&sel->sport, *argv, 0) ||
1210			    (sel->sport & ~((__u16)0xff)))
1211				invarg("\"type\" value is invalid", *argv);
1212			sel->sport = htons(sel->sport);
1213			sel->sport_mask = ~((__u16)0);
1214
1215			filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
1216
1217
1218		} else if (strcmp(*argv, "code") == 0) {
1219			codep = *argv;
1220
1221			NEXT_ARG();
1222
1223			if (get_u16(&sel->dport, *argv, 0) ||
1224			    (sel->dport & ~((__u16)0xff)))
1225				invarg("\"code\" value is invalid", *argv);
1226			sel->dport = htons(sel->dport);
1227			sel->dport_mask = ~((__u16)0);
1228
1229			filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
1230
1231		} else if (strcmp(*argv, "key") == 0) {
1232			unsigned uval;
1233
1234			grekey = *argv;
1235
1236			NEXT_ARG();
1237
1238			if (strchr(*argv, '.'))
1239				uval = htonl(get_addr32(*argv));
1240			else {
1241				if (get_unsigned(&uval, *argv, 0)<0) {
1242					fprintf(stderr, "invalid value of \"key\"\n");
1243					exit(-1);
1244				}
1245			}
1246
1247			sel->sport = htons(uval >> 16);
1248			sel->dport = htons(uval & 0xffff);
1249			sel->sport_mask = ~((__u16)0);
1250			sel->dport_mask = ~((__u16)0);
1251
1252			filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
1253
1254		} else {
1255			PREV_ARG(); /* back track */
1256			break;
1257		}
1258
1259		if (!NEXT_ARG_OK())
1260			break;
1261		NEXT_ARG();
1262	}
1263	if (argc == *argcp)
1264		missarg("UPSPEC");
1265	if (sportp || dportp) {
1266		switch (sel->proto) {
1267		case IPPROTO_TCP:
1268		case IPPROTO_UDP:
1269		case IPPROTO_SCTP:
1270		case IPPROTO_DCCP:
1271			break;
1272		default:
1273			fprintf(stderr, "\"sport\" and \"dport\" are invalid with proto=%s\n", strxf_proto(sel->proto));
1274			exit(1);
1275		}
1276	}
1277	if (typep || codep) {
1278		switch (sel->proto) {
1279		case IPPROTO_ICMP:
1280		case IPPROTO_ICMPV6:
1281		case IPPROTO_MH:
1282			break;
1283		default:
1284			fprintf(stderr, "\"type\" and \"code\" are invalid with proto=%s\n", strxf_proto(sel->proto));
1285			exit(1);
1286		}
1287	}
1288	if (grekey) {
1289		switch (sel->proto) {
1290		case IPPROTO_GRE:
1291			break;
1292		default:
1293			fprintf(stderr, "\"key\" is invalid with proto=%s\n", strxf_proto(sel->proto));
1294			exit(1);
1295		}
1296	}
1297
1298	*argcp = argc;
1299	*argvp = argv;
1300
1301	return 0;
1302}
1303
1304int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp)
1305{
1306	int argc = *argcp;
1307	char **argv = *argvp;
1308	inet_prefix dst;
1309	inet_prefix src;
1310	char *upspecp = NULL;
1311
1312	memset(&dst, 0, sizeof(dst));
1313	memset(&src, 0, sizeof(src));
1314
1315	while (1) {
1316		if (strcmp(*argv, "src") == 0) {
1317			NEXT_ARG();
1318
1319			get_prefix(&src, *argv, preferred_family);
1320			if (src.family == AF_UNSPEC)
1321				invarg("\"src\" address family is AF_UNSPEC", *argv);
1322			sel->family = src.family;
1323
1324			memcpy(&sel->saddr, &src.data, sizeof(sel->saddr));
1325			sel->prefixlen_s = src.bitlen;
1326
1327			filter.sel_src_mask = src.bitlen;
1328
1329		} else if (strcmp(*argv, "dst") == 0) {
1330			NEXT_ARG();
1331
1332			get_prefix(&dst, *argv, preferred_family);
1333			if (dst.family == AF_UNSPEC)
1334				invarg("\"dst\" address family is AF_UNSPEC", *argv);
1335			sel->family = dst.family;
1336
1337			memcpy(&sel->daddr, &dst.data, sizeof(sel->daddr));
1338			sel->prefixlen_d = dst.bitlen;
1339
1340			filter.sel_dst_mask = dst.bitlen;
1341
1342		} else if (strcmp(*argv, "dev") == 0) {
1343			int ifindex;
1344
1345			NEXT_ARG();
1346
1347			if (strcmp(*argv, "none") == 0)
1348				ifindex = 0;
1349			else {
1350				ifindex = ll_name_to_index(*argv);
1351				if (ifindex <= 0)
1352					invarg("\"DEV\" is invalid", *argv);
1353			}
1354			sel->ifindex = ifindex;
1355
1356			filter.sel_dev_mask = XFRM_FILTER_MASK_FULL;
1357
1358		} else {
1359			if (upspecp) {
1360				PREV_ARG(); /* back track */
1361				break;
1362			} else {
1363				upspecp = *argv;
1364				xfrm_selector_upspec_parse(sel, &argc, &argv);
1365			}
1366		}
1367
1368		if (!NEXT_ARG_OK())
1369			break;
1370
1371		NEXT_ARG();
1372	}
1373
1374	if (src.family && dst.family && (src.family != dst.family))
1375		invarg("the same address family is required between \"src\" and \"dst\"", *argv);
1376
1377	if (argc == *argcp)
1378		missarg("SELECTOR");
1379
1380	*argcp = argc;
1381	*argvp = argv;
1382
1383	return 0;
1384}
1385
1386int xfrm_lifetime_cfg_parse(struct xfrm_lifetime_cfg *lft,
1387			    int *argcp, char ***argvp)
1388{
1389	int argc = *argcp;
1390	char **argv = *argvp;
1391	int ret;
1392
1393	if (strcmp(*argv, "time-soft") == 0) {
1394		NEXT_ARG();
1395		ret = get_u64(&lft->soft_add_expires_seconds, *argv, 0);
1396		if (ret)
1397			invarg("\"time-soft\" value is invalid", *argv);
1398	} else if (strcmp(*argv, "time-hard") == 0) {
1399		NEXT_ARG();
1400		ret = get_u64(&lft->hard_add_expires_seconds, *argv, 0);
1401		if (ret)
1402			invarg("\"time-hard\" value is invalid", *argv);
1403	} else if (strcmp(*argv, "time-use-soft") == 0) {
1404		NEXT_ARG();
1405		ret = get_u64(&lft->soft_use_expires_seconds, *argv, 0);
1406		if (ret)
1407			invarg("\"time-use-soft\" value is invalid", *argv);
1408	} else if (strcmp(*argv, "time-use-hard") == 0) {
1409		NEXT_ARG();
1410		ret = get_u64(&lft->hard_use_expires_seconds, *argv, 0);
1411		if (ret)
1412			invarg("\"time-use-hard\" value is invalid", *argv);
1413	} else if (strcmp(*argv, "byte-soft") == 0) {
1414		NEXT_ARG();
1415		ret = get_u64(&lft->soft_byte_limit, *argv, 0);
1416		if (ret)
1417			invarg("\"byte-soft\" value is invalid", *argv);
1418	} else if (strcmp(*argv, "byte-hard") == 0) {
1419		NEXT_ARG();
1420		ret = get_u64(&lft->hard_byte_limit, *argv, 0);
1421		if (ret)
1422			invarg("\"byte-hard\" value is invalid", *argv);
1423	} else if (strcmp(*argv, "packet-soft") == 0) {
1424		NEXT_ARG();
1425		ret = get_u64(&lft->soft_packet_limit, *argv, 0);
1426		if (ret)
1427			invarg("\"packet-soft\" value is invalid", *argv);
1428	} else if (strcmp(*argv, "packet-hard") == 0) {
1429		NEXT_ARG();
1430		ret = get_u64(&lft->hard_packet_limit, *argv, 0);
1431		if (ret)
1432			invarg("\"packet-hard\" value is invalid", *argv);
1433	} else
1434		invarg("\"LIMIT\" is invalid", *argv);
1435
1436	*argcp = argc;
1437	*argvp = argv;
1438
1439	return 0;
1440}
1441
1442int do_xfrm(int argc, char **argv)
1443{
1444	memset(&filter, 0, sizeof(filter));
1445
1446	if (argc < 1)
1447		usage();
1448
1449	if (matches(*argv, "state") == 0 ||
1450	    matches(*argv, "sa") == 0)
1451		return do_xfrm_state(argc-1, argv+1);
1452	else if (matches(*argv, "policy") == 0)
1453		return do_xfrm_policy(argc-1, argv+1);
1454	else if (matches(*argv, "monitor") == 0)
1455		return do_xfrm_monitor(argc-1, argv+1);
1456	else if (matches(*argv, "help") == 0) {
1457		usage();
1458		fprintf(stderr, "xfrm Object \"%s\" is unknown.\n", *argv);
1459		exit(-1);
1460	}
1461	usage();
1462}
1463