/*
       * INET		An implementation of the TCP/IP protocol suite for the LINUX
       *		operating system.  INET is implemented using the  BSD Socket
       *		interface as the means of communication with the user level.
       *
       *		The User Datagram Protocol (UDP).
       *
       * Version:	$Id: udp.c,v 1.91 2000/11/28 13:38:38 davem Exp $
       *
       * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
       *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
       *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
       *		Alan Cox, <Alan.Cox@linux.org>
       *
       * Fixes:
       *		Alan Cox	:	verify_area() calls
       *		Alan Cox	: 	stopped close while in use off icmp
       *					messages. Not a fix but a botch that
       *					for udp at least is 'valid'.
       *		Alan Cox	:	Fixed icmp handling properly
       *		Alan Cox	: 	Correct error for oversized datagrams
       *		Alan Cox	:	Tidied select() semantics. 
       *		Alan Cox	:	udp_err() fixed properly, also now 
       *					select and read wake correctly on errors
       *		Alan Cox	:	udp_send verify_area moved to avoid mem leak
       *		Alan Cox	:	UDP can count its memory
       *		Alan Cox	:	send to an unknown connection causes
       *					an ECONNREFUSED off the icmp, but
       *					does NOT close.
       *		Alan Cox	:	Switched to new sk_buff handlers. No more backlog!
       *		Alan Cox	:	Using generic datagram code. Even smaller and the PEEK
       *					bug no longer crashes it.
       *		Fred Van Kempen	: 	Net2e support for sk->broadcast.
       *		Alan Cox	:	Uses skb_free_datagram
       *		Alan Cox	:	Added get/set sockopt support.
       *		Alan Cox	:	Broadcasting without option set returns EACCES.
       *		Alan Cox	:	No wakeup calls. Instead we now use the callbacks.
       *		Alan Cox	:	Use ip_tos and ip_ttl
       *		Alan Cox	:	SNMP Mibs
       *		Alan Cox	:	MSG_DONTROUTE, and 0.0.0.0 support.
       *		Matt Dillon	:	UDP length checks.
       *		Alan Cox	:	Smarter af_inet used properly.
       *		Alan Cox	:	Use new kernel side addressing.
       *		Alan Cox	:	Incorrect return on truncated datagram receive.
       *	Arnt Gulbrandsen 	:	New udp_send and stuff
       *		Alan Cox	:	Cache last socket
       *		Alan Cox	:	Route cache
       *		Jon Peatfield	:	Minor efficiency fix to sendto().
       *		Mike Shaver	:	RFC1122 checks.
       *		Alan Cox	:	Nonblocking error fix.
       *	Willy Konynenberg	:	Transparent proxying support.
       *		Mike McLagan	:	Routing by source
       *		David S. Miller	:	New socket lookup architecture.
       *					Last socket cache retained as it
       *					does have a high hit rate.
       *		Olaf Kirch	:	Don't linearise iovec on sendmsg.
       *		Andi Kleen	:	Some cleanups, cache destination entry
       *					for connect. 
       *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
       *		Melvin Smith	:	Check msg_name not msg_namelen in sendto(),
       *					return ENOTCONN for unconnected sockets (POSIX)
       *		Janos Farkas	:	don't deliver multi/broadcasts to a different
       *					bound-to-device socket
       *
       *
       *		This program is free software; you can redistribute it and/or
       *		modify it under the terms of the GNU General Public License
       *		as published by the Free Software Foundation; either version
       *		2 of the License, or (at your option) any later version.
       */
       
      /* RFC1122 Status:
         4.1.3.1 (Ports):
           SHOULD send ICMP_PORT_UNREACHABLE in response to datagrams to 
             an un-listened port. (OK)
         4.1.3.2 (IP Options)
           MUST pass IP options from IP -> application (OK)
           MUST allow application to specify IP options (OK)
         4.1.3.3 (ICMP Messages)
           MUST pass ICMP error messages to application (OK -- except when SO_BSDCOMPAT is set)
         4.1.3.4 (UDP Checksums)
           MUST provide facility for checksumming (OK)
           MAY allow application to control checksumming (OK)
           MUST default to checksumming on (OK)
           MUST discard silently datagrams with bad csums (OK, except during debugging)
         4.1.3.5 (UDP Multihoming)
           MUST allow application to specify source address (OK)
           SHOULD be able to communicate the chosen src addr up to application
             when application doesn't choose (DOES - use recvmsg cmsgs)
         4.1.3.6 (Invalid Addresses)
           MUST discard invalid source addresses (OK -- done in the new routing code)
           MUST only send datagrams with one of our addresses (OK)
      */
      
      #include <asm/system.h>
      #include <asm/uaccess.h>
      #include <linux/types.h>
      #include <linux/fcntl.h>
      #include <linux/socket.h>
      #include <linux/sockios.h>
      #include <linux/in.h>
      #include <linux/errno.h>
      #include <linux/timer.h>
      #include <linux/mm.h>
      #include <linux/config.h>
      #include <linux/inet.h>
      #include <linux/netdevice.h>
      #include <net/snmp.h>
      #include <net/ip.h>
      #include <net/protocol.h>
      #include <linux/skbuff.h>
      #include <net/sock.h>
      #include <net/udp.h>
      #include <net/icmp.h>
      #include <net/route.h>
      #include <net/inet_common.h>
      #include <net/checksum.h>
      
      /*
       *	Snmp MIB for the UDP layer
       */
      
      struct udp_mib		udp_statistics[NR_CPUS*2];
      
      struct sock *udp_hash[UDP_HTABLE_SIZE];
      rwlock_t udp_hash_lock = RW_LOCK_UNLOCKED;
      
      /* Shared by v4/v6 udp. */
      int udp_port_rover;
      
 131  static int udp_v4_get_port(struct sock *sk, unsigned short snum)
      {
 133  	write_lock_bh(&udp_hash_lock);
 134  	if (snum == 0) {
      		int best_size_so_far, best, result, i;
      
      		if (udp_port_rover > sysctl_local_port_range[1] ||
 138  		    udp_port_rover < sysctl_local_port_range[0])
      			udp_port_rover = sysctl_local_port_range[0];
      		best_size_so_far = 32767;
      		best = result = udp_port_rover;
 142  		for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
      			struct sock *sk;
      			int size;
      
      			sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
 147  			if (!sk) {
 148  				if (result > sysctl_local_port_range[1])
      					result = sysctl_local_port_range[0] +
      						((result - sysctl_local_port_range[0]) &
      						 (UDP_HTABLE_SIZE - 1));
 152  				goto gotit;
      			}
      			size = 0;
 155  			do {
 156  				if (++size >= best_size_so_far)
 157  					goto next;
 158  			} while ((sk = sk->next) != NULL);
      			best_size_so_far = size;
      			best = result;
      		next:;
      		}
      		result = best;
 164  		for(;; result += UDP_HTABLE_SIZE) {
 165  			if (result > sysctl_local_port_range[1])
      				result = sysctl_local_port_range[0]
      					+ ((result - sysctl_local_port_range[0]) &
      					   (UDP_HTABLE_SIZE - 1));
 169  			if (!udp_lport_inuse(result))
 170  				break;
      		}
      gotit:
      		udp_port_rover = snum = result;
 174  	} else {
      		struct sock *sk2;
      
      		for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
 178  		     sk2 != NULL;
      		     sk2 = sk2->next) {
      			if (sk2->num == snum &&
      			    sk2 != sk &&
      			    sk2->bound_dev_if == sk->bound_dev_if &&
      			    (!sk2->rcv_saddr ||
      			     !sk->rcv_saddr ||
      			     sk2->rcv_saddr == sk->rcv_saddr) &&
 186  			    (!sk2->reuse || !sk->reuse))
 187  				goto fail;
      		}
      	}
      	sk->num = snum;
 191  	if (sk->pprev == NULL) {
      		struct sock **skp = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
 193  		if ((sk->next = *skp) != NULL)
      			(*skp)->pprev = &sk->next;
      		*skp = sk;
      		sk->pprev = skp;
      		sock_prot_inc_use(sk->prot);
      		sock_hold(sk);
      	}
 200  	write_unlock_bh(&udp_hash_lock);
 201  	return 0;
      
      fail:
 204  	write_unlock_bh(&udp_hash_lock);
 205  	return 1;
      }
      
 208  static void udp_v4_hash(struct sock *sk)
      {
 210  	BUG();
      }
      
 213  static void udp_v4_unhash(struct sock *sk)
      {
 215  	write_lock_bh(&udp_hash_lock);
 216  	if (sk->pprev) {
 217  		if (sk->next)
      			sk->next->pprev = sk->pprev;
      		*sk->pprev = sk->next;
      		sk->pprev = NULL;
      		sk->num = 0;
      		sock_prot_dec_use(sk->prot);
      		__sock_put(sk);
      	}
 225  	write_unlock_bh(&udp_hash_lock);
      }
      
      /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
       * harder than this. -DaveM
       */
 231  struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif)
      {
      	struct sock *sk, *result = NULL;
      	unsigned short hnum = ntohs(dport);
      	int badness = -1;
      
 237  	for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
 238  		if(sk->num == hnum) {
      			int score = 0;
 240  			if(sk->rcv_saddr) {
 241  				if(sk->rcv_saddr != daddr)
 242  					continue;
      				score++;
      			}
 245  			if(sk->daddr) {
 246  				if(sk->daddr != saddr)
 247  					continue;
      				score++;
      			}
 250  			if(sk->dport) {
 251  				if(sk->dport != sport)
 252  					continue;
      				score++;
      			}
 255  			if(sk->bound_dev_if) {
 256  				if(sk->bound_dev_if != dif)
 257  					continue;
      				score++;
      			}
 260  			if(score == 4) {
      				result = sk;
 262  				break;
 263  			} else if(score > badness) {
      				result = sk;
      				badness = score;
      			}
      		}
      	}
 269  	return result;
      }
      
 272  __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif)
      {
      	struct sock *sk;
      
      	read_lock(&udp_hash_lock);
      	sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif);
 278  	if (sk)
      		sock_hold(sk);
 280  	read_unlock(&udp_hash_lock);
 281  	return sk;
      }
      
 284  static inline struct sock *udp_v4_mcast_next(struct sock *sk,
      					     u16 loc_port, u32 loc_addr,
      					     u16 rmt_port, u32 rmt_addr,
      					     int dif)
      {
      	struct sock *s = sk;
      	unsigned short hnum = ntohs(loc_port);
 291  	for(; s; s = s->next) {
      		if ((s->num != hnum)					||
      		    (s->daddr && s->daddr!=rmt_addr)			||
      		    (s->dport != rmt_port && s->dport != 0)			||
      		    (s->rcv_saddr  && s->rcv_saddr != loc_addr)		||
 296  		    (s->bound_dev_if && s->bound_dev_if != dif))
 297  			continue;
 298  		break;
        	}
 300    	return s;
      }
      
      /*
       * This routine is called by the ICMP module when it gets some
       * sort of error condition.  If err < 0 then the socket should
       * be closed and the error returned to the user.  If err > 0
       * it's just the icmp type << 8 | icmp code.  
       * Header points to the ip header of the error packet. We move
       * on past this. Then (as it used to claim before adjustment)
       * header points to the first 8 bytes of the udp header.  We need
       * to find the appropriate port.
       */
      
 314  void udp_err(struct sk_buff *skb, unsigned char *dp, int len)
      {
      	struct iphdr *iph = (struct iphdr*)dp;
      	struct udphdr *uh = (struct udphdr*)(dp+(iph->ihl<<2));
      	int type = skb->h.icmph->type;
      	int code = skb->h.icmph->code;
      	struct sock *sk;
      	int harderr;
      	u32 info;
      	int err;
      
 325  	if (len < (iph->ihl<<2)+sizeof(struct udphdr)) {
      		ICMP_INC_STATS_BH(IcmpInErrors);
 327  		return;
      	}
      
      	sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex);
 331  	if (sk == NULL) {
      		ICMP_INC_STATS_BH(IcmpInErrors);
 333      	  	return;	/* No socket for error */
      	}
      
      	err = 0;
      	info = 0;
      	harderr = 0;
      
 340  	switch (type) {
 341  	default:
 342  	case ICMP_TIME_EXCEEDED:
      		err = EHOSTUNREACH;
 344  		break;
 345  	case ICMP_SOURCE_QUENCH:
 346  		goto out;
 347  	case ICMP_PARAMETERPROB:
      		err = EPROTO;
      		info = ntohl(skb->h.icmph->un.gateway)>>24;
      		harderr = 1;
 351  		break;
 352  	case ICMP_DEST_UNREACH:
 353  		if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
 354  			if (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT) {
      				err = EMSGSIZE;
      				info = ntohs(skb->h.icmph->un.frag.mtu);
      				harderr = 1;
 358  				break;
      			}
 360  			goto out;
      		}
      		err = EHOSTUNREACH;
 363  		if (code <= NR_ICMP_UNREACH) {
      			harderr = icmp_err_convert[code].fatal;
      			err = icmp_err_convert[code].errno;
      		}
 367  		break;
      	}
      
      	/*
      	 *      RFC1122: OK.  Passes ICMP errors back to application, as per 
      	 *	4.1.3.3.
      	 */
 374  	if (!sk->protinfo.af_inet.recverr) {
 375  		if (!harderr || sk->state != TCP_ESTABLISHED)
 376  			goto out;
 377  	} else {
      		ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1));
      	}
      	sk->err = err;
      	sk->error_report(sk);
      out:
      	sock_put(sk);
      }
      
      
 387  static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base)
      {
 389  	return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
      }
      
      struct udpfakehdr 
      {
      	struct udphdr uh;
      	u32 saddr;
      	u32 daddr;
      	struct iovec *iov;
      	u32 wcheck;
      };
      
      /*
       *	Copy and checksum a UDP packet from user space into a buffer. We still have
       *	to do the planning to get ip_build_xmit to spot direct transfer to network
       *	card and provide an additional callback mode for direct user->board I/O
       *	transfers. That one will be fun.
       */
       
 408  static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) 
      {
      	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
 411  	if (offset==0) {
      		if (csum_partial_copy_fromiovecend(to+sizeof(struct udphdr), ufh->iov, offset,
 413  						   fraglen-sizeof(struct udphdr), &ufh->wcheck))
 414  			return -EFAULT;
       		ufh->wcheck = csum_partial((char *)ufh, sizeof(struct udphdr),
      					   ufh->wcheck);
      		ufh->uh.check = csum_tcpudp_magic(ufh->saddr, ufh->daddr, 
      					  ntohs(ufh->uh.len),
      					  IPPROTO_UDP, ufh->wcheck);
 420  		if (ufh->uh.check == 0)
      			ufh->uh.check = -1;
      		memcpy(to, ufh, sizeof(struct udphdr));
 423  		return 0;
      	}
      	if (csum_partial_copy_fromiovecend(to, ufh->iov, offset-sizeof(struct udphdr),
 426  					   fraglen, &ufh->wcheck))
 427  		return -EFAULT;
 428  	return 0;
      }
      
      /*
       *	Unchecksummed UDP is sufficiently critical to stuff like ATM video conferencing
       *	that we use two routines for this for speed. Probably we ought to have a
       *	CONFIG_FAST_NET set for >10Mb/second boards to activate this sort of coding.
       *	Timing needed to verify if this is a valid decision.
       */
       
 438  static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen) 
      {
      	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
      
 442  	if (offset==0) {
      		memcpy(to, ufh, sizeof(struct udphdr));
      		return memcpy_fromiovecend(to+sizeof(struct udphdr), ufh->iov, offset,
 445  					   fraglen-sizeof(struct udphdr));
      	}
      	return memcpy_fromiovecend(to, ufh->iov, offset-sizeof(struct udphdr),
 448  				   fraglen);
      }
      
 451  int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
      {
      	int ulen = len + sizeof(struct udphdr);
      	struct ipcm_cookie ipc;
      	struct udpfakehdr ufh;
      	struct rtable *rt = NULL;
      	int free = 0;
      	int connected = 0;
      	u32 daddr;
      	u8  tos;
      	int err;
      
      	/* This check is ONLY to check for arithmetic overflow
      	   on integer(!) len. Not more! Real check will be made
      	   in ip_build_xmit --ANK
      
      	   BTW socket.c -> af_*.c -> ... make multiple
      	   invalid conversions size_t -> int. We MUST repair it f.e.
      	   by replacing all of them with size_t and revise all
      	   the places sort of len += sizeof(struct iphdr)
      	   If len was ULONG_MAX-10 it would be cathastrophe  --ANK
      	 */
      
 474  	if (len < 0 || len > 0xFFFF)
 475  		return -EMSGSIZE;
      
      	/* 
      	 *	Check the flags.
      	 */
      
 481  	if (msg->msg_flags&MSG_OOB)	/* Mirror BSD error message compatibility */
 482  		return -EOPNOTSUPP;
      
      	/*
      	 *	Get and verify the address. 
      	 */
      	 
 488  	if (msg->msg_name) {
      		struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
 490  		if (msg->msg_namelen < sizeof(*usin))
 491  			return -EINVAL;
 492  		if (usin->sin_family != AF_INET) {
 493  			if (usin->sin_family != AF_UNSPEC)
 494  				return -EINVAL;
      		}
      
      		ufh.daddr = usin->sin_addr.s_addr;
      		ufh.uh.dest = usin->sin_port;
 499  		if (ufh.uh.dest == 0)
 500  			return -EINVAL;
 501  	} else {
 502  		if (sk->state != TCP_ESTABLISHED)
 503  			return -ENOTCONN;
      		ufh.daddr = sk->daddr;
      		ufh.uh.dest = sk->dport;
      		/* Open fast path for connected socket.
      		   Route will not be used, if at least one option is set.
      		 */
      		connected = 1;
        	}
      	ipc.addr = sk->saddr;
      	ufh.uh.source = sk->sport;
      
      	ipc.opt = NULL;
      	ipc.oif = sk->bound_dev_if;
 516  	if (msg->msg_controllen) {
      		err = ip_cmsg_send(msg, &ipc);
 518  		if (err)
 519  			return err;
 520  		if (ipc.opt)
      			free = 1;
      		connected = 0;
      	}
 524  	if (!ipc.opt)
      		ipc.opt = sk->protinfo.af_inet.opt;
      
      	ufh.saddr = ipc.addr;
      	ipc.addr = daddr = ufh.daddr;
      
 530  	if (ipc.opt && ipc.opt->srr) {
 531  		if (!daddr)
 532  			return -EINVAL;
      		daddr = ipc.opt->faddr;
      		connected = 0;
      	}
      	tos = RT_TOS(sk->protinfo.af_inet.tos);
      	if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) || 
 538  	    (ipc.opt && ipc.opt->is_strictroute)) {
      		tos |= RTO_ONLINK;
      		connected = 0;
      	}
      
 543  	if (MULTICAST(daddr)) {
 544  		if (!ipc.oif)
      			ipc.oif = sk->protinfo.af_inet.mc_index;
 546  		if (!ufh.saddr)
      			ufh.saddr = sk->protinfo.af_inet.mc_addr;
      		connected = 0;
      	}
      
 551  	if (connected)
      		rt = (struct rtable*)sk_dst_check(sk, 0);
      
 554  	if (rt == NULL) {
      		err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
 556  		if (err)
 557  			goto out;
      
      		err = -EACCES;
 560  		if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) 
 561  			goto out;
 562  		if (connected)
      			sk_dst_set(sk, dst_clone(&rt->u.dst));
      	}
      
 566  	if (msg->msg_flags&MSG_CONFIRM)
 567  		goto do_confirm;
      back_from_confirm:
      
      	ufh.saddr = rt->rt_src;
 571  	if (!ipc.addr)
      		ufh.daddr = ipc.addr = rt->rt_dst;
      	ufh.uh.len = htons(ulen);
      	ufh.uh.check = 0;
      	ufh.iov = msg->msg_iov;
      	ufh.wcheck = 0;
      
      	/* RFC1122: OK.  Provides the checksumming facility (MUST) as per */
      	/* 4.1.3.4. It's configurable by the application via setsockopt() */
      	/* (MAY) and it defaults to on (MUST). */
      
      	err = ip_build_xmit(sk,
      			    (sk->no_check == UDP_CSUM_NOXMIT ?
      			     udp_getfrag_nosum :
      			     udp_getfrag),
      			    &ufh, ulen, &ipc, rt, msg->msg_flags);
      
      out:
      	ip_rt_put(rt);
 590  	if (free)
      		kfree(ipc.opt);
 592  	if (!err) {
      		UDP_INC_STATS_USER(UdpOutDatagrams);
 594  		return len;
      	}
 596  	return err;
      
      do_confirm:
      	dst_confirm(&rt->u.dst);
 600  	if (!(msg->msg_flags&MSG_PROBE) || len)
 601  		goto back_from_confirm;
      	err = 0;
 603  	goto out;
      }
      
      /*
       *	IOCTL requests applicable to the UDP protocol
       */
       
 610  int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
      {
 612  	switch(cmd) 
      	{
 614  		case SIOCOUTQ:
      		{
      			int amount = atomic_read(&sk->wmem_alloc);
 617  			return put_user(amount, (int *)arg);
      		}
      
 620  		case SIOCINQ:
      		{
      			struct sk_buff *skb;
      			unsigned long amount;
      
      			amount = 0;
 626  			spin_lock_irq(&sk->receive_queue.lock);
      			skb = skb_peek(&sk->receive_queue);
 628  			if (skb != NULL) {
      				/*
      				 * We will only return the amount
      				 * of this packet since that is all
      				 * that will be read.
      				 */
      				amount = skb->len - sizeof(struct udphdr);
      			}
 636  			spin_unlock_irq(&sk->receive_queue.lock);
 637  			return put_user(amount, (int *)arg);
      		}
      
 640  		default:
 641  			return -ENOIOCTLCMD;
      	}
 643  	return(0);
      }
      
 646  static __inline__ int __udp_checksum_complete(struct sk_buff *skb)
      {
 648  	return (unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum));
      }
      
 651  static __inline__ int udp_checksum_complete(struct sk_buff *skb)
      {
      	return skb->ip_summed != CHECKSUM_UNNECESSARY &&
 654  		__udp_checksum_complete(skb);
      }
      
      /*
       * 	This should be easy, if there is something there we
       * 	return it, otherwise we block.
       */
      
 662  int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
      		int noblock, int flags, int *addr_len)
      {
        	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
        	struct sk_buff *skb;
        	int copied, err;
      
      	/*
      	 *	Check any passed addresses
      	 */
 672  	if (addr_len)
      		*addr_len=sizeof(*sin);
      
 675  	if (flags & MSG_ERRQUEUE)
 676  		return ip_recv_error(sk, msg, len);
      
      	/*
      	 *	From here the generic datagram does a lot of the work. Come
      	 *	the finished NET3, it will do _ALL_ the work!
      	 */
      
      	skb = skb_recv_datagram(sk, flags, noblock, &err);
 684  	if (!skb)
 685  		goto out;
        
        	copied = skb->len - sizeof(struct udphdr);
 688  	if (copied > len) {
      		copied = len;
      		msg->msg_flags |= MSG_TRUNC;
      	}
      
 693  	if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
      		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
      					      copied);
 696  	} else if (msg->msg_flags&MSG_TRUNC) {
 697  		if (__udp_checksum_complete(skb))
 698  			goto csum_copy_err;
      		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
      					      copied);
 701  	} else {
      		err = copy_and_csum_toiovec(msg->msg_iov, skb, sizeof(struct udphdr));
      
 704  		if (err)
 705  			goto csum_copy_err;
      	}
      
 708  	if (err)
 709  		goto out_free;
      
      	sock_recv_timestamp(msg, sk, skb);
      
      	/* Copy the address. */
 714  	if (sin)
      	{
      		sin->sin_family = AF_INET;
      		sin->sin_port = skb->h.uh->source;
      		sin->sin_addr.s_addr = skb->nh.iph->saddr;
      		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
        	}
 721  	if (sk->protinfo.af_inet.cmsg_flags)
      		ip_cmsg_recv(msg, skb);
      	err = copied;
        
      out_free:
        	skb_free_datagram(sk, skb);
      out:
 728    	return err;
      
      csum_copy_err:
      	UDP_INC_STATS_BH(UdpInErrors);
      
      	/* Clear queue. */
 734  	if (flags&MSG_PEEK) {
      		int clear = 0;
 736  		spin_lock_irq(&sk->receive_queue.lock);
 737  		if (skb == skb_peek(&sk->receive_queue)) {
      			__skb_unlink(skb, &sk->receive_queue);
      			clear = 1;
      		}
 741  		spin_unlock_irq(&sk->receive_queue.lock);
 742  		if (clear)
      			kfree_skb(skb);
      	}
      
      	skb_free_datagram(sk, skb);
      
 748  	return -EAGAIN;	
      }
      
 751  int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
      {
      	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
      	struct rtable *rt;
      	int err;
      
      	
 758  	if (addr_len < sizeof(*usin)) 
 759  	  	return -EINVAL;
      
 761  	if (usin->sin_family != AF_INET) 
 762  	  	return -EAFNOSUPPORT;
      
      	sk_dst_reset(sk);
      
      	err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
      			       sk->protinfo.af_inet.tos|sk->localroute, sk->bound_dev_if);
 768  	if (err)
 769  		return err;
 770  	if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) {
      		ip_rt_put(rt);
 772  		return -EACCES;
      	}
 774    	if(!sk->saddr)
      	  	sk->saddr = rt->rt_src;		/* Update source address */
 776  	if(!sk->rcv_saddr)
      		sk->rcv_saddr = rt->rt_src;
      	sk->daddr = rt->rt_dst;
      	sk->dport = usin->sin_port;
      	sk->state = TCP_ESTABLISHED;
      
      	sk_dst_set(sk, &rt->u.dst);
 783  	return(0);
      }
      
 786  int udp_disconnect(struct sock *sk, int flags)
      {
      	/*
      	 *	1003.1g - break association.
      	 */
      	 
      	sk->state = TCP_CLOSE;
      	sk->daddr = 0;
      	sk->dport = 0;
      	sk->bound_dev_if = 0;
 796  	if (!(sk->userlocks&SOCK_BINDADDR_LOCK)) {
      		sk->rcv_saddr = 0;
      		sk->saddr = 0;
      #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
      		memset(&sk->net_pinfo.af_inet6.saddr, 0, 16);
      		memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, 16);
      #endif
      	}
 804  	if (!(sk->userlocks&SOCK_BINDPORT_LOCK)) {
      		sk->prot->unhash(sk);
      		sk->sport = 0;
      	}
      	sk_dst_reset(sk);
 809  	return 0;
      }
      
 812  static void udp_close(struct sock *sk, long timeout)
      {
      	inet_sock_release(sk);
      }
      
 817  static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
      {
      	/*
      	 *	Charge it to the socket, dropping if the queue is full.
      	 */
      
      #if defined(CONFIG_FILTER)
      	if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
      		if (__udp_checksum_complete(skb)) {
      			UDP_INC_STATS_BH(UdpInErrors);
      			IP_INC_STATS_BH(IpInDiscards);
      			ip_statistics[smp_processor_id()*2].IpInDelivers--;
      			kfree_skb(skb);
      			return -1;
      		}
      		skb->ip_summed = CHECKSUM_UNNECESSARY;
      	}
      #endif
      
 836  	if (sock_queue_rcv_skb(sk,skb)<0) {
      		UDP_INC_STATS_BH(UdpInErrors);
      		IP_INC_STATS_BH(IpInDiscards);
      		ip_statistics[smp_processor_id()*2].IpInDelivers--;
      		kfree_skb(skb);
 841  		return -1;
      	}
      	UDP_INC_STATS_BH(UdpInDatagrams);
 844  	return 0;
      }
      
      /*
       *	Multicasts and broadcasts go to each listener.
       *
       *	Note: called only from the BH handler context,
       *	so we don't need to lock the hashes.
       */
 853  static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
      				 u32 saddr, u32 daddr)
      {
      	struct sock *sk;
      	int dif;
      
      	read_lock(&udp_hash_lock);
      	sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
      	dif = skb->dev->ifindex;
      	sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
 863  	if (sk) {
      		struct sock *sknext = NULL;
      
 866  		do {
      			struct sk_buff *skb1 = skb;
      
      			sknext = udp_v4_mcast_next(sk->next, uh->dest, daddr,
      						   uh->source, saddr, dif);
 871  			if(sknext)
      				skb1 = skb_clone(skb, GFP_ATOMIC);
      
 874  			if(skb1)
      				udp_queue_rcv_skb(sk, skb1);
      			sk = sknext;
 877  		} while(sknext);
 878  	} else
      		kfree_skb(skb);
 880  	read_unlock(&udp_hash_lock);
 881  	return 0;
      }
      
      /* Initialize UDP checksum. If exited with zero value (success),
       * CHECKSUM_UNNECESSARY means, that no more checks are required.
       * Otherwise, csum completion requires chacksumming packet body,
       * including udp header and folding it to skb->csum.
       */
 889  static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
      			     unsigned short ulen, u32 saddr, u32 daddr)
      {
 892  	if (uh->check == 0) {
      		skb->ip_summed = CHECKSUM_UNNECESSARY;
 894  	} else if (skb->ip_summed == CHECKSUM_HW) {
 895  		if (udp_check(uh, ulen, saddr, daddr, skb->csum))
 896  			return -1;
      		skb->ip_summed = CHECKSUM_UNNECESSARY;
 898  	} else if (skb->ip_summed != CHECKSUM_UNNECESSARY)
      		skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
      	/* Probably, we should checksum udp header (it should be in cache
      	 * in any case) and data in tiny packets (< rx copybreak).
      	 */
 903  	return 0;
      }
      
      /*
       *	All we need to do is get the socket, and then do a checksum. 
       */
       
 910  int udp_rcv(struct sk_buff *skb, unsigned short len)
      {
        	struct sock *sk;
        	struct udphdr *uh;
      	unsigned short ulen;
      	struct rtable *rt = (struct rtable*)skb->dst;
      	u32 saddr = skb->nh.iph->saddr;
      	u32 daddr = skb->nh.iph->daddr;
      
      	/*
      	 *	Get the header.
      	 */
      	 
        	uh = skb->h.uh;
      	__skb_pull(skb, skb->h.raw - skb->data);
      
        	IP_INC_STATS_BH(IpInDelivers);
      
      	/*
      	 *	Validate the packet and the UDP length.
      	 */
      	 
      	ulen = ntohs(uh->len);
      
 934  	if (ulen > len || ulen < sizeof(*uh)) {
 935  		NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
      		UDP_INC_STATS_BH(UdpInErrors);
      		kfree_skb(skb);
 938  		return(0);
      	}
      	skb_trim(skb, ulen);
      
 942  	if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0)
 943  		goto csum_error;
      
 945  	if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
 946  		return udp_v4_mcast_deliver(skb, uh, saddr, daddr);
      
      	sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex);
      
 950  	if (sk != NULL) {
      		udp_queue_rcv_skb(sk, skb);
      		sock_put(sk);
 953  		return 0;
      	}
      
      	/* No socket. Drop packet silently, if checksum is wrong */
 957  	if (udp_checksum_complete(skb))
 958  		goto csum_error;
      
      	UDP_INC_STATS_BH(UdpNoPorts);
      	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
      
      	/*
      	 * Hmm.  We got an UDP packet to a port to which we
      	 * don't wanna listen.  Ignore it.
      	 */
      	kfree_skb(skb);
 968  	return(0);
      
      csum_error:
      	/* 
      	 * RFC1122: OK.  Discards the bad packet silently (as far as 
      	 * the network is concerned, anyway) as per 4.1.3.4 (MUST). 
      	 */
 975  	NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",
      			NIPQUAD(saddr),
      			ntohs(uh->source),
      			NIPQUAD(daddr),
      			ntohs(uh->dest),
 980  			ulen));
      	UDP_INC_STATS_BH(UdpInErrors);
      	kfree_skb(skb);
 983  	return(0);
      }
      
 986  static void get_udp_sock(struct sock *sp, char *tmpbuf, int i)
      {
      	unsigned int dest, src;
      	__u16 destp, srcp;
      
      	dest  = sp->daddr;
      	src   = sp->rcv_saddr;
      	destp = ntohs(sp->dport);
      	srcp  = ntohs(sp->sport);
      	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
      		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p",
      		i, src, srcp, dest, destp, sp->state, 
      		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
      		0, 0L, 0,
      		sock_i_uid(sp), 0,
      		sock_i_ino(sp),
      		atomic_read(&sp->refcnt), sp);
      }
      
1005  int udp_get_info(char *buffer, char **start, off_t offset, int length)
      {
      	int len = 0, num = 0, i;
      	off_t pos = 0;
      	off_t begin;
      	char tmpbuf[129];
      
1012  	if (offset < 128) 
      		len += sprintf(buffer, "%-127s\n",
      			       "  sl  local_address rem_address   st tx_queue "
      			       "rx_queue tr tm->when retrnsmt   uid  timeout inode");
      	pos = 128;
      	read_lock(&udp_hash_lock);
1018  	for (i = 0; i < UDP_HTABLE_SIZE; i++) {
      		struct sock *sk;
      
1021  		for (sk = udp_hash[i]; sk; sk = sk->next, num++) {
1022  			if (sk->family != PF_INET)
1023  				continue;
      			pos += 128;
1025  			if (pos <= offset)
1026  				continue;
      			get_udp_sock(sk, tmpbuf, i);
      			len += sprintf(buffer+len, "%-127s\n", tmpbuf);
1029  			if(len >= length)
1030  				goto out;
      		}
      	}
      out:
1034  	read_unlock(&udp_hash_lock);
      	begin = len - (pos - offset);
      	*start = buffer + begin;
      	len -= begin;
1038  	if(len > length)
      		len = length;
1040  	if (len < 0)
      		len = 0; 
1042  	return len;
      }
      
      struct proto udp_prot = {
       	name:		"UDP",
      	close:		udp_close,
      	connect:	udp_connect,
      	disconnect:	udp_disconnect,
      	ioctl:		udp_ioctl,
      	setsockopt:	ip_setsockopt,
      	getsockopt:	ip_getsockopt,
      	sendmsg:	udp_sendmsg,
      	recvmsg:	udp_recvmsg,
      	backlog_rcv:	udp_queue_rcv_skb,
      	hash:		udp_v4_hash,
      	unhash:		udp_v4_unhash,
      	get_port:	udp_v4_get_port,
      };