/*
* hostapd / Kernel driver communication with Linux Host AP driver
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <sys/ioctl.h>
#ifdef USE_KERNEL_HEADERS
+/* compat-wireless does not include linux/compiler.h to define __user, so
+ * define it here */
+#ifndef __user
+#define __user
+#endif /* __user */
#include <asm/types.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* The L2 protocols */
#endif /* USE_KERNEL_HEADERS */
#include "hostapd.h"
+#include "config.h"
#include "driver.h"
-#include "ieee802_1x.h"
#include "eloop.h"
#include "priv_netlink.h"
-#include "ieee802_11.h"
-#include "sta_info.h"
#include "hostap_common.h"
#include "hw_features.h"
+#include "ieee802_11_defs.h"
+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
struct hostap_driver_data {
struct hostapd_data *hapd;
u8 *generic_ie;
size_t generic_ie_len;
+ u8 *wps_ie;
+ size_t wps_ie_len;
};
static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
int len);
static int hostap_set_iface_flags(void *priv, int dev_up);
+static int hostap_sta_disassoc(void *priv, const u8 *addr, int reason);
+static int hostap_sta_deauth(void *priv, const u8 *addr, int reason);
-static void handle_data(struct hostapd_data *hapd, u8 *buf, size_t len,
+static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len,
u16 stype)
{
struct ieee80211_hdr *hdr;
u16 fc, ethertype;
u8 *pos, *sa;
size_t left;
- struct sta_info *sta;
if (len < sizeof(struct ieee80211_hdr))
return;
}
sa = hdr->addr2;
- sta = ap_get_sta(hapd, sa);
- if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
- printf("Data frame from not associated STA " MACSTR "\n",
- MAC2STR(sa));
- if (sta && (sta->flags & WLAN_STA_AUTH))
- hostapd_sta_disassoc(
- hapd, sa,
- WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
- else
- hostapd_sta_deauth(
- hapd, sa,
- WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
- return;
- }
+ hostapd_rx_from_unknown_sta(drv->hapd, sa);
pos = (u8 *) (hdr + 1);
left = len - sizeof(*hdr);
left -= 2;
switch (ethertype) {
case ETH_P_PAE:
- ieee802_1x_receive(hapd, sa, pos, left);
+ hostapd_eapol_receive(drv->hapd, sa, pos, left);
break;
default:
}
-static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len,
- int ok)
+static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf,
+ size_t len, int ok)
{
struct ieee80211_hdr *hdr;
u16 fc, type, stype;
- struct sta_info *sta;
hdr = (struct ieee80211_hdr *) buf;
fc = le_to_host16(hdr->frame_control);
case WLAN_FC_TYPE_MGMT:
wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s",
ok ? "ACK" : "fail");
- ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
+ hostapd_mgmt_tx_cb(drv->hapd, buf, len, stype, ok);
break;
case WLAN_FC_TYPE_CTRL:
wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s",
case WLAN_FC_TYPE_DATA:
wpa_printf(MSG_DEBUG, "DATA (TX callback) %s",
ok ? "ACK" : "fail");
- sta = ap_get_sta(hapd, hdr->addr1);
- if (sta && sta->flags & WLAN_STA_PENDING_POLL) {
- wpa_printf(MSG_DEBUG, "STA " MACSTR
- " %s pending activity poll",
- MAC2STR(sta->addr),
- ok ? "ACKed" : "did not ACK");
- if (ok)
- sta->flags &= ~WLAN_STA_PENDING_POLL;
- }
- if (sta)
- ieee802_1x_tx_status(hapd, sta, buf, len, ok);
+ hostapd_tx_status(drv->hapd, hdr->addr1, buf, len, ok);
break;
default:
printf("unknown TX callback frame type %d\n", type);
}
-static void handle_frame(struct hostapd_data *hapd, u8 *buf, size_t len)
+static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
{
struct ieee80211_hdr *hdr;
u16 fc, extra_len, type, stype;
len -= extra_len + 2;
extra = buf + len;
} else if (ver == 1 || ver == 2) {
- handle_tx_callback(hapd, buf, data_len, ver == 2 ? 1 : 0);
+ handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0);
return;
} else if (ver != 0) {
printf("unknown protocol version %d\n", ver);
case WLAN_FC_TYPE_MGMT:
if (stype != WLAN_FC_STYPE_BEACON)
wpa_printf(MSG_MSGDUMP, "MGMT");
- ieee802_11_mgmt(hapd, buf, data_len, stype, NULL);
+ hostapd_mgmt_rx(drv->hapd, buf, data_len, stype, NULL);
break;
case WLAN_FC_TYPE_CTRL:
wpa_printf(MSG_DEBUG, "CTRL");
break;
case WLAN_FC_TYPE_DATA:
wpa_printf(MSG_DEBUG, "DATA");
- handle_data(hapd, buf, data_len, stype);
+ handle_data(drv, buf, data_len, stype);
break;
default:
wpa_printf(MSG_DEBUG, "unknown frame type %d", type);
static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
{
- struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
+ struct hostap_driver_data *drv = eloop_ctx;
int len;
unsigned char buf[3000];
return;
}
- handle_frame(hapd, buf, len);
+ handle_frame(drv, buf, len);
}
return -1;
}
- if (eloop_register_read_sock(drv->sock, handle_read, drv->hapd, NULL))
- {
+ if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) {
printf("Could not register read socket\n");
return -1;
}
int flags)
{
struct hostap_driver_data *drv = priv;
-
- return send(drv->sock, msg, len, flags);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
+ int res;
+
+ /* Request TX callback */
+ hdr->frame_control |= host_to_le16(BIT(1));
+ res = send(drv->sock, msg, len, flags);
+ hdr->frame_control &= ~host_to_le16(BIT(1));
+
+ return res;
}
hdr->frame_control =
IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
- /* Request TX callback */
- hdr->frame_control |= host_to_le16(BIT(1));
if (encrypt)
hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
}
-static int hostap_set_encryption(const char *ifname, void *priv,
- const char *alg, const u8 *addr,
- int idx, const u8 *key, size_t key_len,
- int txkey)
+static int hostap_set_key(const char *ifname, void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len, const u8 *key,
+ size_t key_len)
{
struct hostap_driver_data *drv = priv;
struct prism2_hostapd_param *param;
memset(param->sta_addr, 0xff, ETH_ALEN);
else
memcpy(param->sta_addr, addr, ETH_ALEN);
- os_strlcpy((char *) param->u.crypt.alg, alg,
- HOSTAP_CRYPT_ALG_NAME_LEN);
- param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
- param->u.crypt.idx = idx;
+ switch (alg) {
+ case WPA_ALG_NONE:
+ os_strlcpy((char *) param->u.crypt.alg, "NONE",
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ break;
+ case WPA_ALG_WEP:
+ os_strlcpy((char *) param->u.crypt.alg, "WEP",
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ break;
+ case WPA_ALG_TKIP:
+ os_strlcpy((char *) param->u.crypt.alg, "TKIP",
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ break;
+ case WPA_ALG_CCMP:
+ os_strlcpy((char *) param->u.crypt.alg, "CCMP",
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ break;
+ default:
+ os_free(buf);
+ return -1;
+ }
+ param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
+ param->u.crypt.idx = key_idx;
param->u.crypt.key_len = key_len;
memcpy((u8 *) (param + 1), key, key_len);
}
-static int hostap_sta_add(const char *ifname, void *priv, const u8 *addr,
- u16 aid, u16 capability, u8 *supp_rates,
- size_t supp_rates_len, int flags,
- u16 listen_interval)
+static int hostap_sta_add(const char *ifname, void *priv,
+ struct hostapd_sta_add_params *params)
{
struct hostap_driver_data *drv = priv;
struct prism2_hostapd_param param;
#define WLAN_RATE_5M5 BIT(2)
#define WLAN_RATE_11M BIT(3)
- for (i = 0; i < supp_rates_len; i++) {
- if ((supp_rates[i] & 0x7f) == 2)
+ for (i = 0; i < params->supp_rates_len; i++) {
+ if ((params->supp_rates[i] & 0x7f) == 2)
tx_supp_rates |= WLAN_RATE_1M;
- if ((supp_rates[i] & 0x7f) == 4)
+ if ((params->supp_rates[i] & 0x7f) == 4)
tx_supp_rates |= WLAN_RATE_2M;
- if ((supp_rates[i] & 0x7f) == 11)
+ if ((params->supp_rates[i] & 0x7f) == 11)
tx_supp_rates |= WLAN_RATE_5M5;
- if ((supp_rates[i] & 0x7f) == 22)
+ if ((params->supp_rates[i] & 0x7f) == 22)
tx_supp_rates |= WLAN_RATE_11M;
}
memset(¶m, 0, sizeof(param));
param.cmd = PRISM2_HOSTAPD_ADD_STA;
- memcpy(param.sta_addr, addr, ETH_ALEN);
- param.u.add_sta.aid = aid;
- param.u.add_sta.capability = capability;
+ memcpy(param.sta_addr, params->addr, ETH_ALEN);
+ param.u.add_sta.aid = params->aid;
+ param.u.add_sta.capability = params->capability;
param.u.add_sta.tx_supp_rates = tx_supp_rates;
return hostapd_ioctl(drv, ¶m, sizeof(param));
}
}
-static int hostap_set_assoc_ap(void *priv, const u8 *addr)
-{
- struct hostap_driver_data *drv = priv;
- struct prism2_hostapd_param param;
-
- memset(¶m, 0, sizeof(param));
- param.cmd = PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR;
- memcpy(param.sta_addr, addr, ETH_ALEN);
- if (hostapd_ioctl(drv, ¶m, sizeof(param)))
- return -1;
-
- return 0;
-}
-
-
static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv)
{
struct prism2_hostapd_param *param;
int res;
size_t blen, elem_len;
- elem_len = drv->generic_ie_len;
+ elem_len = drv->generic_ie_len + drv->wps_ie_len;
blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_len;
if (blen < sizeof(*param))
blen = sizeof(*param);
os_memcpy(param->u.generic_elem.data, drv->generic_ie,
drv->generic_ie_len);
}
+ if (drv->wps_ie) {
+ os_memcpy(¶m->u.generic_elem.data[drv->generic_ie_len],
+ drv->wps_ie, drv->wps_ie_len);
+ }
wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE",
param->u.generic_elem.data, elem_len);
res = hostapd_ioctl(drv, param, blen);
}
+static int hostap_set_wps_beacon_ie(const char *ifname, void *priv,
+ const u8 *ie, size_t len)
+{
+ /* Host AP driver supports only one set of extra IEs, so we need to
+ * use the ProbeResp IEs also for Beacon frames since they include more
+ * information. */
+ return 0;
+}
+
+
+static int hostap_set_wps_probe_resp_ie(const char *ifname, void *priv,
+ const u8 *ie, size_t len)
+{
+ struct hostap_driver_data *drv = priv;
+
+ os_free(drv->wps_ie);
+ drv->wps_ie = NULL;
+ drv->wps_ie_len = 0;
+ if (ie) {
+ drv->wps_ie = os_malloc(len);
+ if (drv->wps_ie == NULL)
+ return -1;
+ os_memcpy(drv->wps_ie, ie, len);
+ drv->wps_ie_len = len;
+ }
+
+ return hostapd_ioctl_set_generic_elem(drv);
+}
+
+
static void
hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv,
char *custom)
}
pos += 5;
if (hwaddr_aton(pos, addr) == 0) {
- ieee80211_michael_mic_failure(drv->hapd, addr, 1);
+ hostapd_michael_mic_failure(drv->hapd, addr);
} else {
wpa_printf(MSG_DEBUG,
"MLME-MICHAELMICFAILURE.indication "
}
-static int hostap_wireless_event_init(void *priv)
+static int hostap_wireless_event_init(struct hostap_driver_data *drv)
{
- struct hostap_driver_data *drv = priv;
int s;
struct sockaddr_nl local;
}
-static void hostap_wireless_event_deinit(void *priv)
+static void hostap_wireless_event_deinit(struct hostap_driver_data *drv)
{
- struct hostap_driver_data *drv = priv;
if (drv->wext_sock < 0)
return;
eloop_unregister_read_sock(drv->wext_sock);
return NULL;
}
- if (hapd->conf->assoc_ap &&
- hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 1)) {
- printf("Could not enable hostapd STA mode for interface %s\n",
- drv->iface);
- close(drv->ioctl_sock);
- free(drv);
- return NULL;
- }
-
- if (hostap_init_sockets(drv)) {
+ if (hostap_init_sockets(drv) || hostap_wireless_event_init(drv)) {
close(drv->ioctl_sock);
free(drv);
return NULL;
{
struct hostap_driver_data *drv = priv;
+ hostap_wireless_event_deinit(drv);
(void) hostap_set_iface_flags(drv, 0);
(void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0);
(void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0);
close(drv->sock);
os_free(drv->generic_ie);
+ os_free(drv->wps_ie);
free(drv);
}
for (i = 0; i < 14; i++) {
mode->channels[i].chan = i + 1;
mode->channels[i].freq = chan2freq[i];
+ /* TODO: Get allowed channel list from the driver */
+ if (i >= 11)
+ mode->channels[i].flag = HOSTAPD_CHAN_DISABLED;
}
mode->rates[0].rate = 10;
}
-const struct wpa_driver_ops wpa_driver_hostap_ops = {
+const struct hapd_driver_ops wpa_driver_hostap_ops = {
.name = "hostap",
.init = hostap_init,
.deinit = hostap_driver_deinit,
- .wireless_event_init = hostap_wireless_event_init,
- .wireless_event_deinit = hostap_wireless_event_deinit,
.set_ieee8021x = hostap_set_ieee8021x,
.set_privacy = hostap_set_privacy,
- .set_encryption = hostap_set_encryption,
+ .set_key = hostap_set_key,
.get_seqnum = hostap_get_seqnum,
.flush = hostap_flush,
.set_generic_elem = hostap_set_generic_elem,
.sta_remove = hostap_sta_remove,
.set_ssid = hostap_set_ssid,
.send_mgmt_frame = hostap_send_mgmt_frame,
- .set_assoc_ap = hostap_set_assoc_ap,
.sta_add = hostap_sta_add,
.get_inact_sec = hostap_get_inact_sec,
.sta_clear_stats = hostap_sta_clear_stats,
.get_hw_feature_data = hostap_get_hw_feature_data,
+ .set_wps_beacon_ie = hostap_set_wps_beacon_ie,
+ .set_wps_probe_resp_ie = hostap_set_wps_probe_resp_ie,
};