Commit 88f964db authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller

[DCCP]: Introduce CCID getsockopt for the CCIDs

Allocation for the optnames is similar to the DCCP options, with a
range for rx and tx half connection CCIDs.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 561713cf
......@@ -179,6 +179,8 @@ enum {
/* DCCP socket options */
#define DCCP_SOCKOPT_PACKET_SIZE 1
#define DCCP_SOCKOPT_SERVICE 2
#define DCCP_SOCKOPT_CCID_RX_INFO 128
#define DCCP_SOCKOPT_CCID_TX_INFO 192
#define DCCP_SERVICE_LIST_MAX_LEN 32
......
......@@ -14,6 +14,7 @@
*/
#include <net/sock.h>
#include <linux/compiler.h>
#include <linux/dccp.h>
#include <linux/list.h>
#include <linux/module.h>
......@@ -54,6 +55,14 @@ struct ccid {
struct tcp_info *info);
void (*ccid_hc_tx_get_info)(struct sock *sk,
struct tcp_info *info);
int (*ccid_hc_rx_getsockopt)(struct sock *sk,
const int optname, int len,
u32 __user *optval,
int __user *optlen);
int (*ccid_hc_tx_getsockopt)(struct sock *sk,
const int optname, int len,
u32 __user *optval,
int __user *optlen);
};
extern int ccid_register(struct ccid *ccid);
......@@ -177,4 +186,26 @@ static inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk,
if (ccid->ccid_hc_tx_get_info != NULL)
ccid->ccid_hc_tx_get_info(sk, info);
}
static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk,
const int optname, int len,
u32 __user *optval, int __user *optlen)
{
int rc = -ENOPROTOOPT;
if (ccid->ccid_hc_rx_getsockopt != NULL)
rc = ccid->ccid_hc_rx_getsockopt(sk, optname, len,
optval, optlen);
return rc;
}
static inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk,
const int optname, int len,
u32 __user *optval, int __user *optlen)
{
int rc = -ENOPROTOOPT;
if (ccid->ccid_hc_tx_getsockopt != NULL)
rc = ccid->ccid_hc_tx_getsockopt(sk, optname, len,
optval, optlen);
return rc;
}
#endif /* _CCID_H */
......@@ -1120,6 +1120,60 @@ static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
info->tcpi_rtt = hctx->ccid3hctx_rtt;
}
static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
u32 __user *optval, int __user *optlen)
{
const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
const void *val;
/* Listen socks doesn't have a private CCID block */
if (sk->sk_state == DCCP_LISTEN)
return -EINVAL;
switch (optname) {
case DCCP_SOCKOPT_CCID_RX_INFO:
if (len < sizeof(hcrx->ccid3hcrx_tfrc))
return -EINVAL;
len = sizeof(hcrx->ccid3hcrx_tfrc);
val = &hcrx->ccid3hcrx_tfrc;
break;
default:
return -ENOPROTOOPT;
}
if (put_user(len, optlen) || copy_to_user(optval, val, len))
return -EFAULT;
return 0;
}
static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
u32 __user *optval, int __user *optlen)
{
const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
const void *val;
/* Listen socks doesn't have a private CCID block */
if (sk->sk_state == DCCP_LISTEN)
return -EINVAL;
switch (optname) {
case DCCP_SOCKOPT_CCID_TX_INFO:
if (len < sizeof(hctx->ccid3hctx_tfrc))
return -EINVAL;
len = sizeof(hctx->ccid3hctx_tfrc);
val = &hctx->ccid3hctx_tfrc;
break;
default:
return -ENOPROTOOPT;
}
if (put_user(len, optlen) || copy_to_user(optval, val, len))
return -EFAULT;
return 0;
}
static struct ccid ccid3 = {
.ccid_id = 3,
.ccid_name = "ccid3",
......@@ -1139,6 +1193,8 @@ static struct ccid ccid3 = {
.ccid_hc_rx_packet_recv = ccid3_hc_rx_packet_recv,
.ccid_hc_rx_get_info = ccid3_hc_rx_get_info,
.ccid_hc_tx_get_info = ccid3_hc_tx_get_info,
.ccid_hc_rx_getsockopt = ccid3_hc_rx_getsockopt,
.ccid_hc_tx_getsockopt = ccid3_hc_tx_getsockopt,
};
module_param(ccid3_debug, int, 0444);
......
......@@ -325,12 +325,7 @@ 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)
if (len < sizeof(int))
return -EINVAL;
dp = dccp_sk(sk);
......@@ -338,7 +333,17 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
switch (optname) {
case DCCP_SOCKOPT_PACKET_SIZE:
val = dp->dccps_packet_size;
len = sizeof(dp->dccps_packet_size);
break;
case DCCP_SOCKOPT_SERVICE:
return dccp_getsockopt_service(sk, len,
(u32 __user *)optval, optlen);
case 128 ... 191:
return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
len, (u32 __user *)optval, optlen);
case 192 ... 255:
return ccid_hc_tx_getsockopt(dp->dccps_hc_tx_ccid, sk, optname,
len, (u32 __user *)optval, optlen);
default:
return -ENOPROTOOPT;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment