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 14a2a0b..bdb1d7e 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/sched.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
 #include <linux/ieee80211.h>
@@ -422,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);
 
@@ -499,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)
@@ -564,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);
@@ -712,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)
@@ -898,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:
@@ -1055,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);
@@ -1295,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:
@@ -1457,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: