Including fixes from Wireless, IPsec, Netfilter and Bluetooth.

Current release - new code bugs:
 
   - netfilter: flowtable: use correct direction to set up tunnel route
 
 Previous releases - regressions:
 
   - wifi:
     - mac80211:
       - free AP_VLAN bc_buf SKBs outside IRQ lock
       - defer link RX stats percpu free to RCU
       - fix double free on alloc failure
     - cfg80211: convert pmsr_free_wk to wiphy_work to fix deadlock
 
   - ipv4: free fib_alias with kfree_rcu() on insert error path
 
   - sched: act_tunnel_key: Defer dst_release to RCU callback
 
   - xfrm: fix sk_dst_cache double-free in xfrm_user_policy()
 
   - bluetooth: fix locking in unpair_device/disconnect_sync
 
   - can: add locking for raw flags bitfield
 
   - openvswitch: reject oversized nested action attrs
 
   - eth: bnxt_en: handle partially initialized auxiliary devices
 
   - eth: ppp: defer channel free to an RCU grace period to fix UAF
 
 Previous releases - always broken:
 
   -  netfilter: xt_nat: reject unsupported target families
 
   -  wifi:
      - brcmfmac: fix heap overflow on a short auth frame
      - cfg80211: add missing FTM API validation
 
   - xfrm:
     - reject optional IPTFS templates in outbound policies
     - policy: preallocate inexact bins before xfrm_hash_rebuild reinsert
 
   - bluetooth: revalidate LOAD_CONN_PARAM queued update
 
   - can: fix lockless bound/ifindex race and silent RX_SETUP failure
 
   - eth: mlx5: free mlx5_st_idx_data on final dealloc
 
 Signed-off-by: Paolo Abeni <pabeni@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCgAwFiEEg1AjqC77wbdLX2LbKSR5jcyPE6QFAmpaK6YSHHBhYmVuaUBy
 ZWRoYXQuY29tAAoJECkkeY3MjxOks1UQAIHudLSXUxTTf+MktIkdEHkJFAaokN6s
 haDwhoi5rxQqigZ883Y6V4AShPnV2HawMaNhGa9biqJ9N4QP9ahPsQbT5mrBNrGx
 Vse9y73L69/6pT2wbpBHKmmiGRR/0BxGICFHPUlmX2Zdzc+nwlArt+5Zlhmzbg/q
 +eSuRylnGv8Y82oQOSxMjf5WZyAsW55tLYLBRpOUeNY6GTWpkecPqCUTCAj3Sn6t
 IQHkFbNVDM6i0oFr117J94a/Q5pSrO17W+GxwS0b5t9Ly1txJYAtfiSGjXToS7aJ
 TXnsGbqUZ1bqc87Z5ZBucw9LGpnyZ6ui8Z0+oAS24RxFf6eJUTo8+ULbGBBYCyIH
 Xk5wQbAz1bms37s01VRsGyUyC1VCiYjSpUT5AZf3vWJfhFNBpVQTMj0IVQsoktZO
 ryxypbYgRUB7DQe9GXyheSoEuLkH5XECQ5GyQ4t6gcMtJrBu6XtPU/EUlf6GLT2s
 kW3VKn4Oc2t3hpEDxs2y2pE93QezdTFQU5ecs2hWSUMn00DMLoj100uODCBwIu/L
 9f50TWA+koAMKyTNu36Zd0QdsrMLRzux+lSScBgIb1WxXWq9aXemV/vZNnmjdtlJ
 CIWFM9AIxhXkL9t9l/8o9tBEaKb0WBQJY4TiCRxs3AwKzKK59ZB+PJ4DZt47YUyC
 i56jtKMYTAT4
 =KH/H
 -----END PGP SIGNATURE-----

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

Pull networking fixes from Paolo Abeni:
 "Including fixes from Wireless, IPsec, Netfilter and Bluetooth.

  Current release - new code bugs:

    - netfilter: flowtable: use correct direction to set up tunnel route

  Previous releases - regressions:

    - wifi:
       - mac80211:
          - free AP_VLAN bc_buf SKBs outside IRQ lock
          - defer link RX stats percpu free to RCU
          - fix double free on alloc failure
       - cfg80211: convert pmsr_free_wk to wiphy_work to fix deadlock

    - ipv4: free fib_alias with kfree_rcu() on insert error path

    - sched: act_tunnel_key: Defer dst_release to RCU callback

    - xfrm: fix sk_dst_cache double-free in xfrm_user_policy()

    - bluetooth: fix locking in unpair_device/disconnect_sync

    - can: add locking for raw flags bitfield

    - openvswitch: reject oversized nested action attrs

    - eth:
       - bnxt_en: handle partially initialized auxiliary devices
       - ppp: defer channel free to an RCU grace period to fix UAF

  Previous releases - always broken:

    -  netfilter: xt_nat: reject unsupported target families

    -  wifi:
        - brcmfmac: fix heap overflow on a short auth frame
        - cfg80211: add missing FTM API validation

    - xfrm:
       - reject optional IPTFS templates in outbound policies
       - policy: preallocate inexact bins before xfrm_hash_rebuild reinsert

    - bluetooth: revalidate LOAD_CONN_PARAM queued update

    - can: fix lockless bound/ifindex race and silent RX_SETUP failure

    - eth: mlx5: free mlx5_st_idx_data on final dealloc"

* tag 'net-7.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (108 commits)
  mpls: fix NULL deref in mpls_valid_fib_dump_req() on CONFIG_INET=n
  llc: fix SAP refcount leak when creating incoming sockets
  selftests: netconsole: only restore MAC when it changed on resume
  bnxt_en: Handle partially initialized auxiliary devices
  sctp: fix auth_hmacs array size in struct sctp_cookie
  net/sched: act_tunnel_key: Defer dst_release to RCU callback
  dpll: fix NULL pointer dereference in dpll_msg_add_pin_ref_sync()
  tcp: fix TIME_WAIT socket reference leak on PSP policy failure
  net/mlx5: free mlx5_st_idx_data on final dealloc
  can: isotp: serialize TX state transitions under so->rx_lock
  can: isotp: fix use-after-free race with concurrent NETDEV_UNREGISTER
  can: isotp: use unconditional synchronize_rcu() in isotp_release()
  can: bcm: track a single source interface for ANYDEV timeout/throttle ops
  can: bcm: fix data race on rx_stamp/rx_ifindex in bcm_rx_handler()
  can: bcm: fix stale rx/tx ops after device removal
  can: bcm: add missing device refcount for CAN filter removal
  can: bcm: validate frame length in bcm_rx_setup() for RTR replies
  can: bcm: extend bcm_tx_lock usage for data and timer updates
  can: bcm: add missing rcu list annotations and operations
  can: bcm: fix CAN frame rx/tx statistics
  ...
This commit is contained in:
Linus Torvalds 2026-07-17 10:25:13 -07:00
commit e13caf1c26
98 changed files with 1688 additions and 608 deletions

View File

@ -826,8 +826,8 @@ Sriram Yagnaraman <sriram.yagnaraman@ericsson.com> <sriram.yagnaraman@est.tech>
Stanislav Fomichev <sdf@fomichev.me> <sdf@google.com>
Stanislav Fomichev <sdf@fomichev.me> <stfomichev@gmail.com>
Stefan Wahren <wahrenst@gmx.net> <stefan.wahren@i2se.com>
Stéphane Grosjean <stephane.grosjean@hms-networks.com> <s.grosjean@peak-system.com>
Stéphane Grosjean <stephane.grosjean@hms-networks.com> <stephane.grosjean@free.fr>
Stéphane Grosjean <s.grosjean@peak-system.fr> <s.grosjean@peak-system.com>
Stéphane Grosjean <s.grosjean@peak-system.fr> <stephane.grosjean@free.fr>
Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
Stephen Hemminger <stephen@networkplumber.org> <shemminger@linux-foundation.org>
Stephen Hemminger <stephen@networkplumber.org> <shemminger@osdl.org>

View File

@ -415,7 +415,7 @@ static int qca_tlv_check_data(struct hci_dev *hdev,
idx = 0;
data = tlv->data;
while (idx < length - sizeof(struct tlv_type_nvm)) {
while (idx + sizeof(struct tlv_type_nvm) <= length) {
tlv_nvm = (struct tlv_type_nvm *)(data + idx);
tag_id = le16_to_cpu(tlv_nvm->tag_id);

View File

@ -797,8 +797,9 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
}
BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
min_size = patch_offset + patch_length;
if (btrtl_dev->fw_len < min_size)
if (patch_length < sizeof(epatch_info->fw_version) ||
patch_offset > btrtl_dev->fw_len ||
patch_length > btrtl_dev->fw_len - patch_offset)
return -EINVAL;
/* Copy the firmware into a new buffer and write the version at

View File

@ -1087,6 +1087,10 @@ static void qca_controller_memdump(struct work_struct *work)
if (!(qca_memdump->ram_dump_size)) {
bt_dev_err(hu->hdev, "Rx invalid memdump size");
kfree(qca_memdump);
qca->qca_memdump = NULL;
qca->memdump_state = QCA_MEMDUMP_COLLECTED;
clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
clear_bit(QCA_IBS_DISABLED, &qca->flags);
kfree_skb(skb);
mutex_unlock(&qca->hci_memdump_lock);
return;

View File

@ -567,6 +567,9 @@ dpll_msg_add_pin_ref_sync(struct sk_buff *msg, struct dpll_pin *pin,
if (!dpll_pin_available(ref_sync_pin))
continue;
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)
continue;
if (WARN_ON(!ops->ref_sync_get))
return -EOPNOTSUPP;
ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin,

View File

@ -40,11 +40,8 @@ config CAN_VXCAN
When one end receives the packet it appears on its pair and vice
versa. The vxcan can be used for cross namespace communication.
In opposite to vcan loopback devices the vxcan only forwards CAN
frames to its pair and does *not* provide a local echo of sent
CAN frames. To disable a potential echo in af_can.c the vxcan driver
announces IFF_ECHO in the interface flags. To have a clean start
in each namespace the CAN GW hop counter is set to zero.
To have a clean start in each namespace the CAN GW hop counter is
set to zero.
This driver can also be built as a module. If so, the module
will be called vxcan.

View File

@ -2,7 +2,7 @@
/* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
*
* Copyright (C) 2016-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*/
#include <linux/can.h>

View File

@ -2,7 +2,7 @@
/* CAN driver for PEAK System micro-CAN based adapters
*
* Copyright (C) 2003-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*/
#ifndef PEAK_CANFD_USER_H
#define PEAK_CANFD_USER_H

View File

@ -4,7 +4,7 @@
* Derived from the PCAN project file driver/src/pcan_pci.c:
*
* Copyright (C) 2001-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*/
#include <linux/kernel.h>
@ -19,7 +19,7 @@
#include "peak_canfd_user.h"
MODULE_AUTHOR("Stéphane Grosjean <stephane.grosjean@hms-networks.com>");
MODULE_AUTHOR("Stéphane Grosjean <s.grosjean@peak-system.fr>");
MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCIe/M.2 FD family cards");
MODULE_LICENSE("GPL v2");

View File

@ -5,7 +5,7 @@
* Derived from the PCAN project file driver/src/pcan_pci.c:
*
* Copyright (C) 2001-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*/
#include <linux/kernel.h>
@ -22,7 +22,7 @@
#include "sja1000.h"
MODULE_AUTHOR("Stéphane Grosjean <stephane.grosjean@hms-networks.com>");
MODULE_AUTHOR("Stéphane Grosjean <s.grosjean@peak-system.fr>");
MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards");
MODULE_LICENSE("GPL v2");

View File

@ -4,7 +4,7 @@
* Derived from the PCAN project file driver/src/pcan_pccard.c
*
* Copyright (C) 2006-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*/
#include <linux/kernel.h>
#include <linux/module.h>
@ -19,7 +19,7 @@
#include <linux/can/dev.h>
#include "sja1000.h"
MODULE_AUTHOR("Stéphane Grosjean <stephane.grosjean@hms-networks.com>");
MODULE_AUTHOR("Stéphane Grosjean <s.grosjean@peak-system.fr>");
MODULE_DESCRIPTION("CAN driver for PEAK-System PCAN-PC Cards");
MODULE_LICENSE("GPL v2");

View File

@ -1390,10 +1390,13 @@ static void esd_usb_disconnect(struct usb_interface *intf)
netdev = dev->nets[i]->netdev;
netdev_info(netdev, "unregister\n");
unregister_netdev(netdev);
free_candev(netdev);
}
}
unlink_all_urbs(dev);
for (i = 0; i < dev->net_count; i++) {
if (dev->nets[i])
free_candev(dev->nets[i]->netdev);
}
kfree(dev);
}
}

View File

@ -4,7 +4,7 @@
* Derived from the PCAN project file driver/src/pcan_usb.c
*
* Copyright (C) 2003-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
*/

View File

@ -4,7 +4,7 @@
* Derived from the PCAN project file driver/src/pcan_usb_core.c
*
* Copyright (C) 2003-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
*/
@ -24,7 +24,7 @@
#include "pcan_usb_core.h"
MODULE_AUTHOR("Stéphane Grosjean <stephane.grosjean@hms-networks.com>");
MODULE_AUTHOR("Stéphane Grosjean <s.grosjean@peak-system.fr>");
MODULE_DESCRIPTION("CAN driver for PEAK-System USB adapters");
MODULE_LICENSE("GPL v2");

View File

@ -4,7 +4,7 @@
* Derived from the PCAN project file driver/src/pcan_usb_core.c
*
* Copyright (C) 2003-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
*/

View File

@ -3,7 +3,7 @@
* CAN driver for PEAK System PCAN-USB FD / PCAN-USB Pro FD adapter
*
* Copyright (C) 2013-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*/
#include <linux/ethtool.h>
#include <linux/module.h>

View File

@ -4,7 +4,7 @@
* Derived from the PCAN project file driver/src/pcan_usbpro.c
*
* Copyright (C) 2003-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*/
#include <linux/ethtool.h>
#include <linux/module.h>

View File

@ -4,7 +4,7 @@
* Derived from the PCAN project file driver/src/pcan_usbpro_fw.h
*
* Copyright (C) 2003-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*/
#ifndef PCAN_USB_PRO_H
#define PCAN_USB_PRO_H

View File

@ -566,6 +566,18 @@ void bnxt_aux_devices_init(struct bnxt *bp)
if (!aux_priv)
goto next_auxdev;
edev = kzalloc_obj(*edev);
if (!edev)
goto aux_priv_free;
aux_priv->edev = edev;
bnxt_set_edev_info(edev, bp);
ulp = kzalloc_obj(*ulp);
if (!ulp)
goto edev_free;
edev->ulp_tbl = ulp;
aux_priv->id = idx;
aux_dev = &aux_priv->aux_dev;
aux_dev->id = bp->auxdev_id;
aux_dev->name = bnxt_aux_devices[idx].name;
@ -573,37 +585,26 @@ void bnxt_aux_devices_init(struct bnxt *bp)
aux_dev->dev.release = bnxt_aux_dev_release;
rc = auxiliary_device_init(aux_dev);
if (rc) {
kfree(aux_priv);
goto next_auxdev;
}
if (rc)
goto ulp_free;
bp->aux_priv[idx] = aux_priv;
/* From this point, all cleanup will happen via the .release
* callback & any error unwinding will need to include a call
* to auxiliary_device_uninit.
*/
edev = kzalloc_obj(*edev);
if (!edev)
goto aux_dev_uninit;
aux_priv->edev = edev;
bnxt_set_edev_info(edev, bp);
ulp = kzalloc_obj(*ulp);
if (!ulp)
goto aux_dev_uninit;
edev->ulp_tbl = ulp;
bp->edev[idx] = edev;
if (idx == BNXT_AUXDEV_RDMA)
bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp);
aux_priv->id = idx;
bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT);
continue;
aux_dev_uninit:
auxiliary_device_uninit(aux_dev);
ulp_free:
kfree(ulp);
edev_free:
kfree(edev);
aux_priv_free:
kfree(aux_priv);
next_auxdev:
if (idx == BNXT_AUXDEV_RDMA)
bp->flags &= ~BNXT_FLAG_ROCE_CAP;

View File

@ -175,6 +175,7 @@ int mlx5_st_dealloc_index(struct mlx5_core_dev *dev, u16 st_index)
if (refcount_dec_and_test(&idx_data->usecount)) {
xa_erase(&st->idx_xa, st_index);
kfree(idx_data);
/* We leave PCI config space as was before, no mkey will refer to it */
}

View File

@ -3615,19 +3615,22 @@ static int macsec_dev_open(struct net_device *dev)
ops = macsec_get_ops(netdev_priv(dev), &ctx);
if (!ops) {
err = -EOPNOTSUPP;
goto clear_allmulti;
goto clear_promisc;
}
ctx.secy = &macsec->secy;
err = macsec_offload(ops->mdo_dev_open, &ctx);
if (err)
goto clear_allmulti;
goto clear_promisc;
}
if (netif_carrier_ok(real_dev))
netif_carrier_on(dev);
return 0;
clear_promisc:
if (dev->flags & IFF_PROMISC)
dev_set_promiscuity(real_dev, -1);
clear_allmulti:
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(real_dev, -1);

View File

@ -184,6 +184,7 @@ struct channel {
struct list_head clist; /* link in list of channels per unit */
spinlock_t upl; /* protects `ppp' and 'bridge' */
struct channel __rcu *bridge; /* "bridged" ppp channel */
struct rcu_head rcu; /* for RCU-deferred free of the channel */
#ifdef CONFIG_PPP_MULTILINK
u8 avail; /* flag used in multilink stuff */
u8 had_frag; /* >= 1 fragments have been sent */
@ -3562,6 +3563,18 @@ ppp_disconnect_channel(struct channel *pch)
return err;
}
/* Purge after the grace period: a late ppp_input() may still queue an
* skb on pch->file.rq before the last RCU reader drains.
*/
static void ppp_release_channel_free(struct rcu_head *rcu)
{
struct channel *pch = container_of(rcu, struct channel, rcu);
skb_queue_purge(&pch->file.xq);
skb_queue_purge(&pch->file.rq);
kfree(pch);
}
/*
* Drop a reference to a ppp channel and free its memory if the refcount reaches
* zero.
@ -3581,9 +3594,7 @@ static void ppp_release_channel(struct channel *pch)
pr_err("ppp: destroying undead channel %p !\n", pch);
return;
}
skb_queue_purge(&pch->file.xq);
skb_queue_purge(&pch->file.rq);
kfree(pch);
call_rcu(&pch->rcu, ppp_release_channel_free);
}
static void __exit ppp_cleanup(void)
@ -3596,6 +3607,7 @@ static void __exit ppp_cleanup(void)
device_destroy(&ppp_class, MKDEV(PPP_MAJOR, 0));
class_unregister(&ppp_class);
unregister_pernet_device(&ppp_net_ops);
rcu_barrier(); /* wait for RCU callbacks before module unload */
}
/*

View File

@ -293,6 +293,12 @@ brcmf_notify_auth_frame_rx(struct brcmf_if *ifp,
return -EINVAL;
}
if (mgmt_frame_len < offsetof(struct ieee80211_mgmt, u)) {
bphy_err(drvr, "Event %s (%d) frame too small. Ignore\n",
brcmf_fweh_event_name(e->event_code), e->event_code);
return -EINVAL;
}
wdev = &ifp->vif->wdev;
WARN_ON(!wdev);

View File

@ -4465,6 +4465,7 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->sdiodev = sdiodev;
sdiodev->bus = bus;
skb_queue_head_init(&bus->glom);
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
bus->txbound = BRCMF_TXBOUND;
bus->rxbound = BRCMF_RXBOUND;
bus->txminmax = BRCMF_TXMINMAX;
@ -4479,7 +4480,6 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
goto fail;
}
brcmf_sdiod_freezer_count(sdiodev);
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
bus->brcmf_wq = wq;
/* attempt to attach to the dongle */

View File

@ -6157,6 +6157,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
if (err) {
printk(KERN_WARNING DRV_NAME
"Error calling pci_enable_device.\n");
free_libipw(dev, 0);
pci_iounmap(pci_dev, ioaddr);
return err;
}
@ -6169,16 +6171,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
if (err) {
printk(KERN_WARNING DRV_NAME
"Error calling pci_set_dma_mask.\n");
pci_disable_device(pci_dev);
return err;
goto fail;
}
err = pci_request_regions(pci_dev, DRV_NAME);
if (err) {
printk(KERN_WARNING DRV_NAME
"Error calling pci_request_regions.\n");
pci_disable_device(pci_dev);
return err;
goto fail;
}
/* We disable the RETRY_TIMEOUT register (0x41) to keep

View File

@ -414,7 +414,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
ieee->host_mc_decrypt : ieee->host_decrypt;
if (can_be_decrypted) {
if (skb->len >= hdrlen + 3) {
if (skb->len >= hdrlen + 4) {
/* Top two-bits of byte 3 are the key index */
keyidx = skb->data[hdrlen + 3] >> 6;
}
@ -660,7 +660,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
int trimlen = 0;
/* Top two-bits of byte 3 are the key index */
if (skb->len >= hdrlen + 3)
if (skb->len >= hdrlen + 4)
keyidx = skb->data[hdrlen + 3] >> 6;
/* To strip off any security data which appears before the

View File

@ -499,11 +499,19 @@ static void p54_rx_eeprom_readback(struct p54_common *priv,
if (le16_to_cpu(eeprom->v2.len) != priv->eeprom_slice_size)
return;
if (eeprom->v2.data + priv->eeprom_slice_size >
skb_tail_pointer(skb))
return;
memcpy(priv->eeprom, eeprom->v2.data, priv->eeprom_slice_size);
} else {
if (le16_to_cpu(eeprom->v1.len) != priv->eeprom_slice_size)
return;
if (eeprom->v1.data + priv->eeprom_slice_size >
skb_tail_pointer(skb))
return;
memcpy(priv->eeprom, eeprom->v1.data, priv->eeprom_slice_size);
}

View File

@ -78,6 +78,7 @@ static void helper_firmware_cb(const struct firmware *firmware, void *context)
} else {
/* No main firmware needed for this helper --> success! */
lbs_fw_loaded(priv, 0, firmware, NULL);
release_firmware(firmware);
}
}

View File

@ -117,6 +117,13 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
if (skb->len < sizeof(*rtap_hdr) + 4 + ETH_ALEN) {
lbs_deb_tx("tx err: short monitor frame %u\n", skb->len);
dev->stats.tx_dropped++;
dev->stats.tx_errors++;
goto free;
}
/* set txpd fields from the radiotap header */
txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));

View File

@ -174,7 +174,7 @@ static void lbtf_free_adapter(struct lbtf_private *priv)
{
lbtf_deb_enter(LBTF_DEB_MAIN);
lbtf_free_cmd_buffer(priv);
timer_delete(&priv->command_timer);
timer_delete_sync(&priv->command_timer);
lbtf_deb_leave(LBTF_DEB_MAIN);
}

View File

@ -4334,7 +4334,7 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy,
return -EOPNOTSUPP;
}
if (!priv->auth_flag) {
if (!(priv->auth_flag & HOST_MLME_AUTH_PENDING)) {
ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET,
req->bss->channel,
AUTH_TX_DEFAULT_WAIT_TIME);

View File

@ -736,7 +736,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
/* Send a Media Connected event, according to the Spec */
priv->media_connected = true;
priv->adapter->ps_state = PS_STATE_AWAKE;
priv->adapter->pps_uapsd_mode = false;
priv->adapter->tx_lock_flag = false;

View File

@ -1429,7 +1429,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
*/
static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
{
struct eeprom_93cx6 eeprom;
struct eeprom_93cx6 eeprom = {};
u32 reg;
u16 word;
u8 *mac;

View File

@ -1555,7 +1555,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
*/
static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
{
struct eeprom_93cx6 eeprom;
struct eeprom_93cx6 eeprom = {};
u32 reg;
u16 word;
u8 *mac;

View File

@ -108,7 +108,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
{
struct eeprom_93cx6 eeprom;
struct eeprom_93cx6 eeprom = {};
u32 reg;
reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR);

View File

@ -1388,7 +1388,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
GFP_KERNEL);
if (!rt2x00dev->drv_data) {
retval = -ENOMEM;
goto exit;
return retval;
}
}
@ -1422,7 +1422,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
alloc_ordered_workqueue("%s", 0, wiphy_name(rt2x00dev->hw->wiphy));
if (!rt2x00dev->workqueue) {
retval = -ENOMEM;
goto exit;
goto exit_free_drv_data;
}
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
@ -1494,6 +1494,14 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
exit:
rt2x00lib_remove_dev(rt2x00dev);
return retval;
exit_free_drv_data:
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
kfree(rt2x00dev->drv_data);
rt2x00dev->drv_data = NULL;
return retval;
}
EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev);

View File

@ -2298,7 +2298,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
*/
static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
{
struct eeprom_93cx6 eeprom;
struct eeprom_93cx6 eeprom = {};
u32 reg;
u16 word;
u8 *mac;

View File

@ -431,6 +431,7 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
struct ieee80211_vif *vif;
struct sk_buff *mac_bcn;
u8 vap_id = 0, i;
unsigned int tailroom;
u16 tim_offset = 0;
for (i = 0; i < RSI_MAX_VIFS; i++) {
@ -480,6 +481,13 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
if (mac_bcn->data[tim_offset + 2] == 0)
bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON);
tailroom = skb_tailroom(skb);
if (tailroom < FRAME_DESC_SZ ||
mac_bcn->len > tailroom - FRAME_DESC_SZ) {
dev_kfree_skb(mac_bcn);
return -EMSGSIZE;
}
memcpy(&skb->data[FRAME_DESC_SZ], mac_bcn->data, mac_bcn->len);
skb_put(skb, mac_bcn->len + FRAME_DESC_SZ);

View File

@ -848,8 +848,10 @@ int rsi_hal_load_key(struct rsi_common *common,
} else {
memcpy(&set_key->key[0][0], data, key_len);
}
memcpy(set_key->tx_mic_key, &data[16], 8);
memcpy(set_key->rx_mic_key, &data[24], 8);
if (cipher == WLAN_CIPHER_SUITE_TKIP) {
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);
}
@ -1911,6 +1913,12 @@ int rsi_send_bgscan_probe_req(struct rsi_common *common,
return -ENOMEM;
}
if (probereq_skb->len > MAX_BGSCAN_PROBE_REQ_LEN) {
dev_kfree_skb(probereq_skb);
dev_kfree_skb(skb);
return -EINVAL;
}
memcpy(&skb->data[frame_len], probereq_skb->data, probereq_skb->len);
bgscan->probe_req_length = cpu_to_le16(probereq_skb->len);

View File

@ -1324,6 +1324,17 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
}
}
static struct ieee80211_rate *
mac80211_hwsim_get_tx_rate(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info)
{
if (info->control.rates[0].flags &
(IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))
return NULL;
return ieee80211_get_tx_rate(hw, info);
}
static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
struct sk_buff *tx_skb,
struct ieee80211_channel *chan)
@ -1333,7 +1344,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
struct hwsim_radiotap_hdr *hdr;
u16 flags, bitrate;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb);
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
struct ieee80211_rate *txrate = mac80211_hwsim_get_tx_rate(hw, info);
if (!txrate)
bitrate = 0;
@ -1603,7 +1614,7 @@ static void mac80211_hwsim_write_tsf(struct mac80211_hwsim_data *data,
spin_lock_bh(&data->tsf_offset_lock);
txrate = ieee80211_get_tx_rate(data->hw, info);
txrate = mac80211_hwsim_get_tx_rate(data->hw, info);
if (txrate)
bitrate = txrate->bitrate;
@ -7289,6 +7300,7 @@ static void hwsim_virtio_rx_work(struct work_struct *work)
skb->data = skb->head;
skb_reset_tail_pointer(skb);
len = min(len, skb_end_offset(skb));
skb_put(skb, len);
hwsim_virtio_handle_cmd(skb);

View File

@ -3,7 +3,7 @@
* CAN driver for PEAK System micro-CAN based adapters
*
* Copyright (C) 2003-2025 PEAK System-Technik GmbH
* Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com>
* Author: Stéphane Grosjean <s.grosjean@peak-system.fr>
*/
#ifndef PUCAN_H
#define PUCAN_H

View File

@ -857,7 +857,7 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
const struct ieee80211_multi_link_elem *mle = (const void *)data;
u8 fixed = sizeof(*mle);
u8 common = 0;
bool check_common_len = false;
u8 common_len;
u16 control;
if (!data || len < fixed)
@ -868,7 +868,6 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) {
case IEEE80211_ML_CONTROL_TYPE_BASIC:
common += sizeof(struct ieee80211_mle_basic_common_info);
check_common_len = true;
if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID)
common += 1;
if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)
@ -888,9 +887,9 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
common += sizeof(struct ieee80211_mle_preq_common_info);
if (control & IEEE80211_MLC_PREQ_PRES_MLD_ID)
common += 1;
check_common_len = true;
break;
case IEEE80211_ML_CONTROL_TYPE_RECONF:
common += 1;
if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR)
common += ETH_ALEN;
if (control & IEEE80211_MLC_RECONF_PRES_EML_CAPA)
@ -902,7 +901,6 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
break;
case IEEE80211_ML_CONTROL_TYPE_TDLS:
common += sizeof(struct ieee80211_mle_tdls_common_info);
check_common_len = true;
break;
case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS:
common = ETH_ALEN + 1;
@ -915,11 +913,9 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
if (len < fixed + common)
return false;
if (!check_common_len)
return true;
common_len = mle->variable[0];
/* if present, common length is the first octet there */
return mle->variable[0] >= common;
return common_len >= common && common_len <= len - fixed;
}
/**

View File

@ -2430,6 +2430,7 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
bool persistent);
void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
u8 *name, u8 name_len);
u8 hci_to_mgmt_reason(u8 err);
void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 reason,
bool mgmt_connected);

View File

@ -7228,7 +7228,7 @@ struct wireless_dev {
enum ieee80211_bss_type conn_bss_type;
u32 conn_owner_nlportid;
struct work_struct disconnect_wk;
struct wiphy_work disconnect_wk;
u8 disconnect_bssid[ETH_ALEN];
struct list_head event_list;
@ -7265,7 +7265,7 @@ struct wireless_dev {
struct list_head pmsr_list;
spinlock_t pmsr_lock;
struct work_struct pmsr_free_wk;
struct wiphy_work pmsr_free_wk;
unsigned long unprot_beacon_reported;

View File

@ -312,7 +312,8 @@ struct sctp_cookie {
__u8 auth_random[sizeof(struct sctp_paramhdr) +
SCTP_AUTH_RANDOM_LENGTH];
__u8 auth_hmacs[SCTP_AUTH_NUM_HMACS * sizeof(__u16) + 2];
__u8 auth_hmacs[sizeof(struct sctp_paramhdr) +
SCTP_AUTH_NUM_HMACS * sizeof(__u16)];
__u8 auth_chunks[sizeof(struct sctp_paramhdr) + SCTP_AUTH_MAX_CHUNKS];
/* This is a shim for my peer's INIT packet, followed by

View File

@ -162,6 +162,8 @@ struct xfrm_dev_offload {
*/
struct net_device *real_dev;
unsigned long offload_handle;
/* Snapshot the attached device index for dump paths. */
int ifindex;
u8 dir : 2;
u8 type : 2;
u8 flags : 2;

View File

@ -2763,7 +2763,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
}
mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
cp->reason, mgmt_conn);
hci_to_mgmt_reason(cp->reason), mgmt_conn);
hci_disconn_cfm(conn, cp->reason);
@ -3381,22 +3381,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
hci_dev_unlock(hdev);
}
static u8 hci_to_mgmt_reason(u8 err)
{
switch (err) {
case HCI_ERROR_CONNECTION_TIMEOUT:
return MGMT_DEV_DISCONN_TIMEOUT;
case HCI_ERROR_REMOTE_USER_TERM:
case HCI_ERROR_REMOTE_LOW_RESOURCES:
case HCI_ERROR_REMOTE_POWER_OFF:
return MGMT_DEV_DISCONN_REMOTE;
case HCI_ERROR_LOCAL_HOST_TERM:
return MGMT_DEV_DISCONN_LOCAL_HOST;
default:
return MGMT_DEV_DISCONN_UNKNOWN;
}
}
static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{

View File

@ -1054,14 +1054,19 @@ static int hci_set_random_addr_sync(struct hci_dev *hdev, bdaddr_t *rpa)
* In this kind of scenario skip the update and let the random
* address be updated at the next cycle.
*/
rcu_read_lock();
if (bacmp(&hdev->random_addr, BDADDR_ANY) &&
(hci_dev_test_flag(hdev, HCI_LE_ADV) ||
hci_lookup_le_connect(hdev))) {
bt_dev_dbg(hdev, "Deferring random address update");
hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
rcu_read_unlock();
return 0;
}
rcu_read_unlock();
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_RANDOM_ADDR,
6, rpa, HCI_CMD_TIMEOUT);
}
@ -2647,12 +2652,17 @@ static int hci_pause_addr_resolution(struct hci_dev *hdev)
/* Cannot disable addr resolution if scanning is enabled or
* when initiating an LE connection.
*/
rcu_read_lock();
if (hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
hci_lookup_le_connect(hdev)) {
rcu_read_unlock();
bt_dev_err(hdev, "Command not allowed when scan/LE connect");
return -EPERM;
}
rcu_read_unlock();
/* Cannot disable addr resolution if advertising is enabled. */
err = hci_pause_advertising_sync(hdev);
if (err) {
@ -2790,6 +2800,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
if (hci_dev_test_flag(hdev, HCI_PA_SYNC)) {
struct hci_conn *conn;
rcu_read_lock();
conn = hci_conn_hash_lookup_create_pa_sync(hdev);
if (conn) {
struct conn_params pa;
@ -2799,6 +2811,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
bacpy(&pa.addr, &conn->dst);
pa.addr_type = conn->dst_type;
rcu_read_unlock();
/* Clear first since there could be addresses left
* behind.
*/
@ -2808,6 +2822,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
err = hci_le_add_accept_list_sync(hdev, &pa,
&num_entries);
goto done;
} else {
rcu_read_unlock();
}
}
@ -2818,10 +2834,13 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
* the controller.
*/
list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) {
if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type))
continue;
rcu_read_lock();
if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type)) {
rcu_read_unlock();
continue;
}
/* Pointers not dereferenced, no locks needed */
pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns,
&b->bdaddr,
b->bdaddr_type);
@ -2829,6 +2848,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
&b->bdaddr,
b->bdaddr_type);
rcu_read_unlock();
/* If the device is not likely to connect or report,
* remove it from the acceptlist.
*/
@ -2955,6 +2976,8 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
if (sent) {
struct hci_conn *conn;
rcu_read_lock();
conn = hci_conn_hash_lookup_ba(hdev, PA_LINK,
&sent->bdaddr);
if (conn) {
@ -2979,8 +3002,12 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
phy++;
}
rcu_read_unlock();
if (num_phy)
goto done;
} else {
rcu_read_unlock();
}
}
}
@ -3231,12 +3258,16 @@ int hci_update_passive_scan_sync(struct hci_dev *hdev)
/* If there is at least one pending LE connection, we should
* keep the background scan running.
*/
bool exists;
/* If controller is connecting, we should not start scanning
* since some controllers are not able to scan and connect at
* the same time.
*/
if (hci_lookup_le_connect(hdev))
rcu_read_lock();
exists = hci_lookup_le_connect(hdev);
rcu_read_unlock();
if (exists)
return 0;
bt_dev_dbg(hdev, "start background scanning");
@ -3454,6 +3485,7 @@ int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable)
}
static bool disconnected_accept_list_entries(struct hci_dev *hdev)
__must_hold(&hdev->lock)
{
struct bdaddr_list *b;
@ -3494,12 +3526,16 @@ int hci_update_scan_sync(struct hci_dev *hdev)
if (hdev->scanning_paused)
return 0;
hci_dev_lock(hdev);
if (hci_dev_test_flag(hdev, HCI_CONNECTABLE) ||
disconnected_accept_list_entries(hdev))
scan = SCAN_PAGE;
else
scan = SCAN_DISABLED;
hci_dev_unlock(hdev);
if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
scan |= SCAN_INQUIRY;
@ -6665,6 +6701,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
if (!hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES))
hci_pause_advertising_sync(hdev);
hci_dev_lock(hdev);
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
if (params) {
conn->le_conn_min_interval = params->conn_min_interval;
@ -6678,6 +6716,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
conn->le_supv_timeout = hdev->le_supv_timeout;
}
hci_dev_unlock(hdev);
/* If controller is scanning, we stop it since some controllers are
* not able to scan and connect at the same time. Also set the
* HCI_LE_SCAN_INTERRUPTED flag so that the command complete
@ -7235,13 +7275,13 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
}
static int hci_le_past_params_sync(struct hci_dev *hdev, struct hci_conn *conn,
struct hci_conn *acl, struct bt_iso_qos *qos)
u16 acl_handle, struct bt_iso_qos *qos)
{
struct hci_cp_le_past_params cp;
int err;
memset(&cp, 0, sizeof(cp));
cp.handle = cpu_to_le16(acl->handle);
cp.handle = cpu_to_le16(acl_handle);
/* An HCI_LE_Periodic_Advertising_Sync_Transfer_Received event is sent
* to the Host. HCI_LE_Periodic_Advertising_Report events will be
* enabled with duplicate filtering enabled.
@ -7306,16 +7346,28 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data)
* 2. Check if that HCI_CONN_FLAG_PAST has been set which indicates that
* user really intended to use PAST.
*/
hci_dev_lock(hdev);
le = hci_conn_hash_lookup_le(hdev, &conn->dst, conn->dst_type);
if (le) {
struct hci_conn_params *params;
hci_conn_flags_t flags = 0;
u16 le_handle = le->handle;
params = hci_conn_params_lookup(hdev, &le->dst, le->dst_type);
if (params && params->flags & HCI_CONN_FLAG_PAST) {
err = hci_le_past_params_sync(hdev, conn, le, qos);
if (params)
flags = params->flags;
hci_dev_unlock(hdev);
if (flags & HCI_CONN_FLAG_PAST) {
err = hci_le_past_params_sync(hdev, conn, le_handle,
qos);
if (!err)
goto done;
}
} else {
hci_dev_unlock(hdev);
}
/* SID has not been set listen for HCI_EV_LE_EXT_ADV_REPORT to update

View File

@ -3091,6 +3091,8 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)
struct mgmt_cp_unpair_device *cp = cmd->param;
struct hci_conn *conn;
hci_dev_lock(hdev);
if (cp->addr.type == BDADDR_BREDR)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
&cp->addr.bdaddr);
@ -3098,6 +3100,11 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)
conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type));
if (conn)
hci_conn_get(conn);
hci_dev_unlock(hdev);
if (!conn)
return 0;
@ -3105,6 +3112,7 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)
* will clean up the connection no matter the error.
*/
hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
hci_conn_put(conn);
return 0;
}
@ -3252,6 +3260,8 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)
struct mgmt_cp_disconnect *cp = cmd->param;
struct hci_conn *conn;
hci_dev_lock(hdev);
if (cp->addr.type == BDADDR_BREDR)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
&cp->addr.bdaddr);
@ -3259,6 +3269,11 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)
conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type));
if (conn)
hci_conn_get(conn);
hci_dev_unlock(hdev);
if (!conn)
return -ENOTCONN;
@ -3266,6 +3281,7 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)
* will clean up the connection no matter the error.
*/
hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
hci_conn_put(conn);
return 0;
}
@ -7388,6 +7404,9 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
rp.max_tx_power = HCI_TX_POWER_INVALID;
}
if (conn)
hci_conn_put(conn);
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status,
&rp, sizeof(rp));
@ -7402,6 +7421,8 @@ static int get_conn_info_sync(struct hci_dev *hdev, void *data)
int err;
__le16 handle;
hci_dev_lock(hdev);
/* Make sure we are still connected */
if (cp->addr.type == BDADDR_BREDR)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
@ -7409,12 +7430,16 @@ static int get_conn_info_sync(struct hci_dev *hdev, void *data)
else
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
if (!conn || conn->state != BT_CONNECTED)
if (!conn || conn->state != BT_CONNECTED) {
hci_dev_unlock(hdev);
return MGMT_STATUS_NOT_CONNECTED;
}
cmd->user_data = conn;
cmd->user_data = hci_conn_get(conn);
handle = cpu_to_le16(conn->handle);
hci_dev_unlock(hdev);
/* Refresh RSSI each time */
err = hci_read_rssi_sync(hdev, handle);
@ -7548,6 +7573,9 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
}
complete:
if (conn)
hci_conn_put(conn);
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp,
sizeof(rp));
@ -7564,15 +7592,21 @@ static int get_clock_info_sync(struct hci_dev *hdev, void *data)
memset(&hci_cp, 0, sizeof(hci_cp));
hci_read_clock_sync(hdev, &hci_cp);
hci_dev_lock(hdev);
/* Make sure connection still exists */
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
if (!conn || conn->state != BT_CONNECTED)
if (!conn || conn->state != BT_CONNECTED) {
hci_dev_unlock(hdev);
return MGMT_STATUS_NOT_CONNECTED;
}
cmd->user_data = conn;
cmd->user_data = hci_conn_get(conn);
hci_cp.handle = cpu_to_le16(conn->handle);
hci_cp.which = 0x01; /* Piconet clock */
hci_dev_unlock(hdev);
return hci_read_clock_sync(hdev, &hci_cp);
}
@ -7937,14 +7971,36 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
static int conn_update_sync(struct hci_dev *hdev, void *data)
{
struct hci_conn_params *params = data;
struct hci_conn *conn;
struct hci_conn *conn = data;
struct hci_conn_params *params;
struct hci_conn_params local = {};
conn = hci_conn_hash_lookup_le(hdev, &params->addr, params->addr_type);
if (!conn)
return -ECANCELED;
hci_dev_lock(hdev);
return hci_le_conn_update_sync(hdev, conn, params);
if (!hci_conn_valid(hdev, conn) || conn->role != HCI_ROLE_MASTER)
goto cancel;
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
if (!params)
goto cancel;
local.conn_min_interval = params->conn_min_interval;
local.conn_max_interval = params->conn_max_interval;
local.conn_latency = params->conn_latency;
local.supervision_timeout = params->supervision_timeout;
hci_dev_unlock(hdev);
return hci_le_conn_update_sync(hdev, conn, &local);
cancel:
hci_dev_unlock(hdev);
return -ECANCELED;
}
static void conn_update_sync_destroy(struct hci_dev *hdev, void *data, int err)
{
hci_conn_put(data);
}
static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
@ -8054,9 +8110,13 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
(conn->le_conn_min_interval != min ||
conn->le_conn_max_interval != max ||
conn->le_conn_latency != latency ||
conn->le_supv_timeout != timeout))
hci_cmd_sync_queue(hdev, conn_update_sync,
hci_param, NULL);
conn->le_supv_timeout != timeout)) {
hci_conn_get(conn);
if (hci_cmd_sync_queue(hdev, conn_update_sync,
conn,
conn_update_sync_destroy) < 0)
hci_conn_put(conn);
}
}
}
@ -9848,6 +9908,22 @@ bool mgmt_powering_down(struct hci_dev *hdev)
return false;
}
u8 hci_to_mgmt_reason(u8 err)
{
switch (err) {
case HCI_ERROR_CONNECTION_TIMEOUT:
return MGMT_DEV_DISCONN_TIMEOUT;
case HCI_ERROR_REMOTE_USER_TERM:
case HCI_ERROR_REMOTE_LOW_RESOURCES:
case HCI_ERROR_REMOTE_POWER_OFF:
return MGMT_DEV_DISCONN_REMOTE;
case HCI_ERROR_LOCAL_HOST_TERM:
return MGMT_DEV_DISCONN_LOCAL_HOST;
default:
return MGMT_DEV_DISCONN_UNKNOWN;
}
}
void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 reason,
bool mgmt_connected)
@ -9909,7 +9985,8 @@ void mgmt_connect_failed(struct hci_dev *hdev, struct hci_conn *conn, u8 status)
if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
conn->dst_type, status, true);
conn->dst_type,
hci_to_mgmt_reason(status), true);
return;
}

File diff suppressed because it is too large Load Diff

View File

@ -152,11 +152,13 @@ struct isotp_sock {
struct sock sk;
int bound;
int ifindex;
struct net_device *dev;
netdevice_tracker dev_tracker;
canid_t txid;
canid_t rxid;
ktime_t tx_gap;
ktime_t lastrxcf_tstamp;
struct hrtimer rxtimer, txtimer, txfrtimer;
struct hrtimer rxtimer, txtimer, txfrtimer, echotimer;
struct can_isotp_options opt;
struct can_isotp_fc_options rxfc, txfc;
struct can_isotp_ll_options ll;
@ -164,6 +166,7 @@ struct isotp_sock {
u32 force_tx_stmin;
u32 force_rx_stmin;
u32 cfecho; /* consecutive frame echo tag */
u32 tx_gen; /* generation, bumped per new tx transfer */
struct tpcon rx, tx;
struct list_head notifier;
wait_queue_head_t wait;
@ -376,6 +379,15 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
hrtimer_cancel(&so->txtimer);
/* isotp_tx_timeout() may have given up on this job while
* hrtimer_cancel() above waited for it to finish; so->rx_lock
* (held by our caller isotp_rcv()) rules out a concurrent claim,
* so a plain recheck is enough here.
*/
if (so->tx.state != ISOTP_WAIT_FC &&
so->tx.state != ISOTP_WAIT_FIRST_FC)
return 1;
if ((cf->len < ae + FC_CONTENT_SZ) ||
((so->opt.flags & ISOTP_CHECK_PADDING) &&
check_pad(so, cf, ae + FC_CONTENT_SZ, so->opt.rxpad_content))) {
@ -422,7 +434,7 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
so->tx.bs = 0;
so->tx.state = ISOTP_SENDING;
/* send CF frame and enable echo timeout handling */
hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
HRTIMER_MODE_REL_SOFT);
isotp_send_cframe(so);
break;
@ -575,6 +587,14 @@ static int isotp_rcv_cf(struct sock *sk, struct canfd_frame *cf, int ae,
hrtimer_cancel(&so->rxtimer);
/* isotp_rx_timer_handler() may have raced us for so->rx.state
* while hrtimer_cancel() above waited for it to finish, already
* reporting ETIMEDOUT and resetting the reception; don't process
* this CF into a reassembly that has already been given up on.
*/
if (so->rx.state != ISOTP_WAIT_DATA)
return 1;
/* CFs are never longer than the FF */
if (cf->len > so->rx.ll_dl)
return 1;
@ -870,20 +890,36 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
struct canfd_frame *cf = (struct canfd_frame *)skb->data;
/* only handle my own local echo CF/SF skb's (no FF!) */
if (skb->sk != sk || so->cfecho != *(u32 *)cf->data)
if (skb->sk != sk)
return;
/* unlike isotp_rcv_fc()/isotp_rcv_cf(), not already under so->rx_lock
* (no isotp_rcv() caller here), so take it ourselves
*/
spin_lock(&so->rx_lock);
/* so->cfecho may since belong to a new transfer; recheck under lock */
if (so->cfecho != *(u32 *)cf->data)
goto out_unlock;
/* cancel local echo timeout */
hrtimer_cancel(&so->txtimer);
hrtimer_cancel(&so->echotimer);
/* local echo skb with consecutive frame has been consumed */
so->cfecho = 0;
/* claiming a transfer also takes so->rx_lock, so a plain recheck
* is enough: so->tx.state can't have flipped to ISOTP_SENDING for
* a new claim while we're still in here
*/
if (so->tx.state != ISOTP_SENDING)
goto out_unlock;
if (so->tx.idx >= so->tx.len) {
/* we are done */
so->tx.state = ISOTP_IDLE;
wake_up_interruptible(&so->wait);
return;
goto out_unlock;
}
if (so->txfc.bs && so->tx.bs >= so->txfc.bs) {
@ -891,53 +927,83 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
so->tx.state = ISOTP_WAIT_FC;
hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
HRTIMER_MODE_REL_SOFT);
return;
goto out_unlock;
}
/* no gap between data frames needed => use burst mode */
if (!so->tx_gap) {
/* enable echo timeout handling */
hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
HRTIMER_MODE_REL_SOFT);
isotp_send_cframe(so);
return;
goto out_unlock;
}
/* start timer to send next consecutive frame with correct delay */
hrtimer_start(&so->txfrtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT);
out_unlock:
spin_unlock(&so->rx_lock);
}
static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
/* shared by so->txtimer's and so->echotimer's callbacks. Both timers get
* cancelled under so->rx_lock elsewhere, so this must stay lock-free to
* avoid deadlocking with that; uses so->tx_gen instead to avoid tainting
* a new transfer with an error from the one that just timed out.
*/
static enum hrtimer_restart isotp_tx_timeout(struct isotp_sock *so)
{
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
txtimer);
struct sock *sk = &so->sk;
u32 gen = READ_ONCE(so->tx_gen);
u32 old_state = READ_ONCE(so->tx.state);
/* don't handle timeouts in IDLE or SHUTDOWN state */
if (so->tx.state == ISOTP_IDLE || so->tx.state == ISOTP_SHUTDOWN)
if (old_state == ISOTP_IDLE || old_state == ISOTP_SHUTDOWN)
return HRTIMER_NORESTART;
/* only claim the timeout if the state is still unchanged */
if (cmpxchg(&so->tx.state, old_state, ISOTP_IDLE) != old_state)
return HRTIMER_NORESTART;
/* we did not get any flow control or echo frame in time */
/* report 'communication error on send' */
sk->sk_err = ECOMM;
if (!sock_flag(sk, SOCK_DEAD))
sk_error_report(sk);
if (READ_ONCE(so->tx_gen) == gen) {
/* report 'communication error on send' */
sk->sk_err = ECOMM;
if (!sock_flag(sk, SOCK_DEAD))
sk_error_report(sk);
}
/* reset tx state */
so->tx.state = ISOTP_IDLE;
wake_up_interruptible(&so->wait);
return HRTIMER_NORESTART;
}
/* so->txtimer: fires when a Flow Control frame does not arrive in time */
static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
{
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
txtimer);
return isotp_tx_timeout(so);
}
/* so->echotimer: fires when a sent CF/SF's local echo does not arrive */
static enum hrtimer_restart isotp_echo_timer_handler(struct hrtimer *hrtimer)
{
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
echotimer);
return isotp_tx_timeout(so);
}
static enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer)
{
struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
txfrtimer);
/* start echo timeout handling and cover below protocol error */
hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
HRTIMER_MODE_REL_SOFT);
/* cfecho should be consumed by isotp_rcv_echo() here */
@ -958,13 +1024,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0;
int wait_tx_done = (so->opt.flags & CAN_ISOTP_WAIT_TX_DONE) ? 1 : 0;
s64 hrtimer_sec = ISOTP_ECHO_TIMEOUT;
struct hrtimer *tx_hrt = &so->echotimer;
u32 new_state = ISOTP_SENDING;
int off;
int err;
if (!so->bound || so->tx.state == ISOTP_SHUTDOWN)
return -EADDRNOTAVAIL;
while (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) {
/* claim the socket under so->rx_lock: this serializes the claim
* with the RX path and with sendmsg()'s own error paths below, so
* none of them can ever see a transfer mid-claim
*/
for (;;) {
spin_lock_bh(&so->rx_lock);
if (READ_ONCE(so->tx.state) == ISOTP_IDLE)
break;
spin_unlock_bh(&so->rx_lock);
/* we do not support multiple buffers - for now */
if (msg->msg_flags & MSG_DONTWAIT)
return -EAGAIN;
@ -973,9 +1050,29 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
return -EADDRNOTAVAIL;
/* wait for complete transmission of current pdu */
err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
err = wait_event_interruptible(so->wait,
so->tx.state == ISOTP_IDLE);
if (err)
goto err_event_drop;
return err;
}
/* new transfer: bump so->tx_gen and drain the old one's timers,
* still under the so->rx_lock we just claimed the socket with
*/
WRITE_ONCE(so->tx.state, ISOTP_SENDING);
WRITE_ONCE(so->tx_gen, READ_ONCE(so->tx_gen) + 1);
hrtimer_cancel(&so->txtimer);
hrtimer_cancel(&so->echotimer);
hrtimer_cancel(&so->txfrtimer);
so->cfecho = 0;
spin_unlock_bh(&so->rx_lock);
/* so->bound is only checked once above - a wakeup may have
* unbound/rebound the socket meanwhile, so re-validate it
*/
if (!so->bound) {
err = -EADDRNOTAVAIL;
goto err_out_drop;
}
/* PDU size > default => try max_pdu_size */
@ -1086,18 +1183,33 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
so->cfecho = *(u32 *)cf->data;
} else {
/* standard flow control check */
so->tx.state = ISOTP_WAIT_FIRST_FC;
new_state = ISOTP_WAIT_FIRST_FC;
/* start timeout for FC */
hrtimer_sec = ISOTP_FC_TIMEOUT;
tx_hrt = &so->txtimer;
/* no CF echo tag for isotp_rcv_echo() (FF-mode) */
so->cfecho = 0;
}
}
hrtimer_start(&so->txtimer, ktime_set(hrtimer_sec, 0),
spin_lock_bh(&so->rx_lock);
if (so->tx.state == ISOTP_SHUTDOWN) {
/* isotp_release() has since taken over and already drained
* our timers - don't send into a socket that's going away
*/
spin_unlock_bh(&so->rx_lock);
kfree_skb(skb);
dev_put(dev);
wake_up_interruptible(&so->wait);
return -EADDRNOTAVAIL;
}
/* WAIT_FIRST_FC for standard FF, else stays ISOTP_SENDING */
so->tx.state = new_state;
hrtimer_start(tx_hrt, ktime_set(hrtimer_sec, 0),
HRTIMER_MODE_REL_SOFT);
spin_unlock_bh(&so->rx_lock);
/* send the first or only CAN frame */
cf->flags = so->ll.tx_flags;
@ -1110,13 +1222,10 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
__func__, ERR_PTR(err));
spin_lock_bh(&so->rx_lock);
/* no transmission -> no timeout monitoring */
hrtimer_cancel(&so->txtimer);
/* reset consecutive frame echo tag */
so->cfecho = 0;
goto err_out_drop;
hrtimer_cancel(tx_hrt);
goto err_out_drop_locked;
}
if (wait_tx_done) {
@ -1132,14 +1241,21 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
return size;
err_out_drop:
/* claimed but nothing sent yet - no timer to cancel */
spin_lock_bh(&so->rx_lock);
goto err_out_drop_locked;
err_event_drop:
/* got signal: force tx state machine to be idle */
so->tx.state = ISOTP_IDLE;
/* interrupted waiting on our own transfer - drain its timers */
spin_lock_bh(&so->rx_lock);
hrtimer_cancel(&so->txfrtimer);
hrtimer_cancel(&so->txtimer);
err_out_drop:
/* drop this PDU and unlock a potential wait queue */
hrtimer_cancel(&so->echotimer);
err_out_drop_locked:
/* release the claim; so->rx_lock still held from above */
so->cfecho = 0;
so->tx.state = ISOTP_IDLE;
spin_unlock_bh(&so->rx_lock);
wake_up_interruptible(&so->wait);
return err;
@ -1201,13 +1317,20 @@ static int isotp_release(struct socket *sock)
so = isotp_sk(sk);
net = sock_net(sk);
/* wait for complete transmission of current pdu */
while (wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0 &&
cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SHUTDOWN) != ISOTP_IDLE)
/* best-effort: wait for a running pdu to finish, but don't block on
* it forever - give up after the first signal
*/
while (so->tx.state != ISOTP_IDLE &&
wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0)
;
/* force state machines to be idle also when a signal occurred */
/* claim the socket under so->rx_lock like sendmsg() does, so its
* claim can't race the forced ISOTP_SHUTDOWN below; force it
* unconditionally, even when a signal cut the wait above short
*/
spin_lock_bh(&so->rx_lock);
so->tx.state = ISOTP_SHUTDOWN;
spin_unlock_bh(&so->rx_lock);
so->rx.state = ISOTP_IDLE;
spin_lock(&isotp_notifier_lock);
@ -1219,35 +1342,42 @@ static int isotp_release(struct socket *sock)
list_del(&so->notifier);
spin_unlock(&isotp_notifier_lock);
rtnl_lock();
lock_sock(sk);
/* remove current filters & unregister */
if (so->bound) {
if (so->ifindex) {
struct net_device *dev;
/* remove current filters & unregister
* tracked reference so->dev is taken at bind() time with rtnl_lock
*/
if (so->bound && so->dev) {
if (isotp_register_rxid(so))
can_rx_unregister(net, so->dev, so->rxid,
SINGLE_MASK(so->rxid),
isotp_rcv, sk);
dev = dev_get_by_index(net, so->ifindex);
if (dev) {
if (isotp_register_rxid(so))
can_rx_unregister(net, dev, so->rxid,
SINGLE_MASK(so->rxid),
isotp_rcv, sk);
can_rx_unregister(net, dev, so->txid,
SINGLE_MASK(so->txid),
isotp_rcv_echo, sk);
dev_put(dev);
synchronize_rcu();
}
}
can_rx_unregister(net, so->dev, so->txid,
SINGLE_MASK(so->txid),
isotp_rcv_echo, sk);
netdev_put(so->dev, &so->dev_tracker);
}
hrtimer_cancel(&so->txfrtimer);
hrtimer_cancel(&so->txtimer);
hrtimer_cancel(&so->rxtimer);
so->ifindex = 0;
so->bound = 0;
so->dev = NULL;
rtnl_unlock();
/* Always wait for a grace period before touching the timers below.
* A concurrent NETDEV_UNREGISTER may have already unregistered our
* filters and cleared so->bound in isotp_notify() without waiting
* for in-flight isotp_rcv() callers to finish, so this call must not
* be skipped just because so->bound is already 0 here.
*/
synchronize_rcu();
hrtimer_cancel(&so->txfrtimer);
hrtimer_cancel(&so->txtimer);
hrtimer_cancel(&so->echotimer);
hrtimer_cancel(&so->rxtimer);
sock_orphan(sk);
sock->sk = NULL;
@ -1303,6 +1433,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
if (!addr->can_ifindex)
return -ENODEV;
rtnl_lock();
lock_sock(sk);
if (so->bound) {
@ -1310,6 +1441,17 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
goto out;
}
/* A transmission or reception that outlived a previous binding
* (unbound by NETDEV_UNREGISTER) may still be draining; the FC/echo
* and RX watchdog timers bound how long this takes. Checked together
* with so->bound in the same lock_sock() section above, so there is
* no window in which a concurrent isotp_notify() could be missed.
*/
if (so->tx.state != ISOTP_IDLE || so->rx.state != ISOTP_IDLE) {
err = -EAGAIN;
goto out;
}
/* ensure different CAN IDs when the rx_id is to be registered */
if (isotp_register_rxid(so) && rx_id == tx_id) {
err = -EADDRNOTAVAIL;
@ -1322,14 +1464,12 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
goto out;
}
if (dev->type != ARPHRD_CAN) {
dev_put(dev);
err = -ENODEV;
goto out;
goto out_put_dev;
}
if (READ_ONCE(dev->mtu) < so->ll.mtu) {
dev_put(dev);
err = -EINVAL;
goto out;
goto out_put_dev;
}
if (!(dev->flags & IFF_UP))
notify_enetdown = 1;
@ -1347,16 +1487,25 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id),
isotp_rcv_echo, sk, "isotpe", sk);
dev_put(dev);
/* switch to new settings */
so->ifindex = ifindex;
so->rxid = rx_id;
so->txid = tx_id;
so->bound = 1;
/* bind() ok -> hold a reference for so->dev so that isotp_release()
* can safely reach the device later, even if a concurrent
* NETDEV_UNREGISTER has already unlisted it by ifindex.
*/
so->dev = dev;
netdev_hold(so->dev, &so->dev_tracker, GFP_KERNEL);
out_put_dev:
/* remove potential reference from dev_get_by_index() */
dev_put(dev);
out:
release_sock(sk);
rtnl_unlock();
if (notify_enetdown) {
sk->sk_err = ENETDOWN;
@ -1559,7 +1708,7 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
if (!net_eq(dev_net(dev), sock_net(sk)))
return;
if (so->ifindex != dev->ifindex)
if (so->dev != dev)
return;
switch (msg) {
@ -1575,10 +1724,12 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
can_rx_unregister(dev_net(dev), dev, so->txid,
SINGLE_MASK(so->txid),
isotp_rcv_echo, sk);
netdev_put(so->dev, &so->dev_tracker);
}
so->ifindex = 0;
so->bound = 0;
so->dev = NULL;
release_sock(sk);
sk->sk_err = ENODEV;
@ -1638,6 +1789,7 @@ static int isotp_init(struct sock *sk)
so->ifindex = 0;
so->bound = 0;
so->dev = NULL;
so->opt.flags = CAN_ISOTP_DEFAULT_FLAGS;
so->opt.ext_address = CAN_ISOTP_DEFAULT_EXT_ADDRESS;
@ -1664,10 +1816,14 @@ static int isotp_init(struct sock *sk)
so->rx.buflen = ARRAY_SIZE(so->rx.sbuf);
so->tx.buflen = ARRAY_SIZE(so->tx.sbuf);
hrtimer_setup(&so->rxtimer, isotp_rx_timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
hrtimer_setup(&so->txtimer, isotp_tx_timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
hrtimer_setup(&so->txfrtimer, isotp_txfr_timer_handler, CLOCK_MONOTONIC,
HRTIMER_MODE_REL_SOFT);
hrtimer_setup(&so->rxtimer, isotp_rx_timer_handler,
CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
hrtimer_setup(&so->txtimer, isotp_tx_timer_handler,
CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
hrtimer_setup(&so->echotimer, isotp_echo_timer_handler,
CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
hrtimer_setup(&so->txfrtimer, isotp_txfr_timer_handler,
CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
init_waitqueue_head(&so->wait);
spin_lock_init(&so->rx_lock);

View File

@ -351,6 +351,18 @@ static void j1939_session_skb_drop_old(struct j1939_session *session)
}
}
static bool j1939_address_is_local(struct j1939_priv *priv, u8 addr)
{
bool local = false;
read_lock_bh(&priv->lock);
if (j1939_address_is_unicast(addr) && priv->ents[addr].nusers)
local = true;
read_unlock_bh(&priv->lock);
return local;
}
void j1939_session_skb_queue(struct j1939_session *session,
struct sk_buff *skb)
{
@ -359,8 +371,7 @@ void j1939_session_skb_queue(struct j1939_session *session,
j1939_ac_fixup(priv, skb);
if (j1939_address_is_unicast(skcb->addr.da) &&
priv->ents[skcb->addr.da].nusers)
if (j1939_address_is_local(priv, skcb->addr.da))
skcb->flags |= J1939_ECU_LOCAL_DST;
skcb->flags |= J1939_ECU_LOCAL_SRC;
@ -2038,8 +2049,7 @@ struct j1939_session *j1939_tp_send(struct j1939_priv *priv,
return ERR_PTR(ret);
/* fix DST flags, it may be used there soon */
if (j1939_address_is_unicast(skcb->addr.da) &&
priv->ents[skcb->addr.da].nusers)
if (j1939_address_is_local(priv, skcb->addr.da))
skcb->flags |= J1939_ECU_LOCAL_DST;
/* src is always local, I'm sending ... */

View File

@ -562,8 +562,8 @@ static int raw_getname(struct socket *sock, struct sockaddr *uaddr,
return RAW_MIN_NAMELEN;
}
static int raw_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
static int raw_setsockopt_locked(struct socket *sock, int optname,
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
struct raw_sock *ro = raw_sk(sk);
@ -575,9 +575,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
int flag;
int err = 0;
if (level != SOL_CAN_RAW)
return -EINVAL;
switch (optname) {
case CAN_RAW_FILTER:
if (optlen % sizeof(struct can_filter) != 0)
@ -598,17 +595,11 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
return -EFAULT;
}
rtnl_lock();
lock_sock(sk);
dev = ro->dev;
if (ro->bound && dev) {
if (dev->reg_state != NETREG_REGISTERED) {
if (count > 1)
kfree(filter);
err = -ENODEV;
goto out_fil;
}
if (ro->bound && dev && dev->reg_state != NETREG_REGISTERED) {
if (count > 1)
kfree(filter);
return -ENODEV;
}
if (ro->bound) {
@ -622,7 +613,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (err) {
if (count > 1)
kfree(filter);
goto out_fil;
return err;
}
/* remove old filter registrations */
@ -642,11 +633,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
}
ro->filter = filter;
ro->count = count;
out_fil:
release_sock(sk);
rtnl_unlock();
break;
case CAN_RAW_ERR_FILTER:
@ -658,16 +644,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
err_mask &= CAN_ERR_MASK;
rtnl_lock();
lock_sock(sk);
dev = ro->dev;
if (ro->bound && dev) {
if (dev->reg_state != NETREG_REGISTERED) {
err = -ENODEV;
goto out_err;
}
}
if (ro->bound && dev && dev->reg_state != NETREG_REGISTERED)
return -ENODEV;
/* remove current error mask */
if (ro->bound) {
@ -676,7 +655,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
err_mask);
if (err)
goto out_err;
return err;
/* remove old err_mask registration */
raw_disable_errfilter(sock_net(sk), dev, sk,
@ -685,11 +664,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
/* link new err_mask to the socket */
ro->err_mask = err_mask;
out_err:
release_sock(sk);
rtnl_unlock();
break;
case CAN_RAW_LOOPBACK:
@ -769,6 +743,26 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
return err;
}
static int raw_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
int err;
if (level != SOL_CAN_RAW)
return -EINVAL;
rtnl_lock();
lock_sock(sk);
err = raw_setsockopt_locked(sock, optname, optval, optlen);
release_sock(sk);
rtnl_unlock();
return err;
}
static int raw_getsockopt(struct socket *sock, int level, int optname,
sockopt_t *opt)
{

View File

@ -4018,6 +4018,9 @@ static struct sk_buff *validate_xmit_unreadable_skb(struct sk_buff *skb,
return NULL;
}
/* Returns the skb on success, NULL if dropped, or ERR_PTR(-EINPROGRESS)
* if stolen by async xfrm crypto (delivered via xfrm_dev_resume()).
*/
static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev, bool *again)
{
netdev_features_t features;
@ -4089,7 +4092,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d
skb->prev = skb;
skb = validate_xmit_skb(skb, dev, again);
if (!skb)
if (IS_ERR_OR_NULL(skb))
continue;
if (!head)
@ -4860,8 +4863,11 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
goto recursion_alert;
skb = validate_xmit_skb(skb, dev, &again);
if (!skb)
if (IS_ERR_OR_NULL(skb)) {
if (PTR_ERR(skb) == -EINPROGRESS)
rc = NET_XMIT_SUCCESS;
goto out;
}
HARD_TX_LOCK(dev, txq, cpu);

View File

@ -1385,7 +1385,7 @@ int fib_table_insert(struct net *net, struct fib_table *tb,
out_remove_new_fa:
fib_remove_alias(t, tp, l, new_fa);
out_free_new_fa:
kmem_cache_free(fn_alias_kmem, new_fa);
alias_free_mem_rcu(new_fa);
out:
fib_release_info(fi);
err:

View File

@ -2318,8 +2318,10 @@ int tcp_v4_rcv(struct sk_buff *skb)
}
drop_reason = psp_twsk_rx_policy_check(inet_twsk(sk), skb);
if (drop_reason)
break;
if (drop_reason) {
inet_twsk_put(inet_twsk(sk));
goto discard_it;
}
}
/* to ACK */
fallthrough;

View File

@ -120,7 +120,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
ktime_t tstamp = skb->tstamp;
struct ip6_frag_state state;
u8 *prevhdr, nexthdr = 0;
unsigned int mtu, hlen;
unsigned int mtu, hlen, nexthdr_offset;
int hroom, err = 0;
__be32 frag_id;
@ -129,6 +129,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
goto blackhole;
hlen = err;
nexthdr = *prevhdr;
nexthdr_offset = prevhdr - skb_network_header(skb);
mtu = skb->dev->mtu;
if (frag_max_size > mtu ||
@ -147,6 +148,7 @@ int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
(err = skb_checksum_help(skb)))
goto blackhole;
prevhdr = skb_network_header(skb) + nexthdr_offset;
hroom = LL_RESERVED_SPACE(skb->dev);
if (skb_has_frag_list(skb)) {
unsigned int first_len = skb_pagelen(skb);

View File

@ -1977,8 +1977,10 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb)
}
drop_reason = psp_twsk_rx_policy_check(inet_twsk(sk), skb);
if (drop_reason)
break;
if (drop_reason) {
inet_twsk_put(inet_twsk(sk));
goto discard_it;
}
}
/* to ACK */
fallthrough;

View File

@ -88,6 +88,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
xdst->u.rt6.rt6i_idev = in6_dev_get(dev);
if (!xdst->u.rt6.rt6i_idev) {
netdev_put(dev, &xdst->u.dst.dev_tracker);
xdst->u.dst.dev = NULL;
return -ENODEV;
}

View File

@ -2089,6 +2089,8 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
}
}
}
if (sk)
sock_hold(sk);
read_unlock(&iucv_sk_list.lock);
if (!iucv)
sk = NULL;
@ -2138,6 +2140,8 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
kfree_skb(skb);
}
if (sk)
sock_put(sk);
return err;
}

View File

@ -767,7 +767,6 @@ static struct sock *llc_create_incoming_sock(struct sock *sk,
newllc->dev = dev;
dev_hold(dev);
llc_sap_add_socket(llc->sap, newsk);
llc_sap_hold(llc->sap);
out:
return newsk;
}

View File

@ -1146,9 +1146,6 @@ static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata,
fd->max_interval = params->max_interval;
old = sdata_dereference(link->u.ap.fils_discovery, sdata);
if (old)
kfree_rcu(old, rcu_head);
if (params->tmpl && params->tmpl_len) {
new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
if (!new)
@ -1160,6 +1157,9 @@ static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata,
RCU_INIT_POINTER(link->u.ap.fils_discovery, NULL);
}
if (old)
kfree_rcu(old, rcu_head);
*changed |= BSS_CHANGED_FILS_DISCOVERY;
return 0;
}
@ -1179,8 +1179,6 @@ ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata,
link_conf->unsol_bcast_probe_resp_interval = params->interval;
old = sdata_dereference(link->u.ap.unsol_bcast_probe_resp, sdata);
if (old)
kfree_rcu(old, rcu_head);
if (params->tmpl && params->tmpl_len) {
new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
@ -1193,6 +1191,9 @@ ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata,
RCU_INIT_POINTER(link->u.ap.unsol_bcast_probe_resp, NULL);
}
if (old)
kfree_rcu(old, rcu_head);
*changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP;
return 0;
}

View File

@ -668,7 +668,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
sta_info_flush(sdata, -1);
netif_carrier_off(sdata->dev);
if (!sta_info_flush(sdata, -1))
synchronize_net();
spin_lock_bh(&ifibss->incomplete_lock);
while (!list_empty(&ifibss->incomplete_stations)) {
@ -682,8 +684,6 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
}
spin_unlock_bh(&ifibss->incomplete_lock);
netif_carrier_off(sdata->dev);
sdata->vif.cfg.ibss_joined = false;
sdata->vif.cfg.ibss_creator = false;
sdata->vif.bss_conf.enable_beacon = false;
@ -710,7 +710,6 @@ static void ieee80211_csa_connection_drop_work(struct wiphy *wiphy,
u.ibss.csa_connection_drop_work);
ieee80211_ibss_disconnect(sdata);
synchronize_rcu();
skb_queue_purge(&sdata->skb_queue);
/* trigger a scan to find another IBSS network to join */
@ -1029,8 +1028,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
u8 rx_nss = sta->sta.deflink.rx_nss;
/* Force rx_nss recalculation */
sta->sta.deflink.rx_nss = 0;
ieee80211_sta_init_nss_bw_capa(&sta->deflink,
&sdata->deflink.conf->chanreq.oper);
rate_control_rate_init(&sta->deflink);
if (sta->sta.deflink.rx_nss != rx_nss)
changed |= IEEE80211_RC_NSS_CHANGED;
@ -1797,8 +1796,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
synchronize_rcu();
skb_queue_purge(&sdata->skb_queue);
timer_delete_sync(&sdata->u.ibss.timer);

View File

@ -588,6 +588,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
WARN_ON(!list_empty(&sdata->u.ap.vlans));
} else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
/* remove all packets in parent bc_buf pointing to this dev */
__skb_queue_head_init(&freeq);
ps = &sdata->bss->ps;
spin_lock_irqsave(&ps->bc_buf.lock, flags);
@ -595,10 +596,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
if (skb->dev == sdata->dev) {
__skb_unlink(skb, &ps->bc_buf);
local->total_ps_buffered--;
ieee80211_free_txskb(&local->hw, skb);
__skb_queue_tail(&freeq, skb);
}
}
spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
skb_queue_walk_safe(&freeq, skb, tmp) {
__skb_unlink(skb, &freeq);
ieee80211_free_txskb(&local->hw, skb);
}
}
if (going_down)

View File

@ -1602,7 +1602,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
sband = kmemdup(sband, sizeof(*sband), GFP_KERNEL);
if (!sband) {
result = -ENOMEM;
goto fail_rate;
goto fail_band;
}
wiphy_dbg(hw->wiphy, "copying sband (band %d) due to VHT EXT NSS BW flag\n",
@ -1678,6 +1678,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
#endif
wiphy_unregister(local->hw.wiphy);
fail_wiphy_register:
fail_band:
rtnl_lock();
rate_control_deinitialize(local);
ieee80211_remove_interfaces(local);

View File

@ -5641,13 +5641,15 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
u16 reason_code;
lockdep_assert_wiphy(sdata->local->hw.wiphy);
if (len < 24 + 2)
if (len < offsetofend(struct ieee80211_mgmt, u.deauth.reason_code))
return;
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) {
ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code);
return;
@ -7138,7 +7140,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
u16 capab_info, status_code, aid;
u16 capab_info, status_code, aid = 0;
struct ieee80211_elems_parse_params parse_params = {
.bss = NULL,
.link_id = -1,
@ -7217,8 +7219,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
if (elems->aid_resp)
aid = le16_to_cpu(elems->aid_resp->aid);
else
else if (!assoc_data->s1g)
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
else if (status_code == WLAN_STATUS_SUCCESS)
goto abandon_assoc;
/*
* The 5 MSB of the AID field are reserved for a non-S1G STA. For

View File

@ -253,9 +253,12 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_nan_channel *sched_idx_to_chan[IEEE80211_NAN_MAX_CHANNELS] = {};
struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
struct ieee80211_nan_sched_cfg backup_sched;
struct ieee80211_nan_sched_cfg *backup_sched __free(kfree) = kmalloc_obj(*backup_sched);
int ret;
if (!backup_sched)
return -ENOMEM;
if (sched->n_channels > IEEE80211_NAN_MAX_CHANNELS)
return -EOPNOTSUPP;
@ -275,13 +278,13 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
memcpy(backup_sched.schedule, sched_cfg->schedule,
sizeof(backup_sched.schedule));
memcpy(backup_sched.channels, sched_cfg->channels,
sizeof(backup_sched.channels));
memcpy(backup_sched.avail_blob, sched_cfg->avail_blob,
sizeof(backup_sched.avail_blob));
backup_sched.avail_blob_len = sched_cfg->avail_blob_len;
memcpy(backup_sched->schedule, sched_cfg->schedule,
sizeof(backup_sched->schedule));
memcpy(backup_sched->channels, sched_cfg->channels,
sizeof(backup_sched->channels));
memcpy(backup_sched->avail_blob, sched_cfg->avail_blob,
sizeof(backup_sched->avail_blob));
backup_sched->avail_blob_len = sched_cfg->avail_blob_len;
memcpy(sched_cfg->avail_blob, sched->nan_avail_blob,
sched->nan_avail_blob_len);
@ -380,17 +383,17 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
if (!chan_def->chan)
continue;
if (!cfg80211_chandef_identical(&backup_sched.channels[i].chanreq.oper,
if (!cfg80211_chandef_identical(&backup_sched->channels[i].chanreq.oper,
chan_def))
ieee80211_nan_remove_channel(sdata,
&sched_cfg->channels[i]);
}
/* Re-add all backed up channels */
for (int i = 0; i < ARRAY_SIZE(backup_sched.channels); i++) {
for (int i = 0; i < ARRAY_SIZE(backup_sched->channels); i++) {
struct ieee80211_nan_channel *chan = &sched_cfg->channels[i];
*chan = backup_sched.channels[i];
*chan = backup_sched->channels[i];
/*
* For deferred update, no channels were removed and the channel
@ -421,11 +424,11 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
}
}
memcpy(sched_cfg->schedule, backup_sched.schedule,
sizeof(backup_sched.schedule));
memcpy(sched_cfg->avail_blob, backup_sched.avail_blob,
sizeof(backup_sched.avail_blob));
sched_cfg->avail_blob_len = backup_sched.avail_blob_len;
memcpy(sched_cfg->schedule, backup_sched->schedule,
sizeof(backup_sched->schedule));
memcpy(sched_cfg->avail_blob, backup_sched->avail_blob,
sizeof(backup_sched->avail_blob));
sched_cfg->avail_blob_len = backup_sched->avail_blob_len;
sched_cfg->deferred = false;
bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);

View File

@ -1526,6 +1526,9 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
if (status->flag & RX_FLAG_DUP_VALIDATED)
return RX_CONTINUE;
if (ieee80211_is_ext(hdr->frame_control))
return RX_CONTINUE;
/*
* Drop duplicate 802.11 retransmissions
* (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
@ -4510,12 +4513,16 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
bool multicast = is_multicast_ether_addr(hdr->addr1) ||
ieee80211_is_s1g_beacon(hdr->frame_control);
bool multicast;
static const u8 nan_network_id[ETH_ALEN] __aligned(2) = {
0x51, 0x6F, 0x9A, 0x01, 0x00, 0x00
};
if (ieee80211_is_s1g_beacon(hdr->frame_control))
return sdata->vif.type == NL80211_IFTYPE_STATION && bssid;
multicast = is_multicast_ether_addr(hdr->addr1);
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
if (!bssid && !sdata->u.mgd.use_4addr)
@ -5212,6 +5219,11 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
hdr = (struct ieee80211_hdr *)rx->skb->data;
}
if (ieee80211_is_s1g_beacon(hdr->frame_control)) {
ieee80211_invoke_rx_handlers(rx);
return true;
}
/* Store a copy of the pre-translated link addresses for SW crypto */
if (unlikely(is_unicast_ether_addr(hdr->addr1) &&
!ieee80211_is_data(hdr->frame_control)))
@ -5301,6 +5313,13 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
struct sta_info *sta;
int link_id = -1;
if (ieee80211_is_s1g_beacon(hdr->frame_control)) {
if (!ieee80211_rx_data_set_sta(rx, NULL, -1))
return false;
return ieee80211_prepare_and_rx_handle(rx, skb, consume);
}
/*
* Look up link station first, in case there's a
* chance that they might have a link address that
@ -5376,6 +5395,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
err = -ENOBUFS;
else
err = skb_linearize(skb);
} else if (ieee80211_is_s1g_beacon(fc)) {
size_t s1g_hdr_len = offsetof(struct ieee80211_ext,
u.s1g_beacon.variable) +
ieee80211_s1g_optional_len(fc);
if (skb->len < s1g_hdr_len)
err = -ENOBUFS;
else
err = skb_linearize(skb);
} else if (ieee80211_is_ext(fc)) {
err = -EINVAL;
} else {
err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
}

View File

@ -355,6 +355,15 @@ static void sta_info_free_link(struct link_sta_info *link_sta)
free_percpu(link_sta->pcpu_rx_stats);
}
static void sta_link_free_rcu(struct rcu_head *head)
{
struct sta_link_alloc *alloc =
container_of(head, struct sta_link_alloc, rcu_head);
sta_info_free_link(&alloc->info);
kfree(alloc);
}
static void sta_accumulate_removed_link_stats(struct sta_info *sta, int link_id)
{
struct link_sta_info *link_sta = wiphy_dereference(sta->local->hw.wiphy,
@ -439,10 +448,8 @@ static void sta_remove_link(struct sta_info *sta, unsigned int link_id,
RCU_INIT_POINTER(sta->link[link_id], NULL);
RCU_INIT_POINTER(sta->sta.link[link_id], NULL);
if (alloc) {
sta_info_free_link(&alloc->info);
kfree_rcu(alloc, rcu_head);
}
if (alloc)
call_rcu(&alloc->rcu_head, sta_link_free_rcu);
ieee80211_sta_recalc_aggregates(&sta->sta);
}

View File

@ -2607,6 +2607,18 @@ static u16 ieee80211_store_ack_skb(struct ieee80211_local *local,
return info_id;
}
static void ieee80211_remove_ack_skb(struct ieee80211_local *local, u16 info_id)
{
struct sk_buff *ack_skb;
unsigned long flags;
spin_lock_irqsave(&local->ack_status_lock, flags);
ack_skb = idr_remove(&local->ack_status_frames, info_id);
spin_unlock_irqrestore(&local->ack_status_lock, flags);
kfree_skb(ack_skb);
}
/**
* ieee80211_build_hdr - build 802.11 header in the given frame
* @sdata: virtual interface to build the header for
@ -2982,7 +2994,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) {
ieee80211_free_txskb(&local->hw, skb);
skb = NULL;
return ERR_PTR(-ENOMEM);
ret = -ENOMEM;
goto free;
}
}
@ -3050,6 +3063,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
return skb;
free:
if (info_id)
ieee80211_remove_ack_skb(local, info_id);
kfree_skb(skb);
return ERR_PTR(ret);
}

View File

@ -73,6 +73,9 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
if (ieee80211_is_s1g_beacon(fc)) {
struct ieee80211_ext *ext = (void *) hdr;
if (len < offsetofend(struct ieee80211_ext, u.s1g_beacon.sa))
return NULL;
return ext->u.s1g_beacon.sa;
}

View File

@ -2186,6 +2186,9 @@ static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
int ifindex;
if (i == RTA_OIF) {
if (!tb[i])
continue;
ifindex = nla_get_u32(tb[i]);
filter->dev = dev_get_by_index_rcu(net, ifindex);
if (!filter->dev)

View File

@ -361,14 +361,13 @@ static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb,
struct ip_vs_iphdr *ipvsh)
{
int diff;
const unsigned int tcp_offset = ip_hdrlen(skb);
struct tcphdr *th;
__u32 seq;
if (skb_ensure_writable(skb, tcp_offset + sizeof(*th)))
if (skb_ensure_writable(skb, ipvsh->len + sizeof(*th)))
return 0;
th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
th = (struct tcphdr *)(skb_network_header(skb) + ipvsh->len);
/*
* Remember seq number in case this pkt gets resized
@ -438,14 +437,13 @@ static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff *skb,
struct ip_vs_iphdr *ipvsh)
{
int diff;
const unsigned int tcp_offset = ip_hdrlen(skb);
struct tcphdr *th;
__u32 seq;
if (skb_ensure_writable(skb, tcp_offset + sizeof(*th)))
if (skb_ensure_writable(skb, ipvsh->len + sizeof(*th)))
return 0;
th = (struct tcphdr *)(skb_network_header(skb) + tcp_offset);
th = (struct tcphdr *)(skb_network_header(skb) + ipvsh->len);
/*
* Remember seq number in case this pkt gets resized

View File

@ -1219,8 +1219,7 @@ static int ip_vs_out_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb,
snet.in6 = ciph.saddr.in6;
offset = ciph.len;
return handle_response_icmp(AF_INET6, skb, &snet, ciph.protocol, cp,
pp, offset, sizeof(struct ipv6hdr),
hooknum);
pp, offset, ipvsh->len, hooknum);
}
#endif

View File

@ -736,13 +736,11 @@ int
ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{
struct iphdr *iph = ip_hdr(skb);
if (__ip_vs_get_out_rt(cp->ipvs, cp->af, skb, NULL, iph->daddr,
if (__ip_vs_get_out_rt(cp->ipvs, cp->af, skb, NULL, ip_hdr(skb)->daddr,
IP_VS_RT_MODE_NON_LOCAL, NULL, ipvsh) < 0)
goto tx_error;
ip_send_check(iph);
ip_send_check(ip_hdr(skb));
/* Another hack: avoid icmp_send in ip_fragment */
skb->ignore_df = 1;

View File

@ -211,8 +211,8 @@ static int __nf_conncount_add(struct net *net,
/* Not found, but might be about to be confirmed */
if (PTR_ERR(found) == -EAGAIN) {
if (nf_ct_tuple_equal(&conn->tuple, &tuple) &&
nf_ct_zone_id(&conn->zone, conn->zone.dir) ==
nf_ct_zone_id(zone, zone->dir))
nf_ct_zone_id(&conn->zone, IP_CT_DIR_ORIGINAL) ==
nf_ct_zone_id(zone, IP_CT_DIR_ORIGINAL))
goto out_put; /* already exists */
} else {
collect++;
@ -223,7 +223,7 @@ static int __nf_conncount_add(struct net *net,
found_ct = nf_ct_tuplehash_to_ctrack(found);
if (nf_ct_tuple_equal(&conn->tuple, &tuple) &&
nf_ct_zone_equal(found_ct, zone, zone->dir)) {
nf_ct_zone_equal(found_ct, zone, IP_CT_DIR_ORIGINAL)) {
/*
* We should not see tuples twice unless someone hooks
* this into a table without "-p tcp --syn".

View File

@ -77,7 +77,7 @@ static enum retry_state ecache_work_evict_list(struct nf_conntrack_net *cnet)
hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode, &evicted_list);
if (time_after(stop, jiffies)) {
if (time_after(jiffies, stop)) {
ret = STATE_RESTART;
break;
}

View File

@ -127,18 +127,18 @@ static int flow_offload_fill_route(struct flow_offload *flow,
switch (route->tuple[dir].xmit_type) {
case FLOW_OFFLOAD_XMIT_DIRECT:
if (flow_tuple->tun_num) {
if (route->tuple[!dir].in.num_tuns) {
flow_tuple->dst_cache = dst;
flow_tuple->dst_cookie =
flow_offload_dst_cookie(flow_tuple);
} else {
dst_release(dst);
}
memcpy(flow_tuple->out.h_dest, route->tuple[dir].out.h_dest,
ETH_ALEN);
memcpy(flow_tuple->out.h_source, route->tuple[dir].out.h_source,
ETH_ALEN);
flow_tuple->out.ifidx = route->tuple[dir].out.ifindex;
if (!flow_tuple->tun_num)
dst_release(dst);
break;
case FLOW_OFFLOAD_XMIT_XFRM:
case FLOW_OFFLOAD_XMIT_NEIGH:

View File

@ -26,6 +26,15 @@ static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par)
static int xt_nat_checkentry(const struct xt_tgchk_param *par)
{
switch (par->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
case NFPROTO_INET:
break;
default:
return -EINVAL;
}
return nf_ct_netns_get(par->net, par->family);
}

View File

@ -130,11 +130,6 @@ static int physdev_mt_check(const struct xt_mtchk_param *par)
if (X(physoutdev))
return -ENAMETOOLONG;
}
if (X(in_mask))
return -ENAMETOOLONG;
if (X(out_mask))
return -ENAMETOOLONG;
#undef X
if (!brnf_probed) {

View File

@ -2496,13 +2496,56 @@ static inline int add_nested_action_start(struct sw_flow_actions **sfa,
return used;
}
static inline void add_nested_action_end(struct sw_flow_actions *sfa,
int st_offset)
static inline int add_nested_action_end(struct sw_flow_actions *sfa,
int st_offset)
{
struct nlattr *a = (struct nlattr *) ((unsigned char *)sfa->actions +
st_offset);
struct nlattr *a;
u32 attr_len;
a->nla_len = sfa->actions_len - st_offset;
if (WARN_ON_ONCE(st_offset < 0 ||
(u32)st_offset > sfa->actions_len))
return -EINVAL;
attr_len = sfa->actions_len - (u32)st_offset;
if (WARN_ON_ONCE(attr_len < NLA_HDRLEN))
return -EINVAL;
if (attr_len > U16_MAX)
return -EMSGSIZE;
a = (struct nlattr *)((u8 *)sfa->actions + st_offset);
a->nla_len = attr_len;
return 0;
}
/* Free the generated action-list tail at @start and truncate it.
* If @nested, @start points to its containing nlattr header.
*/
static void ovs_nla_trim(struct sw_flow_actions *sfa, int start, bool nested)
{
const struct nlattr *actions;
u32 len;
if (start < 0)
return;
if (WARN_ON_ONCE((u32)start > sfa->actions_len))
return;
actions = (const struct nlattr *)((u8 *)sfa->actions + start);
len = sfa->actions_len - (u32)start;
if (nested) {
if (len < NLA_HDRLEN)
goto out;
actions = (const struct nlattr *)((u8 *)actions + NLA_HDRLEN);
len -= NLA_HDRLEN;
}
ovs_nla_free_nested_actions(actions, len);
out:
sfa->actions_len = start;
}
static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
@ -2522,6 +2565,7 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1];
const struct nlattr *probability, *actions;
const struct nlattr *a;
int actions_start;
int rem, start, err;
struct sample_arg arg;
@ -2565,18 +2609,27 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
err = ovs_nla_add_action(sfa, OVS_SAMPLE_ATTR_ARG, &arg, sizeof(arg),
log);
if (err)
return err;
goto err;
actions_start = (*sfa)->actions_len;
err = __ovs_nla_copy_actions(net, actions, key, sfa,
eth_type, vlan_tci, mpls_label_count, log,
depth + 1);
if (err)
return err;
goto err_free;
add_nested_action_end(*sfa, start);
err = add_nested_action_end(*sfa, start);
if (err)
goto err_free;
return 0;
err_free:
ovs_nla_trim(*sfa, actions_start, false);
err:
(*sfa)->actions_len = start;
return err;
}
static int validate_and_copy_dec_ttl(struct net *net,
@ -2624,18 +2677,31 @@ static int validate_and_copy_dec_ttl(struct net *net,
return start;
action_start = add_nested_action_start(sfa, OVS_DEC_TTL_ATTR_ACTION, log);
if (action_start < 0)
return action_start;
if (action_start < 0) {
err = action_start;
goto err;
}
err = __ovs_nla_copy_actions(net, actions, key, sfa, eth_type,
vlan_tci, mpls_label_count, log,
depth + 1);
if (err)
return err;
goto err_free;
add_nested_action_end(*sfa, action_start);
add_nested_action_end(*sfa, start);
err = add_nested_action_end(*sfa, action_start);
if (err)
goto err_free;
err = add_nested_action_end(*sfa, start);
if (err)
goto err_free;
return 0;
err_free:
ovs_nla_trim(*sfa, action_start, true);
err:
(*sfa)->actions_len = start;
return err;
}
static int validate_and_copy_clone(struct net *net,
@ -2646,6 +2712,7 @@ static int validate_and_copy_clone(struct net *net,
u32 mpls_label_count, bool log, bool last,
u32 depth)
{
int actions_start;
int start, err;
u32 exec;
@ -2661,17 +2728,26 @@ static int validate_and_copy_clone(struct net *net,
err = ovs_nla_add_action(sfa, OVS_CLONE_ATTR_EXEC, &exec,
sizeof(exec), log);
if (err)
return err;
goto err;
actions_start = (*sfa)->actions_len;
err = __ovs_nla_copy_actions(net, attr, key, sfa,
eth_type, vlan_tci, mpls_label_count, log,
depth + 1);
if (err)
return err;
goto err_free;
add_nested_action_end(*sfa, start);
err = add_nested_action_end(*sfa, start);
if (err)
goto err_free;
return 0;
err_free:
ovs_nla_trim(*sfa, actions_start, false);
err:
(*sfa)->actions_len = start;
return err;
}
void ovs_match_init(struct sw_flow_match *match,
@ -2763,20 +2839,20 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
tun_dst = metadata_dst_alloc(key.tun_opts_len, METADATA_IP_TUNNEL,
GFP_KERNEL);
if (!tun_dst)
return -ENOMEM;
if (!tun_dst) {
err = -ENOMEM;
goto err;
}
err = dst_cache_init(&tun_dst->u.tun_info.dst_cache, GFP_KERNEL);
if (err) {
dst_release((struct dst_entry *)tun_dst);
return err;
}
if (err)
goto err_free_tun_dst;
a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL,
sizeof(*ovs_tun), log);
if (IS_ERR(a)) {
dst_release((struct dst_entry *)tun_dst);
return PTR_ERR(a);
err = PTR_ERR(a);
goto err_free_tun_dst;
}
ovs_tun = nla_data(a);
@ -2797,8 +2873,16 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
ip_tunnel_info_opts_set(tun_info,
TUN_METADATA_OPTS(&key, key.tun_opts_len),
key.tun_opts_len, dst_opt_type);
add_nested_action_end(*sfa, start);
err = add_nested_action_end(*sfa, start);
if (WARN_ON_ONCE(err))
goto err_free_tun_dst;
return 0;
err_free_tun_dst:
dst_release((struct dst_entry *)tun_dst);
err:
(*sfa)->actions_len = start;
return err;
}
@ -2971,7 +3055,7 @@ static int validate_set(const struct nlattr *a,
/* Convert non-masked non-tunnel set actions to masked set actions. */
if (!masked && key_type != OVS_KEY_ATTR_TUNNEL) {
int start, len = key_len * 2;
int err, start, len = key_len * 2;
struct nlattr *at;
*skip_copy = true;
@ -2983,8 +3067,11 @@ static int validate_set(const struct nlattr *a,
return start;
at = __add_action(sfa, key_type, NULL, len, log);
if (IS_ERR(at))
return PTR_ERR(at);
if (IS_ERR(at)) {
err = PTR_ERR(at);
(*sfa)->actions_len = start;
return err;
}
memcpy(nla_data(at), nla_data(ovs_key), key_len); /* Key. */
memset(nla_data(at) + key_len, 0xff, key_len); /* Mask. */
@ -2994,7 +3081,11 @@ static int validate_set(const struct nlattr *a,
mask->ipv6_label &= htonl(0x000FFFFF);
}
add_nested_action_end(*sfa, start);
err = add_nested_action_end(*sfa, start);
if (WARN_ON_ONCE(err)) {
(*sfa)->actions_len = start;
return err;
}
}
return 0;
@ -3040,7 +3131,8 @@ static int validate_and_copy_check_pkt_len(struct net *net,
const struct nlattr *acts_if_greater, *acts_if_lesser_eq;
struct nlattr *a[OVS_CHECK_PKT_LEN_ATTR_MAX + 1];
struct check_pkt_len_arg arg;
int nested_acts_start;
int greater_acts_start = -1;
int lesser_acts_start = -1;
int start, err;
err = nla_parse_deprecated_strict(a, OVS_CHECK_PKT_LEN_ATTR_MAX,
@ -3075,37 +3167,58 @@ static int validate_and_copy_check_pkt_len(struct net *net,
err = ovs_nla_add_action(sfa, OVS_CHECK_PKT_LEN_ATTR_ARG, &arg,
sizeof(arg), log);
if (err)
return err;
goto err_free;
nested_acts_start = add_nested_action_start(sfa,
OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL, log);
if (nested_acts_start < 0)
return nested_acts_start;
lesser_acts_start =
add_nested_action_start(sfa,
OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL,
log);
if (lesser_acts_start < 0) {
err = lesser_acts_start;
goto err_free;
}
err = __ovs_nla_copy_actions(net, acts_if_lesser_eq, key, sfa,
eth_type, vlan_tci, mpls_label_count, log,
depth + 1);
if (err)
return err;
goto err_free;
add_nested_action_end(*sfa, nested_acts_start);
err = add_nested_action_end(*sfa, lesser_acts_start);
if (err)
goto err_free;
nested_acts_start = add_nested_action_start(sfa,
OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER, log);
if (nested_acts_start < 0)
return nested_acts_start;
greater_acts_start =
add_nested_action_start(sfa,
OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER,
log);
if (greater_acts_start < 0) {
err = greater_acts_start;
goto err_free;
}
err = __ovs_nla_copy_actions(net, acts_if_greater, key, sfa,
eth_type, vlan_tci, mpls_label_count, log,
depth + 1);
if (err)
return err;
goto err_free;
add_nested_action_end(*sfa, nested_acts_start);
add_nested_action_end(*sfa, start);
err = add_nested_action_end(*sfa, greater_acts_start);
if (err)
goto err_free;
err = add_nested_action_end(*sfa, start);
if (err)
goto err_free;
return 0;
err_free:
ovs_nla_trim(*sfa, greater_acts_start, true);
ovs_nla_trim(*sfa, lesser_acts_start, true);
ovs_nla_trim(*sfa, start, false);
return err;
}
static int validate_psample(const struct nlattr *attr)

View File

@ -342,14 +342,20 @@ static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = {
[TCA_TUNNEL_KEY_ENC_TTL] = { .type = NLA_U8 },
};
static void tunnel_key_release_params_rcu(struct rcu_head *head)
{
struct tcf_tunnel_key_params *p = container_of(head, typeof(*p), rcu);
if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
dst_release(&p->tcft_enc_metadata->dst);
kfree(p);
}
static void tunnel_key_release_params(struct tcf_tunnel_key_params *p)
{
if (!p)
return;
if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
dst_release(&p->tcft_enc_metadata->dst);
kfree_rcu(p, rcu);
call_rcu(&p->rcu, tunnel_key_release_params_rcu);
}
static int tunnel_key_init(struct net *net, struct nlattr *nla,

View File

@ -74,7 +74,8 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale(
const struct sctp_association *asoc,
const union sctp_subtype type,
void *arg,
struct sctp_cmd_seq *commands);
struct sctp_cmd_seq *commands,
struct sctp_errhdr *err);
static enum sctp_disposition sctp_sf_shut_8_4_5(
struct net *net,
const struct sctp_endpoint *ep,
@ -2529,9 +2530,15 @@ enum sctp_disposition sctp_sf_cookie_echoed_err(
* errors.
*/
sctp_walk_errors(err, chunk->chunk_hdr) {
if (SCTP_ERROR_STALE_COOKIE == err->cause)
return sctp_sf_do_5_2_6_stale(net, ep, asoc, type,
arg, commands);
if (err->cause != SCTP_ERROR_STALE_COOKIE)
continue;
/* The staleness is only meaningful if the cause is long
* enough to hold it; a shorter one is malformed.
*/
if (ntohs(err->length) < sizeof(*err) + sizeof(__be32))
break;
return sctp_sf_do_5_2_6_stale(net, ep, asoc, type,
arg, commands, err);
}
/* It is possible to have malformed error causes, and that
@ -2573,13 +2580,13 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale(
const struct sctp_association *asoc,
const union sctp_subtype type,
void *arg,
struct sctp_cmd_seq *commands)
struct sctp_cmd_seq *commands,
struct sctp_errhdr *err)
{
int attempts = asoc->init_err_counter + 1;
struct sctp_chunk *chunk = arg, *reply;
struct sctp_cookie_preserve_param bht;
struct sctp_bind_addr *bp;
struct sctp_errhdr *err;
struct sctp_chunk *reply;
u32 stale;
if (attempts > asoc->max_init_attempts) {
@ -2590,8 +2597,6 @@ static enum sctp_disposition sctp_sf_do_5_2_6_stale(
return SCTP_DISPOSITION_DELETE_TCB;
}
err = (struct sctp_errhdr *)(chunk->skb->data);
/* When calculating the time extension, an implementation
* SHOULD use the RTT information measured based on the
* previous COOKIE ECHO / ERROR exchange, and should add no

View File

@ -1335,6 +1335,7 @@ void wiphy_unregister(struct wiphy *wiphy)
/* this has nothing to do now but make sure it's gone */
cancel_work_sync(&rdev->wiphy_work);
cancel_work_sync(&rdev->sched_scan_res_wk);
cancel_work_sync(&rdev->rfkill_block);
cancel_work_sync(&rdev->conn_work);
flush_work(&rdev->event_work);
@ -1424,6 +1425,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
list_del_rcu(&wdev->list);
synchronize_net();
rdev->devlist_generation++;
wiphy_work_cancel(wdev->wiphy, &wdev->disconnect_wk);
cfg80211_mlme_purge_registrations(wdev);
@ -1613,7 +1615,7 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
INIT_LIST_HEAD(&wdev->mgmt_registrations);
INIT_LIST_HEAD(&wdev->pmsr_list);
spin_lock_init(&wdev->pmsr_lock);
INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
wiphy_work_init(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
#ifdef CONFIG_CFG80211_WEXT
wdev->wext.default_key = -1;
@ -1637,7 +1639,7 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
wdev->netdev->priv_flags |= IFF_DONT_BRIDGE;
INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
wiphy_work_init(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
}
void cfg80211_register_wdev(struct cfg80211_registered_device *rdev,
@ -1743,11 +1745,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
break;
case NETDEV_GOING_DOWN:
cfg80211_leave(rdev, wdev, -1);
scoped_guard(wiphy, &rdev->wiphy)
scoped_guard(wiphy, &rdev->wiphy) {
cfg80211_remove_links(wdev);
/* since we just did cfg80211_leave() nothing to do there */
cancel_work_sync(&wdev->disconnect_wk);
cancel_work_sync(&wdev->pmsr_free_wk);
/* since we just did cfg80211_leave() nothing to do there */
wiphy_work_cancel(wdev->wiphy, &wdev->disconnect_wk);
}
break;
case NETDEV_DOWN:
wiphy_lock(&rdev->wiphy);

View File

@ -428,7 +428,7 @@ void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *peer_addr,
const u8 *td_bitmap, u8 td_bitmap_len);
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
void cfg80211_autodisconnect_wk(struct work_struct *work);
void cfg80211_autodisconnect_wk(struct wiphy *wiphy, struct wiphy_work *work);
/* SME implementation */
void cfg80211_conn_work(struct work_struct *work);
@ -586,7 +586,7 @@ cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len,
void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid);
void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev);
void cfg80211_pmsr_free_wk(struct work_struct *work);
void cfg80211_pmsr_free_wk(struct wiphy *wiphy, struct wiphy_work *work);
void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id);
void cfg80211_remove_links(struct wireless_dev *wdev);

View File

@ -32,15 +32,11 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED,
.req_ie = data->req_ies,
.req_ie_len = data->req_ies_len,
.resp_ie = mgmt->u.assoc_resp.variable,
.resp_ie_len = data->len -
offsetof(struct ieee80211_mgmt,
u.assoc_resp.variable),
.status = le16_to_cpu(mgmt->u.assoc_resp.status_code),
.ap_mld_addr = data->ap_mld_addr,
.assoc_encrypted = data->assoc_encrypted,
};
unsigned int link_id;
bool is_s1g = false;
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
cr.links[link_id].status = data->links[link_id].status;
@ -61,16 +57,32 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
if (cr.links[link_id].bss->channel->band == NL80211_BAND_S1GHZ) {
WARN_ON(link_id);
cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
cr.resp_ie_len = data->len -
offsetof(struct ieee80211_mgmt,
u.s1g_assoc_resp.variable);
is_s1g = true;
}
if (cr.ap_mld_addr)
cr.valid_links |= BIT(link_id);
}
if (is_s1g) {
if (data->len < offsetof(struct ieee80211_mgmt,
u.s1g_assoc_resp.variable))
goto free_bss;
cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
cr.resp_ie_len = data->len -
offsetof(struct ieee80211_mgmt,
u.s1g_assoc_resp.variable);
} else {
if (data->len < offsetof(struct ieee80211_mgmt,
u.assoc_resp.variable))
goto free_bss;
cr.resp_ie = mgmt->u.assoc_resp.variable;
cr.resp_ie_len = data->len -
offsetof(struct ieee80211_mgmt,
u.assoc_resp.variable);
}
cr.status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
trace_cfg80211_send_rx_assoc(dev, data);
/*
@ -79,22 +91,24 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
* and got a reject -- we only try again with an assoc
* frame instead of reassoc.
*/
if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
struct cfg80211_bss *bss = data->links[link_id].bss;
if (!bss)
continue;
cfg80211_unhold_bss(bss_from_pub(bss));
cfg80211_put_bss(wiphy, bss);
}
return;
}
if (cfg80211_sme_rx_assoc_resp(wdev, cr.status))
goto free_bss;
nl80211_send_rx_assoc(rdev, dev, data);
/* update current_bss etc., consumes the bss reference */
__cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
return;
free_bss:
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
struct cfg80211_bss *bss = data->links[link_id].bss;
if (!bss)
continue;
cfg80211_unhold_bss(bss_from_pub(bss));
cfg80211_put_bss(wiphy, bss);
}
}
EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
@ -151,19 +165,35 @@ void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_mgmt *mgmt = (void *)buf;
__le16 fc;
lockdep_assert_wiphy(wdev->wiphy);
trace_cfg80211_rx_mlme_mgmt(dev, buf, len);
if (WARN_ON(len < 2))
if (len < sizeof(fc))
return;
if (ieee80211_is_auth(mgmt->frame_control))
fc = mgmt->frame_control;
if (ieee80211_is_auth(fc)) {
if (len < offsetofend(struct ieee80211_mgmt, u.auth.status_code))
return;
} else if (ieee80211_is_deauth(fc)) {
if (len < offsetofend(struct ieee80211_mgmt, u.deauth.reason_code))
return;
} else if (ieee80211_is_disassoc(fc)) {
if (len < offsetofend(struct ieee80211_mgmt, u.disassoc.reason_code))
return;
} else {
return;
}
trace_cfg80211_rx_mlme_mgmt(dev, buf, len);
if (ieee80211_is_auth(fc))
cfg80211_process_auth(wdev, buf, len);
else if (ieee80211_is_deauth(mgmt->frame_control))
else if (ieee80211_is_deauth(fc))
cfg80211_process_deauth(wdev, buf, len, false);
else if (ieee80211_is_disassoc(mgmt->frame_control))
else
cfg80211_process_disassoc(wdev, buf, len, false);
}
EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt);
@ -216,15 +246,28 @@ void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_mgmt *mgmt = (void *)buf;
__le16 fc;
lockdep_assert_wiphy(wdev->wiphy);
trace_cfg80211_tx_mlme_mgmt(dev, buf, len, reconnect);
if (WARN_ON(len < 2))
if (len < sizeof(fc))
return;
if (ieee80211_is_deauth(mgmt->frame_control))
fc = mgmt->frame_control;
if (ieee80211_is_deauth(fc)) {
if (len < offsetofend(struct ieee80211_mgmt, u.deauth.reason_code))
return;
} else if (ieee80211_is_disassoc(fc)) {
if (len < offsetofend(struct ieee80211_mgmt, u.disassoc.reason_code))
return;
} else {
return;
}
trace_cfg80211_tx_mlme_mgmt(dev, buf, len, reconnect);
if (ieee80211_is_deauth(fc))
cfg80211_process_deauth(wdev, buf, len, reconnect);
else
cfg80211_process_disassoc(wdev, buf, len, reconnect);

View File

@ -461,7 +461,9 @@ nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
static const struct nla_policy
nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
[NL80211_PMSR_FTM_REQ_ATTR_ASAP] = { .type = NLA_FLAG },
[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] = { .type = NLA_U32 },
[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] =
NLA_POLICY_RANGE(NLA_U32, NL80211_PREAMBLE_LEGACY,
NL80211_PREAMBLE_HE),
[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] =
NLA_POLICY_MAX(NLA_U8, 15),
[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 },
@ -630,7 +632,7 @@ nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = {
[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 },
[NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG },
[NL80211_MBSSID_CONFIG_ATTR_TX_LINK_ID] =
NLA_POLICY_MAX(NLA_U8, IEEE80211_MLD_MAX_NUM_LINKS),
NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS - 1),
};
static const struct nla_policy
@ -6510,7 +6512,8 @@ static int nl80211_parse_mbssid_config(struct wiphy *wiphy,
}
static struct cfg80211_mbssid_elems *
nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs,
struct netlink_ext_ack *extack)
{
struct nlattr *nl_elems;
struct cfg80211_mbssid_elems *elems;
@ -6521,6 +6524,12 @@ nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
return ERR_PTR(-EINVAL);
nla_for_each_nested(nl_elems, attrs, rem_elems) {
int ret;
ret = validate_ie_attr(nl_elems, extack);
if (ret)
return ERR_PTR(ret);
if (num_elems >= 255)
return ERR_PTR(-EINVAL);
num_elems++;
@ -6787,7 +6796,8 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
if (attrs[NL80211_ATTR_MBSSID_ELEMS]) {
struct cfg80211_mbssid_elems *mbssid =
nl80211_parse_mbssid_elems(&rdev->wiphy,
attrs[NL80211_ATTR_MBSSID_ELEMS]);
attrs[NL80211_ATTR_MBSSID_ELEMS],
extack);
if (IS_ERR(mbssid))
return PTR_ERR(mbssid);
@ -6803,8 +6813,10 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
if (IS_ERR(rnr))
return PTR_ERR(rnr);
if (rnr && rnr->cnt < bcn->mbssid_ies->cnt)
if (rnr && rnr->cnt < bcn->mbssid_ies->cnt) {
kfree(rnr);
return -EINVAL;
}
bcn->rnr_ies = rnr;
}
@ -22942,7 +22954,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
wdev->nl_owner_dead = true;
schedule_work(&rdev->destroy_work);
} else if (wdev->conn_owner_nlportid == notify->portid) {
schedule_work(&wdev->disconnect_wk);
wiphy_work_queue(wdev->wiphy,
&wdev->disconnect_wk);
}
cfg80211_release_pmsr(wdev, notify->portid);

View File

@ -125,6 +125,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
NL_SET_ERR_MSG_ATTR(info->extack,
tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI],
"FTM: LCI request not supported");
return -EOPNOTSUPP;
}
out->ftm.request_civicloc =
@ -133,6 +134,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
NL_SET_ERR_MSG_ATTR(info->extack,
tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC],
"FTM: civic location request not supported");
return -EOPNOTSUPP;
}
out->ftm.trigger_based =
@ -310,6 +312,7 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
{
struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
struct nlattr *req[NL80211_PMSR_REQ_ATTR_MAX + 1];
bool have_measurement_type = false;
struct nlattr *treq;
int err, rem;
@ -376,6 +379,14 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
}
nla_for_each_nested(treq, req[NL80211_PMSR_REQ_ATTR_DATA], rem) {
if (have_measurement_type) {
NL_SET_ERR_MSG_ATTR(info->extack, treq,
"multiple measurement types in request data");
return -EINVAL;
}
have_measurement_type = true;
switch (nla_type(treq)) {
case NL80211_PMSR_TYPE_FTM:
err = pmsr_parse_ftm(rdev, treq, out, info);
@ -385,10 +396,16 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
"unsupported measurement type");
err = -EINVAL;
}
if (err)
return err;
}
if (err)
return err;
if (!have_measurement_type) {
NL_SET_ERR_MSG_ATTR(info->extack,
req[NL80211_PMSR_REQ_ATTR_DATA],
"missing measurement type in request data");
return -EINVAL;
}
return 0;
}
@ -427,6 +444,11 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
}
}
if (!count) {
NL_SET_ERR_MSG_ATTR(info->extack, peers, "No peers specified");
return -EINVAL;
}
req = kzalloc_flex(*req, peers, count);
if (!req)
return -ENOMEM;
@ -807,13 +829,11 @@ static void cfg80211_pmsr_process_abort(struct wireless_dev *wdev)
}
}
void cfg80211_pmsr_free_wk(struct work_struct *work)
void cfg80211_pmsr_free_wk(struct wiphy *wiphy, struct wiphy_work *work)
{
struct wireless_dev *wdev = container_of(work, struct wireless_dev,
pmsr_free_wk);
guard(wiphy)(wdev->wiphy);
cfg80211_pmsr_process_abort(wdev);
}
@ -829,7 +849,7 @@ void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev)
}
spin_unlock_bh(&wdev->pmsr_lock);
cancel_work_sync(&wdev->pmsr_free_wk);
wiphy_work_cancel(wdev->wiphy, &wdev->pmsr_free_wk);
if (found)
cfg80211_pmsr_process_abort(wdev);
@ -844,7 +864,7 @@ void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid)
list_for_each_entry(req, &wdev->pmsr_list, list) {
if (req->nl_portid == portid) {
req->nl_portid = 0;
schedule_work(&wdev->pmsr_free_wk);
wiphy_work_queue(wdev->wiphy, &wdev->pmsr_free_wk);
}
}
spin_unlock_bh(&wdev->pmsr_lock);

View File

@ -205,7 +205,7 @@ bool cfg80211_is_element_inherited(const struct element *elem,
return true;
if (elem->id == WLAN_EID_EXTENSION) {
if (!ext_id_len)
if (!ext_id_len || !elem->datalen)
return true;
loop_len = ext_id_len;
list = &non_inherit_elem->data[3 + id_len];
@ -326,8 +326,11 @@ cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
/* For ML probe response, match the MLE in the frame body with
* MLD id being 'bssid_index'
*/
if (parent->id == WLAN_EID_EXTENSION && parent->datalen > 1 &&
if (parent->id == WLAN_EID_EXTENSION &&
parent->data[0] == WLAN_EID_EXT_EHT_MULTI_LINK &&
ieee80211_mle_type_ok(parent->data + 1,
IEEE80211_ML_CONTROL_TYPE_BASIC,
parent->datalen - 1) &&
bssid_index == ieee80211_mle_get_mld_id(parent->data + 1)) {
if (!cfg80211_copy_elem_with_frags(parent,
ie, ielen,
@ -3311,14 +3314,15 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
bssid = ext->u.s1g_beacon.sa;
capability = le16_to_cpu(compat->compat_info);
beacon_interval = le16_to_cpu(compat->beacon_int);
tsf = le32_to_cpu(ext->u.s1g_beacon.timestamp);
tsf |= (u64)le32_to_cpu(compat->tsf_completion) << 32;
} else {
bssid = mgmt->bssid;
beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
}
tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
if (ieee80211_is_probe_resp(mgmt->frame_control))
ftype = CFG80211_BSS_FTYPE_PRESP;
else if (ext)
@ -3612,8 +3616,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
/* translate "Scan for SSID" request */
if (wreq) {
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
return -EINVAL;
if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) {
err = -EINVAL;
goto out;
}
memcpy(creq->req.ssids[0].ssid, wreq->essid,
wreq->essid_len);
creq->req.ssids[0].ssid_len = wreq->essid_len;

View File

@ -1578,13 +1578,11 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
* Used to clean up after the connection / connection attempt owner socket
* disconnects
*/
void cfg80211_autodisconnect_wk(struct work_struct *work)
void cfg80211_autodisconnect_wk(struct wiphy *wiphy, struct wiphy_work *work)
{
struct wireless_dev *wdev =
container_of(work, struct wireless_dev, disconnect_wk);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
guard(wiphy)(wdev->wiphy);
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
if (wdev->conn_owner_nlportid) {
switch (wdev->iftype) {

View File

@ -182,7 +182,7 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
err = x->type_offload->xmit(x, skb, esp_features);
if (err) {
if (err == -EINPROGRESS)
return NULL;
return ERR_PTR(-EINPROGRESS);
XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
kfree_skb(skb);
@ -224,7 +224,15 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
pskb = skb2;
}
return skb;
/* skb_gso_segment() set skb->prev to the last segment, but async
* crypto may have stolen it above without updating ->prev. Repoint
* it at the last retained segment so validate_xmit_skb_list() does
* not chain onto a segment now owned by the crypto engine.
*/
if (skb)
skb->prev = pskb;
return skb ? skb : ERR_PTR(-EINPROGRESS);
}
EXPORT_SYMBOL_GPL(validate_xmit_xfrm);
@ -313,6 +321,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
}
xso->dev = dev;
xso->ifindex = dev->ifindex;
netdev_tracker_alloc(dev, &xso->dev_tracker, GFP_ATOMIC);
if (xuo->flags & XFRM_OFFLOAD_INBOUND)

View File

@ -480,6 +480,7 @@ static int iptfs_skb_add_frags(struct sk_buff *skb,
}
__skb_frag_ref(tofrag);
shinfo->nr_frags++;
shinfo->flags |= SKBFL_SHARED_FRAG;
/* see if we are done */
fraglen = tofrag->len;

View File

@ -55,8 +55,10 @@ static int nat_keepalive_send_ipv4(struct sk_buff *skb,
ka->encap_sport, sock_net_uid(net, NULL));
rt = ip_route_output_key(net, &fl4);
if (IS_ERR(rt))
if (IS_ERR(rt)) {
kfree_skb(skb);
return PTR_ERR(rt);
}
skb_dst_set(skb, &rt->dst);
@ -101,6 +103,7 @@ static int nat_keepalive_send_ipv6(struct sk_buff *skb,
dst = ip6_dst_lookup_flow(net, sk, &fl6, NULL);
if (IS_ERR(dst)) {
local_unlock_nested_bh(&nat_keepalive_sk_ipv6.bh_lock);
kfree_skb(skb);
return PTR_ERR(dst);
}
@ -118,7 +121,6 @@ static void nat_keepalive_send(struct nat_keepalive *ka)
sizeof(struct ipv6hdr)) +
sizeof(struct udphdr);
const u8 nat_ka_payload = 0xFF;
int err = -EAFNOSUPPORT;
struct sk_buff *skb;
struct udphdr *uh;
@ -140,16 +142,17 @@ static void nat_keepalive_send(struct nat_keepalive *ka)
switch (ka->family) {
case AF_INET:
err = nat_keepalive_send_ipv4(skb, ka);
nat_keepalive_send_ipv4(skb, ka);
break;
#if IS_ENABLED(CONFIG_IPV6)
case AF_INET6:
err = nat_keepalive_send_ipv6(skb, ka, uh);
nat_keepalive_send_ipv6(skb, ka, uh);
break;
#endif
}
if (err)
default:
kfree_skb(skb);
break;
}
}
struct nat_keepalive_work_ctx {

View File

@ -1329,8 +1329,8 @@ static void xfrm_hash_rebuild(struct work_struct *work)
}
}
if (policy->selector.prefixlen_d < dbits ||
policy->selector.prefixlen_s < sbits)
if (policy->selector.prefixlen_d >= dbits &&
policy->selector.prefixlen_s >= sbits)
continue;
bin = xfrm_policy_inexact_alloc_bin(policy, dir);

View File

@ -1547,6 +1547,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
xso->type = XFRM_DEV_OFFLOAD_PACKET;
xso->dir = xdo->dir;
xso->dev = dev;
xso->ifindex = dev->ifindex;
xso->flags = XFRM_DEV_OFFLOAD_FLAG_ACQ;
netdev_hold(dev, &xso->dev_tracker, GFP_ATOMIC);
error = dev->xfrmdev_ops->xdo_dev_state_add(dev, x,
@ -2071,8 +2072,11 @@ static struct xfrm_state *xfrm_state_clone_and_setup(struct xfrm_state *orig,
x->mode_cbs = orig->mode_cbs;
if (x->mode_cbs && x->mode_cbs->clone_state) {
if (x->mode_cbs->clone_state(x, orig))
if (x->mode_cbs->clone_state(x, orig)) {
if (!x->mode_data)
x->mode_cbs = NULL;
goto error;
}
}
x->props.reqid = m->new_reqid;
@ -3010,7 +3014,7 @@ int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
if (sockptr_is_null(optval) && !optlen) {
xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
__sk_dst_reset(sk);
sk_dst_reset(sk);
return 0;
}
@ -3050,7 +3054,7 @@ int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
if (err >= 0) {
xfrm_sk_policy_insert(sk, err, pol);
xfrm_pol_put(pol);
__sk_dst_reset(sk);
sk_dst_reset(sk);
err = 0;
}
@ -3291,6 +3295,8 @@ int __xfrm_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
if (x->mode_cbs->init_state)
err = x->mode_cbs->init_state(x);
module_put(x->mode_cbs->owner);
if (err && !x->mode_data)
x->mode_cbs = NULL;
}
error:
return err;

View File

@ -1201,17 +1201,26 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
return 0;
}
static void xso_to_xuo(const struct xfrm_dev_offload *xso,
struct xfrm_user_offload *xuo)
static void xso_to_xuo_ifindex(const struct xfrm_dev_offload *xso, int ifindex,
struct xfrm_user_offload *xuo)
{
xuo->ifindex = xso->dev->ifindex;
xuo->ifindex = ifindex;
if (xso->dir == XFRM_DEV_OFFLOAD_IN)
xuo->flags = XFRM_OFFLOAD_INBOUND;
if (xso->type == XFRM_DEV_OFFLOAD_PACKET)
xuo->flags |= XFRM_OFFLOAD_PACKET;
}
static int copy_user_offload(struct xfrm_dev_offload *xso, struct sk_buff *skb)
#ifdef CONFIG_XFRM_MIGRATE
static void xso_to_xuo(const struct xfrm_dev_offload *xso,
struct xfrm_user_offload *xuo)
{
xso_to_xuo_ifindex(xso, xso->dev->ifindex, xuo);
}
#endif
static int copy_user_offload_ifindex(const struct xfrm_dev_offload *xso,
int ifindex, struct sk_buff *skb)
{
struct xfrm_user_offload *xuo;
struct nlattr *attr;
@ -1222,11 +1231,22 @@ static int copy_user_offload(struct xfrm_dev_offload *xso, struct sk_buff *skb)
xuo = nla_data(attr);
memset(xuo, 0, sizeof(*xuo));
xso_to_xuo(xso, xuo);
xso_to_xuo_ifindex(xso, ifindex, xuo);
return 0;
}
static int copy_user_offload(struct xfrm_dev_offload *xso, struct sk_buff *skb)
{
return copy_user_offload_ifindex(xso, xso->dev->ifindex, skb);
}
static int copy_user_state_offload(const struct xfrm_dev_offload *xso,
struct sk_buff *skb)
{
return copy_user_offload_ifindex(xso, READ_ONCE(xso->ifindex), skb);
}
static bool xfrm_redact(void)
{
return IS_ENABLED(CONFIG_SECURITY) &&
@ -1433,8 +1453,8 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
&x->replay);
if (ret)
goto out;
if(x->xso.dev)
ret = copy_user_offload(&x->xso, skb);
if (READ_ONCE(x->xso.dev))
ret = copy_user_state_offload(&x->xso, skb);
if (ret)
goto out;
if (x->if_id) {
@ -2104,13 +2124,12 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,
switch (ut[i].mode) {
case XFRM_MODE_TUNNEL:
case XFRM_MODE_BEET:
case XFRM_MODE_IPTFS:
if (ut[i].optional && dir == XFRM_POLICY_OUT) {
NL_SET_ERR_MSG(extack, "Mode in optional template not allowed in outbound policy");
return -EINVAL;
}
break;
case XFRM_MODE_IPTFS:
break;
default:
if (ut[i].family != prev_family) {
NL_SET_ERR_MSG(extack, "Mode in template doesn't support a family change");
@ -4046,8 +4065,8 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x)
l += nla_total_size(sizeof(*x->coaddr));
if (x->props.extra_flags)
l += nla_total_size(sizeof(x->props.extra_flags));
if (x->xso.dev)
l += nla_total_size(sizeof(struct xfrm_user_offload));
if (READ_ONCE(x->xso.dev))
l += nla_total_size(sizeof(struct xfrm_user_offload));
if (x->props.smark.v | x->props.smark.m) {
l += nla_total_size(sizeof(x->props.smark.v));
l += nla_total_size(sizeof(x->props.smark.m));

View File

@ -44,7 +44,8 @@ function trigger_reactivation() {
# Restore MACs
ip netns exec "${NAMESPACE}" ip link set "${DSTIF}" \
address "${SAVED_DSTMAC}"
if [ "${BINDMODE}" == "mac" ]; then
if [ "${BINDMODE}" == "mac" ] &&
[ "$(mac_get "${SRCIF}")" != "${SAVED_SRCMAC}" ]; then
ip link set dev "${SRCIF}" down
ip link set dev "${SRCIF}" address "${SAVED_SRCMAC}"
# Rename device in order to trigger target resume, as initial

View File

@ -736,6 +736,61 @@ if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 "on bridge"; then
ret=1
fi
if ip -net "$nsr1" link show tun0 > /dev/null 2>&1 &&
ip -net "$nsr2" link show tun0 > /dev/null 2>&1; then
ip -net "$nsr1" route change default via 192.168.100.2
ip -net "$nsr2" route change default via 192.168.100.1
ip -6 -net "$nsr1" route delete default
ip -6 -net "$nsr1" route add default via fee1:3::2
ip -6 -net "$nsr2" route delete default
ip -6 -net "$nsr2" route add default via fee1:3::1
ip -net "$ns2" route add default via 10.0.2.1
ip -6 -net "$ns2" route add default via dead:2::1
ip netns exec "$nsr1" nft -a insert rule inet filter forward \
'meta oif "tun0" tcp dport 12345 ct mark set 1 flow add @f1 counter name routed_orig accept'
ip netns exec "$nsr1" nft -a insert rule inet filter forward \
'meta oif "tun6" tcp dport 12345 ct mark set 1 flow add @f1 counter name routed_orig accept'
ip netns exec "$nsr1" nft -a insert rule inet filter forward \
'meta oif "veth0" tcp sport 12345 ct mark set 1 flow add @f1 counter name routed_repl accept'
ip netns exec "$nsr1" nft -a insert rule inet filter forward \
'meta oif "br0" tcp sport 12345 ct mark set 1 flow add @f1 counter name routed_repl accept'
ip netns exec "$nsr1" nft -a insert rule inet filter forward \
'meta oif "tun0" accept'
ip netns exec "$nsr1" nft -a insert rule inet filter forward \
'meta oif "tun6" accept'
ip netns exec "$nsr1" nft reset counters table inet filter >/dev/null
if test_tcp_forwarding "$ns1" "$ns2" 1 4 10.0.2.99 12345; then
check_counters "bridge + IPIP tunnel"
else
echo "FAIL: flow offload for ns1/ns2 with bridge + IPIP tunnel" 1>&2
ip netns exec "$nsr1" nft list ruleset
ret=1
fi
if test_tcp_forwarding "$ns1" "$ns2" 1 6 "[dead:2::99]" 12345; then
check_counters "bridge + IP6IP6 tunnel"
else
echo "FAIL: flow offload for ns1/ns2 with bridge + IP6IP6 tunnel" 1>&2
ip netns exec "$nsr1" nft list ruleset
ret=1
fi
ip -net "$nsr1" route change default via 192.168.10.2
ip -net "$nsr2" route change default via 192.168.10.1
ip -net "$ns2" route del default via 10.0.2.1
ip -6 -net "$nsr1" route delete default
ip -6 -net "$nsr1" route add default via fee1:2::2
ip -6 -net "$nsr2" route delete default
ip -6 -net "$nsr2" route add default via fee1:2::1
ip -6 -net "$ns2" route del default via dead:2::1
else
echo "SKIP: bridge + tunnel flowtable regression (tun0 missing)"
[ "$ret" -eq 0 ] && ret=$ksft_skip
fi
# Another test:
# Add bridge interface br0 to Router1, with NAT and VLAN.