xref: /linux/net/ipv4/udp.c (revision 3305b80c214c642b89cd5c21af83bc91ec13f8bd)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * INET		An implementation of the TCP/IP protocol suite for the LINUX
31da177e4SLinus Torvalds  *		operating system.  INET is implemented using the  BSD Socket
41da177e4SLinus Torvalds  *		interface as the means of communication with the user level.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *		The User Datagram Protocol (UDP).
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Version:	$Id: udp.c,v 1.102 2002/02/01 22:01:04 davem Exp $
91da177e4SLinus Torvalds  *
1002c30a84SJesper Juhl  * Authors:	Ross Biro
111da177e4SLinus Torvalds  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
121da177e4SLinus Torvalds  *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
131da177e4SLinus Torvalds  *		Alan Cox, <Alan.Cox@linux.org>
141da177e4SLinus Torvalds  *		Hirokazu Takahashi, <taka@valinux.co.jp>
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * Fixes:
171da177e4SLinus Torvalds  *		Alan Cox	:	verify_area() calls
181da177e4SLinus Torvalds  *		Alan Cox	: 	stopped close while in use off icmp
191da177e4SLinus Torvalds  *					messages. Not a fix but a botch that
201da177e4SLinus Torvalds  *					for udp at least is 'valid'.
211da177e4SLinus Torvalds  *		Alan Cox	:	Fixed icmp handling properly
221da177e4SLinus Torvalds  *		Alan Cox	: 	Correct error for oversized datagrams
231da177e4SLinus Torvalds  *		Alan Cox	:	Tidied select() semantics.
241da177e4SLinus Torvalds  *		Alan Cox	:	udp_err() fixed properly, also now
251da177e4SLinus Torvalds  *					select and read wake correctly on errors
261da177e4SLinus Torvalds  *		Alan Cox	:	udp_send verify_area moved to avoid mem leak
271da177e4SLinus Torvalds  *		Alan Cox	:	UDP can count its memory
281da177e4SLinus Torvalds  *		Alan Cox	:	send to an unknown connection causes
291da177e4SLinus Torvalds  *					an ECONNREFUSED off the icmp, but
301da177e4SLinus Torvalds  *					does NOT close.
311da177e4SLinus Torvalds  *		Alan Cox	:	Switched to new sk_buff handlers. No more backlog!
321da177e4SLinus Torvalds  *		Alan Cox	:	Using generic datagram code. Even smaller and the PEEK
331da177e4SLinus Torvalds  *					bug no longer crashes it.
341da177e4SLinus Torvalds  *		Fred Van Kempen	: 	Net2e support for sk->broadcast.
351da177e4SLinus Torvalds  *		Alan Cox	:	Uses skb_free_datagram
361da177e4SLinus Torvalds  *		Alan Cox	:	Added get/set sockopt support.
371da177e4SLinus Torvalds  *		Alan Cox	:	Broadcasting without option set returns EACCES.
381da177e4SLinus Torvalds  *		Alan Cox	:	No wakeup calls. Instead we now use the callbacks.
391da177e4SLinus Torvalds  *		Alan Cox	:	Use ip_tos and ip_ttl
401da177e4SLinus Torvalds  *		Alan Cox	:	SNMP Mibs
411da177e4SLinus Torvalds  *		Alan Cox	:	MSG_DONTROUTE, and 0.0.0.0 support.
421da177e4SLinus Torvalds  *		Matt Dillon	:	UDP length checks.
431da177e4SLinus Torvalds  *		Alan Cox	:	Smarter af_inet used properly.
441da177e4SLinus Torvalds  *		Alan Cox	:	Use new kernel side addressing.
451da177e4SLinus Torvalds  *		Alan Cox	:	Incorrect return on truncated datagram receive.
461da177e4SLinus Torvalds  *	Arnt Gulbrandsen 	:	New udp_send and stuff
471da177e4SLinus Torvalds  *		Alan Cox	:	Cache last socket
481da177e4SLinus Torvalds  *		Alan Cox	:	Route cache
491da177e4SLinus Torvalds  *		Jon Peatfield	:	Minor efficiency fix to sendto().
501da177e4SLinus Torvalds  *		Mike Shaver	:	RFC1122 checks.
511da177e4SLinus Torvalds  *		Alan Cox	:	Nonblocking error fix.
521da177e4SLinus Torvalds  *	Willy Konynenberg	:	Transparent proxying support.
531da177e4SLinus Torvalds  *		Mike McLagan	:	Routing by source
541da177e4SLinus Torvalds  *		David S. Miller	:	New socket lookup architecture.
551da177e4SLinus Torvalds  *					Last socket cache retained as it
561da177e4SLinus Torvalds  *					does have a high hit rate.
571da177e4SLinus Torvalds  *		Olaf Kirch	:	Don't linearise iovec on sendmsg.
581da177e4SLinus Torvalds  *		Andi Kleen	:	Some cleanups, cache destination entry
591da177e4SLinus Torvalds  *					for connect.
601da177e4SLinus Torvalds  *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
611da177e4SLinus Torvalds  *		Melvin Smith	:	Check msg_name not msg_namelen in sendto(),
621da177e4SLinus Torvalds  *					return ENOTCONN for unconnected sockets (POSIX)
631da177e4SLinus Torvalds  *		Janos Farkas	:	don't deliver multi/broadcasts to a different
641da177e4SLinus Torvalds  *					bound-to-device socket
651da177e4SLinus Torvalds  *	Hirokazu Takahashi	:	HW checksumming for outgoing UDP
661da177e4SLinus Torvalds  *					datagrams.
671da177e4SLinus Torvalds  *	Hirokazu Takahashi	:	sendfile() on UDP works now.
681da177e4SLinus Torvalds  *		Arnaldo C. Melo :	convert /proc/net/udp to seq_file
691da177e4SLinus Torvalds  *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
701da177e4SLinus Torvalds  *	Alexey Kuznetsov:		allow both IPv4 and IPv6 sockets to bind
711da177e4SLinus Torvalds  *					a single port at the same time.
721da177e4SLinus Torvalds  *	Derek Atkins <derek@ihtfp.com>: Add Encapulation Support
731da177e4SLinus Torvalds  *
741da177e4SLinus Torvalds  *
751da177e4SLinus Torvalds  *		This program is free software; you can redistribute it and/or
761da177e4SLinus Torvalds  *		modify it under the terms of the GNU General Public License
771da177e4SLinus Torvalds  *		as published by the Free Software Foundation; either version
781da177e4SLinus Torvalds  *		2 of the License, or (at your option) any later version.
791da177e4SLinus Torvalds  */
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds #include <asm/system.h>
821da177e4SLinus Torvalds #include <asm/uaccess.h>
831da177e4SLinus Torvalds #include <asm/ioctls.h>
841da177e4SLinus Torvalds #include <linux/types.h>
851da177e4SLinus Torvalds #include <linux/fcntl.h>
861da177e4SLinus Torvalds #include <linux/module.h>
871da177e4SLinus Torvalds #include <linux/socket.h>
881da177e4SLinus Torvalds #include <linux/sockios.h>
891da177e4SLinus Torvalds #include <linux/in.h>
901da177e4SLinus Torvalds #include <linux/errno.h>
911da177e4SLinus Torvalds #include <linux/timer.h>
921da177e4SLinus Torvalds #include <linux/mm.h>
931da177e4SLinus Torvalds #include <linux/config.h>
941da177e4SLinus Torvalds #include <linux/inet.h>
951da177e4SLinus Torvalds #include <linux/ipv6.h>
961da177e4SLinus Torvalds #include <linux/netdevice.h>
971da177e4SLinus Torvalds #include <net/snmp.h>
98c752f073SArnaldo Carvalho de Melo #include <net/ip.h>
99c752f073SArnaldo Carvalho de Melo #include <net/tcp_states.h>
1001da177e4SLinus Torvalds #include <net/protocol.h>
1011da177e4SLinus Torvalds #include <linux/skbuff.h>
1021da177e4SLinus Torvalds #include <linux/proc_fs.h>
1031da177e4SLinus Torvalds #include <linux/seq_file.h>
1041da177e4SLinus Torvalds #include <net/sock.h>
1051da177e4SLinus Torvalds #include <net/udp.h>
1061da177e4SLinus Torvalds #include <net/icmp.h>
1071da177e4SLinus Torvalds #include <net/route.h>
1081da177e4SLinus Torvalds #include <net/inet_common.h>
1091da177e4SLinus Torvalds #include <net/checksum.h>
1101da177e4SLinus Torvalds #include <net/xfrm.h>
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds /*
1131da177e4SLinus Torvalds  *	Snmp MIB for the UDP layer
1141da177e4SLinus Torvalds  */
1151da177e4SLinus Torvalds 
116ba89966cSEric Dumazet DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly;
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds struct hlist_head udp_hash[UDP_HTABLE_SIZE];
1191da177e4SLinus Torvalds DEFINE_RWLOCK(udp_hash_lock);
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds /* Shared by v4/v6 udp. */
1221da177e4SLinus Torvalds int udp_port_rover;
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds static int udp_v4_get_port(struct sock *sk, unsigned short snum)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds 	struct hlist_node *node;
1271da177e4SLinus Torvalds 	struct sock *sk2;
1281da177e4SLinus Torvalds 	struct inet_sock *inet = inet_sk(sk);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	write_lock_bh(&udp_hash_lock);
1311da177e4SLinus Torvalds 	if (snum == 0) {
1321da177e4SLinus Torvalds 		int best_size_so_far, best, result, i;
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 		if (udp_port_rover > sysctl_local_port_range[1] ||
1351da177e4SLinus Torvalds 		    udp_port_rover < sysctl_local_port_range[0])
1361da177e4SLinus Torvalds 			udp_port_rover = sysctl_local_port_range[0];
1371da177e4SLinus Torvalds 		best_size_so_far = 32767;
1381da177e4SLinus Torvalds 		best = result = udp_port_rover;
1391da177e4SLinus Torvalds 		for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
1401da177e4SLinus Torvalds 			struct hlist_head *list;
1411da177e4SLinus Torvalds 			int size;
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 			list = &udp_hash[result & (UDP_HTABLE_SIZE - 1)];
1441da177e4SLinus Torvalds 			if (hlist_empty(list)) {
1451da177e4SLinus Torvalds 				if (result > sysctl_local_port_range[1])
1461da177e4SLinus Torvalds 					result = sysctl_local_port_range[0] +
1471da177e4SLinus Torvalds 						((result - sysctl_local_port_range[0]) &
1481da177e4SLinus Torvalds 						 (UDP_HTABLE_SIZE - 1));
1491da177e4SLinus Torvalds 				goto gotit;
1501da177e4SLinus Torvalds 			}
1511da177e4SLinus Torvalds 			size = 0;
1521da177e4SLinus Torvalds 			sk_for_each(sk2, node, list)
1531da177e4SLinus Torvalds 				if (++size >= best_size_so_far)
1541da177e4SLinus Torvalds 					goto next;
1551da177e4SLinus Torvalds 			best_size_so_far = size;
1561da177e4SLinus Torvalds 			best = result;
1571da177e4SLinus Torvalds 		next:;
1581da177e4SLinus Torvalds 		}
1591da177e4SLinus Torvalds 		result = best;
1601da177e4SLinus Torvalds 		for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) {
1611da177e4SLinus Torvalds 			if (result > sysctl_local_port_range[1])
1621da177e4SLinus Torvalds 				result = sysctl_local_port_range[0]
1631da177e4SLinus Torvalds 					+ ((result - sysctl_local_port_range[0]) &
1641da177e4SLinus Torvalds 					   (UDP_HTABLE_SIZE - 1));
1651da177e4SLinus Torvalds 			if (!udp_lport_inuse(result))
1661da177e4SLinus Torvalds 				break;
1671da177e4SLinus Torvalds 		}
1681da177e4SLinus Torvalds 		if (i >= (1 << 16) / UDP_HTABLE_SIZE)
1691da177e4SLinus Torvalds 			goto fail;
1701da177e4SLinus Torvalds gotit:
1711da177e4SLinus Torvalds 		udp_port_rover = snum = result;
1721da177e4SLinus Torvalds 	} else {
1731da177e4SLinus Torvalds 		sk_for_each(sk2, node,
1741da177e4SLinus Torvalds 			    &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]) {
1751da177e4SLinus Torvalds 			struct inet_sock *inet2 = inet_sk(sk2);
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 			if (inet2->num == snum &&
1781da177e4SLinus Torvalds 			    sk2 != sk &&
1791da177e4SLinus Torvalds 			    !ipv6_only_sock(sk2) &&
1801da177e4SLinus Torvalds 			    (!sk2->sk_bound_dev_if ||
1811da177e4SLinus Torvalds 			     !sk->sk_bound_dev_if ||
1821da177e4SLinus Torvalds 			     sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
1831da177e4SLinus Torvalds 			    (!inet2->rcv_saddr ||
1841da177e4SLinus Torvalds 			     !inet->rcv_saddr ||
1851da177e4SLinus Torvalds 			     inet2->rcv_saddr == inet->rcv_saddr) &&
1861da177e4SLinus Torvalds 			    (!sk2->sk_reuse || !sk->sk_reuse))
1871da177e4SLinus Torvalds 				goto fail;
1881da177e4SLinus Torvalds 		}
1891da177e4SLinus Torvalds 	}
1901da177e4SLinus Torvalds 	inet->num = snum;
1911da177e4SLinus Torvalds 	if (sk_unhashed(sk)) {
1921da177e4SLinus Torvalds 		struct hlist_head *h = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 		sk_add_node(sk, h);
1951da177e4SLinus Torvalds 		sock_prot_inc_use(sk->sk_prot);
1961da177e4SLinus Torvalds 	}
1971da177e4SLinus Torvalds 	write_unlock_bh(&udp_hash_lock);
1981da177e4SLinus Torvalds 	return 0;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds fail:
2011da177e4SLinus Torvalds 	write_unlock_bh(&udp_hash_lock);
2021da177e4SLinus Torvalds 	return 1;
2031da177e4SLinus Torvalds }
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds static void udp_v4_hash(struct sock *sk)
2061da177e4SLinus Torvalds {
2071da177e4SLinus Torvalds 	BUG();
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds static void udp_v4_unhash(struct sock *sk)
2111da177e4SLinus Torvalds {
2121da177e4SLinus Torvalds 	write_lock_bh(&udp_hash_lock);
2131da177e4SLinus Torvalds 	if (sk_del_node_init(sk)) {
2141da177e4SLinus Torvalds 		inet_sk(sk)->num = 0;
2151da177e4SLinus Torvalds 		sock_prot_dec_use(sk->sk_prot);
2161da177e4SLinus Torvalds 	}
2171da177e4SLinus Torvalds 	write_unlock_bh(&udp_hash_lock);
2181da177e4SLinus Torvalds }
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
2211da177e4SLinus Torvalds  * harder than this. -DaveM
2221da177e4SLinus Torvalds  */
2231da177e4SLinus Torvalds static struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport,
2241da177e4SLinus Torvalds 					  u32 daddr, u16 dport, int dif)
2251da177e4SLinus Torvalds {
2261da177e4SLinus Torvalds 	struct sock *sk, *result = NULL;
2271da177e4SLinus Torvalds 	struct hlist_node *node;
2281da177e4SLinus Torvalds 	unsigned short hnum = ntohs(dport);
2291da177e4SLinus Torvalds 	int badness = -1;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	sk_for_each(sk, node, &udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]) {
2321da177e4SLinus Torvalds 		struct inet_sock *inet = inet_sk(sk);
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 		if (inet->num == hnum && !ipv6_only_sock(sk)) {
2351da177e4SLinus Torvalds 			int score = (sk->sk_family == PF_INET ? 1 : 0);
2361da177e4SLinus Torvalds 			if (inet->rcv_saddr) {
2371da177e4SLinus Torvalds 				if (inet->rcv_saddr != daddr)
2381da177e4SLinus Torvalds 					continue;
2391da177e4SLinus Torvalds 				score+=2;
2401da177e4SLinus Torvalds 			}
2411da177e4SLinus Torvalds 			if (inet->daddr) {
2421da177e4SLinus Torvalds 				if (inet->daddr != saddr)
2431da177e4SLinus Torvalds 					continue;
2441da177e4SLinus Torvalds 				score+=2;
2451da177e4SLinus Torvalds 			}
2461da177e4SLinus Torvalds 			if (inet->dport) {
2471da177e4SLinus Torvalds 				if (inet->dport != sport)
2481da177e4SLinus Torvalds 					continue;
2491da177e4SLinus Torvalds 				score+=2;
2501da177e4SLinus Torvalds 			}
2511da177e4SLinus Torvalds 			if (sk->sk_bound_dev_if) {
2521da177e4SLinus Torvalds 				if (sk->sk_bound_dev_if != dif)
2531da177e4SLinus Torvalds 					continue;
2541da177e4SLinus Torvalds 				score+=2;
2551da177e4SLinus Torvalds 			}
2561da177e4SLinus Torvalds 			if(score == 9) {
2571da177e4SLinus Torvalds 				result = sk;
2581da177e4SLinus Torvalds 				break;
2591da177e4SLinus Torvalds 			} else if(score > badness) {
2601da177e4SLinus Torvalds 				result = sk;
2611da177e4SLinus Torvalds 				badness = score;
2621da177e4SLinus Torvalds 			}
2631da177e4SLinus Torvalds 		}
2641da177e4SLinus Torvalds 	}
2651da177e4SLinus Torvalds 	return result;
2661da177e4SLinus Torvalds }
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds static __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport,
2691da177e4SLinus Torvalds 					     u32 daddr, u16 dport, int dif)
2701da177e4SLinus Torvalds {
2711da177e4SLinus Torvalds 	struct sock *sk;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 	read_lock(&udp_hash_lock);
2741da177e4SLinus Torvalds 	sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif);
2751da177e4SLinus Torvalds 	if (sk)
2761da177e4SLinus Torvalds 		sock_hold(sk);
2771da177e4SLinus Torvalds 	read_unlock(&udp_hash_lock);
2781da177e4SLinus Torvalds 	return sk;
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds static inline struct sock *udp_v4_mcast_next(struct sock *sk,
2821da177e4SLinus Torvalds 					     u16 loc_port, u32 loc_addr,
2831da177e4SLinus Torvalds 					     u16 rmt_port, u32 rmt_addr,
2841da177e4SLinus Torvalds 					     int dif)
2851da177e4SLinus Torvalds {
2861da177e4SLinus Torvalds 	struct hlist_node *node;
2871da177e4SLinus Torvalds 	struct sock *s = sk;
2881da177e4SLinus Torvalds 	unsigned short hnum = ntohs(loc_port);
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 	sk_for_each_from(s, node) {
2911da177e4SLinus Torvalds 		struct inet_sock *inet = inet_sk(s);
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 		if (inet->num != hnum					||
2941da177e4SLinus Torvalds 		    (inet->daddr && inet->daddr != rmt_addr)		||
2951da177e4SLinus Torvalds 		    (inet->dport != rmt_port && inet->dport)		||
2961da177e4SLinus Torvalds 		    (inet->rcv_saddr && inet->rcv_saddr != loc_addr)	||
2971da177e4SLinus Torvalds 		    ipv6_only_sock(s)					||
2981da177e4SLinus Torvalds 		    (s->sk_bound_dev_if && s->sk_bound_dev_if != dif))
2991da177e4SLinus Torvalds 			continue;
3001da177e4SLinus Torvalds 		if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif))
3011da177e4SLinus Torvalds 			continue;
3021da177e4SLinus Torvalds 		goto found;
3031da177e4SLinus Torvalds   	}
3041da177e4SLinus Torvalds 	s = NULL;
3051da177e4SLinus Torvalds found:
3061da177e4SLinus Torvalds   	return s;
3071da177e4SLinus Torvalds }
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds /*
3101da177e4SLinus Torvalds  * This routine is called by the ICMP module when it gets some
3111da177e4SLinus Torvalds  * sort of error condition.  If err < 0 then the socket should
3121da177e4SLinus Torvalds  * be closed and the error returned to the user.  If err > 0
3131da177e4SLinus Torvalds  * it's just the icmp type << 8 | icmp code.
3141da177e4SLinus Torvalds  * Header points to the ip header of the error packet. We move
3151da177e4SLinus Torvalds  * on past this. Then (as it used to claim before adjustment)
3161da177e4SLinus Torvalds  * header points to the first 8 bytes of the udp header.  We need
3171da177e4SLinus Torvalds  * to find the appropriate port.
3181da177e4SLinus Torvalds  */
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds void udp_err(struct sk_buff *skb, u32 info)
3211da177e4SLinus Torvalds {
3221da177e4SLinus Torvalds 	struct inet_sock *inet;
3231da177e4SLinus Torvalds 	struct iphdr *iph = (struct iphdr*)skb->data;
3241da177e4SLinus Torvalds 	struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2));
3251da177e4SLinus Torvalds 	int type = skb->h.icmph->type;
3261da177e4SLinus Torvalds 	int code = skb->h.icmph->code;
3271da177e4SLinus Torvalds 	struct sock *sk;
3281da177e4SLinus Torvalds 	int harderr;
3291da177e4SLinus Torvalds 	int err;
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex);
3321da177e4SLinus Torvalds 	if (sk == NULL) {
3331da177e4SLinus Torvalds 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
3341da177e4SLinus Torvalds     	  	return;	/* No socket for error */
3351da177e4SLinus Torvalds 	}
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	err = 0;
3381da177e4SLinus Torvalds 	harderr = 0;
3391da177e4SLinus Torvalds 	inet = inet_sk(sk);
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	switch (type) {
3421da177e4SLinus Torvalds 	default:
3431da177e4SLinus Torvalds 	case ICMP_TIME_EXCEEDED:
3441da177e4SLinus Torvalds 		err = EHOSTUNREACH;
3451da177e4SLinus Torvalds 		break;
3461da177e4SLinus Torvalds 	case ICMP_SOURCE_QUENCH:
3471da177e4SLinus Torvalds 		goto out;
3481da177e4SLinus Torvalds 	case ICMP_PARAMETERPROB:
3491da177e4SLinus Torvalds 		err = EPROTO;
3501da177e4SLinus Torvalds 		harderr = 1;
3511da177e4SLinus Torvalds 		break;
3521da177e4SLinus Torvalds 	case ICMP_DEST_UNREACH:
3531da177e4SLinus Torvalds 		if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
3541da177e4SLinus Torvalds 			if (inet->pmtudisc != IP_PMTUDISC_DONT) {
3551da177e4SLinus Torvalds 				err = EMSGSIZE;
3561da177e4SLinus Torvalds 				harderr = 1;
3571da177e4SLinus Torvalds 				break;
3581da177e4SLinus Torvalds 			}
3591da177e4SLinus Torvalds 			goto out;
3601da177e4SLinus Torvalds 		}
3611da177e4SLinus Torvalds 		err = EHOSTUNREACH;
3621da177e4SLinus Torvalds 		if (code <= NR_ICMP_UNREACH) {
3631da177e4SLinus Torvalds 			harderr = icmp_err_convert[code].fatal;
3641da177e4SLinus Torvalds 			err = icmp_err_convert[code].errno;
3651da177e4SLinus Torvalds 		}
3661da177e4SLinus Torvalds 		break;
3671da177e4SLinus Torvalds 	}
3681da177e4SLinus Torvalds 
3691da177e4SLinus Torvalds 	/*
3701da177e4SLinus Torvalds 	 *      RFC1122: OK.  Passes ICMP errors back to application, as per
3711da177e4SLinus Torvalds 	 *	4.1.3.3.
3721da177e4SLinus Torvalds 	 */
3731da177e4SLinus Torvalds 	if (!inet->recverr) {
3741da177e4SLinus Torvalds 		if (!harderr || sk->sk_state != TCP_ESTABLISHED)
3751da177e4SLinus Torvalds 			goto out;
3761da177e4SLinus Torvalds 	} else {
3771da177e4SLinus Torvalds 		ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1));
3781da177e4SLinus Torvalds 	}
3791da177e4SLinus Torvalds 	sk->sk_err = err;
3801da177e4SLinus Torvalds 	sk->sk_error_report(sk);
3811da177e4SLinus Torvalds out:
3821da177e4SLinus Torvalds 	sock_put(sk);
3831da177e4SLinus Torvalds }
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds /*
3861da177e4SLinus Torvalds  * Throw away all pending data and cancel the corking. Socket is locked.
3871da177e4SLinus Torvalds  */
3881da177e4SLinus Torvalds static void udp_flush_pending_frames(struct sock *sk)
3891da177e4SLinus Torvalds {
3901da177e4SLinus Torvalds 	struct udp_sock *up = udp_sk(sk);
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	if (up->pending) {
3931da177e4SLinus Torvalds 		up->len = 0;
3941da177e4SLinus Torvalds 		up->pending = 0;
3951da177e4SLinus Torvalds 		ip_flush_pending_frames(sk);
3961da177e4SLinus Torvalds 	}
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds /*
4001da177e4SLinus Torvalds  * Push out all pending data as one UDP datagram. Socket is locked.
4011da177e4SLinus Torvalds  */
4021da177e4SLinus Torvalds static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up)
4031da177e4SLinus Torvalds {
4041da177e4SLinus Torvalds 	struct inet_sock *inet = inet_sk(sk);
4051da177e4SLinus Torvalds 	struct flowi *fl = &inet->cork.fl;
4061da177e4SLinus Torvalds 	struct sk_buff *skb;
4071da177e4SLinus Torvalds 	struct udphdr *uh;
4081da177e4SLinus Torvalds 	int err = 0;
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds 	/* Grab the skbuff where UDP header space exists. */
4111da177e4SLinus Torvalds 	if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
4121da177e4SLinus Torvalds 		goto out;
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds 	/*
4151da177e4SLinus Torvalds 	 * Create a UDP header
4161da177e4SLinus Torvalds 	 */
4171da177e4SLinus Torvalds 	uh = skb->h.uh;
4181da177e4SLinus Torvalds 	uh->source = fl->fl_ip_sport;
4191da177e4SLinus Torvalds 	uh->dest = fl->fl_ip_dport;
4201da177e4SLinus Torvalds 	uh->len = htons(up->len);
4211da177e4SLinus Torvalds 	uh->check = 0;
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds 	if (sk->sk_no_check == UDP_CSUM_NOXMIT) {
4241da177e4SLinus Torvalds 		skb->ip_summed = CHECKSUM_NONE;
4251da177e4SLinus Torvalds 		goto send;
4261da177e4SLinus Torvalds 	}
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 	if (skb_queue_len(&sk->sk_write_queue) == 1) {
4291da177e4SLinus Torvalds 		/*
4301da177e4SLinus Torvalds 		 * Only one fragment on the socket.
4311da177e4SLinus Torvalds 		 */
4321da177e4SLinus Torvalds 		if (skb->ip_summed == CHECKSUM_HW) {
4331da177e4SLinus Torvalds 			skb->csum = offsetof(struct udphdr, check);
4341da177e4SLinus Torvalds 			uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst,
4351da177e4SLinus Torvalds 					up->len, IPPROTO_UDP, 0);
4361da177e4SLinus Torvalds 		} else {
4371da177e4SLinus Torvalds 			skb->csum = csum_partial((char *)uh,
4381da177e4SLinus Torvalds 					sizeof(struct udphdr), skb->csum);
4391da177e4SLinus Torvalds 			uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst,
4401da177e4SLinus Torvalds 					up->len, IPPROTO_UDP, skb->csum);
4411da177e4SLinus Torvalds 			if (uh->check == 0)
4421da177e4SLinus Torvalds 				uh->check = -1;
4431da177e4SLinus Torvalds 		}
4441da177e4SLinus Torvalds 	} else {
4451da177e4SLinus Torvalds 		unsigned int csum = 0;
4461da177e4SLinus Torvalds 		/*
4471da177e4SLinus Torvalds 		 * HW-checksum won't work as there are two or more
4481da177e4SLinus Torvalds 		 * fragments on the socket so that all csums of sk_buffs
4491da177e4SLinus Torvalds 		 * should be together.
4501da177e4SLinus Torvalds 		 */
4511da177e4SLinus Torvalds 		if (skb->ip_summed == CHECKSUM_HW) {
4521da177e4SLinus Torvalds 			int offset = (unsigned char *)uh - skb->data;
4531da177e4SLinus Torvalds 			skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 			skb->ip_summed = CHECKSUM_NONE;
4561da177e4SLinus Torvalds 		} else {
4571da177e4SLinus Torvalds 			skb->csum = csum_partial((char *)uh,
4581da177e4SLinus Torvalds 					sizeof(struct udphdr), skb->csum);
4591da177e4SLinus Torvalds 		}
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds 		skb_queue_walk(&sk->sk_write_queue, skb) {
4621da177e4SLinus Torvalds 			csum = csum_add(csum, skb->csum);
4631da177e4SLinus Torvalds 		}
4641da177e4SLinus Torvalds 		uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst,
4651da177e4SLinus Torvalds 				up->len, IPPROTO_UDP, csum);
4661da177e4SLinus Torvalds 		if (uh->check == 0)
4671da177e4SLinus Torvalds 			uh->check = -1;
4681da177e4SLinus Torvalds 	}
4691da177e4SLinus Torvalds send:
4701da177e4SLinus Torvalds 	err = ip_push_pending_frames(sk);
4711da177e4SLinus Torvalds out:
4721da177e4SLinus Torvalds 	up->len = 0;
4731da177e4SLinus Torvalds 	up->pending = 0;
4741da177e4SLinus Torvalds 	return err;
4751da177e4SLinus Torvalds }
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base)
4791da177e4SLinus Torvalds {
4801da177e4SLinus Torvalds 	return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds 
4831da177e4SLinus Torvalds int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
4841da177e4SLinus Torvalds 		size_t len)
4851da177e4SLinus Torvalds {
4861da177e4SLinus Torvalds 	struct inet_sock *inet = inet_sk(sk);
4871da177e4SLinus Torvalds 	struct udp_sock *up = udp_sk(sk);
4881da177e4SLinus Torvalds 	int ulen = len;
4891da177e4SLinus Torvalds 	struct ipcm_cookie ipc;
4901da177e4SLinus Torvalds 	struct rtable *rt = NULL;
4911da177e4SLinus Torvalds 	int free = 0;
4921da177e4SLinus Torvalds 	int connected = 0;
4931da177e4SLinus Torvalds 	u32 daddr, faddr, saddr;
4941da177e4SLinus Torvalds 	u16 dport;
4951da177e4SLinus Torvalds 	u8  tos;
4961da177e4SLinus Torvalds 	int err;
4971da177e4SLinus Torvalds 	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds 	if (len > 0xFFFF)
5001da177e4SLinus Torvalds 		return -EMSGSIZE;
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	/*
5031da177e4SLinus Torvalds 	 *	Check the flags.
5041da177e4SLinus Torvalds 	 */
5051da177e4SLinus Torvalds 
5061da177e4SLinus Torvalds 	if (msg->msg_flags&MSG_OOB)	/* Mirror BSD error message compatibility */
5071da177e4SLinus Torvalds 		return -EOPNOTSUPP;
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds 	ipc.opt = NULL;
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 	if (up->pending) {
5121da177e4SLinus Torvalds 		/*
5131da177e4SLinus Torvalds 		 * There are pending frames.
5141da177e4SLinus Torvalds 	 	 * The socket lock must be held while it's corked.
5151da177e4SLinus Torvalds 		 */
5161da177e4SLinus Torvalds 		lock_sock(sk);
5171da177e4SLinus Torvalds 		if (likely(up->pending)) {
5181da177e4SLinus Torvalds 			if (unlikely(up->pending != AF_INET)) {
5191da177e4SLinus Torvalds 				release_sock(sk);
5201da177e4SLinus Torvalds 				return -EINVAL;
5211da177e4SLinus Torvalds 			}
5221da177e4SLinus Torvalds  			goto do_append_data;
5231da177e4SLinus Torvalds 		}
5241da177e4SLinus Torvalds 		release_sock(sk);
5251da177e4SLinus Torvalds 	}
5261da177e4SLinus Torvalds 	ulen += sizeof(struct udphdr);
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 	/*
5291da177e4SLinus Torvalds 	 *	Get and verify the address.
5301da177e4SLinus Torvalds 	 */
5311da177e4SLinus Torvalds 	if (msg->msg_name) {
5321da177e4SLinus Torvalds 		struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
5331da177e4SLinus Torvalds 		if (msg->msg_namelen < sizeof(*usin))
5341da177e4SLinus Torvalds 			return -EINVAL;
5351da177e4SLinus Torvalds 		if (usin->sin_family != AF_INET) {
5361da177e4SLinus Torvalds 			if (usin->sin_family != AF_UNSPEC)
5371da177e4SLinus Torvalds 				return -EAFNOSUPPORT;
5381da177e4SLinus Torvalds 		}
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds 		daddr = usin->sin_addr.s_addr;
5411da177e4SLinus Torvalds 		dport = usin->sin_port;
5421da177e4SLinus Torvalds 		if (dport == 0)
5431da177e4SLinus Torvalds 			return -EINVAL;
5441da177e4SLinus Torvalds 	} else {
5451da177e4SLinus Torvalds 		if (sk->sk_state != TCP_ESTABLISHED)
5461da177e4SLinus Torvalds 			return -EDESTADDRREQ;
5471da177e4SLinus Torvalds 		daddr = inet->daddr;
5481da177e4SLinus Torvalds 		dport = inet->dport;
5491da177e4SLinus Torvalds 		/* Open fast path for connected socket.
5501da177e4SLinus Torvalds 		   Route will not be used, if at least one option is set.
5511da177e4SLinus Torvalds 		 */
5521da177e4SLinus Torvalds 		connected = 1;
5531da177e4SLinus Torvalds   	}
5541da177e4SLinus Torvalds 	ipc.addr = inet->saddr;
5551da177e4SLinus Torvalds 
5561da177e4SLinus Torvalds 	ipc.oif = sk->sk_bound_dev_if;
5571da177e4SLinus Torvalds 	if (msg->msg_controllen) {
5581da177e4SLinus Torvalds 		err = ip_cmsg_send(msg, &ipc);
5591da177e4SLinus Torvalds 		if (err)
5601da177e4SLinus Torvalds 			return err;
5611da177e4SLinus Torvalds 		if (ipc.opt)
5621da177e4SLinus Torvalds 			free = 1;
5631da177e4SLinus Torvalds 		connected = 0;
5641da177e4SLinus Torvalds 	}
5651da177e4SLinus Torvalds 	if (!ipc.opt)
5661da177e4SLinus Torvalds 		ipc.opt = inet->opt;
5671da177e4SLinus Torvalds 
5681da177e4SLinus Torvalds 	saddr = ipc.addr;
5691da177e4SLinus Torvalds 	ipc.addr = faddr = daddr;
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds 	if (ipc.opt && ipc.opt->srr) {
5721da177e4SLinus Torvalds 		if (!daddr)
5731da177e4SLinus Torvalds 			return -EINVAL;
5741da177e4SLinus Torvalds 		faddr = ipc.opt->faddr;
5751da177e4SLinus Torvalds 		connected = 0;
5761da177e4SLinus Torvalds 	}
5771da177e4SLinus Torvalds 	tos = RT_TOS(inet->tos);
5781da177e4SLinus Torvalds 	if (sock_flag(sk, SOCK_LOCALROUTE) ||
5791da177e4SLinus Torvalds 	    (msg->msg_flags & MSG_DONTROUTE) ||
5801da177e4SLinus Torvalds 	    (ipc.opt && ipc.opt->is_strictroute)) {
5811da177e4SLinus Torvalds 		tos |= RTO_ONLINK;
5821da177e4SLinus Torvalds 		connected = 0;
5831da177e4SLinus Torvalds 	}
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 	if (MULTICAST(daddr)) {
5861da177e4SLinus Torvalds 		if (!ipc.oif)
5871da177e4SLinus Torvalds 			ipc.oif = inet->mc_index;
5881da177e4SLinus Torvalds 		if (!saddr)
5891da177e4SLinus Torvalds 			saddr = inet->mc_addr;
5901da177e4SLinus Torvalds 		connected = 0;
5911da177e4SLinus Torvalds 	}
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 	if (connected)
5941da177e4SLinus Torvalds 		rt = (struct rtable*)sk_dst_check(sk, 0);
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 	if (rt == NULL) {
5971da177e4SLinus Torvalds 		struct flowi fl = { .oif = ipc.oif,
5981da177e4SLinus Torvalds 				    .nl_u = { .ip4_u =
5991da177e4SLinus Torvalds 					      { .daddr = faddr,
6001da177e4SLinus Torvalds 						.saddr = saddr,
6011da177e4SLinus Torvalds 						.tos = tos } },
6021da177e4SLinus Torvalds 				    .proto = IPPROTO_UDP,
6031da177e4SLinus Torvalds 				    .uli_u = { .ports =
6041da177e4SLinus Torvalds 					       { .sport = inet->sport,
6051da177e4SLinus Torvalds 						 .dport = dport } } };
6061da177e4SLinus Torvalds 		err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
6071da177e4SLinus Torvalds 		if (err)
6081da177e4SLinus Torvalds 			goto out;
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 		err = -EACCES;
6111da177e4SLinus Torvalds 		if ((rt->rt_flags & RTCF_BROADCAST) &&
6121da177e4SLinus Torvalds 		    !sock_flag(sk, SOCK_BROADCAST))
6131da177e4SLinus Torvalds 			goto out;
6141da177e4SLinus Torvalds 		if (connected)
6151da177e4SLinus Torvalds 			sk_dst_set(sk, dst_clone(&rt->u.dst));
6161da177e4SLinus Torvalds 	}
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds 	if (msg->msg_flags&MSG_CONFIRM)
6191da177e4SLinus Torvalds 		goto do_confirm;
6201da177e4SLinus Torvalds back_from_confirm:
6211da177e4SLinus Torvalds 
6221da177e4SLinus Torvalds 	saddr = rt->rt_src;
6231da177e4SLinus Torvalds 	if (!ipc.addr)
6241da177e4SLinus Torvalds 		daddr = ipc.addr = rt->rt_dst;
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds 	lock_sock(sk);
6271da177e4SLinus Torvalds 	if (unlikely(up->pending)) {
6281da177e4SLinus Torvalds 		/* The socket is already corked while preparing it. */
6291da177e4SLinus Torvalds 		/* ... which is an evident application bug. --ANK */
6301da177e4SLinus Torvalds 		release_sock(sk);
6311da177e4SLinus Torvalds 
63264ce2073SPatrick McHardy 		LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n");
6331da177e4SLinus Torvalds 		err = -EINVAL;
6341da177e4SLinus Torvalds 		goto out;
6351da177e4SLinus Torvalds 	}
6361da177e4SLinus Torvalds 	/*
6371da177e4SLinus Torvalds 	 *	Now cork the socket to pend data.
6381da177e4SLinus Torvalds 	 */
6391da177e4SLinus Torvalds 	inet->cork.fl.fl4_dst = daddr;
6401da177e4SLinus Torvalds 	inet->cork.fl.fl_ip_dport = dport;
6411da177e4SLinus Torvalds 	inet->cork.fl.fl4_src = saddr;
6421da177e4SLinus Torvalds 	inet->cork.fl.fl_ip_sport = inet->sport;
6431da177e4SLinus Torvalds 	up->pending = AF_INET;
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds do_append_data:
6461da177e4SLinus Torvalds 	up->len += ulen;
6471da177e4SLinus Torvalds 	err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
6481da177e4SLinus Torvalds 			sizeof(struct udphdr), &ipc, rt,
6491da177e4SLinus Torvalds 			corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
6501da177e4SLinus Torvalds 	if (err)
6511da177e4SLinus Torvalds 		udp_flush_pending_frames(sk);
6521da177e4SLinus Torvalds 	else if (!corkreq)
6531da177e4SLinus Torvalds 		err = udp_push_pending_frames(sk, up);
6541da177e4SLinus Torvalds 	release_sock(sk);
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds out:
6571da177e4SLinus Torvalds 	ip_rt_put(rt);
6581da177e4SLinus Torvalds 	if (free)
6591da177e4SLinus Torvalds 		kfree(ipc.opt);
6601da177e4SLinus Torvalds 	if (!err) {
6611da177e4SLinus Torvalds 		UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS);
6621da177e4SLinus Torvalds 		return len;
6631da177e4SLinus Torvalds 	}
6641da177e4SLinus Torvalds 	return err;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds do_confirm:
6671da177e4SLinus Torvalds 	dst_confirm(&rt->u.dst);
6681da177e4SLinus Torvalds 	if (!(msg->msg_flags&MSG_PROBE) || len)
6691da177e4SLinus Torvalds 		goto back_from_confirm;
6701da177e4SLinus Torvalds 	err = 0;
6711da177e4SLinus Torvalds 	goto out;
6721da177e4SLinus Torvalds }
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds static int udp_sendpage(struct sock *sk, struct page *page, int offset,
6751da177e4SLinus Torvalds 			size_t size, int flags)
6761da177e4SLinus Torvalds {
6771da177e4SLinus Torvalds 	struct udp_sock *up = udp_sk(sk);
6781da177e4SLinus Torvalds 	int ret;
6791da177e4SLinus Torvalds 
6801da177e4SLinus Torvalds 	if (!up->pending) {
6811da177e4SLinus Torvalds 		struct msghdr msg = {	.msg_flags = flags|MSG_MORE };
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 		/* Call udp_sendmsg to specify destination address which
6841da177e4SLinus Torvalds 		 * sendpage interface can't pass.
6851da177e4SLinus Torvalds 		 * This will succeed only when the socket is connected.
6861da177e4SLinus Torvalds 		 */
6871da177e4SLinus Torvalds 		ret = udp_sendmsg(NULL, sk, &msg, 0);
6881da177e4SLinus Torvalds 		if (ret < 0)
6891da177e4SLinus Torvalds 			return ret;
6901da177e4SLinus Torvalds 	}
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds 	lock_sock(sk);
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	if (unlikely(!up->pending)) {
6951da177e4SLinus Torvalds 		release_sock(sk);
6961da177e4SLinus Torvalds 
69764ce2073SPatrick McHardy 		LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n");
6981da177e4SLinus Torvalds 		return -EINVAL;
6991da177e4SLinus Torvalds 	}
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	ret = ip_append_page(sk, page, offset, size, flags);
7021da177e4SLinus Torvalds 	if (ret == -EOPNOTSUPP) {
7031da177e4SLinus Torvalds 		release_sock(sk);
7041da177e4SLinus Torvalds 		return sock_no_sendpage(sk->sk_socket, page, offset,
7051da177e4SLinus Torvalds 					size, flags);
7061da177e4SLinus Torvalds 	}
7071da177e4SLinus Torvalds 	if (ret < 0) {
7081da177e4SLinus Torvalds 		udp_flush_pending_frames(sk);
7091da177e4SLinus Torvalds 		goto out;
7101da177e4SLinus Torvalds 	}
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds 	up->len += size;
7131da177e4SLinus Torvalds 	if (!(up->corkflag || (flags&MSG_MORE)))
7141da177e4SLinus Torvalds 		ret = udp_push_pending_frames(sk, up);
7151da177e4SLinus Torvalds 	if (!ret)
7161da177e4SLinus Torvalds 		ret = size;
7171da177e4SLinus Torvalds out:
7181da177e4SLinus Torvalds 	release_sock(sk);
7191da177e4SLinus Torvalds 	return ret;
7201da177e4SLinus Torvalds }
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds /*
7231da177e4SLinus Torvalds  *	IOCTL requests applicable to the UDP protocol
7241da177e4SLinus Torvalds  */
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
7271da177e4SLinus Torvalds {
7281da177e4SLinus Torvalds 	switch(cmd)
7291da177e4SLinus Torvalds 	{
7301da177e4SLinus Torvalds 		case SIOCOUTQ:
7311da177e4SLinus Torvalds 		{
7321da177e4SLinus Torvalds 			int amount = atomic_read(&sk->sk_wmem_alloc);
7331da177e4SLinus Torvalds 			return put_user(amount, (int __user *)arg);
7341da177e4SLinus Torvalds 		}
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds 		case SIOCINQ:
7371da177e4SLinus Torvalds 		{
7381da177e4SLinus Torvalds 			struct sk_buff *skb;
7391da177e4SLinus Torvalds 			unsigned long amount;
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds 			amount = 0;
742208d8984SHerbert Xu 			spin_lock_bh(&sk->sk_receive_queue.lock);
7431da177e4SLinus Torvalds 			skb = skb_peek(&sk->sk_receive_queue);
7441da177e4SLinus Torvalds 			if (skb != NULL) {
7451da177e4SLinus Torvalds 				/*
7461da177e4SLinus Torvalds 				 * We will only return the amount
7471da177e4SLinus Torvalds 				 * of this packet since that is all
7481da177e4SLinus Torvalds 				 * that will be read.
7491da177e4SLinus Torvalds 				 */
7501da177e4SLinus Torvalds 				amount = skb->len - sizeof(struct udphdr);
7511da177e4SLinus Torvalds 			}
752208d8984SHerbert Xu 			spin_unlock_bh(&sk->sk_receive_queue.lock);
7531da177e4SLinus Torvalds 			return put_user(amount, (int __user *)arg);
7541da177e4SLinus Torvalds 		}
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 		default:
7571da177e4SLinus Torvalds 			return -ENOIOCTLCMD;
7581da177e4SLinus Torvalds 	}
7591da177e4SLinus Torvalds 	return(0);
7601da177e4SLinus Torvalds }
7611da177e4SLinus Torvalds 
7621da177e4SLinus Torvalds static __inline__ int __udp_checksum_complete(struct sk_buff *skb)
7631da177e4SLinus Torvalds {
764fb286bb2SHerbert Xu 	return __skb_checksum_complete(skb);
7651da177e4SLinus Torvalds }
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds static __inline__ int udp_checksum_complete(struct sk_buff *skb)
7681da177e4SLinus Torvalds {
7691da177e4SLinus Torvalds 	return skb->ip_summed != CHECKSUM_UNNECESSARY &&
7701da177e4SLinus Torvalds 		__udp_checksum_complete(skb);
7711da177e4SLinus Torvalds }
7721da177e4SLinus Torvalds 
7731da177e4SLinus Torvalds /*
7741da177e4SLinus Torvalds  * 	This should be easy, if there is something there we
7751da177e4SLinus Torvalds  * 	return it, otherwise we block.
7761da177e4SLinus Torvalds  */
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds static int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
7791da177e4SLinus Torvalds 		       size_t len, int noblock, int flags, int *addr_len)
7801da177e4SLinus Torvalds {
7811da177e4SLinus Torvalds 	struct inet_sock *inet = inet_sk(sk);
7821da177e4SLinus Torvalds   	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
7831da177e4SLinus Torvalds   	struct sk_buff *skb;
7841da177e4SLinus Torvalds   	int copied, err;
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 	/*
7871da177e4SLinus Torvalds 	 *	Check any passed addresses
7881da177e4SLinus Torvalds 	 */
7891da177e4SLinus Torvalds 	if (addr_len)
7901da177e4SLinus Torvalds 		*addr_len=sizeof(*sin);
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds 	if (flags & MSG_ERRQUEUE)
7931da177e4SLinus Torvalds 		return ip_recv_error(sk, msg, len);
7941da177e4SLinus Torvalds 
7951da177e4SLinus Torvalds try_again:
7961da177e4SLinus Torvalds 	skb = skb_recv_datagram(sk, flags, noblock, &err);
7971da177e4SLinus Torvalds 	if (!skb)
7981da177e4SLinus Torvalds 		goto out;
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds   	copied = skb->len - sizeof(struct udphdr);
8011da177e4SLinus Torvalds 	if (copied > len) {
8021da177e4SLinus Torvalds 		copied = len;
8031da177e4SLinus Torvalds 		msg->msg_flags |= MSG_TRUNC;
8041da177e4SLinus Torvalds 	}
8051da177e4SLinus Torvalds 
8061da177e4SLinus Torvalds 	if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
8071da177e4SLinus Torvalds 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
8081da177e4SLinus Torvalds 					      copied);
8091da177e4SLinus Torvalds 	} else if (msg->msg_flags&MSG_TRUNC) {
8101da177e4SLinus Torvalds 		if (__udp_checksum_complete(skb))
8111da177e4SLinus Torvalds 			goto csum_copy_err;
8121da177e4SLinus Torvalds 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
8131da177e4SLinus Torvalds 					      copied);
8141da177e4SLinus Torvalds 	} else {
8151da177e4SLinus Torvalds 		err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds 		if (err == -EINVAL)
8181da177e4SLinus Torvalds 			goto csum_copy_err;
8191da177e4SLinus Torvalds 	}
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 	if (err)
8221da177e4SLinus Torvalds 		goto out_free;
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds 	sock_recv_timestamp(msg, sk, skb);
8251da177e4SLinus Torvalds 
8261da177e4SLinus Torvalds 	/* Copy the address. */
8271da177e4SLinus Torvalds 	if (sin)
8281da177e4SLinus Torvalds 	{
8291da177e4SLinus Torvalds 		sin->sin_family = AF_INET;
8301da177e4SLinus Torvalds 		sin->sin_port = skb->h.uh->source;
8311da177e4SLinus Torvalds 		sin->sin_addr.s_addr = skb->nh.iph->saddr;
8321da177e4SLinus Torvalds 		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
8331da177e4SLinus Torvalds   	}
8341da177e4SLinus Torvalds 	if (inet->cmsg_flags)
8351da177e4SLinus Torvalds 		ip_cmsg_recv(msg, skb);
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	err = copied;
8381da177e4SLinus Torvalds 	if (flags & MSG_TRUNC)
8391da177e4SLinus Torvalds 		err = skb->len - sizeof(struct udphdr);
8401da177e4SLinus Torvalds 
8411da177e4SLinus Torvalds out_free:
8421da177e4SLinus Torvalds   	skb_free_datagram(sk, skb);
8431da177e4SLinus Torvalds out:
8441da177e4SLinus Torvalds   	return err;
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds csum_copy_err:
8471da177e4SLinus Torvalds 	UDP_INC_STATS_BH(UDP_MIB_INERRORS);
8481da177e4SLinus Torvalds 
849*3305b80cSHerbert Xu 	skb_kill_datagram(sk, skb, flags);
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 	if (noblock)
8521da177e4SLinus Torvalds 		return -EAGAIN;
8531da177e4SLinus Torvalds 	goto try_again;
8541da177e4SLinus Torvalds }
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds 
8571da177e4SLinus Torvalds int udp_disconnect(struct sock *sk, int flags)
8581da177e4SLinus Torvalds {
8591da177e4SLinus Torvalds 	struct inet_sock *inet = inet_sk(sk);
8601da177e4SLinus Torvalds 	/*
8611da177e4SLinus Torvalds 	 *	1003.1g - break association.
8621da177e4SLinus Torvalds 	 */
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds 	sk->sk_state = TCP_CLOSE;
8651da177e4SLinus Torvalds 	inet->daddr = 0;
8661da177e4SLinus Torvalds 	inet->dport = 0;
8671da177e4SLinus Torvalds 	sk->sk_bound_dev_if = 0;
8681da177e4SLinus Torvalds 	if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
8691da177e4SLinus Torvalds 		inet_reset_saddr(sk);
8701da177e4SLinus Torvalds 
8711da177e4SLinus Torvalds 	if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) {
8721da177e4SLinus Torvalds 		sk->sk_prot->unhash(sk);
8731da177e4SLinus Torvalds 		inet->sport = 0;
8741da177e4SLinus Torvalds 	}
8751da177e4SLinus Torvalds 	sk_dst_reset(sk);
8761da177e4SLinus Torvalds 	return 0;
8771da177e4SLinus Torvalds }
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds static void udp_close(struct sock *sk, long timeout)
8801da177e4SLinus Torvalds {
8811da177e4SLinus Torvalds 	sk_common_release(sk);
8821da177e4SLinus Torvalds }
8831da177e4SLinus Torvalds 
8841da177e4SLinus Torvalds /* return:
8851da177e4SLinus Torvalds  * 	1  if the the UDP system should process it
8861da177e4SLinus Torvalds  *	0  if we should drop this packet
8871da177e4SLinus Torvalds  * 	-1 if it should get processed by xfrm4_rcv_encap
8881da177e4SLinus Torvalds  */
8891da177e4SLinus Torvalds static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
8901da177e4SLinus Torvalds {
8911da177e4SLinus Torvalds #ifndef CONFIG_XFRM
8921da177e4SLinus Torvalds 	return 1;
8931da177e4SLinus Torvalds #else
8941da177e4SLinus Torvalds 	struct udp_sock *up = udp_sk(sk);
8951da177e4SLinus Torvalds   	struct udphdr *uh = skb->h.uh;
8961da177e4SLinus Torvalds 	struct iphdr *iph;
8971da177e4SLinus Torvalds 	int iphlen, len;
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 	__u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr);
9001da177e4SLinus Torvalds 	__u32 *udpdata32 = (__u32 *)udpdata;
9011da177e4SLinus Torvalds 	__u16 encap_type = up->encap_type;
9021da177e4SLinus Torvalds 
9031da177e4SLinus Torvalds 	/* if we're overly short, let UDP handle it */
9041da177e4SLinus Torvalds 	if (udpdata > skb->tail)
9051da177e4SLinus Torvalds 		return 1;
9061da177e4SLinus Torvalds 
9071da177e4SLinus Torvalds 	/* if this is not encapsulated socket, then just return now */
9081da177e4SLinus Torvalds 	if (!encap_type)
9091da177e4SLinus Torvalds 		return 1;
9101da177e4SLinus Torvalds 
9111da177e4SLinus Torvalds 	len = skb->tail - udpdata;
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds 	switch (encap_type) {
9141da177e4SLinus Torvalds 	default:
9151da177e4SLinus Torvalds 	case UDP_ENCAP_ESPINUDP:
9161da177e4SLinus Torvalds 		/* Check if this is a keepalive packet.  If so, eat it. */
9171da177e4SLinus Torvalds 		if (len == 1 && udpdata[0] == 0xff) {
9181da177e4SLinus Torvalds 			return 0;
9191da177e4SLinus Torvalds 		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0 ) {
9201da177e4SLinus Torvalds 			/* ESP Packet without Non-ESP header */
9211da177e4SLinus Torvalds 			len = sizeof(struct udphdr);
9221da177e4SLinus Torvalds 		} else
9231da177e4SLinus Torvalds 			/* Must be an IKE packet.. pass it through */
9241da177e4SLinus Torvalds 			return 1;
9251da177e4SLinus Torvalds 		break;
9261da177e4SLinus Torvalds 	case UDP_ENCAP_ESPINUDP_NON_IKE:
9271da177e4SLinus Torvalds 		/* Check if this is a keepalive packet.  If so, eat it. */
9281da177e4SLinus Torvalds 		if (len == 1 && udpdata[0] == 0xff) {
9291da177e4SLinus Torvalds 			return 0;
9301da177e4SLinus Torvalds 		} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
9311da177e4SLinus Torvalds 			   udpdata32[0] == 0 && udpdata32[1] == 0) {
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds 			/* ESP Packet with Non-IKE marker */
9341da177e4SLinus Torvalds 			len = sizeof(struct udphdr) + 2 * sizeof(u32);
9351da177e4SLinus Torvalds 		} else
9361da177e4SLinus Torvalds 			/* Must be an IKE packet.. pass it through */
9371da177e4SLinus Torvalds 			return 1;
9381da177e4SLinus Torvalds 		break;
9391da177e4SLinus Torvalds 	}
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 	/* At this point we are sure that this is an ESPinUDP packet,
9421da177e4SLinus Torvalds 	 * so we need to remove 'len' bytes from the packet (the UDP
9431da177e4SLinus Torvalds 	 * header and optional ESP marker bytes) and then modify the
9441da177e4SLinus Torvalds 	 * protocol to ESP, and then call into the transform receiver.
9451da177e4SLinus Torvalds 	 */
9464d78b6c7SHerbert Xu 	if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
9474d78b6c7SHerbert Xu 		return 0;
9481da177e4SLinus Torvalds 
9491da177e4SLinus Torvalds 	/* Now we can update and verify the packet length... */
9501da177e4SLinus Torvalds 	iph = skb->nh.iph;
9511da177e4SLinus Torvalds 	iphlen = iph->ihl << 2;
9521da177e4SLinus Torvalds 	iph->tot_len = htons(ntohs(iph->tot_len) - len);
9531da177e4SLinus Torvalds 	if (skb->len < iphlen + len) {
9541da177e4SLinus Torvalds 		/* packet is too small!?! */
9551da177e4SLinus Torvalds 		return 0;
9561da177e4SLinus Torvalds 	}
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds 	/* pull the data buffer up to the ESP header and set the
9591da177e4SLinus Torvalds 	 * transport header to point to ESP.  Keep UDP on the stack
9601da177e4SLinus Torvalds 	 * for later.
9611da177e4SLinus Torvalds 	 */
9621da177e4SLinus Torvalds 	skb->h.raw = skb_pull(skb, len);
9631da177e4SLinus Torvalds 
9641da177e4SLinus Torvalds 	/* modify the protocol (it's ESP!) */
9651da177e4SLinus Torvalds 	iph->protocol = IPPROTO_ESP;
9661da177e4SLinus Torvalds 
9671da177e4SLinus Torvalds 	/* and let the caller know to send this into the ESP processor... */
9681da177e4SLinus Torvalds 	return -1;
9691da177e4SLinus Torvalds #endif
9701da177e4SLinus Torvalds }
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds /* returns:
9731da177e4SLinus Torvalds  *  -1: error
9741da177e4SLinus Torvalds  *   0: success
9751da177e4SLinus Torvalds  *  >0: "udp encap" protocol resubmission
9761da177e4SLinus Torvalds  *
9771da177e4SLinus Torvalds  * Note that in the success and error cases, the skb is assumed to
9781da177e4SLinus Torvalds  * have either been requeued or freed.
9791da177e4SLinus Torvalds  */
9801da177e4SLinus Torvalds static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
9811da177e4SLinus Torvalds {
9821da177e4SLinus Torvalds 	struct udp_sock *up = udp_sk(sk);
9831da177e4SLinus Torvalds 
9841da177e4SLinus Torvalds 	/*
9851da177e4SLinus Torvalds 	 *	Charge it to the socket, dropping if the queue is full.
9861da177e4SLinus Torvalds 	 */
9871da177e4SLinus Torvalds 	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
9881da177e4SLinus Torvalds 		kfree_skb(skb);
9891da177e4SLinus Torvalds 		return -1;
9901da177e4SLinus Torvalds 	}
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds 	if (up->encap_type) {
9931da177e4SLinus Torvalds 		/*
9941da177e4SLinus Torvalds 		 * This is an encapsulation socket, so let's see if this is
9951da177e4SLinus Torvalds 		 * an encapsulated packet.
9961da177e4SLinus Torvalds 		 * If it's a keepalive packet, then just eat it.
9971da177e4SLinus Torvalds 		 * If it's an encapsulateed packet, then pass it to the
9981da177e4SLinus Torvalds 		 * IPsec xfrm input and return the response
9991da177e4SLinus Torvalds 		 * appropriately.  Otherwise, just fall through and
10001da177e4SLinus Torvalds 		 * pass this up the UDP socket.
10011da177e4SLinus Torvalds 		 */
10021da177e4SLinus Torvalds 		int ret;
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds 		ret = udp_encap_rcv(sk, skb);
10051da177e4SLinus Torvalds 		if (ret == 0) {
10061da177e4SLinus Torvalds 			/* Eat the packet .. */
10071da177e4SLinus Torvalds 			kfree_skb(skb);
10081da177e4SLinus Torvalds 			return 0;
10091da177e4SLinus Torvalds 		}
10101da177e4SLinus Torvalds 		if (ret < 0) {
10111da177e4SLinus Torvalds 			/* process the ESP packet */
10121da177e4SLinus Torvalds 			ret = xfrm4_rcv_encap(skb, up->encap_type);
10131da177e4SLinus Torvalds 			UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);
10141da177e4SLinus Torvalds 			return -ret;
10151da177e4SLinus Torvalds 		}
10161da177e4SLinus Torvalds 		/* FALLTHROUGH -- it's a UDP Packet */
10171da177e4SLinus Torvalds 	}
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds 	if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
10201da177e4SLinus Torvalds 		if (__udp_checksum_complete(skb)) {
10211da177e4SLinus Torvalds 			UDP_INC_STATS_BH(UDP_MIB_INERRORS);
10221da177e4SLinus Torvalds 			kfree_skb(skb);
10231da177e4SLinus Torvalds 			return -1;
10241da177e4SLinus Torvalds 		}
10251da177e4SLinus Torvalds 		skb->ip_summed = CHECKSUM_UNNECESSARY;
10261da177e4SLinus Torvalds 	}
10271da177e4SLinus Torvalds 
10281da177e4SLinus Torvalds 	if (sock_queue_rcv_skb(sk,skb)<0) {
10291da177e4SLinus Torvalds 		UDP_INC_STATS_BH(UDP_MIB_INERRORS);
10301da177e4SLinus Torvalds 		kfree_skb(skb);
10311da177e4SLinus Torvalds 		return -1;
10321da177e4SLinus Torvalds 	}
10331da177e4SLinus Torvalds 	UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);
10341da177e4SLinus Torvalds 	return 0;
10351da177e4SLinus Torvalds }
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds /*
10381da177e4SLinus Torvalds  *	Multicasts and broadcasts go to each listener.
10391da177e4SLinus Torvalds  *
10401da177e4SLinus Torvalds  *	Note: called only from the BH handler context,
10411da177e4SLinus Torvalds  *	so we don't need to lock the hashes.
10421da177e4SLinus Torvalds  */
10431da177e4SLinus Torvalds static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
10441da177e4SLinus Torvalds 				 u32 saddr, u32 daddr)
10451da177e4SLinus Torvalds {
10461da177e4SLinus Torvalds 	struct sock *sk;
10471da177e4SLinus Torvalds 	int dif;
10481da177e4SLinus Torvalds 
10491da177e4SLinus Torvalds 	read_lock(&udp_hash_lock);
10501da177e4SLinus Torvalds 	sk = sk_head(&udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]);
10511da177e4SLinus Torvalds 	dif = skb->dev->ifindex;
10521da177e4SLinus Torvalds 	sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
10531da177e4SLinus Torvalds 	if (sk) {
10541da177e4SLinus Torvalds 		struct sock *sknext = NULL;
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds 		do {
10571da177e4SLinus Torvalds 			struct sk_buff *skb1 = skb;
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 			sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr,
10601da177e4SLinus Torvalds 						   uh->source, saddr, dif);
10611da177e4SLinus Torvalds 			if(sknext)
10621da177e4SLinus Torvalds 				skb1 = skb_clone(skb, GFP_ATOMIC);
10631da177e4SLinus Torvalds 
10641da177e4SLinus Torvalds 			if(skb1) {
10651da177e4SLinus Torvalds 				int ret = udp_queue_rcv_skb(sk, skb1);
10661da177e4SLinus Torvalds 				if (ret > 0)
10671da177e4SLinus Torvalds 					/* we should probably re-process instead
10681da177e4SLinus Torvalds 					 * of dropping packets here. */
10691da177e4SLinus Torvalds 					kfree_skb(skb1);
10701da177e4SLinus Torvalds 			}
10711da177e4SLinus Torvalds 			sk = sknext;
10721da177e4SLinus Torvalds 		} while(sknext);
10731da177e4SLinus Torvalds 	} else
10741da177e4SLinus Torvalds 		kfree_skb(skb);
10751da177e4SLinus Torvalds 	read_unlock(&udp_hash_lock);
10761da177e4SLinus Torvalds 	return 0;
10771da177e4SLinus Torvalds }
10781da177e4SLinus Torvalds 
10791da177e4SLinus Torvalds /* Initialize UDP checksum. If exited with zero value (success),
10801da177e4SLinus Torvalds  * CHECKSUM_UNNECESSARY means, that no more checks are required.
10811da177e4SLinus Torvalds  * Otherwise, csum completion requires chacksumming packet body,
10821da177e4SLinus Torvalds  * including udp header and folding it to skb->csum.
10831da177e4SLinus Torvalds  */
10841da177e4SLinus Torvalds static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
10851da177e4SLinus Torvalds 			     unsigned short ulen, u32 saddr, u32 daddr)
10861da177e4SLinus Torvalds {
10871da177e4SLinus Torvalds 	if (uh->check == 0) {
10881da177e4SLinus Torvalds 		skb->ip_summed = CHECKSUM_UNNECESSARY;
10891da177e4SLinus Torvalds 	} else if (skb->ip_summed == CHECKSUM_HW) {
10901da177e4SLinus Torvalds 		if (!udp_check(uh, ulen, saddr, daddr, skb->csum))
1091fb286bb2SHerbert Xu 			skb->ip_summed = CHECKSUM_UNNECESSARY;
10921da177e4SLinus Torvalds 	}
10931da177e4SLinus Torvalds 	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
10941da177e4SLinus Torvalds 		skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
10951da177e4SLinus Torvalds 	/* Probably, we should checksum udp header (it should be in cache
10961da177e4SLinus Torvalds 	 * in any case) and data in tiny packets (< rx copybreak).
10971da177e4SLinus Torvalds 	 */
10981da177e4SLinus Torvalds 	return 0;
10991da177e4SLinus Torvalds }
11001da177e4SLinus Torvalds 
11011da177e4SLinus Torvalds /*
11021da177e4SLinus Torvalds  *	All we need to do is get the socket, and then do a checksum.
11031da177e4SLinus Torvalds  */
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds int udp_rcv(struct sk_buff *skb)
11061da177e4SLinus Torvalds {
11071da177e4SLinus Torvalds   	struct sock *sk;
11081da177e4SLinus Torvalds   	struct udphdr *uh;
11091da177e4SLinus Torvalds 	unsigned short ulen;
11101da177e4SLinus Torvalds 	struct rtable *rt = (struct rtable*)skb->dst;
11111da177e4SLinus Torvalds 	u32 saddr = skb->nh.iph->saddr;
11121da177e4SLinus Torvalds 	u32 daddr = skb->nh.iph->daddr;
11131da177e4SLinus Torvalds 	int len = skb->len;
11141da177e4SLinus Torvalds 
11151da177e4SLinus Torvalds 	/*
11161da177e4SLinus Torvalds 	 *	Validate the packet and the UDP length.
11171da177e4SLinus Torvalds 	 */
11181da177e4SLinus Torvalds 	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
11191da177e4SLinus Torvalds 		goto no_header;
11201da177e4SLinus Torvalds 
11211da177e4SLinus Torvalds 	uh = skb->h.uh;
11221da177e4SLinus Torvalds 
11231da177e4SLinus Torvalds 	ulen = ntohs(uh->len);
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds 	if (ulen > len || ulen < sizeof(*uh))
11261da177e4SLinus Torvalds 		goto short_packet;
11271da177e4SLinus Torvalds 
1128e308e25cSStephen Hemminger 	if (pskb_trim_rcsum(skb, ulen))
11291da177e4SLinus Torvalds 		goto short_packet;
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds 	if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)
11321da177e4SLinus Torvalds 		goto csum_error;
11331da177e4SLinus Torvalds 
11341da177e4SLinus Torvalds 	if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
11351da177e4SLinus Torvalds 		return udp_v4_mcast_deliver(skb, uh, saddr, daddr);
11361da177e4SLinus Torvalds 
11371da177e4SLinus Torvalds 	sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex);
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds 	if (sk != NULL) {
11401da177e4SLinus Torvalds 		int ret = udp_queue_rcv_skb(sk, skb);
11411da177e4SLinus Torvalds 		sock_put(sk);
11421da177e4SLinus Torvalds 
11431da177e4SLinus Torvalds 		/* a return value > 0 means to resubmit the input, but
11441da177e4SLinus Torvalds 		 * it it wants the return to be -protocol, or 0
11451da177e4SLinus Torvalds 		 */
11461da177e4SLinus Torvalds 		if (ret > 0)
11471da177e4SLinus Torvalds 			return -ret;
11481da177e4SLinus Torvalds 		return 0;
11491da177e4SLinus Torvalds 	}
11501da177e4SLinus Torvalds 
11511da177e4SLinus Torvalds 	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
11521da177e4SLinus Torvalds 		goto drop;
11531da177e4SLinus Torvalds 
11541da177e4SLinus Torvalds 	/* No socket. Drop packet silently, if checksum is wrong */
11551da177e4SLinus Torvalds 	if (udp_checksum_complete(skb))
11561da177e4SLinus Torvalds 		goto csum_error;
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 	UDP_INC_STATS_BH(UDP_MIB_NOPORTS);
11591da177e4SLinus Torvalds 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
11601da177e4SLinus Torvalds 
11611da177e4SLinus Torvalds 	/*
11621da177e4SLinus Torvalds 	 * Hmm.  We got an UDP packet to a port to which we
11631da177e4SLinus Torvalds 	 * don't wanna listen.  Ignore it.
11641da177e4SLinus Torvalds 	 */
11651da177e4SLinus Torvalds 	kfree_skb(skb);
11661da177e4SLinus Torvalds 	return(0);
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds short_packet:
116964ce2073SPatrick McHardy 	LIMIT_NETDEBUG(KERN_DEBUG "UDP: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n",
11701da177e4SLinus Torvalds 		       NIPQUAD(saddr),
11711da177e4SLinus Torvalds 		       ntohs(uh->source),
11721da177e4SLinus Torvalds 		       ulen,
11731da177e4SLinus Torvalds 		       len,
11741da177e4SLinus Torvalds 		       NIPQUAD(daddr),
117564ce2073SPatrick McHardy 		       ntohs(uh->dest));
11761da177e4SLinus Torvalds no_header:
11771da177e4SLinus Torvalds 	UDP_INC_STATS_BH(UDP_MIB_INERRORS);
11781da177e4SLinus Torvalds 	kfree_skb(skb);
11791da177e4SLinus Torvalds 	return(0);
11801da177e4SLinus Torvalds 
11811da177e4SLinus Torvalds csum_error:
11821da177e4SLinus Torvalds 	/*
11831da177e4SLinus Torvalds 	 * RFC1122: OK.  Discards the bad packet silently (as far as
11841da177e4SLinus Torvalds 	 * the network is concerned, anyway) as per 4.1.3.4 (MUST).
11851da177e4SLinus Torvalds 	 */
118664ce2073SPatrick McHardy 	LIMIT_NETDEBUG(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",
11871da177e4SLinus Torvalds 		       NIPQUAD(saddr),
11881da177e4SLinus Torvalds 		       ntohs(uh->source),
11891da177e4SLinus Torvalds 		       NIPQUAD(daddr),
11901da177e4SLinus Torvalds 		       ntohs(uh->dest),
119164ce2073SPatrick McHardy 		       ulen);
11921da177e4SLinus Torvalds drop:
11931da177e4SLinus Torvalds 	UDP_INC_STATS_BH(UDP_MIB_INERRORS);
11941da177e4SLinus Torvalds 	kfree_skb(skb);
11951da177e4SLinus Torvalds 	return(0);
11961da177e4SLinus Torvalds }
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds static int udp_destroy_sock(struct sock *sk)
11991da177e4SLinus Torvalds {
12001da177e4SLinus Torvalds 	lock_sock(sk);
12011da177e4SLinus Torvalds 	udp_flush_pending_frames(sk);
12021da177e4SLinus Torvalds 	release_sock(sk);
12031da177e4SLinus Torvalds 	return 0;
12041da177e4SLinus Torvalds }
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds /*
12071da177e4SLinus Torvalds  *	Socket option code for UDP
12081da177e4SLinus Torvalds  */
12091da177e4SLinus Torvalds static int udp_setsockopt(struct sock *sk, int level, int optname,
12101da177e4SLinus Torvalds 			  char __user *optval, int optlen)
12111da177e4SLinus Torvalds {
12121da177e4SLinus Torvalds 	struct udp_sock *up = udp_sk(sk);
12131da177e4SLinus Torvalds 	int val;
12141da177e4SLinus Torvalds 	int err = 0;
12151da177e4SLinus Torvalds 
12161da177e4SLinus Torvalds 	if (level != SOL_UDP)
12171da177e4SLinus Torvalds 		return ip_setsockopt(sk, level, optname, optval, optlen);
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 	if(optlen<sizeof(int))
12201da177e4SLinus Torvalds 		return -EINVAL;
12211da177e4SLinus Torvalds 
12221da177e4SLinus Torvalds 	if (get_user(val, (int __user *)optval))
12231da177e4SLinus Torvalds 		return -EFAULT;
12241da177e4SLinus Torvalds 
12251da177e4SLinus Torvalds 	switch(optname) {
12261da177e4SLinus Torvalds 	case UDP_CORK:
12271da177e4SLinus Torvalds 		if (val != 0) {
12281da177e4SLinus Torvalds 			up->corkflag = 1;
12291da177e4SLinus Torvalds 		} else {
12301da177e4SLinus Torvalds 			up->corkflag = 0;
12311da177e4SLinus Torvalds 			lock_sock(sk);
12321da177e4SLinus Torvalds 			udp_push_pending_frames(sk, up);
12331da177e4SLinus Torvalds 			release_sock(sk);
12341da177e4SLinus Torvalds 		}
12351da177e4SLinus Torvalds 		break;
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds 	case UDP_ENCAP:
12381da177e4SLinus Torvalds 		switch (val) {
12391da177e4SLinus Torvalds 		case 0:
12401da177e4SLinus Torvalds 		case UDP_ENCAP_ESPINUDP:
12411da177e4SLinus Torvalds 		case UDP_ENCAP_ESPINUDP_NON_IKE:
12421da177e4SLinus Torvalds 			up->encap_type = val;
12431da177e4SLinus Torvalds 			break;
12441da177e4SLinus Torvalds 		default:
12451da177e4SLinus Torvalds 			err = -ENOPROTOOPT;
12461da177e4SLinus Torvalds 			break;
12471da177e4SLinus Torvalds 		}
12481da177e4SLinus Torvalds 		break;
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 	default:
12511da177e4SLinus Torvalds 		err = -ENOPROTOOPT;
12521da177e4SLinus Torvalds 		break;
12531da177e4SLinus Torvalds 	};
12541da177e4SLinus Torvalds 
12551da177e4SLinus Torvalds 	return err;
12561da177e4SLinus Torvalds }
12571da177e4SLinus Torvalds 
12581da177e4SLinus Torvalds static int udp_getsockopt(struct sock *sk, int level, int optname,
12591da177e4SLinus Torvalds 			  char __user *optval, int __user *optlen)
12601da177e4SLinus Torvalds {
12611da177e4SLinus Torvalds 	struct udp_sock *up = udp_sk(sk);
12621da177e4SLinus Torvalds 	int val, len;
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 	if (level != SOL_UDP)
12651da177e4SLinus Torvalds 		return ip_getsockopt(sk, level, optname, optval, optlen);
12661da177e4SLinus Torvalds 
12671da177e4SLinus Torvalds 	if(get_user(len,optlen))
12681da177e4SLinus Torvalds 		return -EFAULT;
12691da177e4SLinus Torvalds 
12701da177e4SLinus Torvalds 	len = min_t(unsigned int, len, sizeof(int));
12711da177e4SLinus Torvalds 
12721da177e4SLinus Torvalds 	if(len < 0)
12731da177e4SLinus Torvalds 		return -EINVAL;
12741da177e4SLinus Torvalds 
12751da177e4SLinus Torvalds 	switch(optname) {
12761da177e4SLinus Torvalds 	case UDP_CORK:
12771da177e4SLinus Torvalds 		val = up->corkflag;
12781da177e4SLinus Torvalds 		break;
12791da177e4SLinus Torvalds 
12801da177e4SLinus Torvalds 	case UDP_ENCAP:
12811da177e4SLinus Torvalds 		val = up->encap_type;
12821da177e4SLinus Torvalds 		break;
12831da177e4SLinus Torvalds 
12841da177e4SLinus Torvalds 	default:
12851da177e4SLinus Torvalds 		return -ENOPROTOOPT;
12861da177e4SLinus Torvalds 	};
12871da177e4SLinus Torvalds 
12881da177e4SLinus Torvalds   	if(put_user(len, optlen))
12891da177e4SLinus Torvalds   		return -EFAULT;
12901da177e4SLinus Torvalds 	if(copy_to_user(optval, &val,len))
12911da177e4SLinus Torvalds 		return -EFAULT;
12921da177e4SLinus Torvalds   	return 0;
12931da177e4SLinus Torvalds }
12941da177e4SLinus Torvalds 
12951da177e4SLinus Torvalds /**
12961da177e4SLinus Torvalds  * 	udp_poll - wait for a UDP event.
12971da177e4SLinus Torvalds  *	@file - file struct
12981da177e4SLinus Torvalds  *	@sock - socket
12991da177e4SLinus Torvalds  *	@wait - poll table
13001da177e4SLinus Torvalds  *
13011da177e4SLinus Torvalds  *	This is same as datagram poll, except for the special case of
13021da177e4SLinus Torvalds  *	blocking sockets. If application is using a blocking fd
13031da177e4SLinus Torvalds  *	and a packet with checksum error is in the queue;
13041da177e4SLinus Torvalds  *	then it could get return from select indicating data available
13051da177e4SLinus Torvalds  *	but then block when reading it. Add special case code
13061da177e4SLinus Torvalds  *	to work around these arguably broken applications.
13071da177e4SLinus Torvalds  */
13081da177e4SLinus Torvalds unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
13091da177e4SLinus Torvalds {
13101da177e4SLinus Torvalds 	unsigned int mask = datagram_poll(file, sock, wait);
13111da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
13121da177e4SLinus Torvalds 
13131da177e4SLinus Torvalds 	/* Check for false positives due to checksum errors */
13141da177e4SLinus Torvalds 	if ( (mask & POLLRDNORM) &&
13151da177e4SLinus Torvalds 	     !(file->f_flags & O_NONBLOCK) &&
13161da177e4SLinus Torvalds 	     !(sk->sk_shutdown & RCV_SHUTDOWN)){
13171da177e4SLinus Torvalds 		struct sk_buff_head *rcvq = &sk->sk_receive_queue;
13181da177e4SLinus Torvalds 		struct sk_buff *skb;
13191da177e4SLinus Torvalds 
1320208d8984SHerbert Xu 		spin_lock_bh(&rcvq->lock);
13211da177e4SLinus Torvalds 		while ((skb = skb_peek(rcvq)) != NULL) {
13221da177e4SLinus Torvalds 			if (udp_checksum_complete(skb)) {
13231da177e4SLinus Torvalds 				UDP_INC_STATS_BH(UDP_MIB_INERRORS);
13241da177e4SLinus Torvalds 				__skb_unlink(skb, rcvq);
13251da177e4SLinus Torvalds 				kfree_skb(skb);
13261da177e4SLinus Torvalds 			} else {
13271da177e4SLinus Torvalds 				skb->ip_summed = CHECKSUM_UNNECESSARY;
13281da177e4SLinus Torvalds 				break;
13291da177e4SLinus Torvalds 			}
13301da177e4SLinus Torvalds 		}
1331208d8984SHerbert Xu 		spin_unlock_bh(&rcvq->lock);
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 		/* nothing to see, move along */
13341da177e4SLinus Torvalds 		if (skb == NULL)
13351da177e4SLinus Torvalds 			mask &= ~(POLLIN | POLLRDNORM);
13361da177e4SLinus Torvalds 	}
13371da177e4SLinus Torvalds 
13381da177e4SLinus Torvalds 	return mask;
13391da177e4SLinus Torvalds 
13401da177e4SLinus Torvalds }
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds struct proto udp_prot = {
13431da177e4SLinus Torvalds  	.name =		"UDP",
13441da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
13451da177e4SLinus Torvalds 	.close =	udp_close,
13461da177e4SLinus Torvalds 	.connect =	ip4_datagram_connect,
13471da177e4SLinus Torvalds 	.disconnect =	udp_disconnect,
13481da177e4SLinus Torvalds 	.ioctl =	udp_ioctl,
13491da177e4SLinus Torvalds 	.destroy =	udp_destroy_sock,
13501da177e4SLinus Torvalds 	.setsockopt =	udp_setsockopt,
13511da177e4SLinus Torvalds 	.getsockopt =	udp_getsockopt,
13521da177e4SLinus Torvalds 	.sendmsg =	udp_sendmsg,
13531da177e4SLinus Torvalds 	.recvmsg =	udp_recvmsg,
13541da177e4SLinus Torvalds 	.sendpage =	udp_sendpage,
13551da177e4SLinus Torvalds 	.backlog_rcv =	udp_queue_rcv_skb,
13561da177e4SLinus Torvalds 	.hash =		udp_v4_hash,
13571da177e4SLinus Torvalds 	.unhash =	udp_v4_unhash,
13581da177e4SLinus Torvalds 	.get_port =	udp_v4_get_port,
13591da177e4SLinus Torvalds 	.obj_size =	sizeof(struct udp_sock),
13601da177e4SLinus Torvalds };
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds /* ------------------------------------------------------------------------ */
13631da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
13641da177e4SLinus Torvalds 
13651da177e4SLinus Torvalds static struct sock *udp_get_first(struct seq_file *seq)
13661da177e4SLinus Torvalds {
13671da177e4SLinus Torvalds 	struct sock *sk;
13681da177e4SLinus Torvalds 	struct udp_iter_state *state = seq->private;
13691da177e4SLinus Torvalds 
13701da177e4SLinus Torvalds 	for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) {
13711da177e4SLinus Torvalds 		struct hlist_node *node;
13721da177e4SLinus Torvalds 		sk_for_each(sk, node, &udp_hash[state->bucket]) {
13731da177e4SLinus Torvalds 			if (sk->sk_family == state->family)
13741da177e4SLinus Torvalds 				goto found;
13751da177e4SLinus Torvalds 		}
13761da177e4SLinus Torvalds 	}
13771da177e4SLinus Torvalds 	sk = NULL;
13781da177e4SLinus Torvalds found:
13791da177e4SLinus Torvalds 	return sk;
13801da177e4SLinus Torvalds }
13811da177e4SLinus Torvalds 
13821da177e4SLinus Torvalds static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk)
13831da177e4SLinus Torvalds {
13841da177e4SLinus Torvalds 	struct udp_iter_state *state = seq->private;
13851da177e4SLinus Torvalds 
13861da177e4SLinus Torvalds 	do {
13871da177e4SLinus Torvalds 		sk = sk_next(sk);
13881da177e4SLinus Torvalds try_again:
13891da177e4SLinus Torvalds 		;
13901da177e4SLinus Torvalds 	} while (sk && sk->sk_family != state->family);
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	if (!sk && ++state->bucket < UDP_HTABLE_SIZE) {
13931da177e4SLinus Torvalds 		sk = sk_head(&udp_hash[state->bucket]);
13941da177e4SLinus Torvalds 		goto try_again;
13951da177e4SLinus Torvalds 	}
13961da177e4SLinus Torvalds 	return sk;
13971da177e4SLinus Torvalds }
13981da177e4SLinus Torvalds 
13991da177e4SLinus Torvalds static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos)
14001da177e4SLinus Torvalds {
14011da177e4SLinus Torvalds 	struct sock *sk = udp_get_first(seq);
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds 	if (sk)
14041da177e4SLinus Torvalds 		while(pos && (sk = udp_get_next(seq, sk)) != NULL)
14051da177e4SLinus Torvalds 			--pos;
14061da177e4SLinus Torvalds 	return pos ? NULL : sk;
14071da177e4SLinus Torvalds }
14081da177e4SLinus Torvalds 
14091da177e4SLinus Torvalds static void *udp_seq_start(struct seq_file *seq, loff_t *pos)
14101da177e4SLinus Torvalds {
14111da177e4SLinus Torvalds 	read_lock(&udp_hash_lock);
14121da177e4SLinus Torvalds 	return *pos ? udp_get_idx(seq, *pos-1) : (void *)1;
14131da177e4SLinus Torvalds }
14141da177e4SLinus Torvalds 
14151da177e4SLinus Torvalds static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
14161da177e4SLinus Torvalds {
14171da177e4SLinus Torvalds 	struct sock *sk;
14181da177e4SLinus Torvalds 
14191da177e4SLinus Torvalds 	if (v == (void *)1)
14201da177e4SLinus Torvalds 		sk = udp_get_idx(seq, 0);
14211da177e4SLinus Torvalds 	else
14221da177e4SLinus Torvalds 		sk = udp_get_next(seq, v);
14231da177e4SLinus Torvalds 
14241da177e4SLinus Torvalds 	++*pos;
14251da177e4SLinus Torvalds 	return sk;
14261da177e4SLinus Torvalds }
14271da177e4SLinus Torvalds 
14281da177e4SLinus Torvalds static void udp_seq_stop(struct seq_file *seq, void *v)
14291da177e4SLinus Torvalds {
14301da177e4SLinus Torvalds 	read_unlock(&udp_hash_lock);
14311da177e4SLinus Torvalds }
14321da177e4SLinus Torvalds 
14331da177e4SLinus Torvalds static int udp_seq_open(struct inode *inode, struct file *file)
14341da177e4SLinus Torvalds {
14351da177e4SLinus Torvalds 	struct udp_seq_afinfo *afinfo = PDE(inode)->data;
14361da177e4SLinus Torvalds 	struct seq_file *seq;
14371da177e4SLinus Torvalds 	int rc = -ENOMEM;
14381da177e4SLinus Torvalds 	struct udp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
14391da177e4SLinus Torvalds 
14401da177e4SLinus Torvalds 	if (!s)
14411da177e4SLinus Torvalds 		goto out;
14421da177e4SLinus Torvalds 	memset(s, 0, sizeof(*s));
14431da177e4SLinus Torvalds 	s->family		= afinfo->family;
14441da177e4SLinus Torvalds 	s->seq_ops.start	= udp_seq_start;
14451da177e4SLinus Torvalds 	s->seq_ops.next		= udp_seq_next;
14461da177e4SLinus Torvalds 	s->seq_ops.show		= afinfo->seq_show;
14471da177e4SLinus Torvalds 	s->seq_ops.stop		= udp_seq_stop;
14481da177e4SLinus Torvalds 
14491da177e4SLinus Torvalds 	rc = seq_open(file, &s->seq_ops);
14501da177e4SLinus Torvalds 	if (rc)
14511da177e4SLinus Torvalds 		goto out_kfree;
14521da177e4SLinus Torvalds 
14531da177e4SLinus Torvalds 	seq	     = file->private_data;
14541da177e4SLinus Torvalds 	seq->private = s;
14551da177e4SLinus Torvalds out:
14561da177e4SLinus Torvalds 	return rc;
14571da177e4SLinus Torvalds out_kfree:
14581da177e4SLinus Torvalds 	kfree(s);
14591da177e4SLinus Torvalds 	goto out;
14601da177e4SLinus Torvalds }
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds /* ------------------------------------------------------------------------ */
14631da177e4SLinus Torvalds int udp_proc_register(struct udp_seq_afinfo *afinfo)
14641da177e4SLinus Torvalds {
14651da177e4SLinus Torvalds 	struct proc_dir_entry *p;
14661da177e4SLinus Torvalds 	int rc = 0;
14671da177e4SLinus Torvalds 
14681da177e4SLinus Torvalds 	if (!afinfo)
14691da177e4SLinus Torvalds 		return -EINVAL;
14701da177e4SLinus Torvalds 	afinfo->seq_fops->owner		= afinfo->owner;
14711da177e4SLinus Torvalds 	afinfo->seq_fops->open		= udp_seq_open;
14721da177e4SLinus Torvalds 	afinfo->seq_fops->read		= seq_read;
14731da177e4SLinus Torvalds 	afinfo->seq_fops->llseek	= seq_lseek;
14741da177e4SLinus Torvalds 	afinfo->seq_fops->release	= seq_release_private;
14751da177e4SLinus Torvalds 
14761da177e4SLinus Torvalds 	p = proc_net_fops_create(afinfo->name, S_IRUGO, afinfo->seq_fops);
14771da177e4SLinus Torvalds 	if (p)
14781da177e4SLinus Torvalds 		p->data = afinfo;
14791da177e4SLinus Torvalds 	else
14801da177e4SLinus Torvalds 		rc = -ENOMEM;
14811da177e4SLinus Torvalds 	return rc;
14821da177e4SLinus Torvalds }
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds void udp_proc_unregister(struct udp_seq_afinfo *afinfo)
14851da177e4SLinus Torvalds {
14861da177e4SLinus Torvalds 	if (!afinfo)
14871da177e4SLinus Torvalds 		return;
14881da177e4SLinus Torvalds 	proc_net_remove(afinfo->name);
14891da177e4SLinus Torvalds 	memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
14901da177e4SLinus Torvalds }
14911da177e4SLinus Torvalds 
14921da177e4SLinus Torvalds /* ------------------------------------------------------------------------ */
14931da177e4SLinus Torvalds static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket)
14941da177e4SLinus Torvalds {
14951da177e4SLinus Torvalds 	struct inet_sock *inet = inet_sk(sp);
14961da177e4SLinus Torvalds 	unsigned int dest = inet->daddr;
14971da177e4SLinus Torvalds 	unsigned int src  = inet->rcv_saddr;
14981da177e4SLinus Torvalds 	__u16 destp	  = ntohs(inet->dport);
14991da177e4SLinus Torvalds 	__u16 srcp	  = ntohs(inet->sport);
15001da177e4SLinus Torvalds 
15011da177e4SLinus Torvalds 	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
15021da177e4SLinus Torvalds 		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
15031da177e4SLinus Torvalds 		bucket, src, srcp, dest, destp, sp->sk_state,
15041da177e4SLinus Torvalds 		atomic_read(&sp->sk_wmem_alloc),
15051da177e4SLinus Torvalds 		atomic_read(&sp->sk_rmem_alloc),
15061da177e4SLinus Torvalds 		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
15071da177e4SLinus Torvalds 		atomic_read(&sp->sk_refcnt), sp);
15081da177e4SLinus Torvalds }
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds static int udp4_seq_show(struct seq_file *seq, void *v)
15111da177e4SLinus Torvalds {
15121da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN)
15131da177e4SLinus Torvalds 		seq_printf(seq, "%-127s\n",
15141da177e4SLinus Torvalds 			   "  sl  local_address rem_address   st tx_queue "
15151da177e4SLinus Torvalds 			   "rx_queue tr tm->when retrnsmt   uid  timeout "
15161da177e4SLinus Torvalds 			   "inode");
15171da177e4SLinus Torvalds 	else {
15181da177e4SLinus Torvalds 		char tmpbuf[129];
15191da177e4SLinus Torvalds 		struct udp_iter_state *state = seq->private;
15201da177e4SLinus Torvalds 
15211da177e4SLinus Torvalds 		udp4_format_sock(v, tmpbuf, state->bucket);
15221da177e4SLinus Torvalds 		seq_printf(seq, "%-127s\n", tmpbuf);
15231da177e4SLinus Torvalds 	}
15241da177e4SLinus Torvalds 	return 0;
15251da177e4SLinus Torvalds }
15261da177e4SLinus Torvalds 
15271da177e4SLinus Torvalds /* ------------------------------------------------------------------------ */
15281da177e4SLinus Torvalds static struct file_operations udp4_seq_fops;
15291da177e4SLinus Torvalds static struct udp_seq_afinfo udp4_seq_afinfo = {
15301da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
15311da177e4SLinus Torvalds 	.name		= "udp",
15321da177e4SLinus Torvalds 	.family		= AF_INET,
15331da177e4SLinus Torvalds 	.seq_show	= udp4_seq_show,
15341da177e4SLinus Torvalds 	.seq_fops	= &udp4_seq_fops,
15351da177e4SLinus Torvalds };
15361da177e4SLinus Torvalds 
15371da177e4SLinus Torvalds int __init udp4_proc_init(void)
15381da177e4SLinus Torvalds {
15391da177e4SLinus Torvalds 	return udp_proc_register(&udp4_seq_afinfo);
15401da177e4SLinus Torvalds }
15411da177e4SLinus Torvalds 
15421da177e4SLinus Torvalds void udp4_proc_exit(void)
15431da177e4SLinus Torvalds {
15441da177e4SLinus Torvalds 	udp_proc_unregister(&udp4_seq_afinfo);
15451da177e4SLinus Torvalds }
15461da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
15471da177e4SLinus Torvalds 
15481da177e4SLinus Torvalds EXPORT_SYMBOL(udp_disconnect);
15491da177e4SLinus Torvalds EXPORT_SYMBOL(udp_hash);
15501da177e4SLinus Torvalds EXPORT_SYMBOL(udp_hash_lock);
15511da177e4SLinus Torvalds EXPORT_SYMBOL(udp_ioctl);
15521da177e4SLinus Torvalds EXPORT_SYMBOL(udp_port_rover);
15531da177e4SLinus Torvalds EXPORT_SYMBOL(udp_prot);
15541da177e4SLinus Torvalds EXPORT_SYMBOL(udp_sendmsg);
15551da177e4SLinus Torvalds EXPORT_SYMBOL(udp_poll);
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
15581da177e4SLinus Torvalds EXPORT_SYMBOL(udp_proc_register);
15591da177e4SLinus Torvalds EXPORT_SYMBOL(udp_proc_unregister);
15601da177e4SLinus Torvalds #endif
1561