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