diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2002-11-10 01:33:55 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2002-11-10 01:33:55 +0000 |
commit | 9a2d27249cc2235f7e001a9ea8d4605406bc5f38 (patch) | |
tree | b7b2917c3cf46ac3fa25df5f9a27a9a9fbfb0398 /networking/libiproute/iplink.c | |
parent | 021fa7db9139bff3b4bf404dfd7d2b1541ed71f8 (diff) | |
download | busybox-w32-9a2d27249cc2235f7e001a9ea8d4605406bc5f38.tar.gz busybox-w32-9a2d27249cc2235f7e001a9ea8d4605406bc5f38.tar.bz2 busybox-w32-9a2d27249cc2235f7e001a9ea8d4605406bc5f38.zip |
IP applet by Bastian Blank <waldi@debian.org>
Diffstat (limited to 'networking/libiproute/iplink.c')
-rw-r--r-- | networking/libiproute/iplink.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c new file mode 100644 index 000000000..90d60b44c --- /dev/null +++ b/networking/libiproute/iplink.c | |||
@@ -0,0 +1,349 @@ | |||
1 | /* | ||
2 | * iplink.c "ip link". | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <stdio.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <unistd.h> | ||
16 | #include <syslog.h> | ||
17 | #include <fcntl.h> | ||
18 | #include <errno.h> | ||
19 | #include <sys/socket.h> | ||
20 | #include <linux/if.h> | ||
21 | #include <linux/if_packet.h> | ||
22 | #include <linux/if_ether.h> | ||
23 | #include <linux/sockios.h> | ||
24 | #include <netinet/in.h> | ||
25 | #include <arpa/inet.h> | ||
26 | #include <string.h> | ||
27 | #include <sys/ioctl.h> | ||
28 | #include <linux/sockios.h> | ||
29 | |||
30 | #include "rt_names.h" | ||
31 | #include "utils.h" | ||
32 | #include "ip_common.h" | ||
33 | |||
34 | #include "busybox.h" | ||
35 | |||
36 | static int on_off(char *msg) | ||
37 | { | ||
38 | fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg); | ||
39 | return -1; | ||
40 | } | ||
41 | |||
42 | static int get_ctl_fd(void) | ||
43 | { | ||
44 | int s_errno; | ||
45 | int fd; | ||
46 | |||
47 | fd = socket(PF_INET, SOCK_DGRAM, 0); | ||
48 | if (fd >= 0) | ||
49 | return fd; | ||
50 | s_errno = errno; | ||
51 | fd = socket(PF_PACKET, SOCK_DGRAM, 0); | ||
52 | if (fd >= 0) | ||
53 | return fd; | ||
54 | fd = socket(PF_INET6, SOCK_DGRAM, 0); | ||
55 | if (fd >= 0) | ||
56 | return fd; | ||
57 | errno = s_errno; | ||
58 | perror("Cannot create control socket"); | ||
59 | return -1; | ||
60 | } | ||
61 | |||
62 | static int do_chflags(char *dev, __u32 flags, __u32 mask) | ||
63 | { | ||
64 | struct ifreq ifr; | ||
65 | int fd; | ||
66 | int err; | ||
67 | |||
68 | strcpy(ifr.ifr_name, dev); | ||
69 | fd = get_ctl_fd(); | ||
70 | if (fd < 0) | ||
71 | return -1; | ||
72 | err = ioctl(fd, SIOCGIFFLAGS, &ifr); | ||
73 | if (err) { | ||
74 | perror("SIOCGIFFLAGS"); | ||
75 | close(fd); | ||
76 | return -1; | ||
77 | } | ||
78 | if ((ifr.ifr_flags^flags)&mask) { | ||
79 | ifr.ifr_flags &= ~mask; | ||
80 | ifr.ifr_flags |= mask&flags; | ||
81 | err = ioctl(fd, SIOCSIFFLAGS, &ifr); | ||
82 | if (err) | ||
83 | perror("SIOCSIFFLAGS"); | ||
84 | } | ||
85 | close(fd); | ||
86 | return err; | ||
87 | } | ||
88 | |||
89 | static int do_changename(char *dev, char *newdev) | ||
90 | { | ||
91 | struct ifreq ifr; | ||
92 | int fd; | ||
93 | int err; | ||
94 | |||
95 | strcpy(ifr.ifr_name, dev); | ||
96 | strcpy(ifr.ifr_newname, newdev); | ||
97 | fd = get_ctl_fd(); | ||
98 | if (fd < 0) | ||
99 | return -1; | ||
100 | err = ioctl(fd, SIOCSIFNAME, &ifr); | ||
101 | if (err) { | ||
102 | perror("SIOCSIFNAME"); | ||
103 | close(fd); | ||
104 | return -1; | ||
105 | } | ||
106 | close(fd); | ||
107 | return err; | ||
108 | } | ||
109 | |||
110 | static int set_qlen(char *dev, int qlen) | ||
111 | { | ||
112 | struct ifreq ifr; | ||
113 | int s; | ||
114 | |||
115 | s = get_ctl_fd(); | ||
116 | if (s < 0) | ||
117 | return -1; | ||
118 | |||
119 | memset(&ifr, 0, sizeof(ifr)); | ||
120 | strcpy(ifr.ifr_name, dev); | ||
121 | ifr.ifr_qlen = qlen; | ||
122 | if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { | ||
123 | perror("SIOCSIFXQLEN"); | ||
124 | close(s); | ||
125 | return -1; | ||
126 | } | ||
127 | close(s); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int set_mtu(char *dev, int mtu) | ||
133 | { | ||
134 | struct ifreq ifr; | ||
135 | int s; | ||
136 | |||
137 | s = get_ctl_fd(); | ||
138 | if (s < 0) | ||
139 | return -1; | ||
140 | |||
141 | memset(&ifr, 0, sizeof(ifr)); | ||
142 | strcpy(ifr.ifr_name, dev); | ||
143 | ifr.ifr_mtu = mtu; | ||
144 | if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { | ||
145 | perror("SIOCSIFMTU"); | ||
146 | close(s); | ||
147 | return -1; | ||
148 | } | ||
149 | close(s); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int get_address(char *dev, int *htype) | ||
155 | { | ||
156 | struct ifreq ifr; | ||
157 | struct sockaddr_ll me; | ||
158 | int alen; | ||
159 | int s; | ||
160 | |||
161 | s = socket(PF_PACKET, SOCK_DGRAM, 0); | ||
162 | if (s < 0) { | ||
163 | perror("socket(PF_PACKET)"); | ||
164 | return -1; | ||
165 | } | ||
166 | |||
167 | memset(&ifr, 0, sizeof(ifr)); | ||
168 | strcpy(ifr.ifr_name, dev); | ||
169 | if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { | ||
170 | perror("SIOCGIFINDEX"); | ||
171 | close(s); | ||
172 | return -1; | ||
173 | } | ||
174 | |||
175 | memset(&me, 0, sizeof(me)); | ||
176 | me.sll_family = AF_PACKET; | ||
177 | me.sll_ifindex = ifr.ifr_ifindex; | ||
178 | me.sll_protocol = htons(ETH_P_LOOP); | ||
179 | if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { | ||
180 | perror("bind"); | ||
181 | close(s); | ||
182 | return -1; | ||
183 | } | ||
184 | |||
185 | alen = sizeof(me); | ||
186 | if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { | ||
187 | perror("getsockname"); | ||
188 | close(s); | ||
189 | return -1; | ||
190 | } | ||
191 | close(s); | ||
192 | *htype = me.sll_hatype; | ||
193 | return me.sll_halen; | ||
194 | } | ||
195 | |||
196 | static int parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr) | ||
197 | { | ||
198 | int alen; | ||
199 | |||
200 | memset(ifr, 0, sizeof(*ifr)); | ||
201 | strcpy(ifr->ifr_name, dev); | ||
202 | ifr->ifr_hwaddr.sa_family = hatype; | ||
203 | alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla); | ||
204 | if (alen < 0) | ||
205 | return -1; | ||
206 | if (alen != halen) { | ||
207 | fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen); | ||
208 | return -1; | ||
209 | } | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int set_address(struct ifreq *ifr, int brd) | ||
214 | { | ||
215 | int s; | ||
216 | |||
217 | s = get_ctl_fd(); | ||
218 | if (s < 0) | ||
219 | return -1; | ||
220 | if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) { | ||
221 | perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR"); | ||
222 | close(s); | ||
223 | return -1; | ||
224 | } | ||
225 | close(s); | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | |||
230 | static int do_set(int argc, char **argv) | ||
231 | { | ||
232 | char *dev = NULL; | ||
233 | __u32 mask = 0; | ||
234 | __u32 flags = 0; | ||
235 | int qlen = -1; | ||
236 | int mtu = -1; | ||
237 | char *newaddr = NULL; | ||
238 | char *newbrd = NULL; | ||
239 | struct ifreq ifr0, ifr1; | ||
240 | char *newname = NULL; | ||
241 | int htype, halen; | ||
242 | |||
243 | while (argc > 0) { | ||
244 | if (strcmp(*argv, "up") == 0) { | ||
245 | mask |= IFF_UP; | ||
246 | flags |= IFF_UP; | ||
247 | } else if (strcmp(*argv, "down") == 0) { | ||
248 | mask |= IFF_UP; | ||
249 | flags &= ~IFF_UP; | ||
250 | } else if (strcmp(*argv, "name") == 0) { | ||
251 | NEXT_ARG(); | ||
252 | newname = *argv; | ||
253 | } else if (strcmp(*argv, "mtu") == 0) { | ||
254 | NEXT_ARG(); | ||
255 | if (mtu != -1) | ||
256 | duparg("mtu", *argv); | ||
257 | if (get_integer(&mtu, *argv, 0)) | ||
258 | invarg("Invalid \"mtu\" value\n", *argv); | ||
259 | } else if (strcmp(*argv, "multicast") == 0) { | ||
260 | NEXT_ARG(); | ||
261 | mask |= IFF_MULTICAST; | ||
262 | if (strcmp(*argv, "on") == 0) { | ||
263 | flags |= IFF_MULTICAST; | ||
264 | } else if (strcmp(*argv, "off") == 0) { | ||
265 | flags &= ~IFF_MULTICAST; | ||
266 | } else | ||
267 | return on_off("multicast"); | ||
268 | } else if (strcmp(*argv, "arp") == 0) { | ||
269 | NEXT_ARG(); | ||
270 | mask |= IFF_NOARP; | ||
271 | if (strcmp(*argv, "on") == 0) { | ||
272 | flags &= ~IFF_NOARP; | ||
273 | } else if (strcmp(*argv, "off") == 0) { | ||
274 | flags |= IFF_NOARP; | ||
275 | } else | ||
276 | return on_off("noarp"); | ||
277 | } else { | ||
278 | if (strcmp(*argv, "dev") == 0) { | ||
279 | NEXT_ARG(); | ||
280 | } | ||
281 | if (dev) | ||
282 | duparg2("dev", *argv); | ||
283 | dev = *argv; | ||
284 | } | ||
285 | argc--; argv++; | ||
286 | } | ||
287 | |||
288 | if (!dev) { | ||
289 | fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n"); | ||
290 | exit(-1); | ||
291 | } | ||
292 | |||
293 | if (newaddr || newbrd) { | ||
294 | halen = get_address(dev, &htype); | ||
295 | if (halen < 0) | ||
296 | return -1; | ||
297 | if (newaddr) { | ||
298 | if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) | ||
299 | return -1; | ||
300 | } | ||
301 | if (newbrd) { | ||
302 | if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) | ||
303 | return -1; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | if (newname && strcmp(dev, newname)) { | ||
308 | if (do_changename(dev, newname) < 0) | ||
309 | return -1; | ||
310 | dev = newname; | ||
311 | } | ||
312 | if (qlen != -1) { | ||
313 | if (set_qlen(dev, qlen) < 0) | ||
314 | return -1; | ||
315 | } | ||
316 | if (mtu != -1) { | ||
317 | if (set_mtu(dev, mtu) < 0) | ||
318 | return -1; | ||
319 | } | ||
320 | if (newaddr || newbrd) { | ||
321 | if (newbrd) { | ||
322 | if (set_address(&ifr1, 1) < 0) | ||
323 | return -1; | ||
324 | } | ||
325 | if (newaddr) { | ||
326 | if (set_address(&ifr0, 0) < 0) | ||
327 | return -1; | ||
328 | } | ||
329 | } | ||
330 | if (mask) | ||
331 | return do_chflags(dev, flags, mask); | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | int do_iplink(int argc, char **argv) | ||
336 | { | ||
337 | if (argc > 0) { | ||
338 | if (matches(*argv, "set") == 0) | ||
339 | return do_set(argc-1, argv+1); | ||
340 | if (matches(*argv, "show") == 0 || | ||
341 | matches(*argv, "lst") == 0 || | ||
342 | matches(*argv, "list") == 0) | ||
343 | return ipaddr_list_link(argc-1, argv+1); | ||
344 | } else | ||
345 | return ipaddr_list_link(0, NULL); | ||
346 | |||
347 | fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv); | ||
348 | exit(-1); | ||
349 | } | ||