QCA vendor command support to set band to driver
[mech_eap.git] / src / drivers / driver_nl80211.c
index 7b3dc51..a6441e3 100644 (file)
@@ -87,7 +87,6 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
 #undef nl_socket_set_nonblocking
 #define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
 
-#define genl_ctrl_resolve android_genl_ctrl_resolve
 #endif /* ANDROID */
 
 
@@ -1879,6 +1878,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
                        ret = -1;
        }
 #endif /* CONFIG_TDLS */
+#ifdef CONFIG_FST
+       /* FST Action frames */
+       if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
+               ret = -1;
+#endif /* CONFIG_FST */
 
        /* FT Action frames */
        if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
@@ -2501,7 +2505,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
 {
        struct wpa_driver_nl80211_data *drv = bss->drv;
        int ifindex;
-       struct nl_msg *msg;
+       struct nl_msg *msg = NULL;
        int ret;
        int tdls = 0;
 
@@ -2534,11 +2538,15 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
                if (!msg)
                        return -ENOBUFS;
        } else {
+               u32 suite;
+
+               suite = wpa_alg_to_cipher_suite(alg, key_len);
+               if (!suite)
+                       goto fail;
                msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
                if (!msg ||
                    nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
-                   nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER,
-                               wpa_alg_to_cipher_suite(alg, key_len)))
+                   nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, suite))
                        goto fail;
                wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
        }
@@ -2640,9 +2648,15 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
                      const u8 *key, size_t key_len)
 {
        struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
+       u32 suite;
+
        if (!key_attr)
                return -1;
 
+       suite = wpa_alg_to_cipher_suite(alg, key_len);
+       if (!suite)
+               return -1;
+
        if (defkey && alg == WPA_ALG_IGTK) {
                if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
                        return -1;
@@ -2652,8 +2666,7 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
        }
 
        if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
-           nla_put_u32(msg, NL80211_KEY_CIPHER,
-                       wpa_alg_to_cipher_suite(alg, key_len)) ||
+           nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
            (seq && seq_len &&
             nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
            nla_put(msg, NL80211_KEY_DATA, key_len, key))
@@ -4241,8 +4254,9 @@ static int wpa_driver_nl80211_hapd_send_eapol(
 
 
 static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
-                                           int total_flags,
-                                           int flags_or, int flags_and)
+                                           unsigned int total_flags,
+                                           unsigned int flags_or,
+                                           unsigned int flags_and)
 {
        struct i802_bss *bss = priv;
        struct nl_msg *msg;
@@ -5666,8 +5680,8 @@ static void *i802_init(struct hostapd_data *hapd,
        struct wpa_driver_nl80211_data *drv;
        struct i802_bss *bss;
        size_t i;
-       char brname[IFNAMSIZ];
-       int ifindex, br_ifindex;
+       char master_ifname[IFNAMSIZ];
+       int ifindex, br_ifindex = 0;
        int br_added = 0;
 
        bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
@@ -5678,15 +5692,21 @@ static void *i802_init(struct hostapd_data *hapd,
 
        drv = bss->drv;
 
-       if (linux_br_get(brname, params->ifname) == 0) {
+       if (linux_br_get(master_ifname, params->ifname) == 0) {
                wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
-                          params->ifname, brname);
-               br_ifindex = if_nametoindex(brname);
-               os_strlcpy(bss->brname, brname, IFNAMSIZ);
+                          params->ifname, master_ifname);
+               br_ifindex = if_nametoindex(master_ifname);
+               os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
+       } else if ((params->num_bridge == 0 || !params->bridge[0]) &&
+                  linux_master_get(master_ifname, params->ifname) == 0) {
+               wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
+                       params->ifname, master_ifname);
+               /* start listening for EAPOL on the master interface */
+               add_ifidx(drv, if_nametoindex(master_ifname));
        } else {
-               brname[0] = '\0';
-               br_ifindex = 0;
+               master_ifname[0] = '\0';
        }
+
        bss->br_ifindex = br_ifindex;
 
        for (i = 0; i < params->num_bridge; i++) {
@@ -5706,7 +5726,7 @@ static void *i802_init(struct hostapd_data *hapd,
                if (i802_check_bridge(drv, bss, params->bridge[0],
                                      params->ifname) < 0)
                        goto failed;
-               if (os_strcmp(params->bridge[0], brname) != 0)
+               if (os_strcmp(params->bridge[0], master_ifname) != 0)
                        br_added = 1;
        }
 
@@ -5789,8 +5809,6 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
 }
 
 
-#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
-
 static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
 {
        struct wpa_driver_nl80211_data *drv;
@@ -5826,8 +5844,6 @@ static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
        return 0;
 }
 
-#endif /* CONFIG_P2P || CONFIG_MESH */
-
 
 struct wdev_info {
        u64 wdev_id;
@@ -5903,21 +5919,21 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
        }
 
        if (!addr) {
-               if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+               if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
                        os_memcpy(if_addr, bss->addr, ETH_ALEN);
                else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
-                                           bss->ifname, if_addr) < 0) {
+                                           ifname, if_addr) < 0) {
                        if (added)
                                nl80211_remove_iface(drv, ifidx);
                        return -1;
                }
        }
 
-#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
        if (!addr &&
            (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
-            type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) {
-               /* Enforce unique P2P Interface Address */
+            type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
+            type == WPA_IF_STATION)) {
+               /* Enforce unique address */
                u8 new_addr[ETH_ALEN];
 
                if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
@@ -5928,8 +5944,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                }
                if (nl80211_addr_in_use(drv->global, new_addr)) {
                        wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
-                                  "for %s interface", type == WPA_IF_MESH ?
-                                  "mesh" : "P2P group");
+                                  "for interface %s type %d", ifname, type);
                        if (nl80211_vif_addr(drv, new_addr) < 0) {
                                if (added)
                                        nl80211_remove_iface(drv, ifidx);
@@ -5944,7 +5959,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
                }
                os_memcpy(if_addr, new_addr, ETH_ALEN);
        }
-#endif /* CONFIG_P2P || CONFIG_MESH */
 
        if (type == WPA_IF_AP_BSS) {
                struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
@@ -7242,11 +7256,12 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
 
 
 static int driver_nl80211_send_mlme(void *priv, const u8 *data,
-                                   size_t data_len, int noack)
+                                   size_t data_len, int noack,
+                                   unsigned int freq)
 {
        struct i802_bss *bss = priv;
        return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
-                                           0, 0, 0, 0);
+                                           freq, 0, 0, 0);
 }
 
 
@@ -7804,7 +7819,7 @@ static int nl80211_set_wowlan(void *priv,
 
        wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
 
-       if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) ||
+       if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
            !(wowlan_triggers = nla_nest_start(msg,
                                               NL80211_ATTR_WOWLAN_TRIGGERS)) ||
            (triggers->any &&
@@ -8307,9 +8322,9 @@ static const char * drv_br_net_param_str(enum drv_br_net_param param)
        switch (param) {
        case DRV_BR_NET_PARAM_GARP_ACCEPT:
                return "arp_accept";
+       default:
+               return NULL;
        }
-
-       return NULL;
 }
 
 
@@ -8321,6 +8336,13 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
        const char *param_txt;
        int ip_version = 4;
 
+       if (param == DRV_BR_MULTICAST_SNOOPING) {
+               os_snprintf(path, sizeof(path),
+                           "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
+                           bss->brname);
+               goto set_val;
+       }
+
        param_txt = drv_br_net_param_str(param);
        if (param_txt == NULL)
                return -EINVAL;
@@ -8336,6 +8358,7 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
        os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
                    ip_version, bss->brname, param_txt);
 
+set_val:
        if (linux_write_system_file(path, val))
                return -1;
 
@@ -8354,6 +8377,8 @@ static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
                return QCA_ACS_MODE_IEEE80211A;
        case HOSTAPD_MODE_IEEE80211AD:
                return QCA_ACS_MODE_IEEE80211AD;
+       case HOSTAPD_MODE_IEEE80211ANY:
+               return QCA_ACS_MODE_IEEE80211ANY;
        default:
                return -1;
        }
@@ -8410,6 +8435,53 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
 }
 
 
+static int nl80211_set_band(void *priv, enum set_band band)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct nl_msg *msg;
+       struct nlattr *data;
+       int ret;
+       enum qca_set_band qca_band;
+
+       if (!drv->setband_vendor_cmd_avail)
+               return -1;
+
+       switch (band) {
+       case WPA_SETBAND_AUTO:
+               qca_band = QCA_SETBAND_AUTO;
+               break;
+       case WPA_SETBAND_5G:
+               qca_band = QCA_SETBAND_5G;
+               break;
+       case WPA_SETBAND_2G:
+               qca_band = QCA_SETBAND_2G;
+               break;
+       default:
+               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_SETBAND) ||
+           !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+           nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
+       nla_nest_end(msg, data);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+       if (ret) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Driver setband function failed: %s",
+                          strerror(errno));
+       }
+       return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -8496,7 +8568,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
 #endif /* ANDROID_P2P */
 #ifdef ANDROID
+#ifndef ANDROID_LIB_STUB
        .driver_cmd = wpa_driver_nl80211_driver_cmd,
+#endif /* !ANDROID_LIB_STUB */
 #endif /* ANDROID */
        .vendor_cmd = nl80211_vendor_cmd,
        .set_qos_map = nl80211_set_qos_map,
@@ -8515,4 +8589,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .add_tx_ts = nl80211_add_ts,
        .del_tx_ts = nl80211_del_ts,
        .do_acs = wpa_driver_do_acs,
+       .set_band = nl80211_set_band,
 };