2 * WPA Supplicant - driver interaction with Linux Host AP driver
3 * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
16 #include <sys/ioctl.h>
18 #include "wireless_copy.h"
21 #include "driver_wext.h"
23 #include "driver_hostap.h"
26 struct wpa_driver_hostap_data
{
27 void *wext
; /* private data for driver_wext */
29 char ifname
[IFNAMSIZ
+ 1];
31 int current_mode
; /* infra/adhoc */
35 static int hostapd_ioctl(struct wpa_driver_hostap_data
*drv
,
36 struct prism2_hostapd_param
*param
,
37 int len
, int show_err
)
41 os_memset(&iwr
, 0, sizeof(iwr
));
42 os_strlcpy(iwr
.ifr_name
, drv
->ifname
, IFNAMSIZ
);
43 iwr
.u
.data
.pointer
= (caddr_t
) param
;
44 iwr
.u
.data
.length
= len
;
46 if (ioctl(drv
->sock
, PRISM2_IOCTL_HOSTAPD
, &iwr
) < 0) {
49 perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
57 static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data
*drv
,
58 const u8
*wpa_ie
, size_t wpa_ie_len
)
60 struct prism2_hostapd_param
*param
;
62 size_t blen
= PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN
+ wpa_ie_len
;
63 if (blen
< sizeof(*param
))
64 blen
= sizeof(*param
);
66 param
= os_zalloc(blen
);
70 param
->cmd
= PRISM2_HOSTAPD_SET_GENERIC_ELEMENT
;
71 param
->u
.generic_elem
.len
= wpa_ie_len
;
72 os_memcpy(param
->u
.generic_elem
.data
, wpa_ie
, wpa_ie_len
);
73 res
= hostapd_ioctl(drv
, param
, blen
, 1);
81 static int prism2param(struct wpa_driver_hostap_data
*drv
, int param
,
87 os_memset(&iwr
, 0, sizeof(iwr
));
88 os_strlcpy(iwr
.ifr_name
, drv
->ifname
, IFNAMSIZ
);
89 i
= (int *) iwr
.u
.name
;
93 if (ioctl(drv
->sock
, PRISM2_IOCTL_PRISM2_PARAM
, &iwr
) < 0) {
94 perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
101 static int wpa_driver_hostap_set_wpa(void *priv
, int enabled
)
103 struct wpa_driver_hostap_data
*drv
= priv
;
106 wpa_printf(MSG_DEBUG
, "%s: enabled=%d", __FUNCTION__
, enabled
);
108 if (!enabled
&& wpa_driver_hostap_set_wpa_ie(drv
, NULL
, 0) < 0)
110 if (prism2param(drv
, PRISM2_PARAM_HOST_ROAMING
, enabled
? 2 : 0) < 0)
112 if (prism2param(drv
, PRISM2_PARAM_WPA
, enabled
) < 0)
119 static void show_set_key_error(struct prism2_hostapd_param
*param
)
121 switch (param
->u
.crypt
.err
) {
122 case HOSTAP_CRYPT_ERR_UNKNOWN_ALG
:
123 wpa_printf(MSG_INFO
, "Unknown algorithm '%s'.",
125 wpa_printf(MSG_INFO
, "You may need to load kernel module to "
126 "register that algorithm.");
127 wpa_printf(MSG_INFO
, "E.g., 'modprobe hostap_crypt_wep' for "
130 case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR
:
131 wpa_printf(MSG_INFO
, "Unknown address " MACSTR
".",
132 MAC2STR(param
->sta_addr
));
134 case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED
:
135 wpa_printf(MSG_INFO
, "Crypt algorithm initialization failed.");
137 case HOSTAP_CRYPT_ERR_KEY_SET_FAILED
:
138 wpa_printf(MSG_INFO
, "Key setting failed.");
140 case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED
:
141 wpa_printf(MSG_INFO
, "TX key index setting failed.");
143 case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED
:
144 wpa_printf(MSG_INFO
, "Card configuration failed.");
150 static int wpa_driver_hostap_set_key(void *priv
, wpa_alg alg
,
151 const u8
*addr
, int key_idx
,
152 int set_tx
, const u8
*seq
, size_t seq_len
,
153 const u8
*key
, size_t key_len
)
155 struct wpa_driver_hostap_data
*drv
= priv
;
156 struct prism2_hostapd_param
*param
;
179 wpa_printf(MSG_DEBUG
, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
180 "key_len=%lu", __FUNCTION__
, alg_name
, key_idx
, set_tx
,
181 (unsigned long) seq_len
, (unsigned long) key_len
);
186 blen
= sizeof(*param
) + key_len
;
187 buf
= os_zalloc(blen
);
191 param
= (struct prism2_hostapd_param
*) buf
;
192 param
->cmd
= PRISM2_SET_ENCRYPTION
;
193 /* TODO: In theory, STA in client mode can use five keys; four default
194 * keys for receiving (with keyidx 0..3) and one individual key for
195 * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
196 * keyidx 0 is reserved for this unicast use and default keys can only
197 * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
198 * This should be fine for more or less all cases, but for completeness
199 * sake, the driver could be enhanced to support the missing key. */
202 os_memset(param
->sta_addr
, 0xff, ETH_ALEN
);
204 os_memcpy(param
->sta_addr
, addr
, ETH_ALEN
);
206 os_memset(param
->sta_addr
, 0xff, ETH_ALEN
);
208 os_strlcpy((char *) param
->u
.crypt
.alg
, alg_name
,
209 HOSTAP_CRYPT_ALG_NAME_LEN
);
210 param
->u
.crypt
.flags
= set_tx
? HOSTAP_CRYPT_FLAG_SET_TX_KEY
: 0;
211 param
->u
.crypt
.idx
= key_idx
;
212 os_memcpy(param
->u
.crypt
.seq
, seq
, seq_len
);
213 param
->u
.crypt
.key_len
= key_len
;
214 os_memcpy((u8
*) (param
+ 1), key
, key_len
);
216 if (hostapd_ioctl(drv
, param
, blen
, 1)) {
217 wpa_printf(MSG_WARNING
, "Failed to set encryption.");
218 show_set_key_error(param
);
227 static int wpa_driver_hostap_set_countermeasures(void *priv
, int enabled
)
229 struct wpa_driver_hostap_data
*drv
= priv
;
230 wpa_printf(MSG_DEBUG
, "%s: enabled=%d", __FUNCTION__
, enabled
);
231 return prism2param(drv
, PRISM2_PARAM_TKIP_COUNTERMEASURES
, enabled
);
235 static int wpa_driver_hostap_set_drop_unencrypted(void *priv
, int enabled
)
237 struct wpa_driver_hostap_data
*drv
= priv
;
238 wpa_printf(MSG_DEBUG
, "%s: enabled=%d", __FUNCTION__
, enabled
);
239 return prism2param(drv
, PRISM2_PARAM_DROP_UNENCRYPTED
, enabled
);
243 static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data
*drv
,
249 wpa_printf(MSG_DEBUG
, "%s: type=%d", __FUNCTION__
, type
);
251 os_memset(&iwr
, 0, sizeof(iwr
));
252 os_strlcpy(iwr
.ifr_name
, drv
->ifname
, IFNAMSIZ
);
253 i
= (int *) iwr
.u
.name
;
256 if (ioctl(drv
->sock
, PRISM2_IOCTL_RESET
, &iwr
) < 0) {
257 perror("ioctl[PRISM2_IOCTL_RESET]");
264 static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data
*drv
,
265 const u8
*addr
, int cmd
, int reason_code
)
267 struct prism2_hostapd_param param
;
270 /* There does not seem to be a better way of deauthenticating or
271 * disassociating with Prism2/2.5/3 than sending the management frame
272 * and then resetting the Port0 to make sure both the AP and the STA
273 * end up in disconnected state. */
274 os_memset(¶m
, 0, sizeof(param
));
275 param
.cmd
= PRISM2_HOSTAPD_MLME
;
276 os_memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
277 param
.u
.mlme
.cmd
= cmd
;
278 param
.u
.mlme
.reason_code
= reason_code
;
279 ret
= hostapd_ioctl(drv
, ¶m
, sizeof(param
), 1);
282 ret
= wpa_driver_hostap_reset(drv
, 2);
288 static int wpa_driver_hostap_deauthenticate(void *priv
, const u8
*addr
,
291 struct wpa_driver_hostap_data
*drv
= priv
;
292 wpa_printf(MSG_DEBUG
, "%s", __FUNCTION__
);
293 return wpa_driver_hostap_mlme(drv
, addr
, MLME_STA_DEAUTH
,
298 static int wpa_driver_hostap_disassociate(void *priv
, const u8
*addr
,
301 struct wpa_driver_hostap_data
*drv
= priv
;
302 wpa_printf(MSG_DEBUG
, "%s", __FUNCTION__
);
303 return wpa_driver_hostap_mlme(drv
, addr
, MLME_STA_DISASSOC
,
309 wpa_driver_hostap_associate(void *priv
,
310 struct wpa_driver_associate_params
*params
)
312 struct wpa_driver_hostap_data
*drv
= priv
;
314 int allow_unencrypted_eapol
;
316 wpa_printf(MSG_DEBUG
, "%s", __FUNCTION__
);
318 if (params
->mode
!= drv
->current_mode
) {
319 /* At the moment, Host AP driver requires host_roaming=2 for
320 * infrastructure mode and host_roaming=0 for adhoc. */
321 if (prism2param(drv
, PRISM2_PARAM_HOST_ROAMING
,
322 params
->mode
== IEEE80211_MODE_IBSS
? 0 : 2) <
324 wpa_printf(MSG_DEBUG
, "%s: failed to set host_roaming",
327 drv
->current_mode
= params
->mode
;
330 if (prism2param(drv
, PRISM2_PARAM_PRIVACY_INVOKED
,
331 params
->key_mgmt_suite
!= KEY_MGMT_NONE
) < 0)
333 if (wpa_driver_hostap_set_wpa_ie(drv
, params
->wpa_ie
,
334 params
->wpa_ie_len
) < 0)
336 if (wpa_driver_wext_set_mode(drv
->wext
, params
->mode
) < 0)
339 wpa_driver_wext_set_freq(drv
->wext
, params
->freq
) < 0)
341 if (wpa_driver_wext_set_ssid(drv
->wext
, params
->ssid
, params
->ssid_len
)
344 if (wpa_driver_wext_set_bssid(drv
->wext
, params
->bssid
) < 0)
347 /* Allow unencrypted EAPOL messages even if pairwise keys are set when
348 * not using WPA. IEEE 802.1X specifies that these frames are not
349 * encrypted, but WPA encrypts them when pairwise keys are in use. */
350 if (params
->key_mgmt_suite
== KEY_MGMT_802_1X
||
351 params
->key_mgmt_suite
== KEY_MGMT_PSK
)
352 allow_unencrypted_eapol
= 0;
354 allow_unencrypted_eapol
= 1;
356 if (prism2param(drv
, PRISM2_PARAM_IEEE_802_1X
,
357 allow_unencrypted_eapol
) < 0) {
358 wpa_printf(MSG_DEBUG
, "hostap: Failed to configure "
359 "ieee_802_1x param");
360 /* Ignore this error.. driver_hostap.c can also be used with
361 * other drivers that do not support this prism2_param. */
368 static int wpa_driver_hostap_scan(void *priv
, const u8
*ssid
, size_t ssid_len
)
370 struct wpa_driver_hostap_data
*drv
= priv
;
371 struct prism2_hostapd_param param
;
375 /* Use standard Linux Wireless Extensions ioctl if possible
376 * because some drivers using hostap code in wpa_supplicant
377 * might not support Host AP specific scan request (with SSID
379 return wpa_driver_wext_scan(drv
->wext
, ssid
, ssid_len
);
385 os_memset(¶m
, 0, sizeof(param
));
386 param
.cmd
= PRISM2_HOSTAPD_SCAN_REQ
;
387 param
.u
.scan_req
.ssid_len
= ssid_len
;
388 os_memcpy(param
.u
.scan_req
.ssid
, ssid
, ssid_len
);
389 ret
= hostapd_ioctl(drv
, ¶m
, sizeof(param
), 1);
391 /* Not all drivers generate "scan completed" wireless event, so try to
392 * read results after a timeout. */
393 eloop_cancel_timeout(wpa_driver_wext_scan_timeout
, drv
->wext
,
395 eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout
, drv
->wext
,
402 static int wpa_driver_hostap_set_auth_alg(void *priv
, int auth_alg
)
404 struct wpa_driver_hostap_data
*drv
= priv
;
407 if (auth_alg
& AUTH_ALG_OPEN_SYSTEM
)
409 if (auth_alg
& AUTH_ALG_SHARED_KEY
)
411 if (auth_alg
& AUTH_ALG_LEAP
)
414 algs
= 1; /* at least one algorithm should be set */
416 return prism2param(drv
, PRISM2_PARAM_AP_AUTH_ALGS
, algs
);
420 static int wpa_driver_hostap_get_bssid(void *priv
, u8
*bssid
)
422 struct wpa_driver_hostap_data
*drv
= priv
;
423 return wpa_driver_wext_get_bssid(drv
->wext
, bssid
);
427 static int wpa_driver_hostap_get_ssid(void *priv
, u8
*ssid
)
429 struct wpa_driver_hostap_data
*drv
= priv
;
430 return wpa_driver_wext_get_ssid(drv
->wext
, ssid
);
434 static struct wpa_scan_results
* wpa_driver_hostap_get_scan_results(void *priv
)
436 struct wpa_driver_hostap_data
*drv
= priv
;
437 return wpa_driver_wext_get_scan_results(drv
->wext
);
441 static int wpa_driver_hostap_set_operstate(void *priv
, int state
)
443 struct wpa_driver_hostap_data
*drv
= priv
;
444 return wpa_driver_wext_set_operstate(drv
->wext
, state
);
448 static void * wpa_driver_hostap_init(void *ctx
, const char *ifname
)
450 struct wpa_driver_hostap_data
*drv
;
452 drv
= os_zalloc(sizeof(*drv
));
455 drv
->wext
= wpa_driver_wext_init(ctx
, ifname
);
456 if (drv
->wext
== NULL
) {
462 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
463 drv
->sock
= socket(PF_INET
, SOCK_DGRAM
, 0);
466 wpa_driver_wext_deinit(drv
->wext
);
471 if (os_strncmp(ifname
, "wlan", 4) == 0) {
473 * Host AP driver may use both wlan# and wifi# interface in
476 char ifname2
[IFNAMSIZ
+ 1];
477 os_strlcpy(ifname2
, ifname
, sizeof(ifname2
));
478 os_memcpy(ifname2
, "wifi", 4);
479 wpa_driver_wext_alternative_ifindex(drv
->wext
, ifname2
);
486 static void wpa_driver_hostap_deinit(void *priv
)
488 struct wpa_driver_hostap_data
*drv
= priv
;
489 wpa_driver_wext_deinit(drv
->wext
);
495 const struct wpa_driver_ops wpa_driver_hostap_ops
= {
497 .desc
= "Host AP driver (Intersil Prism2/2.5/3)",
498 .get_bssid
= wpa_driver_hostap_get_bssid
,
499 .get_ssid
= wpa_driver_hostap_get_ssid
,
500 .set_wpa
= wpa_driver_hostap_set_wpa
,
501 .set_key
= wpa_driver_hostap_set_key
,
502 .set_countermeasures
= wpa_driver_hostap_set_countermeasures
,
503 .set_drop_unencrypted
= wpa_driver_hostap_set_drop_unencrypted
,
504 .scan
= wpa_driver_hostap_scan
,
505 .get_scan_results2
= wpa_driver_hostap_get_scan_results
,
506 .deauthenticate
= wpa_driver_hostap_deauthenticate
,
507 .disassociate
= wpa_driver_hostap_disassociate
,
508 .associate
= wpa_driver_hostap_associate
,
509 .set_auth_alg
= wpa_driver_hostap_set_auth_alg
,
510 .init
= wpa_driver_hostap_init
,
511 .deinit
= wpa_driver_hostap_deinit
,
512 .set_operstate
= wpa_driver_hostap_set_operstate
,