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