openbsd_wlan: Synchronize net80211, idualwifi7260, iaxwifi200 with upstream.
This commit is contained in:
@@ -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 <info@genua.de>
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 <[email protected]>
|
||||
@@ -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
|
||||
|
||||
@@ -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 <info@genua.de>
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <info@genua.de>
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <damien.bergamini@free.fr>
|
||||
@@ -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
|
||||
|
||||
@@ -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 <damien.bergamini@free.fr>
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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" */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 **);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 <damien.bergamini@free.fr>
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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 <net80211/ieee80211.h>
|
||||
#include <net80211/ieee80211_crypto.h>
|
||||
#include <net80211/ieee80211_ioctl.h> /* for ieee80211_stats */
|
||||
#ifndef __cplusplus
|
||||
#include <net80211/ieee80211_node.h>
|
||||
#endif
|
||||
#include <net80211/ieee80211_proto.h>
|
||||
|
||||
#define IEEE80211_CHAN_MAX 255
|
||||
@@ -95,6 +97,10 @@ enum ieee80211_phymode {
|
||||
};
|
||||
#define IEEE80211_MODE_MAX (IEEE80211_MODE_11AC+1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <net80211/ieee80211_node.h>
|
||||
#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 *,
|
||||
|
||||
Reference in New Issue
Block a user