]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/rtwn/if_rtwn_tx.c
Update compiler-rt to release_39 branch r288513. Since this contains a
[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
60 void
61 rtwn_drain_mbufq(struct rtwn_softc *sc)
62 {
63         struct mbuf *m;
64         struct ieee80211_node *ni;
65         RTWN_ASSERT_LOCKED(sc);
66         while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
67                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
68                 m->m_pkthdr.rcvif = NULL;
69                 ieee80211_free_node(ni);
70                 m_freem(m);
71         }
72 }
73
74 #ifdef IEEE80211_SUPPORT_SUPERG
75 void
76 rtwn_ff_flush_all(struct rtwn_softc *sc, union sec_param *data)
77 {
78         struct ieee80211com *ic = &sc->sc_ic;
79
80         RTWN_UNLOCK(sc);
81         ieee80211_ff_flush_all(ic);
82         RTWN_LOCK(sc);
83 }
84 #endif
85
86 static uint8_t
87 rtwn_get_cipher(u_int ic_cipher)
88 {
89         uint8_t cipher;
90
91         switch (ic_cipher) {
92         case IEEE80211_CIPHER_NONE:
93                 cipher = RTWN_TXDW1_CIPHER_NONE;
94                 break;
95         case IEEE80211_CIPHER_WEP:
96         case IEEE80211_CIPHER_TKIP:
97                 cipher = RTWN_TXDW1_CIPHER_RC4;
98                 break;
99         case IEEE80211_CIPHER_AES_CCM:
100                 cipher = RTWN_TXDW1_CIPHER_AES;
101                 break;
102         default:
103                 KASSERT(0, ("%s: unknown cipher %d\n", __func__,
104                     ic_cipher));
105                 return (RTWN_TXDW1_CIPHER_SM4);
106         }
107
108         return (cipher);
109 }
110
111 static int
112 rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni,
113     struct mbuf *m)
114 {
115         const struct ieee80211_txparam *tp;
116         struct ieee80211com *ic = &sc->sc_ic;
117         struct ieee80211vap *vap = ni->ni_vap;
118         struct ieee80211_key *k = NULL;
119         struct ieee80211_channel *chan;
120         struct ieee80211_frame *wh;
121         struct rtwn_tx_desc_common *txd;
122         struct rtwn_tx_buf buf;
123         uint8_t rate, ridx, type;
124         u_int cipher;
125         int ismcast, maxretry;
126
127         RTWN_ASSERT_LOCKED(sc);
128
129         wh = mtod(m, struct ieee80211_frame *);
130         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
131         ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
132
133         chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ?
134                 ni->ni_chan : ic->ic_curchan;
135         tp = &vap->iv_txparms[ieee80211_chan2mode(chan)];
136         maxretry = tp->maxretry;
137
138         /* Choose a TX rate index. */
139         if (type == IEEE80211_FC0_TYPE_MGT)
140                 rate = tp->mgmtrate;
141         else if (ismcast)
142                 rate = tp->mcastrate;
143         else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
144                 rate = tp->ucastrate;
145         else if (m->m_flags & M_EAPOL)
146                 rate = tp->mgmtrate;
147         else {
148                 if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
149                         /* XXX pass pktlen */
150                         (void) ieee80211_ratectl_rate(ni, NULL, 0);
151                         rate = ni->ni_txrate;
152                 } else {
153                         if (ni->ni_flags & IEEE80211_NODE_HT)
154                                 rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */
155                         else if (ic->ic_curmode != IEEE80211_MODE_11B)
156                                 rate = ridx2rate[RTWN_RIDX_OFDM36];
157                         else
158                                 rate = ridx2rate[RTWN_RIDX_CCK55];
159                 }
160         }
161
162         ridx = rate2ridx(rate);
163
164         cipher = IEEE80211_CIPHER_NONE;
165         if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
166                 k = ieee80211_crypto_encap(ni, m);
167                 if (k == NULL) {
168                         device_printf(sc->sc_dev,
169                             "ieee80211_crypto_encap returns NULL.\n");
170                         return (ENOBUFS);
171                 }
172                 if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
173                         cipher = k->wk_cipher->ic_cipher;
174
175                 /* in case packet header moved, reset pointer */
176                 wh = mtod(m, struct ieee80211_frame *);
177         }
178
179         /* Fill Tx descriptor. */
180         txd = (struct rtwn_tx_desc_common *)&buf;
181         memset(txd, 0, sc->txdesc_len);
182         txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
183
184         rtwn_fill_tx_desc(sc, ni, m, txd, ridx, maxretry);
185
186         if (ieee80211_radiotap_active_vap(vap)) {
187                 struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
188
189                 tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
190                 if (k != NULL)
191                         tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
192                 ieee80211_radiotap_tx(vap, m);
193         }
194
195         return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
196 }
197
198 static int
199 rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni,
200     struct mbuf *m, const struct ieee80211_bpf_params *params)
201 {
202         struct ieee80211vap *vap = ni->ni_vap;
203         struct ieee80211_key *k = NULL;
204         struct ieee80211_frame *wh;
205         struct rtwn_tx_desc_common *txd;
206         struct rtwn_tx_buf buf;
207         uint8_t type;
208         u_int cipher;
209
210         /* Encrypt the frame if need be. */
211         cipher = IEEE80211_CIPHER_NONE;
212         if (params->ibp_flags & IEEE80211_BPF_CRYPTO) {
213                 /* Retrieve key for TX. */
214                 k = ieee80211_crypto_encap(ni, m);
215                 if (k == NULL) {
216                         device_printf(sc->sc_dev,
217                             "ieee80211_crypto_encap returns NULL.\n");
218                         return (ENOBUFS);
219                 }
220                 if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT))
221                         cipher = k->wk_cipher->ic_cipher;
222         }
223
224         wh = mtod(m, struct ieee80211_frame *);
225         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
226
227         /* Fill Tx descriptor. */
228         txd = (struct rtwn_tx_desc_common *)&buf;
229         memset(txd, 0, sc->txdesc_len);
230         txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher)));
231
232         rtwn_fill_tx_desc_raw(sc, ni, m, txd, params);
233
234         if (ieee80211_radiotap_active_vap(vap)) {
235                 struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap;
236
237                 tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd);
238                 if (k != NULL)
239                         tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
240                 ieee80211_radiotap_tx(vap, m);
241         }
242
243         return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0));
244 }
245
246 int
247 rtwn_transmit(struct ieee80211com *ic, struct mbuf *m)
248 {
249         struct rtwn_softc *sc = ic->ic_softc;
250         int error;
251
252         RTWN_LOCK(sc);
253         if ((sc->sc_flags & RTWN_RUNNING) == 0) {
254                 RTWN_UNLOCK(sc);
255                 return (ENXIO);
256         }
257         error = mbufq_enqueue(&sc->sc_snd, m);
258         if (error) {
259                 RTWN_UNLOCK(sc);
260                 return (error);
261         }
262         rtwn_start(sc);
263         RTWN_UNLOCK(sc);
264
265         return (0);
266 }
267
268 void
269 rtwn_start(struct rtwn_softc *sc)
270 {
271         struct ieee80211_node *ni;
272         struct mbuf *m;
273
274         RTWN_ASSERT_LOCKED(sc);
275         while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
276                 if (sc->qfullmsk != 0) {
277                         mbufq_prepend(&sc->sc_snd, m);
278                         break;
279                 }
280                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
281                 m->m_pkthdr.rcvif = NULL;
282
283                 RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT,
284                     "%s: called; m %p, ni %p\n", __func__, m, ni);
285
286                 if (rtwn_tx_data(sc, ni, m) != 0) {
287                         if_inc_counter(ni->ni_vap->iv_ifp,
288                             IFCOUNTER_OERRORS, 1);
289                         m_freem(m);
290 #ifdef D4054
291                         ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0);
292 #endif
293                         ieee80211_free_node(ni);
294                         break;
295                 }
296         }
297 }
298
299 int
300 rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
301     const struct ieee80211_bpf_params *params)
302 {
303         struct ieee80211com *ic = ni->ni_ic;
304         struct rtwn_softc *sc = ic->ic_softc;
305         int error;
306
307         RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n",
308             __func__, m, ni);
309
310         /* prevent management frames from being sent if we're not ready */
311         RTWN_LOCK(sc);
312         if (!(sc->sc_flags & RTWN_RUNNING)) {
313                 error = ENETDOWN;
314                 goto end;
315         }
316
317         if (sc->qfullmsk != 0) {
318                 error = ENOBUFS;
319                 goto end;
320         }
321
322         if (params == NULL) {
323                 /*
324                  * Legacy path; interpret frame contents to decide
325                  * precisely how to send the frame.
326                  */
327                 error = rtwn_tx_data(sc, ni, m);
328         } else {
329                 /*
330                  * Caller supplied explicit parameters to use in
331                  * sending the frame.
332                  */
333                 error = rtwn_tx_raw(sc, ni, m, params);
334         }
335
336 end:
337         if (error != 0) {
338                 if (m->m_flags & M_TXCB)
339                         ieee80211_process_callback(ni, m, 1);
340                 m_freem(m);
341         }
342
343         RTWN_UNLOCK(sc);
344
345         return (error);
346 }