mac80211: Provide ieee80211_beacon_get_template API

Add a new API ieee80211_beacon_get_template, which doesn't
affect DTIM counter and should be used if the device generates beacon
frames, and new beacon template is needed. In addition set the offsets
to TIM IE for MESH interface.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Andrei Otcheretianski 2014-05-09 14:11:49 +03:00 committed by Johannes Berg
parent 0d06d9ba93
commit 6ec8c332a0
2 changed files with 94 additions and 29 deletions

View File

@ -3411,6 +3411,39 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
*/ */
void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets);
/**
* struct ieee80211_mutable_offsets - mutable beacon offsets
* @tim_offset: position of TIM element
* @tim_length: size of TIM element
*/
struct ieee80211_mutable_offsets {
u16 tim_offset;
u16 tim_length;
};
/**
* ieee80211_beacon_get_template - beacon template generation function
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @offs: &struct ieee80211_mutable_offsets pointer to struct that will
* receive the offsets that may be updated by the driver.
*
* If the driver implements beaconing modes, it must use this function to
* obtain the beacon template.
*
* This function should be used if the beacon frames are generated by the
* device, and then the driver must use the returned beacon as the template
* The driver is responsible to update the DTIM count.
*
* The driver is responsible for freeing the returned skb.
*
* Return: The beacon template. %NULL on error.
*/
struct sk_buff *
ieee80211_beacon_get_template(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_mutable_offsets *offs);
/** /**
* ieee80211_beacon_get_tim - beacon generation function * ieee80211_beacon_get_tim - beacon generation function
* @hw: pointer obtained from ieee80211_alloc_hw(). * @hw: pointer obtained from ieee80211_alloc_hw().
@ -3422,16 +3455,12 @@ void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets);
* Set to 0 if invalid (in non-AP modes). * Set to 0 if invalid (in non-AP modes).
* *
* If the driver implements beaconing modes, it must use this function to * If the driver implements beaconing modes, it must use this function to
* obtain the beacon frame/template. * obtain the beacon frame.
* *
* If the beacon frames are generated by the host system (i.e., not in * If the beacon frames are generated by the host system (i.e., not in
* hardware/firmware), the driver uses this function to get each beacon * hardware/firmware), the driver uses this function to get each beacon
* frame from mac80211 -- it is responsible for calling this function * frame from mac80211 -- it is responsible for calling this function exactly
* before the beacon is needed (e.g. based on hardware interrupt). * once 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. * The driver is responsible for freeing the returned skb.
* *

View File

@ -2328,7 +2328,8 @@ void ieee80211_tx_pending(unsigned long data)
/* functions for drivers to get certain frames */ /* functions for drivers to get certain frames */
static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
struct ps_data *ps, struct sk_buff *skb) struct ps_data *ps, struct sk_buff *skb,
bool is_template)
{ {
u8 *pos, *tim; u8 *pos, *tim;
int aid0 = 0; int aid0 = 0;
@ -2341,11 +2342,12 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
* checking byte-for-byte */ * checking byte-for-byte */
have_bits = !bitmap_empty((unsigned long *)ps->tim, have_bits = !bitmap_empty((unsigned long *)ps->tim,
IEEE80211_MAX_AID+1); IEEE80211_MAX_AID+1);
if (!is_template) {
if (ps->dtim_count == 0) if (ps->dtim_count == 0)
ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1; ps->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
else else
ps->dtim_count--; ps->dtim_count--;
}
tim = pos = (u8 *) skb_put(skb, 6); tim = pos = (u8 *) skb_put(skb, 6);
*pos++ = WLAN_EID_TIM; *pos++ = WLAN_EID_TIM;
@ -2391,7 +2393,8 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
} }
static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
struct ps_data *ps, struct sk_buff *skb) struct ps_data *ps, struct sk_buff *skb,
bool is_template)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
@ -2403,10 +2406,10 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
* of the tim bitmap in mac80211 and the driver. * of the tim bitmap in mac80211 and the driver.
*/ */
if (local->tim_in_locked_section) { if (local->tim_in_locked_section) {
__ieee80211_beacon_add_tim(sdata, ps, skb); __ieee80211_beacon_add_tim(sdata, ps, skb, is_template);
} else { } else {
spin_lock_bh(&local->tim_lock); spin_lock_bh(&local->tim_lock);
__ieee80211_beacon_add_tim(sdata, ps, skb); __ieee80211_beacon_add_tim(sdata, ps, skb, is_template);
spin_unlock_bh(&local->tim_lock); spin_unlock_bh(&local->tim_lock);
} }
@ -2536,9 +2539,11 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
} }
EXPORT_SYMBOL(ieee80211_csa_is_complete); EXPORT_SYMBOL(ieee80211_csa_is_complete);
struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, static struct sk_buff *
struct ieee80211_vif *vif, __ieee80211_beacon_get(struct ieee80211_hw *hw,
u16 *tim_offset, u16 *tim_length) struct ieee80211_vif *vif,
struct ieee80211_mutable_offsets *offs,
bool is_template)
{ {
struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_local *local = hw_to_local(hw);
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
@ -2556,10 +2561,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
if (!ieee80211_sdata_running(sdata) || !chanctx_conf) if (!ieee80211_sdata_running(sdata) || !chanctx_conf)
goto out; goto out;
if (tim_offset) if (offs)
*tim_offset = 0; memset(offs, 0, sizeof(*offs));
if (tim_length)
*tim_length = 0;
if (sdata->vif.type == NL80211_IFTYPE_AP) { if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_if_ap *ap = &sdata->u.ap; struct ieee80211_if_ap *ap = &sdata->u.ap;
@ -2584,12 +2587,13 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
memcpy(skb_put(skb, beacon->head_len), beacon->head, memcpy(skb_put(skb, beacon->head_len), beacon->head,
beacon->head_len); beacon->head_len);
ieee80211_beacon_add_tim(sdata, &ap->ps, skb); ieee80211_beacon_add_tim(sdata, &ap->ps, skb,
is_template);
if (tim_offset) if (offs) {
*tim_offset = beacon->head_len; offs->tim_offset = beacon->head_len;
if (tim_length) offs->tim_length = skb->len - beacon->head_len;
*tim_length = skb->len - beacon->head_len; }
if (beacon->tail) if (beacon->tail)
memcpy(skb_put(skb, beacon->tail_len), memcpy(skb_put(skb, beacon->tail_len),
@ -2641,7 +2645,13 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
goto out; goto out;
skb_reserve(skb, local->tx_headroom); skb_reserve(skb, local->tx_headroom);
memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len); memcpy(skb_put(skb, bcn->head_len), bcn->head, bcn->head_len);
ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb); ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb, is_template);
if (offs) {
offs->tim_offset = bcn->head_len;
offs->tim_length = skb->len - bcn->head_len;
}
memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len); memcpy(skb_put(skb, bcn->tail_len), bcn->tail, bcn->tail_len);
} else { } else {
WARN_ON(1); WARN_ON(1);
@ -2678,6 +2688,32 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
out: out:
rcu_read_unlock(); rcu_read_unlock();
return skb; return skb;
}
struct sk_buff *
ieee80211_beacon_get_template(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_mutable_offsets *offs)
{
return __ieee80211_beacon_get(hw, vif, offs, true);
}
EXPORT_SYMBOL(ieee80211_beacon_get_template);
struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u16 *tim_offset, u16 *tim_length)
{
struct ieee80211_mutable_offsets offs = {};
struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false);
if (tim_offset)
*tim_offset = offs.tim_offset;
if (tim_length)
*tim_length = offs.tim_length;
return bcn;
} }
EXPORT_SYMBOL(ieee80211_beacon_get_tim); EXPORT_SYMBOL(ieee80211_beacon_get_tim);