diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /Documentation/networking/ifenslave.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'Documentation/networking/ifenslave.c')
-rw-r--r-- | Documentation/networking/ifenslave.c | 1110 |
1 files changed, 1110 insertions, 0 deletions
diff --git a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c new file mode 100644 index 000000000000..f315d20d3867 --- /dev/null +++ b/Documentation/networking/ifenslave.c | |||
@@ -0,0 +1,1110 @@ | |||
1 | /* Mode: C; | ||
2 | * ifenslave.c: Configure network interfaces for parallel routing. | ||
3 | * | ||
4 | * This program controls the Linux implementation of running multiple | ||
5 | * network interfaces in parallel. | ||
6 | * | ||
7 | * Author: Donald Becker <becker@cesdis.gsfc.nasa.gov> | ||
8 | * Copyright 1994-1996 Donald Becker | ||
9 | * | ||
10 | * This program is free software; you can redistribute it | ||
11 | * and/or modify it under the terms of the GNU General Public | ||
12 | * License as published by the Free Software Foundation. | ||
13 | * | ||
14 | * The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O | ||
15 | * Center of Excellence in Space Data and Information Sciences | ||
16 | * Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 | ||
17 | * | ||
18 | * Changes : | ||
19 | * - 2000/10/02 Willy Tarreau <willy at meta-x.org> : | ||
20 | * - few fixes. Master's MAC address is now correctly taken from | ||
21 | * the first device when not previously set ; | ||
22 | * - detach support : call BOND_RELEASE to detach an enslaved interface. | ||
23 | * - give a mini-howto from command-line help : # ifenslave -h | ||
24 | * | ||
25 | * - 2001/02/16 Chad N. Tindel <ctindel at ieee dot org> : | ||
26 | * - Master is now brought down before setting the MAC address. In | ||
27 | * the 2.4 kernel you can't change the MAC address while the device is | ||
28 | * up because you get EBUSY. | ||
29 | * | ||
30 | * - 2001/09/13 Takao Indoh <indou dot takao at jp dot fujitsu dot com> | ||
31 | * - Added the ability to change the active interface on a mode 1 bond | ||
32 | * at runtime. | ||
33 | * | ||
34 | * - 2001/10/23 Chad N. Tindel <ctindel at ieee dot org> : | ||
35 | * - No longer set the MAC address of the master. The bond device will | ||
36 | * take care of this itself | ||
37 | * - Try the SIOC*** versions of the bonding ioctls before using the | ||
38 | * old versions | ||
39 | * - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> : | ||
40 | * - ifr2.ifr_flags was not initialized in the hwaddr_notset case, | ||
41 | * SIOCGIFFLAGS now called before hwaddr_notset test | ||
42 | * | ||
43 | * - 2002/10/31 Tony Cureington <tony.cureington * hp_com> : | ||
44 | * - If the master does not have a hardware address when the first slave | ||
45 | * is enslaved, the master is assigned the hardware address of that | ||
46 | * slave - there is a comment in bonding.c stating "ifenslave takes | ||
47 | * care of this now." This corrects the problem of slaves having | ||
48 | * different hardware addresses in active-backup mode when | ||
49 | * multiple interfaces are specified on a single ifenslave command | ||
50 | * (ifenslave bond0 eth0 eth1). | ||
51 | * | ||
52 | * - 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and | ||
53 | * Shmulik Hen <shmulik.hen at intel dot com> | ||
54 | * - Moved setting the slave's mac address and openning it, from | ||
55 | * the application to the driver. This enables support of modes | ||
56 | * that need to use the unique mac address of each slave. | ||
57 | * The driver also takes care of closing the slave and restoring its | ||
58 | * original mac address upon release. | ||
59 | * In addition, block possibility of enslaving before the master is up. | ||
60 | * This prevents putting the system in an undefined state. | ||
61 | * | ||
62 | * - 2003/05/01 - Amir Noam <amir.noam at intel dot com> | ||
63 | * - Added ABI version control to restore compatibility between | ||
64 | * new/old ifenslave and new/old bonding. | ||
65 | * - Prevent adding an adapter that is already a slave. | ||
66 | * Fixes the problem of stalling the transmission and leaving | ||
67 | * the slave in a down state. | ||
68 | * | ||
69 | * - 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com> | ||
70 | * - Prevent enslaving if the bond device is down. | ||
71 | * Fixes the problem of leaving the system in unstable state and | ||
72 | * halting when trying to remove the module. | ||
73 | * - Close socket on all abnormal exists. | ||
74 | * - Add versioning scheme that follows that of the bonding driver. | ||
75 | * current version is 1.0.0 as a base line. | ||
76 | * | ||
77 | * - 2003/05/22 - Jay Vosburgh <fubar at us dot ibm dot com> | ||
78 | * - ifenslave -c was broken; it's now fixed | ||
79 | * - Fixed problem with routes vanishing from master during enslave | ||
80 | * processing. | ||
81 | * | ||
82 | * - 2003/05/27 - Amir Noam <amir.noam at intel dot com> | ||
83 | * - Fix backward compatibility issues: | ||
84 | * For drivers not using ABI versions, slave was set down while | ||
85 | * it should be left up before enslaving. | ||
86 | * Also, master was not set down and the default set_mac_address() | ||
87 | * would fail and generate an error message in the system log. | ||
88 | * - For opt_c: slave should not be set to the master's setting | ||
89 | * while it is running. It was already set during enslave. To | ||
90 | * simplify things, it is now handeled separately. | ||
91 | * | ||
92 | * - 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com> | ||
93 | * - Code cleanup and style changes | ||
94 | * set version to 1.1.0 | ||
95 | */ | ||
96 | |||
97 | #define APP_VERSION "1.1.0" | ||
98 | #define APP_RELDATE "December 1, 2003" | ||
99 | #define APP_NAME "ifenslave" | ||
100 | |||
101 | static char *version = | ||
102 | APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ")\n" | ||
103 | "o Donald Becker (becker@cesdis.gsfc.nasa.gov).\n" | ||
104 | "o Detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" | ||
105 | "o 2.4 kernel support added on 2001/02/16 by Chad N. Tindel\n" | ||
106 | " (ctindel at ieee dot org).\n"; | ||
107 | |||
108 | static const char *usage_msg = | ||
109 | "Usage: ifenslave [-f] <master-if> <slave-if> [<slave-if>...]\n" | ||
110 | " ifenslave -d <master-if> <slave-if> [<slave-if>...]\n" | ||
111 | " ifenslave -c <master-if> <slave-if>\n" | ||
112 | " ifenslave --help\n"; | ||
113 | |||
114 | static const char *help_msg = | ||
115 | "\n" | ||
116 | " To create a bond device, simply follow these three steps :\n" | ||
117 | " - ensure that the required drivers are properly loaded :\n" | ||
118 | " # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n" | ||
119 | " - assign an IP address to the bond device :\n" | ||
120 | " # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\n" | ||
121 | " - attach all the interfaces you need to the bond device :\n" | ||
122 | " # ifenslave [{-f|--force}] bond0 eth0 [eth1 [eth2]...]\n" | ||
123 | " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" | ||
124 | " interfaces attached AFTER this assignment will get the same MAC addr.\n" | ||
125 | " (except for ALB/TLB modes)\n" | ||
126 | "\n" | ||
127 | " To set the bond device down and automatically release all the slaves :\n" | ||
128 | " # ifconfig bond0 down\n" | ||
129 | "\n" | ||
130 | " To detach a dead interface without setting the bond device down :\n" | ||
131 | " # ifenslave {-d|--detach} bond0 eth0 [eth1 [eth2]...]\n" | ||
132 | "\n" | ||
133 | " To change active slave :\n" | ||
134 | " # ifenslave {-c|--change-active} bond0 eth0\n" | ||
135 | "\n" | ||
136 | " To show master interface info\n" | ||
137 | " # ifenslave bond0\n" | ||
138 | "\n" | ||
139 | " To show all interfaces info\n" | ||
140 | " # ifenslave {-a|--all-interfaces}\n" | ||
141 | "\n" | ||
142 | " To be more verbose\n" | ||
143 | " # ifenslave {-v|--verbose} ...\n" | ||
144 | "\n" | ||
145 | " # ifenslave {-u|--usage} Show usage\n" | ||
146 | " # ifenslave {-V|--version} Show version\n" | ||
147 | " # ifenslave {-h|--help} This message\n" | ||
148 | "\n"; | ||
149 | |||
150 | #include <unistd.h> | ||
151 | #include <stdlib.h> | ||
152 | #include <stdio.h> | ||
153 | #include <ctype.h> | ||
154 | #include <string.h> | ||
155 | #include <errno.h> | ||
156 | #include <fcntl.h> | ||
157 | #include <getopt.h> | ||
158 | #include <sys/types.h> | ||
159 | #include <sys/socket.h> | ||
160 | #include <sys/ioctl.h> | ||
161 | #include <linux/if.h> | ||
162 | #include <net/if_arp.h> | ||
163 | #include <linux/if_ether.h> | ||
164 | #include <linux/if_bonding.h> | ||
165 | #include <linux/sockios.h> | ||
166 | |||
167 | typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */ | ||
168 | typedef __uint32_t u32; /* ditto */ | ||
169 | typedef __uint16_t u16; /* ditto */ | ||
170 | typedef __uint8_t u8; /* ditto */ | ||
171 | #include <linux/ethtool.h> | ||
172 | |||
173 | struct option longopts[] = { | ||
174 | /* { name has_arg *flag val } */ | ||
175 | {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ | ||
176 | {"change-active", 0, 0, 'c'}, /* Change the active slave. */ | ||
177 | {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ | ||
178 | {"force", 0, 0, 'f'}, /* Force the operation. */ | ||
179 | {"help", 0, 0, 'h'}, /* Give help */ | ||
180 | {"usage", 0, 0, 'u'}, /* Give usage */ | ||
181 | {"verbose", 0, 0, 'v'}, /* Report each action taken. */ | ||
182 | {"version", 0, 0, 'V'}, /* Emit version information. */ | ||
183 | { 0, 0, 0, 0} | ||
184 | }; | ||
185 | |||
186 | /* Command-line flags. */ | ||
187 | unsigned int | ||
188 | opt_a = 0, /* Show-all-interfaces flag. */ | ||
189 | opt_c = 0, /* Change-active-slave flag. */ | ||
190 | opt_d = 0, /* Detach a slave interface. */ | ||
191 | opt_f = 0, /* Force the operation. */ | ||
192 | opt_h = 0, /* Help */ | ||
193 | opt_u = 0, /* Usage */ | ||
194 | opt_v = 0, /* Verbose flag. */ | ||
195 | opt_V = 0; /* Version */ | ||
196 | |||
197 | int skfd = -1; /* AF_INET socket for ioctl() calls.*/ | ||
198 | int abi_ver = 0; /* userland - kernel ABI version */ | ||
199 | int hwaddr_set = 0; /* Master's hwaddr is set */ | ||
200 | int saved_errno; | ||
201 | |||
202 | struct ifreq master_mtu, master_flags, master_hwaddr; | ||
203 | struct ifreq slave_mtu, slave_flags, slave_hwaddr; | ||
204 | |||
205 | struct dev_ifr { | ||
206 | struct ifreq *req_ifr; | ||
207 | char *req_name; | ||
208 | int req_type; | ||
209 | }; | ||
210 | |||
211 | struct dev_ifr master_ifra[] = { | ||
212 | {&master_mtu, "SIOCGIFMTU", SIOCGIFMTU}, | ||
213 | {&master_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, | ||
214 | {&master_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, | ||
215 | {NULL, "", 0} | ||
216 | }; | ||
217 | |||
218 | struct dev_ifr slave_ifra[] = { | ||
219 | {&slave_mtu, "SIOCGIFMTU", SIOCGIFMTU}, | ||
220 | {&slave_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, | ||
221 | {&slave_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, | ||
222 | {NULL, "", 0} | ||
223 | }; | ||
224 | |||
225 | static void if_print(char *ifname); | ||
226 | static int get_drv_info(char *master_ifname); | ||
227 | static int get_if_settings(char *ifname, struct dev_ifr ifra[]); | ||
228 | static int get_slave_flags(char *slave_ifname); | ||
229 | static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr); | ||
230 | static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr); | ||
231 | static int set_slave_mtu(char *slave_ifname, int mtu); | ||
232 | static int set_if_flags(char *ifname, short flags); | ||
233 | static int set_if_up(char *ifname, short flags); | ||
234 | static int set_if_down(char *ifname, short flags); | ||
235 | static int clear_if_addr(char *ifname); | ||
236 | static int set_if_addr(char *master_ifname, char *slave_ifname); | ||
237 | static int change_active(char *master_ifname, char *slave_ifname); | ||
238 | static int enslave(char *master_ifname, char *slave_ifname); | ||
239 | static int release(char *master_ifname, char *slave_ifname); | ||
240 | #define v_print(fmt, args...) \ | ||
241 | if (opt_v) \ | ||
242 | fprintf(stderr, fmt, ## args ) | ||
243 | |||
244 | int main(int argc, char *argv[]) | ||
245 | { | ||
246 | char **spp, *master_ifname, *slave_ifname; | ||
247 | int c, i, rv; | ||
248 | int res = 0; | ||
249 | int exclusive = 0; | ||
250 | |||
251 | while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) { | ||
252 | switch (c) { | ||
253 | case 'a': opt_a++; exclusive++; break; | ||
254 | case 'c': opt_c++; exclusive++; break; | ||
255 | case 'd': opt_d++; exclusive++; break; | ||
256 | case 'f': opt_f++; exclusive++; break; | ||
257 | case 'h': opt_h++; exclusive++; break; | ||
258 | case 'u': opt_u++; exclusive++; break; | ||
259 | case 'v': opt_v++; break; | ||
260 | case 'V': opt_V++; exclusive++; break; | ||
261 | |||
262 | case '?': | ||
263 | fprintf(stderr, usage_msg); | ||
264 | res = 2; | ||
265 | goto out; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | /* options check */ | ||
270 | if (exclusive > 1) { | ||
271 | fprintf(stderr, usage_msg); | ||
272 | res = 2; | ||
273 | goto out; | ||
274 | } | ||
275 | |||
276 | if (opt_v || opt_V) { | ||
277 | printf(version); | ||
278 | if (opt_V) { | ||
279 | res = 0; | ||
280 | goto out; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | if (opt_u) { | ||
285 | printf(usage_msg); | ||
286 | res = 0; | ||
287 | goto out; | ||
288 | } | ||
289 | |||
290 | if (opt_h) { | ||
291 | printf(usage_msg); | ||
292 | printf(help_msg); | ||
293 | res = 0; | ||
294 | goto out; | ||
295 | } | ||
296 | |||
297 | /* Open a basic socket */ | ||
298 | if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { | ||
299 | perror("socket"); | ||
300 | res = 1; | ||
301 | goto out; | ||
302 | } | ||
303 | |||
304 | if (opt_a) { | ||
305 | if (optind == argc) { | ||
306 | /* No remaining args */ | ||
307 | /* show all interfaces */ | ||
308 | if_print((char *)NULL); | ||
309 | goto out; | ||
310 | } else { | ||
311 | /* Just show usage */ | ||
312 | fprintf(stderr, usage_msg); | ||
313 | res = 2; | ||
314 | goto out; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | /* Copy the interface name */ | ||
319 | spp = argv + optind; | ||
320 | master_ifname = *spp++; | ||
321 | |||
322 | if (master_ifname == NULL) { | ||
323 | fprintf(stderr, usage_msg); | ||
324 | res = 2; | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | /* exchange abi version with bonding module */ | ||
329 | res = get_drv_info(master_ifname); | ||
330 | if (res) { | ||
331 | fprintf(stderr, | ||
332 | "Master '%s': Error: handshake with driver failed. " | ||
333 | "Aborting\n", | ||
334 | master_ifname); | ||
335 | goto out; | ||
336 | } | ||
337 | |||
338 | slave_ifname = *spp++; | ||
339 | |||
340 | if (slave_ifname == NULL) { | ||
341 | if (opt_d || opt_c) { | ||
342 | fprintf(stderr, usage_msg); | ||
343 | res = 2; | ||
344 | goto out; | ||
345 | } | ||
346 | |||
347 | /* A single arg means show the | ||
348 | * configuration for this interface | ||
349 | */ | ||
350 | if_print(master_ifname); | ||
351 | goto out; | ||
352 | } | ||
353 | |||
354 | res = get_if_settings(master_ifname, master_ifra); | ||
355 | if (res) { | ||
356 | /* Probably a good reason not to go on */ | ||
357 | fprintf(stderr, | ||
358 | "Master '%s': Error: get settings failed: %s. " | ||
359 | "Aborting\n", | ||
360 | master_ifname, strerror(res)); | ||
361 | goto out; | ||
362 | } | ||
363 | |||
364 | /* check if master is indeed a master; | ||
365 | * if not then fail any operation | ||
366 | */ | ||
367 | if (!(master_flags.ifr_flags & IFF_MASTER)) { | ||
368 | fprintf(stderr, | ||
369 | "Illegal operation; the specified interface '%s' " | ||
370 | "is not a master. Aborting\n", | ||
371 | master_ifname); | ||
372 | res = 1; | ||
373 | goto out; | ||
374 | } | ||
375 | |||
376 | /* check if master is up; if not then fail any operation */ | ||
377 | if (!(master_flags.ifr_flags & IFF_UP)) { | ||
378 | fprintf(stderr, | ||
379 | "Illegal operation; the specified master interface " | ||
380 | "'%s' is not up.\n", | ||
381 | master_ifname); | ||
382 | res = 1; | ||
383 | goto out; | ||
384 | } | ||
385 | |||
386 | /* Only for enslaving */ | ||
387 | if (!opt_c && !opt_d) { | ||
388 | sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family; | ||
389 | unsigned char *hwaddr = | ||
390 | (unsigned char *)master_hwaddr.ifr_hwaddr.sa_data; | ||
391 | |||
392 | /* The family '1' is ARPHRD_ETHER for ethernet. */ | ||
393 | if (master_family != 1 && !opt_f) { | ||
394 | fprintf(stderr, | ||
395 | "Illegal operation: The specified master " | ||
396 | "interface '%s' is not ethernet-like.\n " | ||
397 | "This program is designed to work with " | ||
398 | "ethernet-like network interfaces.\n " | ||
399 | "Use the '-f' option to force the " | ||
400 | "operation.\n", | ||
401 | master_ifname); | ||
402 | res = 1; | ||
403 | goto out; | ||
404 | } | ||
405 | |||
406 | /* Check master's hw addr */ | ||
407 | for (i = 0; i < 6; i++) { | ||
408 | if (hwaddr[i] != 0) { | ||
409 | hwaddr_set = 1; | ||
410 | break; | ||
411 | } | ||
412 | } | ||
413 | |||
414 | if (hwaddr_set) { | ||
415 | v_print("current hardware address of master '%s' " | ||
416 | "is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " | ||
417 | "type %d\n", | ||
418 | master_ifname, | ||
419 | hwaddr[0], hwaddr[1], | ||
420 | hwaddr[2], hwaddr[3], | ||
421 | hwaddr[4], hwaddr[5], | ||
422 | master_family); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | /* Accepts only one slave */ | ||
427 | if (opt_c) { | ||
428 | /* change active slave */ | ||
429 | res = get_slave_flags(slave_ifname); | ||
430 | if (res) { | ||
431 | fprintf(stderr, | ||
432 | "Slave '%s': Error: get flags failed. " | ||
433 | "Aborting\n", | ||
434 | slave_ifname); | ||
435 | goto out; | ||
436 | } | ||
437 | res = change_active(master_ifname, slave_ifname); | ||
438 | if (res) { | ||
439 | fprintf(stderr, | ||
440 | "Master '%s', Slave '%s': Error: " | ||
441 | "Change active failed\n", | ||
442 | master_ifname, slave_ifname); | ||
443 | } | ||
444 | } else { | ||
445 | /* Accept multiple slaves */ | ||
446 | do { | ||
447 | if (opt_d) { | ||
448 | /* detach a slave interface from the master */ | ||
449 | rv = get_slave_flags(slave_ifname); | ||
450 | if (rv) { | ||
451 | /* Can't work with this slave. */ | ||
452 | /* remember the error and skip it*/ | ||
453 | fprintf(stderr, | ||
454 | "Slave '%s': Error: get flags " | ||
455 | "failed. Skipping\n", | ||
456 | slave_ifname); | ||
457 | res = rv; | ||
458 | continue; | ||
459 | } | ||
460 | rv = release(master_ifname, slave_ifname); | ||
461 | if (rv) { | ||
462 | fprintf(stderr, | ||
463 | "Master '%s', Slave '%s': Error: " | ||
464 | "Release failed\n", | ||
465 | master_ifname, slave_ifname); | ||
466 | res = rv; | ||
467 | } | ||
468 | } else { | ||
469 | /* attach a slave interface to the master */ | ||
470 | rv = get_if_settings(slave_ifname, slave_ifra); | ||
471 | if (rv) { | ||
472 | /* Can't work with this slave. */ | ||
473 | /* remember the error and skip it*/ | ||
474 | fprintf(stderr, | ||
475 | "Slave '%s': Error: get " | ||
476 | "settings failed: %s. " | ||
477 | "Skipping\n", | ||
478 | slave_ifname, strerror(rv)); | ||
479 | res = rv; | ||
480 | continue; | ||
481 | } | ||
482 | rv = enslave(master_ifname, slave_ifname); | ||
483 | if (rv) { | ||
484 | fprintf(stderr, | ||
485 | "Master '%s', Slave '%s': Error: " | ||
486 | "Enslave failed\n", | ||
487 | master_ifname, slave_ifname); | ||
488 | res = rv; | ||
489 | } | ||
490 | } | ||
491 | } while ((slave_ifname = *spp++) != NULL); | ||
492 | } | ||
493 | |||
494 | out: | ||
495 | if (skfd >= 0) { | ||
496 | close(skfd); | ||
497 | } | ||
498 | |||
499 | return res; | ||
500 | } | ||
501 | |||
502 | static short mif_flags; | ||
503 | |||
504 | /* Get the inteface configuration from the kernel. */ | ||
505 | static int if_getconfig(char *ifname) | ||
506 | { | ||
507 | struct ifreq ifr; | ||
508 | int metric, mtu; /* Parameters of the master interface. */ | ||
509 | struct sockaddr dstaddr, broadaddr, netmask; | ||
510 | unsigned char *hwaddr; | ||
511 | |||
512 | strcpy(ifr.ifr_name, ifname); | ||
513 | if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) | ||
514 | return -1; | ||
515 | mif_flags = ifr.ifr_flags; | ||
516 | printf("The result of SIOCGIFFLAGS on %s is %x.\n", | ||
517 | ifname, ifr.ifr_flags); | ||
518 | |||
519 | strcpy(ifr.ifr_name, ifname); | ||
520 | if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) | ||
521 | return -1; | ||
522 | printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n", | ||
523 | ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], | ||
524 | ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); | ||
525 | |||
526 | strcpy(ifr.ifr_name, ifname); | ||
527 | if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) | ||
528 | return -1; | ||
529 | |||
530 | /* Gotta convert from 'char' to unsigned for printf(). */ | ||
531 | hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; | ||
532 | printf("The result of SIOCGIFHWADDR is type %d " | ||
533 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", | ||
534 | ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], | ||
535 | hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); | ||
536 | |||
537 | strcpy(ifr.ifr_name, ifname); | ||
538 | if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { | ||
539 | metric = 0; | ||
540 | } else | ||
541 | metric = ifr.ifr_metric; | ||
542 | |||
543 | strcpy(ifr.ifr_name, ifname); | ||
544 | if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) | ||
545 | mtu = 0; | ||
546 | else | ||
547 | mtu = ifr.ifr_mtu; | ||
548 | |||
549 | strcpy(ifr.ifr_name, ifname); | ||
550 | if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) { | ||
551 | memset(&dstaddr, 0, sizeof(struct sockaddr)); | ||
552 | } else | ||
553 | dstaddr = ifr.ifr_dstaddr; | ||
554 | |||
555 | strcpy(ifr.ifr_name, ifname); | ||
556 | if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) { | ||
557 | memset(&broadaddr, 0, sizeof(struct sockaddr)); | ||
558 | } else | ||
559 | broadaddr = ifr.ifr_broadaddr; | ||
560 | |||
561 | strcpy(ifr.ifr_name, ifname); | ||
562 | if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) { | ||
563 | memset(&netmask, 0, sizeof(struct sockaddr)); | ||
564 | } else | ||
565 | netmask = ifr.ifr_netmask; | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | static void if_print(char *ifname) | ||
571 | { | ||
572 | char buff[1024]; | ||
573 | struct ifconf ifc; | ||
574 | struct ifreq *ifr; | ||
575 | int i; | ||
576 | |||
577 | if (ifname == (char *)NULL) { | ||
578 | ifc.ifc_len = sizeof(buff); | ||
579 | ifc.ifc_buf = buff; | ||
580 | if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { | ||
581 | perror("SIOCGIFCONF failed"); | ||
582 | return; | ||
583 | } | ||
584 | |||
585 | ifr = ifc.ifc_req; | ||
586 | for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { | ||
587 | if (if_getconfig(ifr->ifr_name) < 0) { | ||
588 | fprintf(stderr, | ||
589 | "%s: unknown interface.\n", | ||
590 | ifr->ifr_name); | ||
591 | continue; | ||
592 | } | ||
593 | |||
594 | if (((mif_flags & IFF_UP) == 0) && !opt_a) continue; | ||
595 | /*ife_print(&ife);*/ | ||
596 | } | ||
597 | } else { | ||
598 | if (if_getconfig(ifname) < 0) { | ||
599 | fprintf(stderr, | ||
600 | "%s: unknown interface.\n", ifname); | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | |||
605 | static int get_drv_info(char *master_ifname) | ||
606 | { | ||
607 | struct ifreq ifr; | ||
608 | struct ethtool_drvinfo info; | ||
609 | char *endptr; | ||
610 | |||
611 | memset(&ifr, 0, sizeof(ifr)); | ||
612 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
613 | ifr.ifr_data = (caddr_t)&info; | ||
614 | |||
615 | info.cmd = ETHTOOL_GDRVINFO; | ||
616 | strncpy(info.driver, "ifenslave", 32); | ||
617 | snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); | ||
618 | |||
619 | if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) { | ||
620 | if (errno == EOPNOTSUPP) { | ||
621 | goto out; | ||
622 | } | ||
623 | |||
624 | saved_errno = errno; | ||
625 | v_print("Master '%s': Error: get bonding info failed %s\n", | ||
626 | master_ifname, strerror(saved_errno)); | ||
627 | return 1; | ||
628 | } | ||
629 | |||
630 | abi_ver = strtoul(info.fw_version, &endptr, 0); | ||
631 | if (*endptr) { | ||
632 | v_print("Master '%s': Error: got invalid string as an ABI " | ||
633 | "version from the bonding module\n", | ||
634 | master_ifname); | ||
635 | return 1; | ||
636 | } | ||
637 | |||
638 | out: | ||
639 | v_print("ABI ver is %d\n", abi_ver); | ||
640 | |||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int change_active(char *master_ifname, char *slave_ifname) | ||
645 | { | ||
646 | struct ifreq ifr; | ||
647 | int res = 0; | ||
648 | |||
649 | if (!(slave_flags.ifr_flags & IFF_SLAVE)) { | ||
650 | fprintf(stderr, | ||
651 | "Illegal operation: The specified slave interface " | ||
652 | "'%s' is not a slave\n", | ||
653 | slave_ifname); | ||
654 | return 1; | ||
655 | } | ||
656 | |||
657 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
658 | strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); | ||
659 | if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) && | ||
660 | (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) { | ||
661 | saved_errno = errno; | ||
662 | v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: " | ||
663 | "%s\n", | ||
664 | master_ifname, strerror(saved_errno)); | ||
665 | res = 1; | ||
666 | } | ||
667 | |||
668 | return res; | ||
669 | } | ||
670 | |||
671 | static int enslave(char *master_ifname, char *slave_ifname) | ||
672 | { | ||
673 | struct ifreq ifr; | ||
674 | int res = 0; | ||
675 | |||
676 | if (slave_flags.ifr_flags & IFF_SLAVE) { | ||
677 | fprintf(stderr, | ||
678 | "Illegal operation: The specified slave interface " | ||
679 | "'%s' is already a slave\n", | ||
680 | slave_ifname); | ||
681 | return 1; | ||
682 | } | ||
683 | |||
684 | res = set_if_down(slave_ifname, slave_flags.ifr_flags); | ||
685 | if (res) { | ||
686 | fprintf(stderr, | ||
687 | "Slave '%s': Error: bring interface down failed\n", | ||
688 | slave_ifname); | ||
689 | return res; | ||
690 | } | ||
691 | |||
692 | if (abi_ver < 2) { | ||
693 | /* Older bonding versions would panic if the slave has no IP | ||
694 | * address, so get the IP setting from the master. | ||
695 | */ | ||
696 | res = set_if_addr(master_ifname, slave_ifname); | ||
697 | if (res) { | ||
698 | fprintf(stderr, | ||
699 | "Slave '%s': Error: set address failed\n", | ||
700 | slave_ifname); | ||
701 | return res; | ||
702 | } | ||
703 | } else { | ||
704 | res = clear_if_addr(slave_ifname); | ||
705 | if (res) { | ||
706 | fprintf(stderr, | ||
707 | "Slave '%s': Error: clear address failed\n", | ||
708 | slave_ifname); | ||
709 | return res; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) { | ||
714 | res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu); | ||
715 | if (res) { | ||
716 | fprintf(stderr, | ||
717 | "Slave '%s': Error: set MTU failed\n", | ||
718 | slave_ifname); | ||
719 | return res; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | if (hwaddr_set) { | ||
724 | /* Master already has an hwaddr | ||
725 | * so set it's hwaddr to the slave | ||
726 | */ | ||
727 | if (abi_ver < 1) { | ||
728 | /* The driver is using an old ABI, so | ||
729 | * the application sets the slave's | ||
730 | * hwaddr | ||
731 | */ | ||
732 | res = set_slave_hwaddr(slave_ifname, | ||
733 | &(master_hwaddr.ifr_hwaddr)); | ||
734 | if (res) { | ||
735 | fprintf(stderr, | ||
736 | "Slave '%s': Error: set hw address " | ||
737 | "failed\n", | ||
738 | slave_ifname); | ||
739 | goto undo_mtu; | ||
740 | } | ||
741 | |||
742 | /* For old ABI the application needs to bring the | ||
743 | * slave back up | ||
744 | */ | ||
745 | res = set_if_up(slave_ifname, slave_flags.ifr_flags); | ||
746 | if (res) { | ||
747 | fprintf(stderr, | ||
748 | "Slave '%s': Error: bring interface " | ||
749 | "down failed\n", | ||
750 | slave_ifname); | ||
751 | goto undo_slave_mac; | ||
752 | } | ||
753 | } | ||
754 | /* The driver is using a new ABI, | ||
755 | * so the driver takes care of setting | ||
756 | * the slave's hwaddr and bringing | ||
757 | * it up again | ||
758 | */ | ||
759 | } else { | ||
760 | /* No hwaddr for master yet, so | ||
761 | * set the slave's hwaddr to it | ||
762 | */ | ||
763 | if (abi_ver < 1) { | ||
764 | /* For old ABI, the master needs to be | ||
765 | * down before setting it's hwaddr | ||
766 | */ | ||
767 | res = set_if_down(master_ifname, master_flags.ifr_flags); | ||
768 | if (res) { | ||
769 | fprintf(stderr, | ||
770 | "Master '%s': Error: bring interface " | ||
771 | "down failed\n", | ||
772 | master_ifname); | ||
773 | goto undo_mtu; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | res = set_master_hwaddr(master_ifname, | ||
778 | &(slave_hwaddr.ifr_hwaddr)); | ||
779 | if (res) { | ||
780 | fprintf(stderr, | ||
781 | "Master '%s': Error: set hw address " | ||
782 | "failed\n", | ||
783 | master_ifname); | ||
784 | goto undo_mtu; | ||
785 | } | ||
786 | |||
787 | if (abi_ver < 1) { | ||
788 | /* For old ABI, bring the master | ||
789 | * back up | ||
790 | */ | ||
791 | res = set_if_up(master_ifname, master_flags.ifr_flags); | ||
792 | if (res) { | ||
793 | fprintf(stderr, | ||
794 | "Master '%s': Error: bring interface " | ||
795 | "up failed\n", | ||
796 | master_ifname); | ||
797 | goto undo_master_mac; | ||
798 | } | ||
799 | } | ||
800 | |||
801 | hwaddr_set = 1; | ||
802 | } | ||
803 | |||
804 | /* Do the real thing */ | ||
805 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
806 | strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); | ||
807 | if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) && | ||
808 | (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) { | ||
809 | saved_errno = errno; | ||
810 | v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n", | ||
811 | master_ifname, strerror(saved_errno)); | ||
812 | res = 1; | ||
813 | } | ||
814 | |||
815 | if (res) { | ||
816 | goto undo_master_mac; | ||
817 | } | ||
818 | |||
819 | return 0; | ||
820 | |||
821 | /* rollback (best effort) */ | ||
822 | undo_master_mac: | ||
823 | set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr)); | ||
824 | hwaddr_set = 0; | ||
825 | goto undo_mtu; | ||
826 | undo_slave_mac: | ||
827 | set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr)); | ||
828 | undo_mtu: | ||
829 | set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu); | ||
830 | return res; | ||
831 | } | ||
832 | |||
833 | static int release(char *master_ifname, char *slave_ifname) | ||
834 | { | ||
835 | struct ifreq ifr; | ||
836 | int res = 0; | ||
837 | |||
838 | if (!(slave_flags.ifr_flags & IFF_SLAVE)) { | ||
839 | fprintf(stderr, | ||
840 | "Illegal operation: The specified slave interface " | ||
841 | "'%s' is not a slave\n", | ||
842 | slave_ifname); | ||
843 | return 1; | ||
844 | } | ||
845 | |||
846 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
847 | strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); | ||
848 | if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) && | ||
849 | (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) { | ||
850 | saved_errno = errno; | ||
851 | v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n", | ||
852 | master_ifname, strerror(saved_errno)); | ||
853 | return 1; | ||
854 | } else if (abi_ver < 1) { | ||
855 | /* The driver is using an old ABI, so we'll set the interface | ||
856 | * down to avoid any conflicts due to same MAC/IP | ||
857 | */ | ||
858 | res = set_if_down(slave_ifname, slave_flags.ifr_flags); | ||
859 | if (res) { | ||
860 | fprintf(stderr, | ||
861 | "Slave '%s': Error: bring interface " | ||
862 | "down failed\n", | ||
863 | slave_ifname); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | /* set to default mtu */ | ||
868 | set_slave_mtu(slave_ifname, 1500); | ||
869 | |||
870 | return res; | ||
871 | } | ||
872 | |||
873 | static int get_if_settings(char *ifname, struct dev_ifr ifra[]) | ||
874 | { | ||
875 | int i; | ||
876 | int res = 0; | ||
877 | |||
878 | for (i = 0; ifra[i].req_ifr; i++) { | ||
879 | strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ); | ||
880 | res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr); | ||
881 | if (res < 0) { | ||
882 | saved_errno = errno; | ||
883 | v_print("Interface '%s': Error: %s failed: %s\n", | ||
884 | ifname, ifra[i].req_name, | ||
885 | strerror(saved_errno)); | ||
886 | |||
887 | return saved_errno; | ||
888 | } | ||
889 | } | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static int get_slave_flags(char *slave_ifname) | ||
895 | { | ||
896 | int res = 0; | ||
897 | |||
898 | strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ); | ||
899 | res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags); | ||
900 | if (res < 0) { | ||
901 | saved_errno = errno; | ||
902 | v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n", | ||
903 | slave_ifname, strerror(saved_errno)); | ||
904 | } else { | ||
905 | v_print("Slave %s: flags %04X.\n", | ||
906 | slave_ifname, slave_flags.ifr_flags); | ||
907 | } | ||
908 | |||
909 | return res; | ||
910 | } | ||
911 | |||
912 | static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr) | ||
913 | { | ||
914 | unsigned char *addr = (unsigned char *)hwaddr->sa_data; | ||
915 | struct ifreq ifr; | ||
916 | int res = 0; | ||
917 | |||
918 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
919 | memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); | ||
920 | res = ioctl(skfd, SIOCSIFHWADDR, &ifr); | ||
921 | if (res < 0) { | ||
922 | saved_errno = errno; | ||
923 | v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n", | ||
924 | master_ifname, strerror(saved_errno)); | ||
925 | return res; | ||
926 | } else { | ||
927 | v_print("Master '%s': hardware address set to " | ||
928 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", | ||
929 | master_ifname, addr[0], addr[1], addr[2], | ||
930 | addr[3], addr[4], addr[5]); | ||
931 | } | ||
932 | |||
933 | return res; | ||
934 | } | ||
935 | |||
936 | static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr) | ||
937 | { | ||
938 | unsigned char *addr = (unsigned char *)hwaddr->sa_data; | ||
939 | struct ifreq ifr; | ||
940 | int res = 0; | ||
941 | |||
942 | strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); | ||
943 | memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); | ||
944 | res = ioctl(skfd, SIOCSIFHWADDR, &ifr); | ||
945 | if (res < 0) { | ||
946 | saved_errno = errno; | ||
947 | |||
948 | v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n", | ||
949 | slave_ifname, strerror(saved_errno)); | ||
950 | |||
951 | if (saved_errno == EBUSY) { | ||
952 | v_print(" The device is busy: it must be idle " | ||
953 | "before running this command.\n"); | ||
954 | } else if (saved_errno == EOPNOTSUPP) { | ||
955 | v_print(" The device does not support setting " | ||
956 | "the MAC address.\n" | ||
957 | " Your kernel likely does not support slave " | ||
958 | "devices.\n"); | ||
959 | } else if (saved_errno == EINVAL) { | ||
960 | v_print(" The device's address type does not match " | ||
961 | "the master's address type.\n"); | ||
962 | } | ||
963 | return res; | ||
964 | } else { | ||
965 | v_print("Slave '%s': hardware address set to " | ||
966 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", | ||
967 | slave_ifname, addr[0], addr[1], addr[2], | ||
968 | addr[3], addr[4], addr[5]); | ||
969 | } | ||
970 | |||
971 | return res; | ||
972 | } | ||
973 | |||
974 | static int set_slave_mtu(char *slave_ifname, int mtu) | ||
975 | { | ||
976 | struct ifreq ifr; | ||
977 | int res = 0; | ||
978 | |||
979 | ifr.ifr_mtu = mtu; | ||
980 | strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); | ||
981 | |||
982 | res = ioctl(skfd, SIOCSIFMTU, &ifr); | ||
983 | if (res < 0) { | ||
984 | saved_errno = errno; | ||
985 | v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n", | ||
986 | slave_ifname, strerror(saved_errno)); | ||
987 | } else { | ||
988 | v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu); | ||
989 | } | ||
990 | |||
991 | return res; | ||
992 | } | ||
993 | |||
994 | static int set_if_flags(char *ifname, short flags) | ||
995 | { | ||
996 | struct ifreq ifr; | ||
997 | int res = 0; | ||
998 | |||
999 | ifr.ifr_flags = flags; | ||
1000 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
1001 | |||
1002 | res = ioctl(skfd, SIOCSIFFLAGS, &ifr); | ||
1003 | if (res < 0) { | ||
1004 | saved_errno = errno; | ||
1005 | v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n", | ||
1006 | ifname, strerror(saved_errno)); | ||
1007 | } else { | ||
1008 | v_print("Interface '%s': flags set to %04X.\n", ifname, flags); | ||
1009 | } | ||
1010 | |||
1011 | return res; | ||
1012 | } | ||
1013 | |||
1014 | static int set_if_up(char *ifname, short flags) | ||
1015 | { | ||
1016 | return set_if_flags(ifname, flags | IFF_UP); | ||
1017 | } | ||
1018 | |||
1019 | static int set_if_down(char *ifname, short flags) | ||
1020 | { | ||
1021 | return set_if_flags(ifname, flags & ~IFF_UP); | ||
1022 | } | ||
1023 | |||
1024 | static int clear_if_addr(char *ifname) | ||
1025 | { | ||
1026 | struct ifreq ifr; | ||
1027 | int res = 0; | ||
1028 | |||
1029 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
1030 | ifr.ifr_addr.sa_family = AF_INET; | ||
1031 | memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); | ||
1032 | |||
1033 | res = ioctl(skfd, SIOCSIFADDR, &ifr); | ||
1034 | if (res < 0) { | ||
1035 | saved_errno = errno; | ||
1036 | v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n", | ||
1037 | ifname, strerror(saved_errno)); | ||
1038 | } else { | ||
1039 | v_print("Interface '%s': address cleared\n", ifname); | ||
1040 | } | ||
1041 | |||
1042 | return res; | ||
1043 | } | ||
1044 | |||
1045 | static int set_if_addr(char *master_ifname, char *slave_ifname) | ||
1046 | { | ||
1047 | struct ifreq ifr; | ||
1048 | int res; | ||
1049 | unsigned char *ipaddr; | ||
1050 | int i; | ||
1051 | struct { | ||
1052 | char *req_name; | ||
1053 | char *desc; | ||
1054 | int g_ioctl; | ||
1055 | int s_ioctl; | ||
1056 | } ifra[] = { | ||
1057 | {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR}, | ||
1058 | {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR}, | ||
1059 | {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR}, | ||
1060 | {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK}, | ||
1061 | {NULL, NULL, 0, 0}, | ||
1062 | }; | ||
1063 | |||
1064 | for (i = 0; ifra[i].req_name; i++) { | ||
1065 | strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); | ||
1066 | res = ioctl(skfd, ifra[i].g_ioctl, &ifr); | ||
1067 | if (res < 0) { | ||
1068 | int saved_errno = errno; | ||
1069 | |||
1070 | v_print("Interface '%s': Error: SIOCG%s failed: %s\n", | ||
1071 | master_ifname, ifra[i].req_name, | ||
1072 | strerror(saved_errno)); | ||
1073 | |||
1074 | ifr.ifr_addr.sa_family = AF_INET; | ||
1075 | memset(ifr.ifr_addr.sa_data, 0, | ||
1076 | sizeof(ifr.ifr_addr.sa_data)); | ||
1077 | } | ||
1078 | |||
1079 | strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); | ||
1080 | res = ioctl(skfd, ifra[i].s_ioctl, &ifr); | ||
1081 | if (res < 0) { | ||
1082 | int saved_errno = errno; | ||
1083 | |||
1084 | v_print("Interface '%s': Error: SIOCS%s failed: %s\n", | ||
1085 | slave_ifname, ifra[i].req_name, | ||
1086 | strerror(saved_errno)); | ||
1087 | |||
1088 | return res; | ||
1089 | } | ||
1090 | |||
1091 | ipaddr = ifr.ifr_addr.sa_data; | ||
1092 | v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n", | ||
1093 | slave_ifname, ifra[i].desc, | ||
1094 | ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); | ||
1095 | } | ||
1096 | |||
1097 | return 0; | ||
1098 | } | ||
1099 | |||
1100 | /* | ||
1101 | * Local variables: | ||
1102 | * version-control: t | ||
1103 | * kept-new-versions: 5 | ||
1104 | * c-indent-level: 4 | ||
1105 | * c-basic-offset: 4 | ||
1106 | * tab-width: 4 | ||
1107 | * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" | ||
1108 | * End: | ||
1109 | */ | ||
1110 | |||