ifconfig.c revision 1.152.2.1 1 /* $NetBSD: ifconfig.c,v 1.152.2.1 2006/03/24 22:50:59 riz 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.152.2.1 2006/03/24 22:50:59 riz 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 <net80211/ieee80211.h>
92 #include <net80211/ieee80211_ioctl.h>
93 #include <net/if_vlanvar.h>
94 #include <netinet/in.h>
95 #include <netinet/in_var.h>
96 #ifdef INET6
97 #include <netinet6/nd6.h>
98 #endif
99 #include <arpa/inet.h>
100
101 #include <netatalk/at.h>
102
103 #define NSIP
104 #include <netns/ns.h>
105 #include <netns/ns_if.h>
106 #include <netdb.h>
107
108 #define EON
109 #include <netiso/iso.h>
110 #include <netiso/iso_var.h>
111 #include <sys/protosw.h>
112
113 #include <ctype.h>
114 #include <err.h>
115 #include <errno.h>
116 #include <stddef.h>
117 #include <stdio.h>
118 #include <stdlib.h>
119 #include <string.h>
120 #include <unistd.h>
121 #include <ifaddrs.h>
122 #include <util.h>
123
124 struct ifreq ifr, ridreq;
125 struct ifaliasreq addreq __attribute__((aligned(4)));
126 struct in_aliasreq in_addreq;
127 #ifdef INET6
128 struct in6_ifreq ifr6;
129 struct in6_ifreq in6_ridreq;
130 struct in6_aliasreq in6_addreq;
131 #endif
132 struct iso_ifreq iso_ridreq;
133 struct iso_aliasreq iso_addreq;
134 struct sockaddr_in netmask;
135 struct netrange at_nr; /* AppleTalk net range */
136
137 char name[30];
138 u_short flags;
139 int setaddr, setipdst, doalias;
140 u_long metric, mtu;
141 int clearaddr, s;
142 int newaddr = -1;
143 int conflicting = 0;
144 int nsellength = 1;
145 int af;
146 int aflag, bflag, Cflag, dflag, lflag, mflag, sflag, uflag, vflag, zflag;
147 int hflag;
148 #ifdef INET6
149 int Lflag;
150 #endif
151 int explicit_prefix = 0;
152 u_int vlan_tag = (u_int)-1;
153
154 struct ifcapreq g_ifcr;
155 int g_ifcr_updated;
156
157 void notealias(const char *, int);
158 void notrailers(const char *, int);
159 void setifaddr(const char *, int);
160 void setifdstaddr(const char *, int);
161 void setifflags(const char *, int);
162 void setifcaps(const char *, int);
163 void setifbroadaddr(const char *, int);
164 void setifipdst(const char *, int);
165 void setifmetric(const char *, int);
166 void setifmtu(const char *, int);
167 void setifnwid(const char *, int);
168 void setifnwkey(const char *, int);
169 void setifbssid(const char *, int);
170 void setifchan(const char *, int);
171 void setifpowersave(const char *, int);
172 void setifpowersavesleep(const char *, int);
173 void setifnetmask(const char *, int);
174 void setifprefixlen(const char *, int);
175 void setnsellength(const char *, int);
176 void setsnpaoffset(const char *, int);
177 void setatrange(const char *, int);
178 void setatphase(const char *, int);
179 void settunnel(const char *, const char *);
180 void deletetunnel(const char *, int);
181 #ifdef INET6
182 void setia6flags(const char *, int);
183 void setia6pltime(const char *, int);
184 void setia6vltime(const char *, int);
185 void setia6lifetime(const char *, const char *);
186 void setia6eui64(const char *, int);
187 #endif
188 void checkatrange(struct sockaddr_at *);
189 void setmedia(const char *, int);
190 void setmediamode(const char *, int);
191 void setmediaopt(const char *, int);
192 void unsetmediaopt(const char *, int);
193 void setmediainst(const char *, int);
194 void clone_create(const char *, int);
195 void clone_destroy(const char *, int);
196 void fixnsel(struct sockaddr_iso *);
197 void setvlan(const char *, int);
198 void setvlanif(const char *, int);
199 void unsetvlanif(const char *, int);
200 int main(int, char *[]);
201
202 /*
203 * Media stuff. Whenever a media command is first performed, the
204 * currently select media is grabbed for this interface. If `media'
205 * is given, the current media word is modifed. `mediaopt' commands
206 * only modify the set and clear words. They then operate on the
207 * current media word later.
208 */
209 int media_current;
210 int mediaopt_set;
211 int mediaopt_clear;
212
213 int actions; /* Actions performed */
214
215 #define A_MEDIA 0x0001 /* media command */
216 #define A_MEDIAOPTSET 0x0002 /* mediaopt command */
217 #define A_MEDIAOPTCLR 0x0004 /* -mediaopt command */
218 #define A_MEDIAOPT (A_MEDIAOPTSET|A_MEDIAOPTCLR)
219 #define A_MEDIAINST 0x0008 /* instance or inst command */
220 #define A_MEDIAMODE 0x0010 /* mode command */
221
222 #define NEXTARG 0xffffff
223 #define NEXTARG2 0xfffffe
224
225 const struct cmd {
226 const char *c_name;
227 int c_parameter; /* NEXTARG means next argv */
228 int c_action; /* defered action */
229 void (*c_func)(const char *, int);
230 void (*c_func2)(const char *, const char *);
231 } cmds[] = {
232 { "up", IFF_UP, 0, setifflags } ,
233 { "down", -IFF_UP, 0, setifflags },
234 { "trailers", -1, 0, notrailers },
235 { "-trailers", 1, 0, notrailers },
236 { "arp", -IFF_NOARP, 0, setifflags },
237 { "-arp", IFF_NOARP, 0, setifflags },
238 { "debug", IFF_DEBUG, 0, setifflags },
239 { "-debug", -IFF_DEBUG, 0, setifflags },
240 { "alias", IFF_UP, 0, notealias },
241 { "-alias", -IFF_UP, 0, notealias },
242 { "delete", -IFF_UP, 0, notealias },
243 #ifdef notdef
244 #define EN_SWABIPS 0x1000
245 { "swabips", EN_SWABIPS, 0, setifflags },
246 { "-swabips", -EN_SWABIPS, 0, setifflags },
247 #endif
248 { "netmask", NEXTARG, 0, setifnetmask },
249 { "metric", NEXTARG, 0, setifmetric },
250 { "mtu", NEXTARG, 0, setifmtu },
251 { "bssid", NEXTARG, 0, setifbssid },
252 { "-bssid", -1, 0, setifbssid },
253 { "chan", NEXTARG, 0, setifchan },
254 { "-chan", -1, 0, setifchan },
255 { "ssid", NEXTARG, 0, setifnwid },
256 { "nwid", NEXTARG, 0, setifnwid },
257 { "nwkey", NEXTARG, 0, setifnwkey },
258 { "-nwkey", -1, 0, setifnwkey },
259 { "powersave", 1, 0, setifpowersave },
260 { "-powersave", 0, 0, setifpowersave },
261 { "powersavesleep", NEXTARG, 0, setifpowersavesleep },
262 { "broadcast", NEXTARG, 0, setifbroadaddr },
263 { "ipdst", NEXTARG, 0, setifipdst },
264 { "prefixlen", NEXTARG, 0, setifprefixlen},
265 #ifdef INET6
266 { "anycast", IN6_IFF_ANYCAST, 0, setia6flags },
267 { "-anycast", -IN6_IFF_ANYCAST, 0, setia6flags },
268 { "tentative", IN6_IFF_TENTATIVE, 0, setia6flags },
269 { "-tentative", -IN6_IFF_TENTATIVE, 0, setia6flags },
270 { "deprecated", IN6_IFF_DEPRECATED, 0, setia6flags },
271 { "-deprecated", -IN6_IFF_DEPRECATED, 0, setia6flags },
272 { "pltime", NEXTARG, 0, setia6pltime },
273 { "vltime", NEXTARG, 0, setia6vltime },
274 { "eui64", 0, 0, setia6eui64 },
275 #endif /*INET6*/
276 #ifndef INET_ONLY
277 { "range", NEXTARG, 0, setatrange },
278 { "phase", NEXTARG, 0, setatphase },
279 { "snpaoffset", NEXTARG, 0, setsnpaoffset },
280 { "nsellength", NEXTARG, 0, setnsellength },
281 #endif /* INET_ONLY */
282 { "tunnel", NEXTARG2, 0, NULL,
283 settunnel } ,
284 { "deletetunnel", 0, 0, deletetunnel },
285 { "vlan", NEXTARG, 0, setvlan } ,
286 { "vlanif", NEXTARG, 0, setvlanif } ,
287 { "-vlanif", 0, 0, unsetvlanif } ,
288 #if 0
289 /* XXX `create' special-cased below */
290 { "create", 0, 0, clone_create } ,
291 #endif
292 { "destroy", 0, 0, clone_destroy } ,
293 { "link0", IFF_LINK0, 0, setifflags } ,
294 { "-link0", -IFF_LINK0, 0, setifflags } ,
295 { "link1", IFF_LINK1, 0, setifflags } ,
296 { "-link1", -IFF_LINK1, 0, setifflags } ,
297 { "link2", IFF_LINK2, 0, setifflags } ,
298 { "-link2", -IFF_LINK2, 0, setifflags } ,
299 { "media", NEXTARG, A_MEDIA, setmedia },
300 { "mediaopt", NEXTARG, A_MEDIAOPTSET, setmediaopt },
301 { "-mediaopt", NEXTARG, A_MEDIAOPTCLR, unsetmediaopt },
302 { "mode", NEXTARG, A_MEDIAMODE, setmediamode },
303 { "instance", NEXTARG, A_MEDIAINST, setmediainst },
304 { "inst", NEXTARG, A_MEDIAINST, setmediainst },
305 { "ip4csum", IFCAP_CSUM_IPv4,0, setifcaps },
306 { "-ip4csum", -IFCAP_CSUM_IPv4,0, setifcaps },
307 { "tcp4csum", IFCAP_CSUM_TCPv4,0, setifcaps },
308 { "-tcp4csum", -IFCAP_CSUM_TCPv4,0, setifcaps },
309 { "udp4csum", IFCAP_CSUM_UDPv4,0, setifcaps },
310 { "-udp4csum", -IFCAP_CSUM_UDPv4,0, setifcaps },
311 { "tcp6csum", IFCAP_CSUM_TCPv6,0, setifcaps },
312 { "-tcp6csum", -IFCAP_CSUM_TCPv6,0, setifcaps },
313 { "udp6csum", IFCAP_CSUM_UDPv6,0, setifcaps },
314 { "-udp6csum", -IFCAP_CSUM_UDPv6,0, setifcaps },
315 { "tcp4csum-rx",IFCAP_CSUM_TCPv4_Rx,0, setifcaps },
316 { "-tcp4csum-rx",-IFCAP_CSUM_TCPv4_Rx,0, setifcaps },
317 { "udp4csum-rx",IFCAP_CSUM_UDPv4_Rx,0, setifcaps },
318 { "-udp4csum-rx",-IFCAP_CSUM_UDPv4_Rx,0, setifcaps },
319 { "tso4", IFCAP_TSOv4, 0, setifcaps },
320 { "-tso4", -IFCAP_TSOv4, 0, setifcaps },
321 { 0, 0, 0, setifaddr },
322 { 0, 0, 0, setifdstaddr },
323 };
324
325 void adjust_nsellength(void);
326 int getinfo(struct ifreq *);
327 int carrier(void);
328 void getsock(int);
329 void printall(const char *);
330 void list_cloners(void);
331 int prefix(void *, int);
332 void status(const struct sockaddr_dl *);
333 void usage(void);
334 const char *get_string(const char *, const char *, u_int8_t *, int *);
335 void print_string(const u_int8_t *, int);
336 char *sec2str(time_t);
337
338 void print_media_word(int, const char *);
339 void process_media_commands(void);
340 void init_current_media(void);
341
342 /*
343 * XNS support liberally adapted from code written at the University of
344 * Maryland principally by James O'Toole and Chris Torek.
345 */
346 void in_alias(struct ifreq *);
347 void in_status(int);
348 void in_getaddr(const char *, int);
349 void in_getprefix(const char *, int);
350 #ifdef INET6
351 void in6_fillscopeid(struct sockaddr_in6 *sin6);
352 void in6_alias(struct in6_ifreq *);
353 void in6_status(int);
354 void in6_getaddr(const char *, int);
355 void in6_getprefix(const char *, int);
356 #endif
357 void at_status(int);
358 void at_getaddr(const char *, int);
359 void xns_status(int);
360 void xns_getaddr(const char *, int);
361 void iso_status(int);
362 void iso_getaddr(const char *, int);
363
364 void ieee80211_statistics(void);
365 void ieee80211_status(void);
366 void tunnel_status(void);
367 void vlan_status(void);
368
369 /* Known address families */
370 struct afswtch {
371 const char *af_name;
372 short af_af;
373 void (*af_status)(int);
374 void (*af_getaddr)(const char *, int);
375 void (*af_getprefix)(const char *, int);
376 u_long af_difaddr;
377 u_long af_aifaddr;
378 u_long af_gifaddr;
379 void *af_ridreq;
380 void *af_addreq;
381 } afs[] = {
382 { "inet", AF_INET, in_status, in_getaddr, in_getprefix,
383 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &ridreq, &in_addreq },
384 #ifdef INET6
385 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
386 SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
387 /*
388 * Deleting the first address before setting new one is
389 * not prefered way in this protocol.
390 */
391 0,
392 &in6_ridreq, &in6_addreq },
393 #endif
394 #ifndef INET_ONLY /* small version, for boot media */
395 { "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
396 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &addreq, &addreq },
397 { "ns", AF_NS, xns_status, xns_getaddr, NULL,
398 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &ridreq, &addreq },
399 { "iso", AF_ISO, iso_status, iso_getaddr, NULL,
400 SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, SIOCGIFADDR_ISO,
401 &iso_ridreq, &iso_addreq },
402 #endif /* INET_ONLY */
403 { 0, 0, 0, 0 }
404 };
405
406 struct afswtch *afp; /*the address family being set or asked about*/
407
408 struct afswtch *lookup_af(const char *);
409
410 int
411 main(int argc, char *argv[])
412 {
413 int ch;
414
415 /* Parse command-line options */
416 aflag = mflag = vflag = zflag = 0;
417 while ((ch = getopt(argc, argv, "AabCdhlmsuvz"
418 #ifdef INET6
419 "L"
420 #endif
421 )) != -1) {
422 switch (ch) {
423 case 'A':
424 warnx("-A is deprecated");
425 break;
426
427 case 'a':
428 aflag = 1;
429 break;
430
431 case 'b':
432 bflag = 1;
433 break;
434
435 case 'C':
436 Cflag = 1;
437 break;
438
439 case 'd':
440 dflag = 1;
441 break;
442 case 'h':
443 hflag = 1;
444 break;
445 #ifdef INET6
446 case 'L':
447 Lflag = 1;
448 break;
449 #endif
450
451 case 'l':
452 lflag = 1;
453 break;
454
455 case 'm':
456 mflag = 1;
457 break;
458
459 case 's':
460 sflag = 1;
461 break;
462
463 case 'u':
464 uflag = 1;
465 break;
466
467 case 'v':
468 vflag = 1;
469 break;
470
471 case 'z':
472 zflag = 1;
473 break;
474
475
476 default:
477 usage();
478 /* NOTREACHED */
479 }
480 }
481 argc -= optind;
482 argv += optind;
483
484 /*
485 * -l means "list all interfaces", and is mutally exclusive with
486 * all other flags/commands.
487 *
488 * -C means "list all names of cloners", and it mutually exclusive
489 * with all other flags/commands.
490 *
491 * -a means "print status of all interfaces".
492 */
493 if ((lflag || Cflag) && (aflag || mflag || vflag || argc || zflag))
494 usage();
495 #ifdef INET6
496 if ((lflag || Cflag) && Lflag)
497 usage();
498 #endif
499 if (lflag && Cflag)
500 usage();
501 if (Cflag) {
502 if (argc)
503 usage();
504 list_cloners();
505 exit(0);
506 }
507 if (aflag || lflag) {
508 if (argc > 1)
509 usage();
510 else if (argc == 1) {
511 afp = lookup_af(argv[0]);
512 if (afp == NULL)
513 usage();
514 }
515 if (afp)
516 af = ifr.ifr_addr.sa_family = afp->af_af;
517 else
518 af = ifr.ifr_addr.sa_family = afs[0].af_af;
519 printall(NULL);
520 exit(0);
521 }
522
523 /* Make sure there's an interface name. */
524 if (argc < 1)
525 usage();
526 if (strlcpy(name, argv[0], sizeof(name)) >= sizeof(name))
527 errx(1, "interface name '%s' too long", argv[0]);
528 argc--; argv++;
529
530 /*
531 * NOTE: We must special-case the `create' command right
532 * here as we would otherwise fail in getinfo().
533 */
534 if (argc > 0 && strcmp(argv[0], "create") == 0) {
535 clone_create(argv[0], 0);
536 argc--, argv++;
537 if (argc == 0)
538 exit(0);
539 }
540
541 /* Check for address family. */
542 afp = NULL;
543 if (argc > 0) {
544 afp = lookup_af(argv[0]);
545 if (afp != NULL) {
546 argv++;
547 argc--;
548 }
549 }
550
551 /* Initialize af, just for use in getinfo(). */
552 if (afp == NULL)
553 af = afs->af_af;
554 else
555 af = afp->af_af;
556
557 /* Get information about the interface. */
558 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
559 if (getinfo(&ifr) < 0)
560 exit(1);
561
562 if (sflag) {
563 if (argc != 0)
564 usage();
565 else
566 exit(carrier());
567 }
568
569 /* No more arguments means interface status. */
570 if (argc == 0) {
571 printall(name);
572 exit(0);
573 }
574
575 /* The following operations assume inet family as the default. */
576 if (afp == NULL)
577 afp = afs;
578 af = ifr.ifr_addr.sa_family = afp->af_af;
579
580 #ifdef INET6
581 /* initialization */
582 in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
583 in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
584 #endif
585
586 /* Process commands. */
587 while (argc > 0) {
588 const struct cmd *p;
589
590 for (p = cmds; p->c_name; p++)
591 if (strcmp(argv[0], p->c_name) == 0)
592 break;
593 if (p->c_name == 0 && setaddr) {
594 if ((flags & IFF_POINTOPOINT) == 0) {
595 errx(EXIT_FAILURE,
596 "can't set destination address %s",
597 "on non-point-to-point link");
598 }
599 p++; /* got src, do dst */
600 }
601 if (p->c_func != NULL || p->c_func2 != NULL) {
602 if (p->c_parameter == NEXTARG) {
603 if (argc < 2)
604 errx(EXIT_FAILURE,
605 "'%s' requires argument",
606 p->c_name);
607 (*p->c_func)(argv[1], 0);
608 argc--, argv++;
609 } else if (p->c_parameter == NEXTARG2) {
610 if (argc < 3)
611 errx(EXIT_FAILURE,
612 "'%s' requires 2 arguments",
613 p->c_name);
614 (*p->c_func2)(argv[1], argv[2]);
615 argc -= 2, argv += 2;
616 } else
617 (*p->c_func)(argv[0], p->c_parameter);
618 actions |= p->c_action;
619 }
620 argc--, argv++;
621 }
622
623 /*
624 * See if multiple alias, -alias, or delete commands were
625 * specified. More than one constitutes an invalid command line
626 */
627
628 if (conflicting > 1)
629 errx(EXIT_FAILURE,
630 "Only one use of alias, -alias or delete is valid.");
631
632 /* Process any media commands that may have been issued. */
633 process_media_commands();
634
635 if (af == AF_INET6 && explicit_prefix == 0) {
636 /*
637 * Aggregatable address architecture defines all prefixes
638 * are 64. So, it is convenient to set prefixlen to 64 if
639 * it is not specified.
640 */
641 setifprefixlen("64", 0);
642 /* in6_getprefix("64", MASK) if MASK is available here... */
643 }
644
645 #ifndef INET_ONLY
646 if (af == AF_ISO)
647 adjust_nsellength();
648
649 if (af == AF_APPLETALK)
650 checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
651
652 if (setipdst && af==AF_NS) {
653 struct nsip_req rq;
654 int size = sizeof(rq);
655
656 rq.rq_ns = addreq.ifra_addr;
657 rq.rq_ip = addreq.ifra_dstaddr;
658
659 if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
660 warn("encapsulation routing");
661 }
662
663 #endif /* INET_ONLY */
664
665 if (clearaddr) {
666 (void) strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
667 if (ioctl(s, afp->af_difaddr, afp->af_ridreq) == -1)
668 err(EXIT_FAILURE, "SIOCDIFADDR");
669 }
670 if (newaddr > 0) {
671 (void) strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
672 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) == -1)
673 warn("SIOCAIFADDR");
674 }
675
676 if (g_ifcr_updated) {
677 (void) strncpy(g_ifcr.ifcr_name, name,
678 sizeof(g_ifcr.ifcr_name));
679 if (ioctl(s, SIOCSIFCAP, &g_ifcr) == -1)
680 err(EXIT_FAILURE, "SIOCSIFCAP");
681 }
682
683 exit(0);
684 }
685
686 struct afswtch *
687 lookup_af(const char *cp)
688 {
689 struct afswtch *a;
690
691 for (a = afs; a->af_name != NULL; a++)
692 if (strcmp(a->af_name, cp) == 0)
693 return (a);
694 return (NULL);
695 }
696
697 void
698 getsock(int naf)
699 {
700 static int oaf = -1;
701
702 if (oaf == naf)
703 return;
704 if (oaf != -1)
705 close(s);
706 s = socket(naf, SOCK_DGRAM, 0);
707 if (s < 0)
708 oaf = -1;
709 else
710 oaf = naf;
711 }
712
713 int
714 getinfo(struct ifreq *giifr)
715 {
716
717 getsock(af);
718 if (s < 0)
719 err(EXIT_FAILURE, "socket");
720 if (ioctl(s, SIOCGIFFLAGS, giifr) == -1) {
721 warn("SIOCGIFFLAGS %s", giifr->ifr_name);
722 return (-1);
723 }
724 flags = giifr->ifr_flags;
725 if (ioctl(s, SIOCGIFMETRIC, giifr) == -1) {
726 warn("SIOCGIFMETRIC %s", giifr->ifr_name);
727 metric = 0;
728 } else
729 metric = giifr->ifr_metric;
730 if (ioctl(s, SIOCGIFMTU, giifr) == -1)
731 mtu = 0;
732 else
733 mtu = giifr->ifr_mtu;
734
735 memset(&g_ifcr, 0, sizeof(g_ifcr));
736 strcpy(g_ifcr.ifcr_name, giifr->ifr_name);
737 (void) ioctl(s, SIOCGIFCAP, &g_ifcr);
738
739 return (0);
740 }
741
742 void
743 printall(const char *ifname)
744 {
745 struct ifaddrs *ifap, *ifa;
746 struct ifreq paifr;
747 const struct sockaddr_dl *sdl = NULL;
748 int idx;
749 char *p;
750
751 if (getifaddrs(&ifap) != 0)
752 err(EXIT_FAILURE, "getifaddrs");
753 p = NULL;
754 idx = 0;
755 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
756 memset(&paifr, 0, sizeof(paifr));
757 strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
758 if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
759 memcpy(&paifr.ifr_addr, ifa->ifa_addr,
760 ifa->ifa_addr->sa_len);
761 }
762
763 if (ifname && strcmp(ifname, ifa->ifa_name) != 0)
764 continue;
765 if (ifa->ifa_addr->sa_family == AF_LINK)
766 sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
767 if (p && strcmp(p, ifa->ifa_name) == 0)
768 continue;
769 if (strlcpy(name, ifa->ifa_name, sizeof(name)) >= sizeof(name))
770 continue;
771 p = ifa->ifa_name;
772
773 if (getinfo(&paifr) < 0)
774 continue;
775 if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0)
776 continue;
777 if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
778 continue;
779 if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
780 continue;
781
782 if (sflag && carrier())
783 continue;
784 idx++;
785 /*
786 * Are we just listing the interfaces?
787 */
788 if (lflag) {
789 if (idx > 1)
790 printf(" ");
791 fputs(name, stdout);
792 continue;
793 }
794
795 status(sdl);
796 sdl = NULL;
797 }
798 if (lflag)
799 printf("\n");
800 freeifaddrs(ifap);
801 }
802
803 void
804 list_cloners(void)
805 {
806 struct if_clonereq ifcr;
807 char *cp, *buf;
808 int idx;
809
810 memset(&ifcr, 0, sizeof(ifcr));
811
812 getsock(AF_INET);
813
814 if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
815 err(EXIT_FAILURE, "SIOCIFGCLONERS for count");
816
817 buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
818 if (buf == NULL)
819 err(EXIT_FAILURE, "unable to allocate cloner name buffer");
820
821 ifcr.ifcr_count = ifcr.ifcr_total;
822 ifcr.ifcr_buffer = buf;
823
824 if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
825 err(EXIT_FAILURE, "SIOCIFGCLONERS for names");
826
827 /*
828 * In case some disappeared in the mean time, clamp it down.
829 */
830 if (ifcr.ifcr_count > ifcr.ifcr_total)
831 ifcr.ifcr_count = ifcr.ifcr_total;
832
833 for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
834 if (idx > 0)
835 printf(" ");
836 printf("%s", cp);
837 }
838
839 printf("\n");
840 free(buf);
841 return;
842 }
843
844 /*ARGSUSED*/
845 void
846 clone_create(const char *addr, int param)
847 {
848
849 /* We're called early... */
850 getsock(AF_INET);
851
852 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
853 if (ioctl(s, SIOCIFCREATE, &ifr) == -1)
854 err(EXIT_FAILURE, "SIOCIFCREATE");
855 }
856
857 /*ARGSUSED*/
858 void
859 clone_destroy(const char *addr, int param)
860 {
861
862 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
863 if (ioctl(s, SIOCIFDESTROY, &ifr) == -1)
864 err(EXIT_FAILURE, "SIOCIFDESTROY");
865 }
866
867 #define RIDADDR 0
868 #define ADDR 1
869 #define MASK 2
870 #define DSTADDR 3
871
872 /*ARGSUSED*/
873 void
874 setifaddr(const char *addr, int param)
875 {
876 struct ifreq *siifr; /* XXX */
877
878 /*
879 * Delay the ioctl to set the interface addr until flags are all set.
880 * The address interpretation may depend on the flags,
881 * and the flags may change when the address is set.
882 */
883 setaddr++;
884 if (newaddr == -1)
885 newaddr = 1;
886 if (doalias == 0 && afp->af_gifaddr != 0) {
887 siifr = (struct ifreq *)afp->af_ridreq;
888 (void) strncpy(siifr->ifr_name, name, sizeof(siifr->ifr_name));
889 siifr->ifr_addr.sa_family = afp->af_af;
890 if (ioctl(s, afp->af_gifaddr, afp->af_ridreq) == 0)
891 clearaddr = 1;
892 else if (errno == EADDRNOTAVAIL)
893 /* No address was assigned yet. */
894 ;
895 else
896 err(EXIT_FAILURE, "SIOCGIFADDR");
897 }
898
899 (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
900 }
901
902 void
903 settunnel(const char *src, const char *dst)
904 {
905 struct addrinfo hints, *srcres, *dstres;
906 int ecode;
907 struct if_laddrreq req;
908
909 memset(&hints, 0, sizeof(hints));
910 hints.ai_family = afp->af_af;
911 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
912
913 if ((ecode = getaddrinfo(src, NULL, &hints, &srcres)) != 0)
914 errx(EXIT_FAILURE, "error in parsing address string: %s",
915 gai_strerror(ecode));
916
917 if ((ecode = getaddrinfo(dst, NULL, &hints, &dstres)) != 0)
918 errx(EXIT_FAILURE, "error in parsing address string: %s",
919 gai_strerror(ecode));
920
921 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
922 errx(EXIT_FAILURE,
923 "source and destination address families do not match");
924
925 if (srcres->ai_addrlen > sizeof(req.addr) ||
926 dstres->ai_addrlen > sizeof(req.dstaddr))
927 errx(EXIT_FAILURE, "invalid sockaddr");
928
929 memset(&req, 0, sizeof(req));
930 strncpy(req.iflr_name, name, sizeof(req.iflr_name));
931 memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
932 memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
933
934 #ifdef INET6
935 if (req.addr.ss_family == AF_INET6) {
936 struct sockaddr_in6 *s6, *d;
937
938 s6 = (struct sockaddr_in6 *)&req.addr;
939 d = (struct sockaddr_in6 *)&req.dstaddr;
940 if (s6->sin6_scope_id != d->sin6_scope_id) {
941 errx(EXIT_FAILURE, "scope mismatch");
942 /* NOTREACHED */
943 }
944 #ifdef __KAME__
945 /* embed scopeid */
946 if (s6->sin6_scope_id &&
947 (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) ||
948 IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr))) {
949 *(u_int16_t *)&s6->sin6_addr.s6_addr[2] =
950 htons(s6->sin6_scope_id);
951 }
952 if (d->sin6_scope_id &&
953 (IN6_IS_ADDR_LINKLOCAL(&d->sin6_addr) ||
954 IN6_IS_ADDR_MC_LINKLOCAL(&d->sin6_addr))) {
955 *(u_int16_t *)&d->sin6_addr.s6_addr[2] =
956 htons(d->sin6_scope_id);
957 }
958 #endif
959 }
960 #endif
961
962 if (ioctl(s, SIOCSLIFPHYADDR, &req) == -1)
963 warn("SIOCSLIFPHYADDR");
964
965 freeaddrinfo(srcres);
966 freeaddrinfo(dstres);
967 }
968
969 /* ARGSUSED */
970 void
971 deletetunnel(const char *vname, int param)
972 {
973
974 if (ioctl(s, SIOCDIFPHYADDR, &ifr) == -1)
975 err(EXIT_FAILURE, "SIOCDIFPHYADDR");
976 }
977
978 void
979 setvlan(const char *val, int d)
980 {
981 struct vlanreq vlr;
982
983 if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
984 !isdigit((unsigned char)ifr.ifr_name[4]))
985 errx(EXIT_FAILURE,
986 "``vlan'' valid only with vlan(4) interfaces");
987
988 vlan_tag = atoi(val);
989
990 memset(&vlr, 0, sizeof(vlr));
991 ifr.ifr_data = (void *)&vlr;
992
993 if (ioctl(s, SIOCGETVLAN, &ifr) == -1)
994 err(EXIT_FAILURE, "SIOCGETVLAN");
995
996 vlr.vlr_tag = vlan_tag;
997
998 if (ioctl(s, SIOCSETVLAN, &ifr) == -1)
999 err(EXIT_FAILURE, "SIOCSETVLAN");
1000 }
1001
1002 void
1003 setvlanif(const char *val, int d)
1004 {
1005 struct vlanreq vlr;
1006
1007 if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
1008 !isdigit((unsigned char)ifr.ifr_name[4]))
1009 errx(EXIT_FAILURE,
1010 "``vlanif'' valid only with vlan(4) interfaces");
1011
1012 if (vlan_tag == (u_int)-1)
1013 errx(EXIT_FAILURE,
1014 "must specify both ``vlan'' and ``vlanif''");
1015
1016 memset(&vlr, 0, sizeof(vlr));
1017 ifr.ifr_data = (void *)&vlr;
1018
1019 if (ioctl(s, SIOCGETVLAN, &ifr) == -1)
1020 err(EXIT_FAILURE, "SIOCGETVLAN");
1021
1022 strlcpy(vlr.vlr_parent, val, sizeof(vlr.vlr_parent));
1023 vlr.vlr_tag = vlan_tag;
1024
1025 if (ioctl(s, SIOCSETVLAN, &ifr) == -1)
1026 err(EXIT_FAILURE, "SIOCSETVLAN");
1027 }
1028
1029 void
1030 unsetvlanif(const char *val, int d)
1031 {
1032 struct vlanreq vlr;
1033
1034 if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
1035 !isdigit((unsigned char)ifr.ifr_name[4]))
1036 errx(EXIT_FAILURE,
1037 "``vlanif'' valid only with vlan(4) interfaces");
1038
1039 memset(&vlr, 0, sizeof(vlr));
1040 ifr.ifr_data = (void *)&vlr;
1041
1042 if (ioctl(s, SIOCGETVLAN, &ifr) == -1)
1043 err(EXIT_FAILURE, "SIOCGETVLAN");
1044
1045 vlr.vlr_parent[0] = '\0';
1046 vlr.vlr_tag = 0;
1047
1048 if (ioctl(s, SIOCSETVLAN, &ifr) == -1)
1049 err(EXIT_FAILURE, "SIOCSETVLAN");
1050 }
1051
1052 void
1053 setifnetmask(const char *addr, int d)
1054 {
1055 (*afp->af_getaddr)(addr, MASK);
1056 }
1057
1058 void
1059 setifbroadaddr(const char *addr, int d)
1060 {
1061 (*afp->af_getaddr)(addr, DSTADDR);
1062 }
1063
1064 void
1065 setifipdst(const char *addr, int d)
1066 {
1067 in_getaddr(addr, DSTADDR);
1068 setipdst++;
1069 clearaddr = 0;
1070 newaddr = 0;
1071 }
1072
1073 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
1074 /*ARGSUSED*/
1075 void
1076 notealias(const char *addr, int param)
1077 {
1078 if (setaddr && doalias == 0 && param < 0)
1079 (void) memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
1080 rqtosa(af_addreq)->sa_len);
1081 doalias = param;
1082 if (param < 0) {
1083 clearaddr = 1;
1084 newaddr = 0;
1085 conflicting++;
1086 } else {
1087 clearaddr = 0;
1088 conflicting++;
1089 }
1090 }
1091
1092 /*ARGSUSED*/
1093 void
1094 notrailers(const char *vname, int value)
1095 {
1096 puts("Note: trailers are no longer sent, but always received");
1097 }
1098
1099 /*ARGSUSED*/
1100 void
1101 setifdstaddr(const char *addr, int param)
1102 {
1103 (*afp->af_getaddr)(addr, DSTADDR);
1104 }
1105
1106 void
1107 setifflags(const char *vname, int value)
1108 {
1109 struct ifreq ifreq;
1110
1111 (void) strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
1112 if (ioctl(s, SIOCGIFFLAGS, &ifreq) == -1)
1113 err(EXIT_FAILURE, "SIOCGIFFLAGS");
1114 flags = ifreq.ifr_flags;
1115
1116 if (value < 0) {
1117 value = -value;
1118 flags &= ~value;
1119 } else
1120 flags |= value;
1121 ifreq.ifr_flags = flags;
1122 if (ioctl(s, SIOCSIFFLAGS, &ifreq) == -1)
1123 err(EXIT_FAILURE, "SIOCSIFFLAGS");
1124 }
1125
1126 void
1127 setifcaps(const char *vname, int value)
1128 {
1129
1130 if (value < 0) {
1131 value = -value;
1132 g_ifcr.ifcr_capenable &= ~value;
1133 } else
1134 g_ifcr.ifcr_capenable |= value;
1135
1136 g_ifcr_updated = 1;
1137 }
1138
1139 #ifdef INET6
1140 void
1141 setia6flags(const char *vname, int value)
1142 {
1143
1144 if (value < 0) {
1145 value = -value;
1146 in6_addreq.ifra_flags &= ~value;
1147 } else
1148 in6_addreq.ifra_flags |= value;
1149 }
1150
1151 void
1152 setia6pltime(const char *val, int d)
1153 {
1154
1155 setia6lifetime("pltime", val);
1156 }
1157
1158 void
1159 setia6vltime(const char *val, int d)
1160 {
1161
1162 setia6lifetime("vltime", val);
1163 }
1164
1165 void
1166 setia6lifetime(const char *cmd, const char *val)
1167 {
1168 time_t newval, t;
1169 char *ep;
1170
1171 t = time(NULL);
1172 newval = (time_t)strtoul(val, &ep, 0);
1173 if (val == ep)
1174 errx(EXIT_FAILURE, "invalid %s", cmd);
1175 if (afp->af_af != AF_INET6)
1176 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
1177 if (strcmp(cmd, "vltime") == 0) {
1178 in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
1179 in6_addreq.ifra_lifetime.ia6t_vltime = newval;
1180 } else if (strcmp(cmd, "pltime") == 0) {
1181 in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
1182 in6_addreq.ifra_lifetime.ia6t_pltime = newval;
1183 }
1184 }
1185
1186 void
1187 setia6eui64(const char *cmd, int val)
1188 {
1189 struct ifaddrs *ifap, *ifa;
1190 const struct sockaddr_in6 *sin6 = NULL;
1191 const struct in6_addr *lladdr = NULL;
1192 struct in6_addr *in6;
1193
1194 if (afp->af_af != AF_INET6)
1195 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
1196 in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
1197 if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
1198 errx(EXIT_FAILURE, "interface index is already filled");
1199 if (getifaddrs(&ifap) != 0)
1200 err(EXIT_FAILURE, "getifaddrs");
1201 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1202 if (ifa->ifa_addr->sa_family == AF_INET6 &&
1203 strcmp(ifa->ifa_name, name) == 0) {
1204 sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
1205 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1206 lladdr = &sin6->sin6_addr;
1207 break;
1208 }
1209 }
1210 }
1211 if (!lladdr)
1212 errx(EXIT_FAILURE, "could not determine link local address");
1213
1214 memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
1215
1216 freeifaddrs(ifap);
1217 }
1218 #endif
1219
1220 void
1221 setifmetric(const char *val, int d)
1222 {
1223 char *ep = NULL;
1224
1225 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1226 ifr.ifr_metric = strtoul(val, &ep, 10);
1227 if (!ep || *ep)
1228 errx(EXIT_FAILURE, "%s: invalid metric", val);
1229 if (ioctl(s, SIOCSIFMETRIC, &ifr) == -1)
1230 warn("SIOCSIFMETRIC");
1231 }
1232
1233 void
1234 setifmtu(const char *val, int d)
1235 {
1236 char *ep = NULL;
1237
1238 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1239 ifr.ifr_mtu = strtoul(val, &ep, 10);
1240 if (!ep || *ep)
1241 errx(EXIT_FAILURE, "%s: invalid mtu", val);
1242 if (ioctl(s, SIOCSIFMTU, &ifr) == -1)
1243 warn("SIOCSIFMTU");
1244 }
1245
1246 const char *
1247 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1248 {
1249 int len;
1250 int hexstr;
1251 u_int8_t *p;
1252
1253 len = *lenp;
1254 p = buf;
1255 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1256 if (hexstr)
1257 val += 2;
1258 for (;;) {
1259 if (*val == '\0')
1260 break;
1261 if (sep != NULL && strchr(sep, *val) != NULL) {
1262 val++;
1263 break;
1264 }
1265 if (hexstr) {
1266 if (!isxdigit((u_char)val[0]) ||
1267 !isxdigit((u_char)val[1])) {
1268 warnx("bad hexadecimal digits");
1269 return NULL;
1270 }
1271 }
1272 if (p > buf + len) {
1273 if (hexstr)
1274 warnx("hexadecimal digits too long");
1275 else
1276 warnx("strings too long");
1277 return NULL;
1278 }
1279 if (hexstr) {
1280 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1281 *p++ = (tohex((u_char)val[0]) << 4) |
1282 tohex((u_char)val[1]);
1283 #undef tohex
1284 val += 2;
1285 } else
1286 *p++ = *val++;
1287 }
1288 len = p - buf;
1289 if (len < *lenp)
1290 memset(p, 0, *lenp - len);
1291 *lenp = len;
1292 return val;
1293 }
1294
1295 void
1296 print_string(const u_int8_t *buf, int len)
1297 {
1298 int i;
1299 int hasspc;
1300
1301 i = 0;
1302 hasspc = 0;
1303 if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1304 for (; i < len; i++) {
1305 if (!isprint(buf[i]))
1306 break;
1307 if (isspace(buf[i]))
1308 hasspc++;
1309 }
1310 }
1311 if (i == len) {
1312 if (hasspc || len == 0)
1313 printf("\"%.*s\"", len, buf);
1314 else
1315 printf("%.*s", len, buf);
1316 } else {
1317 printf("0x");
1318 for (i = 0; i < len; i++)
1319 printf("%02x", buf[i]);
1320 }
1321 }
1322
1323 void
1324 setifnwid(const char *val, int d)
1325 {
1326 struct ieee80211_nwid nwid;
1327 int len;
1328
1329 len = sizeof(nwid.i_nwid);
1330 if (get_string(val, NULL, nwid.i_nwid, &len) == NULL)
1331 return;
1332 nwid.i_len = len;
1333 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1334 ifr.ifr_data = (void *)&nwid;
1335 if (ioctl(s, SIOCS80211NWID, &ifr) == -1)
1336 warn("SIOCS80211NWID");
1337 }
1338
1339 void
1340 setifbssid(const char *val, int d)
1341 {
1342 struct ieee80211_bssid bssid;
1343 struct ether_addr *ea;
1344
1345 if (d != 0) {
1346 /* no BSSID is especially desired */
1347 memset(&bssid.i_bssid, 0, sizeof(bssid.i_bssid));
1348 } else {
1349 ea = ether_aton(val);
1350 if (ea == NULL) {
1351 warnx("malformed BSSID: %s", val);
1352 return;
1353 }
1354 memcpy(&bssid.i_bssid, ea->ether_addr_octet,
1355 sizeof(bssid.i_bssid));
1356 }
1357 (void)strncpy(bssid.i_name, name, sizeof(bssid.i_name));
1358 if (ioctl(s, SIOCS80211BSSID, &bssid) == -1)
1359 warn("SIOCS80211BSSID");
1360 }
1361
1362 void
1363 setifchan(const char *val, int d)
1364 {
1365 struct ieee80211chanreq channel;
1366 int chan;
1367
1368 if (d != 0)
1369 chan = IEEE80211_CHAN_ANY;
1370 else {
1371 chan = atoi(val);
1372 if (chan < 0 || chan > 0xffff) {
1373 warnx("invalid channel: %s", val);
1374 return;
1375 }
1376 }
1377
1378 (void)strncpy(channel.i_name, name, sizeof(channel.i_name));
1379 channel.i_channel = (u_int16_t) chan;
1380 if (ioctl(s, SIOCS80211CHANNEL, &channel) == -1)
1381 warn("SIOCS80211CHANNEL");
1382 }
1383
1384 void
1385 setifnwkey(const char *val, int d)
1386 {
1387 struct ieee80211_nwkey nwkey;
1388 int i;
1389 u_int8_t keybuf[IEEE80211_WEP_NKID][16];
1390
1391 nwkey.i_wepon = IEEE80211_NWKEY_WEP;
1392 nwkey.i_defkid = 1;
1393 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1394 nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
1395 nwkey.i_key[i].i_keydat = keybuf[i];
1396 }
1397 if (d != 0) {
1398 /* disable WEP encryption */
1399 nwkey.i_wepon = 0;
1400 i = 0;
1401 } else if (strcasecmp("persist", val) == 0) {
1402 /* use all values from persistent memory */
1403 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1404 nwkey.i_defkid = 0;
1405 for (i = 0; i < IEEE80211_WEP_NKID; i++)
1406 nwkey.i_key[i].i_keylen = -1;
1407 } else if (strncasecmp("persist:", val, 8) == 0) {
1408 val += 8;
1409 /* program keys in persistent memory */
1410 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1411 goto set_nwkey;
1412 } else {
1413 set_nwkey:
1414 if (isdigit((unsigned char)val[0]) && val[1] == ':') {
1415 /* specifying a full set of four keys */
1416 nwkey.i_defkid = val[0] - '0';
1417 val += 2;
1418 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1419 val = get_string(val, ",", keybuf[i],
1420 &nwkey.i_key[i].i_keylen);
1421 if (val == NULL)
1422 return;
1423 }
1424 if (*val != '\0') {
1425 warnx("SIOCS80211NWKEY: too many keys.");
1426 return;
1427 }
1428 } else {
1429 val = get_string(val, NULL, keybuf[0],
1430 &nwkey.i_key[0].i_keylen);
1431 if (val == NULL)
1432 return;
1433 i = 1;
1434 }
1435 }
1436 for (; i < IEEE80211_WEP_NKID; i++)
1437 nwkey.i_key[i].i_keylen = 0;
1438 (void)strncpy(nwkey.i_name, name, sizeof(nwkey.i_name));
1439 if (ioctl(s, SIOCS80211NWKEY, &nwkey) == -1)
1440 warn("SIOCS80211NWKEY");
1441 }
1442
1443 void
1444 setifpowersave(const char *val, int d)
1445 {
1446 struct ieee80211_power power;
1447
1448 (void)strncpy(power.i_name, name, sizeof(power.i_name));
1449 if (ioctl(s, SIOCG80211POWER, &power) == -1) {
1450 warn("SIOCG80211POWER");
1451 return;
1452 }
1453
1454 power.i_enabled = d;
1455 if (ioctl(s, SIOCS80211POWER, &power) == -1)
1456 warn("SIOCS80211POWER");
1457 }
1458
1459 void
1460 setifpowersavesleep(const char *val, int d)
1461 {
1462 struct ieee80211_power power;
1463
1464 (void)strncpy(power.i_name, name, sizeof(power.i_name));
1465 if (ioctl(s, SIOCG80211POWER, &power) == -1) {
1466 warn("SIOCG80211POWER");
1467 return;
1468 }
1469
1470 power.i_maxsleep = atoi(val);
1471 if (ioctl(s, SIOCS80211POWER, &power) == -1)
1472 warn("SIOCS80211POWER");
1473 }
1474
1475 void
1476 ieee80211_statistics(void)
1477 {
1478 struct ieee80211_stats stats;
1479
1480 memset(&ifr, 0, sizeof(ifr));
1481 ifr.ifr_data = (caddr_t)&stats;
1482 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1483 if (ioctl(s, (zflag) ? SIOCG80211ZSTATS : SIOCG80211STATS,
1484 (caddr_t)&ifr) == -1)
1485 return;
1486 #define RX_PRINT(desc, member) printf("\trx " desc ": %u\n", stats.member)
1487 #define TX_PRINT(desc, member) printf("\ttx " desc ": %u\n", stats.member)
1488
1489 RX_PRINT("too short", is_rx_tooshort);
1490 RX_PRINT("bad version", is_rx_badversion);
1491 RX_PRINT("wrong bss", is_rx_wrongbss);
1492 RX_PRINT("duplicate", is_rx_dup);
1493 RX_PRINT("wrong direction", is_rx_wrongdir);
1494 RX_PRINT("multicast echo", is_rx_mcastecho);
1495 RX_PRINT("STA not associated", is_rx_notassoc);
1496 RX_PRINT("WEP-encrypted but WEP not configured", is_rx_nowep);
1497 RX_PRINT("WEP processing failed", is_rx_wepfail);
1498 #if 0
1499 RX_PRINT("single (M)MSDU, both WEP/non-WEP fragments", is_rx_wepmix);
1500 RX_PRINT("non-consecutive fragments", is_rx_fragorder);
1501 #endif
1502 RX_PRINT("decapsulation failed", is_rx_decap);
1503 RX_PRINT("management-type discarded", is_rx_mgtdiscard);
1504 RX_PRINT("control-type discarded", is_rx_ctl);
1505 RX_PRINT("truncated rate set", is_rx_rstoobig);
1506 RX_PRINT("beacon/prresp element missing", is_rx_elem_missing);
1507 RX_PRINT("beacon/prresp element too big", is_rx_elem_toobig);
1508 RX_PRINT("beacon/prresp element too small", is_rx_elem_toosmall);
1509 RX_PRINT("beacon/prresp element unknown", is_rx_elem_unknown);
1510 RX_PRINT("invalid channel", is_rx_badchan);
1511 RX_PRINT("channel mismatch", is_rx_chanmismatch);
1512 RX_PRINT("failed node allocation", is_rx_nodealloc);
1513 RX_PRINT("SSID mismatch", is_rx_ssidmismatch);
1514 RX_PRINT("unsupported authentication algor.", is_rx_auth_unsupported);
1515 RX_PRINT("STA authentication failure", is_rx_auth_fail);
1516 RX_PRINT("association for wrong bss", is_rx_assoc_bss);
1517 RX_PRINT("association without authenication", is_rx_assoc_notauth);
1518 RX_PRINT("association capability mismatch", is_rx_assoc_capmismatch);
1519 RX_PRINT("association without rate match", is_rx_assoc_norate);
1520 RX_PRINT("deauthentication", is_rx_deauth);
1521 RX_PRINT("disassocation", is_rx_disassoc);
1522 RX_PRINT("unknown subtype", is_rx_badsubtype);
1523 RX_PRINT("failed, mbuf unavailable", is_rx_nombuf);
1524 RX_PRINT("failed, bad ICV", is_rx_decryptcrc);
1525 RX_PRINT("discard mgmt frame in ad-hoc demo mode", is_rx_ahdemo_mgt);
1526 RX_PRINT("bad authentication", is_rx_bad_auth);
1527 TX_PRINT("failed, mbuf unavailable", is_tx_nombuf);
1528 TX_PRINT("failed, no node", is_tx_nonode);
1529 TX_PRINT("unknown mgmt frame", is_tx_unknownmgt);
1530 printf("\tactive scans: %u\n", stats.is_scan_active);
1531 printf("\tpassive scans: %u\n", stats.is_scan_passive);
1532 printf("\tnodes timed-out for inactivity: %u\n",
1533 stats.is_node_timeout);
1534 printf("\tcrypto context memory unavailable: %u\n",
1535 stats.is_crypto_nomem);
1536 }
1537
1538 void
1539 ieee80211_status(void)
1540 {
1541 int i, nwkey_verbose;
1542 struct ieee80211_nwid nwid;
1543 struct ieee80211_nwkey nwkey;
1544 struct ieee80211_power power;
1545 u_int8_t keybuf[IEEE80211_WEP_NKID][16];
1546 struct ieee80211_bssid bssid;
1547 struct ieee80211chanreq channel;
1548 struct ether_addr ea;
1549 static const u_int8_t zero_macaddr[IEEE80211_ADDR_LEN];
1550
1551 memset(&ifr, 0, sizeof(ifr));
1552 ifr.ifr_data = (void *)&nwid;
1553 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1554 if (ioctl(s, SIOCG80211NWID, &ifr) == -1)
1555 return;
1556 if (nwid.i_len > IEEE80211_NWID_LEN) {
1557 warnx("SIOCG80211NWID: wrong length of nwid (%d)", nwid.i_len);
1558 return;
1559 }
1560 printf("\tssid ");
1561 print_string(nwid.i_nwid, nwid.i_len);
1562 memset(&nwkey, 0, sizeof(nwkey));
1563 (void)strncpy(nwkey.i_name, name, sizeof(nwkey.i_name));
1564 /* show nwkey only when WEP is enabled */
1565 if (ioctl(s, SIOCG80211NWKEY, &nwkey) == -1 ||
1566 nwkey.i_wepon == 0) {
1567 printf("\n");
1568 goto skip_wep;
1569 }
1570
1571 printf(" nwkey ");
1572 /* try to retrieve WEP keys */
1573 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1574 nwkey.i_key[i].i_keydat = keybuf[i];
1575 nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
1576 }
1577 if (ioctl(s, SIOCG80211NWKEY, &nwkey) == -1) {
1578 printf("*****");
1579 } else {
1580 nwkey_verbose = 0;
1581 /* check to see non default key or multiple keys defined */
1582 if (nwkey.i_defkid != 1) {
1583 nwkey_verbose = 1;
1584 } else {
1585 for (i = 1; i < IEEE80211_WEP_NKID; i++) {
1586 if (nwkey.i_key[i].i_keylen != 0) {
1587 nwkey_verbose = 1;
1588 break;
1589 }
1590 }
1591 }
1592 /* check extra ambiguity with keywords */
1593 if (!nwkey_verbose) {
1594 if (nwkey.i_key[0].i_keylen >= 2 &&
1595 isdigit(nwkey.i_key[0].i_keydat[0]) &&
1596 nwkey.i_key[0].i_keydat[1] == ':')
1597 nwkey_verbose = 1;
1598 else if (nwkey.i_key[0].i_keylen >= 7 &&
1599 strncasecmp("persist", nwkey.i_key[0].i_keydat, 7)
1600 == 0)
1601 nwkey_verbose = 1;
1602 }
1603 if (nwkey_verbose)
1604 printf("%d:", nwkey.i_defkid);
1605 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1606 if (i > 0)
1607 printf(",");
1608 if (nwkey.i_key[i].i_keylen < 0)
1609 printf("persist");
1610 else
1611 print_string(nwkey.i_key[i].i_keydat,
1612 nwkey.i_key[i].i_keylen);
1613 if (!nwkey_verbose)
1614 break;
1615 }
1616 }
1617 printf("\n");
1618
1619 skip_wep:
1620 (void)strncpy(power.i_name, name, sizeof(power.i_name));
1621 if (ioctl(s, SIOCG80211POWER, &power) == -1)
1622 goto skip_power;
1623 printf("\tpowersave ");
1624 if (power.i_enabled)
1625 printf("on (%dms sleep)", power.i_maxsleep);
1626 else
1627 printf("off");
1628 printf("\n");
1629
1630 skip_power:
1631 (void)strncpy(bssid.i_name, name, sizeof(bssid.i_name));
1632 if (ioctl(s, SIOCG80211BSSID, &bssid) == -1)
1633 return;
1634 (void)strncpy(channel.i_name, name, sizeof(channel.i_name));
1635 if (ioctl(s, SIOCG80211CHANNEL, &channel) == -1)
1636 return;
1637 if (memcmp(bssid.i_bssid, zero_macaddr, IEEE80211_ADDR_LEN) == 0) {
1638 if (channel.i_channel != (u_int16_t)-1)
1639 printf("\tchan %d\n", channel.i_channel);
1640 } else {
1641 memcpy(ea.ether_addr_octet, bssid.i_bssid,
1642 sizeof(ea.ether_addr_octet));
1643 printf("\tbssid %s", ether_ntoa(&ea));
1644 if (channel.i_channel != IEEE80211_CHAN_ANY)
1645 printf(" chan %d", channel.i_channel);
1646 printf("\n");
1647 }
1648 }
1649
1650 static void
1651 media_error(int type, const char *val, const char *opt)
1652 {
1653 errx(EXIT_FAILURE, "unknown %s media %s: %s",
1654 get_media_type_string(type), opt, val);
1655 }
1656
1657 void
1658 init_current_media(void)
1659 {
1660 struct ifmediareq ifmr;
1661
1662 /*
1663 * If we have not yet done so, grab the currently-selected
1664 * media.
1665 */
1666 if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
1667 (void) memset(&ifmr, 0, sizeof(ifmr));
1668 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1669
1670 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1671 /*
1672 * If we get E2BIG, the kernel is telling us
1673 * that there are more, so we can ignore it.
1674 */
1675 if (errno != E2BIG)
1676 err(EXIT_FAILURE, "SGIOCGIFMEDIA");
1677 }
1678
1679 media_current = ifmr.ifm_current;
1680 }
1681
1682 /* Sanity. */
1683 if (IFM_TYPE(media_current) == 0)
1684 errx(EXIT_FAILURE, "%s: no link type?", name);
1685 }
1686
1687 void
1688 process_media_commands(void)
1689 {
1690
1691 if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
1692 /* Nothing to do. */
1693 return;
1694 }
1695
1696 /*
1697 * Media already set up, and commands sanity-checked. Set/clear
1698 * any options, and we're ready to go.
1699 */
1700 media_current |= mediaopt_set;
1701 media_current &= ~mediaopt_clear;
1702
1703 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1704 ifr.ifr_media = media_current;
1705
1706 if (ioctl(s, SIOCSIFMEDIA, &ifr) == -1)
1707 err(EXIT_FAILURE, "SIOCSIFMEDIA");
1708 }
1709
1710 void
1711 setmedia(const char *val, int d)
1712 {
1713 int type, subtype, inst;
1714
1715 init_current_media();
1716
1717 /* Only one media command may be given. */
1718 if (actions & A_MEDIA)
1719 errx(EXIT_FAILURE, "only one `media' command may be issued");
1720
1721 /* Must not come after mode commands */
1722 if (actions & A_MEDIAMODE)
1723 errx(EXIT_FAILURE,
1724 "may not issue `media' after `mode' commands");
1725
1726 /* Must not come after mediaopt commands */
1727 if (actions & A_MEDIAOPT)
1728 errx(EXIT_FAILURE,
1729 "may not issue `media' after `mediaopt' commands");
1730
1731 /*
1732 * No need to check if `instance' has been issued; setmediainst()
1733 * craps out if `media' has not been specified.
1734 */
1735
1736 type = IFM_TYPE(media_current);
1737 inst = IFM_INST(media_current);
1738
1739 /* Look up the subtype. */
1740 subtype = get_media_subtype(type, val);
1741 if (subtype == -1)
1742 media_error(type, val, "subtype");
1743
1744 /* Build the new current media word. */
1745 media_current = IFM_MAKEWORD(type, subtype, 0, inst);
1746
1747 /* Media will be set after other processing is complete. */
1748 }
1749
1750 void
1751 setmediaopt(const char *val, int d)
1752 {
1753 char *invalid;
1754
1755 init_current_media();
1756
1757 /* Can only issue `mediaopt' once. */
1758 if (actions & A_MEDIAOPTSET)
1759 errx(EXIT_FAILURE, "only one `mediaopt' command may be issued");
1760
1761 /* Can't issue `mediaopt' if `instance' has already been issued. */
1762 if (actions & A_MEDIAINST)
1763 errx(EXIT_FAILURE, "may not issue `mediaopt' after `instance'");
1764
1765 mediaopt_set = get_media_options(media_current, val, &invalid);
1766 if (mediaopt_set == -1)
1767 media_error(media_current, invalid, "option");
1768
1769 /* Media will be set after other processing is complete. */
1770 }
1771
1772 void
1773 unsetmediaopt(const char *val, int d)
1774 {
1775 char *invalid;
1776
1777 init_current_media();
1778
1779 /* Can only issue `-mediaopt' once. */
1780 if (actions & A_MEDIAOPTCLR)
1781 errx(EXIT_FAILURE,
1782 "only one `-mediaopt' command may be issued");
1783
1784 /* May not issue `media' and `-mediaopt'. */
1785 if (actions & A_MEDIA)
1786 errx(EXIT_FAILURE,
1787 "may not issue both `media' and `-mediaopt'");
1788
1789 /*
1790 * No need to check for A_MEDIAINST, since the test for A_MEDIA
1791 * implicitly checks for A_MEDIAINST.
1792 */
1793
1794 mediaopt_clear = get_media_options(media_current, val, &invalid);
1795 if (mediaopt_clear == -1)
1796 media_error(media_current, invalid, "option");
1797
1798 /* Media will be set after other processing is complete. */
1799 }
1800
1801 void
1802 setmediainst(const char *val, int d)
1803 {
1804 int type, subtype, options, inst;
1805
1806 init_current_media();
1807
1808 /* Can only issue `instance' once. */
1809 if (actions & A_MEDIAINST)
1810 errx(EXIT_FAILURE, "only one `instance' command may be issued");
1811
1812 /* Must have already specified `media' */
1813 if ((actions & A_MEDIA) == 0)
1814 errx(EXIT_FAILURE, "must specify `media' before `instance'");
1815
1816 type = IFM_TYPE(media_current);
1817 subtype = IFM_SUBTYPE(media_current);
1818 options = IFM_OPTIONS(media_current);
1819
1820 inst = atoi(val);
1821 if (inst < 0 || inst > IFM_INST_MAX)
1822 errx(EXIT_FAILURE, "invalid media instance: %s", val);
1823
1824 media_current = IFM_MAKEWORD(type, subtype, options, inst);
1825
1826 /* Media will be set after other processing is complete. */
1827 }
1828
1829 void
1830 setmediamode(const char *val, int d)
1831 {
1832 int type, subtype, options, inst, mode;
1833
1834 init_current_media();
1835
1836 /* Can only issue `mode' once. */
1837 if (actions & A_MEDIAMODE)
1838 errx(EXIT_FAILURE, "only one `mode' command may be issued");
1839
1840 type = IFM_TYPE(media_current);
1841 subtype = IFM_SUBTYPE(media_current);
1842 options = IFM_OPTIONS(media_current);
1843 inst = IFM_INST(media_current);
1844
1845 mode = get_media_mode(type, val);
1846 if (mode == -1)
1847 media_error(type, val, "mode");
1848
1849 media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode;
1850
1851 /* Media will be set after other processing is complete. */
1852 }
1853
1854 void
1855 print_media_word(int ifmw, const char *opt_sep)
1856 {
1857 const char *str;
1858
1859 printf("%s", get_media_subtype_string(ifmw));
1860
1861 /* Find mode. */
1862 if (IFM_MODE(ifmw) != 0) {
1863 str = get_media_mode_string(ifmw);
1864 if (str != NULL)
1865 printf(" mode %s", str);
1866 }
1867
1868 /* Find options. */
1869 for (; (str = get_media_option_string(&ifmw)) != NULL; opt_sep = ",")
1870 printf("%s%s", opt_sep, str);
1871
1872 if (IFM_INST(ifmw) != 0)
1873 printf(" instance %d", IFM_INST(ifmw));
1874 }
1875
1876 int
1877 carrier(void)
1878 {
1879 struct ifmediareq ifmr;
1880
1881 (void) memset(&ifmr, 0, sizeof(ifmr));
1882 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1883
1884 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1885 /*
1886 * Interface doesn't support SIOC{G,S}IFMEDIA;
1887 * assume ok.
1888 */
1889 return 0;
1890 }
1891 if ((ifmr.ifm_status & IFM_AVALID) == 0) {
1892 /*
1893 * Interface doesn't report media-valid status.
1894 * assume ok.
1895 */
1896 return 0;
1897 }
1898 /* otherwise, return ok for active, not-ok if not active. */
1899 return !(ifmr.ifm_status & IFM_ACTIVE);
1900 }
1901
1902
1903 #define IFFBITS \
1904 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
1905 \11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
1906
1907 #define IFCAPBITS \
1908 "\020\1IP4CSUM\2TCP4CSUM\3UDP4CSUM\4TCP6CSUM\5UDP6CSUM\6TCP4CSUM_Rx\7UDP4CSUM_Rx\10TSO4"
1909
1910 const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1911
1912 const struct ifmedia_status_description ifm_status_descriptions[] =
1913 IFM_STATUS_DESCRIPTIONS;
1914
1915 /*
1916 * Print the status of the interface. If an address family was
1917 * specified, show it and it only; otherwise, show them all.
1918 */
1919 void
1920 status(const struct sockaddr_dl *sdl)
1921 {
1922 struct afswtch *p = afp;
1923 struct ifmediareq ifmr;
1924 struct ifdatareq ifdr;
1925 int *media_list, i;
1926 char hbuf[NI_MAXHOST];
1927 char fbuf[BUFSIZ];
1928
1929 (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags);
1930 printf("%s: flags=%s", name, &fbuf[2]);
1931 if (metric)
1932 printf(" metric %lu", metric);
1933 if (mtu)
1934 printf(" mtu %lu", mtu);
1935 printf("\n");
1936
1937 if (g_ifcr.ifcr_capabilities) {
1938 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1939 g_ifcr.ifcr_capabilities);
1940 printf("\tcapabilities=%s\n", &fbuf[2]);
1941 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1942 g_ifcr.ifcr_capenable);
1943 printf("\tenabled=%s\n", &fbuf[2]);
1944 }
1945
1946 ieee80211_status();
1947 vlan_status();
1948 tunnel_status();
1949
1950 if (sdl != NULL &&
1951 getnameinfo((const struct sockaddr *)sdl, sdl->sdl_len,
1952 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0 &&
1953 hbuf[0] != '\0')
1954 printf("\taddress: %s\n", hbuf);
1955
1956 (void) memset(&ifmr, 0, sizeof(ifmr));
1957 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1958
1959 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1960 /*
1961 * Interface doesn't support SIOC{G,S}IFMEDIA.
1962 */
1963 goto iface_stats;
1964 }
1965
1966 if (ifmr.ifm_count == 0) {
1967 warnx("%s: no media types?", name);
1968 goto iface_stats;
1969 }
1970
1971 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
1972 if (media_list == NULL)
1973 err(EXIT_FAILURE, "malloc");
1974 ifmr.ifm_ulist = media_list;
1975
1976 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1)
1977 err(EXIT_FAILURE, "SIOCGIFMEDIA");
1978
1979 printf("\tmedia: %s ", get_media_type_string(ifmr.ifm_current));
1980 print_media_word(ifmr.ifm_current, " ");
1981 if (ifmr.ifm_active != ifmr.ifm_current) {
1982 printf(" (");
1983 print_media_word(ifmr.ifm_active, " ");
1984 printf(")");
1985 }
1986 printf("\n");
1987
1988 if (ifmr.ifm_status & IFM_STATUS_VALID) {
1989 const struct ifmedia_status_description *ifms;
1990 int bitno, found = 0;
1991
1992 printf("\tstatus: ");
1993 for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
1994 for (ifms = ifm_status_descriptions;
1995 ifms->ifms_valid != 0; ifms++) {
1996 if (ifms->ifms_type !=
1997 IFM_TYPE(ifmr.ifm_current) ||
1998 ifms->ifms_valid !=
1999 ifm_status_valid_list[bitno])
2000 continue;
2001 printf("%s%s", found ? ", " : "",
2002 IFM_STATUS_DESC(ifms, ifmr.ifm_status));
2003 found = 1;
2004
2005 /*
2006 * For each valid indicator bit, there's
2007 * only one entry for each media type, so
2008 * terminate the inner loop now.
2009 */
2010 break;
2011 }
2012 }
2013
2014 if (found == 0)
2015 printf("unknown");
2016 printf("\n");
2017 }
2018
2019 if (mflag) {
2020 int type, printed_type;
2021
2022 for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
2023 for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
2024 if (IFM_TYPE(media_list[i]) != type)
2025 continue;
2026 if (printed_type == 0) {
2027 printf("\tsupported %s media:\n",
2028 get_media_type_string(type));
2029 printed_type = 1;
2030 }
2031 printf("\t\tmedia ");
2032 print_media_word(media_list[i], " mediaopt ");
2033 printf("\n");
2034 }
2035 }
2036 }
2037
2038 free(media_list);
2039
2040 iface_stats:
2041 if (!vflag && !zflag)
2042 goto proto_status;
2043
2044 (void) strncpy(ifdr.ifdr_name, name, sizeof(ifdr.ifdr_name));
2045
2046 if (ioctl(s, zflag ? SIOCZIFDATA:SIOCGIFDATA, &ifdr) == -1) {
2047 err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA");
2048 } else {
2049 struct if_data * const ifi = &ifdr.ifdr_data;
2050 char buf[5];
2051
2052 #define PLURAL(n) ((n) == 1 ? "" : "s")
2053 #define PLURALSTR(s) ((atof(s)) == 1.0 ? "" : "s")
2054 printf("\tinput: %llu packet%s, ",
2055 (unsigned long long) ifi->ifi_ipackets,
2056 PLURAL(ifi->ifi_ipackets));
2057 if (hflag) {
2058 (void) humanize_number(buf, sizeof(buf),
2059 (int64_t) ifi->ifi_ibytes, "", HN_AUTOSCALE,
2060 HN_NOSPACE | HN_DECIMAL);
2061 printf("%s byte%s", buf,
2062 PLURALSTR(buf));
2063 } else
2064 printf("%llu byte%s",
2065 (unsigned long long) ifi->ifi_ibytes,
2066 PLURAL(ifi->ifi_ibytes));
2067 if (ifi->ifi_imcasts)
2068 printf(", %llu multicast%s",
2069 (unsigned long long) ifi->ifi_imcasts,
2070 PLURAL(ifi->ifi_imcasts));
2071 if (ifi->ifi_ierrors)
2072 printf(", %llu error%s",
2073 (unsigned long long) ifi->ifi_ierrors,
2074 PLURAL(ifi->ifi_ierrors));
2075 if (ifi->ifi_iqdrops)
2076 printf(", %llu queue drop%s",
2077 (unsigned long long) ifi->ifi_iqdrops,
2078 PLURAL(ifi->ifi_iqdrops));
2079 if (ifi->ifi_noproto)
2080 printf(", %llu unknown protocol",
2081 (unsigned long long) ifi->ifi_noproto);
2082 printf("\n\toutput: %llu packet%s, ",
2083 (unsigned long long) ifi->ifi_opackets,
2084 PLURAL(ifi->ifi_opackets));
2085 if (hflag) {
2086 (void) humanize_number(buf, sizeof(buf),
2087 (int64_t) ifi->ifi_obytes, "", HN_AUTOSCALE,
2088 HN_NOSPACE | HN_DECIMAL);
2089 printf("%s byte%s", buf,
2090 PLURALSTR(buf));
2091 } else
2092 printf("%llu byte%s",
2093 (unsigned long long) ifi->ifi_obytes,
2094 PLURAL(ifi->ifi_obytes));
2095 if (ifi->ifi_omcasts)
2096 printf(", %llu multicast%s",
2097 (unsigned long long) ifi->ifi_omcasts,
2098 PLURAL(ifi->ifi_omcasts));
2099 if (ifi->ifi_oerrors)
2100 printf(", %llu error%s",
2101 (unsigned long long) ifi->ifi_oerrors,
2102 PLURAL(ifi->ifi_oerrors));
2103 if (ifi->ifi_collisions)
2104 printf(", %llu collision%s",
2105 (unsigned long long) ifi->ifi_collisions,
2106 PLURAL(ifi->ifi_collisions));
2107 printf("\n");
2108 #undef PLURAL
2109 #undef PLURALSTR
2110 }
2111
2112 ieee80211_statistics();
2113
2114 proto_status:
2115 if ((p = afp) != NULL) {
2116 (*p->af_status)(1);
2117 } else for (p = afs; p->af_name; p++) {
2118 ifr.ifr_addr.sa_family = p->af_af;
2119 (*p->af_status)(0);
2120 }
2121 }
2122
2123 void
2124 tunnel_status(void)
2125 {
2126 char psrcaddr[NI_MAXHOST];
2127 char pdstaddr[NI_MAXHOST];
2128 const char *ver = "";
2129 const int niflag = NI_NUMERICHOST;
2130 struct if_laddrreq req;
2131
2132 psrcaddr[0] = pdstaddr[0] = '\0';
2133
2134 memset(&req, 0, sizeof(req));
2135 strncpy(req.iflr_name, name, IFNAMSIZ);
2136 if (ioctl(s, SIOCGLIFPHYADDR, &req) == -1)
2137 return;
2138 #ifdef INET6
2139 if (req.addr.ss_family == AF_INET6)
2140 in6_fillscopeid((struct sockaddr_in6 *)&req.addr);
2141 #endif
2142 getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len,
2143 psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
2144 #ifdef INET6
2145 if (req.addr.ss_family == AF_INET6)
2146 ver = "6";
2147 #endif
2148
2149 #ifdef INET6
2150 if (req.dstaddr.ss_family == AF_INET6)
2151 in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr);
2152 #endif
2153 getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len,
2154 pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
2155
2156 printf("\ttunnel inet%s %s --> %s\n", ver, psrcaddr, pdstaddr);
2157 }
2158
2159 void
2160 vlan_status(void)
2161 {
2162 struct vlanreq vlr;
2163
2164 if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
2165 !isdigit((unsigned char)ifr.ifr_name[4]))
2166 return;
2167
2168 memset(&vlr, 0, sizeof(vlr));
2169 ifr.ifr_data = (void *)&vlr;
2170
2171 if (ioctl(s, SIOCGETVLAN, &ifr) == -1)
2172 return;
2173
2174 if (vlr.vlr_tag || vlr.vlr_parent[0] != '\0')
2175 printf("\tvlan: %d parent: %s\n",
2176 vlr.vlr_tag, vlr.vlr_parent[0] == '\0' ?
2177 "<none>" : vlr.vlr_parent);
2178 }
2179
2180 void
2181 in_alias(struct ifreq *creq)
2182 {
2183 struct sockaddr_in *iasin;
2184 int alias;
2185
2186 if (lflag)
2187 return;
2188
2189 alias = 1;
2190
2191 /* Get the non-alias address for this interface. */
2192 getsock(AF_INET);
2193 if (s < 0) {
2194 if (errno == EPROTONOSUPPORT)
2195 return;
2196 err(EXIT_FAILURE, "socket");
2197 }
2198 (void) memset(&ifr, 0, sizeof(ifr));
2199 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2200 if (ioctl(s, SIOCGIFADDR, &ifr) == -1) {
2201 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2202 return;
2203 } else
2204 warn("SIOCGIFADDR");
2205 }
2206 /* If creq and ifr are the same address, this is not an alias. */
2207 if (memcmp(&ifr.ifr_addr, &creq->ifr_addr,
2208 sizeof(creq->ifr_addr)) == 0)
2209 alias = 0;
2210 (void) memset(&in_addreq, 0, sizeof(in_addreq));
2211 (void) strncpy(in_addreq.ifra_name, name, sizeof(in_addreq.ifra_name));
2212 memcpy(&in_addreq.ifra_addr, &creq->ifr_addr,
2213 sizeof(in_addreq.ifra_addr));
2214 if (ioctl(s, SIOCGIFALIAS, &in_addreq) == -1) {
2215 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2216 return;
2217 } else
2218 warn("SIOCGIFALIAS");
2219 }
2220
2221 iasin = &in_addreq.ifra_addr;
2222 printf("\tinet %s%s", alias ? "alias " : "", inet_ntoa(iasin->sin_addr));
2223
2224 if (flags & IFF_POINTOPOINT) {
2225 iasin = &in_addreq.ifra_dstaddr;
2226 printf(" -> %s", inet_ntoa(iasin->sin_addr));
2227 }
2228
2229 iasin = &in_addreq.ifra_mask;
2230 printf(" netmask 0x%x", ntohl(iasin->sin_addr.s_addr));
2231
2232 if (flags & IFF_BROADCAST) {
2233 iasin = &in_addreq.ifra_broadaddr;
2234 printf(" broadcast %s", inet_ntoa(iasin->sin_addr));
2235 }
2236 printf("\n");
2237 }
2238
2239 void
2240 in_status(int force)
2241 {
2242 struct ifaddrs *ifap, *ifa;
2243 struct ifreq isifr;
2244
2245 if (getifaddrs(&ifap) != 0)
2246 err(EXIT_FAILURE, "getifaddrs");
2247 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
2248 if (strcmp(name, ifa->ifa_name) != 0)
2249 continue;
2250 if (ifa->ifa_addr->sa_family != AF_INET)
2251 continue;
2252 if (sizeof(isifr.ifr_addr) < ifa->ifa_addr->sa_len)
2253 continue;
2254
2255 memset(&isifr, 0, sizeof(isifr));
2256 strncpy(isifr.ifr_name, ifa->ifa_name, sizeof(isifr.ifr_name));
2257 memcpy(&isifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
2258 in_alias(&isifr);
2259 }
2260 freeifaddrs(ifap);
2261 }
2262
2263 void
2264 setifprefixlen(const char *addr, int d)
2265 {
2266 if (*afp->af_getprefix)
2267 (*afp->af_getprefix)(addr, MASK);
2268 explicit_prefix = 1;
2269 }
2270
2271 #ifdef INET6
2272 void
2273 in6_fillscopeid(struct sockaddr_in6 *sin6)
2274 {
2275 #if defined(__KAME__) && defined(KAME_SCOPEID)
2276 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
2277 sin6->sin6_scope_id =
2278 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
2279 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
2280 }
2281 #endif
2282 }
2283
2284 /* XXX not really an alias */
2285 void
2286 in6_alias(struct in6_ifreq *creq)
2287 {
2288 struct sockaddr_in6 *sin6;
2289 char hbuf[NI_MAXHOST];
2290 u_int32_t scopeid;
2291 const int niflag = NI_NUMERICHOST;
2292
2293 /* Get the non-alias address for this interface. */
2294 getsock(AF_INET6);
2295 if (s < 0) {
2296 if (errno == EPROTONOSUPPORT)
2297 return;
2298 err(EXIT_FAILURE, "socket");
2299 }
2300
2301 sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
2302
2303 in6_fillscopeid(sin6);
2304 scopeid = sin6->sin6_scope_id;
2305 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
2306 hbuf, sizeof(hbuf), NULL, 0, niflag))
2307 strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
2308 printf("\tinet6 %s", hbuf);
2309
2310 if (flags & IFF_POINTOPOINT) {
2311 (void) memset(&ifr6, 0, sizeof(ifr6));
2312 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
2313 ifr6.ifr_addr = creq->ifr_addr;
2314 if (ioctl(s, SIOCGIFDSTADDR_IN6, &ifr6) == -1) {
2315 if (errno != EADDRNOTAVAIL)
2316 warn("SIOCGIFDSTADDR_IN6");
2317 (void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
2318 ifr6.ifr_addr.sin6_family = AF_INET6;
2319 ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
2320 }
2321 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
2322 in6_fillscopeid(sin6);
2323 hbuf[0] = '\0';
2324 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
2325 hbuf, sizeof(hbuf), NULL, 0, niflag))
2326 strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
2327 printf(" -> %s", hbuf);
2328 }
2329
2330 (void) memset(&ifr6, 0, sizeof(ifr6));
2331 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
2332 ifr6.ifr_addr = creq->ifr_addr;
2333 if (ioctl(s, SIOCGIFNETMASK_IN6, &ifr6) == -1) {
2334 if (errno != EADDRNOTAVAIL)
2335 warn("SIOCGIFNETMASK_IN6");
2336 } else {
2337 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
2338 printf(" prefixlen %d", prefix(&sin6->sin6_addr,
2339 sizeof(struct in6_addr)));
2340 }
2341
2342 (void) memset(&ifr6, 0, sizeof(ifr6));
2343 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
2344 ifr6.ifr_addr = creq->ifr_addr;
2345 if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == -1) {
2346 if (errno != EADDRNOTAVAIL)
2347 warn("SIOCGIFAFLAG_IN6");
2348 } else {
2349 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
2350 printf(" anycast");
2351 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
2352 printf(" tentative");
2353 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
2354 printf(" duplicated");
2355 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
2356 printf(" detached");
2357 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
2358 printf(" deprecated");
2359 }
2360
2361 if (scopeid)
2362 printf(" scopeid 0x%x", scopeid);
2363
2364 if (Lflag) {
2365 struct in6_addrlifetime *lifetime;
2366 (void) memset(&ifr6, 0, sizeof(ifr6));
2367 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
2368 ifr6.ifr_addr = creq->ifr_addr;
2369 lifetime = &ifr6.ifr_ifru.ifru_lifetime;
2370 if (ioctl(s, SIOCGIFALIFETIME_IN6, &ifr6) == -1) {
2371 if (errno != EADDRNOTAVAIL)
2372 warn("SIOCGIFALIFETIME_IN6");
2373 } else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
2374 time_t t = time(NULL);
2375 printf(" pltime ");
2376 if (lifetime->ia6t_preferred) {
2377 printf("%s", lifetime->ia6t_preferred < t
2378 ? "0"
2379 : sec2str(lifetime->ia6t_preferred - t));
2380 } else
2381 printf("infty");
2382
2383 printf(" vltime ");
2384 if (lifetime->ia6t_expire) {
2385 printf("%s", lifetime->ia6t_expire < t
2386 ? "0"
2387 : sec2str(lifetime->ia6t_expire - t));
2388 } else
2389 printf("infty");
2390 }
2391 }
2392
2393 printf("\n");
2394 }
2395
2396 void
2397 in6_status(int force)
2398 {
2399 struct ifaddrs *ifap, *ifa;
2400 struct in6_ifreq isifr;
2401
2402 if (getifaddrs(&ifap) != 0)
2403 err(EXIT_FAILURE, "getifaddrs");
2404 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
2405 if (strcmp(name, ifa->ifa_name) != 0)
2406 continue;
2407 if (ifa->ifa_addr->sa_family != AF_INET6)
2408 continue;
2409 if (sizeof(isifr.ifr_addr) < ifa->ifa_addr->sa_len)
2410 continue;
2411
2412 memset(&isifr, 0, sizeof(isifr));
2413 strncpy(isifr.ifr_name, ifa->ifa_name, sizeof(isifr.ifr_name));
2414 memcpy(&isifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
2415 in6_alias(&isifr);
2416 }
2417 freeifaddrs(ifap);
2418 }
2419 #endif /*INET6*/
2420
2421 #ifndef INET_ONLY
2422
2423 void
2424 at_status(int force)
2425 {
2426 struct sockaddr_at *sat, null_sat;
2427 struct netrange *nr;
2428
2429 getsock(AF_APPLETALK);
2430 if (s < 0) {
2431 if (errno == EPROTONOSUPPORT)
2432 return;
2433 err(EXIT_FAILURE, "socket");
2434 }
2435 (void) memset(&ifr, 0, sizeof(ifr));
2436 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2437 if (ioctl(s, SIOCGIFADDR, &ifr) == -1) {
2438 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2439 if (!force)
2440 return;
2441 (void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2442 } else
2443 warn("SIOCGIFADDR");
2444 }
2445 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
2446 sat = (struct sockaddr_at *)&ifr.ifr_addr;
2447
2448 (void) memset(&null_sat, 0, sizeof(null_sat));
2449
2450 nr = (struct netrange *) &sat->sat_zero;
2451 printf("\tatalk %d.%d range %d-%d phase %d",
2452 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
2453 ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
2454 if (flags & IFF_POINTOPOINT) {
2455 if (ioctl(s, SIOCGIFDSTADDR, &ifr) == -1) {
2456 if (errno == EADDRNOTAVAIL)
2457 (void) memset(&ifr.ifr_addr, 0,
2458 sizeof(ifr.ifr_addr));
2459 else
2460 warn("SIOCGIFDSTADDR");
2461 }
2462 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2463 sat = (struct sockaddr_at *)&ifr.ifr_dstaddr;
2464 if (!sat)
2465 sat = &null_sat;
2466 printf("--> %d.%d",
2467 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
2468 }
2469 if (flags & IFF_BROADCAST) {
2470 /* note RTAX_BRD overlap with IFF_POINTOPOINT */
2471 sat = (struct sockaddr_at *)&ifr.ifr_broadaddr;
2472 if (sat)
2473 printf(" broadcast %d.%d", ntohs(sat->sat_addr.s_net),
2474 sat->sat_addr.s_node);
2475 }
2476 printf("\n");
2477 }
2478
2479 void
2480 xns_status(int force)
2481 {
2482 struct sockaddr_ns *sns;
2483
2484 getsock(AF_NS);
2485 if (s < 0) {
2486 if (errno == EPROTONOSUPPORT)
2487 return;
2488 err(EXIT_FAILURE, "socket");
2489 }
2490 (void) memset(&ifr, 0, sizeof(ifr));
2491 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2492 if (ioctl(s, SIOCGIFADDR, &ifr) == -1) {
2493 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2494 if (!force)
2495 return;
2496 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2497 } else
2498 warn("SIOCGIFADDR");
2499 }
2500 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
2501 sns = (struct sockaddr_ns *)&ifr.ifr_addr;
2502 printf("\tns %s ", ns_ntoa(sns->sns_addr));
2503 if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
2504 if (ioctl(s, SIOCGIFDSTADDR, &ifr) == -1) {
2505 if (errno == EADDRNOTAVAIL)
2506 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
2507 else
2508 warn("SIOCGIFDSTADDR");
2509 }
2510 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
2511 sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
2512 printf("--> %s ", ns_ntoa(sns->sns_addr));
2513 }
2514 printf("\n");
2515 }
2516
2517 void
2518 iso_status(int force)
2519 {
2520 struct sockaddr_iso *siso;
2521 struct iso_ifreq isoifr;
2522
2523 getsock(AF_ISO);
2524 if (s < 0) {
2525 if (errno == EPROTONOSUPPORT)
2526 return;
2527 err(EXIT_FAILURE, "socket");
2528 }
2529 (void) memset(&isoifr, 0, sizeof(isoifr));
2530 (void) strncpy(isoifr.ifr_name, name, sizeof(isoifr.ifr_name));
2531 if (ioctl(s, SIOCGIFADDR_ISO, &isoifr) == -1) {
2532 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
2533 if (!force)
2534 return;
2535 (void) memset(&isoifr.ifr_Addr, 0,
2536 sizeof(isoifr.ifr_Addr));
2537 } else
2538 warn("SIOCGIFADDR_ISO");
2539 }
2540 (void) strncpy(isoifr.ifr_name, name, sizeof isoifr.ifr_name);
2541 siso = &isoifr.ifr_Addr;
2542 printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
2543 if (ioctl(s, SIOCGIFNETMASK_ISO, &isoifr) == -1) {
2544 if (errno == EADDRNOTAVAIL)
2545 memset(&isoifr.ifr_Addr, 0, sizeof(isoifr.ifr_Addr));
2546 else
2547 warn("SIOCGIFNETMASK_ISO");
2548 } else {
2549 if (siso->siso_len > offsetof(struct sockaddr_iso, siso_addr))
2550 siso->siso_addr.isoa_len = siso->siso_len
2551 - offsetof(struct sockaddr_iso, siso_addr);
2552 printf("\n\t\tnetmask %s ", iso_ntoa(&siso->siso_addr));
2553 }
2554 if (flags & IFF_POINTOPOINT) {
2555 if (ioctl(s, SIOCGIFDSTADDR_ISO, &isoifr) == -1) {
2556 if (errno == EADDRNOTAVAIL)
2557 memset(&isoifr.ifr_Addr, 0,
2558 sizeof(isoifr.ifr_Addr));
2559 else
2560 warn("SIOCGIFDSTADDR_ISO");
2561 }
2562 (void) strncpy(isoifr.ifr_name, name, sizeof (isoifr.ifr_name));
2563 siso = &isoifr.ifr_Addr;
2564 printf("--> %s ", iso_ntoa(&siso->siso_addr));
2565 }
2566 printf("\n");
2567 }
2568
2569 #endif /* INET_ONLY */
2570
2571 #define SIN(x) ((struct sockaddr_in *) &(x))
2572 struct sockaddr_in *sintab[] = {
2573 SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
2574 SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
2575
2576 void
2577 in_getaddr(const char *str, int which)
2578 {
2579 struct sockaddr_in *gasin = sintab[which];
2580 struct hostent *hp;
2581 struct netent *np;
2582
2583 gasin->sin_len = sizeof(*gasin);
2584 if (which != MASK)
2585 gasin->sin_family = AF_INET;
2586
2587 if (which == ADDR) {
2588 char *p = NULL;
2589 if ((p = strrchr(str, '/')) != NULL) {
2590 *p = '\0';
2591 in_getprefix(p + 1, MASK);
2592 }
2593 }
2594
2595 if (inet_aton(str, &gasin->sin_addr) == 0) {
2596 if ((hp = gethostbyname(str)) != NULL)
2597 (void) memcpy(&gasin->sin_addr, hp->h_addr, hp->h_length);
2598 else if ((np = getnetbyname(str)) != NULL)
2599 gasin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
2600 else
2601 errx(EXIT_FAILURE, "%s: bad value", str);
2602 }
2603 }
2604
2605 void
2606 in_getprefix(const char *plen, int which)
2607 {
2608 struct sockaddr_in *igsin = sintab[which];
2609 u_char *cp;
2610 int len = strtol(plen, (char **)NULL, 10);
2611
2612 if ((len < 0) || (len > 32))
2613 errx(EXIT_FAILURE, "%s: bad value", plen);
2614 igsin->sin_len = sizeof(*igsin);
2615 if (which != MASK)
2616 igsin->sin_family = AF_INET;
2617 if ((len == 0) || (len == 32)) {
2618 memset(&igsin->sin_addr, 0xff, sizeof(struct in_addr));
2619 return;
2620 }
2621 memset((void *)&igsin->sin_addr, 0x00, sizeof(igsin->sin_addr));
2622 for (cp = (u_char *)&igsin->sin_addr; len > 7; len -= 8)
2623 *cp++ = 0xff;
2624 if (len)
2625 *cp = 0xff << (8 - len);
2626 }
2627
2628 #ifdef INET6
2629 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
2630 struct sockaddr_in6 *sin6tab[] = {
2631 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
2632 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
2633
2634 void
2635 in6_getaddr(const char *str, int which)
2636 {
2637 #if defined(__KAME__) && defined(KAME_SCOPEID)
2638 struct sockaddr_in6 *sin6 = sin6tab[which];
2639 struct addrinfo hints, *res;
2640 int error;
2641 char *slash = NULL;
2642
2643 if (which == ADDR) {
2644 if ((slash = strrchr(str, '/')) != NULL)
2645 *slash = '\0';
2646 }
2647
2648 memset(&hints, 0, sizeof(hints));
2649 hints.ai_family = AF_INET6;
2650 hints.ai_socktype = SOCK_DGRAM;
2651 #if 0 /* in_getaddr() allows FQDN */
2652 hints.ai_flags = AI_NUMERICHOST;
2653 #endif
2654 error = getaddrinfo(str, "0", &hints, &res);
2655 if (error && slash) {
2656 /* try again treating the '/' as part of the name */
2657 *slash = '/';
2658 slash = NULL;
2659 error = getaddrinfo(str, "0", &hints, &res);
2660 }
2661 if (error)
2662 errx(EXIT_FAILURE, "%s: %s", str, gai_strerror(error));
2663 if (res->ai_next)
2664 errx(EXIT_FAILURE, "%s: resolved to multiple addresses", str);
2665 if (res->ai_addrlen != sizeof(struct sockaddr_in6))
2666 errx(EXIT_FAILURE, "%s: bad value", str);
2667 memcpy(sin6, res->ai_addr, res->ai_addrlen);
2668 freeaddrinfo(res);
2669 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && sin6->sin6_scope_id) {
2670 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
2671 htons(sin6->sin6_scope_id);
2672 sin6->sin6_scope_id = 0;
2673 }
2674 if (slash) {
2675 in6_getprefix(slash + 1, MASK);
2676 explicit_prefix = 1;
2677 }
2678 #else
2679 struct sockaddr_in6 *gasin = sin6tab[which];
2680
2681 gasin->sin6_len = sizeof(*gasin);
2682 if (which != MASK)
2683 gasin->sin6_family = AF_INET6;
2684
2685 if (which == ADDR) {
2686 char *p = NULL;
2687 if((p = strrchr(str, '/')) != NULL) {
2688 *p = '\0';
2689 in6_getprefix(p + 1, MASK);
2690 explicit_prefix = 1;
2691 }
2692 }
2693
2694 if (inet_pton(AF_INET6, str, &gasin->sin6_addr) != 1)
2695 errx(EXIT_FAILURE, "%s: bad value", str);
2696 #endif
2697 }
2698
2699 void
2700 in6_getprefix(const char *plen, int which)
2701 {
2702 struct sockaddr_in6 *gpsin = sin6tab[which];
2703 u_char *cp;
2704 int len = strtol(plen, (char **)NULL, 10);
2705
2706 if ((len < 0) || (len > 128))
2707 errx(EXIT_FAILURE, "%s: bad value", plen);
2708 gpsin->sin6_len = sizeof(*gpsin);
2709 if (which != MASK)
2710 gpsin->sin6_family = AF_INET6;
2711 if ((len == 0) || (len == 128)) {
2712 memset(&gpsin->sin6_addr, 0xff, sizeof(struct in6_addr));
2713 return;
2714 }
2715 memset((void *)&gpsin->sin6_addr, 0x00, sizeof(gpsin->sin6_addr));
2716 for (cp = (u_char *)&gpsin->sin6_addr; len > 7; len -= 8)
2717 *cp++ = 0xff;
2718 if (len)
2719 *cp = 0xff << (8 - len);
2720 }
2721
2722 int
2723 prefix(void *val, int size)
2724 {
2725 u_char *pname = (u_char *)val;
2726 int byte, bit, plen = 0;
2727
2728 for (byte = 0; byte < size; byte++, plen += 8)
2729 if (pname[byte] != 0xff)
2730 break;
2731 if (byte == size)
2732 return (plen);
2733 for (bit = 7; bit != 0; bit--, plen++)
2734 if (!(pname[byte] & (1 << bit)))
2735 break;
2736 for (; bit != 0; bit--)
2737 if (pname[byte] & (1 << bit))
2738 return(0);
2739 byte++;
2740 for (; byte < size; byte++)
2741 if (pname[byte])
2742 return(0);
2743 return (plen);
2744 }
2745 #endif /*INET6*/
2746
2747 #ifndef INET_ONLY
2748 void
2749 at_getaddr(const char *addr, int which)
2750 {
2751 struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
2752 u_int net, node;
2753
2754 sat->sat_family = AF_APPLETALK;
2755 sat->sat_len = sizeof(*sat);
2756 if (which == MASK)
2757 errx(EXIT_FAILURE, "AppleTalk does not use netmasks");
2758 if (sscanf(addr, "%u.%u", &net, &node) != 2
2759 || net == 0 || net > 0xffff || node == 0 || node > 0xfe)
2760 errx(EXIT_FAILURE, "%s: illegal address", addr);
2761 sat->sat_addr.s_net = htons(net);
2762 sat->sat_addr.s_node = node;
2763 }
2764
2765 void
2766 setatrange(const char *range, int d)
2767 {
2768 u_short first = 123, last = 123;
2769
2770 if (sscanf(range, "%hu-%hu", &first, &last) != 2
2771 || first == 0 /* || first > 0xffff */
2772 || last == 0 /* || last > 0xffff */ || first > last)
2773 errx(EXIT_FAILURE, "%s: illegal net range: %u-%u", range,
2774 first, last);
2775 at_nr.nr_firstnet = htons(first);
2776 at_nr.nr_lastnet = htons(last);
2777 }
2778
2779 void
2780 setatphase(const char *phase, int d)
2781 {
2782 if (!strcmp(phase, "1"))
2783 at_nr.nr_phase = 1;
2784 else if (!strcmp(phase, "2"))
2785 at_nr.nr_phase = 2;
2786 else
2787 errx(EXIT_FAILURE, "%s: illegal phase", phase);
2788 }
2789
2790 void
2791 checkatrange(struct sockaddr_at *sat)
2792 {
2793 if (at_nr.nr_phase == 0)
2794 at_nr.nr_phase = 2; /* Default phase 2 */
2795 if (at_nr.nr_firstnet == 0)
2796 at_nr.nr_firstnet = /* Default range of one */
2797 at_nr.nr_lastnet = sat->sat_addr.s_net;
2798 printf("\tatalk %d.%d range %d-%d phase %d\n",
2799 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
2800 ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
2801 if ((u_short) ntohs(at_nr.nr_firstnet) >
2802 (u_short) ntohs(sat->sat_addr.s_net)
2803 || (u_short) ntohs(at_nr.nr_lastnet) <
2804 (u_short) ntohs(sat->sat_addr.s_net))
2805 errx(EXIT_FAILURE, "AppleTalk address is not in range");
2806 *((struct netrange *) &sat->sat_zero) = at_nr;
2807 }
2808
2809 #define SNS(x) ((struct sockaddr_ns *) &(x))
2810 struct sockaddr_ns *snstab[] = {
2811 SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
2812 SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
2813
2814 void
2815 xns_getaddr(const char *addr, int which)
2816 {
2817 struct sockaddr_ns *sns = snstab[which];
2818
2819 sns->sns_family = AF_NS;
2820 sns->sns_len = sizeof(*sns);
2821 sns->sns_addr = ns_addr(addr);
2822 if (which == MASK)
2823 puts("Attempt to set XNS netmask will be ineffectual");
2824 }
2825
2826 #define SISO(x) ((struct sockaddr_iso *) &(x))
2827 struct sockaddr_iso *sisotab[] = {
2828 SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
2829 SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
2830
2831 void
2832 iso_getaddr(const char *addr, int which)
2833 {
2834 struct sockaddr_iso *siso = sisotab[which];
2835 siso->siso_addr = *iso_addr(addr);
2836
2837 if (which == MASK) {
2838 siso->siso_len = TSEL(siso) - (char *)(siso);
2839 siso->siso_nlen = 0;
2840 } else {
2841 siso->siso_len = sizeof(*siso);
2842 siso->siso_family = AF_ISO;
2843 }
2844 }
2845
2846 void
2847 setsnpaoffset(const char *val, int d)
2848 {
2849 iso_addreq.ifra_snpaoffset = atoi(val);
2850 }
2851
2852 void
2853 setnsellength(const char *val, int d)
2854 {
2855 nsellength = atoi(val);
2856 if (nsellength < 0)
2857 errx(EXIT_FAILURE, "Negative NSEL length is absurd");
2858 if (afp == 0 || afp->af_af != AF_ISO)
2859 errx(EXIT_FAILURE, "Setting NSEL length valid only for iso");
2860 }
2861
2862 void
2863 fixnsel(struct sockaddr_iso *siso)
2864 {
2865 if (siso->siso_family == 0)
2866 return;
2867 siso->siso_tlen = nsellength;
2868 }
2869
2870 void
2871 adjust_nsellength(void)
2872 {
2873 fixnsel(sisotab[RIDADDR]);
2874 fixnsel(sisotab[ADDR]);
2875 fixnsel(sisotab[DSTADDR]);
2876 }
2877
2878 #endif /* INET_ONLY */
2879
2880 void
2881 usage(void)
2882 {
2883 const char *progname = getprogname();
2884
2885 fprintf(stderr,
2886 "usage: %s [-h] [-m] [-v] [-z] "
2887 #ifdef INET6
2888 "[-L] "
2889 #endif
2890 "interface\n"
2891 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
2892 "\t\t[ alias | -alias ] ]\n"
2893 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n"
2894 "\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n"
2895 "\t[ powersave | -powersave ] [ powersavesleep duration ]\n"
2896 "\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"
2897 "\t[ arp | -arp ]\n"
2898 "\t[ media type ] [ mediaopt opts ] [ -mediaopt opts ] "
2899 "[ instance minst ]\n"
2900 "\t[ vlan n vlanif i ]\n"
2901 "\t[ anycast | -anycast ] [ deprecated | -deprecated ]\n"
2902 "\t[ tentative | -tentative ] [ pltime n ] [ vltime n ] [ eui64 ]\n"
2903 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
2904 " %s -a [-b] [-h] [-m] [-d] [-u] [-v] [-z] [ af ]\n"
2905 " %s -l [-b] [-d] [-u] [-s]\n"
2906 " %s -C\n"
2907 " %s interface create\n"
2908 " %s interface destroy\n",
2909 progname, progname, progname, progname, progname, progname);
2910 exit(1);
2911 }
2912
2913 #ifdef INET6
2914 char *
2915 sec2str(total)
2916 time_t total;
2917 {
2918 static char result[256];
2919 int days, hours, mins, secs;
2920 int first = 1;
2921 char *p = result;
2922 char *end = &result[sizeof(result)];
2923 int n;
2924
2925 if (0) { /*XXX*/
2926 days = total / 3600 / 24;
2927 hours = (total / 3600) % 24;
2928 mins = (total / 60) % 60;
2929 secs = total % 60;
2930
2931 if (days) {
2932 first = 0;
2933 n = snprintf(p, end - p, "%dd", days);
2934 if (n < 0 || n >= end - p)
2935 return(result);
2936 p += n;
2937 }
2938 if (!first || hours) {
2939 first = 0;
2940 n = snprintf(p, end - p, "%dh", hours);
2941 if (n < 0 || n >= end - p)
2942 return(result);
2943 p += n;
2944 }
2945 if (!first || mins) {
2946 first = 0;
2947 n = snprintf(p, end - p, "%dm", mins);
2948 if (n < 0 || n >= end - p)
2949 return(result);
2950 p += n;
2951 }
2952 snprintf(p, end - p, "%ds", secs);
2953 } else
2954 snprintf(p, end - p, "%lu", (u_long)total);
2955
2956 return(result);
2957 }
2958 #endif
2959