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

1997/0531/ip/gre.c (diff list | history)

ip/gre.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 
{ 
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 */ 
	byte	vihl;		/* Version and header length */ 
	byte	tos;		/* Type of service */ 
	byte	len[2];		/* packet length (including headers) */ 
	byte	id[2];		/* Identification */ 
	byte	frag[2];	/* Fragment information */ 
	byte	Unused;	 
	byte	proto;		/* Protocol */ 
	byte	cksum[2];	/* checksum */ 
	byte	src[4];		/* Ip source */ 
	byte	dst[4];		/* Ip destination */ 
 
	/* gre header */ 
	byte	flags[2]; 
	byte	eproto[2];	/* encapsulation protocol */ 
} GREhdr; 
 
	Proto	gre; 
extern	Fs	fs; 
	int	gredebug; 
 
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; 
	lock(p); 
	ecp = &p->conv[p->nc]; 
	for(cp = p->conv; cp < ecp; cp++){ 
		tc = *cp; 
		if(tc == nil) 
			break; 
		if(tc == c) 
			continue; 
		if(tc->rport == c->rport && tc->raddr == c->raddr){ 
			err = "already connected to that addr/proto"; 
			c->rport = 0; 
			c->raddr = 0; 
			break; 
		} 
	} 
	unlock(p); 
 
1997/0403    
	if(err != nil) 
		return err; 
	Fsconnected(&fs, c, nil); 
1997/0327    
 
1997/0403    
	return nil; 
1997/0327    
} 
 
static int 
grestate(char **msg, Conv *c) 
{ 
	USED(c); 
	*msg = "Datagram"; 
	return 1; 
} 
 
static void 
grecreate(Conv *c) 
{ 
	c->rq = qopen(64*1024, 0, 0, c); 
	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); 
	c->laddr = 0; 
	c->raddr = 0; 
	c->lport = 0; 
	c->rport = 0; 
 
	unlock(c); 
} 
 
int drop; 
 
static void 
grekick(Conv *c, int l) 
{ 
	GREhdr *ghp; 
1997/0524    
	Block *bp; 
1997/0530    
	ulong raddr, laddr; 
1997/0327    
 
	USED(l); 
 
	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); 
 
1997/0531    
	raddr = nhgetl(ghp->dst); 
	laddr = nhgetl(ghp->src); 
1997/0530    
	if(raddr == 0) 
		raddr = c->raddr; 
1997/0531    
	if(laddr == 0 || Mediaforme(ghp->src) <= 0) 
1997/0530    
		laddr = c->laddr; 
 
1997/0327    
	ghp->proto = IP_GREPROTO; 
1997/0530    
	hnputl(ghp->dst, raddr); 
	hnputl(ghp->src, laddr); 
1997/0327    
	hnputs(ghp->eproto, c->rport); 
1997/0522    
	ghp->frag[0] = 0; 
	ghp->frag[1] = 0; 
1997/0327    
 
	ipoput(bp, 0, c->ttl); 
} 
 
static void 
1997/0423    
greiput(Media *m, Block *bp) 
1997/0327    
{ 
	int len; 
	GREhdr *ghp; 
	Ipaddr addr; 
	Conv *c, **p; 
	ushort eproto; 
 
1997/0423    
	USED(m); 
1997/0327    
	ghp = (GREhdr*)(bp->rp); 
 
	eproto = nhgets(ghp->eproto); 
	addr = nhgetl(ghp->src); 
 
	/* Look for a conversation structure for this port and address */ 
	c = nil; 
	for(p = gre.conv; *p; p++) { 
		c = *p; 
		if(c->inuse == 0) 
			continue; 
		if(c->raddr == addr && c->rport == eproto) 
			break; 
	} 
 
	if(*p == nil) { 
		freeblist(bp); 
		return; 
	} 
 
	/* 
	 * 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){ 
		gre.lenerr++; 
		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); 
	} 
} 
 
void 
greinit(Fs *fs) 
{ 
	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.ipproto = IP_GREPROTO; 
	gre.nc = 64; 
	gre.ptclsize = 0; 
 
	Fsproto(fs, &gre); 
} 


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