aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/sta_info.c100
-rw-r--r--net/mac80211/tx.c3
3 files changed, 92 insertions, 12 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 674b23ea14d7..da3206450192 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1272,6 +1272,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
1272 struct ieee80211_hdr *hdr, const u8 *tsc, 1272 struct ieee80211_hdr *hdr, const u8 *tsc,
1273 gfp_t gfp); 1273 gfp_t gfp);
1274void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); 1274void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
1275void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
1275void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); 1276void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
1276void ieee802_11_parse_elems(u8 *start, size_t len, 1277void ieee802_11_parse_elems(u8 *start, size_t len,
1277 struct ieee802_11_elems *elems); 1278 struct ieee802_11_elems *elems);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index f9079e478f77..d9cb56f548a9 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -24,6 +24,7 @@
24#include "sta_info.h" 24#include "sta_info.h"
25#include "debugfs_sta.h" 25#include "debugfs_sta.h"
26#include "mesh.h" 26#include "mesh.h"
27#include "wme.h"
27 28
28/** 29/**
29 * DOC: STA information lifetime rules 30 * DOC: STA information lifetime rules
@@ -247,10 +248,16 @@ static void sta_unblock(struct work_struct *wk)
247 ieee80211_sta_ps_deliver_wakeup(sta); 248 ieee80211_sta_ps_deliver_wakeup(sta);
248 else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) { 249 else if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) {
249 clear_sta_flags(sta, WLAN_STA_PS_DRIVER); 250 clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
251
252 local_bh_disable();
250 ieee80211_sta_ps_deliver_poll_response(sta); 253 ieee80211_sta_ps_deliver_poll_response(sta);
254 local_bh_enable();
251 } else if (test_and_clear_sta_flags(sta, WLAN_STA_UAPSD)) { 255 } else if (test_and_clear_sta_flags(sta, WLAN_STA_UAPSD)) {
252 clear_sta_flags(sta, WLAN_STA_PS_DRIVER); 256 clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
257
258 local_bh_disable();
253 ieee80211_sta_ps_deliver_uapsd(sta); 259 ieee80211_sta_ps_deliver_uapsd(sta);
260 local_bh_enable();
254 } else 261 } else
255 clear_sta_flags(sta, WLAN_STA_PS_DRIVER); 262 clear_sta_flags(sta, WLAN_STA_PS_DRIVER);
256} 263}
@@ -1157,6 +1164,70 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
1157#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ 1164#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
1158} 1165}
1159 1166
1167static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
1168 struct sta_info *sta, int tid,
1169 bool uapsd)
1170{
1171 struct ieee80211_local *local = sdata->local;
1172 struct ieee80211_qos_hdr *nullfunc;
1173 struct sk_buff *skb;
1174 int size = sizeof(*nullfunc);
1175 __le16 fc;
1176 bool qos = test_sta_flags(sta, WLAN_STA_WME);
1177 struct ieee80211_tx_info *info;
1178
1179 if (qos) {
1180 fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
1181 IEEE80211_STYPE_QOS_NULLFUNC |
1182 IEEE80211_FCTL_FROMDS);
1183 } else {
1184 size -= 2;
1185 fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
1186 IEEE80211_STYPE_NULLFUNC |
1187 IEEE80211_FCTL_FROMDS);
1188 }
1189
1190 skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
1191 if (!skb)
1192 return;
1193
1194 skb_reserve(skb, local->hw.extra_tx_headroom);
1195
1196 nullfunc = (void *) skb_put(skb, size);
1197 nullfunc->frame_control = fc;
1198 nullfunc->duration_id = 0;
1199 memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
1200 memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
1201 memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
1202
1203 if (qos) {
1204 skb->priority = tid;
1205
1206 skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
1207
1208 nullfunc->qos_ctrl = cpu_to_le16(tid);
1209
1210 if (uapsd)
1211 nullfunc->qos_ctrl |=
1212 cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
1213 }
1214
1215 info = IEEE80211_SKB_CB(skb);
1216
1217 /*
1218 * Tell TX path to send this frame even though the
1219 * STA may still remain is PS mode after this frame
1220 * exchange.
1221 */
1222 info->flags |= IEEE80211_TX_CTL_POLL_RESPONSE;
1223
1224 if (uapsd)
1225 info->flags |= IEEE80211_TX_STATUS_EOSP |
1226 IEEE80211_TX_CTL_REQ_TX_STATUS;
1227
1228 ieee80211_xmit(sdata, skb);
1229}
1230
1160static void 1231static void
1161ieee80211_sta_ps_deliver_response(struct sta_info *sta, 1232ieee80211_sta_ps_deliver_response(struct sta_info *sta,
1162 int n_frames, u8 ignored_acs, 1233 int n_frames, u8 ignored_acs,
@@ -1228,19 +1299,28 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
1228 } 1299 }
1229 1300
1230 if (!found) { 1301 if (!found) {
1231#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 1302 int tid;
1303
1232 /* 1304 /*
1233 * FIXME: This can be the result of a race condition between 1305 * For PS-Poll, this can only happen due to a race condition
1234 * us expiring a frame and the station polling for it. 1306 * when we set the TIM bit and the station notices it, but
1235 * Should we send it a null-func frame indicating we 1307 * before it can poll for the frame we expire it.
1236 * have nothing buffered for it? 1308 *
1309 * For uAPSD, this is said in the standard (11.2.1.5 h):
1310 * At each unscheduled SP for a non-AP STA, the AP shall
1311 * attempt to transmit at least one MSDU or MMPDU, but no
1312 * more than the value specified in the Max SP Length field
1313 * in the QoS Capability element from delivery-enabled ACs,
1314 * that are destined for the non-AP STA.
1315 *
1316 * Since we have no other MSDU/MMPDU, transmit a QoS null frame.
1237 */ 1317 */
1238 if (reason == IEEE80211_FRAME_RELEASE_PSPOLL)
1239 printk(KERN_DEBUG "%s: STA %pM sent PS Poll even "
1240 "though there are no buffered frames for it\n",
1241 sdata->name, sta->sta.addr);
1242#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
1243 1318
1319 /* This will evaluate to 1, 3, 5 or 7. */
1320 tid = 7 - ((ffs(~ignored_acs) - 1) << 1);
1321
1322 ieee80211_send_null_response(sdata, sta, tid,
1323 reason == IEEE80211_FRAME_RELEASE_UAPSD);
1244 return; 1324 return;
1245 } 1325 }
1246 1326
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a0676d39fe8f..5bf91c43c88c 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1520,8 +1520,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
1520 return 0; 1520 return 0;
1521} 1521}
1522 1522
1523static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, 1523void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
1524 struct sk_buff *skb)
1525{ 1524{
1526 struct ieee80211_local *local = sdata->local; 1525 struct ieee80211_local *local = sdata->local;
1527 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1526 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);