]>
Commit | Line | Data |
---|---|---|
b7080c8e A |
1 | /* |
2 | * Copyright (c) 1983, 1993 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #ifndef lint | |
35 | static const char copyright[] = | |
36 | "@(#) Copyright (c) 1983, 1993\n\ | |
37 | The Regents of the University of California. All rights reserved.\n"; | |
38 | #endif /* not lint */ | |
39 | ||
40 | #ifndef lint | |
41 | #if 0 | |
42 | static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; | |
43 | #endif | |
44 | static const char rcsid[] = | |
2b484d24 | 45 | "$Id: ifconfig.c,v 1.8 2004/08/26 23:55:21 lindak Exp $"; |
b7080c8e A |
46 | #endif /* not lint */ |
47 | ||
48 | #include <sys/param.h> | |
7902cf7e | 49 | #define KERNEL_PRIVATE |
b7080c8e | 50 | #include <sys/ioctl.h> |
7902cf7e | 51 | #undef KERNEL_PRIVATE |
b7080c8e A |
52 | #include <sys/socket.h> |
53 | #include <sys/sysctl.h> | |
54 | #include <sys/time.h> | |
55 | ||
7ba0088d | 56 | #include <net/ethernet.h> |
b7080c8e A |
57 | #include <net/if.h> |
58 | #include <net/if_var.h> | |
59 | #include <net/if_dl.h> | |
60 | #include <net/if_types.h> | |
61 | #include <net/route.h> | |
62 | ||
63 | /* IP */ | |
64 | #include <netinet/in.h> | |
65 | #include <netinet/in_var.h> | |
66 | #include <arpa/inet.h> | |
67 | #include <netdb.h> | |
68 | ||
7ba0088d A |
69 | #ifdef INET6 |
70 | #include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */ | |
71 | #endif | |
72 | ||
73 | ||
74 | /* XNS */ | |
75 | #ifdef NS | |
76 | #define NSIP | |
77 | #include <netns/ns.h> | |
78 | #include <netns/ns_if.h> | |
79 | #endif | |
b7080c8e A |
80 | /* OSI */ |
81 | ||
82 | #include <ctype.h> | |
83 | #include <err.h> | |
84 | #include <errno.h> | |
85 | #include <fcntl.h> | |
86 | #include <stdio.h> | |
87 | #include <stdlib.h> | |
88 | #include <string.h> | |
89 | #include <unistd.h> | |
90 | ||
7902cf7e | 91 | |
b7080c8e A |
92 | #include "ifconfig.h" |
93 | ||
7ba0088d A |
94 | /* wrapper for KAME-special getnameinfo() */ |
95 | #ifndef NI_WITHSCOPEID | |
96 | #define NI_WITHSCOPEID 0 | |
97 | #endif | |
98 | ||
b7080c8e A |
99 | struct ifreq ifr, ridreq; |
100 | struct ifaliasreq addreq; | |
7ba0088d A |
101 | #ifdef INET6 |
102 | struct in6_ifreq in6_ridreq; | |
103 | struct in6_aliasreq in6_addreq = | |
104 | { { 0 }, | |
105 | { 0 }, | |
106 | { 0 }, | |
107 | { 0 }, | |
108 | 0, | |
109 | { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } }; | |
110 | #endif | |
b7080c8e A |
111 | struct sockaddr_in netmask; |
112 | ||
113 | ||
114 | char name[32]; | |
115 | int flags; | |
116 | int metric; | |
117 | int mtu; | |
118 | int setaddr; | |
119 | int setipdst; | |
7ba0088d | 120 | int setmask; |
b7080c8e A |
121 | int doalias; |
122 | int clearaddr; | |
7ba0088d A |
123 | int newaddr = 1; |
124 | #ifdef INET6 | |
125 | static int ip6lifetime; | |
126 | #endif | |
b7080c8e A |
127 | |
128 | struct afswtch; | |
129 | ||
2b484d24 | 130 | int bond_details = 0; |
7ba0088d A |
131 | int supmedia = 0; |
132 | int listcloners = 0; | |
133 | ||
134 | #ifdef INET6 | |
135 | char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ | |
136 | #endif | |
137 | ||
b7080c8e A |
138 | void Perror __P((const char *cmd)); |
139 | ||
140 | int ifconfig __P((int argc, char *const *argv, const struct afswtch *afp)); | |
141 | void notealias __P((const char *, int, int, const struct afswtch *afp)); | |
142 | void printb __P((const char *s, unsigned value, const char *bits)); | |
143 | void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); | |
144 | void status __P((const struct afswtch *afp, int addrcount, | |
145 | struct sockaddr_dl *sdl, struct if_msghdr *ifm, | |
146 | struct ifa_msghdr *ifam)); | |
7ba0088d | 147 | void tunnel_status __P((int s)); |
b7080c8e A |
148 | void usage __P((void)); |
149 | ||
7ba0088d A |
150 | #ifdef INET6 |
151 | void in6_fillscopeid __P((struct sockaddr_in6 *sin6)); | |
152 | int prefix __P((void *, int)); | |
153 | static char *sec2str __P((time_t)); | |
154 | int explicit_prefix = 0; | |
155 | #endif | |
b7080c8e | 156 | |
7ba0088d A |
157 | typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp)); |
158 | typedef void c_func2 __P((const char *arg, const char *arg2, int s, const struct afswtch *afp)); | |
b7080c8e | 159 | c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask; |
7ba0088d A |
160 | c_func2 settunnel; |
161 | c_func deletetunnel; | |
162 | #ifdef INET6 | |
163 | c_func setifprefixlen; | |
164 | c_func setip6flags; | |
165 | c_func setip6pltime; | |
166 | c_func setip6vltime; | |
167 | c_func2 setip6lifetime; | |
168 | #endif | |
b7080c8e | 169 | c_func setifipdst; |
7ba0088d | 170 | c_func setifflags, setifmetric, setifmtu, setiflladdr; |
7902cf7e | 171 | c_func clone_destroy; |
b7080c8e A |
172 | |
173 | ||
7902cf7e | 174 | void clone_create(void); |
b7080c8e | 175 | #define NEXTARG 0xffffff |
7ba0088d | 176 | #define NEXTARG2 0xfffffe |
b7080c8e A |
177 | |
178 | const | |
179 | struct cmd { | |
180 | const char *c_name; | |
181 | int c_parameter; /* NEXTARG means next argv */ | |
182 | void (*c_func) __P((const char *, int, int, const struct afswtch *afp)); | |
7ba0088d | 183 | void (*c_func2) __P((const char *, const char *, int, const struct afswtch *afp)); |
b7080c8e A |
184 | } cmds[] = { |
185 | { "up", IFF_UP, setifflags } , | |
186 | { "down", -IFF_UP, setifflags }, | |
187 | { "arp", -IFF_NOARP, setifflags }, | |
188 | { "-arp", IFF_NOARP, setifflags }, | |
189 | { "debug", IFF_DEBUG, setifflags }, | |
190 | { "-debug", -IFF_DEBUG, setifflags }, | |
7ba0088d | 191 | { "add", IFF_UP, notealias }, |
b7080c8e A |
192 | { "alias", IFF_UP, notealias }, |
193 | { "-alias", -IFF_UP, notealias }, | |
194 | { "delete", -IFF_UP, notealias }, | |
7ba0088d | 195 | { "remove", -IFF_UP, notealias }, |
b7080c8e A |
196 | #ifdef notdef |
197 | #define EN_SWABIPS 0x1000 | |
198 | { "swabips", EN_SWABIPS, setifflags }, | |
199 | { "-swabips", -EN_SWABIPS, setifflags }, | |
200 | #endif | |
201 | { "netmask", NEXTARG, setifnetmask }, | |
7ba0088d A |
202 | #ifdef INET6 |
203 | { "prefixlen", NEXTARG, setifprefixlen }, | |
204 | { "anycast", IN6_IFF_ANYCAST, setip6flags }, | |
205 | { "tentative", IN6_IFF_TENTATIVE, setip6flags }, | |
206 | { "-tentative", -IN6_IFF_TENTATIVE, setip6flags }, | |
207 | { "deprecated", IN6_IFF_DEPRECATED, setip6flags }, | |
208 | { "-deprecated", -IN6_IFF_DEPRECATED, setip6flags }, | |
209 | { "autoconf", IN6_IFF_AUTOCONF, setip6flags }, | |
210 | { "-autoconf", -IN6_IFF_AUTOCONF, setip6flags }, | |
211 | { "pltime", NEXTARG, setip6pltime }, | |
212 | { "vltime", NEXTARG, setip6vltime }, | |
213 | #endif | |
b7080c8e A |
214 | { "metric", NEXTARG, setifmetric }, |
215 | { "broadcast", NEXTARG, setifbroadaddr }, | |
216 | { "ipdst", NEXTARG, setifipdst }, | |
7ba0088d A |
217 | { "tunnel", NEXTARG2, NULL, settunnel }, |
218 | { "deletetunnel", 0, deletetunnel }, | |
b7080c8e A |
219 | { "link0", IFF_LINK0, setifflags }, |
220 | { "-link0", -IFF_LINK0, setifflags }, | |
221 | { "link1", IFF_LINK1, setifflags }, | |
222 | { "-link1", -IFF_LINK1, setifflags }, | |
223 | { "link2", IFF_LINK2, setifflags }, | |
224 | { "-link2", -IFF_LINK2, setifflags }, | |
225 | #if USE_IF_MEDIA | |
226 | { "media", NEXTARG, setmedia }, | |
227 | { "mediaopt", NEXTARG, setmediaopt }, | |
228 | { "-mediaopt", NEXTARG, unsetmediaopt }, | |
7ba0088d A |
229 | #endif |
230 | #ifdef USE_VLANS | |
231 | { "vlan", NEXTARG, setvlantag }, | |
232 | { "vlandev", NEXTARG, setvlandev }, | |
233 | { "-vlandev", NEXTARG, unsetvlandev }, | |
234 | #endif | |
2b484d24 A |
235 | #ifdef USE_BONDS |
236 | { "bonddev", NEXTARG, setbonddev }, | |
237 | { "-bonddev", NEXTARG, unsetbonddev }, | |
b8dff150 | 238 | { "bondmode", NEXTARG, setbondmode }, |
2b484d24 | 239 | #endif |
7ba0088d A |
240 | #if 0 |
241 | /* XXX `create' special-cased below */ | |
242 | {"create", 0, clone_create }, | |
243 | {"plumb", 0, clone_create }, | |
244 | #endif | |
7ba0088d A |
245 | {"destroy", 0, clone_destroy }, |
246 | {"unplumb", 0, clone_destroy }, | |
7ba0088d A |
247 | #ifdef USE_IEEE80211 |
248 | { "ssid", NEXTARG, set80211ssid }, | |
249 | { "nwid", NEXTARG, set80211ssid }, | |
250 | { "stationname", NEXTARG, set80211stationname }, | |
251 | { "station", NEXTARG, set80211stationname }, /* BSD/OS */ | |
252 | { "channel", NEXTARG, set80211channel }, | |
253 | { "authmode", NEXTARG, set80211authmode }, | |
254 | { "powersavemode", NEXTARG, set80211powersavemode }, | |
255 | { "powersave", 1, set80211powersave }, | |
256 | { "-powersave", 0, set80211powersave }, | |
257 | { "powersavesleep", NEXTARG, set80211powersavesleep }, | |
258 | { "wepmode", NEXTARG, set80211wepmode }, | |
259 | { "wep", 1, set80211wep }, | |
260 | { "-wep", 0, set80211wep }, | |
261 | { "weptxkey", NEXTARG, set80211weptxkey }, | |
262 | { "wepkey", NEXTARG, set80211wepkey }, | |
263 | { "nwkey", NEXTARG, set80211nwkey }, /* NetBSD */ | |
264 | { "-nwkey", 0, set80211wep }, /* NetBSD */ | |
b7080c8e A |
265 | #endif |
266 | { "normal", -IFF_LINK0, setifflags }, | |
267 | { "compress", IFF_LINK0, setifflags }, | |
268 | { "noicmp", IFF_LINK1, setifflags }, | |
269 | { "mtu", NEXTARG, setifmtu }, | |
7ba0088d | 270 | { "lladdr", NEXTARG, setiflladdr }, |
b7080c8e A |
271 | { 0, 0, setifaddr }, |
272 | { 0, 0, setifdstaddr }, | |
273 | }; | |
274 | ||
275 | /* | |
276 | * XNS support liberally adapted from code written at the University of | |
277 | * Maryland principally by James O'Toole and Chris Torek. | |
278 | */ | |
279 | typedef void af_status __P((int, struct rt_addrinfo *)); | |
280 | typedef void af_getaddr __P((const char *, int)); | |
7ba0088d A |
281 | typedef void af_getprefix __P((const char *, int)); |
282 | ||
283 | af_status in_status, at_status, ether_status; | |
284 | af_getaddr in_getaddr, at_getaddr, ether_getaddr; | |
b7080c8e | 285 | |
7ba0088d A |
286 | |
287 | #ifdef INET6 | |
288 | af_status in6_status; | |
289 | af_getaddr in6_getaddr; | |
290 | af_getprefix in6_getprefix; | |
291 | #endif /*INET6*/ | |
292 | #ifdef NS | |
293 | af_status xns_status; | |
294 | af_getaddr xns_getaddr; | |
295 | #endif | |
b7080c8e A |
296 | |
297 | /* Known address families */ | |
298 | const | |
299 | struct afswtch { | |
300 | const char *af_name; | |
301 | short af_af; | |
302 | af_status *af_status; | |
303 | af_getaddr *af_getaddr; | |
7ba0088d | 304 | af_getprefix *af_getprefix; |
b7080c8e A |
305 | u_long af_difaddr; |
306 | u_long af_aifaddr; | |
307 | caddr_t af_ridreq; | |
308 | caddr_t af_addreq; | |
309 | } afs[] = { | |
310 | #define C(x) ((caddr_t) &x) | |
7ba0088d | 311 | { "inet", AF_INET, in_status, in_getaddr, NULL, |
b7080c8e | 312 | SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, |
7ba0088d A |
313 | #ifdef INET6 |
314 | { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix, | |
315 | SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, | |
316 | C(in6_ridreq), C(in6_addreq) }, | |
317 | #endif /*INET6*/ | |
318 | #ifdef NS | |
319 | { "ns", AF_NS, xns_status, xns_getaddr, NULL, | |
320 | SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, | |
321 | #endif | |
322 | { "ether", AF_LINK, ether_status, ether_getaddr, NULL, | |
323 | 0, SIOCSIFLLADDR, NULL, C(ridreq) }, | |
b7080c8e | 324 | #if 0 /* XXX conflicts with the media command */ |
7ba0088d A |
325 | #ifdef USE_IF_MEDIA |
326 | { "media", AF_UNSPEC, media_status, NULL, NULL, }, /* XXX not real!! */ | |
327 | #endif | |
328 | #ifdef USE_VLANS | |
329 | { "vlan", AF_UNSPEC, vlan_status, NULL, NULL, }, /* XXX not real!! */ | |
330 | #endif | |
2b484d24 A |
331 | #ifdef USE_BONDS |
332 | { "bond", AF_UNSPEC, bond_status, NULL, NULL, }, /* XXX not real!! */ | |
333 | #endif | |
7ba0088d A |
334 | #ifdef USE_IEEE80211 |
335 | { "ieee80211", AF_UNSPEC, ieee80211_status, NULL, NULL, }, /* XXX not real!! */ | |
b7080c8e A |
336 | #endif |
337 | #endif | |
338 | { 0, 0, 0, 0 } | |
339 | }; | |
340 | ||
341 | /* | |
342 | * Expand the compacted form of addresses as returned via the | |
343 | * configuration read via sysctl(). | |
344 | */ | |
345 | ||
346 | #define ROUNDUP(a) \ | |
347 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |
348 | #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) | |
349 | ||
350 | void | |
351 | rt_xaddrs(cp, cplim, rtinfo) | |
352 | caddr_t cp, cplim; | |
353 | struct rt_addrinfo *rtinfo; | |
354 | { | |
355 | struct sockaddr *sa; | |
356 | int i; | |
357 | ||
358 | memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); | |
359 | for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { | |
360 | if ((rtinfo->rti_addrs & (1 << i)) == 0) | |
361 | continue; | |
362 | rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; | |
363 | ADVANCE(cp, sa); | |
364 | } | |
365 | } | |
366 | ||
367 | ||
368 | void | |
369 | usage() | |
370 | { | |
7ba0088d | 371 | #ifndef INET6 |
7902cf7e A |
372 | fprintf(stderr, "%s", |
373 | "usage: ifconfig interface address_family [address [dest_address]]\n" | |
374 | " [parameters]\n" | |
375 | " ifconfig interface create\n" | |
376 | " ifconfig -a [-d] [-m] [-u] [address_family]\n" | |
377 | " ifconfig -l [-d] [-u] [address_family]\n" | |
378 | " ifconfig [-d] [-m] [-u]\n"); | |
7ba0088d | 379 | #else |
7902cf7e A |
380 | fprintf(stderr, "%s", |
381 | "usage: ifconfig [-L] interface address_family [address [dest_address]]\n" | |
382 | " [parameters]\n" | |
383 | " ifconfig interface create\n" | |
384 | " ifconfig -a [-L] [-d] [-m] [-u] [address_family]\n" | |
385 | " ifconfig -l [-d] [-u] [address_family]\n" | |
386 | " ifconfig [-L] [-d] [-m] [-u]\n"); | |
7ba0088d | 387 | #endif |
b7080c8e A |
388 | exit(1); |
389 | } | |
390 | ||
391 | int | |
392 | main(argc, argv) | |
393 | int argc; | |
394 | char *const *argv; | |
395 | { | |
396 | int c; | |
397 | int all, namesonly, downonly, uponly; | |
398 | int foundit = 0, need_nl = 0; | |
399 | const struct afswtch *afp = 0; | |
400 | int addrcount; | |
401 | struct if_msghdr *ifm, *nextifm; | |
402 | struct ifa_msghdr *ifam; | |
403 | struct sockaddr_dl *sdl; | |
404 | char *buf, *lim, *next; | |
405 | ||
406 | ||
407 | size_t needed; | |
408 | int mib[6]; | |
409 | ||
410 | /* Parse leading line options */ | |
411 | all = downonly = uponly = namesonly = 0; | |
2b484d24 | 412 | while ((c = getopt(argc, argv, "abdlmu" |
7ba0088d A |
413 | #ifdef INET6 |
414 | "L" | |
415 | #endif | |
416 | )) != -1) { | |
b7080c8e A |
417 | switch (c) { |
418 | case 'a': /* scan all interfaces */ | |
419 | all++; | |
420 | break; | |
2b484d24 A |
421 | case 'b': /* bond detailed output */ |
422 | bond_details++; | |
423 | break; | |
7ba0088d A |
424 | case 'd': /* restrict scan to "down" interfaces */ |
425 | downonly++; | |
426 | break; | |
b7080c8e A |
427 | case 'l': /* scan interface names only */ |
428 | namesonly++; | |
429 | break; | |
7ba0088d A |
430 | case 'm': /* show media choices in status */ |
431 | supmedia = 1; | |
b7080c8e A |
432 | break; |
433 | case 'u': /* restrict scan to "up" interfaces */ | |
434 | uponly++; | |
435 | break; | |
7ba0088d A |
436 | #ifdef INET6 |
437 | case 'L': | |
438 | ip6lifetime++; /* print IPv6 address lifetime */ | |
b7080c8e | 439 | break; |
7ba0088d | 440 | #endif |
b7080c8e A |
441 | default: |
442 | usage(); | |
443 | break; | |
444 | } | |
445 | } | |
446 | argc -= optind; | |
447 | argv += optind; | |
448 | ||
2b484d24 A |
449 | /* -l cannot be used with -a or -m or -b */ |
450 | if (namesonly && (all || supmedia || bond_details)) | |
b7080c8e A |
451 | usage(); |
452 | ||
453 | /* nonsense.. */ | |
454 | if (uponly && downonly) | |
455 | usage(); | |
456 | ||
7ba0088d A |
457 | /* no arguments is equivalent to '-a' */ |
458 | if (!namesonly && argc < 1) | |
459 | all = 1; | |
460 | ||
b7080c8e A |
461 | /* -a and -l allow an address family arg to limit the output */ |
462 | if (all || namesonly) { | |
463 | if (argc > 1) | |
464 | usage(); | |
465 | ||
466 | if (argc == 1) { | |
467 | for (afp = afs; afp->af_name; afp++) | |
468 | if (strcmp(afp->af_name, *argv) == 0) { | |
469 | argc--, argv++; | |
470 | break; | |
471 | } | |
472 | if (afp->af_name == NULL) | |
473 | usage(); | |
474 | /* leave with afp non-zero */ | |
475 | } | |
476 | } else { | |
477 | /* not listing, need an argument */ | |
478 | if (argc < 1) | |
479 | usage(); | |
480 | ||
481 | strncpy(name, *argv, sizeof(name)); | |
482 | argc--, argv++; | |
7ba0088d A |
483 | |
484 | /* | |
485 | * NOTE: We must special-case the `create' command right | |
486 | * here as we would otherwise fail when trying to find | |
487 | * the interface. | |
488 | */ | |
489 | if (argc > 0 && (strcmp(argv[0], "create") == 0 || | |
490 | strcmp(argv[0], "plumb") == 0)) { | |
7ba0088d | 491 | clone_create(); |
7ba0088d A |
492 | argc--, argv++; |
493 | if (argc == 0) | |
494 | exit(0); | |
495 | } | |
b7080c8e A |
496 | } |
497 | ||
498 | /* Check for address family */ | |
499 | if (argc > 0) { | |
500 | for (afp = afs; afp->af_name; afp++) | |
501 | if (strcmp(afp->af_name, *argv) == 0) { | |
502 | argc--, argv++; | |
503 | break; | |
504 | } | |
505 | if (afp->af_name == NULL) | |
506 | afp = NULL; /* not a family, NULL */ | |
507 | } | |
508 | ||
509 | mib[0] = CTL_NET; | |
510 | mib[1] = PF_ROUTE; | |
511 | mib[2] = 0; | |
512 | mib[3] = 0; /* address family */ | |
513 | mib[4] = NET_RT_IFLIST; | |
514 | mib[5] = 0; | |
515 | ||
516 | /* if particular family specified, only ask about it */ | |
517 | if (afp) | |
518 | mib[3] = afp->af_af; | |
519 | ||
520 | if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) | |
521 | errx(1, "iflist-sysctl-estimate"); | |
522 | if ((buf = malloc(needed)) == NULL) | |
523 | errx(1, "malloc"); | |
524 | if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) | |
525 | errx(1, "actual retrieval of interface table"); | |
526 | lim = buf + needed; | |
527 | ||
528 | next = buf; | |
529 | while (next < lim) { | |
530 | ||
531 | ifm = (struct if_msghdr *)next; | |
532 | ||
533 | if (ifm->ifm_type == RTM_IFINFO) { | |
534 | sdl = (struct sockaddr_dl *)(ifm + 1); | |
535 | flags = ifm->ifm_flags; | |
536 | } else { | |
537 | fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n"); | |
538 | fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, | |
539 | ifm->ifm_type); | |
540 | fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen); | |
541 | fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, | |
542 | lim); | |
543 | exit (1); | |
544 | } | |
545 | ||
546 | next += ifm->ifm_msglen; | |
547 | ifam = NULL; | |
548 | addrcount = 0; | |
549 | while (next < lim) { | |
550 | ||
551 | nextifm = (struct if_msghdr *)next; | |
552 | ||
553 | if (nextifm->ifm_type != RTM_NEWADDR) | |
554 | break; | |
555 | ||
556 | if (ifam == NULL) | |
557 | ifam = (struct ifa_msghdr *)nextifm; | |
558 | ||
559 | addrcount++; | |
560 | next += nextifm->ifm_msglen; | |
561 | } | |
562 | ||
563 | if (all || namesonly) { | |
564 | if (uponly) | |
565 | if ((flags & IFF_UP) == 0) | |
566 | continue; /* not up */ | |
567 | if (downonly) | |
568 | if (flags & IFF_UP) | |
569 | continue; /* not down */ | |
570 | strncpy(name, sdl->sdl_data, sdl->sdl_nlen); | |
571 | name[sdl->sdl_nlen] = '\0'; | |
572 | if (namesonly) { | |
573 | if (afp == NULL || | |
574 | afp->af_status != ether_status || | |
575 | sdl->sdl_type == IFT_ETHER) { | |
576 | if (need_nl) | |
577 | putchar(' '); | |
578 | fputs(name, stdout); | |
579 | need_nl++; | |
580 | } | |
581 | continue; | |
582 | } | |
583 | } else { | |
584 | if (strlen(name) != sdl->sdl_nlen) | |
585 | continue; /* not same len */ | |
586 | if (strncmp(name, sdl->sdl_data, sdl->sdl_nlen) != 0) | |
587 | continue; /* not same name */ | |
588 | } | |
589 | ||
590 | if (argc > 0) | |
591 | ifconfig(argc, argv, afp); | |
592 | else | |
593 | status(afp, addrcount, sdl, ifm, ifam); | |
594 | ||
595 | if (all == 0 && namesonly == 0) { | |
596 | foundit++; /* flag it as 'done' */ | |
597 | break; | |
598 | } | |
599 | } | |
600 | free(buf); | |
601 | ||
602 | if (namesonly && need_nl > 0) | |
603 | putchar('\n'); | |
604 | ||
605 | if (all == 0 && namesonly == 0 && foundit == 0) | |
606 | errx(1, "interface %s does not exist", name); | |
607 | ||
608 | ||
609 | exit (0); | |
610 | } | |
611 | ||
612 | ||
613 | int | |
614 | ifconfig(argc, argv, afp) | |
615 | int argc; | |
616 | char *const *argv; | |
617 | const struct afswtch *afp; | |
618 | { | |
619 | int s; | |
620 | ||
621 | if (afp == NULL) | |
622 | afp = &afs[0]; | |
7ba0088d | 623 | ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; |
b7080c8e A |
624 | strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); |
625 | ||
626 | if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) | |
627 | err(1, "socket"); | |
628 | ||
629 | while (argc > 0) { | |
630 | register const struct cmd *p; | |
631 | ||
632 | for (p = cmds; p->c_name; p++) | |
633 | if (strcmp(*argv, p->c_name) == 0) | |
634 | break; | |
635 | if (p->c_name == 0 && setaddr) | |
636 | p++; /* got src, do dst */ | |
7ba0088d | 637 | if (p->c_func || p->c_func2) { |
b7080c8e A |
638 | if (p->c_parameter == NEXTARG) { |
639 | if (argv[1] == NULL) | |
640 | errx(1, "'%s' requires argument", | |
641 | p->c_name); | |
642 | (*p->c_func)(argv[1], 0, s, afp); | |
643 | argc--, argv++; | |
7ba0088d A |
644 | } else if (p->c_parameter == NEXTARG2) { |
645 | if (argc < 3) | |
646 | errx(1, "'%s' requires 2 arguments", | |
647 | p->c_name); | |
648 | (*p->c_func2)(argv[1], argv[2], s, afp); | |
649 | argc -= 2, argv += 2; | |
b7080c8e A |
650 | } else |
651 | (*p->c_func)(*argv, p->c_parameter, s, afp); | |
652 | } | |
653 | argc--, argv++; | |
654 | } | |
7ba0088d A |
655 | #ifdef INET6 |
656 | if (ifr.ifr_addr.sa_family == AF_INET6 && explicit_prefix == 0) { | |
657 | /* Aggregatable address architecture defines all prefixes | |
658 | are 64. So, it is convenient to set prefixlen to 64 if | |
659 | it is not specified. */ | |
660 | setifprefixlen("64", 0, s, afp); | |
661 | /* in6_getprefix("64", MASK) if MASK is available here... */ | |
662 | } | |
663 | #endif | |
664 | #ifdef NS | |
665 | if (setipdst && ifr.ifr_addr.sa_family == AF_NS) { | |
666 | struct nsip_req rq; | |
667 | int size = sizeof(rq); | |
668 | ||
669 | rq.rq_ns = addreq.ifra_addr; | |
670 | rq.rq_ip = addreq.ifra_dstaddr; | |
b7080c8e | 671 | |
7ba0088d A |
672 | if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0) |
673 | Perror("Encapsulation Routing"); | |
674 | } | |
675 | #endif | |
b7080c8e A |
676 | if (clearaddr) { |
677 | if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { | |
678 | warnx("interface %s cannot change %s addresses!", | |
679 | name, afp->af_name); | |
2b484d24 | 680 | clearaddr = 0; |
b7080c8e A |
681 | } |
682 | } | |
683 | if (clearaddr) { | |
684 | int ret; | |
685 | strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name); | |
686 | if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) { | |
687 | if (errno == EADDRNOTAVAIL && (doalias >= 0)) { | |
688 | /* means no previous address for interface */ | |
689 | } else | |
690 | Perror("ioctl (SIOCDIFADDR)"); | |
691 | } | |
692 | } | |
693 | if (newaddr) { | |
7ba0088d | 694 | if (afp->af_addreq == NULL || afp->af_aifaddr == 0) { |
b7080c8e A |
695 | warnx("interface %s cannot change %s addresses!", |
696 | name, afp->af_name); | |
2b484d24 | 697 | newaddr = 0; |
b7080c8e A |
698 | } |
699 | } | |
7ba0088d | 700 | if (newaddr && (setaddr || setmask)) { |
b7080c8e A |
701 | strncpy(afp->af_addreq, name, sizeof ifr.ifr_name); |
702 | if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) | |
703 | Perror("ioctl (SIOCAIFADDR)"); | |
704 | } | |
705 | close(s); | |
706 | return(0); | |
707 | } | |
708 | #define RIDADDR 0 | |
709 | #define ADDR 1 | |
7902cf7e | 710 | #define NMASK 2 |
b7080c8e A |
711 | #define DSTADDR 3 |
712 | ||
713 | /*ARGSUSED*/ | |
714 | void | |
715 | setifaddr(addr, param, s, afp) | |
716 | const char *addr; | |
717 | int param; | |
718 | int s; | |
719 | const struct afswtch *afp; | |
720 | { | |
7ba0088d A |
721 | if (*afp->af_getaddr == NULL) |
722 | return; | |
b7080c8e A |
723 | /* |
724 | * Delay the ioctl to set the interface addr until flags are all set. | |
725 | * The address interpretation may depend on the flags, | |
726 | * and the flags may change when the address is set. | |
727 | */ | |
728 | setaddr++; | |
7ba0088d | 729 | if (doalias == 0 && afp->af_af != AF_LINK) |
b7080c8e A |
730 | clearaddr = 1; |
731 | (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR)); | |
732 | } | |
733 | ||
7ba0088d A |
734 | void |
735 | settunnel(src, dst, s, afp) | |
736 | const char *src, *dst; | |
737 | int s; | |
738 | const struct afswtch *afp; | |
739 | { | |
740 | struct addrinfo hints, *srcres, *dstres; | |
741 | struct ifaliasreq addreq; | |
742 | int ecode; | |
743 | #ifdef INET6 | |
744 | struct in6_aliasreq in6_addreq; | |
745 | #endif | |
746 | ||
747 | memset(&hints, 0, sizeof(hints)); | |
748 | hints.ai_family = afp->af_af; | |
749 | ||
750 | if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) | |
751 | errx(1, "error in parsing address string: %s", | |
752 | gai_strerror(ecode)); | |
753 | ||
754 | if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) | |
755 | errx(1, "error in parsing address string: %s", | |
756 | gai_strerror(ecode)); | |
757 | ||
758 | if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) | |
759 | errx(1, | |
760 | "source and destination address families do not match"); | |
761 | ||
762 | switch (srcres->ai_addr->sa_family) { | |
763 | case AF_INET: | |
764 | memset(&addreq, 0, sizeof(addreq)); | |
765 | strncpy(addreq.ifra_name, name, IFNAMSIZ); | |
766 | memcpy(&addreq.ifra_addr, srcres->ai_addr, | |
767 | srcres->ai_addr->sa_len); | |
768 | memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, | |
769 | dstres->ai_addr->sa_len); | |
770 | ||
771 | if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) | |
772 | warn("SIOCSIFPHYADDR"); | |
773 | break; | |
774 | ||
775 | #ifdef INET6 | |
776 | case AF_INET6: | |
777 | memset(&in6_addreq, 0, sizeof(in6_addreq)); | |
778 | strncpy(in6_addreq.ifra_name, name, IFNAMSIZ); | |
779 | memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, | |
780 | srcres->ai_addr->sa_len); | |
781 | memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr, | |
782 | dstres->ai_addr->sa_len); | |
783 | ||
784 | if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0) | |
785 | warn("SIOCSIFPHYADDR_IN6"); | |
786 | break; | |
787 | #endif /* INET6 */ | |
788 | ||
789 | default: | |
790 | warn("address family not supported"); | |
791 | } | |
792 | ||
793 | freeaddrinfo(srcres); | |
794 | freeaddrinfo(dstres); | |
795 | } | |
796 | ||
797 | /* ARGSUSED */ | |
798 | void | |
799 | deletetunnel(vname, param, s, afp) | |
800 | const char *vname; | |
801 | int param; | |
802 | int s; | |
803 | const struct afswtch *afp; | |
804 | { | |
805 | ||
806 | if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) | |
807 | err(1, "SIOCDIFPHYADDR"); | |
808 | } | |
809 | ||
b7080c8e A |
810 | void |
811 | setifnetmask(addr, dummy, s, afp) | |
812 | const char *addr; | |
813 | int dummy ; | |
814 | int s; | |
815 | const struct afswtch *afp; | |
816 | { | |
7ba0088d A |
817 | if (*afp->af_getaddr == NULL) |
818 | return; | |
819 | setmask++; | |
7902cf7e | 820 | (*afp->af_getaddr)(addr, NMASK); |
b7080c8e A |
821 | } |
822 | ||
7ba0088d A |
823 | #ifdef INET6 |
824 | void | |
825 | setifprefixlen(addr, dummy, s, afp) | |
826 | const char *addr; | |
827 | int dummy ; | |
828 | int s; | |
829 | const struct afswtch *afp; | |
830 | { | |
831 | if (*afp->af_getprefix) | |
7902cf7e | 832 | (*afp->af_getprefix)(addr, NMASK); |
7ba0088d A |
833 | explicit_prefix = 1; |
834 | } | |
835 | ||
836 | void | |
837 | setip6flags(dummyaddr, flag, dummysoc, afp) | |
838 | const char *dummyaddr ; | |
839 | int flag; | |
840 | int dummysoc ; | |
841 | const struct afswtch *afp; | |
842 | { | |
843 | if (afp->af_af != AF_INET6) | |
844 | err(1, "address flags can be set only for inet6 addresses"); | |
845 | ||
846 | if (flag < 0) | |
847 | in6_addreq.ifra_flags &= ~(-flag); | |
848 | else | |
849 | in6_addreq.ifra_flags |= flag; | |
850 | } | |
851 | ||
852 | void | |
853 | setip6pltime(seconds, dummy, s, afp) | |
854 | const char *seconds; | |
855 | int dummy ; | |
856 | int s; | |
857 | const struct afswtch *afp; | |
858 | { | |
859 | setip6lifetime("pltime", seconds, s, afp); | |
860 | } | |
861 | ||
862 | void | |
863 | setip6vltime(seconds, dummy, s, afp) | |
864 | const char *seconds; | |
865 | int dummy ; | |
866 | int s; | |
867 | const struct afswtch *afp; | |
868 | { | |
869 | setip6lifetime("vltime", seconds, s, afp); | |
870 | } | |
871 | ||
872 | void | |
873 | setip6lifetime(cmd, val, s, afp) | |
874 | const char *cmd; | |
875 | const char *val; | |
876 | int s; | |
877 | const struct afswtch *afp; | |
878 | { | |
879 | time_t newval, t; | |
880 | char *ep; | |
881 | ||
882 | t = time(NULL); | |
883 | newval = (time_t)strtoul(val, &ep, 0); | |
884 | if (val == ep) | |
885 | errx(1, "invalid %s", cmd); | |
886 | if (afp->af_af != AF_INET6) | |
887 | errx(1, "%s not allowed for the AF", cmd); | |
888 | if (strcmp(cmd, "vltime") == 0) { | |
889 | in6_addreq.ifra_lifetime.ia6t_expire = t + newval; | |
890 | in6_addreq.ifra_lifetime.ia6t_vltime = newval; | |
891 | } else if (strcmp(cmd, "pltime") == 0) { | |
892 | in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; | |
893 | in6_addreq.ifra_lifetime.ia6t_pltime = newval; | |
894 | } | |
895 | } | |
896 | #endif | |
897 | ||
b7080c8e A |
898 | void |
899 | setifbroadaddr(addr, dummy, s, afp) | |
900 | const char *addr; | |
901 | int dummy ; | |
902 | int s; | |
903 | const struct afswtch *afp; | |
904 | { | |
7ba0088d | 905 | if (afp->af_getaddr) |
b7080c8e A |
906 | (*afp->af_getaddr)(addr, DSTADDR); |
907 | } | |
908 | ||
909 | void | |
910 | setifipdst(addr, dummy, s, afp) | |
911 | const char *addr; | |
912 | int dummy ; | |
913 | int s; | |
914 | const struct afswtch *afp; | |
915 | { | |
916 | in_getaddr(addr, DSTADDR); | |
917 | setipdst++; | |
918 | clearaddr = 0; | |
919 | newaddr = 0; | |
920 | } | |
921 | #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) | |
922 | ||
923 | void | |
924 | notealias(addr, param, s, afp) | |
925 | const char *addr; | |
926 | int param; | |
927 | int s; | |
928 | const struct afswtch *afp; | |
929 | { | |
930 | if (setaddr && doalias == 0 && param < 0) | |
931 | bcopy((caddr_t)rqtosa(af_addreq), | |
932 | (caddr_t)rqtosa(af_ridreq), | |
933 | rqtosa(af_addreq)->sa_len); | |
934 | doalias = param; | |
935 | if (param < 0) { | |
936 | clearaddr = 1; | |
937 | newaddr = 0; | |
938 | } else | |
939 | clearaddr = 0; | |
940 | } | |
941 | ||
942 | /*ARGSUSED*/ | |
943 | void | |
944 | setifdstaddr(addr, param, s, afp) | |
945 | const char *addr; | |
946 | int param ; | |
947 | int s; | |
948 | const struct afswtch *afp; | |
949 | { | |
7ba0088d A |
950 | if (*afp->af_getaddr == NULL) |
951 | return; | |
b7080c8e A |
952 | (*afp->af_getaddr)(addr, DSTADDR); |
953 | } | |
954 | ||
7ba0088d A |
955 | /* |
956 | * Note: doing an SIOCIGIFFLAGS scribbles on the union portion | |
957 | * of the ifreq structure, which may confuse other parts of ifconfig. | |
958 | * Make a private copy so we can avoid that. | |
959 | */ | |
b7080c8e A |
960 | void |
961 | setifflags(vname, value, s, afp) | |
962 | const char *vname; | |
963 | int value; | |
964 | int s; | |
965 | const struct afswtch *afp; | |
966 | { | |
7ba0088d A |
967 | struct ifreq my_ifr; |
968 | ||
969 | bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq)); | |
970 | ||
971 | if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { | |
b7080c8e A |
972 | Perror("ioctl (SIOCGIFFLAGS)"); |
973 | exit(1); | |
974 | } | |
7ba0088d A |
975 | strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name)); |
976 | flags = my_ifr.ifr_flags; | |
b7080c8e A |
977 | |
978 | if (value < 0) { | |
979 | value = -value; | |
980 | flags &= ~value; | |
981 | } else | |
982 | flags |= value; | |
7ba0088d A |
983 | my_ifr.ifr_flags = flags; |
984 | if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) | |
b7080c8e A |
985 | Perror(vname); |
986 | } | |
987 | ||
988 | void | |
989 | setifmetric(val, dummy, s, afp) | |
990 | const char *val; | |
991 | int dummy ; | |
992 | int s; | |
993 | const struct afswtch *afp; | |
994 | { | |
995 | strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); | |
996 | ifr.ifr_metric = atoi(val); | |
997 | if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) | |
998 | warn("ioctl (set metric)"); | |
999 | } | |
1000 | ||
1001 | void | |
1002 | setifmtu(val, dummy, s, afp) | |
1003 | const char *val; | |
1004 | int dummy ; | |
1005 | int s; | |
1006 | const struct afswtch *afp; | |
1007 | { | |
1008 | strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); | |
1009 | ifr.ifr_mtu = atoi(val); | |
1010 | if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) | |
1011 | warn("ioctl (set mtu)"); | |
1012 | } | |
1013 | ||
7ba0088d A |
1014 | void |
1015 | setiflladdr(val, dummy, s, afp) | |
1016 | const char *val; | |
1017 | int dummy; | |
1018 | int s; | |
1019 | const struct afswtch *afp; | |
1020 | { | |
1021 | struct ether_addr *ea; | |
1022 | ||
1023 | ea = ether_aton(val); | |
1024 | if (ea == NULL) { | |
1025 | warn("malformed link-level address"); | |
1026 | return; | |
1027 | } | |
1028 | strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); | |
1029 | ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; | |
1030 | ifr.ifr_addr.sa_family = AF_LINK; | |
1031 | bcopy(ea, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN); | |
1032 | if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0) | |
1033 | warn("ioctl (set lladdr)"); | |
1034 | ||
1035 | return; | |
1036 | } | |
b7080c8e A |
1037 | |
1038 | #define IFFBITS \ | |
7ba0088d | 1039 | "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \ |
b7080c8e A |
1040 | "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ |
1041 | "\20MULTICAST" | |
1042 | ||
1043 | /* | |
1044 | * Print the status of the interface. If an address family was | |
1045 | * specified, show it and it only; otherwise, show them all. | |
1046 | */ | |
1047 | void | |
1048 | status(afp, addrcount, sdl, ifm, ifam) | |
1049 | const struct afswtch *afp; | |
1050 | int addrcount; | |
1051 | struct sockaddr_dl *sdl; | |
1052 | struct if_msghdr *ifm; | |
1053 | struct ifa_msghdr *ifam; | |
1054 | { | |
1055 | const struct afswtch *p = NULL; | |
1056 | struct rt_addrinfo info; | |
1057 | int allfamilies, s; | |
7ba0088d | 1058 | struct ifstat ifs; |
b7080c8e A |
1059 | |
1060 | if (afp == NULL) { | |
1061 | allfamilies = 1; | |
1062 | afp = &afs[0]; | |
1063 | } else | |
1064 | allfamilies = 0; | |
1065 | ||
7ba0088d | 1066 | ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; |
b7080c8e A |
1067 | strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); |
1068 | ||
1069 | if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) | |
1070 | err(1, "socket"); | |
1071 | ||
1072 | /* | |
1073 | * XXX is it we are doing a SIOCGIFMETRIC etc for one family. | |
1074 | * is it possible that the metric and mtu can be different for | |
1075 | * each family? If so, we have a format problem, because the | |
1076 | * metric and mtu is printed on the global the flags line. | |
1077 | */ | |
1078 | if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0) | |
1079 | warn("ioctl (SIOCGIFMETRIC)"); | |
1080 | else | |
1081 | metric = ifr.ifr_metric; | |
1082 | ||
1083 | if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) | |
1084 | warn("ioctl (SIOCGIFMTU)"); | |
1085 | else | |
1086 | mtu = ifr.ifr_mtu; | |
1087 | ||
1088 | printf("%s: ", name); | |
1089 | printb("flags", flags, IFFBITS); | |
1090 | if (metric) | |
1091 | printf(" metric %d", metric); | |
1092 | if (mtu) | |
1093 | printf(" mtu %d", mtu); | |
1094 | putchar('\n'); | |
1095 | ||
7ba0088d A |
1096 | tunnel_status(s); |
1097 | ||
b7080c8e A |
1098 | while (addrcount > 0) { |
1099 | ||
1100 | info.rti_addrs = ifam->ifam_addrs; | |
1101 | ||
1102 | /* Expand the compacted addresses */ | |
1103 | rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, | |
1104 | &info); | |
1105 | ||
1106 | if (!allfamilies) { | |
7ba0088d | 1107 | if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family) { |
b7080c8e A |
1108 | p = afp; |
1109 | (*p->af_status)(s, &info); | |
1110 | } | |
1111 | } else for (p = afs; p->af_name; p++) { | |
7ba0088d | 1112 | if (p->af_af == info.rti_info[RTAX_IFA]->sa_family) |
b7080c8e A |
1113 | (*p->af_status)(s, &info); |
1114 | } | |
1115 | addrcount--; | |
1116 | ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); | |
1117 | } | |
1118 | if (allfamilies || afp->af_status == ether_status) | |
1119 | ether_status(s, (struct rt_addrinfo *)sdl); | |
1120 | #if USE_IF_MEDIA | |
1121 | if (allfamilies || afp->af_status == media_status) | |
1122 | media_status(s, NULL); | |
1123 | #endif | |
7ba0088d A |
1124 | #ifdef USE_VLANS |
1125 | if (allfamilies || afp->af_status == vlan_status) | |
1126 | vlan_status(s, NULL); | |
1127 | #endif | |
2b484d24 A |
1128 | #ifdef USE_BONDS |
1129 | if (allfamilies || afp->af_status == bond_status) | |
1130 | bond_status(s, NULL); | |
1131 | #endif | |
7ba0088d A |
1132 | #ifdef USE_IEEE80211 |
1133 | if (allfamilies || afp->af_status == ieee80211_status) | |
1134 | ieee80211_status(s, NULL); | |
1135 | #endif | |
1136 | strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name); | |
1137 | if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) | |
1138 | printf("%s", ifs.ascii); | |
1139 | ||
1140 | if (!allfamilies && !p && afp->af_status != media_status && | |
1141 | afp->af_status != ether_status | |
1142 | #ifdef USE_VLANS | |
1143 | && afp->af_status != vlan_status | |
1144 | #endif | |
1145 | ) | |
b7080c8e A |
1146 | warnx("%s has no %s interface address!", name, afp->af_name); |
1147 | ||
1148 | close(s); | |
1149 | return; | |
1150 | } | |
1151 | ||
7ba0088d A |
1152 | void |
1153 | tunnel_status(s) | |
1154 | int s; | |
1155 | { | |
1156 | char psrcaddr[NI_MAXHOST]; | |
1157 | char pdstaddr[NI_MAXHOST]; | |
1158 | u_long srccmd, dstcmd; | |
1159 | struct ifreq *ifrp; | |
1160 | const char *ver = ""; | |
1161 | #ifdef NI_WITHSCOPEID | |
1162 | const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; | |
1163 | #else | |
1164 | const int niflag = NI_NUMERICHOST; | |
1165 | #endif | |
1166 | #ifdef INET6 | |
1167 | struct in6_ifreq in6_ifr; | |
1168 | int s6; | |
1169 | #endif /* INET6 */ | |
1170 | ||
1171 | psrcaddr[0] = pdstaddr[0] = '\0'; | |
1172 | ||
1173 | #ifdef INET6 | |
1174 | memset(&in6_ifr, 0, sizeof(in6_ifr)); | |
1175 | strncpy(in6_ifr.ifr_name, name, IFNAMSIZ); | |
1176 | s6 = socket(AF_INET6, SOCK_DGRAM, 0); | |
1177 | if (s6 < 0) { | |
1178 | srccmd = SIOCGIFPSRCADDR; | |
1179 | dstcmd = SIOCGIFPDSTADDR; | |
1180 | ifrp = 𝔦 | |
1181 | } else { | |
1182 | close(s6); | |
1183 | srccmd = SIOCGIFPSRCADDR_IN6; | |
1184 | dstcmd = SIOCGIFPDSTADDR_IN6; | |
1185 | ifrp = (struct ifreq *)&in6_ifr; | |
1186 | } | |
1187 | #else /* INET6 */ | |
1188 | srccmd = SIOCGIFPSRCADDR; | |
1189 | dstcmd = SIOCGIFPDSTADDR; | |
1190 | ifrp = 𝔦 | |
1191 | #endif /* INET6 */ | |
1192 | ||
1193 | if (ioctl(s, srccmd, (caddr_t)ifrp) < 0) | |
1194 | return; | |
1195 | #ifdef INET6 | |
1196 | if (ifrp->ifr_addr.sa_family == AF_INET6) | |
1197 | in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); | |
1198 | #endif | |
1199 | getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, | |
1200 | psrcaddr, sizeof(psrcaddr), 0, 0, niflag); | |
1201 | #ifdef INET6 | |
1202 | if (ifrp->ifr_addr.sa_family == AF_INET6) | |
1203 | ver = "6"; | |
1204 | #endif | |
1205 | ||
1206 | if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0) | |
1207 | return; | |
1208 | #ifdef INET6 | |
1209 | if (ifrp->ifr_addr.sa_family == AF_INET6) | |
1210 | in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); | |
1211 | #endif | |
1212 | getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, | |
1213 | pdstaddr, sizeof(pdstaddr), 0, 0, niflag); | |
1214 | ||
1215 | printf("\ttunnel inet%s %s --> %s\n", ver, | |
1216 | psrcaddr, pdstaddr); | |
1217 | } | |
1218 | ||
b7080c8e A |
1219 | void |
1220 | in_status(s, info) | |
1221 | int s ; | |
1222 | struct rt_addrinfo * info; | |
1223 | { | |
1224 | struct sockaddr_in *sin, null_sin; | |
1225 | ||
1226 | memset(&null_sin, 0, sizeof(null_sin)); | |
1227 | ||
1228 | sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA]; | |
1229 | printf("\tinet %s ", inet_ntoa(sin->sin_addr)); | |
1230 | ||
1231 | if (flags & IFF_POINTOPOINT) { | |
1232 | /* note RTAX_BRD overlap with IFF_BROADCAST */ | |
1233 | sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD]; | |
1234 | if (!sin) | |
1235 | sin = &null_sin; | |
1236 | printf("--> %s ", inet_ntoa(sin->sin_addr)); | |
1237 | } | |
1238 | ||
1239 | sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK]; | |
1240 | if (!sin) | |
1241 | sin = &null_sin; | |
1242 | printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); | |
1243 | ||
1244 | if (flags & IFF_BROADCAST) { | |
1245 | /* note RTAX_BRD overlap with IFF_POINTOPOINT */ | |
1246 | sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD]; | |
1247 | if (sin && sin->sin_addr.s_addr != 0) | |
1248 | printf("broadcast %s", inet_ntoa(sin->sin_addr)); | |
1249 | } | |
1250 | putchar('\n'); | |
1251 | } | |
1252 | ||
7ba0088d A |
1253 | #ifdef INET6 |
1254 | void | |
1255 | in6_fillscopeid(sin6) | |
1256 | struct sockaddr_in6 *sin6; | |
1257 | { | |
1258 | #if defined(__KAME__) && defined(KAME_SCOPEID) | |
1259 | if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { | |
1260 | sin6->sin6_scope_id = | |
1261 | ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); | |
1262 | sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; | |
1263 | } | |
1264 | #endif | |
1265 | } | |
1266 | ||
1267 | void | |
1268 | in6_status(s, info) | |
1269 | int s ; | |
1270 | struct rt_addrinfo * info; | |
1271 | { | |
1272 | struct sockaddr_in6 *sin, null_sin; | |
1273 | struct in6_ifreq ifr6; | |
1274 | int s6; | |
1275 | u_int32_t flags6; | |
1276 | struct in6_addrlifetime lifetime; | |
1277 | time_t t = time(NULL); | |
1278 | int error; | |
1279 | u_int32_t scopeid; | |
1280 | ||
1281 | memset(&null_sin, 0, sizeof(null_sin)); | |
1282 | ||
1283 | sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA]; | |
1284 | strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); | |
1285 | if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { | |
1286 | perror("ifconfig: socket"); | |
1287 | return; | |
1288 | } | |
1289 | ifr6.ifr_addr = *sin; | |
1290 | if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) { | |
1291 | perror("ifconfig: ioctl(SIOCGIFAFLAG_IN6)"); | |
1292 | close(s6); | |
1293 | return; | |
1294 | } | |
1295 | flags6 = ifr6.ifr_ifru.ifru_flags6; | |
1296 | memset(&lifetime, 0, sizeof(lifetime)); | |
1297 | ifr6.ifr_addr = *sin; | |
1298 | if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) { | |
1299 | perror("ifconfig: ioctl(SIOCGIFALIFETIME_IN6)"); | |
1300 | close(s6); | |
1301 | return; | |
1302 | } | |
1303 | lifetime = ifr6.ifr_ifru.ifru_lifetime; | |
1304 | close(s6); | |
1305 | ||
1306 | /* XXX: embedded link local addr check */ | |
1307 | if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && | |
1308 | *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { | |
1309 | u_short index; | |
1310 | ||
1311 | index = *(u_short *)&sin->sin6_addr.s6_addr[2]; | |
1312 | *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; | |
1313 | if (sin->sin6_scope_id == 0) | |
1314 | sin->sin6_scope_id = ntohs(index); | |
1315 | } | |
1316 | scopeid = sin->sin6_scope_id; | |
1317 | ||
1318 | error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, | |
1319 | sizeof(addr_buf), NULL, 0, | |
1320 | NI_NUMERICHOST|NI_WITHSCOPEID); | |
1321 | if (error != 0) | |
1322 | inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, | |
1323 | sizeof(addr_buf)); | |
1324 | printf("\tinet6 %s ", addr_buf); | |
1325 | ||
1326 | if (flags & IFF_POINTOPOINT) { | |
1327 | /* note RTAX_BRD overlap with IFF_BROADCAST */ | |
1328 | sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD]; | |
1329 | /* | |
1330 | * some of the interfaces do not have valid destination | |
1331 | * address. | |
1332 | */ | |
1333 | if (sin && sin->sin6_family == AF_INET6) { | |
1334 | int error; | |
1335 | ||
1336 | /* XXX: embedded link local addr check */ | |
1337 | if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && | |
1338 | *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { | |
1339 | u_short index; | |
1340 | ||
1341 | index = *(u_short *)&sin->sin6_addr.s6_addr[2]; | |
1342 | *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; | |
1343 | if (sin->sin6_scope_id == 0) | |
1344 | sin->sin6_scope_id = ntohs(index); | |
1345 | } | |
1346 | ||
1347 | error = getnameinfo((struct sockaddr *)sin, | |
1348 | sin->sin6_len, addr_buf, | |
1349 | sizeof(addr_buf), NULL, 0, | |
1350 | NI_NUMERICHOST|NI_WITHSCOPEID); | |
1351 | if (error != 0) | |
1352 | inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, | |
1353 | sizeof(addr_buf)); | |
1354 | printf("--> %s ", addr_buf); | |
1355 | } | |
1356 | } | |
1357 | ||
1358 | sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK]; | |
1359 | if (!sin) | |
1360 | sin = &null_sin; | |
1361 | printf("prefixlen %d ", prefix(&sin->sin6_addr, | |
1362 | sizeof(struct in6_addr))); | |
1363 | ||
1364 | if ((flags6 & IN6_IFF_ANYCAST) != 0) | |
1365 | printf("anycast "); | |
1366 | if ((flags6 & IN6_IFF_TENTATIVE) != 0) | |
1367 | printf("tentative "); | |
1368 | if ((flags6 & IN6_IFF_DUPLICATED) != 0) | |
1369 | printf("duplicated "); | |
1370 | if ((flags6 & IN6_IFF_DETACHED) != 0) | |
1371 | printf("detached "); | |
1372 | if ((flags6 & IN6_IFF_DEPRECATED) != 0) | |
1373 | printf("deprecated "); | |
1374 | if ((flags6 & IN6_IFF_AUTOCONF) != 0) | |
1375 | printf("autoconf "); | |
1376 | if ((flags6 & IN6_IFF_TEMPORARY) != 0) | |
1377 | printf("temporary "); | |
1378 | ||
1379 | if (scopeid) | |
1380 | printf("scopeid 0x%x ", scopeid); | |
1381 | ||
1382 | if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) { | |
1383 | printf("pltime "); | |
1384 | if (lifetime.ia6t_preferred) { | |
1385 | printf("%s ", lifetime.ia6t_preferred < t | |
1386 | ? "0" : sec2str(lifetime.ia6t_preferred - t)); | |
1387 | } else | |
1388 | printf("infty "); | |
1389 | ||
1390 | printf("vltime "); | |
1391 | if (lifetime.ia6t_expire) { | |
1392 | printf("%s ", lifetime.ia6t_expire < t | |
1393 | ? "0" : sec2str(lifetime.ia6t_expire - t)); | |
1394 | } else | |
1395 | printf("infty "); | |
1396 | } | |
1397 | ||
1398 | putchar('\n'); | |
1399 | } | |
1400 | #endif /*INET6*/ | |
1401 | ||
1402 | #ifdef NS | |
1403 | void | |
1404 | xns_status(s, info) | |
1405 | int s ; | |
1406 | struct rt_addrinfo * info; | |
1407 | { | |
1408 | struct sockaddr_ns *sns, null_sns; | |
1409 | ||
1410 | memset(&null_sns, 0, sizeof(null_sns)); | |
1411 | ||
1412 | sns = (struct sockaddr_ns *)info->rti_info[RTAX_IFA]; | |
1413 | printf("\tns %s ", ns_ntoa(sns->sns_addr)); | |
1414 | ||
1415 | if (flags & IFF_POINTOPOINT) { | |
1416 | sns = (struct sockaddr_ns *)info->rti_info[RTAX_BRD]; | |
1417 | if (!sns) | |
1418 | sns = &null_sns; | |
1419 | printf("--> %s ", ns_ntoa(sns->sns_addr)); | |
1420 | } | |
1421 | ||
1422 | putchar('\n'); | |
1423 | close(s); | |
1424 | } | |
1425 | #endif | |
1426 | ||
1427 | ||
b7080c8e A |
1428 | void |
1429 | ether_status(s, info) | |
1430 | int s ; | |
1431 | struct rt_addrinfo *info; | |
1432 | { | |
1433 | char *cp; | |
1434 | int n; | |
1435 | struct sockaddr_dl *sdl = (struct sockaddr_dl *)info; | |
1436 | ||
1437 | cp = (char *)LLADDR(sdl); | |
1438 | if ((n = sdl->sdl_alen) > 0) { | |
1439 | if (sdl->sdl_type == IFT_ETHER) | |
1440 | printf ("\tether "); | |
1441 | else | |
1442 | printf ("\tlladdr "); | |
1443 | while (--n >= 0) | |
1444 | printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' '); | |
1445 | putchar('\n'); | |
1446 | } | |
1447 | } | |
1448 | ||
1449 | void | |
1450 | Perror(cmd) | |
1451 | const char *cmd; | |
1452 | { | |
1453 | switch (errno) { | |
1454 | ||
1455 | case ENXIO: | |
1456 | errx(1, "%s: no such interface", cmd); | |
1457 | break; | |
1458 | ||
1459 | case EPERM: | |
1460 | errx(1, "%s: permission denied", cmd); | |
1461 | break; | |
1462 | ||
1463 | default: | |
1464 | err(1, "%s", cmd); | |
1465 | } | |
1466 | } | |
1467 | ||
1468 | #define SIN(x) ((struct sockaddr_in *) &(x)) | |
1469 | struct sockaddr_in *sintab[] = { | |
1470 | SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr), | |
1471 | SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)}; | |
1472 | ||
1473 | void | |
1474 | in_getaddr(s, which) | |
1475 | const char *s; | |
1476 | int which; | |
1477 | { | |
1478 | register struct sockaddr_in *sin = sintab[which]; | |
1479 | struct hostent *hp; | |
1480 | struct netent *np; | |
1481 | ||
1482 | sin->sin_len = sizeof(*sin); | |
7902cf7e | 1483 | if (which != NMASK) |
b7080c8e A |
1484 | sin->sin_family = AF_INET; |
1485 | ||
7ba0088d A |
1486 | if (which == ADDR) { |
1487 | char *p = NULL; | |
1488 | ||
1489 | if((p = strrchr(s, '/')) != NULL) { | |
1490 | /* address is `name/masklen' */ | |
1491 | int masklen; | |
1492 | int ret; | |
7902cf7e | 1493 | struct sockaddr_in *min = sintab[NMASK]; |
7ba0088d A |
1494 | *p = '\0'; |
1495 | ret = sscanf(p+1, "%u", &masklen); | |
1496 | if(ret != 1 || (masklen < 0 || masklen > 32)) { | |
1497 | *p = '/'; | |
1498 | errx(1, "%s: bad value", s); | |
1499 | } | |
1500 | min->sin_len = sizeof(*min); | |
1501 | min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & | |
1502 | 0xffffffff); | |
1503 | } | |
1504 | } | |
1505 | ||
b7080c8e A |
1506 | if (inet_aton(s, &sin->sin_addr)) |
1507 | return; | |
1508 | if ((hp = gethostbyname(s)) != 0) | |
1509 | bcopy(hp->h_addr, (char *)&sin->sin_addr, | |
1510 | MIN(hp->h_length, sizeof(sin->sin_addr))); | |
1511 | else if ((np = getnetbyname(s)) != 0) | |
1512 | sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); | |
1513 | else | |
1514 | errx(1, "%s: bad value", s); | |
1515 | } | |
1516 | ||
7ba0088d A |
1517 | #ifdef INET6 |
1518 | #define SIN6(x) ((struct sockaddr_in6 *) &(x)) | |
1519 | struct sockaddr_in6 *sin6tab[] = { | |
1520 | SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr), | |
1521 | SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)}; | |
1522 | ||
1523 | void | |
1524 | in6_getaddr(s, which) | |
1525 | const char *s; | |
1526 | int which; | |
1527 | { | |
1528 | register struct sockaddr_in6 *sin = sin6tab[which]; | |
1529 | struct addrinfo hints, *res; | |
1530 | int error = -1; | |
1531 | ||
1532 | newaddr &= 1; | |
1533 | ||
1534 | sin->sin6_len = sizeof(*sin); | |
7902cf7e | 1535 | if (which != NMASK) |
7ba0088d A |
1536 | sin->sin6_family = AF_INET6; |
1537 | ||
1538 | if (which == ADDR) { | |
1539 | char *p = NULL; | |
1540 | if((p = strrchr(s, '/')) != NULL) { | |
1541 | *p = '\0'; | |
7902cf7e | 1542 | in6_getprefix(p + 1, NMASK); |
7ba0088d A |
1543 | explicit_prefix = 1; |
1544 | } | |
1545 | } | |
1546 | ||
1547 | if (sin->sin6_family == AF_INET6) { | |
1548 | bzero(&hints, sizeof(struct addrinfo)); | |
1549 | hints.ai_family = AF_INET6; | |
1550 | error = getaddrinfo(s, NULL, &hints, &res); | |
1551 | } | |
1552 | if (error != 0) { | |
1553 | if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1) | |
1554 | errx(1, "%s: bad value", s); | |
1555 | } else | |
1556 | bcopy(res->ai_addr, sin, res->ai_addrlen); | |
1557 | } | |
1558 | ||
1559 | void | |
1560 | in6_getprefix(plen, which) | |
1561 | const char *plen; | |
1562 | int which; | |
1563 | { | |
1564 | register struct sockaddr_in6 *sin = sin6tab[which]; | |
1565 | register u_char *cp; | |
1566 | int len = atoi(plen); | |
1567 | ||
1568 | if ((len < 0) || (len > 128)) | |
1569 | errx(1, "%s: bad value", plen); | |
1570 | sin->sin6_len = sizeof(*sin); | |
7902cf7e | 1571 | if (which != NMASK) |
7ba0088d A |
1572 | sin->sin6_family = AF_INET6; |
1573 | if ((len == 0) || (len == 128)) { | |
1574 | memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr)); | |
1575 | return; | |
1576 | } | |
1577 | memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr)); | |
1578 | for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8) | |
1579 | *cp++ = 0xff; | |
1580 | *cp = 0xff << (8 - len); | |
1581 | } | |
1582 | #endif | |
1583 | ||
b7080c8e A |
1584 | /* |
1585 | * Print a value a la the %b format of the kernel's printf | |
1586 | */ | |
1587 | void | |
1588 | printb(s, v, bits) | |
1589 | const char *s; | |
1590 | register unsigned v; | |
1591 | register const char *bits; | |
1592 | { | |
1593 | register int i, any = 0; | |
1594 | register char c; | |
1595 | ||
1596 | if (bits && *bits == 8) | |
1597 | printf("%s=%o", s, v); | |
1598 | else | |
1599 | printf("%s=%x", s, v); | |
1600 | bits++; | |
1601 | if (bits) { | |
1602 | putchar('<'); | |
1603 | while ((i = *bits++) != '\0') { | |
1604 | if (v & (1 << (i-1))) { | |
1605 | if (any) | |
1606 | putchar(','); | |
1607 | any = 1; | |
1608 | for (; (c = *bits) > 32; bits++) | |
1609 | putchar(c); | |
1610 | } else | |
1611 | for (; *bits > 32; bits++) | |
1612 | ; | |
1613 | } | |
1614 | putchar('>'); | |
1615 | } | |
1616 | } | |
1617 | ||
7ba0088d A |
1618 | void |
1619 | ether_getaddr(addr, which) | |
1620 | const char *addr; | |
1621 | int which; | |
1622 | { | |
1623 | struct ether_addr *ea; | |
1624 | struct sockaddr *sea = &ridreq.ifr_addr; | |
1625 | ||
1626 | ea = ether_aton(addr); | |
1627 | if (ea == NULL) | |
1628 | errx(1, "malformed ether address"); | |
7902cf7e | 1629 | if (which == NMASK) |
7ba0088d A |
1630 | errx(1, "Ethernet does not use netmasks"); |
1631 | sea->sa_family = AF_LINK; | |
1632 | sea->sa_len = ETHER_ADDR_LEN; | |
1633 | bcopy(ea, sea->sa_data, ETHER_ADDR_LEN); | |
1634 | } | |
1635 | ||
1636 | #ifdef INET6 | |
1637 | int | |
1638 | prefix(val, size) | |
1639 | void *val; | |
1640 | int size; | |
1641 | { | |
1642 | register u_char *name = (u_char *)val; | |
1643 | register int byte, bit, plen = 0; | |
1644 | ||
1645 | for (byte = 0; byte < size; byte++, plen += 8) | |
1646 | if (name[byte] != 0xff) | |
1647 | break; | |
1648 | if (byte == size) | |
1649 | return (plen); | |
1650 | for (bit = 7; bit != 0; bit--, plen++) | |
1651 | if (!(name[byte] & (1 << bit))) | |
1652 | break; | |
1653 | for (; bit != 0; bit--) | |
1654 | if (name[byte] & (1 << bit)) | |
1655 | return(0); | |
1656 | byte++; | |
1657 | for (; byte < size; byte++) | |
1658 | if (name[byte]) | |
1659 | return(0); | |
1660 | return (plen); | |
1661 | } | |
1662 | ||
1663 | static char * | |
1664 | sec2str(total) | |
1665 | time_t total; | |
1666 | { | |
1667 | static char result[256]; | |
1668 | int days, hours, mins, secs; | |
1669 | int first = 1; | |
1670 | char *p = result; | |
1671 | ||
1672 | if (0) { | |
1673 | days = total / 3600 / 24; | |
1674 | hours = (total / 3600) % 24; | |
1675 | mins = (total / 60) % 60; | |
1676 | secs = total % 60; | |
1677 | ||
1678 | if (days) { | |
1679 | first = 0; | |
1680 | p += sprintf(p, "%dd", days); | |
1681 | } | |
1682 | if (!first || hours) { | |
1683 | first = 0; | |
1684 | p += sprintf(p, "%dh", hours); | |
1685 | } | |
1686 | if (!first || mins) { | |
1687 | first = 0; | |
1688 | p += sprintf(p, "%dm", mins); | |
1689 | } | |
1690 | sprintf(p, "%ds", secs); | |
1691 | } else | |
1692 | sprintf(result, "%lu", (unsigned long)total); | |
1693 | ||
1694 | return(result); | |
1695 | } | |
1696 | #endif /*INET6*/ | |
b7080c8e | 1697 | |
7902cf7e A |
1698 | void |
1699 | clone_create(void) | |
1700 | { | |
1701 | int s; | |
1702 | ||
1703 | s = socket(AF_INET, SOCK_DGRAM, 0); | |
1704 | if (s == -1) | |
1705 | err(1, "socket"); | |
1706 | ||
1707 | memset(&ifr, 0, sizeof(ifr)); | |
1708 | (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |
1709 | if (ioctl(s, SIOCIFCREATE, &ifr) < 0) | |
1710 | err(1, "SIOCIFCREATE"); | |
1711 | ||
1712 | if (strcmp(name, ifr.ifr_name) != 0) { | |
1713 | printf("%s\n", ifr.ifr_name); | |
1714 | strlcpy(name, ifr.ifr_name, sizeof(name)); | |
1715 | } | |
1716 | ||
1717 | close(s); | |
1718 | } | |
1719 | ||
1720 | void | |
1721 | clone_destroy(const char *val, int d, int s, const struct afswtch *rafp) | |
1722 | { | |
1723 | ||
1724 | (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |
1725 | if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) | |
1726 | err(1, "SIOCIFDESTROY"); | |
1727 | } |