kern/143627: [ieee80211] A bug in ht_send_action_ba_addba causes
net80211 to send malformed ADDBA response frames
Alexander Egorenkov
egorenar at gmail.com
Sun Feb 7 08:40:01 UTC 2010
>Number: 143627
>Category: kern
>Synopsis: [ieee80211] A bug in ht_send_action_ba_addba causes net80211 to send malformed ADDBA response frames
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Sun Feb 07 08:40:00 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator: Alexander Egorenkov
>Release: FreeBSD 8.0 STABLE
>Organization:
>Environment:
FreeBSD dantooine 8.0-RELEASE FreeBSD 8.0-RELEASE #2: Tue Dec 15 17:56:06 CET 2009 root at dantooine:/usr/obj/usr/src/sys/MYKERNEL i386
>Description:
I'm developing an 802.11n device driver and added A-MPDU Rx support to the driver.
While testing this feature, i noticed that net80211 stack sends malformed ADDBA response frames in response to ADDBA requests from AP. The ADDBA response frames sent by net80211 stack contain 2 bytes fewer. I analyzed this problem and found out that the problem lies in the function ieee80211_ht.c:ht_send_action_ba_addba:2178.
>How-To-Repeat:
>Fix:
Here is the code snippet which causes the problem:
if (m != NULL) {
*frm++ = category;
*frm++ = action;
*frm++ = args[0]; /* dialog token */
ADDSHORT(frm, args[1]); /* baparamset */
ADDSHORT(frm, args[2]); /* batimeout */
if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST)
ADDSHORT(frm, args[3]); /* baseqctl */
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
return ht_action_output(ni, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
return ENOMEM;
}
I took a look into the 802.11 specification and found out that
an ADDBA response has the same size as an ADDBA request but
an ADDBA response has a status code after the dialog token field and
doesn't have a block starting sequence control (baseqctl) field.
So here is my fix to the problem:
if (m != NULL) {
*frm++ = category;
*frm++ = action;
if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST)
{
*frm++ = args[0]; /* dialog token */
ADDSHORT(frm, args[1]); /* baparamset */
ADDSHORT(frm, args[2]); /* batimeout */
ADDSHORT(frm, args[3]); /* baseqctl */
}
else /* IEEE80211_ACTION_BA_ADDBA_RESPONSE */
{
*frm++ = args[0]; /* dialog token */
ADDSHORT(frm, args[1]); /* status code */
ADDSHORT(frm, args[2]); /* baparamset */
ADDSHORT(frm, args[3]); /* batimeout */
}
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
return ht_action_output(ni, m);
} else {
vap->iv_stats.is_tx_nobuf++;
ieee80211_free_node(ni);
return ENOMEM;
}
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list