Muehlenhoff has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/321653

Change subject: Update to 4.4.32
......................................................................

Update to 4.4.32

Change-Id: Ic4221758647cf45e5a24f3d75a4455a965370afb
---
M debian/changelog
A debian/patches/bugfix/all/stable-4.4.32.patch
M debian/patches/series
3 files changed, 1,387 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.wikimedia.org:29418/operations/debs/linux44 
refs/changes/53/321653/1

diff --git a/debian/changelog b/debian/changelog
index e37446f..56ba20e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -11,8 +11,11 @@
     - Drop 1d79b67c4a8a98247407dc245ba7cad2692da3c2, which is
       only needed for recent GGC releases and clashes with
       Debian-specific patches
+  * Update to 4.4.32:
+    https://cdn.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.4.31
+    - CVE-2016-7039 [fcd91dd449867c6bfe56a81cabba76b829fd05cd]
 
- -- Moritz Muehlenhoff <mmuhlenh...@wikimedia.org>  Fri, 11 Nov 2016 15:57:32 
+0100
+ -- Moritz Muehlenhoff <mmuhlenh...@wikimedia.org>  Tue, 15 Nov 2016 14:42:40 
+0100
 
 linux (4.4.2-3+wmf7) jessie-wikimedia; urgency=medium
 
diff --git a/debian/patches/bugfix/all/stable-4.4.32.patch 
b/debian/patches/bugfix/all/stable-4.4.32.patch
new file mode 100644
index 0000000..7b16c50
--- /dev/null
+++ b/debian/patches/bugfix/all/stable-4.4.32.patch
@@ -0,0 +1,1382 @@
+diff --git a/Makefile b/Makefile
+index 7c6f28e7a2f6..fba9b09a1330 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 4
+ PATCHLEVEL = 4
+-SUBLEVEL = 31
++SUBLEVEL = 32
+ EXTRAVERSION =
+ NAME = Blurry Fish Butt
+ 
+diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
+index bbe56871245c..4298aeb1e20f 100644
+--- a/arch/mips/kvm/emulate.c
++++ b/arch/mips/kvm/emulate.c
+@@ -822,7 +822,7 @@ static void kvm_mips_invalidate_guest_tlb(struct kvm_vcpu 
*vcpu,
+       bool user;
+ 
+       /* No need to flush for entries which are already invalid */
+-      if (!((tlb->tlb_lo[0] | tlb->tlb_lo[1]) & ENTRYLO_V))
++      if (!((tlb->tlb_lo0 | tlb->tlb_lo1) & MIPS3_PG_V))
+               return;
+       /* User address space doesn't need flushing for KSeg2/3 changes */
+       user = tlb->tlb_hi < KVM_GUEST_KSEG0;
+diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c 
b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
+index 21aacc1f45c1..7f85c2c1d681 100644
+--- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
++++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c
+@@ -265,15 +265,27 @@ static int amdgpu_atombios_dp_get_dp_link_config(struct 
drm_connector *connector
+       unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
+       unsigned lane_num, i, max_pix_clock;
+ 
+-      for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+-              for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= 
max_link_rate; i++) {
+-                      max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
++      if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) ==
++          ENCODER_OBJECT_ID_NUTMEG) {
++              for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
++                      max_pix_clock = (lane_num * 270000 * 8) / bpp;
+                       if (max_pix_clock >= pix_clock) {
+                               *dp_lanes = lane_num;
+-                              *dp_rate = link_rates[i];
++                              *dp_rate = 270000;
+                               return 0;
+                       }
+               }
++      } else {
++              for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= 
max_link_rate; i++) {
++                      for (lane_num = 1; lane_num <= max_lane_num; lane_num 
<<= 1) {
++                              max_pix_clock = (lane_num * link_rates[i] * 8) 
/ bpp;
++                              if (max_pix_clock >= pix_clock) {
++                                      *dp_lanes = lane_num;
++                                      *dp_rate = link_rates[i];
++                                      return 0;
++                              }
++                      }
++              }
+       }
+ 
+       return -EINVAL;
+diff --git a/drivers/gpu/drm/radeon/atombios_dp.c 
b/drivers/gpu/drm/radeon/atombios_dp.c
+index 44ee72e04df9..b5760851195c 100644
+--- a/drivers/gpu/drm/radeon/atombios_dp.c
++++ b/drivers/gpu/drm/radeon/atombios_dp.c
+@@ -315,15 +315,27 @@ int radeon_dp_get_dp_link_config(struct drm_connector 
*connector,
+       unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
+       unsigned lane_num, i, max_pix_clock;
+ 
+-      for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+-              for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= 
max_link_rate; i++) {
+-                      max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
++      if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
++          ENCODER_OBJECT_ID_NUTMEG) {
++              for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
++                      max_pix_clock = (lane_num * 270000 * 8) / bpp;
+                       if (max_pix_clock >= pix_clock) {
+                               *dp_lanes = lane_num;
+-                              *dp_rate = link_rates[i];
++                              *dp_rate = 270000;
+                               return 0;
+                       }
+               }
++      } else {
++              for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= 
max_link_rate; i++) {
++                      for (lane_num = 1; lane_num <= max_lane_num; lane_num 
<<= 1) {
++                              max_pix_clock = (lane_num * link_rates[i] * 8) 
/ bpp;
++                              if (max_pix_clock >= pix_clock) {
++                                      *dp_lanes = lane_num;
++                                      *dp_rate = link_rates[i];
++                                      return 0;
++                              }
++                      }
++              }
+       }
+ 
+       return -EINVAL;
+diff --git a/drivers/net/ethernet/broadcom/tg3.c 
b/drivers/net/ethernet/broadcom/tg3.c
+index ca5ac5d6f4e6..49056c33be74 100644
+--- a/drivers/net/ethernet/broadcom/tg3.c
++++ b/drivers/net/ethernet/broadcom/tg3.c
+@@ -18142,14 +18142,14 @@ static pci_ers_result_t tg3_io_error_detected(struct 
pci_dev *pdev,
+ 
+       rtnl_lock();
+ 
+-      /* We needn't recover from permanent error */
+-      if (state == pci_channel_io_frozen)
+-              tp->pcierr_recovery = true;
+-
+       /* We probably don't have netdev yet */
+       if (!netdev || !netif_running(netdev))
+               goto done;
+ 
++      /* We needn't recover from permanent error */
++      if (state == pci_channel_io_frozen)
++              tp->pcierr_recovery = true;
++
+       tg3_phy_stop(tp);
+ 
+       tg3_netif_stop(tp);
+@@ -18246,7 +18246,7 @@ static void tg3_io_resume(struct pci_dev *pdev)
+ 
+       rtnl_lock();
+ 
+-      if (!netif_running(netdev))
++      if (!netdev || !netif_running(netdev))
+               goto done;
+ 
+       tg3_full_lock(tp, 0);
+diff --git a/drivers/net/ethernet/freescale/fec_main.c 
b/drivers/net/ethernet/freescale/fec_main.c
+index f6147ffc7fbc..ab716042bdd2 100644
+--- a/drivers/net/ethernet/freescale/fec_main.c
++++ b/drivers/net/ethernet/freescale/fec_main.c
+@@ -944,11 +944,11 @@ fec_restart(struct net_device *ndev)
+        * enet-mac reset will reset mac address registers too,
+        * so need to reconfigure it.
+        */
+-      if (fep->quirks & FEC_QUIRK_ENET_MAC) {
+-              memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
+-              writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
+-              writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
+-      }
++      memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
++      writel((__force u32)cpu_to_be32(temp_mac[0]),
++             fep->hwp + FEC_ADDR_LOW);
++      writel((__force u32)cpu_to_be32(temp_mac[1]),
++             fep->hwp + FEC_ADDR_HIGH);
+ 
+       /* Clear any outstanding interrupt. */
+       writel(0xffffffff, fep->hwp + FEC_IEVENT);
+diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
+index 69e31e2a68fc..4827c6987ac3 100644
+--- a/drivers/net/geneve.c
++++ b/drivers/net/geneve.c
+@@ -440,7 +440,7 @@ static struct sk_buff **geneve_gro_receive(struct sk_buff 
**head,
+ 
+       skb_gro_pull(skb, gh_len);
+       skb_gro_postpull_rcsum(skb, gh, gh_len);
+-      pp = ptype->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
+index 003780901628..6fa8e165878e 100644
+--- a/drivers/net/vxlan.c
++++ b/drivers/net/vxlan.c
+@@ -593,7 +593,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff 
**head,
+               }
+       }
+ 
+-      pp = eth_gro_receive(head, skb);
++      pp = call_gro_receive(eth_gro_receive, head, skb);
+ 
+ out:
+       skb_gro_remcsum_cleanup(skb, &grc);
+diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
+index ed01c0172e4a..07dd81586c52 100644
+--- a/drivers/of/of_reserved_mem.c
++++ b/drivers/of/of_reserved_mem.c
+@@ -127,8 +127,12 @@ static int __init __reserved_mem_alloc_size(unsigned long 
node,
+       }
+ 
+       /* Need adjust the alignment to satisfy the CMA requirement */
+-      if (IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, 
"shared-dma-pool"))
+-              align = max(align, (phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, 
pageblock_order));
++      if (IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, 
"shared-dma-pool")) {
++              unsigned long order =
++                      max_t(unsigned long, MAX_ORDER - 1, pageblock_order);
++
++              align = max(align, (phys_addr_t)PAGE_SIZE << order);
++      }
+ 
+       prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
+       if (prop) {
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h 
b/drivers/scsi/megaraid/megaraid_sas.h
+index ef4ff03242ea..aaf7da07a358 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -1923,7 +1923,7 @@ struct megasas_instance_template {
+ };
+ 
+ #define MEGASAS_IS_LOGICAL(scp)                                               
\
+-      (scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
++      ((scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1)
+ 
+ #define MEGASAS_DEV_INDEX(scp)                                                
\
+       (((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +   \
+diff --git a/include/linux/mroute.h b/include/linux/mroute.h
+index 79aaa9fc1a15..d5277fc3ce2e 100644
+--- a/include/linux/mroute.h
++++ b/include/linux/mroute.h
+@@ -103,5 +103,5 @@ struct mfc_cache {
+ struct rtmsg;
+ extern int ipmr_get_route(struct net *net, struct sk_buff *skb,
+                         __be32 saddr, __be32 daddr,
+-                        struct rtmsg *rtm, int nowait);
++                        struct rtmsg *rtm, int nowait, u32 portid);
+ #endif
+diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h
+index 66982e764051..f831155dc7d1 100644
+--- a/include/linux/mroute6.h
++++ b/include/linux/mroute6.h
+@@ -115,7 +115,7 @@ struct mfc6_cache {
+ 
+ struct rtmsg;
+ extern int ip6mr_get_route(struct net *net, struct sk_buff *skb,
+-                         struct rtmsg *rtm, int nowait);
++                         struct rtmsg *rtm, int nowait, u32 portid);
+ 
+ #ifdef CONFIG_IPV6_MROUTE
+ extern struct sock *mroute6_socket(struct net *net, struct sk_buff *skb);
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 12b4d54a8ffa..9d6025703f73 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -2003,7 +2003,10 @@ struct napi_gro_cb {
+       /* Used in foo-over-udp, set in udp[46]_gro_receive */
+       u8      is_ipv6:1;
+ 
+-      /* 7 bit hole */
++      /* Number of gro_receive callbacks this packet already went through */
++      u8 recursion_counter:4;
++
++      /* 3 bit hole */
+ 
+       /* used to support CHECKSUM_COMPLETE for tunneling protocols */
+       __wsum  csum;
+@@ -2014,6 +2017,25 @@ struct napi_gro_cb {
+ 
+ #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
+ 
++#define GRO_RECURSION_LIMIT 15
++static inline int gro_recursion_inc_test(struct sk_buff *skb)
++{
++      return ++NAPI_GRO_CB(skb)->recursion_counter == GRO_RECURSION_LIMIT;
++}
++
++typedef struct sk_buff **(*gro_receive_t)(struct sk_buff **, struct sk_buff 
*);
++static inline struct sk_buff **call_gro_receive(gro_receive_t cb,
++                                              struct sk_buff **head,
++                                              struct sk_buff *skb)
++{
++      if (unlikely(gro_recursion_inc_test(skb))) {
++              NAPI_GRO_CB(skb)->flush |= 1;
++              return NULL;
++      }
++
++      return cb(head, skb);
++}
++
+ struct packet_type {
+       __be16                  type;   /* This is really htons(ether_type). */
+       struct net_device       *dev;   /* NULL is wildcarded here           */
+@@ -2059,6 +2081,22 @@ struct udp_offload {
+       struct udp_offload_callbacks callbacks;
+ };
+ 
++typedef struct sk_buff **(*gro_receive_udp_t)(struct sk_buff **,
++                                            struct sk_buff *,
++                                            struct udp_offload *);
++static inline struct sk_buff **call_gro_receive_udp(gro_receive_udp_t cb,
++                                                  struct sk_buff **head,
++                                                  struct sk_buff *skb,
++                                                  struct udp_offload *uoff)
++{
++      if (unlikely(gro_recursion_inc_test(skb))) {
++              NAPI_GRO_CB(skb)->flush |= 1;
++              return NULL;
++      }
++
++      return cb(head, skb, uoff);
++}
++
+ /* often modified stats are per cpu, other are shared (netdev->stats) */
+ struct pcpu_sw_netstats {
+       u64     rx_packets;
+diff --git a/include/net/ip.h b/include/net/ip.h
+index 1a98f1ca1638..b450d8653b30 100644
+--- a/include/net/ip.h
++++ b/include/net/ip.h
+@@ -553,7 +553,7 @@ int ip_options_rcv_srr(struct sk_buff *skb);
+  */
+ 
+ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb);
+-void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int offset);
++void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int tlen, 
int offset);
+ int ip_cmsg_send(struct net *net, struct msghdr *msg,
+                struct ipcm_cookie *ipc, bool allow_ipv6);
+ int ip_setsockopt(struct sock *sk, int level, int optname, char __user 
*optval,
+@@ -575,7 +575,7 @@ void ip_local_error(struct sock *sk, int err, __be32 
daddr, __be16 dport,
+ 
+ static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
+ {
+-      ip_cmsg_recv_offset(msg, skb, 0);
++      ip_cmsg_recv_offset(msg, skb, 0, 0);
+ }
+ 
+ bool icmp_global_allow(void);
+diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
+index 86df0835f6b5..e5bba897d206 100644
+--- a/include/net/sch_generic.h
++++ b/include/net/sch_generic.h
+@@ -408,6 +408,15 @@ bool tcf_destroy(struct tcf_proto *tp, bool force);
+ void tcf_destroy_chain(struct tcf_proto __rcu **fl);
+ int skb_do_redirect(struct sk_buff *);
+ 
++static inline bool skb_at_tc_ingress(const struct sk_buff *skb)
++{
++#ifdef CONFIG_NET_CLS_ACT
++      return G_TC_AT(skb->tc_verd) & AT_INGRESS;
++#else
++      return false;
++#endif
++}
++
+ /* Reset all TX qdiscs greater then index of a device.  */
+ static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int 
i)
+ {
+diff --git a/include/net/sock.h b/include/net/sock.h
+index 14d3c0734007..3d5ff7436f41 100644
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -1425,6 +1425,16 @@ static inline void sk_mem_uncharge(struct sock *sk, int 
size)
+       if (!sk_has_account(sk))
+               return;
+       sk->sk_forward_alloc += size;
++
++      /* Avoid a possible overflow.
++       * TCP send queues can make this happen, if sk_mem_reclaim()
++       * is not called and more than 2 GBytes are released at once.
++       *
++       * If we reach 2 MBytes, reclaim 1 MBytes right now, there is
++       * no need to hold that much forward allocation anyway.
++       */
++      if (unlikely(sk->sk_forward_alloc >= 1 << 21))
++              __sk_mem_reclaim(sk, 1 << 20);
+ }
+ 
+ static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
+diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
+index 123a5af4e8bb..fa3b34365560 100644
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -343,7 +343,7 @@ struct rtnexthop {
+ #define RTNH_F_OFFLOAD                8       /* offloaded route */
+ #define RTNH_F_LINKDOWN               16      /* carrier-down on nexthop */
+ 
+-#define RTNH_COMPARE_MASK     (RTNH_F_DEAD | RTNH_F_LINKDOWN)
++#define RTNH_COMPARE_MASK     (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD)
+ 
+ /* Macros to handle hexthops */
+ 
+diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
+index d2cd9de4b724..ad8d6e6b87ca 100644
+--- a/net/8021q/vlan.c
++++ b/net/8021q/vlan.c
+@@ -659,7 +659,7 @@ static struct sk_buff **vlan_gro_receive(struct sk_buff 
**head,
+ 
+       skb_gro_pull(skb, sizeof(*vhdr));
+       skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
+-      pp = ptype->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
+index 9542e84a9455..d80c15d028fe 100644
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -951,13 +951,12 @@ static void br_multicast_enable(struct 
bridge_mcast_own_query *query)
+               mod_timer(&query->timer, jiffies);
+ }
+ 
+-void br_multicast_enable_port(struct net_bridge_port *port)
++static void __br_multicast_enable_port(struct net_bridge_port *port)
+ {
+       struct net_bridge *br = port->br;
+ 
+-      spin_lock(&br->multicast_lock);
+       if (br->multicast_disabled || !netif_running(br->dev))
+-              goto out;
++              return;
+ 
+       br_multicast_enable(&port->ip4_own_query);
+ #if IS_ENABLED(CONFIG_IPV6)
+@@ -965,8 +964,14 @@ void br_multicast_enable_port(struct net_bridge_port 
*port)
+ #endif
+       if (port->multicast_router == 2 && hlist_unhashed(&port->rlist))
+               br_multicast_add_router(br, port);
++}
+ 
+-out:
++void br_multicast_enable_port(struct net_bridge_port *port)
++{
++      struct net_bridge *br = port->br;
++
++      spin_lock(&br->multicast_lock);
++      __br_multicast_enable_port(port);
+       spin_unlock(&br->multicast_lock);
+ }
+ 
+@@ -1905,8 +1910,9 @@ static void br_multicast_start_querier(struct net_bridge 
*br,
+ 
+ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
+ {
+-      int err = 0;
+       struct net_bridge_mdb_htable *mdb;
++      struct net_bridge_port *port;
++      int err = 0;
+ 
+       spin_lock_bh(&br->multicast_lock);
+       if (br->multicast_disabled == !val)
+@@ -1934,10 +1940,9 @@ rollback:
+                       goto rollback;
+       }
+ 
+-      br_multicast_start_querier(br, &br->ip4_own_query);
+-#if IS_ENABLED(CONFIG_IPV6)
+-      br_multicast_start_querier(br, &br->ip6_own_query);
+-#endif
++      br_multicast_open(br);
++      list_for_each_entry(port, &br->port_list, list)
++              __br_multicast_enable_port(port);
+ 
+ unlock:
+       spin_unlock_bh(&br->multicast_lock);
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 0989fea88c44..b3fa4b86ab4c 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -2836,6 +2836,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff 
*skb, struct net_device *d
+       }
+       return head;
+ }
++EXPORT_SYMBOL_GPL(validate_xmit_skb_list);
+ 
+ static void qdisc_pkt_len_init(struct sk_buff *skb)
+ {
+@@ -4240,6 +4241,7 @@ static enum gro_result dev_gro_receive(struct 
napi_struct *napi, struct sk_buff
+               NAPI_GRO_CB(skb)->flush = 0;
+               NAPI_GRO_CB(skb)->free = 0;
+               NAPI_GRO_CB(skb)->encap_mark = 0;
++              NAPI_GRO_CB(skb)->recursion_counter = 0;
+               NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
+ 
+               /* Setup for GRO checksum validation */
+@@ -5204,6 +5206,7 @@ static inline bool netdev_adjacent_is_neigh_list(struct 
net_device *dev,
+ 
+ static int __netdev_adjacent_dev_insert(struct net_device *dev,
+                                       struct net_device *adj_dev,
++                                      u16 ref_nr,
+                                       struct list_head *dev_list,
+                                       void *private, bool master)
+ {
+@@ -5213,7 +5216,7 @@ static int __netdev_adjacent_dev_insert(struct 
net_device *dev,
+       adj = __netdev_find_adj(adj_dev, dev_list);
+ 
+       if (adj) {
+-              adj->ref_nr++;
++              adj->ref_nr += ref_nr;
+               return 0;
+       }
+ 
+@@ -5223,7 +5226,7 @@ static int __netdev_adjacent_dev_insert(struct 
net_device *dev,
+ 
+       adj->dev = adj_dev;
+       adj->master = master;
+-      adj->ref_nr = 1;
++      adj->ref_nr = ref_nr;
+       adj->private = private;
+       dev_hold(adj_dev);
+ 
+@@ -5262,6 +5265,7 @@ free_adj:
+ 
+ static void __netdev_adjacent_dev_remove(struct net_device *dev,
+                                        struct net_device *adj_dev,
++                                       u16 ref_nr,
+                                        struct list_head *dev_list)
+ {
+       struct netdev_adjacent *adj;
+@@ -5274,10 +5278,10 @@ static void __netdev_adjacent_dev_remove(struct 
net_device *dev,
+               BUG();
+       }
+ 
+-      if (adj->ref_nr > 1) {
+-              pr_debug("%s to %s ref_nr-- = %d\n", dev->name, adj_dev->name,
+-                       adj->ref_nr-1);
+-              adj->ref_nr--;
++      if (adj->ref_nr > ref_nr) {
++              pr_debug("%s to %s ref_nr-%d = %d\n", dev->name, adj_dev->name,
++                       ref_nr, adj->ref_nr-ref_nr);
++              adj->ref_nr -= ref_nr;
+               return;
+       }
+ 
+@@ -5296,21 +5300,22 @@ static void __netdev_adjacent_dev_remove(struct 
net_device *dev,
+ 
+ static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
+                                           struct net_device *upper_dev,
++                                          u16 ref_nr,
+                                           struct list_head *up_list,
+                                           struct list_head *down_list,
+                                           void *private, bool master)
+ {
+       int ret;
+ 
+-      ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, private,
+-                                         master);
++      ret = __netdev_adjacent_dev_insert(dev, upper_dev, ref_nr, up_list,
++                                         private, master);
+       if (ret)
+               return ret;
+ 
+-      ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, private,
+-                                         false);
++      ret = __netdev_adjacent_dev_insert(upper_dev, dev, ref_nr, down_list,
++                                         private, false);
+       if (ret) {
+-              __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
++              __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
+               return ret;
+       }
+ 
+@@ -5318,9 +5323,10 @@ static int __netdev_adjacent_dev_link_lists(struct 
net_device *dev,
+ }
+ 
+ static int __netdev_adjacent_dev_link(struct net_device *dev,
+-                                    struct net_device *upper_dev)
++                                    struct net_device *upper_dev,
++                                    u16 ref_nr)
+ {
+-      return __netdev_adjacent_dev_link_lists(dev, upper_dev,
++      return __netdev_adjacent_dev_link_lists(dev, upper_dev, ref_nr,
+                                               &dev->all_adj_list.upper,
+                                               &upper_dev->all_adj_list.lower,
+                                               NULL, false);
+@@ -5328,17 +5334,19 @@ static int __netdev_adjacent_dev_link(struct 
net_device *dev,
+ 
+ static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev,
+                                              struct net_device *upper_dev,
++                                             u16 ref_nr,
+                                              struct list_head *up_list,
+                                              struct list_head *down_list)
+ {
+-      __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
+-      __netdev_adjacent_dev_remove(upper_dev, dev, down_list);
++      __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
++      __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list);
+ }
+ 
+ static void __netdev_adjacent_dev_unlink(struct net_device *dev,
+-                                       struct net_device *upper_dev)
++                                       struct net_device *upper_dev,
++                                       u16 ref_nr)
+ {
+-      __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
++      __netdev_adjacent_dev_unlink_lists(dev, upper_dev, ref_nr,
+                                          &dev->all_adj_list.upper,
+                                          &upper_dev->all_adj_list.lower);
+ }
+@@ -5347,17 +5355,17 @@ static int __netdev_adjacent_dev_link_neighbour(struct 
net_device *dev,
+                                               struct net_device *upper_dev,
+                                               void *private, bool master)
+ {
+-      int ret = __netdev_adjacent_dev_link(dev, upper_dev);
++      int ret = __netdev_adjacent_dev_link(dev, upper_dev, 1);
+ 
+       if (ret)
+               return ret;
+ 
+-      ret = __netdev_adjacent_dev_link_lists(dev, upper_dev,
++      ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, 1,
+                                              &dev->adj_list.upper,
+                                              &upper_dev->adj_list.lower,
+                                              private, master);
+       if (ret) {
+-              __netdev_adjacent_dev_unlink(dev, upper_dev);
++              __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
+               return ret;
+       }
+ 
+@@ -5367,8 +5375,8 @@ static int __netdev_adjacent_dev_link_neighbour(struct 
net_device *dev,
+ static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
+                                                  struct net_device *upper_dev)
+ {
+-      __netdev_adjacent_dev_unlink(dev, upper_dev);
+-      __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
++      __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
++      __netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1,
+                                          &dev->adj_list.upper,
+                                          &upper_dev->adj_list.lower);
+ }
+@@ -5420,7 +5428,7 @@ static int __netdev_upper_dev_link(struct net_device 
*dev,
+               list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
+                       pr_debug("Interlinking %s with %s, non-neighbour\n",
+                                i->dev->name, j->dev->name);
+-                      ret = __netdev_adjacent_dev_link(i->dev, j->dev);
++                      ret = __netdev_adjacent_dev_link(i->dev, j->dev, 
i->ref_nr);
+                       if (ret)
+                               goto rollback_mesh;
+               }
+@@ -5430,7 +5438,7 @@ static int __netdev_upper_dev_link(struct net_device 
*dev,
+       list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
+               pr_debug("linking %s's upper device %s with %s\n",
+                        upper_dev->name, i->dev->name, dev->name);
+-              ret = __netdev_adjacent_dev_link(dev, i->dev);
++              ret = __netdev_adjacent_dev_link(dev, i->dev, i->ref_nr);
+               if (ret)
+                       goto rollback_upper_mesh;
+       }
+@@ -5439,7 +5447,7 @@ static int __netdev_upper_dev_link(struct net_device 
*dev,
+       list_for_each_entry(i, &dev->all_adj_list.lower, list) {
+               pr_debug("linking %s's lower device %s with %s\n", dev->name,
+                        i->dev->name, upper_dev->name);
+-              ret = __netdev_adjacent_dev_link(i->dev, upper_dev);
++              ret = __netdev_adjacent_dev_link(i->dev, upper_dev, i->ref_nr);
+               if (ret)
+                       goto rollback_lower_mesh;
+       }
+@@ -5453,7 +5461,7 @@ rollback_lower_mesh:
+       list_for_each_entry(i, &dev->all_adj_list.lower, list) {
+               if (i == to_i)
+                       break;
+-              __netdev_adjacent_dev_unlink(i->dev, upper_dev);
++              __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
+       }
+ 
+       i = NULL;
+@@ -5463,7 +5471,7 @@ rollback_upper_mesh:
+       list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
+               if (i == to_i)
+                       break;
+-              __netdev_adjacent_dev_unlink(dev, i->dev);
++              __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
+       }
+ 
+       i = j = NULL;
+@@ -5475,7 +5483,7 @@ rollback_mesh:
+               list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
+                       if (i == to_i && j == to_j)
+                               break;
+-                      __netdev_adjacent_dev_unlink(i->dev, j->dev);
++                      __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
+               }
+               if (i == to_i)
+                       break;
+@@ -5559,16 +5567,16 @@ void netdev_upper_dev_unlink(struct net_device *dev,
+        */
+       list_for_each_entry(i, &dev->all_adj_list.lower, list)
+               list_for_each_entry(j, &upper_dev->all_adj_list.upper, list)
+-                      __netdev_adjacent_dev_unlink(i->dev, j->dev);
++                      __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
+ 
+       /* remove also the devices itself from lower/upper device
+        * list
+        */
+       list_for_each_entry(i, &dev->all_adj_list.lower, list)
+-              __netdev_adjacent_dev_unlink(i->dev, upper_dev);
++              __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
+ 
+       list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
+-              __netdev_adjacent_dev_unlink(dev, i->dev);
++              __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
+ 
+       call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
+                                     &changeupper_info.info);
+diff --git a/net/core/pktgen.c b/net/core/pktgen.c
+index 4da4d51a2ccf..b6327601f979 100644
+--- a/net/core/pktgen.c
++++ b/net/core/pktgen.c
+@@ -215,8 +215,8 @@
+ #define M_NETIF_RECEIVE       1       /* Inject packets into stack */
+ 
+ /* If lock -- protects updating of if_list */
+-#define   if_lock(t)           spin_lock(&(t->if_lock));
+-#define   if_unlock(t)           spin_unlock(&(t->if_lock));
++#define   if_lock(t)           mutex_lock(&(t->if_lock));
++#define   if_unlock(t)           mutex_unlock(&(t->if_lock));
+ 
+ /* Used to help with determining the pkts on receive */
+ #define PKTGEN_MAGIC 0xbe9be955
+@@ -422,7 +422,7 @@ struct pktgen_net {
+ };
+ 
+ struct pktgen_thread {
+-      spinlock_t if_lock;             /* for list of devices */
++      struct mutex if_lock;           /* for list of devices */
+       struct list_head if_list;       /* All device here */
+       struct list_head th_list;
+       struct task_struct *tsk;
+@@ -2002,11 +2002,13 @@ static void pktgen_change_name(const struct pktgen_net 
*pn, struct net_device *d
+ {
+       struct pktgen_thread *t;
+ 
++      mutex_lock(&pktgen_thread_lock);
++
+       list_for_each_entry(t, &pn->pktgen_threads, th_list) {
+               struct pktgen_dev *pkt_dev;
+ 
+-              rcu_read_lock();
+-              list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
++              if_lock(t);
++              list_for_each_entry(pkt_dev, &t->if_list, list) {
+                       if (pkt_dev->odev != dev)
+                               continue;
+ 
+@@ -2021,8 +2023,9 @@ static void pktgen_change_name(const struct pktgen_net 
*pn, struct net_device *d
+                                      dev->name);
+                       break;
+               }
+-              rcu_read_unlock();
++              if_unlock(t);
+       }
++      mutex_unlock(&pktgen_thread_lock);
+ }
+ 
+ static int pktgen_device_event(struct notifier_block *unused,
+@@ -2278,7 +2281,7 @@ static void spin(struct pktgen_dev *pkt_dev, ktime_t 
spin_until)
+ 
+ static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
+ {
+-      pkt_dev->pkt_overhead = LL_RESERVED_SPACE(pkt_dev->odev);
++      pkt_dev->pkt_overhead = 0;
+       pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
+       pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
+       pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
+@@ -2769,13 +2772,13 @@ static void pktgen_finalize_skb(struct pktgen_dev 
*pkt_dev, struct sk_buff *skb,
+ }
+ 
+ static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
+-                                      struct pktgen_dev *pkt_dev,
+-                                      unsigned int extralen)
++                                      struct pktgen_dev *pkt_dev)
+ {
++      unsigned int extralen = LL_RESERVED_SPACE(dev);
+       struct sk_buff *skb = NULL;
+-      unsigned int size = pkt_dev->cur_pkt_size + 64 + extralen +
+-                          pkt_dev->pkt_overhead;
++      unsigned int size;
+ 
++      size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead;
+       if (pkt_dev->flags & F_NODE) {
+               int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id();
+ 
+@@ -2788,8 +2791,9 @@ static struct sk_buff *pktgen_alloc_skb(struct 
net_device *dev,
+                skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
+       }
+ 
++      /* the caller pre-fetches from skb->data and reserves for the mac hdr */
+       if (likely(skb))
+-              skb_reserve(skb, LL_RESERVED_SPACE(dev));
++              skb_reserve(skb, extralen - 16);
+ 
+       return skb;
+ }
+@@ -2822,16 +2826,14 @@ static struct sk_buff *fill_packet_ipv4(struct 
net_device *odev,
+       mod_cur_headers(pkt_dev);
+       queue_map = pkt_dev->cur_queue_map;
+ 
+-      datalen = (odev->hard_header_len + 16) & ~0xf;
+-
+-      skb = pktgen_alloc_skb(odev, pkt_dev, datalen);
++      skb = pktgen_alloc_skb(odev, pkt_dev);
+       if (!skb) {
+               sprintf(pkt_dev->result, "No memory");
+               return NULL;
+       }
+ 
+       prefetchw(skb->data);
+-      skb_reserve(skb, datalen);
++      skb_reserve(skb, 16);
+ 
+       /*  Reserve for ethernet and IP header  */
+       eth = (__u8 *) skb_push(skb, 14);
+@@ -2951,7 +2953,7 @@ static struct sk_buff *fill_packet_ipv6(struct 
net_device *odev,
+       mod_cur_headers(pkt_dev);
+       queue_map = pkt_dev->cur_queue_map;
+ 
+-      skb = pktgen_alloc_skb(odev, pkt_dev, 16);
++      skb = pktgen_alloc_skb(odev, pkt_dev);
+       if (!skb) {
+               sprintf(pkt_dev->result, "No memory");
+               return NULL;
+@@ -3727,7 +3729,7 @@ static int __net_init pktgen_create_thread(int cpu, 
struct pktgen_net *pn)
+               return -ENOMEM;
+       }
+ 
+-      spin_lock_init(&t->if_lock);
++      mutex_init(&t->if_lock);
+       t->cpu = cpu;
+ 
+       INIT_LIST_HEAD(&t->if_list);
+diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
+index 9e63f252a89e..de85d4e1cf43 100644
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -436,7 +436,7 @@ struct sk_buff **eth_gro_receive(struct sk_buff **head,
+ 
+       skb_gro_pull(skb, sizeof(*eh));
+       skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
+-      pp = ptype->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
+index 1a5c1ca3ad3c..afc18e9ca94a 100644
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -1372,7 +1372,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff 
**head,
+       skb_gro_pull(skb, sizeof(*iph));
+       skb_set_transport_header(skb, skb_gro_offset(skb));
+ 
+-      pp = ops->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
+index 08d7de55e57e..08d8ee124538 100644
+--- a/net/ipv4/fou.c
++++ b/net/ipv4/fou.c
+@@ -201,7 +201,7 @@ static struct sk_buff **fou_gro_receive(struct sk_buff 
**head,
+       if (!ops || !ops->callbacks.gro_receive)
+               goto out_unlock;
+ 
+-      pp = ops->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+@@ -360,7 +360,7 @@ static struct sk_buff **gue_gro_receive(struct sk_buff 
**head,
+       if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
+               goto out_unlock;
+ 
+-      pp = ops->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
+index e603004c1af8..79ae0d7becbf 100644
+--- a/net/ipv4/gre_offload.c
++++ b/net/ipv4/gre_offload.c
+@@ -219,7 +219,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff 
**head,
+       /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/
+       skb_gro_postpull_rcsum(skb, greh, grehlen);
+ 
+-      pp = ptype->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
+index a50124260f5a..9ce202549e7a 100644
+--- a/net/ipv4/ip_sockglue.c
++++ b/net/ipv4/ip_sockglue.c
+@@ -98,7 +98,7 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct 
sk_buff *skb)
+ }
+ 
+ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
+-                                int offset)
++                                int tlen, int offset)
+ {
+       __wsum csum = skb->csum;
+ 
+@@ -106,7 +106,9 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, 
struct sk_buff *skb,
+               return;
+ 
+       if (offset != 0)
+-              csum = csum_sub(csum, csum_partial(skb->data, offset, 0));
++              csum = csum_sub(csum,
++                              csum_partial(skb->data + tlen,
++                                           offset, 0));
+ 
+       put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum);
+ }
+@@ -152,7 +154,7 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, 
struct sk_buff *skb)
+ }
+ 
+ void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb,
+-                       int offset)
++                       int tlen, int offset)
+ {
+       struct inet_sock *inet = inet_sk(skb->sk);
+       unsigned int flags = inet->cmsg_flags;
+@@ -215,7 +217,7 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct 
sk_buff *skb,
+       }
+ 
+       if (flags & IP_CMSG_CHECKSUM)
+-              ip_cmsg_recv_checksum(msg, skb, offset);
++              ip_cmsg_recv_checksum(msg, skb, tlen, offset);
+ }
+ EXPORT_SYMBOL(ip_cmsg_recv_offset);
+ 
+diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
+index 9d1e555496e3..8e77786549c6 100644
+--- a/net/ipv4/ipmr.c
++++ b/net/ipv4/ipmr.c
+@@ -2192,7 +2192,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, 
struct sk_buff *skb,
+ 
+ int ipmr_get_route(struct net *net, struct sk_buff *skb,
+                  __be32 saddr, __be32 daddr,
+-                 struct rtmsg *rtm, int nowait)
++                 struct rtmsg *rtm, int nowait, u32 portid)
+ {
+       struct mfc_cache *cache;
+       struct mr_table *mrt;
+@@ -2237,6 +2237,7 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
+                       return -ENOMEM;
+               }
+ 
++              NETLINK_CB(skb2).portid = portid;
+               skb_push(skb2, sizeof(struct iphdr));
+               skb_reset_network_header(skb2);
+               iph = ip_hdr(skb2);
+diff --git a/net/ipv4/route.c b/net/ipv4/route.c
+index b050cf980a57..8533a75a9328 100644
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -2492,7 +2492,8 @@ static int rt_fill_info(struct net *net,  __be32 dst, 
__be32 src, u32 table_id,
+                   IPV4_DEVCONF_ALL(net, MC_FORWARDING)) {
+                       int err = ipmr_get_route(net, skb,
+                                                fl4->saddr, fl4->daddr,
+-                                               r, nowait);
++                                               r, nowait, portid);
++
+                       if (err <= 0) {
+                               if (!nowait) {
+                                       if (err == 0)
+diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
+index a0bd7a55193e..70fb352e317f 100644
+--- a/net/ipv4/sysctl_net_ipv4.c
++++ b/net/ipv4/sysctl_net_ipv4.c
+@@ -97,11 +97,11 @@ static void inet_get_ping_group_range_table(struct 
ctl_table *table, kgid_t *low
+               container_of(table->data, struct net, 
ipv4.ping_group_range.range);
+       unsigned int seq;
+       do {
+-              seq = read_seqbegin(&net->ipv4.ip_local_ports.lock);
++              seq = read_seqbegin(&net->ipv4.ping_group_range.lock);
+ 
+               *low = data[0];
+               *high = data[1];
+-      } while (read_seqretry(&net->ipv4.ip_local_ports.lock, seq));
++      } while (read_seqretry(&net->ipv4.ping_group_range.lock, seq));
+ }
+ 
+ /* Update system visible IP port range */
+@@ -110,10 +110,10 @@ static void set_ping_group_range(struct ctl_table 
*table, kgid_t low, kgid_t hig
+       kgid_t *data = table->data;
+       struct net *net =
+               container_of(table->data, struct net, 
ipv4.ping_group_range.range);
+-      write_seqlock(&net->ipv4.ip_local_ports.lock);
++      write_seqlock(&net->ipv4.ping_group_range.lock);
+       data[0] = low;
+       data[1] = high;
+-      write_sequnlock(&net->ipv4.ip_local_ports.lock);
++      write_sequnlock(&net->ipv4.ping_group_range.lock);
+ }
+ 
+ /* Validate changes from /proc interface. */
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 12b98e257c5f..7cc0f8aac28f 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -2324,10 +2324,9 @@ static void DBGUNDO(struct sock *sk, const char *msg)
+       }
+ #if IS_ENABLED(CONFIG_IPV6)
+       else if (sk->sk_family == AF_INET6) {
+-              struct ipv6_pinfo *np = inet6_sk(sk);
+               pr_debug("Undo %s %pI6/%u c%u l%u ss%u/%u p%u\n",
+                        msg,
+-                       &np->daddr, ntohs(inet->inet_dport),
++                       &sk->sk_v6_daddr, ntohs(inet->inet_dport),
+                        tp->snd_cwnd, tcp_left_out(tp),
+                        tp->snd_ssthresh, tp->prior_ssthresh,
+                        tp->packets_out);
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
+index 660c967ba84a..0795647e94c6 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -1950,12 +1950,14 @@ static int tcp_mtu_probe(struct sock *sk)
+       len = 0;
+       tcp_for_write_queue_from_safe(skb, next, sk) {
+               copy = min_t(int, skb->len, probe_size - len);
+-              if (nskb->ip_summed)
++              if (nskb->ip_summed) {
+                       skb_copy_bits(skb, 0, skb_put(nskb, copy), copy);
+-              else
+-                      nskb->csum = skb_copy_and_csum_bits(skb, 0,
+-                                                          skb_put(nskb, copy),
+-                                                          copy, nskb->csum);
++              } else {
++                      __wsum csum = skb_copy_and_csum_bits(skb, 0,
++                                                           skb_put(nskb, 
copy),
++                                                           copy, 0);
++                      nskb->csum = csum_block_add(nskb->csum, csum, len);
++              }
+ 
+               if (skb->len <= copy) {
+                       /* We've eaten all the data from this skb.
+@@ -2569,7 +2571,8 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff 
*skb)
+        * copying overhead: fragmentation, tunneling, mangling etc.
+        */
+       if (atomic_read(&sk->sk_wmem_alloc) >
+-          min(sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), sk->sk_sndbuf))
++          min_t(u32, sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2),
++                sk->sk_sndbuf))
+               return -EAGAIN;
+ 
+       if (skb_still_in_host_queue(sk, skb))
+diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
+index 0b1ea5abcc04..e9513e397c4f 100644
+--- a/net/ipv4/udp.c
++++ b/net/ipv4/udp.c
+@@ -1342,7 +1342,7 @@ try_again:
+               *addr_len = sizeof(*sin);
+       }
+       if (inet->cmsg_flags)
+-              ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr));
++              ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr), off);
+ 
+       err = copied;
+       if (flags & MSG_TRUNC)
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 0e36e56dfd22..6396f1c80ae9 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -339,8 +339,8 @@ unflush:
+       skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp 
header */
+       skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
+       NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto;
+-      pp = uo_priv->offload->callbacks.gro_receive(head, skb,
+-                                                   uo_priv->offload);
++      pp = call_gro_receive_udp(uo_priv->offload->callbacks.gro_receive,
++                                head, skb, uo_priv->offload);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index 036b39eb1220..cb8bb5988c03 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -2916,7 +2916,7 @@ static void init_loopback(struct net_device *dev)
+                                * lo device down, release this obsolete dst and
+                                * reallocate a new router for ifa.
+                                */
+-                              if (sp_ifa->rt->dst.obsolete > 0) {
++                              if (!atomic_read(&sp_ifa->rt->rt6i_ref)) {
+                                       ip6_rt_put(sp_ifa->rt);
+                                       sp_ifa->rt = NULL;
+                               } else {
+diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
+index 4650c6824783..17430f341073 100644
+--- a/net/ipv6/ip6_gre.c
++++ b/net/ipv6/ip6_gre.c
+@@ -886,7 +886,6 @@ static int ip6gre_xmit_other(struct sk_buff *skb, struct 
net_device *dev)
+               encap_limit = t->parms.encap_limit;
+ 
+       memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
+-      fl6.flowi6_proto = skb->protocol;
+ 
+       err = ip6gre_xmit2(skb, dev, 0, &fl6, encap_limit, &mtu);
+ 
+diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
+index 82e9f3076028..efe6268b8bc3 100644
+--- a/net/ipv6/ip6_offload.c
++++ b/net/ipv6/ip6_offload.c
+@@ -247,7 +247,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff 
**head,
+ 
+       skb_gro_postpull_rcsum(skb, iph, nlen);
+ 
+-      pp = ops->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index 3991b21e24ad..e8878886eba4 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -246,6 +246,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr 
*remote, const struct in6_
+       hash = HASH(&any, local);
+       for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+               if (ipv6_addr_equal(local, &t->parms.laddr) &&
++                  ipv6_addr_any(&t->parms.raddr) &&
+                   (t->dev->flags & IFF_UP))
+                       return t;
+       }
+@@ -253,6 +254,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr 
*remote, const struct in6_
+       hash = HASH(remote, &any);
+       for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+               if (ipv6_addr_equal(remote, &t->parms.raddr) &&
++                  ipv6_addr_any(&t->parms.laddr) &&
+                   (t->dev->flags & IFF_UP))
+                       return t;
+       }
+diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
+index e207cb2468da..d9843e5a667f 100644
+--- a/net/ipv6/ip6mr.c
++++ b/net/ipv6/ip6mr.c
+@@ -2276,8 +2276,8 @@ static int __ip6mr_fill_mroute(struct mr6_table *mrt, 
struct sk_buff *skb,
+       return 1;
+ }
+ 
+-int ip6mr_get_route(struct net *net,
+-                  struct sk_buff *skb, struct rtmsg *rtm, int nowait)
++int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
++                  int nowait, u32 portid)
+ {
+       int err;
+       struct mr6_table *mrt;
+@@ -2322,6 +2322,7 @@ int ip6mr_get_route(struct net *net,
+                       return -ENOMEM;
+               }
+ 
++              NETLINK_CB(skb2).portid = portid;
+               skb_reset_transport_header(skb2);
+ 
+               skb_put(skb2, sizeof(struct ipv6hdr));
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index 5af2cca0a46d..dbffc9de184b 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -3140,7 +3140,9 @@ static int rt6_fill_node(struct net *net,
+       if (iif) {
+ #ifdef CONFIG_IPV6_MROUTE
+               if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) {
+-                      int err = ip6mr_get_route(net, skb, rtm, nowait);
++                      int err = ip6mr_get_route(net, skb, rtm, nowait,
++                                                portid);
++
+                       if (err <= 0) {
+                               if (!nowait) {
+                                       if (err == 0)
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index 2d81e2f33ef2..fbd521fdae53 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -1179,6 +1179,16 @@ out:
+       return NULL;
+ }
+ 
++static void tcp_v6_restore_cb(struct sk_buff *skb)
++{
++      /* We need to move header back to the beginning if xfrm6_policy_check()
++       * and tcp_v6_fill_cb() are going to be called again.
++       * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
++       */
++      memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
++              sizeof(struct inet6_skb_parm));
++}
++
+ /* The socket must have it's spinlock held when we get
+  * here, unless it is a TCP_LISTEN socket.
+  *
+@@ -1308,6 +1318,7 @@ ipv6_pktoptions:
+                       np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
+               if (ipv6_opt_accepted(sk, opt_skb, 
&TCP_SKB_CB(opt_skb)->header.h6)) {
+                       skb_set_owner_r(opt_skb, sk);
++                      tcp_v6_restore_cb(opt_skb);
+                       opt_skb = xchg(&np->pktoptions, opt_skb);
+               } else {
+                       __kfree_skb(opt_skb);
+@@ -1341,15 +1352,6 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const 
struct ipv6hdr *hdr,
+       TCP_SKB_CB(skb)->sacked = 0;
+ }
+ 
+-static void tcp_v6_restore_cb(struct sk_buff *skb)
+-{
+-      /* We need to move header back to the beginning if xfrm6_policy_check()
+-       * and tcp_v6_fill_cb() are going to be called again.
+-       */
+-      memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
+-              sizeof(struct inet6_skb_parm));
+-}
+-
+ static int tcp_v6_rcv(struct sk_buff *skb)
+ {
+       const struct tcphdr *th;
+diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
+index e6092bd72ee2..dfa85e7264df 100644
+--- a/net/ipv6/udp.c
++++ b/net/ipv6/udp.c
+@@ -498,7 +498,8 @@ try_again:
+ 
+       if (is_udp4) {
+               if (inet->cmsg_flags)
+-                      ip_cmsg_recv(msg, skb);
++                      ip_cmsg_recv_offset(msg, skb,
++                                          sizeof(struct udphdr), off);
+       } else {
+               if (np->rxopt.all)
+                       ip6_datagram_recv_specific_ctl(sk, msg, skb);
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index 7a5fa0c98377..28fc283c1ec1 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -2557,7 +2557,7 @@ static int netlink_recvmsg(struct socket *sock, struct 
msghdr *msg, size_t len,
+       /* Record the max length of recvmsg() calls for future allocations */
+       nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len);
+       nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len,
+-                                   16384);
++                                   SKB_WITH_OVERHEAD(32768));
+ 
+       copied = data_skb->len;
+       if (len < copied) {
+@@ -2810,14 +2810,13 @@ static int netlink_dump(struct sock *sk)
+       if (alloc_min_size < nlk->max_recvmsg_len) {
+               alloc_size = nlk->max_recvmsg_len;
+               skb = netlink_alloc_skb(sk, alloc_size, nlk->portid,
+-                                      GFP_KERNEL |
+-                                      __GFP_NOWARN |
+-                                      __GFP_NORETRY);
++                                      (GFP_KERNEL & ~__GFP_DIRECT_RECLAIM) |
++                                      __GFP_NOWARN | __GFP_NORETRY);
+       }
+       if (!skb) {
+               alloc_size = alloc_min_size;
+               skb = netlink_alloc_skb(sk, alloc_size, nlk->portid,
+-                                      GFP_KERNEL);
++                                      (GFP_KERNEL & ~__GFP_DIRECT_RECLAIM));
+       }
+       if (!skb)
+               goto errout_skb;
+diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
+index a86f26d05bc2..34e4fcfd240b 100644
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -249,7 +249,7 @@ static void __fanout_link(struct sock *sk, struct 
packet_sock *po);
+ static int packet_direct_xmit(struct sk_buff *skb)
+ {
+       struct net_device *dev = skb->dev;
+-      netdev_features_t features;
++      struct sk_buff *orig_skb = skb;
+       struct netdev_queue *txq;
+       int ret = NETDEV_TX_BUSY;
+ 
+@@ -257,9 +257,8 @@ static int packet_direct_xmit(struct sk_buff *skb)
+                    !netif_carrier_ok(dev)))
+               goto drop;
+ 
+-      features = netif_skb_features(skb);
+-      if (skb_needs_linearize(skb, features) &&
+-          __skb_linearize(skb))
++      skb = validate_xmit_skb_list(skb, dev);
++      if (skb != orig_skb)
+               goto drop;
+ 
+       txq = skb_get_tx_queue(dev, skb);
+@@ -279,7 +278,7 @@ static int packet_direct_xmit(struct sk_buff *skb)
+       return ret;
+ drop:
+       atomic_long_inc(&dev->tx_dropped);
+-      kfree_skb(skb);
++      kfree_skb_list(skb);
+       return NET_XMIT_DROP;
+ }
+ 
+@@ -3855,6 +3854,7 @@ static int packet_notifier(struct notifier_block *this,
+                               }
+                               if (msg == NETDEV_UNREGISTER) {
+                                       packet_cached_dev_reset(po);
++                                      fanout_release(sk);
+                                       po->ifindex = -1;
+                                       if (po->prot_hook.dev)
+                                               dev_put(po->prot_hook.dev);
+diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
+index 796785e0bf96..d7edba4536bd 100644
+--- a/net/sched/act_vlan.c
++++ b/net/sched/act_vlan.c
+@@ -33,6 +33,12 @@ static int tcf_vlan(struct sk_buff *skb, const struct 
tc_action *a,
+       bstats_update(&v->tcf_bstats, skb);
+       action = v->tcf_action;
+ 
++      /* Ensure 'data' points at mac_header prior calling vlan manipulating
++       * functions.
++       */
++      if (skb_at_tc_ingress(skb))
++              skb_push_rcsum(skb, skb->mac_len);
++
+       switch (v->tcfv_action) {
+       case TCA_VLAN_ACT_POP:
+               err = skb_vlan_pop(skb);
+@@ -54,6 +60,9 @@ drop:
+       action = TC_ACT_SHOT;
+       v->tcf_qstats.drops++;
+ unlock:
++      if (skb_at_tc_ingress(skb))
++              skb_pull_rcsum(skb, skb->mac_len);
++
+       spin_unlock(&v->tcf_lock);
+       return action;
+ }
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index a75864d93142..ecc1904e454f 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -315,7 +315,8 @@ replay:
+                       if (err == 0) {
+                               struct tcf_proto *next = 
rtnl_dereference(tp->next);
+ 
+-                              tfilter_notify(net, skb, n, tp, fh, 
RTM_DELTFILTER);
++                              tfilter_notify(net, skb, n, tp,
++                                             t->tcm_handle, RTM_DELTFILTER);
+                               if (tcf_destroy(tp, false))
+                                       RCU_INIT_POINTER(*back, next);
+                       }
+diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
+index 22c2bf367d7e..29c7c43de108 100644
+--- a/net/sctp/sm_statefuns.c
++++ b/net/sctp/sm_statefuns.c
+@@ -3426,6 +3426,12 @@ sctp_disposition_t sctp_sf_ootb(struct net *net,
+                       return sctp_sf_violation_chunklen(net, ep, asoc, type, 
arg,
+                                                 commands);
+ 
++              /* Report violation if chunk len overflows */
++              ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
++              if (ch_end > skb_tail_pointer(skb))
++                      return sctp_sf_violation_chunklen(net, ep, asoc, type, 
arg,
++                                                commands);
++
+               /* Now that we know we at least have a chunk header,
+                * do things that are type appropriate.
+                */
+@@ -3457,12 +3463,6 @@ sctp_disposition_t sctp_sf_ootb(struct net *net,
+                       }
+               }
+ 
+-              /* Report violation if chunk len overflows */
+-              ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+-              if (ch_end > skb_tail_pointer(skb))
+-                      return sctp_sf_violation_chunklen(net, ep, asoc, type, 
arg,
+-                                                commands);
+-
+               ch = (sctp_chunkhdr_t *) ch_end;
+       } while (ch_end < skb_tail_pointer(skb));
+ 
+diff --git a/net/sctp/socket.c b/net/sctp/socket.c
+index be1489fc3234..402817be3873 100644
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -4371,7 +4371,7 @@ static int sctp_getsockopt_disable_fragments(struct sock 
*sk, int len,
+ static int sctp_getsockopt_events(struct sock *sk, int len, char __user 
*optval,
+                                 int __user *optlen)
+ {
+-      if (len <= 0)
++      if (len == 0)
+               return -EINVAL;
+       if (len > sizeof(struct sctp_event_subscribe))
+               len = sizeof(struct sctp_event_subscribe);
+@@ -5972,6 +5972,9 @@ static int sctp_getsockopt(struct sock *sk, int level, 
int optname,
+       if (get_user(len, optlen))
+               return -EFAULT;
+ 
++      if (len < 0)
++              return -EINVAL;
++
+       lock_sock(sk);
+ 
+       switch (optname) {
diff --git a/debian/patches/series b/debian/patches/series
index 3adb02d..d7a0584 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -132,3 +132,4 @@
 bugfix/all/stable-4.4.29.patch
 bugfix/all/stable-4.4.30.patch
 bugfix/all/stable-4.4.31.patch
+bugfix/all/stable-4.4.32.patch

-- 
To view, visit https://gerrit.wikimedia.org/r/321653
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic4221758647cf45e5a24f3d75a4455a965370afb
Gerrit-PatchSet: 1
Gerrit-Project: operations/debs/linux44
Gerrit-Branch: master
Gerrit-Owner: Muehlenhoff <mmuhlenh...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to