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