ath10k: implement mesh support
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / ath / ath10k / mac.c
index 80efcc8debfec8157ea4daa1277296a5b9edd217..1cda4f9dd4531fb9b58364c4eada6d7ac363e802 100644 (file)
@@ -4211,6 +4211,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        case NL80211_IFTYPE_ADHOC:
                arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
                break;
+       case NL80211_IFTYPE_MESH_POINT:
+               if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
+                       ret = -EINVAL;
+                       ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
+                       goto err;
+               }
+               arvif->vdev_type = WMI_VDEV_TYPE_AP;
+               break;
        case NL80211_IFTYPE_AP:
                arvif->vdev_type = WMI_VDEV_TYPE_AP;
 
@@ -4251,6 +4259,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
         * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
         */
        if (vif->type == NL80211_IFTYPE_ADHOC ||
+           vif->type == NL80211_IFTYPE_MESH_POINT ||
            vif->type == NL80211_IFTYPE_AP) {
                arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
                                                        IEEE80211_MAX_FRAME_LEN,
@@ -4590,6 +4599,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                if (ret)
                        ath10k_warn(ar, "failed to update beacon template: %d\n",
                                    ret);
+
+               if (ieee80211_vif_is_mesh(vif)) {
+                       /* mesh doesn't use SSID but firmware needs it */
+                       strncpy(arvif->u.ap.ssid, "mesh",
+                               sizeof(arvif->u.ap.ssid));
+                       arvif->u.ap.ssid_len = 4;
+               }
        }
 
        if (changed & BSS_CHANGED_AP_PROBE_RESP) {
@@ -5329,6 +5345,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC &&
                   (vif->type == NL80211_IFTYPE_AP ||
+                   vif->type == NL80211_IFTYPE_MESH_POINT ||
                    vif->type == NL80211_IFTYPE_ADHOC)) {
                /*
                 * New association.
@@ -5364,6 +5381,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
        } else if (old_state == IEEE80211_STA_ASSOC &&
                    new_state == IEEE80211_STA_AUTH &&
                    (vif->type == NL80211_IFTYPE_AP ||
+                    vif->type == NL80211_IFTYPE_MESH_POINT ||
                     vif->type == NL80211_IFTYPE_ADHOC)) {
                /*
                 * Disassociation.
@@ -6678,6 +6696,9 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
        {
        .max    = 7,
        .types  = BIT(NL80211_IFTYPE_AP)
+#ifdef CONFIG_MAC80211_MESH
+               | BIT(NL80211_IFTYPE_MESH_POINT)
+#endif
        },
 };
 
@@ -6685,6 +6706,9 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
        {
        .max    = 8,
        .types  = BIT(NL80211_IFTYPE_AP)
+#ifdef CONFIG_MAC80211_MESH
+               | BIT(NL80211_IFTYPE_MESH_POINT)
+#endif
        },
 };
 
@@ -6722,6 +6746,9 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = {
        {
                .max = 2,
                .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+                        BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
                         BIT(NL80211_IFTYPE_P2P_CLIENT) |
                         BIT(NL80211_IFTYPE_P2P_GO),
        },
@@ -6743,6 +6770,9 @@ static const struct ieee80211_iface_limit ath10k_tlv_qcs_if_limit[] = {
        {
                .max = 1,
                .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+                        BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
                         BIT(NL80211_IFTYPE_P2P_GO),
        },
        {
@@ -6809,6 +6839,9 @@ static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = {
        {
                .max    = 16,
                .types  = BIT(NL80211_IFTYPE_AP)
+#ifdef CONFIG_MAC80211_MESH
+                       | BIT(NL80211_IFTYPE_MESH_POINT)
+#endif
        },
 };
 
@@ -7033,7 +7066,8 @@ int ath10k_mac_register(struct ath10k *ar)
 
        ar->hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_AP);
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_MESH_POINT);
 
        ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
        ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;