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