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