Minor cleanups of tdma protocol handling:

o break out version-related code to simplify rev'ing the protocol
o add parameter validation macros so checks that appear multiple places
  are consistent (and easy to change)
o add protocol version check when looking for a scan candidate
o improve scan debug output format
o rewrite beacon update handling to calculate a bitmask of changed values
  and pass that down through the driver callback so drivers can optimize work
o do slot bounds check before use when parsing received beacons
This commit is contained in:
Sam Leffler 2009-03-18 19:28:17 +00:00
parent 2e5b83493d
commit 2bc3ce7732
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=189980
6 changed files with 121 additions and 64 deletions

View File

@ -225,7 +225,7 @@ static void ath_tdma_bintvalsetup(struct ath_softc *sc,
const struct ieee80211_tdma_state *tdma);
static void ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap);
static void ath_tdma_update(struct ieee80211_node *ni,
const struct ieee80211_tdma_param *tdma);
const struct ieee80211_tdma_param *tdma, int);
static void ath_tdma_beacon_send(struct ath_softc *sc,
struct ieee80211vap *vap);
@ -7477,7 +7477,7 @@ ath_tdma_config(struct ath_softc *sc, struct ieee80211vap *vap)
*/
static void
ath_tdma_update(struct ieee80211_node *ni,
const struct ieee80211_tdma_param *tdma)
const struct ieee80211_tdma_param *tdma, int changed)
{
#define TSF_TO_TU(_h,_l) \
((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10))
@ -7498,7 +7498,7 @@ ath_tdma_update(struct ieee80211_node *ni,
/*
* Check for and adopt configuration changes.
*/
if (isset(ATH_VAP(vap)->av_boff.bo_flags, IEEE80211_BEACON_TDMA)) {
if (changed != 0) {
const struct ieee80211_tdma_state *ts = vap->iv_tdma;
ath_tdma_bintvalsetup(sc, ts);

View File

@ -1077,15 +1077,27 @@ struct ieee80211_duration {
#define ATH_FF_SNAP_ORGCODE_1 0x03
#define ATH_FF_SNAP_ORGCODE_2 0x7f
/* NB: Atheros allocated the OUI for this purpose ~2005 but beware ... */
#define TDMA_OUI ATH_OUI
#define TDMA_OUI_TYPE 0x02
#define TDMA_VERSION_V2 2
#define TDMA_VERSION TDMA_VERSION_V2
/* NB: we only support 2 right now but protocol handles up to 8 */
#define TDMA_MAXSLOTS 2 /* max slots/sta's */
#define TDMA_PARAM_LEN_V2 sizeof(struct ieee80211_tdma_param)
struct ieee80211_tdma_param {
u_int8_t tdma_id; /* IEEE80211_ELEMID_VENDOR */
u_int8_t tdma_len;
u_int8_t tdma_oui[3]; /* 0x00, 0x03, 0x7f */
u_int8_t tdma_type; /* OUI type */
u_int8_t tdma_subtype; /* OUI subtype */
#define TDMA_SUBTYPE_PARAM 0x01
u_int8_t tdma_version; /* spec revision */
u_int8_t tdma_slot; /* station slot # */
u_int8_t tdma_slotcnt; /* bss slot count */
u_int8_t tdma_slot; /* station slot # [0..7] */
u_int8_t tdma_slotcnt; /* bss slot count [1..8] */
u_int16_t tdma_slotlen; /* bss slot len (100us) */
u_int8_t tdma_bintval; /* beacon interval (superframes) */
u_int8_t tdma_inuse[1]; /* slot occupancy map */
@ -1093,10 +1105,14 @@ struct ieee80211_tdma_param {
u_int8_t tdma_tstamp[8]; /* timestamp from last beacon */
} __packed;
/* NB: Atheros allocated the OUI for this purpose ~3 years ago but beware ... */
#define TDMA_OUI ATH_OUI
#define TDMA_OUI_TYPE 0x02
#define TDMA_SUBTYPE_PARAM 0x01
#define TDMA_VERSION 2
#define TDMA_VERSION_VALID(_version) \
(TDMA_VERSION_V2 <= (_version) && (_version) <= TDMA_VERSION)
#define TDMA_SLOTCNT_VALID(_slotcnt) \
(2 <= (_slotcnt) && (_slotcnt) <= TDMA_MAXSLOTS)
/* XXX magic constants */
#define TDMA_SLOTLEN_VALID(_slotlen) \
(2*100 <= (_slotlen) && (unsigned)(_slotlen) <= 0xfffff)
/* XXX probably should set a max */
#define TDMA_BINTVAL_VALID(_bintval) (1 <= (_bintval))
#endif /* _NET80211_IEEE80211_H_ */

View File

@ -126,6 +126,7 @@ static void sta_flush_table(struct sta_table *);
#define MATCH_TDMA_NOTMASTER 0x0800 /* not TDMA master */
#define MATCH_TDMA_NOSLOT 0x1000 /* all TDMA slots occupied */
#define MATCH_TDMA_LOCAL 0x2000 /* local address */
#define MATCH_TDMA_VERSION 0x4000 /* protocol version mismatch */
static int match_bss(struct ieee80211vap *,
const struct ieee80211_scan_state *, struct sta_entry *, int);
static void adhoc_age(struct ieee80211_scan_state *);
@ -970,9 +971,12 @@ match_bss(struct ieee80211vap *vap,
if (vap->iv_caps & IEEE80211_C_TDMA) {
const struct ieee80211_tdma_param *tdma =
(const struct ieee80211_tdma_param *)se->se_ies.tdma_ie;
const struct ieee80211_tdma_state *ts = vap->iv_tdma;
if (tdma == NULL)
fail |= MATCH_TDMA_NOIE;
else if (tdma->tdma_version != ts->tdma_version)
fail |= MATCH_TDMA_VERSION;
else if (tdma->tdma_slot != 0)
fail |= MATCH_TDMA_NOTMASTER;
else if (tdma_isfull(tdma))
@ -1062,9 +1066,10 @@ match_bss(struct ieee80211vap *vap,
fail & MATCH_CC ? '$' :
#ifdef IEEE80211_SUPPORT_TDMA
fail & MATCH_TDMA_NOIE ? '&' :
fail & MATCH_TDMA_NOTMASTER ? ':' :
fail & MATCH_TDMA_NOSLOT ? '@' :
fail & MATCH_TDMA_LOCAL ? '#' :
fail & MATCH_TDMA_VERSION ? 'v' :
fail & MATCH_TDMA_NOTMASTER ? 's' :
fail & MATCH_TDMA_NOSLOT ? 'f' :
fail & MATCH_TDMA_LOCAL ? 'l' :
#endif
fail ? '-' : '+', ether_sprintf(se->se_macaddr));
printf(" %s%c", ether_sprintf(se->se_bssid),
@ -1076,8 +1081,7 @@ match_bss(struct ieee80211vap *vap,
fail & MATCH_RATE ? '!' : ' ');
printf(" %4s%c",
(se->se_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
(se->se_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
"????",
(se->se_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : "",
fail & MATCH_CAPINFO ? '!' : ' ');
printf(" %3s%c ",
(se->se_capinfo & IEEE80211_CAPINFO_PRIVACY) ?

View File

@ -142,6 +142,7 @@ ieee80211_tdma_vattach(struct ieee80211vap *vap)
return;
}
/* NB: default configuration is passive so no beacons */
ts->tdma_version = TDMA_VERSION;
ts->tdma_slotlen = TDMA_SLOTLEN_DEFAULT;
ts->tdma_slotcnt = TDMA_SLOTCNT_DEFAULT;
ts->tdma_bintval = TDMA_BINTVAL_DEFAULT;
@ -371,71 +372,90 @@ tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
* a TDMA information element. The sender's identity
* is provided so we can track who our peer is. If pickslot
* is non-zero we scan the slot allocation state in the ie
* locate a free slot for our use.
* to locate a free slot for our use.
*/
static int
tdma_update(struct ieee80211vap *vap, const struct ieee80211_tdma_param *tdma,
struct ieee80211_node *ni, int pickslot)
{
struct ieee80211_tdma_state *ts = vap->iv_tdma;
int slotlen, slotcnt, slot, bintval;
int slot, slotlen, update;
KASSERT(vap->iv_caps & IEEE80211_C_TDMA,
("not a tdma vap, caps 0x%x", vap->iv_caps));
slotlen = le16toh(tdma->tdma_slotlen);
slotcnt = tdma->tdma_slotcnt;
bintval = tdma->tdma_bintval;
/* XXX rate-limit printf's */
if (!(2 <= slotcnt && slotcnt <= IEEE80211_TDMA_MAXSLOTS)) {
printf("%s: bogus slot cnt %u\n", __func__, slotcnt);
return 0;
}
/* XXX magic constants */
if (slotlen < 2 || slotlen > (0xfffff/100)) {
printf("%s: bogus slot len %u\n", __func__, slotlen);
return 0;
}
if (bintval < 1) {
printf("%s: bogus beacon interval %u\n", __func__, bintval);
return 0;
}
update = 0;
if (tdma->tdma_slotcnt != ts->tdma_slotcnt) {
if (!TDMA_SLOTCNT_VALID(tdma->tdma_slotcnt)) {
printf("%s: bad slot cnt %u\n",
__func__, tdma->tdma_slotcnt);
return 0;
}
update |= TDMA_UPDATE_SLOTCNT;
}
slotlen = le16toh(tdma->tdma_slotlen) * 100;
if (slotlen != ts->tdma_slotlen) {
if (!TDMA_SLOTLEN_VALID(slotlen)) {
printf("%s: bad slot len %u\n",
__func__, slotlen);
return 0;
}
update |= TDMA_UPDATE_SLOTLEN;
}
if (tdma->tdma_bintval != ts->tdma_bintval) {
if (!TDMA_BINTVAL_VALID(tdma->tdma_bintval)) {
printf("%s: bad beacon interval %u\n",
__func__, tdma->tdma_bintval);
return 0;
}
update |= TDMA_UPDATE_BINTVAL;
}
slot = ts->tdma_slot;
if (pickslot) {
/*
* Pick unoccupied slot. Note we never choose slot 0.
*/
for (slot = slotcnt-1; slot > 0; slot--)
for (slot = tdma->tdma_slotcnt-1; slot > 0; slot--)
if (isclr(tdma->tdma_inuse, slot))
break;
if (slot <= 0) {
printf("%s: no free slot, slotcnt %u inuse: 0x%x\n",
__func__, slotcnt, tdma->tdma_inuse[0]);
__func__, tdma->tdma_slotcnt,
tdma->tdma_inuse[0]);
/* XXX need to do something better */
return 0;
}
} else
slot = ts->tdma_slot;
if (slot != ts->tdma_slot)
update |= TDMA_UPDATE_SLOT;
}
if (ni != ts->tdma_peer) {
/* update everything */
update = TDMA_UPDATE_SLOT
| TDMA_UPDATE_SLOTCNT
| TDMA_UPDATE_SLOTLEN
| TDMA_UPDATE_BINTVAL;
}
if (slotcnt != ts->tdma_slotcnt ||
100*slotlen != ts->tdma_slotlen ||
bintval != ts->tdma_bintval ||
slot != ts->tdma_slot ||
ts->tdma_peer != ni) {
if (update) {
/*
* New/changed parameters; update runtime state.
*/
/* XXX overwrites user parameters */
ts->tdma_slotcnt = slotcnt;
ts->tdma_slotlen = 100*slotlen;
ts->tdma_slot = slot;
ts->tdma_bintval = bintval;
if (update & TDMA_UPDATE_SLOTCNT)
ts->tdma_slotcnt = tdma->tdma_slotcnt;
if (update & TDMA_UPDATE_SLOTLEN)
ts->tdma_slotlen = slotlen;
if (update & TDMA_UPDATE_SLOT)
ts->tdma_slot = slot;
if (update & TDMA_UPDATE_BINTVAL)
ts->tdma_bintval = tdma->tdma_bintval;
/* mark beacon to be updated before next xmit */
ieee80211_beacon_notify(vap, IEEE80211_BEACON_TDMA);
IEEE80211_DPRINTF(vap, IEEE80211_MSG_TDMA,
"%s: slot %u slotcnt %u slotlen %u us bintval %u\n",
__func__, slot, slotcnt, 100*slotlen, tdma->tdma_bintval);
__func__, ts->tdma_slot, ts->tdma_slotcnt,
100*ts->tdma_slotlen, ts->tdma_bintval);
}
/*
* Notify driver. Note we can be called before
@ -445,7 +465,7 @@ tdma_update(struct ieee80211vap *vap, const struct ieee80211_tdma_param *tdma,
* has been setup. The next beacon will dtrt.
*/
if (vap->iv_state == IEEE80211_S_RUN)
vap->iv_ic->ic_tdma_update(ni, tdma);
vap->iv_ic->ic_tdma_update(ni, tdma, update);
/*
* Dispatch join event on first beacon from new master.
*/
@ -481,10 +501,23 @@ tdma_process_params(struct ieee80211_node *ni,
wh, "tdma", "too short, len %u", len);
return IEEE80211_REASON_IE_INVALID;
}
if (tdma->tdma_version != TDMA_VERSION) {
if (tdma->tdma_version != ts->tdma_version) {
IEEE80211_DISCARD_IE(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA,
wh, "tdma", "bad version %u", tdma->tdma_version);
wh, "tdma", "bad version %u (ours %u)",
tdma->tdma_version, ts->tdma_version);
return IEEE80211_REASON_IE_INVALID;
}
/*
* NB: ideally we'd check against tdma_slotcnt, but that
* would require extra effort so do this easy check that
* covers the work below; more stringent checks are done
* before we make more extensive use of the ie contents.
*/
if (tdma->tdma_slot >= TDMA_MAXSLOTS) {
IEEE80211_DISCARD_IE(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA,
wh, "tdma", "invalid slot %u", tdma->tdma_slot);
return IEEE80211_REASON_IE_INVALID;
}
/*
@ -612,7 +645,7 @@ ieee80211_add_tdma(uint8_t *frm, struct ieee80211vap *vap)
.tdma_subtype = TDMA_SUBTYPE_PARAM,
.tdma_version = TDMA_VERSION,
};
const struct ieee80211_tdma_state *tdma = vap->iv_tdma;
const struct ieee80211_tdma_state *ts = vap->iv_tdma;
uint16_t slotlen;
KASSERT(vap->iv_caps & IEEE80211_C_TDMA,
@ -620,13 +653,13 @@ ieee80211_add_tdma(uint8_t *frm, struct ieee80211vap *vap)
memcpy(frm, &param, sizeof(param));
frm += __offsetof(struct ieee80211_tdma_param, tdma_slot);
*frm++ = tdma->tdma_slot;
*frm++ = tdma->tdma_slotcnt;
*frm++ = ts->tdma_slot;
*frm++ = ts->tdma_slotcnt;
/* NB: convert units to fit in 16-bits */
slotlen = tdma->tdma_slotlen / 100; /* 100us units */
slotlen = ts->tdma_slotlen / 100; /* 100us units */
ADDSHORT(frm, slotlen);
*frm++ = tdma->tdma_bintval;
*frm++ = tdma->tdma_inuse[0];
*frm++ = ts->tdma_bintval;
*frm++ = ts->tdma_inuse[0];
frm += 10; /* pad+timestamp */
return frm;
#undef ADDSHORT
@ -717,8 +750,7 @@ ieee80211_tdma_ioctl_set80211(struct ieee80211vap *vap,
}
break;
case IEEE80211_IOC_TDMA_SLOTCNT:
if (!(2 <= ireq->i_val &&
ireq->i_val <= IEEE80211_TDMA_MAXSLOTS))
if (!TDMA_SLOTCNT_VALID(ireq->i_val))
return EINVAL;
if (ireq->i_val != ts->tdma_slotcnt) {
ts->tdma_slotcnt = ireq->i_val;
@ -732,7 +764,7 @@ ieee80211_tdma_ioctl_set80211(struct ieee80211vap *vap,
* 0xfffff is the max duration for bursting
* (implict by way of 16-bit data type for i_val)
*/
if (ireq->i_val < 150)
if (!TDMA_SLOTLEN_VALID(ireq->i_val))
return EINVAL;
if (ireq->i_val != ts->tdma_slotlen) {
ts->tdma_slotlen = ireq->i_val;
@ -740,7 +772,7 @@ ieee80211_tdma_ioctl_set80211(struct ieee80211vap *vap,
}
break;
case IEEE80211_IOC_TDMA_BINTERVAL:
if (ireq->i_val < 1)
if (!TDMA_BINTVAL_VALID(ireq->i_val))
return EINVAL;
if (ireq->i_val != ts->tdma_bintval) {
ts->tdma_bintval = ireq->i_val;

View File

@ -33,11 +33,11 @@
*/
struct ieee80211_tdma_state {
u_int tdma_slotlen; /* bss slot length (us) */
uint8_t tdma_version; /* protocol version to use */
uint8_t tdma_slotcnt; /* bss slot count */
uint8_t tdma_bintval; /* beacon interval (slots) */
uint8_t tdma_slot; /* station slot # */
uint8_t tdma_inuse[1]; /* mask of slots in use */
#define IEEE80211_TDMA_MAXSLOTS 8
void *tdma_peer; /* peer station cookie */
uint8_t tdma_active[1]; /* mask of active slots */
int tdma_count; /* active/inuse countdown */
@ -49,6 +49,11 @@ struct ieee80211_tdma_state {
struct mbuf *, int, int, int, uint32_t);
void (*tdma_opdetach)(struct ieee80211vap *);
};
#define TDMA_UPDATE_SLOT 0x0001 /* tdma_slot changed */
#define TDMA_UPDATE_SLOTCNT 0x0002 /* tdma_slotcnt changed */
#define TDMA_UPDATE_SLOTLEN 0x0004 /* tdma_slotlen changed */
#define TDMA_UPDATE_BINTVAL 0x0008 /* tdma_bintval changed */
void ieee80211_tdma_vattach(struct ieee80211vap *);

View File

@ -229,7 +229,7 @@ struct ieee80211com {
void (*ic_newassoc)(struct ieee80211_node *, int);
/* TDMA update notification */
void (*ic_tdma_update)(struct ieee80211_node *,
const struct ieee80211_tdma_param *);
const struct ieee80211_tdma_param *, int);
/* node state management */
struct ieee80211_node* (*ic_node_alloc)(struct ieee80211vap *,
const uint8_t [IEEE80211_ADDR_LEN]);