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