diff options
-rw-r--r-- | Config.h | 9 | ||||
-rw-r--r-- | ifconfig.c | 711 | ||||
-rw-r--r-- | networking/ifconfig.c | 711 |
3 files changed, 773 insertions, 658 deletions
@@ -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 | ||
39 | static 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 | ||
44 | char *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 | ||
60 | int 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 | /* |
87 | static int | 94 | * cast type: |
88 | set_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*/) |
108 | static int | 135 | #define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/) |
109 | clr_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 */ | 154 | struct arg1opt { |
128 | enum 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 | 160 | struct options { | |
139 | struct 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 | 169 | static 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)}, |
156 | const 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 | 195 | static 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}, | |
182 | static int | 198 | {"txqueuelen", N_ARG, ARG_TXQUEUELEN, 0}, |
183 | INET_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. */ | ||
203 | static int | ||
204 | in_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 | ||
233 | static 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 |
270 | extern int display_interfaces(void); | 237 | extern int display_interfaces(void); |
271 | #else | ||
272 | int display_interfaces(void) | ||
273 | { | ||
274 | show_usage(); | ||
275 | } | ||
276 | #endif | 238 | #endif |
277 | 239 | ||
240 | /* | ||
241 | * Our main function. | ||
242 | */ | ||
243 | |||
278 | int ifconfig_main(int argc, char **argv) | 244 | int 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++; | 443 | static int |
406 | } | 444 | in_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 | ||
39 | static 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 | ||
44 | char *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 | ||
60 | int 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 | /* |
87 | static int | 94 | * cast type: |
88 | set_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*/) |
108 | static int | 135 | #define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/) |
109 | clr_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 */ | 154 | struct arg1opt { |
128 | enum 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 | 160 | struct options { | |
139 | struct 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 | 169 | static 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)}, |
156 | const 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 | 195 | static 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}, | |
182 | static int | 198 | {"txqueuelen", N_ARG, ARG_TXQUEUELEN, 0}, |
183 | INET_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. */ | ||
203 | static int | ||
204 | in_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 | ||
233 | static 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 |
270 | extern int display_interfaces(void); | 237 | extern int display_interfaces(void); |
271 | #else | ||
272 | int display_interfaces(void) | ||
273 | { | ||
274 | show_usage(); | ||
275 | } | ||
276 | #endif | 238 | #endif |
277 | 239 | ||
240 | /* | ||
241 | * Our main function. | ||
242 | */ | ||
243 | |||
278 | int ifconfig_main(int argc, char **argv) | 244 | int 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++; | 443 | static int |
406 | } | 444 | in_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 | |