2 * hostapd / Kernel driver communication with Linux Host AP driver
3 * Copyright (c) 2002-2007, 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 #ifdef USE_KERNEL_HEADERS
19 /* compat-wireless does not include linux/compiler.h to define __user, so
24 #include <asm/types.h>
25 #include <linux/if_packet.h>
26 #include <linux/if_ether.h> /* The L2 protocols */
27 #include <linux/if_arp.h>
28 #include <linux/wireless.h>
29 #else /* USE_KERNEL_HEADERS */
30 #include <net/if_arp.h>
31 #include <netpacket/packet.h>
32 #include "wireless_copy.h"
33 #endif /* USE_KERNEL_HEADERS */
37 #include "ieee802_1x.h"
39 #include "priv_netlink.h"
40 #include "ieee802_11.h"
42 #include "hostap_common.h"
43 #include "hw_features.h"
46 struct hostap_driver_data
{
47 struct hostapd_data
*hapd
;
49 char iface
[IFNAMSIZ
+ 1];
50 int sock
; /* raw packet socket for driver access */
51 int ioctl_sock
; /* socket for ioctl() use */
52 int wext_sock
; /* socket for wireless events */
57 size_t generic_ie_len
;
63 static int hostapd_ioctl(void *priv
, struct prism2_hostapd_param
*param
,
65 static int hostap_set_iface_flags(void *priv
, int dev_up
);
67 static void handle_data(struct hostapd_data
*hapd
, u8
*buf
, size_t len
,
70 struct ieee80211_hdr
*hdr
;
76 if (len
< sizeof(struct ieee80211_hdr
))
79 hdr
= (struct ieee80211_hdr
*) buf
;
80 fc
= le_to_host16(hdr
->frame_control
);
82 if ((fc
& (WLAN_FC_FROMDS
| WLAN_FC_TODS
)) != WLAN_FC_TODS
) {
83 printf("Not ToDS data frame (fc=0x%04x)\n", fc
);
88 sta
= ap_get_sta(hapd
, sa
);
89 if (!sta
|| !(sta
->flags
& WLAN_STA_ASSOC
)) {
90 printf("Data frame from not associated STA " MACSTR
"\n",
92 if (sta
&& (sta
->flags
& WLAN_STA_AUTH
))
95 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA
);
99 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA
);
103 pos
= (u8
*) (hdr
+ 1);
104 left
= len
- sizeof(*hdr
);
106 if (left
< sizeof(rfc1042_header
)) {
107 printf("Too short data frame\n");
111 if (memcmp(pos
, rfc1042_header
, sizeof(rfc1042_header
)) != 0) {
112 printf("Data frame with no RFC1042 header\n");
115 pos
+= sizeof(rfc1042_header
);
116 left
-= sizeof(rfc1042_header
);
119 printf("No ethertype in data frame\n");
123 ethertype
= WPA_GET_BE16(pos
);
128 ieee802_1x_receive(hapd
, sa
, pos
, left
);
132 printf("Unknown ethertype 0x%04x in data frame\n", ethertype
);
138 static void handle_tx_callback(struct hostapd_data
*hapd
, u8
*buf
, size_t len
,
141 struct ieee80211_hdr
*hdr
;
143 struct sta_info
*sta
;
145 hdr
= (struct ieee80211_hdr
*) buf
;
146 fc
= le_to_host16(hdr
->frame_control
);
148 type
= WLAN_FC_GET_TYPE(fc
);
149 stype
= WLAN_FC_GET_STYPE(fc
);
152 case WLAN_FC_TYPE_MGMT
:
153 wpa_printf(MSG_DEBUG
, "MGMT (TX callback) %s",
154 ok
? "ACK" : "fail");
155 ieee802_11_mgmt_cb(hapd
, buf
, len
, stype
, ok
);
157 case WLAN_FC_TYPE_CTRL
:
158 wpa_printf(MSG_DEBUG
, "CTRL (TX callback) %s",
159 ok
? "ACK" : "fail");
161 case WLAN_FC_TYPE_DATA
:
162 wpa_printf(MSG_DEBUG
, "DATA (TX callback) %s",
163 ok
? "ACK" : "fail");
164 sta
= ap_get_sta(hapd
, hdr
->addr1
);
165 if (sta
&& sta
->flags
& WLAN_STA_PENDING_POLL
) {
166 wpa_printf(MSG_DEBUG
, "STA " MACSTR
167 " %s pending activity poll",
169 ok
? "ACKed" : "did not ACK");
171 sta
->flags
&= ~WLAN_STA_PENDING_POLL
;
174 ieee802_1x_tx_status(hapd
, sta
, buf
, len
, ok
);
177 printf("unknown TX callback frame type %d\n", type
);
183 static void handle_frame(struct hostapd_data
*hapd
, u8
*buf
, size_t len
)
185 struct ieee80211_hdr
*hdr
;
186 u16 fc
, extra_len
, type
, stype
;
187 unsigned char *extra
= NULL
;
188 size_t data_len
= len
;
191 /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass
192 * these to user space */
194 wpa_printf(MSG_MSGDUMP
, "handle_frame: too short (%lu)",
195 (unsigned long) len
);
199 hdr
= (struct ieee80211_hdr
*) buf
;
200 fc
= le_to_host16(hdr
->frame_control
);
201 type
= WLAN_FC_GET_TYPE(fc
);
202 stype
= WLAN_FC_GET_STYPE(fc
);
204 if (type
!= WLAN_FC_TYPE_MGMT
|| stype
!= WLAN_FC_STYPE_BEACON
) {
205 wpa_hexdump(MSG_MSGDUMP
, "Received management frame",
209 ver
= fc
& WLAN_FC_PVER
;
211 /* protocol version 3 is reserved for indicating extra data after the
212 * payload, version 2 for indicating ACKed frame (TX callbacks), and
213 * version 1 for indicating failed frame (no ACK, TX callbacks) */
215 u8
*pos
= buf
+ len
- 2;
216 extra_len
= WPA_GET_LE16(pos
);
217 printf("extra data in frame (elen=%d)\n", extra_len
);
218 if ((size_t) extra_len
+ 2 > len
) {
219 printf(" extra data overflow\n");
222 len
-= extra_len
+ 2;
224 } else if (ver
== 1 || ver
== 2) {
225 handle_tx_callback(hapd
, buf
, data_len
, ver
== 2 ? 1 : 0);
227 } else if (ver
!= 0) {
228 printf("unknown protocol version %d\n", ver
);
233 case WLAN_FC_TYPE_MGMT
:
234 if (stype
!= WLAN_FC_STYPE_BEACON
)
235 wpa_printf(MSG_MSGDUMP
, "MGMT");
236 ieee802_11_mgmt(hapd
, buf
, data_len
, stype
, NULL
);
238 case WLAN_FC_TYPE_CTRL
:
239 wpa_printf(MSG_DEBUG
, "CTRL");
241 case WLAN_FC_TYPE_DATA
:
242 wpa_printf(MSG_DEBUG
, "DATA");
243 handle_data(hapd
, buf
, data_len
, stype
);
246 wpa_printf(MSG_DEBUG
, "unknown frame type %d", type
);
252 static void handle_read(int sock
, void *eloop_ctx
, void *sock_ctx
)
254 struct hostapd_data
*hapd
= (struct hostapd_data
*) eloop_ctx
;
256 unsigned char buf
[3000];
258 len
= recv(sock
, buf
, sizeof(buf
), 0);
264 handle_frame(hapd
, buf
, len
);
268 static int hostap_init_sockets(struct hostap_driver_data
*drv
)
271 struct sockaddr_ll addr
;
273 drv
->sock
= socket(PF_PACKET
, SOCK_RAW
, htons(ETH_P_ALL
));
275 perror("socket[PF_PACKET,SOCK_RAW]");
279 if (eloop_register_read_sock(drv
->sock
, handle_read
, drv
->hapd
, NULL
))
281 printf("Could not register read socket\n");
285 memset(&ifr
, 0, sizeof(ifr
));
286 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%sap", drv
->iface
);
287 if (ioctl(drv
->sock
, SIOCGIFINDEX
, &ifr
) != 0) {
288 perror("ioctl(SIOCGIFINDEX)");
292 if (hostap_set_iface_flags(drv
, 1)) {
296 memset(&addr
, 0, sizeof(addr
));
297 addr
.sll_family
= AF_PACKET
;
298 addr
.sll_ifindex
= ifr
.ifr_ifindex
;
299 wpa_printf(MSG_DEBUG
, "Opening raw packet socket for ifindex %d",
302 if (bind(drv
->sock
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
307 memset(&ifr
, 0, sizeof(ifr
));
308 os_strlcpy(ifr
.ifr_name
, drv
->iface
, sizeof(ifr
.ifr_name
));
309 if (ioctl(drv
->sock
, SIOCGIFHWADDR
, &ifr
) != 0) {
310 perror("ioctl(SIOCGIFHWADDR)");
314 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
) {
315 printf("Invalid HW-addr family 0x%04x\n",
316 ifr
.ifr_hwaddr
.sa_family
);
319 memcpy(drv
->hapd
->own_addr
, ifr
.ifr_hwaddr
.sa_data
, ETH_ALEN
);
325 static int hostap_send_mgmt_frame(void *priv
, const void *msg
, size_t len
,
328 struct hostap_driver_data
*drv
= priv
;
329 struct ieee80211_hdr
*hdr
= (struct ieee80211_hdr
*) msg
;
332 /* Request TX callback */
333 hdr
->frame_control
|= host_to_le16(BIT(1));
334 res
= send(drv
->sock
, msg
, len
, flags
);
335 hdr
->frame_control
&= ~host_to_le16(BIT(1));
341 static int hostap_send_eapol(void *priv
, const u8
*addr
, const u8
*data
,
342 size_t data_len
, int encrypt
, const u8
*own_addr
)
344 struct hostap_driver_data
*drv
= priv
;
345 struct ieee80211_hdr
*hdr
;
350 len
= sizeof(*hdr
) + sizeof(rfc1042_header
) + 2 + data_len
;
351 hdr
= os_zalloc(len
);
353 printf("malloc() failed for hostapd_send_data(len=%lu)\n",
354 (unsigned long) len
);
359 IEEE80211_FC(WLAN_FC_TYPE_DATA
, WLAN_FC_STYPE_DATA
);
360 hdr
->frame_control
|= host_to_le16(WLAN_FC_FROMDS
);
362 hdr
->frame_control
|= host_to_le16(WLAN_FC_ISWEP
);
363 memcpy(hdr
->IEEE80211_DA_FROMDS
, addr
, ETH_ALEN
);
364 memcpy(hdr
->IEEE80211_BSSID_FROMDS
, own_addr
, ETH_ALEN
);
365 memcpy(hdr
->IEEE80211_SA_FROMDS
, own_addr
, ETH_ALEN
);
367 pos
= (u8
*) (hdr
+ 1);
368 memcpy(pos
, rfc1042_header
, sizeof(rfc1042_header
));
369 pos
+= sizeof(rfc1042_header
);
370 *((u16
*) pos
) = htons(ETH_P_PAE
);
372 memcpy(pos
, data
, data_len
);
374 res
= hostap_send_mgmt_frame(drv
, (u8
*) hdr
, len
, 0);
378 perror("hostapd_send_eapol: send");
379 printf("hostapd_send_eapol - packet len: %lu - failed\n",
380 (unsigned long) len
);
387 static int hostap_sta_set_flags(void *priv
, const u8
*addr
,
388 int total_flags
, int flags_or
, int flags_and
)
390 struct hostap_driver_data
*drv
= priv
;
391 struct prism2_hostapd_param param
;
393 memset(¶m
, 0, sizeof(param
));
394 param
.cmd
= PRISM2_HOSTAPD_SET_FLAGS_STA
;
395 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
396 param
.u
.set_flags_sta
.flags_or
= flags_or
;
397 param
.u
.set_flags_sta
.flags_and
= flags_and
;
398 return hostapd_ioctl(drv
, ¶m
, sizeof(param
));
402 static int hostap_set_iface_flags(void *priv
, int dev_up
)
404 struct hostap_driver_data
*drv
= priv
;
407 if (drv
->ioctl_sock
< 0)
410 memset(&ifr
, 0, sizeof(ifr
));
411 snprintf(ifr
.ifr_name
, IFNAMSIZ
, "%sap", drv
->iface
);
413 if (ioctl(drv
->ioctl_sock
, SIOCGIFFLAGS
, &ifr
) != 0) {
414 perror("ioctl[SIOCGIFFLAGS]");
419 ifr
.ifr_flags
|= IFF_UP
;
421 ifr
.ifr_flags
&= ~IFF_UP
;
423 if (ioctl(drv
->ioctl_sock
, SIOCSIFFLAGS
, &ifr
) != 0) {
424 perror("ioctl[SIOCSIFFLAGS]");
429 memset(&ifr
, 0, sizeof(ifr
));
430 snprintf(ifr
.ifr_name
, IFNAMSIZ
, "%sap", drv
->iface
);
431 ifr
.ifr_mtu
= HOSTAPD_MTU
;
432 if (ioctl(drv
->ioctl_sock
, SIOCSIFMTU
, &ifr
) != 0) {
433 perror("ioctl[SIOCSIFMTU]");
434 printf("Setting MTU failed - trying to survive with "
443 static int hostapd_ioctl(void *priv
, struct prism2_hostapd_param
*param
,
446 struct hostap_driver_data
*drv
= priv
;
449 memset(&iwr
, 0, sizeof(iwr
));
450 os_strlcpy(iwr
.ifr_name
, drv
->iface
, IFNAMSIZ
);
451 iwr
.u
.data
.pointer
= (caddr_t
) param
;
452 iwr
.u
.data
.length
= len
;
454 if (ioctl(drv
->ioctl_sock
, PRISM2_IOCTL_HOSTAPD
, &iwr
) < 0) {
455 perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
463 static int hostap_set_encryption(const char *ifname
, void *priv
,
464 const char *alg
, const u8
*addr
,
465 int idx
, const u8
*key
, size_t key_len
,
468 struct hostap_driver_data
*drv
= priv
;
469 struct prism2_hostapd_param
*param
;
474 blen
= sizeof(*param
) + key_len
;
475 buf
= os_zalloc(blen
);
479 param
= (struct prism2_hostapd_param
*) buf
;
480 param
->cmd
= PRISM2_SET_ENCRYPTION
;
482 memset(param
->sta_addr
, 0xff, ETH_ALEN
);
484 memcpy(param
->sta_addr
, addr
, ETH_ALEN
);
485 os_strlcpy((char *) param
->u
.crypt
.alg
, alg
,
486 HOSTAP_CRYPT_ALG_NAME_LEN
);
487 param
->u
.crypt
.flags
= txkey
? HOSTAP_CRYPT_FLAG_SET_TX_KEY
: 0;
488 param
->u
.crypt
.idx
= idx
;
489 param
->u
.crypt
.key_len
= key_len
;
490 memcpy((u8
*) (param
+ 1), key
, key_len
);
492 if (hostapd_ioctl(drv
, param
, blen
)) {
493 printf("Failed to set encryption.\n");
502 static int hostap_get_seqnum(const char *ifname
, void *priv
, const u8
*addr
,
505 struct hostap_driver_data
*drv
= priv
;
506 struct prism2_hostapd_param
*param
;
511 blen
= sizeof(*param
) + 32;
512 buf
= os_zalloc(blen
);
516 param
= (struct prism2_hostapd_param
*) buf
;
517 param
->cmd
= PRISM2_GET_ENCRYPTION
;
519 memset(param
->sta_addr
, 0xff, ETH_ALEN
);
521 memcpy(param
->sta_addr
, addr
, ETH_ALEN
);
522 param
->u
.crypt
.idx
= idx
;
524 if (hostapd_ioctl(drv
, param
, blen
)) {
525 printf("Failed to get encryption.\n");
528 memcpy(seq
, param
->u
.crypt
.seq
, 8);
536 static int hostap_ioctl_prism2param(void *priv
, int param
, int value
)
538 struct hostap_driver_data
*drv
= priv
;
542 memset(&iwr
, 0, sizeof(iwr
));
543 os_strlcpy(iwr
.ifr_name
, drv
->iface
, IFNAMSIZ
);
544 i
= (int *) iwr
.u
.name
;
548 if (ioctl(drv
->ioctl_sock
, PRISM2_IOCTL_PRISM2_PARAM
, &iwr
) < 0) {
549 perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
557 static int hostap_set_ieee8021x(const char *ifname
, void *priv
, int enabled
)
559 struct hostap_driver_data
*drv
= priv
;
561 /* enable kernel driver support for IEEE 802.1X */
562 if (hostap_ioctl_prism2param(drv
, PRISM2_PARAM_IEEE_802_1X
, enabled
)) {
563 printf("Could not setup IEEE 802.1X support in kernel driver."
571 /* use host driver implementation of encryption to allow
572 * individual keys and passing plaintext EAPOL frames */
573 if (hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOST_DECRYPT
, 1) ||
574 hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOST_ENCRYPT
, 1)) {
575 printf("Could not setup host-based encryption in kernel "
584 static int hostap_set_privacy(const char *ifname
, void *priv
, int enabled
)
586 struct hostap_drvier_data
*drv
= priv
;
588 return hostap_ioctl_prism2param(drv
, PRISM2_PARAM_PRIVACY_INVOKED
,
593 static int hostap_set_ssid(const char *ifname
, void *priv
, const u8
*buf
,
596 struct hostap_driver_data
*drv
= priv
;
599 memset(&iwr
, 0, sizeof(iwr
));
600 os_strlcpy(iwr
.ifr_name
, drv
->iface
, IFNAMSIZ
);
601 iwr
.u
.essid
.flags
= 1; /* SSID active */
602 iwr
.u
.essid
.pointer
= (caddr_t
) buf
;
603 iwr
.u
.essid
.length
= len
+ 1;
605 if (ioctl(drv
->ioctl_sock
, SIOCSIWESSID
, &iwr
) < 0) {
606 perror("ioctl[SIOCSIWESSID]");
607 printf("len=%d\n", len
);
615 static int hostap_flush(void *priv
)
617 struct hostap_driver_data
*drv
= priv
;
618 struct prism2_hostapd_param param
;
620 memset(¶m
, 0, sizeof(param
));
621 param
.cmd
= PRISM2_HOSTAPD_FLUSH
;
622 return hostapd_ioctl(drv
, ¶m
, sizeof(param
));
626 static int hostap_read_sta_data(void *priv
,
627 struct hostap_sta_driver_data
*data
,
630 struct hostap_driver_data
*drv
= priv
;
631 char buf
[1024], line
[128], *pos
;
635 memset(data
, 0, sizeof(*data
));
636 snprintf(buf
, sizeof(buf
), "/proc/net/hostap/%s/" MACSTR
,
637 drv
->iface
, MAC2STR(addr
));
642 /* Need to read proc file with in one piece, so use large enough
644 setbuffer(f
, buf
, sizeof(buf
));
646 while (fgets(line
, sizeof(line
), f
)) {
647 pos
= strchr(line
, '=');
651 val
= strtoul(pos
, NULL
, 10);
652 if (strcmp(line
, "rx_packets") == 0)
653 data
->rx_packets
= val
;
654 else if (strcmp(line
, "tx_packets") == 0)
655 data
->tx_packets
= val
;
656 else if (strcmp(line
, "rx_bytes") == 0)
657 data
->rx_bytes
= val
;
658 else if (strcmp(line
, "tx_bytes") == 0)
659 data
->tx_bytes
= val
;
668 static int hostap_sta_add(const char *ifname
, void *priv
, const u8
*addr
,
669 u16 aid
, u16 capability
, u8
*supp_rates
,
670 size_t supp_rates_len
, int flags
,
673 struct hostap_driver_data
*drv
= priv
;
674 struct prism2_hostapd_param param
;
675 int tx_supp_rates
= 0;
678 #define WLAN_RATE_1M BIT(0)
679 #define WLAN_RATE_2M BIT(1)
680 #define WLAN_RATE_5M5 BIT(2)
681 #define WLAN_RATE_11M BIT(3)
683 for (i
= 0; i
< supp_rates_len
; i
++) {
684 if ((supp_rates
[i
] & 0x7f) == 2)
685 tx_supp_rates
|= WLAN_RATE_1M
;
686 if ((supp_rates
[i
] & 0x7f) == 4)
687 tx_supp_rates
|= WLAN_RATE_2M
;
688 if ((supp_rates
[i
] & 0x7f) == 11)
689 tx_supp_rates
|= WLAN_RATE_5M5
;
690 if ((supp_rates
[i
] & 0x7f) == 22)
691 tx_supp_rates
|= WLAN_RATE_11M
;
694 memset(¶m
, 0, sizeof(param
));
695 param
.cmd
= PRISM2_HOSTAPD_ADD_STA
;
696 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
697 param
.u
.add_sta
.aid
= aid
;
698 param
.u
.add_sta
.capability
= capability
;
699 param
.u
.add_sta
.tx_supp_rates
= tx_supp_rates
;
700 return hostapd_ioctl(drv
, ¶m
, sizeof(param
));
704 static int hostap_sta_remove(void *priv
, const u8
*addr
)
706 struct hostap_driver_data
*drv
= priv
;
707 struct prism2_hostapd_param param
;
709 hostap_sta_set_flags(drv
, addr
, 0, 0, ~WLAN_STA_AUTHORIZED
);
711 memset(¶m
, 0, sizeof(param
));
712 param
.cmd
= PRISM2_HOSTAPD_REMOVE_STA
;
713 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
714 if (hostapd_ioctl(drv
, ¶m
, sizeof(param
))) {
715 printf("Could not remove station from kernel driver.\n");
722 static int hostap_get_inact_sec(void *priv
, const u8
*addr
)
724 struct hostap_driver_data
*drv
= priv
;
725 struct prism2_hostapd_param param
;
727 memset(¶m
, 0, sizeof(param
));
728 param
.cmd
= PRISM2_HOSTAPD_GET_INFO_STA
;
729 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
730 if (hostapd_ioctl(drv
, ¶m
, sizeof(param
))) {
734 return param
.u
.get_info_sta
.inactive_sec
;
738 static int hostap_sta_clear_stats(void *priv
, const u8
*addr
)
740 struct hostap_driver_data
*drv
= priv
;
741 struct prism2_hostapd_param param
;
743 memset(¶m
, 0, sizeof(param
));
744 param
.cmd
= PRISM2_HOSTAPD_STA_CLEAR_STATS
;
745 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
746 if (hostapd_ioctl(drv
, ¶m
, sizeof(param
))) {
754 static int hostap_set_assoc_ap(void *priv
, const u8
*addr
)
756 struct hostap_driver_data
*drv
= priv
;
757 struct prism2_hostapd_param param
;
759 memset(¶m
, 0, sizeof(param
));
760 param
.cmd
= PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR
;
761 memcpy(param
.sta_addr
, addr
, ETH_ALEN
);
762 if (hostapd_ioctl(drv
, ¶m
, sizeof(param
)))
769 static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data
*drv
)
771 struct prism2_hostapd_param
*param
;
773 size_t blen
, elem_len
;
775 elem_len
= drv
->generic_ie_len
+ drv
->wps_ie_len
;
776 blen
= PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN
+ elem_len
;
777 if (blen
< sizeof(*param
))
778 blen
= sizeof(*param
);
780 param
= os_zalloc(blen
);
784 param
->cmd
= PRISM2_HOSTAPD_SET_GENERIC_ELEMENT
;
785 param
->u
.generic_elem
.len
= elem_len
;
786 if (drv
->generic_ie
) {
787 os_memcpy(param
->u
.generic_elem
.data
, drv
->generic_ie
,
788 drv
->generic_ie_len
);
791 os_memcpy(¶m
->u
.generic_elem
.data
[drv
->generic_ie_len
],
792 drv
->wps_ie
, drv
->wps_ie_len
);
794 wpa_hexdump(MSG_DEBUG
, "hostap: Set generic IE",
795 param
->u
.generic_elem
.data
, elem_len
);
796 res
= hostapd_ioctl(drv
, param
, blen
);
804 static int hostap_set_generic_elem(const char *ifname
, void *priv
,
805 const u8
*elem
, size_t elem_len
)
807 struct hostap_driver_data
*drv
= priv
;
809 os_free(drv
->generic_ie
);
810 drv
->generic_ie
= NULL
;
811 drv
->generic_ie_len
= 0;
813 drv
->generic_ie
= os_malloc(elem_len
);
814 if (drv
->generic_ie
== NULL
)
816 os_memcpy(drv
->generic_ie
, elem
, elem_len
);
817 drv
->generic_ie_len
= elem_len
;
820 return hostapd_ioctl_set_generic_elem(drv
);
824 static int hostap_set_wps_beacon_ie(const char *ifname
, void *priv
,
825 const u8
*ie
, size_t len
)
827 /* Host AP driver supports only one set of extra IEs, so we need to
828 * use the ProbeResp IEs also for Beacon frames since they include more
834 static int hostap_set_wps_probe_resp_ie(const char *ifname
, void *priv
,
835 const u8
*ie
, size_t len
)
837 struct hostap_driver_data
*drv
= priv
;
839 os_free(drv
->wps_ie
);
843 drv
->wps_ie
= os_malloc(len
);
844 if (drv
->wps_ie
== NULL
)
846 os_memcpy(drv
->wps_ie
, ie
, len
);
847 drv
->wps_ie_len
= len
;
850 return hostapd_ioctl_set_generic_elem(drv
);
855 hostapd_wireless_event_wireless_custom(struct hostap_driver_data
*drv
,
858 wpa_printf(MSG_DEBUG
, "Custom wireless event: '%s'", custom
);
860 if (strncmp(custom
, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
863 pos
= strstr(custom
, "addr=");
865 wpa_printf(MSG_DEBUG
,
866 "MLME-MICHAELMICFAILURE.indication "
867 "without sender address ignored");
871 if (hwaddr_aton(pos
, addr
) == 0) {
872 ieee80211_michael_mic_failure(drv
->hapd
, addr
, 1);
874 wpa_printf(MSG_DEBUG
,
875 "MLME-MICHAELMICFAILURE.indication "
876 "with invalid MAC address");
882 static void hostapd_wireless_event_wireless(struct hostap_driver_data
*drv
,
885 struct iw_event iwe_buf
, *iwe
= &iwe_buf
;
886 char *pos
, *end
, *custom
, *buf
;
891 while (pos
+ IW_EV_LCP_LEN
<= end
) {
892 /* Event data may be unaligned, so make a local, aligned copy
893 * before processing. */
894 memcpy(&iwe_buf
, pos
, IW_EV_LCP_LEN
);
895 wpa_printf(MSG_DEBUG
, "Wireless event: cmd=0x%x len=%d",
897 if (iwe
->len
<= IW_EV_LCP_LEN
)
900 custom
= pos
+ IW_EV_POINT_LEN
;
901 if (drv
->we_version
> 18 &&
902 (iwe
->cmd
== IWEVMICHAELMICFAILURE
||
903 iwe
->cmd
== IWEVCUSTOM
)) {
904 /* WE-19 removed the pointer from struct iw_point */
905 char *dpos
= (char *) &iwe_buf
.u
.data
.length
;
906 int dlen
= dpos
- (char *) &iwe_buf
;
907 memcpy(dpos
, pos
+ IW_EV_LCP_LEN
,
908 sizeof(struct iw_event
) - dlen
);
910 memcpy(&iwe_buf
, pos
, sizeof(struct iw_event
));
911 custom
+= IW_EV_POINT_OFF
;
916 if (custom
+ iwe
->u
.data
.length
> end
)
918 buf
= malloc(iwe
->u
.data
.length
+ 1);
921 memcpy(buf
, custom
, iwe
->u
.data
.length
);
922 buf
[iwe
->u
.data
.length
] = '\0';
923 hostapd_wireless_event_wireless_custom(drv
, buf
);
933 static void hostapd_wireless_event_rtm_newlink(struct hostap_driver_data
*drv
,
934 struct nlmsghdr
*h
, int len
)
936 struct ifinfomsg
*ifi
;
937 int attrlen
, nlmsg_len
, rta_len
;
938 struct rtattr
* attr
;
940 if (len
< (int) sizeof(*ifi
))
945 /* TODO: use ifi->ifi_index to filter out wireless events from other
948 nlmsg_len
= NLMSG_ALIGN(sizeof(struct ifinfomsg
));
950 attrlen
= h
->nlmsg_len
- nlmsg_len
;
954 attr
= (struct rtattr
*) (((char *) ifi
) + nlmsg_len
);
956 rta_len
= RTA_ALIGN(sizeof(struct rtattr
));
957 while (RTA_OK(attr
, attrlen
)) {
958 if (attr
->rta_type
== IFLA_WIRELESS
) {
959 hostapd_wireless_event_wireless(
960 drv
, ((char *) attr
) + rta_len
,
961 attr
->rta_len
- rta_len
);
963 attr
= RTA_NEXT(attr
, attrlen
);
968 static void hostapd_wireless_event_receive(int sock
, void *eloop_ctx
,
973 struct sockaddr_nl from
;
976 struct hostap_driver_data
*drv
= eloop_ctx
;
978 fromlen
= sizeof(from
);
979 left
= recvfrom(sock
, buf
, sizeof(buf
), MSG_DONTWAIT
,
980 (struct sockaddr
*) &from
, &fromlen
);
982 if (errno
!= EINTR
&& errno
!= EAGAIN
)
983 perror("recvfrom(netlink)");
987 h
= (struct nlmsghdr
*) buf
;
988 while (left
>= (int) sizeof(*h
)) {
992 plen
= len
- sizeof(*h
);
993 if (len
> left
|| plen
< 0) {
994 printf("Malformed netlink message: "
995 "len=%d left=%d plen=%d\n",
1000 switch (h
->nlmsg_type
) {
1002 hostapd_wireless_event_rtm_newlink(drv
, h
, plen
);
1006 len
= NLMSG_ALIGN(len
);
1008 h
= (struct nlmsghdr
*) ((char *) h
+ len
);
1012 printf("%d extra bytes in the end of netlink message\n", left
);
1017 static int hostap_get_we_version(struct hostap_driver_data
*drv
)
1019 struct iw_range
*range
;
1024 drv
->we_version
= 0;
1027 * Use larger buffer than struct iw_range in order to allow the
1028 * structure to grow in the future.
1030 buflen
= sizeof(struct iw_range
) + 500;
1031 range
= os_zalloc(buflen
);
1035 memset(&iwr
, 0, sizeof(iwr
));
1036 os_strlcpy(iwr
.ifr_name
, drv
->iface
, IFNAMSIZ
);
1037 iwr
.u
.data
.pointer
= (caddr_t
) range
;
1038 iwr
.u
.data
.length
= buflen
;
1040 minlen
= ((char *) &range
->enc_capa
) - (char *) range
+
1041 sizeof(range
->enc_capa
);
1043 if (ioctl(drv
->ioctl_sock
, SIOCGIWRANGE
, &iwr
) < 0) {
1044 perror("ioctl[SIOCGIWRANGE]");
1047 } else if (iwr
.u
.data
.length
>= minlen
&&
1048 range
->we_version_compiled
>= 18) {
1049 wpa_printf(MSG_DEBUG
, "SIOCGIWRANGE: WE(compiled)=%d "
1050 "WE(source)=%d enc_capa=0x%x",
1051 range
->we_version_compiled
,
1052 range
->we_version_source
,
1054 drv
->we_version
= range
->we_version_compiled
;
1062 static int hostap_wireless_event_init(void *priv
)
1064 struct hostap_driver_data
*drv
= priv
;
1066 struct sockaddr_nl local
;
1068 hostap_get_we_version(drv
);
1070 drv
->wext_sock
= -1;
1072 s
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
1074 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
1078 memset(&local
, 0, sizeof(local
));
1079 local
.nl_family
= AF_NETLINK
;
1080 local
.nl_groups
= RTMGRP_LINK
;
1081 if (bind(s
, (struct sockaddr
*) &local
, sizeof(local
)) < 0) {
1082 perror("bind(netlink)");
1087 eloop_register_read_sock(s
, hostapd_wireless_event_receive
, drv
,
1095 static void hostap_wireless_event_deinit(void *priv
)
1097 struct hostap_driver_data
*drv
= priv
;
1098 if (drv
->wext_sock
< 0)
1100 eloop_unregister_read_sock(drv
->wext_sock
);
1101 close(drv
->wext_sock
);
1105 static void * hostap_init(struct hostapd_data
*hapd
)
1107 struct hostap_driver_data
*drv
;
1109 drv
= os_zalloc(sizeof(struct hostap_driver_data
));
1111 printf("Could not allocate memory for hostapd driver data\n");
1116 drv
->ioctl_sock
= drv
->sock
= -1;
1117 memcpy(drv
->iface
, hapd
->conf
->iface
, sizeof(drv
->iface
));
1119 drv
->ioctl_sock
= socket(PF_INET
, SOCK_DGRAM
, 0);
1120 if (drv
->ioctl_sock
< 0) {
1121 perror("socket[PF_INET,SOCK_DGRAM]");
1126 if (hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOSTAPD
, 1)) {
1127 printf("Could not enable hostapd mode for interface %s\n",
1129 close(drv
->ioctl_sock
);
1134 if (hostap_init_sockets(drv
)) {
1135 close(drv
->ioctl_sock
);
1144 static void hostap_driver_deinit(void *priv
)
1146 struct hostap_driver_data
*drv
= priv
;
1148 (void) hostap_set_iface_flags(drv
, 0);
1149 (void) hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOSTAPD
, 0);
1150 (void) hostap_ioctl_prism2param(drv
, PRISM2_PARAM_HOSTAPD_STA
, 0);
1152 if (drv
->ioctl_sock
>= 0)
1153 close(drv
->ioctl_sock
);
1158 os_free(drv
->generic_ie
);
1159 os_free(drv
->wps_ie
);
1165 static int hostap_sta_deauth(void *priv
, const u8
*addr
, int reason
)
1167 struct hostap_driver_data
*drv
= priv
;
1168 struct ieee80211_mgmt mgmt
;
1170 memset(&mgmt
, 0, sizeof(mgmt
));
1171 mgmt
.frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
1172 WLAN_FC_STYPE_DEAUTH
);
1173 memcpy(mgmt
.da
, addr
, ETH_ALEN
);
1174 memcpy(mgmt
.sa
, drv
->hapd
->own_addr
, ETH_ALEN
);
1175 memcpy(mgmt
.bssid
, drv
->hapd
->own_addr
, ETH_ALEN
);
1176 mgmt
.u
.deauth
.reason_code
= host_to_le16(reason
);
1177 return hostap_send_mgmt_frame(drv
, &mgmt
, IEEE80211_HDRLEN
+
1178 sizeof(mgmt
.u
.deauth
), 0);
1182 static int hostap_sta_disassoc(void *priv
, const u8
*addr
, int reason
)
1184 struct hostap_driver_data
*drv
= priv
;
1185 struct ieee80211_mgmt mgmt
;
1187 memset(&mgmt
, 0, sizeof(mgmt
));
1188 mgmt
.frame_control
= IEEE80211_FC(WLAN_FC_TYPE_MGMT
,
1189 WLAN_FC_STYPE_DISASSOC
);
1190 memcpy(mgmt
.da
, addr
, ETH_ALEN
);
1191 memcpy(mgmt
.sa
, drv
->hapd
->own_addr
, ETH_ALEN
);
1192 memcpy(mgmt
.bssid
, drv
->hapd
->own_addr
, ETH_ALEN
);
1193 mgmt
.u
.disassoc
.reason_code
= host_to_le16(reason
);
1194 return hostap_send_mgmt_frame(drv
, &mgmt
, IEEE80211_HDRLEN
+
1195 sizeof(mgmt
.u
.disassoc
), 0);
1199 static struct hostapd_hw_modes
* hostap_get_hw_feature_data(void *priv
,
1203 struct hostapd_hw_modes
*mode
;
1205 const short chan2freq
[14] = {
1206 2412, 2417, 2422, 2427, 2432, 2437, 2442,
1207 2447, 2452, 2457, 2462, 2467, 2472, 2484
1210 mode
= os_zalloc(sizeof(struct hostapd_hw_modes
));
1217 mode
->mode
= HOSTAPD_MODE_IEEE80211B
;
1218 mode
->num_channels
= 14;
1219 mode
->num_rates
= 4;
1221 clen
= mode
->num_channels
* sizeof(struct hostapd_channel_data
);
1222 rlen
= mode
->num_rates
* sizeof(struct hostapd_rate_data
);
1224 mode
->channels
= os_zalloc(clen
);
1225 mode
->rates
= os_zalloc(rlen
);
1226 if (mode
->channels
== NULL
|| mode
->rates
== NULL
) {
1227 hostapd_free_hw_features(mode
, *num_modes
);
1231 for (i
= 0; i
< 14; i
++) {
1232 mode
->channels
[i
].chan
= i
+ 1;
1233 mode
->channels
[i
].freq
= chan2freq
[i
];
1234 /* TODO: Get allowed channel list from the driver */
1236 mode
->channels
[i
].flag
= HOSTAPD_CHAN_DISABLED
;
1239 mode
->rates
[0].rate
= 10;
1240 mode
->rates
[0].flags
= HOSTAPD_RATE_CCK
;
1241 mode
->rates
[1].rate
= 20;
1242 mode
->rates
[1].flags
= HOSTAPD_RATE_CCK
;
1243 mode
->rates
[2].rate
= 55;
1244 mode
->rates
[2].flags
= HOSTAPD_RATE_CCK
;
1245 mode
->rates
[3].rate
= 110;
1246 mode
->rates
[3].flags
= HOSTAPD_RATE_CCK
;
1252 const struct wpa_driver_ops wpa_driver_hostap_ops
= {
1254 .init
= hostap_init
,
1255 .deinit
= hostap_driver_deinit
,
1256 .wireless_event_init
= hostap_wireless_event_init
,
1257 .wireless_event_deinit
= hostap_wireless_event_deinit
,
1258 .set_ieee8021x
= hostap_set_ieee8021x
,
1259 .set_privacy
= hostap_set_privacy
,
1260 .set_encryption
= hostap_set_encryption
,
1261 .get_seqnum
= hostap_get_seqnum
,
1262 .flush
= hostap_flush
,
1263 .set_generic_elem
= hostap_set_generic_elem
,
1264 .read_sta_data
= hostap_read_sta_data
,
1265 .send_eapol
= hostap_send_eapol
,
1266 .sta_set_flags
= hostap_sta_set_flags
,
1267 .sta_deauth
= hostap_sta_deauth
,
1268 .sta_disassoc
= hostap_sta_disassoc
,
1269 .sta_remove
= hostap_sta_remove
,
1270 .set_ssid
= hostap_set_ssid
,
1271 .send_mgmt_frame
= hostap_send_mgmt_frame
,
1272 .set_assoc_ap
= hostap_set_assoc_ap
,
1273 .sta_add
= hostap_sta_add
,
1274 .get_inact_sec
= hostap_get_inact_sec
,
1275 .sta_clear_stats
= hostap_sta_clear_stats
,
1276 .get_hw_feature_data
= hostap_get_hw_feature_data
,
1277 .set_wps_beacon_ie
= hostap_set_wps_beacon_ie
,
1278 .set_wps_probe_resp_ie
= hostap_set_wps_probe_resp_ie
,