mt: mt7921: Add AP mode support
[platform/kernel/linux-rpi.git] / drivers / net / wireless / mediatek / mt76-6e-usb / mt7921 / mcu.c
index 2a609b2..b1ce15c 100644 (file)
@@ -248,7 +248,8 @@ mt7921_mcu_connection_loss_iter(void *priv, u8 *mac,
        if (mvif->idx != event->bss_idx)
                return;
 
-       if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER))
+       if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER) ||
+           vif->type != NL80211_IFTYPE_STATION)
                return;
 
        ieee80211_connection_loss(vif);
@@ -1167,3 +1168,79 @@ int mt7921_mcu_set_sniffer(struct mt7921_dev *dev, struct ieee80211_vif *vif,
        return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req),
                                 true);
 }
+
+int
+mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev,
+                                 struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 bool enable)
+{
+       struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+       struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+       struct ieee80211_mutable_offsets offs;
+       struct {
+               struct req_hdr {
+                       u8 bss_idx;
+                       u8 pad[3];
+               } __packed hdr;
+               struct bcn_content_tlv {
+                       __le16 tag;
+                       __le16 len;
+                       __le16 tim_ie_pos;
+                       __le16 csa_ie_pos;
+                       __le16 bcc_ie_pos;
+                       /* 0: disable beacon offload
+                        * 1: enable beacon offload
+                        * 2: update probe respond offload
+                        */
+                       u8 enable;
+                       /* 0: legacy format (TXD + payload)
+                        * 1: only cap field IE
+                        */
+                       u8 type;
+                       __le16 pkt_len;
+                       u8 pkt[512];
+               } __packed beacon_tlv;
+       } req = {
+               .hdr = {
+                       .bss_idx = mvif->mt76.idx,
+               },
+               .beacon_tlv = {
+                       .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),
+                       .len = cpu_to_le16(sizeof(struct bcn_content_tlv)),
+                       .enable = enable,
+               },
+       };
+       struct sk_buff *skb;
+
+       if (!enable)
+               goto out;
+
+       skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs);
+       if (!skb)
+               return -EINVAL;
+
+       if (skb->len > 512 - MT_TXD_SIZE) {
+               dev_err(dev->mt76.dev, "beacon size limit exceed\n");
+               dev_kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       mt7921_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb,
+                             wcid, NULL, 0, true);
+       memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len);
+       req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
+       req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
+
+       if (offs.cntdwn_counter_offs[0]) {
+               u16 csa_offs;
+
+               csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
+               req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);
+       }
+       dev_kfree_skb(skb);
+
+out:
+       return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
+                                &req, sizeof(req), true);
+}