mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
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:
commit
e13caf1c26
4
.mailmap
4
.mailmap
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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, ¶ms->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;
|
||||
}
|
||||
|
||||
|
|
|
|||
654
net/can/bcm.c
654
net/can/bcm.c
File diff suppressed because it is too large
Load Diff
298
net/can/isotp.c
298
net/can/isotp.c
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ... */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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".
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user