forked from Minki/linux
[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: Arnaldo Carvalho de Melo <acme@mandriva.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
561713cf47
commit
88f964db6e
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user