OSDN Git Service

WEXT: Suppress additional DISASSOCIATE events
[android-x86/external-wpa_supplicant_6.git] / wpa_supplicant / src / drivers / driver_wext.c
index 57ed33f..327c44c 100644 (file)
@@ -39,6 +39,7 @@
 static int wpa_driver_wext_flush_pmkid(void *priv);
 static int wpa_driver_wext_get_range(void *priv);
 static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
 
 
 static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
@@ -68,8 +69,9 @@ static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
        req.ifinfo.ifi_change = 0;
 
        if (linkmode != -1) {
-               rta = (struct rtattr *)
-                       ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+               rta = aliasing_hide_typecast(
+                       ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+                       struct rtattr);
                rta->rta_type = IFLA_LINKMODE;
                rta->rta_len = RTA_LENGTH(sizeof(char));
                *((char *) RTA_DATA(rta)) = linkmode;
@@ -533,10 +535,20 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
                                drv->assoc_req_ies = NULL;
                                os_free(drv->assoc_resp_ies);
                                drv->assoc_resp_ies = NULL;
-                               wpa_supplicant_event(ctx, EVENT_DISASSOC,
+#ifdef ANDROID
+                               if (!drv->skip_disconnect) {
+                                       drv->skip_disconnect = 1;
+#endif
+                                       wpa_supplicant_event(ctx, EVENT_DISASSOC,
                                                     NULL);
+#ifdef ANDROID
+                               }
+#endif
                        
                        } else {
+#ifdef ANDROID
+                               drv->skip_disconnect = 0;
+#endif
                                wpa_driver_wext_event_assoc_ies(drv);
                                wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
                        }
@@ -950,7 +962,11 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
        drv->event_sock = s;
 
        drv->mlme_sock = -1;
-
+#ifdef ANDROID
+       drv->errors = 0;
+       drv->driver_is_loaded = TRUE;
+       drv->skip_disconnect = 0;
+#endif
        wpa_driver_wext_finish_drv_init(drv);
 
        return drv;
@@ -992,6 +1008,13 @@ static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
 
        wpa_driver_wext_get_range(drv);
 
+       /*
+        * Unlock the driver's BSSID and force to a random SSID to clear any
+        * previous association the driver might have when the supplicant
+        * starts up.
+        */
+       wpa_driver_wext_disconnect(drv);
+
        drv->ifindex = if_nametoindex(drv->ifname);
 
        if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
@@ -1031,8 +1054,7 @@ void wpa_driver_wext_deinit(void *priv)
         * Clear possibly configured driver parameters in order to make it
         * easier to use the driver after wpa_supplicant has been terminated.
         */
-       (void) wpa_driver_wext_set_bssid(drv,
-                                        (u8 *) "\x00\x00\x00\x00\x00\x00");
+       wpa_driver_wext_disconnect(drv);
 
        wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP);
 
@@ -1637,6 +1659,9 @@ static int wpa_driver_wext_get_range(void *priv)
                        drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
                if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
                        drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+               drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+                       WPA_DRIVER_AUTH_SHARED |
+                       WPA_DRIVER_AUTH_LEAP;
 
                wpa_printf(MSG_DEBUG, "  capabilities: key_mgmt 0x%x enc 0x%x "
                           "flags 0x%x",
@@ -1929,21 +1954,36 @@ static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
 
 static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
 {
+       struct iwreq iwr;
        const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
        u8 ssid[32];
        int i;
 
        /*
-        * Clear the BSSID selection and set a random SSID to make sure the
-        * driver will not be trying to associate with something even if it
-        * does not understand SIOCSIWMLME commands (or tries to associate
-        * automatically after deauth/disassoc).
+        * Only force-disconnect when the card is in infrastructure mode,
+        * otherwise the driver might interpret the cleared BSSID and random
+        * SSID as an attempt to create a new ad-hoc network.
         */
-       wpa_driver_wext_set_bssid(drv, null_bssid);
+       os_memset(&iwr, 0, sizeof(iwr));
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+               perror("ioctl[SIOCGIWMODE]");
+               iwr.u.mode = IW_MODE_INFRA;
+       }
+
+       if (iwr.u.mode == IW_MODE_INFRA) {
+               /*
+                * Clear the BSSID selection and set a random SSID to make sure
+                * the driver will not be trying to associate with something
+                * even if it does not understand SIOCSIWMLME commands (or
+                * tries to associate automatically after deauth/disassoc).
+                */
+               wpa_driver_wext_set_bssid(drv, null_bssid);
 
-       for (i = 0; i < 32; i++)
-               ssid[i] = rand() & 0xFF;
-       wpa_driver_wext_set_ssid(drv, ssid, 32);
+               for (i = 0; i < 32; i++)
+                       ssid[i] = rand() & 0xFF;
+               wpa_driver_wext_set_ssid(drv, ssid, 32);
+       }
 }
 
 
@@ -1953,8 +1993,8 @@ static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
        struct wpa_driver_wext_data *drv = priv;
        int ret;
        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-       wpa_driver_wext_disconnect(drv);
        ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+       wpa_driver_wext_disconnect(drv);
        return ret;
 }
 
@@ -2375,10 +2415,15 @@ static int wpa_driver_priv_driver_cmd( void *priv, char *cmd, char *buf, size_t
        struct wpa_driver_wext_data *drv = priv;
        struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx);
        struct iwreq iwr;
-       int ret = 0;
+       int ret = 0, flags;
 
        wpa_printf(MSG_DEBUG, "%s %s len = %d", __func__, cmd, buf_len);
 
+       if (!drv->driver_is_loaded && (os_strcasecmp(cmd, "START") != 0)) {
+               wpa_printf(MSG_ERROR,"WEXT: Driver not initialized yet");
+               return -1;
+       }
+
        if (os_strcasecmp(cmd, "RSSI-APPROX") == 0) {
                os_strncpy(cmd, "RSSI", MAX_DRV_CMD_SIZE);
        }
@@ -2389,6 +2434,19 @@ static int wpa_driver_priv_driver_cmd( void *priv, char *cmd, char *buf, size_t
                os_snprintf(cmd, MAX_DRV_CMD_SIZE, "COUNTRY %s",
                        wpa_driver_get_country_code(no_of_chan));
        }
+       else if (os_strcasecmp(cmd, "STOP") == 0) {
+               if ((wpa_driver_wext_get_ifflags(drv, &flags) == 0) &&
+                   (flags & IFF_UP)) {
+                       wpa_printf(MSG_ERROR, "WEXT: %s when iface is UP", cmd);
+                       wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+               }
+       }
+       else if( os_strcasecmp(cmd, "RELOAD") == 0 ) {
+               wpa_printf(MSG_DEBUG,"Reload command");
+               wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+               return ret;
+       }
+
        os_memset(&iwr, 0, sizeof(iwr));
        os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
        os_memcpy(buf, cmd, strlen(cmd) + 1);
@@ -2399,22 +2457,31 @@ static int wpa_driver_priv_driver_cmd( void *priv, char *cmd, char *buf, size_t
                perror("ioctl[SIOCSIWPRIV]");
        }
 
-       if (ret < 0)
-               wpa_printf(MSG_ERROR, "%s failed", __func__);
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret, cmd);
+               drv->errors++;
+               if (drv->errors > WEXT_NUMBER_SEQUENTIAL_ERRORS) {
+                       drv->errors = 0;
+                       wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+               }
+       }
        else {
+               drv->errors = 0;
                ret = 0;
                if ((os_strcasecmp(cmd, "RSSI") == 0) ||
                    (os_strcasecmp(cmd, "LINKSPEED") == 0) ||
                    (os_strcasecmp(cmd, "MACADDR") == 0)) {
                        ret = strlen(buf);
                }
-/*             else if (os_strcasecmp(cmd, "START") == 0) {
-                       os_sleep(0, WPA_DRIVER_WEXT_WAIT_US);
-                       wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED");
+               else if (os_strcasecmp(cmd, "START") == 0) {
+                       drv->driver_is_loaded = TRUE;
+                       /* os_sleep(0, WPA_DRIVER_WEXT_WAIT_US);
+                       wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); */
                }
                else if (os_strcasecmp(cmd, "STOP") == 0) {
-                       wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED");
-               }*/
+                       drv->driver_is_loaded = FALSE;
+                       /* wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); */
+               }
                wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf));
        }
        return ret;