diff options
-rw-r--r-- | net/tipc/bcast.c | 10 | ||||
-rw-r--r-- | net/tipc/core.h | 1 | ||||
-rw-r--r-- | net/tipc/link.c | 67 | ||||
-rw-r--r-- | net/tipc/link.h | 14 | ||||
-rw-r--r-- | net/tipc/msg.c | 55 | ||||
-rw-r--r-- | net/tipc/msg.h | 5 | ||||
-rw-r--r-- | net/tipc/node.c | 7 | ||||
-rw-r--r-- | net/tipc/node.h | 6 |
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) | |||
187 | struct tipc_skb_cb { | 187 | struct 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 | */ |
399 | void tipc_link_reset_fragments(struct tipc_link *l_ptr) | 399 | void 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 | } |
2177 | exit: | 2169 | exit: |
@@ -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 | */ | ||
2315 | int 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; | ||
2354 | out_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 | |||
2361 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) | 2304 | static 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 | */ |
147 | struct tipc_link { | 141 | struct 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); |
244 | void tipc_link_bundle_rcv(struct sk_buff *buf); | 237 | void tipc_link_bundle_rcv(struct sk_buff *buf); |
245 | int tipc_link_frag_rcv(struct sk_buff **reasm_head, | ||
246 | struct sk_buff **reasm_tail, | ||
247 | struct sk_buff **fbuf); | ||
248 | void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, | 238 | void 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); |
250 | void tipc_link_push_queue(struct tipc_link *l_ptr); | 240 | void 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 | */ | ||
108 | int 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; | ||
150 | out_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); |
712 | int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, | 712 | int 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 | |||
715 | int 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 | */ |
76 | struct tipc_node_bclink { | 75 | struct 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 | ||