[NET]: {get|set}sockopt compatibility layer

This patch extends {get|set}sockopt compatibility layer in order to
move protocol specific parts to their place and avoid huge universal
net/compat.c file in the future.

Signed-off-by: Dmitry Mishin <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
Dmitry Mishin 2006-03-20 22:45:21 -08:00 • committed by David S. Miller
commit 3fdadf7d27
29 changed files with 928 additions and 139 deletions

View file

@ -802,6 +802,10 @@ const struct proto_ops inet_stream_ops = {
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
.getsockopt = sock_common_getsockopt,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt,
.compat_getsockopt = compat_sock_common_getsockopt,
#endif
.sendmsg = inet_sendmsg,
.recvmsg = sock_common_recvmsg,
.mmap = sock_no_mmap,
@ -823,6 +827,10 @@ const struct proto_ops inet_dgram_ops = {
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
.getsockopt = sock_common_getsockopt,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt,
.compat_getsockopt = compat_sock_common_getsockopt,
#endif
.sendmsg = inet_sendmsg,
.recvmsg = sock_common_recvmsg,
.mmap = sock_no_mmap,
@ -848,6 +856,10 @@ static const struct proto_ops inet_sockraw_ops = {
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
.getsockopt = sock_common_getsockopt,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt,
.compat_getsockopt = compat_sock_common_getsockopt,
#endif
.sendmsg = inet_sendmsg,
.recvmsg = sock_common_recvmsg,
.mmap = sock_no_mmap,

View file

@ -399,14 +399,12 @@ out:
* an IP socket.
*/
int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen)
static int do_ip_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, int optlen)
{
struct inet_sock *inet = inet_sk(sk);
int val=0,err;
if (level != SOL_IP)
return -ENOPROTOOPT;
if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) |
(1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
(1<<IP_RETOPTS) | (1<<IP_TOS) |
@ -875,12 +873,7 @@ mc_msf_out:
break;
default:
#ifdef CONFIG_NETFILTER
err = nf_setsockopt(sk, PF_INET, optname, optval,
optlen);
#else
err = -ENOPROTOOPT;
#endif
break;
}
release_sock(sk);
@ -891,12 +884,66 @@ e_inval:
return -EINVAL;
}
int ip_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, int optlen)
{
int err;
if (level != SOL_IP)
return -ENOPROTOOPT;
err = do_ip_setsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY
#ifdef CONFIG_IP_MROUTE
&& (optname < MRT_BASE || optname > (MRT_BASE + 10))
#endif
) {
lock_sock(sk);
err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
release_sock(sk);
}
#endif
return err;
}
#ifdef CONFIG_COMPAT
int compat_ip_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, int optlen)
{
int err;
if (level != SOL_IP)
return -ENOPROTOOPT;
err = do_ip_setsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY
#ifdef CONFIG_IP_MROUTE
&& (optname < MRT_BASE || optname > (MRT_BASE + 10))
#endif
) {
lock_sock(sk);
err = compat_nf_setsockopt(sk, PF_INET,
optname, optval, optlen);
release_sock(sk);
}
#endif
return err;
}
#endif
/*
* Get the options. Note for future reference. The GET of IP options gets the
* _received_ ones. The set sets the _sent_ ones.
*/
int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen)
static int do_ip_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
struct inet_sock *inet = inet_sk(sk);
int val;
@ -1080,17 +1127,8 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
val = inet->freebind;
break;
default:
#ifdef CONFIG_NETFILTER
val = nf_getsockopt(sk, PF_INET, optname, optval,
&len);
release_sock(sk);
if (val >= 0)
val = put_user(len, optlen);
return val;
#else
release_sock(sk);
return -ENOPROTOOPT;
#endif
}
release_sock(sk);
@ -1111,7 +1149,73 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
return 0;
}
int ip_getsockopt(struct sock *sk, int level,
int optname, char __user *optval, int __user *optlen)
{
int err;
err = do_ip_getsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS
#ifdef CONFIG_IP_MROUTE
&& (optname < MRT_BASE || optname > MRT_BASE+10)
#endif
) {
int len;
if(get_user(len,optlen))
return -EFAULT;
lock_sock(sk);
err = nf_getsockopt(sk, PF_INET, optname, optval,
&len);
release_sock(sk);
if (err >= 0)
err = put_user(len, optlen);
return err;
}
#endif
return err;
}
#ifdef CONFIG_COMPAT
int compat_ip_getsockopt(struct sock *sk, int level,
int optname, char __user *optval, int __user *optlen)
{
int err;
err = do_ip_getsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS
#ifdef CONFIG_IP_MROUTE
&& (optname < MRT_BASE || optname > MRT_BASE+10)
#endif
) {
int len;
if(get_user(len,optlen))
return -EFAULT;
lock_sock(sk);
err = compat_nf_getsockopt(sk, PF_INET,
optname, optval, &len);
release_sock(sk);
if (err >= 0)
err = put_user(len, optlen);
return err;
}
#endif
return err;
}
#endif
EXPORT_SYMBOL(ip_cmsg_recv);
EXPORT_SYMBOL(ip_getsockopt);
EXPORT_SYMBOL(ip_setsockopt);
#ifdef CONFIG_COMPAT
EXPORT_SYMBOL(compat_ip_getsockopt);
EXPORT_SYMBOL(compat_ip_setsockopt);
#endif

View file

@ -660,12 +660,9 @@ static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *o
out: return ret;
}
static int raw_setsockopt(struct sock *sk, int level, int optname,
static int do_raw_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
{
if (level != SOL_RAW)
return ip_setsockopt(sk, level, optname, optval, optlen);
if (optname == ICMP_FILTER) {
if (inet_sk(sk)->num != IPPROTO_ICMP)
return -EOPNOTSUPP;
@ -675,12 +672,28 @@ static int raw_setsockopt(struct sock *sk, int level, int optname,
return -ENOPROTOOPT;
}
static int raw_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
static int raw_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
{
if (level != SOL_RAW)
return ip_getsockopt(sk, level, optname, optval, optlen);
return ip_setsockopt(sk, level, optname, optval, optlen);
return do_raw_setsockopt(sk, level, optname, optval, optlen);
}
#ifdef CONFIG_COMPAT
static int compat_raw_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
{
if (level != SOL_RAW)
return compat_ip_setsockopt(sk, level,
optname, optval, optlen);
return do_raw_setsockopt(sk, level, optname, optval, optlen);
}
#endif
static int do_raw_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
if (optname == ICMP_FILTER) {
if (inet_sk(sk)->num != IPPROTO_ICMP)
return -EOPNOTSUPP;
@ -690,6 +703,25 @@ static int raw_getsockopt(struct sock *sk, int level, int optname,
return -ENOPROTOOPT;
}
static int raw_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
if (level != SOL_RAW)
return ip_getsockopt(sk, level, optname, optval, optlen);
return do_raw_getsockopt(sk, level, optname, optval, optlen);
}
#ifdef CONFIG_COMPAT
static int compat_raw_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
if (level != SOL_RAW)
return compat_ip_getsockopt(sk, level,
optname, optval, optlen);
return do_raw_getsockopt(sk, level, optname, optval, optlen);
}
#endif
static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
switch (cmd) {
@ -728,6 +760,10 @@ struct proto raw_prot = {
.init = raw_init,
.setsockopt = raw_setsockopt,
.getsockopt = raw_getsockopt,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_raw_setsockopt,
.compat_getsockopt = compat_raw_getsockopt,
#endif
.sendmsg = raw_sendmsg,
.recvmsg = raw_recvmsg,
.bind = raw_bind,

View file

@ -1687,18 +1687,14 @@ int tcp_disconnect(struct sock *sk, int flags)
/*
* Socket option code for TCP.
*/
int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
int optlen)
static int do_tcp_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, int optlen)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
int val;
int err = 0;
if (level != SOL_TCP)
return icsk->icsk_af_ops->setsockopt(sk, level, optname,
optval, optlen);
/* This is a string value all the others are int's */
if (optname == TCP_CONGESTION) {
char name[TCP_CA_NAME_MAX];
@ -1871,6 +1867,35 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
return err;
}
int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
int optlen)
{
struct inet_connection_sock *icsk = inet_csk(sk);
if (level != SOL_TCP)
return icsk->icsk_af_ops->setsockopt(sk, level, optname,
optval, optlen);
return do_tcp_setsockopt(sk, level, optname, optval, optlen);
}
#ifdef CONFIG_COMPAT
int compat_tcp_setsockopt(struct sock *sk, int level,
int optname, char __user *optval, int optlen)
{
struct inet_connection_sock *icsk = inet_csk(sk);
if (level != SOL_TCP) {
if (icsk->icsk_af_ops->compat_setsockopt)
return icsk->icsk_af_ops->compat_setsockopt(sk,
level, optname, optval, optlen);
else
return icsk->icsk_af_ops->setsockopt(sk,
level, optname, optval, optlen);
}
return do_tcp_setsockopt(sk, level, optname, optval, optlen);
}
#endif
/* Return information about state of tcp endpoint in API format. */
void tcp_get_info(struct sock *sk, struct tcp_info *info)
{
@ -1931,17 +1956,13 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
EXPORT_SYMBOL_GPL(tcp_get_info);
int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
int __user *optlen)
static int do_tcp_getsockopt(struct sock *sk, int level,
int optname, char __user *optval, int __user *optlen)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
int val, len;
if (level != SOL_TCP)
return icsk->icsk_af_ops->getsockopt(sk, level, optname,
optval, optlen);
if (get_user(len, optlen))
return -EFAULT;
@ -2025,6 +2046,34 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
return 0;
}
int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
int __user *optlen)
{
struct inet_connection_sock *icsk = inet_csk(sk);
if (level != SOL_TCP)
return icsk->icsk_af_ops->getsockopt(sk, level, optname,
optval, optlen);
return do_tcp_getsockopt(sk, level, optname, optval, optlen);
}
#ifdef CONFIG_COMPAT
int compat_tcp_getsockopt(struct sock *sk, int level,
int optname, char __user *optval, int __user *optlen)
{
struct inet_connection_sock *icsk = inet_csk(sk);
if (level != SOL_TCP) {
if (icsk->icsk_af_ops->compat_getsockopt)
return icsk->icsk_af_ops->compat_getsockopt(sk,
level, optname, optval, optlen);
else
return icsk->icsk_af_ops->getsockopt(sk,
level, optname, optval, optlen);
}
return do_tcp_getsockopt(sk, level, optname, optval, optlen);
}
#endif
extern void __skb_cb_too_small_for_tcp(int, int);
extern struct tcp_congestion_ops tcp_reno;
@ -2142,3 +2191,7 @@ EXPORT_SYMBOL(tcp_sendpage);
EXPORT_SYMBOL(tcp_setsockopt);
EXPORT_SYMBOL(tcp_shutdown);
EXPORT_SYMBOL(tcp_statistics);
#ifdef CONFIG_COMPAT
EXPORT_SYMBOL(compat_tcp_setsockopt);
EXPORT_SYMBOL(compat_tcp_getsockopt);
#endif

View file

@ -1226,6 +1226,10 @@ struct inet_connection_sock_af_ops ipv4_specific = {
.net_header_len = sizeof(struct iphdr),
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ip_setsockopt,
.compat_getsockopt = compat_ip_getsockopt,
#endif
.addr2sockaddr = inet_csk_addr2sockaddr,
.sockaddr_len = sizeof(struct sockaddr_in),
};
@ -1808,6 +1812,10 @@ struct proto tcp_prot = {
.shutdown = tcp_shutdown,
.setsockopt = tcp_setsockopt,
.getsockopt = tcp_getsockopt,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_tcp_setsockopt,
.compat_getsockopt = compat_tcp_getsockopt,
#endif
.sendmsg = tcp_sendmsg,
.recvmsg = tcp_recvmsg,
.backlog_rcv = tcp_v4_do_rcv,

View file

@ -1207,16 +1207,13 @@ static int udp_destroy_sock(struct sock *sk)
/*
* Socket option code for UDP
*/
static int udp_setsockopt(struct sock *sk, int level, int optname,
static int do_udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
{
struct udp_sock *up = udp_sk(sk);
int val;
int err = 0;
if (level != SOL_UDP)
return ip_setsockopt(sk, level, optname, optval, optlen);
if(optlen<sizeof(int))
return -EINVAL;
@ -1256,15 +1253,31 @@ static int udp_setsockopt(struct sock *sk, int level, int optname,
return err;
}
static int udp_getsockopt(struct sock *sk, int level, int optname,
static int udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
{
if (level != SOL_UDP)
return ip_setsockopt(sk, level, optname, optval, optlen);
return do_udp_setsockopt(sk, level, optname, optval, optlen);
}
#ifdef CONFIG_COMPAT
static int compat_udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen)
{
if (level != SOL_UDP)
return compat_ip_setsockopt(sk, level,
optname, optval, optlen);
return do_udp_setsockopt(sk, level, optname, optval, optlen);
}
#endif
static int do_udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
struct udp_sock *up = udp_sk(sk);
int val, len;
if (level != SOL_UDP)
return ip_getsockopt(sk, level, optname, optval, optlen);
if(get_user(len,optlen))
return -EFAULT;
@ -1293,6 +1306,24 @@ static int udp_getsockopt(struct sock *sk, int level, int optname,
return 0;
}
static int udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
if (level != SOL_UDP)
return ip_getsockopt(sk, level, optname, optval, optlen);
return do_udp_getsockopt(sk, level, optname, optval, optlen);
}
#ifdef CONFIG_COMPAT
static int compat_udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
if (level != SOL_UDP)
return compat_ip_getsockopt(sk, level,
optname, optval, optlen);
return do_udp_getsockopt(sk, level, optname, optval, optlen);
}
#endif
/**
* udp_poll - wait for a UDP event.
* @file - file struct
@ -1350,6 +1381,10 @@ struct proto udp_prot = {
.destroy = udp_destroy_sock,
.setsockopt = udp_setsockopt,
.getsockopt = udp_getsockopt,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_udp_setsockopt,
.compat_getsockopt = compat_udp_getsockopt,
#endif
.sendmsg = udp_sendmsg,
.recvmsg = udp_recvmsg,
.sendpage = udp_sendpage,