BBN-Vax-TCP/bbnnet-oct82/udp.c

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../bbnnet/mbuf.h"
#include "../bbnnet/net.h"
#include "../bbnnet/ifcb.h"
#include "../bbnnet/ip.h"
#include "../bbnnet/tcp.h"
#include "../bbnnet/udp.h"
#include "../bbnnet/ucb.h"

extern int nosum;
/*
 *  Process incoming udb messages.  Called directly from ip_input.
 *  User sees udp header with pseudo-header which overlays ip header
 *  (defined in udp.h).
 */
udp_input(mp, ip)
register struct mbuf *mp;
struct ifcb ip;
{
	register struct udp *p;
	register struct ucb *up;
	register u_short lport, fport, i, ulen;

	p = mtod(mp, struct udp *);
	mp->m_off += sizeof p->u_x;
	mp->m_len -= sizeof p->u_x;
	p->u_x1 = 0;
	p->u_ilen = p->u_len;
	ulen = short_from_net(p->u_len);
	lport = short_from_net(p->u_dst);
	fport = short_from_net(p->u_src);
	/*
	 * Do checksum calculation.  Assumes pseudo-header passed up from
	 * IP level and finished above.
	 */
	if ((i = p->u_sum) != 0) {
#ifdef mbb
		i = short_from_net(i);
#endif
		p->u_sum = 0;
		if (i != (u_short)cksum(mp, ulen + UDPCKSIZE)) {
			netstat.u_badsum++;
			if (nosum)
				goto ignore;
			netlog(mp);
			return;
		}
	} 
ignore:
			
	/* find a ucb for incoming message (exact match) */

	for (up = netcb.n_ucb_hd; up != NULL &&
		   (!(up->uc_flags & UUDP) ||
		    up->uc_udp.u_lport != lport ||
		 /* up->uc_udp.u_fport != fport ||  spec only calls for dst */
		    up->uc_host.s_addr != p->u_s.s_addr ||
		    up->uc_local.s_addr!= p->u_d.s_addr); up = up->uc_next);
	
	/* if no exact match, try wild card match */

	if (up == NULL)
		for (up = netcb.n_ucb_hd; up != NULL &&
			(!(up->uc_flags & UUDP) ||
			 up->uc_udp.u_lport != lport ||
		/*	 (up->uc_udp.u_fport != fport && 
			  up->uc_udp.u_fport != 0) ||  spec only calls for dst*/
			 (up->uc_host.s_addr != p->u_s.s_addr &&
			  up->uc_host.s_addr != 0) ||
			 (up->uc_local.s_addr != p->u_d.s_addr &&
			  up->uc_local.s_addr != 0)); up = up->uc_next);
		
	/* if a user is found, queue the data, otherwise drop it */

	if (up != NULL) {
		mp->m_off -= sizeof p->u_x;
		mp->m_len += sizeof p->u_x;
		raw_queue(mp, up);
	} else {
		netstat.u_drops++;
		m_freem(mp);
	}
}

/*
 * Output a udp message.  Called from netuser in the manner of the raw
 * message interface.  Passed an mbuf chain whose first buffer is empty
 * and used for leader construction.
 */
udp_output(up, mp, len)
struct ucb *up;
register struct mbuf *mp;
int len;
{
	register struct udp *p, *q;
	register struct mbuf *m;
	int i;

	switch (up->uc_flags & RAWMASK) {

	case RAWCOMP:
		/*
		 * Compose header in first mbuf.  Get addresses and ports
		 * from ucb, add in pseudo-header fields for checksum.
		 */
		mp->m_off = MSIZE - sizeof(struct udp);
		mp->m_len = sizeof(struct udp);
		p = mtod(mp, struct udp *);
		p->u_len = short_to_net(len+UDPSIZE);
		p->u_s = up->uc_local;
		p->u_d = up->uc_host;
		p->u_src = short_to_net(up->uc_udp.u_lport);
		p->u_dst = short_to_net(up->uc_udp.u_fport);
		break;

	case RAWVER:
	case RAWASIS:
		/*
		 * Header built by user.  Copy the header into the first
		 * mbuf so lower levels can add their leaders.  Assumes
		 * the user had used the udp struct that overlays an ip
		 * header.  The source and destination addresses of the
		 * pseudo-header are assumed, everything else filled in here.
		 */
		m = mp->m_next;
		if (m->m_len < sizeof(struct udp)) {
			u.u_error = ERAWBAD;
			m_freem(mp);
			return;
		}
		q = mtod(m, struct udp *);
		mp->m_off = MSIZE - sizeof(struct udp);
		mp->m_len = sizeof(struct udp);
		p = mtod(mp, struct udp *);
		bcopy((caddr_t)q, (caddr_t)p, sizeof(struct udp));
		m->m_off += sizeof(struct udp);
		m->m_len -= sizeof(struct udp);
		len -= sizeof(struct udp);	/* want data length only here */
		break;
	
	default:
		m_freem(mp);
		u.u_error = ENETPARM;
		return;
	}
	/*
	 * Fill in remainder of pseudo-header.
	 */
	p->u_x1 = 0;
	p->u_pr = UDPROTO;
	p->u_ilen = p->u_len;			/* redundant! */
	/*
	 * Do checksum for all but ASIS.  Include pseudo header.
	 */
	if (!(up->uc_flags&RAWASIS)) {
		mp->m_off += sizeof p->u_x;
		mp->m_len -= sizeof p->u_x;
		p->u_sum = 0;
#ifndef mbb
		p->u_sum = cksum(mp, len + sizeof(struct udp) - sizeof p->u_x);
#else
		i = cksum(mp, len + sizeof(struct udp) - sizeof p->u_x);
		p->u_sum = short_to_net(i);
#endif
		mp->m_off -= sizeof p->u_x;
		mp->m_len += sizeof p->u_x;
	}
	/*
	 * Now send the packet via IP.
	 */
	if (!ip_send(up, mp, UDPROTO, len+UDPSIZE, 0, NULL, FALSE))
		u.u_error = ERAWBAD;
}