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