tipc: let broadcast transmission use new link transmit function
[cascardo/linux.git] / net / tipc / msg.c
index c5ac436..5b47468 100644 (file)
@@ -121,7 +121,7 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
 {
        struct sk_buff *head = *headbuf;
        struct sk_buff *frag = *buf;
-       struct sk_buff *tail;
+       struct sk_buff *tail = NULL;
        struct tipc_msg *msg;
        u32 fragid;
        int delta;
@@ -141,9 +141,15 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
                if (unlikely(skb_unclone(frag, GFP_ATOMIC)))
                        goto err;
                head = *headbuf = frag;
-               skb_frag_list_init(head);
-               TIPC_SKB_CB(head)->tail = NULL;
                *buf = NULL;
+               TIPC_SKB_CB(head)->tail = NULL;
+               if (skb_is_nonlinear(head)) {
+                       skb_walk_frags(head, tail) {
+                               TIPC_SKB_CB(head)->tail = tail;
+                       }
+               } else {
+                       skb_frag_list_init(head);
+               }
                return 0;
        }
 
@@ -559,18 +565,22 @@ bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err)
 /* tipc_msg_reassemble() - clone a buffer chain of fragments and
  *                         reassemble the clones into one message
  */
-struct sk_buff *tipc_msg_reassemble(struct sk_buff_head *list)
+bool tipc_msg_reassemble(struct sk_buff_head *list, struct sk_buff_head *rcvq)
 {
-       struct sk_buff *skb;
+       struct sk_buff *skb, *_skb;
        struct sk_buff *frag = NULL;
        struct sk_buff *head = NULL;
-       int hdr_sz;
+       int hdr_len;
 
        /* Copy header if single buffer */
        if (skb_queue_len(list) == 1) {
                skb = skb_peek(list);
-               hdr_sz = skb_headroom(skb) + msg_hdr_sz(buf_msg(skb));
-               return __pskb_copy(skb, hdr_sz, GFP_ATOMIC);
+               hdr_len = skb_headroom(skb) + msg_hdr_sz(buf_msg(skb));
+               _skb = __pskb_copy(skb, hdr_len, GFP_ATOMIC);
+               if (!_skb)
+                       return false;
+               __skb_queue_tail(rcvq, _skb);
+               return true;
        }
 
        /* Clone all fragments and reassemble */
@@ -584,9 +594,41 @@ struct sk_buff *tipc_msg_reassemble(struct sk_buff_head *list)
                if (!head)
                        goto error;
        }
-       return frag;
+       __skb_queue_tail(rcvq, frag);
+       return true;
 error:
        pr_warn("Failed do clone local mcast rcv buffer\n");
        kfree_skb(head);
-       return NULL;
+       return false;
+}
+
+/* tipc_skb_queue_sorted(); sort pkt into list according to sequence number
+ * @list: list to be appended to
+ * @seqno: sequence number of buffer to add
+ * @skb: buffer to add
+ */
+void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
+                            struct sk_buff *skb)
+{
+       struct sk_buff *_skb, *tmp;
+
+       if (skb_queue_empty(list) || less(seqno, buf_seqno(skb_peek(list)))) {
+               __skb_queue_head(list, skb);
+               return;
+       }
+
+       if (more(seqno, buf_seqno(skb_peek_tail(list)))) {
+               __skb_queue_tail(list, skb);
+               return;
+       }
+
+       skb_queue_walk_safe(list, _skb, tmp) {
+               if (more(seqno, buf_seqno(_skb)))
+                       continue;
+               if (seqno == buf_seqno(_skb))
+                       break;
+               __skb_queue_before(list, _skb, skb);
+               return;
+       }
+       kfree_skb(skb);
 }