Re: I got the RALINK RT5372 usb wifi adapter working

2022-05-10 Thread Stefan Sperling
On Mon, May 09, 2022 at 08:17:35PM +, molotov31337 wrote:
> I recently picked up a Panda Wireless PAU06 and got it working, can this be 
> committed?
> Here is the cvs diff

Committed, thanks!

> Index: usbdevs
> ===
> RCS file: /cvs/src/sys/dev/usb/usbdevs,v
> retrieving revision 1.745
> diff -u -p -u -r1.745 usbdevs
> --- usbdevs 24 Dec 2021 06:18:11 - 1.745
> +++ usbdevs 9 May 2022 20:12:42 -
> @@ -3731,6 +3731,7 @@ product RALINK RT3370 0x3370 RT3370
> product RALINK RT3572 0x3572 RT3572
> product RALINK RT3573 0x3573 RT3573
> product RALINK RT5370 0x5370 RT5370
> +product RALINK RT5372 0x5372 RT5372
> product RALINK RT5572 0x5572 RT5572
> product RALINK MT7601 0x7601 MT7601
> product RALINK MT7601_2 0x760a MT7601
> Index: if_run.c
> ===
> RCS file: /cvs/src/sys/dev/usb/if_run.c,v
> retrieving revision 1.135
> diff -u -p -u -r1.135 if_run.c
> --- if_run.c 22 Nov 2021 10:17:14 - 1.135
> +++ if_run.c 9 May 2022 20:12:43 -
> @@ -259,6 +259,7 @@ static const struct usb_devno run_devs[]
> USB_ID(RALINK, RT3572),
> USB_ID(RALINK, RT3573),
> USB_ID(RALINK, RT5370),
> + USB_ID(RALINK, RT5372),
> USB_ID(RALINK, RT5572),
> USB_ID(RALINK, RT8070), USB_ID(SAMSUNG, WIS09ABGN),
> 
> And the device shows up in dmesg as
> run0 at uhub0 port 4 configuration 1 interface 0 "Ralink 802.11 n WLAN" rev 
> 2.00/1.01 addr 2
> run0: MAC/BBP RT5392 (rev 0x0223), RF RT5372 (MIMO 2T2R), address 
> 9c:ef:d5:fa:4b:15
> 
> Sent with [ProtonMail](https://protonmail.com/) secure email.



fix mac address on iwx(4) AX210

2022-05-10 Thread Stefan Sperling
As noticed by jsg@ and kevlo@ we use a bad MAC address on AX210 devices.
Patch below fixes the issue on AX210, and still works on AX200.

The old way of reading the MAC no longer works on AX210; apparently this
new way of reading the MAC was introduced in the 9k hw generation but the
old way was still working until now.

ok?

diff 04382ee86a01509dce834178b7ab1460d3539207 
37ed6bbfb5c966e24cc7dbbe8dd40222aac69407
blob - b3ea3675ae9dc65b56a1c90ab7f92c1c0a4f3a8f
blob + 9e94f17a9fc41ca7c3ce1096497ccc478f958197
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -341,8 +341,9 @@ voidiwx_sta_tx_agg_start(struct iwx_softc *, struct 
i
uint8_t);
 void   iwx_ba_task(void *);
 
-intiwx_set_mac_addr_from_csr(struct iwx_softc *, struct iwx_nvm_data *);
+void   iwx_set_mac_addr_from_csr(struct iwx_softc *, struct iwx_nvm_data *);
 intiwx_is_valid_mac_addr(const uint8_t *);
+void   iwx_flip_hw_address(uint32_t, uint32_t, uint8_t *);
 intiwx_nvm_get(struct iwx_softc *);
 intiwx_load_firmware(struct iwx_softc *);
 intiwx_start_fw(struct iwx_softc *);
@@ -3688,31 +3689,33 @@ iwx_ampdu_tx_start(struct ieee80211com *ic, struct iee
return EBUSY;
 }
 
-/* Read the mac address from WFMP registers. */
-int
+void
 iwx_set_mac_addr_from_csr(struct iwx_softc *sc, struct iwx_nvm_data *data)
 {
-   const uint8_t *hw_addr;
uint32_t mac_addr0, mac_addr1;
 
+   memset(data->hw_addr, 0, sizeof(data->hw_addr));
+
if (!iwx_nic_lock(sc))
-   return EBUSY;
+   return;
 
-   mac_addr0 = htole32(iwx_read_prph(sc, IWX_WFMP_MAC_ADDR_0));
-   mac_addr1 = htole32(iwx_read_prph(sc, IWX_WFMP_MAC_ADDR_1));
+   mac_addr0 = htole32(IWX_READ(sc, IWX_CSR_MAC_ADDR0_STRAP(sc)));
+   mac_addr1 = htole32(IWX_READ(sc, IWX_CSR_MAC_ADDR1_STRAP(sc)));
 
-   hw_addr = (const uint8_t *)_addr0;
-   data->hw_addr[0] = hw_addr[3];
-   data->hw_addr[1] = hw_addr[2];
-   data->hw_addr[2] = hw_addr[1];
-   data->hw_addr[3] = hw_addr[0];
+   iwx_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
 
-   hw_addr = (const uint8_t *)_addr1;
-   data->hw_addr[4] = hw_addr[1];
-   data->hw_addr[5] = hw_addr[0];
+   /* If OEM fused a valid address, use it instead of the one in OTP. */
+   if (iwx_is_valid_mac_addr(data->hw_addr)) {
+   iwx_nic_unlock(sc);
+   return;
+   }
 
+   mac_addr0 = htole32(IWX_READ(sc, IWX_CSR_MAC_ADDR0_OTP(sc)));
+   mac_addr1 = htole32(IWX_READ(sc, IWX_CSR_MAC_ADDR1_OTP(sc)));
+
+   iwx_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
+
iwx_nic_unlock(sc);
-   return 0;
 }
 
 int
@@ -3728,6 +3731,22 @@ iwx_is_valid_mac_addr(const uint8_t *addr)
!ETHER_IS_MULTICAST(addr));
 }
 
+void
+iwx_flip_hw_address(uint32_t mac_addr0, uint32_t mac_addr1, uint8_t *dest)
+{
+   const uint8_t *hw_addr;
+
+   hw_addr = (const uint8_t *)_addr0;
+   dest[0] = hw_addr[3];
+   dest[1] = hw_addr[2];
+   dest[2] = hw_addr[1];
+   dest[3] = hw_addr[0];
+
+   hw_addr = (const uint8_t *)_addr1;
+   dest[4] = hw_addr[1];
+   dest[5] = hw_addr[0];
+}
+
 int
 iwx_nvm_get(struct iwx_softc *sc)
 {
@@ -10654,6 +10673,8 @@ iwx_attach(struct device *parent, struct device *self,
}
}
 
+   sc->mac_addr_from_csr = 0x380; /* differs on BZ hw generation */
+
if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210) {
sc->sc_umac_prph_offset = 0x30;
sc->max_tfd_queue_size = IWX_TFD_QUEUE_SIZE_MAX_GEN3;
blob - 6ddfb14e5eb9240cc82ea07d12a6e5c846167586
blob + 0f1948913a39bee6956603e3e322b9961615f038
--- sys/dev/pci/if_iwxreg.h
+++ sys/dev/pci/if_iwxreg.h
@@ -1160,6 +1160,12 @@ enum msix_ivar_for_cause {
 #define IWX_MSIX_AUTO_CLEAR_CAUSE  (0 << 7)
 #define IWX_MSIX_NON_AUTO_CLEAR_CAUSE  (1 << 7)
 
+#define IWX_CSR_ADDR_BASE(sc)  ((sc)->mac_addr_from_csr)
+#define IWX_CSR_MAC_ADDR0_OTP(sc)  (IWX_CSR_ADDR_BASE(sc) + 0x00)
+#define IWX_CSR_MAC_ADDR1_OTP(sc)  (IWX_CSR_ADDR_BASE(sc) + 0x04)
+#define IWX_CSR_MAC_ADDR0_STRAP(sc)(IWX_CSR_ADDR_BASE(sc) + 0x08)
+#define IWX_CSR_MAC_ADDR1_STRAP(sc)(IWX_CSR_ADDR_BASE(sc) + 0x0c)
+
 /**
  * uCode API flags
  * @IWX_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously
blob - bec0758d890fb5939a291ed794a610f9e5ac37df
blob + 19f9a333d1a1e479845512439daaef8adc164ca4
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -681,6 +681,7 @@ struct iwx_softc {
 #define IWX_DEVICE_FAMILY_220001
 #define IWX_DEVICE_FAMILY_AX2102
uint32_t sc_sku_id[3];
+   uint32_t mac_addr_from_csr;
 
struct iwx_dma_info ctxt_info_dma;
struct iwx_self_init_dram init_dram;



add support for AX210/AX211 devices to iwx(4)

2022-05-09 Thread Stefan Sperling
This patch adds support for AX210/AX211 devices to iwx(4).

While this patch attempts to make a couple of devices work which
are part of this device family, so far only one specific AX210
device has been tested:

iwx0 at pci4 dev 0 function 0 "Intel Wi-Fi 6 AX210" rev 0x1a, msix
iwx0: hw rev 0x420, fw 67.8f59b80b.0, pnvm dda57f4f, address ba:d0:f1:95:2b:a0

Problems are not entirely unexpected when testing on other devices.
Hopefully, any AX210/AX211 devices will work. But since several variants
of firmware are involved and each firmware variant requires a specific
device, I cannot test everything by myself.
If your device is not working please enable 'ifconfig iwx0 debug' and
include the additional information this prints to /var/log/messages
in your test report.

I have tested this patch on AX200 and AX201 devices as well. I do not
see any regressions but additional testing would be welcome.

AX210 device firmware is already available via fw_update.
The required firmware package version is iwx-firmware-20220110.

Please update your tree before applying this patch. I made a commit
to sys/dev/pci/pcidevs earlier today which this patch depends on.
It will fail to compile otherwise.

diff 9d011d1bb76b879a432878d921f2f89e1153b973 refs/heads/ax210
blob - ba8e3352346b081628ac1b4999fc7681b48eb695
blob + cad4b806a5bb3626af3b395da4ab8bd55f8cd17f
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -175,6 +175,7 @@ static const uint8_t iwx_nvm_channels_uhb[] = {
 };
 
 #define IWX_NUM_2GHZ_CHANNELS  14
+#define IWX_NUM_5GHZ_CHANNELS  37
 
 const struct iwx_rate {
uint16_t rate;
@@ -239,7 +240,10 @@ intiwx_store_cscheme(struct iwx_softc *, uint8_t 
*, s
 intiwx_alloc_fw_monitor_block(struct iwx_softc *, uint8_t, uint8_t);
 intiwx_alloc_fw_monitor(struct iwx_softc *, uint8_t);
 intiwx_apply_debug_destination(struct iwx_softc *);
+void   iwx_set_ltr(struct iwx_softc *);
 intiwx_ctxt_info_init(struct iwx_softc *, const struct iwx_fw_sects *);
+intiwx_ctxt_info_gen3_init(struct iwx_softc *,
+   const struct iwx_fw_sects *);
 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 *,
@@ -250,10 +254,15 @@ int   iwx_firmware_store_section(struct iwx_softc *, 
enu
 intiwx_set_default_calib(struct iwx_softc *, const void *);
 void   iwx_fw_info_free(struct iwx_fw_info *);
 intiwx_read_firmware(struct iwx_softc *);
+uint32_t iwx_prph_addr_mask(struct iwx_softc *);
 uint32_t iwx_read_prph_unlocked(struct iwx_softc *, uint32_t);
 uint32_t iwx_read_prph(struct iwx_softc *, uint32_t);
 void   iwx_write_prph_unlocked(struct iwx_softc *, uint32_t, uint32_t);
 void   iwx_write_prph(struct iwx_softc *, uint32_t, uint32_t);
+uint32_t iwx_read_umac_prph_unlocked(struct iwx_softc *, uint32_t);
+uint32_t iwx_read_umac_prph(struct iwx_softc *, uint32_t);
+void   iwx_write_umac_prph_unlocked(struct iwx_softc *, uint32_t, uint32_t);
+void   iwx_write_umac_prph(struct iwx_softc *, uint32_t, uint32_t);
 intiwx_read_mem(struct iwx_softc *, uint32_t, void *, int);
 intiwx_write_mem(struct iwx_softc *, uint32_t, const void *, int);
 intiwx_write_mem32(struct iwx_softc *, uint32_t, uint32_t);
@@ -337,6 +346,10 @@ intiwx_is_valid_mac_addr(const uint8_t *);
 intiwx_nvm_get(struct iwx_softc *);
 intiwx_load_firmware(struct iwx_softc *);
 intiwx_start_fw(struct iwx_softc *);
+intiwx_pnvm_handle_section(struct iwx_softc *, const uint8_t *, size_t);
+intiwx_pnvm_parse(struct iwx_softc *, const uint8_t *, size_t);
+void   iwx_ctxt_info_gen3_set_pnvm(struct iwx_softc *);
+intiwx_load_pnvm(struct iwx_softc *);
 intiwx_send_tx_ant_cfg(struct iwx_softc *, uint8_t);
 intiwx_send_phy_cfg_cmd(struct iwx_softc *);
 intiwx_load_ucode_wait_alive(struct iwx_softc *);
@@ -357,7 +370,7 @@ voidiwx_rx_frame(struct iwx_softc *, struct mbuf *, 
i
uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *);
 void   iwx_clear_tx_desc(struct iwx_softc *, struct iwx_tx_ring *, int);
 void   iwx_txd_done(struct iwx_softc *, struct iwx_tx_data *);
-void   iwx_txq_advance(struct iwx_softc *, struct iwx_tx_ring *, int);
+void   iwx_txq_advance(struct iwx_softc *, struct iwx_tx_ring *, uint16_t);
 void   iwx_rx_tx_cmd(struct iwx_softc *, struct iwx_rx_packet *,
struct iwx_rx_data *);
 void   iwx_clear_oactive(struct iwx_softc *, struct iwx_tx_ring *);
@@ -381,8 +394,9 @@ int iwx_send_cmd_pdu_status(struct iwx_softc *, uint32
 void   iwx_free_resp(struct iwx_softc *, struct iwx_host_cmd *);
 void   iwx_cmd_done(struct iwx_softc *, int, int, int);
 const struct iwx_rate *iwx_tx_fill_cmd(struct iwx_softc *, struct iwx_node *,
-   struct ieee80211_frame *, struct iwx_tx_cmd_gen2 *);
-void   iwx_tx_update_byte_tbl(struct iwx_tx_ring *, int, uint16_t, uint16_t);
+   struct ieee80211_frame *, uint16_t *, 

Re: athn(4) USB question: Where is Tx interrupt handler?

2022-05-08 Thread Stefan Sperling
On Sun, May 08, 2022 at 12:29:57AM -0400, Farhan Khan wrote:
> On May 6, 2022 4:37:48 AM EDT, Stefan Sperling  wrote:
> >On Thu, May 05, 2022 at 01:19:08PM -0400, Farhan Khan wrote:
> >> Hi all,
> >> 
> >> Summary Question:
> >> 
> >> Broadly, I am trying to understand where a interrupt callback is specified 
> >> if 
> >> not already specified by usbd_open_pipe_intr(9). Specifically, for the 
> >> athn(4) 
> >> driver, I am trying to understand if/how athn_usb_intr() is executed for 
> >> Tx 
> >> interrupts. This seems necessary yet I do not see a callback specified by 
> >> usbd_setup_xfer(9) or by usbd_open_pipe_intr(9).
> >> 
> >> All code is located in sys/dev/usb/if_athn_usb.c.
> >> 
> >> Question Walk-through:
> >> 
> >> >From reading the code, it seems that the athn_usb_intr() function is 
> >> >called 
> >> whenever a Tx interrupt is triggered. The reason I think this is because 
> >> there 
> >> is a tsleep_nsec(9) for a Tx interrupt that awaits for a wakeup(9) that 
> >> only 
> >> happens in athn_usb_intr().
> >> 
> >> The 3 relevant steps are listed below in athn_usb_htc_setup() under the 
> >> comment "Set credits for WLAN Tx pipe":
> >> 
> >> 1. athn_usb_htc_msg(), which runs usbd_setup_xfer(9) and usbd_transfer(9) 
> >> for 
> >> a Tx interrupt. The callback is set to NULL.
> >> 2. usc->wait_msg_id is set to AR_HTC_MSG_CONF_PIPE_RSP.
> >> 3. A tsleep_nsec() on >wait_msg_id
> >> 
> >> The only place I see a wakeup(9) on >wait_msg_id is within 
> >> athn_usb_intr(), on condition that usc->wait_msg_id is set to 
> >> AR_HTC_MSG_CONF_PIPE_RSP. Seems like a perfect match. Additionally, I do 
> >> not 
> >> see an Rx interrupt anywhere else. But even if it does happen somewhere 
> >> and I 
> >> am just missing it, the only place AR_HTC_MSG_CONF_PIPE_RSP is used is 
> >> step 2.
> >> 
> >> Rx interrupt callbacks to athn_usb_intr() are specified by the 
> >> usbd_open_pipe_intr(9) call in athn_usb_open_pipes(). That seems explicit. 
> >> But 
> >> for the Tx interrupt, I do not see where the mapping to athn_usb_intr() is.
> >> 
> >> Please assist, thank you.
> >
> >Everything related to Tx is happening in athn_usb_tx() and athn_usb_txoef().
> >
> >usbd_setup_xfer() gets a function pointer to call when the USB transfer
> >has completed. This function pointer is athn_usb_txeof():
> >
> > usbd_setup_xfer(data->xfer, usc->tx_data_pipe, data, data->buf,
> > xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, ATHN_USB_TX_TIMEOUT,
> > athn_usb_txeof);
> >
> >athn_usb_txeof() puts the buffer associated with the Tx attempt back onto
> >the list of free buffers, and schedules more Tx attempts if needed by
> >calling if_start().
> >
> >The associated mbuf is freed quite early, before the Tx attempt is even made,
> >because the entire packet gets copied into the Tx command sent to the device:
> >
> > /* Copy payload. */
> > m_copydata(m, 0, m->m_pkthdr.len, frm);
> > frm += m->m_pkthdr.len;
> > m_freem(m);
> 
> 
> Hi Stefan!
> Reading through athn_usb_txeof, I don't see where it triggers an Rx interrupt 
> such that the wakeup(9) is done. Additionally, that seems to be a periodic 
> function whereas I suspect thr interrupt I am looking for is only during 
> initial of the device, not if-up. But perhaps I am mistaken? I do kot 
> understand where or how the wakeup(9) occurs.
> 
> Thanks!
 
athn_usb_intr() is not used for Tx interrupts.
athn_usb_intr() is only used to process HTC message responses, not for
processing packets. The driver sleeps on >wait_msg_id when it must
wait for a device command to be processed before the driver can continue.
A wakeup() is required in that case to interrupt the corresponding tsleep().
But when the driver is submitting a packet for Tx there is no need to wait.



Re: athn(4) USB question: Where is Tx interrupt handler?

2022-05-06 Thread Stefan Sperling
On Thu, May 05, 2022 at 01:19:08PM -0400, Farhan Khan wrote:
> Hi all,
> 
> Summary Question:
> 
> Broadly, I am trying to understand where a interrupt callback is specified if 
> not already specified by usbd_open_pipe_intr(9). Specifically, for the 
> athn(4) 
> driver, I am trying to understand if/how athn_usb_intr() is executed for Tx 
> interrupts. This seems necessary yet I do not see a callback specified by 
> usbd_setup_xfer(9) or by usbd_open_pipe_intr(9).
> 
> All code is located in sys/dev/usb/if_athn_usb.c.
> 
> Question Walk-through:
> 
> >From reading the code, it seems that the athn_usb_intr() function is called 
> whenever a Tx interrupt is triggered. The reason I think this is because 
> there 
> is a tsleep_nsec(9) for a Tx interrupt that awaits for a wakeup(9) that only 
> happens in athn_usb_intr().
> 
> The 3 relevant steps are listed below in athn_usb_htc_setup() under the 
> comment "Set credits for WLAN Tx pipe":
> 
> 1. athn_usb_htc_msg(), which runs usbd_setup_xfer(9) and usbd_transfer(9) for 
> a Tx interrupt. The callback is set to NULL.
> 2. usc->wait_msg_id is set to AR_HTC_MSG_CONF_PIPE_RSP.
> 3. A tsleep_nsec() on >wait_msg_id
> 
> The only place I see a wakeup(9) on >wait_msg_id is within 
> athn_usb_intr(), on condition that usc->wait_msg_id is set to 
> AR_HTC_MSG_CONF_PIPE_RSP. Seems like a perfect match. Additionally, I do not 
> see an Rx interrupt anywhere else. But even if it does happen somewhere and I 
> am just missing it, the only place AR_HTC_MSG_CONF_PIPE_RSP is used is step 2.
> 
> Rx interrupt callbacks to athn_usb_intr() are specified by the 
> usbd_open_pipe_intr(9) call in athn_usb_open_pipes(). That seems explicit. 
> But 
> for the Tx interrupt, I do not see where the mapping to athn_usb_intr() is.
> 
> Please assist, thank you.

Everything related to Tx is happening in athn_usb_tx() and athn_usb_txoef().

usbd_setup_xfer() gets a function pointer to call when the USB transfer
has completed. This function pointer is athn_usb_txeof():

usbd_setup_xfer(data->xfer, usc->tx_data_pipe, data, data->buf,
xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, ATHN_USB_TX_TIMEOUT,
athn_usb_txeof);

athn_usb_txeof() puts the buffer associated with the Tx attempt back onto
the list of free buffers, and schedules more Tx attempts if needed by
calling if_start().

The associated mbuf is freed quite early, before the Tx attempt is even made,
because the entire packet gets copied into the Tx command sent to the device:

/* Copy payload. */
m_copydata(m, 0, m->m_pkthdr.len, frm);
frm += m->m_pkthdr.len;
m_freem(m);



Re: patch: if_iwx.c add support for ax201 with subsystem id 0x0030

2022-04-09 Thread Stefan Sperling
On Sat, Apr 09, 2022 at 05:46:29PM +0200, Sven Wolf wrote:
> Hi Stefan,
> 
> thanks for your effort.
> I've successfully tested your latest patch.
> I also got the sw_hw_rev:
> 
> sc_hw_rev=354

Thank you! Now everything makes sense :)



Re: patch: if_iwx.c add support for ax201 with subsystem id 0x0030

2022-04-09 Thread Stefan Sperling
On Sat, Apr 09, 2022 at 04:53:50PM +0200, Stefan Sperling wrote:
> On Sat, Apr 09, 2022 at 04:52:12PM +0200, Stefan Sperling wrote:
> > On Sat, Apr 09, 2022 at 04:29:42PM +0200, Stefan Sperling wrote:
> > > As sthen points out, please show sc_hw_rev without any of its bits
> > > masked out, with a patch like this:
> > 
> > Nevermind, I found a bug in my patch which most certainly
> > breaks your device.
> > 
> > Please try this on top of the patch I sent out, without any
> > other modifcations. Your device should work with this change.
> 
> And for everyone else, here is a new complete diff with this
> fix rolled in.

And looking over the linux code again, I realized there is a whole
class of devices ("Qu C0") which our code didn't handle yet.
Fixed here.

diff refs/heads/master refs/heads/iwx-match
blob - df5614f9f6140ba069db8d60e724b1ab36d124a2
blob + 69f489127b1a6898d12f5f5b2683cb7b3558293b
--- share/man/man4/iwx.4
+++ share/man/man4/iwx.4
@@ -84,8 +84,12 @@ which are loaded when an interface is brought up:
 .Pp
 .Bl -tag -width Ds -offset indent -compact
 .It Pa /etc/firmware/iwx-cc-a0-67
-.It Pa /etc/firmware/iwx-QuZ-a0-hr-b0-67
+.It Pa /etc/firmware/iwx-Qu-b0-hr-b0-63
+.It Pa /etc/firmware/iwx-Qu-b0-jf-b0-63
 .It Pa /etc/firmware/iwx-Qu-c0-hr-b0-63
+.It Pa /etc/firmware/iwx-Qu-c0-jf-b0-63
+.It Pa /etc/firmware/iwx-QuZ-a0-hr-b0-67
+.It Pa /etc/firmware/iwx-QuZ-a0-jf-b0-63
 .El
 .Pp
 These firmware files are not free because Intel refuses to grant
blob - 11f582e67321c9782b9cb38e6ce948b465522c94
blob + 8e21d8db3c63b3644f366a112404a174b8cbd722
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -491,6 +491,7 @@ int iwx_intr_msix(void *);
 intiwx_match(struct device *, void *, void *);
 intiwx_preinit(struct iwx_softc *);
 void   iwx_attach_hook(struct device *);
+const struct iwx_device_cfg *iwx_find_device_cfg(struct iwx_softc *);
 void   iwx_attach(struct device *, struct device *, void *);
 void   iwx_init_task(void *);
 intiwx_activate(struct device *, int);
@@ -870,7 +871,7 @@ iwx_ctxt_info_init(struct iwx_softc *sc, const struct 
/* size is in DWs */
ctxt_info->version.size = htole16(sizeof(*ctxt_info) / 4);
 
-   if (sc->sc_device_family >= IWX_DEVICE_FAMILY_22560)
+   if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210)
rb_size = IWX_CTXT_INFO_RB_SIZE_2K;
else
rb_size = IWX_CTXT_INFO_RB_SIZE_4K;
@@ -9392,61 +9393,192 @@ static const struct pci_matchid iwx_devices[] = {
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_3 },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_4,},
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_5,},
+   { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_6,},
+   { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_7,},
+   { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_8,},
 };
 
-static const struct pci_matchid iwx_subsystem_id_ax201[] = {
-   { PCI_VENDOR_INTEL, 0x0070 },
-   { PCI_VENDOR_INTEL, 0x0074 },
-   { PCI_VENDOR_INTEL, 0x0078 },
-   { PCI_VENDOR_INTEL, 0x007c },
-   { PCI_VENDOR_INTEL, 0x0310 },
-   { PCI_VENDOR_INTEL, 0x2074 },
-   { PCI_VENDOR_INTEL, 0x4070 },
-   /* TODO: There are more ax201 devices with "main" product ID 0x06f0 */
-};
 
 int
 iwx_match(struct device *parent, iwx_match_t match __unused, void *aux)
 {
struct pci_attach_args *pa = aux;
-   pcireg_t subid;
-   pci_vendor_id_t svid;
-   pci_product_id_t spid;
-   int i;
-
-   if (!pci_matchbyid(pa, iwx_devices, nitems(iwx_devices)))
-   return 0;
-
-   /*
-* Some PCI product IDs are shared among devices which use distinct
-* chips or firmware. We need to match the subsystem ID as well to
-* ensure that we have in fact found a supported device.
-*/
-   subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
-   svid = PCI_VENDOR(subid);
-   spid = PCI_PRODUCT(subid);
-
-   switch (PCI_PRODUCT(pa->pa_id)) {
-   case PCI_PRODUCT_INTEL_WL_22500_1: /* AX200 */
-   return 1; /* match any device */
-   case PCI_PRODUCT_INTEL_WL_22500_2: /* AX201 */
-   case PCI_PRODUCT_INTEL_WL_22500_3: /* AX201 */
-   case PCI_PRODUCT_INTEL_WL_22500_4: /* AX201 */
-   case PCI_PRODUCT_INTEL_WL_22500_5: /* AX201 */
-   for (i = 0; i < nitems(iwx_subsystem_id_ax201); i++) {
-   if (svid == iwx_subsystem_id_ax201[i].pm_vid &&
-   spid == iwx_subsystem_id_ax201[i].pm_pid)
-   return 1;
-
-   }
-   break;
-   default:
-   break;
-   }
-
-   return 0;
+   return pci_matchbyid(pa, iwx_devices, nitems(iwx_devices));
 }
 
+/*
+ * The device info table below contains device-sp

Re: patch: if_iwx.c add support for ax201 with subsystem id 0x0030

2022-04-09 Thread Stefan Sperling
On Sat, Apr 09, 2022 at 04:52:12PM +0200, Stefan Sperling wrote:
> On Sat, Apr 09, 2022 at 04:29:42PM +0200, Stefan Sperling wrote:
> > As sthen points out, please show sc_hw_rev without any of its bits
> > masked out, with a patch like this:
> 
> Nevermind, I found a bug in my patch which most certainly
> breaks your device.
> 
> Please try this on top of the patch I sent out, without any
> other modifcations. Your device should work with this change.

And for everyone else, here is a new complete diff with this
fix rolled in.

diff refs/heads/master refs/heads/iwx-match
blob - df5614f9f6140ba069db8d60e724b1ab36d124a2
blob + 69f489127b1a6898d12f5f5b2683cb7b3558293b
--- share/man/man4/iwx.4
+++ share/man/man4/iwx.4
@@ -84,8 +84,12 @@ which are loaded when an interface is brought up:
 .Pp
 .Bl -tag -width Ds -offset indent -compact
 .It Pa /etc/firmware/iwx-cc-a0-67
-.It Pa /etc/firmware/iwx-QuZ-a0-hr-b0-67
+.It Pa /etc/firmware/iwx-Qu-b0-hr-b0-63
+.It Pa /etc/firmware/iwx-Qu-b0-jf-b0-63
 .It Pa /etc/firmware/iwx-Qu-c0-hr-b0-63
+.It Pa /etc/firmware/iwx-Qu-c0-jf-b0-63
+.It Pa /etc/firmware/iwx-QuZ-a0-hr-b0-67
+.It Pa /etc/firmware/iwx-QuZ-a0-jf-b0-63
 .El
 .Pp
 These firmware files are not free because Intel refuses to grant
blob - 11f582e67321c9782b9cb38e6ce948b465522c94
blob + 01d00599c7368fe1aef249a48b110104c980b52c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -491,6 +491,7 @@ int iwx_intr_msix(void *);
 intiwx_match(struct device *, void *, void *);
 intiwx_preinit(struct iwx_softc *);
 void   iwx_attach_hook(struct device *);
+const struct iwx_device_cfg *iwx_find_device_cfg(struct iwx_softc *);
 void   iwx_attach(struct device *, struct device *, void *);
 void   iwx_init_task(void *);
 intiwx_activate(struct device *, int);
@@ -870,7 +871,7 @@ iwx_ctxt_info_init(struct iwx_softc *sc, const struct 
/* size is in DWs */
ctxt_info->version.size = htole16(sizeof(*ctxt_info) / 4);
 
-   if (sc->sc_device_family >= IWX_DEVICE_FAMILY_22560)
+   if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210)
rb_size = IWX_CTXT_INFO_RB_SIZE_2K;
else
rb_size = IWX_CTXT_INFO_RB_SIZE_4K;
@@ -9392,61 +9393,192 @@ static const struct pci_matchid iwx_devices[] = {
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_3 },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_4,},
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_5,},
+   { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_6,},
+   { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_7,},
+   { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_8,},
 };
 
-static const struct pci_matchid iwx_subsystem_id_ax201[] = {
-   { PCI_VENDOR_INTEL, 0x0070 },
-   { PCI_VENDOR_INTEL, 0x0074 },
-   { PCI_VENDOR_INTEL, 0x0078 },
-   { PCI_VENDOR_INTEL, 0x007c },
-   { PCI_VENDOR_INTEL, 0x0310 },
-   { PCI_VENDOR_INTEL, 0x2074 },
-   { PCI_VENDOR_INTEL, 0x4070 },
-   /* TODO: There are more ax201 devices with "main" product ID 0x06f0 */
-};
 
 int
 iwx_match(struct device *parent, iwx_match_t match __unused, void *aux)
 {
struct pci_attach_args *pa = aux;
-   pcireg_t subid;
-   pci_vendor_id_t svid;
-   pci_product_id_t spid;
-   int i;
-
-   if (!pci_matchbyid(pa, iwx_devices, nitems(iwx_devices)))
-   return 0;
-
-   /*
-* Some PCI product IDs are shared among devices which use distinct
-* chips or firmware. We need to match the subsystem ID as well to
-* ensure that we have in fact found a supported device.
-*/
-   subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
-   svid = PCI_VENDOR(subid);
-   spid = PCI_PRODUCT(subid);
-
-   switch (PCI_PRODUCT(pa->pa_id)) {
-   case PCI_PRODUCT_INTEL_WL_22500_1: /* AX200 */
-   return 1; /* match any device */
-   case PCI_PRODUCT_INTEL_WL_22500_2: /* AX201 */
-   case PCI_PRODUCT_INTEL_WL_22500_3: /* AX201 */
-   case PCI_PRODUCT_INTEL_WL_22500_4: /* AX201 */
-   case PCI_PRODUCT_INTEL_WL_22500_5: /* AX201 */
-   for (i = 0; i < nitems(iwx_subsystem_id_ax201); i++) {
-   if (svid == iwx_subsystem_id_ax201[i].pm_vid &&
-   spid == iwx_subsystem_id_ax201[i].pm_pid)
-   return 1;
-
-   }
-   break;
-   default:
-   break;
-   }
-
-   return 0;
+   return pci_matchbyid(pa, iwx_devices, nitems(iwx_devices));
 }
 
+/*
+ * The device info table below contains device-specific config overrides.
+ * The most important parameter derived from this table is the name of the
+ * firmware image to load.
+ *
+ * The Linux iwlwifi driver uses an "old" and a "new" device info table.
+ * The "old" table matches devices based on P

Re: patch: if_iwx.c add support for ax201 with subsystem id 0x0030

2022-04-09 Thread Stefan Sperling
On Sat, Apr 09, 2022 at 04:29:42PM +0200, Stefan Sperling wrote:
> As sthen points out, please show sc_hw_rev without any of its bits
> masked out, with a patch like this:

Nevermind, I found a bug in my patch which most certainly
breaks your device.

Please try this on top of the patch I sent out, without any
other modifcations. Your device should work with this change.

diff 64e15b2294bce6a08025941cf9440784a6b2e1f2 /usr/src
blob - 9ffa40d1606fc261ed610984b82e0dbcada90340
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -9860,13 +9860,12 @@ iwx_attach(struct device *parent, struct device *self,
case PCI_PRODUCT_INTEL_WL_22500_7:
case PCI_PRODUCT_INTEL_WL_22500_8:
if (sc->sc_hw_rev != IWX_CSR_HW_REV_TYPE_QUZ)
sc->sc_fwname = IWX_QU_B_HR_B_FW;
else
sc->sc_fwname = IWX_QUZ_A_HR_B_FW;
-   sc->sc_fwname = IWX_QU_C_HR_B_FW;
sc->sc_device_family = IWX_DEVICE_FAMILY_22000;
sc->sc_integrated = 1;
sc->sc_ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_1820;
sc->sc_low_latency_xtal = 0;
sc->sc_xtal_latency = 1820;
sc->sc_tx_with_siso_diversity = 0;



Re: patch: if_iwx.c add support for ax201 with subsystem id 0x0030

2022-04-09 Thread Stefan Sperling
On Sat, Apr 09, 2022 at 03:28:14PM +0200, Stefan Sperling wrote:
> On Sat, Apr 09, 2022 at 12:47:56PM +0200, Sven Wolf wrote:
> > Hi Stefan,
> > 
> > sorry, I'm not sure how I can get the sc_hw_rev value.
> > Hopefully this is the requested value:
> > 
> > iwx0: hw rev 0x350, fw ver 67.8f59b80b.0
> 
> This is not the "QuZ" (0x354) hardware revision.

So this is in fact very complicated.

Intel changed the layout of hw revision ID bits in hardware, but the
Linux driver had a workaround (which iwx is using as well) to store these
bits in the previous format. Later they changed the Linux driver again,
and now our definition of "QuZ" is different from that of Linux.
I cannot be sure anymore if our code is doing the right thing :-/

As sthen points out, please show sc_hw_rev without any of its bits
masked out, with a patch like this:

diff a26af1db5d30d7a58f91742886569d0d8891b827 /usr/src
blob - 2e96219c0dcfeaa4d24912b7e16f22dd617fe828
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -9483,6 +9483,7 @@ iwx_preinit(struct iwx_softc *sc)
printf("%s: hw rev 0x%x, fw ver %s, address %s\n",
DEVNAME(sc), sc->sc_hw_rev & IWX_CSR_HW_REV_TYPE_MSK,
sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr));
+   printf("sc_hw_rev=%x\n", sc->sc_hw_rev);
 
if (sc->sc_nvm.sku_cap_11n_enable)
iwx_setup_ht_rates(sc);



Re: patch: if_iwx.c add support for ax201 with subsystem id 0x0030

2022-04-09 Thread Stefan Sperling
On Sat, Apr 09, 2022 at 12:47:56PM +0200, Sven Wolf wrote:
> Hi Stefan,
> 
> sorry, I'm not sure how I can get the sc_hw_rev value.
> Hopefully this is the requested value:
> 
> iwx0: hw rev 0x350, fw ver 67.8f59b80b.0

This is not the "QuZ" (0x354) hardware revision.

However, Linux obviously loads QuZ firmware anyway.
So either there is an override for your device in the iwlwifi dev_info
table, or all Qu devices must be treated QuZ unless overridden.

To proceed I need to know the output of pcidump -v on your system.

We already know the product ID (4df0). The device table also contains
the "subsystem" product ID which matters for the overrides table.
The relevant line from pcidump should look something like:
0x002c: Subsystem Vendor ID: 8086 Product ID: "
in the "Intel Wi-Fi 6 AX201" section.



Re: ral(4) 11n? I have spare hardware

2022-04-09 Thread Stefan Sperling
On Sat, Apr 09, 2022 at 03:26:03AM +0200, stolen data wrote:
> It's been great seeing iwm/iwn/iwx/athn getting a lot of updates lately. I
> wonder if there's any work planned for getting 11n support to some of the
> older but still capable Realtek chipsets in ral(4)?
> 
> I have a spare RT2860+RT2820 PCI card - Edimax EW-7728In - that I could
> part with if any developer would be interested. Perhaps stsp@?
> 

I already have ral(4) hardware, but not enough time to implement
802.11n across all drivers myself. It would be great to get some help.



Re: patch: if_iwx.c add support for ax201 with subsystem id 0x0030

2022-04-09 Thread Stefan Sperling
On Sat, Apr 09, 2022 at 12:31:09AM +0200, Sven Wolf wrote:
> Hi Stefan,
> 
> on my device WL_22500_8   0x4df0 this patch doesn't work directly.
> I get the error message:
> iwx0: could not load firmware, 35
> iwx0: failed to load init firmware
> 
> Under Linux the firmware iwlwifi-QuZ-a0-hr-b0-67.ucode is loaded for this
> device. Also my old patch
> (https://marc.info/?l=openbsd-bugs=164201744804674=2) works with the
> firmware for the WL_22500_5 devices.
> 
> With this small patch to your patch, wireless is working.
> 
> *** 9829,9834 
> --- 9829,9835 
>   break;
>   case PCI_PRODUCT_INTEL_WL_22500_2:
>   case PCI_PRODUCT_INTEL_WL_22500_5:
> + case PCI_PRODUCT_INTEL_WL_22500_8:
>   /* These devices should be QuZ only. */
>   if (sc->sc_hw_rev != IWX_CSR_HW_REV_TYPE_QUZ) {
>   printf("%s: unsupported AX201 adapter\n", DEVNAME(sc));
> ***
> *** 9858,9864 
>   break;
>   case PCI_PRODUCT_INTEL_WL_22500_4:
>   case PCI_PRODUCT_INTEL_WL_22500_7:
> - case PCI_PRODUCT_INTEL_WL_22500_8:
>   if (sc->sc_hw_rev != IWX_CSR_HW_REV_TYPE_QUZ)

Thanks Sven!

What is the value of sc_hw_rev on this 0x4df0 device?

>   sc->sc_fwname = IWX_QU_B_HR_B_FW;
>   else
> --- 9859,9864 
> 
> 
> Thanks,
> Sven
> 
> 
> 
> On 4/8/22 14:40, Stefan Sperling wrote:
> > On Tue, Jan 11, 2022 at 10:33:39PM +, Iraklis Karagkiozoglou wrote:
> > > Hello Stefan,
> > > 
> > > I tried to port the firmware detection and config values
> > > from iwlwifi.
> > > 
> > > On iwx_cfg_trans_params and iwx_cfg structs I ported only
> > > the fields iwx_attach was setting based on the iwx_device.
> > > 
> > > With best regards,
> > > Iraklis Karagkiozoglou
> > 
> > Hi Iraklis,
> > 
> > It took me some time to get back to this, sorry about that.
> > 
> > The new patch below attempts to add support for any AX200/AX201 devices
> > which have firmware available in fw_update(4). This will hopefully cover
> > devices which people have reported as not detected and which should
> > already be working as long as we load the correct firmware image.
> > 
> > This new patch is based on your patch from January.
> > Thank you very much for doing the initial work on this.
> > 
> > After studying the Linux driver for some time I believe the following
> > approach could work for us: We only need a table for devices which
> > require overrides that cannot be detected on PCI vendor/product ID alone.
> > The rest of the Linux driver's table is not needed. We can simply set
> > default values based on the PCI vendor/product ID as we have always done.
> > 
> > My AX200 and AX201 devices are still working fine with this.
> > Tests on more devices would be very welcome, especially ones that are
> > not yet detected in -current.
> > 
> > 
> > diff refs/heads/master refs/heads/iwx-match
> > blob - df5614f9f6140ba069db8d60e724b1ab36d124a2
> > blob + 69f489127b1a6898d12f5f5b2683cb7b3558293b
> > --- share/man/man4/iwx.4
> > +++ share/man/man4/iwx.4
> > @@ -84,8 +84,12 @@ which are loaded when an interface is brought up:
> >   .Pp
> >   .Bl -tag -width Ds -offset indent -compact
> >   .It Pa /etc/firmware/iwx-cc-a0-67
> > -.It Pa /etc/firmware/iwx-QuZ-a0-hr-b0-67
> > +.It Pa /etc/firmware/iwx-Qu-b0-hr-b0-63
> > +.It Pa /etc/firmware/iwx-Qu-b0-jf-b0-63
> >   .It Pa /etc/firmware/iwx-Qu-c0-hr-b0-63
> > +.It Pa /etc/firmware/iwx-Qu-c0-jf-b0-63
> > +.It Pa /etc/firmware/iwx-QuZ-a0-hr-b0-67
> > +.It Pa /etc/firmware/iwx-QuZ-a0-jf-b0-63
> >   .El
> >   .Pp
> >   These firmware files are not free because Intel refuses to grant
> > blob - 11f582e67321c9782b9cb38e6ce948b465522c94
> > blob + 9ffa40d1606fc261ed610984b82e0dbcada90340
> > --- sys/dev/pci/if_iwx.c
> > +++ sys/dev/pci/if_iwx.c
> > @@ -491,6 +491,7 @@ int iwx_intr_msix(void *);
> >   int   iwx_match(struct device *, void *, void *);
> >   int   iwx_preinit(struct iwx_softc *);
> >   void  iwx_attach_hook(struct device *);
> > +const struct iwx_device_cfg *iwx_find_device_cfg(struct iwx_softc *);
> >   void  iwx_attach(struct device *, struct device *, void *);
> >   void  iwx_init_task(void *);
> >   int   iwx_activate(struct device *, int);
> > @@ -870,7 +871,7 @@ iwx_ctxt_info_init(struct iwx_softc *sc, const struct
> > /* size is in DWs */
> >  

Re: patch: if_iwx.c add support for ax201 with subsystem id 0x0030

2022-04-08 Thread Stefan Sperling
On Tue, Jan 11, 2022 at 10:33:39PM +, Iraklis Karagkiozoglou wrote:
> Hello Stefan,
> 
> I tried to port the firmware detection and config values
> from iwlwifi.
> 
> On iwx_cfg_trans_params and iwx_cfg structs I ported only
> the fields iwx_attach was setting based on the iwx_device.
> 
> With best regards,
> Iraklis Karagkiozoglou

Hi Iraklis,

It took me some time to get back to this, sorry about that.

The new patch below attempts to add support for any AX200/AX201 devices
which have firmware available in fw_update(4). This will hopefully cover
devices which people have reported as not detected and which should
already be working as long as we load the correct firmware image.

This new patch is based on your patch from January.
Thank you very much for doing the initial work on this.

After studying the Linux driver for some time I believe the following
approach could work for us: We only need a table for devices which
require overrides that cannot be detected on PCI vendor/product ID alone.
The rest of the Linux driver's table is not needed. We can simply set
default values based on the PCI vendor/product ID as we have always done.

My AX200 and AX201 devices are still working fine with this.
Tests on more devices would be very welcome, especially ones that are
not yet detected in -current.


diff refs/heads/master refs/heads/iwx-match
blob - df5614f9f6140ba069db8d60e724b1ab36d124a2
blob + 69f489127b1a6898d12f5f5b2683cb7b3558293b
--- share/man/man4/iwx.4
+++ share/man/man4/iwx.4
@@ -84,8 +84,12 @@ which are loaded when an interface is brought up:
 .Pp
 .Bl -tag -width Ds -offset indent -compact
 .It Pa /etc/firmware/iwx-cc-a0-67
-.It Pa /etc/firmware/iwx-QuZ-a0-hr-b0-67
+.It Pa /etc/firmware/iwx-Qu-b0-hr-b0-63
+.It Pa /etc/firmware/iwx-Qu-b0-jf-b0-63
 .It Pa /etc/firmware/iwx-Qu-c0-hr-b0-63
+.It Pa /etc/firmware/iwx-Qu-c0-jf-b0-63
+.It Pa /etc/firmware/iwx-QuZ-a0-hr-b0-67
+.It Pa /etc/firmware/iwx-QuZ-a0-jf-b0-63
 .El
 .Pp
 These firmware files are not free because Intel refuses to grant
blob - 11f582e67321c9782b9cb38e6ce948b465522c94
blob + 9ffa40d1606fc261ed610984b82e0dbcada90340
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -491,6 +491,7 @@ int iwx_intr_msix(void *);
 intiwx_match(struct device *, void *, void *);
 intiwx_preinit(struct iwx_softc *);
 void   iwx_attach_hook(struct device *);
+const struct iwx_device_cfg *iwx_find_device_cfg(struct iwx_softc *);
 void   iwx_attach(struct device *, struct device *, void *);
 void   iwx_init_task(void *);
 intiwx_activate(struct device *, int);
@@ -870,7 +871,7 @@ iwx_ctxt_info_init(struct iwx_softc *sc, const struct 
/* size is in DWs */
ctxt_info->version.size = htole16(sizeof(*ctxt_info) / 4);
 
-   if (sc->sc_device_family >= IWX_DEVICE_FAMILY_22560)
+   if (sc->sc_device_family >= IWX_DEVICE_FAMILY_AX210)
rb_size = IWX_CTXT_INFO_RB_SIZE_2K;
else
rb_size = IWX_CTXT_INFO_RB_SIZE_4K;
@@ -9392,61 +9393,192 @@ static const struct pci_matchid iwx_devices[] = {
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_3 },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_4,},
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_5,},
+   { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_6,},
+   { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_7,},
+   { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_22500_8,},
 };
 
-static const struct pci_matchid iwx_subsystem_id_ax201[] = {
-   { PCI_VENDOR_INTEL, 0x0070 },
-   { PCI_VENDOR_INTEL, 0x0074 },
-   { PCI_VENDOR_INTEL, 0x0078 },
-   { PCI_VENDOR_INTEL, 0x007c },
-   { PCI_VENDOR_INTEL, 0x0310 },
-   { PCI_VENDOR_INTEL, 0x2074 },
-   { PCI_VENDOR_INTEL, 0x4070 },
-   /* TODO: There are more ax201 devices with "main" product ID 0x06f0 */
-};
 
 int
 iwx_match(struct device *parent, iwx_match_t match __unused, void *aux)
 {
struct pci_attach_args *pa = aux;
-   pcireg_t subid;
-   pci_vendor_id_t svid;
-   pci_product_id_t spid;
-   int i;
-
-   if (!pci_matchbyid(pa, iwx_devices, nitems(iwx_devices)))
-   return 0;
-
-   /*
-* Some PCI product IDs are shared among devices which use distinct
-* chips or firmware. We need to match the subsystem ID as well to
-* ensure that we have in fact found a supported device.
-*/
-   subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
-   svid = PCI_VENDOR(subid);
-   spid = PCI_PRODUCT(subid);
-
-   switch (PCI_PRODUCT(pa->pa_id)) {
-   case PCI_PRODUCT_INTEL_WL_22500_1: /* AX200 */
-   return 1; /* match any device */
-   case PCI_PRODUCT_INTEL_WL_22500_2: /* AX201 */
-   case PCI_PRODUCT_INTEL_WL_22500_3: /* AX201 */
-   case PCI_PRODUCT_INTEL_WL_22500_4: /* AX201 */
-   case PCI_PRODUCT_INTEL_WL_22500_5: /* AX201 */
-   for (i = 0; i < nitems(iwx_subsystem_id_ax201); i++) 

Re: ure(4): add support for RTL8156B

2022-03-31 Thread Stefan Sperling
On Thu, Mar 31, 2022 at 09:41:09PM +0800, Kevin Lo wrote:
> This diff adds preliminary support for RTL8156B to ure(4) and
> bug fixes for RTL8153/RTL8156.
> 
> Tested:
> ure0 at uhub0 port 12 configuration 1 interface 0 "Realtek USB 10/100/1G/2.5G 
> LAN" rev 3.20/31.00 addr 3
> ure0: RTL8156B (0x7410), address 00:e0:4c:xx:xx:xx

Works for me. ok stsp@, with one question about the diff below:

> Index: sys/dev/usb/if_ure.c
> ===
> RCS file: /cvs/src/sys/dev/usb/if_ure.c,v
> retrieving revision 1.28
> diff -u -p -u -p -r1.28 if_ure.c
> --- sys/dev/usb/if_ure.c  20 Aug 2021 04:54:10 -  1.28
> +++ sys/dev/usb/if_ure.c  31 Mar 2022 08:35:04 -
> @@ -197,7 +197,8 @@ void  ure_rtl8153_init(struct ure_softc 
>  void ure_rtl8153b_init(struct ure_softc *);
>  void ure_rtl8152_nic_reset(struct ure_softc *);
>  void ure_rtl8153_nic_reset(struct ure_softc *);
> -void ure_rtl8153_phy_status(struct ure_softc *, int);
> +uint16_t ure_rtl8153_phy_status(struct ure_softc *, int);

The function ure_rtl8153_phy_status() now returns a value,
but no caller is checking this value. Is this intentional?


Tested with xhci(4) and:

ure0 at uhub2 port 1 configuration 1 interface 0 "Lenovo Thinkpad USB LAN" rev 
3.00/30.00 addr 6
ure0: RTL8153 (0x5c20), address 3c:18:a0:a0:95:2b
rgephy0 at ure0 phy 0: RTL8251 PHY, rev. 0

This chip still works fine:

Conn:   1 Mbps:   91.315 Peak Mbps:   92.233 Avg Mbps:   91.315
   27086   10557368   84.459  100.00%
Conn:   1 Mbps:   84.459 Peak Mbps:   92.233 Avg Mbps:   84.459
   280899950656   79.367  100.00%
Conn:   1 Mbps:   79.367 Peak Mbps:   92.233 Avg Mbps:   79.367
   290919335256   74.607  100.00%
Conn:   1 Mbps:   74.607 Peak Mbps:   92.233 Avg Mbps:   74.607
   30091   10476280   83.810  100.00%
Conn:   1 Mbps:   83.810 Peak Mbps:   92.233 Avg Mbps:   83.810
   310949746488   77.739  100.00%
Conn:   1 Mbps:   77.739 Peak Mbps:   92.233 Avg Mbps:   77.739
   320959582864   76.663  100.00%
Conn:   1 Mbps:   76.663 Peak Mbps:   92.233 Avg Mbps:   76.663
   33098   10091112   80.487  100.00%
Conn:   1 Mbps:   80.487 Peak Mbps:   92.233 Avg Mbps:   80.487
   341018650352   68.996  100.00%
Conn:   1 Mbps:   68.996 Peak Mbps:   92.233 Avg Mbps:   68.996
   351069438064   75.204  100.00%
Conn:   1 Mbps:   75.204 Peak Mbps:   92.233 Avg Mbps:   75.204
^C
--- 192.168.1.1 tcpbench statistics ---
350301608 bytes sent over 35.602 seconds
bandwidth min/avg/max/std-dev = 26.875/78.824/92.233/11.918 Mbps



Re: XBox One gamecontroller support

2022-03-21 Thread Stefan Sperling
On Sun, Mar 20, 2022 at 05:00:13PM -0600, Thomas Frohwein wrote:
> I updated the diff for the controller with your diff. Below is the
> complete diff for all the files involved. I tested it again with my
> controller and sdl-jstest (in ports); it continues to work as intended.
> 
> ok?

Thanks! Ok by me.



Tx rate selection fixes for iwm(4) 11ac mode

2022-03-20 Thread Stefan Sperling
This patch fixes a couple of issues in the VHT rate adaptation code,
and with the data which iwm(4) is feeding into it.

Testing 11ac mode from a distance to my AP, I found that iwm(4) tends
to pick a Tx rate which is too high, resulting in too much of a drop
in throughput.

With this patch, iwm(4) hovers around VHT-MCS4 or VHT-MCS5, instead of
trying to reach the AP on VHT-MCS8 or VHT-MCS9 with heavy retries.
Effective throughput changes from 30Mbit/s to about 100Mbit/s, though
the rate is a bit jumpy and less stable than from a short distance.
A quick test suggests that this patch improves the effective data rate
at a short distance, too.

iwm(4) didn't attribute retries to the correct MCS, resulting in lower
MCS being punished unfairly while a higher MCS keeps failing.
This is what made us pick an Tx that is too high.

Another bug is that we didn't actually set rn->best_nss after deciding
on a new best rate. ieee80211_ra_vht_best_rate() would have to return
two values (mcs, nss), so just make it avoid and let it set rn->best_mcs
and rn->best_nss directly. With this, we are switching between SISO and
MIMO rates as intended.

When switching between ratesets, avoid switching directly to the highest
rate in the new rateset, which might be MCS 9 and not work at all from a
distance. Instead, use the most recently determined best rate in the set.
I plan to make this change in ieee80211_ra.c for 11n mode as well.

A non-obvious fix involves the rn->probed_rates[] array.
The bit which corresponds to the current best MS will not be set in
this array while we are probing an MCS other than the best.
So checking for this bit is simply wrong and prevents us from probing
the next rateset unless we manage to successfully probe up all the way
to MCS 9 in the current set.
This fix might also be needed in ieee80211_ra.c for 11n mode, but I will
deal with this later.

ok?

diff f186611d55a60b95262b00c94ece78add3698ea8 
f5d662f7a36c876abaa8b0987deef01a3fa99b0f
blob - ed592c9012b6ed157d2ab3457d6894f0e68a4f50
blob + ad7e788d6aace58e20247e5c522622e84c649667
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -5532,6 +5532,8 @@ iwm_vht_single_rate_control(struct iwm_softc *sc, stru
 {
struct ieee80211com *ic = >sc_ic;
struct iwm_node *in = (void *)ni;
+   uint8_t vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_80;
+   uint8_t sco = IEEE80211_HTOP0_SCO_SCN;
 
/* Ignore Tx reports which don't match our last LQ command. */
if (txmcs != ni->ni_txmcs || nss != ni->ni_vht_ss) {
@@ -5544,13 +5546,34 @@ iwm_vht_single_rate_control(struct iwm_softc *sc, stru
int mcs = txmcs;
unsigned int retries = 0, i;
 
+   if (in->in_phyctxt) {
+   vht_chan_width = in->in_phyctxt->vht_chan_width;
+   sco = in->in_phyctxt->sco;
+   }
in->lq_rate_mismatch = 0;
 
for (i = 0; i < failure_frame; i++) {
if (mcs > 0) {
ieee80211_ra_vht_add_stats(>in_rn_vht,
ic, ni, mcs, nss, 1, 1);
-   mcs--;
+   if (vht_chan_width >=
+   IEEE80211_VHTOP0_CHAN_WIDTH_80) {
+   /*
+* First 4 Tx attempts used same MCS,
+* twice at 80MHz and twice at 40MHz.
+*/
+   if (i >= 4)
+   mcs--;
+   } else if (sco == IEEE80211_HTOP0_SCO_SCA ||
+   sco == IEEE80211_HTOP0_SCO_SCB) {
+   /*
+* First 4 Tx attempts used same MCS,
+* four times at 40MHz.
+*/
+   if (i >= 4)
+   mcs--;
+   } else
+   mcs--;
} else
retries++;
}
@@ -9234,7 +9257,7 @@ iwm_set_rate_table_vht(struct iwm_node *in, struct iwm
}
 
/*
-* First two Tx attempts may use 80MHz/SGI.
+* First two Tx attempts may use 80MHz/40MHz/SGI.
 * Next two Tx attempts may use 40MHz/SGI.
 * Beyond that use 20 MHz and decrease the rate.
 * As a special case, MCS 9 is invalid on 20 Mhz.
@@ -9257,7 +9280,7 @@ iwm_set_rate_table_vht(struct iwm_node *in, struct iwm
tab |= IWM_RATE_MCS_RTS_REQUIRED_MSK;
if 

Re: XBox One gamecontroller support

2022-03-19 Thread Stefan Sperling
On Fri, Jan 15, 2021 at 06:32:04AM -0700, Thomas Frohwein wrote:
> @@ -557,6 +571,23 @@ uhidev_open(struct uhidev *scd)
>   DPRINTF(("uhidev_open: couldn't allocate owxfer\n"));
>   error = ENOMEM;
>   goto out3;
> + }
> +
> + /* XBox One controller initialization */

Shouldn't this initialization code be under #ifndef SMALL_KERNEL,
like the rest of the code your patch is adding to this file?

> + if (sc->sc_flags & UHIDEV_F_XB1) {
> + uint8_t init_data[] = { 0x05, 0x20, 0x00, 0x01, 0x00 };
> + int init_data_len = sizeof(init_data);

I would use 'size_t init_data_len' instead of 'int init_data_len'.
Largely a matter of taste, but this way everything stays unsigned.
usbd_setup_xfer() expects an unsigned int.

> + usbd_setup_xfer(sc->sc_oxfer, sc->sc_opipe, 0,
> + init_data, init_data_len,
> + USBD_SYNCHRONOUS | USBD_CATCH, USBD_NO_TIMEOUT,
> + NULL);
> + err = usbd_transfer(sc->sc_oxfer);
> + if (err != USBD_NORMAL_COMPLETION) {
> + DPRINTF(("uhidev_open: xb1 init failed, "
> + "error=%d\n", err));
> + error = EIO;
> + goto out3;
> + }
>   }
>   }

Both of the above suggestions as a diff:

diff 978a5fa5205c9adcf7df6f7cb4e82b0fc5f3612a /usr/src
blob - 2aa48d139f7b1a0ddedd79e53da2f0c846ca2745
file + sys/dev/usb/uhidev.c
--- sys/dev/usb/uhidev.c
+++ sys/dev/usb/uhidev.c
@@ -599,11 +599,11 @@ uhidev_open(struct uhidev *scd)
error = ENOMEM;
goto out3;
}
-
+#ifndef SMALL_KERNEL
/* XBox One controller initialization */
if (sc->sc_flags & UHIDEV_F_XB1) {
uint8_t init_data[] = { 0x05, 0x20 };
-   int init_data_len = sizeof(init_data);
+   size_t init_data_len = sizeof(init_data);
usbd_setup_xfer(sc->sc_oxfer, sc->sc_opipe, 0,
init_data, init_data_len,
USBD_SYNCHRONOUS | USBD_CATCH, USBD_NO_TIMEOUT,
@@ -616,6 +616,7 @@ uhidev_open(struct uhidev *scd)
goto out3;
}
}
+#endif
}
 
return (0);



fix iwm/iwx announcing VHT on 2GHz during scans

2022-03-19 Thread Stefan Sperling
Both iwm and iwx are currently writing VHT capabilities into
the "common" secion of the firmware's probe request frame template.
This "common" section is used on both 2GHz and 5GHz bands.

Announcing VHT capabilities on 2GHz makes no sense.
Move them into the 5GHz-only section.

ok?

diff f6c92c11f983c9e9dd370657ab43ccf9feb56be5 /usr/src
blob - e82db1f229ad0141f2bedfe4fa81cb46267f2588
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -7661,6 +7661,12 @@ iwm_fill_probe_req(struct iwm_softc *sc, struct iwm_sc
frm = ieee80211_add_xrates(frm, rs);
preq->band_data[1].len = htole16(frm - pos);
remain -= frm - pos;
+   if (ic->ic_flags & IEEE80211_F_VHTON) {
+   if (remain < 14)
+   return ENOBUFS;
+   frm = ieee80211_add_vhtcaps(frm, ic);
+   remain -= frm - pos;
+   }
}
 
/* Send 11n IEs on both 2GHz and 5GHz bands. */
@@ -7674,12 +7680,6 @@ iwm_fill_probe_req(struct iwm_softc *sc, struct iwm_sc
remain -= frm - pos;
}
 
-   if (ic->ic_flags & IEEE80211_F_VHTON) {
-   if (remain < 14)
-   return ENOBUFS;
-   frm = ieee80211_add_vhtcaps(frm, ic);
-   }
-
preq->common_data.len = htole16(frm - pos);
 
return 0;
blob - 6c1c1647fbcd6d6e71f2d6c08e178fc533650239
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -6200,6 +6200,12 @@ iwx_fill_probe_req(struct iwx_softc *sc, struct iwx_sc
frm = ieee80211_add_xrates(frm, rs);
preq->band_data[1].len = htole16(frm - pos);
remain -= frm - pos;
+   if (ic->ic_flags & IEEE80211_F_VHTON) {
+   if (remain < 14)
+   return ENOBUFS;
+   frm = ieee80211_add_vhtcaps(frm, ic);
+   remain -= frm - pos;
+   }
}
 
/* Send 11n IEs on both 2GHz and 5GHz bands. */
@@ -6213,12 +6219,6 @@ iwx_fill_probe_req(struct iwx_softc *sc, struct iwx_sc
remain -= frm - pos;
}
 
-   if (ic->ic_flags & IEEE80211_F_VHTON) {
-   if (remain < 14)
-   return ENOBUFS;
-   frm = ieee80211_add_vhtcaps(frm, ic);
-   }
-
preq->common_data.len = htole16(frm - pos);
 
return 0;



Re: net80211: fix Rx channel hack used by bwfm, iwn, iwm, and iwx

2022-03-19 Thread Stefan Sperling
On Sat, Mar 19, 2022 at 05:32:48PM +0100, Stefan Sperling wrote:
> The net80211 input routine expects that ic->ic_bss->ni_chan will always
> correspond to the channel which is currently being scanned. This dates
> back to older devices which are manually tuned to the next channel by the
> driver during SCAN->SCAN state transitions. And this must of course be
> kept working for these drivers.
> 
> However, this approach is very awkward for drivers which scan across a
> whole range of channels in firmware. Right now such drivers have an ugly
> workaround around in place which changes the ni_chan variable for each
> received frame.
> 
> This patch introduces a channel number field in the Rx info struct which
> can be used to indicate the hardware channel number on which a frame was
> received. If this field is set, net80211 will use it instead of using the
> current channel of ic_bss.
> 
> Works for me on iwm(4).
> Additional tests on iwn, iwm, iwx, and bwfm would be good.

jmc@ managed to trigger a bug where the interface ended up in 11ac
mode on a 2GHz channel. Should be fixed in this version of the diff.

diff 72ccef0dd6ed210ccf409e8bd0918949ccb70238 
2b44274faa697c674c40e5a1ba5ca818cdf5caf4
blob - 15e712c92ee21ac76262d534d58b7f5548341107
blob + ef8ea9876a4f77106aa42033fdff7f8f2bb53d4c
--- sys/dev/ic/bwfm.c
+++ sys/dev/ic/bwfm.c
@@ -2703,8 +2703,6 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct ieee80211_rxinfo rxi;
-   struct ieee80211_channel *bss_chan;
-   uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
struct mbuf *m;
uint32_t pktlen, ieslen;
uint16_t iesoff;
@@ -2739,28 +2737,14 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
/* Finalize mbuf. */
m->m_pkthdr.len = m->m_len = pktlen;
ni = ieee80211_find_rxnode(ic, wh);
-   if (ni == ic->ic_bss) {
-   /*
-* We may switch ic_bss's channel during scans.
-* Record the current channel so we can restore it later.
-*/
-   bss_chan = ni->ni_chan;
-   IEEE80211_ADDR_COPY(_bssid, ni->ni_macaddr);
-   }
/* Channel mask equals IEEE80211_CHAN_MAX */
chanidx = bwfm_spec2chan(sc, letoh32(bss->chanspec));
-   ni->ni_chan = >ic_channels[chanidx];
/* Supply RSSI */
rxi.rxi_flags = 0;
rxi.rxi_rssi = (int16_t)letoh16(bss->rssi);
rxi.rxi_tstamp = 0;
+   rxi.rxi_chan = chanidx;
ieee80211_input(ifp, m, ni, );
-   /*
-* ieee80211_input() might have changed our BSS.
-* Restore ic_bss's channel if we are still in the same BSS.
-*/
-   if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
-   ni->ni_chan = bss_chan;
/* Node is no longer needed. */
ieee80211_release_node(ic, ni);
 }
blob - c7115ed57c8f3367983d438ade529d39a8cd2872
blob + 984ac6f8913c3f576a724e13dbaf9371d14b3d9a
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -4775,24 +4775,12 @@ iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int
struct ifnet *ifp = IC2IFP(ic);
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
-   struct ieee80211_channel *bss_chan;
-   uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
 
if (chanidx < 0 || chanidx >= nitems(ic->ic_channels))  
chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
 
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic, wh);
-   if (ni == ic->ic_bss) {
-   /* 
-* We may switch ic_bss's channel during scans.
-* Record the current channel so we can restore it later.
-*/
-   bss_chan = ni->ni_chan;
-   IEEE80211_ADDR_COPY(_bssid, ni->ni_macaddr);
-   }
-   ni->ni_chan = >ic_channels[chanidx];
-
if ((rxi->rxi_flags & IEEE80211_RXI_HWDEC) &&
iwm_ccmp_decap(sc, m, ni, rxi) != 0) {
ifp->if_ierrors++;
@@ -4856,12 +4844,6 @@ iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int
}
 #endif
ieee80211_inputm(IC2IFP(ic), m, ni, rxi, ml);
-   /*
-* ieee80211_inputm() might have changed our BSS.
-* Restore ic_bss's channel if we are still in the same BSS.
-*/
-   if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
-   ni->ni_chan = bss_chan;
ieee80211_release_node(ic, ni);
 }
 
@@ -4935,6 +4917,7 @@ iwm_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, void
 
rxi.rxi_rssi = rssi;
rxi.rxi_tstamp = device_timestamp;
+   rxi.rxi_chan = chanidx;
 
iwm_rx_frame(sc, m, chanidx, rx_pkt_s

net80211: fix Rx channel hack used by bwfm, iwn, iwm, and iwx

2022-03-19 Thread Stefan Sperling
The net80211 input routine expects that ic->ic_bss->ni_chan will always
correspond to the channel which is currently being scanned. This dates
back to older devices which are manually tuned to the next channel by the
driver during SCAN->SCAN state transitions. And this must of course be
kept working for these drivers.

However, this approach is very awkward for drivers which scan across a
whole range of channels in firmware. Right now such drivers have an ugly
workaround around in place which changes the ni_chan variable for each
received frame.

This patch introduces a channel number field in the Rx info struct which
can be used to indicate the hardware channel number on which a frame was
received. If this field is set, net80211 will use it instead of using the
current channel of ic_bss.

Works for me on iwm(4).
Additional tests on iwn, iwm, iwx, and bwfm would be good.

ok?

 introduce rxi_chan to communicate Rx channel to net80211
 get rid of saved_bssid hacks in drivers
 
diff 72ccef0dd6ed210ccf409e8bd0918949ccb70238 
20d70a4353a34d2cb2f94d8a15fd7b3b8cdd7158
blob - 15e712c92ee21ac76262d534d58b7f5548341107
blob + ef8ea9876a4f77106aa42033fdff7f8f2bb53d4c
--- sys/dev/ic/bwfm.c
+++ sys/dev/ic/bwfm.c
@@ -2703,8 +2703,6 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct ieee80211_rxinfo rxi;
-   struct ieee80211_channel *bss_chan;
-   uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
struct mbuf *m;
uint32_t pktlen, ieslen;
uint16_t iesoff;
@@ -2739,28 +2737,14 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
/* Finalize mbuf. */
m->m_pkthdr.len = m->m_len = pktlen;
ni = ieee80211_find_rxnode(ic, wh);
-   if (ni == ic->ic_bss) {
-   /*
-* We may switch ic_bss's channel during scans.
-* Record the current channel so we can restore it later.
-*/
-   bss_chan = ni->ni_chan;
-   IEEE80211_ADDR_COPY(_bssid, ni->ni_macaddr);
-   }
/* Channel mask equals IEEE80211_CHAN_MAX */
chanidx = bwfm_spec2chan(sc, letoh32(bss->chanspec));
-   ni->ni_chan = >ic_channels[chanidx];
/* Supply RSSI */
rxi.rxi_flags = 0;
rxi.rxi_rssi = (int16_t)letoh16(bss->rssi);
rxi.rxi_tstamp = 0;
+   rxi.rxi_chan = chanidx;
ieee80211_input(ifp, m, ni, );
-   /*
-* ieee80211_input() might have changed our BSS.
-* Restore ic_bss's channel if we are still in the same BSS.
-*/
-   if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
-   ni->ni_chan = bss_chan;
/* Node is no longer needed. */
ieee80211_release_node(ic, ni);
 }
blob - c7115ed57c8f3367983d438ade529d39a8cd2872
blob + 984ac6f8913c3f576a724e13dbaf9371d14b3d9a
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -4775,24 +4775,12 @@ iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int
struct ifnet *ifp = IC2IFP(ic);
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
-   struct ieee80211_channel *bss_chan;
-   uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
 
if (chanidx < 0 || chanidx >= nitems(ic->ic_channels))  
chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
 
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic, wh);
-   if (ni == ic->ic_bss) {
-   /* 
-* We may switch ic_bss's channel during scans.
-* Record the current channel so we can restore it later.
-*/
-   bss_chan = ni->ni_chan;
-   IEEE80211_ADDR_COPY(_bssid, ni->ni_macaddr);
-   }
-   ni->ni_chan = >ic_channels[chanidx];
-
if ((rxi->rxi_flags & IEEE80211_RXI_HWDEC) &&
iwm_ccmp_decap(sc, m, ni, rxi) != 0) {
ifp->if_ierrors++;
@@ -4856,12 +4844,6 @@ iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int
}
 #endif
ieee80211_inputm(IC2IFP(ic), m, ni, rxi, ml);
-   /*
-* ieee80211_inputm() might have changed our BSS.
-* Restore ic_bss's channel if we are still in the same BSS.
-*/
-   if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
-   ni->ni_chan = bss_chan;
ieee80211_release_node(ic, ni);
 }
 
@@ -4935,6 +4917,7 @@ iwm_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, void
 
rxi.rxi_rssi = rssi;
rxi.rxi_tstamp = device_timestamp;
+   rxi.rxi_chan = chanidx;
 
iwm_rx_frame(sc, m, chanidx, rx_pkt_status,
(phy_flags & IWM_PHY_INFO_FLAG_SHPREAMBLE),
@@ -5465,6 +5448,7 @@ iwm_rx_mpdu_mq(struct iwm_softc *sc, struct mbuf *m, v
 
rxi.rxi_rssi = rssi;
rxi.rxi_tstamp = le64toh(desc->v1.tsf_on_air_rise);
+   rxi.rxi_chan = chanidx;
 
if (iwm_rx_reorder(sc, m, chanidx, 

Re: initial 11ac support for iwm(4)

2022-03-19 Thread Stefan Sperling
On Fri, Mar 18, 2022 at 11:36:50AM +0100, Stefan Sperling wrote:
> On Fri, Mar 18, 2022 at 05:25:42AM +0100, Landry Breuil wrote:
> > interestingly, when associated over ac to the livebox the background
> > scans only shows the 5ghz channels from both APs, but when im associated
> > to my regular AP the background scans shows both 2ghz and 5ghz chans.
> > not sure that matters.
> 
> Thanks for pointing this out!
> Background scan should indeed still report APs on all channels.
> I will try to find a fix for this. It can be fixed independently from
> the iwm 11ac patch. This will likely already affect iwx(4) as well.

This fixes bgscan in 11ac mode for me. Can you confirm?
 
diff 24953ebb6e9389b0238498b9d17801bff188cdc9 
72ccef0dd6ed210ccf409e8bd0918949ccb70238
blob - 6ce36c2abb0de676c636cec098c176f55b737072
blob + 29e79454bd5f94785ab0c1f39a0e8e61b997aae2
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -1736,7 +1736,9 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
 #if IEEE80211_CHAN_MAX < 255
chan > IEEE80211_CHAN_MAX ||
 #endif
-   isclr(ic->ic_chan_active, chan)) {
+   (isclr(ic->ic_chan_active, chan) &&
+((ic->ic_caps & IEEE80211_C_SCANALL) == 0 ||
+(ic->ic_flags & IEEE80211_F_BGSCAN) == 0))) {
DPRINTF(("ignore %s with invalid channel %u\n",
isprobe ? "probe response" : "beacon", chan));
ic->ic_stats.is_rx_badchan++;
blob - aeae4edc6f02c6c10b125d89763812a39ddc5146
blob + a756880e173a53d59e4e5bea783f69f9f0459149
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -1056,7 +1056,8 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ie
int fail;
 
fail = 0;
-   if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
+   if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0 &&
+   isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
fail |= IEEE80211_NODE_ASSOCFAIL_CHAN;
if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
ni->ni_chan != ic->ic_des_chan)





two net80211 AP selection fixes

2022-03-19 Thread Stefan Sperling
Fix number 1:
During network selection (for 'ifconfig join'), give APs which support
11n and 11ac a higher score. VHT implies HT, so 11ac networks receive
2 additional points while 11n-only networks receive one additional point.

Fix number 2:
During AP selection within a given network, we would like to prefer 5GHz APs.
However, this check was incorrectly implemented for drivers which report
RSSI as a percentage, such as iwm(4) or iwx(4). Fix this such that APs with
at least 50% rssi level will be preferred, as was intended. We can use an
already existing function which performs this check correctly instead of
hand-rolling the check.

ok?

diff 15b71cdf8530b1f64fb85d50873b1ff1fad3f0e8 /usr/src
blob - 229636579d3554154733676cc8deb0004f8ce173
file + sys/net80211/ieee80211_node.c
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -480,6 +480,12 @@ ieee80211_ess_calculate_score(struct ieee80211com *ic,
ni->ni_rssi > min_5ghz_rssi)
score += 2;
 
+   /* HT/VHT available */
+   if (ieee80211_node_supports_ht(ni))
+   score++;
+   if (ieee80211_node_supports_vht(ni))
+   score++;
+
/* Boost this AP if it had no auth/assoc failures in the past. */
if (ni->ni_fails == 0)
score += 21;
@@ -493,6 +499,7 @@ ieee80211_ess_calculate_score(struct ieee80211com *ic,
  *
  *  crypto: wpa2 > wpa1 > wep > open
  *  band: 5 GHz > 2 GHz provided 5 GHz rssi is above threshold
+ *  supported standard revisions: 11ac > 11n > 11a/b/g
  *  rssi: rssi1 > rssi2 as a numeric comparison with a slight
  * disadvantage for 2 GHz APs
  *
@@ -1413,7 +1420,7 @@ ieee80211_node_choose_bss(struct ieee80211com *ic, int
 * (as long as it meets the minimum RSSI threshold) since the 5Ghz band
 * is usually less saturated.
 */
-   if (selbs5 && selbs5->ni_rssi > min_5ghz_rssi)
+   if (selbs5 && (*ic->ic_node_checkrssi)(ic, selbs5))
selbs = selbs5;
else if (selbs5 && selbs2)
selbs = (selbs5->ni_rssi >= selbs2->ni_rssi ? selbs5 : selbs2);





fix wrong logic in iwm_vht_single_rate_control()

2022-03-19 Thread Stefan Sperling
I botched the logic used by a check in iwm_vht_single_rate_control().

ok?

diff 15b71cdf8530b1f64fb85d50873b1ff1fad3f0e8 /usr/src
blob - 2c01f718d47acb01a227795fef659ef353f5c7f6
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -5550,7 +5550,7 @@ iwm_vht_single_rate_control(struct iwm_softc *sc, stru
struct iwm_node *in = (void *)ni;
 
/* Ignore Tx reports which don't match our last LQ command. */
-   if (txmcs != ni->ni_txmcs && nss != ni->ni_vht_ss) {
+   if (txmcs != ni->ni_txmcs || nss != ni->ni_vht_ss) {
if (++in->lq_rate_mismatch > 15) {
/* Try to sync firmware with the driver... */
iwm_setrates(in, 1);



Re: fix multiple iwm/iwx interfaces

2022-03-19 Thread Stefan Sperling
On Wed, Mar 16, 2022 at 10:03:36PM +0100, Stefan Sperling wrote:
> On Wed, Mar 16, 2022 at 08:46:01PM +0100, Jeremie Courreges-Anglas wrote:
> > On Mon, Mar 14 2022, Stefan Sperling  wrote:
> > > It is currently impossible to use more than one iwm or iwx interface
> > > in a system because I don't understand C.
> > >
> > > Trying to bring up an uninitialized interface anyway results in a
> > > kernel panic ("bogus channel pointer" from net80211), so prevent
> > > the device from being used in case we never managed to initialize it.
> > >
> > > ok?
> > 
> > I only tested iwm(4) 8265 but the change makes sense, ok jca@
> 
> I will need to revisit this later.
> 
> Somehow it fails in bsd.rd. The interface remains unusable.
> Firmware load fails because of rootfs not being mounted yet (expected),
> and it still doesn't work once firmware becomes available (not expected).

Just moving the variable to the soft fixes the multi-device problem,
and it works in bsd.rd. ok?

I will leave the issue of partial initialization due to errors for later.
That problem already affects the existing code and there is no need to
fix it in the same diff.
 
diff 216d1e6a5ea1a2af70c6b285d1b35ab0008729c4 
24648d7cb335eaa6548221fea3e70572f6349676
blob - 19ca8c08d3bf6cbeeedfc8b19de01aab5bc531f9
blob + 2c01f718d47acb01a227795fef659ef353f5c7f6
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -11558,7 +11558,6 @@ iwm_preinit(struct iwm_softc *sc)
struct ieee80211com *ic = >sc_ic;
struct ifnet *ifp = IC2IFP(ic);
int err;
-   static int attached;
 
err = iwm_prepare_card_hw(sc);
if (err) {
@@ -11566,7 +11565,7 @@ iwm_preinit(struct iwm_softc *sc)
return err;
}
 
-   if (attached) {
+   if (sc->attached) {
/* Update MAC in case the upper layers changed it. */
IEEE80211_ADDR_COPY(sc->sc_ic.ic_myaddr,
((struct arpcom *)ifp)->ac_enaddr);
@@ -11585,7 +11584,7 @@ iwm_preinit(struct iwm_softc *sc)
return err;
 
/* Print version info and MAC address on first successful fw load. */
-   attached = 1;
+   sc->attached = 1;
printf("%s: hw rev 0x%x, fw ver %s, address %s\n",
DEVNAME(sc), sc->sc_hw_rev & IWM_CSR_HW_REV_TYPE_MSK,
sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr));
blob - 53693a914a0e1fe20b0954322a7487ada68be821
blob + 5c2e387480d3ad45f585e4c84bd7162d2ef70df9
--- sys/dev/pci/if_iwmvar.h
+++ sys/dev/pci/if_iwmvar.h
@@ -476,6 +476,7 @@ struct iwm_softc {
struct ieee80211com sc_ic;
int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int);
int sc_newstate_pending;
+   int attached;
 
struct ieee80211_amrr sc_amrr;
struct timeout sc_calib_to;
blob - f2f6c046b4266e5c9f214cfcb0b6c9b1069341fc
blob + ba54430a5bbe62eea3749d62d72ee14d97ffb11e
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -9470,7 +9470,6 @@ iwx_preinit(struct iwx_softc *sc)
struct ieee80211com *ic = >sc_ic;
struct ifnet *ifp = IC2IFP(ic);
int err;
-   static int attached;
 
err = iwx_prepare_card_hw(sc);
if (err) {
@@ -9478,7 +9477,7 @@ iwx_preinit(struct iwx_softc *sc)
return err;
}
 
-   if (attached) {
+   if (sc->attached) {
/* Update MAC in case the upper layers changed it. */
IEEE80211_ADDR_COPY(sc->sc_ic.ic_myaddr,
((struct arpcom *)ifp)->ac_enaddr);
@@ -9497,7 +9496,7 @@ iwx_preinit(struct iwx_softc *sc)
return err;
 
/* Print version info and MAC address on first successful fw load. */
-   attached = 1;
+   sc->attached = 1;
printf("%s: hw rev 0x%x, fw ver %s, address %s\n",
DEVNAME(sc), sc->sc_hw_rev & IWX_CSR_HW_REV_TYPE_MSK,
sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr));
blob - 0cd898b16c4e2a59efe22d1f61ca9a37429a590b
blob + 255c28db4dd487f497b26eaaef2a12fd12ef5c66
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -456,6 +456,7 @@ struct iwx_softc {
struct ieee80211com sc_ic;
int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int);
int sc_newstate_pending;
+   int attached;
 
struct task init_task; /* NB: not reference-counted */
struct refcnt   task_refs;



Re: initial 11ac support for iwm(4)

2022-03-18 Thread Stefan Sperling
On Fri, Mar 18, 2022 at 01:39:01PM +0100, Marcus MERIGHI wrote:
> Hello, 
> 
> s...@stsp.name (Stefan Sperling), 2022.03.17 (Thu) 21:09 (CET):
> > On Thu, Mar 17, 2022 at 07:02:06PM +0100, Marcus MERIGHI wrote:
> > > s...@stsp.name (Stefan Sperling), 2022.03.16 (Wed) 16:11 (CET):
> > > > This patch adds initial 11ac support to the iwm(4) driver.
> > > > It allows use of 80 MHz channels and VHT MCS.
> > > [...]
> > > > So far, I have tested this successfully on iwm(4) 8265.
> > > 
> > > With this patch a "larger" file transfer will reliably panic my machine.
> > > "large" means even small files. 
> > > ICMP and NTP (and probably DNS) seem to work, though.
> > > I've tried it six times, it always crashed.
> > > 
> > > This is with:
> > > iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless-AC 8265" rev 
> > > 0x88, msi
> > > iwm0: hw rev 0x230, fw ver 36.ca7b901d.0, address 00:28:f8:xx:yy:zz
> > 
> > If you have not done so yet, could you please try the revised
> > version of the patch which I posted here?
> > https://marc.info/?l=openbsd-tech=164746924001340=2
> > I believe this should fix your issue.
> > 
> > Below is the difference between the two versions, in case it is easier
> > for you to apply the fix on top of the first version of the patch.
> 
> this did the trick. Thank you and sorry for the noise.

Not worries at all, this was informative. You have a fairly unique test case.
The bug triggered because your AP is using 11ac without MIMO, while everyone
else is testing on a MIMO-capable AP.



Re: initial 11ac support for iwm(4)

2022-03-18 Thread Stefan Sperling
On Fri, Mar 18, 2022 at 05:25:42AM +0100, Landry Breuil wrote:
> interestingly, when associated over ac to the livebox the background
> scans only shows the 5ghz channels from both APs, but when im associated
> to my regular AP the background scans shows both 2ghz and 5ghz chans.
> not sure that matters.

Thanks for pointing this out!
Background scan should indeed still report APs on all channels.
I will try to find a fix for this. It can be fixed independently from
the iwm 11ac patch. This will likely already affect iwx(4) as well.



Re: initial 11ac support for iwm(4)

2022-03-17 Thread Stefan Sperling
On Thu, Mar 17, 2022 at 02:43:14PM -0700, Mike Larkin wrote:
> On Wed, Mar 16, 2022 at 11:17:47PM +0100, Stefan Sperling wrote:
> > On Wed, Mar 16, 2022 at 04:11:41PM +0100, Stefan Sperling wrote:
> > > This patch adds initial 11ac support to the iwm(4) driver.
> > > It allows use of 80 MHz channels and VHT MCS.
> >
> > Updated patch. Fixes a fatal firmware error on devices which
> > do not support MIMO, such as the 3160.
> >
> 
> Works great here on
> 
> iwm0 at pci3 dev 0 function 0 "Intel AC 7265" rev 0x59, msi
> iwm0: hw rev 0x210, fw ver 17.3216344376.0
> 
> One thing I did notice is that after ZZZ/un-ZZZ, it won't move out of 11n mode
> until I ifconfig iwm0 down / up. Then it picks up the VHT rate again.

The device must have used an AP on a 2 GHz channel when it stayed
in 11n mode. This is expected because 11ac only works on 5GHz channels.

Our AP selection is not based on AP capabilities, only on the received
signal strength. I don't want to change this right now, the changes
are large enough as it is. But we could tweak this in the future such
that 11ac gets preferred over 11n if possible.



Re: initial 11ac support for iwm(4)

2022-03-17 Thread Stefan Sperling
On Thu, Mar 17, 2022 at 07:02:06PM +0100, Marcus MERIGHI wrote:
> Hello!
> 
> Thanks for your work on this!
> 
> s...@stsp.name (Stefan Sperling), 2022.03.16 (Wed) 16:11 (CET):
> > This patch adds initial 11ac support to the iwm(4) driver.
> > It allows use of 80 MHz channels and VHT MCS.
> [...]
> > So far, I have tested this successfully on iwm(4) 8265.
> 
> With this patch a "larger" file transfer will reliably panic my machine.
> "large" means even small files. 
> ICMP and NTP (and probably DNS) seem to work, though.
> I've tried it six times, it always crashed.
> 
> This is with:
> iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless-AC 8265" rev 0x88, msi
> iwm0: hw rev 0x230, fw ver 36.ca7b901d.0, address 00:28:f8:xx:yy:zz

If you have not done so yet, could you please try the revised
version of the patch which I posted here?
https://marc.info/?l=openbsd-tech=164746924001340=2
I believe this should fix your issue.

Below is the difference between the two versions, in case it is easier
for you to apply the fix on top of the first version of the patch.
 
diff 0191ab443b6994d9adb38f5f22f66ffea008c0b7 
00811a880ed9b9c98b475f172bf5f6fe3e31811f
blob - 3d13d9f024f349521cdf890955a4b6ce2e88fd5d
blob + dea634bcb86b2e41a7da27dd7be552b751eb1b66
--- sys/net80211/ieee80211_ra_vht.c
+++ sys/net80211/ieee80211_ra_vht.c
@@ -233,7 +233,7 @@ const struct ieee80211_vht_rateset *
 ieee80211_ra_vht_next_rateset(struct ieee80211_ra_vht_node *rn,
 struct ieee80211_node *ni)
 {
-   const struct ieee80211_vht_rateset *rs;
+   const struct ieee80211_vht_rateset *rs, *rsnext;
int next;
int sgi = ieee80211_ra_vht_use_sgi(ni);
int mcs = ni->ni_txmcs;
@@ -269,7 +269,11 @@ ieee80211_ra_vht_next_rateset(struct ieee80211_ra_vht_
} else
panic("%s: invalid probing mode %d", __func__, rn->probing);
 
-   return _std_ratesets_11ac[next];
+   rsnext = _std_ratesets_11ac[next];
+   if (rn->valid_rates[rsnext->num_ss - 1] == 0)
+   return NULL;
+
+   return rsnext;
 }
 
 int



Re: initial 11ac support for iwm(4)

2022-03-17 Thread Stefan Sperling
On Thu, Mar 17, 2022 at 01:07:42AM +, Stuart Henderson wrote:
> 802.11 flags=0<>: beacon, ...

> 191:12 0xb109cb33aaff1806aaff1806, 192:5 0x00aaff,

Now is probably a good time to start pretty-printing these fields in tcpdump.

ok?

diff 140ae54c8a573c04824dd96957ebff4e069b2dfd /usr/src
blob - 4af7bdb9350f0feaff2e562ee2a6ec0982de7a70
file + usr.sbin/tcpdump/print-802_11.c
--- usr.sbin/tcpdump/print-802_11.c
+++ usr.sbin/tcpdump/print-802_11.c
@@ -101,6 +101,8 @@ void ieee80211_print_essid(u_int8_t *, u_int);
 voidieee80211_print_country(u_int8_t *, u_int);
 voidieee80211_print_htcaps(u_int8_t *, u_int);
 voidieee80211_print_htop(u_int8_t *, u_int);
+voidieee80211_print_vhtcaps(u_int8_t *, u_int);
+voidieee80211_print_vhtop(u_int8_t *, u_int);
 voidieee80211_print_rsncipher(u_int8_t []);
 voidieee80211_print_akm(u_int8_t []);
 voidieee80211_print_rsn(u_int8_t *, u_int);
@@ -607,6 +609,199 @@ ieee80211_print_htop(u_int8_t *data, u_int len)
 }
 
 void
+print_vht_mcsmap(uint16_t mcsmap)
+{
+   int nss, mcs;
+
+   for (nss = 1; nss < IEEE80211_VHT_NUM_SS; nss++) {
+   mcs = (mcsmap & IEEE80211_VHT_MCS_FOR_SS_MASK(nss)) >>
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(nss);
+   switch (mcs) {
+   case IEEE80211_VHT_MCS_0_9:
+   printf(" 0-9@%uSS", nss);
+   break;
+   case IEEE80211_VHT_MCS_0_8:
+   printf(" 0-8@%uSS", nss);
+   break;
+   case IEEE80211_VHT_MCS_0_7:
+   printf(" 0-7@%uSS", nss);
+   break;
+   case IEEE80211_VHT_MCS_SS_NOT_SUPP:
+   default:
+   break;
+   }
+   }
+}
+
+/* Caller checks len */
+void
+ieee80211_print_vhtcaps(u_int8_t *data, u_int len)
+{
+   uint32_t vhtcaps;
+   uint16_t rxmcs, txmcs, max_lgi;
+   uint32_t rxstbc, num_sts, max_ampdu, link_adapt;
+
+   if (len < 12) {
+   ieee80211_print_element(data, len);
+   return;
+   }
+
+   vhtcaps = (data[0] | (data[1] << 8) | data[2] << 16 |
+   data[3] << 24);
+   printf("=<");
+
+   /* max MPDU length */
+   switch (vhtcaps & IEEE80211_VHTCAP_MAX_MPDU_LENGTH_MASK) {
+   case IEEE80211_VHTCAP_MAX_MPDU_LENGTH_11454:
+   printf("max MPDU 11454");
+   break;
+   case IEEE80211_VHTCAP_MAX_MPDU_LENGTH_7991:
+   printf("max MPDU 7991");
+   break;
+   case IEEE80211_VHTCAP_MAX_MPDU_LENGTH_3895:
+   default:
+   printf("max MPDU 3895");
+   break;
+   }
+
+   /* supported channel widths */
+   switch ((vhtcaps & IEEE80211_VHTCAP_CHAN_WIDTH_MASK) <<
+   IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT) {
+   case IEEE80211_VHTCAP_CHAN_WIDTH_160_8080:
+   printf(",80+80MHz");
+   /* fallthrough */
+   case IEEE80211_VHTCAP_CHAN_WIDTH_160:
+   printf(",160MHz");
+   /* fallthrough */
+   case IEEE80211_VHTCAP_CHAN_WIDTH_80:
+   default:
+   printf(",80MHz");
+   break;
+   }
+
+   /* LDPC coding */
+   if (vhtcaps & IEEE80211_VHTCAP_RX_LDPC)
+   printf(",LDPC");
+
+   /* short guard interval */
+   if (vhtcaps & IEEE80211_VHTCAP_SGI80)
+   printf(",SGI@80MHz");
+   if (vhtcaps & IEEE80211_VHTCAP_SGI160)
+   printf(",SGI@160MHz");
+
+   /* space-time block coding */
+   if (vhtcaps & IEEE80211_VHTCAP_TX_STBC)
+   printf(",TxSTBC");
+   rxstbc = (vhtcaps & IEEE80211_VHTCAP_RX_STBC_SS_MASK)
+   >> IEEE80211_VHTCAP_RX_STBC_SS_SHIFT;
+   if (rxstbc > 0 && rxstbc <= 7)
+   printf(",RxSTBC %d stream", rxstbc);
+
+   /* beamforming */
+   if (vhtcaps & IEEE80211_VHTCAP_SU_BEAMFORMER) {
+   printf(",beamformer");
+   num_sts = ((vhtcaps & IEEE80211_VHTCAP_NUM_STS_MASK) >>
+   IEEE80211_VHTCAP_NUM_STS_SHIFT);
+   if (num_sts)
+   printf(" STS %u", num_sts);
+   }
+   if (vhtcaps & IEEE80211_VHTCAP_SU_BEAMFORMEE) {
+   printf(",beamformee");
+   num_sts = ((vhtcaps & IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK) >>
+   IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT);
+   if (num_sts)
+   printf(" STS %u", num_sts);
+   }
+
+   if (vhtcaps & IEEE80211_VHTCAP_TXOP_PS)
+   printf(",TXOP PS");
+   if (vhtcaps & IEEE80211_VHTCAP_HTC_VHT)
+   printf(",+HTC VHT");
+
+   /* max A-MPDU length */
+   max_ampdu = ((vhtcaps & IEEE80211_VHTCAP_MAX_AMPDU_LEN_MASK) >>
+   IEEE80211_VHTCAP_MAX_AMPDU_LEN_SHIFT);
+   if (max_ampdu >= IEEE80211_VHTCAP_MAX_AMPDU_LEN_8K &&
+   max_ampdu <= IEEE80211_VHTCAP_MAX_AMPDU_LEN_1024K)

Re: initial 11ac support for iwm(4)

2022-03-16 Thread Stefan Sperling
On Wed, Mar 16, 2022 at 04:11:41PM +0100, Stefan Sperling wrote:
> This patch adds initial 11ac support to the iwm(4) driver.
> It allows use of 80 MHz channels and VHT MCS.

Updated patch. Fixes a fatal firmware error on devices which
do not support MIMO, such as the 3160.

diff refs/heads/master refs/heads/11ac
blob - 7df604d4b6e3913ffeef8c16e7e47637c84af881
blob + 8ed3356b0144a014bece57fa7dcf734624be9fbb
--- sys/conf/files
+++ sys/conf/files
@@ -847,6 +847,7 @@ file net80211/ieee80211_pae_input.c wlan
 file net80211/ieee80211_pae_output.c   wlan
 file net80211/ieee80211_proto.cwlan
 file net80211/ieee80211_ra.c   wlan
+file net80211/ieee80211_ra_vht.c   wlan
 file net80211/ieee80211_rssadapt.c wlan
 file net80211/ieee80211_regdomain.cwlan
 file netinet/if_ether.cether
blob - 7e0e0f4841d3ba61fcf8335bc21c0df2fb416801
blob + ddb2d586ed0ed8c43da2c38d982d47685db940b3
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -143,6 +143,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include  /* for SEQ_LT */
 #undef DPRINTF /* defined in ieee80211_priv.h */
@@ -222,7 +223,7 @@ const struct iwm_rate {
 #define IWM_RVAL_IS_OFDM(_i_) ((_i_) >= 12 && (_i_) != 22)
 
 /* Convert an MCS index into an iwm_rates[] index. */
-const int iwm_mcs2ridx[] = {
+const int iwm_ht_mcs2ridx[] = {
IWM_RATE_MCS_0_INDEX,
IWM_RATE_MCS_1_INDEX,
IWM_RATE_MCS_2_INDEX,
@@ -247,7 +248,7 @@ struct iwm_nvm_section {
 };
 
 intiwm_is_mimo_ht_plcp(uint8_t);
-intiwm_is_mimo_mcs(int);
+intiwm_is_mimo_ht_mcs(int);
 intiwm_store_cscheme(struct iwm_softc *, uint8_t *, size_t);
 intiwm_firmware_store_section(struct iwm_softc *, enum iwm_ucode_type,
uint8_t *, size_t);
@@ -334,6 +335,7 @@ voidiwm_init_channel_map(struct iwm_softc *, const 
ui
const uint8_t *nvm_channels, int nchan);
 intiwm_mimo_enabled(struct iwm_softc *);
 void   iwm_setup_ht_rates(struct iwm_softc *);
+void   iwm_setup_vht_rates(struct iwm_softc *);
 void   iwm_mac_ctxt_task(void *);
 void   iwm_phy_ctxt_task(void *);
 void   iwm_updateprot(struct ieee80211com *);
@@ -396,6 +398,8 @@ voidiwm_rx_frame(struct iwm_softc *, struct mbuf *, 
i
uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *);
 void   iwm_ht_single_rate_control(struct iwm_softc *, struct ieee80211_node *,
int, uint8_t, int);
+void   iwm_vht_single_rate_control(struct iwm_softc *, struct ieee80211_node *,
+   int, int, uint8_t, int);
 void   iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_node *, int, int);
 void   iwm_txd_done(struct iwm_softc *, struct iwm_tx_data *);
@@ -409,14 +413,15 @@ void  iwm_rx_compressed_ba(struct iwm_softc *, struct 
i
 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);
+uint8_tiwm_get_vht_ctrl_pos(struct ieee80211com *, struct 
ieee80211_channel *);
 intiwm_phy_ctxt_cmd_uhb(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint32_t, uint8_t, uint8_t);
 void   iwm_phy_ctxt_cmd_hdr(struct iwm_softc *, struct iwm_phy_ctxt *,
struct iwm_phy_context_cmd *, uint32_t, uint32_t);
 void   iwm_phy_ctxt_cmd_data(struct iwm_softc *, struct iwm_phy_context_cmd *,
-   struct ieee80211_channel *, uint8_t, uint8_t, uint8_t);
+   struct ieee80211_channel *, uint8_t, uint8_t, uint8_t, uint8_t);
 intiwm_phy_ctxt_cmd(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint32_t, uint8_t, uint8_t);
 intiwm_send_cmd(struct iwm_softc *, struct iwm_host_cmd *);
 intiwm_send_cmd_pdu(struct iwm_softc *, uint32_t, uint32_t, uint16_t,
const void *);
@@ -428,7 +433,7 @@ voidiwm_free_resp(struct iwm_softc *, struct 
iwm_host
 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 *,
+uint8_tiwm_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);
 intiwm_flush_tx_path(struct iwm_softc *, int);
@@ -484,7 +489,8 @@ int iwm_umac_scan_abort(struct iwm_softc *);
 intiwm_lmac_scan_abort(struct iwm_softc *);
 intiwm_scan_abort(struct iwm_softc *);
 intiwm_phy_ctxt_update(struct iwm_softc *, struct iwm_phy_ctxt *,
-   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t);
+   struct ieee80211_channel *, uint8_t, uint8_t, 

Re: fix multiple iwm/iwx interfaces

2022-03-16 Thread Stefan Sperling
On Wed, Mar 16, 2022 at 08:46:01PM +0100, Jeremie Courreges-Anglas wrote:
> On Mon, Mar 14 2022, Stefan Sperling  wrote:
> > It is currently impossible to use more than one iwm or iwx interface
> > in a system because I don't understand C.
> >
> > Trying to bring up an uninitialized interface anyway results in a
> > kernel panic ("bogus channel pointer" from net80211), so prevent
> > the device from being used in case we never managed to initialize it.
> >
> > ok?
> 
> I only tested iwm(4) 8265 but the change makes sense, ok jca@

I will need to revisit this later.

Somehow it fails in bsd.rd. The interface remains unusable.
Firmware load fails because of rootfs not being mounted yet (expected),
and it still doesn't work once firmware becomes available (not expected).



initial 11ac support for iwm(4)

2022-03-16 Thread Stefan Sperling
This patch adds initial 11ac support to the iwm(4) driver.
It allows use of 80 MHz channels and VHT MCS.

In net80211 I added a new rate control module to support VHT rates, as
a new file called ieee80211_ra_vht.c, derived from ieee80211_ra.c which
we use in 11n mode. The task of this code is to determine the fastest
VHT rate that is usable. (This was not needed to add 11ac support to
iwx(4) because iwx(4) devices perform this task in firmware.)
Retries at lower rates must be handled by the driver. iwm(4) does this via
the "LQ" command which sends a table of Tx rates the firmware should use.

So far, I have tested this successfully on iwm(4) 8265.
In my testing performance peaks at around 250Mbit/s.
There is no device-specific code involved so I would expect this to
work on all cards supported by the driver.

I will test a few more devices I have here soon, but I don't have
access to all iwm(4) hardware variants at the moment. Testing on any
iwm(4) device would be appreciated. Please be precise about which model
of iwm(4) you are testing on when reporting results.

diff refs/heads/master refs/heads/11ac
blob - 7df604d4b6e3913ffeef8c16e7e47637c84af881
blob + 8ed3356b0144a014bece57fa7dcf734624be9fbb
--- sys/conf/files
+++ sys/conf/files
@@ -847,6 +847,7 @@ file net80211/ieee80211_pae_input.c wlan
 file net80211/ieee80211_pae_output.c   wlan
 file net80211/ieee80211_proto.cwlan
 file net80211/ieee80211_ra.c   wlan
+file net80211/ieee80211_ra_vht.c   wlan
 file net80211/ieee80211_rssadapt.c wlan
 file net80211/ieee80211_regdomain.cwlan
 file netinet/if_ether.cether
blob - 7e0e0f4841d3ba61fcf8335bc21c0df2fb416801
blob + ddb2d586ed0ed8c43da2c38d982d47685db940b3
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -143,6 +143,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include  /* for SEQ_LT */
 #undef DPRINTF /* defined in ieee80211_priv.h */
@@ -222,7 +223,7 @@ const struct iwm_rate {
 #define IWM_RVAL_IS_OFDM(_i_) ((_i_) >= 12 && (_i_) != 22)
 
 /* Convert an MCS index into an iwm_rates[] index. */
-const int iwm_mcs2ridx[] = {
+const int iwm_ht_mcs2ridx[] = {
IWM_RATE_MCS_0_INDEX,
IWM_RATE_MCS_1_INDEX,
IWM_RATE_MCS_2_INDEX,
@@ -247,7 +248,7 @@ struct iwm_nvm_section {
 };
 
 intiwm_is_mimo_ht_plcp(uint8_t);
-intiwm_is_mimo_mcs(int);
+intiwm_is_mimo_ht_mcs(int);
 intiwm_store_cscheme(struct iwm_softc *, uint8_t *, size_t);
 intiwm_firmware_store_section(struct iwm_softc *, enum iwm_ucode_type,
uint8_t *, size_t);
@@ -334,6 +335,7 @@ voidiwm_init_channel_map(struct iwm_softc *, const 
ui
const uint8_t *nvm_channels, int nchan);
 intiwm_mimo_enabled(struct iwm_softc *);
 void   iwm_setup_ht_rates(struct iwm_softc *);
+void   iwm_setup_vht_rates(struct iwm_softc *);
 void   iwm_mac_ctxt_task(void *);
 void   iwm_phy_ctxt_task(void *);
 void   iwm_updateprot(struct ieee80211com *);
@@ -396,6 +398,8 @@ voidiwm_rx_frame(struct iwm_softc *, struct mbuf *, 
i
uint32_t, struct ieee80211_rxinfo *, struct mbuf_list *);
 void   iwm_ht_single_rate_control(struct iwm_softc *, struct ieee80211_node *,
int, uint8_t, int);
+void   iwm_vht_single_rate_control(struct iwm_softc *, struct ieee80211_node *,
+   int, int, uint8_t, int);
 void   iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
struct iwm_node *, int, int);
 void   iwm_txd_done(struct iwm_softc *, struct iwm_tx_data *);
@@ -409,14 +413,15 @@ void  iwm_rx_compressed_ba(struct iwm_softc *, struct 
i
 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);
+uint8_tiwm_get_vht_ctrl_pos(struct ieee80211com *, struct 
ieee80211_channel *);
 intiwm_phy_ctxt_cmd_uhb(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint32_t, uint8_t, uint8_t);
 void   iwm_phy_ctxt_cmd_hdr(struct iwm_softc *, struct iwm_phy_ctxt *,
struct iwm_phy_context_cmd *, uint32_t, uint32_t);
 void   iwm_phy_ctxt_cmd_data(struct iwm_softc *, struct iwm_phy_context_cmd *,
-   struct ieee80211_channel *, uint8_t, uint8_t, uint8_t);
+   struct ieee80211_channel *, uint8_t, uint8_t, uint8_t, uint8_t);
 intiwm_phy_ctxt_cmd(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint32_t, uint8_t, uint8_t);
 intiwm_send_cmd(struct iwm_softc *, struct iwm_host_cmd *);
 intiwm_send_cmd_pdu(struct iwm_softc *, uint32_t, uint32_t, uint16_t,
const void *);
@@ -428,7 +433,7 @@ voidiwm_free_resp(struct iwm_softc *, struct 
iwm_host
 void   iwm_cmd_done(struct iwm_softc *, int, int, int);
 void   iwm_update_sched(struct iwm_softc *, int, int, 

fix multiple iwm/iwx interfaces

2022-03-14 Thread Stefan Sperling
It is currently impossible to use more than one iwm or iwx interface
in a system because I don't understand C.

Trying to bring up an uninitialized interface anyway results in a
kernel panic ("bogus channel pointer" from net80211), so prevent
the device from being used in case we never managed to initialize it.

ok?

diff 239e5514c8225a567e26e4070116f5d41f8e7f87 /usr/src
blob - eece4e0d25a8eecb50627233341ffe836c5a99cb
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -9971,6 +9971,9 @@ iwm_init(struct ifnet *ifp)
struct ieee80211com *ic = >sc_ic;
int err, generation;
 
+   if (!sc->attached)
+   return ENXIO;
+
rw_assert_wrlock(>ioctl_rwl);
 
generation = ++sc->sc_generation;
@@ -11189,7 +11192,6 @@ iwm_preinit(struct iwm_softc *sc)
struct ieee80211com *ic = >sc_ic;
struct ifnet *ifp = IC2IFP(ic);
int err;
-   static int attached;
 
err = iwm_prepare_card_hw(sc);
if (err) {
@@ -11197,7 +11199,7 @@ iwm_preinit(struct iwm_softc *sc)
return err;
}
 
-   if (attached) {
+   if (sc->attached) {
/* Update MAC in case the upper layers changed it. */
IEEE80211_ADDR_COPY(sc->sc_ic.ic_myaddr,
((struct arpcom *)ifp)->ac_enaddr);
@@ -11216,7 +11218,7 @@ iwm_preinit(struct iwm_softc *sc)
return err;
 
/* Print version info and MAC address on first successful fw load. */
-   attached = 1;
+   sc->attached = 1;
printf("%s: hw rev 0x%x, fw ver %s, address %s\n",
DEVNAME(sc), sc->sc_hw_rev & IWM_CSR_HW_REV_TYPE_MSK,
sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr));
blob - 4de3e2bfefe4760baecbccee7739972f6d36fb92
file + sys/dev/pci/if_iwmvar.h
--- sys/dev/pci/if_iwmvar.h
+++ sys/dev/pci/if_iwmvar.h
@@ -473,6 +473,7 @@ struct iwm_softc {
struct ieee80211com sc_ic;
int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int);
int sc_newstate_pending;
+   int attached;
 
struct ieee80211_amrr sc_amrr;
struct timeout sc_calib_to;
blob - ff436be11d9ff000250bc7fdc4e6056fa80a327a
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -8223,6 +8223,9 @@ iwx_init(struct ifnet *ifp)
struct ieee80211com *ic = >sc_ic;
int err, generation;
 
+   if (!sc->attached)
+   return ENXIO;
+
rw_assert_wrlock(>ioctl_rwl);
 
generation = ++sc->sc_generation;
@@ -9470,7 +9473,6 @@ iwx_preinit(struct iwx_softc *sc)
struct ieee80211com *ic = >sc_ic;
struct ifnet *ifp = IC2IFP(ic);
int err;
-   static int attached;
 
err = iwx_prepare_card_hw(sc);
if (err) {
@@ -9478,7 +9480,7 @@ iwx_preinit(struct iwx_softc *sc)
return err;
}
 
-   if (attached) {
+   if (sc->attached) {
/* Update MAC in case the upper layers changed it. */
IEEE80211_ADDR_COPY(sc->sc_ic.ic_myaddr,
((struct arpcom *)ifp)->ac_enaddr);
@@ -9497,7 +9499,7 @@ iwx_preinit(struct iwx_softc *sc)
return err;
 
/* Print version info and MAC address on first successful fw load. */
-   attached = 1;
+   sc->attached = 1;
printf("%s: hw rev 0x%x, fw ver %s, address %s\n",
DEVNAME(sc), sc->sc_hw_rev & IWX_CSR_HW_REV_TYPE_MSK,
sc->sc_fwver, ether_sprintf(sc->sc_nvm.hw_addr));
blob - 39c4c34e97ef9d27c645a73123b48fce64ba4445
file + sys/dev/pci/if_iwxvar.h
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -456,6 +456,7 @@ struct iwx_softc {
struct ieee80211com sc_ic;
int (*sc_newstate)(struct ieee80211com *, enum ieee80211_state, int);
int sc_newstate_pending;
+   int attached;
 
struct task init_task; /* NB: not reference-counted */
struct refcnt   task_refs;



Re: initial iwx(4) 11ac patch for testing

2022-03-10 Thread Stefan Sperling
On Thu, Mar 10, 2022 at 01:56:19PM -0500, Dave Voutila wrote:
> 
> Stefan Sperling  writes:
> 
> > On Thu, Mar 10, 2022 at 12:25:17PM +0100, Stefan Sperling wrote:
> >> Unless anyone else finds a problem, this patch can be considered ready
> >> for review and commit.
> >
> > Of course, I forgot to apply my sysassert fix to the second phy context
> > command function...  Fixed here.
> >
> 
> Looking good on the 3 devices I've tested, with one minor nit. All 3
> devices are similar AX200s like so:
> 
> iwx0 at pci3 dev 0 function 0 "Intel Wi-Fi 6 AX200" rev 0x1a, msix
> iwx0: hw rev 0x340, fw ver 67.8f59b80b.0, address ...
> 
> For some reason, on my lenovo x13 I had to manually enable 11ac mode via
> ifconfig. No idea why. It was sitting on the table next to my Go 2 that
> automatically picked up on 11ac mode.

Which channel was it on while not in 11ac mode?
Only the 5GHz channel range (chan 36+) can use 11ac.

In the 2GHz channel range (chan 1-12 for the US) 11ac cannot be used.
In that range it should autoselect mode 11n, or 11g/11b for very old APs.

We could tweak access point selection heuristics to prefer 11ac over 11n
if both are available for a given SSID. But that can be done in a later
patch.

> In all 3 cases I tested with tpcbench between my apu2 gateway connected
> to my Synology RT2600ac and the client machine. In all 3 cases I saw
> close to a 100% increase in average bandwidth reported. :-)

Very nice. Thanks for testing!



Re: initial iwx(4) 11ac patch for testing

2022-03-10 Thread Stefan Sperling
On Thu, Mar 10, 2022 at 12:25:17PM +0100, Stefan Sperling wrote:
> Unless anyone else finds a problem, this patch can be considered ready
> for review and commit.

Of course, I forgot to apply my sysassert fix to the second phy context
command function...  Fixed here.

diff refs/heads/master refs/heads/11ac
blob - 57bdcce64458e7f9d5802ce4247d5651f9183200
blob + 61022a02f457141e31ec6c04351519fedf7b5782
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -304,6 +304,7 @@ int iwx_schedule_session_protection(struct iwx_softc *
uint32_t);
 void   iwx_init_channel_map(struct iwx_softc *, uint16_t *, uint32_t *, int);
 void   iwx_setup_ht_rates(struct iwx_softc *);
+void   iwx_setup_vht_rates(struct iwx_softc *);
 intiwx_mimo_enabled(struct iwx_softc *);
 void   iwx_mac_ctxt_task(void *);
 void   iwx_phy_ctxt_task(void *);
@@ -363,12 +364,13 @@ void  iwx_clear_oactive(struct iwx_softc *, struct 
iwx_
 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);
+uint8_tiwx_get_vht_ctrl_pos(struct ieee80211com *, struct 
ieee80211_channel *);
 intiwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *, struct iwx_phy_ctxt *, 
uint8_t,
-   uint8_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint8_t, uint8_t);
 intiwx_phy_ctxt_cmd_v3(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint8_t, uint8_t);
 intiwx_phy_ctxt_cmd(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint32_t, uint8_t, uint8_t);
 intiwx_send_cmd(struct iwx_softc *, struct iwx_host_cmd *);
 intiwx_send_cmd_pdu(struct iwx_softc *, uint32_t, uint32_t, uint16_t,
const void *);
@@ -430,10 +432,12 @@ int   iwx_scan_abort(struct iwx_softc *);
 intiwx_enable_mgmt_queue(struct iwx_softc *);
 intiwx_rs_rval2idx(uint8_t);
 uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ieee80211_node *, int);
+uint16_t iwx_rs_vht_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_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *,
-   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t);
+   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t,
+   uint8_t);
 intiwx_auth(struct iwx_softc *);
 intiwx_deauth(struct iwx_softc *);
 intiwx_run(struct iwx_softc *);
@@ -2812,6 +2816,12 @@ iwx_init_channel_map(struct iwx_softc *sc, uint16_t *c
if (ch_flags & IWX_NVM_CHANNEL_40MHZ)
channel->ic_flags |= IEEE80211_CHAN_40MHZ;
}
+
+   if (is_5ghz && data->sku_cap_11ac_enable) {
+   channel->ic_flags |= IEEE80211_CHAN_VHT;
+   if (ch_flags & IWX_NVM_CHANNEL_80MHZ)
+   channel->ic_xflags |= IEEE80211_CHANX_80MHZ;
+   }
}
 }
 
@@ -2846,6 +2856,34 @@ iwx_setup_ht_rates(struct iwx_softc *sc)
 }
 
 void
+iwx_setup_vht_rates(struct iwx_softc *sc)
+{
+   struct ieee80211com *ic = >sc_ic;
+   uint8_t rx_ant = iwx_fw_valid_rx_ant(sc);
+   int n;
+
+   ic->ic_vht_rxmcs = (IEEE80211_VHT_MCS_0_9 <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(1));
+
+   if (iwx_mimo_enabled(sc) &&
+   ((rx_ant & IWX_ANT_AB) == IWX_ANT_AB ||
+   (rx_ant & IWX_ANT_BC) == IWX_ANT_BC)) {
+   ic->ic_vht_rxmcs |= (IEEE80211_VHT_MCS_0_9 <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(2));
+   } else {
+   ic->ic_vht_rxmcs |= (IEEE80211_VHT_MCS_SS_NOT_SUPP <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(2));
+   }
+
+   for (n = 3; n <= IEEE80211_VHT_NUM_SS; n++) {
+   ic->ic_vht_rxmcs |= (IEEE80211_VHT_MCS_SS_NOT_SUPP <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(n));
+   }
+
+   ic->ic_vht_txmcs = ic->ic_vht_rxmcs;
+}
+
+void
 iwx_init_reorder_buffer(struct iwx_reorder_buffer *reorder_buf,
 uint16_t ssn, uint16_t buf_size)
 {
@@ -3147,7 +3185,7 @@ iwx_phy_ctxt_task(void *arg)
struct ieee80211com *ic = >sc_ic;
struct iwx_node *in = (void *)ic->ic_bss;
struct ieee80211_node *ni = >in_ni;
-   uint8_t chains, sco;
+   uint8_t chains, sco, vht_chan_width;
int err, s = splnet();
 
if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) ||
@@ -3159,13 +3197,23 @@ iwx_phy_ctxt_task(void *arg)
}
 
chains = iwx_mimo_enabled(sc) ? 2 : 1;
-   if (ieee80211_node_supports_ht_chan40(ni))
+   if ((ni->ni_flags & IEEE80211_NODE_HT) &&

Re: initial iwx(4) 11ac patch for testing

2022-03-10 Thread Stefan Sperling
On Wed, Mar 09, 2022 at 01:07:47PM +0100, Stefan Sperling wrote:
> This patch adds initial 11ac support to the iwx(4) driver.
> This means that 80MHz channels can be used. No other 11ac features
> are enabled yet.
> 
> This is not yet a patch which could be committed. Apart from debug
> prints which need to go, there is a known issue found by dv@ where
> this patch causes a firmware error, sysassert 0x20101A25. The reason
> for this is not known.
> It would help to get more testing to see if more clues can be found
> based on where this error pops up. I cannot reproduce the error myself.

Thanks to a hint from Johannes Berg from Linux/Intel, the above problem
has been found.

In some channel configurations we would end up running the PHY at 20MHz
but ask for Tx rates using 80MHz, which caused sysassert 0x20101A25.
This is fixed here.

I have also removed debug prints.

Unless anyone else finds a problem, this patch can be considered ready
for review and commit.

diff refs/heads/master refs/heads/11ac
blob - 57bdcce64458e7f9d5802ce4247d5651f9183200
blob + f423379b313d1dbdba3c05e45c7d35e74056409b
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -304,6 +304,7 @@ int iwx_schedule_session_protection(struct iwx_softc *
uint32_t);
 void   iwx_init_channel_map(struct iwx_softc *, uint16_t *, uint32_t *, int);
 void   iwx_setup_ht_rates(struct iwx_softc *);
+void   iwx_setup_vht_rates(struct iwx_softc *);
 intiwx_mimo_enabled(struct iwx_softc *);
 void   iwx_mac_ctxt_task(void *);
 void   iwx_phy_ctxt_task(void *);
@@ -363,12 +364,13 @@ void  iwx_clear_oactive(struct iwx_softc *, struct 
iwx_
 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);
+uint8_tiwx_get_vht_ctrl_pos(struct ieee80211com *, struct 
ieee80211_channel *);
 intiwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *, struct iwx_phy_ctxt *, 
uint8_t,
-   uint8_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint8_t, uint8_t);
 intiwx_phy_ctxt_cmd_v3(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint8_t, uint8_t);
 intiwx_phy_ctxt_cmd(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint32_t, uint8_t, uint8_t);
 intiwx_send_cmd(struct iwx_softc *, struct iwx_host_cmd *);
 intiwx_send_cmd_pdu(struct iwx_softc *, uint32_t, uint32_t, uint16_t,
const void *);
@@ -430,10 +432,12 @@ int   iwx_scan_abort(struct iwx_softc *);
 intiwx_enable_mgmt_queue(struct iwx_softc *);
 intiwx_rs_rval2idx(uint8_t);
 uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ieee80211_node *, int);
+uint16_t iwx_rs_vht_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_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *,
-   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t);
+   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t,
+   uint8_t);
 intiwx_auth(struct iwx_softc *);
 intiwx_deauth(struct iwx_softc *);
 intiwx_run(struct iwx_softc *);
@@ -2812,6 +2816,12 @@ iwx_init_channel_map(struct iwx_softc *sc, uint16_t *c
if (ch_flags & IWX_NVM_CHANNEL_40MHZ)
channel->ic_flags |= IEEE80211_CHAN_40MHZ;
}
+
+   if (is_5ghz && data->sku_cap_11ac_enable) {
+   channel->ic_flags |= IEEE80211_CHAN_VHT;
+   if (ch_flags & IWX_NVM_CHANNEL_80MHZ)
+   channel->ic_xflags |= IEEE80211_CHANX_80MHZ;
+   }
}
 }
 
@@ -2846,6 +2856,34 @@ iwx_setup_ht_rates(struct iwx_softc *sc)
 }
 
 void
+iwx_setup_vht_rates(struct iwx_softc *sc)
+{
+   struct ieee80211com *ic = >sc_ic;
+   uint8_t rx_ant = iwx_fw_valid_rx_ant(sc);
+   int n;
+
+   ic->ic_vht_rxmcs = (IEEE80211_VHT_MCS_0_9 <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(1));
+
+   if (iwx_mimo_enabled(sc) &&
+   ((rx_ant & IWX_ANT_AB) == IWX_ANT_AB ||
+   (rx_ant & IWX_ANT_BC) == IWX_ANT_BC)) {
+   ic->ic_vht_rxmcs |= (IEEE80211_VHT_MCS_0_9 <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(2));
+   } else {
+   ic->ic_vht_rxmcs |= (IEEE80211_VHT_MCS_SS_NOT_SUPP <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(2));
+   }
+
+   for (n = 3; n <= IEEE80211_VHT_NUM_SS; n++) {
+   ic->ic_vht_rxmcs |= (IEEE80211_VHT_MCS_SS_NOT_SUPP <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(n));
+   }
+
+   ic->ic_vht_

Re: initial iwx(4) 11ac patch for testing

2022-03-10 Thread Stefan Sperling
On Wed, Mar 09, 2022 at 07:16:41PM +0300, Mikhail wrote:
> On Wed, Mar 09, 2022 at 01:07:47PM +0100, Stefan Sperling wrote:
> >  /*
> > + * Install received VHT caps information in the node's state block.
> > + */
> > +void
> > +ieee80211_setup_vhtcaps(struct ieee80211_node *ni, const uint8_t *data,
> > +uint8_t len)
> > +{
> > +   if (len != 12)
> > +   return;
> > +
> > +   ni->ni_vhtcaps = (data[0] | (data[1] << 8) | data[2] << 16 |
> > +   data[3] << 24);
> > +   ni->ni_vht_rxmcs = (data[4] | (data[5] << 8));
> > +   ni->ni_vht_rx_max_lgi_mbit_s = ((data[6] | (data[7] << 8)) &
> > +   IEEE80211_VHT_MAX_LGI_MBIT_S_MASK);
> > +   ni->ni_vht_txmcs = (data[8] | (data[9] << 8));
> > +   ni->ni_vht_tx_max_lgi_mbit_s = ((data[10] | (data[11] << 8)) &
> > +   IEEE80211_VHT_MAX_LGI_MBIT_S_MASK);
> > +
> > +   ni->ni_flags |= IEEE80211_NODE_VHTCAP;
> > +}
> 
> I understand that this function do things like ieee80211_setup_htcaps()
> (HT, 802.11n), which is mature, working and stable, but is there a
> reason not to return 0 on error, 1 on success, and check it in the
> caller (like in ieee80211_setup_vhtop())?

Doesn't really matter. We can decide to ignore just the VHT cap IE, or
we can discard the whole beacon. Either way, VHT won't be enabled.

> > +/* Check if the peer supports VHT short guard interval (SGI) on 160 MHz. */
> > +static inline int
> > +ieee80211_node_supports_vht_sgi160(struct ieee80211_node *ni)
> > +{
> > +   return ieee80211_node_supports_vht(ni) &&
> > +   (ni->ni_vhtcaps & IEEE80211_VHTCAP_SGI160);
> > +}
> 
> This function is unused.

I added it for future use.

> The patch for whitespacing:

Thanks. I will keep this for later instead of mixing it in right now.
I can then commit it separately and attribute it to you in the log message.



initial iwx(4) 11ac patch for testing

2022-03-09 Thread Stefan Sperling
This patch adds initial 11ac support to the iwx(4) driver.
This means that 80MHz channels can be used. No other 11ac features
are enabled yet.

This is not yet a patch which could be committed. Apart from debug
prints which need to go, there is a known issue found by dv@ where
this patch causes a firmware error, sysassert 0x20101A25. The reason
for this is not known.
It would help to get more testing to see if more clues can be found
based on where this error pops up. I cannot reproduce the error myself.

When sending feedback, please be clear about which iwx(4) device and
which access point has been tested. Thanks!

The patch works for me on AX200 and AX201 with a pepwave AC one mini AP,
although throughput is not much different to 11n 40MHz with this AP.

diff refs/heads/master refs/heads/11ac
blob - 57bdcce64458e7f9d5802ce4247d5651f9183200
blob + a56c59f82c854c282a61c302162df4eae3c27fb8
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -304,6 +304,7 @@ int iwx_schedule_session_protection(struct iwx_softc *
uint32_t);
 void   iwx_init_channel_map(struct iwx_softc *, uint16_t *, uint32_t *, int);
 void   iwx_setup_ht_rates(struct iwx_softc *);
+void   iwx_setup_vht_rates(struct iwx_softc *);
 intiwx_mimo_enabled(struct iwx_softc *);
 void   iwx_mac_ctxt_task(void *);
 void   iwx_phy_ctxt_task(void *);
@@ -363,12 +364,13 @@ void  iwx_clear_oactive(struct iwx_softc *, struct 
iwx_
 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);
+uint8_tiwx_get_vht_ctrl_pos(struct ieee80211com *, struct 
ieee80211_channel *);
 intiwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *, struct iwx_phy_ctxt *, 
uint8_t,
-   uint8_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint8_t, uint8_t);
 intiwx_phy_ctxt_cmd_v3(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint8_t, uint8_t);
 intiwx_phy_ctxt_cmd(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t, uint8_t);
+   uint8_t, uint32_t, uint32_t, uint8_t, uint8_t);
 intiwx_send_cmd(struct iwx_softc *, struct iwx_host_cmd *);
 intiwx_send_cmd_pdu(struct iwx_softc *, uint32_t, uint32_t, uint16_t,
const void *);
@@ -430,10 +432,12 @@ int   iwx_scan_abort(struct iwx_softc *);
 intiwx_enable_mgmt_queue(struct iwx_softc *);
 intiwx_rs_rval2idx(uint8_t);
 uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ieee80211_node *, int);
+uint16_t iwx_rs_vht_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_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *,
-   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t);
+   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t,
+   uint8_t);
 intiwx_auth(struct iwx_softc *);
 intiwx_deauth(struct iwx_softc *);
 intiwx_run(struct iwx_softc *);
@@ -2812,6 +2816,15 @@ iwx_init_channel_map(struct iwx_softc *sc, uint16_t *c
if (ch_flags & IWX_NVM_CHANNEL_40MHZ)
channel->ic_flags |= IEEE80211_CHAN_40MHZ;
}
+
+   if (is_5ghz && data->sku_cap_11ac_enable) {
+   channel->ic_flags |= IEEE80211_CHAN_VHT;
+   if (ch_flags & IWX_NVM_CHANNEL_80MHZ) {
+   printf("%s: channel %d 80MHz ok\n", __func__, 
hw_value);
+   channel->ic_xflags |= IEEE80211_CHANX_80MHZ;
+   } else
+   printf("%s: channel %d 80MHz NOT ok\n", 
__func__, hw_value);
+   }
}
 }
 
@@ -2846,6 +2859,34 @@ iwx_setup_ht_rates(struct iwx_softc *sc)
 }
 
 void
+iwx_setup_vht_rates(struct iwx_softc *sc)
+{
+   struct ieee80211com *ic = >sc_ic;
+   uint8_t rx_ant = iwx_fw_valid_rx_ant(sc);
+   int n;
+
+   ic->ic_vht_rxmcs = (IEEE80211_VHT_MCS_0_9 <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(1));
+
+   if (iwx_mimo_enabled(sc) &&
+   ((rx_ant & IWX_ANT_AB) == IWX_ANT_AB ||
+   (rx_ant & IWX_ANT_BC) == IWX_ANT_BC)) {
+   ic->ic_vht_rxmcs |= (IEEE80211_VHT_MCS_0_9 <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(2));
+   } else {
+   ic->ic_vht_rxmcs |= (IEEE80211_VHT_MCS_SS_NOT_SUPP <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(2));
+   }
+
+   for (n = 3; n <= IEEE80211_VHT_NUM_SS; n++) {
+   ic->ic_vht_rxmcs |= (IEEE80211_VHT_MCS_SS_NOT_SUPP <<
+   IEEE80211_VHT_MCS_FOR_SS_SHIFT(n));
+   }
+
+   ic->ic_vht_txmcs = ic->ic_vht_rxmcs;
+}
+
+void
 iwx_init_reorder_buffer(struct iwx_reorder_buffer *reorder_buf,
 

Re: ieee80211_stats userland vs. kernel

2022-03-09 Thread Stefan Sperling
On Tue, Mar 08, 2022 at 02:38:39PM -0700, Theo de Raadt wrote:
> Stefan Sperling  wrote:
> > In this case it is not ifconfig, but netstat -W iwm0.
> > Which is a debugging tool, like netstat -s.
> 
> We don't care when netstat breaks

Alright, then this diff is indeed not necessary.



Re: ieee80211_stats userland vs. kernel

2022-03-08 Thread Stefan Sperling
On Tue, Mar 08, 2022 at 12:58:27PM -0700, Theo de Raadt wrote:
> Claudio Jeker  wrote:
> 
> > Honestly I think this is overkill. There is no stat struct where we do
> > this dance. It is accepted that netstat needs to keep in sync for these
> > structs to work. Why is it necessary to disconnect the kernel and userland
> > for this?
> 
> Actually there is a major one: it is how ps works.
> 
> I think the problem is when this struct is changed, ifconfig becomes unusable?

In this case it is not ifconfig, but netstat -W iwm0.
Which is a debugging tool, like netstat -s.



Re: ieee80211_stats userland vs. kernel

2022-03-08 Thread Stefan Sperling
On Tue, Mar 08, 2022 at 03:55:48PM +0100, Stefan Sperling wrote:
> On Mon, Mar 07, 2022 at 03:04:06PM -0700, Theo de Raadt wrote:
> > > For now, the structs are identical so the code copying data out is
> > > kept simple.
> > 
> > I think this is unwise, and you should write the field-by-field copying
> > function at the same time, otherwise this is just asking for trouble.
> > You really cannot wait until an intentional change.
> 
> Sure, here it is.

On second thought, avoiding the malloc/free dance is better.
The struct is still small enough to fit on the stack.

diff refs/heads/master refs/heads/statsreq
blob - 85d795d745eb21fd218056c2f3faf7fbc2c7fe49
blob + 62938001ed22fc133a0c98e27ef5690c978e21f3
--- sys/net80211/ieee80211_ioctl.c
+++ sys/net80211/ieee80211_ioctl.c
@@ -55,6 +55,8 @@ void   ieee80211_node2req(struct ieee80211com *,
const struct ieee80211_node *, struct ieee80211_nodereq *);
 voidieee80211_req2node(struct ieee80211com *,
const struct ieee80211_nodereq *, struct ieee80211_node *);
+void ieee80211_stats2req(struct ieee80211_statsreq *,
+   struct ieee80211_stats *);
 
 void
 ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
@@ -180,6 +182,89 @@ ieee80211_req2node(struct ieee80211com *ic, const stru
 }
 
 void
+ieee80211_stats2req(struct ieee80211_statsreq *req,
+struct ieee80211_stats *stats)
+{
+   memset(req, 0, sizeof(*req));
+
+   req->is_rx_badversion = stats->is_rx_badversion;
+   req->is_rx_tooshort = stats->is_rx_tooshort;
+   req->is_rx_wrongbss = stats->is_rx_wrongbss;
+   req->is_rx_dup = stats->is_rx_dup;
+   req->is_rx_wrongdir = stats->is_rx_wrongdir;
+   req->is_rx_mcastecho = stats->is_rx_mcastecho;
+   req->is_rx_notassoc = stats->is_rx_notassoc;
+   req->is_rx_nowep = stats->is_rx_nowep;
+   req->is_rx_unencrypted = stats->is_rx_unencrypted;
+   req->is_rx_wepfail = stats->is_rx_wepfail;
+   req->is_rx_decap = stats->is_rx_decap;
+   req->is_rx_mgtdiscard = stats->is_rx_mgtdiscard;
+   req->is_rx_ctl = stats->is_rx_ctl;
+   req->is_rx_rstoobig = stats->is_rx_rstoobig;
+   req->is_rx_elem_missing = stats->is_rx_elem_missing;
+   req->is_rx_elem_toobig = stats->is_rx_elem_toobig;
+   req->is_rx_elem_toosmall = stats->is_rx_elem_toosmall;
+   req->is_rx_badchan = stats->is_rx_badchan;
+   req->is_rx_chanmismatch = stats->is_rx_chanmismatch;
+   req->is_rx_nodealloc = stats->is_rx_nodealloc;
+   req->is_rx_ssidmismatch = stats->is_rx_ssidmismatch;
+   req->is_rx_auth_unsupported = stats->is_rx_auth_unsupported;
+   req->is_rx_auth_fail = stats->is_rx_auth_fail;
+   req->is_rx_assoc_bss = stats->is_rx_assoc_bss;
+   req->is_rx_assoc_notauth = stats->is_rx_assoc_notauth;
+   req->is_rx_assoc_capmismatch = stats->is_rx_assoc_capmismatch;
+   req->is_rx_assoc_norate = stats->is_rx_assoc_norate;
+   req->is_rx_deauth = stats->is_rx_deauth;
+   req->is_rx_disassoc = stats->is_rx_disassoc;
+   req->is_rx_badsubtype = stats->is_rx_badsubtype;
+   req->is_rx_nombuf = stats->is_rx_nombuf;
+   req->is_rx_decryptcrc = stats->is_rx_decryptcrc;
+   req->is_rx_ahdemo_mgt = stats->is_rx_ahdemo_mgt;
+   req->is_rx_bad_auth = stats->is_rx_bad_auth;
+   req->is_tx_nombuf = stats->is_tx_nombuf;
+   req->is_tx_nonode = stats->is_tx_nonode;
+   req->is_tx_unknownmgt = stats->is_tx_unknownmgt;
+   req->is_scan_active = stats->is_scan_active;
+   req->is_scan_passive = stats->is_scan_passive;
+   req->is_node_timeout = stats->is_node_timeout;
+   req->is_crypto_nomem = stats->is_crypto_nomem;
+   req->is_rx_assoc_badrsnie = stats->is_rx_assoc_badrsnie;
+   req->is_rx_unauth = stats->is_rx_unauth;
+   req->is_tx_noauth = stats->is_tx_noauth;
+   req->is_rx_eapol_key = stats->is_rx_eapol_key;
+   req->is_rx_eapol_replay = stats->is_rx_eapol_replay;
+   req->is_rx_eapol_badmic = stats->is_rx_eapol_badmic;
+   req->is_rx_remmicfail = stats->is_rx_remmicfail;
+   req->is_rx_locmicfail = stats->is_rx_locmicfail;
+   req->is_tkip_replays = stats->is_tkip_replays;
+   req->is_tkip_icv_errs = stats->is_tkip_icv_errs;
+   req->is_ccmp_replays = stats->is_ccmp_replays;
+   req->is_ccmp_dec_errs = stats->is_ccmp_dec_errs;
+   req->is_cmac_replays = stats->is_cmac_replays;
+   req->is_cmac_icv_errs = stats->is_cmac_icv_errs;
+   req->is_pbac_errs = stats->is_pbac_errs;
+   req->is_ht_nego_no_mandatory_mcs = stats->is_ht_nego_no_ma

Re: ieee80211_stats userland vs. kernel

2022-03-08 Thread Stefan Sperling
On Mon, Mar 07, 2022 at 03:04:06PM -0700, Theo de Raadt wrote:
> > For now, the structs are identical so the code copying data out is
> > kept simple.
> 
> I think this is unwise, and you should write the field-by-field copying
> function at the same time, otherwise this is just asking for trouble.
> You really cannot wait until an intentional change.

Sure, here it is.

diff 0ed925b6612724f216b84360a04117aad1c6df9b 
6615def0a9e782a7fd930d75fda1ae4ec0f90dd2
blob - 85d795d745eb21fd218056c2f3faf7fbc2c7fe49
blob + d4f6b536b2eb2165f85f9df7c08a1cee36a428a4
--- sys/net80211/ieee80211_ioctl.c
+++ sys/net80211/ieee80211_ioctl.c
@@ -55,6 +55,7 @@ void   ieee80211_node2req(struct ieee80211com *,
const struct ieee80211_node *, struct ieee80211_nodereq *);
 voidieee80211_req2node(struct ieee80211com *,
const struct ieee80211_nodereq *, struct ieee80211_node *);
+struct ieee80211_statsreq *ieee80211_stats2req(struct ieee80211_stats *);
 
 void
 ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni,
@@ -179,6 +180,94 @@ ieee80211_req2node(struct ieee80211com *ic, const stru
ni->ni_state = nr->nr_state;
 }
 
+struct ieee80211_statsreq *
+ieee80211_stats2req(struct ieee80211_stats *stats)
+{
+   struct ieee80211_statsreq *req;
+
+   req = malloc(sizeof(*req), M_DEVBUF, M_ZERO | M_WAITOK | M_CANFAIL);
+   if (req == NULL)
+   return NULL;
+
+   req->is_rx_badversion = stats->is_rx_badversion;
+   req->is_rx_tooshort = stats->is_rx_tooshort;
+   req->is_rx_wrongbss = stats->is_rx_wrongbss;
+   req->is_rx_dup = stats->is_rx_dup;
+   req->is_rx_wrongdir = stats->is_rx_wrongdir;
+   req->is_rx_mcastecho = stats->is_rx_mcastecho;
+   req->is_rx_notassoc = stats->is_rx_notassoc;
+   req->is_rx_nowep = stats->is_rx_nowep;
+   req->is_rx_unencrypted = stats->is_rx_unencrypted;
+   req->is_rx_wepfail = stats->is_rx_wepfail;
+   req->is_rx_decap = stats->is_rx_decap;
+   req->is_rx_mgtdiscard = stats->is_rx_mgtdiscard;
+   req->is_rx_ctl = stats->is_rx_ctl;
+   req->is_rx_rstoobig = stats->is_rx_rstoobig;
+   req->is_rx_elem_missing = stats->is_rx_elem_missing;
+   req->is_rx_elem_toobig = stats->is_rx_elem_toobig;
+   req->is_rx_elem_toosmall = stats->is_rx_elem_toosmall;
+   req->is_rx_badchan = stats->is_rx_badchan;
+   req->is_rx_chanmismatch = stats->is_rx_chanmismatch;
+   req->is_rx_nodealloc = stats->is_rx_nodealloc;
+   req->is_rx_ssidmismatch = stats->is_rx_ssidmismatch;
+   req->is_rx_auth_unsupported = stats->is_rx_auth_unsupported;
+   req->is_rx_auth_fail = stats->is_rx_auth_fail;
+   req->is_rx_assoc_bss = stats->is_rx_assoc_bss;
+   req->is_rx_assoc_notauth = stats->is_rx_assoc_notauth;
+   req->is_rx_assoc_capmismatch = stats->is_rx_assoc_capmismatch;
+   req->is_rx_assoc_norate = stats->is_rx_assoc_norate;
+   req->is_rx_deauth = stats->is_rx_deauth;
+   req->is_rx_disassoc = stats->is_rx_disassoc;
+   req->is_rx_badsubtype = stats->is_rx_badsubtype;
+   req->is_rx_nombuf = stats->is_rx_nombuf;
+   req->is_rx_decryptcrc = stats->is_rx_decryptcrc;
+   req->is_rx_ahdemo_mgt = stats->is_rx_ahdemo_mgt;
+   req->is_rx_bad_auth = stats->is_rx_bad_auth;
+   req->is_tx_nombuf = stats->is_tx_nombuf;
+   req->is_tx_nonode = stats->is_tx_nonode;
+   req->is_tx_unknownmgt = stats->is_tx_unknownmgt;
+   req->is_scan_active = stats->is_scan_active;
+   req->is_scan_passive = stats->is_scan_passive;
+   req->is_node_timeout = stats->is_node_timeout;
+   req->is_crypto_nomem = stats->is_crypto_nomem;
+   req->is_rx_assoc_badrsnie = stats->is_rx_assoc_badrsnie;
+   req->is_rx_unauth = stats->is_rx_unauth;
+   req->is_tx_noauth = stats->is_tx_noauth;
+   req->is_rx_eapol_key = stats->is_rx_eapol_key;
+   req->is_rx_eapol_replay = stats->is_rx_eapol_replay;
+   req->is_rx_eapol_badmic = stats->is_rx_eapol_badmic;
+   req->is_rx_remmicfail = stats->is_rx_remmicfail;
+   req->is_rx_locmicfail = stats->is_rx_locmicfail;
+   req->is_tkip_replays = stats->is_tkip_replays;
+   req->is_tkip_icv_errs = stats->is_tkip_icv_errs;
+   req->is_ccmp_replays = stats->is_ccmp_replays;
+   req->is_ccmp_dec_errs = stats->is_ccmp_dec_errs;
+   req->is_cmac_replays = stats->is_cmac_replays;
+   req->is_cmac_icv_errs = stats->is_cmac_icv_errs;
+   req->is_pbac_errs = stats->is_pbac_errs;
+   req->is_ht_nego_no_mandatory_mcs = stats->is_ht_nego_no_mandatory_mcs;
+   req->is_ht_nego_no_basic_mcs = stats->is_ht_nego_no_basic_mcs;
+   req->is_ht_nego_bad_crypto = stats->is_ht_nego_bad_crypto;
+   req->is_ht_prot_change = stats->is_ht_prot_change;
+   req->is_ht_rx_ba_agreements = stats->is_ht_rx_ba_agreements;
+   req->is_ht_tx_ba_agreements = stats->is_ht_tx_ba_agreements;
+   req->is_ht_rx_frame_below_ba_winstart =
+   

ieee80211_stats userland vs. kernel

2022-03-07 Thread Stefan Sperling
There is another net80211 ioctl which shares a struct between kernel
and userland: struct ieee80211_stats shown by the netstat -W command.

While it is trivial to recompile netstat when this struct is changed,
giving the kernel a separate struct type would allow us to add, change,
or remove counters in the kernel without impacting userland immediately.
Is this worth it?

For now, the structs are identical so the code copying data out is
kept simple.

The struct is quite large and we could probably get rid of some of these
counters without losing useful debugging information, but that is a
separate problem.

Warning: This diff seems to overflow miniroot71.img on amd64,
breaking 'make release' builds without further changes.

diff 7f506de28f9813c0e2213a45686e27166679219e 
64e5109ffcdce254aca22d4a8a40991e792c0738
blob - 85d795d745eb21fd218056c2f3faf7fbc2c7fe49
blob + a3a734d32123ff96870e24efeb30651bfd0b50be
--- sys/net80211/ieee80211_ioctl.c
+++ sys/net80211/ieee80211_ioctl.c
@@ -810,17 +810,11 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
break;
}
break;
-#if 0
-   case SIOCG80211ZSTATS:
-#endif
case SIOCG80211STATS:
ifr = (struct ifreq *)data;
error = copyout(>ic_stats, ifr->ifr_data,
-   sizeof(ic->ic_stats));
-#if 0
-   if (cmd == SIOCG80211ZSTATS)
-   memset(>ic_stats, 0, sizeof(ic->ic_stats));
-#endif
+   MIN(sizeof(struct ieee80211_statsreq),
+   sizeof(struct ieee80211_stats)));
break;
case SIOCS80211TXPOWER:
if ((error = suser(curproc)) != 0)
blob - 65e93c23da2d86c0ad259f77b7c9affc85d9038b
blob + fa95ad15b809e16868e2eba4dba66568b5a66cfe
--- sys/net80211/ieee80211_ioctl.h
+++ sys/net80211/ieee80211_ioctl.h
@@ -37,8 +37,8 @@
  * IEEE 802.11 ioctls.
  */
 
-/* per-interface statistics */
-struct ieee80211_stats {
+/* per-interface statistics, corresponds to struct ieee80211_stats */
+struct ieee80211_statsreq {
u_int32_t   is_rx_badversion;   /* rx frame with bad version */
u_int32_t   is_rx_tooshort; /* rx frame too short */
u_int32_t   is_rx_wrongbss; /* rx from wrong bssid */
blob - 161853a629887a1aa997480d605d4febd66dd2db
blob + d8845bfc6aa1331110ca22ec949a00932645907e
--- sys/net80211/ieee80211_var.h
+++ sys/net80211/ieee80211_var.h
@@ -214,6 +214,81 @@ struct ieee80211_defrag {
 
 struct ieee80211_node_switch_bss_arg;
 
+/* per-interface statistics */
+struct ieee80211_stats {
+   u_int32_t   is_rx_badversion;   /* rx frame with bad version */
+   u_int32_t   is_rx_tooshort; /* rx frame too short */
+   u_int32_t   is_rx_wrongbss; /* rx from wrong bssid */
+   u_int32_t   is_rx_dup;  /* rx discard 'cuz dup */
+   u_int32_t   is_rx_wrongdir; /* rx w/ wrong direction */
+   u_int32_t   is_rx_mcastecho;/* rx discard 'cuz mcast echo */
+   u_int32_t   is_rx_notassoc; /* rx discard 'cuz sta !assoc */
+   u_int32_t   is_rx_nowep;/* rx w/ wep but wep !config */
+   u_int32_t   is_rx_unencrypted;  /* rx w/o wep but wep config */
+   u_int32_t   is_rx_wepfail;  /* rx wep processing failed */
+   u_int32_t   is_rx_decap;/* rx decapsulation failed */
+   u_int32_t   is_rx_mgtdiscard;   /* rx discard mgt frames */
+   u_int32_t   is_rx_ctl;  /* rx discard ctrl frames */
+   u_int32_t   is_rx_rstoobig; /* rx rate set truncated */
+   u_int32_t   is_rx_elem_missing; /* rx required element missing*/
+   u_int32_t   is_rx_elem_toobig;  /* rx element too big */
+   u_int32_t   is_rx_elem_toosmall;/* rx element too small */
+   u_int32_t   is_rx_badchan;  /* rx frame w/ invalid chan */
+   u_int32_t   is_rx_chanmismatch; /* rx frame chan mismatch */
+   u_int32_t   is_rx_nodealloc;/* rx frame dropped */
+   u_int32_t   is_rx_ssidmismatch; /* rx frame ssid mismatch  */
+   u_int32_t   is_rx_auth_unsupported; /* rx w/ unsupported auth alg */
+   u_int32_t   is_rx_auth_fail;/* rx sta auth failure */
+   u_int32_t   is_rx_assoc_bss;/* rx assoc from wrong bssid */
+   u_int32_t   is_rx_assoc_notauth;/* rx assoc w/o auth */
+   u_int32_t   is_rx_assoc_capmismatch;/* rx assoc w/ cap mismatch */
+   u_int32_t   is_rx_assoc_norate; /* rx assoc w/ no rate match */
+   u_int32_t   is_rx_deauth;   /* rx deauthentication */
+   u_int32_t   is_rx_disassoc; /* rx disassociation */
+   u_int32_t   is_rx_badsubtype;   /* rx frame w/ unknown subtype*/
+   u_int32_t   is_rx_nombuf;   /* rx 

fix net80211 ioctl name collision

2022-03-04 Thread Stefan Sperling
The net80211 ioctl which ifconfig is using to obtain a list of all
supported channels is using a struct name that belongs to the kernel.

Fix this by renaming struct ieee80211_channel to struct ieee80211_chaninfo
in ieee80211_ioctl.h. The way this is done here keeps both old and new
ifconfig binaries happy.

Passes make release on amd64.
I don't expect fallout in ports from this, though just in case I will
wait for a build which sthen@ is running.

diff a6aa266c049fd224e816ccc36f6389e99b7c2826 
7025912fb0f6924813974534ab33fc115d2f7369
blob - 8ee7b194d0be49a83771d72fe554b638fd116fdd
blob + 901c8412fd6d51a104b88a98850fc54132d54211
--- sbin/ifconfig/ifconfig.c
+++ sbin/ifconfig/ifconfig.c
@@ -116,6 +116,10 @@
 
 #include "ifconfig.h"
 
+#ifndef nitems
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
 #define MINIMUM(a, b)  (((a) < (b)) ? (a) : (b))
 #define MAXIMUM(a, b)  (((a) > (b)) ? (a) : (b))
 
@@ -2670,7 +2674,7 @@ join_status(void)
 void
 ieee80211_listchans(void)
 {
-   static struct ieee80211_channel chans[256+1];
+   static struct ieee80211_chaninfo chans[256];
struct ieee80211_chanreq_all ca;
int i;
 
@@ -2684,11 +2688,11 @@ ieee80211_listchans(void)
return;
}
printf("\t\t%4s  %-8s  %s\n", "chan", "freq", "properties");
-   for (i = 1; i <= 256; i++) {
-   if (chans[i].ic_flags == 0)
+   for (i = 1; i < nitems(chans); i++) {
+   if (chans[i].ic_freq == 0)
continue;
printf("\t\t%4d  %4d MHz  ", i, chans[i].ic_freq);
-   if (chans[i].ic_flags & IEEE80211_CHAN_PASSIVE)
+   if (chans[i].ic_flags & IEEE80211_CHANINFO_PASSIVE)
printf("passive scan");
else
putchar('-');
blob - e3da39394d224807bec39c777026f26e2a3022ba
blob + 64731538bdb47877bfce0bc3daa8d61d40de4bae
--- sys/net80211/ieee80211_ioctl.c
+++ sys/net80211/ieee80211_ioctl.c
@@ -469,6 +469,8 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
struct ieee80211_nodereq *nr, nrbuf;
struct ieee80211_nodereq_all *na;
struct ieee80211_node *ni;
+   struct ieee80211_chaninfo chaninfo;
+   struct ieee80211_chanreq_all *allchans;
u_int32_t flags;
 
switch (cmd) {
@@ -791,9 +793,22 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
break;
case SIOCG80211ALLCHANS:
-   error = copyout(ic->ic_channels,
-   ((struct ieee80211_chanreq_all *)data)->i_chans,
-   sizeof(ic->ic_channels));
+   allchans = (struct ieee80211_chanreq_all *)data;
+   for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
+   chan = >ic_channels[i];
+   chaninfo.ic_freq = chan->ic_freq;
+   chaninfo.ic_flags = 0;
+   if (chan->ic_flags & IEEE80211_CHAN_2GHZ)
+   chaninfo.ic_flags |= IEEE80211_CHANINFO_2GHZ;
+   if (chan->ic_flags & IEEE80211_CHAN_5GHZ)
+   chaninfo.ic_flags |= IEEE80211_CHANINFO_5GHZ;
+   if (chan->ic_flags & IEEE80211_CHAN_PASSIVE)
+   chaninfo.ic_flags |= IEEE80211_CHANINFO_PASSIVE;
+   error = copyout(, >i_chans[i],
+   sizeof(chaninfo));
+   if (error)
+   break;
+   }
break;
 #if 0
case SIOCG80211ZSTATS:
blob - 20647ca5ee94709bb6bcbe5cb596e3b9270e4b8a
blob + bcfe3141aaa9286ceee30453614650c82d84ba9b
--- sys/net80211/ieee80211_ioctl.h
+++ sys/net80211/ieee80211_ioctl.h
@@ -161,31 +161,24 @@ struct ieee80211chanreq {
u_int16_t   i_channel;
 };
 
-#ifndef _KERNEL
 /*
  * Channels are specified by frequency and attributes.
  */
-struct ieee80211_channel {
+struct ieee80211_chaninfo {
u_int16_t   ic_freq;/* setting in MHz */
u_int16_t   ic_flags;   /* see below */
 };
 
 /*
- * Channel attributes (XXX must keep in sync with radiotap flags).
+ * Channel attributes.
  */
-#define IEEE80211_CHAN_CCK 0x0020  /* CCK channel */
-#define IEEE80211_CHAN_OFDM0x0040  /* OFDM channel */
-#define IEEE80211_CHAN_2GHZ0x0080  /* 2 GHz spectrum channel */
-#define IEEE80211_CHAN_5GHZ0x0100  /* 5 GHz spectrum channel */
-#define IEEE80211_CHAN_PASSIVE 0x0200  /* Only passive scan allowed */
-#define IEEE80211_CHAN_DYN 0x0400  /* Dynamic CCK-OFDM channel */
-#define IEEE80211_CHAN_XR  0x1000  /* Extended range OFDM channel */
-#define IEEE80211_CHAN_HT  0x2000  /* 11n/HT channel */
-#endif /* !_KERNEL */
+#define IEEE80211_CHANINFO_2GHZ0x0080  /* 2 GHz spectrum 
channel */
+#define IEEE80211_CHANINFO_5GHZ0x0100  /* 5 GHz 

Re: add openvpn 1194/udp/tcp port to /etc/services

2022-03-01 Thread Stefan Sperling
On Tue, Mar 01, 2022 at 10:41:14AM +, Stuart Henderson wrote:
> Probably best to wait a bit for other feedback, but: OK sthen

Ok from me, too. Some of my subnets are routed to me via OpenVPN so
I will be forced to keep using it for the foreseeable future.

I have $openvpn_port variables in some pf.conf files...



Re: A program compiled with '-pg' option always gets SEGV on its execution.

2022-02-21 Thread Stefan Sperling
On Mon, Feb 21, 2022 at 10:20:17AM +0100, Marc Espie wrote:
> On Mon, Feb 21, 2022 at 05:36:16PM +0900, Yuichiro NAITO wrote:
> > Of course, all programs compiled without '-pg' work fine for me.
> > I found this issue when I profile my application with gprof(1).
> > For example, following example C source code fails to execute on OpenBSD 
> > 7.0.
> 
> Profile is partly broken and has been for a while.
> 
> Compiling with -static and removing any pledge() call allow profiling to work.

Yes, and the proposed patch effectively enables -static if -pg is used.
I don't know if this the best fix. But this issue keeps popping up and
it would be nice to have something that works out of the box.
I would not mind this patch going in.

Pledge and unveil interfering with profiling is a separate issue which
is more obvious when it occurs and can easily be worked around by the
developer.



Re: fix active scan on iwm and iwx

2022-02-08 Thread Stefan Sperling
On Tue, Jan 25, 2022 at 11:22:45AM +0100, Mark Kettenis wrote:
> > The KASSERT triggers but for the wrong reason: We don't have outstanding
> > tasks, we have a bad reference counter. Only setting the ref counter to 1 if
> > we are about to launch a task during resume should fix it, and this matches
> > what iwx(4) is doing:
> 
> Running this now.  May take some time to reproduce the issue though.

Any news?  I would like to commit this patch.

> > diff d26399562c831a7212cebc57463cc9931ff8aff2 /usr/src
> > blob - 937f2cc28f6c85502031e4c9efa0a02c75fd1a6d
> > file + sys/dev/pci/if_iwm.c
> > --- sys/dev/pci/if_iwm.c
> > +++ sys/dev/pci/if_iwm.c
> > @@ -11719,8 +11719,6 @@ iwm_wakeup(struct iwm_softc *sc)
> > struct ifnet *ifp = >sc_ic.ic_if;
> > int err;
> >  
> > -   refcnt_init(>task_refs);
> > -
> > err = iwm_start_hw(sc);
> > if (err)
> > return err;
> > @@ -11729,6 +11727,7 @@ iwm_wakeup(struct iwm_softc *sc)
> > if (err)
> > return err;
> >  
> > +   refcnt_init(>task_refs);
> > ifq_clr_oactive(>if_snd);
> > ifp->if_flags |= IFF_RUNNING;
> >  
> > 
> 



Re: fix active scan on iwm and iwx

2022-01-25 Thread Stefan Sperling
On Tue, Jan 25, 2022 at 09:32:21AM +0100, Mark Kettenis wrote:
> Happened again while still on a Jan 16 snapshot kernel.  So it is not
> related to that diff.
> 
> Here is the panic message and backtrace:
> 
> panic: kernel diagnostic assertion "sc->task_refs.refs == 0" failed: file 
> "/usr/src/sys/dev/pci/if_iwm.c", line 9981
> Stopped at  db_enter+0x10:  popq%rbp
> TIDPIDUID PRFLAGS PFLAGS  CPU  COMMAND
> *120744  85293  0 0x3  00K ifconfig
> db_enter() at db_enter+0x10
> panic() at panic+0xbf
> __assert() at __assert+0x25
> iwm_init() at iwm_init+0x254
> iwm_ioctl() at iwm_ioctl+0xf9
> ifioctl() at ifioctl+0x92b
> soo_ioctl() at soo_ioctl+0x161
> sys_ioctl() at sys_ioctl+0x2c4
> syscall() at syscall+0x374
> Xsyscall() at Xsyscall+0x128
> end of kernel
> 

Please try this patch.

Upon resume we, set the task ref count to 1 in anticipation of
the newstate task that will be triggered to move into SCAN state.
iwm_add_task would bump the refcount to 2. The task would decrease
refcount again when it is done, and refcnt_finalize() in iwm_stop()
would eventually let the counter drop back to zero.

Now, for some reason on your system the device is not responding to
the driver's attempt to claim ownership. This looks like maybe some
problem with the bus the device is attached to. I am not in a position
to debug that issue, perhaps you could try? In any case, iwx_wakeup()
errors out early, with task refcount 1 but with no task scheduled and
IFF_RUNNING not set (meaning ioctl will not call iwm_stop()).

Later, you run ifconfig, the ioctl handler runs, and calls iwm_init().
This function expects that we are in a clean initial state (as after boot),
such that iwm_stop() was called beforehand to clear out any tasks, dropping
the task ref counter back to zero.

The KASSERT triggers but for the wrong reason: We don't have outstanding
tasks, we have a bad reference counter. Only setting the ref counter to 1 if
we are about to launch a task during resume should fix it, and this matches
what iwx(4) is doing:

diff d26399562c831a7212cebc57463cc9931ff8aff2 /usr/src
blob - 937f2cc28f6c85502031e4c9efa0a02c75fd1a6d
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -11719,8 +11719,6 @@ iwm_wakeup(struct iwm_softc *sc)
struct ifnet *ifp = >sc_ic.ic_if;
int err;
 
-   refcnt_init(>task_refs);
-
err = iwm_start_hw(sc);
if (err)
return err;
@@ -11729,6 +11727,7 @@ iwm_wakeup(struct iwm_softc *sc)
if (err)
return err;
 
+   refcnt_init(>task_refs);
ifq_clr_oactive(>if_snd);
ifp->if_flags |= IFF_RUNNING;
 



Re: fix active scan on iwm and iwx

2022-01-21 Thread Stefan Sperling
On Sun, Jan 16, 2022 at 07:38:11PM +0100, Mark Kettenis wrote:
> > Date: Sun, 16 Jan 2022 19:28:06 +0100
> > From: Stefan Sperling 
> > 
> > On Sun, Jan 16, 2022 at 03:50:55PM +0100, Mark Kettenis wrote:
> > > However, running this diff I had a problem after resuming my laptop
> > > twice. After resume the interface didn't work and I found the
> > > following in dmesg:
> > > 
> > > iwm0: could not initialize hardware
> > > 
> > > I tried to reset the interface by bringing it down and up again, which
> > > crashed the machine.  It must have been in ddb since typing "bo re"
> > > made it reset.  Unfortunately I don't have further information since I
> > > was in X.
> > 
> > Did you try reproducing this problem without the patch in place?
> > It would be good to know whether this problem is being introduced by
> > this patch. I don't believe this is likely, my bet would be that this
> > is an existing problem. But it would be good to know for sure.
> 
> Yes.  I switched back to regular snapshots.  Will keep you posted.
> 

Any news?

I have unsuccessfully tried to reproduce this problem on a laptop
with a 9560 iwm device, via both S3 suspend and hibernate.
I do not have a 9260 device in a machine which can suspend, unfortunately.

This was not a problem that occurred for you consistently, was it?
If so, even if you have not yet seen the failure without the patch,
I would like to commit this patch to unblock further progress. If the
error happens for more people afterwards we could investigate further.
Hopefully someone will be able to provide a trace from ddb.



Re: fix active scan on iwm and iwx

2022-01-16 Thread Stefan Sperling
On Sun, Jan 16, 2022 at 03:50:55PM +0100, Mark Kettenis wrote:
> However, running this diff I had a problem after resuming my laptop
> twice. After resume the interface didn't work and I found the
> following in dmesg:
> 
> iwm0: could not initialize hardware
> 
> I tried to reset the interface by bringing it down and up again, which
> crashed the machine.  It must have been in ddb since typing "bo re"
> made it reset.  Unfortunately I don't have further information since I
> was in X.

Did you try reproducing this problem without the patch in place?
It would be good to know whether this problem is being introduced by
this patch. I don't believe this is likely, my bet would be that this
is an existing problem. But it would be good to know for sure.



Re: AX210 wifi

2022-01-16 Thread Stefan Sperling
On Sun, Jan 16, 2022 at 05:51:03PM +0300, Alex Beakes wrote:
> FreeBSD has tested iwlwifi with Intel(R) Wi-Fi 6 AX210 160MHz, REV=0x420.
> Wifi 6E, ty-a0-gf-a0-63.ucode.
> 
> Is there a way of implementing this and making the wifi module work.
> 
> https://wiki.freebsd.org/WiFi/Iwlwifi

I will likely work on AX210 suport sometimebut this year.
If anyone else has already done work on this and can provide working diffs
against the OpenBSD drivers I would be happy to review them.

Since FreeBSD has decided to no longer help with developing iwm or iwx
drivers, but implement a completely different approach instead, there is
no chance of cross-polination between the projects to make this any easier.



fix active scan on iwm and iwx

2022-01-13 Thread Stefan Sperling
At present active scans (which send probe requests, as opposed to
just listening for beacons) are disabled on iwm 9k and iwx. This
was done because firmware misbehaved after association.

zxystd from the OpenIntelWireless project has debugged the issue
and has sent me a patch against OpenBSD which fixes this problem. 
The patch is below, with some small tweaks by me which have already
been reviewed by zxystd.

It seems that firmware misbehaves if the driver sets the DTIM period
to zero. This value is read from TIM information elements (IE) in beacons.
Passive scans worked because we picked up the DTIM period from a beacon,
while probe responses received during active scans lack the TIM IE, which
resulted in a zero DTIM period being configured in firmware. We then never
updated TIM information when a beacon was recieved, letting firmware run
with a zero DTIM period until it eventually stopped working.

I have tested this patch on iwm 8265 and iwx ax200.
And jmc@ has been testing this on ax200 for some time.
More tests are welcome, on any supported device.

diff refs/heads/remove-find-node-for-beacon refs/heads/iwm-iwx-active-scan
blob - 607a45b71f7ea71773809136cadf122c72375558
blob + 937f2cc28f6c85502031e4c9efa0a02c75fd1a6d
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -340,6 +340,7 @@ voidiwm_updateprot(struct ieee80211com *);
 void   iwm_updateslot(struct ieee80211com *);
 void   iwm_updateedca(struct ieee80211com *);
 void   iwm_updatechan(struct ieee80211com *);
+void   iwm_updatedtim(struct ieee80211com *);
 void   iwm_init_reorder_buffer(struct iwm_reorder_buffer *, uint16_t,
uint16_t);
 void   iwm_clear_reorder_buffer(struct iwm_softc *, struct iwm_rxba_data *);
@@ -3374,6 +3375,8 @@ iwm_mac_ctxt_task(void *arg)
err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_MODIFY, 1);
if (err)
printf("%s: failed to update MAC\n", DEVNAME(sc));
+   
+   iwm_unprotect_session(sc, in);
 
refcnt_rele_wake(>task_refs);
splx(s);
@@ -3454,6 +3457,16 @@ iwm_updatechan(struct ieee80211com *ic)
iwm_add_task(sc, systq, >phy_ctxt_task);
 }
 
+void
+iwm_updatedtim(struct ieee80211com *ic)
+{
+   struct iwm_softc *sc = ic->ic_softc;
+
+   if (ic->ic_state == IEEE80211_S_RUN &&
+   !task_pending(>newstate_task))
+   iwm_add_task(sc, systq, >mac_ctxt_task);
+}
+
 int
 iwm_sta_tx_agg(struct iwm_softc *sc, struct ieee80211_node *ni, uint8_t tid,
 uint16_t ssn, uint16_t winsize, int start)
@@ -7275,12 +7288,7 @@ iwm_lmac_scan_fill_channels(struct iwm_softc *sc,
chan->iter_count = htole16(1);
chan->iter_interval = 0;
chan->flags = htole32(IWM_UNIFIED_SCAN_CHANNEL_PARTIAL);
-   /*
-* Firmware may become unresponsive when asked to send
-* a directed probe request on a passive channel.
-*/
-   if (n_ssids != 0 && !bgscan &&
-   (c->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
+   if (n_ssids != 0 && !bgscan)
chan->flags |= htole32(1 << 1); /* select SSID 0 */
chan++;
nchan++;
@@ -7307,12 +7315,7 @@ iwm_umac_scan_fill_channels(struct iwm_softc *sc,
chan->channel_num = ieee80211_mhz2ieee(c->ic_freq, 0);
chan->iter_count = 1;
chan->iter_interval = htole16(0);
-   /*
-* Firmware may become unresponsive when asked to send
-* a directed probe request on a passive channel.
-*/
-   if (n_ssids != 0 && !bgscan &&
-   (c->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
+   if (n_ssids != 0 && !bgscan)
chan->flags = htole32(1 << 0); /* select SSID 0 */
chan++;
nchan++;
@@ -7782,13 +7785,7 @@ iwm_umac_scan(struct iwm_softc *sc, int bgscan)
IWM_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER;
}
 
-   /*
-* Check if we're doing an active directed scan.
-* 9k devices may randomly lock up (no interrupts) after association
-* following active scans. Use passive scan only for now on 9k.
-*/
-   if (sc->sc_device_family != IWM_DEVICE_FAMILY_9000 &&
-   ic->ic_des_esslen != 0) {
+   if (ic->ic_des_esslen != 0) {
if (isset(sc->sc_ucode_api,
IWM_UCODE_TLV_API_SCAN_EXT_CHAN_VER)) {
tail->direct_scan[0].id = IEEE80211_ELEMID_SSID;
@@ -11620,6 +11617,7 @@ iwm_attach(struct device *parent, struct device *self,
ic->ic_updateprot = iwm_updateprot;
ic->ic_updateslot = iwm_updateslot;
ic->ic_updateedca = iwm_updateedca;
+   ic->ic_updatedtim = iwm_updatedtim;
ic->ic_ampdu_rx_start = iwm_ampdu_rx_start;
ic->ic_ampdu_rx_stop = iwm_ampdu_rx_stop;

Re: uninitialized stack memory possibly passed to m_freem

2022-01-12 Thread Stefan Sperling
On Wed, Jan 12, 2022 at 11:30:44AM +0100, Moritz Buhl wrote:
> Hi tech@,
> 
> https://github.com/openbsd/src/commit/0ea6bae06233cd25645df14602c3eda6bdff7dca.patch
> 
> the patch forgot to add mrep to the info struct, nfsm_dissect could
> pass info.nmi_mrep to m_freem, which is currently uninitialized
> stack memory.
> 
> Index: sys/nfs/nfs_subs.c
> ===
> RCS file: /mount/openbsd/cvs/src/sys/nfs/nfs_subs.c,v
> retrieving revision 1.145
> diff -u -p -r1.145 nfs_subs.c
> --- sys/nfs/nfs_subs.c11 Jan 2022 03:13:59 -  1.145
> +++ sys/nfs/nfs_subs.c12 Jan 2022 09:31:52 -
> @@ -1841,6 +1841,7 @@ nfsm_srvsattr(struct mbuf **mp, struct v
>  
>   info.nmi_md = *mp;
>   info.nmi_dpos = *dposp;
> + info.nmi_mrep = mrep;
>  
>   nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
>   if (*tl == nfs_true) {
> 

OK stsp@ (without assuming any responsibility for NFS)



Re: sdmmc: fix malloc error handling in sdmmc_mem_send_scr()

2022-01-10 Thread Stefan Sperling
On Mon, Jan 10, 2022 at 04:35:41PM +0100, Tobias Heider wrote:
> On Mon, Jan 10, 2022 at 04:20:36PM +0100, Stefan Sperling wrote:
> > On Mon, Jan 10, 2022 at 03:50:45PM +0100, Tobias Heider wrote:
> > > Makes sense. I also fixed the one in sdmmc_mem_send_cxd_data().
> > 
> > Doesn't build here, there a few errors like this:
> > 
> > /usr/src/sys/dev/sdmmc/sdmmc_mem.c:483:1: error: unused label 'out' 
> > [-Werror,-Wu
> > nused-label] 
> > 
> > I like Visa's idea of using early 'return ENOMEM' instead of goto.
> 
> I removed the unused goto labels and cleaned up the error handling.
> We don't need to check for (ptr != NULL) and in one case we can
> merge two 'if (error == 0)' blocks.
> 
> ok?

ok stsp@

> Index: sdmmc_mem.c
> ===
> RCS file: /mount/openbsd/cvs/src/sys/dev/sdmmc/sdmmc_mem.c,v
> retrieving revision 1.36
> diff -u -p -r1.36 sdmmc_mem.c
> --- sdmmc_mem.c   27 Mar 2021 14:36:28 -  1.36
> +++ sdmmc_mem.c   10 Jan 2022 05:20:37 -
> @@ -466,7 +466,7 @@ sdmmc_mem_send_scr(struct sdmmc_softc *s
>  
>   ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
>   if (ptr == NULL)
> - goto out;
> + return ENOMEM;
>  
>   memset(, 0, sizeof(cmd));
>   cmd.c_data = ptr;
> @@ -480,9 +480,7 @@ sdmmc_mem_send_scr(struct sdmmc_softc *s
>   if (error == 0)
>   memcpy(scr, ptr, datalen);
>  
> -out:
> - if (ptr != NULL)
> - free(ptr, M_DEVBUF, datalen);
> + free(ptr, M_DEVBUF, datalen);
>  
>   return error;
>  }
> @@ -528,10 +526,8 @@ sdmmc_mem_send_cxd_data(struct sdmmc_sof
>   int error = 0;
>  
>   ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
> - if (ptr == NULL) {
> - error = ENOMEM;
> - goto out;
> - }
> + if (ptr == NULL)
> + return ENOMEM;
>  
>   memset(, 0, sizeof(cmd));
>   cmd.c_data = ptr;
> @@ -549,9 +545,7 @@ sdmmc_mem_send_cxd_data(struct sdmmc_sof
>   if (error == 0)
>   memcpy(data, ptr, datalen);
>  
> -out:
> - if (ptr != NULL)
> - free(ptr, M_DEVBUF, datalen);
> + free(ptr, M_DEVBUF, datalen);
>  
>   return error;
>  }
> @@ -608,7 +602,7 @@ sdmmc_mem_sd_switch(struct sdmmc_functio
>  
>   ptr = malloc(statlen, M_DEVBUF, M_NOWAIT | M_ZERO);
>   if (ptr == NULL)
> - goto out;
> + return ENOMEM;
>  
>   memset(, 0, sizeof(cmd));
>   cmd.c_data = ptr;
> @@ -620,15 +614,12 @@ sdmmc_mem_sd_switch(struct sdmmc_functio
>   cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
>  
>   error = sdmmc_mmc_command(sc, );
> - if (error == 0)
> + if (error == 0) {
>   memcpy(status, ptr, statlen);
> -
> -out:
> - if (ptr != NULL)
> - free(ptr, M_DEVBUF, statlen);
> -
> - if (error == 0)
>   sdmmc_be512_to_bitfield512(status);
> + }
> +
> + free(ptr, M_DEVBUF, statlen);
>  
>   return error;
>  }
> 
> 



Re: sdmmc: fix malloc error handling in sdmmc_mem_send_scr()

2022-01-10 Thread Stefan Sperling
On Mon, Jan 10, 2022 at 03:50:45PM +0100, Tobias Heider wrote:
> Makes sense. I also fixed the one in sdmmc_mem_send_cxd_data().

Doesn't build here, there a few errors like this:

/usr/src/sys/dev/sdmmc/sdmmc_mem.c:483:1: error: unused label 'out' [-Werror,-Wu
nused-label] 

I like Visa's idea of using early 'return ENOMEM' instead of goto.

> diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c
> index fae8d63912d..d46b1d612be 100644
> --- a/sys/dev/sdmmc/sdmmc_mem.c
> +++ b/sys/dev/sdmmc/sdmmc_mem.c
> @@ -466,7 +466,7 @@ sdmmc_mem_send_scr(struct sdmmc_softc *sc, uint32_t *scr)
>  
>   ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
>   if (ptr == NULL)
> - goto out;
> + return ENOMEM;
>  
>   memset(, 0, sizeof(cmd));
>   cmd.c_data = ptr;
> @@ -528,10 +528,8 @@ sdmmc_mem_send_cxd_data(struct sdmmc_softc *sc, int 
> opcode, void *data,
>   int error = 0;
>  
>   ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
> - if (ptr == NULL) {
> - error = ENOMEM;
> - goto out;
> - }
> + if (ptr == NULL)
> + return ENOMEM;
>  
>   memset(, 0, sizeof(cmd));
>   cmd.c_data = ptr;
> @@ -608,7 +606,7 @@ sdmmc_mem_sd_switch(struct sdmmc_function *sf, int mode, 
> int group,
>  
>   ptr = malloc(statlen, M_DEVBUF, M_NOWAIT | M_ZERO);
>   if (ptr == NULL)
> - goto out;
> + return ENOMEM;
>  
>   memset(, 0, sizeof(cmd));
>   cmd.c_data = ptr;
> 



Re: sdmmc: fix malloc error handling in sdmmc_mem_send_scr()

2022-01-10 Thread Stefan Sperling
On Mon, Jan 10, 2022 at 01:12:10PM +0100, Tobias Heider wrote:
> sdmmc_mem_send_scr() tries to malloc() with M_NOWAIT and returns 0 on
> error,  which leads to sdmmc_mem_sd_init() passing uninitialized stack
> memory to sdmmc_mem_decode_scr().
> The diff below makes sdmmc_mem_send_scr() return ENOMEM if malloc fails.
> 
> ok?

Nice catch. ok stsp@
 
> diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c
> index fae8d63912d..715c412e6ea 100644
> --- a/sys/dev/sdmmc/sdmmc_mem.c
> +++ b/sys/dev/sdmmc/sdmmc_mem.c
> @@ -465,8 +465,10 @@ sdmmc_mem_send_scr(struct sdmmc_softc *sc, uint32_t *scr)
>   int error = 0;
>  
>   ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
> - if (ptr == NULL)
> + if (ptr == NULL) {
> + error = ENOMEM;
>   goto out;
> + }
>  
>   memset(, 0, sizeof(cmd));
>   cmd.c_data = ptr;
> 
> 



Re: remove ieee80211_find_node_for_beacon()

2022-01-10 Thread Stefan Sperling
Ping. I have had zero feedback on this so far. Anyone?

On Tue, Jan 04, 2022 at 02:35:52PM +0100, Stefan Sperling wrote:
> The function ieee80211_find_node_for_beacon() was added by reyk on 2005.
> At the time, net80211 nodes were stored in a hash table keyed on hashes
> the node's source MAC addresses.
> The purpose of ieee80211_find_node_for_beacon() was to avoid storing
> duplicate nodes with the same source MAC address in a given hash bucket.
> Hash collisions on differing MAC addresses were valid, but collisions
> on the same address had to be avoided.
> 
> Later on, the node table data structure was changed from a hash table
> to an RB tree which is still in use today. The RB tree can only store a
> single node per MAC address. However, find_node_for_beacon() was kept
> regardless, now documented to serve a different purpose.
> Its new purpose is to tell apart different nodes which happen to use
> the same MAC address and hence cannot both be stored in the RB tree.
> The idea is to help the net80211 stack to pick the "better" one of two
> such APs while it is scanning for access points. The comment also claims
> this function would avoid "bloat" of the nodes tree, which is obviously
> related to the function's original purpose.
> 
> There are several problems with this:
> 
> The code which decides which node is "better" can erroneously match
> an AP against itself, in case the AP uses a hidden SSID.
> This prevents state updates for such APs.
> Just a bit further down, the code looks up the same node again
> and performs all of the intended updates. Simply skipping the
> ieee80211_find_node_for_beacon() check makes state updates work.
> (I have received a patch submission which fixes probe responses
> for iwm/iwx in order to interop with hidden SSID APs. And that
> patch contains a workaround for this problem, which prompted me
> to look into it.)
> 
> The intention of avoiding "bloat" makes no sense.
> There cannot be "bloat" of the node tree. Worst case we could end up
> leaking memory when we replace an existing node in the tree with a
> new node which has the same address (we would lose track of the pointer
> to memory which stores the original node, and would never be able to
> free this memory). There is no code in place which would prevent such
> a leak. Simply always updating the existing node we have allocated is
> the safer choice in the absence of proper collision handling.
> 
> My opinion is that this function should simply be removed.
> It is an incomplete attempt at dealing with an edge case (MAC address
> collisions), which is not a problem this function alone could ever
> hope to solve completely.
> 
> ok?
> 
> diff d32c3633e170510dd593f1e288e78acfddaff882 
> 32e6a77a0992dc0014e72c20005dfd9631b2055b
> blob - bb6367fd1d5dd9f4641fedd96491069a8f0878dc
> blob + 51d05f49c8b1ea58ea891f7b0f817e3bf94bed08
> --- sys/net80211/ieee80211_input.c
> +++ sys/net80211/ieee80211_input.c
> @@ -1751,37 +1751,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
>   ic->ic_stats.is_rx_chanmismatch++;
>   return;
>   }
> - /*
> -  * Use mac, channel and rssi so we collect only the
> -  * best potential AP with the equal bssid while scanning.
> -  * Collecting all potential APs may result in bloat of
> -  * the node tree. This call will return NULL if the node
> -  * for this APs does not exist or if the new node is the
> -  * potential better one.
> -  */
> - ni = ieee80211_find_node_for_beacon(ic, wh->i_addr2,
> - >ic_channels[chan], ssid, rxi->rxi_rssi);
> - if (ni != NULL) {
> - /*
> -  * If we are doing a directed scan for an AP with a hidden SSID
> -  * we must collect the SSID from a probe response to override
> -  * a non-zero-length SSID filled with zeroes that we may have
> -  * received earlier in a beacon.
> -  */
> - if (isprobe && ssid[1] != 0 && ni->ni_essid[0] == '\0') {
> - ni->ni_esslen = ssid[1];
> - memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
> - /* we know that ssid[1] <= IEEE80211_NWID_LEN */
> - memcpy(ni->ni_essid, [2], ssid[1]);
> - }
>  
> - /* Update channel in case AP has switched */
> - if (ic->ic_opmode == IEEE80211_M_STA)
> - ni->ni_chan = rni->ni_chan;
> -
> - return;
> - }
> -
>  #ifdef IEEE80211_DEBUG
>   if (ieee80211_debug > 1 &&
>   (ni == NULL ||

Re: patch: if_iwx.c add support for ax201 with subsystem id 0x0030

2022-01-09 Thread Stefan Sperling
On Sun, Jan 09, 2022 at 05:32:21PM +, Iraklis Karagkiozoglou wrote:
> Hi,
> 
> I've added support for AX201 with subsystem id 0x0030 in if_iwx.
> 
> I am only loading a different firmware for the specific subsystem id to
> avoid introducing any regressions or bugs.

We are receiving more and more reports like yours that our iwm(4) and
iwx(4) driver do not match some Intel wifi device which could be supported.

So far, the devices recognized by our drivers are essentially the exact
devices which were used by developers to make the drivers work.
In the wild there are many devices which Intel has released which we do
not recognize because the code we have to match devices is too simplistic.

The Linux driver does not match your device based on subsystem ID 0x0030.
Instead, it matches on the PCI product ID (0x20f0), reads the CSR_HW_RF_ID
register, and maps your device to QuZ-a0-jf-b0 based on the value of this
register! If you look into Linux you will see that it does not list subsystem
ID 0x0030 anywhere; your device's subsystem ID is matched by the "IWL_CFG_ANY"
wildcard.

In order to use the correct firmware for each device Intel has shipped,
the device matching code in our driver needs to be reworked to follow
the same rules as Linux. Otherwise we will never get this right.
Their device matching code is very complicated (see iwlwifif/pcie/drv.c).
We will need to port this code over to have a proper long-term solution :-/



remove ieee80211_find_node_for_beacon()

2022-01-04 Thread Stefan Sperling
The function ieee80211_find_node_for_beacon() was added by reyk on 2005.
At the time, net80211 nodes were stored in a hash table keyed on hashes
the node's source MAC addresses.
The purpose of ieee80211_find_node_for_beacon() was to avoid storing
duplicate nodes with the same source MAC address in a given hash bucket.
Hash collisions on differing MAC addresses were valid, but collisions
on the same address had to be avoided.

Later on, the node table data structure was changed from a hash table
to an RB tree which is still in use today. The RB tree can only store a
single node per MAC address. However, find_node_for_beacon() was kept
regardless, now documented to serve a different purpose.
Its new purpose is to tell apart different nodes which happen to use
the same MAC address and hence cannot both be stored in the RB tree.
The idea is to help the net80211 stack to pick the "better" one of two
such APs while it is scanning for access points. The comment also claims
this function would avoid "bloat" of the nodes tree, which is obviously
related to the function's original purpose.

There are several problems with this:

The code which decides which node is "better" can erroneously match
an AP against itself, in case the AP uses a hidden SSID.
This prevents state updates for such APs.
Just a bit further down, the code looks up the same node again
and performs all of the intended updates. Simply skipping the
ieee80211_find_node_for_beacon() check makes state updates work.
(I have received a patch submission which fixes probe responses
for iwm/iwx in order to interop with hidden SSID APs. And that
patch contains a workaround for this problem, which prompted me
to look into it.)

The intention of avoiding "bloat" makes no sense.
There cannot be "bloat" of the node tree. Worst case we could end up
leaking memory when we replace an existing node in the tree with a
new node which has the same address (we would lose track of the pointer
to memory which stores the original node, and would never be able to
free this memory). There is no code in place which would prevent such
a leak. Simply always updating the existing node we have allocated is
the safer choice in the absence of proper collision handling.

My opinion is that this function should simply be removed.
It is an incomplete attempt at dealing with an edge case (MAC address
collisions), which is not a problem this function alone could ever
hope to solve completely.

ok?

diff d32c3633e170510dd593f1e288e78acfddaff882 
32e6a77a0992dc0014e72c20005dfd9631b2055b
blob - bb6367fd1d5dd9f4641fedd96491069a8f0878dc
blob + 51d05f49c8b1ea58ea891f7b0f817e3bf94bed08
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -1751,37 +1751,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
ic->ic_stats.is_rx_chanmismatch++;
return;
}
-   /*
-* Use mac, channel and rssi so we collect only the
-* best potential AP with the equal bssid while scanning.
-* Collecting all potential APs may result in bloat of
-* the node tree. This call will return NULL if the node
-* for this APs does not exist or if the new node is the
-* potential better one.
-*/
-   ni = ieee80211_find_node_for_beacon(ic, wh->i_addr2,
-   >ic_channels[chan], ssid, rxi->rxi_rssi);
-   if (ni != NULL) {
-   /*
-* If we are doing a directed scan for an AP with a hidden SSID
-* we must collect the SSID from a probe response to override
-* a non-zero-length SSID filled with zeroes that we may have
-* received earlier in a beacon.
-*/
-   if (isprobe && ssid[1] != 0 && ni->ni_essid[0] == '\0') {
-   ni->ni_esslen = ssid[1];
-   memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
-   /* we know that ssid[1] <= IEEE80211_NWID_LEN */
-   memcpy(ni->ni_essid, [2], ssid[1]);
-   }
 
-   /* Update channel in case AP has switched */
-   if (ic->ic_opmode == IEEE80211_M_STA)
-   ni->ni_chan = rni->ni_chan;
-
-   return;
-   }
-
 #ifdef IEEE80211_DEBUG
if (ieee80211_debug > 1 &&
(ni == NULL || ic->ic_state == IEEE80211_S_SCAN ||
@@ -1977,6 +1947,13 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
}
}
 
+   /*
+* Set our SSID if we do not know it yet.
+* If we are doing a directed scan for an AP with a hidden SSID
+* we must collect the SSID from a probe response to override
+* a non-zero-length SSID filled with zeroes that we may have
+* received earlier in a beacon.
+*/
if (ssid[1] != 0 && ni->ni_essid[0] == '\0') {
ni->ni_esslen = ssid[1];
memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
blob - 

Re: remove references to prism54.org

2022-01-03 Thread Stefan Sperling
On Mon, Jan 03, 2022 at 10:19:59PM +1100, Jonathan Gray wrote:
> there are snapshots of some of it on archive.org
> https://web.archive.org/web/20080624074509/http://islsm.org/wiki/doku.php?id=

Unfortunately, the interesting bits, such as archive.org links to
the actual hardware docs on this page, do not seem to work for me:
https://web.archive.org/web/20080116080104/http://islsm.org/wiki/doku.php?id=documentation:the_softmac_protocol



Re: remove references to prism54.org

2022-01-03 Thread Stefan Sperling
On Mon, Jan 03, 2022 at 11:55:08AM +0100, Marcus MERIGHI wrote:
> Hello!
> 
> s...@stsp.name (Stefan Sperling), 2022.01.03 (Mon) 11:37 (CET):
> > On Mon, Jan 03, 2022 at 12:20:37PM +1100, Jonathan Gray wrote:
> > > the prism54.org domain is long abandoned
> > > don't give any traffic to whoever registered it afterwards
> > 
> > ok stsp@
> > A quick web search suggests that no efforts were made to save the
> > original content of the site :(
> 
> A longer search at 
> 
> https://web.archive.org/web/2021*/http://prism54.org
> 
> showed the following:

Thanks for digging.

> first archival by archive.org, 2003:
> https://web.archive.org/web/20031118062037/http://prism54.org/

Impossible, they were still using CVS in 2003?!?

> the last archival *before* the content changed drastically, 
> redirects to wireless.kernel.org:
> https://web.archive.org/web/20100224061113/http://wireless.kernel.org/en/users/Drivers/p54

Given that the original site does not seem to document reserved-engineered
hardware specs there is not much value in us keeping references to it.



Re: remove references to prism54.org

2022-01-03 Thread Stefan Sperling
On Mon, Jan 03, 2022 at 12:20:37PM +1100, Jonathan Gray wrote:
> the prism54.org domain is long abandoned
> don't give any traffic to whoever registered it afterwards
> 

ok stsp@

A quick web search suggests that no efforts were made to save the
original content of the site :(

> Index: share/man/man4/upgt.4
> ===
> RCS file: /cvs/src/share/man/man4/upgt.4,v
> retrieving revision 1.29
> diff -u -p -r1.29 upgt.4
> --- share/man/man4/upgt.4 24 Oct 2021 12:32:42 -  1.29
> +++ share/man/man4/upgt.4 3 Jan 2022 01:12:18 -
> @@ -182,9 +182,6 @@ The
>  .Nm
>  driver was written by
>  .An Marcus Glocker Aq Mt mgloc...@openbsd.org .
> -.Pp
> -The hardware specification was reverse engineered by the people at
> -.Lk http://www.prism54.org .
>  .Sh CAVEATS
>  The
>  .Nm
> Index: sys/dev/ic/pgt.c
> ===
> RCS file: /cvs/src/sys/dev/ic/pgt.c,v
> retrieving revision 1.100
> diff -u -p -r1.100 pgt.c
> --- sys/dev/ic/pgt.c  3 Mar 2021 23:58:28 -   1.100
> +++ sys/dev/ic/pgt.c  3 Jan 2022 01:12:44 -
> @@ -96,8 +96,7 @@
>  
>  /*
>   * This is a driver for the Intersil Prism family of 802.11g network cards,
> - * based upon version 1.2 of the Linux driver and firmware found at
> - * http://www.prism54.org/.
> + * based upon version 1.2 of the Linux driver.
>   */
>  
>  #define SCAN_TIMEOUT 5   /* 5 seconds */
> 
> 



Re: close net80211 hardware crypto set_key races

2021-12-05 Thread Stefan Sperling
On Sun, Dec 05, 2021 at 02:03:29PM +, Mikolaj Kucharski wrote:
> Hi Stefan,
> 
> I'm not yet ready to test new diffs, but I was going through old
> wireless stack related emails and was wondering did below patch got
> committed? Per my git / cvs search I don't think so. Is below diff
> still relevant or can below change be ignored?
> 
I would put this aside for now. The patch does not apply anymore
and never received sufficient testing.



Re: ifconfig description for wireguard peers

2021-11-30 Thread Stefan Sperling
On Tue, Nov 30, 2021 at 02:31:20PM -0500, Noah Meier wrote:
> Hi Stefan,
> 
> Richard Procter offered some kind advice on the ordering of options in the 
> man page
> (to be done alphabetically) and commented on an unnecessary cast.
> 
> I also believe that I goofed by failing to initalize the mutex and zero the 
> description
> upon peer creation (in wg_peer_create).
> 
> I’ve attempted to address these issues and have pasted the diff below.
> 
> NM

This new patch does not apply cleanly.
Leading whitespace was stripped, and thus patch complains as follows:

Patching file if_wg.c using Plan A...
patch:  malformed patch at line 15: };

And it would help if you created a patch where all paths are relative to
the /usr/src directory. Something like this should do it:

 cd /usr/src
 cvs diff -u sbin/ifconfig sys/net  > /tmp/wgdesc.patch

If your mailer cannot preserve whitespace as-is then please try attaching
the patch file instead of inlining it.

Thanks!



Re: ifconfig description for wireguard peers

2021-11-29 Thread Stefan Sperling
On Wed, Oct 20, 2021 at 10:20:09PM -0400, Noah Meier wrote:
> Hi,
> 
> While wireguard interfaces can have a description set by ifconfig, wireguard 
> peers currently cannot. I now have a lot of peers and descriptions of them in 
> ifconfig would be helpful.
> 
> This diff adds a 'wgdesc' option to a 'wgpeer' in ifconfig (and a 
> corresponding '-wgdesc' option). Man page also updated.
> 
> NM

This looks useful to me.
Did you get any feedback for this patch yet, Noah?

> Index: ifconfig.8
> ===
> RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v
> retrieving revision 1.375
> diff -u -p -u -p -r1.375 ifconfig.8
> --- ifconfig.818 Aug 2021 18:10:33 -  1.375
> +++ ifconfig.821 Oct 2021 00:09:20 -
> @@ -2343,6 +2343,10 @@ It is optional but recommended and can b
>  .Dl $ openssl rand -base64 32
>  .It Cm -wgpsk
>  Remove the pre-shared key for this peer.
> +.It Cm wgdesc Ar value
> +Specify a description of the peer.
> +.It Cm -wgdesc
> +Clear the peer description.
>  .El
>  .Sh EXAMPLES
>  Assign the
> Index: ifconfig.c
> ===
> RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
> retrieving revision 1.445
> diff -u -p -u -p -r1.445 ifconfig.c
> --- ifconfig.c6 Oct 2021 06:14:08 -   1.445
> +++ ifconfig.c21 Oct 2021 00:09:20 -
> @@ -355,12 +355,14 @@ voidsetwgpeerep(const char *, const cha
>  void setwgpeeraip(const char *, int);
>  void setwgpeerpsk(const char *, int);
>  void setwgpeerpka(const char *, int);
> +void setwgpeerdesc(const char *, int);
>  void setwgport(const char *, int);
>  void setwgkey(const char *, int);
>  void setwgrtable(const char *, int);
>  
>  void unsetwgpeer(const char *, int);
>  void unsetwgpeerpsk(const char *, int);
> +void unsetwgpeerdesc(const char *, int);
>  void unsetwgpeerall(const char *, int);
>  
>  void wg_status();
> @@ -625,11 +627,13 @@ const structcmd {
>   { "wgaip",  NEXTARG,A_WIREGUARD,setwgpeeraip},
>   { "wgpsk",  NEXTARG,A_WIREGUARD,setwgpeerpsk},
>   { "wgpka",  NEXTARG,A_WIREGUARD,setwgpeerpka},
> + { "wgdesc", NEXTARG,A_WIREGUARD,setwgpeerdesc},
>   { "wgport", NEXTARG,A_WIREGUARD,setwgport},
>   { "wgkey",  NEXTARG,A_WIREGUARD,setwgkey},
>   { "wgrtable",   NEXTARG,A_WIREGUARD,setwgrtable},
>   { "-wgpeer",NEXTARG,A_WIREGUARD,unsetwgpeer},
>   { "-wgpsk", 0,  A_WIREGUARD,unsetwgpeerpsk},
> + { "-wgdesc",0,  A_WIREGUARD,unsetwgpeerdesc},
>   { "-wgpeerall", 0,  A_WIREGUARD,unsetwgpeerall},
>  
>  #else /* SMALL */
> @@ -5827,6 +5831,16 @@ setwgpeerpka(const char *pka, int param)
>  }
>  
>  void
> +setwgpeerdesc(const char *wgdesc, int param)
> +{
> + if (wg_peer == NULL)
> + errx(1, "wgdesc: wgpeer not set");
> + if (strlen(wgdesc))
> + strlcpy(wg_peer->p_description, wgdesc, IFDESCRSIZE);
> + wg_peer->p_flags |= WG_PEER_SET_DESCRIPTION;
> +}
> +
> +void
>  setwgport(const char *port, int param)
>  {
>   const char *errmsg = NULL;
> @@ -5873,6 +5887,15 @@ unsetwgpeerpsk(const char *value, int pa
>  }
>  
>  void
> +unsetwgpeerdesc(const char *value, int param)
> +{
> + if (wg_peer == NULL)
> + errx(1, "wgpesc: wgpeer not set");
> + strlcpy(wg_peer->p_description, (const char *)"", IFDESCRSIZE);
> + wg_peer->p_flags |= WG_PEER_SET_DESCRIPTION;
> +}
> +
> +void
>  unsetwgpeerall(const char *value, int param)
>  {
>   ensurewginterface();
> @@ -5931,6 +5954,9 @@ wg_status(void)
>   b64_ntop(wg_peer->p_public, WG_KEY_LEN,
>   key, sizeof(key));
>   printf("\twgpeer %s\n", key);
> +
> + if (strlen(wg_peer->p_description))
> + printf("\t\tdescription: %s\n", wg_peer->p_description);
>  
>   if (wg_peer->p_flags & WG_PEER_HAS_PSK)
>   printf("\t\twgpsk (present)\n");
> Index: if_wg.c
> ===
> RCS file: /cvs/src/sys/net/if_wg.c,v
> retrieving revision 1.18
> diff -u -p -u -p -r1.18 if_wg.c
> --- if_wg.c   5 Aug 2021 13:37:04 -   1.18
> +++ if_wg.c   21 Oct 2021 00:10:29 -
> @@ -222,6 +222,9 @@ struct wg_peer {
>  
>   SLIST_ENTRY(wg_peer) p_start_list;
>   int  p_start_onlist;
> +
> + struct mutex p_description_mtx;
> + char p_description[IFDESCRSIZE];
>  };
>  
>  struct wg_softc {
> @@ -276,6 +279,7 @@ int   wg_peer_get_sockaddr(struct wg_peer 
>  void wg_peer_clear_src(struct wg_peer *);
>  void wg_peer_get_endpoint(struct wg_peer *, struct wg_endpoint *);
>  void wg_peer_counters_add(struct wg_peer *, uint64_t, uint64_t);
> +void 

Re: iwm/iwx: try to make roaming more reliable

2021-11-27 Thread Stefan Sperling
On Sat, Nov 27, 2021 at 09:57:45AM -0600, Aaron Poffenberger wrote:
> I see two differences. Before the patch, before "deauth" I see "sending
> delba" but not after patching, and before "firmware has detected
> regulatory domain 'US'", but not after.

I decided to try not sending a DELBA because it is immediately followed
by a DEAUTH anyway. The AP will clear block-ack session state in response
to DELBA, and delete *all* state in response to DEAUTH. So omitting DELBA
should be fine, and eliminates a frame we need to manage to send out
successfully in order to roam away. There is an #if 0 in the patch
which you can switch to an #if 1 in order to send the DELBA frame if
you would like to try that.

Not getting a regulatory notification from the firmware does not matter.
We do not do anything with such information yet beyond printing it to
dmesg in debug mode.



iwm/iwx: try to make roaming more reliable

2021-11-27 Thread Stefan Sperling
This patch reworks the steps involved in roaming to a new access
point on iwm(4) and iwx(4) interfaces.

The current implementation suffers from race conditions which can
leave the interface in a state where it gets "stuck". I have seen
this happen on iwm(4) 9560 in particular, while testing the driver
with new firmware images recently published by Intel. This may well
be related to other hangs people have reported in multi-AP environments
on both iwm(4) and iwx(4).

With this patch in place, net80211 can now pass control to drivers
which provide an optional bgscan_done() handler. In this handler the
driver will do everything necessary to prepare the device for switching
APs, and then call back into net80211 to trigger the AP switch.

In the previous implementation, net80211 asked the driver to prepare
the device and immediately proceeded with switching APs. The driver
may need to wait for firmware commands to complete, which is done in a
task context. So we have a situation where the driver-side task and
net80211's switching of APs (which involves sending frames) kind of
happen in parallel, and things may break.

To test roaming, you need to do the following:

All APs involved need to use the same SSID for this to work as intended.
If you do not have such a setup, you cannot effectively test this patch
(unless you just want to run the patch anyway and look for regressions).

Use wifi with 'ifconfig iwm0/iwx0 debug' enabled to make roaming attempts
appear in /var/log/messages, and watch this file with a command such as:

  tail -f /var/log/messages

Move towards another access point and trigger a background scan by
running this command as root:

  ifconfig iwm0 scan

It may take a few scan attempts until roaming triggers.
Successful roaming displays the following in /var/log/messages:

  iwm0: roaming from 00:2b:a2:95:e3:e4 chan 1 to 00:2b:a2:95:e3:f4 chan 36
  iwm0: RUN -> AUTH
  iwm0: sending auth to 00:1a:dd:da:e3:f4 on channel 36 mode 11a
  iwm0: AUTH -> ASSOC
  iwm0: sending assoc_req to 00:2b:a2:95:e3:f4 on channel 36 mode 11a
  iwm0: ASSOC -> RUN

If it doesn't do this but enters INIT or SCAN or whatever, roaming failed.
This can happen for various reasons. One of them is that our attempt to
AUTH to the new AP times out, and I don't know how this could be fixed.
In any case, the driver should recover from any roaming failure by going
though the regular INIT->SCAN->AUTH->ASSOC->RUN sequence with one of
the available APs, and interface link should come back up.

If you want to force roaming from one particular AP to another, this can
be done by forcing the channel number corresponding to the first AP,
associating to this AP, and then clearing the forced channel number:

  # ifconfig iwm0 chan 1
  wait for association to succeed, then clear the forced channel:
  # ifconfig iwm0 -chan
  now trigger a background scan as usual:
  # ifconfig iwm0 scan
 
diff e5ddbb84043d48bc602408a6bf0e30fb062e3280 
af878e690f6195efea7bb4639bf75fe439f3cddc
blob - f1908d2923d90c7be84c010fc68342afda860d0c
blob + dfccd0bd1327325b7c834d1e60f1b37d7a19dc18
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -477,6 +477,9 @@ voidiwm_add_task(struct iwm_softc *, struct taskq 
*, 
 void   iwm_del_task(struct iwm_softc *, struct taskq *, struct task *);
 intiwm_scan(struct iwm_softc *);
 intiwm_bgscan(struct ieee80211com *);
+void   iwm_bgscan_done(struct ieee80211com *,
+   struct ieee80211_node_switch_bss_arg *, size_t);
+void   iwm_bgscan_done_task(void *);
 intiwm_umac_scan_abort(struct iwm_softc *);
 intiwm_lmac_scan_abort(struct iwm_softc *);
 intiwm_scan_abort(struct iwm_softc *);
@@ -8287,6 +8290,81 @@ iwm_bgscan(struct ieee80211com *ic) 
return 0;
 }
 
+void
+iwm_bgscan_done(struct ieee80211com *ic,
+struct ieee80211_node_switch_bss_arg *arg, size_t arg_size)
+{
+   struct iwm_softc *sc = ic->ic_softc;
+
+   free(sc->bgscan_unref_arg, M_DEVBUF, sc->bgscan_unref_arg_size);
+   sc->bgscan_unref_arg = arg;
+   sc->bgscan_unref_arg_size = arg_size;
+   iwm_add_task(sc, sc->sc_nswq, >bgscan_done_task);
+}
+
+void
+iwm_bgscan_done_task(void *arg)
+{
+   struct iwm_softc *sc = arg;
+   struct ieee80211com *ic = >sc_ic;
+   struct iwm_node *in = (void *)ic->ic_bss;
+   struct ieee80211_node *ni = >in_ni;
+   int tid, err = 0, s = splnet();
+
+   if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) ||
+   (ic->ic_flags & IEEE80211_F_BGSCAN) == 0 ||
+   ic->ic_state != IEEE80211_S_RUN) {
+   err = ENXIO;
+   goto done;
+   }
+
+   for (tid = 0; tid < IWM_MAX_TID_COUNT; tid++) {
+   int qid = IWM_FIRST_AGG_TX_QUEUE + tid;
+
+   if ((sc->tx_ba_queue_mask & (1 << qid)) == 0)
+   continue;
+
+   err = iwm_sta_tx_agg(sc, ni, tid, 0, 0, 0);
+   if (err)
+   goto done;
+   err = iwm_disable_txq(sc, IWM_STATION_ID, 

update iwx(4) firmware to -67

2021-11-26 Thread Stefan Sperling
This patch updates iwx(4) to new firmware images (API version -67).

Intel has published a related security advisory:
https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00509.html

Make sure to get a fresh kernel from -current sources and update
to iwx-firmware-20211101 with fw_update before trying this patch.
The new firmware version shows as "fw ver 67.8f59b80b.0" in dmesg.
I have tested on AX200 and AX201 and I am not seeing any issues.

iwx(4) devices which are using the iwx-Qu-c0-hr-b0-63 image did
not receive a firmware update. I cannot tell why.

ok?

 
diff 777a5184786f624f57b85b8460919a1130498508 
1d9e5ec96bf733cdb7c339f7179b945ff1e0a937
blob - 1d87b3522c60081eac0b0f54cdd772984de4b340
blob + d48e22237cb568cb0bed6a49e82d3be6d4744da4
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -9266,7 +9266,7 @@ iwx_attach(struct device *parent, struct device *self,
 
switch (PCI_PRODUCT(pa->pa_id)) {
case PCI_PRODUCT_INTEL_WL_22500_1:
-   sc->sc_fwname = "iwx-cc-a0-63";
+   sc->sc_fwname = "iwx-cc-a0-67";
sc->sc_device_family = IWX_DEVICE_FAMILY_22000;
sc->sc_integrated = 0;
sc->sc_ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_NONE;
@@ -9283,7 +9283,7 @@ iwx_attach(struct device *parent, struct device *self,
return;
}
 
-   sc->sc_fwname = "iwx-QuZ-a0-hr-b0-63";
+   sc->sc_fwname = "iwx-QuZ-a0-hr-b0-67";
sc->sc_device_family = IWX_DEVICE_FAMILY_22000;
sc->sc_integrated = 1;
sc->sc_ltr_delay = IWX_SOC_FLAGS_LTR_APPLY_DELAY_200;



iwm(4): use per-queue Tx timers

2021-11-22 Thread Stefan Sperling
The iwx(4) driver in -current now contains a workaround for Tx queues
which get stuck while other Tx queues keep working. This condition
now triggers a device timeout on iwx(4) rather than leaving interface
in a semi-operational state.

Here is a corresponding patch for iwm(4).
The Linux driver applies the same workaround to iwm(4) devices, too.

ok?
 
diff 1499064ecae4f3d85eb41954a6cc78779c4f2d6f 
4f32e28bcce503a57882fd48c65707579cc9a3fb
blob - 0fd8f7e46184c72d5a840a24f0da8d6a416f9452
blob + 8a14c3c5e5c08681fa02831bee80dc040bab6612
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -4552,8 +4552,6 @@ iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_pack
bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWX_RBUF_SIZE,
BUS_DMASYNC_POSTREAD);
 
-   sc->sc_tx_timer = 0;
-
/* Sanity checks. */
if (sizeof(*tx_resp) > len)
return;
@@ -4563,6 +4561,8 @@ iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_pack
tx_resp->frame_count * sizeof(tx_resp->status) > len)
return;
 
+   sc->sc_tx_timer[qid] = 0;
+
if (tx_resp->frame_count > 1) /* A-MPDU */
return;
 
@@ -4658,7 +4658,7 @@ iwx_rx_compressed_ba(struct iwx_softc *sc, struct iwx_
idx = le16toh(ba_tfd->tfd_index);
if (idx >= IWX_TX_RING_COUNT)
continue;
-   sc->sc_tx_timer = 0;
+   sc->sc_tx_timer[qid] = 0;
iwx_txq_advance(sc, ring, idx);
iwx_clear_oactive(sc, ring);
}
@@ -5433,6 +5433,9 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ie
sc->qfullmsk |= 1 << ring->qid;
}
 
+   if (ic->ic_if.if_flags & IFF_UP)
+   sc->sc_tx_timer[ring->qid] = 15;
+
return 0;
 }
 
@@ -7973,10 +7976,8 @@ iwx_start(struct ifnet *ifp)
continue;
}
 
-   if (ifp->if_flags & IFF_UP) {
-   sc->sc_tx_timer = 15;
+   if (ifp->if_flags & IFF_UP)
ifp->if_timer = 1;
-   }
}
 
return;
@@ -8046,7 +8047,8 @@ iwx_stop(struct ifnet *ifp)
struct iwx_rxba_data *rxba = >sc_rxba_data[i];
iwx_clear_reorder_buffer(sc, rxba);
}
-   ifp->if_timer = sc->sc_tx_timer = 0;
+   memset(sc->sc_tx_timer, 0, sizeof(sc->sc_tx_timer));
+   ifp->if_timer = 0;
 
splx(s);
 }
@@ -8055,21 +8057,30 @@ void
 iwx_watchdog(struct ifnet *ifp)
 {
struct iwx_softc *sc = ifp->if_softc;
+   int i;
 
ifp->if_timer = 0;
-   if (sc->sc_tx_timer > 0) {
-   if (--sc->sc_tx_timer == 0) {
-   printf("%s: device timeout\n", DEVNAME(sc));
-   if (ifp->if_flags & IFF_DEBUG) {
-   iwx_nic_error(sc);
-   iwx_dump_driver_status(sc);
+
+   /*
+* We maintain a separate timer for each Tx queue because
+* Tx aggregation queues can get "stuck" while other queues
+* keep working. The Linux driver uses a similar workaround.
+*/
+   for (i = 0; i < nitems(sc->sc_tx_timer); i++) {
+   if (sc->sc_tx_timer[i] > 0) {
+   if (--sc->sc_tx_timer[i] == 0) {
+   printf("%s: device timeout\n", DEVNAME(sc));
+   if (ifp->if_flags & IFF_DEBUG) {
+   iwx_nic_error(sc);
+   iwx_dump_driver_status(sc);
+   }
+   if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0)
+   task_add(systq, >init_task);
+   ifp->if_oerrors++;
+   return;
}
-   if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) == 0)
-   task_add(systq, >init_task);
-   ifp->if_oerrors++;
-   return;
+   ifp->if_timer = 1;
}
-   ifp->if_timer = 1;
}
 
ieee80211_watchdog(ifp);
blob - 719d9b6295b9eb9c31b36a98bcb0259a8a2f4cf3
blob + 50d9e6346079be78b020a0d43a3c755e5945f1d3
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -563,7 +563,7 @@ struct iwx_softc {
struct iwx_nvm_data sc_nvm;
struct iwx_bf_data sc_bf;
 
-   int sc_tx_timer;
+   int sc_tx_timer[IWX_NUM_TX_QUEUES];
int sc_rx_ba_sessions;
 
int sc_scan_last_antenna;



Re: iwm/iwx: update last_rx timestamp

2021-11-19 Thread Stefan Sperling
On Mon, Nov 08, 2021 at 01:07:58PM +0100, Stefan Sperling wrote:
> The last_rx timestamp which controls timeout of an Rx block ack
> session is not updated when a frame is received.
> This can result in the session timing out too early.
> 
> Not a huge deal because the AP will simply request a new session when
> it has more data to send. And many APs do not even enable session
> timeouts in which case our timeout handler remains inactive, too.
> 
> But we should handle negotiated session timeouts correctly.
> 
> ok?

Ping.

> diff 02c3ac519701a4fe198f8ee3de592b34a39ee6f7 
> d1e8e8a7b10a061d0364e3a63366e646218124a7
> blob - 92f77754c4dd9d8a340a24bc2ce6f89ca77e0f84
> blob + 983c18557ae9bef84372346fd4833c530994faa3
> --- sys/dev/pci/if_iwm.c
> +++ sys/dev/pci/if_iwm.c
> @@ -5121,6 +5121,9 @@ iwm_rx_reorder(struct iwm_softc *sc, struct mbuf *m, i
>   if (rxba == NULL || tid != rxba->tid || rxba->sta_id != IWM_STATION_ID)
>   return 0;
>  
> + if (rxba->timeout != 0)
> + getmicrouptime(>last_rx);
> +
>   /* Bypass A-MPDU re-ordering in net80211. */
>   rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
>  
> blob - 5cac83fd48ebe997a4cd7842730b0cb05f7c28ee
> blob + 1ac1ad3b420a9de838df6e2fc30d21c5bcb8661f
> --- sys/dev/pci/if_iwx.c
> +++ sys/dev/pci/if_iwx.c
> @@ -4202,6 +4202,9 @@ iwx_rx_reorder(struct iwx_softc *sc, struct mbuf *m, i
>   if (rxba == NULL || tid != rxba->tid || rxba->sta_id != IWX_STATION_ID)
>   return 0;
>  
> + if (rxba->timeout != 0)
> + getmicrouptime(>last_rx);
> +
>   /* Bypass A-MPDU re-ordering in net80211. */
>   rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
>  
> 
> 



Re: make iwx(4) use per-queue Tx timers

2021-11-12 Thread Stefan Sperling
On Mon, Nov 08, 2021 at 10:59:55AM +0100, Stefan Sperling wrote:
> iwx(4) has an issue which occurs very occasionally for me (every couple
> of days or sometimes even weeks) where ssh(1) fails to connect until the
> interface is reset with ifconfig down/up.
> 
> The initial protocol exchange with the SSH server succeeds, but as soon
> as the client enters interactive state and sets TCP_NODELAY the connection
> will hang.
> While the interface is in this broken state other traffic such as ping
> still makes it through, but any new ssh connection attempts show the
> same symptom. It is just the interactive SSH packets which are stuck.
> 
> TCP_NODELAY packets are mapped to a special QoS TID by net80211, and each
> such TID gets mapped to a dedicated Tx aggregation queue by the driver.
> Combined with the observation that the Linux driver carries a workaround
> for "stuck" individual Tx queues, we are likely facing a situation where
> only one Tx queue in the device has stopped working.
> 
> Our interface watchdog cannot detect single Tx queue failures at present.
> It is satisfied as long as packets make it out on any queue.
> With the patch below we use a Tx timer per queue which will hopefully result
> in a device timeout when the problem occurs. A manual reset will no longer be
> required to unwedge things since the watchdog should now trigger a reset.
> 
> It is possible that other hangs which have been reported are related to
> this but show different symptoms depending on which Tx queue gets stuck.
> If the default Tx agg queue gets stuck it will become impossible to send
> data packets that are not marked as TCP_NODELAY. If you are connected over
> ssh while this happens the open ssh session might prevent the watchdog from
> triggering and no new connections can be made.
> 
> I wish we had a fix for Tx queues getting stuck in the first place but this
> is the best I can do.
> 
> ok?

Did anyone try this yet? It is working well for me.

This new version of the patch has been rebased on top of two small
iwx(4) driver fixes I have sent out separately today. With this,
the size of the sc_tx_timer array is corrected to match the new
size of the Tx ring array.

Apply them all in sequence:

"fix Tx ring array size"
https://marc.info/?l=openbsd-tech=163671980016530=2

"fix TID array index bound checks"
https://marc.info/?l=openbsd-tech=163672074217035=2

ok?
 
diff 6629860d5767033824e2fb1c0f621c18216a7316 
fbfd8a2c2e804554680d3879819c789931916dc5
blob - 6e67f7db864ec9a7ca61057b7284e7d7a6bffe5d
blob + e1793a5b742f691cbffa930e8f6363538190d590
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -4552,8 +4552,6 @@ iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_pack
bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWX_RBUF_SIZE,
BUS_DMASYNC_POSTREAD);
 
-   sc->sc_tx_timer = 0;
-
/* Sanity checks. */
if (sizeof(*tx_resp) > len)
return;
@@ -4563,6 +4561,8 @@ iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_pack
tx_resp->frame_count * sizeof(tx_resp->status) > len)
return;
 
+   sc->sc_tx_timer[qid] = 0;
+
if (tx_resp->frame_count > 1) /* A-MPDU */
return;
 
@@ -4658,7 +4658,7 @@ iwx_rx_compressed_ba(struct iwx_softc *sc, struct iwx_
idx = le16toh(ba_tfd->tfd_index);
if (idx >= IWX_TX_RING_COUNT)
continue;
-   sc->sc_tx_timer = 0;
+   sc->sc_tx_timer[qid] = 0;
iwx_txq_advance(sc, ring, idx);
iwx_clear_oactive(sc, ring);
}
@@ -5433,6 +5433,9 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ie
sc->qfullmsk |= 1 << ring->qid;
}
 
+   if (ic->ic_if.if_flags & IFF_UP)
+   sc->sc_tx_timer[ring->qid] = 15;
+
return 0;
 }
 
@@ -7973,10 +7976,8 @@ iwx_start(struct ifnet *ifp)
continue;
}
 
-   if (ifp->if_flags & IFF_UP) {
-   sc->sc_tx_timer = 15;
+   if (ifp->if_flags & IFF_UP)
ifp->if_timer = 1;
-   }
}
 
return;
@@ -8045,7 +8046,8 @@ iwx_stop(struct ifnet *ifp)
struct iwx_rxba_data *rxba = >sc_rxba_data[i];
iwx_clear_reorder_buffer(sc, rxba);
}
-   ifp->if_timer = sc->sc_tx_timer = 0;
+   memset(sc->sc_tx_timer, 0, sizeof(sc->sc_tx_timer));
+   ifp->if_timer = 0;
 
splx(s);
 }
@@ -8054,21 +8056,30 @@ void
 iwx_watchdog(struct ifnet *ifp)
 {
struct iwx_softc *sc = ifp->if_softc;
+   int i;
 
ifp->if_timer = 0;
-   if (sc->sc_tx_timer > 0) {
-   if (--sc->sc

iwx(4): fix TID array index bound checks

2021-11-12 Thread Stefan Sperling
This tid variable is used as an array index and must thus be smaller
than MAX_TID_COUNT (which is 8).

The variable will be set to 8 if the AP wants us to use TID 8 for Rx agg,
which I've never seen happen in practice, though it is possible.

Our driver uses this value as an index into an array of
IEEE80211_NUM_TID (16) elements, and thus would not crash.

But the value is passed on to firmware which does who knows what with it.
The Linux driver uses this value as an index into an array ("tid_to_baid")
of MAX_TID_COUNT elements. Perhaps firmware has a similar limitation?
I cannot tell.
 
ok?
 
diff 0433237ad58131957ccba3ddd837ed772dbec416 
6629860d5767033824e2fb1c0f621c18216a7316
blob - 5cac83fd48ebe997a4cd7842730b0cb05f7c28ee
blob + 6e67f7db864ec9a7ca61057b7284e7d7a6bffe5d
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -3264,7 +3264,7 @@ iwx_ampdu_rx_start(struct ieee80211com *ic, struct iee
struct iwx_softc *sc = IC2IFP(ic)->if_softc;
 
if (sc->sc_rx_ba_sessions >= IWX_MAX_RX_BA_SESSIONS ||
-   tid > IWX_MAX_TID_COUNT)
+   tid >= IWX_MAX_TID_COUNT)
return ENOSPC;
 
if (sc->ba_rx.start_tidmask & (1 << tid))
@@ -3286,7 +3286,7 @@ iwx_ampdu_rx_stop(struct ieee80211com *ic, struct ieee
 {
struct iwx_softc *sc = IC2IFP(ic)->if_softc;
 
-   if (tid > IWX_MAX_TID_COUNT || sc->ba_rx.stop_tidmask & (1 << tid))
+   if (tid >= IWX_MAX_TID_COUNT || sc->ba_rx.stop_tidmask & (1 << tid))
return;
 
sc->ba_rx.stop_tidmask = (1 << tid);



iwx(4): fix Tx ring array size

2021-11-12 Thread Stefan Sperling
The iwx Tx ring array is one entry too short due to an off-by-one error.

Fortunately, this bug is harmless. The last Tx agg queue is never used
because ieee80211_classify() only returns TID values in the range 0 - 3.
And iterations over the txq array use nitems() to find the upper bound.

The possiblity of shrinking the txq array by 4 elements to get rid of
unused Tx agg queues could be investigated later.
For now, just fix the off-by-one error.

ok?

diff b19fd44c79660fc69d55de88265e00892505e7ab 
0433237ad58131957ccba3ddd837ed772dbec416
blob - e29148ff81ffa620b806f9244c7ede8f05fb417c
blob + 4f310ad504e6f81a0ee65a11614dc5bd70f79fef
--- sys/dev/pci/if_iwxreg.h
+++ sys/dev/pci/if_iwxreg.h
@@ -1420,6 +1420,7 @@ struct iwx_gen3_bc_tbl {
 #define IWX_MAX_TID_COUNT  8
 #define IWX_FIRST_AGG_TX_QUEUE (IWX_DQA_MGMT_QUEUE + 1)
 #define IWX_LAST_AGG_TX_QUEUE  (IWX_FIRST_AGG_TX_QUEUE + IWX_MAX_TID_COUNT - 1)
+#define IWX_NUM_TX_QUEUES  (IWX_LAST_AGG_TX_QUEUE + 1)
 
 /**
  * Max Tx window size is the max number of contiguous TFDs that the scheduler
blob - 009848fc25471ad90717094d1f67d2f4d22a3d6a
blob + 719d9b6295b9eb9c31b36a98bcb0259a8a2f4cf3
--- sys/dev/pci/if_iwxvar.h
+++ sys/dev/pci/if_iwxvar.h
@@ -497,7 +497,7 @@ struct iwx_softc {
int sc_msix;
 
/* TX/RX rings. */
-   struct iwx_tx_ring txq[IWX_LAST_AGG_TX_QUEUE];
+   struct iwx_tx_ring txq[IWX_NUM_TX_QUEUES];
struct iwx_rx_ring rxq;
int qfullmsk;
int qenablemsk;



Re: add 802.11n 40MHz support to iwn(4)

2021-11-11 Thread Stefan Sperling
On Tue, Nov 09, 2021 at 02:23:09PM +0100, Stefan Sperling wrote:
> On Mon, Nov 01, 2021 at 12:56:26PM +0100, Stefan Sperling wrote:
> > I have tested on a 6205 device. More tests are needed, especially on
> > the old 4965AGN generation because those chips require the driver to
> > do specific calibration work which newer chips perform in firmware.
> > I suspect you will find 4965 devices in older thinkpads which first
> > introduced 11n wifi to these laptops (the x60/x61 generation probably).
> 
> Does nobody have a 4965AGN device anymore?
> 
> The patch is in snaps, so a simple upgrade to the latest snapshot
> would be sufficient to test this. Thanks!

Testing on 4965 by jsg@ revealed an unrelated issue on those devices.
A fix for this problem has just been committed.
This new version of the 40MHz patch applies on top of that fix.

diff refs/heads/iwn-rxon refs/heads/40mhz
blob - 41b2623db022d54e532ab5a1cd06f7a3adc9a69e
blob + 1d6668e5484e58465a874e4c51c943fe4c2ba5d3
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -241,12 +241,16 @@ uint16_t  iwn_get_passive_dwell_time(struct iwn_softc *
 intiwn_scan(struct iwn_softc *, uint16_t, int);
 void   iwn_scan_abort(struct iwn_softc *);
 intiwn_bgscan(struct ieee80211com *);
+void   iwn_rxon_configure_ht40(struct ieee80211com *,
+   struct ieee80211_node *);
+intiwn_rxon_ht40_enabled(struct iwn_softc *);
 intiwn_auth(struct iwn_softc *, int);
 intiwn_run(struct iwn_softc *);
 intiwn_set_key(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_key *);
 void   iwn_delete_key(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_key *);
+void   iwn_updatechan(struct ieee80211com *);
 void   iwn_updateprot(struct ieee80211com *);
 void   iwn_updateslot(struct ieee80211com *);
 void   iwn_update_rxon_restore_power(struct iwn_softc *);
@@ -491,13 +495,15 @@ iwn_attach(struct device *parent, struct device *self,
ic->ic_caps |= (IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU);
/* Set HT capabilities. */
ic->ic_htcaps = IEEE80211_HTCAP_SGI20;
+   /* 6200 devices have issues with SGI40 for some reason. */
+   if ((sc->sc_flags & IWN_FLAG_INTERNAL_PA) == 0)
+   ic->ic_htcaps |= IEEE80211_HTCAP_SGI40;
+   ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40;
 #ifdef notyet
ic->ic_htcaps |=
 #if IWN_RBUF_SIZE == 8192
IEEE80211_HTCAP_AMSDU7935 |
 #endif
-   IEEE80211_HTCAP_CBW20_40 |
-   IEEE80211_HTCAP_SGI40;
if (sc->hw_type != IWN_HW_REV_TYPE_4965)
ic->ic_htcaps |= IEEE80211_HTCAP_GF;
if (sc->hw_type == IWN_HW_REV_TYPE_6050)
@@ -543,6 +549,7 @@ iwn_attach(struct device *parent, struct device *self,
ic->ic_updateedca = iwn_updateedca;
ic->ic_set_key = iwn_set_key;
ic->ic_delete_key = iwn_delete_key;
+   ic->ic_updatechan = iwn_updatechan;
ic->ic_updateprot = iwn_updateprot;
ic->ic_updateslot = iwn_updateslot;
ic->ic_ampdu_rx_start = iwn_ampdu_rx_start;
@@ -1477,8 +1484,8 @@ iwn4965_read_eeprom(struct iwn_softc *sc)
/* Read regulatory domain (4 ASCII characters). */
iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4);
 
-   /* Read the list of authorized channels (20MHz ones only). */
-   for (i = 0; i < 5; i++) {
+   /* Read the list of authorized channels. */
+   for (i = 0; i < 7; i++) {
addr = iwn4965_regulatory_bands[i];
iwn_read_eeprom_channels(sc, i, addr);
}
@@ -1562,8 +1569,8 @@ iwn5000_read_eeprom(struct iwn_softc *sc)
iwn_read_prom_data(sc, base + IWN5000_EEPROM_DOMAIN,
sc->eeprom_domain, 4);
 
-   /* Read the list of authorized channels (20MHz ones only). */
-   for (i = 0; i < 5; i++) {
+   /* Read the list of authorized channels. */
+   for (i = 0; i < 7; i++) {
addr = base + iwn5000_regulatory_bands[i];
iwn_read_eeprom_channels(sc, i, addr);
}
@@ -1633,7 +1640,7 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, 
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
 
-   } else {/* 5GHz band */
+   } else if (n < 5) { /* 5GHz band */
/*
 * Some adapters support channels 7, 8, 11 and 12
 * both in the 2GHz and 4.9GHz bands.
@@ -1648,22 +1655,29 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, 

Re: add 802.11n 40MHz support to iwn(4)

2021-11-09 Thread Stefan Sperling
On Tue, Nov 09, 2021 at 08:38:11PM +0100, Jan Stary wrote:
> On Nov 09 00:36:03, h...@stare.cz wrote:
> > As a naive test of speed, I am downloading a 100MB file
> > from a http server just behind the AP with
> > ftp -o /dev/null http://stare.cz/.tmp/file
> > An average of ten runs is 5.31 MB/s without the diff
> > and 3.37 MB/s with the (updated) diff.
> 
> Any idea how enabling 40 MHz could slow it down?
> 
>   Jan

No idea. On my 5300 it is much faster, but I have tested it on 5 GHz.
Try a 5 GHz channel instead of a 2GHz channel.



Re: add 802.11n 40MHz support to iwn(4)

2021-11-09 Thread Stefan Sperling
On Mon, Nov 01, 2021 at 12:56:26PM +0100, Stefan Sperling wrote:
> I have tested on a 6205 device. More tests are needed, especially on
> the old 4965AGN generation because those chips require the driver to
> do specific calibration work which newer chips perform in firmware.
> I suspect you will find 4965 devices in older thinkpads which first
> introduced 11n wifi to these laptops (the x60/x61 generation probably).

Does nobody have a 4965AGN device anymore?

The patch is in snaps, so a simple upgrade to the latest snapshot
would be sufficient to test this. Thanks!



iwm/iwx: update last_rx timestamp

2021-11-08 Thread Stefan Sperling
The last_rx timestamp which controls timeout of an Rx block ack
session is not updated when a frame is received.
This can result in the session timing out too early.

Not a huge deal because the AP will simply request a new session when
it has more data to send. And many APs do not even enable session
timeouts in which case our timeout handler remains inactive, too.

But we should handle negotiated session timeouts correctly.

ok?

 
diff 02c3ac519701a4fe198f8ee3de592b34a39ee6f7 
d1e8e8a7b10a061d0364e3a63366e646218124a7
blob - 92f77754c4dd9d8a340a24bc2ce6f89ca77e0f84
blob + 983c18557ae9bef84372346fd4833c530994faa3
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -5121,6 +5121,9 @@ iwm_rx_reorder(struct iwm_softc *sc, struct mbuf *m, i
if (rxba == NULL || tid != rxba->tid || rxba->sta_id != IWM_STATION_ID)
return 0;
 
+   if (rxba->timeout != 0)
+   getmicrouptime(>last_rx);
+
/* Bypass A-MPDU re-ordering in net80211. */
rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
 
blob - 5cac83fd48ebe997a4cd7842730b0cb05f7c28ee
blob + 1ac1ad3b420a9de838df6e2fc30d21c5bcb8661f
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -4202,6 +4202,9 @@ iwx_rx_reorder(struct iwx_softc *sc, struct mbuf *m, i
if (rxba == NULL || tid != rxba->tid || rxba->sta_id != IWX_STATION_ID)
return 0;
 
+   if (rxba->timeout != 0)
+   getmicrouptime(>last_rx);
+
/* Bypass A-MPDU re-ordering in net80211. */
rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
 



sync iwm(4) resume code path with iwx(4)

2021-11-08 Thread Stefan Sperling
The resume code path of iwx(4) was improved during the k2k21 hackathon.
This patch merges the corresponding changes to iwm(4), such that iwm(4)
resumes directly in DVACT_WAKEUP instead of using the init task.

Tested by me on an 8265 device.

ok?

diff 02c3ac519701a4fe198f8ee3de592b34a39ee6f7 
d18bc0f805b2b0ec7e08f833f15080cb1614e08c
blob - 92f77754c4dd9d8a340a24bc2ce6f89ca77e0f84
blob + 2410b7d65756166edd8e68fed251c681eddb8851
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -550,7 +550,8 @@ voidiwm_attach_hook(struct device *);
 void   iwm_attach(struct device *, struct device *, void *);
 void   iwm_init_task(void *);
 intiwm_activate(struct device *, int);
-intiwm_resume(struct iwm_softc *);
+void   iwm_resume(struct iwm_softc *);
+intiwm_wakeup(struct iwm_softc *);
 
 #if NBPFILTER > 0
 void   iwm_radiotap_attach(struct iwm_softc *);
@@ -1554,11 +1555,8 @@ int
 iwm_check_rfkill(struct iwm_softc *sc)
 {
uint32_t v;
-   int s;
int rv;
 
-   s = splnet();
-
/*
 * "documentation" is not really helpful here:
 *  27: HW_RF_KILL_SW
@@ -1574,7 +1572,6 @@ iwm_check_rfkill(struct iwm_softc *sc)
sc->sc_flags &= ~IWM_FLAG_RFKILL;
}
 
-   splx(s);
return rv;
 }
 
@@ -1622,8 +1619,6 @@ iwm_restore_interrupts(struct iwm_softc *sc)
 void
 iwm_disable_interrupts(struct iwm_softc *sc)
 {
-   int s = splnet();
-
if (!sc->sc_msix) {
IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
 
@@ -1636,8 +1631,6 @@ iwm_disable_interrupts(struct iwm_softc *sc)
IWM_WRITE(sc, IWM_CSR_MSIX_HW_INT_MASK_AD,
sc->sc_hw_init_mask);
}
-
-   splx(s);
 }
 
 void
@@ -9679,18 +9672,8 @@ int
 iwm_init_hw(struct iwm_softc *sc)
 {
struct ieee80211com *ic = >sc_ic;
-   int err, i, ac, qid;
+   int err, i, ac, qid, s;
 
-   err = iwm_preinit(sc);
-   if (err)
-   return err;
-
-   err = iwm_start_hw(sc);
-   if (err) {
-   printf("%s: could not initialize hardware\n", DEVNAME(sc));
-   return err;
-   }
-
err = iwm_run_init_mvm_ucode(sc, 0);
if (err)
return err;
@@ -9704,14 +9687,18 @@ iwm_init_hw(struct iwm_softc *sc)
}
 
/* Restart, this time with the regular firmware */
+   s = splnet();
err = iwm_load_ucode_wait_alive(sc, IWM_UCODE_TYPE_REGULAR);
if (err) {
printf("%s: could not load firmware\n", DEVNAME(sc));
-   goto err;
+   splx(s);
+   return err;
}
 
-   if (!iwm_nic_lock(sc))
+   if (!iwm_nic_lock(sc)) {
+   splx(s);
return EBUSY;
+   }
 
err = iwm_send_tx_ant_cfg(sc, iwm_fw_valid_tx_ant(sc));
if (err) {
@@ -9738,20 +9725,20 @@ iwm_init_hw(struct iwm_softc *sc)
if (err) {
printf("%s: could not init bt coex (error %d)\n",
DEVNAME(sc), err);
-   return err;
+   goto err;
}
 
if (isset(sc->sc_enabled_capa,
IWM_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT)) {
err = iwm_send_soc_conf(sc);
if (err)
-   return err;
+   goto err;
}
 
if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_DQA_SUPPORT)) {
err = iwm_send_dqa_cmd(sc);
if (err)
-   return err;
+   goto err;
}
 
/* Add auxiliary station for scanning */
@@ -9859,6 +9846,7 @@ iwm_init_hw(struct iwm_softc *sc)
 
 err:
iwm_nic_unlock(sc);
+   splx(s);
return err;
 }
 
@@ -9902,6 +9890,16 @@ iwm_init(struct ifnet *ifp)
KASSERT(sc->task_refs.refs == 0);
refcnt_init(>task_refs);
 
+   err = iwm_preinit(sc);
+   if (err)
+   return err;
+
+   err = iwm_start_hw(sc);
+   if (err) {
+   printf("%s: could not initialize hardware\n", DEVNAME(sc));
+   return err;
+   }
+
err = iwm_init_hw(sc);
if (err) {
if (generation == sc->sc_generation)
@@ -11180,7 +11178,10 @@ iwm_attach(struct device *parent, struct device *self,
return;
}
 
-   /* Clear device-specific "PCI retry timeout" register (41h). */
+   /*
+* We disable the RETRY_TIMEOUT register (0x41) to keep
+* PCI Tx retries from interfering with C3 CPU state.
+*/
reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
 
@@ -11576,12 +11577,15 @@ iwm_init_task(void *arg1)
splx(s);
 }
 
-int
+void
 iwm_resume(struct iwm_softc *sc)
 {
pcireg_t reg;
 
-   /* Clear device-specific "PCI retry timeout" register (41h). */
+   /*
+* We disable the RETRY_TIMEOUT register (0x41) to keep
+* 

make iwx(4) use per-queue Tx timers

2021-11-08 Thread Stefan Sperling
iwx(4) has an issue which occurs very occasionally for me (every couple
of days or sometimes even weeks) where ssh(1) fails to connect until the
interface is reset with ifconfig down/up.

The initial protocol exchange with the SSH server succeeds, but as soon
as the client enters interactive state and sets TCP_NODELAY the connection
will hang.
While the interface is in this broken state other traffic such as ping
still makes it through, but any new ssh connection attempts show the
same symptom. It is just the interactive SSH packets which are stuck.

TCP_NODELAY packets are mapped to a special QoS TID by net80211, and each
such TID gets mapped to a dedicated Tx aggregation queue by the driver.
Combined with the observation that the Linux driver carries a workaround
for "stuck" individual Tx queues, we are likely facing a situation where
only one Tx queue in the device has stopped working.

Our interface watchdog cannot detect single Tx queue failures at present.
It is satisfied as long as packets make it out on any queue.
With the patch below we use a Tx timer per queue which will hopefully result
in a device timeout when the problem occurs. A manual reset will no longer be
required to unwedge things since the watchdog should now trigger a reset.

It is possible that other hangs which have been reported are related to
this but show different symptoms depending on which Tx queue gets stuck.
If the default Tx agg queue gets stuck it will become impossible to send
data packets that are not marked as TCP_NODELAY. If you are connected over
ssh while this happens the open ssh session might prevent the watchdog from
triggering and no new connections can be made.

I wish we had a fix for Tx queues getting stuck in the first place but this
is the best I can do.

ok?


diff 02c3ac519701a4fe198f8ee3de592b34a39ee6f7 
9b169d95d510ed2f3749ba598aa1cdb81cbff623
blob - 5cac83fd48ebe997a4cd7842730b0cb05f7c28ee
blob + c7dcd675c46e07ae4150a6dfdb90a189187dd5b2
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -4552,8 +4552,6 @@ iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_pack
bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWX_RBUF_SIZE,
BUS_DMASYNC_POSTREAD);
 
-   sc->sc_tx_timer = 0;
-
/* Sanity checks. */
if (sizeof(*tx_resp) > len)
return;
@@ -4563,6 +4561,8 @@ iwx_rx_tx_cmd(struct iwx_softc *sc, struct iwx_rx_pack
tx_resp->frame_count * sizeof(tx_resp->status) > len)
return;
 
+   sc->sc_tx_timer[qid] = 0;
+
if (tx_resp->frame_count > 1) /* A-MPDU */
return;
 
@@ -4658,7 +4658,7 @@ iwx_rx_compressed_ba(struct iwx_softc *sc, struct iwx_
idx = le16toh(ba_tfd->tfd_index);
if (idx >= IWX_TX_RING_COUNT)
continue;
-   sc->sc_tx_timer = 0;
+   sc->sc_tx_timer[qid] = 0;
iwx_txq_advance(sc, ring, idx);
iwx_clear_oactive(sc, ring);
}
@@ -5433,6 +5433,9 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ie
sc->qfullmsk |= 1 << ring->qid;
}
 
+   if (ic->ic_if.if_flags & IFF_UP)
+   sc->sc_tx_timer[ring->qid] = 15;
+
return 0;
 }
 
@@ -7973,10 +7976,8 @@ iwx_start(struct ifnet *ifp)
continue;
}
 
-   if (ifp->if_flags & IFF_UP) {
-   sc->sc_tx_timer = 15;
+   if (ifp->if_flags & IFF_UP)
ifp->if_timer = 1;
-   }
}
 
return;
@@ -8045,7 +8046,8 @@ iwx_stop(struct ifnet *ifp)
struct iwx_rxba_data *rxba = >sc_rxba_data[i];
iwx_clear_reorder_buffer(sc, rxba);
}
-   ifp->if_timer = sc->sc_tx_timer = 0;
+   memset(sc->sc_tx_timer, 0, sizeof(sc->sc_tx_timer));
+   ifp->if_timer = 0;
 
splx(s);
 }
@@ -8054,21 +8056,30 @@ void
 iwx_watchdog(struct ifnet *ifp)
 {
struct iwx_softc *sc = ifp->if_softc;
+   int i;
 
ifp->if_timer = 0;
-   if (sc->sc_tx_timer > 0) {
-   if (--sc->sc_tx_timer == 0) {
-   printf("%s: device timeout\n", DEVNAME(sc));
-   if (ifp->if_flags & IFF_DEBUG) {
-   iwx_nic_error(sc);
-   iwx_dump_driver_status(sc);
+
+   /*
+* We maintain a separate timer for each Tx queue because
+* Tx aggregation queues can get "stuck" while other queues
+* keep working. The Linux driver uses a similar workaround.
+*/
+   for (i = 0; i < nitems(sc->sc_tx_timer); i++) {
+   if (sc->sc_tx_timer[i] > 0) {
+   if (--sc->sc_tx_timer[i] == 0) {
+   printf("%s: device timeout\n", DEVNAME(sc));
+   if (ifp->if_flags & IFF_DEBUG) {
+   iwx_nic_error(sc);
+ 

Re: net80211: use BSS load information when choosing access point

2021-11-06 Thread Stefan Sperling
On Wed, Nov 03, 2021 at 02:47:39PM +0100, Stefan Sperling wrote:
> If channel load is not a reliable indicator I would hope vendors are at
> least able to reliably count and report the number of associated stations?

Here is new patch which makes the following changes relative to the
previous version:

Only use BSS load to resolve a tie between APs which meet a minimum RSSI
threshold. Otherwise we keep relying on RSSI as the only indicator.
I hope this will avoid APs which are too far away to be usable.

Ignore channel load values advertised by APs, since they are unreliable
according to research done by hostapd developers. Only use the number
of associated stations as the indicator of BSS load.

ok?

diff 8c2348c4b5d36dddcf1de4644b5bb2c5dd715299 
bc115f3279aa8e472b2d369c2a15d792574a27a1
blob - 888a39c43dd0bbe0629998a8bb1e24a66466c092
blob + 5bd87ce70a265cd354e29b105cfe48ead88b93a6
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -1606,7 +1606,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
const struct ieee80211_frame *wh;
const u_int8_t *frm, *efrm;
const u_int8_t *tstamp, *ssid, *rates, *xrates, *edcaie, *wmmie;
-   const u_int8_t *rsnie, *wpaie, *htcaps, *htop;
+   const u_int8_t *rsnie, *wpaie, *htcaps, *htop, *bssload;
u_int16_t capinfo, bintval;
u_int8_t chan, bchan, erp, dtim_count, dtim_period;
int is_new;
@@ -1647,7 +1647,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
capinfo = LE_READ_2(frm); frm += 2;
 
ssid = rates = xrates = edcaie = wmmie = rsnie = wpaie = NULL;
-   htcaps = htop = NULL;
+   htcaps = htop = bssload = NULL;
bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
chan = bchan;
erp = 0;
@@ -1712,6 +1712,13 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
wmmie = frm;
}
break;
+   case IEEE80211_ELEMID_QBSS_LOAD:
+   if (frm[1] < 5) {
+   ic->ic_stats.is_rx_elem_toosmall++;
+   break;
+   }
+   bssload = frm;
+   break;
}
frm += 2 + frm[1];
}
@@ -1975,6 +1982,18 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
ni->ni_rsncaps = wpa.rsn_caps;
}
}
+
+   if (bssload != NULL) {
+   ni->ni_stacnt = bssload[2] | (bssload[3] << 8);
+   ni->ni_chanutil = (bssload[4] * 100) / 255;
+   ni->ni_admcap = (bssload[5] | (bssload[6] << 8)) / 32;
+   ni->ni_flags |= IEEE80211_NODE_BSSLOAD;
+   } else {
+   ni->ni_stacnt = 0;
+   ni->ni_chanutil = 0;
+   ni->ni_admcap = 0;
+   ni->ni_flags &= ~IEEE80211_NODE_BSSLOAD;
+   }
}
 
if (ssid[1] != 0 && ni->ni_essid[0] == '\0') {
blob - 2fe4984654e67cc638ea1f7b3e48cbeeae24ecca
blob + d0537167f455b4fc3aa514e3c6cee79a2f4d8e59
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -74,6 +74,8 @@ void ieee80211_setup_node(struct ieee80211com *, struc
 const u_int8_t *);
 struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *);
 void ieee80211_node_switch_bss(struct ieee80211com *, struct ieee80211_node *);
+int ieee80211_node_prefer_bss(struct ieee80211com *, struct ieee80211_node *,
+struct ieee80211_node *);
 void ieee80211_node_addba_request(struct ieee80211_node *, int);
 void ieee80211_node_addba_request_ac_be_to(void *);
 void ieee80211_node_addba_request_ac_bk_to(void *);
@@ -1286,6 +1288,45 @@ ieee80211_node_join_bss(struct ieee80211com *ic, struc
}
 }
 
+int
+ieee80211_node_prefer_bss(struct ieee80211com *ic,
+struct ieee80211_node *selbs, struct ieee80211_node *ni)
+{
+   uint8_t min_2ghz_rssi, min_5ghz_rssi, min_ni_rssi, min_selbs_rssi;
+
+   if (selbs == NULL)
+   return 1;
+
+   if (ic->ic_max_rssi) {
+   min_2ghz_rssi = IEEE80211_RSSI_THRES_RATIO_2GHZ;
+   min_5ghz_rssi = IEEE80211_RSSI_THRES_RATIO_5GHZ;
+   } else {
+   min_2ghz_rssi = (uint8_t)IEEE80211_RSSI_THRES_2GHZ;
+   min_5ghz_rssi = (uint8_t)IEEE80211_RSSI_THRES_5GHZ;
+   }
+   min_ni_rssi = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ?
+   min_5ghz_rssi : min_2ghz_rssi;
+   min_selbs_rssi = IEEE80211_IS_CHAN_5GHZ(selbs->ni_chan) ?
+   min_5ghz_rssi : min_2ghz_rssi;
+
+   if ((ni->ni_flags & IEEE80211_NODE_BSSLOAD) &&
+   (selbs->ni_flags & IEEE80211_NODE_BSSLOAD) &&
+   ni->ni_rssi &

Re: net80211: use BSS load information when choosing access point

2021-11-03 Thread Stefan Sperling
On Wed, Nov 03, 2021 at 04:03:08PM +0300, Sergey Ryazanov wrote:
> Hello Stefan,
> 
> On Sun, Oct 31, 2021 at 9:25 PM Stefan Sperling  wrote:
> > Some access points advertise BSS load information in beacons in
> > order to help clients make informed roaming decisions.
> >
> > BSS load information includes the number of associated stations,
> > the channel utilization (this takes other networks on the same
> > channel into account), and current admission capacity (interesting
> > for clients which use QoS, which we do not).
> >
> > We currently ignore BSS load information and only use RSSI to tell APs
> > apart. With this patch we store bss load information for APs during
> > scans if available, and take it into account when chosing an access point.
> >
> > Unfortunately, I do not have a suitable AP available to test with.
> > tcpdump can be used to check whether an access point supports this
> > feature. Run this command while associated to the access point:
> >  tcpdump -n -i iwm0 -y IEEE802_11_RADIO -s 4096 -v
> >
> > If the AP reports BSS load information you should see something like
> > this among the information printed by tcpdump:
> >   64 stations, 100% utilization, admission capacity 0us/s
> >
> > It would help to get this patch tested in an environment where access
> > points advertise BSS load information, with a roaming test between
> > different access points.
> > I wrote down information about how roaming can be tested here:
> > https://marc.info/?l=openbsd-tech=163329420019842=2
> 
> This topic was discussed a couple of weeks ago on the hostapd mailing
> list (http://lists.infradead.org/pipermail/hostap/2021-October/039961.html).
> And Jouni Malinen provide a few concerns about switching to the QBSS
> load IE usage. I would like to quote him:
> 
> > I would also point out that at least the last time I did some testing
> > between vendor implementations, the reported values were completely
> > different between two APs on the same channel in more or less the same
> > location in the test setup.. In other words, I would not place much, if
> > any, trust in this value being something that could be compared between
> > two different APs. The only thing that seemed to be more or less
> > comparable was the values from the same AP device in a sense that the
> > channel load value increased when there was more traffic on the
> > channel..
> 
> So I do not think that the complete switching to the BSS load metric
> is a good idea. But utilizing the AP assistance in the BSS selection
> procedure sounds nice.

I wasn't aware of this research that was done at hostapd. This is good
to know and might save us some time in figuring out how to use these
metrics properly. Thanks!

My patch ignores RSSI on purpose in case BSS load is advertised precisely
because we need to figure out whether "channel load" is indicated reliably.
The standard doesn't really go into much detail about how to decide whether
a channel is "busy". It suggests that either virtual or physical carrier
sense could be used. I guess just letting any faint but valid wifi signal
block the channel would be a bad idea. So vendors may need to use some
threshold to decide whether a given signal is actually keeping the channel
busy in the vicinity of the AP. As with RSSI, measurements of such physical
quantities could differ between any two given APs and between moments in
time for a single AP.

If channel load is not a reliable indicator I would hope vendors are at
least able to reliably count and report the number of associated stations?



Re: ifconfig: return non-zero on failed "nwkey"

2021-11-02 Thread Stefan Sperling
On Tue, Nov 02, 2021 at 05:26:17PM +, Klemens Nanni wrote:
> At least bwfm(4) does not support WEP:
> 
>   # ifconfig bwfm0 nwkey 12345  
>   ifconfig: SIOCS80211NWKEY: Operation not supported by device
>   # echo $?
>   0
> 
> ifconfig(8) must return non-zero in this case.
> 
> This is relevant for an upcoming installer fix, but also worth itself.
> 
> OK?

Yes, ok.

But regardless, this error should never happen.
It looks like bwfm(4) does support WEP but the C_WEP capability is missing
from ic_caps so net80211 believes WEP was not supported by this driver.

I don't think we have any supported wifi device that does not support WEP.
Even an(4) supports WEP!

> Index: ifconfig.c
> ===
> RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
> retrieving revision 1.445
> diff -u -p -r1.445 ifconfig.c
> --- ifconfig.c6 Oct 2021 06:14:08 -   1.445
> +++ ifconfig.c2 Nov 2021 17:20:01 -
> @@ -2033,7 +2033,7 @@ setifnwkey(const char *val, int d)
>   }
>  
>   if (ioctl(sock, SIOCS80211NWKEY, (caddr_t)) == -1)
> - warn("SIOCS80211NWKEY");
> + err("SIOCS80211NWKEY");
>  }
>  
>  /* ARGSUSED */
> 
> 



Re: add 802.11n 40MHz support to iwn(4)

2021-11-02 Thread Stefan Sperling
On Mon, Nov 01, 2021 at 12:56:26PM +0100, Stefan Sperling wrote:
> This patch adds 802.11n 40MHz support to the iwn(4) driver.
> 
> This driver supports many different devices. Please try to be precise
> about which device you have tested so I can maintain a record of our
> test coverage.

Here is a new version of the iwn 40MHz patch.

The previous version of this patch introduced a performance regression
on a 6200 device I have tested with. The only workaround I found so far
is to disable SGI on 40MHz for these devices. This hides the problem and
is not a real fix. But even without the 40MHz patch Tx performance is
suboptimal on this device. It never manages to transmit frames on MCS 5
or higher. Perhaps this device is not properly calibrated by our driver.
In any case, it is a separate issue which this 40MHz patch does not need
to solve.

Other changes are merely cosmetic.

diff refs/heads/master refs/heads/40mhz
blob - aff55acd0f19afbd39ffc78596af5349df58468f
blob + f94b88d85d595cc61209045370b51789262eedcd
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -241,12 +241,16 @@ uint16_t  iwn_get_passive_dwell_time(struct iwn_softc *
 intiwn_scan(struct iwn_softc *, uint16_t, int);
 void   iwn_scan_abort(struct iwn_softc *);
 intiwn_bgscan(struct ieee80211com *);
+void   iwn_rxon_configure_ht40(struct ieee80211com *,
+   struct ieee80211_node *);
+intiwn_rxon_ht40_enabled(struct iwn_softc *);
 intiwn_auth(struct iwn_softc *, int);
 intiwn_run(struct iwn_softc *);
 intiwn_set_key(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_key *);
 void   iwn_delete_key(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_key *);
+void   iwn_updatechan(struct ieee80211com *);
 void   iwn_updateprot(struct ieee80211com *);
 void   iwn_updateslot(struct ieee80211com *);
 void   iwn_update_rxon(struct iwn_softc *);
@@ -489,13 +493,15 @@ iwn_attach(struct device *parent, struct device *self,
ic->ic_caps |= (IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU);
/* Set HT capabilities. */
ic->ic_htcaps = IEEE80211_HTCAP_SGI20;
+   /* 6200 devices have issues with SGI40 for some reason. */
+   if ((sc->sc_flags & IWN_FLAG_INTERNAL_PA) == 0)
+   ic->ic_htcaps |= IEEE80211_HTCAP_SGI40;
+   ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40;
 #ifdef notyet
ic->ic_htcaps |=
 #if IWN_RBUF_SIZE == 8192
IEEE80211_HTCAP_AMSDU7935 |
 #endif
-   IEEE80211_HTCAP_CBW20_40 |
-   IEEE80211_HTCAP_SGI40;
if (sc->hw_type != IWN_HW_REV_TYPE_4965)
ic->ic_htcaps |= IEEE80211_HTCAP_GF;
if (sc->hw_type == IWN_HW_REV_TYPE_6050)
@@ -541,6 +547,7 @@ iwn_attach(struct device *parent, struct device *self,
ic->ic_updateedca = iwn_updateedca;
ic->ic_set_key = iwn_set_key;
ic->ic_delete_key = iwn_delete_key;
+   ic->ic_updatechan = iwn_updatechan;
ic->ic_updateprot = iwn_updateprot;
ic->ic_updateslot = iwn_updateslot;
ic->ic_ampdu_rx_start = iwn_ampdu_rx_start;
@@ -1473,8 +1480,8 @@ iwn4965_read_eeprom(struct iwn_softc *sc)
/* Read regulatory domain (4 ASCII characters). */
iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4);
 
-   /* Read the list of authorized channels (20MHz ones only). */
-   for (i = 0; i < 5; i++) {
+   /* Read the list of authorized channels. */
+   for (i = 0; i < 7; i++) {
addr = iwn4965_regulatory_bands[i];
iwn_read_eeprom_channels(sc, i, addr);
}
@@ -1558,8 +1565,8 @@ iwn5000_read_eeprom(struct iwn_softc *sc)
iwn_read_prom_data(sc, base + IWN5000_EEPROM_DOMAIN,
sc->eeprom_domain, 4);
 
-   /* Read the list of authorized channels (20MHz ones only). */
-   for (i = 0; i < 5; i++) {
+   /* Read the list of authorized channels. */
+   for (i = 0; i < 7; i++) {
addr = base + iwn5000_regulatory_bands[i];
iwn_read_eeprom_channels(sc, i, addr);
}
@@ -1629,7 +1636,7 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, 
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
 
-   } else {/* 5GHz band */
+   } else if (n < 5) { /* 5GHz band */
/*
 * Some adapters support channels 7, 8, 11 and 12
 * both in the 2GHz and 4.9GHz bands.
@@ -1644,22 +1651,29 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, 
 

Re: add 802.11n 40MHz support to iwn(4)

2021-11-01 Thread Stefan Sperling
On Mon, Nov 01, 2021 at 12:56:26PM +0100, Stefan Sperling wrote:
> To check whether your access point uses a 40MHz channel, run this command
> while associated to the access point:
>   tcpdump -n -i iwm0 -v -y IEEE802_11_RADIO -s 4096 type mgt and subtype 
> beacon

Oops, this should of course say -i iwn0 instead of -i iwm0.



add 802.11n 40MHz support to iwn(4)

2021-11-01 Thread Stefan Sperling
This patch adds 802.11n 40MHz support to the iwn(4) driver.

This driver supports many different devices. Please try to be precise
about which device you have tested so I can maintain a record of our
test coverage.

I have tested on a 6205 device. More tests are needed, especially on
the old 4965AGN generation because those chips require the driver to
do specific calibration work which newer chips perform in firmware.
I suspect you will find 4965 devices in older thinkpads which first
introduced 11n wifi to these laptops (the x60/x61 generation probably).

Because iwn(4) does not support MIMO yet, this pushes maximum throughput
from about 50 Mbit/s up to about 100 Mbit/s. Adding MIMO support would
probably double the speed again, but that is left for the future.

To check whether your access point uses a 40MHz channel, run this command
while associated to the access point:
  tcpdump -n -i iwm0 -v -y IEEE802_11_RADIO -s 4096 type mgt and subtype beacon

The htop information element displayed by this command includes the
channel width. A 40MHz channel looks like this: htop=<40MHz chan X:Y >

diff refs/heads/master refs/heads/40mhz
blob - aff55acd0f19afbd39ffc78596af5349df58468f
blob + 853274d96496ec16fcf7d876f7922470cbd7bc17
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -241,12 +241,16 @@ uint16_t  iwn_get_passive_dwell_time(struct iwn_softc *
 intiwn_scan(struct iwn_softc *, uint16_t, int);
 void   iwn_scan_abort(struct iwn_softc *);
 intiwn_bgscan(struct ieee80211com *);
+void   iwn_rxon_configure_ht40(struct ieee80211com *,
+   struct ieee80211_node *);
+intiwn_rxon_ht40_enabled(struct iwn_softc *);
 intiwn_auth(struct iwn_softc *, int);
 intiwn_run(struct iwn_softc *);
 intiwn_set_key(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_key *);
 void   iwn_delete_key(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_key *);
+void   iwn_updatechan(struct ieee80211com *);
 void   iwn_updateprot(struct ieee80211com *);
 void   iwn_updateslot(struct ieee80211com *);
 void   iwn_update_rxon(struct iwn_softc *);
@@ -488,14 +492,13 @@ iwn_attach(struct device *parent, struct device *self,
if (sc->sc_flags & IWN_FLAG_HAS_11N) {
ic->ic_caps |= (IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU);
/* Set HT capabilities. */
-   ic->ic_htcaps = IEEE80211_HTCAP_SGI20;
+   ic->ic_htcaps = IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_SGI40;
+   ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40;
 #ifdef notyet
ic->ic_htcaps |=
 #if IWN_RBUF_SIZE == 8192
IEEE80211_HTCAP_AMSDU7935 |
 #endif
-   IEEE80211_HTCAP_CBW20_40 |
-   IEEE80211_HTCAP_SGI40;
if (sc->hw_type != IWN_HW_REV_TYPE_4965)
ic->ic_htcaps |= IEEE80211_HTCAP_GF;
if (sc->hw_type == IWN_HW_REV_TYPE_6050)
@@ -541,6 +544,7 @@ iwn_attach(struct device *parent, struct device *self,
ic->ic_updateedca = iwn_updateedca;
ic->ic_set_key = iwn_set_key;
ic->ic_delete_key = iwn_delete_key;
+   ic->ic_updatechan = iwn_updatechan;
ic->ic_updateprot = iwn_updateprot;
ic->ic_updateslot = iwn_updateslot;
ic->ic_ampdu_rx_start = iwn_ampdu_rx_start;
@@ -1473,8 +1477,8 @@ iwn4965_read_eeprom(struct iwn_softc *sc)
/* Read regulatory domain (4 ASCII characters). */
iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4);
 
-   /* Read the list of authorized channels (20MHz ones only). */
-   for (i = 0; i < 5; i++) {
+   /* Read the list of authorized channels. */
+   for (i = 0; i < 7; i++) {
addr = iwn4965_regulatory_bands[i];
iwn_read_eeprom_channels(sc, i, addr);
}
@@ -1558,8 +1562,8 @@ iwn5000_read_eeprom(struct iwn_softc *sc)
iwn_read_prom_data(sc, base + IWN5000_EEPROM_DOMAIN,
sc->eeprom_domain, 4);
 
-   /* Read the list of authorized channels (20MHz ones only). */
-   for (i = 0; i < 5; i++) {
+   /* Read the list of authorized channels. */
+   for (i = 0; i < 7; i++) {
addr = base + iwn5000_regulatory_bands[i];
iwn_read_eeprom_channels(sc, i, addr);
}
@@ -1629,7 +1633,7 @@ iwn_read_eeprom_channels(struct iwn_softc *sc, int n, 
IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
 
-   } else {/* 5GHz band */
+   } else if (n < 5) { /* 5GHz band */
/*
 * Some adapters support channels 7, 8, 11 and 12
 * both in the 2GHz and 4.9GHz bands.
@@ -1644,22 +1648,29 @@ 

net80211: use BSS load information when choosing access point

2021-10-31 Thread Stefan Sperling
Some access points advertise BSS load information in beacons in
order to help clients make informed roaming decisions.

BSS load information includes the number of associated stations,
the channel utilization (this takes other networks on the same
channel into account), and current admission capacity (interesting
for clients which use QoS, which we do not).

We currently ignore BSS load information and only use RSSI to tell APs
apart. With this patch we store bss load information for APs during
scans if available, and take it into account when chosing an access point.

Unfortunately, I do not have a suitable AP available to test with.
tcpdump can be used to check whether an access point supports this
feature. Run this command while associated to the access point:
 tcpdump -n -i iwm0 -y IEEE802_11_RADIO -s 4096 -v

If the AP reports BSS load information you should see something like
this among the information printed by tcpdump:
  64 stations, 100% utilization, admission capacity 0us/s

It would help to get this patch tested in an environment where access
points advertise BSS load information, with a roaming test between
different access points.
I wrote down information about how roaming can be tested here:
https://marc.info/?l=openbsd-tech=163329420019842=2

Thanks!

diff 8c2348c4b5d36dddcf1de4644b5bb2c5dd715299 
187113184307352db702dff07a73873bbd1f087c
blob - 888a39c43dd0bbe0629998a8bb1e24a66466c092
blob + 5bd87ce70a265cd354e29b105cfe48ead88b93a6
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -1606,7 +1606,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
const struct ieee80211_frame *wh;
const u_int8_t *frm, *efrm;
const u_int8_t *tstamp, *ssid, *rates, *xrates, *edcaie, *wmmie;
-   const u_int8_t *rsnie, *wpaie, *htcaps, *htop;
+   const u_int8_t *rsnie, *wpaie, *htcaps, *htop, *bssload;
u_int16_t capinfo, bintval;
u_int8_t chan, bchan, erp, dtim_count, dtim_period;
int is_new;
@@ -1647,7 +1647,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
capinfo = LE_READ_2(frm); frm += 2;
 
ssid = rates = xrates = edcaie = wmmie = rsnie = wpaie = NULL;
-   htcaps = htop = NULL;
+   htcaps = htop = bssload = NULL;
bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
chan = bchan;
erp = 0;
@@ -1712,6 +1712,13 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
wmmie = frm;
}
break;
+   case IEEE80211_ELEMID_QBSS_LOAD:
+   if (frm[1] < 5) {
+   ic->ic_stats.is_rx_elem_toosmall++;
+   break;
+   }
+   bssload = frm;
+   break;
}
frm += 2 + frm[1];
}
@@ -1975,6 +1982,18 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
ni->ni_rsncaps = wpa.rsn_caps;
}
}
+
+   if (bssload != NULL) {
+   ni->ni_stacnt = bssload[2] | (bssload[3] << 8);
+   ni->ni_chanutil = (bssload[4] * 100) / 255;
+   ni->ni_admcap = (bssload[5] | (bssload[6] << 8)) / 32;
+   ni->ni_flags |= IEEE80211_NODE_BSSLOAD;
+   } else {
+   ni->ni_stacnt = 0;
+   ni->ni_chanutil = 0;
+   ni->ni_admcap = 0;
+   ni->ni_flags &= ~IEEE80211_NODE_BSSLOAD;
+   }
}
 
if (ssid[1] != 0 && ni->ni_essid[0] == '\0') {
blob - 2fe4984654e67cc638ea1f7b3e48cbeeae24ecca
blob + f09c34dca9ffcfc1fca60c1db984c22d6f1c482d
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -74,6 +74,7 @@ void ieee80211_setup_node(struct ieee80211com *, struc
 const u_int8_t *);
 struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *);
 void ieee80211_node_switch_bss(struct ieee80211com *, struct ieee80211_node *);
+int ieee80211_node_prefer_bss(struct ieee80211_node *, struct ieee80211_node 
*);
 void ieee80211_node_addba_request(struct ieee80211_node *, int);
 void ieee80211_node_addba_request_ac_be_to(void *);
 void ieee80211_node_addba_request_ac_bk_to(void *);
@@ -1286,6 +1287,27 @@ ieee80211_node_join_bss(struct ieee80211com *ic, struc
}
 }
 
+int
+ieee80211_node_prefer_bss(struct ieee80211_node *selbs,
+struct ieee80211_node *ni)
+{
+   if (selbs == NULL)
+   return 1;
+
+   if ((ni->ni_flags & IEEE80211_NODE_BSSLOAD) &&
+   (selbs->ni_flags & IEEE80211_NODE_BSSLOAD)) {
+   if (ni->ni_chanutil < selbs->ni_chanutil)
+   return 1;
+   if (ni->ni_stacnt < selbs->ni_stacnt)
+   return 1;
+   }
+
+   if (ni->ni_rssi > selbs->ni_rssi)
+  

iwx(4) 40MHz channel support

2021-10-12 Thread Stefan Sperling
This patch adds support for 40MHz channels to iwx(4).

Please sync your source tree before attempting to apply this patch.
I have committed some changes to this driver today which this patch
is based on.

Works for me on AX200/AX201. Does anyone else want to do a pre-commit test?
 
diff bc49c35a84a7d84bd19566853e5500905f6d6683 
d5f8682e8252112f70b678e0d1c789d8d657fac4
blob - ae0b27d1ad7bc17f6df0cc5b04f2ebd3c3a3977b
blob + 46c924393c6e1651af38b981b2d197cf952e40e3
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -305,6 +305,8 @@ voidiwx_init_channel_map(struct iwx_softc *, 
uint16_t
 void   iwx_setup_ht_rates(struct iwx_softc *);
 intiwx_mimo_enabled(struct iwx_softc *);
 void   iwx_mac_ctxt_task(void *);
+void   iwx_phy_ctxt_task(void *);
+void   iwx_updatechan(struct ieee80211com *);
 void   iwx_updateprot(struct ieee80211com *);
 void   iwx_updateslot(struct ieee80211com *);
 void   iwx_updateedca(struct ieee80211com *);
@@ -360,11 +362,11 @@ void  iwx_rx_bmiss(struct iwx_softc *, struct 
iwx_rx_pa
struct iwx_rx_data *);
 intiwx_binding_cmd(struct iwx_softc *, struct iwx_node *, uint32_t);
 intiwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *, struct iwx_phy_ctxt *, 
uint8_t,
-   uint8_t, uint32_t);
+   uint8_t, uint32_t, uint8_t);
 intiwx_phy_ctxt_cmd_v3(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t);
+   uint8_t, uint32_t, uint8_t);
 intiwx_phy_ctxt_cmd(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t);
+   uint8_t, uint32_t, uint32_t, uint8_t);
 intiwx_send_cmd(struct iwx_softc *, struct iwx_host_cmd *);
 intiwx_send_cmd_pdu(struct iwx_softc *, uint32_t, uint32_t, uint16_t,
const void *);
@@ -426,7 +428,7 @@ uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ie
 intiwx_rs_init(struct iwx_softc *, struct iwx_node *);
 intiwx_enable_data_tx_queues(struct iwx_softc *);
 intiwx_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *,
-   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t);
+   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t);
 intiwx_auth(struct iwx_softc *);
 intiwx_deauth(struct iwx_softc *);
 intiwx_run(struct iwx_softc *);
@@ -2752,8 +2754,11 @@ iwx_init_channel_map(struct iwx_softc *sc, uint16_t *c
if (!(ch_flags & IWX_NVM_CHANNEL_ACTIVE))
channel->ic_flags |= IEEE80211_CHAN_PASSIVE;
 
-   if (data->sku_cap_11n_enable)
+   if (data->sku_cap_11n_enable) {
channel->ic_flags |= IEEE80211_CHAN_HT;
+   if (ch_flags & IWX_NVM_CHANNEL_40MHZ)
+   channel->ic_flags |= IEEE80211_CHAN_40MHZ;
+   }
}
 }
 
@@ -3083,6 +3088,50 @@ iwx_mac_ctxt_task(void *arg)
 }
 
 void
+iwx_phy_ctxt_task(void *arg)
+{
+   struct iwx_softc *sc = arg;
+   struct ieee80211com *ic = >sc_ic;
+   struct iwx_node *in = (void *)ic->ic_bss;
+   struct ieee80211_node *ni = >in_ni;
+   uint8_t chains, sco;
+   int err, s = splnet();
+
+   if ((sc->sc_flags & IWX_FLAG_SHUTDOWN) ||
+   ic->ic_state != IEEE80211_S_RUN ||
+   in->in_phyctxt == NULL) {
+   refcnt_rele_wake(>task_refs);
+   splx(s);
+   return;
+   }
+
+   chains = iwx_mimo_enabled(sc) ? 2 : 1;
+   if (ieee80211_node_supports_ht_chan40(ni))
+   sco = (ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK);
+   else
+   sco = IEEE80211_HTOP0_SCO_SCN;
+   if (in->in_phyctxt->sco != sco) {
+   err = iwx_phy_ctxt_update(sc, in->in_phyctxt,
+   in->in_phyctxt->channel, chains, chains, 0, sco);
+   if (err)
+   printf("%s: failed to update PHY\n", DEVNAME(sc));
+   }
+
+   refcnt_rele_wake(>task_refs);
+   splx(s);
+}
+
+void
+iwx_updatechan(struct ieee80211com *ic)
+{
+   struct iwx_softc *sc = ic->ic_softc;
+
+   if (ic->ic_state == IEEE80211_S_RUN &&
+   !task_pending(>newstate_task))
+   iwx_add_task(sc, systq, >phy_ctxt_task);
+}
+
+void
 iwx_updateprot(struct ieee80211com *ic)
 {
struct iwx_softc *sc = ic->ic_softc;
@@ -4693,7 +4742,7 @@ iwx_binding_cmd(struct iwx_softc *sc, struct iwx_node 
 
 int
 iwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *sc, struct iwx_phy_ctxt *ctxt,
-uint8_t chains_static, uint8_t chains_dynamic, uint32_t action)
+uint8_t chains_static, uint8_t chains_dynamic, uint32_t action, uint8_t 
sco)
 {
struct ieee80211com *ic = >sc_ic;
struct iwx_phy_context_cmd_uhb cmd;
@@ -4714,8 +4763,23 @@ iwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *sc, struct i
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 = 

Re: iwx: remove support for old firmware versions

2021-10-11 Thread Stefan Sperling
On Fri, Oct 08, 2021 at 12:05:23PM +0200, Stefan Sperling wrote:
> This patch removes code which is only required for running with older
> firmware versions (older than -63). This will make it easier to add
> new features, such as 40MHz support. Some code removed here would
> otherwise need to be updated as well, which is pointless extra work.
> 
> I have tested on AX200/AX201 devices which use the following images:
> 
>  /etc/firmware/iwx-cc-a0-63
>  /etc/firmware/iwx-QuZ-a0-hr-b0-63
> 
> It would be great to get at least one pre-commit test report for
> devices which use this image:
> 
>  /etc/firmware/iwx-Qu-c0-hr-b0-63
> 
> Such devices show up with 'Product ID: 0x34f0' in pcidump(8).
> I do not have such hardware. Can someone help out?
> 
> ok?

I am still looking for a test report with a 0x34f0 device.
If anyone could take this patch for quick spin on such a device, it
would be appreciated and allow me to proceed with more interesting work.

> 
> diff 2611d0ab4f1e42a3f2c5db88a7a8cf0f1d94ef39 
> e2fce28332a64af2eb947d764f33d3255719ec95
> blob - 2cb39f6f37c89487e80cae7c423309688622031f
> blob + f317cea613e3fb89360340cf90c918dac986d863
> --- sys/dev/pci/if_iwx.c
> +++ sys/dev/pci/if_iwx.c
> @@ -301,9 +301,6 @@ int   iwx_enable_txq(struct iwx_softc *, int, int, 
> int, 
>  void iwx_post_alive(struct iwx_softc *);
>  int  iwx_schedule_session_protection(struct iwx_softc *, struct iwx_node *,
>   uint32_t);
> -void iwx_protect_session(struct iwx_softc *, struct iwx_node *, uint32_t,
> - uint32_t);
> -void iwx_unprotect_session(struct iwx_softc *, struct iwx_node *);
>  void iwx_init_channel_map(struct iwx_softc *, uint16_t *, uint32_t *, int);
>  void iwx_setup_ht_rates(struct iwx_softc *);
>  int  iwx_mimo_enabled(struct iwx_softc *);
> @@ -366,8 +363,6 @@ int   iwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *, 
> struct
>   uint8_t, uint32_t);
>  int  iwx_phy_ctxt_cmd_v3(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
>   uint8_t, uint32_t);
> -int  iwx_phy_ctxt_cmd_uhb(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
> - uint8_t, uint32_t, uint32_t);
>  int  iwx_phy_ctxt_cmd(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
>   uint8_t, uint32_t, uint32_t);
>  int  iwx_send_cmd(struct iwx_softc *, struct iwx_host_cmd *);
> @@ -397,12 +392,10 @@ int iwx_power_update_device(struct iwx_softc *);
>  int  iwx_enable_beacon_filter(struct iwx_softc *, struct iwx_node *);
>  int  iwx_disable_beacon_filter(struct iwx_softc *);
>  int  iwx_add_sta_cmd(struct iwx_softc *, struct iwx_node *, int);
> -int  iwx_add_aux_sta(struct iwx_softc *);
>  int  iwx_rm_sta_cmd(struct iwx_softc *, struct iwx_node *);
>  int  iwx_rm_sta(struct iwx_softc *, struct iwx_node *);
>  int  iwx_fill_probe_req(struct iwx_softc *, struct iwx_scan_probe_req *);
>  int  iwx_config_umac_scan_reduced(struct iwx_softc *);
> -int  iwx_config_umac_scan(struct iwx_softc *);
>  uint16_t iwx_scan_umac_flags_v2(struct iwx_softc *, int);
>  void iwx_scan_umac_dwell_v10(struct iwx_softc *,
>   struct iwx_scan_general_params_v10 *, int);
> @@ -411,7 +404,6 @@ void  iwx_scan_umac_fill_general_p_v10(struct 
> iwx_softc
>  void iwx_scan_umac_fill_ch_p_v6(struct iwx_softc *,
>   struct iwx_scan_channel_params_v6 *, uint32_t, int, int);
>  int  iwx_umac_scan_v14(struct iwx_softc *, int);
> -int  iwx_umac_scan(struct iwx_softc *, int);
>  void iwx_mcc_update(struct iwx_softc *, struct iwx_mcc_chub_notif *);
>  uint8_t  iwx_ridx2rate(struct ieee80211_rateset *, int);
>  int  iwx_rval2ridx(int);
> @@ -422,7 +414,6 @@ void  iwx_mac_ctxt_cmd_fill_sta(struct iwx_softc *, 
> str
>   struct iwx_mac_data_sta *, int);
>  int  iwx_mac_ctxt_cmd(struct iwx_softc *, struct iwx_node *, uint32_t, int);
>  int  iwx_clear_statistics(struct iwx_softc *);
> -int  iwx_update_quotas(struct iwx_softc *, struct iwx_node *, int);
>  void iwx_add_task(struct iwx_softc *, struct taskq *, struct task *);
>  void iwx_del_task(struct iwx_softc *, struct taskq *, struct task *);
>  int  iwx_scan(struct iwx_softc *);
> @@ -2670,64 +2661,6 @@ iwx_schedule_session_protection(struct iwx_softc *sc, 
>   return iwx_send_cmd_pdu(sc, cmd_id, 0, sizeof(cmd), );
>  }
>  
> -void
> -iwx_protect_session(struct iwx_softc *sc, struct iwx_node *in,
> -uint32_t duration, uint32_t max_delay)
> -{
> - struct iwx_time_event_cmd time_cmd;
> -
> - /* Do nothing if a time event is already scheduled. */
> - if (sc->sc_flags & IWX_FLAG_TE_ACTIVE)
> - return;
> -
> - memset(_cmd, 0, sizeof(time_cmd));
> -
> - time_cmd.action = htole32(IWX_FW_CTXT_ACTION_ADD);
&

iwx: remove support for old firmware versions

2021-10-08 Thread Stefan Sperling
This patch removes code which is only required for running with older
firmware versions (older than -63). This will make it easier to add
new features, such as 40MHz support. Some code removed here would
otherwise need to be updated as well, which is pointless extra work.

I have tested on AX200/AX201 devices which use the following images:

   /etc/firmware/iwx-cc-a0-63
   /etc/firmware/iwx-QuZ-a0-hr-b0-63

It would be great to get at least one pre-commit test report for
devices which use this image:

   /etc/firmware/iwx-Qu-c0-hr-b0-63

Such devices show up with 'Product ID: 0x34f0' in pcidump(8).
I do not have such hardware. Can someone help out?

ok?

diff 2611d0ab4f1e42a3f2c5db88a7a8cf0f1d94ef39 
e2fce28332a64af2eb947d764f33d3255719ec95
blob - 2cb39f6f37c89487e80cae7c423309688622031f
blob + f317cea613e3fb89360340cf90c918dac986d863
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -301,9 +301,6 @@ int iwx_enable_txq(struct iwx_softc *, int, int, int, 
 void   iwx_post_alive(struct iwx_softc *);
 intiwx_schedule_session_protection(struct iwx_softc *, struct iwx_node *,
uint32_t);
-void   iwx_protect_session(struct iwx_softc *, struct iwx_node *, uint32_t,
-   uint32_t);
-void   iwx_unprotect_session(struct iwx_softc *, struct iwx_node *);
 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 *);
@@ -366,8 +363,6 @@ int iwx_phy_ctxt_cmd_uhb_v3(struct iwx_softc *, struct
uint8_t, uint32_t);
 intiwx_phy_ctxt_cmd_v3(struct iwx_softc *, struct iwx_phy_ctxt *, uint8_t,
uint8_t, uint32_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 *);
@@ -397,12 +392,10 @@ int   iwx_power_update_device(struct iwx_softc *);
 intiwx_enable_beacon_filter(struct iwx_softc *, struct iwx_node *);
 intiwx_disable_beacon_filter(struct iwx_softc *);
 intiwx_add_sta_cmd(struct iwx_softc *, struct iwx_node *, int);
-intiwx_add_aux_sta(struct iwx_softc *);
 intiwx_rm_sta_cmd(struct iwx_softc *, struct iwx_node *);
 intiwx_rm_sta(struct iwx_softc *, struct iwx_node *);
 intiwx_fill_probe_req(struct iwx_softc *, struct iwx_scan_probe_req *);
 intiwx_config_umac_scan_reduced(struct iwx_softc *);
-intiwx_config_umac_scan(struct iwx_softc *);
 uint16_t iwx_scan_umac_flags_v2(struct iwx_softc *, int);
 void   iwx_scan_umac_dwell_v10(struct iwx_softc *,
struct iwx_scan_general_params_v10 *, int);
@@ -411,7 +404,6 @@ voidiwx_scan_umac_fill_general_p_v10(struct 
iwx_softc
 void   iwx_scan_umac_fill_ch_p_v6(struct iwx_softc *,
struct iwx_scan_channel_params_v6 *, uint32_t, int, int);
 intiwx_umac_scan_v14(struct iwx_softc *, int);
-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);
@@ -422,7 +414,6 @@ voidiwx_mac_ctxt_cmd_fill_sta(struct iwx_softc *, 
str
struct iwx_mac_data_sta *, int);
 intiwx_mac_ctxt_cmd(struct iwx_softc *, struct iwx_node *, uint32_t, int);
 intiwx_clear_statistics(struct iwx_softc *);
-intiwx_update_quotas(struct iwx_softc *, struct iwx_node *, int);
 void   iwx_add_task(struct iwx_softc *, struct taskq *, struct task *);
 void   iwx_del_task(struct iwx_softc *, struct taskq *, struct task *);
 intiwx_scan(struct iwx_softc *);
@@ -2670,64 +2661,6 @@ iwx_schedule_session_protection(struct iwx_softc *sc, 
return iwx_send_cmd_pdu(sc, cmd_id, 0, sizeof(cmd), );
 }
 
-void
-iwx_protect_session(struct iwx_softc *sc, struct iwx_node *in,
-uint32_t duration, uint32_t max_delay)
-{
-   struct iwx_time_event_cmd time_cmd;
-
-   /* Do nothing if a time event is already scheduled. */
-   if (sc->sc_flags & IWX_FLAG_TE_ACTIVE)
-   return;
-
-   memset(_cmd, 0, sizeof(time_cmd));
-
-   time_cmd.action = htole32(IWX_FW_CTXT_ACTION_ADD);
-   time_cmd.id_and_color =
-   htole32(IWX_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color));
-   time_cmd.id = htole32(IWX_TE_BSS_STA_AGGRESSIVE_ASSOC);
-
-   time_cmd.apply_time = htole32(0);
-
-   time_cmd.max_frags = IWX_TE_V2_FRAG_NONE;
-   time_cmd.max_delay = htole32(max_delay);
-   /* TODO: why do we need to interval = bi if it is not periodic? */
-   time_cmd.interval = htole32(1);
-   time_cmd.duration = htole32(duration);
-   time_cmd.repeat = 1;
-   time_cmd.policy
-   = htole16(IWX_TE_V2_NOTIF_HOST_EVENT_START |
-   IWX_TE_V2_NOTIF_HOST_EVENT_END |
-   

iwx: stop Rx BA sessions before switching AP

2021-10-08 Thread Stefan Sperling
Before roaming to another AP we should explicitly stop Rx BA sessions
by sending the appropriate 'ADD_STA' commands to firmware, in addition
to clearing Rx BA buffers. This is similar to a recent change in iwm(4).
See the iwm patch description for testing instructions:
https://marc.info/?l=openbsd-tech=163329420019842=2

It seems there is no need to stop Tx BA sessions in this driver.
Note that Tx aggregation sessions are handled entirely in firmware on
iwx(4) devices, which is substantially different from iwm(4).
I have already tried sending commands to disable Tx aggregation queues,
like iwm(4) will do now. This causes fatal firmware errors on iwx.
And everything seems to be working fine with Tx queues left enabled.

While here, remove a pointless STA_ACTIVE check; if we are in RUN state
then our firmware station (which represents the AP) is active by definition.

ok?

diff 58be466d62dc3469b7024e02971f96cadae4041e 
2611d0ab4f1e42a3f2c5db88a7a8cf0f1d94ef39
blob - 55d0375ff3f9ff3ec8c1c37fc03de2eb4f9e5bff
blob + 2cb39f6f37c89487e80cae7c423309688622031f
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -7531,19 +7531,34 @@ iwx_run_stop(struct iwx_softc *sc)
 {
struct ieee80211com *ic = >sc_ic;
struct iwx_node *in = (void *)ic->ic_bss;
-   int err;
+   struct ieee80211_node *ni = >in_ni;
+   int err, i;
 
splassert(IPL_NET);
 
-   if (sc->sc_flags & IWX_FLAG_STA_ACTIVE) {
-   err = iwx_flush_sta(sc, in);
-   if (err) {
-   printf("%s: could not flush Tx path (error %d)\n",
-   DEVNAME(sc), err);
-   return err;
-   }
+   err = iwx_flush_sta(sc, in);
+   if (err) {
+   printf("%s: could not flush Tx path (error %d)\n",
+   DEVNAME(sc), err);
+   return err;
}
 
+   /*
+* Stop Rx BA sessions now. We cannot rely on the BA task
+* for this when moving out of RUN state since it runs in a
+* separate thread.
+* Note that in->in_ni (struct ieee80211_node) already represents
+* our new access point in case we are roaming between APs.
+* This means we cannot rely on struct ieee802111_node to tell
+* us which BA sessions exist.
+*/
+   for (i = 0; i < nitems(sc->sc_rxba_data); i++) {
+   struct iwx_rxba_data *rxba = >sc_rxba_data[i];
+   if (rxba->baid == IWX_RX_REORDER_DATA_INVALID_BAID)
+   continue;
+   iwx_sta_rx_agg(sc, ni, rxba->tid, 0, 0, 0, 0);
+   }
+
err = iwx_sf_config(sc, IWX_SF_INIT_OFF);
if (err)
return err;
@@ -7869,7 +7884,6 @@ iwx_newstate(struct ieee80211com *ic, enum ieee80211_s
 {
struct ifnet *ifp = IC2IFP(ic);
struct iwx_softc *sc = ifp->if_softc;
-   int i;
 
/*
 * Prevent attemps to transition towards the same state, unless
@@ -7887,10 +7901,6 @@ iwx_newstate(struct ieee80211com *ic, enum ieee80211_s
memset(sc->setkey_arg, 0, sizeof(sc->setkey_arg));
sc->setkey_cur = sc->setkey_tail = sc->setkey_nkeys = 0;
iwx_del_task(sc, systq, >mac_ctxt_task);
-   for (i = 0; i < nitems(sc->sc_rxba_data); i++) {
-   struct iwx_rxba_data *rxba = >sc_rxba_data[i];
-   iwx_clear_reorder_buffer(sc, rxba);
-   }
}
 
sc->ns_nstate = nstate;



iwm: initial 40Mhz channel support

2021-10-07 Thread Stefan Sperling
This patch adds initial support for 40Mhz channels to the iwm driver.

There are a few changes in net80211 to support this feature in RA and
when parsing beacons. The work for net80211 is not yet complete but
more can be done incrementally later. What is missing in particular
is integration with ifconfig to display the use of a 40 MHz channel.

And there is no way to force 40 MHz off at the client side yet.
If the AP announces support for 40MHz we will always use it. Whether or
not we'll need an override to handle some edge case remains to be seen.

Please test this on any supported iwm(4) device. Thanks!

diff 4056ab6b22f0b2cb4f14b2b237355717bf154e4f refs/heads/40mhz
blob - fbf2059a1571c2c55b40fce5ffd7d145ab6b1f21
blob + 3bf02ee0969978149c20498a469c1a2dcf4d7177
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -1150,7 +1150,7 @@ ar5008_tx_process(struct athn_softc *sc, int qid)
/* Update rate control statistics. */
if ((ni->ni_flags & IEEE80211_NODE_HT) && ic->ic_fixed_mcs == -1) {
const struct ieee80211_ht_rateset *rs =
-   ieee80211_ra_get_ht_rateset(bf->bf_txmcs,
+   ieee80211_ra_get_ht_rateset(bf->bf_txmcs, 0 /* chan40 */,
ieee80211_node_supports_ht_sgi20(ni));
unsigned int retries = 0, i;
int mcs = bf->bf_txmcs;
blob - 6a145720d3070bd0c1eabae1bedddb5da8fb72a2
blob + 687cbf94f135f6586193b1724e52b80e7f16a529
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -335,9 +335,11 @@ void   iwm_init_channel_map(struct iwm_softc *, const 
ui
 intiwm_mimo_enabled(struct iwm_softc *);
 void   iwm_setup_ht_rates(struct iwm_softc *);
 void   iwm_mac_ctxt_task(void *);
+void   iwm_phy_ctxt_task(void *);
 void   iwm_updateprot(struct ieee80211com *);
 void   iwm_updateslot(struct ieee80211com *);
 void   iwm_updateedca(struct ieee80211com *);
+void   iwm_updatechan(struct ieee80211com *);
 void   iwm_init_reorder_buffer(struct iwm_reorder_buffer *, uint16_t,
uint16_t);
 void   iwm_clear_reorder_buffer(struct iwm_softc *, struct iwm_rxba_data *);
@@ -408,13 +410,13 @@ void  iwm_rx_bmiss(struct iwm_softc *, struct 
iwm_rx_pa
struct iwm_rx_data *);
 intiwm_binding_cmd(struct iwm_softc *, struct iwm_node *, uint32_t);
 intiwm_phy_ctxt_cmd_uhb(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t);
+   uint8_t, uint32_t, uint32_t, uint8_t);
 void   iwm_phy_ctxt_cmd_hdr(struct iwm_softc *, struct iwm_phy_ctxt *,
struct iwm_phy_context_cmd *, uint32_t, uint32_t);
 void   iwm_phy_ctxt_cmd_data(struct iwm_softc *, struct iwm_phy_context_cmd *,
-   struct ieee80211_channel *, uint8_t, uint8_t);
+   struct ieee80211_channel *, uint8_t, uint8_t, uint8_t);
 intiwm_phy_ctxt_cmd(struct iwm_softc *, struct iwm_phy_ctxt *, uint8_t,
-   uint8_t, uint32_t, uint32_t);
+   uint8_t, uint32_t, uint32_t, uint8_t);
 intiwm_send_cmd(struct iwm_softc *, struct iwm_host_cmd *);
 intiwm_send_cmd_pdu(struct iwm_softc *, uint32_t, uint32_t, uint16_t,
const void *);
@@ -479,7 +481,7 @@ int iwm_umac_scan_abort(struct iwm_softc *);
 intiwm_lmac_scan_abort(struct iwm_softc *);
 intiwm_scan_abort(struct iwm_softc *);
 intiwm_phy_ctxt_update(struct iwm_softc *, struct iwm_phy_ctxt *,
-   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t);
+   struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t);
 intiwm_auth(struct iwm_softc *);
 intiwm_deauth(struct iwm_softc *);
 intiwm_run(struct iwm_softc *);
@@ -3075,8 +3077,11 @@ iwm_init_channel_map(struct iwm_softc *sc, const uint1
if (!(ch_flags & IWM_NVM_CHANNEL_ACTIVE))
channel->ic_flags |= IEEE80211_CHAN_PASSIVE;
 
-   if (data->sku_cap_11n_enable)
+   if (data->sku_cap_11n_enable) {
channel->ic_flags |= IEEE80211_CHAN_HT;
+   if (ch_flags & IWM_NVM_CHANNEL_40MHZ)
+   channel->ic_flags |= IEEE80211_CHAN_40MHZ;
+   }
}
 }
 
@@ -3409,6 +3414,51 @@ iwm_updateedca(struct ieee80211com *ic)
iwm_add_task(sc, systq, >mac_ctxt_task);
 }
 
+void
+iwm_phy_ctxt_task(void *arg)
+{
+   struct iwm_softc *sc = arg;
+   struct ieee80211com *ic = >sc_ic;
+   struct iwm_node *in = (void *)ic->ic_bss;
+   struct ieee80211_node *ni = >in_ni;
+   uint8_t chains, sco;
+   int err, s = splnet();
+
+   if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) ||
+   ic->ic_state != IEEE80211_S_RUN ||
+   in->in_phyctxt == NULL) {
+   refcnt_rele_wake(>task_refs);
+   splx(s);
+   return;
+   }
+
+   chains = iwm_mimo_enabled(sc) ? 2 : 1;
+   if (ieee80211_node_supports_ht_chan40(ni))
+   sco = (ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK);
+   else
+   

Re: iwm: set assoc ID in ADD_STA command

2021-10-06 Thread Stefan Sperling
On Tue, Oct 05, 2021 at 02:19:57PM +0200, Stefan Sperling wrote:
> While debugging iwm roaming issues which are now fixed in -current,
> I noticed a small difference between our driver and the Linux driver:
> 
> Set the assoc ID assigned by our AP when updating the firmware station
> with the ADD_STA command. Not sure if this strictly required but it
> doesn't seem to hurt. This assoc ID is also present in the MAC context
> data structure so presumably firmware might use this ID for something.
> 
> This needs to be done in the update case only because we don't know
> our ID yet when the station is first added to firmware. The station
> gets added before the association frame exchange begins.
> 
> Already tested by florian, bket, and myself as part of a larger diff.
> 
> ok?
>  
> diff 3995979b713a9ebcdddbee86864fdb4f14ca7112 
> 3f75e2890abe65d5050904183ad6752454ca8f3b
> blob - 35c4b352f905c1e493d64ccd360e022a77111e1e
> blob + 74545e96d1f0c4c07c3d3cb6fe58c0277628fbeb
> --- sys/dev/pci/if_iwm.c
> +++ sys/dev/pci/if_iwm.c
> @@ -6926,6 +6926,7 @@ iwm_add_sta_cmd(struct iwm_softc *sc, struct iwm_node 
>   if (update) {
>   add_sta_cmd.modify_mask |= (IWM_STA_MODIFY_QUEUES |
>   IWM_STA_MODIFY_TID_DISABLE_TX);
> + add_sta_cmd.assoc_id = htole32(in->in_ni.ni_associd);
>   }
>   add_sta_cmd.tid_disable_tx = htole16(in->tid_disable_ampdu);
>   add_sta_cmd.tfd_queue_msk = htole32(in->tfd_queue_msk);

Thinking about this some more, this change is probably only needed
for hostap mode. So I won't commit it, because a lot of additional
changes would be required to support hostap mode anyway.



iwm/iwx: unbreak band-steering

2021-10-05 Thread Stefan Sperling
AUTH -> AUTH state transitions happen if the access point uses band-steering.
This was originally implemented to fix interop with some Aruba APs.

A recent commit I made to iwm/iwx drivers probably broke this.
Here is a fix.

ok?

diff b1c80baf1b7d4bf6f528498fe67f3d1db4353371 /usr/src
blob - 8bf1224f792b4b4f1e1214660de9a211e3788d74
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -8945,9 +8945,11 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_s
/*
 * Prevent attemps to transition towards the same state, unless
 * we are scanning in which case a SCAN -> SCAN transition
-* triggers another scan iteration.
+* triggers another scan iteration. And AUTH -> AUTH is needed
+* to support band-steering.
 */
-   if (sc->ns_nstate == nstate && nstate != IEEE80211_S_SCAN)
+   if (sc->ns_nstate == nstate && nstate != IEEE80211_S_SCAN &&
+   nstate != IEEE80211_S_AUTH)
return 0;
 
if (ic->ic_state == IEEE80211_S_RUN) {
blob - 692f12524d78cde1117f4a660cc30cadf297e4af
file + sys/dev/pci/if_iwx.c
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -7874,9 +7874,11 @@ iwx_newstate(struct ieee80211com *ic, enum ieee80211_s
/*
 * Prevent attemps to transition towards the same state, unless
 * we are scanning in which case a SCAN -> SCAN transition
-* triggers another scan iteration.
+* triggers another scan iteration. And AUTH -> AUTH is needed
+* to support band-steering.
 */
-   if (sc->ns_nstate == nstate && nstate != IEEE80211_S_SCAN)
+   if (sc->ns_nstate == nstate && nstate != IEEE80211_S_SCAN &&
+   nstate != IEEE80211_S_AUTH)
return 0;
 
if (ic->ic_state == IEEE80211_S_RUN) {



iwm: make old BSSID available to iwm_newstate when roaming

2021-10-05 Thread Stefan Sperling
When roaming between APs, all data in struct net80211_node is replaced
as soon as we have decided to switch to a different AP.

This means that the BSSID of our old AP is no longer stored in ic_bss
once we enter iwm_newstate(). We do however use this address in firmware
commands while tearing things down, in order to prepare firmware for the
switch.

With this patch, firmware commands keep using the old BSSID while tearing
things down. We switch to the new address once we start back up in iwm_auth().

This should keep things consistent from the firmware's point of view.
(ic_bss->ni_chan is also affected. This will be fixed in a later patch
by using the channel stored in the phy context instead of ni_chan.)

Tested by florian, bket, and myself as part of a larger diff.

ok?
 
diff 10fe65f52d60daceea3a3690e6cc566759c1ab54 
fbffc95c6dfab20098670aa21c2318a2eb3c9be7
blob - 64163c3776e9d3483e1e96c09efd40535626c10f
blob + 3c088a34148b5b8a7a41fd88d133005b9b98bc89
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -5718,9 +5718,9 @@ iwm_rx_compressed_ba(struct iwm_softc *sc, struct iwm_
 {
struct iwm_ba_notif *ban = (void *)pkt->data;
struct ieee80211com *ic = >sc_ic;
-   struct ieee80211_node *ni;
+   struct ieee80211_node *ni = ic->ic_bss;
+   struct iwm_node *in = (void *)ni;
struct ieee80211_tx_ba *ba;
-   struct iwm_node *in;
struct iwm_tx_ring *ring;
uint16_t seq, ssn;
int qid;
@@ -5732,12 +5732,9 @@ iwm_rx_compressed_ba(struct iwm_softc *sc, struct iwm_
return;
 
if (ban->sta_id != IWM_STATION_ID ||
-   !IEEE80211_ADDR_EQ(ic->ic_bss->ni_macaddr, ban->sta_addr))
+   !IEEE80211_ADDR_EQ(in->in_macaddr, ban->sta_addr))
return;
 
-   ni = ic->ic_bss;
-   in = (void *)ni;
-
qid = le16toh(ban->scd_flow);
if (qid < IWM_FIRST_AGG_TX_QUEUE || qid > IWM_LAST_AGG_TX_QUEUE)
return;
@@ -6919,7 +6916,7 @@ iwm_add_sta_cmd(struct iwm_softc *sc, struct iwm_node 
etherbroadcastaddr);
else
IEEE80211_ADDR_COPY(_sta_cmd.addr,
-   in->in_ni.ni_bssid);
+   in->in_macaddr);
}
add_sta_cmd.add_modify = update ? 1 : 0;
add_sta_cmd.station_flags_msk
@@ -7900,7 +7897,7 @@ iwm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct i
return;
}
 
-   IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
+   IEEE80211_ADDR_COPY(cmd->bssid_addr, in->in_macaddr);
iwm_ack_rates(sc, in, _ack_rates, _ack_rates);
cmd->cck_rates = htole32(cck_ack_rates);
cmd->ofdm_rates = htole32(ofdm_ack_rates);
@@ -8302,6 +8299,7 @@ iwm_auth(struct iwm_softc *sc)
return err;
}
in->in_phyctxt = >sc_phyctxt[0];
+   IEEE80211_ADDR_COPY(in->in_macaddr, in->in_ni.ni_macaddr); 
 
err = iwm_mac_ctxt_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD, 0);
if (err) {
@@ -9749,7 +9747,7 @@ int
 iwm_allow_mcast(struct iwm_softc *sc)
 {
struct ieee80211com *ic = >sc_ic;
-   struct ieee80211_node *ni = ic->ic_bss;
+   struct iwm_node *in = (void *)ic->ic_bss;
struct iwm_mcast_filter_cmd *cmd;
size_t size;
int err;
@@ -9762,7 +9760,7 @@ iwm_allow_mcast(struct iwm_softc *sc)
cmd->port_id = 0;
cmd->count = 0;
cmd->pass_all = 1;
-   IEEE80211_ADDR_COPY(cmd->bssid, ni->ni_bssid);
+   IEEE80211_ADDR_COPY(cmd->bssid, in->in_macaddr);
 
err = iwm_send_cmd_pdu(sc, IWM_MCAST_FILTER_CMD,
0, size, cmd);
@@ -9931,6 +9929,7 @@ iwm_stop(struct ifnet *ifp)
in->in_phyctxt = NULL;
in->tid_disable_ampdu = 0x;
in->tfd_queue_msk = 0;
+   IEEE80211_ADDR_COPY(in->in_macaddr, etheranyaddr);
 
sc->sc_flags &= ~(IWM_FLAG_SCANNING | IWM_FLAG_BGSCAN);
sc->sc_flags &= ~IWM_FLAG_MAC_ACTIVE;
blob - bcda8e9014625199c027cda244c649d0122f7560
blob + b43453c29a46742cad00be9e54c8a45f3ad6acb2
--- sys/dev/pci/if_iwmvar.h
+++ sys/dev/pci/if_iwmvar.h
@@ -654,6 +654,7 @@ struct iwm_softc {
 struct iwm_node {
struct ieee80211_node in_ni;
struct iwm_phy_ctxt *in_phyctxt;
+   uint8_t in_macaddr[ETHER_ADDR_LEN];
 
uint16_t in_id;
uint16_t in_color;



net80211: send probe req to new AP when roaming

2021-10-05 Thread Stefan Sperling
Send a probe request to our new AP when we are about to roam to it.
When the code modified below runs, we have just replaced ic_bss (ni)
with our new AP a few lines above.

Sending a probe request isn't strictly required but it might help to
initialize state in our AP in case our background scan was passive
(i.e. no probe requests were sent during the background scan).
Note that firmware might decide internally whether a given channel is
passive or not, without giving drivers control over this decision.

It might also help to initialize firmware state on the client side in case
firmware evaluates the probe response (beacon) which the AP should return.
This is known to happen in iwn/iwm/iwx firmware, at least.

ok?
 
diff 6ef004ad7244ea6e24d0c8fe19cc784f7a7c99d6 
10fe65f52d60daceea3a3690e6cc566759c1ab54
blob - 213ef3fc1c96f1aa330597972dab6783ad08399a
blob + 1434b7bf27cc81ed2bd1b2343480c9ec16fdfac1
--- sys/net80211/ieee80211_node.c
+++ sys/net80211/ieee80211_node.c
@@ -1272,8 +1272,11 @@ ieee80211_node_join_bss(struct ieee80211com *ic, struc
 * ieee80211_new_state() try to re-auth and thus send
 * an AUTH frame to our newly selected AP.
 */
-   if (bgscan)
+   if (bgscan) {
+   IEEE80211_SEND_MGMT(ic, ni,
+   IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
mgt = IEEE80211_FC0_SUBTYPE_DEAUTH;
+   }
/*
 * If we are trying another AP after the previous one
 * failed (state transition AUTH->AUTH), ensure that



iwm: fixed Tx rate tweak

2021-10-05 Thread Stefan Sperling
Make sure to use HT for data frames only in case our Tx rate is fixed.
Non-data frames are not supposed to use HT.

This change applies if the Tx rate has been fixed for testing purposes
with a command such as 'ifconfig iwm0 media HT-MCS13 mode 11n'.

I've only found this by code inspection, not because there was some
problem at run-time. But better play it safe.

ok?
 
diff 3f75e2890abe65d5050904183ad6752454ca8f3b 
6ef004ad7244ea6e24d0c8fe19cc784f7a7c99d6
blob - 74545e96d1f0c4c07c3d3cb6fe58c0277628fbeb
blob + 64163c3776e9d3483e1e96c09efd40535626c10f
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -6354,6 +6354,7 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node 
if (IWM_RIDX_IS_CCK(ridx))
rate_flags |= IWM_RATE_MCS_CCK_MSK;
if ((ni->ni_flags & IEEE80211_NODE_HT) &&
+   type == IEEE80211_FC0_TYPE_DATA &&
rinfo->ht_plcp != IWM_RATE_HT_SISO_MCS_INV_PLCP) {
rate_flags |= IWM_RATE_MCS_HT_MSK; 
if (ieee80211_node_supports_ht_sgi20(ni))




iwm: set assoc ID in ADD_STA command

2021-10-05 Thread Stefan Sperling
While debugging iwm roaming issues which are now fixed in -current,
I noticed a small difference between our driver and the Linux driver:

Set the assoc ID assigned by our AP when updating the firmware station
with the ADD_STA command. Not sure if this strictly required but it
doesn't seem to hurt. This assoc ID is also present in the MAC context
data structure so presumably firmware might use this ID for something.

This needs to be done in the update case only because we don't know
our ID yet when the station is first added to firmware. The station
gets added before the association frame exchange begins.

Already tested by florian, bket, and myself as part of a larger diff.

ok?
 
diff 3995979b713a9ebcdddbee86864fdb4f14ca7112 
3f75e2890abe65d5050904183ad6752454ca8f3b
blob - 35c4b352f905c1e493d64ccd360e022a77111e1e
blob + 74545e96d1f0c4c07c3d3cb6fe58c0277628fbeb
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -6926,6 +6926,7 @@ iwm_add_sta_cmd(struct iwm_softc *sc, struct iwm_node 
if (update) {
add_sta_cmd.modify_mask |= (IWM_STA_MODIFY_QUEUES |
IWM_STA_MODIFY_TID_DISABLE_TX);
+   add_sta_cmd.assoc_id = htole32(in->in_ni.ni_associd);
}
add_sta_cmd.tid_disable_tx = htole16(in->tid_disable_ampdu);
add_sta_cmd.tfd_queue_msk = htole32(in->tfd_queue_msk);



Re: iwm 11n mode roaming fix needs testing

2021-10-04 Thread Stefan Sperling
On Mon, Oct 04, 2021 at 10:45:06AM +0200, Florian Obser wrote:
> 
> This works as advertised on:
> 
> iwm0 at pci1 dev 0 function 0 "Intel Dual Band Wireless-AC 9260" rev 0x29, 
> msix
> iwm0: hw rev 0x320, fw ver 46.6b541b68.0, address 40:74:e0:38:11:11
> 
> and
> 
> iwm0 at pci2 dev 0 function 0 "Intel AC 7260" rev 0x83, msi
> iwm0: hw rev 0x140, fw ver 17.3216344376.0, address 5c:c5:d4:63:b3:d9

> raw data:

Thank you! It is great to see that the same issue reproduces on these
devices as well, exactly as I saw it, and that the fix works.



Re: Alternate cpu policy on battery

2021-10-03 Thread Stefan Sperling
On Sat, Sep 25, 2021 at 08:26:06PM +0200, Solene Rapenne wrote:
> +void
> +setperf_powersaving(void *v)
> +{
> + static uint64_t *idleticks, *totalticks;

[...]

> +
> + if (!idleticks)
> + if (!(idleticks = mallocarray(ncpusfound, sizeof(*idleticks),
> + M_DEVBUF, M_NOWAIT | M_ZERO)))
> + return;
> + if (!totalticks)
> + if (!(totalticks = mallocarray(ncpusfound, sizeof(*totalticks),
> + M_DEVBUF, M_NOWAIT | M_ZERO))) {
> + free(idleticks, M_DEVBUF,
> + sizeof(*idleticks) * ncpusfound);
> + return;
> + }

This is unrelated to your patch.
I noticed something that looks wrong in code your patch was based on.

Should setperf_auto() not reset idleticks to NULL after freeing idleticks
in the error path of the totalticks allocation?

Otherwise, if we come back into this function a second time, the static(!)
variable idleticks will still point at freed memory and won't be reallocated
since !idleticks is now false.

A very unlikely edge case. Still worth fixing?

diff ba3fb53d3e94158190d84a1771da21f620e46e26 /usr/src
blob - 956ea24ea07fa9a7301f2e7156698e4e090e9cfb
file + sys/kern/sched_bsd.c
--- sys/kern/sched_bsd.c
+++ sys/kern/sched_bsd.c
@@ -565,10 +565,11 @@ setperf_auto(void *v)
if (!totalticks)
if (!(totalticks = mallocarray(ncpusfound, sizeof(*totalticks),
M_DEVBUF, M_NOWAIT | M_ZERO))) {
free(idleticks, M_DEVBUF,
sizeof(*idleticks) * ncpusfound);
+   idleticks = NULL;
return;
}
 
alltotal = allidle = 0;
j = 0;



  1   2   3   4   5   6   7   8   9   10   >