Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/networking/libiproute/iptunnel.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 815 by niro, Sat Sep 1 22:45:15 2007 UTC revision 816 by niro, Fri Apr 24 18:33:46 2009 UTC
# Line 6  Line 6 
6   *   *
7   * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>   * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8   *   *
  *  
9   * Changes:   * Changes:
10   *   *
11   * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses   * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
# Line 14  Line 13 
13   * Phil Karn <karn@ka9q.ampr.org> 990408: "pmtudisc" flag   * Phil Karn <karn@ka9q.ampr.org> 990408: "pmtudisc" flag
14   */   */
15    
 #include "libbb.h"  
 #include <sys/socket.h>  
 #include <sys/ioctl.h>  
   
 #include <string.h>  
 #include <unistd.h>  
   
16  #include <netinet/ip.h>  #include <netinet/ip.h>
   
17  #include <net/if.h>  #include <net/if.h>
18  #include <net/if_arp.h>  #include <net/if_arp.h>
   
19  #include <asm/types.h>  #include <asm/types.h>
20    
21  #ifndef __constant_htons  #ifndef __constant_htons
22  #define __constant_htons htons  #define __constant_htons htons
23  #endif  #endif
 #include <linux/if_tunnel.h>  
24    
25    // FYI: #define SIOCDEVPRIVATE 0x89F0
26    
27    /* From linux/if_tunnel.h. #including it proved troublesome
28     * (redefiniton errors due to name collisions in linux/ and net[inet]/) */
29    #define SIOCGETTUNNEL   (SIOCDEVPRIVATE + 0)
30    #define SIOCADDTUNNEL   (SIOCDEVPRIVATE + 1)
31    #define SIOCDELTUNNEL   (SIOCDEVPRIVATE + 2)
32    #define SIOCCHGTUNNEL   (SIOCDEVPRIVATE + 3)
33    //#define SIOCGETPRL      (SIOCDEVPRIVATE + 4)
34    //#define SIOCADDPRL      (SIOCDEVPRIVATE + 5)
35    //#define SIOCDELPRL      (SIOCDEVPRIVATE + 6)
36    //#define SIOCCHGPRL      (SIOCDEVPRIVATE + 7)
37    #define GRE_CSUM        __constant_htons(0x8000)
38    //#define GRE_ROUTING     __constant_htons(0x4000)
39    #define GRE_KEY         __constant_htons(0x2000)
40    #define GRE_SEQ         __constant_htons(0x1000)
41    //#define GRE_STRICT      __constant_htons(0x0800)
42    //#define GRE_REC         __constant_htons(0x0700)
43    //#define GRE_FLAGS       __constant_htons(0x00F8)
44    //#define GRE_VERSION     __constant_htons(0x0007)
45    struct ip_tunnel_parm {
46     char            name[IFNAMSIZ];
47     int             link;
48     uint16_t        i_flags;
49     uint16_t        o_flags;
50     uint32_t        i_key;
51     uint32_t        o_key;
52     struct iphdr    iph;
53    };
54    /* SIT-mode i_flags */
55    //#define SIT_ISATAP 0x0001
56    //struct ip_tunnel_prl {
57    // uint32_t          addr;
58    // uint16_t          flags;
59    // uint16_t          __reserved;
60    // uint32_t          datalen;
61    // uint32_t          __reserved2;
62    // /* data follows */
63    //};
64    ///* PRL flags */
65    //#define PRL_DEFAULT 0x0001
66    
67    #include "ip_common.h"  /* #include "libbb.h" is inside */
68  #include "rt_names.h"  #include "rt_names.h"
69  #include "utils.h"  #include "utils.h"
 #include "ip_common.h"  
70    
71    
72    /* Dies on error */
73  static int do_ioctl_get_ifindex(char *dev)  static int do_ioctl_get_ifindex(char *dev)
74  {  {
75   struct ifreq ifr;   struct ifreq ifr;
# Line 44  static int do_ioctl_get_ifindex(char *de Line 77  static int do_ioctl_get_ifindex(char *de
77    
78   strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));   strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
79   fd = xsocket(AF_INET, SOCK_DGRAM, 0);   fd = xsocket(AF_INET, SOCK_DGRAM, 0);
80   if (ioctl(fd, SIOCGIFINDEX, &ifr)) {   xioctl(fd, SIOCGIFINDEX, &ifr);
  bb_perror_msg("ioctl");  
  return 0;  
  }  
81   close(fd);   close(fd);
82   return ifr.ifr_ifindex;   return ifr.ifr_ifindex;
83  }  }
# Line 56  static int do_ioctl_get_iftype(char *dev Line 86  static int do_ioctl_get_iftype(char *dev
86  {  {
87   struct ifreq ifr;   struct ifreq ifr;
88   int fd;   int fd;
89     int err;
90    
91   strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));   strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
92   fd = xsocket(AF_INET, SOCK_DGRAM, 0);   fd = xsocket(AF_INET, SOCK_DGRAM, 0);
93   if (ioctl(fd, SIOCGIFHWADDR, &ifr)) {   err = ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr);
  bb_perror_msg("ioctl");  
  return -1;  
  }  
94   close(fd);   close(fd);
95   return ifr.ifr_addr.sa_family;   return err ? -1 : ifr.ifr_addr.sa_family;
96  }  }
97    
   
98  static char *do_ioctl_get_ifname(int idx)  static char *do_ioctl_get_ifname(int idx)
99  {  {
100   static struct ifreq ifr;   struct ifreq ifr;
101   int fd;   int fd;
102     int err;
103    
104   ifr.ifr_ifindex = idx;   ifr.ifr_ifindex = idx;
105   fd = xsocket(AF_INET, SOCK_DGRAM, 0);   fd = xsocket(AF_INET, SOCK_DGRAM, 0);
106   if (ioctl(fd, SIOCGIFNAME, &ifr)) {   err = ioctl_or_warn(fd, SIOCGIFNAME, &ifr);
  bb_perror_msg("ioctl");  
  return NULL;  
  }  
107   close(fd);   close(fd);
108   return ifr.ifr_name;   return err ? NULL : xstrndup(ifr.ifr_name, sizeof(ifr.ifr_name));
109  }  }
110    
111    static int do_get_ioctl(const char *basedev, struct ip_tunnel_parm *p)
   
 static int do_get_ioctl(char *basedev, struct ip_tunnel_parm *p)  
112  {  {
113   struct ifreq ifr;   struct ifreq ifr;
114   int fd;   int fd;
# Line 94  static int do_get_ioctl(char *basedev, s Line 117  static int do_get_ioctl(char *basedev, s
117   strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name));   strncpy(ifr.ifr_name, basedev, sizeof(ifr.ifr_name));
118   ifr.ifr_ifru.ifru_data = (void*)p;   ifr.ifr_ifru.ifru_data = (void*)p;
119   fd = xsocket(AF_INET, SOCK_DGRAM, 0);   fd = xsocket(AF_INET, SOCK_DGRAM, 0);
120   err = ioctl(fd, SIOCGETTUNNEL, &ifr);   err = ioctl_or_warn(fd, SIOCGETTUNNEL, &ifr);
  if (err) {  
  bb_perror_msg("ioctl");  
  }  
121   close(fd);   close(fd);
122   return err;   return err;
123  }  }
124    
125  static int do_add_ioctl(int cmd, char *basedev, struct ip_tunnel_parm *p)  /* Dies on error, otherwise returns 0 */
126    static int do_add_ioctl(int cmd, const char *basedev, struct ip_tunnel_parm *p)
127  {  {
128   struct ifreq ifr;   struct ifreq ifr;
129   int fd;   int fd;
  int err;  
130    
131   if (cmd == SIOCCHGTUNNEL && p->name[0]) {   if (cmd == SIOCCHGTUNNEL && p->name[0]) {
132   strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));   strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
# Line 115  static int do_add_ioctl(int cmd, char *b Line 135  static int do_add_ioctl(int cmd, char *b
135   }   }
136   ifr.ifr_ifru.ifru_data = (void*)p;   ifr.ifr_ifru.ifru_data = (void*)p;
137   fd = xsocket(AF_INET, SOCK_DGRAM, 0);   fd = xsocket(AF_INET, SOCK_DGRAM, 0);
138   err = ioctl(fd, cmd, &ifr);  #if ENABLE_IOCTL_HEX2STR_ERROR
139   if (err) {   /* #define magic will turn ioctl# into string */
140   bb_perror_msg("ioctl");   if (cmd == SIOCCHGTUNNEL)
141   }   xioctl(fd, SIOCCHGTUNNEL, &ifr);
142     else
143     xioctl(fd, SIOCADDTUNNEL, &ifr);
144    #else
145     xioctl(fd, cmd, &ifr);
146    #endif
147   close(fd);   close(fd);
148   return err;   return 0;
149  }  }
150    
151  static int do_del_ioctl(char *basedev, struct ip_tunnel_parm *p)  /* Dies on error, otherwise returns 0 */
152    static int do_del_ioctl(const char *basedev, struct ip_tunnel_parm *p)
153  {  {
154   struct ifreq ifr;   struct ifreq ifr;
155   int fd;   int fd;
  int err;  
156    
157   if (p->name[0]) {   if (p->name[0]) {
158   strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));   strncpy(ifr.ifr_name, p->name, sizeof(ifr.ifr_name));
# Line 136  static int do_del_ioctl(char *basedev, s Line 161  static int do_del_ioctl(char *basedev, s
161   }   }
162   ifr.ifr_ifru.ifru_data = (void*)p;   ifr.ifr_ifru.ifru_data = (void*)p;
163   fd = xsocket(AF_INET, SOCK_DGRAM, 0);   fd = xsocket(AF_INET, SOCK_DGRAM, 0);
164   err = ioctl(fd, SIOCDELTUNNEL, &ifr);   xioctl(fd, SIOCDELTUNNEL, &ifr);
  if (err) {  
  bb_perror_msg("ioctl");  
  }  
165   close(fd);   close(fd);
166   return err;   return 0;
167  }  }
168    
169  static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)  /* Dies on error */
170    static void parse_args(char **argv, int cmd, struct ip_tunnel_parm *p)
171  {  {
172     static const char keywords[] ALIGN1 =
173     "mode\0""ipip\0""ip/ip\0""gre\0""gre/ip\0""sit\0""ipv6/ip\0"
174     "key\0""ikey\0""okey\0""seq\0""iseq\0""oseq\0"
175     "csum\0""icsum\0""ocsum\0""nopmtudisc\0""pmtudisc\0"
176     "remote\0""any\0""local\0""dev\0"
177     "ttl\0""inherit\0""tos\0""dsfield\0"
178     "name\0";
179     enum {
180     ARG_mode, ARG_ipip, ARG_ip_ip, ARG_gre, ARG_gre_ip, ARG_sit, ARG_ip6_ip,
181     ARG_key, ARG_ikey, ARG_okey, ARG_seq, ARG_iseq, ARG_oseq,
182     ARG_csum, ARG_icsum, ARG_ocsum, ARG_nopmtudisc, ARG_pmtudisc,
183     ARG_remote, ARG_any, ARG_local, ARG_dev,
184     ARG_ttl, ARG_inherit, ARG_tos, ARG_dsfield,
185     ARG_name
186     };
187   int count = 0;   int count = 0;
188   char medium[IFNAMSIZ];   char medium[IFNAMSIZ];
189     int key;
190    
191   memset(p, 0, sizeof(*p));   memset(p, 0, sizeof(*p));
192   memset(&medium, 0, sizeof(medium));   memset(&medium, 0, sizeof(medium));
193    
194   p->iph.version = 4;   p->iph.version = 4;
195   p->iph.ihl = 5;   p->iph.ihl = 5;
196  #ifndef IP_DF  #ifndef IP_DF
197  #define IP_DF 0x4000 /* Flag: "Don't Fragment" */  #define IP_DF 0x4000  /* Flag: "Don't Fragment" */
198  #endif  #endif
199   p->iph.frag_off = htons(IP_DF);   p->iph.frag_off = htons(IP_DF);
200    
201   while (argc > 0) {   while (*argv) {
202   if (strcmp(*argv, "mode") == 0) {   key = index_in_strings(keywords, *argv);
203     if (key == ARG_mode) {
204   NEXT_ARG();   NEXT_ARG();
205   if (strcmp(*argv, "ipip") == 0 ||   key = index_in_strings(keywords, *argv);
206      strcmp(*argv, "ip/ip") == 0) {   if (key == ARG_ipip ||
207        key == ARG_ip_ip) {
208   if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {   if (p->iph.protocol && p->iph.protocol != IPPROTO_IPIP) {
209   bb_error_msg("you managed to ask for more than one tunnel mode");   bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
  exit(-1);  
210   }   }
211   p->iph.protocol = IPPROTO_IPIP;   p->iph.protocol = IPPROTO_IPIP;
212   } else if (strcmp(*argv, "gre") == 0 ||   } else if (key == ARG_gre ||
213     strcmp(*argv, "gre/ip") == 0) {     key == ARG_gre_ip) {
214   if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {   if (p->iph.protocol && p->iph.protocol != IPPROTO_GRE) {
215   bb_error_msg("you managed to ask for more than one tunnel mode");   bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
  exit(-1);  
216   }   }
217   p->iph.protocol = IPPROTO_GRE;   p->iph.protocol = IPPROTO_GRE;
218   } else if (strcmp(*argv, "sit") == 0 ||   } else if (key == ARG_sit ||
219     strcmp(*argv, "ipv6/ip") == 0) {     key == ARG_ip6_ip) {
220   if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {   if (p->iph.protocol && p->iph.protocol != IPPROTO_IPV6) {
221   bb_error_msg("you managed to ask for more than one tunnel mode");   bb_error_msg_and_die("%s tunnel mode", "you managed to ask for more than one");
  exit(-1);  
222   }   }
223   p->iph.protocol = IPPROTO_IPV6;   p->iph.protocol = IPPROTO_IPV6;
224   } else {   } else {
225   bb_error_msg("cannot guess tunnel mode");   bb_error_msg_and_die("%s tunnel mode", "cannot guess");
  exit(-1);  
226   }   }
227   } else if (strcmp(*argv, "key") == 0) {   } else if (key == ARG_key) {
228   unsigned uval;   unsigned uval;
229   NEXT_ARG();   NEXT_ARG();
230   p->i_flags |= GRE_KEY;   p->i_flags |= GRE_KEY;
# Line 194  static int parse_args(int argc, char **a Line 232  static int parse_args(int argc, char **a
232   if (strchr(*argv, '.'))   if (strchr(*argv, '.'))
233   p->i_key = p->o_key = get_addr32(*argv);   p->i_key = p->o_key = get_addr32(*argv);
234   else {   else {
235   if (get_unsigned(&uval, *argv, 0)<0) {   if (get_unsigned(&uval, *argv, 0) < 0) {
236   bb_error_msg("invalid value of \"key\"");   invarg(*argv, "key");
  exit(-1);  
237   }   }
238   p->i_key = p->o_key = htonl(uval);   p->i_key = p->o_key = htonl(uval);
239   }   }
240   } else if (strcmp(*argv, "ikey") == 0) {   } else if (key == ARG_ikey) {
241   unsigned uval;   unsigned uval;
242   NEXT_ARG();   NEXT_ARG();
243   p->i_flags |= GRE_KEY;   p->i_flags |= GRE_KEY;
244   if (strchr(*argv, '.'))   if (strchr(*argv, '.'))
245   p->o_key = get_addr32(*argv);   p->o_key = get_addr32(*argv);
246   else {   else {
247   if (get_unsigned(&uval, *argv, 0)<0) {   if (get_unsigned(&uval, *argv, 0) < 0) {
248   bb_error_msg("invalid value of \"ikey\"");   invarg(*argv, "ikey");
  exit(-1);  
249   }   }
250   p->i_key = htonl(uval);   p->i_key = htonl(uval);
251   }   }
252   } else if (strcmp(*argv, "okey") == 0) {   } else if (key == ARG_okey) {
253   unsigned uval;   unsigned uval;
254   NEXT_ARG();   NEXT_ARG();
255   p->o_flags |= GRE_KEY;   p->o_flags |= GRE_KEY;
256   if (strchr(*argv, '.'))   if (strchr(*argv, '.'))
257   p->o_key = get_addr32(*argv);   p->o_key = get_addr32(*argv);
258   else {   else {
259   if (get_unsigned(&uval, *argv, 0)<0) {   if (get_unsigned(&uval, *argv, 0) < 0) {
260   bb_error_msg("invalid value of \"okey\"");   invarg(*argv, "okey");
  exit(-1);  
261   }   }
262   p->o_key = htonl(uval);   p->o_key = htonl(uval);
263   }   }
264   } else if (strcmp(*argv, "seq") == 0) {   } else if (key == ARG_seq) {
265   p->i_flags |= GRE_SEQ;   p->i_flags |= GRE_SEQ;
266   p->o_flags |= GRE_SEQ;   p->o_flags |= GRE_SEQ;
267   } else if (strcmp(*argv, "iseq") == 0) {   } else if (key == ARG_iseq) {
268   p->i_flags |= GRE_SEQ;   p->i_flags |= GRE_SEQ;
269   } else if (strcmp(*argv, "oseq") == 0) {   } else if (key == ARG_oseq) {
270   p->o_flags |= GRE_SEQ;   p->o_flags |= GRE_SEQ;
271   } else if (strcmp(*argv, "csum") == 0) {   } else if (key == ARG_csum) {
272   p->i_flags |= GRE_CSUM;   p->i_flags |= GRE_CSUM;
273   p->o_flags |= GRE_CSUM;   p->o_flags |= GRE_CSUM;
274   } else if (strcmp(*argv, "icsum") == 0) {   } else if (key == ARG_icsum) {
275   p->i_flags |= GRE_CSUM;   p->i_flags |= GRE_CSUM;
276   } else if (strcmp(*argv, "ocsum") == 0) {   } else if (key == ARG_ocsum) {
277   p->o_flags |= GRE_CSUM;   p->o_flags |= GRE_CSUM;
278   } else if (strcmp(*argv, "nopmtudisc") == 0) {   } else if (key == ARG_nopmtudisc) {
279   p->iph.frag_off = 0;   p->iph.frag_off = 0;
280   } else if (strcmp(*argv, "pmtudisc") == 0) {   } else if (key == ARG_pmtudisc) {
281   p->iph.frag_off = htons(IP_DF);   p->iph.frag_off = htons(IP_DF);
282   } else if (strcmp(*argv, "remote") == 0) {   } else if (key == ARG_remote) {
283   NEXT_ARG();   NEXT_ARG();
284   if (strcmp(*argv, "any"))   key = index_in_strings(keywords, *argv);
285     if (key != ARG_any)
286   p->iph.daddr = get_addr32(*argv);   p->iph.daddr = get_addr32(*argv);
287   } else if (strcmp(*argv, "local") == 0) {   } else if (key == ARG_local) {
288   NEXT_ARG();   NEXT_ARG();
289   if (strcmp(*argv, "any"))   key = index_in_strings(keywords, *argv);
290     if (key != ARG_any)
291   p->iph.saddr = get_addr32(*argv);   p->iph.saddr = get_addr32(*argv);
292   } else if (strcmp(*argv, "dev") == 0) {   } else if (key == ARG_dev) {
293   NEXT_ARG();   NEXT_ARG();
294   strncpy(medium, *argv, IFNAMSIZ-1);   strncpy(medium, *argv, IFNAMSIZ-1);
295   } else if (strcmp(*argv, "ttl") == 0) {   } else if (key == ARG_ttl) {
296   unsigned uval;   unsigned uval;
297   NEXT_ARG();   NEXT_ARG();
298   if (strcmp(*argv, "inherit") != 0) {   key = index_in_strings(keywords, *argv);
299     if (key != ARG_inherit) {
300   if (get_unsigned(&uval, *argv, 0))   if (get_unsigned(&uval, *argv, 0))
301   invarg(*argv, "TTL");   invarg(*argv, "TTL");
302   if (uval > 255)   if (uval > 255)
303   invarg(*argv, "TTL must be <=255");   invarg(*argv, "TTL must be <=255");
304   p->iph.ttl = uval;   p->iph.ttl = uval;
305   }   }
306   } else if (strcmp(*argv, "tos") == 0 ||   } else if (key == ARG_tos ||
307     matches(*argv, "dsfield") == 0) {     key == ARG_dsfield) {
308   uint32_t uval;   uint32_t uval;
309   NEXT_ARG();   NEXT_ARG();
310   if (strcmp(*argv, "inherit") != 0) {   key = index_in_strings(keywords, *argv);
311     if (key != ARG_inherit) {
312   if (rtnl_dsfield_a2n(&uval, *argv))   if (rtnl_dsfield_a2n(&uval, *argv))
313   invarg(*argv, "TOS");   invarg(*argv, "TOS");
314   p->iph.tos = uval;   p->iph.tos = uval;
315   } else   } else
316   p->iph.tos = 1;   p->iph.tos = 1;
317   } else {   } else {
318   if (strcmp(*argv, "name") == 0) {   if (key == ARG_name) {
319   NEXT_ARG();   NEXT_ARG();
320   }   }
321   if (p->name[0])   if (p->name[0])
# Line 286  static int parse_args(int argc, char **a Line 325  static int parse_args(int argc, char **a
325   struct ip_tunnel_parm old_p;   struct ip_tunnel_parm old_p;
326   memset(&old_p, 0, sizeof(old_p));   memset(&old_p, 0, sizeof(old_p));
327   if (do_get_ioctl(*argv, &old_p))   if (do_get_ioctl(*argv, &old_p))
328   return -1;   exit(EXIT_FAILURE);
329   *p = old_p;   *p = old_p;
330   }   }
331   }   }
332   count++;   count++;
333   argc--; argv++;   argv++;
334   }   }
335    
   
336   if (p->iph.protocol == 0) {   if (p->iph.protocol == 0) {
337   if (memcmp(p->name, "gre", 3) == 0)   if (memcmp(p->name, "gre", 3) == 0)
338   p->iph.protocol = IPPROTO_GRE;   p->iph.protocol = IPPROTO_GRE;
# Line 306  static int parse_args(int argc, char **a Line 344  static int parse_args(int argc, char **a
344    
345   if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {   if (p->iph.protocol == IPPROTO_IPIP || p->iph.protocol == IPPROTO_IPV6) {
346   if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {   if ((p->i_flags & GRE_KEY) || (p->o_flags & GRE_KEY)) {
347   bb_error_msg("keys are not allowed with ipip and sit");   bb_error_msg_and_die("keys are not allowed with ipip and sit");
  return -1;  
348   }   }
349   }   }
350    
351   if (medium[0]) {   if (medium[0]) {
352   p->link = do_ioctl_get_ifindex(medium);   p->link = do_ioctl_get_ifindex(medium);
  if (p->link == 0)  
  return -1;  
353   }   }
354    
355   if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {   if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
# Line 326  static int parse_args(int argc, char **a Line 361  static int parse_args(int argc, char **a
361   p->o_flags |= GRE_KEY;   p->o_flags |= GRE_KEY;
362   }   }
363   if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {   if (IN_MULTICAST(ntohl(p->iph.daddr)) && !p->iph.saddr) {
364   bb_error_msg("broadcast tunnel requires a source address");   bb_error_msg_and_die("broadcast tunnel requires a source address");
  return -1;  
365   }   }
  return 0;  
366  }  }
367    
368    
369  static int do_add(int cmd, int argc, char **argv)  /* Return value becomes exitcode. It's okay to not return at all */
370    static int do_add(int cmd, char **argv)
371  {  {
372   struct ip_tunnel_parm p;   struct ip_tunnel_parm p;
373    
374   if (parse_args(argc, argv, cmd, &p) < 0)   parse_args(argv, cmd, &p);
  return -1;  
375    
376   if (p.iph.ttl && p.iph.frag_off == 0) {   if (p.iph.ttl && p.iph.frag_off == 0) {
377   bb_error_msg("ttl != 0 and noptmudisc are incompatible");   bb_error_msg_and_die("ttl != 0 and noptmudisc are incompatible");
  return -1;  
378   }   }
379    
380   switch (p.iph.protocol) {   switch (p.iph.protocol) {
# Line 353  static int do_add(int cmd, int argc, cha Line 385  static int do_add(int cmd, int argc, cha
385   case IPPROTO_IPV6:   case IPPROTO_IPV6:
386   return do_add_ioctl(cmd, "sit0", &p);   return do_add_ioctl(cmd, "sit0", &p);
387   default:   default:
388   bb_error_msg("cannot determine tunnel mode (ipip, gre or sit)");   bb_error_msg_and_die("cannot determine tunnel mode (ipip, gre or sit)");
  return -1;  
389   }   }
  return -1;  
390  }  }
391    
392  static int do_del(int argc, char **argv)  /* Return value becomes exitcode. It's okay to not return at all */
393    static int do_del(char **argv)
394  {  {
395   struct ip_tunnel_parm p;   struct ip_tunnel_parm p;
396    
397   if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)   parse_args(argv, SIOCDELTUNNEL, &p);
  return -1;  
398    
399   switch (p.iph.protocol) {   switch (p.iph.protocol) {
400   case IPPROTO_IPIP:   case IPPROTO_IPIP:
# Line 376  static int do_del(int argc, char **argv) Line 406  static int do_del(int argc, char **argv)
406   default:   default:
407   return do_del_ioctl(p.name, &p);   return do_del_ioctl(p.name, &p);
408   }   }
  return -1;  
409  }  }
410    
411  static void print_tunnel(struct ip_tunnel_parm *p)  static void print_tunnel(struct ip_tunnel_parm *p)
# Line 399  static void print_tunnel(struct ip_tunne Line 428  static void print_tunnel(struct ip_tunne
428         p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any");         p->iph.daddr ? s1 : "any", p->iph.saddr ? s2 : "any");
429   if (p->link) {   if (p->link) {
430   char *n = do_ioctl_get_ifname(p->link);   char *n = do_ioctl_get_ifname(p->link);
431   if (n)   if (n) {
432   printf(" dev %s ", n);   printf(" dev %s ", n);
433     free(n);
434     }
435   }   }
436   if (p->iph.ttl)   if (p->iph.ttl)
437   printf(" ttl %d ", p->iph.ttl);   printf(" ttl %d ", p->iph.ttl);
# Line 428  static void print_tunnel(struct ip_tunne Line 459  static void print_tunnel(struct ip_tunne
459   }   }
460    
461   if (p->i_flags & GRE_SEQ)   if (p->i_flags & GRE_SEQ)
462   printf("%s  Drop packets out of sequence.\n", _SL_);   printf("%c  Drop packets out of sequence.\n", _SL_);
463   if (p->i_flags & GRE_CSUM)   if (p->i_flags & GRE_CSUM)
464   printf("%s  Checksum in received packet is required.", _SL_);   printf("%c  Checksum in received packet is required.", _SL_);
465   if (p->o_flags & GRE_SEQ)   if (p->o_flags & GRE_SEQ)
466   printf("%s  Sequence packets on output.", _SL_);   printf("%c  Sequence packets on output.", _SL_);
467   if (p->o_flags & GRE_CSUM)   if (p->o_flags & GRE_CSUM)
468   printf("%s  Checksum output packets.", _SL_);   printf("%c  Checksum output packets.", _SL_);
469  }  }
470    
471  static int do_tunnels_list(struct ip_tunnel_parm *p)  static void do_tunnels_list(struct ip_tunnel_parm *p)
472  {  {
473   char name[IFNAMSIZ];   char name[IFNAMSIZ];
474   unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,   unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
# Line 447  static int do_tunnels_list(struct ip_tun Line 478  static int do_tunnels_list(struct ip_tun
478   int type;   int type;
479   struct ip_tunnel_parm p1;   struct ip_tunnel_parm p1;
480   char buf[512];   char buf[512];
481   FILE *fp = fopen("/proc/net/dev", "r");   FILE *fp = fopen_or_warn("/proc/net/dev", "r");
482    
483   if (fp == NULL) {   if (fp == NULL) {
484   perror("fopen");   return;
  return -1;  
485   }   }
486     /* skip headers */
487   fgets(buf, sizeof(buf), fp);   fgets(buf, sizeof(buf), fp);
488   fgets(buf, sizeof(buf), fp);   fgets(buf, sizeof(buf), fp);
489    
# Line 464  static int do_tunnels_list(struct ip_tun Line 494  static int do_tunnels_list(struct ip_tun
494   ptr = strchr(buf, ':');   ptr = strchr(buf, ':');
495   if (ptr == NULL ||   if (ptr == NULL ||
496      (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {      (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
497   bb_error_msg("wrong format of /proc/net/dev. Sorry");   bb_error_msg("wrong format of /proc/net/dev");
498   return -1;   return;
499   }   }
500   if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu",   if (sscanf(ptr, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu",
501     &rx_bytes, &rx_packets, &rx_errs, &rx_drops,     &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
# Line 477  static int do_tunnels_list(struct ip_tun Line 507  static int do_tunnels_list(struct ip_tun
507   continue;   continue;
508   type = do_ioctl_get_iftype(name);   type = do_ioctl_get_iftype(name);
509   if (type == -1) {   if (type == -1) {
510   bb_error_msg("failed to get type of [%s]", name);   bb_error_msg("cannot get type of [%s]", name);
511   continue;   continue;
512   }   }
513   if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)   if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
# Line 492  static int do_tunnels_list(struct ip_tun Line 522  static int do_tunnels_list(struct ip_tun
522      (p->i_key && p1.i_key != p->i_key))      (p->i_key && p1.i_key != p->i_key))
523   continue;   continue;
524   print_tunnel(&p1);   print_tunnel(&p1);
525   puts("");   bb_putchar('\n');
526   }   }
  return 0;  
527  }  }
528    
529  static int do_show(int argc, char **argv)  /* Return value becomes exitcode. It's okay to not return at all */
530    static int do_show(char **argv)
531  {  {
532   int err;   int err;
533   struct ip_tunnel_parm p;   struct ip_tunnel_parm p;
534    
535   if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)   parse_args(argv, SIOCGETTUNNEL, &p);
  return -1;  
536    
537   switch (p.iph.protocol) {   switch (p.iph.protocol) {
538   case IPPROTO_IPIP:   case IPPROTO_IPIP:
# Line 523  static int do_show(int argc, char **argv Line 552  static int do_show(int argc, char **argv
552   return -1;   return -1;
553    
554   print_tunnel(&p);   print_tunnel(&p);
555   puts("");   bb_putchar('\n');
556   return 0;   return 0;
557  }  }
558    
559  int do_iptunnel(int argc, char **argv)  /* Return value becomes exitcode. It's okay to not return at all */
560    int do_iptunnel(char **argv)
561  {  {
562   if (argc > 0) {   static const char keywords[] ALIGN1 =
563   if (matches(*argv, "add") == 0)   "add\0""change\0""delete\0""show\0""list\0""lst\0";
564   return do_add(SIOCADDTUNNEL, argc-1, argv+1);   enum { ARG_add = 0, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst };
565   if (matches(*argv, "change") == 0)   int key;
566   return do_add(SIOCCHGTUNNEL, argc-1, argv+1);  
567   if (matches(*argv, "del") == 0)   if (*argv) {
568   return do_del(argc-1, argv+1);   key = index_in_substrings(keywords, *argv);
569   if (matches(*argv, "show") == 0 ||   if (key < 0)
570      matches(*argv, "lst") == 0 ||   bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
571      matches(*argv, "list") == 0)   argv++;
572   return do_show(argc-1, argv+1);   if (key == ARG_add)
573   } else   return do_add(SIOCADDTUNNEL, argv);
574   return do_show(0, NULL);   if (key == ARG_change)
575     return do_add(SIOCCHGTUNNEL, argv);
576   bb_error_msg_and_die("command \"%s\" is unknown", *argv);   if (key == ARG_del)
577     return do_del(argv);
578     }
579     return do_show(argv);
580  }  }

Legend:
Removed from v.815  
changed lines
  Added in v.816