Commit 4c0a6cb0 authored by Gerrit Renker's avatar Gerrit Renker Committed by David S. Miller

[UDP(-Lite)]: consolidate v4 and v6 get|setsockopt code

This patch consolidates set/getsockopt code between UDP(-Lite) v4 and 6. The
justification is that UDP(-Lite) is a transport-layer protocol and therefore
the socket option code (at least in theory) should be AF-independent.

Furthermore, there is the following code reduplication:
 * do_udp{,v6}_getsockopt is 100% identical between v4 and v6
 * do_udp{,v6}_setsockopt is identical up to the following differerence
	--v4 in contrast to v4 additionally allows the experimental encapsulation
          types  UDP_ENCAP_ESPINUDP and UDP_ENCAP_ESPINUDP_NON_IKE
	--the remainder is identical between v4 and v6
   I believe that this difference is of little relevance.

The advantages in not duplicating twice almost completely identical code.

The patch further simplifies the interface of udp{,v6}_push_pending_frames,
since for the second argument (struct udp_sock *up) it always holds that
up = udp_sk(sk); where sk is the first function argument.
Signed-off-by: default avatarGerrit Renker  <gerrit@erg.abdn.ac.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e3703b3d
...@@ -134,6 +134,11 @@ extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); ...@@ -134,6 +134,11 @@ extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
extern int udp_disconnect(struct sock *sk, int flags); extern int udp_disconnect(struct sock *sk, int flags);
extern unsigned int udp_poll(struct file *file, struct socket *sock, extern unsigned int udp_poll(struct file *file, struct socket *sock,
poll_table *wait); poll_table *wait);
extern int udp_lib_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
extern int udp_lib_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen,
int (*push_pending_frames)(struct sock *));
DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); DECLARE_SNMP_STAT(struct udp_mib, udp_statistics);
/* /*
......
...@@ -448,8 +448,9 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, ...@@ -448,8 +448,9 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
/* /*
* Push out all pending data as one UDP datagram. Socket is locked. * Push out all pending data as one UDP datagram. Socket is locked.
*/ */
static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) static int udp_push_pending_frames(struct sock *sk)
{ {
struct udp_sock *up = udp_sk(sk);
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
struct flowi *fl = &inet->cork.fl; struct flowi *fl = &inet->cork.fl;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -673,7 +674,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ...@@ -673,7 +674,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (err) if (err)
udp_flush_pending_frames(sk); udp_flush_pending_frames(sk);
else if (!corkreq) else if (!corkreq)
err = udp_push_pending_frames(sk, up); err = udp_push_pending_frames(sk);
else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
up->pending = 0; up->pending = 0;
release_sock(sk); release_sock(sk);
...@@ -746,7 +747,7 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset, ...@@ -746,7 +747,7 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset,
up->len += size; up->len += size;
if (!(up->corkflag || (flags&MSG_MORE))) if (!(up->corkflag || (flags&MSG_MORE)))
ret = udp_push_pending_frames(sk, up); ret = udp_push_pending_frames(sk);
if (!ret) if (!ret)
ret = size; ret = size;
out: out:
...@@ -1299,8 +1300,9 @@ int udp_destroy_sock(struct sock *sk) ...@@ -1299,8 +1300,9 @@ int udp_destroy_sock(struct sock *sk)
/* /*
* Socket option code for UDP * Socket option code for UDP
*/ */
static int do_udp_setsockopt(struct sock *sk, int level, int optname, int udp_lib_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen) char __user *optval, int optlen,
int (*push_pending_frames)(struct sock *))
{ {
struct udp_sock *up = udp_sk(sk); struct udp_sock *up = udp_sk(sk);
int val; int val;
...@@ -1319,7 +1321,7 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1319,7 +1321,7 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname,
} else { } else {
up->corkflag = 0; up->corkflag = 0;
lock_sock(sk); lock_sock(sk);
udp_push_pending_frames(sk, up); (*push_pending_frames)(sk);
release_sock(sk); release_sock(sk);
} }
break; break;
...@@ -1375,7 +1377,8 @@ int udp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1375,7 +1377,8 @@ int udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen) char __user *optval, int optlen)
{ {
if (level == SOL_UDP || level == SOL_UDPLITE) if (level == SOL_UDP || level == SOL_UDPLITE)
return do_udp_setsockopt(sk, level, optname, optval, optlen); return udp_lib_setsockopt(sk, level, optname, optval, optlen,
udp_push_pending_frames);
return ip_setsockopt(sk, level, optname, optval, optlen); return ip_setsockopt(sk, level, optname, optval, optlen);
} }
...@@ -1384,13 +1387,14 @@ int compat_udp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1384,13 +1387,14 @@ int compat_udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen) char __user *optval, int optlen)
{ {
if (level == SOL_UDP || level == SOL_UDPLITE) if (level == SOL_UDP || level == SOL_UDPLITE)
return do_udp_setsockopt(sk, level, optname, optval, optlen); return udp_lib_setsockopt(sk, level, optname, optval, optlen,
udp_push_pending_frames);
return compat_ip_setsockopt(sk, level, optname, optval, optlen); return compat_ip_setsockopt(sk, level, optname, optval, optlen);
} }
#endif #endif
static int do_udp_getsockopt(struct sock *sk, int level, int optname, int udp_lib_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
struct udp_sock *up = udp_sk(sk); struct udp_sock *up = udp_sk(sk);
int val, len; int val, len;
...@@ -1437,7 +1441,7 @@ int udp_getsockopt(struct sock *sk, int level, int optname, ...@@ -1437,7 +1441,7 @@ int udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
if (level == SOL_UDP || level == SOL_UDPLITE) if (level == SOL_UDP || level == SOL_UDPLITE)
return do_udp_getsockopt(sk, level, optname, optval, optlen); return udp_lib_getsockopt(sk, level, optname, optval, optlen);
return ip_getsockopt(sk, level, optname, optval, optlen); return ip_getsockopt(sk, level, optname, optval, optlen);
} }
...@@ -1446,7 +1450,7 @@ int compat_udp_getsockopt(struct sock *sk, int level, int optname, ...@@ -1446,7 +1450,7 @@ int compat_udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
if (level == SOL_UDP || level == SOL_UDPLITE) if (level == SOL_UDP || level == SOL_UDPLITE)
return do_udp_getsockopt(sk, level, optname, optval, optlen); return udp_lib_getsockopt(sk, level, optname, optval, optlen);
return compat_ip_getsockopt(sk, level, optname, optval, optlen); return compat_ip_getsockopt(sk, level, optname, optval, optlen);
} }
#endif #endif
...@@ -1716,6 +1720,8 @@ EXPORT_SYMBOL(udp_ioctl); ...@@ -1716,6 +1720,8 @@ EXPORT_SYMBOL(udp_ioctl);
EXPORT_SYMBOL(udp_get_port); EXPORT_SYMBOL(udp_get_port);
EXPORT_SYMBOL(udp_prot); EXPORT_SYMBOL(udp_prot);
EXPORT_SYMBOL(udp_sendmsg); EXPORT_SYMBOL(udp_sendmsg);
EXPORT_SYMBOL(udp_lib_getsockopt);
EXPORT_SYMBOL(udp_lib_setsockopt);
EXPORT_SYMBOL(udp_poll); EXPORT_SYMBOL(udp_poll);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
...@@ -505,10 +505,11 @@ static void udp_v6_flush_pending_frames(struct sock *sk) ...@@ -505,10 +505,11 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
* Sending * Sending
*/ */
static int udp_v6_push_pending_frames(struct sock *sk, struct udp_sock *up) static int udp_v6_push_pending_frames(struct sock *sk)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct udphdr *uh; struct udphdr *uh;
struct udp_sock *up = udp_sk(sk);
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
struct flowi *fl = &inet->cork.fl; struct flowi *fl = &inet->cork.fl;
int err = 0; int err = 0;
...@@ -782,7 +783,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -782,7 +783,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (err) if (err)
udp_v6_flush_pending_frames(sk); udp_v6_flush_pending_frames(sk);
else if (!corkreq) else if (!corkreq)
err = udp_v6_push_pending_frames(sk, up); err = udp_v6_push_pending_frames(sk);
else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
up->pending = 0; up->pending = 0;
...@@ -844,72 +845,12 @@ int udpv6_destroy_sock(struct sock *sk) ...@@ -844,72 +845,12 @@ int udpv6_destroy_sock(struct sock *sk)
/* /*
* Socket option code for UDP * Socket option code for UDP
*/ */
static int do_udpv6_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(optlen<sizeof(int))
return -EINVAL;
if (get_user(val, (int __user *)optval))
return -EFAULT;
switch(optname) {
case UDP_CORK:
if (val != 0) {
up->corkflag = 1;
} else {
up->corkflag = 0;
lock_sock(sk);
udp_v6_push_pending_frames(sk, up);
release_sock(sk);
}
break;
case UDP_ENCAP:
switch (val) {
case 0:
up->encap_type = val;
break;
default:
err = -ENOPROTOOPT;
break;
}
break;
case UDPLITE_SEND_CSCOV:
if (!up->pcflag) /* Disable the option on UDP sockets */
return -ENOPROTOOPT;
if (val != 0 && val < 8) /* Illegal coverage: use default (8) */
val = 8;
up->pcslen = val;
up->pcflag |= UDPLITE_SEND_CC;
break;
case UDPLITE_RECV_CSCOV:
if (!up->pcflag) /* Disable the option on UDP sockets */
return -ENOPROTOOPT;
if (val != 0 && val < 8) /* Avoid silly minimal values. */
val = 8;
up->pcrlen = val;
up->pcflag |= UDPLITE_RECV_CC;
break;
default:
err = -ENOPROTOOPT;
break;
};
return err;
}
int udpv6_setsockopt(struct sock *sk, int level, int optname, int udpv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen) char __user *optval, int optlen)
{ {
if (level == SOL_UDP || level == SOL_UDPLITE) if (level == SOL_UDP || level == SOL_UDPLITE)
return do_udpv6_setsockopt(sk, level, optname, optval, optlen); return udp_lib_setsockopt(sk, level, optname, optval, optlen,
udp_v6_push_pending_frames);
return ipv6_setsockopt(sk, level, optname, optval, optlen); return ipv6_setsockopt(sk, level, optname, optval, optlen);
} }
...@@ -918,58 +859,17 @@ int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -918,58 +859,17 @@ int compat_udpv6_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen) char __user *optval, int optlen)
{ {
if (level == SOL_UDP || level == SOL_UDPLITE) if (level == SOL_UDP || level == SOL_UDPLITE)
return do_udpv6_setsockopt(sk, level, optname, optval, optlen); return udp_lib_setsockopt(sk, level, optname, optval, optlen,
udp_v6_push_pending_frames);
return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); return compat_ipv6_setsockopt(sk, level, optname, optval, optlen);
} }
#endif #endif
static int do_udpv6_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(get_user(len,optlen))
return -EFAULT;
len = min_t(unsigned int, len, sizeof(int));
if(len < 0)
return -EINVAL;
switch(optname) {
case UDP_CORK:
val = up->corkflag;
break;
case UDP_ENCAP:
val = up->encap_type;
break;
case UDPLITE_SEND_CSCOV:
val = up->pcslen;
break;
case UDPLITE_RECV_CSCOV:
val = up->pcrlen;
break;
default:
return -ENOPROTOOPT;
};
if(put_user(len, optlen))
return -EFAULT;
if(copy_to_user(optval, &val,len))
return -EFAULT;
return 0;
}
int udpv6_getsockopt(struct sock *sk, int level, int optname, int udpv6_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
if (level == SOL_UDP || level == SOL_UDPLITE) if (level == SOL_UDP || level == SOL_UDPLITE)
return do_udpv6_getsockopt(sk, level, optname, optval, optlen); return udp_lib_getsockopt(sk, level, optname, optval, optlen);
return ipv6_getsockopt(sk, level, optname, optval, optlen); return ipv6_getsockopt(sk, level, optname, optval, optlen);
} }
...@@ -978,7 +878,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, ...@@ -978,7 +878,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
if (level == SOL_UDP || level == SOL_UDPLITE) if (level == SOL_UDP || level == SOL_UDPLITE)
return do_udpv6_getsockopt(sk, level, optname, optval, optlen); return udp_lib_getsockopt(sk, level, optname, optval, optlen);
return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); return compat_ipv6_getsockopt(sk, level, optname, optval, optlen);
} }
#endif #endif
......
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