Including fixes from Bluetooth, IPsec, WiFi and CAN.

Current release - regressions:
 
   - eth: wwan: mhi_wwan_ctrl: send a DTR drop before it can be coalesced
 
 Previous releases - regressions:
 
   - core:
     - use a dedicated flag to track disabled napi instances
     - frags: limit the truesize of a reassembly queue
     - reject a negative TCP header offset in qdisc_pkt_len_segs_init()y
 
   - tcp:
     - reject unhashed sockets during established lookups
     - free ireq->ipv6_opt after an RCU grace period
 
   - ipv6:
     - fix fib6 walker UAF on NLM_F_REPLACE
     - raw: fix use-after-free in rawv6_send_hdrinc()
 
   - wifi:
     - mac80211: reinstate IEEE80211_TX_CTL_AMPDU, fix ath9k stall
     - brcmfmac: map msgbuf RX packet IDs bidirectional, fix firmware
       crash loop
 
   - vsock: size receive SKBs from declared payload
 
   - xfrm: fix use-after-free of migrated state in xfrm_do_migrate_state()
 
   - bluetooth: hci_sync: copy the LE accept list under hdev->lock
 
   - ptp: fix use-after-free in extts_fifo_show() reading tsevqs unlocked
 
   - can: protect the receive lists with a per-device lock
 
   - eth: bnxt: don't keep MSI-X vectors added before FW reserves them
 
   - eth: vxlan: stop rejecting dynamic FDB entries with a nexthop ID
 
 Previous releases - always broken:
 
   - sched: sch_qfq: prevent aggregate self-replacement
 
   - bridge: disable MRP ports before the FDB flush in del_nbp()
 
   - mptcp: do not use fast open on MP_JOIN subflows
 
   - ipv6: serialize multicast router socket ownership
 
   - bluetooth: hci_core: keep link-key filtering inside RCU
 
   - eth: atl1c: drop oversized RX frames instead of panicking
 
   - eth: stmmac: a bunch of XDP path fixes
 
   - eth: b53: enable IGMP and MLD control packet CPU copies
 
 Signed-off-by: Paolo Abeni <pabeni@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEg1AjqC77wbdLX2LbKSR5jcyPE6QFAmrsoSgWHHBhb2xvLmFi
 ZW5pQGdtYWlsLmNvbQAKCRApJHmNzI8TpIKzEACKtniC4wXVre3NhuKc2L0DXVau
 RxlHkwWfSATOXFl382UPRtCMTd1NDzeUGyMEHc1EPYpH6T7svr83MUPnYth0vGZd
 pSKe23Rdpoeppadnj9ErHtOZpcF3/4BcVvAV3AbmW33yUzfOWrT1735UspzQbVvz
 eXrxL1kK/PRyt3uKk/H3gpow/CfRjvPQ8x+mL564Ee/p8c7wXk1r+e/QPSXPZodl
 MZs5oDcLJHjb96aHwU6PuXwtQqfUwaALxtLWk7Bldo7nqMTl4ZWEE0C8X93kOtDS
 zGgTu7ykLhJ+Mlsp4gjWgydUWCPxKKqqFnDg2CG6yOLSdlFwNct0m0o9kV6qjBdD
 JZBpnYVUW3RH4RMcWpMo3szL/EwPc9gNMRK9ug6I7fMfnsB5D9PBljFNy6JRW0K+
 OxQcCMzHW6OVulMzg3hWI7bfG1pgQ5Np8CcjbSaYwT6z/dhP7VWWghdHKa0/w+qR
 PmTaLaBHOIcOsOSKD01ZaCX9QpC+zOSJo+3C0Q7JU9G1nL9z+U8sJlOWjP7MlzU5
 FZd8IiFhgHGe+C6GUigfHnHG30CoRQkcN7Pd53vSe63jtkzavG9VNBj5LLuL61nr
 4avuUKwk2PK4/FgNYGgi7+QwVOJO/txEsJiJlB0f2CEhJKK2IuwDLrT/+wWR2H6G
 Ag9KW4jNwHwFXDyfZw==
 =1UcP
 -----END PGP SIGNATURE-----

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

Pull networking fixes from Paolo Abeni:
 "Including fixes from Bluetooth, IPsec, WiFi and CAN.

  Current release - regressions:

    - eth: wwan: mhi_wwan_ctrl: send a DTR drop before it can be coalesced

  Previous releases - regressions:

    - core:
       - use a dedicated flag to track disabled napi instances
       - frags: limit the truesize of a reassembly queue
       - reject a negative TCP header offset in qdisc_pkt_len_segs_init()y

    - tcp:
       - reject unhashed sockets during established lookups
       - free ireq->ipv6_opt after an RCU grace period

    - ipv6:
       - fix fib6 walker UAF on NLM_F_REPLACE
       - raw: fix use-after-free in rawv6_send_hdrinc()

    - wifi:
       - mac80211: reinstate IEEE80211_TX_CTL_AMPDU, fix ath9k stall
       - brcmfmac: map msgbuf RX packet IDs bidirectional, fix firmware
         crash loop

    - vsock: size receive SKBs from declared payload

    - xfrm: fix use-after-free of migrated state in xfrm_do_migrate_state()

    - bluetooth: hci_sync: copy the LE accept list under hdev->lock

    - ptp: fix use-after-free in extts_fifo_show() reading tsevqs unlocked

    - can: protect the receive lists with a per-device lock

    - eth:
       - bnxt: don't keep MSI-X vectors added before FW reserves them
       - vxlan: stop rejecting dynamic FDB entries with a nexthop ID

  Previous releases - always broken:

    - sched: sch_qfq: prevent aggregate self-replacement

    - bridge: disable MRP ports before the FDB flush in del_nbp()

    - mptcp: do not use fast open on MP_JOIN subflows

    - ipv6: serialize multicast router socket ownership

    - bluetooth: hci_core: keep link-key filtering inside RCU

    - eth:
       - atl1c: drop oversized RX frames instead of panicking
       - stmmac: a bunch of XDP path fixes
       - b53: enable IGMP and MLD control packet CPU copies"

* tag 'net-7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (170 commits)
  tcp: ipv6: free ireq->ipv6_opt after an RCU grace period
  mptcp: pm: kernel: use RCU to free endpoint listeners
  tcp: initialize send sequence numbers before deferring TFO
  net: bridge: disable MRP ports before the FDB flush in del_nbp()
  net: stmmac: set XDP metadata length on the page_pool RX path
  bonding: fix missing down path on speed/duplex failure after FAIL->UP
  ip6mr: Serialize multicast router socket ownership
  bonding: 3ad: don't set BOND_LINK_FAIL on a slave that is not up
  net: ethernet: ti: am65-cpsw-nuss: Enable timestamping of unicast PTP packets
  net: count last skb of each sk_backlog pass in __release_sock()
  net: 8139cp: keep Rx masked while NAPI is scheduled
  net/smc: don't spin in smc_rx_recvmsg() while a pipe holds spliced data
  net: dsa: b53: restore the NSP IMP port 2 Gbps mode
  net: ethernet: bgmac: preserve forced 2.5 Gbps link speed
  l2tp: only return sessions of the given tunnel in l2tp_session_get()
  tipc: raise the minimum bearer MTU to fit tunnel and crypto overhead
  mptcp: do not use Fast Open on MP_JOIN subflows
  tcp: ipv6: do not read ireq->pktopts from tcp_v6_send_synack()
  ipv4: Call rt_add_uncached_list() if !do_cache in ip_route_input_slow().
  ipv6: Flush rt->from in rt6_uncached_list_flush_dev().
  ...
This commit is contained in:
Linus Torvalds 2026-11-05 18:00:16 -08:00
commit f66469d990
153 changed files with 3262 additions and 1444 deletions

View File

@ -1040,17 +1040,21 @@ As described in :ref:`socketcan-receive-lists` the SocketCAN core uses several f
lists to deliver received CAN frames to CAN protocol modules. These
receive lists, their filters and the count of filter matches can be
checked in the appropriate receive list. All entries contain the
device and a protocol module identifier::
CAN network device, the filter (can_id/can_mask), the number of filter
matches, the inode number of the subscribing socket and the name of the
receive function. A sock_inode of 0 denotes a kernel internal subscriber
without a socket (e.g. CAN gateway or J1939). When the function name can
not be resolved (e.g. with CONFIG_KALLSYMS=n) "(unknown)" is printed::
foo@bar:~$ cat /proc/net/can/rcvlist_all
receive list 'rx_all':
(vcan3: no entry)
(vcan2: no entry)
(vcan1: no entry)
device can_id can_mask function userdata matches ident
vcan0 000 00000000 f88e6370 f6c6f400 0 raw
(any: no entry)
device can_id can_mask matches sock_inode function
vcan0 000 00000000 0 63586 raw_rcv [can_raw]
(vcan1: no entry)
(vcan2: no entry)
(vcan3: no entry)
In this example an application requests any CAN traffic from vcan0::

View File

@ -27,15 +27,20 @@ SA Identification
=================
The struct is defined in ``include/uapi/linux/xfrm.h``. The SA is looked
up using ``xfrm_state_lookup()`` with ``id.spi``,
``id.daddr``, ``id.proto``, ``id.family``, and
``old_mark.v & old_mark.m`` as the mark key::
up using ``xfrm_state_lookup_exact()`` with ``id.spi``, ``id.daddr``,
``id.proto``, ``id.family``, and an exact match against ``old_mark.v``
and ``old_mark.m``. Unlike the data path, which uses a masked
comparison, this requires the SA's mark and mask to equal ``old_mark``
exactly, so a broad-mask SA is never matched when a more specific one
was intended. If no such SA exists, ``-ESRCH`` is returned.
The layout is::
struct xfrm_user_migrate_state {
struct xfrm_usersa_id id; /* spi, daddr, proto, family */
xfrm_address_t new_daddr;
xfrm_address_t new_saddr;
struct xfrm_mark old_mark; /* SA lookup: key = v & m */
struct xfrm_mark old_mark; /* SA lookup key (exact v/m match) */
struct xfrm_selector new_sel; /* new selector (see Flags) */
__u32 new_reqid;
__u32 flags; /* XFRM_MIGRATE_STATE_* */
@ -72,8 +77,8 @@ inherits the value from the existing SA (omit-to-inherit).
- Description
* - ``XFRMA_MARK``
- Mark on the migrated SA (``struct xfrm_mark``). Absent inherits
``old_mark``. To use no mark on the new SA, send ``XFRMA_MARK``
with ``{0, 0}``.
the mark of the existing SA. To use no mark on the new SA, send
``XFRMA_MARK`` with ``{0, 0}``.
* - ``XFRMA_ENCAP``
- UDP encapsulation template; only ``UDP_ENCAP_ESPINUDP`` is supported.
Set ``encap_type=0`` to remove encap.
@ -259,8 +264,12 @@ Attributes in the notification
Error Handling
==============
If the target SA tuple (new daddr, SPI, proto, new family) is already
occupied, the operation returns ``-EEXIST`` before the migration begins.
If the target SA tuple (new daddr, SPI, proto, new family, mark) is
already occupied, the operation returns ``-EEXIST`` before the migration
begins. "Occupied" includes wildcard shadowing: an existing SA with a
broader mask (e.g. mark 0/0) claims every mark value, so it blocks
migrating to any more specific mark at the same tuple, not just an
exact mark/mask duplicate.
The old SA remains intact and the operation is safe to retry after
resolving the conflict.

View File

@ -315,6 +315,10 @@ reproducer and against kernel selftests. If the bug is in a hardware driver,
the testing statement must include information about the HW on which the
fix was tested.
Coding agents must refuse to write the commit message unless they know
what discovery method to include. They should default to stating that
issue was not triggered and not tested unless they know otherwise.
Stable tree
~~~~~~~~~~~

View File

@ -1201,7 +1201,29 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev,
err = -EINVAL;
while (fw_ptr - fw->data < fw->size) {
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
struct hci_command_hdr *cmd;
size_t remain = fw->size - (fw_ptr - fw->data);
/* Ensure the header fits before dereferencing */
if (frag_len + sizeof(*cmd) > remain) {
bt_dev_err(hdev,
"Firmware buffer overrun at header (frag_len %u, need %zu, remain %zu)",
frag_len, frag_len + sizeof(*cmd), remain);
err = -EINVAL;
goto done;
}
cmd = (void *)(fw_ptr + frag_len);
/* Ensure the full command (header + payload) fits before use */
if (frag_len + sizeof(*cmd) + cmd->plen > remain) {
bt_dev_err(hdev,
"Firmware buffer overrun at payload (frag_len %u, plen %u, need %zu, remain %zu)",
frag_len, cmd->plen,
frag_len + sizeof(*cmd) + cmd->plen, remain);
err = -EINVAL;
goto done;
}
frag_len += sizeof(*cmd) + cmd->plen;

View File

@ -7,6 +7,7 @@
#include <linux/usb.h>
#include <linux/iopoll.h>
#include <linux/overflow.h>
#include <linux/string.h>
#include <linux/unaligned.h>
#include <net/bluetooth/bluetooth.h>
@ -30,7 +31,7 @@
#define BTMTK_CBMCU_FLAG_ENABLE_PATCH 0xF1
/* It is for mt79xx iso data transmission setting */
#define MTK_ISO_THRESHOLD 264
#define MTK_ISO_THRESHOLD 342
struct btmtk_patch_header {
u8 datetime[16];
@ -1556,8 +1557,15 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
struct sk_buff *skb;
unsigned long flags;
unsigned int iso_mtu;
int err = 0;
/* The controller reports the largest Data_Total_Length it will send in
* LE Read Buffer Size [v2]. Fall back to HCI_MAX_ISO_SIZE while that
* command has not completed yet.
*/
iso_mtu = hdev->iso_mtu ? hdev->iso_mtu : HCI_MAX_ISO_SIZE;
spin_lock_irqsave(&btmtk_data->isorxlock, flags);
skb = btmtk_data->isopkt_skb;
@ -1565,7 +1573,16 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
int len;
if (!skb) {
skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC);
/* Drop the endpoint's zero-filled padding before
* allocating an skb for it; a zero Data_Total_Length
* check below would miss a padding remainder
* shorter than an ISO header.
*/
if (mem_is_zero(buffer, count))
break;
skb = bt_skb_alloc(HCI_ISO_HDR_SIZE + iso_mtu,
GFP_ATOMIC);
if (!skb) {
err = -ENOMEM;
break;
@ -1588,7 +1605,24 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
/* Complete ISO header */
hci_skb_expect(skb) = __le16_to_cpu(dlen);
if (skb_tailroom(skb) < hci_skb_expect(skb)) {
if (!hci_skb_expect(skb)) {
/* Zero padding was ruled out above, so a
* zero Data_Total_Length here is invalid.
*/
kfree_skb(skb);
skb = NULL;
err = -EILSEQ;
break;
}
/* Reject a length the controller said it would never
* send. The skb_tailroom() test is kept because a
* fragment started before hdev->iso_mtu was populated
* sits in a smaller skb than iso_mtu now allows.
*/
if (hci_skb_expect(skb) > iso_mtu ||
skb_tailroom(skb) < hci_skb_expect(skb)) {
kfree_skb(skb);
skb = NULL;
@ -1707,13 +1741,15 @@ static int btmtk_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
static int btmtk_usb_isointf_init(struct hci_dev *hdev)
{
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
u8 iso_param[2] = { 0x08, 0x01 };
__le16 iso_param = cpu_to_le16(MTK_ISO_THRESHOLD);
struct sk_buff *skb;
int err;
spin_lock_init(&btmtk_data->isorxlock);
__set_mtk_intr_interface(hdev);
err = __set_mtk_intr_interface(hdev);
if (err < 0)
return err;
err = btmtk_submit_intr_urb(hdev, GFP_KERNEL);
if (err < 0) {
@ -1722,9 +1758,10 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev)
return err;
}
skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), iso_param,
skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), &iso_param,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor);
bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb));
return PTR_ERR(skb);
}

View File

@ -426,7 +426,8 @@ static int qca_tlv_check_data(struct hci_dev *hdev,
tlv_nvm->data[0] |= 0x80;
/* UART Baud Rate */
if (soc_type >= QCA_WCN3991)
if (soc_type == QCA_WCN3950 ||
soc_type >= QCA_WCN3991)
tlv_nvm->data[1] = nvm_baud_rate;
else
tlv_nvm->data[2] = nvm_baud_rate;

View File

@ -2779,6 +2779,27 @@ static void bond_miimon_link_change(struct bonding *bond,
}
}
static bool bond_miimon_slave_down(struct bonding *bond,
struct slave *slave)
{
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
bond_set_slave_link_state(slave, BOND_LINK_DOWN,
BOND_SLAVE_NOTIFY_NOW);
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
BOND_MODE(bond) == BOND_MODE_8023AD)
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n");
bond_miimon_link_change(bond, slave, BOND_LINK_DOWN);
return slave == rcu_access_pointer(bond->curr_active_slave);
}
static void bond_miimon_commit(struct bonding *bond)
{
struct slave *slave, *primary, *active;
@ -2807,10 +2828,22 @@ static void bond_miimon_commit(struct bonding *bond)
err = bond_update_speed_duplex(slave);
netdev_unlock_ops(slave->dev);
if (err && bond_needs_speed_duplex(bond)) {
slave->link = BOND_LINK_DOWN;
if (net_ratelimit())
slave_warn(bond->dev, slave->dev,
"failed to get link speed/duplex\n");
/* Coming from FAIL/UP, the slave may still be
* in use and may be curr_active_slave, so take
* it through the full down path. Coming from
* DOWN/BACK, it was never brought up, so just
* revert it to DOWN.
*/
if (slave->link == BOND_LINK_FAIL ||
slave->link == BOND_LINK_UP) {
if (bond_miimon_slave_down(bond, slave))
do_failover = true;
continue;
}
slave->link = BOND_LINK_DOWN;
continue;
}
bond_set_slave_link_state(slave, BOND_LINK_UP,
@ -2839,28 +2872,13 @@ static void bond_miimon_commit(struct bonding *bond)
continue;
case BOND_LINK_DOWN:
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
bond_set_slave_link_state(slave, BOND_LINK_DOWN,
BOND_SLAVE_NOTIFY_NOW);
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
BOND_MODE(bond) == BOND_MODE_8023AD)
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n");
bond_miimon_link_change(bond, slave, BOND_LINK_DOWN);
if (slave == rcu_access_pointer(bond->curr_active_slave))
if (bond_miimon_slave_down(bond, slave))
do_failover = true;
continue;
case BOND_LINK_FAIL:
case BOND_LINK_BACK:
bond_commit_link_state(slave, BOND_SLAVE_NOTIFY_LATER);
slave_dbg(bond->dev, slave->dev, "link_new_state %d on slave\n",
slave->link_new_state);
continue;
@ -2894,8 +2912,6 @@ static void bond_mii_monitor(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
mii_work.work);
struct list_head *iter;
struct slave *slave;
unsigned long delay;
bool commit;
@ -2917,13 +2933,8 @@ static void bond_mii_monitor(struct work_struct *work)
goto re_arm;
}
if (commit) {
bond_for_each_slave(bond, slave, iter) {
bond_commit_link_state(slave,
BOND_SLAVE_NOTIFY_LATER);
}
if (commit)
bond_miimon_commit(bond);
}
if (bond->send_peer_notif)
bond_peer_notify_may_events(bond, true);
@ -3973,18 +3984,13 @@ static int bond_slave_netdev_event(unsigned long event,
case NETDEV_CHANGE:
/* For 802.3ad mode only:
* Getting invalid Speed/Duplex values here will put slave
* in weird state. Mark it as link-fail if the link was
* previously up or link-down if it hasn't yet come up, and
* let link-monitoring (miimon) set it right when correct
* speeds/duplex are available.
* in weird state. Mark an up slave as link-fail and let
* miimon set it right when correct speed/duplex are available.
*/
if (bond_update_speed_duplex(slave) &&
BOND_MODE(bond) == BOND_MODE_8023AD) {
if (slave->last_link_up)
slave->link = BOND_LINK_FAIL;
else
slave->link = BOND_LINK_DOWN;
}
BOND_MODE(bond) == BOND_MODE_8023AD &&
slave->link == BOND_LINK_UP)
slave->link = BOND_LINK_FAIL;
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_adapter_speed_duplex_changed(slave);

View File

@ -720,7 +720,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
return 0;
}
static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params,
static size_t can_tdc_get_size(const struct net_device *dev,
struct data_bittiming_params *dbt_params,
u32 tdc_flags)
{
bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK;
@ -742,7 +743,8 @@ static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params,
}
if (tdc_flags) {
if (tdc_manual || dbt_params->do_get_auto_tdcv)
if (tdc_manual ||
(dbt_params->do_get_auto_tdcv && netif_running(dev)))
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO */
if (dbt_params->tdc_const->tdcf_max)
@ -752,7 +754,8 @@ static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params,
return size;
}
static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_params,
static size_t can_data_bittiming_get_size(const struct net_device *dev,
struct data_bittiming_params *dbt_params,
u32 tdc_flags)
{
size_t size = 0;
@ -764,7 +767,7 @@ static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_para
if (dbt_params->data_bitrate_const) /* IFLA_CAN_{,XL}_DATA_BITRATE_CONST */
size += nla_total_size(sizeof(*dbt_params->data_bitrate_const) *
dbt_params->data_bitrate_const_cnt);
size += can_tdc_get_size(dbt_params, tdc_flags);/* IFLA_CAN_{,XL}_TDC */
size += can_tdc_get_size(dev, dbt_params, tdc_flags);/* IFLA_CAN_{,XL}_TDC */
return size;
}
@ -812,7 +815,7 @@ static size_t can_get_size(const struct net_device *dev)
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
if (priv->do_get_berr_counter && netif_running(dev)) /* IFLA_CAN_BERR_COUNTER */
size += nla_total_size(sizeof(struct can_berr_counter));
if (priv->termination_const) {
size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */
@ -825,10 +828,10 @@ static size_t can_get_size(const struct net_device *dev)
size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
size += can_ctrlmode_ext_get_size(); /* IFLA_CAN_CTRLMODE_EXT */
size += can_data_bittiming_get_size(&priv->fd,
size += can_data_bittiming_get_size(dev, &priv->fd,
priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK);
size += can_data_bittiming_get_size(&priv->xl,
size += can_data_bittiming_get_size(dev, &priv->xl,
priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK);
size += can_pwm_get_size(priv->xl.pwm_const, /* IFLA_CAN_XL_PWM */
priv->ctrlmode & CAN_CTRLMODE_XL_TMS);
@ -910,7 +913,7 @@ static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev,
if (tdc_manual) {
tdcv = tdc->tdcv;
err = 0;
} else if (dbt_params->do_get_auto_tdcv) {
} else if (dbt_params->do_get_auto_tdcv && netif_running(dev)) {
err = dbt_params->do_get_auto_tdcv(dev, &tdcv);
}
if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv))
@ -1006,7 +1009,7 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
(priv->do_get_berr_counter &&
(priv->do_get_berr_counter && netif_running(dev) &&
!priv->do_get_berr_counter(dev, &bec) &&
nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||

View File

@ -4,6 +4,7 @@
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
*/
#include <linux/can/can-ml.h>
#include <linux/can/dev.h>
#include <linux/module.h>
#include <net/can.h>
@ -54,6 +55,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
if (idx >= priv->echo_skb_max) {
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
__func__, idx, priv->echo_skb_max);
dev_kfree_skb_any(skb);
return -EINVAL;
}
@ -62,7 +64,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
(skb->protocol != htons(ETH_P_CAN) &&
skb->protocol != htons(ETH_P_CANFD) &&
skb->protocol != htons(ETH_P_CANXL))) {
kfree_skb(skb);
dev_kfree_skb_any(skb);
return 0;
}
@ -90,7 +92,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
} else {
/* locking problem with netif_stop_queue() ?? */
netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
kfree_skb(skb);
dev_kfree_skb_any(skb);
return -EBUSY;
}
@ -227,7 +229,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
csx = can_skb_ext_add(skb);
if (!csx) {
kfree_skb(skb);
dev_kfree_skb_any(skb);
goto out_error_cc;
}
@ -258,7 +260,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
csx = can_skb_ext_add(skb);
if (!csx) {
kfree_skb(skb);
dev_kfree_skb_any(skb);
goto out_error_fd;
}
@ -296,7 +298,7 @@ struct sk_buff *alloc_canxl_skb(struct net_device *dev,
csx = can_skb_ext_add(skb);
if (!csx) {
kfree_skb(skb);
dev_kfree_skb_any(skb);
goto out_error_xl;
}
@ -388,7 +390,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
break;
case ETH_P_CANXL:
if (!can_is_canxl_skb(skb))
if (!can_cap_enabled(dev, CAN_CAP_XL) || !can_is_canxl_skb(skb))
goto inval_skb;
break;
@ -402,7 +404,7 @@ bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
return false;
inval_skb:
kfree_skb(skb);
dev_kfree_skb_any(skb);
dev->stats.tx_dropped++;
return true;
}

View File

@ -755,7 +755,7 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
u16 rx_msg_type, rx_msg_size;
size_t rx_msg_min_size;
if (msg_end - msg_ptr < sizeof(*rx_msg)) {
if (msg_end - msg_ptr < sizeof(rx_msg->size)) {
err = -EBADMSG;
break;
}
@ -766,6 +766,11 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
break;
}
if (msg_end - msg_ptr < sizeof(*rx_msg)) {
err = -EBADMSG;
break;
}
rx_msg_size = le16_to_cpu(rx_msg->size);
rx_msg_type = le16_to_cpu(rx_msg->type);

View File

@ -836,6 +836,59 @@ void b53_brcm_hdr_setup(struct dsa_switch *ds, int port)
}
EXPORT_SYMBOL(b53_brcm_hdr_setup);
int b53_enable_mcast_snooping(struct b53_device *dev)
{
u16 val16;
u32 val;
int ret;
/* Older switches use different IGMP controls, not HL_PRTC_CTRL. */
if (is5325(dev) || is5365(dev) || dev->chip_id == BCM5389_DEVICE_ID ||
is5397_98(dev) || is63xx(dev))
return 0;
/* IGMPv2 and MLDv1 reports use the group's destination MAC. Once
* the first listener is offloaded, ordinary multicast forwarding
* can keep subsequent reports from reaching the bridge CPU.
*/
/* BCM5395 has a narrower register and a single IGMP classifier.
* Its ICMPv6 classifier also covers MLD.
*/
if (dev->chip_id == BCM5395_DEVICE_ID) {
ret = b53_read16(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL, &val16);
if (ret)
return ret;
val16 |= HL_PRTC_IGMP_IP_EN_5395 | HL_PRTC_ICMPV6_EN;
/* Zero forwarding modes copy control traffic to the CPU
* independently of the ARL lookup, retaining L2 forwarding.
*/
val16 &= ~(HL_PRTC_IGMP_FWD_MODE_5395 |
HL_PRTC_ICMPV6_FWD_MODE);
return b53_write16(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL,
val16);
}
ret = b53_read32(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL, &val);
if (ret)
return ret;
val |= HL_PRTC_IGMP_RPTLVE_EN | HL_PRTC_IGMP_QRY_EN |
HL_PRTC_IGMP_UKN_EN | HL_PRTC_MLD_RPTDONE_EN |
HL_PRTC_MLD_QRY_EN;
/* Zero forwarding modes copy control traffic to the CPU
* independently of the ARL lookup, retaining L2 forwarding.
*/
val &= ~(HL_PRTC_IGMP_RPTLVE_FWD_MODE | HL_PRTC_IGMP_QRY_FWD_MODE |
HL_PRTC_IGMP_UKN_FWD_MODE | HL_PRTC_MLD_RPTDONE_FWD_MODE |
HL_PRTC_MLD_QRY_FWD_MODE);
return b53_write32(dev, B53_MGMT_PAGE, B53_HL_PRTC_CTRL, val);
}
EXPORT_SYMBOL(b53_enable_mcast_snooping);
static void b53_enable_cpu_port(struct b53_device *dev, int port)
{
u8 port_ctrl;
@ -1334,6 +1387,10 @@ static int b53_setup(struct dsa_switch *ds)
b53_disable_port(ds, port);
}
ret = b53_enable_mcast_snooping(dev);
if (ret)
return ret;
return b53_setup_devlink_resources(ds);
}
@ -1663,9 +1720,15 @@ static void b53_phylink_mac_link_up(struct phylink_config *config,
}
if (mode == MLO_AN_FIXED) {
/* Force flow control on BCM5301x's CPU port */
if (is5301x(dev) && dsa_is_cpu_port(ds, port))
tx_pause = rx_pause = true;
/* Force flow control and 2Gbits/sec on BCM5301x and NSP CPU
* ports
*/
if ((is5301x(dev) || dev->chip_id == BCM58XX_DEVICE_ID) &&
dsa_is_cpu_port(ds, port)) {
tx_pause = true;
rx_pause = true;
speed = 2000;
}
b53_force_port_config(dev, port, speed, duplex,
tx_pause, rx_pause);

View File

@ -504,6 +504,7 @@ static inline struct gpio_desc *b53_switch_get_reset_gpio(struct b53_device *dev
/* Exported functions towards other drivers */
void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port);
int b53_configure_vlan(struct dsa_switch *ds);
int b53_enable_mcast_snooping(struct b53_device *dev);
void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
uint8_t *data);
void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);

View File

@ -274,6 +274,23 @@
/* Revision ID register (8 bit) */
#define B53_REV_ID 0x40
/* High-level protocol control (16 bit on BCM5395, otherwise 32 bit) */
#define B53_HL_PRTC_CTRL 0x50
#define HL_PRTC_ICMPV6_EN BIT(4)
#define HL_PRTC_ICMPV6_FWD_MODE BIT(5)
#define HL_PRTC_IGMP_IP_EN_5395 BIT(6)
#define HL_PRTC_IGMP_FWD_MODE_5395 BIT(8)
#define HL_PRTC_IGMP_RPTLVE_EN BIT(9)
#define HL_PRTC_IGMP_RPTLVE_FWD_MODE BIT(10)
#define HL_PRTC_IGMP_QRY_EN BIT(11)
#define HL_PRTC_IGMP_QRY_FWD_MODE BIT(12)
#define HL_PRTC_IGMP_UKN_EN BIT(13)
#define HL_PRTC_IGMP_UKN_FWD_MODE BIT(14)
#define HL_PRTC_MLD_RPTDONE_EN BIT(15)
#define HL_PRTC_MLD_RPTDONE_FWD_MODE BIT(16)
#define HL_PRTC_MLD_QRY_EN BIT(17)
#define HL_PRTC_MLD_QRY_FWD_MODE BIT(18)
/* Broadcom header RX control (16 bit) */
#define B53_BRCM_HDR_RX_DIS 0x60

View File

@ -1059,6 +1059,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
unsigned int port;
int ret;
/* Enable all valid ports and disable those unused */
for (port = 0; port < priv->hw_params.num_ports; port++) {
@ -1074,6 +1075,10 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
b53_configure_vlan(ds);
bcm_sf2_enable_acb(ds);
ret = b53_enable_mcast_snooping(priv->dev);
if (ret)
return ret;
return b53_setup_devlink_resources(ds);
}

View File

@ -1934,6 +1934,39 @@ static int atl1c_clean_rx(struct napi_struct *napi, int budget)
break;
}
atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
/* A link partner whose l2mtu is larger than ours can hand us a
* frame that does not fit the buffer the hardware was given:
* the descriptor reports the untruncated length while at most
* buffer_info->length bytes were written. skb_put() of such a
* length would pull in whatever the tail of the buffer holds
* and, past the end of the skb, trips skb_over_panic and takes
* the host down. Bound it by what the device actually wrote
* rather than by skb_tailroom(): the skb carries 64 bytes of
* slack for the DMA erratum, so the two are not the same.
*
* Frames shorter than an Ethernet header plus its FCS are
* rejected by the same test; before this, a length below
* ETH_FCS_LEN underflowed in skb_put().
*/
if (unlikely(length < ETH_HLEN + ETH_FCS_LEN ||
length > buffer_info->length)) {
dev_core_stats_rx_dropped_inc(netdev);
if (netif_msg_rx_err(adapter))
dev_warn_ratelimited(&pdev->dev,
"dropped rx frame: %u bytes, buffer %u\n",
length, buffer_info->length);
kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG);
/* atl1c_clean_rfd() has already recycled the RFD, so
* count the drop as work: the refill at the end of the
* poll only runs when work_done is non-zero, and
* sustained oversized traffic would otherwise drain the
* ring and stop RX for good.
*/
work_done++;
continue;
}
skb_put(skb, length - ETH_FCS_LEN);
skb->protocol = eth_type_trans(skb, netdev);
atl1c_rx_checksum(adapter, skb, rrs);

View File

@ -243,7 +243,8 @@ static int bgmac_probe(struct platform_device *pdev)
bgmac->phy_connect = platform_phy_connect;
} else {
bgmac->phy_connect = bgmac_phy_connect_direct;
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
if (of_machine_is_compatible("brcm,nsp"))
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
}
return bgmac_enet_probe(bgmac);

View File

@ -1430,11 +1430,15 @@ void bgmac_adjust_link(struct net_device *net_dev)
{
struct bgmac *bgmac = netdev_priv(net_dev);
struct phy_device *phy_dev = net_dev->phydev;
int speed = phy_dev->speed;
bool update = false;
if (bgmac->feature_flags & BGMAC_FEAT_FORCE_SPEED_2500)
speed = SPEED_2500;
if (phy_dev->link) {
if (phy_dev->speed != bgmac->mac_speed) {
bgmac->mac_speed = phy_dev->speed;
if (speed != bgmac->mac_speed) {
bgmac->mac_speed = speed;
update = true;
}

View File

@ -11544,6 +11544,7 @@ static int bnxt_change_msix(struct bnxt *bp, int total)
map.index = i - 1;
map.virq = bp->irq_tbl[i - 1].vector;
pci_msix_free_irq(bp->pdev, map);
bp->irq_tbl[i - 1].vector = 0;
bp->total_irqs--;
}
return bp->total_irqs;
@ -11721,8 +11722,23 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
int irqs_required;
int rc;
if (!bnxt_need_reserve_rings(bp))
if (!bnxt_need_reserve_rings(bp)) {
/* FW may already hold the reservation from an earlier
* reservation that was not followed by growing the dynamic
* MSI-X vectors, e.g. because the allocation failed.
*/
if (irq_re_init && BNXT_NEW_RM(bp) && bp->irq_tbl &&
pci_msix_can_alloc_dyn(bp->pdev)) {
irqs_required = bnxt_get_num_msix(bp);
if (irqs_required > bp->total_irqs &&
bnxt_change_msix(bp, irqs_required) != irqs_required) {
netdev_err(bp->dev, "Unable to allocate %d MSIX vectors, maximum available %d\n",
irqs_required, bp->total_irqs);
return -ENOSPC;
}
}
return 0;
}
if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) {
int ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
@ -11748,6 +11764,10 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
rc = bnxt_init_int_mode(bp);
bnxt_ulp_irq_restart(bp, rc);
} else if (irq_change && !rc) {
/* Size the vectors from what FW actually reserved, which
* can be less than what was requested.
*/
irqs_required = bnxt_get_num_msix(bp);
if (bnxt_change_msix(bp, irqs_required) != irqs_required)
rc = -ENOSPC;
}
@ -15113,6 +15133,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
hwr.cp = min_t(int, hwr.cp, bnxt_get_max_func_irqs(bp));
}
if (hwr.cp > bp->total_irqs) {
int old_total = bp->total_irqs;
int total_msix = bnxt_change_msix(bp, hwr.cp);
if (total_msix < hwr.cp) {
@ -15120,6 +15141,17 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
hwr.cp, total_msix);
rc = -ENOSPC;
}
/* FW has not reserved the new vectors yet, and writes to
* MSI-X table entries beyond the reserved IRQs don't
* stick (seen on BCM57508). Free them again;
* bnxt_reserve_rings() allocates them after
* __bnxt_reserve_rings(). Without the new resource
* manager there is no IRQ reservation and
* bnxt_reserve_rings() does not grow the vectors, so
* keep them.
*/
if (BNXT_NEW_RM(bp))
bnxt_change_msix(bp, old_total);
}
}
return rc;

View File

@ -1502,7 +1502,8 @@ jme_intr_msi(struct jme_adapter *jme, u32 intrstat)
* all other events are ignored
*/
jwrite32(jme, JME_IEVE, intrstat);
schedule_work(&jme->linkch_task);
if (!test_bit(JME_FLAG_WOL_QUIESCE, &jme->flags))
schedule_work(&jme->linkch_task);
goto out_reenable;
}
@ -1546,7 +1547,8 @@ jme_intr_msi(struct jme_adapter *jme, u32 intrstat)
/*
* Re-enable interrupt
*/
jwrite32f(jme, JME_IENS, INTR_ENABLE);
if (!test_bit(JME_FLAG_WOL_QUIESCE, &jme->flags))
jwrite32f(jme, JME_IENS, INTR_ENABLE);
}
static irqreturn_t
@ -1892,6 +1894,7 @@ jme_powersave_phy(struct jme_adapter *jme)
jme_set_100m_half(jme);
if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
jme_wait_link(jme);
jme_mac_rxclk_on(jme);
jme_clear_pm_enable_wol(jme);
} else {
jme_phy_off(jme);
@ -3158,6 +3161,21 @@ jme_shutdown(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct jme_adapter *jme = netdev_priv(netdev);
if (netif_running(netdev)) {
set_bit(JME_FLAG_WOL_QUIESCE, &jme->flags);
netif_device_detach(netdev);
netif_stop_queue(netdev);
jme_stop_irq(jme);
synchronize_irq(pdev->irq);
jme_stop_irq(jme);
cancel_work_sync(&jme->linkch_task);
tasklet_disable(&jme->pcc_task);
napi_disable(&jme->napi);
tasklet_disable(&jme->txclean_task);
tasklet_disable(&jme->rxclean_task);
tasklet_disable(&jme->rxempty_task);
}
jme_powersave_phy(jme);
pci_pme_active(pdev, true);
}
@ -3172,11 +3190,16 @@ jme_suspend(struct device *dev)
if (!netif_running(netdev))
return 0;
atomic_dec(&jme->link_changing);
set_bit(JME_FLAG_WOL_QUIESCE, &jme->flags);
netif_device_detach(netdev);
netif_stop_queue(netdev);
jme_stop_irq(jme);
synchronize_irq(jme->pdev->irq);
jme_stop_irq(jme);
cancel_work_sync(&jme->linkch_task);
tasklet_disable(&jme->pcc_task);
napi_disable(&jme->napi);
atomic_dec(&jme->link_changing);
tasklet_disable(&jme->txclean_task);
tasklet_disable(&jme->rxclean_task);
@ -3215,6 +3238,7 @@ jme_resume(struct device *dev)
return 0;
jme_clear_pm_disable_wol(jme);
jme_mac_rxclk_off(jme);
jme_phy_on(jme);
if (test_bit(JME_FLAG_SSET, &jme->flags))
jme_set_link_ksettings(netdev, &jme->old_cmd);
@ -3226,8 +3250,11 @@ jme_resume(struct device *dev)
atomic_inc(&jme->link_changing);
jme_reset_link(jme);
napi_enable(&jme->napi);
tasklet_enable(&jme->pcc_task);
clear_bit(JME_FLAG_WOL_QUIESCE, &jme->flags);
jme_reset_link(jme);
jme_start_irq(jme);
return 0;

View File

@ -450,6 +450,7 @@ enum jme_flags_bits {
JME_FLAG_SSET = 2,
JME_FLAG_POLL = 5,
JME_FLAG_SHUTDOWN = 6,
JME_FLAG_WOL_QUIESCE = 7,
};
#define TX_TIMEOUT (5 * HZ)

View File

@ -754,8 +754,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
hlist_for_each_entry_safe(entry, n, head, list) {
if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) {
if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) ==
MTK_FOE_STATE_BIND))
if (entry->hash != hash)
continue;
entry->hash = 0xffff;
@ -764,7 +763,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
}
if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) {
if (entry->hash != 0xffff)
if (entry->hash == hash)
entry->hash = 0xffff;
continue;
}

View File

@ -257,7 +257,7 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) {
if (dev->rx_wdma[i].desc)
if (!dev->rx_wdma[i].desc)
continue;
wdma_w32(dev,
@ -949,6 +949,14 @@ mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring)
static void
mtk_wed_free_rx_rings(struct mtk_wed_device *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++)
mtk_wed_free_ring(dev, &dev->rx_ring[i]);
for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
mtk_wed_free_ring(dev, &dev->tx_wdma[i]);
mtk_wed_free_rx_buffer(dev);
mtk_wed_free_ring(dev, &dev->rro.ring);
}
@ -1938,7 +1946,7 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0);
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
if (reset)
if (!mtk_wed_is_v3_or_greater(dev->hw) && reset)
mtk_wed_ring_reset(wdma, MTK_WED_WDMA_RING_SIZE, true);
if (!idx) {
@ -2337,7 +2345,20 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
if (!dev->rx_wdma[i].desc)
mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
if (mtk_wed_wdma_rx_ring_setup(dev, i, 16, false)) {
dev_err(dev->hw->dev, "wdma rx ring %d setup failed\n", i);
return;
}
/*
* non-DBDC MT7986 allocates only rx_ring[1] and tx_wdma[1] during setup
* but tx_wdma[0] is also needed for WED to function.
*/
if (mtk_wed_is_v2(dev->hw) && !dev->rx_ring[0].desc)
if (mtk_wed_wdma_tx_ring_setup(dev, 0, MTK_WED_WDMA_RING_SIZE, !!dev->tx_wdma[0].desc)) {
dev_err(dev->hw->dev, "wdma tx ring 0 setup failed\n");
return;
}
if (dev->wlan.hw_rro) {
for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) {

View File

@ -94,6 +94,7 @@ struct mlx5_fs_id {
refcount_t refcnt;
sci_t sci;
struct rhash_head hash;
struct rcu_head rcu;
};
struct mlx5_macsec_device {
@ -684,7 +685,7 @@ static void macsec_fs_id_del(struct list_head *macsec_devices_list, u32 fs_id,
xa_erase(fs_id_xa, fs_id);
kfree(fs_id_found);
kfree_rcu(fs_id_found, rcu);
if (macsec_fs_is_macsec_device_empty(macsec_device)) {
list_del(&macsec_device->macsec_devices_list_entry);

View File

@ -2072,7 +2072,7 @@ static int fbnic_alloc_rx_qt_resources(struct fbnic_net *fbn,
fbnic_bdq_set_page_size(&qt->sub1, rx_page_size);
err = xdp_rxq_info_reg(&qt->xdp_rxq, fbn->netdev, qt->sub0.q_idx,
err = xdp_rxq_info_reg(&qt->xdp_rxq, fbn->netdev, qt->cmpl.q_idx,
nv->napi.napi_id);
if (err)
goto free_page_pools;

View File

@ -353,6 +353,12 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight)
if (!fdma_db_is_done(db))
continue;
/* XDP and page pool APIs can't be used with a budget of 0.
* Leave these buffers for the next NAPI poll.
*/
if (!weight && !dcb_buf->use_skb)
continue;
dcb_buf->dev->stats.tx_packets++;
dcb_buf->dev->stats.tx_bytes += dcb_buf->len;

View File

@ -204,9 +204,10 @@ static void sparx5_ptp_classify(struct sparx5_port *port, struct sk_buff *skb,
*rew_op = IFH_REW_OP_TWO_STEP_PTP;
}
static void sparx5_ptp_txtstamp_old_release(struct sparx5_port *port)
static unsigned int sparx5_ptp_txtstamp_old_release(struct sparx5_port *port)
{
struct sk_buff *skb, *skb_tmp;
unsigned int purged = 0;
unsigned long flags;
spin_lock_irqsave(&port->tx_skbs.lock, flags);
@ -217,8 +218,11 @@ static void sparx5_ptp_txtstamp_old_release(struct sparx5_port *port)
__skb_unlink(skb, &port->tx_skbs);
dev_kfree_skb_any(skb);
purged++;
}
spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
return purged;
}
int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
@ -226,6 +230,7 @@ int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
{
struct sparx5 *sparx5 = port->sparx5;
u8 rew_op, pdu_type, pdu_w16_offset;
unsigned int purged;
unsigned long flags;
sparx5_ptp_classify(port, skb, &rew_op, &pdu_type, &pdu_w16_offset);
@ -236,9 +241,10 @@ int sparx5_ptp_txtstamp_request(struct sparx5_port *port,
if (rew_op != IFH_REW_OP_TWO_STEP_PTP)
return 0;
sparx5_ptp_txtstamp_old_release(port);
purged = sparx5_ptp_txtstamp_old_release(port);
spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags);
sparx5->ptp_skbs -= purged;
if (sparx5->ptp_skbs == SPARX5_MAX_PTP_ID) {
spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags);
return -EBUSY;

View File

@ -757,6 +757,27 @@ void mana_gd_free_service_wq(struct gdma_context *gc)
gc->service_wq = NULL;
}
static void mana_gd_schedule_eq_cqs(struct gdma_queue *eq)
{
struct gdma_context *gc = eq->gdma_dev->gdma_context;
struct gdma_queue *cq;
u8 i;
for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
cq = rcu_dereference(eq->eq.child_cq[i]);
if (!cq)
continue;
if (cq->id >= READ_ONCE(gc->max_num_cqs) ||
!gc->cq_table || gc->cq_table[cq->id] != cq)
continue;
if (cq->cq.callback)
cq->cq.callback(cq->cq.context, cq);
}
}
static void mana_gd_process_eqe(struct gdma_queue *eq)
{
u32 head = eq->head % (eq->queue_size / GDMA_EQE_SIZE);
@ -787,6 +808,14 @@ static void mana_gd_process_eqe(struct gdma_queue *eq)
break;
case GDMA_EQE_THROTTLE:
u64_stats_update_begin(&eq->eq.stats.syncp);
u64_stats_inc(&eq->eq.stats.throttle_count);
u64_stats_update_end(&eq->eq.stats.syncp);
mana_gd_schedule_eq_cqs(eq);
break;
case GDMA_EQE_TEST_EVENT:
gc->test_event_eq_id = eq->id;
complete(&gc->eq_test_event);
@ -1032,6 +1061,8 @@ static int mana_gd_create_eq(struct gdma_dev *gd,
queue->eq.msix_index = INVALID_PCI_MSIX_INDEX;
queue->id = INVALID_QUEUE_ID;
u64_stats_init(&queue->eq.stats.syncp);
log2_num_entries = ilog2(queue->queue_size / GDMA_EQE_SIZE);
if (spec->eq.log2_throttle_limit > log2_num_entries) {
@ -1073,25 +1104,66 @@ static void mana_gd_create_cq(const struct gdma_queue_spec *spec,
struct gdma_queue *queue)
{
u32 log2_num_entries = ilog2(spec->queue_size / GDMA_CQE_SIZE);
struct gdma_queue *parent;
u8 i;
queue->head |= INITIALIZED_OWNER_BIT(log2_num_entries);
queue->cq.parent = spec->cq.parent_eq;
parent = spec->cq.parent_eq;
queue->cq.parent = parent;
queue->cq.context = spec->cq.context;
queue->cq.callback = spec->cq.callback;
if (!parent)
return;
/* For throttled EQE store the child CQ */
for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
if (!rcu_access_pointer(parent->eq.child_cq[i])) {
rcu_assign_pointer(parent->eq.child_cq[i], queue);
return;
}
}
WARN_ONCE(1, "mana: EQ %u has no free child CQ slot\n", parent->id);
}
/* Unlink queue from its parent EQ's child_cq[] and from gc->cq_table[].
*
* Return: true if queue was in the parent EQ's child_cq[]. In that case the
* caller must wait for an RCU grace period before freeing queue, because
* mana_gd_intr() may still be handling a throttle EQE for it.
*/
bool mana_gd_detach_cq(struct gdma_context *gc, struct gdma_queue *queue)
{
struct gdma_queue *eq = queue->cq.parent;
bool attached = false;
u32 id = queue->id;
u8 i;
if (eq) {
for (i = 0; i < GDMA_EQ_MAX_CHILD_CQ; i++) {
if (rcu_access_pointer(eq->eq.child_cq[i]) == queue) {
RCU_INIT_POINTER(eq->eq.child_cq[i], NULL);
attached = true;
}
}
}
/* Check if CQ might have been detached already, only clear if
* it still points to same queue .
*/
if (id < gc->max_num_cqs && READ_ONCE(gc->cq_table[id]) == queue)
WRITE_ONCE(gc->cq_table[id], NULL);
return attached;
}
static void mana_gd_destroy_cq(struct gdma_context *gc,
struct gdma_queue *queue)
{
u32 id = queue->id;
if (id >= gc->max_num_cqs)
return;
if (!gc->cq_table[id])
return;
gc->cq_table[id] = NULL;
/* Wait for irq reader holding the cq */
if (mana_gd_detach_cq(gc, queue))
synchronize_net();
}
int mana_gd_create_hwc_queue(struct gdma_dev *gd,

View File

@ -364,7 +364,7 @@ static void mana_hwc_comp_event(void *ctx, struct gdma_queue *q_self)
completions = hwc_cq->comp_buf;
comp_read = mana_gd_poll_cq(q_self, completions, hwc_cq->queue_depth);
WARN_ON_ONCE(comp_read <= 0 || comp_read > hwc_cq->queue_depth);
WARN_ON_ONCE(comp_read < 0 || comp_read > hwc_cq->queue_depth);
for (i = 0; i < comp_read; ++i) {
comp_data = *(struct hwc_rx_oob *)completions[i].cqe_data;
@ -820,9 +820,14 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
*/
if (gc->max_num_cqs > 0) {
mana_smc_teardown_hwc(&gc->shm_channel, false);
gc->max_num_cqs = 0;
WRITE_ONCE(gc->max_num_cqs, 0);
}
if (hwc->cq)
mana_gd_detach_cq(gc, hwc->cq->gdma_cq);
synchronize_rcu();
if (hwc->txq)
mana_hwc_destroy_wq(hwc, hwc->txq);

View File

@ -2703,6 +2703,7 @@ static void mana_deinit_txq(struct mana_port_context *apc, struct mana_txq *txq)
static void mana_destroy_txq(struct mana_port_context *apc)
{
struct gdma_context *gc = apc->ac->gdma_dev->gdma_context;
struct napi_struct *napi;
int i;
@ -2721,8 +2722,6 @@ static void mana_destroy_txq(struct mana_port_context *apc)
napi_synchronize(napi);
napi_disable_locked(napi);
cancel_work_sync(&apc->tx_qp[i]->tx_cq.dim.work);
netif_napi_del_locked(napi);
apc->tx_qp[i]->txq.napi_initialized = false;
}
/* Forget the SKBs freed without being completed after a drain
@ -2735,6 +2734,18 @@ static void mana_destroy_txq(struct mana_port_context *apc)
if (apc->tx_qp[i]->tx_object != INVALID_MANA_HANDLE)
mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i]->tx_object);
if (apc->tx_qp[i]->txq.napi_initialized) {
/* Detach the CQ only after the WQ object is destroyed,
* so a completion EQE that arrives before then still
* finds the CQ in cq_table[] rather than hitting the
* WARN in mana_gd_process_eqe(). One grace period then
* covers both mana_gd_intr() and NAPI users.
*/
mana_gd_detach_cq(gc, apc->tx_qp[i]->tx_cq.gdma_cq);
netif_napi_del_locked(napi);
apc->tx_qp[i]->txq.napi_initialized = false;
}
mana_deinit_cq(apc, &apc->tx_qp[i]->tx_cq);
mana_deinit_txq(apc, &apc->tx_qp[i]->txq);
@ -2941,7 +2952,6 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
napi_disable_locked(napi);
cancel_work_sync(&rxq->rx_cq.dim.work);
netif_napi_del_locked(napi);
}
if (xdp_rxq_info_is_reg(&rxq->xdp_rxq))
@ -2950,6 +2960,12 @@ static void mana_destroy_rxq(struct mana_port_context *apc,
if (rxq->rxobj != INVALID_MANA_HANDLE)
mana_destroy_wq_obj(apc, GDMA_RQ, rxq->rxobj);
if (napi_initialized) {
/* See the comment in mana_destroy_txq() */
mana_gd_detach_cq(gc, rxq->rx_cq.gdma_cq);
netif_napi_del_locked(napi);
}
mana_deinit_cq(apc, &rxq->rx_cq);
if (rxq->xdp_save_va)

View File

@ -147,7 +147,8 @@ static int mana_get_sset_count(struct net_device *ndev, int stringset)
return ARRAY_SIZE(mana_eth_stats) +
ARRAY_SIZE(mana_phy_stats) +
ARRAY_SIZE(mana_hc_stats) +
num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT);
num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT +
MANA_STATS_EQ_COUNT);
case ETH_SS_PRIV_FLAGS:
return MANA_PRIV_FLAG_MAX;
@ -198,6 +199,9 @@ static void mana_get_strings_stats(struct mana_port_context *apc, u8 **data)
ethtool_sprintf(data, "tx_%d_csum_partial", i);
ethtool_sprintf(data, "tx_%d_mana_map_err", i);
}
for (i = 0; i < num_queues; i++)
ethtool_sprintf(data, "eq_%d_throttle_events", i);
}
static void mana_get_strings_priv_flags(u8 **data)
@ -234,6 +238,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
void *phy_stats = &apc->phy_stats;
struct mana_stats_rx *rx_stats;
struct mana_stats_tx *tx_stats;
struct gdma_eq_stats *eq_stats;
unsigned int start;
u64 packets, bytes;
u64 xdp_redirect;
@ -251,6 +256,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
u64 csum_partial;
u64 mana_map_err;
int q, i = 0, j;
u64 throttled;
if (!apc->port_is_up)
return;
@ -325,6 +331,17 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
data[i++] = csum_partial;
data[i++] = mana_map_err;
}
for (q = 0; q < num_queues; q++) {
eq_stats = &apc->eqs[q].eq->eq.stats;
do {
start = u64_stats_fetch_begin(&eq_stats->syncp);
throttled = u64_stats_read(&eq_stats->throttle_count);
} while (u64_stats_fetch_retry(&eq_stats->syncp, start));
data[i++] = throttled;
}
}
static u32 mana_get_rx_ring_count(struct net_device *ndev)

View File

@ -600,11 +600,11 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
goto out_unlock;
}
if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
if (napi_schedule_prep(&cp->napi)) {
cpw16_f(IntrMask, cp_norx_intr_mask);
if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) {
cpw16_f(IntrMask, cp_norx_intr_mask);
if (napi_schedule_prep(&cp->napi))
__napi_schedule(&cp->napi);
}
}
if (status & (TxOK | TxErr | TxEmpty | SWInt))
cp_tx(cp);

View File

@ -36,6 +36,7 @@
#include <linux/errno.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pps_kernel.h>
#include <linux/ptp_clock_kernel.h>
#include "net_driver.h"
@ -266,11 +267,12 @@ struct efx_ptp_rxfilter {
* @evt_frag_idx: Current fragment number
* @evt_code: Last event code
* @start: Address at which MC indicates ready for synchronisation
* @host_time_pps: Host time at last PPS
* @adjfreq_ppb_shift: Shift required to convert scaled parts-per-billion
* frequency adjustment into a fixed point fractional nanosecond format.
* @current_adjfreq: Current ppb adjustment.
* @phc_clock: Pointer to registered phc device (if primary function)
* @phc_lock: Serializes PHC commands and synchronization, and protects
* @current_adjfreq
* @phc_clock_info: Registration structure for phc device
* @pps_work: pps work task for handling pps events
* @pps_workwq: pps work queue
@ -326,10 +328,10 @@ struct efx_ptp_data {
int evt_frag_idx;
int evt_code;
struct efx_buffer start;
struct pps_event_time host_time_pps;
unsigned int adjfreq_ppb_shift;
s64 current_adjfreq;
struct ptp_clock *phc_clock;
struct mutex phc_lock;
struct ptp_clock_info phc_clock_info;
struct work_struct pps_work;
struct workqueue_struct *pps_workwq;
@ -907,7 +909,8 @@ static void efx_ptp_read_timeset(MCDI_DECLARE_STRUCT_PTR(data),
static int
efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
size_t response_length,
const struct pps_event_time *last_time)
const struct pps_event_time *last_time,
struct pps_event_time *host_time_pps)
{
unsigned number_readings =
MCDI_VAR_ARRAY_LEN(response_length,
@ -985,6 +988,10 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
"PTP bad synchronisation seconds\n");
return -EAGAIN;
}
if (!host_time_pps)
return 0;
delta.tv_sec = (last_sec - start_sec) & 1;
delta.tv_nsec =
last_time->ts_real.tv_nsec -
@ -1001,14 +1008,22 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
delta.tv_nsec += ktime_to_timespec64(mc_time).tv_nsec;
/* Set PPS timestamp to match NIC top of second */
ptp->host_time_pps = *last_time;
pps_sub_ts(&ptp->host_time_pps, delta);
*host_time_pps = *last_time;
pps_sub_ts(host_time_pps, delta);
return 0;
}
/* Synchronize times between the host and the MC */
static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
/* Synchronize times between the host and the MC.
*
* The MC serializes PTP requests, so MC_CMD_PTP_OP_ADJUST cannot be applied
* while MC_CMD_PTP_OP_SYNCHRONIZE is collecting timesets. This holds across
* functions of a controller, which share the clock but adjust it only through
* the function that registered it, so a secondary function can capture here
* without serializing against the primary.
*/
static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings,
struct pps_event_time *host_time_pps)
{
struct efx_ptp_data *ptp = efx->ptp_data;
MCDI_DECLARE_BUF(synch_buf, MC_CMD_PTP_OUT_SYNCHRONIZE_LENMAX);
@ -1026,11 +1041,14 @@ static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
MCDI_SET_QWORD(synch_buf, PTP_IN_SYNCHRONIZE_START_ADDR,
ptp->start.dma_addr);
mutex_lock(&ptp->phc_lock);
/* Clear flag that signals MC ready */
WRITE_ONCE(*start, 0);
rc = efx_mcdi_rpc_start(efx, MC_CMD_PTP, synch_buf,
MC_CMD_PTP_IN_SYNCHRONIZE_LEN);
EFX_WARN_ON_ONCE_PARANOID(rc);
if (rc)
goto out;
/* Wait for start from MCDI (or timeout) */
timeout = jiffies + msecs_to_jiffies(MAX_SYNCHRONISE_WAIT_MS);
@ -1054,18 +1072,20 @@ static int efx_ptp_synchronize(struct efx_nic *efx, unsigned int num_readings)
&response_length);
if (rc == 0) {
rc = efx_ptp_process_times(efx, synch_buf, response_length,
&last_time);
&last_time, host_time_pps);
if (rc == 0)
++ptp->good_syncs;
else
++ptp->no_time_syncs;
}
out:
/* Increment the bad syncs counter if the synchronize fails, whatever
* the reason.
*/
if (rc != 0)
++ptp->bad_syncs;
mutex_unlock(&ptp->phc_lock);
return rc;
}
@ -1445,7 +1465,6 @@ static int efx_ptp_start(struct efx_nic *efx)
goto fail;
ptp->evt_frag_idx = 0;
ptp->current_adjfreq = 0;
return 0;
@ -1485,14 +1504,15 @@ static void efx_ptp_pps_worker(struct work_struct *work)
{
struct efx_ptp_data *ptp =
container_of(work, struct efx_ptp_data, pps_work);
struct pps_event_time host_time_pps = {};
struct efx_nic *efx = ptp->efx;
struct ptp_clock_event ptp_evt;
if (efx_ptp_synchronize(efx, PTP_SYNC_ATTEMPTS))
if (efx_ptp_synchronize(efx, PTP_SYNC_ATTEMPTS, &host_time_pps))
return;
ptp_evt.type = PTP_CLOCK_PPSUSR;
ptp_evt.pps_times = ptp->host_time_pps;
ptp_evt.pps_times = host_time_pps;
ptp_clock_event(ptp->phc_clock, &ptp_evt);
}
@ -1569,6 +1589,7 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
if (!efx->ptp_data)
return -ENOMEM;
mutex_init(&ptp->phc_lock);
ptp->efx = efx;
ptp->channel = channel;
@ -1640,6 +1661,7 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
efx_nic_free_buffer(efx, &ptp->start);
fail1:
mutex_destroy(&ptp->phc_lock);
kfree(efx->ptp_data);
efx->ptp_data = NULL;
@ -1694,6 +1716,7 @@ void efx_ptp_remove(struct efx_nic *efx)
destroy_workqueue(efx->ptp_data->workwq);
efx_nic_free_buffer(efx, &efx->ptp_data->start);
mutex_destroy(&efx->ptp_data->phc_lock);
kfree(efx->ptp_data);
efx->ptp_data = NULL;
}
@ -1825,7 +1848,8 @@ int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
rc = efx_ptp_start(efx);
if (rc == 0) {
rc = efx_ptp_synchronize(efx,
PTP_SYNC_ATTEMPTS * 2);
PTP_SYNC_ATTEMPTS * 2,
NULL);
if (rc != 0)
efx_ptp_stop(efx);
}
@ -2105,23 +2129,23 @@ static int efx_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
MCDI_SET_QWORD(inadj, PTP_IN_ADJUST_FREQ, adjustment_ns);
MCDI_SET_DWORD(inadj, PTP_IN_ADJUST_SECONDS, 0);
MCDI_SET_DWORD(inadj, PTP_IN_ADJUST_NANOSECONDS, 0);
mutex_lock(&ptp_data->phc_lock);
rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inadj, sizeof(inadj),
NULL, 0, NULL);
if (rc != 0)
return rc;
ptp_data->current_adjfreq = adjustment_ns;
return 0;
if (!rc)
ptp_data->current_adjfreq = adjustment_ns;
mutex_unlock(&ptp_data->phc_lock);
return rc;
}
static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
static int _efx_phc_adjtime(struct efx_ptp_data *ptp_data, s64 delta)
__must_hold(&ptp_data->phc_lock)
{
u32 nic_major, nic_minor;
struct efx_ptp_data *ptp_data = container_of(ptp,
struct efx_ptp_data,
phc_clock_info);
struct efx_nic *efx = ptp_data->efx;
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_ADJUST_LEN);
struct efx_nic *efx = ptp_data->efx;
u32 nic_major, nic_minor;
lockdep_assert_held(&ptp_data->phc_lock);
efx->ptp_data->ns_to_nic_time(delta, &nic_major, &nic_minor);
@ -2134,6 +2158,18 @@ static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
NULL, 0, NULL);
}
static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct efx_ptp_data *ptp_data = container_of(ptp, struct efx_ptp_data,
phc_clock_info);
int rc;
mutex_lock(&ptp_data->phc_lock);
rc = _efx_phc_adjtime(ptp_data, delta);
mutex_unlock(&ptp_data->phc_lock);
return rc;
}
static int efx_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
{
struct efx_ptp_data *ptp_data = container_of(ptp,
@ -2165,23 +2201,21 @@ static int efx_phc_settime(struct ptp_clock_info *ptp,
{
/* Get the current NIC time, efx_phc_gettime.
* Subtract from the desired time to get the offset
* call efx_phc_adjtime with the offset
* call _efx_phc_adjtime with the offset
*/
struct efx_ptp_data *ptp_data = container_of(ptp, struct efx_ptp_data,
phc_clock_info);
struct timespec64 time_now, delta;
int rc;
struct timespec64 time_now;
struct timespec64 delta;
mutex_lock(&ptp_data->phc_lock);
rc = efx_phc_gettime(ptp, &time_now);
if (rc != 0)
return rc;
delta = timespec64_sub(*e_ts, time_now);
rc = efx_phc_adjtime(ptp, timespec64_to_ns(&delta));
if (rc != 0)
return rc;
return 0;
if (!rc) {
delta = timespec64_sub(*e_ts, time_now);
rc = _efx_phc_adjtime(ptp_data, timespec64_to_ns(&delta));
}
mutex_unlock(&ptp_data->phc_lock);
return rc;
}
static int efx_phc_enable(struct ptp_clock_info *ptp,

View File

@ -205,7 +205,7 @@ static int enh_desc_get_rx_status(struct stmmac_extra_stats *x,
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
x->rx_length++;
return discard_frame;
return discard_frame | rx_not_ls;
}
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {

View File

@ -620,7 +620,7 @@ struct stmmac_mmc_ops {
struct stmmac_est_ops {
int (*configure)(struct stmmac_priv *priv, struct stmmac_est *cfg,
unsigned int ptp_rate);
unsigned int ptp_rate, bool enable);
void (*irq_status)(struct stmmac_priv *priv, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt);
};

View File

@ -70,7 +70,7 @@ static int ndesc_get_rx_status(struct stmmac_extra_stats *x,
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
x->rx_length++;
return discard_frame;
return discard_frame | rx_not_ls;
}
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {

View File

@ -239,6 +239,7 @@ struct stmmac_est {
u32 gcl[EST_GCL];
u32 gcl_size;
u32 max_sdu[MTL_MAX_TX_QUEUES];
u32 pclass;
};
struct stmmac_msi {

View File

@ -26,7 +26,7 @@ static int est_write(void __iomem *est_addr, u32 reg, u32 val, bool gcl)
}
static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
unsigned int ptp_rate)
unsigned int ptp_rate, bool enable)
{
void __iomem *est_addr = priv->estaddr;
int i, ret = 0;
@ -62,7 +62,7 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_GMAC5_PTOV_MUL) <<
EST_GMAC5_PTOV_SHIFT;
}
if (cfg->enable)
if (enable)
ctrl |= EST_EEST | EST_SSWL | EST_DFBS;
else
ctrl &= ~EST_EEST;
@ -70,7 +70,7 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
writel(ctrl, est_addr + EST_CONTROL);
/* Configure EST interrupt */
if (cfg->enable)
if (enable)
ctrl = EST_IECGCE | EST_IEHS | EST_IEHF | EST_IEBE | EST_IECC;
else
ctrl = 0;
@ -80,6 +80,61 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
return 0;
}
int __stmmac_setup_est(struct stmmac_priv *priv)
{
struct timespec64 current_time, time;
ktime_t current_time_ns, basetime;
u64 cycle_time;
int err;
lockdep_assert_held(&priv->est_lock);
priv->ptp_clock_ops.gettimex64(&priv->ptp_clock_ops, &current_time,
NULL);
current_time_ns = timespec64_to_ktime(current_time);
time.tv_nsec = priv->est->btr_reserve[0];
time.tv_sec = priv->est->btr_reserve[1];
basetime = timespec64_to_ktime(time);
cycle_time = (u64)priv->est->ctr[1] * NSEC_PER_SEC + priv->est->ctr[0];
time = stmmac_calc_tas_basetime(basetime, current_time_ns, cycle_time);
priv->est->btr[0] = (u32)time.tv_nsec;
priv->est->btr[1] = (u32)time.tv_sec;
err = stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate, true);
if (err) {
netdev_err(priv->dev, "failed to re-configure EST\n");
return err;
}
return 0;
}
int stmmac_setup_est(struct stmmac_priv *priv)
{
int ret = 0;
if (!priv->ptp_enabled)
return 0;
mutex_lock(&priv->est_lock);
if (priv->est && priv->est->enable) {
ret = __stmmac_setup_est(priv);
if (ret)
goto unlock;
ret = stmmac_fpe_map_preemption_class(priv, priv->dev, NULL,
priv->est->pclass);
}
unlock:
mutex_unlock(&priv->est_lock);
return ret;
}
static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev,
struct stmmac_extra_stats *x, u32 txqcnt)
{

View File

@ -4,6 +4,9 @@
* stmmac EST(802.3 Qbv) handling
*/
#ifndef __STMMAC_EST_H__
#define __STMMAC_EST_H__
#define EST_GMAC4_OFFSET 0x00000c50
#define EST_XGMAC_OFFSET 0x00001050
@ -65,3 +68,8 @@
#define EST_GCL_DATA 0x00000034
extern const struct stmmac_est_ops dwmac510_est_ops;
int __stmmac_setup_est(struct stmmac_priv *priv);
int stmmac_setup_est(struct stmmac_priv *priv);
#endif /* __STMMAC_EST_H__ */

View File

@ -48,6 +48,7 @@
#include "stmmac_ptp.h"
#include "stmmac_fpe.h"
#include "stmmac.h"
#include "stmmac_est.h"
#include "stmmac_pcs.h"
#include "stmmac_xdp.h"
#include <linux/reset.h>
@ -2182,6 +2183,9 @@ static void __free_dma_rx_desc_resources(struct stmmac_priv *priv,
else
dma_free_rx_skbufs(priv, dma_conf, queue);
dev_kfree_skb_any(rx_q->state.skb);
rx_q->state.skb = NULL;
rx_q->state_saved = false;
rx_q->buf_alloc_num = 0;
rx_q->xsk_pool = NULL;
@ -4201,6 +4205,10 @@ static int __stmmac_open(struct net_device *dev,
if (ret)
goto ptp_error;
ret = stmmac_setup_est(priv);
if (ret)
goto est_error;
stmmac_init_coalesce(priv);
phylink_start(priv->phylink);
@ -4224,7 +4232,7 @@ static int __stmmac_open(struct net_device *dev,
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++)
hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer);
est_error:
stmmac_release_ptp(priv);
ptp_error:
stmmac_stop_all_dma(priv);
@ -5099,22 +5107,35 @@ static netdev_features_t stmmac_features_check(struct sk_buff *skb,
return vlan_features_check(skb, features);
}
static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
static int stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
{
struct vlan_ethhdr *veth = skb_vlan_eth_hdr(skb);
__be16 vlan_proto = veth->h_vlan_proto;
u16 vlanid;
struct vlan_ethhdr *veth;
if ((vlan_proto == htons(ETH_P_8021Q) &&
if (!pskb_may_pull(skb, ETH_HLEN))
return -EINVAL;
veth = skb_vlan_eth_hdr(skb);
if ((veth->h_vlan_proto == htons(ETH_P_8021Q) &&
dev->features & NETIF_F_HW_VLAN_CTAG_RX) ||
(vlan_proto == htons(ETH_P_8021AD) &&
(veth->h_vlan_proto == htons(ETH_P_8021AD) &&
dev->features & NETIF_F_HW_VLAN_STAG_RX)) {
__be16 vlan_proto = veth->h_vlan_proto;
u8 meta_len = skb_metadata_len(skb);
u16 vlanid;
/* pop the vlan tag */
if (!pskb_may_pull(skb, VLAN_ETH_HLEN))
return -EINVAL;
veth = skb_vlan_eth_hdr(skb);
vlanid = ntohs(veth->h_vlan_TCI);
memmove(skb->data + VLAN_HLEN, veth, ETH_ALEN * 2);
memmove(skb->data - meta_len + VLAN_HLEN,
skb->data - meta_len, meta_len + ETH_ALEN * 2);
skb_pull(skb, VLAN_HLEN);
__vlan_hwaccel_put_tag(skb, vlan_proto, vlanid);
}
return 0;
}
static bool stmmac_rx_need_ic(struct stmmac_priv *priv,
@ -5516,7 +5537,8 @@ static struct sk_buff *stmmac_construct_skb_zc(struct stmmac_channel *ch,
return NULL;
skb_reserve(skb, xdp->data - xdp->data_hard_start);
memcpy(__skb_put(skb, datasize), xdp->data, datasize);
__skb_put(skb, datasize);
memcpy(skb->data - metasize, xdp->data_meta, datasize + metasize);
if (metasize)
skb_metadata_set(skb, metasize);
@ -5542,12 +5564,15 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
}
stmmac_get_rx_hwtstamp(priv, p, np, skb);
if (priv->hw->hw_vlan_en)
if (priv->hw->hw_vlan_en) {
/* MAC level stripping. */
stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
else
/* Driver level stripping. */
stmmac_rx_vlan(priv->dev, skb);
} else if (stmmac_rx_vlan(priv->dev, skb)) {
dev_kfree_skb_any(skb);
priv->xstats.rx_dropped++;
return;
}
skb->protocol = eth_type_trans(skb, priv->dev);
if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb))
@ -5629,12 +5654,12 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
unsigned int count = 0, error = 0, len = 0;
int dirty = stmmac_rx_dirty(priv, queue);
unsigned int next_entry = rx_q->cur_rx;
bool in_progress = rx_q->state_saved;
u32 rx_errors = 0, rx_dropped = 0;
unsigned int desc_size;
struct bpf_prog *prog;
bool failure = false;
int xdp_status = 0;
int status = 0;
if (netif_msg_rx_status(priv)) {
void *rx_head = stmmac_get_rx_desc(priv, rx_q, 0);
@ -5645,23 +5670,25 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_display_ring(priv, rx_head, priv->dma_conf.dma_rx_size, true,
rx_q->dma_rx_phy, desc_size);
}
if (rx_q->state_saved) {
error = rx_q->state.error;
len = rx_q->state.len;
rx_q->state_saved = false;
}
while (count < limit) {
struct stmmac_rx_buffer *buf;
struct stmmac_xdp_buff *ctx;
unsigned int buf1_len = 0;
struct dma_desc *np, *p;
int entry;
int entry, status;
int res;
if (!count && rx_q->state_saved) {
error = rx_q->state.error;
len = rx_q->state.len;
} else {
rx_q->state_saved = false;
if (!in_progress) {
error = 0;
len = 0;
}
read_again:
if (count >= limit)
break;
@ -5700,6 +5727,8 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
if (!buf->xdp)
break;
in_progress = status & rx_not_ls;
if (priv->extend_desc) {
/* Read the extended status after the own bit */
dma_rmb();
@ -5707,18 +5736,21 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
&rx_q->dma_erx[entry],
status);
}
if (unlikely(status == discard_frame)) {
xsk_buff_free(buf->xdp);
buf->xdp = NULL;
dirty++;
if (unlikely(!error && (status & discard_frame))) {
error = 1;
if (!priv->hwts_rx_en)
rx_errors++;
}
if (unlikely(error && (status & rx_not_ls)))
goto read_again;
if (unlikely(error)) {
xsk_buff_free(buf->xdp);
buf->xdp = NULL;
dirty++;
if (status & rx_not_ls)
goto read_again;
count++;
continue;
}
@ -5727,8 +5759,9 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
if (likely(status & rx_not_ls)) {
xsk_buff_free(buf->xdp);
buf->xdp = NULL;
rx_dropped++;
error = 1;
dirty++;
count++;
goto read_again;
}
@ -5776,7 +5809,7 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
count++;
}
if (status & rx_not_ls) {
if (in_progress) {
rx_q->state_saved = true;
rx_q->state.error = error;
rx_q->state.len = len;
@ -5818,9 +5851,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
struct stmmac_channel *ch = &priv->channel[queue];
unsigned int count = 0, error = 0, len = 0;
int status = 0, coe = priv->hw->rx_csum;
unsigned int next_entry = rx_q->cur_rx;
bool in_progress = rx_q->state_saved;
enum dma_data_direction dma_dir;
int coe = priv->hw->rx_csum;
unsigned int desc_size;
struct sk_buff *skb = NULL;
struct stmmac_xdp_buff ctx;
@ -5840,25 +5874,28 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
stmmac_display_ring(priv, rx_head, priv->dma_conf.dma_rx_size, true,
rx_q->dma_rx_phy, desc_size);
}
if (rx_q->state_saved) {
skb = rx_q->state.skb;
error = rx_q->state.error;
len = rx_q->state.len;
rx_q->state.skb = NULL;
rx_q->state_saved = false;
}
while (count < limit) {
unsigned int buf1_len = 0, buf2_len = 0;
enum pkt_hash_types hash_type;
struct stmmac_rx_buffer *buf;
struct dma_desc *np, *p;
int entry;
int entry, status;
u32 hash;
if (!count && rx_q->state_saved) {
skb = rx_q->state.skb;
error = rx_q->state.error;
len = rx_q->state.len;
} else {
rx_q->state_saved = false;
if (!in_progress) {
skb = NULL;
error = 0;
len = 0;
}
read_again:
if (count >= limit)
break;
@ -5887,6 +5924,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
prefetch(np);
in_progress = status & rx_not_ls;
if (priv->extend_desc) {
/* Read the extended status after the own bit */
dma_rmb();
@ -5894,21 +5933,26 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
&rx_q->dma_erx[entry],
status);
}
if (unlikely(status == discard_frame)) {
page_pool_put_page(rx_q->page_pool, buf->page, 0, true);
buf->page = NULL;
if (unlikely(!error && (status & discard_frame))) {
error = 1;
if (!priv->hwts_rx_en)
rx_errors++;
}
if (unlikely(error && (status & rx_not_ls)))
goto read_again;
/* We do not support SG in XDP mode */
if (unlikely(!error && (status & rx_not_ls) &&
stmmac_xdp_is_enabled(priv))) {
rx_dropped++;
error = 1;
}
if (unlikely(error)) {
if (status & rx_not_ls)
goto read_again;
dev_kfree_skb(skb);
skb = NULL;
count++;
continue;
goto next;
}
/* Buffer is good. Go on. */
@ -5918,13 +5962,19 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
buf2_len = stmmac_rx_buf2_len(priv, p, status, len);
len += buf2_len;
/* Drop the packet if it is split over buf1 and buf2 on a
* single descriptor if the interface is running in XDP mode.
*/
if (unlikely(stmmac_xdp_is_enabled(priv) && buf2_len)) {
rx_dropped++;
goto next;
}
/* ACS is disabled; strip manually. */
if (likely(!(status & rx_not_ls)))
len -= ETH_FCS_LEN;
if (!skb) {
unsigned int pre_len, sync_len;
/* Each frame starts here: reset the FCS handling */
fcs_stripped = false;
@ -5942,55 +5992,32 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
xdp_prepare_buff(&ctx.xdp, page_address(buf->page),
buf->page_offset, buf1_len, true);
pre_len = ctx.xdp.data_end - ctx.xdp.data_hard_start -
buf->page_offset;
ctx.priv = priv;
ctx.desc = p;
ctx.ndesc = np;
skb = stmmac_xdp_run_prog(priv, &ctx.xdp);
/* Due xdp_adjust_tail: DMA sync for_device
* cover max len CPU touch
*/
sync_len = ctx.xdp.data_end - ctx.xdp.data_hard_start -
buf->page_offset;
sync_len = max(sync_len, pre_len);
/* For Not XDP_PASS verdict */
if (IS_ERR(skb)) {
unsigned int xdp_res = -PTR_ERR(skb);
if (xdp_res & STMMAC_XDP_CONSUMED) {
page_pool_put_page(rx_q->page_pool,
virt_to_head_page(ctx.xdp.data),
sync_len, true);
page_pool_recycle_direct(rx_q->page_pool,
virt_to_head_page(ctx.xdp.data));
buf->page = NULL;
rx_dropped++;
/* Clear skb as it was set as
* status by XDP program.
*/
skb = NULL;
if (unlikely((status & rx_not_ls)))
goto read_again;
count++;
continue;
goto next;
} else if (xdp_res & (STMMAC_XDP_TX |
STMMAC_XDP_REDIRECT)) {
xdp_status |= xdp_res;
buf->page = NULL;
skb = NULL;
count++;
continue;
goto next;
}
}
}
if (!skb) {
unsigned int head_pad_len;
unsigned int metasize;
/* XDP program may expand or reduce tail */
buf1_len = ctx.xdp.data_end - ctx.xdp.data;
@ -6007,10 +6034,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
}
/* XDP program may adjust header */
head_pad_len = ctx.xdp.data - ctx.xdp.data_hard_start;
skb_reserve(skb, head_pad_len);
skb_reserve(skb,
ctx.xdp.data - ctx.xdp.data_hard_start);
skb_put(skb, buf1_len);
skb_mark_for_recycle(skb);
metasize = ctx.xdp.data - ctx.xdp.data_meta;
if (metasize)
skb_metadata_set(skb, metasize);
buf->page = NULL;
} else if (buf1_len) {
dma_sync_single_for_cpu(priv->device, buf->addr,
@ -6041,20 +6072,20 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
/* Remove FCS if needed */
if (!fcs_stripped && pskb_trim(skb, len)) {
dev_kfree_skb_any(skb);
skb = NULL;
rx_dropped++;
count++;
continue;
goto next;
}
stmmac_get_rx_hwtstamp(priv, p, np, skb);
if (priv->hw->hw_vlan_en)
if (priv->hw->hw_vlan_en) {
/* MAC level stripping. */
stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
else
/* Driver level stripping. */
stmmac_rx_vlan(priv->dev, skb);
} else if (stmmac_rx_vlan(priv->dev, skb)) {
dev_kfree_skb_any(skb);
rx_dropped++;
goto next;
}
skb->protocol = eth_type_trans(skb, priv->dev);
@ -6069,14 +6100,15 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
skb_record_rx_queue(skb, queue);
napi_gro_receive(&ch->rx_napi, skb);
skb = NULL;
rx_packets++;
rx_bytes += len;
next:
in_progress = false;
skb = NULL;
count++;
}
if (status & rx_not_ls || skb) {
if (in_progress || skb) {
rx_q->state_saved = true;
rx_q->state.skb = skb;
rx_q->state.error = error;
@ -8213,6 +8245,7 @@ static int __stmmac_dvr_probe(struct device *device,
stmmac_napi_add(ndev);
mutex_init(&priv->lock);
mutex_init(&priv->est_lock);
rwlock_init(&priv->ptp_lock);
stmmac_fpe_init(priv);
@ -8346,6 +8379,7 @@ void stmmac_dvr_remove(struct device *dev)
destroy_workqueue(priv->wq);
mutex_destroy(&priv->lock);
mutex_destroy(&priv->est_lock);
bitmap_free(priv->af_xdp_zc_qps);
pm_runtime_disable(dev);
@ -8421,6 +8455,9 @@ static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue)
{
struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];
dev_kfree_skb_any(rx_q->state.skb);
rx_q->state.skb = NULL;
rx_q->state_saved = false;
rx_q->cur_rx = 0;
rx_q->dirty_rx = 0;
}
@ -8525,6 +8562,10 @@ int stmmac_resume(struct device *dev)
ret = stmmac_init_timestamping(priv);
if (ret)
goto error_stop_dma;
ret = stmmac_setup_est(priv);
if (ret)
goto error_stop_dma;
}
init_coalesce:

View File

@ -8,6 +8,7 @@
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
*******************************************************************************/
#include "stmmac.h"
#include "stmmac_est.h"
#include "stmmac_ptp.h"
#define PTP_SAFE_TIME_OFFSET_NS 500000
@ -54,8 +55,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
u32 sec, nsec;
u32 quotient, reminder;
int neg_adj = 0;
bool xmac, est_rst = false;
int ret;
bool xmac;
xmac = dwmac_is_xmac(priv->plat->core_type);
@ -69,47 +69,21 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
nsec = reminder;
/* If EST is enabled, disabled it before adjust ptp time. */
if (priv->est && priv->est->enable) {
est_rst = true;
mutex_lock(&priv->est_lock);
priv->est->enable = false;
mutex_lock(&priv->est_lock);
if (priv->est && priv->est->enable)
stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->est_lock);
}
priv->plat->clk_ptp_rate, false);
mutex_unlock(&priv->est_lock);
write_lock_irqsave(&priv->ptp_lock, flags);
stmmac_adjust_systime(priv, priv->ptpaddr, sec, nsec, neg_adj, xmac);
write_unlock_irqrestore(&priv->ptp_lock, flags);
/* Calculate new basetime and re-configured EST after PTP time adjust. */
if (est_rst) {
struct timespec64 current_time, time;
ktime_t current_time_ns, basetime;
u64 cycle_time;
mutex_lock(&priv->est_lock);
priv->ptp_clock_ops.gettimex64(&priv->ptp_clock_ops,
&current_time, NULL);
current_time_ns = timespec64_to_ktime(current_time);
time.tv_nsec = priv->est->btr_reserve[0];
time.tv_sec = priv->est->btr_reserve[1];
basetime = timespec64_to_ktime(time);
cycle_time = (u64)priv->est->ctr[1] * NSEC_PER_SEC +
priv->est->ctr[0];
time = stmmac_calc_tas_basetime(basetime,
current_time_ns,
cycle_time);
priv->est->btr[0] = (u32)time.tv_nsec;
priv->est->btr[1] = (u32)time.tv_sec;
priv->est->enable = true;
ret = stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->est_lock);
if (ret)
netdev_err(priv->dev, "failed to configure EST\n");
}
mutex_lock(&priv->est_lock);
if (priv->est && priv->est->enable)
__stmmac_setup_est(priv);
mutex_unlock(&priv->est_lock);
return 0;
}

View File

@ -966,11 +966,12 @@ static void tc_taprio_map_maxsdu_txq(struct stmmac_priv *priv,
static int tc_taprio_configure(struct stmmac_priv *priv,
struct tc_taprio_qopt_offload *qopt)
{
u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep;
u32 wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep;
struct netlink_ext_ack *extack = qopt->mqprio.extack;
struct timespec64 time, current_time, qopt_time;
ktime_t current_time_ns;
int err, i, ret = 0;
u32 *gcl = NULL;
u64 ctr;
if (qopt->base_time < 0)
@ -1013,44 +1014,46 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
return -EOPNOTSUPP;
}
mutex_lock(&priv->est_lock);
if (qopt->cmd == TAPRIO_CMD_DESTROY)
goto disable;
if (qopt->num_entries > dep)
return -EINVAL;
if (!qopt->cycle_time)
return -ERANGE;
if (qopt->cycle_time_extension >= BIT(wid + 7))
return -ERANGE;
if (!priv->est) {
priv->est = devm_kzalloc(priv->device, sizeof(*priv->est),
GFP_KERNEL);
if (!priv->est)
return -ENOMEM;
mutex_init(&priv->est_lock);
} else {
mutex_lock(&priv->est_lock);
memset(priv->est, 0, sizeof(*priv->est));
mutex_unlock(&priv->est_lock);
if (qopt->num_entries > dep) {
ret = -EINVAL;
goto error_unlock;
}
size = qopt->num_entries;
if (!qopt->cycle_time ||
qopt->cycle_time > (u64)U32_MAX * NSEC_PER_SEC) {
ret = -ERANGE;
goto error_unlock;
}
mutex_lock(&priv->est_lock);
priv->est->gcl_size = size;
priv->est->enable = qopt->cmd == TAPRIO_CMD_REPLACE;
mutex_unlock(&priv->est_lock);
if (qopt->cycle_time_extension >= BIT(wid + 7)) {
ret = -ERANGE;
goto error_unlock;
}
for (i = 0; i < size; i++) {
gcl = kcalloc(qopt->num_entries, sizeof(*gcl), GFP_KERNEL);
if (!gcl) {
ret = -ENOMEM;
goto error_unlock;
}
for (i = 0; i < qopt->num_entries; i++) {
s64 delta_ns = qopt->entries[i].interval;
u32 gates = qopt->entries[i].gate_mask;
if (delta_ns > GENMASK(wid - 1, 0))
return -ERANGE;
if (gates > GENMASK(31 - wid, 0))
return -ERANGE;
if (delta_ns > GENMASK(wid - 1, 0)) {
ret = -ERANGE;
goto error_unlock;
}
if (gates > GENMASK(31 - wid, 0)) {
ret = -ERANGE;
goto error_unlock;
}
switch (qopt->entries[i].command) {
case TC_TAPRIO_CMD_SET_GATES:
@ -1062,13 +1065,26 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
gates &= ~BIT(0);
break;
default:
return -EOPNOTSUPP;
ret = -EOPNOTSUPP;
goto error_unlock;
}
priv->est->gcl[i] = delta_ns | (gates << wid);
gcl[i] = delta_ns | (gates << wid);
}
mutex_lock(&priv->est_lock);
if (!priv->est) {
priv->est = devm_kzalloc(priv->device, sizeof(*priv->est),
GFP_KERNEL);
if (!priv->est) {
ret = -ENOMEM;
goto error_unlock;
}
} else {
memset(priv->est, 0, sizeof(*priv->est));
}
memcpy(priv->est->gcl, gcl, sizeof(*gcl) * qopt->num_entries);
priv->est->gcl_size = qopt->num_entries;
/* Adjust for real system time */
priv->ptp_clock_ops.gettimex64(&priv->ptp_clock_ops, &current_time,
NULL);
@ -1092,8 +1108,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
tc_taprio_map_maxsdu_txq(priv, qopt);
ret = stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->est_lock);
priv->plat->clk_ptp_rate, true);
if (ret) {
netdev_err(priv->dev, "failed to configure EST\n");
goto disable;
@ -1104,24 +1119,31 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
if (ret)
goto disable;
priv->est->pclass = qopt->mqprio.preemptible_tcs;
priv->est->enable = true;
mutex_unlock(&priv->est_lock);
kfree(gcl);
return 0;
disable:
if (priv->est) {
mutex_lock(&priv->est_lock);
priv->est->enable = false;
stmmac_est_configure(priv, priv, priv->est,
priv->plat->clk_ptp_rate);
priv->plat->clk_ptp_rate, false);
/* Reset taprio status */
for (i = 0; i < priv->plat->tx_queues_to_use; i++) {
priv->xstats.max_sdu_txq_drop[i] = 0;
priv->xstats.mtl_est_txq_hlbf[i] = 0;
priv->xstats.mtl_est_txq_hlbs[i] = 0;
}
mutex_unlock(&priv->est_lock);
}
err = stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0);
error_unlock:
mutex_unlock(&priv->est_lock);
kfree(gcl);
return qopt->cmd == TAPRIO_CMD_DESTROY ? err : ret;
}

View File

@ -128,6 +128,7 @@
#define AM65_CPSW_PN_TS_CTL_LTYPE2_TS_319 BIT(21)
#define AM65_CPSW_PN_TS_CTL_LTYPE2_TS_320 BIT(22)
#define AM65_CPSW_PN_TS_CTL_LTYPE2_TS_TTL_NONZERO BIT(23)
#define AM65_CPSW_PN_TS_CTL_LTYPE2_TS_UNI_EN BIT(24)
/* The PTP event messages - Sync, Delay_Req, Pdelay_Req, and Pdelay_Resp. */
#define AM65_CPSW_TS_EVENT_MSG_TYPE_BITS (BIT(0) | BIT(1) | BIT(2) | BIT(3))
@ -1857,7 +1858,8 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_132 |
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_319 |
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_320 |
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_TTL_NONZERO;
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_TTL_NONZERO |
AM65_CPSW_PN_TS_CTL_LTYPE2_TS_UNI_EN;
ts_ctrl = AM65_CPSW_TS_EVENT_MSG_TYPE_BITS <<
AM65_CPSW_PN_TS_CTL_MSG_TYPE_EN_SHIFT;

View File

@ -176,6 +176,9 @@ struct am65_cpts {
struct mutex ptp_clk_lock; /* PHC access sync */
u64 timestamp;
u32 genf_enable;
bool genf_neg_adj;
u32 genf_ppm_hi;
u32 genf_ppm_low;
u32 hw_ts_enable;
u32 estf_enable;
struct sk_buff_head txq;
@ -436,9 +439,11 @@ static int am65_cpts_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct am65_cpts *cpts = container_of(ptp, struct am65_cpts, ptp_info);
u32 estf_ctrl_val = 0, estf_ppm_hi = 0, estf_ppm_low = 0;
u32 genf_ctrl_val[AM65_CPTS_GENF_MAX_NUM];
u32 genf_ppm_hi, genf_ppm_low;
s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
int pps_index = cpts->pps_genf_idx;
u64 adj_period, pps_adj_period;
u64 adj_period, genf_adj_period;
u32 ctrl_val, ppm_hi, ppm_low;
unsigned long flags;
int neg_adj = 0, i;
@ -470,20 +475,33 @@ static int am65_cpts_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
ppm_hi = upper_32_bits(adj_period) & 0x3FF;
ppm_low = lower_32_bits(adj_period);
if (cpts->pps_enabled) {
estf_ctrl_val = am65_cpts_read32(cpts, genf[pps_index].control);
if (neg_adj)
estf_ctrl_val &= ~BIT(1);
else
estf_ctrl_val |= BIT(1);
/* GenF PPM will do correction using cpts refclk tick which is
* (cpts->ts_add_val + 1) ns, so GenF length PPM adj period
* need to be corrected.
*/
genf_adj_period = adj_period * (cpts->ts_add_val + 1);
genf_ppm_hi = upper_32_bits(genf_adj_period) & 0x3FF;
genf_ppm_low = lower_32_bits(genf_adj_period);
cpts->genf_neg_adj = neg_adj;
cpts->genf_ppm_hi = genf_ppm_hi;
cpts->genf_ppm_low = genf_ppm_low;
/* GenF PPM will do correction using cpts refclk tick which is
* (cpts->ts_add_val + 1) ns, so GenF length PPM adj period
* need to be corrected.
*/
pps_adj_period = adj_period * (cpts->ts_add_val + 1);
estf_ppm_hi = upper_32_bits(pps_adj_period) & 0x3FF;
estf_ppm_low = lower_32_bits(pps_adj_period);
for (i = 0; i < AM65_CPTS_GENF_MAX_NUM; i++) {
if (cpts->genf_enable & BIT(i)) {
genf_ctrl_val[i] = am65_cpts_read32(cpts,
genf[i].control);
if (neg_adj)
genf_ctrl_val[i] &= ~BIT(1);
else
genf_ctrl_val[i] |= BIT(1);
}
}
if (cpts->pps_enabled) {
/* am65_cpts_perout_enable_hw() sets pps_index in genf_enable */
estf_ctrl_val = genf_ctrl_val[pps_index];
estf_ppm_hi = genf_ppm_hi;
estf_ppm_low = genf_ppm_low;
}
spin_lock_irqsave(&cpts->lock, flags);
@ -500,10 +518,13 @@ static int am65_cpts_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
am65_cpts_write32(cpts, ppm_hi, ts_ppm_hi);
am65_cpts_write32(cpts, ppm_low, ts_ppm_low);
if (cpts->pps_enabled) {
am65_cpts_write32(cpts, estf_ctrl_val, genf[pps_index].control);
am65_cpts_write32(cpts, estf_ppm_hi, genf[pps_index].ppm_hi);
am65_cpts_write32(cpts, estf_ppm_low, genf[pps_index].ppm_low);
for (i = 0; i < AM65_CPTS_GENF_MAX_NUM; i++) {
if (cpts->genf_enable & BIT(i)) {
am65_cpts_write32(cpts, genf_ctrl_val[i],
genf[i].control);
am65_cpts_write32(cpts, genf_ppm_hi, genf[i].ppm_hi);
am65_cpts_write32(cpts, genf_ppm_low, genf[i].ppm_low);
}
}
for (i = 0; i < AM65_CPTS_ESTF_MAX_NUM; i++) {
@ -513,7 +534,6 @@ static int am65_cpts_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
am65_cpts_write32(cpts, estf_ppm_low, estf[i].ppm_low);
}
}
/* All GenF/EstF can be updated here the same way */
spin_unlock_irqrestore(&cpts->lock, flags);
mutex_unlock(&cpts->ptp_clk_lock);
@ -679,9 +699,12 @@ static void am65_cpts_perout_enable_hw(struct am65_cpts *cpts,
val = lower_32_bits(cycles);
am65_cpts_write32(cpts, val, genf[req->index].length);
am65_cpts_write32(cpts, 0, genf[req->index].control);
am65_cpts_write32(cpts, 0, genf[req->index].ppm_hi);
am65_cpts_write32(cpts, 0, genf[req->index].ppm_low);
am65_cpts_write32(cpts, cpts->genf_neg_adj ? 0 : BIT(1),
genf[req->index].control);
am65_cpts_write32(cpts, cpts->genf_ppm_hi,
genf[req->index].ppm_hi);
am65_cpts_write32(cpts, cpts->genf_ppm_low,
genf[req->index].ppm_low);
cpts->genf_enable |= BIT(req->index);
} else {

View File

@ -260,10 +260,8 @@ int ipa_interrupt_config(struct ipa *ipa)
interrupt->enabled = 0;
interrupt->suspend_enabled = bitmap_zalloc(ipa->endpoint_count,
GFP_KERNEL);
if (!interrupt->suspend_enabled) {
ret = -ENOMEM;
goto err_kfree;
}
if (!interrupt->suspend_enabled)
return -ENOMEM;
/* Disable IPA interrupt types */
reg = ipa_reg(ipa, IPA_IRQ_EN);
@ -289,8 +287,6 @@ int ipa_interrupt_config(struct ipa *ipa)
goto err_disable_wakeup;
}
ipa->interrupt = interrupt;
return 0;
err_disable_wakeup:
@ -299,8 +295,6 @@ int ipa_interrupt_config(struct ipa *ipa)
free_irq(interrupt->irq, interrupt);
err_free_bitmap:
bitmap_free(interrupt->suspend_enabled);
err_kfree:
kfree(interrupt);
return ret;
}
@ -311,8 +305,6 @@ void ipa_interrupt_deconfig(struct ipa *ipa)
struct ipa_interrupt *interrupt = ipa->interrupt;
struct device *dev = ipa->dev;
ipa->interrupt = NULL;
dev_pm_clear_wake_irq(dev);
(void)device_init_wakeup(dev, false);
free_irq(interrupt->irq, interrupt);

View File

@ -643,6 +643,14 @@ static int macvlan_open(struct net_device *dev)
if (err < 0)
goto out;
}
if (dev->flags & IFF_ALLMULTI) {
err = dev_set_allmulti(lowerdev, 1);
if (err < 0) {
if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
dev_set_promiscuity(lowerdev, -1);
goto out;
}
}
goto hash_add;
}
@ -713,6 +721,8 @@ static int macvlan_stop(struct net_device *dev)
dev_mc_unsync(lowerdev, dev);
if (macvlan_passthru(vlan->port)) {
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(lowerdev, -1);
if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
dev_set_promiscuity(lowerdev, -1);
goto hash_del;

View File

@ -111,8 +111,7 @@ static int mctp_i3c_read(struct mctp_i3c_device *mi)
mi->mrl + sizeof(struct mctp_i3c_internal_hdr));
if (!skb) {
stats->rx_dropped++;
rc = -ENOMEM;
goto err;
return -ENOMEM;
}
skb->protocol = htons(ETH_P_MCTP);

View File

@ -1826,9 +1826,13 @@ static void phy_detach_internal(struct phy_device *phydev, bool notify_bus)
struct hwtstamp_provider *hwprov;
/* hwprov may technically be protected by ops lock but
* not for devices with a phydev, see phy_link_topo_add_phy()
* not for devices with a phydev, see phy_link_topo_add_phy().
* Drivers may detach without RTNL while dev is unregistered,
* but then nothing else can reach hwprov.
*/
hwprov = rtnl_dereference(dev->hwprov);
hwprov = rcu_dereference_protected(dev->hwprov,
lockdep_rtnl_is_held() ||
dev->reg_state != NETREG_REGISTERED);
/* Disable timestamp if it is the one selected */
if (hwprov && hwprov->phydev == phydev) {
rcu_assign_pointer(dev->hwprov, NULL);

View File

@ -1377,9 +1377,10 @@ static int veth_set_channels(struct net_device *dev,
* to identify the range we have to disable
*/
veth_disable_range_safe(dev, new_rx_count, old_rx_count);
netif_carrier_on(dev);
if (peer)
if (peer && (peer->flags & IFF_UP)) {
netif_carrier_on(dev);
netif_carrier_on(peer);
}
}
/* update XDP supported features */

View File

@ -1005,12 +1005,6 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
return -EOPNOTSUPP;
}
if (rcu_access_pointer(f->nh) &&
!(state & (NUD_PERMANENT | NUD_NOARP))) {
NL_SET_ERR_MSG(extack, "Cannot make a nexthop fdb dynamic");
return -EOPNOTSUPP;
}
/* Do not allow an externally learned entry to take over an entry added
* by the user.
*/
@ -1274,11 +1268,6 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
if (err)
return err;
if (nhid && !(ndm->ndm_state & (NUD_PERMANENT | NUD_NOARP))) {
NL_SET_ERR_MSG(extack, "A nexthop fdb cannot be dynamic");
return -EINVAL;
}
cfg = rtnl_dereference(vxlan->cfg);
if (cfg->remote_ip.sa.sa_family != ip.sa.sa_family)
return -EAFNOSUPPORT;
@ -2947,6 +2936,9 @@ static void vxlan_cleanup(struct timer_list *t)
if (f->flags & NTF_EXT_LEARNED)
continue;
if (rcu_access_pointer(f->nh))
continue;
timeout = READ_ONCE(f->updated) + cfg->age_interval * HZ;
if (time_before_eq(timeout, jiffies)) {
spin_lock(&vxlan->hash_lock);

View File

@ -1639,7 +1639,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
if (!msgbuf->tx_pktids)
goto fail;
msgbuf->rx_pktids = brcmf_msgbuf_init_pktids(NR_RX_PKTIDS,
DMA_FROM_DEVICE);
DMA_BIDIRECTIONAL);
if (!msgbuf->rx_pktids)
goto fail;

View File

@ -458,7 +458,7 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb)
tx_params->sta_id = 0;
}
if (rsta) {
if (rsta && tid < IEEE80211_NUM_TIDS) {
/* Start aggregation if not done for this tid */
if (!rsta->start_tx_aggr[tid]) {
rsta->start_tx_aggr[tid] = true;

View File

@ -209,9 +209,17 @@ static void mhi_wwan_ctrl_dtr_work(struct work_struct *work)
static void mhi_wwan_ctrl_dtr_rts(struct wwan_port *port, unsigned int mdmbits)
{
struct mhi_wwan_dev *mhiwwan = wwan_port_get_drvdata(port);
bool drop = (READ_ONCE(mhiwwan->dtr_mdmbits) & TIOCM_DTR) &&
!(mdmbits & TIOCM_DTR);
WRITE_ONCE(mhiwwan->dtr_mdmbits, mdmbits);
schedule_delayed_work(&mhiwwan->dtr_work, 0);
/* A DTR drop matters on its own, e.g. to hang up a modem set to AT&D2,
* so send it now rather than let a following raise coalesce it away
*/
if (drop)
flush_delayed_work(&mhiwwan->dtr_work);
}
static int mhi_wwan_ctrl_start(struct wwan_port *port)
@ -246,6 +254,9 @@ static void mhi_wwan_ctrl_stop(struct wwan_port *port)
cancel_work_sync(&mhiwwan->rx_refill);
/* Send any pending DTR/RTS state before the channel stops */
flush_delayed_work(&mhiwwan->dtr_work);
mhi_unprepare_from_transfer(mhiwwan->mhi_dev);
}

View File

@ -508,6 +508,11 @@ static int unregister_vclock(struct device *dev, void *data)
int ptp_clock_unregister(struct ptp_clock *ptp)
{
/*
* Stop and drain virtual-clock creation and deletion before walking the
* children. Do not hold n_vclocks_mux while waiting for sysfs callbacks.
*/
ptp_vclock_remove_sysfs(ptp);
if (ptp_vclock_in_use(ptp)) {
device_for_each_child(&ptp->dev, NULL, unregister_vclock);
}

View File

@ -81,7 +81,11 @@ struct ptp_vclock {
struct hlist_node vclock_hash_node;
struct cyclecounter cc;
struct timecounter tc;
struct mutex lock; /* protects tc/cc */
u64 cycles;
struct mutex lock; /* protects tc/cc and the cached sample */
/* Owned by the auxiliary worker. */
unsigned long retry_delay;
unsigned long refresh_deadline;
};
/*
@ -169,6 +173,7 @@ extern const struct attribute_group *ptp_groups[];
int ptp_populate_pin_groups(struct ptp_clock *ptp);
void ptp_cleanup_pin_groups(struct ptp_clock *ptp);
void ptp_vclock_remove_sysfs(struct ptp_clock *ptp);
struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock);
void ptp_vclock_unregister(struct ptp_vclock *vclock);

View File

@ -80,13 +80,17 @@ static ssize_t extts_fifo_show(struct device *dev,
size_t qcnt;
int cnt = 0;
spin_lock_irqsave(&ptp->tsevqs_lock, flags);
cnt = list_count_nodes(&ptp->tsevqs);
if (cnt <= 0)
if (cnt <= 0) {
spin_unlock_irqrestore(&ptp->tsevqs_lock, flags);
goto out;
}
/* The sysfs fifo will always draw from the fist queue */
queue = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue,
qlist);
spin_unlock_irqrestore(&ptp->tsevqs_lock, flags);
memset(&event, 0, sizeof(event));
spin_lock_irqsave(&queue->lock, flags);
@ -224,8 +228,10 @@ static ssize_t n_vclocks_store(struct device *dev,
if (num > ptp->n_vclocks) {
for (i = 0; i < num - ptp->n_vclocks; i++) {
vclock = ptp_vclock_register(ptp);
if (!vclock)
goto out;
if (IS_ERR(vclock)) {
err = PTR_ERR(vclock);
goto err_register;
}
*(ptp->vclock_index + ptp->n_vclocks + i) =
vclock->clock->index;
@ -257,12 +263,24 @@ static ssize_t n_vclocks_store(struct device *dev,
mutex_unlock(&ptp->n_vclocks_mux);
return count;
err_register:
num = i;
if (num)
device_for_each_child_reverse(dev, &num, unregister_vclock);
for (num = 0; num < i; num++)
ptp->vclock_index[ptp->n_vclocks + num] = -1;
out:
mutex_unlock(&ptp->n_vclocks_mux);
return err;
}
static DEVICE_ATTR_RW(n_vclocks);
void ptp_vclock_remove_sysfs(struct ptp_clock *ptp)
{
if (!ptp->is_virtual_clock)
device_remove_file(&ptp->dev, &dev_attr_n_vclocks);
}
static ssize_t max_vclocks_show(struct device *dev,
struct device_attribute *attr, char *page)
{

View File

@ -4,6 +4,7 @@
*
* Copyright 2021 NXP
*/
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/hashtable.h>
#include "ptp_private.h"
@ -13,6 +14,7 @@
#define PTP_VCLOCK_FADJ_SHIFT 9
#define PTP_VCLOCK_FADJ_DENOMINATOR 15625ULL
#define PTP_VCLOCK_REFRESH_INTERVAL (HZ * 2)
#define PTP_VCLOCK_RETRY_INTERVAL msecs_to_jiffies(10)
/* protects vclock_hash addition/deletion */
static DEFINE_SPINLOCK(vclock_hash_lock);
@ -42,21 +44,39 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock)
synchronize_srcu(&vclock_srcu);
}
/* The caller holds vclock->lock, or has not published the clock yet. */
static int ptp_vclock_sample(struct ptp_vclock *vclock)
{
struct ptp_clock *ptp = vclock->pclock;
struct timespec64 ts;
int err;
err = ptp->info->getcycles64(ptp->info, &ts);
if (!err)
vclock->cycles = timespec64_to_ns(&ts);
return err;
}
static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct ptp_vclock *vclock = info_to_vclock(ptp);
s64 adj;
int err;
adj = (s64)scaled_ppm << PTP_VCLOCK_FADJ_SHIFT;
adj = div_s64(adj, PTP_VCLOCK_FADJ_DENOMINATOR);
if (mutex_lock_interruptible(&vclock->lock))
return -EINTR;
timecounter_read(&vclock->tc);
vclock->cc.mult = PTP_VCLOCK_CC_MULT + adj;
err = ptp_vclock_sample(vclock);
if (!err) {
timecounter_read(&vclock->tc);
vclock->cc.mult = PTP_VCLOCK_CC_MULT + adj;
}
mutex_unlock(&vclock->lock);
return 0;
return err;
}
static int ptp_vclock_adjtime(struct ptp_clock_info *ptp, s64 delta)
@ -75,15 +95,16 @@ static int ptp_vclock_gettime(struct ptp_clock_info *ptp,
struct timespec64 *ts)
{
struct ptp_vclock *vclock = info_to_vclock(ptp);
u64 ns;
int err;
if (mutex_lock_interruptible(&vclock->lock))
return -EINTR;
ns = timecounter_read(&vclock->tc);
err = ptp_vclock_sample(vclock);
if (!err)
*ts = ns_to_timespec64(timecounter_read(&vclock->tc));
mutex_unlock(&vclock->lock);
*ts = ns_to_timespec64(ns);
return 0;
return err;
}
static int ptp_vclock_gettimex(struct ptp_clock_info *ptp,
@ -94,20 +115,18 @@ static int ptp_vclock_gettimex(struct ptp_clock_info *ptp,
struct ptp_clock *pptp = vclock->pclock;
struct timespec64 pts;
int err;
u64 ns;
err = pptp->info->getcyclesx64(pptp->info, &pts, sts);
if (err)
return err;
if (mutex_lock_interruptible(&vclock->lock))
return -EINTR;
ns = timecounter_cyc2time(&vclock->tc, timespec64_to_ns(&pts));
err = pptp->info->getcyclesx64(pptp->info, &pts, sts);
if (!err) {
u64 ns = timecounter_cyc2time(&vclock->tc, timespec64_to_ns(&pts));
*ts = ns_to_timespec64(ns);
}
mutex_unlock(&vclock->lock);
*ts = ns_to_timespec64(ns);
return 0;
return err;
}
static int ptp_vclock_settime(struct ptp_clock_info *ptp,
@ -115,13 +134,16 @@ static int ptp_vclock_settime(struct ptp_clock_info *ptp,
{
struct ptp_vclock *vclock = info_to_vclock(ptp);
u64 ns = timespec64_to_ns(ts);
int err;
if (mutex_lock_interruptible(&vclock->lock))
return -EINTR;
timecounter_init(&vclock->tc, &vclock->cc, ns);
err = ptp_vclock_sample(vclock);
if (!err)
timecounter_init(&vclock->tc, &vclock->cc, ns);
mutex_unlock(&vclock->lock);
return 0;
return err;
}
static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp,
@ -130,20 +152,18 @@ static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp,
struct ptp_vclock *vclock = info_to_vclock(ptp);
struct ptp_clock *pptp = vclock->pclock;
int err;
u64 ns;
err = pptp->info->getcrosscycles(pptp->info, xtstamp);
if (err)
return err;
if (mutex_lock_interruptible(&vclock->lock))
return -EINTR;
ns = timecounter_cyc2time(&vclock->tc, ktime_to_ns(xtstamp->device));
err = pptp->info->getcrosscycles(pptp->info, xtstamp);
if (!err) {
u64 ns = timecounter_cyc2time(&vclock->tc, ktime_to_ns(xtstamp->device));
xtstamp->device = ns_to_ktime(ns);
}
mutex_unlock(&vclock->lock);
xtstamp->device = ns_to_ktime(ns);
return 0;
return err;
}
static long ptp_vclock_refresh(struct ptp_clock_info *ptp)
@ -151,8 +171,24 @@ static long ptp_vclock_refresh(struct ptp_clock_info *ptp)
struct ptp_vclock *vclock = info_to_vclock(ptp);
struct timespec64 ts;
ptp_vclock_gettime(&vclock->info, &ts);
/* Retry transient failures promptly, but back off during long outages. */
if (ptp_vclock_gettime(&vclock->info, &ts)) {
unsigned long now = jiffies;
/* Retries must not postpone the next regular refresh attempt. */
if (!vclock->retry_delay || time_after_eq(now, vclock->refresh_deadline))
vclock->refresh_deadline = now + PTP_VCLOCK_REFRESH_INTERVAL;
if (!vclock->retry_delay)
vclock->retry_delay = PTP_VCLOCK_RETRY_INTERVAL;
else
vclock->retry_delay = min_t(unsigned long,
vclock->retry_delay * 2,
PTP_VCLOCK_REFRESH_INTERVAL);
return min(vclock->retry_delay, vclock->refresh_deadline - now);
}
vclock->retry_delay = 0;
return PTP_VCLOCK_REFRESH_INTERVAL;
}
@ -174,12 +210,9 @@ static const struct ptp_clock_info ptp_vclock_info = {
static u64 ptp_vclock_read(struct cyclecounter *cc)
{
struct ptp_vclock *vclock = cc_to_vclock(cc);
struct ptp_clock *ptp = vclock->pclock;
struct timespec64 ts = {};
ptp->info->getcycles64(ptp->info, &ts);
return timespec64_to_ns(&ts);
/* The cyclecounter callback cannot report a failed PHC read. */
return vclock->cycles;
}
static const struct cyclecounter ptp_vclock_cc = {
@ -192,10 +225,11 @@ static const struct cyclecounter ptp_vclock_cc = {
struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock)
{
struct ptp_vclock *vclock;
int err;
vclock = kzalloc_obj(*vclock);
if (!vclock)
return NULL;
return ERR_PTR(-ENOMEM);
vclock->pclock = pclock;
vclock->info = ptp_vclock_info;
@ -214,20 +248,29 @@ struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock)
mutex_init(&vclock->lock);
err = ptp_vclock_sample(vclock);
if (err)
goto free_vclock;
timecounter_init(&vclock->tc, &vclock->cc, 0);
vclock->clock = ptp_clock_register(&vclock->info, &pclock->dev);
if (IS_ERR_OR_NULL(vclock->clock)) {
kfree(vclock);
return NULL;
if (IS_ERR(vclock->clock)) {
err = PTR_ERR(vclock->clock);
goto free_vclock;
}
ptp_vclock_set_subclass(vclock->clock);
timecounter_init(&vclock->tc, &vclock->cc, 0);
ptp_schedule_worker(vclock->clock, PTP_VCLOCK_REFRESH_INTERVAL);
/* The initial sample predates registration; refresh without more delay. */
ptp_schedule_worker(vclock->clock, 0);
ptp_vclock_hash_add(vclock);
return vclock;
free_vclock:
kfree(vclock);
return ERR_PTR(err);
}
void ptp_vclock_unregister(struct ptp_vclock *vclock)
@ -283,6 +326,8 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index)
u64 ns;
ns = ktime_to_ns(*hwtstamp);
if (!ns)
return 0;
srcu_idx = srcu_read_lock(&vclock_srcu);

View File

@ -360,7 +360,7 @@ static struct sk_buff *
vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
unsigned int out, unsigned int in)
{
struct virtio_vsock_hdr *hdr;
struct virtio_vsock_hdr hdr;
struct iov_iter iov_iter;
struct sk_buff *skb;
size_t payload_len;
@ -378,34 +378,32 @@ vhost_vsock_alloc_skb(struct vhost_virtqueue *vq,
len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + VIRTIO_VSOCK_SKB_HEADROOM)
return NULL;
/* len contains both payload and hdr */
skb = virtio_vsock_alloc_skb(len, GFP_KERNEL);
if (!skb)
return NULL;
iov_iter_init(&iov_iter, ITER_SOURCE, vq->iov, out, len);
hdr = virtio_vsock_hdr(skb);
nbytes = copy_from_iter(hdr, sizeof(*hdr), &iov_iter);
if (nbytes != sizeof(*hdr)) {
nbytes = copy_from_iter(&hdr, sizeof(hdr), &iov_iter);
if (nbytes != sizeof(hdr)) {
vq_err(vq, "Expected %zu bytes for pkt->hdr, got %zu bytes\n",
sizeof(*hdr), nbytes);
kfree_skb(skb);
sizeof(hdr), nbytes);
return NULL;
}
payload_len = le32_to_cpu(hdr->len);
payload_len = le32_to_cpu(hdr.len);
/* The pkt is too big or the length in the header is invalid */
if (payload_len > len - sizeof(hdr))
return NULL;
/* Allocate only for the payload declared in the header. */
skb = virtio_vsock_alloc_skb(payload_len + sizeof(hdr), GFP_KERNEL);
if (!skb)
return NULL;
memcpy(virtio_vsock_hdr(skb), &hdr, sizeof(hdr));
/* No payload */
if (!payload_len)
return skb;
/* The pkt is too big or the length in the header is invalid */
if (payload_len + sizeof(*hdr) > len) {
kfree_skb(skb);
return NULL;
}
virtio_vsock_skb_put(skb, payload_len);
if (skb_copy_datagram_from_iter(skb, 0, &iov_iter, payload_len)) {

View File

@ -45,6 +45,7 @@
#include <linux/can.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
/* exposed CAN device capabilities for network layer */
#define CAN_CAP_CC BIT(0) /* CAN CC aka Classical CAN */
@ -59,6 +60,7 @@
enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_MAX };
struct can_dev_rcv_lists {
spinlock_t lock; /* protects the receive lists and entries */
struct hlist_head rx[RX_MAX];
struct hlist_head rx_sff[CAN_SFF_RCV_ARRAY_SZ];
struct hlist_head rx_eff[CAN_EFF_RCV_ARRAY_SZ];
@ -81,6 +83,7 @@ static inline struct can_ml_priv *can_get_ml_priv(struct net_device *dev)
static inline void can_set_ml_priv(struct net_device *dev,
struct can_ml_priv *ml_priv)
{
spin_lock_init(&ml_priv->dev_rcv_lists.lock);
netdev_set_ml_priv(dev, ml_priv, ML_PRIV_CAN);
}

View File

@ -51,7 +51,7 @@ extern void can_proto_unregister(const struct can_proto *cp);
int can_rx_register(struct net *net, struct net_device *dev,
canid_t can_id, canid_t mask,
void (*func)(struct sk_buff *, void *),
void *data, char *ident, struct sock *sk);
void *data, u64 ino, struct sock *sk);
extern void can_rx_unregister(struct net *net, struct net_device *dev,
canid_t can_id, canid_t mask,

View File

@ -176,7 +176,7 @@ static inline bool can_dev_dropped_skb(struct net_device *dev, struct sk_buff *s
return can_dropped_invalid_skb(dev, skb);
invalid_skb:
kfree_skb(skb);
dev_kfree_skb_any(skb);
dev->stats.tx_dropped++;
return true;
}

View File

@ -78,12 +78,12 @@ static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
nskb = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!nskb)) {
kfree_skb(skb);
dev_kfree_skb_any(skb);
return NULL;
}
can_skb_set_owner(nskb, skb->sk);
consume_skb(skb);
dev_consume_skb_any(skb);
return nskb;
}

View File

@ -119,6 +119,7 @@ enum {
* @mfc_flags: entry flags
* @expires: unresolved entry expire time
* @unresolved: unresolved cached skbs
* @nl_queries: queued RTM_GETROUTE requests waiting for resolution
* @last_assert: time of last assert
* @minvif: minimum VIF id
* @maxvif: maximum VIF id
@ -141,6 +142,7 @@ struct mr_mfc {
struct {
unsigned long expires;
struct sk_buff_head unresolved;
struct sk_buff_head nl_queries;
} unres;
struct {
unsigned long last_assert;

View File

@ -440,6 +440,7 @@ enum {
NAPI_STATE_HAS_NOTIFIER, /* Napi has an IRQ notifier */
NAPI_STATE_THREADED_BUSY_POLL, /* The threaded NAPI poller will busy poll */
NAPI_STATE_PERCPU, /* NAPI handler is run per-CPU - incompatible with threaded mode */
NAPI_STATE_DISABLED, /* NAPI is disabled */
};
enum {
@ -456,6 +457,7 @@ enum {
NAPIF_STATE_HAS_NOTIFIER = BIT(NAPI_STATE_HAS_NOTIFIER),
NAPIF_STATE_THREADED_BUSY_POLL = BIT(NAPI_STATE_THREADED_BUSY_POLL),
NAPIF_STATE_PERCPU = BIT(NAPI_STATE_PERCPU),
NAPIF_STATE_DISABLED = BIT(NAPI_STATE_DISABLED),
};
enum gro_result {

View File

@ -496,7 +496,7 @@ int ptp_get_vclocks_index(int pclock_index, int **vclock_index);
* @hwtstamp: timestamp
* @vclock_index: phc index of ptp vclock.
*
* Returns: converted timestamp, or 0 on error.
* Returns: converted timestamp, or 0 if @hwtstamp is zero or on error.
*/
ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index);
#else

View File

@ -179,6 +179,9 @@ struct tcp_request_sock {
u8 ao_rcv_next;
bool used_tcp_ao;
#endif
#if IS_ENABLED(CONFIG_IPV6)
__be32 syn_flowlabel;
#endif
};
#define tcp_rsk(ptr) container_of_const(ptr, struct tcp_request_sock, req.req)

View File

@ -680,6 +680,45 @@ enum conn_reasons {
CONN_REASON_ISO_CONNECT,
};
enum {
HCI_CONN_AUTH_PEND,
HCI_CONN_ENCRYPT_PEND,
HCI_CONN_RSWITCH_PEND,
HCI_CONN_MODE_CHANGE_PEND,
HCI_CONN_SCO_SETUP_PEND,
HCI_CONN_MGMT_CONNECTED,
HCI_CONN_SSP_ENABLED,
HCI_CONN_SC_ENABLED,
HCI_CONN_AES_CCM,
HCI_CONN_POWER_SAVE,
HCI_CONN_FLUSH_KEY,
HCI_CONN_ENCRYPT,
HCI_CONN_AUTH,
HCI_CONN_SECURE,
HCI_CONN_FIPS,
HCI_CONN_STK_ENCRYPT,
HCI_CONN_AUTH_INITIATOR,
HCI_CONN_DROP,
HCI_CONN_CANCEL,
HCI_CONN_PARAM_REMOVAL_PEND,
HCI_CONN_NEW_LINK_KEY,
HCI_CONN_SCANNING,
HCI_CONN_AUTH_FAILURE,
HCI_CONN_PER_ADV,
HCI_CONN_BIG_CREATED,
HCI_CONN_CREATE,
HCI_CONN_CREATE_CIS,
HCI_CONN_CREATE_BIG_SYNC,
HCI_CONN_BIG_SYNC,
HCI_CONN_BIG_SYNC_FAILED,
HCI_CONN_CREATE_PA_SYNC,
HCI_CONN_PA_SYNC,
HCI_CONN_PA_SYNC_FAILED,
HCI_CONN_ENC_KEY_SIZE_PEND,
__HCI_CONN_NUM_FLAGS,
};
struct hci_conn {
struct list_head list;
@ -750,7 +789,7 @@ struct hci_conn {
__u8 num_bis;
__u8 bis[HCI_MAX_ISO_BIS];
unsigned long flags;
DECLARE_BITMAP(flags, __HCI_CONN_NUM_FLAGS);
enum conn_reasons conn_reason;
__u8 abort_reason;
@ -980,55 +1019,18 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
bool name_known);
void hci_inquiry_cache_flush(struct hci_dev *hdev);
/* ----- HCI Connections ----- */
enum {
HCI_CONN_AUTH_PEND,
HCI_CONN_ENCRYPT_PEND,
HCI_CONN_RSWITCH_PEND,
HCI_CONN_MODE_CHANGE_PEND,
HCI_CONN_SCO_SETUP_PEND,
HCI_CONN_MGMT_CONNECTED,
HCI_CONN_SSP_ENABLED,
HCI_CONN_SC_ENABLED,
HCI_CONN_AES_CCM,
HCI_CONN_POWER_SAVE,
HCI_CONN_FLUSH_KEY,
HCI_CONN_ENCRYPT,
HCI_CONN_AUTH,
HCI_CONN_SECURE,
HCI_CONN_FIPS,
HCI_CONN_STK_ENCRYPT,
HCI_CONN_AUTH_INITIATOR,
HCI_CONN_DROP,
HCI_CONN_CANCEL,
HCI_CONN_PARAM_REMOVAL_PEND,
HCI_CONN_NEW_LINK_KEY,
HCI_CONN_SCANNING,
HCI_CONN_AUTH_FAILURE,
HCI_CONN_PER_ADV,
HCI_CONN_BIG_CREATED,
HCI_CONN_CREATE,
HCI_CONN_CREATE_CIS,
HCI_CONN_CREATE_BIG_SYNC,
HCI_CONN_BIG_SYNC,
HCI_CONN_BIG_SYNC_FAILED,
HCI_CONN_CREATE_PA_SYNC,
HCI_CONN_PA_SYNC,
HCI_CONN_PA_SYNC_FAILED,
};
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
return hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
test_bit(HCI_CONN_SSP_ENABLED, conn->flags);
}
static inline bool hci_conn_sc_enabled(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
return hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
test_bit(HCI_CONN_SC_ENABLED, &conn->flags);
test_bit(HCI_CONN_SC_ENABLED, conn->flags);
}
static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
@ -1219,7 +1221,7 @@ hci_conn_hash_lookup_create_pa_sync(struct hci_dev *hdev)
if (c->type != PA_LINK)
continue;
if (!test_bit(HCI_CONN_CREATE_PA_SYNC, &c->flags))
if (!test_bit(HCI_CONN_CREATE_PA_SYNC, c->flags))
continue;
rcu_read_unlock();
@ -1245,7 +1247,7 @@ hci_conn_hash_lookup_per_adv_bis(struct hci_dev *hdev,
list_for_each_entry_rcu(c, &h->list, list) {
if (bacmp(&c->dst, ba) || c->type != BIS_LINK ||
!test_bit(HCI_CONN_PER_ADV, &c->flags))
!test_bit(HCI_CONN_PER_ADV, c->flags))
continue;
if (c->iso_qos.bcast.big == big &&
@ -1502,7 +1504,7 @@ hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big)
list_for_each_entry_rcu(c, &h->list, list) {
if (c->type != BIS_LINK ||
!test_bit(HCI_CONN_PA_SYNC, &c->flags))
!test_bit(HCI_CONN_PA_SYNC, c->flags))
continue;
if (c->iso_qos.bcast.big == big) {
@ -1580,7 +1582,7 @@ static inline void hci_conn_hash_list_flag(struct hci_dev *hdev,
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
if (c->type == type && test_bit(flag, &c->flags))
if (c->type == type && test_bit(flag, c->flags))
func(c, data);
}
@ -1598,7 +1600,7 @@ static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev)
list_for_each_entry_rcu(c, &h->list, list) {
if (c->type == LE_LINK && c->state == BT_CONNECT &&
!test_bit(HCI_CONN_SCANNING, &c->flags)) {
!test_bit(HCI_CONN_SCANNING, c->flags)) {
rcu_read_unlock();
return c;
}
@ -1619,7 +1621,7 @@ static inline bool hci_is_le_conn_scanning(struct hci_dev *hdev)
list_for_each_entry_rcu(c, &h->list, list) {
if (c->type == LE_LINK && c->state == BT_CONNECT &&
test_bit(HCI_CONN_SCANNING, &c->flags)) {
test_bit(HCI_CONN_SCANNING, c->flags)) {
rcu_read_unlock();
return true;
}
@ -2239,10 +2241,10 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
struct hci_cb *cb;
__u8 encrypt;
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
if (test_bit(HCI_CONN_ENCRYPT_PEND, conn->flags))
return;
encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00;
encrypt = test_bit(HCI_CONN_ENCRYPT, conn->flags) ? 0x01 : 0x00;
mutex_lock(&hci_cb_list_lock);
list_for_each_entry(cb, &hci_cb_list, list) {
@ -2271,9 +2273,9 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status)
return;
}
if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
if (!test_bit(HCI_CONN_ENCRYPT, conn->flags))
encrypt = 0x00;
else if (test_bit(HCI_CONN_AES_CCM, &conn->flags))
else if (test_bit(HCI_CONN_AES_CCM, conn->flags))
encrypt = 0x02;
else
encrypt = 0x01;
@ -2426,6 +2428,8 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb);
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
void *hci_sent_cmd_data_len(struct hci_dev *hdev, __u16 opcode,
size_t *len);
void *hci_recv_event_data(struct hci_dev *hdev, __u8 event);
u32 hci_conn_get_phy(struct hci_conn *conn);

View File

@ -34,7 +34,8 @@ static inline struct espintcp_ctx *espintcp_getctx(const struct sock *sk)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
/* RCU is only needed for diag */
return (__force void *)icsk->icsk_ulp_data;
/* pairs with smp_wmb() in espintcp_init_sk() */
smp_rmb();
return (__force void *)READ_ONCE(icsk->icsk_ulp_data);
}
#endif

View File

@ -79,6 +79,7 @@ struct frag_v6_compare_key {
* @tstamp_type: stamp has a mono delivery time (EDT)
* @flags: fragment queue flags
* @max_size: maximum received fragment size
* @truesize: sum of the truesize of queued fragments
* @fqdir: pointer to struct fqdir
* @rcu: rcu head for freeing deferall
*/
@ -100,6 +101,7 @@ struct inet_frag_queue {
u8 tstamp_type;
__u8 flags;
u16 max_size;
unsigned int truesize;
struct fqdir *fqdir;
struct rcu_head rcu;
};
@ -172,6 +174,13 @@ extern const u8 ip_frag_ecn_table[16];
#define IPFRAG_DUP 1
#define IPFRAG_OVERLAP 2
#define IPFRAG_MIXED_SECPATH 3
#define IPFRAG_TOOBIG 4
/* Max sum of the truesize of fragments in a queue. This keeps the sums
* done in inet_frag_reasm_prepare() and inet_frag_reasm_finish() well
* below INT_MAX. Legitimate traffic stays far below this limit.
*/
#define INET_FRAG_MAX_TRUESIZE (INT_MAX / 2)
int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb,
int offset, int end);
void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb,

View File

@ -201,6 +201,8 @@
#include <linux/wireless.h> /* IOCTL user space API */
#include <linux/if_ether.h>
struct net;
/***************************** VERSION *****************************/
/*
* This constant is used to know which version of the driver API is
@ -411,10 +413,10 @@ struct iw_spy_data {
void wireless_send_event(struct net_device *dev, unsigned int cmd,
union iwreq_data *wrqu, const char *extra);
#ifdef CONFIG_WEXT_CORE
/* flush all previous wext events - if work is done from netdev notifiers */
void wireless_nlevent_flush(void);
/* Flush previous wext events in this netns from netdev notifiers. */
void wireless_nlevent_flush(struct net *net);
#else
static inline void wireless_nlevent_flush(void) {}
static inline void wireless_nlevent_flush(struct net *net) {}
#endif
/* We may need a function to send a stream of events to user space.

View File

@ -60,6 +60,7 @@ enum gdma_work_request_flags {
enum gdma_eqe_type {
GDMA_EQE_COMPLETION = 3,
GDMA_EQE_THROTTLE = 4,
GDMA_EQE_TEST_EVENT = 64,
GDMA_EQE_HWC_INIT_EQ_ID_DB = 129,
GDMA_EQE_HWC_INIT_DATA = 130,
@ -291,6 +292,7 @@ struct gdma_dev {
#define GDMA_EQE_SIZE 16
#define GDMA_MAX_SQE_SIZE 512
#define GDMA_MAX_RQE_SIZE 256
#define GDMA_EQ_MAX_CHILD_CQ 2
#define GDMA_COMP_DATA_SIZE 0x3C
@ -318,6 +320,11 @@ struct gdma_event {
struct gdma_queue;
struct gdma_eq_stats {
u64_stats_t throttle_count;
struct u64_stats_sync syncp;
};
struct mana_eq {
struct gdma_queue *eq;
struct dentry *mana_eq_debugfs;
@ -371,6 +378,10 @@ struct gdma_queue {
unsigned int irq;
u32 log2_throttle_limit;
struct gdma_eq_stats stats;
struct gdma_queue __rcu *child_cq[GDMA_EQ_MAX_CHILD_CQ];
} eq;
struct {
@ -601,6 +612,8 @@ void mana_gd_free_service_wq(struct gdma_context *gc);
void mana_gd_ring_dim(struct gdma_queue *cq, u32 mod_usec, bool mod_usec_vld,
u32 mod_comps, bool mod_comps_vld);
bool mana_gd_detach_cq(struct gdma_context *gc, struct gdma_queue *queue);
struct gdma_wqe {
u32 reserved :24;
u32 last_vbytes :8;
@ -760,6 +773,9 @@ enum {
/* Driver supports non-contiguous queue buffers */
#define GDMA_DRV_CAP_FLAG_1_NON_CONTIGUOUS_BUFFERS BIT(30)
/* Driver supports handling throttled EQEs */
#define GDMA_DRV_CAP_FLAG_1_THROTTLED_EVENT_QUEUE BIT_ULL(32)
/* Capabilities in the PCI-only group below rely on dynamic MSI-X allocation
* and on the servicing and reset paths reached through
* mana_schedule_serv_work(). Transports that provide neither leave
@ -784,7 +800,8 @@ enum {
GDMA_DRV_CAP_FLAG_1_HANDLE_STALL_SQ_RECOVERY | \
GDMA_DRV_CAP_FLAG_1_EQ_MSI_UNSHARE_MULTI_VPORT | \
GDMA_DRV_CAP_FLAG_1_DYN_INTERRUPT_MODERATION | \
GDMA_DRV_CAP_FLAG_1_NON_CONTIGUOUS_BUFFERS)
GDMA_DRV_CAP_FLAG_1_NON_CONTIGUOUS_BUFFERS | \
GDMA_DRV_CAP_FLAG_1_THROTTLED_EVENT_QUEUE)
#define GDMA_DRV_CAP_FLAGS2 0

View File

@ -90,6 +90,7 @@ enum mana_priv_flag_bits {
/* Update this count whenever the respective structures are changed */
#define MANA_STATS_RX_COUNT (6 + MANA_CQE_COAL_PKTS_8 - 1)
#define MANA_STATS_TX_COUNT 11
#define MANA_STATS_EQ_COUNT 1
#define MANA_RX_FRAG_ALIGNMENT 64

View File

@ -29,7 +29,7 @@ struct netns_can {
/* receive filters subscribed for 'all' CAN devices */
struct can_dev_rcv_lists *rx_alldev_list;
spinlock_t rcvlists_lock;
spinlock_t rcvlists_lock; /* protects the rcv_entries(_max) stats */
struct timer_list stattimer; /* timer for statistics update */
struct can_pkg_stats *pkg_stats;
struct can_rcv_lists_stats *rcv_lists_stats;

View File

@ -1765,6 +1765,13 @@ struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark,
const xfrm_address_t *saddr,
u8 proto,
unsigned short family);
struct xfrm_state *xfrm_state_lookup_exact(struct net *net, const struct xfrm_mark *mark,
const xfrm_address_t *daddr, __be32 spi,
u8 proto, unsigned short family);
bool xfrm_state_mark_collides(struct net *net, u32 mark,
const xfrm_address_t *daddr, __be32 spi,
u8 proto, unsigned short family,
const struct xfrm_state *self);
#ifdef CONFIG_XFRM_SUB_POLICY
void xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
unsigned short family);

View File

@ -1410,7 +1410,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
return BATADV_NO_DUP;
orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
if (WARN_ON(!orig_ifinfo)) {
if (!orig_ifinfo) {
batadv_orig_node_put(orig_node);
return 0;
}
@ -1909,6 +1909,11 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
goto out;
}
/* Mark aggregate as full before forcing emit. */
spin_lock_bh(&bat_priv->forw_bat_list_lock);
forw_packet->num_packets = BATADV_MAX_AGGREGATION_PACKETS;
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
batadv_iv_ogm_emit(forw_packet);
/* we have to have at least one packet in the queue to determine the

View File

@ -653,6 +653,7 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
* NOT_FOUND
*/
cands[select].type = BATADV_DAT_CANDIDATE_NOT_FOUND;
cands[select].orig_node = NULL;
/* iterate over the originator list and find the node with the closest
* dat_address which has not been selected yet

View File

@ -295,6 +295,11 @@ void batadv_mesh_free(struct net_device *mesh_iface)
WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
/* the originator purge worker accesses (among others) the TT tables
* and must therefore be stopped before any of them are freed
*/
disable_delayed_work_sync(&bat_priv->orig_work);
batadv_purge_outstanding_packets(bat_priv, NULL);
batadv_tp_stop_all(bat_priv);
@ -484,8 +489,10 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
* shut down otherwise the packet may trigger de-reference errors
* further down in the receive path.
*/
if (!kref_get_unless_zero(&hard_iface->refcount))
goto err_out;
if (!kref_get_unless_zero(&hard_iface->refcount)) {
kfree_skb(skb);
return NET_RX_DROP;
}
skb = skb_share_check(skb, GFP_ATOMIC);
@ -541,7 +548,6 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
kfree_skb(skb);
err_put:
batadv_hardif_put(hard_iface);
err_out:
return NET_RX_DROP;
}

View File

@ -950,8 +950,11 @@ static int batadv_mcast_forw_packet(struct batadv_priv *bat_priv,
dest = (u8 *)mcast_tracker + sizeof(*mcast_tracker);
/* check if full tracker tvlv is within skb length */
/* check if full tracker tvlv, including padding, is within skb length */
tvlv_len = sizeof(*mcast_tracker) + ETH_ALEN * num_dests;
if (!(num_dests % 2))
tvlv_len += 2;
if (tvlv_len > skb_network_header_len(skb))
return -EINVAL;

View File

@ -221,7 +221,7 @@ static void batadv_tp_batctl_notify(enum batadv_tp_meter_reason reason,
unsigned long start_time, u64 total_sent,
u32 cookie)
{
u32 total_bytes;
u64 total_bytes;
u32 test_time;
u8 result;

View File

@ -26,8 +26,10 @@
#include <linux/jhash.h>
#include <linux/jiffies.h>
#include <linux/kref.h>
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/lockdep.h>
#include <linux/minmax.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
@ -253,7 +255,8 @@ static int batadv_tt_len(int changes_num)
*
* Return: local translation table size in bytes.
*/
static int batadv_tt_local_transmit_size(u16 num_vlan, u16 num_entries)
static int batadv_tt_local_transmit_size(unsigned int num_vlan,
unsigned int num_entries)
{
int hdr_size;
@ -266,6 +269,25 @@ static int batadv_tt_local_transmit_size(u16 num_vlan, u16 num_entries)
return hdr_size + batadv_tt_len(num_entries);
}
/**
* batadv_tt_local_transmit_size_max() - get the maximum size of a full local table
* response
* @bat_priv: the bat priv with all the mesh interface information
*
* The full table response is sent as a single unicast TVLV packet. Its
* tvlv_len, which covers the TVLV header and the TT TVLV, is only 16 bit wide.
* This limits the response size even when packet_size_max is larger.
*
* Return: maximum size of a full local table response in bytes
*/
static int batadv_tt_local_transmit_size_max(struct batadv_priv *bat_priv)
{
int tvlv_size_max = sizeof(struct batadv_unicast_tvlv_packet) + U16_MAX;
int packet_size_max = READ_ONCE(bat_priv->packet_size_max);
return min(packet_size_max, tvlv_size_max);
}
/**
* batadv_tt_local_reserve() - reserve room in the transmittable local table
* @bat_priv: the bat priv with all the mesh interface information
@ -290,22 +312,23 @@ static int batadv_tt_local_transmit_size(u16 num_vlan, u16 num_entries)
static bool batadv_tt_local_reserve(struct batadv_priv *bat_priv, u16 num_vlan,
u16 num_entries, int *table_size)
{
int packet_size_max = READ_ONCE(bat_priv->packet_size_max);
int size_max = batadv_tt_local_transmit_size_max(bat_priv);
unsigned int entries;
unsigned int vlans;
scoped_guard(spinlock_bh, &bat_priv->tt.reserve_lock) {
bat_priv->tt.reserved_vlans += num_vlan;
bat_priv->tt.reserved_entries += num_entries;
vlans = bat_priv->tt.reserved_vlans + num_vlan;
entries = bat_priv->tt.reserved_entries + num_entries;
*table_size = batadv_tt_local_transmit_size(bat_priv->tt.reserved_vlans,
bat_priv->tt.reserved_entries);
if (*table_size <= packet_size_max)
return true;
*table_size = batadv_tt_local_transmit_size(vlans, entries);
if (*table_size > size_max)
return false;
bat_priv->tt.reserved_vlans -= num_vlan;
bat_priv->tt.reserved_entries -= num_entries;
bat_priv->tt.reserved_vlans = vlans;
bat_priv->tt.reserved_entries = entries;
}
return false;
return true;
}
/**
@ -339,9 +362,10 @@ static bool batadv_tt_local_reserve_entry(struct batadv_priv *bat_priv,
return true;
net_ratelimited_function(batadv_info, bat_priv->mesh_iface,
"Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
"Local translation table size (%i) exceeds maximum table response size (%i); Ignoring new local tt entry: %pM\n",
table_size,
READ_ONCE(bat_priv->packet_size_max), addr);
batadv_tt_local_transmit_size_max(bat_priv),
addr);
return false;
}
@ -374,8 +398,9 @@ bool batadv_tt_local_reserve_vlan(struct batadv_priv *bat_priv,
return true;
net_ratelimited_function(batadv_info, bat_priv->mesh_iface,
"Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new VLAN: %d\n",
table_size, READ_ONCE(bat_priv->packet_size_max),
"Local translation table size (%i) exceeds maximum table response size (%i); Ignoring new VLAN: %d\n",
table_size,
batadv_tt_local_transmit_size_max(bat_priv),
batadv_print_vid(vid));
return false;
@ -622,6 +647,9 @@ static u16 batadv_tt_flags_get(struct batadv_tt_common_entry *common)
* @bat_priv: the bat priv with all the mesh interface information
* @common: the TT entry involved in the event
* @flags: flags of the TT entry combined with the event flags
*
* Only a single change per client is queued. It describes the latest state of
* the client and a new event therefore replaces an already queued one.
*/
static void __batadv_tt_local_event(struct batadv_priv *bat_priv,
const struct batadv_tt_common_entry *common,
@ -631,7 +659,6 @@ static void __batadv_tt_local_event(struct batadv_priv *bat_priv,
struct batadv_tt_change_node *entry;
struct batadv_tt_change_node *safe;
bool del_op_requested;
bool del_op_entry;
size_t changes;
tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC);
@ -643,9 +670,17 @@ static void __batadv_tt_local_event(struct batadv_priv *bat_priv,
ether_addr_copy(tt_change_node->change.addr, common->addr);
tt_change_node->change.vid = htons(common->vid);
tt_change_node->change.flags = flags;
del_op_requested = flags & BATADV_TT_CLIENT_DEL;
/* the ROAM flag is only meaningful for the receiver in combination
* with a DEL. An ADD with ROAM would be interpreted as a roaming
* advertisement
*/
if (!del_op_requested)
flags &= ~BATADV_TT_CLIENT_ROAM;
tt_change_node->change.flags = flags;
/* check for ADD+DEL, DEL+ADD, ADD+ADD or DEL+DEL events */
spin_lock_bh(&bat_priv->tt.changes_list_lock);
changes = READ_ONCE(bat_priv->tt.local_changes);
@ -657,25 +692,12 @@ static void __batadv_tt_local_event(struct batadv_priv *bat_priv,
if (entry->change.vid != tt_change_node->change.vid)
continue;
del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL;
if (del_op_requested != del_op_entry) {
/* DEL+ADD in the same orig interval have no effect and
* can be removed to avoid silly behaviour on the
* receiver side. The other way around (ADD+DEL) can
* happen in case of roaming of a client still in the
* NEW state. Roaming of NEW clients is now possible due
* to automatically recognition of "temporary" clients
*/
list_del(&entry->list);
kmem_cache_free(batadv_tt_change_cache, entry);
changes--;
} else {
/* this is a second add or del in the same originator
* interval. It could mean that flags have been changed
* (e.g. double add): update them
*/
entry->change.flags = flags;
}
/* the other nodes may know the client with different
* flags. A DEL+ADD must therefore still announce the
* current flags and an ADD+DEL must still remove the
* client. ADD+ADD and DEL+DEL only update the flags
*/
entry->change.flags = flags;
kmem_cache_free(batadv_tt_change_cache, tt_change_node);
goto update_changes;
@ -727,9 +749,9 @@ static u16 batadv_tt_entries(u16 tt_len)
*/
static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
{
unsigned int tt_local_entries = 0;
struct batadv_meshif_vlan *vlan;
u16 tt_local_entries = 0;
u16 num_vlan = 0;
unsigned int num_vlan = 0;
rcu_read_lock();
hlist_for_each_entry_rcu(vlan, &bat_priv->meshif_vlan_list, list) {
@ -811,14 +833,21 @@ static void batadv_tt_local_add_roam(struct batadv_priv *bat_priv,
if (!tt_global)
return;
/* Check whether it is a roaming, but don't do anything if the roaming
* process has already been handled
/* Handle newly roamed client - but not roamed back client.
*
* A client which roamed back must always be reclaimed from the
* originator(s) which sent the ROAMING_ADV. The global entry created by
* this ROAMING_ADV might still carry BATADV_TT_CLIENT_ROAM because the
* new originator did not yet announce the client.
*/
scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
if (tt_global->common.flags & BATADV_TT_CLIENT_ROAM)
return;
if (!roamed_back) {
scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
/* Check whether it is a roaming, but don't do anything
* if the roaming process has already been handled.
*/
if (tt_global->common.flags & BATADV_TT_CLIENT_ROAM)
return;
if (!roamed_back) {
/* The global entry has to be marked as ROAMING and has to be
* kept for consistency purpose.
*
@ -886,6 +915,7 @@ static bool batadv_tt_local_add_existing(struct batadv_priv *bat_priv,
bool *roamed_back)
{
struct batadv_tt_common_entry *common = &tt_local->common;
bool readded = false;
tt_local->last_seen = jiffies;
@ -900,8 +930,7 @@ static bool batadv_tt_local_add_existing(struct batadv_priv *bat_priv,
* flag can be reset like it was never enqueued
*/
common->flags &= ~BATADV_TT_CLIENT_PENDING;
return true;
readded = true;
}
if (common->flags & BATADV_TT_CLIENT_ROAM) {
@ -918,7 +947,7 @@ static bool batadv_tt_local_add_existing(struct batadv_priv *bat_priv,
}
}
return false;
return readded;
}
/**
@ -1319,22 +1348,24 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
* batadv_tt_tvlv_container_update() - update the translation table tvlv
* container after local tt changes have been committed
* @bat_priv: the bat priv with all the mesh interface information
* @changes_list: list of committed changes which will be consumed
* @tt_diff_entries_num: number of entries in @changes_list
*/
static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv,
struct list_head *changes_list,
int tt_diff_entries_num)
{
struct batadv_tvlv_tt_change *tt_change;
struct batadv_tt_change_node *entry;
struct batadv_tvlv_tt_data *tt_data;
struct batadv_tt_change_node *safe;
int tt_diff_entries_count = 0;
int tt_diff_entries_num = 0;
bool drop_changes = false;
size_t tt_extra_len = 0;
int tt_change_len = 0;
int tt_diff_len;
u16 tvlv_len;
tt_diff_entries_num = READ_ONCE(bat_priv->tt.local_changes);
tt_diff_len = batadv_tt_len(tt_diff_entries_num);
/* if we have too many changes for one packet don't send any
@ -1352,19 +1383,39 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
&tt_change, &tt_diff_len);
if (!tvlv_len)
if (!tvlv_len) {
/* the changes are lost and the other nodes have to request the
* full table. Don't answer TT requests for the new TTVN with
* the stale changeset of the previous TTVN. Without changes, the
* TTVN was not incremented and the last changeset is still valid
*/
if (drop_changes || tt_diff_entries_num > 0) {
list_for_each_entry_safe(entry, safe, changes_list,
list) {
list_del(&entry->list);
kmem_cache_free(batadv_tt_change_cache, entry);
}
spin_lock_bh(&bat_priv->tt.last_changeset_lock);
kfree(bat_priv->tt.last_changeset);
bat_priv->tt.last_changeset = NULL;
bat_priv->tt.last_changeset_len = 0;
spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
}
/* announce the already committed TTVN in the next OGM interval
* instead of waiting for BATADV_TT_OGM_APPEND_MAX idle rounds
*/
atomic_set(&bat_priv->tt.ogm_append_cnt, 0);
return;
}
tt_data->flags = BATADV_TT_OGM_DIFF;
if (!drop_changes && tt_diff_len == 0)
goto container_register;
spin_lock_bh(&bat_priv->tt.changes_list_lock);
WRITE_ONCE(bat_priv->tt.local_changes, 0);
list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
list) {
list_for_each_entry_safe(entry, safe, changes_list, list) {
if (tt_diff_entries_count < tt_diff_entries_num) {
memcpy(tt_change + tt_diff_entries_count,
&entry->change,
@ -1374,7 +1425,6 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
list_del(&entry->list);
kmem_cache_free(batadv_tt_change_cache, entry);
}
spin_unlock_bh(&bat_priv->tt.changes_list_lock);
tt_extra_len = batadv_tt_len(tt_diff_entries_num -
tt_diff_entries_count);
@ -3342,8 +3392,12 @@ static bool batadv_tt_local_valid(void *entry_ptr,
if (tt_flags & BATADV_TT_CLIENT_NEW)
return false;
/* the entry is (still) announced. A ROAM flag of an entry which is
* pending to be removed must not be transmitted. Otherwise, the
* receiver would handle it like a roaming advertisement
*/
if (flags)
*flags = tt_flags;
*flags = tt_flags & ~BATADV_TT_CLIENT_ROAM;
return true;
}
@ -3922,21 +3976,30 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
u16 tt_num_changes, u8 ttvn)
{
int roams;
u8 flags;
int i;
for (i = 0; i < tt_num_changes; i++) {
if ((tt_change + i)->flags & BATADV_TT_CLIENT_DEL) {
roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
flags = (tt_change + i)->flags;
if (flags & BATADV_TT_CLIENT_DEL) {
roams = flags & BATADV_TT_CLIENT_ROAM;
batadv_tt_global_del(bat_priv, orig_node,
(tt_change + i)->addr,
ntohs((tt_change + i)->vid),
"tt removed by changes",
roams);
} else {
/* an announced client cannot have roamed away from
* orig_node. Only a ROAMING_ADV is allowed to add a
* global entry with the ROAM flag
*/
flags &= ~BATADV_TT_CLIENT_ROAM;
if (!batadv_tt_global_add(bat_priv, orig_node,
(tt_change + i)->addr,
ntohs((tt_change + i)->vid),
(tt_change + i)->flags, ttvn))
flags, ttvn))
/* In case of problem while storing a
* global_entry, we stop the updating
* procedure without committing the
@ -4412,11 +4475,25 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
*/
static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
{
LIST_HEAD(changes_list);
int changes_num;
lockdep_assert_held(&bat_priv->tt.commit_lock);
if (READ_ONCE(bat_priv->tt.local_changes) == 0) {
/* atomically get the list of changes. The TTVN decision and the
* announced changeset must cover the same events. Events queued
* afterwards stay in the tt.changes_list for the next TT round
*/
spin_lock_bh(&bat_priv->tt.changes_list_lock);
list_splice_init(&bat_priv->tt.changes_list, &changes_list);
changes_num = READ_ONCE(bat_priv->tt.local_changes);
WRITE_ONCE(bat_priv->tt.local_changes, 0);
spin_unlock_bh(&bat_priv->tt.changes_list_lock);
if (changes_num == 0) {
if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
batadv_tt_tvlv_container_update(bat_priv);
batadv_tt_tvlv_container_update(bat_priv, &changes_list,
changes_num);
return;
}
@ -4433,7 +4510,7 @@ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
/* reset the sending counter */
atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX);
batadv_tt_tvlv_container_update(bat_priv);
batadv_tt_tvlv_container_update(bat_priv, &changes_list, changes_num);
}
/**
@ -4675,16 +4752,16 @@ void batadv_tt_local_resize_to_mtu(struct net_device *mesh_iface)
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
int timeout = BATADV_TT_LOCAL_TIMEOUT / 2;
bool reduced = false;
int packet_size_max;
int table_size;
int size_max;
packet_size_max = READ_ONCE(bat_priv->packet_size_max);
size_max = batadv_tt_local_transmit_size_max(bat_priv);
spin_lock_bh(&bat_priv->tt.commit_lock);
while (timeout) {
table_size = batadv_tt_local_table_transmit_size(bat_priv);
if (packet_size_max >= table_size)
if (size_max >= table_size)
break;
batadv_tt_local_purge(bat_priv, timeout);
@ -4693,8 +4770,8 @@ void batadv_tt_local_resize_to_mtu(struct net_device *mesh_iface)
timeout /= 2;
reduced = true;
net_ratelimited_function(batadv_info, mesh_iface,
"Forced to purge local tt entries to fit new maximum fragment MTU (%i)\n",
packet_size_max);
"Forced to purge local tt entries to fit new maximum table response size (%i)\n",
size_max);
}
/* commit these changes immediately, to avoid synchronization problem

View File

@ -2047,7 +2047,13 @@ struct batadv_forw_packet {
/** @direct_link_flags: direct link flags for aggregated OGM packets */
DECLARE_BITMAP(direct_link_flags, BATADV_MAX_AGGREGATION_PACKETS);
/** @num_packets: counter for aggregated OGMv1 packets */
/**
* @num_packets: counter for aggregated OGMv1 packets. Set to
* BATADV_MAX_AGGREGATION_PACKETS (independent of the real number of
* aggregated packets) by the send worker to prevent further
* aggregation while the packet is emitted. It must therefore not be
* used to iterate over the aggregated packets
*/
u8 num_packets;
/** @delayed_work: work queue callback item for packet sending */

View File

@ -138,10 +138,10 @@ static void hci_conn_cleanup(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags))
if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, conn->flags))
hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);
if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, conn->flags))
hci_remove_link_key(hdev, &conn->dst);
hci_chan_list_flush(conn);
@ -685,7 +685,7 @@ static void hci_conn_idle(struct work_struct *work)
hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
}
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags)) {
struct hci_cp_sniff_mode cp;
cp.handle = cpu_to_le16(conn->handle);
cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
@ -814,7 +814,7 @@ static int hci_le_terminate_big(struct hci_dev *hdev, struct hci_conn *conn)
d->big = conn->iso_qos.bcast.big;
d->bis = conn->iso_qos.bcast.bis;
d->big_term = test_and_clear_bit(HCI_CONN_BIG_CREATED, &conn->flags);
d->big_term = test_and_clear_bit(HCI_CONN_BIG_CREATED, conn->flags);
ret = hci_cmd_sync_queue(hdev, terminate_big_sync, d,
terminate_big_destroy);
@ -867,7 +867,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn)
d->sync_handle = conn->sync_handle;
if (conn->type == PA_LINK &&
test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
test_and_clear_bit(HCI_CONN_PA_SYNC, conn->flags)) {
hci_conn_hash_list_flag(hdev, find_bis, PA_LINK,
HCI_CONN_PA_SYNC, d);
@ -877,7 +877,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn)
d->count = 0;
}
if (test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags)) {
if (test_and_clear_bit(HCI_CONN_BIG_SYNC, conn->flags)) {
hci_conn_hash_list_flag(hdev, find_bis, BIS_LINK,
HCI_CONN_BIG_SYNC, d);
@ -912,7 +912,7 @@ static void bis_cleanup(struct hci_conn *conn)
bt_dev_dbg(hdev, "conn %p", conn);
if (conn->role == HCI_ROLE_MASTER) {
if (!test_and_clear_bit(HCI_CONN_PER_ADV, &conn->flags))
if (!test_and_clear_bit(HCI_CONN_PER_ADV, conn->flags))
return;
/* Check if ISO connection is a BIS and terminate advertising
@ -1087,7 +1087,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,
conn->sync_handle = HCI_SYNC_HANDLE_INVALID;
conn->sid = HCI_SID_INVALID;
set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
set_bit(HCI_CONN_POWER_SAVE, conn->flags);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
/* Set Default Authenticated payload timeout to 30s */
@ -1217,8 +1217,8 @@ static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
case BIS_LINK:
case PA_LINK:
if ((conn->state != BT_CONNECTED &&
!test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ||
test_bit(HCI_CONN_BIG_CREATED, &conn->flags))
!test_bit(HCI_CONN_CREATE_CIS, conn->flags)) ||
test_bit(HCI_CONN_BIG_CREATED, conn->flags))
hci_conn_failed(conn, reason);
break;
}
@ -1234,8 +1234,8 @@ static void hci_conn_unlink(struct hci_conn *conn)
struct hci_link *link, *t;
conn->sec_level = BT_SECURITY_SDP;
clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
clear_bit(HCI_CONN_AES_CCM, &conn->flags);
clear_bit(HCI_CONN_ENCRYPT, conn->flags);
clear_bit(HCI_CONN_AES_CCM, conn->flags);
/* mgmt_security_level_changed() reports the reset only if
* this connection was actually reported to userspace as
* connected (it checks HCI_CONN_MGMT_CONNECTED itself), so it
@ -1254,7 +1254,7 @@ static void hci_conn_unlink(struct hci_conn *conn)
*/
if (test_bit(HCI_UP, &hdev->flags))
mgmt_security_level_changed(conn);
clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
clear_bit(HCI_CONN_MGMT_CONNECTED, conn->flags);
list_for_each_entry_safe(link, t, &conn->link_list, list) {
struct hci_conn *child = link->conn;
@ -1458,8 +1458,8 @@ void hci_conn_failed(struct hci_conn *conn, u8 status)
/* In case of BIG/PA sync failed, clear conn flags so that
* the conns will be correctly cleaned up by ISO layer
*/
test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags);
test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, &conn->flags);
test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, conn->flags);
test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, conn->flags);
conn->state = BT_CLOSED;
hci_connect_cfm(conn, status);
@ -1524,9 +1524,8 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
* to connect.
*/
conn = hci_conn_hash_lookup_le(hdev, dst, dst_type);
if (conn && !test_bit(HCI_CONN_SCANNING, &conn->flags)) {
if (conn && !test_bit(HCI_CONN_SCANNING, conn->flags))
return ERR_PTR(-EBUSY);
}
/* Check if the destination address has been resolved by the controller
* since if it did then the identity address shall be used.
@ -1614,8 +1613,9 @@ static int hci_explicit_conn_params_set(struct hci_dev *hdev,
if (!params)
return -ENOMEM;
/* If we created new params, mark them to be deleted in
* hci_connect_le_scan_cleanup. It's different case than
/* If we created new params, mark them to be deleted once the
* explicit connect is done, see le_conn_complete_evt() and
* hci_connect_le_scan_cleanup(). It's different case than
* existing disabled params, those will stay after cleanup.
*/
params->auto_connect = HCI_AUTO_CONN_EXPLICIT;
@ -1797,7 +1797,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
}
conn->state = BT_CONNECT;
set_bit(HCI_CONN_SCANNING, &conn->flags);
set_bit(HCI_CONN_SCANNING, conn->flags);
conn->sec_level = BT_SECURITY_LOW;
conn->pending_sec_level = sec_level;
conn->conn_timeout = conn_timeout;
@ -1923,12 +1923,12 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
if (acl->state == BT_CONNECTED &&
(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
set_bit(HCI_CONN_POWER_SAVE, acl->flags);
hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON);
if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) {
if (test_bit(HCI_CONN_MODE_CHANGE_PEND, acl->flags)) {
/* defer SCO setup until mode change completed */
set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags);
set_bit(HCI_CONN_SCO_SETUP_PEND, acl->flags);
return sco;
}
@ -2220,7 +2220,7 @@ int hci_le_create_cis_pending(struct hci_dev *hdev)
rcu_read_lock();
list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) {
if (test_bit(HCI_CONN_CREATE_CIS, conn->flags)) {
rcu_read_unlock();
return -EBUSY;
}
@ -2448,7 +2448,7 @@ static void bis_mark_per_adv(struct hci_conn *conn, void *data)
d->bis != conn->iso_qos.bcast.bis)
return;
set_bit(HCI_CONN_PER_ADV, &conn->flags);
set_bit(HCI_CONN_PER_ADV, conn->flags);
}
struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
@ -2568,7 +2568,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
*/
if (hci_dev_test_flag(conn->hdev, HCI_SC_ONLY)) {
if (!hci_conn_sc_enabled(conn) ||
!test_bit(HCI_CONN_AES_CCM, &conn->flags) ||
!test_bit(HCI_CONN_AES_CCM, conn->flags) ||
conn->key_type != HCI_LK_AUTH_COMBINATION_P256)
return 0;
}
@ -2584,14 +2584,14 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
* not shortened)
*/
if (conn->sec_level == BT_SECURITY_FIPS &&
!test_bit(HCI_CONN_AES_CCM, &conn->flags)) {
!test_bit(HCI_CONN_AES_CCM, conn->flags)) {
bt_dev_err(conn->hdev,
"Invalid security: Missing AES-CCM usage");
return 0;
}
if (hci_conn_ssp_enabled(conn) &&
!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
!test_bit(HCI_CONN_ENCRYPT, conn->flags))
return 0;
return 1;
@ -2607,7 +2607,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
if (sec_level > conn->sec_level)
conn->pending_sec_level = sec_level;
else if (test_bit(HCI_CONN_AUTH, &conn->flags))
else if (test_bit(HCI_CONN_AUTH, conn->flags))
return 1;
/* Make sure we preserve an existing MITM requirement*/
@ -2615,7 +2615,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
conn->auth_type = auth_type;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, conn->flags)) {
struct hci_cp_auth_requested cp;
cp.handle = cpu_to_le16(conn->handle);
@ -2625,8 +2625,8 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
/* Set the ENCRYPT_PEND to trigger encryption after
* authentication.
*/
if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
if (!test_bit(HCI_CONN_ENCRYPT, conn->flags))
set_bit(HCI_CONN_ENCRYPT_PEND, conn->flags);
}
return 0;
@ -2637,7 +2637,7 @@ static void hci_conn_encrypt(struct hci_conn *conn)
{
BT_DBG("hcon %p", conn);
if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 0x01;
@ -2665,7 +2665,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type,
return 1;
/* For other security levels we need the link key. */
if (!test_bit(HCI_CONN_AUTH, &conn->flags))
if (!test_bit(HCI_CONN_AUTH, conn->flags))
goto auth;
switch (conn->key_type) {
@ -2705,17 +2705,17 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type,
}
auth:
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
if (test_bit(HCI_CONN_ENCRYPT_PEND, conn->flags))
return 0;
if (initiator)
set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags);
set_bit(HCI_CONN_AUTH_INITIATOR, conn->flags);
if (!hci_conn_auth(conn, sec_level, auth_type))
return 0;
encrypt:
if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) {
if (test_bit(HCI_CONN_ENCRYPT, conn->flags)) {
/* Ensure that the encryption key size has been read,
* otherwise stall the upper layer responses.
*/
@ -2758,7 +2758,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
if (role == conn->role)
return 1;
if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) {
if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, conn->flags)) {
struct hci_cp_switch_role cp;
bacpy(&cp.bdaddr, &conn->dst);
cp.role = role;
@ -2779,10 +2779,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
if (conn->mode != HCI_CM_SNIFF)
goto timer;
if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active)
if (!test_bit(HCI_CONN_POWER_SAVE, conn->flags) && !force_active)
goto timer;
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags)) {
struct hci_cp_exit_sniff_mode cp;
cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
@ -2822,16 +2822,16 @@ static u32 get_link_mode(struct hci_conn *conn)
if (conn->role == HCI_ROLE_MASTER)
link_mode |= HCI_LM_MASTER;
if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
if (test_bit(HCI_CONN_ENCRYPT, conn->flags))
link_mode |= HCI_LM_ENCRYPT;
if (test_bit(HCI_CONN_AUTH, &conn->flags))
if (test_bit(HCI_CONN_AUTH, conn->flags))
link_mode |= HCI_LM_AUTH;
if (test_bit(HCI_CONN_SECURE, &conn->flags))
if (test_bit(HCI_CONN_SECURE, conn->flags))
link_mode |= HCI_LM_SECURE;
if (test_bit(HCI_CONN_FIPS, &conn->flags))
if (test_bit(HCI_CONN_FIPS, conn->flags))
link_mode |= HCI_LM_FIPS;
return link_mode;
@ -2945,7 +2945,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
BT_DBG("%s hcon %p", hdev->name, conn);
if (test_bit(HCI_CONN_DROP, &conn->flags)) {
if (test_bit(HCI_CONN_DROP, conn->flags)) {
BT_DBG("Refusing to create new hci_chan");
return NULL;
}
@ -2975,7 +2975,7 @@ void hci_chan_del(struct hci_chan *chan)
synchronize_rcu();
/* Prevent new hci_chan's to be created for this hci_conn */
set_bit(HCI_CONN_DROP, &conn->flags);
set_bit(HCI_CONN_DROP, conn->flags);
hci_conn_put(conn);

View File

@ -1075,17 +1075,16 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
rcu_read_lock();
list_for_each_entry_rcu(k, &hdev->link_keys, list) {
if (bacmp(bdaddr, &k->bdaddr) == 0) {
rcu_read_unlock();
if (hci_is_blocked_key(hdev,
HCI_BLOCKED_KEY_TYPE_LINKKEY,
k->val)) {
bt_dev_warn_ratelimited(hdev,
"Link key blocked for %pMR",
&k->bdaddr);
return NULL;
k = NULL;
}
rcu_read_unlock();
return k;
}
}
@ -1252,7 +1251,6 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,
key = kzalloc_obj(*key);
if (!key)
return NULL;
list_add_rcu(&key->list, &hdev->link_keys);
}
BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type);
@ -1276,6 +1274,9 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,
else
key->type = type;
if (!old_key)
list_add_rcu(&key->list, &hdev->link_keys);
if (persistent)
*persistent = hci_persistent_key(hdev, conn, type,
old_key_type);
@ -1297,7 +1298,6 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
key = kzalloc_obj(*key);
if (!key)
return NULL;
list_add_rcu(&key->list, &hdev->long_term_keys);
}
bacpy(&key->bdaddr, bdaddr);
@ -1309,15 +1309,19 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
key->enc_size = enc_size;
key->type = type;
if (!old_key)
list_add_rcu(&key->list, &hdev->long_term_keys);
return key;
}
struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 addr_type, u8 val[16], bdaddr_t *rpa)
{
struct smp_irk *irk;
struct smp_irk *irk, *old_irk;
irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type);
old_irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type);
irk = old_irk;
if (!irk) {
irk = kzalloc_obj(*irk);
if (!irk)
@ -1326,12 +1330,14 @@ struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr,
bacpy(&irk->bdaddr, bdaddr);
irk->addr_type = addr_type;
list_add_rcu(&irk->list, &hdev->identity_resolving_keys);
}
memcpy(irk->val, val, 16);
bacpy(&irk->rpa, rpa);
if (!old_irk)
list_add_rcu(&irk->list, &hdev->identity_resolving_keys);
return irk;
}
@ -1694,6 +1700,9 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
if (!adv)
return ERR_PTR(-ENOMEM);
INIT_DELAYED_WORK(&adv->rpa_expired_cb,
adv_instance_rpa_expired);
adv->pending = true;
adv->instance = instance;
@ -1730,8 +1739,6 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
else
adv->duration = duration;
INIT_DELAYED_WORK(&adv->rpa_expired_cb, adv_instance_rpa_expired);
BT_DBG("%s for %dMR", hdev->name, instance);
return adv;
@ -2897,8 +2904,14 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
u8 dev_pkt_type;
/* Pairs with synchronize_rcu() in hci_dev_close_sync(), so rx_work is
* not queued once the workqueue is being drained.
*/
rcu_read_lock();
if (!hdev || (!test_bit(HCI_UP, &hdev->flags)
&& !test_bit(HCI_INIT, &hdev->flags))) {
rcu_read_unlock();
kfree_skb(skb);
return -ENXIO;
}
@ -2934,6 +2947,7 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
case HCI_DRV_PKT:
break;
default:
rcu_read_unlock();
kfree_skb(skb);
return -EINVAL;
}
@ -2947,6 +2961,8 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
skb_queue_tail(&hdev->rx_q, skb);
queue_work(hdev->workqueue, &hdev->rx_work);
rcu_read_unlock();
return 0;
}
EXPORT_SYMBOL(hci_recv_frame);
@ -3159,7 +3175,8 @@ int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,
EXPORT_SYMBOL(__hci_cmd_send);
/* Get data from the previously sent command */
static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode)
static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode,
size_t *len)
{
struct hci_command_hdr *hdr;
@ -3171,21 +3188,30 @@ static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode)
if (hdr->opcode != cpu_to_le16(opcode))
return NULL;
if (len)
*len = skb->len - HCI_COMMAND_HDR_SIZE;
return skb->data + HCI_COMMAND_HDR_SIZE;
}
/* Get data from the previously sent command */
void *hci_sent_cmd_data_len(struct hci_dev *hdev, __u16 opcode, size_t *len)
{
void *data;
/* Check if opcode matches last sent command */
data = hci_cmd_data(hdev->sent_cmd, opcode, len);
if (!data)
/* Check if opcode matches last request */
data = hci_cmd_data(hdev->req_skb, opcode, len);
return data;
}
/* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
{
void *data;
/* Check if opcode matches last sent command */
data = hci_cmd_data(hdev->sent_cmd, opcode);
if (!data)
/* Check if opcode matches last request */
data = hci_cmd_data(hdev->req_skb, opcode);
return data;
return hci_sent_cmd_data_len(hdev, opcode, NULL);
}
/* Get data from last received event */

View File

@ -724,6 +724,8 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
goto done;
}
clear_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->flags);
/* While unexpected, the read_enc_key_size command may fail. The most
* secure approach is to then assume the key size is 0 to force a
* disconnection.
@ -732,8 +734,8 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
bt_dev_err(hdev, "failed to read key size for handle %u",
handle);
conn->enc_key_size = 0;
clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
clear_bit(HCI_CONN_AES_CCM, &conn->flags);
clear_bit(HCI_CONN_ENCRYPT, conn->flags);
clear_bit(HCI_CONN_AES_CCM, conn->flags);
/* Downgrade to reflect the connection no longer being
* encrypted, instead of advertising a stale elevated
* security level alongside MGMT_CONN_SEC_ENCRYPT_NONE.
@ -761,8 +763,8 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
* state at a later time.
*/
status = HCI_ERROR_AUTH_FAILURE;
clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
clear_bit(HCI_CONN_AES_CCM, &conn->flags);
clear_bit(HCI_CONN_ENCRYPT, conn->flags);
clear_bit(HCI_CONN_AES_CCM, conn->flags);
/* Downgrade to reflect the connection no longer being
* encrypted, instead of advertising a stale elevated
* security level alongside MGMT_CONN_SEC_ENCRYPT_NONE.
@ -1817,6 +1819,8 @@ static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
{
bool timeout_pending;
hci_dev_lock(hdev);
switch (enable) {
@ -1846,10 +1850,18 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
/* Cancel this timer so that we don't try to disable scanning
* when it's already disabled.
*/
cancel_delayed_work(&hdev->le_scan_disable);
timeout_pending = cancel_delayed_work(&hdev->le_scan_disable);
hci_dev_clear_flag(hdev, HCI_LE_SCAN);
/* The scan of a discovery was disabled before its timeout,
* for example by a Stop Discovery that timed out and still
* completed, so nothing else would end the discovery.
*/
if (timeout_pending &&
hdev->discovery.state == DISCOVERY_FINDING)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
hci_test_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY) &&
!test_bit(HCI_INQUIRY, &hdev->flags) &&
@ -2595,10 +2607,10 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
if (!hci_outgoing_auth_needed(hdev, conn))
goto unlock;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, conn->flags)) {
struct hci_cp_auth_requested auth_cp;
set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags);
set_bit(HCI_CONN_AUTH_INITIATOR, conn->flags);
auth_cp.handle = __cpu_to_le16(conn->handle);
hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
@ -2738,9 +2750,9 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
if (conn) {
clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
clear_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags);
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, conn->flags))
hci_sco_setup(conn, status);
}
@ -2765,9 +2777,9 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
if (conn) {
clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags);
clear_bit(HCI_CONN_MODE_CHANGE_PEND, conn->flags);
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, conn->flags))
hci_sco_setup(conn, status);
}
@ -2824,10 +2836,10 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
* still needs it set to know whether to report the security level
* reset, so it is consumed there instead of here.
*/
mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags);
if (conn->type == ACL_LINK) {
if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, conn->flags))
hci_remove_link_key(hdev, &conn->dst);
}
@ -3078,7 +3090,7 @@ static void hci_cs_switch_role(struct hci_dev *hdev, u8 status)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
if (conn)
clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags);
clear_bit(HCI_CONN_RSWITCH_PEND, conn->flags);
hci_dev_unlock(hdev);
}
@ -3190,6 +3202,7 @@ static int hci_read_enc_key_size(struct hci_dev *hdev, struct hci_conn *conn)
{
struct hci_cp_read_enc_key_size cp;
u8 *key_enc_size = hci_conn_key_enc_size(conn);
int err;
if (!read_key_size_capable(hdev)) {
conn->enc_key_size = HCI_LINK_KEY_SIZE;
@ -3211,7 +3224,14 @@ static int hci_read_enc_key_size(struct hci_dev *hdev, struct hci_conn *conn)
else
conn->enc_key_size = hdev->min_enc_key_size;
return hci_send_cmd(hdev, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp);
/* L2CAP holds incoming data back until the key size is known */
set_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->flags);
err = hci_send_cmd(hdev, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp);
if (err)
clear_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->flags);
return err;
}
static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
@ -3309,19 +3329,19 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
hci_conn_add_sysfs(conn);
if (test_bit(HCI_AUTH, &hdev->flags))
set_bit(HCI_CONN_AUTH, &conn->flags);
set_bit(HCI_CONN_AUTH, conn->flags);
if (test_bit(HCI_ENCRYPT, &hdev->flags))
set_bit(HCI_CONN_ENCRYPT, &conn->flags);
set_bit(HCI_CONN_ENCRYPT, conn->flags);
/* "Link key request" completed ahead of "connect request" completes */
if (ev->encr_mode == 1 && !test_bit(HCI_CONN_ENCRYPT, &conn->flags) &&
if (ev->encr_mode == 1 && !test_bit(HCI_CONN_ENCRYPT, conn->flags) &&
ev->link_type == ACL_LINK) {
struct link_key *key;
key = hci_find_link_key(hdev, &ev->bdaddr);
if (key) {
set_bit(HCI_CONN_ENCRYPT, &conn->flags);
set_bit(HCI_CONN_ENCRYPT, conn->flags);
hci_read_enc_key_size(hdev, conn);
hci_encrypt_cfm(conn, ev->status);
}
@ -3525,9 +3545,9 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data,
* still needs it set to know whether to report the security level
* reset, so it is consumed there instead of here.
*/
mgmt_connected = test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
mgmt_connected = test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags);
if (test_bit(HCI_CONN_AUTH_FAILURE, &conn->flags))
if (test_bit(HCI_CONN_AUTH_FAILURE, conn->flags))
reason = MGMT_DEV_DISCONN_AUTH_FAILURE;
else
reason = hci_to_mgmt_reason(ev->reason);
@ -3536,7 +3556,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data,
reason, mgmt_connected);
if (conn->type == ACL_LINK) {
if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, conn->flags))
hci_remove_link_key(hdev, &conn->dst);
hci_update_scan(hdev);
@ -3607,8 +3627,8 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data,
goto unlock;
if (!ev->status) {
clear_bit(HCI_CONN_AUTH_FAILURE, &conn->flags);
set_bit(HCI_CONN_AUTH, &conn->flags);
clear_bit(HCI_CONN_AUTH_FAILURE, conn->flags);
set_bit(HCI_CONN_AUTH, conn->flags);
/* Authentication alone does not imply encryption: for SSP
* capable devices, encryption is only requested below, and
* for legacy devices it is requested by a separate
@ -3621,12 +3641,12 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data,
conn->sec_level = conn->pending_sec_level;
} else {
if (ev->status == HCI_ERROR_PIN_OR_KEY_MISSING)
set_bit(HCI_CONN_AUTH_FAILURE, &conn->flags);
set_bit(HCI_CONN_AUTH_FAILURE, conn->flags);
mgmt_auth_failed(conn, ev->status);
}
clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
clear_bit(HCI_CONN_AUTH_PEND, conn->flags);
if (conn->state == BT_CONFIG) {
if (!ev->status && hci_conn_ssp_enabled(conn)) {
@ -3648,7 +3668,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data,
hci_conn_drop(conn);
}
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
if (test_bit(HCI_CONN_ENCRYPT_PEND, conn->flags)) {
if (!ev->status) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = ev->handle;
@ -3656,7 +3676,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data,
hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp),
&cp);
} else {
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
clear_bit(HCI_CONN_ENCRYPT_PEND, conn->flags);
hci_encrypt_cfm(conn, ev->status);
}
}
@ -3693,10 +3713,10 @@ static void hci_remote_name_evt(struct hci_dev *hdev, void *data,
if (!hci_outgoing_auth_needed(hdev, conn))
goto unlock;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, conn->flags)) {
struct hci_cp_auth_requested cp;
set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags);
set_bit(HCI_CONN_AUTH_INITIATOR, conn->flags);
cp.handle = __cpu_to_le16(conn->handle);
hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
@ -3723,17 +3743,17 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
if (!ev->status) {
if (ev->encrypt) {
/* Encryption implies authentication */
set_bit(HCI_CONN_AUTH, &conn->flags);
set_bit(HCI_CONN_ENCRYPT, &conn->flags);
set_bit(HCI_CONN_AUTH, conn->flags);
set_bit(HCI_CONN_ENCRYPT, conn->flags);
conn->sec_level = conn->pending_sec_level;
/* P-256 authentication key implies FIPS */
if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256)
set_bit(HCI_CONN_FIPS, &conn->flags);
set_bit(HCI_CONN_FIPS, conn->flags);
if ((conn->type == ACL_LINK && ev->encrypt == 0x02) ||
conn->type == LE_LINK)
set_bit(HCI_CONN_AES_CCM, &conn->flags);
set_bit(HCI_CONN_AES_CCM, conn->flags);
/* For ACL links the encryption key size is still
* validated below via hci_read_enc_key_size(). Its
@ -3745,8 +3765,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
if (conn->type != ACL_LINK)
mgmt_security_level_changed(conn);
} else {
clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
clear_bit(HCI_CONN_AES_CCM, &conn->flags);
clear_bit(HCI_CONN_ENCRYPT, conn->flags);
clear_bit(HCI_CONN_AES_CCM, conn->flags);
/* Elevated security levels (MEDIUM and above) require
* encryption, so downgrade to reflect the connection
* no longer being encrypted before reporting, instead
@ -3767,7 +3787,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
hci_adv_instances_set_rpa_expired(hdev, true);
}
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
clear_bit(HCI_CONN_ENCRYPT_PEND, conn->flags);
/* Check link security requirements are met */
if (!hci_conn_check_link_mode(conn))
@ -3775,7 +3795,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
if (ev->status && conn->state == BT_CONNECTED) {
if (ev->status == HCI_ERROR_PIN_OR_KEY_MISSING)
set_bit(HCI_CONN_AUTH_FAILURE, &conn->flags);
set_bit(HCI_CONN_AUTH_FAILURE, conn->flags);
/* Notify upper layers so they can cleanup before
* disconnecting.
@ -3813,8 +3833,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
* type can be either LE or ACL and controller must support LMP Ping.
* Ensure for AES-CCM encryption as well.
*/
if (test_bit(HCI_CONN_ENCRYPT, &conn->flags) &&
test_bit(HCI_CONN_AES_CCM, &conn->flags) &&
if (test_bit(HCI_CONN_ENCRYPT, conn->flags) &&
test_bit(HCI_CONN_AES_CCM, conn->flags) &&
((conn->type == ACL_LINK && lmp_ping_capable(hdev)) ||
(conn->type == LE_LINK && (hdev->le_features[0] & HCI_LE_PING)))) {
struct hci_cp_write_auth_payload_to cp;
@ -3846,9 +3866,9 @@ static void hci_change_link_key_complete_evt(struct hci_dev *hdev, void *data,
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
if (!ev->status)
set_bit(HCI_CONN_SECURE, &conn->flags);
set_bit(HCI_CONN_SECURE, conn->flags);
clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
clear_bit(HCI_CONN_AUTH_PEND, conn->flags);
hci_key_change_cfm(conn, ev->status);
}
@ -3975,13 +3995,16 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
struct hci_conn *conn;
u8 status = rp->status;
bool pending = false;
size_t len;
int i;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_CIG_PARAMS);
cp = hci_sent_cmd_data_len(hdev, HCI_OP_LE_SET_CIG_PARAMS, &len);
if (!rp->status &&
(!cp || rp->num_handles != cp->num_cis ||
(!cp || len < sizeof(*cp) ||
len < struct_size(cp, cis, cp->num_cis) ||
rp->num_handles != cp->num_cis ||
rp->cig_id != cp->cig_id ||
skb->len < array_size(rp->num_handles, sizeof(*rp->handle)))) {
bt_dev_err(hdev, "unexpected Set CIG Parameters response data");
@ -4074,7 +4097,7 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data,
hci_connect_cfm(conn, rp->status);
/* Notify device connected in case it is a BIG Sync */
if (!rp->status && test_bit(HCI_CONN_BIG_SYNC, &conn->flags))
if (!rp->status && test_bit(HCI_CONN_BIG_SYNC, conn->flags))
mgmt_device_connected(hdev, conn, NULL, 0);
break;
@ -4481,6 +4504,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status)
{
struct hci_cp_le_create_cis *cp;
bool pending = false;
size_t len;
int i;
bt_dev_dbg(hdev, "status 0x%2.2x", status);
@ -4488,10 +4512,14 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status)
if (!status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CIS);
cp = hci_sent_cmd_data_len(hdev, HCI_OP_LE_CREATE_CIS, &len);
if (!cp)
return;
if (len < sizeof(*cp) ||
len < struct_size(cp, cis, cp->num_cis))
return;
hci_dev_lock(hdev);
/* Remove connection if command failed */
@ -4504,7 +4532,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status)
conn = hci_conn_hash_lookup_handle(hdev, handle);
if (conn) {
if (test_and_clear_bit(HCI_CONN_CREATE_CIS,
&conn->flags))
conn->flags))
pending = true;
conn->state = BT_CLOSED;
hci_connect_cfm(conn, status);
@ -4625,7 +4653,7 @@ static void hci_role_change_evt(struct hci_dev *hdev, void *data,
if (!ev->status)
conn->role = ev->role;
clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags);
clear_bit(HCI_CONN_RSWITCH_PEND, conn->flags);
hci_role_switch_cfm(conn, ev->status, ev->role);
}
@ -4737,12 +4765,12 @@ static void hci_mode_change_evt(struct hci_dev *hdev, void *data,
conn->mode = ev->mode;
if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND,
&conn->flags)) {
assign_bit(HCI_CONN_POWER_SAVE, &conn->flags,
conn->flags)) {
assign_bit(HCI_CONN_POWER_SAVE, conn->flags,
conn->mode == HCI_CM_ACTIVE);
}
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, conn->flags))
hci_sco_setup(conn, ev->status);
}
@ -4770,7 +4798,7 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, void *data,
}
if (!hci_dev_test_flag(hdev, HCI_BONDABLE) &&
!test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags)) {
!test_bit(HCI_CONN_AUTH_INITIATOR, conn->flags)) {
hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
sizeof(ev->bdaddr), &ev->bdaddr);
} else if (hci_dev_test_flag(hdev, HCI_MGMT)) {
@ -4845,7 +4873,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, void *data,
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (conn) {
clear_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags);
clear_bit(HCI_CONN_NEW_LINK_KEY, conn->flags);
if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 ||
key->type == HCI_LK_UNAUTH_COMBINATION_P256) &&
@ -4908,7 +4936,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data,
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
hci_conn_drop(conn);
set_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags);
set_bit(HCI_CONN_NEW_LINK_KEY, conn->flags);
conn_set_key(conn, ev->key_type, conn->pin_length);
if (!hci_dev_test_flag(hdev, HCI_MGMT))
@ -4939,7 +4967,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data,
goto unlock;
}
assign_bit(HCI_CONN_FLUSH_KEY, &conn->flags, !persistent);
assign_bit(HCI_CONN_FLUSH_KEY, conn->flags, !persistent);
unlock:
hci_dev_unlock(hdev);
@ -5117,7 +5145,7 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data,
ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
if (ev->features[0] & LMP_HOST_SSP) {
set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
set_bit(HCI_CONN_SSP_ENABLED, conn->flags);
} else {
/* It is mandatory by the Bluetooth specification that
* Extended Inquiry Results are only used when Secure
@ -5127,17 +5155,17 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data,
* To make these devices work, the internal SSP
* enabled flag needs to be cleared if the remote host
* features do not indicate SSP support */
clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
clear_bit(HCI_CONN_SSP_ENABLED, conn->flags);
}
if (ev->features[0] & LMP_HOST_SC)
set_bit(HCI_CONN_SC_ENABLED, &conn->flags);
set_bit(HCI_CONN_SC_ENABLED, conn->flags);
}
if (conn->state != BT_CONFIG)
goto unlock;
if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
if (!ev->status && !test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) {
struct hci_cp_remote_name_req cp;
memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst);
@ -5373,7 +5401,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev, void *data,
mgmt_security_level_changed(conn);
}
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
clear_bit(HCI_CONN_ENCRYPT_PEND, conn->flags);
if (ev->status && conn->state == BT_CONNECTED) {
hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
@ -5474,7 +5502,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data,
goto unlock;
/* Assume remote supports SSP since it has triggered this event */
set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
set_bit(HCI_CONN_SSP_ENABLED, conn->flags);
hci_conn_hold(conn);
@ -5485,7 +5513,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, void *data,
* pairing or if the remote is not requesting bonding.
*/
if (hci_dev_test_flag(hdev, HCI_BONDABLE) ||
test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags) ||
test_bit(HCI_CONN_AUTH_INITIATOR, conn->flags) ||
(conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) {
struct hci_cp_io_capability_reply cp;
@ -5595,7 +5623,7 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, void *data,
* local IO capability is not NoInputNoOutput, use JUST_WORKS
* method (mgmt_user_confirm with confirm_hint set to 1).
*/
if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) &&
if (!test_bit(HCI_CONN_AUTH_PEND, conn->flags) &&
conn->io_capability != HCI_IO_NO_INPUT_OUTPUT) {
bt_dev_dbg(hdev, "Confirming auto-accept as acceptor");
confirm_hint = 1;
@ -5738,7 +5766,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, void *data,
* initiated the authentication. A traditional auth_complete
* event gets always produced as initiator and is also mapped to
* the mgmt_auth_failed event */
if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status)
if (!test_bit(HCI_CONN_AUTH_PEND, conn->flags) && ev->status)
mgmt_auth_failed(conn, ev->status);
hci_conn_drop(conn);
@ -5984,7 +6012,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
goto unlock;
/* Drop the connection if it has been aborted */
if (test_bit(HCI_CONN_CANCEL, &conn->flags)) {
if (test_bit(HCI_CONN_CANCEL, conn->flags)) {
hci_conn_drop(conn);
goto unlock;
}
@ -6041,6 +6069,28 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
hci_conn_put(params->conn);
params->conn = NULL;
}
/* An explicit connect request is complete once connected, so
* clean it up here: hci_connect_le_scan_cleanup() no longer
* finds the params since they have just been removed from
* pend_le_conns.
*/
if (params->explicit_connect) {
params->explicit_connect = false;
switch (params->auto_connect) {
case HCI_AUTO_CONN_EXPLICIT:
hci_conn_params_del(hdev, &conn->dst,
conn->dst_type);
break;
case HCI_AUTO_CONN_REPORT:
hci_pend_le_list_add(params,
&hdev->pend_le_reports);
break;
default:
break;
}
}
}
/* If we are central and have subrate parameters stored, queue a
@ -6101,8 +6151,8 @@ static void hci_le_pa_sync_lost_evt(struct hci_dev *hdev, void *data,
/* Delete the pa sync connection */
conn = hci_conn_hash_lookup_pa_sync_handle(hdev, handle);
if (conn) {
clear_bit(HCI_CONN_BIG_SYNC, &conn->flags);
clear_bit(HCI_CONN_PA_SYNC, &conn->flags);
clear_bit(HCI_CONN_BIG_SYNC, conn->flags);
clear_bit(HCI_CONN_PA_SYNC, conn->flags);
hci_disconn_cfm(conn, HCI_ERROR_REMOTE_USER_TERM);
hci_conn_del(conn);
}
@ -6236,7 +6286,7 @@ static void hci_le_past_received_evt(struct hci_dev *hdev, void *data,
pa_sync->sync_handle = le16_to_cpu(ev->sync_handle);
if (ev->status) {
set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags);
set_bit(HCI_CONN_PA_SYNC_FAILED, pa_sync->flags);
/* Notify iso layer */
hci_connect_cfm(pa_sync, ev->status);
@ -6758,7 +6808,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data,
goto unlock;
}
clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
clear_bit(HCI_CONN_CREATE_PA_SYNC, conn->flags);
conn->sync_handle = le16_to_cpu(ev->handle);
conn->sid = HCI_SID_INVALID;
@ -6783,7 +6833,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data,
pa_sync->sync_handle = le16_to_cpu(ev->handle);
if (ev->status) {
set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags);
set_bit(HCI_CONN_PA_SYNC_FAILED, pa_sync->flags);
/* Notify iso layer */
hci_connect_cfm(pa_sync, ev->status);
@ -6827,7 +6877,7 @@ static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data,
goto unlock;
if (ev->data_status == LE_PA_DATA_COMPLETE &&
!test_and_set_bit(HCI_CONN_PA_SYNC, &pa_sync->flags)) {
!test_and_set_bit(HCI_CONN_PA_SYNC, pa_sync->flags)) {
/* Notify iso layer */
hci_connect_cfm(pa_sync, 0);
@ -6940,11 +6990,11 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, void *data,
* using a distributed LTK.
*/
if (ltk->type == SMP_STK) {
set_bit(HCI_CONN_STK_ENCRYPT, &conn->flags);
set_bit(HCI_CONN_STK_ENCRYPT, conn->flags);
list_del_rcu(&ltk->list);
kfree_rcu(ltk, rcu);
} else {
clear_bit(HCI_CONN_STK_ENCRYPT, &conn->flags);
clear_bit(HCI_CONN_STK_ENCRYPT, conn->flags);
}
hci_dev_unlock(hdev);
@ -7140,7 +7190,7 @@ static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data,
qos = &conn->iso_qos;
pending = test_and_clear_bit(HCI_CONN_CREATE_CIS, &conn->flags);
pending = test_and_clear_bit(HCI_CONN_CREATE_CIS, conn->flags);
/* BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 6, Part G
* page 3075:
@ -7337,7 +7387,7 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
}
conn->state = BT_CONNECTED;
set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
set_bit(HCI_CONN_BIG_CREATED, conn->flags);
hci_debugfs_create_conn(conn);
hci_conn_add_sysfs(conn);
hci_iso_setup_path(conn);
@ -7382,7 +7432,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
goto unlock;
}
clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
clear_bit(HCI_CONN_CREATE_BIG_SYNC, conn->flags);
conn->num_bis = 0;
memset(conn->bis, 0, sizeof(conn->bis));
@ -7405,7 +7455,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
if (ev->status != 0x42)
/* Mark PA sync as established */
set_bit(HCI_CONN_PA_SYNC, &bis->flags);
set_bit(HCI_CONN_PA_SYNC, bis->flags);
bis->sync_handle = conn->sync_handle;
bis->iso_qos.bcast.big = ev->handle;
@ -7418,7 +7468,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
if (!ev->status) {
bis->state = BT_CONNECTED;
set_bit(HCI_CONN_BIG_SYNC, &bis->flags);
set_bit(HCI_CONN_BIG_SYNC, bis->flags);
hci_debugfs_create_conn(bis);
hci_conn_add_sysfs(bis);
hci_iso_setup_path(bis);
@ -7436,7 +7486,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
if (!bis)
continue;
set_bit(HCI_CONN_BIG_SYNC_FAILED, &bis->flags);
set_bit(HCI_CONN_BIG_SYNC_FAILED, bis->flags);
hci_connect_cfm(bis, ev->status);
}
@ -7466,13 +7516,13 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data,
* it is consumed there instead of here.
*/
mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED,
&bis->flags);
bis->flags);
mgmt_device_disconnected(hdev, &bis->dst, bis->type,
bis->dst_type, ev->reason,
mgmt_conn);
}
clear_bit(HCI_CONN_BIG_SYNC, &bis->flags);
clear_bit(HCI_CONN_BIG_SYNC, bis->flags);
hci_disconn_cfm(bis, ev->reason);
hci_conn_del(bis);
}

View File

@ -376,8 +376,18 @@ static void le_scan_disable(struct work_struct *work)
bt_dev_dbg(hdev, "");
hci_dev_lock(hdev);
if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
if (!hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
/* The scan of a discovery can be disabled while this work
* waits for the lock, for example by a Stop Discovery that
* timed out and still completed, so end the discovery as
* le_set_scan_enable_complete() does when it cancels this
* work.
*/
if (hdev->discovery.state == DISCOVERY_FINDING)
goto discov_stopped;
goto _return;
}
status = hci_cmd_sync_queue(hdev, scan_disable_sync, NULL, NULL);
if (status) {
@ -2448,15 +2458,17 @@ static int hci_le_del_resolve_list_sync(struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 bdaddr_type)
{
struct hci_cp_le_del_from_resolv_list cp;
struct bdaddr_list_with_irk *entry;
bool exists;
if (!ll_privacy_capable(hdev))
return 0;
/* Check if the IRK has been programmed */
entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, bdaddr,
bdaddr_type);
if (!entry)
hci_dev_lock(hdev);
exists = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
bdaddr, bdaddr_type);
hci_dev_unlock(hdev);
if (!exists)
return 0;
cp.bdaddr_type = bdaddr_type;
@ -2512,8 +2524,8 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev,
{
struct hci_cp_le_add_to_resolv_list cp;
struct smp_irk *irk;
struct bdaddr_list_with_irk *entry;
struct hci_conn_params *p;
bool exists;
if (!ll_privacy_capable(hdev))
return 0;
@ -2531,20 +2543,28 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev,
} else if (!(params->flags & HCI_CONN_FLAG_ADDRESS_RESOLUTION))
return 0;
rcu_read_lock();
irk = hci_find_irk_by_addr(hdev, &params->addr, params->addr_type);
if (!irk)
if (!irk) {
rcu_read_unlock();
return 0;
}
memcpy(cp.peer_irk, irk->val, 16);
rcu_read_unlock();
/* Check if the IK has _not_ been programmed yet. */
entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
&params->addr,
params->addr_type);
if (entry)
hci_dev_lock(hdev);
exists = hci_bdaddr_list_lookup_with_irk(
&hdev->le_resolv_list, &params->addr, params->addr_type);
hci_dev_unlock(hdev);
if (exists)
return 0;
cp.bdaddr_type = params->addr_type;
bacpy(&cp.bdaddr, &params->addr);
memcpy(cp.peer_irk, irk->val, 16);
/* Default privacy mode is always Network */
params->privacy_mode = HCI_NETWORK_PRIVACY;
@ -2733,7 +2753,7 @@ static int hci_pause_advertising_sync(struct hci_dev *hdev)
static int hci_resume_advertising_sync(struct hci_dev *hdev)
{
struct adv_info *adv, *tmp;
int err;
int err = 0;
/* If advertising has not been paused there is nothing to do. */
if (!hdev->advertising_paused)
@ -2766,13 +2786,19 @@ static int hci_resume_advertising_sync(struct hci_dev *hdev)
*/
if (hci_dev_test_and_clear_flag(hdev, HCI_LE_ADV_0))
err = hci_enable_ext_advertising_sync(hdev, 0x00);
} else {
} else if (hdev->cur_adv_instance) {
/* Schedule for most recent instance to be restarted and begin
* the software rotation loop
*/
err = hci_schedule_adv_instance_sync(hdev,
hdev->cur_adv_instance,
true);
} else if (hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
!hci_dev_test_flag(hdev, HCI_LE_ADV)) {
/* hci_schedule_adv_instance_sync() rejects instance 0x00 while
* HCI_ADVERTISING is set, so enable it directly.
*/
err = hci_start_adv_sync(hdev, 0x00);
}
hdev->advertising_paused = false;
@ -2879,6 +2905,31 @@ static struct conn_params *conn_params_copy(struct list_head *list, size_t *n)
return p;
}
static struct conn_params *le_accept_list_copy(struct hci_dev *hdev,
size_t *n)
{
struct bdaddr_list *entry;
struct conn_params *params;
size_t i = 0;
hci_dev_lock(hdev);
*n = list_count_nodes(&hdev->le_accept_list);
params = kvzalloc_objs(struct conn_params, *n);
if (!params)
goto unlock;
list_for_each_entry(entry, &hdev->le_accept_list, list) {
bacpy(&params[i].addr, &entry->bdaddr);
params[i].addr_type = entry->bdaddr_type;
i++;
}
unlock:
hci_dev_unlock(hdev);
return params;
}
/* Clear LE Accept List */
static int hci_le_clear_accept_list_sync(struct hci_dev *hdev)
{
@ -2909,7 +2960,6 @@ static int hci_le_clear_accept_list_sync(struct hci_dev *hdev)
static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
{
struct conn_params *params;
struct bdaddr_list *b, *t;
u8 num_entries = 0;
bool pend_conn, pend_report;
u8 filter_policy;
@ -2974,20 +3024,27 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
* report. If not present in either list, then remove it from
* the controller.
*/
list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) {
params = le_accept_list_copy(hdev, &n);
if (!params) {
err = -ENOMEM;
goto done;
}
for (i = 0; i < n; i++) {
rcu_read_lock();
if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type)) {
if (hci_conn_hash_lookup_le(hdev, &params[i].addr,
params[i].addr_type)) {
rcu_read_unlock();
continue;
}
pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns,
&b->bdaddr,
b->bdaddr_type);
pend_report = hci_pend_le_action_lookup(&hdev->pend_le_reports,
&b->bdaddr,
b->bdaddr_type);
&params[i].addr,
params[i].addr_type);
pend_report = hci_pend_le_action_lookup(
&hdev->pend_le_reports, &params[i].addr,
params[i].addr_type);
rcu_read_unlock();
@ -2995,14 +3052,16 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
* remove it from the acceptlist.
*/
if (!pend_conn && !pend_report) {
hci_le_del_accept_list_sync(hdev, &b->bdaddr,
b->bdaddr_type);
hci_le_del_accept_list_sync(hdev, &params[i].addr,
params[i].addr_type);
continue;
}
num_entries++;
}
kvfree(params);
/* Since all no longer valid accept list entries have been
* removed, walk through the list of pending connections
* and ensure that any new device gets programmed into
@ -3505,9 +3564,13 @@ int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode)
return hci_write_sc_support_sync(hdev, 0x01);
}
static int hci_le_set_host_feature_sync(struct hci_dev *hdev, u16 bit,
u8 value);
int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul)
{
struct hci_cp_write_le_host_supported cp;
int err;
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) ||
!lmp_bredr_capable(hdev))
@ -3525,8 +3588,16 @@ int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul)
cp.le = le;
cp.simul = simul;
return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
err = __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
if (err || !cis_capable(hdev))
return err;
/* The CIS host feature is set during init based on LE being enabled,
* which is not repeated when LE is enabled afterwards, e.g. while the
* controller is still auto powered on, so update it here.
*/
return hci_le_set_host_feature_sync(hdev, 32, iso_enabled(hdev));
}
static int hci_powered_update_adv_sync(struct hci_dev *hdev)
@ -4828,6 +4899,9 @@ static int hci_le_set_def_rate_sync(struct hci_dev *hdev)
struct hci_cp_le_set_def_rate cp;
u16 interval_min = 0x000a; /* 1.25 ms */
u16 interval_max = 0x0078; /* 15 ms */
u16 subrate_max = 0x0004;
u16 max_latency = 0x0000;
u32 supv_timeout;
if (!le_sci_capable(hdev))
return 0;
@ -4852,10 +4926,31 @@ static int hci_le_set_def_rate_sync(struct hci_dev *hdev)
cp.interval_min = cpu_to_le16(interval_min);
cp.interval_max = cpu_to_le16(interval_max);
cp.subrate_min = cpu_to_le16(0x0001);
cp.subrate_max = cpu_to_le16(0x0004);
cp.max_latency = cpu_to_le16(0x0000);
cp.subrate_max = cpu_to_le16(subrate_max);
cp.max_latency = cpu_to_le16(max_latency);
cp.cont_num = cpu_to_le16(0x0001);
cp.supv_timeout = cpu_to_le16(0x000c); /* 120 ms */
/* HOGP v1.2 recommends a Supervision_Timeout greater than or equal to
* (1 + Max_Latency) x Subrate_Max x Connection_Interval_Max x 2, but
* the Core spec treats the equality as invalid:
*
* BLUETOOTH CORE SPECIFICATION Version 6.3 | Vol 4, Part E
* 7.8.158. LE Set Default Rate Parameters command
*
* If Connection_Interval_Max x Subrate_Max x (Max_Latency + 1) is
* greater than or equal to Supervision_Timeout x 40, the Controller
* shall return the error code Invalid HCI Command Parameters (0x12).
*
* So default to 2 s, 10x lower than the 20 s used for non-SCI
* connections while still well above the minimum required, but make
* sure it stays strictly above the minimum in case interval_max has
* been raised.
*/
supv_timeout = (u32)interval_max * subrate_max * (max_latency + 1);
supv_timeout = supv_timeout / 40 + 1;
supv_timeout = clamp_t(u32, max_t(u32, supv_timeout, 0x00c8),
0x000a, 0x0c80);
cp.supv_timeout = cpu_to_le16(supv_timeout);
/* The connection event length recommended in requests by a Peripheral
* uses units of 125 us with a valid range of 0x0001 to 0x7CFF
@ -5637,6 +5732,11 @@ int hci_dev_close_sync(struct hci_dev *hdev)
return err;
}
/* Wait for hci_recv_frame() callers that still saw HCI_UP, so that
* none of them queues rx_work while the workqueue is drained below.
*/
synchronize_rcu();
hci_leds_update_powered(hdev, false);
/* Flush RX and TX works */
@ -5830,11 +5930,15 @@ int hci_stop_discovery_sync(struct hci_dev *hdev)
}
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
cancel_delayed_work(&hdev->le_scan_disable);
err = hci_scan_disable_sync(hdev);
if (err)
return err;
/* Only cancel the LE scan timeout once the scan is
* disabled, so that the discovery still ends if
* stopping it failed.
*/
cancel_delayed_work(&hdev->le_scan_disable);
}
} else {
@ -5913,11 +6017,11 @@ static int hci_le_connect_cancel_sync(struct hci_dev *hdev,
/* Return reason if scanning since the connection shall probably be
* cleanup directly.
*/
if (test_bit(HCI_CONN_SCANNING, &conn->flags))
if (test_bit(HCI_CONN_SCANNING, conn->flags))
return reason;
if (conn->role == HCI_ROLE_SLAVE ||
test_and_set_bit(HCI_CONN_CANCEL, &conn->flags))
test_and_set_bit(HCI_CONN_CANCEL, conn->flags))
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_CREATE_CONN_CANCEL,
@ -5939,7 +6043,7 @@ static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn,
* then an HCI_LE_CIS_Established event shall also be sent for
* this CIS with the Status Operation Cancelled by Host (0x44).
*/
if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
if (test_bit(HCI_CONN_CREATE_CIS, conn->flags))
return hci_disconnect_sync(hdev, conn, reason);
/* CIS with no Create CIS sent have nothing to cancel */
@ -6310,6 +6414,7 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval)
u8 filter_policy = 0x00;
/* Default is to enable duplicates filter */
u8 filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
bool paused;
int err;
bt_dev_dbg(hdev, "");
@ -6333,6 +6438,12 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval)
if (err)
goto failed;
/* LE Set Random Address is disallowed while advertising is enabled. */
paused = !hdev->advertising_paused;
err = hci_pause_advertising_sync(hdev);
if (err)
goto failed;
/* All active scans will be done with either a resolvable private
* address (when privacy feature has been enabled) or non-resolvable
* private address.
@ -6342,6 +6453,9 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval)
if (err < 0)
own_addr_type = ADDR_LE_DEV_PUBLIC;
if (paused)
hci_resume_advertising_sync(hdev);
if (hci_is_adv_monitoring(hdev) ||
(hci_test_quirk(hdev, HCI_QUIRK_STRICT_DUPLICATE_FILTER) &&
hdev->discovery.result_filtering)) {
@ -6365,9 +6479,8 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval)
return err;
failed:
/* Resume advertising if it was paused */
if (ll_privacy_capable(hdev))
hci_resume_advertising_sync(hdev);
/* No-op when advertising was not paused. */
hci_resume_advertising_sync(hdev);
/* Resume passive scanning */
hci_update_passive_scan_sync(hdev);
@ -6460,6 +6573,12 @@ static int hci_pause_discovery_sync(struct hci_dev *hdev)
return 0;
hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
/* Cancel the LE scan timeout first, so that it does not run while
* suspended if the scan cannot be disabled.
*/
cancel_delayed_work(&hdev->le_scan_disable);
err = hci_stop_discovery_sync(hdev);
if (err)
return err;
@ -6928,7 +7047,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
bt_dev_dbg(hdev, "conn %p", conn);
clear_bit(HCI_CONN_SCANNING, &conn->flags);
clear_bit(HCI_CONN_SCANNING, conn->flags);
conn->state = BT_CONNECT;
/* If requested to connect as peripheral use directed advertising */
@ -6995,7 +7114,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
/* Mark create connection in flight so hci_cancel_connect_sync() can
* cancel it while blocking on the connection complete event.
*/
set_bit(HCI_CONN_CREATE, &conn->flags);
set_bit(HCI_CONN_CREATE, conn->flags);
/* Send command LE Extended Create Connection if supported */
if (use_ext_conn(hdev)) {
@ -7032,7 +7151,7 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
conn->conn_timeout, NULL);
done:
clear_bit(HCI_CONN_CREATE, &conn->flags);
clear_bit(HCI_CONN_CREATE, conn->flags);
if (err == -ETIMEDOUT)
hci_le_connect_cancel_sync(hdev, conn, 0x00);
@ -7079,7 +7198,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev)
/* Wait until previous Create CIS has completed */
list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
if (test_bit(HCI_CONN_CREATE_CIS, conn->flags))
goto done;
}
@ -7115,7 +7234,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev)
conn->iso_qos.ucast.cig != cig)
continue;
set_bit(HCI_CONN_CREATE_CIS, &conn->flags);
set_bit(HCI_CONN_CREATE_CIS, conn->flags);
cis->acl_handle = cpu_to_le16(conn->parent->handle);
cis->cis_handle = cpu_to_le16(conn->handle);
timeout = conn->conn_timeout;
@ -7318,14 +7437,14 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
/* Mark create connection in flight so hci_cancel_connect_sync() can
* cancel it while blocking on the connection complete event.
*/
set_bit(HCI_CONN_CREATE, &conn->flags);
set_bit(HCI_CONN_CREATE, conn->flags);
err = __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN,
sizeof(cp), &cp,
HCI_EV_CONN_COMPLETE,
conn->conn_timeout, NULL);
clear_bit(HCI_CONN_CREATE, &conn->flags);
clear_bit(HCI_CONN_CREATE, conn->flags);
return err;
}
@ -7414,7 +7533,7 @@ static int hci_acl_cancel_create_conn_sync(struct hci_dev *hdev,
mutex_lock(&hdev->cmd_sync_work_lock);
/* In flight: this connection owns the pending request, cancel it. */
if (test_bit(HCI_CONN_CREATE, &conn->flags)) {
if (test_bit(HCI_CONN_CREATE, conn->flags)) {
hci_cmd_sync_cancel(hdev, ECANCELED);
goto unlock;
}
@ -7445,7 +7564,7 @@ static int hci_le_cancel_create_conn_sync(struct hci_dev *hdev,
*/
mutex_lock(&hdev->cmd_sync_work_lock);
if (test_bit(HCI_CONN_CREATE, &conn->flags)) {
if (test_bit(HCI_CONN_CREATE, conn->flags)) {
hci_cmd_sync_cancel(hdev, ECANCELED);
goto unlock;
}
@ -7472,7 +7591,7 @@ static int hci_cis_cancel_create_conn_sync(struct hci_dev *hdev,
*/
mutex_lock(&hdev->cmd_sync_work_lock);
if (test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
if (test_bit(HCI_CONN_CREATE_CIS, conn->flags))
hci_cmd_sync_cancel(hdev, ECANCELED);
mutex_unlock(&hdev->cmd_sync_work_lock);
@ -7609,7 +7728,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
hci_dev_lock(hdev);
if (hci_conn_valid(hdev, conn))
clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
clear_bit(HCI_CONN_CREATE_PA_SYNC, conn->flags);
if (!err)
goto unlock;
@ -7621,7 +7740,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
if (IS_ERR(pa_sync))
goto unlock;
set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags);
set_bit(HCI_CONN_PA_SYNC_FAILED, pa_sync->flags);
/* Notify iso layer */
hci_connect_cfm(pa_sync, bt_status(err));
@ -7694,7 +7813,7 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data)
* program the address in the allow list so PA advertisements can be
* received.
*/
set_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
set_bit(HCI_CONN_CREATE_PA_SYNC, conn->flags);
hci_update_passive_scan_sync(hdev);
@ -7797,7 +7916,7 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)
if (err == -ECANCELED)
goto done;
clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
clear_bit(HCI_CONN_CREATE_BIG_SYNC, conn->flags);
done:
hci_conn_put(conn);
@ -7814,7 +7933,7 @@ static int hci_le_big_create_sync(struct hci_dev *hdev, void *data)
if (!hci_conn_valid(hdev, conn))
return -ECANCELED;
set_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
set_bit(HCI_CONN_CREATE_BIG_SYNC, conn->flags);
memset(cp, 0, sizeof(*cp));
cp->handle = qos->bcast.big;

View File

@ -912,7 +912,7 @@ static void iso_sock_disconn(struct sock *sk)
struct sock *bis_sk;
struct hci_conn *hcon = iso_pi(sk)->conn->hcon;
if (test_bit(HCI_CONN_BIG_CREATED, &hcon->flags)) {
if (test_bit(HCI_CONN_BIG_CREATED, hcon->flags)) {
bis_sk = iso_get_sock_big(sk, &iso_pi(sk)->src,
&iso_pi(sk)->dst,
iso_pi(sk)->qos.bcast.big);
@ -957,8 +957,8 @@ static void __iso_sock_close(struct sock *sk)
case BT_CONNECT2:
if (iso_pi(sk)->conn->hcon &&
(test_bit(HCI_CONN_PA_SYNC, &iso_pi(sk)->conn->hcon->flags) ||
test_bit(HCI_CONN_PA_SYNC_FAILED, &iso_pi(sk)->conn->hcon->flags)))
(test_bit(HCI_CONN_PA_SYNC, iso_pi(sk)->conn->hcon->flags) ||
test_bit(HCI_CONN_PA_SYNC_FAILED, iso_pi(sk)->conn->hcon->flags)))
iso_sock_disconn(sk);
else
iso_chan_del(sk, ECONNRESET);
@ -2289,7 +2289,7 @@ static void iso_conn_ready(struct iso_conn *conn)
hdev = hcon->hdev;
if (test_bit(HCI_CONN_BIG_SYNC, &hcon->flags)) {
if (test_bit(HCI_CONN_BIG_SYNC, hcon->flags)) {
/* A BIS slave hcon is notified to the ISO layer
* after the Command Complete for the LE Setup
* ISO Data Path command is received. Get the
@ -2298,7 +2298,7 @@ static void iso_conn_ready(struct iso_conn *conn)
parent = iso_get_sock(hdev, &hcon->src, &hcon->dst,
BT_LISTEN, iso_match_big_hcon,
hcon);
} else if (test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) {
} else if (test_bit(HCI_CONN_BIG_SYNC_FAILED, hcon->flags)) {
ev = hci_recv_event_data(hcon->hdev,
HCI_EVT_LE_BIG_SYNC_ESTABLISHED);
@ -2312,7 +2312,7 @@ static void iso_conn_ready(struct iso_conn *conn)
&hcon->dst,
BT_LISTEN,
iso_match_big, ev);
} else if (test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) {
} else if (test_bit(HCI_CONN_PA_SYNC_FAILED, hcon->flags)) {
ev2 = hci_recv_event_data(hcon->hdev,
HCI_EV_LE_PA_SYNC_ESTABLISHED);
if (ev2)
@ -2320,7 +2320,7 @@ static void iso_conn_ready(struct iso_conn *conn)
&hcon->dst,
BT_LISTEN,
iso_match_sid, ev2);
} else if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags)) {
} else if (test_bit(HCI_CONN_PA_SYNC, hcon->flags)) {
ev3 = hci_recv_event_data(hcon->hdev,
HCI_EV_LE_PER_ADV_REPORT);
if (ev3)
@ -2376,7 +2376,7 @@ static void iso_conn_ready(struct iso_conn *conn)
hcon->dst_type = le_addr_type(iso_pi(parent)->dst_type);
}
if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags)) {
if (test_bit(HCI_CONN_PA_SYNC, hcon->flags)) {
iso_pi(sk)->qos = iso_pi(parent)->qos;
hcon->iso_qos = iso_pi(sk)->qos;
iso_pi(sk)->bc_sid = iso_pi(parent)->bc_sid;
@ -2676,8 +2676,8 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
* into the accept queue of the listening socket and wake up
* userspace, to inform the user about the event.
*/
if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags) ||
test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) {
if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, hcon->flags) ||
test_bit(HCI_CONN_PA_SYNC_FAILED, hcon->flags)) {
struct iso_conn *conn;
conn = iso_conn_add(hcon);

View File

@ -1575,7 +1575,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon,
if (chan->sec_level == BT_SECURITY_FIPS)
min_key_size = 16;
return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) ||
return (!test_bit(HCI_CONN_ENCRYPT, hcon->flags) ||
hcon->enc_key_size >= min_key_size);
}
@ -4480,11 +4480,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
lockdep_assert_held(&chan->conn->lock);
/* Only accept a response to a connection request we sent and that
* is still outstanding. A channel waiting in BT_CONNECT for security
* or the feature mask has not sent one yet.
/* Only accept a response matching a connection request we sent and
* that is still outstanding. A channel waiting in BT_CONNECT for
* security or the feature mask has not sent one yet.
*/
if (!l2cap_chan_connect_pending(chan))
if (!l2cap_chan_connect_pending(chan) || chan->ident != cmd->ident)
goto done;
switch (result) {
@ -7389,7 +7389,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
u16 cid, len;
__le16 psm;
if (hcon->state != BT_CONNECTED) {
/* Also hold data back while the encryption key size is read, as
* the security of the link, e.g. for SMP over BR/EDR, depends on it.
*/
if (hcon->state != BT_CONNECTED ||
test_bit(HCI_CONN_ENC_KEY_SIZE_PEND, hcon->flags)) {
BT_DBG("queueing pending rx skb");
skb_queue_tail(&conn->pending_rx, skb);
return;
@ -7452,7 +7456,11 @@ static void process_pending_rx(struct work_struct *work)
mutex_lock(&conn->lock);
while ((skb = skb_dequeue(&conn->pending_rx)))
/* l2cap_recv_frame() would queue it all again while the encryption
* key size is read, l2cap_security_cfm() schedules this once known.
*/
while (!test_bit(HCI_CONN_ENC_KEY_SIZE_PEND, conn->hcon->flags) &&
(skb = skb_dequeue(&conn->pending_rx)))
l2cap_recv_frame(conn, skb);
mutex_unlock(&conn->lock);
@ -8041,6 +8049,10 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
}
mutex_unlock(&conn->lock);
/* Process data held back while the encryption key size was read */
if (!skb_queue_empty(&conn->pending_rx))
queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
}
/* Append fragment into frame respecting the maximum len of rx_skb */

View File

@ -304,6 +304,8 @@ static u8 mgmt_errno_status(int err)
return MGMT_STATUS_DISCONNECTED;
case -ECANCELED:
return MGMT_STATUS_CANCELLED;
case -ERFKILL:
return MGMT_STATUS_RFKILLED;
}
return MGMT_STATUS_FAILED;
@ -3241,7 +3243,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
/* Defer clearing up the connection parameters until closing to
* give a chance of keeping them if a repairing happens.
*/
set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
set_bit(HCI_CONN_PARAM_REMOVAL_PEND, conn->flags);
/* Disable auto-connection parameters if present */
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type);
@ -3416,7 +3418,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
i = 0;
list_for_each_entry(c, &hdev->conn_hash.list, list) {
if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
if (test_bit(HCI_CONN_MGMT_CONNECTED, c->flags))
i++;
}
@ -3428,7 +3430,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
i = 0;
list_for_each_entry(c, &hdev->conn_hash.list, list) {
if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
if (!test_bit(HCI_CONN_MGMT_CONNECTED, c->flags))
continue;
bacpy(&rp->addr[i].bdaddr, &c->dst);
rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
@ -3628,7 +3630,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
/* The device is paired so there is no need to remove
* its connection parameters anymore.
*/
clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, conn->flags);
hci_conn_put(conn);
@ -6316,12 +6318,29 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
bt_dev_dbg(hdev, "err %d", err);
hci_dev_lock(hdev);
/* Change the state before replying, so that a client acting on the
* reply sees it, and only while the discovery is still stopping, as
* Inquiry Cancel may already have stopped it and a new Start Discovery
* may have followed. Go back to DISCOVERY_FINDING when stopping failed
* while the inquiry or the active LE scan of the discovery is still
* running, so that it can be stopped again.
*/
if (hdev->discovery.state == DISCOVERY_STOPPING) {
if (err && (test_bit(HCI_INQUIRY, &hdev->flags) ||
(hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
hdev->le_scan_type == LE_SCAN_ACTIVE)))
hci_discovery_set_state(hdev, DISCOVERY_FINDING);
else
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
}
hci_dev_unlock(hdev);
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
cmd->param, 1);
mgmt_pending_free(cmd);
if (!err)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
}
static int stop_discovery_sync(struct hci_dev *hdev, void *data)
@ -8173,7 +8192,11 @@ static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
hci_dev_lock(hdev);
if (param_count > 1)
/* A single entry may be an update for one device, so keep the other
* disabled parameters then, but clear them otherwise, including when
* no entries are loaded.
*/
if (param_count != 1)
hci_conn_params_clear_disabled(hdev);
for (i = 0; i < param_count; i++) {
@ -10128,7 +10151,7 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
u16 eir_len = 0;
u32 flags = 0;
if (test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
if (test_and_set_bit(HCI_CONN_MGMT_CONNECTED, conn->flags))
return;
/* allocate buff for LE or BR/EDR adv */
@ -10177,7 +10200,7 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
* since userspace did not know about them yet, so report it now.
* Unencrypted connections have no change to report.
*/
if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
if (test_bit(HCI_CONN_ENCRYPT, conn->flags))
mgmt_security_level_changed(conn);
}
@ -10289,7 +10312,7 @@ void mgmt_connect_failed(struct hci_dev *hdev, struct hci_conn *conn, u8 status)
* still needs it set to know whether to report the security level
* reset, so it is consumed there instead of here.
*/
if (test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
if (test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags)) {
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
conn->dst_type,
hci_to_mgmt_reason(status), true);
@ -10930,7 +10953,7 @@ void mgmt_security_level_changed(struct hci_conn *conn)
u8 *tlv_data;
u8 tlv_len;
if (!test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
if (!test_bit(HCI_CONN_MGMT_CONNECTED, conn->flags))
return;
/* Only ACL, LE and BIS links are tracked as mgmt connections, so
@ -10961,9 +10984,9 @@ void mgmt_security_level_changed(struct hci_conn *conn)
tlv = (void *)tlv_data;
tlv->type = cpu_to_le16(MGMT_SEC_LEVEL_CHANGED_PARAM_ENC_TYPE);
tlv->length = sizeof(__u8);
if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
if (!test_bit(HCI_CONN_ENCRYPT, conn->flags))
tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_NONE;
else if (test_bit(HCI_CONN_AES_CCM, &conn->flags))
else if (test_bit(HCI_CONN_AES_CCM, conn->flags))
tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_AES_CCM;
else
tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_E0;

View File

@ -984,12 +984,12 @@ static u8 smp_random(struct smp_chan *smp)
smp_s1(smp->tk, smp->rrnd, smp->prnd, stk);
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, hcon->flags))
return SMP_UNSPECIFIED;
hci_le_start_enc(hcon, ediv, rand, stk, smp->enc_key_size);
hcon->enc_key_size = smp->enc_key_size;
set_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags);
set_bit(HCI_CONN_STK_ENCRYPT, hcon->flags);
} else {
u8 stk[16], auth;
__le64 rand = 0;
@ -1028,7 +1028,7 @@ static void smp_notify_keys(struct l2cap_conn *conn)
persistent = false;
else
persistent = !test_bit(HCI_CONN_FLUSH_KEY,
&hcon->flags);
hcon->flags);
} else {
/* The LTKs, IRKs and CSRKs should be persistent only if
* both sides had the bonding bit set in their
@ -1186,9 +1186,13 @@ static void sc_generate_ltk(struct smp_chan *smp)
struct hci_conn *hcon = smp->conn->hcon;
struct hci_dev *hdev = hcon->hdev;
struct link_key *key;
int err;
rcu_read_lock();
key = hci_find_link_key(hdev, &hcon->dst);
if (!key) {
rcu_read_unlock();
bt_dev_err(hdev, "no Link Key found to generate LTK");
return;
}
@ -1200,16 +1204,19 @@ static void sc_generate_ltk(struct smp_chan *smp)
/* SALT = 0x000000000000000000000000746D7032 */
const u8 salt[16] = { 0x32, 0x70, 0x6d, 0x74 };
if (smp_h7(key->val, salt, smp->tk))
return;
err = smp_h7(key->val, salt, smp->tk);
} else {
/* From core spec. Spells out in ASCII as 'tmp2'. */
const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 };
if (smp_h6(key->val, tmp2, smp->tk))
return;
err = smp_h6(key->val, tmp2, smp->tk);
}
rcu_read_unlock();
if (err)
return;
if (smp_h6(smp->tk, brle, smp->tk))
return;
@ -1753,7 +1760,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
/* SMP over BR/EDR requires special treatment */
if (conn->hcon->type == ACL_LINK) {
/* We must have a BR/EDR SC link */
if (!test_bit(HCI_CONN_AES_CCM, &conn->hcon->flags) &&
if (!test_bit(HCI_CONN_AES_CCM, conn->hcon->flags) &&
!hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP))
return SMP_CROSS_TRANSP_NOT_ALLOWED;
@ -2202,24 +2209,30 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
{
struct smp_ltk *key;
struct hci_conn *hcon = conn->hcon;
bool ret = false;
rcu_read_lock();
key = hci_find_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, hcon->role);
if (!key)
return false;
goto unlock;
if (smp_ltk_sec_level(key) < sec_level)
return false;
goto unlock;
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
return true;
ret = true;
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, hcon->flags))
goto unlock;
hci_le_start_enc(hcon, key->ediv, key->rand, key->val, key->enc_size);
hcon->enc_key_size = key->enc_size;
/* We never store STKs for initiator role, so clear this flag */
clear_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags);
clear_bit(HCI_CONN_STK_ENCRYPT, hcon->flags);
return true;
unlock:
rcu_read_unlock();
return ret;
}
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,
@ -2235,7 +2248,7 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,
* don't have an LTK (e.g. because of key distribution bits).
*/
if (key_pref == SMP_USE_LTK &&
test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) &&
test_bit(HCI_CONN_STK_ENCRYPT, hcon->flags) &&
hci_find_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, hcon->role))
return false;
@ -3084,11 +3097,11 @@ static void bredr_pairing(struct l2cap_chan *chan)
bt_dev_dbg(hdev, "chan %p", chan);
/* Only new pairings are interesting */
if (!test_bit(HCI_CONN_NEW_LINK_KEY, &hcon->flags))
if (!test_bit(HCI_CONN_NEW_LINK_KEY, hcon->flags))
return;
/* Don't bother if we're not encrypted */
if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
if (!test_bit(HCI_CONN_ENCRYPT, hcon->flags))
return;
/* Only initiator may initiate SMP over BR/EDR */
@ -3100,7 +3113,7 @@ static void bredr_pairing(struct l2cap_chan *chan)
return;
/* BR/EDR must use Secure Connections for SMP */
if (!test_bit(HCI_CONN_AES_CCM, &hcon->flags) &&
if (!test_bit(HCI_CONN_AES_CCM, hcon->flags) &&
!hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP))
return;
@ -3149,7 +3162,7 @@ static void smp_resume_cb(struct l2cap_chan *chan)
if (!smp)
return;
if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
if (!test_bit(HCI_CONN_ENCRYPT, hcon->flags))
return;
cancel_delayed_work(&smp->security_timer);
@ -3172,7 +3185,7 @@ static void smp_ready_cb(struct l2cap_chan *chan)
*/
conn->smp = chan;
if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, hcon->flags))
bredr_pairing(chan);
}

View File

@ -341,13 +341,13 @@ static void del_nbp(struct net_bridge_port *p)
nbp_delete_promisc(p);
br_mrp_port_del(br, p);
br_cfm_port_del(br, p);
spin_lock_bh(&br->lock);
br_stp_disable_port(p);
spin_unlock_bh(&br->lock);
br_mrp_port_del(br, p);
br_cfm_port_del(br, p);
br_ifinfo_notify(RTM_DELLINK, NULL, p);
list_del_rcu(&p->list);

View File

@ -226,7 +226,7 @@ int can_send(struct sk_buff *skb, int loop)
goto inval_skb;
}
if (unlikely(skb->dev->type != ARPHRD_CAN)) {
if (unlikely(!can_get_ml_priv(skb->dev))) {
err = -EPERM;
goto inval_skb;
}
@ -418,7 +418,7 @@ static struct hlist_head *can_rcv_list_find(canid_t *can_id, canid_t *mask,
* @mask: CAN mask (see description)
* @func: callback function on filter match
* @data: returned parameter for callback function
* @ident: string for calling module identification
* @ino: inode number of sock (0 = unknown)
* @sk: socket pointer (might be NULL)
*
* Description:
@ -443,7 +443,7 @@ static struct hlist_head *can_rcv_list_find(canid_t *can_id, canid_t *mask,
*/
int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
canid_t mask, void (*func)(struct sk_buff *, void *),
void *data, char *ident, struct sock *sk)
void *data, u64 ino, struct sock *sk)
{
struct receiver *rcv;
struct hlist_head *rcv_list;
@ -452,7 +452,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
/* insert new receiver (dev,canid,mask) -> (func,data) */
if (dev && (dev->type != ARPHRD_CAN || !can_get_ml_priv(dev)))
if (dev && !can_get_ml_priv(dev))
return -ENODEV;
if (dev && !net_eq(net, dev_net(dev)))
@ -462,9 +462,10 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
if (!rcv)
return -ENOMEM;
spin_lock_bh(&net->can.rcvlists_lock);
dev_rcv_lists = can_dev_rcv_lists_find(net, dev);
spin_lock_bh(&dev_rcv_lists->lock);
rcv_list = can_rcv_list_find(&can_id, &mask, dev_rcv_lists);
rcv->can_id = can_id;
@ -472,12 +473,15 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id,
atomic_long_set(&rcv->matches, 0);
rcv->func = func;
rcv->data = data;
rcv->ident = ident;
rcv->ino = ino;
rcv->sk = sk;
hlist_add_head_rcu(&rcv->list, rcv_list);
dev_rcv_lists->entries++;
spin_unlock_bh(&dev_rcv_lists->lock);
spin_lock_bh(&net->can.rcvlists_lock);
rcv_lists_stats->rcv_entries++;
rcv_lists_stats->rcv_entries_max = max(rcv_lists_stats->rcv_entries_max,
rcv_lists_stats->rcv_entries);
@ -509,6 +513,14 @@ static void can_rx_delete_receiver(struct rcu_head *rp)
*
* Description:
* Removes subscription entry depending on given (subscription) values.
* The receive lists of a CAN device are protected by a per-device lock,
* so the subscription is found even when the device has been moved to
* another network namespace after can_rx_register(). The caller has to
* ensure that @dev stays valid, e.g. by holding a reference to @dev or
* RTNL. @net should be the namespace that has been used for
* can_rx_register(). It selects the 'any' CAN device lists for
* @dev == NULL and is otherwise only used for the receive list
* statistics, which become imprecise when another namespace is passed.
*/
void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
canid_t mask, void (*func)(struct sk_buff *, void *),
@ -519,15 +531,13 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
struct can_dev_rcv_lists *dev_rcv_lists;
if (dev && dev->type != ARPHRD_CAN)
if (dev && !can_get_ml_priv(dev))
return;
if (dev && !net_eq(net, dev_net(dev)))
return;
spin_lock_bh(&net->can.rcvlists_lock);
dev_rcv_lists = can_dev_rcv_lists_find(net, dev);
spin_lock_bh(&dev_rcv_lists->lock);
rcv_list = can_rcv_list_find(&can_id, &mask, dev_rcv_lists);
/* Search the receiver list for the item to delete. This should
@ -547,26 +557,26 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id,
* a warning here.
*/
if (!rcv) {
spin_unlock_bh(&dev_rcv_lists->lock);
pr_warn("can: receive list entry not found for dev %s, id %03X, mask %03X\n",
DNAME(dev), can_id, mask);
goto out;
return;
}
hlist_del_rcu(&rcv->list);
dev_rcv_lists->entries--;
spin_unlock_bh(&dev_rcv_lists->lock);
spin_lock_bh(&net->can.rcvlists_lock);
if (rcv_lists_stats->rcv_entries > 0)
rcv_lists_stats->rcv_entries--;
out:
spin_unlock_bh(&net->can.rcvlists_lock);
/* schedule the receiver item for deletion */
if (rcv) {
if (rcv->sk)
sock_hold(rcv->sk);
call_rcu(&rcv->rcu, can_rx_delete_receiver);
}
if (rcv->sk)
sock_hold(rcv->sk);
call_rcu(&rcv->rcu, can_rx_delete_receiver);
}
EXPORT_SYMBOL(can_rx_unregister);
@ -684,8 +694,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
{
struct can_skb_ext *csx = can_skb_ext_find(skb);
if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
!csx || !can_is_can_skb(skb))) {
if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_can_skb(skb))) {
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n",
dev->type, skb->len);
@ -710,8 +719,7 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
{
struct can_skb_ext *csx = can_skb_ext_find(skb);
if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
!csx || !can_is_canfd_skb(skb))) {
if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_canfd_skb(skb))) {
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n",
dev->type, skb->len);
@ -736,8 +744,7 @@ static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
{
struct can_skb_ext *csx = can_skb_ext_find(skb);
if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) ||
!csx || !can_is_canxl_skb(skb))) {
if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_canxl_skb(skb))) {
pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n",
dev->type, skb->len);
@ -826,6 +833,7 @@ static int can_pernet_init(struct net *net)
net->can.rx_alldev_list = kzalloc_obj(*net->can.rx_alldev_list);
if (!net->can.rx_alldev_list)
goto out;
spin_lock_init(&net->can.rx_alldev_list->lock);
net->can.pkg_stats = kzalloc_obj(*net->can.pkg_stats);
if (!net->can.pkg_stats)
goto out_free_rx_alldev_list;

View File

@ -55,7 +55,7 @@ struct receiver {
atomic_long_t matches;
void (*func)(struct sk_buff *skb, void *data);
void *data;
char *ident;
u64 ino;
struct sock *sk;
struct rcu_head rcu;
};

View File

@ -54,6 +54,7 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/can-ml.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/bcm.h>
@ -220,9 +221,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
struct bcm_sock *bo = bcm_sk(sk);
struct bcm_op *op;
seq_printf(m, ">>> socket %pK", sk->sk_socket);
seq_printf(m, " / sk %pK", sk);
seq_printf(m, " / bo %pK", bo);
seq_printf(m, ">>> sock inode %s", bo->procname);
seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex));
seq_printf(m, " <<<\n");
@ -963,7 +962,7 @@ static void bcm_remove_op(struct bcm_op *op)
static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
{
if (op->rx_reg_dev == dev) {
can_rx_unregister(dev_net(dev), dev, op->can_id,
can_rx_unregister(sock_net(op->sk), dev, op->can_id,
REGMASK(op->can_id), bcm_rx_handler, op);
/* mark as removed subscription */
@ -989,21 +988,10 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
/* disable automatic timer on frame reception */
op->flags |= RX_NO_AUTOTIMER;
/*
* Don't care if we're bound or not (due to netdev
* problems) can_rx_unregister() is always a save
* thing to do here.
*/
if (op->ifindex) {
/*
* Only remove subscriptions that had not
* been removed due to NETDEV_UNREGISTER
* in bcm_notifier()
*
* op->rx_reg_dev is a tracked reference taken
* when the subscription was registered, so it
* stays valid here even if a concurrent
* NETDEV_UNREGISTER already unlisted the dev.
/* Only remove subscriptions that had not been
* removed in bcm_notify(). op->rx_reg_dev keeps
* the device's receive lists accessible.
*/
if (op->rx_reg_dev)
bcm_rx_unreg(op->rx_reg_dev, op);
@ -1536,7 +1524,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op,
"bcm", sk);
sock_i_ino(sk), sk);
/* keep a tracked reference so that a later
* unregister can safely reach the device even
@ -1560,7 +1548,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
} else {
err = can_rx_register(sock_net(sk), NULL, op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op, "bcm", sk);
bcm_rx_handler, op,
sock_i_ino(sk), sk);
}
if (err) {
@ -1719,7 +1708,7 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
goto out_release;
}
if (dev->type != ARPHRD_CAN) {
if (!can_get_ml_priv(dev)) {
dev_put(dev);
ret = -ENODEV;
goto out_release;
@ -1867,7 +1856,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dev->type != ARPHRD_CAN)
if (!can_get_ml_priv(dev))
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
@ -1935,6 +1924,7 @@ static int bcm_release(struct socket *sock)
list_del(&bo->notifier);
spin_unlock(&bcm_notifier_lock);
/* bcm_notify() can not access this socket anymore */
lock_sock(sk);
#if IS_ENABLED(CONFIG_PROC_FS)
@ -1948,29 +1938,20 @@ static int bcm_release(struct socket *sock)
bcm_remove_op(op);
}
list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
/*
* Don't care if we're bound or not (due to netdev problems)
* can_rx_unregister() is always a save thing to do here.
*/
list_for_each_entry(op, &bo->rx_ops, list) {
if (op->ifindex) {
/*
* Only remove subscriptions that had not
* been removed due to NETDEV_UNREGISTER
* in bcm_notifier()
*
* op->rx_reg_dev is a tracked reference taken
* when the subscription was registered, so it
* stays valid here even if a concurrent
* NETDEV_UNREGISTER already unlisted the device.
/* Only remove subscriptions that had not been removed
* in bcm_notify(). op->rx_reg_dev keeps the device's
* receive lists accessible.
*/
if (op->rx_reg_dev)
bcm_rx_unreg(op->rx_reg_dev, op);
} else
} else {
can_rx_unregister(net, NULL, op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op);
}
cond_resched();
}
synchronize_rcu();
@ -2024,7 +2005,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
ret = -ENODEV;
goto fail;
}
if (dev->type != ARPHRD_CAN) {
if (!can_get_ml_priv(dev)) {
dev_put(dev);
ret = -ENODEV;
goto fail;
@ -2040,8 +2021,9 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
#if IS_ENABLED(CONFIG_PROC_FS)
if (net->can.bcmproc_dir) {
/* unique socket address as filename */
sprintf(bo->procname, "%llu", sock_i_ino(sk));
/* use unique socket inode number as filename */
snprintf(bo->procname, sizeof(bo->procname),
"%llu", sock_i_ino(sk));
bo->bcm_proc_read = proc_create_net_single(bo->procname, 0644,
net->can.bcmproc_dir,
bcm_proc_show, sk);

View File

@ -52,6 +52,7 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/can-ml.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/gw.h>
@ -579,7 +580,7 @@ static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj)
{
return can_rx_register(net, gwj->src.dev, gwj->ccgw.filter.can_id,
gwj->ccgw.filter.can_mask, can_can_gw_rcv,
gwj, "gw", NULL);
gwj, 0, NULL);
}
static inline void cgw_unregister_filter(struct net *net, struct cgw_job *gwj)
@ -612,7 +613,7 @@ static int cgw_notifier(struct notifier_block *nb,
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct net *net = dev_net(dev);
if (dev->type != ARPHRD_CAN)
if (!can_get_ml_priv(dev))
return NOTIFY_DONE;
if (msg == NETDEV_UNREGISTER) {
@ -1163,7 +1164,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!gwj->src.dev)
goto out;
if (gwj->src.dev->type != ARPHRD_CAN)
if (!can_get_ml_priv(gwj->src.dev))
goto out;
gwj->dst.dev = __dev_get_by_index(net, gwj->ccgw.dst_idx);
@ -1171,7 +1172,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!gwj->dst.dev)
goto out;
if (gwj->dst.dev->type != ARPHRD_CAN)
if (!can_get_ml_priv(gwj->dst.dev))
goto out;
/* is sending the skb back to the incoming interface intended? */

View File

@ -65,6 +65,7 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/can.h>
#include <linux/can/can-ml.h>
#include <linux/can/core.h>
#include <linux/can/skb.h>
#include <linux/can/isotp.h>
@ -755,6 +756,14 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
if (skb->len != so->ll.mtu)
return;
/* check for correct CAN CC/FD frame content */
if (so->ll.mtu == CAN_MTU) {
if (!can_is_can_skb(skb))
return;
} else if (!can_is_canfd_skb(skb)) {
return;
}
cf = (struct canfd_frame *)skb->data;
/* if enabled: check reception of my configured extended address */
@ -1123,7 +1132,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
int off;
int err;
if (!so->bound || READ_ONCE(so->tx.state) == ISOTP_SHUTDOWN)
if (!READ_ONCE(so->bound) || READ_ONCE(so->tx.state) == ISOTP_SHUTDOWN)
return -EADDRNOTAVAIL;
/* claim the socket under so->rx_lock: this serializes the claim
@ -1168,7 +1177,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
/* so->bound is only checked once above - a wakeup may have
* unbound/rebound the socket meanwhile => recheck
*/
if (!so->bound) {
if (!READ_ONCE(so->bound)) {
err = -EADDRNOTAVAIL;
goto err_out_drop;
}
@ -1414,7 +1423,7 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK | MSG_CMSG_COMPAT))
return -EINVAL;
if (!so->bound)
if (!READ_ONCE(so->bound))
return -EADDRNOTAVAIL;
skb = skb_recv_datagram(sk, flags, &ret);
@ -1488,11 +1497,11 @@ 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
* tracked reference so->dev is taken at bind() time with rtnl_lock
* the tracked reference so->dev keeps the device's receive lists
* accessible, even after a namespace change
*/
if (so->bound && so->dev) {
if (isotp_register_rxid(so))
@ -1507,11 +1516,9 @@ static int isotp_release(struct socket *sock)
}
so->ifindex = 0;
so->bound = 0;
WRITE_ONCE(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
@ -1541,7 +1548,6 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
struct sock *sk = sock->sk;
struct isotp_sock *so = isotp_sk(sk);
struct net *net = sock_net(sk);
int ifindex;
struct net_device *dev;
canid_t tx_id = addr->can_addr.tp.tx_id;
canid_t rx_id = addr->can_addr.tp.rx_id;
@ -1579,7 +1585,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
if (!addr->can_ifindex)
return -ENODEV;
rtnl_lock();
/* lock_sock() serializes the binding with isotp_notify() */
lock_sock(sk);
if (so->bound) {
@ -1605,61 +1611,83 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l
goto out;
}
dev = dev_get_by_index(net, addr->can_ifindex);
if (!dev) {
/* Publish the device inside the RCU section of the lookup: When it
* is unlisted concurrently, either isotp_notify() sees so->dev after
* synchronize_net() or the lookup fails. Check the device before
* publishing it.
*/
rcu_read_lock();
dev = dev_get_by_index_rcu(net, addr->can_ifindex);
if (!dev || !can_get_ml_priv(dev))
err = -ENODEV;
goto out;
}
if (dev->type != ARPHRD_CAN) {
err = -ENODEV;
goto out_put_dev;
}
if (READ_ONCE(dev->mtu) < so->ll.mtu) {
else if (READ_ONCE(dev->mtu) < so->ll.mtu)
err = -EINVAL;
goto out_put_dev;
if (!err) {
dev_hold(dev);
WRITE_ONCE(so->dev, dev);
}
if (!(dev->flags & IFF_UP))
notify_enetdown = 1;
rcu_read_unlock();
if (err)
goto out;
ifindex = dev->ifindex;
if (isotp_register_rxid(so))
can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id),
isotp_rcv, sk, "isotp", sk);
/* switch to new settings */
so->ifindex = dev->ifindex;
so->rxid = rx_id;
so->txid = tx_id;
/* no consecutive frame echo skb in flight */
WRITE_ONCE(so->cfecho, 0);
/* register for echo skb's */
can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id),
isotp_rcv_echo, sk, "isotpe", sk);
/* register for echo skb's first (no echo traffic at this point) */
err = can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id),
isotp_rcv_echo, sk, sock_i_ino(sk), sk);
if (err)
goto out_put_dev;
/* switch to new settings */
so->ifindex = ifindex;
so->rxid = rx_id;
so->txid = tx_id;
so->bound = 1;
if (isotp_register_rxid(so)) {
err = can_rx_register(net, dev, rx_id, SINGLE_MASK(rx_id),
isotp_rcv, sk, sock_i_ino(sk), sk);
if (err) {
/* unregister echo skb subscription */
can_rx_unregister(net, dev, tx_id, SINGLE_MASK(tx_id),
isotp_rcv_echo, sk);
goto out_put_dev;
}
}
WRITE_ONCE(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);
/* Either isotp_notify() sees so->dev on NETDEV_DOWN or we see the
* cleared IFF_UP, pairs with isotp_notify()
*/
smp_mb();
if (!(READ_ONCE(dev->flags) & IFF_UP))
notify_enetdown = 1;
out_put_dev:
/* remove potential reference from dev_get_by_index() */
/* revert so->ifindex and so->dev on failed bind() */
if (err) {
so->ifindex = 0;
WRITE_ONCE(so->dev, NULL);
}
/* remove reference from the device lookup */
dev_put(dev);
out:
release_sock(sk);
rtnl_unlock();
if (notify_enetdown) {
sk->sk_err = ENETDOWN;
if (!sock_flag(sk, SOCK_DEAD))
sk_error_report(sk);
}
release_sock(sk);
return err;
}
@ -1681,8 +1709,8 @@ static int isotp_getname(struct socket *sock, struct sockaddr *uaddr, int peer)
return ISOTP_MIN_NAMELEN;
}
static int isotp_setsockopt_locked(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
static int isotp_setsockopt_locked(struct socket *sock, int optname,
const void *val)
{
struct sock *sk = sock->sk;
struct isotp_sock *so = isotp_sk(sk);
@ -1693,11 +1721,7 @@ static int isotp_setsockopt_locked(struct socket *sock, int level, int optname,
switch (optname) {
case CAN_ISOTP_OPTS:
if (optlen != sizeof(struct can_isotp_options))
return -EINVAL;
if (copy_from_sockptr(&so->opt, optval, optlen))
return -EFAULT;
memcpy(&so->opt, val, sizeof(so->opt));
/* no separate rx_ext_address is given => use ext_address */
if (!(so->opt.flags & CAN_ISOTP_RX_EXT_ADDR))
@ -1722,55 +1746,37 @@ static int isotp_setsockopt_locked(struct socket *sock, int level, int optname,
break;
case CAN_ISOTP_RECV_FC:
if (optlen != sizeof(struct can_isotp_fc_options))
return -EINVAL;
if (copy_from_sockptr(&so->rxfc, optval, optlen))
return -EFAULT;
memcpy(&so->rxfc, val, sizeof(so->rxfc));
break;
case CAN_ISOTP_TX_STMIN:
if (optlen != sizeof(u32))
return -EINVAL;
if (copy_from_sockptr(&so->force_tx_stmin, optval, optlen))
return -EFAULT;
so->force_tx_stmin = *(const u32 *)val;
break;
case CAN_ISOTP_RX_STMIN:
if (optlen != sizeof(u32))
return -EINVAL;
if (copy_from_sockptr(&so->force_rx_stmin, optval, optlen))
return -EFAULT;
so->force_rx_stmin = *(const u32 *)val;
break;
case CAN_ISOTP_LL_OPTS:
if (optlen == sizeof(struct can_isotp_ll_options)) {
struct can_isotp_ll_options ll;
case CAN_ISOTP_LL_OPTS: {
const struct can_isotp_ll_options *ll = val;
if (copy_from_sockptr(&ll, optval, optlen))
return -EFAULT;
/* check for correct ISO 11898-1 DLC data length */
if (ll.tx_dl != padlen(ll.tx_dl))
return -EINVAL;
if (ll.mtu != CAN_MTU && ll.mtu != CANFD_MTU)
return -EINVAL;
if (ll.mtu == CAN_MTU &&
(ll.tx_dl > CAN_MAX_DLEN || ll.tx_flags != 0))
return -EINVAL;
memcpy(&so->ll, &ll, sizeof(ll));
/* set ll_dl for tx path to similar place as for rx */
so->tx.ll_dl = ll.tx_dl;
} else {
/* check for correct ISO 11898-1 DLC data length */
if (ll->tx_dl != padlen(ll->tx_dl))
return -EINVAL;
}
if (ll->mtu != CAN_MTU && ll->mtu != CANFD_MTU)
return -EINVAL;
if (ll->mtu == CAN_MTU &&
(ll->tx_dl > CAN_MAX_DLEN || ll->tx_flags != 0))
return -EINVAL;
memcpy(&so->ll, ll, sizeof(*ll));
/* set ll_dl for tx path to similar place as for rx */
so->tx.ll_dl = ll->tx_dl;
break;
}
default:
ret = -ENOPROTOOPT;
@ -1784,13 +1790,49 @@ static int isotp_setsockopt(struct socket *sock, int level, int optname,
{
struct sock *sk = sock->sk;
union {
struct can_isotp_options opt;
struct can_isotp_fc_options rxfc;
struct can_isotp_ll_options ll;
u32 stmin;
} val;
unsigned int size;
int ret;
if (level != SOL_CAN_ISOTP)
return -EINVAL;
/* copy the option values from user space before lock_sock() */
switch (optname) {
case CAN_ISOTP_OPTS:
size = sizeof(val.opt);
break;
case CAN_ISOTP_RECV_FC:
size = sizeof(val.rxfc);
break;
case CAN_ISOTP_TX_STMIN:
case CAN_ISOTP_RX_STMIN:
size = sizeof(val.stmin);
break;
case CAN_ISOTP_LL_OPTS:
size = sizeof(val.ll);
break;
default:
return -ENOPROTOOPT;
}
if (optlen != size)
return -EINVAL;
if (copy_from_sockptr(&val, optval, size))
return -EFAULT;
lock_sock(sk);
ret = isotp_setsockopt_locked(sock, level, optname, optval, optlen);
ret = isotp_setsockopt_locked(sock, optname, &val);
release_sock(sk);
return ret;
}
@ -1855,12 +1897,21 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
if (!net_eq(dev_net(dev), sock_net(sk)))
return;
if (so->dev != dev)
if (msg == NETDEV_DOWN)
smp_mb(); /* pairs with isotp_bind(), see raw_notify() */
/* lockless fast path, see raw_notify() */
if (READ_ONCE(so->dev) != dev)
return;
switch (msg) {
case NETDEV_UNREGISTER:
lock_sock(sk);
if (so->dev != dev) {
release_sock(sk);
break;
}
/* remove current filters & unregister */
if (so->bound) {
if (isotp_register_rxid(so))
@ -1875,16 +1926,19 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
}
so->ifindex = 0;
so->bound = 0;
so->dev = NULL;
release_sock(sk);
WRITE_ONCE(so->bound, 0);
WRITE_ONCE(so->dev, NULL);
sk->sk_err = ENODEV;
if (!sock_flag(sk, SOCK_DEAD))
sk_error_report(sk);
release_sock(sk);
break;
case NETDEV_DOWN:
if (!READ_ONCE(so->bound))
break;
sk->sk_err = ENETDOWN;
if (!sock_flag(sk, SOCK_DEAD))
sk_error_report(sk);
@ -1897,7 +1951,7 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dev->type != ARPHRD_CAN)
if (!can_get_ml_priv(dev))
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;

View File

@ -184,7 +184,7 @@ static int j1939_can_rx_register(struct j1939_priv *priv)
j1939_priv_get(priv);
ret = can_rx_register(dev_net(ndev), ndev, J1939_CAN_ID, J1939_CAN_MASK,
j1939_can_recv, priv, "j1939", NULL);
j1939_can_recv, priv, 0, NULL);
if (ret < 0) {
j1939_priv_put(priv);
return ret;

View File

@ -76,16 +76,39 @@ static const char rx_list_name[][8] = {
* af_can statistics stuff
*/
static void can_reset_pkg_stats(struct can_pkg_stats *pkg_stats)
{
atomic_long_set(&pkg_stats->rx_frames, 0);
atomic_long_set(&pkg_stats->tx_frames, 0);
atomic_long_set(&pkg_stats->matches, 0);
pkg_stats->total_rx_rate = 0;
pkg_stats->total_tx_rate = 0;
pkg_stats->total_rx_match_ratio = 0;
pkg_stats->current_rx_rate = 0;
pkg_stats->current_tx_rate = 0;
pkg_stats->current_rx_match_ratio = 0;
pkg_stats->max_rx_rate = 0;
pkg_stats->max_tx_rate = 0;
pkg_stats->max_rx_match_ratio = 0;
atomic_long_set(&pkg_stats->rx_frames_delta, 0);
atomic_long_set(&pkg_stats->tx_frames_delta, 0);
atomic_long_set(&pkg_stats->matches_delta, 0);
}
static void can_init_stats(struct net *net)
{
struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
/*
* This memset function is called from a timer context (when
* This stats reset is called from a timer context (when
* can_stattimer is active which is the default) OR in a process
* context (reading the proc_fs when can_stattimer is disabled).
*/
memset(pkg_stats, 0, sizeof(struct can_pkg_stats));
can_reset_pkg_stats(pkg_stats);
pkg_stats->jiffies_init = jiffies;
rcv_lists_stats->stats_reset++;
@ -121,29 +144,23 @@ void can_stat_update(struct timer_list *t)
long rx_frames = atomic_long_read(&pkg_stats->rx_frames);
long tx_frames = atomic_long_read(&pkg_stats->tx_frames);
long matches = atomic_long_read(&pkg_stats->matches);
long rx_frames_delta = atomic_long_read(&pkg_stats->rx_frames_delta);
long tx_frames_delta = atomic_long_read(&pkg_stats->tx_frames_delta);
long matches_delta = atomic_long_read(&pkg_stats->matches_delta);
/* fetch and clear values for 'current rate' calculation */
long rx_frames_delta = atomic_long_xchg(&pkg_stats->rx_frames_delta, 0);
long tx_frames_delta = atomic_long_xchg(&pkg_stats->tx_frames_delta, 0);
long matches_delta = atomic_long_xchg(&pkg_stats->matches_delta, 0);
/* restart counting in timer context on user request */
if (user_reset)
can_init_stats(net);
/* restart counting on jiffies overflow */
if (j < pkg_stats->jiffies_init)
can_init_stats(net);
/* prevent overflow in calc_rate() */
if (rx_frames > (LONG_MAX / HZ))
can_init_stats(net);
/* prevent overflow in calc_rate() */
if (tx_frames > (LONG_MAX / HZ))
can_init_stats(net);
/* matches overflow - very improbable */
if (matches > (LONG_MAX / 100))
/*
* Restart counting in timer context on user request, on jiffies
* overflow or to prevent overflows in calc_rate() and in the
* match ratio calculation. The local snapshots are stale after
* the reset, so skip the calculation for this interval.
*/
if (user_reset || j < pkg_stats->jiffies_init ||
rx_frames > (LONG_MAX / HZ) || tx_frames > (LONG_MAX / HZ) ||
matches > (LONG_MAX / 100)) {
can_init_stats(net);
goto out;
}
/* calc total values */
if (rx_frames)
@ -172,11 +189,7 @@ void can_stat_update(struct timer_list *t)
if (pkg_stats->max_rx_match_ratio < pkg_stats->current_rx_match_ratio)
pkg_stats->max_rx_match_ratio = pkg_stats->current_rx_match_ratio;
/* clear values for 'current rate' calculation */
atomic_long_set(&pkg_stats->tx_frames_delta, 0);
atomic_long_set(&pkg_stats->rx_frames_delta, 0);
atomic_long_set(&pkg_stats->matches_delta, 0);
out:
/* restart timer (one second) */
mod_timer(&net->can.stattimer, round_jiffies(jiffies + HZ));
}
@ -191,26 +204,32 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
struct receiver *r;
hlist_for_each_entry_rcu(r, rx_list, list) {
char symcheck[4];
char *fmt = (r->can_id & CAN_EFF_FLAG)?
" %-5s %08x %08x %pK %pK %8ld %s\n" :
" %-5s %03x %08x %pK %pK %8ld %s\n";
" %6s %08x %08x %8ld %10llu" :
" %6s %03x %08x %8ld %10llu";
seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
r->func, r->data, atomic_long_read(&r->matches),
r->ident);
atomic_long_read(&r->matches), r->ino);
/* %ps falls back to the raw text address when the symbol
* can not be resolved (KALLSYMS=n, stripped module symbols)
*/
snprintf(symcheck, sizeof(symcheck), "%ps", r->func);
if (strncmp(symcheck, "0x", 2))
seq_printf(m, " %ps\n", r->func);
else
seq_puts(m, " (unknown)\n");
}
}
static void can_print_recv_banner(struct seq_file *m)
{
/*
* can1. 00000000 00000000 00000000
* ....... 0 tp20
* device can_id can_mask matches sock_inode function
* vcan0 000 00000000 0 43798 raw_rcv [can_raw]
*/
if (IS_ENABLED(CONFIG_64BIT))
seq_puts(m, " device can_id can_mask function userdata matches ident\n");
else
seq_puts(m, " device can_id can_mask function userdata matches ident\n");
seq_puts(m, " device can_id can_mask matches sock_inode function\n");
}
static int can_stats_proc_show(struct seq_file *m, void *v)

View File

@ -85,6 +85,7 @@ struct raw_sock {
struct sock sk;
struct net_device *dev;
netdevice_tracker dev_tracker;
struct net_device *bind_dev; /* hint for raw_notify(), no reference */
struct list_head notifier;
int ifindex;
unsigned int bound:1;
@ -224,9 +225,10 @@ static int raw_enable_filters(struct net *net, struct net_device *dev,
int i;
for (i = 0; i < count; i++) {
cond_resched();
err = can_rx_register(net, dev, filter[i].can_id,
filter[i].can_mask,
raw_rcv, sk, "raw", sk);
raw_rcv, sk, sock_i_ino(sk), sk);
if (err) {
/* clean up successfully registered filters */
while (--i >= 0)
@ -247,7 +249,7 @@ static int raw_enable_errfilter(struct net *net, struct net_device *dev,
if (err_mask)
err = can_rx_register(net, dev, 0, err_mask | CAN_ERR_FLAG,
raw_rcv, sk, "raw", sk);
raw_rcv, sk, sock_i_ino(sk), sk);
return err;
}
@ -258,9 +260,11 @@ static void raw_disable_filters(struct net *net, struct net_device *dev,
{
int i;
for (i = 0; i < count; i++)
for (i = 0; i < count; i++) {
can_rx_unregister(net, dev, filter[i].can_id,
filter[i].can_mask, raw_rcv, sk);
cond_resched();
}
}
static inline void raw_disable_errfilter(struct net *net,
@ -305,16 +309,31 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,
struct net_device *dev)
{
struct sock *sk = &ro->sk;
struct net_device *bind_dev;
if (!net_eq(dev_net(dev), sock_net(sk)))
return;
if (ro->dev != dev)
if (msg == NETDEV_DOWN)
smp_mb(); /* IFF_UP is cleared before, pairs with raw_bind() */
/* Lockless fast path, ro->bind_dev covers a concurrent bind().
* Read it before ro->dev, pairs with smp_store_release() in
* raw_bind(). A stale ro->bind_dev only costs a lock_sock().
*/
bind_dev = smp_load_acquire(&ro->bind_dev);
if (READ_ONCE(ro->dev) != dev &&
(msg != NETDEV_UNREGISTER || bind_dev != dev))
return;
switch (msg) {
case NETDEV_UNREGISTER:
lock_sock(sk);
if (ro->dev != dev) {
release_sock(sk);
break;
}
/* remove current filters & unregister */
if (ro->bound) {
raw_disable_allfilters(dev_net(dev), dev, sk);
@ -326,13 +345,13 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,
ro->ifindex = 0;
ro->bound = 0;
ro->dev = NULL;
WRITE_ONCE(ro->dev, NULL);
ro->count = 0;
release_sock(sk);
sk->sk_err = ENODEV;
if (!sock_flag(sk, SOCK_DEAD))
sk_error_report(sk);
release_sock(sk);
break;
case NETDEV_DOWN:
@ -348,7 +367,7 @@ static int raw_notifier(struct notifier_block *nb, unsigned long msg,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dev->type != ARPHRD_CAN)
if (!can_get_ml_priv(dev))
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
@ -381,6 +400,7 @@ static int raw_init(struct sock *sk)
ro->bound = 0;
ro->ifindex = 0;
ro->dev = NULL;
ro->bind_dev = NULL;
/* set default filter to single entry dfilter */
ro->dfilter.can_id = 0;
@ -431,13 +451,15 @@ static int raw_release(struct socket *sock)
list_del(&ro->notifier);
spin_unlock(&raw_notifier_lock);
rtnl_lock();
lock_sock(sk);
/* remove current filters & unregister */
/* remove current filters & unregister
* the tracked reference ro->dev keeps the device's receive lists
* accessible, even after a namespace change
*/
if (ro->bound) {
if (ro->dev) {
raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk);
raw_disable_allfilters(net, ro->dev, sk);
netdev_put(ro->dev, &ro->dev_tracker);
} else {
raw_disable_allfilters(net, NULL, sk);
@ -456,7 +478,6 @@ static int raw_release(struct socket *sock)
sock->sk = NULL;
release_sock(sk);
rtnl_unlock();
sock_prot_inuse_add(net, sk->sk_prot, -1);
sock_put(sk);
@ -479,26 +500,34 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len
if (addr->can_family != AF_CAN)
return -EINVAL;
rtnl_lock();
/* lock_sock() serializes the binding with raw_notify() */
lock_sock(sk);
if (ro->bound && addr->can_ifindex == ro->ifindex)
goto out;
if (addr->can_ifindex) {
dev = dev_get_by_index(sock_net(sk), addr->can_ifindex);
/* Publish the device inside the RCU section of the lookup:
* When it is unlisted concurrently, either raw_notify() sees
* ro->bind_dev after synchronize_net() or the lookup fails.
*/
rcu_read_lock();
dev = dev_get_by_index_rcu(sock_net(sk), addr->can_ifindex);
if (dev) {
dev_hold(dev);
/* pairs with smp_load_acquire() in raw_notify() */
smp_store_release(&ro->bind_dev, dev);
}
rcu_read_unlock();
if (!dev) {
err = -ENODEV;
goto out;
}
if (dev->type != ARPHRD_CAN) {
if (!can_get_ml_priv(dev)) {
err = -ENODEV;
goto out_put_dev;
}
if (!(dev->flags & IFF_UP))
notify_enetdown = 1;
ifindex = dev->ifindex;
/* filters set by default/setsockopt */
@ -517,7 +546,7 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len
if (ro->bound) {
/* unregister old filters */
if (ro->dev) {
raw_disable_allfilters(dev_net(ro->dev),
raw_disable_allfilters(sock_net(sk),
ro->dev, sk);
/* drop reference to old ro->dev */
netdev_put(ro->dev, &ro->dev_tracker);
@ -528,24 +557,32 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len
ro->ifindex = ifindex;
ro->bound = 1;
/* bind() ok -> hold a reference for new ro->dev */
ro->dev = dev;
WRITE_ONCE(ro->dev, dev);
if (ro->dev)
netdev_hold(ro->dev, &ro->dev_tracker, GFP_KERNEL);
if (dev) {
/* Either raw_notify() sees ro->dev on NETDEV_DOWN or
* we see the cleared IFF_UP, pairs with raw_notify()
*/
smp_mb();
if (!(READ_ONCE(dev->flags) & IFF_UP))
notify_enetdown = 1;
}
}
out_put_dev:
/* remove potential reference from dev_get_by_index() */
/* remove reference from the device lookup */
dev_put(dev);
out:
release_sock(sk);
rtnl_unlock();
if (notify_enetdown) {
sk->sk_err = ENETDOWN;
if (!sock_flag(sk, SOCK_DEAD))
sk_error_report(sk);
}
release_sock(sk);
return err;
}
@ -567,58 +604,36 @@ static int raw_getname(struct socket *sock, struct sockaddr *uaddr,
}
static int raw_setsockopt_locked(struct socket *sock, int optname,
sockptr_t optval, unsigned int optlen)
const void *val, struct can_filter *filter,
int count)
{
struct sock *sk = sock->sk;
struct raw_sock *ro = raw_sk(sk);
struct can_filter *filter = NULL; /* dyn. alloc'ed filters */
struct can_filter sfilter; /* single filter */
struct net_device *dev = NULL;
can_err_mask_t err_mask = 0;
int count = 0;
can_err_mask_t err_mask;
int flag;
int err = 0;
switch (optname) {
case CAN_RAW_FILTER:
if (optlen % sizeof(struct can_filter) != 0)
return -EINVAL;
if (optlen > CAN_RAW_FILTER_MAX * sizeof(struct can_filter))
return -EINVAL;
count = optlen / sizeof(struct can_filter);
if (count > 1) {
/* filter does not fit into dfilter => alloc space */
filter = memdup_sockptr(optval, optlen);
if (IS_ERR(filter))
return PTR_ERR(filter);
} else if (count == 1) {
if (copy_from_sockptr(&sfilter, optval, sizeof(sfilter)))
return -EFAULT;
}
/* @filter has been copied by raw_setsockopt(). It is linked
* to the socket on success and freed by the caller on error.
*
* The reg_state check is only a shortcut: On a concurrent
* unregistration or namespace change raw_notify() waits for
* lock_sock() and removes the filters set here.
*/
dev = ro->dev;
if (ro->bound && dev && dev->reg_state != NETREG_REGISTERED) {
if (count > 1)
kfree(filter);
if (ro->bound && dev &&
READ_ONCE(dev->reg_state) != NETREG_REGISTERED)
return -ENODEV;
}
if (ro->bound) {
/* (try to) register the new filters */
if (count == 1)
err = raw_enable_filters(sock_net(sk), dev, sk,
&sfilter, 1);
else
err = raw_enable_filters(sock_net(sk), dev, sk,
filter, count);
if (err) {
if (count > 1)
kfree(filter);
err = raw_enable_filters(sock_net(sk), dev, sk, filter,
count);
if (err)
return err;
}
/* remove old filter registrations */
raw_disable_filters(sock_net(sk), dev, sk, ro->filter,
@ -632,7 +647,7 @@ static int raw_setsockopt_locked(struct socket *sock, int optname,
/* link new filters to the socket */
if (count == 1) {
/* copy filter data for single filter */
ro->dfilter = sfilter;
ro->dfilter = *filter;
filter = &ro->dfilter;
}
ro->filter = filter;
@ -640,16 +655,12 @@ static int raw_setsockopt_locked(struct socket *sock, int optname,
break;
case CAN_RAW_ERR_FILTER:
if (optlen != sizeof(err_mask))
return -EINVAL;
if (copy_from_sockptr(&err_mask, optval, optlen))
return -EFAULT;
err_mask &= CAN_ERR_MASK;
err_mask = *(const can_err_mask_t *)val & CAN_ERR_MASK;
/* lockless shortcut, see CAN_RAW_FILTER */
dev = ro->dev;
if (ro->bound && dev && dev->reg_state != NETREG_REGISTERED)
if (ro->bound && dev &&
READ_ONCE(dev->reg_state) != NETREG_REGISTERED)
return -ENODEV;
/* remove current error mask */
@ -671,31 +682,15 @@ static int raw_setsockopt_locked(struct socket *sock, int optname,
break;
case CAN_RAW_LOOPBACK:
if (optlen != sizeof(flag))
return -EINVAL;
if (copy_from_sockptr(&flag, optval, optlen))
return -EFAULT;
ro->loopback = !!flag;
ro->loopback = !!*(const int *)val;
break;
case CAN_RAW_RECV_OWN_MSGS:
if (optlen != sizeof(flag))
return -EINVAL;
if (copy_from_sockptr(&flag, optval, optlen))
return -EFAULT;
ro->recv_own_msgs = !!flag;
ro->recv_own_msgs = !!*(const int *)val;
break;
case CAN_RAW_FD_FRAMES:
if (optlen != sizeof(flag))
return -EINVAL;
if (copy_from_sockptr(&flag, optval, optlen))
return -EFAULT;
flag = *(const int *)val;
/* Enabling CAN XL includes CAN FD */
if (ro->xl_frames && !flag)
@ -705,13 +700,7 @@ static int raw_setsockopt_locked(struct socket *sock, int optname,
break;
case CAN_RAW_XL_FRAMES:
if (optlen != sizeof(flag))
return -EINVAL;
if (copy_from_sockptr(&flag, optval, optlen))
return -EFAULT;
ro->xl_frames = !!flag;
ro->xl_frames = !!*(const int *)val;
/* Enabling CAN XL includes CAN FD */
if (ro->xl_frames)
@ -719,11 +708,7 @@ static int raw_setsockopt_locked(struct socket *sock, int optname,
break;
case CAN_RAW_XL_VCID_OPTS:
if (optlen != sizeof(ro->raw_vcid_opts))
return -EINVAL;
if (copy_from_sockptr(&ro->raw_vcid_opts, optval, optlen))
return -EFAULT;
memcpy(&ro->raw_vcid_opts, val, sizeof(ro->raw_vcid_opts));
/* prepare 32 bit values for handling in hot path */
ro->tx_vcid_shifted = ro->raw_vcid_opts.tx_vcid << CANXL_VCID_OFFSET;
@ -732,13 +717,7 @@ static int raw_setsockopt_locked(struct socket *sock, int optname,
break;
case CAN_RAW_JOIN_FILTERS:
if (optlen != sizeof(flag))
return -EINVAL;
if (copy_from_sockptr(&flag, optval, optlen))
return -EFAULT;
ro->join_filters = !!flag;
ro->join_filters = !!*(const int *)val;
break;
default:
@ -751,18 +730,83 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
struct can_filter *filter = NULL; /* dyn. alloc'ed filters */
struct can_filter sfilter; /* single filter */
union {
can_err_mask_t err_mask;
int flag;
struct can_raw_vcid_options vcid_opts;
} val;
unsigned int size = 0;
int count = 0;
int err;
if (level != SOL_CAN_RAW)
return -EINVAL;
rtnl_lock();
/* Copy the option values from user space before lock_sock(), so a
* stalled copy can not block raw_notify() waiting for lock_sock()
* under RTNL.
*/
switch (optname) {
case CAN_RAW_FILTER:
if (optlen % sizeof(struct can_filter) != 0)
return -EINVAL;
if (optlen > CAN_RAW_FILTER_MAX * sizeof(struct can_filter))
return -EINVAL;
count = optlen / sizeof(struct can_filter);
if (count > 1) {
/* filter does not fit into dfilter => alloc space */
filter = memdup_sockptr(optval, optlen);
if (IS_ERR(filter))
return PTR_ERR(filter);
} else if (count == 1) {
if (copy_from_sockptr(&sfilter, optval, sizeof(sfilter)))
return -EFAULT;
filter = &sfilter;
}
break;
case CAN_RAW_ERR_FILTER:
size = sizeof(val.err_mask);
break;
case CAN_RAW_XL_VCID_OPTS:
size = sizeof(val.vcid_opts);
break;
case CAN_RAW_LOOPBACK:
case CAN_RAW_RECV_OWN_MSGS:
case CAN_RAW_FD_FRAMES:
case CAN_RAW_XL_FRAMES:
case CAN_RAW_JOIN_FILTERS:
size = sizeof(val.flag);
break;
default:
return -ENOPROTOOPT;
}
if (size) {
if (optlen != size)
return -EINVAL;
if (copy_from_sockptr(&val, optval, size))
return -EFAULT;
}
lock_sock(sk);
err = raw_setsockopt_locked(sock, optname, optval, optlen);
err = raw_setsockopt_locked(sock, optname, &val, filter, count);
release_sock(sk);
rtnl_unlock();
/* on error free the filters allocated for CAN_RAW_FILTER above */
if (err && count > 1)
kfree(filter);
return err;
}
@ -784,6 +828,7 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case CAN_RAW_FILTER: {
struct can_filter *filter = NULL;
int err = 0;
lock_sock(sk);
@ -798,15 +843,22 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
} else {
if (len > fsize)
len = fsize;
if (copy_to_iter(ro->filter, len,
&opt->iter_out) != len)
err = -EFAULT;
/* copy to user space after release_sock() */
filter = kmemdup(ro->filter, len, GFP_KERNEL);
if (!filter)
err = -ENOMEM;
}
} else {
len = 0;
}
release_sock(sk);
if (filter) {
if (copy_to_iter(filter, len, &opt->iter_out) != len)
err = -EFAULT;
kfree(filter);
}
if (!err)
opt->optlen = len;
return err;

View File

@ -4320,7 +4320,9 @@ static enum skb_drop_reason qdisc_pkt_len_segs_init(struct sk_buff *skb)
if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
const struct tcphdr *th;
if (!pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr)))
/* A header in front of skb->data gives a negative offset. */
if ((int)hdr_len < 0 ||
!pskb_may_pull(skb, hdr_len + sizeof(struct tcphdr)))
return SKB_DROP_REASON_SKB_BAD_GSO;
th = (const struct tcphdr *)(skb->data + hdr_len);
@ -7073,16 +7075,22 @@ static void __skb_defer_free_flush(struct skb_defer_node *sdn, int budget)
{
struct llist_node *free_list;
struct sk_buff *skb, *next;
long n = 0;
if (llist_empty(&sdn->defer_list))
return;
atomic_long_set(&sdn->defer_count, 0);
free_list = llist_del_all(&sdn->defer_list);
llist_for_each_entry_safe(skb, next, free_list, ll_node) {
prefetch(next);
napi_consume_skb(skb, budget);
n++;
}
/* Subtract exactly what was drained. Never store an absolute value:
* mixing one with the relative updates in skb_attempt_defer_free()
* lets the counter go negative, and it is read as unsigned there.
*/
atomic_long_sub(n, &sdn->defer_count);
}
void skb_defer_node_flush(struct skb_defer_node *sdn)
@ -7389,6 +7397,13 @@ static void napi_stop_kthread(struct napi_struct *napi)
{
unsigned long val, new;
/* Instance is disabled, we can immediately stop the kthread */
if (test_bit(NAPI_STATE_DISABLED, &napi->state)) {
clear_bit(NAPI_STATE_THREADED, &napi->state);
clear_bit(NAPI_STATE_THREADED_BUSY_POLL, &napi->state);
goto stop;
}
/* Wait until the napi STATE_THREADED is unset. */
while (true) {
val = READ_ONCE(napi->state);
@ -7419,6 +7434,7 @@ static void napi_stop_kthread(struct napi_struct *napi)
msleep(20);
}
stop:
kthread_stop(napi->thread);
napi->thread = NULL;
}
@ -7814,6 +7830,7 @@ void netif_napi_add_weight_locked(struct net_device *dev,
napi->list_owner = -1;
set_bit(NAPI_STATE_SCHED, &napi->state);
set_bit(NAPI_STATE_NPSVC, &napi->state);
set_bit(NAPI_STATE_DISABLED, &napi->state);
netif_napi_dev_list_add(dev, napi);
/* default settings from sysfs are applied to all NAPIs. any per-NAPI
@ -7850,7 +7867,8 @@ void napi_disable_locked(struct napi_struct *n)
val = READ_ONCE(n->state);
}
new = val | NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC;
new = val | NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC |
NAPIF_STATE_DISABLED;
new &= ~(NAPIF_STATE_THREADED |
NAPIF_STATE_THREADED_BUSY_POLL |
NAPIF_STATE_PREFER_BUSY_POLL);
@ -7895,7 +7913,8 @@ void napi_enable_locked(struct napi_struct *n)
do {
BUG_ON(!test_bit(NAPI_STATE_SCHED, &val));
new = val & ~(NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC);
new = val & ~(NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC |
NAPIF_STATE_DISABLED);
if (n->dev->threaded && n->thread)
new |= NAPIF_STATE_THREADED;
} while (!try_cmpxchg(&n->state, &val, new));

View File

@ -8114,7 +8114,7 @@ BPF_CALL_3(bpf_sk_assign, struct sk_buff *, skb, struct sock *, sk, u64, flags)
if (sk_unhashed(sk))
return -EOPNOTSUPP;
if (sk_is_refcounted(sk) &&
unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
unlikely(!refcount_inc_not_zero_acquire(&sk->sk_refcnt)))
return -ENOENT;
skb_orphan(skb);

View File

@ -6858,7 +6858,7 @@ int skb_mpls_dec_ttl(struct sk_buff *skb)
lse = be32_to_cpu(mpls_hdr(skb)->label_stack_entry);
ttl = (lse & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT;
if (!--ttl)
if (!ttl || !--ttl)
return -EINVAL;
lse &= ~MPLS_LS_TTL_MASK;
@ -7499,8 +7499,14 @@ nodefer: kfree_skb_napi_cache(skb);
defer_max = READ_ONCE(net_hotdata.sysctl_skb_defer_max);
defer_count = atomic_long_inc_return(&sdn->defer_count);
if (defer_count >= defer_max)
if (defer_count > defer_max) {
/* Undo the reservation. An llist_add() does not release one --
* the skb stays charged until a flush subtracts the batch that
* contains it -- so a rejected free must undo its own.
*/
atomic_long_dec(&sdn->defer_count);
goto nodefer;
}
llist_add(&skb->ll_node, &sdn->defer_list);
@ -7509,8 +7515,13 @@ nodefer: kfree_skb_napi_cache(skb);
return;
}
/* Send an IPI every time queue reaches half capacity. */
kick = (defer_count - 1) == (defer_max >> 1);
/* Half capacity, plus the skb that fills the queue. Equality alone can
* be consumed early -- if the producer holding the kick value publishes
* first, its purge drains only that skb and the reservations published
* after it match nothing -- which would leave a full queue with nothing
* pending.
*/
kick = (defer_count - 1) == (defer_max >> 1) || defer_count == defer_max;
/* Make sure to trigger NET_RX_SOFTIRQ on the remote CPU
* if we are unlucky enough (this seems very unlikely).

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