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