diff options
author | Pontus Fuchs <pontus.fuchs@gmail.com> | 2016-04-19 01:00:40 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2016-04-25 13:37:04 -0400 |
commit | 91c3eeba45e13ab7edfb50610df8672d52809394 (patch) | |
tree | ef2a77d9f86abbc7742b8ce047d3ce8542c33c2b /drivers/net/wireless/ath/wcn36xx | |
parent | 25d217d6e0723481bf90db1d8be02ab475d16002 (diff) |
wcn36xx: Pad TIM PVM if needed
The wcn36xx FW expects a fixed size TIM PVM in the beacon template. If
supplied with a shorter than expected PVM it will overwrite the IE
following the TIM.
Squashed with fix from Jason Mobarak <jam@cozybit.com>:
Patch "wcn36xx: Pad TIM PVM if needed" has caused a regression in mesh
beaconing. The field tim_off is always 0 for mesh mode, and thus
pvm_len (referring to the TIM length field) and pad are both incorrectly
calculated. Thus, msg_body.beacon_length is incorrectly calculated for
mesh mode. Fix this.
Signed-off-by: Pontus Fuchs <pontus.fuchs@gmail.com>
Signed-off-by: Jason Mobarak <jam@cozybit.com>
[bjorn: squashed in Jason's fixup]
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/wcn36xx')
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/hal.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/wcn36xx/smd.c | 27 |
2 files changed, 28 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index d713204f755d..3af16cba3d12 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h | |||
@@ -54,6 +54,9 @@ | |||
54 | /* Default Beacon template size */ | 54 | /* Default Beacon template size */ |
55 | #define BEACON_TEMPLATE_SIZE 0x180 | 55 | #define BEACON_TEMPLATE_SIZE 0x180 |
56 | 56 | ||
57 | /* Minimum PVM size that the FW expects. See comment in smd.c for details. */ | ||
58 | #define TIM_MIN_PVM_SIZE 6 | ||
59 | |||
57 | /* Param Change Bitmap sent to HAL */ | 60 | /* Param Change Bitmap sent to HAL */ |
58 | #define PARAM_BCN_INTERVAL_CHANGED (1 << 0) | 61 | #define PARAM_BCN_INTERVAL_CHANGED (1 << 0) |
59 | #define PARAM_SHORT_PREAMBLE_CHANGED (1 << 1) | 62 | #define PARAM_SHORT_PREAMBLE_CHANGED (1 << 1) |
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index ff3ed2461a69..089a7e445cd6 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c | |||
@@ -1375,12 +1375,19 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, | |||
1375 | u16 p2p_off) | 1375 | u16 p2p_off) |
1376 | { | 1376 | { |
1377 | struct wcn36xx_hal_send_beacon_req_msg msg_body; | 1377 | struct wcn36xx_hal_send_beacon_req_msg msg_body; |
1378 | int ret = 0; | 1378 | int ret = 0, pad, pvm_len; |
1379 | 1379 | ||
1380 | mutex_lock(&wcn->hal_mutex); | 1380 | mutex_lock(&wcn->hal_mutex); |
1381 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ); | 1381 | INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ); |
1382 | 1382 | ||
1383 | msg_body.beacon_length = skb_beacon->len; | 1383 | pvm_len = skb_beacon->data[tim_off + 1] - 3; |
1384 | pad = TIM_MIN_PVM_SIZE - pvm_len; | ||
1385 | |||
1386 | /* Padding is irrelevant to mesh mode since tim_off is always 0. */ | ||
1387 | if (vif->type == NL80211_IFTYPE_MESH_POINT) | ||
1388 | pad = 0; | ||
1389 | |||
1390 | msg_body.beacon_length = skb_beacon->len + pad; | ||
1384 | /* TODO need to find out why + 6 is needed */ | 1391 | /* TODO need to find out why + 6 is needed */ |
1385 | msg_body.beacon_length6 = msg_body.beacon_length + 6; | 1392 | msg_body.beacon_length6 = msg_body.beacon_length + 6; |
1386 | 1393 | ||
@@ -1393,6 +1400,22 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif, | |||
1393 | memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len); | 1400 | memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len); |
1394 | memcpy(msg_body.bssid, vif->addr, ETH_ALEN); | 1401 | memcpy(msg_body.bssid, vif->addr, ETH_ALEN); |
1395 | 1402 | ||
1403 | if (pad > 0) { | ||
1404 | /* | ||
1405 | * The wcn36xx FW has a fixed size for the PVM in the TIM. If | ||
1406 | * given the beacon template from mac80211 with a PVM shorter | ||
1407 | * than the FW expectes it will overwrite the data after the | ||
1408 | * TIM. | ||
1409 | */ | ||
1410 | wcn36xx_dbg(WCN36XX_DBG_HAL, "Pad TIM PVM. %d bytes at %d\n", | ||
1411 | pad, pvm_len); | ||
1412 | memmove(&msg_body.beacon[tim_off + 5 + pvm_len + pad], | ||
1413 | &msg_body.beacon[tim_off + 5 + pvm_len], | ||
1414 | skb_beacon->len - (tim_off + 5 + pvm_len)); | ||
1415 | memset(&msg_body.beacon[tim_off + 5 + pvm_len], 0, pad); | ||
1416 | msg_body.beacon[tim_off + 1] += pad; | ||
1417 | } | ||
1418 | |||
1396 | /* TODO need to find out why this is needed? */ | 1419 | /* TODO need to find out why this is needed? */ |
1397 | if (vif->type == NL80211_IFTYPE_MESH_POINT) | 1420 | if (vif->type == NL80211_IFTYPE_MESH_POINT) |
1398 | /* mesh beacon don't need this, so push further down */ | 1421 | /* mesh beacon don't need this, so push further down */ |