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

1998/0630/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/0313    
	UDP_USEAD6	= 36, 
	UDP_USEAD4	= 12, 
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    
}; 
 
1998/0313    
/* MIB II counters */ 
typedef struct Udpstats Udpstats; 
struct Udpstats 
{ 
	ulong	udpInDatagrams; 
	ulong	udpNoPorts; 
	ulong	udpInErrors; 
	ulong	udpOutDatagrams; 
}; 
 
typedef struct Udppriv Udppriv; 
struct Udppriv 
{ 
	/* MIB counters */ 
	Udpstats	ustats; 
 
	/* non-MIB stats */ 
	ulong		csumerr;		/* checksum errors */ 
	ulong		lenerr;			/* short packet */ 
}; 
 
1997/0327    
/* 
 *  protocol specific part of Conv 
 */ 
typedef struct Udpcb Udpcb; 
struct Udpcb 
{ 
	QLock; 
1998/0306    
	uchar	headers; 
1997/0327    
}; 
 
static char* 
udpconnect(Conv *c, char **argv, int argc) 
{ 
	char *e; 
 
	e = Fsstdconnect(c, argv, argc); 
1998/0313    
	Fsconnected(c, e); 
1997/0327    
 
	return e; 
} 
 
1998/0313    
 
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; 
1998/0313    
	Fsconnected(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/0313    
	Udppriv *upriv; 
	Fs *f; 
1997/0327    
 
1998/0313    
	upriv = c->p->priv; 
	f = c->p->f; 
 
	netlog(c->p->f, Logudp, "udp: kick\n"); 
1997/0327    
	bp = qget(c->wq); 
	if(bp == nil) 
		return; 
 
	ucb = (Udpcb*)c->ptcl; 
1998/0313    
	switch(ucb->headers) { 
	case 6: 
1997/0327    
		/* get user specified addresses */ 
1998/0313    
		bp = pullupblock(bp, UDP_USEAD6); 
1998/0306    
		if(bp == nil) 
1997/0327    
			return; 
1998/0306    
		ipmove(raddr, bp->rp); 
		bp->rp += IPaddrlen; 
		ipmove(laddr, bp->rp); 
		bp->rp += IPaddrlen; 
1998/0414    
		/* pick interface closest to dest */ 
1998/0313    
		if(ipforme(f, laddr) != Runi) 
1998/0414    
			findlocalip(f, laddr, raddr); 
1997/0530    
		rport = nhgets(bp->rp); 
1998/0414    
		bp->rp += 2+2;			/* Igonore local port */ 
1998/0313    
		break; 
	case 4: 
		bp = pullupblock(bp, UDP_USEAD4); 
		if(bp == nil) 
			return; 
		v4tov6(raddr, bp->rp); 
		bp->rp += IPv4addrlen; 
		v4tov6(laddr, bp->rp); 
		bp->rp += IPv4addrlen; 
		if(ipforme(f, laddr) != Runi) 
1998/0414    
			findlocalip(f, laddr, raddr); 
1998/0313    
		rport = nhgets(bp->rp); 
1998/0414    
		bp->rp += 2+2; 
1998/0313    
		break; 
	default: 
1997/0530    
		rport = 0; 
1998/0313    
		break; 
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); 
1998/0313    
	switch(ucb->headers){ 
1998/0414    
	case 4: 
1998/0313    
	case 6: 
1998/0306    
		v6tov4(uh->udpdst, raddr); 
1997/0530    
		hnputs(uh->udpdport, rport); 
1998/0306    
		v6tov4(uh->udpsrc, laddr); 
1998/0313    
		break; 
	default: 
1998/0306    
		v6tov4(uh->udpdst, c->raddr); 
1997/0327    
		hnputs(uh->udpdport, c->rport); 
1998/0306    
		if(ipcmp(c->laddr, IPnoaddr) == 0) 
1998/0414    
			findlocalip(f, c->laddr, c->raddr); 
1998/0306    
		v6tov4(uh->udpsrc, c->laddr); 
1998/0313    
		break; 
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)); 
 
1998/0313    
	upriv->ustats.udpOutDatagrams++; 
	ipoput(f, bp, 0, c->ttl); 
1997/0327    
} 
 
void 
1998/0313    
udpiput(Proto *udp, 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; 
1998/0313    
	Udppriv *upriv; 
	Fs *f; 
1997/0327    
 
1998/0313    
	upriv = udp->priv; 
	f = udp->f; 
 
	upriv->ustats.udpInDatagrams++; 
 
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    
 
1998/0313    
	if(nhgets(uh->udpcksum)) { 
1997/0327    
		if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) { 
1998/0313    
			upriv->ustats.udpInErrors++; 
			netlog(f, Logudp, "udp: checksum error %I\n", raddr); 
1998/0630    
			DPRINT("udp: checksum error %I\n", raddr); 
1997/0327    
			freeblist(bp); 
			return; 
		} 
	} 
 
	/* Look for a conversation structure for this port */ 
	c = nil; 
1998/0313    
	for(p = udp->conv; *p; p++) { 
1997/0327    
		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/0313    
		upriv->ustats.udpNoPorts++; 
1998/0414    
		netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport, 
1998/0306    
			laddr, lport); 
1998/0509    
		uh->Unused = ottl; 
		hnputs(uh->udpplen, olen); 
		icmpnoconv(f, 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/0313    
		netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport, 
1998/0306    
			laddr, lport); 
1998/0313    
		upriv->lenerr++; 
1997/0327    
		return; 
	} 
1997/0806    
 
1998/0313    
	netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport, 
1998/0306    
		laddr, lport, len); 
1997/0327    
 
	ucb = (Udpcb*)c->ptcl; 
 
1998/0313    
	switch(ucb->headers){ 
	case 6: 
1997/0327    
		/* pass the src address */ 
1998/0313    
		bp = padblock(bp, UDP_USEAD6); 
1998/0306    
		ipmove(bp->rp, raddr); 
1998/0313    
		if(ipforme(f, laddr) == Runi) 
1998/0306    
			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); 
1998/0313    
		break; 
	case 4: 
		/* pass the src address */ 
		bp = padblock(bp, UDP_USEAD4); 
1998/0414    
		v6tov4(bp->rp, raddr); 
1998/0313    
		if(ipforme(f, laddr) == Runi) 
1998/0414    
			v6tov4(bp->rp+IPv4addrlen, laddr); 
1998/0313    
		else 
1998/0604    
			v6tov4(bp->rp+IPv4addrlen, ia); 
1998/0313    
		hnputs(bp->rp + 2*IPv4addrlen, rport); 
		hnputs(bp->rp + 2*IPv4addrlen + 2, lport); 
		break; 
	default: 
1997/0327    
		/* 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/0313    
			if(ipforme(f, laddr) == Runi) 
1998/0306    
				ipmove(c->laddr, laddr); 
1997/0708    
			else 
1998/0313    
				v4tov6(c->laddr, ia); 
1997/0327    
		} 
1998/0313    
		break; 
1997/0327    
	} 
	if(bp->next) 
		bp = concatblock(bp); 
 
1997/0725    
	if(qfull(c->rq)){ 
1998/0313    
		netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport, 
1998/0306    
			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; 
1998/0313    
	if(n == 1){ 
		if(strcmp(f[0], "headers4") == 0){ 
			ucb->headers = 4; 
			return nil; 
		} else if(strcmp(f[0], "headers") == 0){ 
			ucb->headers = 6; 
			return nil; 
		} 
1997/0327    
	} 
	return "unknown control request"; 
} 
 
void 
1998/0313    
udpadvise(Proto *udp, Block *bp, char *msg) 
1997/0829    
{ 
	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 */ 
1998/0313    
	for(p = udp->conv; *p; p++) { 
1997/0829    
		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 
1998/0313    
udpstats(Proto *udp, char *buf, int len) 
1998/0306    
{ 
1998/0313    
	Udppriv *upriv; 
 
	upriv = udp->priv; 
1998/0414    
	return snprint(buf, len, "%d %d %d %d\n", 
1998/0313    
		upriv->ustats.udpInDatagrams, 
		upriv->ustats.udpNoPorts, 
		upriv->ustats.udpInErrors, 
		upriv->ustats.udpOutDatagrams); 
1998/0306    
} 
 
1997/0829    
void 
1997/0327    
udpinit(Fs *fs) 
{ 
1998/0313    
	Proto *udp; 
1997/0327    
 
1998/0313    
	udp = smalloc(sizeof(Proto)); 
	udp->priv = smalloc(sizeof(Udppriv)); 
	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; 
	udp->advise = udpadvise; 
	udp->stats = udpstats; 
	udp->ipproto = IP_UDPPROTO; 
	udp->nc = 16; 
	udp->ptclsize = sizeof(Udpcb); 
 
	Fsproto(fs, udp); 
1997/0327    
} 


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