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