Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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 unsigned int udp_poll(struct file *file, struct socket *sock,
			     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);
/*
+18 −12
Original line number Diff line number Diff line
@@ -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.
 */
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 flowi *fl = &inet->cork.fl;
	struct sk_buff *skb;
@@ -673,7 +674,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
	if (err)
		udp_flush_pending_frames(sk);
	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)))
		up->pending = 0;
	release_sock(sk);
@@ -746,7 +747,7 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset,

	up->len += size;
	if (!(up->corkflag || (flags&MSG_MORE)))
		ret = udp_push_pending_frames(sk, up);
		ret = udp_push_pending_frames(sk);
	if (!ret)
		ret = size;
out:
@@ -1299,8 +1300,9 @@ int udp_destroy_sock(struct sock *sk)
/*
 *	Socket option code for UDP
 */
static int do_udp_setsockopt(struct sock *sk, int level, int optname,
			  char __user *optval, int optlen)
int udp_lib_setsockopt(struct sock *sk, int level, int optname,
		       char __user *optval, int optlen,
		       int (*push_pending_frames)(struct sock *))
{
	struct udp_sock *up = udp_sk(sk);
	int val;
@@ -1319,7 +1321,7 @@ static int do_udp_setsockopt(struct sock *sk, int level, int optname,
		} else {
			up->corkflag = 0;
			lock_sock(sk);
			udp_push_pending_frames(sk, up);
			(*push_pending_frames)(sk);
			release_sock(sk);
		}
		break;
@@ -1375,7 +1377,8 @@ int udp_setsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, int optlen)
{
	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);
}

@@ -1384,12 +1387,13 @@ int compat_udp_setsockopt(struct sock *sk, int level, int optname,
			  char __user *optval, int optlen)
{
	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);
}
#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)
{
	struct udp_sock *up = udp_sk(sk);
@@ -1437,7 +1441,7 @@ int udp_getsockopt(struct sock *sk, int level, int optname,
		   char __user *optval, int __user *optlen)
{
	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);
}

@@ -1446,7 +1450,7 @@ int compat_udp_getsockopt(struct sock *sk, int level, int optname,
				 char __user *optval, int __user *optlen)
{
	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);
}
#endif
@@ -1716,6 +1720,8 @@ EXPORT_SYMBOL(udp_ioctl);
EXPORT_SYMBOL(udp_get_port);
EXPORT_SYMBOL(udp_prot);
EXPORT_SYMBOL(udp_sendmsg);
EXPORT_SYMBOL(udp_lib_getsockopt);
EXPORT_SYMBOL(udp_lib_setsockopt);
EXPORT_SYMBOL(udp_poll);

#ifdef CONFIG_PROC_FS
+9 −109
Original line number Diff line number Diff line
@@ -505,10 +505,11 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
 *	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 udphdr *uh;
	struct udp_sock  *up = udp_sk(sk);
	struct inet_sock *inet = inet_sk(sk);
	struct flowi *fl = &inet->cork.fl;
	int err = 0;
@@ -782,7 +783,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
	if (err)
		udp_v6_flush_pending_frames(sk);
	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)))
		up->pending = 0;

@@ -844,72 +845,12 @@ int udpv6_destroy_sock(struct sock *sk)
/*
 *	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,
		     char __user *optval, int optlen)
{
	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);
}

@@ -918,58 +859,17 @@ int compat_udpv6_setsockopt(struct sock *sk, int level, int optname,
			    char __user *optval, int optlen)
{
	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);
}
#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,
		     char __user *optval, int __user *optlen)
{
	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);
}

@@ -978,7 +878,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
			    char __user *optval, int __user *optlen)
{
	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);
}
#endif