00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "includes.h"
00021
00022 #include <sys/ioctl.h>
00023
00024 #include "common.h"
00025
00026 #if 0
00027 #include <netpacket/packet.h>
00028 #include <net/ethernet.h>
00029 #else
00030 #include <linux/if_packet.h>
00031 #include <linux/if_ether.h>
00032 #endif
00033 #include <net/if.h>
00034 #include <typedefs.h>
00035
00036
00037
00038 #include <wlioctl.h>
00039
00040 #include "driver.h"
00041 #include "eloop.h"
00042
00043 struct wpa_driver_broadcom_data {
00044 void *ctx;
00045 int ioctl_sock;
00046 int event_sock;
00047 char ifname[IFNAMSIZ + 1];
00048 };
00049
00050
00051 #ifndef WLC_DEAUTHENTICATE
00052 #define WLC_DEAUTHENTICATE 143
00053 #endif
00054 #ifndef WLC_DEAUTHENTICATE_WITH_REASON
00055 #define WLC_DEAUTHENTICATE_WITH_REASON 201
00056 #endif
00057 #ifndef WLC_SET_TKIP_COUNTERMEASURES
00058 #define WLC_SET_TKIP_COUNTERMEASURES 202
00059 #endif
00060
00061 #if !defined(PSK_ENABLED)
00062 #define WL_VERSION 360130
00063
00064 #define WPA_ENABLED 1
00065 #define PSK_ENABLED 2
00066
00067 #define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
00068 #define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
00069 #define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
00070
00071 #define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
00072
00073 typedef wl_wsec_key_t wsec_key_t;
00074 #endif
00075
00076 typedef struct {
00077 uint32 val;
00078 struct ether_addr ea;
00079 uint16 res;
00080 } wlc_deauth_t;
00081
00082
00083 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
00084 void *timeout_ctx);
00085
00086 static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
00087 void *buf, int len)
00088 {
00089 struct ifreq ifr;
00090 wl_ioctl_t ioc;
00091 int ret = 0;
00092
00093 wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
00094 drv->ifname, cmd, len, buf);
00095
00096
00097 ioc.cmd = cmd;
00098 ioc.buf = buf;
00099 ioc.len = len;
00100 os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
00101 ifr.ifr_data = (caddr_t) &ioc;
00102 if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
00103 if (cmd != WLC_GET_MAGIC)
00104 perror(ifr.ifr_name);
00105 wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
00106 cmd, ret);
00107 }
00108
00109 return ret;
00110 }
00111
00112 static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
00113 {
00114 struct wpa_driver_broadcom_data *drv = priv;
00115 if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
00116 return 0;
00117
00118 os_memset(bssid, 0, ETH_ALEN);
00119 return -1;
00120 }
00121
00122 static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
00123 {
00124 struct wpa_driver_broadcom_data *drv = priv;
00125 wlc_ssid_t s;
00126
00127 if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
00128 return -1;
00129
00130 os_memcpy(ssid, s.SSID, s.SSID_len);
00131 return s.SSID_len;
00132 }
00133
00134 static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
00135 {
00136 struct wpa_driver_broadcom_data *drv = priv;
00137 unsigned int wauth, wsec;
00138 struct ether_addr ea;
00139
00140 os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
00141 if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
00142 -1 ||
00143 broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
00144 return -1;
00145
00146 if (enable) {
00147 wauth = PSK_ENABLED;
00148 wsec = TKIP_ENABLED;
00149 } else {
00150 wauth = 255;
00151 wsec &= ~(TKIP_ENABLED | AES_ENABLED);
00152 }
00153
00154 if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
00155 -1 ||
00156 broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
00157 return -1;
00158
00159
00160 broadcom_ioctl(drv, 122, &ea, sizeof(ea));
00161
00162 return 0;
00163 }
00164
00165 static int wpa_driver_broadcom_set_key(const char *ifname, void *priv,
00166 enum wpa_alg alg,
00167 const u8 *addr, int key_idx, int set_tx,
00168 const u8 *seq, size_t seq_len,
00169 const u8 *key, size_t key_len)
00170 {
00171 struct wpa_driver_broadcom_data *drv = priv;
00172 int ret;
00173 wsec_key_t wkt;
00174
00175 os_memset(&wkt, 0, sizeof wkt);
00176 wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
00177 set_tx ? "PRIMARY " : "", key_idx, alg);
00178 if (key && key_len > 0)
00179 wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
00180
00181 switch (alg) {
00182 case WPA_ALG_NONE:
00183 wkt.algo = CRYPTO_ALGO_OFF;
00184 break;
00185 case WPA_ALG_WEP:
00186 wkt.algo = CRYPTO_ALGO_WEP128;
00187 break;
00188 case WPA_ALG_TKIP:
00189 wkt.algo = 0;
00190 break;
00191 case WPA_ALG_CCMP:
00192 wkt.algo = 0;
00193
00194 break;
00195 default:
00196 wkt.algo = CRYPTO_ALGO_NALG;
00197 break;
00198 }
00199
00200 if (seq && seq_len > 0)
00201 wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
00202
00203 if (addr)
00204 wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
00205
00206 wkt.index = key_idx;
00207 wkt.len = key_len;
00208 if (key && key_len > 0) {
00209 os_memcpy(wkt.data, key, key_len);
00210 if (key_len == 32) {
00211
00212 os_memcpy(&wkt.data[16], &key[24], 8);
00213 os_memcpy(&wkt.data[24], &key[16], 8);
00214 }
00215 }
00216
00217 wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
00218 if (addr && set_tx)
00219 os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
00220 ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
00221 if (addr && set_tx) {
00222
00223 broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
00224 }
00225 return ret;
00226 }
00227
00228
00229 static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
00230 void *sock_ctx)
00231 {
00232 char buf[8192];
00233 int left;
00234 wl_wpa_header_t *wwh;
00235 union wpa_event_data data;
00236 u8 *resp_ies = NULL;
00237
00238 if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
00239 return;
00240
00241 wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
00242
00243 if ((size_t) left < sizeof(wl_wpa_header_t))
00244 return;
00245
00246 wwh = (wl_wpa_header_t *) buf;
00247
00248 if (wwh->snap.type != WL_WPA_ETHER_TYPE)
00249 return;
00250 if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
00251 return;
00252
00253 os_memset(&data, 0, sizeof(data));
00254
00255 switch (wwh->type) {
00256 case WLC_ASSOC_MSG:
00257 left -= WL_WPA_HEADER_LEN;
00258 wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
00259 left);
00260 if (left > 0) {
00261 resp_ies = os_malloc(left);
00262 if (resp_ies == NULL)
00263 return;
00264 os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left);
00265 data.assoc_info.resp_ies = resp_ies;
00266 data.assoc_info.resp_ies_len = left;
00267 }
00268
00269 wpa_supplicant_event(ctx, EVENT_ASSOC, &data);
00270 os_free(resp_ies);
00271 break;
00272 case WLC_DISASSOC_MSG:
00273 wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
00274 wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
00275 break;
00276 case WLC_PTK_MIC_MSG:
00277 wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
00278 data.michael_mic_failure.unicast = 1;
00279 wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
00280 break;
00281 case WLC_GTK_MIC_MSG:
00282 wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
00283 data.michael_mic_failure.unicast = 0;
00284 wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
00285 break;
00286 default:
00287 wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
00288 wwh->type);
00289 break;
00290 }
00291 }
00292
00293 static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
00294 {
00295 int s;
00296 struct sockaddr_ll ll;
00297 struct wpa_driver_broadcom_data *drv;
00298 struct ifreq ifr;
00299
00300
00301 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00302 perror("socket");
00303 return NULL;
00304 }
00305
00306 os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
00307 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
00308 perror(ifr.ifr_name);
00309 return NULL;
00310 }
00311
00312
00313 drv = os_zalloc(sizeof(*drv));
00314 if (drv == NULL)
00315 return NULL;
00316 drv->ctx = ctx;
00317 os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
00318 drv->ioctl_sock = s;
00319
00320 s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
00321 if (s < 0) {
00322 perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
00323 close(drv->ioctl_sock);
00324 os_free(drv);
00325 return NULL;
00326 }
00327
00328 os_memset(&ll, 0, sizeof(ll));
00329 ll.sll_family = AF_PACKET;
00330 ll.sll_protocol = ntohs(ETH_P_802_2);
00331 ll.sll_ifindex = ifr.ifr_ifindex;
00332 ll.sll_hatype = 0;
00333 ll.sll_pkttype = PACKET_HOST;
00334 ll.sll_halen = 0;
00335
00336 if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
00337 perror("bind(netlink)");
00338 close(s);
00339 close(drv->ioctl_sock);
00340 os_free(drv);
00341 return NULL;
00342 }
00343
00344 eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
00345 NULL);
00346 drv->event_sock = s;
00347 wpa_driver_broadcom_set_wpa(drv, 1);
00348
00349 return drv;
00350 }
00351
00352 static void wpa_driver_broadcom_deinit(void *priv)
00353 {
00354 struct wpa_driver_broadcom_data *drv = priv;
00355 wpa_driver_broadcom_set_wpa(drv, 0);
00356 eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
00357 eloop_unregister_read_sock(drv->event_sock);
00358 close(drv->event_sock);
00359 close(drv->ioctl_sock);
00360 os_free(drv);
00361 }
00362
00363 static int wpa_driver_broadcom_set_countermeasures(void *priv,
00364 int enabled)
00365 {
00366 #if 0
00367 struct wpa_driver_broadcom_data *drv = priv;
00368
00369 return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
00370 sizeof(enabled));
00371 #else
00372 return 0;
00373 #endif
00374 }
00375
00376 static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
00377 {
00378 struct wpa_driver_broadcom_data *drv = priv;
00379
00380 int _restrict = (enabled ? 1 : 0);
00381
00382 if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
00383 &_restrict, sizeof(_restrict)) < 0 ||
00384 broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
00385 &_restrict, sizeof(_restrict)) < 0)
00386 return -1;
00387
00388 return 0;
00389 }
00390
00391 static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
00392 void *timeout_ctx)
00393 {
00394 wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
00395 wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
00396 }
00397
00398 static int wpa_driver_broadcom_scan(void *priv,
00399 struct wpa_driver_scan_params *params)
00400 {
00401 struct wpa_driver_broadcom_data *drv = priv;
00402 wlc_ssid_t wst = { 0, "" };
00403 const u8 *ssid = params->ssids[0].ssid;
00404 size_t ssid_len = params->ssids[0].ssid_len;
00405
00406 if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
00407 wst.SSID_len = ssid_len;
00408 os_memcpy(wst.SSID, ssid, ssid_len);
00409 }
00410
00411 if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
00412 return -1;
00413
00414 eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
00415 eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
00416 drv->ctx);
00417 return 0;
00418 }
00419
00420
00421 static const int frequency_list[] = {
00422 2412, 2417, 2422, 2427, 2432, 2437, 2442,
00423 2447, 2452, 2457, 2462, 2467, 2472, 2484
00424 };
00425
00426 struct bss_ie_hdr {
00427 u8 elem_id;
00428 u8 len;
00429 u8 oui[3];
00430
00431
00432 } __attribute__ ((packed));
00433
00434 static struct wpa_scan_results *
00435 wpa_driver_broadcom_get_scan_results(void *priv)
00436 {
00437 struct wpa_driver_broadcom_data *drv = priv;
00438 char *buf;
00439 wl_scan_results_t *wsr;
00440 wl_bss_info_t *wbi;
00441 size_t ap_num;
00442 struct wpa_scan_results *res;
00443
00444 buf = os_malloc(WLC_IOCTL_MAXLEN);
00445 if (buf == NULL)
00446 return NULL;
00447
00448 wsr = (wl_scan_results_t *) buf;
00449
00450 wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
00451 wsr->version = 107;
00452 wsr->count = 0;
00453
00454 if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
00455 os_free(buf);
00456 return NULL;
00457 }
00458
00459 res = os_zalloc(sizeof(*res));
00460 if (res == NULL) {
00461 os_free(buf);
00462 return NULL;
00463 }
00464
00465 res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *));
00466 if (res->res == NULL) {
00467 os_free(res);
00468 os_free(buf);
00469 return NULL;
00470 }
00471
00472 for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
00473 struct wpa_scan_res *r;
00474 r = os_malloc(sizeof(*r) + wbi->ie_length);
00475 if (r == NULL)
00476 break;
00477 res->res[res->num++] = r;
00478
00479 os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN);
00480 r->freq = frequency_list[wbi->channel - 1];
00481
00482 os_memcpy(r + 1, wbi + 1, wbi->ie_length);
00483 r->ie_len = wbi->ie_length;
00484
00485 wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
00486 }
00487
00488 wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
00489 "BSSes)",
00490 wsr->buflen, (unsigned long) ap_num);
00491
00492 os_free(buf);
00493 return res;
00494 }
00495
00496 static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
00497 int reason_code)
00498 {
00499 struct wpa_driver_broadcom_data *drv = priv;
00500 wlc_deauth_t wdt;
00501 wdt.val = reason_code;
00502 os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
00503 wdt.res = 0x7fff;
00504 return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
00505 sizeof(wdt));
00506 }
00507
00508 static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
00509 int reason_code)
00510 {
00511 struct wpa_driver_broadcom_data *drv = priv;
00512 return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
00513 }
00514
00515 static int
00516 wpa_driver_broadcom_associate(void *priv,
00517 struct wpa_driver_associate_params *params)
00518 {
00519 struct wpa_driver_broadcom_data *drv = priv;
00520 wlc_ssid_t s;
00521 int infra = 1;
00522 int auth = 0;
00523 int wsec = 4;
00524 int dummy;
00525 int wpa_auth;
00526 int ret;
00527
00528 ret = wpa_driver_broadcom_set_drop_unencrypted(
00529 drv, params->drop_unencrypted);
00530
00531 s.SSID_len = params->ssid_len;
00532 os_memcpy(s.SSID, params->ssid, params->ssid_len);
00533
00534 switch (params->pairwise_suite) {
00535 case CIPHER_WEP40:
00536 case CIPHER_WEP104:
00537 wsec = 1;
00538 break;
00539
00540 case CIPHER_TKIP:
00541 wsec = 2;
00542 break;
00543
00544 case CIPHER_CCMP:
00545 wsec = 4;
00546 break;
00547
00548 default:
00549 wsec = 0;
00550 break;
00551 }
00552
00553 switch (params->key_mgmt_suite) {
00554 case KEY_MGMT_802_1X:
00555 wpa_auth = 1;
00556 break;
00557
00558 case KEY_MGMT_PSK:
00559 wpa_auth = 2;
00560 break;
00561
00562 default:
00563 wpa_auth = 255;
00564 break;
00565 }
00566
00567
00568
00569
00570
00571
00572 if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
00573 broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
00574 sizeof(wpa_auth)) < 0 ||
00575 broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
00576 broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
00577 broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
00578 broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
00579 broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
00580 return -1;
00581
00582 return ret;
00583 }
00584
00585 const struct wpa_driver_ops wpa_driver_broadcom_ops = {
00586 .name = "broadcom",
00587 .desc = "Broadcom wl.o driver",
00588 .get_bssid = wpa_driver_broadcom_get_bssid,
00589 .get_ssid = wpa_driver_broadcom_get_ssid,
00590 .set_key = wpa_driver_broadcom_set_key,
00591 .init = wpa_driver_broadcom_init,
00592 .deinit = wpa_driver_broadcom_deinit,
00593 .set_countermeasures = wpa_driver_broadcom_set_countermeasures,
00594 .scan2 = wpa_driver_broadcom_scan,
00595 .get_scan_results2 = wpa_driver_broadcom_get_scan_results,
00596 .deauthenticate = wpa_driver_broadcom_deauthenticate,
00597 .disassociate = wpa_driver_broadcom_disassociate,
00598 .associate = wpa_driver_broadcom_associate,
00599 };