3 * Similar to the standard Unix ifconfig, but with only the necessary
4 * parts for AF_INET, and without any printing of if info (for now).
6 * Bjorn Wesen, Axis Communications AB
9 * Authors of the original ifconfig was:
10 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
12 * This program is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU General
14 * Public License as published by the Free Software
15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version.
18 * $Id: ifconfig.c,v 1.4 2001/03/06 00:48:59 andersen Exp $
20 * Majorly hacked up by Larry Doolittle <ldoolitt@recycle.lbl.gov>
25 #include <sys/types.h>
29 #include <string.h> // strcmp and friends
30 #include <ctype.h> // isdigit and friends
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
36 #include <net/if_arp.h>
37 #include <linux/if_ether.h>
39 static int sockfd; /* socket fd we use to manipulate stuff with */
43 #define ioctl test_ioctl
44 char *saddr_to_a(struct sockaddr *s)
46 if (s->sa_family == ARPHRD_ETHER) {
48 sprintf(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
49 s->sa_data[0], s->sa_data[1], s->sa_data[2],
50 s->sa_data[3], s->sa_data[4], s->sa_data[5]);
52 } else if (s->sa_family == AF_INET) {
53 struct sockaddr_in *ss = (struct sockaddr_in *) s;
54 return inet_ntoa(ss->sin_addr);
60 int test_ioctl(int __fd, unsigned long int __request, void *param)
62 struct ifreq *i=(struct ifreq *)param;
63 printf("ioctl fd=%d, request=%ld\n", __fd, __request);
66 case SIOCGIFFLAGS: printf(" SIOCGIFFLAGS\n"); i->ifr_flags = 0; break;
67 case SIOCSIFFLAGS: printf(" SIOCSIFFLAGS, %x\n", i->ifr_flags); break;
68 case SIOCSIFMETRIC: printf(" SIOCSIFMETRIC, %d\n", i->ifr_metric); break;
69 case SIOCSIFMTU: printf(" SIOCSIFMTU, %d\n", i->ifr_mtu); break;
70 case SIOCSIFBRDADDR: printf(" SIOCSIFBRDADDR, %s\n", saddr_to_a(&(i->ifr_broadaddr))); break;
71 case SIOCSIFDSTADDR: printf(" SIOCSIFDSTADDR, %s\n", saddr_to_a(&(i->ifr_dstaddr ))); break;
72 case SIOCSIFNETMASK: printf(" SIOCSIFNETMASK, %s\n", saddr_to_a(&(i->ifr_netmask ))); break;
73 case SIOCSIFADDR: printf(" SIOCSIFADDR, %s\n", saddr_to_a(&(i->ifr_addr ))); break;
74 case SIOCSIFHWADDR: printf(" SIOCSIFHWADDR, %s\n", saddr_to_a(&(i->ifr_hwaddr ))); break; /* broken */
82 /* print usage and exit */
86 /* Set a certain interface flag. */
88 set_flag(char *ifname, short flag)
92 strcpy(ifr.ifr_name, ifname);
93 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
94 perror("SIOCGIFFLAGS");
97 strcpy(ifr.ifr_name, ifname);
98 ifr.ifr_flags |= flag;
99 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
100 perror("SIOCSIFFLAGS");
107 /* Clear a certain interface flag. */
109 clr_flag(char *ifname, short flag)
113 strcpy(ifr.ifr_name, ifname);
114 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
115 perror("SIOCGIFFLAGS");
118 strcpy(ifr.ifr_name, ifname);
119 ifr.ifr_flags &= ~flag;
120 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
121 perror("SIOCSIFFLAGS");
127 /* which element in struct ifreq to frob */
156 const static struct flag_map flag_table[] = {
157 {"arp", 0, IFF_NOARP, 0, 6},
158 {"trailers", 0, IFF_NOTRAILERS, 0, 6},
159 {"promisc", 0, IFF_PROMISC, 0, 8},
160 {"multicast", 0, IFF_MULTICAST, 0, 8},
161 {"allmulti", 0, IFF_ALLMULTI, 0, 8},
162 {"up", 0, (IFF_UP | IFF_RUNNING), 0, 2},
163 {"down", 0, IFF_UP, 0, 4},
164 {"metric", L_METRIC, 0, SIOCSIFMETRIC, 10},
165 {"mtu", L_MTU, 0, SIOCSIFMTU, 10},
166 #ifdef SIOCSKEEPALIVE
167 {"keepalive", L_DATA, 0, SIOCSKEEPALIVE, 10},
170 {"outfill", L_DATA, 0, SIOCSOUTFILL, 10},
172 {"broadcast", L_BROAD, IFF_BROADCAST, SIOCSIFBRDADDR, 14},
173 {"dstaddr", L_DEST, 0, SIOCSIFDSTADDR, 12},
174 {"netmask", L_MASK, 0, SIOCSIFNETMASK, 12},
175 {"pointopoint", L_DEST, IFF_POINTOPOINT, SIOCSIFDSTADDR, 14},
176 {"hw", L_HWAD, 0, SIOCSIFHWADDR, 14},
180 /* resolve XXX.YYY.ZZZ.QQQ -> binary */
183 INET_resolve(char *name, struct sockaddr_in *sin)
185 sin->sin_family = AF_INET;
188 /* Default is special, meaning 0.0.0.0. */
189 if (strcmp(name, "default")==0) {
190 sin->sin_addr.s_addr = INADDR_ANY;
193 /* Look to see if it's a dotted quad. */
194 if (inet_aton(name, &sin->sin_addr)) {
202 /* Input an Ethernet address and convert to binary. */
204 in_ether(char *bufp, struct sockaddr *sap)
211 sap->sa_family = ARPHRD_ETHER;
216 while ((*bufp != '\0') && (i < ETH_ALEN)) {
221 else if (c >= 'a' && c <= 'f')
223 else if (c >= 'A' && c <= 'F')
228 _("in_ether(%s): invalid ether address!"),
238 else if (c >= 'a' && c <= 'f')
240 else if (c >= 'A' && c <= 'F')
242 else if (c == ':' || c == 0)
247 _("in_ether(%s): invalid ether address!"),
255 *ptr++ = (unsigned char) (val & 0377);
258 /* optional colon already handled, don't swallow a second */
269 #ifdef BB_FEATURE_IFCONFIG_STATUS
270 extern int display_interfaces(void);
272 int display_interfaces(void)
278 int ifconfig_main(int argc, char **argv)
281 struct sockaddr_in sa;
285 /* int didnetmask = 0; special case input error detection no longer implemented */
287 const struct flag_map *ft;
293 return(display_interfaces());
296 /* Create a channel to the NET kernel. */
297 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
298 perror_msg_and_die("socket");
308 /* get interface name */
310 safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
312 /* Process the remaining arguments. */
313 while (*spp != (char *) NULL) {
321 for (i=0; i<(sizeof(flag_table)/sizeof(struct flag_map)); i++) {
322 if (strcmp(cmd, flag_table[i].name)==0) {
329 switch (ft->action+sense) {
334 goterr |= clr_flag(ifr.ifr_name, ft->flag);
339 goterr |= set_flag(ifr.ifr_name, ft->flag);
346 case L_METRIC: ifr.ifr_metric = a; break;
347 case L_MTU: ifr.ifr_mtu = a; break;
348 case L_DATA: ifr.ifr_data = (caddr_t) a; break;
349 default: error_msg_and_die("bugaboo");
352 if (ioctl(sockfd, ft->sflag, &ifr) < 0) {
353 perror(ft->name); /* imperfect */
359 if (ft->action+sense==10 && *spp == NULL) {
364 safe_strncpy(host, *spp, (sizeof host));
366 if (ft->frob == L_HWAD) {
367 ecode = in_ether(host, &ifr.ifr_hwaddr);
370 case L_BROAD: d = &ifr.ifr_broadaddr; break;
371 case L_DEST: d = &ifr.ifr_dstaddr; break;
372 case L_MASK: d = &ifr.ifr_netmask; break;
373 default: error_msg_and_die("bugaboo");
375 ecode = INET_resolve(host, (struct sockaddr_in *) d);
377 if (ecode < 0 || ioctl(sockfd, ft->sflag, &ifr) < 0) {
378 perror(ft->name); /* imperfect */
383 goterr |= set_flag(ifr.ifr_name, ft->flag);
388 } /* end of switch */
392 /* If the next argument is a valid hostname, assume OK. */
393 safe_strncpy(host, *spp, (sizeof host));
395 if (INET_resolve(host, &sa) < 0) {
398 memcpy((char *) &ifr.ifr_addr,
399 (char *) &sa, sizeof(struct sockaddr));
401 r = ioctl(sockfd, SIOCSIFADDR, &ifr);
404 perror("SIOCSIFADDR");
409 * Don't do the set_flag() if the address is an alias with a - at the
410 * end, since it's deleted already! - Roman
412 * Should really use regex.h here, not sure though how well it'll go
413 * with the cross-platform support etc.
417 short int found_colon = 0;
418 for (ptr = ifr.ifr_name; *ptr; ptr++ )
419 if (*ptr == ':') found_colon++;
421 if (!(found_colon && *(ptr - 1) == '-'))
422 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
427 } /* end of while-loop */