ifconfig.c revision 1.185 1 /* $NetBSD: ifconfig.c,v 1.185 2008/04/21 05:33:55 dyoung 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.185 2008/04/21 05:33:55 dyoung 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> /* XXX */
92 #include <netinet/in_var.h> /* XXX */
93
94 #include <netdb.h>
95
96 #include <sys/protosw.h>
97
98 #include <ctype.h>
99 #include <err.h>
100 #include <errno.h>
101 #include <stdbool.h>
102 #include <stddef.h>
103 #include <stdio.h>
104 #include <stdlib.h>
105 #include <string.h>
106 #include <unistd.h>
107 #include <ifaddrs.h>
108 #include <util.h>
109
110 #include "extern.h"
111
112 #ifndef INET_ONLY
113 #include "af_atalk.h"
114 #include "af_iso.h"
115 #endif /* ! INET_ONLY */
116 #include "af_inet.h"
117 #ifdef INET6
118 #include "af_inet6.h"
119 #endif /* INET6 */
120
121 #include "agr.h"
122 #include "carp.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
130 char name[30];
131 u_short flags;
132 int setaddr, doalias;
133 u_long metric, mtu, preference;
134 int clearaddr, s;
135 int newaddr = -1;
136 int conflicting = 0;
137 int check_up_state = -1;
138 int af;
139 int aflag, bflag, Cflag, dflag, lflag, mflag, sflag, uflag, vflag, zflag;
140 int hflag;
141 int have_preference = 0;
142 #ifdef INET6
143 int Lflag;
144 #endif
145 int explicit_prefix = 0;
146
147 struct ifcapreq g_ifcr;
148 int g_ifcr_updated;
149
150 void notealias(const char *, int);
151 void notrailers(const char *, int);
152 void setifaddr(const char *, int);
153 void setifdstaddr(const char *, int);
154 void setifflags(const char *, int);
155 void check_ifflags_up(const char *);
156 void setifcaps(const char *, int);
157 void setifbroadaddr(const char *, int);
158 void setifipdst(const char *, int);
159 void setifmetric(const char *, int);
160 void setifpreference(const char *, int);
161 void setifmtu(const char *, int);
162 void setifnetmask(const char *, int);
163 void setifprefixlen(const char *, int);
164 void setmedia(const char *, int);
165 void setmediamode(const char *, int);
166 void setmediaopt(const char *, int);
167 void unsetmediaopt(const char *, int);
168 void setmediainst(const char *, int);
169 void clone_create(const char *, int);
170 void clone_destroy(const char *, int);
171 int main(int, char *[]);
172 void do_setifpreference(void);
173
174 /*
175 * Media stuff. Whenever a media command is first performed, the
176 * currently select media is grabbed for this interface. If `media'
177 * is given, the current media word is modifed. `mediaopt' commands
178 * only modify the set and clear words. They then operate on the
179 * current media word later.
180 */
181 int media_current;
182 int mediaopt_set;
183 int mediaopt_clear;
184
185 int actions; /* Actions performed */
186
187 #define A_MEDIA 0x0001 /* media command */
188 #define A_MEDIAOPTSET 0x0002 /* mediaopt command */
189 #define A_MEDIAOPTCLR 0x0004 /* -mediaopt command */
190 #define A_MEDIAOPT (A_MEDIAOPTSET|A_MEDIAOPTCLR)
191 #define A_MEDIAINST 0x0008 /* instance or inst command */
192 #define A_MEDIAMODE 0x0010 /* mode command */
193
194 #define NEXTARG 0xffffff
195 #define NEXTARG2 0xfffffe
196
197 const struct cmd {
198 const char *c_name;
199 int c_parameter; /* NEXTARG means next argv */
200 int c_action; /* defered action */
201 void (*c_func)(const char *, int);
202 } cmds[] = {
203 { "up", IFF_UP, 0, setifflags } ,
204 { "down", -IFF_UP, 0, setifflags },
205 { "trailers", -1, 0, notrailers },
206 { "-trailers", 1, 0, notrailers },
207 { "arp", -IFF_NOARP, 0, setifflags },
208 { "-arp", IFF_NOARP, 0, setifflags },
209 { "debug", IFF_DEBUG, 0, setifflags },
210 { "-debug", -IFF_DEBUG, 0, setifflags },
211 { "alias", IFF_UP, 0, notealias },
212 { "-alias", -IFF_UP, 0, notealias },
213 { "delete", -IFF_UP, 0, notealias },
214 { "netmask", NEXTARG, 0, setifnetmask },
215 { "metric", NEXTARG, 0, setifmetric },
216 { "mtu", NEXTARG, 0, setifmtu },
217 { "bssid", NEXTARG, 0, setifbssid },
218 { "-bssid", -1, 0, setifbssid },
219 { "chan", NEXTARG, 0, setifchan },
220 { "-chan", -1, 0, setifchan },
221 { "frag", NEXTARG, 0, setiffrag },
222 { "-frag", -1, 0, setiffrag },
223 { "ssid", NEXTARG, 0, setifnwid },
224 { "nwid", NEXTARG, 0, setifnwid },
225 { "nwkey", NEXTARG, 0, setifnwkey },
226 { "-nwkey", -1, 0, setifnwkey },
227 { "powersave", 1, 0, setifpowersave },
228 { "-powersave", 0, 0, setifpowersave },
229 { "powersavesleep", NEXTARG, 0, setifpowersavesleep },
230 { "hidessid", 1, 0, sethidessid },
231 { "-hidessid", 0, 0, sethidessid },
232 { "apbridge", 1, 0, setapbridge },
233 { "-apbridge", 0, 0, setapbridge },
234 { "broadcast", NEXTARG, 0, setifbroadaddr },
235 { "ipdst", NEXTARG, 0, setifipdst },
236 { "prefixlen", NEXTARG, 0, setifprefixlen},
237 { "preference", NEXTARG, 0, setifpreference},
238 { "list", NEXTARG, 0, setiflist},
239 #ifndef INET_ONLY
240 /* CARP */
241 { "advbase", NEXTARG, 0, setcarp_advbase },
242 { "advskew", NEXTARG, 0, setcarp_advskew },
243 { "pass", NEXTARG, 0, setcarp_passwd },
244 { "vhid", NEXTARG, 0, setcarp_vhid },
245 { "state", NEXTARG, 0, setcarp_state },
246 { "carpdev", NEXTARG, 0, setcarpdev },
247 { "-carpdev", 1, 0, unsetcarpdev },
248 #endif
249 #ifdef INET6
250 { "anycast", IN6_IFF_ANYCAST, 0, setia6flags },
251 { "-anycast", -IN6_IFF_ANYCAST, 0, setia6flags },
252 { "tentative", IN6_IFF_TENTATIVE, 0, setia6flags },
253 { "-tentative", -IN6_IFF_TENTATIVE, 0, setia6flags },
254 { "deprecated", IN6_IFF_DEPRECATED, 0, setia6flags },
255 { "-deprecated", -IN6_IFF_DEPRECATED, 0, setia6flags },
256 { "pltime", NEXTARG, 0, setia6pltime },
257 { "vltime", NEXTARG, 0, setia6vltime },
258 { "eui64", 0, 0, setia6eui64 },
259 #endif /*INET6*/
260 #ifndef INET_ONLY
261 { "range", NEXTARG, 0, setatrange },
262 { "phase", NEXTARG, 0, setatphase },
263 { "snpaoffset", NEXTARG, 0, setsnpaoffset },
264 { "nsellength", NEXTARG, 0, setnsellength },
265 #endif /* INET_ONLY */
266 { "tunnel", NEXTARG2, 0, (void (*)(const char *, int))
267 settunnel } ,
268 { "deletetunnel", 0, 0, deletetunnel },
269 { "vlan", NEXTARG, 0, setvlan } ,
270 { "vlanif", NEXTARG, 0, setvlanif } ,
271 { "-vlanif", 0, 0, unsetvlanif } ,
272 #if 0
273 /* XXX `create' special-cased below */
274 { "create", 0, 0, clone_create } ,
275 #endif
276 { "destroy", 0, 0, clone_destroy } ,
277 { "link0", IFF_LINK0, 0, setifflags } ,
278 { "-link0", -IFF_LINK0, 0, setifflags } ,
279 { "link1", IFF_LINK1, 0, setifflags } ,
280 { "-link1", -IFF_LINK1, 0, setifflags } ,
281 { "link2", IFF_LINK2, 0, setifflags } ,
282 { "-link2", -IFF_LINK2, 0, setifflags } ,
283 { "media", NEXTARG, A_MEDIA, setmedia },
284 { "mediaopt", NEXTARG, A_MEDIAOPTSET, setmediaopt },
285 { "-mediaopt", NEXTARG, A_MEDIAOPTCLR, unsetmediaopt },
286 { "mode", NEXTARG, A_MEDIAMODE, setmediamode },
287 { "instance", NEXTARG, A_MEDIAINST, setmediainst },
288 { "inst", NEXTARG, A_MEDIAINST, setmediainst },
289 { "ip4csum-tx", IFCAP_CSUM_IPv4_Tx,0, setifcaps },
290 { "-ip4csum-tx",-IFCAP_CSUM_IPv4_Tx,0, setifcaps },
291 { "ip4csum-rx", IFCAP_CSUM_IPv4_Rx,0, setifcaps },
292 { "-ip4csum-rx",-IFCAP_CSUM_IPv4_Rx,0, setifcaps },
293 { "tcp4csum-tx",IFCAP_CSUM_TCPv4_Tx,0, setifcaps },
294 { "-tcp4csum-tx",-IFCAP_CSUM_TCPv4_Tx,0, setifcaps },
295 { "tcp4csum-rx",IFCAP_CSUM_TCPv4_Rx,0, setifcaps },
296 { "-tcp4csum-rx",-IFCAP_CSUM_TCPv4_Rx,0, setifcaps },
297 { "udp4csum-tx",IFCAP_CSUM_UDPv4_Tx,0, setifcaps },
298 { "-udp4csum-tx",-IFCAP_CSUM_UDPv4_Tx,0, setifcaps },
299 { "udp4csum-rx",IFCAP_CSUM_UDPv4_Rx,0, setifcaps },
300 { "-udp4csum-rx",-IFCAP_CSUM_UDPv4_Rx,0, setifcaps },
301 { "tcp6csum-tx",IFCAP_CSUM_TCPv6_Tx,0, setifcaps },
302 { "-tcp6csum-tx",-IFCAP_CSUM_TCPv6_Tx,0, setifcaps },
303 { "tcp6csum-rx",IFCAP_CSUM_TCPv6_Rx,0, setifcaps },
304 { "-tcp6csum-rx",-IFCAP_CSUM_TCPv6_Rx,0, setifcaps },
305 { "udp6csum-tx",IFCAP_CSUM_UDPv6_Tx,0, setifcaps },
306 { "-udp6csum-tx",-IFCAP_CSUM_UDPv6_Tx,0, setifcaps },
307 { "udp6csum-rx",IFCAP_CSUM_UDPv6_Rx,0, setifcaps },
308 { "-udp6csum-rx",-IFCAP_CSUM_UDPv6_Rx,0, setifcaps },
309 { "ip4csum", IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx,
310 0, setifcaps },
311 { "-ip4csum", -(IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx),
312 0, setifcaps },
313 { "tcp4csum", IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx,
314 0, setifcaps },
315 { "-tcp4csum", -(IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx),
316 0, setifcaps },
317 { "udp4csum", IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx,
318 0, setifcaps },
319 { "-udp4csum", -(IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx),
320 0, setifcaps },
321 { "tcp6csum", IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx,
322 0, setifcaps },
323 { "-tcp6csum", -(IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx),
324 0, setifcaps },
325 { "udp6csum", IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx,
326 0, setifcaps },
327 { "-udp6csum", -(IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx),
328 0, setifcaps },
329 { "tso4", IFCAP_TSOv4, 0, setifcaps },
330 { "-tso4", -IFCAP_TSOv4, 0, setifcaps },
331 { "tso6", IFCAP_TSOv6, 0, setifcaps },
332 { "-tso6", -IFCAP_TSOv6, 0, setifcaps },
333 { "agrport", NEXTARG, 0, agraddport } ,
334 { "-agrport", NEXTARG, 0, agrremport } ,
335 { NULL, 0, 0, setifaddr },
336 { NULL, 0, 0, setifdstaddr },
337 };
338
339 int getinfo(struct ifreq *);
340 int carrier(void);
341 void printall(const char *);
342 void list_cloners(void);
343 void status(const struct sockaddr_dl *);
344 void usage(void);
345
346 void print_media_word(int, const char *);
347 void process_media_commands(void);
348 void init_current_media(void);
349
350 /* Known address families */
351 const struct afswtch afs[] = {
352 { "inet", AF_INET, in_status, in_getaddr, in_getprefix,
353 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &ridreq, &in_addreq },
354 #ifdef INET6
355 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
356 SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
357 /*
358 * Deleting the first address before setting new one is
359 * not prefered way in this protocol.
360 */
361 0,
362 &in6_ridreq, &in6_addreq },
363 #endif
364 #ifndef INET_ONLY /* small version, for boot media */
365 { "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
366 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, &addreq, &addreq },
367 { "iso", AF_ISO, iso_status, iso_getaddr, NULL,
368 SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, SIOCGIFADDR_ISO,
369 &iso_ridreq, &iso_addreq },
370 #endif /* INET_ONLY */
371 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
372 };
373
374 const struct afswtch *afp; /*the address family being set or asked about*/
375
376 int
377 main(int argc, char *argv[])
378 {
379 int ch;
380
381 /* Parse command-line options */
382 aflag = mflag = vflag = zflag = 0;
383 while ((ch = getopt(argc, argv, "AabCdhlmsuvz"
384 #ifdef INET6
385 "L"
386 #endif
387 )) != -1) {
388 switch (ch) {
389 case 'A':
390 warnx("-A is deprecated");
391 break;
392
393 case 'a':
394 aflag = 1;
395 break;
396
397 case 'b':
398 bflag = 1;
399 break;
400
401 case 'C':
402 Cflag = 1;
403 break;
404
405 case 'd':
406 dflag = 1;
407 break;
408 case 'h':
409 hflag = 1;
410 break;
411 #ifdef INET6
412 case 'L':
413 Lflag = 1;
414 break;
415 #endif
416
417 case 'l':
418 lflag = 1;
419 break;
420
421 case 'm':
422 mflag = 1;
423 break;
424
425 case 's':
426 sflag = 1;
427 break;
428
429 case 'u':
430 uflag = 1;
431 break;
432
433 case 'v':
434 vflag = 1;
435 break;
436
437 case 'z':
438 zflag = 1;
439 break;
440
441
442 default:
443 usage();
444 /* NOTREACHED */
445 }
446 }
447 argc -= optind;
448 argv += optind;
449
450 /*
451 * -l means "list all interfaces", and is mutally exclusive with
452 * all other flags/commands.
453 *
454 * -C means "list all names of cloners", and it mutually exclusive
455 * with all other flags/commands.
456 *
457 * -a means "print status of all interfaces".
458 */
459 if ((lflag || Cflag) && (aflag || mflag || vflag || argc || zflag))
460 usage();
461 #ifdef INET6
462 if ((lflag || Cflag) && Lflag)
463 usage();
464 #endif
465 if (lflag && Cflag)
466 usage();
467 if (Cflag) {
468 if (argc)
469 usage();
470 list_cloners();
471 exit(0);
472 }
473 if (aflag || lflag) {
474 if (argc > 1)
475 usage();
476 else if (argc == 1) {
477 afp = lookup_af_byname(argv[0]);
478 if (afp == NULL)
479 usage();
480 }
481 if (afp)
482 af = ifr.ifr_addr.sa_family = afp->af_af;
483 else
484 af = ifr.ifr_addr.sa_family = afs[0].af_af;
485 printall(NULL);
486 exit(0);
487 }
488
489 /* Make sure there's an interface name. */
490 if (argc < 1)
491 usage();
492 if (strlcpy(name, argv[0], sizeof(name)) >= sizeof(name))
493 errx(1, "interface name '%s' too long", argv[0]);
494 argc--; argv++;
495
496 /*
497 * NOTE: We must special-case the `create' command right
498 * here as we would otherwise fail in getinfo().
499 */
500 if (argc > 0 && strcmp(argv[0], "create") == 0) {
501 clone_create(argv[0], 0);
502 argc--, argv++;
503 if (argc == 0)
504 exit(0);
505 }
506
507 /* Check for address family. */
508 afp = NULL;
509 if (argc > 0) {
510 afp = lookup_af_byname(argv[0]);
511 if (afp != NULL) {
512 argv++;
513 argc--;
514 }
515 }
516
517 /* Initialize af, just for use in getinfo(). */
518 if (afp == NULL)
519 af = afs->af_af;
520 else
521 af = afp->af_af;
522
523 /* Get information about the interface. */
524 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
525 if (getinfo(&ifr) < 0)
526 exit(1);
527
528 if (sflag) {
529 if (argc != 0)
530 usage();
531 else
532 exit(carrier());
533 }
534
535 /* No more arguments means interface status. */
536 if (argc == 0) {
537 printall(name);
538 exit(0);
539 }
540
541 /* The following operations assume inet family as the default. */
542 if (afp == NULL)
543 afp = afs;
544 af = ifr.ifr_addr.sa_family = afp->af_af;
545
546 /* Process commands. */
547 for (; argc > 0; argc--, argv++) {
548 const struct cmd *p;
549
550 for (p = cmds; p->c_name != NULL; p++) {
551 if (strcmp(argv[0], p->c_name) == 0)
552 break;
553 }
554 if (p->c_name == NULL && setaddr) {
555 if ((flags & IFF_POINTOPOINT) == 0) {
556 errx(EXIT_FAILURE,
557 "can't set destination address %s",
558 "on non-point-to-point link");
559 }
560 p++; /* got src, do dst */
561 }
562 if (p->c_func == NULL)
563 continue;
564 if (p->c_parameter == NEXTARG) {
565 if (argc < 2)
566 errx(EXIT_FAILURE, "'%s' requires argument",
567 p->c_name);
568 (*p->c_func)(argv[1], 0);
569 argc--, argv++;
570 } else if (p->c_parameter == NEXTARG2) {
571 if (argc < 3)
572 errx(EXIT_FAILURE, "'%s' requires 2 arguments",
573 p->c_name);
574 ((void (*)(const char *, const char *))
575 *p->c_func)(argv[1], argv[2]);
576 argc -= 2, argv += 2;
577 } else
578 (*p->c_func)(argv[0], p->c_parameter);
579 actions |= p->c_action;
580 }
581
582 /*
583 * See if multiple alias, -alias, or delete commands were
584 * specified. More than one constitutes an invalid command line
585 */
586
587 if (conflicting > 1)
588 errx(EXIT_FAILURE,
589 "Only one use of alias, -alias or delete is valid.");
590
591 /* Process any media commands that may have been issued. */
592 process_media_commands();
593
594 if (af == AF_INET6 && explicit_prefix == 0) {
595 /*
596 * Aggregatable address architecture defines all prefixes
597 * are 64. So, it is convenient to set prefixlen to 64 if
598 * it is not specified.
599 */
600 setifprefixlen("64", 0);
601 /* in6_getprefix("64", MASK) if MASK is available here... */
602 }
603
604 #ifndef INET_ONLY
605 if (af == AF_APPLETALK)
606 checkatrange(&addreq.ifra_addr);
607 #endif /* INET_ONLY */
608
609 if (clearaddr) {
610 estrlcpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
611 if (ioctl(s, afp->af_difaddr, afp->af_ridreq) == -1)
612 err(EXIT_FAILURE, "SIOCDIFADDR");
613 }
614 if (newaddr > 0) {
615 estrlcpy(afp->af_addreq, name, sizeof ifr.ifr_name);
616 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) == -1)
617 warn("SIOCAIFADDR");
618 else if (check_up_state < 0)
619 check_up_state = 1;
620 }
621
622 if (have_preference)
623 do_setifpreference();
624 if (g_ifcr_updated) {
625 strlcpy(g_ifcr.ifcr_name, name,
626 sizeof(g_ifcr.ifcr_name));
627 if (ioctl(s, SIOCSIFCAP, &g_ifcr) == -1)
628 err(EXIT_FAILURE, "SIOCSIFCAP");
629 }
630
631 if (check_up_state == 1)
632 check_ifflags_up(name);
633
634 exit(0);
635 }
636
637 const struct afswtch *
638 lookup_af_byname(const char *cp)
639 {
640 const struct afswtch *a;
641
642 for (a = afs; a->af_name != NULL; a++)
643 if (strcmp(a->af_name, cp) == 0)
644 return (a);
645 return (NULL);
646 }
647
648 const struct afswtch *
649 lookup_af_bynum(int afnum)
650 {
651 const struct afswtch *a;
652
653 for (a = afs; a->af_name != NULL; a++)
654 if (a->af_af == afnum)
655 return (a);
656 return (NULL);
657 }
658
659 void
660 getsock(int naf)
661 {
662 static int oaf = -1;
663
664 if (oaf == naf)
665 return;
666 if (oaf != -1)
667 close(s);
668 s = socket(naf, SOCK_DGRAM, 0);
669 if (s < 0)
670 oaf = -1;
671 else
672 oaf = naf;
673 }
674
675 int
676 getinfo(struct ifreq *giifr)
677 {
678
679 getsock(af);
680 if (s < 0)
681 err(EXIT_FAILURE, "socket");
682 if (ioctl(s, SIOCGIFFLAGS, giifr) == -1) {
683 warn("SIOCGIFFLAGS %s", giifr->ifr_name);
684 return (-1);
685 }
686 flags = giifr->ifr_flags;
687 if (ioctl(s, SIOCGIFMETRIC, giifr) == -1) {
688 warn("SIOCGIFMETRIC %s", giifr->ifr_name);
689 metric = 0;
690 } else
691 metric = giifr->ifr_metric;
692 if (ioctl(s, SIOCGIFMTU, giifr) == -1)
693 mtu = 0;
694 else
695 mtu = giifr->ifr_mtu;
696
697 memset(&g_ifcr, 0, sizeof(g_ifcr));
698 estrlcpy(g_ifcr.ifcr_name, giifr->ifr_name, sizeof(g_ifcr.ifcr_name));
699 (void) ioctl(s, SIOCGIFCAP, &g_ifcr);
700
701 return (0);
702 }
703
704 void
705 printall(const char *ifname)
706 {
707 struct ifaddrs *ifap, *ifa;
708 struct ifreq paifr;
709 const struct sockaddr_dl *sdl = NULL;
710 int idx;
711 char *p;
712
713 if (getifaddrs(&ifap) != 0)
714 err(EXIT_FAILURE, "getifaddrs");
715 p = NULL;
716 idx = 0;
717 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
718 memset(&paifr, 0, sizeof(paifr));
719 estrlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
720 if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
721 memcpy(&paifr.ifr_addr, ifa->ifa_addr,
722 ifa->ifa_addr->sa_len);
723 }
724
725 if (ifname && strcmp(ifname, ifa->ifa_name) != 0)
726 continue;
727 if (ifa->ifa_addr->sa_family == AF_LINK)
728 sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
729 if (p && strcmp(p, ifa->ifa_name) == 0)
730 continue;
731 if (strlcpy(name, ifa->ifa_name, sizeof(name)) >= sizeof(name))
732 continue;
733 p = ifa->ifa_name;
734
735 if (getinfo(&paifr) < 0)
736 continue;
737 if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0)
738 continue;
739 if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
740 continue;
741 if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
742 continue;
743
744 if (sflag && carrier())
745 continue;
746 idx++;
747 /*
748 * Are we just listing the interfaces?
749 */
750 if (lflag) {
751 if (idx > 1)
752 printf(" ");
753 fputs(name, stdout);
754 continue;
755 }
756
757 status(sdl);
758 sdl = NULL;
759 }
760 if (lflag)
761 printf("\n");
762 freeifaddrs(ifap);
763 }
764
765 void
766 list_cloners(void)
767 {
768 struct if_clonereq ifcr;
769 char *cp, *buf;
770 int idx;
771
772 memset(&ifcr, 0, sizeof(ifcr));
773
774 getsock(AF_INET);
775
776 if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
777 err(EXIT_FAILURE, "SIOCIFGCLONERS for count");
778
779 buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
780 if (buf == NULL)
781 err(EXIT_FAILURE, "unable to allocate cloner name buffer");
782
783 ifcr.ifcr_count = ifcr.ifcr_total;
784 ifcr.ifcr_buffer = buf;
785
786 if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
787 err(EXIT_FAILURE, "SIOCIFGCLONERS for names");
788
789 /*
790 * In case some disappeared in the mean time, clamp it down.
791 */
792 if (ifcr.ifcr_count > ifcr.ifcr_total)
793 ifcr.ifcr_count = ifcr.ifcr_total;
794
795 for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
796 if (idx > 0)
797 printf(" ");
798 printf("%s", cp);
799 }
800
801 printf("\n");
802 free(buf);
803 return;
804 }
805
806 /*ARGSUSED*/
807 void
808 clone_create(const char *addr, int param)
809 {
810
811 /* We're called early... */
812 getsock(AF_INET);
813
814 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
815 if (ioctl(s, SIOCIFCREATE, &ifr) == -1)
816 err(EXIT_FAILURE, "SIOCIFCREATE");
817 }
818
819 /*ARGSUSED*/
820 void
821 clone_destroy(const char *addr, int param)
822 {
823
824 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
825 if (ioctl(s, SIOCIFDESTROY, &ifr) == -1)
826 err(EXIT_FAILURE, "SIOCIFDESTROY");
827 }
828
829 /*ARGSUSED*/
830 void
831 setifaddr(const char *addr, int param)
832 {
833 struct ifreq *siifr; /* XXX */
834
835 /*
836 * Delay the ioctl to set the interface addr until flags are all set.
837 * The address interpretation may depend on the flags,
838 * and the flags may change when the address is set.
839 */
840 setaddr++;
841 if (newaddr == -1)
842 newaddr = 1;
843 if (doalias == 0 && afp->af_gifaddr != 0) {
844 siifr = (struct ifreq *)afp->af_ridreq;
845 estrlcpy(siifr->ifr_name, name, sizeof(siifr->ifr_name));
846 siifr->ifr_addr.sa_family = afp->af_af;
847 if (ioctl(s, afp->af_gifaddr, afp->af_ridreq) == 0)
848 clearaddr = 1;
849 else if (errno == EADDRNOTAVAIL)
850 /* No address was assigned yet. */
851 ;
852 else
853 err(EXIT_FAILURE, "SIOCGIFADDR");
854 }
855
856 (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
857 }
858
859 void
860 setifnetmask(const char *addr, int d)
861 {
862 (*afp->af_getaddr)(addr, MASK);
863 }
864
865 void
866 setifbroadaddr(const char *addr, int d)
867 {
868 (*afp->af_getaddr)(addr, DSTADDR);
869 }
870
871 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
872 /*ARGSUSED*/
873 void
874 notealias(const char *addr, int param)
875 {
876 if (setaddr && doalias == 0 && param < 0)
877 (void) memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
878 rqtosa(af_addreq)->sa_len);
879 doalias = param;
880 if (param < 0) {
881 clearaddr = 1;
882 newaddr = 0;
883 conflicting++;
884 } else {
885 clearaddr = 0;
886 conflicting++;
887 }
888 }
889
890 /*ARGSUSED*/
891 void
892 notrailers(const char *vname, int value)
893 {
894 puts("Note: trailers are no longer sent, but always received");
895 }
896
897 /*ARGSUSED*/
898 void
899 setifdstaddr(const char *addr, int param)
900 {
901 (*afp->af_getaddr)(addr, DSTADDR);
902 }
903
904 void
905 check_ifflags_up(const char *vname)
906 {
907 struct ifreq ifreq;
908
909 estrlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
910 if (ioctl(s, SIOCGIFFLAGS, &ifreq) == -1)
911 err(EXIT_FAILURE, "SIOCGIFFLAGS");
912 if (ifreq.ifr_flags & IFF_UP)
913 return;
914 ifreq.ifr_flags |= IFF_UP;
915 if (ioctl(s, SIOCSIFFLAGS, &ifreq) == -1)
916 err(EXIT_FAILURE, "SIOCSIFFLAGS");
917 }
918
919 void
920 setifflags(const char *vname, int value)
921 {
922 struct ifreq ifreq;
923
924 estrlcpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
925 if (ioctl(s, SIOCGIFFLAGS, &ifreq) == -1)
926 err(EXIT_FAILURE, "SIOCGIFFLAGS");
927 flags = ifreq.ifr_flags;
928
929 if (value < 0) {
930 value = -value;
931 if (value == IFF_UP)
932 check_up_state = 0;
933 flags &= ~value;
934 } else
935 flags |= value;
936 ifreq.ifr_flags = flags;
937 if (ioctl(s, SIOCSIFFLAGS, &ifreq) == -1)
938 err(EXIT_FAILURE, "SIOCSIFFLAGS");
939 }
940
941 void
942 setifcaps(const char *vname, int value)
943 {
944
945 if (value < 0) {
946 value = -value;
947 g_ifcr.ifcr_capenable &= ~value;
948 } else
949 g_ifcr.ifcr_capenable |= value;
950
951 g_ifcr_updated = 1;
952 }
953
954 void
955 setifmetric(const char *val, int d)
956 {
957 char *ep = NULL;
958
959 estrlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
960 ifr.ifr_metric = strtoul(val, &ep, 10);
961 if (!ep || *ep)
962 errx(EXIT_FAILURE, "%s: invalid metric", val);
963 if (ioctl(s, SIOCSIFMETRIC, &ifr) == -1)
964 warn("SIOCSIFMETRIC");
965 }
966
967 void
968 setifpreference(const char *val, int d)
969 {
970 char *end = NULL;
971 if (setaddr <= 0) {
972 errx(EXIT_FAILURE,
973 "set address preference: first specify an address");
974 }
975 preference = strtoul(val, &end, 10);
976 if (end == NULL || *end != '\0' || preference > UINT16_MAX)
977 errx(EXIT_FAILURE, "invalid preference %s", val);
978 have_preference = 1;
979 }
980
981 void
982 do_setifpreference(void)
983 {
984 struct if_addrprefreq ifap;
985 (void)strncpy(ifap.ifap_name, name, sizeof(ifap.ifap_name));
986 ifap.ifap_preference = (uint16_t)preference;
987 (void)memcpy(&ifap.ifap_addr, rqtosa(af_addreq),
988 MIN(sizeof(ifap.ifap_addr), rqtosa(af_addreq)->sa_len));
989 if (ioctl(s, SIOCSIFADDRPREF, &ifap) == -1)
990 warn("SIOCSIFADDRPREF");
991 }
992
993 void
994 setifmtu(const char *val, int d)
995 {
996 char *ep = NULL;
997
998 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
999 ifr.ifr_mtu = strtoul(val, &ep, 10);
1000 if (!ep || *ep)
1001 errx(EXIT_FAILURE, "%s: invalid mtu", val);
1002 if (ioctl(s, SIOCSIFMTU, &ifr) == -1)
1003 warn("SIOCSIFMTU");
1004 }
1005
1006 const char *
1007 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1008 {
1009 int len;
1010 bool hexstr;
1011 u_int8_t *p;
1012
1013 len = *lenp;
1014 p = buf;
1015 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1016 if (hexstr)
1017 val += 2;
1018 for (;;) {
1019 if (*val == '\0')
1020 break;
1021 if (sep != NULL && strchr(sep, *val) != NULL) {
1022 val++;
1023 break;
1024 }
1025 if (hexstr) {
1026 if (!isxdigit((u_char)val[0]) ||
1027 !isxdigit((u_char)val[1])) {
1028 warnx("bad hexadecimal digits");
1029 return NULL;
1030 }
1031 }
1032 if (p > buf + len) {
1033 if (hexstr)
1034 warnx("hexadecimal digits too long");
1035 else
1036 warnx("strings too long");
1037 return NULL;
1038 }
1039 if (hexstr) {
1040 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1041 *p++ = (tohex((u_char)val[0]) << 4) |
1042 tohex((u_char)val[1]);
1043 #undef tohex
1044 val += 2;
1045 } else
1046 *p++ = *val++;
1047 }
1048 len = p - buf;
1049 if (len < *lenp)
1050 memset(p, 0, *lenp - len);
1051 *lenp = len;
1052 return val;
1053 }
1054
1055 void
1056 print_string(const u_int8_t *buf, int len)
1057 {
1058 int i;
1059 bool hasspc;
1060
1061 i = 0;
1062 hasspc = false;
1063 if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1064 for (; i < len; i++) {
1065 if (!isprint(buf[i]))
1066 break;
1067 if (isspace(buf[i]))
1068 hasspc = true;
1069 }
1070 }
1071 if (i == len) {
1072 if (hasspc || len == 0)
1073 printf("\"%.*s\"", len, buf);
1074 else
1075 printf("%.*s", len, buf);
1076 } else {
1077 printf("0x");
1078 for (i = 0; i < len; i++)
1079 printf("%02x", buf[i]);
1080 }
1081 }
1082
1083 static void
1084 media_error(int type, const char *val, const char *opt)
1085 {
1086 errx(EXIT_FAILURE, "unknown %s media %s: %s",
1087 get_media_type_string(type), opt, val);
1088 }
1089
1090 void
1091 init_current_media(void)
1092 {
1093 struct ifmediareq ifmr;
1094
1095 /*
1096 * If we have not yet done so, grab the currently-selected
1097 * media.
1098 */
1099 if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
1100 (void) memset(&ifmr, 0, sizeof(ifmr));
1101 estrlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1102
1103 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1104 /*
1105 * If we get E2BIG, the kernel is telling us
1106 * that there are more, so we can ignore it.
1107 */
1108 if (errno != E2BIG)
1109 err(EXIT_FAILURE, "SGIOCGIFMEDIA");
1110 }
1111
1112 media_current = ifmr.ifm_current;
1113 }
1114
1115 /* Sanity. */
1116 if (IFM_TYPE(media_current) == 0)
1117 errx(EXIT_FAILURE, "%s: no link type?", name);
1118 }
1119
1120 void
1121 process_media_commands(void)
1122 {
1123
1124 if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
1125 /* Nothing to do. */
1126 return;
1127 }
1128
1129 /*
1130 * Media already set up, and commands sanity-checked. Set/clear
1131 * any options, and we're ready to go.
1132 */
1133 media_current |= mediaopt_set;
1134 media_current &= ~mediaopt_clear;
1135
1136 estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1137 ifr.ifr_media = media_current;
1138
1139 if (ioctl(s, SIOCSIFMEDIA, &ifr) == -1)
1140 err(EXIT_FAILURE, "SIOCSIFMEDIA");
1141 }
1142
1143 void
1144 setmedia(const char *val, int d)
1145 {
1146 int type, subtype, inst;
1147
1148 init_current_media();
1149
1150 /* Only one media command may be given. */
1151 if (actions & A_MEDIA)
1152 errx(EXIT_FAILURE, "only one `media' command may be issued");
1153
1154 /* Must not come after mode commands */
1155 if (actions & A_MEDIAMODE)
1156 errx(EXIT_FAILURE,
1157 "may not issue `media' after `mode' commands");
1158
1159 /* Must not come after mediaopt commands */
1160 if (actions & A_MEDIAOPT)
1161 errx(EXIT_FAILURE,
1162 "may not issue `media' after `mediaopt' commands");
1163
1164 /*
1165 * No need to check if `instance' has been issued; setmediainst()
1166 * craps out if `media' has not been specified.
1167 */
1168
1169 type = IFM_TYPE(media_current);
1170 inst = IFM_INST(media_current);
1171
1172 /* Look up the subtype. */
1173 subtype = get_media_subtype(type, val);
1174 if (subtype == -1)
1175 media_error(type, val, "subtype");
1176
1177 /* Build the new current media word. */
1178 media_current = IFM_MAKEWORD(type, subtype, 0, inst);
1179
1180 /* Media will be set after other processing is complete. */
1181 }
1182
1183 void
1184 setmediaopt(const char *val, int d)
1185 {
1186 char *invalid;
1187
1188 init_current_media();
1189
1190 /* Can only issue `mediaopt' once. */
1191 if (actions & A_MEDIAOPTSET)
1192 errx(EXIT_FAILURE, "only one `mediaopt' command may be issued");
1193
1194 /* Can't issue `mediaopt' if `instance' has already been issued. */
1195 if (actions & A_MEDIAINST)
1196 errx(EXIT_FAILURE, "may not issue `mediaopt' after `instance'");
1197
1198 mediaopt_set = get_media_options(media_current, val, &invalid);
1199 if (mediaopt_set == -1)
1200 media_error(media_current, invalid, "option");
1201
1202 /* Media will be set after other processing is complete. */
1203 }
1204
1205 void
1206 unsetmediaopt(const char *val, int d)
1207 {
1208 char *invalid;
1209
1210 init_current_media();
1211
1212 /* Can only issue `-mediaopt' once. */
1213 if (actions & A_MEDIAOPTCLR)
1214 errx(EXIT_FAILURE,
1215 "only one `-mediaopt' command may be issued");
1216
1217 /* May not issue `media' and `-mediaopt'. */
1218 if (actions & A_MEDIA)
1219 errx(EXIT_FAILURE,
1220 "may not issue both `media' and `-mediaopt'");
1221
1222 /*
1223 * No need to check for A_MEDIAINST, since the test for A_MEDIA
1224 * implicitly checks for A_MEDIAINST.
1225 */
1226
1227 mediaopt_clear = get_media_options(media_current, val, &invalid);
1228 if (mediaopt_clear == -1)
1229 media_error(media_current, invalid, "option");
1230
1231 /* Media will be set after other processing is complete. */
1232 }
1233
1234 void
1235 setmediainst(const char *val, int d)
1236 {
1237 int type, subtype, options, inst;
1238
1239 init_current_media();
1240
1241 /* Can only issue `instance' once. */
1242 if (actions & A_MEDIAINST)
1243 errx(EXIT_FAILURE, "only one `instance' command may be issued");
1244
1245 /* Must have already specified `media' */
1246 if ((actions & A_MEDIA) == 0)
1247 errx(EXIT_FAILURE, "must specify `media' before `instance'");
1248
1249 type = IFM_TYPE(media_current);
1250 subtype = IFM_SUBTYPE(media_current);
1251 options = IFM_OPTIONS(media_current);
1252
1253 inst = atoi(val);
1254 if (inst < 0 || inst > IFM_INST_MAX)
1255 errx(EXIT_FAILURE, "invalid media instance: %s", val);
1256
1257 media_current = IFM_MAKEWORD(type, subtype, options, inst);
1258
1259 /* Media will be set after other processing is complete. */
1260 }
1261
1262 void
1263 setmediamode(const char *val, int d)
1264 {
1265 int type, subtype, options, inst, mode;
1266
1267 init_current_media();
1268
1269 /* Can only issue `mode' once. */
1270 if (actions & A_MEDIAMODE)
1271 errx(EXIT_FAILURE, "only one `mode' command may be issued");
1272
1273 type = IFM_TYPE(media_current);
1274 subtype = IFM_SUBTYPE(media_current);
1275 options = IFM_OPTIONS(media_current);
1276 inst = IFM_INST(media_current);
1277
1278 mode = get_media_mode(type, val);
1279 if (mode == -1)
1280 media_error(type, val, "mode");
1281
1282 media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode;
1283
1284 /* Media will be set after other processing is complete. */
1285 }
1286
1287 void
1288 print_media_word(int ifmw, const char *opt_sep)
1289 {
1290 const char *str;
1291
1292 printf("%s", get_media_subtype_string(ifmw));
1293
1294 /* Find mode. */
1295 if (IFM_MODE(ifmw) != 0) {
1296 str = get_media_mode_string(ifmw);
1297 if (str != NULL)
1298 printf(" mode %s", str);
1299 }
1300
1301 /* Find options. */
1302 for (; (str = get_media_option_string(&ifmw)) != NULL; opt_sep = ",")
1303 printf("%s%s", opt_sep, str);
1304
1305 if (IFM_INST(ifmw) != 0)
1306 printf(" instance %d", IFM_INST(ifmw));
1307 }
1308
1309 int
1310 carrier(void)
1311 {
1312 struct ifmediareq ifmr;
1313
1314 (void) memset(&ifmr, 0, sizeof(ifmr));
1315 estrlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1316
1317 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1318 /*
1319 * Interface doesn't support SIOC{G,S}IFMEDIA;
1320 * assume ok.
1321 */
1322 return 0;
1323 }
1324 if ((ifmr.ifm_status & IFM_AVALID) == 0) {
1325 /*
1326 * Interface doesn't report media-valid status.
1327 * assume ok.
1328 */
1329 return 0;
1330 }
1331 /* otherwise, return ok for active, not-ok if not active. */
1332 return !(ifmr.ifm_status & IFM_ACTIVE);
1333 }
1334
1335
1336 const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
1337
1338 const struct ifmedia_status_description ifm_status_descriptions[] =
1339 IFM_STATUS_DESCRIPTIONS;
1340
1341 /*
1342 * Print the status of the interface. If an address family was
1343 * specified, show it and it only; otherwise, show them all.
1344 */
1345 void
1346 status(const struct sockaddr_dl *sdl)
1347 {
1348 const struct afswtch *p = afp;
1349 struct ifmediareq ifmr;
1350 struct ifdatareq ifdr;
1351 int *media_list, i;
1352 char hbuf[NI_MAXHOST];
1353 char fbuf[BUFSIZ];
1354
1355 (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags);
1356 printf("%s: flags=%s", name, &fbuf[2]);
1357 if (metric)
1358 printf(" metric %lu", metric);
1359 if (mtu)
1360 printf(" mtu %lu", mtu);
1361 printf("\n");
1362
1363 if (g_ifcr.ifcr_capabilities) {
1364 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1365 g_ifcr.ifcr_capabilities);
1366 printf("\tcapabilities=%s\n", &fbuf[2]);
1367 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS,
1368 g_ifcr.ifcr_capenable);
1369 printf("\tenabled=%s\n", &fbuf[2]);
1370 }
1371
1372 ieee80211_status();
1373 vlan_status();
1374 #ifndef INET_ONLY
1375 carp_status();
1376 #endif
1377 tunnel_status();
1378 agr_status();
1379
1380 if (sdl != NULL &&
1381 getnameinfo((const struct sockaddr *)sdl, sdl->sdl_len,
1382 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0 &&
1383 hbuf[0] != '\0')
1384 printf("\taddress: %s\n", hbuf);
1385
1386 (void) memset(&ifmr, 0, sizeof(ifmr));
1387 estrlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
1388
1389 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) {
1390 /*
1391 * Interface doesn't support SIOC{G,S}IFMEDIA.
1392 */
1393 goto iface_stats;
1394 }
1395
1396 if (ifmr.ifm_count == 0) {
1397 warnx("%s: no media types?", name);
1398 goto iface_stats;
1399 }
1400
1401 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
1402 if (media_list == NULL)
1403 err(EXIT_FAILURE, "malloc");
1404 ifmr.ifm_ulist = media_list;
1405
1406 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1)
1407 err(EXIT_FAILURE, "SIOCGIFMEDIA");
1408
1409 printf("\tmedia: %s ", get_media_type_string(ifmr.ifm_current));
1410 print_media_word(ifmr.ifm_current, " ");
1411 if (ifmr.ifm_active != ifmr.ifm_current) {
1412 printf(" (");
1413 print_media_word(ifmr.ifm_active, " ");
1414 printf(")");
1415 }
1416 printf("\n");
1417
1418 if (ifmr.ifm_status & IFM_STATUS_VALID) {
1419 const struct ifmedia_status_description *ifms;
1420 int bitno, found = 0;
1421
1422 printf("\tstatus: ");
1423 for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
1424 for (ifms = ifm_status_descriptions;
1425 ifms->ifms_valid != 0; ifms++) {
1426 if (ifms->ifms_type !=
1427 IFM_TYPE(ifmr.ifm_current) ||
1428 ifms->ifms_valid !=
1429 ifm_status_valid_list[bitno])
1430 continue;
1431 printf("%s%s", found ? ", " : "",
1432 IFM_STATUS_DESC(ifms, ifmr.ifm_status));
1433 found = 1;
1434
1435 /*
1436 * For each valid indicator bit, there's
1437 * only one entry for each media type, so
1438 * terminate the inner loop now.
1439 */
1440 break;
1441 }
1442 }
1443
1444 if (found == 0)
1445 printf("unknown");
1446 printf("\n");
1447 }
1448
1449 if (mflag) {
1450 int type, printed_type;
1451
1452 for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
1453 for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
1454 if (IFM_TYPE(media_list[i]) != type)
1455 continue;
1456 if (printed_type == 0) {
1457 printf("\tsupported %s media:\n",
1458 get_media_type_string(type));
1459 printed_type = 1;
1460 }
1461 printf("\t\tmedia ");
1462 print_media_word(media_list[i], " mediaopt ");
1463 printf("\n");
1464 }
1465 }
1466 }
1467
1468 free(media_list);
1469
1470 iface_stats:
1471 if (!vflag && !zflag)
1472 goto proto_status;
1473
1474 estrlcpy(ifdr.ifdr_name, name, sizeof(ifdr.ifdr_name));
1475
1476 if (ioctl(s, zflag ? SIOCZIFDATA:SIOCGIFDATA, &ifdr) == -1) {
1477 err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA");
1478 } else {
1479 struct if_data * const ifi = &ifdr.ifdr_data;
1480 char buf[5];
1481
1482 #define PLURAL(n) ((n) == 1 ? "" : "s")
1483 #define PLURALSTR(s) ((atof(s)) == 1.0 ? "" : "s")
1484 printf("\tinput: %llu packet%s, ",
1485 (unsigned long long) ifi->ifi_ipackets,
1486 PLURAL(ifi->ifi_ipackets));
1487 if (hflag) {
1488 (void) humanize_number(buf, sizeof(buf),
1489 (int64_t) ifi->ifi_ibytes, "", HN_AUTOSCALE,
1490 HN_NOSPACE | HN_DECIMAL);
1491 printf("%s byte%s", buf,
1492 PLURALSTR(buf));
1493 } else
1494 printf("%llu byte%s",
1495 (unsigned long long) ifi->ifi_ibytes,
1496 PLURAL(ifi->ifi_ibytes));
1497 if (ifi->ifi_imcasts)
1498 printf(", %llu multicast%s",
1499 (unsigned long long) ifi->ifi_imcasts,
1500 PLURAL(ifi->ifi_imcasts));
1501 if (ifi->ifi_ierrors)
1502 printf(", %llu error%s",
1503 (unsigned long long) ifi->ifi_ierrors,
1504 PLURAL(ifi->ifi_ierrors));
1505 if (ifi->ifi_iqdrops)
1506 printf(", %llu queue drop%s",
1507 (unsigned long long) ifi->ifi_iqdrops,
1508 PLURAL(ifi->ifi_iqdrops));
1509 if (ifi->ifi_noproto)
1510 printf(", %llu unknown protocol",
1511 (unsigned long long) ifi->ifi_noproto);
1512 printf("\n\toutput: %llu packet%s, ",
1513 (unsigned long long) ifi->ifi_opackets,
1514 PLURAL(ifi->ifi_opackets));
1515 if (hflag) {
1516 (void) humanize_number(buf, sizeof(buf),
1517 (int64_t) ifi->ifi_obytes, "", HN_AUTOSCALE,
1518 HN_NOSPACE | HN_DECIMAL);
1519 printf("%s byte%s", buf,
1520 PLURALSTR(buf));
1521 } else
1522 printf("%llu byte%s",
1523 (unsigned long long) ifi->ifi_obytes,
1524 PLURAL(ifi->ifi_obytes));
1525 if (ifi->ifi_omcasts)
1526 printf(", %llu multicast%s",
1527 (unsigned long long) ifi->ifi_omcasts,
1528 PLURAL(ifi->ifi_omcasts));
1529 if (ifi->ifi_oerrors)
1530 printf(", %llu error%s",
1531 (unsigned long long) ifi->ifi_oerrors,
1532 PLURAL(ifi->ifi_oerrors));
1533 if (ifi->ifi_collisions)
1534 printf(", %llu collision%s",
1535 (unsigned long long) ifi->ifi_collisions,
1536 PLURAL(ifi->ifi_collisions));
1537 printf("\n");
1538 #undef PLURAL
1539 #undef PLURALSTR
1540 }
1541
1542 ieee80211_statistics();
1543
1544 proto_status:
1545 if ((p = afp) != NULL) {
1546 (*p->af_status)(1);
1547 } else for (p = afs; p->af_name; p++) {
1548 ifr.ifr_addr.sa_family = p->af_af;
1549 (*p->af_status)(0);
1550 }
1551 }
1552
1553 void
1554 setifprefixlen(const char *addr, int d)
1555 {
1556 if (*afp->af_getprefix)
1557 (*afp->af_getprefix)(addr, MASK);
1558 explicit_prefix = 1;
1559 }
1560
1561 void
1562 usage(void)
1563 {
1564 const char *progname = getprogname();
1565
1566 fprintf(stderr,
1567 "usage: %s [-h] [-m] [-v] [-z] "
1568 #ifdef INET6
1569 "[-L] "
1570 #endif
1571 "interface\n"
1572 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
1573 "\t\t[ alias | -alias ] ]\n"
1574 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n"
1575 "\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n"
1576 "\t[ list scan ]\n"
1577 "\t[ powersave | -powersave ] [ powersavesleep duration ]\n"
1578 "\t[ hidessid | -hidessid ] [ apbridge | -apbridge ]\n"
1579 "\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"
1580 "\t[ arp | -arp ]\n"
1581 "\t[ media type ] [ mediaopt opts ] [ -mediaopt opts ] "
1582 "[ instance minst ]\n"
1583 "\t[ preference n ]\n"
1584 "\t[ vlan n vlanif i ]\n"
1585 "\t[ agrport i ] [ -agrport i ]\n"
1586 "\t[ anycast | -anycast ] [ deprecated | -deprecated ]\n"
1587 "\t[ tentative | -tentative ] [ pltime n ] [ vltime n ] [ eui64 ]\n"
1588 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
1589 " %s -a [-b] [-h] [-m] [-d] [-u] [-v] [-z] [ af ]\n"
1590 " %s -l [-b] [-d] [-u] [-s]\n"
1591 " %s -C\n"
1592 " %s interface create\n"
1593 " %s interface destroy\n",
1594 progname, progname, progname, progname, progname, progname);
1595 exit(1);
1596 }
1597