diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 82 |
1 files changed, 66 insertions, 16 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 4d85672f0b8f..b3f841948c09 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -1157,8 +1157,10 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | |||
1157 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 1157 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
1158 | struct ieee80211_local *local = sdata->local; | 1158 | struct ieee80211_local *local = sdata->local; |
1159 | struct sk_buff *skb = NULL; | 1159 | struct sk_buff *skb = NULL; |
1160 | bool found = false; | ||
1160 | bool more_data = false; | 1161 | bool more_data = false; |
1161 | int ac; | 1162 | int ac; |
1163 | unsigned long driver_release_tids = 0; | ||
1162 | u8 ignore_for_response = sta->sta.uapsd_queues; | 1164 | u8 ignore_for_response = sta->sta.uapsd_queues; |
1163 | 1165 | ||
1164 | /* | 1166 | /* |
@@ -1173,19 +1175,40 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | |||
1173 | * Get response frame and more data bit for it. | 1175 | * Get response frame and more data bit for it. |
1174 | */ | 1176 | */ |
1175 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 1177 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
1178 | unsigned long tids; | ||
1179 | |||
1176 | if (ignore_for_response & BIT(ac)) | 1180 | if (ignore_for_response & BIT(ac)) |
1177 | continue; | 1181 | continue; |
1178 | 1182 | ||
1179 | if (!skb) { | 1183 | tids = ieee80211_tids_for_ac(ac); |
1180 | skb = skb_dequeue(&sta->tx_filtered[ac]); | 1184 | |
1181 | if (!skb) { | 1185 | if (!found) { |
1182 | skb = skb_dequeue(&sta->ps_tx_buf[ac]); | 1186 | driver_release_tids = sta->driver_buffered_tids & tids; |
1187 | if (driver_release_tids) { | ||
1188 | found = true; | ||
1189 | } else { | ||
1190 | skb = skb_dequeue(&sta->tx_filtered[ac]); | ||
1191 | if (!skb) { | ||
1192 | skb = skb_dequeue(&sta->ps_tx_buf[ac]); | ||
1193 | if (skb) | ||
1194 | local->total_ps_buffered--; | ||
1195 | } | ||
1183 | if (skb) | 1196 | if (skb) |
1184 | local->total_ps_buffered--; | 1197 | found = true; |
1185 | } | 1198 | } |
1186 | } | ||
1187 | 1199 | ||
1188 | /* FIXME: take into account driver-buffered frames */ | 1200 | /* |
1201 | * If the driver has data on more than one TID then | ||
1202 | * certainly there's more data if we release just a | ||
1203 | * single frame now (from a single TID). | ||
1204 | */ | ||
1205 | if (hweight16(driver_release_tids) > 1) { | ||
1206 | more_data = true; | ||
1207 | driver_release_tids = | ||
1208 | BIT(ffs(driver_release_tids) - 1); | ||
1209 | break; | ||
1210 | } | ||
1211 | } | ||
1189 | 1212 | ||
1190 | if (!skb_queue_empty(&sta->tx_filtered[ac]) || | 1213 | if (!skb_queue_empty(&sta->tx_filtered[ac]) || |
1191 | !skb_queue_empty(&sta->ps_tx_buf[ac])) { | 1214 | !skb_queue_empty(&sta->ps_tx_buf[ac])) { |
@@ -1194,6 +1217,22 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | |||
1194 | } | 1217 | } |
1195 | } | 1218 | } |
1196 | 1219 | ||
1220 | if (!found) { | ||
1221 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | ||
1222 | /* | ||
1223 | * FIXME: This can be the result of a race condition between | ||
1224 | * us expiring a frame and the station polling for it. | ||
1225 | * Should we send it a null-func frame indicating we | ||
1226 | * have nothing buffered for it? | ||
1227 | */ | ||
1228 | printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " | ||
1229 | "though there are no buffered frames for it\n", | ||
1230 | sdata->name, sta->sta.addr); | ||
1231 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | ||
1232 | |||
1233 | return; | ||
1234 | } | ||
1235 | |||
1197 | if (skb) { | 1236 | if (skb) { |
1198 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1237 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1199 | struct ieee80211_hdr *hdr = | 1238 | struct ieee80211_hdr *hdr = |
@@ -1220,18 +1259,29 @@ void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta) | |||
1220 | ieee80211_add_pending_skb(local, skb); | 1259 | ieee80211_add_pending_skb(local, skb); |
1221 | 1260 | ||
1222 | sta_info_recalc_tim(sta); | 1261 | sta_info_recalc_tim(sta); |
1223 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | ||
1224 | } else { | 1262 | } else { |
1225 | /* | 1263 | /* |
1226 | * FIXME: This can be the result of a race condition between | 1264 | * We need to release a frame that is buffered somewhere in the |
1227 | * us expiring a frame and the station polling for it. | 1265 | * driver ... it'll have to handle that. |
1228 | * Should we send it a null-func frame indicating we | 1266 | * Note that, as per the comment above, it'll also have to see |
1229 | * have nothing buffered for it? | 1267 | * if there is more than just one frame on the specific TID that |
1268 | * we're releasing from, and it needs to set the more-data bit | ||
1269 | * accordingly if we tell it that there's no more data. If we do | ||
1270 | * tell it there's more data, then of course the more-data bit | ||
1271 | * needs to be set anyway. | ||
1272 | */ | ||
1273 | drv_release_buffered_frames(local, sta, driver_release_tids, | ||
1274 | 1, IEEE80211_FRAME_RELEASE_PSPOLL, | ||
1275 | more_data); | ||
1276 | |||
1277 | /* | ||
1278 | * Note that we don't recalculate the TIM bit here as it would | ||
1279 | * most likely have no effect at all unless the driver told us | ||
1280 | * that the TID became empty before returning here from the | ||
1281 | * release function. | ||
1282 | * Either way, however, when the driver tells us that the TID | ||
1283 | * became empty we'll do the TIM recalculation. | ||
1230 | */ | 1284 | */ |
1231 | printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " | ||
1232 | "though there are no buffered frames for it\n", | ||
1233 | sdata->name, sta->sta.addr); | ||
1234 | #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ | ||
1235 | } | 1285 | } |
1236 | } | 1286 | } |
1237 | 1287 | ||