diff options
author | wpaul <wpaul@FreeBSD.org> | 2005-02-11 02:13:12 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2005-02-11 02:13:12 +0000 |
commit | 0740f7d7b6e3543f64845dc816668d8b6f8ee1cf (patch) | |
tree | 5ab7fc9f2fe4430b0c00535c034e80638f0030db /sys/dev/if_ndis | |
parent | e8769beaa31e600cc8023e8b902921d31cdb89c6 (diff) | |
download | FreeBSD-src-0740f7d7b6e3543f64845dc816668d8b6f8ee1cf.zip FreeBSD-src-0740f7d7b6e3543f64845dc816668d8b6f8ee1cf.tar.gz |
Merge in patch to support AP scanning via ifconfig and the new
net80211 API.
Submitted by: Stephane E. Potvin sepotvin at videotron dot ca
Diffstat (limited to 'sys/dev/if_ndis')
-rw-r--r-- | sys/dev/if_ndis/if_ndis.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index aed5e4b..9f94daf 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -110,6 +110,8 @@ static void ndis_starttask (void *); static int ndis_ioctl (struct ifnet *, u_long, caddr_t); static int ndis_wi_ioctl_get (struct ifnet *, u_long, caddr_t); static int ndis_wi_ioctl_set (struct ifnet *, u_long, caddr_t); +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 void ndis_init (void *); static void ndis_stop (struct ndis_softc *); static void ndis_watchdog (struct ifnet *); @@ -2035,6 +2037,18 @@ ndis_ioctl(ifp, command, data) ifp->if_hwassist = 0; ndis_set_offload(sc); break; + case SIOCG80211: + if (sc->ndis_80211) + error = ndis_80211_ioctl_get(ifp, command, data); + else + error = ENOTTY; + break; + case SIOCS80211: + if (sc->ndis_80211) + error = ndis_80211_ioctl_set(ifp, command, data); + else + error = ENOTTY; + break; case SIOCGIFGENERIC: case SIOCSIFGENERIC: if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) { @@ -2183,6 +2197,119 @@ ndis_wi_ioctl_set(ifp, command, data) return (error); } +static int +ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct ndis_softc *sc; + struct ieee80211req *ireq; + ndis_80211_bssid_list_ex *bl; + ndis_wlan_bssid_ex *wb; + struct ieee80211req_scan_result *sr, *bsr; + int error, len, i, j; + char *cp; + + sc = ifp->if_softc; + ireq = (struct ieee80211req *) data; + + switch (ireq->i_type) { + case IEEE80211_IOC_SCAN_RESULTS: + len = 0; + error = ndis_get_info(sc, OID_802_11_BSSID_LIST, NULL, &len); + if (error != ENOSPC) + break; + bl = malloc(len, M_DEVBUF, M_WAITOK | 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_WAITOK | M_ZERO); + wb = bl->nblx_bssid; + len = 0; + for (i = 0; i < bl->nblx_items; i++) { + /* + * Check if we have enough space left for this ap + */ + j = roundup(sizeof(*sr) + wb->nwbx_ssid.ns_ssidlen + + wb->nwbx_ielen - 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; + 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); + 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; + default: + error = ieee80211_ioctl(&sc->ic, command, data); + } + + return(error); +} + +static int +ndis_80211_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct ndis_softc *sc; + struct ieee80211req *ireq; + int error, len; + + sc = ifp->if_softc; + ireq = (struct ieee80211req *) data; + + switch (ireq->i_type) { + 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; + default: + error = ieee80211_ioctl(&sc->ic, command, data); + if (error == ENETRESET) { + ndis_setstate_80211(sc); + error = 0; + } + } + + return(error); +} + static void ndis_watchdog(ifp) struct ifnet *ifp; |