Deleted Added
full compact
ieee80211_ht.c (193840) ieee80211_ht.c (195377)
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__
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 193840 2009-06-09 16:32:07Z sam $");
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>
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>
50#include <net80211/ieee80211_input.h>
51
52/* define here, used throughout file */
53#define MS(_v, _f) (((_v) & _f) >> _f##_S)
54#define SM(_v, _f) (((_v) << _f##_S) & _f)
55
56const struct ieee80211_mcs_rates ieee80211_htrates[16] = {
57 { 13, 14, 27, 30 }, /* MCS 0 */

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

99 "ADDBA request backoff (ms)");
100static int ieee80211_addba_maxtries = 3;/* max ADDBA requests before backoff */
101SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLTYPE_INT | CTLFLAG_RW,
102 &ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff");
103
104static int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */
105static int ieee80211_bar_maxtries = 50;/* max BAR requests before DELBA */
106
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
107/*
108 * Setup HT parameters that depends on the clock frequency.
109 */
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
110static void
118static void
111ieee80211_ht_setup(void)
119ieee80211_ht_init(void)
112{
120{
121 /*
122 * Setup HT parameters that depends on the clock frequency.
123 */
113#ifdef IEEE80211_AMPDU_AGE
114 ieee80211_ampdu_age = msecs_to_ticks(500);
115#endif
116 ieee80211_addba_timeout = msecs_to_ticks(250);
117 ieee80211_addba_backoff = msecs_to_ticks(10*1000);
118 ieee80211_bar_timeout = msecs_to_ticks(250);
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);
119}
152}
120SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_setup, NULL);
153SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_init, NULL);
121
122static int ieee80211_ampdu_enable(struct ieee80211_node *ni,
123 struct ieee80211_tx_ampdu *tap);
124static int ieee80211_addba_request(struct ieee80211_node *ni,
125 struct ieee80211_tx_ampdu *tap,
126 int dialogtoken, int baparamset, int batimeout);
127static int ieee80211_addba_response(struct ieee80211_node *ni,
128 struct ieee80211_tx_ampdu *tap,
129 int code, int baparamset, int batimeout);
130static void ieee80211_addba_stop(struct ieee80211_node *ni,
131 struct ieee80211_tx_ampdu *tap);
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);
132static void ieee80211_aggr_recv_action(struct ieee80211_node *ni,
133 const uint8_t *frm, const uint8_t *efrm);
134static void ieee80211_bar_response(struct ieee80211_node *ni,
135 struct ieee80211_tx_ampdu *tap, int status);
136static void ampdu_tx_stop(struct ieee80211_tx_ampdu *tap);
137static void bar_stop_timer(struct ieee80211_tx_ampdu *tap);
138static int ampdu_rx_start(struct ieee80211_node *, struct ieee80211_rx_ampdu *,
139 int baparamset, int batimeout, int baseqctl);
140static void ampdu_rx_stop(struct ieee80211_node *, struct ieee80211_rx_ampdu *);
141
142void
143ieee80211_ht_attach(struct ieee80211com *ic)
144{
145 /* setup default aggregation policy */
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 */
146 ic->ic_recv_action = ieee80211_aggr_recv_action;
177 ic->ic_recv_action = ieee80211_recv_action;
147 ic->ic_send_action = ieee80211_send_action;
148 ic->ic_ampdu_enable = ieee80211_ampdu_enable;
149 ic->ic_addba_request = ieee80211_addba_request;
150 ic->ic_addba_response = ieee80211_addba_response;
151 ic->ic_addba_stop = ieee80211_addba_stop;
152 ic->ic_bar_response = ieee80211_bar_response;
153 ic->ic_ampdu_rx_start = ampdu_rx_start;
154 ic->ic_ampdu_rx_stop = ampdu_rx_stop;

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

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

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

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

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

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

--- 237 unchanged lines hidden ---
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 ---