diff --git a/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwx.c b/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwx.c index 007424c6c8..79f85c5875 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwx.c +++ b/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwx.c,v 1.189 2025/02/04 09:15:04 stsp Exp $ */ +/* $OpenBSD: if_iwx.c,v 1.198 2026/02/17 20:02:43 kettenis Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh @@ -491,6 +491,7 @@ int iwx_send_temp_report_ths_cmd(struct iwx_softc *); int iwx_init_hw(struct iwx_softc *); int iwx_init(struct ifnet *); void iwx_start(struct ifnet *); +void iwx_mfp_leave(struct iwx_softc *); void iwx_stop(struct ifnet *); void iwx_watchdog(struct ifnet *); int iwx_ioctl(struct ifnet *, u_long, caddr_t); @@ -1670,13 +1671,6 @@ iwx_write_prph(struct iwx_softc *sc, uint32_t addr, uint32_t val) iwx_write_prph_unlocked(sc, addr, val); } -void -iwx_write_prph64(struct iwx_softc *sc, uint64_t addr, uint64_t val) -{ - iwx_write_prph(sc, (uint32_t)addr, val & 0xffffffff); - iwx_write_prph(sc, (uint32_t)addr + 4, val >> 32); -} - uint32_t iwx_read_umac_prph_unlocked(struct iwx_softc *sc, uint32_t addr) { @@ -1842,13 +1836,13 @@ iwx_dma_contig_alloc(bus_dma_tag_t tag, struct iwx_dma_info *dma, dma->tag = tag; dma->size = size; - err = bus_dmamap_create(tag, size, 1, size, 0, BUS_DMA_NOWAIT, - &dma->map); + err = bus_dmamap_create(tag, size, 1, size, 0, + BUS_DMA_NOWAIT | BUS_DMA_64BIT, &dma->map); if (err) goto fail; err = bus_dmamem_alloc(tag, size, alignment, 0, &dma->seg, 1, &nsegs, - BUS_DMA_NOWAIT | BUS_DMA_ZERO); + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_64BIT); if (err) goto fail; @@ -1946,7 +1940,8 @@ iwx_alloc_rx_ring(struct iwx_softc *sc, struct iwx_rx_ring *ring) memset(data, 0, sizeof(*data)); err = bus_dmamap_create(sc->sc_dmat, IWX_RBUF_SIZE, 1, - IWX_RBUF_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, + IWX_RBUF_SIZE, 0, + BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, &data->map); if (err) { printf("%s: could not create RX buf DMA map\n", @@ -2112,8 +2107,8 @@ iwx_alloc_tx_ring(struct iwx_softc *sc, struct iwx_tx_ring *ring, int qid) else mapsize = MCLBYTES; err = bus_dmamap_create(sc->sc_dmat, mapsize, - IWX_TFH_NUM_TBS - 2, mapsize, 0, BUS_DMA_NOWAIT, - &data->map); + IWX_TFH_NUM_TBS - 2, mapsize, 0, + BUS_DMA_NOWAIT | BUS_DMA_64BIT, &data->map); if (err) { printf("%s: could not create TX buf DMA map\n", DEVNAME(sc)); @@ -6332,6 +6327,19 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ieee80211_node *ni) if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_get_txkey(ic, wh, ni); + + /* + * Firmware uses IGTK for Rx only while in station mode. + * And because we do not have the IGTK installed for software + * crypto calling into ieee80211_encrypt() with this key would + * result in a kernel panic. Transmitting multicast management + * frames is only useful in hostap mode which we do not support. + */ + if (k->k_flags & IEEE80211_KEY_IGTK) { + m_freem(m); + return ENOTSUP; + } + if (k->k_cipher != IEEE80211_CIPHER_CCMP) { if ((m = ieee80211_encrypt(ic, m, k)) == NULL) return ENOBUFS; @@ -6421,14 +6429,16 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ieee80211_node *ni) desc->tbs[0].tb_len = htole16(IWX_FIRST_TB_SIZE); paddr = htole64(data->cmd_paddr); memcpy(&desc->tbs[0].addr, &paddr, sizeof(paddr)); - if (data->cmd_paddr >> 32 != (data->cmd_paddr + le32toh(desc->tbs[0].tb_len)) >> 32) + if ((uint64_t)data->cmd_paddr >> 32 != ((uint64_t)data->cmd_paddr + + le32toh(desc->tbs[0].tb_len)) >> 32) DPRINTF(("%s: TB0 crosses 32bit boundary\n", __func__)); desc->tbs[1].tb_len = htole16(sizeof(struct iwx_cmd_header) + txcmd_size + hdrlen + pad - IWX_FIRST_TB_SIZE); paddr = htole64(data->cmd_paddr + IWX_FIRST_TB_SIZE); memcpy(&desc->tbs[1].addr, &paddr, sizeof(paddr)); - if (data->cmd_paddr >> 32 != (data->cmd_paddr + le32toh(desc->tbs[1].tb_len)) >> 32) + if ((uint64_t)data->cmd_paddr >> 32 != ((uint64_t)data->cmd_paddr + + le32toh(desc->tbs[1].tb_len)) >> 32) DPRINTF(("%s: TB1 crosses 32bit boundary\n", __func__)); /* Other DMA segments are for data payload. */ @@ -6437,7 +6447,9 @@ iwx_tx(struct iwx_softc *sc, struct mbuf *m, struct ieee80211_node *ni) desc->tbs[i + 2].tb_len = htole16(seg->ds_len); paddr = htole64(seg->ds_addr); memcpy(&desc->tbs[i + 2].addr, &paddr, sizeof(paddr)); - if (data->cmd_paddr >> 32 != (data->cmd_paddr + le32toh(desc->tbs[i + 2].tb_len)) >> 32) + if ((uint64_t)data->cmd_paddr >> 32 != + ((uint64_t)data->cmd_paddr + + le32toh(desc->tbs[i + 2].tb_len)) >> 32) DPRINTF(("%s: TB%d crosses 32bit boundary\n", __func__, i + 2)); } @@ -6934,8 +6946,8 @@ iwx_mld_add_sta_cmd(struct iwx_softc *sc, struct iwx_node *in, int update) struct ieee80211com *ic = &sc->sc_ic; struct iwx_link_config_cmd link_cmd; struct iwx_mvm_sta_cfg_cmd sta_cmd; - uint32_t aggsize; - const uint32_t max_aggsize = (IWX_STA_FLG_MAX_AGG_SIZE_64K >> + uint32_t aggsize, mpdu_dens; + const uint32_t max_aggsize = (IWX_STA_FLG_MAX_AGG_SIZE_4M >> IWX_STA_FLG_MAX_AGG_SIZE_SHIFT); int err, changes; @@ -6986,12 +6998,15 @@ iwx_mld_add_sta_cmd(struct iwx_softc *sc, struct iwx_node *in, int update) sta_cmd.link_id = htole32(0); IEEE80211_ADDR_COPY(sta_cmd.peer_mld_address, in->in_macaddr); IEEE80211_ADDR_COPY(sta_cmd.peer_link_address, in->in_macaddr); - sta_cmd.assoc_id = htole32(in->in_ni.ni_associd); + sta_cmd.assoc_id = htole32(IEEE80211_AID(in->in_ni.ni_associd)); if (in->in_ni.ni_flags & IEEE80211_NODE_HT) { if (iwx_mimo_enabled(sc)) sta_cmd.mimo = htole32(1); + mpdu_dens = (in->in_ni.ni_ampdu_param & + IEEE80211_AMPDU_PARAM_SS) >> 2; + if (in->in_ni.ni_flags & IEEE80211_NODE_VHT) { aggsize = (in->in_ni.ni_vhtcaps & IEEE80211_VHTCAP_MAX_AMPDU_LEN_MASK) >> @@ -7003,10 +7018,13 @@ iwx_mld_add_sta_cmd(struct iwx_softc *sc, struct iwx_node *in, int update) if (aggsize > max_aggsize) aggsize = max_aggsize; - sta_cmd.tx_ampdu_spacing = htole32(0); - sta_cmd.tx_ampdu_max_size = aggsize; + sta_cmd.tx_ampdu_spacing = htole32(mpdu_dens); + sta_cmd.tx_ampdu_max_size = htole32(aggsize); } + if (in->in_ni.ni_flags & IEEE80211_NODE_MFP) + sta_cmd.mfp = htole32(1); + return iwx_send_cmd_pdu(sc, IWX_WIDE_ID(IWX_MAC_CONF_GROUP, IWX_STA_CONFIG_CMD), 0, sizeof(sta_cmd), &sta_cmd); @@ -7733,7 +7751,7 @@ iwx_mac_ctxt_cmd_fill_sta(struct iwx_softc *sc, struct iwx_node *in, sta->dtim_interval = htole32(ni->ni_intval * ni->ni_dtimperiod); sta->data_policy = htole32(0); sta->listen_interval = htole32(10); - sta->assoc_id = htole32(ni->ni_associd); + sta->assoc_id = htole32(IEEE80211_AID(ni->ni_associd)); } int @@ -7805,7 +7823,8 @@ iwx_mld_mac_ctxt_cmd(struct iwx_softc *sc, struct iwx_node *in, else panic("unsupported operating mode %d", ic->ic_opmode); IEEE80211_ADDR_COPY(cmd.local_mld_addr, ic->ic_myaddr); - cmd.client.assoc_id = htole32(ni->ni_associd); + cmd.client.assoc_id = htole32(IEEE80211_AID(ni->ni_associd)); + cmd.client.is_assoc = assoc ? 1 : 0; cmd.filter_flags = htole32(IWX_MAC_CFG_FILTER_ACCEPT_GRP); if (ic->ic_opmode == IEEE80211_M_MONITOR) { @@ -7987,6 +8006,43 @@ iwx_bgscan_done_task(void *arg) sc->aggqid[tid] = 0; } + /* + * Remove installed crypto keys while we still have access to them. + * Once iwx_newstate() is entered ic_bss will already contain + * information about our next AP. + */ + if (ic->ic_flags & IEEE80211_F_RSNON) { + struct ieee80211_key *k; + + if (ic->ic_bss->ni_flags & IEEE80211_NODE_MFP) + iwx_mfp_leave(sc); + + if (in->in_flags & IWX_NODE_FLAG_HAVE_PAIRWISE_KEY) + (*ic->ic_delete_key)(ic, ni, &ni->ni_pairwise_key); + + if ((in->in_flags & IWX_NODE_FLAG_HAVE_GROUP_KEY) && + (ic->ic_def_txkey == 1 || ic->ic_def_txkey == 2)) { + k = &ic->ic_nw_keys[ic->ic_def_txkey]; + if ((k->k_flags & IEEE80211_KEY_GROUP) && + k->k_cipher == IEEE80211_CIPHER_CCMP) + (*ic->ic_delete_key)(ic, ni, k); + } + + if ((in->in_flags & IWX_NODE_FLAG_HAVE_INTEGRITY_GROUP_KEY) && + (ic->ic_igtk_kid == 4 || ic->ic_igtk_kid == 5)) { + + k = &ic->ic_nw_keys[ic->ic_igtk_kid]; + if (k->k_flags & IEEE80211_KEY_IGTK) + (*ic->ic_delete_key)(ic, ni, k); + } + + ni->ni_port_valid = 0; + ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT; + ni->ni_flags &= ~IEEE80211_NODE_TXMGMTPROT; + ni->ni_flags &= ~IEEE80211_NODE_RXMGMTPROT; + ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; + } + /* * Tx queues have been flushed and Tx agg has been stopped. * Allow roaming to proceed. @@ -7995,7 +8051,11 @@ iwx_bgscan_done_task(void *arg) ni->ni_unref_arg_size = sc->bgscan_unref_arg_size; sc->bgscan_unref_arg = NULL; sc->bgscan_unref_arg_size = 0; - ieee80211_node_tx_stopped(ic, &in->in_ni); + if (ni->ni_flags & IEEE80211_NODE_MFP) { + /* Deauth frame already sent. */ + ieee80211_node_switch_bss(ic, &in->in_ni); + } else + ieee80211_node_tx_stopped(ic, &in->in_ni); done: if (err) { free(sc->bgscan_unref_arg, M_DEVBUF, sc->bgscan_unref_arg_size); @@ -8787,7 +8847,8 @@ iwx_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, struct iwx_setkey_task_arg *a; int err; - if (k->k_cipher != IEEE80211_CIPHER_CCMP) { + if (k->k_cipher != IEEE80211_CIPHER_CCMP && + (k->k_flags & IEEE80211_KEY_IGTK) == 0) { /* Fallback to software crypto for other ciphers. */ err = ieee80211_set_key(ic, ni, k); if (!err && in != NULL && (k->k_flags & IEEE80211_KEY_GROUP)) @@ -8809,8 +8870,9 @@ iwx_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, } int -iwx_mld_add_sta_key_cmd(struct iwx_softc *sc, int sta_id, - struct ieee80211_node *ni, struct ieee80211_key *k) +iwx_mld_set_sta_key_cmd(struct iwx_softc *sc, int sta_id, + struct ieee80211_node *ni, struct ieee80211_key *k, + int remove_key) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_sec_key_cmd cmd; @@ -8819,6 +8881,10 @@ iwx_mld_add_sta_key_cmd(struct iwx_softc *sc, int sta_id, if (k->k_flags & IEEE80211_KEY_GROUP) flags |= IWX_SEC_KEY_FLAG_MCAST_KEY; + else if (k->k_flags & IEEE80211_KEY_IGTK) + flags |= IWX_SEC_KEY_FLAG_MCAST_KEY | IWX_SEC_KEY_FLAG_MFP; + else if (ni->ni_flags & IEEE80211_NODE_MFP) + flags |= IWX_SEC_KEY_FLAG_MFP; memset(&cmd, 0, sizeof(cmd)); cmd.u.add.sta_mask = htole32(1 << sta_id); @@ -8826,18 +8892,31 @@ iwx_mld_add_sta_key_cmd(struct iwx_softc *sc, int sta_id, cmd.u.add.key_flags = htole32(flags); cmd.u.add.tx_seq = htole64(k->k_tsc); memcpy(cmd.u.add.key, k->k_key, k->k_len); - cmd.action = IWX_FW_CTXT_ACTION_ADD; + if (remove_key) + cmd.action = IWX_FW_CTXT_ACTION_REMOVE; + else + cmd.action = IWX_FW_CTXT_ACTION_ADD; err = iwx_send_cmd_pdu(sc, IWX_WIDE_ID(IWX_DATA_PATH_GROUP, IWX_SEC_KEY_CMD), - 0, sizeof(cmd), &cmd); + remove_key ? IWX_CMD_ASYNC : 0, sizeof(cmd), &cmd); if (err) { + if (remove_key) + return err; + IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_LEAVE); ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); return err; } + if (!remove_key) { + if (k->k_flags & IEEE80211_KEY_GROUP) + ic->ic_def_txkey = k->k_id; + if (k->k_flags & IEEE80211_KEY_IGTK) + ic->ic_igtk_kid = k->k_id; + } + return 0; } @@ -8859,8 +8938,11 @@ iwx_add_sta_key_cmd(struct iwx_softc *sc, int sta_id, if (k->k_flags & IEEE80211_KEY_GROUP) { cmd.common.key_offset = 1; cmd.common.key_flags |= htole16(IWX_STA_KEY_MULTICAST); - } else + } else { cmd.common.key_offset = 0; + if (ni->ni_flags & IEEE80211_NODE_MFP) + cmd.common.key_flags |= htole16(IWX_STA_KEY_MFP); + } memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len)); cmd.common.sta_id = sta_id; @@ -8881,20 +8963,88 @@ iwx_add_sta_key_cmd(struct iwx_softc *sc, int sta_id, return err; } + if (k->k_flags & IEEE80211_KEY_GROUP) + ic->ic_def_txkey = k->k_id; + return 0; } +int +iwx_set_sta_igtk(struct iwx_softc *sc, int sta_id, struct ieee80211_node *ni, + struct ieee80211_key *k, int remove_key) +{ + struct iwx_mgmt_mcast_key_cmd igtk_cmd = {}; + + /* Verify key details match the required command's expectations. */ + if (k == &ni->ni_pairwise_key || + (k->k_id != 4 && k->k_id != 5 && + k->k_id != 6 && k->k_id != 7) || + /* TODO: Other ciphers for WPA3? */ + k->k_cipher != IEEE80211_CIPHER_BIP) + return EINVAL; + + if (!isset(sc->sc_enabled_capa, + IWX_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT) && + k->k_cipher != IEEE80211_CIPHER_BIP) + return EINVAL; + + igtk_cmd.key_id = htole32(k->k_id); + igtk_cmd.sta_id = htole32(sta_id); + + if (remove_key) { + igtk_cmd.ctrl_flags |= htole32(IWX_STA_KEY_NOT_VALID); + } else { + switch (k->k_cipher) { + case IEEE80211_CIPHER_BIP: + igtk_cmd.ctrl_flags |= htole32(IWX_STA_KEY_FLG_CCM); + break; + /* TODO: Other ciphers for WPA3? */ + default: + return EINVAL; + } + + memcpy(igtk_cmd.igtk, k->k_key, k->k_len); + igtk_cmd.receive_seq_cnt = htole64(k->k_mgmt_rsc); + } + + DPRINTF(("%s %sIGTK (%d) for sta %u\n", + remove_key ? "removing" : "installing", + k->k_id >= 6 ? "B" : "", k->k_id, sta_id)); + + if (!isset(sc->sc_enabled_capa, + IWX_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT)) { + struct iwx_mgmt_mcast_key_cmd_v1 igtk_cmd_v1 = { + .ctrl_flags = igtk_cmd.ctrl_flags, + .key_id = igtk_cmd.key_id, + .sta_id = igtk_cmd.sta_id, + .receive_seq_cnt = igtk_cmd.receive_seq_cnt + }; + + memcpy(igtk_cmd_v1.igtk, igtk_cmd.igtk, + sizeof(igtk_cmd_v1.igtk)); + return iwx_send_cmd_pdu(sc, IWX_MGMT_MCAST_KEY, + remove_key ? IWX_CMD_ASYNC : 0, + sizeof(igtk_cmd_v1), &igtk_cmd_v1); + } + + return iwx_send_cmd_pdu(sc, IWX_MGMT_MCAST_KEY, + remove_key ? IWX_CMD_ASYNC : 0, sizeof(igtk_cmd), &igtk_cmd); +} + int iwx_add_sta_key(struct iwx_softc *sc, int sta_id, struct ieee80211_node *ni, struct ieee80211_key *k) { struct ieee80211com *ic = &sc->sc_ic; struct iwx_node *in = (void *)ni; - const int want_keymask = (IWX_NODE_FLAG_HAVE_PAIRWISE_KEY | + int want_keymask = (IWX_NODE_FLAG_HAVE_PAIRWISE_KEY | IWX_NODE_FLAG_HAVE_GROUP_KEY); uint8_t sec_key_ver; int err; + if (ni->ni_flags & IEEE80211_NODE_MFP) + want_keymask |= IWX_NODE_FLAG_HAVE_INTEGRITY_GROUP_KEY; + /* * Keys are stored in 'ni' so 'k' is valid if 'ni' is valid. * Currently we only implement station mode where 'ni' is always @@ -8905,20 +9055,28 @@ iwx_add_sta_key(struct iwx_softc *sc, int sta_id, struct ieee80211_node *ni, sec_key_ver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP, IWX_SEC_KEY_CMD); if (sec_key_ver != 0 && sec_key_ver != IWX_FW_CMD_VER_UNKNOWN) - err = iwx_mld_add_sta_key_cmd(sc, sta_id, ni, k); + err = iwx_mld_set_sta_key_cmd(sc, sta_id, ni, k, 0); + else if (k->k_flags & IEEE80211_KEY_IGTK) + err = iwx_set_sta_igtk(sc, sta_id, ni, k, 0); else err = iwx_add_sta_key_cmd(sc, sta_id, ni, k); if (err) return err; - if (k->k_flags & IEEE80211_KEY_GROUP) + if (k->k_flags & IEEE80211_KEY_IGTK) { + in->in_flags |= IWX_NODE_FLAG_HAVE_INTEGRITY_GROUP_KEY; + ic->ic_igtk_kid = k->k_id; + } else if (k->k_flags & IEEE80211_KEY_GROUP) { in->in_flags |= IWX_NODE_FLAG_HAVE_GROUP_KEY; - else + ic->ic_def_txkey = k->k_id; + } else in->in_flags |= IWX_NODE_FLAG_HAVE_PAIRWISE_KEY; if ((in->in_flags & want_keymask) == want_keymask) { DPRINTF(("marking port %s valid\n", ether_sprintf(ni->ni_macaddr))); + if (ni->ni_flags & IEEE80211_NODE_MFP) + ni->ni_flags |= IEEE80211_NODE_TXMGMTPROT; ni->ni_port_valid = 1; ieee80211_set_link_state(ic, LINK_STATE_UP); } @@ -8956,8 +9114,10 @@ iwx_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, { struct iwx_softc *sc = ic->ic_softc; struct iwx_add_sta_key_cmd cmd; + uint8_t sec_key_ver; - if (k->k_cipher != IEEE80211_CIPHER_CCMP) { + if (k->k_cipher != IEEE80211_CIPHER_CCMP && + (k->k_flags & IEEE80211_KEY_IGTK) == 0) { /* Fallback to software crypto for other ciphers. */ ieee80211_delete_key(ic, ni, k); return; @@ -8966,6 +9126,18 @@ iwx_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, if ((sc->sc_flags & IWX_FLAG_STA_ACTIVE) == 0) return; + sec_key_ver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP, + IWX_SEC_KEY_CMD); + if (sec_key_ver != 0 && sec_key_ver != IWX_FW_CMD_VER_UNKNOWN) { + iwx_mld_set_sta_key_cmd(sc, IWX_STATION_ID, ni, k, 1); + return; + } + + if (k->k_flags & IEEE80211_KEY_IGTK) { + iwx_set_sta_igtk(sc, IWX_STATION_ID, ni, k, 1); + return; + } + memset(&cmd, 0, sizeof(cmd)); cmd.common.key_flags = htole16(IWX_STA_KEY_NOT_VALID | @@ -9677,6 +9849,49 @@ iwx_start(struct ifnet *ifp) return; } +void +iwx_mfp_leave_done(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + struct iwx_softc *sc = ic->ic_softc; + struct ifnet *ifp = IC2IFP(&sc->sc_ic); + + if ((ifp->if_flags & IFF_RUNNING) && + ic->ic_state == IEEE80211_S_RUN && + (ni->ni_flags & IEEE80211_NODE_MFP)) { + sc->deauth_sent = 1; + wakeup(&sc->deauth_sent); + } +} + +void +iwx_mfp_leave(struct iwx_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = (void *)ic->ic_bss; + + ic->ic_xflags |= IEEE80211_F_TX_MGMT_ONLY; + sc->deauth_sent = 0; + + ni->ni_unref_cb = iwx_mfp_leave_done; + ni->ni_unref_arg = NULL; + ni->ni_unref_arg_size = 0; + + /* + * Send an authenticated deauth frame in order to let our AP know we + * are leaving. This allows our AP to tear down MFP state cleanly. + * Otherwise we would remain locked out of this AP until a timeout + * of stale MFP state occurs at the AP, which might take a while. + */ + if (IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_AUTH_LEAVE) != 0) { + ni->ni_unref_cb = NULL; + return; + } + + if (tsleep_nsec(&sc->deauth_sent, 0, "iwxlv", MSEC_TO_NSEC(500)) != 0) + ni->ni_unref_cb = NULL; +} + void iwx_stop(struct ifnet *ifp) { @@ -9702,6 +9917,11 @@ iwx_stop(struct ifnet *ifp) KASSERT(sc->task_refs.r_refs >= 1); refcnt_finalize(&sc->task_refs, "iwxstop"); + if (ic->ic_opmode == IEEE80211_M_STA && + ic->ic_state == IEEE80211_S_RUN && + (ic->ic_bss->ni_flags & IEEE80211_NODE_MFP)) + iwx_mfp_leave(sc); + iwx_stop_device(sc); free(sc->bgscan_unref_arg, M_DEVBUF, sc->bgscan_unref_arg_size); @@ -10370,6 +10590,7 @@ iwx_rx_pkt(struct iwx_softc *sc, struct iwx_rx_data *data, struct mbuf_list *ml) case IWX_WIDE_ID(IWX_REGULATORY_AND_NVM_GROUP, IWX_NVM_GET_INFO): case IWX_ADD_STA_KEY: + case IWX_MGMT_MCAST_KEY: case IWX_PHY_CONFIGURATION_CMD: case IWX_TX_ANT_CONFIGURATION_CMD: case IWX_ADD_STA: @@ -11588,9 +11809,14 @@ iwx_attach(struct device *parent, struct device *self, void *aux) case PCI_PRODUCT_INTEL_WL_22500_3: if (sc->sc_hw_rev == IWX_CSR_HW_REV_TYPE_QU_C0) sc->sc_fwname = IWX_QU_C_HR_B_FW; - else if (sc->sc_hw_rev == IWX_CSR_HW_REV_TYPE_QUZ) - sc->sc_fwname = IWX_QUZ_A_HR_B_FW; - else + else if (sc->sc_hw_rev == IWX_CSR_HW_REV_TYPE_QUZ) { + uint32_t rf_id = IWX_CSR_HW_RFID_TYPE(sc->sc_hw_rf_id); + if (rf_id == IWX_CFG_RF_TYPE_JF1 || + rf_id == IWX_CFG_RF_TYPE_JF2) + sc->sc_fwname = IWX_QUZ_A_JF_B_FW; + else + sc->sc_fwname = IWX_QUZ_A_HR_B_FW; + } else sc->sc_fwname = IWX_QU_B_HR_B_FW; sc->sc_device_family = IWX_DEVICE_FAMILY_22000; sc->sc_integrated = 1; @@ -11781,7 +12007,8 @@ iwx_attach(struct device *parent, struct device *self, void *aux) IEEE80211_C_SCANALLBAND | /* device scans all bands at once */ IEEE80211_C_MONITOR | /* monitor mode supported */ IEEE80211_C_SHSLOT | /* short slot time supported */ - IEEE80211_C_SHPREAMBLE; /* short preamble supported */ + IEEE80211_C_SHPREAMBLE | /* short preamble supported */ + IEEE80211_C_MFP; /* management frame protection */ ic->ic_htcaps = IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_SGI40; ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40; diff --git a/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwxreg.h b/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwxreg.h index dfc3a5c480..a6556c35ed 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwxreg.h +++ b/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwxreg.h,v 1.55 2024/11/08 09:12:46 kettenis Exp $ */ +/* $OpenBSD: if_iwxreg.h,v 1.58 2025/12/01 16:44:13 stsp Exp $ */ /*- * Based on BSD-licensed source modules in the Linux iwlwifi driver, @@ -2836,7 +2836,7 @@ struct iwx_fw_dbg_trigger_time_event { * rx_bar: tid bitmap to configure on what tid the trigger should occur * when a BAR is received (for a Tx BlockAck session). * tx_bar: tid bitmap to configure on what tid the trigger should occur - * when a BAR is send (for an Rx BlocAck session). + * when a BAR is send (for an Rx BlockAck session). * frame_timeout: tid bitmap to configure on what tid the trigger should occur * when a frame times out in the reordering buffer. */ @@ -4527,7 +4527,7 @@ struct iwx_mac_ctx_cmd { * Available only from version 2 of the command. * This values comes from the EMLSR transition delay in the EML Capabilities * subfield. - * @medium_sync_delay: the value as it appeasr in P802.11be_D2.2 Figure 9-1002j. + * @medium_sync_delay: the value as it appears in P802.11be_D2.2 Figure 9-1002j. * @assoc_id: unique ID assigned by the AP during association * @reserved1: alignment * @data_policy: see &enum iwx_mac_data_policy @@ -8040,16 +8040,34 @@ struct iwx_rm_sta_cmd { * @key_id: * @receive_seq_cnt: initial RSC/PN needed for replay check */ -struct iwx_mgmt_mcast_key_cmd { +struct iwx_mgmt_mcast_key_cmd_v1 { uint32_t ctrl_flags; - uint8_t IGTK[16]; - uint8_t K1[16]; - uint8_t K2[16]; + uint8_t igtk[16]; + uint8_t k1[16]; + uint8_t k2[16]; uint32_t key_id; uint32_t sta_id; uint64_t receive_seq_cnt; } __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_1 */ +/** + * struct iwx_mgmt_mcast_key_cmd - IGTK command + * ( MGMT_MCAST_KEY = 0x1f ) + * @ctrl_flags: &enum iwx_sta_key_flag + * @igtk: IGTK master key + * @sta_id: station ID that support IGTK + * @key_id: key ID + * @receive_seq_cnt: initial RSC/PN needed for replay check + */ +struct iwx_mgmt_mcast_key_cmd { + uint32_t ctrl_flags; + uint8_t igtk[32]; + uint32_t key_id; + uint32_t sta_id; + uint64_t receive_seq_cnt; +} __packed; /* SEC_MGMT_MULTICAST_KEY_CMD_API_S_VER_2 */ + + struct iwx_wep_key { uint8_t key_index; uint8_t key_offset; diff --git a/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwxvar.h b/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwxvar.h index 02b1fa4de9..480102c405 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwxvar.h +++ b/src/add-ons/kernel/drivers/network/wlan/iaxwifi200/dev/pci/if_iwxvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwxvar.h,v 1.42 2024/11/08 09:12:46 kettenis Exp $ */ +/* $OpenBSD: if_iwxvar.h,v 1.43 2025/12/01 16:44:13 stsp Exp $ */ /* * Copyright (c) 2014 genua mbh @@ -656,6 +656,8 @@ struct iwx_softc { enum ieee80211_state ns_nstate; int ns_arg; + int deauth_sent; + /* Task for firmware BlockAck setup/teardown and its arguments. */ struct task ba_task; struct iwx_ba_task_data ba_rx; @@ -664,13 +666,13 @@ struct iwx_softc { /* Task for setting encryption keys and its arguments. */ struct task setkey_task; /* - * At present we need to process at most two keys at once: - * Our pairwise key and a group key. + * At present we need to process at most three keys at once: + * Our pairwise key, a group key, and an integrity group key. * When hostap mode is implemented this array needs to grow or * it might become a bottleneck for associations that occur at * roughly the same time. */ - struct iwx_setkey_task_arg setkey_arg[2]; + struct iwx_setkey_task_arg setkey_arg[3]; int setkey_cur; int setkey_tail; int setkey_nkeys; @@ -849,9 +851,11 @@ struct iwx_node { struct iwx_rxq_dup_data dup_data; int in_flags; -#define IWX_NODE_FLAG_HAVE_PAIRWISE_KEY 0x01 -#define IWX_NODE_FLAG_HAVE_GROUP_KEY 0x02 +#define IWX_NODE_FLAG_HAVE_PAIRWISE_KEY 0x01 +#define IWX_NODE_FLAG_HAVE_GROUP_KEY 0x02 +#define IWX_NODE_FLAG_HAVE_INTEGRITY_GROUP_KEY 0x04 }; + #define IWX_STATION_ID 0 #define IWX_AUX_STA_ID 1 #define IWX_MONITOR_STA_ID 2 diff --git a/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwm.c b/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwm.c index 1a12d50e92..a474dd850a 100644 --- a/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwm.c +++ b/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwm.c,v 1.414 2024/02/16 11:44:52 stsp Exp $ */ +/* $OpenBSD: if_iwm.c,v 1.419 2025/12/01 16:30:46 stsp Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh @@ -8189,7 +8189,7 @@ iwm_rval2ridx(int rval) break; } - return ridx; + return ridx; } void @@ -8554,7 +8554,7 @@ iwm_scan(struct iwm_softc *sc) * The current mode might have been fixed during association. * Ensure all channels get scanned. */ - if (IFM_SUBTYPE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) + if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); sc->sc_flags |= IWM_FLAG_SCANNING; @@ -9149,6 +9149,8 @@ iwm_set_key_v1(struct ieee80211com *ic, struct ieee80211_node *ni, IWM_STA_KEY_FLG_KEYID_MSK)); if (k->k_flags & IEEE80211_KEY_GROUP) cmd.common.key_flags |= htole16(IWM_STA_KEY_MULTICAST); + if (ni->ni_flags & IEEE80211_NODE_MFP) + cmd.common.key_flags |= htole16(IWM_STA_KEY_MFP); memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len)); cmd.common.key_offset = 0; @@ -9182,6 +9184,8 @@ iwm_set_key(struct ieee80211com *ic, struct ieee80211_node *ni, IWM_STA_KEY_FLG_KEYID_MSK)); if (k->k_flags & IEEE80211_KEY_GROUP) cmd.common.key_flags |= htole16(IWM_STA_KEY_MULTICAST); + if (ni->ni_flags & IEEE80211_NODE_MFP) + cmd.common.key_flags |= htole16(IWM_STA_KEY_MFP); memcpy(cmd.common.key, k->k_key, MIN(sizeof(cmd.common.key), k->k_len)); cmd.common.key_offset = 0; @@ -9263,7 +9267,7 @@ iwm_calib_timeout(void *arg) ieee80211_amrr_choose(&sc->sc_amrr, &in->in_ni, &in->in_amn); /* * If AMRR has chosen a new TX rate we must update - * the firwmare's LQ rate table. + * the firmware's LQ rate table. * ni_txrate may change again before the task runs so * cache the chosen rate in the iwm_node structure. */ @@ -10523,6 +10527,49 @@ iwm_start(struct ifnet *ifp) return; } +void +iwm_mfp_leave_done(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + struct iwm_softc *sc = ic->ic_softc; + struct ifnet *ifp = IC2IFP(&sc->sc_ic); + + if ((ifp->if_flags & IFF_RUNNING) && + ic->ic_state == IEEE80211_S_RUN && + (ni->ni_flags & IEEE80211_NODE_MFP)) { + sc->deauth_sent = 1; + wakeup(&sc->deauth_sent); + } +} + +void +iwm_mfp_leave(struct iwm_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = (void *)ic->ic_bss; + + ic->ic_xflags |= IEEE80211_F_TX_MGMT_ONLY; + sc->deauth_sent = 0; + + ni->ni_unref_cb = iwm_mfp_leave_done; + ni->ni_unref_arg = NULL; + ni->ni_unref_arg_size = 0; + + /* + * Send an authenticated deauth frame in order to let our AP know we + * are leaving. This allows our AP to tear down MFP state cleanly. + * Otherwise we would remain locked out of this AP until a timeout + * of stale MFP state occurs at the AP, which might take a while. + */ + if (IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_AUTH_LEAVE) != 0) { + ni->ni_unref_cb = NULL; + return; + } + + if (tsleep_nsec(&sc->deauth_sent, 0, "iwmlv", MSEC_TO_NSEC(500)) != 0) + ni->ni_unref_cb = NULL; +} + void iwm_stop(struct ifnet *ifp) { @@ -10545,6 +10592,11 @@ iwm_stop(struct ifnet *ifp) KASSERT(sc->task_refs.r_refs >= 1); refcnt_finalize(&sc->task_refs, "iwmstop"); + if (ic->ic_opmode == IEEE80211_M_STA && + ic->ic_state == IEEE80211_S_RUN && + (ic->ic_bss->ni_flags & IEEE80211_NODE_MFP)) + iwm_mfp_leave(sc); + iwm_stop_device(sc); free(sc->bgscan_unref_arg, M_DEVBUF, sc->bgscan_unref_arg_size); @@ -12043,7 +12095,8 @@ iwm_attach(struct device *parent, struct device *self, void *aux) IEEE80211_C_SCANALLBAND | /* device scans all bands at once */ IEEE80211_C_MONITOR | /* monitor mode supported */ IEEE80211_C_SHSLOT | /* short slot time supported */ - IEEE80211_C_SHPREAMBLE; /* short preamble supported */ + IEEE80211_C_SHPREAMBLE | /* short preamble supported */ + IEEE80211_C_MFP; /* management frame protection */ ic->ic_htcaps = IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_SGI40; ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40; diff --git a/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwmreg.h b/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwmreg.h index af10511b10..cc48057e05 100644 --- a/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwmreg.h +++ b/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwmreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwmreg.h,v 1.68 2022/03/19 10:26:52 stsp Exp $ */ +/* $OpenBSD: if_iwmreg.h,v 1.70 2024/09/01 03:08:59 jsg Exp $ */ /****************************************************************************** * @@ -1762,7 +1762,7 @@ static inline unsigned int IWM_FH_MEM_CBBC_QUEUE(unsigned int chnl) #define IWM_RX_LOW_WATERMARK 8 /** - * struct iwm_rb_status - reseve buffer status + * struct iwm_rb_status - reserve buffer status * host memory mapped FH registers * @closed_rb_num [0:11] - Indicates the index of the RB which was closed * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed @@ -3361,7 +3361,7 @@ struct iwm_rx_mpdu_desc_v1 { uint32_t phy_data0; uint32_t phy_data1; }; - }; + } __packed; } __packed; #define IWM_RX_REORDER_DATA_INVALID_BAID 0x7f diff --git a/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwmvar.h b/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwmvar.h index ca3eb050b7..3e4e458a14 100644 --- a/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwmvar.h +++ b/src/add-ons/kernel/drivers/network/wlan/idualwifi7260/dev/pci/if_iwmvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwmvar.h,v 1.77 2022/03/19 14:50:01 stsp Exp $ */ +/* $OpenBSD: if_iwmvar.h,v 1.79 2025/12/01 16:30:46 stsp Exp $ */ /* * Copyright (c) 2014 genua mbh @@ -491,6 +491,8 @@ struct iwm_softc { enum ieee80211_state ns_nstate; int ns_arg; + int deauth_sent; + /* Task for firmware BlockAck setup/teardown and its arguments. */ struct task ba_task; struct iwm_ba_task_data ba_rx; diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211.c b/src/libs/compat/openbsd_wlan/net80211/ieee80211.c index 6dac23dc14..4b6a967e4c 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211.c +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211.c,v 1.89 2024/02/15 15:40:56 stsp Exp $ */ +/* $OpenBSD: ieee80211.c,v 1.91 2025/08/01 20:39:26 stsp Exp $ */ /* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */ /*- @@ -1182,7 +1182,7 @@ ieee80211_next_mode(struct ifnet *ifp) * Indicate a wrap-around if we're running in a fixed, user-specified * phy mode. */ - if (IFM_SUBTYPE(ic->ic_media.ifm_cur->ifm_media) != IFM_AUTO) + if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) != IFM_AUTO) return (IEEE80211_MODE_AUTO); /* @@ -1230,55 +1230,6 @@ ieee80211_next_mode(struct ifnet *ifp) return (ic->ic_curmode); } -/* - * Return the phy mode for with the specified channel so the - * caller can select a rate set. This is problematic and the - * work here assumes how things work elsewhere in this code. - * - * Because the result of this function is ultimately used to select a - * rate from the rate set of the returned mode, it must return one of the - * legacy 11a/b/g modes; 11n and 11ac modes use MCS instead of rate sets. - */ -enum ieee80211_phymode -ieee80211_chan2mode(struct ieee80211com *ic, - const struct ieee80211_channel *chan) -{ - /* - * Are we fixed in 11a/b/g mode? - * NB: this assumes the channel would not be supplied to us - * unless it was already compatible with the current mode. - */ - if (ic->ic_curmode == IEEE80211_MODE_11A || - ic->ic_curmode == IEEE80211_MODE_11B || - ic->ic_curmode == IEEE80211_MODE_11G) - return ic->ic_curmode; - - /* If no channel was provided, return the most suitable legacy mode. */ - if (chan == IEEE80211_CHAN_ANYC) { - switch (ic->ic_curmode) { - case IEEE80211_MODE_AUTO: - case IEEE80211_MODE_11N: - if (ic->ic_modecaps & (1 << IEEE80211_MODE_11A)) - return IEEE80211_MODE_11A; - if (ic->ic_modecaps & (1 << IEEE80211_MODE_11G)) - return IEEE80211_MODE_11G; - return IEEE80211_MODE_11B; - case IEEE80211_MODE_11AC: - return IEEE80211_MODE_11A; - default: - return ic->ic_curmode; - } - } - - /* Deduce a legacy mode based on the channel characteristics. */ - if (IEEE80211_IS_CHAN_5GHZ(chan)) - return IEEE80211_MODE_11A; - else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) - return IEEE80211_MODE_11G; - else - return IEEE80211_MODE_11B; -} - /* * Convert IEEE80211 MCS index to ifmedia subtype. */ diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211.h b/src/libs/compat/openbsd_wlan/net80211/ieee80211.h index 74fb5bda3e..31e9b2464f 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211.h +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211.h,v 1.63 2022/03/14 15:07:24 stsp Exp $ */ +/* $OpenBSD: ieee80211.h,v 1.64 2025/08/04 11:39:50 stsp Exp $ */ /* $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $ */ /*- @@ -103,6 +103,8 @@ struct ieee80211_htframe_addr4 { /* 11n */ u_int8_t i_ht[4]; } __packed; +#define IEEE80211_MAX_FRAME_HDR_LEN (sizeof(struct ieee80211_htframe_addr4)) + #define IEEE80211_FC0_VERSION_MASK 0x03 #define IEEE80211_FC0_VERSION_SHIFT 0 #define IEEE80211_FC0_VERSION_0 0x00 diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_crypto.c b/src/libs/compat/openbsd_wlan/net80211/ieee80211_crypto.c index 8873924c2d..424f84a3c1 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_crypto.c +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_crypto.c,v 1.79 2024/04/14 03:26:25 jsg Exp $ */ +/* $OpenBSD: ieee80211_crypto.c,v 1.81 2025/12/03 10:21:12 stsp Exp $ */ /*- * Copyright (c) 2008 Damien Bergamini @@ -62,6 +62,8 @@ ieee80211_crypto_attach(struct ifnet *ifp) if (ic->ic_caps & IEEE80211_C_RSN) { ic->ic_rsnprotos = IEEE80211_PROTO_RSN; ic->ic_rsnakms = IEEE80211_AKM_PSK; + if (ic->ic_caps & IEEE80211_C_MFP) + ic->ic_rsnakms |= IEEE80211_AKM_SHA256_PSK; ic->ic_rsnciphers = IEEE80211_CIPHER_CCMP; ic->ic_rsngroupcipher = IEEE80211_CIPHER_CCMP; ic->ic_rsngroupmgmtcipher = IEEE80211_CIPHER_BIP; @@ -386,8 +388,6 @@ ieee80211_derive_ptk(enum ieee80211_akm akm, const u_int8_t *pmk, const u_int8_t *aa, const u_int8_t *spa, const u_int8_t *anonce, const u_int8_t *snonce, struct ieee80211_ptk *ptk) { - void (*kdf)(const u_int8_t *, size_t, const u_int8_t *, size_t, - const u_int8_t *, size_t, u_int8_t *, size_t); u_int8_t buf[2 * IEEE80211_ADDR_LEN + 2 * EAPOL_KEY_NONCE_LEN]; int ret; @@ -401,9 +401,17 @@ ieee80211_derive_ptk(enum ieee80211_akm akm, const u_int8_t *pmk, memcpy(&buf[12], ret ? anonce : snonce, EAPOL_KEY_NONCE_LEN); memcpy(&buf[44], ret ? snonce : anonce, EAPOL_KEY_NONCE_LEN); - kdf = ieee80211_is_sha256_akm(akm) ? ieee80211_kdf : ieee80211_prf; - (*kdf)(pmk, IEEE80211_PMK_LEN, "Pairwise key expansion", 23, - buf, sizeof buf, (u_int8_t *)ptk, sizeof(*ptk)); + if (ieee80211_is_sha256_akm(akm)) { + ieee80211_kdf(pmk, IEEE80211_PMK_LEN, "Pairwise key expansion", + 22 /* KDF omits \0 */, buf, sizeof buf, (u_int8_t *)ptk, + /* expected output size of 48 is mixed into hash */ + MIN(48, sizeof(*ptk))); + CTASSERT(sizeof(struct ieee80211_ptk) >= 48); + } else { + ieee80211_prf(pmk, IEEE80211_PMK_LEN, "Pairwise key expansion", + 23 /* PRF uses \0 */, buf, sizeof buf, (u_int8_t *)ptk, + sizeof(*ptk)); + } } static void diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_crypto.h b/src/libs/compat/openbsd_wlan/net80211/ieee80211_crypto.h index 748b44b3f8..0386f94ef3 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_crypto.h +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_crypto.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_crypto.h,v 1.27 2020/05/15 14:21:09 stsp Exp $ */ +/* $OpenBSD: ieee80211_crypto.h,v 1.28 2025/03/22 07:24:08 kevlo Exp $ */ /*- * Copyright (c) 2007,2008 Damien Bergamini @@ -44,7 +44,8 @@ enum ieee80211_akm { IEEE80211_AKM_8021X = 0x00000001, IEEE80211_AKM_PSK = 0x00000002, IEEE80211_AKM_SHA256_8021X = 0x00000004, /* 11w */ - IEEE80211_AKM_SHA256_PSK = 0x00000008 /* 11w */ + IEEE80211_AKM_SHA256_PSK = 0x00000008, /* 11w */ + IEEE80211_AKM_SAE = 0x00000010 }; #define IEEE80211_TKIP_HDRLEN 8 diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_input.c b/src/libs/compat/openbsd_wlan/net80211/ieee80211_input.c index c426c898c5..df7ad29b12 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_input.c +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_input.c,v 1.254 2024/05/23 11:19:13 stsp Exp $ */ +/* $OpenBSD: ieee80211_input.c,v 1.258 2026/01/30 04:25:52 gnezdo Exp $ */ /* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */ /*- @@ -424,7 +424,9 @@ ieee80211_inputm(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, *orxseq = nrxseq; } if (ic->ic_state > IEEE80211_S_SCAN) { - ni->ni_rssi = rxi->rxi_rssi; + /* Only update RSSI if driver provided a valid value. */ + if (rxi->rxi_rssi != 0) + ni->ni_rssi = rxi->rxi_rssi; ni->ni_rstamp = rxi->rxi_tstamp; ni->ni_inact = 0; @@ -637,26 +639,39 @@ ieee80211_inputm(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, } if (ni->ni_flags & IEEE80211_NODE_RXMGMTPROT) { + int is_multicast, is_protected; + + is_multicast = IEEE80211_IS_MULTICAST(wh->i_addr1); + is_protected = (wh->i_fc[1] & IEEE80211_FC1_PROTECTED); + /* MMPDU protection is on for Rx */ if (subtype == IEEE80211_FC0_SUBTYPE_DISASSOC || subtype == IEEE80211_FC0_SUBTYPE_DEAUTH || subtype == IEEE80211_FC0_SUBTYPE_ACTION) { - if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && - !(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { + if (rxi->rxi_flags & IEEE80211_RXI_HWDEC) { + m = ieee80211_input_hwdecrypt(ic, ni, + m, rxi); + if (m == NULL) + goto out; + } else if (!is_multicast && !is_protected) { /* unicast mgmt not encrypted */ + ic->ic_stats.is_rx_unencrypted++; goto out; - } - /* do software decryption */ - m = ieee80211_decrypt(ic, m, ni); - if (m == NULL) { - /* XXX stats */ - goto out; + } else { + /* do software decryption */ + m = ieee80211_decrypt(ic, m, ni); + if (m == NULL) { + ic->ic_stats.is_rx_wepfail++; + goto out; + } } wh = mtod(m, struct ieee80211_frame *); } } else if ((ic->ic_flags & IEEE80211_F_RSNON) && - (wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) { + ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) || + (rxi->rxi_flags & IEEE80211_RXI_HWDEC))) { /* encrypted but MMPDU Rx protection off for TA */ + ic->ic_stats.is_rx_nowep++; goto out; } @@ -1429,6 +1444,8 @@ ieee80211_parse_rsn_akm(const u_int8_t selector[4]) return IEEE80211_AKM_SHA256_8021X; case 6: /* PSK with SHA256 KDF */ return IEEE80211_AKM_SHA256_PSK; + case 8: /* SAE */ + return IEEE80211_AKM_SAE; } } return IEEE80211_AKM_NONE; /* ignore unknown AKMs */ @@ -2669,7 +2686,7 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, struct mbuf *m, else if (ni->ni_flags & IEEE80211_NODE_HT) ieee80211_setmode(ic, IEEE80211_MODE_11N); else - ieee80211_setmode(ic, ieee80211_chan2mode(ic, ni->ni_chan)); + ieee80211_setmode(ic, ieee80211_node_abg_mode(ic, ni)); /* * Reset the erp state (mostly the slot time) now that * our operating mode has been nailed down. diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_ioctl.c b/src/libs/compat/openbsd_wlan/net80211/ieee80211_ioctl.c index b433d14242..670fbf236d 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_ioctl.c +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_ioctl.c,v 1.81 2022/03/07 08:13:13 stsp Exp $ */ +/* $OpenBSD: ieee80211_ioctl.c,v 1.84 2025/12/03 10:21:12 stsp Exp $ */ /* $NetBSD: ieee80211_ioctl.c,v 1.15 2004/05/06 02:58:16 dyoung Exp $ */ /*- @@ -129,6 +129,9 @@ ieee80211_node2req(struct ieee80211com *ic, const struct ieee80211_node *ni, nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_8021X; if (ni->ni_supported_rsnakms & IEEE80211_AKM_SHA256_PSK) nr->nr_rsnakms |= IEEE80211_WPA_AKM_SHA256_PSK; + if (ni->ni_supported_rsnakms & IEEE80211_AKM_SAE) + nr->nr_rsnakms |= IEEE80211_WPA_AKM_SAE; + #ifdef __FreeBSD_version if (ni->ni_rsnie != NULL) memcpy(nr->nr_rsnie, ni->ni_rsnie, 2 + ni->ni_rsnie[1]); @@ -207,6 +210,7 @@ void ieee80211_disable_rsn(struct ieee80211com *ic) { ic->ic_flags &= ~(IEEE80211_F_PSK | IEEE80211_F_RSNON); + ic->ic_flags &= ~IEEE80211_F_MFPR; explicit_bzero(ic->ic_psk, sizeof(ic->ic_psk)); ic->ic_rsnprotos = 0; ic->ic_rsnakms = 0; @@ -331,8 +335,11 @@ ieee80211_ioctl_setwpaparms(struct ieee80211com *ic, ic->ic_rsnakms |= IEEE80211_AKM_8021X; if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_8021X) ic->ic_rsnakms |= IEEE80211_AKM_SHA256_8021X; - if (ic->ic_rsnakms == 0) /* set to default (PSK) */ + if (ic->ic_rsnakms == 0) { /* set to default (PSK) */ ic->ic_rsnakms = IEEE80211_AKM_PSK; + if (ic->ic_caps & IEEE80211_C_MFP) + ic->ic_rsnakms |= IEEE80211_AKM_SHA256_PSK; + } if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP40) ic->ic_rsngroupcipher = IEEE80211_CIPHER_WEP40; diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_ioctl.h b/src/libs/compat/openbsd_wlan/net80211/ieee80211_ioctl.h index d8e3ff87cb..f8d914e005 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_ioctl.h +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_ioctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_ioctl.h,v 1.43 2022/03/14 15:07:24 stsp Exp $ */ +/* $OpenBSD: ieee80211_ioctl.h,v 1.44 2025/03/22 07:24:08 kevlo Exp $ */ /* $NetBSD: ieee80211_ioctl.h,v 1.7 2004/04/30 22:51:04 dyoung Exp $ */ /*- @@ -237,6 +237,7 @@ struct ieee80211_wpapsk { #define IEEE80211_WPA_AKM_8021X 0x02 #define IEEE80211_WPA_AKM_SHA256_PSK 0x04 #define IEEE80211_WPA_AKM_SHA256_8021X 0x08 +#define IEEE80211_WPA_AKM_SAE 0x10 struct ieee80211_wpaparams { char i_name[IFNAMSIZ]; /* if_name, e.g. "wi0" */ diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.c b/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.c index e3c5fc207b..7b6e604136 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.c +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.c,v 1.198 2023/10/22 12:01:36 stsp Exp $ */ +/* $OpenBSD: ieee80211_node.c,v 1.209 2026/02/06 16:27:46 stsp Exp $ */ /* $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $ */ /*- @@ -75,12 +75,15 @@ void ieee80211_setup_node(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *); void ieee80211_node_free_unref_cb(struct ieee80211_node *); void ieee80211_node_tx_flushed(struct ieee80211com *, struct ieee80211_node *); -void ieee80211_node_switch_bss(struct ieee80211com *, 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 *); void ieee80211_node_addba_request_ac_vi_to(void *); void ieee80211_node_addba_request_ac_vo_to(void *); +void ieee80211_node_addba_request_tid4(void *); +void ieee80211_node_addba_request_tid5(void *); +void ieee80211_node_addba_request_tid6(void *); +void ieee80211_node_addba_request_tid7(void *); void ieee80211_needs_auth(struct ieee80211com *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_node_join_ht(struct ieee80211com *, struct ieee80211_node *); @@ -143,6 +146,11 @@ ieee80211_print_ess(struct ieee80211_ess *ess) if (ess->rsnprotos & IEEE80211_PROTO_WPA) printf(",wpa1"); + if (ess->rsnakms & IEEE80211_AKM_PSK) + printf(",psk"); + if (ess->rsnakms & IEEE80211_AKM_SHA256_PSK) + printf(",sha256-psk"); + if (ess->rsnakms & IEEE80211_AKM_8021X || ess->rsnakms & IEEE80211_AKM_SHA256_8021X) printf(",802.1x"); @@ -264,7 +272,7 @@ ieee80211_ess_setnwkeys(struct ieee80211_ess *ess, /* Keep in sync with ieee80211_ioctl.c:ieee80211_ioctl_setwpaparms() */ static int -ieee80211_ess_setwpaparms(struct ieee80211_ess *ess, +ieee80211_ess_setwpaparms(struct ieee80211com *ic, struct ieee80211_ess *ess, const struct ieee80211_wpaparams *wpa) { if (!wpa->i_enabled) { @@ -295,8 +303,13 @@ ieee80211_ess_setwpaparms(struct ieee80211_ess *ess, ess->rsnakms |= IEEE80211_AKM_8021X; if (wpa->i_akms & IEEE80211_WPA_AKM_SHA256_8021X) ess->rsnakms |= IEEE80211_AKM_SHA256_8021X; - if (ess->rsnakms == 0) /* set to default (PSK) */ - ess->rsnakms = IEEE80211_AKM_PSK; + if (wpa->i_akms & IEEE80211_WPA_AKM_SAE) + ess->rsnakms |= IEEE80211_AKM_SAE; + if (ess->rsnakms == 0) { /* set to default (PSK) */ + ess->rsnakms |= IEEE80211_AKM_PSK; + if (ic->ic_caps & IEEE80211_C_MFP) + ess->rsnakms |= IEEE80211_AKM_SHA256_PSK; + } if (wpa->i_groupcipher == IEEE80211_WPA_CIPHER_WEP40) ess->rsngroupcipher = IEEE80211_CIPHER_WEP40; @@ -397,7 +410,7 @@ ieee80211_add_ess(struct ieee80211com *ic, struct ieee80211_join *join) free(ess, M_DEVBUF, sizeof(*ess)); return ENODEV; } - ieee80211_ess_setwpaparms(ess, + ieee80211_ess_setwpaparms(ic, ess, &join->i_wpaparams); if (join->i_flags & IEEE80211_JOIN_WPAPSK) { ess->flags |= IEEE80211_F_PSK; @@ -929,8 +942,29 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan) mode = IEEE80211_MODE_11AC; else if (ic->ic_flags & IEEE80211_F_HTON) mode = IEEE80211_MODE_11N; - else - mode = ieee80211_chan2mode(ic, ni->ni_chan); + else { + /* Was a specific 11a/b/g phy mode set by ifconfig? */ + switch (IFM_MODE(ic->ic_media.ifm_cur->ifm_media)) { + case IFM_IEEE80211_11A: + mode = IEEE80211_MODE_11A; + break; + case IFM_IEEE80211_11G: + mode = IEEE80211_MODE_11G; + break; + case IFM_IEEE80211_11B: + mode = IEEE80211_MODE_11B; + break; + default: /* If we get here, our phy mode is MODE_AUTO. */ + if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) + mode = IEEE80211_MODE_11A; + else if ((ni->ni_chan->ic_flags & + (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN)) != 0) + mode = IEEE80211_MODE_11G; + else + mode = IEEE80211_MODE_11B; + break; + } + } ieee80211_setmode(ic, mode); /* Pick an appropriate mode for supported legacy rates. */ if (ic->ic_curmode == IEEE80211_MODE_11AC) { @@ -1301,7 +1335,7 @@ ieee80211_node_join_bss(struct ieee80211com *ic, struct ieee80211_node *selbs) uint32_t assoc_fail = 0; /* Reinitialize media mode and channels if needed. */ - mode = ieee80211_chan2mode(ic, selbs->ni_chan); + mode = ieee80211_node_abg_mode(ic, selbs); if (mode != ic->ic_curmode) ieee80211_setmode(ic, mode); @@ -1315,8 +1349,6 @@ ieee80211_node_join_bss(struct ieee80211com *ic, struct ieee80211_node *selbs) ni = ic->ic_bss; ni->ni_assoc_fail |= assoc_fail; - ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan); - /* Make sure we send valid rates in an association request. */ if (ic->ic_opmode == IEEE80211_M_STA) ieee80211_fix_rate(ic, ni, @@ -1559,7 +1591,7 @@ ieee80211_end_scan(struct ifnet *ifp) ieee80211_setmode(ic, IEEE80211_MODE_11N); else ieee80211_setmode(ic, - ieee80211_chan2mode(ic, ni->ni_chan)); + ieee80211_node_abg_mode(ic, ni)); return; } @@ -1769,6 +1801,14 @@ ieee80211_node_set_timeouts(struct ieee80211_node *ni) ieee80211_node_addba_request_ac_vi_to, ni); timeout_set(&ni->ni_addba_req_to[EDCA_AC_VO], ieee80211_node_addba_request_ac_vo_to, ni); + timeout_set(&ni->ni_addba_req_to[4], + ieee80211_node_addba_request_tid4, ni); + timeout_set(&ni->ni_addba_req_to[5], + ieee80211_node_addba_request_tid5, ni); + timeout_set(&ni->ni_addba_req_to[6], + ieee80211_node_addba_request_tid6, ni); + timeout_set(&ni->ni_addba_req_to[7], + ieee80211_node_addba_request_tid7, ni); for (i = 0; i < nitems(ni->ni_addba_req_intval); i++) ni->ni_addba_req_intval[i] = 1; } @@ -2065,10 +2105,10 @@ ieee80211_ba_del(struct ieee80211_node *ni) for (tid = 0; tid < nitems(ni->ni_tx_ba); tid++) ieee80211_node_tx_ba_clear(ni, tid); - timeout_del(&ni->ni_addba_req_to[EDCA_AC_BE]); - timeout_del(&ni->ni_addba_req_to[EDCA_AC_BK]); - timeout_del(&ni->ni_addba_req_to[EDCA_AC_VI]); - timeout_del(&ni->ni_addba_req_to[EDCA_AC_VO]); + for (tid = 0; tid < IEEE80211_NUM_TID; tid++) { + if (timeout_initialized(&ni->ni_addba_req_to[tid])) + timeout_del(&ni->ni_addba_req_to[tid]); + } } void @@ -2444,7 +2484,7 @@ ieee80211_40mhz_valid_secondary_below(uint8_t primary_chan) * Only accept 40 MHz channel configurations that conform to * regulatory operating classes as defined by the 802.11ac spec. * Passing other configurations down to firmware can result in - * regulatory assertions being trigged, such as fatal firmware + * regulatory assertions being triggered, such as fatal firmware * error 14FD in iwm(4). * * See 802.11ac 2013, page 380, Tables E-1 to E-5. @@ -2521,7 +2561,7 @@ ieee80211_setup_vhtcaps(struct ieee80211_node *ni, const uint8_t *data, * Only accept 80 MHz channel configurations that conform to * regulatory operating classes as defined by the 802.11ac spec. * Passing other configurations down to firmware can result in - * regulatory assertions being trigged, such as fatal firmware + * regulatory assertions being triggered, such as fatal firmware * error 14FD in iwm(4). * * See 802.11ac 2013, page 380, Tables E-1 to E-5. @@ -2604,6 +2644,28 @@ ieee80211_clear_vhtcaps(struct ieee80211_node *ni) } #endif +int +ieee80211_node_is_11g(struct ieee80211_node *ni) +{ + struct ieee80211_rateset *rs = &ni->ni_rates; + const struct ieee80211_rateset *rs_ofdm = &ieee80211_std_rateset_11a; + int i, j; + + if (!IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) + return 0; + + /* 2GHz station which supports 11a OFDM rates implies 11g. */ + for (i = 0; i < rs->rs_nrates; i++) { + for (j = 0; j < rs_ofdm->rs_nrates; j++) { + if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == + (rs_ofdm->rs_rates[j] & IEEE80211_RATE_VAL)) + return 1; + } + } + + return 0; +} + /* * Install received rate set information in the node's state block. */ @@ -2631,10 +2693,50 @@ ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni, } memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates); rs->rs_nrates += nxrates; + } + + /* 11g support implies ERP support */ + if (ieee80211_node_is_11g(ni)) + ni->ni_flags |= IEEE80211_NODE_ERP; + return ieee80211_fix_rate(ic, ni, flags); } +/* + * Return the 11a/b/g mode mutually supported for the given node. + * ni->ni_chan must be set before calling this, and ieee80211_setup_rates() + * should be called beforehand to properly differentiate 11b and 11g. + */ +enum ieee80211_phymode +ieee80211_node_abg_mode(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + /* Handle the case where our own phy mode was fixed by ifconfig. */ + switch (IFM_MODE(ic->ic_media.ifm_cur->ifm_media)) { + case IFM_IEEE80211_11A: + return IEEE80211_MODE_11A; /* Peer uses 11a. */ + case IFM_IEEE80211_11B: + return IEEE80211_MODE_11B; /* Peer uses 11b. */ + case IFM_IEEE80211_11G: + /* Peer could be using either 11g or 11b, check below. */ + break; + default: + break; + } + + /* Our own phy mode is either 11G or AUTO. */ + + if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) + return IEEE80211_MODE_11A; + + if ((ni->ni_flags & IEEE80211_NODE_ERP) && + (ni->ni_chan->ic_flags & + (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN)) != 0) + return IEEE80211_MODE_11G; + + return IEEE80211_MODE_11B; +} + void ieee80211_node_trigger_addba_req(struct ieee80211_node *ni, int tid) { @@ -2682,32 +2784,35 @@ ieee80211_node_addba_request_ac_vo_to(void *arg) ieee80211_node_addba_request(ni, EDCA_AC_VO); } -#ifndef IEEE80211_STA_ONLY -/* - * Check if the specified node supports ERP. - */ -int -ieee80211_iserp_sta(const struct ieee80211_node *ni) +void +ieee80211_node_addba_request_tid4(void *arg) { - static const u_int8_t rates[] = { 2, 4, 11, 22, 12, 24, 48 }; - const struct ieee80211_rateset *rs = &ni->ni_rates; - int i, j; - - /* - * A STA supports ERP operation if it includes all the Clause 19 - * mandatory rates in its supported rate set. - */ - for (i = 0; i < nitems(rates); i++) { - for (j = 0; j < rs->rs_nrates; j++) { - if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == rates[i]) - break; - } - if (j == rs->rs_nrates) - return 0; - } - return 1; + struct ieee80211_node *ni = arg; + ieee80211_node_addba_request(ni, 4); } +void +ieee80211_node_addba_request_tid5(void *arg) +{ + struct ieee80211_node *ni = arg; + ieee80211_node_addba_request(ni, 5); +} + +void +ieee80211_node_addba_request_tid6(void *arg) +{ + struct ieee80211_node *ni = arg; + ieee80211_node_addba_request(ni, 6); +} + +void +ieee80211_node_addba_request_tid7(void *arg) +{ + struct ieee80211_node *ni = arg; + ieee80211_node_addba_request(ni, 7); +} + +#ifndef IEEE80211_STA_ONLY /* * This function is called to notify the 802.1X PACP machine that a new * 802.1X port is enabled and must be authenticated. For 802.11, a port @@ -2759,6 +2864,8 @@ ieee80211_node_join_rsn(struct ieee80211com *ic, struct ieee80211_node *ni) ni->ni_key_count = 0; ni->ni_port_valid = 0; ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT; + ni->ni_flags &= ~IEEE80211_NODE_RXMGMTPROT; + ni->ni_flags &= ~IEEE80211_NODE_TXMGMTPROT; ni->ni_flags &= ~IEEE80211_NODE_RSN_NEW_PTK; ni->ni_replaycnt = -1; /* XXX */ ni->ni_rsn_retries = 0; @@ -2802,7 +2909,7 @@ ieee80211_count_nonerpsta(void *arg, struct ieee80211_node *ni) if (ni->ni_associd == 0 || ni->ni_state == IEEE80211_STA_COLLECT) return; - if (!ieee80211_iserp_sta(ni)) + if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) (*nonerpsta)++; } @@ -2855,7 +2962,7 @@ ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni) ether_sprintf(ni->ni_macaddr), longslotsta)); } - if (!ieee80211_iserp_sta(ni)) { + if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) { /* * Joining STA is non-ERP. */ @@ -2872,8 +2979,7 @@ ieee80211_node_join_11g(struct ieee80211com *ic, struct ieee80211_node *ni) if (!(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; - } else - ni->ni_flags |= IEEE80211_NODE_ERP; + } } void @@ -2998,6 +3104,9 @@ ieee80211_node_leave_rsn(struct ieee80211com *ic, struct ieee80211_node *ni) ni->ni_rsn_retries = 0; ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT; + ni->ni_flags &= ~IEEE80211_NODE_RXMGMTPROT; + ni->ni_flags &= ~IEEE80211_NODE_TXMGMTPROT; + ni->ni_flags &= ~IEEE80211_NODE_RSN_NEW_PTK; ni->ni_port_valid = 0; (*ic->ic_delete_key)(ic, ni, &ni->ni_pairwise_key); } diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.h b/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.h index bb3aaf2bc0..05fd164e96 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.h +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.h,v 1.94 2022/03/20 12:01:58 stsp Exp $ */ +/* $OpenBSD: ieee80211_node.h,v 1.98 2026/02/06 16:27:46 stsp Exp $ */ /* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */ /*- @@ -52,7 +52,7 @@ extern const struct ieee80211_rateset ieee80211_std_rateset_11a; extern const struct ieee80211_rateset ieee80211_std_rateset_11b; extern const struct ieee80211_rateset ieee80211_std_rateset_11g; -/* Index into ieee80211_std_rateset_11n[] array. */ +/* Index into ieee80211_std_ratesets_11n[] array. */ #define IEEE80211_HT_RATESET_SISO 0 #define IEEE80211_HT_RATESET_SISO_SGI 1 #define IEEE80211_HT_RATESET_MIMO2 2 @@ -98,7 +98,7 @@ struct ieee80211_ht_rateset { extern const struct ieee80211_ht_rateset ieee80211_std_ratesets_11n[]; -/* Index into ieee80211_std_rateset_11ac[] array. */ +/* Index into ieee80211_std_ratesets_11ac[] array. */ #define IEEE80211_VHT_RATESET_SISO 0 #define IEEE80211_VHT_RATESET_SISO_SGI 1 #define IEEE80211_VHT_RATESET_MIMO2 2 @@ -117,7 +117,7 @@ extern const struct ieee80211_ht_rateset ieee80211_std_ratesets_11n[]; #define IEEE80211_VHT_RATESET_MAX_NRATES 10 struct ieee80211_vht_rateset { - int idx; /* This rateset's index in ieee80211_std_rateset_11ac[]. */ + int idx; /* This rateset's index in ieee80211_std_ratesets_11ac[]. */ uint32_t nrates; uint32_t rates[IEEE80211_VHT_RATESET_MAX_NRATES]; /* 500 kbit/s units */ @@ -420,13 +420,13 @@ struct ieee80211_node { #define IEEE80211_NODE_SA_QUERY 0x0800 /* SA Query in progress */ #define IEEE80211_NODE_SA_QUERY_FAILED 0x1000 /* last SA Query failed */ #define IEEE80211_NODE_RSN_NEW_PTK 0x2000 /* expecting a new PTK */ -#define IEEE80211_NODE_HT_SGI20 0x4000 /* SGI on 20 MHz negotiated */ -#define IEEE80211_NODE_HT_SGI40 0x8000 /* SGI on 40 MHz negotiated */ +#define IEEE80211_NODE_HT_SGI20 0x4000 /* SGI on 20 MHz negotiated */ +#define IEEE80211_NODE_HT_SGI40 0x8000 /* SGI on 40 MHz negotiated */ #define IEEE80211_NODE_VHT 0x10000 /* VHT negotiated */ #define IEEE80211_NODE_HTCAP 0x20000 /* claims to support HT */ #define IEEE80211_NODE_VHTCAP 0x40000 /* claims to support VHT */ -#define IEEE80211_NODE_VHT_SGI80 0x80000 /* SGI on 80 MHz negotiated */ -#define IEEE80211_NODE_VHT_SGI160 0x100000 /* SGI on 160 MHz negotiated */ +#define IEEE80211_NODE_VHT_SGI80 0x80000 /* SGI on 80 MHz negotiated */ +#define IEEE80211_NODE_VHT_SGI160 0x100000 /* SGI on 160 MHz negotiated */ /* If not NULL, this function gets called when ni_refcnt hits zero. */ void (*ni_unref_cb)(struct ieee80211com *, @@ -484,7 +484,7 @@ ieee80211_unref_node(struct ieee80211_node **ni) *ni = NULL; /* guard against use */ } -/* +/* * Check if the peer supports HT. * Require a HT capabilities IE and at least one of the mandatory MCS. * MCS 0-7 are mandatory but some APs have particular MCS disabled. @@ -521,7 +521,7 @@ ieee80211_node_supports_ht_chan40(struct ieee80211_node *ni) (ni->ni_htop0 & IEEE80211_HTOP0_CHW)); } -/* +/* * Check if the peer supports VHT. * Require a VHT capabilities IE and support for VHT MCS with a single * spatial stream. @@ -565,8 +565,8 @@ ieee80211_node_supports_vht_chan80(struct ieee80211_node *ni) cap_chan_width = (ni->ni_vhtcaps & IEEE80211_VHTCAP_CHAN_WIDTH_MASK) >> IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT; - if (cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_80 && - cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_160 && + if (cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_80 && + cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_160 && cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_160_8080) return 0; @@ -644,8 +644,9 @@ int ieee80211_setup_vhtop(struct ieee80211_node *, const uint8_t *, uint8_t, int); int ieee80211_setup_rates(struct ieee80211com *, struct ieee80211_node *, const u_int8_t *, const u_int8_t *, int); +enum ieee80211_phymode ieee80211_node_abg_mode(struct ieee80211com *, + struct ieee80211_node *); void ieee80211_node_trigger_addba_req(struct ieee80211_node *, int); -int ieee80211_iserp_sta(const struct ieee80211_node *); void ieee80211_count_longslotsta(void *, struct ieee80211_node *); void ieee80211_count_nonerpsta(void *, struct ieee80211_node *); void ieee80211_count_pssta(void *, struct ieee80211_node *); @@ -655,6 +656,7 @@ void ieee80211_node_join(struct ieee80211com *, void ieee80211_node_leave(struct ieee80211com *, struct ieee80211_node *); int ieee80211_match_bss(struct ieee80211com *, struct ieee80211_node *, int); +void ieee80211_node_switch_bss(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_tx_stopped(struct ieee80211com *, struct ieee80211_node *); struct ieee80211_node *ieee80211_node_choose_bss(struct ieee80211com *, int, struct ieee80211_node **); diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_output.c b/src/libs/compat/openbsd_wlan/net80211/ieee80211_output.c index 1706beb255..434f403614 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_output.c +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_output.c,v 1.139 2024/05/08 14:02:59 stsp Exp $ */ +/* $OpenBSD: ieee80211_output.c,v 1.145 2026/01/05 13:41:03 stsp Exp $ */ /* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */ /*- @@ -210,7 +210,7 @@ ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni, IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); /* check if protection is required for this mgmt frame */ - if ((ic->ic_caps & IEEE80211_C_MFP) && + if ((ni->ni_flags & IEEE80211_NODE_MFP) && (type == IEEE80211_FC0_SUBTYPE_DISASSOC || type == IEEE80211_FC0_SUBTYPE_DEAUTH || type == IEEE80211_FC0_SUBTYPE_ACTION)) { @@ -418,6 +418,45 @@ ieee80211_up_to_ac(struct ieee80211com *ic, int up) return ac; } +enum ieee80211_edca_ac +ieee80211_classify_limit(struct ieee80211com *ic, enum ieee80211_edca_ac ac) +{ + const suseconds_t txop_interval = 100 * 1000; /* 100 msec, in usec */ + /* Maximum amounts of high-prio Tx opportunities, per 100ms. */ + static const int txop_limit[EDCA_NUM_AC] = { + 0, /* Best Effort */ + 0, /* Background */ + 4, /* Video */ + 2 /* Voice */ + }; + + if (txop_limit[ac] <= 0) /* not rate-limited */ + return ac; + + if (ic->ic_edca_txop_count[ac] < txop_limit[ac]) { + if (ic->ic_edca_txop_count[ac] == 0) + getmicrouptime(&ic->ic_edca_txop_time[ac]); + ic->ic_edca_txop_count[ac]++; + } else { + struct timeval now, delta; + + getmicrouptime(&now); + timersub(&now, &ic->ic_edca_txop_time[ac], &delta); + + /* + * Fall back on best-effort if the limit has been exceeded + * within the current rate-limiting window. + */ + if (delta.tv_sec == 0 && delta.tv_usec < txop_interval) + return EDCA_AC_BE; + + ic->ic_edca_txop_count[ac] = 1; + ic->ic_edca_txop_time[ac] = now; + } + + return ac; +} + /* * Get mbuf's user-priority: if mbuf is not VLAN tagged, select user-priority * based on the DSCP (Differentiated Services Codepoint) field. @@ -427,16 +466,28 @@ ieee80211_classify(struct ieee80211com *ic, struct mbuf *m) { struct ether_header eh; u_int8_t ds_field; + enum ieee80211_edca_ac ac; + + /* Map EDCA categories (0-3) to User Priority TIDs (0-7) */ + static const int edca_to_up[EDCA_NUM_AC] = { + 0, /* Best Effort */ + 1, /* Background */ + 5, /* Video (primary) */ + 6 /* Voice (primary) */ + }; + #if NVLAN > 0 - if (m->m_flags & M_VLANTAG) /* use VLAN 802.1D user-priority */ - return EVL_PRIOFTAG(m->m_pkthdr.ether_vtag); + if (m->m_flags & M_VLANTAG) { /* use VLAN 802.1D user-priority */ + ac = EVL_PRIOFTAG(m->m_pkthdr.ether_vtag); + return edca_to_up[ieee80211_classify_limit(ic, ac)]; + } #endif m_copydata(m, 0, sizeof(eh), (caddr_t)&eh); if (eh.ether_type == htons(ETHERTYPE_IP)) { struct ip ip; m_copydata(m, sizeof(eh), sizeof(ip), (caddr_t)&ip); if (ip.ip_v != 4) - return 0; + return edca_to_up[EDCA_AC_BE]; ds_field = ip.ip_tos; } #ifdef INET6 @@ -446,33 +497,46 @@ ieee80211_classify(struct ieee80211com *ic, struct mbuf *m) m_copydata(m, sizeof(eh), sizeof(ip6), (caddr_t)&ip6); flowlabel = ntohl(ip6.ip6_flow); if ((flowlabel >> 28) != 6) - return 0; + return edca_to_up[EDCA_AC_BE]; ds_field = (flowlabel >> 20) & 0xff; } #endif /* INET6 */ else /* neither IPv4 nor IPv6 */ - return 0; + return edca_to_up[EDCA_AC_BE]; /* - * Map Differentiated Services Codepoint field (see RFC2474). + * Map Differentiated Services Codepoint field (see RFC8325). * Preserves backward compatibility with IP Precedence field. */ switch (ds_field & 0xfc) { -#ifdef IPTOS_PREC_PRIORITY - case IPTOS_PREC_PRIORITY: - return EDCA_AC_VI; - case IPTOS_PREC_IMMEDIATE: - return EDCA_AC_BK; - case IPTOS_PREC_FLASH: - case IPTOS_PREC_FLASHOVERRIDE: - case IPTOS_PREC_CRITIC_ECP: - case IPTOS_PREC_INTERNETCONTROL: - case IPTOS_PREC_NETCONTROL: - return EDCA_AC_VO; +#ifdef IPTOS_DSCP_CS7 + case IPTOS_DSCP_CS7: + case IPTOS_DSCP_CS6: + case IPTOS_DSCP_EF: + case IPTOS_DSCP_VA: + ac = EDCA_AC_VO; + break; + case IPTOS_DSCP_CS5: + case IPTOS_DSCP_AF41: + case IPTOS_DSCP_AF42: + case IPTOS_DSCP_AF43: + case IPTOS_DSCP_CS4: + case IPTOS_DSCP_AF31: + case IPTOS_DSCP_AF32: + case IPTOS_DSCP_AF33: + case IPTOS_DSCP_CS3: + ac = EDCA_AC_VI; + break; + case IPTOS_DSCP_CS1: + ac = EDCA_AC_BK; + break; #endif default: - return EDCA_AC_BE; + /* unused, or explicitly mapped to UP 0 */ + return edca_to_up[EDCA_AC_BE]; } + + return edca_to_up[ieee80211_classify_limit(ic, ac)]; } int @@ -991,6 +1055,7 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic, const u_int8_t *oui = wpa ? MICROSOFT_OUI : IEEE80211_OUI; u_int8_t *pcount; u_int16_t count, rsncaps; + int pmf = 0; /* write Version field */ LE_WRITE_2(frm, 1); frm += 2; @@ -1065,10 +1130,22 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic, if (wpa) return frm; + if (ic->ic_caps & IEEE80211_C_MFP) { + /* + * When acting as client station, only announce PMF support + * to access points which support PMF. There are access points + * out there which do not support PMF and won't even initiate + * the 4-way handshake with us if the PMF-capable bit is set. + */ + if (ic->ic_opmode != IEEE80211_M_STA || + (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC)) + pmf = 1; + } + /* write RSN Capabilities field */ rsncaps = (ni->ni_rsncaps & (IEEE80211_RSNCAP_PTKSA_RCNT_MASK | IEEE80211_RSNCAP_GTKSA_RCNT_MASK)); - if (ic->ic_caps & IEEE80211_C_MFP) { + if (pmf) { rsncaps |= IEEE80211_RSNCAP_MFPC; if (ic->ic_flags & IEEE80211_F_MFPR) rsncaps |= IEEE80211_RSNCAP_MFPR; @@ -1085,7 +1162,7 @@ ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic, frm += IEEE80211_PMKID_LEN; } - if (!(ic->ic_caps & IEEE80211_C_MFP)) + if (!pmf) return frm; if ((ni->ni_flags & IEEE80211_NODE_PMKID) == 0) { @@ -1264,7 +1341,7 @@ struct mbuf * ieee80211_get_probe_req(struct ieee80211com *ic, struct ieee80211_node *ni) { const struct ieee80211_rateset *rs = - &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; + &ic->ic_sup_rates[ieee80211_node_abg_mode(ic, ni)]; struct mbuf *m; u_int8_t *frm; @@ -1634,53 +1711,6 @@ ieee80211_output_ba_move_window(struct ieee80211com *ic, ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff; } -/* - * Move Tx BA window forward up to the first hole in the bitmap - * or up to the specified SSN, whichever comes first. - * After calling this function, frames before the start of the - * potentially changed BA window should be discarded. - */ -void -ieee80211_output_ba_move_window_to_first_unacked(struct ieee80211com *ic, - struct ieee80211_node *ni, uint8_t tid, uint16_t ssn) -{ - struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; - uint16_t s = ba->ba_winstart; - uint64_t bitmap = ba->ba_bitmap; - int can_move_window = 0; - - while (bitmap && SEQ_LT(s, ssn)) { - if ((bitmap & 1) == 0) - break; - s = (s + 1) % 0xfff; - bitmap >>= 1; - can_move_window = 1; - } - - if (can_move_window) - ieee80211_output_ba_move_window(ic, ni, tid, s); -} - -/* Record an ACK for a frame with a given SSN within the Tx BA window. */ -void -ieee80211_output_ba_record_ack(struct ieee80211com *ic, - struct ieee80211_node *ni, uint8_t tid, uint16_t ssn) -{ - struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid]; - int i = 0; - uint16_t s = ba->ba_winstart; - - KASSERT(!SEQ_LT(ssn, ba->ba_winstart)); - KASSERT(!SEQ_LT(ba->ba_winend, ssn)); - - while (SEQ_LT(s, ssn)) { - s = (s + 1) % 0xfff; - i++; - } - if (i < ba->ba_winsize) - ba->ba_bitmap |= (1 << i); -} - /*- * ADDBA Response frame format: * [1] Category @@ -1823,7 +1853,7 @@ ieee80211_get_action(struct ieee80211com *ic, struct ieee80211_node *ni, /* * Send a management frame. The node is for the destination (or ic_bss * when in station mode). Nodes other than ic_bss have their reference - * count bumped to reflect our use for an indeterminant time. + * count bumped to reflect our use for an indeterminate time. */ int ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_pae_input.c b/src/libs/compat/openbsd_wlan/net80211/ieee80211_pae_input.c index daf550f591..d2148940ef 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_pae_input.c +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_pae_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_pae_input.c,v 1.37 2020/11/19 20:03:33 krw Exp $ */ +/* $OpenBSD: ieee80211_pae_input.c,v 1.38 2025/12/01 16:05:11 stsp Exp $ */ /*- * Copyright (c) 2007,2008 Damien Bergamini @@ -644,6 +644,8 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, /* install the IGTK */ switch ((*ic->ic_set_key)(ic, ni, k)) { case 0: + ni->ni_flags |= IEEE80211_NODE_TXMGMTPROT; + ic->ic_igtk_kid = kid; break; case EBUSY: deferlink = 1; @@ -652,6 +654,8 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic, reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } + + ni->ni_flags |= IEEE80211_NODE_RXMGMTPROT; } } if (info & EAPOL_KEY_INSTALL) @@ -932,12 +936,17 @@ ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic, /* install the IGTK */ switch ((*ic->ic_set_key)(ic, ni, k)) { case 0: + ni->ni_flags |= IEEE80211_NODE_TXMGMTPROT; + ic->ic_igtk_kid = kid; + break; case EBUSY: break; default: reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } + + ni->ni_flags |= IEEE80211_NODE_RXMGMTPROT; } } if (info & EAPOL_KEY_SECURE) { diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_proto.c b/src/libs/compat/openbsd_wlan/net80211/ieee80211_proto.c index b16fa51f61..bdccf1f60d 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_proto.c +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_proto.c,v 1.109 2024/02/08 00:05:46 jsg Exp $ */ +/* $OpenBSD: ieee80211_proto.c,v 1.111 2025/12/01 16:05:11 stsp Exp $ */ /* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */ /*- @@ -224,7 +224,7 @@ ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, error = 0; okrate = badrate = fixedrate = 0; - srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; + srs = &ic->ic_sup_rates[ieee80211_node_abg_mode(ic, ni)]; nrs = &ni->ni_rates; for (i = 0; i < nrs->rs_nrates; ) { ignore = 0; @@ -951,6 +951,8 @@ ieee80211_auth_open(struct ieee80211com *ic, const struct ieee80211_frame *wh, if (ic->ic_flags & IEEE80211_F_RSNON) { /* XXX not here! */ ic->ic_bss->ni_flags &= ~IEEE80211_NODE_TXRXPROT; + ic->ic_bss->ni_flags &= ~IEEE80211_NODE_RXMGMTPROT; + ic->ic_bss->ni_flags &= ~IEEE80211_NODE_TXMGMTPROT; ic->ic_bss->ni_port_valid = 0; ic->ic_bss->ni_replaycnt_ok = 0; (*ic->ic_delete_key)(ic, ic->ic_bss, @@ -1161,7 +1163,7 @@ justcleanup: IEEE80211_ADDR_COPY(ni->ni_macaddr, etherbroadcastaddr); IEEE80211_ADDR_COPY(ni->ni_bssid, etherbroadcastaddr); ni->ni_rates = ic->ic_sup_rates[ - ieee80211_chan2mode(ic, ni->ni_chan)]; + ieee80211_node_abg_mode(ic, ni)]; ni->ni_associd = 0; ni->ni_rstamp = 0; ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_proto.h b/src/libs/compat/openbsd_wlan/net80211/ieee80211_proto.h index 06978b0bab..a16fbd233d 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_proto.h +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_proto.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_proto.h,v 1.49 2024/05/29 00:48:15 jsg Exp $ */ +/* $OpenBSD: ieee80211_proto.h,v 1.50 2025/06/14 08:46:34 jsg Exp $ */ /* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */ /*- @@ -185,9 +185,5 @@ extern void ieee80211_addba_resp_refuse(struct ieee80211com *, struct ieee80211_node *, uint8_t, uint16_t); extern void ieee80211_output_ba_move_window(struct ieee80211com *, struct ieee80211_node *, uint8_t, uint16_t); -extern void ieee80211_output_ba_move_window_to_first_unacked( - struct ieee80211com *, struct ieee80211_node *, uint8_t, uint16_t); -extern void ieee80211_output_ba_record_ack(struct ieee80211com *, - struct ieee80211_node *, uint8_t, uint16_t); #endif /* _NET80211_IEEE80211_PROTO_H_ */ diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_var.h b/src/libs/compat/openbsd_wlan/net80211/ieee80211_var.h index cb79c423ce..56ebcb4fea 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_var.h +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_var.h,v 1.111 2022/03/14 15:07:24 stsp Exp $ */ +/* $OpenBSD: ieee80211_var.h,v 1.113 2026/01/05 12:04:45 stsp Exp $ */ /* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */ /*- @@ -46,7 +46,9 @@ #include #include #include /* for ieee80211_stats */ +#ifndef __cplusplus #include +#endif #include #define IEEE80211_CHAN_MAX 255 @@ -95,6 +97,10 @@ enum ieee80211_phymode { }; #define IEEE80211_MODE_MAX (IEEE80211_MODE_11AC+1) +#ifdef __cplusplus +#include +#endif + enum ieee80211_opmode { IEEE80211_M_STA = 1, /* infrastructure station */ #ifndef IEEE80211_STA_ONLY @@ -343,6 +349,8 @@ struct ieee80211com { */ struct ieee80211_edca_ac_params ic_edca_ac[EDCA_NUM_AC]; u_int ic_edca_updtcount; + u_int ic_edca_txop_count[EDCA_NUM_AC]; + struct timeval ic_edca_txop_time[EDCA_NUM_AC]; u_int16_t ic_tid_noack; u_int8_t ic_globalcnt[EAPOL_KEY_NONCE_LEN]; u_int8_t ic_nonce[EAPOL_KEY_NONCE_LEN]; @@ -502,10 +510,8 @@ int ieee80211_min_basic_rate(struct ieee80211com *); int ieee80211_max_basic_rate(struct ieee80211com *); int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); enum ieee80211_phymode ieee80211_next_mode(struct ifnet *); -enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *, - const struct ieee80211_channel *); -void ieee80211_disable_wep(struct ieee80211com *); -void ieee80211_disable_rsn(struct ieee80211com *); +void ieee80211_disable_wep(struct ieee80211com *); +void ieee80211_disable_rsn(struct ieee80211com *); int ieee80211_add_ess(struct ieee80211com *, struct ieee80211_join *); void ieee80211_del_ess(struct ieee80211com *, char *, int, int); void ieee80211_set_ess(struct ieee80211com *, struct ieee80211_ess *,