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