diff --git a/sys/dev/ic/awi.c b/sys/dev/ic/awi.c index df71d875a4a2..b5725428c9c8 100644 --- a/sys/dev/ic/awi.c +++ b/sys/dev/ic/awi.c @@ -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. @@ -85,7 +85,7 @@ */ #include -__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 "bpfilter.h" @@ -491,9 +491,9 @@ awi_init(struct ifnet *ifp) (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; - memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], sc->sc_ic.ic_des_essid, - 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], ic->ic_des_essid, + ic->ic_des_esslen); if ((error = awi_mode_init(sc)) != 0) { 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_OACTIVE; - if (((sc->sc_ic.ic_flags & IEEE80211_F_ADHOC) && sc->sc_no_bssid) || - (sc->sc_ic.ic_flags & IEEE80211_F_HOSTAP)) { + if (((ic->ic_flags & IEEE80211_F_ADHOC) && sc->sc_no_bssid) || + (ic->ic_flags & IEEE80211_F_HOSTAP)) { bs->bs_chan = ic->ic_ibss_chan; bs->bs_intval = ic->ic_lintval; bs->bs_rssi = 0; @@ -547,7 +547,7 @@ awi_init(struct ifnet *ifp) ic->ic_sup_rates[i]; } 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); bs->bs_esslen = ic->ic_des_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 */ n = 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; goto set_mib; } @@ -1264,8 +1265,14 @@ awi_hw_init(struct awi_softc *sc) printf(" (lost interrupt)\n"); else 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; - 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.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.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 */ 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_Size, 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.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; } diff --git a/sys/dev/ic/awireg.h b/sys/dev/ic/awireg.h index 2dd0c848458a..926a04ef55f6 100644 --- a/sys/dev/ic/awireg.h +++ b/sys/dev/ic/awireg.h @@ -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. @@ -258,7 +258,9 @@ #define AWI_DRV_RXLED 0x40 #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_END 0x6000 diff --git a/sys/net/if_ieee80211.h b/sys/net/if_ieee80211.h index bb019e873ef7..d4648856936b 100644 --- a/sys/net/if_ieee80211.h +++ b/sys/net/if_ieee80211.h @@ -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. @@ -334,6 +334,8 @@ struct ieee80211_auth { #define IEEE80211_ASCAN_WAIT 2 /* active scan wait */ #define IEEE80211_PSCAN_WAIT 5 /* passive scan 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. @@ -382,6 +384,7 @@ struct ieee80211_bss { u_int16_t bs_txseq; /* seq to be transmitted */ u_int16_t bs_rxseq; /* seq previous received */ int bs_fails; /* failure count to associate */ + int bs_inact; /* inactivity mark count */ int bs_txrate; /* index to bs_rates[] */ void *bs_private; /* driver private */ }; @@ -421,6 +424,7 @@ struct ieee80211com { u_int16_t ic_lintval; /* listen interval */ int ic_mgt_timer; /* mgmt timeout */ int ic_scan_timer; /* scant wait */ + int ic_inact_timer; /* inactivity timer wait */ int ic_des_esslen; u_int8_t ic_des_essid[IEEE80211_NWID_LEN]; struct ieee80211_wepkey ic_nw_keys[IEEE80211_WEP_NKID]; diff --git a/sys/net/if_ieee80211subr.c b/sys/net/if_ieee80211subr.c index 9e26f58486d6..d29c6924ba4f 100644 --- a/sys/net/if_ieee80211subr.c +++ b/sys/net/if_ieee80211subr.c @@ -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. @@ -41,7 +41,7 @@ */ #include -__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 "bpfilter.h" @@ -294,6 +294,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, int rssi, u_int32_t rstamp) /* duplicate, silently discarded */ goto out; } + bs->bs_inact = 0; } 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 (!(ic->ic_flags & IEEE80211_F_ADHOC) || - ic->ic_state == IEEE80211_S_SCAN || - subtype != IEEE80211_FC0_SUBTYPE_BEACON) + /* avoid to print too many frames */ + int doprint = 0; + + 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", ifp->if_xname, ieee80211_mgt_subtype_name[subtype @@ -408,6 +426,7 @@ ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_bss *bs, if (bs == NULL) bs = &ic->ic_bss; + bs->bs_inact = 0; M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); if (m == NULL) 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_addr3, bs->bs_bssid, IEEE80211_ADDR_LEN); - if (ifp->if_flags & IFF_DEBUG) - 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 (ifp->if_flags & IFF_DEBUG) { + /* avoid to print too many frames */ + if ((ic->ic_flags & IEEE80211_F_ADHOC) || + (type & IEEE80211_FC0_SUBTYPE_MASK) != + IEEE80211_FC0_SUBTYPE_PROBE_RESP) + 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); ifp->if_timer = 1; (*ifp->if_start)(ifp); @@ -441,6 +465,7 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m) struct ether_header eh; struct ieee80211_frame *wh; struct llc *llc; + struct ieee80211_bss *bs; if (m->m_len < 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; } 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)); llc = mtod(m, struct llc *); 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; *(u_int16_t *)wh->i_dur = 0; *(u_int16_t *)wh->i_seq = - htole16(ic->ic_bss.bs_txseq << IEEE80211_SEQ_SEQ_SHIFT); - ic->ic_bss.bs_txseq++; + htole16(bs->bs_txseq << IEEE80211_SEQ_SEQ_SHIFT); + bs->bs_txseq++; if (ic->ic_flags & IEEE80211_F_ADHOC) { wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 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); + memcpy(wh->i_addr3, bs->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_addr2, bs->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); + memcpy(wh->i_addr1, bs->bs_bssid, IEEE80211_ADDR_LEN); memcpy(wh->i_addr2, eh.ether_shost, IEEE80211_ADDR_LEN); memcpy(wh->i_addr3, eh.ether_dhost, IEEE80211_ADDR_LEN); } @@ -817,6 +861,7 @@ void ieee80211_watchdog(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; + struct ieee80211_bss *bs, *nextbs; if (ic->ic_scan_timer) { if (--ic->ic_scan_timer == 0) { @@ -828,7 +873,33 @@ ieee80211_watchdog(struct ifnet *ifp) if (--ic->ic_mgt_timer == 0) 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; } @@ -1015,6 +1086,9 @@ ieee80211_alloc_bss(struct ieee80211com *ic, int copy) memset(bs->bs_private, 0, ic->ic_bss_privlen); } 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; } @@ -1028,6 +1102,7 @@ ieee80211_free_scan(struct ifnet *ifp) TAILQ_REMOVE(&ic->ic_scan, bs, bs_list); free(bs, M_DEVBUF); } + ic->ic_inact_timer = 0; } int @@ -1177,6 +1252,12 @@ ieee80211_send_prresp(struct ieee80211com *ic, struct ieee80211_bss *bs0, *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ } else { /* 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 */ 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, int type, int reason) { + struct ifnet *ifp = &ic->ic_if; 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); if (m == NULL) return ENOMEM; @@ -1337,10 +1422,14 @@ ieee80211_send_asresp(struct ieee80211com *ic, struct ieee80211_bss *bs, static int 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; + 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); if (m == NULL) return ENOMEM; @@ -1479,9 +1568,12 @@ ieee80211_recv_prreq(struct ieee80211com *ic, struct mbuf *m0, int rssi, struct ieee80211_bss *bs; u_int8_t *frm, *efrm, *ssid, *rates; u_int8_t rate; + int allocbs; - if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0 || - (ic->ic_state != IEEE80211_S_RUN)) + if ((ic->ic_flags & IEEE80211_F_ADHOC) == 0 && + (ic->ic_flags & IEEE80211_F_HOSTAP) == 0) + return; + if (ic->ic_state != IEEE80211_S_RUN) return; 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", ether_sprintf(wh->i_addr2))); memcpy(bs->bs_macaddr, wh->i_addr2, IEEE80211_ADDR_LEN); - } + allocbs = 1; + } else + allocbs = 0; memset(bs->bs_rates, 0, IEEE80211_RATE_SIZE); bs->bs_nrate = rates[1]; 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) { DPRINTF(("ieee80211_recv_prreq: rate negotiation failed: %s\n", 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 ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, int rssi, u_int32_t rstamp) { + struct ifnet *ifp = &ic->ic_if; struct ieee80211_frame *wh; struct ieee80211_bss *bs; u_int8_t *frm, *efrm; u_int16_t algo, seq, status; + int allocbs; wh = mtod(m0, struct ieee80211_frame *); frm = (u_int8_t *)&wh[1]; @@ -1583,17 +1686,16 @@ ieee80211_recv_auth(struct ieee80211com *ic, struct mbuf *m0, int rssi, return; } if (ic->ic_flags & IEEE80211_F_ADHOC) { - if (ic->ic_state != IEEE80211_S_RUN) + if (ic->ic_state != IEEE80211_S_RUN || seq != 1) return; - if (seq == 1) { - ieee80211_new_state(&ic->ic_if, IEEE80211_S_AUTH, - wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); - return; - } + ieee80211_new_state(&ic->ic_if, IEEE80211_S_AUTH, + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + return; } if (ic->ic_flags & IEEE80211_F_HOSTAP) { - if (ic->ic_state != IEEE80211_S_RUN) + if (ic->ic_state != IEEE80211_S_RUN || seq != 1) return; + allocbs = 0; TAILQ_FOREACH(bs, &ic->ic_scan, bs_list) { if (memcmp(bs->bs_macaddr, wh->i_addr2, 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_bssid, ic->ic_bss.bs_bssid, IEEE80211_ADDR_LEN); + allocbs = 1; } 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; } 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, u_int32_t rstamp) { + struct ifnet *ifp = &ic->ic_if; 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; + int reassoc, resp, newassoc; if ((ic->ic_flags & IEEE80211_F_HOSTAP) == 0 || (ic->ic_state != IEEE80211_S_RUN)) @@ -1715,11 +1824,11 @@ ieee80211_recv_asreq(struct ieee80211com *ic, struct mbuf *m0, int rssi, } 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)) { + bs->bs_associd = 0; IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_CAPINFO); 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_F_DONEGO | IEEE80211_F_DODEL); if (bs->bs_nrate == 0) { + bs->bs_associd = 0; IEEE80211_SEND_MGMT(ic, bs, resp, IEEE80211_STATUS_BASIC_RATE); 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_fhdwell = ic->ic_bss.bs_fhdwell; 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); + 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 @@ -1753,6 +1871,11 @@ ieee80211_recv_asresp(struct ieee80211com *ic, struct mbuf *m0, int rssi, u_int8_t *frm, *efrm, *rates; 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 *); frm = (u_int8_t *)&wh[1]; 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, u_int32_t rstamp) { + struct ifnet *ifp = &ic->ic_if; struct ieee80211_frame *wh; + struct ieee80211_bss *bs; + u_int8_t *frm, *efrm; + u_int16_t reason; 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, 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, u_int32_t rstamp) { + struct ifnet *ifp = &ic->ic_if; struct ieee80211_frame *wh; + struct ieee80211_bss *bs; + u_int8_t *frm, *efrm; + u_int16_t reason; 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, 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_ASSOC: /* infra mode */ if (ifp->if_flags & IFF_DEBUG) { - printf("%s: associated with %s ssid ", - ifp->if_xname, + printf("%s: ", 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)); ieee80211_print_essid(ic->ic_bss.bs_essid, 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)) { #ifdef IEEE80211_DEBUG - printf("ieee80211_wep_crypt: decrypt CRC error\n"); - if (ieee80211_debug) - ieee80211_dump_pkt(n0->m_data, n0->m_len, - -1, -1); + if (ieee80211_debug) { + printf("%s: decrypt CRC error\n", + ifp->if_xname); + if (ieee80211_debug > 1) + ieee80211_dump_pkt(n0->m_data, + n0->m_len, -1, -1); + } #endif goto fail; }