Including fixes from Netfilter, Bluetooth, IPSec and WiFi.

Previous releases - regressions:
 
   - netfilter: hold reference on ct until flow is released
 
   - bridge:
     - move switchdev call outside rcu
     - vlan: fix bugs caused by switchdev deletion errors
 
   - wifi:
     - mac80211: reset state when starting AP fails
     - cfg80211: don't free driver-owned scan requests
 
   - tcp: don't call skb_clone_and_charge_r() for close()d listener in tcp_v6_do_rcv().
 
   - mptcp: return sk_wait_data() errors from recvmsg()
 
   - xfrm: serialize state GC with device state flush
 
   - drop_monitor: synchronize tracepoint unregistration on error path
 
   - bluetooth:
     - eir: validate service data length before reading UUID
     - hci_sync: serialize local codec list cleanup
     - RFCOMM: avoid socket lock inversion in listener cleanup
 
   - eth: lan743x: fix RX checksum use-after-free
 
   - eth: mvpp2: prevent buffer overflow in page_pool allocation
 
 Previous releases - always broken:
 
   - core: lock the socket in sock_gettstamp()
 
   - neighbour: enforce min/max to NDTPA_INTERVAL_PROBE_TIME_MS.
 
   - sched: codel: bound the dropping loop per dequeue call
 
   - wifi: mac80211: include TIM bitmap control for buffered S1G mcast traffic
 
   - psp: avoid conflicts with skb->decrypted and sk_validate_xmit_skb()
 
   - xfrm: fix stack OOB read in iptfs_skb_reset_frag_walk()
 
   - bluetooth: hci_qca: do not write to the serial port after it is closed
 
   - dsa: mxl862xx: disable the stats poll on teardown
 
   - eth: stmmac: fix TSO header length truncation
 
   - eth: ip_tunnel: initialize `options_len` before referencing options
 
 Signed-off-by: Paolo Abeni <pabeni@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEg1AjqC77wbdLX2LbKSR5jcyPE6QFAmqsEOsWHHBhb2xvLmFi
 ZW5pQGdtYWlsLmNvbQAKCRApJHmNzI8TpKMnD/4vxx/YloxnyDssUB95WcTfiHau
 XD+YDfTTf4Qy3DwKnMiesZ4w2547FXG+LwJZGpAGWpRSE99OawFHvx5gyn3Vf4IU
 HEsOuZEYMwhSeeMJxGdCg8K6McNEQx+aAD7D8gLoisnJr/DCKBJtxFgKVEjaKUfP
 aCG+FmbBqdS7hwBVbYREwmqwQSMnNzRWLd7/10/oYMcLfvgEsIkZisRErAW2BgZj
 mzGw/IcG+QRldDPGDwLwLzfEG9o1a2JctSRrQ3uLHZ3VOdmpnSkmf25s2IaEFAn6
 xfIhGPMgYIBDrakn/Ci4fAF0L98FtBq4Sa21HlvPMBst7rcce5x49ddSlIUWxRVZ
 Fbvs/0IMN0cEpYGbVJxE8iF3yo+t8XvsMdGS1JXd/ycaL9lpF+9gCzNvChSxba3N
 ik7BGAmlg76rqMuzeeMbWqMCmOcCBhQsb7iZXjNStJoiVY+UT2QfgvJ1TqF8Qrar
 Eu/xFkaqk8i/7jrx4ujceg9XpRt1Y3Y3Pq0sgdzlzTm162AV/kg1fvwHc6ORIML7
 71XpBSGvjyTHoh95ob/w3/5fec/ekzvWlCBL/cYIwBJ4R6n7Vk5e0Y1yZDffPSo3
 xQR0r4YdLewkjQdtnGEih6FSyWsu6nYpVSuwHbof1bQSzvlIM6TAabJmtJckFTld
 1bR2C9UVw5mQYMy8PA==
 =Gw4S
 -----END PGP SIGNATURE-----

Merge tag 'net-7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Pull networking fixes from Paolo Abeni:
 "Including fixes from Netfilter, Bluetooth, IPSec and WiFi.

  Previous releases - regressions:

   - netfilter: hold reference on ct until flow is released

   - bridge:
      - move switchdev call outside rcu
      - vlan: fix bugs caused by switchdev deletion errors

   - wifi:
      - mac80211: reset state when starting AP fails
      - cfg80211: don't free driver-owned scan requests

   - tcp: don't call skb_clone_and_charge_r() for close()d listener in
     tcp_v6_do_rcv()

   - mptcp: return sk_wait_data() errors from recvmsg()

   - xfrm: serialize state GC with device state flush

   - drop_monitor: synchronize tracepoint unregistration on error path

   - bluetooth:
      - eir: validate service data length before reading UUID
      - hci_sync: serialize local codec list cleanup
      - RFCOMM: avoid socket lock inversion in listener cleanup

   - eth:
      - lan743x: fix RX checksum use-after-free
      - mvpp2: prevent buffer overflow in page_pool allocation

  Previous releases - always broken:

   - core: lock the socket in sock_gettstamp()

   - neighbour: enforce min/max to NDTPA_INTERVAL_PROBE_TIME_MS.

   - sched: codel: bound the dropping loop per dequeue call

   - wifi: mac80211: include TIM bitmap control for buffered S1G mcast
     traffic

   - psp: avoid conflicts with skb->decrypted and sk_validate_xmit_skb()

   - xfrm: fix stack OOB read in iptfs_skb_reset_frag_walk()

   - bluetooth: hci_qca: do not write to the serial port after it is
     closed

   - dsa: mxl862xx: disable the stats poll on teardown

   - eth:
      - stmmac: fix TSO header length truncation
      - ip_tunnel: initialize `options_len` before referencing options"

* tag 'net-7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (159 commits)
  mptcp: fix bad accounting in __mptcp_subflow_push_pending()
  mptcp: close race between scheduler and state change
  mptcp: avoid unneeded actions on subflow reset
  net: skbuff: do not leave stale header offsets after pskb_carve()
  selftests: net: packetdrill: test exclusion of old ACK from TCP fast path
  tcp: exclude old ACKs from tcp fast path
  dpll: reject a reference sync pin which is not on the pin's dpll
  net: mvpp2: prevent buffer overflow in page_pool allocation
  net: macb: fix ordering around PTP timestamp read
  selftests: drv-net: psp: test PSP and TCP ULP mutual exclusion
  net: psp: avoid conflicts with skb->decrypted and sk_validate_xmit_skb()
  net: stmmac: preserve real_num_tx_queues on mqprio setup failure
  net: stmmac: propagate FPE preemption-class mapping errors
  net: wwan: t7xx: validate the netif index in t7xx_ccmni_recv_skb()
  net: wwan: mhi_wwan_mbim: check skb_copy_bits() return value
  net: wwan: mhi_wwan_mbim: guard against a cyclic NDP chain
  net: ethernet: cortina: Ack RX overrun interrupt correctly
  net: lock the socket in sock_gettstamp()
  eth: fbnic: ring the doorbell if a burst ends in a drop
  net: netsec: fix device_node reference leak on phy_np
  ...
This commit is contained in:
Linus Torvalds 2026-09-17 10:40:48 -07:00
commit b5a051f6b8
136 changed files with 2071 additions and 681 deletions

View File

@ -4,6 +4,8 @@ Alyssa Rosenzweig <alyssa@rosenzweig.io>
Askar Safin <safinaskar@gmail.com>
Christoph Hellwig <hch@lst.de>
Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Johannes Berg <johannes.berg@intel.com>
Johannes Berg <johannes@sipsolutions.net>
Marc Gonzalez <marc.w.gonzalez@free.fr>
Nathan Chancellor <nathan@kernel.org>
Ralf Baechle <ralf@linux-mips.org>

View File

@ -341,6 +341,9 @@ attribute-sets:
-
name: interval-probe-time-ms
type: u64
checks:
min: 1
max: 86400000
operations:
enum-model: directional

View File

@ -248,7 +248,7 @@ neigh/default/unres_qlen - INTEGER
neigh/default/interval_probe_time_ms - INTEGER
The probe interval for neighbor entries with NTF_MANAGED flag,
the min value is 1.
the min value is 1, and the max value is 86400000 (1 day).
Default: 5000
@ -874,6 +874,8 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max
case this value is ignored.
Default: between 131072 and 32MB, depending on RAM size.
Each of the three values cannot be set below 4096.
tcp_sack - BOOLEAN
Enable select acknowledgments (SACKS).

View File

@ -404,6 +404,12 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
if (tfd_index > txq->count)
return -ERANGE;
if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) {
bt_dev_err(hdev, "TX skb too large (%u > %u)", skb->len,
BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN);
return -EMSGSIZE;
}
/* Firmware raises alive interrupt on HCI_OP_RESET or
* BTINTEL_HCI_OP_RESET
*/
@ -502,7 +508,7 @@ static int btintel_pcie_submit_rx(struct btintel_pcie_data *data)
frbd_index = data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM];
if (frbd_index > rxq->count)
if (frbd_index >= rxq->count)
return -ERANGE;
/* Prepare for RX submit. It updates the FRBD with the address of DMA

View File

@ -721,7 +721,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
case BTMTK_WMT_FUNC_CTRL:
if (!skb_pull_data(data->evt_skb,
sizeof(wmt_evt_funcc->status))) {
status = BTMTK_WMT_ON_UNDONE;
/* A plain enable/disable request is acked with just
* the WMT header and no trailing status word; the
* result is carried in the header's own flag byte.
*/
status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE :
BTMTK_WMT_ON_DONE;
break;
}

View File

@ -217,7 +217,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
}
/* Parse and handle the return WMT event */
wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt));
if (!wmt_evt) {
bt_dev_err(hdev, "WMT event too short (%u bytes)",
bdev->evt_skb->len);
err = -EINVAL;
goto err_free_skb;
}
if (wmt_evt->whdr.op != hdr->op) {
bt_dev_err(hdev, "Wrong op received %d expected %d",
wmt_evt->whdr.op, hdr->op);
@ -233,6 +240,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
status = BTMTK_WMT_PATCH_DONE;
break;
case BTMTK_WMT_FUNC_CTRL:
if (!skb_pull_data(bdev->evt_skb,
sizeof(wmt_evt_funcc->status))) {
/* A plain enable/disable request is acked with just
* the WMT header and no trailing status word; the
* result is carried in the header's own flag byte.
*/
status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE :
BTMTK_WMT_ON_DONE;
break;
}
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
status = BTMTK_WMT_ON_DONE;
@ -1244,10 +1262,8 @@ static int btmtksdio_shutdown(struct hci_dev *hdev)
wmt_params.status = NULL;
err = mtk_hci_wmt_sync(hdev, &wmt_params);
if (err < 0) {
if (err < 0)
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
return err;
}
ignore_wmt_cmd:
pm_runtime_put_noidle(bdev->dev);

View File

@ -151,7 +151,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
}
/* Parse and handle the return WMT event */
wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt));
if (!wmt_evt) {
bt_dev_err(hdev, "WMT event too short (%u bytes)",
bdev->evt_skb->len);
err = -EINVAL;
goto err_free_wc;
}
if (wmt_evt->whdr.op != hdr->op) {
bt_dev_err(hdev, "Wrong op received %d expected %d",
wmt_evt->whdr.op, hdr->op);
@ -167,6 +174,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
status = BTMTK_WMT_PATCH_DONE;
break;
case BTMTK_WMT_FUNC_CTRL:
if (!skb_pull_data(bdev->evt_skb,
sizeof(wmt_evt_funcc->status))) {
/* A plain enable/disable request is acked with just
* the WMT header and no trailing status word; the
* result is carried in the header's own flag byte.
*/
status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE :
BTMTK_WMT_ON_DONE;
break;
}
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
status = BTMTK_WMT_ON_DONE;

View File

@ -71,6 +71,15 @@ static struct usb_driver btusb_driver;
#define BTUSB_BROKEN_EXT_SCAN BIT(29)
static const struct usb_device_id btusb_table[] = {
/*
* NXP IW610 (0471:0215): the composite device reports Bluetooth
* class at the whole-device level, so the generic entry below
* would also match this WiFi vendor interface. Ignore it here
* first so mwifiex-nxp can bind it instead.
*/
{ USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xff, 0xff, 0xff),
.driver_info = BTUSB_IGNORE },
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
@ -477,6 +486,14 @@ static const struct usb_device_id quirks_table[] = {
{ USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
{ USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL },
/*
* NXP IW610 BT interfaces (Marvell-lineage silicon, same quirk as
* the 0x1286 entries above). Scoped to the BT interface class,
* not just VID/PID -- see the btusb_table entry above.
*/
{ USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xe0, 0x01, 0x01),
.driver_info = BTUSB_MARVELL },
/* Intel Bluetooth devices */
{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED },
{ USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_COMBINED },

View File

@ -2228,8 +2228,8 @@ static void qca_power_off(struct hci_uart *hu)
bool sw_ctrl_state;
struct qca_power *power;
/* From this point we go into power off state. But serial port is
* still open, stop queueing the IBS data and flush all the buffered
/* From this point we go into power off state. But serial port may
* still be open, stop queueing the IBS data and flush all the buffered
* data in skb's.
*/
spin_lock_irqsave(&qca->hci_ibs_lock, flags);
@ -2251,8 +2251,14 @@ static void qca_power_off(struct hci_uart *hu)
case QCA_WCN3990:
case QCA_WCN3991:
case QCA_WCN3998:
host_set_baudrate(hu, 2400);
qca_send_power_pulse(hu, false);
/* Both of these write to the serial port which may have
* already been closed by hci_uart_close(), which closes
* the port if HCI_QUIRK_NON_PERSISTENT_SETUP is set.
*/
if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
host_set_baudrate(hu, 2400);
qca_send_power_pulse(hu, false);
}
break;
default:
break;

View File

@ -1202,6 +1202,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
const enum dpll_pin_state state,
struct netlink_ext_ack *extack)
{
void *pin_priv, *ref_sync_pin_priv;
const struct dpll_pin_ops *ops;
enum dpll_pin_state old_state;
struct dpll_pin *ref_sync_pin;
@ -1230,9 +1231,15 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
return -EOPNOTSUPP;
}
dpll = ref->dpll;
ret = ops->ref_sync_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
ref_sync_pin,
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
pin_priv = dpll_pin_on_dpll_priv(dpll, pin);
ref_sync_pin_priv = dpll_pin_on_dpll_priv(dpll, ref_sync_pin);
/* Pin may have been unregistered from this dpll already */
if (!ref_sync_pin_priv) {
NL_SET_ERR_MSG(extack,
"reference sync pin not registered with the dpll");
return -ENODEV;
}
ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin, ref_sync_pin_priv,
&old_state, extack);
if (ret) {
NL_SET_ERR_MSG(extack, "unable to get old reference sync state");
@ -1241,9 +1248,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
if (state == old_state)
return 0;
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
ref_sync_pin,
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
ret = ops->ref_sync_set(pin, pin_priv, ref_sync_pin, ref_sync_pin_priv,
state, extack);
if (ret) {
NL_SET_ERR_MSG_FMT(extack,

View File

@ -685,10 +685,22 @@ static int mxl862xx_setup(struct dsa_switch *ds)
if (ret)
return ret;
ret = mxl862xx_setup_mdio(ds);
if (ret)
return ret;
schedule_delayed_work(&priv->stats_work,
MXL862XX_STATS_POLL_INTERVAL);
return mxl862xx_setup_mdio(ds);
return 0;
}
static void mxl862xx_teardown(struct dsa_switch *ds)
{
struct mxl862xx_priv *priv = ds->priv;
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
disable_delayed_work_sync(&priv->stats_work);
}
static int mxl862xx_port_state(struct dsa_switch *ds, int port, bool enable)
@ -2047,9 +2059,7 @@ static void mxl862xx_get_stats64(struct dsa_switch *ds, int port,
spin_unlock_bh(&priv->ports[port].stats_lock);
/* Trigger a fresh poll so the next read sees up-to-date counters.
* No-op if the work is already pending, running, or teardown started.
*/
/* Trigger a fresh poll so the next read sees up-to-date counters. */
if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags))
schedule_delayed_work(&priv->stats_work, 0);
}
@ -2057,6 +2067,7 @@ static void mxl862xx_get_stats64(struct dsa_switch *ds, int port,
static const struct dsa_switch_ops mxl862xx_switch_ops = {
.get_tag_protocol = mxl862xx_get_tag_protocol,
.setup = mxl862xx_setup,
.teardown = mxl862xx_teardown,
.port_setup = mxl862xx_port_setup,
.port_teardown = mxl862xx_port_teardown,
.phylink_get_caps = mxl862xx_phylink_get_caps,
@ -2131,7 +2142,6 @@ static int mxl862xx_probe(struct mdio_device *mdiodev)
err = dsa_register_switch(ds);
if (err) {
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
cancel_delayed_work_sync(&priv->stats_work);
mxl862xx_host_shutdown(priv);
for (i = 0; i < MXL862XX_MAX_PORTS; i++)
cancel_work_sync(&priv->ports[i].host_flood_work);
@ -2152,7 +2162,6 @@ static void mxl862xx_remove(struct mdio_device *mdiodev)
priv = ds->priv;
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
cancel_delayed_work_sync(&priv->stats_work);
dsa_unregister_switch(ds);
@ -2181,7 +2190,7 @@ static void mxl862xx_shutdown(struct mdio_device *mdiodev)
dsa_switch_shutdown(ds);
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
cancel_delayed_work_sync(&priv->stats_work);
disable_delayed_work_sync(&priv->stats_work);
mxl862xx_host_shutdown(priv);

View File

@ -749,8 +749,17 @@ static void bcmgenet_hfb_init(struct bcmgenet_priv *priv)
INIT_LIST_HEAD(&priv->rxnfc_rules[i].list);
priv->rxnfc_rules[i].state = BCMGENET_RXNFC_STATE_UNUSED;
}
}
static void bcmgenet_hfb_restore(struct bcmgenet_priv *priv)
{
struct bcmgenet_rxnfc_rule *rule;
bcmgenet_hfb_clear(priv);
list_for_each_entry(rule, &priv->rxnfc_list, list)
if (rule->state != BCMGENET_RXNFC_STATE_UNUSED)
bcmgenet_hfb_create_rxnfc_filter(priv, rule);
}
static int bcmgenet_begin(struct net_device *dev)
@ -3376,8 +3385,8 @@ static int bcmgenet_open(struct net_device *dev)
bcmgenet_set_hw_addr(priv, dev->dev_addr);
/* HFB init */
bcmgenet_hfb_init(priv);
/* Restore the filters, the MAC was reset above */
bcmgenet_hfb_restore(priv);
/* Reinitialize TDMA and RDMA and SW housekeeping */
ret = bcmgenet_init_dma(priv, true);
@ -4075,6 +4084,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
/* Mii wait queue */
init_waitqueue_head(&priv->wq);
bcmgenet_hfb_init(priv);
INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task);
priv->clk_wol = devm_clk_get_optional(&priv->pdev->dev, "enet-wol");
@ -4272,10 +4282,7 @@ static int bcmgenet_resume(struct device *d)
bcmgenet_set_hw_addr(priv, dev->dev_addr);
/* Restore hardware filters */
bcmgenet_hfb_clear(priv);
list_for_each_entry(rule, &priv->rxnfc_list, list)
if (rule->state != BCMGENET_RXNFC_STATE_UNUSED)
bcmgenet_hfb_create_rxnfc_filter(priv, rule);
bcmgenet_hfb_restore(priv);
/* Reinitialize TDMA and RDMA and SW housekeeping */
ret = bcmgenet_init_dma(priv, false);

View File

@ -50,7 +50,12 @@ static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts,
spin_lock_irqsave(&bp->tsu_clk_lock, flags);
ptp_read_system_prets(sts);
/* explicit barriers are needed because gem_readl() is relaxed */
if (sts)
rmb();
first = gem_readl(bp, TN);
if (sts)
rmb();
ptp_read_system_postts(sts);
secl = gem_readl(bp, TSL);
sech = gem_readl(bp, TSH);
@ -62,7 +67,11 @@ static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts,
* (assume all done within 1s)
*/
ptp_read_system_prets(sts);
if (sts)
rmb();
ts->tv_nsec = gem_readl(bp, TN);
if (sts)
rmb();
ptp_read_system_postts(sts);
secl = gem_readl(bp, TSL);
sech = gem_readl(bp, TSH);

View File

@ -1798,7 +1798,7 @@ static irqreturn_t gmac_irq(int irq, void *data)
if (val & (GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8))) {
spin_lock(&geth->irq_lock);
writel(GMAC0_RXDERR_INT_BIT << (netdev->dev_id * 8),
writel(GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8),
geth->base + GLOBAL_INTERRUPT_STATUS_4_REG);
u64_stats_update_begin(&port->ir_stats_syncp);
++port->stats.rx_fifo_errors;

View File

@ -5086,7 +5086,8 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu)
netdev_warn(dev, "mtu %d too high, switching to shared buffers", mtu);
mvpp2_bm_switch_buffers(priv, false);
}
} else {
} else if (priv->hw_version >= MVPP22 &&
mvpp2_get_nrxqs(priv) * 2 <= MVPP2_BM_MAX_POOLS) {
bool jumbo = false;
int i;

View File

@ -311,6 +311,29 @@ fbnic_rx_csum(u64 rcd, struct sk_buff *skb, struct fbnic_ring *rcq,
}
}
static void fbnic_tx_doorbell(struct fbnic_ring *ring, __le64 *meta)
{
*meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_COMPLETION);
ring->deferred_meta = -1;
/* Force DMA writes to flush before writing to tail */
dma_wmb();
writel(ring->tail, ring->doorbell);
}
/* Packets handed to us with xmit_more set are left in the ring without a
* doorbell, and without a completion request, in the expectation that the
* packet ending the burst will ring for all of them. If that packet gets
* dropped instead we have to ring here, otherwise the descriptors sit in
* the ring until the next transmit, which may never come.
*/
static void fbnic_tx_flush_doorbell(struct fbnic_ring *ring)
{
if (ring->deferred_meta >= 0)
fbnic_tx_doorbell(ring, &ring->desc[ring->deferred_meta]);
}
static bool
fbnic_tx_map(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
{
@ -378,14 +401,10 @@ fbnic_tx_map(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
/* Verify there is room for another packet */
fbnic_maybe_stop_tx(skb->dev, ring, FBNIC_MAX_SKB_DESC);
if (fbnic_tx_sent_queue(skb, ring)) {
*meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_COMPLETION);
/* Force DMA writes to flush before writing to tail */
dma_wmb();
writel(tail, ring->doorbell);
}
if (fbnic_tx_sent_queue(skb, ring))
fbnic_tx_doorbell(ring, meta);
else
ring->deferred_meta = meta - ring->desc;
return false;
dma_error:
@ -425,8 +444,10 @@ fbnic_xmit_frame_ring(struct sk_buff *skb, struct fbnic_ring *ring)
* otherwise try next time
*/
desc_needed = skb_shinfo(skb)->nr_frags + 10;
if (fbnic_maybe_stop_tx(skb->dev, ring, desc_needed))
if (fbnic_maybe_stop_tx(skb->dev, ring, desc_needed)) {
fbnic_tx_flush_doorbell(ring);
return NETDEV_TX_BUSY;
}
*meta = cpu_to_le64(FBNIC_TWD_FLAG_DEST_MAC);
@ -447,6 +468,8 @@ fbnic_xmit_frame_ring(struct sk_buff *skb, struct fbnic_ring *ring)
err_free:
dev_kfree_skb_any(skb);
err_count:
fbnic_tx_flush_doorbell(ring);
u64_stats_update_begin(&ring->stats.syncp);
ring->stats.dropped++;
u64_stats_update_end(&ring->stats.syncp);
@ -2491,6 +2514,7 @@ static void fbnic_enable_twq0(struct fbnic_ring *twq)
fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ0_CTL, FBNIC_QUEUE_TWQ_CTL_RESET);
twq->tail = 0;
twq->head = 0;
twq->deferred_meta = -1;
/* Store descriptor ring address and size */
fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ0_BAL, lower_32_bits(twq->dma));

View File

@ -128,9 +128,14 @@ struct fbnic_ring {
/* Rx BDQs only */
struct page_pool *page_pool;
/* Deferred_head is used to cache the head for TWQ1 if
/* TWQ0 only, index of the meta descriptor of the last packet
* placed in the ring without ringing the doorbell, -1 if the
* doorbell is in sync with the tail.
*/
s32 deferred_meta;
/* TCQ only, used to cache the head for TWQ1 if
* an attempt is made to clean TWQ1 with zero napi_budget.
* We do not use it for any other ring.
*/
s32 deferred_head;
};

View File

@ -2604,7 +2604,7 @@ static int lan743x_rx_process_buffer(struct lan743x_rx *rx)
rx->adapter->netdev);
if (rx->adapter->netdev->features & NETIF_F_RXCSUM) {
if (!is_ice && !is_tce && !is_icsm)
skb->ip_summed = CHECKSUM_UNNECESSARY;
rx->skb_head->ip_summed = CHECKSUM_UNNECESSARY;
}
netdev_dbg(netdev, "sending %d byte frame to OS",
rx->skb_head->len);

View File

@ -2149,6 +2149,7 @@ static int netsec_probe(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
free_ndev:
of_node_put(priv->phy_np);
free_netdev(ndev);
dev_err(&pdev->dev, "init failed\n");
@ -2166,6 +2167,7 @@ static void netsec_remove(struct platform_device *pdev)
netif_napi_del(&priv->napi);
pm_runtime_disable(&pdev->dev);
of_node_put(priv->phy_np);
free_netdev(priv->ndev);
}

View File

@ -494,7 +494,7 @@ struct stmmac_ops {
#define stmmac_set_arp_offload(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, set_arp_offload, __args)
#define stmmac_fpe_map_preemption_class(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args)
stmmac_do_callback(__priv, mac, fpe_map_preemption_class, __args)
/* PTP and HW Timer helpers */
struct stmmac_hwtimestamp {

View File

@ -1016,8 +1016,6 @@ static int stmmac_get_ts_info(struct net_device *dev,
if (priv->ptp_clock)
info->phc_index = ptp_clock_index(priv->ptp_clock);
else
info->phc_index = 0;
info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);

View File

@ -4513,16 +4513,16 @@ static int stmmac_tso_get_num_desc(struct stmmac_tx_queue *tx_q,
*/
static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned int first_entry, entry, tx_packets, proto_hdr_len;
struct dma_desc *desc, *first, *mss_desc = NULL;
struct stmmac_priv *priv = netdev_priv(dev);
unsigned int first_entry, entry, tx_packets;
struct stmmac_txq_stats *txq_stats;
int i, first_tx, nfrags, ndesc;
struct stmmac_tx_queue *tx_q;
bool set_ic, is_last_segment;
u32 pay_len, mss, queue;
u8 proto_hdr_len, hdr;
dma_addr_t des;
u8 hdr;
nfrags = skb_shinfo(skb)->nr_frags;
queue = skb_get_queue_mapping(skb);
@ -4570,7 +4570,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (netif_msg_tx_queued(priv)) {
pr_info("%s: hdrlen %d, hdr_len %d, pay_len %d, mss %d\n",
pr_info("%s: hdrlen %d, hdr_len %u, pay_len %d, mss %d\n",
__func__, hdr, proto_hdr_len, pay_len, mss);
pr_info("\tskb->len %d, skb->data_len %d\n", skb->len,
skb->data_len);

View File

@ -970,7 +970,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
struct netlink_ext_ack *extack = qopt->mqprio.extack;
struct timespec64 time, current_time, qopt_time;
ktime_t current_time_ns;
int i, ret = 0;
int err, i, ret = 0;
u64 ctr;
if (qopt->base_time < 0)
@ -1120,9 +1120,9 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
mutex_unlock(&priv->est_lock);
}
stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0);
err = stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0);
return ret;
return qopt->cmd == TAPRIO_CMD_DESTROY ? err : ret;
}
static void tc_taprio_stats(struct stmmac_priv *priv,
@ -1237,58 +1237,99 @@ static int tc_query_caps(struct stmmac_priv *priv,
}
}
static void stmmac_reset_tc_mqprio(struct net_device *ndev,
struct netlink_ext_ack *extack)
static int stmmac_set_ndev_tcs(struct net_device *ndev, u8 ntc,
struct netdev_tc_txq *tc_to_txq)
{
int i, err;
netdev_reset_tc(ndev);
if (!ntc)
return 0;
err = netdev_set_num_tc(ndev, ntc);
if (err)
return err;
for (i = 0; i < ntc; i++) {
u16 count, offset;
count = tc_to_txq[i].count;
offset = tc_to_txq[i].offset;
netdev_set_tc_queue(ndev, i, count, offset);
}
return 0;
}
static int stmmac_reset_tc_mqprio(struct net_device *ndev,
struct netlink_ext_ack *extack)
{
struct stmmac_priv *priv = netdev_priv(ndev);
netdev_reset_tc(ndev);
netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use);
stmmac_fpe_map_preemption_class(priv, ndev, extack, 0);
return stmmac_fpe_map_preemption_class(priv, ndev, extack, 0);
}
static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
struct tc_mqprio_qopt_offload *mqprio)
{
unsigned int ndev_num_tx_queues, num_tx_queues = 0;
struct netdev_tc_txq ndev_tc_to_txq[TC_MAX_QUEUE];
struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE] = {};
struct netlink_ext_ack *extack = mqprio->extack;
struct tc_mqprio_qopt *qopt = &mqprio->qopt;
u32 offset, count, num_stack_tx_queues = 0;
struct net_device *ndev = priv->dev;
u32 num_tc = qopt->num_tc;
int err;
u8 ndev_prio_tc_map[TC_BITMASK + 1];
int i, err, ndev_ntc;
if (!num_tc) {
stmmac_reset_tc_mqprio(ndev, extack);
return 0;
if (!qopt->num_tc)
return stmmac_reset_tc_mqprio(ndev, extack);
if (qopt->num_tc > ARRAY_SIZE(tc_to_txq))
return -EINVAL;
/* save current tc values for reset */
ndev_ntc = netdev_get_num_tc(ndev);
for (i = 0; i < ARRAY_SIZE(ndev->tc_to_txq); i++)
ndev_tc_to_txq[i].combined =
READ_ONCE(ndev->tc_to_txq[i].combined);
for (i = 0; i < ARRAY_SIZE(ndev_prio_tc_map); i++)
ndev_prio_tc_map[i] = READ_ONCE(ndev->prio_tc_map[i]);
for (i = 0; i < qopt->num_tc; i++) {
tc_to_txq[i] = (struct netdev_tc_txq) {
.count = qopt->count[i],
.offset = qopt->offset[i],
};
num_tx_queues += qopt->count[i];
}
err = netdev_set_num_tc(ndev, num_tc);
err = stmmac_set_ndev_tcs(ndev, qopt->num_tc, tc_to_txq);
if (err)
return err;
goto error_reset_tc;
for (u32 tc = 0; tc < num_tc; tc++) {
offset = qopt->offset[tc];
count = qopt->count[tc];
num_stack_tx_queues += count;
err = netdev_set_tc_queue(ndev, tc, count, offset);
if (err)
goto err_reset_tc;
}
err = netif_set_real_num_tx_queues(ndev, num_stack_tx_queues);
ndev_num_tx_queues = ndev->real_num_tx_queues;
err = netif_set_real_num_tx_queues(ndev, num_tx_queues);
if (err)
goto err_reset_tc;
goto error_reset_tc;
err = stmmac_fpe_map_preemption_class(priv, ndev, extack,
mqprio->preemptible_tcs);
if (err)
goto err_reset_tc;
goto error_reset_num_tx_queues;
return 0;
err_reset_tc:
stmmac_reset_tc_mqprio(ndev, extack);
error_reset_num_tx_queues:
if (netif_set_real_num_tx_queues(ndev, ndev_num_tx_queues))
netdev_warn(ndev, "Failed to restore %u TX queues\n",
ndev_num_tx_queues);
error_reset_tc:
stmmac_set_ndev_tcs(ndev, ndev_ntc, ndev_tc_to_txq);
for (i = 0; i < ARRAY_SIZE(ndev_prio_tc_map); i++)
netdev_set_prio_tc_map(ndev, i, ndev_prio_tc_map[i]);
return err;
}

View File

@ -928,7 +928,8 @@ static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr)
dev_addr_set(dev, p_sockaddr->sa_data);
spin_lock_irqsave(&bp->DriverLock, Flags);
ResetAdapter(smc);
if (netif_running(dev))
ResetAdapter(smc);
spin_unlock_irqrestore(&bp->DriverLock, Flags);
return 0; /* always return zero */

View File

@ -156,20 +156,27 @@ int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
if (!rules)
return 0;
if (on & on_set)
/* TRIGGER_NETDEV_LINK must not be reported together with any of the
* per-speed rules, the netdev trigger rejects that combination.
* on_set holds every speed this LED can indicate and is what
* mtk_phy_led_hw_ctrl_set() programs for TRIGGER_NETDEV_LINK, so
* report the speed independent rule only when they are all on.
*/
if ((on & on_set) == on_set) {
*rules |= BIT(TRIGGER_NETDEV_LINK);
} else {
if (on & MTK_PHY_LED_ON_LINK10)
*rules |= BIT(TRIGGER_NETDEV_LINK_10);
if (on & MTK_PHY_LED_ON_LINK10)
*rules |= BIT(TRIGGER_NETDEV_LINK_10);
if (on & MTK_PHY_LED_ON_LINK100)
*rules |= BIT(TRIGGER_NETDEV_LINK_100);
if (on & MTK_PHY_LED_ON_LINK100)
*rules |= BIT(TRIGGER_NETDEV_LINK_100);
if (on & MTK_PHY_LED_ON_LINK1000)
*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
if (on & MTK_PHY_LED_ON_LINK1000)
*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
if (on & MTK_PHY_LED_ON_LINK2500)
*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
if (on & MTK_PHY_LED_ON_LINK2500)
*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
}
if (on & MTK_PHY_LED_ON_FDX)
*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);

View File

@ -873,6 +873,22 @@ static int ath11k_mac_set_kickout(struct ath11k_vif *arvif)
return 0;
}
static void ath11k_mac_station_cleanup(struct ieee80211_sta *sta)
{
struct ath11k_sta *arsta;
if (!sta)
return;
arsta = ath11k_sta_to_arsta(sta);
kfree(arsta->tx_stats);
arsta->tx_stats = NULL;
kfree(arsta->rx_stats);
arsta->rx_stats = NULL;
}
void ath11k_mac_peer_cleanup_all(struct ath11k *ar)
{
struct ath11k_peer *peer, *tmp;
@ -885,6 +901,7 @@ void ath11k_mac_peer_cleanup_all(struct ath11k *ar)
list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
ath11k_peer_rx_tid_cleanup(ar, peer);
ath11k_peer_rhash_delete(ab, peer);
ath11k_mac_station_cleanup(peer->sta);
list_del(&peer->list);
kfree(peer);
}
@ -9892,7 +9909,6 @@ static int ath11k_mac_station_remove(struct ath11k *ar,
{
struct ath11k_base *ab = ar->ab;
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
int ret;
if (ab->hw_params.vdev_start_delay &&
@ -9916,12 +9932,7 @@ static int ath11k_mac_station_remove(struct ath11k *ar,
sta->addr, arvif->vdev_id);
ath11k_mac_dec_num_stations(arvif, sta);
kfree(arsta->tx_stats);
arsta->tx_stats = NULL;
kfree(arsta->rx_stats);
arsta->rx_stats = NULL;
ath11k_mac_station_cleanup(sta);
return ret;
}

View File

@ -15,21 +15,6 @@
#include "dp.h"
#include "core.h"
/*
* Node name to UserPD ID mapping
*
* The io_start field is used for additional validation when the reg
* property is present in the device tree. If io_start is 0, only
* node_name matching is performed.
*
* For platforms where not all WiFi nodes have a 'reg' property, set
* io_start to 0 for those entries. The driver will match purely by
* node name in such cases.
*/
static const struct ath12k_ahb_userpd_map ath12k_wifi7_ahb_userpd_map[] = {
{ .io_start = 0x0c000000, .node_name = "wifi", .upd_id = ATH12K_AHB_USERPD_ID_0 },
};
static const struct ath12k_ahb_desc ath12k_wifi7_ahb_desc[] = {
[ATH12K_HW_IPQ5332_HW10] = {
.hw_rev = ATH12K_HW_IPQ5332_HW10,
@ -55,40 +40,6 @@ static const struct of_device_id ath12k_wifi7_ahb_of_match[] = {
MODULE_DEVICE_TABLE(of, ath12k_wifi7_ahb_of_match);
/*
* ath12k_wifi7_ahb_get_userpd_id - Resolve UserPD ID from DT properties
* @ab: ath12k base structure
*
* Returns: UserPD ID (1-based) on success, 0 on failure
*
* Resolution logic:
* 1. If reg property exist in DT, get userpd_id from io_start
* 2. If reg property is absent, get userpd_id from DT node name
* 3. Return 0 if no match found (probe will fail)
*/
static u32 ath12k_wifi7_ahb_get_userpd_id(struct ath12k_base *ab)
{
const struct ath12k_ahb_userpd_map *map;
struct resource *res;
size_t i;
res = platform_get_resource(ab->pdev, IORESOURCE_MEM, 0);
for (i = 0; i < ARRAY_SIZE(ath12k_wifi7_ahb_userpd_map); i++) {
map = &ath12k_wifi7_ahb_userpd_map[i];
if (res) {
if (map->io_start && map->io_start == res->start)
return map->upd_id;
} else if (map->node_name &&
of_node_name_eq(ab->dev->of_node, map->node_name)) {
return map->upd_id;
}
}
return 0;
}
static int ath12k_wifi7_ahb_probe(struct platform_device *pdev)
{
const struct ath12k_ahb_desc *desc;
@ -106,7 +57,7 @@ static int ath12k_wifi7_ahb_probe(struct platform_device *pdev)
ab->hw_rev = desc->hw_rev;
ab->hif.ops = desc->ops;
ab_ahb->scm_auth_enabled = desc->auth_enabled;
ab_ahb->userpd_id = ath12k_wifi7_ahb_get_userpd_id(ab);
ab_ahb->userpd_id = ATH12K_AHB_USERPD_ID_0;
if (!ab_ahb->userpd_id)
return -EOPNOTSUPP;

View File

@ -1055,7 +1055,7 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn)
free_irq(wcn->tx_irq, wcn);
free_irq(wcn->rx_irq, wcn);
timer_delete(&wcn->tx_ack_timer);
timer_shutdown_sync(&wcn->tx_ack_timer);
if (wcn->tx_ack_skb) {
ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb);

View File

@ -555,6 +555,8 @@ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
if (type == ETH_P_PAE) {
atomic_dec(&ifp->pend_8021x_cnt);
/* Order the decrement before waitqueue_active() */
smp_mb__after_atomic();
if (waitqueue_active(&ifp->pend_8021x_wait))
wake_up(&ifp->pend_8021x_wait);
}

View File

@ -198,7 +198,7 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev,
{
struct brcmf_if *ifp;
struct brcmf_pub *drvr;
struct brcmf_auth_req_status_le auth_status;
struct brcmf_auth_req_status_le auth_status = {};
int ret = 0;
brcmf_dbg(TRACE, "Enter\n");
@ -206,6 +206,9 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev,
ifp = netdev_priv(dev);
drvr = ifp->drvr;
if (params->status == WLAN_STATUS_SUCCESS) {
if (params->pmkid)
memcpy(auth_status.pmkid, params->pmkid,
WLAN_PMKID_LEN);
auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS);
} else {
bphy_err(drvr, "External authentication failed: status=%d\n",

View File

@ -1571,6 +1571,10 @@ void brcms_free_timer(struct brcms_timer *t)
/* delete the timer in case it is active */
brcms_del_timer(t);
/* Ensure the callback has finished before freeing the timer
* structure, since brcms_del_timer() uses non-synchronous cancel.
*/
cancel_delayed_work_sync(&t->dly_wrk);
if (wl->timers == t) {
wl->timers = wl->timers->next;

View File

@ -2712,7 +2712,9 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
break;
}
#endif
if (stats.len < sizeof(struct libipw_hdr_3addr))
if (sq->drv[i].frame_size <
sizeof(struct libipw_hdr_3addr) ||
sq->drv[i].frame_size > IPW_RX_NIC_BUFFER_LENGTH)
break;
switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
case IEEE80211_FTYPE_MGMT:

View File

@ -8322,6 +8322,15 @@ static void ipw_rx(struct ipw_priv *priv)
break;
}
if (unlikely(le16_to_cpu(pkt->u.frame.length) >
IPW_RX_BUF_SIZE -
IPW_RX_FRAME_SIZE)) {
IPW_DEBUG_DROP("Received oversized packet. Dropping.\n");
priv->net_dev->stats.rx_errors++;
priv->wstats.discard.misc++;
break;
}
switch (WLAN_FC_GET_TYPE
(le16_to_cpu(header->frame_ctl))) {

View File

@ -474,14 +474,16 @@ static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx,
int hdr_len, void *priv)
{
struct libipw_tkip_data *tkey = priv;
u8 mic[8];
u8 mic[MICHAEL_MIC_LEN];
if (!tkey->key_set)
if (!tkey->key_set || skb->len < hdr_len + MICHAEL_MIC_LEN)
return -1;
michael_mic(&tkey->key[24], (struct ieee80211_hdr *)skb->data,
skb->data + hdr_len, skb->len - 8 - hdr_len, mic);
if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
skb->data + hdr_len,
skb->len - MICHAEL_MIC_LEN - hdr_len, mic);
if (memcmp(mic, skb->data + skb->len - MICHAEL_MIC_LEN,
MICHAEL_MIC_LEN) != 0) {
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *)skb->data;
printk(KERN_DEBUG "%s: Michael MIC verification failed for "
@ -499,7 +501,7 @@ static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx,
tkey->rx_iv32 = tkey->rx_iv32_new;
tkey->rx_iv16 = tkey->rx_iv16_new;
skb_trim(skb, skb->len - 8);
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
return 0;
}

View File

@ -1209,6 +1209,9 @@ static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_as
struct libipw_network *network = &network_resp;
struct net_device *dev = ieee->dev;
if (stats->len < sizeof(*frame))
return 1;
network->flags = 0;
network->qos_data.active = 0;
network->qos_data.supported = 0;
@ -1421,6 +1424,9 @@ static void libipw_process_probe_response(struct libipw_device
#endif
unsigned long flags;
if (stats->len < sizeof(*beacon))
return;
LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
info_element->len, info_element->data,
beacon->header.addr3,

View File

@ -2326,7 +2326,7 @@ il_dealloc_bcast_stations(struct il_priv *il)
if (!(il->stations[i].used & IL_STA_BCAST))
continue;
il->stations[i].used &= ~IL_STA_UCODE_ACTIVE;
il->stations[i].used = 0;
il->num_stations--;
if (WARN_ON(il->num_stations < 0))
il->num_stations = 0;

View File

@ -414,17 +414,22 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
}
static int p54_convert_rev0(struct ieee80211_hw *dev,
struct pda_pa_curve_data *curve_data)
struct pda_pa_curve_data *curve_data, size_t len)
{
struct p54_common *priv = dev->priv;
struct p54_pa_curve_data_sample *dst;
struct pda_pa_curve_data_sample_rev0 *src;
size_t needed = curve_data->channels *
(sizeof(*src) * curve_data->points_per_channel + 2);
size_t cd_len = sizeof(*curve_data) +
(curve_data->points_per_channel*sizeof(*dst) + 2) *
curve_data->channels;
unsigned int i, j;
void *source, *target;
if (len < sizeof(*curve_data) + needed)
return -EINVAL;
priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
GFP_KERNEL);
if (!priv->curve_data)
@ -466,17 +471,22 @@ static int p54_convert_rev0(struct ieee80211_hw *dev,
}
static int p54_convert_rev1(struct ieee80211_hw *dev,
struct pda_pa_curve_data *curve_data)
struct pda_pa_curve_data *curve_data, size_t len)
{
struct p54_common *priv = dev->priv;
struct p54_pa_curve_data_sample *dst;
struct pda_pa_curve_data_sample_rev1 *src;
size_t needed = curve_data->channels *
(sizeof(*src) * curve_data->points_per_channel + 3);
size_t cd_len = sizeof(*curve_data) +
(curve_data->points_per_channel*sizeof(*dst) + 2) *
curve_data->channels;
unsigned int i, j;
void *source, *target;
if (len < sizeof(*curve_data) + needed)
return -EINVAL;
priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
GFP_KERNEL);
if (!priv->curve_data)
@ -763,6 +773,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
case PDR_PRISM_PA_CAL_CURVE_DATA: {
struct pda_pa_curve_data *curve_data =
(struct pda_pa_curve_data *)entry->data;
if (data_len < sizeof(*curve_data)) {
err = -EINVAL;
goto err;
@ -770,10 +781,10 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
switch (curve_data->cal_method_rev) {
case 0:
err = p54_convert_rev0(dev, curve_data);
err = p54_convert_rev0(dev, curve_data, data_len);
break;
case 1:
err = p54_convert_rev1(dev, curve_data);
err = p54_convert_rev1(dev, curve_data, data_len);
break;
default:
wiphy_err(dev->wiphy,
@ -801,7 +812,8 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
break;
case PDR_INTERFACE_LIST:
tmp = entry->data;
while ((u8 *)tmp < entry->data + data_len) {
while ((u8 *)tmp + sizeof(struct exp_if) <=
entry->data + data_len) {
struct exp_if *exp_if = tmp;
if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
synth = le16_to_cpu(exp_if->variant);

View File

@ -173,8 +173,8 @@ static int lbtf_init_adapter(struct lbtf_private *priv)
static void lbtf_free_adapter(struct lbtf_private *priv)
{
lbtf_deb_enter(LBTF_DEB_MAIN);
lbtf_free_cmd_buffer(priv);
timer_delete_sync(&priv->command_timer);
lbtf_free_cmd_buffer(priv);
lbtf_deb_leave(LBTF_DEB_MAIN);
}

View File

@ -4277,6 +4277,7 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy,
struct mwifiex_adapter *adapter = priv->adapter;
struct sk_buff *skb;
u16 pkt_len, auth_alg;
size_t frame_len;
int ret;
struct mwifiex_ieee80211_mgmt *mgmt;
struct mwifiex_txinfo *tx_info;
@ -4349,10 +4350,17 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy,
mwifiex_cancel_scan(adapter);
pkt_len = (u16)req->ie_len + req->auth_data_len +
frame_len = req->ie_len + req->auth_data_len +
MWIFIEX_MGMT_HEADER_LEN + MWIFIEX_AUTH_BODY_LEN;
if (req->auth_data_len >= 4)
pkt_len -= 4;
frame_len -= 4;
if (frame_len > U16_MAX) {
mwifiex_dbg(priv->adapter, ERROR,
"auth frame too long: %zu bytes\n", frame_len);
return -EINVAL;
}
pkt_len = frame_len;
skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN +
MWIFIEX_MGMT_FRAME_HEADER_SIZE +

View File

@ -3068,7 +3068,7 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
ret);
for (j = 0; j < i; j++)
free_irq(card->msix_entries[j].vector,
&card->msix_ctx[i]);
&card->msix_ctx[j]);
pci_disable_msix(pdev);
} else {
mwifiex_dbg(adapter, MSG, "MSIx enabled!");

View File

@ -104,12 +104,24 @@ has_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key)
* a given oui in PTK.
*/
static u8
mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui, int ie_len)
{
const size_t ptk_body_offset = offsetof(struct ie_body, ptk_body);
u8 count;
/* ie_len is the number of bytes available at iebody. Keep it signed
* and reject a negative (underflowed) length before the unsigned
* comparisons below, so a small or zero IE length cannot wrap.
*/
if (ie_len < 0 || (size_t)ie_len < ptk_body_offset)
return MWIFIEX_OUI_NOT_PRESENT;
count = iebody->ptk_cnt[0];
/* Reject an OUI count whose list would run past the element. */
if (ptk_body_offset + count * sizeof(iebody->ptk_body) > (size_t)ie_len)
return MWIFIEX_OUI_NOT_PRESENT;
/* There could be multiple OUIs for PTK hence
1) Take the length.
2) Check all the OUIs for AES.
@ -143,11 +155,14 @@ mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
u8 ret = MWIFIEX_OUI_NOT_PRESENT;
if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) {
int ie_len = (int)bss_desc->bcn_rsn_ie->ieee_hdr.len -
RSN_GTK_OUI_OFFSET;
iebody = (struct ie_body *)
(((u8 *) bss_desc->bcn_rsn_ie->data) +
RSN_GTK_OUI_OFFSET);
oui = &mwifiex_rsn_oui[cipher][0];
ret = mwifiex_search_oui_in_ie(iebody, oui);
ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len);
if (ret)
return ret;
}
@ -169,10 +184,14 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
u8 ret = MWIFIEX_OUI_NOT_PRESENT;
if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) {
int ie_len = (int)bss_desc->bcn_wpa_ie->vend_hdr.len -
(int)sizeof(bss_desc->bcn_wpa_ie->vend_hdr.oui) -
WPA_GTK_OUI_OFFSET;
iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data +
WPA_GTK_OUI_OFFSET);
oui = &mwifiex_wpa_oui[cipher][0];
ret = mwifiex_search_oui_in_ie(iebody, oui);
ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len);
if (ret)
return ret;
}
@ -2096,6 +2115,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
u32 bytes_left;
u32 idx;
u32 tlv_buf_size;
size_t fixed_size;
struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
struct chan_band_param_set *chan_band;
u8 is_bgscan_resp;
@ -2111,6 +2131,14 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
else
scan_rsp = &resp->params.scan_resp;
scan_resp_size = le16_to_cpu(resp->size);
fixed_size = scan_rsp->bss_desc_and_tlv_buffer - (u8 *)resp;
if (scan_resp_size < fixed_size) {
mwifiex_dbg(adapter, ERROR,
"SCAN_RESP: response is too short\n");
ret = -1;
goto check_next_scan;
}
if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
mwifiex_dbg(adapter, ERROR,
@ -2128,8 +2156,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
"info: SCAN_RESP: bss_descript_size %d\n",
bytes_left);
scan_resp_size = le16_to_cpu(resp->size);
mwifiex_dbg(adapter, INFO,
"info: SCAN_RESP: returned %d APs before parsing\n",
scan_rsp->number_of_sets);
@ -2137,15 +2163,17 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
bss_info = scan_rsp->bss_desc_and_tlv_buffer;
/*
* The size of the TLV buffer is equal to the entire command response
* size (scan_resp_size) minus the fixed fields (sizeof()'s), the
* BSS Descriptions (bss_descript_size as bytesLef) and the command
* response header (S_DS_GEN)
* The TLV buffer follows the command-specific fixed fields and the BSS
* descriptions. Background-scan responses have an additional fixed
* field before scan_rsp, which is included in fixed_size.
*/
tlv_buf_size = scan_resp_size - (bytes_left
+ sizeof(scan_rsp->bss_descript_size)
+ sizeof(scan_rsp->number_of_sets)
+ S_DS_GEN);
if (bytes_left > scan_resp_size - fixed_size) {
mwifiex_dbg(adapter, ERROR,
"SCAN_RESP: BSS data exceeds response\n");
ret = -1;
goto check_next_scan;
}
tlv_buf_size = scan_resp_size - fixed_size - bytes_left;
tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
bss_desc_and_tlv_buffer +

View File

@ -317,10 +317,16 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
switch (stype) {
case IEEE80211_STYPE_ACTION:
category = *(payload + sizeof(struct ieee80211_hdr));
if (len < sizeof(*ieee_hdr) + 1)
return -1;
category = *(payload + sizeof(*ieee_hdr));
switch (category) {
case WLAN_CATEGORY_PUBLIC:
action_code = *(payload + sizeof(struct ieee80211_hdr)
if (len < sizeof(*ieee_hdr) + 2)
return -1;
action_code = *(payload + sizeof(*ieee_hdr)
+ 1);
if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
addr2 = ieee_hdr->addr2;

View File

@ -1058,6 +1058,13 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
if (!ieee80211_is_public_action((struct ieee80211_hdr *)buff, size))
goto out_rx_mgmt;
/* ieee80211_is_public_action() only validates up to the category
* byte, so reject frames too short for the P2P public action header
* before dereferencing it or computing size - ie_offset.
*/
if (size < ie_offset)
goto out_rx_mgmt;
d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
if (d->oui_subtype != GO_NEG_REQ && d->oui_subtype != GO_NEG_RSP &&
d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP)
@ -1200,6 +1207,13 @@ static int mgmt_tx(struct wiphy *wiphy,
goto out_set_timeout;
}
/* ieee80211_is_public_action() only validates up to the category
* byte, so reject frames too short for the P2P public action header
* before dereferencing it or computing len - ie_offset.
*/
if (len < ie_offset)
goto out_set_timeout;
d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P ||
d->oui_subtype != GO_NEG_CONF) {

View File

@ -1197,6 +1197,15 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
if (size <= 0)
return;
/* A size exceeding the RX buffer is bogus; drop the transfer
* instead of overflowing the buffer.
*/
if (size > WILC_RX_BUFF_SIZE) {
wilc->hif_func->hif_clear_int_ext(wilc,
DATA_INT_CLR | ENABLE_RX_VMM);
return;
}
if (WILC_RX_BUFF_SIZE - offset < size)
offset = 0;

View File

@ -852,8 +852,6 @@ int rsi_hal_load_key(struct rsi_common *common,
memcpy(set_key->tx_mic_key, &data[16], 8);
memcpy(set_key->rx_mic_key, &data[24], 8);
}
} else {
memset(&set_key[FRAME_DESC_SZ], 0, frame_len - FRAME_DESC_SZ);
}
skb_put(skb, frame_len);

View File

@ -3724,10 +3724,8 @@ void wlcore_regdomain_config(struct wl1271 *wl)
goto out;
ret = wlcore_cmd_regdomain_config_locked(wl);
if (ret < 0) {
if (ret < 0)
wl12xx_queue_recovery_work(wl);
goto out;
}
pm_runtime_put_autosuspend(wl->dev);
out:

View File

@ -2327,7 +2327,12 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw, bool suspend)
struct sk_buff *skb;
int i;
data->started = false;
/*
* Serialise against wmediumd userspace, so no more frames
* can be handed to mac80211 after this returns.
*/
scoped_guard(mutex, &data->mutex)
data->started = false;
for (i = 0; i < ARRAY_SIZE(data->link_data); i++)
hrtimer_cancel(&data->link_data[i].beacon_timer);
@ -6505,12 +6510,12 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
if (frame_data_len < sizeof(struct ieee80211_hdr_3addr) ||
frame_data_len > IEEE80211_MAX_DATA_LEN)
goto err;
goto out;
/* Allocate new skb here */
skb = alloc_skb(frame_data_len, GFP_KERNEL);
if (skb == NULL)
goto err;
goto out;
/* Copy the data */
skb_put_data(skb, frame_data, frame_data_len);
@ -6535,10 +6540,17 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
goto out;
}
/*
* Serialise against mac80211_hwsim_stop() - mac80211 doesn't allow
* frames reported while the HW is down, hence the ->started check
* must be under mutex.
*/
mutex_lock(&data2->mutex);
/* check if radio is configured properly */
if ((data2->idle && !data2->tmp_chan) || !data2->started)
goto out;
goto out_unlock;
/* A frame is received from user space */
memset(&rx_status, 0, sizeof(rx_status));
@ -6557,22 +6569,18 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
iter_data.channel = ieee80211_get_channel(data2->hw->wiphy,
rx_status.freq);
if (!iter_data.channel)
goto out;
goto out_unlock;
rx_status.band = iter_data.channel->band;
mutex_lock(&data2->mutex);
if (!hwsim_chans_compat(iter_data.channel, channel)) {
ieee80211_iterate_active_interfaces_atomic(
data2->hw, IEEE80211_IFACE_ITER_NORMAL,
mac80211_hwsim_tx_iter, &iter_data);
if (!iter_data.receive) {
mutex_unlock(&data2->mutex);
goto out;
}
if (!iter_data.receive)
goto out_unlock;
}
mutex_unlock(&data2->mutex);
} else if (!channel) {
goto out;
goto out_unlock;
} else {
rx_status.freq = channel->center_freq;
rx_status.band = channel->band;
@ -6580,7 +6588,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates)
goto out;
goto out_unlock;
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
hdr = (void *)skb->data;
@ -6590,10 +6598,11 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
rx_status.boottime_ns = ktime_get_boottime_ns();
mac80211_hwsim_rx(data2, &rx_status, skb);
mutex_unlock(&data2->mutex);
return 0;
err:
pr_debug("mac80211_hwsim: error occurred in %s\n", __func__);
out_unlock:
mutex_unlock(&data2->mutex);
out:
dev_kfree_skb(skb);
return -EINVAL;

View File

@ -434,6 +434,7 @@ static netdev_tx_t virt_wifi_start_xmit(struct sk_buff *skb,
priv->tx_packets++;
if (!priv->is_connected) {
priv->tx_failed++;
dev_kfree_skb_any(skb);
return NET_XMIT_DROP;
}
@ -557,7 +558,6 @@ static int virt_wifi_newlink(struct net_device *dev,
}
eth_hw_addr_inherit(dev, priv->lowerdev);
netif_stacked_transfer_operstate(priv->lowerdev, dev);
dev->ieee80211_ptr = kzalloc_obj(*dev->ieee80211_ptr);
@ -583,6 +583,8 @@ static int virt_wifi_newlink(struct net_device *dev,
goto unregister_netdev;
}
netif_stacked_transfer_operstate(priv->lowerdev, dev);
dev->priv_destructor = virt_wifi_net_device_destructor;
priv->being_deleted = false;
priv->is_connected = false;

View File

@ -251,6 +251,14 @@ static int mbim_rx_verify_ndp16(struct sk_buff *skb, struct usb_cdc_ncm_ndp16 *n
return ret;
}
static void mhi_mbim_rx_drop(struct mhi_mbim_link *link, struct sk_buff *skb)
{
dev_kfree_skb_any(skb);
u64_stats_update_begin(&link->rx_syncp);
u64_stats_inc(&link->rx_errors);
u64_stats_update_end(&link->rx_syncp);
}
static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb)
{
int ndpoffset;
@ -320,7 +328,10 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb)
continue;
skb_put(skbn, dgram_len);
skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len);
if (skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len)) {
mhi_mbim_rx_drop(link, skbn);
continue;
}
switch (skbn->data[0] & 0xf0) {
case 0x40:
@ -332,10 +343,7 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb)
default:
net_err_ratelimited("%s: unknown protocol\n",
link->ndev->name);
dev_kfree_skb_any(skbn);
u64_stats_update_begin(&link->rx_syncp);
u64_stats_inc(&link->rx_errors);
u64_stats_update_end(&link->rx_syncp);
mhi_mbim_rx_drop(link, skbn);
continue;
}
@ -349,9 +357,13 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb)
unlock:
rcu_read_unlock();
next_ndp:
/* Other NDP to process? */
ndpoffset = (int)le16_to_cpu(ndp16.wNextNdpIndex);
if (!ndpoffset)
/* Other NDP to process? The offsets must advance, or a
* self-referencing NDP keeps the loop spinning forever.
*/
n = (int)le16_to_cpu(ndp16.wNextNdpIndex);
if (n > ndpoffset)
ndpoffset = n;
else
break;
}

View File

@ -420,6 +420,10 @@ static void t7xx_ccmni_recv_skb(struct t7xx_ccmni_ctrl *ccmni_ctlb, struct sk_bu
skb_cb = T7XX_SKB_CB(skb);
netif_id = skb_cb->netif_idx;
if (netif_id >= NIC_DEV_MAX) {
dev_kfree_skb(skb);
return;
}
ccmni = READ_ONCE(ccmni_ctlb->ccmni_inst[netif_id]);
if (!ccmni) {
dev_kfree_skb(skb);

View File

@ -361,8 +361,7 @@ ieee80211_mesh_hwmp_perr_get_rcode(const u8 *ie, u8 dst_idx)
/* IEEE Std 802.11-2016 9.4.2.113 PREQ element */
static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen)
{
struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom =
ieee80211_mesh_hwmp_preq_get_bottom(pos);
struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom;
u8 target_count;
int needed;
@ -378,6 +377,7 @@ static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen)
if (elen < needed)
return false;
preq_elem_bottom = ieee80211_mesh_hwmp_preq_get_bottom(pos);
target_count = preq_elem_bottom->target_count;
/* IEEE Std 802.11-2016 Table 14-10 to 14-16 */
if (target_count < 1)

View File

@ -70,6 +70,7 @@ struct hci_devcoredump {
const char *hci_devcd_state_name(enum devcoredump_state state);
void hci_devcd_reset(struct hci_dev *hdev);
void hci_devcd_shutdown(struct hci_dev *hdev);
void hci_devcd_rx(struct work_struct *work);
void hci_devcd_timeout(struct work_struct *work);
@ -89,6 +90,7 @@ static inline const char *hci_devcd_state_name(enum devcoredump_state state)
}
static inline void hci_devcd_reset(struct hci_dev *hdev) {}
static inline void hci_devcd_shutdown(struct hci_dev *hdev) {}
static inline void hci_devcd_rx(struct work_struct *work) {}
static inline void hci_devcd_timeout(struct work_struct *work) {}

View File

@ -140,6 +140,11 @@ struct codel_vars {
/* needed shift to get a Q0.32 number from rec_inv_sqrt */
#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
/* Cap on drops per codel_dequeue() call: the loop's work depends on the
* idle gap and backlog, both outside our control; resync when exceeded.
*/
#define CODEL_MAX_DROPS_PER_DEQUEUE 256
/**
* struct codel_stats - contains codel shared variables and stats
* @maxpacket: largest packet we've seen so far

View File

@ -93,12 +93,17 @@ static void codel_Newton_step(struct codel_vars *vars)
* CoDel control_law is t + interval/sqrt(count)
* We maintain in rec_inv_sqrt the reciprocal value of sqrt(count) to avoid
* both sqrt() and divide operation.
*
* Clamp the increment to at least 1 tick: a very small interval (or a
* large count) can truncate it to zero, stalling the dropping loop.
*/
static codel_time_t codel_control_law(codel_time_t t,
codel_time_t interval,
u32 rec_inv_sqrt)
{
return t + reciprocal_scale(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT);
return t + max_t(u32, 1,
reciprocal_scale(interval,
rec_inv_sqrt << REC_INV_SQRT_SHIFT));
}
static bool codel_should_drop(const struct sk_buff *skb,
@ -154,6 +159,7 @@ static struct sk_buff *codel_dequeue(void *ctx,
codel_skb_dequeue_t dequeue_func)
{
struct sk_buff *skb = dequeue_func(vars, ctx);
unsigned int drops = 0;
codel_time_t now;
bool drop;
@ -180,6 +186,14 @@ static struct sk_buff *codel_dequeue(void *ctx,
*/
while (vars->dropping &&
codel_time_after_eq(now, vars->drop_next)) {
if (++drops > CODEL_MAX_DROPS_PER_DEQUEUE) {
/* fell far behind the schedule */
WRITE_ONCE(vars->drop_next,
codel_control_law(now,
params->interval,
vars->rec_inv_sqrt));
break;
}
/* dont care of possible wrap
* since there is no more divide.
*/

View File

@ -7638,11 +7638,14 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
*
* @skb: packet injected by userspace
* @dev: the &struct device of this 802.11 device
* @chandef: the channel definition the frame will be transmitted on, or
* %NULL to skip the bandwidth checks
*
* Return: %true if the radiotap header was parsed, %false otherwise
*/
bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
struct net_device *dev);
struct net_device *dev,
const struct cfg80211_chan_def *chandef);
/**
* struct ieee80211_noa_data - holds temporary data for tracking P2P NoA state

View File

@ -2312,6 +2312,8 @@ static inline void sk_gso_disable(struct sock *sk)
sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
}
bool sk_has_decrypt_user(const struct sock *sk);
static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb,
struct iov_iter *from, char *to,
int copy, int offset)

View File

@ -292,10 +292,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
struct atm_vcc *vcc;
int ret;
if (!pskb_may_pull(skb, 1)) {
kfree_skb(skb);
return DROP_PACKET;
}
ATM_SKB(skb)->vcc = pvcc->atmvcc;
pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);
if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
(void) skb_pull(skb, 1);
vcc = ATM_SKB(skb)->vcc;
bh_lock_sock(sk_atm(vcc));
@ -317,23 +320,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
switch (pvcc->encaps) { /* LLC encapsulation needed */
case e_llc:
if (skb_headroom(skb) < LLC_LEN) {
struct sk_buff *n;
n = skb_realloc_headroom(skb, LLC_LEN);
if (n != NULL &&
!pppoatm_may_send(pvcc, n->truesize)) {
kfree_skb(n);
goto nospace;
}
consume_skb(skb);
skb = n;
if (skb == NULL) {
bh_unlock_sock(sk_atm(vcc));
return DROP_PACKET;
}
} else if (!pppoatm_may_send(pvcc, skb->truesize))
if (skb_cow_head(skb, LLC_LEN)) {
bh_unlock_sock(sk_atm(vcc));
kfree_skb(skb);
return DROP_PACKET;
}
if (!pppoatm_may_send(pvcc, skb->truesize))
goto nospace;
memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
break;
case e_vc:
if (!pppoatm_may_send(pvcc, skb->truesize))
@ -346,6 +339,12 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
return 1;
}
if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
skb_pull(skb, 1);
if (pvcc->encaps == e_llc)
memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
atm_account_tx(vcc, skb);
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
@ -355,13 +354,6 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
return ret;
nospace:
bh_unlock_sock(sk_atm(vcc));
/*
* We don't have space to send this SKB now, but we might have
* already applied SC_COMP_PROT compression, so may need to undo
*/
if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 &&
skb->data[-1] == '\0')
(void) skb_push(skb, 1);
return 0;
}

View File

@ -104,6 +104,22 @@ static void hci_devcd_free(struct hci_dev *hdev)
hci_devcd_reset(hdev);
}
void hci_devcd_shutdown(struct hci_dev *hdev)
{
unsigned long flags;
spin_lock_irqsave(&hdev->dump.dump_q.lock, flags);
hdev->dump.supported = false;
spin_unlock_irqrestore(&hdev->dump.dump_q.lock, flags);
disable_work_sync(&hdev->dump.dump_rx);
disable_delayed_work_sync(&hdev->dump.dump_timeout);
hci_dev_lock(hdev);
hci_devcd_free(hdev);
hci_dev_unlock(hdev);
}
/* Call with hci_dev_lock only. */
static int hci_devcd_alloc(struct hci_dev *hdev, u32 size)
{
@ -442,7 +458,29 @@ EXPORT_SYMBOL(hci_devcd_register);
static inline bool hci_devcd_enabled(struct hci_dev *hdev)
{
return hdev->dump.supported;
return READ_ONCE(hdev->dump.supported);
}
static int hci_devcd_queue(struct hci_dev *hdev, struct sk_buff *skb)
{
unsigned long flags;
int err = 0;
spin_lock_irqsave(&hdev->dump.dump_q.lock, flags);
if (!hdev->dump.supported)
err = -EOPNOTSUPP;
else
__skb_queue_tail(&hdev->dump.dump_q, skb);
spin_unlock_irqrestore(&hdev->dump.dump_q.lock, flags);
if (err) {
kfree_skb(skb);
return err;
}
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
return 0;
}
int hci_devcd_init(struct hci_dev *hdev, u32 dump_size)
@ -459,10 +497,7 @@ int hci_devcd_init(struct hci_dev *hdev, u32 dump_size)
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_INIT;
put_unaligned_le32(dump_size, skb_put(skb, 4));
skb_queue_tail(&hdev->dump.dump_q, skb);
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
return 0;
return hci_devcd_queue(hdev, skb);
}
EXPORT_SYMBOL(hci_devcd_init);
@ -478,10 +513,7 @@ int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb)
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_SKB;
skb_queue_tail(&hdev->dump.dump_q, skb);
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
return 0;
return hci_devcd_queue(hdev, skb);
}
EXPORT_SYMBOL(hci_devcd_append);
@ -503,10 +535,7 @@ int hci_devcd_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len)
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_PATTERN;
skb_put_data(skb, &p, sizeof(p));
skb_queue_tail(&hdev->dump.dump_q, skb);
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
return 0;
return hci_devcd_queue(hdev, skb);
}
EXPORT_SYMBOL(hci_devcd_append_pattern);
@ -523,10 +552,7 @@ int hci_devcd_complete(struct hci_dev *hdev)
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_COMPLETE;
skb_queue_tail(&hdev->dump.dump_q, skb);
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
return 0;
return hci_devcd_queue(hdev, skb);
}
EXPORT_SYMBOL(hci_devcd_complete);
@ -543,10 +569,7 @@ int hci_devcd_abort(struct hci_dev *hdev)
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_ABORT;
skb_queue_tail(&hdev->dump.dump_q, skb);
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
return 0;
return hci_devcd_queue(hdev, skb);
}
EXPORT_SYMBOL(hci_devcd_abort);

View File

@ -373,7 +373,15 @@ void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len)
size_t dlen;
while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, &dlen))) {
u16 value = get_unaligned_le16(eir);
u16 value;
if (dlen < sizeof(value)) {
eir += dlen;
eir_len = eir_end - eir;
continue;
}
value = get_unaligned_le16(eir);
if (uuid == value) {
if (len)

View File

@ -145,11 +145,12 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
skb_pull(skb, sizeof(rp->status));
std_codecs = (void *)skb->data;
std_codecs = skb_pull_data(skb, sizeof(*std_codecs));
if (!std_codecs)
goto error;
/* validate codecs length before accessing */
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num))
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num))
goto error;
/* enumerate codec capabilities of standard codecs */
@ -161,15 +162,14 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
LOCAL_CODEC_ACL_MASK | LOCAL_CODEC_SCO_MASK, &caps);
}
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num));
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num));
vnd_codecs = (void *)skb->data;
vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs));
if (!vnd_codecs)
goto error;
/* validate vendor codecs length before accessing */
if (skb->len <
flex_array_size(vnd_codecs, codec, vnd_codecs->num)
+ sizeof(vnd_codecs->num))
if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num))
goto error;
/* enumerate vendor codec capabilities */
@ -214,11 +214,12 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)
skb_pull(skb, sizeof(rp->status));
std_codecs = (void *)skb->data;
std_codecs = skb_pull_data(skb, sizeof(*std_codecs));
if (!std_codecs)
goto error;
/* check for payload data length before accessing */
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num))
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num))
goto error;
memset(&caps, 0, sizeof(caps));
@ -229,15 +230,14 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)
&caps);
}
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num));
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num));
vnd_codecs = (void *)skb->data;
vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs));
if (!vnd_codecs)
goto error;
/* check for payload data length before accessing */
if (skb->len <
flex_array_size(vnd_codecs, codec, vnd_codecs->num)
+ sizeof(vnd_codecs->num))
if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num))
goto error;
for (i = 0; i < vnd_codecs->num; i++) {

View File

@ -1023,6 +1023,19 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,
if (!hdev->le_mtu && hdev->acl_mtu < HCI_MIN_LE_MTU)
return ERR_PTR(-ECONNREFUSED);
irk = hci_get_irk(hdev, dst, dst_type);
/* An identity address only reaches a peer advertising an RPA
* if the controller translates it. Unless address resolution
* is enabled and this peer is programmed into the resolving
* list, keep the RPA the peer is on air with;
* le_conn_complete_evt() resolves it back once the link is
* up.
*/
if (irk &&
(!hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION) ||
!hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
&irk->bdaddr,
irk->addr_type)))
irk = NULL;
break;
case SCO_LINK:
case ESCO_LINK:
@ -1505,7 +1518,15 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
}
if (conn) {
/* dst may just have been swapped for the peer's RPA above, and
* dst_type describes dst -- it has to travel with it. Leaving
* the identity type behind makes the pair describe a peer that
* does not exist, and nothing downstream repairs it:
* hci_bdaddr_is_rpa() tests the type before the address, so
* the RPA is never treated as one.
*/
bacpy(&conn->dst, dst);
conn->dst_type = dst_type;
} else {
conn = hci_conn_add_unset(hdev, LE_LINK, dst, dst_type, role);
if (IS_ERR(conn))

View File

@ -2673,6 +2673,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
disable_work_sync(&hdev->error_reset);
disable_delayed_work_sync(&hdev->cmd_timer);
disable_delayed_work_sync(&hdev->ncmd_timer);
hci_devcd_shutdown(hdev);
hci_cmd_sync_clear(hdev);
@ -3236,6 +3237,17 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
bt_dev_dbg(hdev, "chan %p queued %d", chan, skb_queue_len(queue));
}
/* Queue hdev->tx_work, unless hdev->workqueue is being drained by
* hci_dev_close_sync(), which would otherwise WARN and drop the work.
*/
static void hci_sched_tx(struct hci_dev *hdev)
{
rcu_read_lock();
if (!hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
queue_work(hdev->workqueue, &hdev->tx_work);
rcu_read_unlock();
}
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
{
struct hci_dev *hdev = chan->conn->hdev;
@ -3244,7 +3256,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
hci_queue_acl(chan, &chan->data_q, skb, flags);
queue_work(hdev->workqueue, &hdev->tx_work);
hci_sched_tx(hdev);
}
/* Send SCO data */
@ -3269,7 +3281,7 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
bt_dev_dbg(hdev, "hcon %p queued %d", conn,
skb_queue_len(&conn->data_q));
queue_work(hdev->workqueue, &hdev->tx_work);
hci_sched_tx(hdev);
}
/* Send ISO data */
@ -3340,7 +3352,7 @@ void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb)
hci_queue_iso(conn, &conn->data_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
hci_sched_tx(hdev);
}
/* ---- HCI TX task (outgoing data) ---- */

View File

@ -5673,7 +5673,9 @@ int hci_dev_close_sync(struct hci_dev *hdev)
memset(hdev->eir, 0, sizeof(hdev->eir));
memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
bacpy(&hdev->random_addr, BDADDR_ANY);
hci_dev_lock(hdev);
hci_codec_list_clear(&hdev->local_codecs);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
return err;

View File

@ -819,19 +819,24 @@ static void iso_sock_destruct(struct sock *sk)
skb_queue_purge(&sk->sk_error_queue);
}
static void iso_sock_cleanup_listen(struct sock *parent)
/* Close not yet accepted channels */
static void iso_sock_flush_accept_q(struct sock *parent)
{
struct sock *sk;
BT_DBG("parent %p", parent);
/* Close not yet accepted channels */
while ((sk = bt_accept_dequeue(parent, NULL))) {
iso_sock_close(sk);
iso_sock_kill(sk);
/* Drop the reference handed back by bt_accept_dequeue(). */
sock_put(sk);
}
}
static void iso_sock_cleanup_listen(struct sock *parent)
{
BT_DBG("parent %p", parent);
iso_sock_flush_accept_q(parent);
/* If listening socket has a hcon, properly disconnect it */
if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon) {
@ -1737,6 +1742,13 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
switch (sk->sk_state) {
case BT_CONNECT2:
if (test_bit(BT_SK_PA_SYNC, &pi->flags)) {
/* Move to BT_LISTEN before requesting the BIG
* sync: the BIS connections are matched to a
* parent socket in BT_LISTEN state, and they
* may be notified before the request returns.
*/
sk->sk_state = BT_LISTEN;
release_sock(sk);
err = iso_conn_big_sync(sk);
lock_sock(sk);
@ -1745,12 +1757,20 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
* connection may have been torn down
* meanwhile and iso_chan_del() may have
* already moved the socket to BT_CLOSED.
* Only move on to BT_LISTEN if the BIG sync
* was actually started and nothing else has
* changed the state.
* Only move back if the BIG sync could not be
* started and nothing else has changed the
* state.
*/
if (!err && sk->sk_state == BT_CONNECT2)
sk->sk_state = BT_LISTEN;
if (err && sk->sk_state == BT_LISTEN) {
/* Discard any child socket that may
* have been queued while the socket
* was in BT_LISTEN, as the cleanup of
* BT_CONNECT2 doesn't drain the
* accept queue.
*/
iso_sock_flush_accept_q(sk);
sk->sk_state = BT_CONNECT2;
}
} else {
iso_conn_defer_accept(pi->conn->hcon);
sk->sk_state = BT_CONFIG;
@ -1760,12 +1780,22 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
break;
case BT_CONNECTED:
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
/* As above, the BIS connections may be
* notified before the request returns.
*/
sk->sk_state = BT_LISTEN;
release_sock(sk);
err = iso_conn_big_sync(sk);
lock_sock(sk);
if (!err && sk->sk_state == BT_CONNECTED)
sk->sk_state = BT_LISTEN;
if (err && sk->sk_state == BT_LISTEN) {
/* As above, don't leave any child
* socket behind in the accept queue.
*/
iso_sock_flush_accept_q(sk);
sk->sk_state = BT_CONNECTED;
}
early_ret = true;
}
@ -2289,6 +2319,7 @@ static void iso_conn_ready(struct iso_conn *conn)
BTPROTO_ISO, GFP_ATOMIC, 0);
if (!sk) {
release_sock(parent);
sock_put(parent);
return;
}

View File

@ -242,9 +242,7 @@ static void __rfcomm_sock_close(struct sock *sk)
*/
static void rfcomm_sock_close(struct sock *sk)
{
lock_sock(sk);
__rfcomm_sock_close(sk);
release_sock(sk);
}
static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
@ -905,6 +903,7 @@ static int rfcomm_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsig
static int rfcomm_sock_shutdown(struct socket *sock, int how)
{
struct sock *sk = sock->sk;
bool cleanup_listen = false;
int err = 0;
BT_DBG("sock %p, sk %p", sock, sk);
@ -915,9 +914,17 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how)
lock_sock(sk);
if (!sk->sk_shutdown) {
sk->sk_shutdown = SHUTDOWN_MASK;
if (sk->sk_state == BT_LISTEN) {
/* Block new children before cleaning up without sk lock. */
sk->sk_state = BT_CLOSED;
cleanup_listen = true;
}
release_sock(sk);
__rfcomm_sock_close(sk);
if (cleanup_listen)
rfcomm_sock_cleanup_listen(sk);
else
__rfcomm_sock_close(sk);
lock_sock(sk);
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&

View File

@ -107,21 +107,24 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
struct net_bridge_vlan *v;
int err = 0;
rcu_read_lock();
vg = nbp_vlan_group_rcu(p);
if (!vg)
goto out;
/* MSTI 0 (CST) state changes are notified via the regular
* SWITCHDEV_ATTR_ID_PORT_STP_STATE.
* SWITCHDEV_ATTR_ID_PORT_STP_STATE. All other MSTIs are handled via
* netlink with RTNL held
*/
if (msti) {
ASSERT_RTNL();
err = switchdev_port_attr_set(p->dev, &attr, extack);
if (err && err != -EOPNOTSUPP)
goto out;
err = 0;
}
err = 0;
rcu_read_lock();
vg = nbp_vlan_group_rcu(p);
if (!vg)
goto out_rcu_unlock;
list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
if (v->brvlan->msti != msti)
continue;
@ -129,8 +132,9 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
br_mst_vlan_set_state(vg, v, state);
}
out:
out_rcu_unlock:
rcu_read_unlock();
out:
return err;
}

View File

@ -387,12 +387,12 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags,
goto out;
}
static int __vlan_del(struct net_bridge_vlan *v)
static void __vlan_del(struct net_bridge_vlan *v)
{
struct net_bridge_vlan *masterv = v;
struct net_bridge_vlan_group *vg;
struct net_bridge_port *p = NULL;
int err = 0;
int err;
if (br_vlan_is_master(v)) {
vg = br_vlan_group(v->br);
@ -406,12 +406,16 @@ static int __vlan_del(struct net_bridge_vlan *v)
if (p) {
err = __vlan_vid_del(p->dev, p->br, v);
if (err)
goto out;
br_warn(p->br,
"port %u(%s) failed to delete vlan %u from switchdev: %pe\n",
(unsigned int)p->port_no, p->dev->name,
v->vid, ERR_PTR(err));
} else {
err = br_switchdev_port_vlan_del(v->br->dev, v->vid);
if (err && err != -EOPNOTSUPP)
goto out;
err = 0;
br_warn(v->br,
"failed to delete bridge vlan %u from switchdev: %pe\n",
v->vid, ERR_PTR(err));
}
if (br_vlan_should_use(v)) {
@ -431,8 +435,6 @@ static int __vlan_del(struct net_bridge_vlan *v)
}
br_vlan_put_master(masterv);
out:
return err;
}
static void __vlan_group_free(struct net_bridge_vlan_group *vg)
@ -449,7 +451,6 @@ static void __vlan_flush(const struct net_bridge *br,
{
struct net_bridge_vlan *vlan, *tmp;
u16 v_start = 0, v_end = 0;
int err;
__vlan_delete_pvid(vg, vg->pvid);
list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist) {
@ -463,13 +464,7 @@ static void __vlan_flush(const struct net_bridge *br,
}
v_end = vlan->vid;
err = __vlan_del(vlan);
if (err) {
br_err(br,
"port %u(%s) failed to delete vlan %d: %pe\n",
(unsigned int) p->port_no, p->dev->name,
vlan->vid, ERR_PTR(err));
}
__vlan_del(vlan);
}
/* notify about the last/whole vlan range */
@ -837,8 +832,9 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
br_fdb_delete_by_port(br, NULL, vid, 0);
vlan_tunnel_info_del(vg, v);
__vlan_del(v);
return __vlan_del(v);
return 0;
}
void br_vlan_flush(struct net_bridge *br)
@ -1368,8 +1364,9 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
return -ENOENT;
br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid);
br_fdb_delete_by_port(port->br, port, vid, 0);
__vlan_del(v);
return __vlan_del(v);
return 0;
}
void nbp_vlan_flush(struct net_bridge_port *port)

View File

@ -789,7 +789,7 @@ int dev_fill_forward_path(struct net_device_path_ctx *ctx,
goto err_out;
stack->num_paths++;
if (WARN_ON_ONCE(last_dev == ctx->dev))
if (last_dev == ctx->dev)
goto err_out;
}

View File

@ -141,9 +141,8 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data)
al = sizeof(struct net_dm_alert_msg);
al += dm_hit_limit * sizeof(struct net_dm_drop_point);
al += sizeof(struct nlattr);
skb = genlmsg_new(al, GFP_KERNEL);
skb = genlmsg_new(nla_total_size(al), GFP_KERNEL);
if (!skb)
goto err;
@ -448,7 +447,7 @@ net_dm_hw_trap_summary_probe(void *ignore, const struct devlink *devlink,
if (metadata->trap_type == DEVLINK_TRAP_TYPE_CONTROL)
return;
hw_data = this_cpu_ptr(&dm_hw_cpu_data);
hw_data = raw_cpu_ptr(&dm_hw_cpu_data);
raw_spin_lock_irqsave(&hw_data->lock, flags);
hw_entries = hw_data->hw_entries;
@ -516,7 +515,7 @@ static void net_dm_packet_trace_kfree_skb_hit(void *ignore,
*/
nskb->tstamp = tstamp;
data = this_cpu_ptr(&dm_cpu_data);
data = raw_cpu_ptr(&dm_cpu_data);
spin_lock_irqsave(&data->drop_queue.lock, flags);
if (skb_queue_len(&data->drop_queue) < net_dm_queue_len)
@ -983,7 +982,7 @@ net_dm_hw_trap_packet_probe(void *ignore, const struct devlink *devlink,
NET_DM_SKB_CB(nskb)->hw_metadata = n_hw_metadata;
nskb->tstamp = tstamp;
hw_data = this_cpu_ptr(&dm_hw_cpu_data);
hw_data = raw_cpu_ptr(&dm_hw_cpu_data);
spin_lock_irqsave(&hw_data->drop_queue.lock, flags);
if (skb_queue_len(&hw_data->drop_queue) < net_dm_queue_len)
@ -1083,7 +1082,7 @@ static int net_dm_hw_monitor_start(struct netlink_ext_ack *extack)
struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu);
struct sk_buff *skb;
timer_delete_sync(&hw_data->send_timer);
timer_shutdown_sync(&hw_data->send_timer);
cancel_work_sync(&hw_data->dm_alert_work);
while ((skb = __skb_dequeue(&hw_data->drop_queue))) {
struct devlink_trap_metadata *hw_metadata;
@ -1117,7 +1116,7 @@ static void net_dm_hw_monitor_stop(struct netlink_ext_ack *extack)
struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu);
struct sk_buff *skb;
timer_delete_sync(&hw_data->send_timer);
timer_shutdown_sync(&hw_data->send_timer);
cancel_work_sync(&hw_data->dm_alert_work);
while ((skb = __skb_dequeue(&hw_data->drop_queue))) {
struct devlink_trap_metadata *hw_metadata;
@ -1173,12 +1172,13 @@ static int net_dm_trace_on_set(struct netlink_ext_ack *extack)
err_unregister_trace:
unregister_trace_kfree_skb(ops->kfree_skb_probe, NULL);
tracepoint_synchronize_unregister();
err_module_put:
for_each_possible_cpu(cpu) {
struct per_cpu_dm_data *data = &per_cpu(dm_cpu_data, cpu);
struct sk_buff *skb;
timer_delete_sync(&data->send_timer);
timer_shutdown_sync(&data->send_timer);
cancel_work_sync(&data->dm_alert_work);
while ((skb = __skb_dequeue(&data->drop_queue)))
consume_skb(skb);
@ -1206,7 +1206,7 @@ static void net_dm_trace_off_set(void)
struct per_cpu_dm_data *data = &per_cpu(dm_cpu_data, cpu);
struct sk_buff *skb;
timer_delete_sync(&data->send_timer);
timer_shutdown_sync(&data->send_timer);
cancel_work_sync(&data->dm_alert_work);
while ((skb = __skb_dequeue(&data->drop_queue)))
consume_skb(skb);

View File

@ -2359,6 +2359,13 @@ static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
[NDTA_PARMS] = { .type = NLA_NESTED },
};
#define NTBL_PARM_MS_MAX (24 * 60 * 60 * MSEC_PER_SEC)
static const struct netlink_range_validation nl_ntbl_parm_ms_range = {
.min = 1,
.max = NTBL_PARM_MS_MAX,
};
static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
[NDTPA_IFINDEX] = { .type = NLA_U32 },
[NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
@ -2375,7 +2382,8 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
[NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
[NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
[NDTPA_LOCKTIME] = { .type = NLA_U64 },
[NDTPA_INTERVAL_PROBE_TIME_MS] = { .type = NLA_U64, .min = 1 },
[NDTPA_INTERVAL_PROBE_TIME_MS] = NLA_POLICY_FULL_RANGE(NLA_U64,
&nl_ntbl_parm_ms_range),
};
static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
@ -2579,9 +2587,10 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
{
const struct nlmsghdr *nlh = cb->nlh;
struct net *net = sock_net(skb->sk);
int default_skip = cb->args[2];
int neigh_skip = cb->args[1];
int family, tidx, nidx = 0;
int tbl_skip = cb->args[0];
int neigh_skip = cb->args[1];
struct neigh_table *tbl;
if (cb->strict_check) {
@ -2605,17 +2614,21 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
if (tidx < tbl_skip || (family && tbl->family != family))
continue;
if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
if (!default_skip &&
neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
NLM_F_MULTI) < 0)
break;
nidx = 0;
p = list_next_entry(&tbl->parms, list);
list_for_each_entry_from_rcu(p, &tbl->parms_list, list) {
default_skip = 1;
list_for_each_entry_rcu(p, &tbl->parms_list, list) {
if (!net_eq(neigh_parms_net(p), net))
continue;
if (!p->dev || p->dev == blackhole_netdev)
continue;
if (nidx < neigh_skip)
goto next;
@ -2630,12 +2643,15 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
}
neigh_skip = 0;
nidx = 0;
default_skip = 0;
}
out:
rcu_read_unlock();
cb->args[0] = tidx;
cb->args[1] = nidx;
cb->args[2] = default_skip;
return skb->len;
}
@ -3669,12 +3685,13 @@ static int neigh_proc_dointvec_ms_jiffies_positive(const struct ctl_table *ctl,
void *buffer, size_t *lenp, loff_t *ppos)
{
struct ctl_table tmp = *ctl;
int ret;
int ret, min, max;
int min = msecs_to_jiffies(1);
min = msecs_to_jiffies(1);
max = msecs_to_jiffies(NTBL_PARM_MS_MAX);
tmp.extra1 = &min;
tmp.extra2 = NULL;
tmp.extra2 = &max;
ret = proc_dointvec_ms_jiffies_minmax(&tmp, write, buffer, lenp, ppos);
neigh_proc_update(ctl, write);

View File

@ -6832,6 +6832,34 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len,
}
EXPORT_SYMBOL(alloc_skb_with_frags);
/* pskb_carve_inside_header() and pskb_carve_inside_nonlinear()
* remove the first bytes of a packet and reallocate skb->head.
*
* Whatever headers were present before the operation are gone,
* we must not leave stale offsets, otherwise users of this skb
* (skb_dump(), drop_monitor, taps, ...) would read or pull garbage.
*/
static void skb_carve_reset_headers(struct sk_buff *skb)
{
skb_unset_mac_header(skb);
skb_unset_transport_header(skb);
skb_reset_network_header(skb);
skb->mac_len = 0;
/* Inner offsets have no "unset" marker, zero them so that
* skb_inner_network_header_was_set() becomes false and no
* consumer mistakes them for a real (and long gone) header.
*/
skb->inner_mac_header = 0;
skb->inner_network_header = 0;
skb->inner_transport_header = 0;
skb->inner_protocol = 0;
skb->encapsulation = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL)
skb->ip_summed = CHECKSUM_NONE;
}
/* carve out the first off bytes from skb when off < headlen */
static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off,
const int headlen, gfp_t gfp_mask)
@ -6887,7 +6915,7 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off,
skb->head_frag = 0;
skb_set_end_offset(skb, size);
skb_set_tail_pointer(skb, skb_headlen(skb));
skb_headers_offset_update(skb, 0);
skb_carve_reset_headers(skb);
skb->cloned = 0;
skb->hdr_len = 0;
skb->nohdr = 0;
@ -7027,7 +7055,7 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off,
skb->data = data;
skb_set_end_offset(skb, size);
skb_reset_tail_pointer(skb);
skb_headers_offset_update(skb, 0);
skb_carve_reset_headers(skb);
skb->cloned = 0;
skb->hdr_len = 0;
skb->nohdr = 0;

View File

@ -142,6 +142,7 @@
#include <trace/events/sock.h>
#include <net/psp.h>
#include <net/tcp.h>
#include <net/busy_poll.h>
#include <net/phonet/phonet.h>
@ -2670,6 +2671,12 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
}
EXPORT_SYMBOL_GPL(sk_setup_caps);
bool sk_has_decrypt_user(const struct sock *sk)
{
return psp_sk_assoc(sk) ||
(sk_is_inet(sk) && inet_csk_has_ulp(sk)); /* for tls */
}
/*
* Simple resource managers for sockets.
*/
@ -3911,7 +3918,14 @@ int sock_gettstamp(struct socket *sock, void __user *userstamp,
struct sock *sk = sock->sk;
struct timespec64 ts;
sock_enable_timestamp(sk, SOCK_TIMESTAMP);
/* sk->sk_flags must only be changed under the socket lock,
* because sock_set_flag() uses non atomic operations.
*/
if (!sock_flag(sk, SOCK_TIMESTAMP)) {
lock_sock(sk);
sock_enable_timestamp(sk, SOCK_TIMESTAMP);
release_sock(sk);
}
ts = ktime_to_timespec64(sock_read_timestamp(sk));
if (ts.tv_sec == -1)
return -ENOENT;

View File

@ -441,6 +441,12 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
esp->inplace = false;
/* Take real page refs and clear SKBFL_MANAGED_FRAG_REFS before
* we mutate the frag array, so the per-frag unref stays balanced
* for zerocopy managed frags (see __ip_append_data()).
*/
skb_zcopy_downgrade_managed(skb);
allocsize = ALIGN(tailen, L1_CACHE_BYTES);
spin_lock_bh(&x->lock);

View File

@ -581,16 +581,19 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
skb_dstref_restore(skb_in, orefdst);
/*
* At this point, fl4_dec.daddr should NOT be local (we
* checked fl4_dec.saddr above). However, a race condition
* may occur if the address is added to the interface
* concurrently. In that case, ip_route_input() returns a
* LOCAL route with dst.output=ip_rt_bug, which must not
* be used for output.
* fl4_dec.daddr is not expected to be local here, but it can be
* added to an interface concurrently, in which case
* ip_route_input() returns a LOCAL route. It can also fail to
* build a forwarding route towards fl4_dec.daddr, for example,
* when forwarding is disabled, and return an UNREACHABLE route.
* Both cases will result in a route with dst.output=ip_rt_bug,
* which must not be used for output.
*/
if (!err && rt2 && rt2->rt_type == RTN_LOCAL) {
if (!err && rt2 && rt2->rt_type == RTN_LOCAL)
net_warn_ratelimited("detected local route for %pI4 during ICMP sending, src %pI4\n",
&fl4_dec.daddr, &fl4_dec.saddr);
if (!err && rt2 &&
(rt2->rt_type == RTN_LOCAL || rt2->rt_type == RTN_UNREACHABLE)) {
dst_release(&rt2->dst);
err = -EINVAL;
}

View File

@ -680,8 +680,14 @@ static int ip_tun_get_optlen(struct nlattr *attr,
}
static int ip_tun_set_opts(struct nlattr *attr, struct ip_tunnel_info *info,
struct netlink_ext_ack *extack)
int opts_len, struct netlink_ext_ack *extack)
{
/* `options_len` is the __counted_by() annotation of the `options`
* flexible array, it must be initialized before parsing writes
* into it.
*/
info->options_len = opts_len;
return ip_tun_parse_opts(attr, info, extack);
}
@ -712,7 +718,8 @@ static int ip_tun_build_state(struct net *net, struct nlattr *attr,
tun_info = lwt_tun_info(new_state);
err = ip_tun_set_opts(tb[LWTUNNEL_IP_OPTS], tun_info, extack);
err = ip_tun_set_opts(tb[LWTUNNEL_IP_OPTS], tun_info, opt_len,
extack);
if (err < 0) {
lwtstate_free(new_state);
return err;
@ -753,7 +760,6 @@ static int ip_tun_build_state(struct net *net, struct nlattr *attr,
}
tun_info->mode = IP_TUNNEL_INFO_TX;
tun_info->options_len = opt_len;
*ts = new_state;
@ -1006,7 +1012,8 @@ static int ip6_tun_build_state(struct net *net, struct nlattr *attr,
tun_info = lwt_tun_info(new_state);
err = ip_tun_set_opts(tb[LWTUNNEL_IP6_OPTS], tun_info, extack);
err = ip_tun_set_opts(tb[LWTUNNEL_IP6_OPTS], tun_info, opt_len,
extack);
if (err < 0) {
lwtstate_free(new_state);
return err;
@ -1040,7 +1047,6 @@ static int ip6_tun_build_state(struct net *net, struct nlattr *attr,
}
tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6;
tun_info->options_len = opt_len;
*ts = new_state;

View File

@ -51,6 +51,8 @@ static int tcp_ecn_mode_max = 5;
static u32 icmp_errors_extension_mask_all =
GENMASK_U8(ICMP_ERR_EXT_COUNT - 1, 0);
static int tcp_min_rcvbuf = 4096;
/* obsolete */
static int sysctl_tcp_low_latency __read_mostly;
@ -1462,7 +1464,7 @@ static const struct ctl_table ipv4_net_table[] = {
.maxlen = sizeof(init_net.ipv4.sysctl_tcp_rmem),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ONE,
.extra1 = &tcp_min_rcvbuf,
},
{
.procname = "tcp_comp_sack_delay_ns",

View File

@ -6490,6 +6490,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
* or pure receivers (this means either the sequence number or the ack
* value must stay constant)
* - Unexpected TCP option.
* - ACK sequence number is outside [SND.UNA, SND.NXT].
*
* When these conditions are not satisfied it drops into a standard
* receive procedure patterned after RFC793 to handle all cases.
@ -6539,7 +6540,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb)
if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
!after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
between(TCP_SKB_CB(skb)->ack_seq, tp->snd_una, tp->snd_nxt)) {
int tcp_header_len = tp->tcp_header_len;
s32 delta = 0;
int flag = 0;

View File

@ -136,6 +136,10 @@ static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops)
if (icsk->icsk_ulp_ops)
goto out_err;
err = -EINVAL;
if (sk_has_decrypt_user(sk))
goto out_err;
if (sk->sk_socket)
clear_bit(SOCK_SUPPORT_ZC, &sk->sk_socket->flags);

View File

@ -471,6 +471,12 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
esp->inplace = false;
/* Take real page refs and clear SKBFL_MANAGED_FRAG_REFS before
* we mutate the frag array, so the per-frag unref stays balanced
* for zerocopy managed frags (see __ip_append_data()).
*/
skb_zcopy_downgrade_managed(skb);
allocsize = ALIGN(tailen, L1_CACHE_BYTES);
spin_lock_bh(&x->lock);

View File

@ -257,10 +257,13 @@ static bool decap_and_validate(struct sk_buff *skb, int proto)
return false;
if (proto == IPPROTO_IPIP) {
bool l3slave = ipv6_l3mdev_skb(IP6CB(skb)->flags);
int iif = IP6CB(skb)->iif;
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
IPCB(skb)->iif = iif;
if (l3slave)
IPCB(skb)->flags |= IPSKB_L3SLAVE;
} else if (proto == IPPROTO_IPV6) {
bool l3slave = ipv6_l3mdev_skb(IP6CB(skb)->flags);
int iif = IP6CB(skb)->iif;

View File

@ -1604,7 +1604,8 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
by tcp. Feel free to propose better solution.
--ANK (980728)
*/
if (np->rxopt.all && sk->sk_state != TCP_LISTEN)
if (np->rxopt.all &&
!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)))
opt_skb = skb_clone_and_charge_r(skb, sk);
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */

View File

@ -19,7 +19,10 @@
void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)
{
struct flowi6 fl6;
struct sock *sk = skb->sk;
struct sock *sk = skb_to_full_sk(skb);
if (!sk)
return;
fl6.flowi6_oif = sk->sk_bound_dev_if;
fl6.daddr = ipv6_hdr(skb)->daddr;
@ -31,7 +34,10 @@ void xfrm6_local_error(struct sk_buff *skb, u32 mtu)
{
struct flowi6 fl6;
const struct ipv6hdr *hdr;
struct sock *sk = skb->sk;
struct sock *sk = skb_to_full_sk(skb);
if (!sk)
return;
hdr = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
fl6.fl6_dport = inet_sk(sk)->inet_dport;

View File

@ -115,6 +115,10 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
return -EBUSY;
}
/* TXQs are reserved in ieee80211_if_add() and cannot be added later */
if ((params->flags & MONITOR_FLAG_ACTIVE) && !sdata->vif.txq)
return -EOPNOTSUPP;
/* validate whether MU-MIMO can be configured */
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
@ -1929,6 +1933,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
return 0;
error:
link_conf->enable_beacon = false;
link_conf->beacon_int = prev_beacon_int;
sdata->vif.cfg.ssid_len = 0;
ieee80211_link_release_channel(link);
return err;
@ -3320,7 +3327,11 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
if (err)
return err;
return ieee80211_start_mesh(sdata);
err = ieee80211_start_mesh(sdata);
if (err)
ieee80211_link_release_channel(&sdata->deflink);
return err;
}
static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
@ -3475,7 +3486,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
static int ieee80211_suspend(struct wiphy *wiphy,
struct cfg80211_wowlan *wowlan)
{
return __ieee80211_suspend(wiphy_priv(wiphy), wowlan);
return __ieee80211_suspend(wiphy_priv(wiphy), wowlan, false);
}
static int ieee80211_resume(struct wiphy *wiphy)
@ -4113,6 +4124,9 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;
if (!(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
return -ENETDOWN;
/*
* If active validate the setting and reject it if it doesn't leave
* at least one basic rate usable, since we really have to be able

View File

@ -384,7 +384,7 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf,
rtnl_lock();
wiphy_lock(local->hw.wiphy);
__ieee80211_suspend(&local->hw, NULL);
__ieee80211_suspend(&local->hw, NULL, true);
ret = __ieee80211_resume(&local->hw);
wiphy_unlock(local->hw.wiphy);

View File

@ -657,6 +657,9 @@ static ssize_t ieee80211_if_fmt_tsf(
struct ieee80211_local *local = sdata->local;
u64 tsf;
if (!ieee80211_sdata_running((struct ieee80211_sub_if_data *)sdata))
return -ENETDOWN;
tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
@ -670,6 +673,9 @@ static ssize_t ieee80211_if_parse_tsf(
int ret;
int tsf_is_delta = 0;
if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;
if (strncmp(buf, "reset", 5) == 0) {
if (local->ops->reset_tsf) {
drv_reset_tsf(local, sdata);
@ -729,6 +735,9 @@ static ssize_t ieee80211_if_parse_active_links(struct ieee80211_sub_if_data *sda
if (kstrtou16(buf, 0, &active_links) || !active_links)
return -EINVAL;
if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;
return ieee80211_set_active_links(&sdata->vif, active_links) ?: buflen;
}
IEEE80211_IF_FILE_RW(active_links);

View File

@ -2432,7 +2432,7 @@ int ieee80211_reconfig(struct ieee80211_local *local);
void ieee80211_stop_device(struct ieee80211_local *local, bool suspend);
int __ieee80211_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan);
struct cfg80211_wowlan *wowlan, bool reset);
static inline int __ieee80211_resume(struct ieee80211_hw *hw)
{

View File

@ -616,6 +616,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
RCU_INIT_POINTER(sdata->vif.bss_conf.chanctx_conf, NULL);
/* see comment in the default case below */
ieee80211_free_keys(sdata, true);
/* increased by AP value on ifup, so reset on ifdown */
sdata->crypto_tx_tailroom_needed_cnt = 0;
/* no need to tell driver */
break;
case NL80211_IFTYPE_MONITOR:
@ -924,9 +926,33 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
}
}
/*
* The netdev can be unregistered without mac80211 doing it, e.g. by the netdev
* core when cfg80211 couldn't move it out of a network namespace that's being
* destroyed. Drop it from the interface list either way.
*/
static void ieee80211_unlist_sdata(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *iter;
ASSERT_RTNL();
list_for_each_entry(iter, &local->interfaces, list) {
if (iter != sdata)
continue;
guard(mutex)(&local->iflist_mtx);
list_del_rcu(&sdata->list);
return;
}
}
static void ieee80211_uninit(struct net_device *dev)
{
ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_unlist_sdata(sdata);
ieee80211_teardown_sdata(sdata);
}
static int ieee80211_netdev_setup_tc(struct net_device *dev,
@ -935,6 +961,9 @@ static int ieee80211_netdev_setup_tc(struct net_device *dev,
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
return -EOPNOTSUPP;
return drv_net_setup_tc(local, sdata, dev, type, type_data);
}
@ -964,7 +993,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
/* reset flags and info before parsing radiotap header */
memset(info, 0, sizeof(*info));
if (!ieee80211_parse_tx_radiotap(skb, dev))
if (!ieee80211_parse_tx_radiotap(skb, dev, NULL))
return 0; /* doesn't matter, frame will be dropped */
len_rthdr = ieee80211_get_radiotap_len(skb->data);
@ -1603,8 +1632,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
err_del_interface:
drv_remove_interface(local, sdata);
err_stop:
if (!local->open_count)
if (!local->open_count) {
ieee80211_led_radio(local, false);
ieee80211_mod_tpt_led_trig(local, 0,
IEEE80211_TPT_LEDTRIG_FL_RADIO);
drv_stop(local, false);
}
if (sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)

View File

@ -1453,6 +1453,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
sizeof(struct ieee80211_he_mcs_nss_supp) +
IEEE80211_HE_PPE_THRES_MAX_LEN;
if (local->hw.wiphy->bands[NL80211_BAND_6GHZ])
local->scan_ies_len +=
3 + sizeof(struct ieee80211_he_6ghz_capa);
if (supp_eht)
local->scan_ies_len +=
3 + sizeof(struct ieee80211_eht_cap_elem) +

View File

@ -1196,6 +1196,21 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
return 0;
}
static void ieee80211_mesh_reset_csa(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct mesh_csa_settings *csa;
/* Reset the TTL value and Initiator flag */
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
ifmsh->chsw_ttl = 0;
/* Remove the CSA and MCSP elements from the beacon */
csa = sdata_dereference(ifmsh->csa, sdata);
RCU_INIT_POINTER(ifmsh->csa, NULL);
kfree_rcu(csa, rcu_head);
}
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
@ -1204,6 +1219,11 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
netif_carrier_off(sdata->dev);
/* abort any running channel switch */
sdata->vif.bss_conf.csa_active = false;
ieee80211_mesh_reset_csa(sdata);
ieee80211_vif_unblock_queues_csa(sdata);
/* flush STAs and mpaths on this iface */
sta_info_flush(sdata, -1);
ieee80211_free_keys(sdata, true);
@ -1510,19 +1530,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata, u64 *changed)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct mesh_csa_settings *tmp_csa_settings;
int ret = 0;
int ret;
/* Reset the TTL value and Initiator flag */
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
ifmsh->chsw_ttl = 0;
ieee80211_mesh_reset_csa(sdata);
/* Remove the CSA and MCSP elements from the beacon */
tmp_csa_settings = sdata_dereference(ifmsh->csa, sdata);
RCU_INIT_POINTER(ifmsh->csa, NULL);
if (tmp_csa_settings)
kfree_rcu(tmp_csa_settings, rcu_head);
ret = ieee80211_mesh_rebuild_beacon(sdata);
if (ret)
return -EINVAL;
@ -1555,7 +1566,6 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
ret = ieee80211_mesh_rebuild_beacon(sdata);
if (ret) {
tmp_csa_settings = rcu_dereference(ifmsh->csa);
RCU_INIT_POINTER(ifmsh->csa, NULL);
kfree_rcu(tmp_csa_settings, rcu_head);
return ret;

View File

@ -460,6 +460,13 @@ static void __ieee80211_roc_work(struct ieee80211_local *local)
return;
if (!roc->started) {
/*
* The work can be started by a previous ROC work, but a scan
* can get between things; scan finish will retrigger us.
*/
if (local->scanning)
return;
WARN_ON(!local->emulate_chanctx);
_ieee80211_start_next_roc(local);
} else {

View File

@ -18,7 +18,8 @@ static void ieee80211_sched_scan_cancel(struct ieee80211_local *local)
cfg80211_sched_scan_stopped_locked(local->hw.wiphy, 0);
}
int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan,
bool reset)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
@ -166,9 +167,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
/*
* We disconnected on all interfaces before suspend, all channel
* contexts should be released.
* contexts should be released, but on 'reset' debugfs that's
* not true so don't check there.
*/
WARN_ON(!list_empty(&local->chanctx_list));
WARN_ON(!reset && !list_empty(&local->chanctx_list));
/* stop hardware - this must stop RX */
ieee80211_stop_device(local, true);

View File

@ -372,6 +372,14 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
u32 rate_flags = 0;
int i;
/*
* Frames that shouldn't use the rate mask could be anything,
* even on a different band, so don't take the sta into account
* to avoid ending up without rates.
*/
if (info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)
sta = NULL;
if (sband->band == NL80211_BAND_S1GHZ) {
info->control.rates[0].flags |= IEEE80211_TX_RC_S1G_MCS;
info->control.rates[0].idx = 0;

View File

@ -1242,7 +1242,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
}
}
if (WARN_ON_ONCE(n_ch == 0))
if (n_ch == 0)
return -EINVAL;
local->int_scan_req->n_channels = n_ch;

View File

@ -1142,6 +1142,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = sdata->local;
enum ieee80211_smps_mode smps_mode =
sdata->deflink.u.mgd.driver_smps_mode;
struct sta_info *sta;
int ret;
/* don't support setup with forced SMPS mode that's not off */
@ -1168,14 +1169,10 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
* Allow error packets to be sent - sometimes we don't even add a STA
* before failing the setup.
*/
if (status_code == 0) {
rcu_read_lock();
if (!sta_info_get(sdata, peer)) {
rcu_read_unlock();
ret = -ENOLINK;
goto out_unlock;
}
rcu_read_unlock();
sta = sta_info_get(sdata, peer);
if ((status_code == 0 && !sta) || (sta && !sta->sta.tdls)) {
ret = -ENOLINK;
goto out_unlock;
}
ieee80211_flush_queues(local, sdata, false);
@ -1284,6 +1281,24 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
peer_capability, initiator,
extra_ies, extra_ies_len);
break;
case WLAN_TDLS_SETUP_CONFIRM: {
struct sta_info *sta;
sta = sta_info_get(sdata, peer);
if (!sta || !sta->sta.tdls) {
ret = -ENOLINK;
break;
}
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
link_id, action_code,
dialog_token,
status_code,
peer_capability,
initiator, extra_ies,
extra_ies_len, 0, NULL);
break;
}
case WLAN_TDLS_DISCOVERY_REQUEST:
/*
* Protect the discovery so we can hear the TDLS discovery
@ -1292,7 +1307,6 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
*/
drv_mgd_protect_tdls_discover(sdata->local, sdata, link_id);
fallthrough;
case WLAN_TDLS_SETUP_CONFIRM:
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
/* no special handling */
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
@ -1442,6 +1456,10 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
*/
tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
sta = sta_info_get(sdata, peer);
if (!sta || !sta->sta.tdls)
return -ENOLINK;
switch (oper) {
case NL80211_TDLS_ENABLE_LINK:
if (sdata->vif.bss_conf.csa_active) {
@ -1449,10 +1467,6 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
return -EBUSY;
}
sta = sta_info_get(sdata, peer);
if (!sta || !sta->sta.tdls)
return -ENOLINK;
iee80211_tdls_recalc_chanctx(sdata, sta);
iee80211_tdls_recalc_ht_protection(sdata, sta);

View File

@ -744,10 +744,12 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
/*
* Lets not bother rate control if we're associated and cannot
* talk to the sta. This should not happen.
* Lets not bother rate control if we're associated and cannot talk to
* the sta. This should not happen - except for frames that aren't
* really for the peer to start with and already ignore rates.
*/
if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
if (!(info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK) &&
WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
!rate_usable_index_exists(sband, &tx->sta->sta),
"%s: Dropped data frame as no usable bitrate found while "
"scanning and associated. Target station: "
@ -2103,8 +2105,29 @@ static bool ieee80211_validate_radiotap_len(struct sk_buff *skb)
return true;
}
static bool ieee80211_rate_bw_usable(u16 rate_flags,
const struct cfg80211_chan_def *chandef)
{
int width;
if (!chandef)
return true;
if (rate_flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
width = 160;
else if (rate_flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
width = 80;
else if (rate_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
width = 40;
else
return true;
return width <= cfg80211_chandef_get_width(chandef);
}
bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
struct net_device *dev)
struct net_device *dev,
const struct cfg80211_chan_def *chandef)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_radiotap_iterator iterator;
@ -2278,6 +2301,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[info->band];
if (!ieee80211_rate_bw_usable(rate_flags, chandef))
return false;
info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
@ -2477,7 +2503,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
* selected chandef above to accurately set injection rates and
* retransmissions.
*/
if (!ieee80211_parse_tx_radiotap(skb, dev))
if (!ieee80211_parse_tx_radiotap(skb, dev, chandef))
goto fail_rcu;
/* remove the injection radiotap header */
@ -2955,10 +2981,23 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
*/
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb)) {
ret = -ENOMEM;
goto free;
/* skb_share_check() already freed the skb */
if (info_id)
ieee80211_remove_ack_skb(local, info_id);
return ERR_PTR(-ENOMEM);
}
/* set this up so failure paths can clean up ack skb */
info = IEEE80211_SKB_CB(skb);
memset(info, 0, sizeof(*info));
info->flags = info_flags;
if (info_id) {
info->status_data = info_id;
info->status_data_idr = 1;
}
info->band = band;
hdr.frame_control = fc;
hdr.duration_id = 0;
hdr.seq_ctrl = 0;
@ -2997,10 +3036,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
head_need += local->tx_headroom;
head_need = max_t(int, 0, head_need);
if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) {
ieee80211_free_txskb(&local->hw, skb);
skb = NULL;
ret = -ENOMEM;
goto free;
goto free_txskb;
}
}
@ -3027,16 +3064,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
skb_reset_mac_header(skb);
info = IEEE80211_SKB_CB(skb);
memset(info, 0, sizeof(*info));
info->flags = info_flags;
if (info_id) {
info->status_data = info_id;
info->status_data_idr = 1;
}
info->band = band;
if (likely(!cookie)) {
ctrl_flags |= u32_encode_bits(link_id,
IEEE80211_TX_CTRL_MLO_LINK);
@ -3060,16 +3087,17 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
pre_conf_link_id, link_id);
#endif
ret = -EINVAL;
goto free;
goto free_txskb;
}
}
info->control.flags = ctrl_flags;
return skb;
free_txskb:
ieee80211_free_txskb(&local->hw, skb);
return ERR_PTR(ret);
free:
if (info_id)
ieee80211_remove_ack_skb(local, info_id);
kfree_skb(skb);
return ERR_PTR(ret);
}
@ -5089,10 +5117,18 @@ static void ieee80211_beacon_add_tim_pvb(struct ps_data *ps,
*/
static void ieee80211_s1g_beacon_add_tim_pvb(struct ps_data *ps,
struct sk_buff *skb,
bool mcast_traffic)
bool mcast_traffic,
bool ucast_traffic)
{
int blk;
/*
* if no unicast and multicast traffic don't emit a bitmap control
* or pvb
*/
if (!mcast_traffic && !ucast_traffic)
return;
/*
* Emit a bitmap control block with a page slice number of 31 and a
* page index of 0 which indicates as per IEEE80211-2024 9.4.2.5.1
@ -5101,6 +5137,10 @@ static void ieee80211_s1g_beacon_add_tim_pvb(struct ps_data *ps,
*/
skb_put_u8(skb, mcast_traffic | (31 << 1));
/* If there's no unicast traffic we don't need to include a PVB. */
if (!ucast_traffic)
return;
/* Emit an encoded block for each non-zero sub-block */
for (blk = 0; blk < IEEE80211_MAX_SUPPORTED_S1G_TIM_BLOCKS; blk++) {
u8 blk_bmap = 0;
@ -5182,25 +5222,16 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
ps->dtim_bc_mc = mcast_traffic;
if (have_bits) {
if (s1g)
ieee80211_s1g_beacon_add_tim_pvb(ps, skb,
mcast_traffic);
else
ieee80211_beacon_add_tim_pvb(ps, skb, mcast_traffic);
if (s1g) {
ieee80211_s1g_beacon_add_tim_pvb(ps, skb, mcast_traffic,
have_bits);
} else if (have_bits) {
ieee80211_beacon_add_tim_pvb(ps, skb, mcast_traffic);
} else {
/*
* If there is no buffered unicast traffic for an S1G
* interface, we can exclude the bitmap control. This is in
* contrast to other phy types as they do include the bitmap
* control and pvb even when there is no buffered traffic.
*/
if (!s1g) {
/* Bitmap control */
skb_put_u8(skb, mcast_traffic);
/* Part Virt Bitmap */
skb_put_u8(skb, 0);
}
/* Bitmap control */
skb_put_u8(skb, mcast_traffic);
/* Part Virt Bitmap */
skb_put_u8(skb, 0);
}
tim->datalen = skb_tail_pointer(skb) - tim->data;

View File

@ -856,12 +856,12 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,
mptcp_dss_corruption(msk, ssk);
}
} else {
sk_eat_skb(ssk, skb);
if (unlikely(!fin)) {
DEBUG_NET_WARN_ON_ONCE(1);
mptcp_dss_corruption(msk, ssk);
}
sk_eat_skb(ssk, skb);
}
WRITE_ONCE(tp->copied_seq, seq);
@ -1664,7 +1664,9 @@ struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
static void mptcp_push_release(struct sock *ssk, struct mptcp_sendmsg_info *info)
{
tcp_push(ssk, 0, info->mss_now, tcp_sk(ssk)->nonagle, info->size_goal);
if (info->mss_now)
tcp_push(ssk, 0, info->mss_now, tcp_sk(ssk)->nonagle,
info->size_goal);
release_sock(ssk);
}
@ -1852,7 +1854,8 @@ static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk, bool
ret = __subflow_push_pending(sk, ssk, &info);
if (ret <= 0)
keep_pushing = false;
copied += ret;
else
copied += ret;
}
mptcp_for_each_subflow(msk, subflow) {
@ -2459,7 +2462,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
mptcp_cleanup_rbuf(msk, copied);
err = sk_wait_data(sk, &timeo, last);
if (err < 0) {
err = copied ? : err;
copied = copied ? : err;
goto out_err;
}
}

View File

@ -585,7 +585,8 @@ struct mptcp_subflow_context {
is_mptfo : 1, /* subflow is doing TFO */
close_event_done : 1, /* has done the post-closed part */
mpc_drop : 1, /* the MPC option has been dropped in a rtx */
__unused : 9;
resetting : 1, /* subflow is resetting */
__unused : 8;
bool data_avail;
bool scheduled;
bool pm_listener; /* a listener managed by the kernel PM? */

View File

@ -438,6 +438,10 @@ void mptcp_subflow_reset(struct sock *ssk)
/* must hold: tcp_done() could drop last reference on parent */
sock_hold(sk);
subflow->resetting = 1;
/* No need to delay the actual close for to-be discarded data. */
__skb_queue_purge(&ssk->sk_receive_queue);
mptcp_send_active_reset_reason(ssk);
tcp_done(ssk);
if (!test_and_set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &mptcp_sk(sk)->flags))
@ -1883,6 +1887,13 @@ static void subflow_state_change(struct sock *sk)
__subflow_state_change(sk);
/* Rx queue processing is unneeded, error reporting will take place at
* __mptcp_close_ssk() time and subflow reset can't happen in case of
* fallback: subflow_sched_work_if_closed() would be a no-op.
*/
if (subflow->resetting)
return;
/* as recvmsg() does not acquire the subflow socket for ssk selection
* a fin packet carrying a DSS can be unnoticed if we don't trigger
* the data available machinery here.

View File

@ -258,6 +258,14 @@ static void flow_offload_route_release(struct flow_offload *flow)
nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_REPLY);
}
static void flow_offload_free_rcu(struct rcu_head *rcu_head)
{
struct flow_offload *flow = container_of(rcu_head, struct flow_offload, rcu_head);
nf_ct_put(flow->ct);
kfree(flow);
}
void flow_offload_free(struct flow_offload *flow)
{
switch (flow->type) {
@ -267,8 +275,7 @@ void flow_offload_free(struct flow_offload *flow)
default:
break;
}
nf_ct_put(flow->ct);
kfree_rcu(flow, rcu_head);
call_rcu(&flow->rcu_head, flow_offload_free_rcu);
}
EXPORT_SYMBOL_GPL(flow_offload_free);
@ -854,6 +861,7 @@ static int __init nf_flow_table_module_init(void)
static void __exit nf_flow_table_module_exit(void)
{
rcu_barrier();
nf_flow_table_offload_exit();
unregister_pernet_subsys(&nf_flow_table_net_ops);
kmem_cache_destroy(flow_offload_cachep);

View File

@ -1224,31 +1224,45 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
}
ret = nf_register_net_hooks(net, nat_ops, ops_count);
if (ret < 0) {
mutex_unlock(&nf_nat_proto_mutex);
for (i = 0; i < ops_count; i++) {
priv = nat_ops[i].priv;
kfree_rcu(priv, rcu_head);
}
kfree_rcu(nat_ops, rcu);
return ret;
}
nat_proto_net->nat_hook_ops = nat_ops;
if (ret < 0)
goto err_free_hooks;
} else {
nat_ops = nat_proto_net->nat_hook_ops;
}
nat_ops = nat_proto_net->nat_hook_ops;
priv = nat_ops[hooknum].priv;
if (WARN_ON_ONCE(!priv)) {
mutex_unlock(&nf_nat_proto_mutex);
return -EOPNOTSUPP;
ret = -EOPNOTSUPP;
goto err_unregister_hooks;
}
ret = nf_hook_entries_insert_raw(&priv->entries, ops);
if (ret == 0)
nat_proto_net->users++;
if (ret)
goto err_unregister_hooks;
if (!nat_proto_net->nat_hook_ops)
nat_proto_net->nat_hook_ops = nat_ops;
nat_proto_net->users++;
mutex_unlock(&nf_nat_proto_mutex);
return 0;
err_unregister_hooks:
if (nat_proto_net->nat_hook_ops) {
mutex_unlock(&nf_nat_proto_mutex);
return ret;
}
nf_unregister_net_hooks(net, nat_ops, ops_count);
err_free_hooks:
mutex_unlock(&nf_nat_proto_mutex);
for (i = 0; i < ops_count; i++) {
priv = nat_ops[i].priv;
kfree_rcu(priv, rcu_head);
}
kfree_rcu(nat_ops, rcu);
return ret;
}

Some files were not shown because too many files have changed in this diff Show More