Charles.Forsyth20060303644188019 years agoHistory
649 lines · 12.9 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h" #include	"ip.h"#include	"ipv6.h"  #define DPRINT if(0)print enum{	UDP_UDPHDR_SZ	= 8, 	UDP4_PHDR_OFF = 8,	UDP4_PHDR_SZ = 12,	UDP4_IPHDR_SZ = 20,	UDP6_IPHDR_SZ = 40,	UDP6_PHDR_SZ = 40,	UDP6_PHDR_OFF = 0, 	IP_UDPPROTO	= 17,	UDP_USEAD7	= 52,	UDP_USEAD6	= 36, 	Udprxms		= 200,	Udptickms	= 100,	Udpmaxxmit	= 10,}; typedef struct Udp4hdr Udp4hdr;struct Udp4hdr{	/* ip header */	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[IPv4addrlen];	/* Ip source */	uchar	udpdst[IPv4addrlen];	/* Ip destination */ 	/* udp header */	uchar	udpsport[2];	/* Source port */	uchar	udpdport[2];	/* Destination port */	uchar	udplen[2];	/* data length */	uchar	udpcksum[2];	/* Checksum */}; typedef struct Udp6hdr Udp6hdr;struct Udp6hdr {	uchar viclfl[4];	uchar len[2];	uchar nextheader;	uchar hoplimit;	uchar udpsrc[IPaddrlen];	uchar udpdst[IPaddrlen]; 	/* udp header */	uchar	udpsport[2];	/* Source port */	uchar	udpdport[2];	/* Destination port */	uchar	udplen[2];	/* data length */	uchar	udpcksum[2];	/* Checksum */}; /* MIB II counters */typedef struct Udpstats Udpstats;struct Udpstats{	ulong	udpInDatagrams;	ulong	udpNoPorts;	ulong	udpInErrors;	ulong	udpOutDatagrams;}; typedef struct Udppriv Udppriv;struct Udppriv{	Ipht		ht; 	/* MIB counters */	Udpstats	ustats; 	/* non-MIB stats */	ulong		csumerr;		/* checksum errors */	ulong		lenerr;			/* short packet */}; void (*etherprofiler)(char *name, int qlen);void udpkick(void *x, Block *bp); /* *  protocol specific part of Conv */typedef struct Udpcb Udpcb;struct Udpcb{	QLock;	uchar	headers;}; static char*udpconnect(Conv *c, char **argv, int argc){	char *e;	Udppriv *upriv; 	upriv = c->p->priv;	e = Fsstdconnect(c, argv, argc);	Fsconnected(c, e);	if(e != nil)		return e; 	iphtadd(&upriv->ht, c);	return nil;}  static intudpstate(Conv *c, char *state, int n){	return snprint(state, n, "%s qin %d qout %d",		c->inuse ? "Open" : "Closed",		c->rq ? qlen(c->rq) : 0,		c->wq ? qlen(c->wq) : 0	);} static char*udpannounce(Conv *c, char** argv, int argc){	char *e;	Udppriv *upriv; 	upriv = c->p->priv;	e = Fsstdannounce(c, argv, argc);	if(e != nil)		return e;	Fsconnected(c, nil);	iphtadd(&upriv->ht, c); 	return nil;} static voidudpcreate(Conv *c){	c->rq = qopen(64*1024, Qmsg, 0, 0);	c->wq = qbypass(udpkick, c);} static voidudpclose(Conv *c){	Udpcb *ucb;	Udppriv *upriv; 	upriv = c->p->priv;	iphtrem(&upriv->ht, c); 	c->state = 0;	qclose(c->rq);	qclose(c->wq);	qclose(c->eq);	ipmove(c->laddr, IPnoaddr);	ipmove(c->raddr, IPnoaddr);	c->lport = 0;	c->rport = 0; 	ucb = (Udpcb*)c->ptcl;	ucb->headers = 0; 	qunlock(c);} voidudpkick(void *x, Block *bp){	Conv *c = x;	Udp4hdr *uh4;	Udp6hdr *uh6;	ushort rport;	uchar laddr[IPaddrlen], raddr[IPaddrlen];	Udpcb *ucb;	int dlen, ptcllen;	Udppriv *upriv;	Fs *f;	int version;	Conv *rc; 	upriv = c->p->priv;	f = c->p->f; 	netlog(c->p->f, Logudp, "udp: kick\n");	if(bp == nil)		return; 	ucb = (Udpcb*)c->ptcl;	switch(ucb->headers) {	case 7:		/* get user specified addresses */		bp = pullupblock(bp, UDP_USEAD7);		if(bp == nil)			return;		ipmove(raddr, bp->rp);		bp->rp += IPaddrlen;		ipmove(laddr, bp->rp);		bp->rp += IPaddrlen;		/* pick interface closest to dest */		if(ipforme(f, laddr) != Runi)			findlocalip(f, laddr, raddr);		bp->rp += IPaddrlen;		/* Ignore ifc address */		rport = nhgets(bp->rp);		bp->rp += 2+2;			/* Ignore local port */		break;	case 6:		/* get user specified addresses */		bp = pullupblock(bp, UDP_USEAD6);		if(bp == nil)			return;		ipmove(raddr, bp->rp);		bp->rp += IPaddrlen;		ipmove(laddr, bp->rp);		bp->rp += IPaddrlen;		/* pick interface closest to dest */		if(ipforme(f, laddr) != Runi)			findlocalip(f, laddr, raddr);		rport = nhgets(bp->rp);		bp->rp += 2+2;			/* Ignore local port */		break;	default:		rport = 0;		break;	} 	if(ucb->headers) {		if(memcmp(laddr, v4prefix, IPv4off) == 0 ||		    ipcmp(laddr, IPnoaddr) == 0)			version = V4;		else			version = V6;	} else {		if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&			memcmp(c->laddr, v4prefix, IPv4off) == 0)			|| ipcmp(c->raddr, IPnoaddr) == 0)			version = V4;		else			version = V6;	} 	dlen = blocklen(bp); 	/* fill in pseudo header and compute checksum */	switch(version){	case V4:		bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);		if(bp == nil)			return; 		uh4 = (Udp4hdr *)(bp->rp);		ptcllen = dlen + UDP_UDPHDR_SZ;		uh4->Unused = 0;		uh4->udpproto = IP_UDPPROTO;		uh4->frag[0] = 0;		uh4->frag[1] = 0;		hnputs(uh4->udpplen, ptcllen);		if(ucb->headers) {			v6tov4(uh4->udpdst, raddr);			hnputs(uh4->udpdport, rport);			v6tov4(uh4->udpsrc, laddr);			rc = nil;		} else {			v6tov4(uh4->udpdst, c->raddr);			hnputs(uh4->udpdport, c->rport);			if(ipcmp(c->laddr, IPnoaddr) == 0)				findlocalip(f, c->laddr, c->raddr);			v6tov4(uh4->udpsrc, c->laddr);			rc = c;		}		hnputs(uh4->udpsport, c->lport);		hnputs(uh4->udplen, ptcllen);		uh4->udpcksum[0] = 0;		uh4->udpcksum[1] = 0;		hnputs(uh4->udpcksum, 		       ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));		uh4->vihl = IP_VER4;		ipoput4(f, bp, 0, c->ttl, c->tos, rc);		break; 	case V6:		bp = padblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ);		if(bp == nil)			return; 		// using the v6 ip header to create pseudo header 		// first then reset it to the normal ip header		uh6 = (Udp6hdr *)(bp->rp);		memset(uh6, 0, 8);		ptcllen = dlen + UDP_UDPHDR_SZ;		hnputl(uh6->viclfl, ptcllen);		uh6->hoplimit = IP_UDPPROTO;		if(ucb->headers) {			ipmove(uh6->udpdst, raddr);			hnputs(uh6->udpdport, rport);			ipmove(uh6->udpsrc, laddr);			rc = nil;		} else {			ipmove(uh6->udpdst, c->raddr);			hnputs(uh6->udpdport, c->rport);			if(ipcmp(c->laddr, IPnoaddr) == 0)				findlocalip(f, c->laddr, c->raddr);			ipmove(uh6->udpsrc, c->laddr);			rc = c;		}		hnputs(uh6->udpsport, c->lport);		hnputs(uh6->udplen, ptcllen);		uh6->udpcksum[0] = 0;		uh6->udpcksum[1] = 0;		hnputs(uh6->udpcksum, 		       ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ));		memset(uh6, 0, 8);		uh6->viclfl[0] = IP_VER6;		hnputs(uh6->len, ptcllen);		uh6->nextheader = IP_UDPPROTO;		ipoput6(f, bp, 0, c->ttl, c->tos, rc);		break; 	default:		panic("udpkick: version %d", version);	}	upriv->ustats.udpOutDatagrams++;} voidudpiput(Proto *udp, Ipifc *ifc, Block *bp){	int len;	Udp4hdr *uh4;	Udp6hdr *uh6;	Conv *c;	Udpcb *ucb;	uchar raddr[IPaddrlen], laddr[IPaddrlen];	ushort rport, lport;	Udppriv *upriv;	Fs *f;	int version;	int ottl, oviclfl, olen;	uchar *p; 	upriv = udp->priv;	f = udp->f;	upriv->ustats.udpInDatagrams++; 	uh4 = (Udp4hdr*)(bp->rp);	version = ((uh4->vihl&0xF0)==IP_VER6) ? V6 : V4; 	/*	 * Put back pseudo header for checksum 	 * (remember old values for icmpnoconv())	 */	switch(version) {	case V4:		ottl = uh4->Unused;		uh4->Unused = 0;		len = nhgets(uh4->udplen);		olen = nhgets(uh4->udpplen);		hnputs(uh4->udpplen, len); 		v4tov6(raddr, uh4->udpsrc);		v4tov6(laddr, uh4->udpdst);		lport = nhgets(uh4->udpdport);		rport = nhgets(uh4->udpsport); 		if(nhgets(uh4->udpcksum)) {			if(ptclcsum(bp, UDP4_PHDR_OFF, len+UDP4_PHDR_SZ)) {				upriv->ustats.udpInErrors++;				netlog(f, Logudp, "udp: checksum error %I\n", raddr);				DPRINT("udp: checksum error %I\n", raddr);				freeblist(bp);				return;			}		}		uh4->Unused = ottl;		hnputs(uh4->udpplen, olen);		break;	case V6:		uh6 = (Udp6hdr*)(bp->rp);		len = nhgets(uh6->udplen);		oviclfl = nhgetl(uh6->viclfl);		olen = nhgets(uh6->len);		ottl = uh6->hoplimit;		ipmove(raddr, uh6->udpsrc);		ipmove(laddr, uh6->udpdst);		lport = nhgets(uh6->udpdport);		rport = nhgets(uh6->udpsport);		memset(uh6, 0, 8);		hnputl(uh6->viclfl, len);		uh6->hoplimit = IP_UDPPROTO;		if(ptclcsum(bp, UDP6_PHDR_OFF, len+UDP6_PHDR_SZ)) {			upriv->ustats.udpInErrors++;			netlog(f, Logudp, "udp: checksum error %I\n", raddr);			DPRINT("udp: checksum error %I\n", raddr);			freeblist(bp);			return;		}		hnputl(uh6->viclfl, oviclfl);		hnputs(uh6->len, olen);		uh6->nextheader = IP_UDPPROTO;		uh6->hoplimit = ottl;		break;	default:		panic("udpiput: version %d", version);		return;	/* to avoid a warning */	} 	qlock(udp); 	c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);	if(c == nil){		/* no converstation found */		upriv->ustats.udpNoPorts++;		qunlock(udp);		netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,		       laddr, lport); 		switch(version){		case V4:			icmpnoconv(f, bp);			break;		case V6:			icmphostunr(f, ifc, bp, icmp6_port_unreach, 0);			break;		default:			panic("udpiput2: version %d", version);		} 		freeblist(bp);		return;	}	ucb = (Udpcb*)c->ptcl; 	if(c->state == Announced){		if(ucb->headers == 0){			/* create a new conversation */			if(ipforme(f, laddr) != Runi) {				switch(version){				case V4:					v4tov6(laddr, ifc->lifc->local);					break;				case V6:					ipmove(laddr, ifc->lifc->local);					break;				default:					panic("udpiput3: version %d", version);				}			}			c = Fsnewcall(c, raddr, rport, laddr, lport, version);			if(c == nil){				qunlock(udp);				freeblist(bp);				return;			}			iphtadd(&upriv->ht, c);			ucb = (Udpcb*)c->ptcl;		}	} 	qlock(c);	qunlock(udp); 	/*	 * Trim the packet down to data size	 */	len -= UDP_UDPHDR_SZ;	switch(version){	case V4:		bp = trimblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ, len);		break;	case V6:		bp = trimblock(bp, UDP6_IPHDR_SZ+UDP_UDPHDR_SZ, len);		break;	default:		bp = nil;		panic("udpiput4: version %d", version);	}	if(bp == nil){		qunlock(c);		netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,		       laddr, lport);		upriv->lenerr++;		return;	} 	netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,

Lines 1–500 of 649.