PERFORCE change 68617 for review
Sam Leffler
sam at FreeBSD.org
Sun Jan 9 20:46:07 PST 2005
http://perforce.freebsd.org/chv.cgi?CH=68617
Change 68617 by sam at sam_ebb on 2005/01/10 04:45:17
working fast frames; still needs work
Affected files ...
.. //depot/projects/wifi/sys/dev/ath/if_ath.c#64 edit
.. //depot/projects/wifi/sys/dev/ath/if_athvar.h#26 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_input.c#37 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#22 edit
.. //depot/projects/wifi/sys/net80211/ieee80211_output.c#32 edit
.. //depot/projects/wifi/tools/tools/ath/80211stats.c#8 edit
Differences ...
==== //depot/projects/wifi/sys/dev/ath/if_ath.c#64 (text+ko) ====
@@ -2184,10 +2184,10 @@
}
/*
* Check if the previous beacon has gone out. If
- * not don't don't try to post another, skip this
- * period and wait for the next. Missed beacons
- * indicate a problem and should not occur. If we
- * miss too many consecutive beacons reset the device.
+ * not don't try to post another, skip this period
+ * and wait for the next. Missed beacons indicate
+ * a problem and should not occur. If we miss too
+ * many consecutive beacons reset the device.
*/
if (ath_hal_numtxpending(ah, sc->sc_bhalq) != 0) {
sc->sc_bmisscount++;
@@ -2890,19 +2890,7 @@
if (status == HAL_EINPROGRESS)
break;
STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
- if (ds->ds_rxstat.rs_more) {
- /*
- * Frame spans multiple descriptors; this
- * cannot happen yet as we don't support
- * jumbograms. If not in monitor mode,
- * discard the frame.
- */
- if (ic->ic_opmode != IEEE80211_M_MONITOR) {
- sc->sc_stats.ast_rx_toobig++;
- goto rx_next;
- }
- /* fall thru for monitor mode handling... */
- } else if (ds->ds_rxstat.rs_status != 0) {
+ if (ds->ds_rxstat.rs_status != 0) {
if (ds->ds_rxstat.rs_status & HAL_RXERR_CRC)
sc->sc_stats.ast_rx_crcerr++;
if (ds->ds_rxstat.rs_status & HAL_RXERR_FIFO)
@@ -2911,7 +2899,7 @@
sc->sc_stats.ast_rx_phyerr++;
phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
sc->sc_stats.ast_rx_phy[phyerr]++;
- goto rx_next;
+ goto rx_error; /* NB: don't count in ierrors */
}
if (ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT) {
/*
@@ -2949,7 +2937,15 @@
}
}
ifp->if_ierrors++;
+rx_error:
/*
+ * Cleanup any pending partial frame.
+ */
+ if (sc->sc_rxpending != NULL) {
+ m_freem(sc->sc_rxpending);
+ sc->sc_rxpending = NULL;
+ }
+ /*
* Reject error frames, we normally don't want
* to see them in monitor mode (in monitor mode
* allow through packets that have crypto problems).
@@ -2972,9 +2968,42 @@
bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
bf->bf_m = NULL;
- m->m_pkthdr.rcvif = ifp;
len = ds->ds_rxstat.rs_datalen;
- m->m_pkthdr.len = m->m_len = len;
+ m->m_len = len;
+
+ if (ds->ds_rxstat.rs_more) {
+ /*
+ * Frame spans multiple descriptors; save
+ * it for the next completed descriptor, it
+ * will be used to construct a jumbogram.
+ */
+ if (sc->sc_rxpending != NULL) {
+ /* NB: max frame size is currently 2 clusters */
+ sc->sc_stats.ast_rx_toobig++;
+ m_freem(sc->sc_rxpending);
+ }
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = len;
+ sc->sc_rxpending = m;
+ goto rx_next;
+ } else if (sc->sc_rxpending != NULL) {
+ /*
+ * This is the second part of a jumbogram,
+ * chain it to the first mbuf, adjust the
+ * frame length, and clear the rxpending state.
+ */
+ sc->sc_rxpending->m_next = m;
+ sc->sc_rxpending->m_pkthdr.len += len;
+ m = sc->sc_rxpending;
+ sc->sc_rxpending = NULL;
+ } else {
+ /*
+ * Normal single-descriptor receive; setup
+ * the rcvif and packet length.
+ */
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = len;
+ }
sc->sc_stats.ast_ant_rx[ds->ds_rxstat.rs_antenna]++;
@@ -3783,8 +3812,6 @@
ds->ds_txstat.ts_rssi;
ATH_RSSI_LPF(an->an_halstats.ns_avgtxrssi,
ds->ds_txstat.ts_rssi);
- if (bf->bf_m->m_flags & M_FF)
- sc->sc_stats.ast_ff_txok++;
pri = M_WME_GETAC(bf->bf_m);
if (pri >= WME_AC_VO)
ic->ic_wme.wme_hipri_traffic++;
@@ -4037,6 +4064,10 @@
}
}
#endif
+ if (sc->sc_rxpending != NULL) {
+ m_freem(sc->sc_rxpending);
+ sc->sc_rxpending = NULL;
+ }
sc->sc_rxlink = NULL; /* just in case */
#undef PA2DESC
}
@@ -4051,6 +4082,7 @@
struct ath_buf *bf;
sc->sc_rxlink = NULL;
+ sc->sc_rxpending = NULL;
STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
int error = ath_rxbuf_init(sc, bf);
if (error != 0) {
==== //depot/projects/wifi/sys/dev/ath/if_athvar.h#26 (text+ko) ====
@@ -258,6 +258,7 @@
struct ath_descdma sc_rxdma; /* RX descriptos */
ath_bufhead sc_rxbuf; /* receive buffer */
+ struct mbuf *sc_rxpending; /* pending receive data */
u_int32_t *sc_rxlink; /* link ptr in last RX desc */
struct task sc_rxtask; /* rx int processing */
struct task sc_rxorntask; /* rxorn int processing */
==== //depot/projects/wifi/sys/net80211/ieee80211_input.c#37 (text+ko) ====
@@ -108,7 +108,11 @@
static struct mbuf *ieee80211_defrag(struct ieee80211com *,
struct ieee80211_node *, struct mbuf *);
+static void ieee80211_deliver_data(struct ieee80211com *,
+ struct ieee80211_node *, struct mbuf *);
static struct mbuf *ieee80211_decap(struct ieee80211com *, struct mbuf *);
+static struct mbuf *ieee80211_decap_fastframe(struct ieee80211com *,
+ struct ieee80211_node *, struct mbuf *);
static void ieee80211_node_pwrsave(struct ieee80211_node *, int enable);
static void ieee80211_recv_pspoll(struct ieee80211com *,
struct ieee80211_node *, struct mbuf *);
@@ -133,7 +137,7 @@
struct ieee80211_frame *wh;
struct ieee80211_key *key;
struct ether_header *eh;
- int len, hdrsize, off;
+ int hdrsize, off;
u_int8_t dir, type, subtype;
u_int8_t *bssid;
u_int16_t rxseq;
@@ -289,8 +293,8 @@
if (m->m_len < hdrsize &&
(m = m_pullup(m, hdrsize)) == NULL) {
IEEE80211_DISCARD(ic, IEEE80211_MSG_ANY,
- wh, "data", "too short: len %u, expecting %u",
- m->m_pkthdr.len, hdrsize);
+ wh, "data", "too short: m_pullup(%u) failed",
+ hdrsize);
ic->ic_stats.is_rx_tooshort++;
goto out; /* XXX */
}
@@ -492,49 +496,32 @@
IEEE80211_NODE_STAT(ni, rx_data);
IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len);
- /* perform as a bridge within the AP */
- if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
- (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0) {
- struct mbuf *m1 = NULL;
+#define FF_LLC_SIZE (sizeof(struct ether_header) + sizeof(struct llc))
+ if ((ni->ni_flags & IEEE80211_NODE_FF) &&
+ m->m_pkthdr.len >= 3*FF_LLC_SIZE) {
+ struct llc *llc;
- if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
- m1 = m_copypacket(m, M_DONTWAIT);
- if (m1 == NULL)
- ifp->if_oerrors++;
- else
- m1->m_flags |= M_MCAST;
- } else {
- /* XXX this dups work done in ieee80211_encap */
- /* check if destination is associated */
- struct ieee80211_node *ni1 =
- ieee80211_find_node(ic->ic_sta,
- eh->ether_dhost);
- if (ni1 != NULL) {
- /* XXX check if authorized */
- if (ni1->ni_associd != 0) {
- m1 = m;
- m = NULL;
- }
- /* XXX statistic? */
- ieee80211_free_node(ni1);
- }
+ /*
+ * Check for fast-frame tunnel encapsulation.
+ */
+ if (m->m_len < FF_LLC_SIZE &&
+ (m = m_pullup(m, FF_LLC_SIZE)) == NULL) {
+ IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+ ni->ni_macaddr, "fast-frame",
+ "%s", "m_pullup(llc) failed");
+ ic->ic_stats.is_rx_tooshort++;
}
- if (m1 != NULL) {
- len = m1->m_pkthdr.len;
- IF_ENQUEUE(&ifp->if_snd, m1);
- if (m != NULL)
- ifp->if_omcasts++;
- ifp->if_obytes += len;
+ llc = (struct llc *)(mtod(m, u_int8_t *) +
+ sizeof(struct ether_header));
+ if (llc->llc_snap.ether_type == htons(ATH_FF_ETH_TYPE)) {
+ m_adj(m, FF_LLC_SIZE);
+ m = ieee80211_decap_fastframe(ic, ni, m);
+ if (m == NULL)
+ return;
}
}
- if (m != NULL) {
- if (ni->ni_vlan != 0) {
- /* attach vlan tag */
- /* XXX goto err? */
- VLAN_INPUT_TAG(ifp, m, ni->ni_vlan, goto out);
- }
- (*ifp->if_input)(ifp, m);
- }
+#undef FF_LLC_SIZE
+ ieee80211_deliver_data(ic, ni, m);
return;
case IEEE80211_FC0_TYPE_MGT:
@@ -711,6 +698,66 @@
return mfrag;
}
+static void
+ieee80211_deliver_data(struct ieee80211com *ic,
+ struct ieee80211_node *ni, struct mbuf *m)
+{
+ struct ether_header *eh = mtod(m, struct ether_header *);
+ struct ifnet *ifp = ic->ic_ifp;
+ int len;
+
+ /* perform as a bridge within the AP */
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ (ic->ic_flags & IEEE80211_F_NOBRIDGE) == 0) {
+ struct mbuf *m1 = NULL;
+
+ if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
+ m1 = m_copypacket(m, M_DONTWAIT);
+ if (m1 == NULL)
+ ifp->if_oerrors++;
+ else
+ m1->m_flags |= M_MCAST;
+ } else {
+ /* XXX this dups work done in ieee80211_encap */
+ /* check if destination is associated */
+ struct ieee80211_node *ni1 =
+ ieee80211_find_node(ic->ic_sta,
+ eh->ether_dhost);
+ if (ni1 != NULL) {
+ /* XXX check if authorized */
+ if (ni1->ni_associd != 0) {
+ m1 = m;
+ m = NULL;
+ }
+ /* XXX statistic? */
+ ieee80211_free_node(ni1);
+ }
+ }
+ if (m1 != NULL) {
+ len = m1->m_pkthdr.len;
+ IF_ENQUEUE(&ifp->if_snd, m1);
+ if (m != NULL)
+ ifp->if_omcasts++;
+ ifp->if_obytes += len;
+ }
+ }
+ if (m != NULL) {
+ if (ni->ni_vlan != 0) {
+ /* attach vlan tag */
+ /* XXX goto err? */
+ VLAN_INPUT_TAG(ifp, m, ni->ni_vlan, goto out);
+ }
+ (*ifp->if_input)(ifp, m);
+ }
+ return;
+ out:
+ if (m != NULL) {
+ if (ic->ic_rawbpf)
+ bpf_mtap(ic->ic_rawbpf, m);
+ m_freem(m);
+ }
+}
+
static struct mbuf *
ieee80211_decap(struct ieee80211com *ic, struct mbuf *m)
{
@@ -813,6 +860,104 @@
}
/*
+ * Decap a frame encapsulated in a fast-frame.
+ */
+static struct mbuf *
+ieee80211_decap1(struct mbuf *m, int *framelen)
+{
+#define FF_LLC_SIZE (sizeof(struct ether_header) + sizeof(struct llc))
+ struct ether_header *eh;
+ struct llc *llc;
+
+ /*
+ * The frame has an 802.3 header followed by an 802.2
+ * LLC header. The encapsulated frame length is in the
+ * first header type field; save that and overwrite it
+ * with the true type field found in the second. Then
+ * copy the 802.3 header up to where it belongs and
+ * adjust the mbuf contents to remove the void.
+ */
+ if (m->m_len < FF_LLC_SIZE && (m = m_pullup(m, FF_LLC_SIZE)) == NULL)
+ return NULL;
+ eh = mtod(m, struct ether_header *); /* 802.3 header is first */
+ llc = (struct llc *)&eh[1]; /* 802.2 header follows */
+ *framelen = ntohs(eh->ether_type) /* encap'd frame size */
+ + sizeof(struct ether_header) - sizeof(struct llc);
+ eh->ether_type = llc->llc_un.type_snap.ether_type;
+ ovbcopy(eh, mtod(m, u_int8_t *) + sizeof(struct llc),
+ sizeof(struct ether_header));
+ m_adj(m, sizeof(struct llc));
+ return m;
+#undef FF_LLC_SIZE
+}
+
+/*
+ * Decap the encapsulated frame pair and dispatch the first
+ * for delivery. The second frame is returned for delivery
+ * via the normal path.
+ */
+static struct mbuf *
+ieee80211_decap_fastframe(struct ieee80211com *ic,
+ struct ieee80211_node *ni, struct mbuf *m)
+{
+#define MS(x,f) (((x) & f) >> f##_S)
+ u_int32_t ath;
+ struct mbuf *n;
+ int framelen;
+
+ m_copydata(m, 0, sizeof(u_int32_t), (caddr_t) &ath);
+ if (MS(ath, ATH_FF_PROTO) != ATH_FF_PROTO_L2TUNNEL) {
+ IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+ ni->ni_macaddr, "fast-frame",
+ "unsupport tunnel protocol, header 0x%x", ath);
+ ic->ic_stats.is_ff_badhdr++;
+ m_freem(m);
+ return NULL;
+ }
+ /* NB: skip header and alignment padding */
+ m_adj(m, roundup(sizeof(u_int32_t) - 2, 4) + 2);
+
+ ic->ic_stats.is_ff_decap++;
+
+ /*
+ * Decap the first frame, bust it apart from the
+ * second and deliver; then decap the second frame
+ * and return it to the caller for normal delivery.
+ */
+ m = ieee80211_decap1(m, &framelen);
+ if (m == NULL) {
+ IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+ ni->ni_macaddr, "fast-frame", "%s", "first decap failed");
+ ic->ic_stats.is_ff_tooshort++;
+ return NULL;
+ }
+ n = m_split(m, framelen, M_NOWAIT);
+ if (n == NULL) {
+ IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+ ni->ni_macaddr, "fast-frame",
+ "%s", "unable to split encapsulated frames");
+ ic->ic_stats.is_ff_split++;
+ m_freem(m); /* NB: must reclaim */
+ return NULL;
+ }
+ ieee80211_deliver_data(ic, ni, m); /* 1st of pair */
+
+ /*
+ * Decap second frame.
+ */
+ m_adj(n, roundup2(framelen, 4) - framelen); /* padding */
+ n = ieee80211_decap1(n, &framelen);
+ if (n == NULL) {
+ IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+ ni->ni_macaddr, "fast-frame", "%s", "second decap failed");
+ ic->ic_stats.is_ff_tooshort++;
+ }
+ /* XXX verify framelen against mbuf contents */
+ return n; /* 2nd delivered by caller */
+#undef MS
+}
+
+/*
* Install received rate set information in the node's state block.
*/
static int
==== //depot/projects/wifi/sys/net80211/ieee80211_ioctl.h#22 (text+ko) ====
@@ -173,6 +173,11 @@
u_int32_t is_ps_unassoc; /* ps-poll for unassoc. sta */
u_int32_t is_ps_badaid; /* ps-poll w/ incorrect aid */
u_int32_t is_ps_qempty; /* ps-poll w/ nothing to send */
+ u_int32_t is_ff_badhdr; /* fast frame rx'd w/ bad hdr */
+ u_int32_t is_ff_tooshort; /* fast frame rx decap error */
+ u_int32_t is_ff_split; /* fast frame rx split error */
+ u_int32_t is_ff_decap; /* fast frames decap'd */
+ u_int32_t is_ff_encap; /* fast frames encap'd for tx */
};
/*
==== //depot/projects/wifi/sys/net80211/ieee80211_output.c#32 (text+ko) ====
@@ -537,9 +537,8 @@
goto bad;
}
m = ieee80211_encap_fastframe(ic, m, &eh, m2, &eh2);
- if (m == NULL) {
+ if (m == NULL)
goto bad;
- }
} else {
/*
* Normal frame.
@@ -768,6 +767,8 @@
llc->llc_snap.org_code[2] = ATH_FF_SNAP_ORGCODE_2;
llc->llc_snap.ether_type = htons(ATH_FF_ETH_TYPE);
+ ic->ic_stats.is_ff_encap++;
+
return m1;
}
==== //depot/projects/wifi/tools/tools/ath/80211stats.c#8 (text+ko) ====
@@ -144,6 +144,11 @@
STAT(ps_unassoc, "ps-poll received for unassociated station");
STAT(ps_badaid, "ps-poll received with invalid association id");
STAT(ps_qempty, "ps-poll received with nothing to send");
+ STAT(ff_badhdr, "fast frame rx'd w/ bad hdr");
+ STAT(ff_tooshort, "fast frame rx decap error");
+ STAT(ff_split, "fast frame rx split error");
+ STAT(ff_decap, "fast frames decap'd");
+ STAT(ff_encap, "fast frames encap'd for tx");
#undef STAT
#undef N
}
More information about the p4-projects
mailing list