Annotation of wikisrc/Converting_drivers_to_the_new_wifi_stack.mdwn, revision 1.24

1.1       wiki        1: # Intro
                      2: 
                      3:  This guide is meant to help you convert an old style NetBSD driver
                      4: for a wifi device to the newer wifi stack based on FreeBSD's current
                      5: version.
                      6: 
                      7:  This is work in progress, as we are trying to create helper functions
                      8: and libraries where usefull, and also the target API is a slightly
                      9: moving target.
                     10: 
                     11: # Overview
                     12: 
                     13:  The main difference between old style and new style drivers is the
                     14: VAP concept. VAP means Virtual Access Point, and it is used to split
                     15: the configuration properties of a wlan (as visible on air) from the
                     16: radio hardware. In many cases multiple wlans can be created using a
                     17: single radio hardware, which is naturally modelled as multiple VAPs
                     18: being created (by pure software) using the same physical radio device.
                     19: 
                     20:  At the user level the radio hardware is hidden quite well - it only
1.6       wiki       21: shows up in `dmesg` or `sysctl net.wlan.devices`.
1.1       wiki       22: There is no network interface for the raw hardware, so ifconfig will
                     23: not show them.
                     24: 
                     25:  To create a VAP for a radio device (and that way a network interface)
                     26: use a command like:
                     27: 
                     28:     ifconfig wlan0 create wlandev run0
                     29: 
                     30:  This split between common radio hardware and per-VAP network properties
                     31: reflects on the driver and causes most of the changes needed.
                     32: 
1.6       wiki       33:  After creation of the `wlan0` VAP, it will also show up under
1.1       wiki       34: 
1.4       wiki       35:     sysctl net.wlan.wlan0
1.1       wiki       36: 
1.4       wiki       37:  and in ifconfig output.
1.1       wiki       38: 
1.3       wiki       39:   More complete instructions for testing are here: [[Testing new wifi]].
                     40:   There also is an older paper describing the initial design in FreeBSD:
                     41:   [FreeBSD wireless BSDCan 2005](https://www.bsdcan.org/2005/papers/FreeBSDWirelessNetwokringSupport.pdf)
                     42: 
1.21      wiki       43: # Help available!
                     44: 
                     45: If your device is a usb(4) device, you can use a new helper facility "usbwifi" similar
                     46: to usbnet(9), which already handles a lot of new wifi stack specific details.
                     47: In the following text the items not applicable for drivers using usbwifi are marked
                     48: like this: [!]*usbwifi*{X} or `// !usbwifi` if appearing in code sections.
                     49: 
1.1       wiki       50: # Step by Step at the driver level
                     51: 
1.6       wiki       52:  * The data is split into the generic `struct ieee80211com`
                     53:    describing the radio hardware (often used as `ic` pointer),
1.1       wiki       54:    which is part of the drivers softc. The individual VAPs are
                     55:    in a TAILQ in the ic structure, and often are a driver defined
1.6       wiki       56:    structure 'derived' from `struct ieee80211vap` (with some
1.1       wiki       57:    additional driver specific data). The VAP structure has the
1.6       wiki       58:    network interface `struct ifnet` as `iv_ifp`.
                     59:    The `if_softc` pointer in the ifnet structure points to the VAP, the VAP structure
                     60:    has a pointer to the ic `iv_ic`, the ic structure has a `ic_softc` pointer to the softc.
1.1       wiki       61: 
                     62:  * MAC addresses are now stored in ic_macaddr instead of ic_myaddr
                     63:    (in struct ieee80211com). It is typically read from the device
                     64:    and cloned into each VAP. Typical code:
                     65: 
1.23      wiki       66:         IEEE80211_ADDR_COPY(ic->ic_macaddr, rom->macaddr);
1.1       wiki       67: 
1.6       wiki       68:  * In the attach function, no `struct ifnet ifp` will be needed,
1.1       wiki       69:    so get rid of code like:
                     70: 
1.23      wiki       71:          struct ifnet *ifp = GET_IFP(sc);
1.1       wiki       72: 
                     73:    and all initialization of ifp members. Move them to the vap_create
                     74:    function (see below) if needed instead, but typically none
                     75:    should be needed (as the generic code initializes the VAP's
                     76:    struct ifnet).
                     77: 
                     78:    Set a direct backlink to the softc, like:
                     79: 
1.23      wiki       80:         ic->ic_softc = sc;
1.1       wiki       81: 
                     82:    Make sure the ic_caps get initialized correctly to the capabilities
                     83:    of the radio, especially you want to add IEEE80211_C_STA for
                     84:    standard AP (station) mode.
                     85: 
1.23      wiki       86:    There is no state machine in the common radio part, it all moves into
1.1       wiki       87:    per-VAP state, so also remove initialization for it, like:
                     88: 
1.23      wiki       89:         ic->ic_state = IEEE80211_S_INIT;
1.1       wiki       90: 
1.23      wiki       91:    You may want a replacement for `IFF_OACATIVE` logic for the main device,
1.1       wiki       92:    as there is no interface so no flags to (ab)use for that.
                     93: 
1.12      wiki       94:  * The way channels are set up has changed.
1.23      wiki       95:    If your driver had a `driver_init_channels()` function, you can
1.12      wiki       96:    use it mostly verbatim (but see caveats below for `maxchans` and `nchans`).
                     97:    Rename it to `driver_get_radiocaps` and make it look like:
1.1       wiki       98: 
1.22      wiki       99: 
                    100:         static void
                    101:         urtwn_get_radiocaps(struct ieee80211com *ic,
                    102:             int maxchans, int *nchans, struct ieee80211_channel chans[])
                    103:         {
                    104:             uint8_t bands[IEEE80211_MODE_BYTES];
                    105:             
                    106:             memset(bands, 0, sizeof(bands));
                    107:             setbit(bands, IEEE80211_MODE_11B);
                    108:             setbit(bands, IEEE80211_MODE_11G);
                    109:             setbit(bands, IEEE80211_MODE_11NG);
                    110:             // XXX see description below if your chip can use other ranges (like 5ghz)
                    111:             ieee80211_add_channels_default_2ghz(chans, maxchans, nchans, bands, 0);
                    112:         }
                    113: 
1.1       wiki      114: 
1.6       wiki      115:    and also assign this function to `ic->ic_getradiocaps` in
1.1       wiki      116:    the attach function.
                    117: 
1.6       wiki      118:    An initial setup must happen before calling `ieee80211_ifattach(ic)`.
                    119:    You can just call the `driver_get_radiocaps()` function during
1.1       wiki      120:    attach like:
                    121: 
1.22      wiki      122:         urtwn_get_radiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,   
                    123:              ic->ic_channels);
                    124:         ieee80211_ifattach(ic);
                    125:         [..]
                    126:         ic->ic_getradiocaps = urtwn_get_radiocaps;
1.1       wiki      127: 
1.10      wiki      128:    If the hardware can use different frequency bands you may have to add them
                    129:    band by band instead of using `ieee80211_add_channels_default_2ghz`, also if
                    130:    the firmware knows about regulatory domains it may be required to select
                    131:    subsets of channels.
                    132: 
                    133:    An example of a multi-frequency driver doing this is iwm(4).
                    134: 
1.11      wiki      135:    It uses a helper function to add single channels individually
1.12      wiki      136:    via `ieee80211_add_channel`.
1.11      wiki      137:    To add the channels for a band, it calls
1.12      wiki      138:    `iwm_add_channel_band(ic, chans, maxchans, nchans, start, num, bands)`
                    139:    where `chans`, `maxchans` and `nchans` are the arguments passed to
1.23      wiki      140:    this callback, `chans` collecting the resulting channels, `nchans` pointing
1.12      wiki      141:    to the number of channels already collected, `bands` is the bitset of
1.23      wiki      142:    bands to add (multiple `IEEE80211_MODE_*` bits). The offset `start`
1.10      wiki      143:    is the index of the first channel to add to the output (first call will
1.23      wiki      144:    always be with 0 as `start`), and `num` the number of channels
1.12      wiki      145:    you expect `iwm_add_channel_band` to add. The `iwm_add_channel_band`
1.11      wiki      146:    helper function iterates over the channels, gets flags for the channels
1.12      wiki      147:    from firmware and calls `ieee80211_add_channel`.
                    148: 
                    149:    Overall the most important part in conversion of old drivers is to make sure that
                    150:    the out parameter `*nchans` is properly set to the number of channel data
                    151:    actually filled, and to respect the `maxchans` limit. This callback
                    152:    is called from two places, once from the drivers attach function,
                    153:    where `maxchan` is big enough (always `IEEE80211_CHAN_MAX`), and from
                    154:    ioctl `IEEE80211_IOC_DEVCAPS` where `maxchan` depends on the userland arguments
                    155:    and e.g. wpa_supplicant only asks for minmal data, as it is not interested
                    156:    in the actual channels available (`maxchan` is 1). The ioctl handling code
                    157:    will KASSERT proper behaviour of the callback.
1.10      wiki      158: 
1.1       wiki      159:  * If your driver used to override state machine functions (typical
1.6       wiki      160:    `newstate` to controll LEDs when associating or similar),
1.1       wiki      161:    remove all traces for this from your softc and override a
                    162:    custom VAP type instead (i.e. derive a struct from
1.23      wiki      163:    `struct ieee80211vap` and use your own struct in your `vap_create`
                    164:    and `vap_delete` methods).
1.1       wiki      165: 
1.23      wiki      166:    Remove the (likely to exist) old `sc_newstate` function from
1.1       wiki      167:    your drivers softc (previously used to store the frameworks
1.23      wiki      168:    newstate function, which now is per-VAP and moved into your
1.1       wiki      169:    derived per-VAP structure.
                    170: 
1.6       wiki      171:  * Many functions will get a `struct ieee80211vap *vap` passed instead
1.1       wiki      172:    of a softc. A typical change to adapt for that looks like:
                    173: 
1.22      wiki      174:         -       struct ieee80211com *ic = &sc->sc_ic;
                    175:         -       struct ieee80211_node *ni = ic->ic_bss;
                    176:         +       struct ieee80211com *ic = vap->iv_ic;
                    177:         +       struct rtwn_softc *sc = ic->ic_softc;
                    178:         +       struct ieee80211_node *ni = vap->iv_bss;
1.1       wiki      179: 
                    180:  * The hardware driver will need a global new outgoing packet queue
                    181:    (as the per-interface queues are attached to VAPs, not the single
1.23      wiki      182:    common transmit hardware). Add the new ifqueue like to your softc
1.1       wiki      183:    like this:
                    184: 
1.22      wiki      185:         struct ifqueue sc_sendq;
1.1       wiki      186: 
1.21      wiki      187:    If your hardware supports multiple transmit priorities you may
                    188:    consider doing more than one ifqueue. Usbwifi does this for devices
                    189:    with multiple transmit pipes (creating a ifqueue per hardware priority
                    190:    and in this case USB send endpoint).
                    191: 
1.23      wiki      192:    While there, check that there is no `struct ethercom sc_ec` in your
1.1       wiki      193:    softc - it is not needed.
                    194: 
                    195:    This queue needs initialization in the attach function, like:
                    196: 
1.22      wiki      197:         sc->sc_sendq.ifq_maxlen = ifqmaxlen;
                    198:         IFQ_LOCK_INIT(&sc->sc_sendq);
                    199: 
1.1       wiki      200: 
                    201:    This device private send queue (writer: any of the current VAPs
                    202:    of this interface, consumer: the devices transmit interrupt handler)
1.23      wiki      203:    abuses the `mbuf rcvif` pointer to store the node pointer
1.6       wiki      204:    `struct ieee80211_node *` of the target node for this packet.
1.23      wiki      205:    When dequeuing a packet before handing it over to the output function,
                    206:    the node is extracted and the `rcvif` pointer set to `NULL`.
1.1       wiki      207:    Yes - this is a hack.
                    208: 
                    209:    Also the attach function needs to set the name of the interface
                    210:    in the common radio device structure:
                    211: 
1.22      wiki      212:         ic->ic_name = device_xname(self);
1.1       wiki      213: 
                    214:    Many drivers query the hardware/firmware for the number of available
1.23      wiki      215:    input/output queues and store these in e.g. `sc->ntxchains`
1.6       wiki      216:    and `sc->nrxchains` or similar variables. This information
1.1       wiki      217:    needs to be propagated to the common radio structure:
                    218: 
1.22      wiki      219:         ic->ic_txstream = sc->ntxchains;
                    220:         ic->ic_rxstream = sc->nrxchains;
1.1       wiki      221: 
                    222:    Same for interface flags:
                    223: 
1.22      wiki      224:         ic->ic_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1.1       wiki      225: 
1.23      wiki      226:    After calling `ieee80211_ifattach(ic);` some methods in `ic`
1.1       wiki      227:    need to be overwritten. The functions needed are explained
                    228:    below, here is a typical setup:
                    229: 
1.22      wiki      230:         /* override default methods */
                    231:         ic->ic_newassoc = urtwn_newassoc;
                    232:         ic->ic_wme.wme_update = urtwn_wme_update;
                    233:         ic->ic_vap_create = urtwn_vap_create;
                    234:         ic->ic_vap_delete = urtwn_vap_delete;
                    235:         ic->ic_parent = urtwn_parent;
                    236:         ic->ic_scan_start = urtwn_scan_start;
                    237:         ic->ic_scan_end = urtwn_scan_end;
                    238:         ic->ic_set_channel = urtwn_set_channel;
                    239:         ic->ic_transmit = urtwn_transmit;    // !usbwifi
                    240:         ic->ic_raw_xmit = urtwn_raw_xmit;    // !usbwifi
1.1       wiki      241: 
                    242:  * detach does not deal with any interfaces any more, remove all traces
1.6       wiki      243:    of `struct ifnet *ifp`.
1.1       wiki      244: 
                    245:  * Add a new function for VAP creation and move all interface specific
                    246:    setup there. It looks like:
                    247: 
1.22      wiki      248:         static struct ieee80211vap *
                    249:         urtwn_vap_create(struct ieee80211com *ic,  const char name[IFNAMSIZ],
                    250:             int  unit, enum ieee80211_opmode opmode, int flags,
                    251:             const uint8_t bssid[IEEE80211_ADDR_LEN],
                    252:             const uint8_t macaddr[IEEE80211_ADDR_LEN])
                    253:         {
                    254:                struct urtwn_softc *sc = ic->ic_softc;
                    255:                struct ifnet *ifp;
                    256:                struct ieee80211vap *vap;
                    257:         ...
                    258:                return vap;
                    259:         }
1.1       wiki      260: 
1.6       wiki      261:    It allocates a new VAP with `kmem_zalloc` initializes it
1.23      wiki      262:    by calling `ieee80211_vap_setup` for it and then overriding whatever
1.6       wiki      263:    the driver needs, passes it to `ieee80211_vap_attach` and
1.23      wiki      264:    attaches BPF to the interface.
1.1       wiki      265: 
                    266:    If your interrupt handler is called in hard interrupt context
                    267:    (that probably means: for all devices that are not on USB)
                    268:    you need to initialize the per CPU interface queue:
                    269: 
1.22      wiki      270:         /* Use common softint-based if_input */
                    271:         ifp->if_percpuq = if_percpuq_create(ifp);
1.1       wiki      272: 
                    273:    If your interrupt handler always is called in softint context,
1.23      wiki      274:    do not do this. If `if_percpuq` is `NULL` the wifi framework will
1.1       wiki      275:    directly handle incoming packets, otherwise it will take a
                    276:    round trip via a per cpu softint handler.
                    277: 
                    278:  * Add a new function for VAP destruction and move interface specific
1.23      wiki      279:    parts that you deleted in the detach function here. A very
1.1       wiki      280:    minimalistic example looks like:
                    281: 
1.22      wiki      282:         static void
                    283:         urtwn_vap_delete(struct ieee80211vap *vap)
                    284:         {
                    285:             struct ifnet *ifp = vap->iv_ifp;
                    286:             struct urtwn_softc *sc __unused = vap->iv_ic->ic_softc;
                    287: 
                    288:             bpf_detach(ifp);
                    289:             ieee80211_vap_detach(vap);
                    290:             kmem_free(vap, sizeof(struct ieee80211vap));
                    291:         }
1.1       wiki      292: 
                    293:  * Rate Adaption happens per VAP, so the ra_init call changes like this:
                    294: 
1.22      wiki      295:         -static int urtwn_ra_init(struct urtwn_softc *);
                    296:         +static int urtwn_ra_init(struct ieee80211vap );
1.1       wiki      297: 
1.23      wiki      298:    See above for recipes how to access the needed structs in there.
1.1       wiki      299: 
                    300:  * State is per VAP, so newstate changes the first parameter:
                    301: 
1.22      wiki      302:         -static int urtwn_newstate(struct ieee80211com *, enum ieee80211_state, int);
                    303:         +static int urtwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
1.1       wiki      304: 
                    305:    If there was a newstate_cb function previously, it is probably not needed
                    306:    any more.
                    307: 
                    308:  * Reset is per interface, so per VAP:
                    309: 
1.22      wiki      310:         -static int urtwn_reset(struct ifnet *);
                    311:         +static int urtwn_reset(struct ieee80211vap *, u_long cmd);
1.1       wiki      312: 
                    313:    A driver is not required to provide this method, if not filled in a
                    314:    default method will be used that always causes a full reset of the
                    315:    device.
                    316: 
                    317:  * The set channel function is generic now, so gets passed a
1.6       wiki      318:    `struct ieee80211com *ic` instead of a softc, and sets
1.1       wiki      319:    the radio hardware to the current channel in that structure,
1.6       wiki      320:    `ic->ic_curchan`.
1.1       wiki      321: 
1.6       wiki      322:  * The start function does not need a `struct ifnet *ifp` any more,
1.9       wiki      323:    but can use a softc or `struct ieee80211com *ic` instead.
1.1       wiki      324: 
1.23      wiki      325:  * Typically, generic media change and status functions will
1.6       wiki      326:    be used: `ieee80211_media_change` and `ieee80211_media_status`.
1.1       wiki      327:    Old drivers often implement their own function - remove that (unless
                    328:    there is something actually chip specific in them).
                    329: 
1.24    ! wiki      330:    If there is, override media_change and/or media_status, and make
1.21      wiki      331:    sure to call the generic variant for all the real work.
1.24    ! wiki      332:    Also make sure to pass your override function to `ieee80211_vap_attach.`
        !           333:    run(4) is an example of this.
        !           334: 
        !           335:    The overridden media_\{change,status\} functions are the only one
        !           336:    in a wlan driver that should get a `struct ifnet *` argument
1.21      wiki      337:    passed.
1.24    ! wiki      338:    Checking for this is a good measurement to know you are done with
        !           339:    conversion (besides the kernel build failing, of course).
1.1       wiki      340: 
1.21      wiki      341:  * [!]*usbwifi*{X} Your driver needs a new transmit function, used to enqueue a
1.1       wiki      342:    mbuf to the hardware send queue (and start transmission if needed).
                    343:    A very simple example:
                    344: 
1.22      wiki      345:         static int
                    346:         urtwn_transmit(struct ieee80211com *ic, struct mbuf *m)
                    347:         {
                    348:             struct urtwn_softc *sc = ic->ic_softc;
                    349:             int s;
                    350:             
                    351:             s = splnet();
                    352:             IF_ENQUEUE(&sc->sc_sendq, m);
                    353:             splx(s);
                    354: 
                    355:             if (!sc->sc_oactive)
                    356:                     urtwn_start(sc);
                    357: 
                    358:             return 0;
                    359:         }
                    360: 
1.1       wiki      361: 
1.23      wiki      362:    A pointer to this function is assigned to the `ic->ic_transmit` member
1.1       wiki      363:    in the attach function.
                    364: 
1.24    ! wiki      365:  * [!]*usbwifi*{X} Your driver needs a raw_xmit function which is close to what
1.1       wiki      366:    the old driver called *_tx(), it looks like:
                    367: 
1.22      wiki      368: 
                    369:         static int
                    370:         urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
                    371:             const struct ieee80211_bpf_params *bpfp)
1.1       wiki      372: 
                    373:    and the "missing" arguments are derived like:
                    374: 
1.22      wiki      375:         struct ieee80211vap *vap = ni->ni_vap;
                    376:         struct ieee80211com *ic = ni->ni_ic;
                    377:         struct urtwn_softc *sc = ic->ic_softc;
1.1       wiki      378: 
1.23      wiki      379:    The check for encrypting packets often was testing the `ieee80211_frame`
                    380:    `wh->i_fc[1] & IEEE80211_FC1_WE` before encapsulating the mbuf
1.6       wiki      381:    via `ieee80211_crypto_encap()`. The check now is for
                    382:    `wh->i_fc[1] & IEEE80211_FC1_PROTECTED`, since WEP is a thing of the
                    383:    past and there are other protocols. Also the `ieee80211_crypto_encap`
1.1       wiki      384:    function lost its first argument (the radio common ic pointer).
                    385: 
1.23      wiki      386:    The transmit function queues the mbuf for transmit and
1.13      wiki      387:    makes sure when transmission is done by hardware to call
1.14      wiki      388:    `ieee80211_tx_complete` with both `mbuf` and `ni`. This function
                    389:    also needs to be called in all error cases, with an error value as
                    390:    status (last argument). The actual value does not matter, the stack
1.23      wiki      391:    just checks for 0 (success) and non zero (failure). This call
1.14      wiki      392:    will free the mbuf and the node, and in some cases also cause
                    393:    further state changes (like waking up VAPs, scheduling a new scan
                    394:    later, or even causing immediate state machine transitions and retrying
                    395:    in error cases).
1.1       wiki      396: 
1.24    ! wiki      397:  * [!]*usbwifi*{X} If the `driver_activate()` function only passes deactivation requests
1.1       wiki      398:    on to if_deactivate() you can replace it by a shim that gets
1.23      wiki      399:    your softc and calls `ieee80211_activate()`, like:
1.1       wiki      400: 
1.22      wiki      401:         static int
                    402:         urtwn_activate(device_t self, enum devact act)
                    403:         {
                    404:             struct urtwn_softc *sc = device_private(self);
                    405:             
                    406:             return ieee80211_activate(&sc->sc_ic, act);
                    407:         }
1.1       wiki      408: 
                    409:  * When the hardware received a full frame, move it into a mbuf
                    410:    and call (with proper frame bound checks)
                    411: 
1.22      wiki      412:         struct ieee80211_node *ni;
1.1       wiki      413: 
1.22      wiki      414:         // XXX unclear - same on NetBSD?
                    415:         if (ieee80211_radiotap_active(ic))
                    416:             mactime = rx->mactime;
                    417:         // or:
                    418:         if (ieee80211_radiotap_active(ic)) 
                    419:             struct urtw_rx_radiotap_header *tap = &sc->sc_rxtap;
                    420: 
                    421:             tap->wr_tsf = mactime;
                    422:             tap->wr_flags = 0;
                    423:             tap->wr_dbm_antsignal = (int8_t)rssi;
                    424:         }
                    425: 
                    426:         ni = ieee80211_find_rxnode(ic,
                    427:             mtod(m, struct ieee80211_frame_min *));
                    428:         if (ni != NULL) {
                    429:             ieee80211_input(ni, m, rssi, nf);
                    430:             ieee80211_free_node(ni);
                    431:         } else {
                    432:             ieee80211_input_all(ic, m, rssi, nf);
                    433:         }
1.1       wiki      434: 
                    435:    If a node is found, the data is passed on to that VAP, otherwise
                    436:    it is a general management packet.
                    437: 
                    438:    Old code often has tests for too short or too long packets and
                    439:    increments error counters in the struct ifnet of the interface
                    440:    that used to belong to the wlan driver. Since there is no such
                    441:    single interface anymore, errors are accounted later (at the VAP
                    442:    level) if a VAP/node is identified for the packet. Otherwise
1.23      wiki      443:    just increment the global `ic->ic_ierrors` counter for errors with
1.1       wiki      444:    incoming packets that can not be associated with a concrete
1.23      wiki      445:    network (or similar `ic->ic_oerrors` for output errors).
1.15      wiki      446: 
                    447:  * Various BPF changes:
                    448: 
                    449:    Many drivers avoid complex setup options for BPF listeners if there are none.
1.18      wiki      450:    With virtual APs this became a bit more complex, but the framework tracks it
                    451:    for the driver. To test if any VAP on the radio hardware is in MONITOR mode and has
                    452:    an active  BPF peer, simply test the `ic->ic_montaps` counter - it will be zero if
                    453:    there are none.
1.15      wiki      454: 
                    455:    For most drivers it should not be necessary to do anything special for BPF, the
                    456:    taps are in the framework.
                    457: 
                    458:    Some drivers provide special low level radiotap data, often via a driver specific
1.18      wiki      459:    `sc->sc_drvbpf`. This is replaced by a generic radiotap bpf listener created by
                    460:    the framework code and stored as `vap-> iv_rawbpf`. A driver signals support for
                    461:    radiotap by making `ic->ic_th` point to a radiotap transmit header (usually in
                    462:    the softc, initialized before attach and updated on transmit) and similar `ic->ic_rh` 
                    463:    point to a receive tap header (updated on every received packet). Make sure to initialize
                    464:    the tap headers `it_len` fields to the proper size (in little endian byte order)
1.19      wiki      465:    and `it_present` flags (also in little endian byte order) to the relevant
1.18      wiki      466:    `IEEE80211_RADIOTAP_*` bits.
                    467: 
                    468:    To avoid updating the receive/transmit tap headers unessecarily the driver can check
                    469:    the `ic->ic_flags_ext` for the `IEEE80211_FEXT_BPF` bit being set - if not, there is
                    470:    no VAP with bpf listener on radiotap headers.
                    471: 
1.20      wiki      472:    The driver needs to update `ic_rh` (usually only the storage for a single header
                    473:    it points to) on every received packet. This is used as a side channel for the
                    474:    radiotap data when passing packet up the stack via `ieee80211_input_all` or
                    475:    `ieee80211_input`. Or in the NetBSD case for USB drivers when calling `usbwifi_enqueue`.
                    476:    The stack automatically dispatches this to the radiotap bpf tap associated with any
                    477:    relevant VAP and also makes sure it is seen by VAPs in MONITOR mode.
                    478: 
1.15      wiki      479:  * Watchdog functions move to callout:
                    480: 
1.1       wiki      481:    Since there is no 1:1 ifnet and its global watchdog mechanism, all
                    482:    driver watchdog functions are converted to a callout.
                    483:    A typical implementation looks like:
                    484: 
1.22      wiki      485:         static void
                    486:         urtwn_watchdog(void *arg)
                    487:         {
                    488:             struct urtwn_softc *sc = arg;
                    489:             struct ieee80211com *ic = &sc->sc_ic;
                    490: 
                    491:             if (sc->tx_timer > 0) {
                    492:                     if (--sc->tx_timer == 0) {
                    493:                             aprint_error_dev(sc->sc_dev, "device timeout\n");
                    494:                             ieee80211_stat_add(&ic->ic_oerrors, 1);
                    495:                             ieee80211_restart_all(ic);
                    496:                             return;
                    497:                     }
                    498:                     callout_schedule(&sc->sc_watchdog_to, hz);
                    499:             }
1.1       wiki      500:         }
                    501: 
1.6       wiki      502:    There is no `ieee80211_watchdog()` function any more.
1.1       wiki      503: 
                    504: 
                    505:  * ioctl functions
                    506:    Typicaly there are no ioctl functions in a wlan driver. The ioctls
                    507:    are handled in generic code and the ic_parent function is called to
                    508:    update the device state accordingly.  XXXX - is this true? implemented?
                    509:    Or one of ic_scan_start/ic_scan_end/ic_set_channel
                    510: 
                    511:  * device _parent function
                    512:    You need to add a new function to update the device state when one of
                    513:    the active VAPs requires something special, like switch to promiscous
                    514:    mode. The function looks like:
                    515: 
1.22      wiki      516:         static void
                    517:         rtwn_parent(struct ieee80211com *ic)
                    518:         {
                    519:             struct rtwn_softc *sc = ic->ic_softc;
                    520:             bool startall = false;
                    521: 
                    522:             mutex_enter(&sc->sc_tx_mtx);
                    523:             if (ic->ic_nrunning > 0 && !sc->sc_running)
                    524:                 startall = true;
                    525:             else if (ic->ic_nrunning == 0 && sc->sc_running)
                    526:                 rtwn_stop(sc);
                    527:             mutex_exit(&sc->sc_tx_mtx);
                    528: 
                    529:             if (startall)
                    530:                 ieee80211_start_all(ic);
                    531:         }

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