diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/msg.c | 20 | ||||
-rw-r--r-- | net/tipc/msg.h | 1 | ||||
-rw-r--r-- | net/tipc/socket.c | 49 |
3 files changed, 64 insertions, 6 deletions
diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 00fbb5c4b2ef..f48e5857210f 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c | |||
@@ -525,6 +525,10 @@ bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, int err) | |||
525 | if (hlen == SHORT_H_SIZE) | 525 | if (hlen == SHORT_H_SIZE) |
526 | hlen = BASIC_H_SIZE; | 526 | hlen = BASIC_H_SIZE; |
527 | 527 | ||
528 | /* Don't return data along with SYN+, - sender has a clone */ | ||
529 | if (msg_is_syn(_hdr) && err == TIPC_ERR_OVERLOAD) | ||
530 | dlen = 0; | ||
531 | |||
528 | /* Allocate new buffer to return */ | 532 | /* Allocate new buffer to return */ |
529 | *skb = tipc_buf_acquire(hlen + dlen, GFP_ATOMIC); | 533 | *skb = tipc_buf_acquire(hlen + dlen, GFP_ATOMIC); |
530 | if (!*skb) | 534 | if (!*skb) |
@@ -552,6 +556,22 @@ exit: | |||
552 | return false; | 556 | return false; |
553 | } | 557 | } |
554 | 558 | ||
559 | bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy) | ||
560 | { | ||
561 | struct sk_buff *skb, *_skb; | ||
562 | |||
563 | skb_queue_walk(msg, skb) { | ||
564 | _skb = skb_clone(skb, GFP_ATOMIC); | ||
565 | if (!_skb) { | ||
566 | __skb_queue_purge(cpy); | ||
567 | pr_err_ratelimited("Failed to clone buffer chain\n"); | ||
568 | return false; | ||
569 | } | ||
570 | __skb_queue_tail(cpy, _skb); | ||
571 | } | ||
572 | return true; | ||
573 | } | ||
574 | |||
555 | /** | 575 | /** |
556 | * tipc_msg_lookup_dest(): try to find new destination for named message | 576 | * tipc_msg_lookup_dest(): try to find new destination for named message |
557 | * @skb: the buffer containing the message. | 577 | * @skb: the buffer containing the message. |
diff --git a/net/tipc/msg.h b/net/tipc/msg.h index cd64d7b2a0fe..a2879e6ec5b6 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h | |||
@@ -980,6 +980,7 @@ bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg, | |||
980 | struct sk_buff_head *cpy); | 980 | struct sk_buff_head *cpy); |
981 | void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno, | 981 | void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno, |
982 | struct sk_buff *skb); | 982 | struct sk_buff *skb); |
983 | bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy); | ||
983 | 984 | ||
984 | static inline u16 buf_seqno(struct sk_buff *skb) | 985 | static inline u16 buf_seqno(struct sk_buff *skb) |
985 | { | 986 | { |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 89d6dc0f456d..595c5001b28d 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -47,7 +47,7 @@ | |||
47 | #include "netlink.h" | 47 | #include "netlink.h" |
48 | #include "group.h" | 48 | #include "group.h" |
49 | 49 | ||
50 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ | 50 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ |
51 | #define CONN_PROBING_INTV msecs_to_jiffies(3600000) /* [ms] => 1 h */ | 51 | #define CONN_PROBING_INTV msecs_to_jiffies(3600000) /* [ms] => 1 h */ |
52 | #define TIPC_FWD_MSG 1 | 52 | #define TIPC_FWD_MSG 1 |
53 | #define TIPC_MAX_PORT 0xffffffff | 53 | #define TIPC_MAX_PORT 0xffffffff |
@@ -80,7 +80,6 @@ struct sockaddr_pair { | |||
80 | * @publications: list of publications for port | 80 | * @publications: list of publications for port |
81 | * @blocking_link: address of the congested link we are currently sleeping on | 81 | * @blocking_link: address of the congested link we are currently sleeping on |
82 | * @pub_count: total # of publications port has made during its lifetime | 82 | * @pub_count: total # of publications port has made during its lifetime |
83 | * @probing_state: | ||
84 | * @conn_timeout: the time we can wait for an unresponded setup request | 83 | * @conn_timeout: the time we can wait for an unresponded setup request |
85 | * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue | 84 | * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue |
86 | * @cong_link_cnt: number of congested links | 85 | * @cong_link_cnt: number of congested links |
@@ -102,8 +101,8 @@ struct tipc_sock { | |||
102 | struct list_head cong_links; | 101 | struct list_head cong_links; |
103 | struct list_head publications; | 102 | struct list_head publications; |
104 | u32 pub_count; | 103 | u32 pub_count; |
105 | uint conn_timeout; | ||
106 | atomic_t dupl_rcvcnt; | 104 | atomic_t dupl_rcvcnt; |
105 | u16 conn_timeout; | ||
107 | bool probe_unacked; | 106 | bool probe_unacked; |
108 | u16 cong_link_cnt; | 107 | u16 cong_link_cnt; |
109 | u16 snt_unacked; | 108 | u16 snt_unacked; |
@@ -507,6 +506,9 @@ static void __tipc_shutdown(struct socket *sock, int error) | |||
507 | tipc_wait_for_cond(sock, &timeout, (!tsk->cong_link_cnt && | 506 | tipc_wait_for_cond(sock, &timeout, (!tsk->cong_link_cnt && |
508 | !tsk_conn_cong(tsk))); | 507 | !tsk_conn_cong(tsk))); |
509 | 508 | ||
509 | /* Remove any pending SYN message */ | ||
510 | __skb_queue_purge(&sk->sk_write_queue); | ||
511 | |||
510 | /* Reject all unreceived messages, except on an active connection | 512 | /* Reject all unreceived messages, except on an active connection |
511 | * (which disconnects locally & sends a 'FIN+' to peer). | 513 | * (which disconnects locally & sends a 'FIN+' to peer). |
512 | */ | 514 | */ |
@@ -1362,6 +1364,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) | |||
1362 | rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts); | 1364 | rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts); |
1363 | if (unlikely(rc != dlen)) | 1365 | if (unlikely(rc != dlen)) |
1364 | return rc; | 1366 | return rc; |
1367 | if (unlikely(syn && !tipc_msg_skb_clone(&pkts, &sk->sk_write_queue))) | ||
1368 | return -ENOMEM; | ||
1365 | 1369 | ||
1366 | rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid); | 1370 | rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid); |
1367 | if (unlikely(rc == -ELINKCONG)) { | 1371 | if (unlikely(rc == -ELINKCONG)) { |
@@ -1491,6 +1495,7 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port, | |||
1491 | tipc_node_add_conn(net, peer_node, tsk->portid, peer_port); | 1495 | tipc_node_add_conn(net, peer_node, tsk->portid, peer_port); |
1492 | tsk->max_pkt = tipc_node_get_mtu(net, peer_node, tsk->portid); | 1496 | tsk->max_pkt = tipc_node_get_mtu(net, peer_node, tsk->portid); |
1493 | tsk->peer_caps = tipc_node_get_capabilities(net, peer_node); | 1497 | tsk->peer_caps = tipc_node_get_capabilities(net, peer_node); |
1498 | __skb_queue_purge(&sk->sk_write_queue); | ||
1494 | if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL) | 1499 | if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL) |
1495 | return; | 1500 | return; |
1496 | 1501 | ||
@@ -1977,6 +1982,7 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) | |||
1977 | u32 oport = msg_origport(hdr); | 1982 | u32 oport = msg_origport(hdr); |
1978 | u32 onode = msg_orignode(hdr); | 1983 | u32 onode = msg_orignode(hdr); |
1979 | int err = msg_errcode(hdr); | 1984 | int err = msg_errcode(hdr); |
1985 | unsigned long delay; | ||
1980 | 1986 | ||
1981 | if (unlikely(msg_mcast(hdr))) | 1987 | if (unlikely(msg_mcast(hdr))) |
1982 | return false; | 1988 | return false; |
@@ -2001,8 +2007,18 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) | |||
2001 | if (oport != pport || onode != pnode) | 2007 | if (oport != pport || onode != pnode) |
2002 | return false; | 2008 | return false; |
2003 | 2009 | ||
2004 | /* Rejected SYN - abort */ | 2010 | /* Rejected SYN */ |
2005 | break; | 2011 | if (err != TIPC_ERR_OVERLOAD) |
2012 | break; | ||
2013 | |||
2014 | /* Prepare for new setup attempt if we have a SYN clone */ | ||
2015 | if (skb_queue_empty(&sk->sk_write_queue)) | ||
2016 | break; | ||
2017 | get_random_bytes(&delay, 2); | ||
2018 | delay %= (tsk->conn_timeout / 4); | ||
2019 | delay = msecs_to_jiffies(delay + 100); | ||
2020 | sk_reset_timer(sk, &sk->sk_timer, jiffies + delay); | ||
2021 | return false; | ||
2006 | case TIPC_OPEN: | 2022 | case TIPC_OPEN: |
2007 | case TIPC_DISCONNECTING: | 2023 | case TIPC_DISCONNECTING: |
2008 | return false; | 2024 | return false; |
@@ -2561,12 +2577,26 @@ static void tipc_sk_check_probing_state(struct sock *sk, | |||
2561 | sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV); | 2577 | sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV); |
2562 | } | 2578 | } |
2563 | 2579 | ||
2580 | static void tipc_sk_retry_connect(struct sock *sk, struct sk_buff_head *list) | ||
2581 | { | ||
2582 | struct tipc_sock *tsk = tipc_sk(sk); | ||
2583 | |||
2584 | /* Try again later if dest link is congested */ | ||
2585 | if (tsk->cong_link_cnt) { | ||
2586 | sk_reset_timer(sk, &sk->sk_timer, msecs_to_jiffies(100)); | ||
2587 | return; | ||
2588 | } | ||
2589 | /* Prepare SYN for retransmit */ | ||
2590 | tipc_msg_skb_clone(&sk->sk_write_queue, list); | ||
2591 | } | ||
2592 | |||
2564 | static void tipc_sk_timeout(struct timer_list *t) | 2593 | static void tipc_sk_timeout(struct timer_list *t) |
2565 | { | 2594 | { |
2566 | struct sock *sk = from_timer(sk, t, sk_timer); | 2595 | struct sock *sk = from_timer(sk, t, sk_timer); |
2567 | struct tipc_sock *tsk = tipc_sk(sk); | 2596 | struct tipc_sock *tsk = tipc_sk(sk); |
2568 | u32 pnode = tsk_peer_node(tsk); | 2597 | u32 pnode = tsk_peer_node(tsk); |
2569 | struct sk_buff_head list; | 2598 | struct sk_buff_head list; |
2599 | int rc = 0; | ||
2570 | 2600 | ||
2571 | skb_queue_head_init(&list); | 2601 | skb_queue_head_init(&list); |
2572 | bh_lock_sock(sk); | 2602 | bh_lock_sock(sk); |
@@ -2580,12 +2610,19 @@ static void tipc_sk_timeout(struct timer_list *t) | |||
2580 | 2610 | ||
2581 | if (sk->sk_state == TIPC_ESTABLISHED) | 2611 | if (sk->sk_state == TIPC_ESTABLISHED) |
2582 | tipc_sk_check_probing_state(sk, &list); | 2612 | tipc_sk_check_probing_state(sk, &list); |
2613 | else if (sk->sk_state == TIPC_CONNECTING) | ||
2614 | tipc_sk_retry_connect(sk, &list); | ||
2583 | 2615 | ||
2584 | bh_unlock_sock(sk); | 2616 | bh_unlock_sock(sk); |
2585 | 2617 | ||
2586 | if (!skb_queue_empty(&list)) | 2618 | if (!skb_queue_empty(&list)) |
2587 | tipc_node_xmit(sock_net(sk), &list, pnode, tsk->portid); | 2619 | rc = tipc_node_xmit(sock_net(sk), &list, pnode, tsk->portid); |
2588 | 2620 | ||
2621 | /* SYN messages may cause link congestion */ | ||
2622 | if (rc == -ELINKCONG) { | ||
2623 | tipc_dest_push(&tsk->cong_links, pnode, 0); | ||
2624 | tsk->cong_link_cnt = 1; | ||
2625 | } | ||
2589 | sock_put(sk); | 2626 | sock_put(sk); |
2590 | } | 2627 | } |
2591 | 2628 | ||