ifconfig.c revision 1.81 1 /* $NetBSD: ifconfig.c,v 1.81 2000/07/02 00:28:01 thorpej 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.81 2000/07/02 00:28:01 thorpej 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 u_int8_t nwid[IEEE80211_NWID_LEN];
1098
1099 memset(&nwid, 0, sizeof(nwid));
1100 (void)strncpy(nwid, val, sizeof(nwid));
1101 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1102 ifr.ifr_data = (caddr_t)nwid;
1103 if (ioctl(s, SIOCS80211NWID, (caddr_t)&ifr) < 0)
1104 warn("SIOCS80211NWID");
1105 }
1106
1107 void
1108 ieee80211_status()
1109 {
1110 u_int8_t nwid[IEEE80211_NWID_LEN + 1];
1111
1112 memset(&ifr, 0, sizeof(ifr));
1113 ifr.ifr_data = (caddr_t)nwid;
1114 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1115 nwid[IEEE80211_NWID_LEN] = 0;
1116 if (ioctl(s, SIOCG80211NWID, (caddr_t)&ifr) == 0)
1117 printf("\tnwid %s\n", nwid);
1118 }
1119
1120 void
1121 init_current_media()
1122 {
1123 struct ifmediareq ifmr;
1124
1125 /*
1126 * If we have not yet done so, grab the currently-selected
1127 * media.
1128 */
1129 if ((actions & (A_MEDIA|A_MEDIAOPT)) == 0) {
1130 (void) memset(&ifmr, 0, sizeof(ifmr));
1131 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1132
1133 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
1134 /*
1135 * If we get E2BIG, the kernel is telling us
1136 * that there are more, so we can ignore it.
1137 */
1138 if (errno != E2BIG)
1139 err(1, "SGIOCGIFMEDIA");
1140 }
1141
1142 media_current = ifmr.ifm_current;
1143 }
1144
1145 /* Sanity. */
1146 if (IFM_TYPE(media_current) == 0)
1147 errx(1, "%s: no link type?", name);
1148 }
1149
1150 void
1151 process_media_commands()
1152 {
1153
1154 if ((actions & (A_MEDIA|A_MEDIAOPT)) == 0) {
1155 /* Nothing to do. */
1156 return;
1157 }
1158
1159 /*
1160 * Media already set up, and commands sanity-checked. Set/clear
1161 * any options, and we're ready to go.
1162 */
1163 media_current |= mediaopt_set;
1164 media_current &= ~mediaopt_clear;
1165
1166 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1167 ifr.ifr_media = media_current;
1168
1169 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
1170 err(1, "SIOCSIFMEDIA");
1171 }
1172
1173 void
1174 setmedia(val, d)
1175 const char *val;
1176 int d;
1177 {
1178 int type, subtype, inst;
1179
1180 init_current_media();
1181
1182 /* Only one media command may be given. */
1183 if (actions & A_MEDIA)
1184 errx(1, "only one `media' command may be issued");
1185
1186 /* Must not come after mediaopt commands */
1187 if (actions & A_MEDIAOPT)
1188 errx(1, "may not issue `media' after `mediaopt' commands");
1189
1190 /*
1191 * No need to check if `instance' has been issued; setmediainst()
1192 * craps out if `media' has not been specified.
1193 */
1194
1195 type = IFM_TYPE(media_current);
1196 inst = IFM_INST(media_current);
1197
1198 /* Look up the subtype. */
1199 subtype = get_media_subtype(type, val);
1200
1201 /* Build the new current media word. */
1202 media_current = IFM_MAKEWORD(type, subtype, 0, inst);
1203
1204 /* Media will be set after other processing is complete. */
1205 }
1206
1207 void
1208 setmediaopt(val, d)
1209 const char *val;
1210 int d;
1211 {
1212
1213 init_current_media();
1214
1215 /* Can only issue `mediaopt' once. */
1216 if (actions & A_MEDIAOPTSET)
1217 errx(1, "only one `mediaopt' command may be issued");
1218
1219 /* Can't issue `mediaopt' if `instance' has already been issued. */
1220 if (actions & A_MEDIAINST)
1221 errx(1, "may not issue `mediaopt' after `instance'");
1222
1223 mediaopt_set = get_media_options(IFM_TYPE(media_current), val);
1224
1225 /* Media will be set after other processing is complete. */
1226 }
1227
1228 void
1229 unsetmediaopt(val, d)
1230 const char *val;
1231 int d;
1232 {
1233
1234 init_current_media();
1235
1236 /* Can only issue `-mediaopt' once. */
1237 if (actions & A_MEDIAOPTCLR)
1238 errx(1, "only one `-mediaopt' command may be issued");
1239
1240 /* May not issue `media' and `-mediaopt'. */
1241 if (actions & A_MEDIA)
1242 errx(1, "may not issue both `media' and `-mediaopt'");
1243
1244 /*
1245 * No need to check for A_MEDIAINST, since the test for A_MEDIA
1246 * implicitly checks for A_MEDIAINST.
1247 */
1248
1249 mediaopt_clear = get_media_options(IFM_TYPE(media_current), val);
1250
1251 /* Media will be set after other processing is complete. */
1252 }
1253
1254 void
1255 setmediainst(val, d)
1256 const char *val;
1257 int d;
1258 {
1259 int type, subtype, options, inst;
1260
1261 init_current_media();
1262
1263 /* Can only issue `instance' once. */
1264 if (actions & A_MEDIAINST)
1265 errx(1, "only one `instance' command may be issued");
1266
1267 /* Must have already specified `media' */
1268 if ((actions & A_MEDIA) == 0)
1269 errx(1, "must specify `media' before `instance'");
1270
1271 type = IFM_TYPE(media_current);
1272 subtype = IFM_SUBTYPE(media_current);
1273 options = IFM_OPTIONS(media_current);
1274
1275 inst = atoi(val);
1276 if (inst < 0 || inst > IFM_INST_MAX)
1277 errx(1, "invalid media instance: %s", val);
1278
1279 media_current = IFM_MAKEWORD(type, subtype, options, inst);
1280
1281 /* Media will be set after other processing is complete. */
1282 }
1283
1284 struct ifmedia_description ifm_type_descriptions[] =
1285 IFM_TYPE_DESCRIPTIONS;
1286
1287 struct ifmedia_description ifm_subtype_descriptions[] =
1288 IFM_SUBTYPE_DESCRIPTIONS;
1289
1290 struct ifmedia_description ifm_option_descriptions[] =
1291 IFM_OPTION_DESCRIPTIONS;
1292
1293 const char *
1294 get_media_type_string(mword)
1295 int mword;
1296 {
1297 struct ifmedia_description *desc;
1298
1299 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
1300 desc++) {
1301 if (IFM_TYPE(mword) == desc->ifmt_word)
1302 return (desc->ifmt_string);
1303 }
1304 return ("<unknown type>");
1305 }
1306
1307 const char *
1308 get_media_subtype_string(mword)
1309 int mword;
1310 {
1311 struct ifmedia_description *desc;
1312
1313 for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
1314 desc++) {
1315 if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
1316 IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
1317 return (desc->ifmt_string);
1318 }
1319 return ("<unknown subtype>");
1320 }
1321
1322 int
1323 get_media_subtype(type, val)
1324 int type;
1325 const char *val;
1326 {
1327 int rval;
1328
1329 rval = lookup_media_word(ifm_subtype_descriptions, type, val);
1330 if (rval == -1)
1331 errx(1, "unknown %s media subtype: %s",
1332 get_media_type_string(type), val);
1333
1334 return (rval);
1335 }
1336
1337 int
1338 get_media_options(type, val)
1339 int type;
1340 const char *val;
1341 {
1342 char *optlist, *str;
1343 int option, rval = 0;
1344
1345 /* We muck with the string, so copy it. */
1346 optlist = strdup(val);
1347 if (optlist == NULL)
1348 err(1, "strdup");
1349 str = optlist;
1350
1351 /*
1352 * Look up the options in the user-provided comma-separated list.
1353 */
1354 for (; (str = strtok(str, ",")) != NULL; str = NULL) {
1355 option = lookup_media_word(ifm_option_descriptions, type, str);
1356 if (option == -1)
1357 errx(1, "unknown %s media option: %s",
1358 get_media_type_string(type), str);
1359 rval |= IFM_OPTIONS(option);
1360 }
1361
1362 free(optlist);
1363 return (rval);
1364 }
1365
1366 int
1367 lookup_media_word(desc, type, val)
1368 struct ifmedia_description *desc;
1369 int type;
1370 const char *val;
1371 {
1372
1373 for (; desc->ifmt_string != NULL; desc++) {
1374 if (IFM_TYPE_MATCH(desc->ifmt_word, type) &&
1375 strcasecmp(desc->ifmt_string, val) == 0)
1376 return (desc->ifmt_word);
1377 }
1378 return (-1);
1379 }
1380
1381 void
1382 print_media_word(ifmw, print_type, as_syntax)
1383 int ifmw, print_type, as_syntax;
1384 {
1385 struct ifmedia_description *desc;
1386 int seen_option = 0;
1387
1388 if (print_type)
1389 printf("%s ", get_media_type_string(ifmw));
1390 printf("%s%s", as_syntax ? "media " : "",
1391 get_media_subtype_string(ifmw));
1392
1393 /* Find options. */
1394 for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
1395 desc++) {
1396 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
1397 (ifmw & IFM_OPTIONS(desc->ifmt_word)) != 0 &&
1398 (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
1399 if (seen_option == 0)
1400 printf(" %s", as_syntax ? "mediaopt " : "");
1401 printf("%s%s", seen_option ? "," : "",
1402 desc->ifmt_string);
1403 seen_option |= IFM_OPTIONS(desc->ifmt_word);
1404 }
1405 }
1406 if (IFM_INST(ifmw) != 0)
1407 printf(" instance %d", IFM_INST(ifmw));
1408 }
1409
1410 int carrier()
1411 {
1412 struct ifmediareq ifmr;
1413
1414 (void) memset(&ifmr, 0, sizeof(ifmr));
1415 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1416
1417 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
1418 /*
1419 * Interface doesn't support SIOC{G,S}IFMEDIA;
1420 * assume ok.
1421 */
1422 return 0;
1423 }
1424 if ((ifmr.ifm_status & IFM_AVALID) == 0) {
1425 /*
1426 * Interface doesn't report media-valid status.
1427 * assume ok.
1428 */
1429 return 0;
1430 }
1431 /* otherwise, return ok for active, not-ok if not active. */
1432 return !(ifmr.ifm_status & IFM_ACTIVE);
1433 }
1434
1435
1436 #define IFFBITS \
1437 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
1438 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
1439
1440 const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1441
1442 const struct ifmedia_status_description ifm_status_descriptions[] =
1443 IFM_STATUS_DESCRIPTIONS;
1444
1445 /*
1446 * Print the status of the interface. If an address family was
1447 * specified, show it and it only; otherwise, show them all.
1448 */
1449 void
1450 status(ap, alen)
1451 const u_int8_t *ap;
1452 int alen;
1453 {
1454 struct afswtch *p = afp;
1455 struct ifmediareq ifmr;
1456 int *media_list, i;
1457
1458 printf("%s: ", name);
1459 printb("flags", flags, IFFBITS);
1460 if (metric)
1461 printf(" metric %d", metric);
1462 if (mtu)
1463 printf(" mtu %d", mtu);
1464 putchar('\n');
1465
1466 ieee80211_status();
1467 tunnel_status();
1468
1469 if (ap && alen > 0) {
1470 printf("\taddress:");
1471 for (i = 0; i < alen; i++, ap++)
1472 printf("%c%02x", i > 0 ? ':' : ' ', *ap);
1473 putchar('\n');
1474 }
1475
1476 (void) memset(&ifmr, 0, sizeof(ifmr));
1477 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1478
1479 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
1480 /*
1481 * Interface doesn't support SIOC{G,S}IFMEDIA.
1482 */
1483 goto proto_status;
1484 }
1485
1486 if (ifmr.ifm_count == 0) {
1487 warnx("%s: no media types?", name);
1488 goto proto_status;
1489 }
1490
1491 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
1492 if (media_list == NULL)
1493 err(1, "malloc");
1494 ifmr.ifm_ulist = media_list;
1495
1496 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
1497 err(1, "SIOCGIFMEDIA");
1498
1499 printf("\tmedia: ");
1500 print_media_word(ifmr.ifm_current, 1, 0);
1501 if (ifmr.ifm_active != ifmr.ifm_current) {
1502 putchar(' ');
1503 putchar('(');
1504 print_media_word(ifmr.ifm_active, 0, 0);
1505 putchar(')');
1506 }
1507 putchar('\n');
1508
1509 if (ifmr.ifm_status & IFM_STATUS_VALID) {
1510 const struct ifmedia_status_description *ifms;
1511 int bitno, found = 0;
1512
1513 printf("\tstatus: ");
1514 for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
1515 for (ifms = ifm_status_descriptions;
1516 ifms->ifms_valid != 0; ifms++) {
1517 if (ifms->ifms_type !=
1518 IFM_TYPE(ifmr.ifm_current) ||
1519 ifms->ifms_valid !=
1520 ifm_status_valid_list[bitno])
1521 continue;
1522 printf("%s%s", found ? ", " : "",
1523 IFM_STATUS_DESC(ifms, ifmr.ifm_status));
1524 found = 1;
1525
1526 /*
1527 * For each valid indicator bit, there's
1528 * only one entry for each media type, so
1529 * terminate the inner loop now.
1530 */
1531 break;
1532 }
1533 }
1534
1535 if (found == 0)
1536 printf("unknown");
1537 putchar('\n');
1538 }
1539
1540 if (mflag) {
1541 int type, printed_type;
1542
1543 for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
1544 for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
1545 if (IFM_TYPE(media_list[i]) == type) {
1546 if (printed_type == 0) {
1547 printf("\tsupported %s media:\n",
1548 get_media_type_string(type));
1549 printed_type = 1;
1550 }
1551 printf("\t\t");
1552 print_media_word(media_list[i], 0, 1);
1553 printf("\n");
1554 }
1555 }
1556 }
1557 }
1558
1559 free(media_list);
1560
1561 proto_status:
1562 if ((p = afp) != NULL) {
1563 (*p->af_status)(1);
1564 } else for (p = afs; p->af_name; p++) {
1565 ifr.ifr_addr.sa_family = p->af_af;
1566 (*p->af_status)(0);
1567 }
1568 }
1569
1570 void
1571 tunnel_status()
1572 {
1573 char psrcaddr[NI_MAXHOST];
1574 char pdstaddr[NI_MAXHOST];
1575 u_long srccmd, dstcmd;
1576 struct ifreq *ifrp;
1577 const char *ver = "";
1578 #ifdef NI_WITHSCOPEID
1579 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
1580 #else
1581 const int niflag = NI_NUMERICHOST;
1582 #endif
1583 #ifdef INET6
1584 struct in6_ifreq in6_ifr;
1585 int s6;
1586 #endif /* INET6 */
1587
1588 psrcaddr[0] = pdstaddr[0] = '\0';
1589
1590 #ifdef INET6
1591 memset(&in6_ifr, 0, sizeof(in6_ifr));
1592 strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
1593 s6 = socket(AF_INET6, SOCK_DGRAM, 0);
1594 if (s6 < 0) {
1595 srccmd = SIOCGIFPSRCADDR;
1596 dstcmd = SIOCGIFPDSTADDR;
1597 ifrp = 𝔦
1598 } else {
1599 close(s6);
1600 srccmd = SIOCGIFPSRCADDR_IN6;
1601 dstcmd = SIOCGIFPDSTADDR_IN6;
1602 ifrp = (struct ifreq *)&in6_ifr;
1603 }
1604 #else /* INET6 */
1605 srccmd = SIOCGIFPSRCADDR;
1606 dstcmd = SIOCGIFPDSTADDR;
1607 ifrp = 𝔦
1608 #endif /* INET6 */
1609
1610 if (ioctl(s, srccmd, (caddr_t)ifrp) < 0)
1611 return;
1612 #ifdef INET6
1613 if (ifrp->ifr_addr.sa_family == AF_INET6)
1614 in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
1615 #endif
1616 getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
1617 psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
1618 #ifdef INET6
1619 if (ifrp->ifr_addr.sa_family == AF_INET6)
1620 ver = "6";
1621 #endif
1622
1623 if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0)
1624 return;
1625 #ifdef INET6
1626 if (ifrp->ifr_addr.sa_family == AF_INET6)
1627 in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr);
1628 #endif
1629 getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len,
1630 pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
1631
1632 printf("\ttunnel inet%s %s --> %s\n", ver,
1633 psrcaddr, pdstaddr);
1634 }
1635
1636 void
1637 in_alias(creq)
1638 struct ifreq *creq;
1639 {
1640 struct sockaddr_in *sin;
1641 int alias;
1642
1643 if (lflag)
1644 return;
1645
1646 alias = 1;
1647
1648 /* Get the non-alias address for this interface. */
1649 getsock(AF_INET);
1650 if (s < 0) {
1651 if (errno == EPROTONOSUPPORT)
1652 return;
1653 err(1, "socket");
1654 }
1655 (void) memset(&ifr, 0, sizeof(ifr));
1656 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1657 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1658 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1659 return;
1660 } else
1661 warn("SIOCGIFADDR");
1662 }
1663 /* If creq and ifr are the same address, this is not an alias. */
1664 if (memcmp(&ifr.ifr_addr, &creq->ifr_addr,
1665 sizeof(creq->ifr_addr)) == 0)
1666 alias = 0;
1667 /* we print aliases only with -A */
1668 if (alias && !Aflag)
1669 return;
1670 (void) memset(&addreq, 0, sizeof(addreq));
1671 (void) strncpy(addreq.ifra_name, name, sizeof(addreq.ifra_name));
1672 addreq.ifra_addr = creq->ifr_addr;
1673 if (ioctl(s, SIOCGIFALIAS, (caddr_t)&addreq) < 0) {
1674 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1675 return;
1676 } else
1677 warn("SIOCGIFALIAS");
1678 }
1679
1680 sin = (struct sockaddr_in *)&addreq.ifra_addr;
1681 printf("\tinet %s%s", alias ? "alias " : "", inet_ntoa(sin->sin_addr));
1682
1683 if (flags & IFF_POINTOPOINT) {
1684 sin = (struct sockaddr_in *)&addreq.ifra_dstaddr;
1685 printf(" -> %s", inet_ntoa(sin->sin_addr));
1686 }
1687
1688 sin = (struct sockaddr_in *)&addreq.ifra_mask;
1689 printf(" netmask 0x%x", ntohl(sin->sin_addr.s_addr));
1690
1691 if (flags & IFF_BROADCAST) {
1692 sin = (struct sockaddr_in *)&addreq.ifra_broadaddr;
1693 printf(" broadcast %s", inet_ntoa(sin->sin_addr));
1694 }
1695 printf("\n");
1696 }
1697
1698 void
1699 in_status(force)
1700 int force;
1701 {
1702 #ifdef HAVE_IFADDRS_H
1703 struct ifaddrs *ifap, *ifa;
1704 struct ifreq ifr;
1705
1706 if (getifaddrs(&ifap) != 0)
1707 err(1, "getifaddrs");
1708 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1709 if (strcmp(name, ifa->ifa_name) != 0)
1710 continue;
1711 if (ifa->ifa_addr->sa_family != AF_INET)
1712 continue;
1713 if (sizeof(ifr.ifr_addr) < ifa->ifa_addr->sa_len)
1714 continue;
1715
1716 memset(&ifr, 0, sizeof(ifr));
1717 strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
1718 memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
1719 in_alias(&ifr);
1720 }
1721 freeifaddrs(ifap);
1722 #else
1723 char inbuf[8192];
1724 struct ifconf ifc;
1725 struct ifreq *ifr;
1726 int i, siz;
1727 char ifrbuf[8192], *cp;
1728
1729 ifc.ifc_len = sizeof(inbuf);
1730 ifc.ifc_buf = inbuf;
1731 getsock(af);
1732 if (s < 0)
1733 err(1, "socket");
1734 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
1735 err(1, "SIOCGIFCONF");
1736 for (i = 0; i < ifc.ifc_len; ) {
1737 /* Copy the mininum ifreq into the buffer. */
1738 cp = ((caddr_t)ifc.ifc_req + i);
1739 memcpy(ifrbuf, cp, sizeof(*ifr));
1740
1741 /* Now compute the actual size of the ifreq. */
1742 ifr = (struct ifreq *)ifrbuf;
1743 siz = ifr->ifr_addr.sa_len;
1744 if (siz < sizeof(ifr->ifr_addr))
1745 siz = sizeof(ifr->ifr_addr);
1746 siz += sizeof(ifr->ifr_name);
1747 i += siz;
1748
1749 /* Now copy the whole thing. */
1750 if (sizeof(ifrbuf) < siz)
1751 errx(1, "ifr too big");
1752 memcpy(ifrbuf, cp, siz);
1753
1754 if (!strncmp(name, ifr->ifr_name, sizeof(ifr->ifr_name))) {
1755 if (ifr->ifr_addr.sa_family == AF_INET)
1756 in_alias(ifr);
1757 }
1758 }
1759 #endif
1760 }
1761
1762 void
1763 setifprefixlen(addr, d)
1764 const char *addr;
1765 int d;
1766 {
1767 if (*afp->af_getprefix)
1768 (*afp->af_getprefix)(addr, MASK);
1769 explicit_prefix = 1;
1770 }
1771
1772 #ifdef INET6
1773 void
1774 in6_fillscopeid(sin6)
1775 struct sockaddr_in6 *sin6;
1776 {
1777 #if defined(__KAME__) && defined(KAME_SCOPEID)
1778 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1779 sin6->sin6_scope_id =
1780 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
1781 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
1782 }
1783 #endif
1784 }
1785
1786 /* XXX not really an alias */
1787 void
1788 in6_alias(creq)
1789 struct in6_ifreq *creq;
1790 {
1791 struct sockaddr_in6 *sin6;
1792 char hbuf[NI_MAXHOST];
1793 u_int32_t scopeid;
1794 #ifdef NI_WITHSCOPEID
1795 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
1796 #else
1797 const int niflag = NI_NUMERICHOST;
1798 #endif
1799
1800 /* Get the non-alias address for this interface. */
1801 getsock(AF_INET6);
1802 if (s < 0) {
1803 if (errno == EPROTONOSUPPORT)
1804 return;
1805 err(1, "socket");
1806 }
1807
1808 sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
1809
1810 in6_fillscopeid(sin6);
1811 scopeid = sin6->sin6_scope_id;
1812 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1813 hbuf, sizeof(hbuf), NULL, 0, niflag))
1814 strncpy(hbuf, "", sizeof(hbuf)); /* some message? */
1815 printf("\tinet6 %s", hbuf);
1816
1817 if (flags & IFF_POINTOPOINT) {
1818 (void) memset(&ifr6, 0, sizeof(ifr6));
1819 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1820 ifr6.ifr_addr = creq->ifr_addr;
1821 if (ioctl(s, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) < 0) {
1822 if (errno != EADDRNOTAVAIL)
1823 warn("SIOCGIFDSTADDR_IN6");
1824 (void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
1825 ifr6.ifr_addr.sin6_family = AF_INET6;
1826 ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
1827 }
1828 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1829 in6_fillscopeid(sin6);
1830 hbuf[0] = '\0';
1831 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
1832 hbuf, sizeof(hbuf), NULL, 0, niflag))
1833 strncpy(hbuf, "", sizeof(hbuf)); /* some message? */
1834 printf(" -> %s", hbuf);
1835 }
1836
1837 (void) memset(&ifr6, 0, sizeof(ifr6));
1838 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1839 ifr6.ifr_addr = creq->ifr_addr;
1840 if (ioctl(s, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
1841 if (errno != EADDRNOTAVAIL)
1842 warn("SIOCGIFNETMASK_IN6");
1843 } else {
1844 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1845 printf(" prefixlen %d", prefix(&sin6->sin6_addr,
1846 sizeof(struct in6_addr)));
1847 }
1848
1849 (void) memset(&ifr6, 0, sizeof(ifr6));
1850 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1851 ifr6.ifr_addr = creq->ifr_addr;
1852 if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) < 0) {
1853 if (errno != EADDRNOTAVAIL)
1854 warn("SIOCGIFAFLAG_IN6");
1855 } else {
1856 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
1857 printf(" anycast");
1858 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
1859 printf(" tentative");
1860 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
1861 printf(" duplicated");
1862 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
1863 printf(" detached");
1864 }
1865
1866 if (scopeid)
1867 printf(" scopeid 0x%x", scopeid);
1868
1869 if (Lflag) {
1870 struct in6_addrlifetime *lifetime;
1871 (void) memset(&ifr6, 0, sizeof(ifr6));
1872 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
1873 ifr6.ifr_addr = creq->ifr_addr;
1874 lifetime = &ifr6.ifr_ifru.ifru_lifetime;
1875 if (ioctl(s, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) < 0) {
1876 if (errno != EADDRNOTAVAIL)
1877 warn("SIOCGIFALIFETIME_IN6");
1878 } else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
1879 time_t t = time(NULL);
1880 printf(" pltime ");
1881 if (lifetime->ia6t_preferred) {
1882 printf("%s", lifetime->ia6t_preferred < t
1883 ? "0"
1884 : sec2str(lifetime->ia6t_preferred - t));
1885 } else
1886 printf("infty");
1887
1888 printf(" vltime ");
1889 if (lifetime->ia6t_expire) {
1890 printf("%s", lifetime->ia6t_expire < t
1891 ? "0"
1892 : sec2str(lifetime->ia6t_expire - t));
1893 } else
1894 printf("infty");
1895 }
1896 }
1897
1898 printf("\n");
1899 }
1900
1901 void
1902 in6_status(force)
1903 int force;
1904 {
1905 #ifdef HAVE_IFADDRS_H
1906 struct ifaddrs *ifap, *ifa;
1907 struct in6_ifreq ifr;
1908
1909 if (getifaddrs(&ifap) != 0)
1910 err(1, "getifaddrs");
1911 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1912 if (strcmp(name, ifa->ifa_name) != 0)
1913 continue;
1914 if (ifa->ifa_addr->sa_family != AF_INET6)
1915 continue;
1916 if (sizeof(ifr.ifr_addr) < ifa->ifa_addr->sa_len)
1917 continue;
1918
1919 memset(&ifr, 0, sizeof(ifr));
1920 strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
1921 memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
1922 in6_alias(&ifr);
1923 }
1924 freeifaddrs(ifap);
1925 #else
1926 char inbuf[8192];
1927 struct ifconf ifc;
1928 struct ifreq *ifr;
1929 int i, siz;
1930 char ifrbuf[8192], *cp;
1931
1932 ifc.ifc_len = sizeof(inbuf);
1933 ifc.ifc_buf = inbuf;
1934 getsock(af);
1935 if (s < 0)
1936 err(1, "socket");
1937 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
1938 err(1, "SIOCGIFCONF");
1939 for (i = 0; i < ifc.ifc_len; ) {
1940 /* Copy the mininum ifreq into the buffer. */
1941 cp = ((caddr_t)ifc.ifc_req + i);
1942 memcpy(ifrbuf, cp, sizeof(*ifr));
1943
1944 /* Now compute the actual size of the ifreq. */
1945 ifr = (struct ifreq *)ifrbuf;
1946 siz = ifr->ifr_addr.sa_len;
1947 if (siz < sizeof(ifr->ifr_addr))
1948 siz = sizeof(ifr->ifr_addr);
1949 siz += sizeof(ifr->ifr_name);
1950 i += siz;
1951
1952 /* Now copy the whole thing. */
1953 if (sizeof(ifrbuf) < siz)
1954 errx(1, "ifr too big");
1955 memcpy(ifrbuf, cp, siz);
1956
1957 if (!strncmp(name, ifr->ifr_name, sizeof(ifr->ifr_name))) {
1958 if (ifr->ifr_addr.sa_family == AF_INET6)
1959 in6_alias((struct in6_ifreq *)ifr);
1960 }
1961 }
1962 #endif
1963 }
1964 #endif /*INET6*/
1965
1966 #ifndef INET_ONLY
1967
1968 void
1969 at_status(force)
1970 int force;
1971 {
1972 struct sockaddr_at *sat, null_sat;
1973 struct netrange *nr;
1974
1975 getsock(AF_APPLETALK);
1976 if (s < 0) {
1977 if (errno == EPROTONOSUPPORT)
1978 return;
1979 err(1, "socket");
1980 }
1981 (void) memset(&ifr, 0, sizeof(ifr));
1982 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1983 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1984 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1985 if (!force)
1986 return;
1987 (void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1988 } else
1989 warn("SIOCGIFADDR");
1990 }
1991 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1992 sat = (struct sockaddr_at *)&ifr.ifr_addr;
1993
1994 (void) memset(&null_sat, 0, sizeof(null_sat));
1995
1996 nr = (struct netrange *) &sat->sat_zero;
1997 printf("\tatalk %d.%d range %d-%d phase %d",
1998 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
1999 ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
2000 if (flags & IFF_POINTOPOINT) {
2001 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
2002 if (errno == EADDRNOTAVAIL)
2003 (void) memset(&ifr.ifr_addr, 0,
2004 sizeof(ifr.ifr_addr));
2005 else
2006 warn("SIOCGIFDSTADDR");
2007 }
2008 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2009 sat = (struct sockaddr_at *)&ifr.ifr_dstaddr;
2010 if (!sat)
2011 sat = &null_sat;
2012 printf("--> %d.%d",
2013 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
2014 }
2015 if (flags & IFF_BROADCAST) {
2016 /* note RTAX_BRD overlap with IFF_POINTOPOINT */
2017 sat = (struct sockaddr_at *)&ifr.ifr_broadaddr;
2018 if (sat)
2019 printf(" broadcast %d.%d", ntohs(sat->sat_addr.s_net),
2020 sat->sat_addr.s_node);
2021 }
2022 putchar('\n');
2023 }
2024
2025 void
2026 xns_status(force)
2027 int force;
2028 {
2029 struct sockaddr_ns *sns;
2030
2031 getsock(AF_NS);
2032 if (s < 0) {
2033 if (errno == EPROTONOSUPPORT)
2034 return;
2035 err(1, "socket");
2036 }
2037 (void) memset(&ifr, 0, sizeof(ifr));
2038 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2039 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
2040 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2041 if (!force)
2042 return;
2043 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2044 } else
2045 warn("SIOCGIFADDR");
2046 }
2047 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
2048 sns = (struct sockaddr_ns *)&ifr.ifr_addr;
2049 printf("\tns %s ", ns_ntoa(sns->sns_addr));
2050 if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
2051 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
2052 if (errno == EADDRNOTAVAIL)
2053 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2054 else
2055 warn("SIOCGIFDSTADDR");
2056 }
2057 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2058 sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
2059 printf("--> %s ", ns_ntoa(sns->sns_addr));
2060 }
2061 putchar('\n');
2062 }
2063
2064 void
2065 iso_status(force)
2066 int force;
2067 {
2068 struct sockaddr_iso *siso;
2069 struct iso_ifreq ifr;
2070
2071 getsock(AF_ISO);
2072 if (s < 0) {
2073 if (errno == EPROTONOSUPPORT)
2074 return;
2075 err(1, "socket");
2076 }
2077 (void) memset(&ifr, 0, sizeof(ifr));
2078 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2079 if (ioctl(s, SIOCGIFADDR_ISO, (caddr_t)&ifr) < 0) {
2080 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2081 if (!force)
2082 return;
2083 (void) memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
2084 } else
2085 warn("SIOCGIFADDR_ISO");
2086 }
2087 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
2088 siso = &ifr.ifr_Addr;
2089 printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
2090 if (ioctl(s, SIOCGIFNETMASK_ISO, (caddr_t)&ifr) < 0) {
2091 if (errno == EADDRNOTAVAIL)
2092 memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
2093 else
2094 warn("SIOCGIFNETMASK_ISO");
2095 } else {
2096 if (siso->siso_len > offsetof(struct sockaddr_iso, siso_addr))
2097 siso->siso_addr.isoa_len = siso->siso_len
2098 - offsetof(struct sockaddr_iso, siso_addr);
2099 printf("\n\t\tnetmask %s ", iso_ntoa(&siso->siso_addr));
2100 }
2101 if (flags & IFF_POINTOPOINT) {
2102 if (ioctl(s, SIOCGIFDSTADDR_ISO, (caddr_t)&ifr) < 0) {
2103 if (errno == EADDRNOTAVAIL)
2104 memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
2105 else
2106 warn("SIOCGIFDSTADDR_ISO");
2107 }
2108 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2109 siso = &ifr.ifr_Addr;
2110 printf("--> %s ", iso_ntoa(&siso->siso_addr));
2111 }
2112 putchar('\n');
2113 }
2114
2115 #endif /* INET_ONLY */
2116
2117 #define SIN(x) ((struct sockaddr_in *) &(x))
2118 struct sockaddr_in *sintab[] = {
2119 SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
2120 SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
2121
2122 void
2123 in_getaddr(s, which)
2124 const char *s;
2125 int which;
2126 {
2127 struct sockaddr_in *sin = sintab[which];
2128 struct hostent *hp;
2129 struct netent *np;
2130
2131 sin->sin_len = sizeof(*sin);
2132 if (which != MASK)
2133 sin->sin_family = AF_INET;
2134
2135 if (which == ADDR) {
2136 char *p = NULL;
2137
2138 if((p = strrchr(s, '/')) != NULL) {
2139 /* address is `name/masklen' */
2140 int masklen;
2141 int ret;
2142 struct sockaddr_in *min = sintab[MASK];
2143 *p = '\0';
2144 ret = sscanf(p+1, "%u", &masklen);
2145 if(ret != 1 || (masklen < 0 || masklen > 32)) {
2146 *p = '/';
2147 errx(1, "%s: bad value", s);
2148 }
2149 min->sin_len = sizeof(*min);
2150 min->sin_addr.s_addr =
2151 htonl(~((1LL << (32 - masklen)) - 1) &
2152 0xffffffff);
2153 }
2154 }
2155
2156 if (inet_aton(s, &sin->sin_addr) == 0) {
2157 if ((hp = gethostbyname(s)) != NULL)
2158 (void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
2159 else if ((np = getnetbyname(s)) != NULL)
2160 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
2161 else
2162 errx(1, "%s: bad value", s);
2163 }
2164 }
2165
2166 /*
2167 * Print a value a la the %b format of the kernel's printf
2168 */
2169 void
2170 printb(s, v, bits)
2171 const char *s;
2172 unsigned short v;
2173 const char *bits;
2174 {
2175 int i, any = 0;
2176 char c;
2177
2178 if (bits && *bits == 8)
2179 printf("%s=%o", s, v);
2180 else
2181 printf("%s=%x", s, v);
2182 bits++;
2183 if (bits) {
2184 putchar('<');
2185 while ((i = *bits++) != 0) {
2186 if (v & (1 << (i-1))) {
2187 if (any)
2188 putchar(',');
2189 any = 1;
2190 for (; (c = *bits) > 32; bits++)
2191 putchar(c);
2192 } else
2193 for (; *bits > 32; bits++)
2194 ;
2195 }
2196 putchar('>');
2197 }
2198 }
2199
2200 #ifdef INET6
2201 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
2202 struct sockaddr_in6 *sin6tab[] = {
2203 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
2204 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
2205
2206 void
2207 in6_getaddr(s, which)
2208 const char *s;
2209 int which;
2210 {
2211 #if defined(__KAME__) && defined(KAME_SCOPEID)
2212 struct sockaddr_in6 *sin6 = sin6tab[which];
2213 struct addrinfo hints, *res;
2214 int error;
2215
2216 memset(&hints, 0, sizeof(hints));
2217 hints.ai_family = AF_INET6;
2218 hints.ai_socktype = SOCK_DGRAM;
2219 #if 0 /* in_getaddr() allows FQDN */
2220 hints.ai_flags = AI_NUMERICHOST;
2221 #endif
2222 error = getaddrinfo(s, "0", &hints, &res);
2223 if (error)
2224 errx(1, "%s: %s", s, gai_strerror(error));
2225 if (res->ai_next)
2226 errx(1, "%s: resolved to multiple hosts", s);
2227 if (res->ai_addrlen != sizeof(struct sockaddr_in6))
2228 errx(1, "%s: bad value", s);
2229 memcpy(sin6, res->ai_addr, res->ai_addrlen);
2230 freeaddrinfo(res);
2231 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && sin6->sin6_scope_id) {
2232 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
2233 htons(sin6->sin6_scope_id);
2234 sin6->sin6_scope_id = 0;
2235 }
2236 #else
2237 struct sockaddr_in6 *sin = sin6tab[which];
2238
2239 sin->sin6_len = sizeof(*sin);
2240 if (which != MASK)
2241 sin->sin6_family = AF_INET6;
2242
2243 if (which == ADDR) {
2244 char *p = NULL;
2245 if((p = strrchr(s, '/')) != NULL) {
2246 *p = '\0';
2247 in6_getprefix(p + 1, MASK);
2248 explicit_prefix = 1;
2249 }
2250 }
2251
2252 if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
2253 errx(1, "%s: bad value", s);
2254 #endif
2255 }
2256
2257 void
2258 in6_getprefix(plen, which)
2259 const char *plen;
2260 int which;
2261 {
2262 register struct sockaddr_in6 *sin = sin6tab[which];
2263 register u_char *cp;
2264 int len = strtol(plen, (char **)NULL, 10);
2265
2266 if ((len < 0) || (len > 128))
2267 errx(1, "%s: bad value", plen);
2268 sin->sin6_len = sizeof(*sin);
2269 if (which != MASK)
2270 sin->sin6_family = AF_INET6;
2271 if ((len == 0) || (len == 128)) {
2272 memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
2273 return;
2274 }
2275 memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
2276 for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
2277 *cp++ = 0xff;
2278 *cp = 0xff << (8 - len);
2279 }
2280
2281 int
2282 prefix(val, size)
2283 void *val;
2284 int size;
2285 {
2286 register u_char *name = (u_char *)val;
2287 register int byte, bit, plen = 0;
2288
2289 for (byte = 0; byte < size; byte++, plen += 8)
2290 if (name[byte] != 0xff)
2291 break;
2292 if (byte == size)
2293 return (plen);
2294 for (bit = 7; bit != 0; bit--, plen++)
2295 if (!(name[byte] & (1 << bit)))
2296 break;
2297 for (; bit != 0; bit--)
2298 if (name[byte] & (1 << bit))
2299 return(0);
2300 byte++;
2301 for (; byte < size; byte++)
2302 if (name[byte])
2303 return(0);
2304 return (plen);
2305 }
2306 #endif /*INET6*/
2307
2308 #ifndef INET_ONLY
2309 void
2310 at_getaddr(addr, which)
2311 const char *addr;
2312 int which;
2313 {
2314 struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
2315 u_int net, node;
2316
2317 sat->sat_family = AF_APPLETALK;
2318 sat->sat_len = sizeof(*sat);
2319 if (which == MASK)
2320 errx(1, "AppleTalk does not use netmasks\n");
2321 if (sscanf(addr, "%u.%u", &net, &node) != 2
2322 || net == 0 || net > 0xffff || node == 0 || node > 0xfe)
2323 errx(1, "%s: illegal address", addr);
2324 sat->sat_addr.s_net = htons(net);
2325 sat->sat_addr.s_node = node;
2326 }
2327
2328 void
2329 setatrange(range, d)
2330 const char *range;
2331 int d;
2332 {
2333 u_short first = 123, last = 123;
2334
2335 if (sscanf(range, "%hu-%hu", &first, &last) != 2
2336 || first == 0 || first > 0xffff
2337 || last == 0 || last > 0xffff || first > last)
2338 errx(1, "%s: illegal net range: %u-%u", range, first, last);
2339 at_nr.nr_firstnet = htons(first);
2340 at_nr.nr_lastnet = htons(last);
2341 }
2342
2343 void
2344 setatphase(phase, d)
2345 const char *phase;
2346 int d;
2347 {
2348 if (!strcmp(phase, "1"))
2349 at_nr.nr_phase = 1;
2350 else if (!strcmp(phase, "2"))
2351 at_nr.nr_phase = 2;
2352 else
2353 errx(1, "%s: illegal phase", phase);
2354 }
2355
2356 void
2357 checkatrange(sat)
2358 struct sockaddr_at *sat;
2359 {
2360 if (at_nr.nr_phase == 0)
2361 at_nr.nr_phase = 2; /* Default phase 2 */
2362 if (at_nr.nr_firstnet == 0)
2363 at_nr.nr_firstnet = /* Default range of one */
2364 at_nr.nr_lastnet = sat->sat_addr.s_net;
2365 printf("\tatalk %d.%d range %d-%d phase %d\n",
2366 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
2367 ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
2368 if ((u_short) ntohs(at_nr.nr_firstnet) >
2369 (u_short) ntohs(sat->sat_addr.s_net)
2370 || (u_short) ntohs(at_nr.nr_lastnet) <
2371 (u_short) ntohs(sat->sat_addr.s_net))
2372 errx(1, "AppleTalk address is not in range");
2373 *((struct netrange *) &sat->sat_zero) = at_nr;
2374 }
2375
2376 #define SNS(x) ((struct sockaddr_ns *) &(x))
2377 struct sockaddr_ns *snstab[] = {
2378 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
2379 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
2380
2381 void
2382 xns_getaddr(addr, which)
2383 const char *addr;
2384 int which;
2385 {
2386 struct sockaddr_ns *sns = snstab[which];
2387
2388 sns->sns_family = AF_NS;
2389 sns->sns_len = sizeof(*sns);
2390 sns->sns_addr = ns_addr(addr);
2391 if (which == MASK)
2392 puts("Attempt to set XNS netmask will be ineffectual");
2393 }
2394
2395 #define SISO(x) ((struct sockaddr_iso *) &(x))
2396 struct sockaddr_iso *sisotab[] = {
2397 SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
2398 SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
2399
2400 void
2401 iso_getaddr(addr, which)
2402 const char *addr;
2403 int which;
2404 {
2405 struct sockaddr_iso *siso = sisotab[which];
2406 siso->siso_addr = *iso_addr(addr);
2407
2408 if (which == MASK) {
2409 siso->siso_len = TSEL(siso) - (caddr_t)(siso);
2410 siso->siso_nlen = 0;
2411 } else {
2412 siso->siso_len = sizeof(*siso);
2413 siso->siso_family = AF_ISO;
2414 }
2415 }
2416
2417 void
2418 setsnpaoffset(val, d)
2419 const char *val;
2420 int d;
2421 {
2422 iso_addreq.ifra_snpaoffset = atoi(val);
2423 }
2424
2425 void
2426 setnsellength(val, d)
2427 const char *val;
2428 int d;
2429 {
2430 nsellength = atoi(val);
2431 if (nsellength < 0)
2432 errx(1, "Negative NSEL length is absurd");
2433 if (afp == 0 || afp->af_af != AF_ISO)
2434 errx(1, "Setting NSEL length valid only for iso");
2435 }
2436
2437 void
2438 fixnsel(s)
2439 struct sockaddr_iso *s;
2440 {
2441 if (s->siso_family == 0)
2442 return;
2443 s->siso_tlen = nsellength;
2444 }
2445
2446 void
2447 adjust_nsellength()
2448 {
2449 fixnsel(sisotab[RIDADDR]);
2450 fixnsel(sisotab[ADDR]);
2451 fixnsel(sisotab[DSTADDR]);
2452 }
2453
2454 #endif /* INET_ONLY */
2455
2456 void
2457 usage()
2458 {
2459 extern const char *__progname;
2460
2461 fprintf(stderr,
2462 "usage: %s [ -m ] [ -A ] "
2463 #ifdef INET6
2464 "[ -L ] "
2465 #endif
2466 "interface\n"
2467 "\t[ af [ address [ dest_addr ] ] [ up ] [ down ] "
2468 "[ netmask mask ] ]\n"
2469 "\t[ metric n ]\n"
2470 "\t[ mtu n ]\n"
2471 "\t[ nwid network_id ]\n"
2472 "\t[ [ af ] tunnel src_addr dest_addr ]\n"
2473 "\t[ deletetunnel ]\n"
2474 "\t[ arp | -arp ]\n"
2475 "\t[ media mtype ]\n"
2476 "\t[ mediaopt mopts ]\n"
2477 "\t[ -mediaopt mopts ]\n"
2478 "\t[ instance minst ]\n"
2479 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
2480 " %s -a [ -A ] [ -m ] [ -d ] [ -u ] [ af ]\n"
2481 " %s -l [ -d ] [ -u ]\n"
2482 " %s interface create\n"
2483 " %s interface destroy\n",
2484 __progname, __progname, __progname, __progname, __progname);
2485 exit(1);
2486 }
2487
2488 #ifdef INET6
2489 char *
2490 sec2str(total)
2491 time_t total;
2492 {
2493 static char result[256];
2494 int days, hours, mins, secs;
2495 int first = 1;
2496 char *p = result;
2497
2498 if (0) { /*XXX*/
2499 days = total / 3600 / 24;
2500 hours = (total / 3600) % 24;
2501 mins = (total / 60) % 60;
2502 secs = total % 60;
2503
2504 if (days) {
2505 first = 0;
2506 p += sprintf(p, "%dd", days);
2507 }
2508 if (!first || hours) {
2509 first = 0;
2510 p += sprintf(p, "%dh", hours);
2511 }
2512 if (!first || mins) {
2513 first = 0;
2514 p += sprintf(p, "%dm", mins);
2515 }
2516 sprintf(p, "%ds", secs);
2517 } else
2518 sprintf(p, "%lu", (u_long)total);
2519
2520 return(result);
2521 }
2522 #endif
2523