xref: /freebsd/sys/dev/iwm/if_iwm_sta.c (revision 685dc743)
1f48f6960SAdrian Chadd /*-
2f48f6960SAdrian Chadd  * Based on BSD-licensed source modules in the Linux iwlwifi driver,
3f48f6960SAdrian Chadd  * which were used as the reference documentation for this implementation.
4f48f6960SAdrian Chadd  *
5f48f6960SAdrian Chadd  * Driver version we are currently based off of is
6f48f6960SAdrian Chadd  * Linux 4.7.3 (tag id d7f6728f57e3ecbb7ef34eb7d9f564d514775d75)
7f48f6960SAdrian Chadd  *
8f48f6960SAdrian Chadd  ***********************************************************************
9f48f6960SAdrian Chadd  *
10f48f6960SAdrian Chadd  * This file is provided under a dual BSD/GPLv2 license.  When using or
11f48f6960SAdrian Chadd  * redistributing this file, you may do so under either license.
12f48f6960SAdrian Chadd  *
13f48f6960SAdrian Chadd  * GPL LICENSE SUMMARY
14f48f6960SAdrian Chadd  *
15f48f6960SAdrian Chadd  * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
16f48f6960SAdrian Chadd  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
17f48f6960SAdrian Chadd  * Copyright(c) 2016 Intel Deutschland GmbH
18f48f6960SAdrian Chadd  *
19f48f6960SAdrian Chadd  * This program is free software; you can redistribute it and/or modify
20f48f6960SAdrian Chadd  * it under the terms of version 2 of the GNU General Public License as
21f48f6960SAdrian Chadd  * published by the Free Software Foundation.
22f48f6960SAdrian Chadd  *
23f48f6960SAdrian Chadd  * This program is distributed in the hope that it will be useful, but
24f48f6960SAdrian Chadd  * WITHOUT ANY WARRANTY; without even the implied warranty of
25f48f6960SAdrian Chadd  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26f48f6960SAdrian Chadd  * General Public License for more details.
27f48f6960SAdrian Chadd  *
28f48f6960SAdrian Chadd  * You should have received a copy of the GNU General Public License
29f48f6960SAdrian Chadd  * along with this program; if not, write to the Free Software
30f48f6960SAdrian Chadd  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
31f48f6960SAdrian Chadd  * USA
32f48f6960SAdrian Chadd  *
33f48f6960SAdrian Chadd  * The full GNU General Public License is included in this distribution
34f48f6960SAdrian Chadd  * in the file called COPYING.
35f48f6960SAdrian Chadd  *
36f48f6960SAdrian Chadd  * Contact Information:
37f48f6960SAdrian Chadd  *  Intel Linux Wireless <linuxwifi@intel.com>
38f48f6960SAdrian Chadd  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
39f48f6960SAdrian Chadd  *
40f48f6960SAdrian Chadd  * BSD LICENSE
41f48f6960SAdrian Chadd  *
42f48f6960SAdrian Chadd  * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
43f48f6960SAdrian Chadd  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
44f48f6960SAdrian Chadd  * Copyright(c) 2016 Intel Deutschland GmbH
45f48f6960SAdrian Chadd  * All rights reserved.
46f48f6960SAdrian Chadd  *
47f48f6960SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
48f48f6960SAdrian Chadd  * modification, are permitted provided that the following conditions
49f48f6960SAdrian Chadd  * are met:
50f48f6960SAdrian Chadd  *
51f48f6960SAdrian Chadd  *  * Redistributions of source code must retain the above copyright
52f48f6960SAdrian Chadd  *    notice, this list of conditions and the following disclaimer.
53f48f6960SAdrian Chadd  *  * Redistributions in binary form must reproduce the above copyright
54f48f6960SAdrian Chadd  *    notice, this list of conditions and the following disclaimer in
55f48f6960SAdrian Chadd  *    the documentation and/or other materials provided with the
56f48f6960SAdrian Chadd  *    distribution.
57f48f6960SAdrian Chadd  *  * Neither the name Intel Corporation nor the names of its
58f48f6960SAdrian Chadd  *    contributors may be used to endorse or promote products derived
59f48f6960SAdrian Chadd  *    from this software without specific prior written permission.
60f48f6960SAdrian Chadd  *
61f48f6960SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
62f48f6960SAdrian Chadd  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
63f48f6960SAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
64f48f6960SAdrian Chadd  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
65f48f6960SAdrian Chadd  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
66f48f6960SAdrian Chadd  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
67f48f6960SAdrian Chadd  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
68f48f6960SAdrian Chadd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
69f48f6960SAdrian Chadd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
70f48f6960SAdrian Chadd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
71f48f6960SAdrian Chadd  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72f48f6960SAdrian Chadd  *
73f48f6960SAdrian Chadd  *****************************************************************************/
74f48f6960SAdrian Chadd 
75f48f6960SAdrian Chadd #include <sys/cdefs.h>
76f48f6960SAdrian Chadd #include "opt_wlan.h"
77f48f6960SAdrian Chadd #include "opt_iwm.h"
78f48f6960SAdrian Chadd 
79f48f6960SAdrian Chadd #include <sys/param.h>
80f48f6960SAdrian Chadd #include <sys/bus.h>
81f48f6960SAdrian Chadd #include <sys/conf.h>
82f48f6960SAdrian Chadd #include <sys/endian.h>
83f48f6960SAdrian Chadd #include <sys/firmware.h>
84f48f6960SAdrian Chadd #include <sys/kernel.h>
85f48f6960SAdrian Chadd #include <sys/malloc.h>
86f48f6960SAdrian Chadd #include <sys/mbuf.h>
87f48f6960SAdrian Chadd #include <sys/mutex.h>
88f48f6960SAdrian Chadd #include <sys/module.h>
89f48f6960SAdrian Chadd #include <sys/proc.h>
90f48f6960SAdrian Chadd #include <sys/rman.h>
91f48f6960SAdrian Chadd #include <sys/socket.h>
92f48f6960SAdrian Chadd #include <sys/sockio.h>
93f48f6960SAdrian Chadd #include <sys/sysctl.h>
94f48f6960SAdrian Chadd #include <sys/linker.h>
95f48f6960SAdrian Chadd 
96f48f6960SAdrian Chadd #include <machine/bus.h>
97f48f6960SAdrian Chadd #include <machine/endian.h>
98f48f6960SAdrian Chadd #include <machine/resource.h>
99f48f6960SAdrian Chadd 
100f48f6960SAdrian Chadd #include <dev/pci/pcivar.h>
101f48f6960SAdrian Chadd #include <dev/pci/pcireg.h>
102f48f6960SAdrian Chadd 
103f48f6960SAdrian Chadd #include <net/bpf.h>
104f48f6960SAdrian Chadd 
105f48f6960SAdrian Chadd #include <net/if.h>
106f48f6960SAdrian Chadd #include <net/if_var.h>
107f48f6960SAdrian Chadd #include <net/if_arp.h>
108f48f6960SAdrian Chadd #include <net/if_dl.h>
109f48f6960SAdrian Chadd #include <net/if_media.h>
110f48f6960SAdrian Chadd #include <net/if_types.h>
111f48f6960SAdrian Chadd 
112f48f6960SAdrian Chadd #include <netinet/in.h>
113f48f6960SAdrian Chadd #include <netinet/in_systm.h>
114f48f6960SAdrian Chadd #include <netinet/if_ether.h>
115f48f6960SAdrian Chadd #include <netinet/ip.h>
116f48f6960SAdrian Chadd 
117f48f6960SAdrian Chadd #include <net80211/ieee80211_var.h>
118f48f6960SAdrian Chadd #include <net80211/ieee80211_regdomain.h>
119f48f6960SAdrian Chadd #include <net80211/ieee80211_ratectl.h>
120f48f6960SAdrian Chadd #include <net80211/ieee80211_radiotap.h>
121f48f6960SAdrian Chadd 
122f48f6960SAdrian Chadd #include <dev/iwm/if_iwmreg.h>
123f48f6960SAdrian Chadd #include <dev/iwm/if_iwmvar.h>
124f48f6960SAdrian Chadd #include <dev/iwm/if_iwm_config.h>
125f48f6960SAdrian Chadd #include <dev/iwm/if_iwm_debug.h>
126f48f6960SAdrian Chadd #include <dev/iwm/if_iwm_constants.h>
127f48f6960SAdrian Chadd #include <dev/iwm/if_iwm_util.h>
128f48f6960SAdrian Chadd #include <dev/iwm/if_iwm_mac_ctxt.h>
129f48f6960SAdrian Chadd #include <dev/iwm/if_iwm_sta.h>
130f48f6960SAdrian Chadd 
131f48f6960SAdrian Chadd /*
132f48f6960SAdrian Chadd  * New version of ADD_STA_sta command added new fields at the end of the
133f48f6960SAdrian Chadd  * structure, so sending the size of the relevant API's structure is enough to
134f48f6960SAdrian Chadd  * support both API versions.
135f48f6960SAdrian Chadd  */
136f48f6960SAdrian Chadd static inline int
iwm_add_sta_cmd_size(struct iwm_softc * sc)137e7065dd1SMark Johnston iwm_add_sta_cmd_size(struct iwm_softc *sc)
138f48f6960SAdrian Chadd {
139e7065dd1SMark Johnston 	return sc->cfg->mqrx_supported ? sizeof(struct iwm_add_sta_cmd) :
140e7065dd1SMark Johnston 	    sizeof(struct iwm_add_sta_cmd_v7);
141f48f6960SAdrian Chadd }
142f48f6960SAdrian Chadd 
143f48f6960SAdrian Chadd /* send station add/update command to firmware */
144f48f6960SAdrian Chadd int
iwm_sta_send_to_fw(struct iwm_softc * sc,struct iwm_node * in,boolean_t update)145e7065dd1SMark Johnston iwm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in,
146f48f6960SAdrian Chadd 	boolean_t update)
147f48f6960SAdrian Chadd {
148f48f6960SAdrian Chadd 	struct iwm_vap *ivp = IWM_VAP(in->in_ni.ni_vap);
149e7065dd1SMark Johnston 	struct iwm_add_sta_cmd add_sta_cmd = {
150f48f6960SAdrian Chadd 		.sta_id = IWM_STATION_ID,
151f48f6960SAdrian Chadd 		.mac_id_n_color =
152f48f6960SAdrian Chadd 		    htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color)),
153f48f6960SAdrian Chadd 		.add_modify = update ? 1 : 0,
154f48f6960SAdrian Chadd 		.station_flags_msk = htole32(IWM_STA_FLG_FAT_EN_MSK |
155f48f6960SAdrian Chadd 					     IWM_STA_FLG_MIMO_EN_MSK),
156f48f6960SAdrian Chadd 		.tid_disable_tx = htole16(0xffff),
157f48f6960SAdrian Chadd 	};
158f48f6960SAdrian Chadd 	int ret;
159f48f6960SAdrian Chadd 	uint32_t status;
160f48f6960SAdrian Chadd 	uint32_t agg_size = 0, mpdu_dens = 0;
161f48f6960SAdrian Chadd 
162f48f6960SAdrian Chadd 	if (!update) {
163f48f6960SAdrian Chadd 		int ac;
164f48f6960SAdrian Chadd 		for (ac = 0; ac < WME_NUM_AC; ac++) {
165f48f6960SAdrian Chadd 			add_sta_cmd.tfd_queue_msk |=
166e7065dd1SMark Johnston 			    htole32(1 << iwm_ac_to_tx_fifo[ac]);
167f48f6960SAdrian Chadd 		}
168f48f6960SAdrian Chadd 		IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid);
169f48f6960SAdrian Chadd 	}
170f48f6960SAdrian Chadd 
171f48f6960SAdrian Chadd 	add_sta_cmd.station_flags |=
172f48f6960SAdrian Chadd 		htole32(agg_size << IWM_STA_FLG_MAX_AGG_SIZE_SHIFT);
173f48f6960SAdrian Chadd 	add_sta_cmd.station_flags |=
174f48f6960SAdrian Chadd 		htole32(mpdu_dens << IWM_STA_FLG_AGG_MPDU_DENS_SHIFT);
175f48f6960SAdrian Chadd 
176f48f6960SAdrian Chadd 	status = IWM_ADD_STA_SUCCESS;
177e7065dd1SMark Johnston 	ret = iwm_send_cmd_pdu_status(sc, IWM_ADD_STA,
178e7065dd1SMark Johnston 					  iwm_add_sta_cmd_size(sc),
179f48f6960SAdrian Chadd 					  &add_sta_cmd, &status);
180f48f6960SAdrian Chadd 	if (ret)
181f48f6960SAdrian Chadd 		return ret;
182f48f6960SAdrian Chadd 
183f48f6960SAdrian Chadd 	switch (status & IWM_ADD_STA_STATUS_MASK) {
184f48f6960SAdrian Chadd 	case IWM_ADD_STA_SUCCESS:
185f48f6960SAdrian Chadd 		IWM_DPRINTF(sc, IWM_DEBUG_NODE, "IWM_ADD_STA PASSED\n");
186f48f6960SAdrian Chadd 		break;
187f48f6960SAdrian Chadd 	default:
188f48f6960SAdrian Chadd 		ret = EIO;
189f48f6960SAdrian Chadd 		device_printf(sc->sc_dev, "IWM_ADD_STA failed\n");
190f48f6960SAdrian Chadd 		break;
191f48f6960SAdrian Chadd 	}
192f48f6960SAdrian Chadd 
193f48f6960SAdrian Chadd 	return ret;
194f48f6960SAdrian Chadd }
195f48f6960SAdrian Chadd 
196f48f6960SAdrian Chadd int
iwm_add_sta(struct iwm_softc * sc,struct iwm_node * in)197e7065dd1SMark Johnston iwm_add_sta(struct iwm_softc *sc, struct iwm_node *in)
198f48f6960SAdrian Chadd {
199e7065dd1SMark Johnston 	return iwm_sta_send_to_fw(sc, in, FALSE);
200f48f6960SAdrian Chadd }
201f48f6960SAdrian Chadd 
202f48f6960SAdrian Chadd int
iwm_update_sta(struct iwm_softc * sc,struct iwm_node * in)203e7065dd1SMark Johnston iwm_update_sta(struct iwm_softc *sc, struct iwm_node *in)
204f48f6960SAdrian Chadd {
205e7065dd1SMark Johnston 	return iwm_sta_send_to_fw(sc, in, TRUE);
206f48f6960SAdrian Chadd }
207f48f6960SAdrian Chadd 
208f48f6960SAdrian Chadd int
iwm_drain_sta(struct iwm_softc * sc,struct iwm_vap * ivp,boolean_t drain)209e7065dd1SMark Johnston iwm_drain_sta(struct iwm_softc *sc, struct iwm_vap *ivp, boolean_t drain)
210f48f6960SAdrian Chadd {
211e7065dd1SMark Johnston 	struct iwm_add_sta_cmd cmd = {};
212f48f6960SAdrian Chadd 	int ret;
213f48f6960SAdrian Chadd 	uint32_t status;
214f48f6960SAdrian Chadd 
215f48f6960SAdrian Chadd 	cmd.mac_id_n_color =
216f48f6960SAdrian Chadd 	    htole32(IWM_FW_CMD_ID_AND_COLOR(ivp->id, ivp->color));
217f48f6960SAdrian Chadd 	cmd.sta_id = IWM_STATION_ID;
218f48f6960SAdrian Chadd 	cmd.add_modify = IWM_STA_MODE_MODIFY;
219f48f6960SAdrian Chadd 	cmd.station_flags = drain ? htole32(IWM_STA_FLG_DRAIN_FLOW) : 0;
220f48f6960SAdrian Chadd 	cmd.station_flags_msk = htole32(IWM_STA_FLG_DRAIN_FLOW);
221f48f6960SAdrian Chadd 
222f48f6960SAdrian Chadd 	status = IWM_ADD_STA_SUCCESS;
223e7065dd1SMark Johnston 	ret = iwm_send_cmd_pdu_status(sc, IWM_ADD_STA,
224e7065dd1SMark Johnston 					  iwm_add_sta_cmd_size(sc),
225f48f6960SAdrian Chadd 					  &cmd, &status);
226f48f6960SAdrian Chadd 	if (ret)
227f48f6960SAdrian Chadd 		return ret;
228f48f6960SAdrian Chadd 
229f48f6960SAdrian Chadd 	switch (status & IWM_ADD_STA_STATUS_MASK) {
230f48f6960SAdrian Chadd 	case IWM_ADD_STA_SUCCESS:
231f48f6960SAdrian Chadd 		IWM_DPRINTF(sc, IWM_DEBUG_NODE,
232f48f6960SAdrian Chadd 		    "Frames for staid %d will drained in fw\n", IWM_STATION_ID);
233f48f6960SAdrian Chadd 		break;
234f48f6960SAdrian Chadd 	default:
235f48f6960SAdrian Chadd 		ret = EIO;
236f48f6960SAdrian Chadd 		device_printf(sc->sc_dev,
237f48f6960SAdrian Chadd 		    "Couldn't drain frames for staid %d\n", IWM_STATION_ID);
238f48f6960SAdrian Chadd 		break;
239f48f6960SAdrian Chadd 	}
240f48f6960SAdrian Chadd 
241f48f6960SAdrian Chadd 	return ret;
242f48f6960SAdrian Chadd }
243f48f6960SAdrian Chadd 
244f48f6960SAdrian Chadd /*
245f48f6960SAdrian Chadd  * Remove a station from the FW table. Before sending the command to remove
246f48f6960SAdrian Chadd  * the station validate that the station is indeed known to the driver (sanity
247f48f6960SAdrian Chadd  * only).
248f48f6960SAdrian Chadd  */
249f48f6960SAdrian Chadd static int
iwm_rm_sta_common(struct iwm_softc * sc)250e7065dd1SMark Johnston iwm_rm_sta_common(struct iwm_softc *sc)
251f48f6960SAdrian Chadd {
252e7065dd1SMark Johnston 	struct iwm_rm_sta_cmd rm_sta_cmd = {
253f48f6960SAdrian Chadd 		.sta_id = IWM_STATION_ID,
254f48f6960SAdrian Chadd 	};
255f48f6960SAdrian Chadd 	int ret;
256f48f6960SAdrian Chadd 
257e7065dd1SMark Johnston 	ret = iwm_send_cmd_pdu(sc, IWM_REMOVE_STA, 0,
258f48f6960SAdrian Chadd 				   sizeof(rm_sta_cmd), &rm_sta_cmd);
259f48f6960SAdrian Chadd 	if (ret) {
260f48f6960SAdrian Chadd 		device_printf(sc->sc_dev,
261f48f6960SAdrian Chadd 		    "Failed to remove station. Id=%d\n", IWM_STATION_ID);
262f48f6960SAdrian Chadd 		return ret;
263f48f6960SAdrian Chadd 	}
264f48f6960SAdrian Chadd 
265f48f6960SAdrian Chadd 	return 0;
266f48f6960SAdrian Chadd }
267f48f6960SAdrian Chadd 
268f48f6960SAdrian Chadd int
iwm_rm_sta(struct iwm_softc * sc,struct ieee80211vap * vap,boolean_t is_assoc)269e7065dd1SMark Johnston iwm_rm_sta(struct iwm_softc *sc, struct ieee80211vap *vap,
270c0487367SAdrian Chadd 	boolean_t is_assoc)
271f48f6960SAdrian Chadd {
272f48f6960SAdrian Chadd 	uint32_t tfd_queue_msk = 0;
273f48f6960SAdrian Chadd 	int ret;
274f48f6960SAdrian Chadd 	int ac;
275f48f6960SAdrian Chadd 
276e7065dd1SMark Johnston 	ret = iwm_drain_sta(sc, IWM_VAP(vap), TRUE);
277f48f6960SAdrian Chadd 	if (ret)
278f48f6960SAdrian Chadd 		return ret;
279f48f6960SAdrian Chadd 	for (ac = 0; ac < WME_NUM_AC; ac++) {
280e7065dd1SMark Johnston 		tfd_queue_msk |= htole32(1 << iwm_ac_to_tx_fifo[ac]);
281f48f6960SAdrian Chadd 	}
282e7065dd1SMark Johnston 	ret = iwm_flush_tx_path(sc, tfd_queue_msk, IWM_CMD_SYNC);
283f48f6960SAdrian Chadd 	if (ret)
284f48f6960SAdrian Chadd 		return ret;
285f48f6960SAdrian Chadd #ifdef notyet /* function not yet implemented */
286f48f6960SAdrian Chadd 	ret = iwl_trans_wait_tx_queue_empty(mvm->trans,
287f48f6960SAdrian Chadd 					    mvm_sta->tfd_queue_msk);
288f48f6960SAdrian Chadd 	if (ret)
289f48f6960SAdrian Chadd 		return ret;
290f48f6960SAdrian Chadd #endif
291e7065dd1SMark Johnston 	ret = iwm_drain_sta(sc, IWM_VAP(vap), FALSE);
292f48f6960SAdrian Chadd 
293f48f6960SAdrian Chadd 	/* if we are associated - we can't remove the AP STA now */
294c0487367SAdrian Chadd 	if (is_assoc)
295f48f6960SAdrian Chadd 		return ret;
296c0487367SAdrian Chadd 
297f48f6960SAdrian Chadd 	/* XXX wait until STA is drained */
298f48f6960SAdrian Chadd 
299e7065dd1SMark Johnston 	ret = iwm_rm_sta_common(sc);
300f48f6960SAdrian Chadd 
301f48f6960SAdrian Chadd 	return ret;
302f48f6960SAdrian Chadd }
303f48f6960SAdrian Chadd 
304c0487367SAdrian Chadd int
iwm_rm_sta_id(struct iwm_softc * sc,struct ieee80211vap * vap)305e7065dd1SMark Johnston iwm_rm_sta_id(struct iwm_softc *sc, struct ieee80211vap *vap)
306c0487367SAdrian Chadd {
307c0487367SAdrian Chadd 	/* XXX wait until STA is drained */
308c0487367SAdrian Chadd 
309e7065dd1SMark Johnston 	return iwm_rm_sta_common(sc);
310c0487367SAdrian Chadd }
311c0487367SAdrian Chadd 
312f48f6960SAdrian Chadd static int
iwm_add_int_sta_common(struct iwm_softc * sc,struct iwm_int_sta * sta,const uint8_t * addr,uint16_t mac_id,uint16_t color)313e7065dd1SMark Johnston iwm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta,
314f48f6960SAdrian Chadd     const uint8_t *addr, uint16_t mac_id, uint16_t color)
315f48f6960SAdrian Chadd {
316e7065dd1SMark Johnston 	struct iwm_add_sta_cmd cmd;
317f48f6960SAdrian Chadd 	int ret;
318f48f6960SAdrian Chadd 	uint32_t status;
319f48f6960SAdrian Chadd 
320f48f6960SAdrian Chadd 	memset(&cmd, 0, sizeof(cmd));
321f48f6960SAdrian Chadd 	cmd.sta_id = sta->sta_id;
322f48f6960SAdrian Chadd 	cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(mac_id, color));
32309a07cd5SMark Johnston 	if (sta->sta_id == IWM_AUX_STA_ID && sc->cfg->mqrx_supported)
32409a07cd5SMark Johnston 		cmd.station_type = IWM_STA_AUX_ACTIVITY;
325f48f6960SAdrian Chadd 
326f48f6960SAdrian Chadd 	cmd.tfd_queue_msk = htole32(sta->tfd_queue_msk);
327f48f6960SAdrian Chadd 	cmd.tid_disable_tx = htole16(0xffff);
328f48f6960SAdrian Chadd 
329f48f6960SAdrian Chadd 	if (addr)
330f48f6960SAdrian Chadd 		IEEE80211_ADDR_COPY(cmd.addr, addr);
331f48f6960SAdrian Chadd 
332e7065dd1SMark Johnston 	ret = iwm_send_cmd_pdu_status(sc, IWM_ADD_STA,
333e7065dd1SMark Johnston 					  iwm_add_sta_cmd_size(sc),
334f48f6960SAdrian Chadd 					  &cmd, &status);
335f48f6960SAdrian Chadd 	if (ret)
336f48f6960SAdrian Chadd 		return ret;
337f48f6960SAdrian Chadd 
338f48f6960SAdrian Chadd 	switch (status & IWM_ADD_STA_STATUS_MASK) {
339f48f6960SAdrian Chadd 	case IWM_ADD_STA_SUCCESS:
340f48f6960SAdrian Chadd 		IWM_DPRINTF(sc, IWM_DEBUG_NODE, "Internal station added.\n");
341f48f6960SAdrian Chadd 		return 0;
342f48f6960SAdrian Chadd 	default:
343f48f6960SAdrian Chadd 		ret = EIO;
344f48f6960SAdrian Chadd 		device_printf(sc->sc_dev,
345f48f6960SAdrian Chadd 		    "Add internal station failed, status=0x%x\n", status);
346f48f6960SAdrian Chadd 		break;
347f48f6960SAdrian Chadd 	}
348f48f6960SAdrian Chadd 	return ret;
349f48f6960SAdrian Chadd }
350f48f6960SAdrian Chadd 
351f48f6960SAdrian Chadd int
iwm_add_aux_sta(struct iwm_softc * sc)352e7065dd1SMark Johnston iwm_add_aux_sta(struct iwm_softc *sc)
353f48f6960SAdrian Chadd {
354f48f6960SAdrian Chadd 	int ret;
355f48f6960SAdrian Chadd 
356f48f6960SAdrian Chadd 	sc->sc_aux_sta.sta_id = IWM_AUX_STA_ID;
357e7065dd1SMark Johnston 	sc->sc_aux_sta.tfd_queue_msk = (1 << IWM_AUX_QUEUE);
358f48f6960SAdrian Chadd 
359f48f6960SAdrian Chadd 	/* Map Aux queue to fifo - needs to happen before adding Aux station */
360e7065dd1SMark Johnston 	ret = iwm_enable_txq(sc, IWM_AUX_STA_ID, IWM_AUX_QUEUE,
361e7065dd1SMark Johnston 	    IWM_TX_FIFO_MCAST);
362f48f6960SAdrian Chadd 	if (ret)
363f48f6960SAdrian Chadd 		return ret;
364f48f6960SAdrian Chadd 
365e7065dd1SMark Johnston 	ret = iwm_add_int_sta_common(sc, &sc->sc_aux_sta, NULL,
366f48f6960SAdrian Chadd 					 IWM_MAC_INDEX_AUX, 0);
367f48f6960SAdrian Chadd 
368f48f6960SAdrian Chadd 	if (ret) {
369f48f6960SAdrian Chadd 		memset(&sc->sc_aux_sta, 0, sizeof(sc->sc_aux_sta));
370e7065dd1SMark Johnston 		sc->sc_aux_sta.sta_id = IWM_STATION_COUNT;
371f48f6960SAdrian Chadd 	}
372f48f6960SAdrian Chadd 	return ret;
373f48f6960SAdrian Chadd }
374f48f6960SAdrian Chadd 
iwm_del_aux_sta(struct iwm_softc * sc)375e7065dd1SMark Johnston void iwm_del_aux_sta(struct iwm_softc *sc)
376f48f6960SAdrian Chadd {
377f48f6960SAdrian Chadd 	memset(&sc->sc_aux_sta, 0, sizeof(sc->sc_aux_sta));
378e7065dd1SMark Johnston 	sc->sc_aux_sta.sta_id = IWM_STATION_COUNT;
379f48f6960SAdrian Chadd }
380