aboutsummaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_ioctl.c
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2007-06-11 03:36:55 +0000
committerSam Leffler <sam@FreeBSD.org>2007-06-11 03:36:55 +0000
commit68e8e04e93c1ec3d37022223b69073f50d3d4981 (patch)
treee13543d4810ca316d27ca22651054eea880c1d34 /sys/net80211/ieee80211_ioctl.c
parentad7a4c3acd6e72aa12c2a1eaa8784bc919b57a80 (diff)
downloadsrc-68e8e04e93c1ec3d37022223b69073f50d3d4981.tar.gz
src-68e8e04e93c1ec3d37022223b69073f50d3d4981.zip
Update 802.11 wireless support:
o major overhaul of the way channels are handled: channels are now fully enumerated and uniquely identify the operating characteristics; these changes are visible to user applications which require changes o make scanning support independent of the state machine to enable background scanning and roaming o move scanning support into loadable modules based on the operating mode to enable different policies and reduce the memory footprint on systems w/ constrained resources o add background scanning in station mode (no support for adhoc/ibss mode yet) o significantly speedup sta mode scanning with a variety of techniques o add roaming support when background scanning is supported; for now we use a simple algorithm to trigger a roam: we threshold the rssi and tx rate, if either drops too low we try to roam to a new ap o add tx fragmentation support o add first cut at 802.11n support: this code works with forthcoming drivers but is incomplete; it's included now to establish a baseline for other drivers to be developed and for user applications o adjust max_linkhdr et. al. to reflect 802.11 requirements; this eliminates prepending mbufs for traffic generated locally o add support for Atheros protocol extensions; mainly the fast frames encapsulation (note this can be used with any card that can tx+rx large frames correctly) o add sta support for ap's that beacon both WPA1+2 support o change all data types from bsd-style to posix-style o propagate noise floor data from drivers to net80211 and on to user apps o correct various issues in the sta mode state machine related to handling authentication and association failures o enable the addition of sta mode power save support for drivers that need net80211 support (not in this commit) o remove old WI compatibility ioctls (wicontrol is officially dead) o change the data structures returned for get sta info and get scan results so future additions will not break user apps o fixed tx rate is now maintained internally as an ieee rate and not an index into the rate set; this needs to be extended to deal with multi-mode operation o add extended channel specifications to radiotap to enable 11n sniffing Drivers: o ath: add support for bg scanning, tx fragmentation, fast frames, dynamic turbo (lightly tested), 11n (sniffing only and needs new hal) o awi: compile tested only o ndis: lightly tested o ipw: lightly tested o iwi: add support for bg scanning (well tested but may have some rough edges) o ral, ural, rum: add suppoort for bg scanning, calibrate rssi data o wi: lightly tested This work is based on contributions by Atheros, kmacy, sephe, thompsa, mlaier, kevlo, and others. Much of the scanning work was supported by Atheros. The 11n work was supported by Marvell.
Notes
Notes: svn path=/head/; revision=170530
Diffstat (limited to 'sys/net80211/ieee80211_ioctl.c')
-rw-r--r--sys/net80211/ieee80211_ioctl.c1902
1 files changed, 852 insertions, 1050 deletions
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index 17befd23e1f2..5929eddad5a2 100644
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -62,752 +62,15 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_ioctl.h>
-#include <dev/wi/if_wavelan_ieee.h>
-
#define IS_UP(_ic) \
(((_ic)->ic_ifp->if_flags & IFF_UP) && \
((_ic)->ic_ifp->if_drv_flags & IFF_DRV_RUNNING))
#define IS_UP_AUTO(_ic) \
(IS_UP(_ic) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
+#define RESCAN 1
-/*
- * XXX
- * Wireless LAN specific configuration interface, which is compatible
- * with wicontrol(8).
- */
-
-struct wi_read_ap_args {
- int i; /* result count */
- struct wi_apinfo *ap; /* current entry in result buffer */
- caddr_t max; /* result buffer bound */
-};
-
-static void
-wi_read_ap_result(void *arg, struct ieee80211_node *ni)
-{
- struct ieee80211com *ic = ni->ni_ic;
- struct wi_read_ap_args *sa = arg;
- struct wi_apinfo *ap = sa->ap;
- struct ieee80211_rateset *rs;
- int j;
-
- if ((caddr_t)(ap + 1) > sa->max)
- return;
- memset(ap, 0, sizeof(struct wi_apinfo));
- if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
- IEEE80211_ADDR_COPY(ap->bssid, ni->ni_macaddr);
- ap->namelen = ic->ic_des_esslen;
- if (ic->ic_des_esslen)
- memcpy(ap->name, ic->ic_des_essid,
- ic->ic_des_esslen);
- } else {
- IEEE80211_ADDR_COPY(ap->bssid, ni->ni_bssid);
- ap->namelen = ni->ni_esslen;
- if (ni->ni_esslen)
- memcpy(ap->name, ni->ni_essid,
- ni->ni_esslen);
- }
- ap->channel = ieee80211_chan2ieee(ic, ni->ni_chan);
- ap->signal = ic->ic_node_getrssi(ni);
- ap->capinfo = ni->ni_capinfo;
- ap->interval = ni->ni_intval;
- rs = &ni->ni_rates;
- for (j = 0; j < rs->rs_nrates; j++) {
- if (rs->rs_rates[j] & IEEE80211_RATE_BASIC) {
- ap->rate = (rs->rs_rates[j] &
- IEEE80211_RATE_VAL) * 5; /* XXX */
- }
- }
- sa->i++;
- sa->ap++;
-}
-
-struct wi_read_prism2_args {
- int i; /* result count */
- struct wi_scan_res *res;/* current entry in result buffer */
- caddr_t max; /* result buffer bound */
-};
-
-static void
-wi_read_prism2_result(void *arg, struct ieee80211_node *ni)
-{
- struct ieee80211com *ic = ni->ni_ic;
- struct wi_read_prism2_args *sa = arg;
- struct wi_scan_res *res = sa->res;
-
- if ((caddr_t)(res + 1) > sa->max)
- return;
- res->wi_chan = ieee80211_chan2ieee(ic, ni->ni_chan);
- res->wi_noise = 0;
- res->wi_signal = ic->ic_node_getrssi(ni);
- IEEE80211_ADDR_COPY(res->wi_bssid, ni->ni_bssid);
- res->wi_interval = ni->ni_intval;
- res->wi_capinfo = ni->ni_capinfo;
- res->wi_ssid_len = ni->ni_esslen;
- memcpy(res->wi_ssid, ni->ni_essid, IEEE80211_NWID_LEN);
- /* NB: assumes wi_srates holds <= ni->ni_rates */
- memcpy(res->wi_srates, ni->ni_rates.rs_rates,
- sizeof(res->wi_srates));
- if (ni->ni_rates.rs_nrates < 10)
- res->wi_srates[ni->ni_rates.rs_nrates] = 0;
- res->wi_rate = ni->ni_rates.rs_rates[ni->ni_txrate];
- res->wi_rsvd = 0;
-
- sa->i++;
- sa->res++;
-}
-
-struct wi_read_sigcache_args {
- int i; /* result count */
- struct wi_sigcache *wsc;/* current entry in result buffer */
- caddr_t max; /* result buffer bound */
-};
-
-static void
-wi_read_sigcache(void *arg, struct ieee80211_node *ni)
-{
- struct ieee80211com *ic = ni->ni_ic;
- struct wi_read_sigcache_args *sa = arg;
- struct wi_sigcache *wsc = sa->wsc;
-
- if ((caddr_t)(wsc + 1) > sa->max)
- return;
- memset(wsc, 0, sizeof(struct wi_sigcache));
- IEEE80211_ADDR_COPY(wsc->macsrc, ni->ni_macaddr);
- wsc->signal = ic->ic_node_getrssi(ni);
-
- sa->wsc++;
- sa->i++;
-}
-
-int
-ieee80211_cfgget(struct ieee80211com *ic, u_long cmd, caddr_t data)
-{
- struct ifnet *ifp = ic->ic_ifp;
- int i, j, error;
- struct ifreq *ifr = (struct ifreq *)data;
- struct wi_req wreq;
- struct wi_ltv_keys *keys;
-
- error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
- if (error)
- return error;
- wreq.wi_len = 0;
- switch (wreq.wi_type) {
- case WI_RID_SERIALNO:
- /* nothing appropriate */
- break;
- case WI_RID_NODENAME:
- strcpy((char *)&wreq.wi_val[1], hostname);
- wreq.wi_val[0] = htole16(strlen(hostname));
- wreq.wi_len = (1 + strlen(hostname) + 1) / 2;
- break;
- case WI_RID_CURRENT_SSID:
- if (ic->ic_state != IEEE80211_S_RUN) {
- wreq.wi_val[0] = 0;
- wreq.wi_len = 1;
- break;
- }
- wreq.wi_val[0] = htole16(ic->ic_bss->ni_esslen);
- memcpy(&wreq.wi_val[1], ic->ic_bss->ni_essid,
- ic->ic_bss->ni_esslen);
- wreq.wi_len = (1 + ic->ic_bss->ni_esslen + 1) / 2;
- break;
- case WI_RID_OWN_SSID:
- case WI_RID_DESIRED_SSID:
- wreq.wi_val[0] = htole16(ic->ic_des_esslen);
- memcpy(&wreq.wi_val[1], ic->ic_des_essid, ic->ic_des_esslen);
- wreq.wi_len = (1 + ic->ic_des_esslen + 1) / 2;
- break;
- case WI_RID_CURRENT_BSSID:
- if (ic->ic_state == IEEE80211_S_RUN)
- IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_bss->ni_bssid);
- else
- memset(wreq.wi_val, 0, IEEE80211_ADDR_LEN);
- wreq.wi_len = IEEE80211_ADDR_LEN / 2;
- break;
- case WI_RID_CHANNEL_LIST:
- memset(wreq.wi_val, 0, sizeof(wreq.wi_val));
- /*
- * Since channel 0 is not available for DS, channel 1
- * is assigned to LSB on WaveLAN.
- */
- if (ic->ic_phytype == IEEE80211_T_DS)
- i = 1;
- else
- i = 0;
- for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++)
- if (isset(ic->ic_chan_active, i)) {
- setbit((u_int8_t *)wreq.wi_val, j);
- wreq.wi_len = j / 16 + 1;
- }
- break;
- case WI_RID_OWN_CHNL:
- wreq.wi_val[0] = htole16(
- ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
- wreq.wi_len = 1;
- break;
- case WI_RID_CURRENT_CHAN:
- wreq.wi_val[0] = htole16(
- ieee80211_chan2ieee(ic, ic->ic_curchan));
- wreq.wi_len = 1;
- break;
- case WI_RID_COMMS_QUALITY:
- wreq.wi_val[0] = 0; /* quality */
- wreq.wi_val[1] = htole16(ic->ic_node_getrssi(ic->ic_bss));
- wreq.wi_val[2] = 0; /* noise */
- wreq.wi_len = 3;
- break;
- case WI_RID_PROMISC:
- wreq.wi_val[0] = htole16((ifp->if_flags & IFF_PROMISC) ? 1 : 0);
- wreq.wi_len = 1;
- break;
- case WI_RID_PORTTYPE:
- wreq.wi_val[0] = htole16(ic->ic_opmode);
- wreq.wi_len = 1;
- break;
- case WI_RID_MAC_NODE:
- IEEE80211_ADDR_COPY(wreq.wi_val, ic->ic_myaddr);
- wreq.wi_len = IEEE80211_ADDR_LEN / 2;
- break;
- case WI_RID_TX_RATE:
- if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
- wreq.wi_val[0] = 0; /* auto */
- else
- wreq.wi_val[0] = htole16(
- (ic->ic_sup_rates[ic->ic_curmode].rs_rates[ic->ic_fixed_rate] &
- IEEE80211_RATE_VAL) / 2);
- wreq.wi_len = 1;
- break;
- case WI_RID_CUR_TX_RATE:
- wreq.wi_val[0] = htole16(
- (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] &
- IEEE80211_RATE_VAL) / 2);
- wreq.wi_len = 1;
- break;
- case WI_RID_RTS_THRESH:
- wreq.wi_val[0] = htole16(ic->ic_rtsthreshold);
- wreq.wi_len = 1;
- break;
- case WI_RID_CREATE_IBSS:
- wreq.wi_val[0] =
- htole16((ic->ic_flags & IEEE80211_F_IBSSON) ? 1 : 0);
- wreq.wi_len = 1;
- break;
- case WI_RID_MICROWAVE_OVEN:
- wreq.wi_val[0] = 0; /* no ... not supported */
- wreq.wi_len = 1;
- break;
- case WI_RID_ROAMING_MODE:
- wreq.wi_val[0] = htole16(ic->ic_roaming); /* XXX map */
- wreq.wi_len = 1;
- break;
- case WI_RID_SYSTEM_SCALE:
- wreq.wi_val[0] = htole16(1); /* low density ... not supp */
- wreq.wi_len = 1;
- break;
- case WI_RID_PM_ENABLED:
- wreq.wi_val[0] =
- htole16((ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
- wreq.wi_len = 1;
- break;
- case WI_RID_MAX_SLEEP:
- wreq.wi_val[0] = htole16(ic->ic_lintval);
- wreq.wi_len = 1;
- break;
- case WI_RID_CUR_BEACON_INT:
- wreq.wi_val[0] = htole16(ic->ic_bss->ni_intval);
- wreq.wi_len = 1;
- break;
- case WI_RID_WEP_AVAIL:
- wreq.wi_val[0] = htole16(1); /* always available */
- wreq.wi_len = 1;
- break;
- case WI_RID_CNFAUTHMODE:
- wreq.wi_val[0] = htole16(1); /* TODO: open system only */
- wreq.wi_len = 1;
- break;
- case WI_RID_ENCRYPTION:
- wreq.wi_val[0] =
- htole16((ic->ic_flags & IEEE80211_F_PRIVACY) ? 1 : 0);
- wreq.wi_len = 1;
- break;
- case WI_RID_TX_CRYPT_KEY:
- wreq.wi_val[0] = htole16(ic->ic_def_txkey);
- wreq.wi_len = 1;
- break;
- case WI_RID_DEFLT_CRYPT_KEYS:
- keys = (struct wi_ltv_keys *)&wreq;
- /* do not show keys to non-root user */
- error = priv_check(curthread, PRIV_NET80211_GETKEY);
- if (error) {
- memset(keys, 0, sizeof(*keys));
- error = 0;
- break;
- }
- for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- keys->wi_keys[i].wi_keylen =
- htole16(ic->ic_nw_keys[i].wk_keylen);
- memcpy(keys->wi_keys[i].wi_keydat,
- ic->ic_nw_keys[i].wk_key,
- ic->ic_nw_keys[i].wk_keylen);
- }
- wreq.wi_len = sizeof(*keys) / 2;
- break;
- case WI_RID_MAX_DATALEN:
- wreq.wi_val[0] = htole16(ic->ic_fragthreshold);
- wreq.wi_len = 1;
- break;
- case WI_RID_IFACE_STATS:
- /* XXX: should be implemented in lower drivers */
- break;
- case WI_RID_READ_APS:
- /*
- * Don't return results until active scan completes.
- */
- if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
- struct wi_read_ap_args args;
-
- args.i = 0;
- args.ap = (void *)((char *)wreq.wi_val + sizeof(i));
- args.max = (void *)(&wreq + 1);
- ieee80211_iterate_nodes(&ic->ic_scan,
- wi_read_ap_result, &args);
- memcpy(wreq.wi_val, &args.i, sizeof(args.i));
- wreq.wi_len = (sizeof(int) +
- sizeof(struct wi_apinfo) * args.i) / 2;
- } else
- error = EINPROGRESS;
- break;
- case WI_RID_PRISM2:
- /* NB: we lie so WI_RID_SCAN_RES can include rates */
- wreq.wi_val[0] = 1;
- wreq.wi_len = sizeof(u_int16_t) / 2;
- break;
- case WI_RID_SCAN_RES: /* compatibility interface */
- if ((ic->ic_flags & (IEEE80211_F_SCAN|IEEE80211_F_ASCAN)) == 0) {
- struct wi_read_prism2_args args;
- struct wi_scan_p2_hdr *p2;
-
- /* NB: use Prism2 format so we can include rate info */
- p2 = (struct wi_scan_p2_hdr *)wreq.wi_val;
- args.i = 0;
- args.res = (void *)&p2[1];
- args.max = (void *)(&wreq + 1);
- ieee80211_iterate_nodes(&ic->ic_scan,
- wi_read_prism2_result, &args);
- p2->wi_rsvd = 0;
- p2->wi_reason = args.i;
- wreq.wi_len = (sizeof(*p2) +
- sizeof(struct wi_scan_res) * args.i) / 2;
- } else
- error = EINPROGRESS;
- break;
- case WI_RID_READ_CACHE: {
- struct wi_read_sigcache_args args;
- args.i = 0;
- args.wsc = (struct wi_sigcache *) wreq.wi_val;
- args.max = (void *)(&wreq + 1);
- ieee80211_iterate_nodes(&ic->ic_scan, wi_read_sigcache, &args);
- wreq.wi_len = sizeof(struct wi_sigcache) * args.i / 2;
- break;
- }
- default:
- error = EINVAL;
- break;
- }
- if (error == 0) {
- wreq.wi_len++;
- error = copyout(&wreq, ifr->ifr_data, sizeof(wreq));
- }
- return error;
-}
-
-static int
-findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
-{
-#define IEEERATE(_ic,_m,_i) \
- ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
- int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
- for (i = 0; i < nrates; i++)
- if (IEEERATE(ic, mode, i) == rate)
- return i;
- return -1;
-#undef IEEERATE
-}
-
-/*
- * Prepare to do a user-initiated scan for AP's. If no
- * current/default channel is setup or the current channel
- * is invalid then pick the first available channel from
- * the active list as the place to start the scan.
- */
-static int
-ieee80211_setupscan(struct ieee80211com *ic, const u_int8_t chanlist[])
-{
-
- /*
- * XXX don't permit a scan to be started unless we
- * know the device is ready. For the moment this means
- * the device is marked up as this is the required to
- * initialize the hardware. It would be better to permit
- * scanning prior to being up but that'll require some
- * changes to the infrastructure.
- */
- if (!IS_UP(ic))
- return EINVAL;
- memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
- /*
- * We force the state to INIT before calling ieee80211_new_state
- * to get ieee80211_begin_scan called. We really want to scan w/o
- * altering the current state but that's not possible right now.
- */
- /* XXX handle proberequest case */
- ic->ic_state = IEEE80211_S_INIT; /* XXX bypass state machine */
- return 0;
-}
-
-int
-ieee80211_cfgset(struct ieee80211com *ic, u_long cmd, caddr_t data)
-{
- struct ifnet *ifp = ic->ic_ifp;
- int i, j, len, error, rate;
- struct ifreq *ifr = (struct ifreq *)data;
- struct wi_ltv_keys *keys;
- struct wi_req wreq;
- u_char chanlist[roundup(IEEE80211_CHAN_MAX, NBBY)];
-
- error = copyin(ifr->ifr_data, &wreq, sizeof(wreq));
- if (error)
- return error;
- len = wreq.wi_len ? (wreq.wi_len - 1) * 2 : 0;
- switch (wreq.wi_type) {
- case WI_RID_SERIALNO:
- case WI_RID_NODENAME:
- return EPERM;
- case WI_RID_CURRENT_SSID:
- return EPERM;
- case WI_RID_OWN_SSID:
- case WI_RID_DESIRED_SSID:
- if (le16toh(wreq.wi_val[0]) * 2 > len ||
- le16toh(wreq.wi_val[0]) > IEEE80211_NWID_LEN) {
- error = ENOSPC;
- break;
- }
- memset(ic->ic_des_essid, 0, sizeof(ic->ic_des_essid));
- ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
- memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
- error = ENETRESET;
- break;
- case WI_RID_CURRENT_BSSID:
- return EPERM;
- case WI_RID_OWN_CHNL:
- if (len != 2)
- return EINVAL;
- i = le16toh(wreq.wi_val[0]);
- if (i < 0 ||
- i > IEEE80211_CHAN_MAX ||
- isclr(ic->ic_chan_active, i))
- return EINVAL;
- ic->ic_ibss_chan = &ic->ic_channels[i];
- if (ic->ic_opmode == IEEE80211_M_MONITOR)
- error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
- else
- error = ENETRESET;
- break;
- case WI_RID_CURRENT_CHAN:
- return EPERM;
- case WI_RID_COMMS_QUALITY:
- return EPERM;
- case WI_RID_PROMISC:
- if (len != 2)
- return EINVAL;
- if (ifp->if_flags & IFF_PROMISC) {
- if (wreq.wi_val[0] == 0) {
- ifp->if_flags &= ~IFF_PROMISC;
- error = ENETRESET;
- }
- } else {
- if (wreq.wi_val[0] != 0) {
- ifp->if_flags |= IFF_PROMISC;
- error = ENETRESET;
- }
- }
- break;
- case WI_RID_PORTTYPE:
- if (len != 2)
- return EINVAL;
- switch (le16toh(wreq.wi_val[0])) {
- case IEEE80211_M_STA:
- break;
- case IEEE80211_M_IBSS:
- if (!(ic->ic_caps & IEEE80211_C_IBSS))
- return EINVAL;
- break;
- case IEEE80211_M_AHDEMO:
- if (ic->ic_phytype != IEEE80211_T_DS ||
- !(ic->ic_caps & IEEE80211_C_AHDEMO))
- return EINVAL;
- break;
- case IEEE80211_M_HOSTAP:
- if (!(ic->ic_caps & IEEE80211_C_HOSTAP))
- return EINVAL;
- break;
- default:
- return EINVAL;
- }
- if (le16toh(wreq.wi_val[0]) != ic->ic_opmode) {
- ic->ic_opmode = le16toh(wreq.wi_val[0]);
- error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
- }
- break;
-#if 0
- case WI_RID_MAC_NODE:
- if (len != IEEE80211_ADDR_LEN)
- return EINVAL;
- IEEE80211_ADDR_COPY(LLADDR(ifp->if_sadl), wreq.wi_val);
- /* if_init will copy lladdr into ic_myaddr */
- error = ENETRESET;
- break;
-#endif
- case WI_RID_TX_RATE:
- if (len != 2)
- return EINVAL;
- if (wreq.wi_val[0] == 0) {
- /* auto */
- ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
- break;
- }
- rate = 2 * le16toh(wreq.wi_val[0]);
- if (ic->ic_curmode == IEEE80211_MODE_AUTO) {
- /*
- * In autoselect mode search for the rate. We take
- * the first instance which may not be right, but we
- * are limited by the interface. Note that we also
- * lock the mode to insure the rate is meaningful
- * when it is used.
- */
- for (j = IEEE80211_MODE_11A;
- j < IEEE80211_MODE_MAX; j++) {
- if (isclr(ic->ic_modecaps, j))
- continue;
- i = findrate(ic, j, rate);
- if (i != -1) {
- /* lock mode too */
- ic->ic_curmode = j;
- goto setrate;
- }
- }
- } else {
- i = findrate(ic, ic->ic_curmode, rate);
- if (i != -1)
- goto setrate;
- }
- return EINVAL;
- setrate:
- ic->ic_fixed_rate = i;
- error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
- break;
- case WI_RID_CUR_TX_RATE:
- return EPERM;
- case WI_RID_RTS_THRESH:
- if (len != 2)
- return EINVAL;
- if (le16toh(wreq.wi_val[0]) != IEEE80211_MAX_LEN)
- return EINVAL; /* TODO: RTS */
- break;
- case WI_RID_CREATE_IBSS:
- if (len != 2)
- return EINVAL;
- if (wreq.wi_val[0] != 0) {
- if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
- return EINVAL;
- if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
- ic->ic_flags |= IEEE80211_F_IBSSON;
- if (ic->ic_opmode == IEEE80211_M_IBSS &&
- ic->ic_state == IEEE80211_S_SCAN)
- error = IS_UP_AUTO(ic) ? ENETRESET : 0;
- }
- } else {
- if (ic->ic_flags & IEEE80211_F_IBSSON) {
- ic->ic_flags &= ~IEEE80211_F_IBSSON;
- if (ic->ic_flags & IEEE80211_F_SIBSS) {
- ic->ic_flags &= ~IEEE80211_F_SIBSS;
- error = IS_UP_AUTO(ic) ? ENETRESET : 0;
- }
- }
- }
- break;
- case WI_RID_MICROWAVE_OVEN:
- if (len != 2)
- return EINVAL;
- if (wreq.wi_val[0] != 0)
- return EINVAL; /* not supported */
- break;
- case WI_RID_ROAMING_MODE:
- if (len != 2)
- return EINVAL;
- i = le16toh(wreq.wi_val[0]);
- if (i > IEEE80211_ROAMING_MANUAL)
- return EINVAL; /* not supported */
- ic->ic_roaming = i;
- break;
- case WI_RID_SYSTEM_SCALE:
- if (len != 2)
- return EINVAL;
- if (le16toh(wreq.wi_val[0]) != 1)
- return EINVAL; /* not supported */
- break;
- case WI_RID_PM_ENABLED:
- if (len != 2)
- return EINVAL;
- if (wreq.wi_val[0] != 0) {
- if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
- return EINVAL;
- if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
- ic->ic_flags |= IEEE80211_F_PMGTON;
- error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
- }
- } else {
- if (ic->ic_flags & IEEE80211_F_PMGTON) {
- ic->ic_flags &= ~IEEE80211_F_PMGTON;
- error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
- }
- }
- break;
- case WI_RID_MAX_SLEEP:
- if (len != 2)
- return EINVAL;
- ic->ic_lintval = le16toh(wreq.wi_val[0]);
- if (ic->ic_flags & IEEE80211_F_PMGTON)
- error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
- break;
- case WI_RID_CUR_BEACON_INT:
- return EPERM;
- case WI_RID_WEP_AVAIL:
- return EPERM;
- case WI_RID_CNFAUTHMODE:
- if (len != 2)
- return EINVAL;
- i = le16toh(wreq.wi_val[0]);
- if (i > IEEE80211_AUTH_WPA)
- return EINVAL;
- ic->ic_bss->ni_authmode = i; /* XXX ENETRESET? */
- error = ENETRESET;
- break;
- case WI_RID_ENCRYPTION:
- if (len != 2)
- return EINVAL;
- if (wreq.wi_val[0] != 0) {
- if ((ic->ic_caps & IEEE80211_C_WEP) == 0)
- return EINVAL;
- if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
- ic->ic_flags |= IEEE80211_F_PRIVACY;
- error = ENETRESET;
- }
- } else {
- if (ic->ic_flags & IEEE80211_F_PRIVACY) {
- ic->ic_flags &= ~IEEE80211_F_PRIVACY;
- error = ENETRESET;
- }
- }
- break;
- case WI_RID_TX_CRYPT_KEY:
- if (len != 2)
- return EINVAL;
- i = le16toh(wreq.wi_val[0]);
- if (i >= IEEE80211_WEP_NKID)
- return EINVAL;
- ic->ic_def_txkey = i;
- error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
- break;
- case WI_RID_DEFLT_CRYPT_KEYS:
- if (len != sizeof(struct wi_ltv_keys))
- return EINVAL;
- keys = (struct wi_ltv_keys *)&wreq;
- for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- len = le16toh(keys->wi_keys[i].wi_keylen);
- if (len != 0 && len < IEEE80211_WEP_KEYLEN)
- return EINVAL;
- if (len > IEEE80211_KEYBUF_SIZE)
- return EINVAL;
- }
- for (i = 0; i < IEEE80211_WEP_NKID; i++) {
- struct ieee80211_key *k = &ic->ic_nw_keys[i];
-
- len = le16toh(keys->wi_keys[i].wi_keylen);
- k->wk_keylen = len;
- k->wk_flags = IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
- memset(k->wk_key, 0, sizeof(k->wk_key));
- memcpy(k->wk_key, keys->wi_keys[i].wi_keydat, len);
-#if 0
- k->wk_type = IEEE80211_CIPHER_WEP;
-#endif
- }
- error = ENETRESET;
- break;
- case WI_RID_MAX_DATALEN:
- if (len != 2)
- return EINVAL;
- len = le16toh(wreq.wi_val[0]);
- if (len < 350 /* ? */ || len > IEEE80211_MAX_LEN)
- return EINVAL;
- ic->ic_fragthreshold = len;
- error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
- break;
- case WI_RID_IFACE_STATS:
- error = EPERM;
- break;
- case WI_RID_SCAN_REQ: /* XXX wicontrol */
- if (ic->ic_opmode == IEEE80211_M_HOSTAP)
- break;
- error = ieee80211_setupscan(ic, ic->ic_chan_avail);
- if (error == 0)
- error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- break;
- case WI_RID_SCAN_APS:
- if (ic->ic_opmode == IEEE80211_M_HOSTAP)
- break;
- len--; /* XXX: tx rate? */
- /* FALLTHRU */
- case WI_RID_CHANNEL_LIST:
- memset(chanlist, 0, sizeof(chanlist));
- /*
- * Since channel 0 is not available for DS, channel 1
- * is assigned to LSB on WaveLAN.
- */
- if (ic->ic_phytype == IEEE80211_T_DS)
- i = 1;
- else
- i = 0;
- for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
- if ((j / 8) >= len)
- break;
- if (isclr((u_int8_t *)wreq.wi_val, j))
- continue;
- if (isclr(ic->ic_chan_active, i)) {
- if (wreq.wi_type != WI_RID_CHANNEL_LIST)
- continue;
- if (isclr(ic->ic_chan_avail, i))
- return EPERM;
- }
- setbit(chanlist, i);
- }
- error = ieee80211_setupscan(ic, chanlist);
- if (wreq.wi_type == WI_RID_CHANNEL_LIST) {
- /* NB: ignore error from ieee80211_setupscan */
- error = ENETRESET;
- } else if (error == 0)
- error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- break;
- default:
- error = EINVAL;
- break;
- }
- if (error == ENETRESET && !IS_UP_AUTO(ic))
- error = 0;
- return error;
-}
+static struct ieee80211_channel *findchannel(struct ieee80211com *,
+ int ieee, int mode);
static int
cap2cipher(int flag)
@@ -889,37 +152,21 @@ ieee80211_ioctl_getchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
static int
ieee80211_ioctl_getchaninfo(struct ieee80211com *ic, struct ieee80211req *ireq)
{
- struct ieee80211req_chaninfo chans; /* XXX off stack? */
- int i, space;
+ int space;
- /*
- * Since channel 0 is not available for DS, channel 1
- * is assigned to LSB on WaveLAN.
- */
- if (ic->ic_phytype == IEEE80211_T_DS)
- i = 1;
- else
- i = 0;
- memset(&chans, 0, sizeof(chans));
- for (; i <= IEEE80211_CHAN_MAX; i++)
- if (isset(ic->ic_chan_avail, i)) {
- struct ieee80211_channel *c = &ic->ic_channels[i];
- chans.ic_chans[chans.ic_nchans].ic_freq = c->ic_freq;
- chans.ic_chans[chans.ic_nchans].ic_flags = c->ic_flags;
- chans.ic_nchans++;
- }
space = __offsetof(struct ieee80211req_chaninfo,
- ic_chans[chans.ic_nchans]);
+ ic_chans[ic->ic_nchans]);
if (space > ireq->i_len)
space = ireq->i_len;
- return copyout(&chans, ireq->i_data, space);
+ /* XXX assumes compatible layout */
+ return copyout(&ic->ic_nchans, ireq->i_data, space);
}
static int
-ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq)
+ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq, int req)
{
struct ieee80211_node *ni;
- struct ieee80211req_wpaie wpaie;
+ struct ieee80211req_wpaie2 wpaie;
int error;
if (ireq->i_len < IEEE80211_ADDR_LEN)
@@ -929,7 +176,7 @@ ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq)
return error;
ni = ieee80211_find_node(&ic->ic_sta, wpaie.wpa_macaddr);
if (ni == NULL)
- return EINVAL; /* XXX */
+ return ENOENT; /* XXX */
memset(wpaie.wpa_ie, 0, sizeof(wpaie.wpa_ie));
if (ni->ni_wpa_ie != NULL) {
int ielen = ni->ni_wpa_ie[1] + 2;
@@ -937,9 +184,29 @@ ieee80211_ioctl_getwpaie(struct ieee80211com *ic, struct ieee80211req *ireq)
ielen = sizeof(wpaie.wpa_ie);
memcpy(wpaie.wpa_ie, ni->ni_wpa_ie, ielen);
}
+ if (req == IEEE80211_IOC_WPAIE2) {
+ memset(wpaie.rsn_ie, 0, sizeof(wpaie.rsn_ie));
+ if (ni->ni_rsn_ie != NULL) {
+ int ielen = ni->ni_rsn_ie[1] + 2;
+ if (ielen > sizeof(wpaie.rsn_ie))
+ ielen = sizeof(wpaie.rsn_ie);
+ memcpy(wpaie.rsn_ie, ni->ni_rsn_ie, ielen);
+ }
+ if (ireq->i_len > sizeof(struct ieee80211req_wpaie2))
+ ireq->i_len = sizeof(struct ieee80211req_wpaie2);
+ } else {
+ /* compatibility op, may overwrite wpa ie */
+ /* XXX check ic_flags? */
+ if (ni->ni_rsn_ie != NULL) {
+ int ielen = ni->ni_rsn_ie[1] + 2;
+ if (ielen > sizeof(wpaie.wpa_ie))
+ ielen = sizeof(wpaie.wpa_ie);
+ memcpy(wpaie.wpa_ie, ni->ni_rsn_ie, ielen);
+ }
+ if (ireq->i_len > sizeof(struct ieee80211req_wpaie))
+ ireq->i_len = sizeof(struct ieee80211req_wpaie);
+ }
ieee80211_free_node(ni);
- if (ireq->i_len > sizeof(wpaie))
- ireq->i_len = sizeof(wpaie);
return copyout(&wpaie, ireq->i_data, ireq->i_len);
}
@@ -947,7 +214,7 @@ static int
ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
{
struct ieee80211_node *ni;
- u_int8_t macaddr[IEEE80211_ADDR_LEN];
+ uint8_t macaddr[IEEE80211_ADDR_LEN];
const int off = __offsetof(struct ieee80211req_sta_stats, is_stats);
int error;
@@ -957,213 +224,250 @@ ieee80211_ioctl_getstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
if (error != 0)
return error;
ni = ieee80211_find_node(&ic->ic_sta, macaddr);
- if (ni == NULL) {
- /* XXX special-case sta-mode until bss is node in ic_sta */
- if (ic->ic_opmode != IEEE80211_M_STA)
- return ENOENT;
- ni = ieee80211_ref_node(ic->ic_bss);
- }
+ if (ni == NULL)
+ return EINVAL;
if (ireq->i_len > sizeof(struct ieee80211req_sta_stats))
ireq->i_len = sizeof(struct ieee80211req_sta_stats);
/* NB: copy out only the statistics */
- error = copyout(&ni->ni_stats, (u_int8_t *) ireq->i_data + off,
+ error = copyout(&ni->ni_stats, (uint8_t *) ireq->i_data + off,
ireq->i_len - off);
ieee80211_free_node(ni);
return error;
}
+static __inline uint8_t *
+copyie(uint8_t *cp, const uint8_t *ie)
+{
+ if (ie != NULL) {
+ memcpy(cp, ie, 2+ie[1]);
+ cp += 2+ie[1];
+ }
+ return cp;
+}
+
#ifdef COMPAT_FREEBSD6
#define IEEE80211_IOC_SCAN_RESULTS_OLD 24
struct scan_result_old {
- u_int16_t isr_len; /* length (mult of 4) */
- u_int16_t isr_freq; /* MHz */
- u_int16_t isr_flags; /* channel flags */
- u_int8_t isr_noise;
- u_int8_t isr_rssi;
- u_int8_t isr_intval; /* beacon interval */
- u_int8_t isr_capinfo; /* capabilities */
- u_int8_t isr_erp; /* ERP element */
- u_int8_t isr_bssid[IEEE80211_ADDR_LEN];
- u_int8_t isr_nrates;
- u_int8_t isr_rates[IEEE80211_RATE_MAXSIZE];
- u_int8_t isr_ssid_len; /* SSID length */
- u_int8_t isr_ie_len; /* IE length */
- u_int8_t isr_pad[5];
+ uint16_t isr_len; /* length (mult of 4) */
+ uint16_t isr_freq; /* MHz */
+ uint16_t isr_flags; /* channel flags */
+ uint8_t isr_noise;
+ uint8_t isr_rssi;
+ uint8_t isr_intval; /* beacon interval */
+ uint8_t isr_capinfo; /* capabilities */
+ uint8_t isr_erp; /* ERP element */
+ uint8_t isr_bssid[IEEE80211_ADDR_LEN];
+ uint8_t isr_nrates;
+ uint8_t isr_rates[IEEE80211_RATE_MAXSIZE];
+ uint8_t isr_ssid_len; /* SSID length */
+ uint8_t isr_ie_len; /* IE length */
+ uint8_t isr_pad[5];
/* variable length SSID followed by IE data */
};
+struct oscanreq {
+ struct scan_result_old *sr;
+ size_t space;
+};
+
+static size_t
+old_scan_space(const struct ieee80211_scan_entry *se, int *ielen)
+{
+ size_t len;
+
+ *ielen = 0;
+ if (se->se_wpa_ie != NULL)
+ *ielen += 2+se->se_wpa_ie[1];
+ if (se->se_wme_ie != NULL)
+ *ielen += 2+se->se_wme_ie[1];
+ /*
+ * NB: ie's can be no more than 255 bytes and the max 802.11
+ * packet is <3Kbytes so we are sure this doesn't overflow
+ * 16-bits; if this is a concern we can drop the ie's.
+ */
+ len = sizeof(struct scan_result_old) + se->se_ssid[1] + *ielen;
+ return roundup(len, sizeof(uint32_t));
+}
+
static void
-old_get_scan_result(struct scan_result_old *sr,
- const struct ieee80211_node *ni)
+old_get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
{
- struct ieee80211com *ic = ni->ni_ic;
- u_int ielen;
+ struct oscanreq *req = arg;
+ int ielen;
+
+ req->space += old_scan_space(se, &ielen);
+}
+
+static void
+old_get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
+{
+ struct oscanreq *req = arg;
+ struct scan_result_old *sr;
+ int ielen, len, nr, nxr;
+ uint8_t *cp;
+
+ len = old_scan_space(se, &ielen);
+ if (len > req->space)
+ return;
+ sr = req->sr;
memset(sr, 0, sizeof(*sr));
- sr->isr_ssid_len = ni->ni_esslen;
- ielen = 0;
- if (ni->ni_wpa_ie != NULL)
- ielen += 2+ni->ni_wpa_ie[1];
- if (ni->ni_wme_ie != NULL)
- ielen += 2+ni->ni_wme_ie[1];
+ sr->isr_ssid_len = se->se_ssid[1];
/* NB: beware of overflow, isr_ie_len is 8 bits */
sr->isr_ie_len = (ielen > 255 ? 0 : ielen);
- sr->isr_len = sizeof(*sr) + sr->isr_ssid_len + sr->isr_ie_len;
- sr->isr_len = roundup(sr->isr_len, sizeof(u_int32_t));
- if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
- sr->isr_freq = ni->ni_chan->ic_freq;
- sr->isr_flags = ni->ni_chan->ic_flags;
+ sr->isr_len = len;
+ sr->isr_freq = se->se_chan->ic_freq;
+ sr->isr_flags = se->se_chan->ic_flags;
+ sr->isr_rssi = se->se_rssi;
+ sr->isr_noise = se->se_noise;
+ sr->isr_intval = se->se_intval;
+ sr->isr_capinfo = se->se_capinfo;
+ sr->isr_erp = se->se_erp;
+ IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
+ nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
+ memcpy(sr->isr_rates, se->se_rates+2, nr);
+ nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
+ memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
+ sr->isr_nrates = nr + nxr;
+
+ cp = (uint8_t *)(sr+1);
+ memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
+ cp += sr->isr_ssid_len;
+ if (sr->isr_ie_len) {
+ cp = copyie(cp, se->se_wpa_ie);
+ cp = copyie(cp, se->se_wme_ie);
}
- sr->isr_rssi = ic->ic_node_getrssi(ni);
- sr->isr_intval = ni->ni_intval;
- sr->isr_capinfo = ni->ni_capinfo;
- sr->isr_erp = ni->ni_erp;
- IEEE80211_ADDR_COPY(sr->isr_bssid, ni->ni_bssid);
- sr->isr_nrates = ni->ni_rates.rs_nrates;
- if (sr->isr_nrates > 15)
- sr->isr_nrates = 15;
- memcpy(sr->isr_rates, ni->ni_rates.rs_rates, sr->isr_nrates);
+
+ req->space -= len;
+ req->sr = (struct scan_result_old *)(((uint8_t *)sr) + len);
}
static int
old_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
{
- union {
- struct scan_result_old res;
- char data[512]; /* XXX shrink? */
- } u;
- struct scan_result_old *sr = &u.res;
- struct ieee80211_node_table *nt;
- struct ieee80211_node *ni;
- int error, space;
- u_int8_t *p, *cp;
+ struct oscanreq req;
+ int error;
+
+ if (ireq->i_len < sizeof(struct scan_result_old))
+ return EFAULT;
- p = ireq->i_data;
- space = ireq->i_len;
error = 0;
- /* XXX locking */
- nt = &ic->ic_scan;
- TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
- /* NB: skip pre-scan node state */
- if (ni->ni_chan == IEEE80211_CHAN_ANYC)
- continue;
- old_get_scan_result(sr, ni);
- if (sr->isr_len > sizeof(u))
- continue; /* XXX */
- if (space < sr->isr_len)
- break;
- cp = (u_int8_t *)(sr+1);
- memcpy(cp, ni->ni_essid, ni->ni_esslen);
- cp += ni->ni_esslen;
- if (sr->isr_ie_len) {
- if (ni->ni_wpa_ie != NULL) {
- memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
- cp += 2+ni->ni_wpa_ie[1];
- }
- if (ni->ni_wme_ie != NULL) {
- memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
- cp += 2+ni->ni_wme_ie[1];
- }
- }
- error = copyout(sr, p, sr->isr_len);
- if (error)
- break;
- p += sr->isr_len;
- space -= sr->isr_len;
- }
- ireq->i_len -= space;
+ req.space = 0;
+ ieee80211_scan_iterate(ic, old_get_scan_space, &req);
+ if (req.space > ireq->i_len)
+ req.space = ireq->i_len;
+ if (req.space > 0) {
+ size_t space;
+ void *p;
+
+ space = req.space;
+ /* XXX M_WAITOK after driver lock released */
+ MALLOC(p, void *, space, M_TEMP, M_NOWAIT | M_ZERO);
+ if (p == NULL)
+ return ENOMEM;
+ req.sr = p;
+ ieee80211_scan_iterate(ic, old_get_scan_result, &req);
+ ireq->i_len = space - req.space;
+ error = copyout(p, ireq->i_data, ireq->i_len);
+ FREE(p, M_TEMP);
+ } else
+ ireq->i_len = 0;
+
return error;
}
#endif /* COMPAT_FREEBSD6 */
-struct scanresultsreq {
+struct scanreq {
struct ieee80211req_scan_result *sr;
- size_t space;
+ size_t space;
};
static size_t
-scan_space(const struct ieee80211_node *ni, size_t *ielen)
+scan_space(const struct ieee80211_scan_entry *se, int *ielen)
{
size_t len;
*ielen = 0;
- if (ni->ni_wpa_ie != NULL)
- *ielen += 2+ni->ni_wpa_ie[1];
- if (ni->ni_wme_ie != NULL)
- *ielen += 2+ni->ni_wme_ie[1];
+ if (se->se_wpa_ie != NULL)
+ *ielen += 2+se->se_wpa_ie[1];
+ if (se->se_rsn_ie != NULL)
+ *ielen += 2+se->se_rsn_ie[1];
+ if (se->se_wme_ie != NULL)
+ *ielen += 2+se->se_wme_ie[1];
+ if (se->se_ath_ie != NULL)
+ *ielen += 2+se->se_ath_ie[1];
/*
* NB: ie's can be no more than 255 bytes and the max 802.11
* packet is <3Kbytes so we are sure this doesn't overflow
* 16-bits; if this is a concern we can drop the ie's.
*/
- len = sizeof(struct ieee80211req_scan_result) + ni->ni_esslen + *ielen;
- return roundup(len, sizeof(u_int32_t));
+ len = sizeof(struct ieee80211req_scan_result) + se->se_ssid[1] + *ielen;
+ return roundup(len, sizeof(uint32_t));
}
static void
-get_scan_space(void *arg, struct ieee80211_node *ni)
+get_scan_space(void *arg, const struct ieee80211_scan_entry *se)
{
- struct scanresultsreq *req = arg;
- size_t ielen;
+ struct scanreq *req = arg;
+ int ielen;
- req->space += scan_space(ni, &ielen);
+ req->space += scan_space(se, &ielen);
}
static void
-get_scan_result(void *arg, struct ieee80211_node *ni)
+get_scan_result(void *arg, const struct ieee80211_scan_entry *se)
{
- struct scanresultsreq *req = arg;
- struct ieee80211com *ic = ni->ni_ic;
+ struct scanreq *req = arg;
struct ieee80211req_scan_result *sr;
- size_t ielen, len;
- u_int8_t *cp;
+ int ielen, len, nr, nxr;
+ uint8_t *cp;
- len = scan_space(ni, &ielen);
+ len = scan_space(se, &ielen);
if (len > req->space)
return;
+
sr = req->sr;
KASSERT(len <= 65535 && ielen <= 65535,
- ("len %zu ssid %u ie %zu", len, ni->ni_esslen, ielen));
- sr->isr_len = len;
- sr->isr_ssid_len = ni->ni_esslen;
+ ("len %u ssid %u ie %u", len, se->se_ssid[1], ielen));
+ sr->isr_ie_off = sizeof(struct ieee80211req_scan_result);
sr->isr_ie_len = ielen;
- if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
- sr->isr_freq = ni->ni_chan->ic_freq;
- sr->isr_flags = ni->ni_chan->ic_flags;
- }
- /* XXX need to rev driver apis for signal data */
- sr->isr_rssi = (int8_t) ic->ic_node_getrssi(ni);
- sr->isr_intval = ni->ni_intval;
- sr->isr_capinfo = ni->ni_capinfo;
- sr->isr_erp = ni->ni_erp;
- IEEE80211_ADDR_COPY(sr->isr_bssid, ni->ni_bssid);
- sr->isr_nrates = ni->ni_rates.rs_nrates;
- if (sr->isr_nrates > 15)
- sr->isr_nrates = 15;
- memcpy(sr->isr_rates, ni->ni_rates.rs_rates, sr->isr_nrates);
- cp = (u_int8_t *)(sr+1);
- memcpy(cp, ni->ni_essid, ni->ni_esslen);
- cp += ni->ni_esslen;
- if (sr->isr_ie_len) {
- if (ni->ni_wpa_ie != NULL) {
- memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
- cp += 2+ni->ni_wpa_ie[1];
- }
- if (ni->ni_wme_ie != NULL) {
- memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
- cp += 2+ni->ni_wme_ie[1];
- }
+ sr->isr_len = len;
+ sr->isr_freq = se->se_chan->ic_freq;
+ sr->isr_flags = se->se_chan->ic_flags;
+ sr->isr_rssi = se->se_rssi;
+ sr->isr_noise = se->se_noise;
+ sr->isr_intval = se->se_intval;
+ sr->isr_capinfo = se->se_capinfo;
+ sr->isr_erp = se->se_erp;
+ IEEE80211_ADDR_COPY(sr->isr_bssid, se->se_bssid);
+ nr = min(se->se_rates[1], IEEE80211_RATE_MAXSIZE);
+ memcpy(sr->isr_rates, se->se_rates+2, nr);
+ nxr = min(se->se_xrates[1], IEEE80211_RATE_MAXSIZE - nr);
+ memcpy(sr->isr_rates+nr, se->se_xrates+2, nxr);
+ sr->isr_nrates = nr + nxr;
+
+ sr->isr_ssid_len = se->se_ssid[1];
+ cp = ((uint8_t *)sr) + sr->isr_ie_off;
+ memcpy(cp, se->se_ssid+2, sr->isr_ssid_len);
+
+ if (ielen) {
+ cp += sr->isr_ssid_len;
+ cp = copyie(cp, se->se_wpa_ie);
+ cp = copyie(cp, se->se_rsn_ie);
+ cp = copyie(cp, se->se_wme_ie);
+ cp = copyie(cp, se->se_ath_ie);
+ cp = copyie(cp, se->se_htcap_ie);
}
- req->sr = (struct ieee80211req_scan_result *)(((u_int8_t *)sr) + len);
req->space -= len;
+ req->sr = (struct ieee80211req_scan_result *)(((uint8_t *)sr) + len);
}
static int
ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ireq)
{
- struct scanresultsreq req;
+ struct scanreq req;
int error;
if (ireq->i_len < sizeof(struct ieee80211req_scan_result))
@@ -1171,7 +475,7 @@ ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ire
error = 0;
req.space = 0;
- ieee80211_iterate_nodes(&ic->ic_scan, get_scan_space, &req);
+ ieee80211_scan_iterate(ic, get_scan_space, &req);
if (req.space > ireq->i_len)
req.space = ireq->i_len;
if (req.space > 0) {
@@ -1184,7 +488,7 @@ ieee80211_ioctl_getscanresults(struct ieee80211com *ic, struct ieee80211req *ire
if (p == NULL)
return ENOMEM;
req.sr = p;
- ieee80211_iterate_nodes(&ic->ic_scan, get_scan_result, &req);
+ ieee80211_scan_iterate(ic, get_scan_result, &req);
ireq->i_len = space - req.space;
error = copyout(p, ireq->i_data, ireq->i_len);
FREE(p, M_TEMP);
@@ -1206,10 +510,14 @@ sta_space(const struct ieee80211_node *ni, size_t *ielen)
*ielen = 0;
if (ni->ni_wpa_ie != NULL)
*ielen += 2+ni->ni_wpa_ie[1];
+ if (ni->ni_rsn_ie != NULL)
+ *ielen += 2+ni->ni_rsn_ie[1];
if (ni->ni_wme_ie != NULL)
*ielen += 2+ni->ni_wme_ie[1];
+ if (ni->ni_ath_ie != NULL)
+ *ielen += 2+ni->ni_ath_ie[1];
return roundup(sizeof(struct ieee80211req_sta_info) + *ielen,
- sizeof(u_int32_t));
+ sizeof(uint32_t));
}
static void
@@ -1232,7 +540,7 @@ get_sta_info(void *arg, struct ieee80211_node *ni)
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211req_sta_info *si;
size_t ielen, len;
- u_int8_t *cp;
+ uint8_t *cp;
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
ni->ni_associd == 0) /* only associated stations */
@@ -1243,14 +551,14 @@ get_sta_info(void *arg, struct ieee80211_node *ni)
if (len > req->space)
return;
si = req->si;
- KASSERT(len <= 65535 && ielen <= 65535, ("len %zu ie %zu", len, ielen));
si->isi_len = len;
+ si->isi_ie_off = sizeof(struct ieee80211req_sta_info);
si->isi_ie_len = ielen;
si->isi_freq = ni->ni_chan->ic_freq;
si->isi_flags = ni->ni_chan->ic_flags;
si->isi_state = ni->ni_flags;
si->isi_authmode = ni->ni_authmode;
- si->isi_rssi = ic->ic_node_getrssi(ni);
+ ic->ic_node_getsignal(ni, &si->isi_rssi, &si->isi_noise);
si->isi_noise = 0; /* XXX */
si->isi_capinfo = ni->ni_capinfo;
si->isi_erp = ni->ni_erp;
@@ -1260,6 +568,7 @@ get_sta_info(void *arg, struct ieee80211_node *ni)
si->isi_nrates = 15;
memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates);
si->isi_txrate = ni->ni_txrate;
+ si->isi_ie_len = ielen;
si->isi_associd = ni->ni_associd;
si->isi_txpower = ni->ni_txpower;
si->isi_vlan = ni->ni_vlan;
@@ -1279,17 +588,15 @@ get_sta_info(void *arg, struct ieee80211_node *ni)
si->isi_inact = ic->ic_inact_init;
si->isi_inact = (si->isi_inact - ni->ni_inact) * IEEE80211_INACT_WAIT;
- cp = (u_int8_t *)(si+1);
- if (ni->ni_wpa_ie != NULL) {
- memcpy(cp, ni->ni_wpa_ie, 2+ni->ni_wpa_ie[1]);
- cp += 2+ni->ni_wpa_ie[1];
- }
- if (ni->ni_wme_ie != NULL) {
- memcpy(cp, ni->ni_wme_ie, 2+ni->ni_wme_ie[1]);
- cp += 2+ni->ni_wme_ie[1];
+ if (ielen) {
+ cp = ((uint8_t *)si) + si->isi_ie_off;
+ cp = copyie(cp, ni->ni_wpa_ie);
+ cp = copyie(cp, ni->ni_rsn_ie);
+ cp = copyie(cp, ni->ni_wme_ie);
+ cp = copyie(cp, ni->ni_ath_ie);
}
- req->si = (struct ieee80211req_sta_info *)(((u_int8_t *)si) + len);
+ req->si = (struct ieee80211req_sta_info *)(((uint8_t *)si) + len);
req->space -= len;
}
@@ -1324,7 +631,7 @@ getstainfo_common(struct ieee80211com *ic, struct ieee80211req *ireq,
else
get_sta_info(&req, ni);
ireq->i_len = space - req.space;
- error = copyout(p, (u_int8_t *) ireq->i_data+off, ireq->i_len);
+ error = copyout(p, (uint8_t *) ireq->i_data+off, ireq->i_len);
FREE(p, M_TEMP);
} else
ireq->i_len = 0;
@@ -1337,7 +644,7 @@ bad:
static int
ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
{
- u_int8_t macaddr[IEEE80211_ADDR_LEN];
+ uint8_t macaddr[IEEE80211_ADDR_LEN];
const int off = __offsetof(struct ieee80211req_sta_req, info);
struct ieee80211_node *ni;
int error;
@@ -1351,12 +658,8 @@ ieee80211_ioctl_getstainfo(struct ieee80211com *ic, struct ieee80211req *ireq)
ni = NULL;
} else {
ni = ieee80211_find_node(&ic->ic_sta, macaddr);
- if (ni == NULL) {
- /* XXX special-case sta-mode until bss is in ic_sta */
- if (ic->ic_opmode != IEEE80211_M_STA)
- return EINVAL; /* XXX */
- ni = ieee80211_ref_node(ic->ic_bss);
- }
+ if (ni == NULL)
+ return EINVAL;
}
return getstainfo_common(ic, ireq, ni, off);
}
@@ -1445,6 +748,28 @@ ieee80211_ioctl_getmaccmd(struct ieee80211com *ic, struct ieee80211req *ireq)
}
/*
+ * Return the current ``state'' of an Atheros capbility.
+ * If associated in station mode report the negotiated
+ * setting. Otherwise report the current setting.
+ */
+static int
+getathcap(struct ieee80211com *ic, int cap)
+{
+ if (ic->ic_opmode == IEEE80211_M_STA && ic->ic_state == IEEE80211_S_RUN)
+ return IEEE80211_ATH_CAP(ic, ic->ic_bss, cap) != 0;
+ else
+ return (ic->ic_flags & cap) != 0;
+}
+
+static int
+ieee80211_ioctl_getcurchan(struct ieee80211com *ic, struct ieee80211req *ireq)
+{
+ if (ireq->i_len != sizeof(struct ieee80211_channel))
+ return EINVAL;
+ return copyout(ic->ic_curchan, ireq->i_data, sizeof(*ic->ic_curchan));
+}
+
+/*
* When building the kernel with -O2 on the i386 architecture, gcc
* seems to want to inline this function into ieee80211_ioctl()
* (which is the only routine that calls it). When this happens,
@@ -1469,7 +794,7 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
const struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
int error = 0;
u_int kid, len, m;
- u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
+ uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
char tmpssid[IEEE80211_NWID_LEN];
switch (ireq->i_type) {
@@ -1477,8 +802,8 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
switch (ic->ic_state) {
case IEEE80211_S_INIT:
case IEEE80211_S_SCAN:
- ireq->i_len = ic->ic_des_esslen;
- memcpy(tmpssid, ic->ic_des_essid, ireq->i_len);
+ ireq->i_len = ic->ic_des_ssid[0].len;
+ memcpy(tmpssid, ic->ic_des_ssid[0].ssid, ireq->i_len);
break;
default:
ireq->i_len = ic->ic_bss->ni_esslen;
@@ -1639,7 +964,10 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
ireq->i_data, ireq->i_len);
break;
case IEEE80211_IOC_WPAIE:
- error = ieee80211_ioctl_getwpaie(ic, ireq);
+ error = ieee80211_ioctl_getwpaie(ic, ireq, ireq->i_type);
+ break;
+ case IEEE80211_IOC_WPAIE2:
+ error = ieee80211_ioctl_getwpaie(ic, ireq, ireq->i_type);
break;
#ifdef COMPAT_FREEBSD6
case IEEE80211_IOC_SCAN_RESULTS_OLD:
@@ -1684,6 +1012,42 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
case IEEE80211_IOC_PUREG:
ireq->i_val = (ic->ic_flags & IEEE80211_F_PUREG) != 0;
break;
+ case IEEE80211_IOC_FF:
+ ireq->i_val = getathcap(ic, IEEE80211_F_FF);
+ break;
+ case IEEE80211_IOC_TURBOP:
+ ireq->i_val = getathcap(ic, IEEE80211_F_TURBOP);
+ break;
+ case IEEE80211_IOC_BGSCAN:
+ ireq->i_val = (ic->ic_flags & IEEE80211_F_BGSCAN) != 0;
+ break;
+ case IEEE80211_IOC_BGSCAN_IDLE:
+ ireq->i_val = ic->ic_bgscanidle*hz/1000; /* ms */
+ break;
+ case IEEE80211_IOC_BGSCAN_INTERVAL:
+ ireq->i_val = ic->ic_bgscanintvl/hz; /* seconds */
+ break;
+ case IEEE80211_IOC_SCANVALID:
+ ireq->i_val = ic->ic_scanvalid/hz; /* seconds */
+ break;
+ case IEEE80211_IOC_ROAM_RSSI_11A:
+ ireq->i_val = ic->ic_roam.rssi11a;
+ break;
+ case IEEE80211_IOC_ROAM_RSSI_11B:
+ ireq->i_val = ic->ic_roam.rssi11bOnly;
+ break;
+ case IEEE80211_IOC_ROAM_RSSI_11G:
+ ireq->i_val = ic->ic_roam.rssi11b;
+ break;
+ case IEEE80211_IOC_ROAM_RATE_11A:
+ ireq->i_val = ic->ic_roam.rate11a;
+ break;
+ case IEEE80211_IOC_ROAM_RATE_11B:
+ ireq->i_val = ic->ic_roam.rate11bOnly;
+ break;
+ case IEEE80211_IOC_ROAM_RATE_11G:
+ ireq->i_val = ic->ic_roam.rate11b;
+ break;
case IEEE80211_IOC_MCAST_RATE:
ireq->i_val = ic->ic_mcast_rate;
break;
@@ -1699,6 +1063,48 @@ ieee80211_ioctl_get80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
case IEEE80211_IOC_BMISSTHRESHOLD:
ireq->i_val = ic->ic_bmissthreshold;
break;
+ case IEEE80211_IOC_CURCHAN:
+ error = ieee80211_ioctl_getcurchan(ic, ireq);
+ break;
+ case IEEE80211_IOC_SHORTGI:
+ ireq->i_val = 0;
+ if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI20)
+ ireq->i_val |= IEEE80211_HTCAP_SHORTGI20;
+ if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI40)
+ ireq->i_val |= IEEE80211_HTCAP_SHORTGI40;
+ break;
+ case IEEE80211_IOC_AMPDU:
+ ireq->i_val = 0;
+ if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX)
+ ireq->i_val |= 1;
+ if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_RX)
+ ireq->i_val |= 2;
+ break;
+ case IEEE80211_IOC_AMPDU_LIMIT:
+ ireq->i_val = ic->ic_ampdu_limit; /* XXX truncation? */
+ break;
+ case IEEE80211_IOC_AMPDU_DENSITY:
+ ireq->i_val = ic->ic_ampdu_density;
+ break;
+ case IEEE80211_IOC_AMSDU:
+ ireq->i_val = 0;
+ if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_TX)
+ ireq->i_val |= 1;
+ if (ic->ic_flags_ext & IEEE80211_FEXT_AMSDU_RX)
+ ireq->i_val |= 2;
+ break;
+ case IEEE80211_IOC_AMSDU_LIMIT:
+ ireq->i_val = ic->ic_amsdu_limit; /* XXX truncation? */
+ break;
+ case IEEE80211_IOC_PUREN:
+ ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_PUREN) != 0;
+ break;
+ case IEEE80211_IOC_DOTH:
+ ireq->i_val = (ic->ic_flags & IEEE80211_F_DOTH) != 0;
+ break;
+ case IEEE80211_IOC_HTCOMPAT:
+ ireq->i_val = (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) != 0;
+ break;
default:
error = EINVAL;
break;
@@ -1722,6 +1128,8 @@ ieee80211_ioctl_setoptie(struct ieee80211com *ic, struct ieee80211req *ireq)
return EINVAL;
if (ireq->i_len > IEEE80211_MAX_OPT_IE)
return EINVAL;
+ /* NB: data.length is validated by the wireless extensions code */
+ /* XXX M_WAITOK after driver lock released */
if (ireq->i_len > 0) {
MALLOC(ie, void *, ireq->i_len, M_DEVBUF, M_NOWAIT);
if (ie == NULL)
@@ -1750,7 +1158,7 @@ ieee80211_ioctl_setkey(struct ieee80211com *ic, struct ieee80211req *ireq)
struct ieee80211req_key ik;
struct ieee80211_node *ni;
struct ieee80211_key *wk;
- u_int16_t kid;
+ uint16_t kid;
int error;
if (ireq->i_len != sizeof(ik))
@@ -1827,8 +1235,8 @@ ieee80211_ioctl_delkey(struct ieee80211com *ic, struct ieee80211req *ireq)
if (error)
return error;
kid = dk.idk_keyix;
- /* XXX u_int8_t -> u_int16_t */
- if (dk.idk_keyix == (u_int8_t) IEEE80211_KEYIX_NONE) {
+ /* XXX uint8_t -> uint16_t */
+ if (dk.idk_keyix == (uint8_t) IEEE80211_KEYIX_NONE) {
struct ieee80211_node *ni;
if (ic->ic_opmode == IEEE80211_M_STA) {
@@ -1870,6 +1278,32 @@ domlme(void *arg, struct ieee80211_node *ni)
ieee80211_node_leave(ic, ni);
}
+struct scanlookup {
+ const uint8_t *mac;
+ int esslen;
+ const uint8_t *essid;
+ const struct ieee80211_scan_entry *se;
+};
+
+/*
+ * Match mac address and any ssid.
+ */
+static void
+mlmelookup(void *arg, const struct ieee80211_scan_entry *se)
+{
+ struct scanlookup *look = arg;
+
+ if (!IEEE80211_ADDR_EQ(look->mac, se->se_macaddr))
+ return;
+ if (look->esslen != 0) {
+ if (se->se_ssid[1] != look->esslen)
+ return;
+ if (memcmp(look->essid, se->se_ssid+2, look->esslen))
+ return;
+ }
+ look->se = se;
+}
+
static int
ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
{
@@ -1884,31 +1318,21 @@ ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
return error;
switch (mlme.im_op) {
case IEEE80211_MLME_ASSOC:
- if (ic->ic_opmode != IEEE80211_M_STA)
- return EINVAL;
- /* XXX must be in S_SCAN state? */
-
- if (mlme.im_ssid_len != 0) {
- /*
- * Desired ssid specified; must match both bssid and
- * ssid to distinguish ap advertising multiple ssid's.
- */
- ni = ieee80211_find_node_with_ssid(&ic->ic_scan,
- mlme.im_macaddr,
- mlme.im_ssid_len, mlme.im_ssid);
- } else {
- /*
- * Normal case; just match bssid.
- */
- ni = ieee80211_find_node(&ic->ic_scan, mlme.im_macaddr);
- }
- if (ni == NULL)
- return EINVAL;
- if (!ieee80211_sta_join(ic, ni)) {
- ieee80211_free_node(ni);
- return EINVAL;
+ /* XXX ibss/ahdemo */
+ if (ic->ic_opmode == IEEE80211_M_STA) {
+ struct scanlookup lookup;
+
+ lookup.se = NULL;
+ lookup.mac = mlme.im_macaddr;
+ /* XXX use revised api w/ explicit ssid */
+ lookup.esslen = ic->ic_des_ssid[0].len;
+ lookup.essid = ic->ic_des_ssid[0].ssid;
+ ieee80211_scan_iterate(ic, mlmelookup, &lookup);
+ if (lookup.se != NULL &&
+ ieee80211_sta_join(ic, lookup.se))
+ return 0;
}
- break;
+ return EINVAL;
case IEEE80211_MLME_DISASSOC:
case IEEE80211_MLME_DEAUTH:
switch (ic->ic_opmode) {
@@ -1956,7 +1380,7 @@ ieee80211_ioctl_setmlme(struct ieee80211com *ic, struct ieee80211req *ireq)
static int
ieee80211_ioctl_macmac(struct ieee80211com *ic, struct ieee80211req *ireq)
{
- u_int8_t mac[IEEE80211_ADDR_LEN];
+ uint8_t mac[IEEE80211_ADDR_LEN];
const struct ieee80211_aclator *acl = ic->ic_acl;
int error;
@@ -2020,7 +1444,7 @@ ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
{
struct ieee80211req_chanlist list;
u_char chanlist[IEEE80211_CHAN_BYTES];
- int i, j, error;
+ int i, j, nchan, error;
if (ireq->i_len != sizeof(list))
return EINVAL;
@@ -2036,34 +1460,31 @@ ieee80211_ioctl_setchanlist(struct ieee80211com *ic, struct ieee80211req *ireq)
i = 1;
else
i = 0;
+ nchan = 0;
for (j = 0; i <= IEEE80211_CHAN_MAX; i++, j++) {
/*
* NB: silently discard unavailable channels so users
* can specify 1-255 to get all available channels.
*/
- if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i))
+ if (isset(list.ic_channels, j) && isset(ic->ic_chan_avail, i)) {
setbit(chanlist, i);
+ nchan++;
+ }
}
- if (ic->ic_ibss_chan == NULL ||
- isclr(chanlist, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
- for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
- if (isset(chanlist, i)) {
- ic->ic_ibss_chan = &ic->ic_channels[i];
- goto found;
- }
- return EINVAL; /* no active channels */
-found:
- ;
- }
+ if (nchan == 0)
+ return EINVAL;
+ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && /* XXX */
+ isclr(chanlist, ic->ic_bsschan->ic_ieee))
+ ic->ic_bsschan = IEEE80211_CHAN_ANYC;
memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
- return IS_UP_AUTO(ic) ? ENETRESET : 0;
+ return IS_UP_AUTO(ic) ? ieee80211_init(ic, RESCAN) : 0;
}
static int
ieee80211_ioctl_setstastats(struct ieee80211com *ic, struct ieee80211req *ireq)
{
struct ieee80211_node *ni;
- u_int8_t macaddr[IEEE80211_ADDR_LEN];
+ uint8_t macaddr[IEEE80211_ADDR_LEN];
int error;
/*
@@ -2193,15 +1614,273 @@ cipher2cap(int cipher)
}
static int
+find11gchannel(struct ieee80211com *ic, int start, int freq)
+{
+ const struct ieee80211_channel *c;
+ int i;
+
+ for (i = start+1; i < ic->ic_nchans; i++) {
+ c = &ic->ic_channels[i];
+ if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
+ return 1;
+ }
+ /* NB: should not be needed but in case things are mis-sorted */
+ for (i = 0; i < start; i++) {
+ c = &ic->ic_channels[i];
+ if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
+ return 1;
+ }
+ return 0;
+}
+
+static struct ieee80211_channel *
+findchannel(struct ieee80211com *ic, int ieee, int mode)
+{
+ static const u_int chanflags[IEEE80211_MODE_MAX] = {
+ 0, /* IEEE80211_MODE_AUTO */
+ IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */
+ IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */
+ IEEE80211_CHAN_G, /* IEEE80211_MODE_11G */
+ IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */
+ IEEE80211_CHAN_108A, /* IEEE80211_MODE_TURBO_A */
+ IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */
+ IEEE80211_CHAN_STURBO, /* IEEE80211_MODE_STURBO_A */
+ /* NB: handled specially below */
+ IEEE80211_CHAN_A, /* IEEE80211_MODE_11NA */
+ IEEE80211_CHAN_G, /* IEEE80211_MODE_11NG */
+ };
+ u_int modeflags;
+ int i;
+
+ KASSERT(mode < IEEE80211_MODE_MAX, ("bad mode %u", mode));
+ modeflags = chanflags[mode];
+ KASSERT(modeflags != 0 || mode == IEEE80211_MODE_AUTO,
+ ("no chanflags for mode %u", mode));
+ for (i = 0; i < ic->ic_nchans; i++) {
+ struct ieee80211_channel *c = &ic->ic_channels[i];
+
+ if (c->ic_ieee != ieee)
+ continue;
+ if (mode == IEEE80211_MODE_AUTO) {
+ /* ignore turbo channels for autoselect */
+ if (IEEE80211_IS_CHAN_TURBO(c))
+ continue;
+ /*
+ * XXX special-case 11b/g channels so we
+ * always select the g channel if both
+ * are present.
+ * XXX prefer HT to non-HT?
+ */
+ if (!IEEE80211_IS_CHAN_B(c) ||
+ !find11gchannel(ic, i, c->ic_freq))
+ return c;
+ } else {
+ /* must check HT specially */
+ if ((mode == IEEE80211_MODE_11NA ||
+ mode == IEEE80211_MODE_11NG) &&
+ !IEEE80211_IS_CHAN_HT(c))
+ continue;
+ if ((c->ic_flags & modeflags) == modeflags)
+ return c;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Check the specified against any desired mode (aka netband).
+ * This is only used (presently) when operating in hostap mode
+ * to enforce consistency.
+ */
+static int
+check_mode_consistency(const struct ieee80211_channel *c, int mode)
+{
+ KASSERT(c != IEEE80211_CHAN_ANYC, ("oops, no channel"));
+
+ switch (mode) {
+ case IEEE80211_MODE_11B:
+ return (IEEE80211_IS_CHAN_B(c));
+ case IEEE80211_MODE_11G:
+ return (IEEE80211_IS_CHAN_ANYG(c) && !IEEE80211_IS_CHAN_HT(c));
+ case IEEE80211_MODE_11A:
+ return (IEEE80211_IS_CHAN_A(c) && !IEEE80211_IS_CHAN_HT(c));
+ case IEEE80211_MODE_STURBO_A:
+ return (IEEE80211_IS_CHAN_STURBO(c));
+ case IEEE80211_MODE_11NA:
+ return (IEEE80211_IS_CHAN_HTA(c));
+ case IEEE80211_MODE_11NG:
+ return (IEEE80211_IS_CHAN_HTG(c));
+ }
+ return 1;
+
+}
+
+/*
+ * Common code to set the current channel. If the device
+ * is up and running this may result in an immediate channel
+ * change or a kick of the state machine.
+ */
+static int
+setcurchan(struct ieee80211com *ic, struct ieee80211_channel *c)
+{
+ int error;
+
+ if (c != IEEE80211_CHAN_ANYC) {
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ !check_mode_consistency(c, ic->ic_des_mode))
+ return EINVAL;
+ if (ic->ic_state == IEEE80211_S_RUN && c == ic->ic_curchan)
+ return 0; /* NB: nothing to do */
+ }
+ ic->ic_des_chan = c;
+
+ error = 0;
+ if ((ic->ic_opmode == IEEE80211_M_MONITOR ||
+ ic->ic_opmode == IEEE80211_M_WDS) &&
+ ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
+ /*
+ * Monitor and wds modes can switch directly.
+ */
+ ic->ic_curchan = ic->ic_des_chan;
+ if (ic->ic_state == IEEE80211_S_RUN)
+ ic->ic_set_channel(ic);
+ } else {
+ /*
+ * Need to go through the state machine in case we
+ * need to reassociate or the like. The state machine
+ * will pickup the desired channel and avoid scanning.
+ */
+ if (IS_UP_AUTO(ic))
+ error = ieee80211_init(ic, RESCAN);
+ else if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
+ /*
+ * When not up+running and a real channel has
+ * been specified fix the current channel so
+ * there is immediate feedback; e.g. via ifconfig.
+ */
+ ic->ic_curchan = ic->ic_des_chan;
+ }
+ }
+ return error;
+}
+
+/*
+ * Old api for setting the current channel; this is
+ * deprecated because channel numbers are ambiguous.
+ */
+static int
+ieee80211_ioctl_setchannel(struct ieee80211com *ic,
+ const struct ieee80211req *ireq)
+{
+ struct ieee80211_channel *c;
+
+ /* XXX 0xffff overflows 16-bit signed */
+ if (ireq->i_val == 0 ||
+ ireq->i_val == (int16_t) IEEE80211_CHAN_ANY) {
+ c = IEEE80211_CHAN_ANYC;
+ } else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX) {
+ return EINVAL;
+ } else {
+ struct ieee80211_channel *c2;
+
+ c = findchannel(ic, ireq->i_val, ic->ic_des_mode);
+ if (c == NULL) {
+ c = findchannel(ic, ireq->i_val,
+ IEEE80211_MODE_AUTO);
+ if (c == NULL)
+ return EINVAL;
+ }
+ /*
+ * Fine tune channel selection based on desired mode:
+ * if 11b is requested, find the 11b version of any
+ * 11g channel returned,
+ * if static turbo, find the turbo version of any
+ * 11a channel return,
+ * if 11na is requested, find the ht version of any
+ * 11a channel returned,
+ * if 11ng is requested, find the ht version of any
+ * 11g channel returned,
+ * otherwise we should be ok with what we've got.
+ */
+ switch (ic->ic_des_mode) {
+ case IEEE80211_MODE_11B:
+ if (IEEE80211_IS_CHAN_ANYG(c)) {
+ c2 = findchannel(ic, ireq->i_val,
+ IEEE80211_MODE_11B);
+ /* NB: should not happen, =>'s 11g w/o 11b */
+ if (c2 != NULL)
+ c = c2;
+ }
+ break;
+ case IEEE80211_MODE_TURBO_A:
+ if (IEEE80211_IS_CHAN_A(c)) {
+ c2 = findchannel(ic, ireq->i_val,
+ IEEE80211_MODE_TURBO_A);
+ if (c2 != NULL)
+ c = c2;
+ }
+ break;
+ case IEEE80211_MODE_11NA:
+ if (IEEE80211_IS_CHAN_A(c)) {
+ c2 = findchannel(ic, ireq->i_val,
+ IEEE80211_MODE_11NA);
+ if (c2 != NULL)
+ c = c2;
+ }
+ break;
+ case IEEE80211_MODE_11NG:
+ if (IEEE80211_IS_CHAN_ANYG(c)) {
+ c2 = findchannel(ic, ireq->i_val,
+ IEEE80211_MODE_11NG);
+ if (c2 != NULL)
+ c = c2;
+ }
+ break;
+ default: /* NB: no static turboG */
+ break;
+ }
+ }
+ return setcurchan(ic, c);
+}
+
+/*
+ * New/current api for setting the current channel; a complete
+ * channel description is provide so there is no ambiguity in
+ * identifying the channel.
+ */
+static int
+ieee80211_ioctl_setcurchan(struct ieee80211com *ic,
+ const struct ieee80211req *ireq)
+{
+ struct ieee80211_channel chan, *c;
+ int error;
+
+ if (ireq->i_len != sizeof(chan))
+ return EINVAL;
+ error = copyin(ireq->i_data, &chan, sizeof(chan));
+ if (error != 0)
+ return error;
+ /* XXX 0xffff overflows 16-bit signed */
+ if (chan.ic_freq == 0 || chan.ic_freq == IEEE80211_CHAN_ANY) {
+ c = IEEE80211_CHAN_ANYC;
+ } else {
+ c = ieee80211_find_channel(ic, chan.ic_freq, chan.ic_flags);
+ if (c == NULL)
+ return EINVAL;
+ }
+ return setcurchan(ic, c);
+}
+
+static int
ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211req *ireq)
{
- static const u_int8_t zerobssid[IEEE80211_ADDR_LEN];
+ static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
struct ieee80211_rsnparms *rsn = &ic->ic_bss->ni_rsn;
int error;
const struct ieee80211_authenticator *auth;
- u_int8_t tmpkey[IEEE80211_KEYBUF_SIZE];
+ uint8_t tmpkey[IEEE80211_KEYBUF_SIZE];
char tmpssid[IEEE80211_NWID_LEN];
- u_int8_t tmpbssid[IEEE80211_ADDR_LEN];
+ uint8_t tmpbssid[IEEE80211_ADDR_LEN];
struct ieee80211_key *k;
int j, caps;
u_int kid;
@@ -2215,10 +1894,12 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
error = copyin(ireq->i_data, tmpssid, ireq->i_len);
if (error)
break;
- memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
- ic->ic_des_esslen = ireq->i_len;
- memcpy(ic->ic_des_essid, tmpssid, ireq->i_len);
- error = ENETRESET;
+ memset(ic->ic_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
+ ic->ic_des_ssid[0].len = ireq->i_len;
+ memcpy(ic->ic_des_ssid[0].ssid, tmpssid, ireq->i_len);
+ ic->ic_des_nssid = (ireq->i_len > 0);
+ if (IS_UP_AUTO(ic))
+ error = ieee80211_init(ic, RESCAN);
break;
case IEEE80211_IOC_WEP:
switch (ireq->i_val) {
@@ -2235,7 +1916,8 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
ic->ic_flags &= ~IEEE80211_F_DROPUNENC;
break;
}
- error = ENETRESET;
+ if (IS_UP_AUTO(ic))
+ error = ieee80211_init(ic, RESCAN);
break;
case IEEE80211_IOC_WEPKEY:
kid = (u_int) ireq->i_val;
@@ -2264,16 +1946,13 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
} else
error = EINVAL;
ieee80211_key_update_end(ic);
- if (!error) /* NB: for compatibility */
- error = ENETRESET;
break;
case IEEE80211_IOC_WEPTXKEY:
kid = (u_int) ireq->i_val;
if (kid >= IEEE80211_WEP_NKID &&
- (u_int16_t) kid != IEEE80211_KEYIX_NONE)
+ (uint16_t) kid != IEEE80211_KEYIX_NONE)
return EINVAL;
ic->ic_def_txkey = kid;
- error = ENETRESET; /* push to hardware */
break;
case IEEE80211_IOC_AUTHMODE:
switch (ireq->i_val) {
@@ -2313,48 +1992,11 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
ic->ic_bss->ni_authmode = ireq->i_val;
/* XXX mixed/mode/usage? */
ic->ic_auth = auth;
- error = ENETRESET;
+ if (IS_UP_AUTO(ic))
+ error = ieee80211_init(ic, RESCAN);
break;
case IEEE80211_IOC_CHANNEL:
- /* XXX 0xffff overflows 16-bit signed */
- if (ireq->i_val == 0 ||
- ireq->i_val == (int16_t) IEEE80211_CHAN_ANY)
- ic->ic_des_chan = IEEE80211_CHAN_ANYC;
- else if ((u_int) ireq->i_val > IEEE80211_CHAN_MAX ||
- isclr(ic->ic_chan_active, ireq->i_val)) {
- return EINVAL;
- } else
- ic->ic_ibss_chan = ic->ic_des_chan =
- &ic->ic_channels[ireq->i_val];
- switch (ic->ic_state) {
- case IEEE80211_S_INIT:
- case IEEE80211_S_SCAN:
- error = ENETRESET;
- break;
- default:
- /*
- * If the desired channel has changed (to something
- * other than any) and we're not already scanning,
- * then kick the state machine.
- */
- if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
- ic->ic_bss->ni_chan != ic->ic_des_chan &&
- (ic->ic_flags & IEEE80211_F_SCAN) == 0)
- error = ENETRESET;
- break;
- }
- if (error == ENETRESET &&
- ic->ic_opmode == IEEE80211_M_MONITOR) {
- if (IS_UP(ic)) {
- /*
- * Monitor mode can switch directly.
- */
- if (ic->ic_des_chan != IEEE80211_CHAN_ANYC)
- ic->ic_curchan = ic->ic_des_chan;
- error = ic->ic_reset(ic->ic_ifp);
- } else
- error = 0;
- }
+ error = ieee80211_ioctl_setchannel(ic, ireq);
break;
case IEEE80211_IOC_POWERSAVE:
switch (ireq->i_val) {
@@ -2402,14 +2044,15 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
return EINVAL;
ic->ic_protmode = ireq->i_val;
/* NB: if not operating in 11g this can wait */
- if (ic->ic_curmode == IEEE80211_MODE_11G)
+ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
+ IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
break;
case IEEE80211_IOC_TXPOWER:
if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
return EINVAL;
- if (!(IEEE80211_TXPOWER_MIN < ireq->i_val &&
- ireq->i_val < IEEE80211_TXPOWER_MAX))
+ if (!(IEEE80211_TXPOWER_MIN <= ireq->i_val &&
+ ireq->i_val <= IEEE80211_TXPOWER_MAX))
return EINVAL;
ic->ic_txpowlimit = ireq->i_val;
error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
@@ -2470,7 +2113,7 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
ic->ic_flags |= IEEE80211_F_WPA1 | IEEE80211_F_WPA2;
break;
}
- error = ENETRESET; /* XXX? */
+ error = ENETRESET;
break;
case IEEE80211_IOC_WME:
if (ireq->i_val) {
@@ -2479,7 +2122,8 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
ic->ic_flags |= IEEE80211_F_WME;
} else
ic->ic_flags &= ~IEEE80211_F_WME;
- error = ENETRESET; /* XXX maybe not for station? */
+ if (IS_UP_AUTO(ic))
+ error = ieee80211_init(ic, 0);
break;
case IEEE80211_IOC_HIDESSID:
if (ireq->i_val)
@@ -2542,8 +2186,8 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
break;
case IEEE80211_IOC_DRIVER_CAPS:
/* NB: for testing */
- ic->ic_caps = (((u_int16_t) ireq->i_val) << 16) |
- ((u_int16_t) ireq->i_len);
+ ic->ic_caps = (((uint16_t) ireq->i_val) << 16) |
+ ((uint16_t) ireq->i_len);
break;
case IEEE80211_IOC_KEYMGTALGS:
/* XXX check */
@@ -2566,17 +2210,21 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
ic->ic_flags &= ~IEEE80211_F_DESBSSID;
else
ic->ic_flags |= IEEE80211_F_DESBSSID;
- error = ENETRESET;
+ if (IS_UP_AUTO(ic))
+ error = ieee80211_init(ic, RESCAN);
break;
case IEEE80211_IOC_CHANLIST:
error = ieee80211_ioctl_setchanlist(ic, ireq);
break;
case IEEE80211_IOC_SCAN_REQ:
- if (ic->ic_opmode == IEEE80211_M_HOSTAP) /* XXX ignore */
- break;
- error = ieee80211_setupscan(ic, ic->ic_chan_avail);
- if (error == 0) /* XXX background scan */
- error = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ if (!IS_UP(ic))
+ return EINVAL;
+ (void) ieee80211_start_scan(ic,
+ IEEE80211_SCAN_ACTIVE |
+ IEEE80211_SCAN_NOPICK |
+ IEEE80211_SCAN_ONCE, IEEE80211_SCAN_FOREVER,
+ /* XXX use ioctl params */
+ ic->ic_des_nssid, ic->ic_des_ssid);
break;
case IEEE80211_IOC_ADDMAC:
case IEEE80211_IOC_DELMAC:
@@ -2627,9 +2275,72 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
else
ic->ic_flags &= ~IEEE80211_F_PUREG;
/* NB: reset only if we're operating on an 11g channel */
- if (ic->ic_curmode == IEEE80211_MODE_11G)
+ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
+ IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
error = ENETRESET;
break;
+ case IEEE80211_IOC_FF:
+ if (ireq->i_val) {
+ if ((ic->ic_caps & IEEE80211_C_FF) == 0)
+ return EINVAL;
+ ic->ic_flags |= IEEE80211_F_FF;
+ } else
+ ic->ic_flags &= ~IEEE80211_F_FF;
+ error = ENETRESET;
+ break;
+ case IEEE80211_IOC_TURBOP:
+ if (ireq->i_val) {
+ if ((ic->ic_caps & IEEE80211_C_TURBOP) == 0)
+ return EINVAL;
+ ic->ic_flags |= IEEE80211_F_TURBOP;
+ } else
+ ic->ic_flags &= ~IEEE80211_F_TURBOP;
+ error = ENETRESET;
+ break;
+ case IEEE80211_IOC_BGSCAN:
+ if (ireq->i_val) {
+ if ((ic->ic_caps & IEEE80211_C_BGSCAN) == 0)
+ return EINVAL;
+ ic->ic_flags |= IEEE80211_F_BGSCAN;
+ } else
+ ic->ic_flags &= ~IEEE80211_F_BGSCAN;
+ break;
+ case IEEE80211_IOC_BGSCAN_IDLE:
+ if (ireq->i_val >= IEEE80211_BGSCAN_IDLE_MIN)
+ ic->ic_bgscanidle = ireq->i_val*hz/1000;
+ else
+ error = EINVAL;
+ break;
+ case IEEE80211_IOC_BGSCAN_INTERVAL:
+ if (ireq->i_val >= IEEE80211_BGSCAN_INTVAL_MIN)
+ ic->ic_bgscanintvl = ireq->i_val*hz;
+ else
+ error = EINVAL;
+ break;
+ case IEEE80211_IOC_SCANVALID:
+ if (ireq->i_val >= IEEE80211_SCAN_VALID_MIN)
+ ic->ic_scanvalid = ireq->i_val*hz;
+ else
+ error = EINVAL;
+ break;
+ case IEEE80211_IOC_ROAM_RSSI_11A:
+ ic->ic_roam.rssi11a = ireq->i_val;
+ break;
+ case IEEE80211_IOC_ROAM_RSSI_11B:
+ ic->ic_roam.rssi11bOnly = ireq->i_val;
+ break;
+ case IEEE80211_IOC_ROAM_RSSI_11G:
+ ic->ic_roam.rssi11b = ireq->i_val;
+ break;
+ case IEEE80211_IOC_ROAM_RATE_11A:
+ ic->ic_roam.rate11a = ireq->i_val & IEEE80211_RATE_VAL;
+ break;
+ case IEEE80211_IOC_ROAM_RATE_11B:
+ ic->ic_roam.rate11bOnly = ireq->i_val & IEEE80211_RATE_VAL;
+ break;
+ case IEEE80211_IOC_ROAM_RATE_11G:
+ ic->ic_roam.rate11b = ireq->i_val & IEEE80211_RATE_VAL;
+ break;
case IEEE80211_IOC_MCAST_RATE:
ic->ic_mcast_rate = ireq->i_val & IEEE80211_RATE_VAL;
break;
@@ -2659,12 +2370,112 @@ ieee80211_ioctl_set80211(struct ieee80211com *ic, u_long cmd, struct ieee80211re
ic->ic_bmissthreshold = ireq->i_val;
error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
break;
+ case IEEE80211_IOC_CURCHAN:
+ error = ieee80211_ioctl_setcurchan(ic, ireq);
+ break;
+ case IEEE80211_IOC_SHORTGI:
+ if (ireq->i_val) {
+#define IEEE80211_HTCAP_SHORTGI \
+ (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40)
+ if (((ireq->i_val ^ ic->ic_htcaps) & IEEE80211_HTCAP_SHORTGI) != 0)
+ return EINVAL;
+ if (ireq->i_val & IEEE80211_HTCAP_SHORTGI20)
+ ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI20;
+ if (ireq->i_val & IEEE80211_HTCAP_SHORTGI40)
+ ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI40;
+#undef IEEE80211_HTCAP_SHORTGI
+ } else
+ ic->ic_flags_ext &=
+ ~(IEEE80211_FEXT_SHORTGI20 | IEEE80211_FEXT_SHORTGI40);
+ /* XXX kick state machine? */
+ error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
+ break;
+ case IEEE80211_IOC_AMPDU:
+ if (ireq->i_val) {
+ if ((ic->ic_htcaps & IEEE80211_HTC_AMPDU) == 0)
+ return EINVAL;
+ if (ireq->i_val & 1)
+ ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
+ if (ireq->i_val & 2)
+ ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
+ } else
+ ic->ic_flags_ext &=
+ ~(IEEE80211_FEXT_AMPDU_TX|IEEE80211_FEXT_AMPDU_RX);
+ /* NB: reset only if we're operating on an 11n channel */
+ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
+ IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
+ error = ENETRESET;
+ break;
+ case IEEE80211_IOC_AMPDU_LIMIT:
+ /* XXX validate */
+ ic->ic_ampdu_limit = ireq->i_val;
+ break;
+ case IEEE80211_IOC_AMPDU_DENSITY:
+ /* XXX validate */
+ ic->ic_ampdu_density = ireq->i_val;
+ break;
+ case IEEE80211_IOC_AMSDU:
+ if (ireq->i_val) {
+ if ((ic->ic_htcaps & IEEE80211_HTC_AMSDU) == 0)
+ return EINVAL;
+ if (ireq->i_val & 1)
+ ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
+ if (ireq->i_val & 2)
+ ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
+ } else
+ ic->ic_flags_ext &=
+ ~(IEEE80211_FEXT_AMSDU_TX|IEEE80211_FEXT_AMSDU_RX);
+ /* NB: reset only if we're operating on an 11n channel */
+ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
+ IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
+ error = ENETRESET;
+ break;
+ case IEEE80211_IOC_AMSDU_LIMIT:
+ /* XXX validate */
+ ic->ic_amsdu_limit = ireq->i_val; /* XXX truncation? */
+ break;
+ case IEEE80211_IOC_PUREN:
+ if (ireq->i_val) {
+ if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
+ return EINVAL;
+ ic->ic_flags_ext |= IEEE80211_FEXT_PUREN;
+ } else
+ ic->ic_flags_ext &= ~IEEE80211_FEXT_PUREN;
+ /* NB: reset only if we're operating on an 11n channel */
+ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
+ IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
+ error = ENETRESET;
+ break;
+ case IEEE80211_IOC_DOTH:
+ if (ireq->i_val) {
+#if 0
+ /* XXX no capability */
+ if ((ic->ic_caps & IEEE80211_C_DOTH) == 0)
+ return EINVAL;
+#endif
+ ic->ic_flags |= IEEE80211_F_DOTH;
+ } else
+ ic->ic_flags &= ~IEEE80211_F_DOTH;
+ error = IS_UP(ic) ? ic->ic_reset(ic->ic_ifp) : 0;
+ break;
+ case IEEE80211_IOC_HTCOMPAT:
+ if (ireq->i_val) {
+ if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) == 0)
+ return EINVAL;
+ ic->ic_flags_ext |= IEEE80211_FEXT_HTCOMPAT;
+ } else
+ ic->ic_flags_ext &= ~IEEE80211_FEXT_HTCOMPAT;
+ /* NB: reset only if we're operating on an 11n channel */
+ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
+ IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
+ error = ENETRESET;
+ break;
default:
error = EINVAL;
break;
}
- if (error == ENETRESET && !IS_UP_AUTO(ic))
- error = 0;
+ if (error == ENETRESET)
+ error = IS_UP_AUTO(ic) ? ieee80211_init(ic, 0) : 0;
return error;
}
@@ -2692,15 +2503,6 @@ ieee80211_ioctl(struct ieee80211com *ic, u_long cmd, caddr_t data)
error = ieee80211_ioctl_set80211(ic, cmd,
(struct ieee80211req *) data);
break;
- case SIOCGIFGENERIC:
- error = ieee80211_cfgget(ic, cmd, data);
- break;
- case SIOCSIFGENERIC:
- error = priv_check(curthread, PRIV_NET80211_MANAGE);
- if (error)
- break;
- error = ieee80211_cfgset(ic, cmd, data);
- break;
case SIOCG80211STATS:
ifr = (struct ifreq *)data;
copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));