1 /* $NetBSD: ifconfig.c,v 1.219 2009/05/26 16:03:24 pooka 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.219 2009/05/26 16:03:24 pooka 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>
104 static bool bflag
, dflag
, hflag
, sflag
, uflag
;
105 bool lflag
, Nflag
, vflag
, zflag
;
107 static char gflags
[10 + 26 * 2 + 1] = "AabCdhlNsuvz";
108 bool gflagset
[10 + 26 * 2];
110 static int carrier(prop_dictionary_t
);
111 static int clone_command(prop_dictionary_t
, prop_dictionary_t
);
112 static void do_setifpreference(prop_dictionary_t
);
113 static int flag_index(int);
114 static void init_afs(void);
115 static int list_cloners(prop_dictionary_t
, prop_dictionary_t
);
116 static int media_status_exec(prop_dictionary_t
, prop_dictionary_t
);
117 static int no_cmds_exec(prop_dictionary_t
, prop_dictionary_t
);
118 static int notrailers(prop_dictionary_t
, prop_dictionary_t
);
119 static void printall(const char *, prop_dictionary_t
);
120 static int setifaddr(prop_dictionary_t
, prop_dictionary_t
);
121 static int setifbroadaddr(prop_dictionary_t
, prop_dictionary_t
);
122 static int setifcaps(prop_dictionary_t
, prop_dictionary_t
);
123 static int setifdstormask(prop_dictionary_t
, prop_dictionary_t
);
124 static int setifflags(prop_dictionary_t
, prop_dictionary_t
);
125 static int setifmetric(prop_dictionary_t
, prop_dictionary_t
);
126 static int setifmtu(prop_dictionary_t
, prop_dictionary_t
);
127 static int setifnetmask(prop_dictionary_t
, prop_dictionary_t
);
128 static int setifprefixlen(prop_dictionary_t
, prop_dictionary_t
);
129 static void status(const struct sockaddr
*, prop_dictionary_t
,
131 static void usage(void);
133 static const struct kwinst ifflagskw
[] = {
134 IFKW("arp", -IFF_NOARP
)
135 , IFKW("debug", IFF_DEBUG
)
136 , IFKW("link0", IFF_LINK0
)
137 , IFKW("link1", IFF_LINK1
)
138 , IFKW("link2", IFF_LINK2
)
139 , {.k_word
= "down", .k_type
= KW_T_INT
, .k_int
= -IFF_UP
}
140 , {.k_word
= "up", .k_type
= KW_T_INT
, .k_int
= IFF_UP
}
143 static const struct kwinst ifcapskw
[] = {
144 IFKW("ip4csum-tx", IFCAP_CSUM_IPv4_Tx
)
145 , IFKW("ip4csum-rx", IFCAP_CSUM_IPv4_Rx
)
146 , IFKW("tcp4csum-tx", IFCAP_CSUM_TCPv4_Tx
)
147 , IFKW("tcp4csum-rx", IFCAP_CSUM_TCPv4_Rx
)
148 , IFKW("udp4csum-tx", IFCAP_CSUM_UDPv4_Tx
)
149 , IFKW("udp4csum-rx", IFCAP_CSUM_UDPv4_Rx
)
150 , IFKW("tcp6csum-tx", IFCAP_CSUM_TCPv6_Tx
)
151 , IFKW("tcp6csum-rx", IFCAP_CSUM_TCPv6_Rx
)
152 , IFKW("udp6csum-tx", IFCAP_CSUM_UDPv6_Tx
)
153 , IFKW("udp6csum-rx", IFCAP_CSUM_UDPv6_Rx
)
154 , IFKW("ip4csum", IFCAP_CSUM_IPv4_Tx
|IFCAP_CSUM_IPv4_Rx
)
155 , IFKW("tcp4csum", IFCAP_CSUM_TCPv4_Tx
|IFCAP_CSUM_TCPv4_Rx
)
156 , IFKW("udp4csum", IFCAP_CSUM_UDPv4_Tx
|IFCAP_CSUM_UDPv4_Rx
)
157 , IFKW("tcp6csum", IFCAP_CSUM_TCPv6_Tx
|IFCAP_CSUM_TCPv6_Rx
)
158 , IFKW("udp6csum", IFCAP_CSUM_UDPv6_Tx
|IFCAP_CSUM_UDPv6_Rx
)
159 , IFKW("tso4", IFCAP_TSOv4
)
160 , IFKW("tso6", IFCAP_TSOv6
)
163 extern struct pbranch command_root
;
164 extern struct pbranch opt_command
;
165 extern struct pbranch opt_family
, opt_silent_family
;
166 extern struct pkw cloning
, silent_family
, family
, ifcaps
, ifflags
, misc
;
168 struct pinteger parse_metric
= PINTEGER_INITIALIZER(&parse_metric
, "metric", 10,
169 setifmetric
, "metric", &command_root
.pb_parser
);
171 struct pinteger parse_mtu
= PINTEGER_INITIALIZER(&parse_mtu
, "mtu", 10,
172 setifmtu
, "mtu", &command_root
.pb_parser
);
174 struct pinteger parse_prefixlen
= PINTEGER_INITIALIZER(&parse_prefixlen
,
175 "prefixlen", 10, setifprefixlen
, "prefixlen", &command_root
.pb_parser
);
177 struct pinteger parse_preference
= PINTEGER_INITIALIZER1(&parse_preference
,
178 "preference", INT16_MIN
, INT16_MAX
, 10, NULL
, "preference",
179 &command_root
.pb_parser
);
181 struct paddr parse_netmask
= PADDR_INITIALIZER(&parse_netmask
, "netmask",
182 setifnetmask
, "dstormask", NULL
, NULL
, NULL
, &command_root
.pb_parser
);
184 struct paddr parse_broadcast
= PADDR_INITIALIZER(&parse_broadcast
,
186 setifbroadaddr
, "broadcast", NULL
, NULL
, NULL
, &command_root
.pb_parser
);
188 static const struct kwinst misckw
[] = {
189 {.k_word
= "alias", .k_key
= "alias", .k_deact
= "alias",
190 .k_type
= KW_T_BOOL
, .k_neg
= true,
191 .k_bool
= true, .k_negbool
= false,
192 .k_nextparser
= &command_root
.pb_parser
}
193 , {.k_word
= "broadcast", .k_nextparser
= &parse_broadcast
.pa_parser
}
194 , {.k_word
= "delete", .k_key
= "alias", .k_deact
= "alias",
195 .k_type
= KW_T_BOOL
, .k_bool
= false,
196 .k_nextparser
= &command_root
.pb_parser
}
197 , {.k_word
= "metric", .k_nextparser
= &parse_metric
.pi_parser
}
198 , {.k_word
= "mtu", .k_nextparser
= &parse_mtu
.pi_parser
}
199 , {.k_word
= "netmask", .k_nextparser
= &parse_netmask
.pa_parser
}
200 , {.k_word
= "preference", .k_act
= "address",
201 .k_nextparser
= &parse_preference
.pi_parser
}
202 , {.k_word
= "prefixlen", .k_nextparser
= &parse_prefixlen
.pi_parser
}
203 , {.k_word
= "trailers", .k_neg
= true,
204 .k_exec
= notrailers
, .k_nextparser
= &command_root
.pb_parser
}
208 static const struct kwinst clonekw
[] = {
209 {.k_word
= "create", .k_type
= KW_T_INT
, .k_int
= SIOCIFCREATE
,
210 .k_nextparser
= &opt_silent_family
.pb_parser
},
211 {.k_word
= "destroy", .k_type
= KW_T_INT
, .k_int
= SIOCIFDESTROY
}
214 static struct kwinst familykw
[24];
216 struct pterm cloneterm
= PTERM_INITIALIZER(&cloneterm
, "list cloners",
217 list_cloners
, "none");
219 struct pterm no_cmds
= PTERM_INITIALIZER(&no_cmds
, "no commands", no_cmds_exec
,
222 struct pkw family_only
=
223 PKW_INITIALIZER(&family_only
, "family-only", NULL
, "af", familykw
,
224 __arraycount(familykw
), &no_cmds
.pt_parser
);
226 struct paddr address
= PADDR_INITIALIZER(&address
,
227 "local address (address 1)",
228 setifaddr
, "address", "netmask", NULL
, "address", &command_root
.pb_parser
);
230 struct paddr dstormask
= PADDR_INITIALIZER(&dstormask
,
231 "destination/netmask (address 2)",
232 setifdstormask
, "dstormask", NULL
, "address", "dstormask",
233 &command_root
.pb_parser
);
235 struct paddr broadcast
= PADDR_INITIALIZER(&broadcast
,
236 "broadcast address (address 3)",
237 setifbroadaddr
, "broadcast", NULL
, "dstormask", "broadcast",
238 &command_root
.pb_parser
);
240 static SIMPLEQ_HEAD(, afswtch
) aflist
= SIMPLEQ_HEAD_INITIALIZER(aflist
);
242 static SIMPLEQ_HEAD(, usage_func
) usage_funcs
=
243 SIMPLEQ_HEAD_INITIALIZER(usage_funcs
);
244 static SIMPLEQ_HEAD(, status_func
) status_funcs
=
245 SIMPLEQ_HEAD_INITIALIZER(status_funcs
);
246 static SIMPLEQ_HEAD(, statistics_func
) statistics_funcs
=
247 SIMPLEQ_HEAD_INITIALIZER(statistics_funcs
);
248 static SIMPLEQ_HEAD(, cmdloop_branch
) cmdloop_branches
=
249 SIMPLEQ_HEAD_INITIALIZER(cmdloop_branches
);
251 struct branch opt_clone_brs
[] = {
252 {.b_nextparser
= &cloning
.pk_parser
}
253 , {.b_nextparser
= &opt_family
.pb_parser
}
254 }, opt_silent_family_brs
[] = {
255 {.b_nextparser
= &silent_family
.pk_parser
}
256 , {.b_nextparser
= &command_root
.pb_parser
}
257 }, opt_family_brs
[] = {
258 {.b_nextparser
= &family
.pk_parser
}
259 , {.b_nextparser
= &opt_command
.pb_parser
}
260 }, command_root_brs
[] = {
261 {.b_nextparser
= &ifflags
.pk_parser
}
262 , {.b_nextparser
= &ifcaps
.pk_parser
}
263 , {.b_nextparser
= &kwmedia
.pk_parser
}
264 , {.b_nextparser
= &misc
.pk_parser
}
265 , {.b_nextparser
= &address
.pa_parser
}
266 , {.b_nextparser
= &dstormask
.pa_parser
}
267 , {.b_nextparser
= &broadcast
.pa_parser
}
268 , {.b_nextparser
= NULL
}
269 }, opt_command_brs
[] = {
270 {.b_nextparser
= &no_cmds
.pt_parser
}
271 , {.b_nextparser
= &command_root
.pb_parser
}
274 struct branch opt_family_only_brs
[] = {
275 {.b_nextparser
= &no_cmds
.pt_parser
}
276 , {.b_nextparser
= &family_only
.pk_parser
}
278 struct pbranch opt_family_only
= PBRANCH_INITIALIZER(&opt_family_only
,
279 "opt-family-only", opt_family_only_brs
,
280 __arraycount(opt_family_only_brs
), true);
281 struct pbranch opt_command
= PBRANCH_INITIALIZER(&opt_command
,
283 opt_command_brs
, __arraycount(opt_command_brs
), true);
285 struct pbranch command_root
= PBRANCH_INITIALIZER(&command_root
,
286 "command-root", command_root_brs
, __arraycount(command_root_brs
), true);
288 struct piface iface_opt_family_only
=
289 PIFACE_INITIALIZER(&iface_opt_family_only
, "iface-opt-family-only",
290 NULL
, "if", &opt_family_only
.pb_parser
);
292 struct pkw family
= PKW_INITIALIZER(&family
, "family", NULL
, "af",
293 familykw
, __arraycount(familykw
), &opt_command
.pb_parser
);
295 struct pkw silent_family
= PKW_INITIALIZER(&silent_family
, "silent family",
296 NULL
, "af", familykw
, __arraycount(familykw
), &command_root
.pb_parser
);
298 struct pkw
*family_users
[] = {&family_only
, &family
, &silent_family
};
300 struct pkw ifcaps
= PKW_INITIALIZER(&ifcaps
, "ifcaps", setifcaps
,
301 "ifcap", ifcapskw
, __arraycount(ifcapskw
), &command_root
.pb_parser
);
303 struct pkw ifflags
= PKW_INITIALIZER(&ifflags
, "ifflags", setifflags
,
304 "ifflag", ifflagskw
, __arraycount(ifflagskw
), &command_root
.pb_parser
);
306 struct pkw cloning
= PKW_INITIALIZER(&cloning
, "cloning", clone_command
,
307 "clonecmd", clonekw
, __arraycount(clonekw
), NULL
);
309 struct pkw misc
= PKW_INITIALIZER(&misc
, "misc", NULL
, NULL
,
310 misckw
, __arraycount(misckw
), NULL
);
312 struct pbranch opt_clone
= PBRANCH_INITIALIZER(&opt_clone
,
313 "opt-clone", opt_clone_brs
, __arraycount(opt_clone_brs
), true);
315 struct pbranch opt_silent_family
= PBRANCH_INITIALIZER(&opt_silent_family
,
316 "optional silent family", opt_silent_family_brs
,
317 __arraycount(opt_silent_family_brs
), true);
319 struct pbranch opt_family
= PBRANCH_INITIALIZER(&opt_family
,
320 "opt-family", opt_family_brs
, __arraycount(opt_family_brs
), true);
322 struct piface iface_start
= PIFACE_INITIALIZER(&iface_start
,
323 "iface-opt-family", NULL
, "if", &opt_clone
.pb_parser
);
325 struct piface iface_only
= PIFACE_INITIALIZER(&iface_only
, "iface",
326 media_status_exec
, "if", NULL
);
329 flag_is_registered(const char *flags
, int flag
)
331 return flags
!= NULL
&& strchr(flags
, flag
) != NULL
;
335 check_flag(const char *flags
, int flag
)
337 if (flag_is_registered(flags
, flag
)) {
342 if (flag
>= '0' && flag
<= '9')
344 if (flag
>= 'a' && flag
<= 'z')
346 if (flag
>= 'A' && flag
<= 'Z')
354 cmdloop_branch_init(cmdloop_branch_t
*b
, struct parser
*p
)
360 statistics_func_init(statistics_func_t
*f
, statistics_cb_t func
)
366 status_func_init(status_func_t
*f
, status_cb_t func
)
372 usage_func_init(usage_func_t
*f
, usage_cb_t func
)
378 register_cmdloop_branch(cmdloop_branch_t
*b
)
380 SIMPLEQ_INSERT_TAIL(&cmdloop_branches
, b
, b_next
);
385 register_statistics(statistics_func_t
*f
)
387 SIMPLEQ_INSERT_TAIL(&statistics_funcs
, f
, f_next
);
392 register_status(status_func_t
*f
)
394 SIMPLEQ_INSERT_TAIL(&status_funcs
, f
, f_next
);
399 register_usage(usage_func_t
*f
)
401 SIMPLEQ_INSERT_TAIL(&usage_funcs
, f
, f_next
);
406 register_family(struct afswtch
*af
)
408 SIMPLEQ_INSERT_TAIL(&aflist
, af
, af_next
);
413 register_flag(int flag
)
415 if (check_flag(gflags
, flag
) == -1)
418 if (strlen(gflags
) + 1 >= sizeof(gflags
)) {
423 gflags
[strlen(gflags
)] = flag
;
431 if (flag
>= '0' && flag
<= '9')
433 if (flag
>= 'a' && flag
<= 'z')
434 return 10 + flag
- 'a';
435 if (flag
>= 'A' && flag
<= 'Z')
436 return 10 + 26 + flag
- 'a';
447 if ((idx
= flag_index(flag
)) == -1)
450 return gflagset
[idx
] = true;
458 if ((idx
= flag_index(flag
)) == -1)
461 return gflagset
[idx
];
464 static struct parser
*
469 if (parser_init(&iface_opt_family_only
.pif_parser
) == -1)
470 err(EXIT_FAILURE
, "parser_init(iface_opt_family_only)");
471 if (parser_init(&iface_only
.pif_parser
) == -1)
472 err(EXIT_FAILURE
, "parser_init(iface_only)");
473 if (parser_init(&iface_start
.pif_parser
) == -1)
474 err(EXIT_FAILURE
, "parser_init(iface_start)");
476 SIMPLEQ_FOREACH(b
, &cmdloop_branches
, b_next
)
477 pbranch_addbranch(&command_root
, b
->b_parser
);
479 return &iface_start
.pif_parser
;
483 no_cmds_exec(prop_dictionary_t env
, prop_dictionary_t oenv
)
486 unsigned short ignore
;
488 /* ifname == NULL is ok. It indicates 'ifconfig -a'. */
489 if ((ifname
= getifname(env
)) == NULL
)
491 else if (getifflags(env
, oenv
, &ignore
) == -1)
492 err(EXIT_FAILURE
, "SIOCGIFFLAGS %s", ifname
);
494 printall(ifname
, env
);
499 media_status_exec(prop_dictionary_t env
, prop_dictionary_t oenv
)
502 unsigned short ignore
;
504 /* ifname == NULL is ok. It indicates 'ifconfig -a'. */
505 if ((ifname
= getifname(env
)) == NULL
)
507 else if (getifflags(env
, oenv
, &ignore
) == -1)
508 err(EXIT_FAILURE
, "SIOCGIFFLAGS %s", ifname
);
514 do_setifcaps(prop_dictionary_t env
)
516 struct ifcapreq ifcr
;
519 d
= (prop_data_t
)prop_dictionary_get(env
, "ifcaps");
523 assert(sizeof(ifcr
) == prop_data_size(d
));
525 memcpy(&ifcr
, prop_data_data_nocopy(d
), sizeof(ifcr
));
526 if (direct_ioctl(env
, SIOCSIFCAP
, &ifcr
) == -1)
527 err(EXIT_FAILURE
, "SIOCSIFCAP");
531 main(int argc
, char **argv
)
533 const struct afswtch
*afp
;
535 bool aflag
= false, Cflag
= false;
536 struct match match
[32];
538 struct parser
*start
;
539 int ch
, narg
= 0, rc
;
540 prop_dictionary_t env
, oenv
;
546 memset(match
, 0, sizeof(match
));
550 start
= init_parser();
552 /* Parse command-line options */
553 aflag
= Nflag
= vflag
= zflag
= false;
554 while ((ch
= getopt(argc
, argv
, gflags
)) != -1) {
557 warnx("-A is deprecated");
608 start
= &opt_family_only
.pb_parser
;
615 if (start
!= &opt_family_only
.pb_parser
)
616 start
= &iface_opt_family_only
.pif_parser
;
619 start
= &cloneterm
.pt_parser
;
622 start
= &no_cmds
.pt_parser
;
625 if (start
!= &no_cmds
.pt_parser
&&
626 start
!= &opt_family_only
.pb_parser
)
627 start
= &iface_only
.pif_parser
;
637 * -l means "list all interfaces", and is mutally exclusive with
638 * all other flags/commands.
640 * -C means "list all names of cloners", and it mutually exclusive
641 * with all other flags/commands.
643 * -a means "print status of all interfaces".
645 if ((lflag
|| Cflag
) && (aflag
|| get_flag('m') || vflag
|| zflag
))
647 if ((lflag
|| Cflag
) && get_flag('L'))
652 nmatch
= __arraycount(match
);
654 rc
= parse(argc
, argv
, start
, match
, &nmatch
, &narg
);
658 if ((oenv
= prop_dictionary_create()) == NULL
)
659 err(EXIT_FAILURE
, "%s: prop_dictionary_create", __func__
);
661 if (matches_exec(match
, oenv
, nmatch
) == -1)
662 err(EXIT_FAILURE
, "exec_matches");
667 env
= (nmatch
> 0) ? match
[(int)nmatch
- 1].m_env
: NULL
;
671 env
= prop_dictionary_augment(env
, oenv
);
673 /* Process any media commands that may have been issued. */
674 process_media_commands(env
);
676 if ((af
= getaf(env
)) == -1)
679 if ((s
= getsock(af
)) == -1)
680 err(EXIT_FAILURE
, "%s: getsock", __func__
);
682 if ((ifname
= getifname(env
)) == NULL
)
683 err(EXIT_FAILURE
, "%s: getifname", __func__
);
685 if ((afp
= lookup_af_bynum(af
)) == NULL
)
686 errx(EXIT_FAILURE
, "%s: lookup_af_bynum", __func__
);
688 assert(afp
->af_addr_commit
!= NULL
);
689 (*afp
->af_addr_commit
)(env
, oenv
);
691 do_setifpreference(env
);
701 const struct afswtch
*afp
;
702 struct kwinst kw
= {.k_type
= KW_T_INT
};
704 SIMPLEQ_FOREACH(afp
, &aflist
, af_next
) {
705 kw
.k_word
= afp
->af_name
;
706 kw
.k_int
= afp
->af_af
;
707 for (i
= 0; i
< __arraycount(familykw
); i
++) {
708 if (familykw
[i
].k_word
== NULL
) {
716 const struct afswtch
*
717 lookup_af_bynum(int afnum
)
719 const struct afswtch
*afp
;
721 SIMPLEQ_FOREACH(afp
, &aflist
, af_next
) {
722 if (afp
->af_af
== afnum
)
729 printall(const char *ifname
, prop_dictionary_t env0
)
731 struct ifaddrs
*ifap
, *ifa
;
733 const struct sockaddr
*sdl
= NULL
;
734 prop_dictionary_t env
, oenv
;
739 env
= prop_dictionary_create();
741 env
= prop_dictionary_copy_mutable(env0
);
743 oenv
= prop_dictionary_create();
745 if (env
== NULL
|| oenv
== NULL
)
746 errx(EXIT_FAILURE
, "%s: prop_dictionary_copy/create", __func__
);
748 if (getifaddrs(&ifap
) != 0)
749 err(EXIT_FAILURE
, "getifaddrs");
752 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
753 memset(&ifr
, 0, sizeof(ifr
));
754 estrlcpy(ifr
.ifr_name
, ifa
->ifa_name
, sizeof(ifr
.ifr_name
));
755 if (sizeof(ifr
.ifr_addr
) >= ifa
->ifa_addr
->sa_len
) {
756 memcpy(&ifr
.ifr_addr
, ifa
->ifa_addr
,
757 ifa
->ifa_addr
->sa_len
);
760 if (ifname
!= NULL
&& strcmp(ifname
, ifa
->ifa_name
) != 0)
762 if (ifa
->ifa_addr
->sa_family
== AF_LINK
)
764 if (p
&& strcmp(p
, ifa
->ifa_name
) == 0)
766 if (!prop_dictionary_set_cstring(env
, "if", ifa
->ifa_name
))
770 if (bflag
&& (ifa
->ifa_flags
& IFF_BROADCAST
) == 0)
772 if (dflag
&& (ifa
->ifa_flags
& IFF_UP
) != 0)
774 if (uflag
&& (ifa
->ifa_flags
& IFF_UP
) == 0)
777 if (sflag
&& carrier(env
))
781 * Are we just listing the interfaces?
786 fputs(ifa
->ifa_name
, stdout
);
790 status(sdl
, env
, oenv
);
795 prop_object_release((prop_object_t
)env
);
796 prop_object_release((prop_object_t
)oenv
);
801 list_cloners(prop_dictionary_t env
, prop_dictionary_t oenv
)
803 struct if_clonereq ifcr
;
807 memset(&ifcr
, 0, sizeof(ifcr
));
809 s
= getsock(AF_INET
);
811 if (ioctl(s
, SIOCIFGCLONERS
, &ifcr
) == -1)
812 err(EXIT_FAILURE
, "SIOCIFGCLONERS for count");
814 buf
= malloc(ifcr
.ifcr_total
* IFNAMSIZ
);
816 err(EXIT_FAILURE
, "unable to allocate cloner name buffer");
818 ifcr
.ifcr_count
= ifcr
.ifcr_total
;
819 ifcr
.ifcr_buffer
= buf
;
821 if (ioctl(s
, SIOCIFGCLONERS
, &ifcr
) == -1)
822 err(EXIT_FAILURE
, "SIOCIFGCLONERS for names");
825 * In case some disappeared in the mean time, clamp it down.
827 if (ifcr
.ifcr_count
> ifcr
.ifcr_total
)
828 ifcr
.ifcr_count
= ifcr
.ifcr_total
;
830 for (cp
= buf
, idx
= 0; idx
< ifcr
.ifcr_count
; idx
++, cp
+= IFNAMSIZ
) {
842 clone_command(prop_dictionary_t env
, prop_dictionary_t oenv
)
846 if (!prop_dictionary_get_int64(env
, "clonecmd", &cmd
)) {
851 if (indirect_ioctl(env
, (unsigned long)cmd
, NULL
) == -1) {
852 warn("%s", __func__
);
860 setifaddr(prop_dictionary_t env
, prop_dictionary_t oenv
)
862 const struct paddr_prefix
*pfx0
;
863 struct paddr_prefix
*pfx
;
867 if ((af
= getaf(env
)) == -1)
870 d
= (prop_data_t
)prop_dictionary_get(env
, "address");
872 pfx0
= prop_data_data_nocopy(d
);
874 if (pfx0
->pfx_len
>= 0) {
875 pfx
= prefixlen_to_mask(af
, pfx0
->pfx_len
);
877 err(EXIT_FAILURE
, "prefixlen_to_mask");
885 setifnetmask(prop_dictionary_t env
, prop_dictionary_t oenv
)
887 const struct paddr_prefix
*pfx
;
890 d
= (prop_data_t
)prop_dictionary_get(env
, "dstormask");
892 pfx
= prop_data_data_nocopy(d
);
894 if (!prop_dictionary_set(oenv
, "netmask", (prop_object_t
)d
))
901 setifbroadaddr(prop_dictionary_t env
, prop_dictionary_t oenv
)
903 const struct paddr_prefix
*pfx
;
905 unsigned short flags
;
907 if (getifflags(env
, oenv
, &flags
) == -1)
908 err(EXIT_FAILURE
, "%s: getifflags", __func__
);
910 if ((flags
& IFF_BROADCAST
) == 0)
911 errx(EXIT_FAILURE
, "not a broadcast interface");
913 d
= (prop_data_t
)prop_dictionary_get(env
, "broadcast");
915 pfx
= prop_data_data_nocopy(d
);
917 if (!prop_dictionary_set(oenv
, "broadcast", (prop_object_t
)d
))
925 notrailers(prop_dictionary_t env
, prop_dictionary_t oenv
)
927 puts("Note: trailers are no longer sent, but always received");
933 setifdstormask(prop_dictionary_t env
, prop_dictionary_t oenv
)
936 const struct paddr_prefix
*pfx
;
938 unsigned short flags
;
940 if (getifflags(env
, oenv
, &flags
) == -1)
941 err(EXIT_FAILURE
, "%s: getifflags", __func__
);
943 d
= (prop_data_t
)prop_dictionary_get(env
, "dstormask");
945 pfx
= prop_data_data_nocopy(d
);
947 if ((flags
& IFF_BROADCAST
) == 0) {
953 if (!prop_dictionary_set(oenv
, key
, (prop_object_t
)d
))
960 setifflags(prop_dictionary_t env
, prop_dictionary_t oenv
)
966 rc
= prop_dictionary_get_int64(env
, "ifflag", &ifflag
);
969 if (direct_ioctl(env
, SIOCGIFFLAGS
, &ifr
) == -1)
974 ifr
.ifr_flags
&= ~ifflag
;
976 ifr
.ifr_flags
|= ifflag
;
978 if (direct_ioctl(env
, SIOCSIFFLAGS
, &ifr
) == -1)
985 getifcaps(prop_dictionary_t env
, prop_dictionary_t oenv
, struct ifcapreq
*oifcr
)
988 struct ifcapreq ifcr
;
989 const struct ifcapreq
*tmpifcr
;
992 capdata
= (prop_data_t
)prop_dictionary_get(env
, "ifcaps");
994 if (capdata
!= NULL
) {
995 tmpifcr
= prop_data_data_nocopy(capdata
);
1000 (void)direct_ioctl(env
, SIOCGIFCAP
, &ifcr
);
1003 capdata
= prop_data_create_data(&ifcr
, sizeof(ifcr
));
1005 rc
= prop_dictionary_set(oenv
, "ifcaps", capdata
);
1007 prop_object_release((prop_object_t
)capdata
);
1013 setifcaps(prop_dictionary_t env
, prop_dictionary_t oenv
)
1018 prop_data_t capdata
;
1019 struct ifcapreq ifcr
;
1021 s
= getsock(AF_INET
);
1023 rc
= prop_dictionary_get_int64(env
, "ifcap", &ifcap
);
1026 if (getifcaps(env
, oenv
, &ifcr
) == -1)
1031 ifcr
.ifcr_capenable
&= ~ifcap
;
1033 ifcr
.ifcr_capenable
|= ifcap
;
1035 if ((capdata
= prop_data_create_data(&ifcr
, sizeof(ifcr
))) == NULL
)
1038 rc
= prop_dictionary_set(oenv
, "ifcaps", capdata
);
1039 prop_object_release((prop_object_t
)capdata
);
1045 setifmetric(prop_dictionary_t env
, prop_dictionary_t oenv
)
1051 rc
= prop_dictionary_get_int64(env
, "metric", &metric
);
1054 ifr
.ifr_metric
= metric
;
1055 if (direct_ioctl(env
, SIOCSIFMETRIC
, &ifr
) == -1)
1056 warn("SIOCSIFMETRIC");
1061 do_setifpreference(prop_dictionary_t env
)
1063 struct if_addrprefreq ifap
;
1065 const struct paddr_prefix
*pfx
;
1067 memset(&ifap
, 0, sizeof(ifap
));
1069 if (!prop_dictionary_get_int16(env
, "preference",
1070 &ifap
.ifap_preference
))
1073 d
= (prop_data_t
)prop_dictionary_get(env
, "address");
1076 pfx
= prop_data_data_nocopy(d
);
1078 memcpy(&ifap
.ifap_addr
, &pfx
->pfx_addr
,
1079 MIN(sizeof(ifap
.ifap_addr
), pfx
->pfx_addr
.sa_len
));
1080 if (direct_ioctl(env
, SIOCSIFADDRPREF
, &ifap
) == -1)
1081 warn("SIOCSIFADDRPREF");
1085 setifmtu(prop_dictionary_t env
, prop_dictionary_t oenv
)
1091 rc
= prop_dictionary_get_int64(env
, "mtu", &mtu
);
1095 if (direct_ioctl(env
, SIOCSIFMTU
, &ifr
) == -1)
1102 carrier(prop_dictionary_t env
)
1104 struct ifmediareq ifmr
;
1106 memset(&ifmr
, 0, sizeof(ifmr
));
1108 if (direct_ioctl(env
, SIOCGIFMEDIA
, &ifmr
) == -1) {
1110 * Interface doesn't support SIOC{G,S}IFMEDIA;
1113 return EXIT_SUCCESS
;
1115 if ((ifmr
.ifm_status
& IFM_AVALID
) == 0) {
1117 * Interface doesn't report media-valid status.
1120 return EXIT_SUCCESS
;
1122 /* otherwise, return ok for active, not-ok if not active. */
1123 if (ifmr
.ifm_status
& IFM_ACTIVE
)
1124 return EXIT_SUCCESS
;
1126 return EXIT_FAILURE
;
1130 print_plural(const char *prefix
, uint64_t n
, const char *unit
)
1132 printf("%s%" PRIu64
" %s%s", prefix
, n
, unit
, (n
== 1) ? "" : "s");
1136 print_human_bytes(bool humanize
, uint64_t n
)
1141 (void)humanize_number(buf
, sizeof(buf
),
1142 (int64_t)n
, "", HN_AUTOSCALE
, HN_NOSPACE
| HN_DECIMAL
);
1143 printf(", %s byte%s", buf
, (atof(buf
) == 1.0) ? "" : "s");
1145 print_plural(", ", n
, "byte");
1149 * Print the status of the interface. If an address family was
1150 * specified, show it and it only; otherwise, show them all.
1153 status(const struct sockaddr
*sdl
, prop_dictionary_t env
,
1154 prop_dictionary_t oenv
)
1156 const struct if_data
*ifi
;
1157 status_func_t
*status_f
;
1158 statistics_func_t
*statistics_f
;
1159 struct ifdatareq ifdr
;
1164 struct ifcapreq ifcr
;
1165 unsigned short flags
;
1166 const struct afswtch
*afp
;
1168 if ((af
= getaf(env
)) == -1) {
1172 afp
= lookup_af_bynum(af
);
1174 /* get out early if the family is unsupported by the kernel */
1175 if ((s
= getsock(af
)) == -1)
1176 err(EXIT_FAILURE
, "%s: getsock", __func__
);
1178 if ((ifname
= getifinfo(env
, oenv
, &flags
)) == NULL
)
1179 err(EXIT_FAILURE
, "%s: getifinfo", __func__
);
1181 (void)snprintb(fbuf
, sizeof(fbuf
), IFFBITS
, flags
);
1182 printf("%s: flags=%s", ifname
, &fbuf
[2]);
1184 estrlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
1185 if (ioctl(s
, SIOCGIFMETRIC
, &ifr
) == -1)
1186 warn("SIOCGIFMETRIC %s", ifr
.ifr_name
);
1187 else if (ifr
.ifr_metric
!= 0)
1188 printf(" metric %d", ifr
.ifr_metric
);
1190 estrlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
1191 if (ioctl(s
, SIOCGIFMTU
, &ifr
) != -1 && ifr
.ifr_mtu
!= 0)
1192 printf(" mtu %d", ifr
.ifr_mtu
);
1195 if (getifcaps(env
, oenv
, &ifcr
) == -1)
1196 err(EXIT_FAILURE
, "%s: getifcaps", __func__
);
1198 if (ifcr
.ifcr_capabilities
!= 0) {
1199 (void)snprintb(fbuf
, sizeof(fbuf
), IFCAPBITS
,
1200 ifcr
.ifcr_capabilities
);
1201 printf("\tcapabilities=%s\n", &fbuf
[2]);
1202 (void)snprintb(fbuf
, sizeof(fbuf
), IFCAPBITS
,
1203 ifcr
.ifcr_capenable
);
1204 printf("\tenabled=%s\n", &fbuf
[2]);
1207 SIMPLEQ_FOREACH(status_f
, &status_funcs
, f_next
)
1208 (*status_f
->f_func
)(env
, oenv
);
1210 print_link_addresses(env
, true);
1212 media_status(env
, oenv
);
1214 if (!vflag
&& !zflag
)
1217 estrlcpy(ifdr
.ifdr_name
, ifname
, sizeof(ifdr
.ifdr_name
));
1219 if (ioctl(s
, zflag
? SIOCZIFDATA
: SIOCGIFDATA
, &ifdr
) == -1)
1220 err(EXIT_FAILURE
, zflag
? "SIOCZIFDATA" : "SIOCGIFDATA");
1222 ifi
= &ifdr
.ifdr_data
;
1224 print_plural("\tinput: ", ifi
->ifi_ipackets
, "packet");
1225 print_human_bytes(hflag
, ifi
->ifi_ibytes
);
1226 if (ifi
->ifi_imcasts
)
1227 print_plural(", ", ifi
->ifi_imcasts
, "multicast");
1228 if (ifi
->ifi_ierrors
)
1229 print_plural(", ", ifi
->ifi_ierrors
, "error");
1230 if (ifi
->ifi_iqdrops
)
1231 print_plural(", ", ifi
->ifi_iqdrops
, "queue drop");
1232 if (ifi
->ifi_noproto
)
1233 printf(", %" PRIu64
" unknown protocol", ifi
->ifi_noproto
);
1234 print_plural("\n\toutput: ", ifi
->ifi_opackets
, "packet");
1235 print_human_bytes(hflag
, ifi
->ifi_obytes
);
1236 if (ifi
->ifi_omcasts
)
1237 print_plural(", ", ifi
->ifi_omcasts
, "multicast");
1238 if (ifi
->ifi_oerrors
)
1239 print_plural(", ", ifi
->ifi_oerrors
, "error");
1240 if (ifi
->ifi_collisions
)
1241 print_plural(", ", ifi
->ifi_collisions
, "collision");
1244 SIMPLEQ_FOREACH(statistics_f
, &statistics_funcs
, f_next
)
1245 (*statistics_f
->f_func
)(env
);
1250 (*afp
->af_status
)(env
, oenv
, true);
1251 else SIMPLEQ_FOREACH(afp
, &aflist
, af_next
)
1252 (*afp
->af_status
)(env
, oenv
, false);
1256 setifprefixlen(prop_dictionary_t env
, prop_dictionary_t oenv
)
1261 struct paddr_prefix
*pfx
;
1264 if ((af
= getaf(env
)) == -1)
1267 rc
= prop_dictionary_get_int64(env
, "prefixlen", &plen
);
1270 pfx
= prefixlen_to_mask(af
, plen
);
1272 err(EXIT_FAILURE
, "prefixlen_to_mask");
1274 d
= prop_data_create_data(pfx
, paddr_prefix_size(pfx
));
1276 err(EXIT_FAILURE
, "%s: prop_data_create_data", __func__
);
1278 if (!prop_dictionary_set(oenv
, "netmask", (prop_object_t
)d
))
1279 err(EXIT_FAILURE
, "%s: prop_dictionary_set", __func__
);
1288 const char *progname
= getprogname();
1289 usage_func_t
*usage_f
;
1290 prop_dictionary_t env
;
1292 if ((env
= prop_dictionary_create()) == NULL
)
1293 err(EXIT_FAILURE
, "%s: prop_dictionary_create", __func__
);
1295 fprintf(stderr
, "usage: %s [-h] %s[-v] [-z] %sinterface\n"
1296 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
1297 "\t\t[ alias | -alias ] ]\n"
1298 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n", progname
,
1299 flag_is_registered(gflags
, 'm') ? "[-m] " : "",
1300 flag_is_registered(gflags
, 'L') ? "[-L] " : "");
1302 SIMPLEQ_FOREACH(usage_f
, &usage_funcs
, f_next
)
1303 (*usage_f
->f_func
)(env
);
1306 "\t[ arp | -arp ]\n"
1307 "\t[ preference n ]\n"
1308 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
1309 " %s -a [-b] [-d] [-h] %s[-u] [-v] [-z] [ af ]\n"
1310 " %s -l [-b] [-d] [-s] [-u]\n"
1312 " %s interface create\n"
1313 " %s interface destroy\n",
1314 progname
, flag_is_registered(gflags
, 'm') ? "[-m] " : "",
1315 progname
, progname
, progname
, progname
);
1317 prop_object_release((prop_object_t
)env
);