Magellan Linux

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

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

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 7  Line 7 
7   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8   */   */
9    
10  #include "libbb.h"  //#include <sys/ioctl.h>
11    //#include <sys/socket.h>
 #include <sys/ioctl.h>  
 #include <sys/socket.h>  
   
12  #include <net/if.h>  #include <net/if.h>
13  #include <net/if_packet.h>  #include <net/if_packet.h>
14  #include <netpacket/packet.h>  #include <netpacket/packet.h>
   
15  #include <net/ethernet.h>  #include <net/ethernet.h>
16    
17    #include "ip_common.h"  /* #include "libbb.h" is inside */
18  #include "rt_names.h"  #include "rt_names.h"
19  #include "utils.h"  #include "utils.h"
 #include "ip_common.h"  
20    
21  /* take from linux/sockios.h */  /* taken from linux/sockios.h */
22  #define SIOCSIFNAME 0x8923 /* set interface name */  #define SIOCSIFNAME 0x8923 /* set interface name */
23    
24  static int on_off(char *msg)  /* Exits on error */
 {  
  bb_error_msg("error: argument of \"%s\" must be \"on\" or \"off\"", msg);  
  return -1;  
 }  
   
25  static int get_ctl_fd(void)  static int get_ctl_fd(void)
26  {  {
  int s_errno;  
27   int fd;   int fd;
28    
29   fd = socket(PF_INET, SOCK_DGRAM, 0);   fd = socket(PF_INET, SOCK_DGRAM, 0);
30   if (fd >= 0)   if (fd >= 0)
31   return fd;   return fd;
  s_errno = errno;  
32   fd = socket(PF_PACKET, SOCK_DGRAM, 0);   fd = socket(PF_PACKET, SOCK_DGRAM, 0);
33   if (fd >= 0)   if (fd >= 0)
34   return fd;   return fd;
35   fd = socket(PF_INET6, SOCK_DGRAM, 0);   return xsocket(PF_INET6, SOCK_DGRAM, 0);
  if (fd >= 0)  
  return fd;  
  errno = s_errno;  
  bb_perror_msg("cannot create control socket");  
  return -1;  
36  }  }
37    
38  static int do_chflags(char *dev, uint32_t flags, uint32_t mask)  /* Exits on error */
39    static void do_chflags(char *dev, uint32_t flags, uint32_t mask)
40  {  {
41   struct ifreq ifr;   struct ifreq ifr;
42   int fd;   int fd;
  int err;  
43    
44   strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));   strncpy_IFNAMSIZ(ifr.ifr_name, dev);
45   fd = get_ctl_fd();   fd = get_ctl_fd();
46   if (fd < 0)   xioctl(fd, SIOCGIFFLAGS, &ifr);
47   return -1;   if ((ifr.ifr_flags ^ flags) & mask) {
  err = ioctl(fd, SIOCGIFFLAGS, &ifr);  
  if (err) {  
  bb_perror_msg("SIOCGIFFLAGS");  
  close(fd);  
  return -1;  
  }  
  if ((ifr.ifr_flags^flags)&mask) {  
48   ifr.ifr_flags &= ~mask;   ifr.ifr_flags &= ~mask;
49   ifr.ifr_flags |= mask&flags;   ifr.ifr_flags |= mask & flags;
50   err = ioctl(fd, SIOCSIFFLAGS, &ifr);   xioctl(fd, SIOCSIFFLAGS, &ifr);
  if (err)  
  bb_perror_msg("SIOCSIFFLAGS");  
51   }   }
52   close(fd);   close(fd);
  return err;  
53  }  }
54    
55  static int do_changename(char *dev, char *newdev)  /* Exits on error */
56    static void do_changename(char *dev, char *newdev)
57  {  {
58   struct ifreq ifr;   struct ifreq ifr;
59   int fd;   int fd;
  int err;  
60    
61   strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));   strncpy_IFNAMSIZ(ifr.ifr_name, dev);
62   strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname));   strncpy_IFNAMSIZ(ifr.ifr_newname, newdev);
63   fd = get_ctl_fd();   fd = get_ctl_fd();
64   if (fd < 0)   xioctl(fd, SIOCSIFNAME, &ifr);
  return -1;  
  err = ioctl(fd, SIOCSIFNAME, &ifr);  
  if (err) {  
  bb_perror_msg("SIOCSIFNAME");  
  close(fd);  
  return -1;  
  }  
65   close(fd);   close(fd);
  return err;  
66  }  }
67    
68  static int set_qlen(char *dev, int qlen)  /* Exits on error */
69    static void set_qlen(char *dev, int qlen)
70  {  {
71   struct ifreq ifr;   struct ifreq ifr;
72   int s;   int s;
73    
74   s = get_ctl_fd();   s = get_ctl_fd();
  if (s < 0)  
  return -1;  
   
75   memset(&ifr, 0, sizeof(ifr));   memset(&ifr, 0, sizeof(ifr));
76   strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));   strncpy_IFNAMSIZ(ifr.ifr_name, dev);
77   ifr.ifr_qlen = qlen;   ifr.ifr_qlen = qlen;
78   if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {   xioctl(s, SIOCSIFTXQLEN, &ifr);
  bb_perror_msg("SIOCSIFXQLEN");  
  close(s);  
  return -1;  
  }  
79   close(s);   close(s);
   
  return 0;  
80  }  }
81    
82  static int set_mtu(char *dev, int mtu)  /* Exits on error */
83    static void set_mtu(char *dev, int mtu)
84  {  {
85   struct ifreq ifr;   struct ifreq ifr;
86   int s;   int s;
87    
88   s = get_ctl_fd();   s = get_ctl_fd();
  if (s < 0)  
  return -1;  
   
89   memset(&ifr, 0, sizeof(ifr));   memset(&ifr, 0, sizeof(ifr));
90   strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));   strncpy_IFNAMSIZ(ifr.ifr_name, dev);
91   ifr.ifr_mtu = mtu;   ifr.ifr_mtu = mtu;
92   if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {   xioctl(s, SIOCSIFMTU, &ifr);
  bb_perror_msg("SIOCSIFMTU");  
  close(s);  
  return -1;  
  }  
93   close(s);   close(s);
   
  return 0;  
94  }  }
95    
96    /* Exits on error */
97  static int get_address(char *dev, int *htype)  static int get_address(char *dev, int *htype)
98  {  {
99   struct ifreq ifr;   struct ifreq ifr;
# Line 150  static int get_address(char *dev, int *h Line 101  static int get_address(char *dev, int *h
101   socklen_t alen;   socklen_t alen;
102   int s;   int s;
103    
104   s = socket(PF_PACKET, SOCK_DGRAM, 0);   s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
  if (s < 0) {  
  bb_perror_msg("socket(PF_PACKET)");  
  return -1;  
  }  
105    
106   memset(&ifr, 0, sizeof(ifr));   memset(&ifr, 0, sizeof(ifr));
107   strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));   strncpy_IFNAMSIZ(ifr.ifr_name, dev);
108   if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {   xioctl(s, SIOCGIFINDEX, &ifr);
  bb_perror_msg("SIOCGIFINDEX");  
  close(s);  
  return -1;  
  }  
109    
110   memset(&me, 0, sizeof(me));   memset(&me, 0, sizeof(me));
111   me.sll_family = AF_PACKET;   me.sll_family = AF_PACKET;
112   me.sll_ifindex = ifr.ifr_ifindex;   me.sll_ifindex = ifr.ifr_ifindex;
113   me.sll_protocol = htons(ETH_P_LOOP);   me.sll_protocol = htons(ETH_P_LOOP);
114   if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {   xbind(s, (struct sockaddr*)&me, sizeof(me));
  bb_perror_msg("bind");  
  close(s);  
  return -1;  
  }  
   
115   alen = sizeof(me);   alen = sizeof(me);
116   if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {   getsockname(s, (struct sockaddr*)&me, &alen);
117   bb_perror_msg("getsockname");   //never happens:
118   close(s);   //if (getsockname(s, (struct sockaddr*)&me, &alen) == -1)
119   return -1;   // bb_perror_msg_and_die("getsockname");
  }  
120   close(s);   close(s);
121   *htype = me.sll_hatype;   *htype = me.sll_hatype;
122   return me.sll_halen;   return me.sll_halen;
123  }  }
124    
125  static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)  /* Exits on error */
126    static void parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
127  {  {
128   int alen;   int alen;
129    
130   memset(ifr, 0, sizeof(*ifr));   memset(ifr, 0, sizeof(*ifr));
131   strncpy(ifr->ifr_name, dev, sizeof(ifr->ifr_name));   strncpy_IFNAMSIZ(ifr->ifr_name, dev);
132   ifr->ifr_hwaddr.sa_family = hatype;   ifr->ifr_hwaddr.sa_family = hatype;
133   alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla);  
134     alen = hatype == 1/*ARPHRD_ETHER*/ ? 14/*ETH_HLEN*/ : 19/*INFINIBAND_HLEN*/;
135     alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), alen, lla);
136   if (alen < 0)   if (alen < 0)
137   return -1;   exit(EXIT_FAILURE);
138   if (alen != halen) {   if (alen != halen) {
139   bb_error_msg("wrong address (%s) length: expected %d bytes", lla, halen);   bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen);
  return -1;  
140   }   }
  return 0;  
141  }  }
142    
143  static int set_address(struct ifreq *ifr, int brd)  /* Exits on error */
144    static void set_address(struct ifreq *ifr, int brd)
145  {  {
146   int s;   int s;
147    
148   s = get_ctl_fd();   s = get_ctl_fd();
149   if (s < 0)   if (brd)
150   return -1;   xioctl(s, SIOCSIFHWBROADCAST, ifr);
151   if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {   else
152   bb_perror_msg(brd ? "SIOCSIFHWBROADCAST" : "SIOCSIFHWADDR");   xioctl(s, SIOCSIFHWADDR, ifr);
  close(s);  
  return -1;  
  }  
153   close(s);   close(s);
  return 0;  
154  }  }
155    
156    
157  static int do_set(int argc, char **argv)  static void die_must_be_on_off(const char *msg) NORETURN;
158    static void die_must_be_on_off(const char *msg)
159    {
160     bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg);
161    }
162    
163    /* Return value becomes exitcode. It's okay to not return at all */
164    static int do_set(char **argv)
165  {  {
166   char *dev = NULL;   char *dev = NULL;
167   uint32_t mask = 0;   uint32_t mask = 0;
# Line 231  static int do_set(int argc, char **argv) Line 173  static int do_set(int argc, char **argv)
173   struct ifreq ifr0, ifr1;   struct ifreq ifr0, ifr1;
174   char *newname = NULL;   char *newname = NULL;
175   int htype, halen;   int htype, halen;
176     static const char keywords[] ALIGN1 =
177   while (argc > 0) {   "up\0""down\0""name\0""mtu\0""multicast\0"
178   if (strcmp(*argv, "up") == 0) {   "arp\0""address\0""dev\0";
179     enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_multicast,
180     ARG_arp, ARG_addr, ARG_dev };
181     static const char str_on_off[] ALIGN1 = "on\0""off\0";
182     enum { PARM_on = 0, PARM_off };
183     smalluint key;
184    
185     while (*argv) {
186     /* substring search ensures that e.g. "addr" and "address"
187     * are both accepted */
188     key = index_in_substrings(keywords, *argv);
189     if (key == ARG_up) {
190   mask |= IFF_UP;   mask |= IFF_UP;
191   flags |= IFF_UP;   flags |= IFF_UP;
192   } else if (strcmp(*argv, "down") == 0) {   }
193     if (key == ARG_down) {
194   mask |= IFF_UP;   mask |= IFF_UP;
195   flags &= ~IFF_UP;   flags &= ~IFF_UP;
196   } else if (strcmp(*argv, "name") == 0) {   }
197     if (key == ARG_name) {
198   NEXT_ARG();   NEXT_ARG();
199   newname = *argv;   newname = *argv;
200   } else if (strcmp(*argv, "mtu") == 0) {   }
201     if (key == ARG_mtu) {
202   NEXT_ARG();   NEXT_ARG();
203   if (mtu != -1)   if (mtu != -1)
204   duparg("mtu", *argv);   duparg("mtu", *argv);
205   if (get_integer(&mtu, *argv, 0))   mtu = get_unsigned(*argv, "mtu");
206   invarg(*argv, "mtu");   }
207   } else if (strcmp(*argv, "multicast") == 0) {   if (key == ARG_multicast) {
208     int param;
209   NEXT_ARG();   NEXT_ARG();
210   mask |= IFF_MULTICAST;   mask |= IFF_MULTICAST;
211   if (strcmp(*argv, "on") == 0) {   param = index_in_strings(str_on_off, *argv);
212     if (param < 0)
213     die_must_be_on_off("multicast");
214     if (param == PARM_on)
215   flags |= IFF_MULTICAST;   flags |= IFF_MULTICAST;
216   } else if (strcmp(*argv, "off") == 0) {   else
217   flags &= ~IFF_MULTICAST;   flags &= ~IFF_MULTICAST;
218   } else   }
219   return on_off("multicast");   if (key == ARG_arp) {
220   } else if (strcmp(*argv, "arp") == 0) {   int param;
221   NEXT_ARG();   NEXT_ARG();
222   mask |= IFF_NOARP;   mask |= IFF_NOARP;
223   if (strcmp(*argv, "on") == 0) {   param = index_in_strings(str_on_off, *argv);
224     if (param < 0)
225     die_must_be_on_off("arp");
226     if (param == PARM_on)
227   flags &= ~IFF_NOARP;   flags &= ~IFF_NOARP;
228   } else if (strcmp(*argv, "off") == 0) {   else
229   flags |= IFF_NOARP;   flags |= IFF_NOARP;
230   } else   }
231   return on_off("noarp");   if (key == ARG_addr) {
  } else if (strcmp(*argv, "addr") == 0) {  
232   NEXT_ARG();   NEXT_ARG();
233   newaddr = *argv;   newaddr = *argv;
234   } else {   }
235   if (strcmp(*argv, "dev") == 0) {   if (key >= ARG_dev) {
236     if (key == ARG_dev) {
237   NEXT_ARG();   NEXT_ARG();
238   }   }
239   if (dev)   if (dev)
240   duparg2("dev", *argv);   duparg2("dev", *argv);
241   dev = *argv;   dev = *argv;
242   }   }
243   argc--; argv++;   argv++;
244   }   }
245    
246   if (!dev) {   if (!dev) {
247   bb_error_msg(bb_msg_requires_arg, "\"dev\"");   bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\"");
  exit(-1);  
248   }   }
249    
250   if (newaddr || newbrd) {   if (newaddr || newbrd) {
251   halen = get_address(dev, &htype);   halen = get_address(dev, &htype);
  if (halen < 0)  
  return -1;  
252   if (newaddr) {   if (newaddr) {
253   if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)   parse_address(dev, htype, halen, newaddr, &ifr0);
  return -1;  
254   }   }
255   if (newbrd) {   if (newbrd) {
256   if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)   parse_address(dev, htype, halen, newbrd, &ifr1);
  return -1;  
257   }   }
258   }   }
259    
260   if (newname && strcmp(dev, newname)) {   if (newname && strcmp(dev, newname)) {
261   if (do_changename(dev, newname) < 0)   do_changename(dev, newname);
  return -1;  
262   dev = newname;   dev = newname;
263   }   }
264   if (qlen != -1) {   if (qlen != -1) {
265   if (set_qlen(dev, qlen) < 0)   set_qlen(dev, qlen);
  return -1;  
266   }   }
267   if (mtu != -1) {   if (mtu != -1) {
268   if (set_mtu(dev, mtu) < 0)   set_mtu(dev, mtu);
  return -1;  
269   }   }
270   if (newaddr || newbrd) {   if (newaddr || newbrd) {
271   if (newbrd) {   if (newbrd) {
272   if (set_address(&ifr1, 1) < 0)   set_address(&ifr1, 1);
  return -1;  
273   }   }
274   if (newaddr) {   if (newaddr) {
275   if (set_address(&ifr0, 0) < 0)   set_address(&ifr0, 0);
  return -1;  
276   }   }
277   }   }
278   if (mask)   if (mask)
279   return do_chflags(dev, flags, mask);   do_chflags(dev, flags, mask);
280   return 0;   return 0;
281  }  }
282    
283  static int ipaddr_list_link(int argc, char **argv)  static int ipaddr_list_link(char **argv)
284  {  {
285   preferred_family = AF_PACKET;   preferred_family = AF_PACKET;
286   return ipaddr_list_or_flush(argc, argv, 0);   return ipaddr_list_or_flush(argv, 0);
287  }  }
288    
289  int do_iplink(int argc, char **argv)  /* Return value becomes exitcode. It's okay to not return at all */
290    int do_iplink(char **argv)
291  {  {
292   if (argc > 0) {   static const char keywords[] ALIGN1 =
293   if (matches(*argv, "set") == 0)   "set\0""show\0""lst\0""list\0";
294   return do_set(argc-1, argv+1);   int key;
295   if (matches(*argv, "show") == 0 ||   if (!*argv)
296      matches(*argv, "lst") == 0 ||   return ipaddr_list_link(argv);
297      matches(*argv, "list") == 0)   key = index_in_substrings(keywords, *argv);
298   return ipaddr_list_link(argc-1, argv+1);   if (key < 0)
299   } else   bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
300   return ipaddr_list_link(0, NULL);   argv++;
301     if (key == 0) /* set */
302   bb_error_msg("command \"%s\" is unknown", *argv);   return do_set(argv);
303   exit(-1);   /* show, lst, list */
304     return ipaddr_list_link(argv);
305  }  }

Legend:
Removed from v.532  
changed lines
  Added in v.984