diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/bcast.c | 87 | ||||
| -rw-r--r-- | net/tipc/bcast.h | 5 | ||||
| -rw-r--r-- | net/tipc/link.c | 794 | ||||
| -rw-r--r-- | net/tipc/link.h | 7 | ||||
| -rw-r--r-- | net/tipc/msg.c | 381 | ||||
| -rw-r--r-- | net/tipc/msg.h | 35 | ||||
| -rw-r--r-- | net/tipc/name_distr.c | 76 | ||||
| -rw-r--r-- | net/tipc/name_distr.h | 2 | ||||
| -rw-r--r-- | net/tipc/net.c | 63 | ||||
| -rw-r--r-- | net/tipc/net.h | 2 | ||||
| -rw-r--r-- | net/tipc/node.c | 38 | ||||
| -rw-r--r-- | net/tipc/node.h | 17 | ||||
| -rw-r--r-- | net/tipc/node_subscr.c | 6 | ||||
| -rw-r--r-- | net/tipc/port.c | 440 | ||||
| -rw-r--r-- | net/tipc/port.h | 55 | ||||
| -rw-r--r-- | net/tipc/socket.c | 553 | ||||
| -rw-r--r-- | net/tipc/socket.h | 16 |
17 files changed, 1117 insertions, 1460 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 55c6c9d3e1ce..dd13bfa09333 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/bcast.c: TIPC broadcast code | 2 | * net/tipc/bcast.c: TIPC broadcast code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2004-2006, Ericsson AB | 4 | * Copyright (c) 2004-2006, 2014, Ericsson AB |
| 5 | * Copyright (c) 2004, Intel Corporation. | 5 | * Copyright (c) 2004, Intel Corporation. |
| 6 | * Copyright (c) 2005, 2010-2011, Wind River Systems | 6 | * Copyright (c) 2005, 2010-2011, Wind River Systems |
| 7 | * All rights reserved. | 7 | * All rights reserved. |
| @@ -38,6 +38,8 @@ | |||
| 38 | #include "core.h" | 38 | #include "core.h" |
| 39 | #include "link.h" | 39 | #include "link.h" |
| 40 | #include "port.h" | 40 | #include "port.h" |
| 41 | #include "socket.h" | ||
| 42 | #include "msg.h" | ||
| 41 | #include "bcast.h" | 43 | #include "bcast.h" |
| 42 | #include "name_distr.h" | 44 | #include "name_distr.h" |
| 43 | 45 | ||
| @@ -138,6 +140,11 @@ static void tipc_bclink_unlock(void) | |||
| 138 | tipc_link_reset_all(node); | 140 | tipc_link_reset_all(node); |
| 139 | } | 141 | } |
| 140 | 142 | ||
| 143 | uint tipc_bclink_get_mtu(void) | ||
| 144 | { | ||
| 145 | return MAX_PKT_DEFAULT_MCAST; | ||
| 146 | } | ||
| 147 | |||
| 141 | void tipc_bclink_set_flags(unsigned int flags) | 148 | void tipc_bclink_set_flags(unsigned int flags) |
| 142 | { | 149 | { |
| 143 | bclink->flags |= flags; | 150 | bclink->flags |= flags; |
| @@ -382,30 +389,50 @@ static void bclink_peek_nack(struct tipc_msg *msg) | |||
| 382 | tipc_node_unlock(n_ptr); | 389 | tipc_node_unlock(n_ptr); |
| 383 | } | 390 | } |
| 384 | 391 | ||
| 385 | /* | 392 | /* tipc_bclink_xmit - broadcast buffer chain to all nodes in cluster |
| 386 | * tipc_bclink_xmit - broadcast a packet to all nodes in cluster | 393 | * and to identified node local sockets |
| 394 | * @buf: chain of buffers containing message | ||
| 395 | * Consumes the buffer chain, except when returning -ELINKCONG | ||
| 396 | * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE | ||
| 387 | */ | 397 | */ |
| 388 | int tipc_bclink_xmit(struct sk_buff *buf) | 398 | int tipc_bclink_xmit(struct sk_buff *buf) |
| 389 | { | 399 | { |
| 390 | int res; | 400 | int rc = 0; |
| 401 | int bc = 0; | ||
| 402 | struct sk_buff *clbuf; | ||
| 391 | 403 | ||
| 392 | tipc_bclink_lock(); | 404 | /* Prepare clone of message for local node */ |
| 393 | 405 | clbuf = tipc_msg_reassemble(buf); | |
| 394 | if (!bclink->bcast_nodes.count) { | 406 | if (unlikely(!clbuf)) { |
| 395 | res = msg_data_sz(buf_msg(buf)); | 407 | kfree_skb_list(buf); |
| 396 | kfree_skb(buf); | 408 | return -EHOSTUNREACH; |
| 397 | goto exit; | ||
| 398 | } | 409 | } |
| 399 | 410 | ||
| 400 | res = __tipc_link_xmit(bcl, buf); | 411 | /* Broadcast to all other nodes */ |
| 401 | if (likely(res >= 0)) { | 412 | if (likely(bclink)) { |
| 402 | bclink_set_last_sent(); | 413 | tipc_bclink_lock(); |
| 403 | bcl->stats.queue_sz_counts++; | 414 | if (likely(bclink->bcast_nodes.count)) { |
| 404 | bcl->stats.accu_queue_sz += bcl->out_queue_size; | 415 | rc = __tipc_link_xmit(bcl, buf); |
| 416 | if (likely(!rc)) { | ||
| 417 | bclink_set_last_sent(); | ||
| 418 | bcl->stats.queue_sz_counts++; | ||
| 419 | bcl->stats.accu_queue_sz += bcl->out_queue_size; | ||
| 420 | } | ||
| 421 | bc = 1; | ||
| 422 | } | ||
| 423 | tipc_bclink_unlock(); | ||
| 405 | } | 424 | } |
| 406 | exit: | 425 | |
| 407 | tipc_bclink_unlock(); | 426 | if (unlikely(!bc)) |
| 408 | return res; | 427 | kfree_skb_list(buf); |
| 428 | |||
| 429 | /* Deliver message clone */ | ||
| 430 | if (likely(!rc)) | ||
| 431 | tipc_sk_mcast_rcv(clbuf); | ||
| 432 | else | ||
| 433 | kfree_skb(clbuf); | ||
| 434 | |||
| 435 | return rc; | ||
| 409 | } | 436 | } |
| 410 | 437 | ||
| 411 | /** | 438 | /** |
| @@ -443,7 +470,7 @@ void tipc_bclink_rcv(struct sk_buff *buf) | |||
| 443 | struct tipc_node *node; | 470 | struct tipc_node *node; |
| 444 | u32 next_in; | 471 | u32 next_in; |
| 445 | u32 seqno; | 472 | u32 seqno; |
| 446 | int deferred; | 473 | int deferred = 0; |
| 447 | 474 | ||
| 448 | /* Screen out unwanted broadcast messages */ | 475 | /* Screen out unwanted broadcast messages */ |
| 449 | 476 | ||
| @@ -494,7 +521,7 @@ receive: | |||
| 494 | tipc_bclink_unlock(); | 521 | tipc_bclink_unlock(); |
| 495 | tipc_node_unlock(node); | 522 | tipc_node_unlock(node); |
| 496 | if (likely(msg_mcast(msg))) | 523 | if (likely(msg_mcast(msg))) |
| 497 | tipc_port_mcast_rcv(buf, NULL); | 524 | tipc_sk_mcast_rcv(buf); |
| 498 | else | 525 | else |
| 499 | kfree_skb(buf); | 526 | kfree_skb(buf); |
| 500 | } else if (msg_user(msg) == MSG_BUNDLER) { | 527 | } else if (msg_user(msg) == MSG_BUNDLER) { |
| @@ -573,8 +600,7 @@ receive: | |||
| 573 | node->bclink.deferred_size += deferred; | 600 | node->bclink.deferred_size += deferred; |
| 574 | bclink_update_last_sent(node, seqno); | 601 | bclink_update_last_sent(node, seqno); |
| 575 | buf = NULL; | 602 | buf = NULL; |
| 576 | } else | 603 | } |
| 577 | deferred = 0; | ||
| 578 | 604 | ||
| 579 | tipc_bclink_lock(); | 605 | tipc_bclink_lock(); |
| 580 | 606 | ||
| @@ -611,6 +637,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 611 | struct tipc_media_addr *unused2) | 637 | struct tipc_media_addr *unused2) |
| 612 | { | 638 | { |
| 613 | int bp_index; | 639 | int bp_index; |
| 640 | struct tipc_msg *msg = buf_msg(buf); | ||
| 614 | 641 | ||
| 615 | /* Prepare broadcast link message for reliable transmission, | 642 | /* Prepare broadcast link message for reliable transmission, |
| 616 | * if first time trying to send it; | 643 | * if first time trying to send it; |
| @@ -618,10 +645,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 618 | * since they are sent in an unreliable manner and don't need it | 645 | * since they are sent in an unreliable manner and don't need it |
| 619 | */ | 646 | */ |
| 620 | if (likely(!msg_non_seq(buf_msg(buf)))) { | 647 | if (likely(!msg_non_seq(buf_msg(buf)))) { |
| 621 | struct tipc_msg *msg; | ||
| 622 | |||
| 623 | bcbuf_set_acks(buf, bclink->bcast_nodes.count); | 648 | bcbuf_set_acks(buf, bclink->bcast_nodes.count); |
| 624 | msg = buf_msg(buf); | ||
| 625 | msg_set_non_seq(msg, 1); | 649 | msg_set_non_seq(msg, 1); |
| 626 | msg_set_mc_netid(msg, tipc_net_id); | 650 | msg_set_mc_netid(msg, tipc_net_id); |
| 627 | bcl->stats.sent_info++; | 651 | bcl->stats.sent_info++; |
| @@ -638,12 +662,14 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 638 | for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { | 662 | for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { |
| 639 | struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary; | 663 | struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary; |
| 640 | struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary; | 664 | struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary; |
| 641 | struct tipc_bearer *b = p; | 665 | struct tipc_bearer *bp[2] = {p, s}; |
| 666 | struct tipc_bearer *b = bp[msg_link_selector(msg)]; | ||
| 642 | struct sk_buff *tbuf; | 667 | struct sk_buff *tbuf; |
| 643 | 668 | ||
| 644 | if (!p) | 669 | if (!p) |
| 645 | break; /* No more bearers to try */ | 670 | break; /* No more bearers to try */ |
| 646 | 671 | if (!b) | |
| 672 | b = p; | ||
| 647 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, | 673 | tipc_nmap_diff(&bcbearer->remains, &b->nodes, |
| 648 | &bcbearer->remains_new); | 674 | &bcbearer->remains_new); |
| 649 | if (bcbearer->remains_new.count == bcbearer->remains.count) | 675 | if (bcbearer->remains_new.count == bcbearer->remains.count) |
| @@ -660,13 +686,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, | |||
| 660 | tipc_bearer_send(b->identity, tbuf, &b->bcast_addr); | 686 | tipc_bearer_send(b->identity, tbuf, &b->bcast_addr); |
| 661 | kfree_skb(tbuf); /* Bearer keeps a clone */ | 687 | kfree_skb(tbuf); /* Bearer keeps a clone */ |
| 662 | } | 688 | } |
| 663 | |||
| 664 | /* Swap bearers for next packet */ | ||
| 665 | if (s) { | ||
| 666 | bcbearer->bpairs[bp_index].primary = s; | ||
| 667 | bcbearer->bpairs[bp_index].secondary = p; | ||
| 668 | } | ||
| 669 | |||
| 670 | if (bcbearer->remains_new.count == 0) | 689 | if (bcbearer->remains_new.count == 0) |
| 671 | break; /* All targets reached */ | 690 | break; /* All targets reached */ |
| 672 | 691 | ||
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 00330c45df3e..4875d9536aee 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/bcast.h: Include file for TIPC broadcast code | 2 | * net/tipc/bcast.h: Include file for TIPC broadcast code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2003-2006, Ericsson AB | 4 | * Copyright (c) 2003-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 | * |
| @@ -89,7 +89,6 @@ void tipc_bclink_add_node(u32 addr); | |||
| 89 | void tipc_bclink_remove_node(u32 addr); | 89 | void tipc_bclink_remove_node(u32 addr); |
| 90 | struct tipc_node *tipc_bclink_retransmit_to(void); | 90 | struct tipc_node *tipc_bclink_retransmit_to(void); |
| 91 | void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked); | 91 | void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked); |
| 92 | int tipc_bclink_xmit(struct sk_buff *buf); | ||
| 93 | void tipc_bclink_rcv(struct sk_buff *buf); | 92 | void tipc_bclink_rcv(struct sk_buff *buf); |
| 94 | u32 tipc_bclink_get_last_sent(void); | 93 | u32 tipc_bclink_get_last_sent(void); |
| 95 | u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); | 94 | u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); |
| @@ -98,5 +97,7 @@ int tipc_bclink_stats(char *stats_buf, const u32 buf_size); | |||
| 98 | int tipc_bclink_reset_stats(void); | 97 | int tipc_bclink_reset_stats(void); |
| 99 | int tipc_bclink_set_queue_limits(u32 limit); | 98 | int tipc_bclink_set_queue_limits(u32 limit); |
| 100 | void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action); | 99 | void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action); |
| 100 | uint tipc_bclink_get_mtu(void); | ||
| 101 | int tipc_bclink_xmit(struct sk_buff *buf); | ||
| 101 | 102 | ||
| 102 | #endif | 103 | #endif |
diff --git a/net/tipc/link.c b/net/tipc/link.c index ad2c57f5868d..fb1485dc6736 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
| @@ -82,15 +82,13 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf); | |||
| 82 | static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr, | 82 | static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr, |
| 83 | struct sk_buff **buf); | 83 | struct sk_buff **buf); |
| 84 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); | 84 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); |
| 85 | static int tipc_link_iovec_long_xmit(struct tipc_port *sender, | ||
| 86 | struct iovec const *msg_sect, | ||
| 87 | unsigned int len, u32 destnode); | ||
| 88 | static void link_state_event(struct tipc_link *l_ptr, u32 event); | 85 | static void link_state_event(struct tipc_link *l_ptr, u32 event); |
| 89 | static void link_reset_statistics(struct tipc_link *l_ptr); | 86 | static void link_reset_statistics(struct tipc_link *l_ptr); |
| 90 | static void link_print(struct tipc_link *l_ptr, const char *str); | 87 | static void link_print(struct tipc_link *l_ptr, const char *str); |
| 91 | static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf); | ||
| 92 | static void tipc_link_sync_xmit(struct tipc_link *l); | 88 | static void tipc_link_sync_xmit(struct tipc_link *l); |
| 93 | static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); | 89 | static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); |
| 90 | static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf); | ||
| 91 | static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf); | ||
| 94 | 92 | ||
| 95 | /* | 93 | /* |
| 96 | * Simple link routines | 94 | * Simple link routines |
| @@ -335,13 +333,15 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) | |||
| 335 | static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz) | 333 | static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz) |
| 336 | { | 334 | { |
| 337 | struct tipc_port *p_ptr; | 335 | struct tipc_port *p_ptr; |
| 336 | struct tipc_sock *tsk; | ||
| 338 | 337 | ||
| 339 | spin_lock_bh(&tipc_port_list_lock); | 338 | spin_lock_bh(&tipc_port_list_lock); |
| 340 | p_ptr = tipc_port_lock(origport); | 339 | p_ptr = tipc_port_lock(origport); |
| 341 | if (p_ptr) { | 340 | if (p_ptr) { |
| 342 | if (!list_empty(&p_ptr->wait_list)) | 341 | if (!list_empty(&p_ptr->wait_list)) |
| 343 | goto exit; | 342 | goto exit; |
| 344 | p_ptr->congested = 1; | 343 | tsk = tipc_port_to_sock(p_ptr); |
| 344 | tsk->link_cong = 1; | ||
| 345 | p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt); | 345 | p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt); |
| 346 | list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports); | 346 | list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports); |
| 347 | l_ptr->stats.link_congs++; | 347 | l_ptr->stats.link_congs++; |
| @@ -355,6 +355,7 @@ exit: | |||
| 355 | void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) | 355 | void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) |
| 356 | { | 356 | { |
| 357 | struct tipc_port *p_ptr; | 357 | struct tipc_port *p_ptr; |
| 358 | struct tipc_sock *tsk; | ||
| 358 | struct tipc_port *temp_p_ptr; | 359 | struct tipc_port *temp_p_ptr; |
| 359 | int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size; | 360 | int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size; |
| 360 | 361 | ||
| @@ -370,10 +371,11 @@ void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) | |||
| 370 | wait_list) { | 371 | wait_list) { |
| 371 | if (win <= 0) | 372 | if (win <= 0) |
| 372 | break; | 373 | break; |
| 374 | tsk = tipc_port_to_sock(p_ptr); | ||
| 373 | list_del_init(&p_ptr->wait_list); | 375 | list_del_init(&p_ptr->wait_list); |
| 374 | spin_lock_bh(p_ptr->lock); | 376 | spin_lock_bh(p_ptr->lock); |
| 375 | p_ptr->congested = 0; | 377 | tsk->link_cong = 0; |
| 376 | tipc_port_wakeup(p_ptr); | 378 | tipc_sock_wakeup(tsk); |
| 377 | win -= p_ptr->waiting_pkts; | 379 | win -= p_ptr->waiting_pkts; |
| 378 | spin_unlock_bh(p_ptr->lock); | 380 | spin_unlock_bh(p_ptr->lock); |
| 379 | } | 381 | } |
| @@ -676,178 +678,142 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) | |||
| 676 | } | 678 | } |
| 677 | } | 679 | } |
| 678 | 680 | ||
| 679 | /* | 681 | /* tipc_link_cong: determine return value and how to treat the |
| 680 | * link_bundle_buf(): Append contents of a buffer to | 682 | * sent buffer during link congestion. |
| 681 | * the tail of an existing one. | 683 | * - For plain, errorless user data messages we keep the buffer and |
| 684 | * return -ELINKONG. | ||
| 685 | * - For all other messages we discard the buffer and return -EHOSTUNREACH | ||
| 686 | * - For TIPC internal messages we also reset the link | ||
| 682 | */ | 687 | */ |
| 683 | static int link_bundle_buf(struct tipc_link *l_ptr, struct sk_buff *bundler, | 688 | static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf) |
| 684 | struct sk_buff *buf) | ||
| 685 | { | 689 | { |
| 686 | struct tipc_msg *bundler_msg = buf_msg(bundler); | ||
| 687 | struct tipc_msg *msg = buf_msg(buf); | 690 | struct tipc_msg *msg = buf_msg(buf); |
| 688 | u32 size = msg_size(msg); | 691 | uint psz = msg_size(msg); |
| 689 | u32 bundle_size = msg_size(bundler_msg); | 692 | uint imp = tipc_msg_tot_importance(msg); |
| 690 | u32 to_pos = align(bundle_size); | 693 | u32 oport = msg_tot_origport(msg); |
| 691 | u32 pad = to_pos - bundle_size; | ||
| 692 | |||
| 693 | if (msg_user(bundler_msg) != MSG_BUNDLER) | ||
| 694 | return 0; | ||
| 695 | if (msg_type(bundler_msg) != OPEN_MSG) | ||
| 696 | return 0; | ||
| 697 | if (skb_tailroom(bundler) < (pad + size)) | ||
| 698 | return 0; | ||
| 699 | if (l_ptr->max_pkt < (to_pos + size)) | ||
| 700 | return 0; | ||
| 701 | |||
| 702 | skb_put(bundler, pad + size); | ||
| 703 | skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size); | ||
| 704 | msg_set_size(bundler_msg, to_pos + size); | ||
| 705 | msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1); | ||
| 706 | kfree_skb(buf); | ||
| 707 | l_ptr->stats.sent_bundled++; | ||
| 708 | return 1; | ||
| 709 | } | ||
| 710 | |||
| 711 | static void link_add_to_outqueue(struct tipc_link *l_ptr, | ||
| 712 | struct sk_buff *buf, | ||
| 713 | struct tipc_msg *msg) | ||
| 714 | { | ||
| 715 | u32 ack = mod(l_ptr->next_in_no - 1); | ||
| 716 | u32 seqno = mod(l_ptr->next_out_no++); | ||
| 717 | 694 | ||
| 718 | msg_set_word(msg, 2, ((ack << 16) | seqno)); | 695 | if (likely(imp <= TIPC_CRITICAL_IMPORTANCE)) { |
| 719 | msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); | 696 | if (!msg_errcode(msg) && !msg_reroute_cnt(msg)) { |
| 720 | buf->next = NULL; | 697 | link_schedule_port(link, oport, psz); |
| 721 | if (l_ptr->first_out) { | 698 | return -ELINKCONG; |
| 722 | l_ptr->last_out->next = buf; | 699 | } |
| 723 | l_ptr->last_out = buf; | 700 | } else { |
| 724 | } else | 701 | pr_warn("%s<%s>, send queue full", link_rst_msg, link->name); |
| 725 | l_ptr->first_out = l_ptr->last_out = buf; | 702 | tipc_link_reset(link); |
| 726 | |||
| 727 | l_ptr->out_queue_size++; | ||
| 728 | if (l_ptr->out_queue_size > l_ptr->stats.max_queue_sz) | ||
| 729 | l_ptr->stats.max_queue_sz = l_ptr->out_queue_size; | ||
| 730 | } | ||
| 731 | |||
| 732 | static void link_add_chain_to_outqueue(struct tipc_link *l_ptr, | ||
| 733 | struct sk_buff *buf_chain, | ||
| 734 | u32 long_msgno) | ||
| 735 | { | ||
| 736 | struct sk_buff *buf; | ||
| 737 | struct tipc_msg *msg; | ||
| 738 | |||
| 739 | if (!l_ptr->next_out) | ||
| 740 | l_ptr->next_out = buf_chain; | ||
| 741 | while (buf_chain) { | ||
| 742 | buf = buf_chain; | ||
| 743 | buf_chain = buf_chain->next; | ||
| 744 | |||
| 745 | msg = buf_msg(buf); | ||
| 746 | msg_set_long_msgno(msg, long_msgno); | ||
| 747 | link_add_to_outqueue(l_ptr, buf, msg); | ||
| 748 | } | 703 | } |
| 704 | kfree_skb_list(buf); | ||
| 705 | return -EHOSTUNREACH; | ||
| 749 | } | 706 | } |
| 750 | 707 | ||
| 751 | /* | 708 | /** |
| 752 | * tipc_link_xmit() is the 'full path' for messages, called from | 709 | * __tipc_link_xmit(): same as tipc_link_xmit, but destlink is known & locked |
| 753 | * inside TIPC when the 'fast path' in tipc_send_xmit | 710 | * @link: link to use |
| 754 | * has failed, and from link_send() | 711 | * @buf: chain of buffers containing message |
| 712 | * Consumes the buffer chain, except when returning -ELINKCONG | ||
| 713 | * Returns 0 if success, otherwise errno: -ELINKCONG, -EMSGSIZE (plain socket | ||
| 714 | * user data messages) or -EHOSTUNREACH (all other messages/senders) | ||
| 715 | * Only the socket functions tipc_send_stream() and tipc_send_packet() need | ||
| 716 | * to act on the return value, since they may need to do more send attempts. | ||
| 755 | */ | 717 | */ |
| 756 | int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf) | 718 | int __tipc_link_xmit(struct tipc_link *link, struct sk_buff *buf) |
| 757 | { | 719 | { |
| 758 | struct tipc_msg *msg = buf_msg(buf); | 720 | struct tipc_msg *msg = buf_msg(buf); |
| 759 | u32 size = msg_size(msg); | 721 | uint psz = msg_size(msg); |
| 760 | u32 dsz = msg_data_sz(msg); | 722 | uint qsz = link->out_queue_size; |
| 761 | u32 queue_size = l_ptr->out_queue_size; | 723 | uint sndlim = link->queue_limit[0]; |
| 762 | u32 imp = tipc_msg_tot_importance(msg); | 724 | uint imp = tipc_msg_tot_importance(msg); |
| 763 | u32 queue_limit = l_ptr->queue_limit[imp]; | 725 | uint mtu = link->max_pkt; |
| 764 | u32 max_packet = l_ptr->max_pkt; | 726 | uint ack = mod(link->next_in_no - 1); |
| 765 | 727 | uint seqno = link->next_out_no; | |
| 766 | /* Match msg importance against queue limits: */ | 728 | uint bc_last_in = link->owner->bclink.last_in; |
| 767 | if (unlikely(queue_size >= queue_limit)) { | 729 | struct tipc_media_addr *addr = &link->media_addr; |
| 768 | if (imp <= TIPC_CRITICAL_IMPORTANCE) { | 730 | struct sk_buff *next = buf->next; |
| 769 | link_schedule_port(l_ptr, msg_origport(msg), size); | 731 | |
| 770 | kfree_skb(buf); | 732 | /* Match queue limits against msg importance: */ |
| 771 | return -ELINKCONG; | 733 | if (unlikely(qsz >= link->queue_limit[imp])) |
| 772 | } | 734 | return tipc_link_cong(link, buf); |
| 773 | kfree_skb(buf); | 735 | |
| 774 | if (imp > CONN_MANAGER) { | 736 | /* Has valid packet limit been used ? */ |
| 775 | pr_warn("%s<%s>, send queue full", link_rst_msg, | 737 | if (unlikely(psz > mtu)) { |
| 776 | l_ptr->name); | 738 | kfree_skb_list(buf); |
| 777 | tipc_link_reset(l_ptr); | 739 | return -EMSGSIZE; |
| 778 | } | ||
| 779 | return dsz; | ||
| 780 | } | 740 | } |
| 781 | 741 | ||
| 782 | /* Fragmentation needed ? */ | 742 | /* Prepare each packet for sending, and add to outqueue: */ |
| 783 | if (size > max_packet) | 743 | while (buf) { |
| 784 | return tipc_link_frag_xmit(l_ptr, buf); | 744 | next = buf->next; |
| 785 | 745 | msg = buf_msg(buf); | |
| 786 | /* Packet can be queued or sent. */ | 746 | msg_set_word(msg, 2, ((ack << 16) | mod(seqno))); |
| 787 | if (likely(!link_congested(l_ptr))) { | 747 | msg_set_bcast_ack(msg, bc_last_in); |
| 788 | link_add_to_outqueue(l_ptr, buf, msg); | 748 | |
| 749 | if (!link->first_out) { | ||
| 750 | link->first_out = buf; | ||
| 751 | } else if (qsz < sndlim) { | ||
| 752 | link->last_out->next = buf; | ||
| 753 | } else if (tipc_msg_bundle(link->last_out, buf, mtu)) { | ||
| 754 | link->stats.sent_bundled++; | ||
| 755 | buf = next; | ||
| 756 | next = buf->next; | ||
| 757 | continue; | ||
| 758 | } else if (tipc_msg_make_bundle(&buf, mtu, link->addr)) { | ||
| 759 | link->stats.sent_bundled++; | ||
| 760 | link->stats.sent_bundles++; | ||
| 761 | link->last_out->next = buf; | ||
| 762 | if (!link->next_out) | ||
| 763 | link->next_out = buf; | ||
| 764 | } else { | ||
| 765 | link->last_out->next = buf; | ||
| 766 | if (!link->next_out) | ||
| 767 | link->next_out = buf; | ||
| 768 | } | ||
| 789 | 769 | ||
| 790 | tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); | 770 | /* Send packet if possible: */ |
| 791 | l_ptr->unacked_window = 0; | 771 | if (likely(++qsz <= sndlim)) { |
| 792 | return dsz; | 772 | tipc_bearer_send(link->bearer_id, buf, addr); |
| 793 | } | 773 | link->next_out = next; |
| 794 | /* Congestion: can message be bundled ? */ | 774 | link->unacked_window = 0; |
| 795 | if ((msg_user(msg) != CHANGEOVER_PROTOCOL) && | ||
| 796 | (msg_user(msg) != MSG_FRAGMENTER)) { | ||
| 797 | |||
| 798 | /* Try adding message to an existing bundle */ | ||
| 799 | if (l_ptr->next_out && | ||
| 800 | link_bundle_buf(l_ptr, l_ptr->last_out, buf)) | ||
| 801 | return dsz; | ||
| 802 | |||
| 803 | /* Try creating a new bundle */ | ||
| 804 | if (size <= max_packet * 2 / 3) { | ||
| 805 | struct sk_buff *bundler = tipc_buf_acquire(max_packet); | ||
| 806 | struct tipc_msg bundler_hdr; | ||
| 807 | |||
| 808 | if (bundler) { | ||
| 809 | tipc_msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG, | ||
| 810 | INT_H_SIZE, l_ptr->addr); | ||
| 811 | skb_copy_to_linear_data(bundler, &bundler_hdr, | ||
| 812 | INT_H_SIZE); | ||
| 813 | skb_trim(bundler, INT_H_SIZE); | ||
| 814 | link_bundle_buf(l_ptr, bundler, buf); | ||
| 815 | buf = bundler; | ||
| 816 | msg = buf_msg(buf); | ||
| 817 | l_ptr->stats.sent_bundles++; | ||
| 818 | } | ||
| 819 | } | 775 | } |
| 776 | seqno++; | ||
| 777 | link->last_out = buf; | ||
| 778 | buf = next; | ||
| 820 | } | 779 | } |
| 821 | if (!l_ptr->next_out) | 780 | link->next_out_no = seqno; |
| 822 | l_ptr->next_out = buf; | 781 | link->out_queue_size = qsz; |
| 823 | link_add_to_outqueue(l_ptr, buf, msg); | 782 | return 0; |
| 824 | return dsz; | ||
| 825 | } | 783 | } |
| 826 | 784 | ||
| 827 | /* | 785 | /** |
| 828 | * tipc_link_xmit(): same as __tipc_link_xmit(), but the link to use | 786 | * tipc_link_xmit() is the general link level function for message sending |
| 829 | * has not been selected yet, and the the owner node is not locked | 787 | * @buf: chain of buffers containing message |
| 830 | * Called by TIPC internal users, e.g. the name distributor | 788 | * @dsz: amount of user data to be sent |
| 789 | * @dnode: address of destination node | ||
| 790 | * @selector: a number used for deterministic link selection | ||
| 791 | * Consumes the buffer chain, except when returning -ELINKCONG | ||
| 792 | * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE | ||
| 831 | */ | 793 | */ |
| 832 | int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector) | 794 | int tipc_link_xmit(struct sk_buff *buf, u32 dnode, u32 selector) |
| 833 | { | 795 | { |
| 834 | struct tipc_link *l_ptr; | 796 | struct tipc_link *link = NULL; |
| 835 | struct tipc_node *n_ptr; | 797 | struct tipc_node *node; |
| 836 | int res = -ELINKCONG; | 798 | int rc = -EHOSTUNREACH; |
| 837 | 799 | ||
| 838 | n_ptr = tipc_node_find(dest); | 800 | node = tipc_node_find(dnode); |
| 839 | if (n_ptr) { | 801 | if (node) { |
| 840 | tipc_node_lock(n_ptr); | 802 | tipc_node_lock(node); |
| 841 | l_ptr = n_ptr->active_links[selector & 1]; | 803 | link = node->active_links[selector & 1]; |
| 842 | if (l_ptr) | 804 | if (link) |
| 843 | res = __tipc_link_xmit(l_ptr, buf); | 805 | rc = __tipc_link_xmit(link, buf); |
| 844 | else | 806 | tipc_node_unlock(node); |
| 845 | kfree_skb(buf); | ||
| 846 | tipc_node_unlock(n_ptr); | ||
| 847 | } else { | ||
| 848 | kfree_skb(buf); | ||
| 849 | } | 807 | } |
| 850 | return res; | 808 | |
| 809 | if (link) | ||
| 810 | return rc; | ||
| 811 | |||
| 812 | if (likely(in_own_node(dnode))) | ||
| 813 | return tipc_sk_rcv(buf); | ||
| 814 | |||
| 815 | kfree_skb_list(buf); | ||
| 816 | return rc; | ||
| 851 | } | 817 | } |
| 852 | 818 | ||
| 853 | /* | 819 | /* |
| @@ -858,7 +824,7 @@ int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector) | |||
| 858 | * | 824 | * |
| 859 | * Called with node locked | 825 | * Called with node locked |
| 860 | */ | 826 | */ |
| 861 | static void tipc_link_sync_xmit(struct tipc_link *l) | 827 | static void tipc_link_sync_xmit(struct tipc_link *link) |
| 862 | { | 828 | { |
| 863 | struct sk_buff *buf; | 829 | struct sk_buff *buf; |
| 864 | struct tipc_msg *msg; | 830 | struct tipc_msg *msg; |
| @@ -868,10 +834,9 @@ static void tipc_link_sync_xmit(struct tipc_link *l) | |||
| 868 | return; | 834 | return; |
| 869 | 835 | ||
| 870 | msg = buf_msg(buf); | 836 | msg = buf_msg(buf); |
| 871 | tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, l->addr); | 837 | tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, link->addr); |
| 872 | msg_set_last_bcast(msg, l->owner->bclink.acked); | 838 | msg_set_last_bcast(msg, link->owner->bclink.acked); |
| 873 | link_add_chain_to_outqueue(l, buf, 0); | 839 | __tipc_link_xmit(link, buf); |
| 874 | tipc_link_push_queue(l); | ||
| 875 | } | 840 | } |
| 876 | 841 | ||
| 877 | /* | 842 | /* |
| @@ -892,293 +857,6 @@ static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf) | |||
| 892 | } | 857 | } |
| 893 | 858 | ||
| 894 | /* | 859 | /* |
| 895 | * tipc_link_names_xmit - send name table entries to new neighbor | ||
| 896 | * | ||
| 897 | * Send routine for bulk delivery of name table messages when contact | ||
| 898 | * with a new neighbor occurs. No link congestion checking is performed | ||
| 899 | * because name table messages *must* be delivered. The messages must be | ||
| 900 | * small enough not to require fragmentation. | ||
| 901 | * Called without any locks held. | ||
| 902 | */ | ||
| 903 | void tipc_link_names_xmit(struct list_head *message_list, u32 dest) | ||
| 904 | { | ||
| 905 | struct tipc_node *n_ptr; | ||
| 906 | struct tipc_link *l_ptr; | ||
| 907 | struct sk_buff *buf; | ||
| 908 | struct sk_buff *temp_buf; | ||
| 909 | |||
| 910 | if (list_empty(message_list)) | ||
| 911 | return; | ||
| 912 | |||
| 913 | n_ptr = tipc_node_find(dest); | ||
| 914 | if (n_ptr) { | ||
| 915 | tipc_node_lock(n_ptr); | ||
| 916 | l_ptr = n_ptr->active_links[0]; | ||
| 917 | if (l_ptr) { | ||
| 918 | /* convert circular list to linear list */ | ||
| 919 | ((struct sk_buff *)message_list->prev)->next = NULL; | ||
| 920 | link_add_chain_to_outqueue(l_ptr, | ||
| 921 | (struct sk_buff *)message_list->next, 0); | ||
| 922 | tipc_link_push_queue(l_ptr); | ||
| 923 | INIT_LIST_HEAD(message_list); | ||
| 924 | } | ||
| 925 | tipc_node_unlock(n_ptr); | ||
| 926 | } | ||
| 927 | |||
| 928 | /* discard the messages if they couldn't be sent */ | ||
| 929 | list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) { | ||
| 930 | list_del((struct list_head *)buf); | ||
| 931 | kfree_skb(buf); | ||
| 932 | } | ||
| 933 | } | ||
| 934 | |||
| 935 | /* | ||
| 936 | * tipc_link_xmit_fast: Entry for data messages where the | ||
| 937 | * destination link is known and the header is complete, | ||
| 938 | * inclusive total message length. Very time critical. | ||
| 939 | * Link is locked. Returns user data length. | ||
| 940 | */ | ||
| 941 | static int tipc_link_xmit_fast(struct tipc_link *l_ptr, struct sk_buff *buf, | ||
| 942 | u32 *used_max_pkt) | ||
| 943 | { | ||
| 944 | struct tipc_msg *msg = buf_msg(buf); | ||
| 945 | int res = msg_data_sz(msg); | ||
| 946 | |||
| 947 | if (likely(!link_congested(l_ptr))) { | ||
| 948 | if (likely(msg_size(msg) <= l_ptr->max_pkt)) { | ||
| 949 | link_add_to_outqueue(l_ptr, buf, msg); | ||
| 950 | tipc_bearer_send(l_ptr->bearer_id, buf, | ||
| 951 | &l_ptr->media_addr); | ||
| 952 | l_ptr->unacked_window = 0; | ||
| 953 | return res; | ||
| 954 | } | ||
| 955 | else | ||
| 956 | *used_max_pkt = l_ptr->max_pkt; | ||
| 957 | } | ||
| 958 | return __tipc_link_xmit(l_ptr, buf); /* All other cases */ | ||
| 959 | } | ||
| 960 | |||
| 961 | /* | ||
| 962 | * tipc_link_iovec_xmit_fast: Entry for messages where the | ||
| 963 | * destination processor is known and the header is complete, | ||
| 964 | * except for total message length. | ||
| 965 | * Returns user data length or errno. | ||
| 966 | */ | ||
| 967 | int tipc_link_iovec_xmit_fast(struct tipc_port *sender, | ||
| 968 | struct iovec const *msg_sect, | ||
| 969 | unsigned int len, u32 destaddr) | ||
| 970 | { | ||
| 971 | struct tipc_msg *hdr = &sender->phdr; | ||
| 972 | struct tipc_link *l_ptr; | ||
| 973 | struct sk_buff *buf; | ||
| 974 | struct tipc_node *node; | ||
| 975 | int res; | ||
| 976 | u32 selector = msg_origport(hdr) & 1; | ||
| 977 | |||
| 978 | again: | ||
| 979 | /* | ||
| 980 | * Try building message using port's max_pkt hint. | ||
| 981 | * (Must not hold any locks while building message.) | ||
| 982 | */ | ||
| 983 | res = tipc_msg_build(hdr, msg_sect, len, sender->max_pkt, &buf); | ||
| 984 | /* Exit if build request was invalid */ | ||
| 985 | if (unlikely(res < 0)) | ||
| 986 | return res; | ||
| 987 | |||
| 988 | node = tipc_node_find(destaddr); | ||
| 989 | if (likely(node)) { | ||
| 990 | tipc_node_lock(node); | ||
| 991 | l_ptr = node->active_links[selector]; | ||
| 992 | if (likely(l_ptr)) { | ||
| 993 | if (likely(buf)) { | ||
| 994 | res = tipc_link_xmit_fast(l_ptr, buf, | ||
| 995 | &sender->max_pkt); | ||
| 996 | exit: | ||
| 997 | tipc_node_unlock(node); | ||
| 998 | return res; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | /* Exit if link (or bearer) is congested */ | ||
| 1002 | if (link_congested(l_ptr)) { | ||
| 1003 | res = link_schedule_port(l_ptr, | ||
| 1004 | sender->ref, res); | ||
| 1005 | goto exit; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | /* | ||
| 1009 | * Message size exceeds max_pkt hint; update hint, | ||
| 1010 | * then re-try fast path or fragment the message | ||
| 1011 | */ | ||
| 1012 | sender->max_pkt = l_ptr->max_pkt; | ||
| 1013 | tipc_node_unlock(node); | ||
| 1014 | |||
| 1015 | |||
| 1016 | if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt) | ||
| 1017 | goto again; | ||
| 1018 | |||
| 1019 | return tipc_link_iovec_long_xmit(sender, msg_sect, | ||
| 1020 | len, destaddr); | ||
| 1021 | } | ||
| 1022 | tipc_node_unlock(node); | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | /* Couldn't find a link to the destination node */ | ||
| 1026 | kfree_skb(buf); | ||
| 1027 | tipc_port_iovec_reject(sender, hdr, msg_sect, len, TIPC_ERR_NO_NODE); | ||
| 1028 | return -ENETUNREACH; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | /* | ||
| 1032 | * tipc_link_iovec_long_xmit(): Entry for long messages where the | ||
| 1033 | * destination node is known and the header is complete, | ||
| 1034 | * inclusive total message length. | ||
| 1035 | * Link and bearer congestion status have been checked to be ok, | ||
| 1036 | * and are ignored if they change. | ||
| 1037 | * | ||
| 1038 | * Note that fragments do not use the full link MTU so that they won't have | ||
| 1039 | * to undergo refragmentation if link changeover causes them to be sent | ||
| 1040 | * over another link with an additional tunnel header added as prefix. | ||
| 1041 | * (Refragmentation will still occur if the other link has a smaller MTU.) | ||
| 1042 | * | ||
| 1043 | * Returns user data length or errno. | ||
| 1044 | */ | ||
| 1045 | static int tipc_link_iovec_long_xmit(struct tipc_port *sender, | ||
| 1046 | struct iovec const *msg_sect, | ||
| 1047 | unsigned int len, u32 destaddr) | ||
| 1048 | { | ||
| 1049 | struct tipc_link *l_ptr; | ||
| 1050 | struct tipc_node *node; | ||
| 1051 | struct tipc_msg *hdr = &sender->phdr; | ||
| 1052 | u32 dsz = len; | ||
| 1053 | u32 max_pkt, fragm_sz, rest; | ||
| 1054 | struct tipc_msg fragm_hdr; | ||
| 1055 | struct sk_buff *buf, *buf_chain, *prev; | ||
| 1056 | u32 fragm_crs, fragm_rest, hsz, sect_rest; | ||
| 1057 | const unchar __user *sect_crs; | ||
| 1058 | int curr_sect; | ||
| 1059 | u32 fragm_no; | ||
| 1060 | int res = 0; | ||
| 1061 | |||
| 1062 | again: | ||
| 1063 | fragm_no = 1; | ||
| 1064 | max_pkt = sender->max_pkt - INT_H_SIZE; | ||
| 1065 | /* leave room for tunnel header in case of link changeover */ | ||
| 1066 | fragm_sz = max_pkt - INT_H_SIZE; | ||
| 1067 | /* leave room for fragmentation header in each fragment */ | ||
| 1068 | rest = dsz; | ||
| 1069 | fragm_crs = 0; | ||
| 1070 | fragm_rest = 0; | ||
| 1071 | sect_rest = 0; | ||
| 1072 | sect_crs = NULL; | ||
| 1073 | curr_sect = -1; | ||
| 1074 | |||
| 1075 | /* Prepare reusable fragment header */ | ||
| 1076 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, | ||
| 1077 | INT_H_SIZE, msg_destnode(hdr)); | ||
| 1078 | msg_set_size(&fragm_hdr, max_pkt); | ||
| 1079 | msg_set_fragm_no(&fragm_hdr, 1); | ||
| 1080 | |||
| 1081 | /* Prepare header of first fragment */ | ||
| 1082 | buf_chain = buf = tipc_buf_acquire(max_pkt); | ||
| 1083 | if (!buf) | ||
| 1084 | return -ENOMEM; | ||
| 1085 | buf->next = NULL; | ||
| 1086 | skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); | ||
| 1087 | hsz = msg_hdr_sz(hdr); | ||
| 1088 | skb_copy_to_linear_data_offset(buf, INT_H_SIZE, hdr, hsz); | ||
| 1089 | |||
| 1090 | /* Chop up message */ | ||
| 1091 | fragm_crs = INT_H_SIZE + hsz; | ||
| 1092 | fragm_rest = fragm_sz - hsz; | ||
| 1093 | |||
| 1094 | do { /* For all sections */ | ||
| 1095 | u32 sz; | ||
| 1096 | |||
| 1097 | if (!sect_rest) { | ||
| 1098 | sect_rest = msg_sect[++curr_sect].iov_len; | ||
| 1099 | sect_crs = msg_sect[curr_sect].iov_base; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | if (sect_rest < fragm_rest) | ||
| 1103 | sz = sect_rest; | ||
| 1104 | else | ||
| 1105 | sz = fragm_rest; | ||
| 1106 | |||
| 1107 | if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) { | ||
| 1108 | res = -EFAULT; | ||
| 1109 | error: | ||
| 1110 | kfree_skb_list(buf_chain); | ||
| 1111 | return res; | ||
| 1112 | } | ||
| 1113 | sect_crs += sz; | ||
| 1114 | sect_rest -= sz; | ||
| 1115 | fragm_crs += sz; | ||
| 1116 | fragm_rest -= sz; | ||
| 1117 | rest -= sz; | ||
| 1118 | |||
| 1119 | if (!fragm_rest && rest) { | ||
| 1120 | |||
| 1121 | /* Initiate new fragment: */ | ||
| 1122 | if (rest <= fragm_sz) { | ||
| 1123 | fragm_sz = rest; | ||
| 1124 | msg_set_type(&fragm_hdr, LAST_FRAGMENT); | ||
| 1125 | } else { | ||
| 1126 | msg_set_type(&fragm_hdr, FRAGMENT); | ||
| 1127 | } | ||
| 1128 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); | ||
| 1129 | msg_set_fragm_no(&fragm_hdr, ++fragm_no); | ||
| 1130 | prev = buf; | ||
| 1131 | buf = tipc_buf_acquire(fragm_sz + INT_H_SIZE); | ||
| 1132 | if (!buf) { | ||
| 1133 | res = -ENOMEM; | ||
| 1134 | goto error; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | buf->next = NULL; | ||
| 1138 | prev->next = buf; | ||
| 1139 | skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE); | ||
| 1140 | fragm_crs = INT_H_SIZE; | ||
| 1141 | fragm_rest = fragm_sz; | ||
| 1142 | } | ||
| 1143 | } while (rest > 0); | ||
| 1144 | |||
| 1145 | /* | ||
| 1146 | * Now we have a buffer chain. Select a link and check | ||
| 1147 | * that packet size is still OK | ||
| 1148 | */ | ||
| 1149 | node = tipc_node_find(destaddr); | ||
| 1150 | if (likely(node)) { | ||
| 1151 | tipc_node_lock(node); | ||
| 1152 | l_ptr = node->active_links[sender->ref & 1]; | ||
| 1153 | if (!l_ptr) { | ||
| 1154 | tipc_node_unlock(node); | ||
| 1155 | goto reject; | ||
| 1156 | } | ||
| 1157 | if (l_ptr->max_pkt < max_pkt) { | ||
| 1158 | sender->max_pkt = l_ptr->max_pkt; | ||
| 1159 | tipc_node_unlock(node); | ||
| 1160 | kfree_skb_list(buf_chain); | ||
| 1161 | goto again; | ||
| 1162 | } | ||
| 1163 | } else { | ||
| 1164 | reject: | ||
| 1165 | kfree_skb_list(buf_chain); | ||
| 1166 | tipc_port_iovec_reject(sender, hdr, msg_sect, len, | ||
| 1167 | TIPC_ERR_NO_NODE); | ||
| 1168 | return -ENETUNREACH; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | /* Append chain of fragments to send queue & send them */ | ||
| 1172 | l_ptr->long_msg_seq_no++; | ||
| 1173 | link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); | ||
| 1174 | l_ptr->stats.sent_fragments += fragm_no; | ||
| 1175 | l_ptr->stats.sent_fragmented++; | ||
| 1176 | tipc_link_push_queue(l_ptr); | ||
| 1177 | tipc_node_unlock(node); | ||
| 1178 | return dsz; | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | /* | ||
| 1182 | * tipc_link_push_packet: Push one unsent packet to the media | 860 | * tipc_link_push_packet: Push one unsent packet to the media |
| 1183 | */ | 861 | */ |
| 1184 | static u32 tipc_link_push_packet(struct tipc_link *l_ptr) | 862 | static u32 tipc_link_push_packet(struct tipc_link *l_ptr) |
| @@ -1238,7 +916,7 @@ static u32 tipc_link_push_packet(struct tipc_link *l_ptr) | |||
| 1238 | tipc_bearer_send(l_ptr->bearer_id, buf, | 916 | tipc_bearer_send(l_ptr->bearer_id, buf, |
| 1239 | &l_ptr->media_addr); | 917 | &l_ptr->media_addr); |
| 1240 | if (msg_user(msg) == MSG_BUNDLER) | 918 | if (msg_user(msg) == MSG_BUNDLER) |
| 1241 | msg_set_type(msg, CLOSED_MSG); | 919 | msg_set_type(msg, BUNDLE_CLOSED); |
| 1242 | l_ptr->next_out = buf->next; | 920 | l_ptr->next_out = buf->next; |
| 1243 | return 0; | 921 | return 0; |
| 1244 | } | 922 | } |
| @@ -1527,11 +1205,6 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
| 1527 | if (unlikely(!list_empty(&l_ptr->waiting_ports))) | 1205 | if (unlikely(!list_empty(&l_ptr->waiting_ports))) |
| 1528 | tipc_link_wakeup_ports(l_ptr, 0); | 1206 | tipc_link_wakeup_ports(l_ptr, 0); |
| 1529 | 1207 | ||
| 1530 | if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) { | ||
| 1531 | l_ptr->stats.sent_acks++; | ||
| 1532 | tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | /* Process the incoming packet */ | 1208 | /* Process the incoming packet */ |
| 1536 | if (unlikely(!link_working_working(l_ptr))) { | 1209 | if (unlikely(!link_working_working(l_ptr))) { |
| 1537 | if (msg_user(msg) == LINK_PROTOCOL) { | 1210 | if (msg_user(msg) == LINK_PROTOCOL) { |
| @@ -1565,57 +1238,19 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
| 1565 | if (unlikely(l_ptr->oldest_deferred_in)) | 1238 | if (unlikely(l_ptr->oldest_deferred_in)) |
| 1566 | head = link_insert_deferred_queue(l_ptr, head); | 1239 | head = link_insert_deferred_queue(l_ptr, head); |
| 1567 | 1240 | ||
| 1568 | /* Deliver packet/message to correct user: */ | 1241 | if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) { |
| 1569 | if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL)) { | 1242 | l_ptr->stats.sent_acks++; |
| 1570 | if (!tipc_link_tunnel_rcv(n_ptr, &buf)) { | 1243 | tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); |
| 1571 | tipc_node_unlock(n_ptr); | ||
| 1572 | continue; | ||
| 1573 | } | ||
| 1574 | msg = buf_msg(buf); | ||
| 1575 | } else if (msg_user(msg) == MSG_FRAGMENTER) { | ||
| 1576 | l_ptr->stats.recv_fragments++; | ||
| 1577 | if (tipc_buf_append(&l_ptr->reasm_buf, &buf)) { | ||
| 1578 | l_ptr->stats.recv_fragmented++; | ||
| 1579 | msg = buf_msg(buf); | ||
| 1580 | } else { | ||
| 1581 | if (!l_ptr->reasm_buf) | ||
| 1582 | tipc_link_reset(l_ptr); | ||
| 1583 | tipc_node_unlock(n_ptr); | ||
| 1584 | continue; | ||
| 1585 | } | ||
| 1586 | } | 1244 | } |
| 1587 | 1245 | ||
| 1588 | switch (msg_user(msg)) { | 1246 | if (tipc_link_prepare_input(l_ptr, &buf)) { |
| 1589 | case TIPC_LOW_IMPORTANCE: | ||
| 1590 | case TIPC_MEDIUM_IMPORTANCE: | ||
| 1591 | case TIPC_HIGH_IMPORTANCE: | ||
| 1592 | case TIPC_CRITICAL_IMPORTANCE: | ||
| 1593 | tipc_node_unlock(n_ptr); | 1247 | tipc_node_unlock(n_ptr); |
| 1594 | tipc_sk_rcv(buf); | ||
| 1595 | continue; | 1248 | continue; |
| 1596 | case MSG_BUNDLER: | ||
| 1597 | l_ptr->stats.recv_bundles++; | ||
| 1598 | l_ptr->stats.recv_bundled += msg_msgcnt(msg); | ||
| 1599 | tipc_node_unlock(n_ptr); | ||
| 1600 | tipc_link_bundle_rcv(buf); | ||
| 1601 | continue; | ||
| 1602 | case NAME_DISTRIBUTOR: | ||
| 1603 | n_ptr->bclink.recv_permitted = true; | ||
| 1604 | tipc_node_unlock(n_ptr); | ||
| 1605 | tipc_named_rcv(buf); | ||
| 1606 | continue; | ||
| 1607 | case CONN_MANAGER: | ||
| 1608 | tipc_node_unlock(n_ptr); | ||
| 1609 | tipc_port_proto_rcv(buf); | ||
| 1610 | continue; | ||
| 1611 | case BCAST_PROTOCOL: | ||
| 1612 | tipc_link_sync_rcv(n_ptr, buf); | ||
| 1613 | break; | ||
| 1614 | default: | ||
| 1615 | kfree_skb(buf); | ||
| 1616 | break; | ||
| 1617 | } | 1249 | } |
| 1618 | tipc_node_unlock(n_ptr); | 1250 | tipc_node_unlock(n_ptr); |
| 1251 | msg = buf_msg(buf); | ||
| 1252 | if (tipc_link_input(l_ptr, buf) != 0) | ||
| 1253 | goto discard; | ||
| 1619 | continue; | 1254 | continue; |
| 1620 | unlock_discard: | 1255 | unlock_discard: |
| 1621 | tipc_node_unlock(n_ptr); | 1256 | tipc_node_unlock(n_ptr); |
| @@ -1625,6 +1260,80 @@ discard: | |||
| 1625 | } | 1260 | } |
| 1626 | 1261 | ||
| 1627 | /** | 1262 | /** |
| 1263 | * tipc_link_prepare_input - process TIPC link messages | ||
| 1264 | * | ||
| 1265 | * returns nonzero if the message was consumed | ||
| 1266 | * | ||
| 1267 | * Node lock must be held | ||
| 1268 | */ | ||
| 1269 | static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf) | ||
| 1270 | { | ||
| 1271 | struct tipc_node *n; | ||
| 1272 | struct tipc_msg *msg; | ||
| 1273 | int res = -EINVAL; | ||
| 1274 | |||
| 1275 | n = l->owner; | ||
| 1276 | msg = buf_msg(*buf); | ||
| 1277 | switch (msg_user(msg)) { | ||
| 1278 | case CHANGEOVER_PROTOCOL: | ||
| 1279 | if (tipc_link_tunnel_rcv(n, buf)) | ||
| 1280 | res = 0; | ||
| 1281 | break; | ||
| 1282 | case MSG_FRAGMENTER: | ||
| 1283 | l->stats.recv_fragments++; | ||
| 1284 | if (tipc_buf_append(&l->reasm_buf, buf)) { | ||
| 1285 | l->stats.recv_fragmented++; | ||
| 1286 | res = 0; | ||
| 1287 | } else if (!l->reasm_buf) { | ||
| 1288 | tipc_link_reset(l); | ||
| 1289 | } | ||
| 1290 | break; | ||
| 1291 | case MSG_BUNDLER: | ||
| 1292 | l->stats.recv_bundles++; | ||
| 1293 | l->stats.recv_bundled += msg_msgcnt(msg); | ||
| 1294 | res = 0; | ||
| 1295 | break; | ||
| 1296 | case NAME_DISTRIBUTOR: | ||
| 1297 | n->bclink.recv_permitted = true; | ||
| 1298 | res = 0; | ||
| 1299 | break; | ||
| 1300 | case BCAST_PROTOCOL: | ||
| 1301 | tipc_link_sync_rcv(n, *buf); | ||
| 1302 | break; | ||
| 1303 | default: | ||
| 1304 | res = 0; | ||
| 1305 | } | ||
| 1306 | return res; | ||
| 1307 | } | ||
| 1308 | /** | ||
| 1309 | * tipc_link_input - Deliver message too higher layers | ||
| 1310 | */ | ||
| 1311 | static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf) | ||
| 1312 | { | ||
| 1313 | struct tipc_msg *msg = buf_msg(buf); | ||
| 1314 | int res = 0; | ||
| 1315 | |||
| 1316 | switch (msg_user(msg)) { | ||
| 1317 | case TIPC_LOW_IMPORTANCE: | ||
| 1318 | case TIPC_MEDIUM_IMPORTANCE: | ||
| 1319 | case TIPC_HIGH_IMPORTANCE: | ||
| 1320 | case TIPC_CRITICAL_IMPORTANCE: | ||
| 1321 | case CONN_MANAGER: | ||
| 1322 | tipc_sk_rcv(buf); | ||
| 1323 | break; | ||
| 1324 | case NAME_DISTRIBUTOR: | ||
| 1325 | tipc_named_rcv(buf); | ||
| 1326 | break; | ||
| 1327 | case MSG_BUNDLER: | ||
| 1328 | tipc_link_bundle_rcv(buf); | ||
| 1329 | break; | ||
| 1330 | default: | ||
| 1331 | res = -EINVAL; | ||
| 1332 | } | ||
| 1333 | return res; | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | /** | ||
| 1628 | * tipc_link_defer_pkt - Add out-of-sequence message to deferred reception queue | 1337 | * tipc_link_defer_pkt - Add out-of-sequence message to deferred reception queue |
| 1629 | * | 1338 | * |
| 1630 | * Returns increase in queue length (i.e. 0 or 1) | 1339 | * Returns increase in queue length (i.e. 0 or 1) |
| @@ -2217,6 +1926,7 @@ void tipc_link_bundle_rcv(struct sk_buff *buf) | |||
| 2217 | u32 msgcount = msg_msgcnt(buf_msg(buf)); | 1926 | u32 msgcount = msg_msgcnt(buf_msg(buf)); |
| 2218 | u32 pos = INT_H_SIZE; | 1927 | u32 pos = INT_H_SIZE; |
| 2219 | struct sk_buff *obuf; | 1928 | struct sk_buff *obuf; |
| 1929 | struct tipc_msg *omsg; | ||
| 2220 | 1930 | ||
| 2221 | while (msgcount--) { | 1931 | while (msgcount--) { |
| 2222 | obuf = buf_extract(buf, pos); | 1932 | obuf = buf_extract(buf, pos); |
| @@ -2224,82 +1934,18 @@ void tipc_link_bundle_rcv(struct sk_buff *buf) | |||
| 2224 | pr_warn("Link unable to unbundle message(s)\n"); | 1934 | pr_warn("Link unable to unbundle message(s)\n"); |
| 2225 | break; | 1935 | break; |
| 2226 | } | 1936 | } |
| 2227 | pos += align(msg_size(buf_msg(obuf))); | 1937 | omsg = buf_msg(obuf); |
| 2228 | tipc_net_route_msg(obuf); | 1938 | pos += align(msg_size(omsg)); |
| 2229 | } | 1939 | if (msg_isdata(omsg) || (msg_user(omsg) == CONN_MANAGER)) { |
| 2230 | kfree_skb(buf); | 1940 | tipc_sk_rcv(obuf); |
| 2231 | } | 1941 | } else if (msg_user(omsg) == NAME_DISTRIBUTOR) { |
| 2232 | 1942 | tipc_named_rcv(obuf); | |
| 2233 | /* | 1943 | } else { |
| 2234 | * Fragmentation/defragmentation: | 1944 | pr_warn("Illegal bundled msg: %u\n", msg_user(omsg)); |
| 2235 | */ | 1945 | kfree_skb(obuf); |
| 2236 | |||
| 2237 | /* | ||
| 2238 | * tipc_link_frag_xmit: Entry for buffers needing fragmentation. | ||
| 2239 | * The buffer is complete, inclusive total message length. | ||
| 2240 | * Returns user data length. | ||
| 2241 | */ | ||
| 2242 | static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf) | ||
| 2243 | { | ||
| 2244 | struct sk_buff *buf_chain = NULL; | ||
| 2245 | struct sk_buff *buf_chain_tail = (struct sk_buff *)&buf_chain; | ||
| 2246 | struct tipc_msg *inmsg = buf_msg(buf); | ||
| 2247 | struct tipc_msg fragm_hdr; | ||
| 2248 | u32 insize = msg_size(inmsg); | ||
| 2249 | u32 dsz = msg_data_sz(inmsg); | ||
| 2250 | unchar *crs = buf->data; | ||
| 2251 | u32 rest = insize; | ||
| 2252 | u32 pack_sz = l_ptr->max_pkt; | ||
| 2253 | u32 fragm_sz = pack_sz - INT_H_SIZE; | ||
| 2254 | u32 fragm_no = 0; | ||
| 2255 | u32 destaddr; | ||
| 2256 | |||
| 2257 | if (msg_short(inmsg)) | ||
| 2258 | destaddr = l_ptr->addr; | ||
| 2259 | else | ||
| 2260 | destaddr = msg_destnode(inmsg); | ||
| 2261 | |||
| 2262 | /* Prepare reusable fragment header: */ | ||
| 2263 | tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, | ||
| 2264 | INT_H_SIZE, destaddr); | ||
| 2265 | |||
| 2266 | /* Chop up message: */ | ||
| 2267 | while (rest > 0) { | ||
| 2268 | struct sk_buff *fragm; | ||
| 2269 | |||
| 2270 | if (rest <= fragm_sz) { | ||
| 2271 | fragm_sz = rest; | ||
| 2272 | msg_set_type(&fragm_hdr, LAST_FRAGMENT); | ||
| 2273 | } | ||
| 2274 | fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); | ||
| 2275 | if (fragm == NULL) { | ||
| 2276 | kfree_skb(buf); | ||
| 2277 | kfree_skb_list(buf_chain); | ||
| 2278 | return -ENOMEM; | ||
| 2279 | } | 1946 | } |
| 2280 | msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); | ||
| 2281 | fragm_no++; | ||
| 2282 | msg_set_fragm_no(&fragm_hdr, fragm_no); | ||
| 2283 | skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE); | ||
| 2284 | skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs, | ||
| 2285 | fragm_sz); | ||
| 2286 | buf_chain_tail->next = fragm; | ||
| 2287 | buf_chain_tail = fragm; | ||
| 2288 | |||
| 2289 | rest -= fragm_sz; | ||
| 2290 | crs += fragm_sz; | ||
| 2291 | msg_set_type(&fragm_hdr, FRAGMENT); | ||
| 2292 | } | 1947 | } |
| 2293 | kfree_skb(buf); | 1948 | kfree_skb(buf); |
| 2294 | |||
| 2295 | /* Append chain of fragments to send queue & send them */ | ||
| 2296 | l_ptr->long_msg_seq_no++; | ||
| 2297 | link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no); | ||
| 2298 | l_ptr->stats.sent_fragments += fragm_no; | ||
| 2299 | l_ptr->stats.sent_fragmented++; | ||
| 2300 | tipc_link_push_queue(l_ptr); | ||
| 2301 | |||
| 2302 | return dsz; | ||
| 2303 | } | 1949 | } |
| 2304 | 1950 | ||
| 2305 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) | 1951 | static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) |
diff --git a/net/tipc/link.h b/net/tipc/link.h index 200d518b218e..782983ccd323 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h | |||
| @@ -227,13 +227,8 @@ void tipc_link_reset_all(struct tipc_node *node); | |||
| 227 | void tipc_link_reset(struct tipc_link *l_ptr); | 227 | void tipc_link_reset(struct tipc_link *l_ptr); |
| 228 | void tipc_link_reset_list(unsigned int bearer_id); | 228 | void tipc_link_reset_list(unsigned int bearer_id); |
| 229 | int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); | 229 | int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector); |
| 230 | void tipc_link_names_xmit(struct list_head *message_list, u32 dest); | 230 | int __tipc_link_xmit(struct tipc_link *link, struct sk_buff *buf); |
| 231 | int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf); | ||
| 232 | int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf); | ||
| 233 | u32 tipc_link_get_max_pkt(u32 dest, u32 selector); | 231 | u32 tipc_link_get_max_pkt(u32 dest, u32 selector); |
| 234 | int tipc_link_iovec_xmit_fast(struct tipc_port *sender, | ||
| 235 | struct iovec const *msg_sect, | ||
| 236 | unsigned int len, u32 destnode); | ||
| 237 | void tipc_link_bundle_rcv(struct sk_buff *buf); | 232 | void tipc_link_bundle_rcv(struct sk_buff *buf); |
| 238 | void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, | 233 | void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, |
| 239 | u32 gap, u32 tolerance, u32 priority, u32 acked_mtu); | 234 | u32 gap, u32 tolerance, u32 priority, u32 acked_mtu); |
diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 0a37a472c29f..9680be6d388a 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c | |||
| @@ -36,21 +36,16 @@ | |||
| 36 | 36 | ||
| 37 | #include "core.h" | 37 | #include "core.h" |
| 38 | #include "msg.h" | 38 | #include "msg.h" |
| 39 | #include "addr.h" | ||
| 40 | #include "name_table.h" | ||
| 39 | 41 | ||
| 40 | u32 tipc_msg_tot_importance(struct tipc_msg *m) | 42 | #define MAX_FORWARD_SIZE 1024 |
| 43 | |||
| 44 | static unsigned int align(unsigned int i) | ||
| 41 | { | 45 | { |
| 42 | if (likely(msg_isdata(m))) { | 46 | return (i + 3) & ~3u; |
| 43 | if (likely(msg_orignode(m) == tipc_own_addr)) | ||
| 44 | return msg_importance(m); | ||
| 45 | return msg_importance(m) + 4; | ||
| 46 | } | ||
| 47 | if ((msg_user(m) == MSG_FRAGMENTER) && | ||
| 48 | (msg_type(m) == FIRST_FRAGMENT)) | ||
| 49 | return msg_importance(msg_get_wrapped(m)); | ||
| 50 | return msg_importance(m); | ||
| 51 | } | 47 | } |
| 52 | 48 | ||
| 53 | |||
| 54 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, | 49 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, |
| 55 | u32 destnode) | 50 | u32 destnode) |
| 56 | { | 51 | { |
| @@ -65,41 +60,6 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, | |||
| 65 | msg_set_destnode(m, destnode); | 60 | msg_set_destnode(m, destnode); |
| 66 | } | 61 | } |
| 67 | 62 | ||
| 68 | /** | ||
| 69 | * tipc_msg_build - create message using specified header and data | ||
| 70 | * | ||
| 71 | * Note: Caller must not hold any locks in case copy_from_user() is interrupted! | ||
| 72 | * | ||
| 73 | * Returns message data size or errno | ||
| 74 | */ | ||
| 75 | int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, | ||
| 76 | unsigned int len, int max_size, struct sk_buff **buf) | ||
| 77 | { | ||
| 78 | int dsz, sz, hsz; | ||
| 79 | unsigned char *to; | ||
| 80 | |||
| 81 | dsz = len; | ||
| 82 | hsz = msg_hdr_sz(hdr); | ||
| 83 | sz = hsz + dsz; | ||
| 84 | msg_set_size(hdr, sz); | ||
| 85 | if (unlikely(sz > max_size)) { | ||
| 86 | *buf = NULL; | ||
| 87 | return dsz; | ||
| 88 | } | ||
| 89 | |||
| 90 | *buf = tipc_buf_acquire(sz); | ||
| 91 | if (!(*buf)) | ||
| 92 | return -ENOMEM; | ||
| 93 | skb_copy_to_linear_data(*buf, hdr, hsz); | ||
| 94 | to = (*buf)->data + hsz; | ||
| 95 | if (len && memcpy_fromiovecend(to, msg_sect, 0, dsz)) { | ||
| 96 | kfree_skb(*buf); | ||
| 97 | *buf = NULL; | ||
| 98 | return -EFAULT; | ||
| 99 | } | ||
| 100 | return dsz; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* tipc_buf_append(): Append a buffer to the fragment list of another buffer | 63 | /* tipc_buf_append(): Append a buffer to the fragment list of another buffer |
| 104 | * @*headbuf: in: NULL for first frag, otherwise value returned from prev call | 64 | * @*headbuf: in: NULL for first frag, otherwise value returned from prev call |
| 105 | * out: set when successful non-complete reassembly, otherwise NULL | 65 | * out: set when successful non-complete reassembly, otherwise NULL |
| @@ -112,27 +72,38 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) | |||
| 112 | struct sk_buff *head = *headbuf; | 72 | struct sk_buff *head = *headbuf; |
| 113 | struct sk_buff *frag = *buf; | 73 | struct sk_buff *frag = *buf; |
| 114 | struct sk_buff *tail; | 74 | struct sk_buff *tail; |
| 115 | struct tipc_msg *msg = buf_msg(frag); | 75 | struct tipc_msg *msg; |
| 116 | u32 fragid = msg_type(msg); | 76 | u32 fragid; |
| 117 | bool headstolen; | ||
| 118 | int delta; | 77 | int delta; |
| 78 | bool headstolen; | ||
| 119 | 79 | ||
| 80 | if (!frag) | ||
| 81 | goto err; | ||
| 82 | |||
| 83 | msg = buf_msg(frag); | ||
| 84 | fragid = msg_type(msg); | ||
| 85 | frag->next = NULL; | ||
| 120 | skb_pull(frag, msg_hdr_sz(msg)); | 86 | skb_pull(frag, msg_hdr_sz(msg)); |
| 121 | 87 | ||
| 122 | if (fragid == FIRST_FRAGMENT) { | 88 | if (fragid == FIRST_FRAGMENT) { |
| 123 | if (head || skb_unclone(frag, GFP_ATOMIC)) | 89 | if (unlikely(head)) |
| 124 | goto out_free; | 90 | goto err; |
| 91 | if (unlikely(skb_unclone(frag, GFP_ATOMIC))) | ||
| 92 | goto err; | ||
| 125 | head = *headbuf = frag; | 93 | head = *headbuf = frag; |
| 126 | skb_frag_list_init(head); | 94 | skb_frag_list_init(head); |
| 95 | TIPC_SKB_CB(head)->tail = NULL; | ||
| 127 | *buf = NULL; | 96 | *buf = NULL; |
| 128 | return 0; | 97 | return 0; |
| 129 | } | 98 | } |
| 99 | |||
| 130 | if (!head) | 100 | if (!head) |
| 131 | goto out_free; | 101 | goto err; |
| 132 | tail = TIPC_SKB_CB(head)->tail; | 102 | |
| 133 | if (skb_try_coalesce(head, frag, &headstolen, &delta)) { | 103 | if (skb_try_coalesce(head, frag, &headstolen, &delta)) { |
| 134 | kfree_skb_partial(frag, headstolen); | 104 | kfree_skb_partial(frag, headstolen); |
| 135 | } else { | 105 | } else { |
| 106 | tail = TIPC_SKB_CB(head)->tail; | ||
| 136 | if (!skb_has_frag_list(head)) | 107 | if (!skb_has_frag_list(head)) |
| 137 | skb_shinfo(head)->frag_list = frag; | 108 | skb_shinfo(head)->frag_list = frag; |
| 138 | else | 109 | else |
| @@ -142,6 +113,7 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) | |||
| 142 | head->len += frag->len; | 113 | head->len += frag->len; |
| 143 | TIPC_SKB_CB(head)->tail = frag; | 114 | TIPC_SKB_CB(head)->tail = frag; |
| 144 | } | 115 | } |
| 116 | |||
| 145 | if (fragid == LAST_FRAGMENT) { | 117 | if (fragid == LAST_FRAGMENT) { |
| 146 | *buf = head; | 118 | *buf = head; |
| 147 | TIPC_SKB_CB(head)->tail = NULL; | 119 | TIPC_SKB_CB(head)->tail = NULL; |
| @@ -150,10 +122,311 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) | |||
| 150 | } | 122 | } |
| 151 | *buf = NULL; | 123 | *buf = NULL; |
| 152 | return 0; | 124 | return 0; |
| 153 | out_free: | 125 | |
| 126 | err: | ||
| 154 | pr_warn_ratelimited("Unable to build fragment list\n"); | 127 | pr_warn_ratelimited("Unable to build fragment list\n"); |
| 155 | kfree_skb(*buf); | 128 | kfree_skb(*buf); |
| 156 | kfree_skb(*headbuf); | 129 | kfree_skb(*headbuf); |
| 157 | *buf = *headbuf = NULL; | 130 | *buf = *headbuf = NULL; |
| 158 | return 0; | 131 | return 0; |
| 159 | } | 132 | } |
| 133 | |||
| 134 | |||
| 135 | /** | ||
| 136 | * tipc_msg_build - create buffer chain containing specified header and data | ||
| 137 | * @mhdr: Message header, to be prepended to data | ||
| 138 | * @iov: User data | ||
| 139 | * @offset: Posision in iov to start copying from | ||
| 140 | * @dsz: Total length of user data | ||
| 141 | * @pktmax: Max packet size that can be used | ||
| 142 | * @chain: Buffer or chain of buffers to be returned to caller | ||
| 143 | * Returns message data size or errno: -ENOMEM, -EFAULT | ||
| 144 | */ | ||
| 145 | int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | ||
| 146 | int offset, int dsz, int pktmax , struct sk_buff **chain) | ||
| 147 | { | ||
| 148 | int mhsz = msg_hdr_sz(mhdr); | ||
| 149 | int msz = mhsz + dsz; | ||
| 150 | int pktno = 1; | ||
| 151 | int pktsz; | ||
| 152 | int pktrem = pktmax; | ||
| 153 | int drem = dsz; | ||
| 154 | struct tipc_msg pkthdr; | ||
| 155 | struct sk_buff *buf, *prev; | ||
| 156 | char *pktpos; | ||
| 157 | int rc; | ||
| 158 | |||
| 159 | msg_set_size(mhdr, msz); | ||
| 160 | |||
| 161 | /* No fragmentation needed? */ | ||
| 162 | if (likely(msz <= pktmax)) { | ||
| 163 | buf = tipc_buf_acquire(msz); | ||
| 164 | *chain = buf; | ||
| 165 | if (unlikely(!buf)) | ||
| 166 | return -ENOMEM; | ||
| 167 | skb_copy_to_linear_data(buf, mhdr, mhsz); | ||
| 168 | pktpos = buf->data + mhsz; | ||
| 169 | if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz)) | ||
| 170 | return dsz; | ||
| 171 | rc = -EFAULT; | ||
| 172 | goto error; | ||
| 173 | } | ||
| 174 | |||
| 175 | /* Prepare reusable fragment header */ | ||
| 176 | tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT, | ||
| 177 | INT_H_SIZE, msg_destnode(mhdr)); | ||
| 178 | msg_set_size(&pkthdr, pktmax); | ||
| 179 | msg_set_fragm_no(&pkthdr, pktno); | ||
| 180 | |||
| 181 | /* Prepare first fragment */ | ||
| 182 | *chain = buf = tipc_buf_acquire(pktmax); | ||
| 183 | if (!buf) | ||
| 184 | return -ENOMEM; | ||
| 185 | pktpos = buf->data; | ||
| 186 | skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); | ||
| 187 | pktpos += INT_H_SIZE; | ||
| 188 | pktrem -= INT_H_SIZE; | ||
| 189 | skb_copy_to_linear_data_offset(buf, INT_H_SIZE, mhdr, mhsz); | ||
| 190 | pktpos += mhsz; | ||
| 191 | pktrem -= mhsz; | ||
| 192 | |||
| 193 | do { | ||
| 194 | if (drem < pktrem) | ||
| 195 | pktrem = drem; | ||
| 196 | |||
| 197 | if (memcpy_fromiovecend(pktpos, iov, offset, pktrem)) { | ||
| 198 | rc = -EFAULT; | ||
| 199 | goto error; | ||
| 200 | } | ||
| 201 | drem -= pktrem; | ||
| 202 | offset += pktrem; | ||
| 203 | |||
| 204 | if (!drem) | ||
| 205 | break; | ||
| 206 | |||
| 207 | /* Prepare new fragment: */ | ||
| 208 | if (drem < (pktmax - INT_H_SIZE)) | ||
| 209 | pktsz = drem + INT_H_SIZE; | ||
| 210 | else | ||
| 211 | pktsz = pktmax; | ||
| 212 | prev = buf; | ||
| 213 | buf = tipc_buf_acquire(pktsz); | ||
| 214 | if (!buf) { | ||
| 215 | rc = -ENOMEM; | ||
| 216 | goto error; | ||
| 217 | } | ||
| 218 | prev->next = buf; | ||
| 219 | msg_set_type(&pkthdr, FRAGMENT); | ||
| 220 | msg_set_size(&pkthdr, pktsz); | ||
| 221 | msg_set_fragm_no(&pkthdr, ++pktno); | ||
| 222 | skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); | ||
| 223 | pktpos = buf->data + INT_H_SIZE; | ||
| 224 | pktrem = pktsz - INT_H_SIZE; | ||
| 225 | |||
| 226 | } while (1); | ||
| 227 | |||
| 228 | msg_set_type(buf_msg(buf), LAST_FRAGMENT); | ||
| 229 | return dsz; | ||
| 230 | error: | ||
| 231 | kfree_skb_list(*chain); | ||
| 232 | *chain = NULL; | ||
| 233 | return rc; | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one | ||
| 238 | * @bbuf: the existing buffer ("bundle") | ||
| 239 | * @buf: buffer to be appended | ||
| 240 | * @mtu: max allowable size for the bundle buffer | ||
| 241 | * Consumes buffer if successful | ||
| 242 | * Returns true if bundling could be performed, otherwise false | ||
| 243 | */ | ||
| 244 | bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu) | ||
| 245 | { | ||
| 246 | struct tipc_msg *bmsg = buf_msg(bbuf); | ||
| 247 | struct tipc_msg *msg = buf_msg(buf); | ||
| 248 | unsigned int bsz = msg_size(bmsg); | ||
| 249 | unsigned int msz = msg_size(msg); | ||
| 250 | u32 start = align(bsz); | ||
| 251 | u32 max = mtu - INT_H_SIZE; | ||
| 252 | u32 pad = start - bsz; | ||
| 253 | |||
| 254 | if (likely(msg_user(msg) == MSG_FRAGMENTER)) | ||
| 255 | return false; | ||
| 256 | if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL)) | ||
| 257 | return false; | ||
| 258 | if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) | ||
| 259 | return false; | ||
| 260 | if (likely(msg_user(bmsg) != MSG_BUNDLER)) | ||
| 261 | return false; | ||
| 262 | if (likely(msg_type(bmsg) != BUNDLE_OPEN)) | ||
| 263 | return false; | ||
| 264 | if (unlikely(skb_tailroom(bbuf) < (pad + msz))) | ||
| 265 | return false; | ||
| 266 | if (unlikely(max < (start + msz))) | ||
| 267 | return false; | ||
| 268 | |||
| 269 | skb_put(bbuf, pad + msz); | ||
| 270 | skb_copy_to_linear_data_offset(bbuf, start, buf->data, msz); | ||
| 271 | msg_set_size(bmsg, start + msz); | ||
| 272 | msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1); | ||
| 273 | bbuf->next = buf->next; | ||
| 274 | kfree_skb(buf); | ||
| 275 | return true; | ||
| 276 | } | ||
| 277 | |||
| 278 | /** | ||
| 279 | * tipc_msg_make_bundle(): Create bundle buf and append message to its tail | ||
| 280 | * @buf: buffer to be appended and replaced | ||
| 281 | * @mtu: max allowable size for the bundle buffer, inclusive header | ||
| 282 | * @dnode: destination node for message. (Not always present in header) | ||
| 283 | * Replaces buffer if successful | ||
| 284 | * Returns true if sucess, otherwise false | ||
| 285 | */ | ||
| 286 | bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode) | ||
| 287 | { | ||
| 288 | struct sk_buff *bbuf; | ||
| 289 | struct tipc_msg *bmsg; | ||
| 290 | struct tipc_msg *msg = buf_msg(*buf); | ||
| 291 | u32 msz = msg_size(msg); | ||
| 292 | u32 max = mtu - INT_H_SIZE; | ||
| 293 | |||
| 294 | if (msg_user(msg) == MSG_FRAGMENTER) | ||
| 295 | return false; | ||
| 296 | if (msg_user(msg) == CHANGEOVER_PROTOCOL) | ||
| 297 | return false; | ||
| 298 | if (msg_user(msg) == BCAST_PROTOCOL) | ||
| 299 | return false; | ||
| 300 | if (msz > (max / 2)) | ||
| 301 | return false; | ||
| 302 | |||
| 303 | bbuf = tipc_buf_acquire(max); | ||
| 304 | if (!bbuf) | ||
| 305 | return false; | ||
| 306 | |||
| 307 | skb_trim(bbuf, INT_H_SIZE); | ||
| 308 | bmsg = buf_msg(bbuf); | ||
| 309 | tipc_msg_init(bmsg, MSG_BUNDLER, BUNDLE_OPEN, INT_H_SIZE, dnode); | ||
| 310 | msg_set_seqno(bmsg, msg_seqno(msg)); | ||
| 311 | msg_set_ack(bmsg, msg_ack(msg)); | ||
| 312 | msg_set_bcast_ack(bmsg, msg_bcast_ack(msg)); | ||
| 313 | bbuf->next = (*buf)->next; | ||
| 314 | tipc_msg_bundle(bbuf, *buf, mtu); | ||
| 315 | *buf = bbuf; | ||
| 316 | return true; | ||
| 317 | } | ||
| 318 | |||
| 319 | /** | ||
| 320 | * tipc_msg_reverse(): swap source and destination addresses and add error code | ||
| 321 | * @buf: buffer containing message to be reversed | ||
| 322 | * @dnode: return value: node where to send message after reversal | ||
| 323 | * @err: error code to be set in message | ||
| 324 | * Consumes buffer if failure | ||
| 325 | * Returns true if success, otherwise false | ||
| 326 | */ | ||
| 327 | bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err) | ||
| 328 | { | ||
| 329 | struct tipc_msg *msg = buf_msg(buf); | ||
| 330 | uint imp = msg_importance(msg); | ||
| 331 | struct tipc_msg ohdr; | ||
| 332 | uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE); | ||
| 333 | |||
| 334 | if (skb_linearize(buf)) | ||
| 335 | goto exit; | ||
| 336 | if (msg_dest_droppable(msg)) | ||
| 337 | goto exit; | ||
| 338 | if (msg_errcode(msg)) | ||
| 339 | goto exit; | ||
| 340 | |||
| 341 | memcpy(&ohdr, msg, msg_hdr_sz(msg)); | ||
| 342 | imp = min_t(uint, imp + 1, TIPC_CRITICAL_IMPORTANCE); | ||
| 343 | if (msg_isdata(msg)) | ||
| 344 | msg_set_importance(msg, imp); | ||
| 345 | msg_set_errcode(msg, err); | ||
| 346 | msg_set_origport(msg, msg_destport(&ohdr)); | ||
| 347 | msg_set_destport(msg, msg_origport(&ohdr)); | ||
| 348 | msg_set_prevnode(msg, tipc_own_addr); | ||
| 349 | if (!msg_short(msg)) { | ||
| 350 | msg_set_orignode(msg, msg_destnode(&ohdr)); | ||
| 351 | msg_set_destnode(msg, msg_orignode(&ohdr)); | ||
| 352 | } | ||
| 353 | msg_set_size(msg, msg_hdr_sz(msg) + rdsz); | ||
| 354 | skb_trim(buf, msg_size(msg)); | ||
| 355 | skb_orphan(buf); | ||
| 356 | *dnode = msg_orignode(&ohdr); | ||
| 357 | return true; | ||
| 358 | exit: | ||
| 359 | kfree_skb(buf); | ||
| 360 | return false; | ||
| 361 | } | ||
| 362 | |||
| 363 | /** | ||
| 364 | * tipc_msg_eval: determine fate of message that found no destination | ||
| 365 | * @buf: the buffer containing the message. | ||
| 366 | * @dnode: return value: next-hop node, if message to be forwarded | ||
| 367 | * @err: error code to use, if message to be rejected | ||
| 368 | * | ||
| 369 | * Does not consume buffer | ||
| 370 | * Returns 0 (TIPC_OK) if message ok and we can try again, -TIPC error | ||
| 371 | * code if message to be rejected | ||
| 372 | */ | ||
| 373 | int tipc_msg_eval(struct sk_buff *buf, u32 *dnode) | ||
| 374 | { | ||
| 375 | struct tipc_msg *msg = buf_msg(buf); | ||
| 376 | u32 dport; | ||
| 377 | |||
| 378 | if (msg_type(msg) != TIPC_NAMED_MSG) | ||
| 379 | return -TIPC_ERR_NO_PORT; | ||
| 380 | if (skb_linearize(buf)) | ||
| 381 | return -TIPC_ERR_NO_NAME; | ||
| 382 | if (msg_data_sz(msg) > MAX_FORWARD_SIZE) | ||
| 383 | return -TIPC_ERR_NO_NAME; | ||
| 384 | if (msg_reroute_cnt(msg) > 0) | ||
| 385 | return -TIPC_ERR_NO_NAME; | ||
| 386 | |||
| 387 | *dnode = addr_domain(msg_lookup_scope(msg)); | ||
| 388 | dport = tipc_nametbl_translate(msg_nametype(msg), | ||
| 389 | msg_nameinst(msg), | ||
| 390 | dnode); | ||
| 391 | if (!dport) | ||
| 392 | return -TIPC_ERR_NO_NAME; | ||
| 393 | msg_incr_reroute_cnt(msg); | ||
| 394 | msg_set_destnode(msg, *dnode); | ||
| 395 | msg_set_destport(msg, dport); | ||
| 396 | return TIPC_OK; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* tipc_msg_reassemble() - clone a buffer chain of fragments and | ||
| 400 | * reassemble the clones into one message | ||
| 401 | */ | ||
| 402 | struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain) | ||
| 403 | { | ||
| 404 | struct sk_buff *buf = chain; | ||
| 405 | struct sk_buff *frag = buf; | ||
| 406 | struct sk_buff *head = NULL; | ||
| 407 | int hdr_sz; | ||
| 408 | |||
| 409 | /* Copy header if single buffer */ | ||
| 410 | if (!buf->next) { | ||
| 411 | hdr_sz = skb_headroom(buf) + msg_hdr_sz(buf_msg(buf)); | ||
| 412 | return __pskb_copy(buf, hdr_sz, GFP_ATOMIC); | ||
| 413 | } | ||
| 414 | |||
| 415 | /* Clone all fragments and reassemble */ | ||
| 416 | while (buf) { | ||
| 417 | frag = skb_clone(buf, GFP_ATOMIC); | ||
| 418 | if (!frag) | ||
| 419 | goto error; | ||
| 420 | frag->next = NULL; | ||
| 421 | if (tipc_buf_append(&head, &frag)) | ||
| 422 | break; | ||
| 423 | if (!head) | ||
| 424 | goto error; | ||
| 425 | buf = buf->next; | ||
| 426 | } | ||
| 427 | return frag; | ||
| 428 | error: | ||
| 429 | pr_warn("Failed do clone local mcast rcv buffer\n"); | ||
| 430 | kfree_skb(head); | ||
| 431 | return NULL; | ||
| 432 | } | ||
diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 503511903d1d..462fa194a6af 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h | |||
| @@ -463,6 +463,11 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) | |||
| 463 | #define FRAGMENT 1 | 463 | #define FRAGMENT 1 |
| 464 | #define LAST_FRAGMENT 2 | 464 | #define LAST_FRAGMENT 2 |
| 465 | 465 | ||
| 466 | /* Bundling protocol message types | ||
| 467 | */ | ||
| 468 | #define BUNDLE_OPEN 0 | ||
| 469 | #define BUNDLE_CLOSED 1 | ||
| 470 | |||
| 466 | /* | 471 | /* |
| 467 | * Link management protocol message types | 472 | * Link management protocol message types |
| 468 | */ | 473 | */ |
| @@ -706,12 +711,36 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) | |||
| 706 | msg_set_bits(m, 9, 0, 0xffff, n); | 711 | msg_set_bits(m, 9, 0, 0xffff, n); |
| 707 | } | 712 | } |
| 708 | 713 | ||
| 709 | u32 tipc_msg_tot_importance(struct tipc_msg *m); | 714 | static inline u32 tipc_msg_tot_importance(struct tipc_msg *m) |
| 715 | { | ||
| 716 | if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT)) | ||
| 717 | return msg_importance(msg_get_wrapped(m)); | ||
| 718 | return msg_importance(m); | ||
| 719 | } | ||
| 720 | |||
| 721 | static inline u32 msg_tot_origport(struct tipc_msg *m) | ||
| 722 | { | ||
| 723 | if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT)) | ||
| 724 | return msg_origport(msg_get_wrapped(m)); | ||
| 725 | return msg_origport(m); | ||
| 726 | } | ||
| 727 | |||
| 728 | bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err); | ||
| 729 | |||
| 730 | int tipc_msg_eval(struct sk_buff *buf, u32 *dnode); | ||
| 731 | |||
| 710 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, | 732 | void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize, |
| 711 | u32 destnode); | 733 | u32 destnode); |
| 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); | ||
| 714 | 734 | ||
| 715 | int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf); | 735 | int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf); |
| 716 | 736 | ||
| 737 | bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu); | ||
| 738 | |||
| 739 | bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode); | ||
| 740 | |||
| 741 | int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | ||
| 742 | int offset, int dsz, int mtu , struct sk_buff **chain); | ||
| 743 | |||
| 744 | struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain); | ||
| 745 | |||
| 717 | #endif | 746 | #endif |
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 8ce730984aa1..dcc15bcd5692 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c | |||
| @@ -101,24 +101,22 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest) | |||
| 101 | 101 | ||
| 102 | void named_cluster_distribute(struct sk_buff *buf) | 102 | void named_cluster_distribute(struct sk_buff *buf) |
| 103 | { | 103 | { |
| 104 | struct sk_buff *buf_copy; | 104 | struct sk_buff *obuf; |
| 105 | struct tipc_node *n_ptr; | 105 | struct tipc_node *node; |
| 106 | struct tipc_link *l_ptr; | 106 | u32 dnode; |
| 107 | 107 | ||
| 108 | rcu_read_lock(); | 108 | rcu_read_lock(); |
| 109 | list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { | 109 | list_for_each_entry_rcu(node, &tipc_node_list, list) { |
| 110 | tipc_node_lock(n_ptr); | 110 | dnode = node->addr; |
| 111 | l_ptr = n_ptr->active_links[n_ptr->addr & 1]; | 111 | if (in_own_node(dnode)) |
| 112 | if (l_ptr) { | 112 | continue; |
| 113 | buf_copy = skb_copy(buf, GFP_ATOMIC); | 113 | if (!tipc_node_active_links(node)) |
| 114 | if (!buf_copy) { | 114 | continue; |
| 115 | tipc_node_unlock(n_ptr); | 115 | obuf = skb_copy(buf, GFP_ATOMIC); |
| 116 | break; | 116 | if (!obuf) |
| 117 | } | 117 | break; |
| 118 | msg_set_destnode(buf_msg(buf_copy), n_ptr->addr); | 118 | msg_set_destnode(buf_msg(obuf), dnode); |
| 119 | __tipc_link_xmit(l_ptr, buf_copy); | 119 | tipc_link_xmit(obuf, dnode, dnode); |
| 120 | } | ||
| 121 | tipc_node_unlock(n_ptr); | ||
| 122 | } | 120 | } |
| 123 | rcu_read_unlock(); | 121 | rcu_read_unlock(); |
| 124 | 122 | ||
| @@ -175,34 +173,44 @@ struct sk_buff *tipc_named_withdraw(struct publication *publ) | |||
| 175 | return buf; | 173 | return buf; |
| 176 | } | 174 | } |
| 177 | 175 | ||
| 178 | /* | 176 | /** |
| 179 | * named_distribute - prepare name info for bulk distribution to another node | 177 | * named_distribute - prepare name info for bulk distribution to another node |
| 178 | * @msg_list: list of messages (buffers) to be returned from this function | ||
| 179 | * @dnode: node to be updated | ||
| 180 | * @pls: linked list of publication items to be packed into buffer chain | ||
| 180 | */ | 181 | */ |
| 181 | static void named_distribute(struct list_head *message_list, u32 node, | 182 | static void named_distribute(struct list_head *msg_list, u32 dnode, |
| 182 | struct publ_list *pls, u32 max_item_buf) | 183 | struct publ_list *pls) |
| 183 | { | 184 | { |
| 184 | struct publication *publ; | 185 | struct publication *publ; |
| 185 | struct sk_buff *buf = NULL; | 186 | struct sk_buff *buf = NULL; |
| 186 | struct distr_item *item = NULL; | 187 | struct distr_item *item = NULL; |
| 187 | u32 left = 0; | 188 | uint dsz = pls->size * ITEM_SIZE; |
| 188 | u32 rest = pls->size * ITEM_SIZE; | 189 | uint msg_dsz = (tipc_node_get_mtu(dnode, 0) / ITEM_SIZE) * ITEM_SIZE; |
| 190 | uint rem = dsz; | ||
| 191 | uint msg_rem = 0; | ||
| 189 | 192 | ||
| 190 | list_for_each_entry(publ, &pls->list, local_list) { | 193 | list_for_each_entry(publ, &pls->list, local_list) { |
| 194 | /* Prepare next buffer: */ | ||
| 191 | if (!buf) { | 195 | if (!buf) { |
| 192 | left = (rest <= max_item_buf) ? rest : max_item_buf; | 196 | msg_rem = min_t(uint, rem, msg_dsz); |
| 193 | rest -= left; | 197 | rem -= msg_rem; |
| 194 | buf = named_prepare_buf(PUBLICATION, left, node); | 198 | buf = named_prepare_buf(PUBLICATION, msg_rem, dnode); |
| 195 | if (!buf) { | 199 | if (!buf) { |
| 196 | pr_warn("Bulk publication failure\n"); | 200 | pr_warn("Bulk publication failure\n"); |
| 197 | return; | 201 | return; |
| 198 | } | 202 | } |
| 199 | item = (struct distr_item *)msg_data(buf_msg(buf)); | 203 | item = (struct distr_item *)msg_data(buf_msg(buf)); |
| 200 | } | 204 | } |
| 205 | |||
| 206 | /* Pack publication into message: */ | ||
| 201 | publ_to_item(item, publ); | 207 | publ_to_item(item, publ); |
| 202 | item++; | 208 | item++; |
| 203 | left -= ITEM_SIZE; | 209 | msg_rem -= ITEM_SIZE; |
| 204 | if (!left) { | 210 | |
| 205 | list_add_tail((struct list_head *)buf, message_list); | 211 | /* Append full buffer to list: */ |
| 212 | if (!msg_rem) { | ||
| 213 | list_add_tail((struct list_head *)buf, msg_list); | ||
| 206 | buf = NULL; | 214 | buf = NULL; |
| 207 | } | 215 | } |
| 208 | } | 216 | } |
| @@ -211,16 +219,20 @@ static void named_distribute(struct list_head *message_list, u32 node, | |||
| 211 | /** | 219 | /** |
| 212 | * tipc_named_node_up - tell specified node about all publications by this node | 220 | * tipc_named_node_up - tell specified node about all publications by this node |
| 213 | */ | 221 | */ |
| 214 | void tipc_named_node_up(u32 max_item_buf, u32 node) | 222 | void tipc_named_node_up(u32 dnode) |
| 215 | { | 223 | { |
| 216 | LIST_HEAD(message_list); | 224 | LIST_HEAD(msg_list); |
| 225 | struct sk_buff *buf_chain; | ||
| 217 | 226 | ||
| 218 | read_lock_bh(&tipc_nametbl_lock); | 227 | read_lock_bh(&tipc_nametbl_lock); |
| 219 | named_distribute(&message_list, node, &publ_cluster, max_item_buf); | 228 | named_distribute(&msg_list, dnode, &publ_cluster); |
| 220 | named_distribute(&message_list, node, &publ_zone, max_item_buf); | 229 | named_distribute(&msg_list, dnode, &publ_zone); |
| 221 | read_unlock_bh(&tipc_nametbl_lock); | 230 | read_unlock_bh(&tipc_nametbl_lock); |
| 222 | 231 | ||
| 223 | tipc_link_names_xmit(&message_list, node); | 232 | /* Convert circular list to linear list and send: */ |
| 233 | buf_chain = (struct sk_buff *)msg_list.next; | ||
| 234 | ((struct sk_buff *)msg_list.prev)->next = NULL; | ||
| 235 | tipc_link_xmit(buf_chain, dnode, dnode); | ||
| 224 | } | 236 | } |
| 225 | 237 | ||
| 226 | /** | 238 | /** |
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h index b2eed4ec1526..8afe32b7fc9a 100644 --- a/net/tipc/name_distr.h +++ b/net/tipc/name_distr.h | |||
| @@ -70,7 +70,7 @@ struct distr_item { | |||
| 70 | struct sk_buff *tipc_named_publish(struct publication *publ); | 70 | struct sk_buff *tipc_named_publish(struct publication *publ); |
| 71 | struct sk_buff *tipc_named_withdraw(struct publication *publ); | 71 | struct sk_buff *tipc_named_withdraw(struct publication *publ); |
| 72 | void named_cluster_distribute(struct sk_buff *buf); | 72 | void named_cluster_distribute(struct sk_buff *buf); |
| 73 | void tipc_named_node_up(u32 max_item_buf, u32 node); | 73 | void tipc_named_node_up(u32 dnode); |
| 74 | void tipc_named_rcv(struct sk_buff *buf); | 74 | void tipc_named_rcv(struct sk_buff *buf); |
| 75 | void tipc_named_reinit(void); | 75 | void tipc_named_reinit(void); |
| 76 | 76 | ||
diff --git a/net/tipc/net.c b/net/tipc/net.c index f64375e7f99f..7fcc94998fea 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/net.c: TIPC network routing code | 2 | * net/tipc/net.c: TIPC network routing code |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 1995-2006, Ericsson AB | 4 | * Copyright (c) 1995-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 | * |
| @@ -104,67 +104,6 @@ | |||
| 104 | * - A local spin_lock protecting the queue of subscriber events. | 104 | * - A local spin_lock protecting the queue of subscriber events. |
| 105 | */ | 105 | */ |
| 106 | 106 | ||
| 107 | static void net_route_named_msg(struct sk_buff *buf) | ||
| 108 | { | ||
| 109 | struct tipc_msg *msg = buf_msg(buf); | ||
| 110 | u32 dnode; | ||
| 111 | u32 dport; | ||
| 112 | |||
| 113 | if (!msg_named(msg)) { | ||
| 114 | kfree_skb(buf); | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | |||
| 118 | dnode = addr_domain(msg_lookup_scope(msg)); | ||
| 119 | dport = tipc_nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode); | ||
| 120 | if (dport) { | ||
| 121 | msg_set_destnode(msg, dnode); | ||
| 122 | msg_set_destport(msg, dport); | ||
| 123 | tipc_net_route_msg(buf); | ||
| 124 | return; | ||
| 125 | } | ||
| 126 | tipc_reject_msg(buf, TIPC_ERR_NO_NAME); | ||
| 127 | } | ||
| 128 | |||
| 129 | void tipc_net_route_msg(struct sk_buff *buf) | ||
| 130 | { | ||
| 131 | struct tipc_msg *msg; | ||
| 132 | u32 dnode; | ||
| 133 | |||
| 134 | if (!buf) | ||
| 135 | return; | ||
| 136 | msg = buf_msg(buf); | ||
| 137 | |||
| 138 | /* Handle message for this node */ | ||
| 139 | dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg); | ||
| 140 | if (tipc_in_scope(dnode, tipc_own_addr)) { | ||
| 141 | if (msg_isdata(msg)) { | ||
| 142 | if (msg_mcast(msg)) | ||
| 143 | tipc_port_mcast_rcv(buf, NULL); | ||
| 144 | else if (msg_destport(msg)) | ||
| 145 | tipc_sk_rcv(buf); | ||
| 146 | else | ||
| 147 | net_route_named_msg(buf); | ||
| 148 | return; | ||
| 149 | } | ||
| 150 | switch (msg_user(msg)) { | ||
| 151 | case NAME_DISTRIBUTOR: | ||
| 152 | tipc_named_rcv(buf); | ||
| 153 | break; | ||
| 154 | case CONN_MANAGER: | ||
| 155 | tipc_port_proto_rcv(buf); | ||
| 156 | break; | ||
| 157 | default: | ||
| 158 | kfree_skb(buf); | ||
| 159 | } | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* Handle message for another node */ | ||
| 164 | skb_trim(buf, msg_size(msg)); | ||
| 165 | tipc_link_xmit(buf, dnode, msg_link_selector(msg)); | ||
| 166 | } | ||
| 167 | |||
| 168 | int tipc_net_start(u32 addr) | 107 | int tipc_net_start(u32 addr) |
| 169 | { | 108 | { |
| 170 | char addr_string[16]; | 109 | char addr_string[16]; |
diff --git a/net/tipc/net.h b/net/tipc/net.h index c6c2b46f7c28..59ef3388be2c 100644 --- a/net/tipc/net.h +++ b/net/tipc/net.h | |||
| @@ -37,8 +37,6 @@ | |||
| 37 | #ifndef _TIPC_NET_H | 37 | #ifndef _TIPC_NET_H |
| 38 | #define _TIPC_NET_H | 38 | #define _TIPC_NET_H |
| 39 | 39 | ||
| 40 | void tipc_net_route_msg(struct sk_buff *buf); | ||
| 41 | |||
| 42 | int tipc_net_start(u32 addr); | 40 | int tipc_net_start(u32 addr); |
| 43 | void tipc_net_stop(void); | 41 | void tipc_net_stop(void); |
| 44 | 42 | ||
diff --git a/net/tipc/node.c b/net/tipc/node.c index 5b44c3041be4..f7069299943f 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * net/tipc/node.c: TIPC node management routines | 2 | * net/tipc/node.c: TIPC node management routines |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2000-2006, 2012 Ericsson AB | 4 | * Copyright (c) 2000-2006, 2012-2014, Ericsson AB |
| 5 | * Copyright (c) 2005-2006, 2010-2014, Wind River Systems | 5 | * Copyright (c) 2005-2006, 2010-2014, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -155,21 +155,25 @@ void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | |||
| 155 | if (!active[0]) { | 155 | if (!active[0]) { |
| 156 | active[0] = active[1] = l_ptr; | 156 | active[0] = active[1] = l_ptr; |
| 157 | node_established_contact(n_ptr); | 157 | node_established_contact(n_ptr); |
| 158 | return; | 158 | goto exit; |
| 159 | } | 159 | } |
| 160 | if (l_ptr->priority < active[0]->priority) { | 160 | if (l_ptr->priority < active[0]->priority) { |
| 161 | pr_info("New link <%s> becomes standby\n", l_ptr->name); | 161 | pr_info("New link <%s> becomes standby\n", l_ptr->name); |
| 162 | return; | 162 | goto exit; |
| 163 | } | 163 | } |
| 164 | tipc_link_dup_queue_xmit(active[0], l_ptr); | 164 | tipc_link_dup_queue_xmit(active[0], l_ptr); |
| 165 | if (l_ptr->priority == active[0]->priority) { | 165 | if (l_ptr->priority == active[0]->priority) { |
| 166 | active[0] = l_ptr; | 166 | active[0] = l_ptr; |
| 167 | return; | 167 | goto exit; |
| 168 | } | 168 | } |
| 169 | pr_info("Old link <%s> becomes standby\n", active[0]->name); | 169 | pr_info("Old link <%s> becomes standby\n", active[0]->name); |
| 170 | if (active[1] != active[0]) | 170 | if (active[1] != active[0]) |
| 171 | pr_info("Old link <%s> becomes standby\n", active[1]->name); | 171 | pr_info("Old link <%s> becomes standby\n", active[1]->name); |
| 172 | active[0] = active[1] = l_ptr; | 172 | active[0] = active[1] = l_ptr; |
| 173 | exit: | ||
| 174 | /* Leave room for changeover header when returning 'mtu' to users: */ | ||
| 175 | n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE; | ||
| 176 | n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE; | ||
| 173 | } | 177 | } |
| 174 | 178 | ||
| 175 | /** | 179 | /** |
| @@ -229,6 +233,19 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) | |||
| 229 | tipc_link_failover_send_queue(l_ptr); | 233 | tipc_link_failover_send_queue(l_ptr); |
| 230 | else | 234 | else |
| 231 | node_lost_contact(n_ptr); | 235 | node_lost_contact(n_ptr); |
| 236 | |||
| 237 | /* Leave room for changeover header when returning 'mtu' to users: */ | ||
| 238 | if (active[0]) { | ||
| 239 | n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE; | ||
| 240 | n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE; | ||
| 241 | return; | ||
| 242 | } | ||
| 243 | |||
| 244 | /* Loopback link went down? No fragmentation needed from now on. */ | ||
| 245 | if (n_ptr->addr == tipc_own_addr) { | ||
| 246 | n_ptr->act_mtus[0] = MAX_MSG_SIZE; | ||
| 247 | n_ptr->act_mtus[1] = MAX_MSG_SIZE; | ||
| 248 | } | ||
| 232 | } | 249 | } |
| 233 | 250 | ||
| 234 | int tipc_node_active_links(struct tipc_node *n_ptr) | 251 | int tipc_node_active_links(struct tipc_node *n_ptr) |
| @@ -457,8 +474,6 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len) | |||
| 457 | void tipc_node_unlock(struct tipc_node *node) | 474 | void tipc_node_unlock(struct tipc_node *node) |
| 458 | { | 475 | { |
| 459 | LIST_HEAD(nsub_list); | 476 | LIST_HEAD(nsub_list); |
| 460 | struct tipc_link *link; | ||
| 461 | int pkt_sz = 0; | ||
| 462 | u32 addr = 0; | 477 | u32 addr = 0; |
| 463 | 478 | ||
| 464 | if (likely(!node->action_flags)) { | 479 | if (likely(!node->action_flags)) { |
| @@ -471,18 +486,13 @@ void tipc_node_unlock(struct tipc_node *node) | |||
| 471 | node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; | 486 | node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; |
| 472 | } | 487 | } |
| 473 | if (node->action_flags & TIPC_NOTIFY_NODE_UP) { | 488 | if (node->action_flags & TIPC_NOTIFY_NODE_UP) { |
| 474 | link = node->active_links[0]; | ||
| 475 | node->action_flags &= ~TIPC_NOTIFY_NODE_UP; | 489 | node->action_flags &= ~TIPC_NOTIFY_NODE_UP; |
| 476 | if (link) { | 490 | addr = node->addr; |
| 477 | pkt_sz = ((link->max_pkt - INT_H_SIZE) / ITEM_SIZE) * | ||
| 478 | ITEM_SIZE; | ||
| 479 | addr = node->addr; | ||
| 480 | } | ||
| 481 | } | 491 | } |
| 482 | spin_unlock_bh(&node->lock); | 492 | spin_unlock_bh(&node->lock); |
| 483 | 493 | ||
| 484 | if (!list_empty(&nsub_list)) | 494 | if (!list_empty(&nsub_list)) |
| 485 | tipc_nodesub_notify(&nsub_list); | 495 | tipc_nodesub_notify(&nsub_list); |
| 486 | if (pkt_sz) | 496 | if (addr) |
| 487 | tipc_named_node_up(pkt_sz, addr); | 497 | tipc_named_node_up(addr); |
| 488 | } | 498 | } |
diff --git a/net/tipc/node.h b/net/tipc/node.h index 9087063793f2..b61716a8218e 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include "addr.h" | 41 | #include "addr.h" |
| 42 | #include "net.h" | 42 | #include "net.h" |
| 43 | #include "bearer.h" | 43 | #include "bearer.h" |
| 44 | #include "msg.h" | ||
| 44 | 45 | ||
| 45 | /* | 46 | /* |
| 46 | * Out-of-range value for node signature | 47 | * Out-of-range value for node signature |
| @@ -105,6 +106,7 @@ struct tipc_node { | |||
| 105 | spinlock_t lock; | 106 | spinlock_t lock; |
| 106 | struct hlist_node hash; | 107 | struct hlist_node hash; |
| 107 | struct tipc_link *active_links[2]; | 108 | struct tipc_link *active_links[2]; |
| 109 | u32 act_mtus[2]; | ||
| 108 | struct tipc_link *links[MAX_BEARERS]; | 110 | struct tipc_link *links[MAX_BEARERS]; |
| 109 | unsigned int action_flags; | 111 | unsigned int action_flags; |
| 110 | struct tipc_node_bclink bclink; | 112 | struct tipc_node_bclink bclink; |
| @@ -143,4 +145,19 @@ static inline bool tipc_node_blocked(struct tipc_node *node) | |||
| 143 | TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN)); | 145 | TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN)); |
| 144 | } | 146 | } |
| 145 | 147 | ||
| 148 | static inline uint tipc_node_get_mtu(u32 addr, u32 selector) | ||
| 149 | { | ||
| 150 | struct tipc_node *node; | ||
| 151 | u32 mtu; | ||
| 152 | |||
| 153 | node = tipc_node_find(addr); | ||
| 154 | |||
| 155 | if (likely(node)) | ||
| 156 | mtu = node->act_mtus[selector & 1]; | ||
| 157 | else | ||
| 158 | mtu = MAX_MSG_SIZE; | ||
| 159 | |||
| 160 | return mtu; | ||
| 161 | } | ||
| 162 | |||
| 146 | #endif | 163 | #endif |
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c index 7c59ab1d6ecb..2d13eea8574a 100644 --- a/net/tipc/node_subscr.c +++ b/net/tipc/node_subscr.c | |||
| @@ -84,11 +84,13 @@ void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub) | |||
| 84 | void tipc_nodesub_notify(struct list_head *nsub_list) | 84 | void tipc_nodesub_notify(struct list_head *nsub_list) |
| 85 | { | 85 | { |
| 86 | struct tipc_node_subscr *ns, *safe; | 86 | struct tipc_node_subscr *ns, *safe; |
| 87 | net_ev_handler handle_node_down; | ||
| 87 | 88 | ||
| 88 | list_for_each_entry_safe(ns, safe, nsub_list, nodesub_list) { | 89 | list_for_each_entry_safe(ns, safe, nsub_list, nodesub_list) { |
| 89 | if (ns->handle_node_down) { | 90 | handle_node_down = ns->handle_node_down; |
| 90 | ns->handle_node_down(ns->usr_handle); | 91 | if (handle_node_down) { |
| 91 | ns->handle_node_down = NULL; | 92 | ns->handle_node_down = NULL; |
| 93 | handle_node_down(ns->usr_handle); | ||
| 92 | } | 94 | } |
| 93 | } | 95 | } |
| 94 | } | 96 | } |
diff --git a/net/tipc/port.c b/net/tipc/port.c index 5fd7acce01ea..7e096a5e7701 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c | |||
| @@ -42,8 +42,6 @@ | |||
| 42 | 42 | ||
| 43 | /* Connection management: */ | 43 | /* Connection management: */ |
| 44 | #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ | 44 | #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */ |
| 45 | #define CONFIRMED 0 | ||
| 46 | #define PROBING 1 | ||
| 47 | 45 | ||
| 48 | #define MAX_REJECT_SIZE 1024 | 46 | #define MAX_REJECT_SIZE 1024 |
| 49 | 47 | ||
| @@ -76,124 +74,6 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg) | |||
| 76 | (!peernode && (orignode == tipc_own_addr)); | 74 | (!peernode && (orignode == tipc_own_addr)); |
| 77 | } | 75 | } |
| 78 | 76 | ||
| 79 | /** | ||
| 80 | * tipc_port_mcast_xmit - send a multicast message to local and remote | ||
| 81 | * destinations | ||
| 82 | */ | ||
| 83 | int tipc_port_mcast_xmit(struct tipc_port *oport, | ||
| 84 | struct tipc_name_seq const *seq, | ||
| 85 | struct iovec const *msg_sect, | ||
| 86 | unsigned int len) | ||
| 87 | { | ||
| 88 | struct tipc_msg *hdr; | ||
| 89 | struct sk_buff *buf; | ||
| 90 | struct sk_buff *ibuf = NULL; | ||
| 91 | struct tipc_port_list dports = {0, NULL, }; | ||
| 92 | int ext_targets; | ||
| 93 | int res; | ||
| 94 | |||
| 95 | /* Create multicast message */ | ||
| 96 | hdr = &oport->phdr; | ||
| 97 | msg_set_type(hdr, TIPC_MCAST_MSG); | ||
| 98 | msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE); | ||
| 99 | msg_set_destport(hdr, 0); | ||
| 100 | msg_set_destnode(hdr, 0); | ||
| 101 | msg_set_nametype(hdr, seq->type); | ||
| 102 | msg_set_namelower(hdr, seq->lower); | ||
| 103 | msg_set_nameupper(hdr, seq->upper); | ||
| 104 | msg_set_hdr_sz(hdr, MCAST_H_SIZE); | ||
| 105 | res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); | ||
| 106 | if (unlikely(!buf)) | ||
| 107 | return res; | ||
| 108 | |||
| 109 | /* Figure out where to send multicast message */ | ||
| 110 | ext_targets = tipc_nametbl_mc_translate(seq->type, seq->lower, seq->upper, | ||
| 111 | TIPC_NODE_SCOPE, &dports); | ||
| 112 | |||
| 113 | /* Send message to destinations (duplicate it only if necessary) */ | ||
| 114 | if (ext_targets) { | ||
| 115 | if (dports.count != 0) { | ||
| 116 | ibuf = skb_copy(buf, GFP_ATOMIC); | ||
| 117 | if (ibuf == NULL) { | ||
| 118 | tipc_port_list_free(&dports); | ||
| 119 | kfree_skb(buf); | ||
| 120 | return -ENOMEM; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | res = tipc_bclink_xmit(buf); | ||
| 124 | if ((res < 0) && (dports.count != 0)) | ||
| 125 | kfree_skb(ibuf); | ||
| 126 | } else { | ||
| 127 | ibuf = buf; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (res >= 0) { | ||
| 131 | if (ibuf) | ||
| 132 | tipc_port_mcast_rcv(ibuf, &dports); | ||
| 133 | } else { | ||
| 134 | tipc_port_list_free(&dports); | ||
| 135 | } | ||
| 136 | return res; | ||
| 137 | } | ||
| 138 | |||
| 139 | /** | ||
| 140 | * tipc_port_mcast_rcv - deliver multicast message to all destination ports | ||
| 141 | * | ||
| 142 | * If there is no port list, perform a lookup to create one | ||
| 143 | */ | ||
| 144 | void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp) | ||
| 145 | { | ||
| 146 | struct tipc_msg *msg; | ||
| 147 | struct tipc_port_list dports = {0, NULL, }; | ||
| 148 | struct tipc_port_list *item = dp; | ||
| 149 | int cnt = 0; | ||
| 150 | |||
| 151 | msg = buf_msg(buf); | ||
| 152 | |||
| 153 | /* Create destination port list, if one wasn't supplied */ | ||
| 154 | if (dp == NULL) { | ||
| 155 | tipc_nametbl_mc_translate(msg_nametype(msg), | ||
| 156 | msg_namelower(msg), | ||
| 157 | msg_nameupper(msg), | ||
| 158 | TIPC_CLUSTER_SCOPE, | ||
| 159 | &dports); | ||
| 160 | item = dp = &dports; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* Deliver a copy of message to each destination port */ | ||
| 164 | if (dp->count != 0) { | ||
| 165 | msg_set_destnode(msg, tipc_own_addr); | ||
| 166 | if (dp->count == 1) { | ||
| 167 | msg_set_destport(msg, dp->ports[0]); | ||
| 168 | tipc_sk_rcv(buf); | ||
| 169 | tipc_port_list_free(dp); | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | for (; cnt < dp->count; cnt++) { | ||
| 173 | int index = cnt % PLSIZE; | ||
| 174 | struct sk_buff *b = skb_clone(buf, GFP_ATOMIC); | ||
| 175 | |||
| 176 | if (b == NULL) { | ||
| 177 | pr_warn("Unable to deliver multicast message(s)\n"); | ||
| 178 | goto exit; | ||
| 179 | } | ||
| 180 | if ((index == 0) && (cnt != 0)) | ||
| 181 | item = item->next; | ||
| 182 | msg_set_destport(buf_msg(b), item->ports[index]); | ||
| 183 | tipc_sk_rcv(b); | ||
| 184 | } | ||
| 185 | } | ||
| 186 | exit: | ||
| 187 | kfree_skb(buf); | ||
| 188 | tipc_port_list_free(dp); | ||
| 189 | } | ||
| 190 | |||
| 191 | |||
| 192 | void tipc_port_wakeup(struct tipc_port *port) | ||
| 193 | { | ||
| 194 | tipc_sock_wakeup(tipc_port_to_sock(port)); | ||
| 195 | } | ||
| 196 | |||
| 197 | /* tipc_port_init - intiate TIPC port and lock it | 77 | /* tipc_port_init - intiate TIPC port and lock it |
| 198 | * | 78 | * |
| 199 | * Returns obtained reference if initialization is successful, zero otherwise | 79 | * Returns obtained reference if initialization is successful, zero otherwise |
| @@ -235,6 +115,8 @@ u32 tipc_port_init(struct tipc_port *p_ptr, | |||
| 235 | void tipc_port_destroy(struct tipc_port *p_ptr) | 115 | void tipc_port_destroy(struct tipc_port *p_ptr) |
| 236 | { | 116 | { |
| 237 | struct sk_buff *buf = NULL; | 117 | struct sk_buff *buf = NULL; |
| 118 | struct tipc_msg *msg = NULL; | ||
| 119 | u32 peer; | ||
| 238 | 120 | ||
| 239 | tipc_withdraw(p_ptr, 0, NULL); | 121 | tipc_withdraw(p_ptr, 0, NULL); |
| 240 | 122 | ||
| @@ -246,14 +128,15 @@ void tipc_port_destroy(struct tipc_port *p_ptr) | |||
| 246 | if (p_ptr->connected) { | 128 | if (p_ptr->connected) { |
| 247 | buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); | 129 | buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); |
| 248 | tipc_nodesub_unsubscribe(&p_ptr->subscription); | 130 | tipc_nodesub_unsubscribe(&p_ptr->subscription); |
| 131 | msg = buf_msg(buf); | ||
| 132 | peer = msg_destnode(msg); | ||
| 133 | tipc_link_xmit(buf, peer, msg_link_selector(msg)); | ||
| 249 | } | 134 | } |
| 250 | |||
| 251 | spin_lock_bh(&tipc_port_list_lock); | 135 | spin_lock_bh(&tipc_port_list_lock); |
| 252 | list_del(&p_ptr->port_list); | 136 | list_del(&p_ptr->port_list); |
| 253 | list_del(&p_ptr->wait_list); | 137 | list_del(&p_ptr->wait_list); |
| 254 | spin_unlock_bh(&tipc_port_list_lock); | 138 | spin_unlock_bh(&tipc_port_list_lock); |
| 255 | k_term_timer(&p_ptr->timer); | 139 | k_term_timer(&p_ptr->timer); |
| 256 | tipc_net_route_msg(buf); | ||
| 257 | } | 140 | } |
| 258 | 141 | ||
| 259 | /* | 142 | /* |
| @@ -275,100 +158,16 @@ static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr, | |||
| 275 | msg_set_destport(msg, tipc_port_peerport(p_ptr)); | 158 | msg_set_destport(msg, tipc_port_peerport(p_ptr)); |
| 276 | msg_set_origport(msg, p_ptr->ref); | 159 | msg_set_origport(msg, p_ptr->ref); |
| 277 | msg_set_msgcnt(msg, ack); | 160 | msg_set_msgcnt(msg, ack); |
| 161 | buf->next = NULL; | ||
| 278 | } | 162 | } |
| 279 | return buf; | 163 | return buf; |
| 280 | } | 164 | } |
| 281 | 165 | ||
| 282 | int tipc_reject_msg(struct sk_buff *buf, u32 err) | ||
| 283 | { | ||
| 284 | struct tipc_msg *msg = buf_msg(buf); | ||
| 285 | struct sk_buff *rbuf; | ||
| 286 | struct tipc_msg *rmsg; | ||
| 287 | int hdr_sz; | ||
| 288 | u32 imp; | ||
| 289 | u32 data_sz = msg_data_sz(msg); | ||
| 290 | u32 src_node; | ||
| 291 | u32 rmsg_sz; | ||
| 292 | |||
| 293 | /* discard rejected message if it shouldn't be returned to sender */ | ||
| 294 | if (WARN(!msg_isdata(msg), | ||
| 295 | "attempt to reject message with user=%u", msg_user(msg))) { | ||
| 296 | dump_stack(); | ||
| 297 | goto exit; | ||
| 298 | } | ||
| 299 | if (msg_errcode(msg) || msg_dest_droppable(msg)) | ||
| 300 | goto exit; | ||
| 301 | |||
| 302 | /* | ||
| 303 | * construct returned message by copying rejected message header and | ||
| 304 | * data (or subset), then updating header fields that need adjusting | ||
| 305 | */ | ||
| 306 | hdr_sz = msg_hdr_sz(msg); | ||
| 307 | rmsg_sz = hdr_sz + min_t(u32, data_sz, MAX_REJECT_SIZE); | ||
| 308 | |||
| 309 | rbuf = tipc_buf_acquire(rmsg_sz); | ||
| 310 | if (rbuf == NULL) | ||
| 311 | goto exit; | ||
| 312 | |||
| 313 | rmsg = buf_msg(rbuf); | ||
| 314 | skb_copy_to_linear_data(rbuf, msg, rmsg_sz); | ||
| 315 | |||
| 316 | if (msg_connected(rmsg)) { | ||
| 317 | imp = msg_importance(rmsg); | ||
| 318 | if (imp < TIPC_CRITICAL_IMPORTANCE) | ||
| 319 | msg_set_importance(rmsg, ++imp); | ||
| 320 | } | ||
| 321 | msg_set_non_seq(rmsg, 0); | ||
| 322 | msg_set_size(rmsg, rmsg_sz); | ||
| 323 | msg_set_errcode(rmsg, err); | ||
| 324 | msg_set_prevnode(rmsg, tipc_own_addr); | ||
| 325 | msg_swap_words(rmsg, 4, 5); | ||
| 326 | if (!msg_short(rmsg)) | ||
| 327 | msg_swap_words(rmsg, 6, 7); | ||
| 328 | |||
| 329 | /* send self-abort message when rejecting on a connected port */ | ||
| 330 | if (msg_connected(msg)) { | ||
| 331 | struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg)); | ||
| 332 | |||
| 333 | if (p_ptr) { | ||
| 334 | struct sk_buff *abuf = NULL; | ||
| 335 | |||
| 336 | if (p_ptr->connected) | ||
| 337 | abuf = port_build_self_abort_msg(p_ptr, err); | ||
| 338 | tipc_port_unlock(p_ptr); | ||
| 339 | tipc_net_route_msg(abuf); | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | /* send returned message & dispose of rejected message */ | ||
| 344 | src_node = msg_prevnode(msg); | ||
| 345 | if (in_own_node(src_node)) | ||
| 346 | tipc_sk_rcv(rbuf); | ||
| 347 | else | ||
| 348 | tipc_link_xmit(rbuf, src_node, msg_link_selector(rmsg)); | ||
| 349 | exit: | ||
| 350 | kfree_skb(buf); | ||
| 351 | return data_sz; | ||
| 352 | } | ||
| 353 | |||
| 354 | int tipc_port_iovec_reject(struct tipc_port *p_ptr, struct tipc_msg *hdr, | ||
| 355 | struct iovec const *msg_sect, unsigned int len, | ||
| 356 | int err) | ||
| 357 | { | ||
| 358 | struct sk_buff *buf; | ||
| 359 | int res; | ||
| 360 | |||
| 361 | res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf); | ||
| 362 | if (!buf) | ||
| 363 | return res; | ||
| 364 | |||
| 365 | return tipc_reject_msg(buf, err); | ||
| 366 | } | ||
| 367 | |||
| 368 | static void port_timeout(unsigned long ref) | 166 | static void port_timeout(unsigned long ref) |
| 369 | { | 167 | { |
| 370 | struct tipc_port *p_ptr = tipc_port_lock(ref); | 168 | struct tipc_port *p_ptr = tipc_port_lock(ref); |
| 371 | struct sk_buff *buf = NULL; | 169 | struct sk_buff *buf = NULL; |
| 170 | struct tipc_msg *msg = NULL; | ||
| 372 | 171 | ||
| 373 | if (!p_ptr) | 172 | if (!p_ptr) |
| 374 | return; | 173 | return; |
| @@ -379,15 +178,16 @@ static void port_timeout(unsigned long ref) | |||
| 379 | } | 178 | } |
| 380 | 179 | ||
| 381 | /* Last probe answered ? */ | 180 | /* Last probe answered ? */ |
| 382 | if (p_ptr->probing_state == PROBING) { | 181 | if (p_ptr->probing_state == TIPC_CONN_PROBING) { |
| 383 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT); | 182 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT); |
| 384 | } else { | 183 | } else { |
| 385 | buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0); | 184 | buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0); |
| 386 | p_ptr->probing_state = PROBING; | 185 | p_ptr->probing_state = TIPC_CONN_PROBING; |
| 387 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); | 186 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); |
| 388 | } | 187 | } |
| 389 | tipc_port_unlock(p_ptr); | 188 | tipc_port_unlock(p_ptr); |
| 390 | tipc_net_route_msg(buf); | 189 | msg = buf_msg(buf); |
| 190 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
| 391 | } | 191 | } |
| 392 | 192 | ||
| 393 | 193 | ||
| @@ -395,12 +195,14 @@ static void port_handle_node_down(unsigned long ref) | |||
| 395 | { | 195 | { |
| 396 | struct tipc_port *p_ptr = tipc_port_lock(ref); | 196 | struct tipc_port *p_ptr = tipc_port_lock(ref); |
| 397 | struct sk_buff *buf = NULL; | 197 | struct sk_buff *buf = NULL; |
| 198 | struct tipc_msg *msg = NULL; | ||
| 398 | 199 | ||
| 399 | if (!p_ptr) | 200 | if (!p_ptr) |
| 400 | return; | 201 | return; |
| 401 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE); | 202 | buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE); |
| 402 | tipc_port_unlock(p_ptr); | 203 | tipc_port_unlock(p_ptr); |
| 403 | tipc_net_route_msg(buf); | 204 | msg = buf_msg(buf); |
| 205 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
| 404 | } | 206 | } |
| 405 | 207 | ||
| 406 | 208 | ||
| @@ -412,6 +214,7 @@ static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 er | |||
| 412 | struct tipc_msg *msg = buf_msg(buf); | 214 | struct tipc_msg *msg = buf_msg(buf); |
| 413 | msg_swap_words(msg, 4, 5); | 215 | msg_swap_words(msg, 4, 5); |
| 414 | msg_swap_words(msg, 6, 7); | 216 | msg_swap_words(msg, 6, 7); |
| 217 | buf->next = NULL; | ||
| 415 | } | 218 | } |
| 416 | return buf; | 219 | return buf; |
| 417 | } | 220 | } |
| @@ -436,60 +239,11 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 er | |||
| 436 | if (imp < TIPC_CRITICAL_IMPORTANCE) | 239 | if (imp < TIPC_CRITICAL_IMPORTANCE) |
| 437 | msg_set_importance(msg, ++imp); | 240 | msg_set_importance(msg, ++imp); |
| 438 | msg_set_errcode(msg, err); | 241 | msg_set_errcode(msg, err); |
| 242 | buf->next = NULL; | ||
| 439 | } | 243 | } |
| 440 | return buf; | 244 | return buf; |
| 441 | } | 245 | } |
| 442 | 246 | ||
| 443 | void tipc_port_proto_rcv(struct sk_buff *buf) | ||
| 444 | { | ||
| 445 | struct tipc_msg *msg = buf_msg(buf); | ||
| 446 | struct tipc_port *p_ptr; | ||
| 447 | struct sk_buff *r_buf = NULL; | ||
| 448 | u32 destport = msg_destport(msg); | ||
| 449 | int wakeable; | ||
| 450 | |||
| 451 | /* Validate connection */ | ||
| 452 | p_ptr = tipc_port_lock(destport); | ||
| 453 | if (!p_ptr || !p_ptr->connected || !tipc_port_peer_msg(p_ptr, msg)) { | ||
| 454 | r_buf = tipc_buf_acquire(BASIC_H_SIZE); | ||
| 455 | if (r_buf) { | ||
| 456 | msg = buf_msg(r_buf); | ||
| 457 | tipc_msg_init(msg, TIPC_HIGH_IMPORTANCE, TIPC_CONN_MSG, | ||
| 458 | BASIC_H_SIZE, msg_orignode(msg)); | ||
| 459 | msg_set_errcode(msg, TIPC_ERR_NO_PORT); | ||
| 460 | msg_set_origport(msg, destport); | ||
| 461 | msg_set_destport(msg, msg_origport(msg)); | ||
| 462 | } | ||
| 463 | if (p_ptr) | ||
| 464 | tipc_port_unlock(p_ptr); | ||
| 465 | goto exit; | ||
| 466 | } | ||
| 467 | |||
| 468 | /* Process protocol message sent by peer */ | ||
| 469 | switch (msg_type(msg)) { | ||
| 470 | case CONN_ACK: | ||
| 471 | wakeable = tipc_port_congested(p_ptr) && p_ptr->congested; | ||
| 472 | p_ptr->acked += msg_msgcnt(msg); | ||
| 473 | if (!tipc_port_congested(p_ptr)) { | ||
| 474 | p_ptr->congested = 0; | ||
| 475 | if (wakeable) | ||
| 476 | tipc_port_wakeup(p_ptr); | ||
| 477 | } | ||
| 478 | break; | ||
| 479 | case CONN_PROBE: | ||
| 480 | r_buf = port_build_proto_msg(p_ptr, CONN_PROBE_REPLY, 0); | ||
| 481 | break; | ||
| 482 | default: | ||
| 483 | /* CONN_PROBE_REPLY or unrecognized - no action required */ | ||
| 484 | break; | ||
| 485 | } | ||
| 486 | p_ptr->probing_state = CONFIRMED; | ||
| 487 | tipc_port_unlock(p_ptr); | ||
| 488 | exit: | ||
| 489 | tipc_net_route_msg(r_buf); | ||
| 490 | kfree_skb(buf); | ||
| 491 | } | ||
| 492 | |||
| 493 | static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id) | 247 | static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id) |
| 494 | { | 248 | { |
| 495 | struct publication *publ; | 249 | struct publication *publ; |
| @@ -581,16 +335,19 @@ void tipc_acknowledge(u32 ref, u32 ack) | |||
| 581 | { | 335 | { |
| 582 | struct tipc_port *p_ptr; | 336 | struct tipc_port *p_ptr; |
| 583 | struct sk_buff *buf = NULL; | 337 | struct sk_buff *buf = NULL; |
| 338 | struct tipc_msg *msg; | ||
| 584 | 339 | ||
| 585 | p_ptr = tipc_port_lock(ref); | 340 | p_ptr = tipc_port_lock(ref); |
| 586 | if (!p_ptr) | 341 | if (!p_ptr) |
| 587 | return; | 342 | return; |
| 588 | if (p_ptr->connected) { | 343 | if (p_ptr->connected) |
| 589 | p_ptr->conn_unacked -= ack; | ||
| 590 | buf = port_build_proto_msg(p_ptr, CONN_ACK, ack); | 344 | buf = port_build_proto_msg(p_ptr, CONN_ACK, ack); |
| 591 | } | 345 | |
| 592 | tipc_port_unlock(p_ptr); | 346 | tipc_port_unlock(p_ptr); |
| 593 | tipc_net_route_msg(buf); | 347 | if (!buf) |
| 348 | return; | ||
| 349 | msg = buf_msg(buf); | ||
| 350 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
| 594 | } | 351 | } |
| 595 | 352 | ||
| 596 | int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, | 353 | int tipc_publish(struct tipc_port *p_ptr, unsigned int scope, |
| @@ -689,7 +446,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, | |||
| 689 | msg_set_hdr_sz(msg, SHORT_H_SIZE); | 446 | msg_set_hdr_sz(msg, SHORT_H_SIZE); |
| 690 | 447 | ||
| 691 | p_ptr->probing_interval = PROBING_INTERVAL; | 448 | p_ptr->probing_interval = PROBING_INTERVAL; |
| 692 | p_ptr->probing_state = CONFIRMED; | 449 | p_ptr->probing_state = TIPC_CONN_OK; |
| 693 | p_ptr->connected = 1; | 450 | p_ptr->connected = 1; |
| 694 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); | 451 | k_start_timer(&p_ptr->timer, p_ptr->probing_interval); |
| 695 | 452 | ||
| @@ -698,7 +455,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, | |||
| 698 | (net_ev_handler)port_handle_node_down); | 455 | (net_ev_handler)port_handle_node_down); |
| 699 | res = 0; | 456 | res = 0; |
| 700 | exit: | 457 | exit: |
| 701 | p_ptr->max_pkt = tipc_link_get_max_pkt(peer->node, ref); | 458 | p_ptr->max_pkt = tipc_node_get_mtu(peer->node, ref); |
| 702 | return res; | 459 | return res; |
| 703 | } | 460 | } |
| 704 | 461 | ||
| @@ -741,6 +498,7 @@ int tipc_port_disconnect(u32 ref) | |||
| 741 | */ | 498 | */ |
| 742 | int tipc_port_shutdown(u32 ref) | 499 | int tipc_port_shutdown(u32 ref) |
| 743 | { | 500 | { |
| 501 | struct tipc_msg *msg; | ||
| 744 | struct tipc_port *p_ptr; | 502 | struct tipc_port *p_ptr; |
| 745 | struct sk_buff *buf = NULL; | 503 | struct sk_buff *buf = NULL; |
| 746 | 504 | ||
| @@ -750,149 +508,7 @@ int tipc_port_shutdown(u32 ref) | |||
| 750 | 508 | ||
| 751 | buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN); | 509 | buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN); |
| 752 | tipc_port_unlock(p_ptr); | 510 | tipc_port_unlock(p_ptr); |
| 753 | tipc_net_route_msg(buf); | 511 | msg = buf_msg(buf); |
| 512 | tipc_link_xmit(buf, msg_destnode(msg), msg_link_selector(msg)); | ||
| 754 | return tipc_port_disconnect(ref); | 513 | return tipc_port_disconnect(ref); |
| 755 | } | 514 | } |
| 756 | |||
| 757 | /* | ||
| 758 | * tipc_port_iovec_rcv: Concatenate and deliver sectioned | ||
| 759 | * message for this node. | ||
| 760 | */ | ||
| 761 | static int tipc_port_iovec_rcv(struct tipc_port *sender, | ||
| 762 | struct iovec const *msg_sect, | ||
| 763 | unsigned int len) | ||
| 764 | { | ||
| 765 | struct sk_buff *buf; | ||
| 766 | int res; | ||
| 767 | |||
| 768 | res = tipc_msg_build(&sender->phdr, msg_sect, len, MAX_MSG_SIZE, &buf); | ||
| 769 | if (likely(buf)) | ||
| 770 | tipc_sk_rcv(buf); | ||
| 771 | return res; | ||
| 772 | } | ||
| 773 | |||
| 774 | /** | ||
| 775 | * tipc_send - send message sections on connection | ||
| 776 | */ | ||
| 777 | int tipc_send(struct tipc_port *p_ptr, | ||
| 778 | struct iovec const *msg_sect, | ||
| 779 | unsigned int len) | ||
| 780 | { | ||
| 781 | u32 destnode; | ||
| 782 | int res; | ||
| 783 | |||
| 784 | if (!p_ptr->connected) | ||
| 785 | return -EINVAL; | ||
| 786 | |||
| 787 | p_ptr->congested = 1; | ||
| 788 | if (!tipc_port_congested(p_ptr)) { | ||
| 789 | destnode = tipc_port_peernode(p_ptr); | ||
| 790 | if (likely(!in_own_node(destnode))) | ||
| 791 | res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, | ||
| 792 | destnode); | ||
| 793 | else | ||
| 794 | res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); | ||
| 795 | |||
| 796 | if (likely(res != -ELINKCONG)) { | ||
| 797 | p_ptr->congested = 0; | ||
| 798 | if (res > 0) | ||
| 799 | p_ptr->sent++; | ||
| 800 | return res; | ||
| 801 | } | ||
| 802 | } | ||
| 803 | if (tipc_port_unreliable(p_ptr)) { | ||
| 804 | p_ptr->congested = 0; | ||
| 805 | return len; | ||
| 806 | } | ||
| 807 | return -ELINKCONG; | ||
| 808 | } | ||
| 809 | |||
| 810 | /** | ||
| 811 | * tipc_send2name - send message sections to port name | ||
| 812 | */ | ||
| 813 | int tipc_send2name(struct tipc_port *p_ptr, | ||
| 814 | struct tipc_name const *name, | ||
| 815 | unsigned int domain, | ||
| 816 | struct iovec const *msg_sect, | ||
| 817 | unsigned int len) | ||
| 818 | { | ||
| 819 | struct tipc_msg *msg; | ||
| 820 | u32 destnode = domain; | ||
| 821 | u32 destport; | ||
| 822 | int res; | ||
| 823 | |||
| 824 | if (p_ptr->connected) | ||
| 825 | return -EINVAL; | ||
| 826 | |||
| 827 | msg = &p_ptr->phdr; | ||
| 828 | msg_set_type(msg, TIPC_NAMED_MSG); | ||
| 829 | msg_set_hdr_sz(msg, NAMED_H_SIZE); | ||
| 830 | msg_set_nametype(msg, name->type); | ||
| 831 | msg_set_nameinst(msg, name->instance); | ||
| 832 | msg_set_lookup_scope(msg, tipc_addr_scope(domain)); | ||
| 833 | destport = tipc_nametbl_translate(name->type, name->instance, &destnode); | ||
| 834 | msg_set_destnode(msg, destnode); | ||
| 835 | msg_set_destport(msg, destport); | ||
| 836 | |||
| 837 | if (likely(destport || destnode)) { | ||
| 838 | if (likely(in_own_node(destnode))) | ||
| 839 | res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); | ||
| 840 | else if (tipc_own_addr) | ||
| 841 | res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, | ||
| 842 | destnode); | ||
| 843 | else | ||
| 844 | res = tipc_port_iovec_reject(p_ptr, msg, msg_sect, | ||
| 845 | len, TIPC_ERR_NO_NODE); | ||
| 846 | if (likely(res != -ELINKCONG)) { | ||
| 847 | if (res > 0) | ||
| 848 | p_ptr->sent++; | ||
| 849 | return res; | ||
| 850 | } | ||
| 851 | if (tipc_port_unreliable(p_ptr)) | ||
| 852 | return len; | ||
| 853 | |||
| 854 | return -ELINKCONG; | ||
| 855 | } | ||
| 856 | return tipc_port_iovec_reject(p_ptr, msg, msg_sect, len, | ||
| 857 | TIPC_ERR_NO_NAME); | ||
| 858 | } | ||
| 859 | |||
| 860 | /** | ||
| 861 | * tipc_send2port - send message sections to port identity | ||
| 862 | */ | ||
| 863 | int tipc_send2port(struct tipc_port *p_ptr, | ||
| 864 | struct tipc_portid const *dest, | ||
| 865 | struct iovec const *msg_sect, | ||
| 866 | unsigned int len) | ||
| 867 | { | ||
| 868 | struct tipc_msg *msg; | ||
| 869 | int res; | ||
| 870 | |||
| 871 | if (p_ptr->connected) | ||
| 872 | return -EINVAL; | ||
| 873 | |||
| 874 | msg = &p_ptr->phdr; | ||
| 875 | msg_set_type(msg, TIPC_DIRECT_MSG); | ||
| 876 | msg_set_lookup_scope(msg, 0); | ||
| 877 | msg_set_destnode(msg, dest->node); | ||
| 878 | msg_set_destport(msg, dest->ref); | ||
| 879 | msg_set_hdr_sz(msg, BASIC_H_SIZE); | ||
| 880 | |||
| 881 | if (in_own_node(dest->node)) | ||
| 882 | res = tipc_port_iovec_rcv(p_ptr, msg_sect, len); | ||
| 883 | else if (tipc_own_addr) | ||
| 884 | res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len, | ||
| 885 | dest->node); | ||
| 886 | else | ||
| 887 | res = tipc_port_iovec_reject(p_ptr, msg, msg_sect, len, | ||
| 888 | TIPC_ERR_NO_NODE); | ||
| 889 | if (likely(res != -ELINKCONG)) { | ||
| 890 | if (res > 0) | ||
| 891 | p_ptr->sent++; | ||
| 892 | return res; | ||
| 893 | } | ||
| 894 | if (tipc_port_unreliable(p_ptr)) | ||
| 895 | return len; | ||
| 896 | |||
| 897 | return -ELINKCONG; | ||
| 898 | } | ||
diff --git a/net/tipc/port.h b/net/tipc/port.h index cf4ca5b1d9a4..3087da39ee47 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h | |||
| @@ -53,17 +53,13 @@ | |||
| 53 | * @connected: non-zero if port is currently connected to a peer port | 53 | * @connected: non-zero if port is currently connected to a peer port |
| 54 | * @conn_type: TIPC type used when connection was established | 54 | * @conn_type: TIPC type used when connection was established |
| 55 | * @conn_instance: TIPC instance used when connection was established | 55 | * @conn_instance: TIPC instance used when connection was established |
| 56 | * @conn_unacked: number of unacknowledged messages received from peer port | ||
| 57 | * @published: non-zero if port has one or more associated names | 56 | * @published: non-zero if port has one or more associated names |
| 58 | * @congested: non-zero if cannot send because of link or port congestion | ||
| 59 | * @max_pkt: maximum packet size "hint" used when building messages sent by port | 57 | * @max_pkt: maximum packet size "hint" used when building messages sent by port |
| 60 | * @ref: unique reference to port in TIPC object registry | 58 | * @ref: unique reference to port in TIPC object registry |
| 61 | * @phdr: preformatted message header used when sending messages | 59 | * @phdr: preformatted message header used when sending messages |
| 62 | * @port_list: adjacent ports in TIPC's global list of ports | 60 | * @port_list: adjacent ports in TIPC's global list of ports |
| 63 | * @wait_list: adjacent ports in list of ports waiting on link congestion | 61 | * @wait_list: adjacent ports in list of ports waiting on link congestion |
| 64 | * @waiting_pkts: | 62 | * @waiting_pkts: |
| 65 | * @sent: # of non-empty messages sent by port | ||
| 66 | * @acked: # of non-empty message acknowledgements from connected port's peer | ||
| 67 | * @publications: list of publications for port | 63 | * @publications: list of publications for port |
| 68 | * @pub_count: total # of publications port has made during its lifetime | 64 | * @pub_count: total # of publications port has made during its lifetime |
| 69 | * @probing_state: | 65 | * @probing_state: |
| @@ -76,17 +72,13 @@ struct tipc_port { | |||
| 76 | int connected; | 72 | int connected; |
| 77 | u32 conn_type; | 73 | u32 conn_type; |
| 78 | u32 conn_instance; | 74 | u32 conn_instance; |
| 79 | u32 conn_unacked; | ||
| 80 | int published; | 75 | int published; |
| 81 | u32 congested; | ||
| 82 | u32 max_pkt; | 76 | u32 max_pkt; |
| 83 | u32 ref; | 77 | u32 ref; |
| 84 | struct tipc_msg phdr; | 78 | struct tipc_msg phdr; |
| 85 | struct list_head port_list; | 79 | struct list_head port_list; |
| 86 | struct list_head wait_list; | 80 | struct list_head wait_list; |
| 87 | u32 waiting_pkts; | 81 | u32 waiting_pkts; |
| 88 | u32 sent; | ||
| 89 | u32 acked; | ||
| 90 | struct list_head publications; | 82 | struct list_head publications; |
| 91 | u32 pub_count; | 83 | u32 pub_count; |
| 92 | u32 probing_state; | 84 | u32 probing_state; |
| @@ -104,8 +96,6 @@ struct tipc_port_list; | |||
| 104 | u32 tipc_port_init(struct tipc_port *p_ptr, | 96 | u32 tipc_port_init(struct tipc_port *p_ptr, |
| 105 | const unsigned int importance); | 97 | const unsigned int importance); |
| 106 | 98 | ||
| 107 | int tipc_reject_msg(struct sk_buff *buf, u32 err); | ||
| 108 | |||
| 109 | void tipc_acknowledge(u32 port_ref, u32 ack); | 99 | void tipc_acknowledge(u32 port_ref, u32 ack); |
| 110 | 100 | ||
| 111 | void tipc_port_destroy(struct tipc_port *p_ptr); | 101 | void tipc_port_destroy(struct tipc_port *p_ptr); |
| @@ -122,8 +112,6 @@ int tipc_port_disconnect(u32 portref); | |||
| 122 | 112 | ||
| 123 | int tipc_port_shutdown(u32 ref); | 113 | int tipc_port_shutdown(u32 ref); |
| 124 | 114 | ||
| 125 | void tipc_port_wakeup(struct tipc_port *port); | ||
| 126 | |||
| 127 | /* | 115 | /* |
| 128 | * The following routines require that the port be locked on entry | 116 | * The following routines require that the port be locked on entry |
| 129 | */ | 117 | */ |
| @@ -132,39 +120,7 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr, | |||
| 132 | struct tipc_portid const *peer); | 120 | struct tipc_portid const *peer); |
| 133 | int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg); | 121 | int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg); |
| 134 | 122 | ||
| 135 | /* | ||
| 136 | * TIPC messaging routines | ||
| 137 | */ | ||
| 138 | |||
| 139 | int tipc_send(struct tipc_port *port, | ||
| 140 | struct iovec const *msg_sect, | ||
| 141 | unsigned int len); | ||
| 142 | |||
| 143 | int tipc_send2name(struct tipc_port *port, | ||
| 144 | struct tipc_name const *name, | ||
| 145 | u32 domain, | ||
| 146 | struct iovec const *msg_sect, | ||
| 147 | unsigned int len); | ||
| 148 | |||
| 149 | int tipc_send2port(struct tipc_port *port, | ||
| 150 | struct tipc_portid const *dest, | ||
| 151 | struct iovec const *msg_sect, | ||
| 152 | unsigned int len); | ||
| 153 | |||
| 154 | int tipc_port_mcast_xmit(struct tipc_port *port, | ||
| 155 | struct tipc_name_seq const *seq, | ||
| 156 | struct iovec const *msg, | ||
| 157 | unsigned int len); | ||
| 158 | |||
| 159 | int tipc_port_iovec_reject(struct tipc_port *p_ptr, | ||
| 160 | struct tipc_msg *hdr, | ||
| 161 | struct iovec const *msg_sect, | ||
| 162 | unsigned int len, | ||
| 163 | int err); | ||
| 164 | |||
| 165 | struct sk_buff *tipc_port_get_ports(void); | 123 | struct sk_buff *tipc_port_get_ports(void); |
| 166 | void tipc_port_proto_rcv(struct sk_buff *buf); | ||
| 167 | void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp); | ||
| 168 | void tipc_port_reinit(void); | 124 | void tipc_port_reinit(void); |
| 169 | 125 | ||
| 170 | /** | 126 | /** |
| @@ -185,12 +141,6 @@ static inline void tipc_port_unlock(struct tipc_port *p_ptr) | |||
| 185 | spin_unlock_bh(p_ptr->lock); | 141 | spin_unlock_bh(p_ptr->lock); |
| 186 | } | 142 | } |
| 187 | 143 | ||
| 188 | static inline int tipc_port_congested(struct tipc_port *p_ptr) | ||
| 189 | { | ||
| 190 | return ((p_ptr->sent - p_ptr->acked) >= TIPC_FLOWCTRL_WIN); | ||
| 191 | } | ||
| 192 | |||
| 193 | |||
| 194 | static inline u32 tipc_port_peernode(struct tipc_port *p_ptr) | 144 | static inline u32 tipc_port_peernode(struct tipc_port *p_ptr) |
| 195 | { | 145 | { |
| 196 | return msg_destnode(&p_ptr->phdr); | 146 | return msg_destnode(&p_ptr->phdr); |
| @@ -229,9 +179,12 @@ static inline int tipc_port_importance(struct tipc_port *port) | |||
| 229 | return msg_importance(&port->phdr); | 179 | return msg_importance(&port->phdr); |
| 230 | } | 180 | } |
| 231 | 181 | ||
| 232 | static inline void tipc_port_set_importance(struct tipc_port *port, int imp) | 182 | static inline int tipc_port_set_importance(struct tipc_port *port, int imp) |
| 233 | { | 183 | { |
| 184 | if (imp > TIPC_CRITICAL_IMPORTANCE) | ||
| 185 | return -EINVAL; | ||
| 234 | msg_set_importance(&port->phdr, (u32)imp); | 186 | msg_set_importance(&port->phdr, (u32)imp); |
| 187 | return 0; | ||
| 235 | } | 188 | } |
| 236 | 189 | ||
| 237 | #endif | 190 | #endif |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index ef0475568f9e..ff8c8118d56e 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
| @@ -36,20 +36,23 @@ | |||
| 36 | 36 | ||
| 37 | #include "core.h" | 37 | #include "core.h" |
| 38 | #include "port.h" | 38 | #include "port.h" |
| 39 | #include "name_table.h" | ||
| 39 | #include "node.h" | 40 | #include "node.h" |
| 40 | 41 | #include "link.h" | |
| 41 | #include <linux/export.h> | 42 | #include <linux/export.h> |
| 42 | 43 | ||
| 43 | #define SS_LISTENING -1 /* socket is listening */ | 44 | #define SS_LISTENING -1 /* socket is listening */ |
| 44 | #define SS_READY -2 /* socket is connectionless */ | 45 | #define SS_READY -2 /* socket is connectionless */ |
| 45 | 46 | ||
| 46 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ | 47 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ |
| 48 | #define TIPC_FWD_MSG 1 | ||
| 47 | 49 | ||
| 48 | static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb); | 50 | static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb); |
| 49 | static void tipc_data_ready(struct sock *sk); | 51 | static void tipc_data_ready(struct sock *sk); |
| 50 | static void tipc_write_space(struct sock *sk); | 52 | static void tipc_write_space(struct sock *sk); |
| 51 | static int tipc_release(struct socket *sock); | 53 | static int tipc_release(struct socket *sock); |
| 52 | static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags); | 54 | static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags); |
| 55 | static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p); | ||
| 53 | 56 | ||
| 54 | static const struct proto_ops packet_ops; | 57 | static const struct proto_ops packet_ops; |
| 55 | static const struct proto_ops stream_ops; | 58 | static const struct proto_ops stream_ops; |
| @@ -123,9 +126,12 @@ static void advance_rx_queue(struct sock *sk) | |||
| 123 | static void reject_rx_queue(struct sock *sk) | 126 | static void reject_rx_queue(struct sock *sk) |
| 124 | { | 127 | { |
| 125 | struct sk_buff *buf; | 128 | struct sk_buff *buf; |
| 129 | u32 dnode; | ||
| 126 | 130 | ||
| 127 | while ((buf = __skb_dequeue(&sk->sk_receive_queue))) | 131 | while ((buf = __skb_dequeue(&sk->sk_receive_queue))) { |
| 128 | tipc_reject_msg(buf, TIPC_ERR_NO_PORT); | 132 | if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) |
| 133 | tipc_link_xmit(buf, dnode, 0); | ||
| 134 | } | ||
| 129 | } | 135 | } |
| 130 | 136 | ||
| 131 | /** | 137 | /** |
| @@ -201,6 +207,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock, | |||
| 201 | sk->sk_data_ready = tipc_data_ready; | 207 | sk->sk_data_ready = tipc_data_ready; |
| 202 | sk->sk_write_space = tipc_write_space; | 208 | sk->sk_write_space = tipc_write_space; |
| 203 | tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; | 209 | tsk->conn_timeout = CONN_TIMEOUT_DEFAULT; |
| 210 | tsk->sent_unacked = 0; | ||
| 204 | atomic_set(&tsk->dupl_rcvcnt, 0); | 211 | atomic_set(&tsk->dupl_rcvcnt, 0); |
| 205 | tipc_port_unlock(port); | 212 | tipc_port_unlock(port); |
| 206 | 213 | ||
| @@ -303,6 +310,7 @@ static int tipc_release(struct socket *sock) | |||
| 303 | struct tipc_sock *tsk; | 310 | struct tipc_sock *tsk; |
| 304 | struct tipc_port *port; | 311 | struct tipc_port *port; |
| 305 | struct sk_buff *buf; | 312 | struct sk_buff *buf; |
| 313 | u32 dnode; | ||
| 306 | 314 | ||
| 307 | /* | 315 | /* |
| 308 | * Exit if socket isn't fully initialized (occurs when a failed accept() | 316 | * Exit if socket isn't fully initialized (occurs when a failed accept() |
| @@ -331,7 +339,8 @@ static int tipc_release(struct socket *sock) | |||
| 331 | sock->state = SS_DISCONNECTING; | 339 | sock->state = SS_DISCONNECTING; |
| 332 | tipc_port_disconnect(port->ref); | 340 | tipc_port_disconnect(port->ref); |
| 333 | } | 341 | } |
| 334 | tipc_reject_msg(buf, TIPC_ERR_NO_PORT); | 342 | if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT)) |
| 343 | tipc_link_xmit(buf, dnode, 0); | ||
| 335 | } | 344 | } |
| 336 | } | 345 | } |
| 337 | 346 | ||
| @@ -504,12 +513,12 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, | |||
| 504 | 513 | ||
| 505 | switch ((int)sock->state) { | 514 | switch ((int)sock->state) { |
| 506 | case SS_UNCONNECTED: | 515 | case SS_UNCONNECTED: |
| 507 | if (!tsk->port.congested) | 516 | if (!tsk->link_cong) |
| 508 | mask |= POLLOUT; | 517 | mask |= POLLOUT; |
| 509 | break; | 518 | break; |
| 510 | case SS_READY: | 519 | case SS_READY: |
| 511 | case SS_CONNECTED: | 520 | case SS_CONNECTED: |
| 512 | if (!tsk->port.congested) | 521 | if (!tsk->link_cong && !tipc_sk_conn_cong(tsk)) |
| 513 | mask |= POLLOUT; | 522 | mask |= POLLOUT; |
| 514 | /* fall thru' */ | 523 | /* fall thru' */ |
| 515 | case SS_CONNECTING: | 524 | case SS_CONNECTING: |
| @@ -526,6 +535,136 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, | |||
| 526 | } | 535 | } |
| 527 | 536 | ||
| 528 | /** | 537 | /** |
| 538 | * tipc_sendmcast - send multicast message | ||
| 539 | * @sock: socket structure | ||
| 540 | * @seq: destination address | ||
| 541 | * @iov: message data to send | ||
| 542 | * @dsz: total length of message data | ||
| 543 | * @timeo: timeout to wait for wakeup | ||
| 544 | * | ||
| 545 | * Called from function tipc_sendmsg(), which has done all sanity checks | ||
| 546 | * Returns the number of bytes sent on success, or errno | ||
| 547 | */ | ||
| 548 | static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, | ||
| 549 | struct iovec *iov, size_t dsz, long timeo) | ||
| 550 | { | ||
| 551 | struct sock *sk = sock->sk; | ||
| 552 | struct tipc_msg *mhdr = &tipc_sk(sk)->port.phdr; | ||
| 553 | struct sk_buff *buf; | ||
| 554 | uint mtu; | ||
| 555 | int rc; | ||
| 556 | |||
| 557 | msg_set_type(mhdr, TIPC_MCAST_MSG); | ||
| 558 | msg_set_lookup_scope(mhdr, TIPC_CLUSTER_SCOPE); | ||
| 559 | msg_set_destport(mhdr, 0); | ||
| 560 | msg_set_destnode(mhdr, 0); | ||
| 561 | msg_set_nametype(mhdr, seq->type); | ||
| 562 | msg_set_namelower(mhdr, seq->lower); | ||
| 563 | msg_set_nameupper(mhdr, seq->upper); | ||
| 564 | msg_set_hdr_sz(mhdr, MCAST_H_SIZE); | ||
| 565 | |||
| 566 | new_mtu: | ||
| 567 | mtu = tipc_bclink_get_mtu(); | ||
| 568 | rc = tipc_msg_build(mhdr, iov, 0, dsz, mtu, &buf); | ||
| 569 | if (unlikely(rc < 0)) | ||
| 570 | return rc; | ||
| 571 | |||
| 572 | do { | ||
| 573 | rc = tipc_bclink_xmit(buf); | ||
| 574 | if (likely(rc >= 0)) { | ||
| 575 | rc = dsz; | ||
| 576 | break; | ||
| 577 | } | ||
| 578 | if (rc == -EMSGSIZE) | ||
| 579 | goto new_mtu; | ||
| 580 | if (rc != -ELINKCONG) | ||
| 581 | break; | ||
| 582 | rc = tipc_wait_for_sndmsg(sock, &timeo); | ||
| 583 | if (rc) | ||
| 584 | kfree_skb_list(buf); | ||
| 585 | } while (!rc); | ||
| 586 | return rc; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* tipc_sk_mcast_rcv - Deliver multicast message to all destination sockets | ||
| 590 | */ | ||
| 591 | void tipc_sk_mcast_rcv(struct sk_buff *buf) | ||
| 592 | { | ||
| 593 | struct tipc_msg *msg = buf_msg(buf); | ||
| 594 | struct tipc_port_list dports = {0, NULL, }; | ||
| 595 | struct tipc_port_list *item; | ||
| 596 | struct sk_buff *b; | ||
| 597 | uint i, last, dst = 0; | ||
| 598 | u32 scope = TIPC_CLUSTER_SCOPE; | ||
| 599 | |||
| 600 | if (in_own_node(msg_orignode(msg))) | ||
| 601 | scope = TIPC_NODE_SCOPE; | ||
| 602 | |||
| 603 | /* Create destination port list: */ | ||
| 604 | tipc_nametbl_mc_translate(msg_nametype(msg), | ||
| 605 | msg_namelower(msg), | ||
| 606 | msg_nameupper(msg), | ||
| 607 | scope, | ||
| 608 | &dports); | ||
| 609 | last = dports.count; | ||
| 610 | if (!last) { | ||
| 611 | kfree_skb(buf); | ||
| 612 | return; | ||
| 613 | } | ||
| 614 | |||
| 615 | for (item = &dports; item; item = item->next) { | ||
| 616 | for (i = 0; i < PLSIZE && ++dst <= last; i++) { | ||
| 617 | b = (dst != last) ? skb_clone(buf, GFP_ATOMIC) : buf; | ||
| 618 | if (!b) { | ||
| 619 | pr_warn("Failed do clone mcast rcv buffer\n"); | ||
| 620 | continue; | ||
| 621 | } | ||
| 622 | msg_set_destport(msg, item->ports[i]); | ||
| 623 | tipc_sk_rcv(b); | ||
| 624 | } | ||
| 625 | } | ||
| 626 | tipc_port_list_free(&dports); | ||
| 627 | } | ||
| 628 | |||
| 629 | /** | ||
| 630 | * tipc_sk_proto_rcv - receive a connection mng protocol message | ||
| 631 | * @tsk: receiving socket | ||
| 632 | * @dnode: node to send response message to, if any | ||
| 633 | * @buf: buffer containing protocol message | ||
| 634 | * Returns 0 (TIPC_OK) if message was consumed, 1 (TIPC_FWD_MSG) if | ||
| 635 | * (CONN_PROBE_REPLY) message should be forwarded. | ||
| 636 | */ | ||
| 637 | static int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode, | ||
| 638 | struct sk_buff *buf) | ||
| 639 | { | ||
| 640 | struct tipc_msg *msg = buf_msg(buf); | ||
| 641 | struct tipc_port *port = &tsk->port; | ||
| 642 | int conn_cong; | ||
| 643 | |||
| 644 | /* Ignore if connection cannot be validated: */ | ||
| 645 | if (!port->connected || !tipc_port_peer_msg(port, msg)) | ||
| 646 | goto exit; | ||
| 647 | |||
| 648 | port->probing_state = TIPC_CONN_OK; | ||
| 649 | |||
| 650 | if (msg_type(msg) == CONN_ACK) { | ||
| 651 | conn_cong = tipc_sk_conn_cong(tsk); | ||
| 652 | tsk->sent_unacked -= msg_msgcnt(msg); | ||
| 653 | if (conn_cong) | ||
| 654 | tipc_sock_wakeup(tsk); | ||
| 655 | } else if (msg_type(msg) == CONN_PROBE) { | ||
| 656 | if (!tipc_msg_reverse(buf, dnode, TIPC_OK)) | ||
| 657 | return TIPC_OK; | ||
| 658 | msg_set_type(msg, CONN_PROBE_REPLY); | ||
| 659 | return TIPC_FWD_MSG; | ||
| 660 | } | ||
| 661 | /* Do nothing if msg_type() == CONN_PROBE_REPLY */ | ||
| 662 | exit: | ||
| 663 | kfree_skb(buf); | ||
| 664 | return TIPC_OK; | ||
| 665 | } | ||
| 666 | |||
| 667 | /** | ||
| 529 | * dest_name_check - verify user is permitted to send to specified port name | 668 | * dest_name_check - verify user is permitted to send to specified port name |
| 530 | * @dest: destination address | 669 | * @dest: destination address |
| 531 | * @m: descriptor for message to be sent | 670 | * @m: descriptor for message to be sent |
| @@ -539,6 +678,8 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) | |||
| 539 | { | 678 | { |
| 540 | struct tipc_cfg_msg_hdr hdr; | 679 | struct tipc_cfg_msg_hdr hdr; |
| 541 | 680 | ||
| 681 | if (unlikely(dest->addrtype == TIPC_ADDR_ID)) | ||
| 682 | return 0; | ||
| 542 | if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES)) | 683 | if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES)) |
| 543 | return 0; | 684 | return 0; |
| 544 | if (likely(dest->addr.name.name.type == TIPC_TOP_SRV)) | 685 | if (likely(dest->addr.name.name.type == TIPC_TOP_SRV)) |
| @@ -575,19 +716,18 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) | |||
| 575 | return sock_intr_errno(*timeo_p); | 716 | return sock_intr_errno(*timeo_p); |
| 576 | 717 | ||
| 577 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 718 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
| 578 | done = sk_wait_event(sk, timeo_p, !tsk->port.congested); | 719 | done = sk_wait_event(sk, timeo_p, !tsk->link_cong); |
| 579 | finish_wait(sk_sleep(sk), &wait); | 720 | finish_wait(sk_sleep(sk), &wait); |
| 580 | } while (!done); | 721 | } while (!done); |
| 581 | return 0; | 722 | return 0; |
| 582 | } | 723 | } |
| 583 | 724 | ||
| 584 | |||
| 585 | /** | 725 | /** |
| 586 | * tipc_sendmsg - send message in connectionless manner | 726 | * tipc_sendmsg - send message in connectionless manner |
| 587 | * @iocb: if NULL, indicates that socket lock is already held | 727 | * @iocb: if NULL, indicates that socket lock is already held |
| 588 | * @sock: socket structure | 728 | * @sock: socket structure |
| 589 | * @m: message to send | 729 | * @m: message to send |
| 590 | * @total_len: length of message | 730 | * @dsz: amount of user data to be sent |
| 591 | * | 731 | * |
| 592 | * Message must have an destination specified explicitly. | 732 | * Message must have an destination specified explicitly. |
| 593 | * Used for SOCK_RDM and SOCK_DGRAM messages, | 733 | * Used for SOCK_RDM and SOCK_DGRAM messages, |
| @@ -597,100 +737,123 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) | |||
| 597 | * Returns the number of bytes sent on success, or errno otherwise | 737 | * Returns the number of bytes sent on success, or errno otherwise |
| 598 | */ | 738 | */ |
| 599 | static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, | 739 | static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock, |
| 600 | struct msghdr *m, size_t total_len) | 740 | struct msghdr *m, size_t dsz) |
| 601 | { | 741 | { |
| 742 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); | ||
| 602 | struct sock *sk = sock->sk; | 743 | struct sock *sk = sock->sk; |
| 603 | struct tipc_sock *tsk = tipc_sk(sk); | 744 | struct tipc_sock *tsk = tipc_sk(sk); |
| 604 | struct tipc_port *port = &tsk->port; | 745 | struct tipc_port *port = &tsk->port; |
| 605 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); | 746 | struct tipc_msg *mhdr = &port->phdr; |
| 606 | int needs_conn; | 747 | struct iovec *iov = m->msg_iov; |
| 748 | u32 dnode, dport; | ||
| 749 | struct sk_buff *buf; | ||
| 750 | struct tipc_name_seq *seq = &dest->addr.nameseq; | ||
| 751 | u32 mtu; | ||
| 607 | long timeo; | 752 | long timeo; |
| 608 | int res = -EINVAL; | 753 | int rc = -EINVAL; |
| 609 | 754 | ||
| 610 | if (unlikely(!dest)) | 755 | if (unlikely(!dest)) |
| 611 | return -EDESTADDRREQ; | 756 | return -EDESTADDRREQ; |
| 757 | |||
| 612 | if (unlikely((m->msg_namelen < sizeof(*dest)) || | 758 | if (unlikely((m->msg_namelen < sizeof(*dest)) || |
| 613 | (dest->family != AF_TIPC))) | 759 | (dest->family != AF_TIPC))) |
| 614 | return -EINVAL; | 760 | return -EINVAL; |
| 615 | if (total_len > TIPC_MAX_USER_MSG_SIZE) | 761 | |
| 762 | if (dsz > TIPC_MAX_USER_MSG_SIZE) | ||
| 616 | return -EMSGSIZE; | 763 | return -EMSGSIZE; |
| 617 | 764 | ||
| 618 | if (iocb) | 765 | if (iocb) |
| 619 | lock_sock(sk); | 766 | lock_sock(sk); |
| 620 | 767 | ||
| 621 | needs_conn = (sock->state != SS_READY); | 768 | if (unlikely(sock->state != SS_READY)) { |
| 622 | if (unlikely(needs_conn)) { | ||
| 623 | if (sock->state == SS_LISTENING) { | 769 | if (sock->state == SS_LISTENING) { |
| 624 | res = -EPIPE; | 770 | rc = -EPIPE; |
| 625 | goto exit; | 771 | goto exit; |
| 626 | } | 772 | } |
| 627 | if (sock->state != SS_UNCONNECTED) { | 773 | if (sock->state != SS_UNCONNECTED) { |
| 628 | res = -EISCONN; | 774 | rc = -EISCONN; |
| 629 | goto exit; | 775 | goto exit; |
| 630 | } | 776 | } |
| 631 | if (tsk->port.published) { | 777 | if (tsk->port.published) { |
| 632 | res = -EOPNOTSUPP; | 778 | rc = -EOPNOTSUPP; |
| 633 | goto exit; | 779 | goto exit; |
| 634 | } | 780 | } |
| 635 | if (dest->addrtype == TIPC_ADDR_NAME) { | 781 | if (dest->addrtype == TIPC_ADDR_NAME) { |
| 636 | tsk->port.conn_type = dest->addr.name.name.type; | 782 | tsk->port.conn_type = dest->addr.name.name.type; |
| 637 | tsk->port.conn_instance = dest->addr.name.name.instance; | 783 | tsk->port.conn_instance = dest->addr.name.name.instance; |
| 638 | } | 784 | } |
| 639 | |||
| 640 | /* Abort any pending connection attempts (very unlikely) */ | ||
| 641 | reject_rx_queue(sk); | ||
| 642 | } | 785 | } |
| 786 | rc = dest_name_check(dest, m); | ||
| 787 | if (rc) | ||
| 788 | goto exit; | ||
| 643 | 789 | ||
| 644 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 790 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
| 645 | do { | 791 | |
| 646 | if (dest->addrtype == TIPC_ADDR_NAME) { | 792 | if (dest->addrtype == TIPC_ADDR_MCAST) { |
| 647 | res = dest_name_check(dest, m); | 793 | rc = tipc_sendmcast(sock, seq, iov, dsz, timeo); |
| 648 | if (res) | 794 | goto exit; |
| 649 | break; | 795 | } else if (dest->addrtype == TIPC_ADDR_NAME) { |
| 650 | res = tipc_send2name(port, | 796 | u32 type = dest->addr.name.name.type; |
| 651 | &dest->addr.name.name, | 797 | u32 inst = dest->addr.name.name.instance; |
| 652 | dest->addr.name.domain, | 798 | u32 domain = dest->addr.name.domain; |
| 653 | m->msg_iov, | 799 | |
| 654 | total_len); | 800 | dnode = domain; |
| 655 | } else if (dest->addrtype == TIPC_ADDR_ID) { | 801 | msg_set_type(mhdr, TIPC_NAMED_MSG); |
| 656 | res = tipc_send2port(port, | 802 | msg_set_hdr_sz(mhdr, NAMED_H_SIZE); |
| 657 | &dest->addr.id, | 803 | msg_set_nametype(mhdr, type); |
| 658 | m->msg_iov, | 804 | msg_set_nameinst(mhdr, inst); |
| 659 | total_len); | 805 | msg_set_lookup_scope(mhdr, tipc_addr_scope(domain)); |
| 660 | } else if (dest->addrtype == TIPC_ADDR_MCAST) { | 806 | dport = tipc_nametbl_translate(type, inst, &dnode); |
| 661 | if (needs_conn) { | 807 | msg_set_destnode(mhdr, dnode); |
| 662 | res = -EOPNOTSUPP; | 808 | msg_set_destport(mhdr, dport); |
| 663 | break; | 809 | if (unlikely(!dport && !dnode)) { |
| 664 | } | 810 | rc = -EHOSTUNREACH; |
| 665 | res = dest_name_check(dest, m); | 811 | goto exit; |
| 666 | if (res) | ||
| 667 | break; | ||
| 668 | res = tipc_port_mcast_xmit(port, | ||
| 669 | &dest->addr.nameseq, | ||
| 670 | m->msg_iov, | ||
| 671 | total_len); | ||
| 672 | } | 812 | } |
| 673 | if (likely(res != -ELINKCONG)) { | 813 | } else if (dest->addrtype == TIPC_ADDR_ID) { |
| 674 | if (needs_conn && (res >= 0)) | 814 | dnode = dest->addr.id.node; |
| 815 | msg_set_type(mhdr, TIPC_DIRECT_MSG); | ||
| 816 | msg_set_lookup_scope(mhdr, 0); | ||
| 817 | msg_set_destnode(mhdr, dnode); | ||
| 818 | msg_set_destport(mhdr, dest->addr.id.ref); | ||
| 819 | msg_set_hdr_sz(mhdr, BASIC_H_SIZE); | ||
| 820 | } | ||
| 821 | |||
| 822 | new_mtu: | ||
| 823 | mtu = tipc_node_get_mtu(dnode, tsk->port.ref); | ||
| 824 | rc = tipc_msg_build(mhdr, iov, 0, dsz, mtu, &buf); | ||
| 825 | if (rc < 0) | ||
| 826 | goto exit; | ||
| 827 | |||
| 828 | do { | ||
| 829 | rc = tipc_link_xmit(buf, dnode, tsk->port.ref); | ||
| 830 | if (likely(rc >= 0)) { | ||
| 831 | if (sock->state != SS_READY) | ||
| 675 | sock->state = SS_CONNECTING; | 832 | sock->state = SS_CONNECTING; |
| 833 | rc = dsz; | ||
| 676 | break; | 834 | break; |
| 677 | } | 835 | } |
| 678 | res = tipc_wait_for_sndmsg(sock, &timeo); | 836 | if (rc == -EMSGSIZE) |
| 679 | if (res) | 837 | goto new_mtu; |
| 838 | |||
| 839 | if (rc != -ELINKCONG) | ||
| 680 | break; | 840 | break; |
| 681 | } while (1); | ||
| 682 | 841 | ||
| 842 | rc = tipc_wait_for_sndmsg(sock, &timeo); | ||
| 843 | if (rc) | ||
| 844 | kfree_skb_list(buf); | ||
| 845 | } while (!rc); | ||
| 683 | exit: | 846 | exit: |
| 684 | if (iocb) | 847 | if (iocb) |
| 685 | release_sock(sk); | 848 | release_sock(sk); |
| 686 | return res; | 849 | |
| 850 | return rc; | ||
| 687 | } | 851 | } |
| 688 | 852 | ||
| 689 | static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) | 853 | static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) |
| 690 | { | 854 | { |
| 691 | struct sock *sk = sock->sk; | 855 | struct sock *sk = sock->sk; |
| 692 | struct tipc_sock *tsk = tipc_sk(sk); | 856 | struct tipc_sock *tsk = tipc_sk(sk); |
| 693 | struct tipc_port *port = &tsk->port; | ||
| 694 | DEFINE_WAIT(wait); | 857 | DEFINE_WAIT(wait); |
| 695 | int done; | 858 | int done; |
| 696 | 859 | ||
| @@ -709,37 +872,49 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p) | |||
| 709 | 872 | ||
| 710 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 873 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
| 711 | done = sk_wait_event(sk, timeo_p, | 874 | done = sk_wait_event(sk, timeo_p, |
| 712 | (!port->congested || !port->connected)); | 875 | (!tsk->link_cong && |
| 876 | !tipc_sk_conn_cong(tsk)) || | ||
| 877 | !tsk->port.connected); | ||
| 713 | finish_wait(sk_sleep(sk), &wait); | 878 | finish_wait(sk_sleep(sk), &wait); |
| 714 | } while (!done); | 879 | } while (!done); |
| 715 | return 0; | 880 | return 0; |
| 716 | } | 881 | } |
| 717 | 882 | ||
| 718 | /** | 883 | /** |
| 719 | * tipc_send_packet - send a connection-oriented message | 884 | * tipc_send_stream - send stream-oriented data |
| 720 | * @iocb: if NULL, indicates that socket lock is already held | 885 | * @iocb: (unused) |
| 721 | * @sock: socket structure | 886 | * @sock: socket structure |
| 722 | * @m: message to send | 887 | * @m: data to send |
| 723 | * @total_len: length of message | 888 | * @dsz: total length of data to be transmitted |
| 724 | * | 889 | * |
| 725 | * Used for SOCK_SEQPACKET messages and SOCK_STREAM data. | 890 | * Used for SOCK_STREAM data. |
| 726 | * | 891 | * |
| 727 | * Returns the number of bytes sent on success, or errno otherwise | 892 | * Returns the number of bytes sent on success (or partial success), |
| 893 | * or errno if no data sent | ||
| 728 | */ | 894 | */ |
| 729 | static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, | 895 | static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, |
| 730 | struct msghdr *m, size_t total_len) | 896 | struct msghdr *m, size_t dsz) |
| 731 | { | 897 | { |
| 732 | struct sock *sk = sock->sk; | 898 | struct sock *sk = sock->sk; |
| 733 | struct tipc_sock *tsk = tipc_sk(sk); | 899 | struct tipc_sock *tsk = tipc_sk(sk); |
| 900 | struct tipc_port *port = &tsk->port; | ||
| 901 | struct tipc_msg *mhdr = &port->phdr; | ||
| 902 | struct sk_buff *buf; | ||
| 734 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); | 903 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); |
| 735 | int res = -EINVAL; | 904 | u32 ref = port->ref; |
| 905 | int rc = -EINVAL; | ||
| 736 | long timeo; | 906 | long timeo; |
| 907 | u32 dnode; | ||
| 908 | uint mtu, send, sent = 0; | ||
| 737 | 909 | ||
| 738 | /* Handle implied connection establishment */ | 910 | /* Handle implied connection establishment */ |
| 739 | if (unlikely(dest)) | 911 | if (unlikely(dest)) { |
| 740 | return tipc_sendmsg(iocb, sock, m, total_len); | 912 | rc = tipc_sendmsg(iocb, sock, m, dsz); |
| 741 | 913 | if (dsz && (dsz == rc)) | |
| 742 | if (total_len > TIPC_MAX_USER_MSG_SIZE) | 914 | tsk->sent_unacked = 1; |
| 915 | return rc; | ||
| 916 | } | ||
| 917 | if (dsz > (uint)INT_MAX) | ||
| 743 | return -EMSGSIZE; | 918 | return -EMSGSIZE; |
| 744 | 919 | ||
| 745 | if (iocb) | 920 | if (iocb) |
| @@ -747,123 +922,66 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, | |||
| 747 | 922 | ||
| 748 | if (unlikely(sock->state != SS_CONNECTED)) { | 923 | if (unlikely(sock->state != SS_CONNECTED)) { |
| 749 | if (sock->state == SS_DISCONNECTING) | 924 | if (sock->state == SS_DISCONNECTING) |
| 750 | res = -EPIPE; | 925 | rc = -EPIPE; |
| 751 | else | 926 | else |
| 752 | res = -ENOTCONN; | 927 | rc = -ENOTCONN; |
| 753 | goto exit; | 928 | goto exit; |
| 754 | } | 929 | } |
| 755 | 930 | ||
| 756 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 931 | timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
| 932 | dnode = tipc_port_peernode(port); | ||
| 933 | |||
| 934 | next: | ||
| 935 | mtu = port->max_pkt; | ||
| 936 | send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE); | ||
| 937 | rc = tipc_msg_build(mhdr, m->msg_iov, sent, send, mtu, &buf); | ||
| 938 | if (unlikely(rc < 0)) | ||
| 939 | goto exit; | ||
| 757 | do { | 940 | do { |
| 758 | res = tipc_send(&tsk->port, m->msg_iov, total_len); | 941 | if (likely(!tipc_sk_conn_cong(tsk))) { |
| 759 | if (likely(res != -ELINKCONG)) | 942 | rc = tipc_link_xmit(buf, dnode, ref); |
| 760 | break; | 943 | if (likely(!rc)) { |
| 761 | res = tipc_wait_for_sndpkt(sock, &timeo); | 944 | tsk->sent_unacked++; |
| 762 | if (res) | 945 | sent += send; |
| 763 | break; | 946 | if (sent == dsz) |
| 764 | } while (1); | 947 | break; |
| 948 | goto next; | ||
| 949 | } | ||
| 950 | if (rc == -EMSGSIZE) { | ||
| 951 | port->max_pkt = tipc_node_get_mtu(dnode, ref); | ||
| 952 | goto next; | ||
| 953 | } | ||
| 954 | if (rc != -ELINKCONG) | ||
| 955 | break; | ||
| 956 | } | ||
| 957 | rc = tipc_wait_for_sndpkt(sock, &timeo); | ||
| 958 | if (rc) | ||
| 959 | kfree_skb_list(buf); | ||
| 960 | } while (!rc); | ||
| 765 | exit: | 961 | exit: |
| 766 | if (iocb) | 962 | if (iocb) |
| 767 | release_sock(sk); | 963 | release_sock(sk); |
| 768 | return res; | 964 | return sent ? sent : rc; |
| 769 | } | 965 | } |
| 770 | 966 | ||
| 771 | /** | 967 | /** |
| 772 | * tipc_send_stream - send stream-oriented data | 968 | * tipc_send_packet - send a connection-oriented message |
| 773 | * @iocb: (unused) | 969 | * @iocb: if NULL, indicates that socket lock is already held |
| 774 | * @sock: socket structure | 970 | * @sock: socket structure |
| 775 | * @m: data to send | 971 | * @m: message to send |
| 776 | * @total_len: total length of data to be sent | 972 | * @dsz: length of data to be transmitted |
| 777 | * | 973 | * |
| 778 | * Used for SOCK_STREAM data. | 974 | * Used for SOCK_SEQPACKET messages. |
| 779 | * | 975 | * |
| 780 | * Returns the number of bytes sent on success (or partial success), | 976 | * Returns the number of bytes sent on success, or errno otherwise |
| 781 | * or errno if no data sent | ||
| 782 | */ | 977 | */ |
| 783 | static int tipc_send_stream(struct kiocb *iocb, struct socket *sock, | 978 | static int tipc_send_packet(struct kiocb *iocb, struct socket *sock, |
| 784 | struct msghdr *m, size_t total_len) | 979 | struct msghdr *m, size_t dsz) |
| 785 | { | 980 | { |
| 786 | struct sock *sk = sock->sk; | 981 | if (dsz > TIPC_MAX_USER_MSG_SIZE) |
| 787 | struct tipc_sock *tsk = tipc_sk(sk); | 982 | return -EMSGSIZE; |
| 788 | struct msghdr my_msg; | ||
| 789 | struct iovec my_iov; | ||
| 790 | struct iovec *curr_iov; | ||
| 791 | int curr_iovlen; | ||
| 792 | char __user *curr_start; | ||
| 793 | u32 hdr_size; | ||
| 794 | int curr_left; | ||
| 795 | int bytes_to_send; | ||
| 796 | int bytes_sent; | ||
| 797 | int res; | ||
| 798 | |||
| 799 | lock_sock(sk); | ||
| 800 | |||
| 801 | /* Handle special cases where there is no connection */ | ||
| 802 | if (unlikely(sock->state != SS_CONNECTED)) { | ||
| 803 | if (sock->state == SS_UNCONNECTED) | ||
| 804 | res = tipc_send_packet(NULL, sock, m, total_len); | ||
| 805 | else | ||
| 806 | res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN; | ||
| 807 | goto exit; | ||
| 808 | } | ||
| 809 | |||
| 810 | if (unlikely(m->msg_name)) { | ||
| 811 | res = -EISCONN; | ||
| 812 | goto exit; | ||
| 813 | } | ||
| 814 | |||
| 815 | if (total_len > (unsigned int)INT_MAX) { | ||
| 816 | res = -EMSGSIZE; | ||
| 817 | goto exit; | ||
| 818 | } | ||
| 819 | |||
| 820 | /* | ||
| 821 | * Send each iovec entry using one or more messages | ||
| 822 | * | ||
| 823 | * Note: This algorithm is good for the most likely case | ||
| 824 | * (i.e. one large iovec entry), but could be improved to pass sets | ||
| 825 | * of small iovec entries into send_packet(). | ||
| 826 | */ | ||
| 827 | curr_iov = m->msg_iov; | ||
| 828 | curr_iovlen = m->msg_iovlen; | ||
| 829 | my_msg.msg_iov = &my_iov; | ||
| 830 | my_msg.msg_iovlen = 1; | ||
| 831 | my_msg.msg_flags = m->msg_flags; | ||
| 832 | my_msg.msg_name = NULL; | ||
| 833 | bytes_sent = 0; | ||
| 834 | |||
| 835 | hdr_size = msg_hdr_sz(&tsk->port.phdr); | ||
| 836 | |||
| 837 | while (curr_iovlen--) { | ||
| 838 | curr_start = curr_iov->iov_base; | ||
| 839 | curr_left = curr_iov->iov_len; | ||
| 840 | |||
| 841 | while (curr_left) { | ||
| 842 | bytes_to_send = tsk->port.max_pkt - hdr_size; | ||
| 843 | if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE) | ||
| 844 | bytes_to_send = TIPC_MAX_USER_MSG_SIZE; | ||
| 845 | if (curr_left < bytes_to_send) | ||
| 846 | bytes_to_send = curr_left; | ||
| 847 | my_iov.iov_base = curr_start; | ||
| 848 | my_iov.iov_len = bytes_to_send; | ||
| 849 | res = tipc_send_packet(NULL, sock, &my_msg, | ||
| 850 | bytes_to_send); | ||
| 851 | if (res < 0) { | ||
| 852 | if (bytes_sent) | ||
| 853 | res = bytes_sent; | ||
| 854 | goto exit; | ||
| 855 | } | ||
| 856 | curr_left -= bytes_to_send; | ||
| 857 | curr_start += bytes_to_send; | ||
| 858 | bytes_sent += bytes_to_send; | ||
| 859 | } | ||
| 860 | 983 | ||
| 861 | curr_iov++; | 984 | return tipc_send_stream(iocb, sock, m, dsz); |
| 862 | } | ||
| 863 | res = bytes_sent; | ||
| 864 | exit: | ||
| 865 | release_sock(sk); | ||
| 866 | return res; | ||
| 867 | } | 985 | } |
| 868 | 986 | ||
| 869 | /** | 987 | /** |
| @@ -1104,8 +1222,10 @@ restart: | |||
| 1104 | /* Consume received message (optional) */ | 1222 | /* Consume received message (optional) */ |
| 1105 | if (likely(!(flags & MSG_PEEK))) { | 1223 | if (likely(!(flags & MSG_PEEK))) { |
| 1106 | if ((sock->state != SS_READY) && | 1224 | if ((sock->state != SS_READY) && |
| 1107 | (++port->conn_unacked >= TIPC_CONNACK_INTV)) | 1225 | (++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) { |
| 1108 | tipc_acknowledge(port->ref, port->conn_unacked); | 1226 | tipc_acknowledge(port->ref, tsk->rcv_unacked); |
| 1227 | tsk->rcv_unacked = 0; | ||
| 1228 | } | ||
| 1109 | advance_rx_queue(sk); | 1229 | advance_rx_queue(sk); |
| 1110 | } | 1230 | } |
| 1111 | exit: | 1231 | exit: |
| @@ -1213,8 +1333,10 @@ restart: | |||
| 1213 | 1333 | ||
| 1214 | /* Consume received message (optional) */ | 1334 | /* Consume received message (optional) */ |
| 1215 | if (likely(!(flags & MSG_PEEK))) { | 1335 | if (likely(!(flags & MSG_PEEK))) { |
| 1216 | if (unlikely(++port->conn_unacked >= TIPC_CONNACK_INTV)) | 1336 | if (unlikely(++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) { |
| 1217 | tipc_acknowledge(port->ref, port->conn_unacked); | 1337 | tipc_acknowledge(port->ref, tsk->rcv_unacked); |
| 1338 | tsk->rcv_unacked = 0; | ||
| 1339 | } | ||
| 1218 | advance_rx_queue(sk); | 1340 | advance_rx_queue(sk); |
| 1219 | } | 1341 | } |
| 1220 | 1342 | ||
| @@ -1269,17 +1391,16 @@ static void tipc_data_ready(struct sock *sk) | |||
| 1269 | * @tsk: TIPC socket | 1391 | * @tsk: TIPC socket |
| 1270 | * @msg: message | 1392 | * @msg: message |
| 1271 | * | 1393 | * |
| 1272 | * Returns TIPC error status code and socket error status code | 1394 | * Returns 0 (TIPC_OK) if everyting ok, -TIPC_ERR_NO_PORT otherwise |
| 1273 | * once it encounters some errors | ||
| 1274 | */ | 1395 | */ |
| 1275 | static u32 filter_connect(struct tipc_sock *tsk, struct sk_buff **buf) | 1396 | static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf) |
| 1276 | { | 1397 | { |
| 1277 | struct sock *sk = &tsk->sk; | 1398 | struct sock *sk = &tsk->sk; |
| 1278 | struct tipc_port *port = &tsk->port; | 1399 | struct tipc_port *port = &tsk->port; |
| 1279 | struct socket *sock = sk->sk_socket; | 1400 | struct socket *sock = sk->sk_socket; |
| 1280 | struct tipc_msg *msg = buf_msg(*buf); | 1401 | struct tipc_msg *msg = buf_msg(*buf); |
| 1281 | 1402 | ||
| 1282 | u32 retval = TIPC_ERR_NO_PORT; | 1403 | int retval = -TIPC_ERR_NO_PORT; |
| 1283 | int res; | 1404 | int res; |
| 1284 | 1405 | ||
| 1285 | if (msg_mcast(msg)) | 1406 | if (msg_mcast(msg)) |
| @@ -1382,32 +1503,37 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) | |||
| 1382 | * | 1503 | * |
| 1383 | * Called with socket lock already taken; port lock may also be taken. | 1504 | * Called with socket lock already taken; port lock may also be taken. |
| 1384 | * | 1505 | * |
| 1385 | * Returns TIPC error status code (TIPC_OK if message is not to be rejected) | 1506 | * Returns 0 (TIPC_OK) if message was consumed, -TIPC error code if message |
| 1507 | * to be rejected, 1 (TIPC_FWD_MSG) if (CONN_MANAGER) message to be forwarded | ||
| 1386 | */ | 1508 | */ |
| 1387 | static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) | 1509 | static int filter_rcv(struct sock *sk, struct sk_buff *buf) |
| 1388 | { | 1510 | { |
| 1389 | struct socket *sock = sk->sk_socket; | 1511 | struct socket *sock = sk->sk_socket; |
| 1390 | struct tipc_sock *tsk = tipc_sk(sk); | 1512 | struct tipc_sock *tsk = tipc_sk(sk); |
| 1391 | struct tipc_msg *msg = buf_msg(buf); | 1513 | struct tipc_msg *msg = buf_msg(buf); |
| 1392 | unsigned int limit = rcvbuf_limit(sk, buf); | 1514 | unsigned int limit = rcvbuf_limit(sk, buf); |
| 1393 | u32 res = TIPC_OK; | 1515 | u32 onode; |
| 1516 | int rc = TIPC_OK; | ||
| 1517 | |||
| 1518 | if (unlikely(msg_user(msg) == CONN_MANAGER)) | ||
| 1519 | return tipc_sk_proto_rcv(tsk, &onode, buf); | ||
| 1394 | 1520 | ||
| 1395 | /* Reject message if it is wrong sort of message for socket */ | 1521 | /* Reject message if it is wrong sort of message for socket */ |
| 1396 | if (msg_type(msg) > TIPC_DIRECT_MSG) | 1522 | if (msg_type(msg) > TIPC_DIRECT_MSG) |
| 1397 | return TIPC_ERR_NO_PORT; | 1523 | return -TIPC_ERR_NO_PORT; |
| 1398 | 1524 | ||
| 1399 | if (sock->state == SS_READY) { | 1525 | if (sock->state == SS_READY) { |
| 1400 | if (msg_connected(msg)) | 1526 | if (msg_connected(msg)) |
| 1401 | return TIPC_ERR_NO_PORT; | 1527 | return -TIPC_ERR_NO_PORT; |
| 1402 | } else { | 1528 | } else { |
| 1403 | res = filter_connect(tsk, &buf); | 1529 | rc = filter_connect(tsk, &buf); |
| 1404 | if (res != TIPC_OK || buf == NULL) | 1530 | if (rc != TIPC_OK || buf == NULL) |
| 1405 | return res; | 1531 | return rc; |
| 1406 | } | 1532 | } |
| 1407 | 1533 | ||
| 1408 | /* Reject message if there isn't room to queue it */ | 1534 | /* Reject message if there isn't room to queue it */ |
| 1409 | if (sk_rmem_alloc_get(sk) + buf->truesize >= limit) | 1535 | if (sk_rmem_alloc_get(sk) + buf->truesize >= limit) |
| 1410 | return TIPC_ERR_OVERLOAD; | 1536 | return -TIPC_ERR_OVERLOAD; |
| 1411 | 1537 | ||
| 1412 | /* Enqueue message */ | 1538 | /* Enqueue message */ |
| 1413 | TIPC_SKB_CB(buf)->handle = NULL; | 1539 | TIPC_SKB_CB(buf)->handle = NULL; |
| @@ -1429,16 +1555,23 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) | |||
| 1429 | */ | 1555 | */ |
| 1430 | static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf) | 1556 | static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf) |
| 1431 | { | 1557 | { |
| 1432 | u32 res; | 1558 | int rc; |
| 1559 | u32 onode; | ||
| 1433 | struct tipc_sock *tsk = tipc_sk(sk); | 1560 | struct tipc_sock *tsk = tipc_sk(sk); |
| 1434 | uint truesize = buf->truesize; | 1561 | uint truesize = buf->truesize; |
| 1435 | 1562 | ||
| 1436 | res = filter_rcv(sk, buf); | 1563 | rc = filter_rcv(sk, buf); |
| 1437 | if (unlikely(res)) | ||
| 1438 | tipc_reject_msg(buf, res); | ||
| 1439 | 1564 | ||
| 1440 | if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) | 1565 | if (likely(!rc)) { |
| 1441 | atomic_add(truesize, &tsk->dupl_rcvcnt); | 1566 | if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT) |
| 1567 | atomic_add(truesize, &tsk->dupl_rcvcnt); | ||
| 1568 | return 0; | ||
| 1569 | } | ||
| 1570 | |||
| 1571 | if ((rc < 0) && !tipc_msg_reverse(buf, &onode, -rc)) | ||
| 1572 | return 0; | ||
| 1573 | |||
| 1574 | tipc_link_xmit(buf, onode, 0); | ||
| 1442 | 1575 | ||
| 1443 | return 0; | 1576 | return 0; |
| 1444 | } | 1577 | } |
| @@ -1455,19 +1588,14 @@ int tipc_sk_rcv(struct sk_buff *buf) | |||
| 1455 | struct tipc_port *port; | 1588 | struct tipc_port *port; |
| 1456 | struct sock *sk; | 1589 | struct sock *sk; |
| 1457 | u32 dport = msg_destport(buf_msg(buf)); | 1590 | u32 dport = msg_destport(buf_msg(buf)); |
| 1458 | int err = TIPC_OK; | 1591 | int rc = TIPC_OK; |
| 1459 | uint limit; | 1592 | uint limit; |
| 1593 | u32 dnode; | ||
| 1460 | 1594 | ||
| 1461 | /* Forward unresolved named message */ | 1595 | /* Validate destination and message */ |
| 1462 | if (unlikely(!dport)) { | ||
| 1463 | tipc_net_route_msg(buf); | ||
| 1464 | return 0; | ||
| 1465 | } | ||
| 1466 | |||
| 1467 | /* Validate destination */ | ||
| 1468 | port = tipc_port_lock(dport); | 1596 | port = tipc_port_lock(dport); |
| 1469 | if (unlikely(!port)) { | 1597 | if (unlikely(!port)) { |
| 1470 | err = TIPC_ERR_NO_PORT; | 1598 | rc = tipc_msg_eval(buf, &dnode); |
| 1471 | goto exit; | 1599 | goto exit; |
| 1472 | } | 1600 | } |
| 1473 | 1601 | ||
| @@ -1478,23 +1606,25 @@ int tipc_sk_rcv(struct sk_buff *buf) | |||
| 1478 | bh_lock_sock(sk); | 1606 | bh_lock_sock(sk); |
| 1479 | 1607 | ||
| 1480 | if (!sock_owned_by_user(sk)) { | 1608 | if (!sock_owned_by_user(sk)) { |
| 1481 | err = filter_rcv(sk, buf); | 1609 | rc = filter_rcv(sk, buf); |
| 1482 | } else { | 1610 | } else { |
| 1483 | if (sk->sk_backlog.len == 0) | 1611 | if (sk->sk_backlog.len == 0) |
| 1484 | atomic_set(&tsk->dupl_rcvcnt, 0); | 1612 | atomic_set(&tsk->dupl_rcvcnt, 0); |
| 1485 | limit = rcvbuf_limit(sk, buf) + atomic_read(&tsk->dupl_rcvcnt); | 1613 | limit = rcvbuf_limit(sk, buf) + atomic_read(&tsk->dupl_rcvcnt); |
| 1486 | if (sk_add_backlog(sk, buf, limit)) | 1614 | if (sk_add_backlog(sk, buf, limit)) |
| 1487 | err = TIPC_ERR_OVERLOAD; | 1615 | rc = -TIPC_ERR_OVERLOAD; |
| 1488 | } | 1616 | } |
| 1489 | |||
| 1490 | bh_unlock_sock(sk); | 1617 | bh_unlock_sock(sk); |
| 1491 | tipc_port_unlock(port); | 1618 | tipc_port_unlock(port); |
| 1492 | 1619 | ||
| 1493 | if (likely(!err)) | 1620 | if (likely(!rc)) |
| 1494 | return 0; | 1621 | return 0; |
| 1495 | exit: | 1622 | exit: |
| 1496 | tipc_reject_msg(buf, err); | 1623 | if ((rc < 0) && !tipc_msg_reverse(buf, &dnode, -rc)) |
| 1497 | return -EHOSTUNREACH; | 1624 | return -EHOSTUNREACH; |
| 1625 | |||
| 1626 | tipc_link_xmit(buf, dnode, 0); | ||
| 1627 | return (rc < 0) ? -EHOSTUNREACH : 0; | ||
| 1498 | } | 1628 | } |
| 1499 | 1629 | ||
| 1500 | static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) | 1630 | static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) |
| @@ -1758,6 +1888,7 @@ static int tipc_shutdown(struct socket *sock, int how) | |||
| 1758 | struct tipc_sock *tsk = tipc_sk(sk); | 1888 | struct tipc_sock *tsk = tipc_sk(sk); |
| 1759 | struct tipc_port *port = &tsk->port; | 1889 | struct tipc_port *port = &tsk->port; |
| 1760 | struct sk_buff *buf; | 1890 | struct sk_buff *buf; |
| 1891 | u32 peer; | ||
| 1761 | int res; | 1892 | int res; |
| 1762 | 1893 | ||
| 1763 | if (how != SHUT_RDWR) | 1894 | if (how != SHUT_RDWR) |
| @@ -1778,7 +1909,8 @@ restart: | |||
| 1778 | goto restart; | 1909 | goto restart; |
| 1779 | } | 1910 | } |
| 1780 | tipc_port_disconnect(port->ref); | 1911 | tipc_port_disconnect(port->ref); |
| 1781 | tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN); | 1912 | if (tipc_msg_reverse(buf, &peer, TIPC_CONN_SHUTDOWN)) |
| 1913 | tipc_link_xmit(buf, peer, 0); | ||
| 1782 | } else { | 1914 | } else { |
| 1783 | tipc_port_shutdown(port->ref); | 1915 | tipc_port_shutdown(port->ref); |
| 1784 | } | 1916 | } |
| @@ -1841,7 +1973,7 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt, | |||
| 1841 | 1973 | ||
| 1842 | switch (opt) { | 1974 | switch (opt) { |
| 1843 | case TIPC_IMPORTANCE: | 1975 | case TIPC_IMPORTANCE: |
| 1844 | tipc_port_set_importance(port, value); | 1976 | res = tipc_port_set_importance(port, value); |
| 1845 | break; | 1977 | break; |
| 1846 | case TIPC_SRC_DROPPABLE: | 1978 | case TIPC_SRC_DROPPABLE: |
| 1847 | if (sock->type != SOCK_STREAM) | 1979 | if (sock->type != SOCK_STREAM) |
| @@ -1936,7 +2068,7 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt, | |||
| 1936 | return put_user(sizeof(value), ol); | 2068 | return put_user(sizeof(value), ol); |
| 1937 | } | 2069 | } |
| 1938 | 2070 | ||
| 1939 | int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) | 2071 | static int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) |
| 1940 | { | 2072 | { |
| 1941 | struct tipc_sioc_ln_req lnr; | 2073 | struct tipc_sioc_ln_req lnr; |
| 1942 | void __user *argp = (void __user *)arg; | 2074 | void __user *argp = (void __user *)arg; |
| @@ -1952,7 +2084,6 @@ int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg) | |||
| 1952 | return 0; | 2084 | return 0; |
| 1953 | } | 2085 | } |
| 1954 | return -EADDRNOTAVAIL; | 2086 | return -EADDRNOTAVAIL; |
| 1955 | break; | ||
| 1956 | default: | 2087 | default: |
| 1957 | return -ENOIOCTLCMD; | 2088 | return -ENOIOCTLCMD; |
| 1958 | } | 2089 | } |
diff --git a/net/tipc/socket.h b/net/tipc/socket.h index 3afcd2a70b31..43b75b3ceced 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h | |||
| @@ -38,6 +38,9 @@ | |||
| 38 | #include "port.h" | 38 | #include "port.h" |
| 39 | #include <net/sock.h> | 39 | #include <net/sock.h> |
| 40 | 40 | ||
| 41 | #define TIPC_CONN_OK 0 | ||
| 42 | #define TIPC_CONN_PROBING 1 | ||
| 43 | |||
| 41 | /** | 44 | /** |
| 42 | * struct tipc_sock - TIPC socket structure | 45 | * struct tipc_sock - TIPC socket structure |
| 43 | * @sk: socket - interacts with 'port' and with user via the socket API | 46 | * @sk: socket - interacts with 'port' and with user via the socket API |
| @@ -45,6 +48,9 @@ | |||
| 45 | * @peer_name: the peer of the connection, if any | 48 | * @peer_name: the peer of the connection, if any |
| 46 | * @conn_timeout: the time we can wait for an unresponded setup request | 49 | * @conn_timeout: the time we can wait for an unresponded setup request |
| 47 | * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue | 50 | * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue |
| 51 | * @link_cong: non-zero if owner must sleep because of link congestion | ||
| 52 | * @sent_unacked: # messages sent by socket, and not yet acked by peer | ||
| 53 | * @rcv_unacked: # messages read by user, but not yet acked back to peer | ||
| 48 | */ | 54 | */ |
| 49 | 55 | ||
| 50 | struct tipc_sock { | 56 | struct tipc_sock { |
| @@ -52,6 +58,9 @@ struct tipc_sock { | |||
| 52 | struct tipc_port port; | 58 | struct tipc_port port; |
| 53 | unsigned int conn_timeout; | 59 | unsigned int conn_timeout; |
| 54 | atomic_t dupl_rcvcnt; | 60 | atomic_t dupl_rcvcnt; |
| 61 | int link_cong; | ||
| 62 | uint sent_unacked; | ||
| 63 | uint rcv_unacked; | ||
| 55 | }; | 64 | }; |
| 56 | 65 | ||
| 57 | static inline struct tipc_sock *tipc_sk(const struct sock *sk) | 66 | static inline struct tipc_sock *tipc_sk(const struct sock *sk) |
| @@ -69,6 +78,13 @@ static inline void tipc_sock_wakeup(struct tipc_sock *tsk) | |||
| 69 | tsk->sk.sk_write_space(&tsk->sk); | 78 | tsk->sk.sk_write_space(&tsk->sk); |
| 70 | } | 79 | } |
| 71 | 80 | ||
| 81 | static inline int tipc_sk_conn_cong(struct tipc_sock *tsk) | ||
| 82 | { | ||
| 83 | return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN; | ||
| 84 | } | ||
| 85 | |||
| 72 | int tipc_sk_rcv(struct sk_buff *buf); | 86 | int tipc_sk_rcv(struct sk_buff *buf); |
| 73 | 87 | ||
| 88 | void tipc_sk_mcast_rcv(struct sk_buff *buf); | ||
| 89 | |||
| 74 | #endif | 90 | #endif |
