aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/tipc/bcast.c10
-rw-r--r--net/tipc/core.h1
-rw-r--r--net/tipc/link.c67
-rw-r--r--net/tipc/link.h14
-rw-r--r--net/tipc/msg.c55
-rw-r--r--net/tipc/msg.h5
-rw-r--r--net/tipc/node.c7
-rw-r--r--net/tipc/node.h6
8 files changed, 74 insertions, 91 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index a0978d0890cb..671f9817b4f4 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -506,18 +506,14 @@ receive:
506 tipc_node_unlock(node); 506 tipc_node_unlock(node);
507 tipc_link_bundle_rcv(buf); 507 tipc_link_bundle_rcv(buf);
508 } else if (msg_user(msg) == MSG_FRAGMENTER) { 508 } else if (msg_user(msg) == MSG_FRAGMENTER) {
509 int ret; 509 tipc_buf_append(&node->bclink.reasm_buf, &buf);
510 ret = tipc_link_frag_rcv(&node->bclink.reasm_head, 510 if (unlikely(!buf && !node->bclink.reasm_buf))
511 &node->bclink.reasm_tail,
512 &buf);
513 if (ret == LINK_REASM_ERROR)
514 goto unlock; 511 goto unlock;
515 tipc_bclink_lock(); 512 tipc_bclink_lock();
516 bclink_accept_pkt(node, seqno); 513 bclink_accept_pkt(node, seqno);
517 bcl->stats.recv_fragments++; 514 bcl->stats.recv_fragments++;
518 if (ret == LINK_REASM_COMPLETE) { 515 if (buf) {
519 bcl->stats.recv_fragmented++; 516 bcl->stats.recv_fragmented++;
520 /* Point msg to inner header */
521 msg = buf_msg(buf); 517 msg = buf_msg(buf);
522 tipc_bclink_unlock(); 518 tipc_bclink_unlock();
523 goto receive; 519 goto receive;
diff --git a/net/tipc/core.h b/net/tipc/core.h
index ae55d37267e6..2e00682bc455 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -187,6 +187,7 @@ static inline void k_term_timer(struct timer_list *timer)
187struct tipc_skb_cb { 187struct tipc_skb_cb {
188 void *handle; 188 void *handle;
189 bool deferred; 189 bool deferred;
190 struct sk_buff *tail;
190}; 191};
191 192
192#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0])) 193#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 9272d4cc0225..24d058796cd9 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -398,9 +398,8 @@ static void link_release_outqueue(struct tipc_link *l_ptr)
398 */ 398 */
399void tipc_link_reset_fragments(struct tipc_link *l_ptr) 399void tipc_link_reset_fragments(struct tipc_link *l_ptr)
400{ 400{
401 kfree_skb(l_ptr->reasm_head); 401 kfree_skb(l_ptr->reasm_buf);
402 l_ptr->reasm_head = NULL; 402 l_ptr->reasm_buf = NULL;
403 l_ptr->reasm_tail = NULL;
404} 403}
405 404
406/** 405/**
@@ -1573,17 +1572,12 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
1573 } 1572 }
1574 msg = buf_msg(buf); 1573 msg = buf_msg(buf);
1575 } else if (msg_user(msg) == MSG_FRAGMENTER) { 1574 } else if (msg_user(msg) == MSG_FRAGMENTER) {
1576 int rc;
1577
1578 l_ptr->stats.recv_fragments++; 1575 l_ptr->stats.recv_fragments++;
1579 rc = tipc_link_frag_rcv(&l_ptr->reasm_head, 1576 if (tipc_buf_append(&l_ptr->reasm_buf, &buf)) {
1580 &l_ptr->reasm_tail,
1581 &buf);
1582 if (rc == LINK_REASM_COMPLETE) {
1583 l_ptr->stats.recv_fragmented++; 1577 l_ptr->stats.recv_fragmented++;
1584 msg = buf_msg(buf); 1578 msg = buf_msg(buf);
1585 } else { 1579 } else {
1586 if (rc == LINK_REASM_ERROR) 1580 if (!l_ptr->reasm_buf)
1587 tipc_link_reset(l_ptr); 1581 tipc_link_reset(l_ptr);
1588 tipc_node_unlock(n_ptr); 1582 tipc_node_unlock(n_ptr);
1589 continue; 1583 continue;
@@ -2169,9 +2163,7 @@ static struct sk_buff *tipc_link_failover_rcv(struct tipc_link *l_ptr,
2169 } 2163 }
2170 if (msg_user(msg) == MSG_FRAGMENTER) { 2164 if (msg_user(msg) == MSG_FRAGMENTER) {
2171 l_ptr->stats.recv_fragments++; 2165 l_ptr->stats.recv_fragments++;
2172 tipc_link_frag_rcv(&l_ptr->reasm_head, 2166 tipc_buf_append(&l_ptr->reasm_buf, &buf);
2173 &l_ptr->reasm_tail,
2174 &buf);
2175 } 2167 }
2176 } 2168 }
2177exit: 2169exit:
@@ -2309,55 +2301,6 @@ static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf)
2309 return dsz; 2301 return dsz;
2310} 2302}
2311 2303
2312/* tipc_link_frag_rcv(): Called with node lock on. Returns
2313 * the reassembled buffer if message is complete.
2314 */
2315int tipc_link_frag_rcv(struct sk_buff **head, struct sk_buff **tail,
2316 struct sk_buff **fbuf)
2317{
2318 struct sk_buff *frag = *fbuf;
2319 struct tipc_msg *msg = buf_msg(frag);
2320 u32 fragid = msg_type(msg);
2321 bool headstolen;
2322 int delta;
2323
2324 skb_pull(frag, msg_hdr_sz(msg));
2325 if (fragid == FIRST_FRAGMENT) {
2326 if (*head || skb_unclone(frag, GFP_ATOMIC))
2327 goto out_free;
2328 *head = frag;
2329 skb_frag_list_init(*head);
2330 *fbuf = NULL;
2331 return 0;
2332 } else if (*head &&
2333 skb_try_coalesce(*head, frag, &headstolen, &delta)) {
2334 kfree_skb_partial(frag, headstolen);
2335 } else {
2336 if (!*head)
2337 goto out_free;
2338 if (!skb_has_frag_list(*head))
2339 skb_shinfo(*head)->frag_list = frag;
2340 else
2341 (*tail)->next = frag;
2342 *tail = frag;
2343 (*head)->truesize += frag->truesize;
2344 (*head)->data_len += frag->len;
2345 (*head)->len += frag->len;
2346 }
2347 if (fragid == LAST_FRAGMENT) {
2348 *fbuf = *head;
2349 *tail = *head = NULL;
2350 return LINK_REASM_COMPLETE;
2351 }
2352 *fbuf = NULL;
2353 return 0;
2354out_free:
2355 pr_warn_ratelimited("Link unable to reassemble fragmented message\n");
2356 kfree_skb(*fbuf);
2357 *fbuf = NULL;
2358 return LINK_REASM_ERROR;
2359}
2360
2361static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) 2304static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance)
2362{ 2305{
2363 if ((tolerance < TIPC_MIN_LINK_TOL) || (tolerance > TIPC_MAX_LINK_TOL)) 2306 if ((tolerance < TIPC_MIN_LINK_TOL) || (tolerance > TIPC_MAX_LINK_TOL))
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 7ba73fa6b81e..200d518b218e 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -40,11 +40,6 @@
40#include "msg.h" 40#include "msg.h"
41#include "node.h" 41#include "node.h"
42 42
43/* Link reassembly status codes
44 */
45#define LINK_REASM_ERROR -1
46#define LINK_REASM_COMPLETE 1
47
48/* Out-of-range value for link sequence numbers 43/* Out-of-range value for link sequence numbers
49 */ 44 */
50#define INVALID_LINK_SEQ 0x10000 45#define INVALID_LINK_SEQ 0x10000
@@ -140,8 +135,7 @@ struct tipc_stats {
140 * @next_out: ptr to first unsent outbound message in queue 135 * @next_out: ptr to first unsent outbound message in queue
141 * @waiting_ports: linked list of ports waiting for link congestion to abate 136 * @waiting_ports: linked list of ports waiting for link congestion to abate
142 * @long_msg_seq_no: next identifier to use for outbound fragmented messages 137 * @long_msg_seq_no: next identifier to use for outbound fragmented messages
143 * @reasm_head: list head of partially reassembled inbound message fragments 138 * @reasm_buf: head of partially reassembled inbound message fragments
144 * @reasm_tail: last fragment received
145 * @stats: collects statistics regarding link activity 139 * @stats: collects statistics regarding link activity
146 */ 140 */
147struct tipc_link { 141struct tipc_link {
@@ -204,8 +198,7 @@ struct tipc_link {
204 198
205 /* Fragmentation/reassembly */ 199 /* Fragmentation/reassembly */
206 u32 long_msg_seq_no; 200 u32 long_msg_seq_no;
207 struct sk_buff *reasm_head; 201 struct sk_buff *reasm_buf;
208 struct sk_buff *reasm_tail;
209 202
210 /* Statistics */ 203 /* Statistics */
211 struct tipc_stats stats; 204 struct tipc_stats stats;
@@ -242,9 +235,6 @@ int tipc_link_iovec_xmit_fast(struct tipc_port *sender,
242 struct iovec const *msg_sect, 235 struct iovec const *msg_sect,
243 unsigned int len, u32 destnode); 236 unsigned int len, u32 destnode);
244void tipc_link_bundle_rcv(struct sk_buff *buf); 237void tipc_link_bundle_rcv(struct sk_buff *buf);
245int tipc_link_frag_rcv(struct sk_buff **reasm_head,
246 struct sk_buff **reasm_tail,
247 struct sk_buff **fbuf);
248void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, 238void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob,
249 u32 gap, u32 tolerance, u32 priority, u32 acked_mtu); 239 u32 gap, u32 tolerance, u32 priority, u32 acked_mtu);
250void tipc_link_push_queue(struct tipc_link *l_ptr); 240void tipc_link_push_queue(struct tipc_link *l_ptr);
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index e525f8ce1dee..8be6e94a1ca9 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * net/tipc/msg.c: TIPC message header routines 2 * net/tipc/msg.c: TIPC message header routines
3 * 3 *
4 * Copyright (c) 2000-2006, Ericsson AB 4 * Copyright (c) 2000-2006, 2014, Ericsson AB
5 * Copyright (c) 2005, 2010-2011, Wind River Systems 5 * Copyright (c) 2005, 2010-2011, Wind River Systems
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
@@ -99,3 +99,56 @@ int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect,
99 } 99 }
100 return dsz; 100 return dsz;
101} 101}
102
103/* tipc_buf_append(): Append a buffer to the fragment list of another buffer
104 * Let first buffer become head buffer
105 * Returns 1 and sets *buf to headbuf if chain is complete, otherwise 0
106 * Leaves headbuf pointer at NULL if failure
107 */
108int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
109{
110 struct sk_buff *head = *headbuf;
111 struct sk_buff *frag = *buf;
112 struct sk_buff *tail;
113 struct tipc_msg *msg = buf_msg(frag);
114 u32 fragid = msg_type(msg);
115 bool headstolen;
116 int delta;
117
118 skb_pull(frag, msg_hdr_sz(msg));
119
120 if (fragid == FIRST_FRAGMENT) {
121 if (head || skb_unclone(frag, GFP_ATOMIC))
122 goto out_free;
123 head = *headbuf = frag;
124 skb_frag_list_init(head);
125 return 0;
126 }
127 if (!head)
128 goto out_free;
129 tail = TIPC_SKB_CB(head)->tail;
130 if (skb_try_coalesce(head, frag, &headstolen, &delta)) {
131 kfree_skb_partial(frag, headstolen);
132 } else {
133 if (!skb_has_frag_list(head))
134 skb_shinfo(head)->frag_list = frag;
135 else
136 tail->next = frag;
137 head->truesize += frag->truesize;
138 head->data_len += frag->len;
139 head->len += frag->len;
140 TIPC_SKB_CB(head)->tail = frag;
141 }
142 if (fragid == LAST_FRAGMENT) {
143 *buf = head;
144 TIPC_SKB_CB(head)->tail = NULL;
145 *headbuf = NULL;
146 return 1;
147 }
148 *buf = NULL;
149 return 0;
150out_free:
151 pr_warn_ratelimited("Unable to build fragment list\n");
152 kfree_skb(*buf);
153 return 0;
154}
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index 76d1269b9443..503511903d1d 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * net/tipc/msg.h: Include file for TIPC message header routines 2 * net/tipc/msg.h: Include file for TIPC message header routines
3 * 3 *
4 * Copyright (c) 2000-2007, Ericsson AB 4 * Copyright (c) 2000-2007, 2014, Ericsson AB
5 * Copyright (c) 2005-2008, 2010-2011, Wind River Systems 5 * Copyright (c) 2005-2008, 2010-2011, Wind River Systems
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
@@ -711,4 +711,7 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
711 u32 destnode); 711 u32 destnode);
712int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, 712int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect,
713 unsigned int len, int max_size, struct sk_buff **buf); 713 unsigned int len, int max_size, struct sk_buff **buf);
714
715int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf);
716
714#endif 717#endif
diff --git a/net/tipc/node.c b/net/tipc/node.c
index facd5611e785..5b44c3041be4 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -286,10 +286,9 @@ static void node_lost_contact(struct tipc_node *n_ptr)
286 kfree_skb_list(n_ptr->bclink.deferred_head); 286 kfree_skb_list(n_ptr->bclink.deferred_head);
287 n_ptr->bclink.deferred_size = 0; 287 n_ptr->bclink.deferred_size = 0;
288 288
289 if (n_ptr->bclink.reasm_head) { 289 if (n_ptr->bclink.reasm_buf) {
290 kfree_skb(n_ptr->bclink.reasm_head); 290 kfree_skb(n_ptr->bclink.reasm_buf);
291 n_ptr->bclink.reasm_head = NULL; 291 n_ptr->bclink.reasm_buf = NULL;
292 n_ptr->bclink.reasm_tail = NULL;
293 } 292 }
294 293
295 tipc_bclink_remove_node(n_ptr->addr); 294 tipc_bclink_remove_node(n_ptr->addr);
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 5454edf994c3..9087063793f2 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -69,8 +69,7 @@ enum {
69 * @deferred_size: number of OOS b'cast messages in deferred queue 69 * @deferred_size: number of OOS b'cast messages in deferred queue
70 * @deferred_head: oldest OOS b'cast message received from node 70 * @deferred_head: oldest OOS b'cast message received from node
71 * @deferred_tail: newest OOS b'cast message received from node 71 * @deferred_tail: newest OOS b'cast message received from node
72 * @reasm_head: broadcast reassembly queue head from node 72 * @reasm_buf: broadcast reassembly queue head from node
73 * @reasm_tail: last broadcast fragment received from node
74 * @recv_permitted: true if node is allowed to receive b'cast messages 73 * @recv_permitted: true if node is allowed to receive b'cast messages
75 */ 74 */
76struct tipc_node_bclink { 75struct tipc_node_bclink {
@@ -81,8 +80,7 @@ struct tipc_node_bclink {
81 u32 deferred_size; 80 u32 deferred_size;
82 struct sk_buff *deferred_head; 81 struct sk_buff *deferred_head;
83 struct sk_buff *deferred_tail; 82 struct sk_buff *deferred_tail;
84 struct sk_buff *reasm_head; 83 struct sk_buff *reasm_buf;
85 struct sk_buff *reasm_tail;
86 bool recv_permitted; 84 bool recv_permitted;
87}; 85};
88 86