aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-09-29 10:04:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-09-30 15:57:21 -0400
commit40b96408831f038b1a6b45e8b22cd050f82a3896 (patch)
treec8ea29b9d01ba28d484cf2d4c4a0cd576d598b79 /net/mac80211/sta_info.c
parent5bade101eceedb716e39bd35b2928c465e3fbd10 (diff)
mac80211: explicitly notify drivers of frame release
iwlwifi needs to know the number of frames that are going to be sent to a station while it is asleep so it can properly handle the uCode blocking of that station. Before uAPSD, we got by by telling the device that a single frame was going to be released whenever we encountered IEEE80211_TX_CTL_POLL_RESPONSE. With uAPSD, however, that is no longer possible since there could be more than a single frame. To support this model, add a new callback to notify drivers when frames are going to be released. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r--net/mac80211/sta_info.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a00358224cd5..907b42081f3c 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1169,7 +1169,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
1169 1169
1170static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, 1170static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
1171 struct sta_info *sta, int tid, 1171 struct sta_info *sta, int tid,
1172 bool uapsd) 1172 enum ieee80211_frame_release_type reason)
1173{ 1173{
1174 struct ieee80211_local *local = sdata->local; 1174 struct ieee80211_local *local = sdata->local;
1175 struct ieee80211_qos_hdr *nullfunc; 1175 struct ieee80211_qos_hdr *nullfunc;
@@ -1210,7 +1210,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
1210 1210
1211 nullfunc->qos_ctrl = cpu_to_le16(tid); 1211 nullfunc->qos_ctrl = cpu_to_le16(tid);
1212 1212
1213 if (uapsd) 1213 if (reason == IEEE80211_FRAME_RELEASE_UAPSD)
1214 nullfunc->qos_ctrl |= 1214 nullfunc->qos_ctrl |=
1215 cpu_to_le16(IEEE80211_QOS_CTL_EOSP); 1215 cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
1216 } 1216 }
@@ -1227,6 +1227,8 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
1227 IEEE80211_TX_STATUS_EOSP | 1227 IEEE80211_TX_STATUS_EOSP |
1228 IEEE80211_TX_CTL_REQ_TX_STATUS; 1228 IEEE80211_TX_CTL_REQ_TX_STATUS;
1229 1229
1230 drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false);
1231
1230 ieee80211_xmit(sdata, skb); 1232 ieee80211_xmit(sdata, skb);
1231} 1233}
1232 1234
@@ -1324,20 +1326,24 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
1324 /* This will evaluate to 1, 3, 5 or 7. */ 1326 /* This will evaluate to 1, 3, 5 or 7. */
1325 tid = 7 - ((ffs(~ignored_acs) - 1) << 1); 1327 tid = 7 - ((ffs(~ignored_acs) - 1) << 1);
1326 1328
1327 ieee80211_send_null_response(sdata, sta, tid, 1329 ieee80211_send_null_response(sdata, sta, tid, reason);
1328 reason == IEEE80211_FRAME_RELEASE_UAPSD);
1329 return; 1330 return;
1330 } 1331 }
1331 1332
1332 if (!driver_release_tids) { 1333 if (!driver_release_tids) {
1333 struct sk_buff_head pending; 1334 struct sk_buff_head pending;
1334 struct sk_buff *skb; 1335 struct sk_buff *skb;
1336 int num = 0;
1337 u16 tids = 0;
1335 1338
1336 skb_queue_head_init(&pending); 1339 skb_queue_head_init(&pending);
1337 1340
1338 while ((skb = __skb_dequeue(&frames))) { 1341 while ((skb = __skb_dequeue(&frames))) {
1339 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1342 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1340 struct ieee80211_hdr *hdr = (void *) skb->data; 1343 struct ieee80211_hdr *hdr = (void *) skb->data;
1344 u8 *qoshdr = NULL;
1345
1346 num++;
1341 1347
1342 /* 1348 /*
1343 * Tell TX path to send this frame even though the 1349 * Tell TX path to send this frame even though the
@@ -1357,19 +1363,29 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
1357 hdr->frame_control |= 1363 hdr->frame_control |=
1358 cpu_to_le16(IEEE80211_FCTL_MOREDATA); 1364 cpu_to_le16(IEEE80211_FCTL_MOREDATA);
1359 1365
1366 if (ieee80211_is_data_qos(hdr->frame_control) ||
1367 ieee80211_is_qos_nullfunc(hdr->frame_control))
1368 qoshdr = ieee80211_get_qos_ctl(hdr);
1369
1370 /* set EOSP for the frame */
1360 if (reason == IEEE80211_FRAME_RELEASE_UAPSD && 1371 if (reason == IEEE80211_FRAME_RELEASE_UAPSD &&
1361 skb_queue_empty(&frames)) { 1372 qoshdr && skb_queue_empty(&frames))
1362 /* set EOSP for the frame */ 1373 *qoshdr |= IEEE80211_QOS_CTL_EOSP;
1363 u8 *p = ieee80211_get_qos_ctl(hdr);
1364 *p |= IEEE80211_QOS_CTL_EOSP;
1365 }
1366 1374
1367 info->flags |= IEEE80211_TX_STATUS_EOSP | 1375 info->flags |= IEEE80211_TX_STATUS_EOSP |
1368 IEEE80211_TX_CTL_REQ_TX_STATUS; 1376 IEEE80211_TX_CTL_REQ_TX_STATUS;
1369 1377
1378 if (qoshdr)
1379 tids |= BIT(*qoshdr & IEEE80211_QOS_CTL_TID_MASK);
1380 else
1381 tids |= BIT(0);
1382
1370 __skb_queue_tail(&pending, skb); 1383 __skb_queue_tail(&pending, skb);
1371 } 1384 }
1372 1385
1386 drv_allow_buffered_frames(local, sta, tids, num,
1387 reason, more_data);
1388
1373 ieee80211_add_pending_skbs(local, &pending); 1389 ieee80211_add_pending_skbs(local, &pending);
1374 1390
1375 sta_info_recalc_tim(sta); 1391 sta_info_recalc_tim(sta);