int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
{
struct dccp_sock *dp = dccp_sk(sk);
+ struct dccp_minisock *dmsk = dccp_msk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
- dccp_options_init(&dp->dccps_options);
+ dccp_minisock_init(&dp->dccps_minisock);
do_gettimeofday(&dp->dccps_epoch);
/*
* 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;
- if (dp->dccps_options.dccpo_send_ack_vector) {
+ if (dmsk->dccpms_send_ack_vector) {
dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
if (dp->dccps_hc_rx_ackvec == NULL)
return -ENOMEM;
}
- dp->dccps_hc_rx_ccid =
- ccid_hc_rx_new(dp->dccps_options.dccpo_rx_ccid,
- sk, GFP_KERNEL);
- dp->dccps_hc_tx_ccid =
- ccid_hc_tx_new(dp->dccps_options.dccpo_tx_ccid,
- sk, GFP_KERNEL);
+ dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
+ sk, GFP_KERNEL);
+ dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
+ sk, GFP_KERNEL);
if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
dp->dccps_hc_tx_ccid == NULL)) {
ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
- if (dp->dccps_options.dccpo_send_ack_vector) {
+ if (dmsk->dccpms_send_ack_vector) {
dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
dp->dccps_hc_rx_ackvec = NULL;
}
}
} else {
/* control socket doesn't need feat nego */
- INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
- INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
+ INIT_LIST_HEAD(&dmsk->dccpms_pending);
+ INIT_LIST_HEAD(&dmsk->dccpms_conf);
}
dccp_init_xmit_timers(sk);
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 (dp->dccps_options.dccpo_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;
optlen);
return do_dccp_setsockopt(sk, level, optname, optval, optlen);
}
+
EXPORT_SYMBOL_GPL(dccp_setsockopt);
#ifdef CONFIG_COMPAT
int compat_dccp_setsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int optlen)
+ char __user *optval, int optlen)
{
- if (level != SOL_DCCP) {
- if (inet_csk(sk)->icsk_af_ops->compat_setsockopt)
- return inet_csk(sk)->icsk_af_ops->compat_setsockopt(sk,
- level, optname, optval, optlen);
- else
- return inet_csk(sk)->icsk_af_ops->setsockopt(sk,
- level, optname, optval, optlen);
- }
+ if (level != SOL_DCCP)
+ return inet_csk_compat_setsockopt(sk, level, optname,
+ optval, optlen);
return do_dccp_setsockopt(sk, level, optname, optval, optlen);
}
+
EXPORT_SYMBOL_GPL(compat_dccp_setsockopt);
#endif
optlen);
return do_dccp_getsockopt(sk, level, optname, optval, optlen);
}
+
EXPORT_SYMBOL_GPL(dccp_getsockopt);
#ifdef CONFIG_COMPAT
int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen)
+ char __user *optval, int __user *optlen)
{
- if (level != SOL_DCCP) {
- if (inet_csk(sk)->icsk_af_ops->compat_setsockopt)
- return inet_csk(sk)->icsk_af_ops->compat_getsockopt(sk,
- level, optname, optval, optlen);
- else
- return inet_csk(sk)->icsk_af_ops->getsockopt(sk,
- level, optname, optval, optlen);
- }
+ if (level != SOL_DCCP)
+ return inet_csk_compat_getsockopt(sk, level, optname,
+ optval, optlen);
return do_dccp_getsockopt(sk, level, optname, optval, optlen);
}
+
EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
#endif
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);