aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormjn3 <mjn3@69ca8d6d-28ef-0310-b511-8ec308f3f277>2001-03-08 22:57:00 +0000
committermjn3 <mjn3@69ca8d6d-28ef-0310-b511-8ec308f3f277>2001-03-08 22:57:00 +0000
commit6ad645ba63942ecf29bb672f8388cc46a3330cf4 (patch)
tree39fcfa0c5e367ba08c30d1a9bee2d02a6e033e75
parentdb5478e664ad21e08b07be471b4d89137a21c53a (diff)
downloadbusybox-w32-6ad645ba63942ecf29bb672f8388cc46a3330cf4.tar.gz
busybox-w32-6ad645ba63942ecf29bb672f8388cc46a3330cf4.tar.bz2
busybox-w32-6ad645ba63942ecf29bb672f8388cc46a3330cf4.zip
Improved port of ifconfig... smaller and with more features.
git-svn-id: svn://busybox.net/trunk/busybox@2014 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--Config.h9
-rw-r--r--ifconfig.c711
-rw-r--r--networking/ifconfig.c711
3 files changed, 773 insertions, 658 deletions
diff --git a/Config.h b/Config.h
index 9b9eec65c..8c6bfe3ec 100644
--- a/Config.h
+++ b/Config.h
@@ -287,6 +287,15 @@
287// Enable ifconfig status reporting output -- this feature adds 12k. 287// Enable ifconfig status reporting output -- this feature adds 12k.
288//#define BB_FEATURE_IFCONFIG_STATUS 288//#define BB_FEATURE_IFCONFIG_STATUS
289// 289//
290// Enable ifconfig slip-specific options "keepalive" and "outfill"
291//#define BB_FEATURE_IFCONFIG_SLIP
292//
293// Enable ifconfig options "mem_start", "io_addr", and "irq".
294//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
295//
296// Enable ifconfig option "hw". Currently works for only with "ether".
297//#define BB_FEATURE_IFCONFIG_HW
298//
290// Enable busybox --install [-s] 299// Enable busybox --install [-s]
291// to create links (or symlinks) for all the commands that are 300// to create links (or symlinks) for all the commands that are
292// compiled into the binary. (needs /proc filesystem) 301// compiled into the binary. (needs /proc filesystem)
diff --git a/ifconfig.c b/ifconfig.c
index 2a50a9605..f342ceede 100644
--- a/ifconfig.c
+++ b/ifconfig.c
@@ -15,19 +15,26 @@
15 * Foundation; either version 2 of the License, or (at 15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version. 16 * your option) any later version.
17 * 17 *
18 * $Id: ifconfig.c,v 1.4 2001/03/06 00:48:59 andersen Exp $ 18 * $Id: ifconfig.c,v 1.5 2001/03/08 22:57:00 mjn3 Exp $
19 * 19 *
20 * Majorly hacked up by Larry Doolittle <ldoolitt@recycle.lbl.gov> 20 */
21
22/*
23 * Heavily modified by Manuel Novoa III Mar 6, 2001
24 *
25 * From initial port to busybox, removed most of the redundancy by
26 * converting to a table-driven approach. Added several (optional)
27 * args missing from initial port.
21 * 28 *
29 * Still missing: media.
22 */ 30 */
23 31
24#include "busybox.h"
25#include <sys/types.h>
26#include <stdio.h> 32#include <stdio.h>
27#include <stdlib.h> 33#include <stdlib.h>
28#include <errno.h>
29#include <string.h> // strcmp and friends 34#include <string.h> // strcmp and friends
30#include <ctype.h> // isdigit and friends 35#include <ctype.h> // isdigit and friends
36#include <stddef.h> /* offsetof */
37#include <sys/types.h>
31#include <sys/socket.h> 38#include <sys/socket.h>
32#include <sys/ioctl.h> 39#include <sys/ioctl.h>
33#include <netinet/in.h> 40#include <netinet/in.h>
@@ -35,397 +42,443 @@
35#include <net/if.h> 42#include <net/if.h>
36#include <net/if_arp.h> 43#include <net/if_arp.h>
37#include <linux/if_ether.h> 44#include <linux/if_ether.h>
45#include "busybox.h"
38 46
39static int sockfd; /* socket fd we use to manipulate stuff with */ 47#ifdef BB_FEATURE_IFCONFIG_SLIP
48#include <linux/if_slip.h>
49#endif
40 50
41#define TESTME 0 51/* I don't know if this is needed for busybox or not. Anyone? */
42#if TESTME 52#define QUESTIONABLE_ALIAS_CASE
43#define ioctl test_ioctl
44char *saddr_to_a(struct sockaddr *s)
45{
46 if (s->sa_family == ARPHRD_ETHER) {
47 static char hw[18];
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]);
51 return hw;
52 } else if (s->sa_family == AF_INET) {
53 struct sockaddr_in *ss = (struct sockaddr_in *) s;
54 return inet_ntoa(ss->sin_addr);
55 } else {
56 return NULL;
57 }
58}
59 53
60int test_ioctl(int __fd, unsigned long int __request, void *param) 54
61{ 55/* Defines for glibc2.0 users. */
62 struct ifreq *i=(struct ifreq *)param; 56#ifndef SIOCSIFTXQLEN
63 printf("ioctl fd=%d, request=%ld\n", __fd, __request); 57#define SIOCSIFTXQLEN 0x8943
64 58#define SIOCGIFTXQLEN 0x8942
65 switch(__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 */
75 default:
76 }
77 return 0;
78}
79#endif 59#endif
80 60
61/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
62#ifndef ifr_qlen
63#define ifr_qlen ifr_ifru.ifru_mtu
64#endif
81 65
82/* print usage and exit */ 66#ifndef IFF_DYNAMIC
67#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
68#endif
83 69
84#define _(x) x 70/*
71 * Here are the bit masks for the "flags" member of struct options below.
72 * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
73 * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg.
74 */
75#define N_CLR 0x01
76#define M_CLR 0x02
77#define N_SET 0x04
78#define M_SET 0x08
79#define N_ARG 0x10
80#define M_ARG 0x20
81
82#define M_MASK (M_CLR | M_SET | M_ARG)
83#define N_MASK (N_CLR | N_SET | N_ARG)
84#define SET_MASK (N_SET | M_SET)
85#define CLR_MASK (N_CLR | M_CLR)
86#define SET_CLR_MASK (SET_MASK | CLR_MASK)
87#define ARG_MASK (M_ARG | N_ARG)
88
89/*
90 * Here are the bit masks for the "arg_flags" member of struct options below.
91 */
85 92
86/* Set a certain interface flag. */ 93/*
87static int 94 * cast type:
88set_flag(char *ifname, short flag) 95 * 00 int
89{ 96 * 01 char *
90 struct ifreq ifr; 97 * 02 HOST_COPY in_ether
91 98 * 03 HOST_COPY INET_resolve
92 strcpy(ifr.ifr_name, ifname); 99 */
93 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { 100#define A_CAST_TYPE 0x03
94 perror("SIOCGIFFLAGS"); 101/*
95 return -1; 102 * map type:
96 } 103 * 00 not a map type (mem_start, io_addr, irq)
97 strcpy(ifr.ifr_name, ifname); 104 * 04 memstart (unsigned long)
98 ifr.ifr_flags |= flag; 105 * 08 io_addr (unsigned short)
99 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { 106 * 0C irq (unsigned char)
100 perror("SIOCSIFFLAGS"); 107 */
101 return -1; 108#define A_MAP_TYPE 0x0C
102 } 109#define A_ARG_REQ 0x10 /* Set if an arg is required. */
103 return 0; 110#define A_NETMASK 0x20 /* Set if netmask (check for multiple sets). */
104} 111#define A_SET_AFTER 0x40 /* Set a flag at the end. */
112#define A_COLON_CHK 0x80 /* Is this needed? See below. */
113
114/*
115 * These defines are for dealing with the A_CAST_TYPE field.
116 */
117#define A_CAST_CHAR_PTR 0x01
118#define A_CAST_RESOLVE 0x01
119#define A_CAST_HOST_COPY 0x02
120#define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY
121#define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE)
122
123/*
124 * These defines are for dealing with the A_MAP_TYPE field.
125 */
126#define A_MAP_ULONG 0x04 /* memstart */
127#define A_MAP_USHORT 0x08 /* io_addr */
128#define A_MAP_UCHAR 0x0C /* irq */
105 129
130/*
131 * Define the bit masks signifying which operations to perform for each arg.
132 */
106 133
107/* Clear a certain interface flag. */ 134#define ARG_METRIC (A_ARG_REQ /*| A_CAST_INT*/)
108static int 135#define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/)
109clr_flag(char *ifname, short flag) 136#define ARG_TXQUEUELEN (A_ARG_REQ /*| A_CAST_INT*/)
110{ 137#define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG)
111 struct ifreq ifr; 138#define ARG_IO_ADDR (A_ARG_REQ | A_MAP_USHORT)
112 139#define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR)
113 strcpy(ifr.ifr_name, ifname); 140#define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
114 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { 141#define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
115 perror("SIOCGIFFLAGS"); 142#define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
116 return -1; 143#define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
117 } 144#define ARG_POINTOPOINT (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
118 strcpy(ifr.ifr_name, ifname); 145#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR)
119 ifr.ifr_flags &= ~flag; 146#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR)
120 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { 147#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
121 perror("SIOCSIFFLAGS"); 148
122 return -1; 149
123 } 150/*
124 return 0; 151 * Set up the tables. Warning! They must have corresponding order!
125} 152 */
126 153
127/* which element in struct ifreq to frob */ 154struct arg1opt {
128enum frob { 155 const char *name;
129 L_METRIC, 156 unsigned short selector;
130 L_MTU, 157 unsigned short ifr_offset;
131 L_DATA,
132 L_BROAD,
133 L_DEST,
134 L_MASK,
135 L_HWAD,
136}; 158};
137 159
138 160struct options {
139struct flag_map { 161 const char *name;
140 char *name; 162 const unsigned char flags;
141 enum frob frob; 163 const unsigned char arg_flags;
142 int flag; 164 const unsigned short selector;
143 int sflag;
144 int action;
145}; 165};
146 166
147/* action: 167#define ifreq_offsetof(x) offsetof(struct ifreq, x)
148 * 2 set 168
149 * 4 clear 169static const struct arg1opt Arg1Opt[] = {
150 * 6 set/clear 170 {"SIOCSIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric)},
151 * 8 clear/set 171 {"SIOCSIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu)},
152 * 10 numeric 172 {"SIOCSIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen)},
153 * 12 address 173 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
154 * 14 address/clear 174 {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
155 */ 175 {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
156const static struct flag_map flag_table[] = { 176#ifdef BB_FEATURE_IFCONFIG_HW
157 {"arp", 0, IFF_NOARP, 0, 6}, 177 {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)},
158 {"trailers", 0, IFF_NOTRAILERS, 0, 6}, 178#endif
159 {"promisc", 0, IFF_PROMISC, 0, 8}, 179 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
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 180#ifdef SIOCSKEEPALIVE
167 {"keepalive", L_DATA, 0, SIOCSKEEPALIVE, 10}, 181 {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},
168#endif 182#endif
169#ifdef SIOCSOUTFILL 183#ifdef SIOCSOUTFILL
170 {"outfill", L_DATA, 0, SIOCSOUTFILL, 10}, 184 {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)},
185#endif
186#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
187 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)},
188 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)},
189 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)},
171#endif 190#endif
172 {"broadcast", L_BROAD, IFF_BROADCAST, SIOCSIFBRDADDR, 14}, 191 /* Last entry if for unmatched (possibly hostname) arg. */
173 {"dstaddr", L_DEST, 0, SIOCSIFDSTADDR, 12}, 192 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)},
174 {"netmask", L_MASK, 0, SIOCSIFNETMASK, 12},
175 {"pointopoint", L_DEST, IFF_POINTOPOINT, SIOCSIFDSTADDR, 14},
176 {"hw", L_HWAD, 0, SIOCSIFHWADDR, 14},
177}; 193};
178 194
179 195static const struct options OptArray[] = {
180/* resolve XXX.YYY.ZZZ.QQQ -> binary */ 196 {"metric", N_ARG, ARG_METRIC, 0},
181 197 {"mtu", N_ARG, ARG_MTU, 0},
182static int 198 {"txqueuelen", N_ARG, ARG_TXQUEUELEN, 0},
183INET_resolve(char *name, struct sockaddr_in *sin) 199 {"dstaddr", N_ARG, ARG_DSTADDR, 0},
184{ 200 {"netmask", N_ARG, ARG_NETMASK, 0},
185 sin->sin_family = AF_INET; 201 {"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST},
186 sin->sin_port = 0; 202#ifdef BB_FEATURE_IFCONFIG_HW
187 203 {"hw", N_ARG, ARG_HW, 0},
188 /* Default is special, meaning 0.0.0.0. */
189 if (strcmp(name, "default")==0) {
190 sin->sin_addr.s_addr = INADDR_ANY;
191 return 1;
192 }
193 /* Look to see if it's a dotted quad. */
194 if (inet_aton(name, &sin->sin_addr)) {
195 return 0;
196 }
197 /* guess not.. */
198 errno = EINVAL;
199 return -1;
200}
201
202/* Input an Ethernet address and convert to binary. */
203static int
204in_ether(char *bufp, struct sockaddr *sap)
205{
206 unsigned char *ptr;
207 char c, *orig;
208 int i;
209 unsigned val;
210
211 sap->sa_family = ARPHRD_ETHER;
212 ptr = sap->sa_data;
213
214 i = 0;
215 orig = bufp;
216 while ((*bufp != '\0') && (i < ETH_ALEN)) {
217 val = 0;
218 c = *bufp++;
219 if (isdigit(c))
220 val = c - '0';
221 else if (c >= 'a' && c <= 'f')
222 val = c - 'a' + 10;
223 else if (c >= 'A' && c <= 'F')
224 val = c - 'A' + 10;
225 else {
226#ifdef DEBUG
227 error_msg(
228 _("in_ether(%s): invalid ether address!"),
229 orig);
230#endif 204#endif
231 errno = EINVAL; 205 {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
232 return -1; 206#ifdef SIOCSKEEPALIVE
233 } 207 {"keepalive", N_ARG, ARG_KEEPALIVE, 0},
234 val <<= 4;
235 c = *bufp;
236 if (isdigit(c))
237 val |= c - '0';
238 else if (c >= 'a' && c <= 'f')
239 val |= c - 'a' + 10;
240 else if (c >= 'A' && c <= 'F')
241 val |= c - 'A' + 10;
242 else if (c == ':' || c == 0)
243 val >>= 4;
244 else {
245#ifdef DEBUG
246 error_msg(
247 _("in_ether(%s): invalid ether address!"),
248 orig);
249#endif 208#endif
250 errno = EINVAL; 209#ifdef SIOCSOUTFILL
251 return -1; 210 {"outfill", N_ARG, ARG_OUTFILL, 0},
252 } 211#endif
253 if (c != 0) 212#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
254 bufp++; 213 {"mem_start", N_ARG, ARG_MEM_START, 0},
255 *ptr++ = (unsigned char) (val & 0377); 214 {"io_addr", N_ARG, ARG_IO_ADDR, 0},
256 i++; 215 {"irq", N_ARG, ARG_IRQ, 0},
257 216#endif
258 /* optional colon already handled, don't swallow a second */ 217 {"arp", N_CLR | M_SET, 0, IFF_NOARP},
259 } 218 {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS},
219 {"promisc", N_SET | M_CLR, 0, IFF_PROMISC},
220 {"multicast", N_SET | M_CLR, 0, IFF_MULTICAST},
221 {"allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI},
222 {"dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC},
223 {"up", N_SET , 0, (IFF_UP | IFF_RUNNING)},
224 {"down", N_CLR , 0, IFF_UP},
225 { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING)}
226};
260 227
261 if(i != ETH_ALEN) { 228/*
262 errno = EINVAL; 229 * A couple of prototypes.
263 return -1; 230 */
264 } 231
232#ifdef BB_FEATURE_IFCONFIG_HW
233static int in_ether(char *bufp, struct sockaddr *sap);
234#endif
265 235
266 return 0;
267}
268
269#ifdef BB_FEATURE_IFCONFIG_STATUS 236#ifdef BB_FEATURE_IFCONFIG_STATUS
270extern int display_interfaces(void); 237extern int display_interfaces(void);
271#else
272int display_interfaces(void)
273{
274 show_usage();
275}
276#endif 238#endif
277 239
240/*
241 * Our main function.
242 */
243
278int ifconfig_main(int argc, char **argv) 244int ifconfig_main(int argc, char **argv)
279{ 245{
280 struct ifreq ifr; 246 struct ifreq ifr;
281 struct sockaddr_in sa; 247 struct sockaddr_in sai;
282 char **spp, *cmd; 248#ifdef BB_FEATURE_IFCONFIG_HW
283 int goterr = 0; 249 struct sockaddr sa;
284 int r; 250#endif
285 /* int didnetmask = 0; special case input error detection no longer implemented */ 251 const struct arg1opt *a1op;
252 const struct options *op;
253 int sockfd; /* socket fd we use to manipulate stuff with */
254 int goterr;
255 int selector;
256 char *p;
286 char host[128]; 257 char host[128];
287 const struct flag_map *ft; 258 unsigned char mask;
288 int i, sense; 259 unsigned char did_flags;
289 int a, ecode; 260
290 struct sockaddr *d; 261 goterr = 0;
262 did_flags = 0;
291 263
292 if(argc < 2) { 264 if(argc < 2) {
265#ifdef BB_FEATURE_IFCONFIG_STATUS
293 return(display_interfaces()); 266 return(display_interfaces());
267#else
268 show_usage();
269#endif
294 } 270 }
295 271
296 /* Create a channel to the NET kernel. */ 272 /* Create a channel to the NET kernel. */
297 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 273 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
298 perror_msg_and_die("socket"); 274 perror("socket");
275 exit(1);
299 } 276 }
300 277
301 /* skip argv[0] */ 278 /* skip argv[0] */
302
303 argc--; 279 argc--;
304 argv++; 280 argv++;
305 281
306 spp = argv;
307
308 /* get interface name */ 282 /* get interface name */
309 283 safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
310 safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
311 284
312 /* Process the remaining arguments. */ 285 /* Process the remaining arguments. */
313 while (*spp != (char *) NULL) { 286 while (*++argv != (char *) NULL) {
314 cmd = *spp; 287 p = *argv;
315 sense=0; 288 mask = N_MASK;
316 if (*cmd=='-') { 289 if (*p == '-') { /* If the arg starts with '-'... */
317 sense=1; 290 ++p; /* advance past it and */
318 cmd++; 291 mask = M_MASK; /* set the appropriate mask. */
319 } 292 }
320 ft = NULL; 293 for (op = OptArray ; op->name ; op++) { /* Find table entry. */
321 for (i=0; i<(sizeof(flag_table)/sizeof(struct flag_map)); i++) { 294 if (!strcmp(p,op->name)) { /* If name matches... */
322 if (strcmp(cmd, flag_table[i].name)==0) { 295 if ((mask &= op->flags)) { /* set the mask and go. */
323 ft=flag_table+i; 296 goto FOUND_ARG;;
324 spp++; 297 }
325 break; 298 /* If we get here, there was a valid arg with an */
299 /* invalid '-' prefix. */
300 ++goterr;
301 goto LOOP;
326 } 302 }
327 } 303 }
328 if (ft) { 304
329 switch (ft->action+sense) { 305 /* We fell through, so treat as possible hostname. */
330 case 4: 306 a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
331 case 7: 307 mask = op->arg_flags;
332 case 8: 308 goto HOSTNAME;
333 case 15: 309
334 goterr |= clr_flag(ifr.ifr_name, ft->flag); 310 FOUND_ARG:
335 break; 311 if (mask & ARG_MASK) {
336 case 2: 312 mask = op->arg_flags;
337 case 6: 313 a1op = Arg1Opt + (op - OptArray);
338 case 9: 314 if (mask & A_NETMASK & did_flags) {
339 goterr |= set_flag(ifr.ifr_name, ft->flag); 315 show_usage();
340 break; 316 }
341 case 10: 317 if (*++argv == NULL) {
342 if (*spp == NULL) 318 if (mask & A_ARG_REQ) {
343 show_usage(); 319 show_usage();
344 a = atoi(*spp++); 320 } else {
345 switch (ft->frob) { 321 --argv;
346 case L_METRIC: ifr.ifr_metric = a; break; 322 mask &= A_SET_AFTER; /* just for broadcast */
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");
350 } 323 }
351 324 } else { /* got an arg so process it */
352 if (ioctl(sockfd, ft->sflag, &ifr) < 0) { 325 HOSTNAME:
353 perror(ft->name); /* imperfect */ 326 did_flags |= (mask & A_NETMASK);
354 goterr++; 327 if (mask & A_CAST_HOST_COPY) {
328#ifdef BB_FEATURE_IFCONFIG_HW
329 if (mask & A_CAST_RESOLVE) {
330#endif
331 safe_strncpy(host, *argv, (sizeof host));
332 sai.sin_family = AF_INET;
333 sai.sin_port = 0;
334 if (!strcmp(host, "default")) {
335 /* Default is special, meaning 0.0.0.0. */
336 sai.sin_addr.s_addr = INADDR_ANY;
337 } else if (inet_aton(host, &sai.sin_addr) == 0) {
338 /* It's not a dotted quad. */
339 ++goterr;
340 continue;
341 }
342 p = (char *) &sai;
343#ifdef BB_FEATURE_IFCONFIG_HW
344 } else { /* A_CAST_HOST_COPY_IN_ETHER */
345 /* This is the "hw" arg case. */
346 if (strcmp("ether", *argv) || (*++argv == NULL)) {
347 show_usage();
348 }
349 safe_strncpy(host, *argv, (sizeof host));
350 if (in_ether(host, &sa)) {
351 fprintf(stderr, "invalid hw-addr %s\n", host);
352 ++goterr;
353 continue;
354 }
355 p = (char *) &sa;
356 }
357#endif
358 memcpy((((char *)(&ifr)) + a1op->ifr_offset),
359 p, sizeof(struct sockaddr));
360 } else {
361 unsigned int i = strtoul(*argv,NULL,0);
362 p = ((char *)(&ifr)) + a1op->ifr_offset;
363#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
364 if (mask & A_MAP_TYPE) {
365 if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
366 ++goterr;
367 continue;
368 }
369 if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
370 *((unsigned char *) p) = i;
371 } else if (mask & A_MAP_USHORT) {
372 *((unsigned short *) p) = i;
373 } else {
374 *((unsigned long *) p) = i;
375 }
376 } else
377#endif
378 if (mask & A_CAST_CHAR_PTR) {
379 *((caddr_t *) p) = (caddr_t) i;
380 } else { /* A_CAST_INT */
381 *((int *) p) = i;
382 }
355 } 383 }
356 break; 384
357 case 12: 385 if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
358 case 14: 386 perror(a1op->name);
359 if (ft->action+sense==10 && *spp == NULL) { 387 ++goterr;
360 show_usage(); 388 continue;
361 break;
362 } 389 }
363 if (*spp != NULL) { 390
364 safe_strncpy(host, *spp, (sizeof host)); 391#ifdef QUESTIONABLE_ALIAS_CASE
365 spp++; 392 if (mask & A_COLON_CHK) {
366 if (ft->frob == L_HWAD) { 393 /*
367 ecode = in_ether(host, &ifr.ifr_hwaddr); 394 * Don't do the set_flag() if the address is an alias with
368 } else { 395 * a - at the end, since it's deleted already! - Roman
369 switch (ft->frob) { 396 *
370 case L_BROAD: d = &ifr.ifr_broadaddr; break; 397 * Should really use regex.h here, not sure though how well
371 case L_DEST: d = &ifr.ifr_dstaddr; break; 398 * it'll go with the cross-platform support etc.
372 case L_MASK: d = &ifr.ifr_netmask; break; 399 */
373 default: error_msg_and_die("bugaboo"); 400 char *ptr;
401 short int found_colon = 0;
402 for (ptr = ifr.ifr_name; *ptr; ptr++ ) {
403 if (*ptr == ':') {
404 found_colon++;
374 } 405 }
375 ecode = INET_resolve(host, (struct sockaddr_in *) d);
376 } 406 }
377 if (ecode < 0 || ioctl(sockfd, ft->sflag, &ifr) < 0) { 407
378 perror(ft->name); /* imperfect */ 408 if (found_colon && *(ptr - 1) == '-') {
379 goterr++; 409 continue;
380 } 410 }
381 } 411 }
382 if (ft->flag != 0) { 412#endif
383 goterr |= set_flag(ifr.ifr_name, ft->flag); 413 }
384 } 414 if (!(mask & A_SET_AFTER)) {
385 break; 415 continue;
386 default: 416 }
387 show_usage(); 417 mask = N_SET;
388 } /* end of switch */
389 continue;
390 } 418 }
391
392 /* If the next argument is a valid hostname, assume OK. */
393 safe_strncpy(host, *spp, (sizeof host));
394 419
395 if (INET_resolve(host, &sa) < 0) { 420 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
396 show_usage(); 421 perror("SIOCGIFFLAGS");
422 ++goterr;
423 } else {
424 selector = op->selector;
425 if (mask & SET_MASK) {
426 ifr.ifr_flags |= selector;
427 } else {
428 ifr.ifr_flags &= ~selector;
429 }
430 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
431 perror("SIOCSIFFLAGS");
432 ++goterr;
433 }
397 } 434 }
398 memcpy((char *) &ifr.ifr_addr, 435 LOOP:
399 (char *) &sa, sizeof(struct sockaddr)); 436 } /* end of while-loop */
400 437
401 r = ioctl(sockfd, SIOCSIFADDR, &ifr); 438 return goterr;
439}
402 440
403 if (r < 0) { 441#ifdef BB_FEATURE_IFCONFIG_HW
404 perror("SIOCSIFADDR"); 442/* Input an Ethernet address and convert to binary. */
405 goterr++; 443static int
406 } 444in_ether(char *bufp, struct sockaddr *sap)
445{
446 unsigned char *ptr;
447 int i, j;
448 unsigned char val;
449 unsigned char c;
450
451 sap->sa_family = ARPHRD_ETHER;
452 ptr = sap->sa_data;
453
454 for (i = 0 ; i < ETH_ALEN ; i++) {
455 val = 0;
407 456
408 /* 457 /* We might get a semicolon here - not required. */
409 * Don't do the set_flag() if the address is an alias with a - at the 458 if (i && (*bufp == ':')) {
410 * end, since it's deleted already! - Roman 459 bufp++;
411 *
412 * Should really use regex.h here, not sure though how well it'll go
413 * with the cross-platform support etc.
414 */
415 {
416 char *ptr;
417 short int found_colon = 0;
418 for (ptr = ifr.ifr_name; *ptr; ptr++ )
419 if (*ptr == ':') found_colon++;
420
421 if (!(found_colon && *(ptr - 1) == '-'))
422 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
423 } 460 }
424
425 spp++;
426 461
427 } /* end of while-loop */ 462 for (j=0 ; j<2 ; j++) {
463 c = *bufp;
464 if (c >= '0' && c <= '9') {
465 c -= '0';
466 } else if (c >= 'a' && c <= 'f') {
467 c -= ('a' + 10);
468 } else if (c >= 'A' && c <= 'F') {
469 c -= ('A' + 10);
470 } else if (j && (c == ':' || c == 0)) {
471 break;
472 } else {
473 return -1;
474 }
475 ++bufp;
476 val <<= 4;
477 val += c;
478 }
479 *ptr++ = val;
480 }
428 481
429 return goterr; 482 return (int) (*bufp); /* Error if we don't end at end of string. */
430} 483}
431 484#endif
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index 2a50a9605..f342ceede 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -15,19 +15,26 @@
15 * Foundation; either version 2 of the License, or (at 15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version. 16 * your option) any later version.
17 * 17 *
18 * $Id: ifconfig.c,v 1.4 2001/03/06 00:48:59 andersen Exp $ 18 * $Id: ifconfig.c,v 1.5 2001/03/08 22:57:00 mjn3 Exp $
19 * 19 *
20 * Majorly hacked up by Larry Doolittle <ldoolitt@recycle.lbl.gov> 20 */
21
22/*
23 * Heavily modified by Manuel Novoa III Mar 6, 2001
24 *
25 * From initial port to busybox, removed most of the redundancy by
26 * converting to a table-driven approach. Added several (optional)
27 * args missing from initial port.
21 * 28 *
29 * Still missing: media.
22 */ 30 */
23 31
24#include "busybox.h"
25#include <sys/types.h>
26#include <stdio.h> 32#include <stdio.h>
27#include <stdlib.h> 33#include <stdlib.h>
28#include <errno.h>
29#include <string.h> // strcmp and friends 34#include <string.h> // strcmp and friends
30#include <ctype.h> // isdigit and friends 35#include <ctype.h> // isdigit and friends
36#include <stddef.h> /* offsetof */
37#include <sys/types.h>
31#include <sys/socket.h> 38#include <sys/socket.h>
32#include <sys/ioctl.h> 39#include <sys/ioctl.h>
33#include <netinet/in.h> 40#include <netinet/in.h>
@@ -35,397 +42,443 @@
35#include <net/if.h> 42#include <net/if.h>
36#include <net/if_arp.h> 43#include <net/if_arp.h>
37#include <linux/if_ether.h> 44#include <linux/if_ether.h>
45#include "busybox.h"
38 46
39static int sockfd; /* socket fd we use to manipulate stuff with */ 47#ifdef BB_FEATURE_IFCONFIG_SLIP
48#include <linux/if_slip.h>
49#endif
40 50
41#define TESTME 0 51/* I don't know if this is needed for busybox or not. Anyone? */
42#if TESTME 52#define QUESTIONABLE_ALIAS_CASE
43#define ioctl test_ioctl
44char *saddr_to_a(struct sockaddr *s)
45{
46 if (s->sa_family == ARPHRD_ETHER) {
47 static char hw[18];
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]);
51 return hw;
52 } else if (s->sa_family == AF_INET) {
53 struct sockaddr_in *ss = (struct sockaddr_in *) s;
54 return inet_ntoa(ss->sin_addr);
55 } else {
56 return NULL;
57 }
58}
59 53
60int test_ioctl(int __fd, unsigned long int __request, void *param) 54
61{ 55/* Defines for glibc2.0 users. */
62 struct ifreq *i=(struct ifreq *)param; 56#ifndef SIOCSIFTXQLEN
63 printf("ioctl fd=%d, request=%ld\n", __fd, __request); 57#define SIOCSIFTXQLEN 0x8943
64 58#define SIOCGIFTXQLEN 0x8942
65 switch(__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 */
75 default:
76 }
77 return 0;
78}
79#endif 59#endif
80 60
61/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
62#ifndef ifr_qlen
63#define ifr_qlen ifr_ifru.ifru_mtu
64#endif
81 65
82/* print usage and exit */ 66#ifndef IFF_DYNAMIC
67#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
68#endif
83 69
84#define _(x) x 70/*
71 * Here are the bit masks for the "flags" member of struct options below.
72 * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
73 * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg.
74 */
75#define N_CLR 0x01
76#define M_CLR 0x02
77#define N_SET 0x04
78#define M_SET 0x08
79#define N_ARG 0x10
80#define M_ARG 0x20
81
82#define M_MASK (M_CLR | M_SET | M_ARG)
83#define N_MASK (N_CLR | N_SET | N_ARG)
84#define SET_MASK (N_SET | M_SET)
85#define CLR_MASK (N_CLR | M_CLR)
86#define SET_CLR_MASK (SET_MASK | CLR_MASK)
87#define ARG_MASK (M_ARG | N_ARG)
88
89/*
90 * Here are the bit masks for the "arg_flags" member of struct options below.
91 */
85 92
86/* Set a certain interface flag. */ 93/*
87static int 94 * cast type:
88set_flag(char *ifname, short flag) 95 * 00 int
89{ 96 * 01 char *
90 struct ifreq ifr; 97 * 02 HOST_COPY in_ether
91 98 * 03 HOST_COPY INET_resolve
92 strcpy(ifr.ifr_name, ifname); 99 */
93 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { 100#define A_CAST_TYPE 0x03
94 perror("SIOCGIFFLAGS"); 101/*
95 return -1; 102 * map type:
96 } 103 * 00 not a map type (mem_start, io_addr, irq)
97 strcpy(ifr.ifr_name, ifname); 104 * 04 memstart (unsigned long)
98 ifr.ifr_flags |= flag; 105 * 08 io_addr (unsigned short)
99 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { 106 * 0C irq (unsigned char)
100 perror("SIOCSIFFLAGS"); 107 */
101 return -1; 108#define A_MAP_TYPE 0x0C
102 } 109#define A_ARG_REQ 0x10 /* Set if an arg is required. */
103 return 0; 110#define A_NETMASK 0x20 /* Set if netmask (check for multiple sets). */
104} 111#define A_SET_AFTER 0x40 /* Set a flag at the end. */
112#define A_COLON_CHK 0x80 /* Is this needed? See below. */
113
114/*
115 * These defines are for dealing with the A_CAST_TYPE field.
116 */
117#define A_CAST_CHAR_PTR 0x01
118#define A_CAST_RESOLVE 0x01
119#define A_CAST_HOST_COPY 0x02
120#define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY
121#define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE)
122
123/*
124 * These defines are for dealing with the A_MAP_TYPE field.
125 */
126#define A_MAP_ULONG 0x04 /* memstart */
127#define A_MAP_USHORT 0x08 /* io_addr */
128#define A_MAP_UCHAR 0x0C /* irq */
105 129
130/*
131 * Define the bit masks signifying which operations to perform for each arg.
132 */
106 133
107/* Clear a certain interface flag. */ 134#define ARG_METRIC (A_ARG_REQ /*| A_CAST_INT*/)
108static int 135#define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/)
109clr_flag(char *ifname, short flag) 136#define ARG_TXQUEUELEN (A_ARG_REQ /*| A_CAST_INT*/)
110{ 137#define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG)
111 struct ifreq ifr; 138#define ARG_IO_ADDR (A_ARG_REQ | A_MAP_USHORT)
112 139#define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR)
113 strcpy(ifr.ifr_name, ifname); 140#define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
114 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { 141#define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
115 perror("SIOCGIFFLAGS"); 142#define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
116 return -1; 143#define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
117 } 144#define ARG_POINTOPOINT (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
118 strcpy(ifr.ifr_name, ifname); 145#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR)
119 ifr.ifr_flags &= ~flag; 146#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR)
120 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { 147#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
121 perror("SIOCSIFFLAGS"); 148
122 return -1; 149
123 } 150/*
124 return 0; 151 * Set up the tables. Warning! They must have corresponding order!
125} 152 */
126 153
127/* which element in struct ifreq to frob */ 154struct arg1opt {
128enum frob { 155 const char *name;
129 L_METRIC, 156 unsigned short selector;
130 L_MTU, 157 unsigned short ifr_offset;
131 L_DATA,
132 L_BROAD,
133 L_DEST,
134 L_MASK,
135 L_HWAD,
136}; 158};
137 159
138 160struct options {
139struct flag_map { 161 const char *name;
140 char *name; 162 const unsigned char flags;
141 enum frob frob; 163 const unsigned char arg_flags;
142 int flag; 164 const unsigned short selector;
143 int sflag;
144 int action;
145}; 165};
146 166
147/* action: 167#define ifreq_offsetof(x) offsetof(struct ifreq, x)
148 * 2 set 168
149 * 4 clear 169static const struct arg1opt Arg1Opt[] = {
150 * 6 set/clear 170 {"SIOCSIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric)},
151 * 8 clear/set 171 {"SIOCSIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu)},
152 * 10 numeric 172 {"SIOCSIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen)},
153 * 12 address 173 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
154 * 14 address/clear 174 {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
155 */ 175 {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
156const static struct flag_map flag_table[] = { 176#ifdef BB_FEATURE_IFCONFIG_HW
157 {"arp", 0, IFF_NOARP, 0, 6}, 177 {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)},
158 {"trailers", 0, IFF_NOTRAILERS, 0, 6}, 178#endif
159 {"promisc", 0, IFF_PROMISC, 0, 8}, 179 {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
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 180#ifdef SIOCSKEEPALIVE
167 {"keepalive", L_DATA, 0, SIOCSKEEPALIVE, 10}, 181 {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},
168#endif 182#endif
169#ifdef SIOCSOUTFILL 183#ifdef SIOCSOUTFILL
170 {"outfill", L_DATA, 0, SIOCSOUTFILL, 10}, 184 {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)},
185#endif
186#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
187 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)},
188 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)},
189 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)},
171#endif 190#endif
172 {"broadcast", L_BROAD, IFF_BROADCAST, SIOCSIFBRDADDR, 14}, 191 /* Last entry if for unmatched (possibly hostname) arg. */
173 {"dstaddr", L_DEST, 0, SIOCSIFDSTADDR, 12}, 192 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)},
174 {"netmask", L_MASK, 0, SIOCSIFNETMASK, 12},
175 {"pointopoint", L_DEST, IFF_POINTOPOINT, SIOCSIFDSTADDR, 14},
176 {"hw", L_HWAD, 0, SIOCSIFHWADDR, 14},
177}; 193};
178 194
179 195static const struct options OptArray[] = {
180/* resolve XXX.YYY.ZZZ.QQQ -> binary */ 196 {"metric", N_ARG, ARG_METRIC, 0},
181 197 {"mtu", N_ARG, ARG_MTU, 0},
182static int 198 {"txqueuelen", N_ARG, ARG_TXQUEUELEN, 0},
183INET_resolve(char *name, struct sockaddr_in *sin) 199 {"dstaddr", N_ARG, ARG_DSTADDR, 0},
184{ 200 {"netmask", N_ARG, ARG_NETMASK, 0},
185 sin->sin_family = AF_INET; 201 {"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST},
186 sin->sin_port = 0; 202#ifdef BB_FEATURE_IFCONFIG_HW
187 203 {"hw", N_ARG, ARG_HW, 0},
188 /* Default is special, meaning 0.0.0.0. */
189 if (strcmp(name, "default")==0) {
190 sin->sin_addr.s_addr = INADDR_ANY;
191 return 1;
192 }
193 /* Look to see if it's a dotted quad. */
194 if (inet_aton(name, &sin->sin_addr)) {
195 return 0;
196 }
197 /* guess not.. */
198 errno = EINVAL;
199 return -1;
200}
201
202/* Input an Ethernet address and convert to binary. */
203static int
204in_ether(char *bufp, struct sockaddr *sap)
205{
206 unsigned char *ptr;
207 char c, *orig;
208 int i;
209 unsigned val;
210
211 sap->sa_family = ARPHRD_ETHER;
212 ptr = sap->sa_data;
213
214 i = 0;
215 orig = bufp;
216 while ((*bufp != '\0') && (i < ETH_ALEN)) {
217 val = 0;
218 c = *bufp++;
219 if (isdigit(c))
220 val = c - '0';
221 else if (c >= 'a' && c <= 'f')
222 val = c - 'a' + 10;
223 else if (c >= 'A' && c <= 'F')
224 val = c - 'A' + 10;
225 else {
226#ifdef DEBUG
227 error_msg(
228 _("in_ether(%s): invalid ether address!"),
229 orig);
230#endif 204#endif
231 errno = EINVAL; 205 {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
232 return -1; 206#ifdef SIOCSKEEPALIVE
233 } 207 {"keepalive", N_ARG, ARG_KEEPALIVE, 0},
234 val <<= 4;
235 c = *bufp;
236 if (isdigit(c))
237 val |= c - '0';
238 else if (c >= 'a' && c <= 'f')
239 val |= c - 'a' + 10;
240 else if (c >= 'A' && c <= 'F')
241 val |= c - 'A' + 10;
242 else if (c == ':' || c == 0)
243 val >>= 4;
244 else {
245#ifdef DEBUG
246 error_msg(
247 _("in_ether(%s): invalid ether address!"),
248 orig);
249#endif 208#endif
250 errno = EINVAL; 209#ifdef SIOCSOUTFILL
251 return -1; 210 {"outfill", N_ARG, ARG_OUTFILL, 0},
252 } 211#endif
253 if (c != 0) 212#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
254 bufp++; 213 {"mem_start", N_ARG, ARG_MEM_START, 0},
255 *ptr++ = (unsigned char) (val & 0377); 214 {"io_addr", N_ARG, ARG_IO_ADDR, 0},
256 i++; 215 {"irq", N_ARG, ARG_IRQ, 0},
257 216#endif
258 /* optional colon already handled, don't swallow a second */ 217 {"arp", N_CLR | M_SET, 0, IFF_NOARP},
259 } 218 {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS},
219 {"promisc", N_SET | M_CLR, 0, IFF_PROMISC},
220 {"multicast", N_SET | M_CLR, 0, IFF_MULTICAST},
221 {"allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI},
222 {"dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC},
223 {"up", N_SET , 0, (IFF_UP | IFF_RUNNING)},
224 {"down", N_CLR , 0, IFF_UP},
225 { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING)}
226};
260 227
261 if(i != ETH_ALEN) { 228/*
262 errno = EINVAL; 229 * A couple of prototypes.
263 return -1; 230 */
264 } 231
232#ifdef BB_FEATURE_IFCONFIG_HW
233static int in_ether(char *bufp, struct sockaddr *sap);
234#endif
265 235
266 return 0;
267}
268
269#ifdef BB_FEATURE_IFCONFIG_STATUS 236#ifdef BB_FEATURE_IFCONFIG_STATUS
270extern int display_interfaces(void); 237extern int display_interfaces(void);
271#else
272int display_interfaces(void)
273{
274 show_usage();
275}
276#endif 238#endif
277 239
240/*
241 * Our main function.
242 */
243
278int ifconfig_main(int argc, char **argv) 244int ifconfig_main(int argc, char **argv)
279{ 245{
280 struct ifreq ifr; 246 struct ifreq ifr;
281 struct sockaddr_in sa; 247 struct sockaddr_in sai;
282 char **spp, *cmd; 248#ifdef BB_FEATURE_IFCONFIG_HW
283 int goterr = 0; 249 struct sockaddr sa;
284 int r; 250#endif
285 /* int didnetmask = 0; special case input error detection no longer implemented */ 251 const struct arg1opt *a1op;
252 const struct options *op;
253 int sockfd; /* socket fd we use to manipulate stuff with */
254 int goterr;
255 int selector;
256 char *p;
286 char host[128]; 257 char host[128];
287 const struct flag_map *ft; 258 unsigned char mask;
288 int i, sense; 259 unsigned char did_flags;
289 int a, ecode; 260
290 struct sockaddr *d; 261 goterr = 0;
262 did_flags = 0;
291 263
292 if(argc < 2) { 264 if(argc < 2) {
265#ifdef BB_FEATURE_IFCONFIG_STATUS
293 return(display_interfaces()); 266 return(display_interfaces());
267#else
268 show_usage();
269#endif
294 } 270 }
295 271
296 /* Create a channel to the NET kernel. */ 272 /* Create a channel to the NET kernel. */
297 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 273 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
298 perror_msg_and_die("socket"); 274 perror("socket");
275 exit(1);
299 } 276 }
300 277
301 /* skip argv[0] */ 278 /* skip argv[0] */
302
303 argc--; 279 argc--;
304 argv++; 280 argv++;
305 281
306 spp = argv;
307
308 /* get interface name */ 282 /* get interface name */
309 283 safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
310 safe_strncpy(ifr.ifr_name, *spp++, IFNAMSIZ);
311 284
312 /* Process the remaining arguments. */ 285 /* Process the remaining arguments. */
313 while (*spp != (char *) NULL) { 286 while (*++argv != (char *) NULL) {
314 cmd = *spp; 287 p = *argv;
315 sense=0; 288 mask = N_MASK;
316 if (*cmd=='-') { 289 if (*p == '-') { /* If the arg starts with '-'... */
317 sense=1; 290 ++p; /* advance past it and */
318 cmd++; 291 mask = M_MASK; /* set the appropriate mask. */
319 } 292 }
320 ft = NULL; 293 for (op = OptArray ; op->name ; op++) { /* Find table entry. */
321 for (i=0; i<(sizeof(flag_table)/sizeof(struct flag_map)); i++) { 294 if (!strcmp(p,op->name)) { /* If name matches... */
322 if (strcmp(cmd, flag_table[i].name)==0) { 295 if ((mask &= op->flags)) { /* set the mask and go. */
323 ft=flag_table+i; 296 goto FOUND_ARG;;
324 spp++; 297 }
325 break; 298 /* If we get here, there was a valid arg with an */
299 /* invalid '-' prefix. */
300 ++goterr;
301 goto LOOP;
326 } 302 }
327 } 303 }
328 if (ft) { 304
329 switch (ft->action+sense) { 305 /* We fell through, so treat as possible hostname. */
330 case 4: 306 a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
331 case 7: 307 mask = op->arg_flags;
332 case 8: 308 goto HOSTNAME;
333 case 15: 309
334 goterr |= clr_flag(ifr.ifr_name, ft->flag); 310 FOUND_ARG:
335 break; 311 if (mask & ARG_MASK) {
336 case 2: 312 mask = op->arg_flags;
337 case 6: 313 a1op = Arg1Opt + (op - OptArray);
338 case 9: 314 if (mask & A_NETMASK & did_flags) {
339 goterr |= set_flag(ifr.ifr_name, ft->flag); 315 show_usage();
340 break; 316 }
341 case 10: 317 if (*++argv == NULL) {
342 if (*spp == NULL) 318 if (mask & A_ARG_REQ) {
343 show_usage(); 319 show_usage();
344 a = atoi(*spp++); 320 } else {
345 switch (ft->frob) { 321 --argv;
346 case L_METRIC: ifr.ifr_metric = a; break; 322 mask &= A_SET_AFTER; /* just for broadcast */
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");
350 } 323 }
351 324 } else { /* got an arg so process it */
352 if (ioctl(sockfd, ft->sflag, &ifr) < 0) { 325 HOSTNAME:
353 perror(ft->name); /* imperfect */ 326 did_flags |= (mask & A_NETMASK);
354 goterr++; 327 if (mask & A_CAST_HOST_COPY) {
328#ifdef BB_FEATURE_IFCONFIG_HW
329 if (mask & A_CAST_RESOLVE) {
330#endif
331 safe_strncpy(host, *argv, (sizeof host));
332 sai.sin_family = AF_INET;
333 sai.sin_port = 0;
334 if (!strcmp(host, "default")) {
335 /* Default is special, meaning 0.0.0.0. */
336 sai.sin_addr.s_addr = INADDR_ANY;
337 } else if (inet_aton(host, &sai.sin_addr) == 0) {
338 /* It's not a dotted quad. */
339 ++goterr;
340 continue;
341 }
342 p = (char *) &sai;
343#ifdef BB_FEATURE_IFCONFIG_HW
344 } else { /* A_CAST_HOST_COPY_IN_ETHER */
345 /* This is the "hw" arg case. */
346 if (strcmp("ether", *argv) || (*++argv == NULL)) {
347 show_usage();
348 }
349 safe_strncpy(host, *argv, (sizeof host));
350 if (in_ether(host, &sa)) {
351 fprintf(stderr, "invalid hw-addr %s\n", host);
352 ++goterr;
353 continue;
354 }
355 p = (char *) &sa;
356 }
357#endif
358 memcpy((((char *)(&ifr)) + a1op->ifr_offset),
359 p, sizeof(struct sockaddr));
360 } else {
361 unsigned int i = strtoul(*argv,NULL,0);
362 p = ((char *)(&ifr)) + a1op->ifr_offset;
363#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
364 if (mask & A_MAP_TYPE) {
365 if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
366 ++goterr;
367 continue;
368 }
369 if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
370 *((unsigned char *) p) = i;
371 } else if (mask & A_MAP_USHORT) {
372 *((unsigned short *) p) = i;
373 } else {
374 *((unsigned long *) p) = i;
375 }
376 } else
377#endif
378 if (mask & A_CAST_CHAR_PTR) {
379 *((caddr_t *) p) = (caddr_t) i;
380 } else { /* A_CAST_INT */
381 *((int *) p) = i;
382 }
355 } 383 }
356 break; 384
357 case 12: 385 if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
358 case 14: 386 perror(a1op->name);
359 if (ft->action+sense==10 && *spp == NULL) { 387 ++goterr;
360 show_usage(); 388 continue;
361 break;
362 } 389 }
363 if (*spp != NULL) { 390
364 safe_strncpy(host, *spp, (sizeof host)); 391#ifdef QUESTIONABLE_ALIAS_CASE
365 spp++; 392 if (mask & A_COLON_CHK) {
366 if (ft->frob == L_HWAD) { 393 /*
367 ecode = in_ether(host, &ifr.ifr_hwaddr); 394 * Don't do the set_flag() if the address is an alias with
368 } else { 395 * a - at the end, since it's deleted already! - Roman
369 switch (ft->frob) { 396 *
370 case L_BROAD: d = &ifr.ifr_broadaddr; break; 397 * Should really use regex.h here, not sure though how well
371 case L_DEST: d = &ifr.ifr_dstaddr; break; 398 * it'll go with the cross-platform support etc.
372 case L_MASK: d = &ifr.ifr_netmask; break; 399 */
373 default: error_msg_and_die("bugaboo"); 400 char *ptr;
401 short int found_colon = 0;
402 for (ptr = ifr.ifr_name; *ptr; ptr++ ) {
403 if (*ptr == ':') {
404 found_colon++;
374 } 405 }
375 ecode = INET_resolve(host, (struct sockaddr_in *) d);
376 } 406 }
377 if (ecode < 0 || ioctl(sockfd, ft->sflag, &ifr) < 0) { 407
378 perror(ft->name); /* imperfect */ 408 if (found_colon && *(ptr - 1) == '-') {
379 goterr++; 409 continue;
380 } 410 }
381 } 411 }
382 if (ft->flag != 0) { 412#endif
383 goterr |= set_flag(ifr.ifr_name, ft->flag); 413 }
384 } 414 if (!(mask & A_SET_AFTER)) {
385 break; 415 continue;
386 default: 416 }
387 show_usage(); 417 mask = N_SET;
388 } /* end of switch */
389 continue;
390 } 418 }
391
392 /* If the next argument is a valid hostname, assume OK. */
393 safe_strncpy(host, *spp, (sizeof host));
394 419
395 if (INET_resolve(host, &sa) < 0) { 420 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
396 show_usage(); 421 perror("SIOCGIFFLAGS");
422 ++goterr;
423 } else {
424 selector = op->selector;
425 if (mask & SET_MASK) {
426 ifr.ifr_flags |= selector;
427 } else {
428 ifr.ifr_flags &= ~selector;
429 }
430 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
431 perror("SIOCSIFFLAGS");
432 ++goterr;
433 }
397 } 434 }
398 memcpy((char *) &ifr.ifr_addr, 435 LOOP:
399 (char *) &sa, sizeof(struct sockaddr)); 436 } /* end of while-loop */
400 437
401 r = ioctl(sockfd, SIOCSIFADDR, &ifr); 438 return goterr;
439}
402 440
403 if (r < 0) { 441#ifdef BB_FEATURE_IFCONFIG_HW
404 perror("SIOCSIFADDR"); 442/* Input an Ethernet address and convert to binary. */
405 goterr++; 443static int
406 } 444in_ether(char *bufp, struct sockaddr *sap)
445{
446 unsigned char *ptr;
447 int i, j;
448 unsigned char val;
449 unsigned char c;
450
451 sap->sa_family = ARPHRD_ETHER;
452 ptr = sap->sa_data;
453
454 for (i = 0 ; i < ETH_ALEN ; i++) {
455 val = 0;
407 456
408 /* 457 /* We might get a semicolon here - not required. */
409 * Don't do the set_flag() if the address is an alias with a - at the 458 if (i && (*bufp == ':')) {
410 * end, since it's deleted already! - Roman 459 bufp++;
411 *
412 * Should really use regex.h here, not sure though how well it'll go
413 * with the cross-platform support etc.
414 */
415 {
416 char *ptr;
417 short int found_colon = 0;
418 for (ptr = ifr.ifr_name; *ptr; ptr++ )
419 if (*ptr == ':') found_colon++;
420
421 if (!(found_colon && *(ptr - 1) == '-'))
422 goterr |= set_flag(ifr.ifr_name, (IFF_UP | IFF_RUNNING));
423 } 460 }
424
425 spp++;
426 461
427 } /* end of while-loop */ 462 for (j=0 ; j<2 ; j++) {
463 c = *bufp;
464 if (c >= '0' && c <= '9') {
465 c -= '0';
466 } else if (c >= 'a' && c <= 'f') {
467 c -= ('a' + 10);
468 } else if (c >= 'A' && c <= 'F') {
469 c -= ('A' + 10);
470 } else if (j && (c == ':' || c == 0)) {
471 break;
472 } else {
473 return -1;
474 }
475 ++bufp;
476 val <<= 4;
477 val += c;
478 }
479 *ptr++ = val;
480 }
428 481
429 return goterr; 482 return (int) (*bufp); /* Error if we don't end at end of string. */
430} 483}
431 484#endif