HTONS(ip->ip_len); HTONS(ip->ip_id); HTONS(ip->ip_off);
static	struct mbuf *udp_saveopt __P((caddr_t, int, int));#ifndef UDBHASHSIZE#define	UDBHASHSIZE	128#endifint	udbhashsize = UDBHASHSIZE;/* from in_pcb.c */extern	struct baddynamicports baddynamicports;voidudp_init(){	in_pcbinit(&udbtable, udbhashsize);}void#if __STDC__udp_input(struct mbuf *m, ...)#elseudp_input(m, va_alist)	struct mbuf *m;	va_dcl#endif{	register struct ip *ip;	register struct udphdr *uh;	register struct inpcb *inp;	struct mbuf *opts = 0;	int len;	struct ip save_ip;	int iphlen;	va_list ap;	va_start(ap, m);	iphlen = va_arg(ap, int);	va_end(ap);	udpstat.udps_ipackets++;	/*	 * Strip IP options, if any; should skip this,	 * make available to user, and use on returned packets,	 * but we don't yet have a way to check the checksum	 * with options still present.	 */	if (iphlen > sizeof (struct ip)) {		ip_stripoptions(m, (struct mbuf *)0);		iphlen = sizeof(struct ip);	}	/*	 * Get IP and UDP header together in first mbuf.	 */	ip = mtod(m, struct ip *);	if (m->m_len < iphlen + sizeof(struct udphdr)) {		if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {			udpstat.udps_hdrops++;			return;		}		ip = mtod(m, struct ip *);	}	uh = (struct udphdr *)((caddr_t)ip + iphlen);	/*	 * Make mbuf data length reflect UDP length.	 * If not enough data to reflect UDP length, drop.	 */	len = ntohs((u_int16_t)uh->uh_ulen);	if (ip->ip_len != len) {		if (len > ip->ip_len || len < sizeof(struct udphdr)) {			udpstat.udps_badlen++;			goto bad;		}		m_adj(m, len - ip->ip_len);		/* ip->ip_len = len; */	}	/*	 * Save a copy of the IP header in case we want restore it	 * for sending an ICMP error message in response.	 */	save_ip = *ip;	/*	 * Checksum extended UDP header and data.	 * from W.R.Stevens: check incoming udp cksums even if	 *	udpcksum is not set.	 */	if (uh->uh_sum) {		bzero(((struct ipovly *)ip)->ih_x1,		    sizeof ((struct ipovly *)ip)->ih_x1);		((struct ipovly *)ip)->ih_len = uh->uh_ulen;		if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) != 0) {			udpstat.udps_badsum++;			m_freem(m);			return;		}	}	if (IN_MULTICAST(ip->ip_dst.s_addr) ||	    in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {		struct socket *last;		/*		 * Deliver a multicast or broadcast datagram to *all* sockets		 * for which the local and remote addresses and ports match		 * those of the incoming datagram.  This allows more than		 * one process to receive multi/broadcasts on the same port.		 * (This really ought to be done for unicast datagrams as		 * well, but that would cause problems with existing		 * applications that open both address-specific sockets and		 * a wildcard socket listening to the same port -- they would		 * end up receiving duplicates of every unicast datagram.		 * Those applications open the multiple sockets to overcome an		 * inadequacy of the UDP socket interface, but for backwards		 * compatibility we avoid the problem here rather than		 * fixing the interface.  Maybe 4.5BSD will remedy this?)		 */		/*		 * Construct sockaddr format source address.		 */		udp_in.sin_port = uh->uh_sport;		udp_in.sin_addr = ip->ip_src;		iphlen += sizeof(struct udphdr);		m->m_len -= iphlen;		m->m_pkthdr.len -= iphlen;		m->m_data += iphlen;		/*		 * Locate pcb(s) for datagram.		 * (Algorithm copied from raw_intr().)		 */		last = NULL;		for (inp = udbtable.inpt_queue.cqh_first;		    inp != (struct inpcb *)&udbtable.inpt_queue;		    inp = inp->inp_queue.cqe_next) {			if (inp->inp_lport != uh->uh_dport)				continue;			if (inp->inp_laddr.s_addr != INADDR_ANY) {				if (inp->inp_laddr.s_addr !=				    ip->ip_dst.s_addr)					continue;			}			if (inp->inp_faddr.s_addr != INADDR_ANY) {				if (inp->inp_faddr.s_addr !=				    ip->ip_src.s_addr ||				    inp->inp_fport != uh->uh_sport)					continue;			}			if (last != NULL) {				struct mbuf *n;				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {					if (sbappendaddr(&last->so_rcv,						sintosa(&udp_in), n,						(struct mbuf *)0) == 0) {						m_freem(n);						udpstat.udps_fullsock++;					} else						sorwakeup(last);				}			}			last = inp->inp_socket;			/*			 * Don't look for additional matches if this one does			 * not have either the SO_REUSEPORT or SO_REUSEADDR			 * socket options set.  This heuristic avoids searching			 * through all pcbs in the common case of a non-shared			 * port.  It * assumes that an application will never			 * clear these options after setting them.			 */			if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)				break;		}		if (last == NULL) {			/*			 * No matching pcb found; discard datagram.			 * (No need to send an ICMP Port Unreachable			 * for a broadcast or multicast datgram.)			 */			udpstat.udps_noportbcast++;			goto bad;		}		if (sbappendaddr(&last->so_rcv, sintosa(&udp_in), m,		    (struct mbuf *)0) == 0) {			udpstat.udps_fullsock++;			goto bad;		}		sorwakeup(last);		return;	}	/*	 * Locate pcb for datagram.	 */	inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport,	    ip->ip_dst, uh->uh_dport);	if (inp == 0) {		++udpstat.udps_pcbhashmiss;		inp = in_pcblookup(&udbtable, ip->ip_src, uh->uh_sport,		    ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);		if (inp == 0) {			udpstat.udps_noport++;			if (m->m_flags & (M_BCAST | M_MCAST)) {				udpstat.udps_noportbcast++;				goto bad;			}			*ip = save_ip;			icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);			return;		}	}	/*	 * Construct sockaddr format source address.	 * Stuff source address and datagram in user buffer.	 */	udp_in.sin_port = uh->uh_sport;	udp_in.sin_addr = ip->ip_src;	if (inp->inp_flags & INP_CONTROLOPTS) {		struct mbuf **mp = &opts;		if (inp->inp_flags & INP_RECVDSTADDR) {			*mp = udp_saveopt((caddr_t) &ip->ip_dst,			    sizeof(struct in_addr), IP_RECVDSTADDR);			if (*mp)				mp = &(*mp)->m_next;		}#ifdef notyet		/* options were tossed above */		if (inp->inp_flags & INP_RECVOPTS) {			*mp = udp_saveopt((caddr_t) opts_deleted_above,			    sizeof(struct in_addr), IP_RECVOPTS);			if (*mp)				mp = &(*mp)->m_next;		}		/* ip_srcroute doesn't do what we want here, need to fix */		if (inp->inp_flags & INP_RECVRETOPTS) {			*mp = udp_saveopt((caddr_t) ip_srcroute(),			    sizeof(struct in_addr), IP_RECVRETOPTS);			if (*mp)				mp = &(*mp)->m_next;		}#endif	}	iphlen += sizeof(struct udphdr);	m->m_len -= iphlen;	m->m_pkthdr.len -= iphlen;	m->m_data += iphlen;	if (sbappendaddr(&inp->inp_socket->so_rcv, sintosa(&udp_in), m,	    opts) == 0) {		udpstat.udps_fullsock++;		goto bad;	}	sorwakeup(inp->inp_socket);	return;bad:	m_freem(m);	if (opts)		m_freem(opts);}/* * Create a "control" mbuf containing the specified data * with the specified type for presentation with a datagram. */struct mbuf *udp_saveopt(p, size, type)	caddr_t p;	register int size;	int type;{	register struct cmsghdr *cp;	struct mbuf *m;	if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)		return ((struct mbuf *) NULL);	cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);	bcopy(p, CMSG_DATA(cp), size);	size += sizeof(*cp);	m->m_len = size;	cp->cmsg_len = size;	cp->cmsg_level = IPPROTO_IP;	cp->cmsg_type = type;	return (m);}