automake build system
[mech_eap.orig] / src / drivers / driver_ralink.c
index 73fa948..09d1ef5 100644 (file)
 #include "driver.h"
 #include "l2_packet/l2_packet.h"
 #include "eloop.h"
-#include "ieee802_11_defs.h"
+#include "common/ieee802_11_defs.h"
 #include "priv_netlink.h"
+#include "netlink.h"
+#include "linux_ioctl.h"
 #include "driver_ralink.h"
 
 static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
@@ -33,7 +35,7 @@ static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
 struct wpa_driver_ralink_data {
        void *ctx;
        int ioctl_sock;
-       int event_sock;
+       struct netlink_data *netlink;
        char ifname[IFNAMSIZ + 1];
        u8 *assoc_req_ies;
        size_t assoc_req_ies_len;
@@ -45,6 +47,7 @@ struct wpa_driver_ralink_data {
        int ap_scan;
        int scanning_done;
        u8 g_driver_down;
+       BOOLEAN bAddWepKey;
 };
 
 static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
@@ -57,7 +60,7 @@ static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
        if (buf == NULL)
                return -1;
        os_memset(&iwr, 0, sizeof(iwr));
-       os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
        iwr.u.data.flags = oid;
        iwr.u.data.flags |= OID_GET_SET_TOGGLE;
 
@@ -84,7 +87,7 @@ ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv)
        UCHAR enabled = 0;
 
        os_memset(&iwr, 0, sizeof(iwr));
-       os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
        iwr.u.data.pointer = (UCHAR*) &enabled;
        iwr.u.data.flags = RT_OID_NEW_DRIVER;
 
@@ -108,7 +111,7 @@ static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid)
        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
        os_memset(&iwr, 0, sizeof(iwr));
-       os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 
        if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
                perror("ioctl[SIOCGIWAP]");
@@ -145,7 +148,7 @@ static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid)
        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
        os_memset(&iwr, 0, sizeof(iwr));
-       os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
        iwr.u.essid.pointer = (caddr_t) ssid;
        iwr.u.essid.length = 32;
 
@@ -236,7 +239,7 @@ static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv,
        buf->SsidLength = ssid_len;
        os_memcpy(buf->Ssid, ssid, ssid_len);
        os_memset(&iwr, 0, sizeof(iwr));
-       os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 
        iwr.u.data.flags = OID_802_11_SSID;
        iwr.u.data.flags |= OID_GET_SET_TOGGLE;
@@ -288,8 +291,9 @@ static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv,
        os_memset(&event, 0, sizeof(event));
        for (i = 0; i < pmkid->NumCandidates; i++) {
                PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
-               wpa_printf(MSG_DEBUG, "RALINK: %d: " MACSTR " Flags 0x%x",
-                          i, MAC2STR(p->BSSID), (int) p->Flags);
+               wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x",
+                          (unsigned long) i, MAC2STR(p->BSSID),
+                          (int) p->Flags);
                os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
                event.pmkid_candidate.index = i;
                event.pmkid_candidate.preauth =
@@ -449,6 +453,7 @@ wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
                                        void *ctx, char *custom)
 {
        union wpa_event_data data;
+       u8 *req_ies = NULL, *resp_ies = NULL;
 
        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
@@ -477,12 +482,12 @@ wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
                 */
                bytes = drv->assoc_req_ies_len;
 
-               data.assoc_info.req_ies = os_malloc(bytes);
-               if (data.assoc_info.req_ies == NULL)
+               req_ies = os_malloc(bytes);
+               if (req_ies == NULL)
                        return;
-
+               os_memcpy(req_ies, spos, bytes);
+               data.assoc_info.req_ies = req_ies;
                data.assoc_info.req_ies_len = bytes;
-               os_memcpy(data.assoc_info.req_ies, spos, bytes);
 
                /* skip the '\0' byte */
                spos += bytes + 1;
@@ -498,21 +503,48 @@ wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
                        if (!bytes)
                                goto done;
 
-
-                       data.assoc_info.resp_ies = os_malloc(bytes);
-                       if (data.assoc_info.resp_ies == NULL)
+                       resp_ies = os_malloc(bytes);
+                       if (resp_ies == NULL)
                                goto done;
-
+                       os_memcpy(resp_ies, spos, bytes);
+                       data.assoc_info.resp_ies = resp_ies;
                        data.assoc_info.resp_ies_len = bytes;
-                       os_memcpy(data.assoc_info.resp_ies, spos, bytes);
                }
 
                wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
 
-               /* free allocated memory */
        done:
-               os_free(data.assoc_info.resp_ies);
-               os_free(data.assoc_info.req_ies);
+               /* free allocated memory */
+               os_free(resp_ies);
+               os_free(req_ies);
+       }
+}
+
+static void ralink_interface_up(struct wpa_driver_ralink_data *drv)
+{
+       union wpa_event_data event;
+       int enable_wpa_supplicant = 0;
+       drv->g_driver_down = 0;
+       os_memset(&event, 0, sizeof(event));
+       os_snprintf(event.interface_status.ifname,
+                   sizeof(event.interface_status.ifname), "%s", drv->ifname);
+
+       event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+
+       if (drv->ap_scan == 1)
+               enable_wpa_supplicant = 1;
+       else
+               enable_wpa_supplicant = 2;
+       /* trigger driver support wpa_supplicant */
+       if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
+                          (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
+       {
+               wpa_printf(MSG_INFO, "RALINK: Failed to set "
+                          "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
+                          (int) enable_wpa_supplicant);
+               wpa_printf(MSG_ERROR, "ralink. Driver does not support "
+                          "wpa_supplicant");
        }
 }
 
@@ -579,33 +611,9 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
                        }
 
                        if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) {
+                               wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
                                wpa_printf(MSG_DEBUG, "Custom wireless event: "
                                           "receive ASSOCIATED_EVENT !!!");
-                               /* determine whether the dynamic-WEP is used or
-                                * not */
-#if 0
-                               if (wpa_s && wpa_s->current_ssid &&
-                                   wpa_s->current_ssid->key_mgmt ==
-                                   WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-                                       if ((wpa_s->current_ssid->eapol_flags &
-                                            (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
-                                               //wpa_printf(MSG_DEBUG, "The current ssid - (%s), eapol_flag = %d.\n",
-                                               //       wpa_ssid_txt(wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid_len),wpa_s->current_ssid->eapol_flags);
-                                               ieee8021x_required_key = TRUE;
-                                       }
-
-                                       if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
-                                       {
-                                               wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
-                                                          (int) ieee8021x_required_key);
-                                       }
-
-                                       wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d).\n", ieee8021x_required_key ? "TRUE" : "FALSE",
-                                                                                                                                                                                               wpa_s->current_ssid->eapol_flags);
-                               }
-#endif
-
-                               wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
                        } else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) {
                                wpa_printf(MSG_DEBUG, "Custom wireless event: "
                                           "receive ReqIEs !!!");
@@ -640,7 +648,7 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
                                           "receive ASSOCINFO_EVENT !!!");
 
                                assoc_info_buf =
-                                       os_malloc(drv->assoc_req_ies_len +
+                                       os_zalloc(drv->assoc_req_ies_len +
                                                  drv->assoc_resp_ies_len + 1);
 
                                if (assoc_info_buf == NULL) {
@@ -652,18 +660,26 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
                                        return;
                                }
 
-                               os_memcpy(assoc_info_buf, drv->assoc_req_ies,
-                                         drv->assoc_req_ies_len);
+                               if (drv->assoc_req_ies) {
+                                       os_memcpy(assoc_info_buf,
+                                                 drv->assoc_req_ies,
+                                                 drv->assoc_req_ies_len);
+                               }
                                info_pos = assoc_info_buf +
                                        drv->assoc_req_ies_len;
-                               os_memcpy(info_pos, drv->assoc_resp_ies,
-                                         drv->assoc_resp_ies_len);
+                               if (drv->assoc_resp_ies) {
+                                       os_memcpy(info_pos,
+                                                 drv->assoc_resp_ies,
+                                                 drv->assoc_resp_ies_len);
+                               }
                                assoc_info_buf[drv->assoc_req_ies_len +
                                               drv->assoc_resp_ies_len] = '\0';
                                wpa_driver_ralink_event_wireless_custom(
                                        drv, ctx, assoc_info_buf);
                                os_free(drv->assoc_req_ies);
+                               drv->assoc_req_ies = NULL;
                                os_free(drv->assoc_resp_ies);
+                               drv->assoc_resp_ies = NULL;
                                os_free(assoc_info_buf);
                        } else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
                        {
@@ -680,51 +696,8 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
                        } else if (iwe->u.data.flags == RT_INTERFACE_DOWN) {
                                drv->g_driver_down = 1;
                                eloop_terminate();
-                       } else if (iwe->u.data.flags == RT_REPORT_AP_INFO) {
-                               if (drv->ap_scan != 1) {
-                                       typedef struct PACKED {
-                                               UCHAR bssid[MAC_ADDR_LEN];
-                                               UCHAR ssid[MAX_LEN_OF_SSID];
-                                               INT ssid_len;
-                                               UCHAR wpa_ie[40];
-                                               INT wpa_ie_len;
-                                               UCHAR rsn_ie[40];
-                                               INT rsn_ie_len;
-                                               INT freq;
-                                               USHORT caps;
-                                       } *PAPINFO;
-
-                                       wpa_printf(MSG_DEBUG, "Custom wireless"
-                                                  " event: receive "
-                                                  "RT_REPORT_AP_INFO !!!");
-                                       //printf("iwe->u.data.length = %d\n", iwe->u.data.length);
-                                       //wpa_hexdump(MSG_DEBUG, "AP_Info: ", buf, iwe->u.data.length);
-#if 0
-                                       wpa_s->num_scan_results = 1;
-                                       if (wpa_s->scan_results)
-                                               os_free(wpa_s->scan_results);
-                                       wpa_s->scan_results = os_malloc(sizeof(struct wpa_scan_result) + 1);
-                                       if (wpa_s->scan_results) {
-                                               PAPINFO pApInfo = (PAPINFO)buf;
-                                               os_memcpy(wpa_s->scan_results[0].bssid, pApInfo->bssid, ETH_ALEN);
-                                               os_memcpy(wpa_s->scan_results[0].ssid, pApInfo->ssid, pApInfo->ssid_len);
-                                               wpa_s->scan_results[0].ssid_len = pApInfo->ssid_len;
-                                               if (pApInfo->wpa_ie_len > 0) {
-                                                       os_memcpy(wpa_s->scan_results[0].wpa_ie, pApInfo->wpa_ie, pApInfo->wpa_ie_len);
-                                                       wpa_s->scan_results[0].wpa_ie_len = pApInfo->wpa_ie_len;
-                                               } else if (pApInfo->rsn_ie_len > 0) {
-                                                       os_memcpy(wpa_s->scan_results[0].rsn_ie, pApInfo->rsn_ie, pApInfo->rsn_ie_len);
-                                                       wpa_s->scan_results[0].rsn_ie_len = pApInfo->rsn_ie_len;
-                                               }
-                                               wpa_s->scan_results[0].caps = pApInfo->caps;
-                                               wpa_s->scan_results[0].freq = pApInfo->freq;
-                                       } else {
-                                               wpa_printf("wpa_s->scan_"
-                                                          "results fail to "
-                                                          "os_malloc!!\n");
-                                       }
-#endif
-                               }
+                       } else if (iwe->u.data.flags == RT_INTERFACE_UP) {
+                               ralink_interface_up(drv);
                        } else {
                                wpa_driver_ralink_event_wireless_custom(
                                        drv, ctx, buf);
@@ -738,29 +711,20 @@ wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
 }
 
 static void
-wpa_driver_ralink_event_rtm_newlink(struct wpa_driver_ralink_data *drv,
-                                   void *ctx, struct nlmsghdr *h, int len)
+wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, 
+                                   u8 *buf, size_t len)
 {
-       struct ifinfomsg *ifi;
-       int attrlen, nlmsg_len, rta_len;
-       struct rtattr * attr;
+       struct wpa_driver_ralink_data *drv = ctx;
+       int attrlen, rta_len;
+       struct rtattr *attr;
 
        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
-       if (len < (int) sizeof(*ifi))
-               return;
-
-       ifi = NLMSG_DATA(h);
        wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg));
 
-       nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
-       attrlen = h->nlmsg_len - nlmsg_len;
+       attrlen = len;
        wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen);
-       if (attrlen < 0)
-               return;
-
-       attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+       attr = (struct rtattr *) buf;
        wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr));
        rta_len = RTA_ALIGN(sizeof(struct rtattr));
        wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len);
@@ -778,60 +742,6 @@ wpa_driver_ralink_event_rtm_newlink(struct wpa_driver_ralink_data *drv,
        }
 }
 
-static void wpa_driver_ralink_event_receive(int sock, void *ctx,
-                                           void *sock_ctx)
-{
-       char buf[8192];
-       int left;
-       struct sockaddr_nl from;
-       socklen_t fromlen;
-       struct nlmsghdr *h;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       fromlen = sizeof(from);
-       left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
-                       (struct sockaddr *) &from, &fromlen);
-
-       if (left < 0) {
-               if (errno != EINTR && errno != EAGAIN)
-                       perror("recvfrom(netlink)");
-               return;
-       }
-
-       h = (struct nlmsghdr *) buf;
-       wpa_hexdump(MSG_DEBUG, "h: ", (u8 *)h, h->nlmsg_len);
-
-       while (left >= (int) sizeof(*h)) {
-               int len, plen;
-
-               len = h->nlmsg_len;
-               plen = len - sizeof(*h);
-               if (len > left || plen < 0) {
-                       wpa_printf(MSG_DEBUG, "Malformed netlink message: "
-                                  "len=%d left=%d plen=%d", len, left, plen);
-                       break;
-               }
-
-               switch (h->nlmsg_type) {
-               case RTM_NEWLINK:
-                       wpa_driver_ralink_event_rtm_newlink(ctx, sock_ctx, h,
-                                                           plen);
-                       break;
-               }
-
-               len = NLMSG_ALIGN(len);
-               left -= len;
-               h = (struct nlmsghdr *) ((char *) h + len);
-       }
-
-       if (left > 0) {
-               wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
-                          "message", left);
-       }
-
-}
-
 static int
 ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
 {
@@ -839,7 +749,7 @@ ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
        UINT we_version_compiled = 0;
 
        os_memset(&iwr, 0, sizeof(iwr));
-       os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
        iwr.u.data.pointer = (caddr_t) &we_version_compiled;
        iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
 
@@ -853,45 +763,13 @@ ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
        return 0;
 }
 
-static int
-ralink_set_iface_flags(void *priv, int dev_up)
-{
-       struct wpa_driver_ralink_data *drv = priv;
-       struct ifreq ifr;
-
-       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-       if (drv->ioctl_sock < 0)
-               return -1;
-
-       os_memset(&ifr, 0, sizeof(ifr));
-       os_snprintf(ifr.ifr_name, IFNAMSIZ, "%s", drv->ifname);
-
-       if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
-               perror("ioctl[SIOCGIFFLAGS]");
-               return -1;
-       }
-
-       if (dev_up)
-               ifr.ifr_flags |= IFF_UP;
-       else
-               ifr.ifr_flags &= ~IFF_UP;
-
-       if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
-               perror("ioctl[SIOCSIFFLAGS]");
-               return -1;
-       }
-
-       return 0;
-}
-
 static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
 {
        int s;
        struct wpa_driver_ralink_data *drv;
        struct ifreq ifr;
-       struct sockaddr_nl local;
        UCHAR enable_wpa_supplicant = 0;
+       struct netlink_config *cfg;
 
        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
@@ -901,7 +779,7 @@ static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
                return NULL;
        }
        /* do it */
-       os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+       os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 
        if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
                perror(ifr.ifr_name);
@@ -915,35 +793,29 @@ static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
        drv->scanning_done = 1;
        drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
        drv->ctx = ctx;
-       os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
+       os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
        drv->ioctl_sock = s;
        drv->g_driver_down = 0;
 
-       s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-       if (s < 0) {
-               perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+       cfg = os_zalloc(sizeof(*cfg));
+       if (cfg == NULL) {
                close(drv->ioctl_sock);
                os_free(drv);
                return NULL;
        }
-
-       os_memset(&local, 0, sizeof(local));
-       local.nl_family = AF_NETLINK;
-       local.nl_groups = RTMGRP_LINK;
-
-       if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
-               perror("bind(netlink)");
-               close(s);
+       cfg->ctx = drv;
+       cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink;
+       drv->netlink = netlink_init(cfg);
+       if (drv->netlink == NULL) {
+               os_free(cfg);
                close(drv->ioctl_sock);
                os_free(drv);
                return NULL;
        }
 
-       eloop_register_read_sock(s, wpa_driver_ralink_event_receive, drv, ctx);
-       drv->event_sock = s;
        drv->no_of_pmkid = 4; /* Number of PMKID saved supported */
 
-       ralink_set_iface_flags(drv, 1); /* mark up during setup */
+       linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
        ralink_get_we_version_compiled(drv);
        wpa_driver_ralink_flush_pmkid(drv);
 
@@ -994,12 +866,11 @@ static void wpa_driver_ralink_deinit(void *priv)
                wpa_driver_ralink_flush_pmkid(drv);
 
                sleep(1);
-               ralink_set_iface_flags(drv, 0);
+               /* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */
        }
 
        eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
-       eloop_unregister_read_sock(drv->event_sock);
-       close(drv->event_sock);
+       netlink_deinit(drv->netlink);
        close(drv->ioctl_sock);
        os_free(drv);
 }
@@ -1017,7 +888,8 @@ static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 
 }
 
-static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_ralink_scan(void *priv,
+                                 struct wpa_driver_scan_params *params)
 {
        struct wpa_driver_ralink_data *drv = priv;
        struct iwreq iwr;
@@ -1028,6 +900,7 @@ static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
 
        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
+#if 0
        if (ssid_len > IW_ESSID_MAX_SIZE) {
                wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
                           __FUNCTION__, (unsigned long) ssid_len);
@@ -1035,9 +908,17 @@ static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
        }
 
        /* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
+#endif
+
+       if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE,
+                          (char *) params->extra_ies, params->extra_ies_len) <
+           0) {
+               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+                          "RT_OID_WPS_PROBE_REQ_IE");
+       }
 
        os_memset(&iwr, 0, sizeof(iwr));
-       os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 
        if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
                perror("ioctl[SIOCSIWSCAN]");
@@ -1055,96 +936,124 @@ static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
        return ret;
 }
 
-static int
-wpa_driver_ralink_get_scan_results(void *priv,
-                                  struct wpa_scan_result *results,
-                                  size_t max_size)
+static struct wpa_scan_results *
+wpa_driver_ralink_get_scan_results(void *priv)
 {
        struct wpa_driver_ralink_data *drv = priv;
        UCHAR *buf = NULL;
+       size_t buf_len;
        NDIS_802_11_BSSID_LIST_EX *wsr;
        NDIS_WLAN_BSSID_EX *wbi;
        struct iwreq iwr;
-       int rv = 0;
        size_t ap_num;
-       u8 *pos, *end;
+       u8 *pos;
+       struct wpa_scan_results *res;
 
        if (drv->g_driver_down == 1)
-               return -1;
+               return NULL;
        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
-       if (drv->we_version_compiled >= 17) {
-               buf = os_zalloc(8192);
-               iwr.u.data.length = 8192;
-       } else {
-               buf = os_zalloc(4096);
-               iwr.u.data.length = 4096;
-       }
-       if (buf == NULL)
-               return -1;
+       if (drv->we_version_compiled >= 17)
+               buf_len = 8192;
+       else
+               buf_len = 4096;
+
+       for (;;) {
+               buf = os_zalloc(buf_len);
+               iwr.u.data.length = buf_len;
+               if (buf == NULL)
+                       return NULL;
 
-       wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
+               wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
 
-       wsr->NumberOfItems = 0;
-       os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-       iwr.u.data.pointer = (void *) buf;
-       iwr.u.data.flags = OID_802_11_BSSID_LIST;
+               wsr->NumberOfItems = 0;
+               os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+               iwr.u.data.pointer = (void *) buf;
+               iwr.u.data.flags = OID_802_11_BSSID_LIST;
 
-       if ((rv = ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr)) < 0) {
-               wpa_printf(MSG_DEBUG, "ioctl fail: rv = %d", rv);
+               if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0)
+                       break;
+
+               if (errno == E2BIG && buf_len < 65535) {
+                       os_free(buf);
+                       buf = NULL;
+                       buf_len *= 2;
+                       if (buf_len > 65535)
+                               buf_len = 65535; /* 16-bit length field */
+                       wpa_printf(MSG_DEBUG, "Scan results did not fit - "
+                                  "trying larger buffer (%lu bytes)",
+                                  (unsigned long) buf_len);
+               } else {
+                       perror("ioctl[RT_PRIV_IOCTL]");
+                       os_free(buf);
+                       return NULL;
+               }
+       }
+
+       res = os_zalloc(sizeof(*res));
+       if (res == NULL) {
                os_free(buf);
-               return -1;
+               return NULL;
        }
 
-       os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+       res->res = os_zalloc(wsr->NumberOfItems *
+                            sizeof(struct wpa_scan_res *));
+       if (res->res == NULL) {
+               os_free(res);
+               os_free(buf);
+               return NULL;
+       }
 
        for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems;
             ++ap_num) {
-               os_memcpy(results[ap_num].bssid, &wbi->MacAddress, ETH_ALEN);
-               os_memcpy(results[ap_num].ssid, wbi->Ssid.Ssid,
-                         wbi->Ssid.SsidLength);
-               results[ap_num].ssid_len = wbi->Ssid.SsidLength;
-               results[ap_num].freq = (wbi->Configuration.DSConfig / 1000);
+               struct wpa_scan_res *r = NULL;
+               size_t extra_len = 0, var_ie_len = 0;
+               u8 *pos2;
+
+               /* SSID data element */
+               extra_len += 2 + wbi->Ssid.SsidLength;
+               var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs);
+               r = os_zalloc(sizeof(*r) + extra_len + var_ie_len);
+               if (r == NULL)
+                       break;
+               res->res[res->num++] = r;
 
+               wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid);
                /* get ie's */
                wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs",
-                           (u8 *) wbi + sizeof(*wbi) - 1, wbi->IELength);
+                           (u8 *) &wbi->IEs[0], wbi->IELength);
 
-               pos = (u8 *) wbi + sizeof(*wbi) - 1;
-               end = (u8 *) wbi + sizeof(*wbi) + wbi->IELength;
+               os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN);
 
-               if (wbi->IELength < sizeof(NDIS_802_11_FIXED_IEs))
-                       break;
+               extra_len += (2 + wbi->Ssid.SsidLength);
+               r->ie_len = extra_len + var_ie_len;
+               pos2 = (u8 *) (r + 1);
 
-               pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
-               os_memcpy(&results[ap_num].caps, pos, 2);
-               pos += 2;
+               /*
+                * Generate a fake SSID IE since the driver did not report
+                * a full IE list.
+                */
+               *pos2++ = WLAN_EID_SSID;
+               *pos2++ = wbi->Ssid.SsidLength;
+               os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength);
+               pos2 += wbi->Ssid.SsidLength;
 
-               while (pos + 1 < end && pos + 2 + pos[1] <= end) {
-                       u8 ielen = 2 + pos[1];
+               r->freq = (wbi->Configuration.DSConfig / 1000);
 
-                       if (ielen > SSID_MAX_WPA_IE_LEN) {
-                               pos += ielen;
-                               continue;
-                       }
+               pos = (u8 *) wbi + sizeof(*wbi) - 1;
 
-                       if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
-                           pos[1] >= 4 &&
-                           os_memcmp(pos + 2, "\x00\x50\xf2\x01", 4) == 0) {
-                               os_memcpy(results[ap_num].wpa_ie, pos, ielen);
-                               results[ap_num].wpa_ie_len = ielen;
-                       } else if (pos[0] == WLAN_EID_RSN) {
-                               os_memcpy(results[ap_num].rsn_ie, pos, ielen);
-                               results[ap_num].rsn_ie_len = ielen;
-                       }
-                       pos += ielen;
-               }
+               pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
+               os_memcpy(&(r->caps), pos, 2);
+               pos += 2;
+
+               if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs))
+                       os_memcpy(pos2, pos, var_ie_len);
 
                wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length);
        }
 
        os_free(buf);
-       return ap_num;
+       return res;
 }
 
 static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
@@ -1164,6 +1073,24 @@ static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
        return 0;
 }
 
+static int ralink_set_encr_type(struct wpa_driver_ralink_data *drv,
+                               NDIS_802_11_WEP_STATUS encr_type)
+{
+       NDIS_802_11_WEP_STATUS wep_status = encr_type;
+
+       wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+       if (ralink_set_oid(drv, OID_802_11_WEP_STATUS,
+                          (char *) &wep_status, sizeof(wep_status)) < 0) {
+               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+                          "OID_802_11_WEP_STATUS (%d)",
+                          (int) wep_status);
+               return -1;
+       }
+       return 0;
+}
+
+
 static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv,
                                        int key_idx, const u8 *addr,
                                        const u8 *bssid, int pairwise)
@@ -1232,7 +1159,8 @@ static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv,
        return res;
 }
 
-static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr,
+static int wpa_driver_ralink_set_key(const char *ifname, void *priv,
+                                    enum wpa_alg alg, const u8 *addr,
                                     int key_idx, int set_tx,
                                     const u8 *seq, size_t seq_len,
                                     const u8 *key, size_t key_len)
@@ -1248,6 +1176,8 @@ static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr,
 
        wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
+       drv->bAddWepKey = FALSE;
+
        if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
                                      ETH_ALEN) == 0) {
                /* Group Key */
@@ -1265,6 +1195,7 @@ static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr,
        }
 
        if (alg == WPA_ALG_WEP) {
+               drv->bAddWepKey = TRUE;
                return wpa_driver_ralink_add_wep(drv, pairwise, key_idx,
                                                 set_tx, key, key_len);
        }
@@ -1354,6 +1285,29 @@ static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr,
        }
 }
 
+static int wpa_driver_ralink_set_gen_ie(void *priv, const u8 *ie,
+                                       size_t ie_len)
+{
+       struct wpa_driver_ralink_data *drv = priv;
+       struct iwreq iwr;
+       int ret = 0;
+
+       os_memset(&iwr, 0, sizeof(iwr));
+       os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+       iwr.u.data.pointer = (caddr_t) ie;
+       iwr.u.data.length = ie_len;
+
+       wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ",
+                   (u8 *) ie, ie_len);
+
+       if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+               perror("ioctl[SIOCSIWGENIE]");
+               ret = -1;
+       }
+
+       return ret;
+}
+
 static int
 wpa_driver_ralink_associate(void *priv,
                            struct wpa_driver_associate_params *params)
@@ -1364,6 +1318,7 @@ wpa_driver_ralink_associate(void *priv,
        NDIS_802_11_AUTHENTICATION_MODE auth_mode;
        NDIS_802_11_WEP_STATUS encr;
        BOOLEAN         ieee8021xMode;
+       BOOLEAN         ieee8021x_required_key = TRUE;
 
        if (drv->g_driver_down == 1)
                return -1;
@@ -1382,83 +1337,131 @@ wpa_driver_ralink_associate(void *priv,
                /* Try to continue anyway */
        }
 
-       if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
-               if (params->auth_alg & AUTH_ALG_SHARED_KEY) {
-                       if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
-                               auth_mode = Ndis802_11AuthModeAutoSwitch;
-                       else
-                               auth_mode = Ndis802_11AuthModeShared;
-               } else
-                       auth_mode = Ndis802_11AuthModeOpen;
-       } else if (params->wpa_ie[0] == WLAN_EID_RSN) {
-               if (params->key_mgmt_suite == KEY_MGMT_PSK)
-                       auth_mode = Ndis802_11AuthModeWPA2PSK;
-               else
-                       auth_mode = Ndis802_11AuthModeWPA2;
+       if (params->key_mgmt_suite == KEY_MGMT_WPS) {
+               UCHAR enable_wps = 0x80;
+               /* trigger driver support wpa_supplicant */
+               if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
+                                  (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) {
+                       wpa_printf(MSG_INFO, "RALINK: Failed to set "
+                                  "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
+                                  (int) enable_wps);
+               }
+
+               wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie,
+                                            params->wpa_ie_len);
+
+               ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen);
+
+               ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled);
        } else {
-               if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
-                       auth_mode = Ndis802_11AuthModeWPANone;
-               else if (params->key_mgmt_suite == KEY_MGMT_PSK)
-                       auth_mode = Ndis802_11AuthModeWPAPSK;
+#ifdef CONFIG_WPS
+               UCHAR enable_wpa_supplicant;
+
+               if (drv->ap_scan == 1)
+                       enable_wpa_supplicant = 0x01;
                else
-                       auth_mode = Ndis802_11AuthModeWPA;
-       }
+                       enable_wpa_supplicant = 0x02;
 
-       switch (params->pairwise_suite) {
-       case CIPHER_CCMP:
-               encr = Ndis802_11Encryption3Enabled;
-               break;
-       case CIPHER_TKIP:
-               encr = Ndis802_11Encryption2Enabled;
-               break;
-       case CIPHER_WEP40:
-       case CIPHER_WEP104:
-               encr = Ndis802_11Encryption1Enabled;
-               break;
-       case CIPHER_NONE:
-               if (params->group_suite == CIPHER_CCMP)
+               /* trigger driver support wpa_supplicant */
+               if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
+                                  (PCHAR) &enable_wpa_supplicant,
+                                  sizeof(UCHAR)) < 0) {
+                       wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+                                  "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
+                                  (int) enable_wpa_supplicant);
+               }
+
+               wpa_driver_ralink_set_gen_ie(priv, (u8 *) "", 0);
+#endif /* CONFIG_WPS */
+
+               if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
+                       if (params->auth_alg & WPA_AUTH_ALG_SHARED) {
+                               if (params->auth_alg & WPA_AUTH_ALG_OPEN)
+                                       auth_mode = Ndis802_11AuthModeAutoSwitch;
+                               else
+                                       auth_mode = Ndis802_11AuthModeShared;
+                       } else
+                               auth_mode = Ndis802_11AuthModeOpen;
+               } else if (params->wpa_ie[0] == WLAN_EID_RSN) {
+                       if (params->key_mgmt_suite == KEY_MGMT_PSK)
+                               auth_mode = Ndis802_11AuthModeWPA2PSK;
+                       else
+                               auth_mode = Ndis802_11AuthModeWPA2;
+               } else {
+                       if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
+                               auth_mode = Ndis802_11AuthModeWPANone;
+                       else if (params->key_mgmt_suite == KEY_MGMT_PSK)
+                               auth_mode = Ndis802_11AuthModeWPAPSK;
+                       else
+                               auth_mode = Ndis802_11AuthModeWPA;
+               }
+
+               switch (params->pairwise_suite) {
+               case CIPHER_CCMP:
                        encr = Ndis802_11Encryption3Enabled;
-               else if (params->group_suite == CIPHER_TKIP)
+                       break;
+               case CIPHER_TKIP:
                        encr = Ndis802_11Encryption2Enabled;
-               else
+                       break;
+               case CIPHER_WEP40:
+               case CIPHER_WEP104:
+                       encr = Ndis802_11Encryption1Enabled;
+                       break;
+               case CIPHER_NONE:
+                       if (params->group_suite == CIPHER_CCMP)
+                               encr = Ndis802_11Encryption3Enabled;
+                       else if (params->group_suite == CIPHER_TKIP)
+                               encr = Ndis802_11Encryption2Enabled;
+                       else
+                               encr = Ndis802_11EncryptionDisabled;
+                       break;
+               default:
                        encr = Ndis802_11EncryptionDisabled;
-               break;
-       default:
-               encr = Ndis802_11EncryptionDisabled;
-               break;
-       }
-
-       ralink_set_auth_mode(drv, auth_mode);
+                       break;
+               }
 
-       /* notify driver that IEEE8021x mode is enabled */
-       if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA)
-               ieee8021xMode = TRUE;
-       else
-               ieee8021xMode = FALSE;
+               ralink_set_auth_mode(drv, auth_mode);
 
-       if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X,
-                          (char *) &ieee8021xMode, sizeof(BOOLEAN)) < 0) {
-               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                          "OID_802_11_SET_IEEE8021X(%d)",
-                          (int) ieee8021xMode);
-       }
+               /* notify driver that IEEE8021x mode is enabled */
+               if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
+                       ieee8021xMode = TRUE;
+                       if (drv->bAddWepKey)
+                               ieee8021x_required_key = FALSE;
+               } else
+                       ieee8021xMode = FALSE;
 
-       if (ralink_set_oid(drv, OID_802_11_WEP_STATUS,
-                        (char *) &encr, sizeof(encr)) < 0) {
-               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                          "OID_802_11_WEP_STATUS(%d)",
-                          (int) encr);
-       }
+               if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY,
+                                  (char *) &ieee8021x_required_key,
+                                  sizeof(BOOLEAN)) < 0) {
+                       wpa_printf(MSG_DEBUG, "ERROR: Failed to set "
+                                  "OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
+                                  (int) ieee8021x_required_key);
+               } else {
+                       wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s",
+                                  ieee8021x_required_key ? "TRUE" : "FALSE");
+               }
 
-       if ((ieee8021xMode == FALSE) &&
-           (encr == Ndis802_11Encryption1Enabled)) {
-               /* static WEP */
-               int enabled = 0;
-               if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED,
-                                  (char *) &enabled, sizeof(enabled)) < 0) {
+               if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X,
+                                  (char *) &ieee8021xMode, sizeof(BOOLEAN)) <
+                   0) {
                        wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-                                  "OID_802_11_DROP_UNENCRYPTED(%d)",
-                                  (int) encr);
+                                  "OID_802_11_SET_IEEE8021X(%d)",
+                                  (int) ieee8021xMode);
+               }
+
+               ralink_set_encr_type(drv, encr);
+
+               if ((ieee8021xMode == FALSE) &&
+                   (encr == Ndis802_11Encryption1Enabled)) {
+                       /* static WEP */
+                       int enabled = 0;
+                       if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED,
+                                          (char *) &enabled, sizeof(enabled))
+                           < 0) {
+                               wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+                                          "OID_802_11_DROP_UNENCRYPTED(%d)",
+                                          (int) encr);
+                       }
                }
        }
 
@@ -1485,8 +1488,8 @@ const struct wpa_driver_ops wpa_driver_ralink_ops = {
        .init = wpa_driver_ralink_init,
        .deinit = wpa_driver_ralink_deinit,
        .set_countermeasures    = wpa_driver_ralink_set_countermeasures,
-       .scan = wpa_driver_ralink_scan,
-       .get_scan_results = wpa_driver_ralink_get_scan_results,
+       .scan2 = wpa_driver_ralink_scan,
+       .get_scan_results2 = wpa_driver_ralink_get_scan_results,
        .deauthenticate = wpa_driver_ralink_deauthenticate,
        .disassociate = wpa_driver_ralink_disassociate,
        .associate = wpa_driver_ralink_associate,