/*
  * net/tipc/bcast.c: TIPC broadcast code
  *
- * Copyright (c) 2004-2006, 2014-2016, Ericsson AB
+ * Copyright (c) 2004-2006, 2014-2017, Ericsson AB
  * Copyright (c) 2004, Intel Corporation.
  * Copyright (c) 2005, 2010-2011, Wind River Systems
  * All rights reserved.
 #include "link.h"
 #include "name_table.h"
 
-#define        BCLINK_WIN_DEFAULT      50      /* bcast link window size (default) */
-#define        BCLINK_WIN_MIN          32      /* bcast minimum link window size */
+#define BCLINK_WIN_DEFAULT  50 /* bcast link window size (default) */
+#define BCLINK_WIN_MIN      32 /* bcast minimum link window size */
 
 const char tipc_bclink_name[] = "broadcast-link";
 
        return tipc_net(net)->bcbase;
 }
 
+/* tipc_bcast_get_mtu(): -get the MTU currently used by broadcast link
+ * Note: the MTU is decremented to give room for a tunnel header, in
+ * case the message needs to be sent as replicast
+ */
 int tipc_bcast_get_mtu(struct net *net)
 {
        return tipc_link_mtu(tipc_bc_sndlink(net)) - INT_H_SIZE;
        spin_lock_init(&tipc_net(net)->bclock);
 
        if (!tipc_link_bc_create(net, 0, 0,
-                                U16_MAX,
+                                FB_MTU,
                                 BCLINK_WIN_DEFAULT,
                                 0,
                                 &bb->inputq,
 
  * @pktmax: Max packet size that can be used
  * @list: Buffer or chain of buffers to be returned to caller
  *
+ * Note that the recursive call we are making here is safe, since it can
+ * logically go only one further level down.
+ *
  * Returns message data size or errno: -ENOMEM, -EFAULT
  */
-int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m,
-                  int offset, int dsz, int pktmax, struct sk_buff_head *list)
+int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
+                  int dsz, int pktmax, struct sk_buff_head *list)
 {
        int mhsz = msg_hdr_sz(mhdr);
+       struct tipc_msg pkthdr;
        int msz = mhsz + dsz;
-       int pktno = 1;
-       int pktsz;
        int pktrem = pktmax;
-       int drem = dsz;
-       struct tipc_msg pkthdr;
        struct sk_buff *skb;
+       int drem = dsz;
+       int pktno = 1;
        char *pktpos;
+       int pktsz;
        int rc;
 
        msg_set_size(mhdr, msz);
        /* No fragmentation needed? */
        if (likely(msz <= pktmax)) {
                skb = tipc_buf_acquire(msz, GFP_KERNEL);
-               if (unlikely(!skb))
+
+               /* Fall back to smaller MTU if node local message */
+               if (unlikely(!skb)) {
+                       if (pktmax != MAX_MSG_SIZE)
+                               return -ENOMEM;
+                       rc = tipc_msg_build(mhdr, m, offset, dsz, FB_MTU, list);
+                       if (rc != dsz)
+                               return rc;
+                       if (tipc_msg_assemble(list))
+                               return dsz;
                        return -ENOMEM;
+               }
                skb_orphan(skb);
                __skb_queue_tail(list, skb);
                skb_copy_to_linear_data(skb, mhdr, mhsz);
        return true;
 }
 
+/* tipc_msg_assemble() - assemble chain of fragments into one message
+ */
+bool tipc_msg_assemble(struct sk_buff_head *list)
+{
+       struct sk_buff *skb, *tmp = NULL;
+
+       if (skb_queue_len(list) == 1)
+               return true;
+
+       while ((skb = __skb_dequeue(list))) {
+               skb->next = NULL;
+               if (tipc_buf_append(&tmp, &skb)) {
+                       __skb_queue_tail(list, skb);
+                       return true;
+               }
+               if (!tmp)
+                       break;
+       }
+       __skb_queue_purge(list);
+       __skb_queue_head_init(list);
+       pr_warn("Failed do assemble buffer\n");
+       return false;
+}
+
 /* tipc_msg_reassemble() - clone a buffer chain of fragments and
  *                         reassemble the clones into one message
  */
 
 #define MAX_H_SIZE                60   /* Largest possible TIPC header size */
 
 #define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE)
-
+#define FB_MTU                  3744
 #define TIPC_MEDIA_INFO_OFFSET 5
 
 struct tipc_skb_cb {
 int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m,
                   int offset, int dsz, int mtu, struct sk_buff_head *list);
 bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err);
+bool tipc_msg_assemble(struct sk_buff_head *list);
 bool tipc_msg_reassemble(struct sk_buff_head *list, struct sk_buff_head *rcvq);
 bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg,
                        struct sk_buff_head *cpy);