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(const char *ifname, void *priv,
    166 				       enum wpa_alg alg,
    167 				       const u8 *addr, int key_idx, int set_tx,
    168 				       const u8 *seq, size_t seq_len,
    169 				       const u8 *key, size_t key_len)
    170 {
    171 	struct wpa_driver_broadcom_data *drv = priv;
    172 	int ret;
    173 	wsec_key_t wkt;
    174 
    175 	os_memset(&wkt, 0, sizeof wkt);
    176 	wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
    177 		   set_tx ? "PRIMARY " : "", key_idx, alg);
    178 	if (key && key_len > 0)
    179 		wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
    180 
    181 	switch (alg) {
    182 	case WPA_ALG_NONE:
    183 		wkt.algo = CRYPTO_ALGO_OFF;
    184 		break;
    185 	case WPA_ALG_WEP:
    186 		wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
    187 		break;
    188 	case WPA_ALG_TKIP:
    189 		wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
    190 		break;
    191 	case WPA_ALG_CCMP:
    192 		wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
    193 			       * AES_OCB_MSDU, AES_OCB_MPDU? */
    194 		break;
    195 	default:
    196 		wkt.algo = CRYPTO_ALGO_NALG;
    197 		break;
    198 	}
    199 
    200 	if (seq && seq_len > 0)
    201 		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
    202 
    203 	if (addr)
    204 		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
    205 
    206 	wkt.index = key_idx;
    207 	wkt.len = key_len;
    208 	if (key && key_len > 0) {
    209 		os_memcpy(wkt.data, key, key_len);
    210 		if (key_len == 32) {
    211 			/* hack hack hack XXX */
    212 			os_memcpy(&wkt.data[16], &key[24], 8);
    213 			os_memcpy(&wkt.data[24], &key[16], 8);
    214 		}
    215 	}
    216 	/* wkt.algo = CRYPTO_ALGO_...; */
    217 	wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
    218 	if (addr && set_tx)
    219 		os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
    220 	ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
    221 	if (addr && set_tx) {
    222 		/* FIX: magic number / error handling? */
    223 		broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
    224 	}
    225 	return ret;
    226 }
    227 
    228 
    229 static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
    230 					      void *sock_ctx)
    231 {
    232 	char buf[8192];
    233 	int left;
    234 	wl_wpa_header_t *wwh;
    235 	union wpa_event_data data;
    236 	u8 *resp_ies = NULL;
    237 
    238 	if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
    239 		return;
    240 
    241 	wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
    242 
    243 	if ((size_t) left < sizeof(wl_wpa_header_t))
    244 		return;
    245 
    246 	wwh = (wl_wpa_header_t *) buf;
    247 
    248 	if (wwh->snap.type != WL_WPA_ETHER_TYPE)
    249 		return;
    250 	if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
    251 		return;
    252 
    253 	os_memset(&data, 0, sizeof(data));
    254 
    255 	switch (wwh->type) {
    256 	case WLC_ASSOC_MSG:
    257 		left -= WL_WPA_HEADER_LEN;
    258 		wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
    259 			   left);
    260 		if (left > 0) {
    261 			resp_ies = os_malloc(left);
    262 			if (resp_ies == NULL)
    263 				return;
    264 			os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left);
    265 			data.assoc_info.resp_ies = resp_ies;
    266 			data.assoc_info.resp_ies_len = left;
    267 		}
    268 
    269 		wpa_supplicant_event(ctx, EVENT_ASSOC, &data);
    270 		os_free(resp_ies);
    271 		break;
    272 	case WLC_DISASSOC_MSG:
    273 		wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
    274 		wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
    275 		break;
    276 	case WLC_PTK_MIC_MSG:
    277 		wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
    278 		data.michael_mic_failure.unicast = 1;
    279 		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
    280 		break;
    281 	case WLC_GTK_MIC_MSG:
    282 		wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
    283 		data.michael_mic_failure.unicast = 0;
    284 		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
    285 		break;
    286 	default:
    287 		wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
    288 			   wwh->type);
    289 		break;
    290 	}
    291 }
    292 
    293 static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
    294 {
    295 	int s;
    296 	struct sockaddr_ll ll;
    297 	struct wpa_driver_broadcom_data *drv;
    298 	struct ifreq ifr;
    299 
    300 	/* open socket to kernel */
    301 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    302 		perror("socket");
    303 		return NULL;
    304 	}
    305 	/* do it */
    306 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
    307 	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
    308 		perror(ifr.ifr_name);
    309 		return NULL;
    310 	}
    311 
    312 
    313 	drv = os_zalloc(sizeof(*drv));
    314 	if (drv == NULL)
    315 		return NULL;
    316 	drv->ctx = ctx;
    317 	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
    318 	drv->ioctl_sock = s;
    319 
    320 	s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
    321 	if (s < 0) {
    322 		perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
    323 		close(drv->ioctl_sock);
    324 		os_free(drv);
    325 		return NULL;
    326 	}
    327 
    328 	os_memset(&ll, 0, sizeof(ll));
    329 	ll.sll_family = AF_PACKET;
    330 	ll.sll_protocol = ntohs(ETH_P_802_2);
    331 	ll.sll_ifindex = ifr.ifr_ifindex;
    332 	ll.sll_hatype = 0;
    333 	ll.sll_pkttype = PACKET_HOST;
    334 	ll.sll_halen = 0;
    335 
    336 	if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
    337 		perror("bind(netlink)");
    338 		close(s);
    339 		close(drv->ioctl_sock);
    340 		os_free(drv);
    341 		return NULL;
    342 	}
    343 
    344 	eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
    345 				 NULL);
    346 	drv->event_sock = s;
    347 	wpa_driver_broadcom_set_wpa(drv, 1);
    348 
    349 	return drv;
    350 }
    351 
    352 static void wpa_driver_broadcom_deinit(void *priv)
    353 {
    354 	struct wpa_driver_broadcom_data *drv = priv;
    355 	wpa_driver_broadcom_set_wpa(drv, 0);
    356 	eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
    357 	eloop_unregister_read_sock(drv->event_sock);
    358 	close(drv->event_sock);
    359 	close(drv->ioctl_sock);
    360 	os_free(drv);
    361 }
    362 
    363 static int wpa_driver_broadcom_set_countermeasures(void *priv,
    364 						   int enabled)
    365 {
    366 #if 0
    367 	struct wpa_driver_broadcom_data *drv = priv;
    368 	/* FIX: ? */
    369 	return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
    370 			      sizeof(enabled));
    371 #else
    372 	return 0;
    373 #endif
    374 }
    375 
    376 static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
    377 {
    378 	struct wpa_driver_broadcom_data *drv = priv;
    379 	/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
    380 	int _restrict = (enabled ? 1 : 0);
    381 
    382 	if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
    383 			   &_restrict, sizeof(_restrict)) < 0 ||
    384 	    broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
    385 			   &_restrict, sizeof(_restrict)) < 0)
    386 		return -1;
    387 
    388 	return 0;
    389 }
    390 
    391 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
    392 					     void *timeout_ctx)
    393 {
    394 	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
    395 	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
    396 }
    397 
    398 static int wpa_driver_broadcom_scan(void *priv,
    399 				    struct wpa_driver_scan_params *params)
    400 {
    401 	struct wpa_driver_broadcom_data *drv = priv;
    402 	wlc_ssid_t wst = { 0, "" };
    403 	const u8 *ssid = params->ssids[0].ssid;
    404 	size_t ssid_len = params->ssids[0].ssid_len;
    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 struct wpa_scan_results *
    435 wpa_driver_broadcom_get_scan_results(void *priv)
    436 {
    437 	struct wpa_driver_broadcom_data *drv = priv;
    438 	char *buf;
    439 	wl_scan_results_t *wsr;
    440 	wl_bss_info_t *wbi;
    441 	size_t ap_num;
    442 	struct wpa_scan_results *res;
    443 
    444 	buf = os_malloc(WLC_IOCTL_MAXLEN);
    445 	if (buf == NULL)
    446 		return NULL;
    447 
    448 	wsr = (wl_scan_results_t *) buf;
    449 
    450 	wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
    451 	wsr->version = 107;
    452 	wsr->count = 0;
    453 
    454 	if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
    455 		os_free(buf);
    456 		return NULL;
    457 	}
    458 
    459 	res = os_zalloc(sizeof(*res));
    460 	if (res == NULL) {
    461 		os_free(buf);
    462 		return NULL;
    463 	}
    464 
    465 	res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *));
    466 	if (res->res == NULL) {
    467 		os_free(res);
    468 		os_free(buf);
    469 		return NULL;
    470 	}
    471 
    472 	for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
    473 		struct wpa_scan_res *r;
    474 		r = os_malloc(sizeof(*r) + wbi->ie_length);
    475 		if (r == NULL)
    476 			break;
    477 		res->res[res->num++] = r;
    478 
    479 		os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN);
    480 		r->freq = frequency_list[wbi->channel - 1];
    481 		/* get ie's */
    482 		os_memcpy(r + 1, wbi + 1, wbi->ie_length);
    483 		r->ie_len = wbi->ie_length;
    484 
    485 		wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
    486 	}
    487 
    488 	wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
    489 		   "BSSes)",
    490 		   wsr->buflen, (unsigned long) ap_num);
    491 
    492 	os_free(buf);
    493 	return res;
    494 	}
    495 
    496 static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
    497 					      int reason_code)
    498 {
    499 	struct wpa_driver_broadcom_data *drv = priv;
    500 	wlc_deauth_t wdt;
    501 	wdt.val = reason_code;
    502 	os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
    503 	wdt.res = 0x7fff;
    504 	return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
    505 			      sizeof(wdt));
    506 }
    507 
    508 static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
    509 					    int reason_code)
    510 {
    511 	struct wpa_driver_broadcom_data *drv = priv;
    512 	return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
    513 }
    514 
    515 static int
    516 wpa_driver_broadcom_associate(void *priv,
    517 			      struct wpa_driver_associate_params *params)
    518 {
    519 	struct wpa_driver_broadcom_data *drv = priv;
    520 	wlc_ssid_t s;
    521 	int infra = 1;
    522 	int auth = 0;
    523 	int wsec = 4;
    524 	int dummy;
    525 	int wpa_auth;
    526 	int ret;
    527 
    528 	ret = wpa_driver_broadcom_set_drop_unencrypted(
    529 		drv, params->drop_unencrypted);
    530 
    531 	s.SSID_len = params->ssid_len;
    532 	os_memcpy(s.SSID, params->ssid, params->ssid_len);
    533 
    534 	switch (params->pairwise_suite) {
    535 	case CIPHER_WEP40:
    536 	case CIPHER_WEP104:
    537 		wsec = 1;
    538 		break;
    539 
    540 	case CIPHER_TKIP:
    541 		wsec = 2;
    542 		break;
    543 
    544 	case CIPHER_CCMP:
    545 		wsec = 4;
    546 		break;
    547 
    548 	default:
    549 		wsec = 0;
    550 		break;
    551 	}
    552 
    553 	switch (params->key_mgmt_suite) {
    554 	case KEY_MGMT_802_1X:
    555 		wpa_auth = 1;
    556 		break;
    557 
    558 	case KEY_MGMT_PSK:
    559 		wpa_auth = 2;
    560 		break;
    561 
    562 	default:
    563 		wpa_auth = 255;
    564 		break;
    565 	}
    566 
    567 	/* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
    568 	 * group_suite, key_mgmt_suite);
    569 	 * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
    570 	 * wl join uses wlc_sec_wep here, not wlc_set_wsec */
    571 
    572 	if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
    573 	    broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
    574 			   sizeof(wpa_auth)) < 0 ||
    575 	    broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
    576 	    broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
    577 	    broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
    578 	    broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
    579 	    broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
    580 		return -1;
    581 
    582 	return ret;
    583 }
    584 
    585 const struct wpa_driver_ops wpa_driver_broadcom_ops = {
    586 	.name = "broadcom",
    587 	.desc = "Broadcom wl.o driver",
    588 	.get_bssid = wpa_driver_broadcom_get_bssid,
    589 	.get_ssid = wpa_driver_broadcom_get_ssid,
    590 	.set_key = wpa_driver_broadcom_set_key,
    591 	.init = wpa_driver_broadcom_init,
    592 	.deinit = wpa_driver_broadcom_deinit,
    593 	.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
    594 	.scan2 = wpa_driver_broadcom_scan,
    595 	.get_scan_results2 = wpa_driver_broadcom_get_scan_results,
    596 	.deauthenticate = wpa_driver_broadcom_deauthenticate,
    597 	.disassociate = wpa_driver_broadcom_disassociate,
    598 	.associate = wpa_driver_broadcom_associate,
    599 };
    600