aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPoul-Henning Kamp <phk@FreeBSD.org>2001-05-26 09:27:08 +0000
committerPoul-Henning Kamp <phk@FreeBSD.org>2001-05-26 09:27:08 +0000
commit419d8080a45c9baf85e2254f2f6f30edb11fb0bd (patch)
treeda27a0f86ea098d14264679df4a59a965ce9f57c /sys
parent3344c5a17e9322ec55ad4e3026e2a1e547b89938 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/an/if_aironet_ieee.h2
-rw-r--r--sys/dev/an/if_an.c500
-rw-r--r--sys/dev/an/if_an_isa.c2
-rw-r--r--sys/dev/an/if_an_pccard.c2
-rw-r--r--sys/dev/an/if_an_pci.c2
-rw-r--r--sys/dev/an/if_anreg.h5
-rw-r--r--sys/dev/awi/awi.c181
-rw-r--r--sys/dev/wi/if_wavelan_ieee.h4
-rw-r--r--sys/dev/wi/if_wi.c376
-rw-r--r--sys/net/if_ieee80211.h39
-rw-r--r--sys/net/if_media.c10
-rw-r--r--sys/net/if_media.h54
12 files changed, 1168 insertions, 9 deletions
diff --git a/sys/dev/an/if_aironet_ieee.h b/sys/dev/an/if_aironet_ieee.h
index bcbd32f05e83..a1eeb2683991 100644
--- a/sys/dev/an/if_aironet_ieee.h
+++ b/sys/dev/an/if_aironet_ieee.h
@@ -336,6 +336,7 @@ struct an_ltv_genconfig {
u_int8_t an_magic_packet_ctl; /* 0x99 */
u_int16_t an_rsvd9;
};
+#endif
#define AN_OPMODE_IBSS_ADHOC 0x0000
#define AN_OPMODE_INFRASTRUCTURE_STATION 0x0001
@@ -395,6 +396,7 @@ struct an_ltv_genconfig {
#define AN_HOME_NETWORK 0x0001
#define AN_HOME_INSTALL_AP 0x0002
+#ifndef _KERNEL
struct an_ltv_ssidlist {
u_int16_t an_len;
u_int16_t an_type;
diff --git a/sys/dev/an/if_an.c b/sys/dev/an/if_an.c
index 2b382842bebf..c7843e6b99ab 100644
--- a/sys/dev/an/if_an.c
+++ b/sys/dev/an/if_an.c
@@ -113,6 +113,8 @@
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_types.h>
+#include <net/if_ieee80211.h>
+#include <net/if_media.h>
#ifdef INET
#include <netinet/in.h>
@@ -160,6 +162,9 @@ static void an_cache_store __P((struct an_softc *, struct ether_header *,
struct mbuf *, unsigned short));
#endif
+static int an_media_change __P((struct ifnet *));
+static void an_media_status __P((struct ifnet *, struct ifmediareq *));
+
/*
* We probe for an Aironet 4500/4800 card by attempting to
* read the default SSID list. On reset, the first entry in
@@ -380,6 +385,31 @@ int an_attach(sc, unit, flags)
sc->an_tx_rate = 0;
bzero((char *)&sc->an_stats, sizeof(sc->an_stats));
+ ifmedia_init(&sc->an_ifmedia, 0, an_media_change, an_media_status);
+#define ADD(m, c) ifmedia_add(&sc->an_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);
+ if(sc->an_caps.an_rates[2] == AN_RATE_5_5MBPS) {
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5,
+ IFM_IEEE80211_ADHOC, 0), 0);
+ ADD(IFM_MAKEWORD(IFM_IEEE80211, IFM_IEEE80211_DS5, 0, 0), 0);
+ }
+ if(sc->an_caps.an_rates[3] == AN_RATE_11MBPS) {
+ 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);
+#undef ADD
+ ifmedia_set(&sc->an_ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
+ 0, 0));
+
/*
* Call MI attach routine.
*/
@@ -713,10 +743,10 @@ static int an_read_record(sc, ltv)
* room to hold all of the returned data).
*/
len = CSR_READ_2(sc, AN_DATA1);
- if (len > ltv->an_len) {
+ if (len > (ltv->an_len - 2)) {
printf("an%d: record length mismatch -- expected %d, "
- "got %d\n", sc->an_unit, ltv->an_len, len);
- return(ENOSPC);
+ "got %d\n", sc->an_unit, (ltv->an_len - 2), len);
+ len = (ltv->an_len - 2);
}
ltv->an_len = len;
@@ -981,14 +1011,29 @@ static int an_ioctl(ifp, command, data)
caddr_t data;
{
int error = 0;
+ int len;
+ int i;
struct an_softc *sc;
struct an_req areq;
struct ifreq *ifr;
struct proc *p = curproc;
+ struct ieee80211req *ireq;
+ u_int8_t tmpstr[IEEE80211_NWID_LEN*2];
+ u_int8_t *tmpptr;
+ struct an_ltv_genconfig *config;
+ struct an_ltv_key *key;
+ struct an_ltv_status *status;
+ struct an_ltv_ssidlist *ssids;
sc = ifp->if_softc;
AN_LOCK(sc);
ifr = (struct ifreq *)data;
+ ireq = (struct ieee80211req *)data;
+
+ config = (struct an_ltv_genconfig *)&areq;
+ key = (struct an_ltv_key *)&areq;
+ status = (struct an_ltv_status *)&areq;
+ ssids = (struct an_ltv_ssidlist *)&areq;
if (sc->an_gone) {
error = ENODEV;
@@ -1020,6 +1065,10 @@ static int an_ioctl(ifp, command, data)
sc->an_if_flags = ifp->if_flags;
error = 0;
break;
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
+ break;
case SIOCADDMULTI:
case SIOCDELMULTI:
/* The Aironet has no multicast filter. */
@@ -1059,6 +1108,369 @@ static int an_ioctl(ifp, command, data)
break;
an_setdef(sc, &areq);
break;
+ case SIOCG80211:
+ areq.an_len = sizeof(areq);
+ switch(ireq->i_type) {
+ case IEEE80211_IOC_SSID:
+ if(ireq->i_val == -1) {
+ areq.an_type = AN_RID_STATUS;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ len = status->an_ssidlen;
+ tmpptr = status->an_ssid;
+ } else if(ireq->i_val >= 0) {
+ areq.an_type = AN_RID_SSIDLIST;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ if(ireq->i_val == 0) {
+ len = ssids->an_ssid1_len;
+ tmpptr = ssids->an_ssid1;
+ } else if(ireq->i_val == 1) {
+ len = ssids->an_ssid2_len;
+ tmpptr = ssids->an_ssid3;
+ } else if(ireq->i_val == 1) {
+ len = ssids->an_ssid3_len;
+ tmpptr = ssids->an_ssid3;
+ } else {
+ error = EINVAL;
+ break;
+ }
+ } else {
+ error = EINVAL;
+ break;
+ }
+ if(len > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ ireq->i_len = len;
+ bzero(tmpstr, IEEE80211_NWID_LEN);
+ bcopy(tmpptr, tmpstr, len);
+ error = copyout(tmpstr, ireq->i_data,
+ IEEE80211_NWID_LEN);
+ break;
+ case IEEE80211_IOC_NUMSSIDS:
+ ireq->i_val = 3;
+ break;
+ case IEEE80211_IOC_WEP:
+ areq.an_type = AN_RID_ACTUALCFG;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ if(config->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) {
+ if(config->an_authtype &
+ AN_AUTHTYPE_ALLOW_UNENCRYPTED)
+ ireq->i_val = IEEE80211_WEP_MIXED;
+ else
+ ireq->i_val = IEEE80211_WEP_ON;
+
+ } else {
+ ireq->i_val = IEEE80211_WEP_OFF;
+ }
+ break;
+ case IEEE80211_IOC_WEPKEY:
+ /*
+ * XXX: I'm not entierly convinced this is
+ * correct, but it's what is implemented in
+ * ancontrol so it will have to do until we get
+ * access to actual Cisco code.
+ */
+ if(ireq->i_val < 0 || ireq->i_val > 7) {
+ error = EINVAL;
+ break;
+ }
+ len = 0;
+ if(ireq->i_val < 4) {
+ areq.an_type = AN_RID_WEP_TEMP;
+ for(i=0; i<4; i++) {
+ areq.an_len = sizeof(areq);
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ len = key->klen;
+ if(i == ireq->i_val)
+ break;
+ /* Required to get next entry */
+ areq.an_type = AN_RID_WEP_PERM;
+ }
+ if(error)
+ break;
+ }
+ /* We aren't allowed to read the value of the
+ * key from the card so we just output zeros
+ * like we would if we could read the card, but
+ * denied the user access.
+ */
+ bzero(tmpstr, len);
+ ireq->i_len = len;
+ error = copyout(tmpstr, ireq->i_data, len);
+ break;
+ case IEEE80211_IOC_NUMWEPKEYS:
+ ireq->i_val = 8;
+ break;
+ case IEEE80211_IOC_WEPTXKEY:
+ areq.an_type = AN_RID_WEP_PERM;
+ key->kindex = 0xffff;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ ireq->i_val = key->mac[0];
+ break;
+ case IEEE80211_IOC_AUTHMODE:
+ areq.an_type = AN_RID_ACTUALCFG;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
+ AN_AUTHTYPE_NONE) {
+ ireq->i_val = IEEE80211_AUTH_NONE;
+ } else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
+ AN_AUTHTYPE_OPEN) {
+ ireq->i_val = IEEE80211_AUTH_OPEN;
+ } else if ((config->an_authtype & AN_AUTHTYPE_MASK) ==
+ AN_AUTHTYPE_SHAREDKEY) {
+ ireq->i_val = IEEE80211_AUTH_SHARED;
+ } else
+ error = EINVAL;
+ break;
+ case IEEE80211_IOC_STATIONNAME:
+ areq.an_type = AN_RID_ACTUALCFG;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ ireq->i_len = sizeof(config->an_nodename);
+ tmpptr = config->an_nodename;
+ bzero(tmpstr, IEEE80211_NWID_LEN);
+ bcopy(tmpptr, tmpstr, ireq->i_len);
+ error = copyout(tmpstr, ireq->i_data,
+ IEEE80211_NWID_LEN);
+ break;
+ case IEEE80211_IOC_CHANNEL:
+ areq.an_type = AN_RID_STATUS;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ ireq->i_val = status->an_cur_channel;
+ break;
+ case IEEE80211_IOC_POWERSAVE:
+ areq.an_type = AN_RID_ACTUALCFG;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ if(config->an_psave_mode == AN_PSAVE_NONE) {
+ ireq->i_val = IEEE80211_POWERSAVE_OFF;
+ } else if(config->an_psave_mode == AN_PSAVE_CAM) {
+ ireq->i_val = IEEE80211_POWERSAVE_CAM;
+ } else if(config->an_psave_mode == AN_PSAVE_PSP) {
+ ireq->i_val = IEEE80211_POWERSAVE_PSP;
+ } else if(config->an_psave_mode == AN_PSAVE_PSP_CAM) {
+ ireq->i_val = IEEE80211_POWERSAVE_PSP_CAM;
+ } else
+ error = EINVAL;
+ break;
+ case IEEE80211_IOC_POWERSAVESLEEP:
+ areq.an_type = AN_RID_ACTUALCFG;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ ireq->i_val = config->an_listen_interval;
+ break;
+ }
+ break;
+ case SIOCS80211:
+ if ((error = suser(p)))
+ goto out;
+ areq.an_len = sizeof(areq);
+ /*
+ * We need a config structure for everything but the WEP
+ * key management and SSIDs so we get it now so avoid
+ * duplicating this code every time.
+ */
+ if (ireq->i_type != IEEE80211_IOC_SSID &&
+ ireq->i_type != IEEE80211_IOC_WEPKEY &&
+ ireq->i_type != IEEE80211_IOC_WEPTXKEY) {
+ areq.an_type = AN_RID_GENCONFIG;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ }
+ switch(ireq->i_type) {
+ case IEEE80211_IOC_SSID:
+ areq.an_type = AN_RID_SSIDLIST;
+ if (an_read_record(sc,
+ (struct an_ltv_gen *)&areq)) {
+ error = EINVAL;
+ break;
+ }
+ if(ireq->i_len > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ switch (ireq->i_val) {
+ case 0:
+ error = copyin(ireq->i_data,
+ ssids->an_ssid1, ireq->i_len);
+ ssids->an_ssid1_len = ireq->i_len;
+ break;
+ case 1:
+ error = copyin(ireq->i_data,
+ ssids->an_ssid2, ireq->i_len);
+ ssids->an_ssid2_len = ireq->i_len;
+ break;
+ case 2:
+ error = copyin(ireq->i_data,
+ ssids->an_ssid3, ireq->i_len);
+ ssids->an_ssid3_len = ireq->i_len;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_WEP:
+ switch (ireq->i_val) {
+ case IEEE80211_WEP_OFF:
+ config->an_authtype &=
+ ~(AN_AUTHTYPE_PRIVACY_IN_USE |
+ AN_AUTHTYPE_ALLOW_UNENCRYPTED);
+ break;
+ case IEEE80211_WEP_ON:
+ config->an_authtype |=
+ AN_AUTHTYPE_PRIVACY_IN_USE;
+ config->an_authtype &=
+ ~AN_AUTHTYPE_ALLOW_UNENCRYPTED;
+ break;
+ case IEEE80211_WEP_MIXED:
+ config->an_authtype |=
+ AN_AUTHTYPE_PRIVACY_IN_USE |
+ AN_AUTHTYPE_ALLOW_UNENCRYPTED;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_WEPKEY:
+ if (ireq->i_val < 0 || ireq->i_val > 7 ||
+ ireq->i_len > 13) {
+ error = EINVAL;
+ break;
+ }
+ error = copyin(ireq->i_data, tmpstr, 13);
+ if(error)
+ break;
+ bzero(&areq, sizeof(struct an_ltv_key));
+ areq.an_len = sizeof(struct an_ltv_key);
+ key->mac[0] = 1; /* The others are 0. */
+ key->kindex = ireq->i_val % 4;
+ if(ireq->i_val < 4)
+ areq.an_type = AN_RID_WEP_TEMP;
+ else
+ areq.an_type = AN_RID_WEP_PERM;
+ key->klen = ireq->i_len;
+ bcopy(tmpstr, key->key, key->klen);
+ break;
+ case IEEE80211_IOC_WEPTXKEY:
+ if(ireq->i_val < 0 || ireq->i_val > 3) {
+ error = EINVAL;
+ break;
+ }
+ bzero(&areq, sizeof(struct an_ltv_key));
+ areq.an_len = sizeof(struct an_ltv_key);
+ areq.an_type = AN_RID_WEP_PERM;
+ key->kindex = 0xffff;
+ key->mac[0] = ireq->i_val;
+ break;
+ case IEEE80211_IOC_AUTHMODE:
+ switch (ireq->i_val) {
+ case IEEE80211_AUTH_NONE:
+ config->an_authtype = AN_AUTHTYPE_NONE |
+ (config->an_authtype & ~AN_AUTHTYPE_MASK);
+ break;
+ case IEEE80211_AUTH_OPEN:
+ config->an_authtype = AN_AUTHTYPE_OPEN |
+ (config->an_authtype & ~AN_AUTHTYPE_MASK);
+ break;
+ case IEEE80211_AUTH_SHARED:
+ config->an_authtype = AN_AUTHTYPE_SHAREDKEY |
+ (config->an_authtype & ~AN_AUTHTYPE_MASK);
+ break;
+ default:
+ error = EINVAL;
+ }
+ break;
+ case IEEE80211_IOC_STATIONNAME:
+ if(ireq->i_len > 16) {
+ error = EINVAL;
+ break;
+ }
+ bzero(config->an_nodename, 16);
+ error = copyin(ireq->i_data,
+ config->an_nodename, ireq->i_len);
+ break;
+ case IEEE80211_IOC_CHANNEL:
+ /*
+ * The actual range is 1-14, but if you set it
+ * to 0 you get the default so we let that work
+ * too.
+ */
+ if (ireq->i_val < 0 || ireq->i_val >14) {
+ error = EINVAL;
+ break;
+ }
+ config->an_ds_channel = ireq->i_val;
+ break;
+ case IEEE80211_IOC_POWERSAVE:
+ switch (ireq->i_val) {
+ case IEEE80211_POWERSAVE_OFF:
+ config->an_psave_mode = AN_PSAVE_NONE;
+ break;
+ case IEEE80211_POWERSAVE_CAM:
+ config->an_psave_mode = AN_PSAVE_CAM;
+ break;
+ case IEEE80211_POWERSAVE_PSP:
+ config->an_psave_mode = AN_PSAVE_PSP;
+ break;
+ case IEEE80211_POWERSAVE_PSP_CAM:
+ config->an_psave_mode = AN_PSAVE_PSP_CAM;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_POWERSAVESLEEP:
+ config->an_listen_interval = ireq->i_val;
+ break;
+ }
+
+ if (!error)
+ an_setdef(sc, &areq);
+ break;
default:
error = EINVAL;
break;
@@ -1416,6 +1828,7 @@ void an_cache_store (sc, eh, m, rx_quality)
static int cache_slot = 0; /* use this cache entry */
static int wrapindex = 0; /* next "free" cache entry */
int saanp=0;
+ int sig, noise;
/* filters:
* 1. ip only
@@ -1523,3 +1936,84 @@ void an_cache_store (sc, eh, m, rx_quality)
return;
}
#endif
+
+static int an_media_change(ifp)
+ struct ifnet *ifp;
+{
+ struct an_softc *sc = ifp->if_softc;
+ int otype = sc->an_config.an_opmode;
+ int orate = sc->an_tx_rate;
+
+ if ((sc->an_ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
+ sc->an_config.an_opmode = AN_OPMODE_IBSS_ADHOC;
+ else
+ sc->an_config.an_opmode = AN_OPMODE_INFRASTRUCTURE_STATION;
+
+ switch (IFM_SUBTYPE(sc->an_ifmedia.ifm_cur->ifm_media)) {
+ case IFM_IEEE80211_DS1:
+ sc->an_tx_rate = AN_RATE_1MBPS;
+ break;
+ case IFM_IEEE80211_DS2:
+ sc->an_tx_rate = AN_RATE_2MBPS;
+ break;
+ case IFM_IEEE80211_DS5:
+ sc->an_tx_rate = AN_RATE_5_5MBPS;
+ break;
+ case IFM_IEEE80211_DS11:
+ sc->an_tx_rate = AN_RATE_11MBPS;
+ break;
+ case IFM_AUTO:
+ sc->an_tx_rate = 0;
+ break;
+ }
+
+ if (otype != sc->an_config.an_opmode ||
+ orate != sc->an_tx_rate)
+ an_init(sc);
+
+ return(0);
+}
+
+static void an_media_status(ifp, imr)
+ struct ifnet *ifp;
+ struct ifmediareq *imr;
+{
+ struct an_ltv_status status;
+ struct an_softc *sc = ifp->if_softc;
+
+ status.an_len = sizeof(status);
+ status.an_type = AN_RID_STATUS;
+ if (an_read_record(sc, (struct an_ltv_gen *)&status)) {
+ /* If the status read fails, just lie. */
+ imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
+ imr->ifm_status = IFM_AVALID|IFM_ACTIVE;
+ }
+
+ if(sc->an_tx_rate == 0) {
+ imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
+ if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC)
+ imr->ifm_active |= IFM_IEEE80211_ADHOC;
+ switch(status.an_current_tx_rate) {
+ case AN_RATE_1MBPS:
+ imr->ifm_active |= IFM_IEEE80211_DS1;
+ break;
+ case AN_RATE_2MBPS:
+ imr->ifm_active |= IFM_IEEE80211_DS2;
+ break;
+ case AN_RATE_5_5MBPS:
+ imr->ifm_active |= IFM_IEEE80211_DS5;
+ break;
+ case AN_RATE_11MBPS:
+ imr->ifm_active |= IFM_IEEE80211_DS11;
+ break;
+ }
+ } else {
+ imr->ifm_active = sc->an_ifmedia.ifm_cur->ifm_media;
+ }
+
+ imr->ifm_status = IFM_AVALID;
+ if (sc->an_config.an_opmode == AN_OPMODE_IBSS_ADHOC)
+ imr->ifm_status |= IFM_ACTIVE;
+ else if (status.an_opmode & AN_STATUS_OPMODE_ASSOCIATED)
+ imr->ifm_status |= IFM_ACTIVE;
+}
diff --git a/sys/dev/an/if_an_isa.c b/sys/dev/an/if_an_isa.c
index 29e6c2869580..8ece54de82dc 100644
--- a/sys/dev/an/if_an_isa.c
+++ b/sys/dev/an/if_an_isa.c
@@ -63,6 +63,7 @@
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_types.h>
+#include <net/if_media.h>
#include <isa/isavar.h>
#include <isa/pnpvar.h>
@@ -137,6 +138,7 @@ an_detach_isa(device_t dev)
struct ifnet *ifp = &sc->arpcom.ac_if;
an_stop(sc);
+ ifmedia_removeall(&sc->an_ifmedia);
ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
an_release_resources(dev);
diff --git a/sys/dev/an/if_an_pccard.c b/sys/dev/an/if_an_pccard.c
index ebb78036271a..dc91b0fa5095 100644
--- a/sys/dev/an/if_an_pccard.c
+++ b/sys/dev/an/if_an_pccard.c
@@ -64,6 +64,7 @@
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_types.h>
+#include <net/if_media.h>
#ifndef lint
static const char rcsid[] =
@@ -111,6 +112,7 @@ an_pccard_detach(device_t dev)
return(0);
}
an_stop(sc);
+ ifmedia_removeall(&sc->an_ifmedia);
ifp->if_flags &= ~IFF_RUNNING;
ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
sc->an_gone = 1;
diff --git a/sys/dev/an/if_an_pci.c b/sys/dev/an/if_an_pci.c
index bde0f3df9c5b..47099e82aeeb 100644
--- a/sys/dev/an/if_an_pci.c
+++ b/sys/dev/an/if_an_pci.c
@@ -76,6 +76,7 @@
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
+#include <net/if_media.h>
#include <pci/pcireg.h>
#include <pci/pcivar.h>
@@ -195,6 +196,7 @@ an_detach_pci(device_t dev)
struct ifnet *ifp = &sc->arpcom.ac_if;
an_stop(sc);
+ ifmedia_removeall(&sc->an_ifmedia);
ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
an_release_resources(dev);
diff --git a/sys/dev/an/if_anreg.h b/sys/dev/an/if_anreg.h
index 844d4807a3ee..e86e354b74dd 100644
--- a/sys/dev/an/if_anreg.h
+++ b/sys/dev/an/if_anreg.h
@@ -34,8 +34,8 @@
#define AN_TIMEOUT 65536
-/* Default network name: ANY */
-#define AN_DEFAULT_NETNAME "ANY"
+/* Default network name: <empty string> */
+#define AN_DEFAULT_NETNAME ""
/* The nodename must be less than 16 bytes */
#define AN_DEFAULT_NODENAME "FreeBSD"
@@ -846,6 +846,7 @@ struct an_softc {
struct callout_handle an_stat_ch;
struct mtx an_mtx;
device_t an_dev;
+ struct ifmedia an_ifmedia;
};
#define AN_LOCK(_sc) mtx_lock(&(_sc)->an_mtx)
diff --git a/sys/dev/awi/awi.c b/sys/dev/awi/awi.c
index 4dab87bbcc6d..fdfa82260182 100644
--- a/sys/dev/awi/awi.c
+++ b/sys/dev/awi/awi.c
@@ -455,9 +455,12 @@ awi_ioctl(ifp, cmd, data)
struct awi_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ieee80211req *ireq = (struct ieee80211req *)data;
int s, error;
struct ieee80211_nwid nwid;
u_int8_t *p;
+ int len;
+ u_int8_t tmpstr[IEEE80211_NWID_LEN*2];
s = splnet();
@@ -566,6 +569,184 @@ awi_ioctl(ifp, cmd, data)
error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
break;
#endif
+#ifdef __FreeBSD__
+ case SIOCG80211:
+ switch(ireq->i_type) {
+ case IEEE80211_IOC_SSID:
+ bzero(tmpstr, IEEE80211_NWID_LEN);
+ if(ireq->i_val == -1 && ifp->if_flags & IFF_RUNNING) {
+ if (sc->sc_mib_local.Network_Mode) {
+ p = sc->sc_bss.essid;
+ len = p[1];
+ p += 2;
+ } else {
+ len = ETHER_ADDR_LEN;
+ p = sc->sc_bss.bssid;
+ }
+ } else if(ireq->i_val == 0) {
+ if (sc->sc_mib_local.Network_Mode)
+ p = sc->sc_mib_mac.aDesired_ESS_ID;
+ else
+ p = sc->sc_ownssid;
+ len = p[1];
+ p += 2;
+ } else {
+ error = EINVAL;
+ break;
+ }
+ if(len > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ bcopy(p, tmpstr, len);
+ error = copyout(tmpstr, ireq->i_data,
+ IEEE80211_NWID_LEN);
+ break;
+ case IEEE80211_IOC_NUMSSIDS:
+ ireq->i_val = 1;
+ break;
+ case IEEE80211_IOC_WEP:
+ /* XXX: I'm not sure this is entierly correct */
+ ireq->i_val = awi_wep_getalgo(sc);
+ if(ireq->i_val != IEEE80211_WEP_OFF)
+ ireq->i_val = IEEE80211_WEP_ON;
+ break;
+ case IEEE80211_IOC_WEPKEY:
+ if(ireq->i_val < 0 || ireq->i_val > 3) {
+ error = EINVAL;
+ break;
+ }
+ len = sizeof(tmpstr);
+ error = awi_wep_getkey(sc, ireq->i_val, tmpstr, &len);
+ if(error)
+ break;
+ if(!suser(curproc))
+ bzero(tmpstr, len);
+ ireq->i_val = len;
+ error = copyout(tmpstr, ireq->i_data, len);
+ break;
+ case IEEE80211_IOC_NUMWEPKEYS:
+ ireq->i_val = 4;
+ break;
+ case IEEE80211_IOC_WEPTXKEY:
+ ireq->i_val = sc->sc_wep_defkid;
+ break;
+ case IEEE80211_IOC_AUTHMODE:
+ /* XXX: Is this correct? */
+ ireq->i_val = IEEE80211_AUTH_OPEN;
+ break;
+ case IEEE80211_IOC_STATIONNAME:
+ bzero(tmpstr, IEEE80211_NWID_LEN);
+ p = hostname;
+ len = strlen(hostname);
+ if(len > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ bcopy(p, tmpstr, len);
+ error = copyout(tmpstr, ireq->i_data,
+ IEEE80211_NWID_LEN);
+ break;
+ case IEEE80211_IOC_CHANNEL:
+ /* XXX: Handle FH cards */
+ ireq->i_val = sc->sc_bss.chanset;
+ break;
+ case IEEE80211_IOC_POWERSAVE:
+ /*
+ * There appears to be a mib for this in the
+ * softc, but since there's no way to enable
+ * powersaving reporting it's value isn't really
+ * meaningfull.
+ */
+ ireq->i_val = IEEE80211_POWERSAVE_NOSUP;
+ break;
+ case IEEE80211_IOC_POWERSAVESLEEP:
+ error = EINVAL;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case SIOCS80211:
+ error = suser(curproc);
+ if(error)
+ break;
+ switch(ireq->i_type) {
+ case IEEE80211_IOC_SSID:
+ if(ireq->i_val != 0) {
+ error = EINVAL;
+ break;
+ }
+ bzero(tmpstr, AWI_ESS_ID_SIZE);
+ tmpstr[0] = IEEE80211_ELEMID_SSID;
+ tmpstr[1] = ireq->i_val;
+ error = copyin(ireq->i_data, tmpstr+2, ireq->i_val);
+ if(error)
+ break;
+ bcopy(tmpstr, sc->sc_mib_mac.aDesired_ESS_ID,
+ AWI_ESS_ID_SIZE);
+ bcopy(tmpstr, sc->sc_ownssid, AWI_ESS_ID_SIZE);
+ break;
+ case IEEE80211_IOC_WEP:
+ if(ireq->i_val == IEEE80211_WEP_OFF)
+ error = awi_wep_setalgo(sc, 0);
+ else
+ error = awi_wep_setalgo(sc, 1);
+ break;
+ case IEEE80211_IOC_WEPKEY:
+ error = copyin(ireq->i_data, tmpstr, 14);
+ if(error)
+ break;
+ if(ireq->i_val < 0 || ireq->i_val > 3 ||
+ tmpstr[0] > 13) {
+ error = EINVAL;
+ break;
+ }
+ error = awi_wep_setkey(sc, ireq->i_val, tmpstr+1,
+ tmpstr[0]);
+ break;
+ case IEEE80211_IOC_WEPTXKEY:
+ if(ireq->i_val < 0 || ireq->i_val > 3) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_wep_defkid = ireq->i_val;
+ break;
+ case IEEE80211_IOC_AUTHMODE:
+ error = EINVAL;
+ break;
+ case IEEE80211_IOC_STATIONNAME:
+ error = EPERM;
+ break;
+ case IEEE80211_IOC_CHANNEL:
+ if(ireq->i_val < sc->sc_scan_min ||
+ ireq->i_val > sc->sc_scan_max) {
+ error = EINVAL;
+ break;
+ }
+ sc->sc_ownch = ireq->i_val;
+ break;
+ case IEEE80211_IOC_POWERSAVE:
+ if(ireq->i_val != 0)
+ error = EINVAL;
+ break;
+ case IEEE80211_IOC_POWERSAVESLEEP:
+ error = EINVAL;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ /* Restart the card so the change takes effect */
+ if(!error) {
+ if(sc->sc_enabled) {
+ awi_stop(sc);
+ error = awi_init(sc);
+ }
+ }
+ break;
+#endif /* __FreeBSD__ */
default:
error = awi_wicfg(ifp, cmd, data);
break;
diff --git a/sys/dev/wi/if_wavelan_ieee.h b/sys/dev/wi/if_wavelan_ieee.h
index 5e1046a6c06f..0454898d7c2a 100644
--- a/sys/dev/wi/if_wavelan_ieee.h
+++ b/sys/dev/wi/if_wavelan_ieee.h
@@ -169,6 +169,7 @@ struct wi_counters {
u_int32_t wi_rx_msg_in_msg_frags;
u_int32_t wi_rx_msg_in_bad_msg_frags;
};
+#endif
/*
* These are all the LTV record types that we can read or write
@@ -247,6 +248,7 @@ struct wi_counters {
#define WI_RID_TX_CRYPT_KEY 0xFCB1
#define WI_RID_TICK_TIME 0xFCE0
+#ifndef _KERNEL
struct wi_key {
u_int16_t wi_keylen;
u_int8_t wi_keydat[14];
@@ -257,6 +259,7 @@ struct wi_ltv_keys {
u_int16_t wi_type;
struct wi_key wi_keys[4];
};
+#endif
/*
* NIC information
@@ -315,7 +318,6 @@ struct wi_ltv_keys {
#define WI_RID_CCA_TIME 0xFDC4 /* clear chan assess time */
#define WI_RID_MAC_PROC_DELAY 0xFDC5 /* MAC processing delay time */
#define WI_RID_DATA_RATES 0xFDC6 /* supported data rates */
-#endif
#endif
diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c
index 2ae8fd1a1ac2..40cdbc509385 100644
--- a/sys/dev/wi/if_wi.c
+++ b/sys/dev/wi/if_wi.c
@@ -92,6 +92,7 @@
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
+#include <net/if_ieee80211.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -161,6 +162,10 @@ static void wi_shutdown __P((device_t));
static int wi_alloc __P((device_t, int));
static void wi_free __P((device_t));
+static int wi_get_cur_ssid __P((struct wi_softc *, char *, int *));
+static int wi_media_change __P((struct ifnet *));
+static void wi_media_status __P((struct ifnet *, struct ifmediareq *));
+
static device_method_t wi_pccard_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, pccard_compat_probe),
@@ -282,6 +287,9 @@ static int wi_pccard_detach(dev)
wi_stop(sc);
+ /* Delete all remaining media. */
+ ifmedia_removeall(&sc->ifmedia);
+
ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
bus_teardown_intr(dev, sc->irq, sc->wi_intrhand);
wi_free(dev);
@@ -511,6 +519,29 @@ wi_generic_attach(device_t dev)
wi_init(sc);
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);
+#undef ADD
+ ifmedia_set(&sc->ifmedia, IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO,
+ 0, 0));
+
+
/*
* Call MI attach routine.
*/
@@ -1297,14 +1328,19 @@ static int wi_ioctl(ifp, command, data)
caddr_t data;
{
int error = 0;
+ int len;
+ u_int8_t tmpkey[14];
+ char tmpssid[IEEE80211_NWID_LEN];
struct wi_softc *sc;
struct wi_req wreq;
struct ifreq *ifr;
+ struct ieee80211req *ireq;
struct proc *p = curproc;
sc = ifp->if_softc;
WI_LOCK(sc);
ifr = (struct ifreq *)data;
+ ireq = (struct ieee80211req *)data;
if (sc->wi_gone) {
error = ENODEV;
@@ -1337,6 +1373,10 @@ static int wi_ioctl(ifp, command, data)
sc->wi_if_flags = ifp->if_flags;
error = 0;
break;
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
+ break;
case SIOCADDMULTI:
case SIOCDELMULTI:
wi_setmulti(sc);
@@ -1398,6 +1438,203 @@ static int wi_ioctl(ifp, command, data)
wi_setdef(sc, &wreq);
}
break;
+ case SIOCG80211:
+ switch(ireq->i_type) {
+ case IEEE80211_IOC_SSID:
+ if(ireq->i_val == -1) {
+ bzero(tmpssid, IEEE80211_NWID_LEN);
+ error = wi_get_cur_ssid(sc, tmpssid, &len);
+ if (error != 0)
+ break;
+ error = copyout(tmpssid, ireq->i_data,
+ IEEE80211_NWID_LEN);
+ ireq->i_len = len;
+ } else if (ireq->i_val == 0) {
+ error = copyout(sc->wi_net_name,
+ ireq->i_data,
+ IEEE80211_NWID_LEN);
+ ireq->i_len = IEEE80211_NWID_LEN;
+ } else
+ error = EINVAL;
+ break;
+ case IEEE80211_IOC_NUMSSIDS:
+ ireq->i_val = 1;
+ break;
+ case IEEE80211_IOC_WEP:
+ if(!sc->wi_has_wep) {
+ ireq->i_val = IEEE80211_WEP_NOSUP;
+ } else {
+ if(sc->wi_use_wep) {
+ ireq->i_val =
+ IEEE80211_WEP_MIXED;
+ } else {
+ ireq->i_val =
+ IEEE80211_WEP_OFF;
+ }
+ }
+ break;
+ case IEEE80211_IOC_WEPKEY:
+ if(!sc->wi_has_wep ||
+ ireq->i_val < 0 || ireq->i_val > 3) {
+ error = EINVAL;
+ break;
+ }
+ len = sc->wi_keys.wi_keys[ireq->i_val].wi_keylen;
+ if (suser(p))
+ bcopy(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat,
+ tmpkey, len);
+ else
+ bzero(tmpkey, len);
+
+ ireq->i_len = len;
+ error = copyout(tmpkey, ireq->i_data, len);
+
+ break;
+ case IEEE80211_IOC_NUMWEPKEYS:
+ if(!sc->wi_has_wep)
+ error = EINVAL;
+ else
+ ireq->i_val = 4;
+ break;
+ case IEEE80211_IOC_WEPTXKEY:
+ if(!sc->wi_has_wep)
+ error = EINVAL;
+ else
+ ireq->i_val = sc->wi_tx_key;
+ break;
+ case IEEE80211_IOC_AUTHMODE:
+ ireq->i_val = IEEE80211_AUTH_NONE;
+ break;
+ case IEEE80211_IOC_STATIONNAME:
+ error = copyout(sc->wi_node_name,
+ ireq->i_data, IEEE80211_NWID_LEN);
+ ireq->i_len = IEEE80211_NWID_LEN;
+ break;
+ case IEEE80211_IOC_CHANNEL:
+ wreq.wi_type = WI_RID_CURRENT_CHAN;
+ wreq.wi_len = WI_MAX_DATALEN;
+ if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq))
+ error = EINVAL;
+ else {
+ ireq->i_val = wreq.wi_val[0];
+ }
+ break;
+ case IEEE80211_IOC_POWERSAVE:
+ if(sc->wi_pm_enabled)
+ ireq->i_val = IEEE80211_POWERSAVE_ON;
+ else
+ ireq->i_val = IEEE80211_POWERSAVE_OFF;
+ break;
+ case IEEE80211_IOC_POWERSAVESLEEP:
+ ireq->i_val = sc->wi_max_sleep;
+ break;
+ default:
+ error = EINVAL;
+ }
+ break;
+ case SIOCS80211:
+ if ((error = suser(p)))
+ goto out;
+ switch(ireq->i_type) {
+ case IEEE80211_IOC_SSID:
+ if (ireq->i_val != 0 ||
+ ireq->i_len > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ /* We set both of them */
+ bzero(sc->wi_net_name, IEEE80211_NWID_LEN);
+ error = copyin(ireq->i_data,
+ sc->wi_net_name, ireq->i_len);
+ bcopy(sc->wi_net_name, sc->wi_ibss_name, IEEE80211_NWID_LEN);
+ break;
+ case IEEE80211_IOC_WEP:
+ /*
+ * These cards only support one mode so
+ * we just turn wep on what ever is
+ * passed in if it's not OFF.
+ */
+ if (ireq->i_val == IEEE80211_WEP_OFF) {
+ sc->wi_use_wep = 0;
+ } else {
+ sc->wi_use_wep = 1;
+ }
+ break;
+ case IEEE80211_IOC_WEPKEY:
+ if (ireq->i_val < 0 || ireq->i_val > 3 ||
+ ireq->i_len > 13) {
+ error = EINVAL;
+ break;
+ }
+ bzero(sc->wi_keys.wi_keys[ireq->i_val].wi_keydat, 13);
+ error = copyin(ireq->i_data,
+ sc->wi_keys.wi_keys[ireq->i_val].wi_keydat,
+ ireq->i_len);
+ if(error)
+ break;
+ sc->wi_keys.wi_keys[ireq->i_val].wi_keylen =
+ ireq->i_len;
+ break;
+ case IEEE80211_IOC_WEPTXKEY:
+ if (ireq->i_val < 0 || ireq->i_val > 3) {
+ error = EINVAL;
+ break;
+ }
+ sc->wi_tx_key = ireq->i_val;
+ break;
+ case IEEE80211_IOC_AUTHMODE:
+ error = EINVAL;
+ break;
+ case IEEE80211_IOC_STATIONNAME:
+ if (ireq->i_len > 32) {
+ error = EINVAL;
+ break;
+ }
+ bzero(sc->wi_node_name, 32);
+ error = copyin(ireq->i_data,
+ sc->wi_node_name, ireq->i_len);
+ break;
+ case IEEE80211_IOC_CHANNEL:
+ /*
+ * The actual range is 1-14, but if you
+ * set it to 0 you get the default. So
+ * we let that work too.
+ */
+ if (ireq->i_val < 0 || ireq->i_val > 14) {
+ error = EINVAL;
+ break;
+ }
+ sc->wi_channel = ireq->i_val;
+ break;
+ case IEEE80211_IOC_POWERSAVE:
+ switch (ireq->i_val) {
+ case IEEE80211_POWERSAVE_OFF:
+ sc->wi_pm_enabled = 0;
+ break;
+ case IEEE80211_POWERSAVE_ON:
+ sc->wi_pm_enabled = 1;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ case IEEE80211_IOC_POWERSAVESLEEP:
+ if (ireq->i_val < 0) {
+ error = EINVAL;
+ break;
+ }
+ sc->wi_max_sleep = ireq->i_val;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ /* Reinitialize WaveLAN. */
+ wi_init(sc);
+
+ break;
default:
error = EINVAL;
break;
@@ -1966,3 +2203,142 @@ void wi_cache_store (struct wi_softc *sc, struct ether_header *eh,
return;
}
#endif
+
+static int wi_get_cur_ssid(sc, ssid, len)
+ struct wi_softc *sc;
+ char *ssid;
+ int *len;
+{
+ int error = 0;
+ struct wi_req wreq;
+
+ wreq.wi_len = WI_MAX_DATALEN;
+ switch (sc->wi_ptype) {
+ case WI_PORTTYPE_ADHOC:
+ wreq.wi_type = WI_RID_CURRENT_SSID;
+ error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
+ if (error != 0)
+ break;
+ if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ *len = wreq.wi_val[0];
+ bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN);
+ break;
+ case WI_PORTTYPE_BSS:
+ wreq.wi_type = WI_RID_COMMQUAL;
+ error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
+ if (error != 0)
+ break;
+ if (wreq.wi_val[0] != 0) /* associated */ {
+ wreq.wi_type = WI_RID_CURRENT_SSID;
+ wreq.wi_len = WI_MAX_DATALEN;
+ error = wi_read_record(sc, (struct wi_ltv_gen *)&wreq);
+ if (error != 0)
+ break;
+ if (wreq.wi_val[0] > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
+ }
+ *len = wreq.wi_val[0];
+ bcopy(&wreq.wi_val[1], ssid, IEEE80211_NWID_LEN);
+ } else {
+ *len = IEEE80211_NWID_LEN;
+ bcopy(sc->wi_net_name, ssid, IEEE80211_NWID_LEN);
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+static int wi_media_change(ifp)
+ struct ifnet *ifp;
+{
+ struct wi_softc *sc = ifp->if_softc;
+ int otype = sc->wi_ptype;
+ int orate = sc->wi_tx_rate;
+
+ if ((sc->ifmedia.ifm_cur->ifm_media & IFM_IEEE80211_ADHOC) != 0)
+ sc->wi_ptype = WI_PORTTYPE_ADHOC;
+ else
+ sc->wi_ptype = WI_PORTTYPE_BSS;
+
+ switch (IFM_SUBTYPE(sc->ifmedia.ifm_cur->ifm_media)) {
+ case IFM_IEEE80211_DS1:
+ sc->wi_tx_rate = 1;
+ break;
+ case IFM_IEEE80211_DS2:
+ sc->wi_tx_rate = 2;
+ break;
+ case IFM_IEEE80211_DS5:
+ sc->wi_tx_rate = 5;
+ break;
+ case IFM_IEEE80211_DS11:
+ sc->wi_tx_rate = 11;
+ break;
+ case IFM_AUTO:
+ sc->wi_tx_rate = 3;
+ break;
+ }
+
+ if (otype != sc->wi_ptype ||
+ orate != sc->wi_tx_rate)
+ wi_init(sc);
+
+ return(0);
+}
+
+static void wi_media_status(ifp, imr)
+ struct ifnet *ifp;
+ struct ifmediareq *imr;
+{
+ struct wi_req wreq;
+ struct wi_softc *sc = ifp->if_softc;
+
+ if (sc->wi_tx_rate == 3) {
+ imr->ifm_active = IFM_IEEE80211|IFM_AUTO;
+ if (sc->wi_ptype == WI_PORTTYPE_ADHOC)
+ imr->ifm_active |= IFM_IEEE80211_ADHOC;
+ 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) {
+ switch(wreq.wi_val[0]) {
+ case 1:
+ imr->ifm_active |= IFM_IEEE80211_DS1;
+ break;
+ case 2:
+ imr->ifm_active |= IFM_IEEE80211_DS2;
+ break;
+ case 6:
+ imr->ifm_active |= IFM_IEEE80211_DS5;
+ break;
+ case 11:
+ imr->ifm_active |= IFM_IEEE80211_DS11;
+ break;
+ }
+ }
+ } else {
+ imr->ifm_active = sc->ifmedia.ifm_cur->ifm_media;
+ }
+
+ imr->ifm_status = IFM_AVALID;
+ if (sc->wi_ptype == WI_PORTTYPE_ADHOC)
+ /*
+ * XXX: It would be nice if we could give some actually
+ * useful status like whether we joined another IBSS or
+ * created one ourselves.
+ */
+ imr->ifm_status |= IFM_ACTIVE;
+ else {
+ wreq.wi_type = WI_RID_COMMQUAL;
+ wreq.wi_len = WI_MAX_DATALEN;
+ if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq) == 0 &&
+ wreq.wi_val[0] != 0)
+ imr->ifm_status |= IFM_ACTIVE;
+ }
+}
diff --git a/sys/net/if_ieee80211.h b/sys/net/if_ieee80211.h
index a95498fb843d..a6e866e3bbe3 100644
--- a/sys/net/if_ieee80211.h
+++ b/sys/net/if_ieee80211.h
@@ -229,4 +229,43 @@ struct ieee80211_nwkey {
#define SIOCS80211NWKEY _IOW('i', 232, struct ieee80211_nwkey)
#define SIOCG80211NWKEY _IOWR('i', 233, struct ieee80211_nwkey)
+#define IEEE80211_WEP_NOSUP -1
+#define IEEE80211_WEP_OFF 0
+#define IEEE80211_WEP_ON 1
+#define IEEE80211_WEP_MIXED 2
+
+#define IEEE80211_AUTH_NONE 0
+#define IEEE80211_AUTH_OPEN 1
+#define IEEE80211_AUTH_SHARED 2
+
+#define IEEE80211_POWERSAVE_NOSUP -1
+#define IEEE80211_POWERSAVE_OFF 0
+#define IEEE80211_POWERSAVE_CAM 1
+#define IEEE80211_POWERSAVE_PSP 2
+#define IEEE80211_POWERSAVE_PSP_CAM 3
+#define IEEE80211_POWERSAVE_ON IEEE80211_POWERSAVE_CAM
+
+/* the first member must be matched with struct ifreq */
+struct ieee80211req {
+ char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */
+ u_int16_t i_type; /* req type */
+ int16_t i_val; /* Index or simple value */
+ int16_t i_len; /* Index or simple value */
+ void *i_data; /* Extra data */
+};
+#define SIOCS80211 _IOW('i', 234, struct ieee80211req)
+#define SIOCG80211 _IOWR('i', 235, struct ieee80211req)
+
+#define IEEE80211_IOC_SSID 1
+#define IEEE80211_IOC_NUMSSIDS 2
+#define IEEE80211_IOC_WEP 3
+#define IEEE80211_IOC_WEPKEY 4
+#define IEEE80211_IOC_NUMWEPKEYS 5
+#define IEEE80211_IOC_WEPTXKEY 6
+#define IEEE80211_IOC_AUTHMODE 7
+#define IEEE80211_IOC_STATIONNAME 8
+#define IEEE80211_IOC_CHANNEL 9
+#define IEEE80211_IOC_POWERSAVE 10
+#define IEEE80211_IOC_POWERSAVESLEEP 11
+
#endif /* !_NET_IF_IEEE80211_H_ */
diff --git a/sys/net/if_media.c b/sys/net/if_media.c
index 691c8cdfad7c..fd372ca5e03b 100644
--- a/sys/net/if_media.c
+++ b/sys/net/if_media.c
@@ -401,6 +401,12 @@ struct ifmedia_description ifm_subtype_fddi_descriptions[] =
struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
+struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
+ IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
+
+struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
+ IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
+
struct ifmedia_description ifm_subtype_shared_descriptions[] =
IFM_SUBTYPE_SHARED_DESCRIPTIONS;
@@ -426,6 +432,10 @@ struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
&ifm_subtype_fddi_descriptions[0],
&ifm_subtype_fddi_option_descriptions[0]
},
+ {
+ &ifm_subtype_ieee80211_descriptions[0],
+ &ifm_subtype_ieee80211_option_descriptions[0]
+ },
};
/*
diff --git a/sys/net/if_media.h b/sys/net/if_media.h
index 2ed5ed0171c7..52bbdbd3667b 100644
--- a/sys/net/if_media.h
+++ b/sys/net/if_media.h
@@ -167,6 +167,19 @@ int ifmedia_ioctl __P((struct ifnet *ifp, struct ifreq *ifr,
#define IFM_FDDI_DA 0x00000100 /* Dual attach / single attach */
/*
+ * IEEE 802.11 Wireless
+ */
+#define IFM_IEEE80211 0x00000080
+#define IFM_IEEE80211_FH1 3 /* Frequency Hopping 1Mbps */
+#define IFM_IEEE80211_FH2 4 /* Frequency Hopping 2Mbps */
+#define IFM_IEEE80211_DS1 5 /* Direct Sequence 1Mbps */
+#define IFM_IEEE80211_DS2 6 /* Direct Sequence 2Mbps */
+#define IFM_IEEE80211_DS5 7 /* Direct Sequence 5.5Mbps */
+#define IFM_IEEE80211_DS11 8 /* Direct Sequence 11Mbps */
+#define IFM_IEEE80211_DS22 9 /* Direct Sequence 22Mbps */
+#define IFM_IEEE80211_ADHOC 0x00000100 /* Operate in Adhoc mode */
+
+/*
* Shared media sub-types
*/
#define IFM_AUTO 0 /* Autoselect best media */
@@ -229,9 +242,10 @@ struct ifmedia_description {
};
#define IFM_TYPE_DESCRIPTIONS { \
- { IFM_ETHER, "Ethernet" }, \
- { IFM_TOKEN, "Token ring" }, \
- { IFM_FDDI, "FDDI" }, \
+ { IFM_ETHER, "Ethernet" }, \
+ { IFM_TOKEN, "Token ring" }, \
+ { IFM_FDDI, "FDDI" }, \
+ { IFM_IEEE80211, "IEEE 802.11 Wireless Ethernet" }, \
{ 0, NULL }, \
}
@@ -330,6 +344,40 @@ struct ifmedia_description {
{ 0, NULL }, \
}
+#define IFM_SUBTYPE_IEEE80211_DESCRIPTIONS { \
+ { IFM_IEEE80211_FH1, "FH/1Mbps" }, \
+ { IFM_IEEE80211_FH2, "FH/2Mbps" }, \
+ { IFM_IEEE80211_DS1, "DS/1Mbps" }, \
+ { IFM_IEEE80211_DS2, "DS/2Mbps" }, \
+ { IFM_IEEE80211_DS5, "DS/5.5Mbps" }, \
+ { IFM_IEEE80211_DS11, "DS/11Mbps" }, \
+ { IFM_IEEE80211_DS22, "DS/22Mbps" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_IEEE80211_ALIASES { \
+ { IFM_IEEE80211_FH1, "FH1" }, \
+ { IFM_IEEE80211_FH2, "FH2" }, \
+ { IFM_IEEE80211_FH1, "FrequencyHopping/1Mbps" }, \
+ { IFM_IEEE80211_FH2, "FrequencyHopping/2Mbps" }, \
+ { IFM_IEEE80211_DS1, "DS1" }, \
+ { IFM_IEEE80211_DS2, "DS2" }, \
+ { IFM_IEEE80211_DS5, "DS5.5" }, \
+ { IFM_IEEE80211_DS11, "DS11" }, \
+ { IFM_IEEE80211_DS22, "DS22" }, \
+ { IFM_IEEE80211_DS1, "DirectSequence/1Mbps" }, \
+ { IFM_IEEE80211_DS2, "DirectSequence/2Mbps" }, \
+ { IFM_IEEE80211_DS5, "DirectSequence/5.5Mbps" }, \
+ { IFM_IEEE80211_DS11, "DirectSequence/11Mbps" }, \
+ { IFM_IEEE80211_DS22, "DirectSequence/22Mbps" }, \
+ { 0, NULL }, \
+}
+
+#define IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS { \
+ { IFM_IEEE80211_ADHOC, "adhoc" }, \
+ { 0, NULL }, \
+}
+
#define IFM_SUBTYPE_SHARED_DESCRIPTIONS { \
{ IFM_AUTO, "autoselect" }, \
{ IFM_MANUAL, "manual" }, \