Date: Tue, 9 Nov 2004 20:29:21 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 64714 for review Message-ID: <200411092029.iA9KTL8a042636@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=64714 Change 64714 by sam@sam_ebb on 2004/11/09 20:28:25 checkpoint ibss support Affected files ... .. //depot/projects/wifi/sys/net80211/ieee80211_input.c#11 edit .. //depot/projects/wifi/sys/net80211/ieee80211_node.c#9 edit .. //depot/projects/wifi/sys/net80211/ieee80211_node.h#8 edit Differences ... ==== //depot/projects/wifi/sys/net80211/ieee80211_input.c#11 (text+ko) ==== @@ -190,8 +190,12 @@ } bssid = wh->i_addr3; } - if (type == IEEE80211_FC0_TYPE_DATA && - !IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) && + if (type != IEEE80211_FC0_TYPE_DATA) + break; + /* + * Data frame, validate the bssid. + */ + if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) && !IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr)) { /* not interested in */ IEEE80211_DPRINTF(ic, IEEE80211_MSG_INPUT, @@ -200,6 +204,24 @@ ic->ic_stats.is_rx_wrongbss++; goto out; } + /* + * For adhoc mode we cons up a node when it doesn't + * exist. This should probably done after an ACL check. + */ + if (ni == ic->ic_bss && + ic->ic_opmode != IEEE80211_M_HOSTAP) { + /* + * Fake up a node for this newly + * discovered member of the IBSS. + */ + ni = ieee80211_fakeup_adhoc_node(ic->ic_sta, + type == IEEE80211_FC0_TYPE_CTL ? + wh->i_addr1 : wh->i_addr2); + if (ni == NULL) { + /* NB: stat kept for alloc failure */ + goto err; + } + } break; default: goto out; @@ -1805,7 +1827,20 @@ wh->i_addr2, chan, bchan, capinfo, bintval, erp, ssid, country); #endif - ni = ieee80211_dup_bss(&ic->ic_scan, wh->i_addr2); + /* + * Create a new entry. If scanning the entry goes + * in the scan cache. Otherwise, be particular when + * operating in adhoc mode--only take nodes marked + * as ibss participants so we don't populate our + * neighbor table with unintersting sta's. + */ + if (ic->ic_state != IEEE80211_S_SCAN) { + if ((capinfo & IEEE80211_CAPINFO_IBSS) == 0) + return; + ni = ieee80211_fakeup_adhoc_node(ic->ic_sta, + wh->i_addr2); + } else + ni = ieee80211_dup_bss(&ic->ic_scan, wh->i_addr2); if (ni == NULL) return; ni->ni_esslen = ssid[1]; @@ -1898,7 +1933,17 @@ IEEE80211_VERIFY_SSID(ic->ic_bss, ssid, "probe"); if (ni == ic->ic_bss) { - ni = ieee80211_dup_bss(ic->ic_sta, wh->i_addr2); + if (ic->ic_opmode == IEEE80211_M_IBSS) { + /* + * XXX Cannot tell if the sender is operating + * in ibss mode. But we need a new node to + * send the response so blindly add them to the + * neighbor table. + */ + ni = ieee80211_fakeup_adhoc_node(ic->ic_sta, + wh->i_addr2); + } else + ni = ieee80211_dup_bss(ic->ic_sta, wh->i_addr2); if (ni == NULL) return; IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, ==== //depot/projects/wifi/sys/net80211/ieee80211_node.c#9 (text+ko) ==== @@ -63,10 +63,10 @@ static void ieee80211_timeout_stations(struct ieee80211_node_table *); static void ieee80211_node_table_init(struct ieee80211com *ic, - struct ieee80211_node_table *nt, int inact, + struct ieee80211_node_table *nt, const char *name, int inact, void (*timeout)(struct ieee80211_node_table *)); static struct ieee80211_node_table *ieee80211_node_table_alloc( - struct ieee80211com *ic, int inact, + struct ieee80211com *ic, const char *name, int inact, void (*timeout)(struct ieee80211_node_table *)); static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt); @@ -77,7 +77,7 @@ { ic->ic_sta = NULL; /* defer to when we need it */ - ieee80211_node_table_init(ic, &ic->ic_scan, + ieee80211_node_table_init(ic, &ic->ic_scan, "scan", IEEE80211_INACT_SCAN, ieee80211_timeout_scan_candidates); ic->ic_node_alloc = node_alloc; @@ -327,21 +327,34 @@ { struct ieee80211_node *ni; - ni = ic->ic_bss; IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "%s: creating ibss\n", __func__); - ic->ic_sta = ieee80211_node_table_alloc(ic, - ic->ic_inact_init, ieee80211_timeout_stations); + /* + * Create the station/neighbor table. Note that for adhoc + * mode we make the initial inactivity timer longer since + * we create nodes only through discovery and they typically + * are long-lived associations. + */ + if (ic->ic_opmode == IEEE80211_M_HOSTAP) + ic->ic_sta = ieee80211_node_table_alloc(ic, + "station", ic->ic_inact_init, + ieee80211_timeout_stations); + else + ic->ic_sta = ieee80211_node_table_alloc(ic, + "neighbor", ic->ic_inact_run, + ieee80211_timeout_stations); if (ic->ic_sta == NULL) { /* * Should remain in SCAN state and retry. */ + /* XXX stat+msg */ return; } + ni = ic->ic_bss; ic->ic_flags |= IEEE80211_F_SIBSS; - ieee80211_set_chan(ic, ic->ic_bss, chan); + ieee80211_set_chan(ic, ni, chan); IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr); IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); if (ic->ic_opmode == IEEE80211_M_IBSS) @@ -612,7 +625,43 @@ goto notfound; } } + +/* + * Handle 802.11 ad hoc network merge. The + * convention, set by the Wireless Ethernet Compatibility Alliance + * (WECA), is that an 802.11 station will change its BSSID to match + * the "oldest" 802.11 ad hoc network, on the same channel, that + * has the station's desired SSID. The "oldest" 802.11 network + * sends beacons with the greatest TSF timestamp. + * + * The caller is assumed to validate TSF's before attempting a merge. + * + * Return !0 if the BSSID changed, 0 otherwise. + */ +int +ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + if (IEEE80211_ADDR_EQ(ni->ni_bssid, ic->ic_bss->ni_bssid)) { + /* unchanged, nothing to do */ + return 0; + } + if (ieee80211_match_bss(ic, ni) != 0) { /* capabilities mismatch */ + IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, + "%s: merge failed, capabilities mismatch\n", __func__); + ic->ic_stats.is_ibss_capmismatch++; + return 0; + } + IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC, + "%s: new bssid %s: %s preamble, %s slot time%s\n", __func__, + ether_sprintf(ni->ni_bssid), + ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", + ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", + ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "" + ); + return ieee80211_sta_join(ic, ni); +} + /* * Join the specified IBSS/BSS network. The node is assumed to * be passed in with a held reference. @@ -630,6 +679,7 @@ IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (selbs->ni_rates.rs_nrates == 0) { selbs->ni_fails++; + ic->ic_stats.is_ibss_norate++; return 0; } } @@ -742,7 +792,9 @@ int hash; IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, - "%s %s\n", __func__, ether_sprintf(macaddr)); + "%s %s in %s table\n", __func__, + ether_sprintf(macaddr), nt->nt_name); + IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); hash = IEEE80211_NODE_HASH(macaddr); ieee80211_node_initref(ni); /* mark referenced */ @@ -845,15 +897,16 @@ } /* - * Fake up a node; this handles node discovery in - * adhoc mode. Note that for the driver's benefit - * we we treat this like an association so the driver - * has an opportunity to setup it's private state. + * Fake up a node; this handles node discovery in adhoc mode. + * Note that for the driver's benefit we we treat this like + * an association so the driver has an opportunity to setup + * it's private state. */ -static __inline struct ieee80211_node * -fakeup_node(struct ieee80211com *ic, struct ieee80211_node_table *nt, +struct ieee80211_node * +ieee80211_fakeup_adhoc_node(struct ieee80211_node_table *nt, const u_int8_t macaddr[IEEE80211_ADDR_LEN]) { + struct ieee80211com *ic = nt->nt_ic; struct ieee80211_node *ni; ni = ieee80211_dup_bss(nt, macaddr); @@ -862,21 +915,20 @@ ni->ni_rates = ic->ic_bss->ni_rates; if (ic->ic_newassoc) ic->ic_newassoc(ic, ni, 1); - /* XXX not sure how 802.1x works w/ IBSS */ + /* XXX not right for 802.1x/WPA */ ieee80211_node_authorize(ic, ni); + ieee80211_ref_node(ni); /* hold reference */ } return ni; } /* - * Locate the node for sender, track state, and then - * pass the (referenced) node up to the 802.11 layer - * for its use. We are required to pass some node so - * we fall back to ic_bss when this frame is from an - * unknown sender. The 802.11 layer knows this means the - * sender wasn't in the node table and acts accordingly. - * Note also that by convention we do not reference - * count ic_bss, only other nodes (ic_bss is never free'd). + * Locate the node for sender, track state, and then pass the + * (referenced) node up to the 802.11 layer for its use. We + * are required to pass some node so we fall back to ic_bss + * when this frame is from an unknown sender. The 802.11 layer + * knows this means the sender wasn't in the node table and + * acts accordingly. */ struct ieee80211_node * #ifdef IEEE80211_DEBUG_REFCNT @@ -892,10 +944,13 @@ struct ieee80211_node_table *nt; struct ieee80211_node *ni; - if (ic->ic_opmode != IEEE80211_M_STA) + /* XXX may want scanned nodes in the neighbor table for adhoc */ + if (ic->ic_opmode == IEEE80211_M_STA || + ic->ic_opmode == IEEE80211_M_MONITOR || + ic->ic_state == IEEE80211_S_SCAN /*XXX*/) + nt = &ic->ic_scan; + else nt = ic->ic_sta; - else - nt = &ic->ic_scan; /* XXX check ic_bss first in station mode */ /* XXX 4-address frames? */ IEEE80211_NODE_LOCK(nt); @@ -905,10 +960,6 @@ ni = _ieee80211_find_node(nt, wh->i_addr2); IEEE80211_NODE_UNLOCK(nt); - if (ni == NULL && - (ic->ic_opmode == IEEE80211_M_IBSS || - ic->ic_opmode == IEEE80211_M_AHDEMO)) - ni = fakeup_node(ic, nt, wh->i_addr2); return (ni != NULL ? ni : ieee80211_ref_node(ic->ic_bss)); #undef IS_CTL } @@ -944,7 +995,7 @@ if (ni == NULL && (ic->ic_opmode == IEEE80211_M_IBSS || ic->ic_opmode == IEEE80211_M_AHDEMO)) - ni = fakeup_node(ic, nt, macaddr); + ni = ieee80211_fakeup_adhoc_node(nt, macaddr); return ni; } @@ -1029,14 +1080,14 @@ _ieee80211_free_node(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; + struct ieee80211_node_table *nt = ni->ni_table; IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, - "%s %s\n", __func__, ether_sprintf(ni->ni_macaddr)); + "%s %s in %s table\n", __func__, ether_sprintf(ni->ni_macaddr), + nt != NULL ? nt->nt_name : "<gone>"); IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap); - if (ni->ni_table != NULL) { - struct ieee80211_node_table *nt = ni->ni_table; - + if (nt != NULL) { TAILQ_REMOVE(&nt->nt_node, ni, ni_list); LIST_REMOVE(ni, ni_hash); } @@ -1111,7 +1162,7 @@ struct ieee80211_node *ni; IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, - "%s: free all nodes\n", __func__); + "%s: free all nodes in %s table\n", __func__, nt->nt_name); while ((ni = TAILQ_FIRST(&nt->nt_node)) != NULL) { if (ni->ni_associd != 0) { @@ -1219,7 +1270,7 @@ * in LOR between the node lock and the driver lock. */ IEEE80211_NODE_UNLOCK(nt); - if (ieee80211_node_is_authorized(ni)) { + if (ni->ni_associd != 0) { IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_EXPIRE); @@ -1454,12 +1505,15 @@ "station %s with aid %d leaves\n", ether_sprintf(ni->ni_macaddr), IEEE80211_NODE_AID(ni)); - KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP, - ("not in ap mode, mode %u", ic->ic_opmode)); + KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP || + ic->ic_opmode == IEEE80211_M_IBSS || + ic->ic_opmode == IEEE80211_M_AHDEMO, + ("unexpected operating mode %u", ic->ic_opmode)); /* * If node wasn't previously associated all * we need to do is reclaim the reference. */ + /* XXX ibss mode bypasses 11g and notification */ if (ni->ni_associd == 0) goto done; /* @@ -1550,20 +1604,27 @@ static void ieee80211_node_table_init(struct ieee80211com *ic, - struct ieee80211_node_table *nt, int inact, + struct ieee80211_node_table *nt, + const char *name, int inact, void (*timeout)(struct ieee80211_node_table *)) { + + IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, + "%s %s table, inact %u\n", __func__, name, inact); + nt->nt_ic = ic; /* XXX need unit */ IEEE80211_NODE_LOCK_INIT(nt, ic->ic_ifp->if_xname); TAILQ_INIT(&nt->nt_node); + nt->nt_name = name; nt->nt_scangen = 1; nt->nt_inact_init = inact; nt->nt_timeout = timeout; } static struct ieee80211_node_table * -ieee80211_node_table_alloc(struct ieee80211com *ic, int inact, +ieee80211_node_table_alloc(struct ieee80211com *ic, + const char *name, int inact, void (*timeout)(struct ieee80211_node_table *)) { struct ieee80211_node_table *nt; @@ -1575,13 +1636,17 @@ printf("%s: no memory node table!\n", __func__); return NULL; } - ieee80211_node_table_init(ic, nt, inact, timeout); + ieee80211_node_table_init(ic, nt, name, inact, timeout); return nt; } void ieee80211_node_table_reset(struct ieee80211_node_table *nt) { + + IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, + "%s %s table\n", __func__, nt->nt_name); + IEEE80211_NODE_LOCK(nt); nt->nt_inact_timer = 0; ieee80211_free_allnodes_locked(nt); @@ -1591,6 +1656,10 @@ static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt) { + + IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, + "%s %s table\n", __func__, nt->nt_name); + ieee80211_free_allnodes_locked(nt); IEEE80211_NODE_LOCK_DESTROY(nt); } @@ -1601,6 +1670,10 @@ void ieee80211_node_table_free(struct ieee80211_node_table *nt) { + + IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, + "%s %s table\n", __func__, nt->nt_name); + IEEE80211_NODE_LOCK(nt); nt->nt_inact_timer = 0; ieee80211_node_table_cleanup(nt); ==== //depot/projects/wifi/sys/net80211/ieee80211_node.h#8 (text+ko) ==== @@ -191,7 +191,7 @@ extern void ieee80211_node_detach(struct ieee80211com *); static __inline int -ieee80211_node_is_authorized(struct ieee80211_node *ni) +ieee80211_node_is_authorized(const struct ieee80211_node *ni) { return (ni->ni_flags & IEEE80211_NODE_AUTH); } @@ -206,6 +206,8 @@ extern void ieee80211_create_ibss(struct ieee80211com*, struct ieee80211_channel *); extern void ieee80211_end_scan(struct ieee80211com *); +extern int ieee80211_ibss_merge(struct ieee80211com *, + struct ieee80211_node *); extern int ieee80211_sta_join(struct ieee80211com *, struct ieee80211_node *); extern void ieee80211_sta_leave(struct ieee80211com *, @@ -222,6 +224,7 @@ ieee80211_node_lock_t nt_nodelock; /* on node table */ TAILQ_HEAD(, ieee80211_node) nt_node; /* information of all nodes */ LIST_HEAD(, ieee80211_node) nt_hash[IEEE80211_NODE_HASHSIZE]; + const char *nt_name; /* for debugging */ u_int nt_scangen; /* gen# for timeout scan */ int nt_inact_timer; /* inactivity timer */ int nt_inact_init; /* initial node inact setting */ @@ -290,6 +293,9 @@ struct ieee80211_node *); extern void ieee80211_dump_nodes(struct ieee80211_node_table *); +extern struct ieee80211_node *ieee80211_fakeup_adhoc_node( + struct ieee80211_node_table *nt, + const u_int8_t macaddr[]); extern void ieee80211_node_join(struct ieee80211com *, struct ieee80211_node *, int); extern void ieee80211_node_leave(struct ieee80211com *,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200411092029.iA9KTL8a042636>