1 /*        $NetBSD: ifconfig.c,v 1.251 2024/08/20 08:18:24 ozaki-r 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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1983, 1993
35  *        The Regents of the University of California.  All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  */
61 
62 #include <sys/cdefs.h>
63 #ifndef lint
64 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
65  The Regents of the University of California.  All rights reserved.");
66 __RCSID("$NetBSD: ifconfig.c,v 1.251 2024/08/20 08:18:24 ozaki-r Exp $");
67 #endif /* not lint */
68 
69 #include <sys/param.h>
70 #include <sys/queue.h>
71 #include <sys/socket.h>
72 #include <sys/ioctl.h>
73 
74 #include <net/if.h>
75 #include <net/if_dl.h>
76 #include <net/if_media.h>
77 #include <net/if_ether.h>
78 #include <netinet/in.h>                 /* XXX */
79 #include <netinet/in_var.h>   /* XXX */
80 
81 #include <netdb.h>
82 
83 #include <sys/protosw.h>
84 
85 #include <assert.h>
86 #include <ctype.h>
87 #include <err.h>
88 #include <errno.h>
89 #include <stdbool.h>
90 #include <stddef.h>
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <string.h>
94 #include <unistd.h>
95 #include <ifaddrs.h>
96 #include <util.h>
97 
98 #include "extern.h"
99 
100 #include "media.h"
101 #include "parse.h"
102 #include "env.h"
103 #include "prog_ops.h"
104 
105 #define WAIT_DAD    10000000 /* nanoseconds between each poll, 10ms */
106 
107 static bool bflag, dflag, hflag, sflag, uflag, Wflag, wflag;
108 bool lflag, Nflag, vflag, zflag;
109 static long wflag_secs, Wflag_secs;
110 
111 static char gflags[10 + 26 * 2 + 1] = "AabCdhlNsuvW:w:z";
112 bool gflagset[10 + 26 * 2];
113 
114 static int link_state(prop_dictionary_t);
115 static const char *link_state_str(int);
116 static int carrier(prop_dictionary_t);
117 static int clone_command(prop_dictionary_t, prop_dictionary_t);
118 static void do_setifpreference(prop_dictionary_t);
119 static int flag_index(int);
120 static void init_afs(void);
121 static int list_cloners(prop_dictionary_t, prop_dictionary_t);
122 static int media_status_exec(prop_dictionary_t, prop_dictionary_t);
123 static int wait_dad_exec(prop_dictionary_t, prop_dictionary_t);
124 static int no_cmds_exec(prop_dictionary_t, prop_dictionary_t);
125 static int notrailers(prop_dictionary_t, prop_dictionary_t);
126 static void printall(const char *, prop_dictionary_t);
127 static int setifaddr(prop_dictionary_t, prop_dictionary_t);
128 static int setifbroadaddr(prop_dictionary_t, prop_dictionary_t);
129 static int setifcaps(prop_dictionary_t, prop_dictionary_t);
130 static int setifdstormask(prop_dictionary_t, prop_dictionary_t);
131 static int setifflags(prop_dictionary_t, prop_dictionary_t);
132 static int setifmetric(prop_dictionary_t, prop_dictionary_t);
133 static int setifmtu(prop_dictionary_t, prop_dictionary_t);
134 static int setifnetmask(prop_dictionary_t, prop_dictionary_t);
135 static int setifprefixlen(prop_dictionary_t, prop_dictionary_t);
136 static int setlinkstr(prop_dictionary_t, prop_dictionary_t);
137 static int unsetlinkstr(prop_dictionary_t, prop_dictionary_t);
138 static int setifdescr(prop_dictionary_t, prop_dictionary_t);
139 static int unsetifdescr(prop_dictionary_t, prop_dictionary_t);
140 static void status(prop_dictionary_t, prop_dictionary_t);
141 __dead static void usage(void);
142 
143 static const struct kwinst ifflagskw[] = {
144             IFKW("arp", -IFF_NOARP)
145           , IFKW("debug", IFF_DEBUG)
146           , IFKW("unnumbered", IFF_UNNUMBERED)
147           , IFKW("link0", IFF_LINK0)
148           , IFKW("link1", IFF_LINK1)
149           , IFKW("link2", IFF_LINK2)
150           , {.k_word = "down", .k_type = KW_T_INT, .k_int = -IFF_UP}
151           , {.k_word = "up", .k_type = KW_T_INT, .k_int = IFF_UP}
152 };
153 
154 static const struct kwinst ifcapskw[] = {
155             IFKW("ip4csum-tx",          IFCAP_CSUM_IPv4_Tx)
156           , IFKW("ip4csum-rx",          IFCAP_CSUM_IPv4_Rx)
157           , IFKW("tcp4csum-tx",         IFCAP_CSUM_TCPv4_Tx)
158           , IFKW("tcp4csum-rx",         IFCAP_CSUM_TCPv4_Rx)
159           , IFKW("udp4csum-tx",         IFCAP_CSUM_UDPv4_Tx)
160           , IFKW("udp4csum-rx",         IFCAP_CSUM_UDPv4_Rx)
161           , IFKW("tcp6csum-tx",         IFCAP_CSUM_TCPv6_Tx)
162           , IFKW("tcp6csum-rx",         IFCAP_CSUM_TCPv6_Rx)
163           , IFKW("udp6csum-tx",         IFCAP_CSUM_UDPv6_Tx)
164           , IFKW("udp6csum-rx",         IFCAP_CSUM_UDPv6_Rx)
165           , IFKW("ip4csum",   IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx)
166           , IFKW("tcp4csum",  IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx)
167           , IFKW("udp4csum",  IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx)
168           , IFKW("tcp6csum",  IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx)
169           , IFKW("udp6csum",  IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx)
170           , IFKW("tso4",                IFCAP_TSOv4)
171           , IFKW("tso6",                IFCAP_TSOv6)
172 };
173 
174 extern struct pbranch command_root;
175 extern struct pbranch opt_command;
176 extern struct pbranch opt_family, opt_silent_family;
177 extern struct pkw cloning, silent_family, family, ifcaps, ifflags, misc;
178 extern struct pstr parse_linkstr;
179 
180 struct pinteger parse_metric = PINTEGER_INITIALIZER(&parse_metric, "metric", 10,
181     setifmetric, "metric", &command_root.pb_parser);
182 
183 struct pinteger parse_mtu = PINTEGER_INITIALIZER(&parse_mtu, "mtu", 10,
184     setifmtu, "mtu", &command_root.pb_parser);
185 
186 struct pinteger parse_prefixlen = PINTEGER_INITIALIZER(&parse_prefixlen,
187     "prefixlen", 10, setifprefixlen, "prefixlen", &command_root.pb_parser);
188 
189 struct pinteger parse_preference = PINTEGER_INITIALIZER1(&parse_preference,
190     "preference", INT16_MIN, INT16_MAX, 10, NULL, "preference",
191     &command_root.pb_parser);
192 
193 struct paddr parse_netmask = PADDR_INITIALIZER(&parse_netmask, "netmask",
194     setifnetmask, "dstormask", NULL, NULL, NULL, &command_root.pb_parser);
195 
196 struct paddr parse_broadcast = PADDR_INITIALIZER(&parse_broadcast,
197     "broadcast address",
198     setifbroadaddr, "broadcast", NULL, NULL, NULL, &command_root.pb_parser);
199 
200 struct pstr parse_descr = PSTR_INITIALIZER1(&parse_descr, "descr",
201     setifdescr, "descr", false, &command_root.pb_parser);
202 
203 static const struct kwinst misckw[] = {
204             {.k_word = "alias", .k_key = "alias", .k_deact = "alias",
205              .k_type = KW_T_BOOL, .k_neg = true,
206              .k_bool = true, .k_negbool = false,
207              .k_nextparser = &command_root.pb_parser}
208           , {.k_word = "broadcast", .k_nextparser = &parse_broadcast.pa_parser}
209           , {.k_word = "delete", .k_key = "alias", .k_deact = "alias",
210              .k_type = KW_T_BOOL, .k_bool = false,
211              .k_nextparser = &command_root.pb_parser}
212           , {.k_word = "metric", .k_nextparser = &parse_metric.pi_parser}
213           , {.k_word = "mtu", .k_nextparser = &parse_mtu.pi_parser}
214           , {.k_word = "netmask", .k_nextparser = &parse_netmask.pa_parser}
215           , {.k_word = "preference", .k_act = "address",
216              .k_nextparser = &parse_preference.pi_parser}
217           , {.k_word = "prefixlen", .k_nextparser = &parse_prefixlen.pi_parser}
218           , {.k_word = "trailers", .k_neg = true,
219              .k_exec = notrailers, .k_nextparser = &command_root.pb_parser}
220           , {.k_word = "linkstr", .k_nextparser = &parse_linkstr.ps_parser }
221           , {.k_word = "-linkstr", .k_exec = unsetlinkstr,
222              .k_nextparser = &command_root.pb_parser }
223           , {.k_word = "descr", .k_nextparser = &parse_descr.ps_parser}
224           , {.k_word = "description", .k_nextparser = &parse_descr.ps_parser}
225           , {.k_word = "-descr", .k_exec = unsetifdescr,
226              .k_nextparser = &command_root.pb_parser}
227           , {.k_word = "-description", .k_exec = unsetifdescr,
228              .k_nextparser = &command_root.pb_parser}
229 };
230 
231 /* key: clonecmd */
232 static const struct kwinst clonekw[] = {
233           {.k_word = "create", .k_type = KW_T_INT, .k_int = SIOCIFCREATE,
234            .k_nextparser = &opt_silent_family.pb_parser},
235           {.k_word = "destroy", .k_type = KW_T_INT, .k_int = SIOCIFDESTROY}
236 };
237 
238 static struct kwinst familykw[24];
239 
240 struct pterm cloneterm = PTERM_INITIALIZER(&cloneterm, "list cloners",
241     list_cloners, "none");
242 
243 struct pterm wait_dad = PTERM_INITIALIZER(&wait_dad, "wait DAD", wait_dad_exec,
244     "none");
245 
246 struct pterm no_cmds = PTERM_INITIALIZER(&no_cmds, "no commands", no_cmds_exec,
247     "none");
248 
249 struct pkw family_only =
250     PKW_INITIALIZER(&family_only, "family-only", NULL, "af", familykw,
251           __arraycount(familykw), &no_cmds.pt_parser);
252 
253 struct paddr address = PADDR_INITIALIZER(&address,
254     "local address (address 1)",
255     setifaddr, "address", "netmask", NULL, "address", &command_root.pb_parser);
256 
257 struct paddr dstormask = PADDR_INITIALIZER(&dstormask,
258     "destination/netmask (address 2)",
259     setifdstormask, "dstormask", NULL, "address", "dstormask",
260     &command_root.pb_parser);
261 
262 struct paddr broadcast = PADDR_INITIALIZER(&broadcast,
263     "broadcast address (address 3)",
264     setifbroadaddr, "broadcast", NULL, "dstormask", "broadcast",
265     &command_root.pb_parser);
266 
267 struct pstr parse_linkstr = PSTR_INITIALIZER(&parse_linkstr, "linkstr",
268     setlinkstr, "linkstr", &command_root.pb_parser);
269 
270 static SIMPLEQ_HEAD(, afswtch) aflist = SIMPLEQ_HEAD_INITIALIZER(aflist);
271 
272 static SIMPLEQ_HEAD(, usage_func) usage_funcs =
273     SIMPLEQ_HEAD_INITIALIZER(usage_funcs);
274 static SIMPLEQ_HEAD(, status_func) status_funcs =
275     SIMPLEQ_HEAD_INITIALIZER(status_funcs);
276 static SIMPLEQ_HEAD(, statistics_func) statistics_funcs =
277     SIMPLEQ_HEAD_INITIALIZER(statistics_funcs);
278 static SIMPLEQ_HEAD(, cmdloop_branch) cmdloop_branches =
279     SIMPLEQ_HEAD_INITIALIZER(cmdloop_branches);
280 
281 struct branch opt_clone_brs[] = {
282             {.b_nextparser = &cloning.pk_parser}
283           , {.b_nextparser = &opt_family.pb_parser}
284 }, opt_silent_family_brs[] = {
285             {.b_nextparser = &silent_family.pk_parser}
286           , {.b_nextparser = &command_root.pb_parser}
287 }, opt_family_brs[] = {
288             {.b_nextparser = &family.pk_parser}
289           , {.b_nextparser = &opt_command.pb_parser}
290 }, command_root_brs[] = {
291             {.b_nextparser = &ifflags.pk_parser}
292           , {.b_nextparser = &ifcaps.pk_parser}
293           , {.b_nextparser = &kwmedia.pk_parser}
294           , {.b_nextparser = &misc.pk_parser}
295           , {.b_nextparser = &address.pa_parser}
296           , {.b_nextparser = &dstormask.pa_parser}
297           , {.b_nextparser = &broadcast.pa_parser}
298           , {.b_nextparser = NULL}
299 }, opt_command_brs[] = {
300             {.b_nextparser = &no_cmds.pt_parser}
301           , {.b_nextparser = &command_root.pb_parser}
302 };
303 
304 struct branch opt_family_only_brs[] = {
305             {.b_nextparser = &no_cmds.pt_parser}
306           , {.b_nextparser = &family_only.pk_parser}
307 };
308 struct pbranch opt_family_only = PBRANCH_INITIALIZER(&opt_family_only,
309     "opt-family-only", opt_family_only_brs,
310     __arraycount(opt_family_only_brs), true);
311 struct pbranch opt_command = PBRANCH_INITIALIZER(&opt_command,
312     "optional command",
313     opt_command_brs, __arraycount(opt_command_brs), true);
314 
315 struct pbranch command_root = PBRANCH_INITIALIZER(&command_root,
316     "command-root", command_root_brs, __arraycount(command_root_brs), true);
317 
318 struct piface iface_opt_family_only =
319     PIFACE_INITIALIZER(&iface_opt_family_only, "iface-opt-family-only",
320     NULL, "if", &opt_family_only.pb_parser);
321 
322 struct pkw family = PKW_INITIALIZER(&family, "family", NULL, "af",
323     familykw, __arraycount(familykw), &opt_command.pb_parser);
324 
325 struct pkw silent_family = PKW_INITIALIZER(&silent_family, "silent family",
326     NULL, "af", familykw, __arraycount(familykw), &command_root.pb_parser);
327 
328 struct pkw *family_users[] = {&family_only, &family, &silent_family};
329 
330 struct pkw ifcaps = PKW_INITIALIZER(&ifcaps, "ifcaps", setifcaps,
331     "ifcap", ifcapskw, __arraycount(ifcapskw), &command_root.pb_parser);
332 
333 struct pkw ifflags = PKW_INITIALIZER(&ifflags, "ifflags", setifflags,
334     "ifflag", ifflagskw, __arraycount(ifflagskw), &command_root.pb_parser);
335 
336 struct pkw cloning = PKW_INITIALIZER(&cloning, "cloning", clone_command,
337     "clonecmd", clonekw, __arraycount(clonekw), NULL);
338 
339 struct pkw misc = PKW_INITIALIZER(&misc, "misc", NULL, NULL,
340     misckw, __arraycount(misckw), NULL);
341 
342 struct pbranch opt_clone = PBRANCH_INITIALIZER(&opt_clone,
343     "opt-clone", opt_clone_brs, __arraycount(opt_clone_brs), true);
344 
345 struct pbranch opt_silent_family = PBRANCH_INITIALIZER(&opt_silent_family,
346     "optional silent family", opt_silent_family_brs,
347     __arraycount(opt_silent_family_brs), true);
348 
349 struct pbranch opt_family = PBRANCH_INITIALIZER(&opt_family,
350     "opt-family", opt_family_brs, __arraycount(opt_family_brs), true);
351 
352 struct piface iface_start = PIFACE_INITIALIZER(&iface_start,
353     "iface-opt-family", NULL, "if", &opt_clone.pb_parser);
354 
355 struct piface iface_only = PIFACE_INITIALIZER(&iface_only, "iface",
356     media_status_exec, "if", NULL);
357 
358 static bool
flag_is_registered(const char * flags,int flag)359 flag_is_registered(const char *flags, int flag)
360 {
361           return flags != NULL && strchr(flags, flag) != NULL;
362 }
363 
364 static int
check_flag(const char * flags,int flag)365 check_flag(const char *flags, int flag)
366 {
367           if (flag_is_registered(flags, flag)) {
368                     errno = EEXIST;
369                     return -1;
370           }
371 
372           if (flag >= '0' && flag <= '9')
373                     return 0;
374           if (flag >= 'a' && flag <= 'z')
375                     return 0;
376           if (flag >= 'A' && flag <= 'Z')
377                     return 0;
378 
379           errno = EINVAL;
380           return -1;
381 }
382 
383 void
cmdloop_branch_init(cmdloop_branch_t * b,struct parser * p)384 cmdloop_branch_init(cmdloop_branch_t *b, struct parser *p)
385 {
386           b->b_parser = p;
387 }
388 
389 void
statistics_func_init(statistics_func_t * f,statistics_cb_t func)390 statistics_func_init(statistics_func_t *f, statistics_cb_t func)
391 {
392           f->f_func = func;
393 }
394 
395 void
status_func_init(status_func_t * f,status_cb_t func)396 status_func_init(status_func_t *f, status_cb_t func)
397 {
398           f->f_func = func;
399 }
400 
401 void
usage_func_init(usage_func_t * f,usage_cb_t func)402 usage_func_init(usage_func_t *f, usage_cb_t func)
403 {
404           f->f_func = func;
405 }
406 
407 int
register_cmdloop_branch(cmdloop_branch_t * b)408 register_cmdloop_branch(cmdloop_branch_t *b)
409 {
410           SIMPLEQ_INSERT_TAIL(&cmdloop_branches, b, b_next);
411           return 0;
412 }
413 
414 int
register_statistics(statistics_func_t * f)415 register_statistics(statistics_func_t *f)
416 {
417           SIMPLEQ_INSERT_TAIL(&statistics_funcs, f, f_next);
418           return 0;
419 }
420 
421 int
register_status(status_func_t * f)422 register_status(status_func_t *f)
423 {
424           SIMPLEQ_INSERT_TAIL(&status_funcs, f, f_next);
425           return 0;
426 }
427 
428 int
register_usage(usage_func_t * f)429 register_usage(usage_func_t *f)
430 {
431           SIMPLEQ_INSERT_TAIL(&usage_funcs, f, f_next);
432           return 0;
433 }
434 
435 int
register_family(struct afswtch * af)436 register_family(struct afswtch *af)
437 {
438           SIMPLEQ_INSERT_TAIL(&aflist, af, af_next);
439           return 0;
440 }
441 
442 int
register_flag(int flag)443 register_flag(int flag)
444 {
445           if (check_flag(gflags, flag) == -1)
446                     return -1;
447 
448           if (strlen(gflags) + 1 >= sizeof(gflags)) {
449                     errno = ENOMEM;
450                     return -1;
451           }
452 
453           gflags[strlen(gflags)] = flag;
454 
455           return 0;
456 }
457 
458 static int
flag_index(int flag)459 flag_index(int flag)
460 {
461           if (flag >= '0' && flag <= '9')
462                     return flag - '0';
463           if (flag >= 'a' && flag <= 'z')
464                     return 10 + flag - 'a';
465           if (flag >= 'A' && flag <= 'Z')
466                     return 10 + 26 + flag - 'a';
467 
468           errno = EINVAL;
469           return -1;
470 }
471 
472 static bool
set_flag(int flag)473 set_flag(int flag)
474 {
475           int idx;
476 
477           if ((idx = flag_index(flag)) == -1)
478                     return false;
479 
480           return gflagset[idx] = true;
481 }
482 
483 bool
get_flag(int flag)484 get_flag(int flag)
485 {
486           int idx;
487 
488           if ((idx = flag_index(flag)) == -1)
489                     return false;
490 
491           return gflagset[idx];
492 }
493 
494 static struct parser *
init_parser(void)495 init_parser(void)
496 {
497           cmdloop_branch_t *b;
498 
499           if (parser_init(&iface_opt_family_only.pif_parser) == -1)
500                     err(EXIT_FAILURE, "parser_init(iface_opt_family_only)");
501           if (parser_init(&iface_only.pif_parser) == -1)
502                     err(EXIT_FAILURE, "parser_init(iface_only)");
503           if (parser_init(&iface_start.pif_parser) == -1)
504                     err(EXIT_FAILURE, "parser_init(iface_start)");
505 
506           SIMPLEQ_FOREACH(b, &cmdloop_branches, b_next)
507                     pbranch_addbranch(&command_root, b->b_parser);
508 
509           return &iface_start.pif_parser;
510 }
511 
512 static int
no_cmds_exec(prop_dictionary_t env,prop_dictionary_t oenv)513 no_cmds_exec(prop_dictionary_t env, prop_dictionary_t oenv)
514 {
515           const char *ifname;
516           unsigned short ignore;
517 
518           /* ifname == NULL is ok.  It indicates 'ifconfig -a'. */
519           if ((ifname = getifname(env)) == NULL)
520                     ;
521           else if (getifflags(env, oenv, &ignore) == -1)
522                     err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname);
523 
524           printall(ifname, env);
525           exit(EXIT_SUCCESS);
526 }
527 
528 static int
wait_dad_exec(prop_dictionary_t env,prop_dictionary_t oenv)529 wait_dad_exec(prop_dictionary_t env, prop_dictionary_t oenv)
530 {
531           bool waiting;
532           struct ifaddrs *ifaddrs, *ifa;
533           const struct timespec ts = { .tv_sec = 0, .tv_nsec = WAIT_DAD };
534           struct timespec now, end_det, end;
535           const struct afswtch *afp;
536 
537           if (wflag_secs) {
538                     const struct timespec tent =
539                         { .tv_sec = wflag_secs, .tv_nsec = 0};
540                     const struct timespec det =
541                         { .tv_sec = Wflag_secs, .tv_nsec = 0};
542 
543                     if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
544                               err(EXIT_FAILURE, "clock_gettime");
545                     timespecadd(&now, &tent, &end);
546                     if (Wflag_secs)
547                               timespecadd(&now, &det, &end_det);
548                     else
549                               timespecclear(&end_det);
550           } else {
551                     timespecclear(&end_det);
552                     timespecclear(&end);
553           }
554 
555           if (getifaddrs(&ifaddrs) == -1)
556                     err(EXIT_FAILURE, "getifaddrs");
557 
558           for (;;) {
559                     waiting = false;
560                     for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
561                               if (ifa->ifa_addr == NULL)
562                                         continue;
563                               afp = lookup_af_bynum(ifa->ifa_addr->sa_family);
564                               if (afp &&
565                                   ((afp->af_addr_tentative_or_detached &&
566                                   ifa->ifa_flags & IFF_UP &&
567                                   timespecisset(&end_det) &&
568                                   timespeccmp(&now, &end_det, <) &&
569                                   afp->af_addr_tentative_or_detached(ifa)) ||
570                                   (afp->af_addr_tentative &&
571                                   afp->af_addr_tentative(ifa))))
572                               {
573                                         waiting = true;
574                                         break;
575                               }
576                     }
577                     if (!waiting)
578                               break;
579                     nanosleep(&ts, NULL);
580                     if (wflag_secs) {
581                               if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
582                                         err(EXIT_FAILURE, "clock_gettime");
583                               if (timespeccmp(&now, &end, >))
584                                         errx(EXIT_FAILURE, "timed out");
585                     }
586           }
587 
588           freeifaddrs(ifaddrs);
589           exit(EXIT_SUCCESS);
590 }
591 
592 static int
media_status_exec(prop_dictionary_t env,prop_dictionary_t oenv)593 media_status_exec(prop_dictionary_t env, prop_dictionary_t oenv)
594 {
595           const char *ifname;
596           unsigned short ignore;
597 
598           /* ifname == NULL is ok.  It indicates 'ifconfig -a'. */
599           if ((ifname = getifname(env)) == NULL)
600                     ;
601           else if (getifflags(env, oenv, &ignore) == -1)
602                     err(EXIT_FAILURE, "SIOCGIFFLAGS %s", ifname);
603 
604           exit(carrier(env));
605 }
606 
607 static void
do_setifcaps(prop_dictionary_t env)608 do_setifcaps(prop_dictionary_t env)
609 {
610           struct ifcapreq ifcr;
611           prop_data_t d;
612 
613           d = (prop_data_t )prop_dictionary_get(env, "ifcaps");
614           if (d == NULL)
615                     return;
616 
617           assert(sizeof(ifcr) == prop_data_size(d));
618 
619           memcpy(&ifcr, prop_data_value(d), sizeof(ifcr));
620           if (direct_ioctl(env, SIOCSIFCAP, &ifcr) == -1)
621                     err(EXIT_FAILURE, "SIOCSIFCAP");
622 }
623 
624 int
main(int argc,char ** argv)625 main(int argc, char **argv)
626 {
627           const struct afswtch *afp;
628           int af, s, e;
629           bool aflag = false, Cflag = false;
630           struct match match[32];
631           size_t nmatch;
632           struct parser *start;
633           int ch, narg = 0, rc;
634           prop_dictionary_t env, oenv;
635           const char *ifname;
636 
637           memset(match, 0, sizeof(match));
638 
639           init_afs();
640 
641           start = init_parser();
642 
643           /* Parse command-line options */
644           Nflag = vflag = zflag = false;
645           aflag = argc == 1 ? true : false;
646           if (aflag)
647                     start = &opt_family_only.pb_parser;
648 
649           while ((ch = getopt(argc, argv, gflags)) != -1) {
650                     switch (ch) {
651                     case 'A':
652                               warnx("-A is deprecated");
653                               break;
654 
655                     case 'a':
656                               aflag = true;
657                               break;
658 
659                     case 'b':
660                               bflag = true;
661                               break;
662 
663                     case 'C':
664                               Cflag = true;
665                               break;
666 
667                     case 'd':
668                               dflag = true;
669                               break;
670                     case 'h':
671                               hflag = true;
672                               break;
673                     case 'l':
674                               lflag = true;
675                               break;
676                     case 'N':
677                               Nflag = true;
678                               break;
679 
680                     case 's':
681                               sflag = true;
682                               break;
683 
684                     case 'u':
685                               uflag = true;
686                               break;
687 
688                     case 'v':
689                               vflag = true;
690                               break;
691 
692                     case 'w':
693                               wflag = true;
694                               wflag_secs = strtoi(optarg, NULL, 10, 0, INT32_MAX, &e);
695                               if (e)
696                                         errx(EXIT_FAILURE, "%s: not a number", optarg);
697                               break;
698 
699                     case 'W':
700                               Wflag = true;
701                               Wflag_secs = strtoi(optarg, NULL, 10, 0, INT32_MAX, &e);
702                               if (e)
703                                         errx(EXIT_FAILURE, "%s: not a number", optarg);
704                               break;
705 
706                     case 'z':
707                               zflag = true;
708                               break;
709 
710                     default:
711                               if (!set_flag(ch))
712                                         usage();
713                               break;
714                     }
715                     switch (ch) {
716                     case 'a':
717                               start = &opt_family_only.pb_parser;
718                               break;
719 
720                     case 'L':
721                     case 'm':
722                     case 'z':
723                               if (start != &opt_family_only.pb_parser)
724                                         start = &iface_opt_family_only.pif_parser;
725                               break;
726                     case 'C':
727                               start = &cloneterm.pt_parser;
728                               break;
729                     case 'l':
730                               start = &no_cmds.pt_parser;
731                               break;
732                     case 's':
733                               if (start != &no_cmds.pt_parser &&
734                                   start != &opt_family_only.pb_parser)
735                                         start = &iface_only.pif_parser;
736                               break;
737                     case 'w':
738                               start = &wait_dad.pt_parser;
739                               break;
740                     default:
741                               break;
742                     }
743           }
744           argc -= optind;
745           argv += optind;
746 
747           /*
748            * -l means "list all interfaces", and is mutually exclusive with
749            * all other flags/commands.
750            *
751            * -C means "list all names of cloners", and it mutually exclusive
752            * with all other flags/commands.
753            *
754            * -a means "print status of all interfaces".
755            *
756            * -w means "spin until DAD completes for all addresses", and is
757            * mutually exclusive with all other flags/commands.
758            */
759           if ((lflag || Cflag || wflag) &&
760               (aflag || get_flag('m') || vflag || zflag))
761                     usage();
762           if ((lflag || Cflag || wflag) && get_flag('L'))
763                     usage();
764           if ((lflag && Cflag) || (lflag & wflag) || (Cflag && wflag))
765                     usage();
766 
767           nmatch = __arraycount(match);
768 
769           rc = parse(argc, argv, start, match, &nmatch, &narg);
770           if (rc != 0)
771                     usage();
772 
773           if (prog_init && prog_init() == -1)
774                     err(1, "rump client init");
775 
776           if ((oenv = prop_dictionary_create()) == NULL)
777                     err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__);
778 
779           if (matches_exec(match, oenv, nmatch) == -1)
780                     err(EXIT_FAILURE, "exec_matches");
781 
782           argc -= narg;
783           argv += narg;
784 
785           env = (nmatch > 0) ? match[(int)nmatch - 1].m_env : NULL;
786           if (env == NULL)
787                     env = oenv;
788           else {
789                     env = prop_dictionary_augment(env, oenv);
790                     if (env == NULL)
791                               err(EXIT_FAILURE, "%s: prop_dictionary_augment",
792                                   __func__);
793           }
794 
795           /* Process any media commands that may have been issued. */
796           process_media_commands(env);
797 
798           if ((af = getaf(env)) == -1)
799                     af = AF_INET;
800 
801           if ((s = getsock(af)) == -1)
802                     err(EXIT_FAILURE, "%s: getsock", __func__);
803 
804           if ((ifname = getifname(env)) == NULL)
805                     err(EXIT_FAILURE, "%s: getifname", __func__);
806 
807           if ((afp = lookup_af_bynum(af)) == NULL)
808                     errx(EXIT_FAILURE, "%s: lookup_af_bynum", __func__);
809 
810           assert(afp->af_addr_commit != NULL);
811           (*afp->af_addr_commit)(env, oenv);
812 
813           do_setifpreference(env);
814           do_setifcaps(env);
815           do_setethercaps(env);
816 
817           exit(EXIT_SUCCESS);
818 }
819 
820 static void
init_afs(void)821 init_afs(void)
822 {
823           size_t i;
824           const struct afswtch *afp;
825           struct kwinst kw = {.k_type = KW_T_INT};
826 
827           SIMPLEQ_FOREACH(afp, &aflist, af_next) {
828                     kw.k_word = afp->af_name;
829                     kw.k_int = afp->af_af;
830                     for (i = 0; i < __arraycount(familykw); i++) {
831                               if (familykw[i].k_word == NULL) {
832                                         familykw[i] = kw;
833                                         break;
834                               }
835                     }
836           }
837 }
838 
839 const struct afswtch *
lookup_af_bynum(int afnum)840 lookup_af_bynum(int afnum)
841 {
842           const struct afswtch *afp;
843 
844           SIMPLEQ_FOREACH(afp, &aflist, af_next) {
845                     if (afp->af_af == afnum)
846                               break;
847           }
848           return afp;
849 }
850 
851 void
printall(const char * ifname,prop_dictionary_t env0)852 printall(const char *ifname, prop_dictionary_t env0)
853 {
854           struct ifaddrs *ifap, *ifa;
855           prop_dictionary_t env, oenv;
856           int idx;
857           char *p;
858 
859           if (env0 == NULL)
860                     env = prop_dictionary_create();
861           else
862                     env = prop_dictionary_copy_mutable(env0);
863 
864           oenv = prop_dictionary_create();
865 
866           if (env == NULL || oenv == NULL)
867                     errx(EXIT_FAILURE, "%s: prop_dictionary_copy/create", __func__);
868 
869           if (getifaddrs(&ifap) != 0)
870                     err(EXIT_FAILURE, "getifaddrs");
871           p = NULL;
872           idx = 0;
873           for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
874                     if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
875                               continue;
876                     if (p && strcmp(p, ifa->ifa_name) == 0)
877                               continue;
878                     if (!prop_dictionary_set_string(env, "if", ifa->ifa_name))
879                               continue;
880                     p = ifa->ifa_name;
881 
882                     if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0)
883                               continue;
884                     if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
885                               continue;
886                     if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
887                               continue;
888 
889                     if (sflag && link_state(env) == LINK_STATE_DOWN)
890                               continue;
891                     idx++;
892                     /*
893                      * Are we just listing the interfaces?
894                      */
895                     if (lflag) {
896                               if (idx > 1)
897                                         printf(" ");
898                               fputs(ifa->ifa_name, stdout);
899                               continue;
900                     }
901 
902                     status(env, oenv);
903           }
904           if (lflag)
905                     printf("\n");
906           prop_object_release((prop_object_t)env);
907           prop_object_release((prop_object_t)oenv);
908           freeifaddrs(ifap);
909 }
910 
911 static int
list_cloners(prop_dictionary_t env,prop_dictionary_t oenv)912 list_cloners(prop_dictionary_t env, prop_dictionary_t oenv)
913 {
914           struct if_clonereq ifcr;
915           char *cp, *buf;
916           int idx, s;
917 
918           memset(&ifcr, 0, sizeof(ifcr));
919 
920           s = getsock(AF_INET);
921 
922           if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
923                     err(EXIT_FAILURE, "SIOCIFGCLONERS for count");
924 
925           buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
926           if (buf == NULL)
927                     err(EXIT_FAILURE, "unable to allocate cloner name buffer");
928 
929           ifcr.ifcr_count = ifcr.ifcr_total;
930           ifcr.ifcr_buffer = buf;
931 
932           if (prog_ioctl(s, SIOCIFGCLONERS, &ifcr) == -1)
933                     err(EXIT_FAILURE, "SIOCIFGCLONERS for names");
934 
935           /*
936            * In case some disappeared in the mean time, clamp it down.
937            */
938           if (ifcr.ifcr_count > ifcr.ifcr_total)
939                     ifcr.ifcr_count = ifcr.ifcr_total;
940 
941           for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
942                     if (idx > 0)
943                               printf(" ");
944                     printf("%s", cp);
945           }
946 
947           printf("\n");
948           free(buf);
949           exit(EXIT_SUCCESS);
950 }
951 
952 static int
clone_command(prop_dictionary_t env,prop_dictionary_t oenv)953 clone_command(prop_dictionary_t env, prop_dictionary_t oenv)
954 {
955           int64_t cmd;
956 
957           if (!prop_dictionary_get_int64(env, "clonecmd", &cmd)) {
958                     errno = ENOENT;
959                     return -1;
960           }
961 
962           if (indirect_ioctl(env, (unsigned long)cmd, NULL) == -1) {
963                     warn("%s", __func__);
964                     return -1;
965           }
966           return 0;
967 }
968 
969 /*ARGSUSED*/
970 static int
setifaddr(prop_dictionary_t env,prop_dictionary_t oenv)971 setifaddr(prop_dictionary_t env, prop_dictionary_t oenv)
972 {
973           const struct paddr_prefix *pfx0;
974           struct paddr_prefix *pfx;
975           prop_data_t d;
976           int af;
977 
978           if ((af = getaf(env)) == -1)
979                     af = AF_INET;
980 
981           d = (prop_data_t)prop_dictionary_get(env, "address");
982           assert(d != NULL);
983           pfx0 = prop_data_value(d);
984 
985           if (pfx0->pfx_len >= 0) {
986                     pfx = prefixlen_to_mask(af, pfx0->pfx_len);
987                     if (pfx == NULL)
988                               err(EXIT_FAILURE, "prefixlen_to_mask");
989                     free(pfx);
990           }
991 
992           return 0;
993 }
994 
995 static int
setifnetmask(prop_dictionary_t env,prop_dictionary_t oenv)996 setifnetmask(prop_dictionary_t env, prop_dictionary_t oenv)
997 {
998           prop_data_t d;
999 
1000           d = (prop_data_t)prop_dictionary_get(env, "dstormask");
1001           assert(d != NULL);
1002 
1003           if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d))
1004                     return -1;
1005 
1006           return 0;
1007 }
1008 
1009 static int
setifbroadaddr(prop_dictionary_t env,prop_dictionary_t oenv)1010 setifbroadaddr(prop_dictionary_t env, prop_dictionary_t oenv)
1011 {
1012           prop_data_t d;
1013           unsigned short flags;
1014 
1015           if (getifflags(env, oenv, &flags) == -1)
1016                     err(EXIT_FAILURE, "%s: getifflags", __func__);
1017 
1018           if ((flags & IFF_BROADCAST) == 0)
1019                     errx(EXIT_FAILURE, "not a broadcast interface");
1020 
1021           d = (prop_data_t)prop_dictionary_get(env, "broadcast");
1022           assert(d != NULL);
1023 
1024           if (!prop_dictionary_set(oenv, "broadcast", (prop_object_t)d))
1025                     return -1;
1026 
1027           return 0;
1028 }
1029 
1030 /*ARGSUSED*/
1031 static int
notrailers(prop_dictionary_t env,prop_dictionary_t oenv)1032 notrailers(prop_dictionary_t env, prop_dictionary_t oenv)
1033 {
1034           puts("Note: trailers are no longer sent, but always received");
1035           return 0;
1036 }
1037 
1038 /*ARGSUSED*/
1039 static int
setifdstormask(prop_dictionary_t env,prop_dictionary_t oenv)1040 setifdstormask(prop_dictionary_t env, prop_dictionary_t oenv)
1041 {
1042           const char *key;
1043           prop_data_t d;
1044           unsigned short flags;
1045 
1046           if (getifflags(env, oenv, &flags) == -1)
1047                     err(EXIT_FAILURE, "%s: getifflags", __func__);
1048 
1049           d = (prop_data_t)prop_dictionary_get(env, "dstormask");
1050           assert(d != NULL);
1051 
1052           if ((flags & IFF_BROADCAST) == 0) {
1053                     key = "dst";
1054           } else {
1055                     key = "netmask";
1056           }
1057 
1058           if (!prop_dictionary_set(oenv, key, (prop_object_t)d))
1059                     return -1;
1060 
1061           return 0;
1062 }
1063 
1064 static int
setifflags(prop_dictionary_t env,prop_dictionary_t oenv)1065 setifflags(prop_dictionary_t env, prop_dictionary_t oenv)
1066 {
1067           struct ifreq ifr;
1068           int64_t ifflag;
1069           bool rc;
1070 
1071           rc = prop_dictionary_get_int64(env, "ifflag", &ifflag);
1072           assert(rc);
1073 
1074           if (direct_ioctl(env, SIOCGIFFLAGS, &ifr) == -1)
1075                     return -1;
1076 
1077           if (ifflag < 0) {
1078                     ifflag = -ifflag;
1079                     ifr.ifr_flags &= ~ifflag;
1080           } else
1081                     ifr.ifr_flags |= ifflag;
1082 
1083           if (direct_ioctl(env, SIOCSIFFLAGS, &ifr) == -1)
1084                     return -1;
1085 
1086           return 0;
1087 }
1088 
1089 static int
getifcaps(prop_dictionary_t env,prop_dictionary_t oenv,struct ifcapreq * oifcr)1090 getifcaps(prop_dictionary_t env, prop_dictionary_t oenv, struct ifcapreq *oifcr)
1091 {
1092           bool rc;
1093           struct ifcapreq ifcr;
1094           const struct ifcapreq *tmpifcr;
1095           prop_data_t capdata;
1096 
1097           capdata = (prop_data_t)prop_dictionary_get(env, "ifcaps");
1098 
1099           if (capdata != NULL) {
1100                     tmpifcr = prop_data_value(capdata);
1101                     *oifcr = *tmpifcr;
1102                     return 0;
1103           }
1104 
1105           (void)direct_ioctl(env, SIOCGIFCAP, &ifcr);
1106           *oifcr = ifcr;
1107 
1108           capdata = prop_data_create_copy(&ifcr, sizeof(ifcr));
1109 
1110           rc = prop_dictionary_set(oenv, "ifcaps", capdata);
1111 
1112           prop_object_release((prop_object_t)capdata);
1113 
1114           return rc ? 0 : -1;
1115 }
1116 
1117 static int
setifcaps(prop_dictionary_t env,prop_dictionary_t oenv)1118 setifcaps(prop_dictionary_t env, prop_dictionary_t oenv)
1119 {
1120           int64_t ifcap;
1121           bool rc;
1122           prop_data_t capdata;
1123           struct ifcapreq ifcr;
1124 
1125           rc = prop_dictionary_get_int64(env, "ifcap", &ifcap);
1126           assert(rc);
1127 
1128           if (getifcaps(env, oenv, &ifcr) == -1)
1129                     return -1;
1130 
1131           if (ifcap < 0) {
1132                     ifcap = -ifcap;
1133                     ifcr.ifcr_capenable &= ~ifcap;
1134           } else
1135                     ifcr.ifcr_capenable |= ifcap;
1136 
1137           if ((capdata = prop_data_create_copy(&ifcr, sizeof(ifcr))) == NULL)
1138                     return -1;
1139 
1140           rc = prop_dictionary_set(oenv, "ifcaps", capdata);
1141           prop_object_release((prop_object_t)capdata);
1142 
1143           return rc ? 0 : -1;
1144 }
1145 
1146 static int
setifmetric(prop_dictionary_t env,prop_dictionary_t oenv)1147 setifmetric(prop_dictionary_t env, prop_dictionary_t oenv)
1148 {
1149           struct ifreq ifr;
1150           bool rc;
1151           int64_t metric;
1152 
1153           rc = prop_dictionary_get_int64(env, "metric", &metric);
1154           assert(rc);
1155 
1156           ifr.ifr_metric = metric;
1157           if (direct_ioctl(env, SIOCSIFMETRIC, &ifr) == -1)
1158                     warn("SIOCSIFMETRIC");
1159           return 0;
1160 }
1161 
1162 static void
do_setifpreference(prop_dictionary_t env)1163 do_setifpreference(prop_dictionary_t env)
1164 {
1165           struct if_addrprefreq ifap;
1166           prop_data_t d;
1167           const struct paddr_prefix *pfx;
1168 
1169           memset(&ifap, 0, sizeof(ifap));
1170 
1171           if (!prop_dictionary_get_int16(env, "preference",
1172               &ifap.ifap_preference))
1173                     return;
1174 
1175           d = (prop_data_t)prop_dictionary_get(env, "address");
1176           assert(d != NULL);
1177 
1178           pfx = prop_data_value(d);
1179 
1180           memcpy(&ifap.ifap_addr, &pfx->pfx_addr,
1181               MIN(sizeof(ifap.ifap_addr), pfx->pfx_addr.sa_len));
1182           if (direct_ioctl(env, SIOCSIFADDRPREF, &ifap) == -1)
1183                     warn("SIOCSIFADDRPREF");
1184 }
1185 
1186 static int
setifmtu(prop_dictionary_t env,prop_dictionary_t oenv)1187 setifmtu(prop_dictionary_t env, prop_dictionary_t oenv)
1188 {
1189           int64_t mtu;
1190           bool rc;
1191           struct ifreq ifr;
1192 
1193           rc = prop_dictionary_get_int64(env, "mtu", &mtu);
1194           assert(rc);
1195 
1196           ifr.ifr_mtu = mtu;
1197           if (direct_ioctl(env, SIOCSIFMTU, &ifr) == -1)
1198                     warn("SIOCSIFMTU");
1199 
1200           return 0;
1201 }
1202 
1203 static int
link_state(prop_dictionary_t env)1204 link_state(prop_dictionary_t env)
1205 {
1206           struct ifdatareq ifdr = { .ifdr_data.ifi_link_state = 0 };
1207 
1208           if (direct_ioctl(env, SIOCGIFDATA, &ifdr) == -1)
1209                     return -1;
1210 
1211           return ifdr.ifdr_data.ifi_link_state;
1212 }
1213 
1214 static const char *
link_state_str(int state)1215 link_state_str(int state)
1216 {
1217 
1218           switch (state) {
1219           case LINK_STATE_UNKNOWN:
1220                     return "unknown";
1221           case LINK_STATE_DOWN:
1222                     return "down";
1223           case LINK_STATE_UP:
1224                     return "up";
1225           default: /* Assume -1 */
1226                     return "error";
1227           }
1228 }
1229 
1230 static int
carrier(prop_dictionary_t env)1231 carrier(prop_dictionary_t env)
1232 {
1233           switch (link_state(env)) {
1234           case -1:
1235           case LINK_STATE_DOWN:
1236                     return EXIT_FAILURE;
1237           default:
1238                     /* Assume UP if UNKNOWN */
1239                     return EXIT_SUCCESS;
1240           }
1241 }
1242 
1243 static void
print_plural(const char * prefix,uint64_t n,const char * unit)1244 print_plural(const char *prefix, uint64_t n, const char *unit)
1245 {
1246           printf("%s%" PRIu64 " %s%s", prefix, n, unit, (n == 1) ? "" : "s");
1247 }
1248 
1249 static void
print_human_bytes(bool humanize,uint64_t n)1250 print_human_bytes(bool humanize, uint64_t n)
1251 {
1252           char buf[5];
1253 
1254           if (humanize) {
1255                     (void)humanize_number(buf, sizeof(buf),
1256                         (int64_t)n, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL);
1257                     printf(", %s byte%s", buf, (atof(buf) == 1.0) ? "" : "s");
1258           } else
1259                     print_plural(", ", n, "byte");
1260 }
1261 
1262 /*
1263  * Print the status of the interface.  If an address family was
1264  * specified, show it and it only; otherwise, show them all.
1265  */
1266 
1267 #define MAX_PRINT_LEN 58      /* XXX need a better way to determine this! */
1268 
1269 void
status(prop_dictionary_t env,prop_dictionary_t oenv)1270 status(prop_dictionary_t env, prop_dictionary_t oenv)
1271 {
1272           status_func_t *status_f;
1273           statistics_func_t *statistics_f;
1274           struct ifdatareq ifdr;
1275           struct if_data *ifi;
1276           struct ifreq ifr;
1277           struct ifdrv ifdrv;
1278           char fbuf[BUFSIZ];
1279           char *bp;
1280           int af, s;
1281           const char *ifname;
1282           struct ifcapreq ifcr;
1283           unsigned short flags;
1284           const struct afswtch *afp;
1285           char ifdescr[IFDESCRSIZE];
1286 
1287           if ((af = getaf(env)) == -1) {
1288                     afp = NULL;
1289                     af = AF_UNSPEC;
1290           } else
1291                     afp = lookup_af_bynum(af);
1292 
1293           /* get out early if the family is unsupported by the kernel */
1294           if ((s = getsock(af)) == -1)
1295                     err(EXIT_FAILURE, "%s: getsock", __func__);
1296 
1297           if ((ifname = getifinfo(env, oenv, &flags)) == NULL)
1298                     err(EXIT_FAILURE, "%s: getifinfo", __func__);
1299 
1300           (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags);
1301           printf("%s: flags=%s", ifname, fbuf);
1302 
1303           estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1304           if (prog_ioctl(s, SIOCGIFMETRIC, &ifr) == -1)
1305                     warn("SIOCGIFMETRIC %s", ifr.ifr_name);
1306           else if (ifr.ifr_metric != 0)
1307                     printf(" metric %d", ifr.ifr_metric);
1308 
1309           estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1310           if (prog_ioctl(s, SIOCGIFMTU, &ifr) != -1 && ifr.ifr_mtu != 0)
1311                     printf(" mtu %d", ifr.ifr_mtu);
1312           printf("\n");
1313 
1314           if (getifcaps(env, oenv, &ifcr) == -1)
1315                     err(EXIT_FAILURE, "%s: getifcaps", __func__);
1316 
1317           if (ifcr.ifcr_capabilities != 0) {
1318                     (void)snprintb_m(fbuf, sizeof(fbuf), IFCAPBITS,
1319                         ifcr.ifcr_capabilities, MAX_PRINT_LEN);
1320                     bp = fbuf;
1321                     while (*bp != '\0') {
1322                               printf("\tcapabilities=%s\n", bp);
1323                               bp += strlen(bp) + 1;
1324                     }
1325                     (void)snprintb_m(fbuf, sizeof(fbuf), IFCAPBITS,
1326                         ifcr.ifcr_capenable, MAX_PRINT_LEN);
1327                     bp = fbuf;
1328                     while (*bp != '\0') {
1329                               printf("\tenabled=%s\n", bp);
1330                               bp += strlen(bp) + 1;
1331                     }
1332           }
1333 
1334           SIMPLEQ_FOREACH(status_f, &status_funcs, f_next)
1335                     (*status_f->f_func)(env, oenv);
1336 
1337           estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1338           ifr.ifr_buf = &ifdescr;
1339           ifr.ifr_buflen = sizeof(ifdescr);
1340           if (prog_ioctl(s, SIOCGIFDESCR, &ifr) == 0)
1341                     printf("\tdescription: \"%s\"\n", (char *)ifr.ifr_buf);
1342 
1343           print_link_addresses(env, true);
1344 
1345           estrlcpy(ifdrv.ifd_name, ifname, sizeof(ifdrv.ifd_name));
1346           ifdrv.ifd_cmd = IFLINKSTR_QUERYLEN;
1347           ifdrv.ifd_len = 0;
1348           ifdrv.ifd_data = NULL;
1349           /* interface supports linkstr? */
1350           if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) != -1) {
1351                     char *p;
1352 
1353                     p = malloc(ifdrv.ifd_len);
1354                     if (p == NULL)
1355                               err(EXIT_FAILURE, "malloc linkstr buf failed");
1356                     ifdrv.ifd_data = p;
1357                     ifdrv.ifd_cmd = 0;
1358                     if (prog_ioctl(s, SIOCGLINKSTR, &ifdrv) == -1)
1359                               err(EXIT_FAILURE, "failed to query linkstr");
1360                     printf("\tlinkstr: %s\n", (char *)ifdrv.ifd_data);
1361                     free(p);
1362           }
1363 
1364           if (vflag)
1365                     printf("\tlinkstate: %s\n", link_state_str(link_state(env)));
1366 
1367           media_status(env, oenv);
1368 
1369           if (!vflag && !zflag)
1370                     goto proto_status;
1371 
1372           /* We already have if_data from SIOCGIFDATA in ifa_data. */
1373           estrlcpy(ifdr.ifdr_name, ifname, sizeof(ifdr.ifdr_name));
1374           if (prog_ioctl(s, zflag ? SIOCZIFDATA : SIOCGIFDATA, &ifdr) == -1)
1375                     err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA");
1376           ifi = &ifdr.ifdr_data;
1377 
1378           print_plural("\tinput: ", ifi->ifi_ipackets, "packet");
1379           print_human_bytes(hflag, ifi->ifi_ibytes);
1380           if (ifi->ifi_imcasts)
1381                     print_plural(", ", ifi->ifi_imcasts, "multicast");
1382           if (ifi->ifi_ierrors)
1383                     print_plural(", ", ifi->ifi_ierrors, "error");
1384           if (ifi->ifi_iqdrops)
1385                     print_plural(", ", ifi->ifi_iqdrops, "queue drop");
1386           if (ifi->ifi_noproto)
1387                     printf(", %" PRIu64 " unknown protocol", ifi->ifi_noproto);
1388           print_plural("\n\toutput: ", ifi->ifi_opackets, "packet");
1389           print_human_bytes(hflag, ifi->ifi_obytes);
1390           if (ifi->ifi_omcasts)
1391                     print_plural(", ", ifi->ifi_omcasts, "multicast");
1392           if (ifi->ifi_oerrors)
1393                     print_plural(", ", ifi->ifi_oerrors, "error");
1394           if (ifi->ifi_collisions)
1395                     print_plural(", ", ifi->ifi_collisions, "collision");
1396           printf("\n");
1397 
1398           SIMPLEQ_FOREACH(statistics_f, &statistics_funcs, f_next)
1399                     (*statistics_f->f_func)(env);
1400 
1401  proto_status:
1402 
1403           if (afp != NULL)
1404                     (*afp->af_status)(env, oenv, true);
1405           else SIMPLEQ_FOREACH(afp, &aflist, af_next)
1406                     (*afp->af_status)(env, oenv, false);
1407 }
1408 
1409 static int
setifprefixlen(prop_dictionary_t env,prop_dictionary_t oenv)1410 setifprefixlen(prop_dictionary_t env, prop_dictionary_t oenv)
1411 {
1412           bool rc;
1413           int64_t plen;
1414           int af;
1415           struct paddr_prefix *pfx;
1416           prop_data_t d;
1417 
1418           if ((af = getaf(env)) == -1)
1419                     af = AF_INET;
1420 
1421           rc = prop_dictionary_get_int64(env, "prefixlen", &plen);
1422           assert(rc);
1423 
1424           pfx = prefixlen_to_mask(af, plen);
1425           if (pfx == NULL)
1426                     err(EXIT_FAILURE, "prefixlen_to_mask");
1427 
1428           d = prop_data_create_copy(pfx, paddr_prefix_size(pfx));
1429           if (d == NULL)
1430                     err(EXIT_FAILURE, "%s: prop_data_create_copy", __func__);
1431 
1432           if (!prop_dictionary_set(oenv, "netmask", (prop_object_t)d))
1433                     err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
1434 
1435           free(pfx);
1436           return 0;
1437 }
1438 
1439 static int
setlinkstr(prop_dictionary_t env,prop_dictionary_t oenv)1440 setlinkstr(prop_dictionary_t env, prop_dictionary_t oenv)
1441 {
1442           struct ifdrv ifdrv;
1443           size_t linkstrlen;
1444           prop_data_t data;
1445           char *linkstr;
1446 
1447           data = (prop_data_t)prop_dictionary_get(env, "linkstr");
1448           if (data == NULL) {
1449                     errno = ENOENT;
1450                     return -1;
1451           }
1452           linkstrlen = prop_data_size(data)+1;
1453 
1454           linkstr = malloc(linkstrlen);
1455           if (linkstr == NULL)
1456                     err(EXIT_FAILURE, "malloc linkstr space");
1457           if (getargstr(env, "linkstr", linkstr, linkstrlen) == -1)
1458                     errx(EXIT_FAILURE, "getargstr linkstr failed");
1459 
1460           ifdrv.ifd_cmd = 0;
1461           ifdrv.ifd_len = linkstrlen;
1462           ifdrv.ifd_data = __UNCONST(linkstr);
1463 
1464           if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1)
1465                     err(EXIT_FAILURE, "SIOCSLINKSTR");
1466           free(linkstr);
1467 
1468           return 0;
1469 }
1470 
1471 static int
unsetlinkstr(prop_dictionary_t env,prop_dictionary_t oenv)1472 unsetlinkstr(prop_dictionary_t env, prop_dictionary_t oenv)
1473 {
1474           struct ifdrv ifdrv;
1475 
1476           memset(&ifdrv, 0, sizeof(ifdrv));
1477           ifdrv.ifd_cmd = IFLINKSTR_UNSET;
1478 
1479           if (direct_ioctl(env, SIOCSLINKSTR, &ifdrv) == -1)
1480                     err(EXIT_FAILURE, "SIOCSLINKSTR");
1481 
1482           return 0;
1483 }
1484 
1485 static int
setifdescr(prop_dictionary_t env,prop_dictionary_t oenv)1486 setifdescr(prop_dictionary_t env, prop_dictionary_t oenv)
1487 {
1488           struct ifreq ifr;
1489           size_t len;
1490           prop_data_t data;
1491           char *descr;
1492 
1493           data = (prop_data_t)prop_dictionary_get(env, "descr");
1494           if (data == NULL) {
1495                     errno = ENOENT;
1496                     return -1;
1497           }
1498           len = prop_data_size(data) + 1;
1499 
1500           if (len > IFDESCRSIZE)
1501                     err(EXIT_FAILURE, "description too long");
1502 
1503           descr = malloc(len);
1504           if (descr == NULL)
1505                     err(EXIT_FAILURE, "malloc description space");
1506           if (getargstr(env, "descr", descr, len) == -1)
1507                     errx(EXIT_FAILURE, "getargstr descr failed");
1508 
1509 
1510           ifr.ifr_buf = descr;
1511           ifr.ifr_buflen = len;
1512           if (direct_ioctl(env, SIOCSIFDESCR, &ifr) != 0)
1513                     err(EXIT_FAILURE, "SIOCSIFDESCR");
1514 
1515           free(descr);
1516 
1517           return 0;
1518 }
1519 
1520 static int
unsetifdescr(prop_dictionary_t env,prop_dictionary_t oenv)1521 unsetifdescr(prop_dictionary_t env, prop_dictionary_t oenv)
1522 {
1523           struct ifreq ifr;
1524           ifr.ifr_buf = NULL;
1525           ifr.ifr_buflen = 0;
1526 
1527           if (direct_ioctl(env, SIOCSIFDESCR, &ifr) != 0)
1528                     err(EXIT_FAILURE, "SIOCSIFDESCR");
1529 
1530           return 0;
1531 }
1532 
1533 
1534 static void
usage(void)1535 usage(void)
1536 {
1537           const char *progname = getprogname();
1538           usage_func_t *usage_f;
1539           prop_dictionary_t env;
1540 
1541           if ((env = prop_dictionary_create()) == NULL)
1542                     err(EXIT_FAILURE, "%s: prop_dictionary_create", __func__);
1543 
1544           fprintf(stderr, "usage: %s [-h] %s[-v] [-z] %sinterface\n"
1545                     "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
1546                     "\t\t[ alias | -alias ] ]\n"
1547                     "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n", progname,
1548                     flag_is_registered(gflags, 'm') ? "[-m] " : "",
1549                     flag_is_registered(gflags, 'L') ? "[-L] " : "");
1550 
1551           SIMPLEQ_FOREACH(usage_f, &usage_funcs, f_next)
1552                     (*usage_f->f_func)(env);
1553 
1554           fprintf(stderr,
1555                     "\t[ arp | -arp ]\n"
1556                     "\t[ preference n ]\n"
1557                     "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
1558                     "\t[ linkstr str | -linkstr ]\n"
1559                     "\t[ unnumbered | -unnumbered ]\n"
1560                     "\t[ description str | descr str | -description | -descr ]\n"
1561                     "       %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n"
1562                     "       %s -l [-b] [-d] [-s] [-u]\n"
1563                     "       %s -C\n"
1564                     "       %s -w n\n"
1565                     "       %s interface create\n"
1566                     "       %s interface destroy\n",
1567                     progname, flag_is_registered(gflags, 'm') ? "[-m] " : "",
1568                     progname, progname, progname, progname, progname);
1569 
1570           prop_object_release((prop_object_t)env);
1571           exit(EXIT_FAILURE);
1572 }
1573