From 79edaebfe4b49937ebda3f09fad4daafb71de5a4 Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Mon, 8 Jan 2007 17:24:51 +0000 Subject: [PATCH] Correct several issues with rate set negotiation: o add IEEE80211_F_JOIN flag to ieee80211_fix_rate to indicate a station is joining a BSS; this is used to control whether or not we over-write the basic rate bit in the calculated rate set o fix ieee80211_fix_rate to honor IEEE80211_F_DODEL when IEEE80211_F_DONEGO is not specified (e.g. when joining an ibss network) o on sta join always delete unusable rates from the negotiated rate set, this was being done only ibss networks but is also needed for 11g bss with mixed stations o on sta join delete unusable rates from the bss node's rate set, not the scan table entry's rate set o when calculating a rate set for new neighbors in an ibss caculate a negotiated rate set so drivers are not presented with rates they should not use Submitted by: Sepherosa Ziehau (w/ modifications) Obtained from: DragonFly MFC after: 1 month --- sys/net80211/ieee80211_input.c | 1 + sys/net80211/ieee80211_node.c | 19 ++++++---- sys/net80211/ieee80211_proto.c | 65 +++++++++++++++++----------------- sys/net80211/ieee80211_proto.h | 1 + 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 511e6e11ef49..53736c1fc333 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -2471,6 +2471,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE); rate = ieee80211_setup_rates(ni, rates, xrates, + IEEE80211_F_JOIN | IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (rate & IEEE80211_RATE_BASIC) { diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 700d4b00b0d2..9c34c296ccf4 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -517,7 +517,8 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni) if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) fail |= 0x04; } - rate = ieee80211_fix_rate(ni, IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); + rate = ieee80211_fix_rate(ni, + IEEE80211_F_JOIN | IEEE80211_F_DONEGO | IEEE80211_F_DOFRATE); if (rate & IEEE80211_RATE_BASIC) fail |= 0x08; if (ic->ic_des_esslen != 0 && @@ -802,11 +803,6 @@ ieee80211_sta_join(struct ieee80211com *ic, struct ieee80211_node *selbs) if (ic->ic_opmode == IEEE80211_M_IBSS) { struct ieee80211_node_table *nt; - /* - * Delete unusable rates; we've already checked - * that the negotiated rate set is acceptable. - */ - ieee80211_fix_rate(selbs, IEEE80211_F_DODEL); /* * Fillin the neighbor table; it will already * exist if we are simply switching mastership. @@ -828,6 +824,13 @@ ieee80211_sta_join(struct ieee80211com *ic, struct ieee80211_node *selbs) copy_bss(selbs, obss); ieee80211_free_node(obss); } + + /* + * Delete unusable rates; we've already checked + * that the negotiated rate set is acceptable. + */ + ieee80211_fix_rate(ic->ic_bss, IEEE80211_F_DODEL | IEEE80211_F_JOIN); + /* * Set the erp state (mostly the slot time) to deal with * the auto-select case; this should be redundant if the @@ -1295,7 +1298,9 @@ ieee80211_init_neighbor(struct ieee80211_node *ni, ieee80211_saveie(&ni->ni_wpa_ie, sp->wpa); /* NB: must be after ni_chan is setup */ - ieee80211_setup_rates(ni, sp->rates, sp->xrates, IEEE80211_F_DOSORT); + ieee80211_setup_rates(ni, sp->rates, sp->xrates, + IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | + IEEE80211_F_DONEGO | IEEE80211_F_DODEL); } /* diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index e11fb70da555..590522f168a8 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -322,12 +322,23 @@ ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi) } } +static __inline int +findrix(const struct ieee80211_rateset *rs, int r) +{ + int i; + + for (i = 0; i < rs->rs_nrates; i++) + if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == r) + return i; + return -1; +} + int ieee80211_fix_rate(struct ieee80211_node *ni, int flags) { #define RV(v) ((v) & IEEE80211_RATE_VAL) struct ieee80211com *ic = ni->ni_ic; - int i, j, ignore, error; + int i, j, rix, error; int okrate, badrate, fixedrate; const struct ieee80211_rateset *srs; struct ieee80211_rateset *nrs; @@ -345,7 +356,6 @@ ieee80211_fix_rate(struct ieee80211_node *ni, int flags) srs = ieee80211_get_suprates(ic, ni->ni_chan); nrs = &ni->ni_rates; for (i = 0; i < nrs->rs_nrates; ) { - ignore = 0; if (flags & IEEE80211_F_DOSORT) { /* * Sort rates. @@ -367,51 +377,40 @@ ieee80211_fix_rate(struct ieee80211_node *ni, int flags) if (r == RV(srs->rs_rates[ic->ic_fixed_rate])) fixedrate = r; } + /* + * Check against supported rates. + */ + rix = findrix(srs, r); if (flags & IEEE80211_F_DONEGO) { - /* - * Check against supported rates. - */ - for (j = 0; j < srs->rs_nrates; j++) { - if (r == RV(srs->rs_rates[j])) { - /* - * Overwrite with the supported rate - * value so any basic rate bit is set. - * This insures that response we send - * to stations have the necessary basic - * rate bit set. - */ - nrs->rs_rates[i] = srs->rs_rates[j]; - break; - } - } - if (j == srs->rs_nrates) { + if (rix < 0) { /* * A rate in the node's rate set is not * supported. If this is a basic rate and we - * are operating as an AP then this is an error. + * are operating as a STA then this is an error. * Otherwise we just discard/ignore the rate. - * Note that this is important for 11b stations - * when they want to associate with an 11g AP. */ - if (ic->ic_opmode == IEEE80211_M_HOSTAP && + if ((flags & IEEE80211_F_JOIN) && (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) error++; - ignore++; + } else if ((flags & IEEE80211_F_JOIN) == 0) { + /* + * Overwrite with the supported rate + * value so any basic rate bit is set. + */ + nrs->rs_rates[i] = srs->rs_rates[rix]; } } - if (flags & IEEE80211_F_DODEL) { + if ((flags & IEEE80211_F_DODEL) && rix < 0) { /* * Delete unacceptable rates. */ - if (ignore) { - nrs->rs_nrates--; - for (j = i; j < nrs->rs_nrates; j++) - nrs->rs_rates[j] = nrs->rs_rates[j + 1]; - nrs->rs_rates[j] = 0; - continue; - } + nrs->rs_nrates--; + for (j = i; j < nrs->rs_nrates; j++) + nrs->rs_rates[j] = nrs->rs_rates[j + 1]; + nrs->rs_rates[j] = 0; + continue; } - if (!ignore) + if (rix >= 0) okrate = nrs->rs_rates[i]; i++; } diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h index 397da4449662..0182cd444fef 100644 --- a/sys/net80211/ieee80211_proto.h +++ b/sys/net80211/ieee80211_proto.h @@ -180,6 +180,7 @@ const struct ieee80211_aclator *ieee80211_aclator_get(const char *name); #define IEEE80211_F_DOFRATE 0x00000002 /* use fixed rate */ #define IEEE80211_F_DONEGO 0x00000004 /* calc negotiated rate */ #define IEEE80211_F_DODEL 0x00000008 /* delete ignore rate */ +#define IEEE80211_F_JOIN 0x00000010 /* sta joining our bss */ int ieee80211_fix_rate(struct ieee80211_node *, int); /*