Compared to ieee80211_beacon_get(), the new function ieee80211_beacon_get_tim() returns information on the location and length of the TIM IE, which some drivers need in order to generate the TIM on the device. The old function, ieee80211_beacon_get(), becomes a small static inline wrapper around the new one to not break all drivers. Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx> --- Will allow a cleanup of a number of drivers ... that parsing code has irked me for a while now. But for now I'll leave it to the driver maintainers to use this new function :) include/net/mac80211.h | 42 ++++++++++++++++++++++++++++++++++-------- net/mac80211/tx.c | 17 ++++++++++++++--- 2 files changed, 48 insertions(+), 11 deletions(-) --- wireless-testing.orig/include/net/mac80211.h 2009-10-29 08:26:31.000000000 +0100 +++ wireless-testing/include/net/mac80211.h 2009-10-29 08:27:27.000000000 +0100 @@ -1743,19 +1743,45 @@ void ieee80211_tx_status_irqsafe(struct struct sk_buff *skb); /** - * ieee80211_beacon_get - beacon generation function + * ieee80211_beacon_get_tim - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * @tim_offset: pointer to variable that will receive the TIM IE offset. + * Set to 0 if invalid (in non-AP modes). + * @tim_length: pointer to variable that will receive the TIM IE length, + * (including the ID and length bytes!). + * Set to 0 if invalid (in non-AP modes). + * + * If the driver implements beaconing modes, it must use this function to + * obtain the beacon frame/template. * * If the beacon frames are generated by the host system (i.e., not in - * hardware/firmware), the low-level driver uses this function to receive - * the next beacon frame from the 802.11 code. The low-level is responsible - * for calling this function before beacon data is needed (e.g., based on - * hardware interrupt). Returned skb is used only once and low-level driver - * is responsible for freeing it. + * hardware/firmware), the driver uses this function to get each beacon + * frame from mac80211 -- it is responsible for calling this function + * before the beacon is needed (e.g. based on hardware interrupt). + * + * If the beacon frames are generated by the device, then the driver + * must use the returned beacon as the template and change the TIM IE + * according to the current DTIM parameters/TIM bitmap. + * + * The driver is responsible for freeing the returned skb. + */ +struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 *tim_offset, u16 *tim_length); + +/** + * ieee80211_beacon_get - beacon generation function + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. + * + * See ieee80211_beacon_get_tim(). */ -struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); +static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + return ieee80211_beacon_get_tim(hw, vif, NULL, NULL); +} /** * ieee80211_rts_get - RTS frame generation function --- wireless-testing.orig/net/mac80211/tx.c 2009-10-29 08:26:31.000000000 +0100 +++ wireless-testing/net/mac80211/tx.c 2009-10-29 08:27:27.000000000 +0100 @@ -2012,8 +2012,9 @@ static void ieee80211_beacon_add_tim(str } } -struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 *tim_offset, u16 *tim_length) { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb = NULL; @@ -2030,6 +2031,11 @@ struct sk_buff *ieee80211_beacon_get(str sdata = vif_to_sdata(vif); + if (tim_offset) + *tim_offset = 0; + if (tim_length) + *tim_length = 0; + if (sdata->vif.type == NL80211_IFTYPE_AP) { ap = &sdata->u.ap; beacon = rcu_dereference(ap->beacon); @@ -2065,6 +2071,11 @@ struct sk_buff *ieee80211_beacon_get(str spin_unlock_irqrestore(&local->sta_lock, flags); } + if (tim_offset) + *tim_offset = beacon->head_len; + if (tim_length) + *tim_length = skb->len - beacon->head_len; + if (beacon->tail) memcpy(skb_put(skb, beacon->tail_len), beacon->tail, beacon->tail_len); @@ -2141,7 +2152,7 @@ struct sk_buff *ieee80211_beacon_get(str rcu_read_unlock(); return skb; } -EXPORT_SYMBOL(ieee80211_beacon_get); +EXPORT_SYMBOL(ieee80211_beacon_get_tim); void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const void *frame, size_t frame_len, -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html