[DCCP]: Introduce DCCP_SOCKOPT_SERVICE
As discussed in the dccp@vger mailing list: Now applications have to use setsockopt(DCCP_SOCKOPT_SERVICE, service[s]), prior to calling listen() and connect(). An array of unsigned ints can be passed meaning that the listening sock accepts connection requests for several services. With this we can ditch struct sockaddr_dccp and use only sockaddr_in (and sockaddr_in6 in the future). Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
0c10c5d968
commit
67e6b62921
@@ -94,7 +94,15 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
|
||||
|
||||
static inline int dccp_listen_start(struct sock *sk)
|
||||
{
|
||||
dccp_sk(sk)->dccps_role = DCCP_ROLE_LISTEN;
|
||||
struct dccp_sock *dp = dccp_sk(sk);
|
||||
|
||||
dp->dccps_role = DCCP_ROLE_LISTEN;
|
||||
/*
|
||||
* Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE)
|
||||
* before calling listen()
|
||||
*/
|
||||
if (dccp_service_not_initialized(sk))
|
||||
return -EPROTO;
|
||||
return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
|
||||
}
|
||||
|
||||
@@ -202,6 +210,42 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static int dccp_setsockopt_service(struct sock *sk, const u32 service,
|
||||
char __user *optval, int optlen)
|
||||
{
|
||||
struct dccp_sock *dp = dccp_sk(sk);
|
||||
struct dccp_service_list *sl = NULL;
|
||||
|
||||
if (service == DCCP_SERVICE_INVALID_VALUE ||
|
||||
optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
|
||||
return -EINVAL;
|
||||
|
||||
if (optlen > sizeof(service)) {
|
||||
sl = kmalloc(optlen, GFP_KERNEL);
|
||||
if (sl == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
sl->dccpsl_nr = optlen / sizeof(u32) - 1;
|
||||
if (copy_from_user(sl->dccpsl_list,
|
||||
optval + sizeof(service),
|
||||
optlen - sizeof(service)) ||
|
||||
dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
|
||||
kfree(sl);
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
lock_sock(sk);
|
||||
dp->dccps_service = service;
|
||||
|
||||
if (dp->dccps_service_list != NULL)
|
||||
kfree(dp->dccps_service_list);
|
||||
|
||||
dp->dccps_service_list = sl;
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dccp_setsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int optlen)
|
||||
{
|
||||
@@ -218,8 +262,10 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
|
||||
if (get_user(val, (int __user *)optval))
|
||||
return -EFAULT;
|
||||
|
||||
lock_sock(sk);
|
||||
if (optname == DCCP_SOCKOPT_SERVICE)
|
||||
return dccp_setsockopt_service(sk, val, optval, optlen);
|
||||
|
||||
lock_sock(sk);
|
||||
dp = dccp_sk(sk);
|
||||
err = 0;
|
||||
|
||||
@@ -236,6 +282,37 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dccp_getsockopt_service(struct sock *sk, int len,
|
||||
u32 __user *optval,
|
||||
int __user *optlen)
|
||||
{
|
||||
const struct dccp_sock *dp = dccp_sk(sk);
|
||||
const struct dccp_service_list *sl;
|
||||
int err = -ENOENT, slen = 0, total_len = sizeof(u32);
|
||||
|
||||
lock_sock(sk);
|
||||
if (dccp_service_not_initialized(sk))
|
||||
goto out;
|
||||
|
||||
if ((sl = dp->dccps_service_list) != NULL) {
|
||||
slen = sl->dccpsl_nr * sizeof(u32);
|
||||
total_len += slen;
|
||||
}
|
||||
|
||||
err = -EINVAL;
|
||||
if (total_len > len)
|
||||
goto out;
|
||||
|
||||
err = 0;
|
||||
if (put_user(total_len, optlen) ||
|
||||
put_user(dp->dccps_service, optval) ||
|
||||
(sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen)))
|
||||
err = -EFAULT;
|
||||
out:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
int dccp_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
@@ -248,6 +325,10 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
if (optname == DCCP_SOCKOPT_SERVICE)
|
||||
return dccp_getsockopt_service(sk, len,
|
||||
(u32 __user *)optval, optlen);
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(int));
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
|
Reference in New Issue
Block a user