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

Pull networking fixes from Paolo Abeni:
 "Including fixes from netfilter and batman-adv.

  Current release - new code bugs:

   - netfilter: cthelper: cap to maximum number of expectation per master

  Previous releases - regressions:

   - netpoll: fix a use-after-free on shutdown path

   - tcp: restore RCU grace period in tcp_ao_destroy_sock

   - ipv6: fix NULL deref in fib6_walk_continiue() on multi-batch dump

   - batman-adv: dat: ensure accessible eth_hdr proto field

   - eth:
      - virtio_net: disable cb when NAPI is busy-polled
      - lan743x: Initialize eth_syslock spinlock before use

  Previous releases - always broken:

   - netfilter:
      - nft_set_pipapo: don't leak bad clone into future transaction

   - sched:
      - sch_teql: Introduce slaves_lock to avoid race condition and UAF
      - replace direct dequeue call with peek and qdisc_dequeue_peeked

   - sctp: add INIT verification after cookie unpacking

   - tipc: fix out-of-bounds read in broadcast Gap ACK blocks

   - seg6: validate SRH length before reading fixed fields

   - eth:
      - mlx5e: fix use-after-free of metadata_dst on RX SC delete
      - enetc: check the number of BDs needed for xdp_frame
      - fbnic: don't cache shinfo across skb realloc"

* tag 'net-7.2-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (58 commits)
  net/mlx5: HWS, fix matcher leak on resize target setup failure
  net/sched: hhf: clear heavy-hitter state on reset
  net/sched: dualpi2: clear stale classification on filter miss
  net/sched: act_bpf: use rcu_dereference_bh() to read the filter
  selftests: drv-net: tso: don't touch dangerous feature bits
  cxgb4: Fix decode strings dump for T6 adapters
  virtio_net: disable cb when NAPI is busy-polled
  sctp: fix addr_wq_timer race in sctp_free_addr_wq()
  selftests: net: bump default cmd() timeout to 20 seconds
  bridge: stp: Fix a potential use-after-free when deleting a bridge
  net/sched: sch_teql: Introduce slaves_lock to avoid race condition and UAF
  net: gianfar: dispose irq mappings on probe failure and device removal
  net: lan743x: Initialize eth_syslock spinlock before use
  net: libwx: fix VMDQ mask for 1-queue mode
  net: airoha: fix max receive size configuration
  fsl/fman: Free init resources on KeyGen failure in fman_init()
  netfilter: nftables: restrict checkum update offset
  netfilter: nftables: restrict linklayer and network header writes
  netfilter: nfnetlink_queue: restrict writes to network header
  netfilter: nft_fib: reject fib expression on the netdev egress hook
  ...
This commit is contained in:
Linus Torvalds
2026-07-02 06:01:12 -10:00
92 changed files with 1291 additions and 454 deletions

View File

@@ -373,6 +373,7 @@ Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@opinsys.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@mellanox.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@nvidia.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgunthorpe@obsidianresearch.com>
Jason Wang <jasowangio@gmail.com> <jasowang@redhat.com>
Jason Xing <kerneljasonxing@gmail.com> <kernelxing@tencent.com>
<javier@osg.samsung.com> <javier.martinez@collabora.co.uk>
Javi Merino <javi.merino@kernel.org> <javi.merino@arm.com>

View File

@@ -15738,8 +15738,8 @@ F: drivers/net/ethernet/marvell/octeon_ep_vf
MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER
M: Sunil Goutham <sgoutham@marvell.com>
M: Geetha sowjanya <gakula@marvell.com>
M: Ratheesh Kannoth <rkannoth@marvell.com>
M: Subbaraya Sundeep <sbhatta@marvell.com>
M: hariprasad <hkelam@marvell.com>
M: Bharat Bhushan <bbhushan2@marvell.com>
L: netdev@vger.kernel.org
S: Maintained
@@ -15748,9 +15748,8 @@ F: include/linux/soc/marvell/octeontx2/
MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER
M: Sunil Goutham <sgoutham@marvell.com>
M: Linu Cherian <lcherian@marvell.com>
M: Ratheesh Kannoth <rkannoth@marvell.com>
M: Geetha sowjanya <gakula@marvell.com>
M: hariprasad <hkelam@marvell.com>
M: Subbaraya Sundeep <sbhatta@marvell.com>
L: netdev@vger.kernel.org
S: Maintained
@@ -15758,8 +15757,8 @@ F: Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
F: drivers/net/ethernet/marvell/octeontx2/af/
MARVELL PEM PMU DRIVER
M: Linu Cherian <lcherian@marvell.com>
M: Gowthami Thiagarajan <gthiagarajan@marvell.com>
M: Geetha sowjanya <gakula@marvell.com>
S: Supported
F: drivers/perf/marvell_pem_pmu.c
@@ -27521,7 +27520,7 @@ F: drivers/net/ethernet/dec/tulip/
TUN/TAP DRIVER
M: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
M: Jason Wang <jasowang@redhat.com>
M: Jason Wang <jasowangio@gmail.com>
S: Maintained
W: http://vtun.sourceforge.net/tun
F: Documentation/networking/tuntap.rst
@@ -28513,7 +28512,7 @@ F: include/uapi/linux/virtio_balloon.h
VIRTIO BLOCK AND SCSI DRIVERS
M: "Michael S. Tsirkin" <mst@redhat.com>
M: Jason Wang <jasowang@redhat.com>
M: Jason Wang <jasowangio@gmail.com>
R: Paolo Bonzini <pbonzini@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
R: Eugenio Pérez <eperezma@redhat.com>
@@ -28542,7 +28541,7 @@ F: include/uapi/linux/virtio_console.h
VIRTIO CORE
M: "Michael S. Tsirkin" <mst@redhat.com>
M: Jason Wang <jasowang@redhat.com>
M: Jason Wang <jasowangio@gmail.com>
R: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
R: Eugenio Pérez <eperezma@redhat.com>
L: virtualization@lists.linux.dev
@@ -28620,7 +28619,7 @@ F: include/uapi/linux/virtio_gpu.h
VIRTIO HOST (VHOST)
M: "Michael S. Tsirkin" <mst@redhat.com>
M: Jason Wang <jasowang@redhat.com>
M: Jason Wang <jasowangio@gmail.com>
R: Eugenio Pérez <eperezma@redhat.com>
L: kvm@vger.kernel.org
L: virtualization@lists.linux.dev
@@ -28635,7 +28634,7 @@ F: kernel/vhost_task.c
VIRTIO HOST (VHOST-SCSI)
M: "Michael S. Tsirkin" <mst@redhat.com>
M: Jason Wang <jasowang@redhat.com>
M: Jason Wang <jasowangio@gmail.com>
M: Mike Christie <michael.christie@oracle.com>
R: Paolo Bonzini <pbonzini@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
@@ -28675,7 +28674,7 @@ F: include/uapi/linux/virtio_mem.h
VIRTIO NET DRIVER
M: "Michael S. Tsirkin" <mst@redhat.com>
M: Jason Wang <jasowang@redhat.com>
M: Jason Wang <jasowangio@gmail.com>
R: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
R: Eugenio Pérez <eperezma@redhat.com>
L: netdev@vger.kernel.org

View File

@@ -178,10 +178,15 @@ static void airoha_fe_maccr_init(struct airoha_eth *eth)
{
int p;
for (p = 1; p <= ARRAY_SIZE(eth->ports); p++)
for (p = 1; p <= ARRAY_SIZE(eth->ports); p++) {
airoha_fe_set(eth, REG_GDM_FWD_CFG(p),
GDM_TCP_CKSUM_MASK | GDM_UDP_CKSUM_MASK |
GDM_IP4_CKSUM_MASK | GDM_DROP_CRC_ERR_MASK);
airoha_fe_rmw(eth, REG_GDM_LEN_CFG(p),
GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_RX_SIZE));
}
airoha_fe_rmw(eth, REG_CDM_VLAN_CTRL(1), CDM_VLAN_MASK,
FIELD_PREP(CDM_VLAN_MASK, 0x8100));
@@ -944,6 +949,25 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
q->txq_stopped = false;
}
static void airoha_unmap_xmit_buf(struct airoha_eth *eth,
struct airoha_queue_entry *e)
{
switch (e->dma_type) {
case AIROHA_DMA_MAP_PAGE:
dma_unmap_page(eth->dev, e->dma_addr, e->dma_len,
DMA_TO_DEVICE);
break;
case AIROHA_DMA_MAP_SINGLE:
dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
DMA_TO_DEVICE);
break;
case AIROHA_DMA_UNMAPPED:
default:
break;
}
e->dma_type = AIROHA_DMA_UNMAPPED;
}
static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_tx_irq_queue *irq_q;
@@ -1006,9 +1030,7 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
skb = e->skb;
e->skb = NULL;
dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
DMA_TO_DEVICE);
e->dma_addr = 0;
airoha_unmap_xmit_buf(eth, e);
list_add_tail(&e->list, &q->tx_list);
WRITE_ONCE(desc->msg0, 0);
@@ -1177,12 +1199,10 @@ static void airoha_qdma_tx_cleanup(struct airoha_qdma *qdma)
struct airoha_qdma_desc *desc = &q->desc[j];
struct sk_buff *skb = e->skb;
if (!e->dma_addr)
if (e->dma_type == AIROHA_DMA_UNMAPPED)
continue;
dma_unmap_single(qdma->eth->dev, e->dma_addr,
e->dma_len, DMA_TO_DEVICE);
e->dma_addr = 0;
airoha_unmap_xmit_buf(qdma->eth, e);
list_add_tail(&e->list, &q->tx_list);
WRITE_ONCE(desc->ctrl, 0);
@@ -1831,13 +1851,24 @@ static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
spin_unlock(&port->stats_lock);
}
static void airoha_dev_set_xmit_frame_size(struct net_device *netdev)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
airoha_ppe_set_xmit_frame_size(dev);
if (!airoha_is_lan_gdm_dev(dev))
airoha_fe_rmw(dev->eth, REG_WAN_MTU0, WAN_MTU0_MASK,
FIELD_PREP(WAN_MTU0_MASK,
VLAN_ETH_HLEN + netdev->mtu));
}
static int airoha_dev_open(struct net_device *netdev)
{
int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
u32 cur_len, pse_port = FE_PSE_PORT_PPE1;
struct airoha_qdma *qdma = dev->qdma;
u32 pse_port = FE_PSE_PORT_PPE1;
int err;
netif_tx_start_all_queues(netdev);
err = airoha_set_vip_for_gdm_port(dev, true);
@@ -1851,19 +1882,7 @@ static int airoha_dev_open(struct net_device *netdev)
airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
GDM_STAG_EN_MASK);
cur_len = airoha_fe_get(qdma->eth, REG_GDM_LEN_CFG(port->id),
GDM_LONG_LEN_MASK);
if (!port->users || len > cur_len) {
/* Opening a sibling net_device with a larger MTU updates the
* MTU of already running devices. This is required to allow
* multiple net_devices with different MTUs to share the same
* GDM port.
*/
airoha_fe_rmw(qdma->eth, REG_GDM_LEN_CFG(port->id),
GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
FIELD_PREP(GDM_LONG_LEN_MASK, len));
}
airoha_dev_set_xmit_frame_size(netdev);
port->users++;
if (!airoha_is_lan_gdm_dev(dev) &&
@@ -1875,30 +1894,6 @@ static int airoha_dev_open(struct net_device *netdev)
return 0;
}
static void airoha_set_port_mtu(struct airoha_eth *eth,
struct airoha_gdm_port *port)
{
u32 len = 0;
int i;
for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
struct airoha_gdm_dev *dev = port->devs[i];
struct net_device *netdev;
if (!dev)
continue;
netdev = netdev_from_priv(dev);
if (netif_running(netdev))
len = max_t(u32, len, netdev->mtu);
}
len += ETH_HLEN + ETH_FCS_LEN;
airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id),
GDM_LONG_LEN_MASK,
FIELD_PREP(GDM_LONG_LEN_MASK, len));
}
static int airoha_dev_stop(struct net_device *netdev)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -1909,7 +1904,7 @@ static int airoha_dev_stop(struct net_device *netdev)
airoha_set_vip_for_gdm_port(dev, false);
if (--port->users)
airoha_set_port_mtu(dev->eth, port);
airoha_ppe_set_xmit_frame_size(dev);
else
airoha_set_gdm_port_fwd_cfg(qdma->eth,
REG_GDM_FWD_CFG(port->id),
@@ -1962,10 +1957,6 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev)
FIELD_PREP(LPBK_CHAN_MASK, chan) |
LBK_GAP_MODE_MASK | LBK_LEN_MODE_MASK |
LBK_CHAN_MODE_MASK | LPBK_EN_MASK);
airoha_fe_rmw(eth, REG_GDM_LEN_CFG(AIROHA_GDM2_IDX),
GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_MTU));
/* Forward the traffic to the proper GDM port */
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
: FE_PSE_PORT_GDM4;
@@ -2098,7 +2089,7 @@ static int airoha_dev_change_mtu(struct net_device *netdev, int mtu)
WRITE_ONCE(netdev->mtu, mtu);
if (port->users)
airoha_set_port_mtu(dev->eth, port);
airoha_dev_set_xmit_frame_size(netdev);
return 0;
}
@@ -2193,8 +2184,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct netdev_queue *txq;
struct airoha_queue *q;
LIST_HEAD(tx_list);
dma_addr_t addr;
int i = 0, qid;
void *data;
u16 index;
u8 fport;
@@ -2250,24 +2241,22 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
len = skb_headlen(skb);
data = skb->data;
e = list_first_entry(&q->tx_list, struct airoha_queue_entry,
list);
len = skb_headlen(skb);
addr = dma_map_single(netdev->dev.parent, skb->data, len,
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
goto error_unlock;
e->dma_type = AIROHA_DMA_MAP_SINGLE;
index = e - q->entry;
while (true) {
struct airoha_qdma_desc *desc = &q->desc[index];
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
dma_addr_t addr;
u32 val;
addr = dma_map_single(netdev->dev.parent, data, len,
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
goto error_unmap;
list_move_tail(&e->list, &tx_list);
e->skb = i == nr_frags - 1 ? skb : NULL;
e->dma_addr = addr;
@@ -2291,8 +2280,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
if (++i == nr_frags)
break;
data = skb_frag_address(frag);
len = skb_frag_size(frag);
addr = skb_frag_dma_map(netdev->dev.parent, frag, 0, len,
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
goto error_unmap;
e->dma_type = AIROHA_DMA_MAP_PAGE;
}
q->queued += i;
@@ -2313,11 +2307,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
error_unmap:
list_for_each_entry(e, &tx_list, list) {
dma_unmap_single(netdev->dev.parent, e->dma_addr, e->dma_len,
DMA_TO_DEVICE);
e->dma_addr = 0;
}
list_for_each_entry(e, &tx_list, list)
airoha_unmap_xmit_buf(dev->eth, e);
list_splice(&tx_list, &q->tx_list);
error_unlock:
spin_unlock_bh(&q->lock);

View File

@@ -23,6 +23,7 @@
#define AIROHA_MAX_DSA_PORTS 7
#define AIROHA_MAX_NUM_RSTS 3
#define AIROHA_MAX_MTU 9220
#define AIROHA_MAX_RX_SIZE 16128
#define AIROHA_MAX_PACKET_SIZE 2048
#define AIROHA_NUM_QOS_CHANNELS 4
#define AIROHA_NUM_QOS_QUEUES 8
@@ -170,12 +171,19 @@ enum trtcm_param {
#define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6)
#define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0)
enum airoha_dma_map_type {
AIROHA_DMA_UNMAPPED,
AIROHA_DMA_MAP_SINGLE,
AIROHA_DMA_MAP_PAGE,
};
struct airoha_queue_entry {
union {
void *buf;
struct {
struct list_head list;
struct sk_buff *skb;
enum airoha_dma_map_type dma_type;
};
};
dma_addr_t dma_addr;
@@ -676,6 +684,7 @@ int airoha_get_fe_port(struct airoha_gdm_dev *dev);
bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
struct airoha_gdm_dev *dev);
void airoha_ppe_set_xmit_frame_size(struct airoha_gdm_dev *dev);
void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport);
bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,

View File

@@ -97,6 +97,33 @@ void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport)
__field_prep(DFT_CPORT_MASK(fport), fe_cpu_port));
}
void airoha_ppe_set_xmit_frame_size(struct airoha_gdm_dev *dev)
{
struct airoha_gdm_port *port = dev->port;
struct airoha_eth *eth = dev->eth;
int i, ppe_id, index;
u32 len = 0;
for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
struct airoha_gdm_dev *d = port->devs[i];
struct net_device *netdev;
if (!d)
continue;
netdev = netdev_from_priv(d);
if (netif_running(netdev))
len = max_t(u32, len, netdev->mtu);
}
len += VLAN_ETH_HLEN;
ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1);
index = port->id == AIROHA_GDM4_IDX ? 7 : port->id;
airoha_fe_rmw(eth, REG_PPE_MTU(ppe_id, index),
FP_EGRESS_MTU_MASK(index),
__field_prep(FP_EGRESS_MTU_MASK(index), len));
}
static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
{
u32 sram_ppe_num_data_entries = PPE_SRAM_NUM_ENTRIES, sram_num_entries;
@@ -115,8 +142,6 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
PPE_RAM_NUM_ENTRIES_SHIFT(sram_ppe_num_data_entries);
for (i = 0; i < eth->soc->num_ppe; i++) {
int p;
airoha_fe_wr(eth, REG_PPE_TB_BASE(i),
ppe->foe_dma + sram_tb_size);
@@ -166,15 +191,6 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED);
airoha_fe_clear(eth, REG_PPE_PPE_FLOW_CFG(i),
PPE_FLOW_CFG_IP6_6RD_MASK);
for (p = 0; p < ARRAY_SIZE(eth->ports); p++)
airoha_fe_rmw(eth, REG_PPE_MTU(i, p),
FP0_EGRESS_MTU_MASK |
FP1_EGRESS_MTU_MASK,
FIELD_PREP(FP0_EGRESS_MTU_MASK,
AIROHA_MAX_MTU) |
FIELD_PREP(FP1_EGRESS_MTU_MASK,
AIROHA_MAX_MTU));
}
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
@@ -196,6 +212,7 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
airoha_ppe_is_enabled(eth, 1);
fport = airoha_get_fe_port(dev);
airoha_ppe_set_cpu_port(dev, ppe_id, fport);
airoha_ppe_set_xmit_frame_size(dev);
}
}
}

View File

@@ -327,9 +327,8 @@
#define PPE_SRAM_TABLE_EN_MASK BIT(0)
#define REG_PPE_MTU_BASE(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x304)
#define REG_PPE_MTU(_m, _n) (REG_PPE_MTU_BASE(_m) + ((_n) << 2))
#define FP1_EGRESS_MTU_MASK GENMASK(29, 16)
#define FP0_EGRESS_MTU_MASK GENMASK(13, 0)
#define REG_PPE_MTU(_m, _n) (REG_PPE_MTU_BASE(_m) + (((_n) / 2) << 2))
#define FP_EGRESS_MTU_MASK(_n) GENMASK(13 + (((_n) % 2) << 4), ((_n) % 2) << 4)
#define REG_PPE_RAM_CTRL(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x31c)
#define PPE_SRAM_CTRL_ACK_MASK BIT(31)
@@ -377,6 +376,10 @@
#define REG_SRC_PORT_FC_MAP6 0x2298
#define FC_ID_OF_SRC_PORT_MASK(_n) GENMASK(4 + ((_n) << 3), ((_n) << 3))
#define REG_WAN_MTU0 0x2300
#define WAN_MTU1_MASK GENMASK(29, 16)
#define WAN_MTU0_MASK GENMASK(13, 0)
#define REG_CDM5_RX_OQ1_DROP_CNT 0x29d4
/* QDMA */

View File

@@ -1163,18 +1163,14 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct)
if (octeon_map_pci_barx(oct, 1, MAX_BAR1_IOREMAP_SIZE)) {
dev_err(&oct->pci_dev->dev, "%s CN23XX BAR1 map failed\n",
__func__);
octeon_unmap_pci_barx(oct, 0);
return 1;
goto err_unmap_bar0;
}
if (cn23xx_get_pf_num(oct) != 0)
return 1;
goto err_unmap_bar1;
if (cn23xx_sriov_config(oct)) {
octeon_unmap_pci_barx(oct, 0);
octeon_unmap_pci_barx(oct, 1);
return 1;
}
if (cn23xx_sriov_config(oct))
goto err_unmap_bar1;
octeon_write_csr64(oct, CN23XX_SLI_MAC_CREDIT_CNT, 0x3F802080802080ULL);
@@ -1205,6 +1201,12 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct)
oct->coproc_clock_rate = 1000000ULL * cn23xx_coprocessor_clock(oct);
return 0;
err_unmap_bar1:
octeon_unmap_pci_barx(oct, 1);
err_unmap_bar0:
octeon_unmap_pci_barx(oct, 0);
return 1;
}
EXPORT_SYMBOL_GPL(setup_cn23xx_octeon_pf_device);

View File

@@ -6737,14 +6737,6 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state)
return;
}
if (is_t4(adapter->params.chip)) {
sge_idma_decode = (const char **)t4_decode;
sge_idma_decode_nstates = ARRAY_SIZE(t4_decode);
} else {
sge_idma_decode = (const char **)t5_decode;
sge_idma_decode_nstates = ARRAY_SIZE(t5_decode);
}
if (state < sge_idma_decode_nstates)
CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]);
else

View File

@@ -1783,6 +1783,7 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames,
{
struct enetc_tx_swbd xdp_redirect_arr[ENETC_MAX_SKB_FRAGS] = {0};
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct skb_shared_info *shinfo;
struct enetc_bdr *tx_ring;
int xdp_tx_bd_cnt, i, k;
int xdp_tx_frm_cnt = 0;
@@ -1798,6 +1799,12 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames,
prefetchw(ENETC_TXBD(*tx_ring, tx_ring->next_to_use));
for (k = 0; k < num_frames; k++) {
if (xdp_frame_has_frags(frames[k])) {
shinfo = xdp_get_shared_info_from_frame(frames[k]);
if (unlikely((shinfo->nr_frags + 1) > ENETC_MAX_SKB_FRAGS))
break;
}
xdp_tx_bd_cnt = enetc_xdp_frame_to_xdp_tx_swbd(tx_ring,
xdp_redirect_arr,
frames[k]);

View File

@@ -1995,8 +1995,10 @@ static int fman_init(struct fman *fman)
/* Init KeyGen */
fman->keygen = keygen_init(fman->kg_regs);
if (!fman->keygen)
if (!fman->keygen) {
free_init_resources(fman);
return -EINVAL;
}
err = enable(fman, cfg);
if (err != 0)

View File

@@ -469,10 +469,13 @@ static void free_gfar_dev(struct gfar_private *priv)
{
int i, j;
for (i = 0; i < priv->num_grps; i++)
for (i = 0; i < MAXGROUPS; i++)
for (j = 0; j < GFAR_NUM_IRQS; j++) {
kfree(priv->gfargrp[i].irqinfo[j]);
priv->gfargrp[i].irqinfo[j] = NULL;
if (priv->gfargrp[i].irqinfo[j]) {
irq_dispose_mapping(priv->gfargrp[i].irqinfo[j]->irq);
kfree(priv->gfargrp[i].irqinfo[j]);
priv->gfargrp[i].irqinfo[j] = NULL;
}
}
free_netdev(priv->ndev);
@@ -616,7 +619,7 @@ static phy_interface_t gfar_get_interface(struct net_device *dev)
static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
{
const char *model;
int err = 0, i;
int err = 0, i, j;
phy_interface_t interface;
struct net_device *dev = NULL;
struct gfar_private *priv = NULL;
@@ -702,8 +705,11 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
priv->rx_list.count = 0;
mutex_init(&priv->rx_queue_access);
for (i = 0; i < MAXGROUPS; i++)
for (i = 0; i < MAXGROUPS; i++) {
priv->gfargrp[i].regs = NULL;
for (j = 0; j < GFAR_NUM_IRQS; j++)
priv->gfargrp[i].irqinfo[j] = NULL;
}
/* Parse and initialize group specific information */
if (priv->mode == MQ_MG_MODE) {

View File

@@ -714,6 +714,26 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx)
}
sc_xarray_element->rx_sc = rx_sc;
rx_sc->md_dst = metadata_dst_alloc(0, METADATA_MACSEC, GFP_KERNEL);
if (!rx_sc->md_dst) {
err = -ENOMEM;
goto destroy_sc_xarray_elemenet;
}
rx_sc->sci = ctx_rx_sc->sci;
rx_sc->active = ctx_rx_sc->active;
rx_sc->sc_xarray_element = sc_xarray_element;
rx_sc->md_dst->u.macsec_info.sci = rx_sc->sci;
/*
* Publish the fully-initialised SC last: xa_alloc() makes
* sc_xarray_element->rx_sc (and rx_sc->md_dst) reachable from the RX
* datapath via xa_load(). Doing it only after md_dst is allocated and
* initialised pairs with the rcu_read_lock()/xa_load() in
* mlx5e_macsec_offload_handle_rx_skb(), so a reader can never observe
* a non-NULL md_dst with uninitialised contents.
*/
err = xa_alloc(&macsec->sc_xarray, &sc_xarray_element->fs_id, sc_xarray_element,
XA_LIMIT(1, MLX5_MACEC_RX_FS_ID_MAX), GFP_KERNEL);
if (err) {
@@ -721,27 +741,16 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx)
netdev_err(ctx->netdev,
"MACsec offload: unable to create entry for RX SC (%d Rx SCs already allocated)\n",
MLX5_MACEC_RX_FS_ID_MAX);
goto destroy_sc_xarray_elemenet;
goto destroy_md_dst;
}
rx_sc->md_dst = metadata_dst_alloc(0, METADATA_MACSEC, GFP_KERNEL);
if (!rx_sc->md_dst) {
err = -ENOMEM;
goto erase_xa_alloc;
}
rx_sc->sci = ctx_rx_sc->sci;
rx_sc->active = ctx_rx_sc->active;
list_add_rcu(&rx_sc->rx_sc_list_element, rx_sc_list);
rx_sc->sc_xarray_element = sc_xarray_element;
rx_sc->md_dst->u.macsec_info.sci = rx_sc->sci;
mutex_unlock(&macsec->lock);
return 0;
erase_xa_alloc:
xa_erase(&macsec->sc_xarray, sc_xarray_element->fs_id);
destroy_md_dst:
dst_release(&rx_sc->md_dst->dst);
destroy_sc_xarray_elemenet:
kfree(sc_xarray_element);
destroy_rx_sc:
@@ -829,7 +838,7 @@ static void macsec_del_rxsc_ctx(struct mlx5e_macsec *macsec, struct mlx5e_macsec
*/
list_del_rcu(&rx_sc->rx_sc_list_element);
xa_erase(&macsec->sc_xarray, rx_sc->sc_xarray_element->fs_id);
metadata_dst_free(rx_sc->md_dst);
dst_release(&rx_sc->md_dst->dst);
kfree(rx_sc->sc_xarray_element);
kfree_rcu_mightsleep(rx_sc);
}
@@ -1695,10 +1704,10 @@ void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev,
rcu_read_lock();
sc_xarray_element = xa_load(&macsec->sc_xarray, fs_id);
rx_sc = sc_xarray_element->rx_sc;
if (rx_sc) {
dst_hold(&rx_sc->md_dst->dst);
skb_dst_set(skb, &rx_sc->md_dst->dst);
rx_sc = sc_xarray_element ? sc_xarray_element->rx_sc : NULL;
if (rx_sc && rx_sc->md_dst) {
if (dst_hold_safe(&rx_sc->md_dst->dst))
skb_dst_set(skb, &rx_sc->md_dst->dst);
}
rcu_read_unlock();

View File

@@ -205,6 +205,7 @@ static int hws_bwc_matcher_move(struct mlx5hws_bwc_matcher *bwc_matcher)
ret = mlx5hws_matcher_resize_set_target(old_matcher, new_matcher);
if (ret) {
mlx5hws_err(ctx, "Rehash error: failed setting resize target\n");
mlx5hws_matcher_destroy(new_matcher);
return ret;
}

View File

@@ -194,16 +194,18 @@ static bool fbnic_tx_tstamp(struct sk_buff *skb)
static bool
fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb,
struct skb_shared_info *shinfo, __le64 *meta,
unsigned int *l2len, unsigned int *i3len)
__le64 *meta, unsigned int *l2len, unsigned int *i3len)
{
unsigned int l3_type, l4_type, l4len, hdrlen;
struct skb_shared_info *shinfo;
unsigned char *l4hdr;
__be16 payload_len;
if (unlikely(skb_cow_head(skb, 0)))
return true;
shinfo = skb_shinfo(skb);
if (shinfo->gso_type & SKB_GSO_PARTIAL) {
l3_type = FBNIC_TWD_L3_TYPE_OTHER;
} else if (!skb->encapsulation) {
@@ -258,7 +260,6 @@ fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb,
static bool
fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
unsigned int l2len, i3len;
if (fbnic_tx_tstamp(skb))
@@ -273,8 +274,8 @@ fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
*meta |= cpu_to_le64(FIELD_PREP(FBNIC_TWD_CSUM_OFFSET_MASK,
skb->csum_offset / 2));
if (shinfo->gso_size) {
if (fbnic_tx_lso(ring, skb, shinfo, meta, &l2len, &i3len))
if (skb_is_gso(skb)) {
if (fbnic_tx_lso(ring, skb, meta, &l2len, &i3len))
return true;
} else {
*meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_CSO);

View File

@@ -3541,8 +3541,8 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
adapter->max_tx_channels = PCI11X1X_MAX_TX_CHANNELS;
adapter->used_tx_channels = PCI11X1X_USED_TX_CHANNELS;
adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT;
pci11x1x_strap_get_status(adapter);
spin_lock_init(&adapter->eth_syslock_spinlock);
pci11x1x_strap_get_status(adapter);
mutex_init(&adapter->sgmii_rw_lock);
pci11x1x_set_rfe_rd_fifo_threshold(adapter);
sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);

View File

@@ -961,7 +961,7 @@ static inline void qede_tpa_cont(struct qede_dev *edev,
{
int i;
for (i = 0; cqe->len_list[i] && i < ARRAY_SIZE(cqe->len_list); i++)
for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++)
qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
le16_to_cpu(cqe->len_list[i]));
@@ -986,7 +986,7 @@ static int qede_tpa_end(struct qede_dev *edev,
dma_unmap_page(rxq->dev, tpa_info->buffer.mapping,
PAGE_SIZE, rxq->data_direction);
for (i = 0; cqe->len_list[i] && i < ARRAY_SIZE(cqe->len_list); i++)
for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++)
qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
le16_to_cpu(cqe->len_list[i]));
if (unlikely(i > 1))

View File

@@ -1802,6 +1802,7 @@ static bool wx_set_vmdq_queues(struct wx *wx)
rss_i = 4;
}
} else {
vmdq_m = WX_VMDQ_1Q_MASK;
/* double check we are limited to maximum pools */
vmdq_i = min_t(u16, 8, vmdq_i);

View File

@@ -486,6 +486,7 @@ enum WX_MSCA_CMD_value {
#define WX_VMDQ_4Q_MASK 0x7C
#define WX_VMDQ_2Q_MASK 0x7E
#define WX_VMDQ_1Q_MASK 0x7F
/****************** Manageablility Host Interface defines ********************/
#define WX_HI_MAX_BLOCK_BYTE_LENGTH 256 /* Num of bytes in range */

View File

@@ -232,19 +232,27 @@ ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init)
&valid_bit);
if (IS_ERR(valid_state))
return PTR_ERR(valid_state);
if (valid_bit >= 32) /* BITS_PER_U32 */
return -EINVAL;
if (valid_bit >= 32) { /* BITS_PER_U32 */
ret = -EINVAL;
goto err_valid_state_put;
}
enabled_state = qcom_smem_state_get(dev, "ipa-clock-enabled",
&enabled_bit);
if (IS_ERR(enabled_state))
return PTR_ERR(enabled_state);
if (enabled_bit >= 32) /* BITS_PER_U32 */
return -EINVAL;
if (IS_ERR(enabled_state)) {
ret = PTR_ERR(enabled_state);
goto err_valid_state_put;
}
if (enabled_bit >= 32) { /* BITS_PER_U32 */
ret = -EINVAL;
goto err_enabled_state_put;
}
smp2p = kzalloc_obj(*smp2p);
if (!smp2p)
return -ENOMEM;
if (!smp2p) {
ret = -ENOMEM;
goto err_enabled_state_put;
}
smp2p->ipa = ipa;
@@ -289,6 +297,10 @@ ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init)
ipa->smp2p = NULL;
mutex_destroy(&smp2p->mutex);
kfree(smp2p);
err_enabled_state_put:
qcom_smem_state_put(enabled_state);
err_valid_state_put:
qcom_smem_state_put(valid_state);
return ret;
}
@@ -305,6 +317,8 @@ void ipa_smp2p_exit(struct ipa *ipa)
ipa_smp2p_power_release(ipa);
ipa->smp2p = NULL;
mutex_destroy(&smp2p->mutex);
qcom_smem_state_put(smp2p->enabled_state);
qcom_smem_state_put(smp2p->valid_state);
kfree(smp2p);
}

View File

@@ -419,50 +419,6 @@ static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int devad,
return 0;
}
static int i2c_mii_probe_rollball(struct i2c_adapter *i2c)
{
u8 data_buf[] = { ROLLBALL_DATA_ADDR, 0x01, 0x00, 0x00 };
u8 cmd_buf[] = { ROLLBALL_CMD_ADDR, ROLLBALL_CMD_READ };
u8 cmd_addr = ROLLBALL_CMD_ADDR;
struct i2c_msg msgs[2];
u8 result;
int ret;
int i;
msgs[0].addr = ROLLBALL_PHY_I2C_ADDR;
msgs[0].flags = 0;
msgs[0].len = sizeof(data_buf);
msgs[0].buf = data_buf;
msgs[1].addr = ROLLBALL_PHY_I2C_ADDR;
msgs[1].flags = 0;
msgs[1].len = sizeof(cmd_buf);
msgs[1].buf = cmd_buf;
ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
return -ENODEV;
msgs[0].addr = ROLLBALL_PHY_I2C_ADDR;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = &cmd_addr;
msgs[1].addr = ROLLBALL_PHY_I2C_ADDR;
msgs[1].flags = I2C_M_RD;
msgs[1].len = 1;
msgs[1].buf = &result;
for (i = 0; i < 10; i++) {
msleep(20);
ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
return -ENODEV;
if (result == ROLLBALL_CMD_DONE)
return 0;
}
return -ENODEV;
}
static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
{
struct i2c_msg msg;
@@ -482,11 +438,11 @@ static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
ret = i2c_transfer(i2c, &msg, 1);
if (ret < 0)
return -ENODEV;
if (ret != 1)
return ret;
else if (ret != 1)
return -EIO;
return i2c_mii_probe_rollball(i2c);
else
return 0;
}
static bool mdio_i2c_check_functionality(struct i2c_adapter *i2c,
@@ -531,10 +487,9 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
case MDIO_I2C_ROLLBALL:
ret = i2c_mii_init_rollball(i2c);
if (ret < 0) {
if (ret != -ENODEV)
dev_err(parent,
"Cannot initialize RollBall MDIO I2C protocol: %d\n",
ret);
dev_err(parent,
"Cannot initialize RollBall MDIO I2C protocol: %d\n",
ret);
mdiobus_free(mii);
return ERR_PTR(ret);
}

View File

@@ -252,6 +252,7 @@ void nsim_ethtool_init(struct netdevsim *ns)
ns->ethtool.channels = ns->nsim_bus_dev->num_queues;
ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir);
ns->ethtool_ddir = ethtool;
debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err);
debugfs_create_u32("set_err", 0600, ethtool, &ns->ethtool.set_err);
@@ -272,3 +273,8 @@ void nsim_ethtool_init(struct netdevsim *ns)
debugfs_create_u32("tx_max_pending", 0600, dir,
&ns->ethtool.ring.tx_max_pending);
}
void nsim_ethtool_fini(struct netdevsim *ns)
{
debugfs_remove(ns->ethtool_ddir);
}

View File

@@ -1165,6 +1165,7 @@ struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,
return ns;
err_free_netdev:
nsim_ethtool_fini(ns);
free_netdev(dev);
return ERR_PTR(err);
}
@@ -1178,6 +1179,7 @@ void nsim_destroy(struct netdevsim *ns)
debugfs_remove(ns->vlan_dfs);
debugfs_remove(ns->qr_dfs);
debugfs_remove(ns->pp_dfs);
nsim_ethtool_fini(ns);
if (ns->nb.notifier_call)
unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb,

View File

@@ -154,6 +154,7 @@ struct netdevsim {
struct dentry *pp_dfs;
struct dentry *qr_dfs;
struct dentry *vlan_dfs;
struct dentry *ethtool_ddir;
struct nsim_ethtool ethtool;
struct netdevsim __rcu *peer;
@@ -169,6 +170,7 @@ void nsim_destroy(struct netdevsim *ns);
bool netdev_is_nsim(struct net_device *dev);
void nsim_ethtool_init(struct netdevsim *ns);
void nsim_ethtool_fini(struct netdevsim *ns);
void nsim_udp_tunnels_debugfs_create(struct nsim_dev *nsim_dev);
int nsim_udp_tunnels_info_create(struct nsim_dev *nsim_dev,

View File

@@ -597,7 +597,6 @@ static const struct sfp_quirk sfp_quirks[] = {
// OEM SFP-GE-T is a 1000Base-T module with broken TX_FAULT indicator
SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault),
SFP_QUIRK_F("OEM", "SFP-10G-T-I", sfp_fixup_rollball),
SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc),
SFP_QUIRK_S("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
SFP_QUIRK_S("OEM", "SFP-2.5G-BX10-D", sfp_quirk_2500basex),
@@ -963,6 +962,7 @@ static int sfp_i2c_mdiobus_create(struct sfp *sfp)
static void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
{
mdiobus_unregister(sfp->i2c_mii);
mdiobus_free(sfp->i2c_mii);
sfp->i2c_mii = NULL;
}
@@ -2173,17 +2173,10 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
static int sfp_sm_add_mdio_bus(struct sfp *sfp)
{
int ret;
if (sfp->mdio_protocol != MDIO_I2C_NONE)
return sfp_i2c_mdiobus_create(sfp);
if (sfp->mdio_protocol == MDIO_I2C_NONE)
return 0;
ret = sfp_i2c_mdiobus_create(sfp);
if (ret == -ENODEV) {
sfp->mdio_protocol = MDIO_I2C_NONE;
return 0;
}
return ret;
return 0;
}
/* Probe a SFP for a PHY device if the module supports copper - the PHY

View File

@@ -1367,7 +1367,7 @@ static void __pse_control_release(struct kref *kref)
if (psec->pcdev->pi[psec->id].admin_state_enabled)
regulator_disable(psec->ps);
devm_regulator_put(psec->ps);
regulator_put(psec->ps);
module_put(psec->pcdev->owner);
@@ -1436,8 +1436,8 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index,
goto free_psec;
pcdev->pi[index].admin_state_enabled = ret;
psec->ps = devm_regulator_get_exclusive(pcdev->dev,
rdev_get_name(pcdev->pi[index].rdev));
psec->ps = regulator_get_exclusive(pcdev->dev,
rdev_get_name(pcdev->pi[index].rdev));
if (IS_ERR(psec->ps)) {
ret = PTR_ERR(psec->ps);
goto put_module;

View File

@@ -104,6 +104,9 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
return 0;
}
if (!skb_pull(skb, size + 4))
return 0;
// allocate the skb for the individual packet
gl_skb = alloc_skb(size, GFP_ATOMIC);
if (gl_skb) {
@@ -116,9 +119,6 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
// advance to the next packet
packet = (struct gl_packet *)&packet->packet_data[size];
count--;
// shift the data pointer to the next gl_packet
skb_pull(skb, size + 4);
}
// skip the packet length field 4 bytes

View File

@@ -3011,6 +3011,9 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
unsigned int xdp_xmit = 0;
bool napi_complete;
if (budget)
virtqueue_disable_cb(rq->vq);
virtnet_poll_cleantx(rq, budget);
received = virtnet_receive(rq, budget, &xdp_xmit);

View File

@@ -553,19 +553,21 @@ static int mux_dl_process_dg(struct iosm_mux *ipc_mux, struct mux_adbh *adbh,
u32 packet_offset, i, rc, dg_len;
for (i = 0; i < nr_of_dg; i++, dg++) {
if (le32_to_cpu(dg->datagram_index)
< sizeof(struct mux_adbh))
u32 dg_index = le32_to_cpu(dg->datagram_index);
dg_len = le16_to_cpu(dg->datagram_length);
if (dg_index < sizeof(struct mux_adbh))
goto dg_error;
/* Is the packet inside of the ADB */
if (le32_to_cpu(dg->datagram_index) >=
le32_to_cpu(adbh->block_length)) {
/* Is the packet inside of the ADB and the received skb ? */
if (dg_index >= le32_to_cpu(adbh->block_length) ||
dg_index >= skb->len ||
dg_len > skb->len - dg_index ||
dl_head_pad_len >= dg_len) {
goto dg_error;
} else {
packet_offset =
le32_to_cpu(dg->datagram_index) +
dl_head_pad_len;
dg_len = le16_to_cpu(dg->datagram_length);
packet_offset = dg_index + dl_head_pad_len;
/* Pass the packet to the netif layer. */
rc = ipc_mux_net_receive(ipc_mux, if_id, ipc_mux->wwan,
packet_offset,
@@ -589,12 +591,16 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
struct mux_adbh *adbh;
struct mux_adth *adth;
int nr_of_dg, if_id;
u32 adth_index;
u32 adth_index, prev_index = 0;
u8 *block;
block = skb->data;
adbh = (struct mux_adbh *)block;
/* The block header itself must fit in the received skb. */
if (skb->len < sizeof(struct mux_adbh))
goto adb_decode_err;
/* Process the aggregated datagram tables. */
adth_index = le32_to_cpu(adbh->first_table_index);
@@ -606,6 +612,16 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
/* Loop through mixed session tables. */
while (adth_index) {
/* The table header must lie within the received skb, and the
* chain must move forward so a modem cannot make the loop
* cycle between two tables.
*/
if (adth_index <= prev_index ||
adth_index < sizeof(struct mux_adbh) ||
adth_index > skb->len - sizeof(struct mux_adth))
goto adb_decode_err;
prev_index = adth_index;
/* Get the reference to the table header. */
adth = (struct mux_adth *)(block + adth_index);
@@ -629,6 +645,10 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
if (le16_to_cpu(adth->table_length) < sizeof(struct mux_adth))
goto adb_decode_err;
/* The whole datagram table must fit in the received skb. */
if (le16_to_cpu(adth->table_length) > skb->len - adth_index)
goto adb_decode_err;
/* Calculate the number of datagrams. */
nr_of_dg = (le16_to_cpu(adth->table_length) -
sizeof(struct mux_adth)) /

View File

@@ -145,6 +145,7 @@ struct tcp_ao_info {
u32 snd_sne;
u32 rcv_sne;
refcount_t refcnt; /* Protects twsk destruction */
struct rcu_head rcu;
};
#ifdef CONFIG_TCP_MD5SIG

View File

@@ -1066,6 +1066,9 @@ static u16 batadv_arp_get_type(struct batadv_priv *bat_priv,
* @skb: the buffer containing the packet to extract the VID from
* @hdr_size: the size of the batman-adv header encapsulating the packet
*
* The caller must ensure that at least @hdr_size + ETH_HLEN bytes are
* accessible after skb->data.
*
* Return: If the packet embedded in the skb is vlan tagged this function
* returns the VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS
* is returned.
@@ -1148,6 +1151,10 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
if (!READ_ONCE(bat_priv->distributed_arp_table))
goto out;
/* first, find out the vid. */
if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
goto out;
vid = batadv_dat_get_vid(skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, skb, hdr_size);
@@ -1243,6 +1250,10 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
if (!READ_ONCE(bat_priv->distributed_arp_table))
goto out;
/* first, find out the vid. */
if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
goto out;
vid = batadv_dat_get_vid(skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, skb, hdr_size);
@@ -1305,6 +1316,10 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
if (!READ_ONCE(bat_priv->distributed_arp_table))
return;
/* first, find out the vid. */
if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
return;
vid = batadv_dat_get_vid(skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, skb, hdr_size);
@@ -1353,6 +1368,10 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
if (!READ_ONCE(bat_priv->distributed_arp_table))
goto out;
/* first, find out the vid. */
if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
goto out;
vid = batadv_dat_get_vid(skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, skb, hdr_size);
@@ -1747,6 +1766,7 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv,
struct ethhdr *ethhdr;
__be32 ip_src, yiaddr;
unsigned short vid;
int hdr_size_tmp;
__be16 proto;
u8 *hw_src;
@@ -1763,8 +1783,10 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv,
if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr))
return;
hdr_size_tmp = hdr_size;
vid = batadv_dat_get_vid(skb, &hdr_size_tmp);
ethhdr = (struct ethhdr *)(skb->data + hdr_size);
hw_src = ethhdr->h_source;
vid = batadv_dat_get_vid(skb, &hdr_size);
batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid);
batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
@@ -1804,6 +1826,10 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
if (batadv_forw_packet_is_rebroadcast(forw_packet))
goto out;
/* first, find out the vid. */
if (!pskb_may_pull(forw_packet->skb, hdr_size + ETH_HLEN))
goto out;
vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size);

View File

@@ -684,12 +684,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct batadv_gw_node *gw_node = NULL;
struct batadv_gw_node *curr_gw = NULL;
struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo;
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct ethhdr *ethhdr;
bool out_of_range = false;
u8 curr_tq_avg;
unsigned short vid;
vid = batadv_get_vid(skb, 0);
ethhdr = (struct ethhdr *)skb->data;
if (is_multicast_ether_addr(ethhdr->h_dest))
goto out;

View File

@@ -580,6 +580,9 @@ void batadv_recv_handler_unregister(u8 packet_type)
* @skb: the buffer containing the packet
* @header_len: length of the batman header preceding the ethernet header
*
* The caller must ensure that at least @header_len + ETH_HLEN bytes are
* accessible after skb->data.
*
* Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the
* skb is vlan tagged. Otherwise BATADV_NO_FLAGS.
*/

View File

@@ -434,6 +434,7 @@ void batadv_interface_rx(struct net_device *mesh_iface,
if (!pskb_may_pull(skb, VLAN_ETH_HLEN))
goto dropped;
ethhdr = eth_hdr(skb);
vhdr = skb_vlan_eth_hdr(skb);
/* drop batman-in-batman packets to prevent loops */

View File

@@ -855,8 +855,8 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
if (skb_cow(skb, sizeof(*unicast_packet)) < 0)
return false;
unicast_packet = (struct batadv_unicast_packet *)skb->data;
vid = batadv_get_vid(skb, hdr_len);
unicast_packet = (struct batadv_unicast_packet *)skb->data;
ethhdr = (struct ethhdr *)(skb->data + hdr_len);
/* do not reroute multicast frames in a unicast header */
@@ -1029,6 +1029,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
hdr_size);
batadv_orig_node_put(orig_node_gw);
if (is_gw) {
orig_addr_gw = eth_hdr(skb)->h_source;
batadv_dbg(BATADV_DBG_BLA, bat_priv,
"%s(): Dropped unicast pkt received from another backbone gw %pM.\n",
__func__, orig_addr_gw);

View File

@@ -392,6 +392,9 @@ void br_dev_delete(struct net_device *dev, struct list_head *head)
br_fdb_delete_by_port(br, NULL, 0, 1);
timer_shutdown_sync(&br->hello_timer);
timer_shutdown_sync(&br->topology_change_timer);
timer_shutdown_sync(&br->tcn_timer);
cancel_delayed_work_sync(&br->gc_work);
br_sysfs_delbr(br->dev);

View File

@@ -382,7 +382,8 @@ void br_topology_change_detection(struct net_bridge *br)
{
int isroot = br_is_root_bridge(br);
if (br->stp_enabled != BR_KERNEL_STP)
if (br->stp_enabled != BR_KERNEL_STP ||
!(br->dev->flags & IFF_UP))
return;
br_info(br, "topology change detected, %s\n",

View File

@@ -633,14 +633,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
container_of(rcu_head, struct netpoll_info, rcu);
skb_queue_purge(&npinfo->txq);
/* we can't call cancel_delayed_work_sync here, as we are in softirq */
cancel_delayed_work(&npinfo->tx_work);
/* clean after last, unfinished work */
__skb_queue_purge(&npinfo->txq);
/* now cancel it again */
cancel_delayed_work(&npinfo->tx_work);
kfree(npinfo);
}
@@ -664,6 +656,7 @@ static void __netpoll_cleanup(struct netpoll *np)
ops->ndo_netpoll_cleanup(np->dev);
RCU_INIT_POINTER(np->dev->npinfo, NULL);
disable_delayed_work_sync(&npinfo->tx_work);
call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
}

View File

@@ -79,15 +79,16 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
if (likely(skb->dev)) {
dsa_default_offload_fwd_mark(skb);
nskb = skb;
} else {
/* Just drop the skb if we can't find the user */
kfree_skb(skb);
}
} else {
nskb = cpu_dp->rcv(skb, dev);
}
if (!nskb) {
kfree_skb(skb);
if (!nskb)
return 0;
}
skb = nskb;
skb_push(skb, ETH_HLEN);
@@ -107,11 +108,10 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
if (unlikely(cpu_dp->ds->untag_bridge_pvid ||
cpu_dp->ds->untag_vlan_aware_bridge_pvid)) {
/* dsa_software_vlan_untag() drops skb on failure */
nskb = dsa_software_vlan_untag(skb);
if (!nskb) {
kfree_skb(skb);
if (!nskb)
return 0;
}
skb = nskb;
}

View File

@@ -51,8 +51,10 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
u8 ver, port;
u16 hdr;
if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN)))
if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN))) {
kfree_skb(skb);
return NULL;
}
hdr = le16_to_cpu(*(__le16 *)skb_mac_header(skb));
@@ -60,12 +62,14 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
if (unlikely(ver != AR9331_HDR_VERSION)) {
netdev_warn_once(ndev, "%s:%i wrong header version 0x%2x\n",
__func__, __LINE__, hdr);
kfree_skb(skb);
return NULL;
}
if (unlikely(hdr & AR9331_HDR_FROM_CPU)) {
netdev_warn_once(ndev, "%s:%i packet should not be from cpu 0x%2x\n",
__func__, __LINE__, hdr);
kfree_skb(skb);
return NULL;
}
@@ -75,8 +79,10 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
port = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr);
skb->dev = dsa_conduit_find_user(ndev, 0, port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
return skb;
}

View File

@@ -102,9 +102,9 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
* (including FCS and tag) because the length verification is done after
* the Broadcom tag is stripped off the ingress packet.
*
* Let dsa_user_xmit() free the SKB
* Free the SKB on error.
*/
if (__skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN, false))
if (skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN))
return NULL;
skb_push(skb, BRCM_TAG_LEN);
@@ -151,27 +151,35 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
int source_port;
u8 *brcm_tag;
if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN))) {
kfree_skb(skb);
return NULL;
}
brcm_tag = skb->data - offset;
/* The opcode should never be different than 0b000 */
if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK)) {
kfree_skb(skb);
return NULL;
}
/* We should never see a reserved reason code without knowing how to
* handle it
*/
if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD))
if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD)) {
kfree_skb(skb);
return NULL;
}
/* Locate which port this is coming from */
source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
/* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN);
@@ -228,8 +236,10 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
__be16 *proto;
u8 *brcm_tag;
if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN)))
if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN))) {
kfree_skb(skb);
return NULL;
}
brcm_tag = dsa_etype_header_pos_rx(skb);
proto = (__be16 *)(brcm_tag + BRCM_LEG_TAG_LEN);
@@ -237,8 +247,10 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
/* The internal switch in BCM63XX SoCs always tags on egress on the CPU
* port. We use VID 0 internally for untagged traffic, so strip the tag
@@ -273,10 +285,8 @@ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
* need to make sure that packets are at least 70 bytes
* (including FCS and tag) because the length verification is done after
* the Broadcom tag is stripped off the ingress packet.
*
* Let dsa_user_xmit() free the SKB
*/
if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
if (skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN))
return NULL;
skb_push(skb, BRCM_LEG_TAG_LEN);
@@ -325,10 +335,8 @@ static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
* need to make sure that packets are at least 70 bytes (including FCS
* and tag) because the length verification is done after the Broadcom
* tag is stripped off the ingress packet.
*
* Let dsa_user_xmit() free the SKB.
*/
if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
if (skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN))
return NULL;
fcs_len = skb->len;
@@ -351,8 +359,9 @@ static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
/* Original FCS value */
if (__skb_pad(skb, ETH_FCS_LEN, false))
if (skb_pad(skb, ETH_FCS_LEN))
return NULL;
skb_put_data(skb, &fcs_val, ETH_FCS_LEN);
return skb;

View File

@@ -224,6 +224,7 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
/* Remote management is not implemented yet,
* drop.
*/
kfree_skb(skb);
return NULL;
case DSA_CODE_ARP_MIRROR:
case DSA_CODE_POLICY_MIRROR:
@@ -244,12 +245,14 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
/* Reserved code, this could be anything. Drop
* seems like the safest option.
*/
kfree_skb(skb);
return NULL;
}
break;
default:
kfree_skb(skb);
return NULL;
}
@@ -271,8 +274,10 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
source_port);
}
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
/* When using LAG offload, skb->dev is not a DSA user interface,
* so we cannot call dsa_default_offload_fwd_mark and we need to
@@ -335,8 +340,10 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev)
{
if (unlikely(!pskb_may_pull(skb, DSA_HLEN)))
if (unlikely(!pskb_may_pull(skb, DSA_HLEN))) {
kfree_skb(skb);
return NULL;
}
return dsa_rcv_ll(skb, dev, 0);
}
@@ -375,8 +382,10 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev)
{
if (unlikely(!pskb_may_pull(skb, EDSA_HLEN)))
if (unlikely(!pskb_may_pull(skb, EDSA_HLEN))) {
kfree_skb(skb);
return NULL;
}
skb_pull_rcsum(skb, EDSA_HLEN - DSA_HLEN);

View File

@@ -80,16 +80,20 @@ static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb,
int port;
u8 *gswip_tag;
if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN)))
if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) {
kfree_skb(skb);
return NULL;
}
gswip_tag = skb->data - ETH_HLEN;
/* Get source port information */
port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT;
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
/* remove GSWIP tag */
skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN);

View File

@@ -27,8 +27,10 @@ static struct sk_buff *hellcreek_xmit(struct sk_buff *skb,
* checksums after the switch strips the tag.
*/
if (skb->ip_summed == CHECKSUM_PARTIAL &&
skb_checksum_help(skb))
skb_checksum_help(skb)) {
kfree_skb(skb);
return NULL;
}
/* Tag encoding */
tag = skb_put(skb, HELLCREEK_TAG_LEN);
@@ -47,11 +49,14 @@ static struct sk_buff *hellcreek_rcv(struct sk_buff *skb,
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev) {
netdev_warn_once(dev, "Failed to get source port: %d\n", port);
kfree_skb(skb);
return NULL;
}
if (pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN))
if (pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN)) {
kfree_skb(skb);
return NULL;
}
dsa_default_offload_fwd_mark(skb);

View File

@@ -88,11 +88,15 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb,
unsigned int port, unsigned int len)
{
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
if (pskb_trim_rcsum(skb, skb->len - len))
if (pskb_trim_rcsum(skb, skb->len - len)) {
kfree_skb(skb);
return NULL;
}
dsa_default_offload_fwd_mark(skb);
@@ -123,8 +127,10 @@ static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev)
struct ethhdr *hdr;
u8 *tag;
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
kfree_skb(skb);
return NULL;
}
/* Tag encoding */
tag = skb_put(skb, KSZ_INGRESS_TAG_LEN);
@@ -141,8 +147,10 @@ static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev)
{
u8 *tag;
if (skb_linearize(skb))
if (skb_linearize(skb)) {
kfree_skb(skb);
return NULL;
}
tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
@@ -255,22 +263,24 @@ static struct sk_buff *ksz_defer_xmit(struct dsa_port *dp, struct sk_buff *skb)
xmit_work_fn = tagger_data->xmit_work_fn;
xmit_worker = priv->xmit_worker;
if (!xmit_work_fn || !xmit_worker)
if (!xmit_work_fn || !xmit_worker) {
kfree_skb(skb);
return NULL;
}
xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC);
if (!xmit_work)
if (!xmit_work) {
kfree_skb(skb);
return NULL;
}
kthread_init_work(&xmit_work->work, xmit_work_fn);
/* Increase refcount so the kfree_skb in dsa_user_xmit
* won't really free the packet.
*/
xmit_work->dp = dp;
xmit_work->skb = skb_get(skb);
kthread_queue_work(xmit_worker, &xmit_work->work);
kfree_skb(skb);
return NULL;
}
@@ -284,8 +294,10 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
__be16 *tag;
u16 val;
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
kfree_skb(skb);
return NULL;
}
/* Tag encoding */
ksz_xmit_timestamp(dp, skb);
@@ -310,8 +322,10 @@ static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev)
unsigned int port;
u8 *tag;
if (skb_linearize(skb))
if (skb_linearize(skb)) {
kfree_skb(skb);
return NULL;
}
/* Tag decoding */
tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
@@ -352,8 +366,10 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb,
struct ethhdr *hdr;
u8 *tag;
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
kfree_skb(skb);
return NULL;
}
/* Tag encoding */
ksz_xmit_timestamp(dp, skb);
@@ -418,8 +434,10 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb,
__be16 *tag;
u16 val;
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
kfree_skb(skb);
return NULL;
}
ksz_xmit_timestamp(dp, skb);

View File

@@ -85,6 +85,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!pskb_may_pull(skb, LAN9303_TAG_LEN))) {
dev_warn_ratelimited(&dev->dev,
"Dropping packet, cannot pull\n");
kfree_skb(skb);
return NULL;
}
@@ -102,6 +103,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
if (!skb->dev) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n");
kfree_skb(skb);
return NULL;
}

View File

@@ -72,8 +72,10 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
int port;
__be16 *phdr;
if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) {
kfree_skb(skb);
return NULL;
}
phdr = dsa_etype_header_pos_rx(skb);
hdr = ntohs(*phdr);
@@ -87,8 +89,10 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
dsa_default_offload_fwd_mark(skb);

View File

@@ -73,6 +73,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, GSW1XX_HEADER_LEN))) {
dev_warn_ratelimited(&dev->dev, "Dropping packet, cannot pull SKB\n");
kfree_skb(skb);
return NULL;
}
@@ -81,6 +82,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb,
if (unlikely(ntohs(gsw1xx_tag[0]) != ETH_P_MXLGSW)) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid special tag\n");
dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag);
kfree_skb(skb);
return NULL;
}
@@ -90,6 +92,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb,
if (!skb->dev) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n");
dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag);
kfree_skb(skb);
return NULL;
}

View File

@@ -64,6 +64,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, MXL862_HEADER_LEN))) {
dev_warn_ratelimited(&dev->dev, "Cannot pull SKB, packet dropped\n");
kfree_skb(skb);
return NULL;
}
@@ -73,6 +74,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
dev_warn_ratelimited(&dev->dev,
"Invalid special tag marker, packet dropped, tag: %8ph\n",
mxl862_tag);
kfree_skb(skb);
return NULL;
}
@@ -83,6 +85,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
dev_warn_ratelimited(&dev->dev,
"Invalid source port, packet dropped, tag: %8ph\n",
mxl862_tag);
kfree_skb(skb);
return NULL;
}

View File

@@ -131,14 +131,13 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
int type, subtype;
if (unlikely(!pskb_may_pull(skb, NETC_TAG_MAX_LEN)))
return NULL;
goto err_free_skb;
tag_cmn = dsa_etype_header_pos_rx(skb);
if (ntohs(tag_cmn->tpid) != ETH_P_NXP_NETC) {
dev_warn_ratelimited(&ndev->dev, "Unknown TPID 0x%04x\n",
ntohs(tag_cmn->tpid));
return NULL;
goto err_free_skb;
}
if (tag_cmn->qos & NETC_TAG_QV)
@@ -149,14 +148,13 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
if (!sw_id) {
dev_warn_ratelimited(&ndev->dev,
"VEPA switch ID is not supported yet\n");
return NULL;
goto err_free_skb;
}
port = FIELD_GET(NETC_TAG_PORT, tag_cmn->switch_port);
skb->dev = dsa_conduit_find_user(ndev, sw_id, port);
if (!skb->dev)
return NULL;
goto err_free_skb;
type = FIELD_GET(NETC_TAG_TYPE, tag_cmn->type);
subtype = FIELD_GET(NETC_TAG_SUBTYPE, tag_cmn->type);
@@ -165,11 +163,11 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
} else if (type == NETC_TAG_TO_HOST) {
/* Currently only subtype0 supported */
if (subtype != NETC_TAG_TH_SUBTYPE0)
return NULL;
goto err_free_skb;
} else {
dev_warn_ratelimited(&ndev->dev,
"Unexpected tag type %d\n", type);
return NULL;
goto err_free_skb;
}
/* Remove Switch tag from the frame */
@@ -178,6 +176,10 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
dsa_strip_etype_header(skb, tag_len);
return skb;
err_free_skb:
kfree_skb(skb);
return NULL;
}
static void netc_flow_dissect(const struct sk_buff *skb, __be16 *proto,

View File

@@ -107,14 +107,16 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
ocelot_xfh_get_rew_val(extraction, &rew_val);
skb->dev = dsa_conduit_find_user(netdev, 0, src_port);
if (!skb->dev)
if (!skb->dev) {
/* The switch will reflect back some frames sent through
* sockets opened on the bare DSA conduit. These will come back
* with src_port equal to the index of the CPU port, for which
* there is no user registered. So don't print any error
* message here (ignore and drop those frames).
*/
kfree_skb(skb);
return NULL;
}
dsa_default_offload_fwd_mark(skb);
skb->priority = qos_class;

View File

@@ -33,30 +33,34 @@ static struct sk_buff *ocelot_defer_xmit(struct dsa_port *dp,
xmit_work_fn = data->xmit_work_fn;
xmit_worker = priv->xmit_worker;
if (!xmit_work_fn || !xmit_worker)
if (!xmit_work_fn || !xmit_worker) {
kfree_skb(skb);
return NULL;
}
/* PTP over IP packets need UDP checksumming. We may have inherited
* NETIF_F_HW_CSUM from the DSA conduit, but these packets are not sent
* through the DSA conduit, so calculate the checksum here.
*/
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
kfree_skb(skb);
return NULL;
}
xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC);
if (!xmit_work)
if (!xmit_work) {
kfree_skb(skb);
return NULL;
}
/* Calls felix_port_deferred_xmit in felix.c */
kthread_init_work(&xmit_work->work, xmit_work_fn);
/* Increase refcount so the kfree_skb in dsa_user_xmit
* won't really free the packet.
*/
xmit_work->dp = dp;
xmit_work->skb = skb_get(skb);
kthread_queue_work(xmit_worker, &xmit_work->work);
kfree_skb(skb);
return NULL;
}
@@ -84,8 +88,10 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
dsa_8021q_rcv(skb, &src_port, &switch_id, NULL, NULL);
skb->dev = dsa_conduit_find_user(netdev, switch_id, src_port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
dsa_default_offload_fwd_mark(skb);

View File

@@ -46,16 +46,20 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
tagger_data = ds->tagger_data;
if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) {
kfree_skb(skb);
return NULL;
}
phdr = dsa_etype_header_pos_rx(skb);
hdr = ntohs(*phdr);
/* Make sure the version is correct */
ver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr);
if (unlikely(ver != QCA_HDR_VERSION))
if (unlikely(ver != QCA_HDR_VERSION)) {
kfree_skb(skb);
return NULL;
}
/* Get pk type */
pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr);
@@ -64,6 +68,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) {
if (likely(tagger_data->rw_reg_ack_handler))
tagger_data->rw_reg_ack_handler(ds, skb);
kfree_skb(skb);
return NULL;
}
@@ -71,6 +76,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (pk_type == QCA_HDR_RECV_TYPE_MIB) {
if (likely(tagger_data->mib_autocast_handler))
tagger_data->mib_autocast_handler(ds, skb);
kfree_skb(skb);
return NULL;
}
@@ -78,8 +84,10 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr);
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
/* Remove QCA tag and recalculate checksum */
skb_pull_rcsum(skb, QCA_HDR_LEN);

View File

@@ -41,7 +41,7 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
u16 out;
/* Pad out to at least 60 bytes */
if (unlikely(__skb_put_padto(skb, ETH_ZLEN, false)))
if (unlikely(eth_skb_pad(skb)))
return NULL;
netdev_dbg(dev, "add realtek tag to package to port %d\n",
@@ -75,8 +75,10 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
u8 prot;
u8 port;
if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN)))
if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN))) {
kfree_skb(skb);
return NULL;
}
tag = dsa_etype_header_pos_rx(skb);
p = (__be16 *)tag;
@@ -92,6 +94,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
prot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f;
if (prot != RTL4_A_PROTOCOL_RTL8366RB) {
netdev_err(dev, "unknown realtek protocol 0x%01x\n", prot);
kfree_skb(skb);
return NULL;
}
port = protport & 0xff;
@@ -99,6 +102,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev) {
netdev_dbg(dev, "could not find user for port %d\n", port);
kfree_skb(skb);
return NULL;
}

View File

@@ -143,8 +143,10 @@ static struct sk_buff *rtl8_4t_tag_xmit(struct sk_buff *skb,
/* Calculate the checksum here if not done yet as trailing tags will
* break either software or hardware based checksum
*/
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
kfree_skb(skb);
return NULL;
}
rtl8_4_write_tag(skb, dev, skb_put(skb, RTL8_4_TAG_LEN));
@@ -201,11 +203,15 @@ static int rtl8_4_read_tag(struct sk_buff *skb, struct net_device *dev,
static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb,
struct net_device *dev)
{
if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN)))
if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN))) {
kfree_skb(skb);
return NULL;
}
if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb))))
if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb)))) {
kfree_skb(skb);
return NULL;
}
/* Remove tag and recalculate checksum */
skb_pull_rcsum(skb, RTL8_4_TAG_LEN);
@@ -218,14 +224,20 @@ static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb,
static struct sk_buff *rtl8_4t_tag_rcv(struct sk_buff *skb,
struct net_device *dev)
{
if (skb_linearize(skb))
if (skb_linearize(skb)) {
kfree_skb(skb);
return NULL;
}
if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN)))
if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN))) {
kfree_skb(skb);
return NULL;
}
if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN))
if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN)) {
kfree_skb(skb);
return NULL;
}
return skb;
}

View File

@@ -48,7 +48,7 @@ static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *de
* least 60 bytes otherwise they will be discarded when they enter the
* switch port logic.
*/
if (__skb_put_padto(skb, ETH_ZLEN, false))
if (eth_skb_pad(skb))
return NULL;
/* provide 'A5PSW_TAG_LEN' bytes additional space */
@@ -77,6 +77,7 @@ static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, A5PSW_TAG_LEN))) {
dev_warn_ratelimited(&dev->dev,
"Dropping packet, cannot pull\n");
kfree_skb(skb);
return NULL;
}
@@ -84,14 +85,17 @@ static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb,
if (tag->ctrl_tag != htons(ETH_P_DSA_A5PSW)) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid TAG marker\n");
kfree_skb(skb);
return NULL;
}
port = FIELD_GET(A5PSW_CTRL_DATA_PORT, ntohs(tag->ctrl_data));
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
skb_pull_rcsum(skb, A5PSW_TAG_LEN);
dsa_strip_etype_header(skb, A5PSW_TAG_LEN);

View File

@@ -149,19 +149,20 @@ static struct sk_buff *sja1105_defer_xmit(struct dsa_port *dp,
xmit_work_fn = tagger_data->xmit_work_fn;
xmit_worker = priv->xmit_worker;
if (!xmit_work_fn || !xmit_worker)
if (!xmit_work_fn || !xmit_worker) {
kfree_skb(skb);
return NULL;
}
xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC);
if (!xmit_work)
if (!xmit_work) {
kfree_skb(skb);
return NULL;
}
kthread_init_work(&xmit_work->work, xmit_work_fn);
/* Increase refcount so the kfree_skb in dsa_user_xmit
* won't really free the packet.
*/
xmit_work->dp = dp;
xmit_work->skb = skb_get(skb);
xmit_work->skb = skb;
kthread_queue_work(xmit_worker, &xmit_work->work);
@@ -401,10 +402,7 @@ static struct sk_buff
kfree_skb(priv->stampable_skb);
}
/* Hold a reference to avoid dsa_switch_rcv
* from freeing the skb.
*/
priv->stampable_skb = skb_get(skb);
priv->stampable_skb = skb;
spin_unlock(&priv->meta_lock);
/* Tell DSA we got nothing */
@@ -436,6 +434,7 @@ static struct sk_buff
dev_err_ratelimited(ds->dev,
"Unexpected meta frame\n");
spin_unlock(&priv->meta_lock);
kfree_skb(skb);
return NULL;
}
@@ -443,6 +442,7 @@ static struct sk_buff
dev_err_ratelimited(ds->dev,
"Meta frame on wrong port\n");
spin_unlock(&priv->meta_lock);
kfree_skb(skb);
return NULL;
}
@@ -501,18 +501,21 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
/* Normal data plane traffic and link-local frames are tagged with
* a tag_8021q VLAN which we have to strip
*/
if (sja1105_skb_has_tag_8021q(skb))
if (sja1105_skb_has_tag_8021q(skb)) {
dsa_8021q_rcv(skb, &source_port, &switch_id, &vbid, &vid);
else if (source_port == -1 && switch_id == -1)
} else if (source_port == -1 && switch_id == -1) {
/* Packets with no source information have no chance of
* getting accepted, drop them straight away.
*/
kfree_skb(skb);
return NULL;
}
skb->dev = dsa_tag_8021q_find_user(netdev, source_port, switch_id,
vid, vbid);
if (!skb->dev) {
netdev_warn(netdev, "Couldn't decode source port\n");
kfree_skb(skb);
return NULL;
}
@@ -539,12 +542,15 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header)
if (!ds) {
net_err_ratelimited("%s: cannot find switch id %d\n",
conduit->name, switch_id);
kfree_skb(skb);
return NULL;
}
tagger_data = sja1105_tagger_data(ds);
if (!tagger_data->meta_tstamp_handler)
if (!tagger_data->meta_tstamp_handler) {
kfree_skb(skb);
return NULL;
}
for (i = 0; i <= n_ts; i++) {
u8 ts_id, source_port, dir;
@@ -562,6 +568,7 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header)
}
/* Discard the meta frame, we've consumed the timestamps it contained */
kfree_skb(skb);
return NULL;
}
@@ -572,8 +579,10 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
{
u16 rx_header;
if (unlikely(!pskb_may_pull(skb, SJA1110_HEADER_LEN)))
if (unlikely(!pskb_may_pull(skb, SJA1110_HEADER_LEN))) {
kfree_skb(skb);
return NULL;
}
/* skb->data points to skb_mac_header(skb) + ETH_HLEN, which is exactly
* what we need because the caller has checked the EtherType (which is
@@ -609,8 +618,10 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
* padding and trailer we need to account for the fact that
* skb->data points to skb_mac_header(skb) + ETH_HLEN.
*/
if (pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN))
if (pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN)) {
kfree_skb(skb);
return NULL;
}
/* Trap-to-host frame, no timestamp trailer */
} else {
*source_port = SJA1110_RX_HEADER_SRC_PORT(rx_header);
@@ -653,6 +664,7 @@ static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
if (!skb->dev) {
netdev_warn(netdev, "Couldn't decode source port\n");
kfree_skb(skb);
return NULL;
}

View File

@@ -30,22 +30,30 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev)
u8 *trailer;
int source_port;
if (skb_linearize(skb))
if (skb_linearize(skb)) {
kfree_skb(skb);
return NULL;
}
trailer = skb_tail_pointer(skb) - 4;
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
(trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
(trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00) {
kfree_skb(skb);
return NULL;
}
source_port = trailer[1] & 7;
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
if (pskb_trim_rcsum(skb, skb->len - 4))
if (pskb_trim_rcsum(skb, skb->len - 4)) {
kfree_skb(skb);
return NULL;
}
return skb;
}

View File

@@ -44,6 +44,7 @@ vsc73xx_rcv(struct sk_buff *skb, struct net_device *netdev)
if (!skb->dev) {
dev_warn_ratelimited(&netdev->dev,
"Couldn't decode source port\n");
kfree_skb(skb);
return NULL;
}

View File

@@ -30,15 +30,21 @@ static struct sk_buff *xrs700x_rcv(struct sk_buff *skb, struct net_device *dev)
source_port = ffs((int)trailer[0]) - 1;
if (source_port < 0)
if (source_port < 0) {
kfree_skb(skb);
return NULL;
}
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
if (!skb->dev)
if (!skb->dev) {
kfree_skb(skb);
return NULL;
}
if (pskb_trim_rcsum(skb, skb->len - 1))
if (pskb_trim_rcsum(skb, skb->len - 1)) {
kfree_skb(skb);
return NULL;
}
/* Frame is forwarded by hardware, don't forward in software. */
dsa_default_offload_fwd_mark(skb);

View File

@@ -87,8 +87,10 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
__be16 *tag;
u16 rx;
if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN)))
if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN))) {
kfree_skb(skb);
return NULL;
}
tag = dsa_etype_header_pos_rx(skb);
@@ -96,6 +98,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
dev_warn_ratelimited(&netdev->dev,
"Unexpected EtherType 0x%04x\n",
ntohs(tag[0]));
kfree_skb(skb);
return NULL;
}
@@ -104,6 +107,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
if (unlikely((rx & YT921X_TAG_PORT_EN) == 0)) {
dev_warn_ratelimited(&netdev->dev,
"Unexpected rx tag 0x%04x\n", rx);
kfree_skb(skb);
return NULL;
}
@@ -112,6 +116,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
if (unlikely(!skb->dev)) {
dev_warn_ratelimited(&netdev->dev,
"Couldn't decode source port %u\n", port);
kfree_skb(skb);
return NULL;
}

View File

@@ -935,13 +935,12 @@ static netdev_tx_t dsa_user_xmit(struct sk_buff *skb, struct net_device *dev)
eth_skb_pad(skb);
/* Transmit function may have to reallocate the original SKB,
* in which case it must have freed it. Only free it here on error.
* in which case it must have freed it. Taggers will drop the
* passed skb on error.
*/
nskb = p->xmit(skb, dev);
if (!nskb) {
kfree_skb(skb);
if (!nskb)
return NETDEV_TX_OK;
}
return dsa_enqueue_skb(nskb, dev);
}

View File

@@ -371,8 +371,9 @@ static void tcp_ao_key_free_rcu(struct rcu_head *head)
kfree_sensitive(key);
}
static void tcp_ao_info_free(struct tcp_ao_info *ao)
static void tcp_ao_info_free_rcu(struct rcu_head *head)
{
struct tcp_ao_info *ao = container_of(head, struct tcp_ao_info, rcu);
struct tcp_ao_key *key;
struct hlist_node *n;
@@ -411,7 +412,7 @@ void tcp_ao_destroy_sock(struct sock *sk, bool twsk)
if (!twsk)
tcp_ao_sk_omem_free(sk, ao);
tcp_ao_info_free(ao);
call_rcu(&ao->rcu, tcp_ao_info_free_rcu);
}
void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp)

View File

@@ -1467,9 +1467,9 @@ void tcp_clear_md5_list(struct sock *sk)
md5sig = rcu_dereference_protected(tp->md5sig_info, 1);
hlist_for_each_entry_safe(key, n, &md5sig->head, node) {
hlist_del(&key->node);
hlist_del_rcu(&key->node);
atomic_sub(sizeof(*key), &sk->sk_omem_alloc);
kfree(key);
kfree_rcu(key, rcu);
}
}

View File

@@ -4329,9 +4329,13 @@ int tcp_connect(struct sock *sk)
if (needs_md5) {
tcp_ao_destroy_sock(sk, false);
} else if (needs_ao) {
struct tcp_md5sig_info *md5sig;
tcp_clear_md5_list(sk);
kfree(rcu_replace_pointer(tp->md5sig_info, NULL,
lockdep_sock_is_held(sk)));
md5sig = rcu_replace_pointer(tp->md5sig_info, NULL,
lockdep_sock_is_held(sk));
kfree_rcu(md5sig, rcu);
static_branch_slow_dec_deferred(&tcp_md5_needed);
}
}
#endif

View File

@@ -636,12 +636,12 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
};
const struct nlmsghdr *nlh = cb->nlh;
struct net *net = sock_net(skb->sk);
unsigned int e = 0, s_e;
struct hlist_head *head;
struct fib6_walker *w;
struct fib6_table *tb;
unsigned int h, s_h;
int err = 0;
u32 s_id;
rcu_read_lock();
if (cb->strict_check) {
@@ -701,23 +701,22 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
}
s_h = cb->args[0];
s_e = cb->args[1];
s_id = cb->args[1];
for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) {
e = 0;
for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_id = 0) {
head = &net->ipv6.fib_table_hash[h];
hlist_for_each_entry_rcu(tb, head, tb6_hlist) {
if (e < s_e)
goto next;
if (s_id && tb->tb6_id != s_id)
continue;
s_id = 0;
cb->args[1] = tb->tb6_id;
err = fib6_dump_table(tb, skb, cb);
if (err != 0)
goto out;
next:
e++;
}
}
out:
cb->args[1] = e;
cb->args[0] = h;
unlock:

View File

@@ -29,6 +29,9 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)
int max_last_entry;
int trailing;
if (len < sizeof(*srh))
return false;
if (srh->type != IPV6_SRCRT_TYPE_4)
return false;

View File

@@ -1480,7 +1480,11 @@ ip_set_dump_done(struct netlink_callback *cb)
struct ip_set_net *inst =
(struct ip_set_net *)cb->args[IPSET_CB_NET];
ip_set_id_t index = (ip_set_id_t)cb->args[IPSET_CB_INDEX];
struct ip_set *set = ip_set_ref_netlink(inst, index);
struct ip_set *set;
rcu_read_lock();
set = ip_set_ref_netlink(inst, index);
rcu_read_unlock();
if (set->variant->uref)
set->variant->uref(set, cb, false);
@@ -1686,7 +1690,9 @@ ip_set_dump_do(struct sk_buff *skb, struct netlink_callback *cb)
release_refcount:
/* If there was an error or set is done, release set */
if (ret || !cb->args[IPSET_CB_ARG0]) {
rcu_read_lock();
set = ip_set_ref_netlink(inst, index);
rcu_read_unlock();
if (set->variant->uref)
set->variant->uref(set, cb, false);
pr_debug("release set %s\n", set->name);

View File

@@ -306,7 +306,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
{
struct nf_conntrack_expect *new;
new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
new = kmem_cache_zalloc(nf_ct_expect_cachep, GFP_ATOMIC);
if (!new)
return NULL;
@@ -391,6 +391,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
#if IS_ENABLED(CONFIG_NF_NAT)
memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
exp->dir = 0;
#endif
}
EXPORT_SYMBOL_GPL(nf_ct_expect_init);

View File

@@ -3549,8 +3549,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
if (cda[CTA_EXPECT_FLAGS]) {
exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
exp->flags &= ~NF_CT_EXPECT_USERSPACE;
} else {
exp->flags = 0;
}
if (cda[CTA_EXPECT_FN]) {
const char *name = nla_data(cda[CTA_EXPECT_FN]);
@@ -3562,8 +3560,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
goto err_out;
}
exp->expectfn = expfn->expectfn;
} else
exp->expectfn = NULL;
}
exp->class = class;
exp->master = ct;
@@ -3583,12 +3580,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
exp, nf_ct_l3num(ct));
if (err < 0)
goto err_out;
#if IS_ENABLED(CONFIG_NF_NAT)
} else {
memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
exp->dir = 0;
#endif
}
return exp;
err_out:

View File

@@ -956,7 +956,6 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
return NF_ACCEPT;
saddr = &ct->tuplehash[!dir].tuple.src.u3;
} else if (sip_external_media) {
struct net_device *dev = skb_dst(skb)->dev;
struct dst_entry *dst = NULL;
struct flowi fl;
@@ -978,7 +977,11 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
* through the same interface as the signalling peer.
*/
if (dst) {
bool external_media = (dst->dev == dev);
const struct dst_entry *this_dst = skb_dst(skb);
bool external_media = false;
if (this_dst && dst->dev == this_dst->dev)
external_media = true;
dst_release(dst);
if (external_media)

View File

@@ -163,6 +163,8 @@ nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
tb[NFCTH_POLICY_NAME], NF_CT_HELPER_NAME_LEN);
expect_policy->max_expected =
ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
if (!expect_policy->max_expected)
expect_policy->max_expected = NF_CT_EXPECT_MAX_CNT;
if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
return -EINVAL;

View File

@@ -1184,6 +1184,173 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
return err;
}
static bool nfqnl_validate_ipopts(const struct iphdr *iph_new,
const struct nf_queue_entry *e)
{
const struct iphdr *iph_orig = ip_hdr(e->skb);
unsigned int ihl = iph_new->ihl * 4;
if (iph_new->ihl != iph_orig->ihl)
return false;
if (ihl == sizeof(*iph_orig))
return true;
return memcmp(iph_new + 1, ip_hdr(e->skb) + 1, ihl - sizeof(*iph_orig)) == 0;
}
static bool nfqnl_validate_ip4(const struct iphdr *iph, unsigned int data_len,
const struct nf_queue_entry *e)
{
unsigned int ihl;
if (data_len < sizeof(*iph))
return false;
ihl = iph->ihl * 4u;
if (ihl < sizeof(*iph) || data_len < ihl)
return false;
if (iph->version != 4 ||
((iph->frag_off ^ ip_hdr(e->skb)->frag_off) & ~htons(IP_DF)) != 0)
return false;
/* BIG TCP won't work; netlink attr len is u16 */
if (ntohs(iph->tot_len) != data_len)
return false;
/* support for ipopts mangling would require
* recompile + skb transport header update.
*/
return nfqnl_validate_ipopts(iph, e);
}
static bool nfqnl_validate_one_exthdr(const u8 *data,
unsigned int data_len,
const struct nf_queue_entry *e,
int start, int hdrlen)
{
u16 octets;
if (data_len < hdrlen || hdrlen < 2)
return false;
while (hdrlen > 0) {
if (data_len < sizeof(octets))
return false;
data_len -= sizeof(octets);
if (skb_copy_bits(e->skb, start, &octets, sizeof(octets)))
return false;
if (hdrlen < sizeof(octets))
return false;
hdrlen -= sizeof(octets);
if (memcmp(data, &octets, sizeof(octets)))
return false;
start += sizeof(octets);
data += sizeof(octets);
}
return true;
}
static bool nfqnl_validate_exthdr(const struct ipv6hdr *ip6_new,
unsigned int data_len,
const struct nf_queue_entry *e)
{
const struct ipv6hdr *ip6_orig = ipv6_hdr(e->skb);
int exthdr_cnt = 0, start = sizeof(*ip6_orig);
const u8 *data = (const u8 *)ip6_new;
u8 orig_nexthdr = ip6_orig->nexthdr;
u8 new_nexthdr = ip6_new->nexthdr;
if (new_nexthdr != orig_nexthdr)
return false;
data += sizeof(*ip6_new);
data_len -= sizeof(*ip6_new);
while (ipv6_ext_hdr(orig_nexthdr)) {
const struct ipv6_opt_hdr *hp;
struct ipv6_opt_hdr _hdr;
int hdrlen;
if (orig_nexthdr == NEXTHDR_NONE)
return true;
if (unlikely(exthdr_cnt++ >= IP6_MAX_EXT_HDRS_CNT))
return false;
hp = skb_header_pointer(e->skb, start, sizeof(_hdr), &_hdr);
if (!hp)
return false;
switch (orig_nexthdr) {
case NEXTHDR_FRAGMENT:
hdrlen = sizeof(struct frag_hdr);
break;
case NEXTHDR_AUTH:
hdrlen = ipv6_authlen(hp);
break;
default:
hdrlen = ipv6_optlen(hp);
break;
}
if (!nfqnl_validate_one_exthdr(data, data_len, e,
start, hdrlen))
return false;
orig_nexthdr = hp->nexthdr;
hp = (const void *)data;
new_nexthdr = hp->nexthdr;
if (new_nexthdr != orig_nexthdr)
return false;
data_len -= hdrlen;
start += hdrlen;
data += hdrlen;
}
return true;
}
static bool nfqnl_validate_ip6(const struct ipv6hdr *ip6, unsigned int data_len,
const struct nf_queue_entry *e)
{
if (data_len < sizeof(*ip6))
return false;
/* BIG TCP/jumbograms won't work; netlink attr len is u16 */
if (ntohs(ip6->payload_len) != data_len - sizeof(*ip6))
return false;
if (ip6->version != 6)
return false;
return nfqnl_validate_exthdr(ip6, data_len, e);
}
static bool nfqnl_validate_write(const void *data, unsigned int data_len,
const struct nf_queue_entry *e)
{
switch (e->state.pf) {
case NFPROTO_IPV4:
return nfqnl_validate_ip4(data, data_len, e);
case NFPROTO_IPV6:
return nfqnl_validate_ip6(data, data_len, e) &&
!(IP6CB(e->skb)->flags & IP6SKB_JUMBOGRAM);
case NFPROTO_BRIDGE:
/* No write support. Bridge is dubious: userspace doesn't even see L2 header */
return false;
}
return false;
}
static int
nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int diff)
{
@@ -1192,6 +1359,9 @@ nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int di
if (e->state.net->user_ns != &init_user_ns)
return -EPERM;
if (!nfqnl_validate_write(data, data_len, e))
return -EINVAL;
if (diff < 0) {
unsigned int min_len = skb_transport_offset(e->skb);

View File

@@ -31,6 +31,15 @@ int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr)
const struct nft_fib *priv = nft_expr_priv(expr);
unsigned int hooks;
switch (ctx->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
case NFPROTO_INET:
break;
default:
return -EOPNOTSUPP;
}
switch (priv->result) {
case NFT_FIB_RESULT_OIF:
case NFT_FIB_RESULT_OIFNAME:

View File

@@ -50,6 +50,33 @@ static void nft_fib_netdev_eval(const struct nft_expr *expr,
regs->verdict.code = NFT_BREAK;
}
static int nft_fib_netdev_validate(const struct nft_ctx *ctx,
const struct nft_expr *expr)
{
const struct nft_fib *priv = nft_expr_priv(expr);
unsigned int hooks;
switch (priv->result) {
case NFT_FIB_RESULT_OIF:
case NFT_FIB_RESULT_OIFNAME:
hooks = (1 << NF_NETDEV_INGRESS);
break;
case NFT_FIB_RESULT_ADDRTYPE:
if (priv->flags & NFTA_FIB_F_IIF)
hooks = (1 << NF_NETDEV_INGRESS);
else if (priv->flags & NFTA_FIB_F_OIF)
hooks = (1 << NF_NETDEV_EGRESS);
else
hooks = (1 << NF_NETDEV_INGRESS) |
(1 << NF_NETDEV_EGRESS);
break;
default:
return -EINVAL;
}
return nft_chain_validate_hooks(ctx->chain, hooks);
}
static struct nft_expr_type nft_fib_netdev_type;
static const struct nft_expr_ops nft_fib_netdev_ops = {
.type = &nft_fib_netdev_type,
@@ -57,7 +84,7 @@ static const struct nft_expr_ops nft_fib_netdev_ops = {
.eval = nft_fib_netdev_eval,
.init = nft_fib_init,
.dump = nft_fib_dump,
.validate = nft_fib_validate,
.validate = nft_fib_netdev_validate,
};
static struct nft_expr_type nft_fib_netdev_type __read_mostly = {

View File

@@ -834,6 +834,249 @@ nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u16 offset, u8 len,
return true;
}
/* Ingress is very early, before l3 protocol handlers.
* There should be no in-tree code that trusts l3/l4 headers
* between ingress and NF_INET_PRE_ROUTING hooks.
*/
static bool nft_in_ingress(const struct nf_hook_state *s)
{
return s->pf == NFPROTO_NETDEV && s->hook == NF_NETDEV_INGRESS;
}
static bool nft_nh_write_ok_ip4(const struct nft_pktinfo *pkt,
const struct nft_payload_set *priv,
const u32 *src)
{
unsigned int offset = priv->offset + skb_network_offset(pkt->skb);
const u8 *new_octets = (const u8 *)src;
u8 old_octet;
switch (priv->offset) {
case 0: /* csum fixups does expand dscp/tos store to 2 bytes.
* make sure ihl/version remain unchanged.
*/
if (skb_copy_bits(pkt->skb, offset, &old_octet, sizeof(old_octet)))
return false;
return priv->len == 2 &&
*new_octets == old_octet;
case offsetof(struct iphdr, tos):
return priv->len == 1;
case offsetof(struct iphdr, id):
return priv->len == 2;
case offsetof(struct iphdr, ttl):
if (priv->len == 1)
return true;
if (priv->len != 2)
return false;
/* same, csum fixup does expand ttl store to two bytes.
* check protocol is not altered.
*/
if (skb_copy_bits(pkt->skb, offset + 1, &old_octet, sizeof(old_octet)))
return false;
return new_octets[1] == old_octet;
case offsetof(struct iphdr, check):
return priv->len <= 2 + 4 + 4;
case offsetof(struct iphdr, saddr):
return priv->len <= 4 + 4;
case offsetof(struct iphdr, daddr):
return priv->len <= 4;
}
return false;
}
static bool nft_nh_write_ok_ip6(const struct nft_pktinfo *pkt,
const struct nft_payload_set *priv,
const u32 *src)
{
const struct ipv6hdr *ih = (const void *)src;
switch (priv->offset) {
case 0: /* store to dscp must not alter ip6 version */
return priv->len <= 4 && ih->version == 6;
case 2:
return priv->len <= 2;
case offsetof(struct ipv6hdr, hop_limit):
return priv->len == 1;
case offsetof(struct ipv6hdr, saddr):
return priv->len <= 16 + 16;
case offsetof(struct ipv6hdr, daddr):
return priv->len <= 16;
}
return false;
}
static bool nft_nh_write_ok_arp(const struct nft_payload_set *priv)
{
/* Variable size for standard ethernet arp */
const unsigned int eth_ip = 2 * (ETH_ALEN + 4);
unsigned int offset = priv->offset;
switch (offset) {
case offsetof(struct arphdr, ar_op):
return priv->len == 2;
default:
break;
}
/* permit writes post fixed arp header size. offset + len are
* checked vs skb size via skb_ensure_writable.
*/
return offset >= sizeof(struct arphdr) && priv->len <= eth_ip;
}
static bool nft_nh_write_ok_netdev(const struct nft_pktinfo *pkt,
const struct nft_payload_set *priv,
const u32 *src)
{
#ifdef CONFIG_NF_TABLES_NETDEV
switch (pkt->skb->protocol) {
case htons(ETH_P_ARP):
return nft_nh_write_ok_arp(priv);
case htons(ETH_P_IP):
return nft_nh_write_ok_ip4(pkt, priv, src);
case htons(ETH_P_IPV6):
return nft_nh_write_ok_ip6(pkt, priv, src);
}
#endif
/* default to false for now, relax later in case we have
* use-cases that need inner header manipulation for
* encapsulated traffic like vlan or PPPoE.
*/
return false;
}
static bool nft_nh_write_ok_bridge(const struct nft_pktinfo *pkt,
const struct nft_payload_set *priv,
const u32 *src)
{
#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
switch (pkt->ethertype) {
case htons(ETH_P_ARP):
return nft_nh_write_ok_arp(priv);
case htons(ETH_P_IP):
return nft_nh_write_ok_ip4(pkt, priv, src);
case htons(ETH_P_IPV6):
return nft_nh_write_ok_ip6(pkt, priv, src);
}
#endif
/* see nft_nh_write_ok_netdev: default to false */
return false;
}
static bool nft_nh_write_ok(const struct nft_pktinfo *pkt,
const struct nft_payload_set *priv,
const u32 *src)
{
switch (pkt->state->pf) {
case NFPROTO_ARP:
return nft_nh_write_ok_arp(priv);
case NFPROTO_BRIDGE:
return nft_nh_write_ok_bridge(pkt, priv, src);
case NFPROTO_IPV4:
return nft_nh_write_ok_ip4(pkt, priv, src);
case NFPROTO_IPV6:
return nft_nh_write_ok_ip6(pkt, priv, src);
case NFPROTO_NETDEV:
if (pkt->state->hook == NF_NETDEV_INGRESS)
return true;
return nft_nh_write_ok_netdev(pkt, priv, src);
}
return false;
}
/* check linklayer modifications don't spill into network header. */
static bool nft_ll_write_ok(const struct nft_pktinfo *pkt, int offset)
{
if (nft_in_ingress(pkt->state))
return true;
return offset <= skb_network_offset(pkt->skb);
}
static bool nft_payload_validate_inet_csum_offset(const struct nft_ctx *ctx,
const struct nft_payload_set *priv)
{
switch (priv->base) {
case NFT_PAYLOAD_LL_HEADER:
break;
case NFT_PAYLOAD_NETWORK_HEADER:
if (ctx->family == NFPROTO_IPV4) {
if (offsetof(struct iphdr, check) == priv->csum_offset)
return true;
return false;
}
return true; /* run time validation required */
case NFT_PAYLOAD_TRANSPORT_HEADER:
if (priv->csum_flags) /* makes no sense, asks for "re-update" of L4 checksum */
return false;
/* no further check here; offset can't be negative so bogus
* offsets can corrupt L4 or payload but not l3 headers.
* We already allow arbitrary l4/inner payload writes.
*/
return true;
case NFT_PAYLOAD_INNER_HEADER:
return true;
case NFT_PAYLOAD_TUN_HEADER:
break;
}
return false;
}
/* do not allow arbitrary network header mangling via bogus csum_off.
* We only support ipv4. Only NFPROTO_IPV4 can be checked from control
* plane.
*/
static bool nft_payload_csum_nh_write_ok(const struct nft_payload_set *priv,
const struct nft_pktinfo *pkt)
{
switch (pkt->state->pf) {
case NFPROTO_IPV4:
/* Warning: NFPROTO_INET was not checked; we can't return true here. */
return priv->csum_offset == offsetof(struct iphdr, check);
case NFPROTO_IPV6:
return false;
case NFPROTO_BRIDGE:
return pkt->ethertype == htons(ETH_P_IP) &&
priv->csum_offset == offsetof(struct iphdr, check);
case NFPROTO_NETDEV:
return pkt->skb->protocol == htons(ETH_P_IP) &&
priv->csum_offset == offsetof(struct iphdr, check);
}
return false;
}
static bool nft_payload_csum_write_ok(const struct nft_pktinfo *pkt,
const struct nft_payload_set *priv)
{
switch (priv->base) {
case NFT_PAYLOAD_LL_HEADER:
break;
case NFT_PAYLOAD_NETWORK_HEADER:
return nft_payload_csum_nh_write_ok(priv, pkt);
case NFT_PAYLOAD_TRANSPORT_HEADER:
case NFT_PAYLOAD_INNER_HEADER:
/* neither offsets are validated, offsets cannot be
* negative so real l3 headers cannot be mangled.
*/
return true;
case NFT_PAYLOAD_TUN_HEADER:
break;
}
return false;
}
static void nft_payload_set_eval(const struct nft_expr *expr,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
@@ -861,8 +1104,12 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
}
offset = skb_mac_header(skb) - skb->data - vlan_hlen;
if (!nft_ll_write_ok(pkt, priv->len + priv->offset + offset))
goto err;
break;
case NFT_PAYLOAD_NETWORK_HEADER:
if (!nft_nh_write_ok(pkt, priv, src))
goto err;
offset = skb_network_offset(skb);
break;
case NFT_PAYLOAD_TRANSPORT_HEADER:
@@ -894,6 +1141,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
tsum = csum_partial(src, priv->len, 0);
if (priv->csum_type == NFT_PAYLOAD_CSUM_INET &&
nft_payload_csum_write_ok(pkt, priv) &&
nft_payload_csum_inet(skb, src, fsum, tsum, csum_offset))
goto err;
@@ -960,7 +1208,26 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
switch (csum_type) {
case NFT_PAYLOAD_CSUM_NONE:
if (priv->csum_offset) /* nonsensical */
return -EINVAL;
if (priv->csum_flags == 0)
break;
/* Userspace requests L4 checksum update, e.g.:
* - IPv6 stateless NAT (no l3 csum)
* - transport header mangling
* - inner data mangling
*/
if (priv->base == NFT_PAYLOAD_NETWORK_HEADER ||
priv->base == NFT_PAYLOAD_TRANSPORT_HEADER ||
priv->base == NFT_PAYLOAD_INNER_HEADER)
break;
return -EINVAL;
case NFT_PAYLOAD_CSUM_INET:
if (!nft_payload_validate_inet_csum_offset(ctx, priv))
return -EINVAL;
break;
case NFT_PAYLOAD_CSUM_SCTP:
if (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER)
@@ -968,6 +1235,9 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
if (priv->csum_offset != offsetof(struct sctphdr, checksum))
return -EINVAL;
if (priv->csum_flags)
return -EINVAL;
break;
default:
return -EOPNOTSUPP;

View File

@@ -342,6 +342,8 @@
#include "nft_set_pipapo_avx2.h"
#include "nft_set_pipapo.h"
static void nft_pipapo_abort(const struct nft_set *set);
/**
* pipapo_refill() - For each set bit, set bits from selected mapping table item
* @map: Bitmap to be scanned for set bits
@@ -1296,7 +1298,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
const u8 *start_p, *end_p;
int i, bsize_max, err = 0;
if (!m)
if (!m || m->state == NFT_PIPAPO_CLONE_ERR)
return -ENOMEM;
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
@@ -1367,8 +1369,10 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
else
ret = pipapo_expand(f, start, end, f->groups * f->bb);
if (ret < 0)
return ret;
if (ret < 0) {
err = ret;
goto abort;
}
if (f->bsize > bsize_max)
bsize_max = f->bsize;
@@ -1384,7 +1388,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
err = pipapo_realloc_scratch(m, bsize_max);
if (err)
return err;
goto abort;
m->bsize_max = bsize_max;
} else {
@@ -1396,7 +1400,26 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
pipapo_map(m, rulemap, e);
m->state = NFT_PIPAPO_CLONE_MOD;
return 0;
abort:
DEBUG_NET_WARN_ON_ONCE(m->state == NFT_PIPAPO_CLONE_ERR);
/* Two rollback cases:
* 1) no previous changes. nft_pipapo_abort is not
* guaranteed to be invoked (there might be no further
* add/delete requests coming after this).
*
* 2) we had previous changes: there are transaction
* records pointing to this set. Leave the rollback to
* the transaction handling.
*/
if (m->state == NFT_PIPAPO_CLONE_NEW)
nft_pipapo_abort(set); /* releases m */
else
m->state = NFT_PIPAPO_CLONE_ERR;
return err;
}
/**
@@ -1473,6 +1496,7 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old)
dst++;
}
new->state = NFT_PIPAPO_CLONE_NEW;
return new;
out_mt:
@@ -1896,7 +1920,7 @@ nft_pipapo_deactivate(const struct net *net, const struct nft_set *set,
/* removal must occur on priv->clone, if we are low on memory
* we have no choice and must fail the removal request.
*/
if (!m)
if (!m || m->state == NFT_PIPAPO_CLONE_ERR)
return NULL;
e = pipapo_get(m, (const u8 *)elem->key.val.data,

View File

@@ -131,9 +131,16 @@ struct nft_pipapo_scratch {
unsigned long __map[];
};
enum nft_pipapo_clone_state {
NFT_PIPAPO_CLONE_NEW,
NFT_PIPAPO_CLONE_MOD,
NFT_PIPAPO_CLONE_ERR,
};
/**
* struct nft_pipapo_match - Data used for lookup and matching
* @field_count: Amount of fields in set
* @state: add/delete state; used from control plane
* @bsize_max: Maximum lookup table bucket size of all fields, in longs
* @scratch: Preallocated per-CPU maps for partial matching results
* @rcu: Matching data is swapped on commits
@@ -141,6 +148,7 @@ struct nft_pipapo_scratch {
*/
struct nft_pipapo_match {
u8 field_count;
enum nft_pipapo_clone_state state:8;
unsigned int bsize_max;
struct nft_pipapo_scratch * __percpu *scratch;
struct rcu_head rcu;

View File

@@ -44,7 +44,7 @@ TC_INDIRECT_SCOPE int tcf_bpf_act(struct sk_buff *skb,
tcf_lastuse_update(&prog->tcf_tm);
bstats_update(this_cpu_ptr(prog->common.cpu_bstats), skb);
filter = rcu_dereference(prog->filter);
filter = rcu_dereference_bh(prog->filter);
if (at_ingress) {
__skb_push(skb, skb->mac_len);
filter_res = bpf_prog_run_data_pointers(filter, skb);

View File

@@ -346,6 +346,8 @@ static int dualpi2_skb_classify(struct dualpi2_sched_data *q,
struct tcf_proto *fl;
int result;
cb->classified = DUALPI2_C_CLASSIC;
dualpi2_read_ect(skb);
if (cb->ect & q->ecn_mask) {
cb->classified = DUALPI2_C_L4S;
@@ -359,10 +361,8 @@ static int dualpi2_skb_classify(struct dualpi2_sched_data *q,
}
fl = rcu_dereference_bh(q->tcf_filters);
if (!fl) {
cb->classified = DUALPI2_C_CLASSIC;
if (!fl)
return NET_XMIT_SUCCESS;
}
result = tcf_classify(skb, NULL, fl, &res, false);
if (result >= 0) {

View File

@@ -462,12 +462,39 @@ static struct sk_buff *hhf_dequeue(struct Qdisc *sch)
return skb;
}
static void hhf_reset_classifier(struct hhf_sched_data *q)
{
int i;
if (!q->hh_flows)
return;
for (i = 0; i < HH_FLOWS_CNT; i++) {
struct hh_flow_state *flow, *next;
struct list_head *head = &q->hh_flows[i];
list_for_each_entry_safe(flow, next, head, flowchain) {
list_del(&flow->flowchain);
kfree(flow);
}
}
WRITE_ONCE(q->hh_flows_current_cnt, 0);
for (i = 0; i < HHF_ARRAYS_CNT; i++) {
if (q->hhf_valid_bits[i])
bitmap_zero(q->hhf_valid_bits[i], HHF_ARRAYS_LEN);
}
q->hhf_arrays_reset_timestamp = hhf_time_stamp();
}
static void hhf_reset(struct Qdisc *sch)
{
struct hhf_sched_data *q = qdisc_priv(sch);
struct sk_buff *skb;
while ((skb = hhf_dequeue(sch)) != NULL)
rtnl_kfree_skbs(skb, skb);
hhf_reset_classifier(q);
}
static void hhf_destroy(struct Qdisc *sch)

View File

@@ -103,7 +103,7 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
if (!netif_xmit_stopped(
netdev_get_tx_queue(qdisc_dev(sch), q->curband))) {
qdisc = q->queues[q->curband];
skb = qdisc->dequeue(qdisc);
skb = qdisc_dequeue_peeked(qdisc);
if (skb) {
qdisc_bstats_update(sch, skb);
qdisc_qlen_dec(sch);

View File

@@ -749,7 +749,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,
return NULL;
skip_peek_checks:
skb = child->ops->dequeue(child);
skb = qdisc_dequeue_peeked(child);
if (unlikely(!skb))
return NULL;

View File

@@ -52,7 +52,8 @@
struct teql_master {
struct Qdisc_ops qops;
struct net_device *dev;
struct Qdisc *slaves;
struct Qdisc __rcu *slaves;
spinlock_t slaves_lock; /* serializes writes to ->slaves */
struct list_head master_list;
unsigned long tx_bytes;
unsigned long tx_packets;
@@ -61,7 +62,7 @@ struct teql_master {
};
struct teql_sched_data {
struct Qdisc *next;
struct Qdisc __rcu *next;
struct teql_master *m;
struct sk_buff_head q;
};
@@ -101,7 +102,9 @@ teql_dequeue(struct Qdisc *sch)
if (skb == NULL) {
struct net_device *m = qdisc_dev(q);
if (m) {
dat->m->slaves = sch;
spin_lock_bh(&dat->m->slaves_lock);
rcu_assign_pointer(dat->m->slaves, sch);
spin_unlock_bh(&dat->m->slaves_lock);
netif_wake_queue(m);
}
} else {
@@ -132,34 +135,49 @@ teql_destroy(struct Qdisc *sch)
struct Qdisc *q, *prev;
struct teql_sched_data *dat = qdisc_priv(sch);
struct teql_master *master = dat->m;
struct netdev_queue *txq = NULL;
bool reset_master_queue = false;
if (!master)
return;
prev = master->slaves;
spin_lock_bh(&master->slaves_lock);
prev = rcu_dereference_protected(master->slaves,
lockdep_is_held(&master->slaves_lock));
if (prev) {
do {
q = NEXT_SLAVE(prev);
if (q == sch) {
NEXT_SLAVE(prev) = NEXT_SLAVE(q);
if (q == master->slaves) {
master->slaves = NEXT_SLAVE(q);
if (q == master->slaves) {
struct netdev_queue *txq;
struct Qdisc *head, *next;
txq = netdev_get_tx_queue(master->dev, 0);
master->slaves = NULL;
dev_reset_queue(master->dev,
txq, NULL);
}
}
skb_queue_purge(&dat->q);
break;
q = rcu_dereference_protected(NEXT_SLAVE(prev),
lockdep_is_held(&master->slaves_lock));
if (q != sch) {
prev = q;
continue;
}
} while ((prev = q) != master->slaves);
next = rcu_dereference_protected(NEXT_SLAVE(q),
lockdep_is_held(&master->slaves_lock));
rcu_assign_pointer(NEXT_SLAVE(prev), next);
head = rcu_dereference_protected(master->slaves,
lockdep_is_held(&master->slaves_lock));
if (q == head) {
rcu_assign_pointer(master->slaves, next);
if (q == next) {
txq = netdev_get_tx_queue(master->dev, 0);
rcu_assign_pointer(master->slaves, NULL);
reset_master_queue = true;
}
}
skb_queue_purge(&dat->q);
break;
} while (prev != rcu_dereference_protected(master->slaves,
lockdep_is_held(&master->slaves_lock)));
}
spin_unlock_bh(&master->slaves_lock);
if (reset_master_queue)
dev_reset_queue(master->dev, txq, NULL);
}
static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
@@ -168,6 +186,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
struct net_device *dev = qdisc_dev(sch);
struct teql_master *m = (struct teql_master *)sch->ops;
struct teql_sched_data *q = qdisc_priv(sch);
struct Qdisc *first;
if (dev->hard_header_len > m->dev->hard_header_len)
return -EINVAL;
@@ -184,7 +203,9 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
skb_queue_head_init(&q->q);
if (m->slaves) {
spin_lock_bh(&m->slaves_lock);
first = rcu_dereference_protected(m->slaves, lockdep_is_held(&m->slaves_lock));
if (first) {
if (m->dev->flags & IFF_UP) {
if ((m->dev->flags & IFF_POINTOPOINT &&
!(dev->flags & IFF_POINTOPOINT)) ||
@@ -192,8 +213,10 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
!(dev->flags & IFF_BROADCAST)) ||
(m->dev->flags & IFF_MULTICAST &&
!(dev->flags & IFF_MULTICAST)) ||
dev->mtu < m->dev->mtu)
dev->mtu < m->dev->mtu) {
spin_unlock_bh(&m->slaves_lock);
return -EINVAL;
}
} else {
if (!(dev->flags&IFF_POINTOPOINT))
m->dev->flags &= ~IFF_POINTOPOINT;
@@ -204,14 +227,17 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
if (dev->mtu < m->dev->mtu)
m->dev->mtu = dev->mtu;
}
q->next = NEXT_SLAVE(m->slaves);
NEXT_SLAVE(m->slaves) = sch;
rcu_assign_pointer(q->next,
rcu_dereference_protected(NEXT_SLAVE(first),
lockdep_is_held(&m->slaves_lock)));
rcu_assign_pointer(NEXT_SLAVE(first), sch);
} else {
q->next = sch;
m->slaves = sch;
rcu_assign_pointer(q->next, sch);
rcu_assign_pointer(m->slaves, sch);
m->dev->mtu = dev->mtu;
m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK);
}
spin_unlock_bh(&m->slaves_lock);
return 0;
}
@@ -285,7 +311,9 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
int subq = skb_get_queue_mapping(skb);
struct sk_buff *skb_res = NULL;
start = master->slaves;
rcu_read_lock_bh();
start = rcu_dereference_bh(master->slaves);
restart:
nores = 0;
@@ -317,10 +345,17 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_start_xmit(skb, slave, slave_txq, false) ==
NETDEV_TX_OK) {
__netif_tx_unlock(slave_txq);
master->slaves = NEXT_SLAVE(q);
spin_lock_bh(&master->slaves_lock);
if (rcu_dereference_protected(master->slaves,
lockdep_is_held(&master->slaves_lock)) == q)
rcu_assign_pointer(master->slaves,
rcu_dereference_protected(NEXT_SLAVE(q),
lockdep_is_held(&master->slaves_lock)));
spin_unlock_bh(&master->slaves_lock);
netif_wake_queue(dev);
master->tx_packets++;
master->tx_bytes += length;
rcu_read_unlock_bh();
return NETDEV_TX_OK;
}
__netif_tx_unlock(slave_txq);
@@ -329,14 +364,21 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
busy = 1;
break;
case 1:
master->slaves = NEXT_SLAVE(q);
spin_lock_bh(&master->slaves_lock);
if (rcu_dereference_protected(master->slaves,
lockdep_is_held(&master->slaves_lock)) == q)
rcu_assign_pointer(master->slaves,
rcu_dereference_protected(NEXT_SLAVE(q),
lockdep_is_held(&master->slaves_lock)));
spin_unlock_bh(&master->slaves_lock);
rcu_read_unlock_bh();
return NETDEV_TX_OK;
default:
nores = 1;
break;
}
__skb_pull(skb, skb_network_offset(skb));
} while ((q = NEXT_SLAVE(q)) != start);
} while ((q = rcu_dereference_bh(NEXT_SLAVE(q))) != start);
if (nores && skb_res == NULL) {
skb_res = skb;
@@ -345,29 +387,32 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
if (busy) {
netif_stop_queue(dev);
rcu_read_unlock_bh();
return NETDEV_TX_BUSY;
}
master->tx_errors++;
drop:
master->tx_dropped++;
rcu_read_unlock_bh();
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
static int teql_master_open(struct net_device *dev)
{
struct Qdisc *q;
struct Qdisc *q, *first;
struct teql_master *m = netdev_priv(dev);
int mtu = 0xFFFE;
unsigned int flags = IFF_NOARP | IFF_MULTICAST;
if (m->slaves == NULL)
first = rtnl_dereference(m->slaves);
if (!first)
return -EUNATCH;
flags = FMASK;
q = m->slaves;
q = first;
do {
struct net_device *slave = qdisc_dev(q);
@@ -389,7 +434,7 @@ static int teql_master_open(struct net_device *dev)
flags &= ~IFF_BROADCAST;
if (!(slave->flags&IFF_MULTICAST))
flags &= ~IFF_MULTICAST;
} while ((q = NEXT_SLAVE(q)) != m->slaves);
} while ((q = rtnl_dereference(NEXT_SLAVE(q))) != first);
m->dev->mtu = mtu;
m->dev->flags = (m->dev->flags&~FMASK) | flags;
@@ -417,14 +462,15 @@ static void teql_master_stats64(struct net_device *dev,
static int teql_master_mtu(struct net_device *dev, int new_mtu)
{
struct teql_master *m = netdev_priv(dev);
struct Qdisc *q;
struct Qdisc *q, *first;
q = m->slaves;
first = rtnl_dereference(m->slaves);
q = first;
if (q) {
do {
if (new_mtu > qdisc_dev(q)->mtu)
return -EINVAL;
} while ((q = NEXT_SLAVE(q)) != m->slaves);
} while ((q = rtnl_dereference(NEXT_SLAVE(q))) != first);
}
WRITE_ONCE(dev->mtu, new_mtu);
@@ -444,6 +490,7 @@ static __init void teql_master_setup(struct net_device *dev)
struct teql_master *master = netdev_priv(dev);
struct Qdisc_ops *ops = &master->qops;
spin_lock_init(&master->slaves_lock);
master->dev = dev;
ops->priv_size = sizeof(struct teql_sched_data);

View File

@@ -663,8 +663,9 @@ static void sctp_free_addr_wq(struct net *net)
struct sctp_sockaddr_entry *addrw;
struct sctp_sockaddr_entry *temp;
timer_shutdown_sync(&net->sctp.addr_wq_timer);
spin_lock_bh(&net->sctp.addr_wq_lock);
timer_delete(&net->sctp.addr_wq_timer);
list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
list_del(&addrw->list);
kfree(addrw);

View File

@@ -1761,6 +1761,8 @@ struct sctp_association *sctp_unpack_cookie(
bear_cookie = &cookie->c;
ch = (struct sctp_chunkhdr *)(bear_cookie + 1);
if (ch->type != SCTP_CID_INIT)
goto malformed;
chlen = ntohs(ch->length);
if (chlen < sizeof(struct sctp_init_chunk))
goto malformed;
@@ -2298,7 +2300,8 @@ int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
* VIOLATION error. We build the ERROR chunk here and let the normal
* error handling code build and send the packet.
*/
if (param.v != (void *)chunk->chunk_end)
if (param.v != (void *)peer_init +
SCTP_PAD4(ntohs(peer_init->chunk_hdr.length)))
return sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
/* The only missing mandatory param possible today is

View File

@@ -707,11 +707,12 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
struct sctp_cmd_seq *commands)
{
struct sctp_ulpevent *ev, *ai_ev = NULL, *auth_ev = NULL;
struct sctp_chunk *err_chk_p = NULL;
struct sctp_association *new_asoc;
struct sctp_init_chunk *peer_init;
struct sctp_chunk *chunk = arg;
struct sctp_chunk *err_chk_p;
struct sctp_chunk *repl;
enum sctp_cid cid;
struct sock *sk;
int error = 0;
@@ -785,6 +786,19 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
}
}
peer_init = (struct sctp_init_chunk *)(chunk->subh.cookie_hdr + 1);
cid = peer_init->chunk_hdr.type;
if (!sctp_sk(sk)->cookie_auth_enable &&
!sctp_verify_init(net, ep, asoc, cid, peer_init, chunk,
&err_chk_p)) {
sctp_association_free(new_asoc);
if (err_chk_p)
sctp_chunk_free(err_chk_p);
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
}
if (err_chk_p)
sctp_chunk_free(err_chk_p);
if (security_sctp_assoc_request(new_asoc, chunk->head_skb ?: chunk->skb)) {
sctp_association_free(new_asoc);
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
@@ -798,7 +812,6 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
/* This is a brand-new association, so these are not yet side
* effects--it is safe to run them here.
*/
peer_init = (struct sctp_init_chunk *)(chunk->subh.cookie_hdr + 1);
if (!sctp_process_init(new_asoc, chunk,
&chunk->subh.cookie_hdr->c.peer_addr,
peer_init, GFP_ATOMIC))
@@ -2215,10 +2228,12 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
void *arg,
struct sctp_cmd_seq *commands)
{
struct sctp_chunk *err_chk_p = NULL;
struct sctp_association *new_asoc;
struct sctp_init_chunk *peer_init;
struct sctp_chunk *chunk = arg;
enum sctp_disposition retval;
struct sctp_chunk *err_chk_p;
enum sctp_cid cid;
int error = 0;
char action;
@@ -2287,6 +2302,21 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
switch (action) {
case 'A': /* Association restart. */
case 'B': /* Collision case B. */
peer_init = (struct sctp_init_chunk *)
(chunk->subh.cookie_hdr + 1);
cid = peer_init->chunk_hdr.type;
if (!sctp_sk(ep->base.sk)->cookie_auth_enable &&
!sctp_verify_init(net, ep, asoc, cid, peer_init, chunk,
&err_chk_p)) {
sctp_association_free(new_asoc);
if (err_chk_p)
sctp_chunk_free(err_chk_p);
return sctp_sf_pdiscard(net, ep, asoc, type, arg,
commands);
}
if (err_chk_p)
sctp_chunk_free(err_chk_p);
fallthrough;
case 'D': /* Collision case D. */
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_association *)asoc,

View File

@@ -4111,8 +4111,9 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,
if (optlen < sizeof(*params))
return -EINVAL;
/* srs_number_streams is u16, so optlen can't be bigger than this. */
optlen = min_t(unsigned int, optlen, USHRT_MAX +
sizeof(__u16) * sizeof(*params));
optlen = min_t(unsigned int, optlen,
struct_size_t(struct sctp_reset_streams, srs_stream_list,
USHRT_MAX));
if (params->srs_number_streams * sizeof(__u16) >
optlen - sizeof(*params))
@@ -4598,8 +4599,8 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
if (optlen > 0) {
/* Trim it to the biggest size sctp sockopt may need if necessary */
optlen = min_t(unsigned int, optlen,
PAGE_ALIGN(USHRT_MAX +
sizeof(__u16) * sizeof(struct sctp_reset_streams)));
PAGE_ALIGN(struct_size_t(struct sctp_reset_streams,
srs_stream_list, USHRT_MAX)));
kopt = memdup_sockptr(optval, optlen);
if (IS_ERR(kopt))
return PTR_ERR(kopt);

View File

@@ -497,12 +497,13 @@ void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
*/
int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr,
struct sk_buff_head *retrq)
struct sk_buff_head *retrq, bool *valid)
{
struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
struct tipc_gap_ack_blks *ga;
struct sk_buff_head xmitq;
int rc = 0;
u16 glen;
__skb_queue_head_init(&xmitq);
@@ -510,13 +511,18 @@ int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
if (msg_type(hdr) != STATE_MSG) {
tipc_link_bc_init_rcv(l, hdr);
} else if (!msg_bc_ack_invalid(hdr)) {
tipc_get_gap_ack_blks(&ga, l, hdr, false);
if (!sysctl_tipc_bc_retruni)
retrq = &xmitq;
rc = tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr),
msg_bc_gap(hdr), ga, &xmitq,
retrq);
rc |= tipc_link_bc_sync_rcv(l, hdr, &xmitq);
glen = tipc_get_gap_ack_blks(&ga, l, hdr, false);
if (glen > msg_data_sz(hdr)) {
/* Malformed Gap ACK blocks; caller drops the msg */
*valid = false;
} else {
if (!sysctl_tipc_bc_retruni)
retrq = &xmitq;
rc = tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr),
msg_bc_gap(hdr), ga, &xmitq,
retrq);
rc |= tipc_link_bc_sync_rcv(l, hdr, &xmitq);
}
}
tipc_bcast_unlock(net);

View File

@@ -97,7 +97,7 @@ void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr);
int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr,
struct sk_buff_head *retrq);
struct sk_buff_head *retrq, bool *valid);
int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg,
struct tipc_link *bcl);
int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]);

View File

@@ -1831,12 +1831,15 @@ static void tipc_node_mcast_rcv(struct tipc_node *n)
}
static void tipc_node_bc_sync_rcv(struct tipc_node *n, struct tipc_msg *hdr,
int bearer_id, struct sk_buff_head *xmitq)
int bearer_id, struct sk_buff_head *xmitq,
bool *valid)
{
struct tipc_link *ucl;
int rc;
rc = tipc_bcast_sync_rcv(n->net, n->bc_entry.link, hdr, xmitq);
rc = tipc_bcast_sync_rcv(n->net, n->bc_entry.link, hdr, xmitq, valid);
if (!*valid)
return;
if (rc & TIPC_LINK_DOWN_EVT) {
tipc_node_reset_links(n);
@@ -2140,12 +2143,18 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)
/* Ensure broadcast reception is in synch with peer's send state */
if (unlikely(usr == LINK_PROTOCOL)) {
bool valid = true;
if (unlikely(skb_linearize(skb))) {
tipc_node_put(n);
goto discard;
}
hdr = buf_msg(skb);
tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq);
tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq, &valid);
if (!valid) {
tipc_node_put(n);
goto discard;
}
} else if (unlikely(tipc_link_acked(n->bc_entry.link) != bc_ack)) {
tipc_bcast_ack_rcv(net, n->bc_entry.link, hdr);
}

View File

@@ -187,28 +187,24 @@ def query_nic_features(cfg) -> None:
cfg.wanted_features.add(f["name"])
cfg.hw_features = set()
hw_all_features_cmd = ""
for f in features["hw"]["bits"]["bit"]:
if f.get("value", False):
feature = f["name"]
cfg.hw_features.add(feature)
hw_all_features_cmd += f" {feature} on"
try:
ethtool(f"-K {cfg.ifname} {hw_all_features_cmd}")
except Exception as e:
ksft_pr(f"WARNING: failure enabling all hw features: {e}")
ksft_pr("partial gso feature detection may be impacted")
cfg.hw_features.add(f["name"])
# Check which features are supported via GSO partial
cfg.partial_features = set()
if 'tx-gso-partial' in cfg.hw_features:
seg_features = {f for f in cfg.hw_features if "segmentation" in f}
ethtool(f"-K {cfg.ifname} " +
" ".join(f"{f} on" for f in seg_features))
ethtool(f"-K {cfg.ifname} tx-gso-partial off")
no_partial = set()
features = cfg.ethnl.features_get({"header": {"dev-index": cfg.ifindex}})
for f in features["active"]["bits"]["bit"]:
no_partial.add(f["name"])
cfg.partial_features = cfg.hw_features - no_partial
cfg.partial_features = seg_features - no_partial
ethtool(f"-K {cfg.ifname} tx-gso-partial on")
restore_wanted_features(cfg)

View File

@@ -44,7 +44,7 @@ class cmd:
Use bkg() instead to run a command in the background.
"""
def __init__(self, comm, shell=None, fail=True, expect_fail=False, ns=None,
background=False, host=None, timeout=5, ksft_ready=None,
background=False, host=None, timeout=20, ksft_ready=None,
ksft_wait=None):
if ns:
if hasattr(ns, 'user_ns_path'):
@@ -113,7 +113,7 @@ class cmd:
return stdout, stderr
def process(self, terminate=True, fail=None, expect_fail=False, timeout=5):
def process(self, terminate=True, fail=None, expect_fail=False, timeout=20):
if fail is None:
fail = not terminate