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

2001/0623/ip/gre.c (diff list | history)

2001/0623/sys/src/9/ip/gre.c:1,2582002/0507/sys/src/9/ip/gre.c:1,259 (short | long | prev | next)
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 
{ 
1997/0530    
	GRE_IPONLY	= 12,		/* size of ip header */ 
	GRE_IPPLUSGRE	= 12,		/* minimum size of GRE header */ 
1997/0327    
	IP_GREPROTO	= 47, 
 
	GRErxms		= 200, 
	GREtickms	= 100, 
	GREmaxxmit	= 10, 
}; 
 
typedef struct GREhdr 
{ 
	/* ip header */ 
1998/0306    
	uchar	vihl;		/* Version and header length */ 
	uchar	tos;		/* Type of service */ 
	uchar	len[2];		/* packet length (including headers) */ 
	uchar	id[2];		/* Identification */ 
	uchar	frag[2];	/* Fragment information */ 
	uchar	Unused;	 
	uchar	proto;		/* Protocol */ 
	uchar	cksum[2];	/* checksum */ 
	uchar	src[4];		/* Ip source */ 
	uchar	dst[4];		/* Ip destination */ 
1997/0327    
 
	/* gre header */ 
1998/0306    
	uchar	flags[2]; 
	uchar	eproto[2];	/* encapsulation protocol */ 
1997/0327    
} GREhdr; 
 
1998/0313    
typedef struct GREpriv GREpriv; 
struct GREpriv 
{ 
	/* non-MIB stats */ 
	ulong		csumerr;		/* checksum errors */ 
	ulong		lenerr;			/* short packet */ 
}; 
1997/0327    
 
static char* 
greconnect(Conv *c, char **argv, int argc) 
{ 
	Proto *p; 
	char *err; 
	Conv *tc, **cp, **ecp; 
 
	err = Fsstdconnect(c, argv, argc); 
	if(err != nil) 
		return err; 
 
	/* make sure noone's already connected to this other sys */ 
	p = c->p; 
1998/0306    
	qlock(p); 
1997/0327    
	ecp = &p->conv[p->nc]; 
	for(cp = p->conv; cp < ecp; cp++){ 
		tc = *cp; 
		if(tc == nil) 
			break; 
		if(tc == c) 
			continue; 
1998/0401    
		if(tc->rport == c->rport && ipcmp(tc->raddr, c->raddr) == 0){ 
1997/0327    
			err = "already connected to that addr/proto"; 
1998/0306    
			ipmove(c->laddr, IPnoaddr); 
			ipmove(c->raddr, IPnoaddr); 
1997/0327    
			break; 
		} 
	} 
1998/0306    
	qunlock(p); 
1997/0327    
 
1997/0403    
	if(err != nil) 
		return err; 
1998/0313    
	Fsconnected(c, nil); 
1997/0327    
 
1997/0403    
	return nil; 
1997/0327    
} 
 
static int 
1998/0306    
grestate(Conv *c, char *state, int n) 
1997/0327    
{ 
	USED(c); 
1998/0306    
	return snprint(state, n, "%s", "Datagram"); 
1997/0327    
} 
 
static void 
grecreate(Conv *c) 
{ 
2001/0127    
	c->rq = qopen(64*1024, 1, 0, c); 
1997/0327    
	c->wq = qopen(64*1024, 0, 0, 0); 
} 
 
1997/0403    
static char* 
greannounce(Conv*, char**, int) 
1997/0327    
{ 
1997/0403    
	return "pktifc does not support announce"; 
1997/0327    
} 
 
static void 
greclose(Conv *c) 
{ 
	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; 
} 
 
int drop; 
 
static void 
2001/0306    
grekick(Conv *c) 
1997/0327    
{ 
	GREhdr *ghp; 
1997/0524    
	Block *bp; 
1998/0306    
	uchar laddr[IPaddrlen], raddr[IPaddrlen]; 
1997/0327    
 
	bp = qget(c->wq); 
	if(bp == nil) 
		return; 
 
	/* Make space to fit ip header (gre header already there) */ 
1997/0530    
	bp = padblock(bp, GRE_IPONLY); 
1997/0327    
	if(bp == nil) 
		return; 
 
	/* make sure the message has a GRE header */ 
1997/0530    
	bp = pullupblock(bp, GRE_IPONLY+GRE_IPPLUSGRE); 
1997/0327    
	if(bp == nil) 
		return; 
 
	ghp = (GREhdr *)(bp->rp); 
2002/0507    
	ghp->vihl = IP_VER4; 
1997/0327    
 
1998/0306    
	v4tov6(raddr, ghp->dst); 
	if(ipcmp(raddr, v4prefix) == 0) 
		memmove(ghp->dst, c->raddr + IPv4off, IPv4addrlen); 
	v4tov6(laddr, ghp->src); 
	if(ipcmp(laddr, v4prefix) == 0){ 
		if(ipcmp(c->laddr, IPnoaddr) == 0) 
1998/0313    
			findlocalip(c->p->f, c->laddr, raddr); /* pick interface closest to dest */ 
1998/0306    
		memmove(ghp->src, c->laddr + IPv4off, IPv4addrlen); 
	} 
1997/0530    
 
1997/0327    
	ghp->proto = IP_GREPROTO; 
	hnputs(ghp->eproto, c->rport); 
1997/0522    
	ghp->frag[0] = 0; 
	ghp->frag[1] = 0; 
1997/0327    
 
1999/0817    
	ipoput(c->p->f, bp, 0, c->ttl, c->tos); 
2002/0507    
	ipoput4(c->p->f, bp, 0, c->ttl, c->tos); 
1997/0327    
} 
 
static void 
2001/0623    
greiput(Proto *gre, Ipifc*, Block *bp) 
1997/0327    
{ 
	int len; 
	GREhdr *ghp; 
	Conv *c, **p; 
	ushort eproto; 
1998/0306    
	uchar raddr[IPaddrlen]; 
1998/0313    
	GREpriv *gpriv; 
1997/0327    
 
1998/0313    
	gpriv = gre->priv; 
1997/0327    
	ghp = (GREhdr*)(bp->rp); 
 
1998/0306    
	v4tov6(raddr, ghp->src); 
1997/0327    
	eproto = nhgets(ghp->eproto); 
 
1999/0302    
	qlock(gre); 
 
1997/0327    
	/* Look for a conversation structure for this port and address */ 
	c = nil; 
1998/0313    
	for(p = gre->conv; *p; p++) { 
1997/0327    
		c = *p; 
		if(c->inuse == 0) 
			continue; 
1998/0306    
		if(c->rport == eproto && ipcmp(c->raddr, raddr) == 0) 
1997/0327    
			break; 
	} 
 
	if(*p == nil) { 
1999/0302    
		qunlock(gre); 
1997/0327    
		freeblist(bp); 
		return; 
	} 
1999/0302    
 
	qunlock(gre); 
1997/0327    
 
	/* 
	 * Trim the packet down to data size 
	 */ 
1997/0530    
	len = nhgets(ghp->len) - GRE_IPONLY; 
	if(len < GRE_IPPLUSGRE){ 
1997/0327    
		freeblist(bp); 
		return; 
	} 
1997/0530    
	bp = trimblock(bp, GRE_IPONLY, len); 
1997/0327    
	if(bp == nil){ 
1998/0313    
		gpriv->lenerr++; 
1997/0327    
		return; 
	} 
 
	/* 
	 *  Can't delimit packet so pull it all into one block. 
	 */ 
	if(qlen(c->rq) > 64*1024) 
		freeblist(bp); 
	else{ 
		bp = concatblock(bp); 
		if(bp == 0) 
			panic("greiput"); 
		qpass(c->rq, bp); 
	} 
} 
 
1998/0306    
int 
1998/0313    
grestats(Proto *gre, char *buf, int len) 
1998/0306    
{ 
1998/0313    
	GREpriv *gpriv; 
 
	gpriv = gre->priv; 
 
1998/0825    
	return snprint(buf, len, "gre: len %lud\n", gpriv->lenerr); 
1998/0306    
} 
 
1997/0327    
void 
greinit(Fs *fs) 
{ 
1998/0313    
	Proto *gre; 
1997/0327    
 
1998/0313    
	gre = smalloc(sizeof(Proto)); 
	gre->priv = smalloc(sizeof(GREpriv)); 
	gre->name = "gre"; 
	gre->kick = grekick; 
	gre->connect = greconnect; 
	gre->announce = greannounce; 
	gre->state = grestate; 
	gre->create = grecreate; 
	gre->close = greclose; 
	gre->rcv = greiput; 
	gre->ctl = nil; 
	gre->advise = nil; 
	gre->stats = grestats; 
	gre->ipproto = IP_GREPROTO; 
	gre->nc = 64; 
	gre->ptclsize = 0; 
 
	Fsproto(fs, gre); 
1997/0327    
} 


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