diff options
Diffstat (limited to 'package')
-rw-r--r-- | package/hostapd/Makefile | 5 | ||||
-rw-r--r-- | package/hostapd/files/driver_nl80211.c | 2382 | ||||
-rw-r--r-- | package/hostapd/files/radiotap.c | 287 | ||||
-rw-r--r-- | package/hostapd/files/radiotap.h | 242 | ||||
-rw-r--r-- | package/hostapd/files/radiotap_iter.h | 41 | ||||
-rw-r--r-- | package/hostapd/patches/002-add-nl80211-driver.patch | 2968 | ||||
-rw-r--r-- | package/hostapd/patches/002-remove-michael-mic.patch | 34 | ||||
-rw-r--r-- | package/hostapd/patches/003-hook-up-nl80211-driver.patch (renamed from package/hostapd/patches/007-add-nl80211-driver.patch) | 0 | ||||
-rw-r--r-- | package/hostapd/patches/003-use-nl80211-for-keys.patch | 112 | ||||
-rw-r--r-- | package/hostapd/patches/004-use-nl80211-for-beacons.patch | 149 | ||||
-rw-r--r-- | package/hostapd/patches/005-use-nl80211-for-get-key.patch | 116 | ||||
-rw-r--r-- | package/hostapd/patches/006-use-nl80211-for-sta.patch | 413 |
12 files changed, 2968 insertions, 3781 deletions
diff --git a/package/hostapd/Makefile b/package/hostapd/Makefile index e38887cf7..f196828c9 100644 --- a/package/hostapd/Makefile +++ b/package/hostapd/Makefile @@ -77,11 +77,6 @@ define Build/ConfigureTarget $(PKG_BUILD_DIR)/hostapd \ $(PKG_BUILD_DIR)/src \ $(PKG_BUILD_DIR)/hostapd.$(1)/ - $(CP) ./files/driver_nl80211.c $(PKG_BUILD_DIR)/hostapd.$(1)/hostapd/ - $(CP) ./files/radiotap.c $(PKG_BUILD_DIR)/hostapd.$(1)/hostapd/ - $(CP) ./files/radiotap.h $(PKG_BUILD_DIR)/hostapd.$(1)/hostapd/ - $(CP) ./files/radiotap_iter.h $(PKG_BUILD_DIR)/hostapd.$(1)/hostapd/ - $(CP) ./files/$(1).config $(PKG_BUILD_DIR)/hostapd.$(1)/hostapd/.config $(if $(CONFIG_PACKAGE_kmod-mac80211),,$(SED) 's,^CONFIG_DRIVER_DEVICESCAPE,#CONFIG_DRIVER_DEVICESCAPE,g' $(PKG_BUILD_DIR)/hostapd.$(1)/hostapd/.config) $(if $(CONFIG_PACKAGE_kmod-madwifi),,$(SED) 's,^CONFIG_DRIVER_MADWIFI,#CONFIG_DRIVER_MADWIFI,g' $(PKG_BUILD_DIR)/hostapd.$(1)/hostapd/.config) diff --git a/package/hostapd/files/driver_nl80211.c b/package/hostapd/files/driver_nl80211.c deleted file mode 100644 index d673aa504..000000000 --- a/package/hostapd/files/driver_nl80211.c +++ /dev/null @@ -1,2382 +0,0 @@ -/* - * hostapd / Kernel driver communication via nl80211 - * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> - * Copyright (c) 2003-2004, Instant802 Networks, Inc. - * Copyright (c) 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> - * - * 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 - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" - -#include <sys/ioctl.h> -#include <netlink/genl/genl.h> -#include <netlink/genl/family.h> -#include <netlink/genl/ctrl.h> -#include <netlink/msg.h> -#include <netlink/attr.h> -#include <linux/nl80211.h> -#include <net/if.h> -#include <linux/if_packet.h> -#include <linux/if_ether.h> /* The L2 protocols */ -#include <linux/wireless.h> -#include <net/if_arp.h> - -#include "hostapd.h" -#include "driver.h" -#include "ieee802_1x.h" -#include "eloop.h" -#include "ieee802_11.h" -#include "sta_info.h" -#include "hw_features.h" -#include "mlme.h" -#include "radiotap.h" -#include "radiotap_iter.h" - -enum ieee80211_msg_type { - ieee80211_msg_normal = 0, - ieee80211_msg_tx_callback_ack = 1, - ieee80211_msg_tx_callback_fail = 2, -}; - -struct i802_driver_data { - struct hostapd_data *hapd; - - char iface[IFNAMSIZ + 1]; - int ioctl_sock; /* socket for ioctl() use */ - int wext_sock; /* socket for wireless events */ - int eapol_sock; /* socket for EAPOL frames */ - int monitor_sock; /* socket for monitor */ - int monitor_ifidx; - - int default_if_indices[16]; - int *if_indices; - int num_if_indices; - - int we_version; - struct nl_handle *nl_handle; - struct nl_cache *nl_cache; - struct genl_family *nl80211; - int dtim_period; - unsigned int beacon_set:1; - unsigned int ieee802_1x_active:1; -}; - - -static void add_ifidx(struct i802_driver_data *drv, int ifidx) -{ - int i; - int *old; - - for (i = 0; i < drv->num_if_indices; i++) { - if (drv->if_indices[i] == 0) { - drv->if_indices[i] = ifidx; - return; - } - } - - if (drv->if_indices != drv->default_if_indices) - old = drv->if_indices; - else - old = NULL; - - drv->if_indices = realloc(old, - sizeof(int) * (drv->num_if_indices + 1)); - if (!drv->if_indices) { - if (!old) - drv->if_indices = drv->default_if_indices; - else - drv->if_indices = old; - wpa_printf(MSG_ERROR, "Failed to reallocate memory for " - "interfaces"); - wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); - return; - } - drv->if_indices[drv->num_if_indices] = ifidx; - drv->num_if_indices++; -} - - -static void del_ifidx(struct i802_driver_data *drv, int ifidx) -{ - int i; - - for (i = 0; i < drv->num_if_indices; i++) { - if (drv->if_indices[i] == ifidx) { - drv->if_indices[i] = 0; - break; - } - } -} - - -static int have_ifidx(struct i802_driver_data *drv, int ifidx) -{ - int i; - - for (i = 0; i < drv->num_if_indices; i++) - if (drv->if_indices[i] == ifidx) - return 1; - - return 0; -} - - -/* helper for netlink get routines */ -static int ack_wait_handler(struct nl_msg *msg, void *arg) -{ - int *finished = arg; - - *finished = 1; - return NL_STOP; -} - - -static int hostapd_set_iface_flags(struct i802_driver_data *drv, - const char *ifname, int dev_up) -{ - struct ifreq ifr; - - if (drv->ioctl_sock < 0) - return -1; - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCGIFFLAGS]"); - wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)", - drv->iface); - return -1; - } - - if (dev_up) - ifr.ifr_flags |= IFF_UP; - else - ifr.ifr_flags &= ~IFF_UP; - - if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { - perror("ioctl[SIOCSIFFLAGS]"); - return -1; - } - - return 0; -} - - -static int i802_set_encryption(const char *iface, void *priv, const char *alg, - const u8 *addr, int idx, const u8 *key, - size_t key_len, int txkey) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int ret = -1; - int err = 0; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - if (strcmp(alg, "none") == 0) { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_KEY, 0); - } else { - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_KEY, 0); - NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); - if (strcmp(alg, "WEP") == 0) { - if (key_len == 5) - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - 0x000FAC01); - else - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, - 0x000FAC05); - } else if (strcmp(alg, "TKIP") == 0) - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02); - else if (strcmp(alg, "CCMP") == 0) - NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04); - else - goto out; - } - - if (addr) - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - (err = nl_wait_for_ack(drv->nl_handle)) < 0) { - if (err != -ENOENT) { - err = 0; - goto out; - } - } - - /* - * If we need to set the default TX key we do that below, - * otherwise we're done here. - */ - if (!txkey || addr) { - ret = 0; - goto out; - } - - nlmsg_free(msg); - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_KEY, 0); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - (err = nl_wait_for_ack(drv->nl_handle)) < 0) { - if (err != -ENOENT) { - err = 0; - goto out; - } - } - - ret = 0; - - out: - nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static inline int min_int(int a, int b) -{ - if (a < b) - return a; - return b; -} - - -static int get_key_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - /* - * TODO: validate the key index and mac address! - * Otherwise, there's a race condition as soon as - * the kernel starts sending key notifications. - */ - - if (tb[NL80211_ATTR_KEY_SEQ]) - memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), - min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); - return NL_SKIP; -} - - -static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, - int idx, u8 *seq) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - struct nl_cb *cb = NULL; - int ret = -1; - int err = 0; - int finished = 0; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_KEY, 0); - - if (addr) - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - - cb = nl_cb_alloc(NL_CB_CUSTOM); - if (!cb) - goto out; - - memset(seq, 0, 6); - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0) - goto out; - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_key_handler, seq); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); - - err = nl_recvmsgs(drv->nl_handle, cb); - - if (!finished) - err = nl_wait_for_ack(drv->nl_handle); - - if (err < 0) - goto out; - - ret = 0; - - out: - nl_cb_put(cb); - nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, - int mode) -{ - return -1; -} - - -static int i802_set_ssid(const char *ifname, void *priv, const u8 *buf, - int len) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); - iwr.u.essid.flags = 1; /* SSID active */ - iwr.u.essid.pointer = (caddr_t) buf; - iwr.u.essid.length = len; - - if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - printf("len=%d\n", len); - return -1; - } - - return 0; -} - - -static int i802_send_mgmt_frame(void *priv, const void *data, size_t len, - int flags) -{ - struct ieee80211_hdr *hdr = (void*) data; - __u8 rtap_hdr[] = { - 0x00, 0x00, /* radiotap version */ - 0x0e, 0x00, /* radiotap length */ - 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ - 0x0c, /* F_WEP | F_FRAG (encrypt/fragment if required) */ - 0x00, /* padding */ - 0x00, 0x00, /* RX and TX flags to indicate that */ - 0x00, 0x00, /* this is the injected frame directly */ - }; - struct i802_driver_data *drv = priv; - struct iovec iov[2] = { - { - .iov_base = &rtap_hdr, - .iov_len = sizeof(rtap_hdr), - }, - { - .iov_base = (void*)data, - .iov_len = len, - } - }; - struct msghdr msg = { - .msg_name = NULL, - .msg_namelen = 0, - .msg_iov = iov, - .msg_iovlen = 2, - .msg_control = NULL, - .msg_controllen = 0, - .msg_flags = 0, - }; - - /* - * ugh, guess what, the generic code sets one of the version - * bits to request tx callback - */ - hdr->frame_control &= ~host_to_le16(BIT(1)); - return sendmsg(drv->monitor_sock, &msg, flags); -} - - -/* Set kernel driver on given frequency (MHz) */ -static int i802_set_freq(void *priv, int mode, int freq) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - iwr.u.freq.m = freq; - iwr.u.freq.e = 6; - - if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { - perror("ioctl[SIOCSIWFREQ]"); - return -1; - } - - return 0; -} - - -static int i802_set_rts(void *priv, int rts) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - iwr.u.rts.value = rts; - iwr.u.rts.fixed = 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &iwr) < 0) { - perror("ioctl[SIOCSIWRTS]"); - return -1; - } - - return 0; -} - - -static int i802_get_rts(void *priv, int *rts) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &iwr) < 0) { - perror("ioctl[SIOCGIWRTS]"); - return -1; - } - - *rts = iwr.u.rts.value; - - return 0; -} - - -static int i802_set_frag(void *priv, int frag) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - iwr.u.frag.value = frag; - iwr.u.frag.fixed = 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { - perror("ioctl[SIOCSIWFRAG]"); - return -1; - } - - return 0; -} - - -static int i802_get_frag(void *priv, int *frag) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIWFRAG, &iwr) < 0) { - perror("ioctl[SIOCGIWFRAG]"); - return -1; - } - - *frag = iwr.u.frag.value; - - return 0; -} - - -static int i802_set_retry(void *priv, int short_retry, int long_retry) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - - iwr.u.retry.value = short_retry; - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; - if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { - perror("ioctl[SIOCSIWRETRY(short)]"); - return -1; - } - - iwr.u.retry.value = long_retry; - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { - perror("ioctl[SIOCSIWRETRY(long)]"); - return -1; - } - - return 0; -} - - -static int i802_get_retry(void *priv, int *short_retry, int *long_retry) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); - - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; - if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { - perror("ioctl[SIOCGIWFRAG(short)]"); - return -1; - } - *short_retry = iwr.u.retry.value; - - iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { - perror("ioctl[SIOCGIWFRAG(long)]"); - return -1; - } - *long_retry = iwr.u.retry.value; - - return 0; -} - - -static int i802_flush(void *priv) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_STATION, 0); - - /* - * XXX: FIX! this needs to flush all VLANs too - */ - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - - ret = 0; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { - ret = -1; - } - - nla_put_failure: - nlmsg_free(msg); - - out: - return ret; -} - - -static int get_sta_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct hostap_sta_driver_data *data = arg; - struct nlattr *stats[NL80211_STA_STAT_MAX + 1]; - static struct nla_policy stats_policy[NL80211_STA_STAT_MAX + 1] = { - [NL80211_STA_STAT_INACTIVE_TIME] = { .type = NLA_U32 }, - [NL80211_STA_STAT_RX_BYTES] = { .type = NLA_U32 }, - [NL80211_STA_STAT_TX_BYTES] = { .type = NLA_U32 }, - }; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - /* - * TODO: validate the interface and mac address! - * Otherwise, there's a race condition as soon as - * the kernel starts sending station notifications. - */ - - if (!tb[NL80211_ATTR_STA_STATS]) { - wpa_printf(MSG_DEBUG, "sta stats missing!"); - return NL_SKIP; - } - if (nla_parse_nested(stats, NL80211_STA_STAT_MAX, - tb[NL80211_ATTR_STA_STATS], - stats_policy)) { - wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); - return NL_SKIP; - } - - if (stats[NL80211_STA_STAT_INACTIVE_TIME]) - data->inactive_msec = - nla_get_u32(stats[NL80211_STA_STAT_INACTIVE_TIME]); - if (stats[NL80211_STA_STAT_RX_BYTES]) - data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_RX_BYTES]); - if (stats[NL80211_STA_STAT_TX_BYTES]) - data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_TX_BYTES]); - - return NL_SKIP; -} - -static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, - const u8 *addr) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - struct nl_cb *cb = NULL; - int ret = -1; - int err = 0; - int finished = 0; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_STATION, 0); - - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - cb = nl_cb_alloc(NL_CB_CUSTOM); - if (!cb) - goto out; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0) - goto out; - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_sta_handler, data); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); - - err = nl_recvmsgs(drv->nl_handle, cb); - - if (!finished) - err = nl_wait_for_ack(drv->nl_handle); - - if (err < 0) - goto out; - - ret = 0; - - out: - nl_cb_put(cb); - nla_put_failure: - nlmsg_free(msg); - return ret; - -} - - -static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, const u8 *own_addr) -{ - struct i802_driver_data *drv = priv; - struct ieee80211_hdr *hdr; - size_t len; - u8 *pos; - int res; -#if 0 /* FIX */ - int qos = sta->flags & WLAN_STA_WME; -#else - int qos = 0; -#endif - - len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + - data_len; - hdr = os_zalloc(len); - if (hdr == NULL) { - printf("malloc() failed for i802_send_data(len=%lu)\n", - (unsigned long) len); - return -1; - } - - hdr->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); - hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); - if (encrypt) - hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); -#if 0 /* To be enabled if qos determination is added above */ - if (qos) { - hdr->frame_control |= - host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); - } -#endif - - memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); - memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); - memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); - pos = (u8 *) (hdr + 1); - -#if 0 /* To be enabled if qos determination is added above */ - if (qos) { - /* add an empty QoS header if needed */ - pos[0] = 0; - pos[1] = 0; - pos += 2; - } -#endif - - memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); - pos += sizeof(rfc1042_header); - WPA_PUT_BE16(pos, ETH_P_PAE); - pos += 2; - memcpy(pos, data, data_len); - - res = i802_send_mgmt_frame(drv, (u8 *) hdr, len, 0); - free(hdr); - - if (res < 0) { - perror("i802_send_eapol: send"); - printf("i802_send_eapol - packet len: %lu - failed\n", - (unsigned long) len); - } - - return res; -} - - -static int i802_sta_add(const char *ifname, void *priv, const u8 *addr, - u16 aid, u16 capability, u8 *supp_rates, - size_t supp_rates_len, int flags) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_STATION, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, aid); - NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len, - supp_rates); - NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 0); - - ret = nl_send_auto_complete(drv->nl_handle, msg); - if (ret < 0) - goto nla_put_failure; - - ret = nl_wait_for_ack(drv->nl_handle); - /* ignore EEXIST, this happens if a STA associates while associated */ - if (ret == -EEXIST || ret >= 0) - ret = 0; - - nla_put_failure: - nlmsg_free(msg); - - out: - return ret; -} - - -static int i802_sta_remove(void *priv, const u8 *addr) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_STATION, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - - ret = 0; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { - ret = -1; - } - - nla_put_failure: - nlmsg_free(msg); - - out: - return ret; -} - - -static int i802_sta_set_flags(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg, *flags = NULL; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - flags = nlmsg_alloc(); - if (!flags) - goto free_msg; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - - if (total_flags & WLAN_STA_AUTHORIZED || !drv->ieee802_1x_active) - NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); - - if (total_flags & WLAN_STA_WME) - NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); - - if (total_flags & WLAN_STA_SHORT_PREAMBLE) - NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); - - if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) - goto nla_put_failure; - - ret = 0; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { - ret = -1; - } - - nla_put_failure: - nlmsg_free(flags); - - free_msg: - nlmsg_free(msg); - - out: - return ret; -} - - -static int i802_set_channel_flag(void *priv, int mode, int chan, int flag, - unsigned char power_level, - unsigned char antenna_max) -{ - return -1; -} - - -static int i802_set_regulatory_domain(void *priv, unsigned int rd) -{ - return -1; -} - - -static int i802_set_tx_queue_params(void *priv, int queue, int aifs, - int cw_min, int cw_max, int burst_time) -{ - return -1; -} - - -static void nl80211_remove_iface(struct i802_driver_data *drv, int ifidx) -{ - struct nl_msg *msg; - - /* stop listening for EAPOL on this interface */ - del_ifidx(drv, ifidx); - - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - nla_put_failure: - printf("Failed to remove interface.\n"); - nlmsg_free(msg); -} - - -static int nl80211_create_iface(struct i802_driver_data *drv, - const char *ifname, - enum nl80211_iftype iftype, - const u8 *addr) -{ - struct nl_msg *msg, *flags = NULL; - int ifidx; - struct ifreq ifreq; - struct iwreq iwr; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_NEW_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->hapd->conf->iface)); - NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); - - if (iftype == NL80211_IFTYPE_MONITOR) { - int err; - - flags = nlmsg_alloc(); - if (!flags) - goto nla_put_failure; - - NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); - - err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); - - nlmsg_free(flags); - - if (err) - goto nla_put_failure; - } - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { - nla_put_failure: - printf("Failed to create interface %s.\n", ifname); - nlmsg_free(msg); - return -1; - } - - nlmsg_free(msg); - - ifidx = if_nametoindex(ifname); - - if (ifidx <= 0) - return -1; - - /* start listening for EAPOL on this interface */ - add_ifidx(drv, ifidx); - - if (addr) { - switch (iftype) { - case NL80211_IFTYPE_AP: - os_strlcpy(ifreq.ifr_name, ifname, IFNAMSIZ); - memcpy(ifreq.ifr_hwaddr.sa_data, addr, ETH_ALEN); - ifreq.ifr_hwaddr.sa_family = ARPHRD_ETHER; - - if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifreq)) { - nl80211_remove_iface(drv, ifidx); - return -1; - } - break; - case NL80211_IFTYPE_WDS: - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); - iwr.u.addr.sa_family = ARPHRD_ETHER; - memcpy(iwr.u.addr.sa_data, addr, ETH_ALEN); - if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr)) - return -1; - break; - default: - /* nothing */ - break; - } - } - - return ifidx; -} - - -static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid) -{ - int ifidx; - - /* - * The kernel supports that when the low-level driver does, - * but we currently don't because we need per-BSS data that - * currently we can't handle easily. - */ - return -1; - - ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid); - if (ifidx < 0) - return -1; - if (hostapd_set_iface_flags(priv, ifname, 1)) { - nl80211_remove_iface(priv, ifidx); - return -1; - } - return 0; -} - - -static int i802_bss_remove(void *priv, const char *ifname) -{ - nl80211_remove_iface(priv, if_nametoindex(ifname)); - return 0; -} - - -static int i802_set_beacon(const char *iface, void *priv, - u8 *head, size_t head_len, - u8 *tail, size_t tail_len) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - u8 cmd = NL80211_CMD_NEW_BEACON; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - if (drv->beacon_set) - cmd = NL80211_CMD_SET_BEACON; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, cmd, 0); - NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); - NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, 1000); - - if (!drv->dtim_period) - drv->dtim_period = 2; - NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - goto out; - - ret = 0; - - drv->beacon_set = 1; - - out: - nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int i802_del_beacon(struct i802_driver_data *drv) -{ - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_DEL_BEACON, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - goto out; - - ret = 0; - - out: - nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int i802_set_ieee8021x(const char *ifname, void *priv, int enabled) -{ - struct i802_driver_data *drv = priv; - - /* - * FIXME: This needs to be per interface (BSS) - */ - drv->ieee802_1x_active = enabled; - return 0; -} - - -static int i802_set_privacy(const char *ifname, void *priv, int enabled) -{ - struct i802_driver_data *drv = priv; - struct iwreq iwr; - - memset(&iwr, 0, sizeof(iwr)); - - os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); - iwr.u.param.flags = IW_AUTH_PRIVACY_INVOKED; - iwr.u.param.value = enabled; - - ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr); - - /* ignore errors, the kernel/driver might not care */ - return 0; -} - - -static int i802_set_internal_bridge(void *priv, int value) -{ - return -1; -} - - -static int i802_set_beacon_int(void *priv, int value) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_BEACON, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value); - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - goto out; - - ret = 0; - - out: - nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int i802_set_dtim_period(const char *iface, void *priv, int value) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_BEACON, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); - - drv->dtim_period = value; - NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) - goto out; - - ret = 0; - - out: - nla_put_failure: - nlmsg_free(msg); - return ret; -} - - -static int i802_set_cts_protect(void *priv, int value) -{ - return -1; -} - - -static int i802_set_preamble(void *priv, int value) -{ - return -1; -} - - -static int i802_set_short_slot_time(void *priv, int value) -{ - return -1; -} - - -static enum nl80211_iftype i802_if_type(enum hostapd_driver_if_type type) -{ - switch (type) { - case HOSTAPD_IF_VLAN: - return NL80211_IFTYPE_AP_VLAN; - case HOSTAPD_IF_WDS: - return NL80211_IFTYPE_WDS; - } - return -1; -} - - -static int i802_if_add(const char *iface, void *priv, - enum hostapd_driver_if_type type, char *ifname, - const u8 *addr) -{ - if (nl80211_create_iface(priv, ifname, i802_if_type(type), addr) < 0) - return -1; - return 0; -} - - -static int i802_if_update(void *priv, enum hostapd_driver_if_type type, - char *ifname, const u8 *addr) -{ - /* unused at the moment */ - return -1; -} - - -static int i802_if_remove(void *priv, enum hostapd_driver_if_type type, - const char *ifname, const u8 *addr) -{ - nl80211_remove_iface(priv, if_nametoindex(ifname)); - return 0; -} - - -struct phy_info_arg { - u16 *num_modes; - struct hostapd_hw_modes *modes; - int error; -}; - -static int phy_info_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct phy_info_arg *phy_info = arg; - - struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; - - struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; - static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { - [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, - [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, - }; - - struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; - static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { - [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, - [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, - }; - - struct nlattr *nl_band; - struct nlattr *nl_freq; - struct nlattr *nl_rate; - int rem_band, rem_freq, rem_rate; - struct hostapd_hw_modes *mode; - int idx, mode_is_set; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) - return NL_SKIP; - - nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { - mode = realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode)); - if (!mode) - return NL_SKIP; - phy_info->modes = mode; - - mode_is_set = 0; - - mode = &phy_info->modes[*(phy_info->num_modes)]; - memset(mode, 0, sizeof(*mode)); - *(phy_info->num_modes) += 1; - - nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), - nla_len(nl_band), NULL); - - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), - nla_len(nl_freq), freq_policy); - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - mode->num_channels++; - } - - mode->channels = calloc(mode->num_channels, sizeof(struct hostapd_channel_data)); - if (!mode->channels) - return NL_SKIP; - - idx = 0; - - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), - nla_len(nl_freq), freq_policy); - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - - mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); - mode->channels[idx].flag |= HOSTAPD_CHAN_W_SCAN | - HOSTAPD_CHAN_W_ACTIVE_SCAN | - HOSTAPD_CHAN_W_IBSS; - - if (!mode_is_set) { - /* crude heuristic */ - if (mode->channels[idx].freq < 4000) - mode->mode = HOSTAPD_MODE_IEEE80211B; - else - mode->mode = HOSTAPD_MODE_IEEE80211A; - mode_is_set = 1; - } - - /* crude heuristic */ - if (mode->channels[idx].freq < 4000) - if (mode->channels[idx].freq == 2848) - mode->channels[idx].chan = 14; - else - mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5; - else - mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000; - - if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) - mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_SCAN; - if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) - mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_ACTIVE_SCAN; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) - mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_IBSS; - idx++; - } - - nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), - nla_len(nl_rate), rate_policy); - if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) - continue; - mode->num_rates++; - } - - mode->rates = calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); - if (!mode->rates) - return NL_SKIP; - - idx = 0; - - nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), - nla_len(nl_rate), rate_policy); - if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) - continue; - mode->rates[idx].rate = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); - - /* crude heuristic */ - if (mode->mode == HOSTAPD_MODE_IEEE80211B && - mode->rates[idx].rate > 200) - mode->mode = HOSTAPD_MODE_IEEE80211G; - - if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE]) - mode->rates[idx].flags |= HOSTAPD_RATE_PREAMBLE2; - - idx++; - } - } - - phy_info->error = 0; - - return NL_SKIP; -} - -static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv, - u16 *num_modes, - u16 *flags) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int err = -1; - struct nl_cb *cb = NULL; - int finished; - struct phy_info_arg result = { - .num_modes = num_modes, - .modes = NULL, - .error = 1, - }; - - *num_modes = 0; - *flags = 0; - - msg = nlmsg_alloc(); - if (!msg) - return NULL; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_GET_WIPHY, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); - - cb = nl_cb_alloc(NL_CB_CUSTOM); - if (!cb) - goto out; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0) - goto out; - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, phy_info_handler, &result); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); - - err = nl_recvmsgs(drv->nl_handle, cb); - - if (!finished) - err = nl_wait_for_ack(drv->nl_handle); - - if (err < 0 || result.error) { - hostapd_free_hw_features(result.modes, *num_modes); - result.modes = NULL; - } - - out: - nl_cb_put(cb); - nla_put_failure: - if (err) - fprintf(stderr, "failed to get information: %d\n", err); - nlmsg_free(msg); - return result.modes; -} - - -static int i802_set_sta_vlan(void *priv, const u8 *addr, - const char *ifname, int vlan_id) -{ - struct i802_driver_data *drv = priv; - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - goto out; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_STATION, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(drv->iface)); - NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(ifname)); - - ret = 0; - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - (errno = nl_wait_for_ack(drv->nl_handle) < 0)) { - ret = -1; - } - - nla_put_failure: - nlmsg_free(msg); - - out: - return ret; -} - - -static void handle_unknown_sta(struct hostapd_data *hapd, u8 *ta) -{ - struct sta_info *sta; - - sta = ap_get_sta(hapd, ta); - if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { - printf("Data/PS-poll frame from not associated STA " - MACSTR "\n", MAC2STR(ta)); - if (sta && (sta->flags & WLAN_STA_AUTH)) - hostapd_sta_disassoc( - hapd, ta, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - else - hostapd_sta_deauth( - hapd, ta, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); - } -} - - -static void handle_tx_callback(struct hostapd_data *hapd, 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); - - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - switch (type) { - 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); - break; - case WLAN_FC_TYPE_CTRL: - wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s", - ok ? "ACK" : "fail"); - break; - 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); - break; - default: - printf("unknown TX callback frame type %d\n", type); - break; - } -} - - -static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len, - struct hostapd_frame_info *hfi, - enum ieee80211_msg_type msg_type) -{ - struct ieee80211_hdr *hdr; - u16 fc, type, stype; - size_t data_len = len; - struct hostapd_data *hapd = NULL; - int broadcast_bssid = 0; - size_t i; - u8 *bssid; - - /* - * PS-Poll frames are 16 bytes. All other frames are - * 24 bytes or longer. - */ - if (len < 16) - return; - - hdr = (struct ieee80211_hdr *) buf; - fc = le_to_host16(hdr->frame_control); - - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - switch (type) { - case WLAN_FC_TYPE_DATA: - if (len < 24) - return; - switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { - case WLAN_FC_TODS: - bssid = hdr->addr1; - break; - default: - /* discard */ - return; - } - break; - case WLAN_FC_TYPE_CTRL: - /* discard non-ps-poll frames */ - if (stype != WLAN_FC_STYPE_PSPOLL) - return; - bssid = hdr->addr1; - break; - case WLAN_FC_TYPE_MGMT: - bssid = hdr->addr3; - break; - default: - /* discard */ - return; - } - - /* find interface frame belongs to */ - for (i = 0; i < iface->num_bss; i++) { - if (memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) { - hapd = iface->bss[i]; - break; - } - } - - if (hapd == NULL) { - hapd = iface->bss[0]; - - if (bssid[0] != 0xff || bssid[1] != 0xff || - bssid[2] != 0xff || bssid[3] != 0xff || - bssid[4] != 0xff || bssid[5] != 0xff) { - /* - * Unknown BSSID - drop frame if this is not from - * passive scanning or a beacon (at least ProbeReq - * frames to other APs may be allowed through RX - * filtering in the wlan hw/driver) - */ - if ((type != WLAN_FC_TYPE_MGMT || - stype != WLAN_FC_STYPE_BEACON)) - return; - } else - broadcast_bssid = 1; - } - - switch (msg_type) { - case ieee80211_msg_normal: - /* continue processing */ - break; - case ieee80211_msg_tx_callback_ack: - handle_tx_callback(hapd, buf, data_len, 1); - return; - case ieee80211_msg_tx_callback_fail: - handle_tx_callback(hapd, buf, data_len, 0); - return; - } - - switch (type) { - case WLAN_FC_TYPE_MGMT: - if (stype != WLAN_FC_STYPE_BEACON && - stype != WLAN_FC_STYPE_PROBE_REQ) - wpa_printf(MSG_MSGDUMP, "MGMT"); - if (broadcast_bssid) { - for (i = 0; i < iface->num_bss; i++) - ieee802_11_mgmt(iface->bss[i], buf, data_len, - stype, hfi); - } else - ieee802_11_mgmt(hapd, buf, data_len, stype, hfi); - break; - case WLAN_FC_TYPE_CTRL: - /* can only get here with PS-Poll frames */ - wpa_printf(MSG_DEBUG, "CTRL"); - handle_unknown_sta(hapd, hdr->addr2); - break; - case WLAN_FC_TYPE_DATA: - wpa_printf(MSG_DEBUG, "DATA"); - handle_unknown_sta(hapd, hdr->addr2); - break; - } -} - - -static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct i802_driver_data *drv = eloop_ctx; - struct hostapd_data *hapd = drv->hapd; - struct sockaddr_ll lladdr; - unsigned char buf[3000]; - int len; - socklen_t fromlen = sizeof(lladdr); - - len = recvfrom(sock, buf, sizeof(buf), 0, - (struct sockaddr *)&lladdr, &fromlen); - if (len < 0) { - perror("recv"); - return; - } - - if (have_ifidx(drv, lladdr.sll_ifindex)) - ieee802_1x_receive(hapd, lladdr.sll_addr, buf, len); -} - - -static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct i802_driver_data *drv = eloop_ctx; - int len; - unsigned char buf[3000]; - struct hostapd_data *hapd = drv->hapd; - struct ieee80211_radiotap_iterator iter; - int ret; - struct hostapd_frame_info hfi; - int injected = 0, failed = 0, msg_type, rxflags = 0; - - len = recv(sock, buf, sizeof(buf), 0); - if (len < 0) { - perror("recv"); - return; - } - - if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { - printf("received invalid radiotap frame\n"); - return; - } - - memset(&hfi, 0, sizeof(hfi)); - - while (1) { - ret = ieee80211_radiotap_iterator_next(&iter); - if (ret == -ENOENT) - break; - if (ret) { - printf("received invalid radiotap frame (%d)\n", ret); - return; - } - switch (iter.this_arg_index) { - case IEEE80211_RADIOTAP_FLAGS: - if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) - len -= 4; - break; - case IEEE80211_RADIOTAP_RX_FLAGS: - rxflags = 1; - break; - case IEEE80211_RADIOTAP_TX_FLAGS: - injected = 1; - failed = le_to_host16((*(uint16_t *) iter.this_arg)) & - IEEE80211_RADIOTAP_F_TX_FAIL; - break; - case IEEE80211_RADIOTAP_DATA_RETRIES: - break; - case IEEE80211_RADIOTAP_CHANNEL: - /* TODO convert from freq/flags to channel number - hfi.channel = XXX; - hfi.phytype = XXX; - */ - break; - case IEEE80211_RADIOTAP_RATE: - hfi.datarate = *iter.this_arg * 5; - break; - case IEEE80211_RADIOTAP_DB_ANTSIGNAL: - hfi.ssi_signal = *iter.this_arg; - break; - } - } - - if (rxflags && injected) - return; - - if (!injected) - msg_type = ieee80211_msg_normal; - else if (failed) - msg_type = ieee80211_msg_tx_callback_fail; - else - msg_type = ieee80211_msg_tx_callback_ack; - - handle_frame(hapd->iface, buf + iter.max_length, - len - iter.max_length, &hfi, msg_type); -} - - -static int nl80211_create_monitor_interface(struct i802_driver_data *drv) -{ - char buf[IFNAMSIZ]; - struct sockaddr_ll ll; - int optval; - socklen_t optlen; - - snprintf(buf, IFNAMSIZ, "mon.%s", drv->iface); - buf[IFNAMSIZ - 1] = '\0'; - - drv->monitor_ifidx = - nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL); - - if (drv->monitor_ifidx < 0) - return -1; - - if (hostapd_set_iface_flags(drv, buf, 1)) - goto error; - - memset(&ll, 0, sizeof(ll)); - ll.sll_family = AF_PACKET; - ll.sll_ifindex = drv->monitor_ifidx; - drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (drv->monitor_sock < 0) { - perror("socket[PF_PACKET,SOCK_RAW]"); - goto error; - } - - if (bind(drv->monitor_sock, (struct sockaddr *) &ll, - sizeof(ll)) < 0) { - perror("monitor socket bind"); - goto error; - } - - optlen = sizeof(optval); - optval = 20; - if (setsockopt - (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { - perror("Failed to set socket priority"); - goto error; - } - - if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, - drv, NULL)) { - printf("Could not register monitor read socket\n"); - goto error; - } - - return 0; - error: - nl80211_remove_iface(drv, drv->monitor_ifidx); - return -1; -} - - -static int nl80211_set_master_mode(struct i802_driver_data *drv, - const char *ifname) -{ - struct nl_msg *msg; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, - 0, NL80211_CMD_SET_INTERFACE, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, - if_nametoindex(ifname)); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP); - - if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || - nl_wait_for_ack(drv->nl_handle) < 0) { - nla_put_failure: - wpa_printf(MSG_ERROR, "Failed to set interface %s to master " - "mode.", ifname); - nlmsg_free(msg); - return -1; - } - - nlmsg_free(msg); - - return 0; -} - - -static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid) -{ - struct ifreq ifr; - struct sockaddr_ll addr; - - drv->ioctl_sock = -1; - - drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (drv->ioctl_sock < 0) { - perror("socket[PF_INET,SOCK_DGRAM]"); - return -1; - } - - /* start listening for EAPOL on the default AP interface */ - add_ifidx(drv, if_nametoindex(drv->iface)); - - if (hostapd_set_iface_flags(drv, drv->iface, 0)) - return -1; - - if (bssid) { - os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); - memcpy(ifr.ifr_hwaddr.sa_data, bssid, ETH_ALEN); - ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; - - if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) { - perror("ioctl(SIOCSIFHWADDR)"); - return -1; - } - } - - /* - * initialise generic netlink and nl80211 - */ - drv->nl_handle = nl_handle_alloc(); - if (!drv->nl_handle) { - printf("Failed to allocate netlink handle.\n"); - return -1; - } - - if (genl_connect(drv->nl_handle)) { - printf("Failed to connect to generic netlink.\n"); - return -1; - } - - drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle); - if (!drv->nl_cache) { - printf("Failed to allocate generic netlink cache.\n"); - return -1; - } - - drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211"); - if (!drv->nl80211) { - printf("nl80211 not found.\n"); - return -1; - } - - /* Initialise a monitor interface */ - if (nl80211_create_monitor_interface(drv)) - return -1; - - if (nl80211_set_master_mode(drv, drv->iface)) - return -1; - - if (hostapd_set_iface_flags(drv, drv->iface, 1)) - return -1; - - memset(&addr, 0, sizeof(addr)); - addr.sll_family = AF_PACKET; - addr.sll_ifindex = ifr.ifr_ifindex; - wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", - addr.sll_ifindex); - - drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); - if (drv->eapol_sock < 0) { - perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); - return -1; - } - - if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) - { - printf("Could not register read socket for eapol\n"); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); - if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) { - perror("ioctl(SIOCGIFHWADDR)"); - return -1; - } - - if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - printf("Invalid HW-addr family 0x%04x\n", - ifr.ifr_hwaddr.sa_family); - return -1; - } - memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); - - return 0; -} - - -static int i802_get_inact_sec(void *priv, const u8 *addr) -{ - struct hostap_sta_driver_data data; - int ret; - - data.inactive_msec = (unsigned long) -1; - ret = i802_read_sta_data(priv, &data, addr); - if (ret || data.inactive_msec == (unsigned long) -1) - return -1; - return data.inactive_msec / 1000; -} - - -static int i802_sta_clear_stats(void *priv, const u8 *addr) -{ -#if 0 - /* TODO */ -#endif - return 0; -} - - -static void -hostapd_wireless_event_wireless_custom(struct i802_driver_data *drv, - char *custom) -{ - wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); - - if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - char *pos; - u8 addr[ETH_ALEN]; - pos = strstr(custom, "addr="); - if (pos == NULL) { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "without sender address ignored"); - return; - } - pos += 5; - if (hwaddr_aton(pos, addr) == 0) { - ieee80211_michael_mic_failure(drv->hapd, addr, 1); - } else { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "with invalid MAC address"); - } - } -} - - -static void hostapd_wireless_event_wireless(struct i802_driver_data *drv, - char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom, *buf; - - pos = data; - end = data + len; - - while (pos + IW_EV_LCP_LEN <= end) { - /* Event data may be unaligned, so make a local, aligned copy - * before processing. */ - memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", - iwe->cmd, iwe->len); - if (iwe->len <= IW_EV_LCP_LEN) - return; - - custom = pos + IW_EV_POINT_LEN; - if (drv->we_version > 18 && - (iwe->cmd == IWEVMICHAELMICFAILURE || - iwe->cmd == IWEVCUSTOM)) { - /* WE-19 removed the pointer from struct iw_point */ - char *dpos = (char *) &iwe_buf.u.data.length; - int dlen = dpos - (char *) &iwe_buf; - memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { - case IWEVCUSTOM: - if (custom + iwe->u.data.length > end) - return; - buf = malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; - memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - hostapd_wireless_event_wireless_custom(drv, buf); - free(buf); - break; - } - - pos += iwe->len; - } -} - - -static void hostapd_wireless_event_rtm_newlink(struct i802_driver_data *drv, - struct nlmsghdr *h, int len) -{ - struct ifinfomsg *ifi; - int attrlen, nlmsg_len, rta_len; - struct rtattr *attr; - - if (len < (int) sizeof(*ifi)) - return; - - ifi = NLMSG_DATA(h); - - /* TODO: use ifi->ifi_index to filter out wireless events from other - * interfaces */ - - nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); - - attrlen = h->nlmsg_len - nlmsg_len; - if (attrlen < 0) - return; - - attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); - - rta_len = RTA_ALIGN(sizeof(struct rtattr)); - while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - hostapd_wireless_event_wireless( - drv, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } - attr = RTA_NEXT(attr, attrlen); - } -} - - -static void hostapd_wireless_event_receive(int sock, void *eloop_ctx, - void *sock_ctx) -{ - char buf[256]; - int left; - struct sockaddr_nl from; - socklen_t fromlen; - struct nlmsghdr *h; - struct i802_driver_data *drv = eloop_ctx; - - fromlen = sizeof(from); - left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *) &from, &fromlen); - if (left < 0) { - if (errno != EINTR && errno != EAGAIN) - perror("recvfrom(netlink)"); - return; - } - - h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { - int len, plen; - - len = h->nlmsg_len; - plen = len - sizeof(*h); - if (len > left || plen < 0) { - printf("Malformed netlink message: " - "len=%d left=%d plen=%d\n", - len, left, plen); - break; - } - - switch (h->nlmsg_type) { - case RTM_NEWLINK: - hostapd_wireless_event_rtm_newlink(drv, h, plen); - break; - } - - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); - } - - if (left > 0) { - printf("%d extra bytes in the end of netlink message\n", left); - } -} - - -static int hostap_get_we_version(struct i802_driver_data *drv) -{ - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; - - drv->we_version = 0; - - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; - - memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); - - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->we_version = range->we_version_compiled; - } - - free(range); - return 0; -} - - -static int i802_wireless_event_init(void *priv) -{ - struct i802_driver_data *drv = priv; - int s; - struct sockaddr_nl local; - - hostap_get_we_version(drv); - - drv->wext_sock = -1; - - s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (s < 0) { - perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); - return -1; - } - - memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { - perror("bind(netlink)"); - close(s); - return -1; - } - - eloop_register_read_sock(s, hostapd_wireless_event_receive, drv, - NULL); - drv->wext_sock = s; - - return 0; -} - - -static void i802_wireless_event_deinit(void *priv) -{ - struct i802_driver_data *drv = priv; - if (drv->wext_sock < 0) - return; - eloop_unregister_read_sock(drv->wext_sock); - close(drv->wext_sock); -} - - -static int i802_sta_deauth(void *priv, const u8 *addr, int reason) -{ - struct i802_driver_data *drv = priv; - struct ieee80211_mgmt mgmt; - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DEAUTH); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); - memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); - mgmt.u.deauth.reason_code = host_to_le16(reason); - return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), 0); -} - - -static int i802_sta_disassoc(void *priv, const u8 *addr, int reason) -{ - struct i802_driver_data *drv = priv; - struct ieee80211_mgmt mgmt; - - memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DISASSOC); - memcpy(mgmt.da, addr, ETH_ALEN); - memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); - memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); - mgmt.u.disassoc.reason_code = host_to_le16(reason); - return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc), 0); -} - - -static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid) -{ - struct i802_driver_data *drv; - - drv = os_zalloc(sizeof(struct i802_driver_data)); - if (drv == NULL) { - printf("Could not allocate memory for i802 driver data\n"); - return NULL; - } - - drv->hapd = hapd; - memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); - - drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); - drv->if_indices = drv->default_if_indices; - - if (i802_init_sockets(drv, bssid)) - goto failed; - - return drv; - -failed: - free(drv); - return NULL; -} - - -static void *i802_init(struct hostapd_data *hapd) -{ - return i802_init_bssid(hapd, NULL); -} - - -static void i802_deinit(void *priv) -{ - struct i802_driver_data *drv = priv; - - i802_del_beacon(drv); - - /* remove monitor interface */ - nl80211_remove_iface(drv, drv->monitor_ifidx); - - (void) hostapd_set_iface_flags(drv, drv->iface, 0); - - if (drv->monitor_sock >= 0) { - eloop_unregister_read_sock(drv->monitor_sock); - close(drv->monitor_sock); - } - if (drv->ioctl_sock >= 0) - close(drv->ioctl_sock); - if (drv->eapol_sock >= 0) { - eloop_unregister_read_sock(drv->eapol_sock); - close(drv->eapol_sock); - } - - genl_family_put(drv->nl80211); - nl_cache_free(drv->nl_cache); - nl_handle_destroy(drv->nl_handle); - - if (drv->if_indices != drv->default_if_indices) - free(drv->if_indices); - - free(drv); -} - - -const struct wpa_driver_ops wpa_driver_nl80211_ops = { - .name = "nl80211", - .init = i802_init, -// .init_bssid = i802_init_bssid, - .deinit = i802_deinit, - .wireless_event_init = i802_wireless_event_init, - .wireless_event_deinit = i802_wireless_event_deinit, - .set_ieee8021x = i802_set_ieee8021x, - .set_privacy = i802_set_privacy, - .set_encryption = i802_set_encryption, - .get_seqnum = i802_get_seqnum, - .flush = i802_flush, - .read_sta_data = i802_read_sta_data, - .send_eapol = i802_send_eapol, - .sta_set_flags = i802_sta_set_flags, - .sta_deauth = i802_sta_deauth, - .sta_disassoc = i802_sta_disassoc, - .sta_remove = i802_sta_remove, - .set_ssid = i802_set_ssid, - .send_mgmt_frame = i802_send_mgmt_frame, - .sta_add = i802_sta_add, - .get_inact_sec = i802_get_inact_sec, - .sta_clear_stats = i802_sta_clear_stats, - .set_freq = i802_set_freq, - .set_rts = i802_set_rts, - .get_rts = i802_get_rts, - .set_frag = i802_set_frag, - .get_frag = i802_get_frag, - .set_retry = i802_set_retry, - .get_retry = i802_get_retry, - .set_rate_sets = i802_set_rate_sets, - .set_channel_flag = i802_set_channel_flag, - .set_regulatory_domain = i802_set_regulatory_domain, - .set_beacon = i802_set_beacon, - .set_internal_bridge = i802_set_internal_bridge, - .set_beacon_int = i802_set_beacon_int, - .set_dtim_period = i802_set_dtim_period, - .set_cts_protect = i802_set_cts_protect, - .set_preamble = i802_set_preamble, - .set_short_slot_time = i802_set_short_slot_time, - .set_tx_queue_params = i802_set_tx_queue_params, - .bss_add = i802_bss_add, - .bss_remove = i802_bss_remove, - .if_add = i802_if_add, - .if_update = i802_if_update, - .if_remove = i802_if_remove, - .get_hw_feature_data = i802_get_hw_feature_data, - .set_sta_vlan = i802_set_sta_vlan, -}; diff --git a/package/hostapd/files/radiotap.c b/package/hostapd/files/radiotap.c deleted file mode 100644 index 804473fa4..000000000 --- a/package/hostapd/files/radiotap.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Radiotap parser - * - * Copyright 2007 Andy Green <andy@warmcat.com> - * - * 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 - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - * - * - * Modified for userspace by Johannes Berg <johannes@sipsolutions.net> - * I only modified some things on top to ease syncing should bugs be found. - */ - -#include "includes.h" - -#include "common.h" -#include "radiotap_iter.h" - -#define le16_to_cpu le_to_host16 -#define le32_to_cpu le_to_host32 -#define __le32 uint32_t -#define ulong unsigned long -#define unlikely(cond) (cond) -#define get_unaligned(p) \ -({ \ - struct packed_dummy_struct { \ - typeof(*(p)) __val; \ - } __attribute__((packed)) *__ptr = (void *) (p); \ - \ - __ptr->__val; \ -}) - -/* function prototypes and related defs are in radiotap_iter.h */ - -/** - * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization - * @iterator: radiotap_iterator to initialize - * @radiotap_header: radiotap header to parse - * @max_length: total length we can parse into (eg, whole packet length) - * - * Returns: 0 or a negative error code if there is a problem. - * - * This function initializes an opaque iterator struct which can then - * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap - * argument which is present in the header. It knows about extended - * present headers and handles them. - * - * How to use: - * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator - * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) - * checking for a good 0 return code. Then loop calling - * __ieee80211_radiotap_iterator_next()... it returns either 0, - * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. - * The iterator's @this_arg member points to the start of the argument - * associated with the current argument index that is present, which can be - * found in the iterator's @this_arg_index member. This arg index corresponds - * to the IEEE80211_RADIOTAP_... defines. - * - * Radiotap header length: - * You can find the CPU-endian total radiotap header length in - * iterator->max_length after executing ieee80211_radiotap_iterator_init() - * successfully. - * - * Alignment Gotcha: - * You must take care when dereferencing iterator.this_arg - * for multibyte types... the pointer is not aligned. Use - * get_unaligned((type *)iterator.this_arg) to dereference - * iterator.this_arg for type "type" safely on all arches. - * - * Example code: - * See Documentation/networking/radiotap-headers.txt - */ - -int ieee80211_radiotap_iterator_init( - struct ieee80211_radiotap_iterator *iterator, - struct ieee80211_radiotap_header *radiotap_header, - int max_length) -{ - /* Linux only supports version 0 radiotap format */ - if (radiotap_header->it_version) - return -EINVAL; - - /* sanity check for allowed length and radiotap length field */ - if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) - return -EINVAL; - - iterator->rtheader = radiotap_header; - iterator->max_length = le16_to_cpu(get_unaligned( - &radiotap_header->it_len)); - iterator->arg_index = 0; - iterator->bitmap_shifter = le32_to_cpu(get_unaligned( - &radiotap_header->it_present)); - iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); - iterator->this_arg = NULL; - - /* find payload start allowing for extended bitmap(s) */ - - if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { - while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) & - (1<<IEEE80211_RADIOTAP_EXT)) { - iterator->arg += sizeof(u32); - - /* - * check for insanity where the present bitmaps - * keep claiming to extend up to or even beyond the - * stated radiotap header length - */ - - if (((ulong)iterator->arg - (ulong)iterator->rtheader) - > (ulong)iterator->max_length) - return -EINVAL; - } - - iterator->arg += sizeof(u32); - - /* - * no need to check again for blowing past stated radiotap - * header length, because ieee80211_radiotap_iterator_next - * checks it before it is dereferenced - */ - } - - /* we are all initialized happily */ - - return 0; -} - - -/** - * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg - * @iterator: radiotap_iterator to move to next arg (if any) - * - * Returns: 0 if there is an argument to handle, - * -ENOENT if there are no more args or -EINVAL - * if there is something else wrong. - * - * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) - * in @this_arg_index and sets @this_arg to point to the - * payload for the field. It takes care of alignment handling and extended - * present fields. @this_arg can be changed by the caller (eg, - * incremented to move inside a compound argument like - * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in - * little-endian format whatever the endianess of your CPU. - * - * Alignment Gotcha: - * You must take care when dereferencing iterator.this_arg - * for multibyte types... the pointer is not aligned. Use - * get_unaligned((type *)iterator.this_arg) to dereference - * iterator.this_arg for type "type" safely on all arches. - */ - -int ieee80211_radiotap_iterator_next( - struct ieee80211_radiotap_iterator *iterator) -{ - - /* - * small length lookup table for all radiotap types we heard of - * starting from b0 in the bitmap, so we can walk the payload - * area of the radiotap header - * - * There is a requirement to pad args, so that args - * of a given length must begin at a boundary of that length - * -- but note that compound args are allowed (eg, 2 x u16 - * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not - * a reliable indicator of alignment requirement. - * - * upper nybble: content alignment for arg - * lower nybble: content length for arg - */ - - static const u8 rt_sizes[] = { - [IEEE80211_RADIOTAP_TSFT] = 0x88, - [IEEE80211_RADIOTAP_FLAGS] = 0x11, - [IEEE80211_RADIOTAP_RATE] = 0x11, - [IEEE80211_RADIOTAP_CHANNEL] = 0x24, - [IEEE80211_RADIOTAP_FHSS] = 0x22, - [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, - [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, - [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, - [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, - [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, - [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, - [IEEE80211_RADIOTAP_ANTENNA] = 0x11, - [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, - [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, - [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, - [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, - [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, - [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, - /* - * add more here as they are defined in - * include/net/ieee80211_radiotap.h - */ - }; - - /* - * for every radiotap entry we can at - * least skip (by knowing the length)... - */ - - while (iterator->arg_index < (int) sizeof(rt_sizes)) { - int hit = 0; - int pad; - - if (!(iterator->bitmap_shifter & 1)) - goto next_entry; /* arg not present */ - - /* - * arg is present, account for alignment padding - * 8-bit args can be at any alignment - * 16-bit args must start on 16-bit boundary - * 32-bit args must start on 32-bit boundary - * 64-bit args must start on 64-bit boundary - * - * note that total arg size can differ from alignment of - * elements inside arg, so we use upper nybble of length - * table to base alignment on - * - * also note: these alignments are ** relative to the - * start of the radiotap header **. There is no guarantee - * that the radiotap header itself is aligned on any - * kind of boundary. - * - * the above is why get_unaligned() is used to dereference - * multibyte elements from the radiotap area - */ - - pad = (((ulong)iterator->arg) - - ((ulong)iterator->rtheader)) & - ((rt_sizes[iterator->arg_index] >> 4) - 1); - - if (pad) - iterator->arg += - (rt_sizes[iterator->arg_index] >> 4) - pad; - - /* - * this is what we will return to user, but we need to - * move on first so next call has something fresh to test - */ - iterator->this_arg_index = iterator->arg_index; - iterator->this_arg = iterator->arg; - hit = 1; - - /* internally move on the size of this arg */ - iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; - - /* - * check for insanity where we are given a bitmap that - * claims to have more arg content than the length of the - * radiotap section. We will normally end up equalling this - * max_length on the last arg, never exceeding it. - */ - - if (((ulong)iterator->arg - (ulong)iterator->rtheader) > - (ulong) iterator->max_length) - return -EINVAL; - - next_entry: - iterator->arg_index++; - if (unlikely((iterator->arg_index & 31) == 0)) { - /* completed current u32 bitmap */ - if (iterator->bitmap_shifter & 1) { - /* b31 was set, there is more */ - /* move to next u32 bitmap */ - iterator->bitmap_shifter = le32_to_cpu( - get_unaligned(iterator->next_bitmap)); - iterator->next_bitmap++; - } else - /* no more bitmaps: end */ - iterator->arg_index = sizeof(rt_sizes); - } else /* just try the next bit */ - iterator->bitmap_shifter >>= 1; - - /* if we found a valid arg earlier, return it now */ - if (hit) - return 0; - } - - /* we don't know how to handle any more args, we're done */ - return -ENOENT; -} diff --git a/package/hostapd/files/radiotap.h b/package/hostapd/files/radiotap.h deleted file mode 100644 index 508264c4c..000000000 --- a/package/hostapd/files/radiotap.h +++ /dev/null @@ -1,242 +0,0 @@ -/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ -/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ - -/*- - * Copyright (c) 2003, 2004 David Young. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of David Young may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID - * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -/* - * Modifications to fit into the linux IEEE 802.11 stack, - * Mike Kershaw (dragorn@kismetwireless.net) - */ - -#ifndef IEEE80211RADIOTAP_H -#define IEEE80211RADIOTAP_H - -#include <stdint.h> - -/* Base version of the radiotap packet header data */ -#define PKTHDR_RADIOTAP_VERSION 0 - -/* A generic radio capture format is desirable. There is one for - * Linux, but it is neither rigidly defined (there were not even - * units given for some fields) nor easily extensible. - * - * I suggest the following extensible radio capture format. It is - * based on a bitmap indicating which fields are present. - * - * I am trying to describe precisely what the application programmer - * should expect in the following, and for that reason I tell the - * units and origin of each measurement (where it applies), or else I - * use sufficiently weaselly language ("is a monotonically nondecreasing - * function of...") that I cannot set false expectations for lawyerly - * readers. - */ - -/* The radio capture header precedes the 802.11 header. - * All data in the header is little endian on all platforms. - */ -struct ieee80211_radiotap_header { - uint8_t it_version; /* Version 0. Only increases - * for drastic changes, - * introduction of compatible - * new fields does not count. - */ - uint8_t it_pad; - uint16_t it_len; /* length of the whole - * header in bytes, including - * it_version, it_pad, - * it_len, and data fields. - */ - uint32_t it_present; /* A bitmap telling which - * fields are present. Set bit 31 - * (0x80000000) to extend the - * bitmap by another 32 bits. - * Additional extensions are made - * by setting bit 31. - */ -}; - -/* Name Data type Units - * ---- --------- ----- - * - * IEEE80211_RADIOTAP_TSFT __le64 microseconds - * - * Value in microseconds of the MAC's 64-bit 802.11 Time - * Synchronization Function timer when the first bit of the - * MPDU arrived at the MAC. For received frames, only. - * - * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap - * - * Tx/Rx frequency in MHz, followed by flags (see below). - * - * IEEE80211_RADIOTAP_FHSS uint16_t see below - * - * For frequency-hopping radios, the hop set (first byte) - * and pattern (second byte). - * - * IEEE80211_RADIOTAP_RATE u8 500kb/s - * - * Tx/Rx data rate - * - * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from - * one milliwatt (dBm) - * - * RF signal power at the antenna, decibel difference from - * one milliwatt. - * - * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from - * one milliwatt (dBm) - * - * RF noise power at the antenna, decibel difference from one - * milliwatt. - * - * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) - * - * RF signal power at the antenna, decibel difference from an - * arbitrary, fixed reference. - * - * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) - * - * RF noise power at the antenna, decibel difference from an - * arbitrary, fixed reference point. - * - * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless - * - * Quality of Barker code lock. Unitless. Monotonically - * nondecreasing with "better" lock strength. Called "Signal - * Quality" in datasheets. (Is there a standard way to measure - * this?) - * - * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless - * - * Transmit power expressed as unitless distance from max - * power set at factory calibration. 0 is max power. - * Monotonically nondecreasing with lower power levels. - * - * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB) - * - * Transmit power expressed as decibel distance from max power - * set at factory calibration. 0 is max power. Monotonically - * nondecreasing with lower power levels. - * - * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from - * one milliwatt (dBm) - * - * Transmit power expressed as dBm (decibels from a 1 milliwatt - * reference). This is the absolute power level measured at - * the antenna port. - * - * IEEE80211_RADIOTAP_FLAGS u8 bitmap - * - * Properties of transmitted and received frames. See flags - * defined below. - * - * IEEE80211_RADIOTAP_ANTENNA u8 antenna index - * - * Unitless indication of the Rx/Tx antenna for this packet. - * The first antenna is antenna 0. - * - * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap - * - * Properties of received frames. See flags defined below. - * - * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap - * - * Properties of transmitted frames. See flags defined below. - * - * IEEE80211_RADIOTAP_RTS_RETRIES u8 data - * - * Number of rts retries a transmitted frame used. - * - * IEEE80211_RADIOTAP_DATA_RETRIES u8 data - * - * Number of unicast retries a transmitted frame used. - * - */ -enum ieee80211_radiotap_type { - IEEE80211_RADIOTAP_TSFT = 0, - IEEE80211_RADIOTAP_FLAGS = 1, - IEEE80211_RADIOTAP_RATE = 2, - IEEE80211_RADIOTAP_CHANNEL = 3, - IEEE80211_RADIOTAP_FHSS = 4, - IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, - IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, - IEEE80211_RADIOTAP_LOCK_QUALITY = 7, - IEEE80211_RADIOTAP_TX_ATTENUATION = 8, - IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, - IEEE80211_RADIOTAP_DBM_TX_POWER = 10, - IEEE80211_RADIOTAP_ANTENNA = 11, - IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, - IEEE80211_RADIOTAP_DB_ANTNOISE = 13, - IEEE80211_RADIOTAP_RX_FLAGS = 14, - IEEE80211_RADIOTAP_TX_FLAGS = 15, - IEEE80211_RADIOTAP_RTS_RETRIES = 16, - IEEE80211_RADIOTAP_DATA_RETRIES = 17, - IEEE80211_RADIOTAP_EXT = 31 -}; - -/* Channel flags. */ -#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ -#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ -#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ -#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ -#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ -#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ -#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ -#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ - -/* For IEEE80211_RADIOTAP_FLAGS */ -#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received - * during CFP - */ -#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received - * with short - * preamble - */ -#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received - * with WEP encryption - */ -#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received - * with fragmentation - */ -#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ -#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between - * 802.11 header and payload - * (to 32-bit boundary) - */ -/* For IEEE80211_RADIOTAP_RX_FLAGS */ -#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ - -/* For IEEE80211_RADIOTAP_TX_FLAGS */ -#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive - * retries */ -#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ -#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ - -#endif /* IEEE80211_RADIOTAP_H */ diff --git a/package/hostapd/files/radiotap_iter.h b/package/hostapd/files/radiotap_iter.h deleted file mode 100644 index 92a798a67..000000000 --- a/package/hostapd/files/radiotap_iter.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __RADIOTAP_ITER_H -#define __RADIOTAP_ITER_H - -#include "radiotap.h" - -/* Radiotap header iteration - * implemented in radiotap.c - */ -/** - * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args - * @rtheader: pointer to the radiotap header we are walking through - * @max_length: length of radiotap header in cpu byte ordering - * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg - * @this_arg: pointer to current radiotap arg - * @arg_index: internal next argument index - * @arg: internal next argument pointer - * @next_bitmap: internal pointer to next present u32 - * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present - */ - -struct ieee80211_radiotap_iterator { - struct ieee80211_radiotap_header *rtheader; - int max_length; - int this_arg_index; - unsigned char *this_arg; - - int arg_index; - unsigned char *arg; - uint32_t *next_bitmap; - uint32_t bitmap_shifter; -}; - -extern int ieee80211_radiotap_iterator_init( - struct ieee80211_radiotap_iterator *iterator, - struct ieee80211_radiotap_header *radiotap_header, - int max_length); - -extern int ieee80211_radiotap_iterator_next( - struct ieee80211_radiotap_iterator *iterator); - -#endif /* __RADIOTAP_ITER_H */ diff --git a/package/hostapd/patches/002-add-nl80211-driver.patch b/package/hostapd/patches/002-add-nl80211-driver.patch new file mode 100644 index 000000000..ba178a054 --- /dev/null +++ b/package/hostapd/patches/002-add-nl80211-driver.patch @@ -0,0 +1,2968 @@ +diff -urN hostapd.orig/driver_nl80211.c hostapd/driver_nl80211.c +--- a/hostapd/driver_nl80211.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/hostapd/driver_nl80211.c 2008-02-16 19:46:38.000000000 +0100 +@@ -0,0 +1,2382 @@ ++/* ++ * hostapd / Kernel driver communication via nl80211 ++ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> ++ * Copyright (c) 2003-2004, Instant802 Networks, Inc. ++ * Copyright (c) 2005-2006, Devicescape Software, Inc. ++ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net> ++ * ++ * 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 ++ * published by the Free Software Foundation. ++ * ++ * Alternatively, this software may be distributed under the terms of BSD ++ * license. ++ * ++ * See README and COPYING for more details. ++ */ ++ ++#include "includes.h" ++ ++#include <sys/ioctl.h> ++#include <netlink/genl/genl.h> ++#include <netlink/genl/family.h> ++#include <netlink/genl/ctrl.h> ++#include <netlink/msg.h> ++#include <netlink/attr.h> ++#include <linux/nl80211.h> ++#include <net/if.h> ++#include <linux/if_packet.h> ++#include <linux/if_ether.h> /* The L2 protocols */ ++#include <linux/wireless.h> ++#include <net/if_arp.h> ++ ++#include "hostapd.h" ++#include "driver.h" ++#include "ieee802_1x.h" ++#include "eloop.h" ++#include "ieee802_11.h" ++#include "sta_info.h" ++#include "hw_features.h" ++#include "mlme.h" ++#include "radiotap.h" ++#include "radiotap_iter.h" ++ ++enum ieee80211_msg_type { ++ ieee80211_msg_normal = 0, ++ ieee80211_msg_tx_callback_ack = 1, ++ ieee80211_msg_tx_callback_fail = 2, ++}; ++ ++struct i802_driver_data { ++ struct hostapd_data *hapd; ++ ++ char iface[IFNAMSIZ + 1]; ++ int ioctl_sock; /* socket for ioctl() use */ ++ int wext_sock; /* socket for wireless events */ ++ int eapol_sock; /* socket for EAPOL frames */ ++ int monitor_sock; /* socket for monitor */ ++ int monitor_ifidx; ++ ++ int default_if_indices[16]; ++ int *if_indices; ++ int num_if_indices; ++ ++ int we_version; ++ struct nl_handle *nl_handle; ++ struct nl_cache *nl_cache; ++ struct genl_family *nl80211; ++ int dtim_period; ++ unsigned int beacon_set:1; ++ unsigned int ieee802_1x_active:1; ++}; ++ ++ ++static void add_ifidx(struct i802_driver_data *drv, int ifidx) ++{ ++ int i; ++ int *old; ++ ++ for (i = 0; i < drv->num_if_indices; i++) { ++ if (drv->if_indices[i] == 0) { ++ drv->if_indices[i] = ifidx; ++ return; ++ } ++ } ++ ++ if (drv->if_indices != drv->default_if_indices) ++ old = drv->if_indices; ++ else ++ old = NULL; ++ ++ drv->if_indices = realloc(old, ++ sizeof(int) * (drv->num_if_indices + 1)); ++ if (!drv->if_indices) { ++ if (!old) ++ drv->if_indices = drv->default_if_indices; ++ else ++ drv->if_indices = old; ++ wpa_printf(MSG_ERROR, "Failed to reallocate memory for " ++ "interfaces"); ++ wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); ++ return; ++ } ++ drv->if_indices[drv->num_if_indices] = ifidx; ++ drv->num_if_indices++; ++} ++ ++ ++static void del_ifidx(struct i802_driver_data *drv, int ifidx) ++{ ++ int i; ++ ++ for (i = 0; i < drv->num_if_indices; i++) { ++ if (drv->if_indices[i] == ifidx) { ++ drv->if_indices[i] = 0; ++ break; ++ } ++ } ++} ++ ++ ++static int have_ifidx(struct i802_driver_data *drv, int ifidx) ++{ ++ int i; ++ ++ for (i = 0; i < drv->num_if_indices; i++) ++ if (drv->if_indices[i] == ifidx) ++ return 1; ++ ++ return 0; ++} ++ ++ ++/* helper for netlink get routines */ ++static int ack_wait_handler(struct nl_msg *msg, void *arg) ++{ ++ int *finished = arg; ++ ++ *finished = 1; ++ return NL_STOP; ++} ++ ++ ++static int hostapd_set_iface_flags(struct i802_driver_data *drv, ++ const char *ifname, int dev_up) ++{ ++ struct ifreq ifr; ++ ++ if (drv->ioctl_sock < 0) ++ return -1; ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) { ++ perror("ioctl[SIOCGIFFLAGS]"); ++ wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)", ++ drv->iface); ++ return -1; ++ } ++ ++ if (dev_up) ++ ifr.ifr_flags |= IFF_UP; ++ else ++ ifr.ifr_flags &= ~IFF_UP; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) { ++ perror("ioctl[SIOCSIFFLAGS]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_set_encryption(const char *iface, void *priv, const char *alg, ++ const u8 *addr, int idx, const u8 *key, ++ size_t key_len, int txkey) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ int err = 0; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ if (strcmp(alg, "none") == 0) { ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_DEL_KEY, 0); ++ } else { ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_NEW_KEY, 0); ++ NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); ++ if (strcmp(alg, "WEP") == 0) { ++ if (key_len == 5) ++ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, ++ 0x000FAC01); ++ else ++ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, ++ 0x000FAC05); ++ } else if (strcmp(alg, "TKIP") == 0) ++ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02); ++ else if (strcmp(alg, "CCMP") == 0) ++ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04); ++ else ++ goto out; ++ } ++ ++ if (addr) ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ (err = nl_wait_for_ack(drv->nl_handle)) < 0) { ++ if (err != -ENOENT) { ++ err = 0; ++ goto out; ++ } ++ } ++ ++ /* ++ * If we need to set the default TX key we do that below, ++ * otherwise we're done here. ++ */ ++ if (!txkey || addr) { ++ ret = 0; ++ goto out; ++ } ++ ++ nlmsg_free(msg); ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_KEY, 0); ++ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ (err = nl_wait_for_ack(drv->nl_handle)) < 0) { ++ if (err != -ENOENT) { ++ err = 0; ++ goto out; ++ } ++ } ++ ++ ret = 0; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static inline int min_int(int a, int b) ++{ ++ if (a < b) ++ return a; ++ return b; ++} ++ ++ ++static int get_key_handler(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *tb[NL80211_ATTR_MAX]; ++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); ++ ++ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), ++ genlmsg_attrlen(gnlh, 0), NULL); ++ ++ /* ++ * TODO: validate the key index and mac address! ++ * Otherwise, there's a race condition as soon as ++ * the kernel starts sending key notifications. ++ */ ++ ++ if (tb[NL80211_ATTR_KEY_SEQ]) ++ memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), ++ min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); ++ return NL_SKIP; ++} ++ ++ ++static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, ++ int idx, u8 *seq) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ struct nl_cb *cb = NULL; ++ int ret = -1; ++ int err = 0; ++ int finished = 0; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_GET_KEY, 0); ++ ++ if (addr) ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ ++ cb = nl_cb_alloc(NL_CB_CUSTOM); ++ if (!cb) ++ goto out; ++ ++ memset(seq, 0, 6); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0) ++ goto out; ++ ++ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_key_handler, seq); ++ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); ++ ++ err = nl_recvmsgs(drv->nl_handle, cb); ++ ++ if (!finished) ++ err = nl_wait_for_ack(drv->nl_handle); ++ ++ if (err < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nl_cb_put(cb); ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, ++ int mode) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_ssid(const char *ifname, void *priv, const u8 *buf, ++ int len) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); ++ iwr.u.essid.flags = 1; /* SSID active */ ++ iwr.u.essid.pointer = (caddr_t) buf; ++ iwr.u.essid.length = len; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { ++ perror("ioctl[SIOCSIWESSID]"); ++ printf("len=%d\n", len); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_send_mgmt_frame(void *priv, const void *data, size_t len, ++ int flags) ++{ ++ struct ieee80211_hdr *hdr = (void*) data; ++ __u8 rtap_hdr[] = { ++ 0x00, 0x00, /* radiotap version */ ++ 0x0e, 0x00, /* radiotap length */ ++ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ ++ 0x0c, /* F_WEP | F_FRAG (encrypt/fragment if required) */ ++ 0x00, /* padding */ ++ 0x00, 0x00, /* RX and TX flags to indicate that */ ++ 0x00, 0x00, /* this is the injected frame directly */ ++ }; ++ struct i802_driver_data *drv = priv; ++ struct iovec iov[2] = { ++ { ++ .iov_base = &rtap_hdr, ++ .iov_len = sizeof(rtap_hdr), ++ }, ++ { ++ .iov_base = (void*)data, ++ .iov_len = len, ++ } ++ }; ++ struct msghdr msg = { ++ .msg_name = NULL, ++ .msg_namelen = 0, ++ .msg_iov = iov, ++ .msg_iovlen = 2, ++ .msg_control = NULL, ++ .msg_controllen = 0, ++ .msg_flags = 0, ++ }; ++ ++ /* ++ * ugh, guess what, the generic code sets one of the version ++ * bits to request tx callback ++ */ ++ hdr->frame_control &= ~host_to_le16(BIT(1)); ++ return sendmsg(drv->monitor_sock, &msg, flags); ++} ++ ++ ++/* Set kernel driver on given frequency (MHz) */ ++static int i802_set_freq(void *priv, int mode, int freq) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ iwr.u.freq.m = freq; ++ iwr.u.freq.e = 6; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { ++ perror("ioctl[SIOCSIWFREQ]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_set_rts(void *priv, int rts) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ iwr.u.rts.value = rts; ++ iwr.u.rts.fixed = 1; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &iwr) < 0) { ++ perror("ioctl[SIOCSIWRTS]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_get_rts(void *priv, int *rts) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &iwr) < 0) { ++ perror("ioctl[SIOCGIWRTS]"); ++ return -1; ++ } ++ ++ *rts = iwr.u.rts.value; ++ ++ return 0; ++} ++ ++ ++static int i802_set_frag(void *priv, int frag) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ iwr.u.frag.value = frag; ++ iwr.u.frag.fixed = 1; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { ++ perror("ioctl[SIOCSIWFRAG]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_get_frag(void *priv, int *frag) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWFRAG, &iwr) < 0) { ++ perror("ioctl[SIOCGIWFRAG]"); ++ return -1; ++ } ++ ++ *frag = iwr.u.frag.value; ++ ++ return 0; ++} ++ ++ ++static int i802_set_retry(void *priv, int short_retry, int long_retry) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ ++ iwr.u.retry.value = short_retry; ++ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; ++ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { ++ perror("ioctl[SIOCSIWRETRY(short)]"); ++ return -1; ++ } ++ ++ iwr.u.retry.value = long_retry; ++ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; ++ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) { ++ perror("ioctl[SIOCSIWRETRY(long)]"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static int i802_get_retry(void *priv, int *short_retry, int *long_retry) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ); ++ ++ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; ++ if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { ++ perror("ioctl[SIOCGIWFRAG(short)]"); ++ return -1; ++ } ++ *short_retry = iwr.u.retry.value; ++ ++ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; ++ if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) { ++ perror("ioctl[SIOCGIWFRAG(long)]"); ++ return -1; ++ } ++ *long_retry = iwr.u.retry.value; ++ ++ return 0; ++} ++ ++ ++static int i802_flush(void *priv) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_NEW_STATION, 0); ++ ++ /* ++ * XXX: FIX! this needs to flush all VLANs too ++ */ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ ++ ret = 0; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ ret = -1; ++ } ++ ++ nla_put_failure: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static int get_sta_handler(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *tb[NL80211_ATTR_MAX + 1]; ++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); ++ struct hostap_sta_driver_data *data = arg; ++ struct nlattr *stats[NL80211_STA_STAT_MAX + 1]; ++ static struct nla_policy stats_policy[NL80211_STA_STAT_MAX + 1] = { ++ [NL80211_STA_STAT_INACTIVE_TIME] = { .type = NLA_U32 }, ++ [NL80211_STA_STAT_RX_BYTES] = { .type = NLA_U32 }, ++ [NL80211_STA_STAT_TX_BYTES] = { .type = NLA_U32 }, ++ }; ++ ++ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), ++ genlmsg_attrlen(gnlh, 0), NULL); ++ ++ /* ++ * TODO: validate the interface and mac address! ++ * Otherwise, there's a race condition as soon as ++ * the kernel starts sending station notifications. ++ */ ++ ++ if (!tb[NL80211_ATTR_STA_STATS]) { ++ wpa_printf(MSG_DEBUG, "sta stats missing!"); ++ return NL_SKIP; ++ } ++ if (nla_parse_nested(stats, NL80211_STA_STAT_MAX, ++ tb[NL80211_ATTR_STA_STATS], ++ stats_policy)) { ++ wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); ++ return NL_SKIP; ++ } ++ ++ if (stats[NL80211_STA_STAT_INACTIVE_TIME]) ++ data->inactive_msec = ++ nla_get_u32(stats[NL80211_STA_STAT_INACTIVE_TIME]); ++ if (stats[NL80211_STA_STAT_RX_BYTES]) ++ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_RX_BYTES]); ++ if (stats[NL80211_STA_STAT_TX_BYTES]) ++ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_TX_BYTES]); ++ ++ return NL_SKIP; ++} ++ ++static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, ++ const u8 *addr) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ struct nl_cb *cb = NULL; ++ int ret = -1; ++ int err = 0; ++ int finished = 0; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_GET_STATION, 0); ++ ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); ++ ++ cb = nl_cb_alloc(NL_CB_CUSTOM); ++ if (!cb) ++ goto out; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0) ++ goto out; ++ ++ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_sta_handler, data); ++ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); ++ ++ err = nl_recvmsgs(drv->nl_handle, cb); ++ ++ if (!finished) ++ err = nl_wait_for_ack(drv->nl_handle); ++ ++ if (err < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nl_cb_put(cb); ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++ ++} ++ ++ ++static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data, ++ size_t data_len, int encrypt, const u8 *own_addr) ++{ ++ struct i802_driver_data *drv = priv; ++ struct ieee80211_hdr *hdr; ++ size_t len; ++ u8 *pos; ++ int res; ++#if 0 /* FIX */ ++ int qos = sta->flags & WLAN_STA_WME; ++#else ++ int qos = 0; ++#endif ++ ++ len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + ++ data_len; ++ hdr = os_zalloc(len); ++ if (hdr == NULL) { ++ printf("malloc() failed for i802_send_data(len=%lu)\n", ++ (unsigned long) len); ++ return -1; ++ } ++ ++ hdr->frame_control = ++ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); ++ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); ++ if (encrypt) ++ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); ++#if 0 /* To be enabled if qos determination is added above */ ++ if (qos) { ++ hdr->frame_control |= ++ host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); ++ } ++#endif ++ ++ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); ++ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); ++ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); ++ pos = (u8 *) (hdr + 1); ++ ++#if 0 /* To be enabled if qos determination is added above */ ++ if (qos) { ++ /* add an empty QoS header if needed */ ++ pos[0] = 0; ++ pos[1] = 0; ++ pos += 2; ++ } ++#endif ++ ++ memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); ++ pos += sizeof(rfc1042_header); ++ WPA_PUT_BE16(pos, ETH_P_PAE); ++ pos += 2; ++ memcpy(pos, data, data_len); ++ ++ res = i802_send_mgmt_frame(drv, (u8 *) hdr, len, 0); ++ free(hdr); ++ ++ if (res < 0) { ++ perror("i802_send_eapol: send"); ++ printf("i802_send_eapol - packet len: %lu - failed\n", ++ (unsigned long) len); ++ } ++ ++ return res; ++} ++ ++ ++static int i802_sta_add(const char *ifname, void *priv, const u8 *addr, ++ u16 aid, u16 capability, u8 *supp_rates, ++ size_t supp_rates_len, int flags) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_NEW_STATION, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, aid); ++ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len, ++ supp_rates); ++ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 0); ++ ++ ret = nl_send_auto_complete(drv->nl_handle, msg); ++ if (ret < 0) ++ goto nla_put_failure; ++ ++ ret = nl_wait_for_ack(drv->nl_handle); ++ /* ignore EEXIST, this happens if a STA associates while associated */ ++ if (ret == -EEXIST || ret >= 0) ++ ret = 0; ++ ++ nla_put_failure: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static int i802_sta_remove(void *priv, const u8 *addr) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_DEL_STATION, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ ++ ret = 0; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ ret = -1; ++ } ++ ++ nla_put_failure: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static int i802_sta_set_flags(void *priv, const u8 *addr, ++ int total_flags, int flags_or, int flags_and) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg, *flags = NULL; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ flags = nlmsg_alloc(); ++ if (!flags) ++ goto free_msg; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_STATION, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ ++ if (total_flags & WLAN_STA_AUTHORIZED || !drv->ieee802_1x_active) ++ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); ++ ++ if (total_flags & WLAN_STA_WME) ++ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); ++ ++ if (total_flags & WLAN_STA_SHORT_PREAMBLE) ++ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); ++ ++ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) ++ goto nla_put_failure; ++ ++ ret = 0; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ ret = -1; ++ } ++ ++ nla_put_failure: ++ nlmsg_free(flags); ++ ++ free_msg: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static int i802_set_channel_flag(void *priv, int mode, int chan, int flag, ++ unsigned char power_level, ++ unsigned char antenna_max) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_regulatory_domain(void *priv, unsigned int rd) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_tx_queue_params(void *priv, int queue, int aifs, ++ int cw_min, int cw_max, int burst_time) ++{ ++ return -1; ++} ++ ++ ++static void nl80211_remove_iface(struct i802_driver_data *drv, int ifidx) ++{ ++ struct nl_msg *msg; ++ ++ /* stop listening for EAPOL on this interface */ ++ del_ifidx(drv, ifidx); ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto nla_put_failure; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_DEL_INTERFACE, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ nla_put_failure: ++ printf("Failed to remove interface.\n"); ++ nlmsg_free(msg); ++} ++ ++ ++static int nl80211_create_iface(struct i802_driver_data *drv, ++ const char *ifname, ++ enum nl80211_iftype iftype, ++ const u8 *addr) ++{ ++ struct nl_msg *msg, *flags = NULL; ++ int ifidx; ++ struct ifreq ifreq; ++ struct iwreq iwr; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ return -1; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_NEW_INTERFACE, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->hapd->conf->iface)); ++ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); ++ ++ if (iftype == NL80211_IFTYPE_MONITOR) { ++ int err; ++ ++ flags = nlmsg_alloc(); ++ if (!flags) ++ goto nla_put_failure; ++ ++ NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); ++ ++ err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); ++ ++ nlmsg_free(flags); ++ ++ if (err) ++ goto nla_put_failure; ++ } ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ nla_put_failure: ++ printf("Failed to create interface %s.\n", ifname); ++ nlmsg_free(msg); ++ return -1; ++ } ++ ++ nlmsg_free(msg); ++ ++ ifidx = if_nametoindex(ifname); ++ ++ if (ifidx <= 0) ++ return -1; ++ ++ /* start listening for EAPOL on this interface */ ++ add_ifidx(drv, ifidx); ++ ++ if (addr) { ++ switch (iftype) { ++ case NL80211_IFTYPE_AP: ++ os_strlcpy(ifreq.ifr_name, ifname, IFNAMSIZ); ++ memcpy(ifreq.ifr_hwaddr.sa_data, addr, ETH_ALEN); ++ ifreq.ifr_hwaddr.sa_family = ARPHRD_ETHER; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifreq)) { ++ nl80211_remove_iface(drv, ifidx); ++ return -1; ++ } ++ break; ++ case NL80211_IFTYPE_WDS: ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); ++ iwr.u.addr.sa_family = ARPHRD_ETHER; ++ memcpy(iwr.u.addr.sa_data, addr, ETH_ALEN); ++ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr)) ++ return -1; ++ break; ++ default: ++ /* nothing */ ++ break; ++ } ++ } ++ ++ return ifidx; ++} ++ ++ ++static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid) ++{ ++ int ifidx; ++ ++ /* ++ * The kernel supports that when the low-level driver does, ++ * but we currently don't because we need per-BSS data that ++ * currently we can't handle easily. ++ */ ++ return -1; ++ ++ ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid); ++ if (ifidx < 0) ++ return -1; ++ if (hostapd_set_iface_flags(priv, ifname, 1)) { ++ nl80211_remove_iface(priv, ifidx); ++ return -1; ++ } ++ return 0; ++} ++ ++ ++static int i802_bss_remove(void *priv, const char *ifname) ++{ ++ nl80211_remove_iface(priv, if_nametoindex(ifname)); ++ return 0; ++} ++ ++ ++static int i802_set_beacon(const char *iface, void *priv, ++ u8 *head, size_t head_len, ++ u8 *tail, size_t tail_len) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ u8 cmd = NL80211_CMD_NEW_BEACON; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ if (drv->beacon_set) ++ cmd = NL80211_CMD_SET_BEACON; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, cmd, 0); ++ NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); ++ NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, 1000); ++ ++ if (!drv->dtim_period) ++ drv->dtim_period = 2; ++ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ goto out; ++ ++ ret = 0; ++ ++ drv->beacon_set = 1; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_del_beacon(struct i802_driver_data *drv) ++{ ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_DEL_BEACON, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_set_ieee8021x(const char *ifname, void *priv, int enabled) ++{ ++ struct i802_driver_data *drv = priv; ++ ++ /* ++ * FIXME: This needs to be per interface (BSS) ++ */ ++ drv->ieee802_1x_active = enabled; ++ return 0; ++} ++ ++ ++static int i802_set_privacy(const char *ifname, void *priv, int enabled) ++{ ++ struct i802_driver_data *drv = priv; ++ struct iwreq iwr; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ ++ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ); ++ iwr.u.param.flags = IW_AUTH_PRIVACY_INVOKED; ++ iwr.u.param.value = enabled; ++ ++ ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr); ++ ++ /* ignore errors, the kernel/driver might not care */ ++ return 0; ++} ++ ++ ++static int i802_set_internal_bridge(void *priv, int value) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_beacon_int(void *priv, int value) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_BEACON, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_set_dtim_period(const char *iface, void *priv, int value) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_BEACON, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); ++ ++ drv->dtim_period = value; ++ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) ++ goto out; ++ ++ ret = 0; ++ ++ out: ++ nla_put_failure: ++ nlmsg_free(msg); ++ return ret; ++} ++ ++ ++static int i802_set_cts_protect(void *priv, int value) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_preamble(void *priv, int value) ++{ ++ return -1; ++} ++ ++ ++static int i802_set_short_slot_time(void *priv, int value) ++{ ++ return -1; ++} ++ ++ ++static enum nl80211_iftype i802_if_type(enum hostapd_driver_if_type type) ++{ ++ switch (type) { ++ case HOSTAPD_IF_VLAN: ++ return NL80211_IFTYPE_AP_VLAN; ++ case HOSTAPD_IF_WDS: ++ return NL80211_IFTYPE_WDS; ++ } ++ return -1; ++} ++ ++ ++static int i802_if_add(const char *iface, void *priv, ++ enum hostapd_driver_if_type type, char *ifname, ++ const u8 *addr) ++{ ++ if (nl80211_create_iface(priv, ifname, i802_if_type(type), addr) < 0) ++ return -1; ++ return 0; ++} ++ ++ ++static int i802_if_update(void *priv, enum hostapd_driver_if_type type, ++ char *ifname, const u8 *addr) ++{ ++ /* unused at the moment */ ++ return -1; ++} ++ ++ ++static int i802_if_remove(void *priv, enum hostapd_driver_if_type type, ++ const char *ifname, const u8 *addr) ++{ ++ nl80211_remove_iface(priv, if_nametoindex(ifname)); ++ return 0; ++} ++ ++ ++struct phy_info_arg { ++ u16 *num_modes; ++ struct hostapd_hw_modes *modes; ++ int error; ++}; ++ ++static int phy_info_handler(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; ++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); ++ struct phy_info_arg *phy_info = arg; ++ ++ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; ++ ++ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; ++ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { ++ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, ++ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, ++ [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, ++ [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, ++ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, ++ }; ++ ++ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; ++ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { ++ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, ++ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, ++ }; ++ ++ struct nlattr *nl_band; ++ struct nlattr *nl_freq; ++ struct nlattr *nl_rate; ++ int rem_band, rem_freq, rem_rate; ++ struct hostapd_hw_modes *mode; ++ int idx, mode_is_set; ++ ++ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), ++ genlmsg_attrlen(gnlh, 0), NULL); ++ ++ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) ++ return NL_SKIP; ++ ++ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { ++ mode = realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode)); ++ if (!mode) ++ return NL_SKIP; ++ phy_info->modes = mode; ++ ++ mode_is_set = 0; ++ ++ mode = &phy_info->modes[*(phy_info->num_modes)]; ++ memset(mode, 0, sizeof(*mode)); ++ *(phy_info->num_modes) += 1; ++ ++ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), ++ nla_len(nl_band), NULL); ++ ++ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { ++ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), ++ nla_len(nl_freq), freq_policy); ++ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) ++ continue; ++ mode->num_channels++; ++ } ++ ++ mode->channels = calloc(mode->num_channels, sizeof(struct hostapd_channel_data)); ++ if (!mode->channels) ++ return NL_SKIP; ++ ++ idx = 0; ++ ++ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { ++ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), ++ nla_len(nl_freq), freq_policy); ++ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) ++ continue; ++ ++ mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); ++ mode->channels[idx].flag |= HOSTAPD_CHAN_W_SCAN | ++ HOSTAPD_CHAN_W_ACTIVE_SCAN | ++ HOSTAPD_CHAN_W_IBSS; ++ ++ if (!mode_is_set) { ++ /* crude heuristic */ ++ if (mode->channels[idx].freq < 4000) ++ mode->mode = HOSTAPD_MODE_IEEE80211B; ++ else ++ mode->mode = HOSTAPD_MODE_IEEE80211A; ++ mode_is_set = 1; ++ } ++ ++ /* crude heuristic */ ++ if (mode->channels[idx].freq < 4000) ++ if (mode->channels[idx].freq == 2848) ++ mode->channels[idx].chan = 14; ++ else ++ mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5; ++ else ++ mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000; ++ ++ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) ++ mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_SCAN; ++ if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) ++ mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_ACTIVE_SCAN; ++ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) ++ mode->channels[idx].flag &= ~HOSTAPD_CHAN_W_IBSS; ++ idx++; ++ } ++ ++ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { ++ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), ++ nla_len(nl_rate), rate_policy); ++ if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) ++ continue; ++ mode->num_rates++; ++ } ++ ++ mode->rates = calloc(mode->num_rates, sizeof(struct hostapd_rate_data)); ++ if (!mode->rates) ++ return NL_SKIP; ++ ++ idx = 0; ++ ++ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { ++ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), ++ nla_len(nl_rate), rate_policy); ++ if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) ++ continue; ++ mode->rates[idx].rate = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); ++ ++ /* crude heuristic */ ++ if (mode->mode == HOSTAPD_MODE_IEEE80211B && ++ mode->rates[idx].rate > 200) ++ mode->mode = HOSTAPD_MODE_IEEE80211G; ++ ++ if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE]) ++ mode->rates[idx].flags |= HOSTAPD_RATE_PREAMBLE2; ++ ++ idx++; ++ } ++ } ++ ++ phy_info->error = 0; ++ ++ return NL_SKIP; ++} ++ ++static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv, ++ u16 *num_modes, ++ u16 *flags) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int err = -1; ++ struct nl_cb *cb = NULL; ++ int finished; ++ struct phy_info_arg result = { ++ .num_modes = num_modes, ++ .modes = NULL, ++ .error = 1, ++ }; ++ ++ *num_modes = 0; ++ *flags = 0; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ return NULL; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_GET_WIPHY, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); ++ ++ cb = nl_cb_alloc(NL_CB_CUSTOM); ++ if (!cb) ++ goto out; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0) ++ goto out; ++ ++ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, phy_info_handler, &result); ++ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); ++ ++ err = nl_recvmsgs(drv->nl_handle, cb); ++ ++ if (!finished) ++ err = nl_wait_for_ack(drv->nl_handle); ++ ++ if (err < 0 || result.error) { ++ hostapd_free_hw_features(result.modes, *num_modes); ++ result.modes = NULL; ++ } ++ ++ out: ++ nl_cb_put(cb); ++ nla_put_failure: ++ if (err) ++ fprintf(stderr, "failed to get information: %d\n", err); ++ nlmsg_free(msg); ++ return result.modes; ++} ++ ++ ++static int i802_set_sta_vlan(void *priv, const u8 *addr, ++ const char *ifname, int vlan_id) ++{ ++ struct i802_driver_data *drv = priv; ++ struct nl_msg *msg; ++ int ret = -1; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ goto out; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_STATION, 0); ++ ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(drv->iface)); ++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(ifname)); ++ ++ ret = 0; ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ (errno = nl_wait_for_ack(drv->nl_handle) < 0)) { ++ ret = -1; ++ } ++ ++ nla_put_failure: ++ nlmsg_free(msg); ++ ++ out: ++ return ret; ++} ++ ++ ++static void handle_unknown_sta(struct hostapd_data *hapd, u8 *ta) ++{ ++ struct sta_info *sta; ++ ++ sta = ap_get_sta(hapd, ta); ++ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { ++ printf("Data/PS-poll frame from not associated STA " ++ MACSTR "\n", MAC2STR(ta)); ++ if (sta && (sta->flags & WLAN_STA_AUTH)) ++ hostapd_sta_disassoc( ++ hapd, ta, ++ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ else ++ hostapd_sta_deauth( ++ hapd, ta, ++ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ } ++} ++ ++ ++static void handle_tx_callback(struct hostapd_data *hapd, 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); ++ ++ type = WLAN_FC_GET_TYPE(fc); ++ stype = WLAN_FC_GET_STYPE(fc); ++ ++ switch (type) { ++ 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); ++ break; ++ case WLAN_FC_TYPE_CTRL: ++ wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s", ++ ok ? "ACK" : "fail"); ++ break; ++ 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); ++ break; ++ default: ++ printf("unknown TX callback frame type %d\n", type); ++ break; ++ } ++} ++ ++ ++static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len, ++ struct hostapd_frame_info *hfi, ++ enum ieee80211_msg_type msg_type) ++{ ++ struct ieee80211_hdr *hdr; ++ u16 fc, type, stype; ++ size_t data_len = len; ++ struct hostapd_data *hapd = NULL; ++ int broadcast_bssid = 0; ++ size_t i; ++ u8 *bssid; ++ ++ /* ++ * PS-Poll frames are 16 bytes. All other frames are ++ * 24 bytes or longer. ++ */ ++ if (len < 16) ++ return; ++ ++ hdr = (struct ieee80211_hdr *) buf; ++ fc = le_to_host16(hdr->frame_control); ++ ++ type = WLAN_FC_GET_TYPE(fc); ++ stype = WLAN_FC_GET_STYPE(fc); ++ ++ switch (type) { ++ case WLAN_FC_TYPE_DATA: ++ if (len < 24) ++ return; ++ switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { ++ case WLAN_FC_TODS: ++ bssid = hdr->addr1; ++ break; ++ default: ++ /* discard */ ++ return; ++ } ++ break; ++ case WLAN_FC_TYPE_CTRL: ++ /* discard non-ps-poll frames */ ++ if (stype != WLAN_FC_STYPE_PSPOLL) ++ return; ++ bssid = hdr->addr1; ++ break; ++ case WLAN_FC_TYPE_MGMT: ++ bssid = hdr->addr3; ++ break; ++ default: ++ /* discard */ ++ return; ++ } ++ ++ /* find interface frame belongs to */ ++ for (i = 0; i < iface->num_bss; i++) { ++ if (memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) { ++ hapd = iface->bss[i]; ++ break; ++ } ++ } ++ ++ if (hapd == NULL) { ++ hapd = iface->bss[0]; ++ ++ if (bssid[0] != 0xff || bssid[1] != 0xff || ++ bssid[2] != 0xff || bssid[3] != 0xff || ++ bssid[4] != 0xff || bssid[5] != 0xff) { ++ /* ++ * Unknown BSSID - drop frame if this is not from ++ * passive scanning or a beacon (at least ProbeReq ++ * frames to other APs may be allowed through RX ++ * filtering in the wlan hw/driver) ++ */ ++ if ((type != WLAN_FC_TYPE_MGMT || ++ stype != WLAN_FC_STYPE_BEACON)) ++ return; ++ } else ++ broadcast_bssid = 1; ++ } ++ ++ switch (msg_type) { ++ case ieee80211_msg_normal: ++ /* continue processing */ ++ break; ++ case ieee80211_msg_tx_callback_ack: ++ handle_tx_callback(hapd, buf, data_len, 1); ++ return; ++ case ieee80211_msg_tx_callback_fail: ++ handle_tx_callback(hapd, buf, data_len, 0); ++ return; ++ } ++ ++ switch (type) { ++ case WLAN_FC_TYPE_MGMT: ++ if (stype != WLAN_FC_STYPE_BEACON && ++ stype != WLAN_FC_STYPE_PROBE_REQ) ++ wpa_printf(MSG_MSGDUMP, "MGMT"); ++ if (broadcast_bssid) { ++ for (i = 0; i < iface->num_bss; i++) ++ ieee802_11_mgmt(iface->bss[i], buf, data_len, ++ stype, hfi); ++ } else ++ ieee802_11_mgmt(hapd, buf, data_len, stype, hfi); ++ break; ++ case WLAN_FC_TYPE_CTRL: ++ /* can only get here with PS-Poll frames */ ++ wpa_printf(MSG_DEBUG, "CTRL"); ++ handle_unknown_sta(hapd, hdr->addr2); ++ break; ++ case WLAN_FC_TYPE_DATA: ++ wpa_printf(MSG_DEBUG, "DATA"); ++ handle_unknown_sta(hapd, hdr->addr2); ++ break; ++ } ++} ++ ++ ++static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) ++{ ++ struct i802_driver_data *drv = eloop_ctx; ++ struct hostapd_data *hapd = drv->hapd; ++ struct sockaddr_ll lladdr; ++ unsigned char buf[3000]; ++ int len; ++ socklen_t fromlen = sizeof(lladdr); ++ ++ len = recvfrom(sock, buf, sizeof(buf), 0, ++ (struct sockaddr *)&lladdr, &fromlen); ++ if (len < 0) { ++ perror("recv"); ++ return; ++ } ++ ++ if (have_ifidx(drv, lladdr.sll_ifindex)) ++ ieee802_1x_receive(hapd, lladdr.sll_addr, buf, len); ++} ++ ++ ++static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) ++{ ++ struct i802_driver_data *drv = eloop_ctx; ++ int len; ++ unsigned char buf[3000]; ++ struct hostapd_data *hapd = drv->hapd; ++ struct ieee80211_radiotap_iterator iter; ++ int ret; ++ struct hostapd_frame_info hfi; ++ int injected = 0, failed = 0, msg_type, rxflags = 0; ++ ++ len = recv(sock, buf, sizeof(buf), 0); ++ if (len < 0) { ++ perror("recv"); ++ return; ++ } ++ ++ if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { ++ printf("received invalid radiotap frame\n"); ++ return; ++ } ++ ++ memset(&hfi, 0, sizeof(hfi)); ++ ++ while (1) { ++ ret = ieee80211_radiotap_iterator_next(&iter); ++ if (ret == -ENOENT) ++ break; ++ if (ret) { ++ printf("received invalid radiotap frame (%d)\n", ret); ++ return; ++ } ++ switch (iter.this_arg_index) { ++ case IEEE80211_RADIOTAP_FLAGS: ++ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) ++ len -= 4; ++ break; ++ case IEEE80211_RADIOTAP_RX_FLAGS: ++ rxflags = 1; ++ break; ++ case IEEE80211_RADIOTAP_TX_FLAGS: ++ injected = 1; ++ failed = le_to_host16((*(uint16_t *) iter.this_arg)) & ++ IEEE80211_RADIOTAP_F_TX_FAIL; ++ break; ++ case IEEE80211_RADIOTAP_DATA_RETRIES: ++ break; ++ case IEEE80211_RADIOTAP_CHANNEL: ++ /* TODO convert from freq/flags to channel number ++ hfi.channel = XXX; ++ hfi.phytype = XXX; ++ */ ++ break; ++ case IEEE80211_RADIOTAP_RATE: ++ hfi.datarate = *iter.this_arg * 5; ++ break; ++ case IEEE80211_RADIOTAP_DB_ANTSIGNAL: ++ hfi.ssi_signal = *iter.this_arg; ++ break; ++ } ++ } ++ ++ if (rxflags && injected) ++ return; ++ ++ if (!injected) ++ msg_type = ieee80211_msg_normal; ++ else if (failed) ++ msg_type = ieee80211_msg_tx_callback_fail; ++ else ++ msg_type = ieee80211_msg_tx_callback_ack; ++ ++ handle_frame(hapd->iface, buf + iter.max_length, ++ len - iter.max_length, &hfi, msg_type); ++} ++ ++ ++static int nl80211_create_monitor_interface(struct i802_driver_data *drv) ++{ ++ char buf[IFNAMSIZ]; ++ struct sockaddr_ll ll; ++ int optval; ++ socklen_t optlen; ++ ++ snprintf(buf, IFNAMSIZ, "mon.%s", drv->iface); ++ buf[IFNAMSIZ - 1] = '\0'; ++ ++ drv->monitor_ifidx = ++ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL); ++ ++ if (drv->monitor_ifidx < 0) ++ return -1; ++ ++ if (hostapd_set_iface_flags(drv, buf, 1)) ++ goto error; ++ ++ memset(&ll, 0, sizeof(ll)); ++ ll.sll_family = AF_PACKET; ++ ll.sll_ifindex = drv->monitor_ifidx; ++ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); ++ if (drv->monitor_sock < 0) { ++ perror("socket[PF_PACKET,SOCK_RAW]"); ++ goto error; ++ } ++ ++ if (bind(drv->monitor_sock, (struct sockaddr *) &ll, ++ sizeof(ll)) < 0) { ++ perror("monitor socket bind"); ++ goto error; ++ } ++ ++ optlen = sizeof(optval); ++ optval = 20; ++ if (setsockopt ++ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { ++ perror("Failed to set socket priority"); ++ goto error; ++ } ++ ++ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, ++ drv, NULL)) { ++ printf("Could not register monitor read socket\n"); ++ goto error; ++ } ++ ++ return 0; ++ error: ++ nl80211_remove_iface(drv, drv->monitor_ifidx); ++ return -1; ++} ++ ++ ++static int nl80211_set_master_mode(struct i802_driver_data *drv, ++ const char *ifname) ++{ ++ struct nl_msg *msg; ++ ++ msg = nlmsg_alloc(); ++ if (!msg) ++ return -1; ++ ++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, ++ 0, NL80211_CMD_SET_INTERFACE, 0); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ++ if_nametoindex(ifname)); ++ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP); ++ ++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || ++ nl_wait_for_ack(drv->nl_handle) < 0) { ++ nla_put_failure: ++ wpa_printf(MSG_ERROR, "Failed to set interface %s to master " ++ "mode.", ifname); ++ nlmsg_free(msg); ++ return -1; ++ } ++ ++ nlmsg_free(msg); ++ ++ return 0; ++} ++ ++ ++static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid) ++{ ++ struct ifreq ifr; ++ struct sockaddr_ll addr; ++ ++ drv->ioctl_sock = -1; ++ ++ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); ++ if (drv->ioctl_sock < 0) { ++ perror("socket[PF_INET,SOCK_DGRAM]"); ++ return -1; ++ } ++ ++ /* start listening for EAPOL on the default AP interface */ ++ add_ifidx(drv, if_nametoindex(drv->iface)); ++ ++ if (hostapd_set_iface_flags(drv, drv->iface, 0)) ++ return -1; ++ ++ if (bssid) { ++ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); ++ memcpy(ifr.ifr_hwaddr.sa_data, bssid, ETH_ALEN); ++ ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; ++ ++ if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) { ++ perror("ioctl(SIOCSIFHWADDR)"); ++ return -1; ++ } ++ } ++ ++ /* ++ * initialise generic netlink and nl80211 ++ */ ++ drv->nl_handle = nl_handle_alloc(); ++ if (!drv->nl_handle) { ++ printf("Failed to allocate netlink handle.\n"); ++ return -1; ++ } ++ ++ if (genl_connect(drv->nl_handle)) { ++ printf("Failed to connect to generic netlink.\n"); ++ return -1; ++ } ++ ++ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle); ++ if (!drv->nl_cache) { ++ printf("Failed to allocate generic netlink cache.\n"); ++ return -1; ++ } ++ ++ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211"); ++ if (!drv->nl80211) { ++ printf("nl80211 not found.\n"); ++ return -1; ++ } ++ ++ /* Initialise a monitor interface */ ++ if (nl80211_create_monitor_interface(drv)) ++ return -1; ++ ++ if (nl80211_set_master_mode(drv, drv->iface)) ++ return -1; ++ ++ if (hostapd_set_iface_flags(drv, drv->iface, 1)) ++ return -1; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sll_family = AF_PACKET; ++ addr.sll_ifindex = ifr.ifr_ifindex; ++ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", ++ addr.sll_ifindex); ++ ++ drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); ++ if (drv->eapol_sock < 0) { ++ perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); ++ return -1; ++ } ++ ++ if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) ++ { ++ printf("Could not register read socket for eapol\n"); ++ return -1; ++ } ++ ++ memset(&ifr, 0, sizeof(ifr)); ++ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); ++ if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) { ++ perror("ioctl(SIOCGIFHWADDR)"); ++ return -1; ++ } ++ ++ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { ++ printf("Invalid HW-addr family 0x%04x\n", ++ ifr.ifr_hwaddr.sa_family); ++ return -1; ++ } ++ memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); ++ ++ return 0; ++} ++ ++ ++static int i802_get_inact_sec(void *priv, const u8 *addr) ++{ ++ struct hostap_sta_driver_data data; ++ int ret; ++ ++ data.inactive_msec = (unsigned long) -1; ++ ret = i802_read_sta_data(priv, &data, addr); ++ if (ret || data.inactive_msec == (unsigned long) -1) ++ return -1; ++ return data.inactive_msec / 1000; ++} ++ ++ ++static int i802_sta_clear_stats(void *priv, const u8 *addr) ++{ ++#if 0 ++ /* TODO */ ++#endif ++ return 0; ++} ++ ++ ++static void ++hostapd_wireless_event_wireless_custom(struct i802_driver_data *drv, ++ char *custom) ++{ ++ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); ++ ++ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { ++ char *pos; ++ u8 addr[ETH_ALEN]; ++ pos = strstr(custom, "addr="); ++ if (pos == NULL) { ++ wpa_printf(MSG_DEBUG, ++ "MLME-MICHAELMICFAILURE.indication " ++ "without sender address ignored"); ++ return; ++ } ++ pos += 5; ++ if (hwaddr_aton(pos, addr) == 0) { ++ ieee80211_michael_mic_failure(drv->hapd, addr, 1); ++ } else { ++ wpa_printf(MSG_DEBUG, ++ "MLME-MICHAELMICFAILURE.indication " ++ "with invalid MAC address"); ++ } ++ } ++} ++ ++ ++static void hostapd_wireless_event_wireless(struct i802_driver_data *drv, ++ char *data, int len) ++{ ++ struct iw_event iwe_buf, *iwe = &iwe_buf; ++ char *pos, *end, *custom, *buf; ++ ++ pos = data; ++ end = data + len; ++ ++ while (pos + IW_EV_LCP_LEN <= end) { ++ /* Event data may be unaligned, so make a local, aligned copy ++ * before processing. */ ++ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); ++ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", ++ iwe->cmd, iwe->len); ++ if (iwe->len <= IW_EV_LCP_LEN) ++ return; ++ ++ custom = pos + IW_EV_POINT_LEN; ++ if (drv->we_version > 18 && ++ (iwe->cmd == IWEVMICHAELMICFAILURE || ++ iwe->cmd == IWEVCUSTOM)) { ++ /* WE-19 removed the pointer from struct iw_point */ ++ char *dpos = (char *) &iwe_buf.u.data.length; ++ int dlen = dpos - (char *) &iwe_buf; ++ memcpy(dpos, pos + IW_EV_LCP_LEN, ++ sizeof(struct iw_event) - dlen); ++ } else { ++ memcpy(&iwe_buf, pos, sizeof(struct iw_event)); ++ custom += IW_EV_POINT_OFF; ++ } ++ ++ switch (iwe->cmd) { ++ case IWEVCUSTOM: ++ if (custom + iwe->u.data.length > end) ++ return; ++ buf = malloc(iwe->u.data.length + 1); ++ if (buf == NULL) ++ return; ++ memcpy(buf, custom, iwe->u.data.length); ++ buf[iwe->u.data.length] = '\0'; ++ hostapd_wireless_event_wireless_custom(drv, buf); ++ free(buf); ++ break; ++ } ++ ++ pos += iwe->len; ++ } ++} ++ ++ ++static void hostapd_wireless_event_rtm_newlink(struct i802_driver_data *drv, ++ struct nlmsghdr *h, int len) ++{ ++ struct ifinfomsg *ifi; ++ int attrlen, nlmsg_len, rta_len; ++ struct rtattr *attr; ++ ++ if (len < (int) sizeof(*ifi)) ++ return; ++ ++ ifi = NLMSG_DATA(h); ++ ++ /* TODO: use ifi->ifi_index to filter out wireless events from other ++ * interfaces */ ++ ++ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); ++ ++ attrlen = h->nlmsg_len - nlmsg_len; ++ if (attrlen < 0) ++ return; ++ ++ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); ++ ++ rta_len = RTA_ALIGN(sizeof(struct rtattr)); ++ while (RTA_OK(attr, attrlen)) { ++ if (attr->rta_type == IFLA_WIRELESS) { ++ hostapd_wireless_event_wireless( ++ drv, ((char *) attr) + rta_len, ++ attr->rta_len - rta_len); ++ } ++ attr = RTA_NEXT(attr, attrlen); ++ } ++} ++ ++ ++static void hostapd_wireless_event_receive(int sock, void *eloop_ctx, ++ void *sock_ctx) ++{ ++ char buf[256]; ++ int left; ++ struct sockaddr_nl from; ++ socklen_t fromlen; ++ struct nlmsghdr *h; ++ struct i802_driver_data *drv = eloop_ctx; ++ ++ fromlen = sizeof(from); ++ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, ++ (struct sockaddr *) &from, &fromlen); ++ if (left < 0) { ++ if (errno != EINTR && errno != EAGAIN) ++ perror("recvfrom(netlink)"); ++ return; ++ } ++ ++ h = (struct nlmsghdr *) buf; ++ while (left >= (int) sizeof(*h)) { ++ int len, plen; ++ ++ len = h->nlmsg_len; ++ plen = len - sizeof(*h); ++ if (len > left || plen < 0) { ++ printf("Malformed netlink message: " ++ "len=%d left=%d plen=%d\n", ++ len, left, plen); ++ break; ++ } ++ ++ switch (h->nlmsg_type) { ++ case RTM_NEWLINK: ++ hostapd_wireless_event_rtm_newlink(drv, h, plen); ++ break; ++ } ++ ++ len = NLMSG_ALIGN(len); ++ left -= len; ++ h = (struct nlmsghdr *) ((char *) h + len); ++ } ++ ++ if (left > 0) { ++ printf("%d extra bytes in the end of netlink message\n", left); ++ } ++} ++ ++ ++static int hostap_get_we_version(struct i802_driver_data *drv) ++{ ++ struct iw_range *range; ++ struct iwreq iwr; ++ int minlen; ++ size_t buflen; ++ ++ drv->we_version = 0; ++ ++ /* ++ * Use larger buffer than struct iw_range in order to allow the ++ * structure to grow in the future. ++ */ ++ buflen = sizeof(struct iw_range) + 500; ++ range = os_zalloc(buflen); ++ if (range == NULL) ++ return -1; ++ ++ memset(&iwr, 0, sizeof(iwr)); ++ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); ++ iwr.u.data.pointer = (caddr_t) range; ++ iwr.u.data.length = buflen; ++ ++ minlen = ((char *) &range->enc_capa) - (char *) range + ++ sizeof(range->enc_capa); ++ ++ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { ++ perror("ioctl[SIOCGIWRANGE]"); ++ free(range); ++ return -1; ++ } else if (iwr.u.data.length >= minlen && ++ range->we_version_compiled >= 18) { ++ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " ++ "WE(source)=%d enc_capa=0x%x", ++ range->we_version_compiled, ++ range->we_version_source, ++ range->enc_capa); ++ drv->we_version = range->we_version_compiled; ++ } ++ ++ free(range); ++ return 0; ++} ++ ++ ++static int i802_wireless_event_init(void *priv) ++{ ++ struct i802_driver_data *drv = priv; ++ int s; ++ struct sockaddr_nl local; ++ ++ hostap_get_we_version(drv); ++ ++ drv->wext_sock = -1; ++ ++ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); ++ if (s < 0) { ++ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); ++ return -1; ++ } ++ ++ memset(&local, 0, sizeof(local)); ++ local.nl_family = AF_NETLINK; ++ local.nl_groups = RTMGRP_LINK; ++ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { ++ perror("bind(netlink)"); ++ close(s); ++ return -1; ++ } ++ ++ eloop_register_read_sock(s, hostapd_wireless_event_receive, drv, ++ NULL); ++ drv->wext_sock = s; ++ ++ return 0; ++} ++ ++ ++static void i802_wireless_event_deinit(void *priv) ++{ ++ struct i802_driver_data *drv = priv; ++ if (drv->wext_sock < 0) ++ return; ++ eloop_unregister_read_sock(drv->wext_sock); ++ close(drv->wext_sock); ++} ++ ++ ++static int i802_sta_deauth(void *priv, const u8 *addr, int reason) ++{ ++ struct i802_driver_data *drv = priv; ++ struct ieee80211_mgmt mgmt; ++ ++ memset(&mgmt, 0, sizeof(mgmt)); ++ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_DEAUTH); ++ memcpy(mgmt.da, addr, ETH_ALEN); ++ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); ++ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); ++ mgmt.u.deauth.reason_code = host_to_le16(reason); ++ return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + ++ sizeof(mgmt.u.deauth), 0); ++} ++ ++ ++static int i802_sta_disassoc(void *priv, const u8 *addr, int reason) ++{ ++ struct i802_driver_data *drv = priv; ++ struct ieee80211_mgmt mgmt; ++ ++ memset(&mgmt, 0, sizeof(mgmt)); ++ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, ++ WLAN_FC_STYPE_DISASSOC); ++ memcpy(mgmt.da, addr, ETH_ALEN); ++ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); ++ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); ++ mgmt.u.disassoc.reason_code = host_to_le16(reason); ++ return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN + ++ sizeof(mgmt.u.disassoc), 0); ++} ++ ++ ++static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid) ++{ ++ struct i802_driver_data *drv; ++ ++ drv = os_zalloc(sizeof(struct i802_driver_data)); ++ if (drv == NULL) { ++ printf("Could not allocate memory for i802 driver data\n"); ++ return NULL; ++ } ++ ++ drv->hapd = hapd; ++ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface)); ++ ++ drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); ++ drv->if_indices = drv->default_if_indices; ++ ++ if (i802_init_sockets(drv, bssid)) ++ goto failed; ++ ++ return drv; ++ ++failed: ++ free(drv); ++ return NULL; ++} ++ ++ ++static void *i802_init(struct hostapd_data *hapd) ++{ ++ return i802_init_bssid(hapd, NULL); ++} ++ ++ ++static void i802_deinit(void *priv) ++{ ++ struct i802_driver_data *drv = priv; ++ ++ i802_del_beacon(drv); ++ ++ /* remove monitor interface */ ++ nl80211_remove_iface(drv, drv->monitor_ifidx); ++ ++ (void) hostapd_set_iface_flags(drv, drv->iface, 0); ++ ++ if (drv->monitor_sock >= 0) { ++ eloop_unregister_read_sock(drv->monitor_sock); ++ close(drv->monitor_sock); ++ } ++ if (drv->ioctl_sock >= 0) ++ close(drv->ioctl_sock); ++ if (drv->eapol_sock >= 0) { ++ eloop_unregister_read_sock(drv->eapol_sock); ++ close(drv->eapol_sock); ++ } ++ ++ genl_family_put(drv->nl80211); ++ nl_cache_free(drv->nl_cache); ++ nl_handle_destroy(drv->nl_handle); ++ ++ if (drv->if_indices != drv->default_if_indices) ++ free(drv->if_indices); ++ ++ free(drv); ++} ++ ++ ++const struct wpa_driver_ops wpa_driver_nl80211_ops = { ++ .name = "nl80211", ++ .init = i802_init, ++// .init_bssid = i802_init_bssid, ++ .deinit = i802_deinit, ++ .wireless_event_init = i802_wireless_event_init, ++ .wireless_event_deinit = i802_wireless_event_deinit, ++ .set_ieee8021x = i802_set_ieee8021x, ++ .set_privacy = i802_set_privacy, ++ .set_encryption = i802_set_encryption, ++ .get_seqnum = i802_get_seqnum, ++ .flush = i802_flush, ++ .read_sta_data = i802_read_sta_data, ++ .send_eapol = i802_send_eapol, ++ .sta_set_flags = i802_sta_set_flags, ++ .sta_deauth = i802_sta_deauth, ++ .sta_disassoc = i802_sta_disassoc, ++ .sta_remove = i802_sta_remove, ++ .set_ssid = i802_set_ssid, ++ .send_mgmt_frame = i802_send_mgmt_frame, ++ .sta_add = i802_sta_add, ++ .get_inact_sec = i802_get_inact_sec, ++ .sta_clear_stats = i802_sta_clear_stats, ++ .set_freq = i802_set_freq, ++ .set_rts = i802_set_rts, ++ .get_rts = i802_get_rts, ++ .set_frag = i802_set_frag, ++ .get_frag = i802_get_frag, ++ .set_retry = i802_set_retry, ++ .get_retry = i802_get_retry, ++ .set_rate_sets = i802_set_rate_sets, ++ .set_channel_flag = i802_set_channel_flag, ++ .set_regulatory_domain = i802_set_regulatory_domain, ++ .set_beacon = i802_set_beacon, ++ .set_internal_bridge = i802_set_internal_bridge, ++ .set_beacon_int = i802_set_beacon_int, ++ .set_dtim_period = i802_set_dtim_period, ++ .set_cts_protect = i802_set_cts_protect, ++ .set_preamble = i802_set_preamble, ++ .set_short_slot_time = i802_set_short_slot_time, ++ .set_tx_queue_params = i802_set_tx_queue_params, ++ .bss_add = i802_bss_add, ++ .bss_remove = i802_bss_remove, ++ .if_add = i802_if_add, ++ .if_update = i802_if_update, ++ .if_remove = i802_if_remove, ++ .get_hw_feature_data = i802_get_hw_feature_data, ++ .set_sta_vlan = i802_set_sta_vlan, ++}; +diff -urN hostapd.orig/radiotap.c hostapd/radiotap.c +--- a/hostapd/radiotap.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/hostapd/radiotap.c 2008-02-15 23:05:17.000000000 +0100 +@@ -0,0 +1,287 @@ ++/* ++ * Radiotap parser ++ * ++ * Copyright 2007 Andy Green <andy@warmcat.com> ++ * ++ * 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 ++ * published by the Free Software Foundation. ++ * ++ * Alternatively, this software may be distributed under the terms of BSD ++ * license. ++ * ++ * See README and COPYING for more details. ++ * ++ * ++ * Modified for userspace by Johannes Berg <johannes@sipsolutions.net> ++ * I only modified some things on top to ease syncing should bugs be found. ++ */ ++ ++#include "includes.h" ++ ++#include "common.h" ++#include "radiotap_iter.h" ++ ++#define le16_to_cpu le_to_host16 ++#define le32_to_cpu le_to_host32 ++#define __le32 uint32_t ++#define ulong unsigned long ++#define unlikely(cond) (cond) ++#define get_unaligned(p) \ ++({ \ ++ struct packed_dummy_struct { \ ++ typeof(*(p)) __val; \ ++ } __attribute__((packed)) *__ptr = (void *) (p); \ ++ \ ++ __ptr->__val; \ ++}) ++ ++/* function prototypes and related defs are in radiotap_iter.h */ ++ ++/** ++ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization ++ * @iterator: radiotap_iterator to initialize ++ * @radiotap_header: radiotap header to parse ++ * @max_length: total length we can parse into (eg, whole packet length) ++ * ++ * Returns: 0 or a negative error code if there is a problem. ++ * ++ * This function initializes an opaque iterator struct which can then ++ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap ++ * argument which is present in the header. It knows about extended ++ * present headers and handles them. ++ * ++ * How to use: ++ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator ++ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) ++ * checking for a good 0 return code. Then loop calling ++ * __ieee80211_radiotap_iterator_next()... it returns either 0, ++ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. ++ * The iterator's @this_arg member points to the start of the argument ++ * associated with the current argument index that is present, which can be ++ * found in the iterator's @this_arg_index member. This arg index corresponds ++ * to the IEEE80211_RADIOTAP_... defines. ++ * ++ * Radiotap header length: ++ * You can find the CPU-endian total radiotap header length in ++ * iterator->max_length after executing ieee80211_radiotap_iterator_init() ++ * successfully. ++ * ++ * Alignment Gotcha: ++ * You must take care when dereferencing iterator.this_arg ++ * for multibyte types... the pointer is not aligned. Use ++ * get_unaligned((type *)iterator.this_arg) to dereference ++ * iterator.this_arg for type "type" safely on all arches. ++ * ++ * Example code: ++ * See Documentation/networking/radiotap-headers.txt ++ */ ++ ++int ieee80211_radiotap_iterator_init( ++ struct ieee80211_radiotap_iterator *iterator, ++ struct ieee80211_radiotap_header *radiotap_header, ++ int max_length) ++{ ++ /* Linux only supports version 0 radiotap format */ ++ if (radiotap_header->it_version) ++ return -EINVAL; ++ ++ /* sanity check for allowed length and radiotap length field */ ++ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) ++ return -EINVAL; ++ ++ iterator->rtheader = radiotap_header; ++ iterator->max_length = le16_to_cpu(get_unaligned( ++ &radiotap_header->it_len)); ++ iterator->arg_index = 0; ++ iterator->bitmap_shifter = le32_to_cpu(get_unaligned( ++ &radiotap_header->it_present)); ++ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); ++ iterator->this_arg = NULL; ++ ++ /* find payload start allowing for extended bitmap(s) */ ++ ++ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { ++ while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) & ++ (1<<IEEE80211_RADIOTAP_EXT)) { ++ iterator->arg += sizeof(u32); ++ ++ /* ++ * check for insanity where the present bitmaps ++ * keep claiming to extend up to or even beyond the ++ * stated radiotap header length ++ */ ++ ++ if (((ulong)iterator->arg - (ulong)iterator->rtheader) ++ > (ulong)iterator->max_length) ++ return -EINVAL; ++ } ++ ++ iterator->arg += sizeof(u32); ++ ++ /* ++ * no need to check again for blowing past stated radiotap ++ * header length, because ieee80211_radiotap_iterator_next ++ * checks it before it is dereferenced ++ */ ++ } ++ ++ /* we are all initialized happily */ ++ ++ return 0; ++} ++ ++ ++/** ++ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg ++ * @iterator: radiotap_iterator to move to next arg (if any) ++ * ++ * Returns: 0 if there is an argument to handle, ++ * -ENOENT if there are no more args or -EINVAL ++ * if there is something else wrong. ++ * ++ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) ++ * in @this_arg_index and sets @this_arg to point to the ++ * payload for the field. It takes care of alignment handling and extended ++ * present fields. @this_arg can be changed by the caller (eg, ++ * incremented to move inside a compound argument like ++ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in ++ * little-endian format whatever the endianess of your CPU. ++ * ++ * Alignment Gotcha: ++ * You must take care when dereferencing iterator.this_arg ++ * for multibyte types... the pointer is not aligned. Use ++ * get_unaligned((type *)iterator.this_arg) to dereference ++ * iterator.this_arg for type "type" safely on all arches. ++ */ ++ ++int ieee80211_radiotap_iterator_next( ++ struct ieee80211_radiotap_iterator *iterator) ++{ ++ ++ /* ++ * small length lookup table for all radiotap types we heard of ++ * starting from b0 in the bitmap, so we can walk the payload ++ * area of the radiotap header ++ * ++ * There is a requirement to pad args, so that args ++ * of a given length must begin at a boundary of that length ++ * -- but note that compound args are allowed (eg, 2 x u16 ++ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not ++ * a reliable indicator of alignment requirement. ++ * ++ * upper nybble: content alignment for arg ++ * lower nybble: content length for arg ++ */ ++ ++ static const u8 rt_sizes[] = { ++ [IEEE80211_RADIOTAP_TSFT] = 0x88, ++ [IEEE80211_RADIOTAP_FLAGS] = 0x11, ++ [IEEE80211_RADIOTAP_RATE] = 0x11, ++ [IEEE80211_RADIOTAP_CHANNEL] = 0x24, ++ [IEEE80211_RADIOTAP_FHSS] = 0x22, ++ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, ++ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, ++ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, ++ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, ++ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, ++ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, ++ [IEEE80211_RADIOTAP_ANTENNA] = 0x11, ++ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, ++ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, ++ [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, ++ [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, ++ [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, ++ [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, ++ /* ++ * add more here as they are defined in ++ * include/net/ieee80211_radiotap.h ++ */ ++ }; ++ ++ /* ++ * for every radiotap entry we can at ++ * least skip (by knowing the length)... ++ */ ++ ++ while (iterator->arg_index < (int) sizeof(rt_sizes)) { ++ int hit = 0; ++ int pad; ++ ++ if (!(iterator->bitmap_shifter & 1)) ++ goto next_entry; /* arg not present */ ++ ++ /* ++ * arg is present, account for alignment padding ++ * 8-bit args can be at any alignment ++ * 16-bit args must start on 16-bit boundary ++ * 32-bit args must start on 32-bit boundary ++ * 64-bit args must start on 64-bit boundary ++ * ++ * note that total arg size can differ from alignment of ++ * elements inside arg, so we use upper nybble of length ++ * table to base alignment on ++ * ++ * also note: these alignments are ** relative to the ++ * start of the radiotap header **. There is no guarantee ++ * that the radiotap header itself is aligned on any ++ * kind of boundary. ++ * ++ * the above is why get_unaligned() is used to dereference ++ * multibyte elements from the radiotap area ++ */ ++ ++ pad = (((ulong)iterator->arg) - ++ ((ulong)iterator->rtheader)) & ++ ((rt_sizes[iterator->arg_index] >> 4) - 1); ++ ++ if (pad) ++ iterator->arg += ++ (rt_sizes[iterator->arg_index] >> 4) - pad; ++ ++ /* ++ * this is what we will return to user, but we need to ++ * move on first so next call has something fresh to test ++ */ ++ iterator->this_arg_index = iterator->arg_index; ++ iterator->this_arg = iterator->arg; ++ hit = 1; ++ ++ /* internally move on the size of this arg */ ++ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; ++ ++ /* ++ * check for insanity where we are given a bitmap that ++ * claims to have more arg content than the length of the ++ * radiotap section. We will normally end up equalling this ++ * max_length on the last arg, never exceeding it. ++ */ ++ ++ if (((ulong)iterator->arg - (ulong)iterator->rtheader) > ++ (ulong) iterator->max_length) ++ return -EINVAL; ++ ++ next_entry: ++ iterator->arg_index++; ++ if (unlikely((iterator->arg_index & 31) == 0)) { ++ /* completed current u32 bitmap */ ++ if (iterator->bitmap_shifter & 1) { ++ /* b31 was set, there is more */ ++ /* move to next u32 bitmap */ ++ iterator->bitmap_shifter = le32_to_cpu( ++ get_unaligned(iterator->next_bitmap)); ++ iterator->next_bitmap++; ++ } else ++ /* no more bitmaps: end */ ++ iterator->arg_index = sizeof(rt_sizes); ++ } else /* just try the next bit */ ++ iterator->bitmap_shifter >>= 1; ++ ++ /* if we found a valid arg earlier, return it now */ ++ if (hit) ++ return 0; ++ } ++ ++ /* we don't know how to handle any more args, we're done */ ++ return -ENOENT; ++} +diff -urN hostapd.orig/radiotap.h hostapd/radiotap.h +--- a/hostapd/radiotap.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/hostapd/radiotap.h 2008-02-15 23:05:17.000000000 +0100 +@@ -0,0 +1,242 @@ ++/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ ++/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ ++ ++/*- ++ * Copyright (c) 2003, 2004 David Young. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of David Young may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID ++ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ++ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY ++ * OF SUCH DAMAGE. ++ */ ++ ++/* ++ * Modifications to fit into the linux IEEE 802.11 stack, ++ * Mike Kershaw (dragorn@kismetwireless.net) ++ */ ++ ++#ifndef IEEE80211RADIOTAP_H ++#define IEEE80211RADIOTAP_H ++ ++#include <stdint.h> ++ ++/* Base version of the radiotap packet header data */ ++#define PKTHDR_RADIOTAP_VERSION 0 ++ ++/* A generic radio capture format is desirable. There is one for ++ * Linux, but it is neither rigidly defined (there were not even ++ * units given for some fields) nor easily extensible. ++ * ++ * I suggest the following extensible radio capture format. It is ++ * based on a bitmap indicating which fields are present. ++ * ++ * I am trying to describe precisely what the application programmer ++ * should expect in the following, and for that reason I tell the ++ * units and origin of each measurement (where it applies), or else I ++ * use sufficiently weaselly language ("is a monotonically nondecreasing ++ * function of...") that I cannot set false expectations for lawyerly ++ * readers. ++ */ ++ ++/* The radio capture header precedes the 802.11 header. ++ * All data in the header is little endian on all platforms. ++ */ ++struct ieee80211_radiotap_header { ++ uint8_t it_version; /* Version 0. Only increases ++ * for drastic changes, ++ * introduction of compatible ++ * new fields does not count. ++ */ ++ uint8_t it_pad; ++ uint16_t it_len; /* length of the whole ++ * header in bytes, including ++ * it_version, it_pad, ++ * it_len, and data fields. ++ */ ++ uint32_t it_present; /* A bitmap telling which ++ * fields are present. Set bit 31 ++ * (0x80000000) to extend the ++ * bitmap by another 32 bits. ++ * Additional extensions are made ++ * by setting bit 31. ++ */ ++}; ++ ++/* Name Data type Units ++ * ---- --------- ----- ++ * ++ * IEEE80211_RADIOTAP_TSFT __le64 microseconds ++ * ++ * Value in microseconds of the MAC's 64-bit 802.11 Time ++ * Synchronization Function timer when the first bit of the ++ * MPDU arrived at the MAC. For received frames, only. ++ * ++ * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap ++ * ++ * Tx/Rx frequency in MHz, followed by flags (see below). ++ * ++ * IEEE80211_RADIOTAP_FHSS uint16_t see below ++ * ++ * For frequency-hopping radios, the hop set (first byte) ++ * and pattern (second byte). ++ * ++ * IEEE80211_RADIOTAP_RATE u8 500kb/s ++ * ++ * Tx/Rx data rate ++ * ++ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from ++ * one milliwatt (dBm) ++ * ++ * RF signal power at the antenna, decibel difference from ++ * one milliwatt. ++ * ++ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from ++ * one milliwatt (dBm) ++ * ++ * RF noise power at the antenna, decibel difference from one ++ * milliwatt. ++ * ++ * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) ++ * ++ * RF signal power at the antenna, decibel difference from an ++ * arbitrary, fixed reference. ++ * ++ * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) ++ * ++ * RF noise power at the antenna, decibel difference from an ++ * arbitrary, fixed reference point. ++ * ++ * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless ++ * ++ * Quality of Barker code lock. Unitless. Monotonically ++ * nondecreasing with "better" lock strength. Called "Signal ++ * Quality" in datasheets. (Is there a standard way to measure ++ * this?) ++ * ++ * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless ++ * ++ * Transmit power expressed as unitless distance from max ++ * power set at factory calibration. 0 is max power. ++ * Monotonically nondecreasing with lower power levels. ++ * ++ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB) ++ * ++ * Transmit power expressed as decibel distance from max power ++ * set at factory calibration. 0 is max power. Monotonically ++ * nondecreasing with lower power levels. ++ * ++ * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from ++ * one milliwatt (dBm) ++ * ++ * Transmit power expressed as dBm (decibels from a 1 milliwatt ++ * reference). This is the absolute power level measured at ++ * the antenna port. ++ * ++ * IEEE80211_RADIOTAP_FLAGS u8 bitmap ++ * ++ * Properties of transmitted and received frames. See flags ++ * defined below. ++ * ++ * IEEE80211_RADIOTAP_ANTENNA u8 antenna index ++ * ++ * Unitless indication of the Rx/Tx antenna for this packet. ++ * The first antenna is antenna 0. ++ * ++ * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap ++ * ++ * Properties of received frames. See flags defined below. ++ * ++ * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap ++ * ++ * Properties of transmitted frames. See flags defined below. ++ * ++ * IEEE80211_RADIOTAP_RTS_RETRIES u8 data ++ * ++ * Number of rts retries a transmitted frame used. ++ * ++ * IEEE80211_RADIOTAP_DATA_RETRIES u8 data ++ * ++ * Number of unicast retries a transmitted frame used. ++ * ++ */ ++enum ieee80211_radiotap_type { ++ IEEE80211_RADIOTAP_TSFT = 0, ++ IEEE80211_RADIOTAP_FLAGS = 1, ++ IEEE80211_RADIOTAP_RATE = 2, ++ IEEE80211_RADIOTAP_CHANNEL = 3, ++ IEEE80211_RADIOTAP_FHSS = 4, ++ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, ++ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, ++ IEEE80211_RADIOTAP_LOCK_QUALITY = 7, ++ IEEE80211_RADIOTAP_TX_ATTENUATION = 8, ++ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, ++ IEEE80211_RADIOTAP_DBM_TX_POWER = 10, ++ IEEE80211_RADIOTAP_ANTENNA = 11, ++ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, ++ IEEE80211_RADIOTAP_DB_ANTNOISE = 13, ++ IEEE80211_RADIOTAP_RX_FLAGS = 14, ++ IEEE80211_RADIOTAP_TX_FLAGS = 15, ++ IEEE80211_RADIOTAP_RTS_RETRIES = 16, ++ IEEE80211_RADIOTAP_DATA_RETRIES = 17, ++ IEEE80211_RADIOTAP_EXT = 31 ++}; ++ ++/* Channel flags. */ ++#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ ++#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ ++#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ ++#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ ++#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ ++#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ ++#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ ++#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ ++ ++/* For IEEE80211_RADIOTAP_FLAGS */ ++#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received ++ * during CFP ++ */ ++#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received ++ * with short ++ * preamble ++ */ ++#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received ++ * with WEP encryption ++ */ ++#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received ++ * with fragmentation ++ */ ++#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ ++#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between ++ * 802.11 header and payload ++ * (to 32-bit boundary) ++ */ ++/* For IEEE80211_RADIOTAP_RX_FLAGS */ ++#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ ++ ++/* For IEEE80211_RADIOTAP_TX_FLAGS */ ++#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive ++ * retries */ ++#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ ++#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ ++ ++#endif /* IEEE80211_RADIOTAP_H */ +diff -urN hostapd.orig/radiotap_iter.h hostapd/radiotap_iter.h +--- a/hostapd/radiotap_iter.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/hostapd/radiotap_iter.h 2008-02-15 23:05:17.000000000 +0100 +@@ -0,0 +1,41 @@ ++#ifndef __RADIOTAP_ITER_H ++#define __RADIOTAP_ITER_H ++ ++#include "radiotap.h" ++ ++/* Radiotap header iteration ++ * implemented in radiotap.c ++ */ ++/** ++ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args ++ * @rtheader: pointer to the radiotap header we are walking through ++ * @max_length: length of radiotap header in cpu byte ordering ++ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg ++ * @this_arg: pointer to current radiotap arg ++ * @arg_index: internal next argument index ++ * @arg: internal next argument pointer ++ * @next_bitmap: internal pointer to next present u32 ++ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present ++ */ ++ ++struct ieee80211_radiotap_iterator { ++ struct ieee80211_radiotap_header *rtheader; ++ int max_length; ++ int this_arg_index; ++ unsigned char *this_arg; ++ ++ int arg_index; ++ unsigned char *arg; ++ uint32_t *next_bitmap; ++ uint32_t bitmap_shifter; ++}; ++ ++extern int ieee80211_radiotap_iterator_init( ++ struct ieee80211_radiotap_iterator *iterator, ++ struct ieee80211_radiotap_header *radiotap_header, ++ int max_length); ++ ++extern int ieee80211_radiotap_iterator_next( ++ struct ieee80211_radiotap_iterator *iterator); ++ ++#endif /* __RADIOTAP_ITER_H */ diff --git a/package/hostapd/patches/002-remove-michael-mic.patch b/package/hostapd/patches/002-remove-michael-mic.patch deleted file mode 100644 index a90b40f36..000000000 --- a/package/hostapd/patches/002-remove-michael-mic.patch +++ /dev/null @@ -1,34 +0,0 @@ ---- - hostapd/driver_devicescape.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - ---- hostap.orig/hostapd/driver_devicescape.c 2007-11-14 17:30:47.000000000 +0100 -+++ hostap/hostapd/driver_devicescape.c 2007-11-14 17:31:07.000000000 +0100 -@@ -1264,6 +1264,7 @@ static void dump_frame_info(struct ieee8 - } - - -+/* - static void hostapd_michael_mic_failure(struct hostapd_data *hapd, u8 *buf, - size_t len) - { -@@ -1278,6 +1279,7 @@ static void hostapd_michael_mic_failure( - - mlme_michaelmicfailure_indication(hapd, hdr->addr2); - } -+*/ - - - static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len, -@@ -1386,10 +1388,10 @@ static void handle_frame(struct hostapd_ - case ieee80211_msg_wep_frame_unknown_key: - ieee802_11_rx_unknown_key(hapd, buf, data_len); - return; -- */ - case ieee80211_msg_michael_mic_failure: - hostapd_michael_mic_failure(hapd, buf, data_len); - return; -+ */ - /* - * TODO - * We should be telling them to go away. But we don't support that now. diff --git a/package/hostapd/patches/007-add-nl80211-driver.patch b/package/hostapd/patches/003-hook-up-nl80211-driver.patch index 6c450fcda..6c450fcda 100644 --- a/package/hostapd/patches/007-add-nl80211-driver.patch +++ b/package/hostapd/patches/003-hook-up-nl80211-driver.patch diff --git a/package/hostapd/patches/003-use-nl80211-for-keys.patch b/package/hostapd/patches/003-use-nl80211-for-keys.patch deleted file mode 100644 index 6b7fe8098..000000000 --- a/package/hostapd/patches/003-use-nl80211-for-keys.patch +++ /dev/null @@ -1,112 +0,0 @@ ---- - hostapd/driver_devicescape.c | 93 ++++++++++++++++++++++++++++++------------- - 1 file changed, 67 insertions(+), 26 deletions(-) - ---- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:12.000000000 +0100 -+++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:13.000000000 +0100 -@@ -150,38 +150,79 @@ static int i802_set_encryption(const cha - size_t key_len, int txkey) - { - struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param *param; -- u8 *buf; -- size_t blen; -- int ret = 0; -+ struct nl_msg *msg; -+ int ret = -1; -+ int err = 0; - -- blen = sizeof(*param) + key_len; -- buf = os_zalloc(blen); -- if (buf == NULL) -- return -1; -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; - -- param = (struct prism2_hostapd_param *) buf; -- param->cmd = PRISM2_SET_ENCRYPTION; -- if (addr == NULL) -- 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; -- param->u.crypt.key_len = key_len; -- memcpy(param->u.crypt.key, key, key_len); -+ if (strcmp(alg, "none") == 0) { -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_DEL_KEY, 0); -+ } else { -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_NEW_KEY, 0); -+ NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); -+ if (strcmp(alg, "WEP") == 0) { -+ if (key_len == 5) -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, -+ 0x000FAC01); -+ else -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, -+ 0x000FAC05); -+ } else if (strcmp(alg, "TKIP") == 0) -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02); -+ else if (strcmp(alg, "CCMP") == 0) -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04); -+ else -+ goto out; -+ } - -- if (hostapd_ioctl_iface(iface, drv, param, blen) && errno != ENOENT) { -- printf("%s: Failed to set encryption to alg '%s' addr " MACSTR -- " errno=%d\n", -- iface, alg, MAC2STR(param->sta_addr), errno); -- ret = -1; -+ if (addr) -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || -+ (err = nl_wait_for_ack(drv->nl_handle)) < 0) { -+ if (err != -ENOENT) { -+ err = 0; -+ goto out; -+ } - } - -- free(buf); -+ if (!txkey) { -+ ret = 0; -+ goto out; -+ } -+ -+ nlmsg_free(msg); -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; - -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_KEY, 0); -+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); -+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || -+ (err = nl_wait_for_ack(drv->nl_handle)) < 0) { -+ if (err != -ENOENT) { -+ err = 0; -+ goto out; -+ } -+ } -+ -+ ret = 0; -+ -+ out: -+ nla_put_failure: -+ nlmsg_free(msg); - return ret; - } - diff --git a/package/hostapd/patches/004-use-nl80211-for-beacons.patch b/package/hostapd/patches/004-use-nl80211-for-beacons.patch deleted file mode 100644 index 34fa841d6..000000000 --- a/package/hostapd/patches/004-use-nl80211-for-beacons.patch +++ /dev/null @@ -1,149 +0,0 @@ ---- - hostapd/driver_devicescape.c | 111 +++++++++++++++++++++++++++++++------------ - 1 file changed, 82 insertions(+), 29 deletions(-) - ---- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:13.000000000 +0100 -+++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:13.000000000 +0100 -@@ -68,6 +68,8 @@ struct i802_driver_data { - struct nl_handle *nl_handle; - struct nl_cache *nl_cache; - struct genl_family *nl80211; -+ int dtim_period; -+ unsigned int beacon_set:1; - }; - - -@@ -908,37 +910,44 @@ static int i802_bss_remove(void *priv, c - } - - --static int i802_set_beacon(const char *ifname, void *priv, -+static int i802_set_beacon(const char *iface, void *priv, - u8 *head, size_t head_len, - u8 *tail, size_t tail_len) - { - struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param *param; -- int len, ret = 0; -+ struct nl_msg *msg; -+ u8 cmd = NL80211_CMD_NEW_BEACON; -+ int ret = -1; - -- param = os_zalloc(sizeof(*param) + head_len + tail_len); -- if (param == NULL) { -- printf("Failed to alloc memory for beacon ioctl\n"); -- return -1; -- } -- len = (¶m->u.beacon.data[0] - (u8 *) param) + head_len + tail_len; -- param->cmd = PRISM2_HOSTAPD_SET_BEACON; -- param->u.beacon.head_len = head_len; -- param->u.beacon.tail_len = tail_len; -- memcpy(¶m->u.beacon.data[0], head, head_len); -- memcpy(¶m->u.beacon.data[0] + head_len, tail, tail_len); -- -- if (len < (int) sizeof(*param)) -- len = sizeof(*param); -- if (hostapd_ioctl_iface(ifname, drv, param, len)) { -- printf("Could not set beacon data to kernel driver.\n"); -- printf("ifname='%s' head=%p head_len=%d tail=%p tail_len=%d " -- "cmd=%d\n", -- ifname, head, head_len, tail, tail_len, param->cmd); -- ret = -1; -- } -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; - -- free(param); -+ if (drv->beacon_set) -+ cmd = NL80211_CMD_SET_BEACON; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, cmd, 0); -+ NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); -+ NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); -+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, 1000); -+ -+ if (!drv->dtim_period) -+ drv->dtim_period = 2; -+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || -+ nl_wait_for_ack(drv->nl_handle) < 0) -+ goto out; -+ -+ ret = 0; -+ -+ drv->beacon_set = 1; -+ -+ out: -+ nla_put_failure: -+ nlmsg_free(msg); - return ret; - } - -@@ -985,15 +994,59 @@ static int i802_set_internal_bridge(void - static int i802_set_beacon_int(void *priv, int value) - { - struct i802_driver_data *drv = priv; -- return hostap_ioctl_prism2param(drv, PRISM2_PARAM_BEACON_INT, value); -+ struct nl_msg *msg; -+ int ret = -1; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_BEACON, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value); -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || -+ nl_wait_for_ack(drv->nl_handle) < 0) -+ goto out; -+ -+ ret = 0; -+ -+ out: -+ nla_put_failure: -+ nlmsg_free(msg); -+ return ret; - } - - --static int i802_set_dtim_period(const char *ifname, void *priv, int value) -+static int i802_set_dtim_period(const char *iface, void *priv, int value) - { - struct i802_driver_data *drv = priv; -- return hostap_ioctl_prism2param_iface(ifname, drv, -- PRISM2_PARAM_DTIM_PERIOD, value); -+ struct nl_msg *msg; -+ int ret = -1; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_BEACON, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); -+ -+ drv->dtim_period = value; -+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period); -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || -+ nl_wait_for_ack(drv->nl_handle) < 0) -+ goto out; -+ -+ ret = 0; -+ -+ out: -+ nla_put_failure: -+ nlmsg_free(msg); -+ return ret; - } - - diff --git a/package/hostapd/patches/005-use-nl80211-for-get-key.patch b/package/hostapd/patches/005-use-nl80211-for-get-key.patch deleted file mode 100644 index 142c1939d..000000000 --- a/package/hostapd/patches/005-use-nl80211-for-get-key.patch +++ /dev/null @@ -1,116 +0,0 @@ ---- - hostapd/driver_devicescape.c | 96 ++++++++++++++++++++++++++++++++++--------- - 1 file changed, 76 insertions(+), 20 deletions(-) - ---- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:13.000000000 +0100 -+++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:14.000000000 +0100 -@@ -228,33 +228,89 @@ static int i802_set_encryption(const cha - return ret; - } - -+static inline int min_int(int a, int b) -+{ -+ if (a<b) -+ return a; -+ return b; -+} -+ -+static int get_key_handler(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb[NL80211_ATTR_MAX]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ -+ /* -+ * TODO: validate the key index and mac address! -+ * Otherwise, there's a race condition as soon as -+ * the kernel starts sending key notifications. -+ */ -+ -+ if (tb[NL80211_ATTR_KEY_SEQ]) -+ memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), -+ min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); -+ return NL_SKIP; -+} -+ -+static int ack_wait_handler(struct nl_msg *msg, void *arg) -+{ -+ int *finished = arg; -+ -+ *finished = 1; -+ return NL_STOP; -+} - - static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, - int idx, u8 *seq) - { - struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param *param; -- size_t param_len; -- int ret; -+ struct nl_msg *msg; -+ struct nl_cb *cb = NULL; -+ int ret = -1; -+ int err = 0; -+ int finished = 0; - -- param_len = sizeof(struct prism2_hostapd_param) + 32; -- param = os_zalloc(param_len); -- if (param == NULL) -- return -1; -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; - -- param->cmd = PRISM2_GET_ENCRYPTION; -- if (addr == NULL) -- memset(param->sta_addr, 0xff, ETH_ALEN); -- else -- memcpy(param->sta_addr, addr, ETH_ALEN); -- param->u.crypt.idx = idx; -- -- ret = hostapd_ioctl_iface(iface, drv, param, param_len); -- if (ret == 0) { -- memcpy(seq, param->u.crypt.seq_counter, -- HOSTAP_SEQ_COUNTER_SIZE); -- } -- free(param); -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_GET_KEY, 0); -+ -+ if (addr) -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); -+ -+ cb = nl_cb_alloc(NL_CB_CUSTOM); -+ if (!cb) -+ goto out; -+ -+ memset(seq, 0, 6); -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0) -+ goto out; -+ -+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_key_handler, seq); -+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); -+ -+ err = nl_recvmsgs(drv->nl_handle, cb); -+ -+ if (!finished) -+ err = nl_wait_for_ack(drv->nl_handle); -+ -+ if (err < 0) -+ goto out; -+ -+ ret = 0; -+ -+ out: -+ nl_cb_put(cb); -+ nla_put_failure: -+ nlmsg_free(msg); - return ret; - } - diff --git a/package/hostapd/patches/006-use-nl80211-for-sta.patch b/package/hostapd/patches/006-use-nl80211-for-sta.patch deleted file mode 100644 index 133a75019..000000000 --- a/package/hostapd/patches/006-use-nl80211-for-sta.patch +++ /dev/null @@ -1,413 +0,0 @@ ---- - hostapd/driver_devicescape.c | 332 ++++++++++++++++++++++++++++++++----------- - 1 file changed, 251 insertions(+), 81 deletions(-) - ---- hostap.orig/hostapd/driver_devicescape.c 2007-11-14 17:31:15.000000000 +0100 -+++ hostap/hostapd/driver_devicescape.c 2007-11-14 17:31:16.000000000 +0100 -@@ -75,8 +75,14 @@ struct i802_driver_data { - - #define HAPD_DECL struct hostapd_data *hapd = iface->bss[0] - --static int i802_sta_set_flags(void *priv, const u8 *addr, -- int total_flags, int flags_or, int flags_and); -+/* helper for netlink get routines */ -+static int ack_wait_handler(struct nl_msg *msg, void *arg) -+{ -+ int *finished = arg; -+ -+ *finished = 1; -+ return NL_STOP; -+} - - - static int hostapd_set_iface_flags(struct i802_driver_data *drv, int dev_up) -@@ -255,14 +261,6 @@ static int get_key_handler(struct nl_msg - return NL_SKIP; - } - --static int ack_wait_handler(struct nl_msg *msg, void *arg) --{ -- int *finished = arg; -- -- *finished = 1; -- return NL_STOP; --} -- - static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, - int idx, u8 *seq) - { -@@ -629,43 +627,126 @@ static int i802_get_retry(void *priv, in - static int i802_flush(void *priv) - { - struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param param; -+ struct nl_msg *msg; -+ int ret = -1; - -- memset(¶m, 0, sizeof(param)); -- param.cmd = PRISM2_HOSTAPD_FLUSH; -- return hostapd_ioctl(drv, ¶m, sizeof(param)); -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_NEW_STATION, 0); -+ -+ /* -+ * XXX: FIX! this needs to flush all VLANs too -+ */ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(drv->iface)); -+ -+ ret = 0; -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || -+ nl_wait_for_ack(drv->nl_handle) < 0) { -+ ret = -1; -+ } -+ -+ nla_put_failure: -+ nlmsg_free(msg); -+ -+ out: -+ return ret; - } - - -+static int get_sta_handler(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct hostap_sta_driver_data *data = arg; -+ struct nlattr *stats[NL80211_STA_STAT_MAX + 1]; -+ static struct nla_policy stats_policy[NL80211_STA_STAT_MAX + 1] = { -+ [NL80211_STA_STAT_INACTIVE_TIME] = { .type = NLA_U32 }, -+ [NL80211_STA_STAT_RX_BYTES] = { .type = NLA_U32 }, -+ [NL80211_STA_STAT_TX_BYTES] = { .type = NLA_U32 }, -+ }; -+ -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ -+ /* -+ * TODO: validate the interface and mac address! -+ * Otherwise, there's a race condition as soon as -+ * the kernel starts sending station notifications. -+ */ -+ -+ if (!tb[NL80211_ATTR_STA_STATS]) { -+ printf("sta stats missing!\n"); -+ return NL_SKIP; -+ } -+ if (nla_parse_nested(stats, NL80211_STA_STAT_MAX, -+ tb[NL80211_ATTR_STA_STATS], -+ stats_policy)) { -+ printf("failed to parse nested attributes!\n"); -+ return NL_SKIP; -+ } -+ -+ if (stats[NL80211_STA_STAT_INACTIVE_TIME]) -+ data->inactive_msec = -+ nla_get_u32(stats[NL80211_STA_STAT_INACTIVE_TIME]); -+ if (stats[NL80211_STA_STAT_RX_BYTES]) -+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_RX_BYTES]); -+ if (stats[NL80211_STA_STAT_TX_BYTES]) -+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_TX_BYTES]); -+ -+ return NL_SKIP; -+} -+ - static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, - const u8 *addr) - { - struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param param; -+ struct nl_msg *msg; -+ struct nl_cb *cb = NULL; -+ int ret = -1; -+ int err = 0; -+ int finished = 0; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; - -- memset(data, 0, sizeof(*data)); -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_GET_STATION, 0); - -- memset(¶m, 0, sizeof(param)); -- param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; -- memcpy(param.sta_addr, addr, ETH_ALEN); -- if (hostapd_ioctl(drv, ¶m, sizeof(param))) { -- printf(" Could not get station info from kernel driver.\n"); -- return -1; -- } -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface)); -+ -+ cb = nl_cb_alloc(NL_CB_CUSTOM); -+ if (!cb) -+ goto out; -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0) -+ goto out; -+ -+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_sta_handler, data); -+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished); -+ -+ err = nl_recvmsgs(drv->nl_handle, cb); -+ -+ if (!finished) -+ err = nl_wait_for_ack(drv->nl_handle); -+ -+ if (err < 0) -+ goto out; -+ -+ ret = 0; -+ -+ out: -+ nl_cb_put(cb); -+ nla_put_failure: -+ nlmsg_free(msg); -+ return ret; - -- data->inactive_msec = param.u.get_info_sta.inactive_msec; -- data->rx_packets = param.u.get_info_sta.rx_packets; -- data->tx_packets = param.u.get_info_sta.tx_packets; -- data->rx_bytes = param.u.get_info_sta.rx_bytes; -- data->tx_bytes = param.u.get_info_sta.tx_bytes; -- data->current_tx_rate = param.u.get_info_sta.current_tx_rate; -- data->flags = param.u.get_info_sta.flags; -- data->num_ps_buf_frames = param.u.get_info_sta.num_ps_buf_frames; -- data->tx_retry_failed = param.u.get_info_sta.tx_retry_failed; -- data->tx_retry_count = param.u.get_info_sta.tx_retry_count; -- data->last_rssi = param.u.get_info_sta.last_rssi; -- data->last_ack_rssi = param.u.get_info_sta.last_ack_rssi; -- return 0; - } - - -@@ -744,35 +825,70 @@ static int i802_sta_add(const char *ifna - size_t supp_rates_len, int flags) - { - struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param param; -- size_t len; -+ struct nl_msg *msg; -+ int ret = -1; - -- 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; -- len = supp_rates_len; -- if (len > sizeof(param.u.add_sta.supp_rates)) -- len = sizeof(param.u.add_sta.supp_rates); -- memcpy(param.u.add_sta.supp_rates, supp_rates, len); -- return hostapd_ioctl_iface(ifname, drv, ¶m, sizeof(param)); -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_NEW_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(drv->iface)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, aid); -+ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len, -+ supp_rates); -+ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 0); -+ -+ ret = nl_send_auto_complete(drv->nl_handle, msg); -+ if (ret < 0) -+ goto nla_put_failure; -+ -+ ret = nl_wait_for_ack(drv->nl_handle); -+ /* ignore EEXIST, this happens if a STA associates while associated */ -+ if (ret == -EEXIST || ret >= 0) -+ ret = 0; -+ -+ nla_put_failure: -+ nlmsg_free(msg); -+ -+ out: -+ return ret; - } - - - static int i802_sta_remove(void *priv, const u8 *addr) - { - struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param param; -+ struct nl_msg *msg; -+ int ret = -1; - -- i802_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED); -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; - -- memset(¶m, 0, sizeof(param)); -- param.cmd = PRISM2_HOSTAPD_REMOVE_STA; -- memcpy(param.sta_addr, addr, ETH_ALEN); -- if (hostapd_ioctl(drv, ¶m, sizeof(param))) -- return -1; -- return 0; -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_DEL_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(drv->iface)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ -+ ret = 0; -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || -+ nl_wait_for_ack(drv->nl_handle) < 0) { -+ ret = -1; -+ } -+ -+ nla_put_failure: -+ nlmsg_free(msg); -+ -+ out: -+ return ret; - } - - -@@ -780,14 +896,51 @@ static int i802_sta_set_flags(void *priv - int total_flags, int flags_or, int flags_and) - { - struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param param; -+ struct nl_msg *msg, *flags = NULL; -+ int ret = -1; - -- memset(¶m, 0, sizeof(param)); -- param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA; -- memcpy(param.sta_addr, addr, ETH_ALEN); -- param.u.set_flags_sta.flags_or = flags_or; -- param.u.set_flags_sta.flags_and = flags_and; -- return hostapd_ioctl(drv, ¶m, sizeof(param)); -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; -+ -+ flags = nlmsg_alloc(); -+ if (!flags) -+ goto free_msg; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(drv->iface)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ -+ if (total_flags & WLAN_STA_AUTHORIZED) -+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); -+ -+ if (total_flags & WLAN_STA_WME) -+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); -+ -+ if (total_flags & WLAN_STA_SHORT_PREAMBLE) -+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); -+ -+ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) -+ goto nla_put_failure; -+ -+ ret = 0; -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || -+ nl_wait_for_ack(drv->nl_handle) < 0) { -+ ret = -1; -+ } -+ -+ nla_put_failure: -+ nlmsg_free(flags); -+ -+ free_msg: -+ nlmsg_free(msg); -+ -+ out: -+ return ret; - } - - -@@ -1257,18 +1410,38 @@ static struct hostapd_hw_modes * i802_ge - } - - --static int i802_set_sta_vlan(void *priv, const u8 *addr, const char *ifname, -- int vlan_id) -+static int i802_set_sta_vlan(void *priv, const u8 *addr, -+ const char *ifname, int vlan_id) - { - struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param param; -+ struct nl_msg *msg; -+ int ret = -1; - -- memset(¶m, 0, sizeof(param)); -- param.cmd = PRISM2_HOSTAPD_SET_STA_VLAN; -- memcpy(param.sta_addr, addr, ETH_ALEN); -- os_strlcpy(param.u.set_sta_vlan.vlan_name, ifname, IFNAMSIZ); -- param.u.set_sta_vlan.vlan_id = vlan_id; -- return hostapd_ioctl(drv, ¶m, sizeof(param)); -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto out; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(drv->iface)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(ifname)); -+ -+ ret = 0; -+ -+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 || -+ nl_wait_for_ack(drv->nl_handle) < 0) { -+ ret = -1; -+ } -+ -+ nla_put_failure: -+ nlmsg_free(msg); -+ -+ out: -+ return ret; - } - - -@@ -1752,17 +1925,14 @@ static int i802_init_sockets(struct i802 - - static int i802_get_inact_sec(void *priv, const u8 *addr) - { -- struct i802_driver_data *drv = priv; -- struct prism2_hostapd_param param; -+ struct hostap_sta_driver_data data; -+ int ret; - -- memset(¶m, 0, sizeof(param)); -- param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; -- memcpy(param.sta_addr, addr, ETH_ALEN); -- if (hostapd_ioctl(drv, ¶m, sizeof(param))) { -+ data.inactive_msec = -1; -+ ret = i802_read_sta_data(priv, &data, addr); -+ if (ret || data.inactive_msec == -1) - return -1; -- } -- -- return param.u.get_info_sta.inactive_msec / 1000; -+ return data.inactive_msec / 1000; - } - - |