Several fixes hostap for awi driver:

- aging ang clear inactivity stations
- DTIM field in beacon/probe response.
- ignore IFF_PROMISC for hostap mode, since 802.11 has 3 address fields,
  so that promisc mode is not required for AP function.
This commit is contained in:
onoe 2002-09-03 14:54:00 +00:00
parent c0a8cbae7c
commit 26ebf5f371
4 changed files with 280 additions and 58 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: awi.c,v 1.45 2002/09/02 13:37:35 onoe Exp $ */ /* $NetBSD: awi.c,v 1.46 2002/09/03 14:54:00 onoe Exp $ */
/*- /*-
* Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc. * Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc.
@ -85,7 +85,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.45 2002/09/02 13:37:35 onoe Exp $"); __KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.46 2002/09/03 14:54:00 onoe Exp $");
#include "opt_inet.h" #include "opt_inet.h"
#include "bpfilter.h" #include "bpfilter.h"
@ -491,9 +491,9 @@ awi_init(struct ifnet *ifp)
(ic->ic_flags & IEEE80211_F_HOSTAP) ? 1 : 0; (ic->ic_flags & IEEE80211_F_HOSTAP) ? 1 : 0;
memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE); 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[0] = IEEE80211_ELEMID_SSID;
sc->sc_mib_mac.aDesired_ESS_ID[1] = sc->sc_ic.ic_des_esslen; sc->sc_mib_mac.aDesired_ESS_ID[1] = ic->ic_des_esslen;
memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], sc->sc_ic.ic_des_essid, memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], ic->ic_des_essid,
sc->sc_ic.ic_des_esslen); ic->ic_des_esslen);
if ((error = awi_mode_init(sc)) != 0) { if ((error = awi_mode_init(sc)) != 0) {
DPRINTF(("awi_init: awi_mode_init failed %d\n", error)); DPRINTF(("awi_init: awi_mode_init failed %d\n", error));
@ -533,8 +533,8 @@ awi_init(struct ifnet *ifp)
ifp->if_flags |= IFF_RUNNING; ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE; ifp->if_flags &= ~IFF_OACTIVE;
if (((sc->sc_ic.ic_flags & IEEE80211_F_ADHOC) && sc->sc_no_bssid) || if (((ic->ic_flags & IEEE80211_F_ADHOC) && sc->sc_no_bssid) ||
(sc->sc_ic.ic_flags & IEEE80211_F_HOSTAP)) { (ic->ic_flags & IEEE80211_F_HOSTAP)) {
bs->bs_chan = ic->ic_ibss_chan; bs->bs_chan = ic->ic_ibss_chan;
bs->bs_intval = ic->ic_lintval; bs->bs_intval = ic->ic_lintval;
bs->bs_rssi = 0; bs->bs_rssi = 0;
@ -547,7 +547,7 @@ awi_init(struct ifnet *ifp)
ic->ic_sup_rates[i]; ic->ic_sup_rates[i];
} }
memcpy(bs->bs_macaddr, ic->ic_myaddr, IEEE80211_ADDR_LEN); memcpy(bs->bs_macaddr, ic->ic_myaddr, IEEE80211_ADDR_LEN);
if (sc->sc_ic.ic_flags & IEEE80211_F_HOSTAP) { if (ic->ic_flags & IEEE80211_F_HOSTAP) {
memcpy(bs->bs_bssid, ic->ic_myaddr, IEEE80211_ADDR_LEN); memcpy(bs->bs_bssid, ic->ic_myaddr, IEEE80211_ADDR_LEN);
bs->bs_esslen = ic->ic_des_esslen; bs->bs_esslen = ic->ic_des_esslen;
memcpy(bs->bs_essid, ic->ic_des_essid, bs->bs_esslen); memcpy(bs->bs_essid, ic->ic_des_essid, bs->bs_esslen);
@ -975,7 +975,8 @@ awi_mode_init(struct awi_softc *sc)
/* reinitialize muticast filter */ /* reinitialize muticast filter */
n = 0; n = 0;
sc->sc_mib_local.Accept_All_Multicast_Dis = 0; sc->sc_mib_local.Accept_All_Multicast_Dis = 0;
if (ifp->if_flags & IFF_PROMISC) { if ((sc->sc_ic.ic_flags & IEEE80211_F_HOSTAP) == 0 &&
(ifp->if_flags & IFF_PROMISC)) {
sc->sc_mib_mac.aPromiscuous_Enable = 1; sc->sc_mib_mac.aPromiscuous_Enable = 1;
goto set_mib; goto set_mib;
} }
@ -1264,8 +1265,14 @@ awi_hw_init(struct awi_softc *sc)
printf(" (lost interrupt)\n"); printf(" (lost interrupt)\n");
else else
printf(" (command timeout)\n"); printf(" (command timeout)\n");
return error;
} }
return error;
/* Initialize VBM */
awi_write_1(sc, AWI_VBM_OFFSET, 0);
awi_write_1(sc, AWI_VBM_LENGTH, 1);
awi_write_1(sc, AWI_VBM_BITMAP, 0);
return 0;
} }
/* /*
@ -1324,11 +1331,19 @@ awi_init_mibs(struct awi_softc *sc)
} }
sc->sc_cur_chan = cs->cs_def; sc->sc_cur_chan = cs->cs_def;
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_local.Fragmentation_Dis = 1; sc->sc_mib_local.Fragmentation_Dis = 1;
sc->sc_mib_local.Accept_All_Multicast_Dis = 1; sc->sc_mib_local.Add_PLCP_Dis = 0;
sc->sc_mib_local.MAC_Hdr_Prsv = 1;
sc->sc_mib_local.Rx_Mgmt_Que_En = 0;
sc->sc_mib_local.Re_Assembly_Dis = 1;
sc->sc_mib_local.Strip_PLCP_Dis = 0;
sc->sc_mib_local.Power_Saving_Mode_Dis = 1; sc->sc_mib_local.Power_Saving_Mode_Dis = 1;
sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
sc->sc_mib_local.Check_Seq_Cntl_Dis = 1;
sc->sc_mib_local.Flush_CFP_Queue_On_CF_End = 0;
sc->sc_mib_local.Network_Mode = 1;
sc->sc_mib_local.PWD_Lvl = 0;
sc->sc_mib_local.CFP_Mode = 0;
/* allocate buffers */ /* allocate buffers */
sc->sc_txbase = AWI_BUFFERS; sc->sc_txbase = AWI_BUFFERS;
@ -1341,8 +1356,15 @@ awi_init_mibs(struct awi_softc *sc)
LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Offset, sc->sc_txend); LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Offset, sc->sc_txend);
LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Size, LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Size,
AWI_BUFFERS_END - sc->sc_txend); AWI_BUFFERS_END - sc->sc_txend);
sc->sc_mib_local.Network_Mode = 1;
sc->sc_mib_local.Acting_as_AP = 0; sc->sc_mib_local.Acting_as_AP = 0;
sc->sc_mib_local.Fill_CFP = 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_mgt.aPower_Mgt_Mode = 0;
sc->sc_mib_mgt.aDTIM_Period = 1;
LE_WRITE_2(&sc->sc_mib_mgt.aATIM_Window, 0);
return 0; return 0;
} }

View File

@ -1,4 +1,4 @@
/* $NetBSD: awireg.h,v 1.6 2002/08/05 06:55:07 onoe Exp $ */ /* $NetBSD: awireg.h,v 1.7 2002/09/03 14:54:01 onoe Exp $ */
/*- /*-
* Copyright (c) 1999 The NetBSD Foundation, Inc. * Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -258,7 +258,9 @@
#define AWI_DRV_RXLED 0x40 #define AWI_DRV_RXLED 0x40
#define AWI_DRV_TXLED 0x80 #define AWI_DRV_TXLED 0x80
#define AWI_VBM 0x500 /* Virtual Bit Map */ #define AWI_VBM_OFFSET 0x500 /* Virtual Bit Map */
#define AWI_VBM_LENGTH 0x501
#define AWI_VBM_BITMAP 0x502
#define AWI_BUFFERS 0x600 /* Buffers */ #define AWI_BUFFERS 0x600 /* Buffers */
#define AWI_BUFFERS_END 0x6000 #define AWI_BUFFERS_END 0x6000

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_ieee80211.h,v 1.16 2002/09/02 13:37:35 onoe Exp $ */ /* $NetBSD: if_ieee80211.h,v 1.17 2002/09/03 14:54:00 onoe Exp $ */
/*- /*-
* Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
@ -334,6 +334,8 @@ struct ieee80211_auth {
#define IEEE80211_ASCAN_WAIT 2 /* active scan wait */ #define IEEE80211_ASCAN_WAIT 2 /* active scan wait */
#define IEEE80211_PSCAN_WAIT 5 /* passive scan wait */ #define IEEE80211_PSCAN_WAIT 5 /* passive scan wait */
#define IEEE80211_TRANS_WAIT 5 /* transition wait */ #define IEEE80211_TRANS_WAIT 5 /* transition wait */
#define IEEE80211_INACT_WAIT 5 /* inactivity timer interval */
#define IEEE80211_INACT_MAX (300/IEEE80211_INACT_WAIT)
/* /*
* Structure for IEEE 802.11 drivers. * Structure for IEEE 802.11 drivers.
@ -382,6 +384,7 @@ struct ieee80211_bss {
u_int16_t bs_txseq; /* seq to be transmitted */ u_int16_t bs_txseq; /* seq to be transmitted */
u_int16_t bs_rxseq; /* seq previous received */ u_int16_t bs_rxseq; /* seq previous received */
int bs_fails; /* failure count to associate */ int bs_fails; /* failure count to associate */
int bs_inact; /* inactivity mark count */
int bs_txrate; /* index to bs_rates[] */ int bs_txrate; /* index to bs_rates[] */
void *bs_private; /* driver private */ void *bs_private; /* driver private */
}; };
@ -421,6 +424,7 @@ struct ieee80211com {
u_int16_t ic_lintval; /* listen interval */ u_int16_t ic_lintval; /* listen interval */
int ic_mgt_timer; /* mgmt timeout */ int ic_mgt_timer; /* mgmt timeout */
int ic_scan_timer; /* scant wait */ int ic_scan_timer; /* scant wait */
int ic_inact_timer; /* inactivity timer wait */
int ic_des_esslen; int ic_des_esslen;
u_int8_t ic_des_essid[IEEE80211_NWID_LEN]; u_int8_t ic_des_essid[IEEE80211_NWID_LEN];
struct ieee80211_wepkey ic_nw_keys[IEEE80211_WEP_NKID]; struct ieee80211_wepkey ic_nw_keys[IEEE80211_WEP_NKID];

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_ieee80211subr.c,v 1.11 2002/09/02 13:37:35 onoe Exp $ */ /* $NetBSD: if_ieee80211subr.c,v 1.12 2002/09/03 14:54:00 onoe Exp $ */
/*- /*-
* Copyright (c) 2001 The NetBSD Foundation, Inc. * Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -41,7 +41,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_ieee80211subr.c,v 1.11 2002/09/02 13:37:35 onoe Exp $"); __KERNEL_RCSID(0, "$NetBSD: if_ieee80211subr.c,v 1.12 2002/09/03 14:54:00 onoe Exp $");
#include "opt_inet.h" #include "opt_inet.h"
#include "bpfilter.h" #include "bpfilter.h"
@ -294,6 +294,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp)
/* duplicate, silently discarded */ /* duplicate, silently discarded */
goto out; goto out;
} }
bs->bs_inact = 0;
} }
switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
@ -362,9 +363,26 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp)
} }
if (ifp->if_flags & IFF_DEBUG) { if (ifp->if_flags & IFF_DEBUG) {
if (!(ic->ic_flags & IEEE80211_F_ADHOC) || /* avoid to print too many frames */
ic->ic_state == IEEE80211_S_SCAN || int doprint = 0;
subtype != IEEE80211_FC0_SUBTYPE_BEACON)
switch (subtype) {
case IEEE80211_FC0_SUBTYPE_BEACON:
if (ic->ic_state == IEEE80211_S_SCAN)
doprint = 1;
break;
case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
if (ic->ic_flags & IEEE80211_F_ADHOC)
doprint = 1;
break;
default:
doprint = 1;
break;
}
#ifdef IEEE80211_DEBUG
doprint += ieee80211_debug;
#endif
if (doprint)
printf("%s: received %s from %s rssi %d\n", printf("%s: received %s from %s rssi %d\n",
ifp->if_xname, ifp->if_xname,
ieee80211_mgt_subtype_name[subtype ieee80211_mgt_subtype_name[subtype
@ -408,6 +426,7 @@ ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_bss *bs,
if (bs == NULL) if (bs == NULL)
bs = &ic->ic_bss; bs = &ic->ic_bss;
bs->bs_inact = 0;
M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
if (m == NULL) if (m == NULL)
return ENOMEM; return ENOMEM;
@ -422,12 +441,17 @@ ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_bss *bs,
memcpy(wh->i_addr2, ic->ic_myaddr, IEEE80211_ADDR_LEN); memcpy(wh->i_addr2, ic->ic_myaddr, IEEE80211_ADDR_LEN);
memcpy(wh->i_addr3, bs->bs_bssid, IEEE80211_ADDR_LEN); memcpy(wh->i_addr3, bs->bs_bssid, IEEE80211_ADDR_LEN);
if (ifp->if_flags & IFF_DEBUG) if (ifp->if_flags & IFF_DEBUG) {
printf("%s: sending %s to %s\n", ifp->if_xname, /* avoid to print too many frames */
ieee80211_mgt_subtype_name[ if ((ic->ic_flags & IEEE80211_F_ADHOC) ||
(type & IEEE80211_FC0_SUBTYPE_MASK) (type & IEEE80211_FC0_SUBTYPE_MASK) !=
>> IEEE80211_FC0_SUBTYPE_SHIFT], IEEE80211_FC0_SUBTYPE_PROBE_RESP)
ether_sprintf(bs->bs_macaddr)); printf("%s: sending %s to %s\n", ifp->if_xname,
ieee80211_mgt_subtype_name[
(type & IEEE80211_FC0_SUBTYPE_MASK)
>> IEEE80211_FC0_SUBTYPE_SHIFT],
ether_sprintf(bs->bs_macaddr));
}
IF_ENQUEUE(&ic->ic_mgtq, m); IF_ENQUEUE(&ic->ic_mgtq, m);
ifp->if_timer = 1; ifp->if_timer = 1;
(*ifp->if_start)(ifp); (*ifp->if_start)(ifp);
@ -441,6 +465,7 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m)
struct ether_header eh; struct ether_header eh;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
struct llc *llc; struct llc *llc;
struct ieee80211_bss *bs;
if (m->m_len < sizeof(struct ether_header)) { if (m->m_len < sizeof(struct ether_header)) {
m = m_pullup(m, sizeof(struct ether_header)); m = m_pullup(m, sizeof(struct ether_header));
@ -448,6 +473,25 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m)
return NULL; return NULL;
} }
memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header)); memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header));
if ((eh.ether_dhost[0] & 0x01) == 0 &&
((ic->ic_flags & IEEE80211_F_ADHOC) ||
(ic->ic_flags & IEEE80211_F_HOSTAP))) {
TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) {
if (memcmp(bs->bs_macaddr, eh.ether_dhost,
IEEE80211_ADDR_LEN) == 0)
break;
}
if (bs == NULL ||
((ic->ic_flags & IEEE80211_F_HOSTAP) &&
bs->bs_associd == 0)) {
m_freem(m);
return NULL;
}
} else
bs = &ic->ic_bss;
bs->bs_inact = 0;
m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
llc = mtod(m, struct llc *); llc = mtod(m, struct llc *);
llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
@ -463,21 +507,21 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m)
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
*(u_int16_t *)wh->i_dur = 0; *(u_int16_t *)wh->i_dur = 0;
*(u_int16_t *)wh->i_seq = *(u_int16_t *)wh->i_seq =
htole16(ic->ic_bss.bs_txseq << IEEE80211_SEQ_SEQ_SHIFT); htole16(bs->bs_txseq << IEEE80211_SEQ_SEQ_SHIFT);
ic->ic_bss.bs_txseq++; bs->bs_txseq++;
if (ic->ic_flags & IEEE80211_F_ADHOC) { if (ic->ic_flags & IEEE80211_F_ADHOC) {
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
memcpy(wh->i_addr1, eh.ether_dhost, IEEE80211_ADDR_LEN); memcpy(wh->i_addr1, eh.ether_dhost, IEEE80211_ADDR_LEN);
memcpy(wh->i_addr2, eh.ether_shost, 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); memcpy(wh->i_addr3, bs->bs_bssid, IEEE80211_ADDR_LEN);
} else if (ic->ic_flags & IEEE80211_F_HOSTAP) { } else if (ic->ic_flags & IEEE80211_F_HOSTAP) {
wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
memcpy(wh->i_addr1, eh.ether_dhost, IEEE80211_ADDR_LEN); 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_addr2, bs->bs_bssid, IEEE80211_ADDR_LEN);
memcpy(wh->i_addr3, eh.ether_shost, IEEE80211_ADDR_LEN); memcpy(wh->i_addr3, eh.ether_shost, IEEE80211_ADDR_LEN);
} else { } else {
wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
memcpy(wh->i_addr1, ic->ic_bss.bs_bssid, IEEE80211_ADDR_LEN); memcpy(wh->i_addr1, bs->bs_bssid, IEEE80211_ADDR_LEN);
memcpy(wh->i_addr2, eh.ether_shost, IEEE80211_ADDR_LEN); memcpy(wh->i_addr2, eh.ether_shost, IEEE80211_ADDR_LEN);
memcpy(wh->i_addr3, eh.ether_dhost, IEEE80211_ADDR_LEN); memcpy(wh->i_addr3, eh.ether_dhost, IEEE80211_ADDR_LEN);
} }
@ -817,6 +861,7 @@ void
ieee80211_watchdog(struct ifnet *ifp) ieee80211_watchdog(struct ifnet *ifp)
{ {
struct ieee80211com *ic = (void *)ifp; struct ieee80211com *ic = (void *)ifp;
struct ieee80211_bss *bs, *nextbs;
if (ic->ic_scan_timer) { if (ic->ic_scan_timer) {
if (--ic->ic_scan_timer == 0) { if (--ic->ic_scan_timer == 0) {
@ -828,7 +873,33 @@ ieee80211_watchdog(struct ifnet *ifp)
if (--ic->ic_mgt_timer == 0) if (--ic->ic_mgt_timer == 0)
ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1); ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1);
} }
if (ic->ic_scan_timer != 0 || ic->ic_mgt_timer != 0) if (ic->ic_inact_timer) {
if (--ic->ic_inact_timer == 0) {
for (bs = TAILQ_FIRST(&ic->ic_scan); bs != NULL; ) {
if (++bs->bs_inact <= IEEE80211_INACT_MAX) {
bs = TAILQ_NEXT(bs, bs_list);
continue;
}
if (ifp->if_flags & IFF_DEBUG)
printf("%s: station %s deauthenticate"
" (reason %d)\n",
ifp->if_xname,
ether_sprintf(bs->bs_macaddr),
IEEE80211_REASON_AUTH_EXPIRE);
nextbs = TAILQ_NEXT(bs, bs_list);
IEEE80211_SEND_MGMT(ic, bs,
IEEE80211_FC0_SUBTYPE_DEAUTH,
IEEE80211_REASON_AUTH_EXPIRE);
TAILQ_REMOVE(&ic->ic_scan, bs, bs_list);
free(bs, M_DEVBUF);
bs = nextbs;
}
if (!TAILQ_EMPTY(&ic->ic_scan))
ic->ic_inact_timer = IEEE80211_INACT_WAIT;
}
}
if (ic->ic_scan_timer != 0 || ic->ic_mgt_timer != 0 ||
ic->ic_inact_timer != 0)
ifp->if_timer = 1; ifp->if_timer = 1;
} }
@ -1015,6 +1086,9 @@ ieee80211_alloc_bss(struct ieee80211com *ic, int copy)
memset(bs->bs_private, 0, ic->ic_bss_privlen); memset(bs->bs_private, 0, ic->ic_bss_privlen);
} }
TAILQ_INSERT_TAIL(&ic->ic_scan, bs, bs_list); TAILQ_INSERT_TAIL(&ic->ic_scan, bs, bs_list);
if ((ic->ic_flags & IEEE80211_F_HOSTAP) ||
(ic->ic_flags & IEEE80211_F_ADHOC))
ic->ic_inact_timer = IEEE80211_INACT_WAIT;
return bs; return bs;
} }
@ -1028,6 +1102,7 @@ ieee80211_free_scan(struct ifnet *ifp)
TAILQ_REMOVE(&ic->ic_scan, bs, bs_list); TAILQ_REMOVE(&ic->ic_scan, bs, bs_list);
free(bs, M_DEVBUF); free(bs, M_DEVBUF);
} }
ic->ic_inact_timer = 0;
} }
int int
@ -1177,6 +1252,12 @@ ieee80211_send_prresp(struct ieee80211com *ic, struct ieee80211_bss *bs0,
*frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */
} else { } else {
/* TODO: TIM */ /* TODO: TIM */
*frm++ = IEEE80211_ELEMID_TIM;
*frm++ = 4; /* length */
*frm++ = 0; /* DTIM count */
*frm++ = 1; /* DTIM period */
*frm++ = 0; /* bitmap control */
*frm++ = 0; /* Partial Virtual Bitmap (variable length) */
} }
/* TODO: check MHLEN limit */ /* TODO: check MHLEN limit */
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
@ -1213,8 +1294,12 @@ static int
ieee80211_send_deauth(struct ieee80211com *ic, struct ieee80211_bss *bs, ieee80211_send_deauth(struct ieee80211com *ic, struct ieee80211_bss *bs,
int type, int reason) int type, int reason)
{ {
struct ifnet *ifp = &ic->ic_if;
struct mbuf *m; struct mbuf *m;
if (ifp->if_flags & IFF_DEBUG)
printf("%s: station %s deauthenticate (reason %d)\n",
ifp->if_xname, ether_sprintf(bs->bs_macaddr), reason);
MGETHDR(m, M_DONTWAIT, MT_DATA); MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) if (m == NULL)
return ENOMEM; return ENOMEM;
@ -1337,10 +1422,14 @@ ieee80211_send_asresp(struct ieee80211com *ic, struct ieee80211_bss *bs,
static int static int
ieee80211_send_disassoc(struct ieee80211com *ic, struct ieee80211_bss *bs, ieee80211_send_disassoc(struct ieee80211com *ic, struct ieee80211_bss *bs,
int reason, int dummy) int type, int reason)
{ {
struct ifnet *ifp = &ic->ic_if;
struct mbuf *m; struct mbuf *m;
if (ifp->if_flags & IFF_DEBUG)
printf("%s: station %s disassociate (reason %d)\n",
ifp->if_xname, ether_sprintf(bs->bs_macaddr), reason);
MGETHDR(m, M_DONTWAIT, MT_DATA); MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) if (m == NULL)
return ENOMEM; return ENOMEM;
@ -1479,9 +1568,12 @@ ieee80211_recv_prreq(struct ieee80211com *ic, struct mbuf *m0, int rssi,
struct ieee80211_bss *bs; struct ieee80211_bss *bs;
u_int8_t *frm, *efrm, *ssid, *rates; u_int8_t *frm, *efrm, *ssid, *rates;
u_int8_t rate; u_int8_t rate;
int allocbs;
if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0 || if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0 &&
(ic->ic_state != IEEE80211_S_RUN)) (ic->ic_flags & IEEE80211_F_HOSTAP) == 0)
return;
if (ic->ic_state != IEEE80211_S_RUN)
return; return;
wh = mtod(m0, struct ieee80211_frame *); wh = mtod(m0, struct ieee80211_frame *);
@ -1533,7 +1625,9 @@ ieee80211_recv_prreq(struct ieee80211com *ic, struct mbuf *m0, int rssi,
DPRINTF(("ieee80211_recv_prreq: new req from %s\n", DPRINTF(("ieee80211_recv_prreq: new req from %s\n",
ether_sprintf(wh->i_addr2))); ether_sprintf(wh->i_addr2)));
memcpy(bs->bs_macaddr, wh->i_addr2, IEEE80211_ADDR_LEN); memcpy(bs->bs_macaddr, wh->i_addr2, IEEE80211_ADDR_LEN);
} allocbs = 1;
} else
allocbs = 0;
memset(bs->bs_rates, 0, IEEE80211_RATE_SIZE); memset(bs->bs_rates, 0, IEEE80211_RATE_SIZE);
bs->bs_nrate = rates[1]; bs->bs_nrate = rates[1];
memcpy(bs->bs_rates, rates + 2, bs->bs_nrate); memcpy(bs->bs_rates, rates + 2, bs->bs_nrate);
@ -1544,19 +1638,28 @@ ieee80211_recv_prreq(struct ieee80211com *ic, struct mbuf *m0, int rssi,
if (rate & IEEE80211_RATE_BASIC) { if (rate & IEEE80211_RATE_BASIC) {
DPRINTF(("ieee80211_recv_prreq: rate negotiation failed: %s\n", DPRINTF(("ieee80211_recv_prreq: rate negotiation failed: %s\n",
ether_sprintf(wh->i_addr2))); ether_sprintf(wh->i_addr2)));
return; } else {
IEEE80211_SEND_MGMT(ic, bs, IEEE80211_FC0_SUBTYPE_PROBE_RESP,
0);
}
if (allocbs && (ic->ic_flags & IEEE80211_F_HOSTAP)) {
TAILQ_REMOVE(&ic->ic_scan, bs, bs_list);
free(bs, M_DEVBUF);
if (TAILQ_EMPTY(&ic->ic_scan))
ic->ic_inact_timer = 0;
} }
IEEE80211_SEND_MGMT(ic, bs, IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
} }
static void static void
ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, int rssi, ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, int rssi,
u_int32_t rstamp) u_int32_t rstamp)
{ {
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
struct ieee80211_bss *bs; struct ieee80211_bss *bs;
u_int8_t *frm, *efrm; u_int8_t *frm, *efrm;
u_int16_t algo, seq, status; u_int16_t algo, seq, status;
int allocbs;
wh = mtod(m0, struct ieee80211_frame *); wh = mtod(m0, struct ieee80211_frame *);
frm = (u_int8_t *)&wh[1]; frm = (u_int8_t *)&wh[1];
@ -1583,17 +1686,16 @@ ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, int rssi,
return; return;
} }
if (ic->ic_flags & IEEE80211_F_ADHOC) { if (ic->ic_flags & IEEE80211_F_ADHOC) {
if (ic->ic_state != IEEE80211_S_RUN) if (ic->ic_state != IEEE80211_S_RUN || seq != 1)
return; return;
if (seq == 1) { ieee80211_new_state(&ic->ic_if, IEEE80211_S_AUTH,
ieee80211_new_state(&ic->ic_if, IEEE80211_S_AUTH, wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); return;
return;
}
} }
if (ic->ic_flags & IEEE80211_F_HOSTAP) { if (ic->ic_flags & IEEE80211_F_HOSTAP) {
if (ic->ic_state != IEEE80211_S_RUN) if (ic->ic_state != IEEE80211_S_RUN || seq != 1)
return; return;
allocbs = 0;
TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) { TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) {
if (memcmp(bs->bs_macaddr, wh->i_addr2, if (memcmp(bs->bs_macaddr, wh->i_addr2,
IEEE80211_ADDR_LEN) == 0) IEEE80211_ADDR_LEN) == 0)
@ -1605,8 +1707,14 @@ ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, int rssi,
memcpy(bs->bs_macaddr, wh->i_addr2, IEEE80211_ADDR_LEN); memcpy(bs->bs_macaddr, wh->i_addr2, IEEE80211_ADDR_LEN);
memcpy(bs->bs_bssid, ic->ic_bss.bs_bssid, memcpy(bs->bs_bssid, ic->ic_bss.bs_bssid,
IEEE80211_ADDR_LEN); IEEE80211_ADDR_LEN);
allocbs = 1;
} }
IEEE80211_SEND_MGMT(ic, bs, IEEE80211_FC0_SUBTYPE_AUTH, 2); IEEE80211_SEND_MGMT(ic, bs, IEEE80211_FC0_SUBTYPE_AUTH, 2);
if (ifp->if_flags & IFF_DEBUG)
printf("%s: station %s %s authenticated\n",
ifp->if_xname,
(allocbs ? "newly" : "already"),
ether_sprintf(bs->bs_macaddr));
return; return;
} }
if (ic->ic_state != IEEE80211_S_AUTH || seq != 2) if (ic->ic_state != IEEE80211_S_AUTH || seq != 2)
@ -1631,11 +1739,12 @@ static void
ieee80211_recv_asreq(struct ieee80211com *ic, struct mbuf *m0, int rssi, ieee80211_recv_asreq(struct ieee80211com *ic, struct mbuf *m0, int rssi,
u_int32_t rstamp) u_int32_t rstamp)
{ {
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
struct ieee80211_bss *bs = &ic->ic_bss; struct ieee80211_bss *bs = &ic->ic_bss;
u_int8_t *frm, *efrm, *ssid, *rates; u_int8_t *frm, *efrm, *ssid, *rates;
u_int16_t capinfo, bintval; u_int16_t capinfo, bintval;
int reassoc, resp; int reassoc, resp, newassoc;
if ((ic->ic_flags & IEEE80211_F_HOSTAP) == 0 || if ((ic->ic_flags & IEEE80211_F_HOSTAP) == 0 ||
(ic->ic_state != IEEE80211_S_RUN)) (ic->ic_state != IEEE80211_S_RUN))
@ -1715,11 +1824,11 @@ ieee80211_recv_asreq(struct ieee80211com *ic, struct mbuf *m0, int rssi,
} }
if (bs == NULL) if (bs == NULL)
return; return;
bs->bs_associd = 0;
if ((capinfo & IEEE80211_CAPINFO_ESS) == 0 || if ((capinfo & IEEE80211_CAPINFO_ESS) == 0 ||
(capinfo & IEEE80211_CAPINFO_PRIVACY) != (capinfo & IEEE80211_CAPINFO_PRIVACY) !=
((ic->ic_flags & IEEE80211_F_WEPON) ? ((ic->ic_flags & IEEE80211_F_WEPON) ?
IEEE80211_CAPINFO_PRIVACY : 0)) { IEEE80211_CAPINFO_PRIVACY : 0)) {
bs->bs_associd = 0;
IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_CAPINFO); IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_CAPINFO);
return; return;
} }
@ -1729,6 +1838,7 @@ ieee80211_recv_asreq(struct ieee80211com *ic, struct mbuf *m0, int rssi,
ieee80211_fix_rate(ic, bs, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | ieee80211_fix_rate(ic, bs, IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
IEEE80211_F_DONEGO | IEEE80211_F_DODEL); IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
if (bs->bs_nrate == 0) { if (bs->bs_nrate == 0) {
bs->bs_associd = 0;
IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_BASIC_RATE); IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_BASIC_RATE);
return; return;
} }
@ -1739,8 +1849,16 @@ ieee80211_recv_asreq(struct ieee80211com *ic, struct mbuf *m0, int rssi,
bs->bs_chan = ic->ic_bss.bs_chan; bs->bs_chan = ic->ic_bss.bs_chan;
bs->bs_fhdwell = ic->ic_bss.bs_fhdwell; bs->bs_fhdwell = ic->ic_bss.bs_fhdwell;
bs->bs_fhindex = ic->ic_bss.bs_fhindex; bs->bs_fhindex = ic->ic_bss.bs_fhindex;
bs->bs_associd = 0xc000 | ic->ic_bss.bs_associd++; if (bs->bs_associd == 0) {
bs->bs_associd = 0xc000 | ic->ic_bss.bs_associd++;
newassoc = 1;
} else
newassoc = 0;
IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_SUCCESS); IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_SUCCESS);
if (ifp->if_flags & IFF_DEBUG)
printf("%s: station %s %s associated\n",
ifp->if_xname, (newassoc ? "newly" : "already"),
ether_sprintf(bs->bs_macaddr));
} }
static void static void
@ -1753,6 +1871,11 @@ ieee80211_recv_asresp(struct ieee80211com *ic, struct mbuf *m0, int rssi,
u_int8_t *frm, *efrm, *rates; u_int8_t *frm, *efrm, *rates;
int status; int status;
if ((ic->ic_flags & IEEE80211_F_HOSTAP) ||
(ic->ic_flags & IEEE80211_F_ADHOC) ||
ic->ic_state != IEEE80211_S_ASSOC)
return;
wh = mtod(m0, struct ieee80211_frame *); wh = mtod(m0, struct ieee80211_frame *);
frm = (u_int8_t *)&wh[1]; frm = (u_int8_t *)&wh[1];
efrm = mtod(m0, u_int8_t *) + m0->m_len; efrm = mtod(m0, u_int8_t *) + m0->m_len;
@ -1805,10 +1928,40 @@ static void
ieee80211_recv_disassoc(struct ieee80211com *ic, struct mbuf *m0, int rssi, ieee80211_recv_disassoc(struct ieee80211com *ic, struct mbuf *m0, int rssi,
u_int32_t rstamp) u_int32_t rstamp)
{ {
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
struct ieee80211_bss *bs;
u_int8_t *frm, *efrm;
u_int16_t reason;
wh = mtod(m0, struct ieee80211_frame *); wh = mtod(m0, struct ieee80211_frame *);
if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0) frm = (u_int8_t *)&wh[1];
efrm = mtod(m0, u_int8_t *) + m0->m_len;
/*
* disassoc frame format
* [2] reason
*/
if (frm + 2 > efrm) {
DPRINTF(("ieee80211_recv_disassoc: too short from %s\n",
ether_sprintf(wh->i_addr2)));
return;
}
reason = le16toh(*(u_int16_t *)frm);
if (ic->ic_flags & IEEE80211_F_HOSTAP) {
TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) {
if (memcmp(wh->i_addr2, bs->bs_macaddr,
IEEE80211_ADDR_LEN) == 0) {
if (ifp->if_flags & IFF_DEBUG)
printf("%s: station %s disassociated"
" by peer (reason %d)\n",
ifp->if_xname,
ether_sprintf(bs->bs_macaddr),
reason);
bs->bs_associd = 0;
break;
}
}
} else if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0)
ieee80211_new_state(&ic->ic_if, IEEE80211_S_ASSOC, ieee80211_new_state(&ic->ic_if, IEEE80211_S_ASSOC,
wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
} }
@ -1817,10 +1970,43 @@ static void
ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m0, int rssi, ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m0, int rssi,
u_int32_t rstamp) u_int32_t rstamp)
{ {
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
struct ieee80211_bss *bs;
u_int8_t *frm, *efrm;
u_int16_t reason;
wh = mtod(m0, struct ieee80211_frame *); wh = mtod(m0, struct ieee80211_frame *);
if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0) frm = (u_int8_t *)&wh[1];
efrm = mtod(m0, u_int8_t *) + m0->m_len;
/*
* dauth frame format
* [2] reason
*/
if (frm + 2 > efrm) {
DPRINTF(("ieee80211_recv_deauth: too short from %s\n",
ether_sprintf(wh->i_addr2)));
return;
}
reason = le16toh(*(u_int16_t *)frm);
if (ic->ic_flags & IEEE80211_F_HOSTAP) {
TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) {
if (memcmp(wh->i_addr2, bs->bs_macaddr,
IEEE80211_ADDR_LEN) == 0) {
if (ifp->if_flags & IFF_DEBUG)
printf("%s: station %s deauthenticated"
" by peer (reason %d)\n",
ifp->if_xname,
ether_sprintf(bs->bs_macaddr),
reason);
TAILQ_REMOVE(&ic->ic_scan, bs, bs_list);
free(bs, M_DEVBUF);
if (TAILQ_EMPTY(&ic->ic_scan))
ic->ic_inact_timer = 0;
break;
}
}
} else if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0)
ieee80211_new_state(&ic->ic_if, IEEE80211_S_AUTH, ieee80211_new_state(&ic->ic_if, IEEE80211_S_AUTH,
wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
} }
@ -2024,8 +2210,13 @@ ieee80211_new_state(struct ifnet *ifp, enum ieee80211_state nstate, int mgt)
case IEEE80211_S_SCAN: /* adhoc mode */ case IEEE80211_S_SCAN: /* adhoc mode */
case IEEE80211_S_ASSOC: /* infra mode */ case IEEE80211_S_ASSOC: /* infra mode */
if (ifp->if_flags & IFF_DEBUG) { if (ifp->if_flags & IFF_DEBUG) {
printf("%s: associated with %s ssid ", printf("%s: ", ifp->if_xname);
ifp->if_xname, if ((ic->ic_flags & IEEE80211_F_ADHOC) ||
(ic->ic_flags & IEEE80211_F_HOSTAP))
printf("synchronized ");
else
printf("associated ");
printf("with %s ssid ",
ether_sprintf(ic->ic_bss.bs_bssid)); ether_sprintf(ic->ic_bss.bs_bssid));
ieee80211_print_essid(ic->ic_bss.bs_essid, ieee80211_print_essid(ic->ic_bss.bs_essid,
ic->ic_bss.bs_esslen); ic->ic_bss.bs_esslen);
@ -2187,10 +2378,13 @@ ieee80211_wep_crypt(struct ifnet *ifp, struct mbuf *m0, int txflag)
} }
if (crc != le32toh(*(u_int32_t *)crcbuf)) { if (crc != le32toh(*(u_int32_t *)crcbuf)) {
#ifdef IEEE80211_DEBUG #ifdef IEEE80211_DEBUG
printf("ieee80211_wep_crypt: decrypt CRC error\n"); if (ieee80211_debug) {
if (ieee80211_debug) printf("%s: decrypt CRC error\n",
ieee80211_dump_pkt(n0->m_data, n0->m_len, ifp->if_xname);
-1, -1); if (ieee80211_debug > 1)
ieee80211_dump_pkt(n0->m_data,
n0->m_len, -1, -1);
}
#endif #endif
goto fail; goto fail;
} }