diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-26 18:25:24 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-26 18:25:24 +0000 |
commit | 06aed4316e1f486f78c6487181c75cb22a70c639 (patch) | |
tree | 65a21a2b40b877b985bfe746df01358546cbf878 /networking/ifenslave.c | |
parent | 04bb2d2d06a87b08743ee997fcd8465bfed809d1 (diff) | |
download | busybox-w32-06aed4316e1f486f78c6487181c75cb22a70c639.tar.gz busybox-w32-06aed4316e1f486f78c6487181c75cb22a70c639.tar.bz2 busybox-w32-06aed4316e1f486f78c6487181c75cb22a70c639.zip |
ifenslave: new applet. closes bug 115.
Diffstat (limited to 'networking/ifenslave.c')
-rw-r--r-- | networking/ifenslave.c | 621 |
1 files changed, 621 insertions, 0 deletions
diff --git a/networking/ifenslave.c b/networking/ifenslave.c new file mode 100644 index 000000000..774d7c2d2 --- /dev/null +++ b/networking/ifenslave.c | |||
@@ -0,0 +1,621 @@ | |||
1 | /* Mode: C; | ||
2 | * | ||
3 | * Mini ifenslave implementation for busybox | ||
4 | * Copyright (C) 2005 by Marc Leeman <marc.leeman@barco.com> | ||
5 | * | ||
6 | * ifenslave.c: Configure network interfaces for parallel routing. | ||
7 | * | ||
8 | * This program controls the Linux implementation of running multiple | ||
9 | * network interfaces in parallel. | ||
10 | * | ||
11 | * Author: Donald Becker <becker@cesdis.gsfc.nasa.gov> | ||
12 | * Copyright 1994-1996 Donald Becker | ||
13 | * | ||
14 | * This program is free software; you can redistribute it | ||
15 | * and/or modify it under the terms of the GNU General Public | ||
16 | * License as published by the Free Software Foundation. | ||
17 | * | ||
18 | * The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O | ||
19 | * Center of Excellence in Space Data and Information Sciences | ||
20 | * Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 | ||
21 | * | ||
22 | * Changes : | ||
23 | * - 2000/10/02 Willy Tarreau <willy at meta-x.org> : | ||
24 | * - few fixes. Master's MAC address is now correctly taken from | ||
25 | * the first device when not previously set ; | ||
26 | * - detach support : call BOND_RELEASE to detach an enslaved interface. | ||
27 | * - give a mini-howto from command-line help : # ifenslave -h | ||
28 | * | ||
29 | * - 2001/02/16 Chad N. Tindel <ctindel at ieee dot org> : | ||
30 | * - Master is now brought down before setting the MAC address. In | ||
31 | * the 2.4 kernel you can't change the MAC address while the device is | ||
32 | * up because you get EBUSY. | ||
33 | * | ||
34 | * - 2001/09/13 Takao Indoh <indou dot takao at jp dot fujitsu dot com> | ||
35 | * - Added the ability to change the active interface on a mode 1 bond | ||
36 | * at runtime. | ||
37 | * | ||
38 | * - 2001/10/23 Chad N. Tindel <ctindel at ieee dot org> : | ||
39 | * - No longer set the MAC address of the master. The bond device will | ||
40 | * take care of this itself | ||
41 | * - Try the SIOC*** versions of the bonding ioctls before using the | ||
42 | * old versions | ||
43 | * - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> : | ||
44 | * - ifr2.ifr_flags was not initialized in the hwaddr_notset case, | ||
45 | * SIOCGIFFLAGS now called before hwaddr_notset test | ||
46 | * | ||
47 | * - 2002/10/31 Tony Cureington <tony.cureington * hp_com> : | ||
48 | * - If the master does not have a hardware address when the first slave | ||
49 | * is enslaved, the master is assigned the hardware address of that | ||
50 | * slave - there is a comment in bonding.c stating "ifenslave takes | ||
51 | * care of this now." This corrects the problem of slaves having | ||
52 | * different hardware addresses in active-backup mode when | ||
53 | * multiple interfaces are specified on a single ifenslave command | ||
54 | * (ifenslave bond0 eth0 eth1). | ||
55 | * | ||
56 | * - 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and | ||
57 | * Shmulik Hen <shmulik.hen at intel dot com> | ||
58 | * - Moved setting the slave's mac address and openning it, from | ||
59 | * the application to the driver. This enables support of modes | ||
60 | * that need to use the unique mac address of each slave. | ||
61 | * The driver also takes care of closing the slave and restoring its | ||
62 | * original mac address upon release. | ||
63 | * In addition, block possibility of enslaving before the master is up. | ||
64 | * This prevents putting the system in an undefined state. | ||
65 | * | ||
66 | * - 2003/05/01 - Amir Noam <amir.noam at intel dot com> | ||
67 | * - Added ABI version control to restore compatibility between | ||
68 | * new/old ifenslave and new/old bonding. | ||
69 | * - Prevent adding an adapter that is already a slave. | ||
70 | * Fixes the problem of stalling the transmission and leaving | ||
71 | * the slave in a down state. | ||
72 | * | ||
73 | * - 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com> | ||
74 | * - Prevent enslaving if the bond device is down. | ||
75 | * Fixes the problem of leaving the system in unstable state and | ||
76 | * halting when trying to remove the module. | ||
77 | * - Close socket on all abnormal exists. | ||
78 | * - Add versioning scheme that follows that of the bonding driver. | ||
79 | * current version is 1.0.0 as a base line. | ||
80 | * | ||
81 | * - 2003/05/22 - Jay Vosburgh <fubar at us dot ibm dot com> | ||
82 | * - ifenslave -c was broken; it's now fixed | ||
83 | * - Fixed problem with routes vanishing from master during enslave | ||
84 | * processing. | ||
85 | * | ||
86 | * - 2003/05/27 - Amir Noam <amir.noam at intel dot com> | ||
87 | * - Fix backward compatibility issues: | ||
88 | * For drivers not using ABI versions, slave was set down while | ||
89 | * it should be left up before enslaving. | ||
90 | * Also, master was not set down and the default set_mac_address() | ||
91 | * would fail and generate an error message in the system log. | ||
92 | * - For opt_c: slave should not be set to the master's setting | ||
93 | * while it is running. It was already set during enslave. To | ||
94 | * simplify things, it is now handeled separately. | ||
95 | * | ||
96 | * - 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com> | ||
97 | * - Code cleanup and style changes | ||
98 | * set version to 1.1.0 | ||
99 | */ | ||
100 | |||
101 | #include "libbb.h" | ||
102 | |||
103 | #include <net/if_arp.h> | ||
104 | #include <linux/if_bonding.h> | ||
105 | #include <linux/sockios.h> | ||
106 | |||
107 | typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */ | ||
108 | typedef uint32_t u32; /* ditto */ | ||
109 | typedef uint16_t u16; /* ditto */ | ||
110 | typedef uint8_t u8; /* ditto */ | ||
111 | #include <linux/ethtool.h> | ||
112 | |||
113 | |||
114 | struct dev_data { | ||
115 | struct ifreq mtu, flags, hwaddr; | ||
116 | }; | ||
117 | |||
118 | |||
119 | enum { skfd = 3 }; /* AF_INET socket for ioctl() calls.*/ | ||
120 | struct globals { | ||
121 | unsigned abi_ver; /* userland - kernel ABI version */ | ||
122 | smallint hwaddr_set; /* Master's hwaddr is set */ | ||
123 | struct dev_data master; | ||
124 | struct dev_data slave; | ||
125 | }; | ||
126 | #define G (*ptr_to_globals) | ||
127 | #define abi_ver (G.abi_ver ) | ||
128 | #define hwaddr_set (G.hwaddr_set) | ||
129 | #define master (G.master ) | ||
130 | #define slave (G.slave ) | ||
131 | #define INIT_G() do { \ | ||
132 | PTR_TO_GLOBALS = xzalloc(sizeof(G)); \ | ||
133 | } while (0) | ||
134 | |||
135 | |||
136 | static void get_drv_info(char *master_ifname); | ||
137 | static int get_if_settings(char *ifname, struct dev_data *dd); | ||
138 | static int get_slave_flags(char *slave_ifname); | ||
139 | static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr); | ||
140 | static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr); | ||
141 | static int set_slave_mtu(char *slave_ifname, int mtu); | ||
142 | static int set_if_flags(char *ifname, short flags); | ||
143 | static int set_if_up(char *ifname, short flags); | ||
144 | static int set_if_down(char *ifname, short flags); | ||
145 | static int clear_if_addr(char *ifname); | ||
146 | static int set_if_addr(char *master_ifname, char *slave_ifname); | ||
147 | static void change_active(char *master_ifname, char *slave_ifname); | ||
148 | static int enslave(char *master_ifname, char *slave_ifname); | ||
149 | static int release(char *master_ifname, char *slave_ifname); | ||
150 | |||
151 | |||
152 | int ifenslave_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
153 | int ifenslave_main(int argc, char **argv) | ||
154 | { | ||
155 | char *master_ifname, *slave_ifname; | ||
156 | int rv; | ||
157 | int res; | ||
158 | unsigned opt; | ||
159 | enum { | ||
160 | OPT_c = (1 << 0), | ||
161 | OPT_d = (1 << 1), | ||
162 | OPT_f = (1 << 2), | ||
163 | }; | ||
164 | #if ENABLE_GETOPT_LONG | ||
165 | static const char ifenslave_longopts[] ALIGN1 = | ||
166 | "change-active" No_argument "c" | ||
167 | "detach" No_argument "d" | ||
168 | "force" No_argument "f" | ||
169 | ; | ||
170 | |||
171 | applet_long_options = ifenslave_longopts; | ||
172 | #endif | ||
173 | opt = getopt32(argv, "cdf"); | ||
174 | argv += optind; | ||
175 | if (opt & (opt-1)) /* options check */ | ||
176 | bb_show_usage(); | ||
177 | |||
178 | /* Copy the interface name */ | ||
179 | master_ifname = *argv++; | ||
180 | |||
181 | /* No remaining args means show all interfaces. */ | ||
182 | if (!master_ifname) { | ||
183 | display_interfaces(NULL); | ||
184 | return EXIT_SUCCESS; | ||
185 | } | ||
186 | |||
187 | /* Open a basic socket */ | ||
188 | xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), skfd); | ||
189 | |||
190 | /* exchange abi version with bonding module */ | ||
191 | get_drv_info(master_ifname); | ||
192 | |||
193 | slave_ifname = *argv++; | ||
194 | if (!slave_ifname) { | ||
195 | if (opt & (OPT_d|OPT_c)) { | ||
196 | display_interfaces(slave_ifname); | ||
197 | return 2; /* why? */ | ||
198 | } | ||
199 | /* A single arg means show the | ||
200 | * configuration for this interface | ||
201 | */ | ||
202 | display_interfaces(master_ifname); | ||
203 | return EXIT_SUCCESS; | ||
204 | } | ||
205 | |||
206 | res = get_if_settings(master_ifname, &master); | ||
207 | if (res) { | ||
208 | /* Probably a good reason not to go on */ | ||
209 | bb_perror_msg_and_die("%s: can't get settings", master_ifname); | ||
210 | } | ||
211 | |||
212 | /* check if master is indeed a master; | ||
213 | * if not then fail any operation | ||
214 | */ | ||
215 | if (!(master.flags.ifr_flags & IFF_MASTER)) | ||
216 | bb_error_msg_and_die("%s is not a master", master_ifname); | ||
217 | |||
218 | /* check if master is up; if not then fail any operation */ | ||
219 | if (!(master.flags.ifr_flags & IFF_UP)) | ||
220 | bb_error_msg_and_die("%s is not up", master_ifname); | ||
221 | |||
222 | /* Only for enslaving */ | ||
223 | if (!(opt & (OPT_c|OPT_d))) { | ||
224 | sa_family_t master_family = master.hwaddr.ifr_hwaddr.sa_family; | ||
225 | |||
226 | /* The family '1' is ARPHRD_ETHER for ethernet. */ | ||
227 | if (master_family != 1 && !(opt & OPT_f)) { | ||
228 | bb_error_msg_and_die( | ||
229 | "%s is not ethernet-like (-f overrides)", | ||
230 | master_ifname); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /* Accepts only one slave */ | ||
235 | if (opt & OPT_c) { | ||
236 | /* change active slave */ | ||
237 | res = get_slave_flags(slave_ifname); | ||
238 | if (res) { | ||
239 | bb_perror_msg_and_die( | ||
240 | "%s: can't get flags", slave_ifname); | ||
241 | } | ||
242 | change_active(master_ifname, slave_ifname); | ||
243 | return EXIT_SUCCESS; | ||
244 | } | ||
245 | |||
246 | /* Accept multiple slaves */ | ||
247 | res = 0; | ||
248 | do { | ||
249 | if (opt & OPT_d) { | ||
250 | /* detach a slave interface from the master */ | ||
251 | rv = get_slave_flags(slave_ifname); | ||
252 | if (rv) { | ||
253 | /* Can't work with this slave. */ | ||
254 | /* remember the error and skip it*/ | ||
255 | bb_perror_msg( | ||
256 | "skipping %s: can't get flags", | ||
257 | slave_ifname); | ||
258 | res = rv; | ||
259 | continue; | ||
260 | } | ||
261 | rv = release(master_ifname, slave_ifname); | ||
262 | if (rv) { | ||
263 | bb_perror_msg( | ||
264 | "master %s, slave %s: " | ||
265 | "can't release", | ||
266 | master_ifname, slave_ifname); | ||
267 | res = rv; | ||
268 | } | ||
269 | } else { | ||
270 | /* attach a slave interface to the master */ | ||
271 | rv = get_if_settings(slave_ifname, &slave); | ||
272 | if (rv) { | ||
273 | /* Can't work with this slave. */ | ||
274 | /* remember the error and skip it*/ | ||
275 | bb_perror_msg( | ||
276 | "skipping %s: can't get settings", | ||
277 | slave_ifname); | ||
278 | res = rv; | ||
279 | continue; | ||
280 | } | ||
281 | rv = enslave(master_ifname, slave_ifname); | ||
282 | if (rv) { | ||
283 | bb_perror_msg( | ||
284 | "master %s, slave %s: " | ||
285 | "can't enslave", | ||
286 | master_ifname, slave_ifname); | ||
287 | res = rv; | ||
288 | } | ||
289 | } | ||
290 | } while ((slave_ifname = *argv++) != NULL); | ||
291 | |||
292 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
293 | close(skfd); | ||
294 | } | ||
295 | |||
296 | return res; | ||
297 | } | ||
298 | |||
299 | static void get_drv_info(char *master_ifname) | ||
300 | { | ||
301 | struct ifreq ifr; | ||
302 | struct ethtool_drvinfo info; | ||
303 | |||
304 | memset(&ifr, 0, sizeof(ifr)); | ||
305 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
306 | ifr.ifr_data = (caddr_t)&info; | ||
307 | |||
308 | info.cmd = ETHTOOL_GDRVINFO; | ||
309 | strncpy(info.driver, "ifenslave", 32); | ||
310 | snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); | ||
311 | |||
312 | if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) { | ||
313 | if (errno == EOPNOTSUPP) | ||
314 | return; | ||
315 | bb_perror_msg_and_die("%s: SIOCETHTOOL error", master_ifname); | ||
316 | } | ||
317 | |||
318 | abi_ver = bb_strtou(info.fw_version, NULL, 0); | ||
319 | if (errno) | ||
320 | bb_error_msg_and_die("%s: SIOCETHTOOL error", master_ifname); | ||
321 | |||
322 | return; | ||
323 | } | ||
324 | |||
325 | static void change_active(char *master_ifname, char *slave_ifname) | ||
326 | { | ||
327 | struct ifreq ifr; | ||
328 | |||
329 | if (!(slave.flags.ifr_flags & IFF_SLAVE)) { | ||
330 | bb_error_msg_and_die( | ||
331 | "%s is not a slave", | ||
332 | slave_ifname); | ||
333 | } | ||
334 | |||
335 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
336 | strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); | ||
337 | if (ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0 | ||
338 | && ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0 | ||
339 | ) { | ||
340 | bb_perror_msg_and_die( | ||
341 | "master %s, slave %s: can't " | ||
342 | "change active", | ||
343 | master_ifname, slave_ifname); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | static int enslave(char *master_ifname, char *slave_ifname) | ||
348 | { | ||
349 | struct ifreq ifr; | ||
350 | int res; | ||
351 | |||
352 | if (slave.flags.ifr_flags & IFF_SLAVE) { | ||
353 | bb_error_msg( | ||
354 | "%s is already a slave", | ||
355 | slave_ifname); | ||
356 | return 1; | ||
357 | } | ||
358 | |||
359 | res = set_if_down(slave_ifname, slave.flags.ifr_flags); | ||
360 | if (res) | ||
361 | return res; | ||
362 | |||
363 | if (abi_ver < 2) { | ||
364 | /* Older bonding versions would panic if the slave has no IP | ||
365 | * address, so get the IP setting from the master. | ||
366 | */ | ||
367 | res = set_if_addr(master_ifname, slave_ifname); | ||
368 | if (res) { | ||
369 | bb_perror_msg("%s: can't set address", slave_ifname); | ||
370 | return res; | ||
371 | } | ||
372 | } else { | ||
373 | res = clear_if_addr(slave_ifname); | ||
374 | if (res) { | ||
375 | bb_perror_msg("%s: can't clear address", slave_ifname); | ||
376 | return res; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | if (master.mtu.ifr_mtu != slave.mtu.ifr_mtu) { | ||
381 | res = set_slave_mtu(slave_ifname, master.mtu.ifr_mtu); | ||
382 | if (res) { | ||
383 | bb_perror_msg("%s: can't set MTU", slave_ifname); | ||
384 | return res; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | if (hwaddr_set) { | ||
389 | /* Master already has an hwaddr | ||
390 | * so set it's hwaddr to the slave | ||
391 | */ | ||
392 | if (abi_ver < 1) { | ||
393 | /* The driver is using an old ABI, so | ||
394 | * the application sets the slave's | ||
395 | * hwaddr | ||
396 | */ | ||
397 | res = set_slave_hwaddr(slave_ifname, | ||
398 | &(master.hwaddr.ifr_hwaddr)); | ||
399 | if (res) { | ||
400 | bb_perror_msg("%s: can't set hw address", | ||
401 | slave_ifname); | ||
402 | goto undo_mtu; | ||
403 | } | ||
404 | |||
405 | /* For old ABI the application needs to bring the | ||
406 | * slave back up | ||
407 | */ | ||
408 | res = set_if_up(slave_ifname, slave.flags.ifr_flags); | ||
409 | if (res) | ||
410 | goto undo_slave_mac; | ||
411 | } | ||
412 | /* The driver is using a new ABI, | ||
413 | * so the driver takes care of setting | ||
414 | * the slave's hwaddr and bringing | ||
415 | * it up again | ||
416 | */ | ||
417 | } else { | ||
418 | /* No hwaddr for master yet, so | ||
419 | * set the slave's hwaddr to it | ||
420 | */ | ||
421 | if (abi_ver < 1) { | ||
422 | /* For old ABI, the master needs to be | ||
423 | * down before setting it's hwaddr | ||
424 | */ | ||
425 | res = set_if_down(master_ifname, master.flags.ifr_flags); | ||
426 | if (res) | ||
427 | goto undo_mtu; | ||
428 | } | ||
429 | |||
430 | res = set_master_hwaddr(master_ifname, | ||
431 | &(slave.hwaddr.ifr_hwaddr)); | ||
432 | if (res) { | ||
433 | bb_error_msg("%s: can't set hw address", | ||
434 | master_ifname); | ||
435 | goto undo_mtu; | ||
436 | } | ||
437 | |||
438 | if (abi_ver < 1) { | ||
439 | /* For old ABI, bring the master | ||
440 | * back up | ||
441 | */ | ||
442 | res = set_if_up(master_ifname, master.flags.ifr_flags); | ||
443 | if (res) | ||
444 | goto undo_master_mac; | ||
445 | } | ||
446 | |||
447 | hwaddr_set = 1; | ||
448 | } | ||
449 | |||
450 | /* Do the real thing */ | ||
451 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
452 | strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); | ||
453 | if (ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0 | ||
454 | && ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0 | ||
455 | ) { | ||
456 | res = 1; | ||
457 | } | ||
458 | |||
459 | if (res) | ||
460 | goto undo_master_mac; | ||
461 | |||
462 | return 0; | ||
463 | |||
464 | /* rollback (best effort) */ | ||
465 | undo_master_mac: | ||
466 | set_master_hwaddr(master_ifname, &(master.hwaddr.ifr_hwaddr)); | ||
467 | hwaddr_set = 0; | ||
468 | goto undo_mtu; | ||
469 | undo_slave_mac: | ||
470 | set_slave_hwaddr(slave_ifname, &(slave.hwaddr.ifr_hwaddr)); | ||
471 | undo_mtu: | ||
472 | set_slave_mtu(slave_ifname, slave.mtu.ifr_mtu); | ||
473 | return res; | ||
474 | } | ||
475 | |||
476 | static int release(char *master_ifname, char *slave_ifname) | ||
477 | { | ||
478 | struct ifreq ifr; | ||
479 | int res = 0; | ||
480 | |||
481 | if (!(slave.flags.ifr_flags & IFF_SLAVE)) { | ||
482 | bb_error_msg("%s is not a slave", | ||
483 | slave_ifname); | ||
484 | return 1; | ||
485 | } | ||
486 | |||
487 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
488 | strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); | ||
489 | if (ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0 | ||
490 | && ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0 | ||
491 | ) { | ||
492 | return 1; | ||
493 | } | ||
494 | if (abi_ver < 1) { | ||
495 | /* The driver is using an old ABI, so we'll set the interface | ||
496 | * down to avoid any conflicts due to same MAC/IP | ||
497 | */ | ||
498 | res = set_if_down(slave_ifname, slave.flags.ifr_flags); | ||
499 | } | ||
500 | |||
501 | /* set to default mtu */ | ||
502 | set_slave_mtu(slave_ifname, 1500); | ||
503 | |||
504 | return res; | ||
505 | } | ||
506 | |||
507 | static int get_if_settings(char *ifname, struct dev_data *dd) | ||
508 | { | ||
509 | int res; | ||
510 | |||
511 | strncpy(dd->mtu.ifr_name, ifname, IFNAMSIZ); | ||
512 | res = ioctl(skfd, SIOCGIFMTU, &dd->mtu); | ||
513 | strncpy(dd->flags.ifr_name, ifname, IFNAMSIZ); | ||
514 | res |= ioctl(skfd, SIOCGIFFLAGS, &dd->flags); | ||
515 | strncpy(dd->hwaddr.ifr_name, ifname, IFNAMSIZ); | ||
516 | res |= ioctl(skfd, SIOCGIFHWADDR, &dd->hwaddr); | ||
517 | |||
518 | return res; | ||
519 | } | ||
520 | |||
521 | static int get_slave_flags(char *slave_ifname) | ||
522 | { | ||
523 | strncpy(slave.flags.ifr_name, slave_ifname, IFNAMSIZ); | ||
524 | return ioctl(skfd, SIOCGIFFLAGS, &slave.flags); | ||
525 | } | ||
526 | |||
527 | static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr) | ||
528 | { | ||
529 | struct ifreq ifr; | ||
530 | |||
531 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
532 | memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); | ||
533 | return ioctl(skfd, SIOCSIFHWADDR, &ifr); | ||
534 | } | ||
535 | |||
536 | static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr) | ||
537 | { | ||
538 | struct ifreq ifr; | ||
539 | |||
540 | strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); | ||
541 | memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); | ||
542 | return ioctl(skfd, SIOCSIFHWADDR, &ifr); | ||
543 | } | ||
544 | |||
545 | static int set_slave_mtu(char *slave_ifname, int mtu) | ||
546 | { | ||
547 | struct ifreq ifr; | ||
548 | |||
549 | ifr.ifr_mtu = mtu; | ||
550 | strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); | ||
551 | return ioctl(skfd, SIOCSIFMTU, &ifr); | ||
552 | } | ||
553 | |||
554 | static int set_if_flags(char *ifname, short flags) | ||
555 | { | ||
556 | struct ifreq ifr; | ||
557 | |||
558 | ifr.ifr_flags = flags; | ||
559 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
560 | return ioctl(skfd, SIOCSIFFLAGS, &ifr); | ||
561 | } | ||
562 | |||
563 | static int set_if_up(char *ifname, short flags) | ||
564 | { | ||
565 | int res = set_if_flags(ifname, flags | IFF_UP); | ||
566 | if (res) | ||
567 | bb_perror_msg("%s: can't up", ifname); | ||
568 | return res; | ||
569 | } | ||
570 | |||
571 | static int set_if_down(char *ifname, short flags) | ||
572 | { | ||
573 | int res = set_if_flags(ifname, flags & ~IFF_UP); | ||
574 | if (res) | ||
575 | bb_perror_msg("%s: can't down", ifname); | ||
576 | return res; | ||
577 | } | ||
578 | |||
579 | static int clear_if_addr(char *ifname) | ||
580 | { | ||
581 | struct ifreq ifr; | ||
582 | |||
583 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
584 | ifr.ifr_addr.sa_family = AF_INET; | ||
585 | memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); | ||
586 | return ioctl(skfd, SIOCSIFADDR, &ifr); | ||
587 | } | ||
588 | |||
589 | static int set_if_addr(char *master_ifname, char *slave_ifname) | ||
590 | { | ||
591 | static const struct { | ||
592 | int g_ioctl; | ||
593 | int s_ioctl; | ||
594 | } ifra[] = { | ||
595 | { SIOCGIFADDR, SIOCSIFADDR }, | ||
596 | { SIOCGIFDSTADDR, SIOCSIFDSTADDR }, | ||
597 | { SIOCGIFBRDADDR, SIOCSIFBRDADDR }, | ||
598 | { SIOCGIFNETMASK, SIOCSIFNETMASK }, | ||
599 | }; | ||
600 | |||
601 | struct ifreq ifr; | ||
602 | int res; | ||
603 | int i; | ||
604 | |||
605 | for (i = 0; i < ARRAY_SIZE(ifra); i++) { | ||
606 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
607 | res = ioctl(skfd, ifra[i].g_ioctl, &ifr); | ||
608 | if (res < 0) { | ||
609 | ifr.ifr_addr.sa_family = AF_INET; | ||
610 | memset(ifr.ifr_addr.sa_data, 0, | ||
611 | sizeof(ifr.ifr_addr.sa_data)); | ||
612 | } | ||
613 | |||
614 | strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); | ||
615 | res = ioctl(skfd, ifra[i].s_ioctl, &ifr); | ||
616 | if (res < 0) | ||
617 | return res; | ||
618 | } | ||
619 | |||
620 | return 0; | ||
621 | } | ||