Add experimental support of Host-AP mode for awi driver.

It works also with WEP enabled.
But aging the associated clients is not implemented yet, so that the number
of clients may increase unlimitedly..
This commit is contained in:
onoe 2002-09-02 13:37:35 +00:00
parent 89e1f79b11
commit efcfc3e1c8
3 changed files with 467 additions and 185 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: awi.c,v 1.44 2002/08/28 09:38:10 onoe Exp $ */
/* $NetBSD: awi.c,v 1.45 2002/09/02 13:37:35 onoe Exp $ */
/*-
* Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc.
@ -85,7 +85,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.44 2002/08/28 09:38:10 onoe Exp $");
__KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.45 2002/09/02 13:37:35 onoe Exp $");
#include "opt_inet.h"
#include "bpfilter.h"
@ -139,8 +139,6 @@ static int awi_ioctl(struct ifnet *, u_long, caddr_t);
static int awi_media_change(struct ifnet *);
static void awi_media_status(struct ifnet *, struct ifmediareq *);
static int awi_mode_init(struct awi_softc *);
static int awi_media_rate2opt(struct awi_softc *, int);
static int awi_media_opt2rate(struct awi_softc *, int);
static void awi_rx_int(struct awi_softc *);
static void awi_tx_int(struct awi_softc *);
static struct mbuf *awi_devget(struct awi_softc *, u_int32_t, u_int16_t);
@ -240,7 +238,8 @@ awi_attach(struct awi_softc *sc)
ic->ic_flags = IEEE80211_F_FH;
else
ic->ic_flags = IEEE80211_F_DS;
ic->ic_flags |= IEEE80211_F_HASWEP | IEEE80211_F_HASIBSS;
ic->ic_flags |=
IEEE80211_F_HASWEP | IEEE80211_F_HASIBSS | IEEE80211_F_HASHAP;
ic->ic_state = IEEE80211_S_INIT;
ic->ic_newstate = awi_newstate;
ic->ic_chancheck = awi_chan_check;
@ -266,24 +265,28 @@ awi_attach(struct awi_softc *sc)
>> IEEE80211_FC0_SUBTYPE_SHIFT] = NULL;
ifmedia_init(&sc->sc_media, 0, awi_media_change, awi_media_status);
mword = IFM_MAKEWORD(IFM_IEEE80211, IFM_AUTO, 0, 0);
ifmedia_add(&sc->sc_media, mword, 0, NULL);
ifmedia_add(&sc->sc_media, mword | IFM_FLAG0, 0, NULL);
mword |= IFM_IEEE80211_ADHOC;
ifmedia_add(&sc->sc_media, mword, 0, NULL);
ifmedia_add(&sc->sc_media, mword | IFM_FLAG0, 0, NULL);
#define ADD(s, o) ifmedia_add(&sc->sc_media, \
IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL)
ADD(IFM_AUTO, 0); /* infra mode */
ADD(IFM_AUTO, IFM_FLAG0); /* melco compat mode */
ADD(IFM_AUTO, IFM_IEEE80211_ADHOC); /* IBSS mode */
if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
ADD(IFM_AUTO, IFM_IEEE80211_ADHOC | IFM_FLAG0);
/* lucent compat mode */
ADD(IFM_AUTO, IFM_IEEE80211_HOSTAP);
for (i = 0; i < nrate; i++) {
mword = awi_media_rate2opt(sc, ic->ic_sup_rates[i]);
mword = ieee80211_rate2media(ic->ic_sup_rates[i],
(ic->ic_flags & (IEEE80211_F_FH | IEEE80211_F_DS)));
if (mword == 0)
continue;
mword |= IFM_IEEE80211;
ifmedia_add(&sc->sc_media, mword, 0, NULL);
ifmedia_add(&sc->sc_media, mword | IFM_FLAG0, 0, NULL);
mword |= IFM_IEEE80211_ADHOC;
ifmedia_add(&sc->sc_media, mword, 0, NULL);
ADD(mword, 0);
ADD(mword, IFM_FLAG0);
ADD(mword, IFM_IEEE80211_ADHOC);
if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
ifmedia_add(&sc->sc_media, mword | IFM_FLAG0, 0, NULL);
ADD(mword, IFM_IEEE80211_ADHOC | IFM_FLAG0);
ADD(mword, IFM_IEEE80211_HOSTAP);
}
#undef ADD
awi_media_status(ifp, &imr);
ifmedia_set(&sc->sc_media, imr.ifm_active);
@ -484,6 +487,8 @@ awi_init(struct ifnet *ifp)
sc->sc_mib_local.Network_Mode =
(ic->ic_flags & IEEE80211_F_ADHOC) ? 0 : 1;
sc->sc_mib_local.Acting_as_AP =
(ic->ic_flags & IEEE80211_F_HOSTAP) ? 1 : 0;
memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
sc->sc_mib_mac.aDesired_ESS_ID[1] = sc->sc_ic.ic_des_esslen;
@ -528,9 +533,13 @@ awi_init(struct ifnet *ifp)
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
if ((sc->sc_ic.ic_flags & IEEE80211_F_ADHOC) && sc->sc_no_bssid) {
if (((sc->sc_ic.ic_flags & IEEE80211_F_ADHOC) && sc->sc_no_bssid) ||
(sc->sc_ic.ic_flags & IEEE80211_F_HOSTAP)) {
bs->bs_chan = ic->ic_ibss_chan;
bs->bs_intval = ic->ic_lintval;
bs->bs_rssi = 0;
bs->bs_rstamp = 0;
memset(bs->bs_tstamp, 0, sizeof(bs->bs_tstamp));
bs->bs_nrate = 0;
for (i = 0; i < IEEE80211_RATE_SIZE; i++) {
if (ic->ic_sup_rates[i])
@ -538,8 +547,22 @@ awi_init(struct ifnet *ifp)
ic->ic_sup_rates[i];
}
memcpy(bs->bs_macaddr, ic->ic_myaddr, IEEE80211_ADDR_LEN);
memset(bs->bs_bssid, 0, IEEE80211_ADDR_LEN);
bs->bs_esslen = 0;
if (sc->sc_ic.ic_flags & IEEE80211_F_HOSTAP) {
memcpy(bs->bs_bssid, ic->ic_myaddr, IEEE80211_ADDR_LEN);
bs->bs_esslen = ic->ic_des_esslen;
memcpy(bs->bs_essid, ic->ic_des_essid, bs->bs_esslen);
bs->bs_capinfo = IEEE80211_CAPINFO_ESS;
if (ic->ic_flags & IEEE80211_F_FH) {
bs->bs_fhdwell = 200; /* XXX */
bs->bs_fhindex = 1;
}
} else {
bs->bs_capinfo = IEEE80211_CAPINFO_IBSS;
memset(bs->bs_bssid, 0, IEEE80211_ADDR_LEN);
bs->bs_esslen = 0;
}
if (ic->ic_flags & IEEE80211_F_WEPON)
bs->bs_capinfo |= IEEE80211_CAPINFO_PRIVACY;
ic->ic_flags |= IEEE80211_F_SIBSS;
ic->ic_state = IEEE80211_S_SCAN; /*XXX*/
sc->sc_substate = AWI_ST_NONE;
@ -817,7 +840,8 @@ awi_media_change(struct ifnet *ifp)
if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
ic->ic_fixed_rate = -1;
} else {
rate = awi_media_opt2rate(sc, ime->ifm_media);
rate = ieee80211_media2rate(ime->ifm_media,
(ic->ic_flags & (IEEE80211_F_FH | IEEE80211_F_DS)));
if (rate == 0)
return EINVAL;
for (i = 0; i < IEEE80211_RATE_SIZE; i++) {
@ -830,18 +854,23 @@ awi_media_change(struct ifnet *ifp)
}
/*
* ADHOC,-FLAG0 ADHOC, !no_bssid, !adhoc_ap IBSS
* ADHOC, FLAG0 ADHOC no_bssid, !adhoc_ap WaveLAN adhoc
* -ADHOC,-FLAG0 ~ADHOC, !no_bssid, !adhoc_ap Infra
* -ADHOC, FLAG0 ADHOC, !no_bssid, adhoc_ap Melco old AP
* ADHOC,-FLAG0 ADHOC|~HOSTAP, !no_bssid, !adhoc_ap IBSS
* ADHOC, FLAG0 ADHOC|~HOSTAP, no_bssid, !adhoc_ap WaveLAN adhoc
* -ADHOC, FLAG0 ADHOC|~HOSTAP, !no_bssid, adhoc_ap Melco old AP
* also LINK0
* -ADHOC,HOSTAP ~ADHOC|HOSTAP, !no_bssid, !adhoc_ap HostAP
* -ADHOC,-FLAG0 ~ADHOC|~HOSTAP, !no_bssid, !adhoc_ap Infra
*/
if (ime->ifm_media & IFM_IEEE80211_ADHOC) {
if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0) {
ic->ic_flags |= IEEE80211_F_ADHOC;
if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0 ||
(ic->ic_flags & IEEE80211_F_IBSSON) == 0 ||
(ic->ic_flags & IEEE80211_F_HOSTAP) ||
sc->sc_adhoc_ap) {
ic->ic_flags |= IEEE80211_F_ADHOC | IEEE80211_F_IBSSON;
ic->ic_flags &= ~IEEE80211_F_HOSTAP;
sc->sc_adhoc_ap = 0;
error = ENETRESET;
}
ic->ic_flags |= IEEE80211_F_IBSSON;
if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH &&
(ime->ifm_media & IFM_FLAG0)) {
if (sc->sc_no_bssid == 0) {
@ -854,35 +883,41 @@ awi_media_change(struct ifnet *ifp)
error = ENETRESET;
}
}
if (sc->sc_adhoc_ap) {
} else if (ime->ifm_media & IFM_FLAG0) {
if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0 ||
(ic->ic_flags & IEEE80211_F_IBSSON) ||
(ic->ic_flags & IEEE80211_F_HOSTAP) ||
sc->sc_no_bssid || !sc->sc_adhoc_ap) {
ic->ic_flags |= IEEE80211_F_ADHOC;
ic->ic_flags &=
~(IEEE80211_F_IBSSON | IEEE80211_F_HOSTAP);
sc->sc_no_bssid = 0;
sc->sc_adhoc_ap = 1;
error = ENETRESET;
}
} else if (ime->ifm_media & IFM_IEEE80211_HOSTAP) {
if ((ic->ic_flags & IEEE80211_F_ADHOC) ||
(ic->ic_flags & IEEE80211_F_IBSSON) ||
(ic->ic_flags & IEEE80211_F_HOSTAP) == 0 ||
sc->sc_no_bssid || sc->sc_adhoc_ap) {
ic->ic_flags |= IEEE80211_F_HOSTAP;
ic->ic_flags &=
~(IEEE80211_F_ADHOC | IEEE80211_F_IBSSON);
sc->sc_no_bssid = 0;
sc->sc_adhoc_ap = 0;
error = ENETRESET;
}
} else {
ic->ic_flags &= ~IEEE80211_F_IBSSON;
if (sc->sc_no_bssid) {
if ((ic->ic_flags & IEEE80211_F_ADHOC) ||
(ic->ic_flags & IEEE80211_F_IBSSON) ||
(ic->ic_flags & IEEE80211_F_HOSTAP) ||
sc->sc_no_bssid || sc->sc_adhoc_ap) {
ic->ic_flags &= ~(IEEE80211_F_ADHOC |
IEEE80211_F_IBSSON | IEEE80211_F_HOSTAP);
sc->sc_no_bssid = 0;
sc->sc_adhoc_ap = 0;
error = ENETRESET;
}
if (ime->ifm_media & IFM_FLAG0) {
if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0) {
ic->ic_flags |= IEEE80211_F_ADHOC;
error = ENETRESET;
}
if (!sc->sc_adhoc_ap) {
sc->sc_adhoc_ap = 1;
error = ENETRESET;
}
} else {
if (ic->ic_flags & IEEE80211_F_ADHOC) {
ic->ic_flags &= ~IEEE80211_F_ADHOC;
error = ENETRESET;
}
if (sc->sc_adhoc_ap) {
sc->sc_adhoc_ap = 0;
error = ENETRESET;
}
}
}
if (error == ENETRESET) {
if (sc->sc_enabled)
@ -914,8 +949,11 @@ awi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
rate = ic->ic_sup_rates[ic->ic_fixed_rate] &
IEEE80211_RATE_VAL;
}
imr->ifm_active |= awi_media_rate2opt(sc, rate);
if (ic->ic_flags & IEEE80211_F_ADHOC) {
imr->ifm_active |= ieee80211_rate2media(rate,
(ic->ic_flags & (IEEE80211_F_FH | IEEE80211_F_DS)));
if (ic->ic_flags & IEEE80211_F_HOSTAP)
imr->ifm_active |= IFM_IEEE80211_HOSTAP;
else if (ic->ic_flags & IEEE80211_F_ADHOC) {
if (sc->sc_adhoc_ap)
imr->ifm_active |= IFM_FLAG0;
else {
@ -976,78 +1014,6 @@ awi_mode_init(struct awi_softc *sc)
return 0;
}
/* XXX should be moved to if_ieee80211subr.c ? */
static int
awi_media_rate2opt(struct awi_softc *sc, int rate)
{
int mword;
mword = 0;
switch (rate & IEEE80211_RATE_VAL) {
case 2:
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
mword = IFM_IEEE80211_FH1;
else
mword = IFM_IEEE80211_DS1;
break;
case 4:
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
mword = IFM_IEEE80211_FH2;
else
mword = IFM_IEEE80211_DS2;
break;
case 11:
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS)
mword = IFM_IEEE80211_DS5;
break;
case 22:
if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS)
mword = IFM_IEEE80211_DS11;
break;
}
return mword;
}
static int
awi_media_opt2rate(struct awi_softc *sc, int opt)
{
int rate;
rate = 0;
switch (IFM_SUBTYPE(opt)) {
case IFM_IEEE80211_FH1:
case IFM_IEEE80211_FH2:
if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
return 0;
break;
case IFM_IEEE80211_DS1:
case IFM_IEEE80211_DS2:
case IFM_IEEE80211_DS5:
case IFM_IEEE80211_DS11:
if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_DS)
return 0;
break;
}
switch (IFM_SUBTYPE(opt)) {
case IFM_IEEE80211_FH1:
case IFM_IEEE80211_DS1:
rate = 2;
break;
case IFM_IEEE80211_FH2:
case IFM_IEEE80211_DS2:
rate = 4;
break;
case IFM_IEEE80211_DS5:
rate = 11;
break;
case IFM_IEEE80211_DS11:
rate = 22;
break;
}
return rate;
}
static void
awi_rx_int(struct awi_softc *sc)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_ieee80211.h,v 1.15 2002/08/28 09:38:08 onoe Exp $ */
/* $NetBSD: if_ieee80211.h,v 1.16 2002/09/02 13:37:35 onoe Exp $ */
/*-
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@ -402,7 +402,7 @@ struct ieee80211com {
void (*ic_recv_mgmt[16])(struct ieee80211com *,
struct mbuf *, int, u_int32_t);
int (*ic_send_mgmt[16])(struct ieee80211com *,
struct ieee80211_bss *, int);
struct ieee80211_bss *, int, int);
int (*ic_newstate)(void *, enum ieee80211_state);
int (*ic_chancheck)(void *, u_char *);
u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
@ -430,10 +430,10 @@ struct ieee80211com {
#define ic_if ic_ec.ec_if
#define ic_softc ic_ec.ec_if.if_softc
#define IEEE80211_SEND_MGMT(ic,bs,type,flag) do { \
#define IEEE80211_SEND_MGMT(ic,bs,type,arg) do { \
if ((ic)->ic_send_mgmt[(type)>>IEEE80211_FC0_SUBTYPE_SHIFT] != NULL) \
(*(ic)->ic_send_mgmt[(type)>>IEEE80211_FC0_SUBTYPE_SHIFT]) \
(ic,bs,flag); \
(ic,bs,type,arg); \
} while (0)
/* ic_flags */
@ -444,9 +444,11 @@ struct ieee80211com {
#define IEEE80211_F_PMGTON 0x00000400 /* CONF: Power mgmt enable */
#define IEEE80211_F_ADHOC 0x00000800 /* CONF: adhoc mode */
#define IEEE80211_F_SCANAP 0x00001000 /* CONF: scan AP mode */
#define IEEE80211_F_HOSTAP 0x00002000 /* CONF: AP mode */
#define IEEE80211_F_HASWEP 0x00010000 /* CAPABILITY: WEP available */
#define IEEE80211_F_HASIBSS 0x00020000 /* CAPABILITY: IBSS available */
#define IEEE80211_F_HASPMGT 0x00040000 /* CAPABILITY: Power mgmt */
#define IEEE80211_F_HASHAP 0x00080000 /* CAPABILITY: HOSTAP avail */
#define IEEE80211_F_FH 0x01000000 /* PHY: FH */
#define IEEE80211_F_DS 0x02000000 /* PHY: DS */
#define IEEE80211_F_OFDM 0x04000000 /* PHY: OFDM */
@ -475,6 +477,8 @@ void ieee80211_free_scan(struct ifnet *);
int ieee80211_fix_rate(struct ieee80211com *, struct ieee80211_bss *, int);
int ieee80211_new_state(struct ifnet *, enum ieee80211_state, int);
struct mbuf *ieee80211_wep_crypt(struct ifnet *, struct mbuf *, int);
int ieee80211_rate2media(int, int);
int ieee80211_media2rate(int, int);
int ieee80211_cfgget(struct ifnet *, u_long, caddr_t);
int ieee80211_cfgset(struct ifnet *, u_long, caddr_t);

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_ieee80211subr.c,v 1.10 2002/08/28 09:38:08 onoe Exp $ */
/* $NetBSD: if_ieee80211subr.c,v 1.11 2002/09/02 13:37:35 onoe Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_ieee80211subr.c,v 1.10 2002/08/28 09:38:08 onoe Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_ieee80211subr.c,v 1.11 2002/09/02 13:37:35 onoe Exp $");
#include "opt_inet.h"
#include "bpfilter.h"
@ -87,17 +87,19 @@ int ieee80211_debug = 0;
#endif
static int ieee80211_send_prreq(struct ieee80211com *,
struct ieee80211_bss *, int);
struct ieee80211_bss *, int, int);
static int ieee80211_send_prresp(struct ieee80211com *,
struct ieee80211_bss *, int);
struct ieee80211_bss *, int, int);
static int ieee80211_send_auth(struct ieee80211com *,
struct ieee80211_bss *, int);
struct ieee80211_bss *, int, int);
static int ieee80211_send_deauth(struct ieee80211com *,
struct ieee80211_bss *, int);
struct ieee80211_bss *, int, int);
static int ieee80211_send_asreq(struct ieee80211com *,
struct ieee80211_bss *, int);
struct ieee80211_bss *, int, int);
static int ieee80211_send_asresp(struct ieee80211com *,
struct ieee80211_bss *, int, int);
static int ieee80211_send_disassoc(struct ieee80211com *,
struct ieee80211_bss *, int);
struct ieee80211_bss *, int, int);
static void ieee80211_recv_beacon(struct ieee80211com *,
struct mbuf *, int, u_int32_t);
@ -105,6 +107,8 @@ static void ieee80211_recv_prreq(struct ieee80211com *,
struct mbuf *, int, u_int32_t);
static void ieee80211_recv_auth(struct ieee80211com *,
struct mbuf *, int, u_int32_t);
static void ieee80211_recv_asreq(struct ieee80211com *,
struct mbuf *, int, u_int32_t);
static void ieee80211_recv_asresp(struct ieee80211com *,
struct mbuf *, int, u_int32_t);
static void ieee80211_recv_disassoc(struct ieee80211com *,
@ -166,6 +170,10 @@ ieee80211_ifattach(struct ifnet *ifp)
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_prreq;
ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_AUTH
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_auth;
ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_REQ
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asreq;
ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_REQ
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asreq;
ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_RESP
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asresp;
ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_RESP
@ -187,6 +195,10 @@ ieee80211_ifattach(struct ifnet *ifp)
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asreq;
ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_REQ
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asreq;
ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_RESP
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asresp;
ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_RESP
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asresp;
ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_DISASSOC
>> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_disassoc;
}
@ -215,9 +227,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp)
struct ieee80211_frame *wh;
void (*rh)(struct ieee80211com *, struct mbuf *, int, u_int);
u_int8_t dir, subtype;
u_int8_t *bssid;
u_int16_t rxseq;
/* trim CRC here for WEP can find its own CRC at the end of packet. */
if (m->m_flags & M_HASFCS) {
m_adj(m, -IEEE80211_CRC_LEN);
@ -233,26 +245,18 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp)
goto err;
}
if ((wh->i_fc[1] & IEEE80211_FC1_WEP) &&
(ic->ic_flags & IEEE80211_F_WEPON)) {
m = ieee80211_wep_crypt(ifp, m, 0);
if (m == NULL)
goto err;
wh = mtod(m, struct ieee80211_frame *);
}
#if NBPFILTER > 0
/* copy to listener after decrypt */
if (ic->ic_rawbpf)
bpf_mtap(ic->ic_rawbpf, m);
#endif
dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
if (ic->ic_state != IEEE80211_S_SCAN) {
if (ic->ic_flags & IEEE80211_F_ADHOC) {
if (memcmp(wh->i_addr3, ic->ic_bss.bs_bssid,
if ((ic->ic_flags & IEEE80211_F_ADHOC) ||
(ic->ic_flags & IEEE80211_F_HOSTAP)) {
if (dir == IEEE80211_FC1_DIR_NODS)
bssid = wh->i_addr3;
else
bssid = wh->i_addr1;
if (memcmp(bssid, ic->ic_bss.bs_bssid,
IEEE80211_ADDR_LEN) != 0 &&
memcmp(wh->i_addr3, ifp->if_broadcastaddr,
memcmp(bssid, ifp->if_broadcastaddr,
IEEE80211_ADDR_LEN) != 0) {
/* not interested in */
DPRINTF(("ieee80211_input: other bss %s\n",
@ -297,6 +301,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp)
if (ic->ic_flags & IEEE80211_F_ADHOC) {
if (dir != IEEE80211_FC1_DIR_NODS)
goto out;
} else if (ic->ic_flags & IEEE80211_F_HOSTAP) {
if (dir != IEEE80211_FC1_DIR_TODS)
goto out;
} else {
if (dir != IEEE80211_FC1_DIR_FROMDS)
goto out;
@ -313,6 +320,20 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp)
goto out;
}
}
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
if (ic->ic_flags & IEEE80211_F_WEPON) {
m = ieee80211_wep_crypt(ifp, m, 0);
if (m == NULL)
goto err;
wh = mtod(m, struct ieee80211_frame *);
} else
goto out;
}
#if NBPFILTER > 0
/* copy to listener after decrypt */
if (ic->ic_rawbpf)
bpf_mtap(ic->ic_rawbpf, m);
#endif
m = ieee80211_decap(ifp, m);
if (m == NULL)
goto err;
@ -350,10 +371,15 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp)
>> IEEE80211_FC0_SUBTYPE_SHIFT],
ether_sprintf(wh->i_addr2), rssi);
}
#if NBPFILTER > 0
if (ic->ic_rawbpf)
bpf_mtap(ic->ic_rawbpf, m);
#endif
rh = ic->ic_recv_mgmt[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT];
if (rh != NULL)
(*rh)(ic, m, rssi, rstamp);
goto out;
m_freem(m);
return;
case IEEE80211_FC0_TYPE_CTL:
default:
@ -364,8 +390,13 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp)
err:
ifp->if_ierrors++;
out:
if (m != NULL)
if (m != NULL) {
#if NBPFILTER > 0
if (ic->ic_rawbpf)
bpf_mtap(ic->ic_rawbpf, m);
#endif
m_freem(m);
}
}
int
@ -396,9 +427,8 @@ ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_bss *bs,
ieee80211_mgt_subtype_name[
(type & IEEE80211_FC0_SUBTYPE_MASK)
>> IEEE80211_FC0_SUBTYPE_SHIFT],
ether_sprintf(bs->bs_bssid));
ether_sprintf(bs->bs_macaddr));
IF_ENQUEUE(&ic->ic_mgtq, m);
ic->ic_mgt_timer = IEEE80211_TRANS_WAIT;
ifp->if_timer = 1;
(*ifp->if_start)(ifp);
return 0;
@ -440,6 +470,11 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m)
memcpy(wh->i_addr1, eh.ether_dhost, IEEE80211_ADDR_LEN);
memcpy(wh->i_addr2, eh.ether_shost, IEEE80211_ADDR_LEN);
memcpy(wh->i_addr3, ic->ic_bss.bs_bssid, IEEE80211_ADDR_LEN);
} else if (ic->ic_flags & IEEE80211_F_HOSTAP) {
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
memcpy(wh->i_addr1, eh.ether_dhost, IEEE80211_ADDR_LEN);
memcpy(wh->i_addr2, ic->ic_bss.bs_bssid, IEEE80211_ADDR_LEN);
memcpy(wh->i_addr3, eh.ether_shost, IEEE80211_ADDR_LEN);
} else {
wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
memcpy(wh->i_addr1, ic->ic_bss.bs_bssid, IEEE80211_ADDR_LEN);
@ -1056,9 +1091,9 @@ ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_bss *bs, int flags)
static int
ieee80211_send_prreq(struct ieee80211com *ic, struct ieee80211_bss *bs,
int dummy)
int type, int dummy)
{
int i;
int i, ret;
struct mbuf *m;
u_int8_t *frm;
@ -1087,19 +1122,19 @@ ieee80211_send_prreq(struct ieee80211com *ic, struct ieee80211_bss *bs,
frm += i;
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
return ieee80211_mgmt_output(&ic->ic_if, bs, m,
IEEE80211_FC0_SUBTYPE_PROBE_REQ);
ret = ieee80211_mgmt_output(&ic->ic_if, bs, m, type);
ic->ic_mgt_timer = IEEE80211_TRANS_WAIT;
return ret;
}
static int
ieee80211_send_prresp(struct ieee80211com *ic, struct ieee80211_bss *bs0,
int dummy)
int type, int dummy)
{
struct mbuf *m;
u_int8_t *frm;
struct ieee80211_bss *bs = &ic->ic_bss;
u_int16_t capinfo;
int ret;
/*
* probe response frame format
@ -1146,14 +1181,12 @@ ieee80211_send_prresp(struct ieee80211com *ic, struct ieee80211_bss *bs0,
/* TODO: check MHLEN limit */
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
ret = ieee80211_mgmt_output(&ic->ic_if, bs0, m,
IEEE80211_FC0_SUBTYPE_PROBE_RESP);
ic->ic_mgt_timer = 0; /* no state transition */
return ret;
return ieee80211_mgmt_output(&ic->ic_if, bs0, m, type);
}
static int
ieee80211_send_auth(struct ieee80211com *ic, struct ieee80211_bss *bs, int seq)
ieee80211_send_auth(struct ieee80211com *ic, struct ieee80211_bss *bs,
int type, int seq)
{
struct mbuf *m;
u_int16_t *frm;
@ -1169,16 +1202,16 @@ ieee80211_send_auth(struct ieee80211com *ic, struct ieee80211_bss *bs, int seq)
frm[0] = htole16(IEEE80211_AUTH_ALG_OPEN);
frm[1] = htole16(seq);
frm[2] = 0; /* status */
ret = ieee80211_mgmt_output(&ic->ic_if, bs, m,
IEEE80211_FC0_SUBTYPE_AUTH);
if (ic->ic_flags & IEEE80211_F_ADHOC)
ic->ic_mgt_timer = 0; /* no state transition */
ret = ieee80211_mgmt_output(&ic->ic_if, bs, m, type);
if ((ic->ic_flags & IEEE80211_F_ADHOC) != 0 &&
(ic->ic_flags & IEEE80211_F_HOSTAP) != 0)
ic->ic_mgt_timer = IEEE80211_TRANS_WAIT;
return ret;
}
static int
ieee80211_send_deauth(struct ieee80211com *ic, struct ieee80211_bss *bs,
int reason)
int type, int reason)
{
struct mbuf *m;
@ -1188,18 +1221,17 @@ ieee80211_send_deauth(struct ieee80211com *ic, struct ieee80211_bss *bs,
MH_ALIGN(m, 2);
m->m_pkthdr.len = m->m_len = 2;
*mtod(m, u_int16_t *) = htole16(reason);
return ieee80211_mgmt_output(&ic->ic_if, bs, m,
IEEE80211_FC0_SUBTYPE_DEAUTH);
return ieee80211_mgmt_output(&ic->ic_if, bs, m, type);
}
static int
ieee80211_send_asreq(struct ieee80211com *ic, struct ieee80211_bss *bs,
int reassoc)
int type, int dummy)
{
struct mbuf *m;
u_int8_t *frm, *rates;
u_int16_t capinfo;
int i;
int i, ret;
/*
* asreq frame format
@ -1228,7 +1260,7 @@ ieee80211_send_asreq(struct ieee80211com *ic, struct ieee80211_bss *bs,
*(u_int16_t *)frm = htole16(ic->ic_lintval);
frm += 2;
if (reassoc) {
if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
memcpy(frm, ic->ic_bss.bs_bssid, IEEE80211_ADDR_LEN);
frm += IEEE80211_ADDR_LEN;
}
@ -1246,14 +1278,66 @@ ieee80211_send_asreq(struct ieee80211com *ic, struct ieee80211_bss *bs,
}
*rates = frm - (rates + 1);
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
return ieee80211_mgmt_output(&ic->ic_if, bs, m,
reassoc ? IEEE80211_FC0_SUBTYPE_REASSOC_REQ :
IEEE80211_FC0_SUBTYPE_ASSOC_REQ);
ret = ieee80211_mgmt_output(&ic->ic_if, bs, m, type);
ic->ic_mgt_timer = IEEE80211_TRANS_WAIT;
return ret;
}
static int
ieee80211_send_asresp(struct ieee80211com *ic, struct ieee80211_bss *bs,
int type, int status)
{
struct mbuf *m;
u_int8_t *frm, *rates, *r;
u_int16_t capinfo;
int i;
/*
* asreq frame format
* [2] capability information
* [2] status
* [2] association ID
* [tlv] supported rates
*/
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
return ENOMEM;
m->m_data += sizeof(struct ieee80211_frame);
frm = mtod(m, u_int8_t *);
capinfo = IEEE80211_CAPINFO_ESS;
if (ic->ic_flags & IEEE80211_F_WEPON)
capinfo |= IEEE80211_CAPINFO_PRIVACY;
*(u_int16_t *)frm = htole16(capinfo);
frm += 2;
*(u_int16_t *)frm = htole16(status);
frm += 2;
if (status == IEEE80211_STATUS_SUCCESS && bs != NULL)
*(u_int16_t *)frm = htole16(bs->bs_associd);
else
*(u_int16_t *)frm = htole16(0);
frm += 2;
*frm++ = IEEE80211_ELEMID_RATES;
rates = frm++; /* update later */
if (bs != NULL)
r = bs->bs_rates;
else
r = ic->ic_bss.bs_rates;
for (i = 0; i < IEEE80211_RATE_SIZE; i++, r++) {
if (*r != 0)
*frm++ = *r;
}
*rates = frm - (rates + 1);
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
return ieee80211_mgmt_output(&ic->ic_if, bs, m, type);
}
static int
ieee80211_send_disassoc(struct ieee80211com *ic, struct ieee80211_bss *bs,
int reason)
int reason, int dummy)
{
struct mbuf *m;
@ -1507,6 +1591,24 @@ ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, int rssi,
return;
}
}
if (ic->ic_flags & IEEE80211_F_HOSTAP) {
if (ic->ic_state != IEEE80211_S_RUN)
return;
TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) {
if (memcmp(bs->bs_macaddr, wh->i_addr2,
IEEE80211_ADDR_LEN) == 0)
break;
}
if (bs == NULL) {
if ((bs = ieee80211_alloc_bss(ic, 0)) == NULL)
return;
memcpy(bs->bs_macaddr, wh->i_addr2, IEEE80211_ADDR_LEN);
memcpy(bs->bs_bssid, ic->ic_bss.bs_bssid,
IEEE80211_ADDR_LEN);
}
IEEE80211_SEND_MGMT(ic, bs, IEEE80211_FC0_SUBTYPE_AUTH, 2);
return;
}
if (ic->ic_state != IEEE80211_S_AUTH || seq != 2)
return;
if (status != 0) {
@ -1525,6 +1627,122 @@ ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, int rssi,
wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
}
static void
ieee80211_recv_asreq(struct ieee80211com *ic, struct mbuf *m0, int rssi,
u_int32_t rstamp)
{
struct ieee80211_frame *wh;
struct ieee80211_bss *bs = &ic->ic_bss;
u_int8_t *frm, *efrm, *ssid, *rates;
u_int16_t capinfo, bintval;
int reassoc, resp;
if ((ic->ic_flags & IEEE80211_F_HOSTAP) == 0 ||
(ic->ic_state != IEEE80211_S_RUN))
return;
wh = mtod(m0, struct ieee80211_frame *);
frm = (u_int8_t *)&wh[1];
efrm = mtod(m0, u_int8_t *) + m0->m_len;
if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
reassoc = 1;
resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
} else {
reassoc = 0;
resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
}
/*
* asreq frame format
* [2] capability information
* [2] listen interval
* [6*] current AP address (reassoc only)
* [tlv] ssid
* [tlv] supported rates
*/
if (frm + (reassoc ? 10 : 4) > efrm) {
DPRINTF(("ieee80211_recv_asreq: too short from %s\n",
ether_sprintf(wh->i_addr2)));
return;
}
if (memcmp(wh->i_addr3, ic->ic_bss.bs_bssid, IEEE80211_ADDR_LEN) != 0) {
DPRINTF(("ieee80211_recv_asreq: ignore other bss from %s\n",
ether_sprintf(wh->i_addr2)));
return;
}
capinfo = le16toh(*(u_int16_t *)frm); frm += 2;
bintval = le16toh(*(u_int16_t *)frm); frm += 2;
if (reassoc)
frm += 6; /* ignore current AP info */
ssid = rates = NULL;
while (frm < efrm) {
switch (*frm) {
case IEEE80211_ELEMID_SSID:
ssid = frm;
break;
case IEEE80211_ELEMID_RATES:
rates = frm;
break;
}
frm += frm[1] + 2;
}
if (ssid == NULL || rates == NULL) {
DPRINTF(("ieee80211_recv_asreq: ssid=%p, rates=%p\n",
ssid, rates));
return;
}
if (ssid[1] > IEEE80211_NWID_LEN) {
DPRINTF(("ieee80211_recv_asreq: bad ssid len %d from %s\n",
ssid[1], ether_sprintf(wh->i_addr2)));
return;
}
if (ssid[1] != ic->ic_bss.bs_esslen ||
memcmp(ssid + 2, ic->ic_bss.bs_essid, ssid[1]) != 0) {
#ifdef IEEE80211_DEBUG
if (ieee80211_debug) {
printf("ieee80211_recv_asreq: ssid unmatch ");
ieee80211_print_essid(ssid + 2, ssid[1]);
printf(" from %s\n", ether_sprintf(wh->i_addr2));
}
#endif
return;
}
TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) {
if (memcmp(bs->bs_macaddr, wh->i_addr2,
IEEE80211_ADDR_LEN) == 0)
break;
}
if (bs == NULL)
return;
bs->bs_associd = 0;
if ((capinfo & IEEE80211_CAPINFO_ESS) == 0 ||
(capinfo & IEEE80211_CAPINFO_PRIVACY) !=
((ic->ic_flags & IEEE80211_F_WEPON) ?
IEEE80211_CAPINFO_PRIVACY : 0)) {
IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_CAPINFO);
return;
}
memset(bs->bs_rates, 0, IEEE80211_RATE_SIZE);
bs->bs_nrate = rates[1];
memcpy(bs->bs_rates, rates + 2, bs->bs_nrate);
ieee80211_fix_rate(ic, bs, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
if (bs->bs_nrate == 0) {
IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_BASIC_RATE);
return;
}
bs->bs_rssi = rssi;
bs->bs_rstamp = rstamp;
bs->bs_intval = bintval;
bs->bs_capinfo = capinfo;
bs->bs_chan = ic->ic_bss.bs_chan;
bs->bs_fhdwell = ic->ic_bss.bs_fhdwell;
bs->bs_fhindex = ic->ic_bss.bs_fhindex;
bs->bs_associd = 0xc000 | ic->ic_bss.bs_associd++;
IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_SUCCESS);
}
static void
ieee80211_recv_asresp(struct ieee80211com *ic, struct mbuf *m0, int rssi,
u_int32_t rstamp)
@ -1637,13 +1855,27 @@ ieee80211_new_state(struct ifnet *ifp, enum ieee80211_state nstate, int mgt)
case IEEE80211_S_INIT:
break;
case IEEE80211_S_RUN:
if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0)
if (ic->ic_flags & IEEE80211_F_HOSTAP) {
TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) {
if (bs->bs_associd == 0)
continue;
IEEE80211_SEND_MGMT(ic, bs,
IEEE80211_FC0_SUBTYPE_DISASSOC,
IEEE80211_REASON_ASSOC_LEAVE);
}
} else if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0)
IEEE80211_SEND_MGMT(ic, bs,
IEEE80211_FC0_SUBTYPE_DISASSOC,
IEEE80211_REASON_ASSOC_LEAVE);
/* FALLTHRU */
case IEEE80211_S_ASSOC:
if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0)
if (ic->ic_flags & IEEE80211_F_HOSTAP) {
TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) {
IEEE80211_SEND_MGMT(ic, bs,
IEEE80211_FC0_SUBTYPE_DEAUTH,
IEEE80211_REASON_AUTH_LEAVE);
}
} else if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0)
IEEE80211_SEND_MGMT(ic, bs,
IEEE80211_FC0_SUBTYPE_DEAUTH,
IEEE80211_REASON_AUTH_LEAVE);
@ -2014,6 +2246,86 @@ ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len)
return crc;
}
/*
* convert IEEE80211 rate value to ifmedia subtype.
* ieee80211 rate is in unit of 0.5Mbps.
* phytype is IEEE80211_F_FH or IEEE80211_F_DS.
*/
int
ieee80211_rate2media(int rate, int phytype)
{
int mword;
mword = 0;
switch (phytype) {
case IEEE80211_F_FH:
switch (rate & IEEE80211_RATE_VAL) {
case 2:
mword = IFM_IEEE80211_FH1;
break;
case 4:
mword = IFM_IEEE80211_FH2;
break;
}
break;
case IEEE80211_F_DS:
switch (rate & IEEE80211_RATE_VAL) {
case 2:
mword = IFM_IEEE80211_DS1;
break;
case 4:
mword = IFM_IEEE80211_DS2;
break;
case 11:
mword = IFM_IEEE80211_DS5;
break;
case 22:
mword = IFM_IEEE80211_DS11;
break;
}
}
return mword;
}
int
ieee80211_media2rate(int mword, int phytype)
{
int rate;
rate = 0;
switch (phytype) {
case IEEE80211_F_FH:
switch (IFM_SUBTYPE(mword)) {
case IFM_IEEE80211_FH1:
rate = 2;
break;
case IFM_IEEE80211_FH2:
rate = 4;
break;
}
break;
case IEEE80211_F_DS:
switch (IFM_SUBTYPE(mword)) {
case IFM_IEEE80211_DS1:
rate = 2;
break;
case IFM_IEEE80211_DS2:
rate = 4;
break;
case IFM_IEEE80211_DS5:
rate = 11;
break;
case IFM_IEEE80211_DS11:
rate = 22;
break;
}
}
return rate;
}
/*
* XXX
* Wireless LAN specific configuration interface, which is compatible