IB/ipoib: Fix memory corruption in ipoib cm mode connect flow
[pandora-kernel.git] / drivers / infiniband / ulp / ipoib / ipoib_main.c
index 83695b4..ae3b1d2 100644 (file)
@@ -148,7 +148,7 @@ static int ipoib_stop(struct net_device *dev)
 
        netif_stop_queue(dev);
 
-       ipoib_ib_dev_down(dev, 0);
+       ipoib_ib_dev_down(dev, 1);
        ipoib_ib_dev_stop(dev, 0);
 
        if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
@@ -208,7 +208,7 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
-static struct ipoib_path *__path_find(struct net_device *dev, void *gid)
+struct ipoib_path *__path_find(struct net_device *dev, void *gid)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct rb_node *n = priv->path_tree.rb_node;
@@ -658,7 +658,7 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
 }
 
 static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
-                            struct ipoib_pseudoheader *phdr)
+                            struct ipoib_cb *cb)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_path *path;
@@ -666,17 +666,15 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       path = __path_find(dev, phdr->hwaddr + 4);
+       path = __path_find(dev, cb->hwaddr + 4);
        if (!path || !path->valid) {
                int new_path = 0;
 
                if (!path) {
-                       path = path_rec_create(dev, phdr->hwaddr + 4);
+                       path = path_rec_create(dev, cb->hwaddr + 4);
                        new_path = 1;
                }
                if (path) {
-                       /* put pseudoheader back on for next time */
-                       skb_push(skb, sizeof *phdr);
                        __skb_queue_tail(&path->queue, skb);
 
                        if (!path->query && path_rec_start(dev, path)) {
@@ -700,12 +698,10 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
                          be16_to_cpu(path->pathrec.dlid));
 
                spin_unlock_irqrestore(&priv->lock, flags);
-               ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr));
+               ipoib_send(dev, skb, path->ah, IPOIB_QPN(cb->hwaddr));
                return;
        } else if ((path->query || !path_rec_start(dev, path)) &&
                   skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
-               /* put pseudoheader back on for next time */
-               skb_push(skb, sizeof *phdr);
                __skb_queue_tail(&path->queue, skb);
        } else {
                ++dev->stats.tx_dropped;
@@ -774,16 +770,14 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        dev_kfree_skb_any(skb);
                }
        } else {
-               struct ipoib_pseudoheader *phdr =
-                       (struct ipoib_pseudoheader *) skb->data;
-               skb_pull(skb, sizeof *phdr);
+               struct ipoib_cb *cb = (struct ipoib_cb *) skb->cb;
 
-               if (phdr->hwaddr[4] == 0xff) {
+               if (cb->hwaddr[4] == 0xff) {
                        /* Add in the P_Key for multicast*/
-                       phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff;
-                       phdr->hwaddr[9] = priv->pkey & 0xff;
+                       cb->hwaddr[8] = (priv->pkey >> 8) & 0xff;
+                       cb->hwaddr[9] = priv->pkey & 0xff;
 
-                       ipoib_mcast_send(dev, phdr->hwaddr + 4, skb);
+                       ipoib_mcast_send(dev, cb->hwaddr + 4, skb);
                } else {
                        /* unicast GID -- should be ARP or RARP reply */
 
@@ -792,14 +786,14 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x %pI6\n",
                                           skb_dst(skb) ? "neigh" : "dst",
                                           be16_to_cpup((__be16 *) skb->data),
-                                          IPOIB_QPN(phdr->hwaddr),
-                                          phdr->hwaddr + 4);
+                                          IPOIB_QPN(cb->hwaddr),
+                                          cb->hwaddr + 4);
                                dev_kfree_skb_any(skb);
                                ++dev->stats.tx_dropped;
                                goto unlock;
                        }
 
-                       unicast_arp_send(skb, dev, phdr);
+                       unicast_arp_send(skb, dev, cb);
                }
        }
 unlock:
@@ -825,8 +819,6 @@ static int ipoib_hard_header(struct sk_buff *skb,
                             const void *daddr, const void *saddr, unsigned len)
 {
        struct ipoib_header *header;
-       struct dst_entry *dst;
-       struct neighbour *n;
 
        header = (struct ipoib_header *) skb_push(skb, sizeof *header);
 
@@ -834,18 +826,13 @@ static int ipoib_hard_header(struct sk_buff *skb,
        header->reserved = 0;
 
        /*
-        * If we don't have a neighbour structure, stuff the
-        * destination address onto the front of the skb so we can
-        * figure out where to send the packet later.
+        * If we don't have a dst_entry structure, stuff the
+        * destination address into skb->cb so we can figure out where
+        * to send the packet later.
         */
-       dst = skb_dst(skb);
-       n = NULL;
-       if (dst)
-               n = dst_get_neighbour_raw(dst);
-       if ((!dst || !n) && daddr) {
-               struct ipoib_pseudoheader *phdr =
-                       (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
-               memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
+       if (!skb_dst(skb)) {
+               struct ipoib_cb *cb = (struct ipoib_cb *) skb->cb;
+               memcpy(cb->hwaddr, daddr, INFINIBAND_ALEN);
        }
 
        return 0;
@@ -1021,11 +1008,7 @@ static void ipoib_setup(struct net_device *dev)
 
        dev->flags              |= IFF_BROADCAST | IFF_MULTICAST;
 
-       /*
-        * We add in INFINIBAND_ALEN to allow for the destination
-        * address "pseudoheader" for skbs without neighbour struct.
-        */
-       dev->hard_header_len     = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
+       dev->hard_header_len     = IPOIB_ENCAP_LEN;
        dev->addr_len            = INFINIBAND_ALEN;
        dev->type                = ARPHRD_INFINIBAND;
        dev->tx_queue_len        = ipoib_sendq_size * 2;