Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 816 - (hide annotations) (download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 6629 byte(s)
-updated to busybox-1.13.4
1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * iplink.c "ip link".
4     *
5     * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6     *
7     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8     */
9    
10 niro 816 //#include <sys/ioctl.h>
11     //#include <sys/socket.h>
12 niro 532 #include <net/if.h>
13     #include <net/if_packet.h>
14     #include <netpacket/packet.h>
15     #include <net/ethernet.h>
16    
17 niro 816 #include "ip_common.h" /* #include "libbb.h" is inside */
18 niro 532 #include "rt_names.h"
19     #include "utils.h"
20    
21 niro 816 /* taken from linux/sockios.h */
22 niro 532 #define SIOCSIFNAME 0x8923 /* set interface name */
23    
24 niro 816 /* Exits on error */
25 niro 532 static int get_ctl_fd(void)
26     {
27     int fd;
28    
29     fd = socket(PF_INET, SOCK_DGRAM, 0);
30     if (fd >= 0)
31     return fd;
32     fd = socket(PF_PACKET, SOCK_DGRAM, 0);
33     if (fd >= 0)
34     return fd;
35 niro 816 return xsocket(PF_INET6, SOCK_DGRAM, 0);
36 niro 532 }
37    
38 niro 816 /* Exits on error */
39     static void do_chflags(char *dev, uint32_t flags, uint32_t mask)
40 niro 532 {
41     struct ifreq ifr;
42     int fd;
43    
44     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
45     fd = get_ctl_fd();
46 niro 816 xioctl(fd, SIOCGIFFLAGS, &ifr);
47     if ((ifr.ifr_flags ^ flags) & mask) {
48 niro 532 ifr.ifr_flags &= ~mask;
49 niro 816 ifr.ifr_flags |= mask & flags;
50     xioctl(fd, SIOCSIFFLAGS, &ifr);
51 niro 532 }
52     close(fd);
53     }
54    
55 niro 816 /* Exits on error */
56     static void do_changename(char *dev, char *newdev)
57 niro 532 {
58     struct ifreq ifr;
59     int fd;
60    
61     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
62     strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname));
63     fd = get_ctl_fd();
64 niro 816 xioctl(fd, SIOCSIFNAME, &ifr);
65 niro 532 close(fd);
66     }
67    
68 niro 816 /* Exits on error */
69     static void set_qlen(char *dev, int qlen)
70 niro 532 {
71     struct ifreq ifr;
72     int s;
73    
74     s = get_ctl_fd();
75     memset(&ifr, 0, sizeof(ifr));
76     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
77     ifr.ifr_qlen = qlen;
78 niro 816 xioctl(s, SIOCSIFTXQLEN, &ifr);
79 niro 532 close(s);
80     }
81    
82 niro 816 /* Exits on error */
83     static void set_mtu(char *dev, int mtu)
84 niro 532 {
85     struct ifreq ifr;
86     int s;
87    
88     s = get_ctl_fd();
89     memset(&ifr, 0, sizeof(ifr));
90     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
91     ifr.ifr_mtu = mtu;
92 niro 816 xioctl(s, SIOCSIFMTU, &ifr);
93 niro 532 close(s);
94     }
95    
96 niro 816 /* Exits on error */
97 niro 532 static int get_address(char *dev, int *htype)
98     {
99     struct ifreq ifr;
100     struct sockaddr_ll me;
101     socklen_t alen;
102     int s;
103    
104 niro 816 s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
105 niro 532
106     memset(&ifr, 0, sizeof(ifr));
107     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
108 niro 816 xioctl(s, SIOCGIFINDEX, &ifr);
109 niro 532
110     memset(&me, 0, sizeof(me));
111     me.sll_family = AF_PACKET;
112     me.sll_ifindex = ifr.ifr_ifindex;
113     me.sll_protocol = htons(ETH_P_LOOP);
114 niro 816 xbind(s, (struct sockaddr*)&me, sizeof(me));
115 niro 532
116     alen = sizeof(me);
117     if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
118 niro 816 bb_perror_msg_and_die("getsockname");
119 niro 532 }
120     close(s);
121     *htype = me.sll_hatype;
122     return me.sll_halen;
123     }
124    
125 niro 816 /* Exits on error */
126     static void parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
127 niro 532 {
128     int alen;
129    
130     memset(ifr, 0, sizeof(*ifr));
131     strncpy(ifr->ifr_name, dev, sizeof(ifr->ifr_name));
132     ifr->ifr_hwaddr.sa_family = hatype;
133 niro 816
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 niro 532 if (alen < 0)
137 niro 816 exit(EXIT_FAILURE);
138 niro 532 if (alen != halen) {
139 niro 816 bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen);
140 niro 532 }
141     }
142    
143 niro 816 /* Exits on error */
144     static void set_address(struct ifreq *ifr, int brd)
145 niro 532 {
146     int s;
147    
148     s = get_ctl_fd();
149 niro 816 if (brd)
150     xioctl(s, SIOCSIFHWBROADCAST, ifr);
151     else
152     xioctl(s, SIOCSIFHWADDR, ifr);
153 niro 532 close(s);
154     }
155    
156    
157 niro 816 static void die_must_be_on_off(const char *msg) NORETURN;
158     static void die_must_be_on_off(const char *msg)
159 niro 532 {
160 niro 816 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 niro 532 char *dev = NULL;
167     uint32_t mask = 0;
168     uint32_t flags = 0;
169     int qlen = -1;
170     int mtu = -1;
171     char *newaddr = NULL;
172     char *newbrd = NULL;
173     struct ifreq ifr0, ifr1;
174     char *newname = NULL;
175     int htype, halen;
176 niro 816 static const char keywords[] ALIGN1 =
177     "up\0""down\0""name\0""mtu\0""multicast\0"
178     "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 niro 532
185 niro 816 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 niro 532 mask |= IFF_UP;
191     flags |= IFF_UP;
192 niro 816 }
193     if (key == ARG_down) {
194 niro 532 mask |= IFF_UP;
195     flags &= ~IFF_UP;
196 niro 816 }
197     if (key == ARG_name) {
198 niro 532 NEXT_ARG();
199     newname = *argv;
200 niro 816 }
201     if (key == ARG_mtu) {
202 niro 532 NEXT_ARG();
203     if (mtu != -1)
204     duparg("mtu", *argv);
205     if (get_integer(&mtu, *argv, 0))
206     invarg(*argv, "mtu");
207 niro 816 }
208     if (key == ARG_multicast) {
209     int param;
210 niro 532 NEXT_ARG();
211     mask |= IFF_MULTICAST;
212 niro 816 param = index_in_strings(str_on_off, *argv);
213     if (param < 0)
214     die_must_be_on_off("multicast");
215     if (param == PARM_on)
216 niro 532 flags |= IFF_MULTICAST;
217 niro 816 else
218 niro 532 flags &= ~IFF_MULTICAST;
219 niro 816 }
220     if (key == ARG_arp) {
221     int param;
222 niro 532 NEXT_ARG();
223     mask |= IFF_NOARP;
224 niro 816 param = index_in_strings(str_on_off, *argv);
225     if (param < 0)
226     die_must_be_on_off("arp");
227     if (param == PARM_on)
228 niro 532 flags &= ~IFF_NOARP;
229 niro 816 else
230 niro 532 flags |= IFF_NOARP;
231 niro 816 }
232     if (key == ARG_addr) {
233 niro 532 NEXT_ARG();
234     newaddr = *argv;
235 niro 816 }
236     if (key >= ARG_dev) {
237     if (key == ARG_dev) {
238 niro 532 NEXT_ARG();
239     }
240     if (dev)
241     duparg2("dev", *argv);
242     dev = *argv;
243     }
244 niro 816 argv++;
245 niro 532 }
246    
247     if (!dev) {
248 niro 816 bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\"");
249 niro 532 }
250    
251     if (newaddr || newbrd) {
252     halen = get_address(dev, &htype);
253     if (newaddr) {
254 niro 816 parse_address(dev, htype, halen, newaddr, &ifr0);
255 niro 532 }
256     if (newbrd) {
257 niro 816 parse_address(dev, htype, halen, newbrd, &ifr1);
258 niro 532 }
259     }
260    
261     if (newname && strcmp(dev, newname)) {
262 niro 816 do_changename(dev, newname);
263 niro 532 dev = newname;
264     }
265     if (qlen != -1) {
266 niro 816 set_qlen(dev, qlen);
267 niro 532 }
268     if (mtu != -1) {
269 niro 816 set_mtu(dev, mtu);
270 niro 532 }
271     if (newaddr || newbrd) {
272     if (newbrd) {
273 niro 816 set_address(&ifr1, 1);
274 niro 532 }
275     if (newaddr) {
276 niro 816 set_address(&ifr0, 0);
277 niro 532 }
278     }
279     if (mask)
280 niro 816 do_chflags(dev, flags, mask);
281 niro 532 return 0;
282     }
283    
284 niro 816 static int ipaddr_list_link(char **argv)
285 niro 532 {
286     preferred_family = AF_PACKET;
287 niro 816 return ipaddr_list_or_flush(argv, 0);
288 niro 532 }
289    
290 niro 816 /* Return value becomes exitcode. It's okay to not return at all */
291     int do_iplink(char **argv)
292 niro 532 {
293 niro 816 static const char keywords[] ALIGN1 =
294     "set\0""show\0""lst\0""list\0";
295     int key;
296     if (!*argv)
297     return ipaddr_list_link(argv);
298     key = index_in_substrings(keywords, *argv);
299     if (key < 0)
300     bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
301     argv++;
302     if (key == 0) /* set */
303     return do_set(argv);
304     /* show, lst, list */
305     return ipaddr_list_link(argv);
306 niro 532 }