15 |
* that either displays or sets the characteristics of |
* that either displays or sets the characteristics of |
16 |
* one or more of the system's networking interfaces. |
* one or more of the system's networking interfaces. |
17 |
* |
* |
|
* Version: $Id: interface.c,v 1.1 2007-09-01 22:43:53 niro Exp $ |
|
18 |
* |
* |
19 |
* Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> |
* Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> |
20 |
* and others. Copyright 1993 MicroWalt Corporation |
* and others. Copyright 1993 MicroWalt Corporation |
31 |
* (default AF was wrong) |
* (default AF was wrong) |
32 |
*/ |
*/ |
33 |
|
|
|
#include "inet_common.h" |
|
|
#include <stdio.h> |
|
|
#include <errno.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <unistd.h> |
|
|
#include <fcntl.h> |
|
|
#include <ctype.h> |
|
|
#include <sys/ioctl.h> |
|
|
#include <sys/types.h> |
|
34 |
#include <net/if.h> |
#include <net/if.h> |
35 |
#include <net/if_arp.h> |
#include <net/if_arp.h> |
36 |
#include "busybox.h" |
#include "inet_common.h" |
37 |
|
#include "libbb.h" |
38 |
|
|
39 |
|
|
40 |
|
#if ENABLE_FEATURE_HWIB |
41 |
|
/* #include <linux/if_infiniband.h> */ |
42 |
|
#undef INFINIBAND_ALEN |
43 |
|
#define INFINIBAND_ALEN 20 |
44 |
|
#endif |
45 |
|
|
46 |
#ifdef CONFIG_FEATURE_IPV6 |
#if ENABLE_FEATURE_IPV6 |
47 |
# define HAVE_AFINET6 1 |
# define HAVE_AFINET6 1 |
48 |
#else |
#else |
49 |
# undef HAVE_AFINET6 |
# undef HAVE_AFINET6 |
89 |
#endif |
#endif |
90 |
|
|
91 |
/* Display an Internet socket address. */ |
/* Display an Internet socket address. */ |
92 |
static char *INET_sprint(struct sockaddr *sap, int numeric) |
static const char* FAST_FUNC INET_sprint(struct sockaddr *sap, int numeric) |
93 |
{ |
{ |
94 |
static char buff[128]; |
static char *buff; |
95 |
|
|
96 |
|
free(buff); |
97 |
if (sap->sa_family == 0xFFFF || sap->sa_family == 0) |
if (sap->sa_family == 0xFFFF || sap->sa_family == 0) |
98 |
return safe_strncpy(buff, "[NONE SET]", sizeof(buff)); |
return "[NONE SET]"; |
99 |
|
buff = INET_rresolve((struct sockaddr_in *) sap, numeric, 0xffffff00); |
|
if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, |
|
|
numeric, 0xffffff00) != 0) |
|
|
return NULL; |
|
|
|
|
100 |
return buff; |
return buff; |
101 |
} |
} |
102 |
|
|
103 |
|
#ifdef UNUSED_AND_BUGGY |
104 |
static int INET_getsock(char *bufp, struct sockaddr *sap) |
static int INET_getsock(char *bufp, struct sockaddr *sap) |
105 |
{ |
{ |
106 |
char *sp = bufp, *bp; |
char *sp = bufp, *bp; |
141 |
|
|
142 |
return (sp - bufp); |
return (sp - bufp); |
143 |
} |
} |
144 |
|
#endif |
145 |
|
|
146 |
static int INET_input(int type, char *bufp, struct sockaddr *sap) |
static int FAST_FUNC INET_input(/*int type,*/ const char *bufp, struct sockaddr *sap) |
147 |
{ |
{ |
148 |
|
return INET_resolve(bufp, (struct sockaddr_in *) sap, 0); |
149 |
|
/* |
150 |
switch (type) { |
switch (type) { |
151 |
case 1: |
case 1: |
152 |
return (INET_getsock(bufp, sap)); |
return (INET_getsock(bufp, sap)); |
155 |
default: |
default: |
156 |
return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0)); |
return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0)); |
157 |
} |
} |
158 |
|
*/ |
159 |
} |
} |
160 |
|
|
161 |
static struct aftype inet_aftype = { |
static const struct aftype inet_aftype = { |
162 |
.name = "inet", |
.name = "inet", |
163 |
.title = "DARPA Internet", |
.title = "DARPA Internet", |
164 |
.af = AF_INET, |
.af = AF_INET, |
165 |
.alen = 4, |
.alen = 4, |
166 |
.sprint = INET_sprint, |
.sprint = INET_sprint, |
167 |
.input = INET_input, |
.input = INET_input, |
|
.fd = -1 |
|
168 |
}; |
}; |
169 |
|
|
170 |
#ifdef HAVE_AFINET6 |
#ifdef HAVE_AFINET6 |
171 |
|
|
172 |
/* Display an Internet socket address. */ |
/* Display an Internet socket address. */ |
173 |
/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */ |
/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */ |
174 |
static char *INET6_sprint(struct sockaddr *sap, int numeric) |
static const char* FAST_FUNC INET6_sprint(struct sockaddr *sap, int numeric) |
175 |
{ |
{ |
176 |
static char buff[128]; |
static char *buff; |
177 |
|
|
178 |
|
free(buff); |
179 |
if (sap->sa_family == 0xFFFF || sap->sa_family == 0) |
if (sap->sa_family == 0xFFFF || sap->sa_family == 0) |
180 |
return safe_strncpy(buff, "[NONE SET]", sizeof(buff)); |
return "[NONE SET]"; |
181 |
if (INET6_rresolve |
buff = INET6_rresolve((struct sockaddr_in6 *) sap, numeric); |
|
(buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0) |
|
|
return safe_strncpy(buff, "[UNKNOWN]", sizeof(buff)); |
|
182 |
return buff; |
return buff; |
183 |
} |
} |
184 |
|
|
185 |
|
#ifdef UNUSED |
186 |
static int INET6_getsock(char *bufp, struct sockaddr *sap) |
static int INET6_getsock(char *bufp, struct sockaddr *sap) |
187 |
{ |
{ |
188 |
struct sockaddr_in6 *sin6; |
struct sockaddr_in6 *sin6; |
196 |
|
|
197 |
return 16; /* ?;) */ |
return 16; /* ?;) */ |
198 |
} |
} |
199 |
|
#endif |
200 |
|
|
201 |
static int INET6_input(int type, char *bufp, struct sockaddr *sap) |
static int FAST_FUNC INET6_input(/*int type,*/ const char *bufp, struct sockaddr *sap) |
202 |
{ |
{ |
203 |
|
return INET6_resolve(bufp, (struct sockaddr_in6 *) sap); |
204 |
|
/* |
205 |
switch (type) { |
switch (type) { |
206 |
case 1: |
case 1: |
207 |
return (INET6_getsock(bufp, sap)); |
return (INET6_getsock(bufp, sap)); |
208 |
default: |
default: |
209 |
return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap)); |
return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap)); |
210 |
} |
} |
211 |
|
*/ |
212 |
} |
} |
213 |
|
|
214 |
static struct aftype inet6_aftype = { |
static const struct aftype inet6_aftype = { |
215 |
.name = "inet6", |
.name = "inet6", |
216 |
.title = "IPv6", |
.title = "IPv6", |
217 |
.af = AF_INET6, |
.af = AF_INET6, |
218 |
.alen = sizeof(struct in6_addr), |
.alen = sizeof(struct in6_addr), |
219 |
.sprint = INET6_sprint, |
.sprint = INET6_sprint, |
220 |
.input = INET6_input, |
.input = INET6_input, |
|
.fd = -1 |
|
221 |
}; |
}; |
222 |
|
|
223 |
#endif /* HAVE_AFINET6 */ |
#endif /* HAVE_AFINET6 */ |
224 |
|
|
225 |
/* Display an UNSPEC address. */ |
/* Display an UNSPEC address. */ |
226 |
static char *UNSPEC_print(unsigned char *ptr) |
static char* FAST_FUNC UNSPEC_print(unsigned char *ptr) |
227 |
{ |
{ |
228 |
static char buff[sizeof(struct sockaddr) * 3 + 1]; |
static char *buff; |
229 |
|
|
230 |
char *pos; |
char *pos; |
231 |
unsigned int i; |
unsigned int i; |
232 |
|
|
233 |
|
if (!buff) |
234 |
|
buff = xmalloc(sizeof(struct sockaddr) * 3 + 1); |
235 |
pos = buff; |
pos = buff; |
236 |
for (i = 0; i < sizeof(struct sockaddr); i++) { |
for (i = 0; i < sizeof(struct sockaddr); i++) { |
237 |
/* careful -- not every libc's sprintf returns # bytes written */ |
/* careful -- not every libc's sprintf returns # bytes written */ |
244 |
} |
} |
245 |
|
|
246 |
/* Display an UNSPEC socket address. */ |
/* Display an UNSPEC socket address. */ |
247 |
static char *UNSPEC_sprint(struct sockaddr *sap, int numeric) |
static const char* FAST_FUNC UNSPEC_sprint(struct sockaddr *sap, int numeric UNUSED_PARAM) |
248 |
{ |
{ |
|
static char buf[64]; |
|
|
|
|
249 |
if (sap->sa_family == 0xFFFF || sap->sa_family == 0) |
if (sap->sa_family == 0xFFFF || sap->sa_family == 0) |
250 |
return safe_strncpy(buf, "[NONE SET]", sizeof(buf)); |
return "[NONE SET]"; |
251 |
return UNSPEC_print((unsigned char *)sap->sa_data); |
return UNSPEC_print((unsigned char *)sap->sa_data); |
252 |
} |
} |
253 |
|
|
254 |
static struct aftype unspec_aftype = { |
static const struct aftype unspec_aftype = { |
255 |
"unspec", "UNSPEC", AF_UNSPEC, 0, |
.name = "unspec", |
256 |
UNSPEC_print, UNSPEC_sprint, NULL, NULL, |
.title = "UNSPEC", |
257 |
NULL, |
.af = AF_UNSPEC, |
258 |
|
.alen = 0, |
259 |
|
.print = UNSPEC_print, |
260 |
|
.sprint = UNSPEC_sprint, |
261 |
}; |
}; |
262 |
|
|
263 |
static struct aftype * const aftypes[] = { |
static const struct aftype *const aftypes[] = { |
264 |
&inet_aftype, |
&inet_aftype, |
265 |
#ifdef HAVE_AFINET6 |
#ifdef HAVE_AFINET6 |
266 |
&inet6_aftype, |
&inet6_aftype, |
270 |
}; |
}; |
271 |
|
|
272 |
/* Check our protocol family table for this family. */ |
/* Check our protocol family table for this family. */ |
273 |
struct aftype *get_aftype(const char *name) |
const struct aftype* FAST_FUNC get_aftype(const char *name) |
274 |
{ |
{ |
275 |
struct aftype * const *afp; |
const struct aftype *const *afp; |
276 |
|
|
277 |
afp = aftypes; |
afp = aftypes; |
278 |
while (*afp != NULL) { |
while (*afp != NULL) { |
284 |
} |
} |
285 |
|
|
286 |
/* Check our protocol family table for this family. */ |
/* Check our protocol family table for this family. */ |
287 |
static struct aftype *get_afntype(int af) |
static const struct aftype *get_afntype(int af) |
288 |
{ |
{ |
289 |
struct aftype * const *afp; |
const struct aftype *const *afp; |
290 |
|
|
291 |
afp = aftypes; |
afp = aftypes; |
292 |
while (*afp != NULL) { |
while (*afp != NULL) { |
297 |
return NULL; |
return NULL; |
298 |
} |
} |
299 |
|
|
|
/* Check our protocol family table for this family and return its socket */ |
|
|
static int get_socket_for_af(int af) |
|
|
{ |
|
|
struct aftype * const *afp; |
|
|
|
|
|
afp = aftypes; |
|
|
while (*afp != NULL) { |
|
|
if ((*afp)->af == af) |
|
|
return (*afp)->fd; |
|
|
afp++; |
|
|
} |
|
|
return -1; |
|
|
} |
|
|
|
|
300 |
struct user_net_device_stats { |
struct user_net_device_stats { |
301 |
unsigned long long rx_packets; /* total packets received */ |
unsigned long long rx_packets; /* total packets received */ |
302 |
unsigned long long tx_packets; /* total packets transmitted */ |
unsigned long long tx_packets; /* total packets transmitted */ |
328 |
|
|
329 |
struct interface { |
struct interface { |
330 |
struct interface *next, *prev; |
struct interface *next, *prev; |
331 |
char name[IFNAMSIZ]; /* interface name */ |
char name[IFNAMSIZ]; /* interface name */ |
332 |
short type; /* if type */ |
short type; /* if type */ |
333 |
short flags; /* various flags */ |
short flags; /* various flags */ |
334 |
int metric; /* routing metric */ |
int metric; /* routing metric */ |
335 |
int mtu; /* MTU value */ |
int mtu; /* MTU value */ |
336 |
int tx_queue_len; /* transmit queue length */ |
int tx_queue_len; /* transmit queue length */ |
337 |
struct ifmap map; /* hardware setup */ |
struct ifmap map; /* hardware setup */ |
338 |
struct sockaddr addr; /* IP address */ |
struct sockaddr addr; /* IP address */ |
339 |
struct sockaddr dstaddr; /* P-P IP address */ |
struct sockaddr dstaddr; /* P-P IP address */ |
340 |
struct sockaddr broadaddr; /* IP broadcast address */ |
struct sockaddr broadaddr; /* IP broadcast address */ |
341 |
struct sockaddr netmask; /* IP network mask */ |
struct sockaddr netmask; /* IP network mask */ |
342 |
int has_ip; |
int has_ip; |
343 |
char hwaddr[32]; /* HW address */ |
char hwaddr[32]; /* HW address */ |
344 |
int statistics_valid; |
int statistics_valid; |
345 |
struct user_net_device_stats stats; /* statistics */ |
struct user_net_device_stats stats; /* statistics */ |
346 |
int keepalive; /* keepalive value for SLIP */ |
int keepalive; /* keepalive value for SLIP */ |
347 |
int outfill; /* outfill value for SLIP */ |
int outfill; /* outfill value for SLIP */ |
348 |
}; |
}; |
349 |
|
|
350 |
|
|
351 |
int interface_opt_a; /* show all interfaces */ |
smallint interface_opt_a; /* show all interfaces */ |
352 |
|
|
353 |
static struct interface *int_list, *int_last; |
static struct interface *int_list, *int_last; |
|
static int skfd = -1; /* generic raw socket desc. */ |
|
|
|
|
|
|
|
|
static int sockets_open(int family) |
|
|
{ |
|
|
struct aftype * const *aft; |
|
|
int sfd = -1; |
|
|
static int force = -1; |
|
354 |
|
|
|
if (force < 0) { |
|
|
force = 0; |
|
|
if (get_linux_version_code() < KERNEL_VERSION(2,1,0)) |
|
|
force = 1; |
|
|
if (access("/proc/net", R_OK)) |
|
|
force = 1; |
|
|
} |
|
|
for (aft = aftypes; *aft; aft++) { |
|
|
struct aftype *af = *aft; |
|
|
int type = SOCK_DGRAM; |
|
|
|
|
|
if (af->af == AF_UNSPEC) |
|
|
continue; |
|
|
if (family && family != af->af) |
|
|
continue; |
|
|
if (af->fd != -1) { |
|
|
sfd = af->fd; |
|
|
continue; |
|
|
} |
|
|
/* Check some /proc file first to not stress kmod */ |
|
|
if (!family && !force && af->flag_file) { |
|
|
if (access(af->flag_file, R_OK)) |
|
|
continue; |
|
|
} |
|
|
af->fd = socket(af->af, type, 0); |
|
|
if (af->fd >= 0) |
|
|
sfd = af->fd; |
|
|
} |
|
|
if (sfd < 0) { |
|
|
bb_error_msg("no usable address families found"); |
|
|
} |
|
|
return sfd; |
|
|
} |
|
355 |
|
|
|
#ifdef CONFIG_FEATURE_CLEAN_UP |
|
|
static void sockets_close(void) |
|
|
{ |
|
|
struct aftype * const *aft; |
|
|
for (aft = aftypes; *aft != NULL; aft++) { |
|
|
struct aftype *af = *aft; |
|
|
if( af->fd != -1 ) { |
|
|
close(af->fd); |
|
|
af->fd = -1; |
|
|
} |
|
|
} |
|
|
} |
|
|
#endif |
|
356 |
#if 0 |
#if 0 |
357 |
/* like strcmp(), but knows about numbers */ |
/* like strcmp(), but knows about numbers */ |
358 |
except that the freshly added calls to xatoul() brf on ethernet aliases with |
except that the freshly added calls to xatoul() brf on ethernet aliases with |
395 |
} |
} |
396 |
|
|
397 |
new = xzalloc(sizeof(*new)); |
new = xzalloc(sizeof(*new)); |
398 |
safe_strncpy(new->name, name, IFNAMSIZ); |
strncpy(new->name, name, IFNAMSIZ); |
399 |
nextp = ife ? &ife->next : &int_list; |
nextp = ife ? &ife->next : &int_list; |
400 |
new->prev = ife; |
new->prev = ife; |
401 |
new->next = *nextp; |
new->next = *nextp; |
407 |
return new; |
return new; |
408 |
} |
} |
409 |
|
|
|
|
|
|
static int if_readconf(void) |
|
|
{ |
|
|
int numreqs = 30; |
|
|
struct ifconf ifc; |
|
|
struct ifreq *ifr; |
|
|
int n, err = -1; |
|
|
int skfd2; |
|
|
|
|
|
/* SIOCGIFCONF currently seems to only work properly on AF_INET sockets |
|
|
(as of 2.1.128) */ |
|
|
skfd2 = get_socket_for_af(AF_INET); |
|
|
if (skfd2 < 0) { |
|
|
bb_perror_msg(("warning: no inet socket available")); |
|
|
/* Try to soldier on with whatever socket we can get hold of. */ |
|
|
skfd2 = sockets_open(0); |
|
|
if (skfd2 < 0) |
|
|
return -1; |
|
|
} |
|
|
|
|
|
ifc.ifc_buf = NULL; |
|
|
for (;;) { |
|
|
ifc.ifc_len = sizeof(struct ifreq) * numreqs; |
|
|
ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len); |
|
|
|
|
|
if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) { |
|
|
perror("SIOCGIFCONF"); |
|
|
goto out; |
|
|
} |
|
|
if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) { |
|
|
/* assume it overflowed and try again */ |
|
|
numreqs += 10; |
|
|
continue; |
|
|
} |
|
|
break; |
|
|
} |
|
|
|
|
|
ifr = ifc.ifc_req; |
|
|
for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { |
|
|
add_interface(ifr->ifr_name); |
|
|
ifr++; |
|
|
} |
|
|
err = 0; |
|
|
|
|
|
out: |
|
|
free(ifc.ifc_buf); |
|
|
return err; |
|
|
} |
|
|
|
|
410 |
static char *get_name(char *name, char *p) |
static char *get_name(char *name, char *p) |
411 |
{ |
{ |
412 |
/* Extract <name> from nul-terminated p where p matches |
/* Extract <name> from nul-terminated p where p matches |
413 |
<name>: after leading whitespace. |
<name>: after leading whitespace. |
414 |
If match is not made, set name empty and return unchanged p */ |
If match is not made, set name empty and return unchanged p */ |
415 |
int namestart=0, nameend=0; |
int namestart = 0, nameend = 0; |
416 |
|
|
417 |
while (isspace(p[namestart])) |
while (isspace(p[namestart])) |
418 |
namestart++; |
namestart++; |
419 |
nameend=namestart; |
nameend = namestart; |
420 |
while (p[nameend] && p[nameend]!=':' && !isspace(p[nameend])) |
while (p[nameend] && p[nameend] != ':' && !isspace(p[nameend])) |
421 |
nameend++; |
nameend++; |
422 |
if (p[nameend]==':') { |
if (p[nameend] == ':') { |
423 |
if ((nameend-namestart)<IFNAMSIZ) { |
if ((nameend - namestart) < IFNAMSIZ) { |
424 |
memcpy(name,&p[namestart],nameend-namestart); |
memcpy(name, &p[namestart], nameend - namestart); |
425 |
name[nameend-namestart]='\0'; |
name[nameend - namestart] = '\0'; |
426 |
p=&p[nameend]; |
p = &p[nameend]; |
427 |
} else { |
} else { |
428 |
/* Interface name too large */ |
/* Interface name too large */ |
429 |
name[0]='\0'; |
name[0] = '\0'; |
430 |
} |
} |
431 |
} else { |
} else { |
432 |
/* trailing ':' not found - return empty */ |
/* trailing ':' not found - return empty */ |
433 |
name[0]='\0'; |
name[0] = '\0'; |
434 |
} |
} |
435 |
return p + 1; |
return p + 1; |
436 |
} |
} |
442 |
* old approach of multiple scanf occurrences with large numbers of |
* old approach of multiple scanf occurrences with large numbers of |
443 |
* args. */ |
* args. */ |
444 |
|
|
445 |
/* static const char * const ss_fmt[] = { */ |
/* static const char *const ss_fmt[] = { */ |
446 |
/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */ |
/* "%lln%llu%lu%lu%lu%lu%ln%ln%lln%llu%lu%lu%lu%lu%lu", */ |
447 |
/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */ |
/* "%llu%llu%lu%lu%lu%lu%ln%ln%llu%llu%lu%lu%lu%lu%lu", */ |
448 |
/* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */ |
/* "%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" */ |
450 |
|
|
451 |
/* Lie about the size of the int pointed to for %n. */ |
/* Lie about the size of the int pointed to for %n. */ |
452 |
#if INT_MAX == LONG_MAX |
#if INT_MAX == LONG_MAX |
453 |
static const char * const ss_fmt[] = { |
static const char *const ss_fmt[] = { |
454 |
"%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u", |
"%n%llu%u%u%u%u%n%n%n%llu%u%u%u%u%u", |
455 |
"%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u", |
"%llu%llu%u%u%u%u%n%n%llu%llu%u%u%u%u%u", |
456 |
"%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u" |
"%llu%llu%u%u%u%u%u%u%llu%llu%u%u%u%u%u%u" |
457 |
}; |
}; |
458 |
#else |
#else |
459 |
static const char * const ss_fmt[] = { |
static const char *const ss_fmt[] = { |
460 |
"%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu", |
"%n%llu%lu%lu%lu%lu%n%n%n%llu%lu%lu%lu%lu%lu", |
461 |
"%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu", |
"%llu%llu%lu%lu%lu%lu%n%n%llu%llu%lu%lu%lu%lu%lu", |
462 |
"%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" |
"%llu%llu%lu%lu%lu%lu%lu%lu%llu%llu%lu%lu%lu%lu%lu%lu" |
498 |
} |
} |
499 |
} |
} |
500 |
|
|
501 |
static inline int procnetdev_version(char *buf) |
static int procnetdev_version(char *buf) |
502 |
{ |
{ |
503 |
if (strstr(buf, "compressed")) |
if (strstr(buf, "compressed")) |
504 |
return 2; |
return 2; |
507 |
return 0; |
return 0; |
508 |
} |
} |
509 |
|
|
510 |
|
static int if_readconf(void) |
511 |
|
{ |
512 |
|
int numreqs = 30; |
513 |
|
struct ifconf ifc; |
514 |
|
struct ifreq *ifr; |
515 |
|
int n, err = -1; |
516 |
|
int skfd; |
517 |
|
|
518 |
|
ifc.ifc_buf = NULL; |
519 |
|
|
520 |
|
/* SIOCGIFCONF currently seems to only work properly on AF_INET sockets |
521 |
|
(as of 2.1.128) */ |
522 |
|
skfd = socket(AF_INET, SOCK_DGRAM, 0); |
523 |
|
if (skfd < 0) { |
524 |
|
bb_perror_msg("error: no inet socket available"); |
525 |
|
return -1; |
526 |
|
} |
527 |
|
|
528 |
|
for (;;) { |
529 |
|
ifc.ifc_len = sizeof(struct ifreq) * numreqs; |
530 |
|
ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len); |
531 |
|
|
532 |
|
if (ioctl_or_warn(skfd, SIOCGIFCONF, &ifc) < 0) { |
533 |
|
goto out; |
534 |
|
} |
535 |
|
if (ifc.ifc_len == (int)(sizeof(struct ifreq) * numreqs)) { |
536 |
|
/* assume it overflowed and try again */ |
537 |
|
numreqs += 10; |
538 |
|
continue; |
539 |
|
} |
540 |
|
break; |
541 |
|
} |
542 |
|
|
543 |
|
ifr = ifc.ifc_req; |
544 |
|
for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { |
545 |
|
add_interface(ifr->ifr_name); |
546 |
|
ifr++; |
547 |
|
} |
548 |
|
err = 0; |
549 |
|
|
550 |
|
out: |
551 |
|
close(skfd); |
552 |
|
free(ifc.ifc_buf); |
553 |
|
return err; |
554 |
|
} |
555 |
|
|
556 |
static int if_readlist_proc(char *target) |
static int if_readlist_proc(char *target) |
557 |
{ |
{ |
558 |
static int proc_read; |
static smallint proc_read; |
559 |
|
|
560 |
FILE *fh; |
FILE *fh; |
561 |
char buf[512]; |
char buf[512]; |
562 |
struct interface *ife; |
struct interface *ife; |
567 |
if (!target) |
if (!target) |
568 |
proc_read = 1; |
proc_read = 1; |
569 |
|
|
570 |
fh = fopen(_PATH_PROCNET_DEV, "r"); |
fh = fopen_or_warn(_PATH_PROCNET_DEV, "r"); |
571 |
if (!fh) { |
if (!fh) { |
|
bb_perror_msg("warning: cannot open %s, limiting output", _PATH_PROCNET_DEV); |
|
572 |
return if_readconf(); |
return if_readconf(); |
573 |
} |
} |
574 |
fgets(buf, sizeof buf, fh); /* eat line */ |
fgets(buf, sizeof buf, fh); /* eat line */ |
588 |
break; |
break; |
589 |
} |
} |
590 |
if (ferror(fh)) { |
if (ferror(fh)) { |
591 |
perror(_PATH_PROCNET_DEV); |
bb_perror_msg(_PATH_PROCNET_DEV); |
592 |
err = -1; |
err = -1; |
593 |
proc_read = 0; |
proc_read = 0; |
594 |
} |
} |
599 |
static int if_readlist(void) |
static int if_readlist(void) |
600 |
{ |
{ |
601 |
int err = if_readlist_proc(NULL); |
int err = if_readlist_proc(NULL); |
602 |
|
/* Needed in order to get ethN:M aliases */ |
603 |
if (!err) |
if (!err) |
604 |
err = if_readconf(); |
err = if_readconf(); |
605 |
return err; |
return err; |
606 |
} |
} |
607 |
|
|
|
static int for_all_interfaces(int (*doit) (struct interface *, void *), |
|
|
void *cookie) |
|
|
{ |
|
|
struct interface *ife; |
|
|
|
|
|
if (!int_list && (if_readlist() < 0)) |
|
|
return -1; |
|
|
for (ife = int_list; ife; ife = ife->next) { |
|
|
int err = doit(ife, cookie); |
|
|
|
|
|
if (err) |
|
|
return err; |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
608 |
/* Fetch the interface configuration from the kernel. */ |
/* Fetch the interface configuration from the kernel. */ |
609 |
static int if_fetch(struct interface *ife) |
static int if_fetch(struct interface *ife) |
610 |
{ |
{ |
611 |
struct ifreq ifr; |
struct ifreq ifr; |
|
int fd; |
|
612 |
char *ifname = ife->name; |
char *ifname = ife->name; |
613 |
|
int skfd; |
614 |
|
|
615 |
|
skfd = xsocket(AF_INET, SOCK_DGRAM, 0); |
616 |
|
|
617 |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
618 |
if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) |
if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) { |
619 |
|
close(skfd); |
620 |
return -1; |
return -1; |
621 |
|
} |
622 |
ife->flags = ifr.ifr_flags; |
ife->flags = ifr.ifr_flags; |
623 |
|
|
624 |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
625 |
if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) |
memset(ife->hwaddr, 0, 32); |
626 |
memset(ife->hwaddr, 0, 32); |
if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) |
|
else |
|
627 |
memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); |
memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); |
628 |
|
|
629 |
ife->type = ifr.ifr_hwaddr.sa_family; |
ife->type = ifr.ifr_hwaddr.sa_family; |
630 |
|
|
631 |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
632 |
if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) |
ife->metric = 0; |
633 |
ife->metric = 0; |
if (ioctl(skfd, SIOCGIFMETRIC, &ifr) >= 0) |
|
else |
|
634 |
ife->metric = ifr.ifr_metric; |
ife->metric = ifr.ifr_metric; |
635 |
|
|
636 |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
637 |
if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) |
ife->mtu = 0; |
638 |
ife->mtu = 0; |
if (ioctl(skfd, SIOCGIFMTU, &ifr) >= 0) |
|
else |
|
639 |
ife->mtu = ifr.ifr_mtu; |
ife->mtu = ifr.ifr_mtu; |
640 |
|
|
641 |
|
memset(&ife->map, 0, sizeof(struct ifmap)); |
642 |
#ifdef SIOCGIFMAP |
#ifdef SIOCGIFMAP |
643 |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
644 |
if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0) |
if (ioctl(skfd, SIOCGIFMAP, &ifr) == 0) |
645 |
ife->map = ifr.ifr_map; |
ife->map = ifr.ifr_map; |
|
else |
|
646 |
#endif |
#endif |
|
memset(&ife->map, 0, sizeof(struct ifmap)); |
|
647 |
|
|
648 |
#ifdef HAVE_TXQUEUELEN |
#ifdef HAVE_TXQUEUELEN |
649 |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
650 |
if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0) |
ife->tx_queue_len = -1; /* unknown value */ |
651 |
ife->tx_queue_len = -1; /* unknown value */ |
if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) >= 0) |
|
else |
|
652 |
ife->tx_queue_len = ifr.ifr_qlen; |
ife->tx_queue_len = ifr.ifr_qlen; |
653 |
#else |
#else |
654 |
ife->tx_queue_len = -1; /* unknown value */ |
ife->tx_queue_len = -1; /* unknown value */ |
655 |
#endif |
#endif |
656 |
|
|
657 |
/* IPv4 address? */ |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
658 |
fd = get_socket_for_af(AF_INET); |
ifr.ifr_addr.sa_family = AF_INET; |
659 |
if (fd >= 0) { |
memset(&ife->addr, 0, sizeof(struct sockaddr)); |
660 |
|
if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) { |
661 |
|
ife->has_ip = 1; |
662 |
|
ife->addr = ifr.ifr_addr; |
663 |
|
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
664 |
|
memset(&ife->dstaddr, 0, sizeof(struct sockaddr)); |
665 |
|
if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) >= 0) |
666 |
|
ife->dstaddr = ifr.ifr_dstaddr; |
667 |
|
|
668 |
|
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
669 |
|
memset(&ife->broadaddr, 0, sizeof(struct sockaddr)); |
670 |
|
if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) >= 0) |
671 |
|
ife->broadaddr = ifr.ifr_broadaddr; |
672 |
|
|
673 |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
674 |
ifr.ifr_addr.sa_family = AF_INET; |
memset(&ife->netmask, 0, sizeof(struct sockaddr)); |
675 |
if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { |
if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0) |
676 |
ife->has_ip = 1; |
ife->netmask = ifr.ifr_netmask; |
|
ife->addr = ifr.ifr_addr; |
|
|
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
|
|
if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0) |
|
|
memset(&ife->dstaddr, 0, sizeof(struct sockaddr)); |
|
|
else |
|
|
ife->dstaddr = ifr.ifr_dstaddr; |
|
|
|
|
|
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
|
|
if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) |
|
|
memset(&ife->broadaddr, 0, sizeof(struct sockaddr)); |
|
|
else |
|
|
ife->broadaddr = ifr.ifr_broadaddr; |
|
|
|
|
|
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
|
|
if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) |
|
|
memset(&ife->netmask, 0, sizeof(struct sockaddr)); |
|
|
else |
|
|
ife->netmask = ifr.ifr_netmask; |
|
|
} else |
|
|
memset(&ife->addr, 0, sizeof(struct sockaddr)); |
|
677 |
} |
} |
678 |
|
|
679 |
|
close(skfd); |
680 |
return 0; |
return 0; |
681 |
} |
} |
682 |
|
|
|
|
|
683 |
static int do_if_fetch(struct interface *ife) |
static int do_if_fetch(struct interface *ife) |
684 |
{ |
{ |
685 |
if (if_fetch(ife) < 0) { |
if (if_fetch(ife) < 0) { |
686 |
char *errmsg; |
const char *errmsg; |
687 |
|
|
688 |
if (errno == ENODEV) { |
if (errno == ENODEV) { |
689 |
/* Give better error message for this case. */ |
/* Give better error message for this case. */ |
720 |
#endif |
#endif |
721 |
|
|
722 |
/* Display an Ethernet address in readable format. */ |
/* Display an Ethernet address in readable format. */ |
723 |
static char *pr_ether(unsigned char *ptr) |
static char* FAST_FUNC ether_print(unsigned char *ptr) |
724 |
{ |
{ |
725 |
static char buff[64]; |
static char *buff; |
726 |
|
|
727 |
snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X", |
free(buff); |
728 |
|
buff = xasprintf("%02X:%02X:%02X:%02X:%02X:%02X", |
729 |
(ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), |
(ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), |
730 |
(ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377) |
(ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377) |
731 |
); |
); |
732 |
return buff; |
return buff; |
733 |
} |
} |
734 |
|
|
735 |
static int in_ether(char *bufp, struct sockaddr *sap); |
static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap); |
736 |
|
|
737 |
static struct hwtype ether_hwtype = { |
static const struct hwtype ether_hwtype = { |
738 |
.name = "ether", |
.name = "ether", |
739 |
.title = "Ethernet", |
.title = "Ethernet", |
740 |
.type = ARPHRD_ETHER, |
.type = ARPHRD_ETHER, |
741 |
.alen = ETH_ALEN, |
.alen = ETH_ALEN, |
742 |
.print = pr_ether, |
.print = ether_print, |
743 |
.input = in_ether |
.input = ether_input |
744 |
}; |
}; |
745 |
|
|
746 |
static unsigned hexchar2int(char c) |
static unsigned hexchar2int(char c) |
754 |
} |
} |
755 |
|
|
756 |
/* Input an Ethernet address and convert to binary. */ |
/* Input an Ethernet address and convert to binary. */ |
757 |
static int in_ether(char *bufp, struct sockaddr *sap) |
static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap) |
758 |
{ |
{ |
759 |
unsigned char *ptr; |
unsigned char *ptr; |
760 |
char c, *orig; |
char c; |
761 |
int i; |
int i; |
762 |
unsigned val; |
unsigned val; |
763 |
|
|
764 |
sap->sa_family = ether_hwtype.type; |
sap->sa_family = ether_hwtype.type; |
765 |
ptr = sap->sa_data; |
ptr = (unsigned char*) sap->sa_data; |
766 |
|
|
767 |
i = 0; |
i = 0; |
|
orig = bufp; |
|
768 |
while ((*bufp != '\0') && (i < ETH_ALEN)) { |
while ((*bufp != '\0') && (i < ETH_ALEN)) { |
769 |
val = hexchar2int(*bufp++) * 0x10; |
val = hexchar2int(*bufp++) * 0x10; |
770 |
if (val > 0xff) { |
if (val > 0xff) { |
802 |
.type = ARPHRD_PPP |
.type = ARPHRD_PPP |
803 |
}; |
}; |
804 |
|
|
805 |
#ifdef CONFIG_FEATURE_IPV6 |
#if ENABLE_FEATURE_IPV6 |
806 |
static const struct hwtype sit_hwtype = { |
static const struct hwtype sit_hwtype = { |
807 |
.name = "sit", |
.name = "sit", |
808 |
.title = "IPv6-in-IPv4", |
.title = "IPv6-in-IPv4", |
809 |
.type = ARPHRD_SIT, |
.type = ARPHRD_SIT, |
810 |
.print = UNSPEC_print, |
.print = UNSPEC_print, |
811 |
.suppress_null_addr = 1 |
.suppress_null_addr = 1 |
812 |
} ; |
}; |
813 |
|
#endif |
814 |
|
#if ENABLE_FEATURE_HWIB |
815 |
|
static const struct hwtype ib_hwtype = { |
816 |
|
.name = "infiniband", |
817 |
|
.title = "InfiniBand", |
818 |
|
.type = ARPHRD_INFINIBAND, |
819 |
|
.alen = INFINIBAND_ALEN, |
820 |
|
.print = UNSPEC_print, |
821 |
|
.input = in_ib, |
822 |
|
}; |
823 |
#endif |
#endif |
824 |
|
|
825 |
static const struct hwtype * const hwtypes[] = { |
|
826 |
|
static const struct hwtype *const hwtypes[] = { |
827 |
&loop_hwtype, |
&loop_hwtype, |
828 |
ðer_hwtype, |
ðer_hwtype, |
829 |
&ppp_hwtype, |
&ppp_hwtype, |
830 |
&unspec_hwtype, |
&unspec_hwtype, |
831 |
#ifdef CONFIG_FEATURE_IPV6 |
#if ENABLE_FEATURE_IPV6 |
832 |
&sit_hwtype, |
&sit_hwtype, |
833 |
#endif |
#endif |
834 |
|
#if ENABLE_FEATURE_HWIB |
835 |
|
&ib_hwtype, |
836 |
|
#endif |
837 |
NULL |
NULL |
838 |
}; |
}; |
839 |
|
|
840 |
#ifdef IFF_PORTSEL |
#ifdef IFF_PORTSEL |
841 |
static const char * const if_port_text[] = { |
static const char *const if_port_text[] = { |
842 |
/* Keep in step with <linux/netdevice.h> */ |
/* Keep in step with <linux/netdevice.h> */ |
843 |
"unknown", |
"unknown", |
844 |
"10base2", |
"10base2", |
852 |
#endif |
#endif |
853 |
|
|
854 |
/* Check our hardware type table for this type. */ |
/* Check our hardware type table for this type. */ |
855 |
const struct hwtype *get_hwtype(const char *name) |
const struct hwtype* FAST_FUNC get_hwtype(const char *name) |
856 |
{ |
{ |
857 |
const struct hwtype * const *hwp; |
const struct hwtype *const *hwp; |
858 |
|
|
859 |
hwp = hwtypes; |
hwp = hwtypes; |
860 |
while (*hwp != NULL) { |
while (*hwp != NULL) { |
866 |
} |
} |
867 |
|
|
868 |
/* Check our hardware type table for this type. */ |
/* Check our hardware type table for this type. */ |
869 |
const struct hwtype *get_hwntype(int type) |
const struct hwtype* FAST_FUNC get_hwntype(int type) |
870 |
{ |
{ |
871 |
const struct hwtype * const *hwp; |
const struct hwtype *const *hwp; |
872 |
|
|
873 |
hwp = hwtypes; |
hwp = hwtypes; |
874 |
while (*hwp != NULL) { |
while (*hwp != NULL) { |
882 |
/* return 1 if address is all zeros */ |
/* return 1 if address is all zeros */ |
883 |
static int hw_null_address(const struct hwtype *hw, void *ap) |
static int hw_null_address(const struct hwtype *hw, void *ap) |
884 |
{ |
{ |
885 |
unsigned int i; |
int i; |
886 |
unsigned char *address = (unsigned char *) ap; |
unsigned char *address = (unsigned char *) ap; |
887 |
|
|
888 |
for (i = 0; i < hw->alen; i++) |
for (i = 0; i < hw->alen; i++) |
891 |
return 1; |
return 1; |
892 |
} |
} |
893 |
|
|
894 |
static const char TRext[] = "\0\0\0Ki\0Mi\0Gi\0Ti"; |
static const char TRext[] ALIGN1 = "\0\0\0Ki\0Mi\0Gi\0Ti"; |
895 |
|
|
896 |
static void print_bytes_scaled(unsigned long long ull, const char *end) |
static void print_bytes_scaled(unsigned long long ull, const char *end) |
897 |
{ |
{ |
916 |
printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end); |
printf("X bytes:%llu (%llu.%u %sB)%s", ull, int_part, frac_part, ext, end); |
917 |
} |
} |
918 |
|
|
|
static const char * const ife_print_flags_strs[] = { |
|
|
"UP ", |
|
|
"BROADCAST ", |
|
|
"DEBUG ", |
|
|
"LOOPBACK ", |
|
|
"POINTOPOINT ", |
|
|
"NOTRAILERS ", |
|
|
"RUNNING ", |
|
|
"NOARP ", |
|
|
"PROMISC ", |
|
|
"ALLMULTI ", |
|
|
"SLAVE ", |
|
|
"MASTER ", |
|
|
"MULTICAST ", |
|
|
#ifdef HAVE_DYNAMIC |
|
|
"DYNAMIC " |
|
|
#endif |
|
|
}; |
|
|
|
|
|
static const unsigned short ife_print_flags_mask[] = { |
|
|
IFF_UP, |
|
|
IFF_BROADCAST, |
|
|
IFF_DEBUG, |
|
|
IFF_LOOPBACK, |
|
|
IFF_POINTOPOINT, |
|
|
IFF_NOTRAILERS, |
|
|
IFF_RUNNING, |
|
|
IFF_NOARP, |
|
|
IFF_PROMISC, |
|
|
IFF_ALLMULTI, |
|
|
IFF_SLAVE, |
|
|
IFF_MASTER, |
|
|
IFF_MULTICAST, |
|
|
#ifdef HAVE_DYNAMIC |
|
|
IFF_DYNAMIC |
|
|
#endif |
|
|
0 |
|
|
}; |
|
|
|
|
919 |
static void ife_print(struct interface *ptr) |
static void ife_print(struct interface *ptr) |
920 |
{ |
{ |
921 |
struct aftype *ap; |
const struct aftype *ap; |
922 |
const struct hwtype *hw; |
const struct hwtype *hw; |
923 |
int hf; |
int hf; |
924 |
int can_compress = 0; |
int can_compress = 0; |
957 |
printf("(auto)"); |
printf("(auto)"); |
958 |
} |
} |
959 |
#endif |
#endif |
960 |
puts(""); |
bb_putchar('\n'); |
961 |
|
|
962 |
if (ptr->has_ip) { |
if (ptr->has_ip) { |
963 |
printf(" %s addr:%s ", ap->name, |
printf(" %s addr:%s ", ap->name, |
990 |
#define IPV6_ADDR_MAPPED 0x1000U |
#define IPV6_ADDR_MAPPED 0x1000U |
991 |
#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */ |
#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */ |
992 |
|
|
993 |
if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { |
f = fopen_for_read(_PATH_PROCNET_IFINET6); |
994 |
|
if (f != NULL) { |
995 |
while (fscanf |
while (fscanf |
996 |
(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", |
(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n", |
997 |
addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], |
addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], |
998 |
addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, |
addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, |
999 |
&dad_status, devname) != EOF) { |
&dad_status, devname) != EOF |
1000 |
|
) { |
1001 |
if (!strcmp(devname, ptr->name)) { |
if (!strcmp(devname, ptr->name)) { |
1002 |
sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", |
sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", |
1003 |
addr6p[0], addr6p[1], addr6p[2], addr6p[3], |
addr6p[0], addr6p[1], addr6p[2], addr6p[3], |
1006 |
(struct sockaddr *) &sap.sin6_addr); |
(struct sockaddr *) &sap.sin6_addr); |
1007 |
sap.sin6_family = AF_INET6; |
sap.sin6_family = AF_INET6; |
1008 |
printf(" inet6 addr: %s/%d", |
printf(" inet6 addr: %s/%d", |
1009 |
inet6_aftype.sprint((struct sockaddr *) &sap, 1), |
INET6_sprint((struct sockaddr *) &sap, 1), |
1010 |
plen); |
plen); |
1011 |
printf(" Scope:"); |
printf(" Scope:"); |
1012 |
switch (scope & IPV6_ADDR_SCOPE_MASK) { |
switch (scope & IPV6_ADDR_SCOPE_MASK) { |
1013 |
case 0: |
case 0: |
1014 |
printf("Global"); |
puts("Global"); |
1015 |
break; |
break; |
1016 |
case IPV6_ADDR_LINKLOCAL: |
case IPV6_ADDR_LINKLOCAL: |
1017 |
printf("Link"); |
puts("Link"); |
1018 |
break; |
break; |
1019 |
case IPV6_ADDR_SITELOCAL: |
case IPV6_ADDR_SITELOCAL: |
1020 |
printf("Site"); |
puts("Site"); |
1021 |
break; |
break; |
1022 |
case IPV6_ADDR_COMPATv4: |
case IPV6_ADDR_COMPATv4: |
1023 |
printf("Compat"); |
puts("Compat"); |
1024 |
break; |
break; |
1025 |
case IPV6_ADDR_LOOPBACK: |
case IPV6_ADDR_LOOPBACK: |
1026 |
printf("Host"); |
puts("Host"); |
1027 |
break; |
break; |
1028 |
default: |
default: |
1029 |
printf("Unknown"); |
puts("Unknown"); |
1030 |
} |
} |
|
puts(""); |
|
1031 |
} |
} |
1032 |
} |
} |
1033 |
fclose(f); |
fclose(f); |
1040 |
if (ptr->flags == 0) { |
if (ptr->flags == 0) { |
1041 |
printf("[NO FLAGS] "); |
printf("[NO FLAGS] "); |
1042 |
} else { |
} else { |
1043 |
int i = 0; |
static const char ife_print_flags_strs[] ALIGN1 = |
1044 |
|
"UP\0" |
1045 |
|
"BROADCAST\0" |
1046 |
|
"DEBUG\0" |
1047 |
|
"LOOPBACK\0" |
1048 |
|
"POINTOPOINT\0" |
1049 |
|
"NOTRAILERS\0" |
1050 |
|
"RUNNING\0" |
1051 |
|
"NOARP\0" |
1052 |
|
"PROMISC\0" |
1053 |
|
"ALLMULTI\0" |
1054 |
|
"SLAVE\0" |
1055 |
|
"MASTER\0" |
1056 |
|
"MULTICAST\0" |
1057 |
|
#ifdef HAVE_DYNAMIC |
1058 |
|
"DYNAMIC\0" |
1059 |
|
#endif |
1060 |
|
; |
1061 |
|
static const unsigned short ife_print_flags_mask[] ALIGN2 = { |
1062 |
|
IFF_UP, |
1063 |
|
IFF_BROADCAST, |
1064 |
|
IFF_DEBUG, |
1065 |
|
IFF_LOOPBACK, |
1066 |
|
IFF_POINTOPOINT, |
1067 |
|
IFF_NOTRAILERS, |
1068 |
|
IFF_RUNNING, |
1069 |
|
IFF_NOARP, |
1070 |
|
IFF_PROMISC, |
1071 |
|
IFF_ALLMULTI, |
1072 |
|
IFF_SLAVE, |
1073 |
|
IFF_MASTER, |
1074 |
|
IFF_MULTICAST |
1075 |
|
#ifdef HAVE_DYNAMIC |
1076 |
|
,IFF_DYNAMIC |
1077 |
|
#endif |
1078 |
|
}; |
1079 |
|
const unsigned short *mask = ife_print_flags_mask; |
1080 |
|
const char *str = ife_print_flags_strs; |
1081 |
do { |
do { |
1082 |
if (ptr->flags & ife_print_flags_mask[i]) { |
if (ptr->flags & *mask) { |
1083 |
printf(ife_print_flags_strs[i]); |
printf("%s ", str); |
1084 |
} |
} |
1085 |
} while (ife_print_flags_mask[++i]); |
mask++; |
1086 |
|
str += strlen(str) + 1; |
1087 |
|
} while (*str); |
1088 |
} |
} |
1089 |
|
|
1090 |
/* DONT FORGET TO ADD THE FLAGS IN ife_print_short */ |
/* DONT FORGET TO ADD THE FLAGS IN ife_print_short */ |
1093 |
if (ptr->outfill || ptr->keepalive) |
if (ptr->outfill || ptr->keepalive) |
1094 |
printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive); |
printf(" Outfill:%d Keepalive:%d", ptr->outfill, ptr->keepalive); |
1095 |
#endif |
#endif |
1096 |
puts(""); |
bb_putchar('\n'); |
1097 |
|
|
1098 |
/* If needed, display the interface statistics. */ |
/* If needed, display the interface statistics. */ |
1099 |
|
|
1142 |
} |
} |
1143 |
if (ptr->map.dma) |
if (ptr->map.dma) |
1144 |
printf("DMA chan:%x ", ptr->map.dma); |
printf("DMA chan:%x ", ptr->map.dma); |
1145 |
puts(""); |
bb_putchar('\n'); |
1146 |
} |
} |
1147 |
puts(""); |
bb_putchar('\n'); |
1148 |
} |
} |
1149 |
|
|
1150 |
|
|
1151 |
static int do_if_print(struct interface *ife, void *cookie) |
static int do_if_print(struct interface *ife) /*, int *opt_a)*/ |
1152 |
{ |
{ |
|
int *opt_a = (int *) cookie; |
|
1153 |
int res; |
int res; |
1154 |
|
|
1155 |
res = do_if_fetch(ife); |
res = do_if_fetch(ife); |
1156 |
if (res >= 0) { |
if (res >= 0) { |
1157 |
if ((ife->flags & IFF_UP) || *opt_a) |
if ((ife->flags & IFF_UP) || interface_opt_a) |
1158 |
ife_print(ife); |
ife_print(ife); |
1159 |
} |
} |
1160 |
return res; |
return res; |
1170 |
return ife; |
return ife; |
1171 |
} |
} |
1172 |
|
|
1173 |
|
#ifdef UNUSED |
1174 |
|
static int for_all_interfaces(int (*doit) (struct interface *, void *), |
1175 |
|
void *cookie) |
1176 |
|
{ |
1177 |
|
struct interface *ife; |
1178 |
|
|
1179 |
|
if (!int_list && (if_readlist() < 0)) |
1180 |
|
return -1; |
1181 |
|
for (ife = int_list; ife; ife = ife->next) { |
1182 |
|
int err = doit(ife, cookie); |
1183 |
|
|
1184 |
|
if (err) |
1185 |
|
return err; |
1186 |
|
} |
1187 |
|
return 0; |
1188 |
|
} |
1189 |
|
#endif |
1190 |
|
|
1191 |
/* for ipv4 add/del modes */ |
/* for ipv4 add/del modes */ |
1192 |
static int if_print(char *ifname) |
static int if_print(char *ifname) |
1193 |
{ |
{ |
1194 |
|
struct interface *ife; |
1195 |
int res; |
int res; |
1196 |
|
|
1197 |
if (!ifname) { |
if (!ifname) { |
1198 |
res = for_all_interfaces(do_if_print, &interface_opt_a); |
/*res = for_all_interfaces(do_if_print, &interface_opt_a);*/ |
1199 |
} else { |
if (!int_list && (if_readlist() < 0)) |
1200 |
struct interface *ife; |
return -1; |
1201 |
|
for (ife = int_list; ife; ife = ife->next) { |
1202 |
ife = lookup_interface(ifname); |
int err = do_if_print(ife); /*, &interface_opt_a);*/ |
1203 |
res = do_if_fetch(ife); |
if (err) |
1204 |
if (res >= 0) |
return err; |
1205 |
ife_print(ife); |
} |
1206 |
|
return 0; |
1207 |
} |
} |
1208 |
|
ife = lookup_interface(ifname); |
1209 |
|
res = do_if_fetch(ife); |
1210 |
|
if (res >= 0) |
1211 |
|
ife_print(ife); |
1212 |
return res; |
return res; |
1213 |
} |
} |
1214 |
|
|
1215 |
int display_interfaces(char *ifname) |
#if ENABLE_FEATURE_HWIB |
1216 |
|
/* Input an Infiniband address and convert to binary. */ |
1217 |
|
int FAST_FUNC in_ib(const char *bufp, struct sockaddr *sap) |
1218 |
{ |
{ |
1219 |
int status; |
unsigned char *ptr; |
1220 |
|
char c; |
1221 |
|
const char *orig; |
1222 |
|
int i; |
1223 |
|
unsigned val; |
1224 |
|
|
1225 |
/* Create a channel to the NET kernel. */ |
sap->sa_family = ib_hwtype.type; |
1226 |
if ((skfd = sockets_open(0)) < 0) { |
ptr = (unsigned char *) sap->sa_data; |
1227 |
bb_perror_msg_and_die("socket"); |
|
1228 |
|
i = 0; |
1229 |
|
orig = bufp; |
1230 |
|
while ((*bufp != '\0') && (i < INFINIBAND_ALEN)) { |
1231 |
|
val = 0; |
1232 |
|
c = *bufp++; |
1233 |
|
if (isdigit(c)) |
1234 |
|
val = c - '0'; |
1235 |
|
else if (c >= 'a' && c <= 'f') |
1236 |
|
val = c - 'a' + 10; |
1237 |
|
else if (c >= 'A' && c <= 'F') |
1238 |
|
val = c - 'A' + 10; |
1239 |
|
else { |
1240 |
|
errno = EINVAL; |
1241 |
|
return -1; |
1242 |
|
} |
1243 |
|
val <<= 4; |
1244 |
|
c = *bufp; |
1245 |
|
if (isdigit(c)) |
1246 |
|
val |= c - '0'; |
1247 |
|
else if (c >= 'a' && c <= 'f') |
1248 |
|
val |= c - 'a' + 10; |
1249 |
|
else if (c >= 'A' && c <= 'F') |
1250 |
|
val |= c - 'A' + 10; |
1251 |
|
else if (c == ':' || c == 0) |
1252 |
|
val >>= 4; |
1253 |
|
else { |
1254 |
|
errno = EINVAL; |
1255 |
|
return -1; |
1256 |
|
} |
1257 |
|
if (c != 0) |
1258 |
|
bufp++; |
1259 |
|
*ptr++ = (unsigned char) (val & 0377); |
1260 |
|
i++; |
1261 |
|
|
1262 |
|
/* We might get a semicolon here - not required. */ |
1263 |
|
if (*bufp == ':') { |
1264 |
|
bufp++; |
1265 |
|
} |
1266 |
} |
} |
1267 |
|
#ifdef DEBUG |
1268 |
|
fprintf(stderr, "in_ib(%s): %s\n", orig, UNSPEC_print(sap->sa_data)); |
1269 |
|
#endif |
1270 |
|
return 0; |
1271 |
|
} |
1272 |
|
#endif |
1273 |
|
|
1274 |
|
|
1275 |
|
int FAST_FUNC display_interfaces(char *ifname) |
1276 |
|
{ |
1277 |
|
int status; |
1278 |
|
|
|
/* Do we have to show the current setup? */ |
|
1279 |
status = if_print(ifname); |
status = if_print(ifname); |
1280 |
#ifdef CONFIG_FEATURE_CLEAN_UP |
|
1281 |
sockets_close(); |
return (status < 0); /* status < 0 == 1 -- error */ |
|
#endif |
|
|
exit(status < 0); |
|
1282 |
} |
} |