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