123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- /*
- * WPA Supplicant - driver interaction with old Broadcom wl.o driver
- * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
- * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
- *
- * 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.
- *
- * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
- * Linux wireless extensions and does not need (or even work) with this old
- * driver wrapper. Use driver_wext.c with that driver.
- */
- #include "includes.h"
- #include <sys/ioctl.h>
- #include "common.h"
- #if 0
- #include <netpacket/packet.h>
- #include <net/ethernet.h> /* the L2 protocols */
- #else
- #include <linux/if_packet.h>
- #include <linux/if_ether.h> /* The L2 protocols */
- #endif
- #include <net/if.h>
- #include <typedefs.h>
- /* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
- * WRT54G GPL tarball. */
- #include <wlioctl.h>
- #include "driver.h"
- #include "eloop.h"
- struct wpa_driver_broadcom_data {
- void *ctx;
- int ioctl_sock;
- int event_sock;
- char ifname[IFNAMSIZ + 1];
- };
- #ifndef WLC_DEAUTHENTICATE
- #define WLC_DEAUTHENTICATE 143
- #endif
- #ifndef WLC_DEAUTHENTICATE_WITH_REASON
- #define WLC_DEAUTHENTICATE_WITH_REASON 201
- #endif
- #ifndef WLC_SET_TKIP_COUNTERMEASURES
- #define WLC_SET_TKIP_COUNTERMEASURES 202
- #endif
- #if !defined(PSK_ENABLED) /* NEW driver interface */
- #define WL_VERSION 360130
- /* wireless authentication bit vector */
- #define WPA_ENABLED 1
- #define PSK_ENABLED 2
-
- #define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
- #define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
- #define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
- #define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
- typedef wl_wsec_key_t wsec_key_t;
- #endif
- typedef struct {
- uint32 val;
- struct ether_addr ea;
- uint16 res;
- } wlc_deauth_t;
- static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
- void *timeout_ctx);
- static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
- void *buf, int len)
- {
- struct ifreq ifr;
- wl_ioctl_t ioc;
- int ret = 0;
- wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
- drv->ifname, cmd, len, buf);
- /* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
- ioc.cmd = cmd;
- ioc.buf = buf;
- ioc.len = len;
- os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
- ifr.ifr_data = (caddr_t) &ioc;
- if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
- if (cmd != WLC_GET_MAGIC)
- perror(ifr.ifr_name);
- wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
- cmd, ret);
- }
- return ret;
- }
- static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
- return 0;
-
- os_memset(bssid, 0, ETH_ALEN);
- return -1;
- }
- static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- wlc_ssid_t s;
-
- if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
- return -1;
- os_memcpy(ssid, s.SSID, s.SSID_len);
- return s.SSID_len;
- }
- static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- unsigned int wauth, wsec;
- struct ether_addr ea;
- os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
- if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
- -1 ||
- broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
- return -1;
- if (enable) {
- wauth = PSK_ENABLED;
- wsec = TKIP_ENABLED;
- } else {
- wauth = 255;
- wsec &= ~(TKIP_ENABLED | AES_ENABLED);
- }
- if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
- -1 ||
- broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
- return -1;
- /* FIX: magic number / error handling? */
- broadcom_ioctl(drv, 122, &ea, sizeof(ea));
- return 0;
- }
- static int wpa_driver_broadcom_set_key(const char *ifname, 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_broadcom_data *drv = priv;
- int ret;
- wsec_key_t wkt;
- os_memset(&wkt, 0, sizeof wkt);
- wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
- set_tx ? "PRIMARY " : "", key_idx, alg);
- if (key && key_len > 0)
- wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
- switch (alg) {
- case WPA_ALG_NONE:
- wkt.algo = CRYPTO_ALGO_OFF;
- break;
- case WPA_ALG_WEP:
- wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
- break;
- case WPA_ALG_TKIP:
- wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
- break;
- case WPA_ALG_CCMP:
- wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
- * AES_OCB_MSDU, AES_OCB_MPDU? */
- break;
- default:
- wkt.algo = CRYPTO_ALGO_NALG;
- break;
- }
- if (seq && seq_len > 0)
- wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
- if (addr)
- wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
- wkt.index = key_idx;
- wkt.len = key_len;
- if (key && key_len > 0) {
- os_memcpy(wkt.data, key, key_len);
- if (key_len == 32) {
- /* hack hack hack XXX */
- os_memcpy(&wkt.data[16], &key[24], 8);
- os_memcpy(&wkt.data[24], &key[16], 8);
- }
- }
- /* wkt.algo = CRYPTO_ALGO_...; */
- wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
- if (addr && set_tx)
- os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
- ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
- if (addr && set_tx) {
- /* FIX: magic number / error handling? */
- broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
- }
- return ret;
- }
- static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
- void *sock_ctx)
- {
- char buf[8192];
- int left;
- wl_wpa_header_t *wwh;
- union wpa_event_data data;
-
- if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
- return;
- wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
- if ((size_t) left < sizeof(wl_wpa_header_t))
- return;
- wwh = (wl_wpa_header_t *) buf;
- if (wwh->snap.type != WL_WPA_ETHER_TYPE)
- return;
- if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
- return;
- os_memset(&data, 0, sizeof(data));
- switch (wwh->type) {
- case WLC_ASSOC_MSG:
- left -= WL_WPA_HEADER_LEN;
- wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
- left);
- if (left > 0) {
- data.assoc_info.resp_ies = os_malloc(left);
- if (data.assoc_info.resp_ies == NULL)
- return;
- os_memcpy(data.assoc_info.resp_ies,
- buf + WL_WPA_HEADER_LEN, left);
- data.assoc_info.resp_ies_len = left;
- wpa_hexdump(MSG_MSGDUMP, "BROADCOM: copying %d bytes "
- "into resp_ies",
- data.assoc_info.resp_ies, left);
- }
- /* data.assoc_info.req_ies = NULL; */
- /* data.assoc_info.req_ies_len = 0; */
- wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
- wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
- break;
- case WLC_DISASSOC_MSG:
- wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
- wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
- break;
- case WLC_PTK_MIC_MSG:
- wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
- data.michael_mic_failure.unicast = 1;
- wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
- break;
- case WLC_GTK_MIC_MSG:
- wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
- data.michael_mic_failure.unicast = 0;
- wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
- break;
- default:
- wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
- wwh->type);
- break;
- }
- os_free(data.assoc_info.resp_ies);
- }
- static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
- {
- int s;
- struct sockaddr_ll ll;
- struct wpa_driver_broadcom_data *drv;
- struct ifreq ifr;
- /* open socket to kernel */
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("socket");
- return NULL;
- }
- /* do it */
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
- perror(ifr.ifr_name);
- return NULL;
- }
- drv = os_zalloc(sizeof(*drv));
- if (drv == NULL)
- return NULL;
- drv->ctx = ctx;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->ioctl_sock = s;
- s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
- if (s < 0) {
- perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
- os_memset(&ll, 0, sizeof(ll));
- ll.sll_family = AF_PACKET;
- ll.sll_protocol = ntohs(ETH_P_802_2);
- ll.sll_ifindex = ifr.ifr_ifindex;
- ll.sll_hatype = 0;
- ll.sll_pkttype = PACKET_HOST;
- ll.sll_halen = 0;
- if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
- perror("bind(netlink)");
- close(s);
- close(drv->ioctl_sock);
- os_free(drv);
- return NULL;
- }
- eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
- NULL);
- drv->event_sock = s;
- wpa_driver_broadcom_set_wpa(drv, 1);
- return drv;
- }
- static void wpa_driver_broadcom_deinit(void *priv)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- wpa_driver_broadcom_set_wpa(drv, 0);
- eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
- eloop_unregister_read_sock(drv->event_sock);
- close(drv->event_sock);
- close(drv->ioctl_sock);
- os_free(drv);
- }
- static int wpa_driver_broadcom_set_countermeasures(void *priv,
- int enabled)
- {
- #if 0
- struct wpa_driver_broadcom_data *drv = priv;
- /* FIX: ? */
- return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
- sizeof(enabled));
- #else
- return 0;
- #endif
- }
- static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
- int _restrict = (enabled ? 1 : 0);
-
- if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
- &_restrict, sizeof(_restrict)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
- &_restrict, sizeof(_restrict)) < 0)
- return -1;
- return 0;
- }
- static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
- void *timeout_ctx)
- {
- wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
- }
- static int wpa_driver_broadcom_scan(void *priv,
- struct wpa_driver_scan_params *params)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- wlc_ssid_t wst = { 0, "" };
- const u8 *ssid = params->ssids[0].ssid;
- size_t ssid_len = params->ssids[0].ssid_len;
- if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
- wst.SSID_len = ssid_len;
- os_memcpy(wst.SSID, ssid, ssid_len);
- }
-
- if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
- return -1;
- eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
- eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
- drv->ctx);
- return 0;
- }
- static const int frequency_list[] = {
- 2412, 2417, 2422, 2427, 2432, 2437, 2442,
- 2447, 2452, 2457, 2462, 2467, 2472, 2484
- };
- struct bss_ie_hdr {
- u8 elem_id;
- u8 len;
- u8 oui[3];
- /* u8 oui_type; */
- /* u16 version; */
- } __attribute__ ((packed));
- static struct wpa_scan_results *
- wpa_driver_broadcom_get_scan_results(void *priv)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- char *buf;
- wl_scan_results_t *wsr;
- wl_bss_info_t *wbi;
- size_t ap_num;
- struct wpa_scan_results *res;
- buf = os_malloc(WLC_IOCTL_MAXLEN);
- if (buf == NULL)
- return NULL;
- wsr = (wl_scan_results_t *) buf;
- wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
- wsr->version = 107;
- wsr->count = 0;
- if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
- os_free(buf);
- return NULL;
- }
- res = os_zalloc(sizeof(*res));
- if (res == NULL) {
- os_free(buf);
- return NULL;
- }
- res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *));
- if (res->res == NULL) {
- os_free(res);
- os_free(buf);
- return NULL;
- }
- for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
- struct wpa_scan_res *r;
- r = os_malloc(sizeof(*r) + wbi->ie_length);
- if (r == NULL)
- break;
- res->res[res->num++] = r;
- os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN);
- r->freq = frequency_list[wbi->channel - 1];
- /* get ie's */
- os_memcpy(r + 1, wbi + 1, wbi->ie_length);
- r->ie_len = wbi->ie_length;
- wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
- }
- wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
- "BSSes)",
- wsr->buflen, (unsigned long) ap_num);
-
- os_free(buf);
- return res;
- }
- static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- wlc_deauth_t wdt;
- wdt.val = reason_code;
- os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
- wdt.res = 0x7fff;
- return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
- sizeof(wdt));
- }
- static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
- int reason_code)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
- }
- static int
- wpa_driver_broadcom_associate(void *priv,
- struct wpa_driver_associate_params *params)
- {
- struct wpa_driver_broadcom_data *drv = priv;
- wlc_ssid_t s;
- int infra = 1;
- int auth = 0;
- int wsec = 4;
- int dummy;
- int wpa_auth;
- int ret;
- ret = wpa_driver_broadcom_set_drop_unencrypted(
- drv, params->drop_unencrypted);
- s.SSID_len = params->ssid_len;
- os_memcpy(s.SSID, params->ssid, params->ssid_len);
- switch (params->pairwise_suite) {
- case CIPHER_WEP40:
- case CIPHER_WEP104:
- wsec = 1;
- break;
- case CIPHER_TKIP:
- wsec = 2;
- break;
- case CIPHER_CCMP:
- wsec = 4;
- break;
- default:
- wsec = 0;
- break;
- }
- switch (params->key_mgmt_suite) {
- case KEY_MGMT_802_1X:
- wpa_auth = 1;
- break;
- case KEY_MGMT_PSK:
- wpa_auth = 2;
- break;
- default:
- wpa_auth = 255;
- break;
- }
- /* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
- * group_suite, key_mgmt_suite);
- * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
- * wl join uses wlc_sec_wep here, not wlc_set_wsec */
- if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
- sizeof(wpa_auth)) < 0 ||
- broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
- broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
- return -1;
- return ret;
- }
- const struct wpa_driver_ops wpa_driver_broadcom_ops = {
- .name = "broadcom",
- .desc = "Broadcom wl.o driver",
- .get_bssid = wpa_driver_broadcom_get_bssid,
- .get_ssid = wpa_driver_broadcom_get_ssid,
- .set_key = wpa_driver_broadcom_set_key,
- .init = wpa_driver_broadcom_init,
- .deinit = wpa_driver_broadcom_deinit,
- .set_countermeasures = wpa_driver_broadcom_set_countermeasures,
- .scan2 = wpa_driver_broadcom_scan,
- .get_scan_results2 = wpa_driver_broadcom_get_scan_results,
- .deauthenticate = wpa_driver_broadcom_deauthenticate,
- .disassociate = wpa_driver_broadcom_disassociate,
- .associate = wpa_driver_broadcom_associate,
- };
|