#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include "nl80211_copy.h"
-#ifndef NO_WEXT
-#include "wireless_copy.h"
-#endif /* NO_WEXT */
#include "common.h"
#include "driver.h"
#include "radiotap.h"
#include "radiotap_iter.h"
-#include "../../hostapd/hostapd_defs.h"
+#include "../../hostapd/sta_flags.h"
#endif /* CONFIG_AP || HOSTAPD */
#ifdef HOSTAPD
-#include "../../hostapd/sta_flags.h"
#include "ieee802_11_common.h"
+#endif /* HOSTAPD */
#ifdef CONFIG_LIBNL20
/* libnl 2.0 compatibility code */
+#define nl_handle nl_sock
#define nl_handle_alloc_cb nl_socket_alloc_cb
#define nl_handle_destroy nl_socket_free
#endif /* CONFIG_LIBNL20 */
-#endif /* HOSTAPD */
-
#ifndef IFF_LOWER_UP
#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
int scan_complete_events;
struct nl_handle *nl_handle;
+ struct nl_handle *nl_handle_event;
struct nl_cache *nl_cache;
+ struct nl_cache *nl_cache_event;
struct nl_cb *nl_cb;
struct genl_family *nl80211;
int nlmode;
int ap_scan_as_station;
- int beacon_int;
int monitor_sock;
int monitor_ifidx;
-#ifdef CONFIG_AP
unsigned int beacon_set:1;
-#endif /* CONFIG_AP */
#ifdef HOSTAPD
int eapol_sock; /* socket for EAPOL frames */
#endif /* HOSTAPD */
-#ifndef HOSTAPD
-
static int wpa_driver_nl80211_send_oper_ifla(
struct wpa_driver_nl80211_data *drv,
int linkmode, int operstate)
req.ifinfo.ifi_change = 0;
if (linkmode != -1) {
- rta = (struct rtattr *)
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
rta->rta_type = IFLA_LINKMODE;
rta->rta_len = RTA_LENGTH(sizeof(char));
*((char *) RTA_DATA(rta)) = linkmode;
RTA_LENGTH(sizeof(char));
}
if (operstate != -1) {
- rta = (struct rtattr *)
- ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
rta->rta_type = IFLA_OPERSTATE;
rta->rta_len = RTA_LENGTH(sizeof(char));
*((char *) RTA_DATA(rta)) = operstate;
}
-#ifndef NO_WEXT
-static int wpa_driver_nl80211_set_auth_param(
- struct wpa_driver_nl80211_data *drv, int idx, u32 value)
-{
- struct iwreq iwr;
- int ret = 0;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.param.flags = idx & IW_AUTH_INDEX;
- iwr.u.param.value = value;
-
- if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
- if (errno != EOPNOTSUPP) {
- wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
- "value 0x%x) failed: %s)",
- idx, value, strerror(errno));
- }
- ret = errno == EOPNOTSUPP ? -2 : -1;
- }
-
- return ret;
-}
-#endif /* NO_WEXT */
-
-
static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
{
struct wpa_driver_nl80211_data *drv = priv;
}
+#ifndef HOSTAPD
+
static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
void *ctx, char *buf, size_t len,
int del)
}
}
+#endif /* HOSTAPD */
+
static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
const u8 *frame, size_t len)
}
+static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *status,
+ struct nlattr *addr, struct nlattr *req_ie,
+ struct nlattr *resp_ie)
+{
+ union wpa_event_data event;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
+ "when using userspace SME", cmd);
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ if (cmd == NL80211_CMD_CONNECT &&
+ nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
+ if (resp_ie) {
+ event.assoc_reject.resp_ies = nla_data(resp_ie);
+ event.assoc_reject.resp_ies_len = nla_len(resp_ie);
+ }
+ event.assoc_reject.status_code = nla_get_u16(status);
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ if (addr)
+ os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+
+ if (req_ie) {
+ event.assoc_info.req_ies = nla_data(req_ie);
+ event.assoc_info.req_ies_len = nla_len(req_ie);
+ }
+ if (resp_ie) {
+ event.assoc_info.resp_ies = nla_data(resp_ie);
+ event.assoc_info.resp_ies_len = nla_len(resp_ie);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *addr)
+{
+ union wpa_event_data event;
+ enum wpa_event_type ev;
+
+ if (nla_len(addr) != ETH_ALEN)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
+ cmd, MAC2STR((u8 *) nla_data(addr)));
+
+ if (cmd == NL80211_CMD_AUTHENTICATE)
+ ev = EVENT_AUTH_TIMED_OUT;
+ else if (cmd == NL80211_CMD_ASSOCIATE)
+ ev = EVENT_ASSOC_TIMED_OUT;
+ else
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, ev, &event);
+}
+
+
static void mlme_event(struct wpa_driver_nl80211_data *drv,
- enum nl80211_commands cmd, struct nlattr *frame)
+ enum nl80211_commands cmd, struct nlattr *frame,
+ struct nlattr *addr, struct nlattr *timed_out)
{
+ if (timed_out && addr) {
+ mlme_timeout_event(drv, cmd, addr);
+ return;
+ }
+
if (frame == NULL) {
wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
"data", cmd);
}
}
-#endif /* HOSTAPD */
-
static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
struct nlattr *tb[])
}
switch (gnlh->cmd) {
+ case NL80211_CMD_TRIGGER_SCAN:
+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
+ break;
case NL80211_CMD_NEW_SCAN_RESULTS:
wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
drv->scan_complete_events = 1;
drv->ctx);
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
break;
-#ifndef HOSTAPD
case NL80211_CMD_AUTHENTICATE:
case NL80211_CMD_ASSOCIATE:
case NL80211_CMD_DEAUTHENTICATE:
case NL80211_CMD_DISASSOCIATE:
- mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME]);
+ mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+ tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT]);
+ break;
+ case NL80211_CMD_CONNECT:
+ case NL80211_CMD_ROAM:
+ mlme_event_connect(drv, gnlh->cmd,
+ tb[NL80211_ATTR_STATUS_CODE],
+ tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_REQ_IE],
+ tb[NL80211_ATTR_RESP_IE]);
+ break;
+ case NL80211_CMD_DISCONNECT:
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two disassociation events that could
+ * confuse the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event when using userspace SME");
+ break;
+ }
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
break;
-#endif /* HOSTAPD */
case NL80211_CMD_MICHAEL_MIC_FAILURE:
mlme_event_michael_mic_failure(drv, tb);
break;
return;
nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
- nl_recvmsgs(drv->nl_handle, cb);
+ nl_recvmsgs(drv->nl_handle_event, cb);
nl_cb_put(cb);
}
struct wiphy_info_data {
int max_scan_ssids;
int ap_supported;
+ int auth_supported;
+ int connect_supported;
};
}
}
+ if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
+ struct nlattr *nl_cmd;
+ int i;
+
+ nla_for_each_nested(nl_cmd,
+ tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
+ u32 cmd = nla_get_u32(nl_cmd);
+ if (cmd == NL80211_CMD_AUTHENTICATE)
+ info->auth_supported = 1;
+ else if (cmd == NL80211_CMD_CONNECT)
+ info->connect_supported = 1;
+ }
+ }
+
return NL_SKIP;
}
}
-static void wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
+static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
{
struct wiphy_info_data info;
if (wpa_driver_nl80211_get_info(drv, &info))
- return;
+ return -1;
drv->has_capability = 1;
/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
drv->capa.max_scan_ssids = info.max_scan_ssids;
if (info.ap_supported)
drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
+
+ if (info.auth_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
+ else if (!info.connect_supported) {
+ wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+ "authentication/association or connect commands");
+ return -1;
+ }
+
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
+
+ return 0;
}
#endif /* HOSTAPD */
goto err2;
}
+ drv->nl_handle_event = nl_handle_alloc_cb(drv->nl_cb);
+ if (drv->nl_handle_event == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks (event)");
+ goto err2b;
+ }
+
if (genl_connect(drv->nl_handle)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
"netlink");
goto err3;
}
+ if (genl_connect(drv->nl_handle_event)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+ "netlink (event)");
+ goto err3;
+ }
+
#ifdef CONFIG_LIBNL20
if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) {
wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
"netlink cache");
goto err3;
}
+ if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) <
+ 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+ "netlink cache (event)");
+ goto err3b;
+ }
#else /* CONFIG_LIBNL20 */
drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
if (drv->nl_cache == NULL) {
"netlink cache");
goto err3;
}
+ drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event);
+ if (drv->nl_cache_event == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+ "netlink cache (event)");
+ goto err3b;
+ }
#endif /* CONFIG_LIBNL20 */
-
drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
if (drv->nl80211 == NULL) {
wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
ret = nl_get_multicast_id(drv, "nl80211", "scan");
if (ret >= 0)
- ret = nl_socket_add_membership(drv->nl_handle, ret);
+ ret = nl_socket_add_membership(drv->nl_handle_event, ret);
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
"membership for scan events: %d (%s)",
ret = nl_get_multicast_id(drv, "nl80211", "mlme");
if (ret >= 0)
- ret = nl_socket_add_membership(drv->nl_handle, ret);
+ ret = nl_socket_add_membership(drv->nl_handle_event, ret);
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
"membership for mlme events: %d (%s)",
goto err4;
}
- eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle),
+ eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
wpa_driver_nl80211_event_receive, drv, ctx);
return 0;
err4:
+ nl_cache_free(drv->nl_cache_event);
+err3b:
nl_cache_free(drv->nl_cache);
err3:
+ nl_handle_destroy(drv->nl_handle_event);
+err2b:
nl_handle_destroy(drv->nl_handle);
err2:
nl_cb_put(drv->nl_cb);
return NULL;
}
- drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
-
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
perror("socket(PF_INET,SOCK_DGRAM)");
return -1;
}
- wpa_driver_nl80211_capa(drv);
+ if (wpa_driver_nl80211_capa(drv))
+ return -1;
wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
#endif /* HOSTAPD */
wpa_driver_nl80211_free_bss(drv);
#else /* HOSTAPD */
-#ifndef NO_WEXT
- wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, 0);
-#endif /* NO_WEXT */
wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
- eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle));
+ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
genl_family_put(drv->nl80211);
nl_cache_free(drv->nl_cache);
+ nl_cache_free(drv->nl_cache_event);
nl_handle_destroy(drv->nl_handle);
+ nl_handle_destroy(drv->nl_handle_event);
nl_cb_put(drv->nl_cb);
os_free(drv);
[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+ [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
};
struct wpa_scan_results *res = arg;
struct wpa_scan_res **tmp;
r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
if (bss[NL80211_BSS_TSF])
r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+ if (bss[NL80211_BSS_SEEN_MS_AGO])
+ r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
r->ie_len = ie_len;
if (ie)
os_memcpy(r + 1, ie, ie_len);
}
-static int nl_set_encr(int ifindex, struct wpa_driver_nl80211_data *drv,
- wpa_alg alg, const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
+static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
+ wpa_alg alg, const u8 *addr, int key_idx,
+ int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int ifindex = if_nametoindex(ifname);
struct nl_msg *msg;
int ret;
case WPA_ALG_WEP:
if (key_len == 5)
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
- 0x000FAC01);
+ WLAN_CIPHER_SUITE_WEP40);
else
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
- 0x000FAC05);
+ WLAN_CIPHER_SUITE_WEP104);
break;
case WPA_ALG_TKIP:
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_TKIP);
break;
case WPA_ALG_CCMP:
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_CCMP);
break;
case WPA_ALG_IGTK:
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_AES_CMAC);
break;
default:
wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
}
}
- if (seq)
+ if (seq && seq_len)
NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
}
-#ifndef HOSTAPD
+static int nl_add_key(struct nl_msg *msg, wpa_alg alg,
+ int key_idx, int defkey,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
+ if (!key_attr)
+ return -1;
-static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
- const u8 *addr, int key_idx,
- int set_tx, const u8 *seq,
- size_t seq_len,
- const u8 *key, size_t key_len)
+ if (defkey && alg == WPA_ALG_IGTK)
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
+ else if (defkey)
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+
+ NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
+
+ switch (alg) {
+ case WPA_ALG_WEP:
+ if (key_len == 5)
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP40);
+ else
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP104);
+ break;
+ case WPA_ALG_TKIP:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
+ break;
+ case WPA_ALG_CCMP:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
+ break;
+ case WPA_ALG_IGTK:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_AES_CMAC);
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
+ "algorithm %d", __func__, alg);
+ return -1;
+ }
+
+ if (seq && seq_len)
+ NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
+
+ NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
+
+ nla_nest_end(msg, key_attr);
+
+ return 0;
+ nla_put_failure:
+ return -1;
+}
+
+
+static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
+ struct nl_msg *msg)
{
- struct wpa_driver_nl80211_data *drv = priv;
- return nl_set_encr(drv->ifindex, drv, alg, addr, key_idx, set_tx, seq,
- seq_len, key, key_len);
+ int i, privacy = 0;
+ struct nlattr *nl_keys, *nl_key;
+
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+ privacy = 1;
+ break;
+ }
+ if (!privacy)
+ return 0;
+
+ NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+
+ nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
+ if (!nl_keys)
+ goto nla_put_failure;
+
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+
+ nl_key = nla_nest_start(msg, i);
+ if (!nl_key)
+ goto nla_put_failure;
+
+ NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
+ params->wep_key[i]);
+ if (params->wep_key_len[i] == 5)
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP40);
+ else
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_WEP104);
+
+ NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
+
+ if (i == params->wep_tx_keyidx)
+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+
+ nla_nest_end(msg, nl_key);
+ }
+ nla_nest_end(msg, nl_keys);
+
+ return 0;
+
+nla_put_failure:
+ return -ENOBUFS;
}
}
+static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int reason_code)
+{
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ drv->associated = 0;
+ return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
+ reason_code);
+}
+
+
static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
int reason_code)
{
struct wpa_driver_nl80211_data *drv = priv;
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
+ return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
wpa_printf(MSG_DEBUG, "%s", __func__);
drv->associated = 0;
return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
int reason_code)
{
struct wpa_driver_nl80211_data *drv = priv;
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
+ return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
wpa_printf(MSG_DEBUG, "%s", __func__);
drv->associated = 0;
return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
int ret = -1, i;
struct nl_msg *msg;
enum nl80211_auth_type type;
+ int count = 0;
drv->associated = 0;
+ if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_INFRA) < 0)
+ return -1;
+
+retry:
msg = nlmsg_alloc();
if (!msg)
return -1;
wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
drv->ifindex);
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_AUTHENTICATE, 0);
+
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
continue;
- wpa_driver_nl80211_set_key(drv, WPA_ALG_WEP, NULL, i,
+ wpa_driver_nl80211_set_key(drv->ifname, drv, WPA_ALG_WEP, NULL,
+ i,
i == params->wep_tx_keyidx, NULL, 0,
params->wep_key[i],
params->wep_key_len[i]);
+ if (params->wep_tx_keyidx != i)
+ continue;
+ if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
+ params->wep_key[i], params->wep_key_len[i])) {
+ nlmsg_free(msg);
+ return -1;
+ }
}
- genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
- NL80211_CMD_AUTHENTICATE, 0);
-
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (params->bssid) {
wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
"(%s)", ret, strerror(-ret));
+ count++;
+ if (ret == -EALREADY && count == 1 && params->bssid) {
+ /*
+ * mac80211 does not currently accept new
+ * authentication if we are already authenticated. As a
+ * workaround, force deauthentication and try again.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
+ "after forced deauthentication");
+ wpa_driver_nl80211_deauthenticate(
+ drv, params->bssid,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ nlmsg_free(msg);
+ goto retry;
+ }
goto nla_put_failure;
}
ret = 0;
return ret;
}
-#endif /* HOSTAPD */
-
#if defined(CONFIG_AP) || defined(HOSTAPD)
tb_band[NL80211_BAND_ATTR_HT_CAPA]);
}
+ if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
+ nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
+ u8 *mcs;
+ mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+ os_memcpy(mode->mcs_set, mcs, 16);
+ }
+
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);
{
struct wpa_driver_nl80211_data *drv = priv;
struct ieee80211_mgmt *mgmt;
- int do_not_encrypt = 0;
+ int encrypt = 1;
u16 fc;
mgmt = (struct ieee80211_mgmt *) data;
*/
u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
- if (auth_alg == WLAN_AUTH_OPEN ||
- (auth_alg == WLAN_AUTH_SHARED_KEY && auth_trans != 3))
- do_not_encrypt = 1;
+ if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
+ encrypt = 0;
}
- return wpa_driver_nl80211_send_frame(drv, data, data_len,
- !do_not_encrypt);
+ return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
}
+#endif /* CONFIG_AP || HOSTAPD */
+
-static int wpa_driver_nl80211_set_beacon_iface(int ifindex, void *priv,
- const u8 *head, size_t head_len,
- const u8 *tail, size_t tail_len,
- int dtim_period)
+static int wpa_driver_nl80211_set_beacon(const char *ifname, void *priv,
+ const u8 *head, size_t head_len,
+ const u8 *tail, size_t tail_len,
+ int dtim_period, int beacon_int)
{
struct wpa_driver_nl80211_data *drv = priv;
struct nl_msg *msg;
u8 cmd = NL80211_CMD_NEW_BEACON;
int ret;
int beacon_set;
+ int ifindex = if_nametoindex(ifname);
#ifdef HOSTAPD
struct i802_bss *bss;
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, ifindex);
- if (!drv->beacon_int)
- drv->beacon_int = 100;
- NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, drv->beacon_int);
+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int);
NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
}
-static int wpa_driver_nl80211_set_beacon_int(void *priv, int value)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- struct nl_msg *msg;
-
- drv->beacon_int = value;
-
-#ifdef HOSTAPD
- if (!drv->bss.beacon_set)
- return 0;
-#else /* HOSTAPD */
- if (!drv->beacon_set)
- return 0;
-#endif /* HOSTAPD */
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- wpa_printf(MSG_DEBUG, "nl80211: Set beacon interval %d", value);
- 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, drv->ifindex);
-
- NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value);
-
- return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
- return -ENOBUFS;
-}
-
+#if defined(CONFIG_AP) || defined(HOSTAPD)
static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
int freq, int ht_enabled,
return -ENOBUFS;
}
-#endif /* CONFIG_AP || HOSTAPD */
-
-
-#ifdef CONFIG_AP
-
-static int wpa_driver_nl80211_set_beacon(void *priv,
- const u8 *head, size_t head_len,
- const u8 *tail, size_t tail_len,
- int dtim_period)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- return wpa_driver_nl80211_set_beacon_iface(drv->ifindex, priv,
- head, head_len,
- tail, tail_len,
- dtim_period);
-}
-
-#endif /* CONFIG_AP */
-
-#if defined(CONFIG_AP) || defined(HOSTAPD)
static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
int ifidx)
}
-static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
- const char *ifname, enum nl80211_iftype iftype,
- const u8 *addr)
+static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
+ const char *ifname,
+ enum nl80211_iftype iftype,
+ const u8 *addr)
{
struct nl_msg *msg, *flags = NULL;
int ifidx;
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
nla_put_failure:
- wpa_printf(MSG_ERROR, "Failed to create interface %s.",
- ifname);
+ wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
+ ifname, ret, strerror(-ret));
return ret;
}
return ifidx;
}
+static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype,
+ const u8 *addr)
+{
+ int ret;
+
+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr);
+
+ /* if error occured and interface exists already */
+ if (ret == -ENFILE && if_nametoindex(ifname)) {
+ wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
+
+ /* Try to remove the interface that was already there. */
+ nl80211_remove_iface(drv, if_nametoindex(ifname));
+
+ /* Try to create the interface again */
+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr);
+ }
+
+ return ret;
+}
#endif /* CONFIG_AP || HOSTAPD */
void ap_tx_status(void *ctx, const u8 *addr,
const u8 *buf, size_t len, int ack);
-void ap_rx_from_unknown_sta(void *ctx, const u8 *addr);
+void ap_rx_from_unknown_sta(void *ctx, struct ieee80211_hdr *hdr, size_t len);
void ap_mgmt_rx(void *ctx, u8 *buf, size_t len, u16 stype,
struct hostapd_frame_info *fi);
void ap_mgmt_tx_cb(void *ctx, u8 *buf, size_t len, u16 stype, int ok);
#ifdef HOSTAPD
hostapd_rx_from_unknown_sta(drv->ctx, hdr, len);
#else /* HOSTAPD */
- ap_rx_from_unknown_sta(drv->ctx, hdr->addr2);
+ ap_rx_from_unknown_sta(drv->ctx, hdr, len);
#endif /* HOSTAPD */
}
return -1;
}
-#endif /* CONFIG_AP || HOSTAPD */
-#ifdef CONFIG_AP
+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
- struct wpa_driver_associate_params *params)
+static int wpa_driver_nl80211_hapd_send_eapol(
+ void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr)
{
- if (wpa_driver_nl80211_set_mode(drv, params->mode) ||
- wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
- nl80211_remove_monitor_interface(drv);
- return -1;
+ struct wpa_driver_nl80211_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 = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
+ "failed: %d (%s)",
+ (unsigned long) len, errno, strerror(errno));
+ }
+ free(hdr);
+
+ return res;
+}
+
+
+static u32 sta_flags_nl80211(int flags)
+{
+ u32 f = 0;
+
+ if (flags & WLAN_STA_AUTHORIZED)
+ f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+ if (flags & WLAN_STA_WMM)
+ f |= BIT(NL80211_STA_FLAG_WME);
+ if (flags & WLAN_STA_SHORT_PREAMBLE)
+ f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
+ if (flags & WLAN_STA_MFP)
+ f |= BIT(NL80211_STA_FLAG_MFP);
+
+ return f;
+}
+
+
+static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
+ int total_flags, int flags_or,
+ int flags_and)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg, *flags = NULL;
+ struct nl80211_sta_flag_update upd;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ flags = nlmsg_alloc();
+ if (!flags) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
+
+ 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->ifname));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ /*
+ * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
+ * can be removed eventually.
+ */
+ if (total_flags & WLAN_STA_AUTHORIZED)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+
+ if (total_flags & WLAN_STA_WMM)
+ 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 (total_flags & WLAN_STA_MFP)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+
+ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
+ goto nla_put_failure;
+
+ os_memset(&upd, 0, sizeof(upd));
+ upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
+ upd.set = sta_flags_nl80211(flags_or);
+ NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+ nlmsg_free(flags);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ nlmsg_free(flags);
+ return -ENOBUFS;
+}
+
+#endif /* CONFIG_AP || HOSTAPD */
+
+#ifdef CONFIG_AP
+
+static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ if (wpa_driver_nl80211_set_mode(drv, params->mode) ||
+ wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
+ nl80211_remove_monitor_interface(drv);
+ return -1;
}
/* TODO: setup monitor interface (and add code somewhere to remove this
#endif /* CONFIG_AP */
-#ifndef HOSTAPD
+static int wpa_driver_nl80211_connect(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct nl_msg *msg;
+ enum nl80211_auth_type type;
+ int ret = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_CONNECT, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+ }
+ if (params->freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+ }
+ if (params->ssid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
+ params->ssid, params->ssid_len);
+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid);
+ if (params->ssid_len > sizeof(drv->ssid))
+ goto nla_put_failure;
+ os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+ drv->ssid_len = params->ssid_len;
+ }
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
+ if (params->wpa_ie)
+ NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie);
+
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ else if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ type = NL80211_AUTHTYPE_SHARED_KEY;
+ else if (params->auth_alg & AUTH_ALG_LEAP)
+ type = NL80211_AUTHTYPE_NETWORK_EAP;
+ else if (params->auth_alg & AUTH_ALG_FT)
+ type = NL80211_AUTHTYPE_FT;
+ else
+ goto nla_put_failure;
+
+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
+ NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+
+ if (params->wpa_ie && params->wpa_ie_len) {
+ enum nl80211_wpa_versions ver;
+
+ if (params->wpa_ie[0] == WLAN_EID_RSN)
+ ver = NL80211_WPA_VERSION_2;
+ else
+ ver = NL80211_WPA_VERSION_1;
+
+ wpa_printf(MSG_DEBUG, " * WPA Version %d", ver);
+ NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+ }
+
+ if (params->pairwise_suite != CIPHER_NONE) {
+ int cipher;
+
+ switch (params->pairwise_suite) {
+ case CIPHER_WEP40:
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ break;
+ case CIPHER_WEP104:
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ break;
+ case CIPHER_CCMP:
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+ break;
+ case CIPHER_TKIP:
+ default:
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+ }
+
+ if (params->group_suite != CIPHER_NONE) {
+ int cipher;
+
+ switch (params->group_suite) {
+ case CIPHER_WEP40:
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ break;
+ case CIPHER_WEP104:
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ break;
+ case CIPHER_CCMP:
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+ break;
+ case CIPHER_TKIP:
+ default:
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+ }
+
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK) {
+ int mgmt = WLAN_AKM_SUITE_PSK;
+
+ switch (params->key_mgmt_suite) {
+ case KEY_MGMT_802_1X:
+ mgmt = WLAN_AKM_SUITE_8021X;
+ break;
+ case KEY_MGMT_PSK:
+ default:
+ mgmt = WLAN_AKM_SUITE_PSK;
+ break;
+ }
+ NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
+ }
+
+ ret = nl80211_set_conn_keys(params, msg);
+ if (ret)
+ goto nla_put_failure;
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+ ret = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+
+}
+
+
static int wpa_driver_nl80211_associate(
void *priv, struct wpa_driver_associate_params *params)
{
return wpa_driver_nl80211_ap(drv, params);
#endif /* CONFIG_AP */
-#ifndef NO_WEXT
- wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
- params->drop_unencrypted);
-#endif /* NO_WEXT */
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ if (wpa_driver_nl80211_set_mode(drv, params->mode) < 0)
+ return -1;
+ return wpa_driver_nl80211_connect(drv, params);
+ }
drv->associated = 0;
NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
params->wpa_ie);
+#ifdef CONFIG_IEEE80211W
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
+ NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+#endif /* CONFIG_IEEE80211W */
+
+ NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+
+ if (params->prev_bssid) {
+ wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
+ MAC2STR(params->prev_bssid));
+ NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
+ params->prev_bssid);
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
nlmsg_free(msg);
return ret;
}
-#endif /* HOSTAPD */
static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
}
-#ifndef HOSTAPD
-
static int wpa_driver_nl80211_get_capa(void *priv,
struct wpa_driver_capa *capa)
{
drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
}
-#endif /* HOSTAPD */
+static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ struct nl80211_sta_flag_update upd;
-#ifdef HOSTAPD
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
-static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+ 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->ifname));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
+
+ os_memset(&upd, 0, sizeof(upd));
+ upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
+ if (authorized)
+ upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
+ NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+#ifdef HOSTAPD
static struct i802_bss * get_bss(struct wpa_driver_nl80211_data *drv,
int ifindex)
}
-static int i802_set_key(const char *iface, void *priv, wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx, const u8 *seq,
- size_t seq_len, const u8 *key, size_t key_len)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- return nl_set_encr(if_nametoindex(iface), drv, alg, addr, key_idx,
- set_tx, seq, seq_len, key, key_len);
-}
-
-
static inline int min_int(int a, int b)
{
if (a < b)
static int i802_set_rts(void *priv, int rts)
{
-#ifdef NO_WEXT
- return -1;
-#else /* NO_WEXT */
struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
-
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, 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;
-#endif /* NO_WEXT */
-}
-
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+ u32 val;
-static int i802_set_frag(void *priv, int frag)
-{
-#ifdef NO_WEXT
- return -1;
-#else /* NO_WEXT */
- struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.frag.value = frag;
- iwr.u.frag.fixed = 1;
+ if (rts >= 2347)
+ val = (u32) -1;
+ else
+ val = rts;
- if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) {
- perror("ioctl[SIOCSIWFRAG]");
- return -1;
- }
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_WIPHY, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
- return 0;
-#endif /* NO_WEXT */
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (!ret)
+ return 0;
+nla_put_failure:
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
+ "%d (%s)", rts, ret, strerror(-ret));
+ return ret;
}
-static int i802_set_retry(void *priv, int short_retry, int long_retry)
+static int i802_set_frag(void *priv, int frag)
{
-#ifdef NO_WEXT
- return -1;
-#else /* NO_WEXT */
struct wpa_driver_nl80211_data *drv = priv;
- struct iwreq iwr;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+ u32 val;
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
- iwr.u.retry.value = short_retry;
- iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
- if (ioctl(drv->ioctl_sock, SIOCSIWRETRY, &iwr) < 0) {
- perror("ioctl[SIOCSIWRETRY(short)]");
- return -1;
- }
+ if (frag >= 2346)
+ val = (u32) -1;
+ else
+ val = frag;
- iwr.u.retry.value = long_retry;
- iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
- if (ioctl(drv->ioctl_sock, SIOCSIWRETRY, &iwr) < 0) {
- perror("ioctl[SIOCSIWRETRY(long)]");
- return -1;
- }
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_WIPHY, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
- return 0;
-#endif /* NO_WEXT */
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (!ret)
+ return 0;
+nla_put_failure:
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
+ "%d: %d (%s)", frag, ret, strerror(-ret));
+ 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 wpa_driver_nl80211_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 = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
- if (res < 0) {
- wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
- "failed: %d (%s)",
- (unsigned long) len, errno, strerror(errno));
- }
- free(hdr);
-
- return res;
-}
-
-
-static int i802_sta_set_flags(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and)
-{
- struct wpa_driver_nl80211_data *drv = priv;
- struct nl_msg *msg, *flags = NULL;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- flags = nlmsg_alloc();
- if (!flags) {
- nlmsg_free(msg);
- return -ENOMEM;
- }
-
- 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->ifname));
- 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_WMM)
- 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 (total_flags & WLAN_STA_MFP)
- NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
-
- if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
- goto nla_put_failure;
-
- nlmsg_free(flags);
-
- return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
- nlmsg_free(flags);
- return -ENOBUFS;
-}
-
-
static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
int cw_min, int cw_max, int burst_time)
{
}
-static int i802_set_beacon(const char *iface, void *priv,
- const u8 *head, size_t head_len,
- const u8 *tail, size_t tail_len, int dtim_period)
-{
- return wpa_driver_nl80211_set_beacon_iface(if_nametoindex(iface), priv,
- head, head_len,
- tail, tail_len,
- dtim_period);
-}
-
-
static int i802_set_bss(void *priv, int cts, int preamble, int slot)
{
struct wpa_driver_nl80211_data *drv = priv;
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
if_nametoindex(drv->ifname));
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
if_nametoindex(ifname));
return send_and_recv_msgs(drv, msg, NULL, NULL);
/* start listening for EAPOL on the default AP interface */
add_ifidx(drv, drv->ifindex);
- if (params->bssid) {
- if (hostapd_set_iface_flags(drv, drv->ifname, 0))
- goto failed;
+ if (hostapd_set_iface_flags(drv, drv->ifname, 0))
+ goto failed;
+ if (params->bssid) {
if (set_ifhwaddr(drv, drv->ifname, params->bssid))
goto failed;
}
- if (nl80211_set_mode(drv, drv->ifindex, NL80211_IFTYPE_AP)) {
+ if (wpa_driver_nl80211_set_mode(drv, IEEE80211_MODE_AP)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
"into AP mode", drv->ifname);
goto failed;
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
-#ifndef HOSTAPD
.get_bssid = wpa_driver_nl80211_get_bssid,
.get_ssid = wpa_driver_nl80211_get_ssid,
.set_key = wpa_driver_nl80211_set_key,
-#endif /* HOSTAPD */
.scan2 = wpa_driver_nl80211_scan,
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
-#ifndef HOSTAPD
.deauthenticate = wpa_driver_nl80211_deauthenticate,
.disassociate = wpa_driver_nl80211_disassociate,
.authenticate = wpa_driver_nl80211_authenticate,
.deinit = wpa_driver_nl80211_deinit,
.get_capa = wpa_driver_nl80211_get_capa,
.set_operstate = wpa_driver_nl80211_set_operstate,
-#endif /* HOSTAPD */
+ .set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
- .set_mode = wpa_driver_nl80211_set_mode,
-#ifdef CONFIG_AP
.set_beacon = wpa_driver_nl80211_set_beacon,
-#endif /* CONFIG_AP */
#if defined(CONFIG_AP) || defined(HOSTAPD)
.send_mlme = wpa_driver_nl80211_send_mlme,
- .set_beacon_int = wpa_driver_nl80211_set_beacon_int,
.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
.sta_remove = wpa_driver_nl80211_sta_remove,
+ .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
+ .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
#endif /* CONFIG_AP || HOSTAPD */
#ifdef HOSTAPD
.hapd_init = i802_init,
.hapd_deinit = i802_deinit,
- .hapd_set_key = i802_set_key,
.get_seqnum = i802_get_seqnum,
.flush = i802_flush,
.read_sta_data = i802_read_sta_data,
- .hapd_send_eapol = i802_send_eapol,
- .sta_set_flags = i802_sta_set_flags,
.sta_deauth = i802_sta_deauth,
.sta_disassoc = i802_sta_disassoc,
.get_inact_sec = i802_get_inact_sec,
.set_freq = i802_set_freq,
.set_rts = i802_set_rts,
.set_frag = i802_set_frag,
- .set_retry = i802_set_retry,
.set_rate_sets = i802_set_rate_sets,
- .hapd_set_beacon = i802_set_beacon,
.set_cts_protect = i802_set_cts_protect,
.set_preamble = i802_set_preamble,
.set_short_slot_time = i802_set_short_slot_time,