Contents of /trunk/mkinitrd-magellan/busybox/networking/libiproute/iplink.c
Parent Directory | 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)
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 | } |