Annotation of /trunk/mkinitrd-magellan/busybox/networking/ifconfig.c
Parent Directory | Revision Log
Revision 816 -
(hide annotations)
(download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 5 months ago) by niro
File MIME type: text/plain
File size: 16060 byte(s)
Fri Apr 24 18:33:46 2009 UTC (15 years, 5 months ago) by niro
File MIME type: text/plain
File size: 16060 byte(s)
-updated to busybox-1.13.4
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* ifconfig | ||
3 | * | ||
4 | * Similar to the standard Unix ifconfig, but with only the necessary | ||
5 | * parts for AF_INET, and without any printing of if info (for now). | ||
6 | * | ||
7 | * Bjorn Wesen, Axis Communications AB | ||
8 | * | ||
9 | * | ||
10 | * Authors of the original ifconfig was: | ||
11 | * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> | ||
12 | * | ||
13 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * Heavily modified by Manuel Novoa III Mar 6, 2001 | ||
18 | * | ||
19 | * From initial port to busybox, removed most of the redundancy by | ||
20 | * converting to a table-driven approach. Added several (optional) | ||
21 | * args missing from initial port. | ||
22 | * | ||
23 | * Still missing: media, tunnel. | ||
24 | * | ||
25 | * 2002-04-20 | ||
26 | * IPV6 support added by Bart Visscher <magick@linux-fan.com> | ||
27 | */ | ||
28 | |||
29 | #include <net/if.h> | ||
30 | #include <net/if_arp.h> | ||
31 | #include <netinet/in.h> | ||
32 | #if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1 | ||
33 | #include <netpacket/packet.h> | ||
34 | #include <net/ethernet.h> | ||
35 | #else | ||
36 | #include <sys/types.h> | ||
37 | #include <netinet/if_ether.h> | ||
38 | #endif | ||
39 | #include "inet_common.h" | ||
40 | niro | 816 | #include "libbb.h" |
41 | niro | 532 | |
42 | #if ENABLE_FEATURE_IFCONFIG_SLIP | ||
43 | # include <net/if_slip.h> | ||
44 | #endif | ||
45 | |||
46 | /* I don't know if this is needed for busybox or not. Anyone? */ | ||
47 | #define QUESTIONABLE_ALIAS_CASE | ||
48 | |||
49 | |||
50 | /* Defines for glibc2.0 users. */ | ||
51 | #ifndef SIOCSIFTXQLEN | ||
52 | # define SIOCSIFTXQLEN 0x8943 | ||
53 | # define SIOCGIFTXQLEN 0x8942 | ||
54 | #endif | ||
55 | |||
56 | /* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */ | ||
57 | #ifndef ifr_qlen | ||
58 | # define ifr_qlen ifr_ifru.ifru_mtu | ||
59 | #endif | ||
60 | |||
61 | #ifndef IFF_DYNAMIC | ||
62 | # define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */ | ||
63 | #endif | ||
64 | |||
65 | #if ENABLE_FEATURE_IPV6 | ||
66 | struct in6_ifreq { | ||
67 | struct in6_addr ifr6_addr; | ||
68 | uint32_t ifr6_prefixlen; | ||
69 | int ifr6_ifindex; | ||
70 | }; | ||
71 | #endif | ||
72 | |||
73 | /* | ||
74 | * Here are the bit masks for the "flags" member of struct options below. | ||
75 | * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'. | ||
76 | * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg. | ||
77 | */ | ||
78 | #define N_CLR 0x01 | ||
79 | #define M_CLR 0x02 | ||
80 | #define N_SET 0x04 | ||
81 | #define M_SET 0x08 | ||
82 | #define N_ARG 0x10 | ||
83 | #define M_ARG 0x20 | ||
84 | |||
85 | #define M_MASK (M_CLR | M_SET | M_ARG) | ||
86 | #define N_MASK (N_CLR | N_SET | N_ARG) | ||
87 | #define SET_MASK (N_SET | M_SET) | ||
88 | #define CLR_MASK (N_CLR | M_CLR) | ||
89 | #define SET_CLR_MASK (SET_MASK | CLR_MASK) | ||
90 | #define ARG_MASK (M_ARG | N_ARG) | ||
91 | |||
92 | /* | ||
93 | * Here are the bit masks for the "arg_flags" member of struct options below. | ||
94 | */ | ||
95 | |||
96 | /* | ||
97 | * cast type: | ||
98 | * 00 int | ||
99 | * 01 char * | ||
100 | * 02 HOST_COPY in_ether | ||
101 | * 03 HOST_COPY INET_resolve | ||
102 | */ | ||
103 | #define A_CAST_TYPE 0x03 | ||
104 | /* | ||
105 | * map type: | ||
106 | * 00 not a map type (mem_start, io_addr, irq) | ||
107 | * 04 memstart (unsigned long) | ||
108 | * 08 io_addr (unsigned short) | ||
109 | * 0C irq (unsigned char) | ||
110 | */ | ||
111 | #define A_MAP_TYPE 0x0C | ||
112 | #define A_ARG_REQ 0x10 /* Set if an arg is required. */ | ||
113 | #define A_NETMASK 0x20 /* Set if netmask (check for multiple sets). */ | ||
114 | #define A_SET_AFTER 0x40 /* Set a flag at the end. */ | ||
115 | #define A_COLON_CHK 0x80 /* Is this needed? See below. */ | ||
116 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
117 | #define A_HOSTNAME 0x100 /* Set if it is ip addr. */ | ||
118 | #define A_BROADCAST 0x200 /* Set if it is broadcast addr. */ | ||
119 | #else | ||
120 | #define A_HOSTNAME 0 | ||
121 | #define A_BROADCAST 0 | ||
122 | #endif | ||
123 | |||
124 | /* | ||
125 | * These defines are for dealing with the A_CAST_TYPE field. | ||
126 | */ | ||
127 | #define A_CAST_CHAR_PTR 0x01 | ||
128 | #define A_CAST_RESOLVE 0x01 | ||
129 | #define A_CAST_HOST_COPY 0x02 | ||
130 | #define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY | ||
131 | #define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE) | ||
132 | |||
133 | /* | ||
134 | * These defines are for dealing with the A_MAP_TYPE field. | ||
135 | */ | ||
136 | #define A_MAP_ULONG 0x04 /* memstart */ | ||
137 | #define A_MAP_USHORT 0x08 /* io_addr */ | ||
138 | #define A_MAP_UCHAR 0x0C /* irq */ | ||
139 | |||
140 | /* | ||
141 | * Define the bit masks signifying which operations to perform for each arg. | ||
142 | */ | ||
143 | |||
144 | #define ARG_METRIC (A_ARG_REQ /*| A_CAST_INT*/) | ||
145 | #define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/) | ||
146 | #define ARG_TXQUEUELEN (A_ARG_REQ /*| A_CAST_INT*/) | ||
147 | #define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG) | ||
148 | #define ARG_IO_ADDR (A_ARG_REQ | A_MAP_ULONG) | ||
149 | #define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR) | ||
150 | #define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE) | ||
151 | #define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK) | ||
152 | #define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_BROADCAST) | ||
153 | #define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER) | ||
154 | #define ARG_POINTOPOINT (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) | ||
155 | #define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR) | ||
156 | #define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR) | ||
157 | #define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK | A_HOSTNAME) | ||
158 | #define ARG_ADD_DEL (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) | ||
159 | |||
160 | |||
161 | /* | ||
162 | * Set up the tables. Warning! They must have corresponding order! | ||
163 | */ | ||
164 | |||
165 | struct arg1opt { | ||
166 | const char *name; | ||
167 | niro | 816 | unsigned short selector; |
168 | niro | 532 | unsigned short ifr_offset; |
169 | }; | ||
170 | |||
171 | struct options { | ||
172 | const char *name; | ||
173 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
174 | const unsigned int flags:6; | ||
175 | const unsigned int arg_flags:10; | ||
176 | #else | ||
177 | const unsigned char flags; | ||
178 | const unsigned char arg_flags; | ||
179 | #endif | ||
180 | const unsigned short selector; | ||
181 | }; | ||
182 | |||
183 | #define ifreq_offsetof(x) offsetof(struct ifreq, x) | ||
184 | |||
185 | static const struct arg1opt Arg1Opt[] = { | ||
186 | niro | 816 | { "SIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric) }, |
187 | { "SIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu) }, | ||
188 | { "SIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen) }, | ||
189 | { "SIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr) }, | ||
190 | { "SIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask) }, | ||
191 | { "SIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr) }, | ||
192 | niro | 532 | #if ENABLE_FEATURE_IFCONFIG_HW |
193 | niro | 816 | { "SIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr) }, |
194 | niro | 532 | #endif |
195 | niro | 816 | { "SIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr) }, |
196 | niro | 532 | #ifdef SIOCSKEEPALIVE |
197 | niro | 816 | { "SKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data) }, |
198 | niro | 532 | #endif |
199 | #ifdef SIOCSOUTFILL | ||
200 | niro | 816 | { "SOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data) }, |
201 | niro | 532 | #endif |
202 | #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ | ||
203 | niro | 816 | { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start) }, |
204 | { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr) }, | ||
205 | { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq) }, | ||
206 | niro | 532 | #endif |
207 | /* Last entry if for unmatched (possibly hostname) arg. */ | ||
208 | #if ENABLE_FEATURE_IPV6 | ||
209 | niro | 816 | { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) }, /* IPv6 version ignores the offset */ |
210 | { "DIFADDR", SIOCDIFADDR, ifreq_offsetof(ifr_addr) }, /* IPv6 version ignores the offset */ | ||
211 | niro | 532 | #endif |
212 | niro | 816 | { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) }, |
213 | niro | 532 | }; |
214 | |||
215 | static const struct options OptArray[] = { | ||
216 | niro | 816 | { "metric", N_ARG, ARG_METRIC, 0 }, |
217 | { "mtu", N_ARG, ARG_MTU, 0 }, | ||
218 | { "txqueuelen", N_ARG, ARG_TXQUEUELEN, 0 }, | ||
219 | { "dstaddr", N_ARG, ARG_DSTADDR, 0 }, | ||
220 | { "netmask", N_ARG, ARG_NETMASK, 0 }, | ||
221 | { "broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST }, | ||
222 | niro | 532 | #if ENABLE_FEATURE_IFCONFIG_HW |
223 | niro | 816 | { "hw", N_ARG, ARG_HW, 0 }, |
224 | niro | 532 | #endif |
225 | niro | 816 | { "pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT }, |
226 | niro | 532 | #ifdef SIOCSKEEPALIVE |
227 | niro | 816 | { "keepalive", N_ARG, ARG_KEEPALIVE, 0 }, |
228 | niro | 532 | #endif |
229 | #ifdef SIOCSOUTFILL | ||
230 | niro | 816 | { "outfill", N_ARG, ARG_OUTFILL, 0 }, |
231 | niro | 532 | #endif |
232 | #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ | ||
233 | niro | 816 | { "mem_start", N_ARG, ARG_MEM_START, 0 }, |
234 | { "io_addr", N_ARG, ARG_IO_ADDR, 0 }, | ||
235 | { "irq", N_ARG, ARG_IRQ, 0 }, | ||
236 | niro | 532 | #endif |
237 | #if ENABLE_FEATURE_IPV6 | ||
238 | niro | 816 | { "add", N_ARG, ARG_ADD_DEL, 0 }, |
239 | { "del", N_ARG, ARG_ADD_DEL, 0 }, | ||
240 | niro | 532 | #endif |
241 | niro | 816 | { "arp", N_CLR | M_SET, 0, IFF_NOARP }, |
242 | { "trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS }, | ||
243 | { "promisc", N_SET | M_CLR, 0, IFF_PROMISC }, | ||
244 | { "multicast", N_SET | M_CLR, 0, IFF_MULTICAST }, | ||
245 | { "allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI }, | ||
246 | { "dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC }, | ||
247 | { "up", N_SET, 0, (IFF_UP | IFF_RUNNING) }, | ||
248 | { "down", N_CLR, 0, IFF_UP }, | ||
249 | { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING) } | ||
250 | niro | 532 | }; |
251 | |||
252 | /* | ||
253 | * A couple of prototypes. | ||
254 | */ | ||
255 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
256 | static int in_ether(const char *bufp, struct sockaddr *sap); | ||
257 | #endif | ||
258 | |||
259 | /* | ||
260 | * Our main function. | ||
261 | */ | ||
262 | niro | 816 | int ifconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
263 | niro | 532 | int ifconfig_main(int argc, char **argv) |
264 | { | ||
265 | struct ifreq ifr; | ||
266 | struct sockaddr_in sai; | ||
267 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
268 | struct sockaddr sa; | ||
269 | #endif | ||
270 | const struct arg1opt *a1op; | ||
271 | const struct options *op; | ||
272 | int sockfd; /* socket fd we use to manipulate stuff with */ | ||
273 | int selector; | ||
274 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
275 | unsigned int mask; | ||
276 | unsigned int did_flags; | ||
277 | unsigned int sai_hostname, sai_netmask; | ||
278 | #else | ||
279 | unsigned char mask; | ||
280 | unsigned char did_flags; | ||
281 | #endif | ||
282 | char *p; | ||
283 | /*char host[128];*/ | ||
284 | const char *host = NULL; /* make gcc happy */ | ||
285 | |||
286 | did_flags = 0; | ||
287 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
288 | sai_hostname = 0; | ||
289 | sai_netmask = 0; | ||
290 | #endif | ||
291 | |||
292 | /* skip argv[0] */ | ||
293 | ++argv; | ||
294 | --argc; | ||
295 | |||
296 | #if ENABLE_FEATURE_IFCONFIG_STATUS | ||
297 | if (argc > 0 && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) { | ||
298 | interface_opt_a = 1; | ||
299 | --argc; | ||
300 | ++argv; | ||
301 | } | ||
302 | #endif | ||
303 | |||
304 | if (argc <= 1) { | ||
305 | #if ENABLE_FEATURE_IFCONFIG_STATUS | ||
306 | return display_interfaces(argc ? *argv : NULL); | ||
307 | #else | ||
308 | bb_error_msg_and_die("no support for status display"); | ||
309 | #endif | ||
310 | } | ||
311 | |||
312 | /* Create a channel to the NET kernel. */ | ||
313 | sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); | ||
314 | |||
315 | /* get interface name */ | ||
316 | niro | 816 | strncpy(ifr.ifr_name, *argv, IFNAMSIZ); |
317 | niro | 532 | |
318 | /* Process the remaining arguments. */ | ||
319 | while (*++argv != (char *) NULL) { | ||
320 | p = *argv; | ||
321 | mask = N_MASK; | ||
322 | if (*p == '-') { /* If the arg starts with '-'... */ | ||
323 | ++p; /* advance past it and */ | ||
324 | mask = M_MASK; /* set the appropriate mask. */ | ||
325 | } | ||
326 | for (op = OptArray; op->name; op++) { /* Find table entry. */ | ||
327 | if (strcmp(p, op->name) == 0) { /* If name matches... */ | ||
328 | mask &= op->flags; | ||
329 | if (mask) /* set the mask and go. */ | ||
330 | goto FOUND_ARG; | ||
331 | /* If we get here, there was a valid arg with an */ | ||
332 | /* invalid '-' prefix. */ | ||
333 | bb_error_msg_and_die("bad: '%s'", p-1); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | /* We fell through, so treat as possible hostname. */ | ||
338 | niro | 816 | a1op = Arg1Opt + ARRAY_SIZE(Arg1Opt) - 1; |
339 | niro | 532 | mask = op->arg_flags; |
340 | goto HOSTNAME; | ||
341 | |||
342 | FOUND_ARG: | ||
343 | if (mask & ARG_MASK) { | ||
344 | mask = op->arg_flags; | ||
345 | a1op = Arg1Opt + (op - OptArray); | ||
346 | if (mask & A_NETMASK & did_flags) | ||
347 | bb_show_usage(); | ||
348 | if (*++argv == NULL) { | ||
349 | if (mask & A_ARG_REQ) | ||
350 | bb_show_usage(); | ||
351 | --argv; | ||
352 | mask &= A_SET_AFTER; /* just for broadcast */ | ||
353 | } else { /* got an arg so process it */ | ||
354 | HOSTNAME: | ||
355 | did_flags |= (mask & (A_NETMASK|A_HOSTNAME)); | ||
356 | if (mask & A_CAST_HOST_COPY) { | ||
357 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
358 | if (mask & A_CAST_RESOLVE) { | ||
359 | #endif | ||
360 | #if ENABLE_FEATURE_IPV6 | ||
361 | char *prefix; | ||
362 | int prefix_len = 0; | ||
363 | #endif | ||
364 | /*safe_strncpy(host, *argv, (sizeof host));*/ | ||
365 | host = *argv; | ||
366 | #if ENABLE_FEATURE_IPV6 | ||
367 | prefix = strchr(host, '/'); | ||
368 | if (prefix) { | ||
369 | prefix_len = xatou_range(prefix + 1, 0, 128); | ||
370 | *prefix = '\0'; | ||
371 | } | ||
372 | #endif | ||
373 | sai.sin_family = AF_INET; | ||
374 | sai.sin_port = 0; | ||
375 | if (!strcmp(host, bb_str_default)) { | ||
376 | /* Default is special, meaning 0.0.0.0. */ | ||
377 | sai.sin_addr.s_addr = INADDR_ANY; | ||
378 | } | ||
379 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
380 | else if ((host[0] == '+' && !host[1]) && (mask & A_BROADCAST) | ||
381 | && (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME) | ||
382 | ) { | ||
383 | /* + is special, meaning broadcast is derived. */ | ||
384 | sai.sin_addr.s_addr = (~sai_netmask) | (sai_hostname & sai_netmask); | ||
385 | } | ||
386 | #endif | ||
387 | niro | 816 | else { |
388 | len_and_sockaddr *lsa; | ||
389 | if (strcmp(host, "inet") == 0) | ||
390 | continue; /* compat stuff */ | ||
391 | lsa = xhost2sockaddr(host, 0); | ||
392 | niro | 532 | #if ENABLE_FEATURE_IPV6 |
393 | niro | 816 | if (lsa->u.sa.sa_family == AF_INET6) { |
394 | int sockfd6; | ||
395 | struct in6_ifreq ifr6; | ||
396 | niro | 532 | |
397 | niro | 816 | memcpy((char *) &ifr6.ifr6_addr, |
398 | (char *) &(lsa->u.sin6.sin6_addr), | ||
399 | sizeof(struct in6_addr)); | ||
400 | niro | 532 | |
401 | niro | 816 | /* Create a channel to the NET kernel. */ |
402 | sockfd6 = xsocket(AF_INET6, SOCK_DGRAM, 0); | ||
403 | xioctl(sockfd6, SIOGIFINDEX, &ifr); | ||
404 | ifr6.ifr6_ifindex = ifr.ifr_ifindex; | ||
405 | ifr6.ifr6_prefixlen = prefix_len; | ||
406 | ioctl_or_perror_and_die(sockfd6, a1op->selector, &ifr6, "SIOC%s", a1op->name); | ||
407 | if (ENABLE_FEATURE_CLEAN_UP) | ||
408 | free(lsa); | ||
409 | continue; | ||
410 | } | ||
411 | niro | 532 | #endif |
412 | niro | 816 | sai.sin_addr = lsa->u.sin.sin_addr; |
413 | if (ENABLE_FEATURE_CLEAN_UP) | ||
414 | free(lsa); | ||
415 | niro | 532 | } |
416 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
417 | if (mask & A_HOSTNAME) | ||
418 | sai_hostname = sai.sin_addr.s_addr; | ||
419 | if (mask & A_NETMASK) | ||
420 | sai_netmask = sai.sin_addr.s_addr; | ||
421 | #endif | ||
422 | p = (char *) &sai; | ||
423 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
424 | } else { /* A_CAST_HOST_COPY_IN_ETHER */ | ||
425 | /* This is the "hw" arg case. */ | ||
426 | niro | 816 | smalluint hw_class= index_in_substrings("ether\0" |
427 | USE_FEATURE_HWIB("infiniband\0"), *argv) + 1; | ||
428 | if (!hw_class || !*++argv) | ||
429 | niro | 532 | bb_show_usage(); |
430 | /*safe_strncpy(host, *argv, sizeof(host));*/ | ||
431 | host = *argv; | ||
432 | niro | 816 | if (hw_class == 1 ? in_ether(host, &sa) : in_ib(host, &sa)) |
433 | niro | 532 | bb_error_msg_and_die("invalid hw-addr %s", host); |
434 | p = (char *) &sa; | ||
435 | } | ||
436 | #endif | ||
437 | memcpy( (((char *)&ifr) + a1op->ifr_offset), | ||
438 | p, sizeof(struct sockaddr)); | ||
439 | } else { | ||
440 | /* FIXME: error check?? */ | ||
441 | unsigned long i = strtoul(*argv, NULL, 0); | ||
442 | p = ((char *)&ifr) + a1op->ifr_offset; | ||
443 | #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ | ||
444 | if (mask & A_MAP_TYPE) { | ||
445 | niro | 816 | xioctl(sockfd, SIOCGIFMAP, &ifr); |
446 | niro | 532 | if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) |
447 | *((unsigned char *) p) = i; | ||
448 | else if (mask & A_MAP_USHORT) | ||
449 | *((unsigned short *) p) = i; | ||
450 | else | ||
451 | *((unsigned long *) p) = i; | ||
452 | } else | ||
453 | #endif | ||
454 | if (mask & A_CAST_CHAR_PTR) | ||
455 | *((caddr_t *) p) = (caddr_t) i; | ||
456 | else /* A_CAST_INT */ | ||
457 | *((int *) p) = i; | ||
458 | } | ||
459 | |||
460 | niro | 816 | ioctl_or_perror_and_die(sockfd, a1op->selector, &ifr, "SIOC%s", a1op->name); |
461 | niro | 532 | #ifdef QUESTIONABLE_ALIAS_CASE |
462 | if (mask & A_COLON_CHK) { | ||
463 | /* | ||
464 | * Don't do the set_flag() if the address is an alias with | ||
465 | * a '-' at the end, since it's deleted already! - Roman | ||
466 | * | ||
467 | * Should really use regex.h here, not sure though how well | ||
468 | * it'll go with the cross-platform support etc. | ||
469 | */ | ||
470 | char *ptr; | ||
471 | short int found_colon = 0; | ||
472 | for (ptr = ifr.ifr_name; *ptr; ptr++) | ||
473 | if (*ptr == ':') | ||
474 | found_colon++; | ||
475 | if (found_colon && ptr[-1] == '-') | ||
476 | continue; | ||
477 | } | ||
478 | #endif | ||
479 | } | ||
480 | if (!(mask & A_SET_AFTER)) | ||
481 | continue; | ||
482 | mask = N_SET; | ||
483 | } | ||
484 | |||
485 | niro | 816 | xioctl(sockfd, SIOCGIFFLAGS, &ifr); |
486 | niro | 532 | selector = op->selector; |
487 | if (mask & SET_MASK) | ||
488 | ifr.ifr_flags |= selector; | ||
489 | else | ||
490 | ifr.ifr_flags &= ~selector; | ||
491 | niro | 816 | xioctl(sockfd, SIOCSIFFLAGS, &ifr); |
492 | niro | 532 | } /* while () */ |
493 | |||
494 | if (ENABLE_FEATURE_CLEAN_UP) | ||
495 | close(sockfd); | ||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
500 | /* Input an Ethernet address and convert to binary. */ | ||
501 | static int in_ether(const char *bufp, struct sockaddr *sap) | ||
502 | { | ||
503 | char *ptr; | ||
504 | int i, j; | ||
505 | unsigned char val; | ||
506 | unsigned char c; | ||
507 | |||
508 | sap->sa_family = ARPHRD_ETHER; | ||
509 | niro | 816 | ptr = (char *) sap->sa_data; |
510 | niro | 532 | |
511 | i = 0; | ||
512 | do { | ||
513 | j = val = 0; | ||
514 | |||
515 | /* We might get a semicolon here - not required. */ | ||
516 | if (i && (*bufp == ':')) { | ||
517 | bufp++; | ||
518 | } | ||
519 | |||
520 | do { | ||
521 | c = *bufp; | ||
522 | if (((unsigned char)(c - '0')) <= 9) { | ||
523 | c -= '0'; | ||
524 | } else if (((unsigned char)((c|0x20) - 'a')) <= 5) { | ||
525 | c = (c|0x20) - ('a'-10); | ||
526 | } else if (j && (c == ':' || c == 0)) { | ||
527 | break; | ||
528 | } else { | ||
529 | return -1; | ||
530 | } | ||
531 | ++bufp; | ||
532 | val <<= 4; | ||
533 | val += c; | ||
534 | } while (++j < 2); | ||
535 | *ptr++ = val; | ||
536 | } while (++i < ETH_ALEN); | ||
537 | |||
538 | return *bufp; /* Error if we don't end at end of string. */ | ||
539 | } | ||
540 | #endif |