Files
android_kernel_fxtec_sm6115/net/bridge/br_forward.c
Thomas Turner e0479e4a5b Merge tag 'v4.19.325-cip127' of https://git.kernel.org/pub/scm/linux/kernel/git/cip/linux-cip into android13-4.19-kona
version 4.19.325-cip127

* tag 'v4.19.325-cip127' of https://git.kernel.org/pub/scm/linux/kernel/git/cip/linux-cip:
  CIP: Bump version suffix to -cip127 after merge from cip/linux-4.19.y-st tree
  Update localversion-st, tree is up-to-date with 5.10.247.
  usb: uas: fix urb unmapping issue when the uas device is remove during ongoing data transfer
  scsi: pm80xx: Set phy->enable_completion only when we
  drm/amd/display: Check NULL before accessing
  wifi: ath10k: Fix connection after GTK rekeying
  pinctrl: single: fix bias pull up/down handling in pin_config_set
  ovl: fix UAF in ovl_dentry_update_reval by moving dput() in ovl_link_up
  fs: writeback: fix use-after-free in __mark_inode_dirty()
  libceph: fix potential use-after-free in have_mon_and_osd_map()
  drm: sti: fix device leaks at component probe
  USB: serial: option: add support for Rolling RW101R-GL
  USB: serial: ftdi_sio: add support for u-blox EVK-M101
  usb: storage: sddr55: Reject out-of-bound new_pba
  USB: storage: Remove subclass and protocol overrides from Novatek quirk
  usb: storage: Fix memory leak in USB bulk transport
  usb: gadget: f_eem: Fix memory leak in eem_unwrap
  slimbus: ngd: Fix reference count leak in qcom_slim_ngd_notify_slaves
  dm-verity: fix unreliable memory allocation
  can: sun4i_can: sun4i_can_interrupt(): fix max irq loop handling
  can: sja1000: fix max irq loop handling
  atm/fore200e: Fix possible data race in fore200e_open()
  MIPS: mm: Prevent a TLB shutdown on initial uniquification
  iio:common:ssp_sensors: Fix an error handling path ssp_probe()
  spi: bcm63xx: fix premature CS deassertion on RX-only transactions
  net: sxgbe: fix potential NULL dereference in sxgbe_rx()
  can: kvaser_usb: leaf: Fix potential infinite loop in command parsers
  mtd: onenand: Pass correct pointer to IRQ handler
  fsdax: mark the iomap argument to dax_iomap_sector as const
  net: sctp: Fix some typos
  iommu/amd: Skip enabling command/event buffers for kdump
  nvme-fc: use lock accessing port_state and rport state
  net: netpoll: fix incorrect refcount handling causing incorrect cleanup
  net: ethernet: ti: netcp: Standardize knav_dma_open_channel to return NULL on error
  tipc: Fix use-after-free in tipc_mon_reinit_self().
  sctp: prevent possible shift-out-of-bounds in sctp_transport_update_rto
  Bluetooth: btusb: reorder cleanup in btusb_disconnect to avoid UAF
  wifi: brcmfmac: fix crash while sending Action Frames in standalone AP Mode
  net/sched: sch_qfq: Fix null-deref in agg_dequeue
  Input: pegasus-notetaker - fix potential out-of-bounds access
  Input: remove third argument of usb_maxpacket()
  usb: deprecate the third argument of usb_maxpacket()
  ata: libata-scsi: Fix system suspend for a security locked drive
  fs/proc: fix uaf in proc_readdir_de()
  pmdomain: imx: Fix reference count leak in imx_gpc_remove
  pmdomain: arm: scmi: Fix genpd leak on provider registration failure
  net: qede: Initialize qede_ll_ops with designated initializer
  uio_hv_generic: Set event for all channels on the device
  ALSA: usb-audio: fix uac2 clock source at terminal parser
  kconfig/nconf: Initialize the default locale at startup
  kconfig/mconf: Initialize the default locale at startup
  vsock: Ignore signal/timeout on connect() if already established
  s390/ctcm: Fix double-kfree
  net: openvswitch: remove never-working support for setting nsh fields
  mlxsw: spectrum: Fix memory leak in mlxsw_sp_flower_stats()
  MIPS: Malta: Fix !EVA SOC-it PCI MMIO
  scsi: target: tcm_loop: Fix segfault in tcm_loop_tpg_address_show()
  scsi: sg: Do not sleep in atomic context
  Input: cros_ec_keyb - fix an invalid memory access
  be2net: pass wrb_params in case of OS2BMC
  HID: quirks: work around VID/PID conflict for 0x4c4a/0x4155
  isdn: mISDN: hfcsusb: fix memory leak in hfcsusb_probe()
  spi: Try to get ACPI GPIO IRQ earlier
  ipv4: route: Prevent rt_bind_exception() from rebinding stale fnhe
  strparser: Fix signed/unsigned mismatch bug
  gcov: add support for GCC 15
  mm/ksm: fix flag-dropping behavior in ksm_madvise
  ALSA: usb-audio: Fix NULL pointer dereference in snd_usb_mixer_controls_badd
  ASoC: cs4271: Fix regulator leak on probe failure
  regulator: fixed: use dev_err_probe for register
  Bluetooth: L2CAP: export l2cap_chan_hold for modules
  net_sched: remove need_resched() from qdisc_run()
  net/mlx5e: Fix maxrate wraparound in threshold between units
  net: sched: act_ife: initialize struct tc_ife to fix KMSAN kernel-infoleak
  Bluetooth: 6lowpan: Don't hold spin lock over sleeping functions
  Bluetooth: 6lowpan: fix BDADDR_LE vs ADDR_LE_DEV address type confusion
  Bluetooth: 6lowpan: reset link-local header on ipv6 recv path
  net: fec: correct rx_bytes statistic for the case SHIFT16 is set
  ASoC: max98090/91: fixed max98091 ALSA widget powering up/down
  HID: quirks: avoid Cooler Master MM712 dongle wakeup bug
  NFS4: Fix state renewals missing after boot
  extcon: adc-jack: Cleanup wakeup source only if it was enabled
  net: usb: qmi_wwan: initialize MAC header offset in qmimux_rx_fixup
  sctp: Prevent TOCTOU out-of-bounds write
  sctp: Hold RCU read lock while iterating over address list
  net: vlan: sync VLAN features with lower device
  ceph: add checking of wait_for_completion_killable() return value
  fbdev: Add bounds checking in bit_putcs to fix vmalloc-out-of-bounds
  ACPI: property: Return present device nodes only on fwnode interface
  9p: sysfs_init: don't hardcode error to ENOMEM
  9p: fix /sys/fs/9p/caches overwriting itself
  fs/hpfs: Fix error code for new_inode() failure in mkdir/create/mknod/symlink
  ACPICA: Update dsmethod.c to get rid of unused variable warning
  page_pool: Clamp pool size to max 16K pages
  Bluetooth: bcsp: receive data only if registered
  Bluetooth: SCO: Fix UAF on sco_conn_free
  net: macb: avoid dealing with endianness in macb_set_hwaddr()
  nfs4_setup_readdir(): insufficient locking for ->d_parent->d_inode dereferencing
  NFSv4.1: fix mount hang after CREATE_SESSION failure
  NFSv4: handle ERR_GRACE on delegation recalls
  remoteproc: qcom: q6v5: Avoid handling handover twice
  sparc/module: Add R_SPARC_UA64 relocation handling
  net: intel: fm10k: Fix parameter idx set but not used
  jfs: fix uninitialized waitqueue in transaction manager
  jfs: Verify inode mode when loading from disk
  ipv6: np->rxpmtu race annotation
  usb: xhci: plat: Facilitate using autosuspend for xhci plat devices
  usb: mon: Increase BUFF_MAX to 64 MiB to support multi-MB URBs
  allow finish_no_open(file, ERR_PTR(-E...))
  scsi: lpfc: Define size of debugfs entry for xri rebalancing
  scsi: lpfc: Check return status of lpfc_reset_flush_io_context during TGT_RESET
  selftests/Makefile: include $(INSTALL_DEP_TARGETS) in clean target to clean net/lib dependency
  net/cls_cgroup: Fix task_get_classid() during qdisc run
  media: redrat3: use int type to store negative error codes
  net: sh_eth: Disable WoL if system can not suspend
  usb: gadget: f_hid: Fix zero length packet transfer
  net: call cond_resched() less often in __release_sock()
  ALSA: usb-audio: apply quirk for MOONDROP Quark2
  net: nfc: nci: Increase NCI_DATA_TIMEOUT to 3000 ms
  dmaengine: mv_xor: match alloc_wc and free_wc
  scsi: pm8001: Use int instead of u32 to store error codes
  mips: lantiq: xway: sysctrl: rename stp clock
  mips: lantiq: danube: add missing properties to cpu node
  media: fix uninitialized symbol warnings
  extcon: adc-jack: Fix wakeup source leaks on device unbind
  rds: Fix endianness annotation for RDS_MPATH_HASH
  net: Call trace_sock_exceed_buf_limit() for memcg failure with SK_MEM_RECV.
  char: misc: Does not request module for miscdevice with dynamic minor
  usb: gadget: f_ncm: Fix MAC assignment NCM ethernet
  iio: adc: spear_adc: mask SPEAR_ADC_STATUS channel and avg sample before setting register
  media: imon: make send_packet() more robust
  net: ipv6: fix field-spanning memcpy warning in AH output
  bridge: Redirect to backup port when port is administratively down
  media: pci: ivtv: Don't create fake v4l2_fh
  drm/amdkfd: return -ENOTTY for unsupported IOCTLs
  selftests/net: Ensure assert() triggers in psock_tpacket.c
  selftests/net: Replace non-standard __WORDSIZE with sizeof(long) * 8
  PCI: Disable MSI on RDC PCI to PCIe bridges
  drm/nouveau: replace snprintf() with scnprintf() in nvkm_snprintbf()
  mfd: madera: Work around false-positive -Wininitialized warning
  mfd: stmpe: Remove IRQ domain upon removal
  tools/power x86_energy_perf_policy: Prefer driver HWP limits
  tools/power x86_energy_perf_policy: Enhance HWP enable
  tools/cpupower: Fix incorrect size in cpuidle_state_disable()
  hwmon: (dell-smm) Add support for Dell OptiPlex 7040
  uprobe: Do not emulate/sstep original instruction when ip is changed
  clocksource/drivers/vf-pit: Replace raw_readl/writel to readl/writel
  video: backlight: lp855x_bl: Set correct EPROM start for LP8556
  tee: allow a driver to allocate a tee_device without a pool
  ACPICA: dispatcher: Use acpi_ds_clear_operands() in acpi_ds_call_control_method()
  irqchip/gic-v2m: Handle Multiple MSI base IRQ Alignment
  arc: Fix __fls() const-foldability via __builtin_clzl()
  cpufreq/longhaul: handle NULL policy in longhaul_exit
  selftests/bpf: Fix bpf_prog_detach2 usage in test_lirc_mode2
  ACPI: video: force native for Lenovo 82K8
  memstick: Add timeout to prevent indefinite waiting
  bpf: Don't use %pK through printk
  spi: loopback-test: Don't use %pK through printk
  soc: qcom: smem: Fix endian-unaware access of num_entries
  usb: gadget: f_fs: Fix epfile null pointer access after ep enable.
  serial: 8250_dw: Use devm_clk_get_optional() to get the input clock
  can: gs_usb: increase max interface to U8_MAX
  devcoredump: Fix circular locking dependency with devcd->mutex.
  x86/resctrl: Fix miscount of bandwidth event when reactivating previously unavailable RMID
  net: phy: dp83867: Disable EEE support as not implemented
  regmap: slimbus: fix bus_context pointer in regmap init calls
  usbnet: Prevents free active kevent
  wifi: ath10k: Fix memory leak on unsupported WMI command
  ASoC: qdsp6: q6asm: do not sleep while atomic
  fbdev: pvr2fb: Fix leftover reference to ONCHIP_NR_DMA_CHANNELS
  fbdev: bitblit: bound-check glyph index in bit_putcs*
  ACPI: video: Fix use-after-free in acpi_video_switch_brightness()
  fbdev: atyfb: Check if pll_ops->init_pll failed
  net: usb: asix_devices: Check return value of usbnet_get_endpoints
  btrfs: use smp_mb__after_atomic() when forcing COW in create_pending_snapshot()
  x86/bugs: Fix reporting of LFENCE retpoline

 Conflicts:
	drivers/slimbus/qcom-ngd-ctrl.c
	drivers/usb/gadget/function/f_fs.c
	drivers/usb/host/xhci-plat.c

Change-Id: Id995e84f0ff2c819145f7ebd62bc8dcd47fbbb47
2026-01-21 21:23:37 +00:00

340 lines
7.8 KiB
C

/*
* Forwarding decision
* Linux ethernet bridge
*
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/netpoll.h>
#include <linux/skbuff.h>
#include <linux/if_vlan.h>
#include <linux/netfilter_bridge.h>
#include "br_private.h"
/* Don't forward packets to originating port or forwarding disabled */
static inline int should_deliver(const struct net_bridge_port *p,
const struct sk_buff *skb)
{
struct net_bridge_vlan_group *vg;
vg = nbp_vlan_group_rcu(p);
return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
br_allowed_egress(vg, skb) && p->state == BR_STATE_FORWARDING &&
nbp_switchdev_allowed_egress(p, skb) &&
!br_skb_isolated(p, skb);
}
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
{
skb_push(skb, ETH_HLEN);
if (!is_skb_forwardable(skb->dev, skb))
goto drop;
br_drop_fake_rtable(skb);
if (skb->ip_summed == CHECKSUM_PARTIAL &&
(skb->protocol == htons(ETH_P_8021Q) ||
skb->protocol == htons(ETH_P_8021AD))) {
int depth;
if (!__vlan_get_protocol(skb, skb->protocol, &depth))
goto drop;
skb_set_network_header(skb, depth);
}
dev_queue_xmit(skb);
return 0;
drop:
kfree_skb(skb);
return 0;
}
EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
skb->tstamp = 0;
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING,
net, sk, skb, NULL, skb->dev,
br_dev_queue_push_xmit);
}
EXPORT_SYMBOL_GPL(br_forward_finish);
static void __br_forward(const struct net_bridge_port *to,
struct sk_buff *skb, bool local_orig)
{
struct net_bridge_vlan_group *vg;
struct net_device *indev;
struct net *net;
int br_hook;
vg = nbp_vlan_group_rcu(to);
skb = br_handle_vlan(to->br, to, vg, skb);
if (!skb)
return;
indev = skb->dev;
skb->dev = to->dev;
if (!local_orig) {
if (skb_warn_if_lro(skb)) {
kfree_skb(skb);
return;
}
br_hook = NF_BR_FORWARD;
skb_forward_csum(skb);
net = dev_net(indev);
} else {
if (unlikely(netpoll_tx_running(to->br->dev))) {
skb_push(skb, ETH_HLEN);
if (!is_skb_forwardable(skb->dev, skb))
kfree_skb(skb);
else
br_netpoll_send_skb(to, skb);
return;
}
br_hook = NF_BR_LOCAL_OUT;
net = dev_net(skb->dev);
indev = NULL;
}
NF_HOOK(NFPROTO_BRIDGE, br_hook,
net, NULL, skb, indev, skb->dev,
br_forward_finish);
}
static int deliver_clone(const struct net_bridge_port *prev,
struct sk_buff *skb, bool local_orig)
{
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
skb = skb_clone(skb, GFP_ATOMIC);
if (!skb) {
dev->stats.tx_dropped++;
return -ENOMEM;
}
__br_forward(prev, skb, local_orig);
return 0;
}
/**
* br_forward - forward a packet to a specific port
* @to: destination port
* @skb: packet being forwarded
* @local_rcv: packet will be received locally after forwarding
* @local_orig: packet is locally originated
*
* Should be called with rcu_read_lock.
*/
void br_forward(const struct net_bridge_port *to,
struct sk_buff *skb, bool local_rcv, bool local_orig)
{
if (unlikely(!to))
goto out;
/* redirect to backup link if the destination port is down */
if (rcu_access_pointer(to->backup_port) &&
(!netif_carrier_ok(to->dev) || !netif_running(to->dev))) {
struct net_bridge_port *backup_port;
backup_port = rcu_dereference(to->backup_port);
if (unlikely(!backup_port))
goto out;
to = backup_port;
}
if (should_deliver(to, skb)) {
if (local_rcv)
deliver_clone(to, skb, local_orig);
else
__br_forward(to, skb, local_orig);
return;
}
out:
if (!local_rcv)
kfree_skb(skb);
}
EXPORT_SYMBOL_GPL(br_forward);
static struct net_bridge_port *maybe_deliver(
struct net_bridge_port *prev, struct net_bridge_port *p,
struct sk_buff *skb, bool local_orig)
{
int err;
if (!should_deliver(p, skb))
return prev;
if (!prev)
goto out;
err = deliver_clone(prev, skb, local_orig);
if (err)
return ERR_PTR(err);
out:
return p;
}
/* called under rcu_read_lock */
void br_flood(struct net_bridge *br, struct sk_buff *skb,
enum br_pkt_type pkt_type, bool local_rcv, bool local_orig)
{
u8 igmp_type = br_multicast_igmp_type(skb);
struct net_bridge_port *prev = NULL;
struct net_bridge_port *p;
list_for_each_entry_rcu(p, &br->port_list, list) {
/* Do not flood unicast traffic to ports that turn it off, nor
* other traffic if flood off, except for traffic we originate
*/
switch (pkt_type) {
case BR_PKT_UNICAST:
if (!(p->flags & BR_FLOOD))
continue;
break;
case BR_PKT_MULTICAST:
if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev)
continue;
break;
case BR_PKT_BROADCAST:
if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev)
continue;
break;
}
/* Do not flood to ports that enable proxy ARP */
if (p->flags & BR_PROXYARP)
continue;
if ((p->flags & (BR_PROXYARP_WIFI | BR_NEIGH_SUPPRESS)) &&
BR_INPUT_SKB_CB(skb)->proxyarp_replied)
continue;
prev = maybe_deliver(prev, p, skb, local_orig);
if (IS_ERR(prev))
goto out;
if (prev == p)
br_multicast_count(p->br, p, skb, igmp_type,
BR_MCAST_DIR_TX);
}
if (!prev)
goto out;
if (local_rcv)
deliver_clone(prev, skb, local_orig);
else
__br_forward(prev, skb, local_orig);
return;
out:
if (!local_rcv)
kfree_skb(skb);
}
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
const unsigned char *addr, bool local_orig)
{
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
const unsigned char *src = eth_hdr(skb)->h_source;
struct sk_buff *nskb;
if (!should_deliver(p, skb))
return;
/* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
if (skb->dev == p->dev && ether_addr_equal(src, addr))
return;
__skb_push(skb, ETH_HLEN);
nskb = pskb_copy(skb, GFP_ATOMIC);
__skb_pull(skb, ETH_HLEN);
if (!nskb) {
dev->stats.tx_dropped++;
return;
}
skb = nskb;
__skb_pull(skb, ETH_HLEN);
if (!is_broadcast_ether_addr(addr))
memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
__br_forward(p, skb, local_orig);
}
/* called with rcu_read_lock */
void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb,
bool local_rcv, bool local_orig)
{
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
u8 igmp_type = br_multicast_igmp_type(skb);
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *prev = NULL;
struct net_bridge_port_group *p;
struct hlist_node *rp;
rp = rcu_dereference(hlist_first_rcu(&br->router_list));
p = mdst ? rcu_dereference(mdst->ports) : NULL;
while (p || rp) {
struct net_bridge_port *port, *lport, *rport;
lport = p ? p->port : NULL;
rport = hlist_entry_safe(rp, struct net_bridge_port, rlist);
if ((unsigned long)lport > (unsigned long)rport) {
port = lport;
if (port->flags & BR_MULTICAST_TO_UNICAST) {
maybe_deliver_addr(lport, skb, p->eth_addr,
local_orig);
goto delivered;
}
} else {
port = rport;
}
prev = maybe_deliver(prev, port, skb, local_orig);
delivered:
if (IS_ERR(prev))
goto out;
if (prev == port)
br_multicast_count(port->br, port, skb, igmp_type,
BR_MCAST_DIR_TX);
if ((unsigned long)lport >= (unsigned long)port)
p = rcu_dereference(p->next);
if ((unsigned long)rport >= (unsigned long)port)
rp = rcu_dereference(hlist_next_rcu(rp));
}
if (!prev)
goto out;
if (local_rcv)
deliver_clone(prev, skb, local_orig);
else
__br_forward(prev, skb, local_orig);
return;
out:
if (!local_rcv)
kfree_skb(skb);
}
#endif