From owner-p4-projects@FreeBSD.ORG Mon Jan 10 04:46:06 2005 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 7917F16A4D1; Mon, 10 Jan 2005 04:46:06 +0000 (GMT) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 507CB16A4CF for ; Mon, 10 Jan 2005 04:46:06 +0000 (GMT) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 0BFF643D39 for ; Mon, 10 Jan 2005 04:46:06 +0000 (GMT) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.1/8.13.1) with ESMTP id j0A4k6Pl033674 for ; Mon, 10 Jan 2005 04:46:06 GMT (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.1/8.13.1/Submit) id j0A4k5jq033671 for perforce@freebsd.org; Mon, 10 Jan 2005 04:46:05 GMT (envelope-from sam@freebsd.org) Date: Mon, 10 Jan 2005 04:46:05 GMT Message-Id: <200501100446.j0A4k5jq033671@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to sam@freebsd.org using -f From: Sam Leffler To: Perforce Change Reviews Subject: PERFORCE change 68617 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 10 Jan 2005 04:46:07 -0000 http://perforce.freebsd.org/chv.cgi?CH=68617 Change 68617 by sam@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 }