Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show 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 /* 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 }