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