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