Skip to content

Commit

Permalink
mac80211: make client powersave independent of interface type
Browse files Browse the repository at this point in the history
This patch prepares mac80211 for a later implementation of mesh or
ad-hoc powersave clients.
The structures related to powersave (buffer, TIM map, counters) are
moved from the AP-specific interface structure to a generic structure
that can be embedded into any interface type.
The functions related to powersave are prepared to allow easy
extension with different interface types. For example with:

+ } else if (sta->sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
+         ps = &sdata->u.mesh.ps;

Some references to the AP's beacon structure are removed where they
were obviously not used.

The patch compiles without warning and has been briefly tested as AP
interface with one client in PS mode.

Signed-off-by: Marco Porsch <marco.porsch@etit.tu-chemnitz.de>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
Marco Porsch authored and Johannes Berg committed Oct 19, 2012
1 parent 5c95b94 commit d012a60
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 74 deletions.
6 changes: 3 additions & 3 deletions net/mac80211/debugfs_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,14 +395,14 @@ __IEEE80211_IF_FILE_W(uapsd_max_sp_len);

/* AP attributes */
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);

static ssize_t ieee80211_if_fmt_num_buffered_multicast(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
{
return scnprintf(buf, buflen, "%u\n",
skb_queue_len(&sdata->u.ap.ps_bc_buf));
skb_queue_len(&sdata->u.ap.ps.bc_buf));
}
__IEEE80211_IF_FILE(num_buffered_multicast, NULL);

Expand Down
20 changes: 12 additions & 8 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,23 +280,27 @@ struct probe_resp {
u8 data[0];
};

struct ieee80211_if_ap {
struct beacon_data __rcu *beacon;
struct probe_resp __rcu *probe_resp;

struct list_head vlans;

struct ps_data {
/* yes, this looks ugly, but guarantees that we can later use
* bitmap_empty :)
* NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
struct sk_buff_head ps_bc_buf;
struct sk_buff_head bc_buf;
atomic_t num_sta_ps; /* number of stations in PS mode */
atomic_t num_mcast_sta; /* number of stations receiving multicast */
int dtim_count;
bool dtim_bc_mc;
};

struct ieee80211_if_ap {
struct beacon_data __rcu *beacon;
struct probe_resp __rcu *probe_resp;

struct list_head vlans;

struct ps_data ps;
atomic_t num_mcast_sta; /* number of stations receiving multicast */
};

struct ieee80211_if_wds {
struct sta_info *sta;
u8 remote_addr[ETH_ALEN];
Expand Down
6 changes: 3 additions & 3 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,8 +767,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
WARN_ON(!list_empty(&sdata->u.ap.vlans));

/* free all potentially still buffered bcast frames */
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps_bc_buf);
skb_queue_purge(&sdata->u.ap.ps_bc_buf);
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
skb_queue_purge(&sdata->u.ap.ps.bc_buf);
} else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
ieee80211_mgd_stop(sdata);
}
Expand Down Expand Up @@ -1171,7 +1171,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->vif.p2p = true;
/* fall through */
case NL80211_IFTYPE_AP:
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
INIT_LIST_HEAD(&sdata->u.ap.vlans);
break;
case NL80211_IFTYPE_P2P_CLIENT:
Expand Down
21 changes: 14 additions & 7 deletions net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1141,20 +1141,27 @@ ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
}

static void ap_sta_ps_start(struct sta_info *sta)
static void sta_ps_start(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct ps_data *ps;

atomic_inc(&sdata->bss->num_sta_ps);
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps;
else
return;

atomic_inc(&ps->num_sta_ps);
set_sta_flag(sta, WLAN_STA_PS_STA);
if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta);
ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
sta->sta.addr, sta->sta.aid);
}

static void ap_sta_ps_end(struct sta_info *sta)
static void sta_ps_end(struct sta_info *sta)
{
ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n",
sta->sta.addr, sta->sta.aid);
Expand All @@ -1181,9 +1188,9 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
return -EINVAL;

if (start)
ap_sta_ps_start(sta_inf);
sta_ps_start(sta_inf);
else
ap_sta_ps_end(sta_inf);
sta_ps_end(sta_inf);

return 0;
}
Expand Down Expand Up @@ -1335,10 +1342,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
*/
if (ieee80211_is_data(hdr->frame_control) &&
!ieee80211_has_pm(hdr->frame_control))
ap_sta_ps_end(sta);
sta_ps_end(sta);
} else {
if (ieee80211_has_pm(hdr->frame_control))
ap_sta_ps_start(sta);
sta_ps_start(sta);
}
}

Expand Down
43 changes: 32 additions & 11 deletions net/mac80211/sta_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ static void free_sta_work(struct work_struct *wk)
struct tid_ampdu_tx *tid_tx;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct ps_data *ps;

/*
* At this point, when being called as call_rcu callback,
Expand All @@ -107,11 +108,15 @@ static void free_sta_work(struct work_struct *wk)
*/

if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
BUG_ON(!sdata->bss);
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps;
else
return;

clear_sta_flag(sta, WLAN_STA_PS_STA);

atomic_dec(&sdata->bss->num_sta_ps);
atomic_dec(&ps->num_sta_ps);
sta_info_recalc_tim(sta);
}

Expand Down Expand Up @@ -502,22 +507,22 @@ int sta_info_insert(struct sta_info *sta)
return err;
}

static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
static inline void __bss_tim_set(u8 *tim, u16 id)
{
/*
* This format has been mandated by the IEEE specifications,
* so this line may not be changed to use the __set_bit() format.
*/
bss->tim[aid / 8] |= (1 << (aid % 8));
tim[id / 8] |= (1 << (id % 8));
}

static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
static inline void __bss_tim_clear(u8 *tim, u16 id)
{
/*
* This format has been mandated by the IEEE specifications,
* so this line may not be changed to use the __clear_bit() format.
*/
bss->tim[aid / 8] &= ~(1 << (aid % 8));
tim[id / 8] &= ~(1 << (id % 8));
}

static unsigned long ieee80211_tids_for_ac(int ac)
Expand All @@ -541,14 +546,23 @@ static unsigned long ieee80211_tids_for_ac(int ac)
void sta_info_recalc_tim(struct sta_info *sta)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_if_ap *bss = sta->sdata->bss;
struct ps_data *ps;
unsigned long flags;
bool indicate_tim = false;
u8 ignore_for_tim = sta->sta.uapsd_queues;
int ac;
u16 id;

if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
if (WARN_ON_ONCE(!sta->sdata->bss))
return;

if (WARN_ON_ONCE(!sta->sdata->bss))
ps = &sta->sdata->bss->ps;
id = sta->sta.aid;
} else {
return;
}

/* No need to do anything if the driver does all */
if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
Expand Down Expand Up @@ -587,9 +601,9 @@ void sta_info_recalc_tim(struct sta_info *sta)
spin_lock_irqsave(&local->tim_lock, flags);

if (indicate_tim)
__bss_tim_set(bss, sta->sta.aid);
__bss_tim_set(ps->tim, id);
else
__bss_tim_clear(bss, sta->sta.aid);
__bss_tim_clear(ps->tim, id);

if (local->ops->set_tim) {
local->tim_in_locked_section = true;
Expand Down Expand Up @@ -948,10 +962,17 @@ static void clear_sta_ps_flags(void *_sta)
{
struct sta_info *sta = _sta;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ps_data *ps;

if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps;
else
return;

clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
atomic_dec(&sdata->bss->num_sta_ps);
atomic_dec(&ps->num_sta_ps);
}

/* powersave support code */
Expand Down
Loading

0 comments on commit d012a60

Please sign in to comment.