* @NAN_SCHEDULE_CMD: &struct iwl_nan_schedule_cmd
*/
NAN_SCHEDULE_CMD = 0x13,
+ /**
+ * @NAN_PEER_CMD: &struct iwl_nan_peer_cmd
+ */
+ NAN_PEER_CMD = 0x14,
/**
* @NAN_DW_END_NOTIF: &struct iwl_nan_dw_end_notif
*/
} __packed channels[NUM_PHY_CTX];
} __packed; /* NAN_SCHEDULE_CMD_API_S_VER_1 */
+/**
+ * struct iwl_nan_peer_cmd - NAN peer command
+ * @nmi_sta_id: NAN management station ID
+ * @sequence_id: NAN Availability attribute sequence ID
+ * @committed_dw_info: committed DW info from the NAN Device
+ * Capability attribute
+ * @max_channel_switch_time: maximum channel switch time
+ * (in microseconds); 0 means unavailable
+ * @reserved: (reserved)
+ * @per_phy: per-PHY information for this peer, indexed by PHY ID
+ * @per_phy.availability_map: bitmap of which slots this peer
+ * is available in on this PHY. 0 indicates the this per-PHY entry
+ * is unused.
+ * @per_phy.channel_entry: the channel description the peer is using,
+ * used for comparisons in ULW management
+ * @per_phy.link_id: FW link ID, should be a valid id.
+ * @per_phy.map_id: map ID from peer's NAN Availability attributec
+ * @initial_ulw_size: size of the initial ULW blob
+ * @initial_ulw: initial ULW data from the peer
+ */
+struct iwl_nan_peer_cmd {
+ u8 nmi_sta_id;
+ u8 sequence_id;
+ __le16 committed_dw_info;
+ __le16 max_channel_switch_time;
+ __le16 reserved;
+
+ struct {
+ __le32 availability_map;
+ u8 channel_entry[6];
+ u8 link_id;
+ u8 map_id;
+ } __packed per_phy[NUM_PHY_CTX];
+
+ __le32 initial_ulw_size;
+ u8 initial_ulw[];
+} __packed; /* NAN_PEER_SCHEDULE_CMD_API_S_VER_1 */
+
/**
* enum iwl_nan_cluster_notif_flags - flags for the cluster notification
*
iwl_mld_rm_vif(mld, vif);
}
}
+
+int iwl_mld_mac802111_nan_peer_sched_changed(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+ struct ieee80211_nan_peer_sched *sched = sta->nan_sched;
+ struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(mld_sta->vif);
+ struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
+ struct iwl_mld_nan_link *nan_link;
+ struct iwl_nan_peer_cmd cmd = {
+ .nmi_sta_id = mld_sta->deflink.fw_id,
+ .sequence_id = sched->seq_id,
+ .committed_dw_info = cpu_to_le16(sched->committed_dw),
+ .max_channel_switch_time = cpu_to_le16(sched->max_chan_switch),
+ .initial_ulw_size = cpu_to_le32(sched->ulw_size),
+ .per_phy[0 ... NUM_PHY_CTX - 1] = {
+ /* unused by FW if availability_map == 0 */
+ .map_id = CFG80211_NAN_INVALID_MAP_ID,
+ .link_id = FW_CTXT_ID_INVALID,
+ },
+ /* .initial_ulw directly provided below by data[1]/len[1] */
+ };
+ struct iwl_host_cmd hcmd = {
+ .id = WIDE_ID(MAC_CONF_GROUP, NAN_PEER_CMD),
+ .data[0] = &cmd,
+ .len[0] = sizeof(cmd),
+ .data[1] = sched->init_ulw,
+ .len[1] = sched->ulw_size,
+ .dataflags[1] = IWL_HCMD_DFL_DUP,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(sched->maps); i++) {
+ if (sched->maps[i].map_id == CFG80211_NAN_INVALID_MAP_ID)
+ continue;
+
+ BUILD_BUG_ON(ARRAY_SIZE(sched->maps[i].slots) != 32);
+ for (int slot = 0;
+ slot < ARRAY_SIZE(sched->maps[i].slots);
+ slot++) {
+ struct ieee80211_chanctx_conf *ctx;
+ struct ieee80211_nan_channel *chan;
+ struct iwl_mld_phy *phy;
+
+ chan = sched->maps[i].slots[slot];
+ if (!chan)
+ continue;
+
+ ctx = chan->chanctx_conf;
+ if (!ctx)
+ continue;
+
+ phy = iwl_mld_phy_from_mac80211(ctx);
+
+ for_each_mld_nan_valid_link(mld_vif, nan_link) {
+ if (nan_link->chanctx == ctx) {
+ cmd.per_phy[phy->fw_id].link_id =
+ nan_link->fw_id;
+ break;
+ }
+ }
+
+ if (WARN_ON(cmd.per_phy[phy->fw_id].link_id ==
+ FW_CTXT_ID_INVALID))
+ continue;
+
+ /*
+ * each channel can only appear in one map,
+ * upper layers enforce that
+ */
+ if (WARN_ON(cmd.per_phy[phy->fw_id].map_id != CFG80211_NAN_INVALID_MAP_ID &&
+ cmd.per_phy[phy->fw_id].map_id != sched->maps[i].map_id))
+ continue;
+
+ cmd.per_phy[phy->fw_id].map_id = sched->maps[i].map_id;
+ memcpy(cmd.per_phy[phy->fw_id].channel_entry,
+ chan->channel_entry,
+ sizeof(cmd.per_phy[phy->fw_id].channel_entry));
+ cmd.per_phy[phy->fw_id].availability_map |=
+ cpu_to_le32(BIT(slot));
+ }
+ }
+
+ return iwl_mld_send_cmd(mld, &hcmd);
+}