tipc: clean up socket layer message reception
When a message is received in a socket, one of the call chains tipc_sk_rcv()->tipc_sk_enqueue()->filter_rcv()(->tipc_sk_proto_rcv()) or tipc_sk_backlog_rcv()->filter_rcv()(->tipc_sk_proto_rcv()) are followed. At each of these levels we may encounter situations where the message may need to be rejected, or a new message produced for transfer back to the sender. Despite recent improvements, the current code for doing this is perceived as awkward and hard to follow. Leveraging the two previous commits in this series, we now introduce a more uniform handling of such situations. We let each of the functions in the chain itself produce/reverse the message to be returned to the sender, but also perform the actual forwarding. This simplifies the necessary logics within each function. Reviewed-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bcd3ffd4f6
commit
cda3696d3d
|
@ -520,17 +520,15 @@ exit:
|
||||||
/**
|
/**
|
||||||
* tipc_msg_lookup_dest(): try to find new destination for named message
|
* tipc_msg_lookup_dest(): try to find new destination for named message
|
||||||
* @skb: the buffer containing the message.
|
* @skb: the buffer containing the message.
|
||||||
* @dnode: return value: next-hop node, if destination found
|
* @err: error code to be used by caller if lookup fails
|
||||||
* @err: return value: error code to use, if message to be rejected
|
|
||||||
* Does not consume buffer
|
* Does not consume buffer
|
||||||
* Returns true if a destination is found, false otherwise
|
* Returns true if a destination is found, false otherwise
|
||||||
*/
|
*/
|
||||||
bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb,
|
bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err)
|
||||||
u32 *dnode, int *err)
|
|
||||||
{
|
{
|
||||||
struct tipc_msg *msg = buf_msg(skb);
|
struct tipc_msg *msg = buf_msg(skb);
|
||||||
u32 dport;
|
u32 dport, dnode;
|
||||||
u32 own_addr = tipc_own_addr(net);
|
u32 onode = tipc_own_addr(net);
|
||||||
|
|
||||||
if (!msg_isdata(msg))
|
if (!msg_isdata(msg))
|
||||||
return false;
|
return false;
|
||||||
|
@ -543,15 +541,15 @@ bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb,
|
||||||
return false;
|
return false;
|
||||||
if (msg_reroute_cnt(msg))
|
if (msg_reroute_cnt(msg))
|
||||||
return false;
|
return false;
|
||||||
*dnode = addr_domain(net, msg_lookup_scope(msg));
|
dnode = addr_domain(net, msg_lookup_scope(msg));
|
||||||
dport = tipc_nametbl_translate(net, msg_nametype(msg),
|
dport = tipc_nametbl_translate(net, msg_nametype(msg),
|
||||||
msg_nameinst(msg), dnode);
|
msg_nameinst(msg), &dnode);
|
||||||
if (!dport)
|
if (!dport)
|
||||||
return false;
|
return false;
|
||||||
msg_incr_reroute_cnt(msg);
|
msg_incr_reroute_cnt(msg);
|
||||||
if (*dnode != own_addr)
|
if (dnode != onode)
|
||||||
msg_set_prevnode(msg, own_addr);
|
msg_set_prevnode(msg, onode);
|
||||||
msg_set_destnode(msg, *dnode);
|
msg_set_destnode(msg, dnode);
|
||||||
msg_set_destport(msg, dport);
|
msg_set_destport(msg, dport);
|
||||||
*err = TIPC_OK;
|
*err = TIPC_OK;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -798,8 +798,7 @@ bool tipc_msg_make_bundle(struct sk_buff **skb, struct tipc_msg *msg,
|
||||||
bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos);
|
bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos);
|
||||||
int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m,
|
int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m,
|
||||||
int offset, int dsz, int mtu, struct sk_buff_head *list);
|
int offset, int dsz, int mtu, struct sk_buff_head *list);
|
||||||
bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, u32 *dnode,
|
bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err);
|
||||||
int *err);
|
|
||||||
struct sk_buff *tipc_msg_reassemble(struct sk_buff_head *list);
|
struct sk_buff *tipc_msg_reassemble(struct sk_buff_head *list);
|
||||||
|
|
||||||
static inline u16 buf_seqno(struct sk_buff *skb)
|
static inline u16 buf_seqno(struct sk_buff *skb)
|
||||||
|
|
|
@ -1520,82 +1520,81 @@ static void tipc_data_ready(struct sock *sk)
|
||||||
* @tsk: TIPC socket
|
* @tsk: TIPC socket
|
||||||
* @skb: pointer to message buffer. Set to NULL if buffer is consumed
|
* @skb: pointer to message buffer. Set to NULL if buffer is consumed
|
||||||
*
|
*
|
||||||
* Returns 0 (TIPC_OK) if everything ok, -TIPC_ERR_NO_PORT otherwise
|
* Returns true if everything ok, false otherwise
|
||||||
*/
|
*/
|
||||||
static int filter_connect(struct tipc_sock *tsk, struct sk_buff **skb)
|
static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct sock *sk = &tsk->sk;
|
struct sock *sk = &tsk->sk;
|
||||||
struct net *net = sock_net(sk);
|
struct net *net = sock_net(sk);
|
||||||
struct socket *sock = sk->sk_socket;
|
struct socket *sock = sk->sk_socket;
|
||||||
struct tipc_msg *msg = buf_msg(*skb);
|
struct tipc_msg *hdr = buf_msg(skb);
|
||||||
int retval = -TIPC_ERR_NO_PORT;
|
|
||||||
|
|
||||||
if (msg_mcast(msg))
|
if (unlikely(msg_mcast(hdr)))
|
||||||
return retval;
|
return false;
|
||||||
|
|
||||||
switch ((int)sock->state) {
|
switch ((int)sock->state) {
|
||||||
case SS_CONNECTED:
|
case SS_CONNECTED:
|
||||||
|
|
||||||
/* Accept only connection-based messages sent by peer */
|
/* Accept only connection-based messages sent by peer */
|
||||||
if (tsk_peer_msg(tsk, msg)) {
|
if (unlikely(!tsk_peer_msg(tsk, hdr)))
|
||||||
if (unlikely(msg_errcode(msg))) {
|
return false;
|
||||||
sock->state = SS_DISCONNECTING;
|
|
||||||
tsk->connected = 0;
|
if (unlikely(msg_errcode(hdr))) {
|
||||||
/* let timer expire on it's own */
|
sock->state = SS_DISCONNECTING;
|
||||||
tipc_node_remove_conn(net, tsk_peer_node(tsk),
|
tsk->connected = 0;
|
||||||
tsk->portid);
|
/* Let timer expire on it's own */
|
||||||
}
|
tipc_node_remove_conn(net, tsk_peer_node(tsk),
|
||||||
retval = TIPC_OK;
|
tsk->portid);
|
||||||
}
|
}
|
||||||
break;
|
return true;
|
||||||
|
|
||||||
case SS_CONNECTING:
|
case SS_CONNECTING:
|
||||||
|
|
||||||
/* Accept only ACK or NACK message */
|
/* Accept only ACK or NACK message */
|
||||||
|
if (unlikely(!msg_connected(hdr)))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (unlikely(!msg_connected(msg)))
|
if (unlikely(msg_errcode(hdr))) {
|
||||||
break;
|
|
||||||
|
|
||||||
if (unlikely(msg_errcode(msg))) {
|
|
||||||
sock->state = SS_DISCONNECTING;
|
sock->state = SS_DISCONNECTING;
|
||||||
sk->sk_err = ECONNREFUSED;
|
sk->sk_err = ECONNREFUSED;
|
||||||
retval = TIPC_OK;
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)) {
|
if (unlikely(!msg_isdata(hdr))) {
|
||||||
sock->state = SS_DISCONNECTING;
|
sock->state = SS_DISCONNECTING;
|
||||||
sk->sk_err = EINVAL;
|
sk->sk_err = EINVAL;
|
||||||
retval = TIPC_OK;
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tipc_sk_finish_conn(tsk, msg_origport(msg), msg_orignode(msg));
|
tipc_sk_finish_conn(tsk, msg_origport(hdr), msg_orignode(hdr));
|
||||||
msg_set_importance(&tsk->phdr, msg_importance(msg));
|
msg_set_importance(&tsk->phdr, msg_importance(hdr));
|
||||||
sock->state = SS_CONNECTED;
|
sock->state = SS_CONNECTED;
|
||||||
|
|
||||||
/* If an incoming message is an 'ACK-', it should be
|
/* If 'ACK+' message, add to socket receive queue */
|
||||||
* discarded here because it doesn't contain useful
|
if (msg_data_sz(hdr))
|
||||||
* data. In addition, we should try to wake up
|
return true;
|
||||||
* connect() routine if sleeping.
|
|
||||||
*/
|
/* If empty 'ACK-' message, wake up sleeping connect() */
|
||||||
if (msg_data_sz(msg) == 0) {
|
if (waitqueue_active(sk_sleep(sk)))
|
||||||
kfree_skb(*skb);
|
wake_up_interruptible(sk_sleep(sk));
|
||||||
*skb = NULL;
|
|
||||||
if (waitqueue_active(sk_sleep(sk)))
|
/* 'ACK-' message is neither accepted nor rejected: */
|
||||||
wake_up_interruptible(sk_sleep(sk));
|
msg_set_dest_droppable(hdr, 1);
|
||||||
}
|
return false;
|
||||||
retval = TIPC_OK;
|
|
||||||
break;
|
|
||||||
case SS_LISTENING:
|
case SS_LISTENING:
|
||||||
case SS_UNCONNECTED:
|
case SS_UNCONNECTED:
|
||||||
|
|
||||||
/* Accept only SYN message */
|
/* Accept only SYN message */
|
||||||
if (!msg_connected(msg) && !(msg_errcode(msg)))
|
if (!msg_connected(hdr) && !(msg_errcode(hdr)))
|
||||||
retval = TIPC_OK;
|
return true;
|
||||||
break;
|
break;
|
||||||
case SS_DISCONNECTING:
|
case SS_DISCONNECTING:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pr_err("Unknown socket state %u\n", sock->state);
|
pr_err("Unknown socket state %u\n", sock->state);
|
||||||
}
|
}
|
||||||
return retval;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1630,61 +1629,70 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf)
|
||||||
/**
|
/**
|
||||||
* filter_rcv - validate incoming message
|
* filter_rcv - validate incoming message
|
||||||
* @sk: socket
|
* @sk: socket
|
||||||
* @skb: pointer to message. Set to NULL if buffer is consumed.
|
* @skb: pointer to message.
|
||||||
*
|
*
|
||||||
* Enqueues message on receive queue if acceptable; optionally handles
|
* Enqueues message on receive queue if acceptable; optionally handles
|
||||||
* disconnect indication for a connected socket.
|
* disconnect indication for a connected socket.
|
||||||
*
|
*
|
||||||
* Called with socket lock already taken
|
* Called with socket lock already taken
|
||||||
*
|
*
|
||||||
* Returns 0 (TIPC_OK) if message was ok, -TIPC error code if rejected
|
* Returns true if message was added to socket receive queue, otherwise false
|
||||||
*/
|
*/
|
||||||
static int filter_rcv(struct sock *sk, struct sk_buff **skb)
|
static bool filter_rcv(struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct socket *sock = sk->sk_socket;
|
struct socket *sock = sk->sk_socket;
|
||||||
struct tipc_sock *tsk = tipc_sk(sk);
|
struct tipc_sock *tsk = tipc_sk(sk);
|
||||||
struct tipc_msg *msg = buf_msg(*skb);
|
struct tipc_msg *hdr = buf_msg(skb);
|
||||||
unsigned int limit = rcvbuf_limit(sk, *skb);
|
unsigned int limit = rcvbuf_limit(sk, skb);
|
||||||
int rc = TIPC_OK;
|
int err = TIPC_OK;
|
||||||
|
int usr = msg_user(hdr);
|
||||||
|
|
||||||
if (unlikely(msg_user(msg) == CONN_MANAGER)) {
|
if (unlikely(msg_user(hdr) == CONN_MANAGER)) {
|
||||||
tipc_sk_proto_rcv(tsk, *skb);
|
tipc_sk_proto_rcv(tsk, skb);
|
||||||
return TIPC_OK;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(msg_user(msg) == SOCK_WAKEUP)) {
|
if (unlikely(usr == SOCK_WAKEUP)) {
|
||||||
kfree_skb(*skb);
|
kfree_skb(skb);
|
||||||
tsk->link_cong = 0;
|
tsk->link_cong = 0;
|
||||||
sk->sk_write_space(sk);
|
sk->sk_write_space(sk);
|
||||||
*skb = NULL;
|
return false;
|
||||||
return TIPC_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reject message if it is wrong sort of message for socket */
|
/* Drop if illegal message type */
|
||||||
if (msg_type(msg) > TIPC_DIRECT_MSG)
|
if (unlikely(msg_type(hdr) > TIPC_DIRECT_MSG)) {
|
||||||
return -TIPC_ERR_NO_PORT;
|
kfree_skb(skb);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (sock->state == SS_READY) {
|
/* Reject if wrong message type for current socket state */
|
||||||
if (msg_connected(msg))
|
if (unlikely(sock->state == SS_READY)) {
|
||||||
return -TIPC_ERR_NO_PORT;
|
if (msg_connected(hdr)) {
|
||||||
} else {
|
err = TIPC_ERR_NO_PORT;
|
||||||
rc = filter_connect(tsk, skb);
|
goto reject;
|
||||||
if (rc != TIPC_OK || !*skb)
|
}
|
||||||
return rc;
|
} else if (unlikely(!filter_connect(tsk, skb))) {
|
||||||
|
err = TIPC_ERR_NO_PORT;
|
||||||
|
goto reject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reject message if there isn't room to queue it */
|
/* Reject message if there isn't room to queue it */
|
||||||
if (sk_rmem_alloc_get(sk) + (*skb)->truesize >= limit)
|
if (unlikely(sk_rmem_alloc_get(sk) + skb->truesize >= limit)) {
|
||||||
return -TIPC_ERR_OVERLOAD;
|
err = TIPC_ERR_OVERLOAD;
|
||||||
|
goto reject;
|
||||||
|
}
|
||||||
|
|
||||||
/* Enqueue message */
|
/* Enqueue message */
|
||||||
TIPC_SKB_CB(*skb)->handle = NULL;
|
TIPC_SKB_CB(skb)->handle = NULL;
|
||||||
__skb_queue_tail(&sk->sk_receive_queue, *skb);
|
__skb_queue_tail(&sk->sk_receive_queue, skb);
|
||||||
skb_set_owner_r(*skb, sk);
|
skb_set_owner_r(skb, sk);
|
||||||
|
|
||||||
sk->sk_data_ready(sk);
|
sk->sk_data_ready(sk);
|
||||||
*skb = NULL;
|
return true;
|
||||||
return TIPC_OK;
|
|
||||||
|
reject:
|
||||||
|
tipc_sk_respond(sk, skb, err);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1698,22 +1706,10 @@ static int filter_rcv(struct sock *sk, struct sk_buff **skb)
|
||||||
*/
|
*/
|
||||||
static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
|
static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
int err;
|
unsigned int truesize = skb->truesize;
|
||||||
atomic_t *dcnt;
|
|
||||||
u32 dnode = msg_prevnode(buf_msg(skb));
|
|
||||||
struct tipc_sock *tsk = tipc_sk(sk);
|
|
||||||
struct net *net = sock_net(sk);
|
|
||||||
uint truesize = skb->truesize;
|
|
||||||
|
|
||||||
err = filter_rcv(sk, &skb);
|
if (likely(filter_rcv(sk, skb)))
|
||||||
if (likely(!skb)) {
|
atomic_add(truesize, &tipc_sk(sk)->dupl_rcvcnt);
|
||||||
dcnt = &tsk->dupl_rcvcnt;
|
|
||||||
if (atomic_read(dcnt) < TIPC_CONN_OVERLOAD_LIMIT)
|
|
||||||
atomic_add(truesize, dcnt);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!err || tipc_msg_reverse(tsk_own_node(tsk), &skb, -err))
|
|
||||||
tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1723,45 +1719,43 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
|
||||||
* @inputq: list of incoming buffers with potentially different destinations
|
* @inputq: list of incoming buffers with potentially different destinations
|
||||||
* @sk: socket where the buffers should be enqueued
|
* @sk: socket where the buffers should be enqueued
|
||||||
* @dport: port number for the socket
|
* @dport: port number for the socket
|
||||||
* @_skb: returned buffer to be forwarded or rejected, if applicable
|
|
||||||
*
|
*
|
||||||
* Caller must hold socket lock
|
* Caller must hold socket lock
|
||||||
*
|
|
||||||
* Returns TIPC_OK if all buffers enqueued, otherwise -TIPC_ERR_OVERLOAD
|
|
||||||
* or -TIPC_ERR_NO_PORT
|
|
||||||
*/
|
*/
|
||||||
static int tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
|
static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
|
||||||
u32 dport, struct sk_buff **_skb)
|
u32 dport)
|
||||||
{
|
{
|
||||||
unsigned int lim;
|
unsigned int lim;
|
||||||
atomic_t *dcnt;
|
atomic_t *dcnt;
|
||||||
int err;
|
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
unsigned long time_limit = jiffies + 2;
|
unsigned long time_limit = jiffies + 2;
|
||||||
|
|
||||||
while (skb_queue_len(inputq)) {
|
while (skb_queue_len(inputq)) {
|
||||||
if (unlikely(time_after_eq(jiffies, time_limit)))
|
if (unlikely(time_after_eq(jiffies, time_limit)))
|
||||||
return TIPC_OK;
|
return;
|
||||||
|
|
||||||
skb = tipc_skb_dequeue(inputq, dport);
|
skb = tipc_skb_dequeue(inputq, dport);
|
||||||
if (unlikely(!skb))
|
if (unlikely(!skb))
|
||||||
return TIPC_OK;
|
return;
|
||||||
|
|
||||||
|
/* Add message directly to receive queue if possible */
|
||||||
if (!sock_owned_by_user(sk)) {
|
if (!sock_owned_by_user(sk)) {
|
||||||
err = filter_rcv(sk, &skb);
|
filter_rcv(sk, skb);
|
||||||
if (likely(!skb))
|
continue;
|
||||||
continue;
|
|
||||||
*_skb = skb;
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try backlog, compensating for double-counted bytes */
|
||||||
dcnt = &tipc_sk(sk)->dupl_rcvcnt;
|
dcnt = &tipc_sk(sk)->dupl_rcvcnt;
|
||||||
if (sk->sk_backlog.len)
|
if (sk->sk_backlog.len)
|
||||||
atomic_set(dcnt, 0);
|
atomic_set(dcnt, 0);
|
||||||
lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt);
|
lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt);
|
||||||
if (likely(!sk_add_backlog(sk, skb, lim)))
|
if (likely(!sk_add_backlog(sk, skb, lim)))
|
||||||
continue;
|
continue;
|
||||||
*_skb = skb;
|
|
||||||
return -TIPC_ERR_OVERLOAD;
|
/* Overload => reject message back to sender */
|
||||||
|
tipc_sk_respond(sk, skb, TIPC_ERR_OVERLOAD);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return TIPC_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1769,51 +1763,46 @@ static int tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
|
||||||
* @inputq: buffer list containing the buffers
|
* @inputq: buffer list containing the buffers
|
||||||
* Consumes all buffers in list until inputq is empty
|
* Consumes all buffers in list until inputq is empty
|
||||||
* Note: may be called in multiple threads referring to the same queue
|
* Note: may be called in multiple threads referring to the same queue
|
||||||
* Returns 0 if last buffer was accepted, otherwise -EHOSTUNREACH
|
|
||||||
* Only node local calls check the return value, sending single-buffer queues
|
|
||||||
*/
|
*/
|
||||||
int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
|
void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
|
||||||
{
|
{
|
||||||
u32 dnode, dport = 0;
|
u32 dnode, dport = 0;
|
||||||
int err;
|
int err;
|
||||||
struct sk_buff *skb;
|
|
||||||
struct tipc_sock *tsk;
|
struct tipc_sock *tsk;
|
||||||
struct tipc_net *tn;
|
|
||||||
struct sock *sk;
|
struct sock *sk;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
while (skb_queue_len(inputq)) {
|
while (skb_queue_len(inputq)) {
|
||||||
err = -TIPC_ERR_NO_PORT;
|
|
||||||
skb = NULL;
|
|
||||||
dport = tipc_skb_peek_port(inputq, dport);
|
dport = tipc_skb_peek_port(inputq, dport);
|
||||||
tsk = tipc_sk_lookup(net, dport);
|
tsk = tipc_sk_lookup(net, dport);
|
||||||
|
|
||||||
if (likely(tsk)) {
|
if (likely(tsk)) {
|
||||||
sk = &tsk->sk;
|
sk = &tsk->sk;
|
||||||
if (likely(spin_trylock_bh(&sk->sk_lock.slock))) {
|
if (likely(spin_trylock_bh(&sk->sk_lock.slock))) {
|
||||||
err = tipc_sk_enqueue(inputq, sk, dport, &skb);
|
tipc_sk_enqueue(inputq, sk, dport);
|
||||||
spin_unlock_bh(&sk->sk_lock.slock);
|
spin_unlock_bh(&sk->sk_lock.slock);
|
||||||
dport = 0;
|
|
||||||
}
|
}
|
||||||
sock_put(sk);
|
sock_put(sk);
|
||||||
} else {
|
|
||||||
skb = tipc_skb_dequeue(inputq, dport);
|
|
||||||
}
|
|
||||||
if (likely(!skb))
|
|
||||||
continue;
|
continue;
|
||||||
if (tipc_msg_lookup_dest(net, skb, &dnode, &err))
|
|
||||||
goto xmit;
|
|
||||||
if (!err) {
|
|
||||||
dnode = msg_destnode(buf_msg(skb));
|
|
||||||
goto xmit;
|
|
||||||
} else {
|
|
||||||
dnode = msg_prevnode(buf_msg(skb));
|
|
||||||
}
|
}
|
||||||
tn = net_generic(net, tipc_net_id);
|
|
||||||
if (!tipc_msg_reverse(tn->own_addr, &skb, -err))
|
/* No destination socket => dequeue skb if still there */
|
||||||
|
skb = tipc_skb_dequeue(inputq, dport);
|
||||||
|
if (!skb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Try secondary lookup if unresolved named message */
|
||||||
|
err = TIPC_ERR_NO_PORT;
|
||||||
|
if (tipc_msg_lookup_dest(net, skb, &err))
|
||||||
|
goto xmit;
|
||||||
|
|
||||||
|
/* Prepare for message rejection */
|
||||||
|
if (!tipc_msg_reverse(tipc_own_addr(net), &skb, err))
|
||||||
continue;
|
continue;
|
||||||
xmit:
|
xmit:
|
||||||
|
dnode = msg_destnode(buf_msg(skb));
|
||||||
tipc_node_xmit_skb(net, skb, dnode, dport);
|
tipc_node_xmit_skb(net, skb, dnode, dport);
|
||||||
}
|
}
|
||||||
return err ? -EHOSTUNREACH : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)
|
static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)
|
||||||
|
@ -2082,7 +2071,10 @@ static int tipc_shutdown(struct socket *sock, int how)
|
||||||
struct net *net = sock_net(sk);
|
struct net *net = sock_net(sk);
|
||||||
struct tipc_sock *tsk = tipc_sk(sk);
|
struct tipc_sock *tsk = tipc_sk(sk);
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
u32 dnode;
|
u32 dnode = tsk_peer_node(tsk);
|
||||||
|
u32 dport = tsk_peer_port(tsk);
|
||||||
|
u32 onode = tipc_own_addr(net);
|
||||||
|
u32 oport = tsk->portid;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (how != SHUT_RDWR)
|
if (how != SHUT_RDWR)
|
||||||
|
@ -2108,9 +2100,8 @@ restart:
|
||||||
} else {
|
} else {
|
||||||
skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
|
skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
|
||||||
TIPC_CONN_MSG, SHORT_H_SIZE,
|
TIPC_CONN_MSG, SHORT_H_SIZE,
|
||||||
0, dnode, tsk_own_node(tsk),
|
0, dnode, onode, dport, oport,
|
||||||
tsk_peer_port(tsk),
|
TIPC_CONN_SHUTDOWN);
|
||||||
tsk->portid, TIPC_CONN_SHUTDOWN);
|
|
||||||
tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
|
tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
|
||||||
}
|
}
|
||||||
tsk->connected = 0;
|
tsk->connected = 0;
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
|
SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
|
||||||
int tipc_socket_init(void);
|
int tipc_socket_init(void);
|
||||||
void tipc_socket_stop(void);
|
void tipc_socket_stop(void);
|
||||||
int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq);
|
void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq);
|
||||||
void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
|
void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
|
||||||
struct sk_buff_head *inputq);
|
struct sk_buff_head *inputq);
|
||||||
void tipc_sk_reinit(struct net *net);
|
void tipc_sk_reinit(struct net *net);
|
||||||
|
|
Loading…
Reference in New Issue