Home | History | Annotate | Download | only in drivers
      1 /*
      2  * WPA Supplicant - driver interaction with old Broadcom wl.o driver
      3  * Copyright (c) 2004, Nikki Chumkov <nikki (at) gattaca.ru>
      4  * Copyright (c) 2004, Jouni Malinen <j (at) w1.fi>
      5  *
      6  * This program is free software; you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License version 2 as
      8  * published by the Free Software Foundation.
      9  *
     10  * Alternatively, this software may be distributed under the terms of BSD
     11  * license.
     12  *
     13  * See README and COPYING for more details.
     14  *
     15  * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
     16  * Linux wireless extensions and does not need (or even work) with this old
     17  * driver wrapper. Use driver_wext.c with that driver.
     18  */
     19 
     20 #include "includes.h"
     21 
     22 #include <sys/ioctl.h>
     23 
     24 #include "common.h"
     25 
     26 #if 0
     27 #include <netpacket/packet.h>
     28 #include <net/ethernet.h>     /* the L2 protocols */
     29 #else
     30 #include <linux/if_packet.h>
     31 #include <linux/if_ether.h>   /* The L2 protocols */
     32 #endif
     33 #include <net/if.h>
     34 #include <typedefs.h>
     35 
     36 /* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
     37  * WRT54G GPL tarball. */
     38 #include <wlioctl.h>
     39 
     40 #include "driver.h"
     41 #include "eloop.h"
     42 
     43 struct wpa_driver_broadcom_data {
     44 	void *ctx;
     45 	int ioctl_sock;
     46 	int event_sock;
     47 	char ifname[IFNAMSIZ + 1];
     48 };
     49 
     50 
     51 #ifndef WLC_DEAUTHENTICATE
     52 #define WLC_DEAUTHENTICATE 143
     53 #endif
     54 #ifndef WLC_DEAUTHENTICATE_WITH_REASON
     55 #define WLC_DEAUTHENTICATE_WITH_REASON 201
     56 #endif
     57 #ifndef WLC_SET_TKIP_COUNTERMEASURES
     58 #define WLC_SET_TKIP_COUNTERMEASURES 202
     59 #endif
     60 
     61 #if !defined(PSK_ENABLED) /* NEW driver interface */
     62 #define WL_VERSION 360130
     63 /* wireless authentication bit vector */
     64 #define WPA_ENABLED 1
     65 #define PSK_ENABLED 2
     66 
     67 #define WAUTH_WPA_ENABLED(wauth)  ((wauth) & WPA_ENABLED)
     68 #define WAUTH_PSK_ENABLED(wauth)  ((wauth) & PSK_ENABLED)
     69 #define WAUTH_ENABLED(wauth)    ((wauth) & (WPA_ENABLED | PSK_ENABLED))
     70 
     71 #define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
     72 
     73 typedef wl_wsec_key_t wsec_key_t;
     74 #endif
     75 
     76 typedef struct {
     77 	uint32 val;
     78 	struct ether_addr ea;
     79 	uint16 res;
     80 } wlc_deauth_t;
     81 
     82 
     83 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
     84 					     void *timeout_ctx);
     85 
     86 static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
     87 			  void *buf, int len)
     88 {
     89 	struct ifreq ifr;
     90 	wl_ioctl_t ioc;
     91 	int ret = 0;
     92 
     93 	wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
     94 		   drv->ifname, cmd, len, buf);
     95 	/* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
     96 
     97 	ioc.cmd = cmd;
     98 	ioc.buf = buf;
     99 	ioc.len = len;
    100 	os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
    101 	ifr.ifr_data = (caddr_t) &ioc;
    102 	if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
    103 		if (cmd != WLC_GET_MAGIC)
    104 			perror(ifr.ifr_name);
    105 		wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
    106 			   cmd, ret);
    107 	}
    108 
    109 	return ret;
    110 }
    111 
    112 static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
    113 {
    114 	struct wpa_driver_broadcom_data *drv = priv;
    115 	if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
    116 		return 0;
    117 
    118 	os_memset(bssid, 0, ETH_ALEN);
    119 	return -1;
    120 }
    121 
    122 static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
    123 {
    124 	struct wpa_driver_broadcom_data *drv = priv;
    125 	wlc_ssid_t s;
    126 
    127 	if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
    128 		return -1;
    129 
    130 	os_memcpy(ssid, s.SSID, s.SSID_len);
    131 	return s.SSID_len;
    132 }
    133 
    134 static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
    135 {
    136 	struct wpa_driver_broadcom_data *drv = priv;
    137 	unsigned int wauth, wsec;
    138 	struct ether_addr ea;
    139 
    140 	os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
    141 	if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
    142 	    -1 ||
    143 	    broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
    144 		return -1;
    145 
    146 	if (enable) {
    147 		wauth = PSK_ENABLED;
    148 		wsec = TKIP_ENABLED;
    149 	} else {
    150 		wauth = 255;
    151 		wsec &= ~(TKIP_ENABLED | AES_ENABLED);
    152 	}
    153 
    154 	if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
    155 	    -1 ||
    156 	    broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
    157 		return -1;
    158 
    159 	/* FIX: magic number / error handling? */
    160 	broadcom_ioctl(drv, 122, &ea, sizeof(ea));
    161 
    162 	return 0;
    163 }
    164 
    165 static int wpa_driver_broadcom_set_key(void *priv, wpa_alg alg,
    166 				       const u8 *addr, int key_idx, int set_tx,
    167 				       const u8 *seq, size_t seq_len,
    168 				       const u8 *key, size_t key_len)
    169 {
    170 	struct wpa_driver_broadcom_data *drv = priv;
    171 	int ret;
    172 	wsec_key_t wkt;
    173 
    174 	os_memset(&wkt, 0, sizeof wkt);
    175 	wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
    176 		   set_tx ? "PRIMARY " : "", key_idx, alg);
    177 	if (key && key_len > 0)
    178 		wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
    179 
    180 	switch (alg) {
    181 	case WPA_ALG_NONE:
    182 		wkt.algo = CRYPTO_ALGO_OFF;
    183 		break;
    184 	case WPA_ALG_WEP:
    185 		wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
    186 		break;
    187 	case WPA_ALG_TKIP:
    188 		wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
    189 		break;
    190 	case WPA_ALG_CCMP:
    191 		wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
    192 			       * AES_OCB_MSDU, AES_OCB_MPDU? */
    193 		break;
    194 	default:
    195 		wkt.algo = CRYPTO_ALGO_NALG;
    196 		break;
    197 	}
    198 
    199 	if (seq && seq_len > 0)
    200 		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
    201 
    202 	if (addr)
    203 		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
    204 
    205 	wkt.index = key_idx;
    206 	wkt.len = key_len;
    207 	if (key && key_len > 0) {
    208 		os_memcpy(wkt.data, key, key_len);
    209 		if (key_len == 32) {
    210 			/* hack hack hack XXX */
    211 			os_memcpy(&wkt.data[16], &key[24], 8);
    212 			os_memcpy(&wkt.data[24], &key[16], 8);
    213 		}
    214 	}
    215 	/* wkt.algo = CRYPTO_ALGO_...; */
    216 	wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
    217 	if (addr && set_tx)
    218 		os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
    219 	ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
    220 	if (addr && set_tx) {
    221 		/* FIX: magic number / error handling? */
    222 		broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
    223 	}
    224 	return ret;
    225 }
    226 
    227 
    228 static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
    229 					      void *sock_ctx)
    230 {
    231 	char buf[8192];
    232 	int left;
    233 	wl_wpa_header_t *wwh;
    234 	union wpa_event_data data;
    235 
    236 	if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
    237 		return;
    238 
    239 	wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
    240 
    241 	if ((size_t) left < sizeof(wl_wpa_header_t))
    242 		return;
    243 
    244 	wwh = (wl_wpa_header_t *) buf;
    245 
    246 	if (wwh->snap.type != WL_WPA_ETHER_TYPE)
    247 		return;
    248 	if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
    249 		return;
    250 
    251 	os_memset(&data, 0, sizeof(data));
    252 
    253 	switch (wwh->type) {
    254 	case WLC_ASSOC_MSG:
    255 		left -= WL_WPA_HEADER_LEN;
    256 		wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
    257 			   left);
    258 		if (left > 0) {
    259 			data.assoc_info.resp_ies = os_malloc(left);
    260 			if (data.assoc_info.resp_ies == NULL)
    261 				return;
    262 			os_memcpy(data.assoc_info.resp_ies,
    263 				  buf + WL_WPA_HEADER_LEN, left);
    264 			data.assoc_info.resp_ies_len = left;
    265 			wpa_hexdump(MSG_MSGDUMP, "BROADCOM: copying %d bytes "
    266 				    "into resp_ies",
    267 				    data.assoc_info.resp_ies, left);
    268 		}
    269 		/* data.assoc_info.req_ies = NULL; */
    270 		/* data.assoc_info.req_ies_len = 0; */
    271 
    272 		wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
    273 		wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
    274 		break;
    275 	case WLC_DISASSOC_MSG:
    276 		wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
    277 		wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
    278 		break;
    279 	case WLC_PTK_MIC_MSG:
    280 		wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
    281 		data.michael_mic_failure.unicast = 1;
    282 		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
    283 		break;
    284 	case WLC_GTK_MIC_MSG:
    285 		wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
    286 		data.michael_mic_failure.unicast = 0;
    287 		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
    288 		break;
    289 	default:
    290 		wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
    291 			   wwh->type);
    292 		break;
    293 	}
    294 	os_free(data.assoc_info.resp_ies);
    295 }
    296 
    297 static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
    298 {
    299 	int s;
    300 	struct sockaddr_ll ll;
    301 	struct wpa_driver_broadcom_data *drv;
    302 	struct ifreq ifr;
    303 
    304 	/* open socket to kernel */
    305 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    306 		perror("socket");
    307 		return NULL;
    308 	}
    309 	/* do it */
    310 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
    311 	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
    312 		perror(ifr.ifr_name);
    313 		return NULL;
    314 	}
    315 
    316 
    317 	drv = os_zalloc(sizeof(*drv));
    318 	if (drv == NULL)
    319 		return NULL;
    320 	drv->ctx = ctx;
    321 	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
    322 	drv->ioctl_sock = s;
    323 
    324 	s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
    325 	if (s < 0) {
    326 		perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
    327 		close(drv->ioctl_sock);
    328 		os_free(drv);
    329 		return NULL;
    330 	}
    331 
    332 	os_memset(&ll, 0, sizeof(ll));
    333 	ll.sll_family = AF_PACKET;
    334 	ll.sll_protocol = ntohs(ETH_P_802_2);
    335 	ll.sll_ifindex = ifr.ifr_ifindex;
    336 	ll.sll_hatype = 0;
    337 	ll.sll_pkttype = PACKET_HOST;
    338 	ll.sll_halen = 0;
    339 
    340 	if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
    341 		perror("bind(netlink)");
    342 		close(s);
    343 		close(drv->ioctl_sock);
    344 		os_free(drv);
    345 		return NULL;
    346 	}
    347 
    348 	eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
    349 				 NULL);
    350 	drv->event_sock = s;
    351 
    352 	return drv;
    353 }
    354 
    355 static void wpa_driver_broadcom_deinit(void *priv)
    356 {
    357 	struct wpa_driver_broadcom_data *drv = priv;
    358 	eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
    359 	eloop_unregister_read_sock(drv->event_sock);
    360 	close(drv->event_sock);
    361 	close(drv->ioctl_sock);
    362 	os_free(drv);
    363 }
    364 
    365 static int wpa_driver_broadcom_set_countermeasures(void *priv,
    366 						   int enabled)
    367 {
    368 #if 0
    369 	struct wpa_driver_broadcom_data *drv = priv;
    370 	/* FIX: ? */
    371 	return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
    372 			      sizeof(enabled));
    373 #else
    374 	return 0;
    375 #endif
    376 }
    377 
    378 static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
    379 {
    380 	struct wpa_driver_broadcom_data *drv = priv;
    381 	/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
    382 	int restrict = (enabled ? 1 : 0);
    383 
    384 	if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
    385 			   &restrict, sizeof(restrict)) < 0 ||
    386 	    broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
    387 			   &restrict, sizeof(restrict)) < 0)
    388 		return -1;
    389 
    390 	return 0;
    391 }
    392 
    393 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
    394 					     void *timeout_ctx)
    395 {
    396 	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
    397 	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
    398 }
    399 
    400 static int wpa_driver_broadcom_scan(void *priv, const u8 *ssid,
    401 				    size_t ssid_len)
    402 {
    403 	struct wpa_driver_broadcom_data *drv = priv;
    404 	wlc_ssid_t wst = { 0, "" };
    405 
    406 	if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
    407 		wst.SSID_len = ssid_len;
    408 		os_memcpy(wst.SSID, ssid, ssid_len);
    409 	}
    410 
    411 	if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
    412 		return -1;
    413 
    414 	eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
    415 	eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
    416 			       drv->ctx);
    417 	return 0;
    418 }
    419 
    420 
    421 static const int frequency_list[] = {
    422 	2412, 2417, 2422, 2427, 2432, 2437, 2442,
    423 	2447, 2452, 2457, 2462, 2467, 2472, 2484
    424 };
    425 
    426 struct bss_ie_hdr {
    427 	u8 elem_id;
    428 	u8 len;
    429 	u8 oui[3];
    430 	/* u8 oui_type; */
    431 	/* u16 version; */
    432 } __attribute__ ((packed));
    433 
    434 static int
    435 wpa_driver_broadcom_get_scan_results(void *priv,
    436 				     struct wpa_scan_result *results,
    437 				     size_t max_size)
    438 {
    439 	struct wpa_driver_broadcom_data *drv = priv;
    440 	char *buf;
    441 	wl_scan_results_t *wsr;
    442 	wl_bss_info_t *wbi;
    443 	size_t ap_num;
    444 
    445 	buf = os_malloc(WLC_IOCTL_MAXLEN);
    446 	if (buf == NULL)
    447 		return -1;
    448 
    449 	wsr = (wl_scan_results_t *) buf;
    450 
    451 	wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
    452 	wsr->version = 107;
    453 	wsr->count = 0;
    454 
    455 	if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
    456 		os_free(buf);
    457 		return -1;
    458 	}
    459 
    460 	os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
    461 
    462 	for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
    463 		int left;
    464 		struct bss_ie_hdr *ie;
    465 
    466 		os_memcpy(results[ap_num].bssid, &wbi->BSSID, ETH_ALEN);
    467 		os_memcpy(results[ap_num].ssid, wbi->SSID, wbi->SSID_len);
    468 		results[ap_num].ssid_len = wbi->SSID_len;
    469 		results[ap_num].freq = frequency_list[wbi->channel - 1];
    470 		/* get ie's */
    471 		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: AP IEs",
    472 			    (u8 *) wbi + sizeof(*wbi), wbi->ie_length);
    473 		ie = (struct bss_ie_hdr *) ((u8 *) wbi + sizeof(*wbi));
    474 		for (left = wbi->ie_length; left > 0;
    475 		     left -= (ie->len + 2), ie = (struct bss_ie_hdr *)
    476 			     ((u8 *) ie + 2 + ie->len)) {
    477 			wpa_printf(MSG_MSGDUMP, "BROADCOM: IE: id:%x, len:%d",
    478 				   ie->elem_id, ie->len);
    479 			if (ie->len >= 3)
    480 				wpa_printf(MSG_MSGDUMP,
    481 					   "BROADCOM: oui:%02x%02x%02x",
    482 					   ie->oui[0], ie->oui[1], ie->oui[2]);
    483 			if (ie->elem_id != 0xdd ||
    484 			    ie->len < 6 ||
    485 			    os_memcmp(ie->oui, WPA_OUI, 3) != 0)
    486 				continue;
    487 			os_memcpy(results[ap_num].wpa_ie, ie, ie->len + 2);
    488 			results[ap_num].wpa_ie_len = ie->len + 2;
    489 			break;
    490 		}
    491 
    492 		wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
    493 	}
    494 
    495 	wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
    496 		   "BSSes)",
    497 		   wsr->buflen, (unsigned long) ap_num);
    498 
    499 	os_free(buf);
    500 	return ap_num;
    501 }
    502 
    503 static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
    504 					      int reason_code)
    505 {
    506 	struct wpa_driver_broadcom_data *drv = priv;
    507 	wlc_deauth_t wdt;
    508 	wdt.val = reason_code;
    509 	os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
    510 	wdt.res = 0x7fff;
    511 	return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
    512 			      sizeof(wdt));
    513 }
    514 
    515 static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
    516 					    int reason_code)
    517 {
    518 	struct wpa_driver_broadcom_data *drv = priv;
    519 	return broadcom_ioctl(drv, WLC_DISASSOC, 0, 0);
    520 }
    521 
    522 static int
    523 wpa_driver_broadcom_associate(void *priv,
    524 			      struct wpa_driver_associate_params *params)
    525 {
    526 	struct wpa_driver_broadcom_data *drv = priv;
    527 	wlc_ssid_t s;
    528 	int infra = 1;
    529 	int auth = 0;
    530 	int wsec = 4;
    531 	int dummy;
    532 	int wpa_auth;
    533 
    534 	s.SSID_len = params->ssid_len;
    535 	os_memcpy(s.SSID, params->ssid, params->ssid_len);
    536 
    537 	switch (params->pairwise_suite) {
    538 	case CIPHER_WEP40:
    539 	case CIPHER_WEP104:
    540 		wsec = 1;
    541 		break;
    542 
    543 	case CIPHER_TKIP:
    544 		wsec = 2;
    545 		break;
    546 
    547 	case CIPHER_CCMP:
    548 		wsec = 4;
    549 		break;
    550 
    551 	default:
    552 		wsec = 0;
    553 		break;
    554 	}
    555 
    556 	switch (params->key_mgmt_suite) {
    557 	case KEY_MGMT_802_1X:
    558 		wpa_auth = 1;
    559 		break;
    560 
    561 	case KEY_MGMT_PSK:
    562 		wpa_auth = 2;
    563 		break;
    564 
    565 	default:
    566 		wpa_auth = 255;
    567 		break;
    568 	}
    569 
    570 	/* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
    571 	 * group_suite, key_mgmt_suite);
    572 	 * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
    573 	 * wl join uses wlc_sec_wep here, not wlc_set_wsec */
    574 
    575 	if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
    576 	    broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
    577 			   sizeof(wpa_auth)) < 0 ||
    578 	    broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
    579 	    broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
    580 	    broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
    581 	    broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
    582 	    broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
    583 		return -1;
    584 
    585 	return 0;
    586 }
    587 
    588 const struct wpa_driver_ops wpa_driver_broadcom_ops = {
    589 	.name = "broadcom",
    590 	.desc = "Broadcom wl.o driver",
    591 	.get_bssid = wpa_driver_broadcom_get_bssid,
    592 	.get_ssid = wpa_driver_broadcom_get_ssid,
    593 	.set_wpa = wpa_driver_broadcom_set_wpa,
    594 	.set_key = wpa_driver_broadcom_set_key,
    595 	.init = wpa_driver_broadcom_init,
    596 	.deinit = wpa_driver_broadcom_deinit,
    597 	.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
    598 	.set_drop_unencrypted = wpa_driver_broadcom_set_drop_unencrypted,
    599 	.scan = wpa_driver_broadcom_scan,
    600 	.get_scan_results = wpa_driver_broadcom_get_scan_results,
    601 	.deauthenticate = wpa_driver_broadcom_deauthenticate,
    602 	.disassociate = wpa_driver_broadcom_disassociate,
    603 	.associate = wpa_driver_broadcom_associate,
    604 };
    605