Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 6940 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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     #include "libbb.h"
11    
12     #include <sys/ioctl.h>
13     #include <sys/socket.h>
14    
15     #include <net/if.h>
16     #include <net/if_packet.h>
17     #include <netpacket/packet.h>
18    
19     #include <net/ethernet.h>
20    
21     #include "rt_names.h"
22     #include "utils.h"
23     #include "ip_common.h"
24    
25     /* take from linux/sockios.h */
26     #define SIOCSIFNAME 0x8923 /* set interface name */
27    
28     static int on_off(char *msg)
29     {
30     bb_error_msg("error: argument of \"%s\" must be \"on\" or \"off\"", msg);
31     return -1;
32     }
33    
34     static int get_ctl_fd(void)
35     {
36     int s_errno;
37     int fd;
38    
39     fd = socket(PF_INET, SOCK_DGRAM, 0);
40     if (fd >= 0)
41     return fd;
42     s_errno = errno;
43     fd = socket(PF_PACKET, SOCK_DGRAM, 0);
44     if (fd >= 0)
45     return fd;
46     fd = socket(PF_INET6, SOCK_DGRAM, 0);
47     if (fd >= 0)
48     return fd;
49     errno = s_errno;
50     bb_perror_msg("cannot create control socket");
51     return -1;
52     }
53    
54     static int do_chflags(char *dev, uint32_t flags, uint32_t mask)
55     {
56     struct ifreq ifr;
57     int fd;
58     int err;
59    
60     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
61     fd = get_ctl_fd();
62     if (fd < 0)
63     return -1;
64     err = ioctl(fd, SIOCGIFFLAGS, &ifr);
65     if (err) {
66     bb_perror_msg("SIOCGIFFLAGS");
67     close(fd);
68     return -1;
69     }
70     if ((ifr.ifr_flags^flags)&mask) {
71     ifr.ifr_flags &= ~mask;
72     ifr.ifr_flags |= mask&flags;
73     err = ioctl(fd, SIOCSIFFLAGS, &ifr);
74     if (err)
75     bb_perror_msg("SIOCSIFFLAGS");
76     }
77     close(fd);
78     return err;
79     }
80    
81     static int do_changename(char *dev, char *newdev)
82     {
83     struct ifreq ifr;
84     int fd;
85     int err;
86    
87     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
88     strncpy(ifr.ifr_newname, newdev, sizeof(ifr.ifr_newname));
89     fd = get_ctl_fd();
90     if (fd < 0)
91     return -1;
92     err = ioctl(fd, SIOCSIFNAME, &ifr);
93     if (err) {
94     bb_perror_msg("SIOCSIFNAME");
95     close(fd);
96     return -1;
97     }
98     close(fd);
99     return err;
100     }
101    
102     static int set_qlen(char *dev, int qlen)
103     {
104     struct ifreq ifr;
105     int s;
106    
107     s = get_ctl_fd();
108     if (s < 0)
109     return -1;
110    
111     memset(&ifr, 0, sizeof(ifr));
112     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
113     ifr.ifr_qlen = qlen;
114     if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
115     bb_perror_msg("SIOCSIFXQLEN");
116     close(s);
117     return -1;
118     }
119     close(s);
120    
121     return 0;
122     }
123    
124     static int set_mtu(char *dev, int mtu)
125     {
126     struct ifreq ifr;
127     int s;
128    
129     s = get_ctl_fd();
130     if (s < 0)
131     return -1;
132    
133     memset(&ifr, 0, sizeof(ifr));
134     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
135     ifr.ifr_mtu = mtu;
136     if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
137     bb_perror_msg("SIOCSIFMTU");
138     close(s);
139     return -1;
140     }
141     close(s);
142    
143     return 0;
144     }
145    
146     static int get_address(char *dev, int *htype)
147     {
148     struct ifreq ifr;
149     struct sockaddr_ll me;
150     socklen_t alen;
151     int s;
152    
153     s = socket(PF_PACKET, SOCK_DGRAM, 0);
154     if (s < 0) {
155     bb_perror_msg("socket(PF_PACKET)");
156     return -1;
157     }
158    
159     memset(&ifr, 0, sizeof(ifr));
160     strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name));
161     if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
162     bb_perror_msg("SIOCGIFINDEX");
163     close(s);
164     return -1;
165     }
166    
167     memset(&me, 0, sizeof(me));
168     me.sll_family = AF_PACKET;
169     me.sll_ifindex = ifr.ifr_ifindex;
170     me.sll_protocol = htons(ETH_P_LOOP);
171     if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
172     bb_perror_msg("bind");
173     close(s);
174     return -1;
175     }
176    
177     alen = sizeof(me);
178     if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
179     bb_perror_msg("getsockname");
180     close(s);
181     return -1;
182     }
183     close(s);
184     *htype = me.sll_hatype;
185     return me.sll_halen;
186     }
187    
188     static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
189     {
190     int alen;
191    
192     memset(ifr, 0, sizeof(*ifr));
193     strncpy(ifr->ifr_name, dev, sizeof(ifr->ifr_name));
194     ifr->ifr_hwaddr.sa_family = hatype;
195     alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), 14, lla);
196     if (alen < 0)
197     return -1;
198     if (alen != halen) {
199     bb_error_msg("wrong address (%s) length: expected %d bytes", lla, halen);
200     return -1;
201     }
202     return 0;
203     }
204    
205     static int set_address(struct ifreq *ifr, int brd)
206     {
207     int s;
208    
209     s = get_ctl_fd();
210     if (s < 0)
211     return -1;
212     if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
213     bb_perror_msg(brd ? "SIOCSIFHWBROADCAST" : "SIOCSIFHWADDR");
214     close(s);
215     return -1;
216     }
217     close(s);
218     return 0;
219     }
220    
221    
222     static int do_set(int argc, char **argv)
223     {
224     char *dev = NULL;
225     uint32_t mask = 0;
226     uint32_t flags = 0;
227     int qlen = -1;
228     int mtu = -1;
229     char *newaddr = NULL;
230     char *newbrd = NULL;
231     struct ifreq ifr0, ifr1;
232     char *newname = NULL;
233     int htype, halen;
234    
235     while (argc > 0) {
236     if (strcmp(*argv, "up") == 0) {
237     mask |= IFF_UP;
238     flags |= IFF_UP;
239     } else if (strcmp(*argv, "down") == 0) {
240     mask |= IFF_UP;
241     flags &= ~IFF_UP;
242     } else if (strcmp(*argv, "name") == 0) {
243     NEXT_ARG();
244     newname = *argv;
245     } else if (strcmp(*argv, "mtu") == 0) {
246     NEXT_ARG();
247     if (mtu != -1)
248     duparg("mtu", *argv);
249     if (get_integer(&mtu, *argv, 0))
250     invarg(*argv, "mtu");
251     } else if (strcmp(*argv, "multicast") == 0) {
252     NEXT_ARG();
253     mask |= IFF_MULTICAST;
254     if (strcmp(*argv, "on") == 0) {
255     flags |= IFF_MULTICAST;
256     } else if (strcmp(*argv, "off") == 0) {
257     flags &= ~IFF_MULTICAST;
258     } else
259     return on_off("multicast");
260     } else if (strcmp(*argv, "arp") == 0) {
261     NEXT_ARG();
262     mask |= IFF_NOARP;
263     if (strcmp(*argv, "on") == 0) {
264     flags &= ~IFF_NOARP;
265     } else if (strcmp(*argv, "off") == 0) {
266     flags |= IFF_NOARP;
267     } else
268     return on_off("noarp");
269     } else if (strcmp(*argv, "addr") == 0) {
270     NEXT_ARG();
271     newaddr = *argv;
272     } else {
273     if (strcmp(*argv, "dev") == 0) {
274     NEXT_ARG();
275     }
276     if (dev)
277     duparg2("dev", *argv);
278     dev = *argv;
279     }
280     argc--; argv++;
281     }
282    
283     if (!dev) {
284     bb_error_msg(bb_msg_requires_arg, "\"dev\"");
285     exit(-1);
286     }
287    
288     if (newaddr || newbrd) {
289     halen = get_address(dev, &htype);
290     if (halen < 0)
291     return -1;
292     if (newaddr) {
293     if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
294     return -1;
295     }
296     if (newbrd) {
297     if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
298     return -1;
299     }
300     }
301    
302     if (newname && strcmp(dev, newname)) {
303     if (do_changename(dev, newname) < 0)
304     return -1;
305     dev = newname;
306     }
307     if (qlen != -1) {
308     if (set_qlen(dev, qlen) < 0)
309     return -1;
310     }
311     if (mtu != -1) {
312     if (set_mtu(dev, mtu) < 0)
313     return -1;
314     }
315     if (newaddr || newbrd) {
316     if (newbrd) {
317     if (set_address(&ifr1, 1) < 0)
318     return -1;
319     }
320     if (newaddr) {
321     if (set_address(&ifr0, 0) < 0)
322     return -1;
323     }
324     }
325     if (mask)
326     return do_chflags(dev, flags, mask);
327     return 0;
328     }
329    
330     static int ipaddr_list_link(int argc, char **argv)
331     {
332     preferred_family = AF_PACKET;
333     return ipaddr_list_or_flush(argc, argv, 0);
334     }
335    
336     int do_iplink(int argc, char **argv)
337     {
338     if (argc > 0) {
339     if (matches(*argv, "set") == 0)
340     return do_set(argc-1, argv+1);
341     if (matches(*argv, "show") == 0 ||
342     matches(*argv, "lst") == 0 ||
343     matches(*argv, "list") == 0)
344     return ipaddr_list_link(argc-1, argv+1);
345     } else
346     return ipaddr_list_link(0, NULL);
347    
348     bb_error_msg("command \"%s\" is unknown", *argv);
349     exit(-1);
350     }