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