Preparations for variable length KCK and KEK
[mech_eap.git] / src / drivers / driver_nl80211.c
index 74f5762..ea52575 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, 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>
@@ -132,6 +132,20 @@ static void nl80211_register_eloop_read(struct nl_handle **handle,
                                        eloop_sock_handler handler,
                                        void *eloop_data)
 {
+       /*
+        * 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
+        * operations are blocked, e.g., with a burst of Deauthentication frames
+        * to hostapd and STA entry deletion. Try to increase the buffer to make
+        * this less likely to occur.
+        */
+       if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Could not set nl_socket RX buffer size: %s",
+                          strerror(errno));
+               /* continue anyway with the default (smaller) buffer */
+       }
+
        nl_socket_set_nonblocking(*handle);
        eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
                                 eloop_data, *handle);
@@ -290,7 +304,13 @@ static void nl80211_nlmsg_clear(struct nl_msg *msg)
        if (msg) {
                struct nlmsghdr *hdr = nlmsg_hdr(msg);
                void *data = nlmsg_data(hdr);
-               int len = nlmsg_datalen(hdr);
+               /*
+                * This would use nlmsg_datalen() or the older nlmsg_len() if
+                * only libnl were to maintain a stable API.. Neither will work
+                * with all released versions, so just calculate the length
+                * here.
+                */
+               int len = hdr->nlmsg_len - NLMSG_HDRLEN;
 
                os_memset(data, 0, len);
        }
@@ -1577,6 +1597,14 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
        drv->ctx = ctx;
        drv->hostapd = !!hostapd;
        drv->eapol_sock = -1;
+
+       /*
+        * There is no driver capability flag for this, so assume it is
+        * supported and disable this on first attempt to use if the driver
+        * rejects the command due to missing support.
+        */
+       drv->set_rekey_offload = 1;
+
        drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
        drv->if_indices = drv->default_if_indices;
 
@@ -1830,11 +1858,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 
        /* WMM-AC ADDTS Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
-               return -1;
+               ret = -1;
 
        /* WMM-AC DELTS */
        if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
-               return -1;
+               ret = -1;
 
        /* Radio Measurement - Neighbor Report Response */
        if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
@@ -2465,7 +2493,10 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
        if (!msg ||
            nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
-           nla_put_flag(msg, alg == WPA_ALG_IGTK ?
+           nla_put_flag(msg, (alg == WPA_ALG_IGTK ||
+                              alg == WPA_ALG_BIP_GMAC_128 ||
+                              alg == WPA_ALG_BIP_GMAC_256 ||
+                              alg == WPA_ALG_BIP_CMAC_256) ?
                         NL80211_ATTR_KEY_DEFAULT_MGMT :
                         NL80211_ATTR_KEY_DEFAULT))
                goto fail;
@@ -3064,9 +3095,25 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 }
 
 
+static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
+{
+       u8 rates[NL80211_MAX_SUPP_RATES];
+       u8 rates_len = 0;
+       int i;
+
+       if (!basic_rates)
+               return 0;
+
+       for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
+               rates[rates_len++] = basic_rates[i] / 5;
+
+       return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+}
+
+
 static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
                           int slot, int ht_opmode, int ap_isolate,
-                          int *basic_rates)
+                          const int *basic_rates)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
@@ -3081,27 +3128,13 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
            (ht_opmode >= 0 &&
             nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
            (ap_isolate >= 0 &&
-            nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)))
-               goto fail;
-
-       if (basic_rates) {
-               u8 rates[NL80211_MAX_SUPP_RATES];
-               u8 rates_len = 0;
-               int i;
-
-               for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
-                    i++)
-                       rates[rates_len++] = basic_rates[i] / 5;
-
-               if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
-                           rates))
-                       goto fail;
+            nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
+           nl80211_put_basic_rates(msg, basic_rates)) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
        }
 
        return send_and_recv_msgs(drv, msg, NULL, NULL);
-fail:
-       nlmsg_free(msg);
-       return -ENOBUFS;
 }
 
 
@@ -3152,6 +3185,18 @@ static int wpa_driver_nl80211_set_acl(void *priv,
 }
 
 
+static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
+{
+       if (beacon_int > 0) {
+               wpa_printf(MSG_DEBUG, "  * beacon_int=%d", beacon_int);
+               return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+                                  beacon_int);
+       }
+
+       return 0;
+}
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
                                     struct wpa_driver_ap_params *params)
 {
@@ -3187,8 +3232,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                    params->head) ||
            nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
                    params->tail) ||
-           nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
-                       params->beacon_int) ||
+           nl80211_put_beacon_int(msg, params->beacon_int) ||
            nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
            nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
                goto fail;
@@ -3374,14 +3418,19 @@ fail:
 
 
 static int nl80211_put_freq_params(struct nl_msg *msg,
-                                  struct hostapd_freq_params *freq)
+                                  const struct hostapd_freq_params *freq)
 {
+       wpa_printf(MSG_DEBUG, "  * freq=%d", freq->freq);
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
                return -ENOBUFS;
 
+       wpa_printf(MSG_DEBUG, "  * vht_enabled=%d", freq->vht_enabled);
+       wpa_printf(MSG_DEBUG, "  * ht_enabled=%d", freq->ht_enabled);
+
        if (freq->vht_enabled) {
                enum nl80211_chan_width cw;
 
+               wpa_printf(MSG_DEBUG, "  * bandwidth=%d", freq->bandwidth);
                switch (freq->bandwidth) {
                case 20:
                        cw = NL80211_CHAN_WIDTH_20;
@@ -3402,6 +3451,11 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
                        return -EINVAL;
                }
 
+               wpa_printf(MSG_DEBUG, "  * channel_width=%d", cw);
+               wpa_printf(MSG_DEBUG, "  * center_freq1=%d",
+                          freq->center_freq1);
+               wpa_printf(MSG_DEBUG, "  * center_freq2=%d",
+                          freq->center_freq2);
                if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
                    nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
                                freq->center_freq1) ||
@@ -3412,6 +3466,8 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
        } else if (freq->ht_enabled) {
                enum nl80211_channel_type ct;
 
+               wpa_printf(MSG_DEBUG, "  * sec_channel_offset=%d",
+                          freq->sec_channel_offset);
                switch (freq->sec_channel_offset) {
                case -1:
                        ct = NL80211_CHAN_HT40MINUS;
@@ -3424,6 +3480,7 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
                        break;
                }
 
+               wpa_printf(MSG_DEBUG, "  * channel_type=%d", ct);
                if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
                        return -ENOBUFS;
        }
@@ -4174,6 +4231,48 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static int nl80211_ht_vht_overrides(struct nl_msg *msg,
+                                   struct wpa_driver_associate_params *params)
+{
+       if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+               return -1;
+
+       if (params->htcaps && params->htcaps_mask) {
+               int sz = sizeof(struct ieee80211_ht_capabilities);
+               wpa_hexdump(MSG_DEBUG, "  * htcaps", params->htcaps, sz);
+               wpa_hexdump(MSG_DEBUG, "  * htcaps_mask",
+                           params->htcaps_mask, sz);
+               if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
+                           params->htcaps) ||
+                   nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+                           params->htcaps_mask))
+                       return -1;
+       }
+
+#ifdef CONFIG_VHT_OVERRIDES
+       if (params->disable_vht) {
+               wpa_printf(MSG_DEBUG, "  * VHT disabled");
+               if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
+                       return -1;
+       }
+
+       if (params->vhtcaps && params->vhtcaps_mask) {
+               int sz = sizeof(struct ieee80211_vht_capabilities);
+               wpa_hexdump(MSG_DEBUG, "  * vhtcaps", params->vhtcaps, sz);
+               wpa_hexdump(MSG_DEBUG, "  * vhtcaps_mask",
+                           params->vhtcaps_mask, sz);
+               if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
+                           params->vhtcaps) ||
+                   nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+                           params->vhtcaps_mask))
+                       return -1;
+       }
+#endif /* CONFIG_VHT_OVERRIDES */
+
+       return 0;
+}
+
+
 static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
                                   struct wpa_driver_associate_params *params)
 {
@@ -4201,24 +4300,10 @@ retry:
        os_memcpy(drv->ssid, params->ssid, params->ssid_len);
        drv->ssid_len = params->ssid_len;
 
-       wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq.freq);
-       wpa_printf(MSG_DEBUG, "  * ht_enabled=%d", params->freq.ht_enabled);
-       wpa_printf(MSG_DEBUG, "  * sec_channel_offset=%d",
-                  params->freq.sec_channel_offset);
-       wpa_printf(MSG_DEBUG, "  * vht_enabled=%d", params->freq.vht_enabled);
-       wpa_printf(MSG_DEBUG, "  * center_freq1=%d", params->freq.center_freq1);
-       wpa_printf(MSG_DEBUG, "  * center_freq2=%d", params->freq.center_freq2);
-       wpa_printf(MSG_DEBUG, "  * bandwidth=%d", params->freq.bandwidth);
-       if (nl80211_put_freq_params(msg, &params->freq) < 0)
+       if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
+           nl80211_put_beacon_int(msg, params->beacon_int))
                goto fail;
 
-       if (params->beacon_int > 0) {
-               wpa_printf(MSG_DEBUG, "  * beacon_int=%d", params->beacon_int);
-               if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
-                               params->beacon_int))
-                       goto fail;
-       }
-
        ret = nl80211_set_conn_keys(params, msg);
        if (ret)
                goto fail;
@@ -4248,6 +4333,9 @@ retry:
                        goto fail;
        }
 
+       if (nl80211_ht_vht_overrides(msg, params) < 0)
+               return -1;
+
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
@@ -4429,41 +4517,9 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
                        return -1;
        }
 
-       if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+       if (nl80211_ht_vht_overrides(msg, params) < 0)
                return -1;
 
-       if (params->htcaps && params->htcaps_mask) {
-               int sz = sizeof(struct ieee80211_ht_capabilities);
-               wpa_hexdump(MSG_DEBUG, "  * htcaps", params->htcaps, sz);
-               wpa_hexdump(MSG_DEBUG, "  * htcaps_mask",
-                           params->htcaps_mask, sz);
-               if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
-                           params->htcaps) ||
-                   nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
-                           params->htcaps_mask))
-                       return -1;
-       }
-
-#ifdef CONFIG_VHT_OVERRIDES
-       if (params->disable_vht) {
-               wpa_printf(MSG_DEBUG, "  * VHT disabled");
-               if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
-                       return -1;
-       }
-
-       if (params->vhtcaps && params->vhtcaps_mask) {
-               int sz = sizeof(struct ieee80211_vht_capabilities);
-               wpa_hexdump(MSG_DEBUG, "  * vhtcaps", params->vhtcaps, sz);
-               wpa_hexdump(MSG_DEBUG, "  * vhtcaps_mask",
-                           params->vhtcaps_mask, sz);
-               if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
-                           params->vhtcaps) ||
-                   nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
-                           params->vhtcaps_mask))
-                       return -1;
-       }
-#endif /* CONFIG_VHT_OVERRIDES */
-
        if (params->p2p)
                wpa_printf(MSG_DEBUG, "  * P2P group");
 
@@ -5193,6 +5249,8 @@ static int i802_get_inact_sec(void *priv, const u8 *addr)
 
        data.inactive_msec = (unsigned long) -1;
        ret = i802_read_sta_data(priv, &data, addr);
+       if (ret == -ENOENT)
+               return -ENOENT;
        if (ret || data.inactive_msec == (unsigned long) -1)
                return -1;
        return data.inactive_msec / 1000;
@@ -6723,18 +6781,24 @@ static int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
 }
 
 
-static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
+                                  const u8 *kck, size_t kck_len,
                                   const u8 *replay_ctr)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nlattr *replay_nested;
        struct nl_msg *msg;
+       int ret;
 
+       if (!drv->set_rekey_offload)
+               return;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
        if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
            !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
-           nla_put(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek) ||
-           nla_put(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck) ||
+           nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
+           nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck) ||
            nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
                    replay_ctr)) {
                nl80211_nlmsg_clear(msg);
@@ -6744,7 +6808,12 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
 
        nla_nest_end(msg, replay_nested);
 
-       send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+       ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+       if (ret == -EOPNOTSUPP) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Driver does not support rekey offload");
+               drv->set_rekey_offload = 0;
+       }
 }
 
 
@@ -6970,6 +7039,62 @@ static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
        return send_and_recv_msgs(drv, msg, NULL, NULL);
 }
 
+
+static int
+nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
+                                  const struct hostapd_freq_params *params)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       int ret = -ENOBUFS;
+
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+           !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+               return -EOPNOTSUPP;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
+                  " oper_class=%u freq=%u",
+                  MAC2STR(addr), oper_class, params->freq);
+       msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
+       if (!msg ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+           nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
+           (ret = nl80211_put_freq_params(msg, params))) {
+               nlmsg_free(msg);
+               wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
+               return ret;
+       }
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
+static int
+nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+           !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+               return -EOPNOTSUPP;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
+                  MAC2STR(addr));
+       msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
+       if (!msg ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+               nlmsg_free(msg);
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Could not build TDLS cancel chan switch");
+               return -ENOBUFS;
+       }
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
 #endif /* CONFIG TDLS */
 
 
@@ -7254,7 +7379,9 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                                  "capa.max_stations=%u\n"
                                  "capa.probe_resp_offloads=0x%x\n"
                                  "capa.max_acl_mac_addrs=%u\n"
-                                 "capa.num_multichan_concurrent=%u\n",
+                                 "capa.num_multichan_concurrent=%u\n"
+                                 "capa.mac_addr_rand_sched_scan_supported=%d\n"
+                                 "capa.mac_addr_rand_scan_supported=%d\n",
                                  drv->capa.key_mgmt,
                                  drv->capa.enc,
                                  drv->capa.auth,
@@ -7268,7 +7395,9 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
                                  drv->capa.max_stations,
                                  drv->capa.probe_resp_offloads,
                                  drv->capa.max_acl_mac_addrs,
-                                 drv->capa.num_multichan_concurrent);
+                                 drv->capa.num_multichan_concurrent,
+                                 drv->capa.mac_addr_rand_sched_scan_supported,
+                                 drv->capa.mac_addr_rand_scan_supported);
                if (os_snprintf_error(end - pos, res))
                        return pos - buf;
                pos += res;
@@ -7701,6 +7830,19 @@ static int wpa_driver_nl80211_init_mesh(void *priv)
 }
 
 
+static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
+                              size_t mesh_id_len)
+{
+       if (mesh_id) {
+               wpa_hexdump_ascii(MSG_DEBUG, "  * Mesh ID (SSID)",
+                                 mesh_id, mesh_id_len);
+               return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
+       }
+
+       return 0;
+}
+
+
 static int
 wpa_driver_nl80211_join_mesh(void *priv,
                             struct wpa_driver_mesh_join_params *params)
@@ -7709,76 +7851,17 @@ wpa_driver_nl80211_join_mesh(void *priv,
        struct wpa_driver_nl80211_data *drv = bss->drv;
        struct nl_msg *msg;
        struct nlattr *container;
-       int ret = 0;
+       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);
-       if (!msg)
+       if (!msg ||
+           nl80211_put_freq_params(msg, &params->freq) ||
+           nl80211_put_basic_rates(msg, params->basic_rates) ||
+           nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
+           nl80211_put_beacon_int(msg, params->beacon_int))
                goto fail;
-       if (params->freq) {
-               wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
-               if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
-                       goto fail;
-       }
-
-       if (params->ht_mode) {
-               unsigned int ht_value;
-               char *ht_mode = "";
-
-               switch (params->ht_mode) {
-               default:
-               case CHAN_NO_HT:
-                       ht_value = NL80211_CHAN_NO_HT;
-                       ht_mode = "NOHT";
-                       break;
-               case CHAN_HT20:
-                       ht_value = NL80211_CHAN_HT20;
-                       ht_mode = "HT20";
-                       break;
-               case CHAN_HT40PLUS:
-                       ht_value = NL80211_CHAN_HT40PLUS;
-                       ht_mode = "HT40+";
-                       break;
-               case CHAN_HT40MINUS:
-                       ht_value = NL80211_CHAN_HT40MINUS;
-                       ht_mode = "HT40-";
-                       break;
-               }
-               wpa_printf(MSG_DEBUG, "  * ht_mode=%s", ht_mode);
-               if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ht_value))
-                       goto fail;
-       }
-
-       if (params->basic_rates) {
-               u8 rates[NL80211_MAX_SUPP_RATES];
-               u8 rates_len = 0;
-               int i;
-
-               for (i = 0; i < NL80211_MAX_SUPP_RATES; i++) {
-                       if (params->basic_rates[i] < 0)
-                               break;
-                       rates[rates_len++] = params->basic_rates[i] / 5;
-               }
-
-               if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
-                           rates))
-                       goto fail;
-       }
-
-       if (params->meshid) {
-               wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
-                                 params->meshid, params->meshid_len);
-               if (nla_put(msg, NL80211_ATTR_MESH_ID, params->meshid_len,
-                           params->meshid))
-                       goto fail;
-       }
-
-       if (params->beacon_int > 0) {
-               wpa_printf(MSG_DEBUG, "  * beacon_int=%d", params->beacon_int);
-               if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
-                               params->beacon_int))
-                       goto fail;
-       }
 
        wpa_printf(MSG_DEBUG, "  * flags=%08X", params->flags);
 
@@ -7817,6 +7900,22 @@ wpa_driver_nl80211_join_mesh(void *priv,
            nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
                        params->max_peer_links))
                goto fail;
+
+       /*
+        * 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)) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+               goto fail;
+       }
+
        nla_nest_end(msg, container);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7827,7 +7926,7 @@ wpa_driver_nl80211_join_mesh(void *priv,
                goto fail;
        }
        ret = 0;
-       bss->freq = params->freq;
+       bss->freq = params->freq.freq;
        wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
 
 fail:
@@ -8257,6 +8356,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 #ifdef CONFIG_TDLS
        .send_tdls_mgmt = nl80211_send_tdls_mgmt,
        .tdls_oper = nl80211_tdls_oper,
+       .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
+       .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
 #endif /* CONFIG_TDLS */
        .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
        .get_mac_addr = wpa_driver_nl80211_get_macaddr,