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:
parent
2e5b83493d
commit
2bc3ce7732
@ -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);
|
||||
|
@ -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_ */
|
||||
|
@ -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) ?
|
||||
|
@ -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, ¶m, 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;
|
||||
|
@ -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 *);
|
||||
|
||||
|
@ -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]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user