driver_wext.c
Go to the documentation of this file.
00001 /*
00002  * Driver interaction with generic Linux Wireless Extensions
00003  * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  *
00014  * This file implements a driver interface for the Linux Wireless Extensions.
00015  * When used with WE-18 or newer, this interface can be used as-is with number
00016  * of drivers. In addition to this, some of the common functions in this file
00017  * can be used by other driver interface implementations that use generic WE
00018  * ioctls, but require private ioctls for some of the functionality.
00019  */
00020 
00021 #include "includes.h"
00022 #include <sys/ioctl.h>
00023 #include <sys/stat.h>
00024 #include <net/if_arp.h>
00025 
00026 #include "wireless_copy.h"
00027 #include "common.h"
00028 #include "eloop.h"
00029 #include "common/ieee802_11_defs.h"
00030 #include "common/wpa_common.h"
00031 #include "priv_netlink.h"
00032 #include "netlink.h"
00033 #include "linux_ioctl.h"
00034 #include "driver.h"
00035 #include "driver_wext.h"
00036 
00037 
00038 static int wpa_driver_wext_flush_pmkid(void *priv);
00039 static int wpa_driver_wext_get_range(void *priv);
00040 static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
00041 static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
00042 static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
00043 
00044 
00045 int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
00046                                    int idx, u32 value)
00047 {
00048         struct iwreq iwr;
00049         int ret = 0;
00050 
00051         os_memset(&iwr, 0, sizeof(iwr));
00052         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00053         iwr.u.param.flags = idx & IW_AUTH_INDEX;
00054         iwr.u.param.value = value;
00055 
00056         if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
00057                 if (errno != EOPNOTSUPP) {
00058                         wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
00059                                    "value 0x%x) failed: %s)",
00060                                    idx, value, strerror(errno));
00061                 }
00062                 ret = errno == EOPNOTSUPP ? -2 : -1;
00063         }
00064 
00065         return ret;
00066 }
00067 
00068 
00075 int wpa_driver_wext_get_bssid(void *priv, u8 *bssid)
00076 {
00077         struct wpa_driver_wext_data *drv = priv;
00078         struct iwreq iwr;
00079         int ret = 0;
00080 
00081         os_memset(&iwr, 0, sizeof(iwr));
00082         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00083 
00084         if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
00085                 perror("ioctl[SIOCGIWAP]");
00086                 ret = -1;
00087         }
00088         os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
00089 
00090         return ret;
00091 }
00092 
00093 
00100 int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid)
00101 {
00102         struct wpa_driver_wext_data *drv = priv;
00103         struct iwreq iwr;
00104         int ret = 0;
00105 
00106         os_memset(&iwr, 0, sizeof(iwr));
00107         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00108         iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
00109         if (bssid)
00110                 os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
00111         else
00112                 os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
00113 
00114         if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
00115                 perror("ioctl[SIOCSIWAP]");
00116                 ret = -1;
00117         }
00118 
00119         return ret;
00120 }
00121 
00122 
00129 int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
00130 {
00131         struct wpa_driver_wext_data *drv = priv;
00132         struct iwreq iwr;
00133         int ret = 0;
00134 
00135         os_memset(&iwr, 0, sizeof(iwr));
00136         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00137         iwr.u.essid.pointer = (caddr_t) ssid;
00138         iwr.u.essid.length = 32;
00139 
00140         if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
00141                 perror("ioctl[SIOCGIWESSID]");
00142                 ret = -1;
00143         } else {
00144                 ret = iwr.u.essid.length;
00145                 if (ret > 32)
00146                         ret = 32;
00147                 /* Some drivers include nul termination in the SSID, so let's
00148                  * remove it here before further processing. WE-21 changes this
00149                  * to explicitly require the length _not_ to include nul
00150                  * termination. */
00151                 if (ret > 0 && ssid[ret - 1] == '\0' &&
00152                     drv->we_version_compiled < 21)
00153                         ret--;
00154         }
00155 
00156         return ret;
00157 }
00158 
00159 
00167 int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
00168 {
00169         struct wpa_driver_wext_data *drv = priv;
00170         struct iwreq iwr;
00171         int ret = 0;
00172         char buf[33];
00173 
00174         if (ssid_len > 32)
00175                 return -1;
00176 
00177         os_memset(&iwr, 0, sizeof(iwr));
00178         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00179         /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
00180         iwr.u.essid.flags = (ssid_len != 0);
00181         os_memset(buf, 0, sizeof(buf));
00182         os_memcpy(buf, ssid, ssid_len);
00183         iwr.u.essid.pointer = (caddr_t) buf;
00184         if (drv->we_version_compiled < 21) {
00185                 /* For historic reasons, set SSID length to include one extra
00186                  * character, C string nul termination, even though SSID is
00187                  * really an octet string that should not be presented as a C
00188                  * string. Some Linux drivers decrement the length by one and
00189                  * can thus end up missing the last octet of the SSID if the
00190                  * length is not incremented here. WE-21 changes this to
00191                  * explicitly require the length _not_ to include nul
00192                  * termination. */
00193                 if (ssid_len)
00194                         ssid_len++;
00195         }
00196         iwr.u.essid.length = ssid_len;
00197 
00198         if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
00199                 perror("ioctl[SIOCSIWESSID]");
00200                 ret = -1;
00201         }
00202 
00203         return ret;
00204 }
00205 
00206 
00213 int wpa_driver_wext_set_freq(void *priv, int freq)
00214 {
00215         struct wpa_driver_wext_data *drv = priv;
00216         struct iwreq iwr;
00217         int ret = 0;
00218 
00219         os_memset(&iwr, 0, sizeof(iwr));
00220         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00221         iwr.u.freq.m = freq * 100000;
00222         iwr.u.freq.e = 1;
00223 
00224         if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
00225                 perror("ioctl[SIOCSIWFREQ]");
00226                 ret = -1;
00227         }
00228 
00229         return ret;
00230 }
00231 
00232 
00233 static void
00234 wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
00235 {
00236         union wpa_event_data data;
00237 
00238         wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
00239                    custom);
00240 
00241         os_memset(&data, 0, sizeof(data));
00242         /* Host AP driver */
00243         if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
00244                 data.michael_mic_failure.unicast =
00245                         os_strstr(custom, " unicast ") != NULL;
00246                 /* TODO: parse parameters(?) */
00247                 wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
00248         } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
00249                 char *spos;
00250                 int bytes;
00251                 u8 *req_ies = NULL, *resp_ies = NULL;
00252 
00253                 spos = custom + 17;
00254 
00255                 bytes = strspn(spos, "0123456789abcdefABCDEF");
00256                 if (!bytes || (bytes & 1))
00257                         return;
00258                 bytes /= 2;
00259 
00260                 req_ies = os_malloc(bytes);
00261                 if (req_ies == NULL ||
00262                     hexstr2bin(spos, req_ies, bytes) < 0)
00263                         goto done;
00264                 data.assoc_info.req_ies = req_ies;
00265                 data.assoc_info.req_ies_len = bytes;
00266 
00267                 spos += bytes * 2;
00268 
00269                 data.assoc_info.resp_ies = NULL;
00270                 data.assoc_info.resp_ies_len = 0;
00271 
00272                 if (os_strncmp(spos, " RespIEs=", 9) == 0) {
00273                         spos += 9;
00274 
00275                         bytes = strspn(spos, "0123456789abcdefABCDEF");
00276                         if (!bytes || (bytes & 1))
00277                                 goto done;
00278                         bytes /= 2;
00279 
00280                         resp_ies = os_malloc(bytes);
00281                         if (resp_ies == NULL ||
00282                             hexstr2bin(spos, resp_ies, bytes) < 0)
00283                                 goto done;
00284                         data.assoc_info.resp_ies = resp_ies;
00285                         data.assoc_info.resp_ies_len = bytes;
00286                 }
00287 
00288                 wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
00289 
00290         done:
00291                 os_free(resp_ies);
00292                 os_free(req_ies);
00293 #ifdef CONFIG_PEERKEY
00294         } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
00295                 if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
00296                         wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
00297                                    "STKSTART.request '%s'", custom + 17);
00298                         return;
00299                 }
00300                 wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
00301 #endif /* CONFIG_PEERKEY */
00302         }
00303 }
00304 
00305 
00306 static int wpa_driver_wext_event_wireless_michaelmicfailure(
00307         void *ctx, const char *ev, size_t len)
00308 {
00309         const struct iw_michaelmicfailure *mic;
00310         union wpa_event_data data;
00311 
00312         if (len < sizeof(*mic))
00313                 return -1;
00314 
00315         mic = (const struct iw_michaelmicfailure *) ev;
00316 
00317         wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
00318                    "flags=0x%x src_addr=" MACSTR, mic->flags,
00319                    MAC2STR(mic->src_addr.sa_data));
00320 
00321         os_memset(&data, 0, sizeof(data));
00322         data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
00323         wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
00324 
00325         return 0;
00326 }
00327 
00328 
00329 static int wpa_driver_wext_event_wireless_pmkidcand(
00330         struct wpa_driver_wext_data *drv, const char *ev, size_t len)
00331 {
00332         const struct iw_pmkid_cand *cand;
00333         union wpa_event_data data;
00334         const u8 *addr;
00335 
00336         if (len < sizeof(*cand))
00337                 return -1;
00338 
00339         cand = (const struct iw_pmkid_cand *) ev;
00340         addr = (const u8 *) cand->bssid.sa_data;
00341 
00342         wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
00343                    "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
00344                    cand->index, MAC2STR(addr));
00345 
00346         os_memset(&data, 0, sizeof(data));
00347         os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
00348         data.pmkid_candidate.index = cand->index;
00349         data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
00350         wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
00351 
00352         return 0;
00353 }
00354 
00355 
00356 static int wpa_driver_wext_event_wireless_assocreqie(
00357         struct wpa_driver_wext_data *drv, const char *ev, int len)
00358 {
00359         if (len < 0)
00360                 return -1;
00361 
00362         wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
00363                     len);
00364         os_free(drv->assoc_req_ies);
00365         drv->assoc_req_ies = os_malloc(len);
00366         if (drv->assoc_req_ies == NULL) {
00367                 drv->assoc_req_ies_len = 0;
00368                 return -1;
00369         }
00370         os_memcpy(drv->assoc_req_ies, ev, len);
00371         drv->assoc_req_ies_len = len;
00372 
00373         return 0;
00374 }
00375 
00376 
00377 static int wpa_driver_wext_event_wireless_assocrespie(
00378         struct wpa_driver_wext_data *drv, const char *ev, int len)
00379 {
00380         if (len < 0)
00381                 return -1;
00382 
00383         wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
00384                     len);
00385         os_free(drv->assoc_resp_ies);
00386         drv->assoc_resp_ies = os_malloc(len);
00387         if (drv->assoc_resp_ies == NULL) {
00388                 drv->assoc_resp_ies_len = 0;
00389                 return -1;
00390         }
00391         os_memcpy(drv->assoc_resp_ies, ev, len);
00392         drv->assoc_resp_ies_len = len;
00393 
00394         return 0;
00395 }
00396 
00397 
00398 static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
00399 {
00400         union wpa_event_data data;
00401 
00402         if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
00403                 return;
00404 
00405         os_memset(&data, 0, sizeof(data));
00406         if (drv->assoc_req_ies) {
00407                 data.assoc_info.req_ies = drv->assoc_req_ies;
00408                 data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
00409         }
00410         if (drv->assoc_resp_ies) {
00411                 data.assoc_info.resp_ies = drv->assoc_resp_ies;
00412                 data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
00413         }
00414 
00415         wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
00416 
00417         os_free(drv->assoc_req_ies);
00418         drv->assoc_req_ies = NULL;
00419         os_free(drv->assoc_resp_ies);
00420         drv->assoc_resp_ies = NULL;
00421 }
00422 
00423 
00424 static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
00425                                            char *data, int len)
00426 {
00427         struct iw_event iwe_buf, *iwe = &iwe_buf;
00428         char *pos, *end, *custom, *buf;
00429 
00430         pos = data;
00431         end = data + len;
00432 
00433         while (pos + IW_EV_LCP_LEN <= end) {
00434                 /* Event data may be unaligned, so make a local, aligned copy
00435                  * before processing. */
00436                 os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
00437                 wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
00438                            iwe->cmd, iwe->len);
00439                 if (iwe->len <= IW_EV_LCP_LEN)
00440                         return;
00441 
00442                 custom = pos + IW_EV_POINT_LEN;
00443                 if (drv->we_version_compiled > 18 &&
00444                     (iwe->cmd == IWEVMICHAELMICFAILURE ||
00445                      iwe->cmd == IWEVCUSTOM ||
00446                      iwe->cmd == IWEVASSOCREQIE ||
00447                      iwe->cmd == IWEVASSOCRESPIE ||
00448                      iwe->cmd == IWEVPMKIDCAND)) {
00449                         /* WE-19 removed the pointer from struct iw_point */
00450                         char *dpos = (char *) &iwe_buf.u.data.length;
00451                         int dlen = dpos - (char *) &iwe_buf;
00452                         os_memcpy(dpos, pos + IW_EV_LCP_LEN,
00453                                   sizeof(struct iw_event) - dlen);
00454                 } else {
00455                         os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
00456                         custom += IW_EV_POINT_OFF;
00457                 }
00458 
00459                 switch (iwe->cmd) {
00460                 case SIOCGIWAP:
00461                         wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
00462                                    MACSTR,
00463                                    MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
00464                         if (is_zero_ether_addr(
00465                                     (const u8 *) iwe->u.ap_addr.sa_data) ||
00466                             os_memcmp(iwe->u.ap_addr.sa_data,
00467                                       "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
00468                             0) {
00469                                 os_free(drv->assoc_req_ies);
00470                                 drv->assoc_req_ies = NULL;
00471                                 os_free(drv->assoc_resp_ies);
00472                                 drv->assoc_resp_ies = NULL;
00473                                 wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
00474                                                      NULL);
00475                         
00476                         } else {
00477                                 wpa_driver_wext_event_assoc_ies(drv);
00478                                 wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
00479                                                      NULL);
00480                         }
00481                         break;
00482                 case IWEVMICHAELMICFAILURE:
00483                         if (custom + iwe->u.data.length > end) {
00484                                 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
00485                                            "IWEVMICHAELMICFAILURE length");
00486                                 return;
00487                         }
00488                         wpa_driver_wext_event_wireless_michaelmicfailure(
00489                                 drv->ctx, custom, iwe->u.data.length);
00490                         break;
00491                 case IWEVCUSTOM:
00492                         if (custom + iwe->u.data.length > end) {
00493                                 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
00494                                            "IWEVCUSTOM length");
00495                                 return;
00496                         }
00497                         buf = os_malloc(iwe->u.data.length + 1);
00498                         if (buf == NULL)
00499                                 return;
00500                         os_memcpy(buf, custom, iwe->u.data.length);
00501                         buf[iwe->u.data.length] = '\0';
00502                         wpa_driver_wext_event_wireless_custom(drv->ctx, buf);
00503                         os_free(buf);
00504                         break;
00505                 case SIOCGIWSCAN:
00506                         drv->scan_complete_events = 1;
00507                         eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
00508                                              drv, drv->ctx);
00509                         wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS,
00510                                              NULL);
00511                         break;
00512                 case IWEVASSOCREQIE:
00513                         if (custom + iwe->u.data.length > end) {
00514                                 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
00515                                            "IWEVASSOCREQIE length");
00516                                 return;
00517                         }
00518                         wpa_driver_wext_event_wireless_assocreqie(
00519                                 drv, custom, iwe->u.data.length);
00520                         break;
00521                 case IWEVASSOCRESPIE:
00522                         if (custom + iwe->u.data.length > end) {
00523                                 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
00524                                            "IWEVASSOCRESPIE length");
00525                                 return;
00526                         }
00527                         wpa_driver_wext_event_wireless_assocrespie(
00528                                 drv, custom, iwe->u.data.length);
00529                         break;
00530                 case IWEVPMKIDCAND:
00531                         if (custom + iwe->u.data.length > end) {
00532                                 wpa_printf(MSG_DEBUG, "WEXT: Invalid "
00533                                            "IWEVPMKIDCAND length");
00534                                 return;
00535                         }
00536                         wpa_driver_wext_event_wireless_pmkidcand(
00537                                 drv, custom, iwe->u.data.length);
00538                         break;
00539                 }
00540 
00541                 pos += iwe->len;
00542         }
00543 }
00544 
00545 
00546 static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
00547                                        char *buf, size_t len, int del)
00548 {
00549         union wpa_event_data event;
00550 
00551         os_memset(&event, 0, sizeof(event));
00552         if (len > sizeof(event.interface_status.ifname))
00553                 len = sizeof(event.interface_status.ifname) - 1;
00554         os_memcpy(event.interface_status.ifname, buf, len);
00555         event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
00556                 EVENT_INTERFACE_ADDED;
00557 
00558         wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
00559                    del ? "DEL" : "NEW",
00560                    event.interface_status.ifname,
00561                    del ? "removed" : "added");
00562 
00563         if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
00564                 if (del)
00565                         drv->if_removed = 1;
00566                 else
00567                         drv->if_removed = 0;
00568         }
00569 
00570         wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
00571 }
00572 
00573 
00574 static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
00575                                       u8 *buf, size_t len)
00576 {
00577         int attrlen, rta_len;
00578         struct rtattr *attr;
00579 
00580         attrlen = len;
00581         attr = (struct rtattr *) buf;
00582 
00583         rta_len = RTA_ALIGN(sizeof(struct rtattr));
00584         while (RTA_OK(attr, attrlen)) {
00585                 if (attr->rta_type == IFLA_IFNAME) {
00586                         if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
00587                             == 0)
00588                                 return 1;
00589                         else
00590                                 break;
00591                 }
00592                 attr = RTA_NEXT(attr, attrlen);
00593         }
00594 
00595         return 0;
00596 }
00597 
00598 
00599 static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
00600                                        int ifindex, u8 *buf, size_t len)
00601 {
00602         if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
00603                 return 1;
00604 
00605         if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) {
00606                 drv->ifindex = if_nametoindex(drv->ifname);
00607                 wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
00608                            "interface");
00609                 wpa_driver_wext_finish_drv_init(drv);
00610                 return 1;
00611         }
00612 
00613         return 0;
00614 }
00615 
00616 
00617 static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
00618                                               u8 *buf, size_t len)
00619 {
00620         struct wpa_driver_wext_data *drv = ctx;
00621         int attrlen, rta_len;
00622         struct rtattr *attr;
00623 
00624         if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) {
00625                 wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
00626                            ifi->ifi_index);
00627                 return;
00628         }
00629 
00630         wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
00631                    "(%s%s%s%s)",
00632                    drv->operstate, ifi->ifi_flags,
00633                    (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
00634                    (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
00635                    (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
00636                    (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
00637         /*
00638          * Some drivers send the association event before the operup event--in
00639          * this case, lifting operstate in wpa_driver_wext_set_operstate()
00640          * fails. This will hit us when wpa_supplicant does not need to do
00641          * IEEE 802.1X authentication
00642          */
00643         if (drv->operstate == 1 &&
00644             (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
00645             !(ifi->ifi_flags & IFF_RUNNING))
00646                 netlink_send_oper_ifla(drv->netlink, drv->ifindex,
00647                                        -1, IF_OPER_UP);
00648 
00649         attrlen = len;
00650         attr = (struct rtattr *) buf;
00651 
00652         rta_len = RTA_ALIGN(sizeof(struct rtattr));
00653         while (RTA_OK(attr, attrlen)) {
00654                 if (attr->rta_type == IFLA_WIRELESS) {
00655                         wpa_driver_wext_event_wireless(
00656                                 drv, ((char *) attr) + rta_len,
00657                                 attr->rta_len - rta_len);
00658                 } else if (attr->rta_type == IFLA_IFNAME) {
00659                         wpa_driver_wext_event_link(drv,
00660                                                    ((char *) attr) + rta_len,
00661                                                    attr->rta_len - rta_len, 0);
00662                 }
00663                 attr = RTA_NEXT(attr, attrlen);
00664         }
00665 }
00666 
00667 
00668 static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi,
00669                                               u8 *buf, size_t len)
00670 {
00671         struct wpa_driver_wext_data *drv = ctx;
00672         int attrlen, rta_len;
00673         struct rtattr *attr;
00674 
00675         attrlen = len;
00676         attr = (struct rtattr *) buf;
00677 
00678         rta_len = RTA_ALIGN(sizeof(struct rtattr));
00679         while (RTA_OK(attr, attrlen)) {
00680                 if (attr->rta_type == IFLA_IFNAME) {
00681                         wpa_driver_wext_event_link(drv,
00682                                                    ((char *) attr) + rta_len,
00683                                                    attr->rta_len - rta_len, 1);
00684                 }
00685                 attr = RTA_NEXT(attr, attrlen);
00686         }
00687 }
00688 
00689 
00697 void * wpa_driver_wext_init(void *ctx, const char *ifname)
00698 {
00699         struct wpa_driver_wext_data *drv;
00700         struct netlink_config *cfg;
00701         char path[128];
00702         struct stat buf;
00703 
00704         drv = os_zalloc(sizeof(*drv));
00705         if (drv == NULL)
00706                 return NULL;
00707         drv->ctx = ctx;
00708         os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
00709 
00710         os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);
00711         if (stat(path, &buf) == 0) {
00712                 wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
00713                 drv->cfg80211 = 1;
00714         }
00715 
00716         drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
00717         if (drv->ioctl_sock < 0) {
00718                 perror("socket(PF_INET,SOCK_DGRAM)");
00719                 goto err1;
00720         }
00721 
00722         cfg = os_zalloc(sizeof(*cfg));
00723         if (cfg == NULL)
00724                 goto err1;
00725         cfg->ctx = drv;
00726         cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink;
00727         cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink;
00728         drv->netlink = netlink_init(cfg);
00729         if (drv->netlink == NULL) {
00730                 os_free(cfg);
00731                 goto err2;
00732         }
00733 
00734         drv->mlme_sock = -1;
00735 
00736         if (wpa_driver_wext_finish_drv_init(drv) < 0)
00737                 goto err3;
00738 
00739         wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1);
00740 
00741         return drv;
00742 
00743 err3:
00744         netlink_deinit(drv->netlink);
00745 err2:
00746         close(drv->ioctl_sock);
00747 err1:
00748         os_free(drv);
00749         return NULL;
00750 }
00751 
00752 
00753 static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
00754 {
00755         if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0)
00756                 return -1;
00757 
00758         /*
00759          * Make sure that the driver does not have any obsolete PMKID entries.
00760          */
00761         wpa_driver_wext_flush_pmkid(drv);
00762 
00763         if (wpa_driver_wext_set_mode(drv, 0) < 0) {
00764                 wpa_printf(MSG_DEBUG, "Could not configure driver to use "
00765                            "managed mode");
00766                 /* Try to use it anyway */
00767         }
00768 
00769         wpa_driver_wext_get_range(drv);
00770 
00771         /*
00772          * Unlock the driver's BSSID and force to a random SSID to clear any
00773          * previous association the driver might have when the supplicant
00774          * starts up.
00775          */
00776         wpa_driver_wext_disconnect(drv);
00777 
00778         drv->ifindex = if_nametoindex(drv->ifname);
00779 
00780         if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
00781                 /*
00782                  * Host AP driver may use both wlan# and wifi# interface in
00783                  * wireless events. Since some of the versions included WE-18
00784                  * support, let's add the alternative ifindex also from
00785                  * driver_wext.c for the time being. This may be removed at
00786                  * some point once it is believed that old versions of the
00787                  * driver are not in use anymore.
00788                  */
00789                 char ifname2[IFNAMSIZ + 1];
00790                 os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
00791                 os_memcpy(ifname2, "wifi", 4);
00792                 wpa_driver_wext_alternative_ifindex(drv, ifname2);
00793         }
00794 
00795         netlink_send_oper_ifla(drv->netlink, drv->ifindex,
00796                                1, IF_OPER_DORMANT);
00797 
00798         return 0;
00799 }
00800 
00801 
00809 void wpa_driver_wext_deinit(void *priv)
00810 {
00811         struct wpa_driver_wext_data *drv = priv;
00812 
00813         wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0);
00814 
00815         eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
00816 
00817         /*
00818          * Clear possibly configured driver parameters in order to make it
00819          * easier to use the driver after wpa_supplicant has been terminated.
00820          */
00821         wpa_driver_wext_disconnect(drv);
00822 
00823         netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
00824         netlink_deinit(drv->netlink);
00825 
00826         if (drv->mlme_sock >= 0)
00827                 eloop_unregister_read_sock(drv->mlme_sock);
00828 
00829         (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
00830 
00831         close(drv->ioctl_sock);
00832         if (drv->mlme_sock >= 0)
00833                 close(drv->mlme_sock);
00834         os_free(drv->assoc_req_ies);
00835         os_free(drv->assoc_resp_ies);
00836         os_free(drv);
00837 }
00838 
00839 
00848 void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
00849 {
00850         wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
00851         wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
00852 }
00853 
00854 
00861 int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
00862 {
00863         struct wpa_driver_wext_data *drv = priv;
00864         struct iwreq iwr;
00865         int ret = 0, timeout;
00866         struct iw_scan_req req;
00867         const u8 *ssid = params->ssids[0].ssid;
00868         size_t ssid_len = params->ssids[0].ssid_len;
00869 
00870         if (ssid_len > IW_ESSID_MAX_SIZE) {
00871                 wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
00872                            __FUNCTION__, (unsigned long) ssid_len);
00873                 return -1;
00874         }
00875 
00876         os_memset(&iwr, 0, sizeof(iwr));
00877         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00878 
00879         if (ssid && ssid_len) {
00880                 os_memset(&req, 0, sizeof(req));
00881                 req.essid_len = ssid_len;
00882                 req.bssid.sa_family = ARPHRD_ETHER;
00883                 os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
00884                 os_memcpy(req.essid, ssid, ssid_len);
00885                 iwr.u.data.pointer = (caddr_t) &req;
00886                 iwr.u.data.length = sizeof(req);
00887                 iwr.u.data.flags = IW_SCAN_THIS_ESSID;
00888         }
00889 
00890         if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
00891                 perror("ioctl[SIOCSIWSCAN]");
00892                 ret = -1;
00893         }
00894 
00895         /* Not all drivers generate "scan completed" wireless event, so try to
00896          * read results after a timeout. */
00897         timeout = 5;
00898         if (drv->scan_complete_events) {
00899                 /*
00900                  * The driver seems to deliver SIOCGIWSCAN events to notify
00901                  * when scan is complete, so use longer timeout to avoid race
00902                  * conditions with scanning and following association request.
00903                  */
00904                 timeout = 30;
00905         }
00906         wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
00907                    "seconds", ret, timeout);
00908         eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
00909         eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
00910                                drv->ctx);
00911 
00912         return ret;
00913 }
00914 
00915 
00916 static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv,
00917                                     size_t *len)
00918 {
00919         struct iwreq iwr;
00920         u8 *res_buf;
00921         size_t res_buf_len;
00922 
00923         res_buf_len = IW_SCAN_MAX_DATA;
00924         for (;;) {
00925                 res_buf = os_malloc(res_buf_len);
00926                 if (res_buf == NULL)
00927                         return NULL;
00928                 os_memset(&iwr, 0, sizeof(iwr));
00929                 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00930                 iwr.u.data.pointer = res_buf;
00931                 iwr.u.data.length = res_buf_len;
00932 
00933                 if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
00934                         break;
00935 
00936                 if (errno == E2BIG && res_buf_len < 65535) {
00937                         os_free(res_buf);
00938                         res_buf = NULL;
00939                         res_buf_len *= 2;
00940                         if (res_buf_len > 65535)
00941                                 res_buf_len = 65535; /* 16-bit length field */
00942                         wpa_printf(MSG_DEBUG, "Scan results did not fit - "
00943                                    "trying larger buffer (%lu bytes)",
00944                                    (unsigned long) res_buf_len);
00945                 } else {
00946                         perror("ioctl[SIOCGIWSCAN]");
00947                         os_free(res_buf);
00948                         return NULL;
00949                 }
00950         }
00951 
00952         if (iwr.u.data.length > res_buf_len) {
00953                 os_free(res_buf);
00954                 return NULL;
00955         }
00956         *len = iwr.u.data.length;
00957 
00958         return res_buf;
00959 }
00960 
00961 
00962 /*
00963  * Data structure for collecting WEXT scan results. This is needed to allow
00964  * the various methods of reporting IEs to be combined into a single IE buffer.
00965  */
00966 struct wext_scan_data {
00967         struct wpa_scan_res res;
00968         u8 *ie;
00969         size_t ie_len;
00970         u8 ssid[32];
00971         size_t ssid_len;
00972         int maxrate;
00973 };
00974 
00975 
00976 static void wext_get_scan_mode(struct iw_event *iwe,
00977                                struct wext_scan_data *res)
00978 {
00979         if (iwe->u.mode == IW_MODE_ADHOC)
00980                 res->res.caps |= IEEE80211_CAP_IBSS;
00981         else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
00982                 res->res.caps |= IEEE80211_CAP_ESS;
00983 }
00984 
00985 
00986 static void wext_get_scan_ssid(struct iw_event *iwe,
00987                                struct wext_scan_data *res, char *custom,
00988                                char *end)
00989 {
00990         int ssid_len = iwe->u.essid.length;
00991         if (custom + ssid_len > end)
00992                 return;
00993         if (iwe->u.essid.flags &&
00994             ssid_len > 0 &&
00995             ssid_len <= IW_ESSID_MAX_SIZE) {
00996                 os_memcpy(res->ssid, custom, ssid_len);
00997                 res->ssid_len = ssid_len;
00998         }
00999 }
01000 
01001 
01002 static void wext_get_scan_freq(struct iw_event *iwe,
01003                                struct wext_scan_data *res)
01004 {
01005         int divi = 1000000, i;
01006 
01007         if (iwe->u.freq.e == 0) {
01008                 /*
01009                  * Some drivers do not report frequency, but a channel.
01010                  * Try to map this to frequency by assuming they are using
01011                  * IEEE 802.11b/g.  But don't overwrite a previously parsed
01012                  * frequency if the driver sends both frequency and channel,
01013                  * since the driver may be sending an A-band channel that we
01014                  * don't handle here.
01015                  */
01016 
01017                 if (res->res.freq)
01018                         return;
01019 
01020                 if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
01021                         res->res.freq = 2407 + 5 * iwe->u.freq.m;
01022                         return;
01023                 } else if (iwe->u.freq.m == 14) {
01024                         res->res.freq = 2484;
01025                         return;
01026                 }
01027         }
01028 
01029         if (iwe->u.freq.e > 6) {
01030                 wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
01031                            MACSTR " m=%d e=%d)",
01032                            MAC2STR(res->res.bssid), iwe->u.freq.m,
01033                            iwe->u.freq.e);
01034                 return;
01035         }
01036 
01037         for (i = 0; i < iwe->u.freq.e; i++)
01038                 divi /= 10;
01039         res->res.freq = iwe->u.freq.m / divi;
01040 }
01041 
01042 
01043 static void wext_get_scan_qual(struct iw_event *iwe,
01044                                struct wext_scan_data *res)
01045 {
01046         res->res.qual = iwe->u.qual.qual;
01047         res->res.noise = iwe->u.qual.noise;
01048         res->res.level = iwe->u.qual.level;
01049         if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID)
01050                 res->res.flags |= WPA_SCAN_QUAL_INVALID;
01051         if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID)
01052                 res->res.flags |= WPA_SCAN_LEVEL_INVALID;
01053         if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID)
01054                 res->res.flags |= WPA_SCAN_NOISE_INVALID;
01055         if (iwe->u.qual.updated & IW_QUAL_DBM)
01056                 res->res.flags |= WPA_SCAN_LEVEL_DBM;
01057 }
01058 
01059 
01060 static void wext_get_scan_encode(struct iw_event *iwe,
01061                                  struct wext_scan_data *res)
01062 {
01063         if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
01064                 res->res.caps |= IEEE80211_CAP_PRIVACY;
01065 }
01066 
01067 
01068 static void wext_get_scan_rate(struct iw_event *iwe,
01069                                struct wext_scan_data *res, char *pos,
01070                                char *end)
01071 {
01072         int maxrate;
01073         char *custom = pos + IW_EV_LCP_LEN;
01074         struct iw_param p;
01075         size_t clen;
01076 
01077         clen = iwe->len;
01078         if (custom + clen > end)
01079                 return;
01080         maxrate = 0;
01081         while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
01082                 /* Note: may be misaligned, make a local, aligned copy */
01083                 os_memcpy(&p, custom, sizeof(struct iw_param));
01084                 if (p.value > maxrate)
01085                         maxrate = p.value;
01086                 clen -= sizeof(struct iw_param);
01087                 custom += sizeof(struct iw_param);
01088         }
01089 
01090         /* Convert the maxrate from WE-style (b/s units) to
01091          * 802.11 rates (500000 b/s units).
01092          */
01093         res->maxrate = maxrate / 500000;
01094 }
01095 
01096 
01097 static void wext_get_scan_iwevgenie(struct iw_event *iwe,
01098                                     struct wext_scan_data *res, char *custom,
01099                                     char *end)
01100 {
01101         char *genie, *gpos, *gend;
01102         u8 *tmp;
01103 
01104         if (iwe->u.data.length == 0)
01105                 return;
01106 
01107         gpos = genie = custom;
01108         gend = genie + iwe->u.data.length;
01109         if (gend > end) {
01110                 wpa_printf(MSG_INFO, "IWEVGENIE overflow");
01111                 return;
01112         }
01113 
01114         tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
01115         if (tmp == NULL)
01116                 return;
01117         os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
01118         res->ie = tmp;
01119         res->ie_len += gend - gpos;
01120 }
01121 
01122 
01123 static void wext_get_scan_custom(struct iw_event *iwe,
01124                                  struct wext_scan_data *res, char *custom,
01125                                  char *end)
01126 {
01127         size_t clen;
01128         u8 *tmp;
01129 
01130         clen = iwe->u.data.length;
01131         if (custom + clen > end)
01132                 return;
01133 
01134         if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
01135                 char *spos;
01136                 int bytes;
01137                 spos = custom + 7;
01138                 bytes = custom + clen - spos;
01139                 if (bytes & 1 || bytes == 0)
01140                         return;
01141                 bytes /= 2;
01142                 tmp = os_realloc(res->ie, res->ie_len + bytes);
01143                 if (tmp == NULL)
01144                         return;
01145                 res->ie = tmp;
01146                 if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
01147                         return;
01148                 res->ie_len += bytes;
01149         } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
01150                 char *spos;
01151                 int bytes;
01152                 spos = custom + 7;
01153                 bytes = custom + clen - spos;
01154                 if (bytes & 1 || bytes == 0)
01155                         return;
01156                 bytes /= 2;
01157                 tmp = os_realloc(res->ie, res->ie_len + bytes);
01158                 if (tmp == NULL)
01159                         return;
01160                 res->ie = tmp;
01161                 if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0)
01162                         return;
01163                 res->ie_len += bytes;
01164         } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
01165                 char *spos;
01166                 int bytes;
01167                 u8 bin[8];
01168                 spos = custom + 4;
01169                 bytes = custom + clen - spos;
01170                 if (bytes != 16) {
01171                         wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
01172                         return;
01173                 }
01174                 bytes /= 2;
01175                 if (hexstr2bin(spos, bin, bytes) < 0) {
01176                         wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value");
01177                         return;
01178                 }
01179                 res->res.tsf += WPA_GET_BE64(bin);
01180         }
01181 }
01182 
01183 
01184 static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd)
01185 {
01186         return drv->we_version_compiled > 18 &&
01187                 (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
01188                  cmd == IWEVGENIE || cmd == IWEVCUSTOM);
01189 }
01190 
01191 
01192 static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
01193                                            struct wext_scan_data *data)
01194 {
01195         struct wpa_scan_res **tmp;
01196         struct wpa_scan_res *r;
01197         size_t extra_len;
01198         u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
01199 
01200         /* Figure out whether we need to fake any IEs */
01201         pos = data->ie;
01202         end = pos + data->ie_len;
01203         while (pos && pos + 1 < end) {
01204                 if (pos + 2 + pos[1] > end)
01205                         break;
01206                 if (pos[0] == WLAN_EID_SSID)
01207                         ssid_ie = pos;
01208                 else if (pos[0] == WLAN_EID_SUPP_RATES)
01209                         rate_ie = pos;
01210                 else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
01211                         rate_ie = pos;
01212                 pos += 2 + pos[1];
01213         }
01214 
01215         extra_len = 0;
01216         if (ssid_ie == NULL)
01217                 extra_len += 2 + data->ssid_len;
01218         if (rate_ie == NULL && data->maxrate)
01219                 extra_len += 3;
01220 
01221         r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
01222         if (r == NULL)
01223                 return;
01224         os_memcpy(r, &data->res, sizeof(*r));
01225         r->ie_len = extra_len + data->ie_len;
01226         pos = (u8 *) (r + 1);
01227         if (ssid_ie == NULL) {
01228                 /*
01229                  * Generate a fake SSID IE since the driver did not report
01230                  * a full IE list.
01231                  */
01232                 *pos++ = WLAN_EID_SSID;
01233                 *pos++ = data->ssid_len;
01234                 os_memcpy(pos, data->ssid, data->ssid_len);
01235                 pos += data->ssid_len;
01236         }
01237         if (rate_ie == NULL && data->maxrate) {
01238                 /*
01239                  * Generate a fake Supported Rates IE since the driver did not
01240                  * report a full IE list.
01241                  */
01242                 *pos++ = WLAN_EID_SUPP_RATES;
01243                 *pos++ = 1;
01244                 *pos++ = data->maxrate;
01245         }
01246         if (data->ie)
01247                 os_memcpy(pos, data->ie, data->ie_len);
01248 
01249         tmp = os_realloc(res->res,
01250                          (res->num + 1) * sizeof(struct wpa_scan_res *));
01251         if (tmp == NULL) {
01252                 os_free(r);
01253                 return;
01254         }
01255         tmp[res->num++] = r;
01256         res->res = tmp;
01257 }
01258                                       
01259 
01265 struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
01266 {
01267         struct wpa_driver_wext_data *drv = priv;
01268         size_t ap_num = 0, len;
01269         int first;
01270         u8 *res_buf;
01271         struct iw_event iwe_buf, *iwe = &iwe_buf;
01272         char *pos, *end, *custom;
01273         struct wpa_scan_results *res;
01274         struct wext_scan_data data;
01275 
01276         res_buf = wpa_driver_wext_giwscan(drv, &len);
01277         if (res_buf == NULL)
01278                 return NULL;
01279 
01280         ap_num = 0;
01281         first = 1;
01282 
01283         res = os_zalloc(sizeof(*res));
01284         if (res == NULL) {
01285                 os_free(res_buf);
01286                 return NULL;
01287         }
01288 
01289         pos = (char *) res_buf;
01290         end = (char *) res_buf + len;
01291         os_memset(&data, 0, sizeof(data));
01292 
01293         while (pos + IW_EV_LCP_LEN <= end) {
01294                 /* Event data may be unaligned, so make a local, aligned copy
01295                  * before processing. */
01296                 os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
01297                 if (iwe->len <= IW_EV_LCP_LEN)
01298                         break;
01299 
01300                 custom = pos + IW_EV_POINT_LEN;
01301                 if (wext_19_iw_point(drv, iwe->cmd)) {
01302                         /* WE-19 removed the pointer from struct iw_point */
01303                         char *dpos = (char *) &iwe_buf.u.data.length;
01304                         int dlen = dpos - (char *) &iwe_buf;
01305                         os_memcpy(dpos, pos + IW_EV_LCP_LEN,
01306                                   sizeof(struct iw_event) - dlen);
01307                 } else {
01308                         os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
01309                         custom += IW_EV_POINT_OFF;
01310                 }
01311 
01312                 switch (iwe->cmd) {
01313                 case SIOCGIWAP:
01314                         if (!first)
01315                                 wpa_driver_wext_add_scan_entry(res, &data);
01316                         first = 0;
01317                         os_free(data.ie);
01318                         os_memset(&data, 0, sizeof(data));
01319                         os_memcpy(data.res.bssid,
01320                                   iwe->u.ap_addr.sa_data, ETH_ALEN);
01321                         break;
01322                 case SIOCGIWMODE:
01323                         wext_get_scan_mode(iwe, &data);
01324                         break;
01325                 case SIOCGIWESSID:
01326                         wext_get_scan_ssid(iwe, &data, custom, end);
01327                         break;
01328                 case SIOCGIWFREQ:
01329                         wext_get_scan_freq(iwe, &data);
01330                         break;
01331                 case IWEVQUAL:
01332                         wext_get_scan_qual(iwe, &data);
01333                         break;
01334                 case SIOCGIWENCODE:
01335                         wext_get_scan_encode(iwe, &data);
01336                         break;
01337                 case SIOCGIWRATE:
01338                         wext_get_scan_rate(iwe, &data, pos, end);
01339                         break;
01340                 case IWEVGENIE:
01341                         wext_get_scan_iwevgenie(iwe, &data, custom, end);
01342                         break;
01343                 case IWEVCUSTOM:
01344                         wext_get_scan_custom(iwe, &data, custom, end);
01345                         break;
01346                 }
01347 
01348                 pos += iwe->len;
01349         }
01350         os_free(res_buf);
01351         res_buf = NULL;
01352         if (!first)
01353                 wpa_driver_wext_add_scan_entry(res, &data);
01354         os_free(data.ie);
01355 
01356         wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
01357                    (unsigned long) len, (unsigned long) res->num);
01358 
01359         return res;
01360 }
01361 
01362 
01363 static int wpa_driver_wext_get_range(void *priv)
01364 {
01365         struct wpa_driver_wext_data *drv = priv;
01366         struct iw_range *range;
01367         struct iwreq iwr;
01368         int minlen;
01369         size_t buflen;
01370 
01371         /*
01372          * Use larger buffer than struct iw_range in order to allow the
01373          * structure to grow in the future.
01374          */
01375         buflen = sizeof(struct iw_range) + 500;
01376         range = os_zalloc(buflen);
01377         if (range == NULL)
01378                 return -1;
01379 
01380         os_memset(&iwr, 0, sizeof(iwr));
01381         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01382         iwr.u.data.pointer = (caddr_t) range;
01383         iwr.u.data.length = buflen;
01384 
01385         minlen = ((char *) &range->enc_capa) - (char *) range +
01386                 sizeof(range->enc_capa);
01387 
01388         if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
01389                 perror("ioctl[SIOCGIWRANGE]");
01390                 os_free(range);
01391                 return -1;
01392         } else if (iwr.u.data.length >= minlen &&
01393                    range->we_version_compiled >= 18) {
01394                 wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
01395                            "WE(source)=%d enc_capa=0x%x",
01396                            range->we_version_compiled,
01397                            range->we_version_source,
01398                            range->enc_capa);
01399                 drv->has_capability = 1;
01400                 drv->we_version_compiled = range->we_version_compiled;
01401                 if (range->enc_capa & IW_ENC_CAPA_WPA) {
01402                         drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
01403                                 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
01404                 }
01405                 if (range->enc_capa & IW_ENC_CAPA_WPA2) {
01406                         drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
01407                                 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
01408                 }
01409                 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
01410                         WPA_DRIVER_CAPA_ENC_WEP104;
01411                 if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
01412                         drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
01413                 if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
01414                         drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
01415                 if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
01416                         drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
01417                 drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
01418                         WPA_DRIVER_AUTH_SHARED |
01419                         WPA_DRIVER_AUTH_LEAP;
01420                 drv->capa.max_scan_ssids = 1;
01421 
01422                 wpa_printf(MSG_DEBUG, "  capabilities: key_mgmt 0x%x enc 0x%x "
01423                            "flags 0x%x",
01424                            drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
01425         } else {
01426                 wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
01427                            "assuming WPA is not supported");
01428         }
01429 
01430         os_free(range);
01431         return 0;
01432 }
01433 
01434 
01435 static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
01436                                    const u8 *psk)
01437 {
01438         struct iw_encode_ext *ext;
01439         struct iwreq iwr;
01440         int ret;
01441 
01442         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01443 
01444         if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
01445                 return 0;
01446 
01447         if (!psk)
01448                 return 0;
01449 
01450         os_memset(&iwr, 0, sizeof(iwr));
01451         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01452 
01453         ext = os_zalloc(sizeof(*ext) + PMK_LEN);
01454         if (ext == NULL)
01455                 return -1;
01456 
01457         iwr.u.encoding.pointer = (caddr_t) ext;
01458         iwr.u.encoding.length = sizeof(*ext) + PMK_LEN;
01459         ext->key_len = PMK_LEN;
01460         os_memcpy(&ext->key, psk, ext->key_len);
01461         ext->alg = IW_ENCODE_ALG_PMK;
01462 
01463         ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
01464         if (ret < 0)
01465                 perror("ioctl[SIOCSIWENCODEEXT] PMK");
01466         os_free(ext);
01467 
01468         return ret;
01469 }
01470 
01471 
01472 static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
01473                                        const u8 *addr, int key_idx,
01474                                        int set_tx, const u8 *seq,
01475                                        size_t seq_len,
01476                                        const u8 *key, size_t key_len)
01477 {
01478         struct wpa_driver_wext_data *drv = priv;
01479         struct iwreq iwr;
01480         int ret = 0;
01481         struct iw_encode_ext *ext;
01482 
01483         if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) {
01484                 wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu",
01485                            __FUNCTION__, (unsigned long) seq_len);
01486                 return -1;
01487         }
01488 
01489         ext = os_zalloc(sizeof(*ext) + key_len);
01490         if (ext == NULL)
01491                 return -1;
01492         os_memset(&iwr, 0, sizeof(iwr));
01493         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01494         iwr.u.encoding.flags = key_idx + 1;
01495         iwr.u.encoding.flags |= IW_ENCODE_TEMP;
01496         if (alg == WPA_ALG_NONE)
01497                 iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
01498         iwr.u.encoding.pointer = (caddr_t) ext;
01499         iwr.u.encoding.length = sizeof(*ext) + key_len;
01500 
01501         if (addr == NULL ||
01502             os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
01503                 ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
01504         if (set_tx)
01505                 ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
01506 
01507         ext->addr.sa_family = ARPHRD_ETHER;
01508         if (addr)
01509                 os_memcpy(ext->addr.sa_data, addr, ETH_ALEN);
01510         else
01511                 os_memset(ext->addr.sa_data, 0xff, ETH_ALEN);
01512         if (key && key_len) {
01513                 os_memcpy(ext + 1, key, key_len);
01514                 ext->key_len = key_len;
01515         }
01516         switch (alg) {
01517         case WPA_ALG_NONE:
01518                 ext->alg = IW_ENCODE_ALG_NONE;
01519                 break;
01520         case WPA_ALG_WEP:
01521                 ext->alg = IW_ENCODE_ALG_WEP;
01522                 break;
01523         case WPA_ALG_TKIP:
01524                 ext->alg = IW_ENCODE_ALG_TKIP;
01525                 break;
01526         case WPA_ALG_CCMP:
01527                 ext->alg = IW_ENCODE_ALG_CCMP;
01528                 break;
01529         case WPA_ALG_PMK:
01530                 ext->alg = IW_ENCODE_ALG_PMK;
01531                 break;
01532 #ifdef CONFIG_IEEE80211W
01533         case WPA_ALG_IGTK:
01534                 ext->alg = IW_ENCODE_ALG_AES_CMAC;
01535                 break;
01536 #endif /* CONFIG_IEEE80211W */
01537         default:
01538                 wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
01539                            __FUNCTION__, alg);
01540                 os_free(ext);
01541                 return -1;
01542         }
01543 
01544         if (seq && seq_len) {
01545                 ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID;
01546                 os_memcpy(ext->rx_seq, seq, seq_len);
01547         }
01548 
01549         if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) {
01550                 ret = errno == EOPNOTSUPP ? -2 : -1;
01551                 if (errno == ENODEV) {
01552                         /*
01553                          * ndiswrapper seems to be returning incorrect error
01554                          * code.. */
01555                         ret = -2;
01556                 }
01557 
01558                 perror("ioctl[SIOCSIWENCODEEXT]");
01559         }
01560 
01561         os_free(ext);
01562         return ret;
01563 }
01564 
01565 
01592 int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
01593                             const u8 *addr, int key_idx,
01594                             int set_tx, const u8 *seq, size_t seq_len,
01595                             const u8 *key, size_t key_len)
01596 {
01597         struct wpa_driver_wext_data *drv = priv;
01598         struct iwreq iwr;
01599         int ret = 0;
01600 
01601         wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
01602                    "key_len=%lu",
01603                    __FUNCTION__, alg, key_idx, set_tx,
01604                    (unsigned long) seq_len, (unsigned long) key_len);
01605 
01606         ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
01607                                           seq, seq_len, key, key_len);
01608         if (ret == 0)
01609                 return 0;
01610 
01611         if (ret == -2 &&
01612             (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) {
01613                 wpa_printf(MSG_DEBUG, "Driver did not support "
01614                            "SIOCSIWENCODEEXT, trying SIOCSIWENCODE");
01615                 ret = 0;
01616         } else {
01617                 wpa_printf(MSG_DEBUG, "Driver did not support "
01618                            "SIOCSIWENCODEEXT");
01619                 return ret;
01620         }
01621 
01622         os_memset(&iwr, 0, sizeof(iwr));
01623         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01624         iwr.u.encoding.flags = key_idx + 1;
01625         iwr.u.encoding.flags |= IW_ENCODE_TEMP;
01626         if (alg == WPA_ALG_NONE)
01627                 iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
01628         iwr.u.encoding.pointer = (caddr_t) key;
01629         iwr.u.encoding.length = key_len;
01630 
01631         if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
01632                 perror("ioctl[SIOCSIWENCODE]");
01633                 ret = -1;
01634         }
01635 
01636         if (set_tx && alg != WPA_ALG_NONE) {
01637                 os_memset(&iwr, 0, sizeof(iwr));
01638                 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01639                 iwr.u.encoding.flags = key_idx + 1;
01640                 iwr.u.encoding.flags |= IW_ENCODE_TEMP;
01641                 iwr.u.encoding.pointer = (caddr_t) NULL;
01642                 iwr.u.encoding.length = 0;
01643                 if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
01644                         perror("ioctl[SIOCSIWENCODE] (set_tx)");
01645                         ret = -1;
01646                 }
01647         }
01648 
01649         return ret;
01650 }
01651 
01652 
01653 static int wpa_driver_wext_set_countermeasures(void *priv,
01654                                                int enabled)
01655 {
01656         struct wpa_driver_wext_data *drv = priv;
01657         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01658         return wpa_driver_wext_set_auth_param(drv,
01659                                               IW_AUTH_TKIP_COUNTERMEASURES,
01660                                               enabled);
01661 }
01662 
01663 
01664 static int wpa_driver_wext_set_drop_unencrypted(void *priv,
01665                                                 int enabled)
01666 {
01667         struct wpa_driver_wext_data *drv = priv;
01668         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01669         drv->use_crypt = enabled;
01670         return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
01671                                               enabled);
01672 }
01673 
01674 
01675 static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
01676                                 const u8 *addr, int cmd, int reason_code)
01677 {
01678         struct iwreq iwr;
01679         struct iw_mlme mlme;
01680         int ret = 0;
01681 
01682         os_memset(&iwr, 0, sizeof(iwr));
01683         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01684         os_memset(&mlme, 0, sizeof(mlme));
01685         mlme.cmd = cmd;
01686         mlme.reason_code = reason_code;
01687         mlme.addr.sa_family = ARPHRD_ETHER;
01688         os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
01689         iwr.u.data.pointer = (caddr_t) &mlme;
01690         iwr.u.data.length = sizeof(mlme);
01691 
01692         if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
01693                 perror("ioctl[SIOCSIWMLME]");
01694                 ret = -1;
01695         }
01696 
01697         return ret;
01698 }
01699 
01700 
01701 static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
01702 {
01703         struct iwreq iwr;
01704         const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
01705         u8 ssid[32];
01706         int i;
01707 
01708         /*
01709          * Only force-disconnect when the card is in infrastructure mode,
01710          * otherwise the driver might interpret the cleared BSSID and random
01711          * SSID as an attempt to create a new ad-hoc network.
01712          */
01713         os_memset(&iwr, 0, sizeof(iwr));
01714         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01715         if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
01716                 perror("ioctl[SIOCGIWMODE]");
01717                 iwr.u.mode = IW_MODE_INFRA;
01718         }
01719 
01720         if (iwr.u.mode == IW_MODE_INFRA) {
01721                 if (drv->cfg80211) {
01722                         /*
01723                          * cfg80211 supports SIOCSIWMLME commands, so there is
01724                          * no need for the random SSID hack, but clear the
01725                          * BSSID and SSID.
01726                          */
01727                         if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
01728                             wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
01729                                 wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
01730                                            "to disconnect");
01731                         }
01732                         return;
01733                 }
01734                 /*
01735                  * Clear the BSSID selection and set a random SSID to make sure
01736                  * the driver will not be trying to associate with something
01737                  * even if it does not understand SIOCSIWMLME commands (or
01738                  * tries to associate automatically after deauth/disassoc).
01739                  */
01740                 for (i = 0; i < 32; i++)
01741                         ssid[i] = rand() & 0xFF;
01742                 if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
01743                     wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
01744                         wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
01745                                    "BSSID/SSID to disconnect");
01746                 }
01747         }
01748 }
01749 
01750 
01751 static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
01752                                           int reason_code)
01753 {
01754         struct wpa_driver_wext_data *drv = priv;
01755         int ret;
01756         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01757         ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
01758         wpa_driver_wext_disconnect(drv);
01759         return ret;
01760 }
01761 
01762 
01763 static int wpa_driver_wext_disassociate(void *priv, const u8 *addr,
01764                                         int reason_code)
01765 {
01766         struct wpa_driver_wext_data *drv = priv;
01767         int ret;
01768         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01769         ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code);
01770         wpa_driver_wext_disconnect(drv);
01771         return ret;
01772 }
01773 
01774 
01775 static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
01776                                       size_t ie_len)
01777 {
01778         struct wpa_driver_wext_data *drv = priv;
01779         struct iwreq iwr;
01780         int ret = 0;
01781 
01782         os_memset(&iwr, 0, sizeof(iwr));
01783         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01784         iwr.u.data.pointer = (caddr_t) ie;
01785         iwr.u.data.length = ie_len;
01786 
01787         if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
01788                 perror("ioctl[SIOCSIWGENIE]");
01789                 ret = -1;
01790         }
01791 
01792         return ret;
01793 }
01794 
01795 
01796 int wpa_driver_wext_cipher2wext(int cipher)
01797 {
01798         switch (cipher) {
01799         case CIPHER_NONE:
01800                 return IW_AUTH_CIPHER_NONE;
01801         case CIPHER_WEP40:
01802                 return IW_AUTH_CIPHER_WEP40;
01803         case CIPHER_TKIP:
01804                 return IW_AUTH_CIPHER_TKIP;
01805         case CIPHER_CCMP:
01806                 return IW_AUTH_CIPHER_CCMP;
01807         case CIPHER_WEP104:
01808                 return IW_AUTH_CIPHER_WEP104;
01809         default:
01810                 return 0;
01811         }
01812 }
01813 
01814 
01815 int wpa_driver_wext_keymgmt2wext(int keymgmt)
01816 {
01817         switch (keymgmt) {
01818         case KEY_MGMT_802_1X:
01819         case KEY_MGMT_802_1X_NO_WPA:
01820                 return IW_AUTH_KEY_MGMT_802_1X;
01821         case KEY_MGMT_PSK:
01822                 return IW_AUTH_KEY_MGMT_PSK;
01823         default:
01824                 return 0;
01825         }
01826 }
01827 
01828 
01829 static int
01830 wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
01831                                   struct wpa_driver_associate_params *params)
01832 {
01833         struct iwreq iwr;
01834         int ret = 0;
01835 
01836         wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
01837                    "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
01838 
01839         os_memset(&iwr, 0, sizeof(iwr));
01840         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01841         /* Just changing mode, not actual keys */
01842         iwr.u.encoding.flags = 0;
01843         iwr.u.encoding.pointer = (caddr_t) NULL;
01844         iwr.u.encoding.length = 0;
01845 
01846         /*
01847          * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
01848          * different things. Here they are used to indicate Open System vs.
01849          * Shared Key authentication algorithm. However, some drivers may use
01850          * them to select between open/restricted WEP encrypted (open = allow
01851          * both unencrypted and encrypted frames; restricted = only allow
01852          * encrypted frames).
01853          */
01854 
01855         if (!drv->use_crypt) {
01856                 iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
01857         } else {
01858                 if (params->auth_alg & WPA_AUTH_ALG_OPEN)
01859                         iwr.u.encoding.flags |= IW_ENCODE_OPEN;
01860                 if (params->auth_alg & WPA_AUTH_ALG_SHARED)
01861                         iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
01862         }
01863 
01864         if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
01865                 perror("ioctl[SIOCSIWENCODE]");
01866                 ret = -1;
01867         }
01868 
01869         return ret;
01870 }
01871 
01872 
01873 int wpa_driver_wext_associate(void *priv,
01874                               struct wpa_driver_associate_params *params)
01875 {
01876         struct wpa_driver_wext_data *drv = priv;
01877         int ret = 0;
01878         int allow_unencrypted_eapol;
01879         int value;
01880 
01881         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01882 
01883         if (drv->cfg80211) {
01884                 /*
01885                  * Stop cfg80211 from trying to associate before we are done
01886                  * with all parameters.
01887                  */
01888                 wpa_driver_wext_set_ssid(drv, (u8 *) "", 0);
01889         }
01890 
01891         if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
01892             < 0)
01893                 ret = -1;
01894         if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0)
01895                 ret = -1;
01896         if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
01897                 ret = -1;
01898 
01899         /*
01900          * If the driver did not support SIOCSIWAUTH, fallback to
01901          * SIOCSIWENCODE here.
01902          */
01903         if (drv->auth_alg_fallback &&
01904             wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
01905                 ret = -1;
01906 
01907         if (!params->bssid &&
01908             wpa_driver_wext_set_bssid(drv, NULL) < 0)
01909                 ret = -1;
01910 
01911         /* TODO: should consider getting wpa version and cipher/key_mgmt suites
01912          * from configuration, not from here, where only the selected suite is
01913          * available */
01914         if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
01915             < 0)
01916                 ret = -1;
01917         if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
01918                 value = IW_AUTH_WPA_VERSION_DISABLED;
01919         else if (params->wpa_ie[0] == WLAN_EID_RSN)
01920                 value = IW_AUTH_WPA_VERSION_WPA2;
01921         else
01922                 value = IW_AUTH_WPA_VERSION_WPA;
01923         if (wpa_driver_wext_set_auth_param(drv,
01924                                            IW_AUTH_WPA_VERSION, value) < 0)
01925                 ret = -1;
01926         value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
01927         if (wpa_driver_wext_set_auth_param(drv,
01928                                            IW_AUTH_CIPHER_PAIRWISE, value) < 0)
01929                 ret = -1;
01930         value = wpa_driver_wext_cipher2wext(params->group_suite);
01931         if (wpa_driver_wext_set_auth_param(drv,
01932                                            IW_AUTH_CIPHER_GROUP, value) < 0)
01933                 ret = -1;
01934         value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
01935         if (wpa_driver_wext_set_auth_param(drv,
01936                                            IW_AUTH_KEY_MGMT, value) < 0)
01937                 ret = -1;
01938         value = params->key_mgmt_suite != KEY_MGMT_NONE ||
01939                 params->pairwise_suite != CIPHER_NONE ||
01940                 params->group_suite != CIPHER_NONE ||
01941                 params->wpa_ie_len;
01942         if (wpa_driver_wext_set_auth_param(drv,
01943                                            IW_AUTH_PRIVACY_INVOKED, value) < 0)
01944                 ret = -1;
01945 
01946         /* Allow unencrypted EAPOL messages even if pairwise keys are set when
01947          * not using WPA. IEEE 802.1X specifies that these frames are not
01948          * encrypted, but WPA encrypts them when pairwise keys are in use. */
01949         if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
01950             params->key_mgmt_suite == KEY_MGMT_PSK)
01951                 allow_unencrypted_eapol = 0;
01952         else
01953                 allow_unencrypted_eapol = 1;
01954 
01955         if (wpa_driver_wext_set_psk(drv, params->psk) < 0)
01956                 ret = -1;
01957         if (wpa_driver_wext_set_auth_param(drv,
01958                                            IW_AUTH_RX_UNENCRYPTED_EAPOL,
01959                                            allow_unencrypted_eapol) < 0)
01960                 ret = -1;
01961 #ifdef CONFIG_IEEE80211W
01962         switch (params->mgmt_frame_protection) {
01963         case NO_MGMT_FRAME_PROTECTION:
01964                 value = IW_AUTH_MFP_DISABLED;
01965                 break;
01966         case MGMT_FRAME_PROTECTION_OPTIONAL:
01967                 value = IW_AUTH_MFP_OPTIONAL;
01968                 break;
01969         case MGMT_FRAME_PROTECTION_REQUIRED:
01970                 value = IW_AUTH_MFP_REQUIRED;
01971                 break;
01972         };
01973         if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
01974                 ret = -1;
01975 #endif /* CONFIG_IEEE80211W */
01976         if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
01977                 ret = -1;
01978         if (!drv->cfg80211 &&
01979             wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
01980                 ret = -1;
01981         if (params->bssid &&
01982             wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
01983                 ret = -1;
01984         if (drv->cfg80211 &&
01985             wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
01986                 ret = -1;
01987 
01988         return ret;
01989 }
01990 
01991 
01992 static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
01993 {
01994         struct wpa_driver_wext_data *drv = priv;
01995         int algs = 0, res;
01996 
01997         if (auth_alg & WPA_AUTH_ALG_OPEN)
01998                 algs |= IW_AUTH_ALG_OPEN_SYSTEM;
01999         if (auth_alg & WPA_AUTH_ALG_SHARED)
02000                 algs |= IW_AUTH_ALG_SHARED_KEY;
02001         if (auth_alg & WPA_AUTH_ALG_LEAP)
02002                 algs |= IW_AUTH_ALG_LEAP;
02003         if (algs == 0) {
02004                 /* at least one algorithm should be set */
02005                 algs = IW_AUTH_ALG_OPEN_SYSTEM;
02006         }
02007 
02008         res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
02009                                              algs);
02010         drv->auth_alg_fallback = res == -2;
02011         return res;
02012 }
02013 
02014 
02021 int wpa_driver_wext_set_mode(void *priv, int mode)
02022 {
02023         struct wpa_driver_wext_data *drv = priv;
02024         struct iwreq iwr;
02025         int ret = -1;
02026         unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
02027 
02028         os_memset(&iwr, 0, sizeof(iwr));
02029         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
02030         iwr.u.mode = new_mode;
02031         if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
02032                 ret = 0;
02033                 goto done;
02034         }
02035 
02036         if (errno != EBUSY) {
02037                 perror("ioctl[SIOCSIWMODE]");
02038                 goto done;
02039         }
02040 
02041         /* mac80211 doesn't allow mode changes while the device is up, so if
02042          * the device isn't in the mode we're about to change to, take device
02043          * down, try to set the mode again, and bring it back up.
02044          */
02045         if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
02046                 perror("ioctl[SIOCGIWMODE]");
02047                 goto done;
02048         }
02049 
02050         if (iwr.u.mode == new_mode) {
02051                 ret = 0;
02052                 goto done;
02053         }
02054 
02055         if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) {
02056                 /* Try to set the mode again while the interface is down */
02057                 iwr.u.mode = new_mode;
02058                 if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
02059                         perror("ioctl[SIOCSIWMODE]");
02060                 else
02061                         ret = 0;
02062 
02063                 (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
02064         }
02065 
02066 done:
02067         return ret;
02068 }
02069 
02070 
02071 static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv,
02072                                  u32 cmd, const u8 *bssid, const u8 *pmkid)
02073 {
02074         struct iwreq iwr;
02075         struct iw_pmksa pmksa;
02076         int ret = 0;
02077 
02078         os_memset(&iwr, 0, sizeof(iwr));
02079         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
02080         os_memset(&pmksa, 0, sizeof(pmksa));
02081         pmksa.cmd = cmd;
02082         pmksa.bssid.sa_family = ARPHRD_ETHER;
02083         if (bssid)
02084                 os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
02085         if (pmkid)
02086                 os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
02087         iwr.u.data.pointer = (caddr_t) &pmksa;
02088         iwr.u.data.length = sizeof(pmksa);
02089 
02090         if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
02091                 if (errno != EOPNOTSUPP)
02092                         perror("ioctl[SIOCSIWPMKSA]");
02093                 ret = -1;
02094         }
02095 
02096         return ret;
02097 }
02098 
02099 
02100 static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid,
02101                                      const u8 *pmkid)
02102 {
02103         struct wpa_driver_wext_data *drv = priv;
02104         return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
02105 }
02106 
02107 
02108 static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid,
02109                                         const u8 *pmkid)
02110 {
02111         struct wpa_driver_wext_data *drv = priv;
02112         return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
02113 }
02114 
02115 
02116 static int wpa_driver_wext_flush_pmkid(void *priv)
02117 {
02118         struct wpa_driver_wext_data *drv = priv;
02119         return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
02120 }
02121 
02122 
02123 int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
02124 {
02125         struct wpa_driver_wext_data *drv = priv;
02126         if (!drv->has_capability)
02127                 return -1;
02128         os_memcpy(capa, &drv->capa, sizeof(*capa));
02129         return 0;
02130 }
02131 
02132 
02133 int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
02134                                         const char *ifname)
02135 {
02136         if (ifname == NULL) {
02137                 drv->ifindex2 = -1;
02138                 return 0;
02139         }
02140 
02141         drv->ifindex2 = if_nametoindex(ifname);
02142         if (drv->ifindex2 <= 0)
02143                 return -1;
02144 
02145         wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for "
02146                    "wireless events", drv->ifindex2, ifname);
02147 
02148         return 0;
02149 }
02150 
02151 
02152 int wpa_driver_wext_set_operstate(void *priv, int state)
02153 {
02154         struct wpa_driver_wext_data *drv = priv;
02155 
02156         wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
02157                    __func__, drv->operstate, state, state ? "UP" : "DORMANT");
02158         drv->operstate = state;
02159         return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
02160                                       state ? IF_OPER_UP : IF_OPER_DORMANT);
02161 }
02162 
02163 
02164 int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
02165 {
02166         return drv->we_version_compiled;
02167 }
02168 
02169 
02170 const struct wpa_driver_ops wpa_driver_wext_ops = {
02171         .name = "wext",
02172         .desc = "Linux wireless extensions (generic)",
02173         .get_bssid = wpa_driver_wext_get_bssid,
02174         .get_ssid = wpa_driver_wext_get_ssid,
02175         .set_key = wpa_driver_wext_set_key,
02176         .set_countermeasures = wpa_driver_wext_set_countermeasures,
02177         .scan2 = wpa_driver_wext_scan,
02178         .get_scan_results2 = wpa_driver_wext_get_scan_results,
02179         .deauthenticate = wpa_driver_wext_deauthenticate,
02180         .disassociate = wpa_driver_wext_disassociate,
02181         .associate = wpa_driver_wext_associate,
02182         .init = wpa_driver_wext_init,
02183         .deinit = wpa_driver_wext_deinit,
02184         .add_pmkid = wpa_driver_wext_add_pmkid,
02185         .remove_pmkid = wpa_driver_wext_remove_pmkid,
02186         .flush_pmkid = wpa_driver_wext_flush_pmkid,
02187         .get_capa = wpa_driver_wext_get_capa,
02188         .set_operstate = wpa_driver_wext_set_operstate,
02189 };


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:34