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