*/
LINK_CONFIG_CMD = 0x9,
/**
- * @STA_CONFIG_CMD: &struct iwl_sta_cfg_cmd
+ * @STA_CONFIG_CMD: &struct iwl_sta_cfg_cmd_v1,
+ * &struct iwl_sta_cfg_cmd_v2, or &struct iwl_sta_cfg_cmd
*/
STA_CONFIG_CMD = 0xA,
/**
* @STATION_TYPE_MCAST: the station used for BCAST / MCAST in GO. Will be
* suspended / resumed at the right timing depending on the clients'
* power save state and the DTIM timing
+ * @STATION_TYPE_NAN_PEER_NMI: NAN management peer station type. A station
+ * of this type can have any number of links (even none) set in the
+ * link_mask. (Supported since version 3.)
+ * @STATION_TYPE_NAN_PEER_NDI: NAN data peer station type. A station
+ * of this type can have any number of links (even none) set in the
+ * link_mask. (Supported since version 3.)
+ * @STATION_TYPE_MAX: maximum number of FW station types
* @STATION_TYPE_AUX: aux sta. In the FW there is no need for a special type
* for the aux sta, so this type is only for driver - internal use.
*/
STATION_TYPE_PEER,
STATION_TYPE_BCAST_MGMT,
STATION_TYPE_MCAST,
- STATION_TYPE_AUX,
-}; /* STATION_TYPE_E_VER_1 */
+ STATION_TYPE_NAN_PEER_NMI,
+ STATION_TYPE_NAN_PEER_NDI,
+ STATION_TYPE_MAX,
+ STATION_TYPE_AUX = STATION_TYPE_MAX /* this doesn't exist in FW */
+}; /* STATION_TYPE_E_VER_1, _VER_2 */
/**
* struct iwl_sta_cfg_cmd_v1 - cmd structure to add a peer sta to the uCode's
} __packed; /* STA_CMD_API_S_VER_1 */
/**
- * struct iwl_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's
+ * struct iwl_sta_cfg_cmd_v2 - cmd structure to add a peer sta to the uCode's
* station table
* ( STA_CONFIG_CMD = 0xA )
*
* @mic_compute_pad_delay: MIC compute time padding
* @reserved: Reserved for alignment
*/
-struct iwl_sta_cfg_cmd {
+struct iwl_sta_cfg_cmd_v2 {
__le32 sta_id;
__le32 link_id;
u8 peer_mld_address[ETH_ALEN];
u8 reserved[2];
} __packed; /* STA_CMD_API_S_VER_2 */
+/**
+ * struct iwl_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's
+ * station table
+ * ( STA_CONFIG_CMD = 0xA )
+ *
+ * @sta_id: index of station in uCode's station table
+ * @link_mask: bitmap of link FW IDs used with this STA
+ * @peer_mld_address: the peers mld address
+ * @reserved_for_peer_mld_address: reserved
+ * @peer_link_address: the address of the link that is used to communicate
+ * with this sta
+ * @reserved_for_peer_link_address: reserved
+ * @station_type: type of this station. See &enum iwl_fw_sta_type
+ * @assoc_id: for GO only
+ * @beamform_flags: beam forming controls
+ * @mfp: indicates whether the STA uses management frame protection or not.
+ * @mimo: indicates whether the sta uses mimo or not
+ * @mimo_protection: indicates whether the sta uses mimo protection or not
+ * @ack_enabled: indicates that the AP supports receiving ACK-
+ * enabled AGG, i.e. both BACK and non-BACK frames in a single AGG
+ * @trig_rnd_alloc: indicates that trigger based random allocation
+ * is enabled according to UORA element existence
+ * @tx_ampdu_spacing: minimum A-MPDU spacing:
+ * 4 - 2us density, 5 - 4us density, 6 - 8us density, 7 - 16us density
+ * @tx_ampdu_max_size: maximum A-MPDU length: 0 - 8K, 1 - 16K, 2 - 32K,
+ * 3 - 64K, 4 - 128K, 5 - 256K, 6 - 512K, 7 - 1024K.
+ * @sp_length: the size of the SP in actual number of frames
+ * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver
+ * enabled ACs.
+ * @pkt_ext: optional, exists according to PPE-present bit in the HE/EHT-PHY
+ * capa
+ * @htc_flags: which features are supported in HTC
+ * @use_ldpc_x2_cw: Indicates whether to use LDPC with double CW
+ * @use_icf: Indicates whether to use ICF instead of RTS
+ * @dps_pad_time: DPS (Dynamic Power Save) padding delay resolution to ensure
+ * proper timing alignment
+ * @dps_trans_delay: DPS minimal time that takes the peer to return to low power
+ * @dps_enabled: flag indicating whether or not DPS is enabled
+ * @mic_prep_pad_delay: MIC prep time padding
+ * @mic_compute_pad_delay: MIC compute time padding
+ * @nmi_sta_id: for an NDI peer STA, the NMI peer STA ID it relates to
+ * @ndi_local_addr: for an NDI peer STA, the local NDI interface MAC address
+ * @reserved: Reserved for alignment
+ */
+struct iwl_sta_cfg_cmd {
+ __le32 sta_id;
+ __le32 link_mask;
+ u8 peer_mld_address[ETH_ALEN];
+ __le16 reserved_for_peer_mld_address;
+ u8 peer_link_address[ETH_ALEN];
+ __le16 reserved_for_peer_link_address;
+ __le32 station_type;
+ __le32 assoc_id;
+ __le32 beamform_flags;
+ __le32 mfp;
+ __le32 mimo;
+ __le32 mimo_protection;
+ __le32 ack_enabled;
+ __le32 trig_rnd_alloc;
+ __le32 tx_ampdu_spacing;
+ __le32 tx_ampdu_max_size;
+ __le32 sp_length;
+ __le32 uapsd_acs;
+ struct iwl_he_pkt_ext_v2 pkt_ext;
+ __le32 htc_flags;
+ u8 use_ldpc_x2_cw;
+ u8 use_icf;
+ u8 dps_pad_time;
+ u8 dps_trans_delay;
+ u8 dps_enabled;
+ u8 mic_prep_pad_delay;
+ u8 mic_compute_pad_delay;
+ u8 nmi_sta_id;
+ u8 ndi_local_addr[ETH_ALEN];
+ u8 reserved[2];
+} __packed; /* STA_CMD_API_S_VER_3 */
+
/**
* struct iwl_aux_sta_cmd - command for AUX STA configuration
* ( AUX_STA_CMD = 0xB )
return htc_flags;
}
+/* Note: modifies the command depending on FW command version */
static int iwl_mld_send_sta_cmd(struct iwl_mld *mld,
- const struct iwl_sta_cfg_cmd *cmd)
+ struct iwl_sta_cfg_cmd *cmd)
{
- int ret = iwl_mld_send_cmd_pdu(mld,
- WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD),
- cmd);
+ int cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD);
+ int cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0);
+ int len = sizeof(*cmd);
+ int ret;
+
+ if (cmd_ver < 2) {
+ IWL_ERR(mld, "Unsupported STA_CONFIG_CMD version %d\n",
+ cmd_ver);
+ return -EINVAL;
+ } else if (cmd_ver == 2) {
+ struct iwl_sta_cfg_cmd_v2 *cmd_v2 = (void *)cmd;
+
+ if (WARN_ON(cmd->station_type == cpu_to_le32(STATION_TYPE_NAN_PEER_NMI) ||
+ cmd->station_type == cpu_to_le32(STATION_TYPE_NAN_PEER_NDI) ||
+ hweight32(le32_to_cpu(cmd->link_mask)) != 1))
+ return -EINVAL;
+ /*
+ * These fields are located in a different place in the struct of v2.
+ * The assumption is that UHR won't be used with FW that has v2.
+ */
+ if (WARN_ON(cmd->mic_prep_pad_delay || cmd->mic_compute_pad_delay))
+ return -EINVAL;
+
+ len = sizeof(struct iwl_sta_cfg_cmd_v2);
+ cmd_v2->link_id = cpu_to_le32(__ffs(le32_to_cpu(cmd->link_mask)));
+ } else if (WARN_ON(cmd->station_type != cpu_to_le32(STATION_TYPE_NAN_PEER_NMI) &&
+ cmd->station_type != cpu_to_le32(STATION_TYPE_NAN_PEER_NDI) &&
+ hweight32(le32_to_cpu(cmd->link_mask)) != 1)) {
+ return -EINVAL;
+ }
+
+ ret = iwl_mld_send_cmd_pdu(mld, cmd_id, cmd, len);
if (ret)
IWL_ERR(mld, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret);
return ret;
return -EINVAL;
cmd.sta_id = cpu_to_le32(fw_id);
+ cmd.link_mask = cpu_to_le32(BIT(mld_link->fw_id));
cmd.station_type = cpu_to_le32(mld_sta->sta_type);
- cmd.link_id = cpu_to_le32(mld_link->fw_id);
memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN);
memcpy(&cmd.peer_link_address, link_sta->addr, ETH_ALEN);
return iwl_mld_send_aux_sta_cmd(mld, internal_sta);
cmd.sta_id = cpu_to_le32((u8)internal_sta->sta_id);
- cmd.link_id = cpu_to_le32(fw_link_id);
+ cmd.link_mask = cpu_to_le32(BIT(fw_link_id));
cmd.station_type = cpu_to_le32(internal_sta->sta_type);
/* FW doesn't allow to add a IGTK/BIGTK if the sta isn't marked as MFP.
}
static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm,
- struct iwl_sta_cfg_cmd *cmd)
+ struct iwl_sta_cfg_cmd_v2 *cmd)
{
u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD);
int cmd_len = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) > 1 ?
struct iwl_mvm_int_sta *sta,
const u8 *addr, int link_id)
{
- struct iwl_sta_cfg_cmd cmd;
+ struct iwl_sta_cfg_cmd_v2 cmd;
lockdep_assert_held(&mvm->mutex);
struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_vif_link_info *link_info =
mvm_vif->link[link_conf->link_id];
- struct iwl_sta_cfg_cmd cmd = {
+ struct iwl_sta_cfg_cmd_v2 cmd = {
.sta_id = cpu_to_le32(mvm_link_sta->sta_id),
.station_type = cpu_to_le32(mvm_sta->sta_type),
};