]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/rtwn/if_rtwn_tx.c
zfs: merge openzfs/zfs@ec64fdb93 (master) into main
[FreeBSD/FreeBSD.git] / sys / dev / rtwn / if_rtwn_tx.c
1 /*      $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $   */
2
3 /*-
4  * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
5  * Copyright (c) 2014 Kevin Lo <kevlo@FreeBSD.org>
6  * Copyright (c) 2015-2016 Andriy Voskoboinyk <avos@FreeBSD.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
23
24 #include "opt_wlan.h"
25
26 #include <sys/param.h>
27 #include <sys/lock.h>
28 #include <sys/mutex.h>
29 #include <sys/mbuf.h>
30 #include <sys/kernel.h>
31 #include <sys/socket.h>
32 #include <sys/systm.h>
33 #include <sys/malloc.h>
34 #include <sys/queue.h>
35 #include <sys/taskqueue.h>
36 #include <sys/bus.h>
37 #include <sys/endian.h>
38
39 #include <net/if.h>
40 #include <net/if_var.h>
41 #include <net/ethernet.h>
42 #include <net/if_media.h>
43
44 #include <net80211/ieee80211_var.h>
45 #include <net80211/ieee80211_radiotap.h>
46 #include <net80211/ieee80211_ratectl.h>
47 #ifdef  IEEE80211_SUPPORT_SUPERG
48 #include <net80211/ieee80211_superg.h>
49 #endif
50
51 #include <dev/rtwn/if_rtwnreg.h>
52 #include <dev/rtwn/if_rtwnvar.h>
53
54 #include <dev/rtwn/if_rtwn_beacon.h>
55 #include <dev/rtwn/if_rtwn_debug.h>
56 #include <dev/rtwn/if_rtwn_ridx.h>
57 #include <dev/rtwn/if_rtwn_tx.h>
58
59 void
60 rtwn_drain_mbufq(struct rtwn_softc *sc)
61 {
62         struct mbuf *m;
63         struct ieee80211_node *ni;
64         RTWN_ASSERT_LOCKED(sc);
65         while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
66                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
67                 m->m_pkthdr.rcvif = NULL;
68                 ieee80211_free_node(ni);
69                 m_freem(m);
70         }
71 }
72
73 #ifdef IEEE80211_SUPPORT_SUPERG
74 void
75 rtwn_ff_flush_all(struct rtwn_softc *sc, union sec_param *data)
76 {
77         struct ieee80211com *ic = &sc->sc_ic;
78
79         RTWN_UNLOCK(sc);
80         ieee80211_ff_flush_all(ic);
81         RTWN_LOCK(sc);
82 }
83 #endif
84
85 static uint8_t
86 rtwn_get_cipher(u_int ic_cipher)
87 {
88         uint8_t cipher;
89
90         switch (ic_cipher) {
91         case IEEE80211_CIPHER_NONE:
92                 cipher = RTWN_TXDW1_CIPHER_NONE;
93                 break;
94         case IEEE80211_CIPHER_WEP:
95         case IEEE80211_CIPHER_TKIP:
96                 cipher = RTWN_TXDW1_CIPHER_RC4;
97                 break;
98         case IEEE80211_CIPHER_AES_CCM:
99                 cipher = RTWN_TXDW1_CIPHER_AES;
100                 break;
101         default:
102                 KASSERT(0, ("%s: unknown cipher %d\n", __func__,
103                     ic_cipher));
104                 return (RTWN_TXDW1_CIPHER_SM4);
105         }
106
107         return (cipher);
108 }
109
110 static int
111 rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni,
112     struct mbuf *m)
113 {
114         const struct ieee80211_txparam *tp = ni->ni_txparms;
115         struct ieee80211com *ic = &sc->sc_ic;
116         struct ieee80211vap *vap = ni->ni_vap;
117         struct ieee80211_key *k = NULL;
118         struct ieee80211_frame *wh;
119         struct rtwn_tx_desc_common *txd;
120         struct rtwn_tx_buf buf;
121         uint8_t rate, ridx, type;
122         u_int cipher;
123         int ismcast;
124
125         RTWN_ASSERT_LOCKED(sc);
126
127         wh = mtod(m, struct ieee80211_frame *);
128         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
129         ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
130
131         /* Choose a TX rate index. */
132         if (type == IEEE80211_FC0_TYPE_MGT ||
133             type == IEEE80211_FC0_TYPE_CTL ||
134             (m->m_flags & M_EAPOL) != 0)
135                 rate = tp->mgmtrate;
136         else if (ismcast)
137                 rate = tp->mcastrate;
138         else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
139                 rate = tp->ucastrate;
140         else {
141                 if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
142                         /* XXX pass pktlen */
143                         (void) ieee80211_ratectl_rate(ni, NULL, 0);
144                         rate = ni->ni_txrate;
145                 } else {
146                         if (ni->ni_flags & IEEE80211_NODE_HT)
147                                 rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */
148                         else if (ic->ic_curmode != IEEE80211_MODE_11B)
149                                 rate = ridx2rate[RTWN_RIDX_OFDM36];
150                         else
151                                 rate = ridx2rate[RTWN_RIDX_CCK55];
152                 }
153         }
154
155         ridx = rate2ridx(rate);
156
157         cipher = IEEE80211_CIPHER_NONE;
158         if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
159                 k = ieee80211_crypto_encap(ni, m);
160                 if (k == NULL) {
161                         device_printf(sc->sc_dev,
162                             "ieee80211_crypto_encap returns NULL.\n");
163                         return (ENOBUFS);
164                 }
165                 if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
166                         cipher = k->wk_cipher->ic_cipher;
167
168                 /* in case packet header moved, reset pointer */
169                 wh = mtod(m, struct ieee80211_frame *);
170         }
171
172         /* Fill Tx descriptor. */
173         txd = (struct rtwn_tx_desc_common *)&buf;
174         memset(txd, 0, sc->txdesc_len);
175         txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
176
177         rtwn_fill_tx_desc(sc, ni, m, txd, ridx, tp->maxretry);
178
179         if (ieee80211_radiotap_active_vap(vap)) {
180                 struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
181
182                 tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
183                 if (k != NULL)
184                         tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
185                 ieee80211_radiotap_tx(vap, m);
186         }
187
188         return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
189 }
190
191 static int
192 rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
193     struct mbuf *m, const struct ieee80211_bpf_params *params)
194 {
195         struct ieee80211vap *vap = ni->ni_vap;
196         struct ieee80211_key *k = NULL;
197         struct ieee80211_frame *wh;
198         struct rtwn_tx_desc_common *txd;
199         struct rtwn_tx_buf buf;
200         uint8_t type;
201         u_int cipher;
202
203         /* Encrypt the frame if need be. */
204         cipher = IEEE80211_CIPHER_NONE;
205         if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
206                 /* Retrieve key for TX. */
207                 k = ieee80211_crypto_encap(ni, m);
208                 if (k == NULL) {
209                         device_printf(sc->sc_dev,
210                             "ieee80211_crypto_encap returns NULL.\n");
211                         return (ENOBUFS);
212                 }
213                 if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
214                         cipher = k->wk_cipher->ic_cipher;
215         }
216
217         wh = mtod(m, struct ieee80211_frame *);
218         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
219
220         /* Fill Tx descriptor. */
221         txd = (struct rtwn_tx_desc_common *)&buf;
222         memset(txd, 0, sc->txdesc_len);
223         txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
224
225         rtwn_fill_tx_desc_raw(sc, ni, m, txd, params);
226
227         if (ieee80211_radiotap_active_vap(vap)) {
228                 struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
229
230                 tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
231                 if (k != NULL)
232                         tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
233                 ieee80211_radiotap_tx(vap, m);
234         }
235
236         return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
237 }
238
239 int
240 rtwn_transmit(struct ieee80211com *ic, struct mbuf *m)
241 {
242         struct rtwn_softc *sc = ic->ic_softc;
243         int error;
244
245         RTWN_LOCK(sc);
246         if ((sc->sc_flags & RTWN_RUNNING) == 0) {
247                 RTWN_UNLOCK(sc);
248                 return (ENXIO);
249         }
250         error = mbufq_enqueue(&sc->sc_snd, m);
251         if (error) {
252                 RTWN_UNLOCK(sc);
253                 return (error);
254         }
255         rtwn_start(sc);
256         RTWN_UNLOCK(sc);
257
258         return (0);
259 }
260
261 void
262 rtwn_start(struct rtwn_softc *sc)
263 {
264         struct ieee80211_node *ni;
265         struct mbuf *m;
266
267         RTWN_ASSERT_LOCKED(sc);
268         while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
269                 if (sc->qfullmsk != 0) {
270                         mbufq_prepend(&sc->sc_snd, m);
271                         break;
272                 }
273                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
274                 m->m_pkthdr.rcvif = NULL;
275
276                 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
277                     "%s: called; m %p, ni %p\n", __func__, m, ni);
278
279                 if (rtwn_tx_data(sc, ni, m) != 0) {
280                         if_inc_counter(ni->ni_vap->iv_ifp,
281                             IFCOUNTER_OERRORS, 1);
282                         m_freem(m);
283 #ifdef D4054
284                         ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0);
285 #endif
286                         ieee80211_free_node(ni);
287                         break;
288                 }
289         }
290 }
291
292 int
293 rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
294     const struct ieee80211_bpf_params *params)
295 {
296         struct ieee80211com *ic = ni->ni_ic;
297         struct rtwn_softc *sc = ic->ic_softc;
298         int error;
299
300         RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n",
301             __func__, m, ni);
302
303         /* prevent management frames from being sent if we're not ready */
304         RTWN_LOCK(sc);
305         if (!(sc->sc_flags & RTWN_RUNNING)) {
306                 error = ENETDOWN;
307                 goto end;
308         }
309
310         if (sc->qfullmsk != 0) {
311                 error = ENOBUFS;
312                 goto end;
313         }
314
315         if (params == NULL) {
316                 /*
317                  * Legacy path; interpret frame contents to decide
318                  * precisely how to send the frame.
319                  */
320                 error = rtwn_tx_data(sc, ni, m);
321         } else {
322                 /*
323                  * Caller supplied explicit parameters to use in
324                  * sending the frame.
325                  */
326                 error = rtwn_tx_raw(sc, ni, m, params);
327         }
328
329 end:
330         if (error != 0) {
331                 if (m->m_flags & M_TXCB)
332                         ieee80211_process_callback(ni, m, 1);
333                 m_freem(m);
334         }
335
336         RTWN_UNLOCK(sc);
337
338         return (error);
339 }