Annotation of /trunk/mkinitrd-magellan/busybox/networking/libiproute/iplink.c
Parent Directory | Revision Log
Revision 984 -
(hide annotations)
(download)
Sun May 30 11:32:42 2010 UTC (14 years ago) by niro
File MIME type: text/plain
File size: 6572 byte(s)
Sun May 30 11:32:42 2010 UTC (14 years ago) by niro
File MIME type: text/plain
File size: 6572 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
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 | niro | 984 | strncpy_IFNAMSIZ(ifr.ifr_name, dev); |
45 | niro | 532 | 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 | niro | 984 | strncpy_IFNAMSIZ(ifr.ifr_name, dev); |
62 | strncpy_IFNAMSIZ(ifr.ifr_newname, newdev); | ||
63 | niro | 532 | 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 | niro | 984 | strncpy_IFNAMSIZ(ifr.ifr_name, dev); |
77 | niro | 532 | 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 | niro | 984 | strncpy_IFNAMSIZ(ifr.ifr_name, dev); |
91 | niro | 532 | 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 | niro | 984 | strncpy_IFNAMSIZ(ifr.ifr_name, dev); |
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 | alen = sizeof(me); |
116 | niro | 984 | getsockname(s, (struct sockaddr*)&me, &alen); |
117 | //never happens: | ||
118 | //if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) | ||
119 | // bb_perror_msg_and_die("getsockname"); | ||
120 | niro | 532 | 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 | niro | 984 | strncpy_IFNAMSIZ(ifr->ifr_name, dev); |
132 | niro | 532 | 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 | niro | 984 | mtu = get_unsigned(*argv, "mtu"); |
206 | niro | 816 | } |
207 | if (key == ARG_multicast) { | ||
208 | int param; | ||
209 | niro | 532 | NEXT_ARG(); |
210 | mask |= IFF_MULTICAST; | ||
211 | niro | 816 | param = index_in_strings(str_on_off, *argv); |
212 | if (param < 0) | ||
213 | die_must_be_on_off("multicast"); | ||
214 | if (param == PARM_on) | ||
215 | niro | 532 | flags |= IFF_MULTICAST; |
216 | niro | 816 | else |
217 | niro | 532 | flags &= ~IFF_MULTICAST; |
218 | niro | 816 | } |
219 | if (key == ARG_arp) { | ||
220 | int param; | ||
221 | niro | 532 | NEXT_ARG(); |
222 | mask |= IFF_NOARP; | ||
223 | niro | 816 | param = index_in_strings(str_on_off, *argv); |
224 | if (param < 0) | ||
225 | die_must_be_on_off("arp"); | ||
226 | if (param == PARM_on) | ||
227 | niro | 532 | flags &= ~IFF_NOARP; |
228 | niro | 816 | else |
229 | niro | 532 | flags |= IFF_NOARP; |
230 | niro | 816 | } |
231 | if (key == ARG_addr) { | ||
232 | niro | 532 | NEXT_ARG(); |
233 | newaddr = *argv; | ||
234 | niro | 816 | } |
235 | if (key >= ARG_dev) { | ||
236 | if (key == ARG_dev) { | ||
237 | niro | 532 | NEXT_ARG(); |
238 | } | ||
239 | if (dev) | ||
240 | duparg2("dev", *argv); | ||
241 | dev = *argv; | ||
242 | } | ||
243 | niro | 816 | argv++; |
244 | niro | 532 | } |
245 | |||
246 | if (!dev) { | ||
247 | niro | 816 | bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\""); |
248 | niro | 532 | } |
249 | |||
250 | if (newaddr || newbrd) { | ||
251 | halen = get_address(dev, &htype); | ||
252 | if (newaddr) { | ||
253 | niro | 816 | parse_address(dev, htype, halen, newaddr, &ifr0); |
254 | niro | 532 | } |
255 | if (newbrd) { | ||
256 | niro | 816 | parse_address(dev, htype, halen, newbrd, &ifr1); |
257 | niro | 532 | } |
258 | } | ||
259 | |||
260 | if (newname && strcmp(dev, newname)) { | ||
261 | niro | 816 | do_changename(dev, newname); |
262 | niro | 532 | dev = newname; |
263 | } | ||
264 | if (qlen != -1) { | ||
265 | niro | 816 | set_qlen(dev, qlen); |
266 | niro | 532 | } |
267 | if (mtu != -1) { | ||
268 | niro | 816 | set_mtu(dev, mtu); |
269 | niro | 532 | } |
270 | if (newaddr || newbrd) { | ||
271 | if (newbrd) { | ||
272 | niro | 816 | set_address(&ifr1, 1); |
273 | niro | 532 | } |
274 | if (newaddr) { | ||
275 | niro | 816 | set_address(&ifr0, 0); |
276 | niro | 532 | } |
277 | } | ||
278 | if (mask) | ||
279 | niro | 816 | do_chflags(dev, flags, mask); |
280 | niro | 532 | return 0; |
281 | } | ||
282 | |||
283 | niro | 816 | static int ipaddr_list_link(char **argv) |
284 | niro | 532 | { |
285 | preferred_family = AF_PACKET; | ||
286 | niro | 816 | return ipaddr_list_or_flush(argv, 0); |
287 | niro | 532 | } |
288 | |||
289 | niro | 816 | /* Return value becomes exitcode. It's okay to not return at all */ |
290 | int do_iplink(char **argv) | ||
291 | niro | 532 | { |
292 | niro | 816 | static const char keywords[] ALIGN1 = |
293 | "set\0""show\0""lst\0""list\0"; | ||
294 | int key; | ||
295 | if (!*argv) | ||
296 | return ipaddr_list_link(argv); | ||
297 | key = index_in_substrings(keywords, *argv); | ||
298 | if (key < 0) | ||
299 | bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); | ||
300 | argv++; | ||
301 | if (key == 0) /* set */ | ||
302 | return do_set(argv); | ||
303 | /* show, lst, list */ | ||
304 | return ipaddr_list_link(argv); | ||
305 | niro | 532 | } |