summaryrefslogtreecommitdiffstats
path: root/sys/dev/wi
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2002-06-19 17:37:34 +0000
committerimp <imp@FreeBSD.org>2002-06-19 17:37:34 +0000
commitb07b8a3f99a0a0a3fe76233557247871500315fc (patch)
treebdd3b806658e88da4a5da17908b3496f1aff89fa /sys/dev/wi
parent4586b0f32343e920637042c5f7f5a4a22a86e000 (diff)
downloadFreeBSD-src-b07b8a3f99a0a0a3fe76233557247871500315fc.zip
FreeBSD-src-b07b8a3f99a0a0a3fe76233557247871500315fc.tar.gz
Add better mediaopt support for ibss and friends.
Now the driver is closer to matching the wi man page. Submitted by: jhay (who obtained it from OpenBSD).
Diffstat (limited to 'sys/dev/wi')
-rw-r--r--sys/dev/wi/if_wi.c198
-rw-r--r--sys/dev/wi/if_wireg.h2
-rw-r--r--sys/dev/wi/if_wivar.h10
3 files changed, 171 insertions, 39 deletions
diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c
index e9e52d1..297ec39 100644
--- a/sys/dev/wi/if_wi.c
+++ b/sys/dev/wi/if_wi.c
@@ -313,6 +313,39 @@ wi_generic_attach(device_t dev)
sc->wi_channel = gen.wi_val;
/*
+ * Set flags based on firmware version.
+ */
+ switch (sc->sc_firmware_type) {
+ case WI_LUCENT:
+ sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
+ if (sc->sc_sta_firmware_ver >= 60000)
+ sc->wi_flags |= WI_FLAGS_HAS_MOR;
+ if (sc->sc_sta_firmware_ver >= 60006) {
+ sc->wi_flags |= WI_FLAGS_HAS_IBSS;
+ sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
+ }
+ sc->wi_ibss_port = htole16(1);
+ break;
+ case WI_INTERSIL:
+ sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
+ if (sc->sc_sta_firmware_ver >= 800) {
+ sc->wi_flags |= WI_FLAGS_HAS_IBSS;
+ sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
+ }
+ sc->wi_ibss_port = htole16(0);
+ break;
+ case WI_SYMBOL:
+ sc->wi_flags |= WI_FLAGS_HAS_DIVERSITY;
+ if (sc->sc_sta_firmware_ver >= 20000)
+ sc->wi_flags |= WI_FLAGS_HAS_IBSS;
+ /* Older Symbol firmware does not support IBSS creation. */
+ if (sc->sc_sta_firmware_ver >= 25000)
+ sc->wi_flags |= WI_FLAGS_HAS_CREATE_IBSS;
+ sc->wi_ibss_port = htole16(4);
+ break;
+ }
+
+ /*
* Find out if we support WEP on this card.
*/
gen.wi_type = WI_RID_WEP_AVAIL;
@@ -326,10 +359,13 @@ wi_generic_attach(device_t dev)
/*
* Find supported rates.
*/
- gen.wi_type = WI_RID_TX_RATE;
+ gen.wi_type = WI_RID_DATA_RATES;
gen.wi_len = 2;
- wi_read_record(sc, &gen);
- sc->wi_supprates = gen.wi_val;
+ if (wi_read_record(sc, &gen))
+ sc->wi_supprates = WI_SUPPRATES_1M | WI_SUPPRATES_2M |
+ WI_SUPPRATES_5M | WI_SUPPRATES_11M;
+ else
+ sc->wi_supprates = gen.wi_val;
bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats));
@@ -337,36 +373,76 @@ wi_generic_attach(device_t dev)
wi_stop(sc);
ifmedia_init(&sc->ifmedia, 0, wi_media_change, wi_media_status);
- /* XXX: Should read from card capabilities */
#define ADD(m, c) ifmedia_add(&sc->ifmedia, (m), (c), NULL)
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
- IFM_IEEE80211_ADHOC, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
- IFM_IEEE80211_ADHOC, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
- IFM_IEEE80211_ADHOC, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
- IFM_IEEE80211_ADHOC, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
- IFM_IEEE80211_ADHOC, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
- if (sc->sc_firmware_type == WI_INTERSIL) {
+ if (sc->wi_supprates & WI_SUPPRATES_1M) {
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1, 0, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
- IFM_IEEE80211_HOSTAP, 0), 0);
+ IFM_IEEE80211_ADHOC, 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
+ IFM_IEEE80211_IBSS, 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
+ IFM_IEEE80211_IBSSMASTER, 0), 0);
+ if (sc->sc_firmware_type == WI_INTERSIL)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS1,
+ IFM_IEEE80211_HOSTAP, 0), 0);
+ }
+ if (sc->wi_supprates & WI_SUPPRATES_2M) {
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2, 0, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
- IFM_IEEE80211_HOSTAP, 0), 0);
+ IFM_IEEE80211_ADHOC, 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
+ IFM_IEEE80211_IBSS, 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
+ IFM_IEEE80211_IBSSMASTER, 0), 0);
+ if (sc->sc_firmware_type == WI_INTERSIL)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS2,
+ IFM_IEEE80211_HOSTAP, 0), 0);
+ }
+ if (sc->wi_supprates & WI_SUPPRATES_5M) {
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
- IFM_IEEE80211_HOSTAP, 0), 0);
+ IFM_IEEE80211_ADHOC, 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
+ IFM_IEEE80211_IBSS, 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
+ IFM_IEEE80211_IBSSMASTER, 0), 0);
+ if (sc->sc_firmware_type == WI_INTERSIL)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
+ IFM_IEEE80211_HOSTAP, 0), 0);
+ }
+ if (sc->wi_supprates & WI_SUPPRATES_11M) {
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11, 0, 0), 0);
ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
+ IFM_IEEE80211_ADHOC, 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
+ IFM_IEEE80211_IBSS, 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
+ IFM_IEEE80211_IBSSMASTER, 0), 0);
+ if (sc->sc_firmware_type == WI_INTERSIL)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS11,
+ IFM_IEEE80211_HOSTAP, 0), 0);
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_MANUAL, 0, 0), 0);
+ }
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_ADHOC, 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, IFM_IEEE80211_IBSS,
+ 0), 0);
+ if (sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
+ IFM_IEEE80211_IBSSMASTER, 0), 0);
+ if (sc->sc_firmware_type == WI_INTERSIL)
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
IFM_IEEE80211_HOSTAP, 0), 0);
- ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
- IFM_IEEE80211_HOSTAP, 0), 0);
- }
-#undef ADD
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0), 0);
+#undef ADD
ifmedia_set(&sc->ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
0, 0));
@@ -1065,7 +1141,15 @@ wi_read_record(sc, ltv)
for (i = 0; i < ltv->wi_len - 1; i++)
ptr[i] = CSR_READ_2(sc, WI_DATA1);
- if (sc->sc_firmware_type != WI_LUCENT) {
+ if (ltv->wi_type == WI_RID_PORTTYPE && sc->wi_ptype == WI_PORTTYPE_IBSS
+ && ltv->wi_val == sc->wi_ibss_port) {
+ /*
+ * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
+ * Since Lucent uses port type 1 for BSS *and* IBSS we
+ * have to rely on wi_ptype to distinguish this for us.
+ */
+ ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
+ } else if (sc->sc_firmware_type != WI_LUCENT) {
switch (oltv->wi_type) {
case WI_RID_TX_RATE:
case WI_RID_CUR_TX_RATE:
@@ -1116,7 +1200,14 @@ wi_write_record(sc, ltv)
int i;
struct wi_ltv_gen p2ltv;
- if (sc->sc_firmware_type != WI_LUCENT) {
+ if (ltv->wi_type == WI_RID_PORTTYPE &&
+ le16toh(ltv->wi_val) == WI_PORTTYPE_IBSS) {
+ /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
+ p2ltv.wi_type = WI_RID_PORTTYPE;
+ p2ltv.wi_len = 2;
+ p2ltv.wi_val = sc->wi_ibss_port;
+ ltv = &p2ltv;
+ } else if (sc->sc_firmware_type != WI_LUCENT) {
switch (ltv->wi_type) {
case WI_RID_TX_RATE:
p2ltv.wi_type = WI_RID_TX_RATE;
@@ -1935,12 +2026,12 @@ wi_init(xsc)
/* Program max data length. */
WI_SETVAL(WI_RID_MAX_DATALEN, sc->wi_max_data_len);
- /* Enable/disable IBSS creation. */
- WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
-
/* Set the port type. */
WI_SETVAL(WI_RID_PORTTYPE, sc->wi_ptype);
+ /* Enable/disable IBSS creation. */
+ WI_SETVAL(WI_RID_CREATE_IBSS, sc->wi_create_ibss);
+
/* Program the RTS/CTS threshold. */
WI_SETVAL(WI_RID_RTS_THRESH, sc->wi_rts_thresh);
@@ -2725,13 +2816,37 @@ wi_media_change(ifp)
struct wi_softc *sc = ifp->if_softc;
int otype = sc->wi_ptype;
int orate = sc->wi_tx_rate;
+ int ocreate_ibss = sc->wi_create_ibss;
+
+ if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP) &&
+ sc->sc_firmware_type != WI_INTERSIL)
+ return (EINVAL);
- if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
+ sc->wi_create_ibss = 0;
+
+ switch (sc->ifmedia.ifm_cur->ifm_media & IFM_OMASK) {
+ case 0:
+ sc->wi_ptype = WI_PORTTYPE_BSS;
+ break;
+ case IFM_IEEE80211_ADHOC:
sc->wi_ptype = WI_PORTTYPE_ADHOC;
- else if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_HOSTAP) != 0)
+ break;
+ case IFM_IEEE80211_HOSTAP:
sc->wi_ptype = WI_PORTTYPE_AP;
- else
- sc->wi_ptype = WI_PORTTYPE_BSS;
+ break;
+ case IFM_IEEE80211_IBSSMASTER:
+ case IFM_IEEE80211_IBSSMASTER|IFM_IEEE80211_IBSS:
+ if (!(sc->wi_flags & WI_FLAGS_HAS_CREATE_IBSS))
+ return (EINVAL);
+ sc->wi_create_ibss = 1;
+ /* FALLTHROUGH */
+ case IFM_IEEE80211_IBSS:
+ sc->wi_ptype = WI_PORTTYPE_IBSS;
+ break;
+ default:
+ /* Invalid combination. */
+ return (EINVAL);
+ }
switch (IFM_SUBTYPE(sc->ifmedia.ifm_cur->ifm_media)) {
case IFM_IEEE80211_DS1:
@@ -2751,7 +2866,7 @@ wi_media_change(ifp)
break;
}
- if (otype != sc->wi_ptype ||
+ if (ocreate_ibss != sc->wi_create_ibss || otype != sc->wi_ptype ||
orate != sc->wi_tx_rate)
wi_init(sc);
@@ -2772,6 +2887,12 @@ wi_media_status(ifp, imr)
imr->ifm_active |= IFM_IEEE80211_ADHOC;
else if (sc->wi_ptype == WI_PORTTYPE_AP)
imr->ifm_active |= IFM_IEEE80211_HOSTAP;
+ else if (sc->wi_ptype == WI_PORTTYPE_IBSS) {
+ if (sc->wi_create_ibss)
+ imr->ifm_active |= IFM_IEEE80211_IBSSMASTER;
+ else
+ imr->ifm_active |= IFM_IEEE80211_IBSS;
+ }
wreq.wi_type = WI_RID_CUR_TX_RATE;
wreq.wi_len = WI_MAX_DATALEN;
if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0) {
@@ -2795,7 +2916,8 @@ wi_media_status(ifp, imr)
}
imr->ifm_status = IFM_AVALID;
- if (sc->wi_ptype == WI_PORTTYPE_ADHOC)
+ if (sc->wi_ptype == WI_PORTTYPE_ADHOC ||
+ sc->wi_ptype == WI_PORTTYPE_IBSS)
/*
* XXX: It would be nice if we could give some actually
* useful status like whether we joined another IBSS or
diff --git a/sys/dev/wi/if_wireg.h b/sys/dev/wi/if_wireg.h
index 7a02987..1310f39 100644
--- a/sys/dev/wi/if_wireg.h
+++ b/sys/dev/wi/if_wireg.h
@@ -497,10 +497,10 @@ struct wi_ltv_pcf {
* (Only PRISM2; not 802.11 compliant mode, testing use only)
* 6 == HOST AP (Only PRISM2)
*/
-#define WI_PORTTYPE_IBSS 0x0
#define WI_PORTTYPE_BSS 0x1
#define WI_PORTTYPE_WDS 0x2
#define WI_PORTTYPE_ADHOC 0x3
+#define WI_PORTTYPE_IBSS 0x4
#define WI_PORTTYPE_AP 0x6
/*
diff --git a/sys/dev/wi/if_wivar.h b/sys/dev/wi/if_wivar.h
index 470ba6d..beba7ef 100644
--- a/sys/dev/wi/if_wivar.h
+++ b/sys/dev/wi/if_wivar.h
@@ -123,6 +123,15 @@ struct wi_softc {
int wi_tx_data_id;
int wi_tx_mgmt_id;
int wi_gone;
+ int wi_flags;
+#define WI_FLAGS_ATTACHED 0x01
+#define WI_FLAGS_INITIALIZED 0x02
+#define WI_FLAGS_HAS_WEP 0x04
+#define WI_FLAGS_HAS_IBSS 0x08
+#define WI_FLAGS_HAS_CREATE_IBSS 0x10
+#define WI_FLAGS_HAS_MOR 0x20
+#define WI_FLAGS_HAS_ROAMING 0x30
+#define WI_FLAGS_HAS_DIVERSITY 0x40
int wi_if_flags;
u_int16_t wi_procframe;
u_int16_t wi_ptype;
@@ -159,6 +168,7 @@ struct wi_softc {
struct wihap_info wi_hostap_info;
u_int32_t wi_icv;
int wi_icv_flag;
+ int wi_ibss_port;
struct callout_handle wi_stat_ch;
#if __FreeBSD_version >= 500000
struct mtx wi_mtx;
OpenPOWER on IntegriCloud