diff options
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi/rx.c')
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/rx.c | 87 |
1 files changed, 71 insertions, 16 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index 86079a187eef..40dbcbc16593 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c | |||
@@ -102,6 +102,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, | |||
102 | error = (struct iwm_umac_notif_error *)buf; | 102 | error = (struct iwm_umac_notif_error *)buf; |
103 | fw_err = &error->err; | 103 | fw_err = &error->err; |
104 | 104 | ||
105 | memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr)); | ||
106 | |||
105 | IWM_ERR(iwm, "%cMAC FW ERROR:\n", | 107 | IWM_ERR(iwm, "%cMAC FW ERROR:\n", |
106 | (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); | 108 | (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); |
107 | IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); | 109 | IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); |
@@ -118,6 +120,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, | |||
118 | IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); | 120 | IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); |
119 | IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); | 121 | IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); |
120 | 122 | ||
123 | iwm_resetting(iwm); | ||
124 | |||
121 | return 0; | 125 | return 0; |
122 | } | 126 | } |
123 | 127 | ||
@@ -487,8 +491,6 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, | |||
487 | 491 | ||
488 | start = (struct iwm_umac_notif_assoc_start *)buf; | 492 | start = (struct iwm_umac_notif_assoc_start *)buf; |
489 | 493 | ||
490 | set_bit(IWM_STATUS_ASSOCIATING, &iwm->status); | ||
491 | |||
492 | IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", | 494 | IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", |
493 | start->bssid, le32_to_cpu(start->roam_reason)); | 495 | start->bssid, le32_to_cpu(start->roam_reason)); |
494 | 496 | ||
@@ -507,47 +509,80 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, | |||
507 | IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", | 509 | IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", |
508 | complete->bssid, complete->status); | 510 | complete->bssid, complete->status); |
509 | 511 | ||
510 | clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); | ||
511 | |||
512 | switch (le32_to_cpu(complete->status)) { | 512 | switch (le32_to_cpu(complete->status)) { |
513 | case UMAC_ASSOC_COMPLETE_SUCCESS: | 513 | case UMAC_ASSOC_COMPLETE_SUCCESS: |
514 | set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | 514 | set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); |
515 | memcpy(iwm->bssid, complete->bssid, ETH_ALEN); | 515 | memcpy(iwm->bssid, complete->bssid, ETH_ALEN); |
516 | iwm->channel = complete->channel; | 516 | iwm->channel = complete->channel; |
517 | 517 | ||
518 | /* Internal roaming state, avoid notifying SME. */ | ||
519 | if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) | ||
520 | && iwm->conf.mode == UMAC_MODE_BSS) { | ||
521 | cancel_delayed_work(&iwm->disconnect); | ||
522 | cfg80211_roamed(iwm_to_ndev(iwm), | ||
523 | complete->bssid, | ||
524 | iwm->req_ie, iwm->req_ie_len, | ||
525 | iwm->resp_ie, iwm->resp_ie_len, | ||
526 | GFP_KERNEL); | ||
527 | break; | ||
528 | } | ||
529 | |||
518 | iwm_link_on(iwm); | 530 | iwm_link_on(iwm); |
519 | 531 | ||
520 | if (iwm->conf.mode == UMAC_MODE_IBSS) | 532 | if (iwm->conf.mode == UMAC_MODE_IBSS) |
521 | goto ibss; | 533 | goto ibss; |
522 | 534 | ||
523 | cfg80211_connect_result(iwm_to_ndev(iwm), | 535 | if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) |
536 | cfg80211_connect_result(iwm_to_ndev(iwm), | ||
537 | complete->bssid, | ||
538 | iwm->req_ie, iwm->req_ie_len, | ||
539 | iwm->resp_ie, iwm->resp_ie_len, | ||
540 | WLAN_STATUS_SUCCESS, | ||
541 | GFP_KERNEL); | ||
542 | else | ||
543 | cfg80211_roamed(iwm_to_ndev(iwm), | ||
524 | complete->bssid, | 544 | complete->bssid, |
525 | iwm->req_ie, iwm->req_ie_len, | 545 | iwm->req_ie, iwm->req_ie_len, |
526 | iwm->resp_ie, iwm->resp_ie_len, | 546 | iwm->resp_ie, iwm->resp_ie_len, |
527 | WLAN_STATUS_SUCCESS, GFP_KERNEL); | 547 | GFP_KERNEL); |
528 | break; | 548 | break; |
529 | case UMAC_ASSOC_COMPLETE_FAILURE: | 549 | case UMAC_ASSOC_COMPLETE_FAILURE: |
530 | clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | 550 | clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); |
531 | memset(iwm->bssid, 0, ETH_ALEN); | 551 | memset(iwm->bssid, 0, ETH_ALEN); |
532 | iwm->channel = 0; | 552 | iwm->channel = 0; |
533 | 553 | ||
554 | /* Internal roaming state, avoid notifying SME. */ | ||
555 | if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) | ||
556 | && iwm->conf.mode == UMAC_MODE_BSS) { | ||
557 | cancel_delayed_work(&iwm->disconnect); | ||
558 | break; | ||
559 | } | ||
560 | |||
534 | iwm_link_off(iwm); | 561 | iwm_link_off(iwm); |
535 | 562 | ||
536 | if (iwm->conf.mode == UMAC_MODE_IBSS) | 563 | if (iwm->conf.mode == UMAC_MODE_IBSS) |
537 | goto ibss; | 564 | goto ibss; |
538 | 565 | ||
539 | cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, | 566 | if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) |
540 | NULL, 0, NULL, 0, | 567 | cfg80211_connect_result(iwm_to_ndev(iwm), |
541 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 568 | complete->bssid, |
542 | GFP_KERNEL); | 569 | NULL, 0, NULL, 0, |
570 | WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
571 | GFP_KERNEL); | ||
572 | else | ||
573 | cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, | ||
574 | GFP_KERNEL); | ||
575 | break; | ||
543 | default: | 576 | default: |
544 | break; | 577 | break; |
545 | } | 578 | } |
546 | 579 | ||
580 | clear_bit(IWM_STATUS_RESETTING, &iwm->status); | ||
547 | return 0; | 581 | return 0; |
548 | 582 | ||
549 | ibss: | 583 | ibss: |
550 | cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); | 584 | cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); |
585 | clear_bit(IWM_STATUS_RESETTING, &iwm->status); | ||
551 | return 0; | 586 | return 0; |
552 | } | 587 | } |
553 | 588 | ||
@@ -556,13 +591,20 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, | |||
556 | struct iwm_wifi_cmd *cmd) | 591 | struct iwm_wifi_cmd *cmd) |
557 | { | 592 | { |
558 | struct iwm_umac_notif_profile_invalidate *invalid; | 593 | struct iwm_umac_notif_profile_invalidate *invalid; |
594 | u32 reason; | ||
559 | 595 | ||
560 | invalid = (struct iwm_umac_notif_profile_invalidate *)buf; | 596 | invalid = (struct iwm_umac_notif_profile_invalidate *)buf; |
597 | reason = le32_to_cpu(invalid->reason); | ||
561 | 598 | ||
562 | IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", | 599 | IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason); |
563 | le32_to_cpu(invalid->reason)); | ||
564 | 600 | ||
565 | clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); | 601 | if (reason != UMAC_PROFILE_INVALID_REQUEST && |
602 | test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)) | ||
603 | cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL, | ||
604 | 0, WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
605 | GFP_KERNEL); | ||
606 | |||
607 | clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); | ||
566 | clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | 608 | clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); |
567 | 609 | ||
568 | iwm->umac_profile_active = 0; | 610 | iwm->umac_profile_active = 0; |
@@ -576,6 +618,19 @@ static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, | |||
576 | return 0; | 618 | return 0; |
577 | } | 619 | } |
578 | 620 | ||
621 | #define IWM_DISCONNECT_INTERVAL (5 * HZ) | ||
622 | |||
623 | static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf, | ||
624 | unsigned long buf_size, | ||
625 | struct iwm_wifi_cmd *cmd) | ||
626 | { | ||
627 | IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); | ||
628 | |||
629 | schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL); | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
579 | static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, | 634 | static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, |
580 | unsigned long buf_size, | 635 | unsigned long buf_size, |
581 | struct iwm_wifi_cmd *cmd) | 636 | struct iwm_wifi_cmd *cmd) |
@@ -813,7 +868,8 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, | |||
813 | iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, | 868 | iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, |
814 | iwm->resp_ie_len, GFP_KERNEL); | 869 | iwm->resp_ie_len, GFP_KERNEL); |
815 | } else { | 870 | } else { |
816 | IWM_ERR(iwm, "Unsupported management frame"); | 871 | IWM_ERR(iwm, "Unsupported management frame: 0x%x", |
872 | le16_to_cpu(mgt->frame_control)); | ||
817 | return 0; | 873 | return 0; |
818 | } | 874 | } |
819 | 875 | ||
@@ -834,8 +890,7 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, | |||
834 | case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: | 890 | case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: |
835 | return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); | 891 | return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); |
836 | case WIFI_IF_NTFY_CONNECTION_TERMINATED: | 892 | case WIFI_IF_NTFY_CONNECTION_TERMINATED: |
837 | IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); | 893 | return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd); |
838 | break; | ||
839 | case WIFI_IF_NTFY_SCAN_COMPLETE: | 894 | case WIFI_IF_NTFY_SCAN_COMPLETE: |
840 | return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); | 895 | return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); |
841 | case WIFI_IF_NTFY_STA_TABLE_CHANGE: | 896 | case WIFI_IF_NTFY_STA_TABLE_CHANGE: |