Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / drivers / net / bonding / bond_main.c
index b9c2ae62166ddb3e8647a2c756e2ab966d2d8063..af506321500b90ab4402ba3fd23a2f98dd986e77 100644 (file)
@@ -1445,8 +1445,8 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
        struct sk_buff *skb = *pskb;
        struct slave *slave;
        struct bonding *bond;
-       int (*recv_probe)(struct sk_buff *, struct bonding *,
-                               struct slave *);
+       int (*recv_probe)(const struct sk_buff *, struct bonding *,
+                         struct slave *);
        int ret = RX_HANDLER_ANOTHER;
 
        skb = skb_share_check(skb, GFP_ATOMIC);
@@ -1463,15 +1463,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
 
        recv_probe = ACCESS_ONCE(bond->recv_probe);
        if (recv_probe) {
-               struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
-
-               if (likely(nskb)) {
-                       ret = recv_probe(nskb, bond, slave);
-                       dev_kfree_skb(nskb);
-                       if (ret == RX_HANDLER_CONSUMED) {
-                               consume_skb(skb);
-                               return ret;
-                       }
+               ret = recv_probe(skb, bond, slave);
+               if (ret == RX_HANDLER_CONSUMED) {
+                       consume_skb(skb);
+                       return ret;
                }
        }
 
@@ -2738,25 +2733,31 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
        }
 }
 
-static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
-                        struct slave *slave)
+static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
+                       struct slave *slave)
 {
-       struct arphdr *arp;
+       struct arphdr *arp = (struct arphdr *)skb->data;
        unsigned char *arp_ptr;
        __be32 sip, tip;
+       int alen;
 
        if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
                return RX_HANDLER_ANOTHER;
 
        read_lock(&bond->lock);
+       alen = arp_hdr_len(bond->dev);
 
        pr_debug("bond_arp_rcv: bond %s skb->dev %s\n",
                 bond->dev->name, skb->dev->name);
 
-       if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
-               goto out_unlock;
+       if (alen > skb_headlen(skb)) {
+               arp = kmalloc(alen, GFP_ATOMIC);
+               if (!arp)
+                       goto out_unlock;
+               if (skb_copy_bits(skb, 0, arp, alen) < 0)
+                       goto out_unlock;
+       }
 
-       arp = arp_hdr(skb);
        if (arp->ar_hln != bond->dev->addr_len ||
            skb->pkt_type == PACKET_OTHERHOST ||
            skb->pkt_type == PACKET_LOOPBACK ||
@@ -2791,6 +2792,8 @@ static int bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
 
 out_unlock:
        read_unlock(&bond->lock);
+       if (arp != (struct arphdr *)skb->data)
+               kfree(arp);
        return RX_HANDLER_ANOTHER;
 }