Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6.git] / drivers / infiniband / ulp / ipoib / ipoib_multicast.c
index a2eb3b9..3871ac6 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/inetdevice.h>
 #include <linux/delay.h>
 #include <linux/completion.h>
+#include <linux/slab.h>
 
 #include <net/dst.h>
 
@@ -261,7 +262,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
 
                skb->dev = dev;
 
-               if (!skb->dst || !skb->dst->neighbour) {
+               if (!skb_dst(skb) || !skb_dst(skb)->neighbour) {
                        /* put pseudoheader back on for next time */
                        skb_push(skb, sizeof (struct ipoib_pseudoheader));
                }
@@ -362,12 +363,19 @@ void ipoib_mcast_carrier_on_task(struct work_struct *work)
 {
        struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
                                                   carrier_on_task);
+       struct ib_port_attr attr;
 
        /*
         * Take rtnl_lock to avoid racing with ipoib_stop() and
         * turning the carrier back on while a device is being
         * removed.
         */
+       if (ib_query_port(priv->ca, priv->port, &attr) ||
+           attr.state != IB_PORT_ACTIVE) {
+               ipoib_dbg(priv, "Keeping carrier off until IB port is active\n");
+               return;
+       }
+
        rtnl_lock();
        netif_carrier_on(priv->dev);
        rtnl_unlock();
@@ -409,7 +417,7 @@ static int ipoib_mcast_join_complete(int status,
        }
 
        if (mcast->logcount++ < 20) {
-               if (status == -ETIMEDOUT) {
+               if (status == -ETIMEDOUT || status == -EAGAIN) {
                        ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n",
                                        mcast->mcmember.mgid.raw, status);
                } else {
@@ -529,6 +537,9 @@ void ipoib_mcast_join_task(struct work_struct *work)
        if (!priv->broadcast) {
                struct ipoib_mcast *broadcast;
 
+               if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
+                       return;
+
                broadcast = ipoib_mcast_alloc(dev, 1);
                if (!broadcast) {
                        ipoib_warn(priv, "failed to allocate broadcast group\n");
@@ -704,10 +715,10 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
 
 out:
        if (mcast && mcast->ah) {
-               if (skb->dst            &&
-                   skb->dst->neighbour &&
-                   !*to_ipoib_neigh(skb->dst->neighbour)) {
-                       struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour,
+               if (skb_dst(skb)                &&
+                   skb_dst(skb)->neighbour &&
+                   !*to_ipoib_neigh(skb_dst(skb)->neighbour)) {
+                       struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour,
                                                                        skb->dev);
 
                        if (neigh) {
@@ -717,7 +728,9 @@ out:
                        }
                }
 
+               spin_unlock_irqrestore(&priv->lock, flags);
                ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN);
+               return;
        }
 
 unlock:
@@ -755,12 +768,23 @@ void ipoib_mcast_dev_flush(struct net_device *dev)
        }
 }
 
+static int ipoib_mcast_addr_is_valid(const u8 *addr, const u8 *broadcast)
+{
+       /* reserved QPN, prefix, scope */
+       if (memcmp(addr, broadcast, 6))
+               return 0;
+       /* signature lower, pkey */
+       if (memcmp(addr + 7, broadcast + 7, 3))
+               return 0;
+       return 1;
+}
+
 void ipoib_mcast_restart_task(struct work_struct *work)
 {
        struct ipoib_dev_priv *priv =
                container_of(work, struct ipoib_dev_priv, restart_task);
        struct net_device *dev = priv->dev;
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        struct ipoib_mcast *mcast, *tmcast;
        LIST_HEAD(remove_list);
        unsigned long flags;
@@ -785,10 +809,13 @@ void ipoib_mcast_restart_task(struct work_struct *work)
                clear_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags);
 
        /* Mark all of the entries that are found or don't exist */
-       for (mclist = dev->mc_list; mclist; mclist = mclist->next) {
+       netdev_for_each_mc_addr(ha, dev) {
                union ib_gid mgid;
 
-               memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid);
+               if (!ipoib_mcast_addr_is_valid(ha->addr, dev->broadcast))
+                       continue;
+
+               memcpy(mgid.raw, ha->addr + 4, sizeof mgid);
 
                mcast = __ipoib_mcast_find(dev, &mgid);
                if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {