From: Stella Liu Forward NAN Unaligned Window attributes between FW and mac80211: report ULW updates from FW via cfg80211_nan_ulw_update() and push peer ULW attributes to FW with NAN_UNI_CMD_UPDATE_ULW. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Stella Liu --- .../net/wireless/mediatek/mt76/mt7925/nan.c | 84 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7925/nan.h | 40 ++++++++- 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c index 16fb196e1bf5..53736b156f69 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c @@ -397,6 +397,52 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv) ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, true, GFP_KERNEL); } +static void +mt7925_nan_handle_ulw_update(struct mt792x_dev *dev, struct tlv *tlv) +{ + struct mt7925_nan_ulw_event *evt; + struct mt7925_nan_ulw_attr attr; + struct wireless_dev *wdev; + u16 len; + + if (!dev || !tlv) + return; + + if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) + return; + + len = le16_to_cpu(tlv->len); + if (len < sizeof(*tlv) + sizeof(*evt)) { + dev_warn(dev->mt76.dev, + "nan: short ulw event tlv len=%u\n", len); + return; + } + + evt = (struct mt7925_nan_ulw_event *)tlv->data; + wdev = ieee80211_vif_to_wdev(dev->nan_vif); + if (!wdev) + return; + + dev_dbg(dev->mt76.dev, + "nan: ulw_update wdev=%p owner_nlportid=%u sched_id=%u seq=%u dur=%u\n", + wdev, wdev->owner_nlportid, + evt->sched_id, evt->seq_id, le32_to_cpu(evt->duration)); + + /* Reorder the FW fields into NAN spec Table 109 attribute layout */ + attr.attr_id = NAN_ULW_ATTR_ID; + attr.length = cpu_to_le16(NAN_ULW_FIXED_PAYLOAD); + attr.sched_id = evt->sched_id; + attr.seq_id = evt->seq_id; + attr.start_time = evt->start_time; + attr.duration = evt->duration; + attr.period = evt->period; + attr.count_down = evt->count_down; + attr.ulw_overwrite = evt->ulw_overwrite; + + cfg80211_nan_ulw_update(wdev, (const u8 *)&attr, sizeof(attr), + GFP_KERNEL); +} + void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct tlv *tlv; @@ -425,6 +471,9 @@ void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb) case NAN_UNI_EVENT_REPORT_DW_START: mt7925_nan_handle_dw_ind(dev, tlv); break; + case NAN_UNI_EVENT_ID_ULW_UPDATE: + mt7925_nan_handle_ulw_update(dev, tlv); + break; default: break; } @@ -736,6 +785,37 @@ static int mt7925_nan_update_crb_tlv(struct sk_buff *skb, return 0; } +static int +mt7925_nan_peer_ulw_tlv(struct sk_buff *skb, + struct ieee80211_sta *sta, + struct mt792x_sta *msta) +{ + struct mt7925_nan_update_ulw_tlv *ulw_tlv = NULL; + struct ieee80211_nan_peer_sched *sched = NULL; + struct tlv *tlv = NULL; + + if (!skb || !sta || !msta) + return -EINVAL; + + sched = sta->nan_sched; + if (!sched || !sched->init_ulw || !sched->ulw_size) + return 0; /* No ULW to send, not an error */ + + if (sched->ulw_size > NAN_ULW_MAX_SIZE) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_ULW, + sizeof(struct mt7925_nan_update_ulw_tlv)); + if (!tlv) + return -ENOMEM; + + ulw_tlv = (struct mt7925_nan_update_ulw_tlv *)tlv; + ether_addr_copy(ulw_tlv->nmi_addr, sta->addr); + memcpy(ulw_tlv->ulw_attr, sched->init_ulw, sched->ulw_size); + + return 0; +} + int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev, struct ieee80211_sta *sta) { @@ -788,6 +868,10 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev, goto free_skb; } + ret = mt7925_nan_peer_ulw_tlv(skb, sta, msta); + if (ret) + goto free_skb; + ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true); if (ret && idx_allocated) goto clear_idx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h index 32e2e9cfffc7..c9207b5c899e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h @@ -50,7 +50,8 @@ (sizeof(struct mt7925_nan_common_hdr) + \ sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv) + \ sizeof(struct mt7925_nan_sched_update_peer_cap_tlv) + \ - sizeof(struct mt7925_nan_sched_update_crb_tlv)) + sizeof(struct mt7925_nan_sched_update_crb_tlv) + \ + sizeof(struct mt7925_nan_update_ulw_tlv)) /* NAN Availability Attribute */ #define NAN_AVAIL_ATTR_ID_OFFSET 0 @@ -81,6 +82,7 @@ enum nan_uni_cmd_tag { NAN_UNI_CMD_UPDATE_CRB = 10, NAN_UNI_CMD_MANAGE_PEER_SCH_RECORD = 12, NAN_UNI_CMD_MAP_STA_RECORD = 13, + NAN_UNI_CMD_UPDATE_ULW = 16, NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL = 20, NAN_UNI_CMD_UPDATE_PEER_CAPABILITY = 21, NAN_UNI_CMD_CHANGE_NMI_ADDRESS = 24, @@ -92,6 +94,7 @@ enum nan_uni_cmd_tag { enum nan_uni_event_tag { NAN_UNI_EVENT_ID_DE_EVENT_IND = 19, + NAN_UNI_EVENT_ID_ULW_UPDATE = 39, NAN_UNI_EVENT_REPORT_DW_START = 59, NAN_UNI_EVENT_REPORT_DW_END = 60, }; @@ -165,6 +168,32 @@ struct nan_rpt_dw_evt { __le16 dw_num; }; +#define NAN_ULW_ATTR_ID 0x17 +#define NAN_ULW_FIXED_PAYLOAD 16 /* Table 109 fixed fields */ + +struct mt7925_nan_ulw_event { + u8 sched_id; + u8 seq_id; + u8 count_down; + u8 ulw_overwrite; + __le32 start_time; + __le32 duration; + __le32 period; +} __packed; + +/* ULW attribute laid out in NAN spec Table 109 field order */ +struct mt7925_nan_ulw_attr { + u8 attr_id; + __le16 length; + u8 sched_id; + u8 seq_id; + __le32 start_time; + __le32 duration; + __le32 period; + u8 count_down; + u8 ulw_overwrite; +} __packed; + struct mt7925_nan_conf_dw { u8 config_2dot4g_dw_band; __le32 dw_2dot4g_interval_val; @@ -389,6 +418,15 @@ struct mt7925_nan_sched_update_crb_tlv { struct mt7925_nan_sched_faw_ndc_timeline faw_ndc_timeline[NAN_TIMELINE_MGMT_SIZE]; } __packed __aligned(4); +#define NAN_ULW_MAX_SIZE 256 + +struct mt7925_nan_update_ulw_tlv { + __le16 tag; + __le16 len; + u8 nmi_addr[ETH_ALEN]; + u8 ulw_attr[NAN_ULW_MAX_SIZE]; +} __packed __aligned(4); + struct mt7925_nan_sched_map_sta_rec_tlv { __le16 tag; __le16 len; -- 2.43.0