--- /dev/null
+From 2e99dedc73f004f650b197c9b269c15c7e01ad15 Mon Sep 17 00:00:00 2001
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Date: Wed, 2 Dec 2020 15:50:17 +0800
+Subject: igc: Report speed and duplex as unknown when device is runtime suspended
+
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+
+commit 2e99dedc73f004f650b197c9b269c15c7e01ad15 upstream.
+
+Similar to commit 165ae7a8feb5 ("igb: Report speed and duplex as unknown
+when device is runtime suspended"), if we try to read speed and duplex
+sysfs while the device is runtime suspended, igc will complain and
+stops working:
+
+[ 123.449883] igc 0000:03:00.0 enp3s0: PCIe link lost, device now detached
+[ 123.450052] BUG: kernel NULL pointer dereference, address: 0000000000000008
+[ 123.450056] #PF: supervisor read access in kernel mode
+[ 123.450058] #PF: error_code(0x0000) - not-present page
+[ 123.450059] PGD 0 P4D 0
+[ 123.450064] Oops: 0000 [#1] SMP NOPTI
+[ 123.450068] CPU: 0 PID: 2525 Comm: udevadm Tainted: G U W OE 5.10.0-1002-oem #2+rkl2-Ubuntu
+[ 123.450078] RIP: 0010:igc_rd32+0x1c/0x90 [igc]
+[ 123.450080] Code: c0 5d c3 b8 fd ff ff ff c3 0f 1f 44 00 00 0f 1f 44 00 00 55 89 f0 48 89 e5 41 56 41 55 41 54 49 89 c4 53 48 8b 57 08 48 01 d0 <44> 8b 28 41 83 fd ff 74 0c 5b 44 89 e8 41 5c 41 5d 4
+
+[ 123.450083] RSP: 0018:ffffb0d100d6fcc0 EFLAGS: 00010202
+[ 123.450085] RAX: 0000000000000008 RBX: ffffb0d100d6fd30 RCX: 0000000000000000
+[ 123.450087] RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffff945a12716c10
+[ 123.450089] RBP: ffffb0d100d6fce0 R08: ffff945a12716550 R09: ffff945a09874000
+[ 123.450090] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000008
+[ 123.450092] R13: ffff945a12716000 R14: ffff945a037da280 R15: ffff945a037da290
+[ 123.450094] FS: 00007f3b34c868c0(0000) GS:ffff945b89200000(0000) knlGS:0000000000000000
+[ 123.450096] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 123.450098] CR2: 0000000000000008 CR3: 00000001144de006 CR4: 0000000000770ef0
+[ 123.450100] PKRU: 55555554
+[ 123.450101] Call Trace:
+[ 123.450111] igc_ethtool_get_link_ksettings+0xd6/0x1b0 [igc]
+[ 123.450118] __ethtool_get_link_ksettings+0x71/0xb0
+[ 123.450123] duplex_show+0x74/0xc0
+[ 123.450129] dev_attr_show+0x1d/0x40
+[ 123.450134] sysfs_kf_seq_show+0xa1/0x100
+[ 123.450137] kernfs_seq_show+0x27/0x30
+[ 123.450142] seq_read+0xb7/0x400
+[ 123.450148] ? common_file_perm+0x72/0x170
+[ 123.450151] kernfs_fop_read+0x35/0x1b0
+[ 123.450155] vfs_read+0xb5/0x1b0
+[ 123.450157] ksys_read+0x67/0xe0
+[ 123.450160] __x64_sys_read+0x1a/0x20
+[ 123.450164] do_syscall_64+0x38/0x90
+[ 123.450168] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 123.450170] RIP: 0033:0x7f3b351fe142
+[ 123.450173] Code: c0 e9 c2 fe ff ff 50 48 8d 3d 3a ca 0a 00 e8 f5 19 02 00 0f 1f 44 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 0f 05 <48> 3d 00 f0 ff ff 77 56 c3 0f 1f 44 00 00 48 83 ec 28 48 89 54 24
+[ 123.450174] RSP: 002b:00007fffef2ec138 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
+[ 123.450177] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f3b351fe142
+[ 123.450179] RDX: 0000000000001001 RSI: 00005644c047f070 RDI: 0000000000000003
+[ 123.450180] RBP: 00007fffef2ec340 R08: 00005644c047f070 R09: 00007f3b352d9320
+[ 123.450182] R10: 00005644c047c010 R11: 0000000000000246 R12: 00005644c047cbf0
+[ 123.450184] R13: 00005644c047e6d0 R14: 0000000000000003 R15: 00007fffef2ec140
+[ 123.450189] Modules linked in: rfcomm ccm cmac algif_hash algif_skcipher af_alg bnep toshiba_acpi industrialio toshiba_haps hp_accel lis3lv02d btusb btrtl btbcm btintel bluetooth ecdh_generic ecc joydev input_leds nls_iso8859_1 snd_sof_pci snd_sof_intel_byt snd_sof_intel_ipc snd_sof_intel_hda_common snd_soc_hdac_hda snd_hda_codec_hdmi snd_sof_xtensa_dsp snd_sof_intel_hda snd_sof snd_hda_ext_core snd_soc_acpi_intel_match snd_soc_acpi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio snd_hda_intel snd_intel_dspcfg soundwire_intel soundwire_generic_allocation soundwire_cadence snd_hda_codec snd_hda_core ath10k_pci snd_hwdep intel_rapl_msr intel_rapl_common ath10k_core soundwire_bus snd_soc_core x86_pkg_temp_thermal ath intel_powerclamp snd_compress ac97_bus snd_pcm_dmaengine mac80211 snd_pcm coretemp snd_seq_midi snd_seq_midi_event snd_rawmidi kvm_intel cfg80211 snd_seq snd_seq_device snd_timer mei_hdcp kvm libarc4 snd crct10dif_pclmul ghash_clmulni_intel aesni_intel
+ mei_me dell_wmi
+[ 123.450266] dell_smbios soundcore sparse_keymap dcdbas crypto_simd cryptd mei dell_uart_backlight glue_helper ee1004 wmi_bmof intel_wmi_thunderbolt dell_wmi_descriptor mac_hid efi_pstore acpi_pad acpi_tad intel_cstate sch_fq_codel parport_pc ppdev lp parport ip_tables x_tables autofs4 btrfs blake2b_generic raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear dm_mirror dm_region_hash dm_log hid_generic usbhid hid i915 i2c_algo_bit drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops cec crc32_pclmul rc_core drm intel_lpss_pci i2c_i801 ahci igc intel_lpss i2c_smbus idma64 xhci_pci libahci virt_dma xhci_pci_renesas wmi video pinctrl_tigerlake
+[ 123.450335] CR2: 0000000000000008
+[ 123.450338] ---[ end trace 9f731e38b53c35cc ]---
+
+The more generic approach will be wrap get_link_ksettings() with begin()
+and complete() callbacks, and calls runtime resume and runtime suspend
+routine respectively. However, igc is like igb, runtime resume routine
+uses rtnl_lock() which upper ethtool layer also uses.
+
+So to prevent a deadlock on rtnl, take a different approach, use
+pm_runtime_suspended() to avoid reading register while device is runtime
+suspended.
+
+Fixes: 8c5ad0dae93c ("igc: Add ethtool support")
+Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Acked-by: Sasha Neftin <sasha.neftin@intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/intel/igc/igc_ethtool.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
++++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
+@@ -1714,7 +1714,8 @@ static int igc_ethtool_get_link_ksetting
+ Asym_Pause);
+ }
+
+- status = rd32(IGC_STATUS);
++ status = pm_runtime_suspended(&adapter->pdev->dev) ?
++ 0 : rd32(IGC_STATUS);
+
+ if (status & IGC_STATUS_LU) {
+ if (status & IGC_STATUS_SPEED_1000) {
--- /dev/null
+From eb4e8fac00d1e01ada5e57c05d24739156086677 Mon Sep 17 00:00:00 2001
+From: Chinmay Agarwal <chinagar@codeaurora.org>
+Date: Wed, 27 Jan 2021 22:24:54 +0530
+Subject: neighbour: Prevent a dead entry from updating gc_list
+
+From: Chinmay Agarwal <chinagar@codeaurora.org>
+
+commit eb4e8fac00d1e01ada5e57c05d24739156086677 upstream.
+
+Following race condition was detected:
+<CPU A, t0> - neigh_flush_dev() is under execution and calls
+neigh_mark_dead(n) marking the neighbour entry 'n' as dead.
+
+<CPU B, t1> - Executing: __netif_receive_skb() ->
+__netif_receive_skb_core() -> arp_rcv() -> arp_process().arp_process()
+calls __neigh_lookup() which takes a reference on neighbour entry 'n'.
+
+<CPU A, t2> - Moves further along neigh_flush_dev() and calls
+neigh_cleanup_and_release(n), but since reference count increased in t2,
+'n' couldn't be destroyed.
+
+<CPU B, t3> - Moves further along, arp_process() and calls
+neigh_update()-> __neigh_update() -> neigh_update_gc_list(), which adds
+the neighbour entry back in gc_list(neigh_mark_dead(), removed it
+earlier in t0 from gc_list)
+
+<CPU B, t4> - arp_process() finally calls neigh_release(n), destroying
+the neighbour entry.
+
+This leads to 'n' still being part of gc_list, but the actual
+neighbour structure has been freed.
+
+The situation can be prevented from happening if we disallow a dead
+entry to have any possibility of updating gc_list. This is what the
+patch intends to achieve.
+
+Fixes: 9c29a2f55ec0 ("neighbor: Fix locking order for gc_list changes")
+Signed-off-by: Chinmay Agarwal <chinagar@codeaurora.org>
+Reviewed-by: Cong Wang <xiyou.wangcong@gmail.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Link: https://lore.kernel.org/r/20210127165453.GA20514@chinagar-linux.qualcomm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/core/neighbour.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/net/core/neighbour.c
++++ b/net/core/neighbour.c
+@@ -1245,13 +1245,14 @@ static int __neigh_update(struct neighbo
+ old = neigh->nud_state;
+ err = -EPERM;
+
+- if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
+- (old & (NUD_NOARP | NUD_PERMANENT)))
+- goto out;
+ if (neigh->dead) {
+ NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
++ new = old;
+ goto out;
+ }
++ if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
++ (old & (NUD_NOARP | NUD_PERMANENT)))
++ goto out;
+
+ ext_learn_change = neigh_update_ext_learned(neigh, flags, ¬ify);
+
--- /dev/null
+From f72f2fb8fb6be095b98af5d740ac50cffd0b0cae Mon Sep 17 00:00:00 2001
+From: DENG Qingfang <dqfext@gmail.com>
+Date: Sat, 30 Jan 2021 21:43:34 +0800
+Subject: net: dsa: mv88e6xxx: override existent unicast portvec in port_fdb_add
+
+From: DENG Qingfang <dqfext@gmail.com>
+
+commit f72f2fb8fb6be095b98af5d740ac50cffd0b0cae upstream.
+
+Having multiple destination ports for a unicast address does not make
+sense.
+Make port_db_load_purge override existent unicast portvec instead of
+adding a new port bit.
+
+Fixes: 884729399260 ("net: dsa: mv88e6xxx: handle multiple ports in ATU")
+Signed-off-by: DENG Qingfang <dqfext@gmail.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20210130134334.10243-1-dqfext@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/dsa/mv88e6xxx/chip.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -1669,7 +1669,11 @@ static int mv88e6xxx_port_db_load_purge(
+ if (!entry.portvec)
+ entry.state = 0;
+ } else {
+- entry.portvec |= BIT(port);
++ if (state == MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC)
++ entry.portvec = BIT(port);
++ else
++ entry.portvec |= BIT(port);
++
+ entry.state = state;
+ }
+
--- /dev/null
+From 28e104d00281ade30250b24e098bf50887671ea4 Mon Sep 17 00:00:00 2001
+From: Vadim Fedorenko <vfedorenko@novek.ru>
+Date: Sat, 30 Jan 2021 01:27:47 +0300
+Subject: net: ip_tunnel: fix mtu calculation
+
+From: Vadim Fedorenko <vfedorenko@novek.ru>
+
+commit 28e104d00281ade30250b24e098bf50887671ea4 upstream.
+
+dev->hard_header_len for tunnel interface is set only when header_ops
+are set too and already contains full overhead of any tunnel encapsulation.
+That's why there is not need to use this overhead twice in mtu calc.
+
+Fixes: fdafed459998 ("ip_gre: set dev->hard_header_len and dev->needed_headroom properly")
+Reported-by: Slava Bacherikov <mail@slava.cc>
+Signed-off-by: Vadim Fedorenko <vfedorenko@novek.ru>
+Link: https://lore.kernel.org/r/1611959267-20536-1-git-send-email-vfedorenko@novek.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ipv4/ip_tunnel.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+--- a/net/ipv4/ip_tunnel.c
++++ b/net/ipv4/ip_tunnel.c
+@@ -317,7 +317,7 @@ static int ip_tunnel_bind_dev(struct net
+ }
+
+ dev->needed_headroom = t_hlen + hlen;
+- mtu -= (dev->hard_header_len + t_hlen);
++ mtu -= t_hlen;
+
+ if (mtu < IPV4_MIN_MTU)
+ mtu = IPV4_MIN_MTU;
+@@ -347,7 +347,7 @@ static struct ip_tunnel *ip_tunnel_creat
+ nt = netdev_priv(dev);
+ t_hlen = nt->hlen + sizeof(struct iphdr);
+ dev->min_mtu = ETH_MIN_MTU;
+- dev->max_mtu = IP_MAX_MTU - dev->hard_header_len - t_hlen;
++ dev->max_mtu = IP_MAX_MTU - t_hlen;
+ ip_tunnel_add(itn, nt);
+ return nt;
+
+@@ -488,11 +488,10 @@ static int tnl_update_pmtu(struct net_de
+ int mtu;
+
+ tunnel_hlen = md ? tunnel_hlen : tunnel->hlen;
+- pkt_size = skb->len - tunnel_hlen - dev->hard_header_len;
++ pkt_size = skb->len - tunnel_hlen;
+
+ if (df)
+- mtu = dst_mtu(&rt->dst) - dev->hard_header_len
+- - sizeof(struct iphdr) - tunnel_hlen;
++ mtu = dst_mtu(&rt->dst) - (sizeof(struct iphdr) + tunnel_hlen);
+ else
+ mtu = skb_valid_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
+
+@@ -972,7 +971,7 @@ int __ip_tunnel_change_mtu(struct net_de
+ {
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ int t_hlen = tunnel->hlen + sizeof(struct iphdr);
+- int max_mtu = IP_MAX_MTU - dev->hard_header_len - t_hlen;
++ int max_mtu = IP_MAX_MTU - t_hlen;
+
+ if (new_mtu < ETH_MIN_MTU)
+ return -EINVAL;
+@@ -1149,10 +1148,9 @@ int ip_tunnel_newlink(struct net_device
+
+ mtu = ip_tunnel_bind_dev(dev);
+ if (tb[IFLA_MTU]) {
+- unsigned int max = IP_MAX_MTU - dev->hard_header_len - nt->hlen;
++ unsigned int max = IP_MAX_MTU - (nt->hlen + sizeof(struct iphdr));
+
+- mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU,
+- (unsigned int)(max - sizeof(struct iphdr)));
++ mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU, max);
+ }
+
+ err = dev_set_mtu(dev, mtu);
--- /dev/null
+From 938e0fcd3253efdef8924714158911286d08cfe1 Mon Sep 17 00:00:00 2001
+From: Alexander Ovechkin <ovov@yandex-team.ru>
+Date: Mon, 1 Feb 2021 23:00:49 +0300
+Subject: net: sched: replaced invalid qdisc tree flush helper in qdisc_replace
+
+From: Alexander Ovechkin <ovov@yandex-team.ru>
+
+commit 938e0fcd3253efdef8924714158911286d08cfe1 upstream.
+
+Commit e5f0e8f8e456 ("net: sched: introduce and use qdisc tree flush/purge helpers")
+introduced qdisc tree flush/purge helpers, but erroneously used flush helper
+instead of purge helper in qdisc_replace function.
+This issue was found in our CI, that tests various qdisc setups by configuring
+qdisc and sending data through it. Call of invalid helper sporadically leads
+to corruption of vt_tree/cf_tree of hfsc_class that causes kernel oops:
+
+ Oops: 0000 [#1] SMP PTI
+ CPU: 1 PID: 0 Comm: swapper/1 Not tainted 5.11.0-8f6859df #1
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.10.2-0-g5f4c7b1-prebuilt.qemu-project.org 04/01/2014
+ RIP: 0010:rb_insert_color+0x18/0x190
+ Code: c3 31 c0 c3 0f 1f 40 00 66 2e 0f 1f 84 00 00 00 00 00 48 8b 07 48 85 c0 0f 84 05 01 00 00 48 8b 10 f6 c2 01 0f 85 34 01 00 00 <48> 8b 4a 08 49 89 d0 48 39 c1 74 7d 48 85 c9 74 32 f6 01 01 75 2d
+ RSP: 0018:ffffc900000b8bb0 EFLAGS: 00010246
+ RAX: ffff8881ef4c38b0 RBX: ffff8881d956e400 RCX: ffff8881ef4c38b0
+ RDX: 0000000000000000 RSI: ffff8881d956f0a8 RDI: ffff8881d956e4b0
+ RBP: 0000000000000000 R08: 000000d5c4e249da R09: 1600000000000000
+ R10: ffffc900000b8be0 R11: ffffc900000b8b28 R12: 0000000000000001
+ R13: 000000000000005a R14: ffff8881f0905000 R15: ffff8881f0387d00
+ FS: 0000000000000000(0000) GS:ffff8881f8b00000(0000) knlGS:0000000000000000
+ CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ CR2: 0000000000000008 CR3: 00000001f4796004 CR4: 0000000000060ee0
+ Call Trace:
+ <IRQ>
+ init_vf.isra.19+0xec/0x250 [sch_hfsc]
+ hfsc_enqueue+0x245/0x300 [sch_hfsc]
+ ? fib_rules_lookup+0x12a/0x1d0
+ ? __dev_queue_xmit+0x4b6/0x930
+ ? hfsc_delete_class+0x250/0x250 [sch_hfsc]
+ __dev_queue_xmit+0x4b6/0x930
+ ? ip6_finish_output2+0x24d/0x590
+ ip6_finish_output2+0x24d/0x590
+ ? ip6_output+0x6c/0x130
+ ip6_output+0x6c/0x130
+ ? __ip6_finish_output+0x110/0x110
+ mld_sendpack+0x224/0x230
+ mld_ifc_timer_expire+0x186/0x2c0
+ ? igmp6_group_dropped+0x200/0x200
+ call_timer_fn+0x2d/0x150
+ run_timer_softirq+0x20c/0x480
+ ? tick_sched_do_timer+0x60/0x60
+ ? tick_sched_timer+0x37/0x70
+ __do_softirq+0xf7/0x2cb
+ irq_exit+0xa0/0xb0
+ smp_apic_timer_interrupt+0x74/0x150
+ apic_timer_interrupt+0xf/0x20
+ </IRQ>
+
+Fixes: e5f0e8f8e456 ("net: sched: introduce and use qdisc tree flush/purge helpers")
+Signed-off-by: Alexander Ovechkin <ovov@yandex-team.ru>
+Reported-by: Alexander Kuznetsov <wwfq@yandex-team.ru>
+Acked-by: Dmitry Monakhov <dmtrmonakhov@yandex-team.ru>
+Acked-by: Dmitry Yakunin <zeil@yandex-team.ru>
+Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
+Link: https://lore.kernel.org/r/20210201200049.299153-1-ovov@yandex-team.ru
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/sch_generic.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -1155,7 +1155,7 @@ static inline struct Qdisc *qdisc_replac
+ old = *pold;
+ *pold = new;
+ if (old != NULL)
+- qdisc_tree_flush_backlog(old);
++ qdisc_purge_queue(old);
+ sch_tree_unlock(sch);
+
+ return old;
input-xpad-sync-supported-devices-with-fork-on-github.patch
input-ili210x-implement-pressure-reporting-for-ili251x.patch
md-set-prev_flush_start-and-flush_bio-in-an-atomic-way.patch
+igc-report-speed-and-duplex-as-unknown-when-device-is-runtime-suspended.patch
+neighbour-prevent-a-dead-entry-from-updating-gc_list.patch
+net-ip_tunnel-fix-mtu-calculation.patch
+udp-ipv4-manipulate-network-header-of-nated-udp-gro-fraglist.patch
+net-dsa-mv88e6xxx-override-existent-unicast-portvec-in-port_fdb_add.patch
+net-sched-replaced-invalid-qdisc-tree-flush-helper-in-qdisc_replace.patch
--- /dev/null
+From c3df39ac9b0e3747bf8233ea9ce4ed5ceb3199d3 Mon Sep 17 00:00:00 2001
+From: Dongseok Yi <dseok.yi@samsung.com>
+Date: Sat, 30 Jan 2021 08:13:27 +0900
+Subject: udp: ipv4: manipulate network header of NATed UDP GRO fraglist
+
+From: Dongseok Yi <dseok.yi@samsung.com>
+
+commit c3df39ac9b0e3747bf8233ea9ce4ed5ceb3199d3 upstream.
+
+UDP/IP header of UDP GROed frag_skbs are not updated even after NAT
+forwarding. Only the header of head_skb from ip_finish_output_gso ->
+skb_gso_segment is updated but following frag_skbs are not updated.
+
+A call path skb_mac_gso_segment -> inet_gso_segment ->
+udp4_ufo_fragment -> __udp_gso_segment -> __udp_gso_segment_list
+does not try to update UDP/IP header of the segment list but copy
+only the MAC header.
+
+Update port, addr and check of each skb of the segment list in
+__udp_gso_segment_list. It covers both SNAT and DNAT.
+
+Fixes: 9fd1ff5d2ac7 (udp: Support UDP fraglist GRO/GSO.)
+Signed-off-by: Dongseok Yi <dseok.yi@samsung.com>
+Acked-by: Steffen Klassert <steffen.klassert@secunet.com>
+Link: https://lore.kernel.org/r/1611962007-80092-1-git-send-email-dseok.yi@samsung.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/udp.h | 2 -
+ net/ipv4/udp_offload.c | 69 +++++++++++++++++++++++++++++++++++++++++++++----
+ net/ipv6/udp_offload.c | 2 -
+ 3 files changed, 66 insertions(+), 7 deletions(-)
+
+--- a/include/net/udp.h
++++ b/include/net/udp.h
+@@ -178,7 +178,7 @@ struct sk_buff *udp_gro_receive(struct l
+ int udp_gro_complete(struct sk_buff *skb, int nhoff, udp_lookup_t lookup);
+
+ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
+- netdev_features_t features);
++ netdev_features_t features, bool is_ipv6);
+
+ static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb)
+ {
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -184,8 +184,67 @@ out_unlock:
+ }
+ EXPORT_SYMBOL(skb_udp_tunnel_segment);
+
++static void __udpv4_gso_segment_csum(struct sk_buff *seg,
++ __be32 *oldip, __be32 *newip,
++ __be16 *oldport, __be16 *newport)
++{
++ struct udphdr *uh;
++ struct iphdr *iph;
++
++ if (*oldip == *newip && *oldport == *newport)
++ return;
++
++ uh = udp_hdr(seg);
++ iph = ip_hdr(seg);
++
++ if (uh->check) {
++ inet_proto_csum_replace4(&uh->check, seg, *oldip, *newip,
++ true);
++ inet_proto_csum_replace2(&uh->check, seg, *oldport, *newport,
++ false);
++ if (!uh->check)
++ uh->check = CSUM_MANGLED_0;
++ }
++ *oldport = *newport;
++
++ csum_replace4(&iph->check, *oldip, *newip);
++ *oldip = *newip;
++}
++
++static struct sk_buff *__udpv4_gso_segment_list_csum(struct sk_buff *segs)
++{
++ struct sk_buff *seg;
++ struct udphdr *uh, *uh2;
++ struct iphdr *iph, *iph2;
++
++ seg = segs;
++ uh = udp_hdr(seg);
++ iph = ip_hdr(seg);
++
++ if ((udp_hdr(seg)->dest == udp_hdr(seg->next)->dest) &&
++ (udp_hdr(seg)->source == udp_hdr(seg->next)->source) &&
++ (ip_hdr(seg)->daddr == ip_hdr(seg->next)->daddr) &&
++ (ip_hdr(seg)->saddr == ip_hdr(seg->next)->saddr))
++ return segs;
++
++ while ((seg = seg->next)) {
++ uh2 = udp_hdr(seg);
++ iph2 = ip_hdr(seg);
++
++ __udpv4_gso_segment_csum(seg,
++ &iph2->saddr, &iph->saddr,
++ &uh2->source, &uh->source);
++ __udpv4_gso_segment_csum(seg,
++ &iph2->daddr, &iph->daddr,
++ &uh2->dest, &uh->dest);
++ }
++
++ return segs;
++}
++
+ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
+- netdev_features_t features)
++ netdev_features_t features,
++ bool is_ipv6)
+ {
+ unsigned int mss = skb_shinfo(skb)->gso_size;
+
+@@ -195,11 +254,11 @@ static struct sk_buff *__udp_gso_segment
+
+ udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss);
+
+- return skb;
++ return is_ipv6 ? skb : __udpv4_gso_segment_list_csum(skb);
+ }
+
+ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
+- netdev_features_t features)
++ netdev_features_t features, bool is_ipv6)
+ {
+ struct sock *sk = gso_skb->sk;
+ unsigned int sum_truesize = 0;
+@@ -211,7 +270,7 @@ struct sk_buff *__udp_gso_segment(struct
+ __be16 newlen;
+
+ if (skb_shinfo(gso_skb)->gso_type & SKB_GSO_FRAGLIST)
+- return __udp_gso_segment_list(gso_skb, features);
++ return __udp_gso_segment_list(gso_skb, features, is_ipv6);
+
+ mss = skb_shinfo(gso_skb)->gso_size;
+ if (gso_skb->len <= sizeof(*uh) + mss)
+@@ -325,7 +384,7 @@ static struct sk_buff *udp4_ufo_fragment
+ goto out;
+
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
+- return __udp_gso_segment(skb, features);
++ return __udp_gso_segment(skb, features, false);
+
+ mss = skb_shinfo(skb)->gso_size;
+ if (unlikely(skb->len <= mss))
+--- a/net/ipv6/udp_offload.c
++++ b/net/ipv6/udp_offload.c
+@@ -46,7 +46,7 @@ static struct sk_buff *udp6_ufo_fragment
+ goto out;
+
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
+- return __udp_gso_segment(skb, features);
++ return __udp_gso_segment(skb, features, true);
+
+ /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
+ * do checksum of UDP packets sent as multiple IP fragments.