source: trunk/mindi-busybox/networking/ifconfig.c @ 904

Last change on this file since 904 was 821, checked in by bruno, 13 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 16.5 KB
Line 
1/* 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 <stdio.h>
30#include <stdlib.h>
31#include <string.h>     /* strcmp and friends */
32#include <ctype.h>      /* isdigit and friends */
33#include <stddef.h>     /* offsetof */
34#include <unistd.h>
35#include <netdb.h>
36#include <sys/ioctl.h>
37#include <net/if.h>
38#include <net/if_arp.h>
39#include <netinet/in.h>
40#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
41#include <netpacket/packet.h>
42#include <net/ethernet.h>
43#else
44#include <sys/types.h>
45#include <netinet/if_ether.h>
46#endif
47#include "inet_common.h"
48#include "busybox.h"
49
50#ifdef CONFIG_FEATURE_IFCONFIG_SLIP
51# include <net/if_slip.h>
52#endif
53
54/* I don't know if this is needed for busybox or not.  Anyone? */
55#define QUESTIONABLE_ALIAS_CASE
56
57
58/* Defines for glibc2.0 users. */
59#ifndef SIOCSIFTXQLEN
60# define SIOCSIFTXQLEN      0x8943
61# define SIOCGIFTXQLEN      0x8942
62#endif
63
64/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
65#ifndef ifr_qlen
66# define ifr_qlen        ifr_ifru.ifru_mtu
67#endif
68
69#ifndef IFF_DYNAMIC
70# define IFF_DYNAMIC     0x8000 /* dialup device with changing addresses */
71#endif
72
73#ifdef CONFIG_FEATURE_IPV6
74struct in6_ifreq {
75    struct in6_addr ifr6_addr;
76    uint32_t ifr6_prefixlen;
77    int ifr6_ifindex;
78};
79#endif
80
81/*
82 * Here are the bit masks for the "flags" member of struct options below.
83 * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
84 * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg.
85 */
86#define N_CLR            0x01
87#define M_CLR            0x02
88#define N_SET            0x04
89#define M_SET            0x08
90#define N_ARG            0x10
91#define M_ARG            0x20
92
93#define M_MASK           (M_CLR | M_SET | M_ARG)
94#define N_MASK           (N_CLR | N_SET | N_ARG)
95#define SET_MASK         (N_SET | M_SET)
96#define CLR_MASK         (N_CLR | M_CLR)
97#define SET_CLR_MASK     (SET_MASK | CLR_MASK)
98#define ARG_MASK         (M_ARG | N_ARG)
99
100/*
101 * Here are the bit masks for the "arg_flags" member of struct options below.
102 */
103
104/*
105 * cast type:
106 *   00 int
107 *   01 char *
108 *   02 HOST_COPY in_ether
109 *   03 HOST_COPY INET_resolve
110 */
111#define A_CAST_TYPE      0x03
112/*
113 * map type:
114 *   00 not a map type (mem_start, io_addr, irq)
115 *   04 memstart (unsigned long)
116 *   08 io_addr  (unsigned short)
117 *   0C irq      (unsigned char)
118 */
119#define A_MAP_TYPE       0x0C
120#define A_ARG_REQ        0x10   /* Set if an arg is required. */
121#define A_NETMASK        0x20   /* Set if netmask (check for multiple sets). */
122#define A_SET_AFTER      0x40   /* Set a flag at the end. */
123#define A_COLON_CHK      0x80   /* Is this needed?  See below. */
124#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
125#define A_HOSTNAME      0x100   /* Set if it is ip addr. */
126#define A_BROADCAST     0x200   /* Set if it is broadcast addr. */
127#else
128#define A_HOSTNAME          0
129#define A_BROADCAST         0
130#endif
131
132/*
133 * These defines are for dealing with the A_CAST_TYPE field.
134 */
135#define A_CAST_CHAR_PTR  0x01
136#define A_CAST_RESOLVE   0x01
137#define A_CAST_HOST_COPY 0x02
138#define A_CAST_HOST_COPY_IN_ETHER    A_CAST_HOST_COPY
139#define A_CAST_HOST_COPY_RESOLVE     (A_CAST_HOST_COPY | A_CAST_RESOLVE)
140
141/*
142 * These defines are for dealing with the A_MAP_TYPE field.
143 */
144#define A_MAP_ULONG      0x04   /* memstart */
145#define A_MAP_USHORT     0x08   /* io_addr */
146#define A_MAP_UCHAR      0x0C   /* irq */
147
148/*
149 * Define the bit masks signifying which operations to perform for each arg.
150 */
151
152#define ARG_METRIC       (A_ARG_REQ /*| A_CAST_INT*/)
153#define ARG_MTU          (A_ARG_REQ /*| A_CAST_INT*/)
154#define ARG_TXQUEUELEN   (A_ARG_REQ /*| A_CAST_INT*/)
155#define ARG_MEM_START    (A_ARG_REQ | A_MAP_ULONG)
156#define ARG_IO_ADDR      (A_ARG_REQ | A_MAP_ULONG)
157#define ARG_IRQ          (A_ARG_REQ | A_MAP_UCHAR)
158#define ARG_DSTADDR      (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
159#define ARG_NETMASK      (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
160#define ARG_BROADCAST    (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_BROADCAST)
161#define ARG_HW           (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
162#define ARG_POINTOPOINT  (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
163#define ARG_KEEPALIVE    (A_ARG_REQ | A_CAST_CHAR_PTR)
164#define ARG_OUTFILL      (A_ARG_REQ | A_CAST_CHAR_PTR)
165#define ARG_HOSTNAME     (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK | A_HOSTNAME)
166#define ARG_ADD_DEL      (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
167
168
169/*
170 * Set up the tables.  Warning!  They must have corresponding order!
171 */
172
173struct arg1opt {
174    const char *name;
175    int selector;
176    unsigned short ifr_offset;
177};
178
179struct options {
180    const char *name;
181#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
182    const unsigned int flags:6;
183    const unsigned int arg_flags:10;
184#else
185    const unsigned char flags;
186    const unsigned char arg_flags;
187#endif
188    const unsigned short selector;
189};
190
191#define ifreq_offsetof(x)  offsetof(struct ifreq, x)
192
193static const struct arg1opt Arg1Opt[] = {
194    {"SIOCSIFMETRIC",  SIOCSIFMETRIC,  ifreq_offsetof(ifr_metric)},
195    {"SIOCSIFMTU",     SIOCSIFMTU,     ifreq_offsetof(ifr_mtu)},
196    {"SIOCSIFTXQLEN",  SIOCSIFTXQLEN,  ifreq_offsetof(ifr_qlen)},
197    {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
198    {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
199    {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
200#ifdef CONFIG_FEATURE_IFCONFIG_HW
201    {"SIOCSIFHWADDR",  SIOCSIFHWADDR,  ifreq_offsetof(ifr_hwaddr)},
202#endif
203    {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
204#ifdef SIOCSKEEPALIVE
205    {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},
206#endif
207#ifdef SIOCSOUTFILL
208    {"SIOCSOUTFILL",   SIOCSOUTFILL,   ifreq_offsetof(ifr_data)},
209#endif
210#ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
211    {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.mem_start)},
212    {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.base_addr)},
213    {"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.irq)},
214#endif
215    /* Last entry if for unmatched (possibly hostname) arg. */
216#ifdef CONFIG_FEATURE_IPV6
217    {"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
218    {"SIOCDIFADDR",    SIOCDIFADDR,    ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
219#endif
220    {"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)},
221};
222
223static const struct options OptArray[] = {
224    {"metric",      N_ARG,         ARG_METRIC,      0},
225    {"mtu",         N_ARG,         ARG_MTU,         0},
226    {"txqueuelen",  N_ARG,         ARG_TXQUEUELEN,  0},
227    {"dstaddr",     N_ARG,         ARG_DSTADDR,     0},
228    {"netmask",     N_ARG,         ARG_NETMASK,     0},
229    {"broadcast",   N_ARG | M_CLR, ARG_BROADCAST,   IFF_BROADCAST},
230#ifdef CONFIG_FEATURE_IFCONFIG_HW
231    {"hw",          N_ARG, ARG_HW,                  0},
232#endif
233    {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
234#ifdef SIOCSKEEPALIVE
235    {"keepalive",   N_ARG,         ARG_KEEPALIVE,   0},
236#endif
237#ifdef SIOCSOUTFILL
238    {"outfill",     N_ARG,         ARG_OUTFILL,     0},
239#endif
240#ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
241    {"mem_start",   N_ARG,         ARG_MEM_START,   0},
242    {"io_addr",     N_ARG,         ARG_IO_ADDR,     0},
243    {"irq",         N_ARG,         ARG_IRQ,         0},
244#endif
245#ifdef CONFIG_FEATURE_IPV6
246    {"add",         N_ARG,         ARG_ADD_DEL,     0},
247    {"del",         N_ARG,         ARG_ADD_DEL,     0},
248#endif
249    {"arp",         N_CLR | M_SET, 0,               IFF_NOARP},
250    {"trailers",    N_CLR | M_SET, 0,               IFF_NOTRAILERS},
251    {"promisc",     N_SET | M_CLR, 0,               IFF_PROMISC},
252    {"multicast",   N_SET | M_CLR, 0,               IFF_MULTICAST},
253    {"allmulti",    N_SET | M_CLR, 0,               IFF_ALLMULTI},
254    {"dynamic",     N_SET | M_CLR, 0,               IFF_DYNAMIC},
255    {"up",          N_SET,         0,               (IFF_UP | IFF_RUNNING)},
256    {"down",        N_CLR,         0,               IFF_UP},
257    {NULL,          0,             ARG_HOSTNAME,    (IFF_UP | IFF_RUNNING)}
258};
259
260/*
261 * A couple of prototypes.
262 */
263
264#ifdef CONFIG_FEATURE_IFCONFIG_HW
265static int in_ether(char *bufp, struct sockaddr *sap);
266#endif
267
268#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
269extern int interface_opt_a;
270extern int display_interfaces(char *ifname);
271#endif
272
273/*
274 * Our main function.
275 */
276
277int ifconfig_main(int argc, char **argv)
278{
279    struct ifreq ifr;
280    struct sockaddr_in sai;
281#ifdef CONFIG_FEATURE_IPV6
282    struct sockaddr_in6 sai6;
283#endif
284#ifdef CONFIG_FEATURE_IFCONFIG_HW
285    struct sockaddr sa;
286#endif
287    const struct arg1opt *a1op;
288    const struct options *op;
289    int sockfd;         /* socket fd we use to manipulate stuff with */
290    int goterr;
291    int selector;
292#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
293    unsigned int mask;
294    unsigned int did_flags;
295    unsigned int sai_hostname, sai_netmask;
296#else
297    unsigned char mask;
298    unsigned char did_flags;
299#endif
300    char *p;
301    char host[128];
302
303    goterr = 0;
304    did_flags = 0;
305#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
306    sai_hostname = 0;
307    sai_netmask = 0;
308#endif
309
310    /* skip argv[0] */
311    ++argv;
312    --argc;
313
314#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
315    if ((argc > 0) && (((*argv)[0] == '-') && ((*argv)[1] == 'a') && !(*argv)[2])) {
316        interface_opt_a = 1;
317        --argc;
318        ++argv;
319    }
320#endif
321
322    if (argc <= 1) {
323#ifdef CONFIG_FEATURE_IFCONFIG_STATUS
324        return display_interfaces(argc ? *argv : NULL);
325#else
326        bb_error_msg_and_die
327            ("ifconfig was not compiled with interface status display support.");
328#endif
329    }
330
331    /* Create a channel to the NET kernel. */
332    sockfd = bb_xsocket(AF_INET, SOCK_DGRAM, 0);
333
334    /* get interface name */
335    safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
336
337    /* Process the remaining arguments. */
338    while (*++argv != (char *) NULL) {
339        p = *argv;
340        mask = N_MASK;
341        if (*p == '-') {    /* If the arg starts with '-'... */
342            ++p;        /*    advance past it and */
343            mask = M_MASK;  /*    set the appropriate mask. */
344        }
345        for (op = OptArray; op->name; op++) {   /* Find table entry. */
346            if (strcmp(p, op->name) == 0) { /* If name matches... */
347                if ((mask &= op->flags)) {  /* set the mask and go. */
348                    goto FOUND_ARG;
349                }
350                /* If we get here, there was a valid arg with an */
351                /* invalid '-' prefix. */
352                ++goterr;
353                goto LOOP;
354            }
355        }
356
357        /* We fell through, so treat as possible hostname. */
358        a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
359        mask = op->arg_flags;
360        goto HOSTNAME;
361
362      FOUND_ARG:
363        if (mask & ARG_MASK) {
364            mask = op->arg_flags;
365            a1op = Arg1Opt + (op - OptArray);
366            if (mask & A_NETMASK & did_flags) {
367                bb_show_usage();
368            }
369            if (*++argv == NULL) {
370                if (mask & A_ARG_REQ) {
371                    bb_show_usage();
372                } else {
373                    --argv;
374                    mask &= A_SET_AFTER;    /* just for broadcast */
375                }
376            } else {    /* got an arg so process it */
377              HOSTNAME:
378                did_flags |= (mask & (A_NETMASK|A_HOSTNAME));
379                if (mask & A_CAST_HOST_COPY) {
380#ifdef CONFIG_FEATURE_IFCONFIG_HW
381                    if (mask & A_CAST_RESOLVE) {
382#endif
383#ifdef CONFIG_FEATURE_IPV6
384                        char *prefix;
385                        int prefix_len = 0;
386#endif
387
388                        safe_strncpy(host, *argv, (sizeof host));
389#ifdef CONFIG_FEATURE_IPV6
390                        if ((prefix = strchr(host, '/'))) {
391                            if (safe_strtoi(prefix + 1, &prefix_len) ||
392                                (prefix_len < 0) || (prefix_len > 128))
393                            {
394                                ++goterr;
395                                goto LOOP;
396                            }
397                            *prefix = 0;
398                        }
399#endif
400
401                        sai.sin_family = AF_INET;
402                        sai.sin_port = 0;
403                        if (!strcmp(host, bb_INET_default)) {
404                            /* Default is special, meaning 0.0.0.0. */
405                            sai.sin_addr.s_addr = INADDR_ANY;
406#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
407                        } else if (((host[0] == '+') && !host[1]) && (mask & A_BROADCAST) &&
408                                   (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME)) {
409                            /* + is special, meaning broadcast is derived. */
410                            sai.sin_addr.s_addr = (~sai_netmask) | (sai_hostname & sai_netmask);
411#endif
412#ifdef CONFIG_FEATURE_IPV6
413                        } else if (inet_pton(AF_INET6, host, &sai6.sin6_addr) > 0) {
414                            int sockfd6;
415                            struct in6_ifreq ifr6;
416
417                            memcpy((char *) &ifr6.ifr6_addr,
418                                   (char *) &sai6.sin6_addr,
419                                   sizeof(struct in6_addr));
420
421                            /* Create a channel to the NET kernel. */
422                            if ((sockfd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
423                                bb_perror_msg_and_die("socket6");
424                            }
425                            if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) {
426                                perror("SIOGIFINDEX");
427                                ++goterr;
428                                continue;
429                            }
430                            ifr6.ifr6_ifindex = ifr.ifr_ifindex;
431                            ifr6.ifr6_prefixlen = prefix_len;
432                            if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) {
433                                perror(a1op->name);
434                                ++goterr;
435                            }
436                            continue;
437#endif
438                        } else if (inet_aton(host, &sai.sin_addr) == 0) {
439                            /* It's not a dotted quad. */
440                            struct hostent *hp;
441                            if ((hp = gethostbyname(host)) == (struct hostent *)NULL) {
442                                ++goterr;
443                                continue;
444                            }
445                            memcpy((char *) &sai.sin_addr, (char *) hp->h_addr_list[0],
446                            sizeof(struct in_addr));
447                        }
448#ifdef CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS
449                        if (mask & A_HOSTNAME) {
450                            sai_hostname = sai.sin_addr.s_addr;
451                        }
452                        if (mask & A_NETMASK) {
453                            sai_netmask = sai.sin_addr.s_addr;
454                        }
455#endif
456                        p = (char *) &sai;
457#ifdef CONFIG_FEATURE_IFCONFIG_HW
458                    } else {    /* A_CAST_HOST_COPY_IN_ETHER */
459                        /* This is the "hw" arg case. */
460                        if (strcmp("ether", *argv) || (*++argv == NULL)) {
461                            bb_show_usage();
462                        }
463                        safe_strncpy(host, *argv, (sizeof host));
464                        if (in_ether(host, &sa)) {
465                            bb_error_msg("invalid hw-addr %s", host);
466                            ++goterr;
467                            continue;
468                        }
469                        p = (char *) &sa;
470                    }
471#endif
472                    memcpy((((char *) (&ifr)) + a1op->ifr_offset),
473                           p, sizeof(struct sockaddr));
474                } else {
475                    unsigned long i = strtoul(*argv, NULL, 0);
476
477                    p = ((char *) (&ifr)) + a1op->ifr_offset;
478#ifdef CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
479                    if (mask & A_MAP_TYPE) {
480                        if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
481                            ++goterr;
482                            continue;
483                        }
484                        if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
485                            *((unsigned char *) p) = i;
486                        } else if (mask & A_MAP_USHORT) {
487                            *((unsigned short *) p) = i;
488                        } else {
489                            *((unsigned long *) p) = i;
490                        }
491                    } else
492#endif
493                    if (mask & A_CAST_CHAR_PTR) {
494                        *((caddr_t *) p) = (caddr_t) i;
495                    } else {    /* A_CAST_INT */
496                        *((int *) p) = i;
497                    }
498                }
499
500                if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
501                    perror(a1op->name);
502                    ++goterr;
503                    continue;
504                }
505#ifdef QUESTIONABLE_ALIAS_CASE
506                if (mask & A_COLON_CHK) {
507                    /*
508                     * Don't do the set_flag() if the address is an alias with
509                     * a - at the end, since it's deleted already! - Roman
510                     *
511                     * Should really use regex.h here, not sure though how well
512                     * it'll go with the cross-platform support etc.
513                     */
514                    char *ptr;
515                    short int found_colon = 0;
516
517                    for (ptr = ifr.ifr_name; *ptr; ptr++) {
518                        if (*ptr == ':') {
519                            found_colon++;
520                        }
521                    }
522
523                    if (found_colon && *(ptr - 1) == '-') {
524                        continue;
525                    }
526                }
527#endif
528            }
529            if (!(mask & A_SET_AFTER)) {
530                continue;
531            }
532            mask = N_SET;
533        }
534
535        if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
536            perror("SIOCGIFFLAGS");
537            ++goterr;
538        } else {
539            selector = op->selector;
540            if (mask & SET_MASK) {
541                ifr.ifr_flags |= selector;
542            } else {
543                ifr.ifr_flags &= ~selector;
544            }
545            if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
546                perror("SIOCSIFFLAGS");
547                ++goterr;
548            }
549        }
550      LOOP:
551        continue;
552    }                   /* end of while-loop */
553
554    if (ENABLE_FEATURE_CLEAN_UP) close(sockfd);
555    return goterr;
556}
557
558#ifdef CONFIG_FEATURE_IFCONFIG_HW
559/* Input an Ethernet address and convert to binary. */
560static int in_ether(char *bufp, struct sockaddr *sap)
561{
562    char *ptr;
563    int i, j;
564    unsigned char val;
565    unsigned char c;
566
567    sap->sa_family = ARPHRD_ETHER;
568    ptr = sap->sa_data;
569
570    i = 0;
571    do {
572        j = val = 0;
573
574        /* We might get a semicolon here - not required. */
575        if (i && (*bufp == ':')) {
576            bufp++;
577        }
578
579        do {
580            c = *bufp;
581            if (((unsigned char)(c - '0')) <= 9) {
582                c -= '0';
583            } else if (((unsigned char)((c|0x20) - 'a')) <= 5) {
584                c = (c|0x20) - ('a'-10);
585            } else if (j && (c == ':' || c == 0)) {
586                break;
587            } else {
588                return -1;
589            }
590            ++bufp;
591            val <<= 4;
592            val += c;
593        } while (++j < 2);
594        *ptr++ = val;
595    } while (++i < ETH_ALEN);
596
597    return (int) (*bufp);   /* Error if we don't end at end of string. */
598}
599#endif
Note: See TracBrowser for help on using the repository browser.