1 /* $NetBSD: ifconfig.c,v 1.235 2015/07/29 07:42:27 ozaki-r Exp $ */
4 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
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.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
34 * Copyright (c) 1983, 1993
35 * The Regents of the University of California. All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
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.
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
62 #include <sys/cdefs.h>
64 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
65 The Regents of the University of California. All rights reserved.");
66 __RCSID("$NetBSD: ifconfig.c,v 1.235 2015/07/29 07:42:27 ozaki-r Exp $");
69 #include <sys/param.h>
70 #include <sys/queue.h>
71 #include <sys/socket.h>
72 #include <sys/ioctl.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 */
83 #include <sys/protosw.h>
103 #include "prog_ops.h"
105 #define WAIT_DAD 10000000 /* nanoseconds between each poll, 10ms */
107 static bool bflag
, dflag
, hflag
, sflag
, uflag
, wflag
;
108 bool lflag
, Nflag
, vflag
, zflag
;
109 static long wflag_secs
;
111 static char gflags
[10 + 26 * 2 + 1] = "AabCdhlNsuvw:z";
112 bool gflagset
[10 + 26 * 2];
114 static int carrier(prop_dictionary_t
);
115 static int clone_command(prop_dictionary_t
, prop_dictionary_t
);
116 static void do_setifpreference(prop_dictionary_t
);
117 static int flag_index(int);
118 static void init_afs(void);
119 static int list_cloners(prop_dictionary_t
, prop_dictionary_t
);
120 static int media_status_exec(prop_dictionary_t
, prop_dictionary_t
);
121 static int wait_dad_exec(prop_dictionary_t
, prop_dictionary_t
);
122 static int no_cmds_exec(prop_dictionary_t
, prop_dictionary_t
);
123 static int notrailers(prop_dictionary_t
, prop_dictionary_t
);
124 static void printall(const char *, prop_dictionary_t
);
125 static int setifaddr(prop_dictionary_t
, prop_dictionary_t
);
126 static int setifbroadaddr(prop_dictionary_t
, prop_dictionary_t
);
127 static int setifcaps(prop_dictionary_t
, prop_dictionary_t
);
128 static int setifdstormask(prop_dictionary_t
, prop_dictionary_t
);
129 static int setifflags(prop_dictionary_t
, prop_dictionary_t
);
130 static int setifmetric(prop_dictionary_t
, prop_dictionary_t
);
131 static int setifmtu(prop_dictionary_t
, prop_dictionary_t
);
132 static int setifnetmask(prop_dictionary_t
, prop_dictionary_t
);
133 static int setifprefixlen(prop_dictionary_t
, prop_dictionary_t
);
134 static int setlinkstr(prop_dictionary_t
, prop_dictionary_t
);
135 static int unsetlinkstr(prop_dictionary_t
, prop_dictionary_t
);
136 static void status(const struct sockaddr
*, prop_dictionary_t
,
138 __dead
static void usage(void);
140 static const struct kwinst ifflagskw
[] = {
141 IFKW("arp", -IFF_NOARP
)
142 , IFKW("debug", IFF_DEBUG
)
143 , IFKW("link0", IFF_LINK0
)
144 , IFKW("link1", IFF_LINK1
)
145 , IFKW("link2", IFF_LINK2
)
146 , {.k_word
= "down", .k_type
= KW_T_INT
, .k_int
= -IFF_UP
}
147 , {.k_word
= "up", .k_type
= KW_T_INT
, .k_int
= IFF_UP
}
150 static const struct kwinst ifcapskw
[] = {
151 IFKW("ip4csum-tx", IFCAP_CSUM_IPv4_Tx
)
152 , IFKW("ip4csum-rx", IFCAP_CSUM_IPv4_Rx
)
153 , IFKW("tcp4csum-tx", IFCAP_CSUM_TCPv4_Tx
)
154 , IFKW("tcp4csum-rx", IFCAP_CSUM_TCPv4_Rx
)
155 , IFKW("udp4csum-tx", IFCAP_CSUM_UDPv4_Tx
)
156 , IFKW("udp4csum-rx", IFCAP_CSUM_UDPv4_Rx
)
157 , IFKW("tcp6csum-tx", IFCAP_CSUM_TCPv6_Tx
)
158 , IFKW("tcp6csum-rx", IFCAP_CSUM_TCPv6_Rx
)
159 , IFKW("udp6csum-tx", IFCAP_CSUM_UDPv6_Tx
)
160 , IFKW("udp6csum-rx", IFCAP_CSUM_UDPv6_Rx
)
161 , IFKW("ip4csum", IFCAP_CSUM_IPv4_Tx
|IFCAP_CSUM_IPv4_Rx
)
162 , IFKW("tcp4csum", IFCAP_CSUM_TCPv4_Tx
|IFCAP_CSUM_TCPv4_Rx
)
163 , IFKW("udp4csum", IFCAP_CSUM_UDPv4_Tx
|IFCAP_CSUM_UDPv4_Rx
)
164 , IFKW("tcp6csum", IFCAP_CSUM_TCPv6_Tx
|IFCAP_CSUM_TCPv6_Rx
)
165 , IFKW("udp6csum", IFCAP_CSUM_UDPv6_Tx
|IFCAP_CSUM_UDPv6_Rx
)
166 , IFKW("tso4", IFCAP_TSOv4
)
167 , IFKW("tso6", IFCAP_TSOv6
)
170 extern struct pbranch command_root
;
171 extern struct pbranch opt_command
;
172 extern struct pbranch opt_family
, opt_silent_family
;
173 extern struct pkw cloning
, silent_family
, family
, ifcaps
, ifflags
, misc
;
174 extern struct pstr parse_linkstr
;
176 struct pinteger parse_metric
= PINTEGER_INITIALIZER(&parse_metric
, "metric", 10,
177 setifmetric
, "metric", &command_root
.pb_parser
);
179 struct pinteger parse_mtu
= PINTEGER_INITIALIZER(&parse_mtu
, "mtu", 10,
180 setifmtu
, "mtu", &command_root
.pb_parser
);
182 struct pinteger parse_prefixlen
= PINTEGER_INITIALIZER(&parse_prefixlen
,
183 "prefixlen", 10, setifprefixlen
, "prefixlen", &command_root
.pb_parser
);
185 struct pinteger parse_preference
= PINTEGER_INITIALIZER1(&parse_preference
,
186 "preference", INT16_MIN
, INT16_MAX
, 10, NULL
, "preference",
187 &command_root
.pb_parser
);
189 struct paddr parse_netmask
= PADDR_INITIALIZER(&parse_netmask
, "netmask",
190 setifnetmask
, "dstormask", NULL
, NULL
, NULL
, &command_root
.pb_parser
);
192 struct paddr parse_broadcast
= PADDR_INITIALIZER(&parse_broadcast
,
194 setifbroadaddr
, "broadcast", NULL
, NULL
, NULL
, &command_root
.pb_parser
);
196 static const struct kwinst misckw
[] = {
197 {.k_word
= "alias", .k_key
= "alias", .k_deact
= "alias",
198 .k_type
= KW_T_BOOL
, .k_neg
= true,
199 .k_bool
= true, .k_negbool
= false,
200 .k_nextparser
= &command_root
.pb_parser
}
201 , {.k_word
= "broadcast", .k_nextparser
= &parse_broadcast
.pa_parser
}
202 , {.k_word
= "delete", .k_key
= "alias", .k_deact
= "alias",
203 .k_type
= KW_T_BOOL
, .k_bool
= false,
204 .k_nextparser
= &command_root
.pb_parser
}
205 , {.k_word
= "metric", .k_nextparser
= &parse_metric
.pi_parser
}
206 , {.k_word
= "mtu", .k_nextparser
= &parse_mtu
.pi_parser
}
207 , {.k_word
= "netmask", .k_nextparser
= &parse_netmask
.pa_parser
}
208 , {.k_word
= "preference", .k_act
= "address",
209 .k_nextparser
= &parse_preference
.pi_parser
}
210 , {.k_word
= "prefixlen", .k_nextparser
= &parse_prefixlen
.pi_parser
}
211 , {.k_word
= "trailers", .k_neg
= true,
212 .k_exec
= notrailers
, .k_nextparser
= &command_root
.pb_parser
}
213 , {.k_word
= "linkstr", .k_nextparser
= &parse_linkstr
.ps_parser
}
214 , {.k_word
= "-linkstr", .k_exec
= unsetlinkstr
,
215 .k_nextparser
= &command_root
.pb_parser
}
219 static const struct kwinst clonekw
[] = {
220 {.k_word
= "create", .k_type
= KW_T_INT
, .k_int
= SIOCIFCREATE
,
221 .k_nextparser
= &opt_silent_family
.pb_parser
},
222 {.k_word
= "destroy", .k_type
= KW_T_INT
, .k_int
= SIOCIFDESTROY
}
225 static struct kwinst familykw
[24];
227 struct pterm cloneterm
= PTERM_INITIALIZER(&cloneterm
, "list cloners",
228 list_cloners
, "none");
230 struct pterm wait_dad
= PTERM_INITIALIZER(&wait_dad
, "wait DAD", wait_dad_exec
,
233 struct pterm no_cmds
= PTERM_INITIALIZER(&no_cmds
, "no commands", no_cmds_exec
,
236 struct pkw family_only
=
237 PKW_INITIALIZER(&family_only
, "family-only", NULL
, "af", familykw
,
238 __arraycount(familykw
), &no_cmds
.pt_parser
);
240 struct paddr address
= PADDR_INITIALIZER(&address
,
241 "local address (address 1)",
242 setifaddr
, "address", "netmask", NULL
, "address", &command_root
.pb_parser
);
244 struct paddr dstormask
= PADDR_INITIALIZER(&dstormask
,
245 "destination/netmask (address 2)",
246 setifdstormask
, "dstormask", NULL
, "address", "dstormask",
247 &command_root
.pb_parser
);
249 struct paddr broadcast
= PADDR_INITIALIZER(&broadcast
,
250 "broadcast address (address 3)",
251 setifbroadaddr
, "broadcast", NULL
, "dstormask", "broadcast",
252 &command_root
.pb_parser
);
254 struct pstr parse_linkstr
= PSTR_INITIALIZER(&parse_linkstr
, "linkstr",
255 setlinkstr
, "linkstr", &command_root
.pb_parser
);
257 static SIMPLEQ_HEAD(, afswtch
) aflist
= SIMPLEQ_HEAD_INITIALIZER(aflist
);
259 static SIMPLEQ_HEAD(, usage_func
) usage_funcs
=
260 SIMPLEQ_HEAD_INITIALIZER(usage_funcs
);
261 static SIMPLEQ_HEAD(, status_func
) status_funcs
=
262 SIMPLEQ_HEAD_INITIALIZER(status_funcs
);
263 static SIMPLEQ_HEAD(, statistics_func
) statistics_funcs
=
264 SIMPLEQ_HEAD_INITIALIZER(statistics_funcs
);
265 static SIMPLEQ_HEAD(, cmdloop_branch
) cmdloop_branches
=
266 SIMPLEQ_HEAD_INITIALIZER(cmdloop_branches
);
268 struct branch opt_clone_brs
[] = {
269 {.b_nextparser
= &cloning
.pk_parser
}
270 , {.b_nextparser
= &opt_family
.pb_parser
}
271 }, opt_silent_family_brs
[] = {
272 {.b_nextparser
= &silent_family
.pk_parser
}
273 , {.b_nextparser
= &command_root
.pb_parser
}
274 }, opt_family_brs
[] = {
275 {.b_nextparser
= &family
.pk_parser
}
276 , {.b_nextparser
= &opt_command
.pb_parser
}
277 }, command_root_brs
[] = {
278 {.b_nextparser
= &ifflags
.pk_parser
}
279 , {.b_nextparser
= &ifcaps
.pk_parser
}
280 , {.b_nextparser
= &kwmedia
.pk_parser
}
281 , {.b_nextparser
= &misc
.pk_parser
}
282 , {.b_nextparser
= &address
.pa_parser
}
283 , {.b_nextparser
= &dstormask
.pa_parser
}
284 , {.b_nextparser
= &broadcast
.pa_parser
}
285 , {.b_nextparser
= NULL
}
286 }, opt_command_brs
[] = {
287 {.b_nextparser
= &no_cmds
.pt_parser
}
288 , {.b_nextparser
= &command_root
.pb_parser
}
291 struct branch opt_family_only_brs
[] = {
292 {.b_nextparser
= &no_cmds
.pt_parser
}
293 , {.b_nextparser
= &family_only
.pk_parser
}
295 struct pbranch opt_family_only
= PBRANCH_INITIALIZER(&opt_family_only
,
296 "opt-family-only", opt_family_only_brs
,
297 __arraycount(opt_family_only_brs
), true);
298 struct pbranch opt_command
= PBRANCH_INITIALIZER(&opt_command
,
300 opt_command_brs
, __arraycount(opt_command_brs
), true);
302 struct pbranch command_root
= PBRANCH_INITIALIZER(&command_root
,
303 "command-root", command_root_brs
, __arraycount(command_root_brs
), true);
305 struct piface iface_opt_family_only
=
306 PIFACE_INITIALIZER(&iface_opt_family_only
, "iface-opt-family-only",
307 NULL
, "if", &opt_family_only
.pb_parser
);
309 struct pkw family
= PKW_INITIALIZER(&family
, "family", NULL
, "af",
310 familykw
, __arraycount(familykw
), &opt_command
.pb_parser
);
312 struct pkw silent_family
= PKW_INITIALIZER(&silent_family
, "silent family",
313 NULL
, "af", familykw
, __arraycount(familykw
), &command_root
.pb_parser
);
315 struct pkw
*family_users
[] = {&family_only
, &family
, &silent_family
};
317 struct pkw ifcaps
= PKW_INITIALIZER(&ifcaps
, "ifcaps", setifcaps
,
318 "ifcap", ifcapskw
, __arraycount(ifcapskw
), &command_root
.pb_parser
);
320 struct pkw ifflags
= PKW_INITIALIZER(&ifflags
, "ifflags", setifflags
,
321 "ifflag", ifflagskw
, __arraycount(ifflagskw
), &command_root
.pb_parser
);
323 struct pkw cloning
= PKW_INITIALIZER(&cloning
, "cloning", clone_command
,
324 "clonecmd", clonekw
, __arraycount(clonekw
), NULL
);
326 struct pkw misc
= PKW_INITIALIZER(&misc
, "misc", NULL
, NULL
,
327 misckw
, __arraycount(misckw
), NULL
);
329 struct pbranch opt_clone
= PBRANCH_INITIALIZER(&opt_clone
,
330 "opt-clone", opt_clone_brs
, __arraycount(opt_clone_brs
), true);
332 struct pbranch opt_silent_family
= PBRANCH_INITIALIZER(&opt_silent_family
,
333 "optional silent family", opt_silent_family_brs
,
334 __arraycount(opt_silent_family_brs
), true);
336 struct pbranch opt_family
= PBRANCH_INITIALIZER(&opt_family
,
337 "opt-family", opt_family_brs
, __arraycount(opt_family_brs
), true);
339 struct piface iface_start
= PIFACE_INITIALIZER(&iface_start
,
340 "iface-opt-family", NULL
, "if", &opt_clone
.pb_parser
);
342 struct piface iface_only
= PIFACE_INITIALIZER(&iface_only
, "iface",
343 media_status_exec
, "if", NULL
);
346 flag_is_registered(const char *flags
, int flag
)
348 return flags
!= NULL
&& strchr(flags
, flag
) != NULL
;
352 check_flag(const char *flags
, int flag
)
354 if (flag_is_registered(flags
, flag
)) {
359 if (flag
>= '0' && flag
<= '9')
361 if (flag
>= 'a' && flag
<= 'z')
363 if (flag
>= 'A' && flag
<= 'Z')
371 cmdloop_branch_init(cmdloop_branch_t
*b
, struct parser
*p
)
377 statistics_func_init(statistics_func_t
*f
, statistics_cb_t func
)
383 status_func_init(status_func_t
*f
, status_cb_t func
)
389 usage_func_init(usage_func_t
*f
, usage_cb_t func
)
395 register_cmdloop_branch(cmdloop_branch_t
*b
)
397 SIMPLEQ_INSERT_TAIL(&cmdloop_branches
, b
, b_next
);
402 register_statistics(statistics_func_t
*f
)
404 SIMPLEQ_INSERT_TAIL(&statistics_funcs
, f
, f_next
);
409 register_status(status_func_t
*f
)
411 SIMPLEQ_INSERT_TAIL(&status_funcs
, f
, f_next
);
416 register_usage(usage_func_t
*f
)
418 SIMPLEQ_INSERT_TAIL(&usage_funcs
, f
, f_next
);
423 register_family(struct afswtch
*af
)
425 SIMPLEQ_INSERT_TAIL(&aflist
, af
, af_next
);
430 register_flag(int flag
)
432 if (check_flag(gflags
, flag
) == -1)
435 if (strlen(gflags
) + 1 >= sizeof(gflags
)) {
440 gflags
[strlen(gflags
)] = flag
;
448 if (flag
>= '0' && flag
<= '9')
450 if (flag
>= 'a' && flag
<= 'z')
451 return 10 + flag
- 'a';
452 if (flag
>= 'A' && flag
<= 'Z')
453 return 10 + 26 + flag
- 'a';
464 if ((idx
= flag_index(flag
)) == -1)
467 return gflagset
[idx
] = true;
475 if ((idx
= flag_index(flag
)) == -1)
478 return gflagset
[idx
];
481 static struct parser
*
486 if (parser_init(&iface_opt_family_only
.pif_parser
) == -1)
487 err(EXIT_FAILURE
, "parser_init(iface_opt_family_only)");
488 if (parser_init(&iface_only
.pif_parser
) == -1)
489 err(EXIT_FAILURE
, "parser_init(iface_only)");
490 if (parser_init(&iface_start
.pif_parser
) == -1)
491 err(EXIT_FAILURE
, "parser_init(iface_start)");
493 SIMPLEQ_FOREACH(b
, &cmdloop_branches
, b_next
)
494 pbranch_addbranch(&command_root
, b
->b_parser
);
496 return &iface_start
.pif_parser
;
500 no_cmds_exec(prop_dictionary_t env
, prop_dictionary_t oenv
)
503 unsigned short ignore
;
505 /* ifname == NULL is ok. It indicates 'ifconfig -a'. */
506 if ((ifname
= getifname(env
)) == NULL
)
508 else if (getifflags(env
, oenv
, &ignore
) == -1)
509 err(EXIT_FAILURE
, "SIOCGIFFLAGS %s", ifname
);
511 printall(ifname
, env
);
516 wait_dad_exec(prop_dictionary_t env
, prop_dictionary_t oenv
)
519 struct ifaddrs
*ifaddrs
, *ifa
;
520 const struct timespec ts
= { .tv_sec
= 0, .tv_nsec
= WAIT_DAD
};
521 const struct timespec add
= { .tv_sec
= wflag_secs
, .tv_nsec
= 0};
522 struct timespec now
, end
= { .tv_sec
= wflag_secs
, .tv_nsec
= 0};
523 const struct afswtch
*afp
;
526 if (clock_gettime(CLOCK_MONOTONIC
, &now
) == -1)
527 err(EXIT_FAILURE
, "clock_gettime");
528 timespecadd(&now
, &add
, &end
);
531 if (getifaddrs(&ifaddrs
) == -1)
532 err(EXIT_FAILURE
, "getifaddrs");
536 for (ifa
= ifaddrs
; ifa
; ifa
= ifa
->ifa_next
) {
537 if (ifa
->ifa_addr
== NULL
)
539 afp
= lookup_af_bynum(ifa
->ifa_addr
->sa_family
);
540 if (afp
&& afp
->af_addr_tentative
&&
541 afp
->af_addr_tentative(ifa
))
549 nanosleep(&ts
, NULL
);
551 if (clock_gettime(CLOCK_MONOTONIC
, &now
) == -1)
552 err(EXIT_FAILURE
, "clock_gettime");
553 if (timespeccmp(&now
, &end
, >))
554 errx(EXIT_FAILURE
, "timed out");
558 freeifaddrs(ifaddrs
);
563 media_status_exec(prop_dictionary_t env
, prop_dictionary_t oenv
)
566 unsigned short ignore
;
568 /* ifname == NULL is ok. It indicates 'ifconfig -a'. */
569 if ((ifname
= getifname(env
)) == NULL
)
571 else if (getifflags(env
, oenv
, &ignore
) == -1)
572 err(EXIT_FAILURE
, "SIOCGIFFLAGS %s", ifname
);
578 do_setifcaps(prop_dictionary_t env
)
580 struct ifcapreq ifcr
;
583 d
= (prop_data_t
)prop_dictionary_get(env
, "ifcaps");
587 assert(sizeof(ifcr
) == prop_data_size(d
));
589 memcpy(&ifcr
, prop_data_data_nocopy(d
), sizeof(ifcr
));
590 if (direct_ioctl(env
, SIOCSIFCAP
, &ifcr
) == -1)
591 err(EXIT_FAILURE
, "SIOCSIFCAP");
595 main(int argc
, char **argv
)
597 const struct afswtch
*afp
;
599 bool aflag
= false, Cflag
= false;
600 struct match match
[32];
602 struct parser
*start
;
603 int ch
, narg
= 0, rc
;
604 prop_dictionary_t env
, oenv
;
608 memset(match
, 0, sizeof(match
));
612 start
= init_parser();
614 /* Parse command-line options */
615 Nflag
= vflag
= zflag
= false;
616 aflag
= argc
== 1 ? true : false;
618 start
= &opt_family_only
.pb_parser
;
620 while ((ch
= getopt(argc
, argv
, gflags
)) != -1) {
623 warnx("-A is deprecated");
665 wflag_secs
= strtol(optarg
, &end
, 10);
666 if ((end
!= NULL
&& *end
!= '\0') ||
667 wflag_secs
< 0 || wflag_secs
>= INT32_MAX
)
668 errx(EXIT_FAILURE
, "%s: not a number", optarg
);
682 start
= &opt_family_only
.pb_parser
;
688 if (start
!= &opt_family_only
.pb_parser
)
689 start
= &iface_opt_family_only
.pif_parser
;
692 start
= &cloneterm
.pt_parser
;
695 start
= &no_cmds
.pt_parser
;
698 if (start
!= &no_cmds
.pt_parser
&&
699 start
!= &opt_family_only
.pb_parser
)
700 start
= &iface_only
.pif_parser
;
703 start
= &wait_dad
.pt_parser
;
713 * -l means "list all interfaces", and is mutually exclusive with
714 * all other flags/commands.
716 * -C means "list all names of cloners", and it mutually exclusive
717 * with all other flags/commands.
719 * -a means "print status of all interfaces".
721 * -w means "spin until DAD completes for all addreseses", and is
722 * mutually exclusivewith all other flags/commands.
724 if ((lflag
|| Cflag
|| wflag
) &&
725 (aflag
|| get_flag('m') || vflag
|| zflag
))
727 if ((lflag
|| Cflag
|| wflag
) && get_flag('L'))
729 if ((lflag
&& Cflag
) || (lflag
& wflag
) || (Cflag
&& wflag
))
732 nmatch
= __arraycount(match
);
734 rc
= parse(argc
, argv
, start
, match
, &nmatch
, &narg
);
738 if (prog_init
&& prog_init() == -1)
739 err(1, "rump client init");
741 if ((oenv
= prop_dictionary_create()) == NULL
)
742 err(EXIT_FAILURE
, "%s: prop_dictionary_create", __func__
);
744 if (matches_exec(match
, oenv
, nmatch
) == -1)
745 err(EXIT_FAILURE
, "exec_matches");
750 env
= (nmatch
> 0) ? match
[(int)nmatch
- 1].m_env
: NULL
;
754 env
= prop_dictionary_augment(env
, oenv
);
756 err(EXIT_FAILURE
, "%s: prop_dictionary_augment",
760 /* Process any media commands that may have been issued. */
761 process_media_commands(env
);
763 if ((af
= getaf(env
)) == -1)
766 if ((s
= getsock(af
)) == -1)
767 err(EXIT_FAILURE
, "%s: getsock", __func__
);
769 if ((ifname
= getifname(env
)) == NULL
)
770 err(EXIT_FAILURE
, "%s: getifname", __func__
);
772 if ((afp
= lookup_af_bynum(af
)) == NULL
)
773 errx(EXIT_FAILURE
, "%s: lookup_af_bynum", __func__
);
775 assert(afp
->af_addr_commit
!= NULL
);
776 (*afp
->af_addr_commit
)(env
, oenv
);
778 do_setifpreference(env
);
788 const struct afswtch
*afp
;
789 struct kwinst kw
= {.k_type
= KW_T_INT
};
791 SIMPLEQ_FOREACH(afp
, &aflist
, af_next
) {
792 kw
.k_word
= afp
->af_name
;
793 kw
.k_int
= afp
->af_af
;
794 for (i
= 0; i
< __arraycount(familykw
); i
++) {
795 if (familykw
[i
].k_word
== NULL
) {
803 const struct afswtch
*
804 lookup_af_bynum(int afnum
)
806 const struct afswtch
*afp
;
808 SIMPLEQ_FOREACH(afp
, &aflist
, af_next
) {
809 if (afp
->af_af
== afnum
)
816 printall(const char *ifname
, prop_dictionary_t env0
)
818 struct ifaddrs
*ifap
, *ifa
;
820 const struct sockaddr
*sdl
= NULL
;
821 prop_dictionary_t env
, oenv
;
826 env
= prop_dictionary_create();
828 env
= prop_dictionary_copy_mutable(env0
);
830 oenv
= prop_dictionary_create();
832 if (env
== NULL
|| oenv
== NULL
)
833 errx(EXIT_FAILURE
, "%s: prop_dictionary_copy/create", __func__
);
835 if (getifaddrs(&ifap
) != 0)
836 err(EXIT_FAILURE
, "getifaddrs");
839 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
840 memset(&ifr
, 0, sizeof(ifr
));
841 estrlcpy(ifr
.ifr_name
, ifa
->ifa_name
, sizeof(ifr
.ifr_name
));
842 if (sizeof(ifr
.ifr_addr
) >= ifa
->ifa_addr
->sa_len
) {
843 memcpy(&ifr
.ifr_addr
, ifa
->ifa_addr
,
844 ifa
->ifa_addr
->sa_len
);
847 if (ifname
!= NULL
&& strcmp(ifname
, ifa
->ifa_name
) != 0)
849 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
851 if (p
&& strcmp(p
, ifa
->ifa_name
) == 0)
853 if (!prop_dictionary_set_cstring(env
, "if", ifa
->ifa_name
))
857 if (bflag
&& (ifa
->ifa_flags
& IFF_BROADCAST
) == 0)
859 if (dflag
&& (ifa
->ifa_flags
& IFF_UP
) != 0)
861 if (uflag
&& (ifa
->ifa_flags
& IFF_UP
) == 0)
864 if (sflag
&& carrier(env
))
868 * Are we just listing the interfaces?
873 fputs(ifa
->ifa_name
, stdout
);
877 status(sdl
, env
, oenv
);
882 prop_object_release((prop_object_t
)env
);
883 prop_object_release((prop_object_t
)oenv
);
888 list_cloners(prop_dictionary_t env
, prop_dictionary_t oenv
)
890 struct if_clonereq ifcr
;
894 memset(&ifcr
, 0, sizeof(ifcr
));
896 s
= getsock(AF_INET
);
898 if (prog_ioctl(s
, SIOCIFGCLONERS
, &ifcr
) == -1)
899 err(EXIT_FAILURE
, "SIOCIFGCLONERS for count");
901 buf
= malloc(ifcr
.ifcr_total
* IFNAMSIZ
);
903 err(EXIT_FAILURE
, "unable to allocate cloner name buffer");
905 ifcr
.ifcr_count
= ifcr
.ifcr_total
;
906 ifcr
.ifcr_buffer
= buf
;
908 if (prog_ioctl(s
, SIOCIFGCLONERS
, &ifcr
) == -1)
909 err(EXIT_FAILURE
, "SIOCIFGCLONERS for names");
912 * In case some disappeared in the mean time, clamp it down.
914 if (ifcr
.ifcr_count
> ifcr
.ifcr_total
)
915 ifcr
.ifcr_count
= ifcr
.ifcr_total
;
917 for (cp
= buf
, idx
= 0; idx
< ifcr
.ifcr_count
; idx
++, cp
+= IFNAMSIZ
) {
929 clone_command(prop_dictionary_t env
, prop_dictionary_t oenv
)
933 if (!prop_dictionary_get_int64(env
, "clonecmd", &cmd
)) {
938 if (indirect_ioctl(env
, (unsigned long)cmd
, NULL
) == -1) {
939 warn("%s", __func__
);
947 setifaddr(prop_dictionary_t env
, prop_dictionary_t oenv
)
949 const struct paddr_prefix
*pfx0
;
950 struct paddr_prefix
*pfx
;
954 if ((af
= getaf(env
)) == -1)
957 d
= (prop_data_t
)prop_dictionary_get(env
, "address");
959 pfx0
= prop_data_data_nocopy(d
);
961 if (pfx0
->pfx_len
>= 0) {
962 pfx
= prefixlen_to_mask(af
, pfx0
->pfx_len
);
964 err(EXIT_FAILURE
, "prefixlen_to_mask");
972 setifnetmask(prop_dictionary_t env
, prop_dictionary_t oenv
)
976 d
= (prop_data_t
)prop_dictionary_get(env
, "dstormask");
979 if (!prop_dictionary_set(oenv
, "netmask", (prop_object_t
)d
))
986 setifbroadaddr(prop_dictionary_t env
, prop_dictionary_t oenv
)
989 unsigned short flags
;
991 if (getifflags(env
, oenv
, &flags
) == -1)
992 err(EXIT_FAILURE
, "%s: getifflags", __func__
);
994 if ((flags
& IFF_BROADCAST
) == 0)
995 errx(EXIT_FAILURE
, "not a broadcast interface");
997 d
= (prop_data_t
)prop_dictionary_get(env
, "broadcast");
1000 if (!prop_dictionary_set(oenv
, "broadcast", (prop_object_t
)d
))
1008 notrailers(prop_dictionary_t env
, prop_dictionary_t oenv
)
1010 puts("Note: trailers are no longer sent, but always received");
1016 setifdstormask(prop_dictionary_t env
, prop_dictionary_t oenv
)
1020 unsigned short flags
;
1022 if (getifflags(env
, oenv
, &flags
) == -1)
1023 err(EXIT_FAILURE
, "%s: getifflags", __func__
);
1025 d
= (prop_data_t
)prop_dictionary_get(env
, "dstormask");
1028 if ((flags
& IFF_BROADCAST
) == 0) {
1034 if (!prop_dictionary_set(oenv
, key
, (prop_object_t
)d
))
1041 setifflags(prop_dictionary_t env
, prop_dictionary_t oenv
)
1047 rc
= prop_dictionary_get_int64(env
, "ifflag", &ifflag
);
1050 if (direct_ioctl(env
, SIOCGIFFLAGS
, &ifr
) == -1)
1055 ifr
.ifr_flags
&= ~ifflag
;
1057 ifr
.ifr_flags
|= ifflag
;
1059 if (direct_ioctl(env
, SIOCSIFFLAGS
, &ifr
) == -1)
1066 getifcaps(prop_dictionary_t env
, prop_dictionary_t oenv
, struct ifcapreq
*oifcr
)
1069 struct ifcapreq ifcr
;
1070 const struct ifcapreq
*tmpifcr
;
1071 prop_data_t capdata
;
1073 capdata
= (prop_data_t
)prop_dictionary_get(env
, "ifcaps");
1075 if (capdata
!= NULL
) {
1076 tmpifcr
= prop_data_data_nocopy(capdata
);
1081 (void)direct_ioctl(env
, SIOCGIFCAP
, &ifcr
);
1084 capdata
= prop_data_create_data(&ifcr
, sizeof(ifcr
));
1086 rc
= prop_dictionary_set(oenv
, "ifcaps", capdata
);
1088 prop_object_release((prop_object_t
)capdata
);
1094 setifcaps(prop_dictionary_t env
, prop_dictionary_t oenv
)
1098 prop_data_t capdata
;
1099 struct ifcapreq ifcr
;
1101 rc
= prop_dictionary_get_int64(env
, "ifcap", &ifcap
);
1104 if (getifcaps(env
, oenv
, &ifcr
) == -1)
1109 ifcr
.ifcr_capenable
&= ~ifcap
;
1111 ifcr
.ifcr_capenable
|= ifcap
;
1113 if ((capdata
= prop_data_create_data(&ifcr
, sizeof(ifcr
))) == NULL
)
1116 rc
= prop_dictionary_set(oenv
, "ifcaps", capdata
);
1117 prop_object_release((prop_object_t
)capdata
);
1123 setifmetric(prop_dictionary_t env
, prop_dictionary_t oenv
)
1129 rc
= prop_dictionary_get_int64(env
, "metric", &metric
);
1132 ifr
.ifr_metric
= metric
;
1133 if (direct_ioctl(env
, SIOCSIFMETRIC
, &ifr
) == -1)
1134 warn("SIOCSIFMETRIC");
1139 do_setifpreference(prop_dictionary_t env
)
1141 struct if_addrprefreq ifap
;
1143 const struct paddr_prefix
*pfx
;
1145 memset(&ifap
, 0, sizeof(ifap
));
1147 if (!prop_dictionary_get_int16(env
, "preference",
1148 &ifap
.ifap_preference
))
1151 d
= (prop_data_t
)prop_dictionary_get(env
, "address");
1154 pfx
= prop_data_data_nocopy(d
);
1156 memcpy(&ifap
.ifap_addr
, &pfx
->pfx_addr
,
1157 MIN(sizeof(ifap
.ifap_addr
), pfx
->pfx_addr
.sa_len
));
1158 if (direct_ioctl(env
, SIOCSIFADDRPREF
, &ifap
) == -1)
1159 warn("SIOCSIFADDRPREF");
1163 setifmtu(prop_dictionary_t env
, prop_dictionary_t oenv
)
1169 rc
= prop_dictionary_get_int64(env
, "mtu", &mtu
);
1173 if (direct_ioctl(env
, SIOCSIFMTU
, &ifr
) == -1)
1180 carrier(prop_dictionary_t env
)
1182 struct ifmediareq ifmr
;
1184 memset(&ifmr
, 0, sizeof(ifmr
));
1186 if (direct_ioctl(env
, SIOCGIFMEDIA
, &ifmr
) == -1) {
1188 * Interface doesn't support SIOC{G,S}IFMEDIA;
1191 return EXIT_SUCCESS
;
1193 if ((ifmr
.ifm_status
& IFM_AVALID
) == 0) {
1195 * Interface doesn't report media-valid status.
1198 return EXIT_SUCCESS
;
1200 /* otherwise, return ok for active, not-ok if not active. */
1201 if (ifmr
.ifm_status
& IFM_ACTIVE
)
1202 return EXIT_SUCCESS
;
1204 return EXIT_FAILURE
;
1208 print_plural(const char *prefix
, uint64_t n
, const char *unit
)
1210 printf("%s%" PRIu64
" %s%s", prefix
, n
, unit
, (n
== 1) ? "" : "s");
1214 print_human_bytes(bool humanize
, uint64_t n
)
1219 (void)humanize_number(buf
, sizeof(buf
),
1220 (int64_t)n
, "", HN_AUTOSCALE
, HN_NOSPACE
| HN_DECIMAL
);
1221 printf(", %s byte%s", buf
, (atof(buf
) == 1.0) ? "" : "s");
1223 print_plural(", ", n
, "byte");
1227 * Print the status of the interface. If an address family was
1228 * specified, show it and it only; otherwise, show them all.
1231 #define MAX_PRINT_LEN 58 /* XXX need a better way to determine this! */
1234 status(const struct sockaddr
*sdl
, prop_dictionary_t env
,
1235 prop_dictionary_t oenv
)
1237 const struct if_data
*ifi
;
1238 status_func_t
*status_f
;
1239 statistics_func_t
*statistics_f
;
1240 struct ifdatareq ifdr
;
1247 struct ifcapreq ifcr
;
1248 unsigned short flags
;
1249 const struct afswtch
*afp
;
1251 if ((af
= getaf(env
)) == -1) {
1255 afp
= lookup_af_bynum(af
);
1257 /* get out early if the family is unsupported by the kernel */
1258 if ((s
= getsock(af
)) == -1)
1259 err(EXIT_FAILURE
, "%s: getsock", __func__
);
1261 if ((ifname
= getifinfo(env
, oenv
, &flags
)) == NULL
)
1262 err(EXIT_FAILURE
, "%s: getifinfo", __func__
);
1264 (void)snprintb(fbuf
, sizeof(fbuf
), IFFBITS
, flags
);
1265 printf("%s: flags=%s", ifname
, fbuf
);
1267 estrlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
1268 if (prog_ioctl(s
, SIOCGIFMETRIC
, &ifr
) == -1)
1269 warn("SIOCGIFMETRIC %s", ifr
.ifr_name
);
1270 else if (ifr
.ifr_metric
!= 0)
1271 printf(" metric %d", ifr
.ifr_metric
);
1273 estrlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
1274 if (prog_ioctl(s
, SIOCGIFMTU
, &ifr
) != -1 && ifr
.ifr_mtu
!= 0)
1275 printf(" mtu %d", ifr
.ifr_mtu
);
1278 if (getifcaps(env
, oenv
, &ifcr
) == -1)
1279 err(EXIT_FAILURE
, "%s: getifcaps", __func__
);
1281 if (ifcr
.ifcr_capabilities
!= 0) {
1282 (void)snprintb_m(fbuf
, sizeof(fbuf
), IFCAPBITS
,
1283 ifcr
.ifcr_capabilities
, MAX_PRINT_LEN
);
1285 while (*bp
!= '\0') {
1286 printf("\tcapabilities=%s\n", &bp
[2]);
1287 bp
+= strlen(bp
) + 1;
1289 (void)snprintb_m(fbuf
, sizeof(fbuf
), IFCAPBITS
,
1290 ifcr
.ifcr_capenable
, MAX_PRINT_LEN
);
1292 while (*bp
!= '\0') {
1293 printf("\tenabled=%s\n", &bp
[2]);
1294 bp
+= strlen(bp
) + 1;
1298 SIMPLEQ_FOREACH(status_f
, &status_funcs
, f_next
)
1299 (*status_f
->f_func
)(env
, oenv
);
1301 print_link_addresses(env
, true);
1303 estrlcpy(ifdrv
.ifd_name
, ifname
, sizeof(ifdrv
.ifd_name
));
1304 ifdrv
.ifd_cmd
= IFLINKSTR_QUERYLEN
;
1306 ifdrv
.ifd_data
= NULL
;
1307 /* interface supports linkstr? */
1308 if (prog_ioctl(s
, SIOCGLINKSTR
, &ifdrv
) != -1) {
1311 p
= malloc(ifdrv
.ifd_len
);
1313 err(EXIT_FAILURE
, "malloc linkstr buf failed");
1316 if (prog_ioctl(s
, SIOCGLINKSTR
, &ifdrv
) == -1)
1317 err(EXIT_FAILURE
, "failed to query linkstr");
1318 printf("\tlinkstr: %s\n", (char *)ifdrv
.ifd_data
);
1322 media_status(env
, oenv
);
1324 if (!vflag
&& !zflag
)
1327 estrlcpy(ifdr
.ifdr_name
, ifname
, sizeof(ifdr
.ifdr_name
));
1329 if (prog_ioctl(s
, zflag
? SIOCZIFDATA
: SIOCGIFDATA
, &ifdr
) == -1)
1330 err(EXIT_FAILURE
, zflag
? "SIOCZIFDATA" : "SIOCGIFDATA");
1332 ifi
= &ifdr
.ifdr_data
;
1334 print_plural("\tinput: ", ifi
->ifi_ipackets
, "packet");
1335 print_human_bytes(hflag
, ifi
->ifi_ibytes
);
1336 if (ifi
->ifi_imcasts
)
1337 print_plural(", ", ifi
->ifi_imcasts
, "multicast");
1338 if (ifi
->ifi_ierrors
)
1339 print_plural(", ", ifi
->ifi_ierrors
, "error");
1340 if (ifi
->ifi_iqdrops
)
1341 print_plural(", ", ifi
->ifi_iqdrops
, "queue drop");
1342 if (ifi
->ifi_noproto
)
1343 printf(", %" PRIu64
" unknown protocol", ifi
->ifi_noproto
);
1344 print_plural("\n\toutput: ", ifi
->ifi_opackets
, "packet");
1345 print_human_bytes(hflag
, ifi
->ifi_obytes
);
1346 if (ifi
->ifi_omcasts
)
1347 print_plural(", ", ifi
->ifi_omcasts
, "multicast");
1348 if (ifi
->ifi_oerrors
)
1349 print_plural(", ", ifi
->ifi_oerrors
, "error");
1350 if (ifi
->ifi_collisions
)
1351 print_plural(", ", ifi
->ifi_collisions
, "collision");
1354 SIMPLEQ_FOREACH(statistics_f
, &statistics_funcs
, f_next
)
1355 (*statistics_f
->f_func
)(env
);
1360 (*afp
->af_status
)(env
, oenv
, true);
1361 else SIMPLEQ_FOREACH(afp
, &aflist
, af_next
)
1362 (*afp
->af_status
)(env
, oenv
, false);
1366 setifprefixlen(prop_dictionary_t env
, prop_dictionary_t oenv
)
1371 struct paddr_prefix
*pfx
;
1374 if ((af
= getaf(env
)) == -1)
1377 rc
= prop_dictionary_get_int64(env
, "prefixlen", &plen
);
1380 pfx
= prefixlen_to_mask(af
, plen
);
1382 err(EXIT_FAILURE
, "prefixlen_to_mask");
1384 d
= prop_data_create_data(pfx
, paddr_prefix_size(pfx
));
1386 err(EXIT_FAILURE
, "%s: prop_data_create_data", __func__
);
1388 if (!prop_dictionary_set(oenv
, "netmask", (prop_object_t
)d
))
1389 err(EXIT_FAILURE
, "%s: prop_dictionary_set", __func__
);
1396 setlinkstr(prop_dictionary_t env
, prop_dictionary_t oenv
)
1403 data
= (prop_data_t
)prop_dictionary_get(env
, "linkstr");
1408 linkstrlen
= prop_data_size(data
)+1;
1410 linkstr
= malloc(linkstrlen
);
1411 if (linkstr
== NULL
)
1412 err(EXIT_FAILURE
, "malloc linkstr space");
1413 if (getargstr(env
, "linkstr", linkstr
, linkstrlen
) == -1)
1414 errx(EXIT_FAILURE
, "getargstr linkstr failed");
1417 ifdrv
.ifd_len
= linkstrlen
;
1418 ifdrv
.ifd_data
= __UNCONST(linkstr
);
1420 if (direct_ioctl(env
, SIOCSLINKSTR
, &ifdrv
) == -1)
1421 err(EXIT_FAILURE
, "SIOCSLINKSTR");
1428 unsetlinkstr(prop_dictionary_t env
, prop_dictionary_t oenv
)
1432 memset(&ifdrv
, 0, sizeof(ifdrv
));
1433 ifdrv
.ifd_cmd
= IFLINKSTR_UNSET
;
1435 if (direct_ioctl(env
, SIOCSLINKSTR
, &ifdrv
) == -1)
1436 err(EXIT_FAILURE
, "SIOCSLINKSTR");
1444 const char *progname
= getprogname();
1445 usage_func_t
*usage_f
;
1446 prop_dictionary_t env
;
1448 if ((env
= prop_dictionary_create()) == NULL
)
1449 err(EXIT_FAILURE
, "%s: prop_dictionary_create", __func__
);
1451 fprintf(stderr
, "usage: %s [-h] %s[-v] [-z] %sinterface\n"
1452 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
1453 "\t\t[ alias | -alias ] ]\n"
1454 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n", progname
,
1455 flag_is_registered(gflags
, 'm') ? "[-m] " : "",
1456 flag_is_registered(gflags
, 'L') ? "[-L] " : "");
1458 SIMPLEQ_FOREACH(usage_f
, &usage_funcs
, f_next
)
1459 (*usage_f
->f_func
)(env
);
1462 "\t[ arp | -arp ]\n"
1463 "\t[ preference n ]\n"
1464 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
1465 " %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n"
1466 " %s -l [-b] [-d] [-s] [-u]\n"
1469 " %s interface create\n"
1470 " %s interface destroy\n",
1471 progname
, flag_is_registered(gflags
, 'm') ? "[-m] " : "",
1472 progname
, progname
, progname
, progname
, progname
);
1474 prop_object_release((prop_object_t
)env
);