> 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;
> 
> 

Reply via email to