~kris/9p

9hist

c334856610642f1e49f6177b9866629f0293b78f — David du Colombier 29 years ago 9443499
Plan 9 from Bell Labs 1997-04-23
11 files changed, 345 insertions(+), 24 deletions(-)

M ip/devip.c
M ip/gre.c
M ip/icmp.c
A ip/igmp.c
M ip/il.c
M ip/ip.c
M ip/ip.h
M ip/ipaux.c
M ip/netlog.c
M ip/tcp.c
M ip/udp.c
M ip/devip.c => ip/devip.c +16 -5
@@ 137,6 137,8 @@ ipgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	switch(TYPE(c->qid)) {
	case Qtopdir:
		if(s < fs.np) {
			if(fs.p[s]->connect == nil)
				return 0;	/* protocol with no user interface */
			q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0};
			devdir(c, q, fs.p[s]->name, 0, network, CHDIR|0555, dp);
			return 1;


@@ 270,6 272,9 @@ ipopen(Chan* c, int omode)
	switch(TYPE(c->qid)) {
	default:
		break;
	case Qipifc:
		c->aux = newifcconv();
		break;
	case Qlog:
		netlogopen();
		break;


@@ 402,6 407,10 @@ ipclose(Chan* c)
	switch(TYPE(c->qid)) {
	default:
		break;
	case Qipifc:
		closeifcconv(c->aux);
		c->aux = nil;
		break;
	case Qlog:
		netlogclose();
		break;


@@ 530,7 539,8 @@ setlport(Conv* c)
static void
setladdrport(Conv* c, char* str)
{
	char *p, addr[4];
	char *p;
	uchar addr[Ipaddrlen];

	p = strchr(str, '!');
	if(p == nil) {


@@ 540,7 550,7 @@ setladdrport(Conv* c, char* str)
	else {
		*p++ = 0;
		parseip(addr, str);
		c->laddr = nhgetl((byte*)addr);
		c->laddr = nhgetl(addr);
	}
	if(*p == '*')
		c->lport = 0;


@@ 554,14 564,15 @@ setladdrport(Conv* c, char* str)
static char*
setraddrport(Conv* c, char* str)
{
	char *p, addr[4];
	char *p;
	uchar addr[Ipaddrlen];

	p = strchr(str, '!');
	if(p == nil)
		return "malformed address";
	*p++ = 0;
	parseip(addr, str);
	c->raddr = nhgetl((byte*)addr);
	c->raddr = nhgetl(addr);
	c->rport = atoi(p);
	p = strchr(p, '!');
	if(p){


@@ 600,7 611,7 @@ ipwrite(Chan* ch, char* a, long n, ulong)
			error(p);
		return n;
	case Qipifc:
		p = Mediaifcwrite(a, n);
		p = Mediaifcwrite(ch->aux, a, n);
		if(p != nil)
			error(p);
		return n;

M ip/gre.c => ip/gre.c +2 -1
@@ 163,7 163,7 @@ grekick(Conv *c, int l)
}

static void
greiput(Block *bp)
greiput(Media *m, Block *bp)
{
	int len;
	GREhdr *ghp;


@@ 171,6 171,7 @@ greiput(Block *bp)
	Conv *c, **p;
	ushort eproto;

	USED(m);
	ghp = (GREhdr*)(bp->rp);

	eproto = nhgets(ghp->eproto);

M ip/icmp.c => ip/icmp.c +2 -1
@@ 173,7 173,7 @@ static char *unreachcode[] =
};

static void
icmpiput(Block *bp)
icmpiput(Media *m, Block *bp)
{
	int	n, iplen;
	Icmp	*p;


@@ 182,6 182,7 @@ icmpiput(Block *bp)
	char	*msg;
	char	m2[128];

	USED(m);
	p = (Icmp *)bp->rp;
	netlog(Logicmp, "icmpiput %d %d\n", p->type, p->code);
	n = blocklen(bp);

A ip/igmp.c => ip/igmp.c +272 -0
@@ 0,0 1,272 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

#include "ip.h"

enum
{
	IGMP_IPHDRSIZE	= 20,		/* size of ip header */
	IGMP_HDRSIZE	= 8,		/* size of IGMP header */
	IP_IGMPPROTO	= 2,

	IGMPquery	= 1,
	IGMPreport	= 2,

	MSPTICK		= 100,
	MAXTIMEOUT	= 10000/MSPTICK,	/* at most 10 secs for a response */
};

typedef struct IGMPpkt IGMPpkt;
struct IGMPpkt
{
	/* 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 of ip portion */
	byte	src[Ipaddrlen];		/* Ip source */
	byte	dst[Ipaddrlen];		/* Ip destination */

	/* igmp header */
	byte	vertype;	/* version and type */
	byte	unused;
	byte	igmpcksum[2];		/* checksum of igmp portion */
	byte	group[Ipaddrlen];	/* multicast group */
};

/*
 *  lists for group reports
 */
typedef struct IGMPrep IGMPrep;
struct IGMPrep
{
	IGMPrep		*next;
	Media		*m;
	int		ticks;
	Multicast	*multi;
};

typedef struct IGMP IGMP;
struct IGMP
{
	Lock;
	Rendez	r;
	Rendez	r0;
	IGMPrep	*reports;
};

IGMP igmpalloc;

	Proto	igmp;
extern	Fs	fs;

void
igmpsendreport(Media *m, byte *addr)
{
	IGMPpkt *p;
	Block *bp;

	bp = allocb(sizeof(IGMPpkt));
	if(bp == nil)
		return;
	p = (IGMPpkt*)bp->wp;
	bp->wp += sizeof(IGMPpkt);
	memset(bp->rp, 0, sizeof(IGMPpkt));
	hnputl(p->src, Mediagetaddr(m));
	hnputl(p->dst, Ipallsys);
	p->vertype = (1<<4) | IGMPreport;
	p->proto = IP_IGMPPROTO;
	memmove(p->group, addr, Ipaddrlen);
	hnputs(p->igmpcksum, ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE));
	netlog(Logigmp, "igmpreport %I\n", p->group);
	ipoput(bp, 0, 1);	/* TTL of 1 */
}

static int
isreport(void *a)
{
	USED(a);
	return igmpalloc.reports != 0;
}


void
igmpproc(void *a)
{
	IGMPrep *rp, **lrp;
	Multicast *mp, **lmp;
	byte ip[Ipaddrlen];

	USED(a);

	for(;;){
		sleep(&igmpalloc.r, isreport, 0);
		for(;;){
			lock(&igmpalloc);

			if(igmpalloc.reports == nil)
				break;
	
			/* look for a single report */
			lrp = &igmpalloc.reports;
			mp = nil;
			for(rp = *lrp; rp; rp = *lrp){
				rp->ticks++;
				lmp = &rp->multi;
				for(mp = *lmp; mp; mp = *lmp){
					if(rp->ticks >= mp->timeout){
						*lmp = mp->next;
						break;
					}
					lmp = &mp->next;
				}
				if(mp != nil)
					break;

				if(rp->multi != nil){
					lrp = &rp->next;
					continue;
				} else {
					*lrp = rp->next;
					free(rp);
				}
			}
			unlock(&igmpalloc);

			if(mp){
				/* do a single report and try again */
				hnputl(ip, mp->addr);
				igmpsendreport(rp->m, ip);
				free(mp);
				continue;
			}

			tsleep(&igmpalloc.r0, return0, 0, MSPTICK);
		}
		unlock(&igmpalloc);
	}

}

void
igmpiput(Media *m, Block *bp)
{
	int n;
	IGMPpkt *ghp;
	Ipaddr group;
	IGMPrep *rp, **lrp;
	Multicast *mp, **lmp;

	ghp = (IGMPpkt*)(bp->rp);
	netlog(Logigmp, "igmpiput: %d %I\n", ghp->vertype, ghp->group);

	n = blocklen(bp);
	if(n < IGMP_IPHDRSIZE+IGMP_HDRSIZE){
		netlog(Logigmp, "igmpiput: bad len\n");
		goto error;
	}
	if((ghp->vertype>>4) != 1){
		netlog(Logigmp, "igmpiput: bad igmp type\n");
		goto error;
	}
	if(ptclcsum(bp, IGMP_IPHDRSIZE, IGMP_HDRSIZE)){
		netlog(Logigmp, "igmpiput: checksum error %I\n", ghp->src);
		goto error;
	}

	group = nhgetl(ghp->group);
	
	lock(&igmpalloc);
	switch(ghp->vertype & 0xf){
	case IGMPquery:
		/*
		 *  start reporting groups that we're a member of.
		 */
		for(rp = igmpalloc.reports; rp; rp = rp->next)
			if(rp->m == m)
				break;
		if(rp != nil)
			break;	/* already reporting */

		mp = Mediacopymulti(m);
		if(mp == nil)
			break;

		rp = malloc(sizeof(*rp));
		if(rp == 0)
			break;

		rp->m = m;
		rp->multi = mp;
		rp->ticks = 0;
		for(; mp; mp = mp->next)
			mp->timeout = nrand(MAXTIMEOUT);
		rp->next = igmpalloc.reports;
		igmpalloc.reports = rp;

		wakeup(&igmpalloc.r);

		break;
	case IGMPreport:
		/*
		 *  find report list for this medium
		 */
		lrp = &igmpalloc.reports;
		for(rp = *lrp; rp; rp = *lrp){
			if(rp->m == m)
				break;
			lrp = &rp->next;
		}
		if(rp == nil)
			break;

		/*
		 *  if someone else has reported a group,
		 *  we don't have to.
		 */
		lmp = &rp->multi;
		for(mp = *lmp; mp; mp = *lmp){
			if(mp->addr == group){
				*lmp = mp->next;
				free(mp);
				break;
			}
			lmp = &mp->next;
		}

		break;
	}
	unlock(&igmpalloc);

error:
	freeb(bp);
}

void
igmpinit(Fs *fs)
{
	igmp.name = "igmp";
	igmp.kick = nil;
	igmp.connect = nil;
	igmp.announce = nil;
	igmp.ctl = nil;
	igmp.state = nil;
	igmp.close = nil;
	igmp.rcv = igmpiput;
	igmp.ipproto = IP_IGMPPROTO;
	igmp.nc = 0;
	igmp.ptclsize = 0;

	igmpreportfn = igmpsendreport;
	kproc("igmpproc", igmpproc, 0);

	Fsproto(fs, &igmp);
}

M ip/il.c => ip/il.c +3 -2
@@ 140,7 140,7 @@ void	iltimers(Ilcb*);
char*	ilstart(Conv*, int, int);
void	ilackproc();
void	iloutoforder(Conv*, Ilhdr*, Block*);
void	iliput(Block*);
void	iliput(Media*, Block*);
void	iladvise(Block*, char*);

#define DBG(x)	if((logmask & Logilmsg) && (iponly == 0 || x == iponly))netlog


@@ 379,7 379,7 @@ ilackto(Ilcb *ic, ulong ackto)
}

void
iliput(Block *bp)
iliput(Media *m, Block *bp)
{
	char *st;
	Ilcb *ic;


@@ 389,6 389,7 @@ iliput(Block *bp)
	int plen, illen;
	Conv *s, **p, *new, *spec, *gen;

	USED(m);
	ih = (Ilhdr *)bp->rp;
	plen = blocklen(bp);
	if(plen < IL_IPSIZE+IL_HDRSIZE){

M ip/ip.c => ip/ip.c +7 -3
@@ 104,7 104,11 @@ ipoput(Block *bp, int gating, int ttl)
		goto raise;
	}

	m = Mediaroute(eh->dst, gate);
	if(isbmcast(eh->dst)){
		m = Mediaroute(eh->src, nil);
		memmove(gate, eh->dst, Ipaddrlen);
	} else
		m = Mediaroute(eh->dst, gate);
	if(m == nil){
		netlog(Logip, "no interface %I\n", eh->dst);
		goto raise;


@@ 222,7 226,7 @@ initfrag(int size)
void (*ipextprotoiput)(Block*);

void
ipiput(Block *bp)
ipiput(Media *m, Block *bp)
{
	Iphdr *h;
	Proto *p;


@@ 288,7 292,7 @@ ipiput(Block *bp)

	p = Fsrcvpcol(&fs, h->proto);
	if(p != nil && p->rcv != nil)
		(*p->rcv)(bp);
		(*p->rcv)(m, bp);
	else if(ipextprotoiput != nil)
		ipextprotoiput(bp);
	else

M ip/ip.h => ip/ip.h +34 -6
@@ 3,8 3,10 @@ typedef uchar	byte;
typedef struct	Conv	Conv;
typedef struct	Fs	Fs;
typedef union	Hwaddr	Hwaddr;
typedef struct	Ifcconv	Ifcconv;
typedef struct	Iproute	Iproute;
typedef struct	Media	Media;
typedef struct	Multicast	Multicast;
typedef struct	Proto	Proto;
typedef struct	Pstate	Pstate;
typedef struct	Tcpc	Tcpc;


@@ 19,8 21,11 @@ enum

	MAXTTL=		255,

	Ipaddrlen=	4,
	Ipbcast=	0xffffffff,	/* ip broadcast address */
	Ipbcastobs=	0,		/* obsolete (but still used) ip broadcast addr */
	Ipallsys=	0xe0000001,	/* multicast for all systems */
	Ipallrouter=	0xe0000002,	/* multicast for all routers */
};

enum


@@ 87,11 92,21 @@ enum
	MPACKET,
};

/* one per multicast address per medium */
struct Multicast
{
	Ipaddr	addr;
	int	ref;
	int	timeout;
	Multicast *next;
};

struct Media
{
	int	type;		/* Media type */
	Chan*	mchan;		/* Data channel */
	Chan*	achan;		/* Arp channel */
	Chan*	cchan;		/* Control channel */
	char*	dev;		/* device mfd points to */
	Ipaddr	myip[5];
	Ipaddr	mymask;


@@ 108,6 123,10 @@ struct Media
	int	inuse;
	Conv	*c;		/* for packet interface */

	QLock	mlock;		/* lock for changing *multi */
	Multicast *multi;	/* list of multicast addresses we're listening to */
	int	mactive;	/* number of active multicast addresses */

	Media*	link;
};
int	Mediaforme(byte*);


@@ 122,11 141,14 @@ Ipaddr	Mediagetaddr(Media*);
Ipaddr	Mediagetraddr(Media*);
void	Mediawrite(Media*, Block*, byte*);
int	Mediaifcread(char*, ulong, int);
char*	Mediaifcwrite(char*, int);
char*	Mediaifcwrite(Ifcconv*, char*, int);
void	Mediaresolver(Media*);
void	Mediaread(Media*);
int	Mediaarp(Media*, Block*, byte*, Hwaddr*);
Media*	Mediafind(Iproute*);
Multicast*	Mediacopymulti(Media*);
void	Mediamulticastadd(Media*, Ifcconv*, Ipaddr);
void	Mediamulticastrem(Media*, Ipaddr);

/*
 *  one per multiplexed protocol


@@ 144,7 166,7 @@ struct Proto
	int		(*state)(char**, Conv*);
	void		(*create)(Conv*);
	void		(*close)(Conv*);
	void		(*rcv)(Block*);
	void		(*rcv)(Media*, Block*);
	char*		(*ctl)(Conv*, char**, int);
	void		(*advise)(Block*, char*);



@@ 195,6 217,7 @@ enum
	Loggre=		1<<9,
	Logppp=		1<<10,
	Logtcpmsg=	1<<11,
	Logigmp=	1<<12,
};

extern int	logmask;	/* mask of things to debug */


@@ 213,9 236,11 @@ extern int	debug;
extern Fs	fs;
extern Media*	media;
extern int	iprouting;	/* true if routing turned on */
extern void	(*igmpreportfn)(Media*, byte*);

int	arpread(byte*, ulong, int);
char*	arpwrite(char*, int);
void	closeifcconv(Ifcconv*);
Ipaddr	defmask(Ipaddr);
int	eipconv(va_list*, Fconv*);
int	equivip(byte*, byte*);


@@ 226,19 251,22 @@ void	initfrag(int);
ushort	ipcsum(byte*);
void	(*ipextprotoiput)(Block*);
Ipaddr	ipgetsrc(byte*);
void	ipiput(Block*);
void	ipiput(Media*, Block*);
void	ipoput(Block*, int, int);
int	ipstats(char*, int);
int	ismcast(byte*);
int	isbmcast(byte*);
byte*	logctl(byte*);
void	maskip(byte*, byte*, byte*);
Ifcconv* newifcconv(void);
ulong	nhgetl(byte*);
ushort	nhgets(byte*);
void	(*pktifcrcv)(Conv*, Block*);
ushort	ptclcsum(Block*, int, int);
int	pullblock(Block**, int);
Block*	pullupblock(Block*, int);
char*	routeadd(Ipaddr, Ipaddr, Ipaddr);
void	routedelete(ulong, ulong);
char*	routeadd(Ipaddr, Ipaddr, Ipaddr, Media *m);
void	routedelete(ulong, ulong, Media *m);
int	routeread(byte*, ulong, int);
char*	routewrite(char*, int);



@@ 246,4 274,4 @@ char*	routewrite(char*, int);
 * ipaux.c
 */
int	myetheraddr(uchar*, char*);
ulong	parseip(char*, char*);
ulong	parseip(uchar*, char*);

M ip/ipaux.c => ip/ipaux.c +2 -2
@@ 212,7 212,7 @@ eipconv(va_list *arg, Fconv *f)
#define CLASS(p) ((*(uchar*)(p))>>6)

ulong
parseip(char *to, char *from)
parseip(uchar *to, char *from)
{
	int i;
	char *p;


@@ 243,5 243,5 @@ parseip(char *to, char *from)
		}
		break;
	}
	return nhgetl((uchar*)to);
	return nhgetl(to);
}

M ip/netlog.c => ip/netlog.c +2 -1
@@ 148,7 148,8 @@ netlogctl(char* s, int len)
{
	int i, n, set;
	Logflag *f;
	char *fields[10], *p, addr[4], buf[256];
	char *fields[10], *p, buf[256];
	uchar addr[Ipaddrlen];

	if(len == 0)
		return Ebadnetctl;

M ip/tcp.c => ip/tcp.c +3 -2
@@ 190,7 190,7 @@ void	addreseq(Tcpctl*, Tcp*, Block*, ushort);
void	getreseq(Tcpctl*, Tcp*, Block**, ushort*);
void	localclose(Conv*, char*);
void	procsyn(Conv*, Tcp*);
void	tcpiput(Block*);
void	tcpiput(Media*, Block*);
void	tcpoutput(Conv*);
int	tcptrim(Tcpctl*, Tcp*, Block**, ushort*);
void	tcpstart(Conv*, int, ushort);


@@ 1052,7 1052,7 @@ update(Conv *s, Tcp *seg)
}

void
tcpiput(Block *bp)
tcpiput(Media *m, Block *bp)
{
	Tcp seg;
	Tcphdr *h;


@@ 1062,6 1062,7 @@ tcpiput(Block *bp)
	Ipaddr source, dest;
	Conv *spec, *gen, *s, **p;

	USED(m);
	h = (Tcphdr*)(bp->rp);

	dest = nhgetl(h->tcpdst);

M ip/udp.c => ip/udp.c +2 -1
@@ 200,7 200,7 @@ udpkick(Conv *c, int l)
}

void
udpiput(Block *bp)
udpiput(Media *m, Block *bp)
{
	int len;
	Udphdr *uh;


@@ 209,6 209,7 @@ udpiput(Block *bp)
	Udpcb *ucb;
	ushort dport, sport;

	USED(m);
	uh = (Udphdr*)(bp->rp);

	/* Put back pseudo header for checksum */