I forgot about initializing the A-MPDU parameters field in HT capability elements.
This field specifies the max size of A-MPDU, and the spacing of A-MPDU subframes. Spacing is currently set to zero which means 'no restricition', but intel wireless devices need at least 4 microseconds of slack between each subframe (according to Linux iwlwifi). I'm not seeing any noticable change in behaviour with this diff, though. Index: dev/pci/if_iwm.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v retrieving revision 1.73 diff -u -p -r1.73 if_iwm.c --- dev/pci/if_iwm.c 6 Jan 2016 09:15:31 -0000 1.73 +++ dev/pci/if_iwm.c 6 Jan 2016 18:46:02 -0000 @@ -6778,6 +6778,7 @@ iwm_attach(struct device *parent, struct ic->ic_htxcaps = 0; ic->ic_txbfcaps = 0; ic->ic_aselcaps = 0; + ic->ic_ampdu_params = IEEE80211_AMPDU_PARAM_SS_4; ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; Index: dev/pci/if_iwn.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v retrieving revision 1.151 diff -u -p -r1.151 if_iwn.c --- dev/pci/if_iwn.c 6 Jan 2016 09:17:42 -0000 1.151 +++ dev/pci/if_iwn.c 6 Jan 2016 18:46:08 -0000 @@ -458,6 +458,7 @@ iwn_attach(struct device *parent, struct ic->ic_htxcaps = 0; ic->ic_txbfcaps = 0; ic->ic_aselcaps = 0; + ic->ic_ampdu_params = IEEE80211_AMPDU_PARAM_SS_4; #ifdef notyet if (sc->sc_flags & IWN_FLAG_HAS_11N) { Index: net80211/ieee80211.h =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211.h,v retrieving revision 1.55 diff -u -p -r1.55 ieee80211.h --- net80211/ieee80211.h 4 Jan 2016 12:32:06 -0000 1.55 +++ net80211/ieee80211.h 6 Jan 2016 17:56:47 -0000 @@ -588,6 +588,14 @@ enum { */ #define IEEE80211_AMPDU_PARAM_LE 0x03 #define IEEE80211_AMPDU_PARAM_SS 0x1c +#define IEEE80211_AMPDU_PARAM_SS_NONE (0 << 2) +#define IEEE80211_AMPDU_PARAM_SS_0_25 (1 << 2) +#define IEEE80211_AMPDU_PARAM_SS_0_5 (2 << 2) +#define IEEE80211_AMPDU_PARAM_SS_1 (3 << 2) +#define IEEE80211_AMPDU_PARAM_SS_3 (4 << 2) +#define IEEE80211_AMPDU_PARAM_SS_4 (5 << 2) +#define IEEE80211_AMPDU_PARAM_SS_8 (6 << 2) +#define IEEE80211_AMPDU_PARAM_SS_16 (7 << 2) /* bits 5-7 reserved */ /* Index: net80211/ieee80211_output.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_output.c,v retrieving revision 1.105 diff -u -p -r1.105 ieee80211_output.c --- net80211/ieee80211_output.c 5 Jan 2016 18:41:16 -0000 1.105 +++ net80211/ieee80211_output.c 6 Jan 2016 17:51:13 -0000 @@ -1021,7 +1021,7 @@ ieee80211_add_htcaps(u_int8_t *frm, stru *frm++ = IEEE80211_ELEMID_HTCAPS; *frm++ = 26; LE_WRITE_2(frm, ic->ic_htcaps); frm += 2; - *frm++ = 0; /* XXX A-MPDU params */ + *frm++ = ic->ic_ampdu_params; memcpy(frm, ic->ic_sup_mcs, 10); frm += 10; LE_WRITE_2(frm, (ic->ic_max_rxrate & IEEE80211_MCS_RX_RATE_HIGH)); frm += 2; Index: net80211/ieee80211_var.h =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_var.h,v retrieving revision 1.68 diff -u -p -r1.68 ieee80211_var.h --- net80211/ieee80211_var.h 5 Jan 2016 18:41:16 -0000 1.68 +++ net80211/ieee80211_var.h 6 Jan 2016 17:50:55 -0000 @@ -318,6 +318,7 @@ struct ieee80211com { u_int32_t ic_txbfcaps; u_int16_t ic_htcaps; + u_int8_t ic_ampdu_params; u_int8_t ic_sup_mcs[howmany(80, NBBY)]; u_int16_t ic_max_rxrate; /* in Mb/s, 0 <= rate <= 1023 */ u_int8_t ic_tx_mcs_set;