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