| .. | .. |
|---|
| 221 | 221 | if (unlikely(wmi->stopped)) |
|---|
| 222 | 222 | goto free_skb; |
|---|
| 223 | 223 | |
|---|
| 224 | + /* Validate the obtained SKB. */ |
|---|
| 225 | + if (unlikely(skb->len < sizeof(struct wmi_cmd_hdr))) |
|---|
| 226 | + goto free_skb; |
|---|
| 227 | + |
|---|
| 224 | 228 | hdr = (struct wmi_cmd_hdr *) skb->data; |
|---|
| 225 | 229 | cmd_id = be16_to_cpu(hdr->command_id); |
|---|
| 226 | 230 | |
|---|
| .. | .. |
|---|
| 238 | 242 | spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
|---|
| 239 | 243 | goto free_skb; |
|---|
| 240 | 244 | } |
|---|
| 241 | | - spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
|---|
| 242 | 245 | |
|---|
| 243 | 246 | /* WMI command response */ |
|---|
| 244 | 247 | ath9k_wmi_rsp_callback(wmi, skb); |
|---|
| 248 | + spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
|---|
| 245 | 249 | |
|---|
| 246 | 250 | free_skb: |
|---|
| 247 | 251 | kfree_skb(skb); |
|---|
| .. | .. |
|---|
| 279 | 283 | |
|---|
| 280 | 284 | static int ath9k_wmi_cmd_issue(struct wmi *wmi, |
|---|
| 281 | 285 | struct sk_buff *skb, |
|---|
| 282 | | - enum wmi_cmd_id cmd, u16 len) |
|---|
| 286 | + enum wmi_cmd_id cmd, u16 len, |
|---|
| 287 | + u8 *rsp_buf, u32 rsp_len) |
|---|
| 283 | 288 | { |
|---|
| 284 | 289 | struct wmi_cmd_hdr *hdr; |
|---|
| 285 | 290 | unsigned long flags; |
|---|
| .. | .. |
|---|
| 289 | 294 | hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); |
|---|
| 290 | 295 | |
|---|
| 291 | 296 | spin_lock_irqsave(&wmi->wmi_lock, flags); |
|---|
| 297 | + |
|---|
| 298 | + /* record the rsp buffer and length */ |
|---|
| 299 | + wmi->cmd_rsp_buf = rsp_buf; |
|---|
| 300 | + wmi->cmd_rsp_len = rsp_len; |
|---|
| 301 | + |
|---|
| 292 | 302 | wmi->last_seq_id = wmi->tx_seq_id; |
|---|
| 293 | 303 | spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
|---|
| 294 | 304 | |
|---|
| .. | .. |
|---|
| 304 | 314 | struct ath_common *common = ath9k_hw_common(ah); |
|---|
| 305 | 315 | u16 headroom = sizeof(struct htc_frame_hdr) + |
|---|
| 306 | 316 | sizeof(struct wmi_cmd_hdr); |
|---|
| 317 | + unsigned long time_left, flags; |
|---|
| 307 | 318 | struct sk_buff *skb; |
|---|
| 308 | | - unsigned long time_left; |
|---|
| 309 | 319 | int ret = 0; |
|---|
| 310 | 320 | |
|---|
| 311 | 321 | if (ah->ah_flags & AH_UNPLUGGED) |
|---|
| .. | .. |
|---|
| 329 | 339 | goto out; |
|---|
| 330 | 340 | } |
|---|
| 331 | 341 | |
|---|
| 332 | | - /* record the rsp buffer and length */ |
|---|
| 333 | | - wmi->cmd_rsp_buf = rsp_buf; |
|---|
| 334 | | - wmi->cmd_rsp_len = rsp_len; |
|---|
| 335 | | - |
|---|
| 336 | | - ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len); |
|---|
| 342 | + ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len, rsp_buf, rsp_len); |
|---|
| 337 | 343 | if (ret) |
|---|
| 338 | 344 | goto out; |
|---|
| 339 | 345 | |
|---|
| .. | .. |
|---|
| 341 | 347 | if (!time_left) { |
|---|
| 342 | 348 | ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n", |
|---|
| 343 | 349 | wmi_cmd_to_name(cmd_id)); |
|---|
| 350 | + spin_lock_irqsave(&wmi->wmi_lock, flags); |
|---|
| 351 | + wmi->last_seq_id = 0; |
|---|
| 352 | + spin_unlock_irqrestore(&wmi->wmi_lock, flags); |
|---|
| 344 | 353 | mutex_unlock(&wmi->op_mutex); |
|---|
| 345 | 354 | return -ETIMEDOUT; |
|---|
| 346 | 355 | } |
|---|