2 * Driver interaction with Linux Host AP driver
3 * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
10 #include <sys/ioctl.h>
12 #include "linux_wext.h"
15 #include "driver_wext.h"
17 #include "driver_hostap.h"
20 #include <net/if_arp.h>
21 #include <netpacket/packet.h>
23 #include "priv_netlink.h"
25 #include "linux_ioctl.h"
26 #include "common/ieee802_11_defs.h"
27 #include "common/ieee802_11_common.h"
30 /* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
31 * frames that might be longer than normal default MTU and they are not
33 #define HOSTAPD_MTU 2290
35 static const u8 rfc1042_header
[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
37 struct hostap_driver_data
{
38 struct hostapd_data
*hapd
;
40 char iface
[IFNAMSIZ
+ 1];
41 int sock
; /* raw packet socket for driver access */
42 int ioctl_sock
; /* socket for ioctl() use */
43 struct netlink_data
*netlink
;
48 size_t generic_ie_len
;
54 static int hostapd_ioctl(void *priv
, struct prism2_hostapd_param
*param
,
56 static int hostap_set_iface_flags(void *priv
, int dev_up
);
58 static void handle_data(struct hostap_driver_data
*drv
, u8
*buf
, size_t len
,
61 struct ieee80211_hdr
*hdr
;
65 union wpa_event_data event
;
67 if (len
< sizeof(struct ieee80211_hdr
))
70 hdr
= (struct ieee80211_hdr
*) buf
;
71 fc
= le_to_host16(hdr
->frame_control
);
73 if ((fc
& (WLAN_FC_FROMDS
| WLAN_FC_TODS
)) != WLAN_FC_TODS
) {
74 printf("Not ToDS data frame (fc=0x%04x)\n", fc
);
79 os_memset(&event
, 0, sizeof(event
));
80 event
.rx_from_unknown
.bssid
= get_hdr_bssid(hdr
, len
);
81 event
.rx_from_unknown
.addr
= sa
;
82 wpa_supplicant_event(drv
->hapd
, EVENT_RX_FROM_UNKNOWN
, &event
);
84 pos
= (u8
*) (hdr
+ 1);
85 left
= len
- sizeof(*hdr
);
87 if (left
< sizeof(rfc1042_header
)) {
88 printf("Too short data frame\n");
92 if (memcmp(pos
, rfc1042_header
, sizeof(rfc1042_header
)) != 0) {
93 printf("Data frame with no RFC1042 header\n");
96 pos
+= sizeof(rfc1042_header
);
97 left
-= sizeof(rfc1042_header
);
100 printf("No ethertype in data frame\n");
104 ethertype
= WPA_GET_BE16(pos
);
109 drv_event_eapol_rx(drv
->hapd
, sa
, pos
, left
);
113 printf("Unknown ethertype 0x%04x in data frame\n", ethertype
);
119 static void handle_tx_callback(struct hostap_driver_data
*drv
, u8
*buf
,
122 struct ieee80211_hdr
*hdr
;
124 union wpa_event_data event
;
126 hdr
= (struct ieee80211_hdr
*) buf
;
127 fc
= le_to_host16(hdr
->frame_control
);
129 os_memset(&event
, 0, sizeof(event
));
130 event
.tx_status
.type
= WLAN_FC_GET_TYPE(fc
);
131 event
.tx_status
.stype
= WLAN_FC_GET_STYPE(fc
);
132 event
.tx_status
.dst
= hdr
->addr1
;
133 event
.tx_status
.data
= buf
;
134 event
.tx_status
.data_len
= len
;
135 event
.tx_status
.ack
= ok
;
136 wpa_supplicant_event(drv
->hapd
, EVENT_TX_STATUS
, &event
);
140 static void handle_frame(struct hostap_driver_data
*drv
, u8
*buf
, size_t len
)
142 struct ieee80211_hdr
*hdr
;
144 size_t data_len
= len
;
146 union wpa_event_data event
;
148 /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass
149 * these to user space */
151 wpa_printf(MSG_MSGDUMP
, "handle_frame: too short (%lu)",
152 (unsigned long) len
);
156 hdr
= (struct ieee80211_hdr
*) buf
;
157 fc
= le_to_host16(hdr
->frame_control
);
158 type
= WLAN_FC_GET_TYPE(fc
);
159 stype
= WLAN_FC_GET_STYPE(fc
);
161 if (type
!= WLAN_FC_TYPE_MGMT
|| stype
!= WLAN_FC_STYPE_BEACON
) {
162 wpa_hexdump(MSG_MSGDUMP
, "Received management frame",
166 ver
= fc
& WLAN_FC_PVER
;
168 /* protocol version 2 is reserved for indicating ACKed frame (TX
169 * callbacks), and version 1 for indicating failed frame (no ACK, TX
171 if (ver
== 1 || ver
== 2) {
172 handle_tx_callback(drv
, buf
, data_len
, ver
== 2 ? 1 : 0);
174 } else if (ver
!= 0) {
175 printf("unknown protocol version %d\n", ver
);
180 case WLAN_FC_TYPE_MGMT
:
181 os_memset(&event
, 0, sizeof(event
));
182 event
.rx_mgmt
.frame
= buf
;
183 event
.rx_mgmt
.frame_len
= data_len
;
184 wpa_supplicant_event(drv
->hapd
, EVENT_RX_MGMT
, &event
);
186 case WLAN_FC_TYPE_CTRL
:
187 wpa_printf(MSG_DEBUG
, "CTRL");
189 case WLAN_FC_TYPE_DATA
:
190 wpa_printf(MSG_DEBUG
, "DATA");
191 handle_data(drv
, buf
, data_len
, stype
);
194 wpa_printf(MSG_DEBUG
, "unknown frame type %d", type
);
200 static void handle_read(int sock
, void *eloop_ctx
, void *sock_ctx
)
202 struct hostap_driver_data
*drv
= eloop_ctx
;
204 unsigned char buf
[3000];
206 len
= recv(sock
, buf
, sizeof(buf
), 0);
208 wpa_printf(MSG_ERROR
, "recv: %s", strerror(errno
));
212 handle_frame(drv
, buf
, len
);
216 static int hostap_init_sockets(struct hostap_driver_data
*drv
, u8
*own_addr
)
219 struct sockaddr_ll addr
;
221 drv
->sock
= socket(PF_PACKET
, SOCK_RAW
, htons(ETH_P_ALL
));
223 wpa_printf(MSG_ERROR
, "socket[PF_PACKET,SOCK_RAW]: %s",
228 if (eloop_register_read_sock(drv
->sock
, handle_read
, drv
, NULL
)) {
229 wpa_printf(MSG_ERROR
, "Could not register read socket");
233 memset(&ifr
, 0, sizeof(ifr
));
234 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%sap", drv
->iface
);
235 if (ioctl(drv
->sock
, SIOCGIFINDEX
, &ifr
) != 0) {
236 wpa_printf(MSG_ERROR
, "ioctl(SIOCGIFINDEX): %s",
241 if (hostap_set_iface_flags(drv
, 1)) {
245 memset(&addr
, 0, sizeof(addr
));
246 addr
.sll_family
= AF_PACKET
;
247 addr
.sll_ifindex
= ifr
.ifr_ifindex
;
248 wpa_printf(MSG_DEBUG
, "Opening raw packet socket for ifindex %d",
251 if (bind(drv
->sock
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
252 wpa_printf(MSG_ERROR
, "bind: %s", strerror(errno
));
256 return linux_get_ifhwaddr(drv
->sock
, drv
->iface
, own_addr
);
260 static int hostap_send_mlme(void *priv
, const u8
*msg
, size_t len
, int noack
,
262 const u16
*csa_offs
, size_t csa_offs_len
)
264 struct hostap_driver_data
*drv
= priv
;
265 struct ieee80211_hdr
*hdr
= (struct ieee80211_hdr
*) msg
;
268 /* Request TX callback */
269 hdr
->frame_control
|= host_to_le16(BIT(1));
270 res
= send(drv
->sock
, msg
, len
, 0);
271 hdr
->frame_control
&= ~host_to_le16(BIT(1));
277 static int hostap_send_eapol(void *priv
, const u8
*addr
, const u8
*data
,
278 size_t data_len
, int encrypt
, const u8
*own_addr
,
281 struct hostap_driver_data
*drv
= priv
;
282 struct ieee80211_hdr
*hdr
;
287 len
= sizeof(*hdr
) + sizeof(rfc1042_header
) + 2 + data_len
;
288 hdr
= os_zalloc(len
);
290 printf("malloc() failed for hostapd_send_data(len=%lu)\n",
291 (unsigned long) len
);
296 IEEE80211_FC(WLAN_FC_TYPE_DATA
, WLAN_FC_STYPE_DATA
);
297 hdr
->frame_control
|= host_to_le16(WLAN_FC_FROMDS
);
299 hdr
->frame_control
|= host_to_le16(WLAN_FC_ISWEP
);
300 memcpy(hdr
->IEEE80211_DA_FROMDS
, addr
, ETH_ALEN
);
301 memcpy(hdr
->IEEE80211_BSSID_FROMDS
, own_addr
, ETH_ALEN
);
302 memcpy(hdr
->IEEE80211_SA_FROMDS
, own_addr
, ETH_ALEN
);
304 pos
= (u8
*) (hdr
+ 1);
305 memcpy(pos
, rfc1042_header
, sizeof(rfc1042_header
));
306 pos
+= sizeof(rfc1042_header
);
307 *((u16
*) pos
) = htons(ETH_P_PAE
);
309 memcpy(pos
, data
, data_len
);
311 res
= hostap_send_mlme(drv
, (u8
*) hdr
, len
, 0, 0, NULL
, 0);
313 wpa_printf(MSG_ERROR
, "hostap_send_eapol - packet len: %lu - "
315 (unsigned long) len
, errno
, strerror(errno
));
323 static int hostap_sta_set_flags(void *priv
, const u8
*addr
,
324 unsigned int total_flags
, unsigned int flags_or
,
325 unsigned int flags_and
)
327 struct hostap_driver_data
*drv
= priv
;
328 struct prism2_hostapd_param param
;
330 if (flags_or
& WPA_STA_AUTHORIZED
)
331 flags_or
= BIT(5); /* WLAN_STA_AUTHORIZED */
332 if (!(flags_and
& WPA_STA_AUTHORIZED
))
336 memset(¶m
, 0, sizeof(param
));
337 param
.cmd
= PRISM2_HOSTAPD_SET_FLAGS_STA
;
338 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
339 param
.u
.set_flags_sta
.flags_or
= flags_or
;
340 param
.u
.set_flags_sta
.flags_and
= flags_and
;
341 return hostapd_ioctl(drv
, ¶m
, sizeof(param
));
345 static int hostap_set_iface_flags(void *priv
, int dev_up
)
347 struct hostap_driver_data
*drv
= priv
;
349 char ifname
[IFNAMSIZ
];
351 os_snprintf(ifname
, IFNAMSIZ
, "%sap", drv
->iface
);
352 if (linux_set_iface_flags(drv
->ioctl_sock
, ifname
, dev_up
) < 0)
356 memset(&ifr
, 0, sizeof(ifr
));
357 os_strlcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
358 ifr
.ifr_mtu
= HOSTAPD_MTU
;
359 if (ioctl(drv
->ioctl_sock
, SIOCSIFMTU
, &ifr
) != 0) {
361 "Setting MTU failed - trying to survive with current value: ioctl[SIOCSIFMTU]: %s",
370 static int hostapd_ioctl(void *priv
, struct prism2_hostapd_param
*param
,
373 struct hostap_driver_data
*drv
= priv
;
376 memset(&iwr
, 0, sizeof(iwr
));
377 os_strlcpy(iwr
.ifr_name
, drv
->iface
, IFNAMSIZ
);
378 iwr
.u
.data
.pointer
= (caddr_t
) param
;
379 iwr
.u
.data
.length
= len
;
381 if (ioctl(drv
->ioctl_sock
, PRISM2_IOCTL_HOSTAPD
, &iwr
) < 0) {
382 wpa_printf(MSG_ERROR
, "ioctl[PRISM2_IOCTL_HOSTAPD]: %s",
391 static int wpa_driver_hostap_set_key(const char *ifname
, void *priv
,
392 enum wpa_alg alg
, const u8
*addr
,
393 int key_idx
, int set_tx
,
394 const u8
*seq
, size_t seq_len
,
395 const u8
*key
, size_t key_len
)
397 struct hostap_driver_data
*drv
= priv
;
398 struct prism2_hostapd_param
*param
;
403 blen
= sizeof(*param
) + key_len
;
404 buf
= os_zalloc(blen
);
408 param
= (struct prism2_hostapd_param
*) buf
;
409 param
->cmd
= PRISM2_SET_ENCRYPTION
;
411 memset(param
->sta_addr
, 0xff, ETH_ALEN
);
413 memcpy(param
->sta_addr
, addr
, ETH_ALEN
);
416 os_strlcpy((char *) param
->u
.crypt
.alg
, "NONE",
417 HOSTAP_CRYPT_ALG_NAME_LEN
);
420 os_strlcpy((char *) param
->u
.crypt
.alg
, "WEP",
421 HOSTAP_CRYPT_ALG_NAME_LEN
);
424 os_strlcpy((char *) param
->u
.crypt
.alg
, "TKIP",
425 HOSTAP_CRYPT_ALG_NAME_LEN
);
428 os_strlcpy((char *) param
->u
.crypt
.alg
, "CCMP",
429 HOSTAP_CRYPT_ALG_NAME_LEN
);
435 param
->u
.crypt
.flags
= set_tx
? HOSTAP_CRYPT_FLAG_SET_TX_KEY
: 0;
436 param
->u
.crypt
.idx
= key_idx
;
437 param
->u
.crypt
.key_len
= key_len
;
438 memcpy((u8
*) (param
+ 1), key
, key_len
);
440 if (hostapd_ioctl(drv
, param
, blen
)) {
441 printf("Failed to set encryption.\n");
450 static int hostap_get_seqnum(const char *ifname
, void *priv
, const u8
*addr
,
453 struct hostap_driver_data
*drv
= priv
;
454 struct prism2_hostapd_param
*param
;
459 blen
= sizeof(*param
) + 32;
460 buf
= os_zalloc(blen
);
464 param
= (struct prism2_hostapd_param
*) buf
;
465 param
->cmd
= PRISM2_GET_ENCRYPTION
;
467 os_memset(param
->sta_addr
, 0xff, ETH_ALEN
);
469 os_memcpy(param
->sta_addr
, addr
, ETH_ALEN
);
470 param
->u
.crypt
.idx
= idx
;
472 if (hostapd_ioctl(drv
, param
, blen
)) {
473 printf("Failed to get encryption.\n");
476 os_memcpy(seq
, param
->u
.crypt
.seq
, 8);
484 static int hostap_ioctl_prism2param(void *priv
, int param
, int value
)
486 struct hostap_driver_data
*drv
= priv
;
490 memset(&iwr
, 0, sizeof(iwr
));
491 os_strlcpy(iwr
.ifr_name
, drv
->iface
, IFNAMSIZ
);
492 i
= (int *) iwr
.u
.name
;
496 if (ioctl(drv
->ioctl_sock
, PRISM2_IOCTL_PRISM2_PARAM
, &iwr
) < 0) {
497 wpa_printf(MSG_ERROR
, "ioctl[PRISM2_IOCTL_PRISM2_PARAM]: %s",
506 static int hostap_set_ieee8021x(void *priv
, struct wpa_bss_params
*params
)
508 struct hostap_driver_data
*drv
= priv
;
509 int enabled
= params
->enabled
;
511 /* enable kernel driver support for IEEE 802.1X */
512 if (hostap_ioctl_prism2param(drv
, PRISM2_PARAM_IEEE_802_1X
, enabled
)) {
513 printf("Could not setup IEEE 802.1X support in kernel driver."
521 /* use host driver implementation of encryption to allow
522 * individual keys and passing plaintext EAPOL frames */
523 if (hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOST_DECRYPT
, 1) ||
524 hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOST_ENCRYPT
, 1)) {
525 printf("Could not setup host-based encryption in kernel "
534 static int hostap_set_privacy(void *priv
, int enabled
)
536 struct hostap_drvier_data
*drv
= priv
;
538 return hostap_ioctl_prism2param(drv
, PRISM2_PARAM_PRIVACY_INVOKED
,
543 static int hostap_set_ssid(void *priv
, const u8
*buf
, int len
)
545 struct hostap_driver_data
*drv
= priv
;
548 memset(&iwr
, 0, sizeof(iwr
));
549 os_strlcpy(iwr
.ifr_name
, drv
->iface
, IFNAMSIZ
);
550 iwr
.u
.essid
.flags
= 1; /* SSID active */
551 iwr
.u
.essid
.pointer
= (caddr_t
) buf
;
552 iwr
.u
.essid
.length
= len
+ 1;
554 if (ioctl(drv
->ioctl_sock
, SIOCSIWESSID
, &iwr
) < 0) {
555 wpa_printf(MSG_ERROR
, "ioctl[SIOCSIWESSID,len=%d]: %s",
556 len
, strerror(errno
));
564 static int hostap_flush(void *priv
)
566 struct hostap_driver_data
*drv
= priv
;
567 struct prism2_hostapd_param param
;
569 memset(¶m
, 0, sizeof(param
));
570 param
.cmd
= PRISM2_HOSTAPD_FLUSH
;
571 return hostapd_ioctl(drv
, ¶m
, sizeof(param
));
575 static int hostap_read_sta_data(void *priv
,
576 struct hostap_sta_driver_data
*data
,
579 struct hostap_driver_data
*drv
= priv
;
580 char buf
[1024], line
[128], *pos
;
584 memset(data
, 0, sizeof(*data
));
585 snprintf(buf
, sizeof(buf
), "/proc/net/hostap/%s/" MACSTR
,
586 drv
->iface
, MAC2STR(addr
));
591 /* Need to read proc file with in one piece, so use large enough
593 setbuffer(f
, buf
, sizeof(buf
));
595 while (fgets(line
, sizeof(line
), f
)) {
596 pos
= strchr(line
, '=');
600 val
= strtoul(pos
, NULL
, 10);
601 if (strcmp(line
, "rx_packets") == 0)
602 data
->rx_packets
= val
;
603 else if (strcmp(line
, "tx_packets") == 0)
604 data
->tx_packets
= val
;
605 else if (strcmp(line
, "rx_bytes") == 0)
606 data
->rx_bytes
= val
;
607 else if (strcmp(line
, "tx_bytes") == 0)
608 data
->tx_bytes
= val
;
617 static int hostap_sta_add(void *priv
, struct hostapd_sta_add_params
*params
)
619 struct hostap_driver_data
*drv
= priv
;
620 struct prism2_hostapd_param param
;
621 int tx_supp_rates
= 0;
624 #define WLAN_RATE_1M BIT(0)
625 #define WLAN_RATE_2M BIT(1)
626 #define WLAN_RATE_5M5 BIT(2)
627 #define WLAN_RATE_11M BIT(3)
629 for (i
= 0; i
< params
->supp_rates_len
; i
++) {
630 if ((params
->supp_rates
[i
] & 0x7f) == 2)
631 tx_supp_rates
|= WLAN_RATE_1M
;
632 if ((params
->supp_rates
[i
] & 0x7f) == 4)
633 tx_supp_rates
|= WLAN_RATE_2M
;
634 if ((params
->supp_rates
[i
] & 0x7f) == 11)
635 tx_supp_rates
|= WLAN_RATE_5M5
;
636 if ((params
->supp_rates
[i
] & 0x7f) == 22)
637 tx_supp_rates
|= WLAN_RATE_11M
;
640 memset(¶m
, 0, sizeof(param
));
641 param
.cmd
= PRISM2_HOSTAPD_ADD_STA
;
642 memcpy(param
.sta_addr
, params
->addr
, ETH_ALEN
);
643 param
.u
.add_sta
.aid
= params
->aid
;
644 param
.u
.add_sta
.capability
= params
->capability
;
645 param
.u
.add_sta
.tx_supp_rates
= tx_supp_rates
;
646 return hostapd_ioctl(drv
, ¶m
, sizeof(param
));
650 static int hostap_sta_remove(void *priv
, const u8
*addr
)
652 struct hostap_driver_data
*drv
= priv
;
653 struct prism2_hostapd_param param
;
655 hostap_sta_set_flags(drv
, addr
, 0, 0, ~WPA_STA_AUTHORIZED
);
657 memset(¶m
, 0, sizeof(param
));
658 param
.cmd
= PRISM2_HOSTAPD_REMOVE_STA
;
659 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
660 if (hostapd_ioctl(drv
, ¶m
, sizeof(param
))) {
661 printf("Could not remove station from kernel driver.\n");
668 static int hostap_get_inact_sec(void *priv
, const u8
*addr
)
670 struct hostap_driver_data
*drv
= priv
;
671 struct prism2_hostapd_param param
;
673 memset(¶m
, 0, sizeof(param
));
674 param
.cmd
= PRISM2_HOSTAPD_GET_INFO_STA
;
675 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
676 if (hostapd_ioctl(drv
, ¶m
, sizeof(param
))) {
680 return param
.u
.get_info_sta
.inactive_sec
;
684 static int hostap_sta_clear_stats(void *priv
, const u8
*addr
)
686 struct hostap_driver_data
*drv
= priv
;
687 struct prism2_hostapd_param param
;
689 memset(¶m
, 0, sizeof(param
));
690 param
.cmd
= PRISM2_HOSTAPD_STA_CLEAR_STATS
;
691 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
692 if (hostapd_ioctl(drv
, ¶m
, sizeof(param
))) {
700 static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data
*drv
)
702 struct prism2_hostapd_param
*param
;
704 size_t blen
, elem_len
;
706 elem_len
= drv
->generic_ie_len
+ drv
->wps_ie_len
;
707 blen
= PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN
+ elem_len
;
708 if (blen
< sizeof(*param
))
709 blen
= sizeof(*param
);
711 param
= os_zalloc(blen
);
715 param
->cmd
= PRISM2_HOSTAPD_SET_GENERIC_ELEMENT
;
716 param
->u
.generic_elem
.len
= elem_len
;
717 if (drv
->generic_ie
) {
718 os_memcpy(param
->u
.generic_elem
.data
, drv
->generic_ie
,
719 drv
->generic_ie_len
);
722 os_memcpy(¶m
->u
.generic_elem
.data
[drv
->generic_ie_len
],
723 drv
->wps_ie
, drv
->wps_ie_len
);
725 wpa_hexdump(MSG_DEBUG
, "hostap: Set generic IE",
726 param
->u
.generic_elem
.data
, elem_len
);
727 res
= hostapd_ioctl(drv
, param
, blen
);
735 static int hostap_set_generic_elem(void *priv
,
736 const u8
*elem
, size_t elem_len
)
738 struct hostap_driver_data
*drv
= priv
;
740 os_free(drv
->generic_ie
);
741 drv
->generic_ie
= NULL
;
742 drv
->generic_ie_len
= 0;
744 drv
->generic_ie
= os_memdup(elem
, elem_len
);
745 if (drv
->generic_ie
== NULL
)
747 drv
->generic_ie_len
= elem_len
;
750 return hostapd_ioctl_set_generic_elem(drv
);
754 static int hostap_set_ap_wps_ie(void *priv
, const struct wpabuf
*beacon
,
755 const struct wpabuf
*proberesp
,
756 const struct wpabuf
*assocresp
)
758 struct hostap_driver_data
*drv
= priv
;
761 * Host AP driver supports only one set of extra IEs, so we need to
762 * use the Probe Response IEs also for Beacon frames since they include
766 os_free(drv
->wps_ie
);
770 drv
->wps_ie
= os_memdup(wpabuf_head(proberesp
),
771 wpabuf_len(proberesp
));
772 if (drv
->wps_ie
== NULL
)
774 drv
->wps_ie_len
= wpabuf_len(proberesp
);
777 return hostapd_ioctl_set_generic_elem(drv
);
782 hostapd_wireless_event_wireless_custom(struct hostap_driver_data
*drv
,
785 wpa_printf(MSG_DEBUG
, "Custom wireless event: '%s'", custom
);
787 if (strncmp(custom
, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
790 pos
= strstr(custom
, "addr=");
792 wpa_printf(MSG_DEBUG
,
793 "MLME-MICHAELMICFAILURE.indication "
794 "without sender address ignored");
798 if (hwaddr_aton(pos
, addr
) == 0) {
799 union wpa_event_data data
;
800 os_memset(&data
, 0, sizeof(data
));
801 data
.michael_mic_failure
.unicast
= 1;
802 data
.michael_mic_failure
.src
= addr
;
803 wpa_supplicant_event(drv
->hapd
,
804 EVENT_MICHAEL_MIC_FAILURE
, &data
);
806 wpa_printf(MSG_DEBUG
,
807 "MLME-MICHAELMICFAILURE.indication "
808 "with invalid MAC address");
814 static void hostapd_wireless_event_wireless(struct hostap_driver_data
*drv
,
815 char *data
, unsigned int len
)
817 struct iw_event iwe_buf
, *iwe
= &iwe_buf
;
818 char *pos
, *end
, *custom
, *buf
;
823 while ((size_t) (end
- pos
) >= IW_EV_LCP_LEN
) {
824 /* Event data may be unaligned, so make a local, aligned copy
825 * before processing. */
826 memcpy(&iwe_buf
, pos
, IW_EV_LCP_LEN
);
827 wpa_printf(MSG_DEBUG
, "Wireless event: cmd=0x%x len=%d",
829 if (iwe
->len
<= IW_EV_LCP_LEN
|| iwe
->len
> end
- pos
)
832 custom
= pos
+ IW_EV_POINT_LEN
;
833 if (drv
->we_version
> 18 &&
834 (iwe
->cmd
== IWEVMICHAELMICFAILURE
||
835 iwe
->cmd
== IWEVCUSTOM
)) {
836 /* WE-19 removed the pointer from struct iw_point */
837 char *dpos
= (char *) &iwe_buf
.u
.data
.length
;
838 int dlen
= dpos
- (char *) &iwe_buf
;
839 memcpy(dpos
, pos
+ IW_EV_LCP_LEN
,
840 sizeof(struct iw_event
) - dlen
);
842 memcpy(&iwe_buf
, pos
, sizeof(struct iw_event
));
843 custom
+= IW_EV_POINT_OFF
;
848 if (iwe
->u
.data
.length
> end
- custom
)
850 buf
= malloc(iwe
->u
.data
.length
+ 1);
853 memcpy(buf
, custom
, iwe
->u
.data
.length
);
854 buf
[iwe
->u
.data
.length
] = '\0';
855 hostapd_wireless_event_wireless_custom(drv
, buf
);
865 static void hostapd_wireless_event_rtm_newlink(void *ctx
,
866 struct ifinfomsg
*ifi
,
869 struct hostap_driver_data
*drv
= ctx
;
870 int attrlen
, rta_len
;
873 /* TODO: use ifi->ifi_index to filter out wireless events from other
877 attr
= (struct rtattr
*) buf
;
879 rta_len
= RTA_ALIGN(sizeof(struct rtattr
));
880 while (RTA_OK(attr
, attrlen
)) {
881 if (attr
->rta_type
== IFLA_WIRELESS
) {
882 hostapd_wireless_event_wireless(
883 drv
, ((char *) attr
) + rta_len
,
884 attr
->rta_len
- rta_len
);
886 attr
= RTA_NEXT(attr
, attrlen
);
891 static int hostap_get_we_version(struct hostap_driver_data
*drv
)
893 struct iw_range
*range
;
901 * Use larger buffer than struct iw_range in order to allow the
902 * structure to grow in the future.
904 buflen
= sizeof(struct iw_range
) + 500;
905 range
= os_zalloc(buflen
);
909 memset(&iwr
, 0, sizeof(iwr
));
910 os_strlcpy(iwr
.ifr_name
, drv
->iface
, IFNAMSIZ
);
911 iwr
.u
.data
.pointer
= (caddr_t
) range
;
912 iwr
.u
.data
.length
= buflen
;
914 minlen
= ((char *) &range
->enc_capa
) - (char *) range
+
915 sizeof(range
->enc_capa
);
917 if (ioctl(drv
->ioctl_sock
, SIOCGIWRANGE
, &iwr
) < 0) {
918 wpa_printf(MSG_ERROR
, "ioctl[SIOCGIWRANGE]: %s",
922 } else if (iwr
.u
.data
.length
>= minlen
&&
923 range
->we_version_compiled
>= 18) {
924 wpa_printf(MSG_DEBUG
, "SIOCGIWRANGE: WE(compiled)=%d "
925 "WE(source)=%d enc_capa=0x%x",
926 range
->we_version_compiled
,
927 range
->we_version_source
,
929 drv
->we_version
= range
->we_version_compiled
;
937 static int hostap_wireless_event_init(struct hostap_driver_data
*drv
)
939 struct netlink_config
*cfg
;
941 hostap_get_we_version(drv
);
943 cfg
= os_zalloc(sizeof(*cfg
));
947 cfg
->newlink_cb
= hostapd_wireless_event_rtm_newlink
;
948 drv
->netlink
= netlink_init(cfg
);
949 if (drv
->netlink
== NULL
) {
958 static void * hostap_init(struct hostapd_data
*hapd
,
959 struct wpa_init_params
*params
)
961 struct hostap_driver_data
*drv
;
963 drv
= os_zalloc(sizeof(struct hostap_driver_data
));
965 printf("Could not allocate memory for hostapd driver data\n");
970 drv
->ioctl_sock
= drv
->sock
= -1;
971 memcpy(drv
->iface
, params
->ifname
, sizeof(drv
->iface
));
973 drv
->ioctl_sock
= socket(PF_INET
, SOCK_DGRAM
, 0);
974 if (drv
->ioctl_sock
< 0) {
975 wpa_printf(MSG_ERROR
, "socket[PF_INET,SOCK_DGRAM]: %s",
981 if (hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOSTAPD
, 1)) {
982 wpa_printf(MSG_ERROR
,
983 "Could not enable hostapd mode for interface %s",
985 close(drv
->ioctl_sock
);
990 if (hostap_init_sockets(drv
, params
->own_addr
) ||
991 hostap_wireless_event_init(drv
)) {
992 close(drv
->ioctl_sock
);
1001 static void hostap_driver_deinit(void *priv
)
1003 struct hostap_driver_data
*drv
= priv
;
1005 netlink_deinit(drv
->netlink
);
1006 (void) hostap_set_iface_flags(drv
, 0);
1007 (void) hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOSTAPD
, 0);
1008 (void) hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOSTAPD_STA
, 0);
1010 if (drv
->ioctl_sock
>= 0)
1011 close(drv
->ioctl_sock
);
1016 os_free(drv
->generic_ie
);
1017 os_free(drv
->wps_ie
);
1023 static int hostap_sta_deauth(void *priv
, const u8
*own_addr
, const u8
*addr
,
1026 struct hostap_driver_data
*drv
= priv
;
1027 struct ieee80211_mgmt mgmt
;
1029 if (is_broadcast_ether_addr(addr
)) {
1031 * New Prism2.5/3 STA firmware versions seem to have issues
1032 * with this broadcast deauth frame. This gets the firmware in
1033 * odd state where nothing works correctly, so let's skip
1034 * sending this for the hostap driver.
1039 memset(&mgmt
, 0, sizeof(mgmt
));
1040 mgmt
.frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
1041 WLAN_FC_STYPE_DEAUTH
);
1042 memcpy(mgmt
.da
, addr
, ETH_ALEN
);
1043 memcpy(mgmt
.sa
, own_addr
, ETH_ALEN
);
1044 memcpy(mgmt
.bssid
, own_addr
, ETH_ALEN
);
1045 mgmt
.u
.deauth
.reason_code
= host_to_le16(reason
);
1046 return hostap_send_mlme(drv
, (u8
*) &mgmt
, IEEE80211_HDRLEN
+
1047 sizeof(mgmt
.u
.deauth
), 0, 0, NULL
, 0);
1051 static int hostap_set_freq(void *priv
, struct hostapd_freq_params
*freq
)
1053 struct hostap_driver_data
*drv
= priv
;
1056 os_memset(&iwr
, 0, sizeof(iwr
));
1057 os_strlcpy(iwr
.ifr_name
, drv
->iface
, IFNAMSIZ
);
1058 iwr
.u
.freq
.m
= freq
->channel
;
1061 if (ioctl(drv
->ioctl_sock
, SIOCSIWFREQ
, &iwr
) < 0) {
1062 wpa_printf(MSG_ERROR
, "ioctl[SIOCSIWFREQ]: %s",
1071 static int hostap_sta_disassoc(void *priv
, const u8
*own_addr
, const u8
*addr
,
1074 struct hostap_driver_data
*drv
= priv
;
1075 struct ieee80211_mgmt mgmt
;
1077 memset(&mgmt
, 0, sizeof(mgmt
));
1078 mgmt
.frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
1079 WLAN_FC_STYPE_DISASSOC
);
1080 memcpy(mgmt
.da
, addr
, ETH_ALEN
);
1081 memcpy(mgmt
.sa
, own_addr
, ETH_ALEN
);
1082 memcpy(mgmt
.bssid
, own_addr
, ETH_ALEN
);
1083 mgmt
.u
.disassoc
.reason_code
= host_to_le16(reason
);
1084 return hostap_send_mlme(drv
, (u8
*) &mgmt
, IEEE80211_HDRLEN
+
1085 sizeof(mgmt
.u
.disassoc
), 0, 0, NULL
, 0);
1089 static struct hostapd_hw_modes
* hostap_get_hw_feature_data(void *priv
,
1093 struct hostapd_hw_modes
*mode
;
1095 const short chan2freq
[14] = {
1096 2412, 2417, 2422, 2427, 2432, 2437, 2442,
1097 2447, 2452, 2457, 2462, 2467, 2472, 2484
1100 mode
= os_zalloc(sizeof(struct hostapd_hw_modes
));
1107 mode
->mode
= HOSTAPD_MODE_IEEE80211B
;
1108 mode
->num_channels
= 14;
1109 mode
->num_rates
= 4;
1111 clen
= mode
->num_channels
* sizeof(struct hostapd_channel_data
);
1112 rlen
= mode
->num_rates
* sizeof(int);
1114 mode
->channels
= os_zalloc(clen
);
1115 mode
->rates
= os_zalloc(rlen
);
1116 if (mode
->channels
== NULL
|| mode
->rates
== NULL
) {
1117 os_free(mode
->channels
);
1118 os_free(mode
->rates
);
1123 for (i
= 0; i
< 14; i
++) {
1124 mode
->channels
[i
].chan
= i
+ 1;
1125 mode
->channels
[i
].freq
= chan2freq
[i
];
1126 /* TODO: Get allowed channel list from the driver */
1128 mode
->channels
[i
].flag
= HOSTAPD_CHAN_DISABLED
;
1131 mode
->rates
[0] = 10;
1132 mode
->rates
[1] = 20;
1133 mode
->rates
[2] = 55;
1134 mode
->rates
[3] = 110;
1140 static void wpa_driver_hostap_poll_client(void *priv
, const u8
*own_addr
,
1141 const u8
*addr
, int qos
)
1143 struct ieee80211_hdr hdr
;
1145 os_memset(&hdr
, 0, sizeof(hdr
));
1148 * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
1149 * but it is apparently not retried so TX Exc events
1150 * are not received for it.
1151 * This is the reason the driver overrides the default
1154 hdr
.frame_control
= IEEE80211_FC(WLAN_FC_TYPE_DATA
,
1155 WLAN_FC_STYPE_DATA
);
1157 hdr
.frame_control
|=
1158 host_to_le16(WLAN_FC_FROMDS
);
1159 os_memcpy(hdr
.IEEE80211_DA_FROMDS
, addr
, ETH_ALEN
);
1160 os_memcpy(hdr
.IEEE80211_BSSID_FROMDS
, own_addr
, ETH_ALEN
);
1161 os_memcpy(hdr
.IEEE80211_SA_FROMDS
, own_addr
, ETH_ALEN
);
1163 hostap_send_mlme(priv
, (u8
*)&hdr
, sizeof(hdr
), 0, 0, NULL
, 0);
1167 const struct wpa_driver_ops wpa_driver_hostap_ops
= {
1169 .desc
= "Host AP driver (Intersil Prism2/2.5/3)",
1170 .set_key
= wpa_driver_hostap_set_key
,
1171 .hapd_init
= hostap_init
,
1172 .hapd_deinit
= hostap_driver_deinit
,
1173 .set_ieee8021x
= hostap_set_ieee8021x
,
1174 .set_privacy
= hostap_set_privacy
,
1175 .get_seqnum
= hostap_get_seqnum
,
1176 .flush
= hostap_flush
,
1177 .set_generic_elem
= hostap_set_generic_elem
,
1178 .read_sta_data
= hostap_read_sta_data
,
1179 .hapd_send_eapol
= hostap_send_eapol
,
1180 .sta_set_flags
= hostap_sta_set_flags
,
1181 .sta_deauth
= hostap_sta_deauth
,
1182 .sta_disassoc
= hostap_sta_disassoc
,
1183 .sta_remove
= hostap_sta_remove
,
1184 .hapd_set_ssid
= hostap_set_ssid
,
1185 .send_mlme
= hostap_send_mlme
,
1186 .sta_add
= hostap_sta_add
,
1187 .get_inact_sec
= hostap_get_inact_sec
,
1188 .sta_clear_stats
= hostap_sta_clear_stats
,
1189 .get_hw_feature_data
= hostap_get_hw_feature_data
,
1190 .set_ap_wps_ie
= hostap_set_ap_wps_ie
,
1191 .set_freq
= hostap_set_freq
,
1192 .poll_client
= wpa_driver_hostap_poll_client
,