ath9k_htc: Fix memory leak on WMI event handler
ath9k_wmi_ctrl_rx is racy with ath9k_wmi_tasklet on event notification due to which the wmi_skb may be overwritten which leads to memory leak. Signed-off-by: Rajkumar Manoharan <rmanoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
3a160a5b5f
commit
cc0de6536e
2 changed files with 23 additions and 55 deletions
|
@ -124,55 +124,11 @@ void ath9k_wmi_tasklet(unsigned long data)
|
||||||
{
|
{
|
||||||
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
|
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
|
||||||
struct ath_common *common = ath9k_hw_common(priv->ah);
|
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||||
struct wmi_cmd_hdr *hdr;
|
|
||||||
struct wmi_swba *swba_hdr;
|
|
||||||
enum wmi_event_id event;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
void *wmi_event;
|
|
||||||
unsigned long flags;
|
|
||||||
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
|
||||||
__be32 txrate;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
|
ath_print(common, ATH_DBG_WMI, "SWBA Event received\n");
|
||||||
skb = priv->wmi->wmi_skb;
|
|
||||||
spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
|
|
||||||
|
|
||||||
hdr = (struct wmi_cmd_hdr *) skb->data;
|
ath9k_htc_swba(priv, priv->wmi->beacon_pending);
|
||||||
event = be16_to_cpu(hdr->command_id);
|
|
||||||
wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
|
|
||||||
|
|
||||||
ath_print(common, ATH_DBG_WMI,
|
|
||||||
"WMI Event: 0x%x\n", event);
|
|
||||||
|
|
||||||
switch (event) {
|
|
||||||
case WMI_TGT_RDY_EVENTID:
|
|
||||||
break;
|
|
||||||
case WMI_SWBA_EVENTID:
|
|
||||||
swba_hdr = (struct wmi_swba *) wmi_event;
|
|
||||||
ath9k_htc_swba(priv, swba_hdr->beacon_pending);
|
|
||||||
break;
|
|
||||||
case WMI_FATAL_EVENTID:
|
|
||||||
break;
|
|
||||||
case WMI_TXTO_EVENTID:
|
|
||||||
break;
|
|
||||||
case WMI_BMISS_EVENTID:
|
|
||||||
break;
|
|
||||||
case WMI_WLAN_TXCOMP_EVENTID:
|
|
||||||
break;
|
|
||||||
case WMI_DELBA_EVENTID:
|
|
||||||
break;
|
|
||||||
case WMI_TXRATE_EVENTID:
|
|
||||||
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
|
||||||
txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
|
|
||||||
priv->debug.txrate = be32_to_cpu(txrate);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree_skb(skb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
|
static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
|
||||||
|
@ -191,6 +147,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
|
||||||
struct wmi *wmi = (struct wmi *) priv;
|
struct wmi *wmi = (struct wmi *) priv;
|
||||||
struct wmi_cmd_hdr *hdr;
|
struct wmi_cmd_hdr *hdr;
|
||||||
u16 cmd_id;
|
u16 cmd_id;
|
||||||
|
void *wmi_event;
|
||||||
|
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
||||||
|
__be32 txrate;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (unlikely(wmi->stopped))
|
if (unlikely(wmi->stopped))
|
||||||
goto free_skb;
|
goto free_skb;
|
||||||
|
@ -199,10 +159,22 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
|
||||||
cmd_id = be16_to_cpu(hdr->command_id);
|
cmd_id = be16_to_cpu(hdr->command_id);
|
||||||
|
|
||||||
if (cmd_id & 0x1000) {
|
if (cmd_id & 0x1000) {
|
||||||
spin_lock(&wmi->wmi_lock);
|
wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
|
||||||
wmi->wmi_skb = skb;
|
switch (cmd_id) {
|
||||||
spin_unlock(&wmi->wmi_lock);
|
case WMI_SWBA_EVENTID:
|
||||||
tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
|
wmi->beacon_pending = *(u8 *)wmi_event;
|
||||||
|
tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
|
||||||
|
break;
|
||||||
|
case WMI_TXRATE_EVENTID:
|
||||||
|
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
|
||||||
|
txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
|
||||||
|
wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
kfree_skb(skb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,6 @@ struct wmi_cmd_hdr {
|
||||||
__be16 seq_no;
|
__be16 seq_no;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct wmi_swba {
|
|
||||||
u8 beacon_pending;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
enum wmi_cmd_id {
|
enum wmi_cmd_id {
|
||||||
WMI_ECHO_CMDID = 0x0001,
|
WMI_ECHO_CMDID = 0x0001,
|
||||||
WMI_ACCESS_MEMORY_CMDID,
|
WMI_ACCESS_MEMORY_CMDID,
|
||||||
|
@ -104,7 +100,7 @@ struct wmi {
|
||||||
u32 cmd_rsp_len;
|
u32 cmd_rsp_len;
|
||||||
bool stopped;
|
bool stopped;
|
||||||
|
|
||||||
struct sk_buff *wmi_skb;
|
u8 beacon_pending;
|
||||||
spinlock_t wmi_lock;
|
spinlock_t wmi_lock;
|
||||||
|
|
||||||
atomic_t mwrite_cnt;
|
atomic_t mwrite_cnt;
|
||||||
|
|
Loading…
Add table
Reference in a new issue