mesh: Use WPA_DRIVER_MESH_CONF_FLAG_* as modification flag
[mech_eap.git] / src / drivers / driver_nl80211.c
index b93721c..b801c9c 100644 (file)
@@ -445,6 +445,8 @@ static int nl_get_multicast_id(struct nl80211_global *global,
 void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
                   struct nl_msg *msg, int flags, uint8_t cmd)
 {
+       if (TEST_FAIL())
+               return NULL;
        return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
                           0, flags, cmd, 0);
 }
@@ -763,6 +765,15 @@ static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
 }
 
 
+static unsigned int nl80211_get_ifindex(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+
+       return drv->ifindex;
+}
+
+
 static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
 {
        struct i802_bss *bss = priv;
@@ -786,11 +797,12 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
 
 
 static void wpa_driver_nl80211_event_newlink(
-       struct wpa_driver_nl80211_data *drv, const char *ifname)
+       struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
+       int ifindex, const char *ifname)
 {
        union wpa_event_data event;
 
-       if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+       if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
                if (if_nametoindex(drv->first_bss->ifname) == 0) {
                        wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
                                   drv->first_bss->ifname);
@@ -804,19 +816,25 @@ static void wpa_driver_nl80211_event_newlink(
        }
 
        os_memset(&event, 0, sizeof(event));
+       event.interface_status.ifindex = ifindex;
        os_strlcpy(event.interface_status.ifname, ifname,
                   sizeof(event.interface_status.ifname));
        event.interface_status.ievent = EVENT_INTERFACE_ADDED;
-       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+       if (drv)
+               wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+       else
+               wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+                                           &event);
 }
 
 
 static void wpa_driver_nl80211_event_dellink(
-       struct wpa_driver_nl80211_data *drv, const char *ifname)
+       struct nl80211_global *global, struct wpa_driver_nl80211_data *drv,
+       int ifindex, const char *ifname)
 {
        union wpa_event_data event;
 
-       if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+       if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
                if (drv->if_removed) {
                        wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
                                   ifname);
@@ -831,10 +849,15 @@ static void wpa_driver_nl80211_event_dellink(
        }
 
        os_memset(&event, 0, sizeof(event));
+       event.interface_status.ifindex = ifindex;
        os_strlcpy(event.interface_status.ifname, ifname,
                   sizeof(event.interface_status.ifname));
        event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
-       wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+       if (drv)
+               wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+       else
+               wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+                                           &event);
 }
 
 
@@ -908,13 +931,6 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
        char ifname[IFNAMSIZ + 1];
        char extra[100], *pos, *end;
 
-       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
-       if (!drv) {
-               wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d",
-                          ifi->ifi_index);
-               return;
-       }
-
        extra[0] = '\0';
        pos = extra;
        end = pos + sizeof(extra);
@@ -958,6 +974,10 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+       if (!drv)
+               goto event_newlink;
+
        if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
                namebuf[0] = '\0';
                if (if_indextoname(ifi->ifi_index, namebuf) &&
@@ -1052,10 +1072,12 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
                                       -1, IF_OPER_UP);
        }
 
+event_newlink:
        if (ifname[0])
-               wpa_driver_nl80211_event_newlink(drv, ifname);
+               wpa_driver_nl80211_event_newlink(global, drv, ifi->ifi_index,
+                                                ifname);
 
-       if (ifi->ifi_family == AF_BRIDGE && brid) {
+       if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
                struct i802_bss *bss;
 
                /* device has been added to bridge */
@@ -1091,13 +1113,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
        char ifname[IFNAMSIZ + 1];
        char extra[100], *pos, *end;
 
-       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
-       if (!drv) {
-               wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d",
-                          ifi->ifi_index);
-               return;
-       }
-
        extra[0] = '\0';
        pos = extra;
        end = pos + sizeof(extra);
@@ -1138,10 +1153,9 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
                   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
-       if (ifname[0] && (ifi->ifi_family != AF_BRIDGE || !brid))
-               wpa_driver_nl80211_event_dellink(drv, ifname);
+       drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
 
-       if (ifi->ifi_family == AF_BRIDGE && brid) {
+       if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
                /* device has been removed from bridge */
                char namebuf[IFNAMSIZ];
 
@@ -1156,6 +1170,10 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
                }
                del_ifidx(drv, brid, ifi->ifi_index);
        }
+
+       if (ifi->ifi_family != AF_BRIDGE || !brid)
+               wpa_driver_nl80211_event_dellink(global, drv, ifi->ifi_index,
+                                                ifname);
 }
 
 
@@ -1973,6 +1991,10 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
        if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
                ret = -1;
 
+       /* Radio Measurement - Radio Measurement Request */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
+               ret = -1;
+
        /* Radio Measurement - Link Measurement Request */
        if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
            (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
@@ -2034,6 +2056,49 @@ static int nl80211_register_spurious_class3(struct i802_bss *bss)
 }
 
 
+static int nl80211_action_subscribe_ap(struct i802_bss *bss)
+{
+       int ret = 0;
+
+       /* Public Action frames */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x04", 1) < 0)
+               ret = -1;
+       /* RRM Measurement Report */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
+               ret = -1;
+       /* RRM Neighbor Report Request */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0)
+               ret = -1;
+       /* FT Action frames */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
+               ret = -1;
+#ifdef CONFIG_IEEE80211W
+       /* SA Query */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x08", 1) < 0)
+               ret = -1;
+#endif /* CONFIG_IEEE80211W */
+       /* Protected Dual of Public Action */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x09", 1) < 0)
+               ret = -1;
+       /* WNM */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x0a", 1) < 0)
+               ret = -1;
+       /* WMM */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x11", 1) < 0)
+               ret = -1;
+#ifdef CONFIG_FST
+       /* FST Action frames */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
+               ret = -1;
+#endif /* CONFIG_FST */
+       /* Vendor-specific */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0)
+               ret = -1;
+
+       return ret;
+}
+
+
 static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
 {
        static const int stypes[] = {
@@ -2042,7 +2107,6 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
                WLAN_FC_STYPE_REASSOC_REQ,
                WLAN_FC_STYPE_DISASSOC,
                WLAN_FC_STYPE_DEAUTH,
-               WLAN_FC_STYPE_ACTION,
                WLAN_FC_STYPE_PROBE_REQ,
 /* Beacon doesn't work as mac80211 doesn't currently allow
  * it, but it wouldn't really be the right thing anyway as
@@ -2067,6 +2131,9 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
                }
        }
 
+       if (nl80211_action_subscribe_ap(bss))
+               goto out_err;
+
        if (nl80211_register_spurious_class3(bss))
                goto out_err;
 
@@ -2089,10 +2156,7 @@ static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
        wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
                   "handle %p (device SME)", bss->nl_mgmt);
 
-       if (nl80211_register_frame(bss, bss->nl_mgmt,
-                                  (WLAN_FC_TYPE_MGMT << 2) |
-                                  (WLAN_FC_STYPE_ACTION << 4),
-                                  NULL, 0) < 0)
+       if (nl80211_action_subscribe_ap(bss))
                goto out_err;
 
        nl80211_mgmt_handle_register_eloop(bss);
@@ -2268,7 +2332,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
 
        if (drv->hostapd || bss->static_ap)
                nlmode = NL80211_IFTYPE_AP;
-       else if (bss->if_dynamic)
+       else if (bss->if_dynamic ||
+                nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
                nlmode = nl80211_get_ifmode(bss);
        else
                nlmode = NL80211_IFTYPE_STATION;
@@ -2350,6 +2415,7 @@ static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
 static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
+       unsigned int i;
 
        wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
                   bss->ifname, drv->disabled_11b_rates);
@@ -2446,6 +2512,10 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 
        os_free(drv->extended_capa);
        os_free(drv->extended_capa_mask);
+       for (i = 0; i < drv->num_iface_ext_capa; i++) {
+               os_free(drv->iface_ext_capa[i].ext_capa);
+               os_free(drv->iface_ext_capa[i].ext_capa_mask);
+       }
        os_free(drv->first_bss);
        os_free(drv);
 }
@@ -3399,6 +3469,17 @@ static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
 }
 
 
+static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period)
+{
+       if (dtim_period > 0) {
+               wpa_printf(MSG_DEBUG, "  * dtim_period=%d", dtim_period);
+               return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+       }
+
+       return 0;
+}
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
                                     struct wpa_driver_ap_params *params)
 {
@@ -3435,7 +3516,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
            nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
                    params->tail) ||
            nl80211_put_beacon_int(msg, params->beacon_int) ||
-           nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
+           nl80211_put_dtim_period(msg, params->dtim_period) ||
            nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
                goto fail;
        if (params->proberesp && params->proberesp_len) {
@@ -3506,8 +3587,10 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                goto fail;
 
        if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
-           params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
-           nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
+           (!params->pairwise_ciphers ||
+            params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
+           (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+            nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
                goto fail;
 
        wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
@@ -3626,7 +3709,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                                           "nl80211: Frequency set succeeded for ht2040 coex");
                                bss->bandwidth = params->freq->bandwidth;
                        }
-               } else if (!beacon_set) {
+               } else if (!beacon_set && params->freq) {
                        /*
                         * cfg80211 updates the driver on frequence change in AP
                         * mode only at the point when beaconing is started, so
@@ -3708,6 +3791,12 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
                wpa_printf(MSG_DEBUG, "  * channel_type=%d", ct);
                if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
                        return -ENOBUFS;
+       } else {
+               wpa_printf(MSG_DEBUG, "  * channel_type=%d",
+                          NL80211_CHAN_NO_HT);
+               if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+                               NL80211_CHAN_NO_HT))
+                       return -ENOBUFS;
        }
        return 0;
 }
@@ -3770,11 +3859,11 @@ static u32 sta_flags_nl80211(int flags)
 static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
 {
        switch (state) {
-       case PLINK_LISTEN:
+       case PLINK_IDLE:
                return NL80211_PLINK_LISTEN;
-       case PLINK_OPEN_SENT:
+       case PLINK_OPN_SNT:
                return NL80211_PLINK_OPN_SNT;
-       case PLINK_OPEN_RCVD:
+       case PLINK_OPN_RCVD:
                return NL80211_PLINK_OPN_RCVD;
        case PLINK_CNF_RCVD:
                return NL80211_PLINK_CNF_RCVD;
@@ -3861,6 +3950,13 @@ static int wpa_driver_nl80211_sta_add(void *priv,
                                    params->ext_capab_len, params->ext_capab))
                                goto fail;
                }
+
+               if (is_ap_interface(drv->nlmode) &&
+                   nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
+                              params->support_p2p_ps ?
+                              NL80211_P2P_PS_SUPPORTED :
+                              NL80211_P2P_PS_UNSUPPORTED))
+                       goto fail;
        }
        if (!params->set) {
                if (params->aid) {
@@ -3956,6 +4052,15 @@ static int wpa_driver_nl80211_sta_add(void *priv,
                        if (!(params->flags & WPA_STA_ASSOCIATED))
                                upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
                }
+#ifdef CONFIG_MESH
+       } else {
+               if (params->plink_state == PLINK_ESTAB && params->peer_aid) {
+                       ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID,
+                                         params->peer_aid);
+                       if (ret)
+                               goto fail;
+               }
+#endif /* CONFIG_MESH */
        }
 
        wpa_printf(MSG_DEBUG, "  * flags set=0x%x mask=0x%x",
@@ -4093,7 +4198,7 @@ void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
 }
 
 
-static const char * nl80211_iftype_str(enum nl80211_iftype mode)
+const char * nl80211_iftype_str(enum nl80211_iftype mode)
 {
        switch (mode) {
        case NL80211_IFTYPE_ADHOC:
@@ -4275,11 +4380,11 @@ static int nl80211_setup_ap(struct i802_bss *bss)
 
        if (drv->device_ap_sme && !drv->use_monitor)
                if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
-                       return -1;
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
 
        if (!drv->device_ap_sme && drv->use_monitor &&
-           nl80211_create_monitor_interface(drv) &&
-           !drv->device_ap_sme)
+           nl80211_create_monitor_interface(drv))
                return -1;
 
        if (drv->device_ap_sme &&
@@ -4800,15 +4905,24 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
        if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
                return -1;
 
+       if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+           (params->pairwise_suite == WPA_CIPHER_NONE ||
+            params->pairwise_suite == WPA_CIPHER_WEP104 ||
+            params->pairwise_suite == WPA_CIPHER_WEP40) &&
+           (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+            nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
+               return -1;
+
        if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
            nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
                return -1;
 
        if (params->rrm_used) {
                u32 drv_rrm_flags = drv->capa.rrm_flags;
-               if (!(drv_rrm_flags &
-                     WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
-                   !(drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET) ||
+               if ((!((drv_rrm_flags &
+                       WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
+                      (drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
+                    !(drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) ||
                    nla_put_flag(msg, NL80211_ATTR_USE_RRM))
                        return -1;
        }
@@ -4825,6 +4939,16 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
                        return -1;
        }
 
+       drv->connect_reassoc = 0;
+       if (params->prev_bssid) {
+               wpa_printf(MSG_DEBUG, "  * prev_bssid=" MACSTR,
+                          MAC2STR(params->prev_bssid));
+               if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
+                           params->prev_bssid))
+                       return -1;
+               drv->connect_reassoc = 1;
+       }
+
        return 0;
 }
 
@@ -4977,14 +5101,6 @@ static int wpa_driver_nl80211_associate(
        if (ret)
                goto fail;
 
-       if (params->prev_bssid) {
-               wpa_printf(MSG_DEBUG, "  * prev_bssid=" MACSTR,
-                          MAC2STR(params->prev_bssid));
-               if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
-                           params->prev_bssid))
-                       goto fail;
-       }
-
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
@@ -5040,6 +5156,9 @@ static int wpa_driver_nl80211_set_mode_impl(
        int res;
        int mode_switch_res;
 
+       if (TEST_FAIL())
+               return -1;
+
        mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
        if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
                mode_switch_res = 0;
@@ -6858,7 +6977,7 @@ static int nl80211_set_param(void *priv, const char *param)
 }
 
 
-static void * nl80211_global_init(void)
+static void * nl80211_global_init(void *ctx)
 {
        struct nl80211_global *global;
        struct netlink_config *cfg;
@@ -6866,6 +6985,7 @@ static void * nl80211_global_init(void)
        global = os_zalloc(sizeof(*global));
        if (global == NULL)
                return NULL;
+       global->ctx = ctx;
        global->ioctl_sock = -1;
        dl_list_init(&global->interfaces);
        global->if_add_ifindex = -1;
@@ -7622,7 +7742,7 @@ static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
 }
 
 
-const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -8230,6 +8350,9 @@ static int nl80211_set_mac_addr(void *priv, const u8 *addr)
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int new_addr = addr != NULL;
 
+       if (TEST_FAIL())
+               return -1;
+
        if (!addr)
                addr = drv->perm_addr;
 
@@ -8290,6 +8413,40 @@ static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
 }
 
 
+static int nl80211_put_mesh_config(struct nl_msg *msg,
+                                  struct wpa_driver_mesh_bss_params *params)
+{
+       struct nlattr *container;
+
+       container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+       if (!container)
+               return -1;
+
+       if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
+            nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+                        params->auto_plinks)) ||
+           ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
+            nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+                        params->max_peer_links)))
+               return -1;
+
+       /*
+        * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
+        * the timer could disconnect stations even in that case.
+        */
+       if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
+           nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
+                       params->peer_link_timeout)) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+               return -1;
+       }
+
+       nla_nest_end(msg, container);
+
+       return 0;
+}
+
+
 static int nl80211_join_mesh(struct i802_bss *bss,
                             struct wpa_driver_mesh_join_params *params)
 {
@@ -8304,7 +8461,8 @@ static int nl80211_join_mesh(struct i802_bss *bss,
            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))
+           nl80211_put_beacon_int(msg, params->beacon_int) ||
+           nl80211_put_dtim_period(msg, params->dtim_period))
                goto fail;
 
        wpa_printf(MSG_DEBUG, "  * flags=%08X", params->flags);
@@ -8333,30 +8491,12 @@ static int nl80211_join_mesh(struct i802_bss *bss,
                goto fail;
        nla_nest_end(msg, container);
 
-       container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
-       if (!container)
-               goto fail;
-
-       if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
-           nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
-               goto fail;
-       if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
-           nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
-                       params->max_peer_links))
+       params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+       params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
+       params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
+       if (nl80211_put_mesh_config(msg, &params->conf) < 0)
                goto fail;
 
-       /*
-        * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
-        * the timer could disconnect stations even in that case.
-        */
-       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;
-       }
-
-       nla_nest_end(msg, container);
-
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
        if (ret) {
@@ -8365,7 +8505,7 @@ static int nl80211_join_mesh(struct i802_bss *bss,
                goto fail;
        }
        ret = 0;
-       bss->freq = params->freq.freq;
+       drv->assoc_freq = bss->freq = params->freq.freq;
        wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
 
 fail:
@@ -9031,9 +9171,216 @@ static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
        return 0;
 }
 
+
+static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
+                               unsigned int period, unsigned int interval,
+                               unsigned int count, const u8 *device_types,
+                               size_t dev_types_len,
+                               const u8 *ies, size_t ies_len)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *container;
+       int ret;
+
+       wpa_printf(MSG_DEBUG,
+                  "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
+                  freq, period, interval, count);
+
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
+               return -1;
+
+       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_P2P_LISTEN_OFFLOAD_START))
+               goto fail;
+
+       container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+       if (!container)
+               goto fail;
+
+       if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
+                       freq) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
+                       period) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
+                       interval) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
+                       count) ||
+           nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
+                   dev_types_len, device_types) ||
+           nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
+                   ies_len, ies))
+               goto fail;
+
+       nla_nest_end(msg, container);
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       msg = NULL;
+       if (ret) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Failed to send P2P Listen offload vendor command");
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       nlmsg_free(msg);
+       return -1;
+}
+
+
+static int nl80211_p2p_lo_stop(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
+
+       if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
+               return -1;
+
+       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_P2P_LISTEN_OFFLOAD_STOP)) {
+               nlmsg_free(msg);
+               return -1;
+       }
+
+       return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
 
+static int nl80211_write_to_file(const char *name, unsigned int val)
+{
+       int fd, len;
+       char tmp[128];
+
+       fd = open(name, O_RDWR);
+       if (fd < 0) {
+               wpa_printf(MSG_ERROR, "nl80211: Failed to open %s: %s",
+                          name, strerror(errno));
+               return fd;
+       }
+
+       len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
+       len = write(fd, tmp, len);
+       if (len < 0)
+               wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
+                          name, strerror(errno));
+       close(fd);
+
+       return 0;
+}
+
+
+static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
+{
+       struct i802_bss *bss = priv;
+       char path[128];
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
+                  filter_flags);
+
+       /* Configure filtering of unicast frame encrypted using GTK */
+       ret = os_snprintf(path, sizeof(path),
+                         "/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast",
+                         bss->ifname);
+       if (os_snprintf_error(sizeof(path), ret))
+               return -1;
+
+       ret = nl80211_write_to_file(path,
+                                   !!(filter_flags &
+                                      WPA_DATA_FRAME_FILTER_FLAG_GTK));
+       if (ret) {
+               wpa_printf(MSG_ERROR,
+                          "nl80211: Failed to set IPv4 unicast in multicast filter");
+               return ret;
+       }
+
+       os_snprintf(path, sizeof(path),
+                   "/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast",
+                   bss->ifname);
+       ret = nl80211_write_to_file(path,
+                                   !!(filter_flags &
+                                      WPA_DATA_FRAME_FILTER_FLAG_GTK));
+
+       if (ret) {
+               wpa_printf(MSG_ERROR,
+                          "nl80211: Failed to set IPv6 unicast in multicast filter");
+               return ret;
+       }
+
+       /* Configure filtering of unicast frame encrypted using GTK */
+       os_snprintf(path, sizeof(path),
+                   "/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp",
+                   bss->ifname);
+       ret = nl80211_write_to_file(path,
+                                   !!(filter_flags &
+                                      WPA_DATA_FRAME_FILTER_FLAG_ARP));
+       if (ret) {
+               wpa_printf(MSG_ERROR,
+                          "nl80211: Failed set gratuitous ARP filter");
+               return ret;
+       }
+
+       /* Configure filtering of IPv6 NA frames */
+       os_snprintf(path, sizeof(path),
+                   "/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na",
+                   bss->ifname);
+       ret = nl80211_write_to_file(path,
+                                   !!(filter_flags &
+                                      WPA_DATA_FRAME_FILTER_FLAG_NA));
+       if (ret) {
+               wpa_printf(MSG_ERROR,
+                          "nl80211: Failed to set unsolicited NA filter");
+               return ret;
+       }
+
+       return 0;
+}
+
+
+static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
+                                const u8 **ext_capa, const u8 **ext_capa_mask,
+                                unsigned int *ext_capa_len)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       enum nl80211_iftype nlmode;
+       unsigned int i;
+
+       if (!ext_capa || !ext_capa_mask || !ext_capa_len)
+               return -1;
+
+       nlmode = wpa_driver_nl80211_if_type(type);
+
+       /* By default, use the per-radio values */
+       *ext_capa = drv->extended_capa;
+       *ext_capa_mask = drv->extended_capa_mask;
+       *ext_capa_len = drv->extended_capa_len;
+
+       /* Replace the default value if a per-interface type value exists */
+       for (i = 0; i < drv->num_iface_ext_capa; i++) {
+               if (nlmode == drv->iface_ext_capa[i].iftype) {
+                       *ext_capa = drv->iface_ext_capa[i].ext_capa;
+                       *ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask;
+                       *ext_capa_len = drv->iface_ext_capa[i].ext_capa_len;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -9128,9 +9475,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .vendor_cmd = nl80211_vendor_cmd,
        .set_qos_map = nl80211_set_qos_map,
        .set_wowlan = nl80211_set_wowlan,
-#ifdef CONFIG_DRIVER_NL80211_QCA
-       .roaming = nl80211_roaming,
-#endif /* CONFIG_DRIVER_NL80211_QCA */
        .set_mac_addr = nl80211_set_mac_addr,
 #ifdef CONFIG_MESH
        .init_mesh = wpa_driver_nl80211_init_mesh,
@@ -9143,10 +9487,17 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .br_set_net_param = wpa_driver_br_set_net_param,
        .add_tx_ts = nl80211_add_ts,
        .del_tx_ts = nl80211_del_ts,
+       .get_ifindex = nl80211_get_ifindex,
 #ifdef CONFIG_DRIVER_NL80211_QCA
+       .roaming = nl80211_roaming,
        .do_acs = wpa_driver_do_acs,
        .set_band = nl80211_set_band,
        .get_pref_freq_list = nl80211_get_pref_freq_list,
        .set_prob_oper_freq = nl80211_set_prob_oper_freq,
+       .p2p_lo_start = nl80211_p2p_lo_start,
+       .p2p_lo_stop = nl80211_p2p_lo_stop,
+       .set_default_scan_ies = nl80211_set_default_scan_ies,
 #endif /* CONFIG_DRIVER_NL80211_QCA */
+       .configure_data_frame_filters = nl80211_configure_data_frame_filters,
+       .get_ext_capab = nl80211_get_ext_capab,
 };