* setsockopt(CCIDs-I-want/accept). -acme
*/
if (likely(ctl_sock_initialized)) {
- int rc = dccp_feat_init(sk);
+ int rc = dccp_feat_init(dmsk);
if (rc)
return rc;
int dccp_destroy_sock(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
+ struct dccp_minisock *dmsk = dccp_msk(sk);
/*
* DCCP doesn't use sk_write_queue, just sk_send_head
kfree(dp->dccps_service_list);
dp->dccps_service_list = NULL;
- if (dccp_msk(sk)->dccpms_send_ack_vector) {
+ if (dmsk->dccpms_send_ack_vector) {
dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
dp->dccps_hc_rx_ackvec = NULL;
}
dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
/* clean up feature negotiation state */
- dccp_feat_clean(sk);
+ dccp_feat_clean(dmsk);
return 0;
}
if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN)
- mask |= POLLIN | POLLRDNORM;
+ mask |= POLLIN | POLLRDNORM | POLLRDHUP;
/* Connected? */
if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
goto out_free_val;
}
- rc = dccp_feat_change(sk, type, opt.dccpsf_feat, val, opt.dccpsf_len,
- GFP_KERNEL);
+ rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
+ val, opt.dccpsf_len, GFP_KERNEL);
if (rc)
goto out_free_val;
void dccp_close(struct sock *sk, long timeout)
{
struct sk_buff *skb;
+ int state;
lock_sock(sk);
sk_stream_wait_close(sk, timeout);
adjudge_to_death:
+ state = sk->sk_state;
+ sock_hold(sk);
+ sock_orphan(sk);
+ atomic_inc(sk->sk_prot->orphan_count);
+
/*
* It is the last release_sock in its life. It will remove backlog.
*/
bh_lock_sock(sk);
BUG_TRAP(!sock_owned_by_user(sk));
- sock_hold(sk);
- sock_orphan(sk);
+ /* Have we already been destroyed by a softirq or backlog? */
+ if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
+ goto out;
/*
* The last release_sock may have processed the CLOSE or RESET
#endif
}
- atomic_inc(sk->sk_prot->orphan_count);
if (sk->sk_state == DCCP_CLOSED)
inet_csk_destroy_sock(sk);
/* Otherwise, socket is reprieved until protocol close. */
+out:
bh_unlock_sock(sk);
local_bh_enable();
sock_put(sk);