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