Annotation of /trunk/mkinitrd-magellan/busybox/networking/ifconfig.c
Parent Directory | Revision Log
Revision 532 -
(hide annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 16061 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 16061 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
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 | #include "busybox.h" | ||
41 | |||
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 | int selector; | ||
168 | 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 | {"SIOCSIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric)}, | ||
187 | {"SIOCSIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu)}, | ||
188 | {"SIOCSIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen)}, | ||
189 | {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, | ||
190 | {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)}, | ||
191 | {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)}, | ||
192 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
193 | {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)}, | ||
194 | #endif | ||
195 | {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, | ||
196 | #ifdef SIOCSKEEPALIVE | ||
197 | {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)}, | ||
198 | #endif | ||
199 | #ifdef SIOCSOUTFILL | ||
200 | {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)}, | ||
201 | #endif | ||
202 | #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ | ||
203 | {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)}, | ||
204 | {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)}, | ||
205 | {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)}, | ||
206 | #endif | ||
207 | /* Last entry if for unmatched (possibly hostname) arg. */ | ||
208 | #if ENABLE_FEATURE_IPV6 | ||
209 | {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */ | ||
210 | {"SIOCDIFADDR", SIOCDIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */ | ||
211 | #endif | ||
212 | {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, | ||
213 | }; | ||
214 | |||
215 | static const struct options OptArray[] = { | ||
216 | {"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 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
223 | {"hw", N_ARG, ARG_HW, 0}, | ||
224 | #endif | ||
225 | {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT}, | ||
226 | #ifdef SIOCSKEEPALIVE | ||
227 | {"keepalive", N_ARG, ARG_KEEPALIVE, 0}, | ||
228 | #endif | ||
229 | #ifdef SIOCSOUTFILL | ||
230 | {"outfill", N_ARG, ARG_OUTFILL, 0}, | ||
231 | #endif | ||
232 | #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ | ||
233 | {"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 | #endif | ||
237 | #if ENABLE_FEATURE_IPV6 | ||
238 | {"add", N_ARG, ARG_ADD_DEL, 0}, | ||
239 | {"del", N_ARG, ARG_ADD_DEL, 0}, | ||
240 | #endif | ||
241 | {"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 | }; | ||
251 | |||
252 | /* | ||
253 | * A couple of prototypes. | ||
254 | */ | ||
255 | |||
256 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
257 | static int in_ether(const char *bufp, struct sockaddr *sap); | ||
258 | #endif | ||
259 | |||
260 | /* | ||
261 | * Our main function. | ||
262 | */ | ||
263 | |||
264 | int ifconfig_main(int argc, char **argv) | ||
265 | { | ||
266 | struct ifreq ifr; | ||
267 | struct sockaddr_in sai; | ||
268 | #if ENABLE_FEATURE_IPV6 | ||
269 | struct sockaddr_in6 sai6; | ||
270 | #endif | ||
271 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
272 | struct sockaddr sa; | ||
273 | #endif | ||
274 | const struct arg1opt *a1op; | ||
275 | const struct options *op; | ||
276 | int sockfd; /* socket fd we use to manipulate stuff with */ | ||
277 | int selector; | ||
278 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
279 | unsigned int mask; | ||
280 | unsigned int did_flags; | ||
281 | unsigned int sai_hostname, sai_netmask; | ||
282 | #else | ||
283 | unsigned char mask; | ||
284 | unsigned char did_flags; | ||
285 | #endif | ||
286 | char *p; | ||
287 | /*char host[128];*/ | ||
288 | const char *host = NULL; /* make gcc happy */ | ||
289 | |||
290 | did_flags = 0; | ||
291 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
292 | sai_hostname = 0; | ||
293 | sai_netmask = 0; | ||
294 | #endif | ||
295 | |||
296 | /* skip argv[0] */ | ||
297 | ++argv; | ||
298 | --argc; | ||
299 | |||
300 | #if ENABLE_FEATURE_IFCONFIG_STATUS | ||
301 | if (argc > 0 && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) { | ||
302 | interface_opt_a = 1; | ||
303 | --argc; | ||
304 | ++argv; | ||
305 | } | ||
306 | #endif | ||
307 | |||
308 | if (argc <= 1) { | ||
309 | #if ENABLE_FEATURE_IFCONFIG_STATUS | ||
310 | return display_interfaces(argc ? *argv : NULL); | ||
311 | #else | ||
312 | bb_error_msg_and_die("no support for status display"); | ||
313 | #endif | ||
314 | } | ||
315 | |||
316 | /* Create a channel to the NET kernel. */ | ||
317 | sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); | ||
318 | |||
319 | /* get interface name */ | ||
320 | safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ); | ||
321 | |||
322 | /* Process the remaining arguments. */ | ||
323 | while (*++argv != (char *) NULL) { | ||
324 | p = *argv; | ||
325 | mask = N_MASK; | ||
326 | if (*p == '-') { /* If the arg starts with '-'... */ | ||
327 | ++p; /* advance past it and */ | ||
328 | mask = M_MASK; /* set the appropriate mask. */ | ||
329 | } | ||
330 | for (op = OptArray; op->name; op++) { /* Find table entry. */ | ||
331 | if (strcmp(p, op->name) == 0) { /* If name matches... */ | ||
332 | mask &= op->flags; | ||
333 | if (mask) /* set the mask and go. */ | ||
334 | goto FOUND_ARG; | ||
335 | /* If we get here, there was a valid arg with an */ | ||
336 | /* invalid '-' prefix. */ | ||
337 | bb_error_msg_and_die("bad: '%s'", p-1); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | /* We fell through, so treat as possible hostname. */ | ||
342 | a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1; | ||
343 | mask = op->arg_flags; | ||
344 | goto HOSTNAME; | ||
345 | |||
346 | FOUND_ARG: | ||
347 | if (mask & ARG_MASK) { | ||
348 | mask = op->arg_flags; | ||
349 | a1op = Arg1Opt + (op - OptArray); | ||
350 | if (mask & A_NETMASK & did_flags) | ||
351 | bb_show_usage(); | ||
352 | if (*++argv == NULL) { | ||
353 | if (mask & A_ARG_REQ) | ||
354 | bb_show_usage(); | ||
355 | --argv; | ||
356 | mask &= A_SET_AFTER; /* just for broadcast */ | ||
357 | } else { /* got an arg so process it */ | ||
358 | HOSTNAME: | ||
359 | did_flags |= (mask & (A_NETMASK|A_HOSTNAME)); | ||
360 | if (mask & A_CAST_HOST_COPY) { | ||
361 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
362 | if (mask & A_CAST_RESOLVE) { | ||
363 | #endif | ||
364 | #if ENABLE_FEATURE_IPV6 | ||
365 | char *prefix; | ||
366 | int prefix_len = 0; | ||
367 | #endif | ||
368 | /*safe_strncpy(host, *argv, (sizeof host));*/ | ||
369 | host = *argv; | ||
370 | #if ENABLE_FEATURE_IPV6 | ||
371 | prefix = strchr(host, '/'); | ||
372 | if (prefix) { | ||
373 | prefix_len = xatou_range(prefix + 1, 0, 128); | ||
374 | *prefix = '\0'; | ||
375 | } | ||
376 | #endif | ||
377 | sai.sin_family = AF_INET; | ||
378 | sai.sin_port = 0; | ||
379 | if (!strcmp(host, bb_str_default)) { | ||
380 | /* Default is special, meaning 0.0.0.0. */ | ||
381 | sai.sin_addr.s_addr = INADDR_ANY; | ||
382 | } | ||
383 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
384 | else if ((host[0] == '+' && !host[1]) && (mask & A_BROADCAST) | ||
385 | && (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME) | ||
386 | ) { | ||
387 | /* + is special, meaning broadcast is derived. */ | ||
388 | sai.sin_addr.s_addr = (~sai_netmask) | (sai_hostname & sai_netmask); | ||
389 | } | ||
390 | #endif | ||
391 | #if ENABLE_FEATURE_IPV6 | ||
392 | else if (inet_pton(AF_INET6, host, &sai6.sin6_addr) > 0) { | ||
393 | int sockfd6; | ||
394 | struct in6_ifreq ifr6; | ||
395 | |||
396 | memcpy((char *) &ifr6.ifr6_addr, | ||
397 | (char *) &sai6.sin6_addr, | ||
398 | sizeof(struct in6_addr)); | ||
399 | |||
400 | /* Create a channel to the NET kernel. */ | ||
401 | sockfd6 = xsocket(AF_INET6, SOCK_DGRAM, 0); | ||
402 | if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) | ||
403 | bb_perror_msg_and_die("SIOGIFINDEX"); | ||
404 | ifr6.ifr6_ifindex = ifr.ifr_ifindex; | ||
405 | ifr6.ifr6_prefixlen = prefix_len; | ||
406 | if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) | ||
407 | bb_perror_msg_and_die(a1op->name); | ||
408 | continue; | ||
409 | } | ||
410 | #endif | ||
411 | else if (inet_aton(host, &sai.sin_addr) == 0) { | ||
412 | /* It's not a dotted quad. */ | ||
413 | struct hostent *hp = xgethostbyname(host); | ||
414 | memcpy((char *) &sai.sin_addr, (char *) hp->h_addr_list[0], | ||
415 | sizeof(struct in_addr)); | ||
416 | } | ||
417 | #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS | ||
418 | if (mask & A_HOSTNAME) | ||
419 | sai_hostname = sai.sin_addr.s_addr; | ||
420 | if (mask & A_NETMASK) | ||
421 | sai_netmask = sai.sin_addr.s_addr; | ||
422 | #endif | ||
423 | p = (char *) &sai; | ||
424 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
425 | } else { /* A_CAST_HOST_COPY_IN_ETHER */ | ||
426 | /* This is the "hw" arg case. */ | ||
427 | if (strcmp("ether", *argv) || !*++argv) | ||
428 | bb_show_usage(); | ||
429 | /*safe_strncpy(host, *argv, sizeof(host));*/ | ||
430 | host = *argv; | ||
431 | if (in_ether(host, &sa)) | ||
432 | bb_error_msg_and_die("invalid hw-addr %s", host); | ||
433 | p = (char *) &sa; | ||
434 | } | ||
435 | #endif | ||
436 | memcpy( (((char *)&ifr) + a1op->ifr_offset), | ||
437 | p, sizeof(struct sockaddr)); | ||
438 | } else { | ||
439 | /* FIXME: error check?? */ | ||
440 | unsigned long i = strtoul(*argv, NULL, 0); | ||
441 | p = ((char *)&ifr) + a1op->ifr_offset; | ||
442 | #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ | ||
443 | if (mask & A_MAP_TYPE) { | ||
444 | if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) | ||
445 | bb_perror_msg_and_die("SIOCGIFMAP"); | ||
446 | 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 | if (ioctl(sockfd, a1op->selector, &ifr) < 0) | ||
461 | bb_perror_msg_and_die(a1op->name); | ||
462 | #ifdef QUESTIONABLE_ALIAS_CASE | ||
463 | if (mask & A_COLON_CHK) { | ||
464 | /* | ||
465 | * Don't do the set_flag() if the address is an alias with | ||
466 | * a '-' at the end, since it's deleted already! - Roman | ||
467 | * | ||
468 | * Should really use regex.h here, not sure though how well | ||
469 | * it'll go with the cross-platform support etc. | ||
470 | */ | ||
471 | char *ptr; | ||
472 | short int found_colon = 0; | ||
473 | for (ptr = ifr.ifr_name; *ptr; ptr++) | ||
474 | if (*ptr == ':') | ||
475 | found_colon++; | ||
476 | if (found_colon && ptr[-1] == '-') | ||
477 | continue; | ||
478 | } | ||
479 | #endif | ||
480 | } | ||
481 | if (!(mask & A_SET_AFTER)) | ||
482 | continue; | ||
483 | mask = N_SET; | ||
484 | } | ||
485 | |||
486 | if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) | ||
487 | bb_perror_msg_and_die("SIOCGIFFLAGS"); | ||
488 | selector = op->selector; | ||
489 | if (mask & SET_MASK) | ||
490 | ifr.ifr_flags |= selector; | ||
491 | else | ||
492 | ifr.ifr_flags &= ~selector; | ||
493 | if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) | ||
494 | bb_perror_msg_and_die("SIOCSIFFLAGS"); | ||
495 | } /* while () */ | ||
496 | |||
497 | if (ENABLE_FEATURE_CLEAN_UP) | ||
498 | close(sockfd); | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | #if ENABLE_FEATURE_IFCONFIG_HW | ||
503 | /* Input an Ethernet address and convert to binary. */ | ||
504 | static int in_ether(const char *bufp, struct sockaddr *sap) | ||
505 | { | ||
506 | char *ptr; | ||
507 | int i, j; | ||
508 | unsigned char val; | ||
509 | unsigned char c; | ||
510 | |||
511 | sap->sa_family = ARPHRD_ETHER; | ||
512 | ptr = sap->sa_data; | ||
513 | |||
514 | i = 0; | ||
515 | do { | ||
516 | j = val = 0; | ||
517 | |||
518 | /* We might get a semicolon here - not required. */ | ||
519 | if (i && (*bufp == ':')) { | ||
520 | bufp++; | ||
521 | } | ||
522 | |||
523 | do { | ||
524 | c = *bufp; | ||
525 | if (((unsigned char)(c - '0')) <= 9) { | ||
526 | c -= '0'; | ||
527 | } else if (((unsigned char)((c|0x20) - 'a')) <= 5) { | ||
528 | c = (c|0x20) - ('a'-10); | ||
529 | } else if (j && (c == ':' || c == 0)) { | ||
530 | break; | ||
531 | } else { | ||
532 | return -1; | ||
533 | } | ||
534 | ++bufp; | ||
535 | val <<= 4; | ||
536 | val += c; | ||
537 | } while (++j < 2); | ||
538 | *ptr++ = val; | ||
539 | } while (++i < ETH_ALEN); | ||
540 | |||
541 | return *bufp; /* Error if we don't end at end of string. */ | ||
542 | } | ||
543 | #endif |