1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2010 The FreeBSD Foundation
5  *
6  * This software was developed by Shteryana Sotirova Shopova under
7  * sponsorship from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32 
33 #include <sys/ioctl.h>
34 #include <sys/param.h>
35 #include <sys/module.h>
36 #include <sys/linker.h>
37 #include <sys/socket.h>
38 #include <sys/sysctl.h>
39 
40 #include <net/if.h>
41 #include <net/if_dl.h>
42 #include <net/if_media.h>
43 #include <net/if_mib.h>
44 #include <net/if_types.h>
45 #include <net80211/ieee80211.h>
46 #include <net80211/ieee80211_ioctl.h>
47 #include <net80211/ieee80211_regdomain.h>
48 
49 #include <errno.h>
50 #include <ifaddrs.h>
51 #include <stdarg.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <syslog.h>
56 
57 #include <bsnmp/snmpmod.h>
58 #include <bsnmp/snmp_mibII.h>
59 
60 #define	SNMPTREE_TYPES
61 #include "wlan_tree.h"
62 #include "wlan_snmp.h"
63 
64 static int sock = -1;
65 
66 static int	wlan_ioctl(char *, uint16_t, int *, void *, size_t *, int);
67 static int	wlan_kmod_load(const char *);
68 static uint32_t	wlan_drivercaps_to_snmp(uint32_t);
69 static uint32_t	wlan_cryptocaps_to_snmp(uint32_t);
70 static uint32_t	wlan_htcaps_to_snmp(uint32_t);
71 static uint32_t	wlan_peerstate_to_snmp(uint32_t);
72 static uint32_t	wlan_peercaps_to_snmp(uint32_t );
73 static uint32_t	wlan_channel_flags_to_snmp_phy(uint32_t);
74 static uint32_t	wlan_regdomain_to_snmp(int);
75 static uint32_t	wlan_snmp_to_scan_flags(int);
76 static int	wlan_config_snmp2ioctl(int);
77 static int	wlan_snmp_to_regdomain(enum WlanRegDomainCode);
78 static int	wlan_config_get_country(struct wlan_iface *);
79 static int	wlan_config_set_country(struct wlan_iface *, char *, int);
80 static int	wlan_config_get_dchannel(struct wlan_iface *wif);
81 static int	wlan_config_set_dchannel(struct wlan_iface *wif, uint32_t);
82 static int	wlan_config_get_bssid(struct wlan_iface *);
83 static int	wlan_config_set_bssid(struct wlan_iface *, uint8_t *);
84 static void	wlan_config_set_snmp_intval(struct wlan_iface *, int, int);
85 static int	wlan_config_snmp2value(int, int, int *);
86 static int	wlan_config_check(struct wlan_iface *, int);
87 static int	wlan_config_get_intval(struct wlan_iface *, int);
88 static int	wlan_config_set_intval(struct wlan_iface *, int, int);
89 static int	wlan_add_new_scan_result(struct wlan_iface *,
90     const struct ieee80211req_scan_result *, uint8_t *);
91 static int	wlan_add_mac_macinfo(struct wlan_iface *,
92     const struct ieee80211req_maclist *);
93 static struct wlan_peer *wlan_add_peerinfo(const struct ieee80211req_sta_info *);
94 
95 int
96 wlan_ioctl_init(void)
97 {
98 	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
99 		syslog(LOG_ERR, "cannot open socket : %s", strerror(errno));
100 		return (-1);
101 	}
102 
103 	return (0);
104 }
105 /*
106  * Load the needed modules in kernel if not already there.
107  */
108 enum wlan_kmodules {
109 	WLAN_KMOD = 0,
110 	WLAN_KMOD_ACL,
111 	WLAN_KMOD_WEP,
112 	WLAN_KMODS_MAX
113 };
114 
115 static const char *wmod_names[] = {
116 	"wlan",
117 	"wlan_wlan_acl",
118 	"wlan_wep",
119 	NULL
120 };
121 
122 static int
123 wlan_kmod_load(const char *modname)
124 {
125 	int fileid, modid;
126 	struct module_stat mstat;
127 
128 	mstat.version = sizeof(struct module_stat);
129 	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
130 		for (modid = kldfirstmod(fileid); modid > 0;
131 			modid = modfnext(modid)) {
132 			if (modstat(modid, &mstat) < 0)
133 				continue;
134 			if (strcmp(modname, mstat.name) == 0)
135 				return (0);
136 		}
137 	}
138 
139 	/* Not present - load it. */
140 	if (kldload(modname) < 0) {
141 		syslog(LOG_ERR, "failed to load %s kernel module - %s", modname,
142 		    strerror(errno));
143 		return (-1);
144 	}
145 
146 	return (1);
147 }
148 
149 int
150 wlan_kmodules_load(void)
151 {
152 	if (wlan_kmod_load(wmod_names[WLAN_KMOD]) < 0)
153 		return (-1);
154 
155 	if (wlan_kmod_load(wmod_names[WLAN_KMOD_ACL]) > 0)
156 		syslog(LOG_NOTICE, "SNMP wlan loaded %s module",
157 		    wmod_names[WLAN_KMOD_ACL]);
158 
159 	if (wlan_kmod_load(wmod_names[WLAN_KMOD_WEP]) > 0)
160 		syslog(LOG_NOTICE, "SNMP wlan loaded %s module",
161 		    wmod_names[WLAN_KMOD_WEP]);
162 
163 	return (0);
164 }
165 
166 /* XXX: FIXME */
167 static int
168 wlan_ioctl(char *wif_name, uint16_t req_type, int *val, void *arg,
169      size_t *argsize, int set)
170 {
171 	struct ieee80211req ireq;
172 
173 	memset(&ireq, 0, sizeof(struct ieee80211req));
174 	strlcpy(ireq.i_name, wif_name, IFNAMSIZ);
175 
176 	ireq.i_type = req_type;
177 	ireq.i_val = *val;
178 	ireq.i_len = *argsize;
179 	ireq.i_data = arg;
180 
181 	if (ioctl(sock, set ? SIOCS80211 : SIOCG80211, &ireq) < 0) {
182 		syslog(LOG_ERR, "iface %s - %s param: ioctl(%d) "
183 		    "failed: %s", wif_name, set ? "set" : "get",
184 		    req_type, strerror(errno));
185 		return (-1);
186 	}
187 
188 	*argsize = ireq.i_len;
189 	*val = ireq.i_val;
190 
191 	return (0);
192 }
193 
194 int
195 wlan_check_media(char *ifname)
196 {
197 	struct ifmediareq ifmr;
198 
199 	memset(&ifmr, 0, sizeof(struct ifmediareq));
200 	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
201 
202 	if (ioctl(sock, SIOCGIFMEDIA, &ifmr) < 0 || ifmr.ifm_count == 0)
203 		return (0);     /* Interface doesn't support SIOCGIFMEDIA. */
204 
205 	if ((ifmr.ifm_status & IFM_AVALID) == 0)
206 		return (0);
207 
208 	return (IFM_TYPE(ifmr.ifm_active));
209 }
210 
211 int
212 wlan_get_opmode(struct wlan_iface *wif)
213 {
214 	struct ifmediareq ifmr;
215 
216 	memset(&ifmr, 0, sizeof(struct ifmediareq));
217 	strlcpy(ifmr.ifm_name, wif->wname, sizeof(ifmr.ifm_name));
218 
219 	if (ioctl(sock, SIOCGIFMEDIA, &ifmr) < 0) {
220 		if (errno == ENXIO)
221 			return (-1);
222 		wif->mode = WlanIfaceOperatingModeType_station;
223 		return (0);
224 	}
225 
226 	if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
227 		if (ifmr.ifm_current & IFM_FLAG0)
228 			wif->mode = WlanIfaceOperatingModeType_adhocDemo;
229 		else
230 			wif->mode = WlanIfaceOperatingModeType_ibss;
231 	} else if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
232 		wif->mode = WlanIfaceOperatingModeType_hostAp;
233 	else if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
234 		wif->mode = WlanIfaceOperatingModeType_monitor;
235 	else if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
236 		wif->mode = WlanIfaceOperatingModeType_meshPoint;
237 	else if (ifmr.ifm_current & IFM_IEEE80211_WDS)
238 		wif->mode = WlanIfaceOperatingModeType_wds;
239 
240 	return (0);
241 }
242 
243 int
244 wlan_config_state(struct wlan_iface *wif, uint8_t set)
245 {
246 	int	flags;
247 	struct ifreq ifr;
248 
249 	memset(&ifr, 0, sizeof(ifr));
250 	strcpy(ifr.ifr_name, wif->wname);
251 
252 	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
253 		syslog(LOG_ERR, "set %s status: ioctl(SIOCGIFFLAGS) "
254 		    "failed: %s", wif->wname, strerror(errno));
255 		return (-1);
256 	}
257 
258 	if (set == 0) {
259 		if ((ifr.ifr_flags & IFF_UP) != 0)
260 			wif->state = wlanIfaceState_up;
261 		else
262 			wif->state = wlanIfaceState_down;
263 		return (0);
264 	}
265 
266 	flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
267 
268 	if (wif->state == wlanIfaceState_up)
269 		flags |= IFF_UP;
270 	else
271 		flags &= ~IFF_UP;
272 
273 	ifr.ifr_flags = flags & 0xffff;
274 	ifr.ifr_flagshigh = flags >> 16;
275 	if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
276 		syslog(LOG_ERR, "set %s %s: ioctl(SIOCSIFFLAGS) failed: %s",
277 		    wif->wname, wif->state == wlanIfaceState_up?"up":"down",
278 		    strerror(errno));
279 		return (-1);
280 	}
281 
282 	return (0);
283 }
284 
285 int
286 wlan_get_local_addr(struct wlan_iface *wif)
287 {
288 	int len;
289 	char ifname[IFNAMSIZ];
290 	struct ifaddrs *ifap, *ifa;
291 	struct sockaddr_dl sdl;
292 
293 	if (getifaddrs(&ifap) != 0) {
294 		syslog(LOG_ERR, "wlan get mac: getifaddrs() failed - %s",
295 		    strerror(errno));
296 		return (-1);
297 	}
298 
299 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
300 		if (ifa->ifa_addr->sa_family != AF_LINK)
301 			continue;
302 		memcpy(&sdl, ifa->ifa_addr, sizeof(struct sockaddr_dl));
303 		if (sdl.sdl_alen > IEEE80211_ADDR_LEN)
304 			continue;
305 		if ((len = sdl.sdl_nlen) >= IFNAMSIZ)
306 			len = IFNAMSIZ - 1;
307 		memcpy(ifname, sdl.sdl_data, len);
308 		ifname[len] = '\0';
309 		if (strcmp(wif->wname, ifname) == 0)
310 			break;
311 	}
312 
313 	freeifaddrs(ifap);
314 	return (0);
315 }
316 
317 int
318 wlan_get_parent(struct wlan_iface *wif __unused)
319 {
320 	/* XXX: There's no way to fetch this from the kernel. */
321 	return (0);
322 }
323 
324 /* XXX */
325 #define	IEEE80211_C_STA		0x00000001	/* CAPABILITY: STA available */
326 #define	IEEE80211_C_8023ENCAP	0x00000002	/* CAPABILITY: 802.3 encap */
327 #define	IEEE80211_C_FF		0x00000040	/* CAPABILITY: ATH FF avail */
328 #define	IEEE80211_C_TURBOP	0x00000080	/* CAPABILITY: ATH Turbo avail*/
329 #define	IEEE80211_C_IBSS	0x00000100	/* CAPABILITY: IBSS available */
330 #define	IEEE80211_C_PMGT	0x00000200	/* CAPABILITY: Power mgmt */
331 #define	IEEE80211_C_HOSTAP	0x00000400	/* CAPABILITY: HOSTAP avail */
332 #define	IEEE80211_C_AHDEMO	0x00000800	/* CAPABILITY: Old Adhoc Demo */
333 #define	IEEE80211_C_SWRETRY	0x00001000	/* CAPABILITY: sw tx retry */
334 #define	IEEE80211_C_TXPMGT	0x00002000	/* CAPABILITY: tx power mgmt */
335 #define	IEEE80211_C_SHSLOT	0x00004000	/* CAPABILITY: short slottime */
336 #define	IEEE80211_C_SHPREAMBLE	0x00008000	/* CAPABILITY: short preamble */
337 #define	IEEE80211_C_MONITOR	0x00010000	/* CAPABILITY: monitor mode */
338 #define	IEEE80211_C_DFS		0x00020000	/* CAPABILITY: DFS/radar avail*/
339 #define	IEEE80211_C_MBSS	0x00040000	/* CAPABILITY: MBSS available */
340 /* 0x7c0000 available */
341 #define	IEEE80211_C_WPA1	0x00800000	/* CAPABILITY: WPA1 avail */
342 #define	IEEE80211_C_WPA2	0x01000000	/* CAPABILITY: WPA2 avail */
343 #define	IEEE80211_C_WPA		0x01800000	/* CAPABILITY: WPA1+WPA2 avail*/
344 #define	IEEE80211_C_BURST	0x02000000	/* CAPABILITY: frame bursting */
345 #define	IEEE80211_C_WME		0x04000000	/* CAPABILITY: WME avail */
346 #define	IEEE80211_C_WDS		0x08000000	/* CAPABILITY: 4-addr support */
347 /* 0x10000000 reserved */
348 #define	IEEE80211_C_BGSCAN	0x20000000	/* CAPABILITY: bg scanning */
349 #define	IEEE80211_C_TXFRAG	0x40000000	/* CAPABILITY: tx fragments */
350 #define	IEEE80211_C_TDMA	0x80000000	/* CAPABILITY: TDMA avail */
351 
352 static uint32_t
353 wlan_drivercaps_to_snmp(uint32_t dcaps)
354 {
355 	uint32_t scaps = 0;
356 
357 	if ((dcaps & IEEE80211_C_STA) != 0)
358 		scaps |= (0x1 << WlanDriverCaps_station);
359 	if ((dcaps & IEEE80211_C_8023ENCAP) != 0)
360 		scaps |= (0x1 << WlanDriverCaps_ieee8023encap);
361 	if ((dcaps & IEEE80211_C_FF) != 0)
362 		scaps |= (0x1 << WlanDriverCaps_athFastFrames);
363 	if ((dcaps & IEEE80211_C_TURBOP) != 0)
364 		scaps |= (0x1 << WlanDriverCaps_athTurbo);
365 	if ((dcaps & IEEE80211_C_IBSS) != 0)
366 		scaps |= (0x1 << WlanDriverCaps_ibss);
367 	if ((dcaps & IEEE80211_C_PMGT) != 0)
368 		scaps |= (0x1 << WlanDriverCaps_pmgt);
369 	if ((dcaps & IEEE80211_C_HOSTAP) != 0)
370 		scaps |= (0x1 << WlanDriverCaps_hostAp);
371 	if ((dcaps & IEEE80211_C_AHDEMO) != 0)
372 		scaps |= (0x1 << WlanDriverCaps_ahDemo);
373 	if ((dcaps & IEEE80211_C_SWRETRY) != 0)
374 		scaps |= (0x1 << WlanDriverCaps_swRetry);
375 	if ((dcaps & IEEE80211_C_TXPMGT) != 0)
376 		scaps |= (0x1 << WlanDriverCaps_txPmgt);
377 	if ((dcaps & IEEE80211_C_SHSLOT) != 0)
378 		scaps |= (0x1 << WlanDriverCaps_shortSlot);
379 	if ((dcaps & IEEE80211_C_SHPREAMBLE) != 0)
380 		scaps |= (0x1 << WlanDriverCaps_shortPreamble);
381 	if ((dcaps & IEEE80211_C_MONITOR) != 0)
382 		scaps |= (0x1 << WlanDriverCaps_monitor);
383 	if ((dcaps & IEEE80211_C_DFS) != 0)
384 		scaps |= (0x1 << WlanDriverCaps_dfs);
385 	if ((dcaps & IEEE80211_C_MBSS) != 0)
386 		scaps |= (0x1 << WlanDriverCaps_mbss);
387 	if ((dcaps & IEEE80211_C_WPA1) != 0)
388 		scaps |= (0x1 << WlanDriverCaps_wpa1);
389 	if ((dcaps & IEEE80211_C_WPA2) != 0)
390 		scaps |= (0x1 << WlanDriverCaps_wpa2);
391 	if ((dcaps & IEEE80211_C_BURST) != 0)
392 		scaps |= (0x1 << WlanDriverCaps_burst);
393 	if ((dcaps & IEEE80211_C_WME) != 0)
394 		scaps |= (0x1 << WlanDriverCaps_wme);
395 	if ((dcaps & IEEE80211_C_WDS) != 0)
396 		scaps |= (0x1 << WlanDriverCaps_wds);
397 	if ((dcaps & IEEE80211_C_BGSCAN) != 0)
398 		scaps |= (0x1 << WlanDriverCaps_bgScan);
399 	if ((dcaps & IEEE80211_C_TXFRAG) != 0)
400 		scaps |= (0x1 << WlanDriverCaps_txFrag);
401 	if ((dcaps & IEEE80211_C_TDMA) != 0)
402 		scaps |= (0x1 << WlanDriverCaps_tdma);
403 
404 	return (scaps);
405 }
406 
407 static uint32_t
408 wlan_cryptocaps_to_snmp(uint32_t ccaps)
409 {
410 	uint32_t scaps = 0;
411 
412 #if NOT_YET
413 	if ((ccaps & IEEE80211_CRYPTO_WEP) != 0)
414 		scaps |= (0x1 << wlanCryptoCaps_wep);
415 	if ((ccaps & IEEE80211_CRYPTO_TKIP) != 0)
416 		scaps |= (0x1 << wlanCryptoCaps_tkip);
417 	if ((ccaps & IEEE80211_CRYPTO_AES_OCB) != 0)
418 		scaps |= (0x1 << wlanCryptoCaps_aes);
419 	if ((ccaps & IEEE80211_CRYPTO_AES_CCM) != 0)
420 		scaps |= (0x1 << wlanCryptoCaps_aesCcm);
421 	if ((ccaps & IEEE80211_CRYPTO_TKIPMIC) != 0)
422 		scaps |= (0x1 << wlanCryptoCaps_tkipMic);
423 	if ((ccaps & IEEE80211_CRYPTO_CKIP) != 0)
424 		scaps |= (0x1 << wlanCryptoCaps_ckip);
425 #else /* !NOT_YET */
426 	scaps = ccaps;
427 #endif
428 	return (scaps);
429 }
430 
431 #define	IEEE80211_HTC_AMPDU	0x00010000	/* CAPABILITY: A-MPDU tx */
432 #define	IEEE80211_HTC_AMSDU	0x00020000	/* CAPABILITY: A-MSDU tx */
433 /* NB: HT40 is implied by IEEE80211_HTCAP_CHWIDTH40 */
434 #define	IEEE80211_HTC_HT	0x00040000	/* CAPABILITY: HT operation */
435 #define	IEEE80211_HTC_SMPS	0x00080000	/* CAPABILITY: MIMO power save*/
436 #define	IEEE80211_HTC_RIFS	0x00100000	/* CAPABILITY: RIFS support */
437 
438 static uint32_t
439 wlan_htcaps_to_snmp(uint32_t hcaps)
440 {
441 	uint32_t scaps = 0;
442 
443 	if ((hcaps & IEEE80211_HTCAP_LDPC) != 0)
444 		scaps |= (0x1 << WlanHTCaps_ldpc);
445 	if ((hcaps & IEEE80211_HTCAP_CHWIDTH40) != 0)
446 		scaps |= (0x1 << WlanHTCaps_chwidth40);
447 	if ((hcaps & IEEE80211_HTCAP_GREENFIELD) != 0)
448 		scaps |= (0x1 << WlanHTCaps_greenField);
449 	if ((hcaps & IEEE80211_HTCAP_SHORTGI20) != 0)
450 		scaps |= (0x1 << WlanHTCaps_shortGi20);
451 	if ((hcaps & IEEE80211_HTCAP_SHORTGI40) != 0)
452 		scaps |= (0x1 << WlanHTCaps_shortGi40);
453 	if ((hcaps & IEEE80211_HTCAP_TXSTBC) != 0)
454 		scaps |= (0x1 << WlanHTCaps_txStbc);
455 	if ((hcaps & IEEE80211_HTCAP_DELBA) != 0)
456 		scaps |= (0x1 << WlanHTCaps_delba);
457 	if ((hcaps & IEEE80211_HTCAP_MAXAMSDU_7935) != 0)
458 		scaps |= (0x1 << WlanHTCaps_amsdu7935);
459 	if ((hcaps & IEEE80211_HTCAP_DSSSCCK40) != 0)
460 		scaps |= (0x1 << WlanHTCaps_dssscck40);
461 	if ((hcaps & IEEE80211_HTCAP_PSMP) != 0)
462 		scaps |= (0x1 << WlanHTCaps_psmp);
463 	if ((hcaps & IEEE80211_HTCAP_40INTOLERANT) != 0)
464 		scaps |= (0x1 << WlanHTCaps_fortyMHzIntolerant);
465 	if ((hcaps & IEEE80211_HTCAP_LSIGTXOPPROT) != 0)
466 		scaps |= (0x1 << WlanHTCaps_lsigTxOpProt);
467 	if ((hcaps & IEEE80211_HTC_AMPDU) != 0)
468 		scaps |= (0x1 << WlanHTCaps_htcAmpdu);
469 	if ((hcaps & IEEE80211_HTC_AMSDU) != 0)
470 		scaps |= (0x1 << WlanHTCaps_htcAmsdu);
471 	if ((hcaps & IEEE80211_HTC_HT) != 0)
472 		scaps |= (0x1 << WlanHTCaps_htcHt);
473 	if ((hcaps & IEEE80211_HTC_SMPS) != 0)
474 		scaps |= (0x1 << WlanHTCaps_htcSmps);
475 	if ((hcaps & IEEE80211_HTC_RIFS) != 0)
476 		scaps |= (0x1 << WlanHTCaps_htcRifs);
477 
478 	return (scaps);
479 }
480 
481 /* XXX: Not here? */
482 #define	WLAN_SET_TDMA_OPMODE(w) do {						\
483 	if ((w)->mode == WlanIfaceOperatingModeType_adhocDemo &&		\
484 	    ((w)->drivercaps & WlanDriverCaps_tdma) != 0)			\
485 		(w)->mode = WlanIfaceOperatingModeType_tdma;			\
486 } while (0)
487 int
488 wlan_get_driver_caps(struct wlan_iface *wif)
489 {
490 	int val = 0;
491 	size_t argsize;
492 	struct ieee80211_devcaps_req dc;
493 
494 	memset(&dc, 0, sizeof(struct ieee80211_devcaps_req));
495 	argsize = sizeof(struct ieee80211_devcaps_req);
496 
497 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_DEVCAPS, &val, &dc,
498 	    &argsize, 0) < 0)
499 		return (-1);
500 
501 	wif->drivercaps = wlan_drivercaps_to_snmp(dc.dc_drivercaps);
502 	wif->cryptocaps = wlan_cryptocaps_to_snmp(dc.dc_cryptocaps);
503 	wif->htcaps = wlan_htcaps_to_snmp(dc.dc_htcaps);
504 
505 	WLAN_SET_TDMA_OPMODE(wif);
506 
507 	argsize = dc.dc_chaninfo.ic_nchans * sizeof(struct ieee80211_channel);
508 	wif->chanlist = (struct ieee80211_channel *)malloc(argsize);
509 	if (wif->chanlist == NULL)
510 		return (0);
511 
512 	memcpy(wif->chanlist, dc.dc_chaninfo.ic_chans, argsize);
513 	wif->nchannels = dc.dc_chaninfo.ic_nchans;
514 
515 	return (0);
516 }
517 
518 uint8_t
519 wlan_channel_state_to_snmp(uint8_t cstate)
520 {
521 	uint8_t cs = 0;
522 
523 	if ((cstate & IEEE80211_CHANSTATE_RADAR) != 0)
524 		cs |= (0x1 << WlanIfaceChannelStateType_radar);
525 	if ((cstate & IEEE80211_CHANSTATE_CACDONE) != 0)
526 		cs |= (0x1 << WlanIfaceChannelStateType_cacDone);
527 	if ((cstate & IEEE80211_CHANSTATE_CWINT) != 0)
528 		cs |= (0x1 << WlanIfaceChannelStateType_interferenceDetected);
529 	if ((cstate & IEEE80211_CHANSTATE_NORADAR) != 0)
530 		cs |= (0x1 << WlanIfaceChannelStateType_radarClear);
531 
532 	return (cs);
533 }
534 
535 uint32_t
536 wlan_channel_flags_to_snmp(uint32_t cflags)
537 {
538 	uint32_t cf = 0;
539 
540 	if ((cflags & IEEE80211_CHAN_TURBO) != 0)
541 		cf |= (0x1 << WlanIfaceChannelFlagsType_turbo);
542 	if ((cflags & IEEE80211_CHAN_CCK) != 0)
543 		cf |= (0x1 << WlanIfaceChannelFlagsType_cck);
544 	if ((cflags & IEEE80211_CHAN_OFDM) != 0)
545 		cf |= (0x1 << WlanIfaceChannelFlagsType_ofdm);
546 	if ((cflags & IEEE80211_CHAN_2GHZ) != 0)
547 		cf |= (0x1 << WlanIfaceChannelFlagsType_spectrum2Ghz);
548 	if ((cflags & IEEE80211_CHAN_5GHZ) != 0)
549 		cf |= (0x1 << WlanIfaceChannelFlagsType_spectrum5Ghz);
550 	if ((cflags & IEEE80211_CHAN_PASSIVE) != 0)
551 		cf |= (0x1 << WlanIfaceChannelFlagsType_passiveScan);
552 	if ((cflags & IEEE80211_CHAN_DYN) != 0)
553 		cf |= (0x1 << WlanIfaceChannelFlagsType_dynamicCckOfdm);
554 	if ((cflags & IEEE80211_CHAN_GFSK) != 0)
555 		cf |= (0x1 << WlanIfaceChannelFlagsType_gfsk);
556 	if ((cflags & IEEE80211_CHAN_GSM) != 0)
557 		cf |= (0x1 << WlanIfaceChannelFlagsType_spectrum900Mhz);
558 	if ((cflags & IEEE80211_CHAN_STURBO) != 0)
559 		cf |= (0x1 << WlanIfaceChannelFlagsType_dot11aStaticTurbo);
560 	if ((cflags & IEEE80211_CHAN_HALF) != 0)
561 		cf |= (0x1 << WlanIfaceChannelFlagsType_halfRate);
562 	if ((cflags & IEEE80211_CHAN_QUARTER) != 0)
563 		cf |= (0x1 << WlanIfaceChannelFlagsType_quarterRate);
564 	if ((cflags & IEEE80211_CHAN_HT20) != 0)
565 		cf |= (0x1 << WlanIfaceChannelFlagsType_ht20);
566 	if ((cflags & IEEE80211_CHAN_HT40U) != 0)
567 		cf |= (0x1 << WlanIfaceChannelFlagsType_ht40u);
568 	if ((cflags & IEEE80211_CHAN_HT40D) != 0)
569 		cf |= (0x1 << WlanIfaceChannelFlagsType_ht40d);
570 	if ((cflags & IEEE80211_CHAN_DFS) != 0)
571 		cf |= (0x1 << WlanIfaceChannelFlagsType_dfs);
572 	if ((cflags & IEEE80211_CHAN_4MSXMIT) != 0)
573 		cf |= (0x1 << WlanIfaceChannelFlagsType_xmit4ms);
574 	if ((cflags & IEEE80211_CHAN_NOADHOC) != 0)
575 		cf |= (0x1 << WlanIfaceChannelFlagsType_noAdhoc);
576 	if ((cflags & IEEE80211_CHAN_NOHOSTAP) != 0)
577 		cf |= (0x1 << WlanIfaceChannelFlagsType_noHostAp);
578 	if ((cflags & IEEE80211_CHAN_11D) != 0)
579 		cf |= (0x1 << WlanIfaceChannelFlagsType_dot11d);
580 
581 	return (cf);
582 }
583 
584 /* XXX: */
585 #define WLAN_SNMP_MAX_CHANS	256
586 int
587 wlan_get_channel_list(struct wlan_iface *wif)
588 {
589 	int val = 0;
590 	uint32_t i, nchans;
591 	size_t argsize;
592 	struct ieee80211req_chaninfo *chaninfo;
593 	struct ieee80211req_chanlist active;
594 	const struct ieee80211_channel *c;
595 
596 	argsize = sizeof(struct ieee80211req_chaninfo) +
597 	    sizeof(struct ieee80211_channel) * WLAN_SNMP_MAX_CHANS;
598 	chaninfo = (struct ieee80211req_chaninfo *)malloc(argsize);
599 	if (chaninfo == NULL)
600 		return (-1);
601 
602 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_CHANINFO, &val, chaninfo,
603 	    &argsize, 0) < 0)
604 		return (-1);
605 
606 	argsize = sizeof(active);
607 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_CHANLIST, &val, &active,
608 	    &argsize, 0) < 0)
609 		goto error;
610 
611 	for (i = 0, nchans = 0; i < chaninfo->ic_nchans; i++) {
612 		c = &chaninfo->ic_chans[i];
613 		if (!isset(active.ic_channels, c->ic_ieee))
614 				continue;
615 		nchans++;
616 	}
617 	wif->chanlist = (struct ieee80211_channel *)reallocf(wif->chanlist,
618 	    nchans * sizeof(*c));
619 	if (wif->chanlist == NULL)
620 		goto error;
621 	wif->nchannels = nchans;
622 	for (i = 0, nchans = 0; i < chaninfo->ic_nchans; i++) {
623 		c = &chaninfo->ic_chans[i];
624 		if (!isset(active.ic_channels, c->ic_ieee))
625 				continue;
626 		memcpy(wif->chanlist + nchans, c, sizeof (*c));
627 		nchans++;
628 	}
629 
630 	free(chaninfo);
631 	return (0);
632 error:
633 	wif->nchannels = 0;
634 	free(chaninfo);
635 	return (-1);
636 }
637 
638 static enum WlanIfPhyMode
639 wlan_channel_flags_to_snmp_phy(uint32_t cflags)
640 {
641 	/* XXX: recheck */
642 	if ((cflags & IEEE80211_CHAN_A) != 0)
643 		return (WlanIfPhyMode_dot11a);
644 	if ((cflags & IEEE80211_CHAN_B) != 0)
645 		return (WlanIfPhyMode_dot11b);
646 	if ((cflags & IEEE80211_CHAN_G) != 0 ||
647 	    (cflags & IEEE80211_CHAN_PUREG) != 0)
648 		return (WlanIfPhyMode_dot11g);
649 	if ((cflags & IEEE80211_CHAN_FHSS) != 0)
650 		return (WlanIfPhyMode_fh);
651 	if ((cflags & IEEE80211_CHAN_TURBO) != 0 &&
652 	    (cflags & IEEE80211_CHAN_A) != 0)
653 		return (WlanIfPhyMode_turboA);
654 	if ((cflags & IEEE80211_CHAN_TURBO) != 0 &&
655 	    (cflags & IEEE80211_CHAN_G) != 0)
656 		return (WlanIfPhyMode_turboG);
657 	if ((cflags & IEEE80211_CHAN_STURBO) != 0)
658 		return (WlanIfPhyMode_sturboA);
659 	if ((cflags & IEEE80211_CHAN_HALF) != 0)
660 		return (WlanIfPhyMode_ofdmHalf);
661 	if ((cflags & IEEE80211_CHAN_QUARTER) != 0)
662 		return (WlanIfPhyMode_ofdmQuarter);
663 
664 	return (WlanIfPhyMode_auto);
665 }
666 
667 int
668 wlan_get_roam_params(struct wlan_iface *wif)
669 {
670 	int val = 0;
671 	size_t argsize;
672 
673 	argsize = sizeof(struct ieee80211_roamparams_req);
674 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_ROAM, &val,
675 	    &wif->roamparams, &argsize, 0) < 0)
676 		return (-1);
677 
678 	return (0);
679 }
680 
681 int
682 wlan_get_tx_params(struct wlan_iface *wif)
683 {
684 	int val = 0;
685 	size_t argsize;
686 
687 	/*
688 	 * XXX: Reset IEEE80211_RATE_MCS bit on IEEE80211_MODE_11NA
689 	 * and IEEE80211_MODE_11NG modes.
690 	 */
691 	argsize = sizeof(struct ieee80211_txparams_req);
692 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_TXPARAMS, &val,
693 	    &wif->txparams, &argsize, 0) < 0)
694 		return (-1);
695 
696 	return (0);
697 }
698 
699 int
700 wlan_set_tx_params(struct wlan_iface *wif, int32_t pmode __unused)
701 {
702 	int val = 0;
703 	size_t argsize;
704 
705 	/*
706 	 * XXX: Set IEEE80211_RATE_MCS bit on IEEE80211_MODE_11NA
707 	 * and IEEE80211_MODE_11NG modes.
708 	 */
709 	argsize = sizeof(struct ieee80211_txparams_req);
710 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_TXPARAMS, &val,
711 	    &wif->txparams, &argsize, 1) < 0)
712 		return (-1);
713 
714 	return (0);
715 }
716 
717 int
718 wlan_clone_create(struct wlan_iface *wif)
719 {
720 	struct ifreq ifr;
721 	struct ieee80211_clone_params wcp;
722 	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
723 
724 	memset(&wcp, 0, sizeof(wcp));
725 	memset(&ifr, 0, sizeof(ifr));
726 
727 	/* Sanity checks. */
728 	if (wif == NULL || wif->pname[0] == '\0' || wif->mode > WLAN_IFMODE_MAX)
729 		return (SNMP_ERR_INCONS_VALUE);
730 
731 	if (wif->mode == WlanIfaceOperatingModeType_wds &&
732 	    memcmp(wif->dbssid, zerobssid, IEEE80211_ADDR_LEN) == 0)
733 		return (SNMP_ERR_INCONS_VALUE);
734 
735 	strlcpy(wcp.icp_parent, wif->pname, IFNAMSIZ);
736 	if ((wif->flags & WlanIfaceFlagsType_uniqueBssid) != 0)
737 		wcp.icp_flags |= IEEE80211_CLONE_BSSID;
738 	if ((wif->flags & WlanIfaceFlagsType_noBeacons) != 0)
739 		wcp.icp_flags |= IEEE80211_CLONE_NOBEACONS;
740 	if (wif->mode == WlanIfaceOperatingModeType_wds &&
741 	    (wif->flags & WlanIfaceFlagsType_wdsLegacy) != 0)
742 		wcp.icp_flags |= IEEE80211_CLONE_WDSLEGACY;
743 
744 	switch (wif->mode) {
745 	case WlanIfaceOperatingModeType_ibss:
746 		wcp.icp_opmode = IEEE80211_M_IBSS;
747 		break;
748 	case WlanIfaceOperatingModeType_station:
749 		wcp.icp_opmode = IEEE80211_M_STA;
750 		break;
751 	case WlanIfaceOperatingModeType_wds:
752 		wcp.icp_opmode = IEEE80211_M_WDS;
753 		break;
754 	case WlanIfaceOperatingModeType_adhocDemo:
755 		wcp.icp_opmode = IEEE80211_M_AHDEMO;
756 		break;
757 	case WlanIfaceOperatingModeType_hostAp:
758 		wcp.icp_opmode = IEEE80211_M_HOSTAP;
759 		break;
760 	case WlanIfaceOperatingModeType_monitor:
761 		wcp.icp_opmode = IEEE80211_M_MONITOR;
762 		break;
763 	case WlanIfaceOperatingModeType_meshPoint:
764 		wcp.icp_opmode = IEEE80211_M_MBSS;
765 		break;
766 	case WlanIfaceOperatingModeType_tdma:
767 		wcp.icp_opmode = IEEE80211_M_AHDEMO;
768 		wcp.icp_flags |= IEEE80211_CLONE_TDMA;
769 		break;
770 	}
771 
772 	memcpy(wcp.icp_bssid, wif->dbssid, IEEE80211_ADDR_LEN);
773 	if (memcmp(wif->dlmac, zerobssid, IEEE80211_ADDR_LEN) != 0) {
774 		memcpy(wcp.icp_macaddr, wif->dlmac, IEEE80211_ADDR_LEN);
775 		wcp.icp_flags |= IEEE80211_CLONE_MACADDR;
776 	}
777 
778 	strlcpy(ifr.ifr_name, wif->wname, IFNAMSIZ);
779 	ifr.ifr_data = (caddr_t) &wcp;
780 
781 	if (ioctl(sock, SIOCIFCREATE2, (caddr_t) &ifr) < 0) {
782 		syslog(LOG_ERR, "wlan clone create: ioctl(SIOCIFCREATE2) "
783 		    "failed: %s", strerror(errno));
784 		return (SNMP_ERR_GENERR);
785 	}
786 
787 	return (SNMP_ERR_NOERROR);
788 }
789 
790 int
791 wlan_clone_destroy(struct wlan_iface *wif)
792 {
793 	struct ifreq ifr;
794 
795 	if (wif == NULL)
796 		return (SNMP_ERR_INCONS_VALUE);
797 
798 	memset(&ifr, 0, sizeof(ifr));
799 	strcpy(ifr.ifr_name, wif->wname);
800 
801 	if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) {
802 		syslog(LOG_ERR, "wlan clone destroy: ioctl(SIOCIFDESTROY) "
803 		    "failed: %s", strerror(errno));
804 		return (SNMP_ERR_GENERR);
805 	}
806 
807 	return (SNMP_ERR_NOERROR);
808 }
809 
810 static int
811 wlan_config_snmp2ioctl(int which)
812 {
813 	int op;
814 
815 	switch (which) {
816 	case LEAF_wlanIfacePacketBurst:
817 		op = IEEE80211_IOC_BURST;
818 		break;
819 	case LEAF_wlanIfaceCountryCode:
820 		op = IEEE80211_IOC_REGDOMAIN;
821 		break;
822 	case LEAF_wlanIfaceRegDomain:
823 		op = IEEE80211_IOC_REGDOMAIN;
824 		break;
825 	case LEAF_wlanIfaceDesiredSsid:
826 		op = IEEE80211_IOC_SSID;
827 		break;
828 	case LEAF_wlanIfaceDesiredChannel:
829 		op = IEEE80211_IOC_CURCHAN;
830 		break;
831 	case LEAF_wlanIfaceDynamicFreqSelection:
832 		op = IEEE80211_IOC_DFS;
833 		break;
834 	case LEAF_wlanIfaceFastFrames:
835 		op = IEEE80211_IOC_FF;
836 		break;
837 	case LEAF_wlanIfaceDturbo:
838 		op = IEEE80211_IOC_TURBOP;
839 		break;
840 	case LEAF_wlanIfaceTxPower:
841 		op = IEEE80211_IOC_TXPOWER;
842 		break;
843 	case LEAF_wlanIfaceFragmentThreshold:
844 		op = IEEE80211_IOC_FRAGTHRESHOLD;
845 		break;
846 	case LEAF_wlanIfaceRTSThreshold:
847 		op = IEEE80211_IOC_RTSTHRESHOLD;
848 		break;
849 	case LEAF_wlanIfaceWlanPrivacySubscribe:
850 		op = IEEE80211_IOC_WPS;
851 		break;
852 	case LEAF_wlanIfaceBgScan:
853 		op = IEEE80211_IOC_BGSCAN;
854 		break;
855 	case LEAF_wlanIfaceBgScanIdle:
856 		op = IEEE80211_IOC_BGSCAN_IDLE;
857 		break;
858 	case LEAF_wlanIfaceBgScanInterval:
859 		op = IEEE80211_IOC_BGSCAN_INTERVAL;
860 		break;
861 	case LEAF_wlanIfaceBeaconMissedThreshold:
862 		op = IEEE80211_IOC_BMISSTHRESHOLD;
863 		break;
864 	case LEAF_wlanIfaceDesiredBssid:
865 		op = IEEE80211_IOC_BSSID;
866 		break;
867 	case LEAF_wlanIfaceRoamingMode:
868 		op = IEEE80211_IOC_ROAMING;
869 		break;
870 	case LEAF_wlanIfaceDot11d:
871 		op = IEEE80211_IOC_DOTD;
872 		break;
873 	case LEAF_wlanIfaceDot11h:
874 		op = IEEE80211_IOC_DOTH;
875 		break;
876 	case LEAF_wlanIfaceDynamicWds:
877 		op = IEEE80211_IOC_DWDS;
878 		break;
879 	case LEAF_wlanIfacePowerSave:
880 		op = IEEE80211_IOC_POWERSAVE;
881 		break;
882 	case LEAF_wlanIfaceApBridge:
883 		op = IEEE80211_IOC_APBRIDGE;
884 		break;
885 	case LEAF_wlanIfaceBeaconInterval:
886 		op = IEEE80211_IOC_BEACON_INTERVAL;
887 		break;
888 	case LEAF_wlanIfaceDtimPeriod:
889 		op = IEEE80211_IOC_DTIM_PERIOD;
890 		break;
891 	case LEAF_wlanIfaceHideSsid:
892 		op = IEEE80211_IOC_HIDESSID;
893 		break;
894 	case LEAF_wlanIfaceInactivityProccess:
895 		op = IEEE80211_IOC_INACTIVITY;
896 		break;
897 	case LEAF_wlanIfaceDot11gProtMode:
898 		op = IEEE80211_IOC_PROTMODE;
899 		break;
900 	case LEAF_wlanIfaceDot11gPureMode:
901 		op = IEEE80211_IOC_PUREG;
902 		break;
903 	case LEAF_wlanIfaceDot11nPureMode:
904 		op = IEEE80211_IOC_PUREN;
905 		break;
906 	case LEAF_wlanIfaceDot11nAmpdu:
907 		op = IEEE80211_IOC_AMPDU;
908 		break;
909 	case LEAF_wlanIfaceDot11nAmpduDensity:
910 		op = IEEE80211_IOC_AMPDU_DENSITY;
911 		break;
912 	case LEAF_wlanIfaceDot11nAmpduLimit:
913 		op = IEEE80211_IOC_AMPDU_LIMIT;
914 		break;
915 	case LEAF_wlanIfaceDot11nAmsdu:
916 		op = IEEE80211_IOC_AMSDU;
917 		break;
918 	case LEAF_wlanIfaceDot11nAmsduLimit:
919 		op = IEEE80211_IOC_AMSDU_LIMIT;
920 		break;
921 	case LEAF_wlanIfaceDot11nHighThroughput:
922 		op = IEEE80211_IOC_HTCONF;
923 		break;
924 	case LEAF_wlanIfaceDot11nHTCompatible:
925 		op = IEEE80211_IOC_HTCOMPAT;
926 		break;
927 	case LEAF_wlanIfaceDot11nHTProtMode:
928 		op = IEEE80211_IOC_HTPROTMODE;
929 		break;
930 	case LEAF_wlanIfaceDot11nRIFS:
931 		op = IEEE80211_IOC_RIFS;
932 		break;
933 	case LEAF_wlanIfaceDot11nShortGI:
934 		op = IEEE80211_IOC_SHORTGI;
935 		break;
936 	case LEAF_wlanIfaceDot11nSMPSMode:
937 		op = IEEE80211_IOC_SMPS;
938 		break;
939 	case LEAF_wlanIfaceTdmaSlot:
940 		op = IEEE80211_IOC_TDMA_SLOT;
941 		break;
942 	case LEAF_wlanIfaceTdmaSlotCount:
943 		op = IEEE80211_IOC_TDMA_SLOTCNT;
944 		break;
945 	case LEAF_wlanIfaceTdmaSlotLength:
946 		op = IEEE80211_IOC_TDMA_SLOTLEN;
947 		break;
948 	case LEAF_wlanIfaceTdmaBeaconInterval:
949 		op = IEEE80211_IOC_TDMA_BINTERVAL;
950 		break;
951 	default:
952 		op = -1;
953 	}
954 
955 	return (op);
956 }
957 
958 static enum WlanRegDomainCode
959 wlan_regdomain_to_snmp(int which)
960 {
961 	enum WlanRegDomainCode reg_domain;
962 
963 	switch (which) {
964 	case SKU_FCC:
965 		reg_domain = WlanRegDomainCode_fcc;
966 		break;
967 	case SKU_CA:
968 		reg_domain = WlanRegDomainCode_ca;
969 		break;
970 	case SKU_ETSI:
971 		reg_domain = WlanRegDomainCode_etsi;
972 		break;
973 	case SKU_ETSI2:
974 		reg_domain = WlanRegDomainCode_etsi2;
975 		break;
976 	case SKU_ETSI3:
977 		reg_domain = WlanRegDomainCode_etsi3;
978 		break;
979 	case SKU_FCC3:
980 		reg_domain = WlanRegDomainCode_fcc3;
981 		break;
982 	case SKU_JAPAN:
983 		reg_domain = WlanRegDomainCode_japan;
984 		break;
985 	case SKU_KOREA:
986 		reg_domain = WlanRegDomainCode_korea;
987 		break;
988 	case SKU_APAC:
989 		reg_domain = WlanRegDomainCode_apac;
990 		break;
991 	case SKU_APAC2:
992 		reg_domain = WlanRegDomainCode_apac2;
993 		break;
994 	case SKU_APAC3:
995 		reg_domain = WlanRegDomainCode_apac3;
996 		break;
997 	case SKU_ROW:
998 		reg_domain = WlanRegDomainCode_row;
999 		break;
1000 	case SKU_NONE:
1001 		reg_domain = WlanRegDomainCode_none;
1002 		break;
1003 	case SKU_DEBUG:
1004 		reg_domain = WlanRegDomainCode_debug;
1005 		break;
1006 	case SKU_SR9:
1007 		reg_domain = WlanRegDomainCode_sr9;
1008 		break;
1009 	case SKU_XR9:
1010 		reg_domain = WlanRegDomainCode_xr9;
1011 		break;
1012 	case SKU_GZ901:
1013 		reg_domain = WlanRegDomainCode_gz901;
1014 		break;
1015 	case 0:
1016 		reg_domain = WlanRegDomainCode_none;
1017 		break;
1018 	default:
1019 		syslog(LOG_ERR, "unknown regdomain (0x%x) ", which);
1020 		reg_domain = WlanRegDomainCode_none;
1021 		break;
1022 	}
1023 
1024 	return (reg_domain);
1025 }
1026 
1027 static int
1028 wlan_snmp_to_regdomain(enum WlanRegDomainCode regdomain)
1029 {
1030 	int which;
1031 
1032 	switch (regdomain) {
1033 	case WlanRegDomainCode_fcc:
1034 		which = SKU_FCC;
1035 		break;
1036 	case WlanRegDomainCode_ca:
1037 		which = SKU_CA;
1038 		break;
1039 	case WlanRegDomainCode_etsi:
1040 		which = SKU_ETSI;
1041 		break;
1042 	case WlanRegDomainCode_etsi2:
1043 		which = SKU_ETSI2;
1044 		break;
1045 	case WlanRegDomainCode_etsi3:
1046 		which = SKU_ETSI3;
1047 		break;
1048 	case WlanRegDomainCode_fcc3:
1049 		which = SKU_FCC3;
1050 		break;
1051 	case WlanRegDomainCode_japan:
1052 		which = SKU_JAPAN;
1053 		break;
1054 	case WlanRegDomainCode_korea:
1055 		which = SKU_KOREA;
1056 		break;
1057 	case WlanRegDomainCode_apac:
1058 		which = SKU_APAC;
1059 		break;
1060 	case WlanRegDomainCode_apac2:
1061 		which = SKU_APAC2;
1062 		break;
1063 	case WlanRegDomainCode_apac3:
1064 		which = SKU_APAC3;
1065 		break;
1066 	case WlanRegDomainCode_row:
1067 		which = SKU_ROW;
1068 		break;
1069 	case WlanRegDomainCode_none:
1070 		which = SKU_NONE;
1071 		break;
1072 	case WlanRegDomainCode_debug:
1073 		which = SKU_DEBUG;
1074 		break;
1075 	case WlanRegDomainCode_sr9:
1076 		which = SKU_SR9;
1077 		break;
1078 	case WlanRegDomainCode_xr9:
1079 		which = SKU_XR9;
1080 		break;
1081 	case WlanRegDomainCode_gz901:
1082 		which = SKU_GZ901;
1083 		break;
1084 	default:
1085 		syslog(LOG_ERR, "unknown snmp regdomain (0x%x) ", regdomain);
1086 		which = SKU_NONE;
1087 		break;
1088 	}
1089 
1090 	return (which);
1091 }
1092 
1093 static int
1094 wlan_config_get_country(struct wlan_iface *wif)
1095 {
1096 	int val = 0;
1097 	size_t argsize;
1098 	struct ieee80211_regdomain regdomain;
1099 
1100 	memset(&regdomain, 0, sizeof(regdomain));
1101 	argsize = sizeof(regdomain);
1102 
1103 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_REGDOMAIN, &val, &regdomain,
1104 	    &argsize, 0) < 0)
1105 		return (-1);
1106 
1107 	wif->reg_domain = wlan_regdomain_to_snmp(regdomain.regdomain);
1108 	wif->country_code[0] = regdomain.isocc[0];
1109 	wif->country_code[1] = regdomain.isocc[1];
1110 	wif->country_code[2] = regdomain.location;
1111 
1112 	return (0);
1113 }
1114 
1115 static int
1116 wlan_config_set_country(struct wlan_iface *wif, char *ccode, int rdomain)
1117 {
1118 	int val = 0, txpowermax;
1119 	uint32_t i;
1120 	size_t argsize = 0;
1121 	struct ieee80211_regdomain_req *regdomain;
1122 
1123 	if (wlan_get_channel_list(wif) < 0)
1124 		return (-1);
1125 
1126 	if (wif->nchannels == 0) {
1127 		syslog(LOG_ERR, "iface %s - set regdomain failed", wif->wname);
1128 		return (-1);
1129 	}
1130 
1131 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_TXPOWMAX, &txpowermax, 0,
1132 	    &argsize, 0) < 0)
1133 		return (-1);
1134 
1135 	regdomain = malloc(IEEE80211_REGDOMAIN_SIZE(wif->nchannels));
1136 	if (regdomain == NULL)
1137 		return (-1);
1138 	memset(regdomain, 0, IEEE80211_REGDOMAIN_SIZE(wif->nchannels));
1139 	argsize = IEEE80211_REGDOMAIN_SIZE(wif->nchannels);
1140 
1141 	/* XXX: recheck with how this is done by ifconfig(8) */
1142 	regdomain->rd.regdomain = wlan_snmp_to_regdomain(rdomain);
1143 	regdomain->rd.isocc[0] = ccode[0];
1144 	regdomain->rd.isocc[1] = ccode[1];
1145 	regdomain->rd.location = ccode[2];
1146 
1147 	/* XXX: fill the channel list properly */
1148 	regdomain->chaninfo.ic_nchans = wif->nchannels;
1149 	memcpy(regdomain->chaninfo.ic_chans, wif->chanlist,
1150 	    wif->nchannels * sizeof(struct ieee80211_channel));
1151 	for (i = 0; i < wif->nchannels; i++)
1152 		regdomain->chaninfo.ic_chans[i].ic_maxregpower = txpowermax;
1153 
1154 	wif->state = wlanIfaceState_down;
1155 	if (wlan_config_state(wif, 1) < 0 ||
1156 	    wlan_ioctl(wif->wname, IEEE80211_IOC_REGDOMAIN, &val, regdomain,
1157 	    &argsize, 1) < 0) {
1158 		free(regdomain);
1159 		return (-1);
1160 	}
1161 
1162 	wif->state = wlanIfaceState_up;
1163 	(void)wlan_config_state(wif, 1);
1164 	wif->reg_domain = wlan_regdomain_to_snmp(regdomain->rd.regdomain);
1165 	wif->country_code[0] = regdomain->rd.isocc[0];
1166 	wif->country_code[1] = regdomain->rd.isocc[1];
1167 	wif->country_code[2] = regdomain->rd.location;
1168 	free(regdomain);
1169 
1170 	return (0);
1171 }
1172 
1173 int
1174 wlan_config_get_dssid(struct wlan_iface *wif)
1175 {
1176 	int val = -1;
1177 	size_t argsize = IEEE80211_NWID_LEN + 1;
1178 	char ssid[IEEE80211_NWID_LEN + 1];
1179 
1180 	memset(ssid, 0, IEEE80211_NWID_LEN + 1);
1181 
1182 	if (wlan_ioctl(wif->wname,
1183 	    (wif->mode == WlanIfaceOperatingModeType_meshPoint) ?
1184 	    IEEE80211_IOC_MESH_ID : IEEE80211_IOC_SSID, &val, ssid,
1185 	    &argsize, 0) < 0)
1186 		return (-1);
1187 
1188 	if (argsize > IEEE80211_NWID_LEN)
1189 		argsize = IEEE80211_NWID_LEN;
1190 	memcpy(wif->desired_ssid, ssid, argsize);
1191 	wif->desired_ssid[argsize] = '\0';
1192 
1193 	return (0);
1194 }
1195 
1196 int
1197 wlan_config_set_dssid(struct wlan_iface *wif, char *ssid, int slen)
1198 {
1199 	int val = 0;
1200 	size_t argsize = slen;
1201 
1202 	if (wlan_ioctl(wif->wname,
1203 	    (wif->mode == WlanIfaceOperatingModeType_meshPoint) ?
1204 	    IEEE80211_IOC_MESH_ID : IEEE80211_IOC_SSID, &val, ssid,
1205 	    &argsize, 1) < 0)
1206 		return (-1);
1207 
1208 	if (argsize > IEEE80211_NWID_LEN)
1209 		argsize = IEEE80211_NWID_LEN;
1210 	memcpy(wif->desired_ssid, ssid, argsize);
1211 	wif->desired_ssid[argsize] = '\0';
1212 
1213 	return (0);
1214 }
1215 
1216 static int
1217 wlan_config_get_dchannel(struct wlan_iface *wif)
1218 {
1219 	uint32_t i = 0;
1220 	int val = 0;
1221 	size_t argsize = sizeof(struct ieee80211_channel);
1222 	struct ieee80211_channel chan;
1223 
1224 	if (wlan_get_channel_list(wif) < 0)
1225 		return (-1);
1226 
1227 	memset(&chan, 0, sizeof(chan));
1228 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_CURCHAN, &val, &chan,
1229 	    &argsize, 0) < 0)
1230 		return (-1);
1231 
1232 	for (i = 0; i < wif->nchannels; i++)
1233 		if (chan.ic_ieee == wif->chanlist[i].ic_ieee &&
1234 		    chan.ic_flags == wif->chanlist[i].ic_flags) {
1235 			wif->desired_channel = i + 1;
1236 			break;
1237 		}
1238 
1239 	return (0);
1240 }
1241 
1242 static int
1243 wlan_config_set_dchannel(struct wlan_iface *wif, uint32_t dchannel)
1244 {
1245 	int val = 0;
1246 	size_t argsize = sizeof(struct ieee80211_channel);
1247 	struct ieee80211_channel chan;
1248 
1249 	if (wlan_get_channel_list(wif) < 0)
1250 		return (-1);
1251 
1252 	if (dchannel > wif->nchannels)
1253 		return (-1);
1254 
1255 	memcpy(&chan, wif->chanlist + dchannel - 1, sizeof(chan));
1256 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_CURCHAN, &val, &chan,
1257 	    &argsize, 1) < 0)
1258 		return (-1);
1259 
1260 	wif->desired_channel = dchannel;
1261 
1262 	return (0);
1263 }
1264 
1265 static int
1266 wlan_config_get_bssid(struct wlan_iface *wif)
1267 {
1268 	int val = 0;
1269 	size_t argsize = IEEE80211_ADDR_LEN;
1270 	char bssid[IEEE80211_ADDR_LEN];
1271 
1272 	memset(bssid, 0, IEEE80211_ADDR_LEN);
1273 
1274 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_BSSID, &val, bssid,
1275 	    &argsize, 0) < 0 || argsize != IEEE80211_ADDR_LEN)
1276 		return (-1);
1277 
1278 	memcpy(wif->desired_bssid, bssid, IEEE80211_ADDR_LEN);
1279 
1280 	return (0);
1281 }
1282 
1283 static int
1284 wlan_config_set_bssid(struct wlan_iface *wif, uint8_t *bssid)
1285 {
1286 	int val = 0;
1287 	size_t argsize = IEEE80211_ADDR_LEN;
1288 
1289 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_BSSID, &val, bssid,
1290 	    &argsize, 1) < 0 || argsize != IEEE80211_ADDR_LEN)
1291 		return (-1);
1292 
1293 	memcpy(wif->desired_bssid, bssid, IEEE80211_ADDR_LEN);
1294 
1295 	return (0);
1296 }
1297 
1298 /*
1299  * Convert the value returned by the kernel to the appropriate SNMP
1300  * representation and set the corresponding interface member accordingly.
1301  */
1302 static void
1303 wlan_config_set_snmp_intval(struct wlan_iface *wif, int op, int val)
1304 {
1305 	switch (op) {
1306 	case IEEE80211_IOC_BURST:
1307 		if (val == 0)
1308 			wif->packet_burst = TruthValue_false;
1309 		else
1310 			wif->packet_burst = TruthValue_true;
1311 		break;
1312 	case IEEE80211_IOC_DFS:
1313 		if (val == 0)
1314 			wif->dyn_frequency = TruthValue_false;
1315 		else
1316 			wif->dyn_frequency = TruthValue_true;
1317 		break;
1318 	case IEEE80211_IOC_FF:
1319 		if (val == 0)
1320 			wif->fast_frames = TruthValue_false;
1321 		else
1322 			wif->fast_frames = TruthValue_true;
1323 		break;
1324 	case IEEE80211_IOC_TURBOP:
1325 		if (val == 0)
1326 			wif->dturbo = TruthValue_false;
1327 		else
1328 			wif->dturbo = TruthValue_true;
1329 		break;
1330 	case IEEE80211_IOC_TXPOWER:
1331 		wif->tx_power = val / 2;
1332 		break;
1333 	case IEEE80211_IOC_FRAGTHRESHOLD:
1334 		wif->frag_threshold = val;
1335 		break;
1336 	case IEEE80211_IOC_RTSTHRESHOLD:
1337 		wif->rts_threshold = val;
1338 		break;
1339 	case IEEE80211_IOC_WPS:
1340 		if (val == 0)
1341 			wif->priv_subscribe = TruthValue_false;
1342 		else
1343 			wif->priv_subscribe = TruthValue_true;
1344 		break;
1345 	case IEEE80211_IOC_BGSCAN:
1346 		if (val == 0)
1347 			wif->bg_scan = TruthValue_false;
1348 		else
1349 			wif->bg_scan = TruthValue_true;
1350 		break;
1351 	case IEEE80211_IOC_BGSCAN_IDLE:
1352 		wif->bg_scan_idle = val;
1353 		break;
1354 	case IEEE80211_IOC_BGSCAN_INTERVAL:
1355 		wif->bg_scan_interval = val;
1356 		break;
1357 	case IEEE80211_IOC_BMISSTHRESHOLD:
1358 		wif->beacons_missed = val;
1359 		break;
1360 	case IEEE80211_IOC_ROAMING:
1361 		switch (val) {
1362 		case IEEE80211_ROAMING_DEVICE:
1363 			wif->roam_mode = wlanIfaceRoamingMode_device;
1364 			break;
1365 		case IEEE80211_ROAMING_MANUAL:
1366 			wif->roam_mode = wlanIfaceRoamingMode_manual;
1367 			break;
1368 		case IEEE80211_ROAMING_AUTO:
1369 			/* FALTHROUGH */
1370 		default:
1371 			wif->roam_mode = wlanIfaceRoamingMode_auto;
1372 			break;
1373 		}
1374 		break;
1375 	case IEEE80211_IOC_DOTD:
1376 		if (val == 0)
1377 			wif->dot11d = TruthValue_false;
1378 		else
1379 			wif->dot11d = TruthValue_true;
1380 		break;
1381 	case IEEE80211_IOC_DOTH:
1382 		if (val == 0)
1383 			wif->dot11h = TruthValue_false;
1384 		else
1385 			wif->dot11h = TruthValue_true;
1386 		break;
1387 	case IEEE80211_IOC_DWDS:
1388 		if (val == 0)
1389 			wif->dynamic_wds = TruthValue_false;
1390 		else
1391 			wif->dynamic_wds = TruthValue_true;
1392 		break;
1393 	case IEEE80211_IOC_POWERSAVE:
1394 		if (val == 0)
1395 			wif->power_save = TruthValue_false;
1396 		else
1397 			wif->power_save = TruthValue_true;
1398 		break;
1399 	case IEEE80211_IOC_APBRIDGE:
1400 		if (val == 0)
1401 			wif->ap_bridge = TruthValue_false;
1402 		else
1403 			wif->ap_bridge = TruthValue_true;
1404 		break;
1405 	case IEEE80211_IOC_BEACON_INTERVAL:
1406 		wif->beacon_interval = val;
1407 		break;
1408 	case IEEE80211_IOC_DTIM_PERIOD:
1409 		wif->dtim_period = val;
1410 		break;
1411 	case IEEE80211_IOC_HIDESSID:
1412 		if (val == 0)
1413 			wif->hide_ssid = TruthValue_false;
1414 		else
1415 			wif->hide_ssid = TruthValue_true;
1416 		break;
1417 	case IEEE80211_IOC_INACTIVITY:
1418 		if (val == 0)
1419 			wif->inact_process = TruthValue_false;
1420 		else
1421 			wif->inact_process = TruthValue_true;
1422 		break;
1423 	case IEEE80211_IOC_PROTMODE:
1424 		switch (val) {
1425 		case IEEE80211_PROTMODE_CTS:
1426 			wif->do11g_protect = wlanIfaceDot11gProtMode_cts;
1427 			break;
1428 		case IEEE80211_PROTMODE_RTSCTS:
1429 			wif->do11g_protect = wlanIfaceDot11gProtMode_rtscts;
1430 			break;
1431 		case IEEE80211_PROTMODE_OFF:
1432 			/* FALLTHROUGH */
1433 		default:
1434 			wif->do11g_protect = wlanIfaceDot11gProtMode_off;
1435 			break;
1436 		}
1437 		break;
1438 	case IEEE80211_IOC_PUREG:
1439 		if (val == 0)
1440 			wif->dot11g_pure = TruthValue_false;
1441 		else
1442 			wif->dot11g_pure = TruthValue_true;
1443 		break;
1444 	case IEEE80211_IOC_PUREN:
1445 		if (val == 0)
1446 			wif->dot11n_pure = TruthValue_false;
1447 		else
1448 			wif->dot11n_pure = TruthValue_true;
1449 		break;
1450 	case IEEE80211_IOC_AMPDU:
1451 		switch (val) {
1452 		case 0:
1453 			wif->ampdu = WlanIfaceDot11nPduType_disabled;
1454 			break;
1455 		case 1:
1456 			wif->ampdu = WlanIfaceDot11nPduType_txOnly;
1457 			break;
1458 		case 2:
1459 			wif->ampdu = WlanIfaceDot11nPduType_rxOnly;
1460 			break;
1461 		case 3:
1462 			/* FALLTHROUGH */
1463 		default:
1464 			wif->ampdu = WlanIfaceDot11nPduType_txAndRx;
1465 			break;
1466 		}
1467 		break;
1468 	case IEEE80211_IOC_AMPDU_DENSITY:
1469 		switch (val) {
1470 		case IEEE80211_HTCAP_MPDUDENSITY_025:
1471 			wif->ampdu_density = 25;
1472 			break;
1473 		case IEEE80211_HTCAP_MPDUDENSITY_05:
1474 			wif->ampdu_density = 50;
1475 			break;
1476 		case IEEE80211_HTCAP_MPDUDENSITY_1:
1477 			wif->ampdu_density = 100;
1478 			break;
1479 		case IEEE80211_HTCAP_MPDUDENSITY_2:
1480 			wif->ampdu_density = 200;
1481 			break;
1482 		case IEEE80211_HTCAP_MPDUDENSITY_4:
1483 			wif->ampdu_density = 400;
1484 			break;
1485 		case IEEE80211_HTCAP_MPDUDENSITY_8:
1486 			wif->ampdu_density = 800;
1487 			break;
1488 		case IEEE80211_HTCAP_MPDUDENSITY_16:
1489 			wif->ampdu_density = 1600;
1490 			break;
1491 		case IEEE80211_HTCAP_MPDUDENSITY_NA:
1492 		default:
1493 			wif->ampdu_density = 0;
1494 			break;
1495 		}
1496 		break;
1497 	case IEEE80211_IOC_AMPDU_LIMIT:
1498 		switch (val) {
1499 		case IEEE80211_HTCAP_MAXRXAMPDU_8K:
1500 			wif->ampdu_limit = 8192;
1501 			break;
1502 		case IEEE80211_HTCAP_MAXRXAMPDU_16K:
1503 			wif->ampdu_limit = 16384;
1504 			break;
1505 		case IEEE80211_HTCAP_MAXRXAMPDU_32K:
1506 			wif->ampdu_limit = 32768;
1507 			break;
1508 		case IEEE80211_HTCAP_MAXRXAMPDU_64K:
1509 		default:
1510 			wif->ampdu_limit = 65536;
1511 			break;
1512 		}
1513 		break;
1514 	case IEEE80211_IOC_AMSDU:
1515 		switch (val) {
1516 		case 0:
1517 			wif->amsdu = WlanIfaceDot11nPduType_disabled;
1518 			break;
1519 		case 1:
1520 			wif->amsdu = WlanIfaceDot11nPduType_txOnly;
1521 			break;
1522 		case 3:
1523 			wif->amsdu = WlanIfaceDot11nPduType_txAndRx;
1524 			break;
1525 		case 2:
1526 		default:
1527 			/* FALLTHROUGH */
1528 			wif->amsdu = WlanIfaceDot11nPduType_rxOnly;
1529 			break;
1530 		}
1531 		break;
1532 	case IEEE80211_IOC_AMSDU_LIMIT:
1533 		wif->amsdu_limit = val;
1534 		break;
1535 	case IEEE80211_IOC_HTCONF:
1536 		if (val == 0) /* XXX */
1537 			wif->ht_enabled = TruthValue_false;
1538 		else
1539 			wif->ht_enabled = TruthValue_true;
1540 		break;
1541 	case IEEE80211_IOC_HTCOMPAT:
1542 		if (val == 0)
1543 			wif->ht_compatible = TruthValue_false;
1544 		else
1545 			wif->ht_compatible = TruthValue_true;
1546 		break;
1547 	case IEEE80211_IOC_HTPROTMODE:
1548 		if (val == IEEE80211_PROTMODE_RTSCTS)
1549 			wif->ht_prot_mode = wlanIfaceDot11nHTProtMode_rts;
1550 		else
1551 			wif->ht_prot_mode = wlanIfaceDot11nHTProtMode_off;
1552 		break;
1553 	case IEEE80211_IOC_RIFS:
1554 		if (val == 0)
1555 			wif->rifs = TruthValue_false;
1556 		else
1557 			wif->rifs = TruthValue_true;
1558 		break;
1559 	case IEEE80211_IOC_SHORTGI:
1560 		if (val == 0)
1561 			wif->short_gi = TruthValue_false;
1562 		else
1563 			wif->short_gi = TruthValue_true;
1564 		break;
1565 	case IEEE80211_IOC_SMPS:
1566 		switch (val) {
1567 		case IEEE80211_HTCAP_SMPS_DYNAMIC:
1568 			wif->smps_mode = wlanIfaceDot11nSMPSMode_dynamic;
1569 			break;
1570 		case IEEE80211_HTCAP_SMPS_ENA:
1571 			wif->smps_mode = wlanIfaceDot11nSMPSMode_static;
1572 			break;
1573 		case IEEE80211_HTCAP_SMPS_OFF:
1574 			/* FALLTHROUGH */
1575 		default:
1576 			wif->smps_mode = wlanIfaceDot11nSMPSMode_disabled;
1577 			break;
1578 		}
1579 		break;
1580 	case IEEE80211_IOC_TDMA_SLOT:
1581 		wif->tdma_slot = val;
1582 		break;
1583 	case IEEE80211_IOC_TDMA_SLOTCNT:
1584 		wif->tdma_slot_count = val;
1585 		break;
1586 	case IEEE80211_IOC_TDMA_SLOTLEN:
1587 		wif->tdma_slot_length = val;
1588 		break;
1589 	case IEEE80211_IOC_TDMA_BINTERVAL:
1590 		wif->tdma_binterval = val;
1591 		break;
1592 	default:
1593 		break;
1594 	}
1595 }
1596 
1597 /*
1598  * Convert an SNMP value to the kernel equivalent and also do sanity check
1599  * for each specific type.
1600  */
1601 static int
1602 wlan_config_snmp2value(int which, int sval, int *value)
1603 {
1604 	*value = 0;
1605 
1606 	switch (which) {
1607 	case IEEE80211_IOC_BURST:
1608 	case IEEE80211_IOC_DFS:
1609 	case IEEE80211_IOC_FF:
1610 	case IEEE80211_IOC_TURBOP:
1611 	case IEEE80211_IOC_WPS:
1612 	case IEEE80211_IOC_BGSCAN:
1613 	case IEEE80211_IOC_DOTD:
1614 	case IEEE80211_IOC_DOTH:
1615 	case IEEE80211_IOC_DWDS:
1616 	case IEEE80211_IOC_POWERSAVE:
1617 	case IEEE80211_IOC_APBRIDGE:
1618 	case IEEE80211_IOC_HIDESSID:
1619 	case IEEE80211_IOC_INACTIVITY:
1620 	case IEEE80211_IOC_PUREG:
1621 	case IEEE80211_IOC_PUREN:
1622 	case IEEE80211_IOC_HTCONF:
1623 	case IEEE80211_IOC_HTCOMPAT:
1624 	case IEEE80211_IOC_RIFS:
1625 		if (sval == TruthValue_true)
1626 			*value = 1;
1627 		else if (sval != TruthValue_false)
1628 			return (SNMP_ERR_INCONS_VALUE);
1629 		break;
1630 	case IEEE80211_IOC_REGDOMAIN:
1631 		break;
1632 	case IEEE80211_IOC_SSID:
1633 		break;
1634 	case IEEE80211_IOC_CURCHAN:
1635 		break;
1636 	case IEEE80211_IOC_TXPOWER:
1637 		*value = sval * 2;
1638 		break;
1639 	case IEEE80211_IOC_FRAGTHRESHOLD:
1640 		if (sval < IEEE80211_FRAG_MIN || sval > IEEE80211_FRAG_MAX)
1641 			return (SNMP_ERR_INCONS_VALUE);
1642 		*value = sval;
1643 		break;
1644 	case IEEE80211_IOC_RTSTHRESHOLD:
1645 		if (sval < IEEE80211_RTS_MIN || sval > IEEE80211_RTS_MAX)
1646 			return (SNMP_ERR_INCONS_VALUE);
1647 		*value = sval;
1648 		break;
1649 	case IEEE80211_IOC_BGSCAN_IDLE:
1650 		if (sval < WLAN_BGSCAN_IDLE_MIN)
1651 			return (SNMP_ERR_INCONS_VALUE);
1652 		*value = sval;
1653 		break;
1654 	case IEEE80211_IOC_BGSCAN_INTERVAL:
1655 		if (sval < WLAN_SCAN_VALID_MIN)
1656 			return (SNMP_ERR_INCONS_VALUE);
1657 		*value = sval;
1658 		break;
1659 	case IEEE80211_IOC_BMISSTHRESHOLD:
1660 		if (sval < IEEE80211_HWBMISS_MIN || sval > IEEE80211_HWBMISS_MAX)
1661 			return (SNMP_ERR_INCONS_VALUE);
1662 		*value = sval;
1663 		break;
1664 	case IEEE80211_IOC_BSSID:
1665 		break;
1666 	case IEEE80211_IOC_ROAMING:
1667 		switch (sval) {
1668 		case wlanIfaceRoamingMode_device:
1669 			*value = IEEE80211_ROAMING_DEVICE;
1670 			break;
1671 		case wlanIfaceRoamingMode_manual:
1672 			*value = IEEE80211_ROAMING_MANUAL;
1673 			break;
1674 		case wlanIfaceRoamingMode_auto:
1675 			*value = IEEE80211_ROAMING_AUTO;
1676 			break;
1677 		default:
1678 			return (SNMP_ERR_INCONS_VALUE);
1679 		}
1680 		break;
1681 	case IEEE80211_IOC_BEACON_INTERVAL:
1682 		if (sval < IEEE80211_BINTVAL_MIN || sval > IEEE80211_BINTVAL_MAX)
1683 			return (SNMP_ERR_INCONS_VALUE);
1684 		*value = sval;
1685 		break;
1686 	case IEEE80211_IOC_DTIM_PERIOD:
1687 		if (sval < IEEE80211_DTIM_MIN || sval > IEEE80211_DTIM_MAX)
1688 			return (SNMP_ERR_INCONS_VALUE);
1689 		*value = sval;
1690 		break;
1691 	case IEEE80211_IOC_PROTMODE:
1692 		switch (sval) {
1693 		case wlanIfaceDot11gProtMode_cts:
1694 			*value = IEEE80211_PROTMODE_CTS;
1695 			break;
1696 		case wlanIfaceDot11gProtMode_rtscts:
1697 			*value = IEEE80211_PROTMODE_RTSCTS;
1698 			break;
1699 		case wlanIfaceDot11gProtMode_off:
1700 			*value = IEEE80211_PROTMODE_OFF;
1701 			break;
1702 		default:
1703 			return (SNMP_ERR_INCONS_VALUE);
1704 		}
1705 		break;
1706 	case IEEE80211_IOC_AMPDU:
1707 		switch (sval) {
1708 		case WlanIfaceDot11nPduType_disabled:
1709 			break;
1710 		case WlanIfaceDot11nPduType_txOnly:
1711 			*value = 1;
1712 			break;
1713 		case WlanIfaceDot11nPduType_rxOnly:
1714 			*value = 2;
1715 			break;
1716 		case WlanIfaceDot11nPduType_txAndRx:
1717 			*value = 3;
1718 			break;
1719 		default:
1720 			return (SNMP_ERR_INCONS_VALUE);
1721 		}
1722 		break;
1723 	case IEEE80211_IOC_AMPDU_DENSITY:
1724 		switch (sval) {
1725 		case 0:
1726 			*value = IEEE80211_HTCAP_MPDUDENSITY_NA;
1727 			break;
1728 		case 25:
1729 			*value = IEEE80211_HTCAP_MPDUDENSITY_025;
1730 			break;
1731 		case 50:
1732 			*value = IEEE80211_HTCAP_MPDUDENSITY_05;
1733 			break;
1734 		case 100:
1735 			*value = IEEE80211_HTCAP_MPDUDENSITY_1;
1736 			break;
1737 		case 200:
1738 			*value = IEEE80211_HTCAP_MPDUDENSITY_2;
1739 			break;
1740 		case 400:
1741 			*value = IEEE80211_HTCAP_MPDUDENSITY_4;
1742 			break;
1743 		case 800:
1744 			*value = IEEE80211_HTCAP_MPDUDENSITY_8;
1745 			break;
1746 		case 1600:
1747 			*value = IEEE80211_HTCAP_MPDUDENSITY_16;
1748 			break;
1749 		default:
1750 			return (SNMP_ERR_INCONS_VALUE);
1751 		}
1752 		break;
1753 	case IEEE80211_IOC_AMPDU_LIMIT:
1754 		switch (sval) {
1755 		case 8192:
1756 			*value = IEEE80211_HTCAP_MAXRXAMPDU_8K;
1757 			break;
1758 		case 16384:
1759 			*value = IEEE80211_HTCAP_MAXRXAMPDU_16K;
1760 			break;
1761 		case 32768:
1762 			*value = IEEE80211_HTCAP_MAXRXAMPDU_32K;
1763 			break;
1764 		case 65536:
1765 			*value = IEEE80211_HTCAP_MAXRXAMPDU_64K;
1766 			break;
1767 		default:
1768 			return (SNMP_ERR_INCONS_VALUE);
1769 		}
1770 		break;
1771 	case IEEE80211_IOC_AMSDU:
1772 		switch (sval) {
1773 		case WlanIfaceDot11nPduType_disabled:
1774 			break;
1775 		case WlanIfaceDot11nPduType_txOnly:
1776 			*value = 1;
1777 			break;
1778 		case WlanIfaceDot11nPduType_rxOnly:
1779 			*value = 2;
1780 			break;
1781 		case WlanIfaceDot11nPduType_txAndRx:
1782 			*value = 3;
1783 			break;
1784 		default:
1785 			return (SNMP_ERR_INCONS_VALUE);
1786 		}
1787 		break;
1788 	case IEEE80211_IOC_AMSDU_LIMIT:
1789 		if (sval == 3839 || sval == 0)
1790 			*value = IEEE80211_HTCAP_MAXAMSDU_3839;
1791 		else if (sval == 7935)
1792 			*value = IEEE80211_HTCAP_MAXAMSDU_7935;
1793 		else
1794 			return (SNMP_ERR_INCONS_VALUE);
1795 		break;
1796 	case IEEE80211_IOC_HTPROTMODE:
1797 		switch (sval) {
1798 		case wlanIfaceDot11nHTProtMode_rts:
1799 			*value = IEEE80211_PROTMODE_RTSCTS;
1800 			break;
1801 		case wlanIfaceDot11nHTProtMode_off:
1802 			break;
1803 		default:
1804 			return (SNMP_ERR_INCONS_VALUE);
1805 		}
1806 		break;
1807 	case IEEE80211_IOC_SHORTGI:
1808 		if (sval == TruthValue_true)
1809 			*value = IEEE80211_HTCAP_SHORTGI20 |
1810 			    IEEE80211_HTCAP_SHORTGI40;
1811 		else if (sval != TruthValue_false)
1812 			return (SNMP_ERR_INCONS_VALUE);
1813 		break;
1814 	case IEEE80211_IOC_SMPS:
1815 		switch (sval) {
1816 		case wlanIfaceDot11nSMPSMode_disabled:
1817 			*value = IEEE80211_HTCAP_SMPS_OFF;
1818 			break;
1819 		case wlanIfaceDot11nSMPSMode_static:
1820 			*value = IEEE80211_HTCAP_SMPS_ENA;
1821 			break;
1822 		case wlanIfaceDot11nSMPSMode_dynamic:
1823 			*value = IEEE80211_HTCAP_SMPS_DYNAMIC;
1824 			break;
1825 		default:
1826 			return (SNMP_ERR_INCONS_VALUE);
1827 		}
1828 		break;
1829 	case IEEE80211_IOC_TDMA_SLOT:
1830 		if (sval < 0 || sval > WLAN_TDMA_MAXSLOTS) /* XXX */
1831 			return (SNMP_ERR_INCONS_VALUE);
1832 		*value = sval;
1833 		break;
1834 	case IEEE80211_IOC_TDMA_SLOTCNT:
1835 		if (sval < 0 || sval > WLAN_TDMA_MAXSLOTS) /* XXX */
1836 			return (SNMP_ERR_INCONS_VALUE);
1837 		*value = sval;
1838 		break;
1839 	case IEEE80211_IOC_TDMA_SLOTLEN:
1840 		if (sval < 2*100 || sval > 0xfffff) /* XXX */
1841 			return (SNMP_ERR_INCONS_VALUE);
1842 		*value = sval;
1843 		break;
1844 	case IEEE80211_IOC_TDMA_BINTERVAL:
1845 		if (sval < 1) /* XXX */
1846 			return (SNMP_ERR_INCONS_VALUE);
1847 		*value = sval;
1848 		break;
1849 	default:
1850 		return (SNMP_ERR_INCONS_VALUE);
1851 	}
1852 
1853 	return (SNMP_ERR_NOERROR);
1854 }
1855 
1856 /*
1857  * Sanity checks for the wlanIfaceConfigTable.
1858  */
1859 static int
1860 wlan_config_check(struct wlan_iface *wif, int op)
1861 {
1862 	switch (op) {
1863 	case IEEE80211_IOC_BURST:
1864 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_burst)) == 0) {
1865 			wif->packet_burst = TruthValue_false;
1866 			return (-1);
1867 		}
1868 		break;
1869 	case IEEE80211_IOC_DFS:
1870 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_dfs)) == 0) {
1871 			wif->dyn_frequency = TruthValue_false;
1872 			return (-1);
1873 		}
1874 		break;
1875 	case IEEE80211_IOC_FF:
1876 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_athFastFrames))
1877 		    == 0) {
1878 			wif->fast_frames = TruthValue_false;
1879 			return (-1);
1880 		}
1881 		break;
1882 	case IEEE80211_IOC_TURBOP:
1883 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_athTurbo)) == 0) {
1884 			wif->dturbo = TruthValue_false;
1885 			return (-1);
1886 		}
1887 		break;
1888 	case IEEE80211_IOC_TXPOWER:
1889 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_txPmgt)) == 0) {
1890 			wif->tx_power = 0;
1891 			return (-1);
1892 		}
1893 		break;
1894 	case IEEE80211_IOC_FRAGTHRESHOLD:
1895 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_txFrag)) == 0) {
1896 			wif->frag_threshold = IEEE80211_FRAG_MAX;
1897 			return (-1);
1898 		}
1899 		break;
1900 	case IEEE80211_IOC_DWDS:
1901 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_wds)) == 0) {
1902 			wif->dynamic_wds = TruthValue_false;
1903 			return (-1);
1904 		}
1905 		break;
1906 	case IEEE80211_IOC_POWERSAVE:
1907 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_pmgt)) == 0) {
1908 			wif->power_save = TruthValue_false;
1909 			return (-1);
1910 		}
1911 		break;
1912 	case IEEE80211_IOC_BEACON_INTERVAL:
1913 		if (wif->mode != WlanIfaceOperatingModeType_hostAp &&
1914 		    wif->mode != WlanIfaceOperatingModeType_meshPoint &&
1915 		    wif->mode != WlanIfaceOperatingModeType_ibss) {
1916 			wif->beacon_interval = 100; /* XXX */
1917 			return (-1);
1918 		}
1919 		break;
1920 	case IEEE80211_IOC_DTIM_PERIOD:
1921 		if (wif->mode != WlanIfaceOperatingModeType_hostAp &&
1922 		    wif->mode != WlanIfaceOperatingModeType_meshPoint &&
1923 		    wif->mode != WlanIfaceOperatingModeType_ibss) {
1924 			wif->dtim_period = 1; /* XXX */
1925 			return (-1);
1926 		}
1927 		break;
1928 	case IEEE80211_IOC_PUREN:
1929 		if ((wif->htcaps & (0x1 << WlanHTCaps_htcHt)) == 0) {
1930 			wif->dot11n_pure = TruthValue_false;
1931 			return (-1);
1932 		}
1933 		break;
1934 	case IEEE80211_IOC_AMPDU:
1935 		if ((wif->htcaps & (0x1 << WlanHTCaps_htcAmpdu)) == 0) {
1936 			wif->ampdu = WlanIfaceDot11nPduType_disabled;
1937 			return (-1);
1938 		}
1939 		break;
1940 	case IEEE80211_IOC_AMSDU:
1941 		if ((wif->htcaps & (0x1 << WlanHTCaps_htcAmsdu)) == 0) {
1942 			wif->amsdu = WlanIfaceDot11nPduType_disabled;
1943 			return (-1);
1944 		}
1945 		break;
1946 	case IEEE80211_IOC_RIFS:
1947 		if ((wif->htcaps & (0x1 << WlanHTCaps_htcRifs)) == 0) {
1948 			wif->rifs = TruthValue_false;
1949 			return (-1);
1950 		}
1951 		break;
1952 	case IEEE80211_IOC_SHORTGI:
1953 		if ((wif->htcaps & (0x1 << WlanHTCaps_shortGi20 |
1954 		    0x1 << WlanHTCaps_shortGi40)) == 0) {
1955 			wif->short_gi = TruthValue_false;
1956 			return (-1);
1957 		}
1958 		break;
1959 	case IEEE80211_IOC_SMPS:
1960 		if ((wif->htcaps & (0x1 << WlanHTCaps_htcSmps)) == 0) {
1961 			wif->smps_mode = wlanIfaceDot11nSMPSMode_disabled;
1962 			return (-1);
1963 		}
1964 		break;
1965 	case IEEE80211_IOC_TDMA_SLOT:
1966 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) {
1967 			wif->tdma_slot = 0;
1968 			return (-1);
1969 		}
1970 		break;
1971 	case IEEE80211_IOC_TDMA_SLOTCNT:
1972 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) {
1973 			wif->tdma_slot_count = 0;
1974 			return (-1);
1975 		}
1976 		break;
1977 	case IEEE80211_IOC_TDMA_SLOTLEN:
1978 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) {
1979 			wif->tdma_slot_length = 0;
1980 			return (-1);
1981 		}
1982 		break;
1983 	case IEEE80211_IOC_TDMA_BINTERVAL:
1984 		if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) {
1985 			wif->tdma_binterval = 0;
1986 			return (-1);
1987 		}
1988 		break;
1989 	default:
1990 		break;
1991 	}
1992 
1993 	return (0);
1994 }
1995 
1996 static int
1997 wlan_config_get_intval(struct wlan_iface *wif, int op)
1998 {
1999 	int val = 0;
2000 	size_t argsize = 0;
2001 
2002 	if (wlan_config_check(wif, op) < 0)
2003 		return (0);
2004 	if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 0) < 0)
2005 		return (-1);
2006 	wlan_config_set_snmp_intval(wif, op, val);
2007 
2008 	return (0);
2009 }
2010 
2011 static int
2012 wlan_config_set_intval(struct wlan_iface *wif, int op, int sval)
2013 {
2014 	size_t argsize = 0;
2015 	int val;
2016 
2017 	if (wlan_config_check(wif, op) < 0)
2018 		return (-1);
2019 	if (wlan_config_snmp2value(op, sval, &val) != SNMP_ERR_NOERROR)
2020 		return (-1);
2021 	if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 1) < 0)
2022 		return (-1);
2023 	wlan_config_set_snmp_intval(wif, op, val);
2024 
2025 	return (0);
2026 }
2027 
2028 int
2029 wlan_config_get_ioctl(struct wlan_iface *wif, int which)
2030 {
2031 	int op;
2032 
2033 	switch (which) {
2034 		case LEAF_wlanIfaceCountryCode:
2035 			/* FALLTHROUGH */
2036 		case LEAF_wlanIfaceRegDomain:
2037 			return (wlan_config_get_country(wif));
2038 		case LEAF_wlanIfaceDesiredSsid:
2039 			return (wlan_config_get_dssid(wif));
2040 		case LEAF_wlanIfaceDesiredChannel:
2041 			return (wlan_config_get_dchannel(wif));
2042 		case LEAF_wlanIfaceDesiredBssid:
2043 			return (wlan_config_get_bssid(wif));
2044 		default:
2045 			op = wlan_config_snmp2ioctl(which);
2046 			return (wlan_config_get_intval(wif, op));
2047 	}
2048 
2049 	return (-1);
2050 }
2051 
2052 int
2053 wlan_config_set_ioctl(struct wlan_iface *wif, int which, int val,
2054     char *strval, int len)
2055 {
2056 	int op;
2057 
2058 	switch (which) {
2059 		case LEAF_wlanIfaceCountryCode:
2060 			return (wlan_config_set_country(wif, strval,
2061 			    wif->reg_domain));
2062 		case LEAF_wlanIfaceRegDomain:
2063 			return (wlan_config_set_country(wif, wif->country_code,
2064 			    val));
2065 		case LEAF_wlanIfaceDesiredSsid:
2066 			return (wlan_config_set_dssid(wif, strval, len));
2067 		case LEAF_wlanIfaceDesiredChannel:
2068 			return (wlan_config_set_dchannel(wif, val));
2069 		case LEAF_wlanIfaceDesiredBssid:
2070 			return (wlan_config_set_bssid(wif, strval));
2071 		default:
2072 			op = wlan_config_snmp2ioctl(which);
2073 			return (wlan_config_set_intval(wif, op, val));
2074 	}
2075 
2076 	return (-1);
2077 }
2078 
2079 static uint32_t
2080 wlan_snmp_to_scan_flags(int flags)
2081 {
2082 	int sr_flags = 0;
2083 
2084 	if ((flags & (0x1 << WlanScanFlagsType_noSelection)) != 0)
2085 		sr_flags |= IEEE80211_IOC_SCAN_NOPICK;
2086 	if ((flags & (0x1 << WlanScanFlagsType_activeScan)) != 0)
2087 		sr_flags |= IEEE80211_IOC_SCAN_ACTIVE;
2088 	if ((flags & (0x1 << WlanScanFlagsType_pickFirst)) != 0)
2089 		sr_flags |= IEEE80211_IOC_SCAN_PICK1ST;
2090 	if ((flags & (0x1 << WlanScanFlagsType_backgroundScan)) != 0)
2091 		sr_flags |= IEEE80211_IOC_SCAN_BGSCAN;
2092 	if ((flags & (0x1 << WlanScanFlagsType_once)) != 0)
2093 		sr_flags |= IEEE80211_IOC_SCAN_ONCE;
2094 	if ((flags & (0x1 << WlanScanFlagsType_noBroadcast)) != 0)
2095 		sr_flags |= IEEE80211_IOC_SCAN_NOBCAST;
2096 	if ((flags & (0x1 << WlanScanFlagsType_noAutoSequencing)) != 0)
2097 		sr_flags |= IEEE80211_IOC_SCAN_NOJOIN;
2098 	if ((flags & (0x1 << WlanScanFlagsType_flushCashe)) != 0)
2099 		sr_flags |= IEEE80211_IOC_SCAN_FLUSH;
2100 	if ((flags & (0x1 << WlanScanFlagsType_chechCashe)) != 0)
2101 		sr_flags |= IEEE80211_IOC_SCAN_CHECK;
2102 
2103 	return (sr_flags);
2104 }
2105 
2106 int
2107 wlan_set_scan_config(struct wlan_iface *wif)
2108 {
2109 	int val = 0;
2110 	size_t argsize;
2111 	struct ieee80211_scan_req sr;
2112 
2113 
2114 	memset(&sr, 0, sizeof(sr));
2115 	argsize = sizeof(struct ieee80211_scan_req);
2116 	sr.sr_flags = wlan_snmp_to_scan_flags(wif->scan_flags);
2117 	sr.sr_flags |= IEEE80211_IOC_SCAN_BGSCAN;
2118 	sr.sr_duration = wif->scan_duration;
2119 	sr.sr_mindwell = wif->scan_mindwell;
2120 	sr.sr_maxdwell = wif->scan_maxdwell;
2121 	sr.sr_nssid = 0;
2122 
2123 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_SCAN_REQ,
2124 	    &val, &sr, &argsize, 1) < 0)
2125 		return (-1);
2126 
2127 	wif->scan_status = wlanScanConfigStatus_running;
2128 	return (0);
2129 }
2130 
2131 static uint32_t
2132 wlan_peercaps_to_snmp(uint32_t pcaps)
2133 {
2134 	uint32_t scaps = 0;
2135 
2136 	if ((pcaps & IEEE80211_CAPINFO_ESS) != 0)
2137 		scaps |= (0x1 << WlanPeerCapabilityFlags_ess);
2138 	if ((pcaps & IEEE80211_CAPINFO_IBSS) != 0)
2139 		scaps |= (0x1 << WlanPeerCapabilityFlags_ibss);
2140 	if ((pcaps & IEEE80211_CAPINFO_CF_POLLABLE) != 0)
2141 		scaps |= (0x1 << WlanPeerCapabilityFlags_cfPollable);
2142 	if ((pcaps & IEEE80211_CAPINFO_CF_POLLREQ) != 0)
2143 		scaps |= (0x1 << WlanPeerCapabilityFlags_cfPollRequest);
2144 	if ((pcaps & IEEE80211_CAPINFO_PRIVACY) != 0)
2145 		scaps |= (0x1 << WlanPeerCapabilityFlags_privacy);
2146 	if ((pcaps & IEEE80211_CAPINFO_SHORT_PREAMBLE) != 0)
2147 		scaps |= (0x1 << WlanPeerCapabilityFlags_shortPreamble);
2148 	if ((pcaps & IEEE80211_CAPINFO_PBCC) != 0)
2149 		scaps |= (0x1 << WlanPeerCapabilityFlags_pbcc);
2150 	if ((pcaps & IEEE80211_CAPINFO_CHNL_AGILITY) != 0)
2151 		scaps |= (0x1 << WlanPeerCapabilityFlags_channelAgility);
2152 	if ((pcaps & IEEE80211_CAPINFO_SHORT_SLOTTIME) != 0)
2153 		scaps |= (0x1 << WlanPeerCapabilityFlags_shortSlotTime);
2154 	if ((pcaps & IEEE80211_CAPINFO_RSN) != 0)
2155 		scaps |= (0x1 << WlanPeerCapabilityFlags_rsn);
2156 	if ((pcaps & IEEE80211_CAPINFO_DSSSOFDM) != 0)
2157 		scaps |= (0x1 << WlanPeerCapabilityFlags_dsssofdm);
2158 
2159 	return (scaps);
2160 }
2161 
2162 static int
2163 wlan_add_new_scan_result(struct wlan_iface *wif,
2164     const struct ieee80211req_scan_result *isr, uint8_t *ssid)
2165 {
2166 	struct wlan_scan_result *sr;
2167 
2168 	if ((sr = wlan_scan_new_result(ssid, isr->isr_bssid)) == NULL)
2169 		return (-1);
2170 
2171 	sr->opchannel = wlan_channel_flags_to_snmp_phy(isr->isr_flags);
2172 	sr->rssi = isr->isr_rssi;
2173 	sr->frequency = isr->isr_freq;
2174 	sr->noise = isr->isr_noise;
2175 	sr->bintval = isr->isr_intval;
2176 	sr->capinfo = wlan_peercaps_to_snmp(isr->isr_capinfo);
2177 
2178 	if (wlan_scan_add_result(wif, sr) < 0) {
2179 		wlan_scan_free_result(sr);
2180 		return (-1);
2181 	}
2182 
2183 	return (0);
2184 }
2185 
2186 int
2187 wlan_get_scan_results(struct wlan_iface *wif)
2188 {
2189 	int ssidlen, val = 0;
2190 	uint8_t buf[24 * 1024];
2191 	size_t argsize;
2192 	const uint8_t *cp, *idp;
2193 	uint8_t ssid[IEEE80211_NWID_LEN + 1];
2194 	struct ieee80211req_scan_result isr;
2195 
2196 	argsize = sizeof(buf);
2197 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_SCAN_RESULTS, &val, &buf,
2198 	    &argsize, 0) < 0)
2199 		return (-1);
2200 
2201 	if (argsize < sizeof(struct ieee80211req_scan_result))
2202 		return (0);
2203 
2204 	cp = buf;
2205 	do {
2206 		memcpy(&isr, cp, sizeof(struct ieee80211req_scan_result));
2207 		memset(ssid, 0, IEEE80211_NWID_LEN + 1);
2208 
2209 		if (isr.isr_meshid_len) {
2210 			idp = cp + isr.isr_ie_off + isr.isr_ssid_len;
2211 			ssidlen = isr.isr_meshid_len;
2212 		} else {
2213 			idp = cp + isr.isr_ie_off;
2214 			ssidlen = isr.isr_ssid_len;
2215 		}
2216 		if (ssidlen > IEEE80211_NWID_LEN)
2217 			ssidlen = IEEE80211_NWID_LEN;
2218 		memcpy(ssid, idp, ssidlen);
2219 		ssid[IEEE80211_NWID_LEN] = '\0';
2220 		(void)wlan_add_new_scan_result(wif, &isr, ssid);
2221 		cp += isr.isr_len;
2222 		argsize -= isr.isr_len;
2223 	} while (argsize >= sizeof(struct ieee80211req_scan_result));
2224 
2225 	return (0);
2226 }
2227 
2228 int
2229 wlan_get_stats(struct wlan_iface *wif)
2230 {
2231 	struct ifreq ifr;
2232 
2233 	memset(&ifr, 0, sizeof(struct ifreq));
2234 	strlcpy(ifr.ifr_name, wif->wname, IFNAMSIZ);
2235 
2236 	ifr.ifr_data = (caddr_t) &wif->stats;
2237 
2238 	if (ioctl(sock, SIOCG80211STATS, &ifr) < 0) {
2239 		syslog(LOG_ERR, "iface %s - ioctl(SIOCG80211STATS) failed: %s",
2240 		    wif->wname, strerror(errno));
2241 		return (-1);
2242 	}
2243 
2244 	return (0);
2245 }
2246 
2247 int
2248 wlan_get_wepmode(struct wlan_iface *wif)
2249 {
2250 	int val = 0;
2251 	size_t argsize = 0;
2252 
2253 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEP, &val, NULL,
2254 	    &argsize, 0) < 0 || val == IEEE80211_WEP_NOSUP) {
2255 		wif->wepsupported = 0; /* XXX */
2256 		wif->wepmode = wlanWepMode_off;
2257 		wif->weptxkey = 0;
2258 		return (-1);
2259 	}
2260 
2261 	wif->wepsupported = 1;
2262 
2263 	switch (val) {
2264 	case IEEE80211_WEP_ON:
2265 		wif->wepmode = wlanWepMode_on;
2266 		break;
2267 	case IEEE80211_WEP_MIXED:
2268 		wif->wepmode = wlanWepMode_mixed;
2269 		break;
2270 	case IEEE80211_WEP_OFF:
2271 		/* FALLTHROUGH */
2272 	default:
2273 		wif->wepmode = wlanWepMode_off;
2274 		break;
2275 	}
2276 
2277 	return (0);
2278 }
2279 
2280 int
2281 wlan_set_wepmode(struct wlan_iface *wif)
2282 {
2283 	int val;
2284 	size_t argsize = 0;
2285 
2286 	if (!wif->wepsupported)
2287 		return (-1);
2288 
2289 	switch (wif->wepmode) {
2290 	case wlanWepMode_off:
2291 		val = IEEE80211_WEP_OFF;
2292 		break;
2293 	case wlanWepMode_on:
2294 		val = IEEE80211_WEP_ON;
2295 		break;
2296 	case wlanWepMode_mixed:
2297 		val = IEEE80211_WEP_MIXED;
2298 		break;
2299 	default:
2300 		return (-1);
2301 	}
2302 
2303 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEP, &val, NULL,
2304 	    &argsize, 1) < 0)
2305 		return (-1);
2306 
2307 	return (0);
2308 }
2309 
2310 int
2311 wlan_get_weptxkey(struct wlan_iface *wif)
2312 {
2313 	int val;
2314 	size_t argsize = 0;
2315 
2316 	if (!wif->wepsupported)
2317 		return (0);
2318 
2319 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEPTXKEY, &val, NULL,
2320 	    &argsize, 0) < 0)
2321 		return (-1);
2322 
2323 	if (val == IEEE80211_KEYIX_NONE)
2324 		wif->weptxkey = 0;
2325 	else
2326 		wif->weptxkey = val + 1;
2327 
2328 	return (0);
2329 }
2330 
2331 int
2332 wlan_set_weptxkey(struct wlan_iface *wif)
2333 {
2334 	int val;
2335 	size_t argsize = 0;
2336 
2337 	if (!wif->wepsupported)
2338 		return (0);
2339 
2340 	if (wif->weptxkey >= IEEE80211_WEP_NKID)
2341 		return (-1);
2342 
2343 	if (wif->weptxkey == 0)
2344 		val = IEEE80211_KEYIX_NONE;
2345 	else
2346 		val = wif->weptxkey - 1;
2347 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEPTXKEY, &val, NULL,
2348 	    &argsize, 1) < 0)
2349 		return (-1);
2350 
2351 	return (0);
2352 }
2353 
2354 int
2355 wlan_get_wepkeys(struct wlan_iface *wif __unused)
2356 {
2357 	/* XXX: should they be visible via SNMP */
2358 	return (0);
2359 }
2360 
2361 int
2362 wlan_set_wepkeys(struct wlan_iface *wif __unused)
2363 {
2364 	/* XXX: should they be configurable via SNMP */
2365 	return (0);
2366 }
2367 
2368 int
2369 wlan_get_mac_policy(struct wlan_iface *wif)
2370 {
2371 	int val = IEEE80211_MACCMD_POLICY;
2372 	size_t argsize = 0;
2373 	struct ieee80211req ireq;
2374 
2375 	memset(&ireq, 0, sizeof(struct ieee80211req));
2376 	strlcpy(ireq.i_name, wif->wname, IFNAMSIZ);
2377 	ireq.i_type = IEEE80211_IOC_MACCMD;
2378 	ireq.i_val = IEEE80211_MACCMD_POLICY;
2379 
2380 	if (ioctl(sock, SIOCG80211, &ireq) < 0) {
2381 		if (errno != EINVAL) {
2382 			syslog(LOG_ERR, "iface %s - get param: ioctl(%d) "
2383 			    "failed: %s", wif->wname, ireq.i_type,
2384 			    strerror(errno));
2385 			wif->macsupported = 0;
2386 			return (-1);
2387 		} else {
2388 			wif->macsupported = 1;
2389 			wif->mac_policy = wlanMACAccessControlPolicy_open;
2390 			return (0);
2391 		}
2392 
2393 	}
2394 
2395 	wif->macsupported = 1;
2396 
2397 	switch (val) {
2398 	case IEEE80211_MACCMD_POLICY_ALLOW:
2399 		wif->mac_policy = wlanMACAccessControlPolicy_allow;
2400 		break;
2401 	case IEEE80211_MACCMD_POLICY_DENY:
2402 		wif->mac_policy = wlanMACAccessControlPolicy_deny;
2403 		break;
2404 	case IEEE80211_MACCMD_POLICY_RADIUS:
2405 		wif->mac_policy = wlanMACAccessControlPolicy_radius;
2406 		break;
2407 	case IEEE80211_MACCMD_POLICY_OPEN:
2408 		/* FALLTHROUGH */
2409 	default:
2410 		wif->mac_policy = wlanMACAccessControlPolicy_open;
2411 		break;
2412 	}
2413 
2414 	argsize = 0;
2415 	val = IEEE80211_MACCMD_LIST;
2416 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, NULL,
2417 	    &argsize, 0) < 0)
2418 		return (-1);
2419 
2420 	wif->mac_nacls = argsize / sizeof(struct ieee80211req_maclist *);
2421 	return (0);
2422 }
2423 
2424 int
2425 wlan_set_mac_policy(struct wlan_iface *wif)
2426 {
2427 	int val;
2428 	size_t argsize = 0;
2429 
2430 	if (!wif->macsupported)
2431 		return (-1);
2432 
2433 	switch (wif->mac_policy) {
2434 	case wlanMACAccessControlPolicy_allow:
2435 		val = IEEE80211_MACCMD_POLICY_ALLOW;
2436 		break;
2437 	case wlanMACAccessControlPolicy_deny:
2438 		val = IEEE80211_MACCMD_POLICY_DENY;
2439 		break;
2440 	case wlanMACAccessControlPolicy_radius:
2441 		val = IEEE80211_MACCMD_POLICY_RADIUS;
2442 		break;
2443 	case wlanMACAccessControlPolicy_open:
2444 		val = IEEE80211_MACCMD_POLICY_OPEN;
2445 		break;
2446 	default:
2447 		return (-1);
2448 	}
2449 
2450 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, NULL,
2451 	    &argsize, 1) < 0)
2452 		return (-1);
2453 
2454 	return (0);
2455 }
2456 
2457 int
2458 wlan_flush_mac_mac(struct wlan_iface *wif)
2459 {
2460 	int val = IEEE80211_MACCMD_FLUSH;
2461 	size_t argsize = 0;
2462 
2463 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, NULL,
2464 	    &argsize, 1) < 0)
2465 		return (-1);
2466 
2467 	return (0);
2468 }
2469 
2470 static int
2471 wlan_add_mac_macinfo(struct wlan_iface *wif,
2472     const struct ieee80211req_maclist *ml)
2473 {
2474 	struct wlan_mac_mac *mmac;
2475 
2476 	if ((mmac = wlan_mac_new_mac(ml->ml_macaddr)) == NULL)
2477 		return (-1);
2478 
2479 	mmac->mac_status = RowStatus_active;
2480 	if (wlan_mac_add_mac(wif, mmac) < 0) {
2481 		wlan_mac_free_mac(mmac);
2482 		return (-1);
2483 	}
2484 
2485 	return (0);
2486 }
2487 
2488 int
2489 wlan_get_mac_acl_macs(struct wlan_iface *wif)
2490 {
2491 	int i, nacls, val = IEEE80211_MACCMD_LIST;
2492 	size_t argsize = 0;
2493 	uint8_t *data;
2494 	struct ieee80211req ireq;
2495 	const struct ieee80211req_maclist *acllist;
2496 
2497 	if (wif->mac_policy == wlanMACAccessControlPolicy_radius) {
2498 		wif->mac_nacls = 0;
2499 		return (0);
2500 	}
2501 
2502 	memset(&ireq, 0, sizeof(struct ieee80211req));
2503 	strlcpy(ireq.i_name, wif->wname, IFNAMSIZ);
2504 	ireq.i_type = IEEE80211_IOC_MACCMD;
2505 	ireq.i_val = IEEE80211_MACCMD_LIST;
2506 
2507 
2508 	if (ioctl(sock, SIOCG80211, &ireq) < 0) {
2509 		if (errno != EINVAL) {
2510 			syslog(LOG_ERR, "iface %s - get param: ioctl(%d) "
2511 			    "failed: %s", wif->wname, ireq.i_type,
2512 			    strerror(errno));
2513 			wif->macsupported = 0;
2514 			return (-1);
2515 		}
2516 	}
2517 
2518 	if (argsize == 0) {
2519 		wif->mac_nacls = 0;
2520 		return (0);
2521 	}
2522 
2523 	if ((data = (uint8_t *)malloc(argsize)) == NULL)
2524 		return (-1);
2525 
2526 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, data,
2527 	    &argsize, 0) < 0)
2528 		return (-1);
2529 
2530 	nacls = argsize / sizeof(*acllist);
2531 	acllist = (struct ieee80211req_maclist *) data;
2532 	for (i = 0; i < nacls; i++)
2533 		(void)wlan_add_mac_macinfo(wif, acllist + i);
2534 
2535 	wif->mac_nacls = nacls;
2536 	return (0);
2537 }
2538 
2539 int
2540 wlan_add_mac_acl_mac(struct wlan_iface *wif, struct wlan_mac_mac *mmac)
2541 {
2542 	int val = 0;
2543 	size_t argsize = IEEE80211_ADDR_LEN;
2544 	struct ieee80211req_mlme mlme;
2545 
2546 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_ADDMAC, &val,
2547 	    mmac->mac, &argsize, 1) < 0)
2548 		return (-1);
2549 
2550 	mmac->mac_status = RowStatus_active;
2551 
2552 	/* If policy is deny, try to kick the station just in case. */
2553 	if (wif->mac_policy != wlanMACAccessControlPolicy_deny)
2554 		return (0);
2555 
2556 	memset(&mlme, 0, sizeof(mlme));
2557 	mlme.im_op = IEEE80211_MLME_DEAUTH;
2558 	mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
2559 	memcpy(mlme.im_macaddr, mmac->mac, IEEE80211_ADDR_LEN);
2560 	argsize = sizeof(struct ieee80211req_mlme);
2561 
2562 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MLME, &val, &mlme,
2563 	    &argsize, 1) < 0 && errno != ENOENT)
2564 		return (-1);
2565 
2566 	return (0);
2567 }
2568 
2569 int
2570 wlan_del_mac_acl_mac(struct wlan_iface *wif, struct wlan_mac_mac *mmac)
2571 {
2572 	int val = 0;
2573 	size_t argsize = IEEE80211_ADDR_LEN;
2574 	struct ieee80211req_mlme mlme;
2575 
2576 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_DELMAC, &val,
2577 	    mmac->mac, &argsize, 1) < 0)
2578 		return (-1);
2579 
2580 	mmac->mac_status = RowStatus_active;
2581 
2582 	/* If policy is allow, try to kick the station just in case. */
2583 	if (wif->mac_policy != wlanMACAccessControlPolicy_allow)
2584 		return (0);
2585 
2586 	memset(&mlme, 0, sizeof(mlme));
2587 	mlme.im_op = IEEE80211_MLME_DEAUTH;
2588 	mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
2589 	memcpy(mlme.im_macaddr, mmac->mac, IEEE80211_ADDR_LEN);
2590 	argsize = sizeof(struct ieee80211req_mlme);
2591 
2592 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MLME, &val, &mlme,
2593 	    &argsize, 1) < 0 && errno != ENOENT)
2594 		return (-1);
2595 
2596 	return (0);
2597 }
2598 
2599 int
2600 wlan_peer_set_vlan(struct wlan_iface *wif, struct wlan_peer *wip, int vlan)
2601 {
2602 	int val = 0;
2603 	size_t argsize;
2604 	struct ieee80211req_sta_vlan vreq;
2605 
2606 	memcpy(vreq.sv_macaddr, wip->pmac, IEEE80211_ADDR_LEN);
2607 	vreq.sv_vlan = vlan;
2608 	argsize = sizeof(struct ieee80211req_sta_vlan);
2609 
2610 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_STA_VLAN,
2611 	    &val, &vreq, &argsize, 1) < 0)
2612 		return (-1);
2613 
2614 	wip->vlan = vlan;
2615 
2616 	return (0);
2617 }
2618 
2619 /* XXX */
2620 #ifndef IEEE80211_NODE_AUTH
2621 #define	IEEE80211_NODE_AUTH	0x000001	/* authorized for data */
2622 #define	IEEE80211_NODE_QOS	0x000002	/* QoS enabled */
2623 #define	IEEE80211_NODE_ERP	0x000004	/* ERP enabled */
2624 #define	IEEE80211_NODE_PWR_MGT	0x000010	/* power save mode enabled */
2625 #define	IEEE80211_NODE_AREF	0x000020	/* authentication ref held */
2626 #define	IEEE80211_NODE_HT	0x000040	/* HT enabled */
2627 #define	IEEE80211_NODE_HTCOMPAT	0x000080	/* HT setup w/ vendor OUI's */
2628 #define	IEEE80211_NODE_WPS	0x000100	/* WPS association */
2629 #define	IEEE80211_NODE_TSN	0x000200	/* TSN association */
2630 #define	IEEE80211_NODE_AMPDU_RX	0x000400	/* AMPDU rx enabled */
2631 #define	IEEE80211_NODE_AMPDU_TX	0x000800	/* AMPDU tx enabled */
2632 #define	IEEE80211_NODE_MIMO_PS	0x001000	/* MIMO power save enabled */
2633 #define	IEEE80211_NODE_MIMO_RTS	0x002000	/* send RTS in MIMO PS */
2634 #define	IEEE80211_NODE_RIFS	0x004000	/* RIFS enabled */
2635 #define	IEEE80211_NODE_SGI20	0x008000	/* Short GI in HT20 enabled */
2636 #define	IEEE80211_NODE_SGI40	0x010000	/* Short GI in HT40 enabled */
2637 #define	IEEE80211_NODE_ASSOCID	0x020000	/* xmit requires associd */
2638 #define	IEEE80211_NODE_AMSDU_RX	0x040000	/* AMSDU rx enabled */
2639 #define	IEEE80211_NODE_AMSDU_TX	0x080000	/* AMSDU tx enabled */
2640 #endif
2641 
2642 static uint32_t
2643 wlan_peerstate_to_snmp(uint32_t pstate)
2644 {
2645 	uint32_t sstate = 0;
2646 
2647 	if ((pstate & IEEE80211_NODE_AUTH) != 0)
2648 		sstate |= (0x1 << WlanIfacePeerFlagsType_authorizedForData);
2649 	if ((pstate & IEEE80211_NODE_QOS) != 0)
2650 		sstate |= (0x1 << WlanIfacePeerFlagsType_qosEnabled);
2651 	if ((pstate & IEEE80211_NODE_ERP) != 0)
2652 		sstate |= (0x1 << WlanIfacePeerFlagsType_erpEnabled);
2653 	if ((pstate & IEEE80211_NODE_PWR_MGT) != 0)
2654 		sstate |= (0x1 << WlanIfacePeerFlagsType_powerSaveMode);
2655 	if ((pstate & IEEE80211_NODE_AREF) != 0)
2656 		sstate |= (0x1 << WlanIfacePeerFlagsType_authRefHeld);
2657 	if ((pstate & IEEE80211_NODE_HT) != 0)
2658 		sstate |= (0x1 << WlanIfacePeerFlagsType_htEnabled);
2659 	if ((pstate & IEEE80211_NODE_HTCOMPAT) != 0)
2660 		sstate |= (0x1 << WlanIfacePeerFlagsType_htCompat);
2661 	if ((pstate & IEEE80211_NODE_WPS) != 0)
2662 		sstate |= (0x1 << WlanIfacePeerFlagsType_wpsAssoc);
2663 	if ((pstate & IEEE80211_NODE_TSN) != 0)
2664 		sstate |= (0x1 << WlanIfacePeerFlagsType_tsnAssoc);
2665 	if ((pstate & IEEE80211_NODE_AMPDU_RX) != 0)
2666 		sstate |= (0x1 << WlanIfacePeerFlagsType_ampduRx);
2667 	if ((pstate & IEEE80211_NODE_AMPDU_TX) != 0)
2668 		sstate |= (0x1 << WlanIfacePeerFlagsType_ampduTx);
2669 	if ((pstate & IEEE80211_NODE_MIMO_PS) != 0)
2670 		sstate |= (0x1 << WlanIfacePeerFlagsType_mimoPowerSave);
2671 	if ((pstate & IEEE80211_NODE_MIMO_RTS) != 0)
2672 		sstate |= (0x1 << WlanIfacePeerFlagsType_sendRts);
2673 	if ((pstate & IEEE80211_NODE_RIFS) != 0)
2674 		sstate |= (0x1 << WlanIfacePeerFlagsType_rifs);
2675 	if ((pstate & IEEE80211_NODE_SGI20) != 0)
2676 		sstate |= (0x1 << WlanIfacePeerFlagsType_shortGiHT20);
2677 	if ((pstate & IEEE80211_NODE_SGI40) != 0)
2678 		sstate |= (0x1 << WlanIfacePeerFlagsType_shortGiHT40);
2679 	if ((pstate & IEEE80211_NODE_AMSDU_RX) != 0)
2680 		sstate |= (0x1 << WlanIfacePeerFlagsType_amsduRx);
2681 	if ((pstate & IEEE80211_NODE_AMSDU_TX) != 0)
2682 		sstate |= (0x1 << WlanIfacePeerFlagsType_amsduTx);
2683 
2684 	return (sstate);
2685 }
2686 
2687 static struct wlan_peer *
2688 wlan_add_peerinfo(const struct ieee80211req_sta_info *si)
2689 {
2690 	struct wlan_peer *wip;
2691 
2692 	if ((wip = wlan_new_peer(si->isi_macaddr))== NULL)
2693 		return (NULL);
2694 
2695 	wip->associd = IEEE80211_AID(si->isi_associd);
2696 	wip->vlan = si->isi_vlan;
2697 	wip->frequency =  si->isi_freq;
2698 	wip->fflags = si->isi_flags;
2699 	wip->txrate = si->isi_txrate;
2700 	wip->rssi = si->isi_rssi;
2701 	wip->idle = si->isi_inact;
2702 	wip->txseqs = si->isi_txseqs[0]; /* XXX */
2703 	wip->rxseqs = si->isi_rxseqs[0]; /* XXX */
2704 	wip->txpower = si->isi_txpower;
2705 	wip->capinfo = wlan_peercaps_to_snmp(si->isi_capinfo);
2706 	wip->state = wlan_peerstate_to_snmp(si->isi_state);
2707 	wip->local_id = si->isi_localid;
2708 	wip->peer_id = si->isi_peerid;
2709 
2710 	return (wip);
2711 }
2712 
2713 int
2714 wlan_get_peerinfo(struct wlan_iface *wif)
2715 {
2716 	union {
2717 		struct ieee80211req_sta_req req;
2718 		uint8_t buf[24 * 1024];
2719 	} u;
2720 	const uint8_t *cp;
2721 	int val = 0;
2722 	size_t len;
2723 	struct ieee80211req_sta_info si;
2724 	struct wlan_peer *wip;
2725 
2726 	/* Get all stations - broadcast address */
2727 	(void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
2728 	len =  sizeof(u);
2729 
2730 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_STA_INFO,
2731 	    & val, &u, &len, 0) < 0)
2732 		return (-1);
2733 
2734 	if (len < sizeof(struct ieee80211req_sta_info))
2735 		return (-1);
2736 
2737 	cp = (const uint8_t *) u.req.info;
2738 	do {
2739 		memcpy(&si, cp, sizeof(struct ieee80211req_sta_info));
2740 		if ((wip = wlan_add_peerinfo(&si)) != NULL &&
2741 		    wlan_add_peer(wif, wip) < 0)
2742 			wlan_free_peer(wip);
2743 		cp += si.isi_len, len -= si.isi_len;
2744 	} while (len >= sizeof(struct ieee80211req_sta_info));
2745 
2746 	return (0);
2747 }
2748 
2749 /************************************************************************
2750  * Wireless MESH & HWMP sysctl config.
2751  */
2752 const char wlan_sysctl_name[] = "net.wlan.";
2753 
2754 static const char *wlan_sysctl[] = {
2755 	"mesh.retrytimeout",
2756 	"mesh.holdingtimeout",
2757 	"mesh.confirmtimeout",
2758 	"mesh.maxretries",
2759 	"hwmp.targetonly",
2760 	"hwmp.replyforward",
2761 	"hwmp.pathlifetime",
2762 	"hwmp.roottimeout",
2763 	"hwmp.rootint",
2764 	"hwmp.rannint",
2765 	"hwmp.inact",
2766 };
2767 
2768 int32_t
2769 wlan_do_sysctl(struct wlan_config *cfg, enum wlan_syscl which, int set)
2770 {
2771 	char mib_name[100];
2772 	int val, sval;
2773 	size_t len, vlen;
2774 
2775 	if (set) {
2776 		vlen = sizeof(sval);
2777 		switch (which) {
2778 		case WLAN_MESH_RETRY_TO:
2779 			sval = cfg->mesh_retryto;
2780 			break;
2781 		case WLAN_MESH_HOLDING_TO:
2782 			sval = cfg->mesh_holdingto;
2783 			break;
2784 		case WLAN_MESH_CONFIRM_TO:
2785 			sval = cfg->mesh_confirmto;
2786 			break;
2787 		case WLAN_MESH_MAX_RETRIES:
2788 			sval = cfg->mesh_maxretries;
2789 			break;
2790 		case WLAN_HWMP_TARGET_ONLY:
2791 			sval = cfg->hwmp_targetonly;
2792 			break;
2793 		case WLAN_HWMP_REPLY_FORWARD:
2794 			sval = cfg->hwmp_replyforward;
2795 			break;
2796 		case WLAN_HWMP_PATH_LIFETIME:
2797 			sval = cfg->hwmp_pathlifetime;
2798 			break;
2799 		case WLAN_HWMP_ROOT_TO:
2800 			sval = cfg->hwmp_roottimeout;
2801 			break;
2802 		case WLAN_HWMP_ROOT_INT:
2803 			sval = cfg->hwmp_rootint;
2804 			break;
2805 		case WLAN_HWMP_RANN_INT:
2806 			sval = cfg->hwmp_rannint;
2807 			break;
2808 		case WLAN_HWMP_INACTIVITY_TO:
2809 			sval = cfg->hwmp_inact;
2810 			break;
2811 		default:
2812 			return (-1);
2813 		}
2814 	} else {
2815 		if (which >= WLAN_SYSCTL_MAX)
2816 			return (-1);
2817 		vlen = 0;
2818 	}
2819 
2820 	strlcpy(mib_name, wlan_sysctl_name, sizeof(mib_name));
2821 	strlcat(mib_name, wlan_sysctl[which], sizeof(mib_name));
2822 	len = sizeof (val);
2823 
2824 	if (sysctlbyname(mib_name, &val, &len, (set? &sval : NULL), vlen) < 0) {
2825 		syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_name,
2826 		    strerror(errno));
2827 		return (-1);
2828 	}
2829 
2830 	switch (which) {
2831 	case WLAN_MESH_RETRY_TO:
2832 		cfg->mesh_retryto = val;
2833 		break;
2834 	case WLAN_MESH_HOLDING_TO:
2835 		cfg->mesh_holdingto = val;
2836 		break;
2837 	case WLAN_MESH_CONFIRM_TO:
2838 		cfg->mesh_confirmto = val;
2839 		break;
2840 	case WLAN_MESH_MAX_RETRIES:
2841 		cfg->mesh_maxretries = val;
2842 		break;
2843 	case WLAN_HWMP_TARGET_ONLY:
2844 		cfg->hwmp_targetonly = val;
2845 		break;
2846 	case WLAN_HWMP_REPLY_FORWARD:
2847 		cfg->hwmp_replyforward = val;
2848 		break;
2849 	case WLAN_HWMP_PATH_LIFETIME:
2850 		cfg->hwmp_pathlifetime = val;
2851 		break;
2852 	case WLAN_HWMP_ROOT_TO:
2853 		cfg->hwmp_roottimeout = val;
2854 		break;
2855 	case WLAN_HWMP_ROOT_INT:
2856 		cfg->hwmp_rootint = val;
2857 		break;
2858 	case WLAN_HWMP_RANN_INT:
2859 		cfg->hwmp_rannint = val;
2860 		break;
2861 	case WLAN_HWMP_INACTIVITY_TO:
2862 		cfg->hwmp_inact = val;
2863 		break;
2864 	default:
2865 		/* NOTREACHED */
2866 		abort();
2867 	}
2868 
2869 	return (0);
2870 }
2871 
2872 int
2873 wlan_mesh_config_get(struct wlan_iface *wif, int which)
2874 {
2875 	int op, val = 0;
2876 	size_t argsize = 0;
2877 	uint8_t data[32], *pd = NULL;
2878 
2879 	switch (which) {
2880 	case LEAF_wlanMeshTTL:
2881 		op = IEEE80211_IOC_MESH_TTL;
2882 		break;
2883 	case LEAF_wlanMeshPeeringEnabled:
2884 		op = IEEE80211_IOC_MESH_AP;
2885 		break;
2886 	case LEAF_wlanMeshForwardingEnabled:
2887 		op = IEEE80211_IOC_MESH_FWRD;
2888 		break;
2889 	case LEAF_wlanMeshMetric:
2890 		op = IEEE80211_IOC_MESH_PR_METRIC;
2891 		pd = data;
2892 		argsize = sizeof(data);
2893 		break;
2894 	case LEAF_wlanMeshPath:
2895 		op = IEEE80211_IOC_MESH_PR_PATH;
2896 		pd = data;
2897 		argsize = sizeof(data);
2898 		break;
2899 	case LEAF_wlanMeshRoutesFlush:
2900 		return (0);
2901 	default:
2902 		return (-1);
2903 	}
2904 
2905 	if (wlan_ioctl(wif->wname, op, &val, pd, &argsize, 0) < 0)
2906 		return (-1);
2907 
2908 	switch (which) {
2909 	case LEAF_wlanMeshTTL:
2910 		wif->mesh_ttl = val;
2911 		break;
2912 	case LEAF_wlanMeshPeeringEnabled:
2913 		if (val)
2914 			wif->mesh_peering = wlanMeshPeeringEnabled_true;
2915 		else
2916 			wif->mesh_peering = wlanMeshPeeringEnabled_false;
2917 		break;
2918 	case LEAF_wlanMeshForwardingEnabled:
2919 		if (val)
2920 			wif->mesh_forwarding = wlanMeshForwardingEnabled_true;
2921 		else
2922 			wif->mesh_forwarding = wlanMeshForwardingEnabled_false;
2923 		break;
2924 	case LEAF_wlanMeshMetric:
2925 		data[argsize] = '\0';
2926 		if (strcmp(data, "AIRTIME") == 0)
2927 			wif->mesh_metric = wlanMeshMetric_airtime;
2928 		else
2929 			wif->mesh_metric = wlanMeshMetric_unknown;
2930 		break;
2931 	case LEAF_wlanMeshPath:
2932 		data[argsize] = '\0';
2933 		if (strcmp(data, "HWMP") == 0)
2934 			wif->mesh_path = wlanMeshPath_hwmp;
2935 		else
2936 			wif->mesh_path = wlanMeshPath_unknown;
2937 	}
2938 
2939 	return (0);
2940 }
2941 
2942 int
2943 wlan_mesh_config_set(struct wlan_iface *wif, int which)
2944 {
2945 	int op, val = 0;
2946 	size_t argsize = 0;
2947 	uint8_t data[32], *pd = NULL;
2948 
2949 	switch (which) {
2950 	case LEAF_wlanMeshTTL:
2951 		op = IEEE80211_IOC_MESH_TTL;
2952 		val = wif->mesh_ttl;
2953 		break;
2954 	case LEAF_wlanMeshPeeringEnabled:
2955 		op = IEEE80211_IOC_MESH_AP;
2956 		if (wif->mesh_peering == wlanMeshPeeringEnabled_true)
2957 			val = 1;
2958 		break;
2959 	case LEAF_wlanMeshForwardingEnabled:
2960 		if (wif->mesh_forwarding == wlanMeshForwardingEnabled_true)
2961 			val = 1;
2962 		op = IEEE80211_IOC_MESH_FWRD;
2963 		break;
2964 	case LEAF_wlanMeshMetric:
2965 		op = IEEE80211_IOC_MESH_PR_METRIC;
2966 		if (wif->mesh_metric == wlanMeshMetric_airtime)
2967 			strcpy(data, "AIRTIME");
2968 		else
2969 			return (-1);
2970 		pd = data;
2971 		argsize = sizeof(data);
2972 		break;
2973 	case LEAF_wlanMeshPath:
2974 		op = IEEE80211_IOC_MESH_PR_PATH;
2975 		if (wif->mesh_path == wlanMeshPath_hwmp)
2976 			strcpy(data, "HWMP");
2977 		else
2978 			return (-1);
2979 		pd = data;
2980 		argsize = sizeof(data);
2981 		break;
2982 	default:
2983 		return (-1);
2984 	}
2985 
2986 	if (wlan_ioctl(wif->wname, op, &val, pd, &argsize, 1) < 0)
2987 		return (-1);
2988 
2989 	return(0);
2990 }
2991 
2992 int
2993 wlan_mesh_flush_routes(struct wlan_iface *wif)
2994 {
2995 	int val = IEEE80211_MESH_RTCMD_FLUSH;
2996 	size_t argsize = 0;
2997 
2998 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val, NULL,
2999 	    &argsize, 1) < 0)
3000 		return (-1);
3001 
3002 	return (0);
3003 }
3004 
3005 int
3006 wlan_mesh_add_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
3007 {
3008 	int val = IEEE80211_MESH_RTCMD_ADD;
3009 	size_t argsize = IEEE80211_ADDR_LEN;
3010 
3011 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val,
3012 	    wmr->imroute.imr_dest, &argsize, 1) < 0)
3013 		return (-1);
3014 
3015 	wmr->mroute_status = RowStatus_active;
3016 
3017 	return (0);
3018 }
3019 
3020 int
3021 wlan_mesh_del_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr)
3022 {
3023 	int val = IEEE80211_MESH_RTCMD_DELETE;
3024 	size_t argsize = IEEE80211_ADDR_LEN;
3025 
3026 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val,
3027 	    wmr->imroute.imr_dest, &argsize, 1) < 0)
3028 		return (-1);
3029 
3030 	wmr->mroute_status = RowStatus_destroy;
3031 
3032 	return (0);
3033 }
3034 
3035 int
3036 wlan_mesh_get_routelist(struct wlan_iface *wif)
3037 {
3038 	int i, nroutes, val = IEEE80211_MESH_RTCMD_LIST;
3039 	size_t argsize;
3040 	struct ieee80211req_mesh_route routes[128];
3041 	struct ieee80211req_mesh_route *rt;
3042 	struct wlan_mesh_route *wmr;
3043 
3044 	argsize = sizeof(routes);
3045 	if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val, routes,
3046 	    &argsize, 0) < 0) /* XXX: ENOMEM? */
3047 		return (-1);
3048 
3049 	nroutes = argsize / sizeof(*rt);
3050 	for (i = 0; i < nroutes; i++) {
3051 		rt = routes + i;
3052 		if ((wmr = wlan_mesh_new_route(rt->imr_dest)) == NULL)
3053 			return (-1);
3054 		memcpy(&wmr->imroute, rt, sizeof(*rt));
3055 		wmr->mroute_status = RowStatus_active;
3056 		if (wlan_mesh_add_rtentry(wif, wmr) < 0)
3057 			wlan_mesh_free_route(wmr);
3058 	}
3059 
3060 	return (0);
3061 }
3062 
3063 int
3064 wlan_hwmp_config_get(struct wlan_iface *wif, int which)
3065 {
3066 	int op, val = 0;
3067 	size_t argsize = 0;
3068 
3069 	switch (which) {
3070 	case LEAF_wlanHWMPRootMode:
3071 		op = IEEE80211_IOC_HWMP_ROOTMODE;
3072 		break;
3073 	case LEAF_wlanHWMPMaxHops:
3074 		op = IEEE80211_IOC_HWMP_MAXHOPS;
3075 		break;
3076 	default:
3077 		return (-1);
3078 	}
3079 
3080 	if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 0) < 0)
3081 		return (-1);
3082 
3083 	switch (which) {
3084 	case LEAF_wlanHWMPRootMode:
3085 		switch (val) {
3086 		case IEEE80211_HWMP_ROOTMODE_NORMAL:
3087 			wif->hwmp_root_mode = wlanHWMPRootMode_normal;
3088 			break;
3089 		case IEEE80211_HWMP_ROOTMODE_PROACTIVE:
3090 			wif->hwmp_root_mode = wlanHWMPRootMode_proactive;
3091 			break;
3092 		case IEEE80211_HWMP_ROOTMODE_RANN:
3093 			wif->hwmp_root_mode = wlanHWMPRootMode_rann;
3094 			break;
3095 		case IEEE80211_HWMP_ROOTMODE_DISABLED:
3096 		default:
3097 			wif->hwmp_root_mode = wlanHWMPRootMode_disabled;
3098 			break;
3099 		}
3100 		break;
3101 	case LEAF_wlanHWMPMaxHops:
3102 		wif->hwmp_max_hops = val;
3103 		break;
3104 	}
3105 
3106 	return (0);
3107 }
3108 
3109 int
3110 wlan_hwmp_config_set(struct wlan_iface *wif, int which)
3111 {
3112 	int op, val = 0;
3113 	size_t argsize = 0;
3114 
3115 	switch (which) {
3116 	case LEAF_wlanHWMPRootMode:
3117 		op = IEEE80211_IOC_HWMP_ROOTMODE;
3118 		switch (wif->hwmp_root_mode) {
3119 		case wlanHWMPRootMode_disabled:
3120 			val = IEEE80211_HWMP_ROOTMODE_DISABLED;
3121 			break;
3122 		case wlanHWMPRootMode_normal:
3123 			val = IEEE80211_HWMP_ROOTMODE_NORMAL;
3124 			break;
3125 		case wlanHWMPRootMode_proactive:
3126 			val = IEEE80211_HWMP_ROOTMODE_PROACTIVE;
3127 			break;
3128 		case wlanHWMPRootMode_rann:
3129 			val = IEEE80211_HWMP_ROOTMODE_RANN;
3130 			break;
3131 		default:
3132 			return (-1);
3133 		}
3134 		break;
3135 	case LEAF_wlanHWMPMaxHops:
3136 		op = IEEE80211_IOC_HWMP_MAXHOPS;
3137 		val = wif->hwmp_max_hops;
3138 		break;
3139 	default:
3140 		return (-1);
3141 	}
3142 
3143 	if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 1) < 0)
3144 		return (-1);
3145 
3146 	return (0);
3147 }
3148