Subject: Re: adding an 802.11 data link type
To: None <tech-net@netbsd.org>
From: David Young <dyoung@ojctech.com>
List: tech-net
Date: 08/08/2002 14:39:31
Here is the way it works.

I posit three 802.11 DLTs. Two are hardware-specific:
DLT_PRISM2_IEEE802_11 for Prism2.x, DLT_ORINOCO_IEEE802_11 for Lucent
WaveLAN. For plain 802.11, there is DLT_IEEE802_11.

I add to the wi_softc two fields,

        struct bpf_if           *sc_bpf80211;
        struct bpf_if           *sc_bpf80211plus;

In wi_attach, I register as a tap for 802.3 and plain 802.11 frames:

        bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
        bpfattach2(ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4),
                   (caddr_t*) &sc->sc_bpf80211);

Depending what firmware I detect---Intersil, Symbol (is only a divergence
from Prism reference design, I think), or Lucent---I register as a tap
for either Prism or Lucent hardware-specific frames, also:

        if (sc->sc_firmware_type == WI_INTERSIL ||
            sc->sc_firmware_type == WI_SYMBOL) {
                bpfattach2(ifp, DLT_PRISM2_IEEE802_11, sizeof(struct wi_frame),
                           (caddr_t*) &sc->sc_bpf80211plus);
        } else if (sc->sc_firmware_type == WI_LUCENT) {
                bpfattach2(ifp, DLT_ORINOCO_IEEE802_11, sizeof(struct wi_frame),
                           (caddr_t*) &sc->sc_bpf80211plus);
        }

I add to wi(4) two subroutine to tap frames. One takes an mbuf chain
containing an 802.11 mgmt/ctrl frame w/ hardware-specific extensions,
and hands up either an 802.11 frame, an 802.11 frame w/ extensions,
both, or neither:

STATIC void
wi_tap_802_11_plus(struct wi_softc *sc, struct mbuf *m,
                   struct wi_frame *hwframe)
{
        struct mbuf *m2;

        if (sc->sc_bpf80211plus) {
                bpf_mtap((caddr_t) sc->sc_bpf80211plus, m);
        }
        if (sc->sc_bpf80211) {

                m2 = m_copym(m, WI_802_11_OFFSET_HDR, M_COPYALL, M_DONTWAIT);
                if (m2) {
                        bpf_mtap((caddr_t) sc->sc_bpf80211, m);
                        m_freem(m2);
                }
        }
}

The second subroutine takes an mbuf chain containing an 802.3 frame,
and augments it with an 802.11 header, an 802.11 header w/ extensions,
both, or neither:

STATIC void
wi_tap_802_3(struct wi_softc *sc, struct mbuf *m, struct wi_frame *hwframe)
{
        struct mbuf *m2 = 0;

        /* hand up 802.3 frame */
        if (sc->sc_ifp->if_bpf) {
                bpf_mtap(sc->sc_ifp->if_bpf, m);
        }

        /* hand up hardware-specific frame */
        if (sc->sc_bpf80211plus) {

                if (!(m2 = m_copym(m, 0, M_COPYALL, M_DONTWAIT))) {
                        goto bpf80211plus_failure;
                }

                M_PREPEND(m2, WI_802_3_OFFSET, M_DONTWAIT);
                if (!m2) {
                        goto bpf80211plus_failure;
                }

                m_copyback(m2, 0, WI_802_3_OFFSET, (caddr_t) &hwframe);

                bpf_mtap((caddr_t) sc->sc_bpf80211plus, m2);

                m_freem(m2);
        }

bpf80211plus_failure:

        /* hand up 802.11 frame */
        if (sc->sc_bpf80211) {

                /* TBD optimize when m2 contains extended 802.11 frame */

                if (!(m2 = m_copym(m, 0, M_COPYALL, M_DONTWAIT))) {
                        goto bpf80211_failure;
                }

                M_PREPEND(m2, WI_802_3_OFFSET - WI_802_11_OFFSET_HDR,
                          M_DONTWAIT);

                if (!m2) {
                        goto bpf80211_failure;
                }

                m_copyback(m2, 0, WI_802_3_OFFSET - WI_802_11_OFFSET_HDR,
                           (caddr_t) &hwframe + WI_802_11_OFFSET_HDR);

                bpf_mtap((caddr_t) sc->sc_bpf80211, m2);

                m_freem(m2);
        }
bpf80211_failure:
        return;
}

BPF writes a pointer to a bpf_if into each of ifp->if_bpf,
sc->sc_bpf80211, or sc->sc_bpf80211plus as the first subscriber for
the associated DLT attaches. It writes a NULL to each of ifp->if_bpf,
sc->sc_bpf80211, or sc->sc_bpf80211plus, as the last subscriber detaches.
Because the tap subroutines check for a non-zero bpf_if pointer before
they produce or tap a frame, no frame will be built or handed up to BPF,
if a subscriber does not listen for it.

Questions? Criticisms?

Dave

On Thu, Aug 08, 2002 at 10:08:24AM -0700, Bill Studenmund wrote:
> On Thu, 8 Aug 2002, Atsushi Onoe wrote:
> 
> > > So if I understand your code right, (ic->ic_rawbpf) is a necessary but not
> > > sufficient condition to hand the packet off to bpf_mtap. The bpf system
> > > would have had to ask for that packet type too. So something like:
> > > if ((ic->ic_rawbpf) && (ic->ic_raw_bpfcount))
> > > 	bpf_mtap(ic->ic_rawbpf, m0);
> >
> > Please note that this interface is very similar to existing bpf hook.
> > So the value of ic->ic_rawbpf remains NULL unless someone issues BPFSETIF
> > and BIOCSDLT, and recovered to NULL when the bpf listener closes bpf.
> > The number of opening listeners are counted in bpf itself.
> 
> How does bpf communicate what kind of packets it wants to the driver?
> 
> Take care,
> 
> Bill

-- 
David Young             OJC Technologies
dyoung@onthejob.net     Engineering from the Right Brain
                        Urbana, IL * (217) 278-3933