static int accept(struct socket *sock, struct socket *new_sock, int flags) { struct sock *sk = sock->sk; struct sk_buff *buf; int res; lock_sock(sk); if (sock->state != SS_LISTENING) { res = -EINVAL; goto exit; } while (skb_queue_empty(&sk->sk_receive_queue)) { if (flags & O_NONBLOCK) { res = -EWOULDBLOCK; goto exit; } release_sock(sk); res = wait_event_interruptible(*sk_sleep(sk), (!skb_queue_empty(&sk->sk_receive_queue))); lock_sock(sk); if (res) goto exit; } buf = skb_peek(&sk->sk_receive_queue); res = tipc_create(sock_net(sock->sk), new_sock, 0, 0); if (!res) { struct sock *new_sk = new_sock->sk; struct tipc_sock *new_tsock = tipc_sk(new_sk); struct tipc_port *new_tport = new_tsock->p; u32 new_ref = new_tport->ref; struct tipc_msg *msg = buf_msg(buf); lock_sock(new_sk); /* * Reject any stray messages received by new socket * before the socket lock was taken (very, very unlikely) */ reject_rx_queue(new_sk); /* Connect new socket to it's peer */ new_tsock->peer_name.ref = msg_origport(msg); new_tsock->peer_name.node = msg_orignode(msg); tipc_connect2port(new_ref, &new_tsock->peer_name); new_sock->state = SS_CONNECTED; tipc_set_portimportance(new_ref, msg_importance(msg)); if (msg_named(msg)) { new_tport->conn_type = msg_nametype(msg); new_tport->conn_instance = msg_nameinst(msg); } /* * Respond to 'SYN-' by discarding it & returning 'ACK'-. * Respond to 'SYN+' by queuing it on new socket. */ if (!msg_data_sz(msg)) { struct msghdr m = {NULL,}; advance_rx_queue(sk); send_packet(NULL, new_sock, &m, 0); } else { __skb_dequeue(&sk->sk_receive_queue); __skb_queue_head(&new_sk->sk_receive_queue, buf); } release_sock(new_sk); } exit: release_sock(sk); return res; }
static int accept(struct socket *sock, struct socket *newsock, int flags) { struct tipc_sock *tsock = tipc_sk(sock->sk); struct sk_buff *buf; int res = -EFAULT; if (sock->state == SS_READY) return -EOPNOTSUPP; if (sock->state != SS_LISTENING) return -EINVAL; if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && (flags & O_NONBLOCK))) return -EWOULDBLOCK; if (down_interruptible(&tsock->sem)) return -ERESTARTSYS; if (wait_event_interruptible(*sock->sk->sk_sleep, skb_queue_len(&sock->sk->sk_receive_queue))) { res = -ERESTARTSYS; goto exit; } buf = skb_peek(&sock->sk->sk_receive_queue); res = tipc_create(newsock, 0); if (!res) { struct tipc_sock *new_tsock = tipc_sk(newsock->sk); struct tipc_portid id; struct tipc_msg *msg = buf_msg(buf); u32 new_ref = new_tsock->p->ref; id.ref = msg_origport(msg); id.node = msg_orignode(msg); tipc_connect2port(new_ref, &id); newsock->state = SS_CONNECTED; tipc_set_portimportance(new_ref, msg_importance(msg)); if (msg_named(msg)) { new_tsock->p->conn_type = msg_nametype(msg); new_tsock->p->conn_instance = msg_nameinst(msg); } /* * Respond to 'SYN-' by discarding it & returning 'ACK'-. * Respond to 'SYN+' by queuing it on new socket. */ msg_dbg(msg,"<ACC<: "); if (!msg_data_sz(msg)) { struct msghdr m = {NULL,}; send_packet(NULL, newsock, &m, 0); advance_queue(tsock); } else { sock_lock(tsock); skb_dequeue(&sock->sk->sk_receive_queue); sock_unlock(tsock); skb_queue_head(&newsock->sk->sk_receive_queue, buf); } } exit: up(&tsock->sem); return res; }