aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211_sta.c
diff options
context:
space:
mode:
authorRon Rindjunsky <ron.rindjunsky@intel.com>2008-01-28 07:07:17 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-02-29 15:19:14 -0500
commiteadc8d9e9047266a8914eb2ed4d36e797ce540d1 (patch)
treed4abb405e46c279aae81f32106000090f70e9a53 /net/mac80211/ieee80211_sta.c
parent80656c20315558a9bc5c5b7f7c6949fa72277afd (diff)
mac80211: A-MPDU Tx adding basic functionality
This patch adds the following abilities to mac80211: - start A-MPDU Tx session - stop A-MPDU Tx session - call backs to start/stop A-MPDU Tx session - sending addBA request - processing addBA response Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/ieee80211_sta.c')
-rw-r--r--net/mac80211/ieee80211_sta.c182
1 files changed, 180 insertions, 2 deletions
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index d5d5610db1bd..c4d57346eacf 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -1045,6 +1045,58 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
1045 return; 1045 return;
1046} 1046}
1047 1047
1048void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
1049 u16 tid, u8 dialog_token, u16 start_seq_num,
1050 u16 agg_size, u16 timeout)
1051{
1052 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1053 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1054 struct ieee80211_if_sta *ifsta = &sdata->u.sta;
1055 struct sk_buff *skb;
1056 struct ieee80211_mgmt *mgmt;
1057 u16 capab;
1058
1059 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
1060 sizeof(mgmt->u.action.u.addba_req));
1061
1062
1063 if (!skb) {
1064 printk(KERN_ERR "%s: failed to allocate buffer "
1065 "for addba request frame\n", dev->name);
1066 return;
1067 }
1068 skb_reserve(skb, local->hw.extra_tx_headroom);
1069 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
1070 memset(mgmt, 0, 24);
1071 memcpy(mgmt->da, da, ETH_ALEN);
1072 memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
1073 if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
1074 memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
1075 else
1076 memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
1077
1078 mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
1079 IEEE80211_STYPE_ACTION);
1080
1081 skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
1082
1083 mgmt->u.action.category = WLAN_CATEGORY_BACK;
1084 mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
1085
1086 mgmt->u.action.u.addba_req.dialog_token = dialog_token;
1087 capab = (u16)(1 << 1); /* bit 1 aggregation policy */
1088 capab |= (u16)(tid << 2); /* bit 5:2 TID number */
1089 capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
1090
1091 mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
1092
1093 mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
1094 mgmt->u.action.u.addba_req.start_seq_num =
1095 cpu_to_le16(start_seq_num << 4);
1096
1097 ieee80211_sta_tx(dev, skb, 0);
1098}
1099
1048static void ieee80211_sta_process_addba_request(struct net_device *dev, 1100static void ieee80211_sta_process_addba_request(struct net_device *dev,
1049 struct ieee80211_mgmt *mgmt, 1101 struct ieee80211_mgmt *mgmt,
1050 size_t len) 1102 size_t len)
@@ -1156,8 +1208,80 @@ end_no_lock:
1156 sta_info_put(sta); 1208 sta_info_put(sta);
1157} 1209}
1158 1210
1159static void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, 1211static void ieee80211_sta_process_addba_resp(struct net_device *dev,
1160 u16 initiator, u16 reason_code) 1212 struct ieee80211_mgmt *mgmt,
1213 size_t len)
1214{
1215 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1216 struct ieee80211_hw *hw = &local->hw;
1217 struct sta_info *sta;
1218 u16 capab;
1219 u16 tid;
1220 u8 *state;
1221
1222 sta = sta_info_get(local, mgmt->sa);
1223 if (!sta)
1224 return;
1225
1226 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
1227 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
1228
1229 state = &sta->ampdu_mlme.tid_tx[tid].state;
1230
1231 spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
1232
1233 if (mgmt->u.action.u.addba_resp.dialog_token !=
1234 sta->ampdu_mlme.tid_tx[tid].dialog_token) {
1235 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
1236#ifdef CONFIG_MAC80211_HT_DEBUG
1237 printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
1238#endif /* CONFIG_MAC80211_HT_DEBUG */
1239 sta_info_put(sta);
1240 return;
1241 }
1242
1243 del_timer_sync(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer);
1244#ifdef CONFIG_MAC80211_HT_DEBUG
1245 printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
1246#endif /* CONFIG_MAC80211_HT_DEBUG */
1247 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
1248 == WLAN_STATUS_SUCCESS) {
1249 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
1250 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
1251 printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
1252 "%d\n", *state);
1253 sta_info_put(sta);
1254 return;
1255 }
1256
1257 if (*state & HT_ADDBA_RECEIVED_MSK)
1258 printk(KERN_DEBUG "double addBA response\n");
1259
1260 *state |= HT_ADDBA_RECEIVED_MSK;
1261 sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0;
1262
1263 if (*state == HT_AGG_STATE_OPERATIONAL) {
1264 printk(KERN_DEBUG "Aggregation on for tid %d \n", tid);
1265 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
1266 }
1267
1268 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
1269 printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
1270 } else {
1271 printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
1272
1273 sta->ampdu_mlme.tid_tx[tid].addba_req_num++;
1274 /* this will allow the state check in stop_BA_session */
1275 *state = HT_AGG_STATE_OPERATIONAL;
1276 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
1277 ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
1278 WLAN_BACK_INITIATOR);
1279 }
1280 sta_info_put(sta);
1281}
1282
1283void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
1284 u16 initiator, u16 reason_code)
1161{ 1285{
1162 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 1286 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1163 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1287 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1259,6 +1383,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
1259 sta_info_put(sta); 1383 sta_info_put(sta);
1260} 1384}
1261 1385
1386
1262static void ieee80211_sta_process_delba(struct net_device *dev, 1387static void ieee80211_sta_process_delba(struct net_device *dev,
1263 struct ieee80211_mgmt *mgmt, size_t len) 1388 struct ieee80211_mgmt *mgmt, size_t len)
1264{ 1389{
@@ -1290,6 +1415,53 @@ static void ieee80211_sta_process_delba(struct net_device *dev,
1290} 1415}
1291 1416
1292/* 1417/*
1418 * After sending add Block Ack request we activated a timer until
1419 * add Block Ack response will arrive from the recipient.
1420 * If this timer expires sta_addba_resp_timer_expired will be executed.
1421 */
1422void sta_addba_resp_timer_expired(unsigned long data)
1423{
1424 /* not an elegant detour, but there is no choice as the timer passes
1425 * only one argument, and both sta_info and TID are needed, so init
1426 * flow in sta_info_add gives the TID as data, while the timer_to_id
1427 * array gives the sta through container_of */
1428 u16 tid = *(int *)data;
1429 struct sta_info *temp_sta = container_of((void *)data,
1430 struct sta_info, timer_to_tid[tid]);
1431
1432 struct ieee80211_local *local = temp_sta->local;
1433 struct ieee80211_hw *hw = &local->hw;
1434 struct sta_info *sta;
1435 u8 *state;
1436
1437 sta = sta_info_get(local, temp_sta->addr);
1438 if (!sta)
1439 return;
1440
1441 state = &sta->ampdu_mlme.tid_tx[tid].state;
1442 /* check if the TID waits for addBA response */
1443 spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
1444 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
1445 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
1446 *state = HT_AGG_STATE_IDLE;
1447 printk(KERN_DEBUG "timer expired on tid %d but we are not "
1448 "expecting addBA response there", tid);
1449 goto timer_expired_exit;
1450 }
1451
1452 printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
1453
1454 /* go through the state check in stop_BA_session */
1455 *state = HT_AGG_STATE_OPERATIONAL;
1456 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
1457 ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
1458 WLAN_BACK_INITIATOR);
1459
1460timer_expired_exit:
1461 sta_info_put(sta);
1462}
1463
1464/*
1293 * After receiving Block Ack Request (BAR) we activated a 1465 * After receiving Block Ack Request (BAR) we activated a
1294 * timer after each frame arrives from the originator. 1466 * timer after each frame arrives from the originator.
1295 * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. 1467 * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
@@ -2236,6 +2408,12 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
2236 break; 2408 break;
2237 ieee80211_sta_process_addba_request(dev, mgmt, len); 2409 ieee80211_sta_process_addba_request(dev, mgmt, len);
2238 break; 2410 break;
2411 case WLAN_ACTION_ADDBA_RESP:
2412 if (len < (IEEE80211_MIN_ACTION_SIZE +
2413 sizeof(mgmt->u.action.u.addba_resp)))
2414 break;
2415 ieee80211_sta_process_addba_resp(dev, mgmt, len);
2416 break;
2239 case WLAN_ACTION_DELBA: 2417 case WLAN_ACTION_DELBA:
2240 if (len < (IEEE80211_MIN_ACTION_SIZE + 2418 if (len < (IEEE80211_MIN_ACTION_SIZE +
2241 sizeof(mgmt->u.action.u.delba))) 2419 sizeof(mgmt->u.action.u.delba)))