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