]>
Commit | Line | Data |
---|---|---|
c7699875 | 1 | /* $USAGI: $ */ |
2 | ||
3 | /* | |
4 | * Copyright (C)2004 USAGI/WIDE Project | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | /* | |
21 | * based on 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 | |
53 | ||
54 | static void usage(void) __attribute__((noreturn)); | |
55 | ||
56 | static void usage(void) | |
57 | { | |
7ea4f5d3 | 58 | fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ XFRM_OPT ] [ mode MODE ]\n"); |
fb7399b2 | 59 | fprintf(stderr, " [ reqid REQID ] [ seq SEQ ] [ replay-window SIZE ] [ flag FLAG-LIST ]\n"); |
5cf576d9 | 60 | fprintf(stderr, " [ encap ENCAP ] [ sel SELECTOR ] [ LIMIT-LIST ]\n"); |
fb7399b2 | 61 | fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ reqid REQID ] [ seq SEQ ]\n"); |
62 | fprintf(stderr, " [ min SPI max SPI ]\n"); | |
c7699875 | 63 | fprintf(stderr, "Usage: ip xfrm state { delete | get } ID\n"); |
9bec1a43 | 64 | fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n"); |
eaa34ee3 | 65 | fprintf(stderr, " [ flag FLAG_LIST ]\n"); |
9bec1a43 | 66 | fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM_PROTO ]\n"); |
c7699875 | 67 | |
68 | fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n"); | |
29aa4dd7 | 69 | //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n"); |
9e566a46 | 70 | fprintf(stderr, "XFRM_PROTO := [ "); |
29aa4dd7 | 71 | fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP)); |
72 | fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH)); | |
7ea4f5d3 MN |
73 | fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP)); |
74 | fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING)); | |
75 | fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_DSTOPTS)); | |
7809c616 | 76 | fprintf(stderr, "]\n"); |
9e566a46 | 77 | |
c7699875 | 78 | //fprintf(stderr, "SPI - security parameter index(default=0)\n"); |
79 | ||
7ea4f5d3 | 80 | fprintf(stderr, "MODE := [ transport | tunnel | ro | beet ](default=transport)\n"); |
c7699875 | 81 | //fprintf(stderr, "REQID - number(default=0)\n"); |
82 | ||
eaa34ee3 | 83 | fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n"); |
7ea4f5d3 | 84 | fprintf(stderr, "FLAG := [ noecn | decap-dscp | wildrecv ]\n"); |
5cf576d9 SH |
85 | |
86 | fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n"); | |
87 | fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n"); | |
c7699875 | 88 | |
7809c616 | 89 | fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ ALGO ]\n"); |
c7699875 | 90 | fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY\n"); |
7809c616 | 91 | fprintf(stderr, "ALGO_TYPE := [ "); |
92 | fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT)); | |
93 | fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AUTH)); | |
94 | fprintf(stderr, "%s ", strxf_algotype(XFRMA_ALG_COMP)); | |
95 | fprintf(stderr, "]\n"); | |
96 | ||
c7699875 | 97 | //fprintf(stderr, "ALGO_NAME - algorithm name\n"); |
98 | //fprintf(stderr, "ALGO_KEY - algorithm key\n"); | |
99 | ||
eaa34ee3 | 100 | fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ UPSPEC ] [ dev DEV ]\n"); |
c7699875 | 101 | |
c70b36d2 | 102 | fprintf(stderr, "UPSPEC := proto PROTO [ [ sport PORT ] [ dport PORT ] |\n"); |
103 | fprintf(stderr, " [ type NUMBER ] [ code NUMBER ] ]\n"); | |
104 | ||
c7699875 | 105 | |
106 | //fprintf(stderr, "DEV - device name(default=none)\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 | exit(-1); | |
111 | } | |
112 | ||
113 | static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type, | |
114 | char *name, char *key, int max) | |
115 | { | |
116 | int len; | |
7809c616 | 117 | int slen = strlen(key); |
c7699875 | 118 | |
eaa34ee3 | 119 | #if 0 |
c7699875 | 120 | /* XXX: verifying both name and key is required! */ |
121 | fprintf(stderr, "warning: ALGONAME/ALGOKEY will send to kernel promiscuously!(verifying them isn't implemented yet)\n"); | |
122 | #endif | |
123 | ||
124 | strncpy(alg->alg_name, name, sizeof(alg->alg_name)); | |
125 | ||
7809c616 | 126 | if (slen > 2 && strncmp(key, "0x", 2) == 0) { |
54f7328a | 127 | /* split two chars "0x" from the top */ |
128 | char *p = key + 2; | |
129 | int plen = slen - 2; | |
130 | int i; | |
131 | int j; | |
132 | ||
133 | /* Converting hexadecimal numbered string into real key; | |
134 | * Convert each two chars into one char(value). If number | |
135 | * of the length is odd, add zero on the top for rounding. | |
c7699875 | 136 | */ |
7809c616 | 137 | |
54f7328a | 138 | /* calculate length of the converted values(real key) */ |
139 | len = (plen + 1) / 2; | |
140 | if (len > max) | |
141 | invarg("\"ALGOKEY\" makes buffer overflow\n", key); | |
c7699875 | 142 | |
54f7328a | 143 | for (i = - (plen % 2), j = 0; j < len; i += 2, j++) { |
144 | char vbuf[3]; | |
737f15f6 | 145 | __u8 val; |
c7699875 | 146 | |
54f7328a | 147 | vbuf[0] = i >= 0 ? p[i] : '0'; |
148 | vbuf[1] = p[i + 1]; | |
149 | vbuf[2] = '\0'; | |
c7699875 | 150 | |
54f7328a | 151 | if (get_u8(&val, vbuf, 16)) |
152 | invarg("\"ALGOKEY\" is invalid", key); | |
7809c616 | 153 | |
54f7328a | 154 | alg->alg_key[j] = val; |
c7699875 | 155 | } |
c7699875 | 156 | } else { |
7809c616 | 157 | len = slen; |
c7699875 | 158 | if (len > 0) { |
159 | if (len > max) | |
160 | invarg("\"ALGOKEY\" makes buffer overflow\n", key); | |
161 | ||
162 | strncpy(alg->alg_key, key, len); | |
163 | } | |
164 | } | |
165 | ||
166 | alg->alg_key_len = len * 8; | |
167 | ||
168 | return 0; | |
169 | } | |
170 | ||
fb7399b2 | 171 | static int xfrm_seq_parse(__u32 *seq, int *argcp, char ***argvp) |
172 | { | |
173 | int argc = *argcp; | |
174 | char **argv = *argvp; | |
175 | ||
176 | if (get_u32(seq, *argv, 0)) | |
177 | invarg("\"SEQ\" is invalid", *argv); | |
178 | ||
179 | *seq = htonl(*seq); | |
180 | ||
181 | *argcp = argc; | |
182 | *argvp = argv; | |
183 | ||
184 | return 0; | |
185 | } | |
186 | ||
c7699875 | 187 | static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp) |
188 | { | |
189 | int argc = *argcp; | |
190 | char **argv = *argvp; | |
9e566a46 | 191 | int len = strlen(*argv); |
192 | ||
193 | if (len > 2 && strncmp(*argv, "0x", 2) == 0) { | |
194 | __u8 val = 0; | |
c7699875 | 195 | |
9e566a46 | 196 | if (get_u8(&val, *argv, 16)) |
197 | invarg("\"FLAG\" is invalid", *argv); | |
198 | *flags = val; | |
199 | } else { | |
eaa34ee3 | 200 | while (1) { |
201 | if (strcmp(*argv, "noecn") == 0) | |
202 | *flags |= XFRM_STATE_NOECN; | |
203 | else if (strcmp(*argv, "decap-dscp") == 0) | |
204 | *flags |= XFRM_STATE_DECAP_DSCP; | |
7ea4f5d3 MN |
205 | else if (strcmp(*argv, "wildrecv") == 0) |
206 | *flags |= XFRM_STATE_WILDRECV; | |
eaa34ee3 | 207 | else { |
208 | PREV_ARG(); /* back track */ | |
209 | break; | |
210 | } | |
211 | ||
212 | if (!NEXT_ARG_OK()) | |
213 | break; | |
214 | NEXT_ARG(); | |
215 | } | |
9e566a46 | 216 | } |
c7699875 | 217 | |
218 | filter.state_flags_mask = XFRM_FILTER_MASK_FULL; | |
219 | ||
220 | *argcp = argc; | |
221 | *argvp = argv; | |
222 | ||
223 | return 0; | |
224 | } | |
225 | ||
226 | static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv) | |
227 | { | |
228 | struct rtnl_handle rth; | |
229 | struct { | |
230 | struct nlmsghdr n; | |
231 | struct xfrm_usersa_info xsinfo; | |
232 | char buf[RTA_BUF_SIZE]; | |
233 | } req; | |
234 | char *idp = NULL; | |
235 | char *ealgop = NULL; | |
236 | char *aalgop = NULL; | |
237 | char *calgop = NULL; | |
7ea4f5d3 | 238 | char *coap = NULL; |
c7699875 | 239 | |
240 | memset(&req, 0, sizeof(req)); | |
241 | ||
242 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo)); | |
243 | req.n.nlmsg_flags = NLM_F_REQUEST|flags; | |
244 | req.n.nlmsg_type = cmd; | |
245 | req.xsinfo.family = preferred_family; | |
246 | ||
247 | req.xsinfo.lft.soft_byte_limit = XFRM_INF; | |
248 | req.xsinfo.lft.hard_byte_limit = XFRM_INF; | |
249 | req.xsinfo.lft.soft_packet_limit = XFRM_INF; | |
250 | req.xsinfo.lft.hard_packet_limit = XFRM_INF; | |
251 | ||
252 | while (argc > 0) { | |
7809c616 | 253 | if (strcmp(*argv, "mode") == 0) { |
c7699875 | 254 | NEXT_ARG(); |
255 | xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv); | |
256 | } else if (strcmp(*argv, "reqid") == 0) { | |
257 | NEXT_ARG(); | |
258 | xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv); | |
fb7399b2 | 259 | } else if (strcmp(*argv, "seq") == 0) { |
260 | NEXT_ARG(); | |
261 | xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv); | |
eaa34ee3 | 262 | } else if (strcmp(*argv, "replay-window") == 0) { |
263 | NEXT_ARG(); | |
264 | if (get_u8(&req.xsinfo.replay_window, *argv, 0)) | |
265 | invarg("\"replay-window\" value is invalid", *argv); | |
c7699875 | 266 | } else if (strcmp(*argv, "flag") == 0) { |
267 | NEXT_ARG(); | |
268 | xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv); | |
269 | } else if (strcmp(*argv, "sel") == 0) { | |
270 | NEXT_ARG(); | |
271 | xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv); | |
c7699875 | 272 | } else if (strcmp(*argv, "limit") == 0) { |
273 | NEXT_ARG(); | |
274 | xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv); | |
5cf576d9 SH |
275 | } else if (strcmp(*argv, "encap") == 0) { |
276 | struct xfrm_encap_tmpl encap; | |
277 | inet_prefix oa; | |
278 | NEXT_ARG(); | |
279 | xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); | |
280 | NEXT_ARG(); | |
281 | if (get_u16(&encap.encap_sport, *argv, 0)) | |
282 | invarg("\"encap\" sport value is invalid", *argv); | |
283 | encap.encap_sport = htons(encap.encap_sport); | |
284 | NEXT_ARG(); | |
285 | if (get_u16(&encap.encap_dport, *argv, 0)) | |
286 | invarg("\"encap\" dport value is invalid", *argv); | |
287 | encap.encap_dport = htons(encap.encap_dport); | |
288 | NEXT_ARG(); | |
289 | get_addr(&oa, *argv, AF_UNSPEC); | |
290 | memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa)); | |
291 | addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP, | |
292 | (void *)&encap, sizeof(encap)); | |
7ea4f5d3 MN |
293 | } else if (strcmp(*argv, "coa") == 0) { |
294 | inet_prefix coa; | |
295 | xfrm_address_t xcoa; | |
296 | ||
297 | if (coap) | |
298 | duparg("coa", *argv); | |
299 | coap = *argv; | |
300 | ||
301 | NEXT_ARG(); | |
302 | ||
303 | get_prefix(&coa, *argv, preferred_family); | |
304 | if (coa.family == AF_UNSPEC) | |
305 | invarg("\"coa\" address family is AF_UNSPEC", *argv); | |
306 | if (coa.bytelen > sizeof(xcoa)) | |
307 | invarg("\"coa\" address length is too large", *argv); | |
308 | ||
309 | memset(&xcoa, 0, sizeof(xcoa)); | |
310 | memcpy(&xcoa, &coa.data, coa.bytelen); | |
311 | ||
312 | addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR, | |
313 | (void *)&xcoa, sizeof(xcoa)); | |
c7699875 | 314 | } else { |
7809c616 | 315 | /* try to assume ALGO */ |
316 | int type = xfrm_algotype_getbyname(*argv); | |
317 | switch (type) { | |
318 | case XFRMA_ALG_CRYPT: | |
319 | case XFRMA_ALG_AUTH: | |
320 | case XFRMA_ALG_COMP: | |
321 | { | |
322 | /* ALGO */ | |
323 | struct { | |
324 | struct xfrm_algo alg; | |
325 | char buf[XFRM_ALGO_KEY_BUF_SIZE]; | |
326 | } alg; | |
327 | int len; | |
328 | char *name; | |
329 | char *key; | |
330 | ||
331 | switch (type) { | |
332 | case XFRMA_ALG_CRYPT: | |
333 | if (ealgop) | |
334 | duparg("ALGOTYPE", *argv); | |
335 | ealgop = *argv; | |
336 | break; | |
337 | case XFRMA_ALG_AUTH: | |
338 | if (aalgop) | |
339 | duparg("ALGOTYPE", *argv); | |
340 | aalgop = *argv; | |
341 | break; | |
342 | case XFRMA_ALG_COMP: | |
343 | if (calgop) | |
344 | duparg("ALGOTYPE", *argv); | |
345 | calgop = *argv; | |
346 | break; | |
347 | default: | |
348 | /* not reached */ | |
349 | invarg("\"ALGOTYPE\" is invalid\n", *argv); | |
350 | } | |
351 | ||
352 | if (!NEXT_ARG_OK()) | |
353 | missarg("ALGONAME"); | |
354 | NEXT_ARG(); | |
355 | name = *argv; | |
356 | ||
357 | if (!NEXT_ARG_OK()) | |
358 | missarg("ALGOKEY"); | |
359 | NEXT_ARG(); | |
360 | key = *argv; | |
361 | ||
362 | memset(&alg, 0, sizeof(alg)); | |
363 | ||
364 | xfrm_algo_parse((void *)&alg, type, name, key, | |
365 | sizeof(alg.buf)); | |
366 | len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len; | |
367 | ||
368 | addattr_l(&req.n, sizeof(req.buf), type, | |
369 | (void *)&alg, len); | |
370 | break; | |
371 | } | |
372 | default: | |
373 | /* try to assume ID */ | |
374 | if (idp) | |
375 | invarg("unknown", *argv); | |
376 | idp = *argv; | |
377 | ||
378 | /* ID */ | |
379 | xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id, | |
380 | &req.xsinfo.family, 0, &argc, &argv); | |
381 | if (preferred_family == AF_UNSPEC) | |
382 | preferred_family = req.xsinfo.family; | |
383 | } | |
c7699875 | 384 | } |
385 | argc--; argv++; | |
386 | } | |
387 | ||
388 | if (!idp) { | |
389 | fprintf(stderr, "Not enough information: \"ID\" is required\n"); | |
390 | exit(1); | |
391 | } | |
392 | ||
7ea4f5d3 MN |
393 | switch (req.xsinfo.mode) { |
394 | case XFRM_MODE_TRANSPORT: | |
395 | case XFRM_MODE_TUNNEL: | |
396 | if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { | |
397 | fprintf(stderr, "\"mode\" is invalid with proto=%s\n", | |
398 | strxf_xfrmproto(req.xsinfo.id.proto)); | |
399 | exit(1); | |
400 | } | |
401 | break; | |
402 | case XFRM_MODE_ROUTEOPTIMIZATION: | |
403 | case XFRM_MODE_IN_TRIGGER: | |
404 | if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { | |
405 | fprintf(stderr, "\"mode\" is invalid with proto=%s\n", | |
406 | strxf_xfrmproto(req.xsinfo.id.proto)); | |
407 | exit(1); | |
408 | } | |
409 | if (req.xsinfo.id.spi != 0) { | |
410 | fprintf(stderr, "\"spi\" must be 0 with proto=%s\n", | |
411 | strxf_xfrmproto(req.xsinfo.id.proto)); | |
412 | exit(1); | |
413 | } | |
414 | break; | |
415 | default: | |
416 | break; | |
417 | } | |
418 | ||
c7699875 | 419 | if (ealgop || aalgop || calgop) { |
7ea4f5d3 MN |
420 | if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { |
421 | fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", | |
422 | strxf_xfrmproto(req.xsinfo.id.proto)); | |
423 | exit(1); | |
424 | } | |
425 | } else { | |
426 | if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { | |
427 | fprintf(stderr, "\"ALGO\" is required with proto=%s\n", | |
428 | strxf_xfrmproto(req.xsinfo.id.proto)); | |
429 | exit (1); | |
430 | } | |
431 | } | |
432 | ||
433 | if (coap) { | |
434 | if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { | |
435 | fprintf(stderr, "\"coa\" is invalid with proto=%s\n", | |
436 | strxf_xfrmproto(req.xsinfo.id.proto)); | |
c7699875 | 437 | exit(1); |
438 | } | |
439 | } else { | |
7ea4f5d3 MN |
440 | if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { |
441 | fprintf(stderr, "\"coa\" is required with proto=%s\n", | |
442 | strxf_xfrmproto(req.xsinfo.id.proto)); | |
c7699875 | 443 | exit (1); |
444 | } | |
445 | } | |
446 | ||
447 | if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) | |
448 | exit(1); | |
449 | ||
450 | if (req.xsinfo.family == AF_UNSPEC) | |
451 | req.xsinfo.family = AF_INET; | |
452 | ||
453 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) | |
454 | exit(2); | |
455 | ||
456 | rtnl_close(&rth); | |
457 | ||
458 | return 0; | |
459 | } | |
460 | ||
fb7399b2 | 461 | static int xfrm_state_allocspi(int argc, char **argv) |
462 | { | |
463 | struct rtnl_handle rth; | |
464 | struct { | |
465 | struct nlmsghdr n; | |
466 | struct xfrm_userspi_info xspi; | |
467 | char buf[RTA_BUF_SIZE]; | |
468 | } req; | |
469 | char *idp = NULL; | |
470 | char *minp = NULL; | |
471 | char *maxp = NULL; | |
472 | char res_buf[NLMSG_BUF_SIZE]; | |
473 | struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf; | |
474 | ||
475 | memset(res_buf, 0, sizeof(res_buf)); | |
476 | ||
477 | memset(&req, 0, sizeof(req)); | |
478 | ||
479 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi)); | |
480 | req.n.nlmsg_flags = NLM_F_REQUEST; | |
481 | req.n.nlmsg_type = XFRM_MSG_ALLOCSPI; | |
482 | req.xspi.info.family = preferred_family; | |
483 | ||
484 | #if 0 | |
485 | req.xsinfo.lft.soft_byte_limit = XFRM_INF; | |
486 | req.xsinfo.lft.hard_byte_limit = XFRM_INF; | |
487 | req.xsinfo.lft.soft_packet_limit = XFRM_INF; | |
488 | req.xsinfo.lft.hard_packet_limit = XFRM_INF; | |
489 | #endif | |
490 | ||
491 | while (argc > 0) { | |
492 | if (strcmp(*argv, "mode") == 0) { | |
493 | NEXT_ARG(); | |
494 | xfrm_mode_parse(&req.xspi.info.mode, &argc, &argv); | |
495 | } else if (strcmp(*argv, "reqid") == 0) { | |
496 | NEXT_ARG(); | |
497 | xfrm_reqid_parse(&req.xspi.info.reqid, &argc, &argv); | |
498 | } else if (strcmp(*argv, "seq") == 0) { | |
499 | NEXT_ARG(); | |
500 | xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv); | |
501 | } else if (strcmp(*argv, "min") == 0) { | |
502 | if (minp) | |
503 | duparg("min", *argv); | |
504 | minp = *argv; | |
505 | ||
506 | NEXT_ARG(); | |
507 | ||
508 | if (get_u32(&req.xspi.min, *argv, 0)) | |
509 | invarg("\"min\" value is invalid", *argv); | |
510 | } else if (strcmp(*argv, "max") == 0) { | |
511 | if (maxp) | |
512 | duparg("max", *argv); | |
513 | maxp = *argv; | |
514 | ||
515 | NEXT_ARG(); | |
516 | ||
517 | if (get_u32(&req.xspi.max, *argv, 0)) | |
518 | invarg("\"max\" value is invalid", *argv); | |
519 | } else { | |
520 | /* try to assume ID */ | |
521 | if (idp) | |
522 | invarg("unknown", *argv); | |
523 | idp = *argv; | |
524 | ||
525 | /* ID */ | |
526 | xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id, | |
527 | &req.xspi.info.family, 0, &argc, &argv); | |
528 | if (req.xspi.info.id.spi) { | |
529 | fprintf(stderr, "\"SPI\" must be zero\n"); | |
530 | exit(1); | |
531 | } | |
532 | if (preferred_family == AF_UNSPEC) | |
533 | preferred_family = req.xspi.info.family; | |
534 | } | |
535 | argc--; argv++; | |
536 | } | |
537 | ||
538 | if (!idp) { | |
539 | fprintf(stderr, "Not enough information: \"ID\" is required\n"); | |
540 | exit(1); | |
541 | } | |
542 | ||
543 | if (minp) { | |
544 | if (!maxp) { | |
545 | fprintf(stderr, "\"max\" is missing\n"); | |
546 | exit(1); | |
547 | } | |
548 | if (req.xspi.min > req.xspi.max) { | |
549 | fprintf(stderr, "\"min\" valie is larger than \"max\" one\n"); | |
550 | exit(1); | |
551 | } | |
552 | } else { | |
553 | if (maxp) { | |
554 | fprintf(stderr, "\"min\" is missing\n"); | |
555 | exit(1); | |
556 | } | |
557 | ||
558 | /* XXX: Default value defined in PF_KEY; | |
559 | * See kernel's net/key/af_key.c(pfkey_getspi). | |
560 | */ | |
561 | req.xspi.min = 0x100; | |
562 | req.xspi.max = 0x0fffffff; | |
563 | ||
564 | /* XXX: IPCOMP spi is 16-bits; | |
565 | * See kernel's net/xfrm/xfrm_user(verify_userspi_info). | |
566 | */ | |
567 | if (req.xspi.info.id.proto == IPPROTO_COMP) | |
568 | req.xspi.max = 0xffff; | |
569 | } | |
570 | ||
571 | if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) | |
572 | exit(1); | |
573 | ||
574 | if (req.xspi.info.family == AF_UNSPEC) | |
575 | req.xspi.info.family = AF_INET; | |
576 | ||
577 | ||
578 | if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0) | |
579 | exit(2); | |
580 | ||
581 | if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) { | |
582 | fprintf(stderr, "An error :-)\n"); | |
583 | exit(1); | |
584 | } | |
585 | ||
586 | rtnl_close(&rth); | |
587 | ||
588 | return 0; | |
589 | } | |
590 | ||
c7699875 | 591 | static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo) |
592 | { | |
593 | if (!filter.use) | |
594 | return 1; | |
595 | ||
596 | if (filter.id_src_mask) | |
eaa34ee3 | 597 | if (xfrm_addr_match(&xsinfo->saddr, &filter.xsinfo.saddr, |
598 | filter.id_src_mask)) | |
c7699875 | 599 | return 0; |
600 | if (filter.id_dst_mask) | |
eaa34ee3 | 601 | if (xfrm_addr_match(&xsinfo->id.daddr, &filter.xsinfo.id.daddr, |
602 | filter.id_dst_mask)) | |
c7699875 | 603 | return 0; |
604 | if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask) | |
605 | return 0; | |
606 | if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask) | |
607 | return 0; | |
608 | if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask) | |
609 | return 0; | |
610 | if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask) | |
611 | return 0; | |
612 | if (filter.state_flags_mask) | |
613 | if ((xsinfo->flags & filter.xsinfo.flags) == 0) | |
614 | return 0; | |
615 | ||
616 | return 1; | |
617 | } | |
618 | ||
fb7399b2 | 619 | int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n, |
620 | void *arg) | |
c7699875 | 621 | { |
622 | FILE *fp = (FILE*)arg; | |
c7699875 | 623 | struct rtattr * tb[XFRMA_MAX+1]; |
90f93024 | 624 | struct rtattr * rta; |
c595c790 SH |
625 | struct xfrm_usersa_info *xsinfo = NULL; |
626 | struct xfrm_user_expire *xexp = NULL; | |
627 | struct xfrm_usersa_id *xsid = NULL; | |
628 | int len = n->nlmsg_len; | |
c7699875 | 629 | |
630 | if (n->nlmsg_type != XFRM_MSG_NEWSA && | |
90f93024 | 631 | n->nlmsg_type != XFRM_MSG_DELSA && |
669ae748 | 632 | n->nlmsg_type != XFRM_MSG_UPDSA && |
90f93024 | 633 | n->nlmsg_type != XFRM_MSG_EXPIRE) { |
c7699875 | 634 | fprintf(stderr, "Not a state: %08x %08x %08x\n", |
635 | n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); | |
636 | return 0; | |
637 | } | |
638 | ||
669ae748 SH |
639 | if (n->nlmsg_type == XFRM_MSG_DELSA) { |
640 | /* Dont blame me for this .. Herbert made me do it */ | |
641 | xsid = NLMSG_DATA(n); | |
af1b6a41 | 642 | len -= NLMSG_SPACE(sizeof(*xsid)); |
669ae748 | 643 | } else if (n->nlmsg_type == XFRM_MSG_EXPIRE) { |
90f93024 SH |
644 | xexp = NLMSG_DATA(n); |
645 | xsinfo = &xexp->state; | |
af1b6a41 | 646 | len -= NLMSG_SPACE(sizeof(*xexp)); |
90f93024 SH |
647 | } else { |
648 | xexp = NULL; | |
649 | xsinfo = NLMSG_DATA(n); | |
af1b6a41 | 650 | len -= NLMSG_SPACE(sizeof(*xsinfo)); |
90f93024 SH |
651 | } |
652 | ||
c7699875 | 653 | if (len < 0) { |
654 | fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); | |
655 | return -1; | |
656 | } | |
657 | ||
669ae748 | 658 | if (xsinfo && !xfrm_state_filter_match(xsinfo)) |
c7699875 | 659 | return 0; |
660 | ||
669ae748 | 661 | if (n->nlmsg_type == XFRM_MSG_DELSA) |
c595c790 | 662 | fprintf(fp, "Deleted "); |
669ae748 SH |
663 | else if (n->nlmsg_type == XFRM_MSG_UPDSA) |
664 | fprintf(fp, "Updated "); | |
c595c790 SH |
665 | else if (n->nlmsg_type == XFRM_MSG_EXPIRE) |
666 | fprintf(fp, "Expired "); | |
667 | ||
669ae748 SH |
668 | if (n->nlmsg_type == XFRM_MSG_DELSA) |
669 | rta = XFRMSID_RTA(xsid); | |
670 | else if (n->nlmsg_type == XFRM_MSG_EXPIRE) | |
90f93024 | 671 | rta = XFRMEXP_RTA(xexp); |
c595c790 | 672 | else |
90f93024 SH |
673 | rta = XFRMS_RTA(xsinfo); |
674 | ||
675 | parse_rtattr(tb, XFRMA_MAX, rta, len); | |
c7699875 | 676 | |
c595c790 | 677 | if (n->nlmsg_type == XFRM_MSG_DELSA) { |
669ae748 SH |
678 | //xfrm_policy_id_print(); |
679 | ||
680 | if (!tb[XFRMA_SA]) { | |
681 | fprintf(stderr, "Buggy XFRM_MSG_DELSA: no XFRMA_SA\n"); | |
682 | return -1; | |
683 | } | |
684 | if (RTA_PAYLOAD(tb[XFRMA_SA]) < sizeof(*xsinfo)) { | |
685 | fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n"); | |
686 | return -1; | |
c595c790 | 687 | } |
669ae748 | 688 | xsinfo = (struct xfrm_usersa_info *)RTA_DATA(tb[XFRMA_SA]); |
c595c790 | 689 | } |
c7699875 | 690 | |
fb7399b2 | 691 | xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL); |
c7699875 | 692 | |
90f93024 SH |
693 | if (n->nlmsg_type == XFRM_MSG_EXPIRE) { |
694 | fprintf(fp, "\t"); | |
695 | fprintf(fp, "hard %u", xexp->hard); | |
696 | fprintf(fp, "%s", _SL_); | |
697 | } | |
698 | ||
7809c616 | 699 | if (oneline) |
700 | fprintf(fp, "\n"); | |
669ae748 | 701 | fflush(fp); |
7809c616 | 702 | |
c7699875 | 703 | return 0; |
704 | } | |
705 | ||
706 | static int xfrm_state_get_or_delete(int argc, char **argv, int delete) | |
707 | { | |
708 | struct rtnl_handle rth; | |
709 | struct { | |
710 | struct nlmsghdr n; | |
711 | struct xfrm_usersa_id xsid; | |
7ea4f5d3 | 712 | char buf[RTA_BUF_SIZE]; |
c7699875 | 713 | } req; |
714 | struct xfrm_id id; | |
715 | char *idp = NULL; | |
716 | ||
717 | memset(&req, 0, sizeof(req)); | |
718 | ||
719 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid)); | |
720 | req.n.nlmsg_flags = NLM_F_REQUEST; | |
721 | req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA; | |
722 | req.xsid.family = preferred_family; | |
723 | ||
724 | while (argc > 0) { | |
7ea4f5d3 | 725 | xfrm_address_t saddr; |
c7699875 | 726 | |
727 | if (idp) | |
728 | invarg("unknown", *argv); | |
729 | idp = *argv; | |
730 | ||
731 | /* ID */ | |
732 | memset(&id, 0, sizeof(id)); | |
7ea4f5d3 MN |
733 | memset(&saddr, 0, sizeof(saddr)); |
734 | xfrm_id_parse(&saddr, &id, &req.xsid.family, 0, | |
c7699875 | 735 | &argc, &argv); |
736 | ||
737 | memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr)); | |
738 | req.xsid.spi = id.spi; | |
739 | req.xsid.proto = id.proto; | |
740 | ||
7ea4f5d3 MN |
741 | addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR, |
742 | (void *)&saddr, sizeof(saddr)); | |
743 | ||
c7699875 | 744 | argc--; argv++; |
745 | } | |
746 | ||
747 | if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) | |
748 | exit(1); | |
749 | ||
750 | if (req.xsid.family == AF_UNSPEC) | |
751 | req.xsid.family = AF_INET; | |
752 | ||
753 | if (delete) { | |
754 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) | |
755 | exit(2); | |
756 | } else { | |
757 | char buf[NLMSG_BUF_SIZE]; | |
758 | struct nlmsghdr *res_n = (struct nlmsghdr *)buf; | |
759 | ||
760 | memset(buf, 0, sizeof(buf)); | |
761 | ||
762 | if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0) | |
763 | exit(2); | |
764 | ||
765 | if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) { | |
766 | fprintf(stderr, "An error :-)\n"); | |
767 | exit(1); | |
768 | } | |
769 | } | |
770 | ||
771 | rtnl_close(&rth); | |
772 | ||
773 | return 0; | |
774 | } | |
775 | ||
776 | /* | |
777 | * With an existing state of nlmsg, make new nlmsg for deleting the state | |
778 | * and store it to buffer. | |
779 | */ | |
6dc9f016 | 780 | static int xfrm_state_keep(const struct sockaddr_nl *who, |
50772dc5 | 781 | struct nlmsghdr *n, |
6dc9f016 | 782 | void *arg) |
c7699875 | 783 | { |
784 | struct xfrm_buffer *xb = (struct xfrm_buffer *)arg; | |
785 | struct rtnl_handle *rth = xb->rth; | |
786 | struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n); | |
787 | int len = n->nlmsg_len; | |
788 | struct nlmsghdr *new_n; | |
789 | struct xfrm_usersa_id *xsid; | |
790 | ||
791 | if (n->nlmsg_type != XFRM_MSG_NEWSA) { | |
792 | fprintf(stderr, "Not a state: %08x %08x %08x\n", | |
793 | n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); | |
794 | return 0; | |
795 | } | |
796 | ||
797 | len -= NLMSG_LENGTH(sizeof(*xsinfo)); | |
798 | if (len < 0) { | |
799 | fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); | |
800 | return -1; | |
801 | } | |
802 | ||
803 | if (!xfrm_state_filter_match(xsinfo)) | |
804 | return 0; | |
805 | ||
806 | if (xb->offset > xb->size) { | |
9bec1a43 | 807 | fprintf(stderr, "State buffer overflow\n"); |
c7699875 | 808 | return -1; |
809 | } | |
810 | ||
811 | new_n = (struct nlmsghdr *)(xb->buf + xb->offset); | |
812 | new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid)); | |
813 | new_n->nlmsg_flags = NLM_F_REQUEST; | |
814 | new_n->nlmsg_type = XFRM_MSG_DELSA; | |
815 | new_n->nlmsg_seq = ++rth->seq; | |
816 | ||
817 | xsid = NLMSG_DATA(new_n); | |
818 | xsid->family = xsinfo->family; | |
819 | memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr)); | |
820 | xsid->spi = xsinfo->id.spi; | |
821 | xsid->proto = xsinfo->id.proto; | |
822 | ||
7ea4f5d3 MN |
823 | addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr, |
824 | sizeof(xsid->daddr)); | |
825 | ||
c7699875 | 826 | xb->offset += new_n->nlmsg_len; |
827 | xb->nlmsg_count ++; | |
828 | ||
829 | return 0; | |
830 | } | |
831 | ||
9bec1a43 | 832 | static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall) |
c7699875 | 833 | { |
834 | char *idp = NULL; | |
835 | struct rtnl_handle rth; | |
836 | ||
bd641cd6 | 837 | if(argc > 0) |
838 | filter.use = 1; | |
c7699875 | 839 | filter.xsinfo.family = preferred_family; |
840 | ||
841 | while (argc > 0) { | |
842 | if (strcmp(*argv, "mode") == 0) { | |
843 | NEXT_ARG(); | |
844 | xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv); | |
845 | ||
846 | filter.mode_mask = XFRM_FILTER_MASK_FULL; | |
847 | ||
848 | } else if (strcmp(*argv, "reqid") == 0) { | |
849 | NEXT_ARG(); | |
850 | xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv); | |
851 | ||
852 | filter.reqid_mask = XFRM_FILTER_MASK_FULL; | |
853 | ||
854 | } else if (strcmp(*argv, "flag") == 0) { | |
855 | NEXT_ARG(); | |
856 | xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv); | |
857 | ||
858 | filter.state_flags_mask = XFRM_FILTER_MASK_FULL; | |
859 | ||
860 | } else { | |
861 | if (idp) | |
862 | invarg("unknown", *argv); | |
863 | idp = *argv; | |
864 | ||
865 | /* ID */ | |
7809c616 | 866 | xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id, |
867 | &filter.xsinfo.family, 1, &argc, &argv); | |
c7699875 | 868 | if (preferred_family == AF_UNSPEC) |
869 | preferred_family = filter.xsinfo.family; | |
870 | } | |
871 | argc--; argv++; | |
872 | } | |
873 | ||
874 | if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) | |
875 | exit(1); | |
876 | ||
9bec1a43 | 877 | if (deleteall) { |
c7699875 | 878 | struct xfrm_buffer xb; |
9bec1a43 | 879 | char buf[NLMSG_DELETEALL_BUF_SIZE]; |
c7699875 | 880 | int i; |
881 | ||
882 | xb.buf = buf; | |
883 | xb.size = sizeof(buf); | |
884 | xb.rth = &rth; | |
885 | ||
886 | for (i = 0; ; i++) { | |
887 | xb.offset = 0; | |
888 | xb.nlmsg_count = 0; | |
889 | ||
890 | if (show_stats > 1) | |
9bec1a43 | 891 | fprintf(stderr, "Delete-all round = %d\n", i); |
c7699875 | 892 | |
893 | if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) { | |
894 | perror("Cannot send dump request"); | |
895 | exit(1); | |
896 | } | |
897 | ||
898 | if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb, NULL, NULL) < 0) { | |
9bec1a43 | 899 | fprintf(stderr, "Delete-all terminated\n"); |
c7699875 | 900 | exit(1); |
901 | } | |
902 | if (xb.nlmsg_count == 0) { | |
903 | if (show_stats > 1) | |
9bec1a43 | 904 | fprintf(stderr, "Delete-all completed\n"); |
c7699875 | 905 | break; |
906 | } | |
907 | ||
908 | if (rtnl_send(&rth, xb.buf, xb.offset) < 0) { | |
9bec1a43 | 909 | perror("Failed to send delete-all request\n"); |
c7699875 | 910 | exit(1); |
911 | } | |
912 | if (show_stats > 1) | |
9bec1a43 | 913 | fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count); |
c7699875 | 914 | |
915 | xb.offset = 0; | |
916 | xb.nlmsg_count = 0; | |
917 | } | |
918 | ||
919 | } else { | |
920 | if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) { | |
921 | perror("Cannot send dump request"); | |
922 | exit(1); | |
923 | } | |
924 | ||
925 | if (rtnl_dump_filter(&rth, xfrm_state_print, stdout, NULL, NULL) < 0) { | |
926 | fprintf(stderr, "Dump terminated\n"); | |
927 | exit(1); | |
928 | } | |
929 | } | |
930 | ||
931 | rtnl_close(&rth); | |
932 | ||
933 | exit(0); | |
934 | } | |
935 | ||
9bec1a43 | 936 | static int xfrm_state_flush(int argc, char **argv) |
bd641cd6 | 937 | { |
938 | struct rtnl_handle rth; | |
939 | struct { | |
940 | struct nlmsghdr n; | |
941 | struct xfrm_usersa_flush xsf; | |
942 | } req; | |
9bec1a43 | 943 | char *protop = NULL; |
bd641cd6 | 944 | |
945 | memset(&req, 0, sizeof(req)); | |
946 | ||
947 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf)); | |
948 | req.n.nlmsg_flags = NLM_F_REQUEST; | |
949 | req.n.nlmsg_type = XFRM_MSG_FLUSHSA; | |
7ea4f5d3 | 950 | req.xsf.proto = 0; |
bd641cd6 | 951 | |
9bec1a43 SH |
952 | while (argc > 0) { |
953 | if (strcmp(*argv, "proto") == 0) { | |
954 | int ret; | |
955 | ||
956 | if (protop) | |
957 | duparg("proto", *argv); | |
958 | protop = *argv; | |
959 | ||
960 | NEXT_ARG(); | |
961 | ||
962 | ret = xfrm_xfrmproto_getbyname(*argv); | |
963 | if (ret < 0) | |
964 | invarg("\"XFRM_PROTO\" is invalid", *argv); | |
965 | ||
966 | req.xsf.proto = (__u8)ret; | |
967 | } else | |
968 | invarg("unknown", *argv); | |
969 | ||
970 | argc--; argv++; | |
971 | } | |
972 | ||
bd641cd6 | 973 | if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) |
974 | exit(1); | |
975 | ||
976 | if (show_stats > 1) | |
9bec1a43 SH |
977 | fprintf(stderr, "Flush state proto=%s\n", |
978 | (req.xsf.proto == IPSEC_PROTO_ANY) ? "any" : | |
979 | strxf_xfrmproto(req.xsf.proto)); | |
bd641cd6 | 980 | |
981 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) | |
982 | exit(2); | |
983 | ||
984 | rtnl_close(&rth); | |
985 | ||
986 | return 0; | |
987 | } | |
988 | ||
c7699875 | 989 | int do_xfrm_state(int argc, char **argv) |
990 | { | |
991 | if (argc < 1) | |
9bec1a43 | 992 | return xfrm_state_list_or_deleteall(0, NULL, 0); |
c7699875 | 993 | |
994 | if (matches(*argv, "add") == 0) | |
995 | return xfrm_state_modify(XFRM_MSG_NEWSA, 0, | |
996 | argc-1, argv+1); | |
997 | if (matches(*argv, "update") == 0) | |
998 | return xfrm_state_modify(XFRM_MSG_UPDSA, 0, | |
999 | argc-1, argv+1); | |
fb7399b2 | 1000 | if (matches(*argv, "allocspi") == 0) |
1001 | return xfrm_state_allocspi(argc-1, argv+1); | |
9bec1a43 | 1002 | if (matches(*argv, "delete") == 0) |
c7699875 | 1003 | return xfrm_state_get_or_delete(argc-1, argv+1, 1); |
9bec1a43 SH |
1004 | if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0) |
1005 | return xfrm_state_list_or_deleteall(argc-1, argv+1, 1); | |
c7699875 | 1006 | if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 |
1007 | || matches(*argv, "lst") == 0) | |
9bec1a43 | 1008 | return xfrm_state_list_or_deleteall(argc-1, argv+1, 0); |
c7699875 | 1009 | if (matches(*argv, "get") == 0) |
1010 | return xfrm_state_get_or_delete(argc-1, argv+1, 0); | |
9bec1a43 SH |
1011 | if (matches(*argv, "flush") == 0) |
1012 | return xfrm_state_flush(argc-1, argv+1); | |
c7699875 | 1013 | if (matches(*argv, "help") == 0) |
1014 | usage(); | |
1015 | fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv); | |
1016 | exit(-1); | |
1017 | } |