diff options
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r-- | net/tipc/link.c | 159 |
1 files changed, 44 insertions, 115 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c index ada8cadf5af8..a63646e6c2cf 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -404,15 +404,9 @@ static void link_release_outqueue(struct tipc_link *l_ptr) | |||
404 | */ | 404 | */ |
405 | void tipc_link_reset_fragments(struct tipc_link *l_ptr) | 405 | void tipc_link_reset_fragments(struct tipc_link *l_ptr) |
406 | { | 406 | { |
407 | struct sk_buff *buf = l_ptr->defragm_buf; | 407 | kfree_skb(l_ptr->reasm_head); |
408 | struct sk_buff *next; | 408 | l_ptr->reasm_head = NULL; |
409 | 409 | l_ptr->reasm_tail = NULL; | |
410 | while (buf) { | ||
411 | next = buf->next; | ||
412 | kfree_skb(buf); | ||
413 | buf = next; | ||
414 | } | ||
415 | l_ptr->defragm_buf = NULL; | ||
416 | } | 410 | } |
417 | 411 | ||
418 | /** | 412 | /** |
@@ -1649,13 +1643,15 @@ deliver: | |||
1649 | continue; | 1643 | continue; |
1650 | case MSG_FRAGMENTER: | 1644 | case MSG_FRAGMENTER: |
1651 | l_ptr->stats.recv_fragments++; | 1645 | l_ptr->stats.recv_fragments++; |
1652 | ret = tipc_link_recv_fragment(&l_ptr->defragm_buf, | 1646 | ret = tipc_link_recv_fragment(&l_ptr->reasm_head, |
1653 | &buf, &msg); | 1647 | &l_ptr->reasm_tail, |
1654 | if (ret == 1) { | 1648 | &buf); |
1649 | if (ret == LINK_REASM_COMPLETE) { | ||
1655 | l_ptr->stats.recv_fragmented++; | 1650 | l_ptr->stats.recv_fragmented++; |
1651 | msg = buf_msg(buf); | ||
1656 | goto deliver; | 1652 | goto deliver; |
1657 | } | 1653 | } |
1658 | if (ret == -1) | 1654 | if (ret == LINK_REASM_ERROR) |
1659 | l_ptr->next_in_no--; | 1655 | l_ptr->next_in_no--; |
1660 | tipc_node_unlock(n_ptr); | 1656 | tipc_node_unlock(n_ptr); |
1661 | continue; | 1657 | continue; |
@@ -2343,114 +2339,47 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf) | |||
2343 | } | 2339 | } |
2344 | 2340 | ||
2345 | /* | 2341 | /* |
2346 | * A pending message being re-assembled must store certain values | ||
2347 | * to handle subsequent fragments correctly. The following functions | ||
2348 | * help storing these values in unused, available fields in the | ||
2349 | * pending message. This makes dynamic memory allocation unnecessary. | ||
2350 | */ | ||
2351 | static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno) | ||
2352 | { | ||
2353 | msg_set_seqno(buf_msg(buf), seqno); | ||
2354 | } | ||
2355 | |||
2356 | static u32 get_fragm_size(struct sk_buff *buf) | ||
2357 | { | ||
2358 | return msg_ack(buf_msg(buf)); | ||
2359 | } | ||
2360 | |||
2361 | static void set_fragm_size(struct sk_buff *buf, u32 sz) | ||
2362 | { | ||
2363 | msg_set_ack(buf_msg(buf), sz); | ||
2364 | } | ||
2365 | |||
2366 | static u32 get_expected_frags(struct sk_buff *buf) | ||
2367 | { | ||
2368 | return msg_bcast_ack(buf_msg(buf)); | ||
2369 | } | ||
2370 | |||
2371 | static void set_expected_frags(struct sk_buff *buf, u32 exp) | ||
2372 | { | ||
2373 | msg_set_bcast_ack(buf_msg(buf), exp); | ||
2374 | } | ||
2375 | |||
2376 | /* | ||
2377 | * tipc_link_recv_fragment(): Called with node lock on. Returns | 2342 | * tipc_link_recv_fragment(): Called with node lock on. Returns |
2378 | * the reassembled buffer if message is complete. | 2343 | * the reassembled buffer if message is complete. |
2379 | */ | 2344 | */ |
2380 | int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, | 2345 | int tipc_link_recv_fragment(struct sk_buff **head, struct sk_buff **tail, |
2381 | struct tipc_msg **m) | 2346 | struct sk_buff **fbuf) |
2382 | { | 2347 | { |
2383 | struct sk_buff *prev = NULL; | 2348 | struct sk_buff *frag = *fbuf; |
2384 | struct sk_buff *fbuf = *fb; | 2349 | struct tipc_msg *msg = buf_msg(frag); |
2385 | struct tipc_msg *fragm = buf_msg(fbuf); | 2350 | u32 fragid = msg_type(msg); |
2386 | struct sk_buff *pbuf = *pending; | 2351 | bool headstolen; |
2387 | u32 long_msg_seq_no = msg_long_msgno(fragm); | 2352 | int delta; |
2388 | 2353 | ||
2389 | *fb = NULL; | 2354 | skb_pull(frag, msg_hdr_sz(msg)); |
2390 | 2355 | if (fragid == FIRST_FRAGMENT) { | |
2391 | /* Is there an incomplete message waiting for this fragment? */ | 2356 | if (*head || skb_unclone(frag, GFP_ATOMIC)) |
2392 | while (pbuf && ((buf_seqno(pbuf) != long_msg_seq_no) || | 2357 | goto out_free; |
2393 | (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) { | 2358 | *head = frag; |
2394 | prev = pbuf; | 2359 | skb_frag_list_init(*head); |
2395 | pbuf = pbuf->next; | ||
2396 | } | ||
2397 | |||
2398 | if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) { | ||
2399 | struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm); | ||
2400 | u32 msg_sz = msg_size(imsg); | ||
2401 | u32 fragm_sz = msg_data_sz(fragm); | ||
2402 | u32 exp_fragm_cnt; | ||
2403 | u32 max = TIPC_MAX_USER_MSG_SIZE + NAMED_H_SIZE; | ||
2404 | |||
2405 | if (msg_type(imsg) == TIPC_MCAST_MSG) | ||
2406 | max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE; | ||
2407 | if (fragm_sz == 0 || msg_size(imsg) > max) { | ||
2408 | kfree_skb(fbuf); | ||
2409 | return 0; | ||
2410 | } | ||
2411 | exp_fragm_cnt = msg_sz / fragm_sz + !!(msg_sz % fragm_sz); | ||
2412 | pbuf = tipc_buf_acquire(msg_size(imsg)); | ||
2413 | if (pbuf != NULL) { | ||
2414 | pbuf->next = *pending; | ||
2415 | *pending = pbuf; | ||
2416 | skb_copy_to_linear_data(pbuf, imsg, | ||
2417 | msg_data_sz(fragm)); | ||
2418 | /* Prepare buffer for subsequent fragments. */ | ||
2419 | set_long_msg_seqno(pbuf, long_msg_seq_no); | ||
2420 | set_fragm_size(pbuf, fragm_sz); | ||
2421 | set_expected_frags(pbuf, exp_fragm_cnt - 1); | ||
2422 | } else { | ||
2423 | pr_debug("Link unable to reassemble fragmented message\n"); | ||
2424 | kfree_skb(fbuf); | ||
2425 | return -1; | ||
2426 | } | ||
2427 | kfree_skb(fbuf); | ||
2428 | return 0; | ||
2429 | } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) { | ||
2430 | u32 dsz = msg_data_sz(fragm); | ||
2431 | u32 fsz = get_fragm_size(pbuf); | ||
2432 | u32 crs = ((msg_fragm_no(fragm) - 1) * fsz); | ||
2433 | u32 exp_frags = get_expected_frags(pbuf) - 1; | ||
2434 | skb_copy_to_linear_data_offset(pbuf, crs, | ||
2435 | msg_data(fragm), dsz); | ||
2436 | kfree_skb(fbuf); | ||
2437 | |||
2438 | /* Is message complete? */ | ||
2439 | if (exp_frags == 0) { | ||
2440 | if (prev) | ||
2441 | prev->next = pbuf->next; | ||
2442 | else | ||
2443 | *pending = pbuf->next; | ||
2444 | msg_reset_reroute_cnt(buf_msg(pbuf)); | ||
2445 | *fb = pbuf; | ||
2446 | *m = buf_msg(pbuf); | ||
2447 | return 1; | ||
2448 | } | ||
2449 | set_expected_frags(pbuf, exp_frags); | ||
2450 | return 0; | 2360 | return 0; |
2361 | } else if (skb_try_coalesce(*head, frag, &headstolen, &delta)) { | ||
2362 | kfree_skb_partial(frag, headstolen); | ||
2363 | } else { | ||
2364 | if (!*head) | ||
2365 | goto out_free; | ||
2366 | if (!skb_has_frag_list(*head)) | ||
2367 | skb_shinfo(*head)->frag_list = frag; | ||
2368 | else | ||
2369 | (*tail)->next = frag; | ||
2370 | *tail = frag; | ||
2371 | (*head)->truesize += frag->truesize; | ||
2372 | } | ||
2373 | if (fragid == LAST_FRAGMENT) { | ||
2374 | *fbuf = *head; | ||
2375 | *tail = *head = NULL; | ||
2376 | return LINK_REASM_COMPLETE; | ||
2451 | } | 2377 | } |
2452 | kfree_skb(fbuf); | ||
2453 | return 0; | 2378 | return 0; |
2379 | out_free: | ||
2380 | pr_warn_ratelimited("Link unable to reassemble fragmented message\n"); | ||
2381 | kfree_skb(*fbuf); | ||
2382 | return LINK_REASM_ERROR; | ||
2454 | } | 2383 | } |
2455 | 2384 | ||
2456 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) | 2385 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) |