This reverts "Merge branch 'dccp' of git://eden-feed.erg.abdn.ac.uk/dccp_exp"
as it accentally contained the wrong set of patches. These will be submitted separately. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
This commit is contained in:
285
net/dccp/proto.c
285
net/dccp/proto.c
@ -67,9 +67,6 @@ void dccp_set_state(struct sock *sk, const int state)
|
||||
case DCCP_OPEN:
|
||||
if (oldstate != DCCP_OPEN)
|
||||
DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
|
||||
/* Client retransmits all Confirm options until entering OPEN */
|
||||
if (oldstate == DCCP_PARTOPEN)
|
||||
dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
|
||||
break;
|
||||
|
||||
case DCCP_CLOSED:
|
||||
@ -178,25 +175,63 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
|
||||
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_minisock_init(&dp->dccps_minisock);
|
||||
|
||||
icsk->icsk_rto = DCCP_TIMEOUT_INIT;
|
||||
icsk->icsk_syn_retries = sysctl_dccp_request_retries;
|
||||
sk->sk_state = DCCP_CLOSED;
|
||||
sk->sk_write_space = dccp_write_space;
|
||||
icsk->icsk_sync_mss = dccp_sync_mss;
|
||||
dp->dccps_mss_cache = TCP_MIN_RCVMSS;
|
||||
dp->dccps_mss_cache = 536;
|
||||
dp->dccps_rate_last = jiffies;
|
||||
dp->dccps_role = DCCP_ROLE_UNDEFINED;
|
||||
dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
|
||||
dp->dccps_tx_qlen = sysctl_dccp_tx_qlen;
|
||||
dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
|
||||
|
||||
dccp_init_xmit_timers(sk);
|
||||
|
||||
INIT_LIST_HEAD(&dp->dccps_featneg);
|
||||
/* control socket doesn't need feat nego */
|
||||
if (likely(ctl_sock_initialized))
|
||||
return dccp_feat_init(sk);
|
||||
/*
|
||||
* FIXME: We're hardcoding the CCID, and doing this at this point makes
|
||||
* the listening (master) sock get CCID control blocks, which is not
|
||||
* necessary, but for now, to not mess with the test userspace apps,
|
||||
* lets leave it here, later the real solution is to do this in a
|
||||
* setsockopt(CCIDs-I-want/accept). -acme
|
||||
*/
|
||||
if (likely(ctl_sock_initialized)) {
|
||||
int rc = dccp_feat_init(dmsk);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
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(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 (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;
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
/* control socket doesn't need feat nego */
|
||||
INIT_LIST_HEAD(&dmsk->dccpms_pending);
|
||||
INIT_LIST_HEAD(&dmsk->dccpms_conf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -205,6 +240,7 @@ EXPORT_SYMBOL_GPL(dccp_init_sock);
|
||||
void 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
|
||||
@ -222,7 +258,7 @@ void dccp_destroy_sock(struct sock *sk)
|
||||
kfree(dp->dccps_service_list);
|
||||
dp->dccps_service_list = NULL;
|
||||
|
||||
if (dp->dccps_hc_rx_ackvec != NULL) {
|
||||
if (dmsk->dccpms_send_ack_vector) {
|
||||
dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
|
||||
dp->dccps_hc_rx_ackvec = NULL;
|
||||
}
|
||||
@ -231,7 +267,7 @@ void dccp_destroy_sock(struct sock *sk)
|
||||
dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
|
||||
|
||||
/* clean up feature negotiation state */
|
||||
dccp_feat_list_purge(&dp->dccps_featneg);
|
||||
dccp_feat_clean(dmsk);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(dccp_destroy_sock);
|
||||
@ -241,9 +277,6 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
|
||||
struct dccp_sock *dp = dccp_sk(sk);
|
||||
|
||||
dp->dccps_role = DCCP_ROLE_LISTEN;
|
||||
/* do not start to listen if feature negotiation setup fails */
|
||||
if (dccp_feat_finalise_settings(dp))
|
||||
return -EPROTO;
|
||||
return inet_csk_listen_start(sk, backlog);
|
||||
}
|
||||
|
||||
@ -433,70 +466,42 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
|
||||
{
|
||||
u8 *list, len;
|
||||
int i, rc;
|
||||
|
||||
if (cscov < 0 || cscov > 15)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Populate a list of permissible values, in the range cscov...15. This
|
||||
* is necessary since feature negotiation of single values only works if
|
||||
* both sides incidentally choose the same value. Since the list starts
|
||||
* lowest-value first, negotiation will pick the smallest shared value.
|
||||
*/
|
||||
if (cscov == 0)
|
||||
return 0;
|
||||
len = 16 - cscov;
|
||||
|
||||
list = kmalloc(len, GFP_KERNEL);
|
||||
if (list == NULL)
|
||||
return -ENOBUFS;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
list[i] = cscov++;
|
||||
|
||||
rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
|
||||
|
||||
if (rc == 0) {
|
||||
if (rx)
|
||||
dccp_sk(sk)->dccps_pcrlen = cscov;
|
||||
else
|
||||
dccp_sk(sk)->dccps_pcslen = cscov;
|
||||
}
|
||||
kfree(list);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dccp_setsockopt_ccid(struct sock *sk, int type,
|
||||
char __user *optval, int optlen)
|
||||
/* byte 1 is feature. the rest is the preference list */
|
||||
static int dccp_setsockopt_change(struct sock *sk, int type,
|
||||
struct dccp_so_feat __user *optval)
|
||||
{
|
||||
struct dccp_so_feat opt;
|
||||
u8 *val;
|
||||
int rc = 0;
|
||||
int rc;
|
||||
|
||||
if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
|
||||
if (copy_from_user(&opt, optval, sizeof(opt)))
|
||||
return -EFAULT;
|
||||
/*
|
||||
* rfc4340: 6.1. Change Options
|
||||
*/
|
||||
if (opt.dccpsf_len < 1)
|
||||
return -EINVAL;
|
||||
|
||||
val = kmalloc(optlen, GFP_KERNEL);
|
||||
if (val == NULL)
|
||||
val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
|
||||
if (!val)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(val, optval, optlen)) {
|
||||
kfree(val);
|
||||
return -EFAULT;
|
||||
if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
|
||||
rc = -EFAULT;
|
||||
goto out_free_val;
|
||||
}
|
||||
|
||||
lock_sock(sk);
|
||||
if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
|
||||
rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
|
||||
rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
|
||||
val, opt.dccpsf_len, GFP_KERNEL);
|
||||
if (rc)
|
||||
goto out_free_val;
|
||||
|
||||
if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
|
||||
rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
|
||||
release_sock(sk);
|
||||
|
||||
kfree(val);
|
||||
out:
|
||||
return rc;
|
||||
|
||||
out_free_val:
|
||||
kfree(val);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
|
||||
@ -505,21 +510,7 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
|
||||
struct dccp_sock *dp = dccp_sk(sk);
|
||||
int val, err = 0;
|
||||
|
||||
switch (optname) {
|
||||
case DCCP_SOCKOPT_PACKET_SIZE:
|
||||
DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
|
||||
return 0;
|
||||
case DCCP_SOCKOPT_CHANGE_L:
|
||||
case DCCP_SOCKOPT_CHANGE_R:
|
||||
DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
|
||||
return 0;
|
||||
case DCCP_SOCKOPT_CCID:
|
||||
case DCCP_SOCKOPT_RX_CCID:
|
||||
case DCCP_SOCKOPT_TX_CCID:
|
||||
return dccp_setsockopt_ccid(sk, optname, optval, optlen);
|
||||
}
|
||||
|
||||
if (optlen < (int)sizeof(int))
|
||||
if (optlen < sizeof(int))
|
||||
return -EINVAL;
|
||||
|
||||
if (get_user(val, (int __user *)optval))
|
||||
@ -530,38 +521,53 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
|
||||
|
||||
lock_sock(sk);
|
||||
switch (optname) {
|
||||
case DCCP_SOCKOPT_PACKET_SIZE:
|
||||
DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
|
||||
err = 0;
|
||||
break;
|
||||
case DCCP_SOCKOPT_CHANGE_L:
|
||||
if (optlen != sizeof(struct dccp_so_feat))
|
||||
err = -EINVAL;
|
||||
else
|
||||
err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
|
||||
(struct dccp_so_feat __user *)
|
||||
optval);
|
||||
break;
|
||||
case DCCP_SOCKOPT_CHANGE_R:
|
||||
if (optlen != sizeof(struct dccp_so_feat))
|
||||
err = -EINVAL;
|
||||
else
|
||||
err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
|
||||
(struct dccp_so_feat __user *)
|
||||
optval);
|
||||
break;
|
||||
case DCCP_SOCKOPT_SERVER_TIMEWAIT:
|
||||
if (dp->dccps_role != DCCP_ROLE_SERVER)
|
||||
err = -EOPNOTSUPP;
|
||||
else
|
||||
dp->dccps_server_timewait = (val != 0);
|
||||
break;
|
||||
case DCCP_SOCKOPT_SEND_CSCOV:
|
||||
err = dccp_setsockopt_cscov(sk, val, false);
|
||||
break;
|
||||
case DCCP_SOCKOPT_RECV_CSCOV:
|
||||
err = dccp_setsockopt_cscov(sk, val, true);
|
||||
break;
|
||||
case DCCP_SOCKOPT_QPOLICY_ID:
|
||||
if (sk->sk_state != DCCP_CLOSED)
|
||||
err = -EISCONN;
|
||||
else if (val < 0 || val >= DCCPQ_POLICY_MAX)
|
||||
case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */
|
||||
if (val < 0 || val > 15)
|
||||
err = -EINVAL;
|
||||
else
|
||||
dp->dccps_qpolicy = val;
|
||||
dp->dccps_pcslen = val;
|
||||
break;
|
||||
case DCCP_SOCKOPT_QPOLICY_TXQLEN:
|
||||
if (val < 0)
|
||||
case DCCP_SOCKOPT_RECV_CSCOV: /* receiver side, RFC 4340 sec. 9.2.1 */
|
||||
if (val < 0 || val > 15)
|
||||
err = -EINVAL;
|
||||
else
|
||||
dp->dccps_tx_qlen = val;
|
||||
else {
|
||||
dp->dccps_pcrlen = val;
|
||||
/* FIXME: add feature negotiation,
|
||||
* ChangeL(MinimumChecksumCoverage, val) */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
err = -ENOPROTOOPT;
|
||||
break;
|
||||
}
|
||||
release_sock(sk);
|
||||
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -642,18 +648,6 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
|
||||
case DCCP_SOCKOPT_GET_CUR_MPS:
|
||||
val = dp->dccps_mss_cache;
|
||||
break;
|
||||
case DCCP_SOCKOPT_AVAILABLE_CCIDS:
|
||||
return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
|
||||
case DCCP_SOCKOPT_TX_CCID:
|
||||
val = ccid_get_current_tx_ccid(dp);
|
||||
if (val < 0)
|
||||
return -ENOPROTOOPT;
|
||||
break;
|
||||
case DCCP_SOCKOPT_RX_CCID:
|
||||
val = ccid_get_current_rx_ccid(dp);
|
||||
if (val < 0)
|
||||
return -ENOPROTOOPT;
|
||||
break;
|
||||
case DCCP_SOCKOPT_SERVER_TIMEWAIT:
|
||||
val = dp->dccps_server_timewait;
|
||||
break;
|
||||
@ -663,12 +657,6 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
|
||||
case DCCP_SOCKOPT_RECV_CSCOV:
|
||||
val = dp->dccps_pcrlen;
|
||||
break;
|
||||
case DCCP_SOCKOPT_QPOLICY_ID:
|
||||
val = dp->dccps_qpolicy;
|
||||
break;
|
||||
case DCCP_SOCKOPT_QPOLICY_TXQLEN:
|
||||
val = dp->dccps_tx_qlen;
|
||||
break;
|
||||
case 128 ... 191:
|
||||
return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
|
||||
len, (u32 __user *)optval, optlen);
|
||||
@ -711,47 +699,6 @@ int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
|
||||
EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
|
||||
#endif
|
||||
|
||||
static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb)
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
|
||||
|
||||
/*
|
||||
* Assign an (opaque) qpolicy priority value to skb->priority.
|
||||
*
|
||||
* We are overloading this skb field for use with the qpolicy subystem.
|
||||
* The skb->priority is normally used for the SO_PRIORITY option, which
|
||||
* is initialised from sk_priority. Since the assignment of sk_priority
|
||||
* to skb->priority happens later (on layer 3), we overload this field
|
||||
* for use with queueing priorities as long as the skb is on layer 4.
|
||||
* The default priority value (if nothing is set) is 0.
|
||||
*/
|
||||
skb->priority = 0;
|
||||
|
||||
for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
|
||||
if (!CMSG_OK(msg, cmsg))
|
||||
return -EINVAL;
|
||||
|
||||
if (cmsg->cmsg_level != SOL_DCCP)
|
||||
continue;
|
||||
|
||||
if (cmsg->cmsg_type <= DCCP_SCM_QPOLICY_MAX &&
|
||||
!dccp_qpolicy_param_ok(skb->sk, cmsg->cmsg_type))
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmsg->cmsg_type) {
|
||||
case DCCP_SCM_PRIORITY:
|
||||
if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32)))
|
||||
return -EINVAL;
|
||||
skb->priority = *(__u32 *)CMSG_DATA(cmsg);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
size_t len)
|
||||
{
|
||||
@ -767,7 +714,8 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (dccp_qpolicy_full(sk)) {
|
||||
if (sysctl_dccp_tx_qlen &&
|
||||
(sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) {
|
||||
rc = -EAGAIN;
|
||||
goto out_release;
|
||||
}
|
||||
@ -795,12 +743,8 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
if (rc != 0)
|
||||
goto out_discard;
|
||||
|
||||
rc = dccp_msghdr_parse(msg, skb);
|
||||
if (rc != 0)
|
||||
goto out_discard;
|
||||
|
||||
dccp_qpolicy_push(sk, skb);
|
||||
dccp_write_xmit(sk);
|
||||
skb_queue_tail(&sk->sk_write_queue, skb);
|
||||
dccp_write_xmit(sk,0);
|
||||
out_release:
|
||||
release_sock(sk);
|
||||
return rc ? : len;
|
||||
@ -1023,22 +967,9 @@ void dccp_close(struct sock *sk, long timeout)
|
||||
/* Check zero linger _after_ checking for unread data. */
|
||||
sk->sk_prot->disconnect(sk, 0);
|
||||
} else if (sk->sk_state != DCCP_CLOSED) {
|
||||
/*
|
||||
* Normal connection termination. May need to wait if there are
|
||||
* still packets in the TX queue that are delayed by the CCID.
|
||||
*/
|
||||
dccp_flush_write_queue(sk, &timeout);
|
||||
dccp_terminate_connection(sk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush write queue. This may be necessary in several cases:
|
||||
* - we have been closed by the peer but still have application data;
|
||||
* - abortive termination (unread data or zero linger time),
|
||||
* - normal termination but queue could not be flushed within time limit
|
||||
*/
|
||||
__skb_queue_purge(&sk->sk_write_queue);
|
||||
|
||||
sk_stream_wait_close(sk, timeout);
|
||||
|
||||
adjudge_to_death:
|
||||
|
Reference in New Issue
Block a user