Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / net / wireless / iwmc3200wifi / rx.c
index 771a301..bdb1d7e 100644 (file)
@@ -423,7 +423,9 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
                        if (IS_ERR(ticket_node))
                                return PTR_ERR(ticket_node);
 
-                       IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
+                       IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n",
+                                  ticket->action ==  IWM_RX_TICKET_RELEASE ?
+                                  "RELEASE" : "DROP",
                                   ticket->id);
                        list_add_tail(&ticket_node->node, &iwm->rx_tickets);
 
@@ -500,6 +502,18 @@ static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf,
        return 0;
 }
 
+static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm)
+{
+       if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 ||
+            iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) &&
+           (iwm->umac_profile->sec.ucast_cipher ==
+            iwm->umac_profile->sec.mcast_cipher) &&
+           (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN))
+              return 1;
+
+       return 0;
+}
+
 static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                                   unsigned long buf_size,
                                   struct iwm_wifi_cmd *cmd)
@@ -565,11 +579,17 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                        goto ibss;
 
                if (!test_bit(IWM_STATUS_RESETTING, &iwm->status))
-                       cfg80211_connect_result(iwm_to_ndev(iwm),
-                                               complete->bssid,
-                                               NULL, 0, NULL, 0,
-                                               WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                               GFP_KERNEL);
+                       if (!iwm_is_open_wep_profile(iwm)) {
+                               cfg80211_connect_result(iwm_to_ndev(iwm),
+                                              complete->bssid,
+                                              NULL, 0, NULL, 0,
+                                              WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                              GFP_KERNEL);
+                       } else {
+                               /* Let's try shared WEP auth */
+                               IWM_ERR(iwm, "Trying WEP shared auth\n");
+                               schedule_work(&iwm->auth_retry_worker);
+                       }
                else
                        cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0,
                                              GFP_KERNEL);
@@ -713,6 +733,19 @@ static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf,
        return 0;
 }
 
+static int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf,
+                               unsigned long buf_size,
+                               struct iwm_wifi_cmd *cmd)
+{
+       struct wiphy *wiphy = iwm_to_wiphy(iwm);
+
+       IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n");
+
+       wiphy_rfkill_set_hw_state(wiphy, true);
+
+       return 0;
+}
+
 static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
                                     unsigned long buf_size,
                                     struct iwm_wifi_cmd *cmd)
@@ -899,6 +932,8 @@ static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf,
        case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED:
                IWM_DBG_MLME(iwm, DBG, "Extended IE required\n");
                break;
+       case WIFI_IF_NTFY_RADIO_PREEMPTION:
+               return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd);
        case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED:
                return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd);
        case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED:
@@ -1056,8 +1091,14 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
                                   unsigned long buf_size,
                                   struct iwm_wifi_cmd *cmd)
 {
-       struct iwm_umac_wifi_if *hdr =
-                       (struct iwm_umac_wifi_if *)cmd->buf.payload;
+       struct iwm_umac_wifi_if *hdr;
+
+       if (cmd == NULL) {
+               IWM_ERR(iwm, "Couldn't find expected wifi command\n");
+               return -EINVAL;
+       }
+
+       hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload;
 
        IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
                    "oid is 0x%x\n", hdr->oid);
@@ -1079,6 +1120,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
        return 0;
 }
 
+#define CT_KILL_DELAY (30 * HZ)
 static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
                              unsigned long buf_size, struct iwm_wifi_cmd *cmd)
 {
@@ -1091,7 +1133,20 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
                 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
                 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
 
-       wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
+       if (flags & IWM_CARD_STATE_CTKILL_DISABLED) {
+               /*
+                * We got a CTKILL event: We bring the interface down in
+                * oder to cool the device down, and try to bring it up
+                * 30 seconds later. If it's still too hot, we'll go through
+                * this code path again.
+                */
+               cancel_delayed_work_sync(&iwm->ct_kill_delay);
+               schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY);
+       }
+
+       wiphy_rfkill_set_hw_state(wiphy, flags &
+                                 (IWM_CARD_STATE_HW_DISABLED |
+                                  IWM_CARD_STATE_CTKILL_DISABLED));
 
        return 0;
 }
@@ -1282,6 +1337,14 @@ int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size)
 
        switch (le32_to_cpu(hdr->cmd)) {
        case UMAC_REBOOT_BARKER:
+               if (test_bit(IWM_STATUS_READY, &iwm->status)) {
+                       IWM_ERR(iwm, "Unexpected BARKER\n");
+
+                       schedule_work(&iwm->reset_worker);
+
+                       return 0;
+               }
+
                return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION,
                                      IWM_SRC_UDMA, buf, buf_size);
        case UMAC_ACK_BARKER:
@@ -1444,7 +1507,8 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
                }
                break;
        case IWM_RX_TICKET_DROP:
-               IWM_DBG_RX(iwm, DBG, "DROP packet\n");
+               IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n",
+                          le16_to_cpu(ticket_node->ticket->flags));
                kfree_skb(packet->skb);
                break;
        default: