aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ieee80211.h7
-rw-r--r--net/mac80211/ieee80211.c9
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/ieee80211_sta.c221
-rw-r--r--net/mac80211/sta_info.c3
5 files changed, 232 insertions, 11 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 3e641590d0c8..4d5a4c9dcba7 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -472,6 +472,13 @@ enum ieee80211_back_actioncode {
472 WLAN_ACTION_DELBA = 2, 472 WLAN_ACTION_DELBA = 2,
473}; 473};
474 474
475/* BACK (block-ack) parties */
476enum ieee80211_back_parties {
477 WLAN_BACK_RECIPIENT = 0,
478 WLAN_BACK_INITIATOR = 1,
479 WLAN_BACK_TIMER = 2,
480};
481
475/* A-MSDU 802.11n */ 482/* A-MSDU 802.11n */
476#define IEEE80211_QOS_CONTROL_A_MSDU_PRESENT 0x0080 483#define IEEE80211_QOS_CONTROL_A_MSDU_PRESENT 0x0080
477 484
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 9c14e3d303c5..2011c726f2b1 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -292,9 +292,18 @@ static int ieee80211_stop(struct net_device *dev)
292 struct ieee80211_sub_if_data *sdata; 292 struct ieee80211_sub_if_data *sdata;
293 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 293 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
294 struct ieee80211_if_init_conf conf; 294 struct ieee80211_if_init_conf conf;
295 struct sta_info *sta;
296 int i;
295 297
296 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 298 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
297 299
300 list_for_each_entry(sta, &local->sta_list, list) {
301 for (i = 0; i < STA_TID_NUM; i++)
302 ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr,
303 i, WLAN_BACK_RECIPIENT,
304 WLAN_REASON_QSTA_LEAVE_QBSS);
305 }
306
298 netif_stop_queue(dev); 307 netif_stop_queue(dev);
299 308
300 /* 309 /*
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index baf53c047127..740d69d5bbd3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -767,6 +767,9 @@ int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
767int ieee80211_ht_addt_info_ie_to_ht_bss_info( 767int ieee80211_ht_addt_info_ie_to_ht_bss_info(
768 struct ieee80211_ht_addt_info *ht_add_info_ie, 768 struct ieee80211_ht_addt_info *ht_add_info_ie,
769 struct ieee80211_ht_bss_info *bss_info); 769 struct ieee80211_ht_bss_info *bss_info);
770void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
771 u16 tid, u16 initiator, u16 reason);
772void sta_rx_agg_session_timer_expired(unsigned long data);
770/* ieee80211_iface.c */ 773/* ieee80211_iface.c */
771int ieee80211_if_add(struct net_device *dev, const char *name, 774int ieee80211_if_add(struct net_device *dev, const char *name,
772 struct net_device **new_dev, int type); 775 struct net_device **new_dev, int type);
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 5b8f484c1673..d5a7683fab3a 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -64,6 +64,11 @@
64#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C 64#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
65#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0 65#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
66 66
67/* next values represent the buffer size for A-MPDU frame.
68 * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */
69#define IEEE80211_MIN_AMPDU_BUF 0x8
70#define IEEE80211_MAX_AMPDU_BUF 0x40
71
67static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, 72static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
68 u8 *ssid, size_t ssid_len); 73 u8 *ssid, size_t ssid_len);
69static struct ieee80211_sta_bss * 74static struct ieee80211_sta_bss *
@@ -1005,7 +1010,8 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
1005 struct ieee80211_mgmt *mgmt; 1010 struct ieee80211_mgmt *mgmt;
1006 u16 capab; 1011 u16 capab;
1007 1012
1008 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); 1013 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
1014 sizeof(mgmt->u.action.u.addba_resp));
1009 if (!skb) { 1015 if (!skb) {
1010 printk(KERN_DEBUG "%s: failed to allocate buffer " 1016 printk(KERN_DEBUG "%s: failed to allocate buffer "
1011 "for addba resp frame\n", dev->name); 1017 "for addba resp frame\n", dev->name);
@@ -1047,9 +1053,14 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
1047 size_t len) 1053 size_t len)
1048{ 1054{
1049 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 1055 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1056 struct ieee80211_hw *hw = &local->hw;
1057 struct ieee80211_conf *conf = &hw->conf;
1050 struct sta_info *sta; 1058 struct sta_info *sta;
1051 u16 capab, tid, timeout, ba_policy, buf_size, status; 1059 struct tid_ampdu_rx *tid_agg_rx;
1060 u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
1052 u8 dialog_token; 1061 u8 dialog_token;
1062 int ret = -EOPNOTSUPP;
1063 DECLARE_MAC_BUF(mac);
1053 1064
1054 sta = sta_info_get(local, mgmt->sa); 1065 sta = sta_info_get(local, mgmt->sa);
1055 if (!sta) 1066 if (!sta)
@@ -1058,28 +1069,216 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
1058 /* extract session parameters from addba request frame */ 1069 /* extract session parameters from addba request frame */
1059 dialog_token = mgmt->u.action.u.addba_req.dialog_token; 1070 dialog_token = mgmt->u.action.u.addba_req.dialog_token;
1060 timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); 1071 timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
1072 start_seq_num =
1073 le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
1061 1074
1062 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); 1075 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
1063 ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; 1076 ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
1064 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; 1077 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
1065 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; 1078 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
1066 1079
1067 /* TODO - currently aggregation is declined (A-MPDU add BA request
1068 * acceptance is not obligatory by 802.11n draft), but here is
1069 * the entry point for dealing with it */
1070#ifdef MAC80211_HT_DEBUG
1071 if (net_ratelimit())
1072 printk(KERN_DEBUG "Add Block Ack request arrived,"
1073 " currently denying it\n");
1074#endif /* MAC80211_HT_DEBUG */
1075
1076 status = WLAN_STATUS_REQUEST_DECLINED; 1080 status = WLAN_STATUS_REQUEST_DECLINED;
1077 1081
1082 /* sanity check for incoming parameters:
1083 * check if configuration can support the BA policy
1084 * and if buffer size does not exceeds max value */
1085 if (((ba_policy != 1)
1086 && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA)))
1087 || (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
1088 status = WLAN_STATUS_INVALID_QOS_PARAM;
1089#ifdef CONFIG_MAC80211_HT_DEBUG
1090 if (net_ratelimit())
1091 printk(KERN_DEBUG "Block Ack Req with bad params from "
1092 "%s on tid %u. policy %d, buffer size %d\n",
1093 print_mac(mac, mgmt->sa), tid, ba_policy,
1094 buf_size);
1095#endif /* CONFIG_MAC80211_HT_DEBUG */
1096 goto end_no_lock;
1097 }
1098 /* determine default buffer size */
1099 if (buf_size == 0) {
1100 struct ieee80211_hw_mode *mode = conf->mode;
1101 buf_size = IEEE80211_MIN_AMPDU_BUF;
1102 buf_size = buf_size << mode->ht_info.ampdu_factor;
1103 }
1104
1105 tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid];
1106
1107 /* examine state machine */
1108 spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
1109
1110 if (tid_agg_rx->state != HT_AGG_STATE_IDLE) {
1111#ifdef CONFIG_MAC80211_HT_DEBUG
1112 if (net_ratelimit())
1113 printk(KERN_DEBUG "unexpected Block Ack Req from "
1114 "%s on tid %u\n",
1115 print_mac(mac, mgmt->sa), tid);
1116#endif /* CONFIG_MAC80211_HT_DEBUG */
1117 goto end;
1118 }
1119
1120 /* prepare reordering buffer */
1121 tid_agg_rx->reorder_buf =
1122 kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC);
1123 if ((!tid_agg_rx->reorder_buf) && net_ratelimit()) {
1124 printk(KERN_ERR "can not allocate reordering buffer "
1125 "to tid %d\n", tid);
1126 goto end;
1127 }
1128 memset(tid_agg_rx->reorder_buf, 0,
1129 buf_size * sizeof(struct sk_buf *));
1130
1131 if (local->ops->ampdu_action)
1132 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
1133 sta->addr, tid, start_seq_num);
1134#ifdef CONFIG_MAC80211_HT_DEBUG
1135 printk(KERN_DEBUG "Rx A-MPDU on tid %d result %d", tid, ret);
1136#endif /* CONFIG_MAC80211_HT_DEBUG */
1137
1138 if (ret) {
1139 kfree(tid_agg_rx->reorder_buf);
1140 goto end;
1141 }
1142
1143 /* change state and send addba resp */
1144 tid_agg_rx->state = HT_AGG_STATE_OPERATIONAL;
1145 tid_agg_rx->dialog_token = dialog_token;
1146 tid_agg_rx->ssn = start_seq_num;
1147 tid_agg_rx->head_seq_num = start_seq_num;
1148 tid_agg_rx->buf_size = buf_size;
1149 tid_agg_rx->timeout = timeout;
1150 tid_agg_rx->stored_mpdu_num = 0;
1151 status = WLAN_STATUS_SUCCESS;
1152end:
1153 spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
1154
1155end_no_lock:
1078 ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token, 1156 ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token,
1079 status, 1, buf_size, timeout); 1157 status, 1, buf_size, timeout);
1080 sta_info_put(sta); 1158 sta_info_put(sta);
1081} 1159}
1082 1160
1161void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
1162 u16 initiator, u16 reason_code)
1163{
1164 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1165 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1166 struct ieee80211_if_sta *ifsta = &sdata->u.sta;
1167 struct sk_buff *skb;
1168 struct ieee80211_mgmt *mgmt;
1169 u16 params;
1170
1171 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
1172 sizeof(mgmt->u.action.u.delba));
1173
1174 if (!skb) {
1175 printk(KERN_ERR "%s: failed to allocate buffer "
1176 "for delba frame\n", dev->name);
1177 return;
1178 }
1179
1180 skb_reserve(skb, local->hw.extra_tx_headroom);
1181 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
1182 memset(mgmt, 0, 24);
1183 memcpy(mgmt->da, da, ETH_ALEN);
1184 memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
1185 if (sdata->type == IEEE80211_IF_TYPE_AP)
1186 memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
1187 else
1188 memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
1189 mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
1190 IEEE80211_STYPE_ACTION);
1191
1192 skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
1193
1194 mgmt->u.action.category = WLAN_CATEGORY_BACK;
1195 mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
1196 params = (u16)(initiator << 11); /* bit 11 initiator */
1197 params |= (u16)(tid << 12); /* bit 15:12 TID number */
1198
1199 mgmt->u.action.u.delba.params = cpu_to_le16(params);
1200 mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
1201
1202 ieee80211_sta_tx(dev, skb, 0);
1203}
1204
1205void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
1206 u16 initiator, u16 reason)
1207{
1208 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1209 struct ieee80211_hw *hw = &local->hw;
1210 struct sta_info *sta;
1211 int ret;
1212
1213 sta = sta_info_get(local, ra);
1214 if (!sta)
1215 return;
1216
1217 /* check if TID is in operational state */
1218 spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
1219 if (sta->ampdu_mlme.tid_rx[tid].state
1220 != HT_AGG_STATE_OPERATIONAL) {
1221 spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
1222 if (net_ratelimit())
1223 printk(KERN_DEBUG "rx BA session requested to stop on "
1224 "inactive tid %d\n", tid);
1225 sta_info_put(sta);
1226 return;
1227 }
1228 sta->ampdu_mlme.tid_rx[tid].state =
1229 HT_AGG_STATE_REQ_STOP_BA_MSK |
1230 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
1231 spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
1232
1233 /* stop HW Rx aggregation. ampdu_action existence
1234 * already verified in session init so we add the BUG_ON */
1235 BUG_ON(!local->ops->ampdu_action);
1236
1237 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
1238 ra, tid, EINVAL);
1239 if (ret)
1240 printk(KERN_DEBUG "HW problem - can not stop rx "
1241 "aggergation for tid %d\n", tid);
1242
1243 /* shutdown timer has not expired */
1244 if (initiator != WLAN_BACK_TIMER)
1245 del_timer_sync(&sta->ampdu_mlme.tid_rx[tid].
1246 session_timer);
1247
1248 /* check if this is a self generated aggregation halt */
1249 if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
1250 ieee80211_send_delba(dev, ra, tid, 0, reason);
1251
1252 /* free the reordering buffer */
1253 kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf);
1254
1255 sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE;
1256 sta_info_put(sta);
1257}
1258
1259/*
1260 * After receiving Block Ack Request (BAR) we activated a
1261 * timer after each frame arrives from the originator.
1262 * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
1263 */
1264void sta_rx_agg_session_timer_expired(unsigned long data)
1265{
1266 /* not an elegant detour, but there is no choice as the timer passes
1267 * only one argument, and verious sta_info are needed here, so init
1268 * flow in sta_info_add gives the TID as data, while the timer_to_id
1269 * array gives the sta through container_of */
1270 u8 *ptid = (u8 *)data;
1271 u8 *timer_to_id = ptid - *ptid;
1272 struct sta_info *sta = container_of(timer_to_id, struct sta_info,
1273 timer_to_tid[0]);
1274
1275 printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
1276 ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid,
1277 WLAN_BACK_TIMER,
1278 WLAN_REASON_QSTA_TIMEOUT);
1279}
1280
1281
1083static void ieee80211_rx_mgmt_auth(struct net_device *dev, 1282static void ieee80211_rx_mgmt_auth(struct net_device *dev,
1084 struct ieee80211_if_sta *ifsta, 1283 struct ieee80211_if_sta *ifsta,
1085 struct ieee80211_mgmt *mgmt, 1284 struct ieee80211_mgmt *mgmt,
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ffe8a49d8927..60ca07804056 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -104,6 +104,7 @@ static void sta_info_release(struct kref *kref)
104 struct sta_info *sta = container_of(kref, struct sta_info, kref); 104 struct sta_info *sta = container_of(kref, struct sta_info, kref);
105 struct ieee80211_local *local = sta->local; 105 struct ieee80211_local *local = sta->local;
106 struct sk_buff *skb; 106 struct sk_buff *skb;
107 int i;
107 108
108 /* free sta structure; it has already been removed from 109 /* free sta structure; it has already been removed from
109 * hash table etc. external structures. Make sure that all 110 * hash table etc. external structures. Make sure that all
@@ -116,6 +117,8 @@ static void sta_info_release(struct kref *kref)
116 while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { 117 while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
117 dev_kfree_skb_any(skb); 118 dev_kfree_skb_any(skb);
118 } 119 }
120 for (i = 0; i < STA_TID_NUM; i++)
121 del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer);
119 rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); 122 rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
120 rate_control_put(sta->rate_ctrl); 123 rate_control_put(sta->rate_ctrl);
121 kfree(sta); 124 kfree(sta);