]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/xfrm_state.c
iproute2: ip6gre: update man pages
[mirror_iproute2.git] / ip / xfrm_state.c
CommitLineData
c7699875 1/* $USAGI: $ */
2
3/*
4 * Copyright (C)2004 USAGI/WIDE Project
ae665a52 5 *
c7699875 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.
ae665a52 10 *
c7699875 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.
ae665a52 15 *
c7699875 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
9bec1a43
SH
37//#define NLMSG_DELETEALL_BUF_SIZE (4096-512)
38#define NLMSG_DELETEALL_BUF_SIZE 8192
c7699875 39
40/*
41 * Receiving buffer defines:
42 * nlmsg
43 * data = struct xfrm_usersa_info
44 * rtattr
45 * rtattr
2534613e 46 * ... (max count of rtattr is XFRM_MAX+1
c7699875 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
0c7a5945 53#define CTX_BUF_SIZE 256
c7699875 54
55static void usage(void) __attribute__((noreturn));
56
57static void usage(void)
58{
cbec0219
DW
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");
dc8867d0 63 fprintf(stderr, " [ coa ADDR[/PLEN] ] [ ctx CTX ] [ extra-flag EXTRA-FLAG-LIST ]\n");
cbec0219
DW
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");
9bec1a43 67 fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
c1fa2253 68 fprintf(stderr, " [ flag FLAG-LIST ]\n");
cbec0219
DW
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 := ");
29aa4dd7 73 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
74 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
7ea4f5d3
MN
75 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
76 fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
cbec0219
DW
77 fprintf(stderr, "%s\n", strxf_xfrmproto(IPPROTO_DSTOPTS));
78 fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] ALGO\n");
79 fprintf(stderr, "ALGO := { ");
7809c616 80 fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT));
f3b9aa3d 81 fprintf(stderr, "%s", strxf_algotype(XFRMA_ALG_AUTH));
29665f92 82 fprintf(stderr, " } ALGO-NAME ALGO-KEYMAT |\n");
f3b9aa3d 83 fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_AUTH_TRUNC));
29665f92 84 fprintf(stderr, " ALGO-NAME ALGO-KEYMAT ALGO-TRUNC-LEN |\n");
cbec0219 85 fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_AEAD));
29665f92 86 fprintf(stderr, " ALGO-NAME ALGO-KEYMAT ALGO-ICV-LEN |\n");
f3b9aa3d
DW
87 fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_COMP));
88 fprintf(stderr, " ALGO-NAME\n");
e8740e42 89 fprintf(stderr, "MODE := transport | tunnel | beet | ro | in_trigger\n");
cbec0219
DW
90 fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
91 fprintf(stderr, "FLAG := noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4\n");
dc8867d0
ND
92 fprintf(stderr, "EXTRA-FLAG-LIST := [ EXTRA-FLAG-LIST ] EXTRA-FLAG\n");
93 fprintf(stderr, "EXTRA-FLAG := dont-encap-dscp\n");
cbec0219
DW
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");
c7699875 112
c7699875 113 exit(-1);
114}
115
116static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
1758a81f 117 char *name, char *key, char *buf, int max)
c7699875 118{
119 int len;
7809c616 120 int slen = strlen(key);
c7699875 121
eaa34ee3 122#if 0
c7699875 123 /* XXX: verifying both name and key is required! */
29665f92 124 fprintf(stderr, "warning: ALGO-NAME/ALGO-KEYMAT values will be sent to the kernel promiscuously! (verifying them isn't implemented yet)\n");
c7699875 125#endif
126
127 strncpy(alg->alg_name, name, sizeof(alg->alg_name));
128
7809c616 129 if (slen > 2 && strncmp(key, "0x", 2) == 0) {
54f7328a 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.
c7699875 139 */
7809c616 140
54f7328a 141 /* calculate length of the converted values(real key) */
142 len = (plen + 1) / 2;
143 if (len > max)
29665f92 144 invarg("ALGO-KEYMAT value makes buffer overflow\n", key);
c7699875 145
54f7328a 146 for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
147 char vbuf[3];
737f15f6 148 __u8 val;
c7699875 149
54f7328a 150 vbuf[0] = i >= 0 ? p[i] : '0';
151 vbuf[1] = p[i + 1];
152 vbuf[2] = '\0';
c7699875 153
54f7328a 154 if (get_u8(&val, vbuf, 16))
29665f92 155 invarg("ALGO-KEYMAT value is invalid", key);
7809c616 156
1758a81f 157 buf[j] = val;
c7699875 158 }
c7699875 159 } else {
7809c616 160 len = slen;
c7699875 161 if (len > 0) {
162 if (len > max)
29665f92 163 invarg("ALGO-KEYMAT value makes buffer overflow\n", key);
c7699875 164
99500b56 165 memcpy(buf, key, len);
c7699875 166 }
167 }
168
169 alg->alg_key_len = len * 8;
170
171 return 0;
172}
173
fb7399b2 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))
e8740e42 180 invarg("SEQ value is invalid", *argv);
fb7399b2 181
182 *seq = htonl(*seq);
183
184 *argcp = argc;
185 *argvp = argv;
186
187 return 0;
188}
189
c7699875 190static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
191{
192 int argc = *argcp;
193 char **argv = *argvp;
9e566a46 194 int len = strlen(*argv);
195
196 if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
197 __u8 val = 0;
c7699875 198
9e566a46 199 if (get_u8(&val, *argv, 16))
e8740e42 200 invarg("FLAG value is invalid", *argv);
9e566a46 201 *flags = val;
202 } else {
eaa34ee3 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;
c1fa2253
MN
208 else if (strcmp(*argv, "nopmtudisc") == 0)
209 *flags |= XFRM_STATE_NOPMTUDISC;
7ea4f5d3
MN
210 else if (strcmp(*argv, "wildrecv") == 0)
211 *flags |= XFRM_STATE_WILDRECV;
15bb82c6
AB
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;
98f5519c
ND
216 else if (strcmp(*argv, "align4") == 0)
217 *flags |= XFRM_STATE_ALIGN4;
eaa34ee3 218 else {
219 PREV_ARG(); /* back track */
220 break;
221 }
222
223 if (!NEXT_ARG_OK())
224 break;
225 NEXT_ARG();
226 }
9e566a46 227 }
c7699875 228
c7699875 229 *argcp = argc;
230 *argvp = argv;
231
232 return 0;
233}
234
dc8867d0
ND
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
c7699875 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;
de95ae7c 276 struct xfrm_replay_state replay;
c7699875 277 char *idp = NULL;
1758a81f 278 char *aeadop = NULL;
c7699875 279 char *ealgop = NULL;
280 char *aalgop = NULL;
281 char *calgop = NULL;
7ea4f5d3 282 char *coap = NULL;
0c7a5945 283 char *sctxp = NULL;
dc8867d0 284 __u32 extra_flags = 0;
c90cda94 285 struct xfrm_mark mark = {0, 0};
0c7a5945
JL
286 struct {
287 struct xfrm_user_sec_ctx sctx;
288 char str[CTX_BUF_SIZE];
289 } ctx;
c7699875 290
291 memset(&req, 0, sizeof(req));
de95ae7c 292 memset(&replay, 0, sizeof(replay));
0c7a5945 293 memset(&ctx, 0, sizeof(ctx));
c7699875 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) {
7809c616 306 if (strcmp(*argv, "mode") == 0) {
c7699875 307 NEXT_ARG();
308 xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
c90cda94
JHS
309 } else if (strcmp(*argv, "mark") == 0) {
310 xfrm_parse_mark(&mark, &argc, &argv);
c7699875 311 } else if (strcmp(*argv, "reqid") == 0) {
312 NEXT_ARG();
313 xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
fb7399b2 314 } else if (strcmp(*argv, "seq") == 0) {
315 NEXT_ARG();
316 xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
eaa34ee3 317 } else if (strcmp(*argv, "replay-window") == 0) {
318 NEXT_ARG();
319 if (get_u8(&req.xsinfo.replay_window, *argv, 0))
e8740e42 320 invarg("value after \"replay-window\" is invalid", *argv);
de95ae7c
HX
321 } else if (strcmp(*argv, "replay-seq") == 0) {
322 NEXT_ARG();
323 if (get_u32(&replay.seq, *argv, 0))
e8740e42 324 invarg("value after \"replay-seq\" is invalid", *argv);
de95ae7c
HX
325 } else if (strcmp(*argv, "replay-oseq") == 0) {
326 NEXT_ARG();
327 if (get_u32(&replay.oseq, *argv, 0))
e8740e42 328 invarg("value after \"replay-oseq\" is invalid", *argv);
c7699875 329 } else if (strcmp(*argv, "flag") == 0) {
330 NEXT_ARG();
331 xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
dc8867d0
ND
332 } else if (strcmp(*argv, "extra-flag") == 0) {
333 NEXT_ARG();
334 xfrm_state_extra_flag_parse(&extra_flags, &argc, &argv);
c7699875 335 } else if (strcmp(*argv, "sel") == 0) {
336 NEXT_ARG();
23d5b0d5 337 preferred_family = AF_UNSPEC;
c7699875 338 xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
0c5982fd 339 preferred_family = req.xsinfo.sel.family;
c7699875 340 } else if (strcmp(*argv, "limit") == 0) {
341 NEXT_ARG();
342 xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
5cf576d9
SH
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))
e8740e42 350 invarg("SPORT value after \"encap\" is invalid", *argv);
5cf576d9
SH
351 encap.encap_sport = htons(encap.encap_sport);
352 NEXT_ARG();
353 if (get_u16(&encap.encap_dport, *argv, 0))
e8740e42 354 invarg("DPORT value after \"encap\" is invalid", *argv);
5cf576d9
SH
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));
7ea4f5d3
MN
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)
e8740e42 373 invarg("value after \"coa\" has an unrecognized address family", *argv);
7ea4f5d3 374 if (coa.bytelen > sizeof(xcoa))
e8740e42 375 invarg("value after \"coa\" is too large", *argv);
7ea4f5d3
MN
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));
0c7a5945
JL
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);
c7699875 395 } else {
7809c616 396 /* try to assume ALGO */
397 int type = xfrm_algotype_getbyname(*argv);
398 switch (type) {
1758a81f 399 case XFRMA_ALG_AEAD:
7809c616 400 case XFRMA_ALG_CRYPT:
401 case XFRMA_ALG_AUTH:
f323f2a3 402 case XFRMA_ALG_AUTH_TRUNC:
7809c616 403 case XFRMA_ALG_COMP:
404 {
405 /* ALGO */
406 struct {
1758a81f
HX
407 union {
408 struct xfrm_algo alg;
409 struct xfrm_algo_aead aead;
f323f2a3 410 struct xfrm_algo_auth auth;
1758a81f 411 } u;
7809c616 412 char buf[XFRM_ALGO_KEY_BUF_SIZE];
1758a81f 413 } alg = {};
7809c616 414 int len;
f323f2a3 415 __u32 icvlen, trunclen;
7809c616 416 char *name;
f3b9aa3d 417 char *key = "";
1758a81f 418 char *buf;
7809c616 419
420 switch (type) {
1758a81f 421 case XFRMA_ALG_AEAD:
ec839527 422 if (ealgop || aalgop || aeadop)
cbec0219 423 duparg("ALGO-TYPE", *argv);
1758a81f
HX
424 aeadop = *argv;
425 break;
7809c616 426 case XFRMA_ALG_CRYPT:
ec839527 427 if (ealgop || aeadop)
cbec0219 428 duparg("ALGO-TYPE", *argv);
7809c616 429 ealgop = *argv;
430 break;
431 case XFRMA_ALG_AUTH:
f323f2a3 432 case XFRMA_ALG_AUTH_TRUNC:
ec839527 433 if (aalgop || aeadop)
cbec0219 434 duparg("ALGO-TYPE", *argv);
7809c616 435 aalgop = *argv;
436 break;
437 case XFRMA_ALG_COMP:
438 if (calgop)
cbec0219 439 duparg("ALGO-TYPE", *argv);
7809c616 440 calgop = *argv;
441 break;
442 default:
443 /* not reached */
e8740e42 444 invarg("ALGO-TYPE value is invalid\n", *argv);
7809c616 445 }
446
447 if (!NEXT_ARG_OK())
cbec0219 448 missarg("ALGO-NAME");
7809c616 449 NEXT_ARG();
450 name = *argv;
451
f3b9aa3d
DW
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())
29665f92 458 missarg("ALGO-KEYMAT");
f3b9aa3d
DW
459 NEXT_ARG();
460 key = *argv;
461 break;
462 }
7809c616 463
1758a81f
HX
464 buf = alg.u.alg.alg_key;
465 len = sizeof(alg.u.alg);
466
f323f2a3
ND
467 switch (type) {
468 case XFRMA_ALG_AEAD:
469 if (!NEXT_ARG_OK())
cbec0219 470 missarg("ALGO-ICV-LEN");
f323f2a3
ND
471 NEXT_ARG();
472 if (get_u32(&icvlen, *argv, 0))
e8740e42 473 invarg("ALGO-ICV-LEN value is invalid",
f323f2a3
ND
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())
cbec0219 482 missarg("ALGO-TRUNC-LEN");
f323f2a3
ND
483 NEXT_ARG();
484 if (get_u32(&trunclen, *argv, 0))
e8740e42 485 invarg("ALGO-TRUNC-LEN value is invalid",
f323f2a3
ND
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 }
7809c616 493
494 xfrm_algo_parse((void *)&alg, type, name, key,
1758a81f
HX
495 buf, sizeof(alg.buf));
496 len += alg.u.alg.alg_key_len;
7809c616 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 }
c7699875 514 }
515 argc--; argv++;
516 }
517
de95ae7c
HX
518 if (replay.seq || replay.oseq)
519 addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL,
520 (void *)&replay, sizeof(replay));
521
dc8867d0
ND
522 if (extra_flags)
523 addattr32(&req.n, sizeof(req.buf), XFRMA_SA_EXTRA_FLAGS,
524 extra_flags);
525
c7699875 526 if (!idp) {
e8740e42 527 fprintf(stderr, "Not enough information: ID is required\n");
c7699875 528 exit(1);
529 }
530
c90cda94
JHS
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
6128fdfd
DW
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",
7ea4f5d3
MN
550 strxf_xfrmproto(req.xsinfo.id.proto));
551 exit(1);
552 }
6128fdfd
DW
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",
7ea4f5d3
MN
608 strxf_xfrmproto(req.xsinfo.id.proto));
609 exit(1);
610 }
7ea4f5d3
MN
611 }
612
6128fdfd
DW
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",
7ea4f5d3
MN
620 strxf_xfrmproto(req.xsinfo.id.proto));
621 exit(1);
6128fdfd
DW
622 default:
623 fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n",
7ea4f5d3 624 strxf_xfrmproto(req.xsinfo.id.proto));
6128fdfd 625 exit(1);
7ea4f5d3 626 }
7ea4f5d3 627
6128fdfd
DW
628 if (!coap) {
629 fprintf(stderr, "\"coa\" is required with XFRM-PROTO value \"%s\"\n",
7ea4f5d3 630 strxf_xfrmproto(req.xsinfo.id.proto));
c7699875 631 exit(1);
632 }
633 } else {
6128fdfd
DW
634 if (coap) {
635 fprintf(stderr, "\"coa\" is invalid with XFRM-PROTO value \"%s\"\n",
7ea4f5d3 636 strxf_xfrmproto(req.xsinfo.id.proto));
6128fdfd 637 exit(1);
c7699875 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
cd70f3f5 647 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
c7699875 648 exit(2);
649
650 rtnl_close(&rth);
651
652 return 0;
653}
654
fb7399b2 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;
c90cda94 666 struct xfrm_mark mark = {0, 0};
fb7399b2 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);
c90cda94
JHS
690 } else if (strcmp(*argv, "mark") == 0) {
691 xfrm_parse_mark(&mark, &argc, &argv);
fb7399b2 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))
e8740e42 706 invarg("value after \"min\" is invalid", *argv);
fb7399b2 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))
e8740e42 715 invarg("value after \"max\" is invalid", *argv);
fb7399b2 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) {
e8740e42 726 fprintf(stderr, "\"spi\" is invalid\n");
fb7399b2 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) {
e8740e42 736 fprintf(stderr, "Not enough information: ID is required\n");
fb7399b2 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) {
e8740e42 746 fprintf(stderr, "value after \"min\" is larger than value after \"max\"\n");
fb7399b2 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
c90cda94
JHS
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
fb7399b2 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
cd70f3f5 784 if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
fb7399b2 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
c7699875 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)
eaa34ee3 803 if (xfrm_addr_match(&xsinfo->saddr, &filter.xsinfo.saddr,
804 filter.id_src_mask))
c7699875 805 return 0;
806 if (filter.id_dst_mask)
eaa34ee3 807 if (xfrm_addr_match(&xsinfo->id.daddr, &filter.xsinfo.id.daddr,
808 filter.id_dst_mask))
c7699875 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
fb7399b2 825int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
826 void *arg)
c7699875 827{
828 FILE *fp = (FILE*)arg;
c7699875 829 struct rtattr * tb[XFRMA_MAX+1];
90f93024 830 struct rtattr * rta;
c595c790
SH
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;
c7699875 835
836 if (n->nlmsg_type != XFRM_MSG_NEWSA &&
90f93024 837 n->nlmsg_type != XFRM_MSG_DELSA &&
669ae748 838 n->nlmsg_type != XFRM_MSG_UPDSA &&
90f93024 839 n->nlmsg_type != XFRM_MSG_EXPIRE) {
c7699875 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
669ae748
SH
845 if (n->nlmsg_type == XFRM_MSG_DELSA) {
846 /* Dont blame me for this .. Herbert made me do it */
847 xsid = NLMSG_DATA(n);
af1b6a41 848 len -= NLMSG_SPACE(sizeof(*xsid));
669ae748 849 } else if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
90f93024
SH
850 xexp = NLMSG_DATA(n);
851 xsinfo = &xexp->state;
af1b6a41 852 len -= NLMSG_SPACE(sizeof(*xexp));
90f93024
SH
853 } else {
854 xexp = NULL;
855 xsinfo = NLMSG_DATA(n);
af1b6a41 856 len -= NLMSG_SPACE(sizeof(*xsinfo));
90f93024
SH
857 }
858
c7699875 859 if (len < 0) {
860 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
861 return -1;
862 }
863
669ae748 864 if (xsinfo && !xfrm_state_filter_match(xsinfo))
c7699875 865 return 0;
866
669ae748 867 if (n->nlmsg_type == XFRM_MSG_DELSA)
c595c790 868 fprintf(fp, "Deleted ");
669ae748
SH
869 else if (n->nlmsg_type == XFRM_MSG_UPDSA)
870 fprintf(fp, "Updated ");
c595c790
SH
871 else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
872 fprintf(fp, "Expired ");
873
669ae748
SH
874 if (n->nlmsg_type == XFRM_MSG_DELSA)
875 rta = XFRMSID_RTA(xsid);
876 else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
90f93024 877 rta = XFRMEXP_RTA(xexp);
ae665a52 878 else
90f93024
SH
879 rta = XFRMS_RTA(xsinfo);
880
881 parse_rtattr(tb, XFRMA_MAX, rta, len);
c7699875 882
c595c790 883 if (n->nlmsg_type == XFRM_MSG_DELSA) {
669ae748
SH
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;
c595c790 893 }
bdf9e86d 894 xsinfo = RTA_DATA(tb[XFRMA_SA]);
c595c790 895 }
c7699875 896
fb7399b2 897 xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL);
c7699875 898
90f93024
SH
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
7809c616 905 if (oneline)
906 fprintf(fp, "\n");
669ae748 907 fflush(fp);
7809c616 908
c7699875 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;
7ea4f5d3 918 char buf[RTA_BUF_SIZE];
c7699875 919 } req;
920 struct xfrm_id id;
921 char *idp = NULL;
c90cda94 922 struct xfrm_mark mark = {0, 0};
c7699875 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) {
7ea4f5d3 932 xfrm_address_t saddr;
c7699875 933
c90cda94
JHS
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;
c7699875 940
c90cda94
JHS
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);
c7699875 946
c90cda94
JHS
947 memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
948 req.xsid.spi = id.spi;
949 req.xsid.proto = id.proto;
c7699875 950
c90cda94
JHS
951 addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
952 (void *)&saddr, sizeof(saddr));
953 }
7ea4f5d3 954
c7699875 955 argc--; argv++;
956 }
957
c90cda94
JHS
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
c7699875 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) {
cd70f3f5 974 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
c7699875 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
cd70f3f5 982 if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
c7699875 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 */
6dc9f016 1000static int xfrm_state_keep(const struct sockaddr_nl *who,
50772dc5 1001 struct nlmsghdr *n,
6dc9f016 1002 void *arg)
c7699875 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) {
9bec1a43 1027 fprintf(stderr, "State buffer overflow\n");
c7699875 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
7ea4f5d3
MN
1043 addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr,
1044 sizeof(xsid->daddr));
1045
c7699875 1046 xb->offset += new_n->nlmsg_len;
1047 xb->nlmsg_count ++;
1048
1049 return 0;
1050}
1051
9bec1a43 1052static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
c7699875 1053{
1054 char *idp = NULL;
1055 struct rtnl_handle rth;
1056
bd641cd6 1057 if(argc > 0)
1058 filter.use = 1;
c7699875 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 */
7809c616 1086 xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id,
1087 &filter.xsinfo.family, 1, &argc, &argv);
c7699875 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
9bec1a43 1097 if (deleteall) {
c7699875 1098 struct xfrm_buffer xb;
9bec1a43 1099 char buf[NLMSG_DELETEALL_BUF_SIZE];
c7699875 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)
9bec1a43 1111 fprintf(stderr, "Delete-all round = %d\n", i);
c7699875 1112
1113 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
1114 perror("Cannot send dump request");
1115 exit(1);
1116 }
1117
cd70f3f5 1118 if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb) < 0) {
9bec1a43 1119 fprintf(stderr, "Delete-all terminated\n");
c7699875 1120 exit(1);
1121 }
1122 if (xb.nlmsg_count == 0) {
1123 if (show_stats > 1)
9bec1a43 1124 fprintf(stderr, "Delete-all completed\n");
c7699875 1125 break;
1126 }
1127
f31a37f7 1128 if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) {
9bec1a43 1129 perror("Failed to send delete-all request\n");
c7699875 1130 exit(1);
1131 }
1132 if (show_stats > 1)
9bec1a43 1133 fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count);
c7699875 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
cd70f3f5 1145 if (rtnl_dump_filter(&rth, xfrm_state_print, stdout) < 0) {
c7699875 1146 fprintf(stderr, "Dump terminated\n");
1147 exit(1);
1148 }
1149 }
1150
1151 rtnl_close(&rth);
1152
1153 exit(0);
1154}
1155
d1f28cf1 1156static int print_sadinfo(struct nlmsghdr *n, void *arg)
0bb4a4c2 1157{
1158 FILE *fp = (FILE*)arg;
1159 __u32 *f = NLMSG_DATA(n);
1160 struct rtattr *tb[XFRMA_SAD_MAX+1];
1161 struct rtattr *rta;
0bb4a4c2 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
bdf9e86d 1175 if (tb[XFRMA_SAD_CNT]) {
0bb4a4c2 1176 fprintf(fp,"\t SAD");
bdf9e86d 1177 cnt = (__u32 *)RTA_DATA(tb[XFRMA_SAD_CNT]);
0bb4a4c2 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) {
bdf9e86d
SH
1185 if (tb[XFRMA_SAD_HINFO]) {
1186 struct xfrmu_sadhinfo *si;
0bb4a4c2 1187
bdf9e86d
SH
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 }
0bb4a4c2 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
cd70f3f5 1223 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
0bb4a4c2 1224 exit(2);
1225
1226 print_sadinfo(&req.n, (void*)stdout);
1227
1228 rtnl_close(&rth);
1229
1230 return 0;
1231}
1232
9bec1a43 1233static int xfrm_state_flush(int argc, char **argv)
bd641cd6 1234{
1235 struct rtnl_handle rth;
1236 struct {
1237 struct nlmsghdr n;
1238 struct xfrm_usersa_flush xsf;
1239 } req;
9bec1a43 1240 char *protop = NULL;
bd641cd6 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;
7ea4f5d3 1247 req.xsf.proto = 0;
bd641cd6 1248
9bec1a43
SH
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)
e8740e42 1261 invarg("XFRM-PROTO value is invalid", *argv);
9bec1a43
SH
1262
1263 req.xsf.proto = (__u8)ret;
1264 } else
1265 invarg("unknown", *argv);
1266
1267 argc--; argv++;
1268 }
1269
bd641cd6 1270 if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1271 exit(1);
1272
1273 if (show_stats > 1)
e8740e42 1274 fprintf(stderr, "Flush state with XFRM-PROTO value \"%s\"\n",
9bec1a43 1275 strxf_xfrmproto(req.xsf.proto));
bd641cd6 1276
cd70f3f5 1277 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
bd641cd6 1278 exit(2);
1279
1280 rtnl_close(&rth);
1281
1282 return 0;
1283}
1284
c7699875 1285int do_xfrm_state(int argc, char **argv)
1286{
1287 if (argc < 1)
9bec1a43 1288 return xfrm_state_list_or_deleteall(0, NULL, 0);
c7699875 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);
fb7399b2 1296 if (matches(*argv, "allocspi") == 0)
1297 return xfrm_state_allocspi(argc-1, argv+1);
9bec1a43 1298 if (matches(*argv, "delete") == 0)
c7699875 1299 return xfrm_state_get_or_delete(argc-1, argv+1, 1);
9bec1a43
SH
1300 if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0)
1301 return xfrm_state_list_or_deleteall(argc-1, argv+1, 1);
c7699875 1302 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
1303 || matches(*argv, "lst") == 0)
9bec1a43 1304 return xfrm_state_list_or_deleteall(argc-1, argv+1, 0);
c7699875 1305 if (matches(*argv, "get") == 0)
1306 return xfrm_state_get_or_delete(argc-1, argv+1, 0);
9bec1a43
SH
1307 if (matches(*argv, "flush") == 0)
1308 return xfrm_state_flush(argc-1, argv+1);
0bb4a4c2 1309 if (matches(*argv, "count") == 0) {
1310 return xfrm_sad_getinfo(argc, argv);
1311 }
c7699875 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}