driver_wext.c

Go to the documentation of this file.
00001 
00022 #include "includes.h"
00023 #include <sys/ioctl.h>
00024 #include <net/if_arp.h>
00025 
00026 #include "wireless_copy.h"
00027 #include "common.h"
00028 #include "driver.h"
00029 #include "l2_packet.h"
00030 #include "eloop.h"
00031 #include "wpa_supplicant.h"
00032 #include "priv_netlink.h"
00033 #include "driver_wext.h"
00034 #include "wpa.h"
00035 
00036 #ifdef CONFIG_CLIENT_MLME
00037 #include <netpacket/packet.h>
00038 #include <hostapd_ioctl.h>
00039 #include <net/d80211_common.h>
00040 #include <net/d80211_shared.h>
00041 #include "mlme.h"
00042 
00043 #ifndef ETH_P_ALL
00044 #define ETH_P_ALL 0x0003
00045 #endif
00046 #endif /* CONFIG_CLIENT_MLME */
00047 
00048 
00049 struct wpa_driver_wext_data {
00050         void *ctx;
00051         int event_sock;
00052         int ioctl_sock;
00053         int mlme_sock;
00054         char ifname[IFNAMSIZ + 1];
00055         int ifindex;
00056         int ifindex2;
00057         u8 *assoc_req_ies;
00058         size_t assoc_req_ies_len;
00059         u8 *assoc_resp_ies;
00060         size_t assoc_resp_ies_len;
00061         struct wpa_driver_capa capa;
00062         int has_capability;
00063         int we_version_compiled;
00064 
00065         /* for set_auth_alg fallback */
00066         int use_crypt;
00067         int auth_alg_fallback;
00068 
00069         int operstate;
00070 
00071         char mlmedev[IFNAMSIZ + 1];
00072 };
00073 
00074 
00075 static int wpa_driver_wext_flush_pmkid(void *priv);
00076 static int wpa_driver_wext_get_range(void *priv);
00077 
00078 static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
00079                                           int linkmode, int operstate)
00080 {
00081         struct {
00082                 struct nlmsghdr hdr;
00083                 struct ifinfomsg ifinfo;
00084                 char opts[16];
00085         } req;
00086         struct rtattr *rta;
00087         static int nl_seq;
00088         ssize_t ret;
00089 
00090         req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
00091         req.hdr.nlmsg_type = RTM_SETLINK;
00092         req.hdr.nlmsg_flags = NLM_F_REQUEST;
00093         req.hdr.nlmsg_seq = ++nl_seq;
00094         req.hdr.nlmsg_pid = 0;
00095 
00096         req.ifinfo.ifi_family = AF_UNSPEC;
00097         req.ifinfo.ifi_type = 0;
00098         req.ifinfo.ifi_index = drv->ifindex;
00099         req.ifinfo.ifi_flags = 0;
00100         req.ifinfo.ifi_change = 0;
00101 
00102         if (linkmode != -1) {
00103                 rta = (struct rtattr *)
00104                         ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
00105                 rta->rta_type = IFLA_LINKMODE;
00106                 rta->rta_len = RTA_LENGTH(sizeof(char));
00107                 *((char *) RTA_DATA(rta)) = linkmode;
00108                 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
00109                         RTA_LENGTH(sizeof(char));
00110         }
00111         if (operstate != -1) {
00112                 rta = (struct rtattr *)
00113                         ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
00114                 rta->rta_type = IFLA_OPERSTATE;
00115                 rta->rta_len = RTA_LENGTH(sizeof(char));
00116                 *((char *) RTA_DATA(rta)) = operstate;
00117                 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
00118                         RTA_LENGTH(sizeof(char));
00119         }
00120 
00121         wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
00122                    linkmode, operstate);
00123 
00124         ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
00125         if (ret < 0) {
00126                 wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
00127                            "%s (assume operstate is not supported)",
00128                            strerror(errno));
00129         }
00130 
00131         return ret < 0 ? -1 : 0;
00132 }
00133 
00134 
00135 static int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
00136                                           int idx, u32 value)
00137 {
00138         struct iwreq iwr;
00139         int ret = 0;
00140 
00141         os_memset(&iwr, 0, sizeof(iwr));
00142         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00143         iwr.u.param.flags = idx & IW_AUTH_INDEX;
00144         iwr.u.param.value = value;
00145 
00146         if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
00147                 perror("ioctl[SIOCSIWAUTH]");
00148                 fprintf(stderr, "WEXT auth param %d value 0x%x - ",
00149                         idx, value);
00150                 ret = errno == EOPNOTSUPP ? -2 : -1;
00151         }
00152 
00153         return ret;
00154 }
00155 
00156 
00164 int wpa_driver_wext_get_bssid(void *priv, u8 *bssid)
00165 {
00166         struct wpa_driver_wext_data *drv = priv;
00167         struct iwreq iwr;
00168         int ret = 0;
00169 
00170         os_memset(&iwr, 0, sizeof(iwr));
00171         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00172 
00173         if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
00174                 perror("ioctl[SIOCGIWAP]");
00175                 ret = -1;
00176         }
00177         os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
00178 
00179         return ret;
00180 }
00181 
00182 
00190 int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid)
00191 {
00192         struct wpa_driver_wext_data *drv = priv;
00193         struct iwreq iwr;
00194         int ret = 0;
00195 
00196         os_memset(&iwr, 0, sizeof(iwr));
00197         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00198         iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
00199         if (bssid)
00200                 os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
00201         else
00202                 os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
00203 
00204         if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
00205                 perror("ioctl[SIOCSIWAP]");
00206                 ret = -1;
00207         }
00208 
00209         return ret;
00210 }
00211 
00212 
00220 int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
00221 {
00222         struct wpa_driver_wext_data *drv = priv;
00223         struct iwreq iwr;
00224         int ret = 0;
00225 
00226         os_memset(&iwr, 0, sizeof(iwr));
00227         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00228         iwr.u.essid.pointer = (caddr_t) ssid;
00229         iwr.u.essid.length = 32;
00230 
00231         if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
00232                 perror("ioctl[SIOCGIWESSID]");
00233                 ret = -1;
00234         } else {
00235                 ret = iwr.u.essid.length;
00236                 if (ret > 32)
00237                         ret = 32;
00238                 /* Some drivers include nul termination in the SSID, so let's
00239                  * remove it here before further processing. WE-21 changes this
00240                  * to explicitly require the length _not_ to include nul
00241                  * termination. */
00242                 if (ret > 0 && ssid[ret - 1] == '\0' &&
00243                     drv->we_version_compiled < 21)
00244                         ret--;
00245         }
00246 
00247         return ret;
00248 }
00249 
00250 
00259 int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
00260 {
00261         struct wpa_driver_wext_data *drv = priv;
00262         struct iwreq iwr;
00263         int ret = 0;
00264         char buf[33];
00265 
00266         if (ssid_len > 32)
00267                 return -1;
00268 
00269         os_memset(&iwr, 0, sizeof(iwr));
00270         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00271         /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
00272         iwr.u.essid.flags = (ssid_len != 0);
00273         os_memset(buf, 0, sizeof(buf));
00274         os_memcpy(buf, ssid, ssid_len);
00275         iwr.u.essid.pointer = (caddr_t) buf;
00276         if (drv->we_version_compiled < 21) {
00277                 /* For historic reasons, set SSID length to include one extra
00278                  * character, C string nul termination, even though SSID is
00279                  * really an octet string that should not be presented as a C
00280                  * string. Some Linux drivers decrement the length by one and
00281                  * can thus end up missing the last octet of the SSID if the
00282                  * length is not incremented here. WE-21 changes this to
00283                  * explicitly require the length _not_ to include nul
00284                  * termination. */
00285                 if (ssid_len)
00286                         ssid_len++;
00287         }
00288         iwr.u.essid.length = ssid_len;
00289 
00290         if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
00291                 perror("ioctl[SIOCSIWESSID]");
00292                 ret = -1;
00293         }
00294 
00295         return ret;
00296 }
00297 
00298 
00306 int wpa_driver_wext_set_freq(void *priv, int freq)
00307 {
00308         struct wpa_driver_wext_data *drv = priv;
00309         struct iwreq iwr;
00310         int ret = 0;
00311 
00312         os_memset(&iwr, 0, sizeof(iwr));
00313         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00314         iwr.u.freq.m = freq * 100000;
00315         iwr.u.freq.e = 1;
00316 
00317         if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
00318                 perror("ioctl[SIOCSIWFREQ]");
00319                 ret = -1;
00320         }
00321 
00322         return ret;
00323 }
00324 
00325 
00326 static void
00327 wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
00328 {
00329         union wpa_event_data data;
00330 
00331         wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
00332                    custom);
00333 
00334         os_memset(&data, 0, sizeof(data));
00335         /* Host AP driver */
00336         if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
00337                 data.michael_mic_failure.unicast =
00338                         os_strstr(custom, " unicast ") != NULL;
00339                 /* TODO: parse parameters(?) */
00340                 wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
00341         } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
00342                 char *spos;
00343                 int bytes;
00344 
00345                 spos = custom + 17;
00346 
00347                 bytes = strspn(spos, "0123456789abcdefABCDEF");
00348                 if (!bytes || (bytes & 1))
00349                         return;
00350                 bytes /= 2;
00351 
00352                 data.assoc_info.req_ies = os_malloc(bytes);
00353                 if (data.assoc_info.req_ies == NULL)
00354                         return;
00355 
00356                 data.assoc_info.req_ies_len = bytes;
00357                 hexstr2bin(spos, data.assoc_info.req_ies, bytes);
00358 
00359                 spos += bytes * 2;
00360 
00361                 data.assoc_info.resp_ies = NULL;
00362                 data.assoc_info.resp_ies_len = 0;
00363 
00364                 if (os_strncmp(spos, " RespIEs=", 9) == 0) {
00365                         spos += 9;
00366 
00367                         bytes = strspn(spos, "0123456789abcdefABCDEF");
00368                         if (!bytes || (bytes & 1))
00369                                 goto done;
00370                         bytes /= 2;
00371 
00372                         data.assoc_info.resp_ies = os_malloc(bytes);
00373                         if (data.assoc_info.resp_ies == NULL)
00374                                 goto done;
00375 
00376                         data.assoc_info.resp_ies_len = bytes;
00377                         hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
00378                 }
00379 
00380                 wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
00381 
00382         done:
00383                 os_free(data.assoc_info.resp_ies);
00384                 os_free(data.assoc_info.req_ies);
00385 #ifdef CONFIG_PEERKEY
00386         } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
00387                 if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
00388                         wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
00389                                    "STKSTART.request '%s'", custom + 17);
00390                         return;
00391                 }
00392                 wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
00393 #endif /* CONFIG_PEERKEY */
00394         }
00395 }
00396 
00397 
00398 static int wpa_driver_wext_event_wireless_michaelmicfailure(
00399         void *ctx, const char *ev, size_t len)
00400 {
00401         const struct iw_michaelmicfailure *mic;
00402         union wpa_event_data data;
00403 
00404         if (len < sizeof(*mic))
00405                 return -1;
00406 
00407         mic = (const struct iw_michaelmicfailure *) ev;
00408 
00409         wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
00410                    "flags=0x%x src_addr=" MACSTR, mic->flags,
00411                    MAC2STR(mic->src_addr.sa_data));
00412 
00413         os_memset(&data, 0, sizeof(data));
00414         data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
00415         wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
00416 
00417         return 0;
00418 }
00419 
00420 
00421 static int wpa_driver_wext_event_wireless_pmkidcand(
00422         struct wpa_driver_wext_data *drv, const char *ev, size_t len)
00423 {
00424         const struct iw_pmkid_cand *cand;
00425         union wpa_event_data data;
00426         const u8 *addr;
00427 
00428         if (len < sizeof(*cand))
00429                 return -1;
00430 
00431         cand = (const struct iw_pmkid_cand *) ev;
00432         addr = (const u8 *) cand->bssid.sa_data;
00433 
00434         wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
00435                    "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
00436                    cand->index, MAC2STR(addr));
00437 
00438         os_memset(&data, 0, sizeof(data));
00439         os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
00440         data.pmkid_candidate.index = cand->index;
00441         data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
00442         wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
00443 
00444         return 0;
00445 }
00446 
00447 
00448 static int wpa_driver_wext_event_wireless_assocreqie(
00449         struct wpa_driver_wext_data *drv, const char *ev, int len)
00450 {
00451         if (len < 0)
00452                 return -1;
00453 
00454         wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
00455                     len);
00456         os_free(drv->assoc_req_ies);
00457         drv->assoc_req_ies = os_malloc(len);
00458         if (drv->assoc_req_ies == NULL) {
00459                 drv->assoc_req_ies_len = 0;
00460                 return -1;
00461         }
00462         os_memcpy(drv->assoc_req_ies, ev, len);
00463         drv->assoc_req_ies_len = len;
00464 
00465         return 0;
00466 }
00467 
00468 
00469 static int wpa_driver_wext_event_wireless_assocrespie(
00470         struct wpa_driver_wext_data *drv, const char *ev, int len)
00471 {
00472         if (len < 0)
00473                 return -1;
00474 
00475         wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
00476                     len);
00477         os_free(drv->assoc_resp_ies);
00478         drv->assoc_resp_ies = os_malloc(len);
00479         if (drv->assoc_resp_ies == NULL) {
00480                 drv->assoc_resp_ies_len = 0;
00481                 return -1;
00482         }
00483         os_memcpy(drv->assoc_resp_ies, ev, len);
00484         drv->assoc_resp_ies_len = len;
00485 
00486         return 0;
00487 }
00488 
00489 
00490 static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
00491 {
00492         union wpa_event_data data;
00493 
00494         if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
00495                 return;
00496 
00497         os_memset(&data, 0, sizeof(data));
00498         if (drv->assoc_req_ies) {
00499                 data.assoc_info.req_ies = drv->assoc_req_ies;
00500                 drv->assoc_req_ies = NULL;
00501                 data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
00502         }
00503         if (drv->assoc_resp_ies) {
00504                 data.assoc_info.resp_ies = drv->assoc_resp_ies;
00505                 drv->assoc_resp_ies = NULL;
00506                 data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
00507         }
00508 
00509         wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
00510 
00511         os_free(data.assoc_info.req_ies);
00512         os_free(data.assoc_info.resp_ies);
00513 }
00514 
00515 
00516 static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
00517                                            void *ctx, char *data, int len)
00518 {
00519         struct iw_event iwe_buf, *iwe = &iwe_buf;
00520         char *pos, *end, *custom, *buf;
00521 
00522         pos = data;
00523         end = data + len;
00524 
00525         while (pos + IW_EV_LCP_LEN <= end) {
00526                 /* Event data may be unaligned, so make a local, aligned copy
00527                  * before processing. */
00528                 os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
00529                 wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
00530                            iwe->cmd, iwe->len);
00531                 if (iwe->len <= IW_EV_LCP_LEN)
00532                         return;
00533 
00534                 custom = pos + IW_EV_POINT_LEN;
00535                 if (drv->we_version_compiled > 18 &&
00536                     (iwe->cmd == IWEVMICHAELMICFAILURE ||
00537                      iwe->cmd == IWEVCUSTOM ||
00538                      iwe->cmd == IWEVASSOCREQIE ||
00539                      iwe->cmd == IWEVASSOCRESPIE ||
00540                      iwe->cmd == IWEVPMKIDCAND)) {
00541                         /* WE-19 removed the pointer from struct iw_point */
00542                         char *dpos = (char *) &iwe_buf.u.data.length;
00543                         int dlen = dpos - (char *) &iwe_buf;
00544                         os_memcpy(dpos, pos + IW_EV_LCP_LEN,
00545                                   sizeof(struct iw_event) - dlen);
00546                 } else {
00547                         os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
00548                         custom += IW_EV_POINT_OFF;
00549                 }
00550 
00551                 switch (iwe->cmd) {
00552                 case SIOCGIWAP:
00553                         wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
00554                                    MACSTR,
00555                                    MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
00556                         if (os_memcmp(iwe->u.ap_addr.sa_data,
00557                                       "\x00\x00\x00\x00\x00\x00", ETH_ALEN) ==
00558                             0 ||
00559                             os_memcmp(iwe->u.ap_addr.sa_data,
00560                                       "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
00561                             0) {
00562                                 os_free(drv->assoc_req_ies);
00563                                 drv->assoc_req_ies = NULL;
00564                                 os_free(drv->assoc_resp_ies);
00565                                 drv->assoc_resp_ies = NULL;
00566                                 wpa_supplicant_event(ctx, EVENT_DISASSOC,
00567                                                      NULL);
00568                         
00569                         } else {
00570                                 wpa_driver_wext_event_assoc_ies(drv);
00571                                 wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
00572                         }
00573                         break;
00574                 case IWEVMICHAELMICFAILURE:
00575                         wpa_driver_wext_event_wireless_michaelmicfailure(
00576                                 ctx, custom, iwe->u.data.length);
00577                         break;
00578                 case IWEVCUSTOM:
00579                         if (custom + iwe->u.data.length > end)
00580                                 return;
00581                         buf = os_malloc(iwe->u.data.length + 1);
00582                         if (buf == NULL)
00583                                 return;
00584                         os_memcpy(buf, custom, iwe->u.data.length);
00585                         buf[iwe->u.data.length] = '\0';
00586                         wpa_driver_wext_event_wireless_custom(ctx, buf);
00587                         os_free(buf);
00588                         break;
00589                 case SIOCGIWSCAN:
00590                         eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
00591                                              drv, ctx);
00592                         wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
00593                         break;
00594                 case IWEVASSOCREQIE:
00595                         wpa_driver_wext_event_wireless_assocreqie(
00596                                 drv, custom, iwe->u.data.length);
00597                         break;
00598                 case IWEVASSOCRESPIE:
00599                         wpa_driver_wext_event_wireless_assocrespie(
00600                                 drv, custom, iwe->u.data.length);
00601                         break;
00602                 case IWEVPMKIDCAND:
00603                         wpa_driver_wext_event_wireless_pmkidcand(
00604                                 drv, custom, iwe->u.data.length);
00605                         break;
00606                 }
00607 
00608                 pos += iwe->len;
00609         }
00610 }
00611 
00612 
00613 static void wpa_driver_wext_event_link(void *ctx, char *buf, size_t len,
00614                                        int del)
00615 {
00616         union wpa_event_data event;
00617 
00618         os_memset(&event, 0, sizeof(event));
00619         if (len > sizeof(event.interface_status.ifname))
00620                 len = sizeof(event.interface_status.ifname) - 1;
00621         os_memcpy(event.interface_status.ifname, buf, len);
00622         event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
00623                 EVENT_INTERFACE_ADDED;
00624 
00625         wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
00626                    del ? "DEL" : "NEW",
00627                    event.interface_status.ifname,
00628                    del ? "removed" : "added");
00629 
00630         wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
00631 }
00632 
00633 
00634 static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
00635                                               void *ctx, struct nlmsghdr *h,
00636                                               size_t len)
00637 {
00638         struct ifinfomsg *ifi;
00639         int attrlen, nlmsg_len, rta_len;
00640         struct rtattr * attr;
00641 
00642         if (len < sizeof(*ifi))
00643                 return;
00644 
00645         ifi = NLMSG_DATA(h);
00646 
00647         if (drv->ifindex != ifi->ifi_index && drv->ifindex2 != ifi->ifi_index)
00648         {
00649                 wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
00650                            ifi->ifi_index);
00651                 return;
00652         }
00653 
00654         wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
00655                    "(%s%s%s%s)",
00656                    drv->operstate, ifi->ifi_flags,
00657                    (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
00658                    (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
00659                    (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
00660                    (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT" : "");
00661         /*
00662          * Some drivers send the association event before the operup event--in
00663          * this case, lifting operstate in wpa_driver_wext_set_operstate()
00664          * fails. This will hit us when wpa_supplicant does not need to do
00665          * IEEE 802.1X authentication
00666          */
00667         if (drv->operstate == 1 &&
00668             (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
00669             !(ifi->ifi_flags & IFF_RUNNING))
00670                 wpa_driver_wext_send_oper_ifla(drv, -1, IF_OPER_UP);
00671 
00672         nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
00673 
00674         attrlen = h->nlmsg_len - nlmsg_len;
00675         if (attrlen < 0)
00676                 return;
00677 
00678         attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
00679 
00680         rta_len = RTA_ALIGN(sizeof(struct rtattr));
00681         while (RTA_OK(attr, attrlen)) {
00682                 if (attr->rta_type == IFLA_WIRELESS) {
00683                         wpa_driver_wext_event_wireless(
00684                                 drv, ctx, ((char *) attr) + rta_len,
00685                                 attr->rta_len - rta_len);
00686                 } else if (attr->rta_type == IFLA_IFNAME) {
00687                         wpa_driver_wext_event_link(ctx,
00688                                                    ((char *) attr) + rta_len,
00689                                                    attr->rta_len - rta_len, 0);
00690                 }
00691                 attr = RTA_NEXT(attr, attrlen);
00692         }
00693 }
00694 
00695 
00696 static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv,
00697                                               void *ctx, struct nlmsghdr *h,
00698                                               size_t len)
00699 {
00700         struct ifinfomsg *ifi;
00701         int attrlen, nlmsg_len, rta_len;
00702         struct rtattr * attr;
00703 
00704         if (len < sizeof(*ifi))
00705                 return;
00706 
00707         ifi = NLMSG_DATA(h);
00708 
00709         nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
00710 
00711         attrlen = h->nlmsg_len - nlmsg_len;
00712         if (attrlen < 0)
00713                 return;
00714 
00715         attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
00716 
00717         rta_len = RTA_ALIGN(sizeof(struct rtattr));
00718         while (RTA_OK(attr, attrlen)) {
00719                 if (attr->rta_type == IFLA_IFNAME) {
00720                         wpa_driver_wext_event_link(ctx,
00721                                                    ((char *) attr) + rta_len,
00722                                                    attr->rta_len - rta_len, 1);
00723                 }
00724                 attr = RTA_NEXT(attr, attrlen);
00725         }
00726 }
00727 
00728 
00729 static void wpa_driver_wext_event_receive(int sock, void *eloop_ctx,
00730                                           void *sock_ctx)
00731 {
00732         char buf[8192];
00733         int left;
00734         struct sockaddr_nl from;
00735         socklen_t fromlen;
00736         struct nlmsghdr *h;
00737         int max_events = 10;
00738 
00739 try_again:
00740         fromlen = sizeof(from);
00741         left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
00742                         (struct sockaddr *) &from, &fromlen);
00743         if (left < 0) {
00744                 if (errno != EINTR && errno != EAGAIN)
00745                         perror("recvfrom(netlink)");
00746                 return;
00747         }
00748 
00749         h = (struct nlmsghdr *) buf;
00750         while (left >= (int) sizeof(*h)) {
00751                 int len, plen;
00752 
00753                 len = h->nlmsg_len;
00754                 plen = len - sizeof(*h);
00755                 if (len > left || plen < 0) {
00756                         wpa_printf(MSG_DEBUG, "Malformed netlink message: "
00757                                    "len=%d left=%d plen=%d",
00758                                    len, left, plen);
00759                         break;
00760                 }
00761 
00762                 switch (h->nlmsg_type) {
00763                 case RTM_NEWLINK:
00764                         wpa_driver_wext_event_rtm_newlink(eloop_ctx, sock_ctx,
00765                                                           h, plen);
00766                         break;
00767                 case RTM_DELLINK:
00768                         wpa_driver_wext_event_rtm_dellink(eloop_ctx, sock_ctx,
00769                                                           h, plen);
00770                         break;
00771                 }
00772 
00773                 len = NLMSG_ALIGN(len);
00774                 left -= len;
00775                 h = (struct nlmsghdr *) ((char *) h + len);
00776         }
00777 
00778         if (left > 0) {
00779                 wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
00780                            "message", left);
00781         }
00782 
00783         if (--max_events > 0) {
00784                 /*
00785                  * Try to receive all events in one eloop call in order to
00786                  * limit race condition on cases where AssocInfo event, Assoc
00787                  * event, and EAPOL frames are received more or less at the
00788                  * same time. We want to process the event messages first
00789                  * before starting EAPOL processing.
00790                  */
00791                 goto try_again;
00792         }
00793 }
00794 
00795 
00796 static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv,
00797                                               const char *ifname, int *flags)
00798 {
00799         struct ifreq ifr;
00800 
00801         os_memset(&ifr, 0, sizeof(ifr));
00802         os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
00803         if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
00804                 perror("ioctl[SIOCGIFFLAGS]");
00805                 return -1;
00806         }
00807         *flags = ifr.ifr_flags & 0xffff;
00808         return 0;
00809 }
00810 
00811 
00819 int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags)
00820 {
00821         return wpa_driver_wext_get_ifflags_ifname(drv, drv->ifname, flags);
00822 }
00823 
00824 
00825 static int wpa_driver_wext_set_ifflags_ifname(struct wpa_driver_wext_data *drv,
00826                                               const char *ifname, int flags)
00827 {
00828         struct ifreq ifr;
00829 
00830         os_memset(&ifr, 0, sizeof(ifr));
00831         os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
00832         ifr.ifr_flags = flags & 0xffff;
00833         if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
00834                 perror("SIOCSIFFLAGS");
00835                 return -1;
00836         }
00837         return 0;
00838 }
00839 
00840 
00848 int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags)
00849 {
00850         return wpa_driver_wext_set_ifflags_ifname(drv, drv->ifname, flags);
00851 }
00852 
00853 
00862 void * wpa_driver_wext_init(void *ctx, const char *ifname)
00863 {
00864         int s, flags;
00865         struct sockaddr_nl local;
00866         struct wpa_driver_wext_data *drv;
00867 
00868         drv = os_zalloc(sizeof(*drv));
00869         if (drv == NULL)
00870                 return NULL;
00871         drv->ctx = ctx;
00872         os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
00873 
00874         drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
00875         if (drv->ioctl_sock < 0) {
00876                 perror("socket(PF_INET,SOCK_DGRAM)");
00877                 os_free(drv);
00878                 return NULL;
00879         }
00880 
00881         s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
00882         if (s < 0) {
00883                 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
00884                 close(drv->ioctl_sock);
00885                 os_free(drv);
00886                 return NULL;
00887         }
00888 
00889         os_memset(&local, 0, sizeof(local));
00890         local.nl_family = AF_NETLINK;
00891         local.nl_groups = RTMGRP_LINK;
00892         if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
00893                 perror("bind(netlink)");
00894                 close(s);
00895                 close(drv->ioctl_sock);
00896                 os_free(drv);
00897                 return NULL;
00898         }
00899 
00900         eloop_register_read_sock(s, wpa_driver_wext_event_receive, drv, ctx);
00901         drv->event_sock = s;
00902 
00903         drv->mlme_sock = -1;
00904 
00905         /*
00906          * Make sure that the driver does not have any obsolete PMKID entries.
00907          */
00908         wpa_driver_wext_flush_pmkid(drv);
00909 
00910         if (wpa_driver_wext_set_mode(drv, 0) < 0) {
00911                 printf("Could not configure driver to use managed mode\n");
00912         }
00913 
00914         if (wpa_driver_wext_get_ifflags(drv, &flags) != 0 ||
00915             wpa_driver_wext_set_ifflags(drv, flags | IFF_UP) != 0) {
00916                 printf("Could not set interface '%s' UP\n", drv->ifname);
00917         }
00918 
00919         wpa_driver_wext_get_range(drv);
00920 
00921         drv->ifindex = if_nametoindex(drv->ifname);
00922 
00923         if (os_strncmp(ifname, "wlan", 4) == 0) {
00924                 /*
00925                  * Host AP driver may use both wlan# and wifi# interface in
00926                  * wireless events. Since some of the versions included WE-18
00927                  * support, let's add the alternative ifindex also from
00928                  * driver_wext.c for the time being. This may be removed at
00929                  * some point once it is believed that old versions of the
00930                  * driver are not in use anymore.
00931                  */
00932                 char ifname2[IFNAMSIZ + 1];
00933                 os_strncpy(ifname2, ifname, sizeof(ifname2));
00934                 os_memcpy(ifname2, "wifi", 4);
00935                 wpa_driver_wext_alternative_ifindex(drv, ifname2);
00936         }
00937 
00938         wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
00939 
00940         return drv;
00941 }
00942 
00943 
00952 void wpa_driver_wext_deinit(void *priv)
00953 {
00954         struct wpa_driver_wext_data *drv = priv;
00955         int flags;
00956 
00957         eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
00958 
00959         /*
00960          * Clear possibly configured driver parameters in order to make it
00961          * easier to use the driver after wpa_supplicant has been terminated.
00962          */
00963         wpa_driver_wext_set_bssid(drv, (u8 *) "\x00\x00\x00\x00\x00\x00");
00964 
00965         wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP);
00966 
00967         eloop_unregister_read_sock(drv->event_sock);
00968         if (drv->mlme_sock >= 0)
00969                 eloop_unregister_read_sock(drv->mlme_sock);
00970 
00971         if (wpa_driver_wext_get_ifflags(drv, &flags) == 0)
00972                 (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
00973 
00974 #ifdef CONFIG_CLIENT_MLME
00975         if (drv->mlmedev[0] &&
00976             wpa_driver_wext_get_ifflags_ifname(drv, drv->mlmedev, &flags) == 0)
00977                 (void) wpa_driver_wext_set_ifflags_ifname(drv, drv->mlmedev,
00978                                                           flags & ~IFF_UP);
00979 #endif /* CONFIG_CLIENT_MLME */
00980 
00981         close(drv->event_sock);
00982         close(drv->ioctl_sock);
00983         if (drv->mlme_sock >= 0)
00984                 close(drv->mlme_sock);
00985         os_free(drv->assoc_req_ies);
00986         os_free(drv->assoc_resp_ies);
00987         os_free(drv);
00988 }
00989 
00990 
01000 void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
01001 {
01002         wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
01003         wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
01004 }
01005 
01006 
01017 int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len)
01018 {
01019         struct wpa_driver_wext_data *drv = priv;
01020         struct iwreq iwr;
01021         int ret = 0;
01022         struct iw_scan_req req;
01023 
01024         if (ssid_len > IW_ESSID_MAX_SIZE) {
01025                 wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
01026                            __FUNCTION__, (unsigned long) ssid_len);
01027                 return -1;
01028         }
01029 
01030         os_memset(&iwr, 0, sizeof(iwr));
01031         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01032 
01033         if (ssid && ssid_len) {
01034                 os_memset(&req, 0, sizeof(req));
01035                 req.essid_len = ssid_len;
01036                 req.bssid.sa_family = ARPHRD_ETHER;
01037                 os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
01038                 os_memcpy(req.essid, ssid, ssid_len);
01039                 iwr.u.data.pointer = (caddr_t) &req;
01040                 iwr.u.data.length = sizeof(req);
01041                 iwr.u.data.flags = IW_SCAN_THIS_ESSID;
01042         }
01043 
01044         if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
01045                 perror("ioctl[SIOCSIWSCAN]");
01046                 ret = -1;
01047         }
01048 
01049         /* Not all drivers generate "scan completed" wireless event, so try to
01050          * read results after a timeout. */
01051         eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv,
01052                                drv->ctx);
01053 
01054         return ret;
01055 }
01056 
01057 
01058 /* Compare function for sorting scan results. Return >0 if @b is considered
01059  * better. */
01060 static int wpa_scan_result_compar(const void *a, const void *b)
01061 {
01062         const struct wpa_scan_result *wa = a;
01063         const struct wpa_scan_result *wb = b;
01064 
01065         /* WPA/WPA2 support preferred */
01066         if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
01067             !(wa->wpa_ie_len || wa->rsn_ie_len))
01068                 return 1;
01069         if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
01070             (wa->wpa_ie_len || wa->rsn_ie_len))
01071                 return -1;
01072 
01073         /* privacy support preferred */
01074         if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
01075             (wb->caps & IEEE80211_CAP_PRIVACY))
01076                 return 1;
01077         if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
01078             (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
01079                 return -1;
01080 
01081         /* best/max rate preferred if signal level close enough XXX */
01082         if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
01083                 return wb->maxrate - wa->maxrate;
01084 
01085         /* use freq for channel preference */
01086 
01087         /* all things being equal, use signal level; if signal levels are
01088          * identical, use quality values since some drivers may only report
01089          * that value and leave the signal level zero */
01090         if (wb->level == wa->level)
01091                 return wb->qual - wa->qual;
01092         return wb->level - wa->level;
01093 }
01094 
01095 
01109 int wpa_driver_wext_get_scan_results(void *priv,
01110                                      struct wpa_scan_result *results,
01111                                      size_t max_size)
01112 {
01113         struct wpa_driver_wext_data *drv = priv;
01114         struct iwreq iwr;
01115         size_t ap_num = 0;
01116         int first, maxrate;
01117         u8 *res_buf;
01118         struct iw_event iwe_buf, *iwe = &iwe_buf;
01119         char *pos, *end, *custom, *genie, *gpos, *gend;
01120         struct iw_param p;
01121         size_t len, clen, res_buf_len;
01122 
01123         os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
01124 
01125         res_buf_len = IW_SCAN_MAX_DATA;
01126         for (;;) {
01127                 res_buf = os_malloc(res_buf_len);
01128                 if (res_buf == NULL)
01129                         return -1;
01130                 os_memset(&iwr, 0, sizeof(iwr));
01131                 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01132                 iwr.u.data.pointer = res_buf;
01133                 iwr.u.data.length = res_buf_len;
01134 
01135                 if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
01136                         break;
01137 
01138                 if (errno == E2BIG && res_buf_len < 100000) {
01139                         os_free(res_buf);
01140                         res_buf = NULL;
01141                         res_buf_len *= 2;
01142                         wpa_printf(MSG_DEBUG, "Scan results did not fit - "
01143                                    "trying larger buffer (%lu bytes)",
01144                                    (unsigned long) res_buf_len);
01145                 } else {
01146                         perror("ioctl[SIOCGIWSCAN]");
01147                         os_free(res_buf);
01148                         return -1;
01149                 }
01150         }
01151 
01152         len = iwr.u.data.length;
01153         ap_num = 0;
01154         first = 1;
01155 
01156         pos = (char *) res_buf;
01157         end = (char *) res_buf + len;
01158 
01159         while (pos + IW_EV_LCP_LEN <= end) {
01160                 int ssid_len;
01161                 /* Event data may be unaligned, so make a local, aligned copy
01162                  * before processing. */
01163                 os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
01164                 if (iwe->len <= IW_EV_LCP_LEN)
01165                         break;
01166 
01167                 custom = pos + IW_EV_POINT_LEN;
01168                 if (drv->we_version_compiled > 18 &&
01169                     (iwe->cmd == SIOCGIWESSID ||
01170                      iwe->cmd == SIOCGIWENCODE ||
01171                      iwe->cmd == IWEVGENIE ||
01172                      iwe->cmd == IWEVCUSTOM)) {
01173                         /* WE-19 removed the pointer from struct iw_point */
01174                         char *dpos = (char *) &iwe_buf.u.data.length;
01175                         int dlen = dpos - (char *) &iwe_buf;
01176                         os_memcpy(dpos, pos + IW_EV_LCP_LEN,
01177                                   sizeof(struct iw_event) - dlen);
01178                 } else {
01179                         os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
01180                         custom += IW_EV_POINT_OFF;
01181                 }
01182 
01183                 switch (iwe->cmd) {
01184                 case SIOCGIWAP:
01185                         if (!first)
01186                                 ap_num++;
01187                         first = 0;
01188                         if (ap_num < max_size) {
01189                                 os_memcpy(results[ap_num].bssid,
01190                                           iwe->u.ap_addr.sa_data, ETH_ALEN);
01191                         }
01192                         break;
01193                 case SIOCGIWMODE:
01194                         if (ap_num >= max_size)
01195                                 break;
01196                         if (iwe->u.mode == IW_MODE_ADHOC)
01197                                 results[ap_num].caps |= IEEE80211_CAP_IBSS;
01198                         else if (iwe->u.mode == IW_MODE_MASTER ||
01199                                  iwe->u.mode == IW_MODE_INFRA)
01200                                 results[ap_num].caps |= IEEE80211_CAP_ESS;
01201                         break;
01202                 case SIOCGIWESSID:
01203                         ssid_len = iwe->u.essid.length;
01204                         if (custom + ssid_len > end)
01205                                 break;
01206                         if (iwe->u.essid.flags &&
01207                             ssid_len > 0 &&
01208                             ssid_len <= IW_ESSID_MAX_SIZE) {
01209                                 if (ap_num < max_size) {
01210                                         os_memcpy(results[ap_num].ssid, custom,
01211                                                   ssid_len);
01212                                         results[ap_num].ssid_len = ssid_len;
01213                                 }
01214                         }
01215                         break;
01216                 case SIOCGIWFREQ:
01217                         if (ap_num < max_size) {
01218                                 int divi = 1000000, i;
01219                                 if (iwe->u.freq.e == 0) {
01220                                         /*
01221                                          * Some drivers do not report
01222                                          * frequency, but a channel. Try to map
01223                                          * this to frequency by assuming they
01224                                          * are using IEEE 802.11b/g.
01225                                          */
01226                                         if (iwe->u.freq.m >= 1 &&
01227                                             iwe->u.freq.m <= 13) {
01228                                                 results[ap_num].freq =
01229                                                         2407 +
01230                                                         5 * iwe->u.freq.m;
01231                                                 break;
01232                                         } else if (iwe->u.freq.m == 14) {
01233                                                 results[ap_num].freq = 2484;
01234                                                 break;
01235                                         }
01236                                 }
01237                                 if (iwe->u.freq.e > 6) {
01238                                         wpa_printf(
01239                                                 MSG_DEBUG, "Invalid freq "
01240                                                 "in scan results (BSSID="
01241                                                 MACSTR ": m=%d e=%d\n",
01242                                                 MAC2STR(results[ap_num].bssid),
01243                                                 iwe->u.freq.m, iwe->u.freq.e);
01244                                         break;
01245                                 }
01246                                 for (i = 0; i < iwe->u.freq.e; i++)
01247                                         divi /= 10;
01248                                 results[ap_num].freq = iwe->u.freq.m / divi;
01249                         }
01250                         break;
01251                 case IWEVQUAL:
01252                         if (ap_num < max_size) {
01253                                 results[ap_num].qual = iwe->u.qual.qual;
01254                                 results[ap_num].noise = iwe->u.qual.noise;
01255                                 results[ap_num].level = iwe->u.qual.level;
01256                         }
01257                         break;
01258                 case SIOCGIWENCODE:
01259                         if (ap_num < max_size &&
01260                             !(iwe->u.data.flags & IW_ENCODE_DISABLED))
01261                                 results[ap_num].caps |= IEEE80211_CAP_PRIVACY;
01262                         break;
01263                 case SIOCGIWRATE:
01264                         custom = pos + IW_EV_LCP_LEN;
01265                         clen = iwe->len;
01266                         if (custom + clen > end)
01267                                 break;
01268                         maxrate = 0;
01269                         while (((ssize_t) clen) >=
01270                                (ssize_t) sizeof(struct iw_param)) {
01271                                 /* Note: may be misaligned, make a local,
01272                                  * aligned copy */
01273                                 os_memcpy(&p, custom, sizeof(struct iw_param));
01274                                 if (p.value > maxrate)
01275                                         maxrate = p.value;
01276                                 clen -= sizeof(struct iw_param);
01277                                 custom += sizeof(struct iw_param);
01278                         }
01279                         if (ap_num < max_size)
01280                                 results[ap_num].maxrate = maxrate;
01281                         break;
01282                 case IWEVGENIE:
01283                         if (ap_num >= max_size)
01284                                 break;
01285                         gpos = genie = custom;
01286                         gend = genie + iwe->u.data.length;
01287                         if (gend > end) {
01288                                 wpa_printf(MSG_INFO, "IWEVGENIE overflow");
01289                                 break;
01290                         }
01291                         while (gpos + 1 < gend &&
01292                                gpos + 2 + (u8) gpos[1] <= gend) {
01293                                 u8 ie = gpos[0], ielen = gpos[1] + 2;
01294                                 if (ielen > SSID_MAX_WPA_IE_LEN) {
01295                                         gpos += ielen;
01296                                         continue;
01297                                 }
01298                                 switch (ie) {
01299                                 case GENERIC_INFO_ELEM:
01300                                         if (ielen < 2 + 4 ||
01301                                             os_memcmp(&gpos[2],
01302                                                       "\x00\x50\xf2\x01", 4) !=
01303                                             0)
01304                                                 break;
01305                                         os_memcpy(results[ap_num].wpa_ie, gpos,
01306                                                   ielen);
01307                                         results[ap_num].wpa_ie_len = ielen;
01308                                         break;
01309                                 case RSN_INFO_ELEM:
01310                                         os_memcpy(results[ap_num].rsn_ie, gpos,
01311                                                   ielen);
01312                                         results[ap_num].rsn_ie_len = ielen;
01313                                         break;
01314                                 }
01315                                 gpos += ielen;
01316                         }
01317                         break;
01318                 case IWEVCUSTOM:
01319                         clen = iwe->u.data.length;
01320                         if (custom + clen > end)
01321                                 break;
01322                         if (clen > 7 &&
01323                             os_strncmp(custom, "wpa_ie=", 7) == 0 &&
01324                             ap_num < max_size) {
01325                                 char *spos;
01326                                 int bytes;
01327                                 spos = custom + 7;
01328                                 bytes = custom + clen - spos;
01329                                 if (bytes & 1)
01330                                         break;
01331                                 bytes /= 2;
01332                                 if (bytes > SSID_MAX_WPA_IE_LEN) {
01333                                         wpa_printf(MSG_INFO, "Too long WPA IE "
01334                                                    "(%d)", bytes);
01335                                         break;
01336                                 }
01337                                 hexstr2bin(spos, results[ap_num].wpa_ie,
01338                                            bytes);
01339                                 results[ap_num].wpa_ie_len = bytes;
01340                         } else if (clen > 7 &&
01341                                    os_strncmp(custom, "rsn_ie=", 7) == 0 &&
01342                                    ap_num < max_size) {
01343                                 char *spos;
01344                                 int bytes;
01345                                 spos = custom + 7;
01346                                 bytes = custom + clen - spos;
01347                                 if (bytes & 1)
01348                                         break;
01349                                 bytes /= 2;
01350                                 if (bytes > SSID_MAX_WPA_IE_LEN) {
01351                                         wpa_printf(MSG_INFO, "Too long RSN IE "
01352                                                    "(%d)", bytes);
01353                                         break;
01354                                 }
01355                                 hexstr2bin(spos, results[ap_num].rsn_ie,
01356                                            bytes);
01357                                 results[ap_num].rsn_ie_len = bytes;
01358                         }
01359                         break;
01360                 }
01361 
01362                 pos += iwe->len;
01363         }
01364         os_free(res_buf);
01365         res_buf = NULL;
01366         if (!first)
01367                 ap_num++;
01368         if (ap_num > max_size) {
01369                 wpa_printf(MSG_DEBUG, "Too small scan result buffer - "
01370                            "%lu BSSes but room only for %lu",
01371                            (unsigned long) ap_num,
01372                            (unsigned long) max_size);
01373                 ap_num = max_size;
01374         }
01375         qsort(results, ap_num, sizeof(struct wpa_scan_result),
01376               wpa_scan_result_compar);
01377 
01378         wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
01379                    (unsigned long) len, (unsigned long) ap_num);
01380 
01381         return ap_num;
01382 }
01383 
01384 
01385 static int wpa_driver_wext_get_range(void *priv)
01386 {
01387         struct wpa_driver_wext_data *drv = priv;
01388         struct iw_range *range;
01389         struct iwreq iwr;
01390         int minlen;
01391         size_t buflen;
01392 
01393         /*
01394          * Use larger buffer than struct iw_range in order to allow the
01395          * structure to grow in the future.
01396          */
01397         buflen = sizeof(struct iw_range) + 500;
01398         range = os_zalloc(buflen);
01399         if (range == NULL)
01400                 return -1;
01401 
01402         os_memset(&iwr, 0, sizeof(iwr));
01403         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01404         iwr.u.data.pointer = (caddr_t) range;
01405         iwr.u.data.length = buflen;
01406 
01407         minlen = ((char *) &range->enc_capa) - (char *) range +
01408                 sizeof(range->enc_capa);
01409 
01410         if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
01411                 perror("ioctl[SIOCGIWRANGE]");
01412                 os_free(range);
01413                 return -1;
01414         } else if (iwr.u.data.length >= minlen &&
01415                    range->we_version_compiled >= 18) {
01416                 wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
01417                            "WE(source)=%d enc_capa=0x%x",
01418                            range->we_version_compiled,
01419                            range->we_version_source,
01420                            range->enc_capa);
01421                 drv->has_capability = 1;
01422                 drv->we_version_compiled = range->we_version_compiled;
01423                 if (range->enc_capa & IW_ENC_CAPA_WPA) {
01424                         drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
01425                                 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
01426                 }
01427                 if (range->enc_capa & IW_ENC_CAPA_WPA2) {
01428                         drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
01429                                 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
01430                 }
01431                 drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
01432                         WPA_DRIVER_CAPA_ENC_WEP104;
01433                 if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
01434                         drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
01435                 if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
01436                         drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
01437                 wpa_printf(MSG_DEBUG, "  capabilities: key_mgmt 0x%x enc 0x%x",
01438                            drv->capa.key_mgmt, drv->capa.enc);
01439         } else {
01440                 wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
01441                            "assuming WPA is not supported");
01442         }
01443 
01444         os_free(range);
01445         return 0;
01446 }
01447 
01448 
01449 static int wpa_driver_wext_set_wpa(void *priv, int enabled)
01450 {
01451         struct wpa_driver_wext_data *drv = priv;
01452         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01453 
01454         return wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
01455                                               enabled);
01456 }
01457 
01458 
01459 static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg,
01460                                        const u8 *addr, int key_idx,
01461                                        int set_tx, const u8 *seq,
01462                                        size_t seq_len,
01463                                        const u8 *key, size_t key_len)
01464 {
01465         struct wpa_driver_wext_data *drv = priv;
01466         struct iwreq iwr;
01467         int ret = 0;
01468         struct iw_encode_ext *ext;
01469 
01470         if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) {
01471                 wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu",
01472                            __FUNCTION__, (unsigned long) seq_len);
01473                 return -1;
01474         }
01475 
01476         ext = os_zalloc(sizeof(*ext) + key_len);
01477         if (ext == NULL)
01478                 return -1;
01479         os_memset(&iwr, 0, sizeof(iwr));
01480         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01481         iwr.u.encoding.flags = key_idx + 1;
01482         if (alg == WPA_ALG_NONE)
01483                 iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
01484         iwr.u.encoding.pointer = (caddr_t) ext;
01485         iwr.u.encoding.length = sizeof(*ext) + key_len;
01486 
01487         if (addr == NULL ||
01488             os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
01489                 ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
01490         if (set_tx)
01491                 ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
01492 
01493         ext->addr.sa_family = ARPHRD_ETHER;
01494         if (addr)
01495                 os_memcpy(ext->addr.sa_data, addr, ETH_ALEN);
01496         else
01497                 os_memset(ext->addr.sa_data, 0xff, ETH_ALEN);
01498         if (key && key_len) {
01499                 os_memcpy(ext + 1, key, key_len);
01500                 ext->key_len = key_len;
01501         }
01502         switch (alg) {
01503         case WPA_ALG_NONE:
01504                 ext->alg = IW_ENCODE_ALG_NONE;
01505                 break;
01506         case WPA_ALG_WEP:
01507                 ext->alg = IW_ENCODE_ALG_WEP;
01508                 break;
01509         case WPA_ALG_TKIP:
01510                 ext->alg = IW_ENCODE_ALG_TKIP;
01511                 break;
01512         case WPA_ALG_CCMP:
01513                 ext->alg = IW_ENCODE_ALG_CCMP;
01514                 break;
01515         default:
01516                 wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
01517                            __FUNCTION__, alg);
01518                 os_free(ext);
01519                 return -1;
01520         }
01521 
01522         if (seq && seq_len) {
01523                 ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID;
01524                 os_memcpy(ext->rx_seq, seq, seq_len);
01525         }
01526 
01527         if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) {
01528                 ret = errno == EOPNOTSUPP ? -2 : -1;
01529                 if (errno == ENODEV) {
01530                         /*
01531                          * ndiswrapper seems to be returning incorrect error
01532                          * code.. */
01533                         ret = -2;
01534                 }
01535 
01536                 perror("ioctl[SIOCSIWENCODEEXT]");
01537         }
01538 
01539         os_free(ext);
01540         return ret;
01541 }
01542 
01543 
01571 int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
01572                             const u8 *addr, int key_idx,
01573                             int set_tx, const u8 *seq, size_t seq_len,
01574                             const u8 *key, size_t key_len)
01575 {
01576         struct wpa_driver_wext_data *drv = priv;
01577         struct iwreq iwr;
01578         int ret = 0;
01579 
01580         wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
01581                    "key_len=%lu",
01582                    __FUNCTION__, alg, key_idx, set_tx,
01583                    (unsigned long) seq_len, (unsigned long) key_len);
01584 
01585         ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
01586                                           seq, seq_len, key, key_len);
01587         if (ret == 0)
01588                 return 0;
01589 
01590         if (ret == -2 &&
01591             (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) {
01592                 wpa_printf(MSG_DEBUG, "Driver did not support "
01593                            "SIOCSIWENCODEEXT, trying SIOCSIWENCODE");
01594                 ret = 0;
01595         } else {
01596                 wpa_printf(MSG_DEBUG, "Driver did not support "
01597                            "SIOCSIWENCODEEXT");
01598                 return ret;
01599         }
01600 
01601         os_memset(&iwr, 0, sizeof(iwr));
01602         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01603         iwr.u.encoding.flags = key_idx + 1;
01604         if (alg == WPA_ALG_NONE)
01605                 iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
01606         iwr.u.encoding.pointer = (caddr_t) key;
01607         iwr.u.encoding.length = key_len;
01608 
01609         if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
01610                 perror("ioctl[SIOCSIWENCODE]");
01611                 ret = -1;
01612         }
01613 
01614         if (set_tx && alg != WPA_ALG_NONE) {
01615                 os_memset(&iwr, 0, sizeof(iwr));
01616                 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01617                 iwr.u.encoding.flags = key_idx + 1;
01618                 iwr.u.encoding.pointer = (caddr_t) key;
01619                 iwr.u.encoding.length = 0;
01620                 if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
01621                         perror("ioctl[SIOCSIWENCODE] (set_tx)");
01622                         ret = -1;
01623                 }
01624         }
01625 
01626         return ret;
01627 }
01628 
01629 
01630 static int wpa_driver_wext_set_countermeasures(void *priv,
01631                                                int enabled)
01632 {
01633         struct wpa_driver_wext_data *drv = priv;
01634         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01635         return wpa_driver_wext_set_auth_param(drv,
01636                                               IW_AUTH_TKIP_COUNTERMEASURES,
01637                                               enabled);
01638 }
01639 
01640 
01641 static int wpa_driver_wext_set_drop_unencrypted(void *priv,
01642                                                 int enabled)
01643 {
01644         struct wpa_driver_wext_data *drv = priv;
01645         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01646         drv->use_crypt = enabled;
01647         return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
01648                                               enabled);
01649 }
01650 
01651 
01652 static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
01653                                 const u8 *addr, int cmd, int reason_code)
01654 {
01655         struct iwreq iwr;
01656         struct iw_mlme mlme;
01657         int ret = 0;
01658 
01659         os_memset(&iwr, 0, sizeof(iwr));
01660         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01661         os_memset(&mlme, 0, sizeof(mlme));
01662         mlme.cmd = cmd;
01663         mlme.reason_code = reason_code;
01664         mlme.addr.sa_family = ARPHRD_ETHER;
01665         os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
01666         iwr.u.data.pointer = (caddr_t) &mlme;
01667         iwr.u.data.length = sizeof(mlme);
01668 
01669         if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
01670                 perror("ioctl[SIOCSIWMLME]");
01671                 ret = -1;
01672         }
01673 
01674         return ret;
01675 }
01676 
01677 
01678 static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
01679                                           int reason_code)
01680 {
01681         struct wpa_driver_wext_data *drv = priv;
01682         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01683         return wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
01684 }
01685 
01686 
01687 static int wpa_driver_wext_disassociate(void *priv, const u8 *addr,
01688                                         int reason_code)
01689 {
01690         struct wpa_driver_wext_data *drv = priv;
01691         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01692         return wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC,
01693                                     reason_code);
01694 }
01695 
01696 
01697 static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
01698                                       size_t ie_len)
01699 {
01700         struct wpa_driver_wext_data *drv = priv;
01701         struct iwreq iwr;
01702         int ret = 0;
01703 
01704         os_memset(&iwr, 0, sizeof(iwr));
01705         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01706         iwr.u.data.pointer = (caddr_t) ie;
01707         iwr.u.data.length = ie_len;
01708 
01709         if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
01710                 perror("ioctl[SIOCSIWGENIE]");
01711                 ret = -1;
01712         }
01713 
01714         return ret;
01715 }
01716 
01717 
01718 static int wpa_driver_wext_cipher2wext(int cipher)
01719 {
01720         switch (cipher) {
01721         case CIPHER_NONE:
01722                 return IW_AUTH_CIPHER_NONE;
01723         case CIPHER_WEP40:
01724                 return IW_AUTH_CIPHER_WEP40;
01725         case CIPHER_TKIP:
01726                 return IW_AUTH_CIPHER_TKIP;
01727         case CIPHER_CCMP:
01728                 return IW_AUTH_CIPHER_CCMP;
01729         case CIPHER_WEP104:
01730                 return IW_AUTH_CIPHER_WEP104;
01731         default:
01732                 return 0;
01733         }
01734 }
01735 
01736 
01737 static int wpa_driver_wext_keymgmt2wext(int keymgmt)
01738 {
01739         switch (keymgmt) {
01740         case KEY_MGMT_802_1X:
01741                 return IW_AUTH_KEY_MGMT_802_1X;
01742         case KEY_MGMT_PSK:
01743                 return IW_AUTH_KEY_MGMT_PSK;
01744         default:
01745                 return 0;
01746         }
01747 }
01748 
01749 
01750 static int
01751 wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
01752                                   struct wpa_driver_associate_params *params)
01753 {
01754         struct iwreq iwr;
01755         int ret = 0;
01756 
01757         wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
01758                    "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
01759 
01760         os_memset(&iwr, 0, sizeof(iwr));
01761         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01762         /* Just changing mode, not actual keys */
01763         iwr.u.encoding.flags = 0;
01764         iwr.u.encoding.pointer = (caddr_t) NULL;
01765         iwr.u.encoding.length = 0;
01766 
01767         /*
01768          * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
01769          * different things. Here they are used to indicate Open System vs.
01770          * Shared Key authentication algorithm. However, some drivers may use
01771          * them to select between open/restricted WEP encrypted (open = allow
01772          * both unencrypted and encrypted frames; restricted = only allow
01773          * encrypted frames).
01774          */
01775 
01776         if (!drv->use_crypt) {
01777                 iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
01778         } else {
01779                 if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
01780                         iwr.u.encoding.flags |= IW_ENCODE_OPEN;
01781                 if (params->auth_alg & AUTH_ALG_SHARED_KEY)
01782                         iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
01783         }
01784 
01785         if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
01786                 perror("ioctl[SIOCSIWENCODE]");
01787                 ret = -1;
01788         }
01789 
01790         return ret;
01791 }
01792 
01793 
01794 static int
01795 wpa_driver_wext_associate(void *priv,
01796                           struct wpa_driver_associate_params *params)
01797 {
01798         struct wpa_driver_wext_data *drv = priv;
01799         int ret = 0;
01800         int allow_unencrypted_eapol;
01801         int value;
01802 
01803         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
01804 
01805         /*
01806          * If the driver did not support SIOCSIWAUTH, fallback to
01807          * SIOCSIWENCODE here.
01808          */
01809         if (drv->auth_alg_fallback &&
01810             wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
01811                 ret = -1;
01812 
01813         if (!params->bssid &&
01814             wpa_driver_wext_set_bssid(drv, NULL) < 0)
01815                 ret = -1;
01816 
01817         if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
01818                 ret = -1;
01819         /* TODO: should consider getting wpa version and cipher/key_mgmt suites
01820          * from configuration, not from here, where only the selected suite is
01821          * available */
01822         if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
01823             < 0)
01824                 ret = -1;
01825         if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
01826                 value = IW_AUTH_WPA_VERSION_DISABLED;
01827         else if (params->wpa_ie[0] == RSN_INFO_ELEM)
01828                 value = IW_AUTH_WPA_VERSION_WPA2;
01829         else
01830                 value = IW_AUTH_WPA_VERSION_WPA;
01831         if (wpa_driver_wext_set_auth_param(drv,
01832                                            IW_AUTH_WPA_VERSION, value) < 0)
01833                 ret = -1;
01834         value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
01835         if (wpa_driver_wext_set_auth_param(drv,
01836                                            IW_AUTH_CIPHER_PAIRWISE, value) < 0)
01837                 ret = -1;
01838         value = wpa_driver_wext_cipher2wext(params->group_suite);
01839         if (wpa_driver_wext_set_auth_param(drv,
01840                                            IW_AUTH_CIPHER_GROUP, value) < 0)
01841                 ret = -1;
01842         value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
01843         if (wpa_driver_wext_set_auth_param(drv,
01844                                            IW_AUTH_KEY_MGMT, value) < 0)
01845                 ret = -1;
01846         value = params->key_mgmt_suite != KEY_MGMT_NONE ||
01847                 params->pairwise_suite != CIPHER_NONE ||
01848                 params->group_suite != CIPHER_NONE ||
01849                 params->wpa_ie_len;
01850         if (wpa_driver_wext_set_auth_param(drv,
01851                                            IW_AUTH_PRIVACY_INVOKED, value) < 0)
01852                 ret = -1;
01853 
01854         /* Allow unencrypted EAPOL messages even if pairwise keys are set when
01855          * not using WPA. IEEE 802.1X specifies that these frames are not
01856          * encrypted, but WPA encrypts them when pairwise keys are in use. */
01857         if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
01858             params->key_mgmt_suite == KEY_MGMT_PSK)
01859                 allow_unencrypted_eapol = 0;
01860         else
01861                 allow_unencrypted_eapol = 1;
01862         
01863         if (wpa_driver_wext_set_auth_param(drv,
01864                                            IW_AUTH_RX_UNENCRYPTED_EAPOL,
01865                                            allow_unencrypted_eapol) < 0)
01866                 ret = -1;
01867         if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
01868                 ret = -1;
01869         if (wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
01870                 ret = -1;
01871         if (params->bssid &&
01872             wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
01873                 ret = -1;
01874 
01875         return ret;
01876 }
01877 
01878 
01879 static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
01880 {
01881         struct wpa_driver_wext_data *drv = priv;
01882         int algs = 0, res;
01883 
01884         if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
01885                 algs |= IW_AUTH_ALG_OPEN_SYSTEM;
01886         if (auth_alg & AUTH_ALG_SHARED_KEY)
01887                 algs |= IW_AUTH_ALG_SHARED_KEY;
01888         if (auth_alg & AUTH_ALG_LEAP)
01889                 algs |= IW_AUTH_ALG_LEAP;
01890         if (algs == 0) {
01891                 /* at least one algorithm should be set */
01892                 algs = IW_AUTH_ALG_OPEN_SYSTEM;
01893         }
01894 
01895         res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
01896                                              algs);
01897         drv->auth_alg_fallback = res == -2;
01898         return res;
01899 }
01900 
01901 
01909 int wpa_driver_wext_set_mode(void *priv, int mode)
01910 {
01911         struct wpa_driver_wext_data *drv = priv;
01912         struct iwreq iwr;
01913         int ret = 0;
01914 
01915         os_memset(&iwr, 0, sizeof(iwr));
01916         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01917         iwr.u.mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
01918 
01919         if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
01920                 perror("ioctl[SIOCSIWMODE]");
01921                 ret = -1;
01922         }
01923 
01924         return ret;
01925 }
01926 
01927 
01928 static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv,
01929                                  u32 cmd, const u8 *bssid, const u8 *pmkid)
01930 {
01931         struct iwreq iwr;
01932         struct iw_pmksa pmksa;
01933         int ret = 0;
01934 
01935         os_memset(&iwr, 0, sizeof(iwr));
01936         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
01937         os_memset(&pmksa, 0, sizeof(pmksa));
01938         pmksa.cmd = cmd;
01939         pmksa.bssid.sa_family = ARPHRD_ETHER;
01940         if (bssid)
01941                 os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
01942         if (pmkid)
01943                 os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
01944         iwr.u.data.pointer = (caddr_t) &pmksa;
01945         iwr.u.data.length = sizeof(pmksa);
01946 
01947         if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
01948                 if (errno != EOPNOTSUPP)
01949                         perror("ioctl[SIOCSIWPMKSA]");
01950                 ret = -1;
01951         }
01952 
01953         return ret;
01954 }
01955 
01956 
01957 static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid,
01958                                      const u8 *pmkid)
01959 {
01960         struct wpa_driver_wext_data *drv = priv;
01961         return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
01962 }
01963 
01964 
01965 static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid,
01966                                         const u8 *pmkid)
01967 {
01968         struct wpa_driver_wext_data *drv = priv;
01969         return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
01970 }
01971 
01972 
01973 static int wpa_driver_wext_flush_pmkid(void *priv)
01974 {
01975         struct wpa_driver_wext_data *drv = priv;
01976         return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
01977 }
01978 
01979 
01980 static int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
01981 {
01982         struct wpa_driver_wext_data *drv = priv;
01983         if (!drv->has_capability)
01984                 return -1;
01985         os_memcpy(capa, &drv->capa, sizeof(*capa));
01986         return 0;
01987 }
01988 
01989 
01990 int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
01991                                         const char *ifname)
01992 {
01993         if (ifname == NULL) {
01994                 drv->ifindex2 = -1;
01995                 return 0;
01996         }
01997 
01998         drv->ifindex2 = if_nametoindex(ifname);
01999         if (drv->ifindex2 <= 0)
02000                 return -1;
02001 
02002         wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for "
02003                    "wireless events", drv->ifindex2, ifname);
02004 
02005         return 0;
02006 }
02007 
02008 
02009 int wpa_driver_wext_set_operstate(void *priv, int state)
02010 {
02011         struct wpa_driver_wext_data *drv = priv;
02012 
02013         wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
02014                    __func__, drv->operstate, state, state ? "UP" : "DORMANT");
02015         drv->operstate = state;
02016         return wpa_driver_wext_send_oper_ifla(
02017                 drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
02018 }
02019 
02020 
02021 #ifdef CONFIG_CLIENT_MLME
02022 static int hostapd_ioctl(struct wpa_driver_wext_data *drv,
02023                          struct prism2_hostapd_param *param, int len)
02024 {
02025         struct iwreq iwr;
02026 
02027         os_memset(&iwr, 0, sizeof(iwr));
02028         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
02029         iwr.u.data.pointer = (caddr_t) param;
02030         iwr.u.data.length = len;
02031 
02032         if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
02033                 perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
02034                 return -1;
02035         }
02036 
02037         return 0;
02038 }
02039 
02040 
02041 static struct wpa_hw_modes *
02042 wpa_driver_wext_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
02043 {
02044         struct wpa_driver_wext_data *drv = priv;
02045         struct prism2_hostapd_param *param;
02046         u8 *pos, *end;
02047         struct wpa_hw_modes *modes = NULL;
02048         int i;
02049 
02050         param = os_zalloc(PRISM2_HOSTAPD_MAX_BUF_SIZE);
02051         if (param == NULL)
02052                 return NULL;
02053         param->cmd = PRISM2_HOSTAPD_GET_HW_FEATURES;
02054 
02055         if (hostapd_ioctl(drv, param, PRISM2_HOSTAPD_MAX_BUF_SIZE) < 0) {
02056                 perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
02057                 goto out;
02058         }
02059 
02060         *num_modes = param->u.hw_features.num_modes;
02061         *flags = param->u.hw_features.flags;
02062 
02063         pos = param->u.hw_features.data;
02064         end = pos + PRISM2_HOSTAPD_MAX_BUF_SIZE -
02065                 (param->u.hw_features.data - (u8 *) param);
02066 
02067         modes = os_zalloc(*num_modes * sizeof(struct wpa_hw_modes));
02068         if (modes == NULL)
02069                 goto out;
02070 
02071         for (i = 0; i < *num_modes; i++) {
02072                 struct hostapd_ioctl_hw_modes_hdr *hdr;
02073                 struct wpa_hw_modes *feature;
02074                 int clen, rlen;
02075 
02076                 hdr = (struct hostapd_ioctl_hw_modes_hdr *) pos;
02077                 pos = (u8 *) (hdr + 1);
02078                 clen = hdr->num_channels * sizeof(struct wpa_channel_data);
02079                 rlen = hdr->num_rates * sizeof(struct wpa_rate_data);
02080 
02081                 feature = &modes[i];
02082                 switch (hdr->mode) {
02083                 case MODE_IEEE80211A:
02084                         feature->mode = WPA_MODE_IEEE80211A;
02085                         break;
02086                 case MODE_IEEE80211B:
02087                         feature->mode = WPA_MODE_IEEE80211B;
02088                         break;
02089                 case MODE_IEEE80211G:
02090                         feature->mode = WPA_MODE_IEEE80211G;
02091                         break;
02092                 case MODE_ATHEROS_TURBO:
02093                 case MODE_ATHEROS_TURBOG:
02094                         wpa_printf(MSG_ERROR, "Skip unsupported hw_mode=%d in "
02095                                    "get_hw_features data", hdr->mode);
02096                         pos += clen + rlen;
02097                         continue;
02098                 default:
02099                         wpa_printf(MSG_ERROR, "Unknown hw_mode=%d in "
02100                                    "get_hw_features data", hdr->mode);
02101                         ieee80211_sta_free_hw_features(modes, *num_modes);
02102                         modes = NULL;
02103                         break;
02104                 }
02105                 feature->num_channels = hdr->num_channels;
02106                 feature->num_rates = hdr->num_rates;
02107 
02108                 feature->channels = os_malloc(clen);
02109                 feature->rates = os_malloc(rlen);
02110                 if (!feature->channels || !feature->rates) {
02111                         ieee80211_sta_free_hw_features(modes, *num_modes);
02112                         modes = NULL;
02113                         break;
02114                 }
02115 
02116                 os_memcpy(feature->channels, pos, clen);
02117                 pos += clen;
02118                 os_memcpy(feature->rates, pos, rlen);
02119                 pos += rlen;
02120         }
02121 
02122 out:
02123         os_free(param);
02124         return modes;
02125 }
02126 
02127 
02128 int wpa_driver_wext_set_channel(void *priv, wpa_hw_mode phymode, int chan,
02129                                 int freq)
02130 {
02131         return wpa_driver_wext_set_freq(priv, freq);
02132 }
02133 
02134 
02135 static void wpa_driver_wext_mlme_read(int sock, void *eloop_ctx,
02136                                       void *sock_ctx)
02137 {
02138         struct wpa_driver_wext_data *drv = eloop_ctx;
02139         int len;
02140         unsigned char buf[3000];
02141         struct ieee80211_frame_info *fi;
02142         struct ieee80211_rx_status rx_status;
02143 
02144         len = recv(sock, buf, sizeof(buf), 0);
02145         if (len < 0) {
02146                 perror("recv[MLME]");
02147                 return;
02148         }
02149 
02150         if (len < (int) sizeof(struct ieee80211_frame_info)) {
02151                 wpa_printf(MSG_DEBUG, "WEXT: Too short MLME frame (len=%d)",
02152                            len);
02153                 return;
02154         }
02155 
02156         fi = (struct ieee80211_frame_info *) buf;
02157         if (ntohl(fi->version) != IEEE80211_FI_VERSION) {
02158                 wpa_printf(MSG_DEBUG, "WEXT: Invalid MLME frame info version "
02159                            "0x%x", ntohl(fi->version));
02160                 return;
02161         }
02162 
02163         os_memset(&rx_status, 0, sizeof(rx_status));
02164         rx_status.ssi = ntohl(fi->ssi_signal);
02165         rx_status.channel = ntohl(fi->channel);
02166 
02167         ieee80211_sta_rx(drv->ctx, buf + sizeof(struct ieee80211_frame_info),
02168                          len - sizeof(struct ieee80211_frame_info),
02169                          &rx_status);
02170 }
02171 
02172 
02173 static int wpa_driver_wext_open_mlme(struct wpa_driver_wext_data *drv)
02174 {
02175         int flags, ifindex, s, *i;
02176         struct sockaddr_ll addr;
02177         struct iwreq iwr;
02178 
02179         os_memset(&iwr, 0, sizeof(iwr));
02180         os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
02181         i = (int *) iwr.u.name;
02182         *i++ = PRISM2_PARAM_USER_SPACE_MLME;
02183         *i++ = 1;
02184 
02185         if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
02186                 wpa_printf(MSG_ERROR, "WEXT: Failed to configure driver to "
02187                            "use user space MLME");
02188                 return -1;
02189         }
02190 
02191         ifindex = if_nametoindex(drv->mlmedev);
02192         if (ifindex == 0) {
02193                 wpa_printf(MSG_ERROR, "WEXT: mlmedev='%s' not found",
02194                            drv->mlmedev);
02195                 return -1;
02196         }
02197 
02198         if (wpa_driver_wext_get_ifflags_ifname(drv, drv->mlmedev, &flags) != 0
02199             || wpa_driver_wext_set_ifflags_ifname(drv, drv->mlmedev,
02200                                                   flags | IFF_UP) != 0) {
02201                 wpa_printf(MSG_ERROR, "WEXT: Could not set interface "
02202                            "'%s' UP", drv->mlmedev);
02203                 return -1;
02204         }
02205 
02206         s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
02207         if (s < 0) {
02208                 perror("socket[PF_PACKET,SOCK_RAW]");
02209                 return -1;
02210         }
02211 
02212         os_memset(&addr, 0, sizeof(addr));
02213         addr.sll_family = AF_PACKET;
02214         addr.sll_ifindex = ifindex;
02215 
02216         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
02217                 perror("bind(MLME)");
02218                 return -1;
02219         }
02220 
02221         if (eloop_register_read_sock(s, wpa_driver_wext_mlme_read, drv, NULL))
02222         {
02223                 wpa_printf(MSG_ERROR, "WEXT: Could not register MLME read "
02224                            "socket");
02225                 close(s);
02226                 return -1;
02227         }
02228 
02229         return s;
02230 }
02231 
02232 
02233 static int wpa_driver_wext_send_mlme(void *priv, const u8 *data,
02234                                      size_t data_len)
02235 {
02236         struct wpa_driver_wext_data *drv = priv;
02237         int ret;
02238 
02239         ret = send(drv->mlme_sock, data, data_len, 0);
02240         if (ret < 0) {
02241                 perror("send[MLME]");
02242                 return -1;
02243         }
02244 
02245         return 0;
02246 }
02247 
02248 
02249 static int wpa_driver_wext_mlme_add_sta(void *priv, const u8 *addr,
02250                                         const u8 *supp_rates,
02251                                         size_t supp_rates_len)
02252 {
02253         struct wpa_driver_wext_data *drv = priv;
02254         struct prism2_hostapd_param param;
02255         size_t len;
02256 
02257         os_memset(&param, 0, sizeof(param));
02258         param.cmd = PRISM2_HOSTAPD_ADD_STA;
02259         os_memcpy(param.sta_addr, addr, ETH_ALEN);
02260         len = supp_rates_len;
02261         if (len > sizeof(param.u.add_sta.supp_rates))
02262                 len = sizeof(param.u.add_sta.supp_rates);
02263         os_memcpy(param.u.add_sta.supp_rates, supp_rates, len);
02264         return hostapd_ioctl(drv, &param, sizeof(param));
02265 }
02266 
02267 
02268 static int wpa_driver_wext_mlme_remove_sta(void *priv, const u8 *addr)
02269 {
02270         struct wpa_driver_wext_data *drv = priv;
02271         struct prism2_hostapd_param param;
02272 
02273         os_memset(&param, 0, sizeof(param));
02274         param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
02275         os_memcpy(param.sta_addr, addr, ETH_ALEN);
02276         return hostapd_ioctl(drv, &param, sizeof(param));
02277 }
02278 
02279 #endif /* CONFIG_CLIENT_MLME */
02280 
02281 
02282 static int wpa_driver_wext_set_param(void *priv, const char *param)
02283 {
02284 #ifdef CONFIG_CLIENT_MLME
02285         struct wpa_driver_wext_data *drv = priv;
02286         const char *pos, *pos2;
02287         size_t len;
02288 
02289         if (param == NULL)
02290                 return 0;
02291 
02292         wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
02293 
02294         pos = os_strstr(param, "mlmedev=");
02295         if (pos) {
02296                 pos += 8;
02297                 pos2 = os_strchr(pos, ' ');
02298                 if (pos2)
02299                         len = pos2 - pos;
02300                 else
02301                         len = os_strlen(pos);
02302                 if (len + 1 > sizeof(drv->mlmedev))
02303                         return -1;
02304                 os_memcpy(drv->mlmedev, pos, len);
02305                 drv->mlmedev[len] = '\0';
02306                 wpa_printf(MSG_DEBUG, "WEXT: Using user space MLME with "
02307                            "mlmedev='%s'", drv->mlmedev);
02308                 drv->capa.flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
02309 
02310                 drv->mlme_sock = wpa_driver_wext_open_mlme(drv);
02311                 if (drv->mlme_sock < 0)
02312                         return -1;
02313         }
02314 #endif /* CONFIG_CLIENT_MLME */
02315 
02316         return 0;
02317 }
02318 
02319 
02320 int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
02321 {
02322         return drv->we_version_compiled;
02323 }
02324 
02325 
02326 const struct wpa_driver_ops wpa_driver_wext_ops = {
02327         .name = "wext",
02328         .desc = "Linux wireless extensions (generic)",
02329         .get_bssid = wpa_driver_wext_get_bssid,
02330         .get_ssid = wpa_driver_wext_get_ssid,
02331         .set_wpa = wpa_driver_wext_set_wpa,
02332         .set_key = wpa_driver_wext_set_key,
02333         .set_countermeasures = wpa_driver_wext_set_countermeasures,
02334         .set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted,
02335         .scan = wpa_driver_wext_scan,
02336         .get_scan_results = wpa_driver_wext_get_scan_results,
02337         .deauthenticate = wpa_driver_wext_deauthenticate,
02338         .disassociate = wpa_driver_wext_disassociate,
02339         .associate = wpa_driver_wext_associate,
02340         .set_auth_alg = wpa_driver_wext_set_auth_alg,
02341         .init = wpa_driver_wext_init,
02342         .deinit = wpa_driver_wext_deinit,
02343         .set_param = wpa_driver_wext_set_param,
02344         .add_pmkid = wpa_driver_wext_add_pmkid,
02345         .remove_pmkid = wpa_driver_wext_remove_pmkid,
02346         .flush_pmkid = wpa_driver_wext_flush_pmkid,
02347         .get_capa = wpa_driver_wext_get_capa,
02348         .set_operstate = wpa_driver_wext_set_operstate,
02349 #ifdef CONFIG_CLIENT_MLME
02350         .get_hw_feature_data = wpa_driver_wext_get_hw_feature_data,
02351         .set_channel = wpa_driver_wext_set_channel,
02352         .set_ssid = wpa_driver_wext_set_ssid,
02353         .set_bssid = wpa_driver_wext_set_bssid,
02354         .send_mlme = wpa_driver_wext_send_mlme,
02355         .mlme_add_sta = wpa_driver_wext_mlme_add_sta,
02356         .mlme_remove_sta = wpa_driver_wext_mlme_remove_sta,
02357 #endif /* CONFIG_CLIENT_MLME */
02358 };
02359 

Generated on Sun Dec 31 13:48:53 2006 for wpa_supplicant by  doxygen 1.4.2