> Date: Sat, 12 Dec 2015 14:26:19 +0100 > From: Stefan Sperling <s...@stsp.name> > > A-MSDU frames are aggregates which contain MSDUs (ethernet frames) as > subframes, rather than MPDUs (802.11 frames) as A-MPDUs do. > Each subframe has a header containing sender and target MAC address > and the subframe's length. For a visual illustration, see > http://www.gta.ufrj.br/ensino/eel879/trabalhos_vf_2014_2/remi/img/A-MSDU.png > > The 802.11 standard requires 11n STAs to receive and send A-MSDUs. > As with A-MPDUs, we only implement receive for now. > > Since the subframes are ethernet frames they go directly to the interface > input queue via ieee80211_deliver_data(), rather than to ieee80211_input(). > > damien@ added code for A-MSDU Rx years ago and it works mostly out of > the box. This diff adds an upper bounds check on the subframe length, > and a clean exit at the bottom of the loop for fully processed A-MSDUs > without which we'd normally terminate the loop via the error handling > path of the m_pullup() call at the top of the loop. > > Tested against several APs. Only two of my APs send A-MSDUs (fritzbox > and Linux iwlwifi). With the Linux iwlwifi AP I'm seeing A-MSDU decryption > failures which I believe is caused by an intel firmware bug since the frame > sent by the AP has the wrong kind of encryption header (not CCMP). > The fritzbox AP uses a CCMP header as mandated by the standard so no > problem there. > > Note that A-MPDUs may contain A-MSDUs in subframes. The iwlwifi AP > sends frames like this (unencrypted, though ;) so I could confirm > that this works as expected. > > Index: net80211/ieee80211_input.c > =================================================================== > RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v > retrieving revision 1.143 > diff -u -p -r1.143 ieee80211_input.c > --- net80211/ieee80211_input.c 12 Dec 2015 11:25:46 -0000 1.143 > +++ net80211/ieee80211_input.c 12 Dec 2015 13:04:29 -0000 > @@ -1061,6 +1061,13 @@ ieee80211_amsdu_decap(struct ieee80211co > len -= LLC_SNAPFRAMELEN; > } > len += ETHER_HDR_LEN; > + if (len > m->m_pkthdr.len) { > + /* stop processing A-MSDU subframes */ > + DPRINTF(("A-MSDU subframe too long (%d)\n", len)); > + ic->ic_stats.is_rx_decap++; > + m_freem(m); > + break; > + } > > /* "detach" our A-MSDU subframe from the others */ > n = m_split(m, len, M_NOWAIT); > @@ -1072,6 +1079,10 @@ ieee80211_amsdu_decap(struct ieee80211co > } > ieee80211_deliver_data(ic, m, ni); > > + if (n->m_len == 0) { > + m_freem(n); > + break; > + }
Can this really happen? I would expect that m_split() would have returned NULL if we'd tried to split the packet in a way that there is nothing left. Not sure if that can happen though, but ouldn't it be a bug if it did? > m = n; > /* remove padding */ > pad = ((len + 3) & ~3) - len; > >