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
This commit is contained in:
Sam Leffler 2007-01-08 17:24:51 +00:00
parent d05b58ad32
commit 79edaebfe4
4 changed files with 46 additions and 40 deletions

View File

@ -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) {

View File

@ -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);
}
/*

View File

@ -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++;
}

View File

@ -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);
/*