Diff for /wikisrc/Converting_drivers_to_the_new_wifi_stack.mdwn between versions 1.1 and 1.2

version 1.1, 2020/09/29 17:51:24 version 1.2, 2020/09/29 18:06:34
Line 87  reflects on the driver and causes most o Line 87  reflects on the driver and causes most o
    use it mostly verbatim. Rename it to ``driver_get_radiocaps`` and     use it mostly verbatim. Rename it to ``driver_get_radiocaps`` and
    make it look like:     make it look like:
   
       ```
     static void      static void
     urtwn_get_radiocaps(struct ieee80211com *ic,      urtwn_get_radiocaps(struct ieee80211com *ic,
         int maxchans, int *nchans, struct ieee80211_channel chans[])          int maxchans, int *nchans, struct ieee80211_channel chans[])
Line 99  reflects on the driver and causes most o Line 100  reflects on the driver and causes most o
         setbit(bands, IEEE80211_MODE_11NG);          setbit(bands, IEEE80211_MODE_11NG);
         ieee80211_add_channels_default_2ghz(chans, maxchans, nchans, bands, 0);          ieee80211_add_channels_default_2ghz(chans, maxchans, nchans, bands, 0);
     }      }
       ```
   
    and also assign this function to ``ic->ic_getradiocaps`` in     and also assign this function to ``ic->ic_getradiocaps`` in
    the attach function.     the attach function.
Line 107  reflects on the driver and causes most o Line 109  reflects on the driver and causes most o
    You can just call the ``driver_get_radiocaps()`` function during     You can just call the ``driver_get_radiocaps()`` function during
    attach like:     attach like:
   
      urtwn_get_radiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,         ```
           ic->ic_channels);      urtwn_get_radiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,   
      ieee80211_ifattach(ic);           ic->ic_channels);
      [..]      ieee80211_ifattach(ic);
      ic->ic_getradiocaps = urtwn_get_radiocaps;      [..]
       ic->ic_getradiocaps = urtwn_get_radiocaps;
       ```
   
  * If your driver used to override state machine functions (typical   * If your driver used to override state machine functions (typical
    ``newstate`` to controll LEDs when associating or similar),     ``newstate`` to controll LEDs when associating or similar),
Line 128  reflects on the driver and causes most o Line 132  reflects on the driver and causes most o
  * Many functions will get a ``struct ieee80211vap *vap`` passed instead   * Many functions will get a ``struct ieee80211vap *vap`` passed instead
    of a softc. A typical change to adapt for that looks like:     of a softc. A typical change to adapt for that looks like:
   
       ```
     -       struct ieee80211com *ic = &sc->sc_ic;      -       struct ieee80211com *ic = &sc->sc_ic;
     -       struct ieee80211_node *ni = ic->ic_bss;      -       struct ieee80211_node *ni = ic->ic_bss;
     +       struct ieee80211com *ic = vap->iv_ic;      +       struct ieee80211com *ic = vap->iv_ic;
     +       struct rtwn_softc *sc = ic->ic_softc;      +       struct rtwn_softc *sc = ic->ic_softc;
     +       struct ieee80211_node *ni = vap->iv_bss;      +       struct ieee80211_node *ni = vap->iv_bss;
       ```
   
  * The hardware driver will need a global new outgoing packet queue   * The hardware driver will need a global new outgoing packet queue
    (as the per-interface queues are attached to VAPs, not the single     (as the per-interface queues are attached to VAPs, not the single
Line 146  reflects on the driver and causes most o Line 152  reflects on the driver and causes most o
   
    This queue needs initialization in the attach function, like:     This queue needs initialization in the attach function, like:
   
       ```
     sc->sc_sendq.ifq_maxlen = ifqmaxlen;      sc->sc_sendq.ifq_maxlen = ifqmaxlen;
     IFQ_LOCK_INIT(&sc->sc_sendq);      IFQ_LOCK_INIT(&sc->sc_sendq);
       ```
   
    This device private send queue (writer: any of the current VAPs     This device private send queue (writer: any of the current VAPs
    of this interface, consumer: the devices transmit interrupt handler)     of this interface, consumer: the devices transmit interrupt handler)
Line 167  reflects on the driver and causes most o Line 175  reflects on the driver and causes most o
    and ``sc->nrxchains`` or similar variables. This information     and ``sc->nrxchains`` or similar variables. This information
    needs to be propagated to the common radio structure:     needs to be propagated to the common radio structure:
   
       ```
     ic->ic_txstream = sc->ntxchains;      ic->ic_txstream = sc->ntxchains;
     ic->ic_rxstream = sc->nrxchains;      ic->ic_rxstream = sc->nrxchains;
       ```
   
    Same for interface flags:     Same for interface flags:
   
Line 178  reflects on the driver and causes most o Line 188  reflects on the driver and causes most o
    need to be overwritten. The functions needed are explained     need to be overwritten. The functions needed are explained
    below, here is a typical setup:     below, here is a typical setup:
   
       ```
     /* override default methods */      /* override default methods */
     ic->ic_newassoc = urtwn_newassoc;      ic->ic_newassoc = urtwn_newassoc;
     ic->ic_wme.wme_update = urtwn_wme_update;      ic->ic_wme.wme_update = urtwn_wme_update;
Line 189  reflects on the driver and causes most o Line 200  reflects on the driver and causes most o
     ic->ic_set_channel = urtwn_set_channel;      ic->ic_set_channel = urtwn_set_channel;
     ic->ic_transmit = urtwn_transmit;      ic->ic_transmit = urtwn_transmit;
     ic->ic_raw_xmit = urtwn_raw_xmit;      ic->ic_raw_xmit = urtwn_raw_xmit;
       ```
   
   
  * detach does not deal with any interfaces any more, remove all traces   * detach does not deal with any interfaces any more, remove all traces
Line 197  reflects on the driver and causes most o Line 209  reflects on the driver and causes most o
  * Add a new function for VAP creation and move all interface specific   * Add a new function for VAP creation and move all interface specific
    setup there. It looks like:     setup there. It looks like:
   
       ```
     static struct ieee80211vap *      static struct ieee80211vap *
     urtwn_vap_create(struct ieee80211com *ic,  const char name[IFNAMSIZ],      urtwn_vap_create(struct ieee80211com *ic,  const char name[IFNAMSIZ],
         int  unit, enum ieee80211_opmode opmode, int flags,          int  unit, enum ieee80211_opmode opmode, int flags,
Line 209  reflects on the driver and causes most o Line 222  reflects on the driver and causes most o
     ...      ...
            return vap;             return vap;
     }      }
       ```
   
    It allocates a new VAP with ``kmem_zalloc`` initializes it     It allocates a new VAP with ``kmem_zalloc`` initializes it
    by calling ``ieee80211_vap_setup`` for it and then ovverriding whatever     by calling ``ieee80211_vap_setup`` for it and then ovverriding whatever
Line 219  reflects on the driver and causes most o Line 233  reflects on the driver and causes most o
    (that probably means: for all devices that are not on USB)     (that probably means: for all devices that are not on USB)
    you need to initialize the per CPU interface queue:     you need to initialize the per CPU interface queue:
   
       ```
     /* Use common softint-based if_input */      /* Use common softint-based if_input */
     ifp->if_percpuq = if_percpuq_create(ifp);      ifp->if_percpuq = if_percpuq_create(ifp);
       ```
   
    If your interrupt handler always is called in softint context,     If your interrupt handler always is called in softint context,
    do not do this. If if_percpuq is NULL the wifi framework will     do not do this. If if_percpuq is NULL the wifi framework will
Line 231  reflects on the driver and causes most o Line 247  reflects on the driver and causes most o
    parts that you deleted in the detach() function here. A very     parts that you deleted in the detach() function here. A very
    minimalistic example looks like:     minimalistic example looks like:
   
       ```
     static void      static void
     urtwn_vap_delete(struct ieee80211vap *vap)      urtwn_vap_delete(struct ieee80211vap *vap)
     {      {
Line 241  reflects on the driver and causes most o Line 258  reflects on the driver and causes most o
         ieee80211_vap_detach(vap);          ieee80211_vap_detach(vap);
         kmem_free(vap, sizeof(struct ieee80211vap));          kmem_free(vap, sizeof(struct ieee80211vap));
     }      }
       ```
   
  * Rate Adaption happens per VAP, so the ra_init call changes like this:   * Rate Adaption happens per VAP, so the ra_init call changes like this:
   
       ```
     -static int urtwn_ra_init(struct urtwn_softc *);      -static int urtwn_ra_init(struct urtwn_softc *);
     +static int urtwn_ra_init(struct ieee80211vap );      +static int urtwn_ra_init(struct ieee80211vap );
       ```
   
    See above for recipes how to acces the needed structs in there.     See above for recipes how to acces the needed structs in there.
   
  * State is per VAP, so newstate changes the first parameter:   * State is per VAP, so newstate changes the first parameter:
   
       ```
     -static int urtwn_newstate(struct ieee80211com *, enum ieee80211_state, int);      -static int urtwn_newstate(struct ieee80211com *, enum ieee80211_state, int);
     +static int urtwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);      +static int urtwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
       ```
   
    If there was a newstate_cb function previously, it is probably not needed     If there was a newstate_cb function previously, it is probably not needed
    any more.     any more.
   
  * Reset is per interface, so per VAP:   * Reset is per interface, so per VAP:
   
       ```
     -static int urtwn_reset(struct ifnet *);      -static int urtwn_reset(struct ifnet *);
     +static int urtwn_reset(struct ieee80211vap *, u_long cmd);      +static int urtwn_reset(struct ieee80211vap *, u_long cmd);
       ```
   
    A driver is not required to provide this method, if not filled in a     A driver is not required to provide this method, if not filled in a
    default method will be used that always causes a full reset of the     default method will be used that always causes a full reset of the
Line 295  reflects on the driver and causes most o Line 319  reflects on the driver and causes most o
    mbuf to the hardware send queue (and start transmission if needed).     mbuf to the hardware send queue (and start transmission if needed).
    A very simple example:     A very simple example:
   
       ```
     static int      static int
     urtwn_transmit(struct ieee80211com *ic, struct mbuf *m)      urtwn_transmit(struct ieee80211com *ic, struct mbuf *m)
     {        {  
Line 310  reflects on the driver and causes most o Line 335  reflects on the driver and causes most o
   
         return 0;          return 0;
     }      }
       ```
   
    A pointer to this function is assigned to the ic->ic_transmit member     A pointer to this function is assigned to the ic->ic_transmit member
    in the attach function.     in the attach function.
Line 317  reflects on the driver and causes most o Line 343  reflects on the driver and causes most o
  * Your driver needs a raw_xmit function which is close to what   * Your driver needs a raw_xmit function which is close to what
    the old driver called *_tx(), it looks like:     the old driver called *_tx(), it looks like:
   
       ```
     static int      static int
     urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,      urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
         const struct ieee80211_bpf_params *bpfp)          const struct ieee80211_bpf_params *bpfp)
       ```
   
    and the "missing" arguments are derived like:     and the "missing" arguments are derived like:
   
       ```
     struct ieee80211vap *vap = ni->ni_vap;      struct ieee80211vap *vap = ni->ni_vap;
     struct ieee80211com *ic = ni->ni_ic;      struct ieee80211com *ic = ni->ni_ic;
     struct urtwn_softc *sc = ic->ic_softc;      struct urtwn_softc *sc = ic->ic_softc;
       ```
   
    The check for encrypting packets often was testing the ieee80211_frame     The check for encrypting packets often was testing the ``ieee80211_frame`
    wh->i_fc[1] & IEEE80211_FC1_WE before encapsulating the mbuf     wh->i_fc[1] & IEEE80211_FC1_WE`` before encapsulating the ``mbuf``
    via ieee80211_crypto_encap(). The check now is for     via ``ieee80211_crypto_encap()``. The check now is for
    wh->i_fc[1] & IEEE80211_FC1_PROTECTED, since WEP is a thing of the     ``wh->i_fc[1] & IEEE80211_FC1_PROTECTED``, since WEP is a thing of the
    past and there are other protocols. Also the ieee80211_crypto_encap     past and there are other protocols. Also the ``ieee80211_crypto_encap``
    function lost its first argument (the radio common ic pointer).     function lost its first argument (the radio common ic pointer).
   
      XXXXX       XXXXX
   
    This function frees the mbuf and calls ieee80211_free_node(ni).     This function frees the ``mbuf`` and calls ``ieee80211_free_node(ni)``.
   
  * If the driver_activate() function only passes deactivation requests   * If the driver_activate() function only passes deactivation requests
    on to if_deactivate() you can replace it by a shim that gets     on to if_deactivate() you can replace it by a shim that gets
    your softc and calls ieee80211_activate(), like:     your softc and calls ieee80211_activate(), like:
   
       ```
     static int      static int
     urtwn_activate(device_t self, enum devact act)      urtwn_activate(device_t self, enum devact act)
     {      {
Line 349  reflects on the driver and causes most o Line 380  reflects on the driver and causes most o
                   
         return ieee80211_activate(&sc->sc_ic, act);          return ieee80211_activate(&sc->sc_ic, act);
     }             }       
       ```
   
  * When the hardware received a full frame, move it into a mbuf   * When the hardware received a full frame, move it into a mbuf
    and call (with proper frame bound checks)     and call (with proper frame bound checks)
   
       ```
     struct ieee80211_node *ni;      struct ieee80211_node *ni;
   
     // XXX unclear - same on NetBSD?      // XXX unclear - same on NetBSD?
Line 375  reflects on the driver and causes most o Line 408  reflects on the driver and causes most o
     } else {      } else {
         ieee80211_input_all(ic, m, rssi, nf);          ieee80211_input_all(ic, m, rssi, nf);
     }      }
       ```
   
    If a node is found, the data is passed on to that VAP, otherwise     If a node is found, the data is passed on to that VAP, otherwise
    it is a general management packet.     it is a general management packet.
Line 393  reflects on the driver and causes most o Line 427  reflects on the driver and causes most o
    driver watchdog functions are converted to a callout.     driver watchdog functions are converted to a callout.
    A typical implementation looks like:     A typical implementation looks like:
   
       ```
     static void           static void     
     urtwn_watchdog(void *arg)      urtwn_watchdog(void *arg)
     {      {
Line 409  reflects on the driver and causes most o Line 444  reflects on the driver and causes most o
                 callout_schedule(&sc->sc_watchdog_to, hz);                  callout_schedule(&sc->sc_watchdog_to, hz);
         }          }
     }      }
       ```
   
    There is no ieee80211_watchdog() function any more.     There is no ``ieee80211_watchdog()`` function any more.
   
   
  * ioctl functions   * ioctl functions
Line 424  reflects on the driver and causes most o Line 460  reflects on the driver and causes most o
    the active VAPs requires something special, like switch to promiscous     the active VAPs requires something special, like switch to promiscous
    mode. The function looks like:     mode. The function looks like:
   
       ```
     static void      static void
     rtwn_parent(struct ieee80211com *ic)      rtwn_parent(struct ieee80211com *ic)
     {      {
         struct rtwn_softc *sc = ic->ic_softc;          struct rtwn_softc *sc = ic->ic_softc;
         bool startall = false;          bool startall = false;
   
         mutex_enter(&sc->sc_tx_mtx);          mutex_enter(&sc->sc_tx_mtx);
         if (ic->ic_nrunning > 0 && !sc->sc_running)          if (ic->ic_nrunning > 0 && !sc->sc_running)
              startall = true;              startall = true;
         else if (ic->ic_nrunning == 0 && sc->sc_running)          else if (ic->ic_nrunning == 0 && sc->sc_running)
              rtwn_stop(sc);              rtwn_stop(sc);
         mutex_exit(&sc->sc_tx_mtx);          mutex_exit(&sc->sc_tx_mtx);
   
         if (startall)          if (startall)
              ieee80211_start_all(ic);              ieee80211_start_all(ic);
     }      }
       ```
   

Removed from v.1.1  
changed lines
  Added in v.1.2


CVSweb for NetBSD wikisrc <wikimaster@NetBSD.org> software: FreeBSD-CVSweb