Date: Wed, 10 Sep 2008 17:58:49 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 149552 for review Message-ID: <200809101758.m8AHwnVA051525@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=149552 Change 149552 by sam@sam_ebb on 2008/09/10 17:57:49 Checkpoint support for sending BAR: o set the start seq# from ni_txseqs o add callback for response processing for driver to override o don't commit the new seq# until we believe the BAR has been delivered; this is problematic for drivers that don't give back ACK status (so they'll just have to assume it goes through) NB: there is no locking and we should allocate tap struct's on demand instead of statically allocating them in the node NB: we are super aggressive sending BAR as it's delivery is critical; this may need to be rethought NB: we reuse the addba request state which is a hack done w/ the assumption there should never be an addba request pending at the same time we send BAR Affected files ... .. //depot/projects/vap/sys/net80211/ieee80211_ht.c#48 edit .. //depot/projects/vap/sys/net80211/ieee80211_ht.h#21 edit .. //depot/projects/vap/sys/net80211/ieee80211_var.h#52 edit Differences ... ==== //depot/projects/vap/sys/net80211/ieee80211_ht.c#48 (text+ko) ==== @@ -86,6 +86,8 @@ int ieee80211_addba_timeout = -1; /* timeout waiting for ADDBA response */ int ieee80211_addba_backoff = -1; /* backoff after max ADDBA requests */ int ieee80211_addba_maxtries = 3; /* max ADDBA requests before backoff */ +int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */ +int ieee80211_bar_maxtries = 50; /* max BAR requests before DELBA */ /* * Setup HT parameters that depends on the clock frequency. @@ -98,6 +100,7 @@ #endif ieee80211_addba_timeout = msecs_to_ticks(250); ieee80211_addba_backoff = msecs_to_ticks(10*1000); + ieee80211_bar_timeout = msecs_to_ticks(250); } SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_setup, NULL); @@ -113,6 +116,8 @@ struct ieee80211_tx_ampdu *tap); static void ieee80211_aggr_recv_action(struct ieee80211_node *ni, const uint8_t *frm, const uint8_t *efrm); +static void ieee80211_bar_response(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap, int status); void ieee80211_ht_attach(struct ieee80211com *ic) @@ -124,6 +129,7 @@ ic->ic_addba_request = ieee80211_addba_request; ic->ic_addba_response = ieee80211_addba_response; ic->ic_addba_stop = ieee80211_addba_stop; + ic->ic_bar_response = ieee80211_bar_response; ic->ic_htprotmode = IEEE80211_PROT_RTSCTS; ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE; @@ -802,6 +808,7 @@ for (ac = 0; ac < WME_NUM_AC; ac++) { tap = &ni->ni_tx_ampdu[ac]; tap->txa_ac = ac; + tap->txa_ni = ni; /* NB: further initialization deferred */ } ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU; @@ -1485,7 +1492,7 @@ struct ieee80211_tx_ampdu *tap, int status, int baparamset, int batimeout) { - int bufsiz; + int bufsiz, tid; /* XXX locking */ addba_stop_timeout(tap); @@ -1494,7 +1501,11 @@ /* XXX override our request? */ tap->txa_wnd = (bufsiz == 0) ? IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX); + /* XXX AC/TID */ + tid = MS(baparamset, IEEE80211_BAPS_TID); + tap->txa_seqstart = tap->txa_start = ni->ni_txseqs[tid]; tap->txa_flags |= IEEE80211_AGGR_RUNNING; + tap->txa_attempts = 0; } else { /* mark tid so we don't try again */ tap->txa_flags |= IEEE80211_AGGR_NAK; @@ -1868,6 +1879,7 @@ uint16_t args[4]; /* XXX locking */ + tap->txa_flags &= ~IEEE80211_AGGR_BARPEND; if (IEEE80211_AMPDU_RUNNING(tap)) { IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni, "%s: stop BA stream for AC %d (reason %d)", @@ -1888,6 +1900,83 @@ } } +static void +bar_timeout(void *arg) +{ + struct ieee80211_tx_ampdu *tap = arg; + struct ieee80211_node *ni = tap->txa_ni; + + KASSERT((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0, + ("bar/addba collision, flags 0x%x", tap->txa_flags)); + + IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, + ni, "%s: tid %u flags 0x%x attempts %d", __func__, + tap->txa_ac, tap->txa_flags, tap->txa_attempts); + + /* guard against race with bar_tx_complete */ + if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0) + return; + /* XXX ? */ + if (tap->txa_attempts >= ieee80211_bar_maxtries) + ieee80211_ampdu_stop(ni, tap, IEEE80211_REASON_TIMEOUT); + else + ieee80211_send_bar(ni, tap, tap->txa_seqpending); +} + +static void +bar_start_timer(struct ieee80211_tx_ampdu *tap) +{ + callout_reset(&tap->txa_timer, ieee80211_bar_timeout, bar_timeout, tap); +} + +static void +bar_stop_timer(struct ieee80211_tx_ampdu *tap) +{ + callout_stop(&tap->txa_timer); +} + +static void +bar_tx_complete(struct ieee80211_node *ni, void *arg, int status) +{ + struct ieee80211_tx_ampdu *tap = arg; + + IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, + ni, "%s: tid %u flags 0x%x pending %d status %d", + __func__, tap->txa_ac, tap->txa_flags, + callout_pending(&tap->txa_timer), status); + + /* XXX locking */ + if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) && + callout_pending(&tap->txa_timer)) { + struct ieee80211com *ic = ni->ni_ic; + + if (status) /* ACK'd */ + bar_stop_timer(tap); + ic->ic_bar_response(ni, tap, status); + } else { + /* NB: just let timer expire so we pace requests */ + } +} + +static void +ieee80211_bar_response(struct ieee80211_node *ni, + struct ieee80211_tx_ampdu *tap, int status) +{ + + if (status != 0) { /* got ACK */ + IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, + ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u", + tap->txa_start, + IEEE80211_SEQ_ADD(tap->txa_start, tap->txa_wnd-1), + tap->txa_qframes, tap->txa_seqpending, + WME_AC_TO_TID(tap->txa_ac)); + + /* NB: timer already stopped in bar_tx_complete */ + tap->txa_start = tap->txa_seqpending; + tap->txa_flags &= ~IEEE80211_AGGR_BARPEND; + } +} + /* * Transmit a BAR frame to the specified node. The * BAR contents are drawn from the supplied aggregation @@ -1904,17 +1993,30 @@ struct ieee80211com *ic = ni->ni_ic; struct ieee80211_frame_bar *bar; struct mbuf *m; + uint16_t barctl, barseqctl; uint8_t *frm; - uint16_t barctl, barseqctl; int tid, ret; + if ((tap->txa_flags & IEEE80211_AGGR_RUNNING) == 0) { + /* no ADDBA response, should not happen */ + /* XXX stat+msg */ + return EINVAL; + } + /* XXX locking */ + bar_stop_timer(tap); + ieee80211_ref_node(ni); - m = ieee80211_getmgtframe(&frm, ic->ic_headroom, - sizeof(struct ieee80211_frame_bar)); + m = ieee80211_getmgtframe(&frm, ic->ic_headroom, sizeof(*bar)); if (m == NULL) senderr(ENOMEM, is_tx_nobuf); + if (!ieee80211_add_callback(m, bar_tx_complete, tap)) { + m_freem(m); + senderr(ENOMEM, is_tx_nobuf); /* XXX */ + /* NOTREACHED */ + } + bar = mtod(m, struct ieee80211_frame_bar *); bar->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR; @@ -1938,11 +2040,29 @@ IEEE80211_NODE_STAT(ni, tx_mgmt); /* XXX tx_ctl? */ + /* XXX locking */ + /* init/bump attempts counter */ + if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0) + tap->txa_attempts = 1; + else + tap->txa_attempts++; + tap->txa_seqpending = seq; + tap->txa_flags |= IEEE80211_AGGR_BARPEND; + IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N, ni, "send BAR: tid %u ctl 0x%x start %u (attempt %d)", tid, barctl, seq, tap->txa_attempts); - return ic->ic_raw_xmit(ni, m, NULL); + ret = ic->ic_raw_xmit(ni, m, NULL); + if (ret != 0) { + /* xmit failed, clear state flag */ + tap->txa_flags &= ~IEEE80211_AGGR_BARPEND; + goto bad; + } + /* XXX hack against tx complete happening before timer is started */ + if (tap->txa_flags & IEEE80211_AGGR_BARPEND) + bar_start_timer(tap); + return 0; bad: ieee80211_free_node(ni); return ret; ==== //depot/projects/vap/sys/net80211/ieee80211_ht.h#21 (text+ko) ==== @@ -38,12 +38,14 @@ typedef uint16_t ieee80211_seq; struct ieee80211_tx_ampdu { + struct ieee80211_node *txa_ni; /* back pointer */ u_short txa_flags; #define IEEE80211_AGGR_IMMEDIATE 0x0001 /* BA policy */ #define IEEE80211_AGGR_XCHGPEND 0x0002 /* ADDBA response pending */ #define IEEE80211_AGGR_RUNNING 0x0004 /* ADDBA response received */ #define IEEE80211_AGGR_SETUP 0x0008 /* deferred state setup */ #define IEEE80211_AGGR_NAK 0x0010 /* peer NAK'd ADDBA request */ +#define IEEE80211_AGGR_BARPEND 0x0020 /* BAR response pending */ uint8_t txa_ac; uint8_t txa_token; /* dialog token */ int txa_lastsample; /* ticks @ last traffic sample */ @@ -53,9 +55,10 @@ short txa_qframes; /* data queued (frames) */ ieee80211_seq txa_seqstart; ieee80211_seq txa_start; + ieee80211_seq txa_seqpending; /* new start pending BAR response */ uint16_t txa_wnd; /* BA window size */ - uint8_t txa_attempts; /* # ADDBA requests w/o a response */ - int txa_nextrequest;/* soonest to make next ADDBA request */ + uint8_t txa_attempts; /* # ADDBA/BAR requests w/o a response*/ + int txa_nextrequest;/* soonest to make next request */ struct callout txa_timer; void *txa_private; /* driver-private storage */ }; @@ -187,8 +190,8 @@ struct ieee80211_tx_ampdu *); void ieee80211_ampdu_stop(struct ieee80211_node *, struct ieee80211_tx_ampdu *, int); -int ieee80211_send_bar(struct ieee80211_node *, - struct ieee80211_tx_ampdu *tap, ieee80211_seq seq); +int ieee80211_send_bar(struct ieee80211_node *, struct ieee80211_tx_ampdu *, + ieee80211_seq); int ieee80211_send_action(struct ieee80211_node *, int, int, uint16_t [4]); uint8_t *ieee80211_add_htcap(uint8_t *, struct ieee80211_node *); ==== //depot/projects/vap/sys/net80211/ieee80211_var.h#52 (text+ko) ==== @@ -273,6 +273,9 @@ int status, int baparamset, int batimeout); void (*ic_addba_stop)(struct ieee80211_node *, struct ieee80211_tx_ampdu *); + /* BAR response received */ + void (*ic_bar_response)(struct ieee80211_node *, + struct ieee80211_tx_ampdu *, int status); }; struct ieee80211_aclator;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200809101758.m8AHwnVA051525>