| /* |
| * WPA Supplicant - driver interaction with Linux ndiswrapper |
| * Copyright (c) 2004-2006, Giridhar Pemmasani <[email protected]> |
| * Copyright (c) 2004-2006, Jouni Malinen <[email protected]> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * Alternatively, this software may be distributed under the terms of BSD |
| * license. |
| * |
| * See README and COPYING for more details. |
| */ |
| |
| #include "includes.h" |
| #include <sys/ioctl.h> |
| #include <net/if_arp.h> |
| |
| #include "wireless_copy.h" |
| #include "common.h" |
| #include "driver.h" |
| #include "l2_packet.h" |
| #include "eloop.h" |
| #include "priv_netlink.h" |
| #include "driver_wext.h" |
| |
| struct wpa_driver_ndiswrapper_data { |
| void *wext; /* private data for driver_wext */ |
| void *ctx; |
| char ifname[IFNAMSIZ + 1]; |
| int sock; |
| }; |
| |
| |
| struct wpa_key |
| { |
| wpa_alg alg; |
| const u8 *addr; |
| int key_index; |
| int set_tx; |
| const u8 *seq; |
| size_t seq_len; |
| const u8 *key; |
| size_t key_len; |
| }; |
| |
| struct wpa_assoc_info |
| { |
| const u8 *bssid; |
| const u8 *ssid; |
| size_t ssid_len; |
| int freq; |
| const u8 *wpa_ie; |
| size_t wpa_ie_len; |
| wpa_cipher pairwise_suite; |
| wpa_cipher group_suite; |
| wpa_key_mgmt key_mgmt_suite; |
| int auth_alg; |
| int mode; |
| }; |
| |
| #define PRIV_RESET SIOCIWFIRSTPRIV+0 |
| #define WPA_SET_WPA SIOCIWFIRSTPRIV+1 |
| #define WPA_SET_KEY SIOCIWFIRSTPRIV+2 |
| #define WPA_ASSOCIATE SIOCIWFIRSTPRIV+3 |
| #define WPA_DISASSOCIATE SIOCIWFIRSTPRIV+4 |
| #define WPA_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+5 |
| #define WPA_SET_COUNTERMEASURES SIOCIWFIRSTPRIV+6 |
| #define WPA_DEAUTHENTICATE SIOCIWFIRSTPRIV+7 |
| #define WPA_SET_AUTH_ALG SIOCIWFIRSTPRIV+8 |
| #define WPA_INIT SIOCIWFIRSTPRIV+9 |
| #define WPA_DEINIT SIOCIWFIRSTPRIV+10 |
| #define WPA_GET_CAPA SIOCIWFIRSTPRIV+11 |
| |
| static int get_socket(void) |
| { |
| static const int families[] = { |
| AF_INET, AF_IPX, AF_AX25, AF_APPLETALK |
| }; |
| unsigned int i; |
| int sock; |
| |
| for (i = 0; i < sizeof(families) / sizeof(int); ++i) { |
| sock = socket(families[i], SOCK_DGRAM, 0); |
| if (sock >= 0) |
| return sock; |
| } |
| |
| return -1; |
| } |
| |
| static int iw_set_ext(struct wpa_driver_ndiswrapper_data *drv, int request, |
| struct iwreq *pwrq) |
| { |
| os_strncpy(pwrq->ifr_name, drv->ifname, IFNAMSIZ); |
| return ioctl(drv->sock, request, pwrq); |
| } |
| |
| static int wpa_ndiswrapper_set_wpa(void *priv, int enabled) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| struct iwreq priv_req; |
| int ret = 0; |
| |
| os_memset(&priv_req, 0, sizeof(priv_req)); |
| |
| priv_req.u.data.flags = enabled; |
| if (iw_set_ext(drv, WPA_SET_WPA, &priv_req) < 0) |
| ret = -1; |
| return ret; |
| } |
| |
| static int wpa_ndiswrapper_set_key(void *priv, wpa_alg alg, const u8 *addr, |
| int key_idx, int set_tx, |
| const u8 *seq, size_t seq_len, |
| const u8 *key, size_t key_len) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| struct wpa_key wpa_key; |
| int ret = 0; |
| struct iwreq priv_req; |
| |
| os_memset(&priv_req, 0, sizeof(priv_req)); |
| |
| wpa_key.alg = alg; |
| wpa_key.addr = addr; |
| wpa_key.key_index = key_idx; |
| wpa_key.set_tx = set_tx; |
| wpa_key.seq = seq; |
| wpa_key.seq_len = seq_len; |
| wpa_key.key = key; |
| wpa_key.key_len = key_len; |
| |
| priv_req.u.data.pointer = (void *)&wpa_key; |
| priv_req.u.data.length = sizeof(wpa_key); |
| |
| if (iw_set_ext(drv, WPA_SET_KEY, &priv_req) < 0) |
| ret = -1; |
| |
| if (alg == WPA_ALG_NONE) { |
| /* |
| * ndiswrapper did not seem to be clearing keys properly in |
| * some cases with WPA_SET_KEY. For example, roaming from WPA |
| * enabled AP to plaintext one seemed to fail since the driver |
| * did not associate. Try to make sure the keys are cleared so |
| * that plaintext APs can be used in all cases. |
| */ |
| wpa_driver_wext_set_key(drv->wext, alg, addr, key_idx, set_tx, |
| seq, seq_len, key, key_len); |
| } |
| |
| return ret; |
| } |
| |
| static int wpa_ndiswrapper_set_countermeasures(void *priv, int enabled) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| int ret = 0; |
| struct iwreq priv_req; |
| |
| os_memset(&priv_req, 0, sizeof(priv_req)); |
| |
| priv_req.u.param.value = enabled; |
| if (iw_set_ext(drv, WPA_SET_COUNTERMEASURES, &priv_req) < 0) |
| ret = -1; |
| |
| return ret; |
| } |
| |
| static int wpa_ndiswrapper_set_drop_unencrypted(void *priv, |
| int enabled) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| int ret = 0; |
| struct iwreq priv_req; |
| |
| os_memset(&priv_req, 0, sizeof(priv_req)); |
| |
| priv_req.u.param.value = enabled; |
| if (iw_set_ext(drv, WPA_DROP_UNENCRYPTED, &priv_req) < 0) |
| ret = -1; |
| return ret; |
| } |
| |
| static int wpa_ndiswrapper_deauthenticate(void *priv, const u8 *addr, |
| int reason_code) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| int ret = 0; |
| struct iwreq priv_req; |
| |
| os_memset(&priv_req, 0, sizeof(priv_req)); |
| |
| priv_req.u.param.value = reason_code; |
| os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN); |
| if (iw_set_ext(drv, WPA_DEAUTHENTICATE, &priv_req) < 0) |
| ret = -1; |
| return ret; |
| } |
| |
| static int wpa_ndiswrapper_disassociate(void *priv, const u8 *addr, |
| int reason_code) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| int ret = 0; |
| struct iwreq priv_req; |
| |
| os_memset(&priv_req, 0, sizeof(priv_req)); |
| |
| os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN); |
| if (iw_set_ext(drv, WPA_DISASSOCIATE, &priv_req) < 0) |
| ret = -1; |
| return ret; |
| } |
| |
| static int |
| wpa_ndiswrapper_associate(void *priv, |
| struct wpa_driver_associate_params *params) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| int ret = 0; |
| struct wpa_assoc_info wpa_assoc_info; |
| struct iwreq priv_req; |
| |
| os_memset(&priv_req, 0, sizeof(priv_req)); |
| os_memset(&wpa_assoc_info, 0, sizeof(wpa_assoc_info)); |
| |
| wpa_assoc_info.bssid = params->bssid; |
| wpa_assoc_info.ssid = params->ssid; |
| wpa_assoc_info.ssid_len = params->ssid_len; |
| wpa_assoc_info.freq = params->freq; |
| wpa_assoc_info.wpa_ie = params->wpa_ie; |
| wpa_assoc_info.wpa_ie_len = params->wpa_ie_len; |
| wpa_assoc_info.pairwise_suite = params->pairwise_suite; |
| wpa_assoc_info.group_suite = params->group_suite; |
| wpa_assoc_info.key_mgmt_suite = params->key_mgmt_suite; |
| wpa_assoc_info.auth_alg = params->auth_alg; |
| wpa_assoc_info.mode = params->mode; |
| |
| priv_req.u.data.pointer = (void *)&wpa_assoc_info; |
| priv_req.u.data.length = sizeof(wpa_assoc_info); |
| |
| if (iw_set_ext(drv, WPA_ASSOCIATE, &priv_req) < 0) |
| ret = -1; |
| return ret; |
| } |
| |
| static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| int ret = 0; |
| struct iwreq priv_req; |
| |
| os_memset(&priv_req, 0, sizeof(priv_req)); |
| |
| priv_req.u.param.value = auth_alg; |
| if (iw_set_ext(drv, WPA_SET_AUTH_ALG, &priv_req) < 0) |
| ret = -1; |
| return ret; |
| } |
| |
| static int wpa_ndiswrapper_get_bssid(void *priv, u8 *bssid) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| return wpa_driver_wext_get_bssid(drv->wext, bssid); |
| } |
| |
| |
| static int wpa_ndiswrapper_get_ssid(void *priv, u8 *ssid) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| return wpa_driver_wext_get_ssid(drv->wext, ssid); |
| } |
| |
| |
| static int wpa_ndiswrapper_scan(void *priv, const u8 *ssid, size_t ssid_len) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| return wpa_driver_wext_scan(drv->wext, ssid, ssid_len); |
| } |
| |
| |
| static int wpa_ndiswrapper_get_scan_results(void *priv, |
| struct wpa_scan_result *results, |
| size_t max_size) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| return wpa_driver_wext_get_scan_results(drv->wext, results, max_size); |
| } |
| |
| |
| static int wpa_ndiswrapper_get_capa(void *priv, struct wpa_driver_capa *capa) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| int ret = 0; |
| struct iwreq priv_req; |
| |
| os_memset(&priv_req, 0, sizeof(priv_req)); |
| |
| priv_req.u.data.pointer = (void *) capa; |
| priv_req.u.data.length = sizeof(*capa); |
| if (iw_set_ext(drv, WPA_GET_CAPA, &priv_req) < 0) |
| ret = -1; |
| return ret; |
| |
| } |
| |
| |
| static int wpa_ndiswrapper_set_operstate(void *priv, int state) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| return wpa_driver_wext_set_operstate(drv->wext, state); |
| } |
| |
| |
| static void * wpa_ndiswrapper_init(void *ctx, const char *ifname) |
| { |
| struct wpa_driver_ndiswrapper_data *drv; |
| |
| drv = os_zalloc(sizeof(*drv)); |
| if (drv == NULL) |
| return NULL; |
| drv->wext = wpa_driver_wext_init(ctx, ifname); |
| if (drv->wext == NULL) { |
| os_free(drv); |
| return NULL; |
| } |
| |
| drv->ctx = ctx; |
| os_strncpy(drv->ifname, ifname, sizeof(drv->ifname)); |
| drv->sock = get_socket(); |
| if (drv->sock < 0) { |
| wpa_driver_wext_deinit(drv->wext); |
| os_free(drv); |
| return NULL; |
| } |
| |
| return drv; |
| } |
| |
| |
| static void wpa_ndiswrapper_deinit(void *priv) |
| { |
| struct wpa_driver_ndiswrapper_data *drv = priv; |
| wpa_driver_wext_deinit(drv->wext); |
| close(drv->sock); |
| os_free(drv); |
| } |
| |
| |
| const struct wpa_driver_ops wpa_driver_ndiswrapper_ops = { |
| .name = "ndiswrapper", |
| .desc = "Linux ndiswrapper", |
| .set_wpa = wpa_ndiswrapper_set_wpa, |
| .set_key = wpa_ndiswrapper_set_key, |
| .set_countermeasures = wpa_ndiswrapper_set_countermeasures, |
| .set_drop_unencrypted = wpa_ndiswrapper_set_drop_unencrypted, |
| .deauthenticate = wpa_ndiswrapper_deauthenticate, |
| .disassociate = wpa_ndiswrapper_disassociate, |
| .associate = wpa_ndiswrapper_associate, |
| .set_auth_alg = wpa_ndiswrapper_set_auth_alg, |
| |
| .get_bssid = wpa_ndiswrapper_get_bssid, |
| .get_ssid = wpa_ndiswrapper_get_ssid, |
| .scan = wpa_ndiswrapper_scan, |
| .get_scan_results = wpa_ndiswrapper_get_scan_results, |
| .init = wpa_ndiswrapper_init, |
| .deinit = wpa_ndiswrapper_deinit, |
| .get_capa = wpa_ndiswrapper_get_capa, |
| .set_operstate = wpa_ndiswrapper_set_operstate, |
| }; |