diff options
author | thompsa <thompsa@FreeBSD.org> | 2007-07-12 02:54:05 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2007-07-12 02:54:05 +0000 |
commit | b4a663c82ad0a4c227971f6662fb4715b6acecdb (patch) | |
tree | bb253fe610d5f1c2e0a93345032842d56e457bad /sys | |
parent | 1f75e6a1254a7cba32e7866028f470f6da00741a (diff) | |
download | FreeBSD-src-b4a663c82ad0a4c227971f6662fb4715b6acecdb.zip FreeBSD-src-b4a663c82ad0a4c227971f6662fb4715b6acecdb.tar.gz |
Improve the net80211 handling within ndis
- use net80211 for scanning and pass the results back to the scan cache
- use ieee80211_init_channels to fill our channel list
- fix up state transitions
- depreciate the old wicontrol ioctls
- add some debugging lines (#define NDIS_DEBUG)
Reviewed by: sam
Approved by: re (kensmith)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/if_ndis/if_ndis.c | 453 | ||||
-rw-r--r-- | sys/dev/if_ndis/if_ndisvar.h | 8 |
2 files changed, 303 insertions, 158 deletions
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index f4a3e8c..cba39c8 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sockio.h> #include <sys/mbuf.h> #include <sys/malloc.h> +#include <sys/endian.h> #include <sys/priv.h> #include <sys/kernel.h> #include <sys/socket.h> @@ -50,6 +51,8 @@ __FBSDID("$FreeBSD$"); #if __FreeBSD_version < 502113 #include <sys/sysctl.h> #endif +#include <sys/kthread.h> +#include <sys/taskqueue.h> #include <net/if.h> @@ -69,8 +72,11 @@ __FBSDID("$FreeBSD$"); #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_ioctl.h> +#include <net80211/ieee80211_regdomain.h> +#if __FreeBSD_version < 700046 #include <dev/wi/if_wavelan_ieee.h> +#endif #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> @@ -83,6 +89,12 @@ __FBSDID("$FreeBSD$"); #include <compat/ndis/ndis_var.h> #include <dev/if_ndis/if_ndisvar.h> +#ifdef NDIS_DEBUG +#define DPRINTF(x) printf x +#else +#define DPRINTF(x) +#endif + MODULE_DEPEND(ndis, ether, 1, 1, 1); MODULE_DEPEND(ndis, wlan, 1, 1, 1); MODULE_DEPEND(ndis, ndisapi, 1, 1, 1); @@ -130,10 +142,21 @@ static void ndis_starttask (device_object *, void *); static void ndis_resettask (device_object *, void *); static void ndis_inputtask (device_object *, void *); static int ndis_ioctl (struct ifnet *, u_long, caddr_t); +#if __FreeBSD_version < 700046 static int ndis_wi_ioctl_get (struct ifnet *, u_long, caddr_t); static int ndis_wi_ioctl_set (struct ifnet *, u_long, caddr_t); +#endif static int ndis_80211_ioctl_get (struct ifnet *, u_long, caddr_t); static int ndis_80211_ioctl_set (struct ifnet *, u_long, caddr_t); +static int ndis_newstate (struct ieee80211com *, enum ieee80211_state, + int); +static void ndis_scan (void *, int); +static void ndis_scan_results (struct ndis_softc *); +static void ndis_scan_start (struct ieee80211com *); +static void ndis_scan_end (struct ieee80211com *); +static void ndis_set_channel (struct ieee80211com *); +static void ndis_scan_curchan (struct ieee80211com *, unsigned long); +static void ndis_scan_mindwell (struct ieee80211com *); static void ndis_init (void *); static void ndis_stop (struct ndis_softc *); static void ndis_watchdog (struct ifnet *); @@ -477,8 +500,8 @@ ndis_attach(dev) driver_object *pdrv; device_object *pdo; struct ifnet *ifp = NULL; - int error = 0, len; - int i, j; + int error = 0, len, bands = 0; + int i; sc = device_get_softc(dev); #if __FreeBSD_version < 600031 @@ -680,13 +703,25 @@ ndis_attach(dev) uint32_t arg; int r; +#if __FreeBSD_version >= 700000 + sc->ndis_tq = taskqueue_create("nids_taskq", M_NOWAIT | M_ZERO, + taskqueue_thread_enqueue, &sc->ndis_tq); + taskqueue_start_threads(&sc->ndis_tq, 1, PI_NET, "%s taskq", + device_get_nameunit(dev)); +#else + sc->ndis_tq = taskqueue_create("ndis_taskq", M_NOWAIT | M_ZERO, + taskqueue_thread_enqueue, &sc->ndis_tq, &sc->sc_tqproc); + kthread_create(taskqueue_thread_loop, &sc->ndis_tq, &sc->sc_tqproc, + 0, 0, "%s taskq", device_get_nameunit(dev)); +#endif + TASK_INIT(&sc->ndis_scantask, 0, ndis_scan, sc); + #if __FreeBSD_version >= 600007 ic->ic_ifp = ifp; #endif ic->ic_phytype = IEEE80211_T_DS; ic->ic_opmode = IEEE80211_M_STA; ic->ic_caps = IEEE80211_C_IBSS; - ic->ic_state = IEEE80211_S_ASSOC; setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO); len = 0; r = ndis_get_info(sc, OID_802_11_NETWORK_TYPES_SUPPORTED, @@ -706,12 +741,15 @@ ndis_attach(dev) case NDIS_80211_NETTYPE_11FH: case NDIS_80211_NETTYPE_11DS: setbit(ic->ic_modecaps, IEEE80211_MODE_11B); + setbit(&bands, IEEE80211_MODE_11B); break; case NDIS_80211_NETTYPE_11OFDM5: setbit(ic->ic_modecaps, IEEE80211_MODE_11A); + setbit(&bands, IEEE80211_MODE_11A); break; case NDIS_80211_NETTYPE_11OFDM24: setbit(ic->ic_modecaps, IEEE80211_MODE_11G); + setbit(&bands, IEEE80211_MODE_11G); break; default: break; @@ -817,25 +855,7 @@ nonettypes: } #undef SETRATE #undef INCRATE - ic->ic_nchans = 12; - /* - * Taking yet more guesses here. - */ - for (j = 0, i = 1; i <= 12; i++, j++) { - int chanflag = 0; - - if (ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates) - chanflag |= IEEE80211_CHAN_G; - if (i <= 14) - chanflag |= IEEE80211_CHAN_B; - if (ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates && - i > 14) - chanflag = IEEE80211_CHAN_A; - if (chanflag == 0) - break; - ic->ic_channels[j].ic_freq = ieee80211_ieee2mhz(i, chanflag); - ic->ic_channels[j].ic_flags = chanflag; - } + ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1); /* * To test for WPA support, we need to see if we can @@ -897,8 +917,16 @@ got_crypto: ieee80211_media_init(ic, ieee80211_media_change, ndis_media_status); #endif + ic->ic_scan_start = ndis_scan_start; + ic->ic_scan_end = ndis_scan_end; + ic->ic_set_channel = ndis_set_channel; + ic->ic_scan_curchan = ndis_scan_curchan; + ic->ic_scan_mindwell = ndis_scan_mindwell; ic->ic_bsschan = IEEE80211_CHAN_ANYC; ic->ic_bss->ni_chan = ic->ic_bsschan; + /* override state transition machine */ + sc->ndis_newstate = ic->ic_newstate; + ic->ic_newstate = ndis_newstate; #ifdef IEEE80211_F_WPA /* install key handing routines */ ic->ic_crypto.cs_key_set = ndis_add_key; @@ -1021,6 +1049,7 @@ ndis_detach(dev) if (sc->ndis_iftype == PCIBus) bus_dma_tag_destroy(sc->ndis_parent_tag); + taskqueue_free(sc->ndis_tq); #if __FreeBSD_version < 502113 sysctl_ctx_free(&sc->ndis_ctx); #endif @@ -1640,7 +1669,7 @@ ndis_ticktask(d, xsc) NDIS_UNLOCK(sc); if (sc->ndis_80211) { ndis_getstate_80211(sc); - ic->ic_state = IEEE80211_S_RUN; + ieee80211_new_state(ic, IEEE80211_S_RUN, -1); } NDIS_LOCK(sc); #ifdef LINK_STATE_UP @@ -1659,7 +1688,7 @@ ndis_ticktask(d, xsc) sc->ndis_sts == NDIS_STATUS_MEDIA_DISCONNECT) { sc->ndis_link = 0; if (sc->ndis_80211) - ic->ic_state = IEEE80211_S_ASSOC; + ieee80211_new_state(ic, IEEE80211_S_SCAN, 0); #ifdef LINK_STATE_DOWN #if __FreeBSD_version > 600006 if_link_state_change(sc->ifp, LINK_STATE_DOWN); @@ -1880,6 +1909,7 @@ ndis_init(xsc) void *xsc; { struct ndis_softc *sc = xsc; + struct ieee80211com *ic = (void *)&sc->ic; struct ifnet *ifp = sc->ifp; int i, len, error; @@ -1954,6 +1984,18 @@ ndis_init(xsc) #endif #endif /* LINK_STATE_UNKNOWN */ + if (ic->ic_opmode != IEEE80211_M_MONITOR) { + /* + * NB: When restarting the adapter clock the state + * machine regardless of the roaming mode; otherwise + * we need to notify user apps so they can manually + * get us going again. + */ + if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) + ieee80211_new_state(ic, IEEE80211_S_SCAN, 0); + } else + ieee80211_new_state(ic, IEEE80211_S_RUN, -1); + ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; @@ -2073,6 +2115,7 @@ ndis_set_cipher(sc, cipher) arg = NDIS_80211_WEPSTAT_ENC3ENABLED; } + DPRINTF(("Setting cipher to %d\n", arg)); save = arg; rval = ndis_set_info(sc, OID_802_11_ENCRYPTION_STATUS, &arg, &len); @@ -2123,8 +2166,10 @@ ndis_set_wpa(sc) w = (struct ieee80211_ie_wpa *)ic->ic_opt_ie; /* Check for the right kind of IE. */ - if (w->wpa_id != IEEE80211_ELEMID_VENDOR) + if (w->wpa_id != IEEE80211_ELEMID_VENDOR) { + DPRINTF(("Incorrect IE type %d\n", w->wpa_id)); return(EINVAL); + } /* Skip over the ucast cipher OIDs. */ pos = (char *)&w->wpa_uciphers[0]; @@ -2148,6 +2193,7 @@ ndis_set_wpa(sc) if (n->ni_val == WPA_ASE_8021X_PSK) arg = NDIS_80211_AUTHMODE_WPAPSK; + DPRINTF(("Setting WPA auth mode to %d\n", arg)); i = sizeof(arg); if (ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &i)) return(ENOTSUP); @@ -2181,6 +2227,7 @@ ndis_setstate_80211(sc) struct ndis_softc *sc; { struct ieee80211com *ic; + struct ieee80211_node *ni; ndis_80211_ssid ssid; ndis_80211_macaddr bssid; ndis_80211_config config; @@ -2191,9 +2238,12 @@ ndis_setstate_80211(sc) ic = &sc->ic; ifp = sc->ifp; + ni = ic->ic_bss; - if (!NDIS_INITIALIZED(sc)) + if (!NDIS_INITIALIZED(sc)) { + DPRINTF(("%s: NDIS not initialized\n", __func__)); return; + } /* Disassociate and turn off radio. */ @@ -2270,6 +2320,7 @@ ndis_setstate_80211(sc) if (ic->ic_bss->ni_authmode == IEEE80211_AUTH_SHARED) { len = sizeof(arg); arg = NDIS_80211_AUTHMODE_SHARED; + DPRINTF(("Setting shared auth\n")); ndis_set_info(sc, OID_802_11_AUTHENTICATION_MODE, &arg, &len); } @@ -2307,6 +2358,7 @@ ndis_setstate_80211(sc) bcopy(ic->ic_nw_keys[i].wk_key, wep.nw_keydata, wep.nw_length); len = sizeof(wep); + DPRINTF(("Setting WEP key %d\n", i)); rval = ndis_set_info(sc, OID_802_11_ADD_WEP, &wep, &len); if (rval) @@ -2316,6 +2368,7 @@ ndis_setstate_80211(sc) } } if (keys_set) { + DPRINTF(("Setting WEP on\n")); arg = NDIS_80211_WEPSTAT_ENABLED; len = sizeof(arg); rval = ndis_set_info(sc, @@ -2366,6 +2419,7 @@ ndis_setstate_80211(sc) } if (arg) { + DPRINTF(("Setting network type to %d\n", arg)); len = sizeof(arg); rval = ndis_set_info(sc, OID_802_11_NETWORK_TYPE_IN_USE, &arg, &len); @@ -2406,6 +2460,7 @@ ndis_setstate_80211(sc) config.nc_length = len; config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh); + DPRINTF(("Setting channel to %ukHz\n", config.nc_dsconfig)); rval = ndis_set_info(sc, OID_802_11_CONFIGURATION, &config, &len); if (rval) @@ -2434,10 +2489,11 @@ ndis_setstate_80211(sc) len = IEEE80211_ADDR_LEN; if (ic->ic_flags & IEEE80211_F_DESBSSID && ic->ic_opmode != IEEE80211_M_IBSS) - bcopy(ic->ic_des_bssid, bssid, len); + bcopy(ni->ni_bssid, bssid, len); else bcopy(ifp->if_broadcastaddr, bssid, len); + DPRINTF(("Setting BSSID to %6D\n", &bssid, ":")); rval = ndis_set_info(sc, OID_802_11_BSSID, &bssid, &len); if (rval) device_printf(sc->ndis_dev, @@ -2445,20 +2501,27 @@ ndis_setstate_80211(sc) /* Set SSID -- always do this last. */ +#ifdef NDIS_DEBUG + printf("Setting ESSID to "); + ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); + printf("\n"); +#endif + len = sizeof(ssid); bzero((char *)&ssid, len); - ssid.ns_ssidlen = ic->ic_des_ssid[0].len; + ssid.ns_ssidlen = ni->ni_esslen; if (ssid.ns_ssidlen == 0) { ssid.ns_ssidlen = 1; } else - bcopy(ic->ic_des_ssid[0].ssid, ssid.ns_ssid, ssid.ns_ssidlen); + bcopy(ni->ni_essid, ssid.ns_ssid, ssid.ns_ssidlen); rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len); if (rval) device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval); - ic->ic_state = IEEE80211_S_ASSOC; + if (ic->ic_state == IEEE80211_S_AUTH) + ieee80211_new_state(ic, IEEE80211_S_ASSOC, 0); return; } @@ -2579,7 +2642,7 @@ ndis_getstate_80211(sc) struct ieee80211com *ic; ndis_wlan_bssid_ex *bs; int rval, len, i = 0; - int chan; + int chanflag; uint32_t arg; struct ifnet *ifp; @@ -2589,12 +2652,6 @@ ndis_getstate_80211(sc) if (!NDIS_INITIALIZED(sc)) return; - if (sc->ndis_link) - ic->ic_state = IEEE80211_S_RUN; - else - ic->ic_state = IEEE80211_S_ASSOC; - - /* * If we're associated, retrieve info on the current bssid. */ @@ -2603,16 +2660,20 @@ ndis_getstate_80211(sc) case NDIS_80211_NETTYPE_11FH: case NDIS_80211_NETTYPE_11DS: ic->ic_curmode = IEEE80211_MODE_11B; + chanflag = IEEE80211_CHAN_B; break; case NDIS_80211_NETTYPE_11OFDM5: ic->ic_curmode = IEEE80211_MODE_11A; + chanflag = IEEE80211_CHAN_A; break; case NDIS_80211_NETTYPE_11OFDM24: ic->ic_curmode = IEEE80211_MODE_11G; + chanflag = IEEE80211_CHAN_G; break; default: device_printf(sc->ndis_dev, "unknown nettype %d\n", arg); + chanflag = 0; break; } IEEE80211_ADDR_COPY(ic->ic_bss->ni_bssid, bs->nwbx_macaddr); @@ -2673,22 +2734,13 @@ ndis_getstate_80211(sc) * Use the current association information to reflect * what channel we're on. */ - - chan = ieee80211_mhz2ieee(bs->nwbx_config.nc_dsconfig / 1000, 0); - if (chan < 0 || chan >= IEEE80211_CHAN_MAX) { - if (ifp->if_flags & IFF_DEBUG) - device_printf(sc->ndis_dev, "current channel " - "(%uMHz) out of bounds\n", - bs->nwbx_config.nc_dsconfig / 1000); - chan = 1; - } - - ic->ic_bss->ni_chan = &ic->ic_channels[chan]; - ic->ic_des_chan = &ic->ic_channels[chan]; - ic->ic_bsschan = &ic->ic_channels[chan]; -#if __FreeBSD_version >= 600007 - ic->ic_curchan = &ic->ic_channels[chan]; -#endif + ic->ic_curchan = ieee80211_find_channel(ic, + bs->nwbx_config.nc_dsconfig / 1000, chanflag); + if (ic->ic_curchan == NULL) + ic->ic_curchan = &ic->ic_channels[0]; + ic->ic_bss->ni_chan = ic->ic_curchan; + ic->ic_des_chan = ic->ic_curchan; + ic->ic_bsschan = ic->ic_curchan; free(bs, M_TEMP); @@ -2945,6 +2997,7 @@ ndis_ioctl(ifp, command, data) NDIS_EVTINC(sc->ndis_evtcidx); NDIS_UNLOCK(sc); break; +#if __FreeBSD_version < 700046 case SIOCGIFGENERIC: case SIOCSIFGENERIC: if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) { @@ -2956,6 +3009,7 @@ ndis_ioctl(ifp, command, data) error = ENOTTY; if (error != ENOTTY) break; +#endif default: do_80211: sc->ndis_skip = 1; @@ -2980,6 +3034,7 @@ do_80211: return(error); } +#if __FreeBSD_version < 700046 static int ndis_wi_ioctl_get(ifp, command, data) struct ifnet *ifp; @@ -3097,19 +3152,13 @@ ndis_wi_ioctl_set(ifp, command, data) } return (error); } +#endif static int ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data) { struct ndis_softc *sc; struct ieee80211req *ireq; -#ifdef RTM_IEEE80211_SCAN - ndis_80211_bssid_list_ex *bl; - ndis_wlan_bssid_ex *wb; - struct ieee80211req_scan_result *sr, *bsr; - int i, j; - char *cp; -#endif int error, len; uint16_t nodename_u[IEEE80211_NWID_LEN + 1]; unicode_string us; @@ -3124,91 +3173,6 @@ ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data) error = 0; break; #endif -#ifdef RTM_IEEE80211_SCAN - case IEEE80211_IOC_SCAN_RESULTS: - len = 0; - error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len); - if (error != ENOSPC) - len = 65536; - bl = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); - error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len); - if (error) { - free(bl, M_DEVBUF); - break; - } - sr = bsr = malloc(ireq->i_len, M_DEVBUF, M_NOWAIT | M_ZERO); - wb = &bl->nblx_bssid[0]; - len = 0; - for (i = 0; i < bl->nblx_items; i++) { - /* - * Check if we have enough space left for this ap. - * Note that the size of the SSID list structure - * can vary: the extended structure with info - * elements is only supported by NDIS 5.1 drivers. - */ - if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) { - j = roundup(sizeof(*sr) + - wb->nwbx_ssid.ns_ssidlen + - wb->nwbx_ielen - - sizeof(struct ndis_80211_fixed_ies), - sizeof(uint32_t)); - } else { - j = roundup(sizeof(*sr) + - wb->nwbx_ssid.ns_ssidlen + - sizeof(struct ndis_80211_fixed_ies), - sizeof(uint32_t)); - } - if (len + j > ireq->i_len) - break; - bcopy(&wb->nwbx_macaddr, &sr->isr_bssid, - sizeof(sr->isr_bssid)); - if (wb->nwbx_privacy) - sr->isr_capinfo |= IEEE80211_CAPINFO_PRIVACY; - sr->isr_rssi = wb->nwbx_rssi + 200; - sr->isr_freq = wb->nwbx_config.nc_dsconfig / 1000; - sr->isr_intval = wb->nwbx_config.nc_beaconperiod; - switch (wb->nwbx_netinfra) { - case NDIS_80211_NET_INFRA_IBSS: - sr->isr_capinfo |= IEEE80211_CAPINFO_IBSS; - break; - case NDIS_80211_NET_INFRA_BSS: - sr->isr_capinfo |= IEEE80211_CAPINFO_ESS; - break; - } - for (j = 0; j < sizeof(sr->isr_rates); j++) { - /* XXX - check units */ - if (wb->nwbx_supportedrates[j] == 0) - break; - sr->isr_rates[j] = - wb->nwbx_supportedrates[j] & 0x7f; - } - sr->isr_nrates = j; - sr->isr_ssid_len = wb->nwbx_ssid.ns_ssidlen; - cp = (char *)sr + sizeof(*sr); - bcopy(&wb->nwbx_ssid.ns_ssid, cp, sr->isr_ssid_len); - cp += sr->isr_ssid_len; - if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) { - sr->isr_ie_len = wb->nwbx_ielen - - sizeof(struct ndis_80211_fixed_ies); - bcopy((char *)wb->nwbx_ies + - sizeof(struct ndis_80211_fixed_ies), - cp, sr->isr_ie_len); - } else { - sr->isr_ie_len = 0; - } - sr->isr_len = roundup(sizeof(*sr) + sr->isr_ssid_len - + sr->isr_ie_len, sizeof(uint32_t)); - len += sr->isr_len; - sr = (struct ieee80211req_scan_result *)((char *)sr + - sr->isr_len); - wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len); - } - ireq->i_len = len; - error = copyout(bsr, ireq->i_data, len); - free(bl, M_DEVBUF); - free(bsr, M_DEVBUF); - break; -#endif case IEEE80211_IOC_STATIONNAME: error = ndis_get_info(sc, OID_GEN_MACHINE_NAME, &nodename_u, &len); @@ -3365,23 +3329,12 @@ ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data) ireq = (struct ieee80211req *) data; switch (ireq->i_type) { -#ifdef IEEE80211_IOC_MLME - case IEEE80211_IOC_MLME: - case IEEE80211_IOC_ROAMING: +#ifdef IEEE80211_IOC_COUNTERMEASURES case IEEE80211_IOC_COUNTERMEASURES: case IEEE80211_IOC_DROPUNENCRYPTED: error = 0; break; #endif -#ifdef RTM_IEEE80211_SCAN - case IEEE80211_IOC_SCAN_REQ: - len = 0; - error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, - NULL, &len); - tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2); - rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); - break; -#endif case IEEE80211_IOC_STATIONNAME: error = priv_check(curthread, PRIV_NET80211_MANAGE); if (error) @@ -3466,7 +3419,7 @@ ndis_stop(sc) ic = &sc->ic; if (sc->ndis_80211) - ic->ic_state = IEEE80211_S_INIT; + ieee80211_new_state(ic, IEEE80211_S_INIT, -1); ifp = sc->ifp; untimeout(ndis_tick, sc, sc->ndis_stat_ch); @@ -3508,3 +3461,187 @@ ndis_shutdown(dev) return; } + +static int +ndis_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) +{ + struct ifnet *ifp = ic->ic_ifp; + struct ndis_softc *sc = ifp->if_softc; + enum ieee80211_state ostate; + + DPRINTF(("%s: %s -> %s\n", __func__, + ieee80211_state_name[ic->ic_state], + ieee80211_state_name[nstate])); + + ostate = ic->ic_state; + ic->ic_state = nstate; + + switch (nstate) { + /* pass on to net80211 */ + case IEEE80211_S_INIT: + case IEEE80211_S_SCAN: + return (sc->ndis_newstate(ic, nstate, arg)); + + case IEEE80211_S_ASSOC: + if (ostate != IEEE80211_S_AUTH) + ndis_setstate_80211(sc); + break; + + case IEEE80211_S_AUTH: + ndis_setstate_80211(sc); + break; + + default: + break; + } + return (0); +} + +static void +ndis_scan(void *arg, int npending) +{ + struct ndis_softc *sc = arg; + struct ieee80211com *ic = (void *)&sc->ic; + int error, len; + + len = 0; + error = ndis_set_info(sc, OID_802_11_BSSID_LIST_SCAN, + NULL, &len); + tsleep(&error, PPAUSE|PCATCH, "ssidscan", hz * 2); + ndis_scan_results(sc); + ieee80211_scan_done(ic); +} + +static void +ndis_scan_results(struct ndis_softc *sc) +{ + struct ieee80211com *ic = (void *)&sc->ic; + ndis_80211_bssid_list_ex *bl; + ndis_wlan_bssid_ex *wb; + struct ieee80211_scanparams sp; + struct ieee80211_frame wh; + int i, j; + int error, len, rssi, noise; + static long rstamp; + uint8_t ssid[2+IEEE80211_NWID_LEN]; + uint8_t rates[2+IEEE80211_RATE_MAXSIZE]; + uint8_t *frm, *efrm; + + len = 0; + noise = -96; + error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len); + if (error != ENOSPC) + len = 65536; + bl = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); + error = ndis_get_info(sc, OID_802_11_BSSID_LIST, bl, &len); + if (error) { + free(bl, M_DEVBUF); + return;; + } + + rstamp++; + wb = &bl->nblx_bssid[0]; + for (i = 0; i < bl->nblx_items; i++) { + memset(&sp, 0, sizeof(sp)); + + memcpy(wh.i_addr2, wb->nwbx_macaddr, sizeof(wh.i_addr2)); + memcpy(wh.i_addr3, wb->nwbx_macaddr, sizeof(wh.i_addr3)); + rssi = (wb->nwbx_rssi - noise) / (-32 - noise) * 100; + rssi = max(0, min(rssi, 100)); /* limit 0 <= rssi <= 100 */ + if (wb->nwbx_privacy) + sp.capinfo |= IEEE80211_CAPINFO_PRIVACY; + sp.bintval = wb->nwbx_config.nc_beaconperiod; + switch (wb->nwbx_netinfra) { + case NDIS_80211_NET_INFRA_IBSS: + sp.capinfo |= IEEE80211_CAPINFO_IBSS; + break; + case NDIS_80211_NET_INFRA_BSS: + sp.capinfo |= IEEE80211_CAPINFO_ESS; + break; + } + sp.rates = &rates[0]; + for (j = 0; j < IEEE80211_RATE_MAXSIZE; j++) { + /* XXX - check units */ + if (wb->nwbx_supportedrates[j] == 0) + break; + rates[2 + j] = + wb->nwbx_supportedrates[j] & 0x7f; + } + rates[1] = j; + sp.ssid = (uint8_t *)&ssid[0]; + memcpy(sp.ssid + 2, &wb->nwbx_ssid.ns_ssid, + wb->nwbx_ssid.ns_ssidlen); + sp.ssid[1] = wb->nwbx_ssid.ns_ssidlen; + + sp.bchan = ieee80211_mhz2ieee( + wb->nwbx_config.nc_dsconfig / 1000, 0); + sp.curchan = ieee80211_find_channel(ic, + ieee80211_ieee2mhz(sp.bchan, IEEE80211_CHAN_B), + IEEE80211_CHAN_B); + if (sp.curchan == NULL) + sp.curchan = &ic->ic_channels[0]; + + /* Process extended info from AP */ + if (wb->nwbx_len > sizeof(ndis_wlan_bssid)) { + frm = (uint8_t *)&wb->nwbx_ies; + efrm = frm + wb->nwbx_ielen; + if (efrm - frm < 12) + goto done; + sp.tstamp = frm; + frm += 8; + sp.bintval = le16toh(*(uint16_t *)frm); + frm += 2; + sp.capinfo = le16toh(*(uint16_t *)frm); + frm += 2; + + /* Grab variable length ies */ + while (efrm - frm > 1) { + if (efrm - frm < frm[1] + 2) + break; + switch (*frm) { + case IEEE80211_ELEMID_RSN: + sp.rsn = frm; + break; + } + frm += frm[1] + 2; + } + } +done: + ieee80211_add_scan(ic, &sp, &wh, 0, rssi, noise, rstamp); + wb = (ndis_wlan_bssid_ex *)((char *)wb + wb->nwbx_len); + } +} + +static void +ndis_scan_start(struct ieee80211com *ic) +{ + struct ifnet *ifp = ic->ic_ifp; + struct ndis_softc *sc = ifp->if_softc; + + taskqueue_enqueue(sc->ndis_tq, &sc->ndis_scantask); +} + +static void +ndis_set_channel(struct ieee80211com *ic) +{ + /* ignore */ +} + +static void +ndis_scan_curchan(struct ieee80211com *ic, unsigned long maxdwell) +{ + /* ignore */ +} + +static void +ndis_scan_mindwell(struct ieee80211com *ic) +{ + /* NB: don't try to abort scan; wait for firmware to finish */ +} + +static void +ndis_scan_end(struct ieee80211com *ic) +{ + /* ignore */ +} + diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h index 13d517c..f4382c6 100644 --- a/sys/dev/if_ndis/if_ndisvar.h +++ b/sys/dev/if_ndis/if_ndisvar.h @@ -174,6 +174,14 @@ struct ndis_softc { int ndis_evtcidx; struct ifqueue ndis_rxqueue; kspin_lock ndis_rxlock; + + struct taskqueue *ndis_tq; /* private task queue */ +#if __FreeBSD_version < 700000 + struct proc *ndis_tqproc; +#endif + struct task ndis_scantask; + int (*ndis_newstate)(struct ieee80211com *, + enum ieee80211_state, int); }; #define NDIS_LOCK(_sc) KeAcquireSpinLock(&(_sc)->ndis_spinlock, \ |