eloop_sock_handler handler,
void *eloop_data)
{
+#ifdef CONFIG_LIBNL20
/*
* libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
* by default. It is possible to hit that limit in some cases where
strerror(errno));
/* continue anyway with the default (smaller) buffer */
}
+#endif /* CONFIG_LIBNL20 */
nl_socket_set_nonblocking(*handle);
eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
static void nl80211_global_deinit(void *priv);
+static void nl80211_check_global(struct nl80211_global *global);
static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
return 1;
if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
+ nl80211_check_global(drv->global);
wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
"interface");
wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
(ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+ namebuf[0] = '\0';
if (if_indextoname(ifi->ifi_index, namebuf) &&
- linux_iface_up(drv->global->ioctl_sock,
- drv->first_bss->ifname) > 0) {
+ linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
"event since interface %s is up", namebuf);
drv->ignore_if_down_event = 0;
return;
}
- wpa_printf(MSG_DEBUG, "nl80211: Interface down");
- if (drv->ignore_if_down_event) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
+ namebuf, ifname);
+ if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Not the main interface (%s) - do not indicate interface down",
+ drv->first_bss->ifname);
+ } else if (drv->ignore_if_down_event) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
"event generated by mode change");
drv->ignore_if_down_event = 0;
if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
if (if_indextoname(ifi->ifi_index, namebuf) &&
- linux_iface_up(drv->global->ioctl_sock,
- drv->first_bss->ifname) == 0) {
+ linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
"event since interface %s is down",
namebuf);
}
+static void nl80211_check_global(struct nl80211_global *global)
+{
+ struct nl_handle *handle;
+ const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
+ int ret;
+ unsigned int i;
+
+ /*
+ * Try to re-add memberships to handle case of cfg80211 getting reloaded
+ * and all registration having been cleared.
+ */
+ handle = (void *) (((intptr_t) global->nl_event) ^
+ ELOOP_SOCKET_INVALID);
+
+ for (i = 0; groups[i]; i++) {
+ ret = nl_get_multicast_id(global, "nl80211", groups[i]);
+ if (ret >= 0)
+ ret = nl_socket_add_membership(handle, ret);
+ if (ret < 0) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
+ groups[i], ret, strerror(-ret));
+ }
+ }
+}
+
+
static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
{
wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
}
if (drv->global) {
+ nl80211_check_global(drv->global);
dl_list_add(&drv->global->interfaces, &drv->list);
drv->in_interface_list = 1;
}
}
+#ifdef CONFIG_TESTING_OPTIONS
+static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
+{
+ /* struct wpa_driver_nl80211_data *drv = arg; */
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: QCA vendor test command response received");
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_VENDOR_DATA]) {
+ wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
+ return NL_SKIP;
+ }
+
+ wpa_hexdump(MSG_DEBUG,
+ "nl80211: Received QCA vendor test command response",
+ nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
+ nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
+
+ return NL_SKIP;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
+static void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_TEST) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
+ nlmsg_free(msg);
+ return;
+ }
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: QCA vendor test command returned %d (%s)",
+ ret, strerror(-ret));
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
const u8 *set_addr, int first,
drv, drv->ctx);
}
+ if (drv->vendor_cmd_test_avail)
+ qca_vendor_test(drv);
+
return 0;
}
u32 suites[10], suite;
u32 ver;
- beacon_set = bss->beacon_set;
+ beacon_set = params->reenable ? 0 : bss->beacon_set;
wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
beacon_set);
goto fail;
}
+#ifdef CONFIG_P2P
+ if (params->p2p_go_ctwindow > 0) {
+ if (drv->p2p_go_ctwindow_supported) {
+ wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
+ params->p2p_go_ctwindow);
+ if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
+ params->p2p_go_ctwindow))
+ goto fail;
+ } else {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
+ }
+ }
+#endif /* CONFIG_P2P */
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
goto fail;
}
+ if (params->fixed_freq) {
+ wpa_printf(MSG_DEBUG, " * fixed_freq");
+ if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
+ goto fail;
+ }
+
if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
- params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
int mgmt = WLAN_AKM_SUITE_PSK;
switch (params->key_mgmt_suite) {
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
break;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ mgmt = WLAN_AKM_SUITE_8021X_SUITE_B_192;
+ break;
case WPA_KEY_MGMT_PSK:
default:
mgmt = WLAN_AKM_SUITE_PSK;
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
+ int ret;
if (!drv->poll_command_supported) {
nl80211_send_null_frame(bss, own_addr, addr, qos);
return;
}
- send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
+ MACSTR " failed: ret=%d (%s)",
+ MAC2STR(addr), ret, strerror(-ret));
+ }
}
}
-static int
-wpa_driver_nl80211_join_mesh(void *priv,
+static int nl80211_join_mesh(struct i802_bss *bss,
struct wpa_driver_mesh_join_params *params)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *container;
int ret = -1;
- u32 timeout;
wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
/*
* Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
* the timer could disconnect stations even in that case.
- *
- * Set 0xffffffff instead of 0 because NL80211_MESHCONF_PLINK_TIMEOUT
- * does not allow 0.
*/
- timeout = params->conf.peer_link_timeout;
- if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) || timeout == 0)
- timeout = 0xffffffff;
- if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, timeout)) {
+ if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
+ params->conf.peer_link_timeout)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
goto fail;
}
}
+static int
+wpa_driver_nl80211_join_mesh(void *priv,
+ struct wpa_driver_mesh_join_params *params)
+{
+ struct i802_bss *bss = priv;
+ int ret, timeout;
+
+ timeout = params->conf.peer_link_timeout;
+
+ /* Disable kernel inactivity timer */
+ if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
+ params->conf.peer_link_timeout = 0;
+
+ ret = nl80211_join_mesh(bss, params);
+ if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Mesh join retry for peer_link_timeout");
+ /*
+ * Old kernel does not support setting
+ * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
+ * into future from peer_link_timeout.
+ */
+ params->conf.peer_link_timeout = timeout + 60;
+ ret = nl80211_join_mesh(priv, params);
+ }
+
+ params->conf.peer_link_timeout = timeout;
+ return ret;
+}
+
+
static int wpa_driver_nl80211_leave_mesh(void *priv)
{
struct i802_bss *bss = priv;