Merge tag 'pwm/for-3.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry...
[cascardo/linux.git] / net / tipc / bcast.c
index 55c6c9d..dd13bfa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/bcast.c: TIPC broadcast code
  *
- * Copyright (c) 2004-2006, Ericsson AB
+ * Copyright (c) 2004-2006, 2014, Ericsson AB
  * Copyright (c) 2004, Intel Corporation.
  * Copyright (c) 2005, 2010-2011, Wind River Systems
  * All rights reserved.
@@ -38,6 +38,8 @@
 #include "core.h"
 #include "link.h"
 #include "port.h"
+#include "socket.h"
+#include "msg.h"
 #include "bcast.h"
 #include "name_distr.h"
 
@@ -138,6 +140,11 @@ static void tipc_bclink_unlock(void)
                tipc_link_reset_all(node);
 }
 
+uint  tipc_bclink_get_mtu(void)
+{
+       return MAX_PKT_DEFAULT_MCAST;
+}
+
 void tipc_bclink_set_flags(unsigned int flags)
 {
        bclink->flags |= flags;
@@ -382,30 +389,50 @@ static void bclink_peek_nack(struct tipc_msg *msg)
        tipc_node_unlock(n_ptr);
 }
 
-/*
- * tipc_bclink_xmit - broadcast a packet to all nodes in cluster
+/* tipc_bclink_xmit - broadcast buffer chain to all nodes in cluster
+ *                    and to identified node local sockets
+ * @buf: chain of buffers containing message
+ * Consumes the buffer chain, except when returning -ELINKCONG
+ * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
  */
 int tipc_bclink_xmit(struct sk_buff *buf)
 {
-       int res;
+       int rc = 0;
+       int bc = 0;
+       struct sk_buff *clbuf;
 
-       tipc_bclink_lock();
-
-       if (!bclink->bcast_nodes.count) {
-               res = msg_data_sz(buf_msg(buf));
-               kfree_skb(buf);
-               goto exit;
+       /* Prepare clone of message for local node */
+       clbuf = tipc_msg_reassemble(buf);
+       if (unlikely(!clbuf)) {
+               kfree_skb_list(buf);
+               return -EHOSTUNREACH;
        }
 
-       res = __tipc_link_xmit(bcl, buf);
-       if (likely(res >= 0)) {
-               bclink_set_last_sent();
-               bcl->stats.queue_sz_counts++;
-               bcl->stats.accu_queue_sz += bcl->out_queue_size;
+       /* Broadcast to all other nodes */
+       if (likely(bclink)) {
+               tipc_bclink_lock();
+               if (likely(bclink->bcast_nodes.count)) {
+                       rc = __tipc_link_xmit(bcl, buf);
+                       if (likely(!rc)) {
+                               bclink_set_last_sent();
+                               bcl->stats.queue_sz_counts++;
+                               bcl->stats.accu_queue_sz += bcl->out_queue_size;
+                       }
+                       bc = 1;
+               }
+               tipc_bclink_unlock();
        }
-exit:
-       tipc_bclink_unlock();
-       return res;
+
+       if (unlikely(!bc))
+               kfree_skb_list(buf);
+
+       /* Deliver message clone */
+       if (likely(!rc))
+               tipc_sk_mcast_rcv(clbuf);
+       else
+               kfree_skb(clbuf);
+
+       return rc;
 }
 
 /**
@@ -443,7 +470,7 @@ void tipc_bclink_rcv(struct sk_buff *buf)
        struct tipc_node *node;
        u32 next_in;
        u32 seqno;
-       int deferred;
+       int deferred = 0;
 
        /* Screen out unwanted broadcast messages */
 
@@ -494,7 +521,7 @@ receive:
                        tipc_bclink_unlock();
                        tipc_node_unlock(node);
                        if (likely(msg_mcast(msg)))
-                               tipc_port_mcast_rcv(buf, NULL);
+                               tipc_sk_mcast_rcv(buf);
                        else
                                kfree_skb(buf);
                } else if (msg_user(msg) == MSG_BUNDLER) {
@@ -573,8 +600,7 @@ receive:
                node->bclink.deferred_size += deferred;
                bclink_update_last_sent(node, seqno);
                buf = NULL;
-       } else
-               deferred = 0;
+       }
 
        tipc_bclink_lock();
 
@@ -611,6 +637,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
                              struct tipc_media_addr *unused2)
 {
        int bp_index;
+       struct tipc_msg *msg = buf_msg(buf);
 
        /* Prepare broadcast link message for reliable transmission,
         * if first time trying to send it;
@@ -618,10 +645,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
         * since they are sent in an unreliable manner and don't need it
         */
        if (likely(!msg_non_seq(buf_msg(buf)))) {
-               struct tipc_msg *msg;
-
                bcbuf_set_acks(buf, bclink->bcast_nodes.count);
-               msg = buf_msg(buf);
                msg_set_non_seq(msg, 1);
                msg_set_mc_netid(msg, tipc_net_id);
                bcl->stats.sent_info++;
@@ -638,12 +662,14 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
        for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) {
                struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary;
                struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary;
-               struct tipc_bearer *b = p;
+               struct tipc_bearer *bp[2] = {p, s};
+               struct tipc_bearer *b = bp[msg_link_selector(msg)];
                struct sk_buff *tbuf;
 
                if (!p)
                        break; /* No more bearers to try */
-
+               if (!b)
+                       b = p;
                tipc_nmap_diff(&bcbearer->remains, &b->nodes,
                               &bcbearer->remains_new);
                if (bcbearer->remains_new.count == bcbearer->remains.count)
@@ -660,13 +686,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
                        tipc_bearer_send(b->identity, tbuf, &b->bcast_addr);
                        kfree_skb(tbuf); /* Bearer keeps a clone */
                }
-
-               /* Swap bearers for next packet */
-               if (s) {
-                       bcbearer->bpairs[bp_index].primary = s;
-                       bcbearer->bpairs[bp_index].secondary = p;
-               }
-
                if (bcbearer->remains_new.count == 0)
                        break; /* All targets reached */