The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/rtwn/if_rtwn_tx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: d45499ec887f44c76b0909a5b00c7f6e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.