Deleted Added
sdiff udiff text old ( 193840 ) new ( 195377 )
full compact
1/*-
2 * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27#ifdef __FreeBSD__
28__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_ht.c 195377 2009-07-05 17:59:19Z sam $");
29#endif
30
31/*
32 * IEEE 802.11n protocol support.
33 */
34
35#include "opt_inet.h"
36#include "opt_wlan.h"

--- 5 unchanged lines hidden (view full) ---

42
43#include <sys/socket.h>
44
45#include <net/if.h>
46#include <net/if_media.h>
47#include <net/ethernet.h>
48
49#include <net80211/ieee80211_var.h>
50#include <net80211/ieee80211_action.h>
51#include <net80211/ieee80211_input.h>
52
53/* define here, used throughout file */
54#define MS(_v, _f) (((_v) & _f) >> _f##_S)
55#define SM(_v, _f) (((_v) << _f##_S) & _f)
56
57const struct ieee80211_mcs_rates ieee80211_htrates[16] = {
58 { 13, 14, 27, 30 }, /* MCS 0 */

--- 41 unchanged lines hidden (view full) ---

100 "ADDBA request backoff (ms)");
101static int ieee80211_addba_maxtries = 3;/* max ADDBA requests before backoff */
102SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLTYPE_INT | CTLFLAG_RW,
103 &ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff");
104
105static int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */
106static int ieee80211_bar_maxtries = 50;/* max BAR requests before DELBA */
107
108static ieee80211_recv_action_func ht_recv_action_ba_addba_request;
109static ieee80211_recv_action_func ht_recv_action_ba_addba_response;
110static ieee80211_recv_action_func ht_recv_action_ba_delba;
111static ieee80211_recv_action_func ht_recv_action_ht_mimopwrsave;
112static ieee80211_recv_action_func ht_recv_action_ht_txchwidth;
113
114static ieee80211_send_action_func ht_send_action_ba_addba;
115static ieee80211_send_action_func ht_send_action_ba_delba;
116static ieee80211_send_action_func ht_send_action_ht_txchwidth;
117
118static void
119ieee80211_ht_init(void)
120{
121 /*
122 * Setup HT parameters that depends on the clock frequency.
123 */
124#ifdef IEEE80211_AMPDU_AGE
125 ieee80211_ampdu_age = msecs_to_ticks(500);
126#endif
127 ieee80211_addba_timeout = msecs_to_ticks(250);
128 ieee80211_addba_backoff = msecs_to_ticks(10*1000);
129 ieee80211_bar_timeout = msecs_to_ticks(250);
130 /*
131 * Register action frame handlers.
132 */
133 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA,
134 IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_recv_action_ba_addba_request);
135 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA,
136 IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_recv_action_ba_addba_response);
137 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA,
138 IEEE80211_ACTION_BA_DELBA, ht_recv_action_ba_delba);
139 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT,
140 IEEE80211_ACTION_HT_MIMOPWRSAVE, ht_recv_action_ht_mimopwrsave);
141 ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT,
142 IEEE80211_ACTION_HT_TXCHWIDTH, ht_recv_action_ht_txchwidth);
143
144 ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA,
145 IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_send_action_ba_addba);
146 ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA,
147 IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_send_action_ba_addba);
148 ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA,
149 IEEE80211_ACTION_BA_DELBA, ht_send_action_ba_delba);
150 ieee80211_send_action_register(IEEE80211_ACTION_CAT_HT,
151 IEEE80211_ACTION_HT_TXCHWIDTH, ht_send_action_ht_txchwidth);
152}
153SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_init, NULL);
154
155static int ieee80211_ampdu_enable(struct ieee80211_node *ni,
156 struct ieee80211_tx_ampdu *tap);
157static int ieee80211_addba_request(struct ieee80211_node *ni,
158 struct ieee80211_tx_ampdu *tap,
159 int dialogtoken, int baparamset, int batimeout);
160static int ieee80211_addba_response(struct ieee80211_node *ni,
161 struct ieee80211_tx_ampdu *tap,
162 int code, int baparamset, int batimeout);
163static void ieee80211_addba_stop(struct ieee80211_node *ni,
164 struct ieee80211_tx_ampdu *tap);
165static void ieee80211_bar_response(struct ieee80211_node *ni,
166 struct ieee80211_tx_ampdu *tap, int status);
167static void ampdu_tx_stop(struct ieee80211_tx_ampdu *tap);
168static void bar_stop_timer(struct ieee80211_tx_ampdu *tap);
169static int ampdu_rx_start(struct ieee80211_node *, struct ieee80211_rx_ampdu *,
170 int baparamset, int batimeout, int baseqctl);
171static void ampdu_rx_stop(struct ieee80211_node *, struct ieee80211_rx_ampdu *);
172
173void
174ieee80211_ht_attach(struct ieee80211com *ic)
175{
176 /* setup default aggregation policy */
177 ic->ic_recv_action = ieee80211_recv_action;
178 ic->ic_send_action = ieee80211_send_action;
179 ic->ic_ampdu_enable = ieee80211_ampdu_enable;
180 ic->ic_addba_request = ieee80211_addba_request;
181 ic->ic_addba_response = ieee80211_addba_response;
182 ic->ic_addba_stop = ieee80211_addba_stop;
183 ic->ic_bar_response = ieee80211_bar_response;
184 ic->ic_ampdu_rx_start = ampdu_rx_start;
185 ic->ic_ampdu_rx_stop = ampdu_rx_stop;

--- 1420 unchanged lines hidden (view full) ---

1606}
1607
1608/*
1609 * Process a received action frame using the default aggregation
1610 * policy. We intercept ADDBA-related frames and use them to
1611 * update our aggregation state. All other frames are passed up
1612 * for processing by ieee80211_recv_action.
1613 */
1614static int
1615ht_recv_action_ba_addba_request(struct ieee80211_node *ni,
1616 const struct ieee80211_frame *wh,
1617 const uint8_t *frm, const uint8_t *efrm)
1618{
1619 struct ieee80211com *ic = ni->ni_ic;
1620 struct ieee80211vap *vap = ni->ni_vap;
1621 struct ieee80211_rx_ampdu *rap;
1622 uint8_t dialogtoken;
1623 uint16_t baparamset, batimeout, baseqctl;
1624 uint16_t args[4];
1625 int tid;
1626
1627 dialogtoken = frm[2];
1628 baparamset = LE_READ_2(frm+3);
1629 batimeout = LE_READ_2(frm+5);
1630 baseqctl = LE_READ_2(frm+7);
1631
1632 tid = MS(baparamset, IEEE80211_BAPS_TID);
1633
1634 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1635 "recv ADDBA request: dialogtoken %u baparamset 0x%x "
1636 "(tid %d bufsiz %d) batimeout %d baseqctl %d:%d",
1637 dialogtoken, baparamset,
1638 tid, MS(baparamset, IEEE80211_BAPS_BUFSIZ),
1639 batimeout,
1640 MS(baseqctl, IEEE80211_BASEQ_START),
1641 MS(baseqctl, IEEE80211_BASEQ_FRAG));
1642
1643 rap = &ni->ni_rx_ampdu[tid];
1644
1645 /* Send ADDBA response */
1646 args[0] = dialogtoken;
1647 /*
1648 * NB: We ack only if the sta associated with HT and
1649 * the ap is configured to do AMPDU rx (the latter
1650 * violates the 11n spec and is mostly for testing).
1651 */
1652 if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
1653 (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)) {
1654 /* XXX handle ampdu_rx_start failure */
1655 ic->ic_ampdu_rx_start(ni, rap,
1656 baparamset, batimeout, baseqctl);
1657
1658 args[1] = IEEE80211_STATUS_SUCCESS;
1659 } else {
1660 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1661 ni, "reject ADDBA request: %s",
1662 ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
1663 "administratively disabled" :
1664 "not negotiated for station");
1665 vap->iv_stats.is_addba_reject++;
1666 args[1] = IEEE80211_STATUS_UNSPECIFIED;
1667 }
1668 /* XXX honor rap flags? */
1669 args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
1670 | SM(tid, IEEE80211_BAPS_TID)
1671 | SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
1672 ;
1673 args[3] = 0;
1674 ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1675 IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
1676 return 0;
1677}
1678
1679static int
1680ht_recv_action_ba_addba_response(struct ieee80211_node *ni,
1681 const struct ieee80211_frame *wh,
1682 const uint8_t *frm, const uint8_t *efrm)
1683{
1684 struct ieee80211com *ic = ni->ni_ic;
1685 struct ieee80211vap *vap = ni->ni_vap;
1686 struct ieee80211_tx_ampdu *tap;
1687 uint8_t dialogtoken, policy;
1688 uint16_t baparamset, batimeout, code;
1689 int tid, ac, bufsiz;
1690
1691 dialogtoken = frm[2];
1692 code = LE_READ_2(frm+3);
1693 baparamset = LE_READ_2(frm+5);
1694 tid = MS(baparamset, IEEE80211_BAPS_TID);
1695 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1696 policy = MS(baparamset, IEEE80211_BAPS_POLICY);
1697 batimeout = LE_READ_2(frm+7);
1698
1699 ac = TID_TO_WME_AC(tid);
1700 tap = &ni->ni_tx_ampdu[ac];
1701 if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
1702 IEEE80211_DISCARD_MAC(vap,
1703 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1704 ni->ni_macaddr, "ADDBA response",
1705 "no pending ADDBA, tid %d dialogtoken %u "
1706 "code %d", tid, dialogtoken, code);
1707 vap->iv_stats.is_addba_norequest++;
1708 return 0;
1709 }
1710 if (dialogtoken != tap->txa_token) {
1711 IEEE80211_DISCARD_MAC(vap,
1712 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1713 ni->ni_macaddr, "ADDBA response",
1714 "dialogtoken mismatch: waiting for %d, "
1715 "received %d, tid %d code %d",
1716 tap->txa_token, dialogtoken, tid, code);
1717 vap->iv_stats.is_addba_badtoken++;
1718 return 0;
1719 }
1720 /* NB: assumes IEEE80211_AGGR_IMMEDIATE is 1 */
1721 if (policy != (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE)) {
1722 IEEE80211_DISCARD_MAC(vap,
1723 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1724 ni->ni_macaddr, "ADDBA response",
1725 "policy mismatch: expecting %s, "
1726 "received %s, tid %d code %d",
1727 tap->txa_flags & IEEE80211_AGGR_IMMEDIATE,
1728 policy, tid, code);
1729 vap->iv_stats.is_addba_badpolicy++;
1730 return 0;
1731 }
1732#if 0
1733 /* XXX we take MIN in ieee80211_addba_response */
1734 if (bufsiz > IEEE80211_AGGR_BAWMAX) {
1735 IEEE80211_DISCARD_MAC(vap,
1736 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1737 ni->ni_macaddr, "ADDBA response",
1738 "BA window too large: max %d, "
1739 "received %d, tid %d code %d",
1740 bufsiz, IEEE80211_AGGR_BAWMAX, tid, code);
1741 vap->iv_stats.is_addba_badbawinsize++;
1742 return 0;
1743 }
1744#endif
1745 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1746 "recv ADDBA response: dialogtoken %u code %d "
1747 "baparamset 0x%x (tid %d bufsiz %d) batimeout %d",
1748 dialogtoken, code, baparamset, tid, bufsiz,
1749 batimeout);
1750 ic->ic_addba_response(ni, tap, code, baparamset, batimeout);
1751 return 0;
1752}
1753
1754static int
1755ht_recv_action_ba_delba(struct ieee80211_node *ni,
1756 const struct ieee80211_frame *wh,
1757 const uint8_t *frm, const uint8_t *efrm)
1758{
1759 struct ieee80211com *ic = ni->ni_ic;
1760 struct ieee80211_rx_ampdu *rap;
1761 struct ieee80211_tx_ampdu *tap;
1762 uint16_t baparamset, code;
1763 int tid, ac;
1764
1765 baparamset = LE_READ_2(frm+2);
1766 code = LE_READ_2(frm+4);
1767
1768 tid = MS(baparamset, IEEE80211_DELBAPS_TID);
1769
1770 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1771 "recv DELBA: baparamset 0x%x (tid %d initiator %d) "
1772 "code %d", baparamset, tid,
1773 MS(baparamset, IEEE80211_DELBAPS_INIT), code);
1774
1775 if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
1776 ac = TID_TO_WME_AC(tid);
1777 tap = &ni->ni_tx_ampdu[ac];
1778 ic->ic_addba_stop(ni, tap);
1779 } else {
1780 rap = &ni->ni_rx_ampdu[tid];
1781 ic->ic_ampdu_rx_stop(ni, rap);
1782 }
1783 return 0;
1784}
1785
1786static int
1787ht_recv_action_ht_txchwidth(struct ieee80211_node *ni,
1788 const struct ieee80211_frame *wh,
1789 const uint8_t *frm, const uint8_t *efrm)
1790{
1791 int chw;
1792
1793 chw = (frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040) ? 40 : 20;
1794
1795 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1796 "%s: HT txchwidth, width %d%s",
1797 __func__, chw, ni->ni_chw != chw ? "*" : "");
1798 if (chw != ni->ni_chw) {
1799 ni->ni_chw = chw;
1800 /* XXX notify on change */
1801 }
1802 return 0;
1803}
1804
1805static int
1806ht_recv_action_ht_mimopwrsave(struct ieee80211_node *ni,
1807 const struct ieee80211_frame *wh,
1808 const uint8_t *frm, const uint8_t *efrm)
1809{
1810 const struct ieee80211_action_ht_mimopowersave *mps =
1811 (const struct ieee80211_action_ht_mimopowersave *) frm;
1812
1813 /* XXX check iv_htcaps */
1814 if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_ENA)
1815 ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
1816 else
1817 ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
1818 if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_MODE)
1819 ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
1820 else
1821 ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
1822 /* XXX notify on change */
1823 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1824 "%s: HT MIMO PS (%s%s)", __func__,
1825 (ni->ni_flags & IEEE80211_NODE_MIMO_PS) ? "on" : "off",
1826 (ni->ni_flags & IEEE80211_NODE_MIMO_RTS) ? "+rts" : ""
1827 );
1828 return 0;
1829}
1830
1831/*
1832 * Transmit processing.
1833 */
1834
1835/*
1836 * Check if A-MPDU should be requested/enabled for a stream.
1837 * We require a traffic rate above a per-AC threshold and we
1838 * also handle backoff from previous failed attempts.

--- 98 unchanged lines hidden (view full) ---

1937 ni, "%s: stop BA stream for AC %d (reason %d)",
1938 __func__, tap->txa_ac, reason);
1939 vap->iv_stats.is_ampdu_stop++;
1940
1941 ic->ic_addba_stop(ni, tap);
1942 args[0] = WME_AC_TO_TID(tap->txa_ac);
1943 args[1] = IEEE80211_DELBAPS_INIT;
1944 args[2] = reason; /* XXX reason code */
1945 ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1946 IEEE80211_ACTION_BA_DELBA, args);
1947 } else {
1948 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1949 ni, "%s: BA stream for AC %d not running (reason %d)",
1950 __func__, tap->txa_ac, reason);
1951 vap->iv_stats.is_ampdu_stop_failed++;
1952 }
1953}

--- 161 unchanged lines hidden (view full) ---

2115 bar_start_timer(tap);
2116 return 0;
2117bad:
2118 ieee80211_free_node(ni);
2119 return ret;
2120#undef senderr
2121}
2122
2123static int
2124ht_action_output(struct ieee80211_node *ni, struct mbuf *m)
2125{
2126 struct ieee80211_bpf_params params;
2127
2128 memset(&params, 0, sizeof(params));
2129 params.ibp_pri = WME_AC_VO;
2130 params.ibp_rate0 = ni->ni_txparms->mgmtrate;
2131 /* NB: we know all frames are unicast */
2132 params.ibp_try0 = ni->ni_txparms->maxretry;
2133 params.ibp_power = ni->ni_txpower;
2134 return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
2135 &params);
2136}
2137
2138#define ADDSHORT(frm, v) do { \
2139 frm[0] = (v) & 0xff; \
2140 frm[1] = (v) >> 8; \
2141 frm += 2; \
2142} while (0)
2143
2144/*
2145 * Send an action management frame. The arguments are stuff
2146 * into a frame without inspection; the caller is assumed to
2147 * prepare them carefully (e.g. based on the aggregation state).
2148 */
2149static int
2150ht_send_action_ba_addba(struct ieee80211_node *ni,
2151 int category, int action, void *arg0)
2152{
2153 struct ieee80211vap *vap = ni->ni_vap;
2154 struct ieee80211com *ic = ni->ni_ic;
2155 uint16_t *args = arg0;
2156 struct mbuf *m;
2157 uint8_t *frm;
2158
2159 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2160 "send ADDBA %s: dialogtoken %d "
2161 "baparamset 0x%x (tid %d) batimeout 0x%x baseqctl 0x%x",
2162 (action == IEEE80211_ACTION_BA_ADDBA_REQUEST) ?
2163 "request" : "response",
2164 args[0], args[1], MS(args[1], IEEE80211_BAPS_TID),
2165 args[2], args[3]);
2166
2167 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2168 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
2169 ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
2170 ieee80211_ref_node(ni);
2171
2172 m = ieee80211_getmgtframe(&frm,
2173 ic->ic_headroom + sizeof(struct ieee80211_frame),
2174 sizeof(uint16_t) /* action+category */
2175 /* XXX may action payload */
2176 + sizeof(struct ieee80211_action_ba_addbaresponse)
2177 );
2178 if (m != NULL) {
2179 *frm++ = category;
2180 *frm++ = action;
2181 *frm++ = args[0]; /* dialog token */
2182 ADDSHORT(frm, args[1]); /* baparamset */
2183 ADDSHORT(frm, args[2]); /* batimeout */
2184 if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST)
2185 ADDSHORT(frm, args[3]); /* baseqctl */
2186 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2187 return ht_action_output(ni, m);
2188 } else {
2189 vap->iv_stats.is_tx_nobuf++;
2190 ieee80211_free_node(ni);
2191 return ENOMEM;
2192 }
2193}
2194
2195static int
2196ht_send_action_ba_delba(struct ieee80211_node *ni,
2197 int category, int action, void *arg0)
2198{
2199 struct ieee80211vap *vap = ni->ni_vap;
2200 struct ieee80211com *ic = ni->ni_ic;
2201 uint16_t *args = arg0;
2202 struct mbuf *m;
2203 uint16_t baparamset;
2204 uint8_t *frm;
2205
2206 baparamset = SM(args[0], IEEE80211_DELBAPS_TID)
2207 | args[1]
2208 ;
2209 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2210 "send DELBA action: tid %d, initiator %d reason %d",
2211 args[0], args[1], args[2]);
2212
2213 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2214 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
2215 ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
2216 ieee80211_ref_node(ni);
2217
2218 m = ieee80211_getmgtframe(&frm,
2219 ic->ic_headroom + sizeof(struct ieee80211_frame),
2220 sizeof(uint16_t) /* action+category */
2221 /* XXX may action payload */
2222 + sizeof(struct ieee80211_action_ba_addbaresponse)
2223 );
2224 if (m != NULL) {
2225 *frm++ = category;
2226 *frm++ = action;
2227 ADDSHORT(frm, baparamset);
2228 ADDSHORT(frm, args[2]); /* reason code */
2229 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2230 return ht_action_output(ni, m);
2231 } else {
2232 vap->iv_stats.is_tx_nobuf++;
2233 ieee80211_free_node(ni);
2234 return ENOMEM;
2235 }
2236}
2237
2238static int
2239ht_send_action_ht_txchwidth(struct ieee80211_node *ni,
2240 int category, int action, void *arg0)
2241{
2242 struct ieee80211vap *vap = ni->ni_vap;
2243 struct ieee80211com *ic = ni->ni_ic;
2244 struct mbuf *m;
2245 uint8_t *frm;
2246
2247 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2248 "send HT txchwidth: width %d",
2249 IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 40 : 20);
2250
2251 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2252 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
2253 ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
2254 ieee80211_ref_node(ni);
2255
2256 m = ieee80211_getmgtframe(&frm,
2257 ic->ic_headroom + sizeof(struct ieee80211_frame),
2258 sizeof(uint16_t) /* action+category */
2259 /* XXX may action payload */
2260 + sizeof(struct ieee80211_action_ba_addbaresponse)
2261 );
2262 if (m != NULL) {
2263 *frm++ = category;
2264 *frm++ = action;
2265 *frm++ = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
2266 IEEE80211_A_HT_TXCHWIDTH_2040 :
2267 IEEE80211_A_HT_TXCHWIDTH_20;
2268 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2269 return ht_action_output(ni, m);
2270 } else {
2271 vap->iv_stats.is_tx_nobuf++;
2272 ieee80211_free_node(ni);
2273 return ENOMEM;
2274 }
2275}
2276#undef ADDSHORT
2277
2278/*
2279 * Construct the MCS bit mask for inclusion
2280 * in an HT information element.
2281 */
2282static void
2283ieee80211_set_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
2284{

--- 237 unchanged lines hidden ---