diff options
Diffstat (limited to 'usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c')
-rw-r--r-- | usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c | 3145 |
1 files changed, 3145 insertions, 0 deletions
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c new file mode 100644 index 0000000..739f11f --- /dev/null +++ b/usr.sbin/bsnmpd/modules/snmp_wlan/wlan_sys.c @@ -0,0 +1,3145 @@ +/*- + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + + * This software was developed by Shteryana Sotirova Shopova under + * sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/ioctl.h> +#include <sys/param.h> +#include <sys/module.h> +#include <sys/linker.h> +#include <sys/socket.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_mib.h> +#include <net/if_types.h> +#include <net80211/ieee80211.h> +#include <net80211/ieee80211_ioctl.h> +#include <net80211/ieee80211_regdomain.h> + +#include <errno.h> +#include <ifaddrs.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include <bsnmp/snmpmod.h> +#include <bsnmp/snmp_mibII.h> + +#include "wlan_tree.h" +#include "wlan_snmp.h" + +static int sock = -1; + +static int wlan_ioctl(char *, uint16_t, int *, void *, size_t *, int); +static int wlan_kmod_load(const char *); +static uint32_t wlan_drivercaps_to_snmp(uint32_t); +static uint32_t wlan_cryptocaps_to_snmp(uint32_t); +static uint32_t wlan_htcaps_to_snmp(uint32_t); +static uint32_t wlan_peerstate_to_snmp(uint32_t); +static uint32_t wlan_peercaps_to_snmp(uint32_t ); +static uint32_t wlan_channel_flags_to_snmp_phy(uint32_t); +static uint32_t wlan_regdomain_to_snmp(int); +static uint32_t wlan_snmp_to_scan_flags(int); +static int wlan_config_snmp2ioctl(int); +static int wlan_snmp_to_regdomain(enum WlanRegDomainCode); +static int wlan_config_get_country(struct wlan_iface *); +static int wlan_config_set_country(struct wlan_iface *, char *, int); +static int wlan_config_get_dchannel(struct wlan_iface *wif); +static int wlan_config_set_dchannel(struct wlan_iface *wif, uint32_t); +static int wlan_config_get_bssid(struct wlan_iface *); +static int wlan_config_set_bssid(struct wlan_iface *, uint8_t *); +static void wlan_config_set_snmp_intval(struct wlan_iface *, int, int); +static int wlan_config_snmp2value(int, int, int *); +static int wlan_config_check(struct wlan_iface *, int); +static int wlan_config_get_intval(struct wlan_iface *, int); +static int wlan_config_set_intval(struct wlan_iface *, int, int); +static int wlan_add_new_scan_result(struct wlan_iface *, + const struct ieee80211req_scan_result *, uint8_t *); +static int wlan_add_mac_macinfo(struct wlan_iface *, + const struct ieee80211req_maclist *); +static struct wlan_peer *wlan_add_peerinfo(const struct ieee80211req_sta_info *); + +int +wlan_ioctl_init(void) +{ + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "cannot open socket : %s", strerror(errno)); + return (-1); + } + + return (0); +} +/* + * Load the needed modules in kernel if not already there. + */ +enum wlan_kmodules { + WLAN_KMOD = 0, + WLAN_KMOD_ACL, + WLAN_KMOD_WEP, + WLAN_KMODS_MAX +}; + +static const char *wmod_names[] = { + "wlan", + "wlan_wlan_acl", + "wlan_wep", + NULL +}; + +static int +wlan_kmod_load(const char *modname) +{ + int fileid, modid; + struct module_stat mstat; + + mstat.version = sizeof(struct module_stat); + for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { + for (modid = kldfirstmod(fileid); modid > 0; + modid = modfnext(modid)) { + if (modstat(modid, &mstat) < 0) + continue; + if (strcmp(modname, mstat.name) == 0) + return (0); + } + } + + /* Not present - load it. */ + if (kldload(modname) < 0) { + syslog(LOG_ERR, "failed to load %s kernel module - %s", modname, + strerror(errno)); + return (-1); + } + + return (1); +} + +int +wlan_kmodules_load(void) +{ + if (wlan_kmod_load(wmod_names[WLAN_KMOD]) < 0) + return (-1); + + if (wlan_kmod_load(wmod_names[WLAN_KMOD_ACL]) > 0) + syslog(LOG_NOTICE, "SNMP wlan loaded %s module", + wmod_names[WLAN_KMOD_ACL]); + + if (wlan_kmod_load(wmod_names[WLAN_KMOD_WEP]) > 0) + syslog(LOG_NOTICE, "SNMP wlan loaded %s module", + wmod_names[WLAN_KMOD_WEP]); + + return (0); +} + +/* XXX: FIXME */ +static int +wlan_ioctl(char *wif_name, uint16_t req_type, int *val, void *arg, + size_t *argsize, int set) +{ + struct ieee80211req ireq; + + memset(&ireq, 0, sizeof(struct ieee80211req)); + strlcpy(ireq.i_name, wif_name, IFNAMSIZ); + + ireq.i_type = req_type; + ireq.i_val = *val; + ireq.i_len = *argsize; + ireq.i_data = arg; + + if (ioctl(sock, set ? SIOCS80211 : SIOCG80211, &ireq) < 0) { + syslog(LOG_ERR, "iface %s - %s param: ioctl(%d) " + "failed: %s", wif_name, set ? "set" : "get", + req_type, strerror(errno)); + return (-1); + } + + *argsize = ireq.i_len; + *val = ireq.i_val; + + return (0); +} + +int +wlan_check_media(char *ifname) +{ + struct ifmediareq ifmr; + + memset(&ifmr, 0, sizeof(struct ifmediareq)); + strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); + + if (ioctl(sock, SIOCGIFMEDIA, &ifmr) < 0 || ifmr.ifm_count == 0) + return (0); /* Interface doesn't support SIOCGIFMEDIA. */ + + if ((ifmr.ifm_status & IFM_AVALID) == 0) + return (0); + + return (IFM_TYPE(ifmr.ifm_active)); +} + +int +wlan_get_opmode(struct wlan_iface *wif) +{ + struct ifmediareq ifmr; + + memset(&ifmr, 0, sizeof(struct ifmediareq)); + strlcpy(ifmr.ifm_name, wif->wname, sizeof(ifmr.ifm_name)); + + if (ioctl(sock, SIOCGIFMEDIA, &ifmr) < 0) { + if (errno == ENXIO) + return (-1); + wif->mode = WlanIfaceOperatingModeType_station; + return (0); + } + + if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) { + if (ifmr.ifm_current & IFM_FLAG0) + wif->mode = WlanIfaceOperatingModeType_adhocDemo; + else + wif->mode = WlanIfaceOperatingModeType_ibss; + } else if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) + wif->mode = WlanIfaceOperatingModeType_hostAp; + else if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) + wif->mode = WlanIfaceOperatingModeType_monitor; + else if (ifmr.ifm_current & IFM_IEEE80211_MBSS) + wif->mode = WlanIfaceOperatingModeType_meshPoint; + else if (ifmr.ifm_current & IFM_IEEE80211_WDS) + wif->mode = WlanIfaceOperatingModeType_wds; + + return (0); +} + +int +wlan_config_state(struct wlan_iface *wif, uint8_t set) +{ + int flags; + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, wif->wname); + + if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { + syslog(LOG_ERR, "set %s status: ioctl(SIOCGIFFLAGS) " + "failed: %s", wif->wname, strerror(errno)); + return (-1); + } + + if (set == 0) { + if ((ifr.ifr_flags & IFF_UP) != 0) + wif->state = wlanIfaceState_up; + else + wif->state = wlanIfaceState_down; + return (0); + } + + flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + + if (wif->state == wlanIfaceState_up) + flags |= IFF_UP; + else + flags &= ~IFF_UP; + + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; + if (ioctl(sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { + syslog(LOG_ERR, "set %s %s: ioctl(SIOCSIFFLAGS) failed: %s", + wif->wname, wif->state == wlanIfaceState_up?"up":"down", + strerror(errno)); + return (-1); + } + + return (0); +} + +int +wlan_get_local_addr(struct wlan_iface *wif) +{ + int len; + char ifname[IFNAMSIZ]; + struct ifaddrs *ifap, *ifa; + struct sockaddr_dl sdl; + + if (getifaddrs(&ifap) != 0) { + syslog(LOG_ERR, "wlan get mac: getifaddrs() failed - %s", + strerror(errno)); + return (-1); + } + + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + memcpy(&sdl, ifa->ifa_addr, sizeof(struct sockaddr_dl)); + if (sdl.sdl_alen > IEEE80211_ADDR_LEN) + continue; + if ((len = sdl.sdl_nlen) >= IFNAMSIZ) + len = IFNAMSIZ - 1; + memcpy(ifname, sdl.sdl_data, len); + ifname[len] = '\0'; + if (strcmp(wif->wname, ifname) == 0) + break; + } + + freeifaddrs(ifap); + return (0); +} + +int +wlan_get_parent(struct wlan_iface *wif __unused) +{ + /* XXX: There's no way to fetch this from the kernel. */ + return (0); +} + +/* XXX */ +#define IEEE80211_C_STA 0x00000001 /* CAPABILITY: STA available */ +#define IEEE80211_C_8023ENCAP 0x00000002 /* CAPABILITY: 802.3 encap */ +#define IEEE80211_C_FF 0x00000040 /* CAPABILITY: ATH FF avail */ +#define IEEE80211_C_TURBOP 0x00000080 /* CAPABILITY: ATH Turbo avail*/ +#define IEEE80211_C_IBSS 0x00000100 /* CAPABILITY: IBSS available */ +#define IEEE80211_C_PMGT 0x00000200 /* CAPABILITY: Power mgmt */ +#define IEEE80211_C_HOSTAP 0x00000400 /* CAPABILITY: HOSTAP avail */ +#define IEEE80211_C_AHDEMO 0x00000800 /* CAPABILITY: Old Adhoc Demo */ +#define IEEE80211_C_SWRETRY 0x00001000 /* CAPABILITY: sw tx retry */ +#define IEEE80211_C_TXPMGT 0x00002000 /* CAPABILITY: tx power mgmt */ +#define IEEE80211_C_SHSLOT 0x00004000 /* CAPABILITY: short slottime */ +#define IEEE80211_C_SHPREAMBLE 0x00008000 /* CAPABILITY: short preamble */ +#define IEEE80211_C_MONITOR 0x00010000 /* CAPABILITY: monitor mode */ +#define IEEE80211_C_DFS 0x00020000 /* CAPABILITY: DFS/radar avail*/ +#define IEEE80211_C_MBSS 0x00040000 /* CAPABILITY: MBSS available */ +/* 0x7c0000 available */ +#define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */ +#define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */ +#define IEEE80211_C_WPA 0x01800000 /* CAPABILITY: WPA1+WPA2 avail*/ +#define IEEE80211_C_BURST 0x02000000 /* CAPABILITY: frame bursting */ +#define IEEE80211_C_WME 0x04000000 /* CAPABILITY: WME avail */ +#define IEEE80211_C_WDS 0x08000000 /* CAPABILITY: 4-addr support */ +/* 0x10000000 reserved */ +#define IEEE80211_C_BGSCAN 0x20000000 /* CAPABILITY: bg scanning */ +#define IEEE80211_C_TXFRAG 0x40000000 /* CAPABILITY: tx fragments */ +#define IEEE80211_C_TDMA 0x80000000 /* CAPABILITY: TDMA avail */ + +static uint32_t +wlan_drivercaps_to_snmp(uint32_t dcaps) +{ + uint32_t scaps = 0; + + if ((dcaps & IEEE80211_C_STA) != 0) + scaps |= (0x1 << WlanDriverCaps_station); + if ((dcaps & IEEE80211_C_8023ENCAP) != 0) + scaps |= (0x1 << WlanDriverCaps_ieee8023encap); + if ((dcaps & IEEE80211_C_FF) != 0) + scaps |= (0x1 << WlanDriverCaps_athFastFrames); + if ((dcaps & IEEE80211_C_TURBOP) != 0) + scaps |= (0x1 << WlanDriverCaps_athTurbo); + if ((dcaps & IEEE80211_C_IBSS) != 0) + scaps |= (0x1 << WlanDriverCaps_ibss); + if ((dcaps & IEEE80211_C_PMGT) != 0) + scaps |= (0x1 << WlanDriverCaps_pmgt); + if ((dcaps & IEEE80211_C_HOSTAP) != 0) + scaps |= (0x1 << WlanDriverCaps_hostAp); + if ((dcaps & IEEE80211_C_AHDEMO) != 0) + scaps |= (0x1 << WlanDriverCaps_ahDemo); + if ((dcaps & IEEE80211_C_SWRETRY) != 0) + scaps |= (0x1 << WlanDriverCaps_swRetry); + if ((dcaps & IEEE80211_C_TXPMGT) != 0) + scaps |= (0x1 << WlanDriverCaps_txPmgt); + if ((dcaps & IEEE80211_C_SHSLOT) != 0) + scaps |= (0x1 << WlanDriverCaps_shortSlot); + if ((dcaps & IEEE80211_C_SHPREAMBLE) != 0) + scaps |= (0x1 << WlanDriverCaps_shortPreamble); + if ((dcaps & IEEE80211_C_MONITOR) != 0) + scaps |= (0x1 << WlanDriverCaps_monitor); + if ((dcaps & IEEE80211_C_DFS) != 0) + scaps |= (0x1 << WlanDriverCaps_dfs); + if ((dcaps & IEEE80211_C_MBSS) != 0) + scaps |= (0x1 << WlanDriverCaps_mbss); + if ((dcaps & IEEE80211_C_WPA1) != 0) + scaps |= (0x1 << WlanDriverCaps_wpa1); + if ((dcaps & IEEE80211_C_WPA2) != 0) + scaps |= (0x1 << WlanDriverCaps_wpa2); + if ((dcaps & IEEE80211_C_BURST) != 0) + scaps |= (0x1 << WlanDriverCaps_burst); + if ((dcaps & IEEE80211_C_WME) != 0) + scaps |= (0x1 << WlanDriverCaps_wme); + if ((dcaps & IEEE80211_C_WDS) != 0) + scaps |= (0x1 << WlanDriverCaps_wds); + if ((dcaps & IEEE80211_C_BGSCAN) != 0) + scaps |= (0x1 << WlanDriverCaps_bgScan); + if ((dcaps & IEEE80211_C_TXFRAG) != 0) + scaps |= (0x1 << WlanDriverCaps_txFrag); + if ((dcaps & IEEE80211_C_TDMA) != 0) + scaps |= (0x1 << WlanDriverCaps_tdma); + + return (scaps); +} + +static uint32_t +wlan_cryptocaps_to_snmp(uint32_t ccaps) +{ + uint32_t scaps = 0; + +#if NOT_YET + if ((ccaps & IEEE80211_CRYPTO_WEP) != 0) + scaps |= (0x1 << wlanCryptoCaps_wep); + if ((ccaps & IEEE80211_CRYPTO_TKIP) != 0) + scaps |= (0x1 << wlanCryptoCaps_tkip); + if ((ccaps & IEEE80211_CRYPTO_AES_OCB) != 0) + scaps |= (0x1 << wlanCryptoCaps_aes); + if ((ccaps & IEEE80211_CRYPTO_AES_CCM) != 0) + scaps |= (0x1 << wlanCryptoCaps_aesCcm); + if ((ccaps & IEEE80211_CRYPTO_TKIPMIC) != 0) + scaps |= (0x1 << wlanCryptoCaps_tkipMic); + if ((ccaps & IEEE80211_CRYPTO_CKIP) != 0) + scaps |= (0x1 << wlanCryptoCaps_ckip); +#else /* !NOT_YET */ + scaps = ccaps; +#endif + return (scaps); +} + +#define IEEE80211_HTC_AMPDU 0x00010000 /* CAPABILITY: A-MPDU tx */ +#define IEEE80211_HTC_AMSDU 0x00020000 /* CAPABILITY: A-MSDU tx */ +/* NB: HT40 is implied by IEEE80211_HTCAP_CHWIDTH40 */ +#define IEEE80211_HTC_HT 0x00040000 /* CAPABILITY: HT operation */ +#define IEEE80211_HTC_SMPS 0x00080000 /* CAPABILITY: MIMO power save*/ +#define IEEE80211_HTC_RIFS 0x00100000 /* CAPABILITY: RIFS support */ + +static uint32_t +wlan_htcaps_to_snmp(uint32_t hcaps) +{ + uint32_t scaps = 0; + + if ((hcaps & IEEE80211_HTCAP_LDPC) != 0) + scaps |= (0x1 << WlanHTCaps_ldpc); + if ((hcaps & IEEE80211_HTCAP_CHWIDTH40) != 0) + scaps |= (0x1 << WlanHTCaps_chwidth40); + if ((hcaps & IEEE80211_HTCAP_GREENFIELD) != 0) + scaps |= (0x1 << WlanHTCaps_greenField); + if ((hcaps & IEEE80211_HTCAP_SHORTGI20) != 0) + scaps |= (0x1 << WlanHTCaps_shortGi20); + if ((hcaps & IEEE80211_HTCAP_SHORTGI40) != 0) + scaps |= (0x1 << WlanHTCaps_shortGi40); + if ((hcaps & IEEE80211_HTCAP_TXSTBC) != 0) + scaps |= (0x1 << WlanHTCaps_txStbc); + if ((hcaps & IEEE80211_HTCAP_DELBA) != 0) + scaps |= (0x1 << WlanHTCaps_delba); + if ((hcaps & IEEE80211_HTCAP_MAXAMSDU_7935) != 0) + scaps |= (0x1 << WlanHTCaps_amsdu7935); + if ((hcaps & IEEE80211_HTCAP_DSSSCCK40) != 0) + scaps |= (0x1 << WlanHTCaps_dssscck40); + if ((hcaps & IEEE80211_HTCAP_PSMP) != 0) + scaps |= (0x1 << WlanHTCaps_psmp); + if ((hcaps & IEEE80211_HTCAP_40INTOLERANT) != 0) + scaps |= (0x1 << WlanHTCaps_fortyMHzIntolerant); + if ((hcaps & IEEE80211_HTCAP_LSIGTXOPPROT) != 0) + scaps |= (0x1 << WlanHTCaps_lsigTxOpProt); + if ((hcaps & IEEE80211_HTC_AMPDU) != 0) + scaps |= (0x1 << WlanHTCaps_htcAmpdu); + if ((hcaps & IEEE80211_HTC_AMSDU) != 0) + scaps |= (0x1 << WlanHTCaps_htcAmsdu); + if ((hcaps & IEEE80211_HTC_HT) != 0) + scaps |= (0x1 << WlanHTCaps_htcHt); + if ((hcaps & IEEE80211_HTC_SMPS) != 0) + scaps |= (0x1 << WlanHTCaps_htcSmps); + if ((hcaps & IEEE80211_HTC_RIFS) != 0) + scaps |= (0x1 << WlanHTCaps_htcRifs); + + return (scaps); +} + +/* XXX: Not here? */ +#define WLAN_SET_TDMA_OPMODE(w) do { \ + if ((w)->mode == WlanIfaceOperatingModeType_adhocDemo && \ + ((w)->drivercaps & WlanDriverCaps_tdma) != 0) \ + (w)->mode = WlanIfaceOperatingModeType_tdma; \ +} while (0) +int +wlan_get_driver_caps(struct wlan_iface *wif) +{ + int val = 0; + size_t argsize; + struct ieee80211_devcaps_req dc; + + memset(&dc, 0, sizeof(struct ieee80211_devcaps_req)); + argsize = sizeof(struct ieee80211_devcaps_req); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_DEVCAPS, &val, &dc, + &argsize, 0) < 0) + return (-1); + + wif->drivercaps = wlan_drivercaps_to_snmp(dc.dc_drivercaps); + wif->cryptocaps = wlan_cryptocaps_to_snmp(dc.dc_cryptocaps); + wif->htcaps = wlan_htcaps_to_snmp(dc.dc_htcaps); + + WLAN_SET_TDMA_OPMODE(wif); + + argsize = dc.dc_chaninfo.ic_nchans * sizeof(struct ieee80211_channel); + wif->chanlist = (struct ieee80211_channel *)malloc(argsize); + if (wif->chanlist == NULL) + return (0); + + memcpy(wif->chanlist, dc.dc_chaninfo.ic_chans, argsize); + wif->nchannels = dc.dc_chaninfo.ic_nchans; + + return (0); +} + +uint8_t +wlan_channel_state_to_snmp(uint8_t cstate) +{ + uint8_t cs = 0; + + if ((cstate & IEEE80211_CHANSTATE_RADAR) != 0) + cs |= (0x1 << WlanIfaceChannelStateType_radar); + if ((cstate & IEEE80211_CHANSTATE_CACDONE) != 0) + cs |= (0x1 << WlanIfaceChannelStateType_cacDone); + if ((cstate & IEEE80211_CHANSTATE_CWINT) != 0) + cs |= (0x1 << WlanIfaceChannelStateType_interferenceDetected); + if ((cstate & IEEE80211_CHANSTATE_NORADAR) != 0) + cs |= (0x1 << WlanIfaceChannelStateType_radarClear); + + return (cs); +} + +uint32_t +wlan_channel_flags_to_snmp(uint32_t cflags) +{ + uint32_t cf = 0; + + if ((cflags & IEEE80211_CHAN_TURBO) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_turbo); + if ((cflags & IEEE80211_CHAN_CCK) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_cck); + if ((cflags & IEEE80211_CHAN_OFDM) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_ofdm); + if ((cflags & IEEE80211_CHAN_2GHZ) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_spectrum2Ghz); + if ((cflags & IEEE80211_CHAN_5GHZ) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_spectrum5Ghz); + if ((cflags & IEEE80211_CHAN_PASSIVE) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_passiveScan); + if ((cflags & IEEE80211_CHAN_DYN) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_dynamicCckOfdm); + if ((cflags & IEEE80211_CHAN_GFSK) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_gfsk); + if ((cflags & IEEE80211_CHAN_GSM) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_spectrum900Mhz); + if ((cflags & IEEE80211_CHAN_STURBO) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_dot11aStaticTurbo); + if ((cflags & IEEE80211_CHAN_HALF) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_halfRate); + if ((cflags & IEEE80211_CHAN_QUARTER) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_quarterRate); + if ((cflags & IEEE80211_CHAN_HT20) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_ht20); + if ((cflags & IEEE80211_CHAN_HT40U) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_ht40u); + if ((cflags & IEEE80211_CHAN_HT40D) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_ht40d); + if ((cflags & IEEE80211_CHAN_DFS) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_dfs); + if ((cflags & IEEE80211_CHAN_4MSXMIT) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_xmit4ms); + if ((cflags & IEEE80211_CHAN_NOADHOC) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_noAdhoc); + if ((cflags & IEEE80211_CHAN_NOHOSTAP) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_noHostAp); + if ((cflags & IEEE80211_CHAN_11D) != 0) + cf |= (0x1 << WlanIfaceChannelFlagsType_dot11d); + + return (cf); +} + +/* XXX: */ +#define WLAN_SNMP_MAX_CHANS 256 +int +wlan_get_channel_list(struct wlan_iface *wif) +{ + int val = 0; + uint32_t i, nchans; + size_t argsize; + struct ieee80211req_chaninfo *chaninfo; + struct ieee80211req_chanlist active; + const struct ieee80211_channel *c; + + argsize = sizeof(struct ieee80211req_chaninfo) + + sizeof(struct ieee80211_channel) * WLAN_SNMP_MAX_CHANS; + chaninfo = (struct ieee80211req_chaninfo *)malloc(argsize); + if (chaninfo == NULL) + return (-1); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_CHANINFO, &val, chaninfo, + &argsize, 0) < 0) + return (-1); + + argsize = sizeof(active); + if (wlan_ioctl(wif->wname, IEEE80211_IOC_CHANLIST, &val, &active, + &argsize, 0) < 0) + goto error; + + for (i = 0, nchans = 0; i < chaninfo->ic_nchans; i++) { + c = &chaninfo->ic_chans[i]; + if (!isset(active.ic_channels, c->ic_ieee)) + continue; + nchans++; + } + wif->chanlist = (struct ieee80211_channel *)reallocf(wif->chanlist, + nchans * sizeof(*c)); + if (wif->chanlist == NULL) + goto error; + wif->nchannels = nchans; + for (i = 0, nchans = 0; i < chaninfo->ic_nchans; i++) { + c = &chaninfo->ic_chans[i]; + if (!isset(active.ic_channels, c->ic_ieee)) + continue; + memcpy(wif->chanlist + nchans, c, sizeof (*c)); + nchans++; + } + + free(chaninfo); + return (0); +error: + wif->nchannels = 0; + free(chaninfo); + return (-1); +} + +static enum WlanIfPhyMode +wlan_channel_flags_to_snmp_phy(uint32_t cflags) +{ + /* XXX: recheck */ + if ((cflags & IEEE80211_CHAN_A) != 0) + return (WlanIfPhyMode_dot11a); + if ((cflags & IEEE80211_CHAN_B) != 0) + return (WlanIfPhyMode_dot11b); + if ((cflags & IEEE80211_CHAN_G) != 0 || + (cflags & IEEE80211_CHAN_PUREG) != 0) + return (WlanIfPhyMode_dot11g); + if ((cflags & IEEE80211_CHAN_FHSS) != 0) + return (WlanIfPhyMode_fh); + if ((cflags & IEEE80211_CHAN_TURBO) != 0 && + (cflags & IEEE80211_CHAN_A) != 0) + return (WlanIfPhyMode_turboA); + if ((cflags & IEEE80211_CHAN_TURBO) != 0 && + (cflags & IEEE80211_CHAN_G) != 0) + return (WlanIfPhyMode_turboG); + if ((cflags & IEEE80211_CHAN_STURBO) != 0) + return (WlanIfPhyMode_sturboA); + if ((cflags & IEEE80211_CHAN_HALF) != 0) + return (WlanIfPhyMode_ofdmHalf); + if ((cflags & IEEE80211_CHAN_QUARTER) != 0) + return (WlanIfPhyMode_ofdmQuarter); + + return (WlanIfPhyMode_auto); +} + +int +wlan_get_roam_params(struct wlan_iface *wif) +{ + int val = 0; + size_t argsize; + + argsize = sizeof(struct ieee80211_roamparams_req); + if (wlan_ioctl(wif->wname, IEEE80211_IOC_ROAM, &val, + &wif->roamparams, &argsize, 0) < 0) + return (-1); + + return (0); +} + +int +wlan_get_tx_params(struct wlan_iface *wif) +{ + int val = 0; + size_t argsize; + + /* + * XXX: Reset IEEE80211_RATE_MCS bit on IEEE80211_MODE_11NA + * and IEEE80211_MODE_11NG modes. + */ + argsize = sizeof(struct ieee80211_txparams_req); + if (wlan_ioctl(wif->wname, IEEE80211_IOC_TXPARAMS, &val, + &wif->txparams, &argsize, 0) < 0) + return (-1); + + return (0); +} + +int +wlan_set_tx_params(struct wlan_iface *wif, int32_t pmode __unused) +{ + int val = 0; + size_t argsize; + + /* + * XXX: Set IEEE80211_RATE_MCS bit on IEEE80211_MODE_11NA + * and IEEE80211_MODE_11NG modes. + */ + argsize = sizeof(struct ieee80211_txparams_req); + if (wlan_ioctl(wif->wname, IEEE80211_IOC_TXPARAMS, &val, + &wif->txparams, &argsize, 1) < 0) + return (-1); + + return (0); +} + +int +wlan_clone_create(struct wlan_iface *wif) +{ + struct ifreq ifr; + struct ieee80211_clone_params wcp; + static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; + + memset(&wcp, 0, sizeof(wcp)); + memset(&ifr, 0, sizeof(ifr)); + + /* Sanity checks. */ + if (wif == NULL || wif->pname[0] == '\0' || wif->mode > WLAN_IFMODE_MAX) + return (SNMP_ERR_INCONS_VALUE); + + if (wif->mode == WlanIfaceOperatingModeType_wds && + memcmp(wif->dbssid, zerobssid, IEEE80211_ADDR_LEN) == 0) + return (SNMP_ERR_INCONS_VALUE); + + strlcpy(wcp.icp_parent, wif->pname, IFNAMSIZ); + if ((wif->flags & WlanIfaceFlagsType_uniqueBssid) != 0) + wcp.icp_flags |= IEEE80211_CLONE_BSSID; + if ((wif->flags & WlanIfaceFlagsType_noBeacons) != 0) + wcp.icp_flags |= IEEE80211_CLONE_NOBEACONS; + if (wif->mode == WlanIfaceOperatingModeType_wds && + (wif->flags & WlanIfaceFlagsType_wdsLegacy) != 0) + wcp.icp_flags |= IEEE80211_CLONE_WDSLEGACY; + + switch (wif->mode) { + case WlanIfaceOperatingModeType_ibss: + wcp.icp_opmode = IEEE80211_M_IBSS; + break; + case WlanIfaceOperatingModeType_station: + wcp.icp_opmode = IEEE80211_M_STA; + break; + case WlanIfaceOperatingModeType_wds: + wcp.icp_opmode = IEEE80211_M_WDS; + break; + case WlanIfaceOperatingModeType_adhocDemo: + wcp.icp_opmode = IEEE80211_M_AHDEMO; + break; + case WlanIfaceOperatingModeType_hostAp: + wcp.icp_opmode = IEEE80211_M_HOSTAP; + break; + case WlanIfaceOperatingModeType_monitor: + wcp.icp_opmode = IEEE80211_M_MONITOR; + break; + case WlanIfaceOperatingModeType_meshPoint: + wcp.icp_opmode = IEEE80211_M_MBSS; + break; + case WlanIfaceOperatingModeType_tdma: + wcp.icp_opmode = IEEE80211_M_AHDEMO; + wcp.icp_flags |= IEEE80211_CLONE_TDMA; + break; + } + + memcpy(wcp.icp_bssid, wif->dbssid, IEEE80211_ADDR_LEN); + if (memcmp(wif->dlmac, zerobssid, IEEE80211_ADDR_LEN) != 0) { + memcpy(wcp.icp_macaddr, wif->dlmac, IEEE80211_ADDR_LEN); + wcp.icp_flags |= IEEE80211_CLONE_MACADDR; + } + + strlcpy(ifr.ifr_name, wif->wname, IFNAMSIZ); + ifr.ifr_data = (caddr_t) &wcp; + + if (ioctl(sock, SIOCIFCREATE2, (caddr_t) &ifr) < 0) { + syslog(LOG_ERR, "wlan clone create: ioctl(SIOCIFCREATE2) " + "failed: %s", strerror(errno)); + return (SNMP_ERR_GENERR); + } + + return (SNMP_ERR_NOERROR); +} + +int +wlan_clone_destroy(struct wlan_iface *wif) +{ + struct ifreq ifr; + + if (wif == NULL) + return (SNMP_ERR_INCONS_VALUE); + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, wif->wname); + + if (ioctl(sock, SIOCIFDESTROY, &ifr) < 0) { + syslog(LOG_ERR, "wlan clone destroy: ioctl(SIOCIFDESTROY) " + "failed: %s", strerror(errno)); + return (SNMP_ERR_GENERR); + } + + return (SNMP_ERR_NOERROR); +} + +static int +wlan_config_snmp2ioctl(int which) +{ + int op; + + switch (which) { + case LEAF_wlanIfacePacketBurst: + op = IEEE80211_IOC_BURST; + break; + case LEAF_wlanIfaceCountryCode: + op = IEEE80211_IOC_REGDOMAIN; + break; + case LEAF_wlanIfaceRegDomain: + op = IEEE80211_IOC_REGDOMAIN; + break; + case LEAF_wlanIfaceDesiredSsid: + op = IEEE80211_IOC_SSID; + break; + case LEAF_wlanIfaceDesiredChannel: + op = IEEE80211_IOC_CURCHAN; + break; + case LEAF_wlanIfaceDynamicFreqSelection: + op = IEEE80211_IOC_DFS; + break; + case LEAF_wlanIfaceFastFrames: + op = IEEE80211_IOC_FF; + break; + case LEAF_wlanIfaceDturbo: + op = IEEE80211_IOC_TURBOP; + break; + case LEAF_wlanIfaceTxPower: + op = IEEE80211_IOC_TXPOWER; + break; + case LEAF_wlanIfaceFragmentThreshold: + op = IEEE80211_IOC_FRAGTHRESHOLD; + break; + case LEAF_wlanIfaceRTSThreshold: + op = IEEE80211_IOC_RTSTHRESHOLD; + break; + case LEAF_wlanIfaceWlanPrivacySubscribe: + op = IEEE80211_IOC_WPS; + break; + case LEAF_wlanIfaceBgScan: + op = IEEE80211_IOC_BGSCAN; + break; + case LEAF_wlanIfaceBgScanIdle: + op = IEEE80211_IOC_BGSCAN_IDLE; + break; + case LEAF_wlanIfaceBgScanInterval: + op = IEEE80211_IOC_BGSCAN_INTERVAL; + break; + case LEAF_wlanIfaceBeaconMissedThreshold: + op = IEEE80211_IOC_BMISSTHRESHOLD; + break; + case LEAF_wlanIfaceDesiredBssid: + op = IEEE80211_IOC_BSSID; + break; + case LEAF_wlanIfaceRoamingMode: + op = IEEE80211_IOC_ROAMING; + break; + case LEAF_wlanIfaceDot11d: + op = IEEE80211_IOC_DOTD; + break; + case LEAF_wlanIfaceDot11h: + op = IEEE80211_IOC_DOTH; + break; + case LEAF_wlanIfaceDynamicWds: + op = IEEE80211_IOC_DWDS; + break; + case LEAF_wlanIfacePowerSave: + op = IEEE80211_IOC_POWERSAVE; + break; + case LEAF_wlanIfaceApBridge: + op = IEEE80211_IOC_APBRIDGE; + break; + case LEAF_wlanIfaceBeaconInterval: + op = IEEE80211_IOC_BEACON_INTERVAL; + break; + case LEAF_wlanIfaceDtimPeriod: + op = IEEE80211_IOC_DTIM_PERIOD; + break; + case LEAF_wlanIfaceHideSsid: + op = IEEE80211_IOC_HIDESSID; + break; + case LEAF_wlanIfaceInactivityProccess: + op = IEEE80211_IOC_INACTIVITY; + break; + case LEAF_wlanIfaceDot11gProtMode: + op = IEEE80211_IOC_PROTMODE; + break; + case LEAF_wlanIfaceDot11gPureMode: + op = IEEE80211_IOC_PUREG; + break; + case LEAF_wlanIfaceDot11nPureMode: + op = IEEE80211_IOC_PUREN; + break; + case LEAF_wlanIfaceDot11nAmpdu: + op = IEEE80211_IOC_AMPDU; + break; + case LEAF_wlanIfaceDot11nAmpduDensity: + op = IEEE80211_IOC_AMPDU_DENSITY; + break; + case LEAF_wlanIfaceDot11nAmpduLimit: + op = IEEE80211_IOC_AMPDU_LIMIT; + break; + case LEAF_wlanIfaceDot11nAmsdu: + op = IEEE80211_IOC_AMSDU; + break; + case LEAF_wlanIfaceDot11nAmsduLimit: + op = IEEE80211_IOC_AMSDU_LIMIT; + break; + case LEAF_wlanIfaceDot11nHighThroughput: + op = IEEE80211_IOC_HTCONF; + break; + case LEAF_wlanIfaceDot11nHTCompatible: + op = IEEE80211_IOC_HTCOMPAT; + break; + case LEAF_wlanIfaceDot11nHTProtMode: + op = IEEE80211_IOC_HTPROTMODE; + break; + case LEAF_wlanIfaceDot11nRIFS: + op = IEEE80211_IOC_RIFS; + break; + case LEAF_wlanIfaceDot11nShortGI: + op = IEEE80211_IOC_SHORTGI; + break; + case LEAF_wlanIfaceDot11nSMPSMode: + op = IEEE80211_IOC_SMPS; + break; + case LEAF_wlanIfaceTdmaSlot: + op = IEEE80211_IOC_TDMA_SLOT; + break; + case LEAF_wlanIfaceTdmaSlotCount: + op = IEEE80211_IOC_TDMA_SLOTCNT; + break; + case LEAF_wlanIfaceTdmaSlotLength: + op = IEEE80211_IOC_TDMA_SLOTLEN; + break; + case LEAF_wlanIfaceTdmaBeaconInterval: + op = IEEE80211_IOC_TDMA_BINTERVAL; + break; + default: + op = -1; + } + + return (op); +} + +static enum WlanRegDomainCode +wlan_regdomain_to_snmp(int which) +{ + enum WlanRegDomainCode reg_domain; + + switch (which) { + case SKU_FCC: + reg_domain = WlanRegDomainCode_fcc; + break; + case SKU_CA: + reg_domain = WlanRegDomainCode_ca; + break; + case SKU_ETSI: + reg_domain = WlanRegDomainCode_etsi; + break; + case SKU_ETSI2: + reg_domain = WlanRegDomainCode_etsi2; + break; + case SKU_ETSI3: + reg_domain = WlanRegDomainCode_etsi3; + break; + case SKU_FCC3: + reg_domain = WlanRegDomainCode_fcc3; + break; + case SKU_JAPAN: + reg_domain = WlanRegDomainCode_japan; + break; + case SKU_KOREA: + reg_domain = WlanRegDomainCode_korea; + break; + case SKU_APAC: + reg_domain = WlanRegDomainCode_apac; + break; + case SKU_APAC2: + reg_domain = WlanRegDomainCode_apac2; + break; + case SKU_APAC3: + reg_domain = WlanRegDomainCode_apac3; + break; + case SKU_ROW: + reg_domain = WlanRegDomainCode_row; + break; + case SKU_NONE: + reg_domain = WlanRegDomainCode_none; + break; + case SKU_DEBUG: + reg_domain = WlanRegDomainCode_debug; + break; + case SKU_SR9: + reg_domain = WlanRegDomainCode_sr9; + break; + case SKU_XR9: + reg_domain = WlanRegDomainCode_xr9; + break; + case SKU_GZ901: + reg_domain = WlanRegDomainCode_gz901; + break; + case 0: + reg_domain = WlanRegDomainCode_none; + break; + default: + syslog(LOG_ERR, "unknown regdomain (0x%x) ", which); + reg_domain = WlanRegDomainCode_none; + break; + } + + return (reg_domain); +} + +static int +wlan_snmp_to_regdomain(enum WlanRegDomainCode regdomain) +{ + int which; + + switch (regdomain) { + case WlanRegDomainCode_fcc: + which = SKU_FCC; + break; + case WlanRegDomainCode_ca: + which = SKU_CA; + break; + case WlanRegDomainCode_etsi: + which = SKU_ETSI; + break; + case WlanRegDomainCode_etsi2: + which = SKU_ETSI2; + break; + case WlanRegDomainCode_etsi3: + which = SKU_ETSI3; + break; + case WlanRegDomainCode_fcc3: + which = SKU_FCC3; + break; + case WlanRegDomainCode_japan: + which = SKU_JAPAN; + break; + case WlanRegDomainCode_korea: + which = SKU_KOREA; + break; + case WlanRegDomainCode_apac: + which = SKU_APAC; + break; + case WlanRegDomainCode_apac2: + which = SKU_APAC2; + break; + case WlanRegDomainCode_apac3: + which = SKU_APAC3; + break; + case WlanRegDomainCode_row: + which = SKU_ROW; + break; + case WlanRegDomainCode_none: + which = SKU_NONE; + break; + case WlanRegDomainCode_debug: + which = SKU_DEBUG; + break; + case WlanRegDomainCode_sr9: + which = SKU_SR9; + break; + case WlanRegDomainCode_xr9: + which = SKU_XR9; + break; + case WlanRegDomainCode_gz901: + which = SKU_GZ901; + break; + default: + syslog(LOG_ERR, "unknown snmp regdomain (0x%x) ", regdomain); + which = SKU_NONE; + break; + } + + return (which); +} + +static int +wlan_config_get_country(struct wlan_iface *wif) +{ + int val = 0; + size_t argsize; + struct ieee80211_regdomain regdomain; + + memset(®domain, 0, sizeof(regdomain)); + argsize = sizeof(regdomain); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_REGDOMAIN, &val, ®domain, + &argsize, 0) < 0) + return (-1); + + wif->reg_domain = wlan_regdomain_to_snmp(regdomain.regdomain); + wif->country_code[0] = regdomain.isocc[0]; + wif->country_code[1] = regdomain.isocc[1]; + wif->country_code[2] = regdomain.location; + + return (0); +} + +static int +wlan_config_set_country(struct wlan_iface *wif, char *ccode, int rdomain) +{ + int val = 0, txpowermax; + uint32_t i; + size_t argsize = 0; + struct ieee80211_regdomain_req *regdomain; + + if (wlan_get_channel_list(wif) < 0) + return (-1); + + if (wif->nchannels == 0) { + syslog(LOG_ERR, "iface %s - set regdomain failed", wif->wname); + return (-1); + } + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_TXPOWMAX, &txpowermax, 0, + &argsize, 0) < 0) + return (-1); + + regdomain = malloc(IEEE80211_REGDOMAIN_SIZE(wif->nchannels)); + if (regdomain == NULL) + return (-1); + memset(regdomain, 0, IEEE80211_REGDOMAIN_SIZE(wif->nchannels)); + argsize = IEEE80211_REGDOMAIN_SIZE(wif->nchannels); + + /* XXX: recheck with how this is done by ifconfig(8) */ + regdomain->rd.regdomain = wlan_snmp_to_regdomain(rdomain); + regdomain->rd.isocc[0] = ccode[0]; + regdomain->rd.isocc[1] = ccode[1]; + regdomain->rd.location = ccode[2]; + + /* XXX: fill the channel list properly */ + regdomain->chaninfo.ic_nchans = wif->nchannels; + memcpy(regdomain->chaninfo.ic_chans, wif->chanlist, + wif->nchannels * sizeof(struct ieee80211_channel)); + for (i = 0; i < wif->nchannels; i++) + regdomain->chaninfo.ic_chans[i].ic_maxregpower = txpowermax; + + wif->state = wlanIfaceState_down; + if (wlan_config_state(wif, 1) < 0 || + wlan_ioctl(wif->wname, IEEE80211_IOC_REGDOMAIN, &val, regdomain, + &argsize, 1) < 0) { + free(regdomain); + return (-1); + } + + wif->state = wlanIfaceState_up; + (void)wlan_config_state(wif, 1); + wif->reg_domain = wlan_regdomain_to_snmp(regdomain->rd.regdomain); + wif->country_code[0] = regdomain->rd.isocc[0]; + wif->country_code[1] = regdomain->rd.isocc[1]; + wif->country_code[2] = regdomain->rd.location; + free(regdomain); + + return (0); +} + +int +wlan_config_get_dssid(struct wlan_iface *wif) +{ + int val = -1; + size_t argsize = IEEE80211_NWID_LEN + 1; + char ssid[IEEE80211_NWID_LEN + 1]; + + memset(ssid, 0, IEEE80211_NWID_LEN + 1); + + if (wlan_ioctl(wif->wname, + (wif->mode == WlanIfaceOperatingModeType_meshPoint) ? + IEEE80211_IOC_MESH_ID : IEEE80211_IOC_SSID, &val, ssid, + &argsize, 0) < 0) + return (-1); + + if (argsize > IEEE80211_NWID_LEN) + argsize = IEEE80211_NWID_LEN; + memcpy(wif->desired_ssid, ssid, argsize); + wif->desired_ssid[argsize] = '\0'; + + return (0); +} + +int +wlan_config_set_dssid(struct wlan_iface *wif, char *ssid, int slen) +{ + int val = 0; + size_t argsize = slen; + + if (wlan_ioctl(wif->wname, + (wif->mode == WlanIfaceOperatingModeType_meshPoint) ? + IEEE80211_IOC_MESH_ID : IEEE80211_IOC_SSID, &val, ssid, + &argsize, 1) < 0) + return (-1); + + if (argsize > IEEE80211_NWID_LEN) + argsize = IEEE80211_NWID_LEN; + memcpy(wif->desired_ssid, ssid, argsize); + wif->desired_ssid[argsize] = '\0'; + + return (0); +} + +static int +wlan_config_get_dchannel(struct wlan_iface *wif) +{ + uint32_t i = 0; + int val = 0; + size_t argsize = sizeof(struct ieee80211_channel); + struct ieee80211_channel chan; + + if (wlan_get_channel_list(wif) < 0) + return (-1); + + memset(&chan, 0, sizeof(chan)); + if (wlan_ioctl(wif->wname, IEEE80211_IOC_CURCHAN, &val, &chan, + &argsize, 0) < 0) + return (-1); + + for (i = 0; i < wif->nchannels; i++) + if (chan.ic_ieee == wif->chanlist[i].ic_ieee && + chan.ic_flags == wif->chanlist[i].ic_flags) { + wif->desired_channel = i + 1; + break; + } + + return (0); +} + +static int +wlan_config_set_dchannel(struct wlan_iface *wif, uint32_t dchannel) +{ + int val = 0; + size_t argsize = sizeof(struct ieee80211_channel); + struct ieee80211_channel chan; + + if (wlan_get_channel_list(wif) < 0) + return (-1); + + if (dchannel > wif->nchannels) + return (-1); + + memcpy(&chan, wif->chanlist + dchannel - 1, sizeof(chan)); + if (wlan_ioctl(wif->wname, IEEE80211_IOC_CURCHAN, &val, &chan, + &argsize, 1) < 0) + return (-1); + + wif->desired_channel = dchannel; + + return (0); +} + +static int +wlan_config_get_bssid(struct wlan_iface *wif) +{ + int val = 0; + size_t argsize = IEEE80211_ADDR_LEN; + char bssid[IEEE80211_ADDR_LEN]; + + memset(bssid, 0, IEEE80211_ADDR_LEN); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_BSSID, &val, bssid, + &argsize, 0) < 0 || argsize != IEEE80211_ADDR_LEN) + return (-1); + + memcpy(wif->desired_bssid, bssid, IEEE80211_ADDR_LEN); + + return (0); +} + +static int +wlan_config_set_bssid(struct wlan_iface *wif, uint8_t *bssid) +{ + int val = 0; + size_t argsize = IEEE80211_ADDR_LEN; + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_BSSID, &val, bssid, + &argsize, 1) < 0 || argsize != IEEE80211_ADDR_LEN) + return (-1); + + memcpy(wif->desired_bssid, bssid, IEEE80211_ADDR_LEN); + + return (0); +} + +/* + * Convert the value returned by the kernel to the appropriate SNMP + * representation and set the corresponding interface member accordingly. + */ +static void +wlan_config_set_snmp_intval(struct wlan_iface *wif, int op, int val) +{ + switch (op) { + case IEEE80211_IOC_BURST: + if (val == 0) + wif->packet_burst = TruthValue_false; + else + wif->packet_burst = TruthValue_true; + break; + case IEEE80211_IOC_DFS: + if (val == 0) + wif->dyn_frequency = TruthValue_false; + else + wif->dyn_frequency = TruthValue_true; + break; + case IEEE80211_IOC_FF: + if (val == 0) + wif->fast_frames = TruthValue_false; + else + wif->fast_frames = TruthValue_true; + break; + case IEEE80211_IOC_TURBOP: + if (val == 0) + wif->dturbo = TruthValue_false; + else + wif->dturbo = TruthValue_true; + break; + case IEEE80211_IOC_TXPOWER: + wif->tx_power = val / 2; + break; + case IEEE80211_IOC_FRAGTHRESHOLD: + wif->frag_threshold = val; + break; + case IEEE80211_IOC_RTSTHRESHOLD: + wif->rts_threshold = val; + break; + case IEEE80211_IOC_WPS: + if (val == 0) + wif->priv_subscribe = TruthValue_false; + else + wif->priv_subscribe = TruthValue_true; + break; + case IEEE80211_IOC_BGSCAN: + if (val == 0) + wif->bg_scan = TruthValue_false; + else + wif->bg_scan = TruthValue_true; + break; + case IEEE80211_IOC_BGSCAN_IDLE: + wif->bg_scan_idle = val; + break; + case IEEE80211_IOC_BGSCAN_INTERVAL: + wif->bg_scan_interval = val; + break; + case IEEE80211_IOC_BMISSTHRESHOLD: + wif->beacons_missed = val; + break; + case IEEE80211_IOC_ROAMING: + switch (val) { + case IEEE80211_ROAMING_DEVICE: + wif->roam_mode = wlanIfaceRoamingMode_device; + break; + case IEEE80211_ROAMING_MANUAL: + wif->roam_mode = wlanIfaceRoamingMode_manual; + break; + case IEEE80211_ROAMING_AUTO: + /* FALTHROUGH */ + default: + wif->roam_mode = wlanIfaceRoamingMode_auto; + break; + } + break; + case IEEE80211_IOC_DOTD: + if (val == 0) + wif->dot11d = TruthValue_false; + else + wif->dot11d = TruthValue_true; + break; + case IEEE80211_IOC_DOTH: + if (val == 0) + wif->dot11h = TruthValue_false; + else + wif->dot11h = TruthValue_true; + break; + case IEEE80211_IOC_DWDS: + if (val == 0) + wif->dynamic_wds = TruthValue_false; + else + wif->dynamic_wds = TruthValue_true; + break; + case IEEE80211_IOC_POWERSAVE: + if (val == 0) + wif->power_save = TruthValue_false; + else + wif->power_save = TruthValue_true; + break; + case IEEE80211_IOC_APBRIDGE: + if (val == 0) + wif->ap_bridge = TruthValue_false; + else + wif->ap_bridge = TruthValue_true; + break; + case IEEE80211_IOC_BEACON_INTERVAL: + wif->beacon_interval = val; + break; + case IEEE80211_IOC_DTIM_PERIOD: + wif->dtim_period = val; + break; + case IEEE80211_IOC_HIDESSID: + if (val == 0) + wif->hide_ssid = TruthValue_false; + else + wif->hide_ssid = TruthValue_true; + break; + case IEEE80211_IOC_INACTIVITY: + if (val == 0) + wif->inact_process = TruthValue_false; + else + wif->inact_process = TruthValue_true; + break; + case IEEE80211_IOC_PROTMODE: + switch (val) { + case IEEE80211_PROTMODE_CTS: + wif->do11g_protect = wlanIfaceDot11gProtMode_cts; + break; + case IEEE80211_PROTMODE_RTSCTS: + wif->do11g_protect = wlanIfaceDot11gProtMode_rtscts; + break; + case IEEE80211_PROTMODE_OFF: + /* FALLTHROUGH */ + default: + wif->do11g_protect = wlanIfaceDot11gProtMode_off; + break; + } + break; + case IEEE80211_IOC_PUREG: + if (val == 0) + wif->dot11g_pure = TruthValue_false; + else + wif->dot11g_pure = TruthValue_true; + break; + case IEEE80211_IOC_PUREN: + if (val == 0) + wif->dot11n_pure = TruthValue_false; + else + wif->dot11n_pure = TruthValue_true; + break; + case IEEE80211_IOC_AMPDU: + switch (val) { + case 0: + wif->ampdu = WlanIfaceDot11nPduType_disabled; + break; + case 1: + wif->ampdu = WlanIfaceDot11nPduType_txOnly; + break; + case 2: + wif->ampdu = WlanIfaceDot11nPduType_rxOnly; + break; + case 3: + /* FALLTHROUGH */ + default: + wif->ampdu = WlanIfaceDot11nPduType_txAndRx; + break; + } + break; + case IEEE80211_IOC_AMPDU_DENSITY: + switch (val) { + case IEEE80211_HTCAP_MPDUDENSITY_025: + wif->ampdu_density = 25; + break; + case IEEE80211_HTCAP_MPDUDENSITY_05: + wif->ampdu_density = 50; + break; + case IEEE80211_HTCAP_MPDUDENSITY_1: + wif->ampdu_density = 100; + break; + case IEEE80211_HTCAP_MPDUDENSITY_2: + wif->ampdu_density = 200; + break; + case IEEE80211_HTCAP_MPDUDENSITY_4: + wif->ampdu_density = 400; + break; + case IEEE80211_HTCAP_MPDUDENSITY_8: + wif->ampdu_density = 800; + break; + case IEEE80211_HTCAP_MPDUDENSITY_16: + wif->ampdu_density = 1600; + break; + case IEEE80211_HTCAP_MPDUDENSITY_NA: + default: + wif->ampdu_density = 0; + break; + } + break; + case IEEE80211_IOC_AMPDU_LIMIT: + switch (val) { + case IEEE80211_HTCAP_MAXRXAMPDU_8K: + wif->ampdu_limit = 8192; + break; + case IEEE80211_HTCAP_MAXRXAMPDU_16K: + wif->ampdu_limit = 16384; + break; + case IEEE80211_HTCAP_MAXRXAMPDU_32K: + wif->ampdu_limit = 32768; + break; + case IEEE80211_HTCAP_MAXRXAMPDU_64K: + default: + wif->ampdu_limit = 65536; + break; + } + break; + case IEEE80211_IOC_AMSDU: + switch (val) { + case 0: + wif->amsdu = WlanIfaceDot11nPduType_disabled; + break; + case 1: + wif->amsdu = WlanIfaceDot11nPduType_txOnly; + break; + case 3: + wif->amsdu = WlanIfaceDot11nPduType_txAndRx; + break; + case 2: + default: + /* FALLTHROUGH */ + wif->amsdu = WlanIfaceDot11nPduType_rxOnly; + break; + } + break; + case IEEE80211_IOC_AMSDU_LIMIT: + wif->amsdu_limit = val; + break; + case IEEE80211_IOC_HTCONF: + if (val == 0) /* XXX */ + wif->ht_enabled = TruthValue_false; + else + wif->ht_enabled = TruthValue_true; + break; + case IEEE80211_IOC_HTCOMPAT: + if (val == 0) + wif->ht_compatible = TruthValue_false; + else + wif->ht_compatible = TruthValue_true; + break; + case IEEE80211_IOC_HTPROTMODE: + if (val == IEEE80211_PROTMODE_RTSCTS) + wif->ht_prot_mode = wlanIfaceDot11nHTProtMode_rts; + else + wif->ht_prot_mode = wlanIfaceDot11nHTProtMode_off; + break; + case IEEE80211_IOC_RIFS: + if (val == 0) + wif->rifs = TruthValue_false; + else + wif->rifs = TruthValue_true; + break; + case IEEE80211_IOC_SHORTGI: + if (val == 0) + wif->short_gi = TruthValue_false; + else + wif->short_gi = TruthValue_true; + break; + case IEEE80211_IOC_SMPS: + switch (val) { + case IEEE80211_HTCAP_SMPS_DYNAMIC: + wif->smps_mode = wlanIfaceDot11nSMPSMode_dynamic; + break; + case IEEE80211_HTCAP_SMPS_ENA: + wif->smps_mode = wlanIfaceDot11nSMPSMode_static; + break; + case IEEE80211_HTCAP_SMPS_OFF: + /* FALLTHROUGH */ + default: + wif->smps_mode = wlanIfaceDot11nSMPSMode_disabled; + break; + } + break; + case IEEE80211_IOC_TDMA_SLOT: + wif->tdma_slot = val; + break; + case IEEE80211_IOC_TDMA_SLOTCNT: + wif->tdma_slot_count = val; + break; + case IEEE80211_IOC_TDMA_SLOTLEN: + wif->tdma_slot_length = val; + break; + case IEEE80211_IOC_TDMA_BINTERVAL: + wif->tdma_binterval = val; + break; + default: + break; + } +} + +/* + * Convert an SNMP value to the kernel equivalent and also do sanity check + * for each specific type. + */ +static int +wlan_config_snmp2value(int which, int sval, int *value) +{ + *value = 0; + + switch (which) { + case IEEE80211_IOC_BURST: + case IEEE80211_IOC_DFS: + case IEEE80211_IOC_FF: + case IEEE80211_IOC_TURBOP: + case IEEE80211_IOC_WPS: + case IEEE80211_IOC_BGSCAN: + case IEEE80211_IOC_DOTD: + case IEEE80211_IOC_DOTH: + case IEEE80211_IOC_DWDS: + case IEEE80211_IOC_POWERSAVE: + case IEEE80211_IOC_APBRIDGE: + case IEEE80211_IOC_HIDESSID: + case IEEE80211_IOC_INACTIVITY: + case IEEE80211_IOC_PUREG: + case IEEE80211_IOC_PUREN: + case IEEE80211_IOC_HTCONF: + case IEEE80211_IOC_HTCOMPAT: + case IEEE80211_IOC_RIFS: + if (sval == TruthValue_true) + *value = 1; + else if (sval != TruthValue_false) + return (SNMP_ERR_INCONS_VALUE); + break; + case IEEE80211_IOC_REGDOMAIN: + break; + case IEEE80211_IOC_SSID: + break; + case IEEE80211_IOC_CURCHAN: + break; + case IEEE80211_IOC_TXPOWER: + *value = sval * 2; + break; + case IEEE80211_IOC_FRAGTHRESHOLD: + if (sval < IEEE80211_FRAG_MIN || sval > IEEE80211_FRAG_MAX) + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_RTSTHRESHOLD: + if (sval < IEEE80211_RTS_MIN || sval > IEEE80211_RTS_MAX) + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_BGSCAN_IDLE: + if (sval < WLAN_BGSCAN_IDLE_MIN) + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_BGSCAN_INTERVAL: + if (sval < WLAN_SCAN_VALID_MIN) + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_BMISSTHRESHOLD: + if (sval < IEEE80211_HWBMISS_MIN || sval > IEEE80211_HWBMISS_MAX) + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_BSSID: + break; + case IEEE80211_IOC_ROAMING: + switch (sval) { + case wlanIfaceRoamingMode_device: + *value = IEEE80211_ROAMING_DEVICE; + break; + case wlanIfaceRoamingMode_manual: + *value = IEEE80211_ROAMING_MANUAL; + break; + case wlanIfaceRoamingMode_auto: + *value = IEEE80211_ROAMING_AUTO; + break; + default: + return (SNMP_ERR_INCONS_VALUE); + } + break; + case IEEE80211_IOC_BEACON_INTERVAL: + if (sval < IEEE80211_BINTVAL_MIN || sval > IEEE80211_BINTVAL_MAX) + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_DTIM_PERIOD: + if (sval < IEEE80211_DTIM_MIN || sval > IEEE80211_DTIM_MAX) + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_PROTMODE: + switch (sval) { + case wlanIfaceDot11gProtMode_cts: + *value = IEEE80211_PROTMODE_CTS; + break; + case wlanIfaceDot11gProtMode_rtscts: + *value = IEEE80211_PROTMODE_RTSCTS; + break; + case wlanIfaceDot11gProtMode_off: + *value = IEEE80211_PROTMODE_OFF; + break; + default: + return (SNMP_ERR_INCONS_VALUE); + } + break; + case IEEE80211_IOC_AMPDU: + switch (sval) { + case WlanIfaceDot11nPduType_disabled: + break; + case WlanIfaceDot11nPduType_txOnly: + *value = 1; + break; + case WlanIfaceDot11nPduType_rxOnly: + *value = 2; + break; + case WlanIfaceDot11nPduType_txAndRx: + *value = 3; + break; + default: + return (SNMP_ERR_INCONS_VALUE); + } + break; + case IEEE80211_IOC_AMPDU_DENSITY: + switch (sval) { + case 0: + *value = IEEE80211_HTCAP_MPDUDENSITY_NA; + break; + case 25: + *value = IEEE80211_HTCAP_MPDUDENSITY_025; + break; + case 50: + *value = IEEE80211_HTCAP_MPDUDENSITY_05; + break; + case 100: + *value = IEEE80211_HTCAP_MPDUDENSITY_1; + break; + case 200: + *value = IEEE80211_HTCAP_MPDUDENSITY_2; + break; + case 400: + *value = IEEE80211_HTCAP_MPDUDENSITY_4; + break; + case 800: + *value = IEEE80211_HTCAP_MPDUDENSITY_8; + break; + case 1600: + *value = IEEE80211_HTCAP_MPDUDENSITY_16; + break; + default: + return (SNMP_ERR_INCONS_VALUE); + } + break; + case IEEE80211_IOC_AMPDU_LIMIT: + switch (sval) { + case 8192: + *value = IEEE80211_HTCAP_MAXRXAMPDU_8K; + break; + case 16384: + *value = IEEE80211_HTCAP_MAXRXAMPDU_16K; + break; + case 32768: + *value = IEEE80211_HTCAP_MAXRXAMPDU_32K; + break; + case 65536: + *value = IEEE80211_HTCAP_MAXRXAMPDU_64K; + break; + default: + return (SNMP_ERR_INCONS_VALUE); + } + break; + case IEEE80211_IOC_AMSDU: + switch (sval) { + case WlanIfaceDot11nPduType_disabled: + break; + case WlanIfaceDot11nPduType_txOnly: + *value = 1; + break; + case WlanIfaceDot11nPduType_rxOnly: + *value = 2; + break; + case WlanIfaceDot11nPduType_txAndRx: + *value = 3; + break; + default: + return (SNMP_ERR_INCONS_VALUE); + } + break; + case IEEE80211_IOC_AMSDU_LIMIT: + if (sval == 3839 || sval == 0) + *value = IEEE80211_HTCAP_MAXAMSDU_3839; + else if (sval == 7935) + *value = IEEE80211_HTCAP_MAXAMSDU_7935; + else + return (SNMP_ERR_INCONS_VALUE); + break; + case IEEE80211_IOC_HTPROTMODE: + switch (sval) { + case wlanIfaceDot11nHTProtMode_rts: + *value = IEEE80211_PROTMODE_RTSCTS; + break; + case wlanIfaceDot11nHTProtMode_off: + break; + default: + return (SNMP_ERR_INCONS_VALUE); + } + break; + case IEEE80211_IOC_SHORTGI: + if (sval == TruthValue_true) + *value = IEEE80211_HTCAP_SHORTGI20 | + IEEE80211_HTCAP_SHORTGI40; + else if (sval != TruthValue_false) + return (SNMP_ERR_INCONS_VALUE); + break; + case IEEE80211_IOC_SMPS: + switch (sval) { + case wlanIfaceDot11nSMPSMode_disabled: + *value = IEEE80211_HTCAP_SMPS_OFF; + break; + case wlanIfaceDot11nSMPSMode_static: + *value = IEEE80211_HTCAP_SMPS_ENA; + break; + case wlanIfaceDot11nSMPSMode_dynamic: + *value = IEEE80211_HTCAP_SMPS_DYNAMIC; + break; + default: + return (SNMP_ERR_INCONS_VALUE); + } + break; + case IEEE80211_IOC_TDMA_SLOT: + if (sval < 0 || sval > WLAN_TDMA_MAXSLOTS) /* XXX */ + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_TDMA_SLOTCNT: + if (sval < 0 || sval > WLAN_TDMA_MAXSLOTS) /* XXX */ + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_TDMA_SLOTLEN: + if (sval < 2*100 || sval > 0xfffff) /* XXX */ + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + case IEEE80211_IOC_TDMA_BINTERVAL: + if (sval < 1) /* XXX */ + return (SNMP_ERR_INCONS_VALUE); + *value = sval; + break; + default: + return (SNMP_ERR_INCONS_VALUE); + } + + return (SNMP_ERR_NOERROR); +} + +/* + * Sanity checks for the wlanIfaceConfigTable. + */ +static int +wlan_config_check(struct wlan_iface *wif, int op) +{ + switch (op) { + case IEEE80211_IOC_BURST: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_burst)) == 0) { + wif->packet_burst = TruthValue_false; + return (-1); + } + break; + case IEEE80211_IOC_DFS: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_dfs)) == 0) { + wif->dyn_frequency = TruthValue_false; + return (-1); + } + break; + case IEEE80211_IOC_FF: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_athFastFrames)) + == 0) { + wif->fast_frames = TruthValue_false; + return (-1); + } + break; + case IEEE80211_IOC_TURBOP: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_athTurbo)) == 0) { + wif->dturbo = TruthValue_false; + return (-1); + } + break; + case IEEE80211_IOC_TXPOWER: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_txPmgt)) == 0) { + wif->tx_power = 0; + return (-1); + } + break; + case IEEE80211_IOC_FRAGTHRESHOLD: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_txFrag)) == 0) { + wif->frag_threshold = IEEE80211_FRAG_MAX; + return (-1); + } + break; + case IEEE80211_IOC_DWDS: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_wds)) == 0) { + wif->dynamic_wds = TruthValue_false; + return (-1); + } + break; + case IEEE80211_IOC_POWERSAVE: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_pmgt)) == 0) { + wif->power_save = TruthValue_false; + return (-1); + } + break; + case IEEE80211_IOC_BEACON_INTERVAL: + if (wif->mode != WlanIfaceOperatingModeType_hostAp && + wif->mode != WlanIfaceOperatingModeType_meshPoint && + wif->mode != WlanIfaceOperatingModeType_ibss) { + wif->beacon_interval = 100; /* XXX */ + return (-1); + } + break; + case IEEE80211_IOC_DTIM_PERIOD: + if (wif->mode != WlanIfaceOperatingModeType_hostAp && + wif->mode != WlanIfaceOperatingModeType_meshPoint && + wif->mode != WlanIfaceOperatingModeType_ibss) { + wif->dtim_period = 1; /* XXX */ + return (-1); + } + break; + case IEEE80211_IOC_PUREN: + if ((wif->htcaps & (0x1 << WlanHTCaps_htcHt)) == 0) { + wif->dot11n_pure = TruthValue_false; + return (-1); + } + break; + case IEEE80211_IOC_AMPDU: + if ((wif->htcaps & (0x1 << WlanHTCaps_htcAmpdu)) == 0) { + wif->ampdu = WlanIfaceDot11nPduType_disabled; + return (-1); + } + break; + case IEEE80211_IOC_AMSDU: + if ((wif->htcaps & (0x1 << WlanHTCaps_htcAmsdu)) == 0) { + wif->amsdu = WlanIfaceDot11nPduType_disabled; + return (-1); + } + break; + case IEEE80211_IOC_RIFS: + if ((wif->htcaps & (0x1 << WlanHTCaps_htcRifs)) == 0) { + wif->rifs = TruthValue_false; + return (-1); + } + break; + case IEEE80211_IOC_SHORTGI: + if ((wif->htcaps & (0x1 << WlanHTCaps_shortGi20 | + 0x1 << WlanHTCaps_shortGi40)) == 0) { + wif->short_gi = TruthValue_false; + return (-1); + } + break; + case IEEE80211_IOC_SMPS: + if ((wif->htcaps & (0x1 << WlanHTCaps_htcSmps)) == 0) { + wif->smps_mode = wlanIfaceDot11nSMPSMode_disabled; + return (-1); + } + break; + case IEEE80211_IOC_TDMA_SLOT: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) { + wif->tdma_slot = 0; + return (-1); + } + break; + case IEEE80211_IOC_TDMA_SLOTCNT: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) { + wif->tdma_slot_count = 0; + return (-1); + } + break; + case IEEE80211_IOC_TDMA_SLOTLEN: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) { + wif->tdma_slot_length = 0; + return (-1); + } + break; + case IEEE80211_IOC_TDMA_BINTERVAL: + if ((wif->drivercaps & (0x1 << WlanDriverCaps_tdma)) == 0) { + wif->tdma_binterval = 0; + return (-1); + } + break; + default: + break; + } + + return (0); +} + +static int +wlan_config_get_intval(struct wlan_iface *wif, int op) +{ + int val = 0; + size_t argsize = 0; + + if (wlan_config_check(wif, op) < 0) + return (0); + if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 0) < 0) + return (-1); + wlan_config_set_snmp_intval(wif, op, val); + + return (0); +} + +static int +wlan_config_set_intval(struct wlan_iface *wif, int op, int sval) +{ + size_t argsize = 0; + int val; + + if (wlan_config_check(wif, op) < 0) + return (-1); + if (wlan_config_snmp2value(op, sval, &val) != SNMP_ERR_NOERROR) + return (-1); + if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 1) < 0) + return (-1); + wlan_config_set_snmp_intval(wif, op, val); + + return (0); +} + +int +wlan_config_get_ioctl(struct wlan_iface *wif, int which) +{ + int op; + + switch (which) { + case LEAF_wlanIfaceCountryCode: + /* FALLTHROUGH */ + case LEAF_wlanIfaceRegDomain: + return (wlan_config_get_country(wif)); + case LEAF_wlanIfaceDesiredSsid: + return (wlan_config_get_dssid(wif)); + case LEAF_wlanIfaceDesiredChannel: + return (wlan_config_get_dchannel(wif)); + case LEAF_wlanIfaceDesiredBssid: + return (wlan_config_get_bssid(wif)); + default: + op = wlan_config_snmp2ioctl(which); + return (wlan_config_get_intval(wif, op)); + } + + return (-1); +} + +int +wlan_config_set_ioctl(struct wlan_iface *wif, int which, int val, + char *strval, int len) +{ + int op; + + switch (which) { + case LEAF_wlanIfaceCountryCode: + return (wlan_config_set_country(wif, strval, + wif->reg_domain)); + case LEAF_wlanIfaceRegDomain: + return (wlan_config_set_country(wif, wif->country_code, + val)); + case LEAF_wlanIfaceDesiredSsid: + return (wlan_config_set_dssid(wif, strval, len)); + case LEAF_wlanIfaceDesiredChannel: + return (wlan_config_set_dchannel(wif, val)); + case LEAF_wlanIfaceDesiredBssid: + return (wlan_config_set_bssid(wif, strval)); + default: + op = wlan_config_snmp2ioctl(which); + return (wlan_config_set_intval(wif, op, val)); + } + + return (-1); +} + +static uint32_t +wlan_snmp_to_scan_flags(int flags) +{ + int sr_flags = 0; + + if ((flags & (0x1 << WlanScanFlagsType_noSelection)) != 0) + sr_flags |= IEEE80211_IOC_SCAN_NOPICK; + if ((flags & (0x1 << WlanScanFlagsType_activeScan)) != 0) + sr_flags |= IEEE80211_IOC_SCAN_ACTIVE; + if ((flags & (0x1 << WlanScanFlagsType_pickFirst)) != 0) + sr_flags |= IEEE80211_IOC_SCAN_PICK1ST; + if ((flags & (0x1 << WlanScanFlagsType_backgroundScan)) != 0) + sr_flags |= IEEE80211_IOC_SCAN_BGSCAN; + if ((flags & (0x1 << WlanScanFlagsType_once)) != 0) + sr_flags |= IEEE80211_IOC_SCAN_ONCE; + if ((flags & (0x1 << WlanScanFlagsType_noBroadcast)) != 0) + sr_flags |= IEEE80211_IOC_SCAN_NOBCAST; + if ((flags & (0x1 << WlanScanFlagsType_noAutoSequencing)) != 0) + sr_flags |= IEEE80211_IOC_SCAN_NOJOIN; + if ((flags & (0x1 << WlanScanFlagsType_flushCashe)) != 0) + sr_flags |= IEEE80211_IOC_SCAN_FLUSH; + if ((flags & (0x1 << WlanScanFlagsType_chechCashe)) != 0) + sr_flags |= IEEE80211_IOC_SCAN_CHECK; + + return (sr_flags); +} + +int +wlan_set_scan_config(struct wlan_iface *wif) +{ + int val = 0; + size_t argsize; + struct ieee80211_scan_req sr; + + + memset(&sr, 0, sizeof(sr)); + argsize = sizeof(struct ieee80211_scan_req); + sr.sr_flags = wlan_snmp_to_scan_flags(wif->scan_flags); + sr.sr_flags |= IEEE80211_IOC_SCAN_BGSCAN; + sr.sr_duration = wif->scan_duration; + sr.sr_mindwell = wif->scan_mindwell; + sr.sr_maxdwell = wif->scan_maxdwell; + sr.sr_nssid = 0; + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_SCAN_REQ, + &val, &sr, &argsize, 1) < 0) + return (-1); + + wif->scan_status = wlanScanConfigStatus_running; + return (0); +} + +static uint32_t +wlan_peercaps_to_snmp(uint32_t pcaps) +{ + uint32_t scaps = 0; + + if ((pcaps & IEEE80211_CAPINFO_ESS) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_ess); + if ((pcaps & IEEE80211_CAPINFO_IBSS) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_ibss); + if ((pcaps & IEEE80211_CAPINFO_CF_POLLABLE) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_cfPollable); + if ((pcaps & IEEE80211_CAPINFO_CF_POLLREQ) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_cfPollRequest); + if ((pcaps & IEEE80211_CAPINFO_PRIVACY) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_privacy); + if ((pcaps & IEEE80211_CAPINFO_SHORT_PREAMBLE) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_shortPreamble); + if ((pcaps & IEEE80211_CAPINFO_PBCC) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_pbcc); + if ((pcaps & IEEE80211_CAPINFO_CHNL_AGILITY) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_channelAgility); + if ((pcaps & IEEE80211_CAPINFO_SHORT_SLOTTIME) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_shortSlotTime); + if ((pcaps & IEEE80211_CAPINFO_RSN) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_rsn); + if ((pcaps & IEEE80211_CAPINFO_DSSSOFDM) != 0) + scaps |= (0x1 << WlanPeerCapabilityFlags_dsssofdm); + + return (scaps); +} + +static int +wlan_add_new_scan_result(struct wlan_iface *wif, + const struct ieee80211req_scan_result *isr, uint8_t *ssid) +{ + struct wlan_scan_result *sr; + + if ((sr = wlan_scan_new_result(ssid, isr->isr_bssid)) == NULL) + return (-1); + + sr->opchannel = wlan_channel_flags_to_snmp_phy(isr->isr_flags); + sr->rssi = isr->isr_rssi; + sr->frequency = isr->isr_freq; + sr->noise = isr->isr_noise; + sr->bintval = isr->isr_intval; + sr->capinfo = wlan_peercaps_to_snmp(isr->isr_capinfo); + + if (wlan_scan_add_result(wif, sr) < 0) { + wlan_scan_free_result(sr); + return (-1); + } + + return (0); +} + +int +wlan_get_scan_results(struct wlan_iface *wif) +{ + int ssidlen, val = 0; + uint8_t buf[24 * 1024]; + size_t argsize; + const uint8_t *cp, *idp; + uint8_t ssid[IEEE80211_NWID_LEN + 1]; + struct ieee80211req_scan_result isr; + + argsize = sizeof(buf); + if (wlan_ioctl(wif->wname, IEEE80211_IOC_SCAN_RESULTS, &val, &buf, + &argsize, 0) < 0) + return (-1); + + if (argsize < sizeof(struct ieee80211req_scan_result)) + return (0); + + cp = buf; + do { + memcpy(&isr, cp, sizeof(struct ieee80211req_scan_result)); + memset(ssid, 0, IEEE80211_NWID_LEN + 1); + + if (isr.isr_meshid_len) { + idp = cp + isr.isr_ie_off + isr.isr_ssid_len; + ssidlen = isr.isr_meshid_len; + } else { + idp = cp + isr.isr_ie_off; + ssidlen = isr.isr_ssid_len; + } + if (ssidlen > IEEE80211_NWID_LEN) + ssidlen = IEEE80211_NWID_LEN; + memcpy(ssid, idp, ssidlen); + ssid[IEEE80211_NWID_LEN] = '\0'; + (void)wlan_add_new_scan_result(wif, &isr, ssid); + cp += isr.isr_len; + argsize -= isr.isr_len; + } while (argsize >= sizeof(struct ieee80211req_scan_result)); + + return (0); +} + +int +wlan_get_stats(struct wlan_iface *wif) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(struct ifreq)); + strlcpy(ifr.ifr_name, wif->wname, IFNAMSIZ); + + ifr.ifr_data = (caddr_t) &wif->stats; + + if (ioctl(sock, SIOCG80211STATS, &ifr) < 0) { + syslog(LOG_ERR, "iface %s - ioctl(SIOCG80211STATS) failed: %s", + wif->wname, strerror(errno)); + return (-1); + } + + return (0); +} + +int +wlan_get_wepmode(struct wlan_iface *wif) +{ + int val = 0; + size_t argsize = 0; + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEP, &val, NULL, + &argsize, 0) < 0 || val == IEEE80211_WEP_NOSUP) { + wif->wepsupported = 0; /* XXX */ + wif->wepmode = wlanWepMode_off; + wif->weptxkey = 0; + return (-1); + } + + wif->wepsupported = 1; + + switch (val) { + case IEEE80211_WEP_ON: + wif->wepmode = wlanWepMode_on; + break; + case IEEE80211_WEP_MIXED: + wif->wepmode = wlanWepMode_mixed; + break; + case IEEE80211_WEP_OFF: + /* FALLTHROUGH */ + default: + wif->wepmode = wlanWepMode_off; + break; + } + + return (0); +} + +int +wlan_set_wepmode(struct wlan_iface *wif) +{ + int val; + size_t argsize = 0; + + if (!wif->wepsupported) + return (-1); + + switch (wif->wepmode) { + case wlanWepMode_off: + val = IEEE80211_WEP_OFF; + break; + case wlanWepMode_on: + val = IEEE80211_WEP_ON; + break; + case wlanWepMode_mixed: + val = IEEE80211_WEP_MIXED; + break; + default: + return (-1); + } + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEP, &val, NULL, + &argsize, 1) < 0) + return (-1); + + return (0); +} + +int +wlan_get_weptxkey(struct wlan_iface *wif) +{ + int val; + size_t argsize = 0; + + if (!wif->wepsupported) + return (0); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEPTXKEY, &val, NULL, + &argsize, 0) < 0) + return (-1); + + if (val == IEEE80211_KEYIX_NONE) + wif->weptxkey = 0; + else + wif->weptxkey = val + 1; + + return (0); +} + +int +wlan_set_weptxkey(struct wlan_iface *wif) +{ + int val; + size_t argsize = 0; + + if (!wif->wepsupported) + return (0); + + if (wif->weptxkey >= IEEE80211_WEP_NKID) + return (-1); + + if (wif->weptxkey == 0) + val = IEEE80211_KEYIX_NONE; + else + val = wif->weptxkey - 1; + if (wlan_ioctl(wif->wname, IEEE80211_IOC_WEPTXKEY, &val, NULL, + &argsize, 1) < 0) + return (-1); + + return (0); +} + +int +wlan_get_wepkeys(struct wlan_iface *wif __unused) +{ + /* XXX: should they be visible via SNMP */ + return (0); +} + +int +wlan_set_wepkeys(struct wlan_iface *wif __unused) +{ + /* XXX: should they be configurable via SNMP */ + return (0); +} + +int +wlan_get_mac_policy(struct wlan_iface *wif) +{ + int val = IEEE80211_MACCMD_POLICY; + size_t argsize = 0; + struct ieee80211req ireq; + + memset(&ireq, 0, sizeof(struct ieee80211req)); + strlcpy(ireq.i_name, wif->wname, IFNAMSIZ); + ireq.i_type = IEEE80211_IOC_MACCMD; + ireq.i_val = IEEE80211_MACCMD_POLICY; + + if (ioctl(sock, SIOCG80211, &ireq) < 0) { + if (errno != EINVAL) { + syslog(LOG_ERR, "iface %s - get param: ioctl(%d) " + "failed: %s", wif->wname, ireq.i_type, + strerror(errno)); + wif->macsupported = 0; + return (-1); + } else { + wif->macsupported = 1; + wif->mac_policy = wlanMACAccessControlPolicy_open; + return (0); + } + + } + + wif->macsupported = 1; + + switch (val) { + case IEEE80211_MACCMD_POLICY_ALLOW: + wif->mac_policy = wlanMACAccessControlPolicy_allow; + break; + case IEEE80211_MACCMD_POLICY_DENY: + wif->mac_policy = wlanMACAccessControlPolicy_deny; + break; + case IEEE80211_MACCMD_POLICY_RADIUS: + wif->mac_policy = wlanMACAccessControlPolicy_radius; + break; + case IEEE80211_MACCMD_POLICY_OPEN: + /* FALLTHROUGH */ + default: + wif->mac_policy = wlanMACAccessControlPolicy_open; + break; + } + + argsize = 0; + val = IEEE80211_MACCMD_LIST; + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, NULL, + &argsize, 0) < 0) + return (-1); + + wif->mac_nacls = argsize / sizeof(struct ieee80211req_maclist *); + return (0); +} + +int +wlan_set_mac_policy(struct wlan_iface *wif) +{ + int val; + size_t argsize = 0; + + if (!wif->macsupported) + return (-1); + + switch (wif->mac_policy) { + case wlanMACAccessControlPolicy_allow: + val = IEEE80211_MACCMD_POLICY_ALLOW; + break; + case wlanMACAccessControlPolicy_deny: + val = IEEE80211_MACCMD_POLICY_DENY; + break; + case wlanMACAccessControlPolicy_radius: + val = IEEE80211_MACCMD_POLICY_RADIUS; + break; + case wlanMACAccessControlPolicy_open: + val = IEEE80211_MACCMD_POLICY_OPEN; + break; + default: + return (-1); + } + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, NULL, + &argsize, 1) < 0) + return (-1); + + return (0); +} + +int +wlan_flush_mac_mac(struct wlan_iface *wif) +{ + int val = IEEE80211_MACCMD_FLUSH; + size_t argsize = 0; + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, NULL, + &argsize, 1) < 0) + return (-1); + + return (0); +} + +static int +wlan_add_mac_macinfo(struct wlan_iface *wif, + const struct ieee80211req_maclist *ml) +{ + struct wlan_mac_mac *mmac; + + if ((mmac = wlan_mac_new_mac(ml->ml_macaddr)) == NULL) + return (-1); + + mmac->mac_status = RowStatus_active; + if (wlan_mac_add_mac(wif, mmac) < 0) { + wlan_mac_free_mac(mmac); + return (-1); + } + + return (0); +} + +int +wlan_get_mac_acl_macs(struct wlan_iface *wif) +{ + int i, nacls, val = IEEE80211_MACCMD_LIST; + size_t argsize = 0; + uint8_t *data; + struct ieee80211req ireq; + const struct ieee80211req_maclist *acllist; + + if (wif->mac_policy == wlanMACAccessControlPolicy_radius) { + wif->mac_nacls = 0; + return (0); + } + + memset(&ireq, 0, sizeof(struct ieee80211req)); + strlcpy(ireq.i_name, wif->wname, IFNAMSIZ); + ireq.i_type = IEEE80211_IOC_MACCMD; + ireq.i_val = IEEE80211_MACCMD_LIST; + + + if (ioctl(sock, SIOCG80211, &ireq) < 0) { + if (errno != EINVAL) { + syslog(LOG_ERR, "iface %s - get param: ioctl(%d) " + "failed: %s", wif->wname, ireq.i_type, + strerror(errno)); + wif->macsupported = 0; + return (-1); + } + } + + if (argsize == 0) { + wif->mac_nacls = 0; + return (0); + } + + if ((data = (uint8_t *)malloc(argsize)) == NULL) + return (-1); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MACCMD, &val, data, + &argsize, 0) < 0) + return (-1); + + nacls = argsize / sizeof(*acllist); + acllist = (struct ieee80211req_maclist *) data; + for (i = 0; i < nacls; i++) + (void)wlan_add_mac_macinfo(wif, acllist + i); + + wif->mac_nacls = nacls; + return (0); +} + +int +wlan_add_mac_acl_mac(struct wlan_iface *wif, struct wlan_mac_mac *mmac) +{ + int val = 0; + size_t argsize = IEEE80211_ADDR_LEN; + struct ieee80211req_mlme mlme; + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_ADDMAC, &val, + mmac->mac, &argsize, 1) < 0) + return (-1); + + mmac->mac_status = RowStatus_active; + + /* If policy is deny, try to kick the station just in case. */ + if (wif->mac_policy != wlanMACAccessControlPolicy_deny) + return (0); + + memset(&mlme, 0, sizeof(mlme)); + mlme.im_op = IEEE80211_MLME_DEAUTH; + mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; + memcpy(mlme.im_macaddr, mmac->mac, IEEE80211_ADDR_LEN); + argsize = sizeof(struct ieee80211req_mlme); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MLME, &val, &mlme, + &argsize, 1) < 0 && errno != ENOENT) + return (-1); + + return (0); +} + +int +wlan_del_mac_acl_mac(struct wlan_iface *wif, struct wlan_mac_mac *mmac) +{ + int val = 0; + size_t argsize = IEEE80211_ADDR_LEN; + struct ieee80211req_mlme mlme; + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_DELMAC, &val, + mmac->mac, &argsize, 1) < 0) + return (-1); + + mmac->mac_status = RowStatus_active; + + /* If policy is allow, try to kick the station just in case. */ + if (wif->mac_policy != wlanMACAccessControlPolicy_allow) + return (0); + + memset(&mlme, 0, sizeof(mlme)); + mlme.im_op = IEEE80211_MLME_DEAUTH; + mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE; + memcpy(mlme.im_macaddr, mmac->mac, IEEE80211_ADDR_LEN); + argsize = sizeof(struct ieee80211req_mlme); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MLME, &val, &mlme, + &argsize, 1) < 0 && errno != ENOENT) + return (-1); + + return (0); +} + +int +wlan_peer_set_vlan(struct wlan_iface *wif, struct wlan_peer *wip, int vlan) +{ + int val = 0; + size_t argsize; + struct ieee80211req_sta_vlan vreq; + + memcpy(vreq.sv_macaddr, wip->pmac, IEEE80211_ADDR_LEN); + vreq.sv_vlan = vlan; + argsize = sizeof(struct ieee80211req_sta_vlan); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_STA_VLAN, + &val, &vreq, &argsize, 1) < 0) + return (-1); + + wip->vlan = vlan; + + return (0); +} + +/* XXX */ +#ifndef IEEE80211_NODE_AUTH +#define IEEE80211_NODE_AUTH 0x000001 /* authorized for data */ +#define IEEE80211_NODE_QOS 0x000002 /* QoS enabled */ +#define IEEE80211_NODE_ERP 0x000004 /* ERP enabled */ +#define IEEE80211_NODE_PWR_MGT 0x000010 /* power save mode enabled */ +#define IEEE80211_NODE_AREF 0x000020 /* authentication ref held */ +#define IEEE80211_NODE_HT 0x000040 /* HT enabled */ +#define IEEE80211_NODE_HTCOMPAT 0x000080 /* HT setup w/ vendor OUI's */ +#define IEEE80211_NODE_WPS 0x000100 /* WPS association */ +#define IEEE80211_NODE_TSN 0x000200 /* TSN association */ +#define IEEE80211_NODE_AMPDU_RX 0x000400 /* AMPDU rx enabled */ +#define IEEE80211_NODE_AMPDU_TX 0x000800 /* AMPDU tx enabled */ +#define IEEE80211_NODE_MIMO_PS 0x001000 /* MIMO power save enabled */ +#define IEEE80211_NODE_MIMO_RTS 0x002000 /* send RTS in MIMO PS */ +#define IEEE80211_NODE_RIFS 0x004000 /* RIFS enabled */ +#define IEEE80211_NODE_SGI20 0x008000 /* Short GI in HT20 enabled */ +#define IEEE80211_NODE_SGI40 0x010000 /* Short GI in HT40 enabled */ +#define IEEE80211_NODE_ASSOCID 0x020000 /* xmit requires associd */ +#define IEEE80211_NODE_AMSDU_RX 0x040000 /* AMSDU rx enabled */ +#define IEEE80211_NODE_AMSDU_TX 0x080000 /* AMSDU tx enabled */ +#endif + +static uint32_t +wlan_peerstate_to_snmp(uint32_t pstate) +{ + uint32_t sstate = 0; + + if ((pstate & IEEE80211_NODE_AUTH) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_authorizedForData); + if ((pstate & IEEE80211_NODE_QOS) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_qosEnabled); + if ((pstate & IEEE80211_NODE_ERP) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_erpEnabled); + if ((pstate & IEEE80211_NODE_PWR_MGT) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_powerSaveMode); + if ((pstate & IEEE80211_NODE_AREF) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_authRefHeld); + if ((pstate & IEEE80211_NODE_HT) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_htEnabled); + if ((pstate & IEEE80211_NODE_HTCOMPAT) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_htCompat); + if ((pstate & IEEE80211_NODE_WPS) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_wpsAssoc); + if ((pstate & IEEE80211_NODE_TSN) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_tsnAssoc); + if ((pstate & IEEE80211_NODE_AMPDU_RX) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_ampduRx); + if ((pstate & IEEE80211_NODE_AMPDU_TX) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_ampduTx); + if ((pstate & IEEE80211_NODE_MIMO_PS) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_mimoPowerSave); + if ((pstate & IEEE80211_NODE_MIMO_RTS) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_sendRts); + if ((pstate & IEEE80211_NODE_RIFS) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_rifs); + if ((pstate & IEEE80211_NODE_SGI20) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_shortGiHT20); + if ((pstate & IEEE80211_NODE_SGI40) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_shortGiHT40); + if ((pstate & IEEE80211_NODE_AMSDU_RX) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_amsduRx); + if ((pstate & IEEE80211_NODE_AMSDU_TX) != 0) + sstate |= (0x1 << WlanIfacePeerFlagsType_amsduTx); + + return (sstate); +} + +static struct wlan_peer * +wlan_add_peerinfo(const struct ieee80211req_sta_info *si) +{ + struct wlan_peer *wip; + + if ((wip = wlan_new_peer(si->isi_macaddr))== NULL) + return (NULL); + + wip->associd = IEEE80211_AID(si->isi_associd); + wip->vlan = si->isi_vlan; + wip->frequency = si->isi_freq; + wip->fflags = si->isi_flags; + wip->txrate = si->isi_txrate; + wip->rssi = si->isi_rssi; + wip->idle = si->isi_inact; + wip->txseqs = si->isi_txseqs[0]; /* XXX */ + wip->rxseqs = si->isi_rxseqs[0]; /* XXX */ + wip->txpower = si->isi_txpower; + wip->capinfo = wlan_peercaps_to_snmp(si->isi_capinfo); + wip->state = wlan_peerstate_to_snmp(si->isi_state); + wip->local_id = si->isi_localid; + wip->peer_id = si->isi_peerid; + + return (wip); +} + +int +wlan_get_peerinfo(struct wlan_iface *wif) +{ + union { + struct ieee80211req_sta_req req; + uint8_t buf[24 * 1024]; + } u; + const uint8_t *cp; + int val = 0; + size_t len; + struct ieee80211req_sta_info si; + struct wlan_peer *wip; + + /* Get all stations - broadcast address */ + (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); + len = sizeof(u); + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_STA_INFO, + & val, &u, &len, 0) < 0) + return (-1); + + if (len < sizeof(struct ieee80211req_sta_info)) + return (-1); + + cp = (const uint8_t *) u.req.info; + do { + memcpy(&si, cp, sizeof(struct ieee80211req_sta_info)); + if ((wip = wlan_add_peerinfo(&si)) != NULL && + wlan_add_peer(wif, wip) < 0) + wlan_free_peer(wip); + cp += si.isi_len, len -= si.isi_len; + } while (len >= sizeof(struct ieee80211req_sta_info)); + + return (0); +} + +/************************************************************************ + * Wireless MESH & HWMP sysctl config. + */ +const char wlan_sysctl_name[] = "net.wlan."; + +static const char *wlan_sysctl[] = { + "mesh.retrytimeout", + "mesh.holdingtimeout", + "mesh.confirmtimeout", + "mesh.maxretries", + "hwmp.targetonly", + "hwmp.replyforward", + "hwmp.pathlifetime", + "hwmp.roottimeout", + "hwmp.rootint", + "hwmp.rannint", + "hwmp.inact", +}; + +int32_t +wlan_do_sysctl(struct wlan_config *cfg, enum wlan_syscl which, int set) +{ + char mib_name[100]; + int val, sval; + size_t len, vlen; + + if (set) { + vlen = sizeof(sval); + switch (which) { + case WLAN_MESH_RETRY_TO: + sval = cfg->mesh_retryto; + break; + case WLAN_MESH_HOLDING_TO: + sval = cfg->mesh_holdingto; + break; + case WLAN_MESH_CONFIRM_TO: + sval = cfg->mesh_confirmto; + break; + case WLAN_MESH_MAX_RETRIES: + sval = cfg->mesh_maxretries; + break; + case WLAN_HWMP_TARGET_ONLY: + sval = cfg->hwmp_targetonly; + break; + case WLAN_HWMP_REPLY_FORWARD: + sval = cfg->hwmp_replyforward; + break; + case WLAN_HWMP_PATH_LIFETIME: + sval = cfg->hwmp_pathlifetime; + break; + case WLAN_HWMP_ROOT_TO: + sval = cfg->hwmp_roottimeout; + break; + case WLAN_HWMP_ROOT_INT: + sval = cfg->hwmp_rootint; + break; + case WLAN_HWMP_RANN_INT: + sval = cfg->hwmp_rannint; + break; + case WLAN_HWMP_INACTIVITY_TO: + sval = cfg->hwmp_inact; + break; + default: + return (-1); + } + } else { + if (which >= WLAN_SYSCTL_MAX) + return (-1); + vlen = 0; + } + + strlcpy(mib_name, wlan_sysctl_name, sizeof(mib_name)); + strlcat(mib_name, wlan_sysctl[which], sizeof(mib_name)); + len = sizeof (val); + + if (sysctlbyname(mib_name, &val, &len, (set? &sval : NULL), vlen) < 0) { + syslog(LOG_ERR, "sysctl(%s) failed - %s", mib_name, + strerror(errno)); + return (-1); + } + + switch (which) { + case WLAN_MESH_RETRY_TO: + cfg->mesh_retryto = val; + break; + case WLAN_MESH_HOLDING_TO: + cfg->mesh_holdingto = val; + break; + case WLAN_MESH_CONFIRM_TO: + cfg->mesh_confirmto = val; + break; + case WLAN_MESH_MAX_RETRIES: + cfg->mesh_maxretries = val; + break; + case WLAN_HWMP_TARGET_ONLY: + cfg->hwmp_targetonly = val; + break; + case WLAN_HWMP_REPLY_FORWARD: + cfg->hwmp_replyforward = val; + break; + case WLAN_HWMP_PATH_LIFETIME: + cfg->hwmp_pathlifetime = val; + break; + case WLAN_HWMP_ROOT_TO: + cfg->hwmp_roottimeout = val; + break; + case WLAN_HWMP_ROOT_INT: + cfg->hwmp_rootint = val; + break; + case WLAN_HWMP_RANN_INT: + cfg->hwmp_rannint = val; + break; + case WLAN_HWMP_INACTIVITY_TO: + cfg->hwmp_inact = val; + break; + default: + /* NOTREACHED */ + abort(); + } + + return (0); +} + +int +wlan_mesh_config_get(struct wlan_iface *wif, int which) +{ + int op, val = 0; + size_t argsize = 0; + uint8_t data[32], *pd = NULL; + + switch (which) { + case LEAF_wlanMeshTTL: + op = IEEE80211_IOC_MESH_TTL; + break; + case LEAF_wlanMeshPeeringEnabled: + op = IEEE80211_IOC_MESH_AP; + break; + case LEAF_wlanMeshForwardingEnabled: + op = IEEE80211_IOC_MESH_FWRD; + break; + case LEAF_wlanMeshMetric: + op = IEEE80211_IOC_MESH_PR_METRIC; + pd = data; + argsize = sizeof(data); + break; + case LEAF_wlanMeshPath: + op = IEEE80211_IOC_MESH_PR_PATH; + pd = data; + argsize = sizeof(data); + break; + case LEAF_wlanMeshRoutesFlush: + return (0); + default: + return (-1); + } + + if (wlan_ioctl(wif->wname, op, &val, pd, &argsize, 0) < 0) + return (-1); + + switch (which) { + case LEAF_wlanMeshTTL: + wif->mesh_ttl = val; + break; + case LEAF_wlanMeshPeeringEnabled: + if (val) + wif->mesh_peering = wlanMeshPeeringEnabled_true; + else + wif->mesh_peering = wlanMeshPeeringEnabled_false; + break; + case LEAF_wlanMeshForwardingEnabled: + if (val) + wif->mesh_forwarding = wlanMeshForwardingEnabled_true; + else + wif->mesh_forwarding = wlanMeshForwardingEnabled_false; + break; + case LEAF_wlanMeshMetric: + data[argsize] = '\0'; + if (strcmp(data, "AIRTIME") == 0) + wif->mesh_metric = wlanMeshMetric_airtime; + else + wif->mesh_metric = wlanMeshMetric_unknown; + break; + case LEAF_wlanMeshPath: + data[argsize] = '\0'; + if (strcmp(data, "HWMP") == 0) + wif->mesh_path = wlanMeshPath_hwmp; + else + wif->mesh_path = wlanMeshPath_unknown; + } + + return (0); +} + +int +wlan_mesh_config_set(struct wlan_iface *wif, int which) +{ + int op, val = 0; + size_t argsize = 0; + uint8_t data[32], *pd = NULL; + + switch (which) { + case LEAF_wlanMeshTTL: + op = IEEE80211_IOC_MESH_TTL; + val = wif->mesh_ttl; + break; + case LEAF_wlanMeshPeeringEnabled: + op = IEEE80211_IOC_MESH_AP; + if (wif->mesh_peering == wlanMeshPeeringEnabled_true) + val = 1; + break; + case LEAF_wlanMeshForwardingEnabled: + if (wif->mesh_forwarding == wlanMeshForwardingEnabled_true) + val = 1; + op = IEEE80211_IOC_MESH_FWRD; + break; + case LEAF_wlanMeshMetric: + op = IEEE80211_IOC_MESH_PR_METRIC; + if (wif->mesh_metric == wlanMeshMetric_airtime) + strcpy(data, "AIRTIME"); + else + return (-1); + pd = data; + argsize = sizeof(data); + break; + case LEAF_wlanMeshPath: + op = IEEE80211_IOC_MESH_PR_PATH; + if (wif->mesh_path == wlanMeshPath_hwmp) + strcpy(data, "HWMP"); + else + return (-1); + pd = data; + argsize = sizeof(data); + break; + default: + return (-1); + } + + if (wlan_ioctl(wif->wname, op, &val, pd, &argsize, 1) < 0) + return (-1); + + return(0); +} + +int +wlan_mesh_flush_routes(struct wlan_iface *wif) +{ + int val = IEEE80211_MESH_RTCMD_FLUSH; + size_t argsize = 0; + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val, NULL, + &argsize, 1) < 0) + return (-1); + + return (0); +} + +int +wlan_mesh_add_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr) +{ + int val = IEEE80211_MESH_RTCMD_ADD; + size_t argsize = IEEE80211_ADDR_LEN; + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val, + wmr->imroute.imr_dest, &argsize, 1) < 0) + return (-1); + + wmr->mroute_status = RowStatus_active; + + return (0); +} + +int +wlan_mesh_del_route(struct wlan_iface *wif, struct wlan_mesh_route *wmr) +{ + int val = IEEE80211_MESH_RTCMD_DELETE; + size_t argsize = IEEE80211_ADDR_LEN; + + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val, + wmr->imroute.imr_dest, &argsize, 1) < 0) + return (-1); + + wmr->mroute_status = RowStatus_destroy; + + return (0); +} + +int +wlan_mesh_get_routelist(struct wlan_iface *wif) +{ + int i, nroutes, val = IEEE80211_MESH_RTCMD_LIST; + size_t argsize; + struct ieee80211req_mesh_route routes[128]; + struct ieee80211req_mesh_route *rt; + struct wlan_mesh_route *wmr; + + argsize = sizeof(routes); + if (wlan_ioctl(wif->wname, IEEE80211_IOC_MESH_RTCMD, &val, routes, + &argsize, 0) < 0) /* XXX: ENOMEM? */ + return (-1); + + nroutes = argsize / sizeof(*rt); + for (i = 0; i < nroutes; i++) { + rt = routes + i; + if ((wmr = wlan_mesh_new_route(rt->imr_dest)) == NULL) + return (-1); + memcpy(&wmr->imroute, rt, sizeof(*rt)); + wmr->mroute_status = RowStatus_active; + if (wlan_mesh_add_rtentry(wif, wmr) < 0) + wlan_mesh_free_route(wmr); + } + + return (0); +} + +int +wlan_hwmp_config_get(struct wlan_iface *wif, int which) +{ + int op, val = 0; + size_t argsize = 0; + + switch (which) { + case LEAF_wlanHWMPRootMode: + op = IEEE80211_IOC_HWMP_ROOTMODE; + break; + case LEAF_wlanHWMPMaxHops: + op = IEEE80211_IOC_HWMP_MAXHOPS; + break; + default: + return (-1); + } + + if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 0) < 0) + return (-1); + + switch (which) { + case LEAF_wlanHWMPRootMode: + switch (val) { + case IEEE80211_HWMP_ROOTMODE_NORMAL: + wif->hwmp_root_mode = wlanHWMPRootMode_normal; + break; + case IEEE80211_HWMP_ROOTMODE_PROACTIVE: + wif->hwmp_root_mode = wlanHWMPRootMode_proactive; + break; + case IEEE80211_HWMP_ROOTMODE_RANN: + wif->hwmp_root_mode = wlanHWMPRootMode_rann; + break; + case IEEE80211_HWMP_ROOTMODE_DISABLED: + default: + wif->hwmp_root_mode = wlanHWMPRootMode_disabled; + break; + } + break; + case LEAF_wlanHWMPMaxHops: + wif->hwmp_max_hops = val; + break; + } + + return (0); +} + +int +wlan_hwmp_config_set(struct wlan_iface *wif, int which) +{ + int op, val = 0; + size_t argsize = 0; + + switch (which) { + case LEAF_wlanHWMPRootMode: + op = IEEE80211_IOC_HWMP_ROOTMODE; + switch (wif->hwmp_root_mode) { + case wlanHWMPRootMode_disabled: + val = IEEE80211_HWMP_ROOTMODE_DISABLED; + break; + case wlanHWMPRootMode_normal: + val = IEEE80211_HWMP_ROOTMODE_NORMAL; + break; + case wlanHWMPRootMode_proactive: + val = IEEE80211_HWMP_ROOTMODE_PROACTIVE; + break; + case wlanHWMPRootMode_rann: + val = IEEE80211_HWMP_ROOTMODE_RANN; + break; + default: + return (-1); + } + break; + case LEAF_wlanHWMPMaxHops: + op = IEEE80211_IOC_HWMP_MAXHOPS; + val = wif->hwmp_max_hops; + break; + default: + return (-1); + } + + if (wlan_ioctl(wif->wname, op, &val, NULL, &argsize, 1) < 0) + return (-1); + + return (0); +} |