ifconfig.c revision 1.84 1 /* $NetBSD: ifconfig.c,v 1.84 2000/07/06 08:20:51 onoe Exp $ */
2
3 /*-
4 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Copyright (c) 1983, 1993
42 * The Regents of the University of California. All rights reserved.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
71 */
72
73 #include <sys/cdefs.h>
74 #ifndef lint
75 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
76 The Regents of the University of California. All rights reserved.\n");
77 #endif /* not lint */
78
79 #ifndef lint
80 #if 0
81 static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
82 #else
83 __RCSID("$NetBSD: ifconfig.c,v 1.84 2000/07/06 08:20:51 onoe Exp $");
84 #endif
85 #endif /* not lint */
86
87 #include <sys/param.h>
88 #include <sys/socket.h>
89 #include <sys/ioctl.h>
90
91 #include <net/if.h>
92 #include <net/if_dl.h>
93 #include <net/if_media.h>
94 #include <net/if_ether.h>
95 #include <net/if_ieee80211.h>
96 #include <netinet/in.h>
97 #include <netinet/in_var.h>
98 #ifdef INET6
99 #include <netinet6/nd6.h>
100 #endif
101 #include <arpa/inet.h>
102
103 #include <netatalk/at.h>
104
105 #define NSIP
106 #include <netns/ns.h>
107 #include <netns/ns_if.h>
108 #include <netdb.h>
109
110 #define EON
111 #include <netiso/iso.h>
112 #include <netiso/iso_var.h>
113 #include <sys/protosw.h>
114
115 #include <ctype.h>
116 #include <err.h>
117 #include <errno.h>
118 #include <stddef.h>
119 #include <stdio.h>
120 #include <stdlib.h>
121 #include <string.h>
122 #include <unistd.h>
123 #ifdef HAVE_IFADDRS_H
124 #include <ifaddrs.h>
125 #endif
126
127 struct ifreq ifr, ridreq;
128 struct ifaliasreq addreq __attribute__((aligned(4)));
129 #ifdef INET6
130 struct in6_ifreq ifr6;
131 struct in6_ifreq in6_ridreq;
132 struct in6_aliasreq in6_addreq __attribute__((aligned(4)));
133 #endif
134 struct iso_ifreq iso_ridreq;
135 struct iso_aliasreq iso_addreq;
136 struct sockaddr_in netmask;
137 struct netrange at_nr; /* AppleTalk net range */
138
139 char name[30];
140 int flags, metric, mtu, setaddr, setipdst, doalias;
141 int clearaddr, s;
142 int newaddr = -1;
143 int nsellength = 1;
144 int af;
145 int Aflag, aflag, bflag, dflag, lflag, mflag, sflag, uflag;
146 #ifdef INET6
147 int Lflag;
148 #endif
149 int reset_if_flags;
150 int explicit_prefix = 0;
151
152 void notealias __P((const char *, int));
153 void notrailers __P((const char *, int));
154 void setifaddr __P((const char *, int));
155 void setifdstaddr __P((const char *, int));
156 void setifflags __P((const char *, int));
157 void setifbroadaddr __P((const char *, int));
158 void setifipdst __P((const char *, int));
159 void setifmetric __P((const char *, int));
160 void setifmtu __P((const char *, int));
161 void setifnwid __P((const char *, int));
162 void setifnetmask __P((const char *, int));
163 void setifprefixlen __P((const char *, int));
164 void setnsellength __P((const char *, int));
165 void setsnpaoffset __P((const char *, int));
166 void setatrange __P((const char *, int));
167 void setatphase __P((const char *, int));
168 void settunnel __P((const char *, const char *));
169 void deletetunnel __P((const char *, int));
170 #ifdef INET6
171 void setia6flags __P((const char *, int));
172 void setia6pltime __P((const char *, int));
173 void setia6vltime __P((const char *, int));
174 void setia6lifetime __P((const char *, const char *));
175 #endif
176 void checkatrange __P ((struct sockaddr_at *));
177 void setmedia __P((const char *, int));
178 void setmediaopt __P((const char *, int));
179 void unsetmediaopt __P((const char *, int));
180 void setmediainst __P((const char *, int));
181 void clone_create __P((const char *, int));
182 void clone_destroy __P((const char *, int));
183 void fixnsel __P((struct sockaddr_iso *));
184 int main __P((int, char *[]));
185
186 /*
187 * Media stuff. Whenever a media command is first performed, the
188 * currently select media is grabbed for this interface. If `media'
189 * is given, the current media word is modifed. `mediaopt' commands
190 * only modify the set and clear words. They then operate on the
191 * current media word later.
192 */
193 int media_current;
194 int mediaopt_set;
195 int mediaopt_clear;
196
197 int actions; /* Actions performed */
198
199 #define A_MEDIA 0x0001 /* media command */
200 #define A_MEDIAOPTSET 0x0002 /* mediaopt command */
201 #define A_MEDIAOPTCLR 0x0004 /* -mediaopt command */
202 #define A_MEDIAOPT (A_MEDIAOPTSET|A_MEDIAOPTCLR)
203 #define A_MEDIAINST 0x0008 /* instance or inst command */
204
205 #define NEXTARG 0xffffff
206 #define NEXTARG2 0xfffffe
207
208 const struct cmd {
209 const char *c_name;
210 int c_parameter; /* NEXTARG means next argv */
211 int c_action; /* defered action */
212 void (*c_func) __P((const char *, int));
213 void (*c_func2) __P((const char *, const char *));
214 } cmds[] = {
215 { "up", IFF_UP, 0, setifflags } ,
216 { "down", -IFF_UP, 0, setifflags },
217 { "trailers", -1, 0, notrailers },
218 { "-trailers", 1, 0, notrailers },
219 { "arp", -IFF_NOARP, 0, setifflags },
220 { "-arp", IFF_NOARP, 0, setifflags },
221 { "debug", IFF_DEBUG, 0, setifflags },
222 { "-debug", -IFF_DEBUG, 0, setifflags },
223 { "alias", IFF_UP, 0, notealias },
224 { "-alias", -IFF_UP, 0, notealias },
225 { "delete", -IFF_UP, 0, notealias },
226 #ifdef notdef
227 #define EN_SWABIPS 0x1000
228 { "swabips", EN_SWABIPS, 0, setifflags },
229 { "-swabips", -EN_SWABIPS, 0, setifflags },
230 #endif
231 { "netmask", NEXTARG, 0, setifnetmask },
232 { "metric", NEXTARG, 0, setifmetric },
233 { "mtu", NEXTARG, 0, setifmtu },
234 { "nwid", NEXTARG, 0, setifnwid },
235 { "broadcast", NEXTARG, 0, setifbroadaddr },
236 { "ipdst", NEXTARG, 0, setifipdst },
237 { "prefixlen", NEXTARG, 0, setifprefixlen},
238 #ifdef INET6
239 { "anycast", IN6_IFF_ANYCAST, 0, setia6flags },
240 { "-anycast", -IN6_IFF_ANYCAST, 0, setia6flags },
241 { "tentative", IN6_IFF_TENTATIVE, 0, setia6flags },
242 { "-tentative", -IN6_IFF_TENTATIVE, 0, setia6flags },
243 { "pltime", NEXTARG, 0, setia6pltime },
244 { "vltime", NEXTARG, 0, setia6vltime },
245 #endif /*INET6*/
246 #ifndef INET_ONLY
247 { "range", NEXTARG, 0, setatrange },
248 { "phase", NEXTARG, 0, setatphase },
249 { "snpaoffset", NEXTARG, 0, setsnpaoffset },
250 { "nsellength", NEXTARG, 0, setnsellength },
251 #endif /* INET_ONLY */
252 { "tunnel", NEXTARG2, 0, NULL,
253 settunnel } ,
254 { "deletetunnel", 0, 0, deletetunnel },
255 #if 0
256 /* XXX `create' special-cased below */
257 { "create", 0, 0, clone_create } ,
258 #endif
259 { "destroy", 0, 0, clone_destroy } ,
260 { "link0", IFF_LINK0, 0, setifflags } ,
261 { "-link0", -IFF_LINK0, 0, setifflags } ,
262 { "link1", IFF_LINK1, 0, setifflags } ,
263 { "-link1", -IFF_LINK1, 0, setifflags } ,
264 { "link2", IFF_LINK2, 0, setifflags } ,
265 { "-link2", -IFF_LINK2, 0, setifflags } ,
266 { "media", NEXTARG, A_MEDIA, setmedia },
267 { "mediaopt", NEXTARG, A_MEDIAOPTSET, setmediaopt },
268 { "-mediaopt", NEXTARG, A_MEDIAOPTCLR, unsetmediaopt },
269 { "instance", NEXTARG, A_MEDIAINST, setmediainst },
270 { "inst", NEXTARG, A_MEDIAINST, setmediainst },
271 { 0, 0, 0, setifaddr },
272 { 0, 0, 0, setifdstaddr },
273 };
274
275 void adjust_nsellength __P((void));
276 int getinfo __P((struct ifreq *));
277 int carrier __P((void));
278 void getsock __P((int));
279 void printall __P((void));
280 void printb __P((const char *, unsigned short, const char *));
281 int prefix __P((void *, int));
282 void status __P((const u_int8_t *, int));
283 void usage __P((void));
284 char *sec2str __P((time_t));
285
286 const char *get_media_type_string __P((int));
287 const char *get_media_subtype_string __P((int));
288 int get_media_subtype __P((int, const char *));
289 int get_media_options __P((int, const char *));
290 int lookup_media_word __P((struct ifmedia_description *, int,
291 const char *));
292 void print_media_word __P((int, int, int));
293 void process_media_commands __P((void));
294 void init_current_media __P((void));
295
296 /*
297 * XNS support liberally adapted from code written at the University of
298 * Maryland principally by James O'Toole and Chris Torek.
299 */
300 void in_alias __P((struct ifreq *));
301 void in_status __P((int));
302 void in_getaddr __P((const char *, int));
303 #ifdef INET6
304 void in6_fillscopeid __P((struct sockaddr_in6 *sin6));
305 void in6_alias __P((struct in6_ifreq *));
306 void in6_status __P((int));
307 void in6_getaddr __P((const char *, int));
308 void in6_getprefix __P((const char *, int));
309 #endif
310 void at_status __P((int));
311 void at_getaddr __P((const char *, int));
312 void xns_status __P((int));
313 void xns_getaddr __P((const char *, int));
314 void iso_status __P((int));
315 void iso_getaddr __P((const char *, int));
316
317 void ieee80211_status __P((void));
318 void tunnel_status __P((void));
319
320 /* Known address families */
321 struct afswtch {
322 const char *af_name;
323 short af_af;
324 void (*af_status) __P((int));
325 void (*af_getaddr) __P((const char *, int));
326 void (*af_getprefix) __P((const char *, int));
327 u_long af_difaddr;
328 u_long af_aifaddr;
329 u_long af_gifaddr;
330 caddr_t af_ridreq;
331 caddr_t af_addreq;
332 } afs[] = {
333 #define C(x) ((caddr_t) &x)
334 { "inet", AF_INET, in_status, in_getaddr, NULL,
335 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, C(ridreq), C(addreq) },
336 #ifdef INET6
337 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
338 SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
339 /*
340 * Deleting the first address before setting new one is
341 * not prefered way in this protocol.
342 */
343 0,
344 C(in6_ridreq), C(in6_addreq) },
345 #endif
346 #ifndef INET_ONLY /* small version, for boot media */
347 { "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
348 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, C(addreq), C(addreq) },
349 { "ns", AF_NS, xns_status, xns_getaddr, NULL,
350 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, C(ridreq), C(addreq) },
351 { "iso", AF_ISO, iso_status, iso_getaddr, NULL,
352 SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, SIOCGIFADDR_ISO,
353 C(iso_ridreq), C(iso_addreq) },
354 #endif /* INET_ONLY */
355 { 0, 0, 0, 0 }
356 };
357
358 struct afswtch *afp; /*the address family being set or asked about*/
359
360 struct afswtch *lookup_af __P((const char *));
361
362 int
363 main(argc, argv)
364 int argc;
365 char *argv[];
366 {
367 struct ifreq ifreq;
368 int ch;
369
370 /* Parse command-line options */
371 aflag = mflag = 0;
372 while ((ch = getopt(argc, argv, "Aabdlmsu"
373 #ifdef INET6
374 "L"
375 #endif
376 )) != -1) {
377 switch (ch) {
378 case 'A':
379 Aflag = 1;
380 break;
381
382 case 'a':
383 aflag = 1;
384 break;
385
386 case 'b':
387 bflag = 1;
388 break;
389
390 case 'd':
391 dflag = 1;
392 break;
393
394 #ifdef INET6
395 case 'L':
396 Lflag = 1;
397 break;
398 #endif
399
400 case 'l':
401 lflag = 1;
402 break;
403
404 case 'm':
405 mflag = 1;
406 break;
407
408 case 's':
409 sflag = 1;
410 break;
411
412 case 'u':
413 uflag = 1;
414 break;
415
416
417 default:
418 usage();
419 /* NOTREACHED */
420 }
421 }
422 argc -= optind;
423 argv += optind;
424
425 /*
426 * -l means "list all interfaces", and is mutally exclusive with
427 * all other flags/commands.
428 *
429 * -a means "print status of all interfaces".
430 */
431 if (lflag && (aflag || mflag || Aflag || argc))
432 usage();
433 #ifdef INET6
434 if (lflag && Lflag)
435 usage();
436 #endif
437 if (aflag || lflag) {
438 if (argc > 1)
439 usage();
440 else if (argc == 1) {
441 afp = lookup_af(argv[0]);
442 if (afp == NULL)
443 usage();
444 }
445 if (afp)
446 af = ifr.ifr_addr.sa_family = afp->af_af;
447 else
448 af = ifr.ifr_addr.sa_family = afs[0].af_af;
449 printall();
450 exit(0);
451 }
452
453 /* Make sure there's an interface name. */
454 if (argc < 1)
455 usage();
456 (void) strncpy(name, argv[0], sizeof(name));
457 argc--; argv++;
458
459 /*
460 * NOTE: We must special-case the `create' command right
461 * here as we would otherwise fail in getinfo().
462 */
463 if (argc > 0 && strcmp(argv[0], "create") == 0) {
464 clone_create(argv[0], 0);
465 argc--, argv++;
466 if (argc == 0)
467 exit(0);
468 }
469
470 /* Check for address family. */
471 afp = NULL;
472 if (argc > 0) {
473 afp = lookup_af(argv[0]);
474 if (afp != NULL) {
475 argv++;
476 argc--;
477 }
478 }
479
480 /* Initialize af, just for use in getinfo(). */
481 if (afp == NULL)
482 af = afs->af_af;
483 else
484 af = afp->af_af;
485
486 /* Get information about the interface. */
487 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
488 if (getinfo(&ifr) < 0)
489 exit(1);
490
491 if (sflag) {
492 if (argc != 0)
493 usage();
494 else
495 exit(carrier());
496 }
497
498 /* No more arguments means interface status. */
499 if (argc == 0) {
500 status(NULL, 0);
501 exit(0);
502 }
503
504 /* The following operations assume inet family as the default. */
505 if (afp == NULL)
506 afp = afs;
507 af = ifr.ifr_addr.sa_family = afp->af_af;
508
509 #ifdef INET6
510 /* initialization */
511 in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
512 in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
513 #endif
514
515 /* Process commands. */
516 while (argc > 0) {
517 const struct cmd *p;
518
519 for (p = cmds; p->c_name; p++)
520 if (strcmp(argv[0], p->c_name) == 0)
521 break;
522 if (p->c_name == 0 && setaddr) {
523 if ((flags & IFF_POINTOPOINT) == 0) {
524 errx(1, "can't set destination address %s",
525 "on non-point-to-point link");
526 }
527 p++; /* got src, do dst */
528 }
529 if (p->c_func != NULL || p->c_func2 != NULL) {
530 if (p->c_parameter == NEXTARG) {
531 if (argc < 2)
532 errx(1, "'%s' requires argument",
533 p->c_name);
534 (*p->c_func)(argv[1], 0);
535 argc--, argv++;
536 } else if (p->c_parameter == NEXTARG2) {
537 if (argc < 3)
538 errx(1, "'%s' requires 2 arguments",
539 p->c_name);
540 (*p->c_func2)(argv[1], argv[2]);
541 argc -= 2, argv += 2;
542 } else
543 (*p->c_func)(argv[0], p->c_parameter);
544 actions |= p->c_action;
545 }
546 argc--, argv++;
547 }
548
549 /* Process any media commands that may have been issued. */
550 process_media_commands();
551
552 if (af == AF_INET6 && explicit_prefix == 0) {
553 /*
554 * Aggregatable address architecture defines all prefixes
555 * are 64. So, it is convenient to set prefixlen to 64 if
556 * it is not specified.
557 */
558 setifprefixlen("64", 0);
559 /* in6_getprefix("64", MASK) if MASK is available here... */
560 }
561
562 #ifndef INET_ONLY
563 if (af == AF_ISO)
564 adjust_nsellength();
565
566 if (af == AF_APPLETALK)
567 checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
568
569 if (setipdst && af==AF_NS) {
570 struct nsip_req rq;
571 int size = sizeof(rq);
572
573 rq.rq_ns = addreq.ifra_addr;
574 rq.rq_ip = addreq.ifra_dstaddr;
575
576 if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
577 warn("encapsulation routing");
578 }
579
580 #endif /* INET_ONLY */
581
582 if (clearaddr) {
583 (void) strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
584 if (ioctl(s, afp->af_difaddr, afp->af_ridreq) < 0)
585 err(1, "SIOCDIFADDR");
586 }
587 if (newaddr > 0) {
588 (void) strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
589 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
590 warn("SIOCAIFADDR");
591 }
592
593 if (reset_if_flags) {
594 (void) strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
595 ifreq.ifr_flags = flags;
596 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) < 0)
597 err(1, "SIOCSIFFLAGS");
598 }
599 exit(0);
600 }
601
602 struct afswtch *
603 lookup_af(cp)
604 const char *cp;
605 {
606 struct afswtch *a;
607
608 for (a = afs; a->af_name != NULL; a++)
609 if (strcmp(a->af_name, cp) == 0)
610 return (a);
611 return (NULL);
612 }
613
614 void
615 getsock(naf)
616 int naf;
617 {
618 static int oaf = -1;
619
620 if (oaf == naf)
621 return;
622 if (oaf != -1)
623 close(s);
624 s = socket(naf, SOCK_DGRAM, 0);
625 if (s < 0)
626 oaf = -1;
627 else
628 oaf = naf;
629 }
630
631 int
632 getinfo(ifr)
633 struct ifreq *ifr;
634 {
635
636 getsock(af);
637 if (s < 0)
638 err(1, "socket");
639 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
640 warn("SIOCGIFFLAGS %s", ifr->ifr_name);
641 return (-1);
642 }
643 flags = ifr->ifr_flags;
644 if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0) {
645 warn("SIOCGIFMETRIC %s", ifr->ifr_name);
646 metric = 0;
647 } else
648 metric = ifr->ifr_metric;
649 if (ioctl(s, SIOCGIFMTU, (caddr_t)ifr) < 0)
650 mtu = 0;
651 else
652 mtu = ifr->ifr_mtu;
653 return (0);
654 }
655
656 void
657 printall()
658 {
659 #ifdef HAVE_IFADDRS_H
660 struct ifaddrs *ifap, *ifa;
661 struct ifreq ifr;
662 const struct sockaddr_dl *sdl;
663 int idx;
664 char *p;
665
666 if (getifaddrs(&ifap) != 0)
667 err(1, "getifaddrs");
668 p = NULL;
669 idx = 0;
670 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
671 memset(&ifr, 0, sizeof(ifr));
672 strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
673 if (sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
674 memcpy(&ifr.ifr_addr, ifa->ifa_addr,
675 ifa->ifa_addr->sa_len);
676 }
677
678 if (ifa->ifa_addr->sa_family == AF_LINK)
679 sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
680 if (p && strcmp(p, ifa->ifa_name) == 0)
681 continue;
682 (void) strncpy(name, ifa->ifa_name, sizeof(name));
683 name[sizeof(name) - 1] = '\0';
684 p = ifa->ifa_name;
685
686 if (getinfo(&ifr) < 0)
687 continue;
688 if (bflag && (ifa->ifa_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)))
689 continue;
690 if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
691 continue;
692 if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
693 continue;
694
695 if (sflag && carrier())
696 continue;
697 idx++;
698 /*
699 * Are we just listing the interfaces?
700 */
701 if (lflag) {
702 if (idx > 1)
703 putchar(' ');
704 fputs(name, stdout);
705 continue;
706 }
707
708 if (sdl == NULL) {
709 status(NULL, 0);
710 } else {
711 status(LLADDR(sdl), sdl->sdl_alen);
712 sdl = NULL;
713 }
714 }
715 if (lflag)
716 putchar('\n');
717 freeifaddrs(ifap);
718 #else
719 char inbuf[8192];
720 const struct sockaddr_dl *sdl = NULL;
721 struct ifconf ifc;
722 struct ifreq ifreq, *ifr;
723 int i, siz, idx;
724 char ifrbuf[8192], *cp;
725
726 ifc.ifc_len = sizeof(inbuf);
727 ifc.ifc_buf = inbuf;
728 getsock(af);
729 if (s < 0)
730 err(1, "socket");
731 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
732 err(1, "SIOCGIFCONF");
733 ifreq.ifr_name[0] = '\0';
734 for (i = 0, idx = 0; i < ifc.ifc_len; ) {
735 /* Copy the mininum ifreq into the buffer. */
736 cp = ((caddr_t)ifc.ifc_req + i);
737 memcpy(ifrbuf, cp, sizeof(*ifr));
738
739 /* Now compute the actual size of the ifreq. */
740 ifr = (struct ifreq *)ifrbuf;
741 siz = ifr->ifr_addr.sa_len;
742 if (siz < sizeof(ifr->ifr_addr))
743 siz = sizeof(ifr->ifr_addr);
744 siz += sizeof(ifr->ifr_name);
745 i += siz;
746
747 /* Now copy the whole thing. */
748 if (sizeof(ifrbuf) < siz)
749 errx(1, "ifr too big");
750 memcpy(ifrbuf, cp, siz);
751
752 if (ifr->ifr_addr.sa_family == AF_LINK)
753 sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
754 if (!strncmp(ifreq.ifr_name, ifr->ifr_name,
755 sizeof(ifr->ifr_name)))
756 continue;
757 (void) strncpy(name, ifr->ifr_name, sizeof(ifr->ifr_name));
758 ifreq = *ifr;
759
760 if (getinfo(&ifreq) < 0)
761 continue;
762 if (bflag && (flags & (IFF_POINTOPOINT|IFF_LOOPBACK)))
763 continue;
764 if (dflag && (flags & IFF_UP) != 0)
765 continue;
766 if (uflag && (flags & IFF_UP) == 0)
767 continue;
768
769 if (sflag && carrier())
770 continue;
771 idx++;
772 /*
773 * Are we just listing the interfaces?
774 */
775 if (lflag) {
776 if (idx > 1)
777 putchar(' ');
778 fputs(name, stdout);
779 continue;
780 }
781
782 if (sdl == NULL) {
783 status(NULL, 0);
784 } else {
785 status(LLADDR(sdl), sdl->sdl_alen);
786 sdl = NULL;
787 }
788 }
789 if (lflag)
790 putchar('\n');
791 #endif
792 }
793
794 /*ARGSUSED*/
795 void
796 clone_create(addr, param)
797 const char *addr;
798 int param;
799 {
800
801 /* We're called early... */
802 getsock(AF_INET);
803
804 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
805 if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
806 err(1, "SIOCIFCREATE");
807 }
808
809 /*ARGSUSED*/
810 void
811 clone_destroy(addr, param)
812 const char *addr;
813 int param;
814 {
815
816 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
817 if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
818 err(1, "SIOCIFDESTROY");
819 }
820
821 #define RIDADDR 0
822 #define ADDR 1
823 #define MASK 2
824 #define DSTADDR 3
825
826 /*ARGSUSED*/
827 void
828 setifaddr(addr, param)
829 const char *addr;
830 int param;
831 {
832 struct ifreq *ifr; /* XXX */
833
834 /*
835 * Delay the ioctl to set the interface addr until flags are all set.
836 * The address interpretation may depend on the flags,
837 * and the flags may change when the address is set.
838 */
839 setaddr++;
840 if (newaddr == -1)
841 newaddr = 1;
842 if (doalias == 0 && afp->af_gifaddr != 0) {
843 ifr = (struct ifreq *)afp->af_ridreq;
844 (void) strncpy(ifr->ifr_name, name, sizeof(ifr->ifr_name));
845 ifr->ifr_addr.sa_family = afp->af_af;
846 if (ioctl(s, afp->af_gifaddr, afp->af_ridreq) == 0)
847 clearaddr = 1;
848 else if (errno == EADDRNOTAVAIL)
849 /* No address was assigned yet. */
850 ;
851 else
852 err(1, "SIOCGIFADDR");
853 }
854
855 (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
856 }
857
858 void
859 settunnel(src, dst)
860 const char *src, *dst;
861 {
862 struct addrinfo hints, *srcres, *dstres;
863 struct ifaliasreq addreq;
864 int ecode;
865 #ifdef INET6
866 struct in6_aliasreq in6_addreq;
867 #endif
868
869 memset(&hints, 0, sizeof(hints));
870 hints.ai_family = afp->af_af;
871
872 if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
873 errx(1, "error in parsing address string: %s",
874 gai_strerror(ecode));
875
876 if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
877 errx(1, "error in parsing address string: %s",
878 gai_strerror(ecode));
879
880 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
881 errx(1,
882 "source and destination address families do not match");
883
884 switch (srcres->ai_addr->sa_family) {
885 case AF_INET:
886 memset(&addreq, 0, sizeof(addreq));
887 strncpy(addreq.ifra_name, name, IFNAMSIZ);
888 memcpy(&addreq.ifra_addr, srcres->ai_addr,
889 srcres->ai_addr->sa_len);
890 memcpy(&addreq.ifra_dstaddr, dstres->ai_addr,
891 dstres->ai_addr->sa_len);
892
893 if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0)
894 warn("SIOCSIFPHYADDR");
895 break;
896
897 #ifdef INET6
898 case AF_INET6:
899 memset(&in6_addreq, 0, sizeof(in6_addreq));
900 strncpy(in6_addreq.ifra_name, name, IFNAMSIZ);
901 memcpy(&in6_addreq.ifra_addr, srcres->ai_addr,
902 srcres->ai_addr->sa_len);
903 memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
904 dstres->ai_addr->sa_len);
905
906 if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
907 warn("SIOCSIFPHYADDR_IN6");
908 break;
909 #endif /* INET6 */
910
911 default:
912 warn("address family not supported");
913 }
914
915 freeaddrinfo(srcres);
916 freeaddrinfo(dstres);
917 }
918
919 /* ARGSUSED */
920 void
921 deletetunnel(vname, param)
922 const char *vname;
923 int param;
924 {
925
926 if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
927 err(1, "SIOCDIFPHYADDR");
928 }
929
930 void
931 setifnetmask(addr, d)
932 const char *addr;
933 int d;
934 {
935 (*afp->af_getaddr)(addr, MASK);
936 }
937
938 void
939 setifbroadaddr(addr, d)
940 const char *addr;
941 int d;
942 {
943 (*afp->af_getaddr)(addr, DSTADDR);
944 }
945
946 void
947 setifipdst(addr, d)
948 const char *addr;
949 int d;
950 {
951 in_getaddr(addr, DSTADDR);
952 setipdst++;
953 clearaddr = 0;
954 newaddr = 0;
955 }
956
957 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
958 /*ARGSUSED*/
959 void
960 notealias(addr, param)
961 const char *addr;
962 int param;
963 {
964 if (setaddr && doalias == 0 && param < 0)
965 (void) memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
966 rqtosa(af_addreq)->sa_len);
967 doalias = param;
968 if (param < 0) {
969 clearaddr = 1;
970 newaddr = 0;
971 } else
972 clearaddr = 0;
973 }
974
975 /*ARGSUSED*/
976 void
977 notrailers(vname, value)
978 const char *vname;
979 int value;
980 {
981 puts("Note: trailers are no longer sent, but always received");
982 }
983
984 /*ARGSUSED*/
985 void
986 setifdstaddr(addr, param)
987 const char *addr;
988 int param;
989 {
990 (*afp->af_getaddr)(addr, DSTADDR);
991 }
992
993 void
994 setifflags(vname, value)
995 const char *vname;
996 int value;
997 {
998 struct ifreq ifreq;
999
1000 (void) strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
1001 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifreq) < 0)
1002 err(1, "SIOCGIFFLAGS");
1003 flags = ifreq.ifr_flags;
1004
1005 if (value < 0) {
1006 value = -value;
1007 flags &= ~value;
1008 } else
1009 flags |= value;
1010 ifreq.ifr_flags = flags;
1011 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) < 0)
1012 err(1, "SIOCSIFFLAGS");
1013
1014 reset_if_flags = 1;
1015 }
1016
1017 #ifdef INET6
1018 void
1019 setia6flags(vname, value)
1020 const char *vname;
1021 int value;
1022 {
1023 if (value < 0) {
1024 value = -value;
1025 in6_addreq.ifra_flags &= ~value;
1026 } else
1027 in6_addreq.ifra_flags |= value;
1028 }
1029
1030 void
1031 setia6pltime(val, d)
1032 const char *val;
1033 int d;
1034 {
1035 setia6lifetime("pltime", val);
1036 }
1037
1038 void
1039 setia6vltime(val, d)
1040 const char *val;
1041 int d;
1042 {
1043 setia6lifetime("vltime", val);
1044 }
1045
1046 void
1047 setia6lifetime(cmd, val)
1048 const char *cmd;
1049 const char *val;
1050 {
1051 time_t newval, t;
1052 char *ep;
1053
1054 t = time(NULL);
1055 newval = (time_t)strtoul(val, &ep, 0);
1056 if (val == ep)
1057 errx(1, "invalid %s", cmd);
1058 if (afp->af_af != AF_INET6)
1059 errx(1, "%s not allowed for the AF", cmd);
1060 if (strcmp(cmd, "vltime") == 0) {
1061 in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
1062 in6_addreq.ifra_lifetime.ia6t_vltime = newval;
1063 } else if (strcmp(cmd, "pltime") == 0) {
1064 in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
1065 in6_addreq.ifra_lifetime.ia6t_pltime = newval;
1066 }
1067 }
1068 #endif
1069
1070 void
1071 setifmetric(val, d)
1072 const char *val;
1073 int d;
1074 {
1075 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1076 ifr.ifr_metric = atoi(val);
1077 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
1078 warn("SIOCSIFMETRIC");
1079 }
1080
1081 void
1082 setifmtu(val, d)
1083 const char *val;
1084 int d;
1085 {
1086 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1087 ifr.ifr_mtu = atoi(val);
1088 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
1089 warn("SIOCSIFMTU");
1090 }
1091
1092 void
1093 setifnwid(val, d)
1094 const char *val;
1095 int d;
1096 {
1097 struct ieee80211_nwid nwid;
1098 u_int8_t *p;
1099
1100 memset(&nwid, 0, sizeof(nwid));
1101 if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) {
1102 val += 2;
1103 p = nwid.i_nwid;
1104 while (isxdigit((u_char)val[0]) && isxdigit((u_char)val[1])) {
1105 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1106 *p++ = (tohex((u_char)val[0]) << 4) |
1107 tohex((u_char)val[1]);
1108 #undef tohex
1109 val += 2;
1110 }
1111 if (*val != '\0') {
1112 warnx("SIOCS80211NWID: Bad hexdecimal digits.");
1113 return;
1114 }
1115 nwid.i_len = p - nwid.i_nwid;
1116 } else {
1117 nwid.i_len = strlen(val);
1118 memcpy(nwid.i_nwid, val, nwid.i_len);
1119 }
1120 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1121 ifr.ifr_data = (caddr_t)&nwid;
1122 if (ioctl(s, SIOCS80211NWID, (caddr_t)&ifr) < 0)
1123 warn("SIOCS80211NWID");
1124 }
1125
1126 void
1127 ieee80211_status()
1128 {
1129 int i;
1130 struct ieee80211_nwid nwid;
1131
1132 memset(&ifr, 0, sizeof(ifr));
1133 ifr.ifr_data = (caddr_t)&nwid;
1134 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1135 if (ioctl(s, SIOCG80211NWID, (caddr_t)&ifr) != 0)
1136 return;
1137 if (nwid.i_len > IEEE80211_NWID_LEN) {
1138 warnx("SIOCS80211NWID: wrong length of nwid (%d)", nwid.i_len);
1139 return;
1140 }
1141 i = 0;
1142 if (nwid.i_nwid[0] != '0' || tolower(nwid.i_nwid[1]) != 'x') {
1143 for (; i < nwid.i_len; i++) {
1144 if (!isprint(nwid.i_nwid[i]))
1145 break;
1146 }
1147 }
1148 if (i == nwid.i_len)
1149 printf("\tnwid \"%.*s\"\n", nwid.i_len, nwid.i_nwid);
1150 else {
1151 printf("\tnwid 0x");
1152 for (i = 0; i < nwid.i_len; i++)
1153 printf("%02x", nwid.i_nwid[i]);
1154 printf("\n");
1155 }
1156 }
1157
1158 void
1159 init_current_media()
1160 {
1161 struct ifmediareq ifmr;
1162
1163 /*
1164 * If we have not yet done so, grab the currently-selected
1165 * media.
1166 */
1167 if ((actions & (A_MEDIA|A_MEDIAOPT)) == 0) {
1168 (void) memset(&ifmr, 0, sizeof(ifmr));
1169 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1170
1171 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
1172 /*
1173 * If we get E2BIG, the kernel is telling us
1174 * that there are more, so we can ignore it.
1175 */
1176 if (errno != E2BIG)
1177 err(1, "SGIOCGIFMEDIA");
1178 }
1179
1180 media_current = ifmr.ifm_current;
1181 }
1182
1183 /* Sanity. */
1184 if (IFM_TYPE(media_current) == 0)
1185 errx(1, "%s: no link type?", name);
1186 }
1187
1188 void
1189 process_media_commands()
1190 {
1191
1192 if ((actions & (A_MEDIA|A_MEDIAOPT)) == 0) {
1193 /* Nothing to do. */
1194 return;
1195 }
1196
1197 /*
1198 * Media already set up, and commands sanity-checked. Set/clear
1199 * any options, and we're ready to go.
1200 */
1201 media_current |= mediaopt_set;
1202 media_current &= ~mediaopt_clear;
1203
1204 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1205 ifr.ifr_media = media_current;
1206
1207 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
1208 err(1, "SIOCSIFMEDIA");
1209 }
1210
1211 void
1212 setmedia(val, d)
1213 const char *val;
1214 int d;
1215 {
1216 int type, subtype, inst;
1217
1218 init_current_media();
1219
1220 /* Only one media command may be given. */
1221 if (actions & A_MEDIA)
1222 errx(1, "only one `media' command may be issued");
1223
1224 /* Must not come after mediaopt commands */
1225 if (actions & A_MEDIAOPT)
1226 errx(1, "may not issue `media' after `mediaopt' commands");
1227
1228 /*
1229 * No need to check if `instance' has been issued; setmediainst()
1230 * craps out if `media' has not been specified.
1231 */
1232
1233 type = IFM_TYPE(media_current);
1234 inst = IFM_INST(media_current);
1235
1236 /* Look up the subtype. */
1237 subtype = get_media_subtype(type, val);
1238
1239 /* Build the new current media word. */
1240 media_current = IFM_MAKEWORD(type, subtype, 0, inst);
1241
1242 /* Media will be set after other processing is complete. */
1243 }
1244
1245 void
1246 setmediaopt(val, d)
1247 const char *val;
1248 int d;
1249 {
1250
1251 init_current_media();
1252
1253 /* Can only issue `mediaopt' once. */
1254 if (actions & A_MEDIAOPTSET)
1255 errx(1, "only one `mediaopt' command may be issued");
1256
1257 /* Can't issue `mediaopt' if `instance' has already been issued. */
1258 if (actions & A_MEDIAINST)
1259 errx(1, "may not issue `mediaopt' after `instance'");
1260
1261 mediaopt_set = get_media_options(IFM_TYPE(media_current), val);
1262
1263 /* Media will be set after other processing is complete. */
1264 }
1265
1266 void
1267 unsetmediaopt(val, d)
1268 const char *val;
1269 int d;
1270 {
1271
1272 init_current_media();
1273
1274 /* Can only issue `-mediaopt' once. */
1275 if (actions & A_MEDIAOPTCLR)
1276 errx(1, "only one `-mediaopt' command may be issued");
1277
1278 /* May not issue `media' and `-mediaopt'. */
1279 if (actions & A_MEDIA)
1280 errx(1, "may not issue both `media' and `-mediaopt'");
1281
1282 /*
1283 * No need to check for A_MEDIAINST, since the test for A_MEDIA
1284 * implicitly checks for A_MEDIAINST.
1285 */
1286
1287 mediaopt_clear = get_media_options(IFM_TYPE(media_current), val);
1288
1289 /* Media will be set after other processing is complete. */
1290 }
1291
1292 void
1293 setmediainst(val, d)
1294 const char *val;
1295 int d;
1296 {
1297 int type, subtype, options, inst;
1298
1299 init_current_media();
1300
1301 /* Can only issue `instance' once. */
1302 if (actions & A_MEDIAINST)
1303 errx(1, "only one `instance' command may be issued");
1304
1305 /* Must have already specified `media' */
1306 if ((actions & A_MEDIA) == 0)
1307 errx(1, "must specify `media' before `instance'");
1308
1309 type = IFM_TYPE(media_current);
1310 subtype = IFM_SUBTYPE(media_current);
1311 options = IFM_OPTIONS(media_current);
1312
1313 inst = atoi(val);
1314 if (inst < 0 || inst > IFM_INST_MAX)
1315 errx(1, "invalid media instance: %s", val);
1316
1317 media_current = IFM_MAKEWORD(type, subtype, options, inst);
1318
1319 /* Media will be set after other processing is complete. */
1320 }
1321
1322 struct ifmedia_description ifm_type_descriptions[] =
1323 IFM_TYPE_DESCRIPTIONS;
1324
1325 struct ifmedia_description ifm_subtype_descriptions[] =
1326 IFM_SUBTYPE_DESCRIPTIONS;
1327
1328 struct ifmedia_description ifm_option_descriptions[] =
1329 IFM_OPTION_DESCRIPTIONS;
1330
1331 const char *
1332 get_media_type_string(mword)
1333 int mword;
1334 {
1335 struct ifmedia_description *desc;
1336
1337 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
1338 desc++) {
1339 if (IFM_TYPE(mword) == desc->ifmt_word)
1340 return (desc->ifmt_string);
1341 }
1342 return ("<unknown type>");
1343 }
1344
1345 const char *
1346 get_media_subtype_string(mword)
1347 int mword;
1348 {
1349 struct ifmedia_description *desc;
1350
1351 for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
1352 desc++) {
1353 if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
1354 IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
1355 return (desc->ifmt_string);
1356 }
1357 return ("<unknown subtype>");
1358 }
1359
1360 int
1361 get_media_subtype(type, val)
1362 int type;
1363 const char *val;
1364 {
1365 int rval;
1366
1367 rval = lookup_media_word(ifm_subtype_descriptions, type, val);
1368 if (rval == -1)
1369 errx(1, "unknown %s media subtype: %s",
1370 get_media_type_string(type), val);
1371
1372 return (rval);
1373 }
1374
1375 int
1376 get_media_options(type, val)
1377 int type;
1378 const char *val;
1379 {
1380 char *optlist, *str;
1381 int option, rval = 0;
1382
1383 /* We muck with the string, so copy it. */
1384 optlist = strdup(val);
1385 if (optlist == NULL)
1386 err(1, "strdup");
1387 str = optlist;
1388
1389 /*
1390 * Look up the options in the user-provided comma-separated list.
1391 */
1392 for (; (str = strtok(str, ",")) != NULL; str = NULL) {
1393 option = lookup_media_word(ifm_option_descriptions, type, str);
1394 if (option == -1)
1395 errx(1, "unknown %s media option: %s",
1396 get_media_type_string(type), str);
1397 rval |= IFM_OPTIONS(option);
1398 }
1399
1400 free(optlist);
1401 return (rval);
1402 }
1403
1404 int
1405 lookup_media_word(desc, type, val)
1406 struct ifmedia_description *desc;
1407 int type;
1408 const char *val;
1409 {
1410
1411 for (; desc->ifmt_string != NULL; desc++) {
1412 if (IFM_TYPE_MATCH(desc->ifmt_word, type) &&
1413 strcasecmp(desc->ifmt_string, val) == 0)
1414 return (desc->ifmt_word);
1415 }
1416 return (-1);
1417 }
1418
1419 void
1420 print_media_word(ifmw, print_type, as_syntax)
1421 int ifmw, print_type, as_syntax;
1422 {
1423 struct ifmedia_description *desc;
1424 int seen_option = 0;
1425
1426 if (print_type)
1427 printf("%s ", get_media_type_string(ifmw));
1428 printf("%s%s", as_syntax ? "media " : "",
1429 get_media_subtype_string(ifmw));
1430
1431 /* Find options. */
1432 for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
1433 desc++) {
1434 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
1435 (ifmw & IFM_OPTIONS(desc->ifmt_word)) != 0 &&
1436 (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
1437 if (seen_option == 0)
1438 printf(" %s", as_syntax ? "mediaopt " : "");
1439 printf("%s%s", seen_option ? "," : "",
1440 desc->ifmt_string);
1441 seen_option |= IFM_OPTIONS(desc->ifmt_word);
1442 }
1443 }
1444 if (IFM_INST(ifmw) != 0)
1445 printf(" instance %d", IFM_INST(ifmw));
1446 }
1447
1448 int carrier()
1449 {
1450 struct ifmediareq ifmr;
1451
1452 (void) memset(&ifmr, 0, sizeof(ifmr));
1453 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1454
1455 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
1456 /*
1457 * Interface doesn't support SIOC{G,S}IFMEDIA;
1458 * assume ok.
1459 */
1460 return 0;
1461 }
1462 if ((ifmr.ifm_status & IFM_AVALID) == 0) {
1463 /*
1464 * Interface doesn't report media-valid status.
1465 * assume ok.
1466 */
1467 return 0;
1468 }
1469 /* otherwise, return ok for active, not-ok if not active. */
1470 return !(ifmr.ifm_status & IFM_ACTIVE);
1471 }
1472
1473
1474 #define IFFBITS \
1475 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
1476 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
1477
1478 const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1479
1480 const struct ifmedia_status_description ifm_status_descriptions[] =
1481 IFM_STATUS_DESCRIPTIONS;
1482
1483 /*
1484 * Print the status of the interface. If an address family was
1485 * specified, show it and it only; otherwise, show them all.
1486 */
1487 void
1488 status(ap, alen)
1489 const u_int8_t *ap;
1490 int alen;
1491 {
1492 struct afswtch *p = afp;
1493 struct ifmediareq ifmr;
1494 int *media_list, i;
1495
1496 printf("%s: ", name);
1497 printb("flags", flags, IFFBITS);
1498 if (metric)
1499 printf(" metric %d", metric);
1500 if (mtu)
1501 printf(" mtu %d", mtu);
1502 putchar('\n');
1503
1504 ieee80211_status();
1505 tunnel_status();
1506
1507 if (ap && alen > 0) {
1508 printf("\taddress:");
1509 for (i = 0; i < alen; i++, ap++)
1510 printf("%c%02x", i > 0 ? ':' : ' ', *ap);
1511 putchar('\n');
1512 }
1513
1514 (void) memset(&ifmr, 0, sizeof(ifmr));
1515 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1516
1517 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
1518 /*
1519 * Interface doesn't support SIOC{G,S}IFMEDIA.
1520 */
1521 goto proto_status;
1522 }
1523
1524 if (ifmr.ifm_count == 0) {
1525 warnx("%s: no media types?", name);
1526 goto proto_status;
1527 }
1528
1529 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
1530 if (media_list == NULL)
1531 err(1, "malloc");
1532 ifmr.ifm_ulist = media_list;
1533
1534 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
1535 err(1, "SIOCGIFMEDIA");
1536
1537 printf("\tmedia: ");
1538 print_media_word(ifmr.ifm_current, 1, 0);
1539 if (ifmr.ifm_active != ifmr.ifm_current) {
1540 putchar(' ');
1541 putchar('(');
1542 print_media_word(ifmr.ifm_active, 0, 0);
1543 putchar(')');
1544 }
1545 putchar('\n');
1546
1547 if (ifmr.ifm_status & IFM_STATUS_VALID) {
1548 const struct ifmedia_status_description *ifms;
1549 int bitno, found = 0;
1550
1551 printf("\tstatus: ");
1552 for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
1553 for (ifms = ifm_status_descriptions;
1554 ifms->ifms_valid != 0; ifms++) {
1555 if (ifms->ifms_type !=
1556 IFM_TYPE(ifmr.ifm_current) ||
1557 ifms->ifms_valid !=
1558 ifm_status_valid_list[bitno])
1559 continue;
1560 printf("%s%s", found ? ", " : "",
1561 IFM_STATUS_DESC(ifms, ifmr.ifm_status));
1562 found = 1;
1563
1564 /*
1565 * For each valid indicator bit, there's
1566 * only one entry for each media type, so
1567 * terminate the inner loop now.
1568 */
1569 break;
1570 }
1571 }
1572
1573 if (found == 0)
1574 printf("unknown");
1575 putchar('\n');
1576 }
1577
1578 if (mflag) {
1579 int type, printed_type;
1580
1581 for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
1582 for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
1583 if (IFM_TYPE(media_list[i]) == type) {
1584 if (printed_type == 0) {
1585 printf("\tsupported %s media:\n",
1586 get_media_type_string(type));
1587 printed_type = 1;
1588 }
1589 printf("\t\t");
1590 print_media_word(media_list[i], 0, 1);
1591 printf("\n");
1592 }
1593 }
1594 }
1595 }
1596
1597 free(media_list);
1598
1599 proto_status:
1600 if ((p = afp) != NULL) {
1601 (*p->af_status)(1);
1602 } else for (p = afs; p->af_name; p++) {
1603 ifr.ifr_addr.sa_family = p->af_af;
1604 (*p->af_status)(0);
1605 }
1606 }
1607
1608 void
1609 tunnel_status()
1610 {
1611 char psrcaddr[NI_MAXHOST];
1612 char pdstaddr[NI_MAXHOST];
1613 u_long srccmd, dstcmd;
1614 struct ifreq *ifrp;
1615 const char *ver = "";
1616 #ifdef NI_WITHSCOPEID
1617 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
1618 #else
1619 const int niflag = NI_NUMERICHOST;
1620 #endif
1621 #ifdef INET6
1622 struct in6_ifreq in6_ifr;
1623 int s6;
1624 #endif /* INET6 */
1625
1626 psrcaddr[0] = pdstaddr[0] = '\0';
1627
1628 #ifdef INET6
1629 memset(&in6_ifr, 0, sizeof(in6_ifr));
1630 strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
1631 s6 = socket(AF_INET6, SOCK_DGRAM, 0);
1632 if (s6 < 0) {
1633 srccmd = SIOCGIFPSRCADDR;
1634 dstcmd = SIOCGIFPDSTADDR;
1635 ifrp = 𝔦
1636 } else {
1637 close(s6);
1638 srccmd = SIOCGIFPSRCADDR_IN6;
1639 dstcmd = SIOCGIFPDSTADDR_IN6;
1640 ifrp = (struct ifreq *)&in6_ifr;
1641 }
1642 #else /* INET6 */
1643 srccmd = SIOCGIFPSRCADDR;
1644 dstcmd = SIOCGIFPDSTADDR;
1645 ifrp = 𝔦
1646 #endif /* INET6 */
1647
1648 if (ioctl(s, srccmd, (caddr_t)ifrp) < 0)
1649 return;
1650 #ifdef INET6
1651 if (ifrp->ifr_addr.sa_family == AF_INET6)
1652 in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
1653 #endif
1654 getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
1655 psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
1656 #ifdef INET6
1657 if (ifrp->ifr_addr.sa_family == AF_INET6)
1658 ver = "6";
1659 #endif
1660
1661 if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0)
1662 return;
1663 #ifdef INET6
1664 if (ifrp->ifr_addr.sa_family == AF_INET6)
1665 in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
1666 #endif
1667 getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
1668 pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
1669
1670 printf("\ttunnel inet%s %s --> %s\n", ver,
1671 psrcaddr, pdstaddr);
1672 }
1673
1674 void
1675 in_alias(creq)
1676 struct ifreq *creq;
1677 {
1678 struct sockaddr_in *sin;
1679 int alias;
1680
1681 if (lflag)
1682 return;
1683
1684 alias = 1;
1685
1686 /* Get the non-alias address for this interface. */
1687 getsock(AF_INET);
1688 if (s < 0) {
1689 if (errno == EPROTONOSUPPORT)
1690 return;
1691 err(1, "socket");
1692 }
1693 (void) memset(&ifr, 0, sizeof(ifr));
1694 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1695 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1696 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1697 return;
1698 } else
1699 warn("SIOCGIFADDR");
1700 }
1701 /* If creq and ifr are the same address, this is not an alias. */
1702 if (memcmp(&ifr.ifr_addr, &creq->ifr_addr,
1703 sizeof(creq->ifr_addr)) == 0)
1704 alias = 0;
1705 /* we print aliases only with -A */
1706 if (alias && !Aflag)
1707 return;
1708 (void) memset(&addreq, 0, sizeof(addreq));
1709 (void) strncpy(addreq.ifra_name, name, sizeof(addreq.ifra_name));
1710 addreq.ifra_addr = creq->ifr_addr;
1711 if (ioctl(s, SIOCGIFALIAS, (caddr_t)&addreq) < 0) {
1712 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1713 return;
1714 } else
1715 warn("SIOCGIFALIAS");
1716 }
1717
1718 sin = (struct sockaddr_in *)&addreq.ifra_addr;
1719 printf("\tinet %s%s", alias ? "alias " : "", inet_ntoa(sin->sin_addr));
1720
1721 if (flags & IFF_POINTOPOINT) {
1722 sin = (struct sockaddr_in *)&addreq.ifra_dstaddr;
1723 printf(" -> %s", inet_ntoa(sin->sin_addr));
1724 }
1725
1726 sin = (struct sockaddr_in *)&addreq.ifra_mask;
1727 printf(" netmask 0x%x", ntohl(sin->sin_addr.s_addr));
1728
1729 if (flags & IFF_BROADCAST) {
1730 sin = (struct sockaddr_in *)&addreq.ifra_broadaddr;
1731 printf(" broadcast %s", inet_ntoa(sin->sin_addr));
1732 }
1733 printf("\n");
1734 }
1735
1736 void
1737 in_status(force)
1738 int force;
1739 {
1740 #ifdef HAVE_IFADDRS_H
1741 struct ifaddrs *ifap, *ifa;
1742 struct ifreq ifr;
1743
1744 if (getifaddrs(&ifap) != 0)
1745 err(1, "getifaddrs");
1746 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1747 if (strcmp(name, ifa->ifa_name) != 0)
1748 continue;
1749 if (ifa->ifa_addr->sa_family != AF_INET)
1750 continue;
1751 if (sizeof(ifr.ifr_addr) < ifa->ifa_addr->sa_len)
1752 continue;
1753
1754 memset(&ifr, 0, sizeof(ifr));
1755 strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
1756 memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
1757 in_alias(&ifr);
1758 }
1759 freeifaddrs(ifap);
1760 #else
1761 char inbuf[8192];
1762 struct ifconf ifc;
1763 struct ifreq *ifr;
1764 int i, siz;
1765 char ifrbuf[8192], *cp;
1766
1767 ifc.ifc_len = sizeof(inbuf);
1768 ifc.ifc_buf = inbuf;
1769 getsock(af);
1770 if (s < 0)
1771 err(1, "socket");
1772 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
1773 err(1, "SIOCGIFCONF");
1774 for (i = 0; i < ifc.ifc_len; ) {
1775 /* Copy the mininum ifreq into the buffer. */
1776 cp = ((caddr_t)ifc.ifc_req + i);
1777 memcpy(ifrbuf, cp, sizeof(*ifr));
1778
1779 /* Now compute the actual size of the ifreq. */
1780 ifr = (struct ifreq *)ifrbuf;
1781 siz = ifr->ifr_addr.sa_len;
1782 if (siz < sizeof(ifr->ifr_addr))
1783 siz = sizeof(ifr->ifr_addr);
1784 siz += sizeof(ifr->ifr_name);
1785 i += siz;
1786
1787 /* Now copy the whole thing. */
1788 if (sizeof(ifrbuf) < siz)
1789 errx(1, "ifr too big");
1790 memcpy(ifrbuf, cp, siz);
1791
1792 if (!strncmp(name, ifr->ifr_name, sizeof(ifr->ifr_name))) {
1793 if (ifr->ifr_addr.sa_family == AF_INET)
1794 in_alias(ifr);
1795 }
1796 }
1797 #endif
1798 }
1799
1800 void
1801 setifprefixlen(addr, d)
1802 const char *addr;
1803 int d;
1804 {
1805 if (*afp->af_getprefix)
1806 (*afp->af_getprefix)(addr, MASK);
1807 explicit_prefix = 1;
1808 }
1809
1810 #ifdef INET6
1811 void
1812 in6_fillscopeid(sin6)
1813 struct sockaddr_in6 *sin6;
1814 {
1815 #if defined(__KAME__) && defined(KAME_SCOPEID)
1816 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1817 sin6->sin6_scope_id =
1818 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
1819 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
1820 }
1821 #endif
1822 }
1823
1824 /* XXX not really an alias */
1825 void
1826 in6_alias(creq)
1827 struct in6_ifreq *creq;
1828 {
1829 struct sockaddr_in6 *sin6;
1830 char hbuf[NI_MAXHOST];
1831 u_int32_t scopeid;
1832 #ifdef NI_WITHSCOPEID
1833 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
1834 #else
1835 const int niflag = NI_NUMERICHOST;
1836 #endif
1837
1838 /* Get the non-alias address for this interface. */
1839 getsock(AF_INET6);
1840 if (s < 0) {
1841 if (errno == EPROTONOSUPPORT)
1842 return;
1843 err(1, "socket");
1844 }
1845
1846 sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
1847
1848 in6_fillscopeid(sin6);
1849 scopeid = sin6->sin6_scope_id;
1850 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1851 hbuf, sizeof(hbuf), NULL, 0, niflag))
1852 strncpy(hbuf, "", sizeof(hbuf)); /* some message? */
1853 printf("\tinet6 %s", hbuf);
1854
1855 if (flags & IFF_POINTOPOINT) {
1856 (void) memset(&ifr6, 0, sizeof(ifr6));
1857 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1858 ifr6.ifr_addr = creq->ifr_addr;
1859 if (ioctl(s, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) < 0) {
1860 if (errno != EADDRNOTAVAIL)
1861 warn("SIOCGIFDSTADDR_IN6");
1862 (void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
1863 ifr6.ifr_addr.sin6_family = AF_INET6;
1864 ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
1865 }
1866 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1867 in6_fillscopeid(sin6);
1868 hbuf[0] = '\0';
1869 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1870 hbuf, sizeof(hbuf), NULL, 0, niflag))
1871 strncpy(hbuf, "", sizeof(hbuf)); /* some message? */
1872 printf(" -> %s", hbuf);
1873 }
1874
1875 (void) memset(&ifr6, 0, sizeof(ifr6));
1876 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1877 ifr6.ifr_addr = creq->ifr_addr;
1878 if (ioctl(s, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
1879 if (errno != EADDRNOTAVAIL)
1880 warn("SIOCGIFNETMASK_IN6");
1881 } else {
1882 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1883 printf(" prefixlen %d", prefix(&sin6->sin6_addr,
1884 sizeof(struct in6_addr)));
1885 }
1886
1887 (void) memset(&ifr6, 0, sizeof(ifr6));
1888 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1889 ifr6.ifr_addr = creq->ifr_addr;
1890 if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) < 0) {
1891 if (errno != EADDRNOTAVAIL)
1892 warn("SIOCGIFAFLAG_IN6");
1893 } else {
1894 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
1895 printf(" anycast");
1896 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
1897 printf(" tentative");
1898 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
1899 printf(" duplicated");
1900 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
1901 printf(" detached");
1902 }
1903
1904 if (scopeid)
1905 printf(" scopeid 0x%x", scopeid);
1906
1907 if (Lflag) {
1908 struct in6_addrlifetime *lifetime;
1909 (void) memset(&ifr6, 0, sizeof(ifr6));
1910 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1911 ifr6.ifr_addr = creq->ifr_addr;
1912 lifetime = &ifr6.ifr_ifru.ifru_lifetime;
1913 if (ioctl(s, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) < 0) {
1914 if (errno != EADDRNOTAVAIL)
1915 warn("SIOCGIFALIFETIME_IN6");
1916 } else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
1917 time_t t = time(NULL);
1918 printf(" pltime ");
1919 if (lifetime->ia6t_preferred) {
1920 printf("%s", lifetime->ia6t_preferred < t
1921 ? "0"
1922 : sec2str(lifetime->ia6t_preferred - t));
1923 } else
1924 printf("infty");
1925
1926 printf(" vltime ");
1927 if (lifetime->ia6t_expire) {
1928 printf("%s", lifetime->ia6t_expire < t
1929 ? "0"
1930 : sec2str(lifetime->ia6t_expire - t));
1931 } else
1932 printf("infty");
1933 }
1934 }
1935
1936 printf("\n");
1937 }
1938
1939 void
1940 in6_status(force)
1941 int force;
1942 {
1943 #ifdef HAVE_IFADDRS_H
1944 struct ifaddrs *ifap, *ifa;
1945 struct in6_ifreq ifr;
1946
1947 if (getifaddrs(&ifap) != 0)
1948 err(1, "getifaddrs");
1949 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1950 if (strcmp(name, ifa->ifa_name) != 0)
1951 continue;
1952 if (ifa->ifa_addr->sa_family != AF_INET6)
1953 continue;
1954 if (sizeof(ifr.ifr_addr) < ifa->ifa_addr->sa_len)
1955 continue;
1956
1957 memset(&ifr, 0, sizeof(ifr));
1958 strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
1959 memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
1960 in6_alias(&ifr);
1961 }
1962 freeifaddrs(ifap);
1963 #else
1964 char inbuf[8192];
1965 struct ifconf ifc;
1966 struct ifreq *ifr;
1967 int i, siz;
1968 char ifrbuf[8192], *cp;
1969
1970 ifc.ifc_len = sizeof(inbuf);
1971 ifc.ifc_buf = inbuf;
1972 getsock(af);
1973 if (s < 0)
1974 err(1, "socket");
1975 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
1976 err(1, "SIOCGIFCONF");
1977 for (i = 0; i < ifc.ifc_len; ) {
1978 /* Copy the mininum ifreq into the buffer. */
1979 cp = ((caddr_t)ifc.ifc_req + i);
1980 memcpy(ifrbuf, cp, sizeof(*ifr));
1981
1982 /* Now compute the actual size of the ifreq. */
1983 ifr = (struct ifreq *)ifrbuf;
1984 siz = ifr->ifr_addr.sa_len;
1985 if (siz < sizeof(ifr->ifr_addr))
1986 siz = sizeof(ifr->ifr_addr);
1987 siz += sizeof(ifr->ifr_name);
1988 i += siz;
1989
1990 /* Now copy the whole thing. */
1991 if (sizeof(ifrbuf) < siz)
1992 errx(1, "ifr too big");
1993 memcpy(ifrbuf, cp, siz);
1994
1995 if (!strncmp(name, ifr->ifr_name, sizeof(ifr->ifr_name))) {
1996 if (ifr->ifr_addr.sa_family == AF_INET6)
1997 in6_alias((struct in6_ifreq *)ifr);
1998 }
1999 }
2000 #endif
2001 }
2002 #endif /*INET6*/
2003
2004 #ifndef INET_ONLY
2005
2006 void
2007 at_status(force)
2008 int force;
2009 {
2010 struct sockaddr_at *sat, null_sat;
2011 struct netrange *nr;
2012
2013 getsock(AF_APPLETALK);
2014 if (s < 0) {
2015 if (errno == EPROTONOSUPPORT)
2016 return;
2017 err(1, "socket");
2018 }
2019 (void) memset(&ifr, 0, sizeof(ifr));
2020 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2021 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
2022 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2023 if (!force)
2024 return;
2025 (void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2026 } else
2027 warn("SIOCGIFADDR");
2028 }
2029 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
2030 sat = (struct sockaddr_at *)&ifr.ifr_addr;
2031
2032 (void) memset(&null_sat, 0, sizeof(null_sat));
2033
2034 nr = (struct netrange *) &sat->sat_zero;
2035 printf("\tatalk %d.%d range %d-%d phase %d",
2036 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
2037 ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
2038 if (flags & IFF_POINTOPOINT) {
2039 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
2040 if (errno == EADDRNOTAVAIL)
2041 (void) memset(&ifr.ifr_addr, 0,
2042 sizeof(ifr.ifr_addr));
2043 else
2044 warn("SIOCGIFDSTADDR");
2045 }
2046 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2047 sat = (struct sockaddr_at *)&ifr.ifr_dstaddr;
2048 if (!sat)
2049 sat = &null_sat;
2050 printf("--> %d.%d",
2051 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
2052 }
2053 if (flags & IFF_BROADCAST) {
2054 /* note RTAX_BRD overlap with IFF_POINTOPOINT */
2055 sat = (struct sockaddr_at *)&ifr.ifr_broadaddr;
2056 if (sat)
2057 printf(" broadcast %d.%d", ntohs(sat->sat_addr.s_net),
2058 sat->sat_addr.s_node);
2059 }
2060 putchar('\n');
2061 }
2062
2063 void
2064 xns_status(force)
2065 int force;
2066 {
2067 struct sockaddr_ns *sns;
2068
2069 getsock(AF_NS);
2070 if (s < 0) {
2071 if (errno == EPROTONOSUPPORT)
2072 return;
2073 err(1, "socket");
2074 }
2075 (void) memset(&ifr, 0, sizeof(ifr));
2076 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2077 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
2078 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2079 if (!force)
2080 return;
2081 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2082 } else
2083 warn("SIOCGIFADDR");
2084 }
2085 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
2086 sns = (struct sockaddr_ns *)&ifr.ifr_addr;
2087 printf("\tns %s ", ns_ntoa(sns->sns_addr));
2088 if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
2089 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
2090 if (errno == EADDRNOTAVAIL)
2091 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2092 else
2093 warn("SIOCGIFDSTADDR");
2094 }
2095 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2096 sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
2097 printf("--> %s ", ns_ntoa(sns->sns_addr));
2098 }
2099 putchar('\n');
2100 }
2101
2102 void
2103 iso_status(force)
2104 int force;
2105 {
2106 struct sockaddr_iso *siso;
2107 struct iso_ifreq ifr;
2108
2109 getsock(AF_ISO);
2110 if (s < 0) {
2111 if (errno == EPROTONOSUPPORT)
2112 return;
2113 err(1, "socket");
2114 }
2115 (void) memset(&ifr, 0, sizeof(ifr));
2116 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2117 if (ioctl(s, SIOCGIFADDR_ISO, (caddr_t)&ifr) < 0) {
2118 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2119 if (!force)
2120 return;
2121 (void) memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
2122 } else
2123 warn("SIOCGIFADDR_ISO");
2124 }
2125 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
2126 siso = &ifr.ifr_Addr;
2127 printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
2128 if (ioctl(s, SIOCGIFNETMASK_ISO, (caddr_t)&ifr) < 0) {
2129 if (errno == EADDRNOTAVAIL)
2130 memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
2131 else
2132 warn("SIOCGIFNETMASK_ISO");
2133 } else {
2134 if (siso->siso_len > offsetof(struct sockaddr_iso, siso_addr))
2135 siso->siso_addr.isoa_len = siso->siso_len
2136 - offsetof(struct sockaddr_iso, siso_addr);
2137 printf("\n\t\tnetmask %s ", iso_ntoa(&siso->siso_addr));
2138 }
2139 if (flags & IFF_POINTOPOINT) {
2140 if (ioctl(s, SIOCGIFDSTADDR_ISO, (caddr_t)&ifr) < 0) {
2141 if (errno == EADDRNOTAVAIL)
2142 memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
2143 else
2144 warn("SIOCGIFDSTADDR_ISO");
2145 }
2146 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2147 siso = &ifr.ifr_Addr;
2148 printf("--> %s ", iso_ntoa(&siso->siso_addr));
2149 }
2150 putchar('\n');
2151 }
2152
2153 #endif /* INET_ONLY */
2154
2155 #define SIN(x) ((struct sockaddr_in *) &(x))
2156 struct sockaddr_in *sintab[] = {
2157 SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
2158 SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
2159
2160 void
2161 in_getaddr(s, which)
2162 const char *s;
2163 int which;
2164 {
2165 struct sockaddr_in *sin = sintab[which];
2166 struct hostent *hp;
2167 struct netent *np;
2168
2169 sin->sin_len = sizeof(*sin);
2170 if (which != MASK)
2171 sin->sin_family = AF_INET;
2172
2173 if (which == ADDR) {
2174 char *p = NULL;
2175
2176 if((p = strrchr(s, '/')) != NULL) {
2177 /* address is `name/masklen' */
2178 int masklen;
2179 int ret;
2180 struct sockaddr_in *min = sintab[MASK];
2181 *p = '\0';
2182 ret = sscanf(p+1, "%u", &masklen);
2183 if(ret != 1 || (masklen < 0 || masklen > 32)) {
2184 *p = '/';
2185 errx(1, "%s: bad value", s);
2186 }
2187 min->sin_len = sizeof(*min);
2188 min->sin_addr.s_addr =
2189 htonl(~((1LL << (32 - masklen)) - 1) &
2190 0xffffffff);
2191 }
2192 }
2193
2194 if (inet_aton(s, &sin->sin_addr) == 0) {
2195 if ((hp = gethostbyname(s)) != NULL)
2196 (void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
2197 else if ((np = getnetbyname(s)) != NULL)
2198 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
2199 else
2200 errx(1, "%s: bad value", s);
2201 }
2202 }
2203
2204 /*
2205 * Print a value a la the %b format of the kernel's printf
2206 */
2207 void
2208 printb(s, v, bits)
2209 const char *s;
2210 unsigned short v;
2211 const char *bits;
2212 {
2213 int i, any = 0;
2214 char c;
2215
2216 if (bits && *bits == 8)
2217 printf("%s=%o", s, v);
2218 else
2219 printf("%s=%x", s, v);
2220 bits++;
2221 if (bits) {
2222 putchar('<');
2223 while ((i = *bits++) != 0) {
2224 if (v & (1 << (i-1))) {
2225 if (any)
2226 putchar(',');
2227 any = 1;
2228 for (; (c = *bits) > 32; bits++)
2229 putchar(c);
2230 } else
2231 for (; *bits > 32; bits++)
2232 ;
2233 }
2234 putchar('>');
2235 }
2236 }
2237
2238 #ifdef INET6
2239 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
2240 struct sockaddr_in6 *sin6tab[] = {
2241 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
2242 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
2243
2244 void
2245 in6_getaddr(s, which)
2246 const char *s;
2247 int which;
2248 {
2249 #if defined(__KAME__) && defined(KAME_SCOPEID)
2250 struct sockaddr_in6 *sin6 = sin6tab[which];
2251 struct addrinfo hints, *res;
2252 int error;
2253
2254 memset(&hints, 0, sizeof(hints));
2255 hints.ai_family = AF_INET6;
2256 hints.ai_socktype = SOCK_DGRAM;
2257 #if 0 /* in_getaddr() allows FQDN */
2258 hints.ai_flags = AI_NUMERICHOST;
2259 #endif
2260 error = getaddrinfo(s, "0", &hints, &res);
2261 if (error)
2262 errx(1, "%s: %s", s, gai_strerror(error));
2263 if (res->ai_next)
2264 errx(1, "%s: resolved to multiple hosts", s);
2265 if (res->ai_addrlen != sizeof(struct sockaddr_in6))
2266 errx(1, "%s: bad value", s);
2267 memcpy(sin6, res->ai_addr, res->ai_addrlen);
2268 freeaddrinfo(res);
2269 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && sin6->sin6_scope_id) {
2270 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
2271 htons(sin6->sin6_scope_id);
2272 sin6->sin6_scope_id = 0;
2273 }
2274 #else
2275 struct sockaddr_in6 *sin = sin6tab[which];
2276
2277 sin->sin6_len = sizeof(*sin);
2278 if (which != MASK)
2279 sin->sin6_family = AF_INET6;
2280
2281 if (which == ADDR) {
2282 char *p = NULL;
2283 if((p = strrchr(s, '/')) != NULL) {
2284 *p = '\0';
2285 in6_getprefix(p + 1, MASK);
2286 explicit_prefix = 1;
2287 }
2288 }
2289
2290 if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
2291 errx(1, "%s: bad value", s);
2292 #endif
2293 }
2294
2295 void
2296 in6_getprefix(plen, which)
2297 const char *plen;
2298 int which;
2299 {
2300 register struct sockaddr_in6 *sin = sin6tab[which];
2301 register u_char *cp;
2302 int len = strtol(plen, (char **)NULL, 10);
2303
2304 if ((len < 0) || (len > 128))
2305 errx(1, "%s: bad value", plen);
2306 sin->sin6_len = sizeof(*sin);
2307 if (which != MASK)
2308 sin->sin6_family = AF_INET6;
2309 if ((len == 0) || (len == 128)) {
2310 memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
2311 return;
2312 }
2313 memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
2314 for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
2315 *cp++ = 0xff;
2316 *cp = 0xff << (8 - len);
2317 }
2318
2319 int
2320 prefix(val, size)
2321 void *val;
2322 int size;
2323 {
2324 register u_char *name = (u_char *)val;
2325 register int byte, bit, plen = 0;
2326
2327 for (byte = 0; byte < size; byte++, plen += 8)
2328 if (name[byte] != 0xff)
2329 break;
2330 if (byte == size)
2331 return (plen);
2332 for (bit = 7; bit != 0; bit--, plen++)
2333 if (!(name[byte] & (1 << bit)))
2334 break;
2335 for (; bit != 0; bit--)
2336 if (name[byte] & (1 << bit))
2337 return(0);
2338 byte++;
2339 for (; byte < size; byte++)
2340 if (name[byte])
2341 return(0);
2342 return (plen);
2343 }
2344 #endif /*INET6*/
2345
2346 #ifndef INET_ONLY
2347 void
2348 at_getaddr(addr, which)
2349 const char *addr;
2350 int which;
2351 {
2352 struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
2353 u_int net, node;
2354
2355 sat->sat_family = AF_APPLETALK;
2356 sat->sat_len = sizeof(*sat);
2357 if (which == MASK)
2358 errx(1, "AppleTalk does not use netmasks\n");
2359 if (sscanf(addr, "%u.%u", &net, &node) != 2
2360 || net == 0 || net > 0xffff || node == 0 || node > 0xfe)
2361 errx(1, "%s: illegal address", addr);
2362 sat->sat_addr.s_net = htons(net);
2363 sat->sat_addr.s_node = node;
2364 }
2365
2366 void
2367 setatrange(range, d)
2368 const char *range;
2369 int d;
2370 {
2371 u_short first = 123, last = 123;
2372
2373 if (sscanf(range, "%hu-%hu", &first, &last) != 2
2374 || first == 0 || first > 0xffff
2375 || last == 0 || last > 0xffff || first > last)
2376 errx(1, "%s: illegal net range: %u-%u", range, first, last);
2377 at_nr.nr_firstnet = htons(first);
2378 at_nr.nr_lastnet = htons(last);
2379 }
2380
2381 void
2382 setatphase(phase, d)
2383 const char *phase;
2384 int d;
2385 {
2386 if (!strcmp(phase, "1"))
2387 at_nr.nr_phase = 1;
2388 else if (!strcmp(phase, "2"))
2389 at_nr.nr_phase = 2;
2390 else
2391 errx(1, "%s: illegal phase", phase);
2392 }
2393
2394 void
2395 checkatrange(sat)
2396 struct sockaddr_at *sat;
2397 {
2398 if (at_nr.nr_phase == 0)
2399 at_nr.nr_phase = 2; /* Default phase 2 */
2400 if (at_nr.nr_firstnet == 0)
2401 at_nr.nr_firstnet = /* Default range of one */
2402 at_nr.nr_lastnet = sat->sat_addr.s_net;
2403 printf("\tatalk %d.%d range %d-%d phase %d\n",
2404 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
2405 ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
2406 if ((u_short) ntohs(at_nr.nr_firstnet) >
2407 (u_short) ntohs(sat->sat_addr.s_net)
2408 || (u_short) ntohs(at_nr.nr_lastnet) <
2409 (u_short) ntohs(sat->sat_addr.s_net))
2410 errx(1, "AppleTalk address is not in range");
2411 *((struct netrange *) &sat->sat_zero) = at_nr;
2412 }
2413
2414 #define SNS(x) ((struct sockaddr_ns *) &(x))
2415 struct sockaddr_ns *snstab[] = {
2416 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
2417 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
2418
2419 void
2420 xns_getaddr(addr, which)
2421 const char *addr;
2422 int which;
2423 {
2424 struct sockaddr_ns *sns = snstab[which];
2425
2426 sns->sns_family = AF_NS;
2427 sns->sns_len = sizeof(*sns);
2428 sns->sns_addr = ns_addr(addr);
2429 if (which == MASK)
2430 puts("Attempt to set XNS netmask will be ineffectual");
2431 }
2432
2433 #define SISO(x) ((struct sockaddr_iso *) &(x))
2434 struct sockaddr_iso *sisotab[] = {
2435 SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
2436 SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
2437
2438 void
2439 iso_getaddr(addr, which)
2440 const char *addr;
2441 int which;
2442 {
2443 struct sockaddr_iso *siso = sisotab[which];
2444 siso->siso_addr = *iso_addr(addr);
2445
2446 if (which == MASK) {
2447 siso->siso_len = TSEL(siso) - (caddr_t)(siso);
2448 siso->siso_nlen = 0;
2449 } else {
2450 siso->siso_len = sizeof(*siso);
2451 siso->siso_family = AF_ISO;
2452 }
2453 }
2454
2455 void
2456 setsnpaoffset(val, d)
2457 const char *val;
2458 int d;
2459 {
2460 iso_addreq.ifra_snpaoffset = atoi(val);
2461 }
2462
2463 void
2464 setnsellength(val, d)
2465 const char *val;
2466 int d;
2467 {
2468 nsellength = atoi(val);
2469 if (nsellength < 0)
2470 errx(1, "Negative NSEL length is absurd");
2471 if (afp == 0 || afp->af_af != AF_ISO)
2472 errx(1, "Setting NSEL length valid only for iso");
2473 }
2474
2475 void
2476 fixnsel(s)
2477 struct sockaddr_iso *s;
2478 {
2479 if (s->siso_family == 0)
2480 return;
2481 s->siso_tlen = nsellength;
2482 }
2483
2484 void
2485 adjust_nsellength()
2486 {
2487 fixnsel(sisotab[RIDADDR]);
2488 fixnsel(sisotab[ADDR]);
2489 fixnsel(sisotab[DSTADDR]);
2490 }
2491
2492 #endif /* INET_ONLY */
2493
2494 void
2495 usage()
2496 {
2497 extern const char *__progname;
2498
2499 fprintf(stderr,
2500 "usage: %s [ -m ] [ -A ] "
2501 #ifdef INET6
2502 "[ -L ] "
2503 #endif
2504 "interface\n"
2505 "\t[ af [ address [ dest_addr ] ] [ up ] [ down ] "
2506 "[ netmask mask ] ]\n"
2507 "\t[ metric n ]\n"
2508 "\t[ mtu n ]\n"
2509 "\t[ nwid network_id ]\n"
2510 "\t[ [ af ] tunnel src_addr dest_addr ]\n"
2511 "\t[ deletetunnel ]\n"
2512 "\t[ arp | -arp ]\n"
2513 "\t[ media mtype ]\n"
2514 "\t[ mediaopt mopts ]\n"
2515 "\t[ -mediaopt mopts ]\n"
2516 "\t[ instance minst ]\n"
2517 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
2518 " %s -a [ -A ] [ -m ] [ -d ] [ -u ] [ af ]\n"
2519 " %s -l [ -d ] [ -u ]\n"
2520 " %s interface create\n"
2521 " %s interface destroy\n",
2522 __progname, __progname, __progname, __progname, __progname);
2523 exit(1);
2524 }
2525
2526 #ifdef INET6
2527 char *
2528 sec2str(total)
2529 time_t total;
2530 {
2531 static char result[256];
2532 int days, hours, mins, secs;
2533 int first = 1;
2534 char *p = result;
2535
2536 if (0) { /*XXX*/
2537 days = total / 3600 / 24;
2538 hours = (total / 3600) % 24;
2539 mins = (total / 60) % 60;
2540 secs = total % 60;
2541
2542 if (days) {
2543 first = 0;
2544 p += sprintf(p, "%dd", days);
2545 }
2546 if (!first || hours) {
2547 first = 0;
2548 p += sprintf(p, "%dh", hours);
2549 }
2550 if (!first || mins) {
2551 first = 0;
2552 p += sprintf(p, "%dm", mins);
2553 }
2554 sprintf(p, "%ds", secs);
2555 } else
2556 sprintf(p, "%lu", (u_long)total);
2557
2558 return(result);
2559 }
2560 #endif
2561