Merge 4.7-rc6 into tty-next
[cascardo/linux.git] / net / tipc / socket.c
index 88bfcd7..c49b8df 100644 (file)
@@ -796,9 +796,11 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
  * @tsk: receiving socket
  * @skb: pointer to message buffer.
  */
-static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb)
+static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
+                             struct sk_buff_head *xmitq)
 {
        struct sock *sk = &tsk->sk;
+       u32 onode = tsk_own_node(tsk);
        struct tipc_msg *hdr = buf_msg(skb);
        int mtyp = msg_type(hdr);
        bool conn_cong;
@@ -811,7 +813,8 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb)
 
        if (mtyp == CONN_PROBE) {
                msg_set_type(hdr, CONN_PROBE_REPLY);
-               tipc_sk_respond(sk, skb, TIPC_OK);
+               if (tipc_msg_reverse(onode, &skb, TIPC_OK))
+                       __skb_queue_tail(xmitq, skb);
                return;
        } else if (mtyp == CONN_ACK) {
                conn_cong = tsk_conn_cong(tsk);
@@ -1686,7 +1689,8 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *skb)
  *
  * Returns true if message was added to socket receive queue, otherwise false
  */
-static bool filter_rcv(struct sock *sk, struct sk_buff *skb)
+static bool filter_rcv(struct sock *sk, struct sk_buff *skb,
+                      struct sk_buff_head *xmitq)
 {
        struct socket *sock = sk->sk_socket;
        struct tipc_sock *tsk = tipc_sk(sk);
@@ -1696,7 +1700,7 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb)
        int usr = msg_user(hdr);
 
        if (unlikely(msg_user(hdr) == CONN_MANAGER)) {
-               tipc_sk_proto_rcv(tsk, skb);
+               tipc_sk_proto_rcv(tsk, skb, xmitq);
                return false;
        }
 
@@ -1739,7 +1743,8 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb)
        return true;
 
 reject:
-       tipc_sk_respond(sk, skb, err);
+       if (tipc_msg_reverse(tsk_own_node(tsk), &skb, err))
+               __skb_queue_tail(xmitq, skb);
        return false;
 }
 
@@ -1755,9 +1760,24 @@ reject:
 static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
        unsigned int truesize = skb->truesize;
+       struct sk_buff_head xmitq;
+       u32 dnode, selector;
 
-       if (likely(filter_rcv(sk, skb)))
+       __skb_queue_head_init(&xmitq);
+
+       if (likely(filter_rcv(sk, skb, &xmitq))) {
                atomic_add(truesize, &tipc_sk(sk)->dupl_rcvcnt);
+               return 0;
+       }
+
+       if (skb_queue_empty(&xmitq))
+               return 0;
+
+       /* Send response/rejected message */
+       skb = __skb_dequeue(&xmitq);
+       dnode = msg_destnode(buf_msg(skb));
+       selector = msg_origport(buf_msg(skb));
+       tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector);
        return 0;
 }
 
@@ -1771,12 +1791,13 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
  * Caller must hold socket lock
  */
 static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
-                           u32 dport)
+                           u32 dport, struct sk_buff_head *xmitq)
 {
+       unsigned long time_limit = jiffies + 2;
+       struct sk_buff *skb;
        unsigned int lim;
        atomic_t *dcnt;
-       struct sk_buff *skb;
-       unsigned long time_limit = jiffies + 2;
+       u32 onode;
 
        while (skb_queue_len(inputq)) {
                if (unlikely(time_after_eq(jiffies, time_limit)))
@@ -1788,7 +1809,7 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
 
                /* Add message directly to receive queue if possible */
                if (!sock_owned_by_user(sk)) {
-                       filter_rcv(sk, skb);
+                       filter_rcv(sk, skb, xmitq);
                        continue;
                }
 
@@ -1801,7 +1822,9 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
                        continue;
 
                /* Overload => reject message back to sender */
-               tipc_sk_respond(sk, skb, TIPC_ERR_OVERLOAD);
+               onode = tipc_own_addr(sock_net(sk));
+               if (tipc_msg_reverse(onode, &skb, TIPC_ERR_OVERLOAD))
+                       __skb_queue_tail(xmitq, skb);
                break;
        }
 }
@@ -1814,12 +1837,14 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
  */
 void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
 {
+       struct sk_buff_head xmitq;
        u32 dnode, dport = 0;
        int err;
        struct tipc_sock *tsk;
        struct sock *sk;
        struct sk_buff *skb;
 
+       __skb_queue_head_init(&xmitq);
        while (skb_queue_len(inputq)) {
                dport = tipc_skb_peek_port(inputq, dport);
                tsk = tipc_sk_lookup(net, dport);
@@ -1827,9 +1852,14 @@ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
                if (likely(tsk)) {
                        sk = &tsk->sk;
                        if (likely(spin_trylock_bh(&sk->sk_lock.slock))) {
-                               tipc_sk_enqueue(inputq, sk, dport);
+                               tipc_sk_enqueue(inputq, sk, dport, &xmitq);
                                spin_unlock_bh(&sk->sk_lock.slock);
                        }
+                       /* Send pending response/rejected messages, if any */
+                       while ((skb = __skb_dequeue(&xmitq))) {
+                               dnode = msg_destnode(buf_msg(skb));
+                               tipc_node_xmit_skb(net, skb, dnode, dport);
+                       }
                        sock_put(sk);
                        continue;
                }