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