wlan_sys.c revision 310903
1/*-
2 * Copyright (c) 2010 The FreeBSD Foundation
3 * All rights reserved.
4
5 * This software was developed by Shteryana Sotirova Shopova under
6 * sponsorship from the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: stable/10/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c 310903 2016-12-31 10:34:09Z ngie $
30 */
31
32#include <sys/ioctl.h>
33#include <sys/param.h>
34#include <sys/module.h>
35#include <sys/linker.h>
36#include <sys/socket.h>
37#include <sys/sysctl.h>
38
39#include <net/if.h>
40#include <net/if_dl.h>
41#include <net/if_media.h>
42#include <net/if_mib.h>
43#include <net/if_types.h>
44#include <net80211/ieee80211.h>
45#include <net80211/ieee80211_ioctl.h>
46#include <net80211/ieee80211_regdomain.h>
47
48#include <errno.h>
49#include <ifaddrs.h>
50#include <stdarg.h>
51#include <stdlib.h>
52#include <stdio.h>
53#include <string.h>
54#include <syslog.h>
55
56#include <bsnmp/snmpmod.h>
57#include <bsnmp/snmp_mibII.h>
58
59#include "wlan_tree.h"
60#include "wlan_snmp.h"
61
62static int sock = -1;
63
64static int	wlan_ioctl(char *, uint16_t, int *, void *, size_t *, int);
65static int	wlan_kmod_load(const char *);
66static uint32_t	wlan_drivercaps_to_snmp(uint32_t);
67static uint32_t	wlan_cryptocaps_to_snmp(uint32_t);
68static uint32_t	wlan_htcaps_to_snmp(uint32_t);
69static uint32_t	wlan_peerstate_to_snmp(uint32_t);
70static uint32_t	wlan_peercaps_to_snmp(uint32_t );
71static uint32_t	wlan_channel_flags_to_snmp_phy(uint32_t);
72static uint32_t	wlan_regdomain_to_snmp(int);
73static uint32_t	wlan_snmp_to_scan_flags(int);
74static int	wlan_config_snmp2ioctl(int);
75static int	wlan_snmp_to_regdomain(enum WlanRegDomainCode);
76static int	wlan_config_get_country(struct wlan_iface *);
77static int	wlan_config_set_country(struct wlan_iface *, char *, int);
78static int	wlan_config_get_dchannel(struct wlan_iface *wif);
79static int	wlan_config_set_dchannel(struct wlan_iface *wif, uint32_t);
80static int	wlan_config_get_bssid(struct wlan_iface *);
81static int	wlan_config_set_bssid(struct wlan_iface *, uint8_t *);
82static void	wlan_config_set_snmp_intval(struct wlan_iface *, int, int);
83static int	wlan_config_snmp2value(int, int, int *);
84static int	wlan_config_check(struct wlan_iface *, int);
85static int	wlan_config_get_intval(struct wlan_iface *, int);
86static int	wlan_config_set_intval(struct wlan_iface *, int, int);
87static int	wlan_add_new_scan_result(struct wlan_iface *,
88    const struct ieee80211req_scan_result *, uint8_t *);
89static int	wlan_add_mac_macinfo(struct wlan_iface *,
90    const struct ieee80211req_maclist *);
91static struct wlan_peer *wlan_add_peerinfo(const struct ieee80211req_sta_info *);
92
93int
94wlan_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 */
106enum wlan_kmodules {
107	WLAN_KMOD = 0,
108	WLAN_KMOD_ACL,
109	WLAN_KMOD_WEP,
110	WLAN_KMODS_MAX
111};
112
113static const char *wmod_names[] = {
114	"wlan",
115	"wlan_wlan_acl",
116	"wlan_wep",
117	NULL
118};
119
120static int
121wlan_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
147int
148wlan_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 */
165static int
166wlan_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
192int
193wlan_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
209int
210wlan_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
241int
242wlan_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
283int
284wlan_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
315int
316wlan_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
350static uint32_t
351wlan_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
405static uint32_t
406wlan_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
436static uint32_t
437wlan_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)
485int
486wlan_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
516uint8_t
517wlan_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
533uint32_t
534wlan_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
584int
585wlan_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);
630error:
631	wif->nchannels = 0;
632	free(chaninfo);
633	return (-1);
634}
635
636static enum WlanIfPhyMode
637wlan_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
665int
666wlan_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
679int
680wlan_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
697int
698wlan_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
715int
716wlan_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
788int
789wlan_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
808static int
809wlan_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
956static enum WlanRegDomainCode
957wlan_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
1025static int
1026wlan_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
1091static int
1092wlan_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
1113static int
1114wlan_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
1171int
1172wlan_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
1194int
1195wlan_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
1214static int
1215wlan_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
1240static int
1241wlan_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
1263static int
1264wlan_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
1281static int
1282wlan_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 */
1300static void
1301wlan_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 */
1599static int
1600wlan_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 */
1857static int
1858wlan_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
1994static int
1995wlan_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
2009static int
2010wlan_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
2026int
2027wlan_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
2050int
2051wlan_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
2077static uint32_t
2078wlan_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
2104int
2105wlan_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
2129static uint32_t
2130wlan_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
2160static int
2161wlan_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
2184int
2185wlan_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
2226int
2227wlan_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
2245int
2246wlan_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
2278int
2279wlan_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
2308int
2309wlan_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
2329int
2330wlan_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
2352int
2353wlan_get_wepkeys(struct wlan_iface *wif __unused)
2354{
2355	/* XXX: should they be visible via SNMP */
2356	return (0);
2357}
2358
2359int
2360wlan_set_wepkeys(struct wlan_iface *wif __unused)
2361{
2362	/* XXX: should they be configurable via SNMP */
2363	return (0);
2364}
2365
2366int
2367wlan_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
2422int
2423wlan_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
2455int
2456wlan_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
2468static int
2469wlan_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
2486int
2487wlan_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
2537int
2538wlan_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
2567int
2568wlan_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
2597int
2598wlan_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
2640static uint32_t
2641wlan_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
2685static struct wlan_peer *
2686wlan_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
2711int
2712wlan_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 */
2750const char wlan_sysctl_name[] = "net.wlan.";
2751
2752static 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
2766int32_t
2767wlan_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
2870int
2871wlan_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
2940int
2941wlan_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
2990int
2991wlan_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
3003int
3004wlan_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
3018int
3019wlan_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
3033int
3034wlan_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
3061int
3062wlan_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
3107int
3108wlan_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