mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
Including fixes from Netfilter, Bluetooth, IPSec and WiFi.
Previous releases - regressions:
- netfilter: hold reference on ct until flow is released
- bridge:
- move switchdev call outside rcu
- vlan: fix bugs caused by switchdev deletion errors
- wifi:
- mac80211: reset state when starting AP fails
- cfg80211: don't free driver-owned scan requests
- tcp: don't call skb_clone_and_charge_r() for close()d listener in tcp_v6_do_rcv().
- mptcp: return sk_wait_data() errors from recvmsg()
- xfrm: serialize state GC with device state flush
- drop_monitor: synchronize tracepoint unregistration on error path
- bluetooth:
- eir: validate service data length before reading UUID
- hci_sync: serialize local codec list cleanup
- RFCOMM: avoid socket lock inversion in listener cleanup
- eth: lan743x: fix RX checksum use-after-free
- eth: mvpp2: prevent buffer overflow in page_pool allocation
Previous releases - always broken:
- core: lock the socket in sock_gettstamp()
- neighbour: enforce min/max to NDTPA_INTERVAL_PROBE_TIME_MS.
- sched: codel: bound the dropping loop per dequeue call
- wifi: mac80211: include TIM bitmap control for buffered S1G mcast traffic
- psp: avoid conflicts with skb->decrypted and sk_validate_xmit_skb()
- xfrm: fix stack OOB read in iptfs_skb_reset_frag_walk()
- bluetooth: hci_qca: do not write to the serial port after it is closed
- dsa: mxl862xx: disable the stats poll on teardown
- eth: stmmac: fix TSO header length truncation
- eth: ip_tunnel: initialize `options_len` before referencing options
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-----BEGIN PGP SIGNATURE-----
iQJKBAABCgA0FiEEg1AjqC77wbdLX2LbKSR5jcyPE6QFAmqsEOsWHHBhb2xvLmFi
ZW5pQGdtYWlsLmNvbQAKCRApJHmNzI8TpKMnD/4vxx/YloxnyDssUB95WcTfiHau
XD+YDfTTf4Qy3DwKnMiesZ4w2547FXG+LwJZGpAGWpRSE99OawFHvx5gyn3Vf4IU
HEsOuZEYMwhSeeMJxGdCg8K6McNEQx+aAD7D8gLoisnJr/DCKBJtxFgKVEjaKUfP
aCG+FmbBqdS7hwBVbYREwmqwQSMnNzRWLd7/10/oYMcLfvgEsIkZisRErAW2BgZj
mzGw/IcG+QRldDPGDwLwLzfEG9o1a2JctSRrQ3uLHZ3VOdmpnSkmf25s2IaEFAn6
xfIhGPMgYIBDrakn/Ci4fAF0L98FtBq4Sa21HlvPMBst7rcce5x49ddSlIUWxRVZ
Fbvs/0IMN0cEpYGbVJxE8iF3yo+t8XvsMdGS1JXd/ycaL9lpF+9gCzNvChSxba3N
ik7BGAmlg76rqMuzeeMbWqMCmOcCBhQsb7iZXjNStJoiVY+UT2QfgvJ1TqF8Qrar
Eu/xFkaqk8i/7jrx4ujceg9XpRt1Y3Y3Pq0sgdzlzTm162AV/kg1fvwHc6ORIML7
71XpBSGvjyTHoh95ob/w3/5fec/ekzvWlCBL/cYIwBJ4R6n7Vk5e0Y1yZDffPSo3
xQR0r4YdLewkjQdtnGEih6FSyWsu6nYpVSuwHbof1bQSzvlIM6TAabJmtJckFTld
1bR2C9UVw5mQYMy8PA==
=Gw4S
-----END PGP SIGNATURE-----
Merge tag 'net-7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Pull networking fixes from Paolo Abeni:
"Including fixes from Netfilter, Bluetooth, IPSec and WiFi.
Previous releases - regressions:
- netfilter: hold reference on ct until flow is released
- bridge:
- move switchdev call outside rcu
- vlan: fix bugs caused by switchdev deletion errors
- wifi:
- mac80211: reset state when starting AP fails
- cfg80211: don't free driver-owned scan requests
- tcp: don't call skb_clone_and_charge_r() for close()d listener in
tcp_v6_do_rcv()
- mptcp: return sk_wait_data() errors from recvmsg()
- xfrm: serialize state GC with device state flush
- drop_monitor: synchronize tracepoint unregistration on error path
- bluetooth:
- eir: validate service data length before reading UUID
- hci_sync: serialize local codec list cleanup
- RFCOMM: avoid socket lock inversion in listener cleanup
- eth:
- lan743x: fix RX checksum use-after-free
- mvpp2: prevent buffer overflow in page_pool allocation
Previous releases - always broken:
- core: lock the socket in sock_gettstamp()
- neighbour: enforce min/max to NDTPA_INTERVAL_PROBE_TIME_MS.
- sched: codel: bound the dropping loop per dequeue call
- wifi: mac80211: include TIM bitmap control for buffered S1G mcast
traffic
- psp: avoid conflicts with skb->decrypted and sk_validate_xmit_skb()
- xfrm: fix stack OOB read in iptfs_skb_reset_frag_walk()
- bluetooth: hci_qca: do not write to the serial port after it is
closed
- dsa: mxl862xx: disable the stats poll on teardown
- eth:
- stmmac: fix TSO header length truncation
- ip_tunnel: initialize `options_len` before referencing options"
* tag 'net-7.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (159 commits)
mptcp: fix bad accounting in __mptcp_subflow_push_pending()
mptcp: close race between scheduler and state change
mptcp: avoid unneeded actions on subflow reset
net: skbuff: do not leave stale header offsets after pskb_carve()
selftests: net: packetdrill: test exclusion of old ACK from TCP fast path
tcp: exclude old ACKs from tcp fast path
dpll: reject a reference sync pin which is not on the pin's dpll
net: mvpp2: prevent buffer overflow in page_pool allocation
net: macb: fix ordering around PTP timestamp read
selftests: drv-net: psp: test PSP and TCP ULP mutual exclusion
net: psp: avoid conflicts with skb->decrypted and sk_validate_xmit_skb()
net: stmmac: preserve real_num_tx_queues on mqprio setup failure
net: stmmac: propagate FPE preemption-class mapping errors
net: wwan: t7xx: validate the netif index in t7xx_ccmni_recv_skb()
net: wwan: mhi_wwan_mbim: check skb_copy_bits() return value
net: wwan: mhi_wwan_mbim: guard against a cyclic NDP chain
net: ethernet: cortina: Ack RX overrun interrupt correctly
net: lock the socket in sock_gettstamp()
eth: fbnic: ring the doorbell if a burst ends in a drop
net: netsec: fix device_node reference leak on phy_np
...
This commit is contained in:
commit
b5a051f6b8
|
|
@ -4,6 +4,8 @@ Alyssa Rosenzweig <alyssa@rosenzweig.io>
|
|||
Askar Safin <safinaskar@gmail.com>
|
||||
Christoph Hellwig <hch@lst.de>
|
||||
Jeff Kirsher <jeffrey.t.kirsher@intel.com>
|
||||
Johannes Berg <johannes.berg@intel.com>
|
||||
Johannes Berg <johannes@sipsolutions.net>
|
||||
Marc Gonzalez <marc.w.gonzalez@free.fr>
|
||||
Nathan Chancellor <nathan@kernel.org>
|
||||
Ralf Baechle <ralf@linux-mips.org>
|
||||
|
|
|
|||
|
|
@ -341,6 +341,9 @@ attribute-sets:
|
|||
-
|
||||
name: interval-probe-time-ms
|
||||
type: u64
|
||||
checks:
|
||||
min: 1
|
||||
max: 86400000
|
||||
|
||||
operations:
|
||||
enum-model: directional
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ neigh/default/unres_qlen - INTEGER
|
|||
|
||||
neigh/default/interval_probe_time_ms - INTEGER
|
||||
The probe interval for neighbor entries with NTF_MANAGED flag,
|
||||
the min value is 1.
|
||||
the min value is 1, and the max value is 86400000 (1 day).
|
||||
|
||||
Default: 5000
|
||||
|
||||
|
|
@ -874,6 +874,8 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max
|
|||
case this value is ignored.
|
||||
Default: between 131072 and 32MB, depending on RAM size.
|
||||
|
||||
Each of the three values cannot be set below 4096.
|
||||
|
||||
tcp_sack - BOOLEAN
|
||||
Enable select acknowledgments (SACKS).
|
||||
|
||||
|
|
|
|||
|
|
@ -404,6 +404,12 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
|
|||
if (tfd_index > txq->count)
|
||||
return -ERANGE;
|
||||
|
||||
if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) {
|
||||
bt_dev_err(hdev, "TX skb too large (%u > %u)", skb->len,
|
||||
BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/* Firmware raises alive interrupt on HCI_OP_RESET or
|
||||
* BTINTEL_HCI_OP_RESET
|
||||
*/
|
||||
|
|
@ -502,7 +508,7 @@ static int btintel_pcie_submit_rx(struct btintel_pcie_data *data)
|
|||
|
||||
frbd_index = data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM];
|
||||
|
||||
if (frbd_index > rxq->count)
|
||||
if (frbd_index >= rxq->count)
|
||||
return -ERANGE;
|
||||
|
||||
/* Prepare for RX submit. It updates the FRBD with the address of DMA
|
||||
|
|
|
|||
|
|
@ -721,7 +721,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev,
|
|||
case BTMTK_WMT_FUNC_CTRL:
|
||||
if (!skb_pull_data(data->evt_skb,
|
||||
sizeof(wmt_evt_funcc->status))) {
|
||||
status = BTMTK_WMT_ON_UNDONE;
|
||||
/* A plain enable/disable request is acked with just
|
||||
* the WMT header and no trailing status word; the
|
||||
* result is carried in the header's own flag byte.
|
||||
*/
|
||||
status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE :
|
||||
BTMTK_WMT_ON_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -217,7 +217,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
}
|
||||
|
||||
/* Parse and handle the return WMT event */
|
||||
wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
|
||||
wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt));
|
||||
if (!wmt_evt) {
|
||||
bt_dev_err(hdev, "WMT event too short (%u bytes)",
|
||||
bdev->evt_skb->len);
|
||||
err = -EINVAL;
|
||||
goto err_free_skb;
|
||||
}
|
||||
|
||||
if (wmt_evt->whdr.op != hdr->op) {
|
||||
bt_dev_err(hdev, "Wrong op received %d expected %d",
|
||||
wmt_evt->whdr.op, hdr->op);
|
||||
|
|
@ -233,6 +240,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
status = BTMTK_WMT_PATCH_DONE;
|
||||
break;
|
||||
case BTMTK_WMT_FUNC_CTRL:
|
||||
if (!skb_pull_data(bdev->evt_skb,
|
||||
sizeof(wmt_evt_funcc->status))) {
|
||||
/* A plain enable/disable request is acked with just
|
||||
* the WMT header and no trailing status word; the
|
||||
* result is carried in the header's own flag byte.
|
||||
*/
|
||||
status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE :
|
||||
BTMTK_WMT_ON_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
|
||||
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
|
||||
status = BTMTK_WMT_ON_DONE;
|
||||
|
|
@ -1244,10 +1262,8 @@ static int btmtksdio_shutdown(struct hci_dev *hdev)
|
|||
wmt_params.status = NULL;
|
||||
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
if (err < 0)
|
||||
bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ignore_wmt_cmd:
|
||||
pm_runtime_put_noidle(bdev->dev);
|
||||
|
|
|
|||
|
|
@ -151,7 +151,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
}
|
||||
|
||||
/* Parse and handle the return WMT event */
|
||||
wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
|
||||
wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt));
|
||||
if (!wmt_evt) {
|
||||
bt_dev_err(hdev, "WMT event too short (%u bytes)",
|
||||
bdev->evt_skb->len);
|
||||
err = -EINVAL;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
if (wmt_evt->whdr.op != hdr->op) {
|
||||
bt_dev_err(hdev, "Wrong op received %d expected %d",
|
||||
wmt_evt->whdr.op, hdr->op);
|
||||
|
|
@ -167,6 +174,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
status = BTMTK_WMT_PATCH_DONE;
|
||||
break;
|
||||
case BTMTK_WMT_FUNC_CTRL:
|
||||
if (!skb_pull_data(bdev->evt_skb,
|
||||
sizeof(wmt_evt_funcc->status))) {
|
||||
/* A plain enable/disable request is acked with just
|
||||
* the WMT header and no trailing status word; the
|
||||
* result is carried in the header's own flag byte.
|
||||
*/
|
||||
status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE :
|
||||
BTMTK_WMT_ON_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
|
||||
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
|
||||
status = BTMTK_WMT_ON_DONE;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,15 @@ static struct usb_driver btusb_driver;
|
|||
#define BTUSB_BROKEN_EXT_SCAN BIT(29)
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/*
|
||||
* NXP IW610 (0471:0215): the composite device reports Bluetooth
|
||||
* class at the whole-device level, so the generic entry below
|
||||
* would also match this WiFi vendor interface. Ignore it here
|
||||
* first so mwifiex-nxp can bind it instead.
|
||||
*/
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xff, 0xff, 0xff),
|
||||
.driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* Generic Bluetooth USB device */
|
||||
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
|
|
@ -477,6 +486,14 @@ static const struct usb_device_id quirks_table[] = {
|
|||
{ USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
|
||||
{ USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL },
|
||||
|
||||
/*
|
||||
* NXP IW610 BT interfaces (Marvell-lineage silicon, same quirk as
|
||||
* the 0x1286 entries above). Scoped to the BT interface class,
|
||||
* not just VID/PID -- see the btusb_table entry above.
|
||||
*/
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xe0, 0x01, 0x01),
|
||||
.driver_info = BTUSB_MARVELL },
|
||||
|
||||
/* Intel Bluetooth devices */
|
||||
{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
|
|
|
|||
|
|
@ -2228,8 +2228,8 @@ static void qca_power_off(struct hci_uart *hu)
|
|||
bool sw_ctrl_state;
|
||||
struct qca_power *power;
|
||||
|
||||
/* From this point we go into power off state. But serial port is
|
||||
* still open, stop queueing the IBS data and flush all the buffered
|
||||
/* From this point we go into power off state. But serial port may
|
||||
* still be open, stop queueing the IBS data and flush all the buffered
|
||||
* data in skb's.
|
||||
*/
|
||||
spin_lock_irqsave(&qca->hci_ibs_lock, flags);
|
||||
|
|
@ -2251,8 +2251,14 @@ static void qca_power_off(struct hci_uart *hu)
|
|||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
host_set_baudrate(hu, 2400);
|
||||
qca_send_power_pulse(hu, false);
|
||||
/* Both of these write to the serial port which may have
|
||||
* already been closed by hci_uart_close(), which closes
|
||||
* the port if HCI_QUIRK_NON_PERSISTENT_SETUP is set.
|
||||
*/
|
||||
if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
|
||||
host_set_baudrate(hu, 2400);
|
||||
qca_send_power_pulse(hu, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1202,6 +1202,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
|||
const enum dpll_pin_state state,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
void *pin_priv, *ref_sync_pin_priv;
|
||||
const struct dpll_pin_ops *ops;
|
||||
enum dpll_pin_state old_state;
|
||||
struct dpll_pin *ref_sync_pin;
|
||||
|
|
@ -1230,9 +1231,15 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
dpll = ref->dpll;
|
||||
ret = ops->ref_sync_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
ref_sync_pin,
|
||||
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
|
||||
pin_priv = dpll_pin_on_dpll_priv(dpll, pin);
|
||||
ref_sync_pin_priv = dpll_pin_on_dpll_priv(dpll, ref_sync_pin);
|
||||
/* Pin may have been unregistered from this dpll already */
|
||||
if (!ref_sync_pin_priv) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"reference sync pin not registered with the dpll");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin, ref_sync_pin_priv,
|
||||
&old_state, extack);
|
||||
if (ret) {
|
||||
NL_SET_ERR_MSG(extack, "unable to get old reference sync state");
|
||||
|
|
@ -1241,9 +1248,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
|
|||
if (state == old_state)
|
||||
return 0;
|
||||
|
||||
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
|
||||
ref_sync_pin,
|
||||
dpll_pin_on_dpll_priv(dpll, ref_sync_pin),
|
||||
ret = ops->ref_sync_set(pin, pin_priv, ref_sync_pin, ref_sync_pin_priv,
|
||||
state, extack);
|
||||
if (ret) {
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
|
|
|
|||
|
|
@ -685,10 +685,22 @@ static int mxl862xx_setup(struct dsa_switch *ds)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mxl862xx_setup_mdio(ds);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
schedule_delayed_work(&priv->stats_work,
|
||||
MXL862XX_STATS_POLL_INTERVAL);
|
||||
|
||||
return mxl862xx_setup_mdio(ds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mxl862xx_teardown(struct dsa_switch *ds)
|
||||
{
|
||||
struct mxl862xx_priv *priv = ds->priv;
|
||||
|
||||
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
|
||||
disable_delayed_work_sync(&priv->stats_work);
|
||||
}
|
||||
|
||||
static int mxl862xx_port_state(struct dsa_switch *ds, int port, bool enable)
|
||||
|
|
@ -2047,9 +2059,7 @@ static void mxl862xx_get_stats64(struct dsa_switch *ds, int port,
|
|||
|
||||
spin_unlock_bh(&priv->ports[port].stats_lock);
|
||||
|
||||
/* Trigger a fresh poll so the next read sees up-to-date counters.
|
||||
* No-op if the work is already pending, running, or teardown started.
|
||||
*/
|
||||
/* Trigger a fresh poll so the next read sees up-to-date counters. */
|
||||
if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags))
|
||||
schedule_delayed_work(&priv->stats_work, 0);
|
||||
}
|
||||
|
|
@ -2057,6 +2067,7 @@ static void mxl862xx_get_stats64(struct dsa_switch *ds, int port,
|
|||
static const struct dsa_switch_ops mxl862xx_switch_ops = {
|
||||
.get_tag_protocol = mxl862xx_get_tag_protocol,
|
||||
.setup = mxl862xx_setup,
|
||||
.teardown = mxl862xx_teardown,
|
||||
.port_setup = mxl862xx_port_setup,
|
||||
.port_teardown = mxl862xx_port_teardown,
|
||||
.phylink_get_caps = mxl862xx_phylink_get_caps,
|
||||
|
|
@ -2131,7 +2142,6 @@ static int mxl862xx_probe(struct mdio_device *mdiodev)
|
|||
err = dsa_register_switch(ds);
|
||||
if (err) {
|
||||
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
|
||||
cancel_delayed_work_sync(&priv->stats_work);
|
||||
mxl862xx_host_shutdown(priv);
|
||||
for (i = 0; i < MXL862XX_MAX_PORTS; i++)
|
||||
cancel_work_sync(&priv->ports[i].host_flood_work);
|
||||
|
|
@ -2152,7 +2162,6 @@ static void mxl862xx_remove(struct mdio_device *mdiodev)
|
|||
priv = ds->priv;
|
||||
|
||||
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
|
||||
cancel_delayed_work_sync(&priv->stats_work);
|
||||
|
||||
dsa_unregister_switch(ds);
|
||||
|
||||
|
|
@ -2181,7 +2190,7 @@ static void mxl862xx_shutdown(struct mdio_device *mdiodev)
|
|||
dsa_switch_shutdown(ds);
|
||||
|
||||
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
|
||||
cancel_delayed_work_sync(&priv->stats_work);
|
||||
disable_delayed_work_sync(&priv->stats_work);
|
||||
|
||||
mxl862xx_host_shutdown(priv);
|
||||
|
||||
|
|
|
|||
|
|
@ -749,8 +749,17 @@ static void bcmgenet_hfb_init(struct bcmgenet_priv *priv)
|
|||
INIT_LIST_HEAD(&priv->rxnfc_rules[i].list);
|
||||
priv->rxnfc_rules[i].state = BCMGENET_RXNFC_STATE_UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
static void bcmgenet_hfb_restore(struct bcmgenet_priv *priv)
|
||||
{
|
||||
struct bcmgenet_rxnfc_rule *rule;
|
||||
|
||||
bcmgenet_hfb_clear(priv);
|
||||
|
||||
list_for_each_entry(rule, &priv->rxnfc_list, list)
|
||||
if (rule->state != BCMGENET_RXNFC_STATE_UNUSED)
|
||||
bcmgenet_hfb_create_rxnfc_filter(priv, rule);
|
||||
}
|
||||
|
||||
static int bcmgenet_begin(struct net_device *dev)
|
||||
|
|
@ -3376,8 +3385,8 @@ static int bcmgenet_open(struct net_device *dev)
|
|||
|
||||
bcmgenet_set_hw_addr(priv, dev->dev_addr);
|
||||
|
||||
/* HFB init */
|
||||
bcmgenet_hfb_init(priv);
|
||||
/* Restore the filters, the MAC was reset above */
|
||||
bcmgenet_hfb_restore(priv);
|
||||
|
||||
/* Reinitialize TDMA and RDMA and SW housekeeping */
|
||||
ret = bcmgenet_init_dma(priv, true);
|
||||
|
|
@ -4075,6 +4084,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
|
|||
|
||||
/* Mii wait queue */
|
||||
init_waitqueue_head(&priv->wq);
|
||||
bcmgenet_hfb_init(priv);
|
||||
INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task);
|
||||
|
||||
priv->clk_wol = devm_clk_get_optional(&priv->pdev->dev, "enet-wol");
|
||||
|
|
@ -4272,10 +4282,7 @@ static int bcmgenet_resume(struct device *d)
|
|||
bcmgenet_set_hw_addr(priv, dev->dev_addr);
|
||||
|
||||
/* Restore hardware filters */
|
||||
bcmgenet_hfb_clear(priv);
|
||||
list_for_each_entry(rule, &priv->rxnfc_list, list)
|
||||
if (rule->state != BCMGENET_RXNFC_STATE_UNUSED)
|
||||
bcmgenet_hfb_create_rxnfc_filter(priv, rule);
|
||||
bcmgenet_hfb_restore(priv);
|
||||
|
||||
/* Reinitialize TDMA and RDMA and SW housekeeping */
|
||||
ret = bcmgenet_init_dma(priv, false);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,12 @@ static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts,
|
|||
|
||||
spin_lock_irqsave(&bp->tsu_clk_lock, flags);
|
||||
ptp_read_system_prets(sts);
|
||||
/* explicit barriers are needed because gem_readl() is relaxed */
|
||||
if (sts)
|
||||
rmb();
|
||||
first = gem_readl(bp, TN);
|
||||
if (sts)
|
||||
rmb();
|
||||
ptp_read_system_postts(sts);
|
||||
secl = gem_readl(bp, TSL);
|
||||
sech = gem_readl(bp, TSH);
|
||||
|
|
@ -62,7 +67,11 @@ static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts,
|
|||
* (assume all done within 1s)
|
||||
*/
|
||||
ptp_read_system_prets(sts);
|
||||
if (sts)
|
||||
rmb();
|
||||
ts->tv_nsec = gem_readl(bp, TN);
|
||||
if (sts)
|
||||
rmb();
|
||||
ptp_read_system_postts(sts);
|
||||
secl = gem_readl(bp, TSL);
|
||||
sech = gem_readl(bp, TSH);
|
||||
|
|
|
|||
|
|
@ -1798,7 +1798,7 @@ static irqreturn_t gmac_irq(int irq, void *data)
|
|||
|
||||
if (val & (GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8))) {
|
||||
spin_lock(&geth->irq_lock);
|
||||
writel(GMAC0_RXDERR_INT_BIT << (netdev->dev_id * 8),
|
||||
writel(GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8),
|
||||
geth->base + GLOBAL_INTERRUPT_STATUS_4_REG);
|
||||
u64_stats_update_begin(&port->ir_stats_syncp);
|
||||
++port->stats.rx_fifo_errors;
|
||||
|
|
|
|||
|
|
@ -5086,7 +5086,8 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu)
|
|||
netdev_warn(dev, "mtu %d too high, switching to shared buffers", mtu);
|
||||
mvpp2_bm_switch_buffers(priv, false);
|
||||
}
|
||||
} else {
|
||||
} else if (priv->hw_version >= MVPP22 &&
|
||||
mvpp2_get_nrxqs(priv) * 2 <= MVPP2_BM_MAX_POOLS) {
|
||||
bool jumbo = false;
|
||||
int i;
|
||||
|
||||
|
|
|
|||
|
|
@ -311,6 +311,29 @@ fbnic_rx_csum(u64 rcd, struct sk_buff *skb, struct fbnic_ring *rcq,
|
|||
}
|
||||
}
|
||||
|
||||
static void fbnic_tx_doorbell(struct fbnic_ring *ring, __le64 *meta)
|
||||
{
|
||||
*meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_COMPLETION);
|
||||
ring->deferred_meta = -1;
|
||||
|
||||
/* Force DMA writes to flush before writing to tail */
|
||||
dma_wmb();
|
||||
|
||||
writel(ring->tail, ring->doorbell);
|
||||
}
|
||||
|
||||
/* Packets handed to us with xmit_more set are left in the ring without a
|
||||
* doorbell, and without a completion request, in the expectation that the
|
||||
* packet ending the burst will ring for all of them. If that packet gets
|
||||
* dropped instead we have to ring here, otherwise the descriptors sit in
|
||||
* the ring until the next transmit, which may never come.
|
||||
*/
|
||||
static void fbnic_tx_flush_doorbell(struct fbnic_ring *ring)
|
||||
{
|
||||
if (ring->deferred_meta >= 0)
|
||||
fbnic_tx_doorbell(ring, &ring->desc[ring->deferred_meta]);
|
||||
}
|
||||
|
||||
static bool
|
||||
fbnic_tx_map(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
|
||||
{
|
||||
|
|
@ -378,14 +401,10 @@ fbnic_tx_map(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
|
|||
/* Verify there is room for another packet */
|
||||
fbnic_maybe_stop_tx(skb->dev, ring, FBNIC_MAX_SKB_DESC);
|
||||
|
||||
if (fbnic_tx_sent_queue(skb, ring)) {
|
||||
*meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_COMPLETION);
|
||||
|
||||
/* Force DMA writes to flush before writing to tail */
|
||||
dma_wmb();
|
||||
|
||||
writel(tail, ring->doorbell);
|
||||
}
|
||||
if (fbnic_tx_sent_queue(skb, ring))
|
||||
fbnic_tx_doorbell(ring, meta);
|
||||
else
|
||||
ring->deferred_meta = meta - ring->desc;
|
||||
|
||||
return false;
|
||||
dma_error:
|
||||
|
|
@ -425,8 +444,10 @@ fbnic_xmit_frame_ring(struct sk_buff *skb, struct fbnic_ring *ring)
|
|||
* otherwise try next time
|
||||
*/
|
||||
desc_needed = skb_shinfo(skb)->nr_frags + 10;
|
||||
if (fbnic_maybe_stop_tx(skb->dev, ring, desc_needed))
|
||||
if (fbnic_maybe_stop_tx(skb->dev, ring, desc_needed)) {
|
||||
fbnic_tx_flush_doorbell(ring);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
*meta = cpu_to_le64(FBNIC_TWD_FLAG_DEST_MAC);
|
||||
|
||||
|
|
@ -447,6 +468,8 @@ fbnic_xmit_frame_ring(struct sk_buff *skb, struct fbnic_ring *ring)
|
|||
err_free:
|
||||
dev_kfree_skb_any(skb);
|
||||
err_count:
|
||||
fbnic_tx_flush_doorbell(ring);
|
||||
|
||||
u64_stats_update_begin(&ring->stats.syncp);
|
||||
ring->stats.dropped++;
|
||||
u64_stats_update_end(&ring->stats.syncp);
|
||||
|
|
@ -2491,6 +2514,7 @@ static void fbnic_enable_twq0(struct fbnic_ring *twq)
|
|||
fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ0_CTL, FBNIC_QUEUE_TWQ_CTL_RESET);
|
||||
twq->tail = 0;
|
||||
twq->head = 0;
|
||||
twq->deferred_meta = -1;
|
||||
|
||||
/* Store descriptor ring address and size */
|
||||
fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ0_BAL, lower_32_bits(twq->dma));
|
||||
|
|
|
|||
|
|
@ -128,9 +128,14 @@ struct fbnic_ring {
|
|||
/* Rx BDQs only */
|
||||
struct page_pool *page_pool;
|
||||
|
||||
/* Deferred_head is used to cache the head for TWQ1 if
|
||||
/* TWQ0 only, index of the meta descriptor of the last packet
|
||||
* placed in the ring without ringing the doorbell, -1 if the
|
||||
* doorbell is in sync with the tail.
|
||||
*/
|
||||
s32 deferred_meta;
|
||||
|
||||
/* TCQ only, used to cache the head for TWQ1 if
|
||||
* an attempt is made to clean TWQ1 with zero napi_budget.
|
||||
* We do not use it for any other ring.
|
||||
*/
|
||||
s32 deferred_head;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2604,7 +2604,7 @@ static int lan743x_rx_process_buffer(struct lan743x_rx *rx)
|
|||
rx->adapter->netdev);
|
||||
if (rx->adapter->netdev->features & NETIF_F_RXCSUM) {
|
||||
if (!is_ice && !is_tce && !is_icsm)
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
rx->skb_head->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
}
|
||||
netdev_dbg(netdev, "sending %d byte frame to OS",
|
||||
rx->skb_head->len);
|
||||
|
|
|
|||
|
|
@ -2149,6 +2149,7 @@ static int netsec_probe(struct platform_device *pdev)
|
|||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
free_ndev:
|
||||
of_node_put(priv->phy_np);
|
||||
free_netdev(ndev);
|
||||
dev_err(&pdev->dev, "init failed\n");
|
||||
|
||||
|
|
@ -2166,6 +2167,7 @@ static void netsec_remove(struct platform_device *pdev)
|
|||
netif_napi_del(&priv->napi);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
of_node_put(priv->phy_np);
|
||||
free_netdev(priv->ndev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -494,7 +494,7 @@ struct stmmac_ops {
|
|||
#define stmmac_set_arp_offload(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, set_arp_offload, __args)
|
||||
#define stmmac_fpe_map_preemption_class(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args)
|
||||
stmmac_do_callback(__priv, mac, fpe_map_preemption_class, __args)
|
||||
|
||||
/* PTP and HW Timer helpers */
|
||||
struct stmmac_hwtimestamp {
|
||||
|
|
|
|||
|
|
@ -1016,8 +1016,6 @@ static int stmmac_get_ts_info(struct net_device *dev,
|
|||
|
||||
if (priv->ptp_clock)
|
||||
info->phc_index = ptp_clock_index(priv->ptp_clock);
|
||||
else
|
||||
info->phc_index = 0;
|
||||
|
||||
info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
|
||||
|
||||
|
|
|
|||
|
|
@ -4513,16 +4513,16 @@ static int stmmac_tso_get_num_desc(struct stmmac_tx_queue *tx_q,
|
|||
*/
|
||||
static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
unsigned int first_entry, entry, tx_packets, proto_hdr_len;
|
||||
struct dma_desc *desc, *first, *mss_desc = NULL;
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
unsigned int first_entry, entry, tx_packets;
|
||||
struct stmmac_txq_stats *txq_stats;
|
||||
int i, first_tx, nfrags, ndesc;
|
||||
struct stmmac_tx_queue *tx_q;
|
||||
bool set_ic, is_last_segment;
|
||||
u32 pay_len, mss, queue;
|
||||
u8 proto_hdr_len, hdr;
|
||||
dma_addr_t des;
|
||||
u8 hdr;
|
||||
|
||||
nfrags = skb_shinfo(skb)->nr_frags;
|
||||
queue = skb_get_queue_mapping(skb);
|
||||
|
|
@ -4570,7 +4570,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
}
|
||||
|
||||
if (netif_msg_tx_queued(priv)) {
|
||||
pr_info("%s: hdrlen %d, hdr_len %d, pay_len %d, mss %d\n",
|
||||
pr_info("%s: hdrlen %d, hdr_len %u, pay_len %d, mss %d\n",
|
||||
__func__, hdr, proto_hdr_len, pay_len, mss);
|
||||
pr_info("\tskb->len %d, skb->data_len %d\n", skb->len,
|
||||
skb->data_len);
|
||||
|
|
|
|||
|
|
@ -970,7 +970,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
|
|||
struct netlink_ext_ack *extack = qopt->mqprio.extack;
|
||||
struct timespec64 time, current_time, qopt_time;
|
||||
ktime_t current_time_ns;
|
||||
int i, ret = 0;
|
||||
int err, i, ret = 0;
|
||||
u64 ctr;
|
||||
|
||||
if (qopt->base_time < 0)
|
||||
|
|
@ -1120,9 +1120,9 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
|
|||
mutex_unlock(&priv->est_lock);
|
||||
}
|
||||
|
||||
stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0);
|
||||
err = stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0);
|
||||
|
||||
return ret;
|
||||
return qopt->cmd == TAPRIO_CMD_DESTROY ? err : ret;
|
||||
}
|
||||
|
||||
static void tc_taprio_stats(struct stmmac_priv *priv,
|
||||
|
|
@ -1237,58 +1237,99 @@ static int tc_query_caps(struct stmmac_priv *priv,
|
|||
}
|
||||
}
|
||||
|
||||
static void stmmac_reset_tc_mqprio(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack)
|
||||
static int stmmac_set_ndev_tcs(struct net_device *ndev, u8 ntc,
|
||||
struct netdev_tc_txq *tc_to_txq)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
netdev_reset_tc(ndev);
|
||||
if (!ntc)
|
||||
return 0;
|
||||
|
||||
err = netdev_set_num_tc(ndev, ntc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < ntc; i++) {
|
||||
u16 count, offset;
|
||||
|
||||
count = tc_to_txq[i].count;
|
||||
offset = tc_to_txq[i].offset;
|
||||
netdev_set_tc_queue(ndev, i, count, offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_reset_tc_mqprio(struct net_device *ndev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
netdev_reset_tc(ndev);
|
||||
netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use);
|
||||
stmmac_fpe_map_preemption_class(priv, ndev, extack, 0);
|
||||
|
||||
return stmmac_fpe_map_preemption_class(priv, ndev, extack, 0);
|
||||
}
|
||||
|
||||
static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
|
||||
struct tc_mqprio_qopt_offload *mqprio)
|
||||
{
|
||||
unsigned int ndev_num_tx_queues, num_tx_queues = 0;
|
||||
struct netdev_tc_txq ndev_tc_to_txq[TC_MAX_QUEUE];
|
||||
struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE] = {};
|
||||
struct netlink_ext_ack *extack = mqprio->extack;
|
||||
struct tc_mqprio_qopt *qopt = &mqprio->qopt;
|
||||
u32 offset, count, num_stack_tx_queues = 0;
|
||||
struct net_device *ndev = priv->dev;
|
||||
u32 num_tc = qopt->num_tc;
|
||||
int err;
|
||||
u8 ndev_prio_tc_map[TC_BITMASK + 1];
|
||||
int i, err, ndev_ntc;
|
||||
|
||||
if (!num_tc) {
|
||||
stmmac_reset_tc_mqprio(ndev, extack);
|
||||
return 0;
|
||||
if (!qopt->num_tc)
|
||||
return stmmac_reset_tc_mqprio(ndev, extack);
|
||||
|
||||
if (qopt->num_tc > ARRAY_SIZE(tc_to_txq))
|
||||
return -EINVAL;
|
||||
|
||||
/* save current tc values for reset */
|
||||
ndev_ntc = netdev_get_num_tc(ndev);
|
||||
for (i = 0; i < ARRAY_SIZE(ndev->tc_to_txq); i++)
|
||||
ndev_tc_to_txq[i].combined =
|
||||
READ_ONCE(ndev->tc_to_txq[i].combined);
|
||||
for (i = 0; i < ARRAY_SIZE(ndev_prio_tc_map); i++)
|
||||
ndev_prio_tc_map[i] = READ_ONCE(ndev->prio_tc_map[i]);
|
||||
|
||||
for (i = 0; i < qopt->num_tc; i++) {
|
||||
tc_to_txq[i] = (struct netdev_tc_txq) {
|
||||
.count = qopt->count[i],
|
||||
.offset = qopt->offset[i],
|
||||
};
|
||||
num_tx_queues += qopt->count[i];
|
||||
}
|
||||
|
||||
err = netdev_set_num_tc(ndev, num_tc);
|
||||
err = stmmac_set_ndev_tcs(ndev, qopt->num_tc, tc_to_txq);
|
||||
if (err)
|
||||
return err;
|
||||
goto error_reset_tc;
|
||||
|
||||
for (u32 tc = 0; tc < num_tc; tc++) {
|
||||
offset = qopt->offset[tc];
|
||||
count = qopt->count[tc];
|
||||
num_stack_tx_queues += count;
|
||||
|
||||
err = netdev_set_tc_queue(ndev, tc, count, offset);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
}
|
||||
|
||||
err = netif_set_real_num_tx_queues(ndev, num_stack_tx_queues);
|
||||
ndev_num_tx_queues = ndev->real_num_tx_queues;
|
||||
err = netif_set_real_num_tx_queues(ndev, num_tx_queues);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
goto error_reset_tc;
|
||||
|
||||
err = stmmac_fpe_map_preemption_class(priv, ndev, extack,
|
||||
mqprio->preemptible_tcs);
|
||||
if (err)
|
||||
goto err_reset_tc;
|
||||
goto error_reset_num_tx_queues;
|
||||
|
||||
return 0;
|
||||
|
||||
err_reset_tc:
|
||||
stmmac_reset_tc_mqprio(ndev, extack);
|
||||
error_reset_num_tx_queues:
|
||||
if (netif_set_real_num_tx_queues(ndev, ndev_num_tx_queues))
|
||||
netdev_warn(ndev, "Failed to restore %u TX queues\n",
|
||||
ndev_num_tx_queues);
|
||||
error_reset_tc:
|
||||
stmmac_set_ndev_tcs(ndev, ndev_ntc, ndev_tc_to_txq);
|
||||
for (i = 0; i < ARRAY_SIZE(ndev_prio_tc_map); i++)
|
||||
netdev_set_prio_tc_map(ndev, i, ndev_prio_tc_map[i]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -928,7 +928,8 @@ static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr)
|
|||
|
||||
dev_addr_set(dev, p_sockaddr->sa_data);
|
||||
spin_lock_irqsave(&bp->DriverLock, Flags);
|
||||
ResetAdapter(smc);
|
||||
if (netif_running(dev))
|
||||
ResetAdapter(smc);
|
||||
spin_unlock_irqrestore(&bp->DriverLock, Flags);
|
||||
|
||||
return 0; /* always return zero */
|
||||
|
|
|
|||
|
|
@ -156,20 +156,27 @@ int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index,
|
|||
if (!rules)
|
||||
return 0;
|
||||
|
||||
if (on & on_set)
|
||||
/* TRIGGER_NETDEV_LINK must not be reported together with any of the
|
||||
* per-speed rules, the netdev trigger rejects that combination.
|
||||
* on_set holds every speed this LED can indicate and is what
|
||||
* mtk_phy_led_hw_ctrl_set() programs for TRIGGER_NETDEV_LINK, so
|
||||
* report the speed independent rule only when they are all on.
|
||||
*/
|
||||
if ((on & on_set) == on_set) {
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK);
|
||||
} else {
|
||||
if (on & MTK_PHY_LED_ON_LINK10)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_10);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_LINK10)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_10);
|
||||
if (on & MTK_PHY_LED_ON_LINK100)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_100);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_LINK100)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_100);
|
||||
if (on & MTK_PHY_LED_ON_LINK1000)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_LINK1000)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
|
||||
|
||||
if (on & MTK_PHY_LED_ON_LINK2500)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
|
||||
if (on & MTK_PHY_LED_ON_LINK2500)
|
||||
*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
|
||||
}
|
||||
|
||||
if (on & MTK_PHY_LED_ON_FDX)
|
||||
*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
|
||||
|
|
|
|||
|
|
@ -873,6 +873,22 @@ static int ath11k_mac_set_kickout(struct ath11k_vif *arvif)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ath11k_mac_station_cleanup(struct ieee80211_sta *sta)
|
||||
{
|
||||
struct ath11k_sta *arsta;
|
||||
|
||||
if (!sta)
|
||||
return;
|
||||
|
||||
arsta = ath11k_sta_to_arsta(sta);
|
||||
|
||||
kfree(arsta->tx_stats);
|
||||
arsta->tx_stats = NULL;
|
||||
|
||||
kfree(arsta->rx_stats);
|
||||
arsta->rx_stats = NULL;
|
||||
}
|
||||
|
||||
void ath11k_mac_peer_cleanup_all(struct ath11k *ar)
|
||||
{
|
||||
struct ath11k_peer *peer, *tmp;
|
||||
|
|
@ -885,6 +901,7 @@ void ath11k_mac_peer_cleanup_all(struct ath11k *ar)
|
|||
list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
|
||||
ath11k_peer_rx_tid_cleanup(ar, peer);
|
||||
ath11k_peer_rhash_delete(ab, peer);
|
||||
ath11k_mac_station_cleanup(peer->sta);
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
}
|
||||
|
|
@ -9892,7 +9909,6 @@ static int ath11k_mac_station_remove(struct ath11k *ar,
|
|||
{
|
||||
struct ath11k_base *ab = ar->ab;
|
||||
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
|
||||
struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
|
||||
int ret;
|
||||
|
||||
if (ab->hw_params.vdev_start_delay &&
|
||||
|
|
@ -9916,12 +9932,7 @@ static int ath11k_mac_station_remove(struct ath11k *ar,
|
|||
sta->addr, arvif->vdev_id);
|
||||
|
||||
ath11k_mac_dec_num_stations(arvif, sta);
|
||||
|
||||
kfree(arsta->tx_stats);
|
||||
arsta->tx_stats = NULL;
|
||||
|
||||
kfree(arsta->rx_stats);
|
||||
arsta->rx_stats = NULL;
|
||||
ath11k_mac_station_cleanup(sta);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,21 +15,6 @@
|
|||
#include "dp.h"
|
||||
#include "core.h"
|
||||
|
||||
/*
|
||||
* Node name to UserPD ID mapping
|
||||
*
|
||||
* The io_start field is used for additional validation when the reg
|
||||
* property is present in the device tree. If io_start is 0, only
|
||||
* node_name matching is performed.
|
||||
*
|
||||
* For platforms where not all WiFi nodes have a 'reg' property, set
|
||||
* io_start to 0 for those entries. The driver will match purely by
|
||||
* node name in such cases.
|
||||
*/
|
||||
static const struct ath12k_ahb_userpd_map ath12k_wifi7_ahb_userpd_map[] = {
|
||||
{ .io_start = 0x0c000000, .node_name = "wifi", .upd_id = ATH12K_AHB_USERPD_ID_0 },
|
||||
};
|
||||
|
||||
static const struct ath12k_ahb_desc ath12k_wifi7_ahb_desc[] = {
|
||||
[ATH12K_HW_IPQ5332_HW10] = {
|
||||
.hw_rev = ATH12K_HW_IPQ5332_HW10,
|
||||
|
|
@ -55,40 +40,6 @@ static const struct of_device_id ath12k_wifi7_ahb_of_match[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(of, ath12k_wifi7_ahb_of_match);
|
||||
|
||||
/*
|
||||
* ath12k_wifi7_ahb_get_userpd_id - Resolve UserPD ID from DT properties
|
||||
* @ab: ath12k base structure
|
||||
*
|
||||
* Returns: UserPD ID (1-based) on success, 0 on failure
|
||||
*
|
||||
* Resolution logic:
|
||||
* 1. If reg property exist in DT, get userpd_id from io_start
|
||||
* 2. If reg property is absent, get userpd_id from DT node name
|
||||
* 3. Return 0 if no match found (probe will fail)
|
||||
*/
|
||||
static u32 ath12k_wifi7_ahb_get_userpd_id(struct ath12k_base *ab)
|
||||
{
|
||||
const struct ath12k_ahb_userpd_map *map;
|
||||
struct resource *res;
|
||||
size_t i;
|
||||
|
||||
res = platform_get_resource(ab->pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ath12k_wifi7_ahb_userpd_map); i++) {
|
||||
map = &ath12k_wifi7_ahb_userpd_map[i];
|
||||
|
||||
if (res) {
|
||||
if (map->io_start && map->io_start == res->start)
|
||||
return map->upd_id;
|
||||
} else if (map->node_name &&
|
||||
of_node_name_eq(ab->dev->of_node, map->node_name)) {
|
||||
return map->upd_id;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_wifi7_ahb_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct ath12k_ahb_desc *desc;
|
||||
|
|
@ -106,7 +57,7 @@ static int ath12k_wifi7_ahb_probe(struct platform_device *pdev)
|
|||
ab->hw_rev = desc->hw_rev;
|
||||
ab->hif.ops = desc->ops;
|
||||
ab_ahb->scm_auth_enabled = desc->auth_enabled;
|
||||
ab_ahb->userpd_id = ath12k_wifi7_ahb_get_userpd_id(ab);
|
||||
ab_ahb->userpd_id = ATH12K_AHB_USERPD_ID_0;
|
||||
if (!ab_ahb->userpd_id)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
|
|
|||
|
|
@ -1055,7 +1055,7 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn)
|
|||
|
||||
free_irq(wcn->tx_irq, wcn);
|
||||
free_irq(wcn->rx_irq, wcn);
|
||||
timer_delete(&wcn->tx_ack_timer);
|
||||
timer_shutdown_sync(&wcn->tx_ack_timer);
|
||||
|
||||
if (wcn->tx_ack_skb) {
|
||||
ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb);
|
||||
|
|
|
|||
|
|
@ -555,6 +555,8 @@ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
|
|||
|
||||
if (type == ETH_P_PAE) {
|
||||
atomic_dec(&ifp->pend_8021x_cnt);
|
||||
/* Order the decrement before waitqueue_active() */
|
||||
smp_mb__after_atomic();
|
||||
if (waitqueue_active(&ifp->pend_8021x_wait))
|
||||
wake_up(&ifp->pend_8021x_wait);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev,
|
|||
{
|
||||
struct brcmf_if *ifp;
|
||||
struct brcmf_pub *drvr;
|
||||
struct brcmf_auth_req_status_le auth_status;
|
||||
struct brcmf_auth_req_status_le auth_status = {};
|
||||
int ret = 0;
|
||||
|
||||
brcmf_dbg(TRACE, "Enter\n");
|
||||
|
|
@ -206,6 +206,9 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev,
|
|||
ifp = netdev_priv(dev);
|
||||
drvr = ifp->drvr;
|
||||
if (params->status == WLAN_STATUS_SUCCESS) {
|
||||
if (params->pmkid)
|
||||
memcpy(auth_status.pmkid, params->pmkid,
|
||||
WLAN_PMKID_LEN);
|
||||
auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS);
|
||||
} else {
|
||||
bphy_err(drvr, "External authentication failed: status=%d\n",
|
||||
|
|
|
|||
|
|
@ -1571,6 +1571,10 @@ void brcms_free_timer(struct brcms_timer *t)
|
|||
|
||||
/* delete the timer in case it is active */
|
||||
brcms_del_timer(t);
|
||||
/* Ensure the callback has finished before freeing the timer
|
||||
* structure, since brcms_del_timer() uses non-synchronous cancel.
|
||||
*/
|
||||
cancel_delayed_work_sync(&t->dly_wrk);
|
||||
|
||||
if (wl->timers == t) {
|
||||
wl->timers = wl->timers->next;
|
||||
|
|
|
|||
|
|
@ -2712,7 +2712,9 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
if (stats.len < sizeof(struct libipw_hdr_3addr))
|
||||
if (sq->drv[i].frame_size <
|
||||
sizeof(struct libipw_hdr_3addr) ||
|
||||
sq->drv[i].frame_size > IPW_RX_NIC_BUFFER_LENGTH)
|
||||
break;
|
||||
switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
|
||||
case IEEE80211_FTYPE_MGMT:
|
||||
|
|
|
|||
|
|
@ -8322,6 +8322,15 @@ static void ipw_rx(struct ipw_priv *priv)
|
|||
break;
|
||||
}
|
||||
|
||||
if (unlikely(le16_to_cpu(pkt->u.frame.length) >
|
||||
IPW_RX_BUF_SIZE -
|
||||
IPW_RX_FRAME_SIZE)) {
|
||||
IPW_DEBUG_DROP("Received oversized packet. Dropping.\n");
|
||||
priv->net_dev->stats.rx_errors++;
|
||||
priv->wstats.discard.misc++;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (WLAN_FC_GET_TYPE
|
||||
(le16_to_cpu(header->frame_ctl))) {
|
||||
|
||||
|
|
|
|||
|
|
@ -474,14 +474,16 @@ static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx,
|
|||
int hdr_len, void *priv)
|
||||
{
|
||||
struct libipw_tkip_data *tkey = priv;
|
||||
u8 mic[8];
|
||||
u8 mic[MICHAEL_MIC_LEN];
|
||||
|
||||
if (!tkey->key_set)
|
||||
if (!tkey->key_set || skb->len < hdr_len + MICHAEL_MIC_LEN)
|
||||
return -1;
|
||||
|
||||
michael_mic(&tkey->key[24], (struct ieee80211_hdr *)skb->data,
|
||||
skb->data + hdr_len, skb->len - 8 - hdr_len, mic);
|
||||
if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
|
||||
skb->data + hdr_len,
|
||||
skb->len - MICHAEL_MIC_LEN - hdr_len, mic);
|
||||
if (memcmp(mic, skb->data + skb->len - MICHAEL_MIC_LEN,
|
||||
MICHAEL_MIC_LEN) != 0) {
|
||||
struct ieee80211_hdr *hdr;
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
printk(KERN_DEBUG "%s: Michael MIC verification failed for "
|
||||
|
|
@ -499,7 +501,7 @@ static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx,
|
|||
tkey->rx_iv32 = tkey->rx_iv32_new;
|
||||
tkey->rx_iv16 = tkey->rx_iv16_new;
|
||||
|
||||
skb_trim(skb, skb->len - 8);
|
||||
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1209,6 +1209,9 @@ static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_as
|
|||
struct libipw_network *network = &network_resp;
|
||||
struct net_device *dev = ieee->dev;
|
||||
|
||||
if (stats->len < sizeof(*frame))
|
||||
return 1;
|
||||
|
||||
network->flags = 0;
|
||||
network->qos_data.active = 0;
|
||||
network->qos_data.supported = 0;
|
||||
|
|
@ -1421,6 +1424,9 @@ static void libipw_process_probe_response(struct libipw_device
|
|||
#endif
|
||||
unsigned long flags;
|
||||
|
||||
if (stats->len < sizeof(*beacon))
|
||||
return;
|
||||
|
||||
LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
|
||||
info_element->len, info_element->data,
|
||||
beacon->header.addr3,
|
||||
|
|
|
|||
|
|
@ -2326,7 +2326,7 @@ il_dealloc_bcast_stations(struct il_priv *il)
|
|||
if (!(il->stations[i].used & IL_STA_BCAST))
|
||||
continue;
|
||||
|
||||
il->stations[i].used &= ~IL_STA_UCODE_ACTIVE;
|
||||
il->stations[i].used = 0;
|
||||
il->num_stations--;
|
||||
if (WARN_ON(il->num_stations < 0))
|
||||
il->num_stations = 0;
|
||||
|
|
|
|||
|
|
@ -414,17 +414,22 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
|
|||
}
|
||||
|
||||
static int p54_convert_rev0(struct ieee80211_hw *dev,
|
||||
struct pda_pa_curve_data *curve_data)
|
||||
struct pda_pa_curve_data *curve_data, size_t len)
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
struct p54_pa_curve_data_sample *dst;
|
||||
struct pda_pa_curve_data_sample_rev0 *src;
|
||||
size_t needed = curve_data->channels *
|
||||
(sizeof(*src) * curve_data->points_per_channel + 2);
|
||||
size_t cd_len = sizeof(*curve_data) +
|
||||
(curve_data->points_per_channel*sizeof(*dst) + 2) *
|
||||
curve_data->channels;
|
||||
unsigned int i, j;
|
||||
void *source, *target;
|
||||
|
||||
if (len < sizeof(*curve_data) + needed)
|
||||
return -EINVAL;
|
||||
|
||||
priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
|
||||
GFP_KERNEL);
|
||||
if (!priv->curve_data)
|
||||
|
|
@ -466,17 +471,22 @@ static int p54_convert_rev0(struct ieee80211_hw *dev,
|
|||
}
|
||||
|
||||
static int p54_convert_rev1(struct ieee80211_hw *dev,
|
||||
struct pda_pa_curve_data *curve_data)
|
||||
struct pda_pa_curve_data *curve_data, size_t len)
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
struct p54_pa_curve_data_sample *dst;
|
||||
struct pda_pa_curve_data_sample_rev1 *src;
|
||||
size_t needed = curve_data->channels *
|
||||
(sizeof(*src) * curve_data->points_per_channel + 3);
|
||||
size_t cd_len = sizeof(*curve_data) +
|
||||
(curve_data->points_per_channel*sizeof(*dst) + 2) *
|
||||
curve_data->channels;
|
||||
unsigned int i, j;
|
||||
void *source, *target;
|
||||
|
||||
if (len < sizeof(*curve_data) + needed)
|
||||
return -EINVAL;
|
||||
|
||||
priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
|
||||
GFP_KERNEL);
|
||||
if (!priv->curve_data)
|
||||
|
|
@ -763,6 +773,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
|||
case PDR_PRISM_PA_CAL_CURVE_DATA: {
|
||||
struct pda_pa_curve_data *curve_data =
|
||||
(struct pda_pa_curve_data *)entry->data;
|
||||
|
||||
if (data_len < sizeof(*curve_data)) {
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
|
|
@ -770,10 +781,10 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
|||
|
||||
switch (curve_data->cal_method_rev) {
|
||||
case 0:
|
||||
err = p54_convert_rev0(dev, curve_data);
|
||||
err = p54_convert_rev0(dev, curve_data, data_len);
|
||||
break;
|
||||
case 1:
|
||||
err = p54_convert_rev1(dev, curve_data);
|
||||
err = p54_convert_rev1(dev, curve_data, data_len);
|
||||
break;
|
||||
default:
|
||||
wiphy_err(dev->wiphy,
|
||||
|
|
@ -801,7 +812,8 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
|
|||
break;
|
||||
case PDR_INTERFACE_LIST:
|
||||
tmp = entry->data;
|
||||
while ((u8 *)tmp < entry->data + data_len) {
|
||||
while ((u8 *)tmp + sizeof(struct exp_if) <=
|
||||
entry->data + data_len) {
|
||||
struct exp_if *exp_if = tmp;
|
||||
if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
|
||||
synth = le16_to_cpu(exp_if->variant);
|
||||
|
|
|
|||
|
|
@ -173,8 +173,8 @@ static int lbtf_init_adapter(struct lbtf_private *priv)
|
|||
static void lbtf_free_adapter(struct lbtf_private *priv)
|
||||
{
|
||||
lbtf_deb_enter(LBTF_DEB_MAIN);
|
||||
lbtf_free_cmd_buffer(priv);
|
||||
timer_delete_sync(&priv->command_timer);
|
||||
lbtf_free_cmd_buffer(priv);
|
||||
lbtf_deb_leave(LBTF_DEB_MAIN);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4277,6 +4277,7 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy,
|
|||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
struct sk_buff *skb;
|
||||
u16 pkt_len, auth_alg;
|
||||
size_t frame_len;
|
||||
int ret;
|
||||
struct mwifiex_ieee80211_mgmt *mgmt;
|
||||
struct mwifiex_txinfo *tx_info;
|
||||
|
|
@ -4349,10 +4350,17 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy,
|
|||
|
||||
mwifiex_cancel_scan(adapter);
|
||||
|
||||
pkt_len = (u16)req->ie_len + req->auth_data_len +
|
||||
frame_len = req->ie_len + req->auth_data_len +
|
||||
MWIFIEX_MGMT_HEADER_LEN + MWIFIEX_AUTH_BODY_LEN;
|
||||
if (req->auth_data_len >= 4)
|
||||
pkt_len -= 4;
|
||||
frame_len -= 4;
|
||||
|
||||
if (frame_len > U16_MAX) {
|
||||
mwifiex_dbg(priv->adapter, ERROR,
|
||||
"auth frame too long: %zu bytes\n", frame_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
pkt_len = frame_len;
|
||||
|
||||
skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN +
|
||||
MWIFIEX_MGMT_FRAME_HEADER_SIZE +
|
||||
|
|
|
|||
|
|
@ -3068,7 +3068,7 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
|
|||
ret);
|
||||
for (j = 0; j < i; j++)
|
||||
free_irq(card->msix_entries[j].vector,
|
||||
&card->msix_ctx[i]);
|
||||
&card->msix_ctx[j]);
|
||||
pci_disable_msix(pdev);
|
||||
} else {
|
||||
mwifiex_dbg(adapter, MSG, "MSIx enabled!");
|
||||
|
|
|
|||
|
|
@ -104,12 +104,24 @@ has_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key)
|
|||
* a given oui in PTK.
|
||||
*/
|
||||
static u8
|
||||
mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
|
||||
mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui, int ie_len)
|
||||
{
|
||||
const size_t ptk_body_offset = offsetof(struct ie_body, ptk_body);
|
||||
u8 count;
|
||||
|
||||
/* ie_len is the number of bytes available at iebody. Keep it signed
|
||||
* and reject a negative (underflowed) length before the unsigned
|
||||
* comparisons below, so a small or zero IE length cannot wrap.
|
||||
*/
|
||||
if (ie_len < 0 || (size_t)ie_len < ptk_body_offset)
|
||||
return MWIFIEX_OUI_NOT_PRESENT;
|
||||
|
||||
count = iebody->ptk_cnt[0];
|
||||
|
||||
/* Reject an OUI count whose list would run past the element. */
|
||||
if (ptk_body_offset + count * sizeof(iebody->ptk_body) > (size_t)ie_len)
|
||||
return MWIFIEX_OUI_NOT_PRESENT;
|
||||
|
||||
/* There could be multiple OUIs for PTK hence
|
||||
1) Take the length.
|
||||
2) Check all the OUIs for AES.
|
||||
|
|
@ -143,11 +155,14 @@ mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
|
|||
u8 ret = MWIFIEX_OUI_NOT_PRESENT;
|
||||
|
||||
if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) {
|
||||
int ie_len = (int)bss_desc->bcn_rsn_ie->ieee_hdr.len -
|
||||
RSN_GTK_OUI_OFFSET;
|
||||
|
||||
iebody = (struct ie_body *)
|
||||
(((u8 *) bss_desc->bcn_rsn_ie->data) +
|
||||
RSN_GTK_OUI_OFFSET);
|
||||
oui = &mwifiex_rsn_oui[cipher][0];
|
||||
ret = mwifiex_search_oui_in_ie(iebody, oui);
|
||||
ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -169,10 +184,14 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
|
|||
u8 ret = MWIFIEX_OUI_NOT_PRESENT;
|
||||
|
||||
if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) {
|
||||
int ie_len = (int)bss_desc->bcn_wpa_ie->vend_hdr.len -
|
||||
(int)sizeof(bss_desc->bcn_wpa_ie->vend_hdr.oui) -
|
||||
WPA_GTK_OUI_OFFSET;
|
||||
|
||||
iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data +
|
||||
WPA_GTK_OUI_OFFSET);
|
||||
oui = &mwifiex_wpa_oui[cipher][0];
|
||||
ret = mwifiex_search_oui_in_ie(iebody, oui);
|
||||
ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -2096,6 +2115,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
|
|||
u32 bytes_left;
|
||||
u32 idx;
|
||||
u32 tlv_buf_size;
|
||||
size_t fixed_size;
|
||||
struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
|
||||
struct chan_band_param_set *chan_band;
|
||||
u8 is_bgscan_resp;
|
||||
|
|
@ -2111,6 +2131,14 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
|
|||
else
|
||||
scan_rsp = &resp->params.scan_resp;
|
||||
|
||||
scan_resp_size = le16_to_cpu(resp->size);
|
||||
fixed_size = scan_rsp->bss_desc_and_tlv_buffer - (u8 *)resp;
|
||||
if (scan_resp_size < fixed_size) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"SCAN_RESP: response is too short\n");
|
||||
ret = -1;
|
||||
goto check_next_scan;
|
||||
}
|
||||
|
||||
if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
|
|
@ -2128,8 +2156,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
|
|||
"info: SCAN_RESP: bss_descript_size %d\n",
|
||||
bytes_left);
|
||||
|
||||
scan_resp_size = le16_to_cpu(resp->size);
|
||||
|
||||
mwifiex_dbg(adapter, INFO,
|
||||
"info: SCAN_RESP: returned %d APs before parsing\n",
|
||||
scan_rsp->number_of_sets);
|
||||
|
|
@ -2137,15 +2163,17 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
|
|||
bss_info = scan_rsp->bss_desc_and_tlv_buffer;
|
||||
|
||||
/*
|
||||
* The size of the TLV buffer is equal to the entire command response
|
||||
* size (scan_resp_size) minus the fixed fields (sizeof()'s), the
|
||||
* BSS Descriptions (bss_descript_size as bytesLef) and the command
|
||||
* response header (S_DS_GEN)
|
||||
* The TLV buffer follows the command-specific fixed fields and the BSS
|
||||
* descriptions. Background-scan responses have an additional fixed
|
||||
* field before scan_rsp, which is included in fixed_size.
|
||||
*/
|
||||
tlv_buf_size = scan_resp_size - (bytes_left
|
||||
+ sizeof(scan_rsp->bss_descript_size)
|
||||
+ sizeof(scan_rsp->number_of_sets)
|
||||
+ S_DS_GEN);
|
||||
if (bytes_left > scan_resp_size - fixed_size) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"SCAN_RESP: BSS data exceeds response\n");
|
||||
ret = -1;
|
||||
goto check_next_scan;
|
||||
}
|
||||
tlv_buf_size = scan_resp_size - fixed_size - bytes_left;
|
||||
|
||||
tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
|
||||
bss_desc_and_tlv_buffer +
|
||||
|
|
|
|||
|
|
@ -317,10 +317,16 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
|
|||
|
||||
switch (stype) {
|
||||
case IEEE80211_STYPE_ACTION:
|
||||
category = *(payload + sizeof(struct ieee80211_hdr));
|
||||
if (len < sizeof(*ieee_hdr) + 1)
|
||||
return -1;
|
||||
|
||||
category = *(payload + sizeof(*ieee_hdr));
|
||||
switch (category) {
|
||||
case WLAN_CATEGORY_PUBLIC:
|
||||
action_code = *(payload + sizeof(struct ieee80211_hdr)
|
||||
if (len < sizeof(*ieee_hdr) + 2)
|
||||
return -1;
|
||||
|
||||
action_code = *(payload + sizeof(*ieee_hdr)
|
||||
+ 1);
|
||||
if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
|
||||
addr2 = ieee_hdr->addr2;
|
||||
|
|
|
|||
|
|
@ -1058,6 +1058,13 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
|
|||
if (!ieee80211_is_public_action((struct ieee80211_hdr *)buff, size))
|
||||
goto out_rx_mgmt;
|
||||
|
||||
/* ieee80211_is_public_action() only validates up to the category
|
||||
* byte, so reject frames too short for the P2P public action header
|
||||
* before dereferencing it or computing size - ie_offset.
|
||||
*/
|
||||
if (size < ie_offset)
|
||||
goto out_rx_mgmt;
|
||||
|
||||
d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
|
||||
if (d->oui_subtype != GO_NEG_REQ && d->oui_subtype != GO_NEG_RSP &&
|
||||
d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP)
|
||||
|
|
@ -1200,6 +1207,13 @@ static int mgmt_tx(struct wiphy *wiphy,
|
|||
goto out_set_timeout;
|
||||
}
|
||||
|
||||
/* ieee80211_is_public_action() only validates up to the category
|
||||
* byte, so reject frames too short for the P2P public action header
|
||||
* before dereferencing it or computing len - ie_offset.
|
||||
*/
|
||||
if (len < ie_offset)
|
||||
goto out_set_timeout;
|
||||
|
||||
d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
|
||||
if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P ||
|
||||
d->oui_subtype != GO_NEG_CONF) {
|
||||
|
|
|
|||
|
|
@ -1197,6 +1197,15 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
|
|||
if (size <= 0)
|
||||
return;
|
||||
|
||||
/* A size exceeding the RX buffer is bogus; drop the transfer
|
||||
* instead of overflowing the buffer.
|
||||
*/
|
||||
if (size > WILC_RX_BUFF_SIZE) {
|
||||
wilc->hif_func->hif_clear_int_ext(wilc,
|
||||
DATA_INT_CLR | ENABLE_RX_VMM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WILC_RX_BUFF_SIZE - offset < size)
|
||||
offset = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -852,8 +852,6 @@ int rsi_hal_load_key(struct rsi_common *common,
|
|||
memcpy(set_key->tx_mic_key, &data[16], 8);
|
||||
memcpy(set_key->rx_mic_key, &data[24], 8);
|
||||
}
|
||||
} else {
|
||||
memset(&set_key[FRAME_DESC_SZ], 0, frame_len - FRAME_DESC_SZ);
|
||||
}
|
||||
|
||||
skb_put(skb, frame_len);
|
||||
|
|
|
|||
|
|
@ -3724,10 +3724,8 @@ void wlcore_regdomain_config(struct wl1271 *wl)
|
|||
goto out;
|
||||
|
||||
ret = wlcore_cmd_regdomain_config_locked(wl);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
wl12xx_queue_recovery_work(wl);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pm_runtime_put_autosuspend(wl->dev);
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -2327,7 +2327,12 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw, bool suspend)
|
|||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
||||
data->started = false;
|
||||
/*
|
||||
* Serialise against wmediumd userspace, so no more frames
|
||||
* can be handed to mac80211 after this returns.
|
||||
*/
|
||||
scoped_guard(mutex, &data->mutex)
|
||||
data->started = false;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data->link_data); i++)
|
||||
hrtimer_cancel(&data->link_data[i].beacon_timer);
|
||||
|
|
@ -6505,12 +6510,12 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
|||
|
||||
if (frame_data_len < sizeof(struct ieee80211_hdr_3addr) ||
|
||||
frame_data_len > IEEE80211_MAX_DATA_LEN)
|
||||
goto err;
|
||||
goto out;
|
||||
|
||||
/* Allocate new skb here */
|
||||
skb = alloc_skb(frame_data_len, GFP_KERNEL);
|
||||
if (skb == NULL)
|
||||
goto err;
|
||||
goto out;
|
||||
|
||||
/* Copy the data */
|
||||
skb_put_data(skb, frame_data, frame_data_len);
|
||||
|
|
@ -6535,10 +6540,17 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
|||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialise against mac80211_hwsim_stop() - mac80211 doesn't allow
|
||||
* frames reported while the HW is down, hence the ->started check
|
||||
* must be under mutex.
|
||||
*/
|
||||
mutex_lock(&data2->mutex);
|
||||
|
||||
/* check if radio is configured properly */
|
||||
|
||||
if ((data2->idle && !data2->tmp_chan) || !data2->started)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
|
||||
/* A frame is received from user space */
|
||||
memset(&rx_status, 0, sizeof(rx_status));
|
||||
|
|
@ -6557,22 +6569,18 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
|||
iter_data.channel = ieee80211_get_channel(data2->hw->wiphy,
|
||||
rx_status.freq);
|
||||
if (!iter_data.channel)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
rx_status.band = iter_data.channel->band;
|
||||
|
||||
mutex_lock(&data2->mutex);
|
||||
if (!hwsim_chans_compat(iter_data.channel, channel)) {
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
data2->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
mac80211_hwsim_tx_iter, &iter_data);
|
||||
if (!iter_data.receive) {
|
||||
mutex_unlock(&data2->mutex);
|
||||
goto out;
|
||||
}
|
||||
if (!iter_data.receive)
|
||||
goto out_unlock;
|
||||
}
|
||||
mutex_unlock(&data2->mutex);
|
||||
} else if (!channel) {
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
} else {
|
||||
rx_status.freq = channel->center_freq;
|
||||
rx_status.band = channel->band;
|
||||
|
|
@ -6580,7 +6588,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
|||
|
||||
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
|
||||
if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
|
||||
|
||||
hdr = (void *)skb->data;
|
||||
|
|
@ -6590,10 +6598,11 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
|
|||
rx_status.boottime_ns = ktime_get_boottime_ns();
|
||||
|
||||
mac80211_hwsim_rx(data2, &rx_status, skb);
|
||||
mutex_unlock(&data2->mutex);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
pr_debug("mac80211_hwsim: error occurred in %s\n", __func__);
|
||||
out_unlock:
|
||||
mutex_unlock(&data2->mutex);
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -434,6 +434,7 @@ static netdev_tx_t virt_wifi_start_xmit(struct sk_buff *skb,
|
|||
priv->tx_packets++;
|
||||
if (!priv->is_connected) {
|
||||
priv->tx_failed++;
|
||||
dev_kfree_skb_any(skb);
|
||||
return NET_XMIT_DROP;
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +558,6 @@ static int virt_wifi_newlink(struct net_device *dev,
|
|||
}
|
||||
|
||||
eth_hw_addr_inherit(dev, priv->lowerdev);
|
||||
netif_stacked_transfer_operstate(priv->lowerdev, dev);
|
||||
|
||||
dev->ieee80211_ptr = kzalloc_obj(*dev->ieee80211_ptr);
|
||||
|
||||
|
|
@ -583,6 +583,8 @@ static int virt_wifi_newlink(struct net_device *dev,
|
|||
goto unregister_netdev;
|
||||
}
|
||||
|
||||
netif_stacked_transfer_operstate(priv->lowerdev, dev);
|
||||
|
||||
dev->priv_destructor = virt_wifi_net_device_destructor;
|
||||
priv->being_deleted = false;
|
||||
priv->is_connected = false;
|
||||
|
|
|
|||
|
|
@ -251,6 +251,14 @@ static int mbim_rx_verify_ndp16(struct sk_buff *skb, struct usb_cdc_ncm_ndp16 *n
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void mhi_mbim_rx_drop(struct mhi_mbim_link *link, struct sk_buff *skb)
|
||||
{
|
||||
dev_kfree_skb_any(skb);
|
||||
u64_stats_update_begin(&link->rx_syncp);
|
||||
u64_stats_inc(&link->rx_errors);
|
||||
u64_stats_update_end(&link->rx_syncp);
|
||||
}
|
||||
|
||||
static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb)
|
||||
{
|
||||
int ndpoffset;
|
||||
|
|
@ -320,7 +328,10 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb)
|
|||
continue;
|
||||
|
||||
skb_put(skbn, dgram_len);
|
||||
skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len);
|
||||
if (skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len)) {
|
||||
mhi_mbim_rx_drop(link, skbn);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (skbn->data[0] & 0xf0) {
|
||||
case 0x40:
|
||||
|
|
@ -332,10 +343,7 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb)
|
|||
default:
|
||||
net_err_ratelimited("%s: unknown protocol\n",
|
||||
link->ndev->name);
|
||||
dev_kfree_skb_any(skbn);
|
||||
u64_stats_update_begin(&link->rx_syncp);
|
||||
u64_stats_inc(&link->rx_errors);
|
||||
u64_stats_update_end(&link->rx_syncp);
|
||||
mhi_mbim_rx_drop(link, skbn);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -349,9 +357,13 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb)
|
|||
unlock:
|
||||
rcu_read_unlock();
|
||||
next_ndp:
|
||||
/* Other NDP to process? */
|
||||
ndpoffset = (int)le16_to_cpu(ndp16.wNextNdpIndex);
|
||||
if (!ndpoffset)
|
||||
/* Other NDP to process? The offsets must advance, or a
|
||||
* self-referencing NDP keeps the loop spinning forever.
|
||||
*/
|
||||
n = (int)le16_to_cpu(ndp16.wNextNdpIndex);
|
||||
if (n > ndpoffset)
|
||||
ndpoffset = n;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -420,6 +420,10 @@ static void t7xx_ccmni_recv_skb(struct t7xx_ccmni_ctrl *ccmni_ctlb, struct sk_bu
|
|||
|
||||
skb_cb = T7XX_SKB_CB(skb);
|
||||
netif_id = skb_cb->netif_idx;
|
||||
if (netif_id >= NIC_DEV_MAX) {
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
ccmni = READ_ONCE(ccmni_ctlb->ccmni_inst[netif_id]);
|
||||
if (!ccmni) {
|
||||
dev_kfree_skb(skb);
|
||||
|
|
|
|||
|
|
@ -361,8 +361,7 @@ ieee80211_mesh_hwmp_perr_get_rcode(const u8 *ie, u8 dst_idx)
|
|||
/* IEEE Std 802.11-2016 9.4.2.113 PREQ element */
|
||||
static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen)
|
||||
{
|
||||
struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom =
|
||||
ieee80211_mesh_hwmp_preq_get_bottom(pos);
|
||||
struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom;
|
||||
u8 target_count;
|
||||
int needed;
|
||||
|
||||
|
|
@ -378,6 +377,7 @@ static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen)
|
|||
if (elen < needed)
|
||||
return false;
|
||||
|
||||
preq_elem_bottom = ieee80211_mesh_hwmp_preq_get_bottom(pos);
|
||||
target_count = preq_elem_bottom->target_count;
|
||||
/* IEEE Std 802.11-2016 Table 14-10 to 14-16 */
|
||||
if (target_count < 1)
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ struct hci_devcoredump {
|
|||
const char *hci_devcd_state_name(enum devcoredump_state state);
|
||||
|
||||
void hci_devcd_reset(struct hci_dev *hdev);
|
||||
void hci_devcd_shutdown(struct hci_dev *hdev);
|
||||
void hci_devcd_rx(struct work_struct *work);
|
||||
void hci_devcd_timeout(struct work_struct *work);
|
||||
|
||||
|
|
@ -89,6 +90,7 @@ static inline const char *hci_devcd_state_name(enum devcoredump_state state)
|
|||
}
|
||||
|
||||
static inline void hci_devcd_reset(struct hci_dev *hdev) {}
|
||||
static inline void hci_devcd_shutdown(struct hci_dev *hdev) {}
|
||||
static inline void hci_devcd_rx(struct work_struct *work) {}
|
||||
static inline void hci_devcd_timeout(struct work_struct *work) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -140,6 +140,11 @@ struct codel_vars {
|
|||
/* needed shift to get a Q0.32 number from rec_inv_sqrt */
|
||||
#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
|
||||
|
||||
/* Cap on drops per codel_dequeue() call: the loop's work depends on the
|
||||
* idle gap and backlog, both outside our control; resync when exceeded.
|
||||
*/
|
||||
#define CODEL_MAX_DROPS_PER_DEQUEUE 256
|
||||
|
||||
/**
|
||||
* struct codel_stats - contains codel shared variables and stats
|
||||
* @maxpacket: largest packet we've seen so far
|
||||
|
|
|
|||
|
|
@ -93,12 +93,17 @@ static void codel_Newton_step(struct codel_vars *vars)
|
|||
* CoDel control_law is t + interval/sqrt(count)
|
||||
* We maintain in rec_inv_sqrt the reciprocal value of sqrt(count) to avoid
|
||||
* both sqrt() and divide operation.
|
||||
*
|
||||
* Clamp the increment to at least 1 tick: a very small interval (or a
|
||||
* large count) can truncate it to zero, stalling the dropping loop.
|
||||
*/
|
||||
static codel_time_t codel_control_law(codel_time_t t,
|
||||
codel_time_t interval,
|
||||
u32 rec_inv_sqrt)
|
||||
{
|
||||
return t + reciprocal_scale(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT);
|
||||
return t + max_t(u32, 1,
|
||||
reciprocal_scale(interval,
|
||||
rec_inv_sqrt << REC_INV_SQRT_SHIFT));
|
||||
}
|
||||
|
||||
static bool codel_should_drop(const struct sk_buff *skb,
|
||||
|
|
@ -154,6 +159,7 @@ static struct sk_buff *codel_dequeue(void *ctx,
|
|||
codel_skb_dequeue_t dequeue_func)
|
||||
{
|
||||
struct sk_buff *skb = dequeue_func(vars, ctx);
|
||||
unsigned int drops = 0;
|
||||
codel_time_t now;
|
||||
bool drop;
|
||||
|
||||
|
|
@ -180,6 +186,14 @@ static struct sk_buff *codel_dequeue(void *ctx,
|
|||
*/
|
||||
while (vars->dropping &&
|
||||
codel_time_after_eq(now, vars->drop_next)) {
|
||||
if (++drops > CODEL_MAX_DROPS_PER_DEQUEUE) {
|
||||
/* fell far behind the schedule */
|
||||
WRITE_ONCE(vars->drop_next,
|
||||
codel_control_law(now,
|
||||
params->interval,
|
||||
vars->rec_inv_sqrt));
|
||||
break;
|
||||
}
|
||||
/* dont care of possible wrap
|
||||
* since there is no more divide.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7638,11 +7638,14 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
|
|||
*
|
||||
* @skb: packet injected by userspace
|
||||
* @dev: the &struct device of this 802.11 device
|
||||
* @chandef: the channel definition the frame will be transmitted on, or
|
||||
* %NULL to skip the bandwidth checks
|
||||
*
|
||||
* Return: %true if the radiotap header was parsed, %false otherwise
|
||||
*/
|
||||
bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
struct net_device *dev,
|
||||
const struct cfg80211_chan_def *chandef);
|
||||
|
||||
/**
|
||||
* struct ieee80211_noa_data - holds temporary data for tracking P2P NoA state
|
||||
|
|
|
|||
|
|
@ -2312,6 +2312,8 @@ static inline void sk_gso_disable(struct sock *sk)
|
|||
sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
|
||||
}
|
||||
|
||||
bool sk_has_decrypt_user(const struct sock *sk);
|
||||
|
||||
static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb,
|
||||
struct iov_iter *from, char *to,
|
||||
int copy, int offset)
|
||||
|
|
|
|||
|
|
@ -292,10 +292,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
|||
struct atm_vcc *vcc;
|
||||
int ret;
|
||||
|
||||
if (!pskb_may_pull(skb, 1)) {
|
||||
kfree_skb(skb);
|
||||
return DROP_PACKET;
|
||||
}
|
||||
|
||||
ATM_SKB(skb)->vcc = pvcc->atmvcc;
|
||||
pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);
|
||||
if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
|
||||
(void) skb_pull(skb, 1);
|
||||
|
||||
vcc = ATM_SKB(skb)->vcc;
|
||||
bh_lock_sock(sk_atm(vcc));
|
||||
|
|
@ -317,23 +320,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
|||
|
||||
switch (pvcc->encaps) { /* LLC encapsulation needed */
|
||||
case e_llc:
|
||||
if (skb_headroom(skb) < LLC_LEN) {
|
||||
struct sk_buff *n;
|
||||
n = skb_realloc_headroom(skb, LLC_LEN);
|
||||
if (n != NULL &&
|
||||
!pppoatm_may_send(pvcc, n->truesize)) {
|
||||
kfree_skb(n);
|
||||
goto nospace;
|
||||
}
|
||||
consume_skb(skb);
|
||||
skb = n;
|
||||
if (skb == NULL) {
|
||||
bh_unlock_sock(sk_atm(vcc));
|
||||
return DROP_PACKET;
|
||||
}
|
||||
} else if (!pppoatm_may_send(pvcc, skb->truesize))
|
||||
if (skb_cow_head(skb, LLC_LEN)) {
|
||||
bh_unlock_sock(sk_atm(vcc));
|
||||
kfree_skb(skb);
|
||||
return DROP_PACKET;
|
||||
}
|
||||
if (!pppoatm_may_send(pvcc, skb->truesize))
|
||||
goto nospace;
|
||||
memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
|
||||
break;
|
||||
case e_vc:
|
||||
if (!pppoatm_may_send(pvcc, skb->truesize))
|
||||
|
|
@ -346,6 +339,12 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
|
||||
skb_pull(skb, 1);
|
||||
|
||||
if (pvcc->encaps == e_llc)
|
||||
memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
|
||||
|
||||
atm_account_tx(vcc, skb);
|
||||
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
|
||||
skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
|
||||
|
|
@ -355,13 +354,6 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
|||
return ret;
|
||||
nospace:
|
||||
bh_unlock_sock(sk_atm(vcc));
|
||||
/*
|
||||
* We don't have space to send this SKB now, but we might have
|
||||
* already applied SC_COMP_PROT compression, so may need to undo
|
||||
*/
|
||||
if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 &&
|
||||
skb->data[-1] == '\0')
|
||||
(void) skb_push(skb, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,22 @@ static void hci_devcd_free(struct hci_dev *hdev)
|
|||
hci_devcd_reset(hdev);
|
||||
}
|
||||
|
||||
void hci_devcd_shutdown(struct hci_dev *hdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hdev->dump.dump_q.lock, flags);
|
||||
hdev->dump.supported = false;
|
||||
spin_unlock_irqrestore(&hdev->dump.dump_q.lock, flags);
|
||||
|
||||
disable_work_sync(&hdev->dump.dump_rx);
|
||||
disable_delayed_work_sync(&hdev->dump.dump_timeout);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_devcd_free(hdev);
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
/* Call with hci_dev_lock only. */
|
||||
static int hci_devcd_alloc(struct hci_dev *hdev, u32 size)
|
||||
{
|
||||
|
|
@ -442,7 +458,29 @@ EXPORT_SYMBOL(hci_devcd_register);
|
|||
|
||||
static inline bool hci_devcd_enabled(struct hci_dev *hdev)
|
||||
{
|
||||
return hdev->dump.supported;
|
||||
return READ_ONCE(hdev->dump.supported);
|
||||
}
|
||||
|
||||
static int hci_devcd_queue(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
spin_lock_irqsave(&hdev->dump.dump_q.lock, flags);
|
||||
if (!hdev->dump.supported)
|
||||
err = -EOPNOTSUPP;
|
||||
else
|
||||
__skb_queue_tail(&hdev->dump.dump_q, skb);
|
||||
spin_unlock_irqrestore(&hdev->dump.dump_q.lock, flags);
|
||||
|
||||
if (err) {
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hci_devcd_init(struct hci_dev *hdev, u32 dump_size)
|
||||
|
|
@ -459,10 +497,7 @@ int hci_devcd_init(struct hci_dev *hdev, u32 dump_size)
|
|||
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_INIT;
|
||||
put_unaligned_le32(dump_size, skb_put(skb, 4));
|
||||
|
||||
skb_queue_tail(&hdev->dump.dump_q, skb);
|
||||
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
|
||||
|
||||
return 0;
|
||||
return hci_devcd_queue(hdev, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_devcd_init);
|
||||
|
||||
|
|
@ -478,10 +513,7 @@ int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
|
||||
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_SKB;
|
||||
|
||||
skb_queue_tail(&hdev->dump.dump_q, skb);
|
||||
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
|
||||
|
||||
return 0;
|
||||
return hci_devcd_queue(hdev, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_devcd_append);
|
||||
|
||||
|
|
@ -503,10 +535,7 @@ int hci_devcd_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len)
|
|||
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_PATTERN;
|
||||
skb_put_data(skb, &p, sizeof(p));
|
||||
|
||||
skb_queue_tail(&hdev->dump.dump_q, skb);
|
||||
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
|
||||
|
||||
return 0;
|
||||
return hci_devcd_queue(hdev, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_devcd_append_pattern);
|
||||
|
||||
|
|
@ -523,10 +552,7 @@ int hci_devcd_complete(struct hci_dev *hdev)
|
|||
|
||||
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_COMPLETE;
|
||||
|
||||
skb_queue_tail(&hdev->dump.dump_q, skb);
|
||||
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
|
||||
|
||||
return 0;
|
||||
return hci_devcd_queue(hdev, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_devcd_complete);
|
||||
|
||||
|
|
@ -543,10 +569,7 @@ int hci_devcd_abort(struct hci_dev *hdev)
|
|||
|
||||
hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_ABORT;
|
||||
|
||||
skb_queue_tail(&hdev->dump.dump_q, skb);
|
||||
queue_work(hdev->workqueue, &hdev->dump.dump_rx);
|
||||
|
||||
return 0;
|
||||
return hci_devcd_queue(hdev, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_devcd_abort);
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,15 @@ void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len)
|
|||
size_t dlen;
|
||||
|
||||
while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, &dlen))) {
|
||||
u16 value = get_unaligned_le16(eir);
|
||||
u16 value;
|
||||
|
||||
if (dlen < sizeof(value)) {
|
||||
eir += dlen;
|
||||
eir_len = eir_end - eir;
|
||||
continue;
|
||||
}
|
||||
|
||||
value = get_unaligned_le16(eir);
|
||||
|
||||
if (uuid == value) {
|
||||
if (len)
|
||||
|
|
|
|||
|
|
@ -145,11 +145,12 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
|
|||
|
||||
skb_pull(skb, sizeof(rp->status));
|
||||
|
||||
std_codecs = (void *)skb->data;
|
||||
std_codecs = skb_pull_data(skb, sizeof(*std_codecs));
|
||||
if (!std_codecs)
|
||||
goto error;
|
||||
|
||||
/* validate codecs length before accessing */
|
||||
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
|
||||
+ sizeof(std_codecs->num))
|
||||
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num))
|
||||
goto error;
|
||||
|
||||
/* enumerate codec capabilities of standard codecs */
|
||||
|
|
@ -161,15 +162,14 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
|
|||
LOCAL_CODEC_ACL_MASK | LOCAL_CODEC_SCO_MASK, &caps);
|
||||
}
|
||||
|
||||
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
|
||||
+ sizeof(std_codecs->num));
|
||||
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num));
|
||||
|
||||
vnd_codecs = (void *)skb->data;
|
||||
vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs));
|
||||
if (!vnd_codecs)
|
||||
goto error;
|
||||
|
||||
/* validate vendor codecs length before accessing */
|
||||
if (skb->len <
|
||||
flex_array_size(vnd_codecs, codec, vnd_codecs->num)
|
||||
+ sizeof(vnd_codecs->num))
|
||||
if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num))
|
||||
goto error;
|
||||
|
||||
/* enumerate vendor codec capabilities */
|
||||
|
|
@ -214,11 +214,12 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)
|
|||
|
||||
skb_pull(skb, sizeof(rp->status));
|
||||
|
||||
std_codecs = (void *)skb->data;
|
||||
std_codecs = skb_pull_data(skb, sizeof(*std_codecs));
|
||||
if (!std_codecs)
|
||||
goto error;
|
||||
|
||||
/* check for payload data length before accessing */
|
||||
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
|
||||
+ sizeof(std_codecs->num))
|
||||
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num))
|
||||
goto error;
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
|
|
@ -229,15 +230,14 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)
|
|||
&caps);
|
||||
}
|
||||
|
||||
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
|
||||
+ sizeof(std_codecs->num));
|
||||
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num));
|
||||
|
||||
vnd_codecs = (void *)skb->data;
|
||||
vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs));
|
||||
if (!vnd_codecs)
|
||||
goto error;
|
||||
|
||||
/* check for payload data length before accessing */
|
||||
if (skb->len <
|
||||
flex_array_size(vnd_codecs, codec, vnd_codecs->num)
|
||||
+ sizeof(vnd_codecs->num))
|
||||
if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num))
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < vnd_codecs->num; i++) {
|
||||
|
|
|
|||
|
|
@ -1023,6 +1023,19 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,
|
|||
if (!hdev->le_mtu && hdev->acl_mtu < HCI_MIN_LE_MTU)
|
||||
return ERR_PTR(-ECONNREFUSED);
|
||||
irk = hci_get_irk(hdev, dst, dst_type);
|
||||
/* An identity address only reaches a peer advertising an RPA
|
||||
* if the controller translates it. Unless address resolution
|
||||
* is enabled and this peer is programmed into the resolving
|
||||
* list, keep the RPA the peer is on air with;
|
||||
* le_conn_complete_evt() resolves it back once the link is
|
||||
* up.
|
||||
*/
|
||||
if (irk &&
|
||||
(!hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION) ||
|
||||
!hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
|
||||
&irk->bdaddr,
|
||||
irk->addr_type)))
|
||||
irk = NULL;
|
||||
break;
|
||||
case SCO_LINK:
|
||||
case ESCO_LINK:
|
||||
|
|
@ -1505,7 +1518,15 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
}
|
||||
|
||||
if (conn) {
|
||||
/* dst may just have been swapped for the peer's RPA above, and
|
||||
* dst_type describes dst -- it has to travel with it. Leaving
|
||||
* the identity type behind makes the pair describe a peer that
|
||||
* does not exist, and nothing downstream repairs it:
|
||||
* hci_bdaddr_is_rpa() tests the type before the address, so
|
||||
* the RPA is never treated as one.
|
||||
*/
|
||||
bacpy(&conn->dst, dst);
|
||||
conn->dst_type = dst_type;
|
||||
} else {
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, dst, dst_type, role);
|
||||
if (IS_ERR(conn))
|
||||
|
|
|
|||
|
|
@ -2673,6 +2673,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
|
|||
disable_work_sync(&hdev->error_reset);
|
||||
disable_delayed_work_sync(&hdev->cmd_timer);
|
||||
disable_delayed_work_sync(&hdev->ncmd_timer);
|
||||
hci_devcd_shutdown(hdev);
|
||||
|
||||
hci_cmd_sync_clear(hdev);
|
||||
|
||||
|
|
@ -3236,6 +3237,17 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
|
|||
bt_dev_dbg(hdev, "chan %p queued %d", chan, skb_queue_len(queue));
|
||||
}
|
||||
|
||||
/* Queue hdev->tx_work, unless hdev->workqueue is being drained by
|
||||
* hci_dev_close_sync(), which would otherwise WARN and drop the work.
|
||||
*/
|
||||
static void hci_sched_tx(struct hci_dev *hdev)
|
||||
{
|
||||
rcu_read_lock();
|
||||
if (!hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
|
||||
{
|
||||
struct hci_dev *hdev = chan->conn->hdev;
|
||||
|
|
@ -3244,7 +3256,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
|
|||
|
||||
hci_queue_acl(chan, &chan->data_q, skb, flags);
|
||||
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
hci_sched_tx(hdev);
|
||||
}
|
||||
|
||||
/* Send SCO data */
|
||||
|
|
@ -3269,7 +3281,7 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
|
|||
bt_dev_dbg(hdev, "hcon %p queued %d", conn,
|
||||
skb_queue_len(&conn->data_q));
|
||||
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
hci_sched_tx(hdev);
|
||||
}
|
||||
|
||||
/* Send ISO data */
|
||||
|
|
@ -3340,7 +3352,7 @@ void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb)
|
|||
|
||||
hci_queue_iso(conn, &conn->data_q, skb);
|
||||
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
hci_sched_tx(hdev);
|
||||
}
|
||||
|
||||
/* ---- HCI TX task (outgoing data) ---- */
|
||||
|
|
|
|||
|
|
@ -5673,7 +5673,9 @@ int hci_dev_close_sync(struct hci_dev *hdev)
|
|||
memset(hdev->eir, 0, sizeof(hdev->eir));
|
||||
memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
|
||||
bacpy(&hdev->random_addr, BDADDR_ANY);
|
||||
hci_dev_lock(hdev);
|
||||
hci_codec_list_clear(&hdev->local_codecs);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
hci_dev_put(hdev);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -819,19 +819,24 @@ static void iso_sock_destruct(struct sock *sk)
|
|||
skb_queue_purge(&sk->sk_error_queue);
|
||||
}
|
||||
|
||||
static void iso_sock_cleanup_listen(struct sock *parent)
|
||||
/* Close not yet accepted channels */
|
||||
static void iso_sock_flush_accept_q(struct sock *parent)
|
||||
{
|
||||
struct sock *sk;
|
||||
|
||||
BT_DBG("parent %p", parent);
|
||||
|
||||
/* Close not yet accepted channels */
|
||||
while ((sk = bt_accept_dequeue(parent, NULL))) {
|
||||
iso_sock_close(sk);
|
||||
iso_sock_kill(sk);
|
||||
/* Drop the reference handed back by bt_accept_dequeue(). */
|
||||
sock_put(sk);
|
||||
}
|
||||
}
|
||||
|
||||
static void iso_sock_cleanup_listen(struct sock *parent)
|
||||
{
|
||||
BT_DBG("parent %p", parent);
|
||||
|
||||
iso_sock_flush_accept_q(parent);
|
||||
|
||||
/* If listening socket has a hcon, properly disconnect it */
|
||||
if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon) {
|
||||
|
|
@ -1737,6 +1742,13 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
switch (sk->sk_state) {
|
||||
case BT_CONNECT2:
|
||||
if (test_bit(BT_SK_PA_SYNC, &pi->flags)) {
|
||||
/* Move to BT_LISTEN before requesting the BIG
|
||||
* sync: the BIS connections are matched to a
|
||||
* parent socket in BT_LISTEN state, and they
|
||||
* may be notified before the request returns.
|
||||
*/
|
||||
sk->sk_state = BT_LISTEN;
|
||||
|
||||
release_sock(sk);
|
||||
err = iso_conn_big_sync(sk);
|
||||
lock_sock(sk);
|
||||
|
|
@ -1745,12 +1757,20 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
* connection may have been torn down
|
||||
* meanwhile and iso_chan_del() may have
|
||||
* already moved the socket to BT_CLOSED.
|
||||
* Only move on to BT_LISTEN if the BIG sync
|
||||
* was actually started and nothing else has
|
||||
* changed the state.
|
||||
* Only move back if the BIG sync could not be
|
||||
* started and nothing else has changed the
|
||||
* state.
|
||||
*/
|
||||
if (!err && sk->sk_state == BT_CONNECT2)
|
||||
sk->sk_state = BT_LISTEN;
|
||||
if (err && sk->sk_state == BT_LISTEN) {
|
||||
/* Discard any child socket that may
|
||||
* have been queued while the socket
|
||||
* was in BT_LISTEN, as the cleanup of
|
||||
* BT_CONNECT2 doesn't drain the
|
||||
* accept queue.
|
||||
*/
|
||||
iso_sock_flush_accept_q(sk);
|
||||
sk->sk_state = BT_CONNECT2;
|
||||
}
|
||||
} else {
|
||||
iso_conn_defer_accept(pi->conn->hcon);
|
||||
sk->sk_state = BT_CONFIG;
|
||||
|
|
@ -1760,12 +1780,22 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
break;
|
||||
case BT_CONNECTED:
|
||||
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
|
||||
/* As above, the BIS connections may be
|
||||
* notified before the request returns.
|
||||
*/
|
||||
sk->sk_state = BT_LISTEN;
|
||||
|
||||
release_sock(sk);
|
||||
err = iso_conn_big_sync(sk);
|
||||
lock_sock(sk);
|
||||
|
||||
if (!err && sk->sk_state == BT_CONNECTED)
|
||||
sk->sk_state = BT_LISTEN;
|
||||
if (err && sk->sk_state == BT_LISTEN) {
|
||||
/* As above, don't leave any child
|
||||
* socket behind in the accept queue.
|
||||
*/
|
||||
iso_sock_flush_accept_q(sk);
|
||||
sk->sk_state = BT_CONNECTED;
|
||||
}
|
||||
early_ret = true;
|
||||
}
|
||||
|
||||
|
|
@ -2289,6 +2319,7 @@ static void iso_conn_ready(struct iso_conn *conn)
|
|||
BTPROTO_ISO, GFP_ATOMIC, 0);
|
||||
if (!sk) {
|
||||
release_sock(parent);
|
||||
sock_put(parent);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -242,9 +242,7 @@ static void __rfcomm_sock_close(struct sock *sk)
|
|||
*/
|
||||
static void rfcomm_sock_close(struct sock *sk)
|
||||
{
|
||||
lock_sock(sk);
|
||||
__rfcomm_sock_close(sk);
|
||||
release_sock(sk);
|
||||
}
|
||||
|
||||
static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
|
||||
|
|
@ -905,6 +903,7 @@ static int rfcomm_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsig
|
|||
static int rfcomm_sock_shutdown(struct socket *sock, int how)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
bool cleanup_listen = false;
|
||||
int err = 0;
|
||||
|
||||
BT_DBG("sock %p, sk %p", sock, sk);
|
||||
|
|
@ -915,9 +914,17 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how)
|
|||
lock_sock(sk);
|
||||
if (!sk->sk_shutdown) {
|
||||
sk->sk_shutdown = SHUTDOWN_MASK;
|
||||
if (sk->sk_state == BT_LISTEN) {
|
||||
/* Block new children before cleaning up without sk lock. */
|
||||
sk->sk_state = BT_CLOSED;
|
||||
cleanup_listen = true;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
__rfcomm_sock_close(sk);
|
||||
if (cleanup_listen)
|
||||
rfcomm_sock_cleanup_listen(sk);
|
||||
else
|
||||
__rfcomm_sock_close(sk);
|
||||
lock_sock(sk);
|
||||
|
||||
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
|
||||
|
|
|
|||
|
|
@ -107,21 +107,24 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
|
|||
struct net_bridge_vlan *v;
|
||||
int err = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
vg = nbp_vlan_group_rcu(p);
|
||||
if (!vg)
|
||||
goto out;
|
||||
|
||||
/* MSTI 0 (CST) state changes are notified via the regular
|
||||
* SWITCHDEV_ATTR_ID_PORT_STP_STATE.
|
||||
* SWITCHDEV_ATTR_ID_PORT_STP_STATE. All other MSTIs are handled via
|
||||
* netlink with RTNL held
|
||||
*/
|
||||
if (msti) {
|
||||
ASSERT_RTNL();
|
||||
|
||||
err = switchdev_port_attr_set(p->dev, &attr, extack);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
goto out;
|
||||
err = 0;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
rcu_read_lock();
|
||||
vg = nbp_vlan_group_rcu(p);
|
||||
if (!vg)
|
||||
goto out_rcu_unlock;
|
||||
|
||||
list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
|
||||
if (v->brvlan->msti != msti)
|
||||
continue;
|
||||
|
|
@ -129,8 +132,9 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state,
|
|||
br_mst_vlan_set_state(vg, v, state);
|
||||
}
|
||||
|
||||
out:
|
||||
out_rcu_unlock:
|
||||
rcu_read_unlock();
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -387,12 +387,12 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags,
|
|||
goto out;
|
||||
}
|
||||
|
||||
static int __vlan_del(struct net_bridge_vlan *v)
|
||||
static void __vlan_del(struct net_bridge_vlan *v)
|
||||
{
|
||||
struct net_bridge_vlan *masterv = v;
|
||||
struct net_bridge_vlan_group *vg;
|
||||
struct net_bridge_port *p = NULL;
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
if (br_vlan_is_master(v)) {
|
||||
vg = br_vlan_group(v->br);
|
||||
|
|
@ -406,12 +406,16 @@ static int __vlan_del(struct net_bridge_vlan *v)
|
|||
if (p) {
|
||||
err = __vlan_vid_del(p->dev, p->br, v);
|
||||
if (err)
|
||||
goto out;
|
||||
br_warn(p->br,
|
||||
"port %u(%s) failed to delete vlan %u from switchdev: %pe\n",
|
||||
(unsigned int)p->port_no, p->dev->name,
|
||||
v->vid, ERR_PTR(err));
|
||||
} else {
|
||||
err = br_switchdev_port_vlan_del(v->br->dev, v->vid);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
goto out;
|
||||
err = 0;
|
||||
br_warn(v->br,
|
||||
"failed to delete bridge vlan %u from switchdev: %pe\n",
|
||||
v->vid, ERR_PTR(err));
|
||||
}
|
||||
|
||||
if (br_vlan_should_use(v)) {
|
||||
|
|
@ -431,8 +435,6 @@ static int __vlan_del(struct net_bridge_vlan *v)
|
|||
}
|
||||
|
||||
br_vlan_put_master(masterv);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __vlan_group_free(struct net_bridge_vlan_group *vg)
|
||||
|
|
@ -449,7 +451,6 @@ static void __vlan_flush(const struct net_bridge *br,
|
|||
{
|
||||
struct net_bridge_vlan *vlan, *tmp;
|
||||
u16 v_start = 0, v_end = 0;
|
||||
int err;
|
||||
|
||||
__vlan_delete_pvid(vg, vg->pvid);
|
||||
list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist) {
|
||||
|
|
@ -463,13 +464,7 @@ static void __vlan_flush(const struct net_bridge *br,
|
|||
}
|
||||
v_end = vlan->vid;
|
||||
|
||||
err = __vlan_del(vlan);
|
||||
if (err) {
|
||||
br_err(br,
|
||||
"port %u(%s) failed to delete vlan %d: %pe\n",
|
||||
(unsigned int) p->port_no, p->dev->name,
|
||||
vlan->vid, ERR_PTR(err));
|
||||
}
|
||||
__vlan_del(vlan);
|
||||
}
|
||||
|
||||
/* notify about the last/whole vlan range */
|
||||
|
|
@ -837,8 +832,9 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
|
|||
br_fdb_delete_by_port(br, NULL, vid, 0);
|
||||
|
||||
vlan_tunnel_info_del(vg, v);
|
||||
__vlan_del(v);
|
||||
|
||||
return __vlan_del(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void br_vlan_flush(struct net_bridge *br)
|
||||
|
|
@ -1368,8 +1364,9 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
|
|||
return -ENOENT;
|
||||
br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid);
|
||||
br_fdb_delete_by_port(port->br, port, vid, 0);
|
||||
__vlan_del(v);
|
||||
|
||||
return __vlan_del(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nbp_vlan_flush(struct net_bridge_port *port)
|
||||
|
|
|
|||
|
|
@ -789,7 +789,7 @@ int dev_fill_forward_path(struct net_device_path_ctx *ctx,
|
|||
goto err_out;
|
||||
|
||||
stack->num_paths++;
|
||||
if (WARN_ON_ONCE(last_dev == ctx->dev))
|
||||
if (last_dev == ctx->dev)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,9 +141,8 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data)
|
|||
|
||||
al = sizeof(struct net_dm_alert_msg);
|
||||
al += dm_hit_limit * sizeof(struct net_dm_drop_point);
|
||||
al += sizeof(struct nlattr);
|
||||
|
||||
skb = genlmsg_new(al, GFP_KERNEL);
|
||||
skb = genlmsg_new(nla_total_size(al), GFP_KERNEL);
|
||||
|
||||
if (!skb)
|
||||
goto err;
|
||||
|
|
@ -448,7 +447,7 @@ net_dm_hw_trap_summary_probe(void *ignore, const struct devlink *devlink,
|
|||
if (metadata->trap_type == DEVLINK_TRAP_TYPE_CONTROL)
|
||||
return;
|
||||
|
||||
hw_data = this_cpu_ptr(&dm_hw_cpu_data);
|
||||
hw_data = raw_cpu_ptr(&dm_hw_cpu_data);
|
||||
raw_spin_lock_irqsave(&hw_data->lock, flags);
|
||||
hw_entries = hw_data->hw_entries;
|
||||
|
||||
|
|
@ -516,7 +515,7 @@ static void net_dm_packet_trace_kfree_skb_hit(void *ignore,
|
|||
*/
|
||||
nskb->tstamp = tstamp;
|
||||
|
||||
data = this_cpu_ptr(&dm_cpu_data);
|
||||
data = raw_cpu_ptr(&dm_cpu_data);
|
||||
|
||||
spin_lock_irqsave(&data->drop_queue.lock, flags);
|
||||
if (skb_queue_len(&data->drop_queue) < net_dm_queue_len)
|
||||
|
|
@ -983,7 +982,7 @@ net_dm_hw_trap_packet_probe(void *ignore, const struct devlink *devlink,
|
|||
NET_DM_SKB_CB(nskb)->hw_metadata = n_hw_metadata;
|
||||
nskb->tstamp = tstamp;
|
||||
|
||||
hw_data = this_cpu_ptr(&dm_hw_cpu_data);
|
||||
hw_data = raw_cpu_ptr(&dm_hw_cpu_data);
|
||||
|
||||
spin_lock_irqsave(&hw_data->drop_queue.lock, flags);
|
||||
if (skb_queue_len(&hw_data->drop_queue) < net_dm_queue_len)
|
||||
|
|
@ -1083,7 +1082,7 @@ static int net_dm_hw_monitor_start(struct netlink_ext_ack *extack)
|
|||
struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu);
|
||||
struct sk_buff *skb;
|
||||
|
||||
timer_delete_sync(&hw_data->send_timer);
|
||||
timer_shutdown_sync(&hw_data->send_timer);
|
||||
cancel_work_sync(&hw_data->dm_alert_work);
|
||||
while ((skb = __skb_dequeue(&hw_data->drop_queue))) {
|
||||
struct devlink_trap_metadata *hw_metadata;
|
||||
|
|
@ -1117,7 +1116,7 @@ static void net_dm_hw_monitor_stop(struct netlink_ext_ack *extack)
|
|||
struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu);
|
||||
struct sk_buff *skb;
|
||||
|
||||
timer_delete_sync(&hw_data->send_timer);
|
||||
timer_shutdown_sync(&hw_data->send_timer);
|
||||
cancel_work_sync(&hw_data->dm_alert_work);
|
||||
while ((skb = __skb_dequeue(&hw_data->drop_queue))) {
|
||||
struct devlink_trap_metadata *hw_metadata;
|
||||
|
|
@ -1173,12 +1172,13 @@ static int net_dm_trace_on_set(struct netlink_ext_ack *extack)
|
|||
|
||||
err_unregister_trace:
|
||||
unregister_trace_kfree_skb(ops->kfree_skb_probe, NULL);
|
||||
tracepoint_synchronize_unregister();
|
||||
err_module_put:
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct per_cpu_dm_data *data = &per_cpu(dm_cpu_data, cpu);
|
||||
struct sk_buff *skb;
|
||||
|
||||
timer_delete_sync(&data->send_timer);
|
||||
timer_shutdown_sync(&data->send_timer);
|
||||
cancel_work_sync(&data->dm_alert_work);
|
||||
while ((skb = __skb_dequeue(&data->drop_queue)))
|
||||
consume_skb(skb);
|
||||
|
|
@ -1206,7 +1206,7 @@ static void net_dm_trace_off_set(void)
|
|||
struct per_cpu_dm_data *data = &per_cpu(dm_cpu_data, cpu);
|
||||
struct sk_buff *skb;
|
||||
|
||||
timer_delete_sync(&data->send_timer);
|
||||
timer_shutdown_sync(&data->send_timer);
|
||||
cancel_work_sync(&data->dm_alert_work);
|
||||
while ((skb = __skb_dequeue(&data->drop_queue)))
|
||||
consume_skb(skb);
|
||||
|
|
|
|||
|
|
@ -2359,6 +2359,13 @@ static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
|
|||
[NDTA_PARMS] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
#define NTBL_PARM_MS_MAX (24 * 60 * 60 * MSEC_PER_SEC)
|
||||
|
||||
static const struct netlink_range_validation nl_ntbl_parm_ms_range = {
|
||||
.min = 1,
|
||||
.max = NTBL_PARM_MS_MAX,
|
||||
};
|
||||
|
||||
static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
|
||||
[NDTPA_IFINDEX] = { .type = NLA_U32 },
|
||||
[NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
|
||||
|
|
@ -2375,7 +2382,8 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
|
|||
[NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
|
||||
[NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
|
||||
[NDTPA_LOCKTIME] = { .type = NLA_U64 },
|
||||
[NDTPA_INTERVAL_PROBE_TIME_MS] = { .type = NLA_U64, .min = 1 },
|
||||
[NDTPA_INTERVAL_PROBE_TIME_MS] = NLA_POLICY_FULL_RANGE(NLA_U64,
|
||||
&nl_ntbl_parm_ms_range),
|
||||
};
|
||||
|
||||
static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
|
|
@ -2579,9 +2587,10 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
{
|
||||
const struct nlmsghdr *nlh = cb->nlh;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
int default_skip = cb->args[2];
|
||||
int neigh_skip = cb->args[1];
|
||||
int family, tidx, nidx = 0;
|
||||
int tbl_skip = cb->args[0];
|
||||
int neigh_skip = cb->args[1];
|
||||
struct neigh_table *tbl;
|
||||
|
||||
if (cb->strict_check) {
|
||||
|
|
@ -2605,17 +2614,21 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
if (tidx < tbl_skip || (family && tbl->family != family))
|
||||
continue;
|
||||
|
||||
if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
|
||||
if (!default_skip &&
|
||||
neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
|
||||
nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
|
||||
NLM_F_MULTI) < 0)
|
||||
break;
|
||||
|
||||
nidx = 0;
|
||||
p = list_next_entry(&tbl->parms, list);
|
||||
list_for_each_entry_from_rcu(p, &tbl->parms_list, list) {
|
||||
default_skip = 1;
|
||||
|
||||
list_for_each_entry_rcu(p, &tbl->parms_list, list) {
|
||||
if (!net_eq(neigh_parms_net(p), net))
|
||||
continue;
|
||||
|
||||
if (!p->dev || p->dev == blackhole_netdev)
|
||||
continue;
|
||||
|
||||
if (nidx < neigh_skip)
|
||||
goto next;
|
||||
|
||||
|
|
@ -2630,12 +2643,15 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
}
|
||||
|
||||
neigh_skip = 0;
|
||||
nidx = 0;
|
||||
default_skip = 0;
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
cb->args[0] = tidx;
|
||||
cb->args[1] = nidx;
|
||||
cb->args[2] = default_skip;
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
|
@ -3669,12 +3685,13 @@ static int neigh_proc_dointvec_ms_jiffies_positive(const struct ctl_table *ctl,
|
|||
void *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
struct ctl_table tmp = *ctl;
|
||||
int ret;
|
||||
int ret, min, max;
|
||||
|
||||
int min = msecs_to_jiffies(1);
|
||||
min = msecs_to_jiffies(1);
|
||||
max = msecs_to_jiffies(NTBL_PARM_MS_MAX);
|
||||
|
||||
tmp.extra1 = &min;
|
||||
tmp.extra2 = NULL;
|
||||
tmp.extra2 = &max;
|
||||
|
||||
ret = proc_dointvec_ms_jiffies_minmax(&tmp, write, buffer, lenp, ppos);
|
||||
neigh_proc_update(ctl, write);
|
||||
|
|
|
|||
|
|
@ -6832,6 +6832,34 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len,
|
|||
}
|
||||
EXPORT_SYMBOL(alloc_skb_with_frags);
|
||||
|
||||
/* pskb_carve_inside_header() and pskb_carve_inside_nonlinear()
|
||||
* remove the first bytes of a packet and reallocate skb->head.
|
||||
*
|
||||
* Whatever headers were present before the operation are gone,
|
||||
* we must not leave stale offsets, otherwise users of this skb
|
||||
* (skb_dump(), drop_monitor, taps, ...) would read or pull garbage.
|
||||
*/
|
||||
static void skb_carve_reset_headers(struct sk_buff *skb)
|
||||
{
|
||||
skb_unset_mac_header(skb);
|
||||
skb_unset_transport_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb->mac_len = 0;
|
||||
|
||||
/* Inner offsets have no "unset" marker, zero them so that
|
||||
* skb_inner_network_header_was_set() becomes false and no
|
||||
* consumer mistakes them for a real (and long gone) header.
|
||||
*/
|
||||
skb->inner_mac_header = 0;
|
||||
skb->inner_network_header = 0;
|
||||
skb->inner_transport_header = 0;
|
||||
skb->inner_protocol = 0;
|
||||
skb->encapsulation = 0;
|
||||
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL)
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
}
|
||||
|
||||
/* carve out the first off bytes from skb when off < headlen */
|
||||
static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off,
|
||||
const int headlen, gfp_t gfp_mask)
|
||||
|
|
@ -6887,7 +6915,7 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off,
|
|||
skb->head_frag = 0;
|
||||
skb_set_end_offset(skb, size);
|
||||
skb_set_tail_pointer(skb, skb_headlen(skb));
|
||||
skb_headers_offset_update(skb, 0);
|
||||
skb_carve_reset_headers(skb);
|
||||
skb->cloned = 0;
|
||||
skb->hdr_len = 0;
|
||||
skb->nohdr = 0;
|
||||
|
|
@ -7027,7 +7055,7 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off,
|
|||
skb->data = data;
|
||||
skb_set_end_offset(skb, size);
|
||||
skb_reset_tail_pointer(skb);
|
||||
skb_headers_offset_update(skb, 0);
|
||||
skb_carve_reset_headers(skb);
|
||||
skb->cloned = 0;
|
||||
skb->hdr_len = 0;
|
||||
skb->nohdr = 0;
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@
|
|||
|
||||
#include <trace/events/sock.h>
|
||||
|
||||
#include <net/psp.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/busy_poll.h>
|
||||
#include <net/phonet/phonet.h>
|
||||
|
|
@ -2670,6 +2671,12 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(sk_setup_caps);
|
||||
|
||||
bool sk_has_decrypt_user(const struct sock *sk)
|
||||
{
|
||||
return psp_sk_assoc(sk) ||
|
||||
(sk_is_inet(sk) && inet_csk_has_ulp(sk)); /* for tls */
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple resource managers for sockets.
|
||||
*/
|
||||
|
|
@ -3911,7 +3918,14 @@ int sock_gettstamp(struct socket *sock, void __user *userstamp,
|
|||
struct sock *sk = sock->sk;
|
||||
struct timespec64 ts;
|
||||
|
||||
sock_enable_timestamp(sk, SOCK_TIMESTAMP);
|
||||
/* sk->sk_flags must only be changed under the socket lock,
|
||||
* because sock_set_flag() uses non atomic operations.
|
||||
*/
|
||||
if (!sock_flag(sk, SOCK_TIMESTAMP)) {
|
||||
lock_sock(sk);
|
||||
sock_enable_timestamp(sk, SOCK_TIMESTAMP);
|
||||
release_sock(sk);
|
||||
}
|
||||
ts = ktime_to_timespec64(sock_read_timestamp(sk));
|
||||
if (ts.tv_sec == -1)
|
||||
return -ENOENT;
|
||||
|
|
|
|||
|
|
@ -441,6 +441,12 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
|
|||
|
||||
esp->inplace = false;
|
||||
|
||||
/* Take real page refs and clear SKBFL_MANAGED_FRAG_REFS before
|
||||
* we mutate the frag array, so the per-frag unref stays balanced
|
||||
* for zerocopy managed frags (see __ip_append_data()).
|
||||
*/
|
||||
skb_zcopy_downgrade_managed(skb);
|
||||
|
||||
allocsize = ALIGN(tailen, L1_CACHE_BYTES);
|
||||
|
||||
spin_lock_bh(&x->lock);
|
||||
|
|
|
|||
|
|
@ -581,16 +581,19 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
|
|||
skb_dstref_restore(skb_in, orefdst);
|
||||
|
||||
/*
|
||||
* At this point, fl4_dec.daddr should NOT be local (we
|
||||
* checked fl4_dec.saddr above). However, a race condition
|
||||
* may occur if the address is added to the interface
|
||||
* concurrently. In that case, ip_route_input() returns a
|
||||
* LOCAL route with dst.output=ip_rt_bug, which must not
|
||||
* be used for output.
|
||||
* fl4_dec.daddr is not expected to be local here, but it can be
|
||||
* added to an interface concurrently, in which case
|
||||
* ip_route_input() returns a LOCAL route. It can also fail to
|
||||
* build a forwarding route towards fl4_dec.daddr, for example,
|
||||
* when forwarding is disabled, and return an UNREACHABLE route.
|
||||
* Both cases will result in a route with dst.output=ip_rt_bug,
|
||||
* which must not be used for output.
|
||||
*/
|
||||
if (!err && rt2 && rt2->rt_type == RTN_LOCAL) {
|
||||
if (!err && rt2 && rt2->rt_type == RTN_LOCAL)
|
||||
net_warn_ratelimited("detected local route for %pI4 during ICMP sending, src %pI4\n",
|
||||
&fl4_dec.daddr, &fl4_dec.saddr);
|
||||
if (!err && rt2 &&
|
||||
(rt2->rt_type == RTN_LOCAL || rt2->rt_type == RTN_UNREACHABLE)) {
|
||||
dst_release(&rt2->dst);
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -680,8 +680,14 @@ static int ip_tun_get_optlen(struct nlattr *attr,
|
|||
}
|
||||
|
||||
static int ip_tun_set_opts(struct nlattr *attr, struct ip_tunnel_info *info,
|
||||
struct netlink_ext_ack *extack)
|
||||
int opts_len, struct netlink_ext_ack *extack)
|
||||
{
|
||||
/* `options_len` is the __counted_by() annotation of the `options`
|
||||
* flexible array, it must be initialized before parsing writes
|
||||
* into it.
|
||||
*/
|
||||
info->options_len = opts_len;
|
||||
|
||||
return ip_tun_parse_opts(attr, info, extack);
|
||||
}
|
||||
|
||||
|
|
@ -712,7 +718,8 @@ static int ip_tun_build_state(struct net *net, struct nlattr *attr,
|
|||
|
||||
tun_info = lwt_tun_info(new_state);
|
||||
|
||||
err = ip_tun_set_opts(tb[LWTUNNEL_IP_OPTS], tun_info, extack);
|
||||
err = ip_tun_set_opts(tb[LWTUNNEL_IP_OPTS], tun_info, opt_len,
|
||||
extack);
|
||||
if (err < 0) {
|
||||
lwtstate_free(new_state);
|
||||
return err;
|
||||
|
|
@ -753,7 +760,6 @@ static int ip_tun_build_state(struct net *net, struct nlattr *attr,
|
|||
}
|
||||
|
||||
tun_info->mode = IP_TUNNEL_INFO_TX;
|
||||
tun_info->options_len = opt_len;
|
||||
|
||||
*ts = new_state;
|
||||
|
||||
|
|
@ -1006,7 +1012,8 @@ static int ip6_tun_build_state(struct net *net, struct nlattr *attr,
|
|||
|
||||
tun_info = lwt_tun_info(new_state);
|
||||
|
||||
err = ip_tun_set_opts(tb[LWTUNNEL_IP6_OPTS], tun_info, extack);
|
||||
err = ip_tun_set_opts(tb[LWTUNNEL_IP6_OPTS], tun_info, opt_len,
|
||||
extack);
|
||||
if (err < 0) {
|
||||
lwtstate_free(new_state);
|
||||
return err;
|
||||
|
|
@ -1040,7 +1047,6 @@ static int ip6_tun_build_state(struct net *net, struct nlattr *attr,
|
|||
}
|
||||
|
||||
tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6;
|
||||
tun_info->options_len = opt_len;
|
||||
|
||||
*ts = new_state;
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ static int tcp_ecn_mode_max = 5;
|
|||
static u32 icmp_errors_extension_mask_all =
|
||||
GENMASK_U8(ICMP_ERR_EXT_COUNT - 1, 0);
|
||||
|
||||
static int tcp_min_rcvbuf = 4096;
|
||||
|
||||
/* obsolete */
|
||||
static int sysctl_tcp_low_latency __read_mostly;
|
||||
|
||||
|
|
@ -1462,7 +1464,7 @@ static const struct ctl_table ipv4_net_table[] = {
|
|||
.maxlen = sizeof(init_net.ipv4.sysctl_tcp_rmem),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = SYSCTL_ONE,
|
||||
.extra1 = &tcp_min_rcvbuf,
|
||||
},
|
||||
{
|
||||
.procname = "tcp_comp_sack_delay_ns",
|
||||
|
|
|
|||
|
|
@ -6490,6 +6490,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
|
|||
* or pure receivers (this means either the sequence number or the ack
|
||||
* value must stay constant)
|
||||
* - Unexpected TCP option.
|
||||
* - ACK sequence number is outside [SND.UNA, SND.NXT].
|
||||
*
|
||||
* When these conditions are not satisfied it drops into a standard
|
||||
* receive procedure patterned after RFC793 to handle all cases.
|
||||
|
|
@ -6539,7 +6540,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb)
|
|||
|
||||
if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
|
||||
TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
|
||||
!after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
|
||||
between(TCP_SKB_CB(skb)->ack_seq, tp->snd_una, tp->snd_nxt)) {
|
||||
int tcp_header_len = tp->tcp_header_len;
|
||||
s32 delta = 0;
|
||||
int flag = 0;
|
||||
|
|
|
|||
|
|
@ -136,6 +136,10 @@ static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops)
|
|||
if (icsk->icsk_ulp_ops)
|
||||
goto out_err;
|
||||
|
||||
err = -EINVAL;
|
||||
if (sk_has_decrypt_user(sk))
|
||||
goto out_err;
|
||||
|
||||
if (sk->sk_socket)
|
||||
clear_bit(SOCK_SUPPORT_ZC, &sk->sk_socket->flags);
|
||||
|
||||
|
|
|
|||
|
|
@ -471,6 +471,12 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
|
|||
|
||||
esp->inplace = false;
|
||||
|
||||
/* Take real page refs and clear SKBFL_MANAGED_FRAG_REFS before
|
||||
* we mutate the frag array, so the per-frag unref stays balanced
|
||||
* for zerocopy managed frags (see __ip_append_data()).
|
||||
*/
|
||||
skb_zcopy_downgrade_managed(skb);
|
||||
|
||||
allocsize = ALIGN(tailen, L1_CACHE_BYTES);
|
||||
|
||||
spin_lock_bh(&x->lock);
|
||||
|
|
|
|||
|
|
@ -257,10 +257,13 @@ static bool decap_and_validate(struct sk_buff *skb, int proto)
|
|||
return false;
|
||||
|
||||
if (proto == IPPROTO_IPIP) {
|
||||
bool l3slave = ipv6_l3mdev_skb(IP6CB(skb)->flags);
|
||||
int iif = IP6CB(skb)->iif;
|
||||
|
||||
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
|
||||
IPCB(skb)->iif = iif;
|
||||
if (l3slave)
|
||||
IPCB(skb)->flags |= IPSKB_L3SLAVE;
|
||||
} else if (proto == IPPROTO_IPV6) {
|
||||
bool l3slave = ipv6_l3mdev_skb(IP6CB(skb)->flags);
|
||||
int iif = IP6CB(skb)->iif;
|
||||
|
|
|
|||
|
|
@ -1604,7 +1604,8 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
|
|||
by tcp. Feel free to propose better solution.
|
||||
--ANK (980728)
|
||||
*/
|
||||
if (np->rxopt.all && sk->sk_state != TCP_LISTEN)
|
||||
if (np->rxopt.all &&
|
||||
!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)))
|
||||
opt_skb = skb_clone_and_charge_r(skb, sk);
|
||||
|
||||
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@
|
|||
void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)
|
||||
{
|
||||
struct flowi6 fl6;
|
||||
struct sock *sk = skb->sk;
|
||||
struct sock *sk = skb_to_full_sk(skb);
|
||||
|
||||
if (!sk)
|
||||
return;
|
||||
|
||||
fl6.flowi6_oif = sk->sk_bound_dev_if;
|
||||
fl6.daddr = ipv6_hdr(skb)->daddr;
|
||||
|
|
@ -31,7 +34,10 @@ void xfrm6_local_error(struct sk_buff *skb, u32 mtu)
|
|||
{
|
||||
struct flowi6 fl6;
|
||||
const struct ipv6hdr *hdr;
|
||||
struct sock *sk = skb->sk;
|
||||
struct sock *sk = skb_to_full_sk(skb);
|
||||
|
||||
if (!sk)
|
||||
return;
|
||||
|
||||
hdr = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
|
||||
fl6.fl6_dport = inet_sk(sk)->inet_dport;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,10 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* TXQs are reserved in ieee80211_if_add() and cannot be added later */
|
||||
if ((params->flags & MONITOR_FLAG_ACTIVE) && !sdata->vif.txq)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* validate whether MU-MIMO can be configured */
|
||||
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
|
||||
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
|
||||
|
|
@ -1929,6 +1933,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
return 0;
|
||||
|
||||
error:
|
||||
link_conf->enable_beacon = false;
|
||||
link_conf->beacon_int = prev_beacon_int;
|
||||
sdata->vif.cfg.ssid_len = 0;
|
||||
ieee80211_link_release_channel(link);
|
||||
|
||||
return err;
|
||||
|
|
@ -3320,7 +3327,11 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
return ieee80211_start_mesh(sdata);
|
||||
err = ieee80211_start_mesh(sdata);
|
||||
if (err)
|
||||
ieee80211_link_release_channel(&sdata->deflink);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
|
||||
|
|
@ -3475,7 +3486,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
|
|||
static int ieee80211_suspend(struct wiphy *wiphy,
|
||||
struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
return __ieee80211_suspend(wiphy_priv(wiphy), wowlan);
|
||||
return __ieee80211_suspend(wiphy_priv(wiphy), wowlan, false);
|
||||
}
|
||||
|
||||
static int ieee80211_resume(struct wiphy *wiphy)
|
||||
|
|
@ -4113,6 +4124,9 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
|||
if (!ieee80211_sdata_running(sdata))
|
||||
return -ENETDOWN;
|
||||
|
||||
if (!(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
|
||||
return -ENETDOWN;
|
||||
|
||||
/*
|
||||
* If active validate the setting and reject it if it doesn't leave
|
||||
* at least one basic rate usable, since we really have to be able
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf,
|
|||
|
||||
rtnl_lock();
|
||||
wiphy_lock(local->hw.wiphy);
|
||||
__ieee80211_suspend(&local->hw, NULL);
|
||||
__ieee80211_suspend(&local->hw, NULL, true);
|
||||
ret = __ieee80211_resume(&local->hw);
|
||||
wiphy_unlock(local->hw.wiphy);
|
||||
|
||||
|
|
|
|||
|
|
@ -657,6 +657,9 @@ static ssize_t ieee80211_if_fmt_tsf(
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
u64 tsf;
|
||||
|
||||
if (!ieee80211_sdata_running((struct ieee80211_sub_if_data *)sdata))
|
||||
return -ENETDOWN;
|
||||
|
||||
tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
|
||||
|
||||
return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
|
||||
|
|
@ -670,6 +673,9 @@ static ssize_t ieee80211_if_parse_tsf(
|
|||
int ret;
|
||||
int tsf_is_delta = 0;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return -ENETDOWN;
|
||||
|
||||
if (strncmp(buf, "reset", 5) == 0) {
|
||||
if (local->ops->reset_tsf) {
|
||||
drv_reset_tsf(local, sdata);
|
||||
|
|
@ -729,6 +735,9 @@ static ssize_t ieee80211_if_parse_active_links(struct ieee80211_sub_if_data *sda
|
|||
if (kstrtou16(buf, 0, &active_links) || !active_links)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
return -ENETDOWN;
|
||||
|
||||
return ieee80211_set_active_links(&sdata->vif, active_links) ?: buflen;
|
||||
}
|
||||
IEEE80211_IF_FILE_RW(active_links);
|
||||
|
|
|
|||
|
|
@ -2432,7 +2432,7 @@ int ieee80211_reconfig(struct ieee80211_local *local);
|
|||
void ieee80211_stop_device(struct ieee80211_local *local, bool suspend);
|
||||
|
||||
int __ieee80211_suspend(struct ieee80211_hw *hw,
|
||||
struct cfg80211_wowlan *wowlan);
|
||||
struct cfg80211_wowlan *wowlan, bool reset);
|
||||
|
||||
static inline int __ieee80211_resume(struct ieee80211_hw *hw)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -616,6 +616,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
|||
RCU_INIT_POINTER(sdata->vif.bss_conf.chanctx_conf, NULL);
|
||||
/* see comment in the default case below */
|
||||
ieee80211_free_keys(sdata, true);
|
||||
/* increased by AP value on ifup, so reset on ifdown */
|
||||
sdata->crypto_tx_tailroom_needed_cnt = 0;
|
||||
/* no need to tell driver */
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
|
|
@ -924,9 +926,33 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The netdev can be unregistered without mac80211 doing it, e.g. by the netdev
|
||||
* core when cfg80211 couldn't move it out of a network namespace that's being
|
||||
* destroyed. Drop it from the interface list either way.
|
||||
*/
|
||||
static void ieee80211_unlist_sdata(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_sub_if_data *iter;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
list_for_each_entry(iter, &local->interfaces, list) {
|
||||
if (iter != sdata)
|
||||
continue;
|
||||
guard(mutex)(&local->iflist_mtx);
|
||||
list_del_rcu(&sdata->list);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_uninit(struct net_device *dev)
|
||||
{
|
||||
ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
ieee80211_unlist_sdata(sdata);
|
||||
ieee80211_teardown_sdata(sdata);
|
||||
}
|
||||
|
||||
static int ieee80211_netdev_setup_tc(struct net_device *dev,
|
||||
|
|
@ -935,6 +961,9 @@ static int ieee80211_netdev_setup_tc(struct net_device *dev,
|
|||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return drv_net_setup_tc(local, sdata, dev, type, type_data);
|
||||
}
|
||||
|
||||
|
|
@ -964,7 +993,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev,
|
|||
/* reset flags and info before parsing radiotap header */
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
if (!ieee80211_parse_tx_radiotap(skb, dev))
|
||||
if (!ieee80211_parse_tx_radiotap(skb, dev, NULL))
|
||||
return 0; /* doesn't matter, frame will be dropped */
|
||||
|
||||
len_rthdr = ieee80211_get_radiotap_len(skb->data);
|
||||
|
|
@ -1603,8 +1632,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
err_del_interface:
|
||||
drv_remove_interface(local, sdata);
|
||||
err_stop:
|
||||
if (!local->open_count)
|
||||
if (!local->open_count) {
|
||||
ieee80211_led_radio(local, false);
|
||||
ieee80211_mod_tpt_led_trig(local, 0,
|
||||
IEEE80211_TPT_LEDTRIG_FL_RADIO);
|
||||
drv_stop(local, false);
|
||||
}
|
||||
if (sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
|
||||
RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
|
|
|
|||
|
|
@ -1453,6 +1453,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
sizeof(struct ieee80211_he_mcs_nss_supp) +
|
||||
IEEE80211_HE_PPE_THRES_MAX_LEN;
|
||||
|
||||
if (local->hw.wiphy->bands[NL80211_BAND_6GHZ])
|
||||
local->scan_ies_len +=
|
||||
3 + sizeof(struct ieee80211_he_6ghz_capa);
|
||||
|
||||
if (supp_eht)
|
||||
local->scan_ies_len +=
|
||||
3 + sizeof(struct ieee80211_eht_cap_elem) +
|
||||
|
|
|
|||
|
|
@ -1196,6 +1196,21 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_mesh_reset_csa(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct mesh_csa_settings *csa;
|
||||
|
||||
/* Reset the TTL value and Initiator flag */
|
||||
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
|
||||
ifmsh->chsw_ttl = 0;
|
||||
|
||||
/* Remove the CSA and MCSP elements from the beacon */
|
||||
csa = sdata_dereference(ifmsh->csa, sdata);
|
||||
RCU_INIT_POINTER(ifmsh->csa, NULL);
|
||||
kfree_rcu(csa, rcu_head);
|
||||
}
|
||||
|
||||
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
|
@ -1204,6 +1219,11 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
netif_carrier_off(sdata->dev);
|
||||
|
||||
/* abort any running channel switch */
|
||||
sdata->vif.bss_conf.csa_active = false;
|
||||
ieee80211_mesh_reset_csa(sdata);
|
||||
ieee80211_vif_unblock_queues_csa(sdata);
|
||||
|
||||
/* flush STAs and mpaths on this iface */
|
||||
sta_info_flush(sdata, -1);
|
||||
ieee80211_free_keys(sdata, true);
|
||||
|
|
@ -1510,19 +1530,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata, u64 *changed)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
struct mesh_csa_settings *tmp_csa_settings;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
/* Reset the TTL value and Initiator flag */
|
||||
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
|
||||
ifmsh->chsw_ttl = 0;
|
||||
ieee80211_mesh_reset_csa(sdata);
|
||||
|
||||
/* Remove the CSA and MCSP elements from the beacon */
|
||||
tmp_csa_settings = sdata_dereference(ifmsh->csa, sdata);
|
||||
RCU_INIT_POINTER(ifmsh->csa, NULL);
|
||||
if (tmp_csa_settings)
|
||||
kfree_rcu(tmp_csa_settings, rcu_head);
|
||||
ret = ieee80211_mesh_rebuild_beacon(sdata);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
|
@ -1555,7 +1566,6 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
ret = ieee80211_mesh_rebuild_beacon(sdata);
|
||||
if (ret) {
|
||||
tmp_csa_settings = rcu_dereference(ifmsh->csa);
|
||||
RCU_INIT_POINTER(ifmsh->csa, NULL);
|
||||
kfree_rcu(tmp_csa_settings, rcu_head);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -460,6 +460,13 @@ static void __ieee80211_roc_work(struct ieee80211_local *local)
|
|||
return;
|
||||
|
||||
if (!roc->started) {
|
||||
/*
|
||||
* The work can be started by a previous ROC work, but a scan
|
||||
* can get between things; scan finish will retrigger us.
|
||||
*/
|
||||
if (local->scanning)
|
||||
return;
|
||||
|
||||
WARN_ON(!local->emulate_chanctx);
|
||||
_ieee80211_start_next_roc(local);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ static void ieee80211_sched_scan_cancel(struct ieee80211_local *local)
|
|||
cfg80211_sched_scan_stopped_locked(local->hw.wiphy, 0);
|
||||
}
|
||||
|
||||
int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
||||
int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan,
|
||||
bool reset)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
|
@ -166,9 +167,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
|
||||
/*
|
||||
* We disconnected on all interfaces before suspend, all channel
|
||||
* contexts should be released.
|
||||
* contexts should be released, but on 'reset' debugfs that's
|
||||
* not true so don't check there.
|
||||
*/
|
||||
WARN_ON(!list_empty(&local->chanctx_list));
|
||||
WARN_ON(!reset && !list_empty(&local->chanctx_list));
|
||||
|
||||
/* stop hardware - this must stop RX */
|
||||
ieee80211_stop_device(local, true);
|
||||
|
|
|
|||
|
|
@ -372,6 +372,14 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
|
|||
u32 rate_flags = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Frames that shouldn't use the rate mask could be anything,
|
||||
* even on a different band, so don't take the sta into account
|
||||
* to avoid ending up without rates.
|
||||
*/
|
||||
if (info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)
|
||||
sta = NULL;
|
||||
|
||||
if (sband->band == NL80211_BAND_S1GHZ) {
|
||||
info->control.rates[0].flags |= IEEE80211_TX_RC_S1G_MCS;
|
||||
info->control.rates[0].idx = 0;
|
||||
|
|
|
|||
|
|
@ -1242,7 +1242,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(n_ch == 0))
|
||||
if (n_ch == 0)
|
||||
return -EINVAL;
|
||||
|
||||
local->int_scan_req->n_channels = n_ch;
|
||||
|
|
|
|||
|
|
@ -1142,6 +1142,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
enum ieee80211_smps_mode smps_mode =
|
||||
sdata->deflink.u.mgd.driver_smps_mode;
|
||||
struct sta_info *sta;
|
||||
int ret;
|
||||
|
||||
/* don't support setup with forced SMPS mode that's not off */
|
||||
|
|
@ -1168,14 +1169,10 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
|
|||
* Allow error packets to be sent - sometimes we don't even add a STA
|
||||
* before failing the setup.
|
||||
*/
|
||||
if (status_code == 0) {
|
||||
rcu_read_lock();
|
||||
if (!sta_info_get(sdata, peer)) {
|
||||
rcu_read_unlock();
|
||||
ret = -ENOLINK;
|
||||
goto out_unlock;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
sta = sta_info_get(sdata, peer);
|
||||
if ((status_code == 0 && !sta) || (sta && !sta->sta.tdls)) {
|
||||
ret = -ENOLINK;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ieee80211_flush_queues(local, sdata, false);
|
||||
|
|
@ -1284,6 +1281,24 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
|||
peer_capability, initiator,
|
||||
extra_ies, extra_ies_len);
|
||||
break;
|
||||
case WLAN_TDLS_SETUP_CONFIRM: {
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = sta_info_get(sdata, peer);
|
||||
if (!sta || !sta->sta.tdls) {
|
||||
ret = -ENOLINK;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
|
||||
link_id, action_code,
|
||||
dialog_token,
|
||||
status_code,
|
||||
peer_capability,
|
||||
initiator, extra_ies,
|
||||
extra_ies_len, 0, NULL);
|
||||
break;
|
||||
}
|
||||
case WLAN_TDLS_DISCOVERY_REQUEST:
|
||||
/*
|
||||
* Protect the discovery so we can hear the TDLS discovery
|
||||
|
|
@ -1292,7 +1307,6 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
|||
*/
|
||||
drv_mgd_protect_tdls_discover(sdata->local, sdata, link_id);
|
||||
fallthrough;
|
||||
case WLAN_TDLS_SETUP_CONFIRM:
|
||||
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
|
||||
/* no special handling */
|
||||
ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer,
|
||||
|
|
@ -1442,6 +1456,10 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
|
|||
*/
|
||||
tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
|
||||
|
||||
sta = sta_info_get(sdata, peer);
|
||||
if (!sta || !sta->sta.tdls)
|
||||
return -ENOLINK;
|
||||
|
||||
switch (oper) {
|
||||
case NL80211_TDLS_ENABLE_LINK:
|
||||
if (sdata->vif.bss_conf.csa_active) {
|
||||
|
|
@ -1449,10 +1467,6 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
sta = sta_info_get(sdata, peer);
|
||||
if (!sta || !sta->sta.tdls)
|
||||
return -ENOLINK;
|
||||
|
||||
iee80211_tdls_recalc_chanctx(sdata, sta);
|
||||
iee80211_tdls_recalc_ht_protection(sdata, sta);
|
||||
|
||||
|
|
|
|||
|
|
@ -744,10 +744,12 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|||
assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
|
||||
|
||||
/*
|
||||
* Lets not bother rate control if we're associated and cannot
|
||||
* talk to the sta. This should not happen.
|
||||
* Lets not bother rate control if we're associated and cannot talk to
|
||||
* the sta. This should not happen - except for frames that aren't
|
||||
* really for the peer to start with and already ignore rates.
|
||||
*/
|
||||
if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
|
||||
if (!(info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK) &&
|
||||
WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
|
||||
!rate_usable_index_exists(sband, &tx->sta->sta),
|
||||
"%s: Dropped data frame as no usable bitrate found while "
|
||||
"scanning and associated. Target station: "
|
||||
|
|
@ -2103,8 +2105,29 @@ static bool ieee80211_validate_radiotap_len(struct sk_buff *skb)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool ieee80211_rate_bw_usable(u16 rate_flags,
|
||||
const struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
int width;
|
||||
|
||||
if (!chandef)
|
||||
return true;
|
||||
|
||||
if (rate_flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
|
||||
width = 160;
|
||||
else if (rate_flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
|
||||
width = 80;
|
||||
else if (rate_flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
|
||||
width = 40;
|
||||
else
|
||||
return true;
|
||||
|
||||
return width <= cfg80211_chandef_get_width(chandef);
|
||||
}
|
||||
|
||||
bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
struct net_device *dev,
|
||||
const struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
|
||||
struct ieee80211_radiotap_iterator iterator;
|
||||
|
|
@ -2278,6 +2301,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
|
|||
struct ieee80211_supported_band *sband =
|
||||
local->hw.wiphy->bands[info->band];
|
||||
|
||||
if (!ieee80211_rate_bw_usable(rate_flags, chandef))
|
||||
return false;
|
||||
|
||||
info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
|
||||
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
|
|
@ -2477,7 +2503,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
|||
* selected chandef above to accurately set injection rates and
|
||||
* retransmissions.
|
||||
*/
|
||||
if (!ieee80211_parse_tx_radiotap(skb, dev))
|
||||
if (!ieee80211_parse_tx_radiotap(skb, dev, chandef))
|
||||
goto fail_rcu;
|
||||
|
||||
/* remove the injection radiotap header */
|
||||
|
|
@ -2955,10 +2981,23 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
if (unlikely(!skb)) {
|
||||
ret = -ENOMEM;
|
||||
goto free;
|
||||
/* skb_share_check() already freed the skb */
|
||||
if (info_id)
|
||||
ieee80211_remove_ack_skb(local, info_id);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/* set this up so failure paths can clean up ack skb */
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
info->flags = info_flags;
|
||||
if (info_id) {
|
||||
info->status_data = info_id;
|
||||
info->status_data_idr = 1;
|
||||
}
|
||||
info->band = band;
|
||||
|
||||
hdr.frame_control = fc;
|
||||
hdr.duration_id = 0;
|
||||
hdr.seq_ctrl = 0;
|
||||
|
|
@ -2997,10 +3036,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
head_need += local->tx_headroom;
|
||||
head_need = max_t(int, 0, head_need);
|
||||
if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
skb = NULL;
|
||||
ret = -ENOMEM;
|
||||
goto free;
|
||||
goto free_txskb;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3027,16 +3064,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
skb_reset_mac_header(skb);
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
info->flags = info_flags;
|
||||
if (info_id) {
|
||||
info->status_data = info_id;
|
||||
info->status_data_idr = 1;
|
||||
}
|
||||
info->band = band;
|
||||
|
||||
if (likely(!cookie)) {
|
||||
ctrl_flags |= u32_encode_bits(link_id,
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
|
|
@ -3060,16 +3087,17 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
pre_conf_link_id, link_id);
|
||||
#endif
|
||||
ret = -EINVAL;
|
||||
goto free;
|
||||
goto free_txskb;
|
||||
}
|
||||
}
|
||||
|
||||
info->control.flags = ctrl_flags;
|
||||
|
||||
return skb;
|
||||
free_txskb:
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
return ERR_PTR(ret);
|
||||
free:
|
||||
if (info_id)
|
||||
ieee80211_remove_ack_skb(local, info_id);
|
||||
kfree_skb(skb);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
|
@ -5089,10 +5117,18 @@ static void ieee80211_beacon_add_tim_pvb(struct ps_data *ps,
|
|||
*/
|
||||
static void ieee80211_s1g_beacon_add_tim_pvb(struct ps_data *ps,
|
||||
struct sk_buff *skb,
|
||||
bool mcast_traffic)
|
||||
bool mcast_traffic,
|
||||
bool ucast_traffic)
|
||||
{
|
||||
int blk;
|
||||
|
||||
/*
|
||||
* if no unicast and multicast traffic don't emit a bitmap control
|
||||
* or pvb
|
||||
*/
|
||||
if (!mcast_traffic && !ucast_traffic)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Emit a bitmap control block with a page slice number of 31 and a
|
||||
* page index of 0 which indicates as per IEEE80211-2024 9.4.2.5.1
|
||||
|
|
@ -5101,6 +5137,10 @@ static void ieee80211_s1g_beacon_add_tim_pvb(struct ps_data *ps,
|
|||
*/
|
||||
skb_put_u8(skb, mcast_traffic | (31 << 1));
|
||||
|
||||
/* If there's no unicast traffic we don't need to include a PVB. */
|
||||
if (!ucast_traffic)
|
||||
return;
|
||||
|
||||
/* Emit an encoded block for each non-zero sub-block */
|
||||
for (blk = 0; blk < IEEE80211_MAX_SUPPORTED_S1G_TIM_BLOCKS; blk++) {
|
||||
u8 blk_bmap = 0;
|
||||
|
|
@ -5182,25 +5222,16 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
ps->dtim_bc_mc = mcast_traffic;
|
||||
|
||||
if (have_bits) {
|
||||
if (s1g)
|
||||
ieee80211_s1g_beacon_add_tim_pvb(ps, skb,
|
||||
mcast_traffic);
|
||||
else
|
||||
ieee80211_beacon_add_tim_pvb(ps, skb, mcast_traffic);
|
||||
if (s1g) {
|
||||
ieee80211_s1g_beacon_add_tim_pvb(ps, skb, mcast_traffic,
|
||||
have_bits);
|
||||
} else if (have_bits) {
|
||||
ieee80211_beacon_add_tim_pvb(ps, skb, mcast_traffic);
|
||||
} else {
|
||||
/*
|
||||
* If there is no buffered unicast traffic for an S1G
|
||||
* interface, we can exclude the bitmap control. This is in
|
||||
* contrast to other phy types as they do include the bitmap
|
||||
* control and pvb even when there is no buffered traffic.
|
||||
*/
|
||||
if (!s1g) {
|
||||
/* Bitmap control */
|
||||
skb_put_u8(skb, mcast_traffic);
|
||||
/* Part Virt Bitmap */
|
||||
skb_put_u8(skb, 0);
|
||||
}
|
||||
/* Bitmap control */
|
||||
skb_put_u8(skb, mcast_traffic);
|
||||
/* Part Virt Bitmap */
|
||||
skb_put_u8(skb, 0);
|
||||
}
|
||||
|
||||
tim->datalen = skb_tail_pointer(skb) - tim->data;
|
||||
|
|
|
|||
|
|
@ -856,12 +856,12 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,
|
|||
mptcp_dss_corruption(msk, ssk);
|
||||
}
|
||||
} else {
|
||||
sk_eat_skb(ssk, skb);
|
||||
|
||||
if (unlikely(!fin)) {
|
||||
DEBUG_NET_WARN_ON_ONCE(1);
|
||||
mptcp_dss_corruption(msk, ssk);
|
||||
}
|
||||
|
||||
sk_eat_skb(ssk, skb);
|
||||
}
|
||||
|
||||
WRITE_ONCE(tp->copied_seq, seq);
|
||||
|
|
@ -1664,7 +1664,9 @@ struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
|
|||
|
||||
static void mptcp_push_release(struct sock *ssk, struct mptcp_sendmsg_info *info)
|
||||
{
|
||||
tcp_push(ssk, 0, info->mss_now, tcp_sk(ssk)->nonagle, info->size_goal);
|
||||
if (info->mss_now)
|
||||
tcp_push(ssk, 0, info->mss_now, tcp_sk(ssk)->nonagle,
|
||||
info->size_goal);
|
||||
release_sock(ssk);
|
||||
}
|
||||
|
||||
|
|
@ -1852,7 +1854,8 @@ static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk, bool
|
|||
ret = __subflow_push_pending(sk, ssk, &info);
|
||||
if (ret <= 0)
|
||||
keep_pushing = false;
|
||||
copied += ret;
|
||||
else
|
||||
copied += ret;
|
||||
}
|
||||
|
||||
mptcp_for_each_subflow(msk, subflow) {
|
||||
|
|
@ -2459,7 +2462,7 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
|||
mptcp_cleanup_rbuf(msk, copied);
|
||||
err = sk_wait_data(sk, &timeo, last);
|
||||
if (err < 0) {
|
||||
err = copied ? : err;
|
||||
copied = copied ? : err;
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -585,7 +585,8 @@ struct mptcp_subflow_context {
|
|||
is_mptfo : 1, /* subflow is doing TFO */
|
||||
close_event_done : 1, /* has done the post-closed part */
|
||||
mpc_drop : 1, /* the MPC option has been dropped in a rtx */
|
||||
__unused : 9;
|
||||
resetting : 1, /* subflow is resetting */
|
||||
__unused : 8;
|
||||
bool data_avail;
|
||||
bool scheduled;
|
||||
bool pm_listener; /* a listener managed by the kernel PM? */
|
||||
|
|
|
|||
|
|
@ -438,6 +438,10 @@ void mptcp_subflow_reset(struct sock *ssk)
|
|||
/* must hold: tcp_done() could drop last reference on parent */
|
||||
sock_hold(sk);
|
||||
|
||||
subflow->resetting = 1;
|
||||
|
||||
/* No need to delay the actual close for to-be discarded data. */
|
||||
__skb_queue_purge(&ssk->sk_receive_queue);
|
||||
mptcp_send_active_reset_reason(ssk);
|
||||
tcp_done(ssk);
|
||||
if (!test_and_set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &mptcp_sk(sk)->flags))
|
||||
|
|
@ -1883,6 +1887,13 @@ static void subflow_state_change(struct sock *sk)
|
|||
|
||||
__subflow_state_change(sk);
|
||||
|
||||
/* Rx queue processing is unneeded, error reporting will take place at
|
||||
* __mptcp_close_ssk() time and subflow reset can't happen in case of
|
||||
* fallback: subflow_sched_work_if_closed() would be a no-op.
|
||||
*/
|
||||
if (subflow->resetting)
|
||||
return;
|
||||
|
||||
/* as recvmsg() does not acquire the subflow socket for ssk selection
|
||||
* a fin packet carrying a DSS can be unnoticed if we don't trigger
|
||||
* the data available machinery here.
|
||||
|
|
|
|||
|
|
@ -258,6 +258,14 @@ static void flow_offload_route_release(struct flow_offload *flow)
|
|||
nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_REPLY);
|
||||
}
|
||||
|
||||
static void flow_offload_free_rcu(struct rcu_head *rcu_head)
|
||||
{
|
||||
struct flow_offload *flow = container_of(rcu_head, struct flow_offload, rcu_head);
|
||||
|
||||
nf_ct_put(flow->ct);
|
||||
kfree(flow);
|
||||
}
|
||||
|
||||
void flow_offload_free(struct flow_offload *flow)
|
||||
{
|
||||
switch (flow->type) {
|
||||
|
|
@ -267,8 +275,7 @@ void flow_offload_free(struct flow_offload *flow)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
nf_ct_put(flow->ct);
|
||||
kfree_rcu(flow, rcu_head);
|
||||
call_rcu(&flow->rcu_head, flow_offload_free_rcu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(flow_offload_free);
|
||||
|
||||
|
|
@ -854,6 +861,7 @@ static int __init nf_flow_table_module_init(void)
|
|||
|
||||
static void __exit nf_flow_table_module_exit(void)
|
||||
{
|
||||
rcu_barrier();
|
||||
nf_flow_table_offload_exit();
|
||||
unregister_pernet_subsys(&nf_flow_table_net_ops);
|
||||
kmem_cache_destroy(flow_offload_cachep);
|
||||
|
|
|
|||
|
|
@ -1224,31 +1224,45 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
|
|||
}
|
||||
|
||||
ret = nf_register_net_hooks(net, nat_ops, ops_count);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&nf_nat_proto_mutex);
|
||||
for (i = 0; i < ops_count; i++) {
|
||||
priv = nat_ops[i].priv;
|
||||
kfree_rcu(priv, rcu_head);
|
||||
}
|
||||
kfree_rcu(nat_ops, rcu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nat_proto_net->nat_hook_ops = nat_ops;
|
||||
if (ret < 0)
|
||||
goto err_free_hooks;
|
||||
} else {
|
||||
nat_ops = nat_proto_net->nat_hook_ops;
|
||||
}
|
||||
|
||||
nat_ops = nat_proto_net->nat_hook_ops;
|
||||
priv = nat_ops[hooknum].priv;
|
||||
if (WARN_ON_ONCE(!priv)) {
|
||||
mutex_unlock(&nf_nat_proto_mutex);
|
||||
return -EOPNOTSUPP;
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_unregister_hooks;
|
||||
}
|
||||
|
||||
ret = nf_hook_entries_insert_raw(&priv->entries, ops);
|
||||
if (ret == 0)
|
||||
nat_proto_net->users++;
|
||||
if (ret)
|
||||
goto err_unregister_hooks;
|
||||
|
||||
if (!nat_proto_net->nat_hook_ops)
|
||||
nat_proto_net->nat_hook_ops = nat_ops;
|
||||
|
||||
nat_proto_net->users++;
|
||||
|
||||
mutex_unlock(&nf_nat_proto_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_hooks:
|
||||
if (nat_proto_net->nat_hook_ops) {
|
||||
mutex_unlock(&nf_nat_proto_mutex);
|
||||
return ret;
|
||||
}
|
||||
nf_unregister_net_hooks(net, nat_ops, ops_count);
|
||||
err_free_hooks:
|
||||
mutex_unlock(&nf_nat_proto_mutex);
|
||||
for (i = 0; i < ops_count; i++) {
|
||||
priv = nat_ops[i].priv;
|
||||
kfree_rcu(priv, rcu_head);
|
||||
}
|
||||
kfree_rcu(nat_ops, rcu);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user