plan 9 kernel history: overview | file list | diff list

1998/0306/ip/udp.c (diff list | history)

ip/udp.c on 1997/0327
1997/0327    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
 
#include	"ip.h" 
 
#define DPRINT if(0)print 
 
enum 
{ 
	UDP_PHDRSIZE	= 12, 
	UDP_HDRSIZE	= 20, 
	UDP_IPHDR	= 8, 
	IP_UDPPROTO	= 17, 
1998/0306    
	UDP_USEAD	= 36, 
1997/0327    
 
	Udprxms		= 200, 
	Udptickms	= 100, 
	Udpmaxxmit	= 10, 
}; 
 
typedef struct Udphdr Udphdr; 
struct Udphdr 
{ 
	/* ip header */ 
1998/0306    
	uchar	vihl;		/* Version and header length */ 
	uchar	tos;		/* Type of service */ 
	uchar	length[2];	/* packet length */ 
	uchar	id[2];		/* Identification */ 
	uchar	frag[2];	/* Fragment information */ 
	uchar	Unused;	 
	uchar	udpproto;	/* Protocol */ 
	uchar	udpplen[2];	/* Header plus data length */ 
	uchar	udpsrc[4];	/* Ip source */ 
	uchar	udpdst[4];	/* Ip destination */ 
1997/0327    
 
	/* udp header */ 
1998/0306    
	uchar	udpsport[2];	/* Source port */ 
	uchar	udpdport[2];	/* Destination port */ 
	uchar	udplen[2];	/* data length */ 
	uchar	udpcksum[2];	/* Checksum */ 
1997/0327    
}; 
 
/* 
 *  protocol specific part of Conv 
 */ 
typedef struct Udpcb Udpcb; 
struct Udpcb 
{ 
	QLock; 
1998/0306    
	uchar	headers; 
1997/0327    
}; 
 
	Proto	udp; 
	int	udpsum; 
	uint	generation; 
extern	Fs	fs; 
	int	udpdebug; 
 
static char* 
udpconnect(Conv *c, char **argv, int argc) 
{ 
	char *e; 
 
	e = Fsstdconnect(c, argv, argc); 
	Fsconnected(&fs, c, e); 
 
	return e; 
} 
 
1998/0306    
static int 
udpstate(Conv *c, char *state, int n) 
1997/0327    
{ 
	USED(c); 
1998/0306    
	return snprint(state, n, "%s", "Datagram"); 
1997/0327    
} 
 
1997/0403    
static char* 
1997/0411    
udpannounce(Conv *c, char** argv, int argc) 
1997/0327    
{ 
1997/0411    
	char *e; 
 
	e = Fsstdannounce(c, argv, argc); 
	if(e != nil) 
		return e; 
1997/0327    
	Fsconnected(&fs, c, nil); 
1997/0403    
 
	return nil; 
1997/0327    
} 
 
static void 
udpcreate(Conv *c) 
{ 
1997/0806    
	c->rq = qopen(64*1024, 1, 0, 0); 
	c->wq = qopen(64*1024, 0, 0, 0); 
1997/0327    
} 
 
static void 
udpclose(Conv *c) 
{ 
	Udpcb *ucb; 
 
	qclose(c->rq); 
	qclose(c->wq); 
	qclose(c->eq); 
1998/0306    
	ipmove(c->laddr, IPnoaddr); 
	ipmove(c->raddr, IPnoaddr); 
1997/0327    
	c->lport = 0; 
	c->rport = 0; 
 
	ucb = (Udpcb*)c->ptcl; 
	ucb->headers = 0; 
 
	unlock(c); 
} 
 
void 
1998/0306    
udpkick(Conv *c, int) 
1997/0327    
{ 
	Udphdr *uh; 
1997/0530    
	ushort rport; 
1998/0306    
	uchar laddr[IPaddrlen], raddr[IPaddrlen]; 
1997/0806    
	Block *bp; 
1997/0327    
	Udpcb *ucb; 
	int dlen, ptcllen; 
 
1998/0306    
	netlog(Logudp, "udp: kick\n"); 
1997/0327    
	bp = qget(c->wq); 
	if(bp == nil) 
		return; 
 
	ucb = (Udpcb*)c->ptcl; 
	if(ucb->headers) { 
		/* get user specified addresses */ 
		bp = pullupblock(bp, UDP_USEAD); 
1998/0306    
		if(bp == nil) 
1997/0327    
			return; 
1998/0306    
		ipmove(raddr, bp->rp); 
		bp->rp += IPaddrlen; 
		ipmove(laddr, bp->rp); 
		bp->rp += IPaddrlen; 
		if(ipforme(laddr) != Runi) 
			findlocalip(laddr, raddr);	/* pick interface closest to dest */ 
1997/0530    
		rport = nhgets(bp->rp); 
1997/0327    
		bp->rp += 2; 
1997/0530    
		/* ignore local port number */ 
		bp->rp += 2; 
1997/0327    
	} else { 
1997/0530    
		rport = 0; 
1997/0327    
	} 
 
	dlen = blocklen(bp); 
 
	/* Make space to fit udp & ip header */ 
	bp = padblock(bp, UDP_IPHDR+UDP_HDRSIZE); 
	if(bp == nil) 
		return; 
 
	uh = (Udphdr *)(bp->rp); 
 
	ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); 
	uh->Unused = 0; 
	uh->udpproto = IP_UDPPROTO; 
	uh->frag[0] = 0; 
	uh->frag[1] = 0; 
	hnputs(uh->udpplen, ptcllen); 
	if(ucb->headers) { 
1998/0306    
		v6tov4(uh->udpdst, raddr); 
1997/0530    
		hnputs(uh->udpdport, rport); 
1998/0306    
		v6tov4(uh->udpsrc, laddr); 
1997/0327    
	} else { 
1998/0306    
		v6tov4(uh->udpdst, c->raddr); 
1997/0327    
		hnputs(uh->udpdport, c->rport); 
1998/0306    
		if(ipcmp(c->laddr, IPnoaddr) == 0) 
			findlocalip(c->laddr, c->raddr);	/* pick interface closest to dest */ 
		v6tov4(uh->udpsrc, c->laddr); 
1997/0327    
	} 
	hnputs(uh->udpsport, c->lport); 
	hnputs(uh->udplen, ptcllen); 
	uh->udpcksum[0] = 0; 
	uh->udpcksum[1] = 0; 
 
	hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_HDRSIZE)); 
 
	ipoput(bp, 0, c->ttl); 
} 
 
void 
1998/0306    
udpiput(uchar *ia, Block *bp) 
1997/0327    
{ 
1997/0904    
	int len, olen, ottl; 
1997/0327    
	Udphdr *uh; 
	Conv *c, **p; 
	Udpcb *ucb; 
1998/0306    
	uchar raddr[IPaddrlen], laddr[IPaddrlen]; 
1997/0530    
	ushort rport, lport; 
1997/0327    
 
	uh = (Udphdr*)(bp->rp); 
 
1997/0904    
	/* Put back pseudo header for checksum (remember old values for icmpnoconv()) */ 
	ottl = uh->Unused; 
1997/0327    
	uh->Unused = 0; 
	len = nhgets(uh->udplen); 
1997/0904    
	olen = nhgets(uh->udpplen); 
1997/0327    
	hnputs(uh->udpplen, len); 
 
1998/0306    
	v4tov6(raddr, uh->udpsrc); 
	v4tov6(laddr, uh->udpdst); 
1997/0725    
	lport = nhgets(uh->udpdport); 
	rport = nhgets(uh->udpsport); 
1997/0327    
 
	if(udpsum && nhgets(uh->udpcksum)) { 
		if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) { 
			udp.csumerr++; 
1998/0306    
			netlog(Logudp, "udp: checksum error %I\n", raddr); 
1997/0327    
			freeblist(bp); 
			return; 
		} 
	} 
 
	/* Look for a conversation structure for this port */ 
	c = nil; 
	for(p = udp.conv; *p; p++) { 
		c = *p; 
		if(c->inuse == 0) 
			continue; 
1997/0530    
		if(c->lport == lport && (c->rport == 0 || c->rport == rport)) 
1997/0327    
			break; 
	} 
 
	if(*p == nil) { 
1998/0306    
		netlog(Logudp, "udp: no conv %I.%d -> %I.%d\n", raddr, rport, 
			laddr, lport); 
1997/0904    
		/* don't complain about broadcasts... */ 
1998/0306    
		if(ipforme(raddr) == 0){ 
1997/0904    
			uh->Unused = ottl; 
			hnputs(uh->udpplen, olen); 
			icmpnoconv(bp); 
		} 
1997/0327    
		freeblist(bp); 
		return; 
	} 
 
	/* 
	 * Trim the packet down to data size 
	 */ 
	len -= (UDP_HDRSIZE-UDP_PHDRSIZE); 
	bp = trimblock(bp, UDP_IPHDR+UDP_HDRSIZE, len); 
	if(bp == nil){ 
1998/0306    
		netlog(Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport, 
			laddr, lport); 
1997/0327    
		udp.lenerr++; 
		return; 
	} 
1997/0806    
 
1998/0306    
	netlog(Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport, 
		laddr, lport, len); 
1997/0327    
 
	ucb = (Udpcb*)c->ptcl; 
 
	if(ucb->headers) { 
		/* pass the src address */ 
		bp = padblock(bp, UDP_USEAD); 
1998/0306    
		ipmove(bp->rp, raddr); 
		if(ipforme(laddr) == Runi) 
			ipmove(bp->rp+IPaddrlen, laddr); 
1997/0901    
		else 
1998/0306    
			ipmove(bp->rp+IPaddrlen, ia); 
		hnputs(bp->rp+2*IPaddrlen, rport); 
		hnputs(bp->rp+2*IPaddrlen+2, lport); 
1997/0327    
	} else { 
		/* connection oriented udp */ 
		if(c->raddr == 0){ 
			/* save the src address in the conversation */ 
1998/0306    
		 	ipmove(c->raddr, raddr); 
1997/0530    
			c->rport = rport; 
1997/0327    
 
			/* reply with the same ip address (if not broadcast) */ 
1998/0306    
			if(ipforme(laddr) == Runi) 
				ipmove(c->laddr, laddr); 
1997/0708    
			else 
1998/0306    
				ipmove(c->laddr, ia); 
1997/0327    
		} 
	} 
	if(bp->next) 
		bp = concatblock(bp); 
 
1997/0725    
	if(qfull(c->rq)){ 
1998/0306    
		netlog(Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport, 
			laddr, lport); 
1997/0327    
		freeblist(bp); 
1997/0725    
	}else 
1997/0327    
		qpass(c->rq, bp); 
} 
 
char* 
udpctl(Conv *c, char **f, int n) 
{ 
	Udpcb *ucb; 
 
	ucb = (Udpcb*)c->ptcl; 
	if(n == 1 && strcmp(f[0], "headers") == 0){ 
		ucb->headers = 1; 
		return nil; 
	} 
	if(n == 1 && strcmp(f[0], "debug") == 0){ 
		udpdebug = 1; 
		return nil; 
	} 
	return "unknown control request"; 
} 
 
void 
1997/0829    
udpadvise(Block *bp, char *msg) 
{ 
	Udphdr *h; 
1998/0306    
	uchar source[IPaddrlen], dest[IPaddrlen]; 
1997/0829    
	ushort psource, pdest; 
	Conv *s, **p; 
 
	h = (Udphdr*)(bp->rp); 
 
1998/0306    
	v4tov6(dest, h->udpdst); 
	v4tov6(source, h->udpsrc); 
1997/0829    
	psource = nhgets(h->udpsport); 
	pdest = nhgets(h->udpdport); 
 
	/* Look for a connection */ 
	for(p = udp.conv; *p; p++) { 
		s = *p; 
1998/0306    
		if(s->rport == pdest) 
		if(s->lport == psource) 
		if(ipcmp(s->raddr, dest) == 0) 
		if(ipcmp(s->laddr, source) == 0){ 
1997/0829    
			qhangup(s->rq, msg); 
			qhangup(s->wq, msg); 
			break; 
		} 
	} 
	freeblist(bp); 
} 
 
1998/0306    
int 
udpstats(char *buf, int len) 
{ 
	return snprint(buf, len, 
		"udp: csum %d hlen %d len %d order %d rexmit %d\n", 
		udp.csumerr, udp.hlenerr, udp.lenerr, udp.order, udp.rexmit); 
} 
 
1997/0829    
void 
1997/0327    
udpinit(Fs *fs) 
{ 
	udp.name = "udp"; 
	udp.kick = udpkick; 
	udp.connect = udpconnect; 
	udp.announce = udpannounce; 
	udp.ctl = udpctl; 
	udp.state = udpstate; 
	udp.create = udpcreate; 
	udp.close = udpclose; 
	udp.rcv = udpiput; 
1997/0829    
	udp.advise = udpadvise; 
1998/0306    
	udp.stats = udpstats; 
1997/0327    
	udp.ipproto = IP_UDPPROTO; 
	udp.nc = 16; 
	udp.ptclsize = sizeof(Udpcb); 
 
	Fsproto(fs, &udp); 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)