OSDN Git Service

Accumulative patch from commit 17b8995cf5813d7c027cd7a6884700e791d72392
[android-x86/external-wpa_supplicant_8.git] / src / drivers / driver_nl80211.c
index c2b9fff..cd266b4 100644 (file)
@@ -214,6 +214,8 @@ struct wpa_driver_nl80211_data {
        int ignore_if_down_event;
        struct rfkill_data *rfkill;
        struct wpa_driver_capa capa;
+       u8 *extended_capa, *extended_capa_mask;
+       unsigned int extended_capa_len;
        int has_capability;
 
        int operstate;
@@ -2554,6 +2556,7 @@ nla_put_failure:
 
 
 struct wiphy_info_data {
+       struct wpa_driver_nl80211_data *drv;
        struct wpa_driver_capa *capa;
 
        unsigned int error:1;
@@ -2795,6 +2798,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
        struct wiphy_info_data *info = arg;
        struct wpa_driver_capa *capa = info->capa;
+       struct wpa_driver_nl80211_data *drv = info->drv;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
@@ -2842,6 +2846,30 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
        wiphy_info_probe_resp_offload(capa,
                                      tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
 
+       if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+           drv->extended_capa == NULL) {
+               drv->extended_capa =
+                       os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               if (drv->extended_capa) {
+                       os_memcpy(drv->extended_capa,
+                                 nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+                                 nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+                       drv->extended_capa_len =
+                               nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+               }
+               drv->extended_capa_mask =
+                       os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               if (drv->extended_capa_mask) {
+                       os_memcpy(drv->extended_capa_mask,
+                                 nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+                                 nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+               } else {
+                       os_free(drv->extended_capa);
+                       drv->extended_capa = NULL;
+                       drv->extended_capa_len = 0;
+               }
+       }
+
        return NL_SKIP;
 }
 
@@ -2854,6 +2882,7 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
 
        os_memset(info, 0, sizeof(*info));
        info->capa = &drv->capa;
+       info->drv = drv;
 
        msg = nlmsg_alloc();
        if (!msg)
@@ -3751,6 +3780,8 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
        if (drv->in_interface_list)
                dl_list_del(&drv->list);
 
+       os_free(drv->extended_capa);
+       os_free(drv->extended_capa_mask);
        os_free(drv);
 }
 
@@ -3781,7 +3812,6 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
                    struct wpa_driver_scan_params *params)
 {
        struct nl_msg *msg;
-       int err;
        size_t i;
 
        msg = nlmsg_alloc();
@@ -3794,23 +3824,20 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
                goto fail;
 
        if (params->num_ssids) {
-               struct nl_msg *ssids = nlmsg_alloc();
+               struct nlattr *ssids;
+
+               ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
                if (ssids == NULL)
                        goto fail;
                for (i = 0; i < params->num_ssids; i++) {
                        wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
                                          params->ssids[i].ssid,
                                          params->ssids[i].ssid_len);
-                       if (nla_put(ssids, i + 1, params->ssids[i].ssid_len,
-                                   params->ssids[i].ssid) < 0) {
-                               nlmsg_free(ssids);
+                       if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+                                   params->ssids[i].ssid) < 0)
                                goto fail;
-                       }
                }
-               err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-               nlmsg_free(ssids);
-               if (err < 0)
-                       goto fail;
+               nla_nest_end(msg, ssids);
        }
 
        if (params->extra_ies) {
@@ -3822,22 +3849,17 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
        }
 
        if (params->freqs) {
-               struct nl_msg *freqs = nlmsg_alloc();
+               struct nlattr *freqs;
+               freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
                if (freqs == NULL)
                        goto fail;
                for (i = 0; params->freqs[i]; i++) {
                        wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
                                   "MHz", params->freqs[i]);
-                       if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
-                               nlmsg_free(freqs);
+                       if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
                                goto fail;
-                       }
                }
-               err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
-                                    freqs);
-               nlmsg_free(freqs);
-               if (err < 0)
-                       goto fail;
+               nla_nest_end(msg, freqs);
        }
 
        os_free(drv->filter_ssids);
@@ -3864,7 +3886,7 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1, timeout;
-       struct nl_msg *msg, *rates = NULL;
+       struct nl_msg *msg = NULL;
 
        wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
        drv->scan_for_auth = 0;
@@ -3874,9 +3896,11 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
                return -1;
 
        if (params->p2p_probe) {
+               struct nlattr *rates;
+
                wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
 
-               rates = nlmsg_alloc();
+               rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
                if (rates == NULL)
                        goto nla_put_failure;
 
@@ -3886,11 +3910,9 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
                 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
                 * rates are left enabled.
                 */
-               NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
+               NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
                        "\x0c\x12\x18\x24\x30\x48\x60\x6c");
-               if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
-                   0)
-                       goto nla_put_failure;
+               nla_nest_end(msg, rates);
 
                NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
        }
@@ -3944,7 +3966,6 @@ static int wpa_driver_nl80211_scan(struct i802_bss *bss,
 
 nla_put_failure:
        nlmsg_free(msg);
-       nlmsg_free(rates);
        return ret;
 }
 
@@ -3964,8 +3985,6 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ret = -1;
        struct nl_msg *msg;
-       struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
-       struct nl_msg *match_set_rssi = NULL;
        size_t i;
 
        wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
@@ -3984,46 +4003,42 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
        if ((drv->num_filter_ssids &&
            (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
            params->filter_rssi) {
-               match_sets = nlmsg_alloc();
+               struct nlattr *match_sets;
+               match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
                if (match_sets == NULL)
                        goto nla_put_failure;
 
                for (i = 0; i < drv->num_filter_ssids; i++) {
+                       struct nlattr *match_set_ssid;
                        wpa_hexdump_ascii(MSG_MSGDUMP,
                                          "nl80211: Sched scan filter SSID",
                                          drv->filter_ssids[i].ssid,
                                          drv->filter_ssids[i].ssid_len);
 
-                       match_set_ssid = nlmsg_alloc();
+                       match_set_ssid = nla_nest_start(msg, i + 1);
                        if (match_set_ssid == NULL)
                                goto nla_put_failure;
-                       NLA_PUT(match_set_ssid,
-                               NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+                       NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
                                drv->filter_ssids[i].ssid_len,
                                drv->filter_ssids[i].ssid);
 
-                       if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
-                           0)
-                               goto nla_put_failure;
+                       nla_nest_end(msg, match_sets);
                }
 
                if (params->filter_rssi) {
-                       match_set_rssi = nlmsg_alloc();
+                       struct nlattr *match_set_rssi;
+                       match_set_rssi = nla_nest_start(msg, 0);
                        if (match_set_rssi == NULL)
                                goto nla_put_failure;
-                       NLA_PUT_U32(match_set_rssi,
-                                   NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+                       NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
                                    params->filter_rssi);
                        wpa_printf(MSG_MSGDUMP,
                                   "nl80211: Sched scan RSSI filter %d dBm",
                                   params->filter_rssi);
-                       if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
-                               goto nla_put_failure;
+                       nla_nest_end(msg, match_set_rssi);
                }
 
-               if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
-                                  match_sets) < 0)
-                       goto nla_put_failure;
+               nla_nest_end(msg, match_sets);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -4041,9 +4056,6 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
                   "scan interval %d msec", ret, interval);
 
 nla_put_failure:
-       nlmsg_free(match_set_ssid);
-       nlmsg_free(match_sets);
-       nlmsg_free(match_set_rssi);
        nlmsg_free(msg);
        return ret;
 }
@@ -4532,18 +4544,15 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                                    NL80211_KEYTYPE_GROUP);
                }
        } else if (addr && is_broadcast_ether_addr(addr)) {
-               struct nl_msg *types;
-               int err;
+               struct nlattr *types;
+
                wpa_printf(MSG_DEBUG, "   broadcast key");
-               types = nlmsg_alloc();
+
+               types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
                if (!types)
                        goto nla_put_failure;
-               NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-               err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-                                    types);
-               nlmsg_free(types);
-               if (err)
-                       goto nla_put_failure;
+               NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+               nla_nest_end(msg, types);
        }
        NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
@@ -4577,29 +4586,21 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
        else
                NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
        if (addr && is_broadcast_ether_addr(addr)) {
-               struct nl_msg *types;
-               int err;
-               types = nlmsg_alloc();
+               struct nlattr *types;
+
+               types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
                if (!types)
                        goto nla_put_failure;
-               NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
-               err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-                                    types);
-               nlmsg_free(types);
-               if (err)
-                       goto nla_put_failure;
+               NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+               nla_nest_end(msg, types);
        } else if (addr) {
-               struct nl_msg *types;
-               int err;
-               types = nlmsg_alloc();
+               struct nlattr *types;
+
+               types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
                if (!types)
                        goto nla_put_failure;
-               NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
-               err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
-                                    types);
-               nlmsg_free(types);
-               if (err)
-                       goto nla_put_failure;
+               NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+               nla_nest_end(msg, types);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6071,7 +6072,7 @@ static int wpa_driver_nl80211_sta_add(void *priv,
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg, *wme = NULL;
+       struct nl_msg *msg;
        struct nl80211_sta_flag_update upd;
        int ret = -ENOBUFS;
 
@@ -6138,18 +6139,18 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
 
        if (params->flags & WPA_STA_WMM) {
-               wme = nlmsg_alloc();
+               struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
+
                if (!wme)
                        goto nla_put_failure;
 
                wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
-               NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+               NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
                                params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
-               NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+               NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
                                (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
                                WMM_QOSINFO_STA_SP_MASK);
-               if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
-                       goto nla_put_failure;
+               nla_nest_end(msg, wme);
        }
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6161,7 +6162,6 @@ static int wpa_driver_nl80211_sta_add(void *priv,
        if (ret == -EEXIST)
                ret = 0;
  nla_put_failure:
-       nlmsg_free(wme);
        nlmsg_free(msg);
        return ret;
 }
@@ -6245,7 +6245,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
                                     enum nl80211_iftype iftype,
                                     const u8 *addr, int wds)
 {
-       struct nl_msg *msg, *flags = NULL;
+       struct nl_msg *msg;
        int ifidx;
        int ret = -ENOBUFS;
 
@@ -6262,20 +6262,15 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
        NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
 
        if (iftype == NL80211_IFTYPE_MONITOR) {
-               int err;
+               struct nlattr *flags;
 
-               flags = nlmsg_alloc();
+               flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
                if (!flags)
                        goto nla_put_failure;
 
-               NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
-
-               err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
-
-               nlmsg_free(flags);
+               NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
 
-               if (err)
-                       goto nla_put_failure;
+               nla_nest_end(msg, flags);
        } else if (wds) {
                NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
        }
@@ -6908,19 +6903,14 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg, *flags = NULL;
+       struct nl_msg *msg;
+       struct nlattr *flags;
        struct nl80211_sta_flag_update upd;
 
        msg = nlmsg_alloc();
        if (!msg)
                return -ENOMEM;
 
-       flags = nlmsg_alloc();
-       if (!flags) {
-               nlmsg_free(msg);
-               return -ENOMEM;
-       }
-
        nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
@@ -6931,35 +6921,34 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
         * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
         * can be removed eventually.
         */
+       flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
+       if (!flags)
+               goto nla_put_failure;
        if (total_flags & WPA_STA_AUTHORIZED)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
 
        if (total_flags & WPA_STA_WMM)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
 
        if (total_flags & WPA_STA_SHORT_PREAMBLE)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
 
        if (total_flags & WPA_STA_MFP)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
 
        if (total_flags & WPA_STA_TDLS_PEER)
-               NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+               NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
 
-       if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
-               goto nla_put_failure;
+       nla_nest_end(msg, flags);
 
        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(msg);
-       nlmsg_free(flags);
        return -ENOBUFS;
 }
 
@@ -7664,6 +7653,11 @@ static int wpa_driver_nl80211_get_capa(void *priv,
        if (!drv->has_capability)
                return -1;
        os_memcpy(capa, &drv->capa, sizeof(*capa));
+       if (drv->extended_capa && drv->extended_capa_mask) {
+               capa->extended_capa = drv->extended_capa;
+               capa->extended_capa_mask = drv->extended_capa_mask;
+               capa->extended_capa_len = drv->extended_capa_len;
+       }
        return 0;
 }
 
@@ -9032,7 +9026,8 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
 {
        struct i802_bss *bss = priv;
        struct wpa_driver_nl80211_data *drv = bss->drv;
-       struct nl_msg *msg, *cqm = NULL;
+       struct nl_msg *msg;
+       struct nlattr *cqm;
        int ret = -1;
 
        wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
@@ -9046,20 +9041,18 @@ static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 
-       cqm = nlmsg_alloc();
+       cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
        if (cqm == NULL)
                goto nla_put_failure;
 
-       NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
-       NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
-       if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
-               goto nla_put_failure;
+       NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
+       NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+       nla_nest_end(msg, cqm);
 
        ret = send_and_recv_msgs(drv, msg, NULL, NULL);
        msg = NULL;
 
 nla_put_failure:
-       nlmsg_free(cqm);
        nlmsg_free(msg);
        return ret;
 }