1 /* $OpenBSD: ifconfig.c,v 1.475 2025/01/06 17:49:29 denis Exp $ */
2 /* $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $ */
3
4 /*
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*-
34 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
35 * All rights reserved.
36 *
37 * This code is derived from software contributed to The NetBSD Foundation
38 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
39 * NASA Ames Research Center.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60 * POSSIBILITY OF SUCH DAMAGE.
61 */
62
63 #include <sys/socket.h>
64 #include <sys/ioctl.h>
65 #include <sys/time.h>
66
67 #include <net/if.h>
68 #include <net/if_dl.h>
69 #include <net/if_media.h>
70 #include <net/if_types.h>
71 #include <netinet/in.h>
72 #include <netinet/in_var.h>
73 #include <netinet6/in6_var.h>
74 #include <netinet6/nd6.h>
75 #include <arpa/inet.h>
76 #include <netinet/ip_ipsp.h>
77 #include <netinet/if_ether.h>
78 #include <net80211/ieee80211.h>
79 #include <net80211/ieee80211_ioctl.h>
80 #include <net/pfvar.h>
81 #include <net/if_pfsync.h>
82 #include <net/if_pflow.h>
83 #include <net/if_pppoe.h>
84 #include <net/if_trunk.h>
85 #include <net/if_wg.h>
86 #include <net/trunklacp.h>
87 #include <net/if_sppp.h>
88 #include <net/ppp_defs.h>
89
90 #include <netinet/ip_carp.h>
91
92 #include <netdb.h>
93
94 #include <net/if_vlan_var.h>
95
96 #include <netmpls/mpls.h>
97
98 #include <ctype.h>
99 #include <err.h>
100 #include <errno.h>
101 #include <stdio.h>
102 #include <stdint.h>
103 #include <stdlib.h>
104 #include <stddef.h>
105 #include <string.h>
106 #include <unistd.h>
107 #include <limits.h>
108 #include <resolv.h>
109 #include <util.h>
110 #include <ifaddrs.h>
111
112 #ifndef SMALL
113 #include <dev/usb/mbim.h>
114 #include <dev/usb/if_umb.h>
115 #endif /* SMALL */
116
117 #include "ifconfig.h"
118
119 #ifndef nitems
120 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
121 #endif
122
123 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
124 #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
125
126 #define HWFEATURESBITS \
127 "\024\1CSUM_IPv4\2CSUM_TCPv4\3CSUM_UDPv4" \
128 "\5VLAN_MTU\6VLAN_HWTAGGING\7VLAN_HWOFFLOAD\10CSUM_TCPv6" \
129 "\11CSUM_UDPv6\15TSOv4\16TSOv6\17LRO\20WOL"
130
131 struct ifencap {
132 unsigned int ife_flags;
133 #define IFE_VNETID_MASK 0xf
134 #define IFE_VNETID_NOPE 0x0
135 #define IFE_VNETID_NONE 0x1
136 #define IFE_VNETID_ANY 0x2
137 #define IFE_VNETID_SET 0x3
138 int64_t ife_vnetid;
139 #define IFE_VNETFLOWID 0x10
140
141 #define IFE_PARENT_MASK 0xf00
142 #define IFE_PARENT_NOPE 0x000
143 #define IFE_PARENT_NONE 0x100
144 #define IFE_PARENT_SET 0x200
145 char ife_parent[IFNAMSIZ];
146
147 #define IFE_TXHPRIO_SET 0x1000
148 int ife_txhprio;
149 #define IFE_RXHPRIO_SET 0x2000
150 int ife_rxhprio;
151 };
152
153 struct ifreq ifr, ridreq;
154 struct in_aliasreq in_addreq;
155 struct in6_ifreq ifr6;
156 struct in6_ifreq in6_ridreq;
157 struct in6_aliasreq in6_addreq;
158 struct sockaddr_in netmask;
159
160 #ifndef SMALL
161 int rdomainid;
162 #endif /* SMALL */
163
164 char ifname[IFNAMSIZ];
165 int flags, xflags, setaddr, setipdst, doalias;
166 u_long metric, mtu;
167 int llprio;
168 int clearaddr, sock;
169 int newaddr = 0;
170 int af = AF_INET;
171 int explicit_prefix = 0;
172 int Lflag = 1;
173 int show_join = 0;
174
175 int showmediaflag;
176 int showcapsflag;
177 int shownet80211chans;
178 int shownet80211nodes;
179 int showclasses;
180 int showtransceiver;
181
182 struct ifencap;
183
184 struct ieee80211_join join;
185
186 const char *lacpmodeactive = "active";
187 const char *lacpmodepassive = "passive";
188 const char *lacptimeoutfast = "fast";
189 const char *lacptimeoutslow = "slow";
190
191 void notealias(const char *, int);
192 void setifaddr(const char *, int);
193 void setiflladdr(const char *, int);
194 void setifdstaddr(const char *, int);
195 void setifflags(const char *, int);
196 void setifxflags(const char *, int);
197 void addaf(const char *, int);
198 void removeaf(const char *, int);
199 void setifbroadaddr(const char *, int);
200 void setifmtu(const char *, int);
201 void setifllprio(const char *, int);
202 void setifnwid(const char *, int);
203 void setifjoin(const char *, int);
204 void delifjoin(const char *, int);
205 void delifjoinlist(const char *, int);
206 void showjoin(const char *, int);
207 void setifbssid(const char *, int);
208 void setifnwkey(const char *, int);
209 void setifwpa(const char *, int);
210 void setifwpaprotos(const char *, int);
211 void setifwpaakms(const char *, int);
212 void setifwpaciphers(const char *, int);
213 void setifwpagroupcipher(const char *, int);
214 void setifwpakey(const char *, int);
215 void setifchan(const char *, int);
216 void setifscan(const char *, int);
217 void setifnwflag(const char *, int);
218 void unsetifnwflag(const char *, int);
219 void setifnetmask(const char *, int);
220 void setifprefixlen(const char *, int);
221 void setvnetid(const char *, int);
222 void delvnetid(const char *, int);
223 void getvnetid(struct ifencap *);
224 void setifparent(const char *, int);
225 void delifparent(const char *, int);
226 void getifparent(struct ifencap *);
227 void getencap(void);
228 void setia6flags(const char *, int);
229 void setia6pltime(const char *, int);
230 void setia6vltime(const char *, int);
231 void setia6lifetime(const char *, const char *);
232 void setia6eui64(const char *, int);
233 void setmedia(const char *, int);
234 void setmediaopt(const char *, int);
235 void setmediamode(const char *, int);
236 void unsetmediamode(const char *, int);
237 void clone_create(const char *, int);
238 void clone_destroy(const char *, int);
239 void unsetmediaopt(const char *, int);
240 void setmediainst(const char *, int);
241 int prefix(void *val, int);
242 void getifgroups(void);
243 void setifgroup(const char *, int);
244 void unsetifgroup(const char *, int);
245 void setgroupattribs(char *, int, char *[]);
246 int printgroup(char *, int);
247 void setautoconf(const char *, int);
248 void settemporary(const char *, int);
249 void settrunkport(const char *, int);
250 void unsettrunkport(const char *, int);
251 void settrunkproto(const char *, int);
252 void settrunklacpmode(const char *, int);
253 void settrunklacptimeout(const char *, int);
254 void trunk_status(void);
255 void list_cloners(void);
256
257 #ifndef SMALL
258 void setifrtlabel(const char *, int);
259 void setrdomain(const char *, int);
260 void unsetrdomain(const char *, int);
261 void setkeepalive(const char *, const char *);
262 void unsetkeepalive(const char *, int);
263 void carp_status(void);
264 void setcarp_advbase(const char *,int);
265 void setcarp_advskew(const char *, int);
266 void setcarppeer(const char *, int);
267 void unsetcarppeer(const char *, int);
268 void setcarp_passwd(const char *, int);
269 void setcarp_vhid(const char *, int);
270 void setcarp_state(const char *, int);
271 void setcarpdev(const char *, int);
272 void setcarp_nodes(const char *, int);
273 void setcarp_balancing(const char *, int);
274 void setpfsync_syncdev(const char *, int);
275 void setpfsync_maxupd(const char *, int);
276 void unsetpfsync_syncdev(const char *, int);
277 void setpfsync_syncpeer(const char *, int);
278 void unsetpfsync_syncpeer(const char *, int);
279 void setpfsync_defer(const char *, int);
280 void pfsync_status(void);
281 void setvnetflowid(const char *, int);
282 void delvnetflowid(const char *, int);
283 void getvnetflowid(struct ifencap *);
284 void gettxprio(struct ifencap *);
285 void settxprio(const char *, int);
286 void getrxprio(struct ifencap *);
287 void setrxprio(const char *, int);
288 void setmplslabel(const char *, int);
289 void unsetmplslabel(const char *, int);
290 void setpwe3cw(const char *, int);
291 void unsetpwe3cw(const char *, int);
292 void setpwe3fat(const char *, int);
293 void unsetpwe3fat(const char *, int);
294 void setpwe3neighbor(const char *, const char *);
295 void unsetpwe3neighbor(const char *, int);
296 void mpls_status(void);
297 void settunnel(const char *, const char *);
298 void settunneladdr(const char *, int);
299 void deletetunnel(const char *, int);
300 void settunnelinst(const char *, int);
301 void unsettunnelinst(const char *, int);
302 void settunnelttl(const char *, int);
303 void settunneldf(const char *, int);
304 void settunnelnodf(const char *, int);
305 void settunnelecn(const char *, int);
306 void settunnelnoecn(const char *, int);
307 void setpppoe_dev(const char *,int);
308 void setpppoe_svc(const char *,int);
309 void setpppoe_ac(const char *,int);
310 void pppoe_status(void);
311 void setspppproto(const char *, int);
312 void setspppname(const char *, int);
313 void setspppkey(const char *, int);
314 void setsppppeerproto(const char *, int);
315 void setsppppeername(const char *, int);
316 void setsppppeerkey(const char *, int);
317 void setsppppeerflag(const char *, int);
318 void unsetsppppeerflag(const char *, int);
319 void sppp_status(void);
320 void sppp_printproto(const char *, struct sauthreq *);
321 void setifpriority(const char *, int);
322 void setifpowersave(const char *, int);
323 void setifmetric(const char *, int);
324 void pflow_status(void);
325 void pflow_addr(const char*, struct sockaddr_storage *);
326 void setpflow_sender(const char *, int);
327 void unsetpflow_sender(const char *, int);
328 void setpflow_receiver(const char *, int);
329 void unsetpflow_receiver(const char *, int);
330 void setpflowproto(const char *, int);
331 void setifipdst(const char *, int);
332 void setifdesc(const char *, int);
333 void unsetifdesc(const char *, int);
334 void printifhwfeatures(const char *, int);
335 void setpair(const char *, int);
336 void unsetpair(const char *, int);
337 void umb_status(void);
338 void umb_printclasses(char *, int);
339 int umb_parse_classes(const char *);
340 void umb_setpin(const char *, int);
341 void umb_chgpin(const char *, const char *);
342 void umb_puk(const char *, const char *);
343 void umb_pinop(int, int, const char *, const char *);
344 void umb_apn(const char *, int);
345 void umb_setclass(const char *, int);
346 void umb_roaming(const char *, int);
347 void utf16_to_char(uint16_t *, int, char *, size_t);
348 int char_to_utf16(const char *, uint16_t *, size_t);
349 void transceiver(const char *, int);
350 void transceiverdump(const char *, int);
351
352 /* WG */
353 void setwgpeer(const char *, int);
354 void setwgpeerdesc(const char *, int);
355 void setwgpeerep(const char *, const char *);
356 void setwgpeeraip(const char *, int);
357 void setwgpeerpsk(const char *, int);
358 void setwgpeerpka(const char *, int);
359 void setwgport(const char *, int);
360 void setwgkey(const char *, int);
361 void setwgrtable(const char *, int);
362
363 void unsetwgpeer(const char *, int);
364 void unsetwgpeerdesc(const char *, int);
365 void unsetwgpeerpsk(const char *, int);
366 void unsetwgpeerall(const char *, int);
367
368 void wg_status(int);
369 #else
370 void setignore(const char *, int);
371 #endif
372
373 struct if_clonereq *get_cloners(void);
374 int findmac(const char *);
375
376 /*
377 * Media stuff. Whenever a media command is first performed, the
378 * currently select media is grabbed for this interface. If `media'
379 * is given, the current media word is modified. `mediaopt' commands
380 * only modify the set and clear words. They then operate on the
381 * current media word later.
382 */
383 uint64_t media_current;
384 uint64_t mediaopt_set;
385 uint64_t mediaopt_clear;
386
387 int actions; /* Actions performed */
388
389 #define A_MEDIA 0x0001 /* media command */
390 #define A_MEDIAOPTSET 0x0002 /* mediaopt command */
391 #define A_MEDIAOPTCLR 0x0004 /* -mediaopt command */
392 #define A_MEDIAOPT (A_MEDIAOPTSET|A_MEDIAOPTCLR)
393 #define A_MEDIAINST 0x0008 /* instance or inst command */
394 #define A_MEDIAMODE 0x0010 /* mode command */
395 #define A_JOIN 0x0020 /* join */
396 #define A_WIREGUARD 0x0040 /* any WireGuard command */
397 #define A_SILENT 0x8000000 /* doing operation, do not print */
398
399 #define NEXTARG0 0xffffff
400 #define NEXTARG 0xfffffe
401 #define NEXTARG2 0xfffffd
402
403 const struct cmd {
404 char *c_name;
405 int c_parameter; /* NEXTARG means next argv */
406 int c_action; /* defered action */
407 void (*c_func)(const char *, int);
408 void (*c_func2)(const char *, const char *);
409 } cmds[] = {
410 { "up", IFF_UP, 0, setifflags } ,
411 { "down", -IFF_UP, 0, setifflags },
412 { "arp", -IFF_NOARP, 0, setifflags },
413 { "-arp", IFF_NOARP, 0, setifflags },
414 { "debug", IFF_DEBUG, 0, setifflags },
415 { "-debug", -IFF_DEBUG, 0, setifflags },
416 { "alias", IFF_UP, 0, notealias },
417 { "-alias", -IFF_UP, 0, notealias },
418 { "delete", -IFF_UP, 0, notealias },
419 { "netmask", NEXTARG, 0, setifnetmask },
420 { "mtu", NEXTARG, 0, setifmtu },
421 { "nwid", NEXTARG, 0, setifnwid },
422 { "-nwid", -1, 0, setifnwid },
423 { "join", NEXTARG, 0, setifjoin },
424 { "-join", NEXTARG, 0, delifjoin },
425 { "joinlist", NEXTARG0, 0, showjoin },
426 { "-joinlist", -1, 0, delifjoinlist },
427 { "bssid", NEXTARG, 0, setifbssid },
428 { "-bssid", -1, 0, setifbssid },
429 { "nwkey", NEXTARG, 0, setifnwkey },
430 { "-nwkey", -1, 0, setifnwkey },
431 { "wpa", 1, 0, setifwpa },
432 { "-wpa", 0, 0, setifwpa },
433 { "wpaakms", NEXTARG, 0, setifwpaakms },
434 { "wpaciphers", NEXTARG, 0, setifwpaciphers },
435 { "wpagroupcipher", NEXTARG, 0, setifwpagroupcipher },
436 { "wpaprotos", NEXTARG, 0, setifwpaprotos },
437 { "wpakey", NEXTARG, 0, setifwpakey },
438 { "-wpakey", -1, 0, setifwpakey },
439 { "chan", NEXTARG0, 0, setifchan },
440 { "-chan", -1, 0, setifchan },
441 { "scan", NEXTARG0, 0, setifscan },
442 { "broadcast", NEXTARG, 0, setifbroadaddr },
443 { "prefixlen", NEXTARG, 0, setifprefixlen},
444 { "vnetid", NEXTARG, 0, setvnetid },
445 { "-vnetid", 0, 0, delvnetid },
446 { "parent", NEXTARG, 0, setifparent },
447 { "-parent", 1, 0, delifparent },
448 { "vlan", NEXTARG, 0, setvnetid },
449 { "-vlan", 0, 0, delvnetid },
450 { "vlandev", NEXTARG, 0, setifparent },
451 { "-vlandev", 1, 0, delifparent },
452 { "group", NEXTARG, 0, setifgroup },
453 { "-group", NEXTARG, 0, unsetifgroup },
454 { "autoconf", 1, 0, setautoconf },
455 { "-autoconf", -1, 0, setautoconf },
456 { "trunkport", NEXTARG, 0, settrunkport },
457 { "-trunkport", NEXTARG, 0, unsettrunkport },
458 { "trunkproto", NEXTARG, 0, settrunkproto },
459 { "lacpmode", NEXTARG, 0, settrunklacpmode },
460 { "lacptimeout", NEXTARG, 0, settrunklacptimeout },
461 { "anycast", IN6_IFF_ANYCAST, 0, setia6flags },
462 { "-anycast", -IN6_IFF_ANYCAST, 0, setia6flags },
463 { "tentative", IN6_IFF_TENTATIVE, 0, setia6flags },
464 { "-tentative", -IN6_IFF_TENTATIVE, 0, setia6flags },
465 { "pltime", NEXTARG, 0, setia6pltime },
466 { "vltime", NEXTARG, 0, setia6vltime },
467 { "eui64", 0, 0, setia6eui64 },
468 { "temporary", 1, 0, settemporary },
469 { "-temporary", -1, 0, settemporary },
470 { "soii", -IFXF_INET6_NOSOII, 0, setifxflags },
471 { "-soii", IFXF_INET6_NOSOII, 0, setifxflags },
472 { "monitor", IFXF_MONITOR, 0, setifxflags },
473 { "-monitor", -IFXF_MONITOR, 0, setifxflags },
474 { "tcplro", IFXF_LRO, 0, setifxflags },
475 { "-tcplro", -IFXF_LRO, 0, setifxflags },
476 #ifndef SMALL
477 { "hwfeatures", NEXTARG0, 0, printifhwfeatures },
478 { "metric", NEXTARG, 0, setifmetric },
479 { "powersave", NEXTARG0, 0, setifpowersave },
480 { "-powersave", -1, 0, setifpowersave },
481 { "priority", NEXTARG, 0, setifpriority },
482 { "rtlabel", NEXTARG, 0, setifrtlabel },
483 { "-rtlabel", -1, 0, setifrtlabel },
484 { "rdomain", NEXTARG, 0, setrdomain },
485 { "-rdomain", 0, 0, unsetrdomain },
486 { "staticarp", IFF_STATICARP, 0, setifflags },
487 { "-staticarp", -IFF_STATICARP, 0, setifflags },
488 { "mpls", IFXF_MPLS, 0, setifxflags },
489 { "-mpls", -IFXF_MPLS, 0, setifxflags },
490 { "mplslabel", NEXTARG, 0, setmplslabel },
491 { "-mplslabel", 0, 0, unsetmplslabel },
492 { "pwecw", 0, 0, setpwe3cw },
493 { "-pwecw", 0, 0, unsetpwe3cw },
494 { "pwefat", 0, 0, setpwe3fat },
495 { "-pwefat", 0, 0, unsetpwe3fat },
496 { "pweneighbor", NEXTARG2, 0, NULL, setpwe3neighbor },
497 { "-pweneighbor", 0, 0, unsetpwe3neighbor },
498 { "advbase", NEXTARG, 0, setcarp_advbase },
499 { "advskew", NEXTARG, 0, setcarp_advskew },
500 { "carppeer", NEXTARG, 0, setcarppeer },
501 { "-carppeer", 1, 0, unsetcarppeer },
502 { "pass", NEXTARG, 0, setcarp_passwd },
503 { "vhid", NEXTARG, 0, setcarp_vhid },
504 { "state", NEXTARG, 0, setcarp_state },
505 { "carpdev", NEXTARG, 0, setcarpdev },
506 { "carpnodes", NEXTARG, 0, setcarp_nodes },
507 { "balancing", NEXTARG, 0, setcarp_balancing },
508 { "syncdev", NEXTARG, 0, setpfsync_syncdev },
509 { "-syncdev", 1, 0, unsetpfsync_syncdev },
510 { "syncif", NEXTARG, 0, setpfsync_syncdev },
511 { "-syncif", 1, 0, unsetpfsync_syncdev },
512 { "syncpeer", NEXTARG, 0, setpfsync_syncpeer },
513 { "-syncpeer", 1, 0, unsetpfsync_syncpeer },
514 { "maxupd", NEXTARG, 0, setpfsync_maxupd },
515 { "defer", 1, 0, setpfsync_defer },
516 { "-defer", 0, 0, setpfsync_defer },
517 { "tunnel", NEXTARG2, 0, NULL, settunnel },
518 { "tunneladdr", NEXTARG, 0, settunneladdr },
519 { "-tunnel", 0, 0, deletetunnel },
520 { "tunneldomain", NEXTARG, 0, settunnelinst },
521 { "-tunneldomain", 0, 0, unsettunnelinst },
522 { "tunnelttl", NEXTARG, 0, settunnelttl },
523 { "tunneldf", 0, 0, settunneldf },
524 { "-tunneldf", 0, 0, settunnelnodf },
525 { "tunnelecn", 0, 0, settunnelecn },
526 { "-tunnelecn", 0, 0, settunnelnoecn },
527 { "vnetflowid", 0, 0, setvnetflowid },
528 { "-vnetflowid", 0, 0, delvnetflowid },
529 { "txprio", NEXTARG, 0, settxprio },
530 { "rxprio", NEXTARG, 0, setrxprio },
531 { "pppoedev", NEXTARG, 0, setpppoe_dev },
532 { "pppoesvc", NEXTARG, 0, setpppoe_svc },
533 { "-pppoesvc", 1, 0, setpppoe_svc },
534 { "pppoeac", NEXTARG, 0, setpppoe_ac },
535 { "-pppoeac", 1, 0, setpppoe_ac },
536 { "authproto", NEXTARG, 0, setspppproto },
537 { "authname", NEXTARG, 0, setspppname },
538 { "authkey", NEXTARG, 0, setspppkey },
539 { "peerproto", NEXTARG, 0, setsppppeerproto },
540 { "peername", NEXTARG, 0, setsppppeername },
541 { "peerkey", NEXTARG, 0, setsppppeerkey },
542 { "peerflag", NEXTARG, 0, setsppppeerflag },
543 { "-peerflag", NEXTARG, 0, unsetsppppeerflag },
544 { "nwflag", NEXTARG, 0, setifnwflag },
545 { "-nwflag", NEXTARG, 0, unsetifnwflag },
546 { "flowsrc", NEXTARG, 0, setpflow_sender },
547 { "-flowsrc", 1, 0, unsetpflow_sender },
548 { "flowdst", NEXTARG, 0, setpflow_receiver },
549 { "-flowdst", 1, 0, unsetpflow_receiver },
550 { "pflowproto", NEXTARG, 0, setpflowproto },
551 { "-inet", AF_INET, 0, removeaf },
552 { "-inet6", AF_INET6, 0, removeaf },
553 { "keepalive", NEXTARG2, 0, NULL, setkeepalive },
554 { "-keepalive", 1, 0, unsetkeepalive },
555 { "add", NEXTARG, 0, bridge_add },
556 { "del", NEXTARG, 0, bridge_delete },
557 { "addspan", NEXTARG, 0, bridge_addspan },
558 { "delspan", NEXTARG, 0, bridge_delspan },
559 { "discover", NEXTARG, 0, setdiscover },
560 { "-discover", NEXTARG, 0, unsetdiscover },
561 { "blocknonip", NEXTARG, 0, setblocknonip },
562 { "-blocknonip",NEXTARG, 0, unsetblocknonip },
563 { "learn", NEXTARG, 0, setlearn },
564 { "-learn", NEXTARG, 0, unsetlearn },
565 { "stp", NEXTARG, 0, setstp },
566 { "-stp", NEXTARG, 0, unsetstp },
567 { "edge", NEXTARG, 0, setedge },
568 { "-edge", NEXTARG, 0, unsetedge },
569 { "autoedge", NEXTARG, 0, setautoedge },
570 { "-autoedge", NEXTARG, 0, unsetautoedge },
571 { "protected", NEXTARG2, 0, NULL, bridge_protect },
572 { "-protected", NEXTARG, 0, bridge_unprotect },
573 { "ptp", NEXTARG, 0, setptp },
574 { "-ptp", NEXTARG, 0, unsetptp },
575 { "autoptp", NEXTARG, 0, setautoptp },
576 { "-autoptp", NEXTARG, 0, unsetautoptp },
577 { "flush", 0, 0, bridge_flush },
578 { "flushall", 0, 0, bridge_flushall },
579 { "static", NEXTARG2, 0, NULL, bridge_addaddr },
580 { "endpoint", NEXTARG2, 0, NULL, bridge_addendpoint },
581 { "-endpoint", NEXTARG, 0, bridge_delendpoint },
582 { "deladdr", NEXTARG, 0, bridge_deladdr },
583 { "maxaddr", NEXTARG, 0, bridge_maxaddr },
584 { "addr", 0, 0, bridge_addrs },
585 { "hellotime", NEXTARG, 0, bridge_hellotime },
586 { "fwddelay", NEXTARG, 0, bridge_fwddelay },
587 { "maxage", NEXTARG, 0, bridge_maxage },
588 { "proto", NEXTARG, 0, bridge_proto },
589 { "ifpriority", NEXTARG2, 0, NULL, bridge_ifprio },
590 { "ifcost", NEXTARG2, 0, NULL, bridge_ifcost },
591 { "-ifcost", NEXTARG, 0, bridge_noifcost },
592 { "timeout", NEXTARG, 0, bridge_timeout },
593 { "holdcnt", NEXTARG, 0, bridge_holdcnt },
594 { "spanpriority", NEXTARG, 0, bridge_priority },
595 { "ipdst", NEXTARG, 0, setifipdst },
596 #if 0
597 /* XXX `rule` special-cased below */
598 { "rule", 0, 0, bridge_rule },
599 #endif
600 { "rules", NEXTARG, 0, bridge_rules },
601 { "rulefile", NEXTARG, 0, bridge_rulefile },
602 { "flushrule", NEXTARG, 0, bridge_flushrule },
603 { "description", NEXTARG, 0, setifdesc },
604 { "descr", NEXTARG, 0, setifdesc },
605 { "-description", 1, 0, unsetifdesc },
606 { "-descr", 1, 0, unsetifdesc },
607 { "wol", IFXF_WOL, 0, setifxflags },
608 { "-wol", -IFXF_WOL, 0, setifxflags },
609 { "pin", NEXTARG, 0, umb_setpin },
610 { "chgpin", NEXTARG2, 0, NULL, umb_chgpin },
611 { "puk", NEXTARG2, 0, NULL, umb_puk },
612 { "apn", NEXTARG, 0, umb_apn },
613 { "-apn", -1, 0, umb_apn },
614 { "class", NEXTARG0, 0, umb_setclass },
615 { "-class", -1, 0, umb_setclass },
616 { "roaming", 1, 0, umb_roaming },
617 { "-roaming", 0, 0, umb_roaming },
618 { "patch", NEXTARG, 0, setpair },
619 { "-patch", 1, 0, unsetpair },
620 { "addlocal", NEXTARG, 0, addlocal },
621 { "transceiver", NEXTARG0, 0, transceiver },
622 { "sff", NEXTARG0, 0, transceiver },
623 { "sffdump", 0, 0, transceiverdump },
624
625 { "wgpeer", NEXTARG, A_WIREGUARD, setwgpeer},
626 { "wgdescription", NEXTARG, A_WIREGUARD, setwgpeerdesc},
627 { "wgdescr", NEXTARG, A_WIREGUARD, setwgpeerdesc},
628 { "wgendpoint", NEXTARG2, A_WIREGUARD, NULL, setwgpeerep},
629 { "wgaip", NEXTARG, A_WIREGUARD, setwgpeeraip},
630 { "wgpsk", NEXTARG, A_WIREGUARD, setwgpeerpsk},
631 { "wgpka", NEXTARG, A_WIREGUARD, setwgpeerpka},
632 { "wgport", NEXTARG, A_WIREGUARD, setwgport},
633 { "wgkey", NEXTARG, A_WIREGUARD, setwgkey},
634 { "wgrtable", NEXTARG, A_WIREGUARD, setwgrtable},
635 { "-wgpeer", NEXTARG, A_WIREGUARD, unsetwgpeer},
636 { "-wgpsk", 0, A_WIREGUARD, unsetwgpeerpsk},
637 { "-wgdescription", 0, A_WIREGUARD, unsetwgpeerdesc},
638 { "-wgdescr", 0, A_WIREGUARD, unsetwgpeerdesc},
639 { "-wgpeerall", 0, A_WIREGUARD, unsetwgpeerall},
640
641 #else /* SMALL */
642 { "powersave", NEXTARG0, 0, setignore },
643 { "priority", NEXTARG, 0, setignore },
644 { "rtlabel", NEXTARG, 0, setignore },
645 { "mpls", IFXF_MPLS, 0, setignore },
646 { "nwflag", NEXTARG, 0, setignore },
647 { "rdomain", NEXTARG, 0, setignore },
648 { "-inet", AF_INET, 0, removeaf },
649 { "-inet6", AF_INET6, 0, removeaf },
650 { "description", NEXTARG, 0, setignore },
651 { "descr", NEXTARG, 0, setignore },
652 { "wol", IFXF_WOL, 0, setignore },
653 { "-wol", -IFXF_WOL, 0, setignore },
654 #endif /* SMALL */
655 #if 0
656 /* XXX `create' special-cased below */
657 { "create", 0, 0, clone_create } ,
658 #endif
659 { "destroy", 0, 0, clone_destroy } ,
660 { "link0", IFF_LINK0, 0, setifflags } ,
661 { "-link0", -IFF_LINK0, 0, setifflags } ,
662 { "link1", IFF_LINK1, 0, setifflags } ,
663 { "-link1", -IFF_LINK1, 0, setifflags } ,
664 { "link2", IFF_LINK2, 0, setifflags } ,
665 { "-link2", -IFF_LINK2, 0, setifflags } ,
666 { "media", NEXTARG0, A_MEDIA, setmedia },
667 { "mediaopt", NEXTARG, A_MEDIAOPTSET, setmediaopt },
668 { "-mediaopt", NEXTARG, A_MEDIAOPTCLR, unsetmediaopt },
669 { "mode", NEXTARG, A_MEDIAMODE, setmediamode },
670 { "-mode", 0, A_MEDIAMODE, unsetmediamode },
671 { "instance", NEXTARG, A_MEDIAINST, setmediainst },
672 { "inst", NEXTARG, A_MEDIAINST, setmediainst },
673 { "lladdr", NEXTARG, 0, setiflladdr },
674 { "llprio", NEXTARG, 0, setifllprio },
675 { NULL, /*src*/ 0, 0, setifaddr },
676 { NULL, /*dst*/ 0, 0, setifdstaddr },
677 { NULL, /*illegal*/0, 0, NULL },
678 };
679
680 #define IFFBITS \
681 "\024\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6STATICARP" \
682 "\7RUNNING\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX" \
683 "\15LINK0\16LINK1\17LINK2\20MULTICAST" \
684 "\23AUTOCONF6TEMP\24MPLS\25WOL\26AUTOCONF6\27INET6_NOSOII" \
685 "\30AUTOCONF4" "\31MONITOR" "\32LRO"
686
687 int getinfo(struct ifreq *, int);
688 void getsock(int);
689 void printgroupattribs(char *);
690 void printif(char *, int);
691 void printb_status(unsigned short, unsigned char *);
692 const char *get_linkstate(int, int);
693 void status(int, struct sockaddr_dl *, int, int);
694 __dead void usage(void);
695 const char *get_string(const char *, const char *, u_int8_t *, int *);
696 int len_string(const u_int8_t *, int);
697 int print_string(const u_int8_t *, int);
698 char *sec2str(time_t);
699
700 const char *get_media_type_string(uint64_t);
701 const char *get_media_subtype_string(uint64_t);
702 uint64_t get_media_mode(uint64_t, const char *);
703 uint64_t get_media_subtype(uint64_t, const char *);
704 uint64_t get_media_options(uint64_t, const char *);
705 uint64_t lookup_media_word(const struct ifmedia_description *, uint64_t,
706 const char *);
707 void print_media_word(uint64_t, int, int);
708 void process_media_commands(void);
709 void init_current_media(void);
710
711 void process_join_commands(void);
712
713 void process_wg_commands(void);
714
715 void in_status(int);
716 void in_getaddr(const char *, int);
717 void in_getprefix(const char *, int);
718 void in6_fillscopeid(struct sockaddr_in6 *);
719 void in6_alias(struct in6_ifreq *);
720 void in6_status(int);
721 void in6_getaddr(const char *, int);
722 void in6_getprefix(const char *, int);
723 void ieee80211_status(void);
724 void join_status(void);
725 void ieee80211_listchans(void);
726 void ieee80211_listnodes(void);
727 void ieee80211_printnode(struct ieee80211_nodereq *);
728 u_int getwpacipher(const char *);
729 void print_cipherset(u_int32_t);
730
731 void spppauthinfo(struct sauthreq *, int);
732 void spppdnsinfo(struct sdnsreq *);
733
734 /* Known address families */
735 const struct afswtch {
736 char *af_name;
737 short af_af;
738 void (*af_status)(int);
739 void (*af_getaddr)(const char *, int);
740 void (*af_getprefix)(const char *, int);
741 u_long af_difaddr;
742 u_long af_aifaddr;
743 caddr_t af_ridreq;
744 caddr_t af_addreq;
745 } afs[] = {
746 #define C(x) ((caddr_t) &x)
747 { "inet", AF_INET, in_status, in_getaddr, in_getprefix,
748 SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(in_addreq) },
749 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
750 SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, C(in6_ridreq), C(in6_addreq) },
751 { 0, 0, 0, 0 }
752 };
753
754 const struct afswtch *afp; /*the address family being set or asked about*/
755
756 char joinname[IEEE80211_NWID_LEN];
757 size_t joinlen;
758 char nwidname[IEEE80211_NWID_LEN];
759 size_t nwidlen;
760
761 int ifaliases = 0;
762 int aflag = 0;
763
764 int
main(int argc,char * argv[])765 main(int argc, char *argv[])
766 {
767 const struct afswtch *rafp = NULL;
768 int create = 0;
769 int Cflag = 0;
770 int gflag = 0;
771 int found_rulefile = 0;
772 int i;
773
774 /* If no args at all, print all interfaces. */
775 if (argc < 2) {
776 /* no filesystem visibility */
777 if (unveil("/", "") == -1)
778 err(1, "unveil /");
779 if (unveil(NULL, NULL) == -1)
780 err(1, "unveil");
781 aflag = 1;
782 printif(NULL, 0);
783 return (0);
784 }
785 argc--, argv++;
786 if (*argv[0] == '-') {
787 int nomore = 0;
788
789 for (i = 1; argv[0][i]; i++) {
790 switch (argv[0][i]) {
791 case 'a':
792 aflag = 1;
793 nomore = 1;
794 break;
795 case 'A':
796 aflag = 1;
797 ifaliases = 1;
798 nomore = 1;
799 break;
800 case 'g':
801 gflag = 1;
802 break;
803 case 'C':
804 Cflag = 1;
805 nomore = 1;
806 break;
807 case 'M':
808 if (argv[1] == NULL)
809 usage();
810 exit(findmac(argv[1]));
811 break;
812 default:
813 usage();
814 break;
815 }
816 }
817 if (nomore == 0) {
818 argc--, argv++;
819 if (argc < 1)
820 usage();
821 if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ)
822 errx(1, "interface name '%s' too long", *argv);
823 }
824 } else if (strlcpy(ifname, *argv, sizeof(ifname)) >= IFNAMSIZ)
825 errx(1, "interface name '%s' too long", *argv);
826 argc--, argv++;
827
828 for (i = 0; i < argc; i++) {
829 if (strcmp(argv[i], "rulefile") == 0) {
830 found_rulefile = 1;
831 break;
832 }
833 }
834
835 if (!found_rulefile) {
836 if (unveil(_PATH_RESCONF, "r") == -1)
837 err(1, "unveil %s", _PATH_RESCONF);
838 if (unveil(_PATH_HOSTS, "r") == -1)
839 err(1, "unveil %s", _PATH_HOSTS);
840 if (unveil(_PATH_SERVICES, "r") == -1)
841 err(1, "unveil %s", _PATH_SERVICES);
842 if (unveil(NULL, NULL) == -1)
843 err(1, "unveil");
844 }
845
846 if (argc > 0) {
847 for (afp = rafp = afs; rafp->af_name; rafp++)
848 if (strcmp(rafp->af_name, *argv) == 0) {
849 afp = rafp;
850 argc--;
851 argv++;
852 break;
853 }
854 rafp = afp;
855 af = ifr.ifr_addr.sa_family = rafp->af_af;
856 }
857 if (Cflag) {
858 if (argc > 0 || aflag)
859 usage();
860 list_cloners();
861 return (0);
862 }
863 if (gflag) {
864 if (argc == 0)
865 printgroupattribs(ifname);
866 else
867 setgroupattribs(ifname, argc, argv);
868 return (0);
869 }
870 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
871
872 /* initialization */
873 in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
874 in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
875
876 /*
877 * NOTE: We must special-case the `create' command right
878 * here as we would otherwise fail in getinfo().
879 */
880 if (argc > 0 && strcmp(argv[0], "create") == 0) {
881 clone_create(argv[0], 0);
882 argc--, argv++;
883 if (argc == 0)
884 return (0);
885 }
886 if (aflag == 0) {
887 create = (argc > 0) && strcmp(argv[0], "destroy") != 0;
888 (void)getinfo(&ifr, create);
889 }
890
891 if (argc != 0 && af == AF_INET6)
892 addaf(ifname, AF_INET6);
893
894 while (argc > 0) {
895 const struct cmd *p;
896
897 for (p = cmds; p->c_name; p++)
898 if (strcmp(*argv, p->c_name) == 0)
899 break;
900 #ifndef SMALL
901 if (strcmp(*argv, "rule") == 0) {
902 argc--, argv++;
903 return bridge_rule(argc, argv, -1);
904 }
905 #endif
906 if (p->c_name == 0 && setaddr)
907 for (i = setaddr; i > 0; i--) {
908 p++;
909 if (p->c_func == NULL)
910 errx(1, "%s: bad value", *argv);
911 }
912 if (p->c_func || p->c_func2) {
913 if (p->c_parameter == NEXTARG0) {
914 const struct cmd *p0;
915 int noarg = 1;
916
917 if (argv[1]) {
918 for (p0 = cmds; p0->c_name; p0++)
919 if (strcmp(argv[1],
920 p0->c_name) == 0) {
921 noarg = 0;
922 break;
923 }
924 } else
925 noarg = 0;
926
927 if (noarg == 0)
928 (*p->c_func)(NULL, 0);
929 else
930 goto nextarg;
931 } else if (p->c_parameter == NEXTARG) {
932 nextarg:
933 if (argv[1] == NULL)
934 errx(1, "'%s' requires argument",
935 p->c_name);
936 (*p->c_func)(argv[1], 0);
937 argc--, argv++;
938 actions = actions | A_SILENT | p->c_action;
939 } else if (p->c_parameter == NEXTARG2) {
940 if ((argv[1] == NULL) ||
941 (argv[2] == NULL))
942 errx(1, "'%s' requires 2 arguments",
943 p->c_name);
944 (*p->c_func2)(argv[1], argv[2]);
945 argc -= 2;
946 argv += 2;
947 actions = actions | A_SILENT | p->c_action;
948 } else {
949 (*p->c_func)(*argv, p->c_parameter);
950 actions = actions | A_SILENT | p->c_action;
951 }
952 }
953 argc--, argv++;
954 }
955
956 if (argc == 0 && actions == 0) {
957 printif(ifr.ifr_name, aflag ? ifaliases : 1);
958 return (0);
959 }
960
961 #ifndef SMALL
962 process_wg_commands();
963 #endif
964
965 process_join_commands();
966
967 /* Process any media commands that may have been issued. */
968 process_media_commands();
969
970 if (af == AF_INET6 && explicit_prefix == 0) {
971 /*
972 * Aggregatable address architecture defines all prefixes
973 * are 64. So, it is convenient to set prefixlen to 64 if
974 * it is not specified. If we are setting a destination
975 * address on a point-to-point interface, 128 is required.
976 */
977 if (setipdst && (flags & IFF_POINTOPOINT))
978 setifprefixlen("128", 0);
979 else
980 setifprefixlen("64", 0);
981 /* in6_getprefix("64", MASK) if MASK is available here... */
982 }
983
984 if (clearaddr) {
985 (void) strlcpy(rafp->af_ridreq, ifname, sizeof(ifr.ifr_name));
986 if (ioctl(sock, rafp->af_difaddr, rafp->af_ridreq) == -1) {
987 if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
988 /* means no previous address for interface */
989 } else
990 err(1, "SIOCDIFADDR");
991 }
992 }
993 if (newaddr) {
994 (void) strlcpy(rafp->af_addreq, ifname, sizeof(ifr.ifr_name));
995 if (ioctl(sock, rafp->af_aifaddr, rafp->af_addreq) == -1)
996 err(1, "SIOCAIFADDR");
997 }
998 return (0);
999 }
1000
1001 void
getsock(int naf)1002 getsock(int naf)
1003 {
1004 static int oaf = -1;
1005
1006 if (oaf == naf)
1007 return;
1008 if (oaf != -1)
1009 close(sock);
1010 sock = socket(naf, SOCK_DGRAM, 0);
1011 if (sock == -1)
1012 oaf = -1;
1013 else
1014 oaf = naf;
1015 }
1016
1017 int
getinfo(struct ifreq * ifr,int create)1018 getinfo(struct ifreq *ifr, int create)
1019 {
1020
1021 getsock(af);
1022 if (sock == -1)
1023 err(1, "socket");
1024 if (!isdigit((unsigned char)ifname[strlen(ifname) - 1]))
1025 return (-1); /* ignore groups here */
1026 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1) {
1027 int oerrno = errno;
1028
1029 if (!create)
1030 return (-1);
1031 if (ioctl(sock, SIOCIFCREATE, (caddr_t)ifr) == -1) {
1032 errno = oerrno;
1033 return (-1);
1034 }
1035 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)ifr) == -1)
1036 return (-1);
1037 }
1038 flags = ifr->ifr_flags & 0xffff;
1039 if (ioctl(sock, SIOCGIFXFLAGS, (caddr_t)ifr) == -1)
1040 ifr->ifr_flags = 0;
1041 xflags = ifr->ifr_flags;
1042 if (ioctl(sock, SIOCGIFMETRIC, (caddr_t)ifr) == -1)
1043 metric = 0;
1044 else
1045 metric = ifr->ifr_metric;
1046 if (ioctl(sock, SIOCGIFMTU, (caddr_t)ifr) == -1)
1047 mtu = 0;
1048 else
1049 mtu = ifr->ifr_mtu;
1050 #ifndef SMALL
1051 if (ioctl(sock, SIOCGIFRDOMAIN, (caddr_t)ifr) == -1)
1052 rdomainid = 0;
1053 else
1054 rdomainid = ifr->ifr_rdomainid;
1055 #endif
1056 if (ioctl(sock, SIOCGIFLLPRIO, (caddr_t)ifr) == -1)
1057 llprio = 0;
1058 else
1059 llprio = ifr->ifr_llprio;
1060
1061 return (0);
1062 }
1063
1064 int
printgroup(char * groupname,int ifaliases)1065 printgroup(char *groupname, int ifaliases)
1066 {
1067 struct ifgroupreq ifgr;
1068 struct ifg_req *ifg;
1069 int len, cnt = 0;
1070
1071 getsock(AF_INET);
1072 bzero(&ifgr, sizeof(ifgr));
1073 strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
1074 if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
1075 if (errno == EINVAL || errno == ENOTTY ||
1076 errno == ENOENT)
1077 return (-1);
1078 else
1079 err(1, "%s: SIOCGIFGMEMB", ifgr.ifgr_name);
1080 }
1081
1082 len = ifgr.ifgr_len;
1083 if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
1084 err(1, "printgroup");
1085 if (ioctl(sock, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
1086 err(1, "%s: SIOCGIFGMEMB", ifgr.ifgr_name);
1087
1088 for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
1089 ifg++) {
1090 len -= sizeof(struct ifg_req);
1091 printif(ifg->ifgrq_member, ifaliases);
1092 cnt++;
1093 }
1094 free(ifgr.ifgr_groups);
1095
1096 return (cnt);
1097 }
1098
1099 void
printgroupattribs(char * groupname)1100 printgroupattribs(char *groupname)
1101 {
1102 struct ifgroupreq ifgr;
1103
1104 getsock(AF_INET);
1105 bzero(&ifgr, sizeof(ifgr));
1106 strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
1107 if (ioctl(sock, SIOCGIFGATTR, (caddr_t)&ifgr) == -1)
1108 err(1, "%s: SIOCGIFGATTR", ifgr.ifgr_name);
1109
1110 printf("%s:", groupname);
1111 printf(" carp demote count %d", ifgr.ifgr_attrib.ifg_carp_demoted);
1112 printf("\n");
1113 }
1114
1115 void
setgroupattribs(char * groupname,int argc,char * argv[])1116 setgroupattribs(char *groupname, int argc, char *argv[])
1117 {
1118 const char *errstr;
1119 char *p = argv[0];
1120 int neg = 1;
1121
1122 struct ifgroupreq ifgr;
1123
1124 getsock(AF_INET);
1125 bzero(&ifgr, sizeof(ifgr));
1126 strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
1127
1128 if (argc > 1) {
1129 neg = strtonum(argv[1], 0, 128, &errstr);
1130 if (errstr)
1131 errx(1, "%s: invalid carp demotion: %s", ifgr.ifgr_name,
1132 errstr);
1133 }
1134
1135 if (p[0] == '-') {
1136 neg = neg * -1;
1137 p++;
1138 }
1139 if (!strcmp(p, "carpdemote"))
1140 ifgr.ifgr_attrib.ifg_carp_demoted = neg;
1141 else
1142 usage();
1143
1144 if (ioctl(sock, SIOCSIFGATTR, (caddr_t)&ifgr) == -1)
1145 err(1, "%s: SIOCSIFGATTR", ifgr.ifgr_name);
1146 }
1147
1148 void
printif(char * name,int ifaliases)1149 printif(char *name, int ifaliases)
1150 {
1151 struct ifaddrs *ifap, *ifa;
1152 struct if_data *ifdata;
1153 const char *namep;
1154 char *oname = NULL;
1155 struct ifreq *ifrp;
1156 int count = 0, noinet = 1;
1157 size_t nlen = 0;
1158
1159 if (aflag)
1160 name = NULL;
1161 if (name) {
1162 if ((oname = strdup(name)) == NULL)
1163 err(1, "strdup");
1164 nlen = strlen(oname);
1165 /* is it a group? */
1166 if (nlen && !isdigit((unsigned char)oname[nlen - 1]))
1167 if (printgroup(oname, ifaliases) != -1) {
1168 free(oname);
1169 return;
1170 }
1171 }
1172
1173 if (getifaddrs(&ifap) != 0)
1174 err(1, "getifaddrs");
1175
1176 namep = NULL;
1177 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1178 if (oname) {
1179 if (nlen && isdigit((unsigned char)oname[nlen - 1])) {
1180 /* must have exact match */
1181 if (strcmp(oname, ifa->ifa_name) != 0)
1182 continue;
1183 } else {
1184 /* partial match OK if it ends w/ digit */
1185 if (strncmp(oname, ifa->ifa_name, nlen) != 0 ||
1186 !isdigit((unsigned char)ifa->ifa_name[nlen]))
1187 continue;
1188 }
1189 }
1190 /* quickhack: sizeof(ifr) < sizeof(ifr6) */
1191 if (ifa->ifa_addr != NULL &&
1192 ifa->ifa_addr->sa_family == AF_INET6) {
1193 memset(&ifr6, 0, sizeof(ifr6));
1194 memcpy(&ifr6.ifr_addr, ifa->ifa_addr,
1195 MINIMUM(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len));
1196 ifrp = (struct ifreq *)&ifr6;
1197 } else if (ifa->ifa_addr != NULL) {
1198 memset(&ifr, 0, sizeof(ifr));
1199 memcpy(&ifr.ifr_addr, ifa->ifa_addr,
1200 MINIMUM(sizeof(ifr.ifr_addr), ifa->ifa_addr->sa_len));
1201 ifrp = 𝔦
1202 }
1203 strlcpy(ifname, ifa->ifa_name, sizeof(ifname));
1204 strlcpy(ifrp->ifr_name, ifa->ifa_name, sizeof(ifrp->ifr_name));
1205
1206 if (ifa->ifa_addr != NULL &&
1207 ifa->ifa_addr->sa_family == AF_LINK) {
1208 namep = ifa->ifa_name;
1209 if (getinfo(ifrp, 0) < 0)
1210 continue;
1211 ifdata = ifa->ifa_data;
1212 status(1, (struct sockaddr_dl *)ifa->ifa_addr,
1213 ifdata->ifi_link_state, ifaliases);
1214 count++;
1215 noinet = 1;
1216 continue;
1217 }
1218
1219 if (!namep || !strcmp(namep, ifa->ifa_name)) {
1220 const struct afswtch *p;
1221
1222 if (ifa->ifa_addr == NULL ||
1223 (ifa->ifa_addr->sa_family == AF_INET &&
1224 ifaliases == 0 && noinet == 0))
1225 continue;
1226 if ((p = afp) != NULL) {
1227 if (ifa->ifa_addr->sa_family == p->af_af)
1228 p->af_status(1);
1229 } else {
1230 for (p = afs; p->af_name; p++) {
1231 if (ifa->ifa_addr->sa_family ==
1232 p->af_af)
1233 p->af_status(0);
1234 }
1235 }
1236 count++;
1237 if (ifa->ifa_addr->sa_family == AF_INET)
1238 noinet = 0;
1239 continue;
1240 }
1241 }
1242 freeifaddrs(ifap);
1243 free(oname);
1244 if (count == 0) {
1245 fprintf(stderr, "%s: no such interface\n", ifname);
1246 exit(1);
1247 }
1248 }
1249
1250 void
clone_create(const char * addr,int param)1251 clone_create(const char *addr, int param)
1252 {
1253
1254 /* We're called early... */
1255 getsock(AF_INET);
1256
1257 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1258 if (ioctl(sock, SIOCIFCREATE, &ifr) == -1)
1259 err(1, "%s: SIOCIFCREATE", ifr.ifr_name);
1260 }
1261
1262 void
clone_destroy(const char * addr,int param)1263 clone_destroy(const char *addr, int param)
1264 {
1265
1266 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1267 if (ioctl(sock, SIOCIFDESTROY, &ifr) == -1)
1268 err(1, "%s: SIOCIFDESTROY", ifr.ifr_name);
1269 }
1270
1271 struct if_clonereq *
get_cloners(void)1272 get_cloners(void)
1273 {
1274 static struct if_clonereq ifcr;
1275
1276 memset(&ifcr, 0, sizeof(ifcr));
1277
1278 getsock(AF_INET);
1279
1280 if (ioctl(sock, SIOCIFGCLONERS, &ifcr) == -1)
1281 err(1, "SIOCIFGCLONERS for count");
1282
1283 if ((ifcr.ifcr_buffer = calloc(ifcr.ifcr_total, IFNAMSIZ)) == NULL)
1284 err(1, "unable to allocate cloner name buffer");
1285 ifcr.ifcr_count = ifcr.ifcr_total;
1286
1287 if (ioctl(sock, SIOCIFGCLONERS, &ifcr) == -1)
1288 err(1, "SIOCIFGCLONERS for names");
1289
1290 /*
1291 * In case some disappeared in the mean time, clamp it down.
1292 */
1293 if (ifcr.ifcr_count > ifcr.ifcr_total)
1294 ifcr.ifcr_count = ifcr.ifcr_total;
1295
1296 return &ifcr;
1297 }
1298
1299 void
list_cloners(void)1300 list_cloners(void)
1301 {
1302 struct if_clonereq *ifcr;
1303 char *cp, *buf;
1304 int idx;
1305
1306 ifcr = get_cloners();
1307 buf = ifcr->ifcr_buffer;
1308
1309 qsort(buf, ifcr->ifcr_count, IFNAMSIZ,
1310 (int(*)(const void *, const void *))strcmp);
1311
1312 for (cp = buf, idx = 0; idx < ifcr->ifcr_count; idx++, cp += IFNAMSIZ) {
1313 if (idx > 0)
1314 putchar(' ');
1315 printf("%s", cp);
1316 }
1317
1318 putchar('\n');
1319 free(ifcr->ifcr_buffer);
1320 }
1321
1322 #define RIDADDR 0
1323 #define ADDR 1
1324 #define MASK 2
1325 #define DSTADDR 3
1326
1327 void
setifaddr(const char * addr,int param)1328 setifaddr(const char *addr, int param)
1329 {
1330 /*
1331 * Delay the ioctl to set the interface addr until flags are all set.
1332 * The address interpretation may depend on the flags,
1333 * and the flags may change when the address is set.
1334 */
1335 setaddr++;
1336 if (doalias >= 0)
1337 newaddr = 1;
1338 if (doalias == 0)
1339 clearaddr = 1;
1340 afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
1341 }
1342
1343 #ifndef SMALL
1344 void
setifrtlabel(const char * label,int d)1345 setifrtlabel(const char *label, int d)
1346 {
1347 if (d != 0)
1348 ifr.ifr_data = (caddr_t)(const char *)"";
1349 else
1350 ifr.ifr_data = (caddr_t)label;
1351 if (ioctl(sock, SIOCSIFRTLABEL, &ifr) == -1)
1352 warn("SIOCSIFRTLABEL");
1353 }
1354 #endif
1355
1356 void
setifnetmask(const char * addr,int ignored)1357 setifnetmask(const char *addr, int ignored)
1358 {
1359 afp->af_getaddr(addr, MASK);
1360 explicit_prefix = 1;
1361 }
1362
1363 void
setifbroadaddr(const char * addr,int ignored)1364 setifbroadaddr(const char *addr, int ignored)
1365 {
1366 afp->af_getaddr(addr, DSTADDR);
1367 }
1368
1369 #ifndef SMALL
1370 void
setifdesc(const char * val,int ignored)1371 setifdesc(const char *val, int ignored)
1372 {
1373 ifr.ifr_data = (caddr_t)val;
1374 if (ioctl(sock, SIOCSIFDESCR, &ifr) == -1)
1375 warn("SIOCSIFDESCR");
1376 }
1377
1378 void
unsetifdesc(const char * noval,int ignored)1379 unsetifdesc(const char *noval, int ignored)
1380 {
1381 ifr.ifr_data = (caddr_t)(const char *)"";
1382 if (ioctl(sock, SIOCSIFDESCR, &ifr) == -1)
1383 warn("SIOCSIFDESCR");
1384 }
1385
1386 void
setifipdst(const char * addr,int ignored)1387 setifipdst(const char *addr, int ignored)
1388 {
1389 in_getaddr(addr, DSTADDR);
1390 setipdst++;
1391 clearaddr = 0;
1392 newaddr = 0;
1393 }
1394 #endif
1395
1396 #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
1397 void
notealias(const char * addr,int param)1398 notealias(const char *addr, int param)
1399 {
1400 if (setaddr && doalias == 0 && param < 0)
1401 memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
1402 rqtosa(af_addreq)->sa_len);
1403 doalias = param;
1404 if (param < 0) {
1405 clearaddr = 1;
1406 newaddr = 0;
1407 } else
1408 clearaddr = 0;
1409 }
1410
1411 void
setifdstaddr(const char * addr,int param)1412 setifdstaddr(const char *addr, int param)
1413 {
1414 setaddr++;
1415 setipdst++;
1416 afp->af_getaddr(addr, DSTADDR);
1417 }
1418
1419 /*
1420 * Note: doing an SIOCGIFFLAGS scribbles on the union portion
1421 * of the ifreq structure, which may confuse other parts of ifconfig.
1422 * Make a private copy so we can avoid that.
1423 */
1424 void
setifflags(const char * vname,int value)1425 setifflags(const char *vname, int value)
1426 {
1427 struct ifreq my_ifr;
1428
1429 bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
1430
1431 if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&my_ifr) == -1)
1432 err(1, "%s: SIOCGIFFLAGS", my_ifr.ifr_name);
1433 (void) strlcpy(my_ifr.ifr_name, ifname, sizeof(my_ifr.ifr_name));
1434 flags = my_ifr.ifr_flags;
1435
1436 if (value < 0) {
1437 value = -value;
1438 flags &= ~value;
1439 } else
1440 flags |= value;
1441 my_ifr.ifr_flags = flags;
1442 if (ioctl(sock, SIOCSIFFLAGS, (caddr_t)&my_ifr) == -1)
1443 err(1, "%s: SIOCSIFFLAGS", my_ifr.ifr_name);
1444 }
1445
1446 void
setifxflags(const char * vname,int value)1447 setifxflags(const char *vname, int value)
1448 {
1449 struct ifreq my_ifr;
1450
1451 bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
1452
1453 if (ioctl(sock, SIOCGIFXFLAGS, (caddr_t)&my_ifr) == -1)
1454 warn("%s: SIOCGIFXFLAGS", my_ifr.ifr_name);
1455 (void) strlcpy(my_ifr.ifr_name, ifname, sizeof(my_ifr.ifr_name));
1456 xflags = my_ifr.ifr_flags;
1457
1458 if (value < 0) {
1459 value = -value;
1460 xflags &= ~value;
1461 } else
1462 xflags |= value;
1463 my_ifr.ifr_flags = xflags;
1464 if (ioctl(sock, SIOCSIFXFLAGS, (caddr_t)&my_ifr) == -1)
1465 warn("%s: SIOCSIFXFLAGS", my_ifr.ifr_name);
1466 }
1467
1468 void
addaf(const char * vname,int value)1469 addaf(const char *vname, int value)
1470 {
1471 struct if_afreq ifar;
1472
1473 strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name));
1474 ifar.ifar_af = value;
1475 if (ioctl(sock, SIOCIFAFATTACH, (caddr_t)&ifar) == -1)
1476 warn("%s: SIOCIFAFATTACH", ifar.ifar_name);
1477 }
1478
1479 void
removeaf(const char * vname,int value)1480 removeaf(const char *vname, int value)
1481 {
1482 struct if_afreq ifar;
1483
1484 strlcpy(ifar.ifar_name, ifname, sizeof(ifar.ifar_name));
1485 ifar.ifar_af = value;
1486 if (ioctl(sock, SIOCIFAFDETACH, (caddr_t)&ifar) == -1)
1487 warn("%s: SIOCIFAFDETACH", ifar.ifar_name);
1488 }
1489
1490 void
setia6flags(const char * vname,int value)1491 setia6flags(const char *vname, int value)
1492 {
1493
1494 if (value < 0) {
1495 value = -value;
1496 in6_addreq.ifra_flags &= ~value;
1497 } else
1498 in6_addreq.ifra_flags |= value;
1499 }
1500
1501 void
setia6pltime(const char * val,int d)1502 setia6pltime(const char *val, int d)
1503 {
1504
1505 setia6lifetime("pltime", val);
1506 }
1507
1508 void
setia6vltime(const char * val,int d)1509 setia6vltime(const char *val, int d)
1510 {
1511
1512 setia6lifetime("vltime", val);
1513 }
1514
1515 void
setia6lifetime(const char * cmd,const char * val)1516 setia6lifetime(const char *cmd, const char *val)
1517 {
1518 const char *errmsg = NULL;
1519 time_t newval, t;
1520
1521 newval = strtonum(val, 0, 1000000, &errmsg);
1522 if (errmsg)
1523 errx(1, "invalid %s %s: %s", cmd, val, errmsg);
1524
1525 t = time(NULL);
1526
1527 if (afp->af_af != AF_INET6)
1528 errx(1, "%s not allowed for this address family", cmd);
1529 if (strcmp(cmd, "vltime") == 0) {
1530 in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
1531 in6_addreq.ifra_lifetime.ia6t_vltime = newval;
1532 } else if (strcmp(cmd, "pltime") == 0) {
1533 in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
1534 in6_addreq.ifra_lifetime.ia6t_pltime = newval;
1535 }
1536 }
1537
1538 void
setia6eui64(const char * cmd,int val)1539 setia6eui64(const char *cmd, int val)
1540 {
1541 struct ifaddrs *ifap, *ifa;
1542 const struct sockaddr_in6 *sin6 = NULL;
1543 const struct in6_addr *lladdr = NULL;
1544 struct in6_addr *in6;
1545
1546 if (afp->af_af != AF_INET6)
1547 errx(1, "%s not allowed for this address family", cmd);
1548
1549 addaf(ifname, AF_INET6);
1550
1551 in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
1552 if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
1553 errx(1, "interface index is already filled");
1554 if (getifaddrs(&ifap) != 0)
1555 err(1, "getifaddrs");
1556 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1557 if (ifa->ifa_addr->sa_family == AF_INET6 &&
1558 strcmp(ifa->ifa_name, ifname) == 0) {
1559 sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
1560 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1561 lladdr = &sin6->sin6_addr;
1562 break;
1563 }
1564 }
1565 }
1566 if (!lladdr)
1567 errx(1, "could not determine link local address");
1568
1569 memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
1570
1571 freeifaddrs(ifap);
1572 }
1573
1574 void
setautoconf(const char * cmd,int val)1575 setautoconf(const char *cmd, int val)
1576 {
1577 switch (afp->af_af) {
1578 case AF_INET:
1579 setifxflags("inet", val * IFXF_AUTOCONF4);
1580 break;
1581 case AF_INET6:
1582 if (val > 0)
1583 setifxflags("inet6", (IFXF_AUTOCONF6 |
1584 IFXF_AUTOCONF6TEMP));
1585 else
1586 setifxflags("inet6", -IFXF_AUTOCONF6);
1587 break;
1588 default:
1589 errx(1, "autoconf not allowed for this address family");
1590 }
1591 }
1592
1593 void
settemporary(const char * cmd,int val)1594 settemporary(const char *cmd, int val)
1595 {
1596 switch (afp->af_af) {
1597 case AF_INET6:
1598 setifxflags("inet6", val * IFXF_AUTOCONF6TEMP);
1599 break;
1600 default:
1601 errx(1, "temporary not allowed for this address family");
1602 }
1603 }
1604
1605 #ifndef SMALL
1606 void
setifmetric(const char * val,int ignored)1607 setifmetric(const char *val, int ignored)
1608 {
1609 const char *errmsg = NULL;
1610
1611 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1612
1613 ifr.ifr_metric = strtonum(val, 0, INT_MAX, &errmsg);
1614 if (errmsg)
1615 errx(1, "metric %s: %s", val, errmsg);
1616 if (ioctl(sock, SIOCSIFMETRIC, (caddr_t)&ifr) == -1)
1617 warn("SIOCSIFMETRIC");
1618 }
1619 #endif
1620
1621 void
setifmtu(const char * val,int d)1622 setifmtu(const char *val, int d)
1623 {
1624 const char *errmsg = NULL;
1625
1626 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1627
1628 ifr.ifr_mtu = strtonum(val, 0, INT_MAX, &errmsg);
1629 if (errmsg)
1630 errx(1, "mtu %s: %s", val, errmsg);
1631 if (ioctl(sock, SIOCSIFMTU, (caddr_t)&ifr) == -1)
1632 warn("SIOCSIFMTU");
1633 }
1634
1635 void
setifllprio(const char * val,int d)1636 setifllprio(const char *val, int d)
1637 {
1638 const char *errmsg = NULL;
1639
1640 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1641
1642 ifr.ifr_llprio = strtonum(val, 0, UCHAR_MAX, &errmsg);
1643 if (errmsg)
1644 errx(1, "llprio %s: %s", val, errmsg);
1645 if (ioctl(sock, SIOCSIFLLPRIO, (caddr_t)&ifr) == -1)
1646 warn("SIOCSIFLLPRIO");
1647 }
1648
1649 void
setifgroup(const char * group_name,int dummy)1650 setifgroup(const char *group_name, int dummy)
1651 {
1652 struct ifgroupreq ifgr;
1653 size_t namelen;
1654
1655 memset(&ifgr, 0, sizeof(ifgr));
1656 strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ);
1657
1658 namelen = strlen(group_name);
1659 if (namelen == 0)
1660 errx(1, "setifgroup: group name empty");
1661 if (namelen >= IFNAMSIZ)
1662 errx(1, "setifgroup: group name too long");
1663 if (isdigit((unsigned char)group_name[namelen - 1]))
1664 errx(1, "setifgroup: group names may not end in a digit");
1665
1666 strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ);
1667 if (ioctl(sock, SIOCAIFGROUP, (caddr_t)&ifgr) == -1) {
1668 if (errno != EEXIST)
1669 err(1,"%s: SIOCAIFGROUP", group_name);
1670 }
1671 }
1672
1673 void
unsetifgroup(const char * group_name,int dummy)1674 unsetifgroup(const char *group_name, int dummy)
1675 {
1676 struct ifgroupreq ifgr;
1677
1678 memset(&ifgr, 0, sizeof(ifgr));
1679 strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ);
1680
1681 if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
1682 errx(1, "unsetifgroup: group name too long");
1683 if (ioctl(sock, SIOCDIFGROUP, (caddr_t)&ifgr) == -1)
1684 err(1, "%s: SIOCDIFGROUP", group_name);
1685 }
1686
1687 const char *
get_string(const char * val,const char * sep,u_int8_t * buf,int * lenp)1688 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
1689 {
1690 int len = *lenp, hexstr;
1691 u_int8_t *p = buf;
1692
1693 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
1694 if (hexstr)
1695 val += 2;
1696 for (;;) {
1697 if (*val == '\0')
1698 break;
1699 if (sep != NULL && strchr(sep, *val) != NULL) {
1700 val++;
1701 break;
1702 }
1703 if (hexstr) {
1704 if (!isxdigit((u_char)val[0]) ||
1705 !isxdigit((u_char)val[1])) {
1706 warnx("bad hexadecimal digits");
1707 return NULL;
1708 }
1709 }
1710 if (p > buf + len) {
1711 if (hexstr)
1712 warnx("hexadecimal digits too long");
1713 else
1714 warnx("strings too long");
1715 return NULL;
1716 }
1717 if (hexstr) {
1718 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
1719 *p++ = (tohex((u_char)val[0]) << 4) |
1720 tohex((u_char)val[1]);
1721 #undef tohex
1722 val += 2;
1723 } else {
1724 if (*val == '\\' &&
1725 sep != NULL && strchr(sep, *(val + 1)) != NULL)
1726 val++;
1727 *p++ = *val++;
1728 }
1729 }
1730 len = p - buf;
1731 if (len < *lenp)
1732 memset(p, 0, *lenp - len);
1733 *lenp = len;
1734 return val;
1735 }
1736
1737 int
len_string(const u_int8_t * buf,int len)1738 len_string(const u_int8_t *buf, int len)
1739 {
1740 int i = 0, hasspc = 0;
1741
1742 if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1743 for (; i < len; i++) {
1744 /* Only print 7-bit ASCII keys */
1745 if (buf[i] & 0x80 || !isprint(buf[i]))
1746 break;
1747 if (isspace(buf[i]))
1748 hasspc++;
1749 }
1750 }
1751 if (i == len) {
1752 if (hasspc || len == 0)
1753 return len + 2;
1754 else
1755 return len;
1756 } else
1757 return (len * 2) + 2;
1758 }
1759
1760 int
print_string(const u_int8_t * buf,int len)1761 print_string(const u_int8_t *buf, int len)
1762 {
1763 int i = 0, hasspc = 0;
1764
1765 if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
1766 for (; i < len; i++) {
1767 /* Only print 7-bit ASCII keys */
1768 if (buf[i] & 0x80 || !isprint(buf[i]))
1769 break;
1770 if (isspace(buf[i]))
1771 hasspc++;
1772 }
1773 }
1774 if (i == len) {
1775 if (hasspc || len == 0) {
1776 printf("\"%.*s\"", len, buf);
1777 return len + 2;
1778 } else {
1779 printf("%.*s", len, buf);
1780 return len;
1781 }
1782 } else {
1783 printf("0x");
1784 for (i = 0; i < len; i++)
1785 printf("%02x", buf[i]);
1786 return (len * 2) + 2;
1787 }
1788 }
1789
1790 void
setifnwid(const char * val,int d)1791 setifnwid(const char *val, int d)
1792 {
1793 struct ieee80211_nwid nwid;
1794 int len;
1795
1796 if (joinlen != 0) {
1797 errx(1, "nwid and join may not be used at the same time");
1798 }
1799
1800 if (nwidlen != 0) {
1801 errx(1, "nwid may not be specified twice");
1802 }
1803
1804 if (d != 0) {
1805 /* no network id is especially desired */
1806 memset(&nwid, 0, sizeof(nwid));
1807 len = 0;
1808 } else {
1809 len = sizeof(nwid.i_nwid);
1810 if (get_string(val, NULL, nwid.i_nwid, &len) == NULL)
1811 return;
1812 }
1813 nwidlen = nwid.i_len = len;
1814 (void)strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1815 memcpy(nwidname, nwid.i_nwid, len);
1816 ifr.ifr_data = (caddr_t)&nwid;
1817 if (ioctl(sock, SIOCS80211NWID, (caddr_t)&ifr) == -1)
1818 warn("SIOCS80211NWID");
1819 }
1820
1821
1822 void
process_join_commands(void)1823 process_join_commands(void)
1824 {
1825 if (!(actions & A_JOIN))
1826 return;
1827
1828 ifr.ifr_data = (caddr_t)&join;
1829 if (ioctl(sock, SIOCS80211JOIN, (caddr_t)&ifr) == -1)
1830 err(1, "%s: SIOCS80211JOIN", ifr.ifr_name);
1831 }
1832
1833 void
setifjoin(const char * val,int d)1834 setifjoin(const char *val, int d)
1835 {
1836 int len;
1837
1838 if (nwidlen != 0) {
1839 errx(1, "nwid and join may not be used at the same time");
1840 }
1841
1842 if (joinlen != 0) {
1843 errx(1, "join may not be specified twice");
1844 }
1845
1846 if (d != 0) {
1847 /* no network id is especially desired */
1848 memset(&join, 0, sizeof(join));
1849 len = 0;
1850 } else {
1851 len = sizeof(join.i_nwid);
1852 if (get_string(val, NULL, join.i_nwid, &len) == NULL)
1853 return;
1854 if (len == 0)
1855 join.i_flags |= IEEE80211_JOIN_ANY;
1856 }
1857 joinlen = join.i_len = len;
1858 (void)strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1859 memcpy(joinname, join.i_nwid, len);
1860
1861 actions |= A_JOIN;
1862 }
1863
1864 void
delifjoin(const char * val,int d)1865 delifjoin(const char *val, int d)
1866 {
1867 struct ieee80211_join join;
1868 int len;
1869
1870 memset(&join, 0, sizeof(join));
1871 len = 0;
1872 join.i_flags |= IEEE80211_JOIN_DEL;
1873
1874 if (d == -1) {
1875 ifr.ifr_data = (caddr_t)&join;
1876 if (ioctl(sock, SIOCS80211JOIN, (caddr_t)&ifr) == -1)
1877 err(1, "%s: SIOCS80211JOIN", ifr.ifr_name);
1878 }
1879
1880 len = sizeof(join.i_nwid);
1881 if (get_string(val, NULL, join.i_nwid, &len) == NULL)
1882 return;
1883 join.i_len = len;
1884 if (len == 0)
1885 join.i_flags |= IEEE80211_JOIN_ANY;
1886 (void)strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1887 ifr.ifr_data = (caddr_t)&join;
1888 if (ioctl(sock, SIOCS80211JOIN, (caddr_t)&ifr) == -1)
1889 err(1, "%s: SIOCS80211JOIN", ifr.ifr_name);
1890 }
1891
1892 void
delifjoinlist(const char * val,int d)1893 delifjoinlist(const char *val, int d)
1894 {
1895 struct ieee80211_join join;
1896
1897 memset(&join, 0, sizeof(join));
1898 join.i_flags |= (IEEE80211_JOIN_DEL | IEEE80211_JOIN_DEL_ALL);
1899
1900 ifr.ifr_data = (caddr_t)&join;
1901 if (ioctl(sock, SIOCS80211JOIN, (caddr_t)&ifr) == -1)
1902 err(1, "%s: SIOCS80211JOIN", ifr.ifr_name);
1903 }
1904
1905 void
setifbssid(const char * val,int d)1906 setifbssid(const char *val, int d)
1907 {
1908
1909 struct ieee80211_bssid bssid;
1910 struct ether_addr *ea;
1911
1912 if (d != 0) {
1913 /* no BSSID is especially desired */
1914 memset(&bssid.i_bssid, 0, sizeof(bssid.i_bssid));
1915 } else {
1916 ea = ether_aton((char*)val);
1917 if (ea == NULL) {
1918 warnx("malformed BSSID: %s", val);
1919 return;
1920 }
1921 memcpy(&bssid.i_bssid, ea->ether_addr_octet,
1922 sizeof(bssid.i_bssid));
1923 }
1924 strlcpy(bssid.i_name, ifname, sizeof(bssid.i_name));
1925 if (ioctl(sock, SIOCS80211BSSID, &bssid) == -1)
1926 warn("%s: SIOCS80211BSSID", bssid.i_name);
1927 }
1928
1929 void
setifnwkey(const char * val,int d)1930 setifnwkey(const char *val, int d)
1931 {
1932 int i, len;
1933 struct ieee80211_nwkey nwkey;
1934 u_int8_t keybuf[IEEE80211_WEP_NKID][16];
1935
1936 bzero(&nwkey, sizeof(nwkey));
1937 bzero(&keybuf, sizeof(keybuf));
1938
1939 nwkey.i_wepon = IEEE80211_NWKEY_WEP;
1940 nwkey.i_defkid = 1;
1941 if (d == -1) {
1942 /* disable WEP encryption */
1943 nwkey.i_wepon = IEEE80211_NWKEY_OPEN;
1944 i = 0;
1945 } else if (strcasecmp("persist", val) == 0) {
1946 /* use all values from persistent memory */
1947 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1948 nwkey.i_defkid = 0;
1949 for (i = 0; i < IEEE80211_WEP_NKID; i++)
1950 nwkey.i_key[i].i_keylen = -1;
1951 } else if (strncasecmp("persist:", val, 8) == 0) {
1952 val += 8;
1953 /* program keys in persistent memory */
1954 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST;
1955 goto set_nwkey;
1956 } else {
1957 set_nwkey:
1958 if (isdigit((unsigned char)val[0]) && val[1] == ':') {
1959 /* specifying a full set of four keys */
1960 nwkey.i_defkid = val[0] - '0';
1961 val += 2;
1962 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1963 len = sizeof(keybuf[i]);
1964 val = get_string(val, ",", keybuf[i], &len);
1965 if (val == NULL)
1966 return;
1967 nwkey.i_key[i].i_keylen = len;
1968 nwkey.i_key[i].i_keydat = keybuf[i];
1969 }
1970 if (*val != '\0') {
1971 warnx("SIOCS80211NWKEY: too many keys.");
1972 return;
1973 }
1974 } else {
1975 /*
1976 * length of each key must be either a 5
1977 * character ASCII string or 10 hex digits for
1978 * 40 bit encryption, or 13 character ASCII
1979 * string or 26 hex digits for 128 bit
1980 * encryption.
1981 */
1982 int j;
1983 char *tmp = NULL;
1984 size_t vlen = strlen(val);
1985 switch(vlen) {
1986 case 10:
1987 case 26:
1988 /* 0x must be missing for these lengths */
1989 j = asprintf(&tmp, "0x%s", val);
1990 if (j == -1) {
1991 warnx("malloc failed");
1992 return;
1993 }
1994 val = tmp;
1995 break;
1996 case 12:
1997 case 28:
1998 case 5:
1999 case 13:
2000 /* 0xkey or string case - all is ok */
2001 break;
2002 default:
2003 warnx("Invalid WEP key length");
2004 return;
2005 }
2006 len = sizeof(keybuf[0]);
2007 val = get_string(val, NULL, keybuf[0], &len);
2008 free(tmp);
2009 if (val == NULL)
2010 return;
2011 nwkey.i_key[0].i_keylen = len;
2012 nwkey.i_key[0].i_keydat = keybuf[0];
2013 i = 1;
2014 }
2015 }
2016 (void)strlcpy(nwkey.i_name, ifname, sizeof(nwkey.i_name));
2017
2018 if (actions & A_JOIN) {
2019 memcpy(&join.i_nwkey, &nwkey, sizeof(join.i_nwkey));
2020 join.i_flags |= IEEE80211_JOIN_NWKEY;
2021 return;
2022 }
2023
2024 if (ioctl(sock, SIOCS80211NWKEY, (caddr_t)&nwkey) == -1)
2025 err(1, "%s: SIOCS80211NWKEY", nwkey.i_name);
2026 }
2027
2028 void
setifwpa(const char * val,int d)2029 setifwpa(const char *val, int d)
2030 {
2031 struct ieee80211_wpaparams wpa;
2032
2033 memset(&wpa, 0, sizeof(wpa));
2034 (void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2035 /* Don't read current values. The kernel will set defaults. */
2036 wpa.i_enabled = d;
2037
2038 if (actions & A_JOIN) {
2039 join.i_wpaparams.i_enabled = d;
2040 join.i_flags |= IEEE80211_JOIN_WPA;
2041 return;
2042 }
2043
2044 if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2045 err(1, "%s: SIOCS80211WPAPARMS", wpa.i_name);
2046 }
2047
2048 void
setifwpaprotos(const char * val,int d)2049 setifwpaprotos(const char *val, int d)
2050 {
2051 struct ieee80211_wpaparams wpa;
2052 char *optlist, *str;
2053 u_int rval = 0;
2054
2055 if ((optlist = strdup(val)) == NULL)
2056 err(1, "strdup");
2057 str = strtok(optlist, ",");
2058 while (str != NULL) {
2059 if (strcasecmp(str, "wpa1") == 0)
2060 rval |= IEEE80211_WPA_PROTO_WPA1;
2061 else if (strcasecmp(str, "wpa2") == 0)
2062 rval |= IEEE80211_WPA_PROTO_WPA2;
2063 else
2064 errx(1, "wpaprotos: unknown protocol: %s", str);
2065 str = strtok(NULL, ",");
2066 }
2067 free(optlist);
2068
2069 if (actions & A_JOIN) {
2070 join.i_wpaparams.i_protos = rval;
2071 join.i_flags |= IEEE80211_JOIN_WPA;
2072 return;
2073 }
2074
2075 memset(&wpa, 0, sizeof(wpa));
2076 (void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2077 if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2078 err(1, "%s: SIOCG80211WPAPARMS", wpa.i_name);
2079 wpa.i_protos = rval;
2080 /* Let the kernel set up the appropriate default ciphers. */
2081 wpa.i_ciphers = 0;
2082 wpa.i_groupcipher = 0;
2083
2084 if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2085 err(1, "%s: SIOCS80211WPAPARMS", wpa.i_name);
2086 }
2087
2088 void
setifwpaakms(const char * val,int d)2089 setifwpaakms(const char *val, int d)
2090 {
2091 struct ieee80211_wpaparams wpa;
2092 char *optlist, *str;
2093 u_int rval = 0;
2094
2095 if ((optlist = strdup(val)) == NULL)
2096 err(1, "strdup");
2097 str = strtok(optlist, ",");
2098 while (str != NULL) {
2099 if (strcasecmp(str, "psk") == 0)
2100 rval |= IEEE80211_WPA_AKM_PSK;
2101 else if (strcasecmp(str, "802.1x") == 0)
2102 rval |= IEEE80211_WPA_AKM_8021X;
2103 else
2104 errx(1, "wpaakms: unknown akm: %s", str);
2105 str = strtok(NULL, ",");
2106 }
2107 free(optlist);
2108
2109 if (actions & A_JOIN) {
2110 join.i_wpaparams.i_akms = rval;
2111 join.i_wpaparams.i_enabled =
2112 ((rval & IEEE80211_WPA_AKM_8021X) != 0);
2113 join.i_flags |= IEEE80211_JOIN_WPA;
2114 return;
2115 }
2116
2117 memset(&wpa, 0, sizeof(wpa));
2118 (void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2119 if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2120 err(1, "%s: SIOCG80211WPAPARMS", wpa.i_name);
2121 wpa.i_akms = rval;
2122 /* Enable WPA for 802.1x here. PSK case is handled in setifwpakey(). */
2123 wpa.i_enabled = ((rval & IEEE80211_WPA_AKM_8021X) != 0);
2124
2125 if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2126 err(1, "%s: SIOCS80211WPAPARMS", wpa.i_name);
2127 }
2128
2129 static const struct {
2130 const char *name;
2131 u_int cipher;
2132 } ciphers[] = {
2133 { "usegroup", IEEE80211_WPA_CIPHER_USEGROUP },
2134 { "wep40", IEEE80211_WPA_CIPHER_WEP40 },
2135 { "tkip", IEEE80211_WPA_CIPHER_TKIP },
2136 { "ccmp", IEEE80211_WPA_CIPHER_CCMP },
2137 { "wep104", IEEE80211_WPA_CIPHER_WEP104 }
2138 };
2139
2140 u_int
getwpacipher(const char * name)2141 getwpacipher(const char *name)
2142 {
2143 int i;
2144
2145 for (i = 0; i < sizeof(ciphers) / sizeof(ciphers[0]); i++)
2146 if (strcasecmp(name, ciphers[i].name) == 0)
2147 return ciphers[i].cipher;
2148 return IEEE80211_WPA_CIPHER_NONE;
2149 }
2150
2151 void
setifwpaciphers(const char * val,int d)2152 setifwpaciphers(const char *val, int d)
2153 {
2154 struct ieee80211_wpaparams wpa;
2155 char *optlist, *str;
2156 u_int rval = 0;
2157
2158 if ((optlist = strdup(val)) == NULL)
2159 err(1, "strdup");
2160 str = strtok(optlist, ",");
2161 while (str != NULL) {
2162 u_int cipher = getwpacipher(str);
2163 if (cipher == IEEE80211_WPA_CIPHER_NONE)
2164 errx(1, "wpaciphers: unknown cipher: %s", str);
2165
2166 rval |= cipher;
2167 str = strtok(NULL, ",");
2168 }
2169 free(optlist);
2170
2171 if (actions & A_JOIN) {
2172 join.i_wpaparams.i_ciphers = rval;
2173 join.i_flags |= IEEE80211_JOIN_WPA;
2174 return;
2175 }
2176
2177 memset(&wpa, 0, sizeof(wpa));
2178 (void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2179 if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2180 err(1, "%s: SIOCG80211WPAPARMS", wpa.i_name);
2181 wpa.i_ciphers = rval;
2182
2183 if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2184 err(1, "%s: SIOCS80211WPAPARMS", wpa.i_name);
2185 }
2186
2187 void
setifwpagroupcipher(const char * val,int d)2188 setifwpagroupcipher(const char *val, int d)
2189 {
2190 struct ieee80211_wpaparams wpa;
2191 u_int cipher;
2192
2193 cipher = getwpacipher(val);
2194 if (cipher == IEEE80211_WPA_CIPHER_NONE)
2195 errx(1, "wpagroupcipher: unknown cipher: %s", val);
2196
2197 memset(&wpa, 0, sizeof(wpa));
2198 (void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2199 if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2200 err(1, "%s: SIOCG80211WPAPARMS", wpa.i_name);
2201 wpa.i_groupcipher = cipher;
2202
2203 if (actions & A_JOIN) {
2204 join.i_wpaparams.i_groupcipher = cipher;
2205 join.i_flags |= IEEE80211_JOIN_WPA;
2206 return;
2207 }
2208
2209 if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2210 err(1, "%s: SIOCS80211WPAPARMS", wpa.i_name);
2211 }
2212
2213 void
setifwpakey(const char * val,int d)2214 setifwpakey(const char *val, int d)
2215 {
2216 struct ieee80211_wpaparams wpa;
2217 struct ieee80211_wpapsk psk;
2218 struct ieee80211_nwid nwid;
2219 int passlen;
2220
2221 memset(&psk, 0, sizeof(psk));
2222 if (d != -1) {
2223 memset(&ifr, 0, sizeof(ifr));
2224 ifr.ifr_data = (caddr_t)&nwid;
2225 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2226
2227 /* Use the value specified in 'join' or 'nwid' */
2228 if (joinlen != 0) {
2229 memcpy(nwid.i_nwid, joinname, joinlen);
2230 nwid.i_len = joinlen;
2231 } else if (nwidlen != 0) {
2232 memcpy(nwid.i_nwid, nwidname, nwidlen);
2233 nwid.i_len = nwidlen;
2234 } else {
2235 warnx("no nwid or join command, guessing nwid to use");
2236
2237 if (ioctl(sock, SIOCG80211NWID, (caddr_t)&ifr) == -1)
2238 err(1, "%s: SIOCG80211NWID", ifr.ifr_name);
2239 }
2240
2241 passlen = strlen(val);
2242 if (passlen == 2 + 2 * sizeof(psk.i_psk) &&
2243 val[0] == '0' && val[1] == 'x') {
2244 /* Parse a WPA hex key (must be full-length) */
2245 passlen = sizeof(psk.i_psk);
2246 val = get_string(val, NULL, psk.i_psk, &passlen);
2247 if (val == NULL || passlen != sizeof(psk.i_psk))
2248 errx(1, "wpakey: invalid pre-shared key");
2249 } else {
2250 /* Parse a WPA passphrase */
2251 if (passlen < 8 || passlen > 63)
2252 errx(1, "wpakey: passphrase must be between "
2253 "8 and 63 characters");
2254 if (nwid.i_len == 0)
2255 errx(1, "wpakey: nwid not set");
2256 if (pkcs5_pbkdf2(val, passlen, nwid.i_nwid, nwid.i_len,
2257 psk.i_psk, sizeof(psk.i_psk), 4096) != 0)
2258 errx(1, "wpakey: passphrase hashing failed");
2259 }
2260 psk.i_enabled = 1;
2261 } else
2262 psk.i_enabled = 0;
2263
2264 (void)strlcpy(psk.i_name, ifname, sizeof(psk.i_name));
2265
2266 if (actions & A_JOIN) {
2267 memcpy(&join.i_wpapsk, &psk, sizeof(join.i_wpapsk));
2268 join.i_flags |= IEEE80211_JOIN_WPAPSK;
2269 if (!join.i_wpaparams.i_enabled)
2270 setifwpa(NULL, join.i_wpapsk.i_enabled);
2271 return;
2272 }
2273
2274 if (ioctl(sock, SIOCS80211WPAPSK, (caddr_t)&psk) == -1)
2275 err(1, "%s: SIOCS80211WPAPSK", psk.i_name);
2276
2277 /* And ... automatically enable or disable WPA */
2278 memset(&wpa, 0, sizeof(wpa));
2279 (void)strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2280 if (ioctl(sock, SIOCG80211WPAPARMS, (caddr_t)&wpa) == -1)
2281 err(1, "%s: SIOCG80211WPAPARMS", psk.i_name);
2282 wpa.i_enabled = psk.i_enabled;
2283 if (ioctl(sock, SIOCS80211WPAPARMS, (caddr_t)&wpa) == -1)
2284 err(1, "%s: SIOCS80211WPAPARMS", psk.i_name);
2285 }
2286
2287 void
setifchan(const char * val,int d)2288 setifchan(const char *val, int d)
2289 {
2290 struct ieee80211chanreq channel;
2291 const char *errstr;
2292 int chan;
2293
2294 if (val == NULL) {
2295 if (shownet80211chans || shownet80211nodes)
2296 usage();
2297 shownet80211chans = 1;
2298 return;
2299 }
2300 if (d != 0)
2301 chan = IEEE80211_CHAN_ANY;
2302 else {
2303 chan = strtonum(val, 1, 256, &errstr);
2304 if (errstr) {
2305 warnx("invalid channel %s: %s", val, errstr);
2306 return;
2307 }
2308 }
2309
2310 strlcpy(channel.i_name, ifname, sizeof(channel.i_name));
2311 channel.i_channel = (u_int16_t)chan;
2312 if (ioctl(sock, SIOCS80211CHANNEL, (caddr_t)&channel) == -1)
2313 warn("%s: SIOCS80211CHANNEL", channel.i_name);
2314 }
2315
2316 void
setifscan(const char * val,int d)2317 setifscan(const char *val, int d)
2318 {
2319 if (shownet80211chans || shownet80211nodes)
2320 usage();
2321 shownet80211nodes = 1;
2322 }
2323
2324 #ifndef SMALL
2325
2326 void
setifnwflag(const char * val,int d)2327 setifnwflag(const char *val, int d)
2328 {
2329 static const struct ieee80211_flags nwflags[] = IEEE80211_FLAGS;
2330 u_int i, flag = 0;
2331
2332 for (i = 0; i < (sizeof(nwflags) / sizeof(nwflags[0])); i++) {
2333 if (strcmp(val, nwflags[i].f_name) == 0) {
2334 flag = nwflags[i].f_flag;
2335 break;
2336 }
2337 }
2338 if (flag == 0)
2339 errx(1, "Invalid nwflag: %s", val);
2340
2341 if (ioctl(sock, SIOCG80211FLAGS, (caddr_t)&ifr) != 0)
2342 err(1, "%s: SIOCG80211FLAGS", ifr.ifr_name);
2343
2344 if (d)
2345 ifr.ifr_flags &= ~flag;
2346 else
2347 ifr.ifr_flags |= flag;
2348
2349 if (ioctl(sock, SIOCS80211FLAGS, (caddr_t)&ifr) != 0)
2350 err(1, "%s: SIOCS80211FLAGS", ifr.ifr_name);
2351 }
2352
2353 void
unsetifnwflag(const char * val,int d)2354 unsetifnwflag(const char *val, int d)
2355 {
2356 setifnwflag(val, 1);
2357 }
2358
2359 void
setifpowersave(const char * val,int d)2360 setifpowersave(const char *val, int d)
2361 {
2362 struct ieee80211_power power;
2363 const char *errmsg = NULL;
2364
2365 (void)strlcpy(power.i_name, ifname, sizeof(power.i_name));
2366 if (ioctl(sock, SIOCG80211POWER, (caddr_t)&power) == -1) {
2367 warn("%s: SIOCG80211POWER", power.i_name);
2368 return;
2369 }
2370
2371 if (d != -1 && val != NULL) {
2372 power.i_maxsleep = strtonum(val, 0, INT_MAX, &errmsg);
2373 if (errmsg)
2374 errx(1, "powersave %s: %s", val, errmsg);
2375 }
2376
2377 power.i_enabled = d == -1 ? 0 : 1;
2378 if (ioctl(sock, SIOCS80211POWER, (caddr_t)&power) == -1)
2379 warn("%s: SIOCS80211POWER", power.i_name);
2380 }
2381 #endif
2382
2383 void
print_cipherset(u_int32_t cipherset)2384 print_cipherset(u_int32_t cipherset)
2385 {
2386 const char *sep = "";
2387 int i;
2388
2389 if (cipherset == IEEE80211_WPA_CIPHER_NONE) {
2390 printf("none");
2391 return;
2392 }
2393 for (i = 0; i < sizeof(ciphers) / sizeof(ciphers[0]); i++) {
2394 if (cipherset & ciphers[i].cipher) {
2395 printf("%s%s", sep, ciphers[i].name);
2396 sep = ",";
2397 }
2398 }
2399 }
2400
2401 static void
print_assoc_failures(uint32_t assoc_fail)2402 print_assoc_failures(uint32_t assoc_fail)
2403 {
2404 /* Filter out the most obvious failure cases. */
2405 assoc_fail &= ~IEEE80211_NODEREQ_ASSOCFAIL_ESSID;
2406 if (assoc_fail & IEEE80211_NODEREQ_ASSOCFAIL_PRIVACY)
2407 assoc_fail &= ~IEEE80211_NODEREQ_ASSOCFAIL_WPA_PROTO;
2408 assoc_fail &= ~IEEE80211_NODEREQ_ASSOCFAIL_PRIVACY;
2409
2410 if (assoc_fail == 0)
2411 return;
2412
2413 printb_status(assoc_fail, IEEE80211_NODEREQ_ASSOCFAIL_BITS);
2414 }
2415
2416 void
ieee80211_status(void)2417 ieee80211_status(void)
2418 {
2419 int len, inwid, ijoin, inwkey, ipsk, ichan, ipwr;
2420 int ibssid, iwpa, assocfail = 0;
2421 struct ieee80211_nwid nwid;
2422 struct ieee80211_join join;
2423 struct ieee80211_nwkey nwkey;
2424 struct ieee80211_wpapsk psk;
2425 struct ieee80211_power power;
2426 struct ieee80211chanreq channel;
2427 struct ieee80211_bssid bssid;
2428 struct ieee80211_wpaparams wpa;
2429 struct ieee80211_nodereq nr;
2430 u_int8_t zero_bssid[IEEE80211_ADDR_LEN];
2431 struct ether_addr ea;
2432
2433 /* get current status via ioctls */
2434 memset(&ifr, 0, sizeof(ifr));
2435 ifr.ifr_data = (caddr_t)&nwid;
2436 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2437 inwid = ioctl(sock, SIOCG80211NWID, (caddr_t)&ifr);
2438
2439 ifr.ifr_data = (caddr_t)&join;
2440 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2441 ijoin = ioctl(sock, SIOCG80211JOIN, (caddr_t)&ifr);
2442
2443 memset(&nwkey, 0, sizeof(nwkey));
2444 strlcpy(nwkey.i_name, ifname, sizeof(nwkey.i_name));
2445 inwkey = ioctl(sock, SIOCG80211NWKEY, (caddr_t)&nwkey);
2446
2447 memset(&psk, 0, sizeof(psk));
2448 strlcpy(psk.i_name, ifname, sizeof(psk.i_name));
2449 ipsk = ioctl(sock, SIOCG80211WPAPSK, (caddr_t)&psk);
2450
2451 memset(&power, 0, sizeof(power));
2452 strlcpy(power.i_name, ifname, sizeof(power.i_name));
2453 ipwr = ioctl(sock, SIOCG80211POWER, &power);
2454
2455 memset(&channel, 0, sizeof(channel));
2456 strlcpy(channel.i_name, ifname, sizeof(channel.i_name));
2457 ichan = ioctl(sock, SIOCG80211CHANNEL, (caddr_t)&channel);
2458
2459 memset(&bssid, 0, sizeof(bssid));
2460 strlcpy(bssid.i_name, ifname, sizeof(bssid.i_name));
2461 ibssid = ioctl(sock, SIOCG80211BSSID, &bssid);
2462
2463 memset(&wpa, 0, sizeof(wpa));
2464 strlcpy(wpa.i_name, ifname, sizeof(wpa.i_name));
2465 iwpa = ioctl(sock, SIOCG80211WPAPARMS, &wpa);
2466
2467 /* check if any ieee80211 option is active */
2468 if (inwid == 0 || ijoin == 0 || inwkey == 0 || ipsk == 0 ||
2469 ipwr == 0 || ichan == 0 || ibssid == 0 || iwpa == 0)
2470 fputs("\tieee80211:", stdout);
2471 else
2472 return;
2473
2474 if (inwid == 0) {
2475 /* nwid.i_nwid is not NUL terminated. */
2476 len = nwid.i_len;
2477 if (len > IEEE80211_NWID_LEN)
2478 len = IEEE80211_NWID_LEN;
2479 if (ijoin == 0 && join.i_flags & IEEE80211_JOIN_FOUND)
2480 fputs(" join ", stdout);
2481 else
2482 fputs(" nwid ", stdout);
2483 print_string(nwid.i_nwid, len);
2484 }
2485
2486 if (ichan == 0 && channel.i_channel != 0 &&
2487 channel.i_channel != IEEE80211_CHAN_ANY)
2488 printf(" chan %u", channel.i_channel);
2489
2490 memset(&zero_bssid, 0, sizeof(zero_bssid));
2491 if (ibssid == 0 &&
2492 memcmp(bssid.i_bssid, zero_bssid, IEEE80211_ADDR_LEN) != 0) {
2493 memcpy(&ea.ether_addr_octet, bssid.i_bssid,
2494 sizeof(ea.ether_addr_octet));
2495 printf(" bssid %s", ether_ntoa(&ea));
2496
2497 bzero(&nr, sizeof(nr));
2498 bcopy(bssid.i_bssid, &nr.nr_macaddr, sizeof(nr.nr_macaddr));
2499 strlcpy(nr.nr_ifname, ifname, sizeof(nr.nr_ifname));
2500 if (ioctl(sock, SIOCG80211NODE, &nr) == 0) {
2501 if (nr.nr_max_rssi)
2502 printf(" %u%%", IEEE80211_NODEREQ_RSSI(&nr));
2503 else
2504 printf(" %ddBm", nr.nr_rssi);
2505 assocfail = nr.nr_assoc_fail;
2506 }
2507 }
2508
2509 if (inwkey == 0 && nwkey.i_wepon > IEEE80211_NWKEY_OPEN)
2510 fputs(" nwkey", stdout);
2511
2512 if (ipsk == 0 && psk.i_enabled)
2513 fputs(" wpakey", stdout);
2514 if (iwpa == 0 && wpa.i_enabled) {
2515 const char *sep;
2516
2517 fputs(" wpaprotos ", stdout); sep = "";
2518 if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA1) {
2519 fputs("wpa1", stdout);
2520 sep = ",";
2521 }
2522 if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA2)
2523 printf("%swpa2", sep);
2524
2525 fputs(" wpaakms ", stdout); sep = "";
2526 if (wpa.i_akms & IEEE80211_WPA_AKM_PSK) {
2527 fputs("psk", stdout);
2528 sep = ",";
2529 }
2530 if (wpa.i_akms & IEEE80211_WPA_AKM_8021X)
2531 printf("%s802.1x", sep);
2532
2533 fputs(" wpaciphers ", stdout);
2534 print_cipherset(wpa.i_ciphers);
2535
2536 fputs(" wpagroupcipher ", stdout);
2537 print_cipherset(wpa.i_groupcipher);
2538 }
2539
2540 if (ipwr == 0 && power.i_enabled)
2541 printf(" powersave on (%dms sleep)", power.i_maxsleep);
2542
2543 if (ioctl(sock, SIOCG80211FLAGS, (caddr_t)&ifr) == 0 &&
2544 ifr.ifr_flags) {
2545 putchar(' ');
2546 printb_status(ifr.ifr_flags, IEEE80211_F_USERBITS);
2547 }
2548
2549 if (assocfail) {
2550 putchar(' ');
2551 print_assoc_failures(assocfail);
2552 }
2553 putchar('\n');
2554 if (show_join)
2555 join_status();
2556 if (shownet80211chans)
2557 ieee80211_listchans();
2558 else if (shownet80211nodes)
2559 ieee80211_listnodes();
2560 }
2561
2562 void
showjoin(const char * cmd,int val)2563 showjoin(const char *cmd, int val)
2564 {
2565 show_join = 1;
2566 return;
2567 }
2568
2569 void
join_status(void)2570 join_status(void)
2571 {
2572 struct ieee80211_joinreq_all ja;
2573 struct ieee80211_join *jn = NULL;
2574 struct ieee80211_wpaparams *wpa;
2575 int jsz = 100;
2576 int ojsz;
2577 int i;
2578 int r;
2579 int maxlen, len;
2580
2581 bzero(&ja, sizeof(ja));
2582 jn = recallocarray(NULL, 0, jsz, sizeof(*jn));
2583 if (jn == NULL)
2584 err(1, "recallocarray");
2585 ojsz = jsz;
2586 while (1) {
2587 ja.ja_node = jn;
2588 ja.ja_size = jsz * sizeof(*jn);
2589 strlcpy(ja.ja_ifname, ifname, sizeof(ja.ja_ifname));
2590
2591 if ((r = ioctl(sock, SIOCG80211JOINALL, &ja)) != 0) {
2592 if (errno == E2BIG) {
2593 jsz += 100;
2594 jn = recallocarray(jn, ojsz, jsz, sizeof(*jn));
2595 if (jn == NULL)
2596 err(1, "recallocarray");
2597 ojsz = jsz;
2598 continue;
2599 } else if (errno != ENOENT)
2600 warn("%s: SIOCG80211JOINALL", ja.ja_ifname);
2601 return;
2602 }
2603 break;
2604 }
2605
2606 if (!ja.ja_nodes)
2607 return;
2608
2609 maxlen = 0;
2610 for (i = 0; i < ja.ja_nodes; i++) {
2611 len = len_string(jn[i].i_nwid, jn[i].i_len);
2612 if (len > maxlen)
2613 maxlen = len;
2614 }
2615
2616 for (i = 0; i < ja.ja_nodes; i++) {
2617 printf("\t ");
2618 if (jn[i].i_len > IEEE80211_NWID_LEN)
2619 jn[i].i_len = IEEE80211_NWID_LEN;
2620 len = print_string(jn[i].i_nwid, jn[i].i_len);
2621 printf("%-*s", maxlen - len, "");
2622 if (jn[i].i_flags) {
2623 const char *sep;
2624 printf(" ");
2625
2626 if (jn[i].i_flags & IEEE80211_JOIN_NWKEY)
2627 printf("nwkey");
2628
2629 if (jn[i].i_flags & IEEE80211_JOIN_WPA) {
2630 wpa = &jn[i].i_wpaparams;
2631
2632 printf("wpaprotos "); sep = "";
2633 if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA1) {
2634 printf("wpa1");
2635 sep = ",";
2636 }
2637 if (wpa->i_protos & IEEE80211_WPA_PROTO_WPA2)
2638 printf("%swpa2", sep);
2639
2640 printf(" wpaakms "); sep = "";
2641 if (wpa->i_akms & IEEE80211_WPA_AKM_PSK) {
2642 printf("psk");
2643 sep = ",";
2644 }
2645 if (wpa->i_akms & IEEE80211_WPA_AKM_8021X)
2646 printf("%s802.1x", sep);
2647
2648 printf(" wpaciphers ");
2649 print_cipherset(wpa->i_ciphers);
2650
2651 printf(" wpagroupcipher ");
2652 print_cipherset(wpa->i_groupcipher);
2653 }
2654 }
2655 putchar('\n');
2656 }
2657 }
2658
2659 void
ieee80211_listchans(void)2660 ieee80211_listchans(void)
2661 {
2662 static struct ieee80211_chaninfo chans[256];
2663 struct ieee80211_chanreq_all ca;
2664 int i;
2665
2666 bzero(&ca, sizeof(ca));
2667 bzero(chans, sizeof(chans));
2668 ca.i_chans = chans;
2669 strlcpy(ca.i_name, ifname, sizeof(ca.i_name));
2670
2671 if (ioctl(sock, SIOCG80211ALLCHANS, &ca) != 0) {
2672 warn("%s: SIOCG80211ALLCHANS", ca.i_name);
2673 return;
2674 }
2675 printf("\t\t%4s %-8s %s\n", "chan", "freq", "properties");
2676 for (i = 1; i < nitems(chans); i++) {
2677 if (chans[i].ic_freq == 0)
2678 continue;
2679 printf("\t\t%4d %4d MHz ", i, chans[i].ic_freq);
2680 if (chans[i].ic_flags & IEEE80211_CHANINFO_PASSIVE)
2681 printf("passive scan");
2682 else
2683 putchar('-');
2684 putchar('\n');
2685 }
2686 }
2687
2688 /*
2689 * Returns an integer less than, equal to, or greater than zero if nr1's
2690 * RSSI is respectively greater than, equal to, or less than nr2's RSSI.
2691 */
2692 static int
rssicmp(const void * nr1,const void * nr2)2693 rssicmp(const void *nr1, const void *nr2)
2694 {
2695 const struct ieee80211_nodereq *x = nr1, *y = nr2;
2696 return y->nr_rssi < x->nr_rssi ? -1 : y->nr_rssi > x->nr_rssi;
2697 }
2698
2699 void
ieee80211_listnodes(void)2700 ieee80211_listnodes(void)
2701 {
2702 struct ieee80211_nodereq_all na;
2703 struct ieee80211_nodereq nr[512];
2704 struct ifreq ifr;
2705 int i;
2706
2707 if ((flags & IFF_UP) == 0) {
2708 printf("\t\tcannot scan, interface is down\n");
2709 return;
2710 }
2711
2712 bzero(&ifr, sizeof(ifr));
2713 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2714
2715 if (ioctl(sock, SIOCS80211SCAN, (caddr_t)&ifr) != 0) {
2716 if (errno == EPERM)
2717 printf("\t\tno permission to scan\n");
2718 return;
2719 }
2720
2721 bzero(&na, sizeof(na));
2722 bzero(&nr, sizeof(nr));
2723 na.na_node = nr;
2724 na.na_size = sizeof(nr);
2725 strlcpy(na.na_ifname, ifname, sizeof(na.na_ifname));
2726
2727 if (ioctl(sock, SIOCG80211ALLNODES, &na) != 0) {
2728 warn("%s: SIOCG80211ALLNODES", na.na_ifname);
2729 return;
2730 }
2731
2732 if (!na.na_nodes)
2733 printf("\t\tnone\n");
2734 else
2735 qsort(nr, na.na_nodes, sizeof(*nr), rssicmp);
2736
2737 for (i = 0; i < na.na_nodes; i++) {
2738 printf("\t\t");
2739 ieee80211_printnode(&nr[i]);
2740 putchar('\n');
2741 }
2742 }
2743
2744 void
ieee80211_printnode(struct ieee80211_nodereq * nr)2745 ieee80211_printnode(struct ieee80211_nodereq *nr)
2746 {
2747 int len, i;
2748
2749 if (nr->nr_flags & IEEE80211_NODEREQ_AP ||
2750 nr->nr_capinfo & IEEE80211_CAPINFO_IBSS) {
2751 len = nr->nr_nwid_len;
2752 if (len > IEEE80211_NWID_LEN)
2753 len = IEEE80211_NWID_LEN;
2754 printf("nwid ");
2755 print_string(nr->nr_nwid, len);
2756 putchar(' ');
2757
2758 printf("chan %u ", nr->nr_channel);
2759
2760 printf("bssid %s ",
2761 ether_ntoa((struct ether_addr*)nr->nr_bssid));
2762 }
2763
2764 if ((nr->nr_flags & IEEE80211_NODEREQ_AP) == 0)
2765 printf("lladdr %s ",
2766 ether_ntoa((struct ether_addr*)nr->nr_macaddr));
2767
2768 if (nr->nr_max_rssi)
2769 printf("%u%% ", IEEE80211_NODEREQ_RSSI(nr));
2770 else
2771 printf("%ddBm ", nr->nr_rssi);
2772
2773 if (nr->nr_pwrsave)
2774 printf("powersave ");
2775 /*
2776 * Print our current Tx rate for associated nodes.
2777 * Print the fastest supported rate for APs.
2778 */
2779 if ((nr->nr_flags & (IEEE80211_NODEREQ_AP)) == 0) {
2780 if (nr->nr_flags & IEEE80211_NODEREQ_VHT) {
2781 printf("VHT-MCS%d/%dSS", nr->nr_txmcs, nr->nr_vht_ss);
2782 } else if (nr->nr_flags & IEEE80211_NODEREQ_HT) {
2783 printf("HT-MCS%d ", nr->nr_txmcs);
2784 } else if (nr->nr_nrates) {
2785 printf("%uM ",
2786 (nr->nr_rates[nr->nr_txrate] & IEEE80211_RATE_VAL)
2787 / 2);
2788 }
2789 } else if (nr->nr_max_rxrate) {
2790 printf("%uM HT ", nr->nr_max_rxrate);
2791 } else if (nr->nr_rxmcs[0] != 0) {
2792 for (i = IEEE80211_HT_NUM_MCS - 1; i >= 0; i--) {
2793 if (nr->nr_rxmcs[i / 8] & (1 << (i / 10)))
2794 break;
2795 }
2796 printf("HT-MCS%d ", i);
2797 } else if (nr->nr_nrates) {
2798 printf("%uM ",
2799 (nr->nr_rates[nr->nr_nrates - 1] & IEEE80211_RATE_VAL) / 2);
2800 }
2801 /* ESS is the default, skip it */
2802 nr->nr_capinfo &= ~IEEE80211_CAPINFO_ESS;
2803 if (nr->nr_capinfo) {
2804 printb_status(nr->nr_capinfo, IEEE80211_CAPINFO_BITS);
2805 if (nr->nr_capinfo & IEEE80211_CAPINFO_PRIVACY) {
2806 if (nr->nr_rsnprotos) {
2807 if (nr->nr_rsnprotos & IEEE80211_WPA_PROTO_WPA2)
2808 fputs(",wpa2", stdout);
2809 if (nr->nr_rsnprotos & IEEE80211_WPA_PROTO_WPA1)
2810 fputs(",wpa1", stdout);
2811 } else
2812 fputs(",wep", stdout);
2813
2814 if (nr->nr_rsnakms & IEEE80211_WPA_AKM_8021X ||
2815 nr->nr_rsnakms & IEEE80211_WPA_AKM_SHA256_8021X)
2816 fputs(",802.1x", stdout);
2817 }
2818 putchar(' ');
2819 }
2820
2821 if ((nr->nr_flags & IEEE80211_NODEREQ_AP) == 0)
2822 printb_status(IEEE80211_NODEREQ_STATE(nr->nr_state),
2823 IEEE80211_NODEREQ_STATE_BITS);
2824 else if (nr->nr_assoc_fail)
2825 print_assoc_failures(nr->nr_assoc_fail);
2826 }
2827
2828 void
init_current_media(void)2829 init_current_media(void)
2830 {
2831 struct ifmediareq ifmr;
2832
2833 /*
2834 * If we have not yet done so, grab the currently-selected
2835 * media.
2836 */
2837 if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
2838 (void) memset(&ifmr, 0, sizeof(ifmr));
2839 (void) strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
2840
2841 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
2842 /*
2843 * If we get E2BIG, the kernel is telling us
2844 * that there are more, so we can ignore it.
2845 */
2846 if (errno != E2BIG)
2847 err(1, "%s: SIOCGIFMEDIA", ifmr.ifm_name);
2848 }
2849
2850 media_current = ifmr.ifm_current;
2851 }
2852
2853 /* Sanity. */
2854 if (IFM_TYPE(media_current) == 0)
2855 errx(1, "%s: no link type?", ifname);
2856 }
2857
2858 void
process_media_commands(void)2859 process_media_commands(void)
2860 {
2861
2862 if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) {
2863 /* Nothing to do. */
2864 return;
2865 }
2866
2867 /*
2868 * Media already set up, and commands sanity-checked. Set/clear
2869 * any options, and we're ready to go.
2870 */
2871 media_current |= mediaopt_set;
2872 media_current &= ~mediaopt_clear;
2873
2874 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2875 ifr.ifr_media = media_current;
2876
2877 if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) == -1)
2878 err(1, "%s: SIOCSIFMEDIA", ifr.ifr_name);
2879 }
2880
2881 void
setmedia(const char * val,int d)2882 setmedia(const char *val, int d)
2883 {
2884 uint64_t type, subtype, inst;
2885
2886 if (val == NULL) {
2887 if (showmediaflag)
2888 usage();
2889 showmediaflag = 1;
2890 return;
2891 }
2892
2893 init_current_media();
2894
2895 /* Only one media command may be given. */
2896 if (actions & A_MEDIA)
2897 errx(1, "only one `media' command may be issued");
2898
2899 /* Must not come after mode commands */
2900 if (actions & A_MEDIAMODE)
2901 errx(1, "may not issue `media' after `mode' commands");
2902
2903 /* Must not come after mediaopt commands */
2904 if (actions & A_MEDIAOPT)
2905 errx(1, "may not issue `media' after `mediaopt' commands");
2906
2907 /*
2908 * No need to check if `instance' has been issued; setmediainst()
2909 * craps out if `media' has not been specified.
2910 */
2911
2912 type = IFM_TYPE(media_current);
2913 inst = IFM_INST(media_current);
2914
2915 /* Look up the subtype. */
2916 subtype = get_media_subtype(type, val);
2917
2918 /* Build the new current media word. */
2919 media_current = IFM_MAKEWORD(type, subtype, 0, inst);
2920
2921 /* Media will be set after other processing is complete. */
2922 }
2923
2924 void
setmediamode(const char * val,int d)2925 setmediamode(const char *val, int d)
2926 {
2927 uint64_t type, subtype, options, inst, mode;
2928
2929 init_current_media();
2930
2931 /* Can only issue `mode' once. */
2932 if (actions & A_MEDIAMODE)
2933 errx(1, "only one `mode' command may be issued");
2934
2935 type = IFM_TYPE(media_current);
2936 subtype = IFM_SUBTYPE(media_current);
2937 options = IFM_OPTIONS(media_current);
2938 inst = IFM_INST(media_current);
2939
2940 if ((mode = get_media_mode(type, val)) == -1)
2941 errx(1, "invalid media mode: %s", val);
2942 media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode;
2943 /* Media will be set after other processing is complete. */
2944 }
2945
2946 void
unsetmediamode(const char * val,int d)2947 unsetmediamode(const char *val, int d)
2948 {
2949 uint64_t type, subtype, options, inst;
2950
2951 init_current_media();
2952
2953 /* Can only issue `mode' once. */
2954 if (actions & A_MEDIAMODE)
2955 errx(1, "only one `mode' command may be issued");
2956
2957 type = IFM_TYPE(media_current);
2958 subtype = IFM_SUBTYPE(media_current);
2959 options = IFM_OPTIONS(media_current);
2960 inst = IFM_INST(media_current);
2961
2962 media_current = IFM_MAKEWORD(type, subtype, options, inst) |
2963 (IFM_AUTO << IFM_MSHIFT);
2964 /* Media will be set after other processing is complete. */
2965 }
2966
2967 void
setmediaopt(const char * val,int d)2968 setmediaopt(const char *val, int d)
2969 {
2970
2971 init_current_media();
2972
2973 /* Can only issue `mediaopt' once. */
2974 if (actions & A_MEDIAOPTSET)
2975 errx(1, "only one `mediaopt' command may be issued");
2976
2977 /* Can't issue `mediaopt' if `instance' has already been issued. */
2978 if (actions & A_MEDIAINST)
2979 errx(1, "may not issue `mediaopt' after `instance'");
2980
2981 mediaopt_set = get_media_options(IFM_TYPE(media_current), val);
2982
2983 /* Media will be set after other processing is complete. */
2984 }
2985
2986 void
unsetmediaopt(const char * val,int d)2987 unsetmediaopt(const char *val, int d)
2988 {
2989
2990 init_current_media();
2991
2992 /* Can only issue `-mediaopt' once. */
2993 if (actions & A_MEDIAOPTCLR)
2994 errx(1, "only one `-mediaopt' command may be issued");
2995
2996 /* May not issue `media' and `-mediaopt'. */
2997 if (actions & A_MEDIA)
2998 errx(1, "may not issue both `media' and `-mediaopt'");
2999
3000 /*
3001 * No need to check for A_MEDIAINST, since the test for A_MEDIA
3002 * implicitly checks for A_MEDIAINST.
3003 */
3004
3005 mediaopt_clear = get_media_options(IFM_TYPE(media_current), val);
3006
3007 /* Media will be set after other processing is complete. */
3008 }
3009
3010 void
setmediainst(const char * val,int d)3011 setmediainst(const char *val, int d)
3012 {
3013 uint64_t type, subtype, options, inst;
3014 const char *errmsg = NULL;
3015
3016 init_current_media();
3017
3018 /* Can only issue `instance' once. */
3019 if (actions & A_MEDIAINST)
3020 errx(1, "only one `instance' command may be issued");
3021
3022 /* Must have already specified `media' */
3023 if ((actions & A_MEDIA) == 0)
3024 errx(1, "must specify `media' before `instance'");
3025
3026 type = IFM_TYPE(media_current);
3027 subtype = IFM_SUBTYPE(media_current);
3028 options = IFM_OPTIONS(media_current);
3029
3030 inst = strtonum(val, 0, IFM_INST_MAX, &errmsg);
3031 if (errmsg)
3032 errx(1, "media instance %s: %s", val, errmsg);
3033
3034 media_current = IFM_MAKEWORD(type, subtype, options, inst);
3035
3036 /* Media will be set after other processing is complete. */
3037 }
3038
3039
3040 const struct ifmedia_description ifm_type_descriptions[] =
3041 IFM_TYPE_DESCRIPTIONS;
3042
3043 const struct ifmedia_description ifm_subtype_descriptions[] =
3044 IFM_SUBTYPE_DESCRIPTIONS;
3045
3046 const struct ifmedia_description ifm_mode_descriptions[] =
3047 IFM_MODE_DESCRIPTIONS;
3048
3049 const struct ifmedia_description ifm_option_descriptions[] =
3050 IFM_OPTION_DESCRIPTIONS;
3051
3052 const char *
get_media_type_string(uint64_t mword)3053 get_media_type_string(uint64_t mword)
3054 {
3055 const struct ifmedia_description *desc;
3056
3057 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
3058 desc++) {
3059 if (IFM_TYPE(mword) == desc->ifmt_word)
3060 return (desc->ifmt_string);
3061 }
3062 return ("<unknown type>");
3063 }
3064
3065 const char *
get_media_subtype_string(uint64_t mword)3066 get_media_subtype_string(uint64_t mword)
3067 {
3068 const struct ifmedia_description *desc;
3069
3070 for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
3071 desc++) {
3072 if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
3073 IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
3074 return (desc->ifmt_string);
3075 }
3076 return ("<unknown subtype>");
3077 }
3078
3079 uint64_t
get_media_subtype(uint64_t type,const char * val)3080 get_media_subtype(uint64_t type, const char *val)
3081 {
3082 uint64_t rval;
3083
3084 rval = lookup_media_word(ifm_subtype_descriptions, type, val);
3085 if (rval == -1)
3086 errx(1, "unknown %s media subtype: %s",
3087 get_media_type_string(type), val);
3088
3089 return (rval);
3090 }
3091
3092 uint64_t
get_media_mode(uint64_t type,const char * val)3093 get_media_mode(uint64_t type, const char *val)
3094 {
3095 uint64_t rval;
3096
3097 rval = lookup_media_word(ifm_mode_descriptions, type, val);
3098 if (rval == -1)
3099 errx(1, "unknown %s media mode: %s",
3100 get_media_type_string(type), val);
3101 return (rval);
3102 }
3103
3104 uint64_t
get_media_options(uint64_t type,const char * val)3105 get_media_options(uint64_t type, const char *val)
3106 {
3107 char *optlist, *str;
3108 uint64_t option, rval = 0;
3109
3110 /* We muck with the string, so copy it. */
3111 optlist = strdup(val);
3112 if (optlist == NULL)
3113 err(1, "strdup");
3114 str = optlist;
3115
3116 /*
3117 * Look up the options in the user-provided comma-separated list.
3118 */
3119 for (; (str = strtok(str, ",")) != NULL; str = NULL) {
3120 option = lookup_media_word(ifm_option_descriptions, type, str);
3121 if (option == -1)
3122 errx(1, "unknown %s media option: %s",
3123 get_media_type_string(type), str);
3124 rval |= IFM_OPTIONS(option);
3125 }
3126
3127 free(optlist);
3128 return (rval);
3129 }
3130
3131 uint64_t
lookup_media_word(const struct ifmedia_description * desc,uint64_t type,const char * val)3132 lookup_media_word(const struct ifmedia_description *desc, uint64_t type,
3133 const char *val)
3134 {
3135
3136 for (; desc->ifmt_string != NULL; desc++) {
3137 if (IFM_TYPE_MATCH(desc->ifmt_word, type) &&
3138 strcasecmp(desc->ifmt_string, val) == 0)
3139 return (desc->ifmt_word);
3140 }
3141 return (-1);
3142 }
3143
3144 void
print_media_word(uint64_t ifmw,int print_type,int as_syntax)3145 print_media_word(uint64_t ifmw, int print_type, int as_syntax)
3146 {
3147 const struct ifmedia_description *desc;
3148 uint64_t seen_option = 0;
3149
3150 if (print_type)
3151 printf("%s ", get_media_type_string(ifmw));
3152 printf("%s%s", as_syntax ? "media " : "",
3153 get_media_subtype_string(ifmw));
3154
3155 /* Find mode. */
3156 if (IFM_MODE(ifmw) != 0) {
3157 for (desc = ifm_mode_descriptions; desc->ifmt_string != NULL;
3158 desc++) {
3159 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
3160 IFM_MODE(ifmw) == IFM_MODE(desc->ifmt_word)) {
3161 printf(" mode %s", desc->ifmt_string);
3162 break;
3163 }
3164 }
3165 }
3166
3167 /* Find options. */
3168 for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
3169 desc++) {
3170 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
3171 (IFM_OPTIONS(ifmw) & IFM_OPTIONS(desc->ifmt_word)) != 0 &&
3172 (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
3173 if (seen_option == 0)
3174 printf(" %s", as_syntax ? "mediaopt " : "");
3175 printf("%s%s", seen_option ? "," : "",
3176 desc->ifmt_string);
3177 seen_option |= IFM_OPTIONS(desc->ifmt_word);
3178 }
3179 }
3180 if (IFM_INST(ifmw) != 0)
3181 printf(" instance %lld", IFM_INST(ifmw));
3182 }
3183
3184 static void
print_tunnel(const struct if_laddrreq * req)3185 print_tunnel(const struct if_laddrreq *req)
3186 {
3187 char psrcaddr[NI_MAXHOST];
3188 char psrcport[NI_MAXSERV];
3189 char pdstaddr[NI_MAXHOST];
3190 char pdstport[NI_MAXSERV];
3191 const char *ver = "";
3192 const int niflag = NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM;
3193
3194 if (req == NULL) {
3195 printf("(unset)");
3196 return;
3197 }
3198
3199 psrcaddr[0] = pdstaddr[0] = '\0';
3200
3201 if (getnameinfo((struct sockaddr *)&req->addr, req->addr.ss_len,
3202 psrcaddr, sizeof(psrcaddr), psrcport, sizeof(psrcport),
3203 niflag) != 0)
3204 strlcpy(psrcaddr, "<error>", sizeof(psrcaddr));
3205 if (req->addr.ss_family == AF_INET6)
3206 ver = "6";
3207
3208 printf("inet%s %s", ver, psrcaddr);
3209 if (strcmp(psrcport, "0") != 0)
3210 printf(":%s", psrcport);
3211
3212 if (req->dstaddr.ss_family != AF_UNSPEC) {
3213 if (getnameinfo((struct sockaddr *)&req->dstaddr,
3214 req->dstaddr.ss_len, pdstaddr, sizeof(pdstaddr),
3215 pdstport, sizeof(pdstport), niflag) != 0)
3216 strlcpy(pdstaddr, "<error>", sizeof(pdstaddr));
3217
3218 printf(" --> %s", pdstaddr);
3219 if (strcmp(pdstport, "0") != 0)
3220 printf(":%s", pdstport);
3221 }
3222 }
3223
3224 static void
phys_status(int force)3225 phys_status(int force)
3226 {
3227 struct if_laddrreq req;
3228 struct if_laddrreq *r = &req;
3229
3230 memset(&req, 0, sizeof(req));
3231 (void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
3232 if (ioctl(sock, SIOCGLIFPHYADDR, (caddr_t)&req) == -1) {
3233 if (errno != EADDRNOTAVAIL)
3234 return;
3235
3236 r = NULL;
3237 }
3238
3239 printf("\ttunnel: ");
3240 print_tunnel(r);
3241
3242 if (ioctl(sock, SIOCGLIFPHYTTL, (caddr_t)&ifr) == 0) {
3243 if (ifr.ifr_ttl == -1)
3244 printf(" ttl copy");
3245 else if (ifr.ifr_ttl > 0)
3246 printf(" ttl %d", ifr.ifr_ttl);
3247 }
3248
3249 if (ioctl(sock, SIOCGLIFPHYDF, (caddr_t)&ifr) == 0)
3250 printf(" %s", ifr.ifr_df ? "df" : "nodf");
3251
3252 #ifndef SMALL
3253 if (ioctl(sock, SIOCGLIFPHYECN, (caddr_t)&ifr) == 0)
3254 printf(" %s", ifr.ifr_metric ? "ecn" : "noecn");
3255
3256 if (ioctl(sock, SIOCGLIFPHYRTABLE, (caddr_t)&ifr) == 0 &&
3257 (rdomainid != 0 || ifr.ifr_rdomainid != 0))
3258 printf(" rdomain %d", ifr.ifr_rdomainid);
3259 #endif
3260 printf("\n");
3261 }
3262
3263 #ifndef SMALL
3264 const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
3265
3266 const struct ifmedia_status_description ifm_status_descriptions[] =
3267 IFM_STATUS_DESCRIPTIONS;
3268 #endif
3269
3270 const struct if_status_description if_status_descriptions[] =
3271 LINK_STATE_DESCRIPTIONS;
3272
3273 const char *
get_linkstate(int mt,int link_state)3274 get_linkstate(int mt, int link_state)
3275 {
3276 const struct if_status_description *p;
3277 static char buf[8];
3278
3279 for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
3280 if (LINK_STATE_DESC_MATCH(p, mt, link_state))
3281 return (p->ifs_string);
3282 }
3283 snprintf(buf, sizeof(buf), "[#%d]", link_state);
3284 return buf;
3285 }
3286
3287 /*
3288 * Print the status of the interface. If an address family was
3289 * specified, show it and it only; otherwise, show them all.
3290 */
3291 void
status(int link,struct sockaddr_dl * sdl,int ls,int ifaliases)3292 status(int link, struct sockaddr_dl *sdl, int ls, int ifaliases)
3293 {
3294 const struct afswtch *p = afp;
3295 struct ifmediareq ifmr;
3296 #ifndef SMALL
3297 struct ifreq ifrdesc;
3298 struct ifkalivereq ikardesc;
3299 char ifdescr[IFDESCRSIZE];
3300 char pifname[IF_NAMESIZE];
3301 #endif
3302 uint64_t *media_list;
3303 int i;
3304 char sep;
3305
3306
3307 printf("%s: ", ifname);
3308 printb("flags", flags | (xflags << 16), IFFBITS);
3309 #ifndef SMALL
3310 if (rdomainid)
3311 printf(" rdomain %d", rdomainid);
3312 #endif
3313 if (metric)
3314 printf(" metric %lu", metric);
3315 if (mtu)
3316 printf(" mtu %lu", mtu);
3317 putchar('\n');
3318 #ifndef SMALL
3319 if (showcapsflag)
3320 printifhwfeatures(NULL, 1);
3321 #endif
3322 if (sdl != NULL && sdl->sdl_alen &&
3323 (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP))
3324 (void)printf("\tlladdr %s\n", ether_ntoa(
3325 (struct ether_addr *)LLADDR(sdl)));
3326
3327 sep = '\t';
3328 #ifndef SMALL
3329 (void) memset(&ifrdesc, 0, sizeof(ifrdesc));
3330 (void) strlcpy(ifrdesc.ifr_name, ifname, sizeof(ifrdesc.ifr_name));
3331 ifrdesc.ifr_data = (caddr_t)&ifdescr;
3332 if (ioctl(sock, SIOCGIFDESCR, &ifrdesc) == 0 &&
3333 strlen(ifrdesc.ifr_data))
3334 printf("\tdescription: %s\n", ifrdesc.ifr_data);
3335
3336 if (sdl != NULL) {
3337 printf("%cindex %u", sep, sdl->sdl_index);
3338 sep = ' ';
3339 }
3340 if (!is_bridge() && ioctl(sock, SIOCGIFPRIORITY, &ifrdesc) == 0) {
3341 printf("%cpriority %d", sep, ifrdesc.ifr_metric);
3342 sep = ' ';
3343 }
3344 #endif
3345 printf("%cllprio %d\n", sep, llprio);
3346
3347 #ifndef SMALL
3348 (void) memset(&ikardesc, 0, sizeof(ikardesc));
3349 (void) strlcpy(ikardesc.ikar_name, ifname, sizeof(ikardesc.ikar_name));
3350 if (ioctl(sock, SIOCGETKALIVE, &ikardesc) == 0 &&
3351 (ikardesc.ikar_timeo != 0 || ikardesc.ikar_cnt != 0))
3352 printf("\tkeepalive: timeout %d count %d\n",
3353 ikardesc.ikar_timeo, ikardesc.ikar_cnt);
3354 if (ioctl(sock, SIOCGIFPAIR, &ifrdesc) == 0 && ifrdesc.ifr_index != 0 &&
3355 if_indextoname(ifrdesc.ifr_index, pifname) != NULL)
3356 printf("\tpatch: %s\n", pifname);
3357 #endif
3358 getencap();
3359 #ifndef SMALL
3360 carp_status();
3361 pfsync_status();
3362 pppoe_status();
3363 sppp_status();
3364 mpls_status();
3365 pflow_status();
3366 umb_status();
3367 wg_status(ifaliases);
3368 #endif
3369 trunk_status();
3370 getifgroups();
3371
3372 (void) memset(&ifmr, 0, sizeof(ifmr));
3373 (void) strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
3374
3375 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
3376 /*
3377 * Interface doesn't support SIOC{G,S}IFMEDIA.
3378 */
3379 if (ls != LINK_STATE_UNKNOWN)
3380 printf("\tstatus: %s\n",
3381 get_linkstate(sdl->sdl_type, ls));
3382 goto proto_status;
3383 }
3384
3385 if (ifmr.ifm_count == 0) {
3386 warnx("%s: no media types?", ifname);
3387 goto proto_status;
3388 }
3389
3390 media_list = calloc(ifmr.ifm_count, sizeof(*media_list));
3391 if (media_list == NULL)
3392 err(1, "calloc");
3393 ifmr.ifm_ulist = media_list;
3394
3395 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1)
3396 err(1, "%s: SIOCGIFMEDIA", ifmr.ifm_name);
3397
3398 printf("\tmedia: ");
3399 print_media_word(ifmr.ifm_current, 1, 0);
3400 if (ifmr.ifm_active != ifmr.ifm_current) {
3401 putchar(' ');
3402 putchar('(');
3403 print_media_word(ifmr.ifm_active, 0, 0);
3404 putchar(')');
3405 }
3406 putchar('\n');
3407
3408 #ifdef SMALL
3409 printf("\tstatus: %s\n", get_linkstate(sdl->sdl_type, ls));
3410 #else
3411 if (ifmr.ifm_status & IFM_AVALID) {
3412 const struct ifmedia_status_description *ifms;
3413 int bitno, found = 0;
3414
3415 printf("\tstatus: ");
3416 for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
3417 for (ifms = ifm_status_descriptions;
3418 ifms->ifms_valid != 0; ifms++) {
3419 if (ifms->ifms_type !=
3420 IFM_TYPE(ifmr.ifm_current) ||
3421 ifms->ifms_valid !=
3422 ifm_status_valid_list[bitno])
3423 continue;
3424 printf("%s%s", found ? ", " : "",
3425 IFM_STATUS_DESC(ifms, ifmr.ifm_status));
3426 found = 1;
3427
3428 /*
3429 * For each valid indicator bit, there's
3430 * only one entry for each media type, so
3431 * terminate the inner loop now.
3432 */
3433 break;
3434 }
3435 }
3436
3437 if (found == 0)
3438 printf("unknown");
3439 putchar('\n');
3440 }
3441
3442 if (showtransceiver) {
3443 if (if_sff_info(0) == -1)
3444 if (!aflag && errno != EPERM && errno != ENOTTY)
3445 warn("%s transceiver", ifname);
3446 }
3447 #endif
3448 ieee80211_status();
3449
3450 if (showmediaflag) {
3451 uint64_t type;
3452 int printed_type = 0;
3453
3454 for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
3455 for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
3456 if (IFM_TYPE(media_list[i]) == type) {
3457
3458 /*
3459 * Don't advertise media with fixed
3460 * data rates for wireless interfaces.
3461 * Normal people don't need these.
3462 */
3463 if (type == IFM_IEEE80211 &&
3464 (media_list[i] & IFM_TMASK) !=
3465 IFM_AUTO)
3466 continue;
3467
3468 if (printed_type == 0) {
3469 printf("\tsupported media:\n");
3470 printed_type = 1;
3471 }
3472 printf("\t\t");
3473 print_media_word(media_list[i], 0, 1);
3474 printf("\n");
3475 }
3476 }
3477 }
3478 }
3479
3480 free(media_list);
3481
3482 proto_status:
3483 if (link == 0) {
3484 if ((p = afp) != NULL) {
3485 p->af_status(1);
3486 } else for (p = afs; p->af_name; p++) {
3487 ifr.ifr_addr.sa_family = p->af_af;
3488 p->af_status(0);
3489 }
3490 }
3491
3492 phys_status(0);
3493 #ifndef SMALL
3494 bridge_status();
3495 #endif
3496 }
3497
3498 void
in_status(int force)3499 in_status(int force)
3500 {
3501 struct sockaddr_in *sin, sin2;
3502
3503 getsock(AF_INET);
3504 if (sock == -1) {
3505 if (errno == EPROTONOSUPPORT)
3506 return;
3507 err(1, "socket");
3508 }
3509 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3510 sin = (struct sockaddr_in *)&ifr.ifr_addr;
3511
3512 /*
3513 * We keep the interface address and reset it before each
3514 * ioctl() so we can get ifaliases information (as opposed
3515 * to the primary interface netmask/dstaddr/broadaddr, if
3516 * the ifr_addr field is zero).
3517 */
3518 memcpy(&sin2, &ifr.ifr_addr, sizeof(sin2));
3519
3520 printf("\tinet %s", inet_ntoa(sin->sin_addr));
3521 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3522 if (ioctl(sock, SIOCGIFNETMASK, (caddr_t)&ifr) == -1) {
3523 if (errno != EADDRNOTAVAIL)
3524 warn("SIOCGIFNETMASK");
3525 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3526 } else
3527 netmask.sin_addr =
3528 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
3529 if (flags & IFF_POINTOPOINT) {
3530 memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
3531 if (ioctl(sock, SIOCGIFDSTADDR, (caddr_t)&ifr) == -1) {
3532 if (errno == EADDRNOTAVAIL)
3533 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3534 else
3535 warn("SIOCGIFDSTADDR");
3536 }
3537 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3538 sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
3539 printf(" --> %s", inet_ntoa(sin->sin_addr));
3540 }
3541 printf(" netmask 0x%x", ntohl(netmask.sin_addr.s_addr));
3542 if (flags & IFF_BROADCAST) {
3543 memcpy(&ifr.ifr_addr, &sin2, sizeof(sin2));
3544 if (ioctl(sock, SIOCGIFBRDADDR, (caddr_t)&ifr) == -1) {
3545 if (errno == EADDRNOTAVAIL)
3546 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
3547 else
3548 warn("SIOCGIFBRDADDR");
3549 }
3550 (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3551 sin = (struct sockaddr_in *)&ifr.ifr_addr;
3552 if (sin->sin_addr.s_addr != 0)
3553 printf(" broadcast %s", inet_ntoa(sin->sin_addr));
3554 }
3555 putchar('\n');
3556 }
3557
3558 void
setifprefixlen(const char * addr,int d)3559 setifprefixlen(const char *addr, int d)
3560 {
3561 if (afp->af_getprefix)
3562 afp->af_getprefix(addr, MASK);
3563 explicit_prefix = 1;
3564 }
3565
3566 void
in6_fillscopeid(struct sockaddr_in6 * sin6)3567 in6_fillscopeid(struct sockaddr_in6 *sin6)
3568 {
3569 #ifdef __KAME__
3570 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
3571 sin6->sin6_scope_id == 0) {
3572 sin6->sin6_scope_id =
3573 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
3574 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
3575 }
3576 #endif /* __KAME__ */
3577 }
3578
3579 /* XXX not really an alias */
3580 void
in6_alias(struct in6_ifreq * creq)3581 in6_alias(struct in6_ifreq *creq)
3582 {
3583 struct sockaddr_in6 *sin6;
3584 struct in6_ifreq ifr6; /* shadows file static variable */
3585 u_int32_t scopeid;
3586 char hbuf[NI_MAXHOST];
3587 const int niflag = NI_NUMERICHOST;
3588
3589 /* Get the non-alias address for this interface. */
3590 getsock(AF_INET6);
3591 if (sock == -1) {
3592 if (errno == EPROTONOSUPPORT)
3593 return;
3594 err(1, "socket");
3595 }
3596
3597 sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
3598
3599 in6_fillscopeid(sin6);
3600 scopeid = sin6->sin6_scope_id;
3601 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
3602 hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
3603 strlcpy(hbuf, "", sizeof hbuf);
3604 printf("\tinet6 %s", hbuf);
3605
3606 if (flags & IFF_POINTOPOINT) {
3607 (void) memset(&ifr6, 0, sizeof(ifr6));
3608 (void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
3609 ifr6.ifr_addr = creq->ifr_addr;
3610 if (ioctl(sock, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) == -1) {
3611 if (errno != EADDRNOTAVAIL)
3612 warn("SIOCGIFDSTADDR_IN6");
3613 (void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
3614 ifr6.ifr_addr.sin6_family = AF_INET6;
3615 ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
3616 }
3617 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
3618 in6_fillscopeid(sin6);
3619 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
3620 hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
3621 strlcpy(hbuf, "", sizeof hbuf);
3622 printf(" --> %s", hbuf);
3623 }
3624
3625 (void) memset(&ifr6, 0, sizeof(ifr6));
3626 (void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
3627 ifr6.ifr_addr = creq->ifr_addr;
3628 if (ioctl(sock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == -1) {
3629 if (errno != EADDRNOTAVAIL)
3630 warn("SIOCGIFNETMASK_IN6");
3631 } else {
3632 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
3633 printf(" prefixlen %d", prefix(&sin6->sin6_addr,
3634 sizeof(struct in6_addr)));
3635 }
3636
3637 (void) memset(&ifr6, 0, sizeof(ifr6));
3638 (void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
3639 ifr6.ifr_addr = creq->ifr_addr;
3640 if (ioctl(sock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) == -1) {
3641 if (errno != EADDRNOTAVAIL)
3642 warn("SIOCGIFAFLAG_IN6");
3643 } else {
3644 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
3645 printf(" anycast");
3646 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
3647 printf(" tentative");
3648 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
3649 printf(" duplicated");
3650 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
3651 printf(" detached");
3652 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
3653 printf(" deprecated");
3654 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_AUTOCONF)
3655 printf(" autoconf");
3656 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TEMPORARY)
3657 printf(" temporary");
3658 }
3659
3660 if (scopeid)
3661 printf(" scopeid 0x%x", scopeid);
3662
3663 if (Lflag) {
3664 struct in6_addrlifetime *lifetime;
3665
3666 (void) memset(&ifr6, 0, sizeof(ifr6));
3667 (void) strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
3668 ifr6.ifr_addr = creq->ifr_addr;
3669 lifetime = &ifr6.ifr_ifru.ifru_lifetime;
3670 if (ioctl(sock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) == -1) {
3671 if (errno != EADDRNOTAVAIL)
3672 warn("SIOCGIFALIFETIME_IN6");
3673 } else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
3674 time_t t = time(NULL);
3675
3676 printf(" pltime ");
3677 if (lifetime->ia6t_preferred) {
3678 printf("%s", lifetime->ia6t_preferred < t
3679 ? "0" :
3680 sec2str(lifetime->ia6t_preferred - t));
3681 } else
3682 printf("infty");
3683
3684 printf(" vltime ");
3685 if (lifetime->ia6t_expire) {
3686 printf("%s", lifetime->ia6t_expire < t
3687 ? "0"
3688 : sec2str(lifetime->ia6t_expire - t));
3689 } else
3690 printf("infty");
3691 }
3692 }
3693
3694 printf("\n");
3695 }
3696
3697 void
in6_status(int force)3698 in6_status(int force)
3699 {
3700 in6_alias((struct in6_ifreq *)&ifr6);
3701 }
3702
3703 #ifndef SMALL
3704 void
settunnel(const char * src,const char * dst)3705 settunnel(const char *src, const char *dst)
3706 {
3707 char srcbuf[HOST_NAME_MAX], dstbuf[HOST_NAME_MAX];
3708 const char *srcport, *dstport;
3709 const char *srcaddr, *dstaddr;
3710 struct addrinfo *srcres, *dstres;
3711 struct addrinfo hints = {
3712 .ai_family = AF_UNSPEC,
3713 .ai_socktype = SOCK_DGRAM,
3714 .ai_protocol = IPPROTO_UDP,
3715 .ai_flags = AI_PASSIVE,
3716 };
3717 int ecode;
3718 size_t len;
3719 struct if_laddrreq req;
3720
3721 srcport = strchr(src, ':');
3722 if (srcport == NULL || srcport != strrchr(src, ':')) {
3723 /* no port or IPv6 */
3724 srcaddr = src;
3725 srcport = NULL;
3726 } else {
3727 len = srcport - src;
3728 if (len >= sizeof(srcbuf))
3729 errx(1, "src %s bad value", src);
3730 memcpy(srcbuf, src, len);
3731 srcbuf[len] = '\0';
3732
3733 srcaddr = srcbuf;
3734 srcport++;
3735 }
3736
3737 dstport = strchr(dst, ':');
3738 if (dstport == NULL || dstport != strrchr(dst, ':')) {
3739 /* no port or IPv6 */
3740 dstaddr = dst;
3741 dstport = NULL;
3742 } else {
3743 len = dstport - dst;
3744 if (len >= sizeof(dstbuf))
3745 errx(1, "dst %s bad value", dst);
3746 memcpy(dstbuf, dst, len);
3747 dstbuf[len] = '\0';
3748
3749 dstaddr = dstbuf;
3750 dstport++;
3751 }
3752
3753 if ((ecode = getaddrinfo(srcaddr, srcport, &hints, &srcres)) != 0)
3754 errx(1, "error in parsing address string: %s",
3755 gai_strerror(ecode));
3756
3757 hints.ai_flags = 0;
3758 if ((ecode = getaddrinfo(dstaddr, dstport, &hints, &dstres)) != 0)
3759 errx(1, "error in parsing address string: %s",
3760 gai_strerror(ecode));
3761
3762 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
3763 errx(1,
3764 "source and destination address families do not match");
3765
3766 memset(&req, 0, sizeof(req));
3767 (void) strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
3768 memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
3769 memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
3770 if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1)
3771 warn("SIOCSLIFPHYADDR");
3772
3773 freeaddrinfo(srcres);
3774 freeaddrinfo(dstres);
3775 }
3776
3777 void
settunneladdr(const char * src,int ignored)3778 settunneladdr(const char *src, int ignored)
3779 {
3780 char srcbuf[HOST_NAME_MAX];
3781 const char *srcport;
3782 const char *srcaddr;
3783 struct addrinfo *srcres;
3784 struct addrinfo hints = {
3785 .ai_family = AF_UNSPEC,
3786 .ai_socktype = SOCK_DGRAM,
3787 .ai_protocol = IPPROTO_UDP,
3788 .ai_flags = AI_PASSIVE,
3789 };
3790 struct if_laddrreq req;
3791 ssize_t len;
3792 int rv;
3793
3794 srcport = strchr(src, ':');
3795 if (srcport == NULL || srcport != strrchr(src, ':')) {
3796 /* no port or IPv6 */
3797 srcaddr = src;
3798 srcport = NULL;
3799 } else {
3800 len = srcport - src;
3801 if (len >= sizeof(srcbuf))
3802 errx(1, "src %s bad value", src);
3803 memcpy(srcbuf, src, len);
3804 srcbuf[len] = '\0';
3805
3806 srcaddr = srcbuf;
3807 srcport++;
3808 }
3809
3810 rv = getaddrinfo(srcaddr, srcport, &hints, &srcres);
3811 if (rv != 0)
3812 errx(1, "tunneladdr %s: %s", src, gai_strerror(rv));
3813
3814 memset(&req, 0, sizeof(req));
3815 len = strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name));
3816 if (len >= sizeof(req.iflr_name))
3817 errx(1, "%s: Interface name too long", ifname);
3818
3819 memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
3820
3821 req.dstaddr.ss_len = 2;
3822 req.dstaddr.ss_family = AF_UNSPEC;
3823
3824 if (ioctl(sock, SIOCSLIFPHYADDR, &req) == -1)
3825 warn("tunneladdr %s", src);
3826
3827 freeaddrinfo(srcres);
3828 }
3829
3830 void
deletetunnel(const char * ignored,int alsoignored)3831 deletetunnel(const char *ignored, int alsoignored)
3832 {
3833 if (ioctl(sock, SIOCDIFPHYADDR, &ifr) == -1)
3834 warn("SIOCDIFPHYADDR");
3835 }
3836
3837 void
settunnelinst(const char * id,int param)3838 settunnelinst(const char *id, int param)
3839 {
3840 const char *errmsg = NULL;
3841 int rdomainid;
3842
3843 rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
3844 if (errmsg)
3845 errx(1, "rdomain %s: %s", id, errmsg);
3846
3847 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3848 ifr.ifr_rdomainid = rdomainid;
3849 if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1)
3850 warn("SIOCSLIFPHYRTABLE");
3851 }
3852
3853 void
unsettunnelinst(const char * ignored,int alsoignored)3854 unsettunnelinst(const char *ignored, int alsoignored)
3855 {
3856 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3857 ifr.ifr_rdomainid = 0;
3858 if (ioctl(sock, SIOCSLIFPHYRTABLE, (caddr_t)&ifr) == -1)
3859 warn("SIOCSLIFPHYRTABLE");
3860 }
3861
3862 void
settunnelttl(const char * id,int param)3863 settunnelttl(const char *id, int param)
3864 {
3865 const char *errmsg = NULL;
3866 int ttl;
3867
3868 if (strcmp(id, "copy") == 0)
3869 ttl = -1;
3870 else {
3871 ttl = strtonum(id, 0, 0xff, &errmsg);
3872 if (errmsg)
3873 errx(1, "tunnelttl %s: %s", id, errmsg);
3874 }
3875
3876 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3877 ifr.ifr_ttl = ttl;
3878 if (ioctl(sock, SIOCSLIFPHYTTL, (caddr_t)&ifr) == -1)
3879 warn("SIOCSLIFPHYTTL");
3880 }
3881
3882 void
settunneldf(const char * ignored,int alsoignored)3883 settunneldf(const char *ignored, int alsoignored)
3884 {
3885 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3886 ifr.ifr_df = 1;
3887 if (ioctl(sock, SIOCSLIFPHYDF, (caddr_t)&ifr) == -1)
3888 warn("SIOCSLIFPHYDF");
3889 }
3890
3891 void
settunnelnodf(const char * ignored,int alsoignored)3892 settunnelnodf(const char *ignored, int alsoignored)
3893 {
3894 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3895 ifr.ifr_df = 0;
3896 if (ioctl(sock, SIOCSLIFPHYDF, (caddr_t)&ifr) == -1)
3897 warn("SIOCSLIFPHYDF");
3898 }
3899
3900 void
settunnelecn(const char * ignored,int alsoignored)3901 settunnelecn(const char *ignored, int alsoignored)
3902 {
3903 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3904 ifr.ifr_metric = 1;
3905 if (ioctl(sock, SIOCSLIFPHYECN, (caddr_t)&ifr) == -1)
3906 warn("SIOCSLIFPHYECN");
3907 }
3908
3909 void
settunnelnoecn(const char * ignored,int alsoignored)3910 settunnelnoecn(const char *ignored, int alsoignored)
3911 {
3912 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3913 ifr.ifr_metric = 0;
3914 if (ioctl(sock, SIOCSLIFPHYECN, (caddr_t)&ifr) == -1)
3915 warn("SIOCSLIFPHYECN");
3916 }
3917
3918 void
setvnetflowid(const char * ignored,int alsoignored)3919 setvnetflowid(const char *ignored, int alsoignored)
3920 {
3921 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
3922 sizeof(ifr.ifr_name))
3923 errx(1, "vnetflowid: name is too long");
3924
3925 ifr.ifr_vnetid = 1;
3926 if (ioctl(sock, SIOCSVNETFLOWID, &ifr) == -1)
3927 warn("SIOCSVNETFLOWID");
3928 }
3929
3930 void
delvnetflowid(const char * ignored,int alsoignored)3931 delvnetflowid(const char *ignored, int alsoignored)
3932 {
3933 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
3934 sizeof(ifr.ifr_name))
3935 errx(1, "vnetflowid: name is too long");
3936
3937 ifr.ifr_vnetid = 0;
3938 if (ioctl(sock, SIOCSVNETFLOWID, &ifr) == -1)
3939 warn("SIOCSVNETFLOWID");
3940 }
3941
3942 static void
pwe3_neighbor(void)3943 pwe3_neighbor(void)
3944 {
3945 const char *prefix = "pwe3 remote label";
3946 struct if_laddrreq req;
3947 char hbuf[NI_MAXHOST];
3948 struct sockaddr_mpls *smpls;
3949 int error;
3950
3951 memset(&req, 0, sizeof(req));
3952 if (strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name)) >=
3953 sizeof(req.iflr_name))
3954 errx(1, "pwe3 neighbor: name is too long");
3955
3956 if (ioctl(sock, SIOCGPWE3NEIGHBOR, &req) == -1) {
3957 if (errno != EADDRNOTAVAIL)
3958 return;
3959
3960 printf(" %s (unset)", prefix);
3961 return;
3962 }
3963
3964 if (req.dstaddr.ss_family != AF_MPLS) {
3965 warnc(EPFNOSUPPORT, "pwe3 neighbor");
3966 return;
3967 }
3968 smpls = (struct sockaddr_mpls *)&req.dstaddr;
3969
3970 error = getnameinfo((struct sockaddr *)&req.addr, sizeof(req.addr),
3971 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
3972 if (error != 0) {
3973 warnx("%s: %s", prefix, gai_strerror(error));
3974 return;
3975 }
3976
3977 printf(" %s %u on %s", prefix, smpls->smpls_label, hbuf);
3978 }
3979
3980 static void
pwe3_cword(void)3981 pwe3_cword(void)
3982 {
3983 struct ifreq req;
3984
3985 memset(&req, 0, sizeof(req));
3986 if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
3987 sizeof(req.ifr_name))
3988 errx(1, "pwe3 control word: name is too long");
3989
3990 if (ioctl(sock, SIOCGPWE3CTRLWORD, &req) == -1) {
3991 return;
3992 }
3993
3994 printf(" %s", req.ifr_pwe3 ? "cw" : "nocw");
3995 }
3996
3997 static void
pwe3_fword(void)3998 pwe3_fword(void)
3999 {
4000 struct ifreq req;
4001
4002 memset(&req, 0, sizeof(req));
4003 if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
4004 sizeof(req.ifr_name))
4005 errx(1, "pwe3 control word: name is too long");
4006
4007 if (ioctl(sock, SIOCGPWE3FAT, &req) == -1)
4008 return;
4009
4010 printf(" %s", req.ifr_pwe3 ? "fat" : "nofat");
4011 }
4012
4013 void
mpls_status(void)4014 mpls_status(void)
4015 {
4016 struct shim_hdr shim;
4017
4018 bzero(&shim, sizeof(shim));
4019 ifr.ifr_data = (caddr_t)&shim;
4020
4021 if (ioctl(sock, SIOCGETLABEL, (caddr_t)&ifr) == -1) {
4022 if (errno != EADDRNOTAVAIL)
4023 return;
4024
4025 printf("\tmpls: label (unset)");
4026 } else
4027 printf("\tmpls: label %u", shim.shim_label);
4028
4029 pwe3_neighbor();
4030 pwe3_cword();
4031 pwe3_fword();
4032
4033 printf("\n");
4034 }
4035
4036 void
setmplslabel(const char * val,int d)4037 setmplslabel(const char *val, int d)
4038 {
4039 struct shim_hdr shim;
4040 const char *estr;
4041
4042 bzero(&shim, sizeof(shim));
4043 ifr.ifr_data = (caddr_t)&shim;
4044 shim.shim_label = strtonum(val, 0, MPLS_LABEL_MAX, &estr);
4045
4046 if (estr)
4047 errx(1, "mpls label %s is %s", val, estr);
4048 if (ioctl(sock, SIOCSETLABEL, (caddr_t)&ifr) == -1)
4049 warn("SIOCSETLABEL");
4050 }
4051
4052 void
unsetmplslabel(const char * val,int d)4053 unsetmplslabel(const char *val, int d)
4054 {
4055 struct ifreq req;
4056
4057 memset(&req, 0, sizeof(req));
4058 if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
4059 sizeof(req.ifr_name))
4060 errx(1, "interface name is too long");
4061
4062 if (ioctl(sock, SIOCDELLABEL, (caddr_t)&ifr) == -1)
4063 warn("-mplslabel");
4064 }
4065
4066 static void
setpwe3(unsigned long cmd,const char * cmdname,int value)4067 setpwe3(unsigned long cmd, const char *cmdname, int value)
4068 {
4069 struct ifreq req;
4070
4071 memset(&req, 0, sizeof(req));
4072 if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
4073 sizeof(req.ifr_name))
4074 errx(1, "interface name is too long");
4075
4076 req.ifr_pwe3 = value;
4077
4078 if (ioctl(sock, cmd, &req) == -1)
4079 warn("%s", cmdname);
4080 }
4081
4082 void
setpwe3cw(const char * val,int d)4083 setpwe3cw(const char *val, int d)
4084 {
4085 setpwe3(SIOCSPWE3CTRLWORD, "pwecw", 1);
4086 }
4087
4088 void
unsetpwe3cw(const char * val,int d)4089 unsetpwe3cw(const char *val, int d)
4090 {
4091 setpwe3(SIOCSPWE3CTRLWORD, "-pwecw", 0);
4092 }
4093
4094 void
setpwe3fat(const char * val,int d)4095 setpwe3fat(const char *val, int d)
4096 {
4097 setpwe3(SIOCSPWE3FAT, "pwefat", 1);
4098 }
4099
4100 void
unsetpwe3fat(const char * val,int d)4101 unsetpwe3fat(const char *val, int d)
4102 {
4103 setpwe3(SIOCSPWE3FAT, "-pwefat", 0);
4104 }
4105
4106 void
setpwe3neighbor(const char * label,const char * neighbor)4107 setpwe3neighbor(const char *label, const char *neighbor)
4108 {
4109 struct if_laddrreq req;
4110 struct addrinfo hints, *res;
4111 struct sockaddr_mpls *smpls = (struct sockaddr_mpls *)&req.dstaddr;
4112 const char *errstr;
4113 int error;
4114
4115 memset(&req, 0, sizeof(req));
4116 if (strlcpy(req.iflr_name, ifname, sizeof(req.iflr_name)) >=
4117 sizeof(req.iflr_name))
4118 errx(1, "interface name is too long");
4119
4120 memset(&hints, 0, sizeof(hints));
4121 hints.ai_family = AF_UNSPEC;
4122 hints.ai_socktype = SOCK_DGRAM;
4123 error = getaddrinfo(neighbor, NULL, &hints, &res);
4124 if (error != 0)
4125 errx(1, "pweneighbor %s: %s", neighbor, gai_strerror(error));
4126
4127 smpls->smpls_len = sizeof(*smpls);
4128 smpls->smpls_family = AF_MPLS;
4129 smpls->smpls_label = strtonum(label,
4130 (MPLS_LABEL_RESERVED_MAX + 1), MPLS_LABEL_MAX, &errstr);
4131 if (errstr != NULL)
4132 errx(1, "pweneighbor: invalid label: %s", errstr);
4133
4134
4135 if (res->ai_addrlen > sizeof(req.addr))
4136 errx(1, "pweneighbors: unexpected socklen");
4137
4138 memcpy(&req.addr, res->ai_addr, res->ai_addrlen);
4139
4140 freeaddrinfo(res);
4141
4142 if (ioctl(sock, SIOCSPWE3NEIGHBOR, &req) == -1)
4143 warn("pweneighbor");
4144 }
4145
4146 void
unsetpwe3neighbor(const char * val,int d)4147 unsetpwe3neighbor(const char *val, int d)
4148 {
4149 struct ifreq req;
4150
4151 memset(&req, 0, sizeof(req));
4152 if (strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)) >=
4153 sizeof(req.ifr_name))
4154 errx(1, "interface name is too long");
4155
4156 if (ioctl(sock, SIOCDPWE3NEIGHBOR, &req) == -1)
4157 warn("-pweneighbor");
4158 }
4159
4160 void
transceiver(const char * value,int d)4161 transceiver(const char *value, int d)
4162 {
4163 showtransceiver = 1;
4164 }
4165
4166 void
transceiverdump(const char * value,int d)4167 transceiverdump(const char *value, int d)
4168 {
4169 if (if_sff_info(1) == -1)
4170 err(1, "%s transceiver", ifname);
4171 }
4172 #endif /* SMALL */
4173
4174 void
getvnetflowid(struct ifencap * ife)4175 getvnetflowid(struct ifencap *ife)
4176 {
4177 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4178 sizeof(ifr.ifr_name))
4179 errx(1, "vnetflowid: name is too long");
4180
4181 if (ioctl(sock, SIOCGVNETFLOWID, &ifr) == -1)
4182 return;
4183
4184 if (ifr.ifr_vnetid)
4185 ife->ife_flags |= IFE_VNETFLOWID;
4186 }
4187
4188 void
setvnetid(const char * id,int param)4189 setvnetid(const char *id, int param)
4190 {
4191 const char *errmsg = NULL;
4192 int64_t vnetid;
4193
4194 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
4195
4196 if (strcasecmp("any", id) == 0)
4197 vnetid = -1;
4198 else {
4199 vnetid = strtonum(id, 0, INT64_MAX, &errmsg);
4200 if (errmsg)
4201 errx(1, "vnetid %s: %s", id, errmsg);
4202 }
4203
4204 ifr.ifr_vnetid = vnetid;
4205 if (ioctl(sock, SIOCSVNETID, (caddr_t)&ifr) == -1)
4206 warn("SIOCSVNETID");
4207 }
4208
4209 void
delvnetid(const char * ignored,int alsoignored)4210 delvnetid(const char *ignored, int alsoignored)
4211 {
4212 if (ioctl(sock, SIOCDVNETID, &ifr) == -1)
4213 warn("SIOCDVNETID");
4214 }
4215
4216 void
getvnetid(struct ifencap * ife)4217 getvnetid(struct ifencap *ife)
4218 {
4219 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4220 sizeof(ifr.ifr_name))
4221 errx(1, "vnetid: name is too long");
4222
4223 if (ioctl(sock, SIOCGVNETID, &ifr) == -1) {
4224 if (errno != EADDRNOTAVAIL)
4225 return;
4226
4227 ife->ife_flags |= IFE_VNETID_NONE;
4228 return;
4229 }
4230
4231 if (ifr.ifr_vnetid < 0) {
4232 ife->ife_flags |= IFE_VNETID_ANY;
4233 return;
4234 }
4235
4236 ife->ife_flags |= IFE_VNETID_SET;
4237 ife->ife_vnetid = ifr.ifr_vnetid;
4238 }
4239
4240 void
setifparent(const char * id,int param)4241 setifparent(const char *id, int param)
4242 {
4243 struct if_parent ifp;
4244
4245 if (strlcpy(ifp.ifp_name, ifname, sizeof(ifp.ifp_name)) >=
4246 sizeof(ifp.ifp_name))
4247 errx(1, "parent: name too long");
4248
4249 if (strlcpy(ifp.ifp_parent, id, sizeof(ifp.ifp_parent)) >=
4250 sizeof(ifp.ifp_parent))
4251 errx(1, "parent: parent too long");
4252
4253 if (ioctl(sock, SIOCSIFPARENT, (caddr_t)&ifp) == -1)
4254 warn("%s: %s: SIOCSIFPARENT", ifp.ifp_name, ifp.ifp_parent);
4255 }
4256
4257 void
delifparent(const char * ignored,int alsoignored)4258 delifparent(const char *ignored, int alsoignored)
4259 {
4260 if (ioctl(sock, SIOCDIFPARENT, &ifr) == -1)
4261 warn("SIOCDIFPARENT");
4262 }
4263
4264 void
getifparent(struct ifencap * ife)4265 getifparent(struct ifencap *ife)
4266 {
4267 struct if_parent ifp;
4268
4269 memset(&ifp, 0, sizeof(ifp));
4270 if (strlcpy(ifp.ifp_name, ifname, sizeof(ifp.ifp_name)) >=
4271 sizeof(ifp.ifp_name))
4272 errx(1, "parent: name too long");
4273
4274 if (ioctl(sock, SIOCGIFPARENT, (caddr_t)&ifp) == -1) {
4275 if (errno != EADDRNOTAVAIL)
4276 return;
4277
4278 ife->ife_flags |= IFE_PARENT_NONE;
4279 } else {
4280 memcpy(ife->ife_parent, ifp.ifp_parent,
4281 sizeof(ife->ife_parent));
4282 ife->ife_flags |= IFE_PARENT_SET;
4283 }
4284 }
4285
4286 #ifndef SMALL
4287 void
gettxprio(struct ifencap * ife)4288 gettxprio(struct ifencap *ife)
4289 {
4290 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4291 sizeof(ifr.ifr_name))
4292 errx(1, "hdr prio: name is too long");
4293
4294 if (ioctl(sock, SIOCGTXHPRIO, (caddr_t)&ifr) == -1)
4295 return;
4296
4297 ife->ife_flags |= IFE_TXHPRIO_SET;
4298 ife->ife_txhprio = ifr.ifr_hdrprio;
4299 }
4300
4301 void
settxprio(const char * val,int d)4302 settxprio(const char *val, int d)
4303 {
4304 const char *errmsg = NULL;
4305
4306 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4307 sizeof(ifr.ifr_name))
4308 errx(1, "tx prio: name is too long");
4309
4310 if (strcmp(val, "packet") == 0)
4311 ifr.ifr_hdrprio = IF_HDRPRIO_PACKET;
4312 else if (strcmp(val, "payload") == 0)
4313 ifr.ifr_hdrprio = IF_HDRPRIO_PAYLOAD;
4314 else {
4315 ifr.ifr_hdrprio = strtonum(val,
4316 IF_HDRPRIO_MIN, IF_HDRPRIO_MAX, &errmsg);
4317 if (errmsg)
4318 errx(1, "tx prio %s: %s", val, errmsg);
4319 }
4320
4321 if (ioctl(sock, SIOCSTXHPRIO, (caddr_t)&ifr) == -1)
4322 warn("SIOCSTXHPRIO");
4323 }
4324
4325 void
getrxprio(struct ifencap * ife)4326 getrxprio(struct ifencap *ife)
4327 {
4328 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4329 sizeof(ifr.ifr_name))
4330 errx(1, "hdr prio: name is too long");
4331
4332 if (ioctl(sock, SIOCGRXHPRIO, (caddr_t)&ifr) == -1)
4333 return;
4334
4335 ife->ife_flags |= IFE_RXHPRIO_SET;
4336 ife->ife_rxhprio = ifr.ifr_hdrprio;
4337 }
4338
4339 void
setrxprio(const char * val,int d)4340 setrxprio(const char *val, int d)
4341 {
4342 const char *errmsg = NULL;
4343
4344 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
4345 sizeof(ifr.ifr_name))
4346 errx(1, "rx prio: name is too long");
4347
4348 if (strcmp(val, "packet") == 0)
4349 ifr.ifr_hdrprio = IF_HDRPRIO_PACKET;
4350 else if (strcmp(val, "payload") == 0)
4351 ifr.ifr_hdrprio = IF_HDRPRIO_PAYLOAD;
4352 else if (strcmp(val, "outer") == 0)
4353 ifr.ifr_hdrprio = IF_HDRPRIO_OUTER;
4354 else {
4355 ifr.ifr_hdrprio = strtonum(val,
4356 IF_HDRPRIO_MIN, IF_HDRPRIO_MAX, &errmsg);
4357 if (errmsg)
4358 errx(1, "rx prio %s: %s", val, errmsg);
4359 }
4360
4361 if (ioctl(sock, SIOCSRXHPRIO, (caddr_t)&ifr) == -1)
4362 warn("SIOCSRXHPRIO");
4363 }
4364 #endif
4365
4366 void
getencap(void)4367 getencap(void)
4368 {
4369 struct ifencap ife = { .ife_flags = 0 };
4370
4371 getvnetid(&ife);
4372 getvnetflowid(&ife);
4373 getifparent(&ife);
4374 #ifndef SMALL
4375 gettxprio(&ife);
4376 getrxprio(&ife);
4377 #endif
4378
4379 if (ife.ife_flags == 0)
4380 return;
4381
4382 printf("\tencap:");
4383
4384 switch (ife.ife_flags & IFE_VNETID_MASK) {
4385 case IFE_VNETID_NONE:
4386 printf(" vnetid none");
4387 break;
4388 case IFE_VNETID_ANY:
4389 printf(" vnetid any");
4390 break;
4391 case IFE_VNETID_SET:
4392 printf(" vnetid %lld", ife.ife_vnetid);
4393 if (ife.ife_flags & IFE_VNETFLOWID)
4394 printf("+");
4395 break;
4396 }
4397
4398 switch (ife.ife_flags & IFE_PARENT_MASK) {
4399 case IFE_PARENT_NONE:
4400 printf(" parent none");
4401 break;
4402 case IFE_PARENT_SET:
4403 printf(" parent %s", ife.ife_parent);
4404 break;
4405 }
4406
4407 #ifndef SMALL
4408 if (ife.ife_flags & IFE_TXHPRIO_SET) {
4409 printf(" txprio ");
4410 switch (ife.ife_txhprio) {
4411 case IF_HDRPRIO_PACKET:
4412 printf("packet");
4413 break;
4414 case IF_HDRPRIO_PAYLOAD:
4415 printf("payload");
4416 break;
4417 default:
4418 printf("%d", ife.ife_txhprio);
4419 break;
4420 }
4421 }
4422
4423 if (ife.ife_flags & IFE_RXHPRIO_SET) {
4424 printf(" rxprio ");
4425 switch (ife.ife_rxhprio) {
4426 case IF_HDRPRIO_PACKET:
4427 printf("packet");
4428 break;
4429 case IF_HDRPRIO_PAYLOAD:
4430 printf("payload");
4431 break;
4432 case IF_HDRPRIO_OUTER:
4433 printf("outer");
4434 break;
4435 default:
4436 printf("%d", ife.ife_rxhprio);
4437 break;
4438 }
4439 }
4440 #endif
4441
4442 printf("\n");
4443 }
4444
4445 void
settrunkport(const char * val,int d)4446 settrunkport(const char *val, int d)
4447 {
4448 struct trunk_reqport rp;
4449
4450 bzero(&rp, sizeof(rp));
4451 strlcpy(rp.rp_ifname, ifname, sizeof(rp.rp_ifname));
4452 strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
4453
4454 if (ioctl(sock, SIOCSTRUNKPORT, &rp) == -1)
4455 err(1, "%s %s: SIOCSTRUNKPORT", rp.rp_ifname, rp.rp_portname);
4456 }
4457
4458 void
unsettrunkport(const char * val,int d)4459 unsettrunkport(const char *val, int d)
4460 {
4461 struct trunk_reqport rp;
4462
4463 bzero(&rp, sizeof(rp));
4464 strlcpy(rp.rp_ifname, ifname, sizeof(rp.rp_ifname));
4465 strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
4466
4467 if (ioctl(sock, SIOCSTRUNKDELPORT, &rp) == -1)
4468 err(1, "%s: %s: SIOCSTRUNKDELPORT", rp.rp_ifname,
4469 rp.rp_portname);
4470 }
4471
4472 void
settrunkproto(const char * val,int d)4473 settrunkproto(const char *val, int d)
4474 {
4475 struct trunk_protos tpr[] = TRUNK_PROTOS;
4476 struct trunk_reqall ra;
4477 int i;
4478
4479 bzero(&ra, sizeof(ra));
4480 ra.ra_proto = TRUNK_PROTO_MAX;
4481
4482 for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
4483 if (strcmp(val, tpr[i].tpr_name) == 0) {
4484 ra.ra_proto = tpr[i].tpr_proto;
4485 break;
4486 }
4487 }
4488 if (ra.ra_proto == TRUNK_PROTO_MAX)
4489 errx(1, "Invalid trunk protocol: %s", val);
4490
4491 strlcpy(ra.ra_ifname, ifname, sizeof(ra.ra_ifname));
4492 if (ioctl(sock, SIOCSTRUNK, &ra) != 0)
4493 err(1, "%s: SIOCSTRUNK", ra.ra_ifname);
4494 }
4495
4496 void
settrunklacpmode(const char * val,int d)4497 settrunklacpmode(const char *val, int d)
4498 {
4499 struct trunk_reqall ra;
4500 struct trunk_opts tops;
4501
4502 bzero(&ra, sizeof(ra));
4503 strlcpy(ra.ra_ifname, ifname, sizeof(ra.ra_ifname));
4504
4505 if (ioctl(sock, SIOCGTRUNK, &ra) != 0)
4506 err(1, "%s: SIOCGTRUNK", ra.ra_ifname);
4507
4508 if (ra.ra_proto != TRUNK_PROTO_LACP)
4509 errx(1, "Invalid option for trunk: %s", ifname);
4510
4511 if (strcmp(val, lacpmodeactive) != 0 &&
4512 strcmp(val, lacpmodepassive) != 0)
4513 errx(1, "Invalid lacpmode option for trunk: %s", ifname);
4514
4515 bzero(&tops, sizeof(tops));
4516 strlcpy(tops.to_ifname, ifname, sizeof(tops.to_ifname));
4517 tops.to_proto = TRUNK_PROTO_LACP;
4518 tops.to_opts |= TRUNK_OPT_LACP_MODE;
4519
4520 if (strcmp(val, lacpmodeactive) == 0)
4521 tops.to_lacpopts.lacp_mode = 1;
4522 else
4523 tops.to_lacpopts.lacp_mode = 0;
4524
4525 if (ioctl(sock, SIOCSTRUNKOPTS, &tops) != 0)
4526 err(1, "%s: SIOCSTRUNKOPTS", tops.to_ifname);
4527 }
4528
4529 void
settrunklacptimeout(const char * val,int d)4530 settrunklacptimeout(const char *val, int d)
4531 {
4532 struct trunk_reqall ra;
4533 struct trunk_opts tops;
4534
4535 bzero(&ra, sizeof(ra));
4536 strlcpy(ra.ra_ifname, ifname, sizeof(ra.ra_ifname));
4537
4538 if (ioctl(sock, SIOCGTRUNK, &ra) != 0)
4539 err(1, "%s SIOCGTRUNK", ra.ra_ifname);
4540
4541 if (ra.ra_proto != TRUNK_PROTO_LACP)
4542 errx(1, "Invalid option for trunk: %s", ifname);
4543
4544 if (strcmp(val, lacptimeoutfast) != 0 &&
4545 strcmp(val, lacptimeoutslow) != 0)
4546 errx(1, "Invalid lacptimeout option for trunk: %s", ifname);
4547
4548 bzero(&tops, sizeof(tops));
4549 strlcpy(tops.to_ifname, ifname, sizeof(tops.to_ifname));
4550 tops.to_proto = TRUNK_PROTO_LACP;
4551 tops.to_opts |= TRUNK_OPT_LACP_TIMEOUT;
4552
4553 if (strcmp(val, lacptimeoutfast) == 0)
4554 tops.to_lacpopts.lacp_timeout = 1;
4555 else
4556 tops.to_lacpopts.lacp_timeout = 0;
4557
4558 if (ioctl(sock, SIOCSTRUNKOPTS, &tops) != 0)
4559 err(1, "%s: SIOCSTRUNKOPTS", tops.to_ifname);
4560 }
4561
4562 void
trunk_status(void)4563 trunk_status(void)
4564 {
4565 struct trunk_protos tpr[] = TRUNK_PROTOS;
4566 struct trunk_reqport rp, rpbuf[TRUNK_MAX_PORTS];
4567 struct trunk_reqall ra;
4568 struct lacp_opreq *lp;
4569 const char *proto = "<unknown>";
4570 int i, isport = 0;
4571
4572 bzero(&rp, sizeof(rp));
4573 bzero(&ra, sizeof(ra));
4574
4575 strlcpy(rp.rp_ifname, ifname, sizeof(rp.rp_ifname));
4576 strlcpy(rp.rp_portname, ifname, sizeof(rp.rp_portname));
4577
4578 if (ioctl(sock, SIOCGTRUNKPORT, &rp) == 0)
4579 isport = 1;
4580
4581 strlcpy(ra.ra_ifname, ifname, sizeof(ra.ra_ifname));
4582 ra.ra_size = sizeof(rpbuf);
4583 ra.ra_port = rpbuf;
4584
4585 if (ioctl(sock, SIOCGTRUNK, &ra) == 0) {
4586 lp = (struct lacp_opreq *)&ra.ra_lacpreq;
4587
4588 for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++) {
4589 if (ra.ra_proto == tpr[i].tpr_proto) {
4590 proto = tpr[i].tpr_name;
4591 break;
4592 }
4593 }
4594
4595 printf("\ttrunk: trunkproto %s", proto);
4596 if (isport)
4597 printf(" trunkdev %s", rp.rp_ifname);
4598 putchar('\n');
4599 if (ra.ra_proto == TRUNK_PROTO_LACP) {
4600 char *act_mac = strdup(
4601 ether_ntoa((struct ether_addr*)lp->actor_mac));
4602 if (act_mac == NULL)
4603 err(1, "strdup");
4604 printf("\ttrunk id: [(%04X,%s,%04X,%04X,%04X),\n"
4605 "\t\t (%04X,%s,%04X,%04X,%04X)]\n",
4606 lp->actor_prio, act_mac,
4607 lp->actor_key, lp->actor_portprio, lp->actor_portno,
4608 lp->partner_prio,
4609 ether_ntoa((struct ether_addr*)lp->partner_mac),
4610 lp->partner_key, lp->partner_portprio,
4611 lp->partner_portno);
4612 free(act_mac);
4613 }
4614
4615 for (i = 0; i < ra.ra_ports; i++) {
4616 lp = (struct lacp_opreq *)&(rpbuf[i].rp_lacpreq);
4617 if (ra.ra_proto == TRUNK_PROTO_LACP) {
4618 printf("\t\t%s lacp actor "
4619 "system pri 0x%x mac %s, key 0x%x, "
4620 "port pri 0x%x number 0x%x\n",
4621 rpbuf[i].rp_portname,
4622 lp->actor_prio,
4623 ether_ntoa((struct ether_addr*)
4624 lp->actor_mac),
4625 lp->actor_key,
4626 lp->actor_portprio, lp->actor_portno);
4627 printf("\t\t%s lacp actor state ",
4628 rpbuf[i].rp_portname);
4629 printb_status(lp->actor_state,
4630 LACP_STATE_BITS);
4631 putchar('\n');
4632
4633 printf("\t\t%s lacp partner "
4634 "system pri 0x%x mac %s, key 0x%x, "
4635 "port pri 0x%x number 0x%x\n",
4636 rpbuf[i].rp_portname,
4637 lp->partner_prio,
4638 ether_ntoa((struct ether_addr*)
4639 lp->partner_mac),
4640 lp->partner_key,
4641 lp->partner_portprio, lp->partner_portno);
4642 printf("\t\t%s lacp partner state ",
4643 rpbuf[i].rp_portname);
4644 printb_status(lp->partner_state,
4645 LACP_STATE_BITS);
4646 putchar('\n');
4647 }
4648
4649 printf("\t\t%s port ", rpbuf[i].rp_portname);
4650 printb_status(rpbuf[i].rp_flags, TRUNK_PORT_BITS);
4651 putchar('\n');
4652 }
4653
4654 if (showmediaflag) {
4655 printf("\tsupported trunk protocols:\n");
4656 for (i = 0; i < (sizeof(tpr) / sizeof(tpr[0])); i++)
4657 printf("\t\ttrunkproto %s\n", tpr[i].tpr_name);
4658 }
4659 } else if (isport)
4660 printf("\ttrunk: trunkdev %s\n", rp.rp_ifname);
4661 }
4662
4663 #ifndef SMALL
4664 static const char *carp_states[] = { CARP_STATES };
4665 static const char *carp_bal_modes[] = { CARP_BAL_MODES };
4666
4667 void
carp_status(void)4668 carp_status(void)
4669 {
4670 const char *state, *balmode;
4671 struct carpreq carpr;
4672 char peer[32];
4673 int i;
4674
4675 memset((char *)&carpr, 0, sizeof(struct carpreq));
4676 ifr.ifr_data = (caddr_t)&carpr;
4677
4678 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4679 return;
4680
4681 if (carpr.carpr_vhids[0] == 0)
4682 return;
4683
4684 if (carpr.carpr_balancing > CARP_BAL_MAXID)
4685 balmode = "<UNKNOWN>";
4686 else
4687 balmode = carp_bal_modes[carpr.carpr_balancing];
4688
4689 if (carpr.carpr_peer.s_addr != htonl(INADDR_CARP_GROUP))
4690 snprintf(peer, sizeof(peer),
4691 " carppeer %s", inet_ntoa(carpr.carpr_peer));
4692 else
4693 peer[0] = '\0';
4694
4695 for (i = 0; carpr.carpr_vhids[i]; i++) {
4696 if (carpr.carpr_states[i] > CARP_MAXSTATE)
4697 state = "<UNKNOWN>";
4698 else
4699 state = carp_states[carpr.carpr_states[i]];
4700 if (carpr.carpr_vhids[1] == 0) {
4701 printf("\tcarp: %s carpdev %s vhid %u advbase %d "
4702 "advskew %u%s\n", state,
4703 carpr.carpr_carpdev[0] != '\0' ?
4704 carpr.carpr_carpdev : "none", carpr.carpr_vhids[0],
4705 carpr.carpr_advbase, carpr.carpr_advskews[0],
4706 peer);
4707 } else {
4708 if (i == 0) {
4709 printf("\tcarp: carpdev %s advbase %d"
4710 " balancing %s%s\n",
4711 carpr.carpr_carpdev[0] != '\0' ?
4712 carpr.carpr_carpdev : "none",
4713 carpr.carpr_advbase, balmode, peer);
4714 }
4715 printf("\t\tstate %s vhid %u advskew %u\n", state,
4716 carpr.carpr_vhids[i], carpr.carpr_advskews[i]);
4717 }
4718 }
4719 }
4720
4721 void
setcarp_passwd(const char * val,int d)4722 setcarp_passwd(const char *val, int d)
4723 {
4724 struct carpreq carpr;
4725
4726 bzero(&carpr, sizeof(struct carpreq));
4727 ifr.ifr_data = (caddr_t)&carpr;
4728
4729 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4730 err(1, "%s: SIOCGVH", ifr.ifr_name);
4731
4732 bzero(carpr.carpr_key, CARP_KEY_LEN);
4733 strlcpy((char *)carpr.carpr_key, val, CARP_KEY_LEN);
4734
4735 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4736 err(1, "%s: SIOCSVH", ifr.ifr_name);
4737 }
4738
4739 void
setcarp_vhid(const char * val,int d)4740 setcarp_vhid(const char *val, int d)
4741 {
4742 const char *errmsg = NULL;
4743 struct carpreq carpr;
4744 int vhid;
4745
4746 vhid = strtonum(val, 1, 255, &errmsg);
4747 if (errmsg)
4748 errx(1, "vhid %s: %s", val, errmsg);
4749
4750 bzero(&carpr, sizeof(struct carpreq));
4751 ifr.ifr_data = (caddr_t)&carpr;
4752
4753 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4754 err(1, "%s: SIOCGVH", ifr.ifr_name);
4755
4756 carpr.carpr_vhids[0] = vhid;
4757 carpr.carpr_vhids[1] = 0;
4758
4759 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4760 err(1, "%s: SIOCSVH", ifr.ifr_name);
4761 }
4762
4763 void
setcarp_advskew(const char * val,int d)4764 setcarp_advskew(const char *val, int d)
4765 {
4766 const char *errmsg = NULL;
4767 struct carpreq carpr;
4768 int advskew;
4769
4770 advskew = strtonum(val, 0, 254, &errmsg);
4771 if (errmsg)
4772 errx(1, "advskew %s: %s", val, errmsg);
4773
4774 bzero(&carpr, sizeof(struct carpreq));
4775 ifr.ifr_data = (caddr_t)&carpr;
4776
4777 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4778 err(1, "%s: SIOCGVH", ifr.ifr_name);
4779
4780 carpr.carpr_advskews[0] = advskew;
4781
4782 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4783 err(1, "%s: SIOCSVH", ifr.ifr_name);
4784 }
4785
4786 void
setcarp_advbase(const char * val,int d)4787 setcarp_advbase(const char *val, int d)
4788 {
4789 const char *errmsg = NULL;
4790 struct carpreq carpr;
4791 int advbase;
4792
4793 advbase = strtonum(val, 0, 254, &errmsg);
4794 if (errmsg)
4795 errx(1, "advbase %s: %s", val, errmsg);
4796
4797 bzero(&carpr, sizeof(struct carpreq));
4798 ifr.ifr_data = (caddr_t)&carpr;
4799
4800 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4801 err(1, "%s: SIOCGVH", ifr.ifr_name);
4802
4803 carpr.carpr_advbase = advbase;
4804
4805 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4806 err(1, "%s: SIOCSVH", ifr.ifr_name);
4807 }
4808
4809 void
setcarppeer(const char * val,int d)4810 setcarppeer(const char *val, int d)
4811 {
4812 struct carpreq carpr;
4813 struct addrinfo hints, *peerres;
4814 int ecode;
4815
4816 bzero(&carpr, sizeof(struct carpreq));
4817 ifr.ifr_data = (caddr_t)&carpr;
4818
4819 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4820 err(1, "%s: SIOCGVH", ifr.ifr_name);
4821
4822 bzero(&hints, sizeof(hints));
4823 hints.ai_family = AF_INET;
4824 hints.ai_socktype = SOCK_DGRAM;
4825
4826 if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
4827 errx(1, "error in parsing address string: %s",
4828 gai_strerror(ecode));
4829
4830 if (peerres->ai_addr->sa_family != AF_INET)
4831 errx(1, "only IPv4 addresses supported for the carppeer");
4832
4833 carpr.carpr_peer.s_addr = ((struct sockaddr_in *)
4834 peerres->ai_addr)->sin_addr.s_addr;
4835
4836 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4837 err(1, "%s: SIOCSVH", ifr.ifr_name);
4838
4839 freeaddrinfo(peerres);
4840 }
4841
4842 void
unsetcarppeer(const char * val,int d)4843 unsetcarppeer(const char *val, int d)
4844 {
4845 struct carpreq carpr;
4846
4847 bzero(&carpr, sizeof(struct carpreq));
4848 ifr.ifr_data = (caddr_t)&carpr;
4849
4850 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4851 err(1, "%s: SIOCGVH", ifr.ifr_name);
4852
4853 bzero(&carpr.carpr_peer, sizeof(carpr.carpr_peer));
4854
4855 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4856 err(1, "%s: SIOCSVH", ifr.ifr_name);
4857 }
4858
4859 void
setcarp_state(const char * val,int d)4860 setcarp_state(const char *val, int d)
4861 {
4862 struct carpreq carpr;
4863 int i;
4864
4865 bzero(&carpr, sizeof(struct carpreq));
4866 ifr.ifr_data = (caddr_t)&carpr;
4867
4868 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4869 err(1, "%s: SIOCGVH", ifr.ifr_name);
4870
4871 for (i = 0; i <= CARP_MAXSTATE; i++) {
4872 if (!strcasecmp(val, carp_states[i])) {
4873 carpr.carpr_state = i;
4874 break;
4875 }
4876 }
4877
4878 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4879 err(1, "%s: SIOCSVH", ifr.ifr_name);
4880 }
4881
4882 void
setcarpdev(const char * val,int d)4883 setcarpdev(const char *val, int d)
4884 {
4885 struct carpreq carpr;
4886
4887 bzero(&carpr, sizeof(struct carpreq));
4888 ifr.ifr_data = (caddr_t)&carpr;
4889
4890 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4891 err(1, "%s: SIOCGVH", ifr.ifr_name);
4892
4893 strlcpy(carpr.carpr_carpdev, val, sizeof(carpr.carpr_carpdev));
4894
4895 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4896 err(1, "%s: SIOCSVH", ifr.ifr_name);
4897 }
4898
4899 void
setcarp_nodes(const char * val,int d)4900 setcarp_nodes(const char *val, int d)
4901 {
4902 char *optlist, *str;
4903 int i;
4904 struct carpreq carpr;
4905
4906 bzero(&carpr, sizeof(struct carpreq));
4907 ifr.ifr_data = (caddr_t)&carpr;
4908
4909 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4910 err(1, "%s: SIOCGVH", ifr.ifr_name);
4911
4912 bzero(carpr.carpr_vhids, sizeof(carpr.carpr_vhids));
4913 bzero(carpr.carpr_advskews, sizeof(carpr.carpr_advskews));
4914
4915 optlist = strdup(val);
4916 if (optlist == NULL)
4917 err(1, "strdup");
4918
4919 str = strtok(optlist, ",");
4920 for (i = 0; str != NULL; i++) {
4921 u_int vhid, advskew;
4922
4923 if (i >= CARP_MAXNODES)
4924 errx(1, "too many carp nodes");
4925 if (sscanf(str, "%u:%u", &vhid, &advskew) != 2) {
4926 errx(1, "non parsable arg: %s", str);
4927 }
4928 if (vhid > 255)
4929 errx(1, "vhid %u: value too large", vhid);
4930 if (advskew >= 255)
4931 errx(1, "advskew %u: value too large", advskew);
4932
4933 carpr.carpr_vhids[i] = vhid;
4934 carpr.carpr_advskews[i] = advskew;
4935 str = strtok(NULL, ",");
4936 }
4937 free(optlist);
4938
4939 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4940 err(1, "%s: SIOCSVH", ifr.ifr_name);
4941 }
4942
4943 void
setcarp_balancing(const char * val,int d)4944 setcarp_balancing(const char *val, int d)
4945 {
4946 int i;
4947 struct carpreq carpr;
4948
4949 bzero(&carpr, sizeof(struct carpreq));
4950 ifr.ifr_data = (caddr_t)&carpr;
4951
4952 if (ioctl(sock, SIOCGVH, (caddr_t)&ifr) == -1)
4953 err(1, "%s: SIOCGVH", ifr.ifr_name);
4954
4955 for (i = 0; i <= CARP_BAL_MAXID; i++)
4956 if (!strcasecmp(val, carp_bal_modes[i]))
4957 break;
4958
4959 if (i > CARP_BAL_MAXID)
4960 errx(1, "balancing %s: unknown mode", val);
4961
4962 carpr.carpr_balancing = i;
4963
4964 if (ioctl(sock, SIOCSVH, (caddr_t)&ifr) == -1)
4965 err(1, "%s: SIOCSVH", ifr.ifr_name);
4966 }
4967
4968 void
setpfsync_syncdev(const char * val,int d)4969 setpfsync_syncdev(const char *val, int d)
4970 {
4971 struct pfsyncreq preq;
4972
4973 bzero(&preq, sizeof(struct pfsyncreq));
4974 ifr.ifr_data = (caddr_t)&preq;
4975
4976 if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4977 err(1, "%s: SIOCGETPFSYNC", ifr.ifr_name);
4978
4979 strlcpy(preq.pfsyncr_syncdev, val, sizeof(preq.pfsyncr_syncdev));
4980
4981 if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4982 err(1, "%s: SIOCSETPFSYNC", ifr.ifr_name);
4983 }
4984
4985 void
unsetpfsync_syncdev(const char * val,int d)4986 unsetpfsync_syncdev(const char *val, int d)
4987 {
4988 struct pfsyncreq preq;
4989
4990 bzero(&preq, sizeof(struct pfsyncreq));
4991 ifr.ifr_data = (caddr_t)&preq;
4992
4993 if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
4994 err(1, "%s: SIOCGETPFSYNC", ifr.ifr_name);
4995
4996 bzero(&preq.pfsyncr_syncdev, sizeof(preq.pfsyncr_syncdev));
4997
4998 if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
4999 err(1, "%s: SIOCSETPFSYNC", ifr.ifr_name);
5000 }
5001
5002 void
setpfsync_syncpeer(const char * val,int d)5003 setpfsync_syncpeer(const char *val, int d)
5004 {
5005 struct pfsyncreq preq;
5006 struct addrinfo hints, *peerres;
5007 int ecode;
5008
5009 bzero(&preq, sizeof(struct pfsyncreq));
5010 ifr.ifr_data = (caddr_t)&preq;
5011
5012 if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5013 err(1, "%s: SIOCGETPFSYNC", ifr.ifr_name);
5014
5015 memset(&hints, 0, sizeof(hints));
5016 hints.ai_family = AF_INET;
5017 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
5018
5019 if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
5020 errx(1, "error in parsing address string: %s",
5021 gai_strerror(ecode));
5022
5023 if (peerres->ai_addr->sa_family != AF_INET)
5024 errx(1, "only IPv4 addresses supported for the syncpeer");
5025
5026 preq.pfsyncr_syncpeer.s_addr = ((struct sockaddr_in *)
5027 peerres->ai_addr)->sin_addr.s_addr;
5028
5029 if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
5030 err(1, "%s: SIOCSETPFSYNC", ifr.ifr_name);
5031
5032 freeaddrinfo(peerres);
5033 }
5034
5035 void
unsetpfsync_syncpeer(const char * val,int d)5036 unsetpfsync_syncpeer(const char *val, int d)
5037 {
5038 struct pfsyncreq preq;
5039
5040 bzero(&preq, sizeof(struct pfsyncreq));
5041 ifr.ifr_data = (caddr_t)&preq;
5042
5043 if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5044 err(1, "%s: SIOCGETPFSYNC", ifr.ifr_name);
5045
5046 preq.pfsyncr_syncpeer.s_addr = 0;
5047
5048 if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
5049 err(1, "%s: SIOCSETPFSYNC", ifr.ifr_name);
5050 }
5051
5052 void
setpfsync_maxupd(const char * val,int d)5053 setpfsync_maxupd(const char *val, int d)
5054 {
5055 const char *errmsg = NULL;
5056 struct pfsyncreq preq;
5057 int maxupdates;
5058
5059 maxupdates = strtonum(val, 0, 255, &errmsg);
5060 if (errmsg)
5061 errx(1, "maxupd %s: %s", val, errmsg);
5062
5063 bzero(&preq, sizeof(struct pfsyncreq));
5064 ifr.ifr_data = (caddr_t)&preq;
5065
5066 if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5067 err(1, "%s: SIOCGETPFSYNC", ifr.ifr_name);
5068
5069 preq.pfsyncr_maxupdates = maxupdates;
5070
5071 if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
5072 err(1, "%s: SIOCSETPFSYNC", ifr.ifr_name);
5073 }
5074
5075 void
setpfsync_defer(const char * val,int d)5076 setpfsync_defer(const char *val, int d)
5077 {
5078 struct pfsyncreq preq;
5079
5080 bzero(&preq, sizeof(struct pfsyncreq));
5081 ifr.ifr_data = (caddr_t)&preq;
5082
5083 if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5084 err(1, "%s: SIOCGETPFSYNC", ifr.ifr_name);
5085
5086 preq.pfsyncr_defer = d;
5087 if (ioctl(sock, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
5088 err(1, "%s: SIOCSETPFSYNC", ifr.ifr_name);
5089 }
5090
5091 void
pfsync_status(void)5092 pfsync_status(void)
5093 {
5094 struct pfsyncreq preq;
5095
5096 bzero(&preq, sizeof(struct pfsyncreq));
5097 ifr.ifr_data = (caddr_t)&preq;
5098
5099 if (ioctl(sock, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
5100 return;
5101
5102 if (preq.pfsyncr_syncdev[0] != '\0') {
5103 printf("\tpfsync: syncdev: %s ", preq.pfsyncr_syncdev);
5104 if (preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP))
5105 printf("syncpeer: %s ",
5106 inet_ntoa(preq.pfsyncr_syncpeer));
5107 printf("maxupd: %d ", preq.pfsyncr_maxupdates);
5108 printf("defer: %s\n", preq.pfsyncr_defer ? "on" : "off");
5109 }
5110 }
5111
5112 void
pflow_status(void)5113 pflow_status(void)
5114 {
5115 struct pflowreq preq;
5116 struct sockaddr_in *sin;
5117 struct sockaddr_in6 *sin6;
5118 int error;
5119 char buf[INET6_ADDRSTRLEN];
5120
5121 bzero(&preq, sizeof(struct pflowreq));
5122 ifr.ifr_data = (caddr_t)&preq;
5123
5124 if (ioctl(sock, SIOCGETPFLOW, (caddr_t)&ifr) == -1)
5125 return;
5126
5127 if (preq.flowsrc.ss_family == AF_INET || preq.flowsrc.ss_family ==
5128 AF_INET6) {
5129 error = getnameinfo((struct sockaddr*)&preq.flowsrc,
5130 preq.flowsrc.ss_len, buf, sizeof(buf), NULL, 0,
5131 NI_NUMERICHOST);
5132 if (error)
5133 err(1, "sender: %s", gai_strerror(error));
5134 }
5135
5136 printf("\tpflow: ");
5137 switch (preq.flowsrc.ss_family) {
5138 case AF_INET:
5139 sin = (struct sockaddr_in*) &preq.flowsrc;
5140 if (sin->sin_addr.s_addr != INADDR_ANY) {
5141 printf("sender: %s", buf);
5142 if (sin->sin_port != 0)
5143 printf(":%u", ntohs(sin->sin_port));
5144 printf(" ");
5145 }
5146 break;
5147 case AF_INET6:
5148 sin6 = (struct sockaddr_in6*) &preq.flowsrc;
5149 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
5150 printf("sender: [%s]", buf);
5151 if (sin6->sin6_port != 0)
5152 printf(":%u", ntohs(sin6->sin6_port));
5153 printf(" ");
5154 }
5155 default:
5156 break;
5157 }
5158 if (preq.flowdst.ss_family == AF_INET || preq.flowdst.ss_family ==
5159 AF_INET6) {
5160 error = getnameinfo((struct sockaddr*)&preq.flowdst,
5161 preq.flowdst.ss_len, buf, sizeof(buf), NULL, 0,
5162 NI_NUMERICHOST);
5163 if (error)
5164 err(1, "receiver: %s", gai_strerror(error));
5165 }
5166 switch (preq.flowdst.ss_family) {
5167 case AF_INET:
5168 sin = (struct sockaddr_in*)&preq.flowdst;
5169 printf("receiver: %s:", sin->sin_addr.s_addr != INADDR_ANY ?
5170 buf : "INVALID");
5171 if (sin->sin_port == 0)
5172 printf("%s ", "INVALID");
5173 else
5174 printf("%u ", ntohs(sin->sin_port));
5175 break;
5176 case AF_INET6:
5177 sin6 = (struct sockaddr_in6*) &preq.flowdst;
5178 printf("receiver: [%s]:",
5179 !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ? buf :
5180 "INVALID");
5181 if (sin6->sin6_port == 0)
5182 printf("%s ", "INVALID");
5183 else
5184 printf("%u ", ntohs(sin6->sin6_port));
5185 break;
5186 default:
5187 printf("receiver: INVALID:INVALID ");
5188 break;
5189 }
5190 printf("version: %d\n", preq.version);
5191 }
5192
5193 void
pflow_addr(const char * val,struct sockaddr_storage * ss)5194 pflow_addr(const char *val, struct sockaddr_storage *ss) {
5195 struct addrinfo hints, *res0;
5196 int error, flag;
5197 char *cp, *ip, *port, buf[HOST_NAME_MAX+1 + sizeof (":65535")];
5198
5199 if (strlcpy(buf, val, sizeof(buf)) >= sizeof(buf))
5200 errx(1, "%s bad value", val);
5201
5202 port = NULL;
5203 cp = buf;
5204 if (*cp == '[')
5205 flag = 1;
5206 else
5207 flag = 0;
5208
5209 for(; *cp; ++cp) {
5210 if (*cp == ']' && *(cp + 1) == ':' && flag) {
5211 *cp = '\0';
5212 *(cp + 1) = '\0';
5213 port = cp + 2;
5214 break;
5215 }
5216 if (*cp == ']' && *(cp + 1) == '\0' && flag) {
5217 *cp = '\0';
5218 port = NULL;
5219 break;
5220 }
5221 if (*cp == ':' && !flag) {
5222 *cp = '\0';
5223 port = cp + 1;
5224 break;
5225 }
5226 }
5227
5228 ip = buf;
5229 if (flag)
5230 ip++;
5231
5232 bzero(&hints, sizeof(hints));
5233 hints.ai_family = AF_UNSPEC;
5234 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
5235 hints.ai_flags = AI_NUMERICHOST;
5236
5237 if ((error = getaddrinfo(ip, port, &hints, &res0)) != 0)
5238 errx(1, "error in parsing address string: %s",
5239 gai_strerror(error));
5240
5241 memcpy(ss, res0->ai_addr, res0->ai_addr->sa_len);
5242 freeaddrinfo(res0);
5243 }
5244
5245 void
setpflow_sender(const char * val,int d)5246 setpflow_sender(const char *val, int d)
5247 {
5248 struct pflowreq preq;
5249
5250 bzero(&preq, sizeof(struct pflowreq));
5251 ifr.ifr_data = (caddr_t)&preq;
5252 preq.addrmask |= PFLOW_MASK_SRCIP;
5253 pflow_addr(val, &preq.flowsrc);
5254
5255 if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5256 err(1, "%s: SIOCSETPFLOW", ifr.ifr_name);
5257 }
5258
5259 void
unsetpflow_sender(const char * val,int d)5260 unsetpflow_sender(const char *val, int d)
5261 {
5262 struct pflowreq preq;
5263
5264 bzero(&preq, sizeof(struct pflowreq));
5265 preq.addrmask |= PFLOW_MASK_SRCIP;
5266 ifr.ifr_data = (caddr_t)&preq;
5267 if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5268 err(1, "%s: SIOCSETPFLOW", ifr.ifr_name);
5269 }
5270
5271 void
setpflow_receiver(const char * val,int d)5272 setpflow_receiver(const char *val, int d)
5273 {
5274 struct pflowreq preq;
5275
5276 bzero(&preq, sizeof(struct pflowreq));
5277 ifr.ifr_data = (caddr_t)&preq;
5278 preq.addrmask |= PFLOW_MASK_DSTIP;
5279 pflow_addr(val, &preq.flowdst);
5280
5281 if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5282 err(1, "%s: SIOCSETPFLOW", ifr.ifr_name);
5283 }
5284
5285 void
unsetpflow_receiver(const char * val,int d)5286 unsetpflow_receiver(const char *val, int d)
5287 {
5288 struct pflowreq preq;
5289
5290 bzero(&preq, sizeof(struct pflowreq));
5291 ifr.ifr_data = (caddr_t)&preq;
5292 preq.addrmask |= PFLOW_MASK_DSTIP;
5293 if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5294 err(1, "%s: SIOCSETPFLOW", ifr.ifr_name);
5295 }
5296
5297 /* PFLOWPROTO XXX */
5298 void
setpflowproto(const char * val,int d)5299 setpflowproto(const char *val, int d)
5300 {
5301 struct pflow_protos ppr[] = PFLOW_PROTOS;
5302 struct pflowreq preq;
5303 int i;
5304
5305 bzero(&preq, sizeof(preq));
5306 preq.version = PFLOW_PROTO_MAX;
5307
5308 for (i = 0; i < (sizeof(ppr) / sizeof(ppr[0])); i++) {
5309 if (strcmp(val, ppr[i].ppr_name) == 0) {
5310 preq.version = ppr[i].ppr_proto;
5311 break;
5312 }
5313 }
5314 if (preq.version == PFLOW_PROTO_MAX)
5315 errx(1, "Invalid pflow protocol: %s", val);
5316
5317 preq.addrmask |= PFLOW_MASK_VERSION;
5318
5319 ifr.ifr_data = (caddr_t)&preq;
5320
5321 if (ioctl(sock, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
5322 err(1, "%s: SIOCSETPFLOW", ifr.ifr_name);
5323 }
5324
5325 void
pppoe_status(void)5326 pppoe_status(void)
5327 {
5328 struct pppoediscparms parms;
5329 struct pppoeconnectionstate state;
5330
5331 memset(&state, 0, sizeof(state));
5332
5333 strlcpy(parms.ifname, ifname, sizeof(parms.ifname));
5334 if (ioctl(sock, PPPOEGETPARMS, &parms) == -1)
5335 return;
5336
5337 printf("\tdev: %s ", parms.eth_ifname);
5338
5339 if (*parms.ac_name)
5340 printf("ac: %s ", parms.ac_name);
5341 if (*parms.service_name)
5342 printf("svc: %s ", parms.service_name);
5343
5344 strlcpy(state.ifname, ifname, sizeof(state.ifname));
5345 if (ioctl(sock, PPPOEGETSESSION, &state) == -1)
5346 err(1, "PPPOEGETSESSION");
5347
5348 printf("state: ");
5349 switch (state.state) {
5350 case PPPOE_STATE_INITIAL:
5351 printf("initial"); break;
5352 case PPPOE_STATE_PADI_SENT:
5353 printf("PADI sent"); break;
5354 case PPPOE_STATE_PADR_SENT:
5355 printf("PADR sent"); break;
5356 case PPPOE_STATE_SESSION:
5357 printf("session"); break;
5358 case PPPOE_STATE_CLOSING:
5359 printf("closing"); break;
5360 }
5361 printf("\n\tsid: 0x%x", state.session_id);
5362 printf(" PADI retries: %d", state.padi_retry_no);
5363 printf(" PADR retries: %d", state.padr_retry_no);
5364
5365 if (state.state == PPPOE_STATE_SESSION) {
5366 struct timespec temp_time;
5367 time_t diff_time, day = 0;
5368 unsigned int hour = 0, min = 0, sec = 0;
5369
5370 if (state.session_time.tv_sec != 0) {
5371 if (clock_gettime(CLOCK_BOOTTIME, &temp_time) == -1)
5372 goto notime;
5373 diff_time = temp_time.tv_sec -
5374 state.session_time.tv_sec;
5375
5376 day = diff_time / (60 * 60 * 24);
5377 diff_time %= (60 * 60 * 24);
5378
5379 hour = diff_time / (60 * 60);
5380 diff_time %= (60 * 60);
5381
5382 min = diff_time / 60;
5383 diff_time %= 60;
5384
5385 sec = diff_time;
5386 }
5387 printf(" time: ");
5388 if (day != 0)
5389 printf("%lldd ", (long long)day);
5390 printf("%02u:%02u:%02u", hour, min, sec);
5391 }
5392 notime:
5393 putchar('\n');
5394 }
5395
5396 void
setpppoe_dev(const char * val,int d)5397 setpppoe_dev(const char *val, int d)
5398 {
5399 struct pppoediscparms parms;
5400
5401 strlcpy(parms.ifname, ifname, sizeof(parms.ifname));
5402 if (ioctl(sock, PPPOEGETPARMS, &parms) == -1)
5403 return;
5404
5405 strlcpy(parms.eth_ifname, val, sizeof(parms.eth_ifname));
5406
5407 if (ioctl(sock, PPPOESETPARMS, &parms) == -1)
5408 err(1, "PPPOESETPARMS");
5409 }
5410
5411 void
setpppoe_svc(const char * val,int d)5412 setpppoe_svc(const char *val, int d)
5413 {
5414 struct pppoediscparms parms;
5415
5416 strlcpy(parms.ifname, ifname, sizeof(parms.ifname));
5417 if (ioctl(sock, PPPOEGETPARMS, &parms) == -1)
5418 return;
5419
5420 if (d == 0)
5421 strlcpy(parms.service_name, val, sizeof(parms.service_name));
5422 else
5423 memset(parms.service_name, 0, sizeof(parms.service_name));
5424
5425 if (ioctl(sock, PPPOESETPARMS, &parms) == -1)
5426 err(1, "PPPOESETPARMS");
5427 }
5428
5429 void
setpppoe_ac(const char * val,int d)5430 setpppoe_ac(const char *val, int d)
5431 {
5432 struct pppoediscparms parms;
5433
5434 strlcpy(parms.ifname, ifname, sizeof(parms.ifname));
5435 if (ioctl(sock, PPPOEGETPARMS, &parms) == -1)
5436 return;
5437
5438 if (d == 0)
5439 strlcpy(parms.ac_name, val, sizeof(parms.ac_name));
5440 else
5441 memset(parms.ac_name, 0, sizeof(parms.ac_name));
5442
5443 if (ioctl(sock, PPPOESETPARMS, &parms) == -1)
5444 err(1, "PPPOESETPARMS");
5445 }
5446
5447 void
spppauthinfo(struct sauthreq * spa,int d)5448 spppauthinfo(struct sauthreq *spa, int d)
5449 {
5450 bzero(spa, sizeof(struct sauthreq));
5451
5452 ifr.ifr_data = (caddr_t)spa;
5453 spa->cmd = d == 0 ? SPPPIOGMAUTH : SPPPIOGHAUTH;
5454 if (ioctl(sock, SIOCGSPPPPARAMS, &ifr) == -1)
5455 err(1, "%s: SIOCGSPPPPARAMS(SPPPIOGXAUTH)", ifr.ifr_name);
5456 }
5457
5458 void
spppdnsinfo(struct sdnsreq * spd)5459 spppdnsinfo(struct sdnsreq *spd)
5460 {
5461 memset(spd, 0, sizeof(*spd));
5462
5463 ifr.ifr_data = (caddr_t)spd;
5464 spd->cmd = SPPPIOGDNS;
5465 if (ioctl(sock, SIOCGSPPPPARAMS, &ifr) == -1)
5466 err(1, "%s: SIOCGSPPPPARAMS(SPPPIOGDNS)", ifr.ifr_name);
5467 }
5468
5469 void
setspppproto(const char * val,int d)5470 setspppproto(const char *val, int d)
5471 {
5472 struct sauthreq spa;
5473
5474 spppauthinfo(&spa, d);
5475
5476 if (strcmp(val, "pap") == 0)
5477 spa.proto = PPP_PAP;
5478 else if (strcmp(val, "chap") == 0)
5479 spa.proto = PPP_CHAP;
5480 else if (strcmp(val, "none") == 0)
5481 spa.proto = 0;
5482 else
5483 errx(1, "setpppproto");
5484
5485 spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
5486 if (ioctl(sock, SIOCSSPPPPARAMS, &ifr) == -1)
5487 err(1, "%s: SIOCSSPPPPARAMS(SPPPIOSXAUTH)", ifr.ifr_name);
5488 }
5489
5490 void
setsppppeerproto(const char * val,int d)5491 setsppppeerproto(const char *val, int d)
5492 {
5493 setspppproto(val, 1);
5494 }
5495
5496 void
setspppname(const char * val,int d)5497 setspppname(const char *val, int d)
5498 {
5499 struct sauthreq spa;
5500
5501 spppauthinfo(&spa, d);
5502
5503 if (spa.proto == 0)
5504 errx(1, "unspecified protocol");
5505 if (strlcpy(spa.name, val, sizeof(spa.name)) >= sizeof(spa.name))
5506 errx(1, "setspppname");
5507
5508 spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
5509 if (ioctl(sock, SIOCSSPPPPARAMS, &ifr) == -1)
5510 err(1, "%s: SIOCSSPPPPARAMS(SPPPIOSXAUTH)", ifr.ifr_name);
5511 }
5512
5513 void
setsppppeername(const char * val,int d)5514 setsppppeername(const char *val, int d)
5515 {
5516 setspppname(val, 1);
5517 }
5518
5519 void
setspppkey(const char * val,int d)5520 setspppkey(const char *val, int d)
5521 {
5522 struct sauthreq spa;
5523
5524 spppauthinfo(&spa, d);
5525
5526 if (spa.proto == 0)
5527 errx(1, "unspecified protocol");
5528 if (strlcpy(spa.secret, val, sizeof(spa.secret)) >= sizeof(spa.secret))
5529 errx(1, "setspppkey");
5530
5531 spa.cmd = d == 0 ? SPPPIOSMAUTH : SPPPIOSHAUTH;
5532 if (ioctl(sock, SIOCSSPPPPARAMS, &ifr) == -1)
5533 err(1, "%s: SIOCSSPPPPARAMS(SPPPIOSXAUTH)", ifr.ifr_name);
5534 }
5535
5536 void
setsppppeerkey(const char * val,int d)5537 setsppppeerkey(const char *val, int d)
5538 {
5539 setspppkey(val, 1);
5540 }
5541
5542 void
setsppppeerflag(const char * val,int d)5543 setsppppeerflag(const char *val, int d)
5544 {
5545 struct sauthreq spa;
5546 int flag;
5547
5548 spppauthinfo(&spa, 1);
5549
5550 if (spa.proto == 0)
5551 errx(1, "unspecified protocol");
5552 if (strcmp(val, "callin") == 0)
5553 flag = AUTHFLAG_NOCALLOUT;
5554 else if (strcmp(val, "norechallenge") == 0)
5555 flag = AUTHFLAG_NORECHALLENGE;
5556 else
5557 errx(1, "setppppeerflags");
5558
5559 if (d)
5560 spa.flags &= ~flag;
5561 else
5562 spa.flags |= flag;
5563
5564 spa.cmd = SPPPIOSHAUTH;
5565 if (ioctl(sock, SIOCSSPPPPARAMS, &ifr) == -1)
5566 err(1, "%s: SIOCSSPPPPARAMS(SPPPIOSXAUTH)", ifr.ifr_name);
5567 }
5568
5569 void
unsetsppppeerflag(const char * val,int d)5570 unsetsppppeerflag(const char *val, int d)
5571 {
5572 setsppppeerflag(val, 1);
5573 }
5574
5575 void
sppp_printproto(const char * name,struct sauthreq * auth)5576 sppp_printproto(const char *name, struct sauthreq *auth)
5577 {
5578 if (auth->proto == 0)
5579 return;
5580 printf("%sproto ", name);
5581 switch (auth->proto) {
5582 case PPP_PAP:
5583 printf("pap ");
5584 break;
5585 case PPP_CHAP:
5586 printf("chap ");
5587 break;
5588 default:
5589 printf("0x%04x ", auth->proto);
5590 break;
5591 }
5592 if (auth->name[0])
5593 printf("%sname \"%s\" ", name, auth->name);
5594 if (auth->secret[0])
5595 printf("%skey \"%s\" ", name, auth->secret);
5596 }
5597
5598 void
sppp_status(void)5599 sppp_status(void)
5600 {
5601 struct spppreq spr;
5602 struct sauthreq spa;
5603 struct sdnsreq spd;
5604 char astr[INET_ADDRSTRLEN];
5605 int i, n;
5606
5607 bzero(&spr, sizeof(spr));
5608
5609 ifr.ifr_data = (caddr_t)&spr;
5610 spr.cmd = SPPPIOGDEFS;
5611 if (ioctl(sock, SIOCGSPPPPARAMS, &ifr) == -1) {
5612 return;
5613 }
5614
5615 if (spr.phase == PHASE_DEAD)
5616 return;
5617 printf("\tsppp: phase ");
5618 switch (spr.phase) {
5619 case PHASE_ESTABLISH:
5620 printf("establish ");
5621 break;
5622 case PHASE_TERMINATE:
5623 printf("terminate ");
5624 break;
5625 case PHASE_AUTHENTICATE:
5626 printf("authenticate ");
5627 break;
5628 case PHASE_NETWORK:
5629 printf("network ");
5630 break;
5631 default:
5632 printf("illegal ");
5633 break;
5634 }
5635
5636 spppauthinfo(&spa, 0);
5637 sppp_printproto("auth", &spa);
5638 spppauthinfo(&spa, 1);
5639 sppp_printproto("peer", &spa);
5640 if (spa.flags & AUTHFLAG_NOCALLOUT)
5641 printf("callin ");
5642 if (spa.flags & AUTHFLAG_NORECHALLENGE)
5643 printf("norechallenge ");
5644 putchar('\n');
5645
5646 spppdnsinfo(&spd);
5647 for (i = 0, n = 0; i < IPCP_MAX_DNSSRV; i++) {
5648 if (spd.dns[i].s_addr == INADDR_ANY)
5649 break;
5650 printf("%s %s", n++ ? "" : "\tdns:",
5651 inet_ntop(AF_INET, &spd.dns[i], astr, sizeof(astr)));
5652 }
5653 if (n)
5654 printf("\n");
5655 }
5656
5657 void
setkeepalive(const char * timeout,const char * count)5658 setkeepalive(const char *timeout, const char *count)
5659 {
5660 const char *errmsg = NULL;
5661 struct ifkalivereq ikar;
5662 int t, c;
5663
5664 t = strtonum(timeout, 1, 3600, &errmsg);
5665 if (errmsg)
5666 errx(1, "keepalive period %s: %s", timeout, errmsg);
5667 c = strtonum(count, 2, 600, &errmsg);
5668 if (errmsg)
5669 errx(1, "keepalive count %s: %s", count, errmsg);
5670
5671 strlcpy(ikar.ikar_name, ifname, sizeof(ikar.ikar_name));
5672 ikar.ikar_timeo = t;
5673 ikar.ikar_cnt = c;
5674 if (ioctl(sock, SIOCSETKALIVE, (caddr_t)&ikar) == -1)
5675 warn("SIOCSETKALIVE");
5676 }
5677
5678 void
unsetkeepalive(const char * val,int d)5679 unsetkeepalive(const char *val, int d)
5680 {
5681 struct ifkalivereq ikar;
5682
5683 bzero(&ikar, sizeof(ikar));
5684 strlcpy(ikar.ikar_name, ifname, sizeof(ikar.ikar_name));
5685 if (ioctl(sock, SIOCSETKALIVE, (caddr_t)&ikar) == -1)
5686 warn("SIOCSETKALIVE");
5687 }
5688
5689 void
setifpriority(const char * id,int param)5690 setifpriority(const char *id, int param)
5691 {
5692 const char *errmsg = NULL;
5693 int prio;
5694
5695 prio = strtonum(id, 0, 15, &errmsg);
5696 if (errmsg)
5697 errx(1, "priority %s: %s", id, errmsg);
5698
5699 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
5700 ifr.ifr_metric = prio;
5701 if (ioctl(sock, SIOCSIFPRIORITY, (caddr_t)&ifr) == -1)
5702 warn("SIOCSIFPRIORITY");
5703 }
5704
5705 /*
5706 * WireGuard configuration
5707 *
5708 * WG_BASE64_KEY_LEN specifies the size of a base64 encoded WireGuard key.
5709 * WG_TMP_KEY_LEN specifies the size of a decoded base64 key. For every 4
5710 * input (base64) bytes, 3 output bytes wil be produced. The output will be
5711 * padded with 0 bits, therefore we need more than the regular 32 bytes of
5712 * space.
5713 */
5714 #define WG_BASE64_KEY_LEN (4 * ((WG_KEY_LEN + 2) / 3))
5715 #define WG_LOAD_KEY(dst, src, fn_name) do { \
5716 uint8_t _tmp[WG_KEY_LEN]; int _r; \
5717 if (strlen(src) != WG_BASE64_KEY_LEN) \
5718 errx(1, fn_name " (key): invalid length"); \
5719 if ((_r = b64_pton(src, _tmp, sizeof(_tmp))) != sizeof(_tmp)) \
5720 errx(1, fn_name " (key): invalid base64 %d/%zu", _r, sizeof(_tmp)); \
5721 memcpy(dst, _tmp, WG_KEY_LEN); \
5722 } while (0)
5723
5724 struct wg_data_io wgdata = { 0 };
5725 struct wg_interface_io *wg_interface = NULL;
5726 struct wg_peer_io *wg_peer = NULL;
5727 struct wg_aip_io *wg_aip = NULL;
5728
5729 void
ensurewginterface(void)5730 ensurewginterface(void)
5731 {
5732 if (wg_interface != NULL)
5733 return;
5734 wgdata.wgd_size = sizeof(*wg_interface);
5735 wgdata.wgd_interface = wg_interface = calloc(1, wgdata.wgd_size);
5736 if (wg_interface == NULL)
5737 err(1, "calloc");
5738 }
5739
5740 void
growwgdata(size_t by)5741 growwgdata(size_t by)
5742 {
5743 ptrdiff_t peer_offset, aip_offset;
5744
5745 if (wg_interface == NULL)
5746 wgdata.wgd_size = sizeof(*wg_interface);
5747
5748 peer_offset = (void *)wg_peer - (void *)wg_interface;
5749 aip_offset = (void *)wg_aip - (void *)wg_interface;
5750
5751 wgdata.wgd_size += by;
5752 wgdata.wgd_interface = realloc(wg_interface, wgdata.wgd_size);
5753 if (wgdata.wgd_interface == NULL)
5754 err(1, "calloc");
5755 if (wg_interface == NULL)
5756 bzero(wgdata.wgd_interface, sizeof(*wg_interface));
5757 wg_interface = wgdata.wgd_interface;
5758
5759 if (wg_peer != NULL)
5760 wg_peer = (void *)wg_interface + peer_offset;
5761 if (wg_aip != NULL)
5762 wg_aip = (void *)wg_interface + aip_offset;
5763
5764 bzero((char *)wg_interface + wgdata.wgd_size - by, by);
5765 }
5766
5767 void
setwgpeer(const char * peerkey_b64,int param)5768 setwgpeer(const char *peerkey_b64, int param)
5769 {
5770 growwgdata(sizeof(*wg_peer));
5771 if (wg_aip)
5772 wg_peer = (struct wg_peer_io *)wg_aip;
5773 else
5774 wg_peer = &wg_interface->i_peers[0];
5775 wg_aip = &wg_peer->p_aips[0];
5776 wg_peer->p_flags |= WG_PEER_HAS_PUBLIC;
5777 WG_LOAD_KEY(wg_peer->p_public, peerkey_b64, "wgpeer");
5778 wg_interface->i_peers_count++;
5779 }
5780
5781 void
setwgpeerdesc(const char * descr,int param)5782 setwgpeerdesc(const char *descr, int param)
5783 {
5784 if (wg_peer == NULL)
5785 errx(1, "wgdescr: wgpeer not set");
5786 wg_peer->p_flags |= WG_PEER_SET_DESCRIPTION;
5787 strlcpy(wg_peer->p_description, descr, IFDESCRSIZE);
5788 }
5789
5790 void
setwgpeeraip(const char * aip,int param)5791 setwgpeeraip(const char *aip, int param)
5792 {
5793 int res;
5794 if (wg_peer == NULL)
5795 errx(1, "wgaip: wgpeer not set");
5796
5797 growwgdata(sizeof(*wg_aip));
5798
5799 if ((res = inet_net_pton(AF_INET, aip, &wg_aip->a_ipv4,
5800 sizeof(wg_aip->a_ipv4))) != -1) {
5801 wg_aip->a_af = AF_INET;
5802 } else if ((res = inet_net_pton(AF_INET6, aip, &wg_aip->a_ipv6,
5803 sizeof(wg_aip->a_ipv6))) != -1) {
5804 wg_aip->a_af = AF_INET6;
5805 } else {
5806 errx(1, "wgaip: bad address");
5807 }
5808
5809 wg_aip->a_cidr = res;
5810
5811 wg_peer->p_flags |= WG_PEER_REPLACE_AIPS;
5812 wg_peer->p_aips_count++;
5813
5814 wg_aip++;
5815 }
5816
5817 void
setwgpeerep(const char * host,const char * service)5818 setwgpeerep(const char *host, const char *service)
5819 {
5820 int error;
5821 struct addrinfo *ai;
5822
5823 if (wg_peer == NULL)
5824 errx(1, "wgendpoint: wgpeer not set");
5825
5826 if ((error = getaddrinfo(host, service, NULL, &ai)) != 0)
5827 errx(1, "%s", gai_strerror(error));
5828
5829 wg_peer->p_flags |= WG_PEER_HAS_ENDPOINT;
5830 memcpy(&wg_peer->p_sa, ai->ai_addr, ai->ai_addrlen);
5831 freeaddrinfo(ai);
5832 }
5833
5834 void
setwgpeerpsk(const char * psk_b64,int param)5835 setwgpeerpsk(const char *psk_b64, int param)
5836 {
5837 if (wg_peer == NULL)
5838 errx(1, "wgpsk: wgpeer not set");
5839 wg_peer->p_flags |= WG_PEER_HAS_PSK;
5840 WG_LOAD_KEY(wg_peer->p_psk, psk_b64, "wgpsk");
5841 }
5842
5843 void
setwgpeerpka(const char * pka,int param)5844 setwgpeerpka(const char *pka, int param)
5845 {
5846 const char *errmsg = NULL;
5847 if (wg_peer == NULL)
5848 errx(1, "wgpka: wgpeer not set");
5849 /* 43200 == 12h, reasonable for a 16 bit value */
5850 wg_peer->p_flags |= WG_PEER_HAS_PKA;
5851 wg_peer->p_pka = strtonum(pka, 0, 43200, &errmsg);
5852 if (errmsg)
5853 errx(1, "wgpka: %s, %s", pka, errmsg);
5854 }
5855
5856 void
setwgport(const char * port,int param)5857 setwgport(const char *port, int param)
5858 {
5859 const char *errmsg = NULL;
5860 ensurewginterface();
5861 wg_interface->i_flags |= WG_INTERFACE_HAS_PORT;
5862 wg_interface->i_port = strtonum(port, 0, 65535, &errmsg);
5863 if (errmsg)
5864 errx(1, "wgport: %s, %s", port, errmsg);
5865 }
5866
5867 void
setwgkey(const char * private_b64,int param)5868 setwgkey(const char *private_b64, int param)
5869 {
5870 ensurewginterface();
5871 wg_interface->i_flags |= WG_INTERFACE_HAS_PRIVATE;
5872 WG_LOAD_KEY(wg_interface->i_private, private_b64, "wgkey");
5873 }
5874
5875 void
setwgrtable(const char * id,int param)5876 setwgrtable(const char *id, int param)
5877 {
5878 const char *errmsg = NULL;
5879 ensurewginterface();
5880 wg_interface->i_flags |= WG_INTERFACE_HAS_RTABLE;
5881 wg_interface->i_rtable = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
5882 if (errmsg)
5883 errx(1, "wgrtable %s: %s", id, errmsg);
5884 }
5885
5886 void
unsetwgpeer(const char * peerkey_b64,int param)5887 unsetwgpeer(const char *peerkey_b64, int param)
5888 {
5889 setwgpeer(peerkey_b64, param);
5890 wg_peer->p_flags |= WG_PEER_REMOVE;
5891 }
5892
5893 void
unsetwgpeerdesc(const char * descr,int param)5894 unsetwgpeerdesc(const char *descr, int param)
5895 {
5896 if (wg_peer == NULL)
5897 errx(1, "wgdescr: wgpeer not set");
5898 wg_peer->p_flags |= WG_PEER_SET_DESCRIPTION;
5899 strlcpy(wg_peer->p_description, "", IFDESCRSIZE);
5900 }
5901
5902 void
unsetwgpeerpsk(const char * value,int param)5903 unsetwgpeerpsk(const char *value, int param)
5904 {
5905 if (wg_peer == NULL)
5906 errx(1, "wgpsk: wgpeer not set");
5907 wg_peer->p_flags |= WG_PEER_HAS_PSK;
5908 bzero(wg_peer->p_psk, WG_KEY_LEN);
5909 }
5910
5911 void
unsetwgpeerall(const char * value,int param)5912 unsetwgpeerall(const char *value, int param)
5913 {
5914 ensurewginterface();
5915 wg_interface->i_flags |= WG_INTERFACE_REPLACE_PEERS;
5916 }
5917
5918 void
process_wg_commands(void)5919 process_wg_commands(void)
5920 {
5921 if (actions & A_WIREGUARD) {
5922 strlcpy(wgdata.wgd_name, ifname, sizeof(wgdata.wgd_name));
5923
5924 if (ioctl(sock, SIOCSWG, (caddr_t)&wgdata) == -1)
5925 err(1, "%s: SIOCSWG", wgdata.wgd_name);
5926 }
5927 }
5928
5929 void
wg_status(int ifaliases)5930 wg_status(int ifaliases)
5931 {
5932 size_t i, j, last_size;
5933 struct timespec now;
5934 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
5935 char key[WG_BASE64_KEY_LEN + 1];
5936
5937 strlcpy(wgdata.wgd_name, ifname, sizeof(wgdata.wgd_name));
5938 wgdata.wgd_size = 0;
5939 wgdata.wgd_interface = NULL;
5940 for (last_size = wgdata.wgd_size;; last_size = wgdata.wgd_size) {
5941 if (ioctl(sock, SIOCGWG, (caddr_t)&wgdata) < 0) {
5942 if (errno == ENOTTY)
5943 goto out;
5944 err(1, "%s: SIOCGWG", wgdata.wgd_name);
5945 }
5946 if (last_size >= wgdata.wgd_size)
5947 break;
5948 wgdata.wgd_interface = realloc(wgdata.wgd_interface,
5949 wgdata.wgd_size);
5950 if (!wgdata.wgd_interface)
5951 err(1, "realloc");
5952 }
5953 wg_interface = wgdata.wgd_interface;
5954
5955 if (wg_interface->i_flags & WG_INTERFACE_HAS_PORT)
5956 printf("\twgport %hu\n", wg_interface->i_port);
5957 if (wg_interface->i_flags & WG_INTERFACE_HAS_RTABLE)
5958 printf("\twgrtable %d\n", wg_interface->i_rtable);
5959 if (wg_interface->i_flags & WG_INTERFACE_HAS_PUBLIC) {
5960 b64_ntop(wg_interface->i_public, WG_KEY_LEN,
5961 key, sizeof(key));
5962 printf("\twgpubkey %s\n", key);
5963 }
5964
5965 if (ifaliases) {
5966 wg_peer = &wg_interface->i_peers[0];
5967 for (i = 0; i < wg_interface->i_peers_count; i++) {
5968 b64_ntop(wg_peer->p_public, WG_KEY_LEN,
5969 key, sizeof(key));
5970 printf("\twgpeer %s\n", key);
5971
5972 if (strlen(wg_peer->p_description))
5973 printf("\t\twgdescr: %s\n",
5974 wg_peer->p_description);
5975
5976 if (wg_peer->p_flags & WG_PEER_HAS_PSK)
5977 printf("\t\twgpsk (present)\n");
5978
5979 if (wg_peer->p_flags & WG_PEER_HAS_PKA && wg_peer->p_pka)
5980 printf("\t\twgpka %u (sec)\n", wg_peer->p_pka);
5981
5982 if (wg_peer->p_flags & WG_PEER_HAS_ENDPOINT) {
5983 if (getnameinfo(&wg_peer->p_sa, wg_peer->p_sa.sa_len,
5984 hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
5985 NI_NUMERICHOST | NI_NUMERICSERV) == 0)
5986 printf("\t\twgendpoint %s %s\n", hbuf, sbuf);
5987 else
5988 printf("\t\twgendpoint unable to print\n");
5989 }
5990
5991 printf("\t\ttx: %llu, rx: %llu\n",
5992 wg_peer->p_txbytes, wg_peer->p_rxbytes);
5993
5994 if (wg_peer->p_last_handshake.tv_sec != 0) {
5995 clock_gettime(CLOCK_REALTIME, &now);
5996 printf("\t\tlast handshake: %lld seconds ago\n",
5997 now.tv_sec - wg_peer->p_last_handshake.tv_sec);
5998 }
5999
6000
6001 wg_aip = &wg_peer->p_aips[0];
6002 for (j = 0; j < wg_peer->p_aips_count; j++) {
6003 inet_ntop(wg_aip->a_af, &wg_aip->a_addr,
6004 hbuf, sizeof(hbuf));
6005 printf("\t\twgaip %s/%d\n", hbuf, wg_aip->a_cidr);
6006 wg_aip++;
6007 }
6008 wg_peer = (struct wg_peer_io *)wg_aip;
6009 }
6010 }
6011 out:
6012 free(wgdata.wgd_interface);
6013 }
6014
6015 const struct umb_valdescr umb_regstate[] = MBIM_REGSTATE_DESCRIPTIONS;
6016 const struct umb_valdescr umb_dataclass[] = MBIM_DATACLASS_DESCRIPTIONS;
6017 const struct umb_valdescr umb_simstate[] = MBIM_SIMSTATE_DESCRIPTIONS;
6018 const struct umb_valdescr umb_istate[] = UMB_INTERNAL_STATE_DESCRIPTIONS;
6019
6020 const struct umb_valdescr umb_classalias[] = {
6021 { MBIM_DATACLASS_GPRS | MBIM_DATACLASS_EDGE, "2g" },
6022 { MBIM_DATACLASS_UMTS | MBIM_DATACLASS_HSDPA | MBIM_DATACLASS_HSUPA,
6023 "3g" },
6024 { MBIM_DATACLASS_LTE, "4g" },
6025 { 0, NULL }
6026 };
6027
6028 static int
umb_descr2val(const struct umb_valdescr * vdp,char * str)6029 umb_descr2val(const struct umb_valdescr *vdp, char *str)
6030 {
6031 while (vdp->descr != NULL) {
6032 if (!strcasecmp(vdp->descr, str))
6033 return vdp->val;
6034 vdp++;
6035 }
6036 return 0;
6037 }
6038
6039 void
umb_status(void)6040 umb_status(void)
6041 {
6042 struct umb_info mi;
6043 char provider[UMB_PROVIDERNAME_MAXLEN+1];
6044 char providerid[UMB_PROVIDERID_MAXLEN+1];
6045 char roamingtxt[UMB_ROAMINGTEXT_MAXLEN+1];
6046 char devid[UMB_DEVID_MAXLEN+1];
6047 char fwinfo[UMB_FWINFO_MAXLEN+1];
6048 char hwinfo[UMB_HWINFO_MAXLEN+1];
6049 char sid[UMB_SUBSCRIBERID_MAXLEN+1];
6050 char iccid[UMB_ICCID_MAXLEN+1];
6051 char apn[UMB_APN_MAXLEN+1];
6052 char pn[UMB_PHONENR_MAXLEN+1];
6053 int i, n;
6054 char astr[INET6_ADDRSTRLEN];
6055
6056 memset((char *)&mi, 0, sizeof(mi));
6057 ifr.ifr_data = (caddr_t)&mi;
6058 if (ioctl(sock, SIOCGUMBINFO, (caddr_t)&ifr) == -1)
6059 return;
6060
6061 if (mi.nwerror) {
6062 /* 3GPP 24.008 Cause Code */
6063 printf("\terror: ");
6064 switch (mi.nwerror) {
6065 case 2:
6066 printf("SIM not activated");
6067 break;
6068 case 4:
6069 printf("Roaming not supported");
6070 break;
6071 case 6:
6072 printf("SIM reported stolen");
6073 break;
6074 case 7:
6075 printf("No GPRS subscription");
6076 break;
6077 case 8:
6078 printf("GPRS and non-GPRS services not allowed");
6079 break;
6080 case 11:
6081 printf("Subscription expired");
6082 break;
6083 case 12:
6084 printf("Subscription does not cover current location");
6085 break;
6086 case 13:
6087 printf("No roaming in this location");
6088 break;
6089 case 14:
6090 printf("GPRS not supported");
6091 break;
6092 case 15:
6093 printf("No subscription for the service");
6094 break;
6095 case 17:
6096 printf("Registration failed");
6097 break;
6098 case 22:
6099 printf("Network congestion");
6100 break;
6101 default:
6102 printf("Error code %d", mi.nwerror);
6103 break;
6104 }
6105 printf("\n");
6106 }
6107
6108 printf("\troaming %s registration %s",
6109 mi.enable_roaming ? "enabled" : "disabled",
6110 umb_val2descr(umb_regstate, mi.regstate));
6111 utf16_to_char(mi.roamingtxt, UMB_ROAMINGTEXT_MAXLEN,
6112 roamingtxt, sizeof (roamingtxt));
6113 if (roamingtxt[0])
6114 printf(" [%s]", roamingtxt);
6115 printf("\n");
6116
6117 if (showclasses)
6118 umb_printclasses("available classes", mi.supportedclasses);
6119 printf("\tstate %s cell-class %s",
6120 umb_val2descr(umb_istate, mi.state),
6121 umb_val2descr(umb_dataclass, mi.highestclass));
6122 if (mi.rssi != UMB_VALUE_UNKNOWN && mi.rssi != 0)
6123 printf(" rssi %ddBm", mi.rssi);
6124 if (mi.uplink_speed != 0 || mi.downlink_speed != 0) {
6125 char s[2][FMT_SCALED_STRSIZE];
6126 if (fmt_scaled(mi.uplink_speed, s[0]) != 0)
6127 snprintf(s[0], sizeof (s[0]), "%llu", mi.uplink_speed);
6128 if (fmt_scaled(mi.downlink_speed, s[1]) != 0)
6129 snprintf(s[1], sizeof (s[1]), "%llu", mi.downlink_speed);
6130 printf(" speed %sbps up %sbps down", s[0], s[1]);
6131 }
6132 printf("\n");
6133
6134 printf("\tSIM %s PIN ", umb_val2descr(umb_simstate, mi.sim_state));
6135 switch (mi.pin_state) {
6136 case UMB_PIN_REQUIRED:
6137 printf("required");
6138 break;
6139 case UMB_PIN_UNLOCKED:
6140 printf("valid");
6141 break;
6142 case UMB_PUK_REQUIRED:
6143 printf("locked (PUK required)");
6144 break;
6145 default:
6146 printf("unknown state (%d)", mi.pin_state);
6147 break;
6148 }
6149 if (mi.pin_attempts_left != UMB_VALUE_UNKNOWN)
6150 printf(" (%d attempts left)", mi.pin_attempts_left);
6151 printf("\n");
6152
6153 utf16_to_char(mi.sid, UMB_SUBSCRIBERID_MAXLEN, sid, sizeof (sid));
6154 utf16_to_char(mi.iccid, UMB_ICCID_MAXLEN, iccid, sizeof (iccid));
6155 utf16_to_char(mi.provider, UMB_PROVIDERNAME_MAXLEN,
6156 provider, sizeof (provider));
6157 utf16_to_char(mi.providerid, UMB_PROVIDERID_MAXLEN,
6158 providerid, sizeof (providerid));
6159 if (sid[0] || iccid[0]) {
6160 printf("\t");
6161 n = 0;
6162 if (sid[0])
6163 printf("%ssubscriber-id %s", n++ ? " " : "", sid);
6164 if (iccid[0])
6165 printf("%sICC-id %s", n++ ? " " : "", iccid);
6166 printf("\n");
6167 }
6168
6169 utf16_to_char(mi.hwinfo, UMB_HWINFO_MAXLEN, hwinfo, sizeof (hwinfo));
6170 utf16_to_char(mi.devid, UMB_DEVID_MAXLEN, devid, sizeof (devid));
6171 utf16_to_char(mi.fwinfo, UMB_FWINFO_MAXLEN, fwinfo, sizeof (fwinfo));
6172 if (hwinfo[0] || devid[0] || fwinfo[0]) {
6173 printf("\t");
6174 n = 0;
6175 if (hwinfo[0])
6176 printf("%sdevice %s", n++ ? " " : "", hwinfo);
6177 if (devid[0]) {
6178 printf("%s", n++ ? " " : "");
6179 switch (mi.cellclass) {
6180 case MBIM_CELLCLASS_GSM:
6181 printf("IMEI");
6182 break;
6183 case MBIM_CELLCLASS_CDMA:
6184 n = strlen(devid);
6185 if (n == 8 || n == 11) {
6186 printf("ESN");
6187 break;
6188 } else if (n == 14 || n == 18) {
6189 printf("MEID");
6190 break;
6191 }
6192 /*FALLTHROUGH*/
6193 default:
6194 printf("ID");
6195 break;
6196 }
6197 printf(" %s", devid);
6198 }
6199 if (fwinfo[0])
6200 printf("%sfirmware %s", n++ ? " " : "", fwinfo);
6201 printf("\n");
6202 }
6203
6204 utf16_to_char(mi.pn, UMB_PHONENR_MAXLEN, pn, sizeof (pn));
6205 utf16_to_char(mi.apn, UMB_APN_MAXLEN, apn, sizeof (apn));
6206 if (pn[0] || apn[0] || provider[0] || providerid[0]) {
6207 printf("\t");
6208 n = 0;
6209 if (pn[0])
6210 printf("%sphone# %s", n++ ? " " : "", pn);
6211 if (apn[0])
6212 printf("%sAPN %s", n++ ? " " : "", apn);
6213 if (provider[0])
6214 printf("%sprovider %s", n++ ? " " : "", provider);
6215 if (providerid[0])
6216 printf("%sprovider-id %s", n ? " " : "", providerid);
6217 printf("\n");
6218 }
6219
6220 for (i = 0, n = 0; i < UMB_MAX_DNSSRV; i++) {
6221 if (mi.ipv4dns[i].s_addr == INADDR_ANY)
6222 break;
6223 printf("%s %s", n++ ? "" : "\tdns",
6224 inet_ntop(AF_INET, &mi.ipv4dns[i], astr, sizeof(astr)));
6225 }
6226 for (i = 0; i < UMB_MAX_DNSSRV; i++) {
6227 if (memcmp(&mi.ipv6dns[i], &in6addr_any,
6228 sizeof (mi.ipv6dns[i])) == 0)
6229 break;
6230 printf("%s %s", n++ ? "" : "\tdns",
6231 inet_ntop(AF_INET6, &mi.ipv6dns[i], astr, sizeof(astr)));
6232 }
6233 if (n)
6234 printf("\n");
6235 }
6236
6237 void
umb_printclasses(char * tag,int c)6238 umb_printclasses(char *tag, int c)
6239 {
6240 int i;
6241 char *sep = "";
6242
6243 printf("\t%s: ", tag);
6244 i = 0;
6245 while (umb_dataclass[i].descr) {
6246 if (umb_dataclass[i].val & c) {
6247 printf("%s%s", sep, umb_dataclass[i].descr);
6248 sep = ",";
6249 }
6250 i++;
6251 }
6252 printf("\n");
6253 }
6254
6255 int
umb_parse_classes(const char * spec)6256 umb_parse_classes(const char *spec)
6257 {
6258 char *optlist, *str;
6259 int c = 0, v;
6260
6261 if ((optlist = strdup(spec)) == NULL)
6262 err(1, "strdup");
6263 str = strtok(optlist, ",");
6264 while (str != NULL) {
6265 if ((v = umb_descr2val(umb_dataclass, str)) != 0 ||
6266 (v = umb_descr2val(umb_classalias, str)) != 0)
6267 c |= v;
6268 str = strtok(NULL, ",");
6269 }
6270 free(optlist);
6271 return c;
6272 }
6273
6274 void
umb_setpin(const char * pin,int d)6275 umb_setpin(const char *pin, int d)
6276 {
6277 umb_pinop(MBIM_PIN_OP_ENTER, 0, pin, NULL);
6278 }
6279
6280 void
umb_chgpin(const char * pin,const char * newpin)6281 umb_chgpin(const char *pin, const char *newpin)
6282 {
6283 umb_pinop(MBIM_PIN_OP_CHANGE, 0, pin, newpin);
6284 }
6285
6286 void
umb_puk(const char * pin,const char * newpin)6287 umb_puk(const char *pin, const char *newpin)
6288 {
6289 umb_pinop(MBIM_PIN_OP_ENTER, 1, pin, newpin);
6290 }
6291
6292 void
umb_pinop(int op,int is_puk,const char * pin,const char * newpin)6293 umb_pinop(int op, int is_puk, const char *pin, const char *newpin)
6294 {
6295 struct umb_parameter mp;
6296
6297 memset(&mp, 0, sizeof (mp));
6298 ifr.ifr_data = (caddr_t)∓
6299 if (ioctl(sock, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
6300 err(1, "%s: SIOCGUMBPARAM", ifr.ifr_name);
6301
6302 mp.op = op;
6303 mp.is_puk = is_puk;
6304 if ((mp.pinlen = char_to_utf16(pin, (uint16_t *)mp.pin,
6305 sizeof (mp.pin))) == -1)
6306 errx(1, "PIN too long");
6307
6308 if (newpin) {
6309 if ((mp.newpinlen = char_to_utf16(newpin, (uint16_t *)mp.newpin,
6310 sizeof (mp.newpin))) == -1)
6311 errx(1, "new PIN too long");
6312 }
6313
6314 if (ioctl(sock, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
6315 err(1, "%s: SIOCSUMBPARAM", ifr.ifr_name);
6316 }
6317
6318 void
umb_apn(const char * apn,int d)6319 umb_apn(const char *apn, int d)
6320 {
6321 struct umb_parameter mp;
6322
6323 memset(&mp, 0, sizeof (mp));
6324 ifr.ifr_data = (caddr_t)∓
6325 if (ioctl(sock, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
6326 err(1, "%s: SIOCGUMBPARAM", ifr.ifr_name);
6327
6328 if (d != 0)
6329 memset(mp.apn, 0, sizeof (mp.apn));
6330 else if ((mp.apnlen = char_to_utf16(apn, mp.apn,
6331 sizeof (mp.apn))) == -1)
6332 errx(1, "APN too long");
6333
6334 if (ioctl(sock, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
6335 err(1, "%s: SIOCSUMBPARAM", ifr.ifr_name);
6336 }
6337
6338 void
umb_setclass(const char * val,int d)6339 umb_setclass(const char *val, int d)
6340 {
6341 struct umb_parameter mp;
6342
6343 if (val == NULL) {
6344 if (showclasses)
6345 usage();
6346 showclasses = 1;
6347 return;
6348 }
6349
6350 memset(&mp, 0, sizeof (mp));
6351 ifr.ifr_data = (caddr_t)∓
6352 if (ioctl(sock, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
6353 err(1, "%s: SIOCGUMBPARAM", ifr.ifr_name);
6354 if (d != -1)
6355 mp.preferredclasses = umb_parse_classes(val);
6356 else
6357 mp.preferredclasses = MBIM_DATACLASS_NONE;
6358 if (ioctl(sock, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
6359 err(1, "%s: SIOCSUMBPARAM", ifr.ifr_name);
6360 }
6361
6362 void
umb_roaming(const char * val,int d)6363 umb_roaming(const char *val, int d)
6364 {
6365 struct umb_parameter mp;
6366
6367 memset(&mp, 0, sizeof (mp));
6368 ifr.ifr_data = (caddr_t)∓
6369 if (ioctl(sock, SIOCGUMBPARAM, (caddr_t)&ifr) == -1)
6370 err(1, "%s: SIOCGUMBPARAM", ifr.ifr_name);
6371 mp.roaming = d;
6372 if (ioctl(sock, SIOCSUMBPARAM, (caddr_t)&ifr) == -1)
6373 err(1, "%s: SIOCSUMBPARAM", ifr.ifr_name);
6374 }
6375
6376 void
utf16_to_char(uint16_t * in,int inlen,char * out,size_t outlen)6377 utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen)
6378 {
6379 uint16_t c;
6380
6381 while (outlen > 0) {
6382 c = inlen > 0 ? letoh16(*in) : 0;
6383 if (c == 0 || --outlen == 0) {
6384 /* always NUL terminate result */
6385 *out = '\0';
6386 break;
6387 }
6388 *out++ = isascii(c) ? (char)c : '?';
6389 in++;
6390 inlen--;
6391 }
6392 }
6393
6394 int
char_to_utf16(const char * in,uint16_t * out,size_t outlen)6395 char_to_utf16(const char *in, uint16_t *out, size_t outlen)
6396 {
6397 int n = 0;
6398 uint16_t c;
6399
6400 for (;;) {
6401 c = *in++;
6402
6403 if (c == '\0') {
6404 /*
6405 * NUL termination is not required, but zero out the
6406 * residual buffer
6407 */
6408 memset(out, 0, outlen);
6409 return n;
6410 }
6411 if (outlen < sizeof (*out))
6412 return -1;
6413
6414 *out++ = htole16(c);
6415 n += sizeof (*out);
6416 outlen -= sizeof (*out);
6417 }
6418 }
6419
6420 #endif
6421
6422 #define SIN(x) ((struct sockaddr_in *) &(x))
6423 struct sockaddr_in *sintab[] = {
6424 SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
6425 SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
6426
6427 void
in_getaddr(const char * s,int which)6428 in_getaddr(const char *s, int which)
6429 {
6430 struct sockaddr_in *sin = sintab[which], tsin;
6431 struct hostent *hp;
6432 int bits, l;
6433 char p[3];
6434
6435 bzero(&tsin, sizeof(tsin));
6436 sin->sin_len = sizeof(*sin);
6437 if (which != MASK)
6438 sin->sin_family = AF_INET;
6439
6440 if (which == ADDR && strrchr(s, '/') != NULL &&
6441 (bits = inet_net_pton(AF_INET, s, &tsin.sin_addr,
6442 sizeof(tsin.sin_addr))) != -1) {
6443 l = snprintf(p, sizeof(p), "%d", bits);
6444 if (l < 0 || l >= sizeof(p))
6445 errx(1, "%d: bad prefixlen", bits);
6446 in_getprefix(p, MASK);
6447 memcpy(&sin->sin_addr, &tsin.sin_addr, sizeof(sin->sin_addr));
6448 } else if (inet_aton(s, &sin->sin_addr) == 0) {
6449 if ((hp = gethostbyname(s)))
6450 memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
6451 else
6452 errx(1, "%s: bad value", s);
6453 }
6454 if (which == MASK && (ntohl(sin->sin_addr.s_addr) &
6455 (~ntohl(sin->sin_addr.s_addr) >> 1)))
6456 errx(1, "%s: non-contiguous mask", s);
6457 }
6458
6459 void
in_getprefix(const char * plen,int which)6460 in_getprefix(const char *plen, int which)
6461 {
6462 struct sockaddr_in *sin = sintab[which];
6463 const char *errmsg = NULL;
6464 u_char *cp;
6465 int len;
6466
6467 len = strtonum(plen, 0, 32, &errmsg);
6468 if (errmsg)
6469 errx(1, "prefix %s: %s", plen, errmsg);
6470
6471 sin->sin_len = sizeof(*sin);
6472 if (which != MASK)
6473 sin->sin_family = AF_INET;
6474 if ((len == 0) || (len == 32)) {
6475 memset(&sin->sin_addr, 0xff, sizeof(struct in_addr));
6476 return;
6477 }
6478 memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr));
6479 for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8)
6480 *cp++ = 0xff;
6481 if (len)
6482 *cp = 0xff << (8 - len);
6483 }
6484
6485 /*
6486 * Print a value a la the %b format of the kernel's printf
6487 */
6488 void
printb(char * s,unsigned int v,unsigned char * bits)6489 printb(char *s, unsigned int v, unsigned char *bits)
6490 {
6491 int i, any = 0;
6492 unsigned char c;
6493
6494 if (bits && *bits == 8)
6495 printf("%s=%o", s, v);
6496 else
6497 printf("%s=%x", s, v);
6498
6499 if (bits) {
6500 bits++;
6501 putchar('<');
6502 while ((i = *bits++)) {
6503 if (v & (1 << (i-1))) {
6504 if (any)
6505 putchar(',');
6506 any = 1;
6507 for (; (c = *bits) > 32; bits++)
6508 putchar(c);
6509 } else
6510 for (; *bits > 32; bits++)
6511 ;
6512 }
6513 putchar('>');
6514 }
6515 }
6516
6517 /*
6518 * A simple version of printb for status output
6519 */
6520 void
printb_status(unsigned short v,unsigned char * bits)6521 printb_status(unsigned short v, unsigned char *bits)
6522 {
6523 int i, any = 0;
6524 unsigned char c;
6525
6526 if (bits) {
6527 bits++;
6528 while ((i = *bits++)) {
6529 if (v & (1 << (i-1))) {
6530 if (any)
6531 putchar(',');
6532 any = 1;
6533 for (; (c = *bits) > 32; bits++)
6534 putchar(tolower(c));
6535 } else
6536 for (; *bits > 32; bits++)
6537 ;
6538 }
6539 }
6540 }
6541
6542 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
6543 struct sockaddr_in6 *sin6tab[] = {
6544 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
6545 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
6546
6547 void
in6_getaddr(const char * s,int which)6548 in6_getaddr(const char *s, int which)
6549 {
6550 struct sockaddr_in6 *sin6 = sin6tab[which];
6551 struct addrinfo hints, *res;
6552 char buf[HOST_NAME_MAX+1 + sizeof("/128")], *pfxlen;
6553 int error;
6554
6555 memset(&hints, 0, sizeof(hints));
6556 hints.ai_family = AF_INET6;
6557 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
6558
6559 if (which == ADDR && strchr(s, '/') != NULL) {
6560 if (strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
6561 errx(1, "%s: bad value", s);
6562 pfxlen = strchr(buf, '/');
6563 *pfxlen++ = '\0';
6564 s = buf;
6565 in6_getprefix(pfxlen, MASK);
6566 explicit_prefix = 1;
6567 }
6568
6569 error = getaddrinfo(s, "0", &hints, &res);
6570 if (error)
6571 errx(1, "%s: %s", s, gai_strerror(error));
6572 memcpy(sin6, res->ai_addr, res->ai_addrlen);
6573 #ifdef __KAME__
6574 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
6575 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] == 0 &&
6576 sin6->sin6_scope_id) {
6577 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
6578 htons(sin6->sin6_scope_id & 0xffff);
6579 sin6->sin6_scope_id = 0;
6580 }
6581 #endif /* __KAME__ */
6582 freeaddrinfo(res);
6583 }
6584
6585 void
in6_getprefix(const char * plen,int which)6586 in6_getprefix(const char *plen, int which)
6587 {
6588 struct sockaddr_in6 *sin6 = sin6tab[which];
6589 const char *errmsg = NULL;
6590 u_char *cp;
6591 int len;
6592
6593 len = strtonum(plen, 0, 128, &errmsg);
6594 if (errmsg)
6595 errx(1, "prefix %s: %s", plen, errmsg);
6596
6597 sin6->sin6_len = sizeof(*sin6);
6598 if (which != MASK)
6599 sin6->sin6_family = AF_INET6;
6600 if ((len == 0) || (len == 128)) {
6601 memset(&sin6->sin6_addr, 0xff, sizeof(struct in6_addr));
6602 return;
6603 }
6604 memset((void *)&sin6->sin6_addr, 0x00, sizeof(sin6->sin6_addr));
6605 for (cp = (u_char *)&sin6->sin6_addr; len > 7; len -= 8)
6606 *cp++ = 0xff;
6607 if (len)
6608 *cp = 0xff << (8 - len);
6609 }
6610
6611 int
prefix(void * val,int size)6612 prefix(void *val, int size)
6613 {
6614 u_char *nam = (u_char *)val;
6615 int byte, bit, plen = 0;
6616
6617 for (byte = 0; byte < size; byte++, plen += 8)
6618 if (nam[byte] != 0xff)
6619 break;
6620 if (byte == size)
6621 return (plen);
6622 for (bit = 7; bit != 0; bit--, plen++)
6623 if (!(nam[byte] & (1 << bit)))
6624 break;
6625 for (; bit != 0; bit--)
6626 if (nam[byte] & (1 << bit))
6627 return (0);
6628 byte++;
6629 for (; byte < size; byte++)
6630 if (nam[byte])
6631 return (0);
6632 return (plen);
6633 }
6634
6635 /* Print usage and exit */
6636 __dead void
usage(void)6637 usage(void)
6638 {
6639 fprintf(stderr,
6640 "usage: ifconfig [-AaC] [-M lladdr] [interface] [address_family]\n"
6641 "\t\t[address [dest_address]] [parameters]\n");
6642 exit(1);
6643 }
6644
6645 void
getifgroups(void)6646 getifgroups(void)
6647 {
6648 int len, cnt;
6649 struct ifgroupreq ifgr;
6650 struct ifg_req *ifg;
6651
6652 memset(&ifgr, 0, sizeof(ifgr));
6653 strlcpy(ifgr.ifgr_name, ifname, IFNAMSIZ);
6654
6655 if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
6656 if (errno == EINVAL || errno == ENOTTY)
6657 return;
6658 else
6659 err(1, "%s: SIOCGIFGROUP", ifgr.ifgr_name);
6660 }
6661
6662 len = ifgr.ifgr_len;
6663 ifgr.ifgr_groups = calloc(len / sizeof(struct ifg_req),
6664 sizeof(struct ifg_req));
6665 if (ifgr.ifgr_groups == NULL)
6666 err(1, "getifgroups");
6667 if (ioctl(sock, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
6668 err(1, "%s: SIOCGIFGROUP", ifgr.ifgr_name);
6669
6670 cnt = 0;
6671 ifg = ifgr.ifgr_groups;
6672 for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
6673 len -= sizeof(struct ifg_req);
6674 if (strcmp(ifg->ifgrq_group, "all")) {
6675 if (cnt == 0)
6676 printf("\tgroups:");
6677 cnt++;
6678 printf(" %s", ifg->ifgrq_group);
6679 }
6680 }
6681 if (cnt)
6682 printf("\n");
6683
6684 free(ifgr.ifgr_groups);
6685 }
6686
6687 #ifndef SMALL
6688 void
printifhwfeatures(const char * unused,int show)6689 printifhwfeatures(const char *unused, int show)
6690 {
6691 struct if_data ifrdat;
6692
6693 if (!show) {
6694 if (showcapsflag)
6695 usage();
6696 showcapsflag = 1;
6697 return;
6698 }
6699 bzero(&ifrdat, sizeof(ifrdat));
6700 ifr.ifr_data = (caddr_t)&ifrdat;
6701 if (ioctl(sock, SIOCGIFDATA, (caddr_t)&ifr) == -1)
6702 err(1, "%s: SIOCGIFDATA", ifr.ifr_name);
6703 printb("\thwfeatures", (u_int)ifrdat.ifi_capabilities, HWFEATURESBITS);
6704
6705 if (ioctl(sock, SIOCGIFHARDMTU, (caddr_t)&ifr) != -1) {
6706 if (ifr.ifr_hardmtu)
6707 printf(" hardmtu %u", ifr.ifr_hardmtu);
6708 }
6709 putchar('\n');
6710 }
6711 #endif
6712
6713 char *
sec2str(time_t total)6714 sec2str(time_t total)
6715 {
6716 static char result[256];
6717 char *p = result;
6718 char *end = &result[sizeof(result)];
6719
6720 snprintf(p, end - p, "%lld", (long long)total);
6721 return (result);
6722 }
6723
6724 void
setiflladdr(const char * addr,int param)6725 setiflladdr(const char *addr, int param)
6726 {
6727 struct ether_addr *eap, eabuf;
6728
6729 if (!strcmp(addr, "random")) {
6730 arc4random_buf(&eabuf, sizeof eabuf);
6731 /* Non-multicast and claim it is a hardware address */
6732 eabuf.ether_addr_octet[0] &= 0xfc;
6733 eap = &eabuf;
6734 } else {
6735 eap = ether_aton(addr);
6736 if (eap == NULL) {
6737 warnx("malformed link-level address");
6738 return;
6739 }
6740 }
6741 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6742 ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
6743 ifr.ifr_addr.sa_family = AF_LINK;
6744 bcopy(eap, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
6745 if (ioctl(sock, SIOCSIFLLADDR, (caddr_t)&ifr) == -1)
6746 warn("SIOCSIFLLADDR");
6747 }
6748
6749 #ifndef SMALL
6750 void
setrdomain(const char * id,int param)6751 setrdomain(const char *id, int param)
6752 {
6753 const char *errmsg = NULL;
6754 int rdomainid;
6755
6756 rdomainid = strtonum(id, 0, RT_TABLEID_MAX, &errmsg);
6757 if (errmsg)
6758 errx(1, "rdomain %s: %s", id, errmsg);
6759
6760 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6761 ifr.ifr_rdomainid = rdomainid;
6762 if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1)
6763 warn("SIOCSIFRDOMAIN");
6764 }
6765
6766 void
unsetrdomain(const char * ignored,int alsoignored)6767 unsetrdomain(const char *ignored, int alsoignored)
6768 {
6769 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6770 ifr.ifr_rdomainid = 0;
6771 if (ioctl(sock, SIOCSIFRDOMAIN, (caddr_t)&ifr) == -1)
6772 warn("SIOCSIFRDOMAIN");
6773 }
6774 #endif
6775
6776 #ifndef SMALL
6777 void
setpair(const char * val,int d)6778 setpair(const char *val, int d)
6779 {
6780 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6781 if ((ifr.ifr_index = if_nametoindex(val)) == 0) {
6782 errno = ENOENT;
6783 err(1, "patch %s", val);
6784 }
6785 if (ioctl(sock, SIOCSIFPAIR, (caddr_t)&ifr) == -1)
6786 warn("SIOCSIFPAIR");
6787 }
6788
6789 void
unsetpair(const char * val,int d)6790 unsetpair(const char *val, int d)
6791 {
6792 ifr.ifr_index = 0;
6793 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
6794 if (ioctl(sock, SIOCSIFPAIR, (caddr_t)&ifr) == -1)
6795 warn("SIOCSIFPAIR");
6796 }
6797 #endif
6798
6799 #ifdef SMALL
6800 void
setignore(const char * id,int param)6801 setignore(const char *id, int param)
6802 {
6803 /* just digest the command */
6804 }
6805 #endif
6806
6807 int
findmac(const char * mac)6808 findmac(const char *mac)
6809 {
6810 struct ifaddrs *ifap, *ifa;
6811 const char *ifnam = NULL;
6812 struct if_clonereq *ifcr;
6813 int ret = 0;
6814
6815 ifcr = get_cloners();
6816 if (getifaddrs(&ifap) != 0)
6817 err(1, "getifaddrs");
6818
6819 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
6820 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
6821
6822 if (sdl != NULL && sdl->sdl_alen &&
6823 (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP)) {
6824 if (strcmp(ether_ntoa((struct ether_addr *)LLADDR(sdl)),
6825 mac) == 0) {
6826 char *cp, *nam = ifa->ifa_name;
6827 int idx, skip = 0;
6828 size_t len;
6829
6830 /* MACs on cloned devices are ignored */
6831 for (len = 0; nam[len]; len++)
6832 if (isdigit((unsigned char)nam[len]))
6833 break;
6834 for (cp = ifcr->ifcr_buffer, idx = 0;
6835 idx < ifcr->ifcr_count;
6836 idx++, cp += IFNAMSIZ) {
6837 if (strncmp(nam, cp, len) == 0) {
6838 skip = 1;
6839 break;
6840 }
6841 }
6842 if (skip)
6843 continue;
6844
6845 if (ifnam) { /* same MAC on multiple ifp */
6846 ret = 1;
6847 goto done;
6848 }
6849 ifnam = nam;
6850 }
6851 }
6852 }
6853 if (ifnam)
6854 printf("%s\n", ifnam);
6855 done:
6856 free(ifcr->ifcr_buffer);
6857 freeifaddrs(ifap);
6858 return ret;
6859 }
6860