stricter bioctl -c option parsing

2021-02-08 Thread Stefan Sperling
bioctl(8) only looks at the first character of the -c option argument
and ignores any trailing characters in the argument. Following the
addition of the RAID1C discipline this behaviour can lead to confusion.

This command with a typo ("C1" vs "1C") attempts to create a CRYPTO volume:

# bioctl -cC1 -l /dev/sd1d,/dev/sd2d softraid0  
   
bioctl: not exactly one partition

With the patch below, "C1" is instead rejected as an invalid raid level:

# /tmp/bioctl -cC1 -l /dev/sd1d,/dev/sd2d softraid0
bioctl: Invalid RAID level

ok?

diff 5ee6e27345c7d0c6d947bafadc8160eb9da3f73b /usr/src
blob - 24d4042d6d6dd2ee997eac511b0816ad47441d35
file + sbin/bioctl/bioctl.c
--- sbin/bioctl/bioctl.c
+++ sbin/bioctl/bioctl.c
@@ -133,6 +133,8 @@ main(int argc, char *argv[])
func |= BIOC_CREATERAID;
if (strcmp(optarg, "1C") == 0) {
cr_level = 0x1C;
+   } else if (strlen(optarg) != 1) {
+   errx(1, "Invalid RAID level");
} else if (isdigit((unsigned char)*optarg)) {
cr_level = strtonum(optarg, 0, 10, );
if (errstr != NULL)



Re: fix ieee80211_amsdu_decap()

2020-12-10 Thread Stefan Sperling
This patch was committed last night but contains a bug: I forgot to adjust
error paths to avoid a double-free. Please check the follow-up fix below. Ok?

(This double-free wouldn't trigger under normal conditions even in -current,
unless we receive crafted packets that would also need to pass decryption
if we're not on an open network)

On Wed, Dec 09, 2020 at 03:34:05PM +0100, Stefan Sperling wrote:
> With A-MSDUs enabled in -current people are seeing a lot of
> 
>   input packet decapsulations failed
> 
> events in netstat -W iwm0.
> 
> This fixes the issue on iwm 8265 for me. There are between 6 and 8 bytes of
> trailing data in the A-MSDU frame buffer. This results in a decap failure
> being counted when m_pullup() fails to fetch ETHER_HDR_LEN + LLC_SNAPFRAMELEN
> bytes.
> 
> I suppose such bytes are padding left by the hardware, most likely due to
> decryption. It should be safe to ignore these. A TCP stream that uses
> A-MSDUs looks clean, so we're not losing any packets. This problem is
> just a cosmetic one.
> 
> ok?

> iwm(4) 9260+ and iwx(4) have another issue because these devices actually
> decapsulate A-MSDUs in hardware and our code doesn't handle that yet.
> I will send a separate patch for this soon.

Regarding the above paragraph, I have changed my mind and am shelving
further work on A-MSDU support for now due to lack of time. I will try
to pick this up again later. I would have time to review patches, though,
if anyone else wants to continue this work.

Double-free fix:

diff 22c79bfc5a343ef1dfe575157d8cd8a0dc743910 /usr/src
blob - 924608b6724ca4d3939200dd9f1bc19024870f42
file + sys/net80211/ieee80211_input.c
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -1158,7 +1158,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct 
m = m_pullup(m, ETHER_HDR_LEN + LLC_SNAPFRAMELEN);
if (m == NULL) {
ic->ic_stats.is_rx_decap++;
-   break;
+   return;
}
eh = mtod(m, struct ether_header *);
/* examine 802.3 header */
@@ -1168,7 +1168,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct 
/* stop processing A-MSDU subframes */
ic->ic_stats.is_rx_decap++;
m_freem(m);
-   break;
+   return;
}
llc = (struct llc *)[1];
/* examine 802.2 LLC header */
@@ -1192,7 +1192,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct 
DPRINTF(("A-MSDU subframe too long (%d)\n", len));
ic->ic_stats.is_rx_decap++;
m_freem(m);
-   break;
+   return;
}
 
/* "detach" our A-MSDU subframe from the others */
@@ -1201,7 +1201,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct 
/* stop processing A-MSDU subframes */
ic->ic_stats.is_rx_decap++;
m_freem(m);
-   break;
+   return;
}
ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 



fix ieee80211_amsdu_decap()

2020-12-09 Thread Stefan Sperling
With A-MSDUs enabled in -current people are seeing a lot of

input packet decapsulations failed

events in netstat -W iwm0.

This fixes the issue on iwm 8265 for me. There are between 6 and 8 bytes of
trailing data in the A-MSDU frame buffer. This results in a decap failure
being counted when m_pullup() fails to fetch ETHER_HDR_LEN + LLC_SNAPFRAMELEN
bytes.

I suppose such bytes are padding left by the hardware, most likely due to
decryption. It should be safe to ignore these. A TCP stream that uses
A-MSDUs looks clean, so we're not losing any packets. This problem is
just a cosmetic one.

ok?

iwm(4) 9260+ and iwx(4) have another issue because these devices actually
decapsulate A-MSDUs in hardware and our code doesn't handle that yet.
I will send a separate patch for this soon.

diff b0e5533ef47f577f6c3be1bfdbb89151a76d3add /usr/src
blob - 2c9ee3ab48a212ce9730860568ca59d17d3d4636
file + sys/net80211/ieee80211_input.c
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -1148,14 +1148,13 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct 
/* strip 802.11 header */
m_adj(m, hdrlen);
 
-   for (;;) {
+   while (m->m_pkthdr.len >= ETHER_HDR_LEN + LLC_SNAPFRAMELEN) {
/* process an A-MSDU subframe */
-   if (m->m_len < ETHER_HDR_LEN + LLC_SNAPFRAMELEN) {
-   m = m_pullup(m, ETHER_HDR_LEN + LLC_SNAPFRAMELEN);
-   if (m == NULL) {
-   ic->ic_stats.is_rx_decap++;
-   break;
-   }
+   len = m->m_pkthdr.len;
+   m = m_pullup(m, ETHER_HDR_LEN + LLC_SNAPFRAMELEN);
+   if (m == NULL) {
+   ic->ic_stats.is_rx_decap++;
+   break;
}
eh = mtod(m, struct ether_header *);
/* examine 802.3 header */
@@ -1202,15 +1201,13 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct 
}
ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 
-   if (n->m_pkthdr.len == 0) {
-   m_freem(n);
-   break;
-   }
m = n;
/* remove padding */
pad = ((len + 3) & ~3) - len;
m_adj(m, pad);
}
+
+   m_freem(m);
 }
 
 /*



Re: ieee80211: Flush reorder buffer after gap timeout

2020-12-08 Thread Stefan Sperling
On Tue, Dec 08, 2020 at 04:49:27PM +0100, Tobias Heider wrote:
> Hi,
> 
> here is another diff that should fix associating with
> some APs that currently don't work.
> 
> If block ack is active and the first frame got lost,
> subsequent packets are held back until a timeout expires.
> When this timeout expires, the gap at the start of the
> reorder buffer is skipped and subsequent frames that are
> sitting in the reorder buffer can be processed.
> 
> In order to make this work, flush the reorder buffer
> after skipping the sequence number gap. Without doing this,
> packets in the reorder buffer will remain there until a new
> block ack packet is received.

The last sentence is not quite accurate; we don't need a block ack frame
to advance, any received data frame will do it.
 
> Found and fix provided by Christian Ehrhardt
> 
> ok?

Yes, OK.  We had something like this before. I removed that code because
I was not sure whether if_input() from a timeout is safe. But I've since
been told that if_input() from a timeout is indeed safe.

> Index: ieee80211_input.c
> ===
> RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
> retrieving revision 1.222
> diff -u -p -r1.222 ieee80211_input.c
> --- ieee80211_input.c 8 Dec 2020 10:28:22 -   1.222
> +++ ieee80211_input.c 8 Dec 2020 11:45:44 -
> @@ -972,6 +972,11 @@ ieee80211_input_ba_gap_timeout(void *arg
>  
>   skipped = ieee80211_input_ba_gap_skip(ba);
>   ic->ic_stats.is_ht_rx_ba_frame_lost += skipped;
> + if (skipped) {
> + struct mbuf_list ml = MBUF_LIST_INITIALIZER();
> + ieee80211_input_ba_flush(ic, ni, ba, );
> + if_input(>ic_if, );
> + }
>  
>   splx(s);
>  }
> 



net80211: fix announced RSN (WPA2) capabilities

2020-12-07 Thread Stefan Sperling
When announcing RSN (WPA2) capabilities in management frames such as
association requests, we currently echo back all RSN (i.e. WPA2)
capabilities which were announced by our peer.

This is bad in case the peer announces features we don't support.
One such feature is Management Frame Protection (MFP). If we announce this
capability then the peer sends us encrypted management frames which won't be
processed. One symptom of this is that we fail to negotiate 11n block ack
with APs that enable MFP if the client announces support for MFP (problem
found by sthen@).

With this patch we only echo the RSN capalibities which we actually support.
I am handling MFP and PBAR bits here as done elsewhere, but note that
neither of these features is enabled yet at run-time.
(We do have code for MFP; but it is untested, and disabled in all of our
wifi drivers. That's for another day...)

ok?

diff 18e888c6238d4d2767f9b9d181633c8a9b33b1a3 /usr/src
blob - 1610fbf508ab3f6fb12721ee5c1ba7f56c0a94b3
file + sys/net80211/ieee80211_output.c
--- sys/net80211/ieee80211_output.c
+++ sys/net80211/ieee80211_output.c
@@ -941,7 +941,7 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211
 {
const u_int8_t *oui = wpa ? MICROSOFT_OUI : IEEE80211_OUI;
u_int8_t *pcount;
-   u_int16_t count;
+   u_int16_t count, rsncaps;
 
/* write Version field */
LE_WRITE_2(frm, 1); frm += 2;
@@ -1017,7 +1017,16 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211
return frm;
 
/* write RSN Capabilities field */
-   LE_WRITE_2(frm, ni->ni_rsncaps); frm += 2;
+   rsncaps = (ni->ni_rsncaps & (IEEE80211_RSNCAP_PTKSA_RCNT_MASK |
+   IEEE80211_RSNCAP_GTKSA_RCNT_MASK));
+   if (ic->ic_caps & IEEE80211_C_MFP) {
+   rsncaps |= IEEE80211_RSNCAP_MFPC;
+   if (ic->ic_flags & IEEE80211_F_MFPR)
+   rsncaps |= IEEE80211_RSNCAP_MFPR;
+   }
+   if (ic->ic_flags & IEEE80211_F_PBAR)
+   rsncaps |= IEEE80211_RSNCAP_PBAC;
+   LE_WRITE_2(frm, rsncaps); frm += 2;
 
if (ni->ni_flags & IEEE80211_NODE_PMKID) {
/* write PMKID Count field */




Re: net80211: Use a BA agreement for rx immediately

2020-12-07 Thread Stefan Sperling
On Mon, Dec 07, 2020 at 03:49:20PM +0100, Tobias Heider wrote:
> On Mon, Dec 07, 2020 at 02:33:10PM +0100, Stefan Sperling wrote:
> > On Mon, Dec 07, 2020 at 01:31:09PM +0100, Tobias Heider wrote:
> > > Some APs request a BA agreement and continue to send QOS packets
> > > for the same tid (with normal ack policy). Currently, these packets
> > > make it to the higher layers without going through BA reordering or the
> > > BA buffer. This results in reduced performance later on as the sequence
> > > numbers are expected by BA reordering.
> > > 
> > > To fix this, we should use BA agreement immediately after it is
> > > requested by the AP.  This causes the sequence number counter in
> > > the BA agreement to advance for the normal qos packets and the gap
> > > wait later on is avoided.
> > > 
> > > ok?
> > 
> > Not yet, see below:
> > 
> 
> Update with comments addressed.

ok

> Index: ieee80211_input.c
> ===
> RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
> retrieving revision 1.221
> diff -u -p -r1.221 ieee80211_input.c
> --- ieee80211_input.c 28 Aug 2020 12:01:48 -  1.221
> +++ ieee80211_input.c 7 Dec 2020 14:38:24 -
> @@ -358,6 +358,17 @@ ieee80211_inputm(struct ifnet *ifp, stru
>   /* go through A-MPDU reordering */
>   ieee80211_input_ba(ic, m, ni, tid, rxi, ml);
>   return; /* don't free m! */
> + } else if (ba_state == IEEE80211_BA_REQUESTED &&
> + (qos & IEEE80211_QOS_ACK_POLICY_MASK) ==
> + IEEE80211_QOS_ACK_POLICY_NORMAL) {
> + /*
> +  * Apparently, qos frames for a tid where a
> +  * block ack agreement was requested but not
> +  * yet confirmed by us should still contribute
> +  * to the sequence number for this tid.
> +  */
> + ieee80211_input_ba(ic, m, ni, tid, rxi, ml);
> + return; /* don't free m! */
>   }
>   }
>  
> @@ -2698,6 +2709,9 @@ ieee80211_recv_addba_req(struct ieee8021
>   ssn = LE_READ_2([7]) >> 4;
>  
>   ba = >ni_rx_ba[tid];
> + /* The driver is still processing an ADDBA request for this tid. */
> + if (ba->ba_state == IEEE80211_BA_REQUESTED)
> + return;
>   /* check if we already have a Block Ack agreement for this RA/TID */
>   if (ba->ba_state == IEEE80211_BA_AGREED) {
>   /* XXX should we update the timeout value? */
> @@ -2737,7 +2751,7 @@ ieee80211_recv_addba_req(struct ieee8021
>   goto refuse;
>  
>   /* setup Block Ack agreement */
> - ba->ba_state = IEEE80211_BA_INIT;
> + ba->ba_state = IEEE80211_BA_REQUESTED;
>   ba->ba_timeout_val = timeout * IEEE80211_DUR_TU;
>   ba->ba_ni = ni;
>   ba->ba_token = token;
> @@ -2816,6 +2830,7 @@ ieee80211_addba_req_refuse(struct ieee80
>   free(ba->ba_buf, M_DEVBUF,
>   IEEE80211_BA_MAX_WINSZ * sizeof(*ba->ba_buf));
>   ba->ba_buf = NULL;
> + ba->ba_state = IEEE80211_BA_INIT;
>  
>   /* MLME-ADDBA.response */
>   IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA,
> 



Re: iwx(4): decoding of multiple MPDUs in one receive packet

2020-12-07 Thread Stefan Sperling
On Mon, Dec 07, 2020 at 03:32:48PM +0100, Tobias Heider wrote:
> Hi,
> 
> this is an iwx(4) port of the iwm(4) fix by Christian Erhardt
> which I sent in a previous mail:
> https://marc.info/?l=openbsd-tech=160733342209497=2
> 
> I don't have a iwx(4) card to test this, but the diff to iwm(4) is trivial.
> ok?

Yes, ok. This part of the code should be kept in sync across both drivers.

> Index: if_iwx.c
> ===
> RCS file: /cvs/src/sys/dev/pci/if_iwx.c,v
> retrieving revision 1.46
> diff -u -p -r1.46 if_iwx.c
> --- if_iwx.c  22 Oct 2020 11:24:01 -  1.46
> +++ if_iwx.c  7 Dec 2020 14:06:10 -
> @@ -7141,7 +7141,6 @@ iwx_rx_pkt(struct iwx_softc *sc, struct 
>   uint32_t offset = 0, nextoff = 0, nmpdu = 0, len;
>   struct mbuf *m0, *m;
>   const size_t minsz = sizeof(pkt->len_n_flags) + sizeof(pkt->hdr);
> - size_t remain = IWX_RBUF_SIZE;
>   int qid, idx, code, handled = 1;
>  
>   bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWX_RBUF_SIZE,
> @@ -7178,7 +7177,7 @@ iwx_rx_pkt(struct iwx_softc *sc, struct 
>   break;
>  
>   case IWX_REPLY_RX_MPDU_CMD: {
> - size_t maxlen = remain - minsz;
> + size_t maxlen = IWX_RBUF_SIZE - offset - minsz;
>   nextoff = offset +
>   roundup(len, IWX_FH_RSCSR_FRAME_ALIGN);
>   nextpkt = (struct iwx_rx_packet *)
> @@ -7206,11 +7205,6 @@ iwx_rx_pkt(struct iwx_softc *sc, struct 
>   m_adj(m, offset);
>   iwx_rx_mpdu_mq(sc, m, pkt->data, maxlen, ml);
>   }
> -
> - if (offset + minsz < remain)
> - remain -= offset;
> - else
> - remain = minsz;
>   break;
>   }
>  
> 



Re: net80211: Better gapwait accounting

2020-12-07 Thread Stefan Sperling
On Mon, Dec 07, 2020 at 02:36:05PM +0100, Tobias Heider wrote:
> Hi,
> 
> our net80211 gapwait accounting implementation seems to have several
> problems:
> - If we lose packets with serial numbers 0 und 2 but receive the
>   packet with serial number 1, the first gap wait timeout will
>   skip serial number 0, flush out serial number 1 and then wait
>   for serial number 2. However, at this time the timeout is not
>   re-armed and we have to wait for a window slide.
> - The logic that does gap skip if too many packets are in the reorder
>   buffer does not kick in if we lose two packets (as gapwait cannot
>   reach windowsize - 1. Additionally, what the logic does is mostly
>   equivalent to a normal window slide if we receive a packet that is
>   beyond the window. So remove this logic completely.
> 
> To fix this use ba_gapwait to actually count all the packets
> currently in the reorder buffer and restart the gap timeout if the
> buffer is not empty after we flush out some of the packets.
> 
> Found and fix by Christian Erhardt (CC).
> 
> ok?
 
I am happy with this if it works well during testing.

Could someone convince phessler@ to take this for a flight in Minecraft?

> Index: ieee80211_input.c
> ===
> RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
> retrieving revision 1.221
> diff -u -p -r1.221 ieee80211_input.c
> --- ieee80211_input.c 28 Aug 2020 12:01:48 -  1.221
> +++ ieee80211_input.c 7 Dec 2020 12:58:31 -
> @@ -839,30 +839,10 @@ ieee80211_input_ba(struct ieee80211com *
>   /* store Rx meta-data too */
>   rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
>   ba->ba_buf[idx].rxi = *rxi;
> + ba->ba_gapwait++;
>  
> - if (ba->ba_buf[ba->ba_head].m == NULL) {
> - if (ba->ba_gapwait < (ba->ba_winsize - 1)) {
> - if (ba->ba_gapwait == 0) {
> - timeout_add_msec(>ba_gap_to,
> - IEEE80211_BA_GAP_TIMEOUT);
> - }
> - ba->ba_gapwait++;
> - } else {
> - /*
> -  * A full BA window worth of frames is now waiting.
> -  * Skip the missing frame at the head of the window.
> -  */
> - int skipped = ieee80211_input_ba_gap_skip(ba);
> - ic->ic_stats.is_ht_rx_ba_frame_lost += skipped;
> - ba->ba_gapwait = 0;
> - if (timeout_pending(>ba_gap_to))
> - timeout_del(>ba_gap_to);
> - }
> - } else {
> - ba->ba_gapwait = 0;
> - if (timeout_pending(>ba_gap_to))
> - timeout_del(>ba_gap_to);
> - }
> + if (ba->ba_buf[ba->ba_head].m == NULL && ba->ba_gapwait == 1)
> + timeout_add_msec(>ba_gap_to, IEEE80211_BA_GAP_TIMEOUT);
>  
>   ieee80211_input_ba_flush(ic, ni, ba, ml);
>  }
> @@ -894,6 +874,7 @@ ieee80211_input_ba_seq(struct ieee80211c
>   ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m,
>   ni, >ba_buf[ba->ba_head].rxi, ml);
>   ba->ba_buf[ba->ba_head].m = NULL;
> + ba->ba_gapwait--;
>   } else
>   ic->ic_stats.is_ht_rx_ba_frame_lost++;
>   ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
> @@ -916,12 +897,18 @@ ieee80211_input_ba_flush(struct ieee8021
>   ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni,
>   >ba_buf[ba->ba_head].rxi, ml);
>   ba->ba_buf[ba->ba_head].m = NULL;
> + ba->ba_gapwait--;
>  
>   ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
>   /* move window forward */
>   ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff;
>   }
>   ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
> +
> + if (timeout_pending(>ba_gap_to))
> + timeout_del(>ba_gap_to);
> + if (ba->ba_gapwait)
> + timeout_add_msec(>ba_gap_to, IEEE80211_BA_GAP_TIMEOUT);
>  }
>  
>  /* 
> @@ -989,6 +976,7 @@ ieee80211_ba_move_window(struct ieee8021
>   ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni,
>   >ba_buf[ba->ba_head].rxi, ml);
>   ba->ba_buf[ba->ba_head].m = NULL;
> + ba->ba_gapwait--;
>   } else
>   ic->ic_stats.is_ht_rx_ba_frame_lost++;
>   ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
> 



Re: net80211: Use a BA agreement for rx immediately

2020-12-07 Thread Stefan Sperling
On Mon, Dec 07, 2020 at 01:31:09PM +0100, Tobias Heider wrote:
> Some APs request a BA agreement and continue to send QOS packets
> for the same tid (with normal ack policy). Currently, these packets
> make it to the higher layers without going through BA reordering or the
> BA buffer. This results in reduced performance later on as the sequence
> numbers are expected by BA reordering.
> 
> To fix this, we should use BA agreement immediately after it is
> requested by the AP.  This causes the sequence number counter in
> the BA agreement to advance for the normal qos packets and the gap
> wait later on is avoided.
> 
> ok?

Not yet, see below:

> Index: ieee80211_input.c
> ===
> RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
> retrieving revision 1.221
> diff -u -p -r1.221 ieee80211_input.c
> --- ieee80211_input.c 28 Aug 2020 12:01:48 -  1.221
> +++ ieee80211_input.c 7 Dec 2020 11:57:19 -
> @@ -358,6 +358,18 @@ ieee80211_inputm(struct ifnet *ifp, stru
>   /* go through A-MPDU reordering */
>   ieee80211_input_ba(ic, m, ni, tid, rxi, ml);
>   return; /* don't free m! */
> + } else if (ba_state == IEEE80211_BA_REQUESTED &&
> + (qos & IEEE80211_QOS_ACK_POLICY_MASK) ==
> + IEEE80211_QOS_ACK_POLICY_NORMAL) {
> + /*
> +  * Apparently, qos frames for a tid where a
> +  * block ack agreement was requested but not
> +  * yet confirmed by us should still contribute
> +  * to the sequence number for this tid.
> +  * XXX Add quote from the standard...

Please remove the last XXX line from this comment.

Whatever the standard says about this is irrelevant.

The fact is there are 802.11 implementations which require block ack to
operate before the WPA handshake is done, and some that only enable block
ack when WPA2 has been set up.

The former implementation choice is problematic (why remember state for a
peer that hasn't even been authenticated? WTF!) but we have to accept such
behaviour from peers for interop, regardless of the standard's opinion
on this.

> +  */
> + ieee80211_input_ba(ic, m, ni, tid, rxi, ml);
> + return; /* don't free m! */
>   }
>   }
>  
> @@ -2698,6 +2710,9 @@ ieee80211_recv_addba_req(struct ieee8021
>   ssn = LE_READ_2([7]) >> 4;
>  
>   ba = >ni_rx_ba[tid];
> + /* The driver is still processing an ADDBA request for this tid. */
> + if (ba->ba_state == IEEE80211_BA_REQUESTED)
> + return;
>   /* check if we already have a Block Ack agreement for this RA/TID */
>   if (ba->ba_state == IEEE80211_BA_AGREED) {
>   /* XXX should we update the timeout value? */
> @@ -2737,7 +2752,7 @@ ieee80211_recv_addba_req(struct ieee8021
>   goto refuse;
>  
>   /* setup Block Ack agreement */
> - ba->ba_state = IEEE80211_BA_INIT;
> + ba->ba_state = IEEE80211_BA_REQUESTED;
>   ba->ba_timeout_val = timeout * IEEE80211_DUR_TU;
>   ba->ba_ni = ni;
>   ba->ba_token = token;
> @@ -2811,11 +2826,20 @@ void
>  ieee80211_addba_req_refuse(struct ieee80211com *ic, struct ieee80211_node 
> *ni,
>  uint8_t tid)
>  {
> +#ifdef IEEE80211_DEBUG
> + struct ifnet *ifp = >ic_if;
> +#endif
>   struct ieee80211_rx_ba *ba = >ni_rx_ba[tid];
>  
> + if (ba->ba_state != IEEE80211_BA_REQUESTED) {
> + DPRINTF(("%s: Invalid ba_state=%d\n", ifp->if_xname,
> + ba->ba_state));
> + }

I think the above debug hunk should be dropped. There's way too much
debug printf in interrupt context happening already in wifi, to the
point where some drivers fail to work if DEBUG is enabled. It is better
to keep debug prints as local changes where needed.

> +
>   free(ba->ba_buf, M_DEVBUF,
>   IEEE80211_BA_MAX_WINSZ * sizeof(*ba->ba_buf));
>   ba->ba_buf = NULL;
> + ba->ba_state = IEEE80211_BA_INIT;
>  
>   /* MLME-ADDBA.response */
>   IEEE80211_SEND_ACTION(ic, ni, IEEE80211_CATEG_BA,
> 



Re: iwm(4): decoding of multiple MPDUs in one receive packet

2020-12-07 Thread Stefan Sperling
On Mon, Dec 07, 2020 at 10:28:59AM +0100, Tobias Heider wrote:
> Hi,
> 
> In iwm_rx_pkt() the calculation of "remain" seems to be wrong if
> there are three or more MPDUs in one packet.
> "remain" is initialized with the output buffer size.
> Each time an MPDU is found in the packet remain is reduced
> by the offset of the MPDU in the receive buffer, which is only
> correct for the first MPDU in the packet.
> This causes spurious input errors.
> 
> We can fix this by removing the "remain" variable.
> The variable "offset" always points to the current position in the
> receive buffer and the maximum size of the receive buffer is fixed.
> Thus offset can be used for the caculation of maxlen.
> 
> ok?

Please credit Christian Ehrhardt who did all the hard work in
tracking this down :)

ok!

> 
> Index: if_iwm.c
> ===
> RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
> retrieving revision 1.315
> diff -u -p -r1.315 if_iwm.c
> --- if_iwm.c  11 Oct 2020 07:05:28 -  1.315
> +++ if_iwm.c  7 Dec 2020 09:02:44 -
> @@ -8494,7 +8494,6 @@ iwm_rx_pkt(struct iwm_softc *sc, struct 
>   uint32_t offset = 0, nextoff = 0, nmpdu = 0, len;
>   struct mbuf *m0, *m;
>   const size_t minsz = sizeof(pkt->len_n_flags) + sizeof(pkt->hdr);
> - size_t remain = IWM_RBUF_SIZE;
>   int qid, idx, code, handled = 1;
>  
>   bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE,
> @@ -8531,7 +8530,7 @@ iwm_rx_pkt(struct iwm_softc *sc, struct 
>   break;
>  
>   case IWM_REPLY_RX_MPDU_CMD: {
> - size_t maxlen = remain - minsz;
> + size_t maxlen = IWM_RBUF_SIZE - offset - minsz;
>   nextoff = offset +
>   roundup(len, IWM_FH_RSCSR_FRAME_ALIGN);
>   nextpkt = (struct iwm_rx_packet *)
> @@ -8569,11 +8568,6 @@ iwm_rx_pkt(struct iwm_softc *sc, struct 
>   iwm_rx_mpdu(sc, m, pkt->data,
>   maxlen, ml);
>   }
> -
> - if (offset + minsz < remain)
> - remain -= offset;
> - else
> - remain = minsz;
>   break;
>   }
>  
> 
> 



Re: athn(4) WPA2/WPA1 mixed-mode compat fix

2020-11-11 Thread Stefan Sperling
On Wed, Nov 11, 2020 at 09:16:16PM +0100, Matej Nanut wrote:
> Hello,
> 
> I've applied your diff and dhclient now works on my athn0 interface,
> where it didn't work before.
> 
> The symptom was that it did get a link, but couldn't get a lease.
> 
> Thanks. Matej
 
Thank you for confirming. I have committed this fix.



athn(4) WPA2/WPA1 mixed-mode compat fix

2020-11-10 Thread Stefan Sperling
Similar to the urtwn(4) WPA1/TKIP fix I have just committed, there's
a bug in athn(4) where the value of ni_rsncipher is used to guide the
hardware- vs. software-crypto decision for multicast frames, not just
for unicast frames as was intended.

This means multicast frames could fail to decrypt if the AP is configured
to use WPA1/TKIP instead of WPA2/CMMP as the group cipher (symptoms may
include dhclient failing to get link).

Ok?

diff 89be218cf39e3311509e6aba9a8efd44b360a42f /usr/src
blob - 560db09a447651b7bcabac7b94286a872b313ee2
file + sys/dev/ic/ar5008.c
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -1003,7 +1003,8 @@ ar5008_rx_process(struct athn_softc *sc, struct mbuf_l
(wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
(ic->ic_flags & IEEE80211_F_RSNON) &&
(ni->ni_flags & IEEE80211_NODE_RXPROT) &&
-   (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
+   ((!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+   ni->ni_rsncipher == IEEE80211_CIPHER_CCMP) ||
(IEEE80211_IS_MULTICAST(wh->i_addr1) &&
ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP))) {
if (ar5008_ccmp_decap(sc, m, ni) != 0) {





Re: basename(3) should have non-const arg, says POSIX

2020-10-19 Thread Stefan Sperling
On Mon, Oct 19, 2020 at 10:06:52PM +0200, Christian Weisgerber wrote:
> [Picking this up again after a month:]
> 
> Our basename(3) and dirname(3) take a const argument:
> 
>   char*basename(const char *);
>   char*dirname(const char *);
> 
> POSIX says otherwise...
> 
>   char *basename(char *path);
>   char *dirname(char *path);
> 
> ... and explicitly says the functions may modify the input string.
> 
> 
> Our functions were const-ified in 1999 by espie@:
> 
>   proper const semantics for dirname & basename.
>   (this follows FreeBSD and Linux. Single Unix 2 is still illogical)
> 
> Well, four years ago, FreeBSD finally switched to the POSIX prototypes
> https://svnweb.freebsd.org/base/head/include/libgen.h?revision=303451=markup
> and in fact now has an implementation that modifies the string.
> 
> Linux (GNU libc) has a bizarro solution where you get a const basename()
> and no dirname() if you just include , but POSIX basename()
> and dirname() if you instead or also include .
> 
> This is a portability trap.  Code written on OpenBSD may not be
> prepared for basename() or dirname() to splat a '\0' into the input
> string, despite the warning in the man page.  This is not hypothetical.
> Both Got and OpenCVS have fallen victim to the unportable assumption.
> 
> 
> The patch below aligns the function prototypes with POSIX.  All
> resulting warnings "passing 'const char *' to parameter of type
> 'char *' discards qualifiers" in the base system have been cleaned
> up.  It successfully passes "make release".  For good measure I'm
> also running a package bulk build with it as we speak.
> 
> OK?

Ok by me.

> Index: include/libgen.h
> ===
> RCS file: /cvs/src/include/libgen.h,v
> retrieving revision 1.9
> diff -u -p -r1.9 libgen.h
> --- include/libgen.h  25 Jan 2019 00:19:25 -  1.9
> +++ include/libgen.h  11 Sep 2020 20:41:34 -
> @@ -22,8 +22,8 @@
>  #include 
>  
>  __BEGIN_DECLS
> -char *basename(const char *);
> -char *dirname(const char *);
> +char *basename(char *);
> +char *dirname(char *);
>  __END_DECLS
>  
>  #endif /* _LIBGEN_H_ */
> Index: lib/libc/gen/basename.3
> ===
> RCS file: /cvs/src/lib/libc/gen/basename.3,v
> retrieving revision 1.24
> diff -u -p -r1.24 basename.3
> --- lib/libc/gen/basename.3   25 Jan 2019 00:19:25 -  1.24
> +++ lib/libc/gen/basename.3   11 Sep 2020 20:46:30 -
> @@ -23,7 +23,7 @@
>  .Sh SYNOPSIS
>  .In libgen.h
>  .Ft char *
> -.Fn basename "const char *path"
> +.Fn basename "char *path"
>  .Sh DESCRIPTION
>  The
>  .Fn basename
> Index: lib/libc/gen/basename.c
> ===
> RCS file: /cvs/src/lib/libc/gen/basename.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 basename.c
> --- lib/libc/gen/basename.c   25 Jan 2019 00:19:25 -  1.16
> +++ lib/libc/gen/basename.c   11 Sep 2020 20:43:13 -
> @@ -22,7 +22,7 @@
>  #include 
>  
>  char *
> -basename(const char *path)
> +basename(char *path)
>  {
>   static char bname[PATH_MAX];
>   size_t len;
> Index: lib/libc/gen/dirname.3
> ===
> RCS file: /cvs/src/lib/libc/gen/dirname.3,v
> retrieving revision 1.23
> diff -u -p -r1.23 dirname.3
> --- lib/libc/gen/dirname.38 Mar 2019 17:33:23 -   1.23
> +++ lib/libc/gen/dirname.311 Sep 2020 20:47:08 -
> @@ -23,7 +23,7 @@
>  .Sh SYNOPSIS
>  .In libgen.h
>  .Ft char *
> -.Fn dirname "const char *path"
> +.Fn dirname "char *path"
>  .Sh DESCRIPTION
>  The
>  .Fn dirname
> Index: lib/libc/gen/dirname.c
> ===
> RCS file: /cvs/src/lib/libc/gen/dirname.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 dirname.c
> --- lib/libc/gen/dirname.c25 Jan 2019 00:19:25 -  1.16
> +++ lib/libc/gen/dirname.c11 Sep 2020 20:43:34 -
> @@ -24,7 +24,7 @@
>  /* A slightly modified copy of this file exists in libexec/ld.so */
>  
>  char *
> -dirname(const char *path)
> +dirname(char *path)
>  {
>   static char dname[PATH_MAX];
>   size_t len;
> -- 
> Christian "naddy" Weisgerber  na...@mips.inka.de
> 
> 



Re: run(4): crash still observed on 6.7 and -current

2020-09-06 Thread Stefan Sperling
On Sun, Sep 06, 2020 at 05:19:46PM +0530, Neeraj Pal wrote:
> Hi there,
> 
> I have found that the crash is still observed which had already been
> discussed, here,
> https://marc.info/?l=openbsd-tech=143662082630187=2 on -current
> and also on 6.7
> 
> also verified that the patch
> (https://marc.info/?l=openbsd-tech=143693266301743=2) sent by
> @stefan fixes the problem for me on -current.
> 
> regards,
> Neeraj
> 
> 

I have looked over that old thread, and looking at it back today I
see that none of the proposed diffs look perfect.

Somebody will have to take a fresh look at this.
Please file a new bug report for the issue, including crash information
and a dmesg.



Re: m_defrag(9) leak

2020-09-03 Thread Stefan Sperling
On Thu, Sep 03, 2020 at 07:15:23AM +0200, Claudio Jeker wrote:
> On Thu, Sep 03, 2020 at 06:34:38AM +0200, Bjorn Ketelaars wrote:
> > The diff below should fix this. At least I'm able to build a kernel
> > (amd64 only), which doesn't explode when actually using it.
> 
> This is probably not correct. m_defrag does not free the mbuf on failure
> because in the drivers the mbuf is most probably still sitting on the
> interace output queue and will be retried later on.

It might still be worth taking a careful look at each of these.
Even if you don't end up finding a bug, you'll end up understanding
driver code much better.

Generally if a driver leaks mbufs people will notice quickly.
But some drivers aren't used a lot and we've had some mbuf leaks being
noticed only after weeks. I fixed one mbuf leak in urtwn(4) in July,
where the bug was introduced in June (and was unrelated to m_defrag()).

In any case, such changes should be tested with relevant devices before commit.

As claudio says, when reviewing these you need to find out where the mbuf
came from and when it is supposed to be freed. In most cases drivers will
refer to mbufs by other data structures on lists or queues. These mbufs
must not be freed while they're still being referred to.

For example:

> > diff --git sys/arch/octeon/dev/if_cnmac.c sys/arch/octeon/dev/if_cnmac.c
> > index c45503c3d7f..c6a12d20a9a 100644
> > --- sys/arch/octeon/dev/if_cnmac.c
> > +++ sys/arch/octeon/dev/if_cnmac.c
> > @@ -755,8 +755,10 @@ cnmac_send_makecmd_gbuf(struct cnmac_softc *sc, struct 
> > mbuf *m0,
> > return 0;
> >  
> >  defrag:
> > -   if (m_defrag(m0, M_DONTWAIT) != 0)
> > +   if (m_defrag(m0, M_DONTWAIT) != 0) {
> > +   m_freem(m0);
> > return 1;
> > +   }
> > gbuf[0] = cnmac_send_makecmd_w1(m0->m_len, KVTOPHYS(m0->m_data));
> > *rsegs = 1;
> > return 0;

In this instance, cnmac_start() will already free the mbuf on failure,
so your change introduces a double-free. On success, the mbuf ends up on
a list (via cnmac_send()) and will be freed later (via cnmac_free_task()).



Re: ldom.conf.5: clarify vcpu strides

2020-09-02 Thread Stefan Sperling
On Wed, Sep 02, 2020 at 04:41:49PM +0200, Klemens Nanni wrote:
> They way strides work is everything but intuitive and the manual doesn't
> really help;  I've had multiple hackers/users ask me how to use them.
> 
> `vcpu 8' assigns eight virtual CPUs to a domain.
> 
> `vcpu 8:2' allocates eight VCPUs two times but assigns eight VCPUs
> only once, leaving the other eight allocated (read: unusable) but not
> assigned to any domain.
> 
> `vcpu 8:3' would allocate 24 VCPUs and assign eight to a domain.
> 
> This multiplicative property is not obvious from the manual; the way I
> read the current wording is `vcpu 8:2' allocating ten VCPUs and assign
> eight, i.e. the stride being an additive count.
> 
> stsp brought this up and we came up with the following diff.
> Feedback? OK?

My problem with the existing wording is that it says a "stride" exists
but semantics are not specified. I ended up assuming stride corresponded
to the amount of unused CPUs (e.g. 8:4 would mean allocate 8 CPUs, and
leave 4 of those CPUs unused).
I could only find out how it actually works by reading code.

I would like to suggest an example for the EXAMPLES section which
illustrates how a suitable stride factor can be determined (divide the
number of desired "unused" cpus by the number of desired "used" cpus):

diff f2b93fb3c1fc6097f79ea2bfd28de3a4ab8b938b /usr/src
blob - 1d72ee44a4ab333146b004907e240dfd939f11c5
file + usr.sbin/ldomctl/ldom.conf.5
--- usr.sbin/ldomctl/ldom.conf.5
+++ usr.sbin/ldomctl/ldom.conf.5
@@ -112,6 +112,12 @@ domain "salmah" {
 .Pp
 On a machine with 32 cores and 64GB physical memory, this leaves 12 cores and
 58GB memory to the primary domain.
+.Pp
+In order to use 2 CPUs out of 8, leaving 6 CPUs allocated but unused,
+a stride factor of 3 must be used (6 divided by 2):
+.Bd -literal -offset indent
+   vcpu 2:3
+.Ed
 .Sh SEE ALSO
 .Xr eeprom 8 ,
 .Xr ldomctl 8 ,



iwm/iwx: reset Rx BA session counter

2020-08-25 Thread Stefan Sperling
The Rx block ack session counter is not reset when an iwm/iwx interface
disassociates from the AP or is put down via ifconfig.
This can lead to new Rx block ack session being refused upon re-association.

Found by zxystd from the OpenIntelWireless project (drivers for macOS).

The firmware associates Rx block ack state with its "STA node". So while the
device is running the best place to reset our counter is when this STA node
gets removed; this handles re-association without device reset. And we can
of course clear the counter unconditionally when the device is reset.

ok?

diff fd93b7840df11a14bfc329fed5b0c451ca1aff33 /usr/src
blob - c788d9762fd2d82acd39182deac0fbe81209d30d
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -,6 +,7 @@ iwm_deauth(struct iwm_softc *sc)
return err;
}
sc->sc_flags &= ~IWM_FLAG_STA_ACTIVE;
+   sc->sc_rx_ba_sessions = 0;
}
 
tfd_queue_msk = 0;
@@ -6743,6 +6744,7 @@ iwm_disassoc(struct iwm_softc *sc)
return err;
}
sc->sc_flags &= ~IWM_FLAG_STA_ACTIVE;
+   sc->sc_rx_ba_sessions = 0;
}
 
return 0;
@@ -8116,6 +8118,8 @@ iwm_stop(struct ifnet *ifp)
sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE;
sc->sc_flags &= ~IWM_FLAG_HW_ERR;
sc->sc_flags &= ~IWM_FLAG_SHUTDOWN;
+
+   sc->sc_rx_ba_sessions = 0;
 
sc->sc_newstate(ic, IEEE80211_S_INIT, -1);
 
blob - 0482cf039bdd9b8060dbf1b2b89348e18db4d233
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -5736,6 +5736,7 @@ iwx_deauth(struct iwx_softc *sc)
return err;
}
sc->sc_flags &= ~IWX_FLAG_STA_ACTIVE;
+   sc->sc_rx_ba_sessions = 0;
}
 
if (sc->sc_flags & IWX_FLAG_BINDING_ACTIVE) {
@@ -5801,6 +5802,7 @@ iwx_disassoc(struct iwx_softc *sc)
return err;
}
sc->sc_flags &= ~IWX_FLAG_STA_ACTIVE;
+   sc->sc_rx_ba_sessions = 0;
}
 
return 0;
@@ -6759,6 +6761,8 @@ iwx_stop(struct ifnet *ifp)
sc->sc_flags &= ~IWX_FLAG_TE_ACTIVE;
sc->sc_flags &= ~IWX_FLAG_HW_ERR;
sc->sc_flags &= ~IWX_FLAG_SHUTDOWN;
+
+   sc->sc_rx_ba_sessions = 0;
 
sc->sc_newstate(ic, IEEE80211_S_INIT, -1);
 



Re: cosmetic sdmmc(4) diff

2020-08-15 Thread Stefan Sperling
On Sat, Aug 15, 2020 at 02:56:25PM +0200, Mark Kettenis wrote:
> This diff makes sdmmc(4) print ddr52 and hs200 capabilities, making it
> possible to see whether a controller supports these high-speed eMMC
> modes.
> 
> ok?

ok stsp@

> Index: dev/sdmmc/sdmmc.c
> ===
> RCS file: /cvs/src/sys/dev/sdmmc/sdmmc.c,v
> retrieving revision 1.56
> diff -u -p -r1.56 sdmmc.c
> --- dev/sdmmc/sdmmc.c 24 Jul 2020 12:43:32 -  1.56
> +++ dev/sdmmc/sdmmc.c 15 Aug 2020 12:53:32 -
> @@ -113,6 +113,10 @@ sdmmc_attach(struct device *parent, stru
>   printf(", sd high-speed");
>   if (ISSET(saa->caps, SMC_CAPS_MMC_HIGHSPEED))
>   printf(", mmc high-speed");
> + if (ISSET(saa->caps, SMC_CAPS_MMC_DDR52))
> + printf(", ddr52");
> + if (ISSET(saa->caps, SMC_CAPS_MMC_HS200))
> + printf(", hs200");
>   if (ISSET(saa->caps, SMC_CAPS_DMA))
>   printf(", dma");
>   printf("\n");



Re: wireguard listen in other rdomain?

2020-08-12 Thread Stefan Sperling
On Tue, Aug 11, 2020 at 05:46:05PM -0500, Abel Abraham Camarillo Ojeda wrote:
> Hi to all,
> 
> (unsure if this if for tech@ or misc@)
> 
> I'm using wireguard interfaces but I see that no matter what
> domain I put the interface:
> 
> # ifconfig wg0 rdomain X
> 
> It always listens in rdomain 0 (default),
> is this expected?, is there any way to listen in another rdomain?
> I want to expose several wg interfaces all listening in same port but
> there's not option to listen in another ip address:
> 
>  wgport port
>  Set the UDP port that the tunnel operates on.  The interface
> will
>  bind to INADDR_ANY and IN6ADDR_ANY_INIT.  If no port is
>  configured, one will be chosen automatically.
> 
> I tried creating several wg interfaces with different wgport and using
> pf udp redirections but source address selection gets very messy...
> 
> Ideas?

Did you try 'ifconfig wg0 wgrtable X' already?



Re: iwn: fix off-by-one in antenna calibration for iwn5000

2020-07-20 Thread Stefan Sperling
On Fri, Jul 17, 2020 at 12:50:04PM +0200, Holger Mikolon wrote:
> I came across this by reading the code if_iwn.c and DPRINTFs on
> a kernel with IWN_DEBUG.
> 
> IWN_LSB() returns an index starting with 1, however the arrays used
> later on (noise and gain in iwn5000_set_gains()) start with 0. The
> current code accounts for this difference when setting the antenna
> gain by accessing cmd.gain[i - 1]. However the noise array is accessed
> with noise[i], the chainmask is as well checked against i and more
> importantly the overall for() loop iterates wrongly over the antennas by
> always starting with i=2 (the third antenna). One consequence is, that
> gain calibration never happens in case of only two antennas.
> 
> Secondly, the final DPRINTF in iwn5000_set_gains() assumes a two-antenna
> setup. In my case three antennas are connected. I don't know if there
> are iwn setups with one antenna, but the DPRINTF wouldn't make sense
> there at all. Hence I propose to move this DPRINTF up where it makes
> more sense (and adjust it to the new place).
> 
> My diff below fixes the said off-by-one and DPRINTF. Additionally
> it adds another DPRINTF which I felt useful while debugging and
> it extends a comment - those additions may be skipped of course.
> 
> Here is few details of my laptop (cvs updated and kernel built today):
> 
> $ dmesg | grep iwn0
> iwn0 at pci2 dev 0 function 0 "Intel WiFi Link 5300" rev 0x00: msi, MIMO 
> 3T3R, MoW, address 00:21:6a:56:2b:36
> 
> $ sysctl hw | grep -e machine -e model -e vendor -e product
> hw.machine=amd64
> hw.model=Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz
> hw.vendor=Dell Inc.
> hw.product=Studio 1555
> 
> Let me know if you need a full dmesg or anything else.
> 

Thanks! This is a pretty obvious fix. I have committed it and afterwards
tweaked the multi-line comment you've added to conform to style(9).
Something to keep in mind for future patches ;-)

Regarding DPRINTFs: I try to avoid committing them into the tree because
they add a lot of noise as they accumulate. And they are rarely useful
outside of the context of the debugging session they were written for.

Note that iwn(4) in particular contains so many DPRINTFs that just turning
on IWN_DEBUG may cause the driver to miss the WPA handshake timeout while
the console is being displayed (in particular if 'ifconfig iwn0 debug' is
enabled, too). We have already reached the point where the many DPRINTFs
prevent proper operation of this driver.
I kept your DPRINTFs for now. But it would make sense to do a sweep over
the entire iwn(4) driver and eliminate some or most of them. I did that
for iwm(4) many years ago and never had any regrets.



Re: net80211: skip input block ack window gaps faster

2020-07-17 Thread Stefan Sperling
On Fri, Jul 17, 2020 at 03:59:38PM +0200, Stefan Sperling wrote:
> While measuring Tx performance at a fixed Tx rate with iwm(4) I observed
> unexpected dips in throughput measured by tcpbench. These dips coincided
> with one or more gap timeouts shown in 'netstat -W iwm0', such as:
>   77 input block ack window gaps timed out
> Which means lost frames on the receive side were stalling subsequent frames
> and thus slowing tcpbench down.
> 
> I decided to disable the gap timeout entirely to see what would happen if
> those missing frames were immediately skipped rather than waiting for them.
> The result was stable throughput according to tcpbench.
> 
> I then wrote the patch below which keeps the gap timeout intact (it is needed
> in case the peer stops sending anything) but skips missing frames at the head
> of the Rx block window once a certain amount of frames have queued up. This
> heuristics avoids having to wait for the timeout to fire in order to get
> frames flowing again if we lose one of more frames during Rx traffic bursts.
> 
> I have picked a threshold of 16 outstanding frames based on local testing.
> I have no idea if this is a good threshold for everyone. It would help to
> get some feedback from tests in other RF environments and other types of 
> access points. Any regressions?

Next version.

One problem with the previous patch was that it effectively limited the
size of the BA window to the arbitrarily chosen limit of 16. We should not
drop frames which arrive out of order but still fall within the BA window.

With this version, we allow the entire block ack window (usually 64 frames)
to fill up beyond the missing frame at the head, and only then bypass the
gap timeout handler and skip over the missing frame directly. I can still
trigger this shortcut with tcpbench, and still see the timeout run sometimes.
Direct skip should be faster than having to wait for the timeout to run,
and missing just one out of 64 frames is a common case in my testing.

Also, I am not quite sure if calling if_input() from a timeout is such a
good idea. Any opinions about that? This patch still lets the gap timeout
handler clear the leading gap but avoids flushing buffered frames there.
The peer will now need to send another frame to flush the buffer, but now
if_input() will be called from network interrupt context only. Which is
probably a good thing?

This code still seems to recover well enough from occasional packet loss,
which is what this is all about. If you are on a really bad link, none
of this will help anyway.

diff refs/heads/master refs/heads/ba-gap
blob - 098aa9bce19481ce09676ce3c4fc0040f14c9b93
blob + 4f41b568311bf29e131a3f4802e0a238ba940fe0
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -67,6 +67,7 @@ void  ieee80211_input_ba(struct ieee80211com *, struct 
struct mbuf_list *);
 void   ieee80211_input_ba_flush(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_rx_ba *, struct mbuf_list *);
+intieee80211_input_ba_gap_skip(struct ieee80211_rx_ba *);
 void   ieee80211_input_ba_gap_timeout(void *arg);
 void   ieee80211_ba_move_window(struct ieee80211com *,
struct ieee80211_node *, u_int8_t, u_int16_t, struct mbuf_list *);
@@ -837,10 +838,29 @@ ieee80211_input_ba(struct ieee80211com *ic, struct mbu
rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
ba->ba_buf[idx].rxi = *rxi;
 
-   if (ba->ba_buf[ba->ba_head].m == NULL)
-   timeout_add_msec(>ba_gap_to, IEEE80211_BA_GAP_TIMEOUT);
-   else if (timeout_pending(>ba_gap_to))
-   timeout_del(>ba_gap_to);
+   if (ba->ba_buf[ba->ba_head].m == NULL) {
+   if (ba->ba_gapwait < (ba->ba_winsize - 1)) {
+   if (ba->ba_gapwait == 0) {
+   timeout_add_msec(>ba_gap_to,
+   IEEE80211_BA_GAP_TIMEOUT);
+   }
+   ba->ba_gapwait++;
+   } else {
+   /*
+* A full BA window worth of frames is now waiting.
+* Skip the missing frame at the head of the window.
+*/
+   int skipped = ieee80211_input_ba_gap_skip(ba);
+   ic->ic_stats.is_ht_rx_ba_frame_lost += skipped;
+   ba->ba_gapwait = 0;
+   if (timeout_pending(>ba_gap_to))
+   timeout_del(>ba_gap_to);
+   }
+   } else {
+   ba->ba_gapwait = 0;
+   if (timeout_pending(>ba_gap_to))
+   timeout_del(>ba_gap_to);
+   }
 
ieee80211_input_ba_flush(ic, ni, ba, ml);
 }
@@ -908,10 +928,26 @@ ieee80211_input_ba_flush(struct ieee80211com *ic, stru
  * A leading gap will

net80211: skip input block ack window gaps faster

2020-07-17 Thread Stefan Sperling
While measuring Tx performance at a fixed Tx rate with iwm(4) I observed
unexpected dips in throughput measured by tcpbench. These dips coincided
with one or more gap timeouts shown in 'netstat -W iwm0', such as:
77 input block ack window gaps timed out
Which means lost frames on the receive side were stalling subsequent frames
and thus slowing tcpbench down.

I decided to disable the gap timeout entirely to see what would happen if
those missing frames were immediately skipped rather than waiting for them.
The result was stable throughput according to tcpbench.

I then wrote the patch below which keeps the gap timeout intact (it is needed
in case the peer stops sending anything) but skips missing frames at the head
of the Rx block window once a certain amount of frames have queued up. This
heuristics avoids having to wait for the timeout to fire in order to get
frames flowing again if we lose one of more frames during Rx traffic bursts.

I have picked a threshold of 16 outstanding frames based on local testing.
I have no idea if this is a good threshold for everyone. It would help to
get some feedback from tests in other RF environments and other types of 
access points. Any regressions?

diff e27fc20afa168944a7605737ac45330f21645404 /usr/src
blob - 098aa9bce19481ce09676ce3c4fc0040f14c9b93
file + sys/net80211/ieee80211_input.c
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -67,6 +67,7 @@ void  ieee80211_input_ba(struct ieee80211com *, struct 
struct mbuf_list *);
 void   ieee80211_input_ba_flush(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_rx_ba *, struct mbuf_list *);
+intieee80211_input_ba_gap_skip(struct ieee80211_rx_ba *);
 void   ieee80211_input_ba_gap_timeout(void *arg);
 void   ieee80211_ba_move_window(struct ieee80211com *,
struct ieee80211_node *, u_int8_t, u_int16_t, struct mbuf_list *);
@@ -837,10 +838,24 @@ ieee80211_input_ba(struct ieee80211com *ic, struct mbu
rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
ba->ba_buf[idx].rxi = *rxi;
 
-   if (ba->ba_buf[ba->ba_head].m == NULL)
-   timeout_add_msec(>ba_gap_to, IEEE80211_BA_GAP_TIMEOUT);
-   else if (timeout_pending(>ba_gap_to))
-   timeout_del(>ba_gap_to);
+   if (ba->ba_buf[ba->ba_head].m == NULL) {
+   if (ba->ba_gapwait < IEEE80211_BA_MAX_GAPWAIT) {
+   if (ba->ba_gapwait == 0)
+   timeout_add_msec(>ba_gap_to,
+   IEEE80211_BA_GAP_TIMEOUT);
+   ba->ba_gapwait++;
+   } else {
+   int skipped = ieee80211_input_ba_gap_skip(ba);
+   ic->ic_stats.is_ht_rx_ba_frame_lost += skipped;
+   ba->ba_gapwait = 0;
+   if (timeout_pending(>ba_gap_to))
+   timeout_del(>ba_gap_to);
+   }
+   } else {
+   ba->ba_gapwait = 0;
+   if (timeout_pending(>ba_gap_to))
+   timeout_del(>ba_gap_to);
+   }
 
ieee80211_input_ba_flush(ic, ni, ba, ml);
 }
@@ -902,6 +917,23 @@ ieee80211_input_ba_flush(struct ieee80211com *ic, stru
ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
 }
 
+int
+ieee80211_input_ba_gap_skip(struct ieee80211_rx_ba *ba)
+{
+   int skipped = 0;
+
+   while (skipped < ba->ba_winsize && ba->ba_buf[ba->ba_head].m == NULL) {
+   /* move window forward */
+   ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
+   ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff;
+   skipped++;
+   }
+   if (skipped > 0)
+   ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
+
+   return skipped;
+}
+
 /* 
  * Forcibly move the BA window forward to remove a leading gap which has
  * been causing frames to linger in the reordering buffer for too long.
@@ -921,17 +953,8 @@ ieee80211_input_ba_gap_timeout(void *arg)
 
s = splnet();
 
-   skipped = 0;
-   while (skipped < ba->ba_winsize && ba->ba_buf[ba->ba_head].m == NULL) {
-   /* move window forward */
-   ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
-   ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff;
-   skipped++;
-   ic->ic_stats.is_ht_rx_ba_frame_lost++;
-   }
-   if (skipped > 0)
-   ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
-
+   skipped = ieee80211_input_ba_gap_skip(ba);
+   ic->ic_stats.is_ht_rx_ba_frame_lost += skipped;
ieee80211_input_ba_flush(ic, ni, ba, );
if_input(>ic_if, );
 
@@ -2716,6 +2739,7 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, stru
ba->ba_token = token;
timeout_set(>ba_to, ieee80211_rx_ba_timeout, ba);
timeout_set(>ba_gap_to, 

iwn: fix automatic rate control for aggrated frames

2020-07-16 Thread Stefan Sperling
There's a logic bug in iwn(4) which means that automatic rate control
for A-MPDU runs while a fixed Tx MCS is configured with a command like
"ifconfig iwn0 media HT-MCS10 mode 11n".
The intention was of course the inverse: Use automatic rate control if
the Tx MCS is not fixed (i.e. if ic->ic_fixed_mcs == -1).
 
And there is a second bug which went unnoticed because of the above bug.
The value of 'seq' provided by firmware may be smaller than ba_winstart.
When this happens we trigger a KASSERT in ieee80211_output_ba_record_ack:
[[[
void
ieee80211_output_ba_record_ack(struct ieee80211com *ic,
struct ieee80211_node *ni, uint8_t tid, uint16_t ssn)
{
struct ieee80211_tx_ba *ba = >ni_tx_ba[tid];
int i = 0;
uint16_t s = ba->ba_winstart;

KASSERT(!SEQ_LT(ssn, ba->ba_winstart));
]]]

In fact, iwn_ampdu_rate_control() implicitly assumes that its 'seq'
parameter equals ba_winstart, so just pass that value directly.
Any frames before ba_winstart should already have been processed earlier.
They have been taken off the Tx ring already and any associated status
information about those frames has already been freed.

For clarity we could rename the 'seq' parameter of iwn_ampdu_rate_control()
to something like 'winstart'. But doing so would add a lot of noise to this
diff so I left that change out for now.

Technically, 'seq' is now unused, but I'd like to leave the code and its
comments intact because there is no information elsewhere about how this
part of the Intel firmware block ack mechanism works. I suppose the compiler
will optimize it away.

ok?

diff 595dd8c72381b17b942a17026a1ed6071864ca33 
3a86217247de0a2c279745d477ce0fd05e104135
blob - 7b3117d466e7d2ca798ddb1b01cef99e8b832dac
blob + 40a5316402f2ecc256b8ea777014595340cf7823
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2379,19 +2379,22 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
 * Multiple BA notifications in a row may be using this number, with
 * additional bits being set in cba->bitmap. It is unclear how the
 * firmware decides to shift this window forward.
+* We rely on ba->ba_winstart instead.
 */
seq = le16toh(cba->seq) >> IEEE80211_SEQ_SEQ_SHIFT;
 
/*
 * The firmware's new BA window starting sequence number
 * corresponds to the first hole in cba->bitmap, implying
-* that all frames between 'seq' and 'ssn' have been acked.
+* that all frames between 'seq' and 'ssn' (non-inclusive)
+* have been acked.
 */
ssn = le16toh(cba->ssn);
 
/* Skip rate control if our Tx rate is fixed. */
-   if (ic->ic_fixed_mcs != -1)
-   iwn_ampdu_rate_control(sc, ni, txq, cba->tid, seq, ssn);
+   if (ic->ic_fixed_mcs == -1)
+   iwn_ampdu_rate_control(sc, ni, txq, cba->tid, ba->ba_winstart,
+   ssn);
 
/*
 * SSN corresponds to the first (perhaps not yet transmitted) frame



iwn: fix off-by-one sequence number in iwn_ampdu_tx_done()

2020-07-16 Thread Stefan Sperling
Make iwn_ampdu_tx_done() record an ACK for the frame for which the hardware
triggered the Tx completion interrupt, instead of the frame with the starting
sequence number (SSN) of the firmware's block ack window. The frame at SSN
is unrelated and may not even have been transmitted yet.

ok?

diff 5345c351e74da1e58df9c8fa251f4dce69b95c33 
595dd8c72381b17b942a17026a1ed6071864ca33
blob - f42cb27d391168e5eb5a46fb79baea6ec8d017e9
blob + 7b3117d466e7d2ca798ddb1b01cef99e8b832dac
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2569,6 +2569,7 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_
int txfail = (status != IWN_TX_STATUS_SUCCESS &&
status != IWN_TX_STATUS_DIRECT_DONE);
struct ieee80211_tx_ba *ba;
+   uint16_t seq;
 
sc->sc_tx_timer = 0;
 
@@ -2654,10 +2655,8 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_
if (ba->ba_state != IEEE80211_BA_AGREED)
return;
 
-   /* This is a final single-frame Tx attempt. */
-   DPRINTFN(3, ("%s: final tx status=0x%x qid=%d queued=%d idx=%d ssn=%u "
-   "bitmap=0x%llx\n", __func__, status, desc->qid, txq->queued,
-   desc->idx, ssn, ba->ba_bitmap));
+   /* This was a final single-frame Tx attempt for frame SSN-1. */
+   seq = (ssn - 1) & 0xfff;
 
/*
 * Skip rate control if our Tx rate is fixed.
@@ -2677,22 +2676,22 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_
 
if (txfail)
ieee80211_tx_compressed_bar(ic, ni, tid, ssn);
-   else if (!SEQ_LT(ssn, ba->ba_winstart)) {
+   else if (!SEQ_LT(seq, ba->ba_winstart)) {
/*
-* Move window forward if SSN lies beyond end of window,
+* Move window forward if SEQ lies beyond end of window,
 * otherwise we can't record the ACK for this frame.
 * Non-acked frames which left holes in the bitmap near
 * the beginning of the window must be discarded.
 */
-   uint16_t s = ssn;
+   uint16_t s = seq;
while (SEQ_LT(ba->ba_winend, s)) {
ieee80211_output_ba_move_window(ic, ni, tid, s);
iwn_ampdu_txq_advance(sc, txq, desc->qid,
IWN_AGG_SSN_TO_TXQ_IDX(s));
s = (s + 1) % 0xfff;
}
-   /* SSN should now be within window; set corresponding bit. */
-   ieee80211_output_ba_record_ack(ic, ni, tid, ssn);
+   /* SEQ should now be within window; set corresponding bit. */
+   ieee80211_output_ba_record_ack(ic, ni, tid, seq);
}
 
/* Move window forward up to the first hole in the bitmap. */



fix wpa rsngroupcipher displayed by ifconfig

2020-07-11 Thread Stefan Sperling
When a wifi interface acts as a client, ifconfig will currently display
the default value 'ccmp' for the wpagroupcipher parameter, even while
associated to a WPA2 access point which uses TKIP as the group cipher
for WPA1 compatibility.

This patch updates the variable which gets copied out when ifconfig asks
for this information, so we get the group cipher displayed correctly.

This is a cosmetic problem only since the actual negotiation of the group
cipher is based on ni->ni_rsngroupcipher, not ic->ic_rsngroupcipher.

ok?

diff 21633c8848e72769b1658114d9c706c177040a2a /usr/src
blob - 333f6c1b22a6c027dd8f417430082d27587a6d2f
file + sys/net80211/ieee80211_pae_input.c
--- sys/net80211/ieee80211_pae_input.c
+++ sys/net80211/ieee80211_pae_input.c
@@ -651,6 +651,8 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
ni->ni_port_valid = 1;
ieee80211_set_link_state(ic, LINK_STATE_UP);
ni->ni_assoc_fail = 0;
+   if (ic->ic_opmode == IEEE80211_M_STA)
+   ic->ic_rsngroupcipher = ni->ni_rsngroupcipher;
}
}
  deauth:



11n Tx aggregation for iwm(4)

2020-06-26 Thread Stefan Sperling
This patch adds support for 11n Tx aggregation to iwm(4).

Please help with testing if you can by running the patch and using wifi
as usual. Nothing should change, except that Tx speed may potentially
improve. If you have time to run before/after performance measurements with
tcpbench or such, that would be nice. But it's not required for testing.

If Tx aggregation is active then netstat will show a non-zero output block ack
agreement counter:

$ netstat -W iwm0 | grep 'output block'
3 new output block ack agreements
0 output block ack agreements timed out

It would be great to get at least one test for all the chipsets the driver
supports: 7260, 7265, 3160, 3165, 3168, 8260, 8265, 9260, 9560
The behaviour of the access point also matters a great deal. It won't
hurt to test the same chipset against several different access points.

I have tested this version on 8265 only so far. I've run older revisions
of this patch on 7265 so I'm confident that this chip will work, too.
So far, the APs I have tested against are athn(4) in 11a mode and in 11n
mode with the 'nomimo' nwflag, and a Sagemcom 11ac AP. All on 5Ghz channels.

diff refs/heads/master refs/heads/txagg
blob - 3a75d07a60a7eb4c66540474e47aeffd7a85250a
blob + 853bdd1290ad509f5fce7b5bf20550f458a2b460
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -144,6 +144,8 @@
 #include 
 #include 
 #include 
+#include  /* for SEQ_LT */
+#undef DPRINTF /* defined in ieee80211_priv.h */
 
 #define DEVNAME(_s)((_s)->sc_dev.dv_xname)
 
@@ -299,7 +301,8 @@ int iwm_nic_rx_mq_init(struct iwm_softc *);
 intiwm_nic_tx_init(struct iwm_softc *);
 intiwm_nic_init(struct iwm_softc *);
 intiwm_enable_ac_txq(struct iwm_softc *, int, int);
-intiwm_enable_txq(struct iwm_softc *, int, int, int);
+intiwm_enable_txq(struct iwm_softc *, int, int, int, int, uint8_t,
+   uint16_t);
 intiwm_post_alive(struct iwm_softc *);
 struct iwm_phy_db_entry *iwm_phy_db_get_section(struct iwm_softc *, uint16_t,
uint16_t);
@@ -334,12 +337,12 @@ void  iwm_ampdu_rx_stop(struct ieee80211com *, struct 
i
uint8_t);
 void   iwm_sta_rx_agg(struct iwm_softc *, struct ieee80211_node *, uint8_t,
uint16_t, uint16_t, int);
-#ifdef notyet
+void   iwm_sta_tx_agg(struct iwm_softc *, struct ieee80211_node *, uint8_t,
+   uint16_t, uint16_t, int);
 intiwm_ampdu_tx_start(struct ieee80211com *, struct ieee80211_node *,
uint8_t);
 void   iwm_ampdu_tx_stop(struct ieee80211com *, struct ieee80211_node *,
uint8_t);
-#endif
 void   iwm_ba_task(void *);
 
 intiwm_parse_nvm_data(struct iwm_softc *, const uint16_t *,
@@ -372,14 +375,25 @@ int   iwm_rxmq_get_signal_strength(struct iwm_softc 
*, s
 void   iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_rx_data *);
 intiwm_get_noise(const struct iwm_statistics_rx_non_phy *);
+void   iwm_txq_advance(struct iwm_softc *, struct iwm_tx_ring *, int);
+void   iwm_ampdu_tx_done(struct iwm_softc *, struct iwm_cmd_header *,
+   struct iwm_node *, struct iwm_tx_ring *, uint32_t, uint8_t,
+   uint8_t, uint16_t, int, struct iwm_agg_tx_status *);
 intiwm_ccmp_decap(struct iwm_softc *, struct mbuf *,
struct ieee80211_node *);
 void   iwm_rx_frame(struct iwm_softc *, struct mbuf *, int, uint32_t, int, int,
uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *);
-void   iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
-   struct iwm_node *, int, int);
+void   iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_tx_resp *,
+   struct iwm_node *, int, int, int);
+void   iwm_txd_done(struct iwm_softc *, struct iwm_tx_data *);
 void   iwm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_rx_data *);
+void   iwm_clear_oactive(struct iwm_softc *, struct iwm_tx_ring *);
+void   iwm_mira_choose(struct iwm_softc *, struct ieee80211_node *);
+void   iwm_ampdu_rate_control(struct iwm_softc *, struct ieee80211_node *,
+   struct iwm_tx_ring *, int, uint16_t, uint16_t);
+void   iwm_rx_ba(struct iwm_softc *, struct iwm_rx_packet *,
+   struct iwm_rx_data *);
 void   iwm_rx_bmiss(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_rx_data *);
 intiwm_binding_cmd(struct iwm_softc *, struct iwm_node *, uint32_t);
@@ -399,6 +413,7 @@ int iwm_send_cmd_pdu_status(struct iwm_softc *, uint32
 void   iwm_free_resp(struct iwm_softc *, struct iwm_host_cmd *);
 void   iwm_cmd_done(struct iwm_softc *, int, int, int);
 void   iwm_update_sched(struct iwm_softc *, int, int, uint8_t, uint16_t);
+void   iwm_reset_sched(struct iwm_softc *, int, int, uint8_t);
 const struct iwm_rate *iwm_tx_fill_cmd(struct iwm_softc *, struct iwm_node *,
struct ieee80211_frame *, struct iwm_tx_cmd *);
 intiwm_tx(struct iwm_softc *, struct mbuf *, struct ieee80211_node *, int);
@@ -1306,17 +1321,17 @@ 

Re: vlan and bridge panic with latest snapshot

2020-06-22 Thread Stefan Sperling
On Mon, Jun 22, 2020 at 12:37:03PM +0200, Hrvoje Popovski wrote:
> for some reason i couldn't reproduce panic if i compile kernel with
> WITNESS and after that with or without your "if.c if_wg.c" commit 

The bug might not trigger if your ifconfig binary and kernel out of sync.
But that's just dumb luck.



iwx: fix length specification in probe requests

2020-06-19 Thread Stefan Sperling
Fix length specification for 2GHz band information element (IE) data in
the iwx(4) probe request template. The value that was being written
previously is too short so some IEs weren't included in the probe
request frame.

The active scanning code path is currently disabled in-tree, so this
fixes a bug in as of yet unused code.

Transmitted probe requests look alright with this fix and the other
fix I sent previously to avoid an unnecessary SSID copy.

ok?
 
diff 7559788cdf552c503c6d5124af11504b3bdf3e56 
e12181434a6e36b2fcc7734fbbbf11a2bca93a27
blob - f4d61c5993c26ff5df5052cc26402c433d03a3ae
blob + ca67248839d23af02c87c34fae6ae18ffaf96209
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -5028,7 +5028,6 @@ iwx_fill_probe_req(struct iwx_softc *sc, struct iwx_sc
frm = ieee80211_add_rates(frm, rs);
if (rs->rs_nrates > IEEE80211_RATE_SIZE)
frm = ieee80211_add_xrates(frm, rs);
-   preq->band_data[0].len = htole16(frm - pos);
remain -= frm - pos;
 
if (isset(sc->sc_enabled_capa, 
@@ -5040,6 +5039,7 @@ iwx_fill_probe_req(struct iwx_softc *sc, struct iwx_sc
*frm++ = 0;
remain -= 3;
}
+   preq->band_data[0].len = htole16(frm - pos);
 
if (sc->sc_nvm.sku_cap_band_52GHz_enable) {
/* Fill in 5GHz IEs. */



iwx: avoid unnecessary SSID copy

2020-06-19 Thread Stefan Sperling
Do not copy an SSID into the probe request template because hardware
will add the SSID by itself.

I have verified that probe requests transmitted by the device still
look good and contain the SSID configured by ifconfig.

Note that the in-tree driver does not send probe requests right now
because active scanning is disabled. There are known problems when
active scanning is enabled that I still need to get back to.

ok?
 
diff d5a17cd5fc2d0da90d4870589fc45e6eb0bb64f5 
7559788cdf552c503c6d5124af11504b3bdf3e56
blob - cb9f612f1f103f2a3cb6563c3ad1a0ca49f7a47d
blob + f4d61c5993c26ff5df5052cc26402c433d03a3ae
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -5007,7 +5007,9 @@ iwx_fill_probe_req(struct iwx_softc *sc, struct iwx_sc
*(uint16_t *)>i_seq[0] = 0; /* filled by HW */
 
frm = (uint8_t *)(wh + 1);
-   frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
+   *frm++ = IEEE80211_ELEMID_SSID;
+   *frm++ = 0;
+   /* hardware inserts SSID */
 
/* Tell the firmware where the MAC header is. */
preq->mac_header.offset = 0;



iwx: fix bad write to scan command

2020-06-19 Thread Stefan Sperling
This fixes a wrong unconditional write to a field of the scan command.

The scan command struct is a hell of a union of structs which represent
different versions of the scan command. This coding style makes it easy to
write to a wrong offset by accident. I intend to eventually clean this up
but I'm not sure yet which scan command versions will be needed for all the
devices that iwx(4) could cover in the future. So I'm keeping the scan
command data structures aligned with the Linux driver code for now.

ok?
 
diff a6511f65cdcb27cc87ec2022a72e2600f0ab8969 
27b87cbc607cd7feeac9d8b53142a430792e9a5b
blob - ca6d9fead056a08b48f61b30f2107afa68ebcda3
blob + 8fe53e36421a57841702a16a86f4b9f8e25bb681
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -5261,6 +5261,8 @@ iwx_umac_scan(struct iwx_softc *sc, int bgscan)
req->v1.passive_dwell = 110;
req->v1.fragmented_dwell = 44;
req->v1.extended_dwell = 90;
+
+   req->v1.scan_priority = htole32(IWX_SCAN_PRIORITY_HIGH);
}
 
if (bgscan) {
@@ -5279,7 +5281,6 @@ iwx_umac_scan(struct iwx_softc *sc, int bgscan)
}
}
 
-   req->v1.scan_priority = htole32(IWX_SCAN_PRIORITY_HIGH);
req->ooc_priority = htole32(IWX_SCAN_PRIORITY_HIGH);
 
cmd_data = iwx_get_scan_req_umac_data(sc, req);





iwx: enable critical temperature detection

2020-06-19 Thread Stefan Sperling
iwx(4) hardware can monitor device temperature and notify the driver when
a critical temperature has been reached.

This patch enables the mechanism. The driver will now turn the device off
and print a message to dmesg if the firmware signals critical temperature.

Comments in Linux source code (reproduced in this patch) imply that firmware
will also make use of a Tx-backoff mechanism to regulate temperature.

I have been doing driver development and testing for a while now with this
patch in place and no visible downsides. I've not seen a critical temperature
notification yet and I'd rather not try to provoke one since I only have one
device :-)

ok?

diff 46dd352d1f9381c0e7702f0426f195b14c3d66d8 
a6511f65cdcb27cc87ec2022a72e2600f0ab8969
blob - c44544816b57a627e8b071c1ebcb8408742d9f8c
blob + ca6d9fead056a08b48f61b30f2107afa68ebcda3
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -437,6 +437,7 @@ int iwx_sf_config(struct iwx_softc *, int);
 intiwx_send_bt_init_conf(struct iwx_softc *);
 intiwx_send_soc_conf(struct iwx_softc *);
 intiwx_send_update_mcc_cmd(struct iwx_softc *, const char *);
+intiwx_send_temp_report_ths_cmd(struct iwx_softc *);
 intiwx_init_hw(struct iwx_softc *);
 intiwx_init(struct ifnet *);
 void   iwx_start(struct ifnet *);
@@ -6813,6 +6814,29 @@ out:
 }
 
 int
+iwx_send_temp_report_ths_cmd(struct iwx_softc *sc)
+{
+   struct iwx_temp_report_ths_cmd cmd;
+   int err;
+
+   /*
+* In order to give responsibility for critical-temperature-kill
+* and TX backoff to FW we need to send an empty temperature
+* reporting command at init time.
+*/
+   memset(, 0, sizeof(cmd));
+
+   err = iwx_send_cmd_pdu(sc,
+   IWX_WIDE_ID(IWX_PHY_OPS_GROUP, IWX_TEMP_REPORTING_THRESHOLDS_CMD),
+   0, sizeof(cmd), );
+   if (err)
+   printf("%s: TEMP_REPORT_THS_CMD command failed (error %d)\n",
+   DEVNAME(sc), err);
+
+   return err;
+}
+
+int
 iwx_init_hw(struct iwx_softc *sc)
 {
struct ieee80211com *ic = >sc_ic;
@@ -6896,6 +6920,12 @@ iwx_init_hw(struct iwx_softc *sc)
DEVNAME(sc), err);
}
 
+   if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_CT_KILL_BY_FW)) {
+   err = iwx_send_temp_report_ths_cmd(sc);
+   if (err)
+   goto err;
+   }
+
err = iwx_power_update_device(sc);
if (err) {
printf("%s: could not send power command (error %d)\n",
@@ -7614,7 +7644,21 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *d
case IWX_DTS_MEASUREMENT_NOTIFICATION:
case IWX_WIDE_ID(IWX_PHY_OPS_GROUP,
 IWX_DTS_MEASUREMENT_NOTIF_WIDE):
+   case IWX_WIDE_ID(IWX_PHY_OPS_GROUP,
+IWX_TEMP_REPORTING_THRESHOLDS_CMD):
break;
+
+   case IWX_WIDE_ID(IWX_PHY_OPS_GROUP,
+   IWX_CT_KILL_NOTIFICATION): {
+   struct iwx_ct_kill_notif *notif;
+   SYNC_RESP_STRUCT(notif, pkt);
+   printf("%s: device at critical temperature (%u degC), "
+   "stopping device\n",
+   DEVNAME(sc), le16toh(notif->temperature));
+   sc->sc_flags |= IWX_FLAG_HW_ERR;
+   task_add(systq, >init_task);
+   break;
+   }
 
case IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP,
IWX_NVM_GET_INFO):
blob - 0892fd4e61f3ce4d57c2770395a07c13c4386a8e
blob + 74f17f31c85ca3a67b3fcbc1699a167d04ea6c6c
--- sys/dev/pci/if_iwxreg.h
+++ sys/dev/pci/if_iwxreg.h
@@ -1685,6 +1685,31 @@ struct iwx_phy_cfg_cmd {
 #define IWX_PHY_CFG_RX_CHAIN_B (1 << 13)
 #define IWX_PHY_CFG_RX_CHAIN_C (1 << 14)
 
+#define IWX_MAX_DTS_TRIPS  8
+
+/**
+ * struct iwx_ct_kill_notif - CT-kill entry notification
+ *
+ * @temperature: the current temperature in celsius
+ * @reserved: reserved
+ */
+struct iwx_ct_kill_notif {
+   uint16_t temperature;
+   uint16_t reserved;
+} __packed; /* GRP_PHY_CT_KILL_NTF */
+
+/**
+ * struct iwx_temp_report_ths_cmd - set temperature thresholds
+ * (IWX_TEMP_REPORTING_THRESHOLDS_CMD)
+ *
+ * @num_temps: number of temperature thresholds passed
+ * @thresholds: array with the thresholds to be configured
+ */
+struct iwx_temp_report_ths_cmd {
+   uint32_t num_temps;
+   uint16_t thresholds[IWX_MAX_DTS_TRIPS];
+} __packed; /* GRP_PHY_TEMP_REPORTING_THRESHOLDS_CMD */
+
 #define IWX_NVM_VERSION0
 
 /* 8k family NVM HW-Section offset (in words) definitions */



iwx: offload WPA2 crypto to hardware

2020-06-17 Thread Stefan Sperling
This patch implements WPA2 (CCMP) crypto offload for iwx(4).
The patch will only work on top of an up-to-date tree. Note that I just
committed another patch (Tx rate selection offload) to CVS which is
required in order to test this CCMP offload patch.

ok?
 
diff 928c82450e6e5ea105cab6ca7a7766c4b84f1e21 
730c65a14bf291ecd58baa8b3cc72e18ca34903d
blob - 113362f4c0f4a672dc8ef719bd95964a53817db5
blob + d3fa66b174be1e0200e95254640f95c60c0e4508
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -349,8 +349,10 @@ intiwx_rxmq_get_signal_strength(struct iwx_softc 
*, s
 void   iwx_rx_rx_phy_cmd(struct iwx_softc *, struct iwx_rx_packet *,
struct iwx_rx_data *);
 intiwx_get_noise(const struct iwx_statistics_rx_non_phy *);
-void   iwx_rx_frame(struct iwx_softc *, struct mbuf *, int, int, int, uint32_t,
-   struct ieee80211_rxinfo *, struct mbuf_list *);
+intiwx_ccmp_decap(struct iwx_softc *, struct mbuf *,
+   struct ieee80211_node *);
+void   iwx_rx_frame(struct iwx_softc *, struct mbuf *, int, uint32_t, int, int,
+   uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *);
 void   iwx_enable_ht_cck_fallback(struct iwx_softc *, struct iwx_node *);
 void   iwx_rx_tx_cmd_single(struct iwx_softc *, struct iwx_rx_packet *,
struct iwx_node *, int, int);
@@ -420,6 +422,10 @@ intiwx_disassoc(struct iwx_softc *);
 intiwx_run(struct iwx_softc *);
 intiwx_run_stop(struct iwx_softc *);
 struct ieee80211_node *iwx_node_alloc(struct ieee80211com *);
+intiwx_set_key(struct ieee80211com *, struct ieee80211_node *,
+   struct ieee80211_key *);
+void   iwx_delete_key(struct ieee80211com *,
+   struct ieee80211_node *, struct ieee80211_key *);
 void   iwx_calib_timeout(void *);
 intiwx_media_change(struct ifnet *);
 void   iwx_newstate_task(void *);
@@ -3538,16 +3544,65 @@ iwx_get_noise(const struct iwx_statistics_rx_non_phy *
return (nbant == 0) ? -127 : (total / nbant) - 107;
 }
 
+int
+iwx_ccmp_decap(struct iwx_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
+{
+   struct ieee80211com *ic = >sc_ic;
+   struct ieee80211_key *k = >ni_pairwise_key;
+   struct ieee80211_frame *wh;
+   uint64_t pn, *prsc;
+   uint8_t *ivp;
+   uint8_t tid;
+   int hdrlen, hasqos;
+
+   wh = mtod(m, struct ieee80211_frame *);
+   hdrlen = ieee80211_get_hdrlen(wh);
+   ivp = (uint8_t *)wh + hdrlen;
+
+   /* Check that ExtIV bit is be set. */
+   if (!(ivp[3] & IEEE80211_WEP_EXTIV))
+   return 1;
+
+   hasqos = ieee80211_has_qos(wh);
+   tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
+   prsc = >k_rsc[tid];
+
+   /* Extract the 48-bit PN from the CCMP header. */
+   pn = (uint64_t)ivp[0]   |
+(uint64_t)ivp[1] <<  8 |
+(uint64_t)ivp[4] << 16 |
+(uint64_t)ivp[5] << 24 |
+(uint64_t)ivp[6] << 32 |
+(uint64_t)ivp[7] << 40;
+   if (pn <= *prsc) {
+   ic->ic_stats.is_ccmp_replays++;
+   return 1;
+   }
+   /* Last seen packet number is updated in ieee80211_inputm(). */
+
+   /*
+* Some firmware versions strip the MIC, and some don't. It is not
+* clear which of the capability flags could tell us what to expect.
+* For now, keep things simple and just leave the MIC in place if
+* it is present.
+*
+* The IV will be stripped by ieee80211_inputm().
+*/
+   return 0;
+}
+
 void
 iwx_rx_frame(struct iwx_softc *sc, struct mbuf *m, int chanidx,
- int is_shortpre, int rate_n_flags, uint32_t device_timestamp,
- struct ieee80211_rxinfo *rxi, struct mbuf_list *ml)
+uint32_t rx_pkt_status, int is_shortpre, int rate_n_flags,
+uint32_t device_timestamp, struct ieee80211_rxinfo *rxi,
+struct mbuf_list *ml)
 {
struct ieee80211com *ic = >sc_ic;
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct ieee80211_channel *bss_chan;
uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
+   struct ifnet *ifp = IC2IFP(ic);
 
if (chanidx < 0 || chanidx >= nitems(ic->ic_channels))  
chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
@@ -3564,6 +3619,37 @@ iwx_rx_frame(struct iwx_softc *sc, struct mbuf *m, int
}
ni->ni_chan = >ic_channels[chanidx];
 
+   /* Handle hardware decryption. */
+   if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL)
+   && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
+   (ni->ni_flags & IEEE80211_NODE_RXPROT) &&
+   ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) {
+   if ((rx_pkt_status & IWX_RX_MPDU_RES_STATUS_SEC_ENC_MSK) !=
+   IWX_RX_MPDU_RES_STATUS_SEC_CCM_ENC) {
+   ic->ic_stats.is_ccmp_dec_errs++;
+   ifp->if_ierrors++;
+   

iwx: offload Tx rate selection

2020-06-11 Thread Stefan Sperling
Intel has moved Tx rate selection code from the Linux iwlwifi driver into
ax200 device firmware. There is code in iwlwifi/mvm/rs.c which should more
or less match what the firmware is doing, given how the firmware API works.

Equivalent functionality is offered by AMRR/MiRA in our kernel.
During initial development I decided to keep Tx rate selection in the driver.
The firmware still allows the driver to force a Tx rate so I could reuse
Tx rate selection code inherited from iwm(4). But going forward it makes
sense to reduce our differences in behaviour to the Linux driver.

Offloading Tx rate selection should allow us to eventually delete a
non-trivial amount of code from iwx(4).
That code is disabled by my patch, not yet deleted.

For now, the driver restricts the firmware to 11n/20MHz operation because
that's what net80211 can support. Offloading Tx rate selection should make
it somewhat easier to eventually add 11ac support to iwx(4) since we won't
have to worry about adding 11ac support to MiRA first.

The firmware will notify the driver when it decides to change Tx rate.
Based on those notifications the driver updates the value displayed by
ifconfig. This is similar to how bwfm(4) and urtwn(4) handle this.

The firmware's Tx rate selection algorithm tends to pick "faster" Tx rates
than our kernel. But I don't see much difference compared to AMRR/MiRA.
Keep in mind that because we don't offload WPA2 crypto yet a very fast
CPU is required for best performance.

ok?

diff 6b8d7eb2718cb6a24e8079826c06467f5510a0d7 
9eab1fff69f13bad0dd4fd1b1f9d77e6adca61f7
blob - fdf9db0c88ec9d3c196b298b785a307dfc74d482
blob + 113362f4c0f4a672dc8ef719bd95964a53817db5
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -409,6 +409,9 @@ int iwx_scan(struct iwx_softc *);
 intiwx_bgscan(struct ieee80211com *);
 intiwx_umac_scan_abort(struct iwx_softc *);
 intiwx_scan_abort(struct iwx_softc *);
+intiwx_rs_rval2idx(uint8_t);
+uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ieee80211_node *, int);
+intiwx_rs_init(struct iwx_softc *, struct iwx_node *);
 intiwx_enable_data_tx_queues(struct iwx_softc *);
 intiwx_auth(struct iwx_softc *);
 intiwx_deauth(struct iwx_softc *);
@@ -3775,6 +3778,7 @@ iwx_rx_tx_cmd_single(struct iwx_softc *sc, struct iwx_
in->in_mn.retries += tx_resp->failure_frame;
if (txfail)
in->in_mn.txfail += tx_resp->frame_count;
+#if 0
if (ic->ic_state == IEEE80211_S_RUN && !in->ht_force_cck) {
int otxmcs = ni->ni_txmcs;
 
@@ -3785,6 +3789,7 @@ iwx_rx_tx_cmd_single(struct iwx_softc *sc, struct iwx_
otxmcs == 0 && ni->ni_txmcs == 0)
iwx_enable_ht_cck_fallback(sc, in);
}
+#endif
}
 
if (txfail)
@@ -4294,10 +4299,13 @@ iwx_tx_fill_cmd(struct iwx_softc *sc, struct iwx_node 
type != IEEE80211_FC0_TYPE_DATA) {
/* for non-data, use the lowest supported rate */
ridx = min_ridx;
+   flags |= IWX_TX_FLAGS_CMD_RATE;
} else if (ic->ic_fixed_mcs != -1) {
ridx = sc->sc_fixed_ridx;
+   flags |= IWX_TX_FLAGS_CMD_RATE;
} else if (ic->ic_fixed_rate != -1) {
ridx = sc->sc_fixed_ridx;
+   flags |= IWX_TX_FLAGS_CMD_RATE;
} else if ((ni->ni_flags & IEEE80211_NODE_HT) && !in->ht_force_cck) {
ridx = iwx_mcs2ridx[ni->ni_txmcs];
} else {
@@ -4308,7 +4316,7 @@ iwx_tx_fill_cmd(struct iwx_softc *sc, struct iwx_node 
ridx = min_ridx;
}
 
-   flags = (IWX_TX_FLAGS_CMD_RATE | IWX_TX_FLAGS_ENCRYPT_DIS);
+   flags |= IWX_TX_FLAGS_ENCRYPT_DIS;
if ((ic->ic_flags & IEEE80211_F_RSNON) &&
ni->ni_rsn_supp_state == RSNA_SUPP_PTKNEGOTIATING)
flags |= IWX_TX_FLAGS_HIGH_PRI;
@@ -5751,6 +5759,120 @@ iwx_enable_data_tx_queues(struct iwx_softc *sc)
 }
 
 int
+iwx_rs_rval2idx(uint8_t rval)
+{
+   /* Firmware expects indices which match our 11g rate set. */
+   const struct ieee80211_rateset *rs = _std_rateset_11g;
+   int i;
+
+   for (i = 0; i < rs->rs_nrates; i++) {
+   if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rval)
+   return i;
+   }
+
+   return -1;
+}
+
+uint16_t
+iwx_rs_ht_rates(struct iwx_softc *sc, struct ieee80211_node *ni, int rsidx)
+{
+   struct ieee80211com *ic = >sc_ic;
+   const struct ieee80211_ht_rateset *rs;
+   uint16_t htrates = 0;
+   int mcs;
+
+   rs = _std_ratesets_11n[rsidx];
+   for (mcs = rs->min_mcs; mcs <= rs->max_mcs; mcs++) {
+   if (!isset(ni->ni_rxmcs, mcs) ||
+   !isset(ic->ic_sup_mcs, mcs))
+   continue;
+   htrates |= (1 << (mcs - rs->min_mcs));
+   }
+
+   return htrates;
+}
+
+int
+iwx_rs_init(struct iwx_softc 

Re: iwn/iwm/iwx: remove useless memcpy

2020-06-11 Thread Stefan Sperling
On Thu, Jun 11, 2020 at 11:00:30AM +0200, Mark Kettenis wrote:
> > Date: Thu, 11 Jun 2020 10:48:09 +0200
> > From: Stefan Sperling 
> > 
> > I spotted this while working on iwx(4).
> > 
> > Setting up ic_myaddr when we're about to scan for APs is rather late in
> > the game. All these drivers are already setting up ic_myaddr during the
> > device initialization phase, long before they get here.
> > 
> > This seems to be a copy-paste error in iwn(4) originally.
> > The older wpi(4) driver has similar code which doesn't have this.
> > 
> > ok?
> 
> Hmm, won't this affect the ability to changed the lladdr while the
> interface is up?

That was never possible.
Changing LLADDR implies ENETRESET, i.e. a down -> up cycle.



iwn/iwm/iwx: remove useless memcpy

2020-06-11 Thread Stefan Sperling
I spotted this while working on iwx(4).

Setting up ic_myaddr when we're about to scan for APs is rather late in
the game. All these drivers are already setting up ic_myaddr during the
device initialization phase, long before they get here.

This seems to be a copy-paste error in iwn(4) originally.
The older wpi(4) driver has similar code which doesn't have this.

ok?

diff 66ecf2e2f524653126dce17a447a43b26ee90abb /usr/src
blob - 69c252f4e8a6283d2e7f22c7b815feb769a4c694
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -5610,7 +5610,6 @@ int
 iwm_fill_probe_req(struct iwm_softc *sc, struct iwm_scan_probe_req *preq)
 {
struct ieee80211com *ic = >sc_ic;
-   struct ifnet *ifp = IC2IFP(ic);
struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf;
struct ieee80211_rateset *rs;
size_t remain = sizeof(preq->buf);
@@ -5628,7 +5627,6 @@ iwm_fill_probe_req(struct iwm_softc *sc, struct iwm_sc
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
IEEE80211_FC0_SUBTYPE_PROBE_REQ;
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
-   IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr);
blob - 76bdd28a6d3b3f392fabb05fcd726d86976ec43e
file + sys/dev/pci/if_iwn.c
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -5190,7 +5190,6 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags, int bgs
struct ieee80211_frame *wh;
struct ieee80211_rateset *rs;
struct ieee80211_channel *c;
-   struct ifnet *ifp = >ic_if;
uint8_t *buf, *frm;
uint16_t rxchain, dwell_active, dwell_passive;
uint8_t txant;
@@ -5294,7 +5293,6 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags, int bgs
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
IEEE80211_FC0_SUBTYPE_PROBE_REQ;
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
-   IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr);
blob - c3ca08c7a726326e37cda8645596a176051b6cf4
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -4705,7 +4705,6 @@ int
 iwx_fill_probe_req(struct iwx_softc *sc, struct iwx_scan_probe_req *preq)
 {
struct ieee80211com *ic = >sc_ic;
-   struct ifnet *ifp = IC2IFP(ic);
struct ieee80211_frame *wh = (struct ieee80211_frame *)preq->buf;
struct ieee80211_rateset *rs;
size_t remain = sizeof(preq->buf);
@@ -4723,7 +4722,6 @@ iwx_fill_probe_req(struct iwx_softc *sc, struct iwx_sc
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
IEEE80211_FC0_SUBTYPE_PROBE_REQ;
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
-   IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr);



iwx: increase command queue size

2020-06-10 Thread Stefan Sperling
Increase iwx(4) firmware command queue size.

Otherwise, the firmware will eventually send spurious "command done"
notifications for commands which were completed successfully earlier
(which looks like a ring overflow) and then crash with a fatal error.

This is required to get -48 firmware to work without fatal firmware errors.

ok?

diff 593cf89bed2f9f27ccf55d4cebf8aa65c36c7bb1 
047e3a7211742260b7a9097053380f87b72b3eae
blob - d6c823fe64ce7509e69c5b4ec20fdfa8681cfb2d
blob + 7781f264940a644deff624a05a3b9ce2b65d
--- sys/dev/pci/if_iwxreg.h
+++ sys/dev/pci/if_iwxreg.h
@@ -1402,7 +1402,7 @@ enum iwx_gen2_tx_fifo {
 #define IWX_TX_QUEUE_CFG_TFD_SHORT_FORMAT  (1 << 1)
 
 #define IWX_DEFAULT_QUEUE_SIZE IWX_TFD_QUEUE_SIZE_MAX
-#define IWX_CMD_QUEUE_SIZE 32
+#define IWX_CMD_QUEUE_SIZE 64
 
 /**
  * struct iwx_tx_queue_cfg_cmd - txq hw scheduler config command



iwx: do not load the firmware twice

2020-06-10 Thread Stefan Sperling
Firmware loading code inherited from iwm(4) loads firmware twice:
Once to load the 'INIT' (boot) device firmware, and a second time
to load the RT (run-time) device firmware. Both of these firmware
images are part of the single firmware file in /etc/firmware.

With iwx(4) devices only a single load is required. Double-loading the
firmware seems to be the reason for various fatal firmware errors.

The older -46 firmware we currently use works to some extent anyway,
which is why this problem wasn't obvious at all and took quite a
while to track down.

The -48 version of the firmware was extremely unhappy and just went
into fatal firmware error mode as soon as the driver tried to send
a frame. I have that firmware version working locally now with this
change and some additional fixes.

With this change regulatory domain updates start appearing on both
firmware versions. Which suggests that we never actually had the
firmware running in a fully operational state before.
I have already sent another patch which adds support for these
regulatory domain notifications.

ok?
 
diff 3387c0fc20f29323f58bb3abae4a685d2cca4969 
593cf89bed2f9f27ccf55d4cebf8aa65c36c7bb1
blob - eaad5ad73abbd1d25eb5895de88cf48e731abfcc
blob + bb81a869c36b13d7bf5cb7c037a4c023d9baf6d0
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -6547,20 +6547,6 @@ iwx_init_hw(struct iwx_softc *sc)
if (err)
return err;
 
-   /* Should stop and start HW since INIT image just loaded. */
-   iwx_stop_device(sc);
-   err = iwx_start_hw(sc);
-   if (err) {
-   printf("%s: could not initialize hardware\n", DEVNAME(sc));
-   return err;
-   }
-
-   err = iwx_load_ucode_wait_alive(sc);
-   if (err) {
-   printf("%s: could not load firmware\n", DEVNAME(sc));
-   goto err;
-   }
-
if (!iwx_nic_lock(sc))
return EBUSY;
 



iwx: handle regulatory domain updates

2020-06-10 Thread Stefan Sperling
(This patch depends on the iwx NVM parser patch which I just sent
out previously. This patch won't apply otherwise.)

iwx(4) devices have a hardware component that can detect which country
it is running in. The firmware will then inform the driver about the
auto-detected regulatory domain.

Currently we don't see this notification due to a bug in our driver.
I have a fix for that other bug which I will send out separately.
If we do not handle the regulatory domain notification, this other
fix would result in messages like:
iwx0: unhandled firmware response 0xc9/0x2008 rx ring 64[35]

For now, just print a message which shows the detected regulatory domain
if 'ifconfig iwx0 debug' is enabled. It is up to the driver whether it
wants to react to regulatory domain updates.

ok?

diff e883cbeb57aae26539e3cf9c73701c2e0d44bb50 
3387c0fc20f29323f58bb3abae4a685d2cca4969
blob - f99f211301ac2da8cc350549e9fc029852c971fb
blob + eaad5ad73abbd1d25eb5895de88cf48e731abfcc
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -392,6 +392,7 @@ int iwx_rm_sta_cmd(struct iwx_softc *, struct iwx_node
 intiwx_fill_probe_req(struct iwx_softc *, struct iwx_scan_probe_req *);
 intiwx_config_umac_scan(struct iwx_softc *);
 intiwx_umac_scan(struct iwx_softc *, int);
+void   iwx_mcc_update(struct iwx_softc *, struct iwx_mcc_chub_notif *);
 uint8_tiwx_ridx2rate(struct ieee80211_rateset *, int);
 intiwx_rval2ridx(int);
 void   iwx_ack_rates(struct iwx_softc *, struct iwx_node *, int *, int *);
@@ -2709,12 +2710,15 @@ iwx_init_channel_map(struct iwx_softc *sc, uint16_t *c
if (is_5ghz && !data->sku_cap_band_52GHz_enable)
ch_flags &= ~IWX_NVM_CHANNEL_VALID;
 
-   if (!(ch_flags & IWX_NVM_CHANNEL_VALID))
-   continue;
-
hw_value = nvm_channels[ch_idx];
channel = >ic_channels[hw_value];
 
+   if (!(ch_flags & IWX_NVM_CHANNEL_VALID)) {
+   channel->ic_freq = 0;
+   channel->ic_flags = 0;
+   continue;
+   }
+
if (!is_5ghz) {
flags = IEEE80211_CHAN_2GHZ;
channel->ic_flags
@@ -5245,6 +5249,24 @@ iwx_umac_scan(struct iwx_softc *sc, int bgscan)
return err;
 }
 
+void
+iwx_mcc_update(struct iwx_softc *sc, struct iwx_mcc_chub_notif *notif)
+{
+   struct ieee80211com *ic = >sc_ic;
+   struct ifnet *ifp = IC2IFP(ic);
+   char alpha2[3];
+
+   snprintf(alpha2, sizeof(alpha2), "%c%c",
+   (le16toh(notif->mcc) & 0xff00) >> 8, le16toh(notif->mcc) & 0xff);
+
+   if (ifp->if_flags & IFF_DEBUG) {
+   printf("%s: firmware has detected regulatory domain '%s' "
+   "(0x%x)\n", DEVNAME(sc), alpha2, le16toh(notif->mcc));
+   }
+
+   /* TODO: Schedule a task to send MCC_UPDATE_CMD? */
+}
+
 uint8_t
 iwx_ridx2rate(struct ieee80211_rateset *rs, int ridx)
 {
@@ -6454,6 +6476,9 @@ iwx_send_update_mcc_cmd(struct iwx_softc *sc, const ch
.flags = IWX_CMD_WANT_RESP,
.data = { _cmd },
};
+   struct iwx_rx_packet *pkt;
+   struct iwx_mcc_update_resp *resp;
+   size_t resp_len;
int err;
 
memset(_cmd, 0, sizeof(mcc_cmd));
@@ -6465,16 +6490,41 @@ iwx_send_update_mcc_cmd(struct iwx_softc *sc, const ch
mcc_cmd.source_id = IWX_MCC_SOURCE_OLD_FW;
 
hcmd.len[0] = sizeof(struct iwx_mcc_update_cmd);
-   hcmd.resp_pkt_len = sizeof(struct iwx_rx_packet) +
-   sizeof(struct iwx_mcc_update_resp);
+   hcmd.resp_pkt_len = IWX_CMD_RESP_MAX;
 
err = iwx_send_cmd(sc, );
if (err)
return err;
 
+   pkt = hcmd.resp_pkt;
+   if (!pkt || (pkt->hdr.flags & IWX_CMD_FAILED_MSK)) {
+   err = EIO;
+   goto out;
+   }
+
+   resp_len = iwx_rx_packet_payload_len(pkt);
+   if (resp_len < sizeof(*resp)) {
+   err = EIO;
+   goto out;
+   }
+
+   resp = (void *)pkt->data;
+   if (resp_len != sizeof(*resp) +
+   resp->n_channels * sizeof(resp->channels[0])) {
+   err = EIO;
+   goto out;
+   }
+
+   DPRINTF(("MCC status=0x%x mcc=0x%x cap=0x%x time=0x%x geo_info=0x%x 
source_id=0x%d n_channels=%u\n",
+   resp->status, resp->mcc, resp->cap, resp->time, resp->geo_info, 
resp->source_id, resp->n_channels));
+
+   /* Update channel map for net80211 and our scan configuration. */
+   iwx_init_channel_map(sc, NULL, resp->channels, resp->n_channels);
+
+out:
iwx_free_resp(sc, );
 
-   return 0;
+   return err;
 }
 
 int
@@ -7365,6 +7415,13 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *d
break;
}
 
+   case IWX_MCC_CHUB_UPDATE_CMD: {
+   struct iwx_mcc_chub_notif *notif;
+   

iwx: stop reading NVM directly

2020-06-10 Thread Stefan Sperling
The iwx(4) firmware offers a command which reads data stored in non-volative
memory of the device. Currently the driver still parses this data directly
with a parser inherited from iwm(4). Use the command instead, which matches
what Linux does on this hardware and is future-proof.

The old parser is disabled with #if 0 in this diff. The diff becomes unreadable
if the old code gets removed at the same time. I can remove the old code later.

ok?

diff f1d28b72d0b54d89dd3bb820cb5c91a8709d1640 
e883cbeb57aae26539e3cf9c73701c2e0d44bb50
blob - 2a770aa05771214b055de5c570fa155b9cb39433
blob + f99f211301ac2da8cc350549e9fc029852c971fb
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -160,6 +160,20 @@ const uint8_t iwx_nvm_channels_8000[] = {
149, 153, 157, 161, 165, 169, 173, 177, 181
 };
 
+static const uint8_t iwx_nvm_channels_uhb[] = {
+   /* 2.4 GHz */
+   1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+   /* 5 GHz */
+   36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
+   96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
+   149, 153, 157, 161, 165, 169, 173, 177, 181,
+   /* 6-7 GHz */
+   1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69,
+   73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129,
+   133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185,
+   189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233
+};
+
 #define IWX_NUM_2GHZ_CHANNELS  14
 
 const struct iwx_rate {
@@ -291,8 +305,7 @@ int iwx_nvm_read_chunk(struct iwx_softc *, uint16_t, u
uint8_t *, uint16_t *);
 intiwx_nvm_read_section(struct iwx_softc *, uint16_t, uint8_t *,
uint16_t *, size_t);
-void   iwx_init_channel_map(struct iwx_softc *, const uint16_t * const,
-   const uint8_t *nvm_channels, int nchan);
+void   iwx_init_channel_map(struct iwx_softc *, uint16_t *, uint32_t *, int);
 void   iwx_setup_ht_rates(struct iwx_softc *);
 intiwx_mimo_enabled(struct iwx_softc *);
 void   iwx_htprot_task(void *);
@@ -315,6 +328,9 @@ int iwx_parse_nvm_data(struct iwx_softc *, const uint1
const uint16_t *, const uint16_t *,
const uint16_t *, const uint16_t *,
const uint16_t *, int);
+intiwx_set_mac_addr_from_csr(struct iwx_softc *, struct iwx_nvm_data *);
+intiwx_is_valid_mac_addr(const uint8_t *);
+intiwx_nvm_get(struct iwx_softc *);
 void   iwx_set_hw_address_8000(struct iwx_softc *, struct iwx_nvm_data *,
const uint16_t *, const uint16_t *);
 intiwx_parse_nvm_sections(struct iwx_softc *, struct iwx_nvm_section *);
@@ -2662,22 +2678,35 @@ iwx_fw_valid_rx_ant(struct iwx_softc *sc)
 }
 
 void
-iwx_init_channel_map(struct iwx_softc *sc, const uint16_t * const nvm_ch_flags,
-const uint8_t *nvm_channels, int nchan)
+iwx_init_channel_map(struct iwx_softc *sc, uint16_t *channel_profile_v3,
+uint32_t *channel_profile_v4, int nchan_profile)
 {
struct ieee80211com *ic = >sc_ic;
struct iwx_nvm_data *data = >sc_nvm;
int ch_idx;
struct ieee80211_channel *channel;
-   uint16_t ch_flags;
+   uint32_t ch_flags;
int is_5ghz;
int flags, hw_value;
+   int nchan;
+   const uint8_t *nvm_channels;
 
-   for (ch_idx = 0; ch_idx < nchan; ch_idx++) {
-   ch_flags = le16_to_cpup(nvm_ch_flags + ch_idx);
+   if (sc->sc_uhb_supported) {
+   nchan = nitems(iwx_nvm_channels_uhb);
+   nvm_channels = iwx_nvm_channels_uhb;
+   } else {
+   nchan = nitems(iwx_nvm_channels_8000);
+   nvm_channels = iwx_nvm_channels_8000;
+   }
 
-   if (ch_idx >= IWX_NUM_2GHZ_CHANNELS &&
-   !data->sku_cap_band_52GHz_enable)
+   for (ch_idx = 0; ch_idx < nchan && ch_idx < nchan_profile; ch_idx++) {
+   if (channel_profile_v4)
+   ch_flags = le32_to_cpup(channel_profile_v4 + ch_idx);
+   else
+   ch_flags = le16_to_cpup(channel_profile_v3 + ch_idx);
+
+   is_5ghz = ch_idx >= IWX_NUM_2GHZ_CHANNELS;
+   if (is_5ghz && !data->sku_cap_band_52GHz_enable)
ch_flags &= ~IWX_NVM_CHANNEL_VALID;
 
if (!(ch_flags & IWX_NVM_CHANNEL_VALID))
@@ -2686,7 +2715,6 @@ iwx_init_channel_map(struct iwx_softc *sc, const uint1
hw_value = nvm_channels[ch_idx];
channel = >ic_channels[hw_value];
 
-   is_5ghz = ch_idx >= IWX_NUM_2GHZ_CHANNELS;
if (!is_5ghz) {
flags = IEEE80211_CHAN_2GHZ;
channel->ic_flags
@@ -2889,6 +2917,134 @@ iwx_ampdu_rx_stop(struct ieee80211com *ic, struct ieee
iwx_add_task(sc, systq, >ba_task);
 }
 
+/* Read the mac address from WFMP registers. */
+int
+iwx_set_mac_addr_from_csr(struct iwx_softc *sc, struct iwx_nvm_data *data)
+{
+   const uint8_t 

Re: 6.7 snaps upgrade went fine - Intel ax200ngw not so much

2020-06-08 Thread Stefan Sperling
On Fri, May 22, 2020 at 01:48:28PM -0400, sven falempin wrote:
>  After a few days ... (free size too small  288 < 1024 /2 )
> 
> Maybe this can help make the driver better.
> 
> printf '%x\n' $((0x350+0xf7)) ; grep -A2 'if_iwx.c:515'  /tmp/iwx.dis
> 447
> /usr/src/sys/dev/pci/if_iwx.c:515
>  447:   41 c7 86 28 2f 05 00movl   $0x0,0x52f28(%r14)
>  44e:   00 00 00 00
> 
> [0]-[current]-[~]
> # cat -n /usr/src/sys/dev/pci/if_iwx.c | grep -C5 -E '  515'
>510  /* free paging*/
>511  for (i = 0; i < dram->paging_cnt; i++)
>512  iwx_dma_contig_free(dram->paging);
>513
>514  free(dram->paging, M_DEVBUF, dram->paging_cnt *
> sizeof(*dram->paging));
>515  dram->paging_cnt = 0;
>516  dram->paging = NULL;
>517  }
>518
>519  int
>520  iwx_get_num_sections(const struct iwx_fw_sects *fws, int start

This should fix free with a wrong size in the error case, and avoids
re-allocating a chunk of DMA memory (sc->ctxt_info_dma) every time the
firmware gets loaded. Instead, this chunk is now allocated once at
attach time. This seems to be the allocation that failed in your case.

diff 66ecf2e2f524653126dce17a447a43b26ee90abb /usr/src
blob - c3ca08c7a726326e37cda8645596a176051b6cf4
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -230,7 +230,7 @@ int iwx_alloc_fw_monitor_block(struct iwx_softc *, uin
 intiwx_alloc_fw_monitor(struct iwx_softc *, uint8_t);
 intiwx_apply_debug_destination(struct iwx_softc *);
 intiwx_ctxt_info_init(struct iwx_softc *, const struct iwx_fw_sects *);
-void   iwx_ctxt_info_free(struct iwx_softc *);
+void   iwx_ctxt_info_free_fw_img(struct iwx_softc *);
 void   iwx_ctxt_info_free_paging(struct iwx_softc *);
 intiwx_init_fw_sec(struct iwx_softc *, const struct iwx_fw_sects *,
struct iwx_context_info_dram *);
@@ -535,52 +535,60 @@ iwx_init_fw_sec(struct iwx_softc *sc, const struct iwx
 struct iwx_context_info_dram *ctxt_dram)
 {
struct iwx_self_init_dram *dram = >init_dram;
-   int i, ret, lmac_cnt, umac_cnt, paging_cnt;
+   int i, ret, fw_cnt = 0;
 
KASSERT(dram->paging == NULL);
 
-   lmac_cnt = iwx_get_num_sections(fws, 0);
+   dram->lmac_cnt = iwx_get_num_sections(fws, 0);
/* add 1 due to separator */
-   umac_cnt = iwx_get_num_sections(fws, lmac_cnt + 1);
+   dram->umac_cnt = iwx_get_num_sections(fws, dram->lmac_cnt + 1);
/* add 2 due to separators */
-   paging_cnt = iwx_get_num_sections(fws, lmac_cnt + umac_cnt + 2);
+   dram->paging_cnt = iwx_get_num_sections(fws,
+   dram->lmac_cnt + dram->umac_cnt + 2);
 
-   dram->fw = mallocarray(umac_cnt + lmac_cnt, sizeof(*dram->fw),
-   M_DEVBUF,  M_ZERO | M_NOWAIT);
-   if (!dram->fw)
+   dram->fw = mallocarray(dram->umac_cnt + dram->lmac_cnt,
+   sizeof(*dram->fw), M_DEVBUF,  M_ZERO | M_NOWAIT);
+   if (!dram->fw) {
+   printf("%s: could not allocate memory for firmware sections\n",
+   DEVNAME(sc));
return ENOMEM;
-   dram->paging = mallocarray(paging_cnt, sizeof(*dram->paging),
+   }
+
+   dram->paging = mallocarray(dram->paging_cnt, sizeof(*dram->paging),
M_DEVBUF, M_ZERO | M_NOWAIT);
-   if (!dram->paging)
+   if (!dram->paging) {
+   printf("%s: could not allocate memory for firmware paging\n",
+   DEVNAME(sc));
return ENOMEM;
+   }
 
/* initialize lmac sections */
-   for (i = 0; i < lmac_cnt; i++) {
+   for (i = 0; i < dram->lmac_cnt; i++) {
ret = iwx_ctxt_info_alloc_dma(sc, >fw_sect[i],
-  >fw[dram->fw_cnt]);
+  >fw[fw_cnt]);
if (ret)
return ret;
ctxt_dram->lmac_img[i] =
-   htole64(dram->fw[dram->fw_cnt].paddr);
+   htole64(dram->fw[fw_cnt].paddr);
DPRINTF(("%s: firmware LMAC section %d at 0x%llx size %lld\n", 
__func__, i,
-   (unsigned long long)dram->fw[dram->fw_cnt].paddr,
-   (unsigned long long)dram->fw[dram->fw_cnt].size));
-   dram->fw_cnt++;
+   (unsigned long long)dram->fw[fw_cnt].paddr,
+   (unsigned long long)dram->fw[fw_cnt].size));
+   fw_cnt++;
}
 
/* initialize umac sections */
-   for (i = 0; i < umac_cnt; i++) {
+   for (i = 0; i < dram->umac_cnt; i++) {
/* access FW with +1 to make up for lmac separator */
ret = iwx_ctxt_info_alloc_dma(sc,
-   >fw_sect[dram->fw_cnt + 1], >fw[dram->fw_cnt]);
+   >fw_sect[fw_cnt + 1], >fw[fw_cnt]);
if (ret)
return ret;

iwx: fix tx queue index in iwx_tx()

2020-05-26 Thread Stefan Sperling
When enabling Tx queues in iwx_enable_data_tx_queues() the driver computes
the Tx queue index as:

int qid = ac + IWX_DQA_AUX_QUEUE + 1;

with:
#define IWX_DQA_AUX_QUEUE   1

In iwx_tx(), we use a different way of computing the Tx queue index,
which is a leftover from iwm(4):

ring = >txq[IWX_DQA_MIN_MGMT_QUEUE + ac];

with:
#define IWX_DQA_MIN_MGMT_QUEUE  5

This kind of bug would usually have severe consequences.
But in this case I got very lucky:

'ac' ranges from 0 to 3, and iwx_tx() always ends up picking Tx queue 5
from the range 5-8 because 'ac' is always passed in as 0 by the caller.

iwx_enable_data_tx_queues() enables Tx queues 2-5 inclusive.

So from the firmware's point of view, Tx queue 5 is enabled and is used
to send frames, and it all just works in spite of the bug.

With this fix, iwx_tx() uses Tx queue 2 and would work correctly for values
of 'ac' other than 0, as intended.

ok?
 
diff 6fed087d6e00a5c30641d2658d09ced7cb1e3090 
1e58df09264b5ea64bbe8f02e26da8b4e738c867
blob - 2f41c5a7c8a943e38bbd69a81d46cf432d329607
blob + 831f4d766af8fbf4e00f3fc0ad1624838869d92e
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -1674,13 +1674,13 @@ iwx_alloc_tx_ring(struct iwx_softc *sc, struct iwx_tx_
 *
 * In DQA mode we use 1 command queue + 4 DQA mgmt/data queues.
 * The command is queue 0 (sc->txq[0]), and 4 mgmt/data frame queues
-* are sc->tqx[IWX_DQA_MIN_MGMT_QUEUE + ac], i.e. sc->txq[5:8],
+* are sc->tqx[ac + IWX_DQA_AUX_QUEUE + 1], i.e. sc->txq[2:5],
 * in order to provide one queue per EDCA category.
 *
 * Tx aggregation will require additional queues (one queue per TID
 * for which aggregation is enabled) but we do not implement this yet.
 */
-   if (qid > IWX_DQA_MAX_MGMT_QUEUE)
+   if (qid > IWX_DQA_MIN_MGMT_QUEUE)
return 0;
 
err = iwx_dma_contig_alloc(sc->sc_dmat, >bc_tbl,
@@ -4246,7 +4246,7 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ie
 * Tx aggregation will require additional queues (one queue per TID
 * for which aggregation is enabled) but we do not implement this yet.
 */
-   ring = >txq[IWX_DQA_MIN_MGMT_QUEUE + ac];
+   ring = >txq[ac + IWX_DQA_AUX_QUEUE + 1];
desc = >desc[ring->cur];
memset(desc, 0, sizeof(*desc));
data = >data[ring->cur];



iwx: add support for the soc command

2020-05-24 Thread Stefan Sperling
Going back over the full list of commands the Linux driver sends to an
ax200 device when it connects to an access point, I have noticed some
that are missing from our driver.

One of those is the SOC_CONFIGURATION command which provides some low-level
details about the hardware device to firmware. This command doesn't seem to
be needed with the ax200 device we currently support. But it does not hurt
and will be needed for other devices this driver intends to support in the
future.

ok?

diff 275365c274c71989968d3bae8c5244a411c26876 
812326fa38786e39e6b9062983fda1ea32c571ac
blob - 585527d032e511ae31b3c06c212f6f99d494494e
blob + 05a96a041a182e2326bc3f745e20150e5053e064
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -409,6 +409,7 @@ voidiwx_fill_sf_command(struct iwx_softc *, struct 
iw
struct ieee80211_node *);
 intiwx_sf_config(struct iwx_softc *, int);
 intiwx_send_bt_init_conf(struct iwx_softc *);
+intiwx_send_soc_conf(struct iwx_softc *);
 intiwx_send_update_mcc_cmd(struct iwx_softc *, const char *);
 intiwx_init_hw(struct iwx_softc *);
 intiwx_init(struct ifnet *);
@@ -437,7 +438,6 @@ int iwx_resume(struct iwx_softc *);
 void   iwx_radiotap_attach(struct iwx_softc *);
 #endif
 
-#ifdef notyet
 uint8_t
 iwx_lookup_cmd_ver(struct iwx_softc *sc, uint8_t grp, uint8_t cmd)
 {
@@ -452,7 +452,6 @@ iwx_lookup_cmd_ver(struct iwx_softc *sc, uint8_t grp, 
 
return IWX_FW_CMD_VER_UNKNOWN;
 }
-#endif
 
 int
 iwx_is_mimo_ht_plcp(uint8_t ht_plcp)
@@ -6255,6 +6254,44 @@ iwx_send_bt_init_conf(struct iwx_softc *sc)
 }
 
 int
+iwx_send_soc_conf(struct iwx_softc *sc)
+{
+   struct iwx_soc_configuration_cmd cmd;
+   int err;
+   uint32_t cmd_id, flags = 0;
+
+   memset(, 0, sizeof(cmd));
+
+   /*
+* In VER_1 of this command, the discrete value is considered
+* an integer; In VER_2, it's a bitmask.  Since we have only 2
+* values in VER_1, this is backwards-compatible with VER_2,
+* as long as we don't set any other flag bits.
+*/
+   if (!sc->sc_integrated) { /* VER_1 */
+   flags = IWX_SOC_CONFIG_CMD_FLAGS_DISCRETE;
+   } else { /* VER_2 */
+   uint8_t scan_cmd_ver;
+   if (sc->sc_ltr_delay != IWX_SOC_FLAGS_LTR_APPLY_DELAY_NONE)
+   flags |= (sc->sc_ltr_delay &
+   IWX_SOC_FLAGS_LTR_APPLY_DELAY_MASK);
+   scan_cmd_ver = iwx_lookup_cmd_ver(sc, IWX_LONG_GROUP,
+   IWX_SCAN_REQ_UMAC);
+   if (scan_cmd_ver >= 2 && sc->sc_low_latency_xtal)
+   flags |= IWX_SOC_CONFIG_CMD_FLAGS_LOW_LATENCY;
+   }
+   cmd.flags = htole32(flags);
+
+   cmd.latency = htole32(sc->sc_xtal_latency);
+
+   cmd_id = iwx_cmd_id(IWX_SOC_CONFIGURATION_CMD, IWX_SYSTEM_GROUP, 0);
+   err = iwx_send_cmd_pdu(sc, cmd_id, 0, sizeof(cmd), );
+   if (err)
+   printf("%s: failed to set soc latency: %d\n", DEVNAME(sc), err);
+   return err;
+}
+
+int
 iwx_send_update_mcc_cmd(struct iwx_softc *sc, const char *alpha2)
 {
struct iwx_mcc_update_cmd mcc_cmd;
@@ -6346,6 +6383,10 @@ iwx_init_hw(struct iwx_softc *sc)
return err;
}
 
+   err = iwx_send_soc_conf(sc);
+   if (err)
+   return err;
+
err = iwx_send_dqa_cmd(sc);
if (err)
return err;
@@ -7207,6 +7248,9 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *d
case IWX_WIDE_ID(IWX_DATA_PATH_GROUP, IWX_DQA_ENABLE_CMD):
break;
 
+   case IWX_WIDE_ID(IWX_SYSTEM_GROUP, IWX_SOC_CONFIGURATION_CMD):
+   break;
+
case IWX_WIDE_ID(IWX_SYSTEM_GROUP, IWX_INIT_EXTENDED_CFG_CMD):
break;
 
@@ -7673,6 +7717,9 @@ iwx_attach(struct device *parent, struct device *self,
sc->sc_fwdmasegsz = IWX_FWDMASEGSZ_8000;
sc->sc_nvm_max_section_size = 32768;
sc->sc_integrated = 1;
+   sc->sc_ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_NONE;
+   sc->sc_low_latency_xtal = 0;
+   sc->sc_xtal_latency = 0;
sc->sc_tx_with_siso_diversity = 0;
break;
default:
blob - 04653f5d23e199b791eef8421b881a6a1854343a
blob + f49a482ac2e6f5196c0c2de5c0426d5c87735070
--- sys/dev/pci/if_iwxreg.h
+++ sys/dev/pci/if_iwxreg.h
@@ -1866,6 +1866,31 @@ struct iwx_alive_resp_v4 {
struct iwx_umac_alive umac_data;
 } __packed; /* ALIVE_RES_API_S_VER_4 */
 
+#define IWX_SOC_CONFIG_CMD_FLAGS_DISCRETE  (1 << 0)
+#define IWX_SOC_CONFIG_CMD_FLAGS_LOW_LATENCY   (1 << 1)
+
+#define IWX_SOC_FLAGS_LTR_APPLY_DELAY_MASK 0xc
+#define IWX_SOC_FLAGS_LTR_APPLY_DELAY_NONE 0
+#define IWX_SOC_FLAGS_LTR_APPLY_DELAY_200  1
+#define IWX_SOC_FLAGS_LTR_APPLY_DELAY_2500 2
+#define IWX_SOC_FLAGS_LTR_APPLY_DELAY_1820 3

iwx: bt config command fix

2020-05-24 Thread Stefan Sperling
The iwx(4) driver intends to disable bluetooth. The command we send to the
firmware says "wifi only", but also enables a bluetooth module. This seems
to work as intended but is ambiguous. Linux also leaves all modules disabled
in wifi-only mode. So do not enable any BT modules in the BT_COEX command.

ok?
 
diff e019717a40a05199a329a1ee64ec1f165be1aa76 
275365c274c71989968d3bae8c5244a411c26876
blob - e3a0a5eb7745c41397922d9fc0e821fb01e242bd
blob + 585527d032e511ae31b3c06c212f6f99d494494e
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -6248,7 +6248,7 @@ iwx_send_bt_init_conf(struct iwx_softc *sc)
struct iwx_bt_coex_cmd bt_cmd;
 
bt_cmd.mode = htole32(IWX_BT_COEX_WIFI);
-   bt_cmd.enabled_modules = htole32(IWX_BT_COEX_HIGH_BAND_RET);
+   bt_cmd.enabled_modules = 0;
 
return iwx_send_cmd_pdu(sc, IWX_BT_CONFIG, 0, sizeof(bt_cmd),
_cmd);



iwx: fix firmware error when leaving AUTH state

2020-05-23 Thread Stefan Sperling
When moving from AUTH state to INIT or SCAN state the iwx(4) driver
performs the following two steps:

1. Remove the formerly chosen access point from the firmware's station table

2. Flush firmware Tx queues

This order of operations was inherited from iwm(4) where it works fine.
But iwx(4) firmware has changed how the flushing step works.

Flushing the Tx path now depends on the station being present in the
firmware's station table. So the driver should flush the Tx path before
removing the station. Otherwise, we get a fatal firmware error when the
driver moves out of AUTH state.

I came across this bug while testing unrelated changes. Perhaps it's been
triggered in the wild, perhaps not. There are worse problems in this driver
which I haven't figured out yet. But this one was easy to figure out and fix.

ok?
 
diff 17409ae76a1a51c4975a1efea612708ad984b8df 
087785340de686b7a85b51f5f1137690e3b88c2f
blob - dd72733d9028d10a3e8dfdce7f1211c72475843f
blob + 7a9e711abbc6814dfbc2bafc8c72ed8244f53d57
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -5681,6 +5681,12 @@ iwx_deauth(struct iwx_softc *sc)
iwx_unprotect_session(sc, in);
 
if (sc->sc_flags & IWX_FLAG_STA_ACTIVE) {
+   err = iwx_flush_tx_path(sc);
+   if (err) {
+   printf("%s: could not flush Tx path (error %d)\n",
+   DEVNAME(sc), err);
+   return err;
+   }
err = iwx_rm_sta_cmd(sc, in);
if (err) {
printf("%s: could not remove STA (error %d)\n",
@@ -5688,13 +5694,6 @@ iwx_deauth(struct iwx_softc *sc)
return err;
}
sc->sc_flags &= ~IWX_FLAG_STA_ACTIVE;
-   }
-
-   err = iwx_flush_tx_path(sc);
-   if (err) {
-   printf("%s: could not flush Tx path (error %d)\n",
-   DEVNAME(sc), err);
-   return err;
}
 
if (sc->sc_flags & IWX_FLAG_BINDING_ACTIVE) {




iwx: fix binding command

2020-05-23 Thread Stefan Sperling
The iwx(4) binding command can fail with 5 Ghz channels.
Some firmware versions don't expect LMAC_5G_INDEX in the binding command.
I have no idea what "CDB" stands for, but this check matches what the
Linux driver does and makes the command work on -48 firmware.

The Linux driver actually checks two capabilities, CAPA_BINDING_CDB_SUPPORT
and CAPA_CDB_SUPPORT. Because BINDING_CDB_SUPPORT is set for all firmware
versions used by iwx(4) we don't need to check it explicitly. Linux has to
check both flags because their code runs with iwm(4) and iwx(4) devices.

ok?
 
diff cad9585f8bd2c9a5a5bcdc5cd1fa273652ba3309 
17409ae76a1a51c4975a1efea612708ad984b8df
blob - b65fa80f56f6dd878b1ac48bbed7ae2d191ffc76
blob + dd72733d9028d10a3e8dfdce7f1211c72475843f
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -3765,7 +3765,8 @@ iwx_binding_cmd(struct iwx_softc *sc, struct iwx_node 
for (i = 1; i < IWX_MAX_MACS_IN_BINDING; i++)
cmd.macs[i] = htole32(IWX_FW_CTXT_INVALID);
 
-   if (IEEE80211_IS_CHAN_2GHZ(phyctxt->channel))
+   if (IEEE80211_IS_CHAN_2GHZ(phyctxt->channel) ||
+   !isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_CDB_SUPPORT))
cmd.lmac_id = htole32(IWX_LMAC_24G_INDEX);
else
cmd.lmac_id = htole32(IWX_LMAC_5G_INDEX);




iwx: beacon filter command v4

2020-05-23 Thread Stefan Sperling
I have started looking into updating iwx(4) to newer firmware.
This newer firmware is not working yet but I already have a few simple
changes which could be reviewed and committed. This is the first one:

Newer iwx(4) firmware versions will require a larger beacon filter command.
The extra fields fields are initialized to zero even on Linux but newer
firmware will require a size change anyway.

This is a fairly straightforward adaptation of changes made in iwlwifi.

ok?

Tested on -46 and -48 firmware.

diff 83ac15007194e8c54722e3f86d4805975b1b47a8 
cad9585f8bd2c9a5a5bcdc5cd1fa273652ba3309
blob - 96350c02d07ea7a54cb27f04257ced45814b15d6
blob + b65fa80f56f6dd878b1ac48bbed7ae2d191ffc76
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -4411,8 +4411,16 @@ int
 iwx_beacon_filter_send_cmd(struct iwx_softc *sc,
 struct iwx_beacon_filter_cmd *cmd)
 {
+   size_t len;
+
+   if (isset(sc->sc_ucode_api, IWX_UCODE_TLV_API_BEACON_FILTER_V4))
+   len = sizeof(struct iwx_beacon_filter_cmd);
+   else
+   len = offsetof(struct iwx_beacon_filter_cmd,
+   bf_threshold_absolute_low);
+
return iwx_send_cmd_pdu(sc, IWX_REPLY_BEACON_FILTERING_CMD,
-   0, sizeof(struct iwx_beacon_filter_cmd), cmd);
+   0, len, cmd);
 }
 
 int
blob - 3ca42ff579a929d5f5d71b80e8afe1943aec60f2
lob + 04653f5d23e199b791eef8421b881a6a1854343a
--- sys/dev/pci/if_iwxreg.h
+++ sys/dev/pci/if_iwxreg.h
@@ -909,6 +909,7 @@ enum msix_ivar_for_cause {
 #define IWX_UCODE_TLV_API_ADAPTIVE_DWELL   32
 #define IWX_UCODE_TLV_API_NEW_RX_STATS 35
 #define IWX_UCODE_TLV_API_ADAPTIVE_DWELL_V242
+#define IWX_UCODE_TLV_API_BEACON_FILTER_V4 47
 #define IWX_UCODE_TLV_API_REDUCED_SCAN_CONFIG   56
 #define IWX_UCODE_TLV_API_SCAN_EXT_CHAN_VER58
 #define IWX_NUM_UCODE_TLV_API  128
@@ -3996,6 +3997,13 @@ struct iwx_uapsd_misbehaving_ap_notif {
  * @ba_escape_timer: Fully receive and parse beacon if no beacons were passed
  *  for a longer period of time then this escape-timeout. Units: Beacons.
  * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled.
+ * @bf_threshold_absolute_low: See below.
+ * @bf_threshold_absolute_high: Send Beacon to driver if Energy value 
calculated
+ *  for this beacon crossed this absolute threshold. For the 'Increase'
+ *  direction the bf_energy_absolute_low[i] is used. For the 'Decrease'
+ *  direction the bf_energy_absolute_high[i] is used. Zero value means
+ *  that this specific threshold is ignored for beacon filtering, and
+ *  beacon will not be forced to be sent to driver due to this setting.
  */
 struct iwx_beacon_filter_cmd {
uint32_t bf_energy_delta;
@@ -4009,7 +4017,9 @@ struct iwx_beacon_filter_cmd {
uint32_t bf_escape_timer;
uint32_t ba_escape_timer;
uint32_t ba_enable_beacon_abort;
-} __packed;
+   uint32_t bf_threshold_absolute_low[2];
+   uint32_t bf_threshold_absolute_high[2];
+} __packed; /* BEACON_FILTER_CONFIG_API_S_VER_4 */
 
 /* Beacon filtering and beacon abort */
 #define IWX_BF_ENERGY_DELTA_DEFAULT 5



Re: iwm(4): re-add CCMP hardware offload support

2020-05-18 Thread Stefan Sperling
On Sun, May 17, 2020 at 04:45:44PM +0200, Matthias Schmidt wrote:
> I have your diff running since yesterday and noticed no regression.
> 
> iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless-AC 8265" rev 0x78, msi
> iwm0: hw rev 0x230, fw ver 34.0.1
> 
> Cheers
> 
>   Matthias

Great, thanks for your help Matthias and others! It's committed now.



Re: iwm(4): re-add CCMP hardware offload support

2020-05-16 Thread Stefan Sperling
On Sat, May 16, 2020 at 05:41:43PM +0200, Stefan Sperling wrote:
> On Fri, May 15, 2020 at 05:02:28PM +0200, Stefan Sperling wrote:
> > This has been attempted before, but had to backed out because in some
> > cases firmware was failing to decrypt a subset of received frames, which
> > resulted in packet loss.
> > 
> > That was before we updated all iwm(4) devices to newer firmware in the
> > previous release cycle. I hope we won't see such problems again now.
> > 
> > Please help out with getting this tested on the many iwm(4) variants:
> > 7260, 7265, 3160, 3165, 3168, 8260, 8265, 9260, and 9560.
> 
> Turns out that my initial testing was insufficient. Sorry about that.
> 
> My previous patch, which was based on code code written against older
> firmware, did not work on some devices. I missed that some newer firmware
> versions we use nowadays have different hardware encryption APIs.
> 
> This new version has been tested by me on 7265, 8260, and 9260.
> It seems to work fine on those devices.
> 
> Could someone test on any of the other devices?
> 
> ok?

Sorry, that diff was generated against the wrong base and contained unrelated
stuff.

This is the intended diff:

blob - 906e910b02a49203bca9a703455a37fcb716b5da
blob + 9b4477cbba3795b6665b1ff0d33082ce205b9c9b
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -372,8 +372,10 @@ intiwm_rxmq_get_signal_strength(struct iwm_softc 
*, s
 void   iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_rx_data *);
 intiwm_get_noise(const struct iwm_statistics_rx_non_phy *);
-void   iwm_rx_frame(struct iwm_softc *, struct mbuf *, int, int, int, uint32_t,
-   struct ieee80211_rxinfo *, struct mbuf_list *);
+intiwm_ccmp_decap(struct iwm_softc *, struct mbuf *,
+   struct ieee80211_node *);
+void   iwm_rx_frame(struct iwm_softc *, struct mbuf *, int, uint32_t, int, int,
+   uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *);
 void   iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_node *, int, int);
 void   iwm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *,
@@ -452,6 +454,14 @@ intiwm_disassoc(struct iwm_softc *);
 intiwm_run(struct iwm_softc *);
 intiwm_run_stop(struct iwm_softc *);
 struct ieee80211_node *iwm_node_alloc(struct ieee80211com *);
+intiwm_set_key_v1(struct ieee80211com *, struct ieee80211_node *,
+   struct ieee80211_key *);
+intiwm_set_key(struct ieee80211com *, struct ieee80211_node *,
+   struct ieee80211_key *);
+void   iwm_delete_key_v1(struct ieee80211com *,
+   struct ieee80211_node *, struct ieee80211_key *);
+void   iwm_delete_key(struct ieee80211com *,
+   struct ieee80211_node *, struct ieee80211_key *);
 void   iwm_calib_timeout(void *);
 void   iwm_setrates(struct iwm_node *, int);
 intiwm_media_change(struct ifnet *);
@@ -3896,16 +3906,65 @@ iwm_get_noise(const struct iwm_statistics_rx_non_phy *
return (nbant == 0) ? -127 : (total / nbant) - 107;
 }
 
+int
+iwm_ccmp_decap(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
+{
+   struct ieee80211com *ic = >sc_ic;
+   struct ieee80211_key *k = >ni_pairwise_key;
+   struct ieee80211_frame *wh;
+   uint64_t pn, *prsc;
+   uint8_t *ivp;
+   uint8_t tid;
+   int hdrlen, hasqos;
+
+   wh = mtod(m, struct ieee80211_frame *);
+   hdrlen = ieee80211_get_hdrlen(wh);
+   ivp = (uint8_t *)wh + hdrlen;
+
+   /* Check that ExtIV bit is be set. */
+   if (!(ivp[3] & IEEE80211_WEP_EXTIV))
+   return 1;
+
+   hasqos = ieee80211_has_qos(wh);
+   tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
+   prsc = >k_rsc[tid];
+
+   /* Extract the 48-bit PN from the CCMP header. */
+   pn = (uint64_t)ivp[0]   |
+(uint64_t)ivp[1] <<  8 |
+(uint64_t)ivp[4] << 16 |
+(uint64_t)ivp[5] << 24 |
+(uint64_t)ivp[6] << 32 |
+(uint64_t)ivp[7] << 40;
+   if (pn <= *prsc) {
+   ic->ic_stats.is_ccmp_replays++;
+   return 1;
+   }
+   /* Last seen packet number is updated in ieee80211_inputm(). */
+
+   /*
+* Some firmware versions strip the MIC, and some don't. It is not
+* clear which of the capability flags could tell us what to expect.
+* For now, keep things simple and just leave the MIC in place if
+* it is present.
+*
+* The IV will be stripped by ieee80211_inputm().
+*/
+   return 0;
+}
+
 void
 iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int chanidx,
- int is_shortpre, int rate_n_flags, uint32_t device_timestamp,
- struct ieee80211_rxinfo *rxi, struct mbuf_list *ml)
+uint32_t rx_pkt_status, int is_sh

Re: iwm(4): re-add CCMP hardware offload support

2020-05-16 Thread Stefan Sperling
On Fri, May 15, 2020 at 05:02:28PM +0200, Stefan Sperling wrote:
> This has been attempted before, but had to backed out because in some
> cases firmware was failing to decrypt a subset of received frames, which
> resulted in packet loss.
> 
> That was before we updated all iwm(4) devices to newer firmware in the
> previous release cycle. I hope we won't see such problems again now.
> 
> Please help out with getting this tested on the many iwm(4) variants:
> 7260, 7265, 3160, 3165, 3168, 8260, 8265, 9260, and 9560.

Turns out that my initial testing was insufficient. Sorry about that.

My previous patch, which was based on code code written against older
firmware, did not work on some devices. I missed that some newer firmware
versions we use nowadays have different hardware encryption APIs.

This new version has been tested by me on 7265, 8260, and 9260.
It seems to work fine on those devices.

Could someone test on any of the other devices?

ok?

diff refs/heads/master refs/heads/iwm-ccmp
blob - 9193ae3c7b5101a86b85b1b3ba48489d75f5150c
blob + 8bc189dc146562f7ab0af2f1690fa02676aecfcd
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -794,9 +794,8 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
struct ieee80211_frame *wh;
struct ieee80211_rx_ba *ba;
uint64_t pn, *prsc;
-   u_int8_t *ivp, *mmie;
+   u_int8_t *ivp;
uint8_t tid;
-   uint16_t kid;
int hdrlen, hasqos;
uintptr_t entry;
 
@@ -805,35 +804,8 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
ivp = mtod(m, u_int8_t *) + hdrlen;
 
/* find key for decryption */
-   if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
-   k = >ni_pairwise_key;
-   } else if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
-   IEEE80211_FC0_TYPE_MGT) {
-   /* retrieve group data key id from IV field */
-   /* check that IV field is present */
-   if (m->m_len < hdrlen + 4)
-   return 1;
-   kid = ivp[3] >> 6;
-   k = >ic_nw_keys[kid];
-   } else {
-   /* retrieve integrity group key id from MMIE */
-   if (m->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) {
-   return 1;
-   }
-   /* it is assumed management frames are contiguous */
-   mmie = (u_int8_t *)wh + m->m_len - IEEE80211_MMIE_LEN;
-   /* check that MMIE is valid */
-   if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) {
-   return 1;
-   }
-   kid = LE_READ_2([2]);
-   if (kid != 4 && kid != 5) {
-   return 1;
-   }
-   k = >ic_nw_keys[kid];
-   }
-
-   if (k->k_cipher != IEEE80211_CIPHER_CCMP)
+   k = ieee80211_get_rxkey(ic, m, ni);
+   if (k == NULL || k->k_cipher != IEEE80211_CIPHER_CCMP)
return 1;
 
/* Sanity checks to ensure this is really a key we installed. */
@@ -853,7 +825,7 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
hasqos = ieee80211_has_qos(wh);
tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
ba = hasqos ? >ni_rx_ba[tid] : NULL;
-   prsc = >k_rsc[0];
+   prsc = >k_rsc[tid];
 
/* Extract the 48-bit PN from the CCMP header. */
pn = (uint64_t)ivp[0]   |
@@ -863,30 +835,12 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
 (uint64_t)ivp[6] << 32 |
 (uint64_t)ivp[7] << 40;
if (pn <= *prsc) {
-   if (hasqos && ba->ba_state == IEEE80211_BA_AGREED) {
-   /*
-* This is an A-MPDU subframe.
-* Such frames may be received out of order due to
-* legitimate retransmissions of failed subframes
-* in previous A-MPDUs. Duplicates will be handled
-* in ieee80211_inputm() as part of A-MPDU reordering.
-*
-* XXX TODO We can probably do better than this! Store
-* re-ordered PN in BA agreement state and check it?
-*/
-   } else {
-   ic->ic_stats.is_ccmp_replays++;
-   return 1;
-   }
+   ic->ic_stats.is_ccmp_replays++;
+   return 1;
}
-   /* Update last seen packet number. */
-   *prsc = pn;
+   /* Last seen packet number is updated in ieee80211_inputm(). */
 
-   /* Clear Protected bit and strip IV. */
-   wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
-   memmove(mtod(m, caddr_t) + IEEE80211_CCMP_HDRLEN, wh, hdrlen);
-   m_adj(m, IEEE80211_CCMP_HDRLEN);
-   /* Strip MIC. */
+ 

Re: iwx: fix phy context command

2020-05-16 Thread Stefan Sperling
On Fri, May 15, 2020 at 02:21:48PM -0400, sven falempin wrote:
> OK Fri May 15 13:37:31 EDT 2020
> OK Fri May 15 13:38:10 EDT 2020
> OK Fri May 15 13:38:49 EDT 2020
> OK Fri May 15 13:39:28 EDT 2020
> OK Fri May 15 13:40:07 EDT 2020
> FAILED Fri May 15 13:40:50 EDT 2020
> OK Fri May 15 13:41:29 EDT 2020
> FAILED Fri May 15 13:42:12 EDT 2020

I don't expect this phy context patch to have any impact on the bug you
are seeing. These are unrelated bugs. This new driver is going to have
several bugs which still need to be found and fixed, for quite a while.

It's great that you have a reproducible test case for your particular bug.
This should help with finding a sweet spot for adding a DELAY to work around
the bug you are seeing.



Re: 6.7 snaps upgrade went fine - Intel ax200ngw not so much

2020-05-15 Thread Stefan Sperling
On Fri, May 15, 2020 at 11:11:44AM -0400, sven falempin wrote:
> Index: if_iwx.c
> ===
> RCS file: /cvs/src/sys/dev/pci/if_iwx.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 if_iwx.c
> --- if_iwx.c29 Apr 2020 13:13:30 -  1.11
> +++ if_iwx.c15 May 2020 15:08:45 -
> @@ -3222,6 +3222,9 @@ iwx_run_init_mvm_ucode(struct iwx_softc
>  * Send init config command to mark that we are sending NVM
>  * access commands
>  */
> +   printf("%s: DELAYING\n", DEVNAME(sc));
> +   DELAY(5000);
> +
> err = iwx_send_cmd_pdu(sc, IWX_WIDE_ID(IWX_SYSTEM_GROUP,
> IWX_INIT_EXTENDED_CFG_CMD), 0, sizeof(init_cfg), _cfg);
> if (err)
> 
> Gave
> 
> iwx0: DELAYING
> iwx0: dumping device error log
> iwx0: Start Error Log Dump:
> iwx0: Status: 0x1, count: 6
> iwx0: 0x0071 | NMI_INTERRUPT_UMAC_FATAL
> iwx0: 0020A2F0 | trm_hw_status0
> iwx0:  | trm_hw_status1
> iwx0: 004FC308 | branchlink2
> iwx0: 00016E5A | interruptlink1
> iwx0: 00016E5A | interruptlink2
> iwx0: 004F9F62 | data1
> iwx0: 1000 | data2
> iwx0: F008 | data3
> iwx0:  | beacon time
> iwx0: 000115E1 | tsf low
> iwx0:  | tsf hi
> iwx0:  | time gp1
> iwx0: 000115E2 | time gp2
> iwx0: 0001 | uCode revision type
> iwx0: 002E | uCode version major
> iwx0: 177B3E46 | uCode version minor
> iwx0: 0340 | hw version
> iwx0: 18889000 | board version
> iwx0: 800AFD0C | hcmd
> iwx0: 2002 | isr0
> iwx0:  | isr1
> iwx0: 18F2 | isr2
> iwx0: 00CC | isr3
> iwx0:  | isr4
> iwx0:  | last cmd Id
> iwx0: 004F9F62 | wait_event
> iwx0:  | l2p_control
> iwx0: 0020 | l2p_duration
> iwx0:  | l2p_mhvalid
> iwx0:  | l2p_addr_match
> iwx0: 0009 | lmpm_pmg_sel
> iwx0: 19071335 | timestamp
> iwx0: 0828 | flow_handler
> iwx0: Start UMAC Error Log Dump:
> iwx0: Status: 0x1, count: 7
> iwx0: 0x201010A3 | ADVANCED_SYSASSERT
> iwx0: 0x | umac branchlink1
> iwx0: 0xC008B1C0 | umac branchlink2
> iwx0: 0xC0084E04 | umac interruptlink1
> iwx0: 0x | umac interruptlink2
> iwx0: 0x0002 | umac data1
> iwx0: 0x0001 | umac data2
> iwx0: 0xDEADBEEF | umac data3
> iwx0: 0x002E | umac major
> iwx0: 0x177B3E46 | umac minor
> iwx0: 0x000115D2 | frame pointer
> iwx0: 0xC0886C6C | stack pointer
> iwx0: 0x00050C00 | last host cmd
> iwx0: 0x | isr status reg
> driver status:
>   tx ring  0: qid=0  cur=6   queued=0
>   tx ring  1: qid=1  cur=0   queued=0
>   tx ring  2: qid=2  cur=0   queued=0
>   tx ring  3: qid=3  cur=0   queued=0
>   tx ring  4: qid=4  cur=0   queued=0
>   tx ring  5: qid=5  cur=0   queued=0
>   tx ring  6: qid=6  cur=0   queued=0
>   tx ring  7: qid=7  cur=0   queued=0
>   tx ring  8: qid=8  cur=0   queued=0
>   tx ring  9: qid=9  cur=0   queued=0
>   tx ring 10: qid=10 cur=0   queued=0
>   tx ring 11: qid=11 cur=0   queued=0
>   tx ring 12: qid=12 cur=0   queued=0
>   tx ring 13: qid=13 cur=0   queued=0
>   tx ring 14: qid=14 cur=0   queued=0
>   tx ring 15: qid=15 cur=0   queued=0
>   tx ring 16: qid=16 cur=0   queued=0
>   tx ring 17: qid=17 cur=0   queued=0
>   tx ring 18: qid=18 cur=0   queued=0
>   tx ring 19: qid=19 cur=0   queued=0
>   tx ring 20: qid=20 cur=0   queued=0
>   tx ring 21: qid=21 cur=0   queued=0
>   tx ring 22: qid=22 cur=0   queued=0
>   tx ring 23: qid=23 cur=0   queued=0
>   tx ring 24: qid=24 cur=0   queued=0
>   tx ring 25: qid=25 cur=0   queued=0
>   tx ring 26: qid=26 cur=0   queued=0
>   tx ring 27: qid=27 cur=0   queued=0
>   tx ring 28: qid=28 cur=0   queued=0
>   tx ring 29: qid=29 cur=0   queued=0
>   tx ring 30: qid=30 cur=0   queued=0
>   rx ring: cur=265
>   802.11 state INIT
> iwx0: fatal firmware error
> 
> I think the delay must be somewhere after.

Ouch. Yes, looks like that's a bad spot.

Though it is an interesting observation that waiting there for a long time
causes another problem.

> I know it s a bit silly , but would a test with
> 
> #ifdef IWX_DEBUG
> #define DPRINTF(x)  do { if (iwx_debug > 0) printf x; } while (0)
> #define DPRINTFN(n, x)  do { if (iwx_debug >= (n)) printf x; } while (0)
> int iwx_debug = 1;
> #else
> #define DPRINTF(x)  do { DELAY(10); } while (1)
> #define DPRINTFN(n, x)  do { DELAY(10); } while (1)
> #endif
> 
> makes sense ?

Not really. That just puts DELAY(10) in some arbitrary places.
What we need to know is where exactly the driver is going too fast.



iwm(4): re-add CCMP hardware offload support

2020-05-15 Thread Stefan Sperling
This has been attempted before, but had to backed out because in some
cases firmware was failing to decrypt a subset of received frames, which
resulted in packet loss.

That was before we updated all iwm(4) devices to newer firmware in the
previous release cycle. I hope we won't see such problems again now.

Please help out with getting this tested on the many iwm(4) variants:
7260, 7265, 3160, 3165, 3168, 8260, 8265, 9260, and 9560.

In particular, if you see an impact on system responsiveness while iwm(4)
is pushing a lot of traffic, please check if this patch makes a difference.

Note that you need an up-to-date tree. This patch depends on the CCMP replay
fix which I have just committed.
 
 M  sys/dev/pci/if_iwm.c

diff 726ed64885e754593692b3521ec292fecb37a563 
6f4a43795c837cf1a31eb8cd5cbf23a908d22c4a
blob - 906e910b02a49203bca9a703455a37fcb716b5da
blob + dde808778b74b07f586bc5f982668459e15fd8cb
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -372,8 +372,10 @@ intiwm_rxmq_get_signal_strength(struct iwm_softc 
*, s
 void   iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_rx_data *);
 intiwm_get_noise(const struct iwm_statistics_rx_non_phy *);
-void   iwm_rx_frame(struct iwm_softc *, struct mbuf *, int, int, int, uint32_t,
-   struct ieee80211_rxinfo *, struct mbuf_list *);
+intiwm_ccmp_decap(struct iwm_softc *, struct mbuf *,
+   struct ieee80211_node *);
+void   iwm_rx_frame(struct iwm_softc *, struct mbuf *, int, uint32_t, int, int,
+   uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *);
 void   iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_node *, int, int);
 void   iwm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *,
@@ -452,6 +454,10 @@ intiwm_disassoc(struct iwm_softc *);
 intiwm_run(struct iwm_softc *);
 intiwm_run_stop(struct iwm_softc *);
 struct ieee80211_node *iwm_node_alloc(struct ieee80211com *);
+intiwm_set_key(struct ieee80211com *, struct ieee80211_node *,
+   struct ieee80211_key *);
+void   iwm_delete_key(struct ieee80211com *,
+   struct ieee80211_node *, struct ieee80211_key *);
 void   iwm_calib_timeout(void *);
 void   iwm_setrates(struct iwm_node *, int);
 intiwm_media_change(struct ifnet *);
@@ -3896,16 +3902,60 @@ iwm_get_noise(const struct iwm_statistics_rx_non_phy *
return (nbant == 0) ? -127 : (total / nbant) - 107;
 }
 
+int
+iwm_ccmp_decap(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
+{
+   struct ieee80211com *ic = >sc_ic;
+   struct ieee80211_key *k = >ni_pairwise_key;
+   struct ieee80211_frame *wh;
+   uint64_t pn, *prsc;
+   uint8_t *ivp;
+   uint8_t tid;
+   int hdrlen, hasqos;
+
+   wh = mtod(m, struct ieee80211_frame *);
+   hdrlen = ieee80211_get_hdrlen(wh);
+   ivp = (uint8_t *)wh + hdrlen;
+
+   /* Check that ExtIV bit is be set. */
+   if (!(ivp[3] & IEEE80211_WEP_EXTIV)) {
+   DPRINTF(("CCMP decap ExtIV not set\n"));
+   return 1;
+   }
+   hasqos = ieee80211_has_qos(wh);
+   tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
+   prsc = >k_rsc[tid];
+
+   /* Extract the 48-bit PN from the CCMP header. */
+   pn = (uint64_t)ivp[0]   |
+(uint64_t)ivp[1] <<  8 |
+(uint64_t)ivp[4] << 16 |
+(uint64_t)ivp[5] << 24 |
+(uint64_t)ivp[6] << 32 |
+(uint64_t)ivp[7] << 40;
+   if (pn <= *prsc) {
+   ic->ic_stats.is_ccmp_replays++;
+   return 1;
+   }
+   /* Last seen packet number is updated in ieee80211_inputm(). */
+
+   /* Strip MIC. IV will be stripped by ieee80211_inputm(). */
+   m_adj(m, -IEEE80211_CCMP_MICLEN);
+   return 0;
+}
+
 void
 iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int chanidx,
- int is_shortpre, int rate_n_flags, uint32_t device_timestamp,
- struct ieee80211_rxinfo *rxi, struct mbuf_list *ml)
+uint32_t rx_pkt_status, int is_shortpre, int rate_n_flags,
+uint32_t device_timestamp, struct ieee80211_rxinfo *rxi,
+struct mbuf_list *ml)
 {
struct ieee80211com *ic = >sc_ic;
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct ieee80211_channel *bss_chan;
uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
+   struct ifnet *ifp = IC2IFP(ic);
 
if (chanidx < 0 || chanidx >= nitems(ic->ic_channels))  
chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
@@ -3922,6 +3972,38 @@ iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int
}
ni->ni_chan = >ic_channels[chanidx];
 
+   /* Handle hardware decryption. */
+   if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL)
+   && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
+   !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+   (ni->ni_flags & 

iwx: fix phy context command

2020-05-15 Thread Stefan Sperling
iwx(4) firmware understands two different variants of the "PHY_CONTEXT"
command. Both variants are documented with the same command API version
number, but they use different sizes for an embedded struct that contains
information about channels.

Which variant to use depends on whether the firmware advertises support for
the "ULTRA_HB_CHANNELS" feature (we don't use this feature; it's about 6 GHz
channels; but if the command we send has the wrong size the firmware will
reject the command).

The code I wrote to handle both of these cases has a bug in case this
feature is *not* supported. Our current iwx(4) firmware supports the
feature, so there is no actual problem for now.

I have considered removing the command variant which is currently not needed.
However, additional devices may be added to this driver at some point.
And some of those are kind of hybrids between the 9k and the ax200 device
generations. I do not know which variant those devices will need. So this
diff fixes the bug in the non-UHB code path, in case it will be needed.
We can always remove this later.

ok?

 M  sys/dev/pci/if_iwx.c
 M  sys/dev/pci/if_iwxreg.h

diff f896dbcaba91a37b23dc6cbeb42839fba3e329be 
24bd56723f1f029278b7c9cc71d56349db3c5950
blob - 64c3641a2d0d07a9d899c0b7ccdbe46d46e17b96
blob + d01db87880cc583922d1610de8319e491e7f148c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -343,10 +343,8 @@ void   iwx_rx_tx_cmd(struct iwx_softc *, struct 
iwx_rx_p
 void   iwx_rx_bmiss(struct iwx_softc *, struct iwx_rx_packet *,
struct iwx_rx_data *);
 intiwx_binding_cmd(struct iwx_softc *, struct iwx_node *, uint32_t);
-void   iwx_phy_ctxt_cmd_hdr(struct iwx_softc *, struct iwx_phy_ctxt *,
-   struct iwx_phy_context_cmd *, uint32_t, uint32_t);
-void   iwx_phy_ctxt_cmd_data(struct iwx_softc *, struct iwx_phy_context_cmd *,
-   struct ieee80211_channel *, uint8_t, uint8_t);
+intiwx_phy_ctxt_cmd_uhb(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
+   uint8_t, uint32_t, uint32_t);
 intiwx_phy_ctxt_cmd(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
uint8_t, uint32_t, uint32_t);
 intiwx_send_cmd(struct iwx_softc *, struct iwx_host_cmd *);
@@ -3773,52 +3771,38 @@ iwx_binding_cmd(struct iwx_softc *sc, struct iwx_node 
return err;
 }
 
-void
-iwx_phy_ctxt_cmd_hdr(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt,
-struct iwx_phy_context_cmd *cmd, uint32_t action, uint32_t apply_time)
+int
+iwx_phy_ctxt_cmd_uhb(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt,
+uint8_t chains_static, uint8_t chains_dynamic, uint32_t action,
+uint32_t apply_time)
 {
-   memset(cmd, 0, sizeof(struct iwx_phy_context_cmd));
+   struct ieee80211com *ic = >sc_ic;
+   struct iwx_phy_context_cmd_uhb cmd;
+   uint8_t active_cnt, idle_cnt;
+   struct ieee80211_channel *chan = ctxt->channel;
 
-   cmd->id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(ctxt->id,
+   memset(, 0, sizeof(cmd));
+   cmd.id_and_color = htole32(IWX_FW_CMD_ID_AND_COLOR(ctxt->id,
ctxt->color));
-   cmd->action = htole32(action);
-   cmd->apply_time = htole32(apply_time);
-}
+   cmd.action = htole32(action);
+   cmd.apply_time = htole32(apply_time);
 
-void
-iwx_phy_ctxt_cmd_data(struct iwx_softc *sc, struct iwx_phy_context_cmd *cmd,
-struct ieee80211_channel *chan, uint8_t chains_static,
-uint8_t chains_dynamic)
-{
-   struct ieee80211com *ic = >sc_ic;
-   uint8_t active_cnt, idle_cnt;
+   cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
+   IWX_PHY_BAND_24 : IWX_PHY_BAND_5;
+   cmd.ci.channel = htole32(ieee80211_chan2ieee(ic, chan));
+   cmd.ci.width = IWX_PHY_VHT_CHANNEL_MODE20;
+   cmd.ci.ctrl_pos = IWX_PHY_VHT_CTRL_POS_1_BELOW;
 
-   if (isset(sc->sc_enabled_capa, IWX_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS)) {
-   cmd->ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
-   IWX_PHY_BAND_24 : IWX_PHY_BAND_5;
-   cmd->ci.channel = htole32(ieee80211_chan2ieee(ic, chan));
-   cmd->ci.width = IWX_PHY_VHT_CHANNEL_MODE20;
-   cmd->ci.ctrl_pos = IWX_PHY_VHT_CTRL_POS_1_BELOW;
-   } else {
-   struct iwx_fw_channel_info_v1 *ci_v1;
-   ci_v1 = (struct iwx_fw_channel_info_v1 *)>ci;
-   ci_v1->band = IEEE80211_IS_CHAN_2GHZ(chan) ?
-   IWX_PHY_BAND_24 : IWX_PHY_BAND_5;
-   ci_v1->channel = ieee80211_chan2ieee(ic, chan);
-   ci_v1->width = IWX_PHY_VHT_CHANNEL_MODE20;
-   ci_v1->ctrl_pos = IWX_PHY_VHT_CTRL_POS_1_BELOW;
-   }
-   /* Set rx the chains */
idle_cnt = chains_static;
active_cnt = chains_dynamic;
-
-   cmd->rxchain_info = htole32(iwx_fw_valid_rx_ant(sc) <<
+   cmd.rxchain_info = htole32(iwx_fw_valid_rx_ant(sc) <<
IWX_PHY_RX_CHAIN_VALID_POS);
-   cmd->rxchain_info |= htole32(idle_cnt << 

Re: iwn/athn/wpi: fix CCMP replay check with HW crypto

2020-05-15 Thread Stefan Sperling
On Fri, May 08, 2020 at 10:53:30AM +0200, Stefan Sperling wrote:
> So the diff below contains just the reordering fix for drivers using
> hardware acceleration for WPA.

Is there anybody who wants to OK this?

To recap:

Currently, CCMP replay checking is skipped for aggregated 11n frames on
drivers which use CCMP hardware acceleration: athn(4) and iwn(4).

This diff makes reply checking in that case possible without false positives,
by updating the last-seen packet number after the aggregated subframes, which
may be received out of order, have been put back into their intended order by
ieee80211_input_ba(). The old code only works in the single-frame case for
11a/b/g modes where no such legitimate re-transmissions can occur.

> diff refs/heads/master refs/heads/pn
> blob - 9193ae3c7b5101a86b85b1b3ba48489d75f5150c
> blob + 8bc189dc146562f7ab0af2f1690fa02676aecfcd
> --- sys/dev/ic/ar5008.c
> +++ sys/dev/ic/ar5008.c
> @@ -794,9 +794,8 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
>   struct ieee80211_frame *wh;
>   struct ieee80211_rx_ba *ba;
>   uint64_t pn, *prsc;
> - u_int8_t *ivp, *mmie;
> + u_int8_t *ivp;
>   uint8_t tid;
> - uint16_t kid;
>   int hdrlen, hasqos;
>   uintptr_t entry;
>  
> @@ -805,35 +804,8 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
>   ivp = mtod(m, u_int8_t *) + hdrlen;
>  
>   /* find key for decryption */
> - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
> - k = >ni_pairwise_key;
> - } else if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
> - IEEE80211_FC0_TYPE_MGT) {
> - /* retrieve group data key id from IV field */
> - /* check that IV field is present */
> - if (m->m_len < hdrlen + 4)
> - return 1;
> - kid = ivp[3] >> 6;
> - k = >ic_nw_keys[kid];
> - } else {
> - /* retrieve integrity group key id from MMIE */
> - if (m->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) {
> - return 1;
> - }
> - /* it is assumed management frames are contiguous */
> - mmie = (u_int8_t *)wh + m->m_len - IEEE80211_MMIE_LEN;
> - /* check that MMIE is valid */
> - if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) {
> - return 1;
> - }
> - kid = LE_READ_2([2]);
> - if (kid != 4 && kid != 5) {
> - return 1;
> - }
> - k = >ic_nw_keys[kid];
> - }
> -
> - if (k->k_cipher != IEEE80211_CIPHER_CCMP)
> + k = ieee80211_get_rxkey(ic, m, ni);
> + if (k == NULL || k->k_cipher != IEEE80211_CIPHER_CCMP)
>   return 1;
>  
>   /* Sanity checks to ensure this is really a key we installed. */
> @@ -853,7 +825,7 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
>   hasqos = ieee80211_has_qos(wh);
>   tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
>   ba = hasqos ? >ni_rx_ba[tid] : NULL;
> - prsc = >k_rsc[0];
> + prsc = >k_rsc[tid];
>  
>   /* Extract the 48-bit PN from the CCMP header. */
>   pn = (uint64_t)ivp[0]   |
> @@ -863,30 +835,12 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
>(uint64_t)ivp[6] << 32 |
>(uint64_t)ivp[7] << 40;
>   if (pn <= *prsc) {
> - if (hasqos && ba->ba_state == IEEE80211_BA_AGREED) {
> - /*
> -  * This is an A-MPDU subframe.
> -  * Such frames may be received out of order due to
> -  * legitimate retransmissions of failed subframes
> -  * in previous A-MPDUs. Duplicates will be handled
> -  * in ieee80211_inputm() as part of A-MPDU reordering.
> -  *
> -  * XXX TODO We can probably do better than this! Store
> -  * re-ordered PN in BA agreement state and check it?
> -  */
> - } else {
> - ic->ic_stats.is_ccmp_replays++;
> - return 1;
> - }
> + ic->ic_stats.is_ccmp_replays++;
> + return 1;
>   }
> - /* Update last seen packet number. */
> - *prsc = pn;
> + /* Last seen packet number is updated in ieee80211_inputm(). */
>  
> - /* Clear Protected bit and strip IV. */
> - wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
> - memmove(mtod(m, caddr_t) + IEEE80211_CCMP_HDRLEN, wh, hdrlen);
> - m

net80211: fix capinfo in assoc request

2020-05-14 Thread Stefan Sperling
The capablities info field in an association request contains an ESS bit
which is set if the sender is an access point (there are other cases but
they don't matter for us; see 802.11-2012 8.4.1.4 if you are interested).

This bit is set when OpenBSD clients send an association request to an AP.
This seems wrong. The ESS bit should be zero when sent by clients.

Noticed while looking over packet captures for an unrelated issue.

ok?

diff 4a0fa473f5ea308b63ffd39645f73b2195291973 /usr/src
blob - 7952471d5bb369c9bb844966425fffc892a71038
file + sys/net80211/ieee80211_output.c
--- sys/net80211/ieee80211_output.c
+++ sys/net80211/ieee80211_output.c
@@ -1384,7 +1384,7 @@ ieee80211_get_assoc_req(struct ieee80211com *ic, struc
return NULL;
 
frm = mtod(m, u_int8_t *);
-   capinfo = IEEE80211_CAPINFO_ESS;
+   capinfo = 0;
if (ic->ic_flags & IEEE80211_F_WEPON)
capinfo |= IEEE80211_CAPINFO_PRIVACY;
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&



Re: 6.7 snaps upgrade went fine - Intel ax200ngw not so much

2020-05-14 Thread Stefan Sperling
On Wed, May 13, 2020 at 07:55:02PM -0400, sven falempin wrote:
> 'good news'
> 
> I build a custom kernel with the DEBUG flag for the driver

> I 'works' ,

This means that the driver is doing something too fast on your hardware,
and some miscommunication happens with the card as a result.

One way to work around this is to add DELAY calls. It is not the ideal
solution but would be a good first step to get the card working.

Can you disable debugging again and try the patch below instead?
If the problem re-appears, try to increase the amount of delay (up to 5000
seems reasonable). If increasing the DELAY value does not help, try to move
the DELAY call further down until it works.

The DELAY may even need to be moved into the while loop inside iwx_nvm_init().
But please try using the DELAY outside of a loop first.

Finding the right spot might take some time. Welcome to driver development :)

If you cannot find a spot for the DELAY that makes this work, then we will
have to wait for someone else who is seeing the same problem and tries harder.

diff 4a0fa473f5ea308b63ffd39645f73b2195291973 /usr/src
blob - 64c3641a2d0d07a9d899c0b7ccdbe46d46e17b96
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -3222,6 +3222,7 @@ iwx_run_init_mvm_ucode(struct iwx_softc *sc, int readn
 * Send init config command to mark that we are sending NVM
 * access commands
 */
+   DELAY(1000);
err = iwx_send_cmd_pdu(sc, IWX_WIDE_ID(IWX_SYSTEM_GROUP,
IWX_INIT_EXTENDED_CFG_CMD), 0, sizeof(init_cfg), _cfg);
if (err)



Re: 6.7 snaps upgrade went fine - Intel ax200ngw not so much

2020-05-11 Thread Stefan Sperling
On Sun, May 10, 2020 at 04:17:46PM -0400, sven falempin wrote:
> On Sun, May 10, 2020 at 4:51 AM Stefan Sperling  wrote:
> 
> > On Sat, May 09, 2020 at 04:23:08PM -0400, sven falempin wrote:
> > > "no config, interface is down", Did not do anything special,
> > > upgrade => Plug card => boot => crash
> >
> > > I tested with the intel firmware it does the same.
> >
> > I'm sorry, but there is really not enough information in your messages
> > that would allow me to do anything other than just trying to somehow
> > reproduce this problem by chance.
> >
> 
> I understand.
> 
> there is nothing I did that is outside what I tell,
> the problem is constant,
> unavoidable
> and requires 0 config
> nor any command to enter.

Yes, I believe what you are saying.

The problem is that this error is not happening to me, and to diagnose it
I need to see this same error happen on a machine I have in front of me.
Once we reach that point, I can silently work on it until I find a fix.
But before then, I cannot do anything. In order to try to replicate your
setup as closely as possible, I need to know what your setup looks like.

So, for example, knowing what hardware you have in front of you would be
a good first step. But your report lacks a dmesg.

Please follow the guidance given on https://www.openbsd.org/report.html
Any bit of information that is requested there, if you can tell us about it,
then please include it in your report. It will save us time in the long term.



Re: 6.7 snaps upgrade went fine - Intel ax200ngw not so much

2020-05-10 Thread Stefan Sperling
On Sat, May 09, 2020 at 04:23:08PM -0400, sven falempin wrote:
> "no config, interface is down", Did not do anything special,
> upgrade => Plug card => boot => crash

> I tested with the intel firmware it does the same.

I'm sorry, but there is really not enough information in your messages
that would allow me to do anything other than just trying to somehow
reproduce this problem by chance.



Re: 6.7 snaps upgrade went fine - Intel ax200ngw not so much

2020-05-09 Thread Stefan Sperling
On Fri, May 08, 2020 at 11:51:50AM -0400, sven falempin wrote:
> I upgraded to 6.7 - beta a tftp server i use
> 
> Not much to report as the device is basic but i wanted to test some wifi on
> it.
> 
> iwx0 at pci8 dev 0 function 0 "Intel Wi-Fi 6 AX200" rev 0x1a, msix
> 
> The firmware crashes at start,

It looks like a failure of the NVM_ACCESS command:

> iwx0: 0x00050088 | last host cmd

#define IWX_NVM_ACCESS_CMD  0x88

> no config down:

What does "no config down" mean?

If you could provide an exact sequence of steps anyone without prior knowledge
could perform in order to repeat this problem, then I would take a look.
Please don't assume that I already knew. I have never seen this error.



Re: iwn/athn/wpi: fix CCMP replay check with HW crypto

2020-05-08 Thread Stefan Sperling
On Fri, May 01, 2020 at 06:05:47PM +0200, Stefan Sperling wrote:
> The following diff moves the Packet Number check out of affected drivers
> into ieee80211_inputm() so the check can be performed after frames have
> been re-ordered.

Here is a new version of this diff.

I realized I made a mistake in my reasoning here:

>  - Fix a wrong assumption made about reply counters and TIDs. We only
>announce support for one replay counter per key, and never initialize
>counters other than k_rsc[0]. Some code was accessing k_rsc[tid] based
>on the TID value in the frame header. Based on the fact that counters
>at offsets other than zero are not initialized, and on my understanding
>of the 802.11-2012 spec, this is wrong. Multiple counters are only used
>if support for them is announced in an RSN capability field, and we do
>not announce this.

Here's my error: In fact we do announce whatever the peer has announced,
by echoing back the relevant setting in the peer's RSN capability field.

My misunderstanding came about due to a limited sample size of APs.
An AP which advertises support for multiple counters sees a matching
response from us and works fine with our current code.

>We also use TIDs only to correlate frames with an
>existing block ack agreement. The multi-replay counter case assumes
>instead that TIDs are used for purposes of real OoS, which we do not
>implement. Real QoS could lead to out-of-order transmissions based
>on the priority assigned to the data contained in a frame, so it makes
>sense to maintain one replay counter per priority with real QoS.

What's really happening in our implementation is that we maintain an
array of up to 16 replay counters per key. All counters start at zero
which is the lowest possible value since they are unsigned. No matter how
many counters a peer advertises, we support any configuration the peer wants,
up to the max number of counters allowed by the spec (16, not 8 as I wrote
in comments in my earlier diff). The peer then sends frames with particular
TIDs using the appropriate replay counter value, and we use our corresponding
per-TID replay counter if support for it was advertised by the peer.
For the rest we use the default replay counter (TID 0).

So the diff below contains just the reordering fix for drivers using
hardware acceleration for WPA.

diff refs/heads/master refs/heads/pn
blob - 9193ae3c7b5101a86b85b1b3ba48489d75f5150c
blob + 8bc189dc146562f7ab0af2f1690fa02676aecfcd
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -794,9 +794,8 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
struct ieee80211_frame *wh;
struct ieee80211_rx_ba *ba;
uint64_t pn, *prsc;
-   u_int8_t *ivp, *mmie;
+   u_int8_t *ivp;
uint8_t tid;
-   uint16_t kid;
int hdrlen, hasqos;
uintptr_t entry;
 
@@ -805,35 +804,8 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
ivp = mtod(m, u_int8_t *) + hdrlen;
 
/* find key for decryption */
-   if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
-   k = >ni_pairwise_key;
-   } else if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
-   IEEE80211_FC0_TYPE_MGT) {
-   /* retrieve group data key id from IV field */
-   /* check that IV field is present */
-   if (m->m_len < hdrlen + 4)
-   return 1;
-   kid = ivp[3] >> 6;
-   k = >ic_nw_keys[kid];
-   } else {
-   /* retrieve integrity group key id from MMIE */
-   if (m->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) {
-   return 1;
-   }
-   /* it is assumed management frames are contiguous */
-   mmie = (u_int8_t *)wh + m->m_len - IEEE80211_MMIE_LEN;
-   /* check that MMIE is valid */
-   if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) {
-   return 1;
-   }
-   kid = LE_READ_2([2]);
-   if (kid != 4 && kid != 5) {
-   return 1;
-   }
-   k = >ic_nw_keys[kid];
-   }
-
-   if (k->k_cipher != IEEE80211_CIPHER_CCMP)
+   k = ieee80211_get_rxkey(ic, m, ni);
+   if (k == NULL || k->k_cipher != IEEE80211_CIPHER_CCMP)
return 1;
 
/* Sanity checks to ensure this is really a key we installed. */
@@ -853,7 +825,7 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
hasqos = ieee80211_has_qos(wh);
tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
ba = hasqos ? >ni_rx_ba[tid] : NULL;
-   prsc = >k_rsc[0];
+   prsc = >k_rsc[tid];
 
/* Extract the 48-bit PN from the CCMP header. */
pn = (uint64_t)ivp[0]   |
@@ -863,30 +835,12 @@ ar5008_ccm

iwn: fix connection hangs with some APs

2020-05-04 Thread Stefan Sperling
For some reason, changes I made to iwn(4) in the commit quoted below
have caused connections to get stuck on some APs during Tx bursts.

This does not occur with every type of AP. It was observed on an Apple
Airport Extreme 6th gen, and on a b-box 3V+ (Sagemcom Mac address).

The patch below reverts all changes related to interaction between driver
and firmware from the relevant commit and works around the problem in all
known cases. It is unclear why it helps, but at least this patch should
avoid the problem from affecting 6.7-release.

ok?

The relevant commit was:

---
Module name:src
Changes by: s...@cvs.openbsd.org2020/04/27 02:02:24

Modified files:
sys/dev/pci: if_iwn.c if_iwnvar.h 

Log message:
Fix processing of compressed block ack notifications sent by iwn(4) firmware.

Fix wrong assumptions about what the data in these notifications is supposed
to represent, and actually piece information about individual subframes of
aggregated frames (A-MPDUs) back together when reporting to MiRA, rather than
reporting unrelated subframes to MiRA individually.

Testing by cwen@, Josh Grosse, f.holop, benno@
ok jmatthew@
---


diff 523aa541f5e65a29bda64c13043addf764654fa1 /usr/src
blob - 620cbd4c138516398a4683d83c1b6bf8aac57c82
file + sys/dev/pci/if_iwn.c
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -158,6 +158,8 @@ voidiwn_rx_phy(struct iwn_softc *, struct 
iwn_rx_des
 void   iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *, struct mbuf_list *);
 void   iwn_mira_choose(struct iwn_softc *, struct ieee80211_node *);
+void   iwn_ampdu_rate_control(struct iwn_softc *, struct 
ieee80211_node *,
+   struct iwn_tx_ring *, int, uint16_t, uint16_t);
 void   iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
 void   iwn5000_rx_calib_results(struct iwn_softc *,
@@ -2248,83 +2250,16 @@ iwn_mira_choose(struct iwn_softc *sc, struct ieee80211
iwn_set_link_quality(sc, ni);
 }
 
-/*
- * Process an incoming Compressed BlockAck.
- * Note that these block ack notifications are generated by firmware and do
- * not necessarily correspond to contents of block ack frames seen on the air.
- */
 void
-iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
-struct iwn_rx_data *data)
+iwn_ampdu_rate_control(struct iwn_softc *sc, struct ieee80211_node *ni,
+struct iwn_tx_ring *txq, int tid, uint16_t seq, uint16_t ssn)
 {
-   struct iwn_compressed_ba *cba = (struct iwn_compressed_ba *)(desc + 1);
struct ieee80211com *ic = >sc_ic;
-   struct ieee80211_node *ni;
-   struct ieee80211_tx_ba *ba;
-   struct iwn_node *wn;
-   struct iwn_tx_ring *txq;
-   uint16_t seq, ssn, idx, end_idx;
+   struct iwn_node *wn = (void *)ni;
+   struct ieee80211_tx_ba *ba = >ni_tx_ba[tid];
int min_ampdu_id, max_ampdu_id, id;
-   int qid;
+   int idx, end_idx;
 
-   if (ic->ic_state != IEEE80211_S_RUN)
-   return;
-
-   bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*cba),
-   BUS_DMASYNC_POSTREAD);
-
-   if (!IEEE80211_ADDR_EQ(ic->ic_bss->ni_macaddr, cba->macaddr))
-   return;
-
-   ni = ic->ic_bss;
-   wn = (void *)ni;
-
-   qid = le16toh(cba->qid);
-   if (qid < sc->first_agg_txq || qid >= sc->ntxqs)
-   return;
-
-   txq = >txq[qid];
-
-   /* Protect against a firmware bug where the queue/TID are off. */
-   if (qid != sc->first_agg_txq + cba->tid)
-   return;
-
-   ba = >ni_tx_ba[cba->tid];
-   if (ba->ba_state != IEEE80211_BA_AGREED)
-   return;
-
-   /*
-* The first bit in cba->bitmap corresponds to the sequence number
-* stored in the sequence control field cba->seq.
-* Any frames older than this can now be discarded; they should
-* already have been reported as failures or been acknowledged.
-*
-* Multiple BA notifications in a row may be using this number, with
-* additional bits being set in cba->bitmap. It is unclear how the
-* firmware decides to shift this window forward.
-*/
-   seq = le16toh(cba->seq) >> IEEE80211_SEQ_SEQ_SHIFT;
-   if (!SEQ_LT(seq, ba->ba_winstart)) {
-   ieee80211_output_ba_move_window(ic, ni, cba->tid, seq);
-   iwn_ampdu_txq_advance(sc, txq, qid,
-   IWN_AGG_SSN_TO_TXQ_IDX(seq));
-   iwn_clear_oactive(sc, txq);
-   }
-   /* Our BA window should now correspond to the bitmap. */
-   if (ba->ba_winstart != seq)
-   return;
-
-   /* Skip rate control if our Tx rate is fixed. */
-   if (ic->ic_fixed_mcs != -1)
-   return;
-
-   /*
-* The firmware's new BA window starting sequence number
-* corresponds to the 

Re: iwn/athn/wpi: fix CCMP replay check with HW crypto

2020-05-01 Thread Stefan Sperling
On Fri, May 01, 2020 at 08:06:05PM +, Kevin Chadwick wrote:
> On 2020-05-01 16:05, Stefan Sperling wrote:
> >  The CCMP header contains a nonce,
> > which is incremented by the transmitter whenever it encrypts a new frame.
> 
> I assume there isn't opportunity to set the nonce to a 128 bit random one. It
> would avoid a lot of risk with the likelihood of collisions being
> probalistically guaranteed in all circumstances, rather than absolutely
> guaranteed to avoid collisions, in some?

No, this cannot be changed.

(Unless you are willing to break interop with other 802.11 implementations
and all the hardware/firmware our drivers support ;-)



iwn/athn/wpi: fix CCMP replay check with HW crypto

2020-05-01 Thread Stefan Sperling
This diff needs testing in particular on: athn(4), iwn(4), wpi(4)
I have tested on iwn(4) and athn(4) so far.
Testing with other drivers would be good, too, to ensure that no
regressions are introduced for the software crypto case.

Drivers which offload CCMP decryption to hardware contain a check for
replayed frames. This check is simple: The CCMP header contains a nonce,
which is incremented by the transmitter whenever it encrypts a new frame.
This nonce is known as the "Packet Number" in CCMP (WPA2) and as the
"Transmit Sequence Counter" in TKIP (WPA1). If an encrypted frame is
received which uses a nonce lower than the most recently received nonce,
then the frame can be assumed to be a replay and is discarded.
This is important to defend against replay attacks on WPA.

The way our drivers implement this check doesn't work with block ack.
This is because a driver-side check must assume that frames arrive in order.
With block ack, frames may arrive out of order, and they are put back into
the proper order in ieee80211_inputm() by checking their sequence number
(a separate number from the nonce discussed above).

The 802.11 standard says that the Packet Number should be checked *after*
re-ordering frames back into their proper sequence.
In our drivers, this check can only happen before re-ordering and hence
legitimate out-of-order frame transmissions would be discarded.
For this reason, we currently skip the replay check entirely if block ack
and hardware decryption are used together. Which makes things work but is
obviously not good for security.

This problem only affects hardware crypto because software decryption
happens after re-ordering. I would like to fix this problem before adding
CCMP hardware offload support to more drivers.

The following diff moves the Packet Number check out of affected drivers
into ieee80211_inputm() so the check can be performed after frames have
been re-ordered.
Drivers no longer update the expected replay counter value, but they can
still read its current value to discard replayed frames early.
This simplifies CCMP input handling in affected drivers significantly.

Drivers which only do WEP in hardware don't need any change.

While here:

 - Implement ieee80211_get_rxkey(); a prototype already existed but now
   we actually need an implementation of this to avoid code duplication
   within net80211 and some drivers.

 - Fix a wrong assumption made about reply counters and TIDs. We only
   announce support for one replay counter per key, and never initialize
   counters other than k_rsc[0]. Some code was accessing k_rsc[tid] based
   on the TID value in the frame header. Based on the fact that counters
   at offsets other than zero are not initialized, and on my understanding
   of the 802.11-2012 spec, this is wrong. Multiple counters are only used
   if support for them is announced in an RSN capability field, and we do
   not announce this. We also use TIDs only to correlate frames with an
   existing block ack agreement. The multi-replay counter case assumes
   instead that TIDs are used for purposes of real OoS, which we do not
   implement. Real QoS could lead to out-of-order transmissions based
   on the priority assigned to the data contained in a frame, so it makes
   sense to maintain one replay counter per priority with real QoS.

diff refs/heads/master refs/heads/pn
blob - 9193ae3c7b5101a86b85b1b3ba48489d75f5150c
blob + 5c17a7d065c622cdde56ccc81baa1859df93404f
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -792,12 +792,9 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
struct ieee80211com *ic = >sc_ic;
struct ieee80211_key *k;
struct ieee80211_frame *wh;
-   struct ieee80211_rx_ba *ba;
uint64_t pn, *prsc;
-   u_int8_t *ivp, *mmie;
-   uint8_t tid;
-   uint16_t kid;
-   int hdrlen, hasqos;
+   u_int8_t *ivp;
+   int hdrlen;
uintptr_t entry;
 
wh = mtod(m, struct ieee80211_frame *);
@@ -805,35 +802,8 @@ ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *
ivp = mtod(m, u_int8_t *) + hdrlen;
 
/* find key for decryption */
-   if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
-   k = >ni_pairwise_key;
-   } else if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
-   IEEE80211_FC0_TYPE_MGT) {
-   /* retrieve group data key id from IV field */
-   /* check that IV field is present */
-   if (m->m_len < hdrlen + 4)
-   return 1;
-   kid = ivp[3] >> 6;
-   k = >ic_nw_keys[kid];
-   } else {
-   /* retrieve integrity group key id from MMIE */
-   if (m->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) {
-   return 1;
-   }
-   /* it is assumed management frames are contiguous */
-   mmie = (u_int8_t *)wh + m->m_len - IEEE80211_MMIE_LEN;
-   /* check that MMIE is valid */
-   

iwn(4): prevent divide-by-zero

2020-05-01 Thread Stefan Sperling
I have seen a kernel panic with iwn(4) due to a divide by zero on
this line in ieee80211_mira.c's ieee80211_mira_update_stats():

sfer /= (mn->txfail + 1) * mn->frames;

We ended up in mira_choose() via iwn_rx_compressed_ba().

The following patch prevents the problem.

ok?

diff 618f51c546b1ced449867c384af3a2f0afbf155d /usr/src
blob - 73157095886b0073524e13ea29b695e7809aa870
file + sys/dev/pci/if_iwn.c
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2372,6 +2372,7 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
 */
if (txdata->m != NULL && txdata->ampdu_id == id &&
txdata->ampdu_txmcs == ni->ni_txmcs &&
+   txdata->ampdu_nframes > 0 &&
(SEQ_LT(ba->ba_winend, s) ||
(ba->ba_bitmap & (1 << bit)) == 0)) {
have_ack++;
blob - 23bfcf0a331ed839037f8c2a4ef58ed640923233
file + sys/net80211/ieee80211_mira.c
--- sys/net80211/ieee80211_mira.c
+++ sys/net80211/ieee80211_mira.c
@@ -400,6 +400,9 @@ ieee80211_mira_update_stats(struct ieee80211_mira_node
uint64_t rate = ieee80211_mira_get_txrate(ni->ni_txmcs, sgi);
struct ieee80211_mira_goodput_stats *g = >g[ni->ni_txmcs];
 
+   if (mn->frames == 0)
+   return; /* avoid divide-by-zero in sfer calculation below */
+
g->nprobes += mn->agglen;
g->nprobe_bytes += mn->ampdu_size;
 



net80211/athn/iwm/iwx: add nwflag nomimo

2020-04-27 Thread Stefan Sperling
We currently do not support 11n mode on devices which do not have all
antenna ports connected. So if e.g. an athn(4) card is installed into
an APU or Alix, we require that users plug pigtails into all antenna
connectors on the card, and mount a corresponding number of antennas
on the case. Given hardware restrictions this may not always be possible.

I happen to have an Alix case with only one hole for an antenna, and I am now
running a MIMO-capable AR9280 card on this board. Without this patch I can
either run the card in 11a/g mode, or I could screw a hole for another
antenna into the case. But 11n mode isn't a viable option; if either side
decides to send a MIMO data frame this frame will be lost.

There is no technical requirement for this restriction since 11n mode
can operate with just MCS 0-7. There are 11n devices which do not even
support MIMO and 11n mode already works fine with such devices.

However, on devices which support MIMO we would need a way to tell how
many antennas are physically connected in order to make a decision.

Automatically detecting dead antennas requires tedious driver-specific
heuristics, and in some cases isn't even a possibility since firmware may
restrict what the driver can see. E.g. I've been told by an iwlwifi developer
that current Intel firmware doesn't bother with detecting missing antennas.

What we can easily offer is another nwflag to disable MIMO at run-time.
With this set, drivers will operate their device as if it didn't support MIMO,
net80211 can stop announcing support for MIMO rates, and 11n mode works.

Tested on iwm(4) and athn(4), and works as expected for me.

ok?

(Apply this patch, run 'make includes', and recompile ifconfig and the kernel.)
 
diff 6608380519f922f07dba3821961f4d7330327041 
ad4a4e1aff0295006baf16de294666e4b1293b93
blob - f6efc3bc13e84ddb4e7821b23637e3404668caef
blob + c954658d613a805b0e003654429ff8ae68c3c6a7
--- sbin/ifconfig/ifconfig.8
+++ sbin/ifconfig/ifconfig.8
@@ -1053,6 +1053,13 @@ flag will disable the direct bridging of frames betwee
 nodes when operating in Host AP mode.
 Setting this flag will block and filter direct inter-station
 communications.
+.It nomimo
+The
+.Ql nomimo
+flag will disable MIMO reception and transmission even if the driver
+and wireless network device support MIMO.
+This flag can be used to work around packet loss in 11n mode if the
+wireless network device has unpopulated extra antenna connectors.
 .It stayauth
 The
 .Ql stayauth
blob - 8153923216917c1f8fdb77c3ac4de21feba10e1d
blob + 7d2d13f168c1d6eb7e50756c8956e0b05a3c8270
--- sys/dev/ic/athn.c
+++ sys/dev/ic/athn.c
@@ -180,6 +180,53 @@ struct cfdriver athn_cd = {
NULL, "athn", DV_IFNET
 };
 
+void
+athn_config_ht(struct athn_softc *sc)
+{
+   struct ieee80211com *ic = >sc_ic;
+   int i, ntxstreams, nrxstreams;
+
+   if ((sc->flags & ATHN_FLAG_11N) == 0)
+   return;
+
+   /* Set HT capabilities. */
+   ic->ic_htcaps = (IEEE80211_HTCAP_SMPS_DIS <<
+   IEEE80211_HTCAP_SMPS_SHIFT);
+#ifdef notyet
+   ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40 |
+   IEEE80211_HTCAP_SGI40 |
+   IEEE80211_HTCAP_DSSSCCK40;
+#endif
+   ic->ic_htxcaps = 0;
+#ifdef notyet
+   if (AR_SREV_9271(sc) || AR_SREV_9287_10_OR_LATER(sc))
+   ic->ic_htcaps |= IEEE80211_HTCAP_SGI20;
+   if (AR_SREV_9380_10_OR_LATER(sc))
+   ic->ic_htcaps |= IEEE80211_HTCAP_LDPC;
+   if (AR_SREV_9280_10_OR_LATER(sc)) {
+   ic->ic_htcaps |= IEEE80211_HTCAP_TXSTBC;
+   ic->ic_htcaps |= 1 << IEEE80211_HTCAP_RXSTBC_SHIFT;
+   }
+#endif
+   ntxstreams = sc->ntxchains;
+   nrxstreams = sc->nrxchains;
+   if (!AR_SREV_9380_10_OR_LATER(sc)) {
+   ntxstreams = MIN(ntxstreams, 2);
+   nrxstreams = MIN(nrxstreams, 2);
+   }
+   /* Set supported HT rates. */
+   if (ic->ic_userflags & IEEE80211_F_NOMIMO)
+   ntxstreams = nrxstreams = 1;
+   memset(ic->ic_sup_mcs, 0, sizeof(ic->ic_sup_mcs));
+   for (i = 0; i < nrxstreams; i++)
+   ic->ic_sup_mcs[i] = 0xff;
+   ic->ic_tx_mcs_set = IEEE80211_TX_MCS_SET_DEFINED;
+   if (ntxstreams != nrxstreams) {
+   ic->ic_tx_mcs_set |= IEEE80211_TX_RX_MCS_NOT_EQUAL;
+   ic->ic_tx_mcs_set |= (ntxstreams - 1) << 2;
+   }
+}
+
 int
 athn_attach(struct athn_softc *sc)
 {
@@ -302,44 +349,8 @@ athn_attach(struct athn_softc *sc)
IEEE80211_C_SHPREAMBLE |/* Short preamble supported. */
IEEE80211_C_PMGT;   /* Power saving supported. */
 
-   if (sc->flags & ATHN_FLAG_11N) {
-   int i, ntxstreams, nrxstreams;
+   athn_config_ht(sc);
 
-   /* Set HT capabilities. */
-   ic->ic_htcaps = (IEEE80211_HTCAP_SMPS_DIS <<
-   IEEE80211_HTCAP_SMPS_SHIFT);
-#ifdef notyet
-   ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40 |
-   

Re: athn(4): configure Tx interrupt mitigation

2020-04-27 Thread Stefan Sperling
Anyone?

On Wed, Apr 22, 2020 at 07:28:02PM +0200, Stefan Sperling wrote:
> We currently configure interrupt mitigation for Rx, but not for Tx.
> 
> And there is also a global Tx/Rx interrupt limit which can be configured
> via the MIRT register. Setting this could prevent Tx/Rx interrupt storms.
> 
> This change doesn't really buy us anything during regular use of the
> device, but during my testing it didn't hurt either.
> 
> OK?
> 
> diff 9b00dd5006bdfc0cf9d71dac4defe47f2ccfda0d 
> c50b0f0215d7dd5773e0ee8623d8aa2c7d2107c6
> blob - 88784561c133b42b2b23dff2cea0075cf2ffdd27
> blob + b3532eb8263f678c80a44257fe4f55820458a18c
> --- sys/dev/ic/athn.c
> +++ sys/dev/ic/athn.c
> @@ -2428,6 +2428,12 @@ athn_hw_reset(struct athn_softc *sc, struct ieee80211_
>   /* Setup Rx interrupt mitigation. */
>   AR_WRITE(sc, AR_RIMT, SM(AR_RIMT_FIRST, 2000) | SM(AR_RIMT_LAST, 500));
>  
> + /* Setup Tx interrupt mitigation. */
> + AR_WRITE(sc, AR_TIMT, SM(AR_TIMT_FIRST, 2000) | SM(AR_TIMT_LAST, 500));
> +
> + /* Set maximum interrupt rate threshold (in micro seconds). */
> + AR_WRITE(sc, AR_MIRT, SM(AR_MIRT_RATE_THRES, 2000));
> +
>   ops->init_baseband(sc);
>  
>   if ((error = athn_init_calib(sc, c, extc)) != 0) {
> blob - 92b937ce3b3a0977a0f8548051863c39656a4862
> blob + e14c096b90b5350712548d245a9bfd919b66f23b
> --- sys/dev/ic/athnreg.h
> +++ sys/dev/ic/athnreg.h
> @@ -280,6 +280,10 @@
>  /* Bits for AR_IER. */
>  #define AR_IER_ENABLE0x0001
>  
> +/* Bits for AR_MIRT. */
> +#define AR_MIRT_RATE_THRES_M 0x
> +#define AR_MIRT_RATE_THRES_S 0 
> +
>  /* Bits for AR_TIMT. */
>  #define AR_TIMT_LAST_M   0x
>  #define AR_TIMT_LAST_S   0
> 
> 



Re: athn(4): WPA2 crypto hardware offload

2020-04-24 Thread Stefan Sperling
On Fri, Apr 24, 2020 at 03:31:12PM +0200, Stefan Sperling wrote:
> On Wed, Apr 22, 2020 at 07:37:10PM +0200, Stefan Sperling wrote:
> > This makes athn(4) offload CCMP encryption and decryption to hardware.
> > CCMP is used with WPA2, so this reduces CPU load on WPA2 networks only.
> > 
> > The WPA1 (TKIP) and WEP ciphers remain in software because this simplifies
> > the driver. TKIP in particular is a annoying to deal with on this hardware.
> > Old ciphers should not be used anymore anyway and they don't work in 11n 
> > mode.
> > 
> > I have successfully tested the following on this device:
> > athn0 at pci1 dev 0 function 0 "Atheros AR9281" rev 0x01: apic 2 int 16
> > athn0: AR9280 rev 2 (2T2R), ROM rev 22, address xx:xx:xx:xx:xx:xx
> > 
> > Hostap mode with multiple clients in parallel: wpa2, wpa1, wep, plaintext
> > Client mode: wpa2, plaintext
> > 
> > Could anyone else test this?
> 
> This patch panics on athn(4) USB devices (reported to me by several people).
> I am working on a fix for USB.

New diff which also works on USB devices (tested on AR9271 and AR9280+AR7010).

diff c50b0f0215d7dd5773e0ee8623d8aa2c7d2107c6 
b593e0ca32b1c816510ec76bdd498bc9101dea15
blob - 9dd0499c9704c87fbe039b65f02e907284fea120
blob + 0f78d27c9e99239d6ec08410dd42e65c5781245d
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -77,11 +77,14 @@ voidar5008_rx_free(struct athn_softc *);
 void   ar5008_rx_enable(struct athn_softc *);
 void   ar5008_rx_radiotap(struct athn_softc *, struct mbuf *,
struct ar_rx_desc *);
+intar5008_ccmp_decap(struct athn_softc *, struct mbuf *,
+   struct ieee80211_node *);
 void   ar5008_rx_intr(struct athn_softc *);
 intar5008_tx_process(struct athn_softc *, int);
 void   ar5008_tx_intr(struct athn_softc *);
 intar5008_swba_intr(struct athn_softc *);
 intar5008_intr(struct athn_softc *);
+intar5008_ccmp_encap(struct mbuf *, u_int, struct ieee80211_key *);
 intar5008_tx(struct athn_softc *, struct mbuf *, struct ieee80211_node *,
int);
 void   ar5008_set_rf_mode(struct athn_softc *, struct ieee80211_channel *);
@@ -254,6 +257,8 @@ ar5008_attach(struct athn_softc *sc)
kc_entries_log = MS(base->deviceCap, AR_EEP_DEVCAP_KC_ENTRIES);
sc->kc_entries = (kc_entries_log != 0) ?
1 << kc_entries_log : AR_KEYTABLE_SIZE;
+   if (sc->kc_entries > AR_KEYTABLE_SIZE)
+   sc->kc_entries = AR_KEYTABLE_SIZE;
 
sc->txchainmask = base->txMask;
if (sc->mac_ver == AR_SREV_VERSION_5416_PCI &&
@@ -781,6 +786,111 @@ ar5008_rx_radiotap(struct athn_softc *sc, struct mbuf 
 }
 #endif
 
+int
+ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node 
*ni)
+{
+   struct ieee80211com *ic = >sc_ic;
+   struct ieee80211_key *k;
+   struct ieee80211_frame *wh;
+   struct ieee80211_rx_ba *ba;
+   uint64_t pn, *prsc;
+   u_int8_t *ivp, *mmie;
+   uint8_t tid;
+   uint16_t kid;
+   int hdrlen, hasqos;
+   uintptr_t entry;
+
+   wh = mtod(m, struct ieee80211_frame *);
+   hdrlen = ieee80211_get_hdrlen(wh);
+   ivp = mtod(m, u_int8_t *) + hdrlen;
+
+   /* find key for decryption */
+   if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+   k = >ni_pairwise_key;
+   } else if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
+   IEEE80211_FC0_TYPE_MGT) {
+   /* retrieve group data key id from IV field */
+   /* check that IV field is present */
+   if (m->m_len < hdrlen + 4)
+   return 1;
+   kid = ivp[3] >> 6;
+   k = >ic_nw_keys[kid];
+   } else {
+   /* retrieve integrity group key id from MMIE */
+   if (m->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) {
+   return 1;
+   }
+   /* it is assumed management frames are contiguous */
+   mmie = (u_int8_t *)wh + m->m_len - IEEE80211_MMIE_LEN;
+   /* check that MMIE is valid */
+   if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) {
+   return 1;
+   }
+   kid = LE_READ_2([2]);
+   if (kid != 4 && kid != 5) {
+   return 1;
+   }
+   k = >ic_nw_keys[kid];
+   }
+
+   if (k->k_cipher != IEEE80211_CIPHER_CCMP)
+   return 1;
+
+   /* Sanity checks to ensure this is really a key we installed. */
+   entry = (uintptr_t)k->k_priv;
+   if (k->k_flags & IEEE80211_KEY_GROUP) {
+   if (k->k_id > IEEE80211_WEP_NKID ||
+   entry != k->k_id)
+   return 1;
+   } else if (entry != IEEE80211_WEP_NKID 

Re: athn(4): WPA2 crypto hardware offload

2020-04-24 Thread Stefan Sperling
On Wed, Apr 22, 2020 at 07:37:10PM +0200, Stefan Sperling wrote:
> This makes athn(4) offload CCMP encryption and decryption to hardware.
> CCMP is used with WPA2, so this reduces CPU load on WPA2 networks only.
> 
> The WPA1 (TKIP) and WEP ciphers remain in software because this simplifies
> the driver. TKIP in particular is a annoying to deal with on this hardware.
> Old ciphers should not be used anymore anyway and they don't work in 11n mode.
> 
> I have successfully tested the following on this device:
> athn0 at pci1 dev 0 function 0 "Atheros AR9281" rev 0x01: apic 2 int 16
> athn0: AR9280 rev 2 (2T2R), ROM rev 22, address xx:xx:xx:xx:xx:xx
> 
> Hostap mode with multiple clients in parallel: wpa2, wpa1, wep, plaintext
> Client mode: wpa2, plaintext
> 
> Could anyone else test this?

This patch panics on athn(4) USB devices (reported to me by several people).
I am working on a fix for USB.

Meanwhile, testing on PCI devices is still welcome.

Thanks!



iwm(4) timeout cancellation fix

2020-04-23 Thread Stefan Sperling
I have observed a uvm fault in ieee80211_mira_probe_timeout_up() while
testing with iwm(4) and tcpbench:

void
ieee80211_mira_probe_timeout_up(void *arg)
{
struct ieee80211_mira_node *mn = arg;
int s;

s = splnet();
mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] = 1;
DPRINTFN(3, ("probe up timeout fired\n"));
splx(s);
}

One obvious possibility is that the 'mn' pointer became invalid before the
timeout was executed. But I am not certain what happened exactly; the info
in ddb was inconclusive since the console switching ran into splassert
failures and I didn't see a good backtrace. But r12 in 'show regs' contained
the address of ieee80211_mira_probe_timeout_up() and it looked like the
kernel was in softclock context.

In any case, it looks like cancelling timeouts before scheduling the
iwm_newstate_task can lead to a race:

 - Timeouts are cancelled and iwm_newstate_task is scheduled
 - Tx done interrupts feed frames to MiRA which adds a new timeout
 - iwm_newstate_task runs and switches state without cancelling this timeout
 
So cancel timeouts when we are actually switching state in the task.

While here, initialize MiRA timeouts and other rate scaling state earlier,
when the node is allocated.

ok?

diff 9b00dd5006bdfc0cf9d71dac4defe47f2ccfda0d 
caa4131c31c0809410871043d8c29cf157d68ff3
blob - 01c059a512b8d83fe9900942e07b4c1b128f660c
blob + 196b7814bbfaf625495278070374393409f7cb69
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -6770,7 +6770,16 @@ iwm_run_stop(struct iwm_softc *sc)
 struct ieee80211_node *
 iwm_node_alloc(struct ieee80211com *ic)
 {
-   return malloc(sizeof (struct iwm_node), M_DEVBUF, M_NOWAIT | M_ZERO);
+   struct iwm_softc *sc = IC2IFP(ic)->if_softc;
+   struct iwm_node *in;
+
+   in = malloc(sizeof (struct iwm_node), M_DEVBUF, M_NOWAIT | M_ZERO);
+   if (in == NULL)
+   return NULL;
+
+   ieee80211_amrr_node_init(>sc_amrr, >in_amn);
+   ieee80211_mira_node_init(>in_mn);
+   return (struct ieee80211_node *)in;
 }
 
 void
@@ -6961,6 +6970,14 @@ iwm_newstate_task(void *psc)
int arg = sc->ns_arg;
int err = 0, s = splnet();
 
+   if (ic->ic_state == IEEE80211_S_RUN) {
+   struct iwm_node *in = (void *)ic->ic_bss;
+   timeout_del(>sc_calib_to);
+   ieee80211_mira_cancel_timeouts(>in_mn);
+   iwm_del_task(sc, systq, >ba_task);
+   iwm_del_task(sc, systq, >htprot_task);
+   }
+
if (sc->sc_flags & IWM_FLAG_SHUTDOWN) {
/* iwm_stop() is waiting for us. */
refcnt_rele_wake(>task_refs);
@@ -7057,14 +7074,6 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_s
 {
struct ifnet *ifp = IC2IFP(ic);
struct iwm_softc *sc = ifp->if_softc;
-   struct iwm_node *in = (void *)ic->ic_bss;
-
-   if (ic->ic_state == IEEE80211_S_RUN) {
-   timeout_del(>sc_calib_to);
-   ieee80211_mira_cancel_timeouts(>in_mn);
-   iwm_del_task(sc, systq, >ba_task);
-   iwm_del_task(sc, systq, >htprot_task);
-   }
 
sc->ns_nstate = nstate;
sc->ns_arg = arg;



athn(4): WPA2 crypto hardware offload

2020-04-22 Thread Stefan Sperling
This makes athn(4) offload CCMP encryption and decryption to hardware.
CCMP is used with WPA2, so this reduces CPU load on WPA2 networks only.

The WPA1 (TKIP) and WEP ciphers remain in software because this simplifies
the driver. TKIP in particular is a annoying to deal with on this hardware.
Old ciphers should not be used anymore anyway and they don't work in 11n mode.

I have successfully tested the following on this device:
athn0 at pci1 dev 0 function 0 "Atheros AR9281" rev 0x01: apic 2 int 16
athn0: AR9280 rev 2 (2T2R), ROM rev 22, address xx:xx:xx:xx:xx:xx

Hostap mode with multiple clients in parallel: wpa2, wpa1, wep, plaintext
Client mode: wpa2, plaintext

Could anyone else test this?

diff c50b0f0215d7dd5773e0ee8623d8aa2c7d2107c6 
72190e7ad96414fa4e11cb3c5ff1dc74b1d69795
blob - 9dd0499c9704c87fbe039b65f02e907284fea120
blob + 8ebdc15cbec490ea4a2f28a0fadab014e3d62645
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -254,6 +254,8 @@ ar5008_attach(struct athn_softc *sc)
kc_entries_log = MS(base->deviceCap, AR_EEP_DEVCAP_KC_ENTRIES);
sc->kc_entries = (kc_entries_log != 0) ?
1 << kc_entries_log : AR_KEYTABLE_SIZE;
+   if (sc->kc_entries > AR_KEYTABLE_SIZE)
+   sc->kc_entries = AR_KEYTABLE_SIZE;
 
sc->txchainmask = base->txMask;
if (sc->mac_ver == AR_SREV_VERSION_5416_PCI &&
@@ -781,6 +783,111 @@ ar5008_rx_radiotap(struct athn_softc *sc, struct mbuf 
 }
 #endif
 
+int
+ar5008_ccmp_decap(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node 
*ni)
+{
+   struct ieee80211com *ic = >sc_ic;
+   struct ieee80211_key *k;
+   struct ieee80211_frame *wh;
+   struct ieee80211_rx_ba *ba;
+   uint64_t pn, *prsc;
+   u_int8_t *ivp, *mmie;
+   uint8_t tid;
+   uint16_t kid;
+   int hdrlen, hasqos;
+   uintptr_t entry;
+
+   wh = mtod(m, struct ieee80211_frame *);
+   hdrlen = ieee80211_get_hdrlen(wh);
+   ivp = mtod(m, u_int8_t *) + hdrlen;
+
+   /* find key for decryption */
+   if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+   k = >ni_pairwise_key;
+   } else if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
+   IEEE80211_FC0_TYPE_MGT) {
+   /* retrieve group data key id from IV field */
+   /* check that IV field is present */
+   if (m->m_len < hdrlen + 4)
+   return 1;
+   kid = ivp[3] >> 6;
+   k = >ic_nw_keys[kid];
+   } else {
+   /* retrieve integrity group key id from MMIE */
+   if (m->m_len < sizeof(*wh) + IEEE80211_MMIE_LEN) {
+   return 1;
+   }
+   /* it is assumed management frames are contiguous */
+   mmie = (u_int8_t *)wh + m->m_len - IEEE80211_MMIE_LEN;
+   /* check that MMIE is valid */
+   if (mmie[0] != IEEE80211_ELEMID_MMIE || mmie[1] != 16) {
+   return 1;
+   }
+   kid = LE_READ_2([2]);
+   if (kid != 4 && kid != 5) {
+   return 1;
+   }
+   k = >ic_nw_keys[kid];
+   }
+
+   if (k->k_cipher != IEEE80211_CIPHER_CCMP)
+   return 1;
+
+   /* Sanity checks to ensure this is really a key we installed. */
+   entry = (uintptr_t)k->k_priv;
+   if (k->k_flags & IEEE80211_KEY_GROUP) {
+   if (k->k_id > IEEE80211_WEP_NKID ||
+   entry != k->k_id)
+   return 1;
+   } else if (entry != IEEE80211_WEP_NKID +
+   IEEE80211_AID(ni->ni_associd))
+   return 1;
+
+   /* Check that ExtIV bit is be set. */
+   if (!(ivp[3] & IEEE80211_WEP_EXTIV))
+   return 1;
+
+   hasqos = ieee80211_has_qos(wh);
+   tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
+   ba = hasqos ? >ni_rx_ba[tid] : NULL;
+   prsc = >k_rsc[0];
+
+   /* Extract the 48-bit PN from the CCMP header. */
+   pn = (uint64_t)ivp[0]   |
+(uint64_t)ivp[1] <<  8 |
+(uint64_t)ivp[4] << 16 |
+(uint64_t)ivp[5] << 24 |
+(uint64_t)ivp[6] << 32 |
+(uint64_t)ivp[7] << 40;
+   if (pn <= *prsc) {
+   if (hasqos && ba->ba_state == IEEE80211_BA_AGREED) {
+   /*
+* This is an A-MPDU subframe.
+* Such frames may be received out of order due to
+* legitimate retransmissions of failed subframes
+* in previous A-MPDUs. Duplicates will be handled
+* in ieee80211_inputm() as part of A-MPDU reordering.
+*
+* XXX TODO We can probably do better than this! Store
+* re-ordered PN in BA agreement state and check it?
+*/
+   } else {
+   

athn(4): configure Tx interrupt mitigation

2020-04-22 Thread Stefan Sperling
We currently configure interrupt mitigation for Rx, but not for Tx.

And there is also a global Tx/Rx interrupt limit which can be configured
via the MIRT register. Setting this could prevent Tx/Rx interrupt storms.

This change doesn't really buy us anything during regular use of the
device, but during my testing it didn't hurt either.

OK?

diff 9b00dd5006bdfc0cf9d71dac4defe47f2ccfda0d 
c50b0f0215d7dd5773e0ee8623d8aa2c7d2107c6
blob - 88784561c133b42b2b23dff2cea0075cf2ffdd27
blob + b3532eb8263f678c80a44257fe4f55820458a18c
--- sys/dev/ic/athn.c
+++ sys/dev/ic/athn.c
@@ -2428,6 +2428,12 @@ athn_hw_reset(struct athn_softc *sc, struct ieee80211_
/* Setup Rx interrupt mitigation. */
AR_WRITE(sc, AR_RIMT, SM(AR_RIMT_FIRST, 2000) | SM(AR_RIMT_LAST, 500));
 
+   /* Setup Tx interrupt mitigation. */
+   AR_WRITE(sc, AR_TIMT, SM(AR_TIMT_FIRST, 2000) | SM(AR_TIMT_LAST, 500));
+
+   /* Set maximum interrupt rate threshold (in micro seconds). */
+   AR_WRITE(sc, AR_MIRT, SM(AR_MIRT_RATE_THRES, 2000));
+
ops->init_baseband(sc);
 
if ((error = athn_init_calib(sc, c, extc)) != 0) {
blob - 92b937ce3b3a0977a0f8548051863c39656a4862
blob + e14c096b90b5350712548d245a9bfd919b66f23b
--- sys/dev/ic/athnreg.h
+++ sys/dev/ic/athnreg.h
@@ -280,6 +280,10 @@
 /* Bits for AR_IER. */
 #define AR_IER_ENABLE  0x0001
 
+/* Bits for AR_MIRT. */
+#define AR_MIRT_RATE_THRES_M   0x
+#define AR_MIRT_RATE_THRES_S   0 
+
 /* Bits for AR_TIMT. */
 #define AR_TIMT_LAST_M 0x
 #define AR_TIMT_LAST_S 0



Re: bwfm(4): document supported chipsets

2020-04-19 Thread Stefan Sperling
On Sun, Apr 19, 2020 at 03:00:59PM -0600, Theo de Raadt wrote:
> % man -k sdio
> amlmmc(4) - Amlogic MMC/SD/SDIO controller
> dwmmc(4) - Synopsis DesignWare MMC/SD/SDIO controller
> ommmc(4/armv7) - MMC/SD/SDIO controller
> 
> 
> Oh, so it only works on those 3 controllers?

Fine. I'll commit my first diff then.

Sorry Mark. And I'll just omit the slash from SD/MMC, too!
If you want to see a list of supported devices and don't have peril
sensitive glasses to read the man page then I'm sure the source code
will serve as great reference, too :)



Re: bwfm(4): document supported chipsets

2020-04-19 Thread Stefan Sperling
On Sun, Apr 19, 2020 at 10:46:28PM +0200, Mark Kettenis wrote:
> > Date: Sun, 19 Apr 2020 22:24:31 +0200
> > From: Stefan Sperling 
> > 
> > We really should be documenting supported wifi chipsets to help users
> > find devices that will work with OpenBSD.
> > The bwfm(4) man page leaves such questions entirely open at present.
> > 
> > The diff below intends to fill that gap by adding table which lists
> > supported devices. The table includes chipset name, supported bands,
> > MIMO config, and bus attachments.
> > 
> > I have cross-checked data in my table with internet searches. Sometimes
> > I found official product sheets, but some info is based on tech press
> > articles, copies of wikidevi pages, or gleaned from kernel messages
> > posted on forums. It should be mostly accurate and much better than
> > no info at all.
> > 
> > Note that some chips support bus attachments which bwfm does not
> > recognize. I have documented the bus attachments which the driver
> > actually supports, which is a subset of what the chipsets support.
> > This list will need to be kept in sync anyway whenever device support
> > in the driver is improved.
> > 
> > While here, also document the hex product IDs in bwfm's sdmmc attachment
> > driver in source code comments. These hex numbers actually correspond
> > to decimal chipset numbers but that is not immediately obvious so I think
> > adding comments is warranted (of course it would be better to use macros,
> > but I'm not going to go that far in a documentation patch).
> > 
> > ok?
> 
> I like the comments documenting the product IDs.  Don't think there is
> much value here in adding #defines actually.
> 
> As for the man page, can you use "SDIO" instead of "SDMMC"?  That is
> techically more correct and avoids the ugliness of leaving out the
> slash in "SD/MMC".

Sure. I agree that SDIO is way more accurate.

The SYNOPSIS section of the page says the driver will attach at 'sdmmc?'
which is why I used that term. But I guess people will make the mental leap.

diff 5c72fbec79072d838dd652f6d7785e8d2b15dab2 /usr/src
blob - f1df893ec80181f14a37bbc8703739bbca13e316
file + share/man/man4/bwfm.4
--- share/man/man4/bwfm.4
+++ share/man/man4/bwfm.4
@@ -30,6 +30,36 @@ The
 driver provides support for Broadcom and Cypress FullMAC network
 adapters.
 .Pp
+The following table summarizes supported chipsets and their capabilites,
+as well as the bus attachments recognized by the
+.Nm
+driver:
+.Bl -column "Chipset" "Spectrum" "MIMO" "Bus" -offset 6n
+.It Em Chipset Ta Em Spectrum Ta Em MIMO Ta Em Bus
+.It BCM43143 Ta 2GHz Ta 1x1 Ta SDIO/USB
+.It BCM43236 Ta 2GHz/5GHz Ta 2x2 Ta USB
+.It BCM4324 Ta  2GHz/5GHz Ta 2x2 Ta SDIO
+.It BCM43242 Ta 2GHz/5GHz Ta 2x2 Ta USB
+.It BCM4329 Ta  2GHz/5GHz Ta 2x2 Ta SDIO
+.It BCM4330 Ta  2GHz/5GHz Ta 2x2 Ta SDIO
+.It BCM4334 Ta  2GHz/5GHz Ta 2x2 Ta SDIO
+.It BCM43340 Ta 2GHz/5GHz Ta 1x1 Ta SDIO
+.It BCM43341 Ta 2GHz/5GHz Ta 1x1 Ta SDIO
+.It BCM4335 Ta  2GHz/5GHz Ta 1x1 Ta SDIO
+.It BCM43362 Ta 2GHz Ta 1x1 Ta SDIO
+.It BCM43364 Ta 2GHz Ta 1x1 Ta SDIO
+.It BCM4339 Ta  2GHz/5GHz Ta 1x1 Ta SDIO
+.It BCM43430 Ta 2GHz Ta 1x1 Ta SDIO
+.It BCM43455 Ta  2GHz/5GHz Ta 1x1 Ta SDIO
+.It BCM43456 Ta  2GHz/5GHz Ta 2x2 Ta SDIO
+.It BCM4350 Ta 2GHz/5GHz Ta 2x2 Ta PCI
+.It BCM4354 Ta  2GHz/5GHz Ta 2x2 Ta SDIO
+.It BCM4356 Ta 2GHz/5GHz Ta 2x2 Ta PCI/SDIO
+.It BCM43569 Ta 2GHz/5GHz Ta 2x2 Ta USB
+.It BCM43602 Ta 2GHz/5GHz Ta 3x3 Ta PCI
+.It BCM4371 Ta 2GHz/5GHz Ta 2x2 Ta PCI
+.El
+.Pp
 These are the modes the
 .Nm
 driver can operate in:
blob - b053ab936ef10b21834ed74640124d8abe761af2
file + sys/dev/sdmmc/if_bwfm_sdio.c
--- sys/dev/sdmmc/if_bwfm_sdio.c
+++ sys/dev/sdmmc/if_bwfm_sdio.c
@@ -222,12 +222,12 @@ bwfm_sdio_match(struct device *parent, void *match, vo
case 0x4345:
case 0x4354:
case 0x4356:
-   case 0xa887:
-   case 0xa94c:
-   case 0xa94d:
-   case 0xa962:
-   case 0xa9a6:
-   case 0xa9bf:
+   case 0xa887:/* BCM43143 */
+   case 0xa94c:/* BCM43340 */
+   case 0xa94d:/* BCM43341 */
+   case 0xa962:/* BCM43362 */
+   case 0xa9a6:/* BCM43430 */
+   case 0xa9bf:/* BCM43364 */
break;
default:
return 0;




bwfm(4): document supported chipsets

2020-04-19 Thread Stefan Sperling
We really should be documenting supported wifi chipsets to help users
find devices that will work with OpenBSD.
The bwfm(4) man page leaves such questions entirely open at present.

The diff below intends to fill that gap by adding table which lists
supported devices. The table includes chipset name, supported bands,
MIMO config, and bus attachments.

I have cross-checked data in my table with internet searches. Sometimes
I found official product sheets, but some info is based on tech press
articles, copies of wikidevi pages, or gleaned from kernel messages
posted on forums. It should be mostly accurate and much better than
no info at all.

Note that some chips support bus attachments which bwfm does not
recognize. I have documented the bus attachments which the driver
actually supports, which is a subset of what the chipsets support.
This list will need to be kept in sync anyway whenever device support
in the driver is improved.

While here, also document the hex product IDs in bwfm's sdmmc attachment
driver in source code comments. These hex numbers actually correspond
to decimal chipset numbers but that is not immediately obvious so I think
adding comments is warranted (of course it would be better to use macros,
but I'm not going to go that far in a documentation patch).

ok?

diff 5c72fbec79072d838dd652f6d7785e8d2b15dab2 /usr/src
blob - f1df893ec80181f14a37bbc8703739bbca13e316
file + share/man/man4/bwfm.4
--- share/man/man4/bwfm.4
+++ share/man/man4/bwfm.4
@@ -30,6 +30,36 @@ The
 driver provides support for Broadcom and Cypress FullMAC network
 adapters.
 .Pp
+The following table summarizes supported chipsets and their capabilites,
+as well as the bus attachments recognized by the
+.Nm
+driver:
+.Bl -column "Chipset" "Spectrum" "MIMO" "Bus" -offset 6n
+.It Em Chipset Ta Em Spectrum Ta Em MIMO Ta Em Bus
+.It BCM43143 Ta 2GHz Ta 1x1 Ta SDMMC/USB
+.It BCM43236 Ta 2GHz/5GHz Ta 2x2 Ta USB
+.It BCM4324 Ta  2GHz/5GHz Ta 2x2 Ta SDMMC
+.It BCM43242 Ta 2GHz/5GHz Ta 2x2 Ta USB
+.It BCM4329 Ta  2GHz/5GHz Ta 2x2 Ta SDMMC
+.It BCM4330 Ta  2GHz/5GHz Ta 2x2 Ta SDMMC
+.It BCM4334 Ta  2GHz/5GHz Ta 2x2 Ta SDMMC
+.It BCM43340 Ta 2GHz/5GHz Ta 1x1 Ta SDMMC
+.It BCM43341 Ta 2GHz/5GHz Ta 1x1 Ta SDMMC
+.It BCM4335 Ta  2GHz/5GHz Ta 1x1 Ta SDMMC
+.It BCM43362 Ta 2GHz Ta 1x1 Ta SDMMC
+.It BCM43364 Ta 2GHz Ta 1x1 Ta SDMMC
+.It BCM4339 Ta  2GHz/5GHz Ta 1x1 Ta SDMMC
+.It BCM43430 Ta 2GHz Ta 1x1 Ta SDMMC
+.It BCM43455 Ta  2GHz/5GHz Ta 1x1 Ta SDMMC
+.It BCM43456 Ta  2GHz/5GHz Ta 2x2 Ta SDMMC
+.It BCM4350 Ta 2GHz/5GHz Ta 2x2 Ta PCI
+.It BCM4354 Ta  2GHz/5GHz Ta 2x2 Ta SDMMC
+.It BCM4356 Ta 2GHz/5GHz Ta 2x2 Ta PCI/SDMMC
+.It BCM43569 Ta 2GHz/5GHz Ta 2x2 Ta USB
+.It BCM43602 Ta 2GHz/5GHz Ta 3x3 Ta PCI
+.It BCM4371 Ta 2GHz/5GHz Ta 2x2 Ta PCI
+.El
+.Pp
 These are the modes the
 .Nm
 driver can operate in:
blob - b053ab936ef10b21834ed74640124d8abe761af2
file + sys/dev/sdmmc/if_bwfm_sdio.c
--- sys/dev/sdmmc/if_bwfm_sdio.c
+++ sys/dev/sdmmc/if_bwfm_sdio.c
@@ -222,12 +222,12 @@ bwfm_sdio_match(struct device *parent, void *match, vo
case 0x4345:
case 0x4354:
case 0x4356:
-   case 0xa887:
-   case 0xa94c:
-   case 0xa94d:
-   case 0xa962:
-   case 0xa9a6:
-   case 0xa9bf:
+   case 0xa887:/* BCM43143 */
+   case 0xa94c:/* BCM43340 */
+   case 0xa94d:/* BCM43341 */
+   case 0xa962:/* BCM43362 */
+   case 0xa9a6:/* BCM43430 */
+   case 0xa9bf:/* BCM43364 */
break;
default:
return 0;



Re: iwn: improve processing of block ack notifications

2020-04-17 Thread Stefan Sperling
On Fri, Apr 17, 2020 at 06:30:22PM +0200, Stefan Sperling wrote:
> On Fri, Apr 17, 2020 at 04:03:30PM +0200, Stefan Sperling wrote:
> > In particular, this fixes wrong assumptions about what the data in the
> > firmware's "compressed block ack" notifications is supposed to represent,
> > and actually pieces information about individual subframes of aggregated
> > frames (A-MPDUs) back together when reporting to MiRA, rather than reporting
> > unrelated subframes to MiRA individually. (Recall that MiRA was primarily
> > designed to operate on units of entire A-MDPUs.)
> 
> Unfortunately, this diff can trigger a page fault. I am looking for a fix.

This new version has been tested by cwen and Josh Grosse and seems to
fix the problems they found with the previous diff. Thanks!

diff 24c5886569df7f9428f24e6e74c71e02cba8c34c 
719fff35cc167c0814926c547e92b317aad32553
blob - 8476916e4337cb6e681c11f26fc1fca5f4a48334
blob + b8beb56aa1112e65c2907b2955694b6a8907d9ae
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2282,7 +2282,11 @@ iwn_mira_choose(struct iwn_softc *sc, struct ieee80211
iwn_set_link_quality(sc, ni);
 }
 
-/* Process an incoming Compressed BlockAck. */
+/*
+ * Process an incoming Compressed BlockAck.
+ * Note that these block ack notifications are generated by firmware and do
+ * not necessarily correspond to contents of block ack frames seen on the air.
+ */
 void
 iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
 struct iwn_rx_data *data)
@@ -2293,7 +2297,8 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
struct ieee80211_tx_ba *ba;
struct iwn_node *wn;
struct iwn_tx_ring *txq;
-   uint16_t ssn, idx;
+   uint16_t seq, ssn, idx, end_idx;
+   int min_ampdu_id, max_ampdu_id, id;
int qid;
 
if (ic->ic_state != IEEE80211_S_RUN)
@@ -2322,66 +2327,103 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
if (ba->ba_state != IEEE80211_BA_AGREED)
return;
 
-   ssn = le16toh(cba->ssn); /* BA window starting sequence number */
-   if (!SEQ_LT(ssn, ba->ba_winstart)) {
-   ieee80211_output_ba_move_window(ic, ni, cba->tid, ssn);
+   /*
+* The first bit in cba->bitmap corresponds to the sequence number
+* stored in the sequence control field cba->seq.
+* Any frames older than this can now be discarded; they should
+* already have been reported as failures or been acknowledged.
+*
+* Multiple BA notifications in a row may be using this number, with
+* additional bits being set in cba->bitmap. It is unclear how the
+* firmware decides to shift this window forward.
+*/
+   seq = le16toh(cba->seq) >> IEEE80211_SEQ_SEQ_SHIFT;
+   if (!SEQ_LT(seq, ba->ba_winstart)) {
+   ieee80211_output_ba_move_window(ic, ni, cba->tid, seq);
iwn_ampdu_txq_advance(sc, txq, qid,
-   IWN_AGG_SSN_TO_TXQ_IDX(ssn));
+   IWN_AGG_SSN_TO_TXQ_IDX(seq));
iwn_clear_oactive(sc, txq);
}
+   /* Our BA window should now correspond to the bitmap. */
+   if (ba->ba_winstart != seq)
+   return;
 
-   /* ba->ba_winstart should now correspond to cba->ssn */
-   if (ba->ba_winstart != cba->ssn)
+   /* Skip rate control if our Tx rate is fixed. */
+   if (ic->ic_fixed_mcs != -1)
return;
 
/*
-* Update Tx rate statistics.
-* Skip rate control if our Tx rate is fixed.
+* The firmware's new BA window starting sequence number
+* corresponds to the first hole in cba->bitmap, implying
+* that all frames between 'seq' and 'ssn' have been acked.
 */
-   if (ic->ic_fixed_mcs == -1 && cba->nframes_sent > 0) {
-   int end_idx = IWN_AGG_SSN_TO_TXQ_IDX(ba->ba_winend);
-   int bit = 0, nsent = cba->nframes_sent;
+   ssn = le16toh(cba->ssn);
 
+   /* Determine the min/max IDs we assigned to AMPDUs in this range. */
+   idx = IWN_AGG_SSN_TO_TXQ_IDX(seq);
+   end_idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn);
+   min_ampdu_id = txq->data[idx].ampdu_id;
+   max_ampdu_id = min_ampdu_id;
+   while (idx != end_idx) {
+   struct iwn_tx_data *txdata = >data[idx];
+
+   if (txdata->m != NULL) {
+   if (min_ampdu_id > txdata->ampdu_id)
+   min_ampdu_id = txdata->ampdu_id;
+   if (max_ampdu_id < txdata->ampdu_id)
+   max_ampdu_id = txdata->ampdu_id;
+   }
+
+   idx = (idx + 1) % IWN_TX_RING_COUNT;
+   }
+
+   /*
+* Update Tx rate statistics for A-MPDUs before firmware's BA win

Re: iwn: improve processing of block ack notifications

2020-04-17 Thread Stefan Sperling
On Fri, Apr 17, 2020 at 04:03:30PM +0200, Stefan Sperling wrote:
> In particular, this fixes wrong assumptions about what the data in the
> firmware's "compressed block ack" notifications is supposed to represent,
> and actually pieces information about individual subframes of aggregated
> frames (A-MPDUs) back together when reporting to MiRA, rather than reporting
> unrelated subframes to MiRA individually. (Recall that MiRA was primarily
> designed to operate on units of entire A-MDPUs.)

Unfortunately, this diff can trigger a page fault. I am looking for a fix.



Re: implement locale(1) charmap argument

2020-04-17 Thread Stefan Sperling
On Fri, Apr 17, 2020 at 03:05:06PM +0200, Ingo Schwarze wrote:
> Naively, it does seem like it would make sense to have "locale -m"
> print a list of possible output values of "locale chardef", so i'm
> not opposed to adding "US-ASCII" to it.  But that doesn't appear to
> be how it works elsewhere, at least not everywhere.  I found no
> documentation stating clearly what it is supposed to do, POSIX feels
> murky at best.

Good grief! Well, we can leave good enough alone then, I suppose :)

Thank you for doing such elaborate research.



iwn: improve processing of block ack notifications

2020-04-17 Thread Stefan Sperling
This applies on top of a previous diff I sent, the one to make use of
the entire firmware retry table.

Recently I have spent a good amount of time trying to reverse-engineer
the sparsely documented behaviour of both iwn(4) and iwm(4) firmware with
respect to Tx aggregation. For details, see my comments in the diff.

I have also put some thought into how we can reconcile the firmware's
representation of relevant information with what MiRA expects to see.

This diff is the best I could come up with so far. There were at lot of
earlier attempts and I'm still not sure if this is the best possible
solution, but it seems more correct than what we have now.

In particular, this fixes wrong assumptions about what the data in the
firmware's "compressed block ack" notifications is supposed to represent,
and actually pieces information about individual subframes of aggregated
frames (A-MPDUs) back together when reporting to MiRA, rather than reporting
unrelated subframes to MiRA individually. (Recall that MiRA was primarily
designed to operate on units of entire A-MDPUs.)
 
diff 24c5886569df7f9428f24e6e74c71e02cba8c34c 
636d6d139ade79b967dc9eb8b553e48dcd939227
blob - 8476916e4337cb6e681c11f26fc1fca5f4a48334
blob + f1a30eea896c8502e8f15bb3d1133b74120253f4
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2282,7 +2282,11 @@ iwn_mira_choose(struct iwn_softc *sc, struct ieee80211
iwn_set_link_quality(sc, ni);
 }
 
-/* Process an incoming Compressed BlockAck. */
+/*
+ * Process an incoming Compressed BlockAck.
+ * Note that these block ack notifications are generated by firmware and do
+ * not necessarily correspond to contents of block ack frames seen on the air.
+ */
 void
 iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
 struct iwn_rx_data *data)
@@ -2293,7 +2297,8 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
struct ieee80211_tx_ba *ba;
struct iwn_node *wn;
struct iwn_tx_ring *txq;
-   uint16_t ssn, idx;
+   uint16_t seq, ssn, idx, end_idx;
+   int min_ampdu_id, max_ampdu_id, id;
int qid;
 
if (ic->ic_state != IEEE80211_S_RUN)
@@ -2322,66 +2327,98 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
if (ba->ba_state != IEEE80211_BA_AGREED)
return;
 
-   ssn = le16toh(cba->ssn); /* BA window starting sequence number */
-   if (!SEQ_LT(ssn, ba->ba_winstart)) {
-   ieee80211_output_ba_move_window(ic, ni, cba->tid, ssn);
+   /*
+* The first bit in cba->bitmap corresponds to the sequence number
+* stored in the sequence control field cba->seq.
+* Any frames older than this can now be discarded; they should
+* already have been reported as failures or been acknowledged.
+*
+* Multiple BA notifications in a row may be using this number, with
+* additional bits being set in cba->bitmap. It is unclear how the
+* firmware decides to shift this window forward.
+*/
+   seq = le16toh(cba->seq) >> IEEE80211_SEQ_SEQ_SHIFT;
+   if (!SEQ_LT(seq, ba->ba_winstart)) {
+   ieee80211_output_ba_move_window(ic, ni, cba->tid, seq);
iwn_ampdu_txq_advance(sc, txq, qid,
-   IWN_AGG_SSN_TO_TXQ_IDX(ssn));
+   IWN_AGG_SSN_TO_TXQ_IDX(seq));
iwn_clear_oactive(sc, txq);
}
+   /* Our BA window should now correspond to the bitmap. */
+   if (ba->ba_winstart != seq)
+   return;
 
-   /* ba->ba_winstart should now correspond to cba->ssn */
-   if (ba->ba_winstart != cba->ssn)
+   /* Skip rate control if our Tx rate is fixed. */
+   if (ic->ic_fixed_mcs != -1)
return;
 
/*
-* Update Tx rate statistics.
-* Skip rate control if our Tx rate is fixed.
+* The firmware's new BA window starting sequence number
+* corresponds to the first hole in cba->bitmap, implying
+* that all frames between 'seq' and 'ssn' have been acked.
 */
-   if (ic->ic_fixed_mcs == -1 && cba->nframes_sent > 0) {
-   int end_idx = IWN_AGG_SSN_TO_TXQ_IDX(ba->ba_winend);
-   int bit = 0, nsent = cba->nframes_sent;
+   ssn = le16toh(cba->ssn);
 
+   /* Determine the min/max IDs we assigned to AMPDUs in this range. */
+   idx = IWN_AGG_SSN_TO_TXQ_IDX(seq);
+   end_idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn);
+   min_ampdu_id = txq->data[idx].ampdu_id;
+   max_ampdu_id = min_ampdu_id;
+   while (idx != end_idx) {
+   struct iwn_tx_data *txdata = >data[idx];
+
+   if (min_ampdu_id > txdata->ampdu_id)
+   min_ampdu_id = txdata->ampdu_id;
+   if (max_ampdu_id < txdata->ampdu_id)
+   max_ampdu_id = txdata->ampdu_id;
+
+   idx = (idx + 1) % IWN_TX_RING_COUNT;
+   }
+
+   /*
+* Update Tx rate statistics for A-MPDUs before 

iwn(4): always traverse the entire multi-rate retry table

2020-04-17 Thread Stefan Sperling
This adapts the use of the firmware multi-rate retry table to always
make use of all available slots.

The table specifies 16 Tx rates the firmware can use, one per Tx attempt.

For example, on a 5 GHz channel the current code fills this table with
static values like this:
  MCS-7 MCS-6 MCS-5 MCS-4 MCS-3 MCS-2 MCS-1 MCS-0 OFDM6 OFDM6 OFDM6 ...

We then point the firmware at the entry in this table where Tx attempts
should begin. If we're currently sending at, say, MCS-5, then the rate
at the 3rd entry will be used first, then the 4th, and so on.

This is in fact what a comment in the Linux driver suggests doing for
non-11n operation, and I guess that's why Damien implemented it this way.
When I added 11n mode to the driver, with MCS 0 to 7, I kept this design.

With MIMO this approach won't work because then we'll have two ranges of
continous rates: MCS 0 to 7 (single antenna) and MCS 8 to 15 (dual antenna).
MiRA never mixes Tx rates using different amounts of antennas.
So we will need an approach that looks more like iwm(4) does it, where the
table is continuously updated and our the Tx current rate is at the front.

While we're transmitting at MCS 5, the table now looks like this:

  MCS-5 MCS-4 MCS-3 MCS-2 MCS-1 MCS-0 OFDM6 OFDM6 OFDM6 OFDM6 OFDM6 OFDM6 ...

Once we support MIMO, the table would look like this while we're using MCS-9:

  MCS-9 MCS-8 OFDM6 OFDM6 OFDM6 OFDM6 OFDM6 OFDM6 ...

So this change prepares for MIMO and makes sure that the firmware can
always make use of the full amount of Tx attempts.

diff 6f793971788fd7061f66330336cbeb5103b717c3 
24c5886569df7f9428f24e6e74c71e02cba8c34c
blob - 110bbe97b980b338acd8aa61fbabd33926c207be
blob + 8476916e4337cb6e681c11f26fc1fca5f4a48334
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -157,6 +157,7 @@ voidiwn_rx_phy(struct iwn_softc *, struct 
iwn_rx_des
struct iwn_rx_data *);
 void   iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *, struct mbuf_list *);
+void   iwn_mira_choose(struct iwn_softc *, struct ieee80211_node *);
 void   iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
 void   iwn5000_rx_calib_results(struct iwn_softc *,
@@ -1864,8 +1865,12 @@ iwn_iter_func(void *arg, struct ieee80211_node *ni)
struct iwn_softc *sc = arg;
struct iwn_node *wn = (void *)ni;
 
-   if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
+   if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) {
+   int old_txrate = ni->ni_txrate;
ieee80211_amrr_choose(>amrr, ni, >amn);
+   if (old_txrate != ni->ni_txrate)
+   iwn_set_link_quality(sc, ni);
+   }
 }
 
 void
@@ -2254,6 +2259,29 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *
ieee80211_release_node(ic, ni);
 }
 
+void
+iwn_mira_choose(struct iwn_softc *sc, struct ieee80211_node *ni)
+{
+   struct ieee80211com *ic = >sc_ic;
+   struct iwn_node *wn = (void *)ni;
+   int best_mcs = ieee80211_mira_get_best_mcs(>mn);
+
+   ieee80211_mira_choose(>mn, ic, ni);
+
+   /*
+* Update firmware's LQ retry table if MiRA has chosen a new MCS.
+*
+* We only need to do this if the best MCS has changed because
+* we ask firmware to use a fixed MCS while MiRA is probing a
+* candidate MCS.
+* While not probing we ask firmware to retry at lower rates in case
+* Tx at the newly chosen best MCS ends up failing, and then report
+* any resulting Tx retries to MiRA in order to trigger probing.
+*/
+   if (best_mcs != ieee80211_mira_get_best_mcs(>mn))
+   iwn_set_link_quality(sc, ni);
+}
+
 /* Process an incoming Compressed BlockAck. */
 void
 iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
@@ -2352,6 +2380,8 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
if (wn->mn.ampdu_size > 0)
ieee80211_mira_choose(>mn, ic, ni);
}
+   if (wn->mn.ampdu_size > 0)
+   iwn_mira_choose(sc, ni);
 }
 
 /*
@@ -2584,7 +2614,7 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_
wn->mn.retries++;
if (txfail)
wn->mn.txfail++;
-   ieee80211_mira_choose(>mn, ic, ni);
+   iwn_mira_choose(sc, ni);
}
 
if (txfail)
@@ -2778,7 +2808,7 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *
wn->mn.retries++;
if (txfail)
wn->mn.txfail++;
-   ieee80211_mira_choose(>mn, ic, data->ni);
+   iwn_mira_choose(sc, data->ni);
}
} else if (data->txrate == data->ni->ni_txrate) {
wn->amn.amn_txcnt++;
@@ -3526,11 +3556,8 @@ iwn_tx(struct iwn_softc *sc, 

iwn: work around fifo underrun Tx errors

2020-04-17 Thread Stefan Sperling
This diff works around FIFO_UNDERRUN (0x84) Tx errors being reported
by iwn(4) firmware. When this error occurs, it tends to occur multiple
times in a row. Affected frames are lost and never get transmitted, and
traffic stalls for a while. This affects tcpbench very visibly.

I don't understand what is causing this. I have found that it only
occurs when we ask the firmware to use its multi-rate retry table.
If we send frames at a fixed rate, it does not happen.

This error is particularly problematic with block ack, because the
failed frames disappear and leave a hole in the receivers block ack
window. The receiver will then have to wait a while for the lost frames
until it eventually decides to skip them.

This problem effectively makes Tx aggegration unusable on iwn(4).

My workaround is to always use a fixed Tx rate for aggregation queues.
This is not ideal for single frames which also get send from such queues
when traffic is low and may now be more likely to fail.
But if the firmware decides to aggregate frames during traffic bursts,
all frames contained in an aggregate are always sent together at the
same rate anyway, so in this case we don't loose anything.

I would like to find a better fix, but this allows me to proceed with
additional fixes for aggregation support and together with those fixes
this seems better than the lossy behaviour we have now.
 
diff 0eca04344da7ad4deb76485dcef00cdf88803be4 
6f793971788fd7061f66330336cbeb5103b717c3
blob - 14c2d9a35e2973feb1ec2347eeef3d6041864291
blob + 110bbe97b980b338acd8aa61fbabd33926c207be
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -3513,10 +3513,12 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ie
else
tx->rflags = rinfo->flags;
/*
-* Skip rate control if our Tx rate is fixed.
-* Keep the Tx rate constant while mira is probing.
+* Keep the Tx rate constant while mira is probing, or if this is
+* an aggregation queue in which case a fixed Tx rate works around
+* FIFO_UNDERRUN Tx errors.
 */
if (tx->id == sc->broadcast_id || ieee80211_mira_is_probing(>mn) ||
+   qid >= sc->first_agg_txq ||
ic->ic_fixed_mcs != -1 || ic->ic_fixed_rate != -1) {
/* Group or management frame, or probing, or fixed Tx rate. */
tx->linkq = 0;



iwn(4): TID fix for block ack request frames

2020-04-17 Thread Stefan Sperling
Make iwn(4) put the correct traffic identifier (TID) into the Tx command
when sending block ack request (BAR) frames.

This is not critical but occasionally I have seen the firmware send a
BAR frame with a bogus TID value, which the receiver will simply discard.
Writing the correct TID into the Tx command seems to fix this.

The bogus value was always 8, which matches IWN_NONQOS_TID and is the
default value for the variable 'tid' seen in the diff below; 'tid' will
be copied to the Tx command later. 
 
diff 807e4f4b605ac66e215f436cbcf9b39590b82cab 
0eca04344da7ad4deb76485dcef00cdf88803be4
blob - 2a1f1c261914ed847c02c9e9f39d9acb1dabbd0e
blob + 14c2d9a35e2973feb1ec2347eeef3d6041864291
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -3422,8 +3422,17 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ie
flags |= IWN_TX_NEED_ACK;
}
if (type == IEEE80211_FC0_TYPE_CTL &&
-   subtype == IEEE80211_FC0_SUBTYPE_BAR)
+   subtype == IEEE80211_FC0_SUBTYPE_BAR) {
+   struct ieee80211_frame_min *mwh;
+   uint8_t *barfrm;
+   uint16_t ctl;
+   mwh = mtod(m, struct ieee80211_frame_min *);
+   barfrm = (uint8_t *)[1];
+   ctl = LE_READ_2(barfrm);
+   tid = (ctl & IEEE80211_BA_TID_INFO_MASK) >>
+   IEEE80211_BA_TID_INFO_SHIFT;
flags |= (IWN_TX_NEED_ACK | IWN_TX_IMM_BA);
+   }
 
if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
flags |= IWN_TX_MORE_FRAG;  /* Cannot happen yet. */



Re: implement locale(1) charmap argument

2020-04-17 Thread Stefan Sperling
On Thu, Apr 16, 2020 at 09:35:18PM +0200, Ingo Schwarze wrote:
>$ locale -m
>   UTF-8
>$ locale charmap
>   UTF-8
>$ LC_ALL=C locale charmap
>   US-ASCII
>$ LC_ALL=POSIX locale charmap
>   US-ASCII

I am OK with your diff, and noticed a separate issue with -m which
is exposed by this change:

If US-ASCII is an available charmap, shouldn't locale -m list "US-ASCII"
in addition to "UTF-8"?



net80211: mira fix for MIMO

2020-04-14 Thread Stefan Sperling
This change affects MIMO-capable drivers: iwm(4), iwx(4), and athn(4)

Prevent MiRA from jumping from very high to very low rates while
switching ratesets when probing.

MiRA does multi-phase probing where it first probes within the current
rateset (e.g. MCS 8-15 aka MIMO2) and then switches to another rateset
(e.g. MCS 0-7 aka SISO) to see if that rateset contains an even better
rate.

When switching to another rateset, MiRA is supposed to begin probing
within the new rateset at a rate which is a close equivalent to the
"best" rate in the rateset it is switching away from.

E.g. if MCS 15 has been determined as the best MIMO2 rate, we should
start probing at MCS 7 when switching to the SISO rateset.
But because of a bug we start at the lowest rate (MCS 0) in this case,
which causes a noticable drop in throughput.

Keeps average throughput closer to the ideal test case of running
at a fixed high MIMO rate (provided that rate actually works best).

diff 875a69c55949fd83d2e1a833af1fbc2174a52ee0 /usr/src (staged changes)
blob - 29df16879e093b5774cfc010d9ad488e5a4af97e
blob + fb2f7c3f9553b3c473f25597d0005bd43c928b15
--- sys/net80211/ieee80211_mira.c
+++ sys/net80211/ieee80211_mira.c
@@ -670,6 +670,9 @@ ieee80211_mira_probe_next_rateset(struct ieee80211_mir
break;
}
}
+   /* If all rates are lower the maximum rate is the closest match. */
+   if (i == rsnext->nrates)
+   ni->ni_txmcs = rsnext->max_mcs;
 
/* Add rates from the next rateset as candidates. */
mn->candidate_rates |= (1 << ni->ni_txmcs);



fix iwn(4) hardware encryption errors

2020-04-11 Thread Stefan Sperling
Since my recent commit to fix Tx reporting in iwn(4) I have observed a
continously rising CCMP decryption error counter in 'netstat -W athn0'
while running tcpbench from iwn(4) towards an athn(4) hostap.

Eventually iwn(4) will send a frame which pushes the CCMP packet number
(a nonce used to detect replays) upwards way out of range, with subsequent
frames having incrementing packet numbers in the expected range again.
Then the link gets stuck since every subsequent CCMP encrypted frame is
discarded by the AP as a replay based on its packet number.

Note that iwn(4) hands off CCMP encryption to hardware.

This diff seems to fix the problem. The ccmp error counter on the AP now
remains at zero. It seems iwn firmware doesn't like it if we reset the
Tx scheduler slot for a frame which is still within the firmware's
block ack window, even if the frame has already been ACKed.
So frames now get cleared off the Tx queue only when the block ack window
has moved past them, which is good enough.

ok?

diff a41d2ed2e84e5db614fcd9a9fdc2f9168577d88c /usr/src
blob - 1751328768da8596f73e42dd81d88482a1fcc13d
file + sys/dev/pci/if_iwn.c
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2259,7 +2259,6 @@ void
 iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
 struct iwn_rx_data *data)
 {
-   struct iwn_ops *ops = >ops;
struct iwn_compressed_ba *cba = (struct iwn_compressed_ba *)(desc + 1);
struct ieee80211com *ic = >sc_ic;
struct ieee80211_node *ni;
@@ -2322,9 +2321,9 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn);
while (nsent && idx != end_idx) {
struct iwn_tx_data *txdata = >data[idx];
-   int have_ack = (le64toh(cba->bitmap) & (1 << bit++));
+   int have_ack = (le64toh(cba->bitmap) & (1 << bit));
 
-   if (txdata->m != NULL) {
+   if ((ba->ba_bitmap & (1 << bit)) == 0) {
/*
 * Don't report frames to MiRA which were sent
 * at a different Tx rate than ni->ni_txmcs.
@@ -2339,18 +2338,15 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
if (!have_ack || txdata->txfail > 0)
wn->mn.txfail++;
}
-   if (have_ack) {
+   if (have_ack)
ieee80211_output_ba_record_ack(ic,
ni, cba->tid, ssn);
-   ops->reset_sched(sc, qid, idx);
-   iwn_tx_done_free_txdata(sc, txdata);
-   txq->queued--;
-   }
}
 
idx = (idx + 1) % IWN_TX_RING_COUNT;
ssn = (ssn + 1) % 0xfff;
nsent--;
+   bit++;
}
 
if (wn->mn.ampdu_size > 0)



net80211: event-based probing trigger fix

2020-04-09 Thread Stefan Sperling
This diff skips MiRA's event-based probing trigger if we're already
at the minimum or maximum rate of our current rateset.

As of this commit on March 5:
https://marc.info/?l=openbsd-cvs=158340898502913=2
if we're beginning a probe because of a throughput measurement change event
we cancel the timeouts responsible for interval-based probing.
Otherwise these timeouts could kick off another unncessary probe right
after the event-based probe has finished.

This change addresses a related problem where we get stuck at the lowest
transmission rate of a rate set (e.g. MCS 0) for some time, due to small
fluctuations in measured throughput at the lowest rate, which keep telling
us to "probe down" (while we're already at the lowest rate there is no way
to actually probe down).

Each time this happens we cancel the probing timeouts, so the "probe-up"
timeout doesn't get to run, and we may not try to probe to a higher rate
for a relatively long time, and our throughput stays lower than it could
perhaps be.

For consistency this diff also addresses the inverse issue of "probing up"
while we're already at the highest rate.

diff 14a1ca7807811e518898c39a278a89782a0362d8 
c3784c0ccfcd72ac91a3d2e413a283a25f088b56
blob - fbfd7148bd3e7d82eca9c0221203b64318d57d2f
blob + 4fdace1c4e65b2b2ecaebfd5d0a03d3b345eeacb
--- sys/net80211/ieee80211_mira.c
+++ sys/net80211/ieee80211_mira.c
@@ -1141,9 +1141,8 @@ ieee80211_mira_choose(struct ieee80211_mira_node *mn, 
 {
struct ieee80211_mira_goodput_stats *g = >g[ni->ni_txmcs];
int s;
-#ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING
int sgi = (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0;
-#endif
+   const struct ieee80211_ht_rateset *rs;
 
s = splnet();
 
@@ -1187,7 +1186,9 @@ ieee80211_mira_choose(struct ieee80211_mira_node *mn, 
}
 
/* Check if event-based probing should be triggered. */
-   if (g->measured < g->average - 2 * g->stddeviation) {
+   rs = ieee80211_mira_get_rateset(ni->ni_txmcs, sgi);
+   if (g->measured < g->average - 2 * g->stddeviation &&
+   ni->ni_txmcs != rs->min_mcs) {
/* Channel becomes bad. Probe downwards. */
DPRINTFN(2, ("channel becomes bad; probe downwards\n"));
DPRINTFN(3, ("measured: %s Mbit/s\n",
@@ -1208,7 +1209,8 @@ ieee80211_mira_choose(struct ieee80211_mira_node *mn, 
(1 << ieee80211_mira_next_lower_intra_rate(mn, ni));
 #endif
ieee80211_mira_cancel_timeouts(mn);
-   } else if (g->measured > g->average + 2 * g->stddeviation) {
+   } else if (g->measured > g->average + 2 * g->stddeviation &&
+   ni->ni_txmcs != rs->max_mcs) {
/* Channel becomes good. */
DPRINTFN(2, ("channel becomes good; probe upwards\n"));
DPRINTFN(3, ("measured: %s Mbit/s\n",



net80211: mira probing interval fix

2020-04-09 Thread Stefan Sperling
This seems to be a more accurate interpretation of the MiRA paper (a link
to paper can be found at the top of the ieee80211_mira.h header file).
I see a slight stabilization of Tx throughput with the change.

MiRA's rate probe interval is computed based on the number of frames sent,
and perhaps lost, during a probe attempt to another Tx rate.

If we saw no loss during our probe attempt the new interval will be small so
the rate may be probed again soon. If we saw high packet loss the new interval
will be larger (up to about 20 seconds) in order to reduce packet loss caused
by probing.

The paper says the probe interval for a rate needs to be updated if the rate's
goodput is worse than that of the "current transmission rate" (see the
"Adaptive probing interval" section). Our implementation interpreted
"current transmission rate" as "rate being probed right now" and adjusted
the interval of the previously probed rate. However, the context of this
section of the paper suggests that "current transmissions rate" intends to
refer to the currently selected best rate for our non-probing transmissions.
At least that's what I believe after having re-read the section a few times...

With this diff we update the probing interval of any rate which has been
probed and has lost against the best rate. As before, the interval of a
rate is reset to the minimum if it gets chosen as the best rate.

Note that there are two ways probing can be triggered, and the probe interval
is just one of those two. The other trigger is a significant change in measured
throughput (which happens when e.g. a laptop moves further from the AP, and we
start probing down). This other probing trigger is unaffected.
 

diff 25e76d314b84a6d0b1c697db14f987e4ad0a9520 
14a1ca7807811e518898c39a278a89782a0362d8
blob - 15b2250fc3701a48824bc0c5772586c30e19e85a
blob + fbfd7148bd3e7d82eca9c0221203b64318d57d2f
--- sys/net80211/ieee80211_mira.c
+++ sys/net80211/ieee80211_mira.c
@@ -73,7 +73,7 @@ int   ieee80211_mira_inter_mode_ra_finished(
struct ieee80211_mira_node *, struct ieee80211_node *);
 intieee80211_mira_best_rate(struct ieee80211_mira_node *,
struct ieee80211_node *);
-void   ieee80211_mira_update_probe_interval(struct ieee80211_mira_node *,
+void   ieee80211_mira_update_probe_interval(
struct ieee80211_mira_goodput_stats *);
 void   ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *,
struct ieee80211_node *);
@@ -735,6 +735,19 @@ ieee80211_mira_probe_valid(struct ieee80211_mira_node 
 void
 ieee80211_mira_probe_done(struct ieee80211_mira_node *mn)
 {
+   int mcs;
+
+   /* Reset probe interval of the best rate. */
+   mn->g[mn->best_mcs].probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN;
+   mn->g[mn->best_mcs].nprobes = 0;
+   mn->g[mn->best_mcs].nprobe_bytes = 0;
+
+   /* Update probing interval of other probed rates. */
+   for (mcs = 0; mcs < IEEE80211_HT_RATESET_NUM_MCS; mcs++) {
+   if (mcs != mn->best_mcs && (mn->probed_rates & (1 << mcs)))
+   ieee80211_mira_update_probe_interval(>g[mcs]);
+   }
+
ieee80211_mira_cancel_timeouts(mn);
ieee80211_mira_reset_driver_stats(mn);
ieee80211_mira_reset_collision_stats(mn);
@@ -871,8 +884,7 @@ ieee80211_mira_best_rate(struct ieee80211_mira_node *m
 
 /* See section 5.1.1 (at "Adaptive probing interval") in MiRA paper. */
 void
-ieee80211_mira_update_probe_interval(struct ieee80211_mira_node *mn,
-struct ieee80211_mira_goodput_stats *g)
+ieee80211_mira_update_probe_interval(struct ieee80211_mira_goodput_stats *g)
 {
uint64_t lt;
int intval;
@@ -971,17 +983,6 @@ void
 ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *mn,
 struct ieee80211_node *ni)
 {
-   struct ieee80211_mira_goodput_stats *gprev, *g;
-   int prev_mcs;
-
-   prev_mcs = ieee80211_mira_prev_mcs(mn, ni);
-   gprev = >g[prev_mcs];
-   g = >g[ni->ni_txmcs];
-   /* If the previous rate was worse, increase its probing interval. */
-   if (prev_mcs != ni->ni_txmcs &&
-   gprev->measured + IEEE80211_MIRA_RATE_THRESHOLD < g->measured)
-   ieee80211_mira_update_probe_interval(mn, gprev);
-
/* Select the next rate to probe. */
mn->probed_rates |= (1 << ni->ni_txmcs);
ni->ni_txmcs = ieee80211_mira_next_mcs(mn, ni);
@@ -1165,16 +1166,9 @@ ieee80211_mira_choose(struct ieee80211_mira_node *mn, 
DPRINTFN(4, ("probing MCS %d\n", ni->ni_txmcs));
} else if (ieee80211_mira_inter_mode_ra_finished(mn, ni)) {
int best = ieee80211_mira_best_rate(mn, ni);
-   if (mn->best_mcs != best) {
+   if (mn->best_mcs != best)
mn->best_mcs = best;
-   ni->ni_txmcs = best;
-   /* Reset probe interval for new best rate. */
-  

Re: Include /var/www/tmp into base install

2020-04-07 Thread Stefan Sperling
On Tue, Apr 07, 2020 at 06:13:12PM +0200, Stefan Sperling wrote:
> For temp stuff we really need a separate space that can just be wiped
> without consequences when it has run full.

The way Got internally provides access to files in /tmp for every helper
process is to pass one or more open file descriptors for files in /tmp
from the main process to the helper process. The helper doesn't have any
direct filesystem access. Of course it could fill up /tmp with this one
file, but not /var.

It would be nice if e.g. slowcgi could provide something like that.
At present gotweb uses /var/www/got/tmp instead of /tmp because its
main process runs in /var/www chroot via slowcgi.



Re: Include /var/www/tmp into base install

2020-04-07 Thread Stefan Sperling
On Tue, Apr 07, 2020 at 05:05:08PM +0100, Stuart Henderson wrote:
> On 2020/04/07 18:01, Stefan Sperling wrote:
> > Yes, absolutely correct. Logs or tempfiles filling up /var are a problem,
> > and in the gotweb application Tracey and I created it is indeed possible
> > for requests to trigger large tempfiles. We need to look at that and come
> > up with a better solution.
> > We could check whether httpd/slowcgi could help with this somehow and try
> > to come up with something that works for any application and not just ours.
> > 
> 
> fwiw my usual approach is to put /var/www on a separate filesystem ..

I had that in mind, too. But then you can still fill up that partition,
and in gotweb's case it has Git repositories which also freak out in
various ways if you run them out of disk.
So it doesn't solve the problem from the application's point of view.
Like regular /var, these repositories always need some breathing room.

For temp stuff we really need a separate space that can just be wiped
without consequences when it has run full.



Re: Include /var/www/tmp into base install

2020-04-07 Thread Stefan Sperling
On Tue, Apr 07, 2020 at 09:51:15AM -0600, Theo de Raadt wrote:
> Stefan Sperling  wrote:
> 
> > On Tue, Apr 07, 2020 at 09:37:02AM -0600, Theo de Raadt wrote:
> > > > The idea was to have /var/www/tmp created by default, but with
> > > > www:www ownership.
> >  
> > > Create the directory.  Now as a user, completely fill it.
> > 
> > The proposal is to create tmp with www:www ownership, writable only for
> > that user, not like the old /var/tmp which was writable by anyone.
> 
> That's not true; the diff created it mode 1777.

Ah, I missed that. Yes that would be a problem in the diff.

> A smaller secondary concern is if you can convince software using this space,
> from remote, to hog the space too much, and/or lose track of files in there.
> Which would also create the fallout problems of "/var is full".
> 
> It's a matter of how other /var-using software misbehaves or fails in
> those circumstances.  These concerns have been ignored too long.

Yes, absolutely correct. Logs or tempfiles filling up /var are a problem,
and in the gotweb application Tracey and I created it is indeed possible
for requests to trigger large tempfiles. We need to look at that and come
up with a better solution.
We could check whether httpd/slowcgi could help with this somehow and try
to come up with something that works for any application and not just ours.



Re: Include /var/www/tmp into base install

2020-04-07 Thread Stefan Sperling
On Tue, Apr 07, 2020 at 09:37:02AM -0600, Theo de Raadt wrote:
> > The idea was to have /var/www/tmp created by default, but with
> > www:www ownership.
 
> Create the directory.  Now as a user, completely fill it.

The proposal is to create tmp with www:www ownership, writable only for
that user, not like the old /var/tmp which was writable by anyone.

Currently ports create per-application temp directories for this purpose
when they get installed. I think this is fine and helps to keep unrelated
things apart, so I don't see a reason to create a global 'www:www' tmp
unless it helps ports sigificantly.



fix wifi media: line during background scan

2020-04-07 Thread Stefan Sperling
I've noticed that wireless interfaces in 11n mode show a "media:" line
in ifconfig such as this while a background scan is in progress:

 media: IEEE802.11 autoselect (OFDM6)

What is expected is a line showing active 11n mode, such as:

 media: IEEE802.11 autoselect (HT-MCS0 mode 11n)

This happens because ieee80211_media_status() sees ic->ic_curmode as
AUTO during background scans. Also, because net80211 forgets to reset
ic_curmode back to MODE_11N when the background scan has finished, the
displayed mode remains "autoselect (OFDM6)" until the interface is reset.

This is just a cosmetic issue.
Internally, the interface operates in 11n mode regardless.

ok?

diff 5e4be56314753be1a3ad288aa6b16bcb5257b37c /usr/src
blob - 410c33358e72c4063f9f71bf69f6c72ecfc558d9
file + sys/net80211/ieee80211.c
--- sys/net80211/ieee80211.c
+++ sys/net80211/ieee80211.c
@@ -728,6 +728,9 @@ ieee80211_media_status(struct ifnet *ifp, struct ifmed
ic->ic_curmode == IEEE80211_MODE_11AC)
imr->ifm_active |= ieee80211_mcs2media(ic,
ni->ni_txmcs, ic->ic_curmode);
+   else if (ni->ni_flags & IEEE80211_NODE_HT) /* in MODE_AUTO */
+   imr->ifm_active |= ieee80211_mcs2media(ic,
+   ni->ni_txmcs, IEEE80211_MODE_11N);
else
/* calculate rate subtype */
imr->ifm_active |= ieee80211_rate2media(ic,
blob - 6656d29d160c26dce86fb44e3f5e715e42b7c42c
file + sys/net80211/ieee80211_node.c
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -1441,6 +1441,19 @@ ieee80211_end_scan(struct ifnet *ifp)
ic->ic_bgscan_fail *= 2;
}
ic->ic_flags &= ~IEEE80211_F_BGSCAN;
+
+   /*
+* HT is negotiated during association so we must use
+* ic_bss to check HT. The nodes tree was re-populated
+* during background scan and therefore selbs and curbs
+* may not carry HT information.
+*/
+   ni = ic->ic_bss;
+   if (ni->ni_flags & IEEE80211_NODE_HT)
+   ieee80211_setmode(ic, IEEE80211_MODE_11N);
+   else
+   ieee80211_setmode(ic,
+   ieee80211_chan2mode(ic, ni->ni_chan));
return;
}




Re: wi(4): tsleep(9) -> tsleep_nsec(9)

2020-04-06 Thread Stefan Sperling
On Mon, Apr 06, 2020 at 02:03:36PM -0500, Scott Cheloha wrote:
> Ticks to seconds.  Trivial.
> 
> ok?

ok stsp@

> Index: if_wi.c
> ===
> RCS file: /cvs/src/sys/dev/ic/if_wi.c,v
> retrieving revision 1.171
> diff -u -p -r1.171 if_wi.c
> --- if_wi.c   31 Dec 2019 10:05:32 -  1.171
> +++ if_wi.c   6 Apr 2020 18:29:33 -
> @@ -1865,8 +1865,8 @@ wi_ioctl(struct ifnet *ifp, u_long comma
>   timeout_add(>wi_scan_timeout, len);
>  
>   /* Let the userspace process wait for completion */
> - error = tsleep(>wi_scan_lock, PCATCH, "wiscan",
> - hz * IEEE80211_SCAN_TIMEOUT);
> + error = tsleep_nsec(>wi_scan_lock, PCATCH, "wiscan",
> + SEC_TO_NSEC(IEEE80211_SCAN_TIMEOUT));
>   break;
>   case SIOCG80211ALLNODES:
>   {
> 



Re: iwn: fix tx result reporting

2020-04-06 Thread Stefan Sperling
On Mon, Apr 06, 2020 at 05:02:00PM +0200, Stefan Sperling wrote:
> On Thu, Apr 02, 2020 at 03:52:11PM +0200, Stefan Sperling wrote:
> > While working on iwm Tx aggregation and revisiting some parts of MiRA,
> > I have noticed a rate-control problem in iwm and iwx (this also affects
> > iwn, but I am leaving that for later since iwn already does Tx aggregation
> > and requires a more elaborate fix).
> 
> Here is the corresponding diff for iwn(4).
> 
> Fixes an automatic Tx rate control issue in iwn(4).
> Same change as for iwm(4) and iwx(4), but also accounts for block ack.
> 
> Also fix this driver's handling of ic_fixed_mcs.

Block ack is hard :(
The previous diff had a bug in evaluating the block ack bitmap.

We must align our own block ack window with the current window used by
firmware before looking at bits in the ACK bitmap provided by firmware.
Otherwise ACK/non-ACK status could be associated with the wrong frames.

Fixed in this version.

diff refs/heads/master refs/heads/iwn
blob - 72e19d7e35646822faaed4f2ebd157297a8ec907
blob + b50cd5642bd70be70e8d6d70f70e665208c0
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -166,8 +166,8 @@ voidiwn_rx_statistics(struct iwn_softc *, 
struct iwn
 void   iwn_ampdu_txq_advance(struct iwn_softc *, struct iwn_tx_ring *,
int, int);
 void   iwn_ampdu_tx_done(struct iwn_softc *, struct iwn_tx_ring *,
-   struct iwn_rx_desc *, uint16_t, struct iwn_txagg_status *,
-   int, uint32_t);
+   struct iwn_rx_desc *, uint16_t, uint8_t, uint8_t, uint8_t,
+   int, uint32_t, struct iwn_txagg_status *);
 void   iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
 void   iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
@@ -176,7 +176,7 @@ voidiwn_tx_done_free_txdata(struct 
iwn_softc *,
struct iwn_tx_data *);
 void   iwn_clear_oactive(struct iwn_softc *, struct iwn_tx_ring *);
 void   iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
-   uint8_t, int, int, uint16_t);
+   uint8_t, uint8_t, int, int, uint16_t);
 void   iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
 void   iwn_notif_intr(struct iwn_softc *);
 void   iwn_wakeup_intr(struct iwn_softc *);
@@ -2259,6 +2259,7 @@ void
 iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
 struct iwn_rx_data *data)
 {
+   struct iwn_ops *ops = >ops;
struct iwn_compressed_ba *cba = (struct iwn_compressed_ba *)(desc + 1);
struct ieee80211com *ic = >sc_ic;
struct ieee80211_node *ni;
@@ -2268,6 +2269,9 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
uint16_t ssn, idx;
int qid;
 
+   if (ic->ic_state != IEEE80211_S_RUN)
+   return;
+
bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*cba),
BUS_DMASYNC_POSTREAD);
 
@@ -2282,47 +2286,76 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
return;
 
txq = >txq[qid];
-   ssn = le16toh(cba->ssn); /* BA window starting sequence number */
-   idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn);
 
/* Protect against a firmware bug where the queue/TID are off. */
if (qid != sc->first_agg_txq + cba->tid)
return;
-   /*
-* Update Tx rate statistics.
-*/
-   if (ic->ic_state == IEEE80211_S_RUN && cba->nframes_sent > 0) {
-   uint8_t nframes = cba->nframes_sent;
-   int read = txq->read;
-   wn->mn.agglen = 0;
-   wn->mn.ampdu_size = 0;
-   /* Add up the lengths of all frames before the window. */
-   while (nframes && read != idx) {
-   struct iwn_tx_data *txdata = >data[read];
-   wn->mn.agglen++;
-   wn->mn.ampdu_size += txdata->totlen + IEEE80211_CRC_LEN;
-   read = (read + 1) % IWN_TX_RING_COUNT;
-   nframes--;
-   }
-   wn->mn.frames += cba->nframes_sent;
-   /* If firmware reports a bogus ACK counter, fix it up. */
-   if (cba->nframes_acked > cba->nframes_sent)
-   cba->nframes_acked = cba->nframes_sent;
-   wn->mn.retries += cba->nframes_sent - cba->nframes_acked;
-   if (wn->mn.txfail > wn->mn.frames)
-   wn->mn.txfail = wn->mn.frames;
-   if (wn->mn.ampdu_size > 0)
-   ieee80211_mira_choose(>mn, ic, ni);
-   }
 
ba = >ni_tx_ba[cba->tid];
+

iwn: fix tx result reporting

2020-04-06 Thread Stefan Sperling
On Thu, Apr 02, 2020 at 03:52:11PM +0200, Stefan Sperling wrote:
> While working on iwm Tx aggregation and revisiting some parts of MiRA,
> I have noticed a rate-control problem in iwm and iwx (this also affects
> iwn, but I am leaving that for later since iwn already does Tx aggregation
> and requires a more elaborate fix).

Here is the corresponding diff for iwn(4).

Fixes an automatic Tx rate control issue in iwn(4).
Same change as for iwm(4) and iwx(4), but also accounts for block ack.

Also fix this driver's handling of ic_fixed_mcs.
 
diff 5c2ccc6893e39ccee38b5e7e6ecf6487be392b1e 
efc01515a309caa279d79c1a251c73cdbcc68bba
blob - 72e19d7e35646822faaed4f2ebd157297a8ec907
blob + 30a936bedb20e7958f73ee789e9aced79626e580
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -166,8 +166,8 @@ voidiwn_rx_statistics(struct iwn_softc *, 
struct iwn
 void   iwn_ampdu_txq_advance(struct iwn_softc *, struct iwn_tx_ring *,
int, int);
 void   iwn_ampdu_tx_done(struct iwn_softc *, struct iwn_tx_ring *,
-   struct iwn_rx_desc *, uint16_t, struct iwn_txagg_status *,
-   int, uint32_t);
+   struct iwn_rx_desc *, uint16_t, uint8_t, uint8_t, uint8_t,
+   int, uint32_t, struct iwn_txagg_status *);
 void   iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
 void   iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
@@ -176,7 +176,7 @@ voidiwn_tx_done_free_txdata(struct 
iwn_softc *,
struct iwn_tx_data *);
 void   iwn_clear_oactive(struct iwn_softc *, struct iwn_tx_ring *);
 void   iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
-   uint8_t, int, int, uint16_t);
+   uint8_t, uint8_t, int, int, uint16_t);
 void   iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
 void   iwn_notif_intr(struct iwn_softc *);
 void   iwn_wakeup_intr(struct iwn_softc *);
@@ -2259,6 +2259,7 @@ void
 iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
 struct iwn_rx_data *data)
 {
+   struct iwn_ops *ops = >ops;
struct iwn_compressed_ba *cba = (struct iwn_compressed_ba *)(desc + 1);
struct ieee80211com *ic = >sc_ic;
struct ieee80211_node *ni;
@@ -2268,6 +2269,9 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
uint16_t ssn, idx;
int qid;
 
+   if (ic->ic_state != IEEE80211_S_RUN)
+   return;
+
bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*cba),
BUS_DMASYNC_POSTREAD);
 
@@ -2282,41 +2286,66 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_
return;
 
txq = >txq[qid];
-   ssn = le16toh(cba->ssn); /* BA window starting sequence number */
-   idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn);
 
/* Protect against a firmware bug where the queue/TID are off. */
if (qid != sc->first_agg_txq + cba->tid)
return;
+
+   ba = >ni_tx_ba[cba->tid];
+   if (ba->ba_state != IEEE80211_BA_AGREED)
+   return;
+
/*
 * Update Tx rate statistics.
+* Skip rate control if our Tx rate is fixed.
 */
-   if (ic->ic_state == IEEE80211_S_RUN && cba->nframes_sent > 0) {
-   uint8_t nframes = cba->nframes_sent;
-   int read = txq->read;
+   if (ic->ic_fixed_mcs == -1 && cba->nframes_sent > 0) {
+   int end_idx = IWN_AGG_SSN_TO_TXQ_IDX(ba->ba_winend);
+   int bit = 0, nsent = cba->nframes_sent;
+
wn->mn.agglen = 0;
wn->mn.ampdu_size = 0;
-   /* Add up the lengths of all frames before the window. */
-   while (nframes && read != idx) {
-   struct iwn_tx_data *txdata = >data[read];
-   wn->mn.agglen++;
-   wn->mn.ampdu_size += txdata->totlen + IEEE80211_CRC_LEN;
-   read = (read + 1) % IWN_TX_RING_COUNT;
-   nframes--;
+
+   ssn = le16toh(ba->ba_winstart);
+   idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn);
+   while (nsent && idx != end_idx) {
+   struct iwn_tx_data *txdata = >data[idx];
+   int have_ack = (le64toh(cba->bitmap) & (1 << bit++));
+
+   if (txdata->m != NULL) {
+   /*
+* Don't report frames to MiRA which were sent
+* at a different Tx rate than ni->ni_txmcs.
+*/
+   if (txdata->actual_txmcs == ni->ni_txmcs) {
+ 

iwm/iwx: fix tx result reporting

2020-04-02 Thread Stefan Sperling
While working on iwm Tx aggregation and revisiting some parts of MiRA,
I have noticed a rate-control problem in iwm and iwx (this also affects
iwn, but I am leaving that for later since iwn already does Tx aggregation
and requires a more elaborate fix).

Rate control algorithms will choose a Tx rate and then gather feedback
from drivers on per-frame basis, with the assumption that feedback
provided by drivers is always based on frames which have been transmitted
at the most recently chosen rate.

During a transmit burst, e.g. while tcpbench is running, iwm and iwx will
queue up to 224 frames on the Tx ring (256 would fit, but our driver stops
queuing new frames after 224 have been queued; an easy way to tell whether
this condition has been reached is to check whether ifconfig reports the
OACTIVE interface flag).

The problem is that rate control will make decisions a lot more often than
just every 224 frames. Which means that results get reported and evaluated
even if they do not correspond to the most recently chosen rate, spoiling
the data available to the rate control algorithm.

This change prevents this problem by only reporting frames which match
the currently chosen Tx rate. Since the algorithms do not advance unless
their choose() function is called this effectively flushes out frames
queued at any previously chosen rates and restarts reporting as soon as
frames with the expected rate are being processed.

ok?

(I am also tweaking how iwx reports retries to AMRR; this is just to reduce
complexity and differences to iwm, and shouldn't make a big difference)

diff 144217ab9d3715f0cf6c417288c8a50500b221fa 
addfc4a92b67df7f2aa49c5af241e149413d0015
blob - 2dbd3cac8dc4eddb316034b37b5ce951868b019a
blob + c9d48475e122021d2738076c838a2d8ef03cf48b
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -336,7 +336,7 @@ voidiwx_rx_frame(struct iwx_softc *, struct mbuf *, 
i
struct ieee80211_rxinfo *, struct mbuf_list *);
 void   iwx_enable_ht_cck_fallback(struct iwx_softc *, struct iwx_node *);
 void   iwx_rx_tx_cmd_single(struct iwx_softc *, struct iwx_rx_packet *,
-   struct iwx_node *);
+   struct iwx_node *, int, int);
 void   iwx_rx_tx_cmd(struct iwx_softc *, struct iwx_rx_packet *,
struct iwx_rx_data *);
 void   iwx_rx_bmiss(struct iwx_softc *, struct iwx_rx_packet *,
@@ -3563,7 +3563,7 @@ iwx_enable_ht_cck_fallback(struct iwx_softc *sc, struc
 
 void
 iwx_rx_tx_cmd_single(struct iwx_softc *sc, struct iwx_rx_packet *pkt,
-struct iwx_node *in)
+struct iwx_node *in, int txmcs, int txrate)
 {
struct ieee80211com *ic = >sc_ic;
struct ieee80211_node *ni = >in_ni;
@@ -3577,19 +3577,23 @@ iwx_rx_tx_cmd_single(struct iwx_softc *sc, struct iwx_
txfail = (status != IWX_TX_STATUS_SUCCESS &&
status != IWX_TX_STATUS_DIRECT_DONE);
 
-   /* Update rate control statistics. */
+   /*
+* Update rate control statistics.
+* Only report frames which were actually queued with the currently
+* selected Tx rate. Because Tx queues are relatively long we may
+* encounter previously selected rates here during Tx bursts.
+* Providing feedback based on such frames can lead to suboptimal
+* Tx rate control decisions.
+*/
if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 || in->ht_force_cck) {
-   in->in_amn.amn_txcnt++;
-   if (in->ht_force_cck) {
-   /*
-* We want to move back to OFDM quickly if possible.
-* Only show actual Tx failures to AMRR, not retries.
-*/
+   if (txrate == ni->ni_txrate) {
+   in->in_amn.amn_txcnt++;
if (txfail)
in->in_amn.amn_retrycnt++;
-   } else if (tx_resp->failure_frame > 0)
-   in->in_amn.amn_retrycnt++;
-   } else if (ic->ic_fixed_mcs == -1) {
+   if (tx_resp->failure_frame > 0)
+   in->in_amn.amn_retrycnt++;
+   }
+   } else if (ic->ic_fixed_mcs == -1 && txmcs == ni->ni_txmcs) {
in->in_mn.frames += tx_resp->frame_count;
in->in_mn.ampdu_size = le16toh(tx_resp->byte_cnt);
in->in_mn.agglen = tx_resp->frame_count;
@@ -3650,7 +3654,7 @@ iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_pack
if (txd->m == NULL)
return;
 
-   iwx_rx_tx_cmd_single(sc, pkt, txd->in);
+   iwx_rx_tx_cmd_single(sc, pkt, txd->in, txd->txmcs, txd->txrate);
iwx_txd_done(sc, txd);
 
/*
@@ -4304,6 +4308,8 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ie
}
data->m = m;
data->in = in;
+   data->txmcs = ni->ni_txmcs;
+   data->txrate = ni->ni_txrate;
 
/* Fill TX descriptor. */
num_tbs = 2 + data->map->dm_nsegs;
blob - 

iwm: async firmware LQ updates

2020-03-30 Thread Stefan Sperling
The "link quality" (LQ) command for iwm firmware is used to tell the
firmware about our Tx rate selection decisions, among other things.

The driver currently avoids sending this command directly from interrupt
context. Instead it schedules a task which will send the command.

The driver usually defers to a task when it needs to wait for a
response to the command from the firmware, and runs in a context
where sleeping (i.e. waiting) isn't allowed.

The LQ command requires no actual response handling, and works just fine
when sent asynchrounously. So get rid of the task and just send the LQ
command directly from interrupt context.

This simplifies the driver a bit and means we have less potential delay
between our decision to use a new Tx rate and getting the firmware's
rate retry table updated for our new Tx rate.

ok?

diff 960b1fc5c6485d1b9e9fe9d73b34986dd0a3a942 
50417a34cf53a2cdd32a025c586789525bfa9d00
blob - c6963275801e8f8b962721bcd81fd3b1a541b46f (mode 644)
blob + cb582fd301f6a85569c578a83e49daeffa087724 (mode 600)
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -453,8 +453,7 @@ int iwm_run(struct iwm_softc *);
 intiwm_run_stop(struct iwm_softc *);
 struct ieee80211_node *iwm_node_alloc(struct ieee80211com *);
 void   iwm_calib_timeout(void *);
-void   iwm_setrates_task(void *);
-void   iwm_setrates(struct iwm_node *);
+void   iwm_setrates(struct iwm_node *, int);
 intiwm_media_change(struct ifnet *);
 void   iwm_newstate_task(void *);
 intiwm_newstate(struct ieee80211com *, enum ieee80211_state, int);
@@ -4206,7 +4205,7 @@ iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_
best_mcs = ieee80211_mira_get_best_mcs(>in_mn);
if (best_mcs != in->chosen_txmcs) {
in->chosen_txmcs = best_mcs;
-   iwm_add_task(sc, systq, >setrates_task);
+   iwm_setrates(in, 1);
}
 
/* Fall back to CCK rates if MCS 0 is failing. */
@@ -6736,7 +6735,7 @@ iwm_run(struct iwm_softc *sc)
in->in_ni.ni_txmcs = 0;
in->chosen_txrate = 0;
in->chosen_txmcs = 0;
-   iwm_setrates(in);
+   iwm_setrates(in, 0);
 
timeout_add_msec(>sc_calib_to, 500);
iwm_led_enable(sc);
@@ -6817,7 +6816,7 @@ iwm_calib_timeout(void *arg)
 */
if (ni->ni_txrate != in->chosen_txrate) {
in->chosen_txrate = ni->ni_txrate;
-   iwm_add_task(sc, systq, >setrates_task);
+   iwm_setrates(in, 1);
}
if (in->ht_force_cck) {
struct ieee80211_rateset *rs = >ni_rates;
@@ -6834,28 +6833,8 @@ iwm_calib_timeout(void *arg)
 }
 
 void
-iwm_setrates_task(void *arg)
+iwm_setrates(struct iwm_node *in, int async)
 {
-   struct iwm_softc *sc = arg;
-   struct ieee80211com *ic = >sc_ic;
-   struct iwm_node *in = (struct iwm_node *)ic->ic_bss;
-   int s = splnet();
-
-   if (sc->sc_flags & IWM_FLAG_SHUTDOWN) {
-   refcnt_rele_wake(>task_refs);
-   splx(s);
-   return;
-   }
-
-   /* Update rates table based on new TX rate determined by AMRR. */
-   iwm_setrates(in);
-   refcnt_rele_wake(>task_refs);
-   splx(s);
-}
-
-void
-iwm_setrates(struct iwm_node *in)
-{
struct ieee80211_node *ni = >in_ni;
struct ieee80211com *ic = ni->ni_ic;
struct iwm_softc *sc = IC2IFP(ic)->if_softc;
@@ -6867,6 +6846,8 @@ iwm_setrates(struct iwm_node *in)
.len = { sizeof(lqcmd), },
};
 
+   cmd.flags = async ? IWM_CMD_ASYNC : 0;
+
memset(, 0, sizeof(lqcmd));
lqcmd.sta_id = IWM_STATION_ID;
 
@@ -7111,7 +7092,6 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_s
ieee80211_mira_cancel_timeouts(>in_mn);
iwm_del_task(sc, systq, >ba_task);
iwm_del_task(sc, systq, >htprot_task);
-   iwm_del_task(sc, systq, >setrates_task);
}
 
sc->ns_nstate = nstate;
@@ -7885,7 +7865,6 @@ iwm_stop(struct ifnet *ifp)
/* Cancel scheduled tasks and let any stale tasks finish up. */
task_del(systq, >init_task);
iwm_del_task(sc, sc->sc_nswq, >newstate_task);
-   iwm_del_task(sc, systq, >setrates_task);
iwm_del_task(sc, systq, >ba_task);
iwm_del_task(sc, systq, >htprot_task);
KASSERT(sc->task_refs.refs >= 1);
@@ -9313,7 +9292,6 @@ iwm_attach(struct device *parent, struct device *self,
timeout_set(>sc_led_blink_to, iwm_led_blink_timeout, sc);
task_set(>init_task, iwm_init_task, sc);
task_set(>newstate_task, iwm_newstate_task, sc);
-   task_set(>setrates_task, iwm_setrates_task, sc);
task_set(>ba_task, iwm_ba_task, sc);
task_set(>htprot_task, iwm_htprot_task, sc);
 
blob - ec579e3f75095d6c28ea14293bd75d257971c66f
blob + 

iwm(4): fix mimo

2020-03-30 Thread Stefan Sperling
I noticed that iwm's firmware skips MIMO rates on Tx and sends frames
at the lowest fallback rate instead.

This is not visible in ifconfig or even net80211. Everything there
indicates that we were using some MCS >= 8 and all was good.

But tcpbench is much slower than it should be, and monitor mode
reveals that all frames are sent on the air with the lowest rate,
e.g. 6Mbit/s on 5 GHz.

This happens because new firmware requires flags to be set in order
to enable MIMO rates for a peer, and we don't set those flags yet.

I have also found that one of my APs advertises its supported HT rates
quite late (in the assoc response, rather than the auth response),
and that iwm doesn't pick this up yet. Applying just the first hunk
isn't enough to fix the problem with that AP. We need to give the
firmware latest info about our AP in iwm_run() as well.  

ok?
 
diff 960b1fc5c6485d1b9e9fe9d73b34986dd0a3a942 
afc0cb751528613b0fea93e24aee4f4f3a0aa9f7
blob - c6963275801e8f8b962721bcd81fd3b1a541b46f (mode 644)
blob + d2395389096f3181ff9503e07a4b9541783ab9af (mode 600)
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -5286,6 +5286,17 @@ iwm_add_sta_cmd(struct iwm_softc *sc, struct iwm_node 
|= htole32(IWM_STA_FLG_MAX_AGG_SIZE_MSK |
IWM_STA_FLG_AGG_MPDU_DENS_MSK);
 
+   if (!sc->sc_nvm.sku_cap_mimo_disable) {
+   if (in->in_ni.ni_rxmcs[1] != 0) {
+   add_sta_cmd.station_flags |=
+   htole32(IWM_STA_FLG_MIMO_EN_MIMO2);
+   }
+   if (in->in_ni.ni_rxmcs[2] != 0) {
+   add_sta_cmd.station_flags |=
+   htole32(IWM_STA_FLG_MIMO_EN_MIMO3);
+   }
+   }
+
add_sta_cmd.station_flags
|= htole32(IWM_STA_FLG_MAX_AGG_SIZE_64K);
switch (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_SS) {
@@ -6667,6 +6678,14 @@ iwm_run(struct iwm_softc *sc)
DEVNAME(sc));
return err;
}
+   }
+
+   /* Update STA again, for HT-related settings such as MIMO. */
+   err = iwm_add_sta_cmd(sc, in, 1);
+   if (err) {
+   printf("%s: could not update STA (error %d)\n",
+   DEVNAME(sc), err);
+   return err;
}
 
/* We have now been assigned an associd by the AP. */



Re: softraid_raid5: possible NULL dereference

2020-03-26 Thread Stefan Sperling
On Thu, Mar 26, 2020 at 01:03:26AM +0100, Tobias Heider wrote:
> sr_block_get() returns dma_alloc(length, PR_NOWAIT | PR_ZERO) which may be
> NULL if the memory pool is depleted.
> The result is used as 'dst' argument to memcpy() in the following call to
> sr_raid5_regenerate(), resulting in a possible NULL dereference.
> 
> ok?
> 
> Index: softraid_raid5.c
> ===
> RCS file: /mount/openbsd/cvs/src/sys/dev/softraid_raid5.c,v
> retrieving revision 1.29
> diff -u -p -r1.29 softraid_raid5.c
> --- softraid_raid5.c  8 Aug 2019 02:19:55 -   1.29
> +++ softraid_raid5.c  25 Mar 2020 23:54:25 -
> @@ -818,7 +818,8 @@ sr_raid5_rebuild(struct sr_discipline *s
>   wu_w = sr_scsi_wu_get(sd, 0);
>   wu_r = sr_scsi_wu_get(sd, 0);
>  
> - xorbuf = sr_block_get(sd, strip_size);
> + if ((xorbuf = sr_block_get(sd, strip_size)) == NULL)
> + goto bad;
>   if (sr_raid5_regenerate(wu_r, rebuild_chunk, chunk_lba,
>   strip_size, xorbuf))
>   goto bad;
> 

Obvious fix. ok stsp@

Same problem is present in sr_raid5_scrub() which is currently in #if 0.



Re: acpitoshiba: remove dead code

2020-03-16 Thread Stefan Sperling
On Mon, Mar 16, 2020 at 09:29:43AM +0100, Jasper Lievisse Adriaanse wrote:
> Hi,
> 
> The type of brightness and video_output is uint32_t; therefore it
> can never be less than 0 (which is what HCI_LCD_BRIGHTNESS_MIN and
> HCI_VIDEO_OUTPUT_CYCLE_MIN are defined to). So trim the checks by
> removig the impossible cases.
> 
> Coverity CID 1453109, 1453169
> 
> OK?

These values ultimately come from aml_val2int() which returns int64_t,
i.e. a signed value. This driver currently copies that value to a uint32_t,
shifts it, and this shifted value ends up being copied to an int, and then
again to a uint32_t, which is then range-checked.
I don't understand why a range check is done only that late in the game,
after multiple integer type conversions that seem to be performed for no
good reason other than that the expected range will fit into an int.

So an alternative fix could be to switch brightness values in this
driver to int64_t everywhere, i.e. in toshiba_get_brightness(),
toshiba_find_brightness(), toshiba_set_brightness(), etc.
Then you can keep all the code as it is.

Or read an int64_t with aml_val2int(), shift and range-check it right away,
and only convert to a narrower type if the value is in the expected range.
Else error.

> Index: acpi/acpitoshiba.c
> ===
> RCS file: /cvs/src/sys/dev/acpi/acpitoshiba.c,v
> retrieving revision 1.12
> diff -u -p -r1.12 acpitoshiba.c
> --- acpi/acpitoshiba.c13 Oct 2019 10:56:31 -  1.12
> +++ acpi/acpitoshiba.c11 Mar 2020 11:35:23 -
> @@ -438,9 +438,8 @@ toshiba_set_brightness(struct acpitoshib
>   for (i = 0; i < HCI_WORDS; ++i)
>   args[i].type = AML_OBJTYPE_INTEGER;
>  
> - if ((*brightness < HCI_LCD_BRIGHTNESS_MIN) ||
> - (*brightness > HCI_LCD_BRIGHTNESS_MAX))
> -return (HCI_FAILURE);
> + if (*brightness > HCI_LCD_BRIGHTNESS_MAX)
> + return (HCI_FAILURE);
>  
>   *brightness <<= HCI_LCD_BRIGHTNESS_SHIFT;
>  
> @@ -534,8 +533,7 @@ toshiba_set_video_output(struct acpitosh
>  
>   bzero(args, sizeof(args));
>  
> - if ((*video_output < HCI_VIDEO_OUTPUT_CYCLE_MIN) ||
> - (*video_output > HCI_VIDEO_OUTPUT_CYCLE_MAX))
> + if (*video_output > HCI_VIDEO_OUTPUT_CYCLE_MAX)
>   return (HCI_FAILURE);
>  
>   *video_output |= HCI_VIDEO_OUTPUT_FLAG;
> -- 
> jasper
> 
> 



net80211: properly wrap sequence numbers on increment

2020-03-06 Thread Stefan Sperling
802.11 frame sequence numbers are in the range 0x0 - 0xfff.

Don't let internal representations of sequence numbers grow beyond 0xfff.

ok?

diff 582540bcd55abf4efa3abe8c23ebc7f3c247245d 
ba499e0f51b139f9ad6d4b4ea18cbf56bd93
blob - 808b6e1f46b777ea408561c0fbf511e79d477c54
blob + 6c8057426973640ab03af4ec061adfa1d3c695bf
--- sys/net80211/ieee80211_output.c
+++ sys/net80211/ieee80211_output.c
@@ -190,7 +190,7 @@ ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80
*(u_int16_t *)>i_dur[0] = 0;
*(u_int16_t *)>i_seq[0] =
htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
-   ni->ni_txseq++;
+   ni->ni_txseq = (ni->ni_txseq + 1) & 0xfff;
IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
@@ -623,11 +623,11 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, str
*(u_int16_t *)qwh->i_qos = htole16(qos);
*(u_int16_t *)qwh->i_seq =
htole16(ni->ni_qos_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
-   ni->ni_qos_txseqs[tid]++;
+   ni->ni_qos_txseqs[tid] = (ni->ni_qos_txseqs[tid] + 1) & 0xfff;
} else {
*(u_int16_t *)>i_seq[0] =
htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
-   ni->ni_txseq++;
+   ni->ni_txseq = (ni->ni_txseq + 1) & 0xfff;
}
switch (ic->ic_opmode) {
case IEEE80211_M_STA:



  1   2   3   4   5   6   7   8   9   10   >