static int shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); struct sk_buff *buf; int res; if (how != SHUT_RDWR) return -EINVAL; lock_sock(sk); switch (sock->state) { case SS_CONNECTING: case SS_CONNECTED: /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ restart: buf = __skb_dequeue(&sk->sk_receive_queue); if (buf) { atomic_dec(&tipc_queue_size); if (TIPC_SKB_CB(buf)->handle != 0) { kfree_skb(buf); goto restart; } tipc_disconnect(tport->ref); tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN); } else { tipc_shutdown(tport->ref); } sock->state = SS_DISCONNECTING; /* fall through */ case SS_DISCONNECTING: /* Discard any unreceived messages; wake up sleeping tasks */ discard_rx_queue(sk); if (waitqueue_active(sk_sleep(sk))) wake_up_interruptible(sk_sleep(sk)); res = 0; break; default: res = -ENOTCONN; } release_sock(sk); return res; }
/** * shutdown - shutdown socket connection * @sock: socket structure * @how: direction to close (must be SHUT_RDWR) * * Terminates connection (if necessary), then purges socket's receive queue. * * Returns 0 on success, errno otherwise */ static int shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); struct sk_buff *buf; int res; if (how != SHUT_RDWR) return -EINVAL; lock_sock(sk); switch (sock->state) { case SS_CONNECTING: case SS_CONNECTED: restart: /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ buf = __skb_dequeue(&sk->sk_receive_queue); if (buf) { if (TIPC_SKB_CB(buf)->handle != 0) { kfree_skb(buf); goto restart; } tipc_disconnect(tport->ref); tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN); } else { tipc_shutdown(tport->ref); } sock->state = SS_DISCONNECTING; /* fall through */ case SS_DISCONNECTING: /* Discard any unreceived messages */ __skb_queue_purge(&sk->sk_receive_queue); /* Wake up anyone sleeping in poll */ sk->sk_state_change(sk); res = 0; break; default: res = -ENOTCONN; } release_sock(sk); return res; }
static int shutdown(struct socket *sock, int how) { struct tipc_sock* tsock = tipc_sk(sock->sk); struct sk_buff *buf; int res; /* Could return -EINVAL for an invalid "how", but why bother? */ if (down_interruptible(&tsock->sem)) return -ERESTARTSYS; sock_lock(tsock); switch (sock->state) { case SS_CONNECTED: /* Send 'FIN+' or 'FIN-' message to peer */ sock_unlock(tsock); restart: if ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) { atomic_dec(&tipc_queue_size); if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) { buf_discard(buf); goto restart; } tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN); } else { tipc_shutdown(tsock->p->ref); } sock_lock(tsock); /* fall through */ case SS_DISCONNECTING: /* Discard any unreceived messages */ while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) { atomic_dec(&tipc_queue_size); buf_discard(buf); } tsock->p->conn_unacked = 0; /* fall through */ case SS_CONNECTING: sock->state = SS_DISCONNECTING; res = 0; break; default: res = -ENOTCONN; } sock_unlock(tsock); up(&tsock->sem); return res; }