diff options
author | imp <imp@FreeBSD.org> | 2002-06-19 17:37:34 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2002-06-19 17:37:34 +0000 |
commit | b07b8a3f99a0a0a3fe76233557247871500315fc (patch) | |
tree | bdd3b806658e88da4a5da17908b3496f1aff89fa /sys/dev/wi | |
parent | 4586b0f32343e920637042c5f7f5a4a22a86e000 (diff) | |
download | FreeBSD-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.c | 198 | ||||
-rw-r--r-- | sys/dev/wi/if_wireg.h | 2 | ||||
-rw-r--r-- | sys/dev/wi/if_wivar.h | 10 |
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; |