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

1992/1221/port/devip.c (diff list | history)

port/devip.c on 1991/0424
1991/0424    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1991/0424    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1991/0424    
#include 	"arp.h" 
#include 	"ipdat.h" 
 
#include	"devtab.h" 
 
1991/1012    
enum 
{ 
1992/0318    
	Nrprotocol	= 3,	/* Number of protocols supported by this driver */ 
	Nipsubdir	= 4,	/* Number of subdirectory entries per connection */ 
1992/0626    
	Nfrag		= 32,	/* Ip reassembly queue entries */ 
	Nifc		= 4,	/* max interfaces */ 
1991/0424    
}; 
 
1991/1030    
int 	udpsum = 1; 
1991/12171    
Queue	*Ipoutput;			/* Control message stream for tcp/il */ 
1992/0626    
Ipifc	*ipifc[Nrprotocol+1]; 
1991/12171    
QLock	ipalloc;			/* Protocol port allocation lock */ 
1992/0626    
Ipconv	**tcpbase; 
1991/0424    
 
1992/0903    
Streamput	udpstiput, udpstoput, tcpstiput, tcpstoput; 
Streamput	iliput, iloput, bsdiput, bsdoput; 
Streamopen	udpstopen, tcpstopen, ilopen, bsdopen; 
Streamclose	udpstclose, tcpstclose, ilclose, bsdclose; 
1991/0424    
 
1992/0318    
Qinfo tcpinfo = { tcpstiput, tcpstoput, tcpstopen, tcpstclose, "tcp", 0, 1 }; 
1991/0424    
Qinfo udpinfo = { udpstiput, udpstoput, udpstopen, udpstclose, "udp" }; 
1991/1012    
Qinfo ilinfo  = { iliput,    iloput,    ilopen,    ilclose,    "il"  }; 
1992/0529    
Qinfo bsdinfo = { bsdiput,   bsdoput,	bsdopen,   bsdclose,   "bsd", 0, 1 }; 
1991/0424    
 
1991/1012    
Qinfo *protocols[] = { &tcpinfo, &udpinfo, &ilinfo, 0 }; 
1991/0424    
 
1991/1114    
void 
1992/0626    
ipinitifc(Ipifc *ifc, Qinfo *stproto) 
1991/1012    
{ 
1992/0626    
	ifc->conv = xalloc(Nipconv * sizeof(Ipconv*)); 
	ifc->protop = stproto; 
	ifc->nconv = Nipconv; 
	ifc->devp = &ipinfo; 
1991/1114    
	if(stproto != &udpinfo) 
1992/0626    
		ifc->listen = iplisten; 
	ifc->clone = ipclonecon; 
	ifc->ninfo = 3; 
	ifc->info[0].name = "remote"; 
	ifc->info[0].fill = ipremotefill; 
	ifc->info[1].name = "local"; 
	ifc->info[1].fill = iplocalfill; 
	ifc->info[2].name = "status"; 
	ifc->info[2].fill = ipstatusfill; 
	ifc->name = stproto->name; 
1991/1114    
} 
1991/0424    
 
void 
ipreset(void) 
{ 
1992/0626    
	int i; 
1991/0424    
 
1991/1012    
	for(i = 0; protocols[i]; i++) { 
1992/0626    
		ipifc[i] = xalloc(sizeof(Ipifc)); 
		ipinitifc(ipifc[i], protocols[i]); 
1991/0424    
		newqinfo(protocols[i]); 
	} 
 
1992/0626    
	initfrag(Nfrag); 
1991/0424    
} 
 
void 
ipinit(void) 
{ 
} 
 
Chan * 
ipattach(char *spec) 
{ 
	int i; 
1992/0903    
	Chan *c; 
1991/0424    
 
1992/0219    
	/* fail if ip is not yet configured */ 
	if(Ipoutput == 0) 
		error(Enoproto); 
 
1991/0424    
	for(i = 0; protocols[i]; i++) { 
		if(strcmp(spec, protocols[i]->name) == 0) { 
			c = devattach('I', spec); 
			c->dev = i; 
 
			return (c); 
		} 
	} 
 
	error(Enoproto); 
1992/0520    
	return 0;		/* not reached */ 
1991/0424    
} 
 
Chan * 
ipclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
 
int 
ipwalk(Chan *c, char *name) 
{ 
1992/0626    
	return netwalk(c, name, ipifc[c->dev]); 
1991/0424    
} 
 
void 
ipstat(Chan *c, char *db) 
{ 
1992/0626    
	netstat(c, db, ipifc[c->dev]); 
1991/0424    
} 
 
Chan * 
ipopen(Chan *c, int omode) 
{ 
1992/0626    
	return netopen(c, omode, ipifc[c->dev]); 
1991/0424    
} 
 
1991/1114    
int 
1991/0424    
ipclonecon(Chan *c) 
{ 
1992/0626    
	Ipconv *new; 
1991/0424    
 
1992/0626    
	new = ipincoming(ipifc[c->dev], 0); 
1991/1108    
	if(new == 0) 
		error(Enodev); 
1992/0626    
	return new->id; 
1991/1023    
} 
 
1992/0626    
/* 
 *  create a new conversation structure if none exists for this conversation slot 
 */ 
Ipconv* 
ipcreateconv(Ipifc *ifc, int id) 
1991/1023    
{ 
1992/0626    
	Ipconv **p; 
	Ipconv *new; 
1991/1023    
 
1992/0626    
	p = &ifc->conv[id]; 
	if(*p) 
		return *p; 
	qlock(ifc); 
	p = &ifc->conv[id]; 
	if(*p){ 
		qunlock(ifc); 
		return *p; 
	} 
	if(waserror()){ 
		qunlock(ifc); 
		nexterror(); 
	} 
	new = smalloc(sizeof(Ipconv)); 
	new->ifc = ifc; 
	netadd(ifc, new, p - ifc->conv); 
	new->ref = 1; 
	*p = new; 
	qunlock(ifc); 
	poperror(); 
	return new; 
} 
 
/* 
 *  allocate a conversation structure. 
 */ 
Ipconv* 
ipincoming(Ipifc *ifc, Ipconv *from) 
{ 
	Ipconv *new; 
1992/0903    
	Ipconv **p, **etab; 
1992/0626    
 
	/* look for an unused existing conversation */ 
	etab = &ifc->conv[Nipconv]; 
	for(p = ifc->conv; p < etab; p++) { 
		new = *p; 
		if(new == 0) 
			break; 
1991/0424    
		if(new->ref == 0 && canqlock(new)) { 
1992/0313    
			if(new->ref || ipconbusy(new)) { 
1991/0424    
				qunlock(new); 
				continue; 
			} 
1992/0318    
			if(from)	/* copy ownership from listening channel */ 
1992/0623    
				netown(new, from->owner, 0); 
1992/0318    
			else		/* current user becomes owner */ 
1992/0623    
				netown(new, u->p->user, 0); 
1992/0313    
 
1991/1114    
			new->ref = 1; 
1991/0424    
			qunlock(new); 
			return new; 
		}	 
	} 
1992/0626    
 
	/* create one */ 
	qlock(ifc); 
	etab = &ifc->conv[Nipconv]; 
	for(p = ifc->conv; ; p++){ 
		if(p == etab){ 
			qunlock(ifc); 
			return 0; 
		} 
		if(*p == 0) 
			break; 
	} 
	if(waserror()){ 
		qunlock(ifc); 
		nexterror(); 
	} 
	new = smalloc(sizeof(Ipconv)); 
	new->ifc = ifc; 
	netadd(ifc, new, p - ifc->conv); 
	qlock(new); 
	*p = new; 
	qunlock(ifc); 
1992/0728    
	poperror(); 
1992/0626    
	if(from)	/* copy ownership from listening channel */ 
		netown(new, from->owner, 0); 
	else		/* current user becomes owner */ 
		netown(new, u->p->user, 0); 
	new->ref = 1; 
	qunlock(new); 
	return new; 
1991/0424    
} 
 
void 
ipcreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1991/1115    
	USED(c, name, omode, perm); 
1991/0424    
	error(Eperm); 
} 
 
void 
ipremove(Chan *c) 
{ 
1991/1115    
	USED(c); 
1991/0424    
	error(Eperm); 
} 
 
void 
ipwstat(Chan *c, char *dp) 
{ 
1992/0626    
	netwstat(c, dp, ipifc[c->dev]); 
1991/0424    
} 
 
void 
ipclose(Chan *c) 
{ 
1991/1114    
	if(c->stream) 
1991/0424    
		streamclose(c); 
} 
 
long 
ipread(Chan *c, void *a, long n, ulong offset) 
{ 
1992/0626    
	return netread(c, a, n, offset, ipifc[c->dev]); 
1991/0424    
} 
 
long 
ipwrite(Chan *c, char *a, long n, ulong offset) 
{ 
1992/0128    
	int 	m, backlog, type, priv; 
1991/1024    
	char 	*field[5], *ctlarg[5], buf[256]; 
1992/0128    
	Port	port; 
1991/1024    
	Ipconv  *cp; 
1991/0424    
 
1992/0711    
	USED(offset); 
1991/0424    
	type = STREAMTYPE(c->qid.path); 
	if (type == Sdataqid) 
		return streamwrite(c, a, n, 0);  
 
1991/1024    
	if (type != Sctlqid) 
		error(Eperm); 
1991/0424    
 
1992/0626    
	cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path)); 
1991/0424    
 
1991/1024    
	m = n; 
	if(m > sizeof(buf)-1) 
		m = sizeof(buf)-1; 
	strncpy(buf, a, m); 
	buf[m] = '\0'; 
1991/0516    
 
1991/1024    
	m = getfields(buf, field, 5, ' '); 
	if(m < 1) 
1992/0111    
		error(Ebadarg); 
1991/0424    
 
1991/1024    
	if(strcmp(field[0], "connect") == 0) { 
1992/0313    
		if(ipconbusy(cp)) 
			error(Enetbusy); 
1991/0424    
 
1991/1024    
		if(m != 2) 
			error(Ebadarg); 
1991/0424    
 
1991/1025    
		switch(getfields(field[1], ctlarg, 5, '!')) { 
1991/1024    
		default: 
1992/0528    
			error(Eneedservice); 
1991/1024    
		case 2: 
1992/0128    
			priv = 0; 
1991/1024    
			break; 
		case 3: 
			if(strcmp(ctlarg[2], "r") != 0) 
				error(Eperm); 
1992/0128    
			priv = 1; 
1991/1024    
			break; 
1991/0424    
		} 
1991/1024    
		cp->dst = ipparse(ctlarg[0]); 
		cp->pdst = atoi(ctlarg[1]); 
1991/0516    
 
1991/1024    
		/* If we have no local port assign one */ 
1992/0416    
		if(cp->psrc == 0){ 
			qlock(&ipalloc); 
1992/0626    
			cp->psrc = nextport(ipifc[c->dev], priv); 
1992/0416    
			qunlock(&ipalloc); 
		} 
1991/0424    
 
1992/0626    
		if(cp->ifc->protop == &tcpinfo) 
1991/1114    
			tcpstart(cp, TCP_ACTIVE, Streamhi, 0); 
1992/0626    
		else if(cp->ifc->protop == &ilinfo) 
1991/1124    
			ilstart(cp, IL_ACTIVE, 20); 
1991/1114    
 
1992/0529    
		/* 
		 *  stupid hack for BSD port's 512, 513, & 514 
		 *  to make it harder for user to lie about his 
		 *  identity. -- presotto 
		 */ 
		switch(cp->pdst){ 
		case 512: 
		case 513: 
		case 514: 
			pushq(c->stream, &bsdinfo); 
			break; 
		} 
1991/1024    
	} 
1991/1125    
	else if(strcmp(field[0], "disconnect") == 0) { 
1992/0626    
		if(cp->ifc->protop != &udpinfo) 
1991/1125    
			error(Eperm); 
 
		cp->dst = 0; 
		cp->pdst = 0; 
	} 
1991/1104    
	else if(strcmp(field[0], "announce") == 0) { 
1992/0313    
		if(ipconbusy(cp)) 
			error(Enetbusy); 
1991/0424    
 
1991/1024    
		if(m != 2) 
			error(Ebadarg); 
 
		port = atoi(field[1]); 
 
1992/0416    
		if(port){ 
			qlock(&ipalloc); 
1992/0626    
			if(portused(ipifc[c->dev], port)) { 
1992/0416    
				qunlock(&ipalloc);	 
				error(Einuse); 
			} 
			cp->psrc = port; 
			qunlock(&ipalloc); 
		} else if(*field[1] != '*'){ 
			qlock(&ipalloc); 
1992/0626    
			cp->psrc = nextport(ipifc[c->dev], 0); 
1992/0416    
			qunlock(&ipalloc); 
		} else 
			cp->psrc = 0; 
1991/1114    
 
1992/0626    
		if(cp->ifc->protop == &tcpinfo) 
1991/1114    
			tcpstart(cp, TCP_PASSIVE, Streamhi, 0); 
1992/0626    
		else if(cp->ifc->protop == &ilinfo) 
1991/1114    
			ilstart(cp, IL_PASSIVE, 10); 
 
		if(cp->backlog == 0) 
			cp->backlog = 3; 
1991/0424    
	} 
1991/1024    
	else if(strcmp(field[0], "backlog") == 0) { 
		if(m != 2) 
			error(Ebadarg); 
		backlog = atoi(field[1]); 
		if(backlog == 0) 
			error(Ebadarg); 
		if(backlog > 5) 
			backlog = 5; 
		cp->backlog = backlog; 
	} 
1992/0627    
	else if(strcmp(field[0], "headers") == 0) { 
		cp->headers = 1;	/* include addr/port in user packet */ 
	} 
1991/1024    
	else 
		return streamwrite(c, a, n, 0); 
1991/0424    
 
1991/1024    
	return n; 
1991/0424    
} 
 
1992/0313    
int 
ipconbusy(Ipconv  *cp) 
{ 
1992/0626    
	if(cp->ifc->protop == &tcpinfo) 
1992/0313    
	if(cp->tcpctl.state != Closed) 
		return 1; 
1991/0424    
 
1992/0626    
	if(cp->ifc->protop == &ilinfo) 
1992/0313    
	if(cp->ilctl.state != Ilclosed) 
		return 1; 
 
	return 0; 
} 
 
1991/0424    
void 
udpstiput(Queue *q, Block *bp) 
{ 
1991/0516    
	PUTNEXT(q, bp); 
1991/0424    
} 
 
/* 
 * udprcvmsg - called by stip to multiplex udp ports onto conversations 
 */ 
void 
1992/0626    
udprcvmsg(Ipifc *ifc, Block *bp) 
1991/0424    
{ 
1992/0626    
	Ipconv *cp, **p, **etab; 
1991/0424    
	Udphdr *uh; 
1991/1125    
	Port   dport, sport; 
1991/0424    
	ushort sum, len; 
	Ipaddr addr; 
1992/0627    
	Block *nbp; 
1991/0424    
 
	uh = (Udphdr *)(bp->rptr); 
 
	/* Put back pseudo header for checksum */ 
	uh->Unused = 0; 
	len = nhgets(uh->udplen); 
	hnputs(uh->udpplen, len); 
 
	addr = nhgetl(uh->udpsrc); 
 
	if(udpsum && nhgets(uh->udpcksum)) { 
		if(sum = ptcl_csum(bp, UDP_EHSIZE, len+UDP_PHDRSIZE)) { 
			print("udp: checksum error %x (%d.%d.%d.%d)\n", 
			      sum, fmtaddr(addr)); 
			 
			freeb(bp); 
			return; 
		} 
	} 
 
	dport = nhgets(uh->udpdport); 
1991/1125    
	sport = nhgets(uh->udpsport); 
1991/0424    
 
	/* Look for a conversation structure for this port */ 
1992/0626    
	etab = &ifc->conv[Nipconv]; 
	for(p = ifc->conv; p < etab; p++) { 
		cp = *p; 
		if(cp == 0) 
			break; 
		if(cp->ref) 
		if(cp->psrc == dport) 
		if(cp->pdst == 0 || cp->pdst == sport) { 
1991/0424    
			/* Trim the packet down to data size */ 
			len = len - (UDP_HDRSIZE-UDP_PHDRSIZE); 
			bp = btrim(bp, UDP_EHSIZE+UDP_HDRSIZE, len); 
			if(bp == 0) 
				return; 
 
1992/0627    
			if(cp->headers){ 
				/* pass the src address to the stream head */ 
				nbp = allocb(Udphdrsize); 
				nbp->next = bp; 
				bp = nbp; 
				hnputl(bp->wptr, addr); 
				bp->wptr += 4; 
				hnputs(bp->wptr, sport); 
				bp->wptr += 2; 
			} else { 
				/* save the src address in the conversation struct */ 
			 	cp->dst = addr; 
				cp->pdst = sport; 
			} 
1992/0626    
			PUTNEXT(cp->readq, bp); 
1991/0424    
			return; 
		} 
	} 
 
	freeb(bp); 
} 
 
void 
udpstoput(Queue *q, Block *bp) 
{ 
1992/0627    
	Ipconv *cp; 
1991/0424    
	Udphdr *uh; 
1991/1104    
	int dlen, ptcllen, newlen; 
1992/0627    
	Ipaddr addr; 
	Port port; 
1991/0424    
 
1991/1104    
	if(bp->type == M_CTL) { 
		PUTNEXT(q, bp); 
		return; 
	} 
 
1992/0627    
	cp = (Ipconv *)(q->ptr); 
	if(cp->psrc == 0) 
1991/0424    
		error(Enoport); 
 
	if(bp->type != M_DATA) { 
		freeb(bp); 
		error(Ebadctl); 
	} 
 
	/* Only allow atomic udp writes to form datagrams */ 
	if(!(bp->flags & S_DELIM)) { 
		freeb(bp); 
		error(Emsgsize); 
	} 
 
1992/0627    
	/* 
	 *  if we're in header mode, rip off the first 64 bytes as the 
	 *  destination.  The destination is in ascii in the form 
	 *	%d.%d.%d.%d!%d 
	 */ 
	if(cp->headers){ 
		/* get user specified addresses */ 
		bp = pullup(bp, Udphdrsize); 
		if(bp == 0){ 
			freeb(bp); 
			error(Emsgsize); 
		} 
		addr = nhgetl(bp->rptr); 
		bp->rptr += 4; 
		port = nhgets(bp->rptr); 
		bp->rptr += 2; 
	} else 
		addr = port = 0; 
 
1991/0424    
	/* Round packet up to even number of bytes and check we can 
	 * send it 
	 */ 
	dlen = blen(bp); 
	if(dlen > UDP_DATMAX) { 
		freeb(bp); 
		error(Emsgsize); 
	} 
	newlen = bround(bp, 1); 
 
	/* Make space to fit udp & ip & ethernet header */ 
	bp = padb(bp, UDP_EHSIZE + UDP_HDRSIZE); 
 
	uh = (Udphdr *)(bp->rptr); 
 
	ptcllen = dlen + (UDP_HDRSIZE-UDP_PHDRSIZE); 
	uh->Unused = 0; 
	uh->udpproto = IP_UDPPROTO; 
1992/0106    
	uh->frag[0] = 0; 
	uh->frag[1] = 0; 
1991/0424    
	hnputs(uh->udpplen, ptcllen); 
1992/0213    
	hnputl(uh->udpsrc, Myip[Myself]); 
1992/0627    
	hnputs(uh->udpsport, cp->psrc); 
1992/0903    
	if(cp->headers) { 
1992/0627    
		hnputl(uh->udpdst, addr); 
		hnputs(uh->udpdport, port); 
1992/0903    
	} 
	else { 
1992/0627    
		hnputl(uh->udpdst, cp->dst); 
		hnputs(uh->udpdport, cp->pdst); 
	} 
1991/0424    
	hnputs(uh->udplen, ptcllen); 
	uh->udpcksum[0] = 0; 
	uh->udpcksum[1] = 0; 
 
	hnputs(uh->udpcksum, ptcl_csum(bp, UDP_EHSIZE, newlen+UDP_HDRSIZE)); 
	PUTNEXT(q, bp); 
} 
 
void 
udpstclose(Queue *q) 
{ 
	Ipconv *ipc; 
 
	ipc = (Ipconv *)(q->ptr); 
 
1992/0627    
	ipc->headers = 0; 
1991/1114    
	ipc->psrc = 0; 
	ipc->pdst = 0; 
	ipc->dst = 0; 
1991/0424    
} 
 
void 
udpstopen(Queue *q, Stream *s) 
{ 
	Ipconv *ipc; 
 
1992/0626    
	ipc = ipcreateconv(ipifc[s->dev], s->id); 
1992/0711    
	initipifc(ipifc[s->dev], IP_UDPPROTO, udprcvmsg, 1500, 512, ETHER_HDR); 
1991/0424    
 
	ipc->readq = RD(q);	 
	RD(q)->ptr = (void *)ipc; 
1992/0626    
	WR(q)->next->ptr = (void *)ipc->ifc; 
1991/0424    
	WR(q)->ptr = (void *)ipc; 
} 
 
void 
tcpstiput(Queue *q, Block *bp) 
{ 
1991/0516    
	PUTNEXT(q, bp); 
1991/0424    
} 
 
1992/1221    
tcproominq(void *a) 
{ 
	return !((Tcpctl *)a)->sndfull; 
} 
 
1991/0424    
void 
tcpstoput(Queue *q, Block *bp) 
{ 
	Ipconv *s; 
	Tcpctl *tcb;  
1991/1126    
	Block *f; 
1991/0424    
 
	s = (Ipconv *)(q->ptr); 
	tcb = &s->tcpctl; 
 
1991/1104    
	if(bp->type == M_CTL) { 
		PUTNEXT(q, bp); 
		return; 
	} 
 
1991/0424    
	if(s->psrc == 0) 
		error(Enoport); 
 
	/* Report asynchronous errors */ 
	if(s->err) 
		error(s->err); 
 
	switch(tcb->state) { 
1991/12171    
	case Listen: 
1991/0424    
		tcb->flags |= ACTIVE; 
1992/0903    
		tcpsndsyn(tcb); 
		tcpsetstate(s, Syn_sent); 
1992/0313    
 
1991/0424    
		/* No break */ 
1991/12171    
	case Syn_sent: 
	case Syn_received: 
	case Established: 
	case Close_wait: 
1992/0903    
		/* 
1992/1221    
		 * Process flow control 
	 	 */ 
		if(tcb->sndfull){ 
			qlock(&tcb->sndrlock); 
			if(waserror()) { 
				qunlock(&tcb->sndrlock); 
				nexterror(); 
			} 
			sleep(&tcb->sndr, tcproominq, tcb); 
			poperror(); 
			qunlock(&tcb->sndrlock); 
		} 
 
		/* 
1992/0903    
		 * Push data 
		 */ 
1991/0424    
		qlock(tcb); 
1992/0322    
		if(waserror()) { 
			qunlock(tcb); 
			nexterror(); 
		} 
1991/1126    
		tcb->sndcnt += blen(bp); 
1992/1221    
		if(tcb->sndcnt > Streamhi) 
			tcb->sndfull = 1; 
1991/1126    
		if(tcb->sndq == 0) 
			tcb->sndq = bp; 
		else { 
			for(f = tcb->sndq; f->next; f = f->next) 
				; 
			f->next = bp; 
		} 
1991/0424    
		tcprcvwin(s); 
1992/0903    
		tcpoutput(s); 
1992/0322    
		poperror(); 
1991/0424    
		qunlock(tcb); 
		break; 
1992/0313    
 
1991/0424    
	default: 
		freeb(bp); 
		error(Ehungup); 
	}	 
} 
 
void 
tcpstopen(Queue *q, Stream *s) 
{ 
	Ipconv *ipc; 
1992/0626    
	Ipifc *ifc; 
1992/0416    
	Tcpctl *tcb; 
	Block *bp;	 
1991/1019    
	static int tcpkprocs; 
1991/0424    
 
1991/1019    
	if(!Ipoutput) { 
		Ipoutput = WR(q); 
1991/0430    
		s->opens++; 
1991/0504    
		s->inuse++; 
1991/1019    
	} 
 
	/* Flow control and tcp timer processes */ 
	if(tcpkprocs == 0) { 
		tcpkprocs = 1; 
1991/0424    
		kproc("tcpack", tcpackproc, 0); 
1992/0626    
		kproc("tcpflow", tcpflow, ipifc[s->dev]); 
1991/0430    
 
1991/0424    
	} 
 
1992/0416    
	if(tcpbase == 0) 
1992/0626    
		tcpbase = ipifc[s->dev]->conv; 
	ifc = ipifc[s->dev]; 
1992/0903    
	initipifc(ifc, IP_TCPPROTO, tcpinput, 1500, 512, ETHER_HDR); 
1992/0626    
	ipc = ipcreateconv(ifc, s->id); 
1991/0424    
 
	ipc->readq = RD(q); 
	ipc->readq->rp = &tcpflowr; 
1992/0128    
	ipc->err = 0; 
1991/0424    
 
	RD(q)->ptr = (void *)ipc; 
1992/0626    
	WR(q)->next->ptr = (void *)ipc->ifc; 
1991/0424    
	WR(q)->ptr = (void *)ipc; 
1992/0416    
 
	/* pass any waiting data upstream */ 
	tcb = &ipc->tcpctl; 
	qlock(tcb); 
	while(bp = getb(&tcb->rcvq)) 
		PUTNEXT(ipc->readq, bp); 
	qunlock(tcb); 
1991/0424    
} 
 
1991/1114    
void 
ipremotefill(Chan *c, char *buf, int len) 
{ 
	Ipconv *cp; 
 
1992/0711    
	if(len < 24) 
		error(Ebadarg); 
1992/0626    
	cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path)); 
1992/0717    
	sprint(buf, "%d.%d.%d.%d!%d\n", fmtaddr(cp->dst), cp->pdst); 
1991/1114    
} 
1991/1124    
 
1991/1114    
void 
iplocalfill(Chan *c, char *buf, int len) 
{ 
	Ipconv *cp; 
 
1992/0711    
	if(len < 24) 
		error(Ebadarg); 
1992/0626    
	cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path)); 
1992/0717    
	sprint(buf, "%d.%d.%d.%d!%d\n", fmtaddr(Myip[Myself]), cp->psrc); 
1991/1114    
} 
1991/1124    
 
1991/1114    
void 
ipstatusfill(Chan *c, char *buf, int len) 
{ 
	Ipconv *cp; 
1992/0903    
	int connection; 
1991/1114    
 
1992/0711    
	if(len < 64) 
		error(Ebadarg); 
1991/1114    
	connection = STREAMID(c->qid.path); 
1992/0626    
	cp = ipcreateconv(ipifc[c->dev], connection); 
	if(cp->ifc->protop == &tcpinfo) 
1991/1114    
		sprint(buf, "tcp/%d %d %s %s\n", connection, cp->ref, 
			tcpstate[cp->tcpctl.state], 
			cp->tcpctl.flags & CLONE ? "listen" : "connect"); 
1992/0626    
	else if(cp->ifc->protop == &ilinfo) 
1992/0307    
		sprint(buf, "il/%d %d %s rtt %d ms %d csum\n", connection, cp->ref, 
			ilstate[cp->ilctl.state], cp->ilctl.rtt, 
1992/0626    
			cp->ifc ? cp->ifc->chkerrs : 0); 
1991/1114    
	else 
1992/0720    
		sprint(buf, "%s/%d %d Datagram\n", 
				cp->ifc->protop->name, connection, cp->ref); 
1991/1114    
} 
 
1991/0424    
int 
1991/1023    
iphavecon(Ipconv *s) 
1991/0424    
{ 
	return s->curlog; 
} 
 
1991/1114    
int 
iplisten(Chan *c) 
1991/0424    
{ 
1992/0626    
	Ipconv *s; 
1991/1114    
	int connection; 
1992/0903    
	Ipconv **p, **etab, *new; 
1991/0424    
 
1991/1114    
	connection = STREAMID(c->qid.path); 
1992/0626    
	s = ipcreateconv(ipifc[c->dev], connection); 
1991/1114    
 
1992/0626    
	if(s->ifc->protop == &tcpinfo) 
1992/0313    
	if(s->tcpctl.state != Listen) 
1992/0112    
		error(Enolisten); 
1991/1114    
 
1992/0626    
	if(s->ifc->protop == &ilinfo) 
1992/0313    
	if(s->ilctl.state != Illistening) 
		error(Enolisten); 
 
1991/0424    
	for(;;) { 
1992/0414    
		qlock(&s->listenq);	/* single thread for the sleep */ 
		if(waserror()) { 
			qunlock(&s->listenq); 
			nexterror(); 
		} 
1991/1023    
		sleep(&s->listenr, iphavecon, s); 
1991/1025    
		poperror(); 
1992/0626    
		etab = &ipifc[c->dev]->conv[Nipconv]; 
 		for(p = ipifc[c->dev]->conv; p < etab; p++) { 
			new = *p; 
			if(new == 0) 
				break; 
1992/0414    
			if(new->newcon == s) { 
1992/0306    
				qlock(s); 
1991/0424    
				s->curlog--; 
1992/0306    
				qunlock(s); 
1991/1023    
				new->newcon = 0; 
1991/0424    
				qunlock(&s->listenq); 
1992/0626    
				return new->id; 
1991/0424    
			} 
		} 
1992/0414    
		qunlock(&s->listenq); 
1992/0307    
		print("iplisten: no newcon\n"); 
1991/0424    
	} 
1992/0520    
	return -1;		/* not reached */ 
1991/0424    
} 
 
void 
tcpstclose(Queue *q) 
{ 
	Ipconv *s; 
1992/0626    
	Ipconv **etab, **p; 
1991/0424    
	Tcpctl *tcb; 
 
	s = (Ipconv *)(q->ptr); 
	tcb = &s->tcpctl; 
 
	/* Not interested in data anymore */ 
1992/0223    
	qlock(s); 
1991/0424    
	s->readq = 0; 
1992/0223    
	qunlock(s); 
1991/0424    
 
	switch(tcb->state){ 
1991/12171    
	case Listen: 
1992/0416    
		/* 
		 *  reset any incoming calls to this listener 
		 */ 
		qlock(s); 
		s->backlog = 0; 
		s->curlog = 0; 
1992/0626    
		etab = &tcpbase[Nipconv]; 
		for(p = tcpbase; p < etab && *p; p++){ 
			if((*p)->newcon == s) { 
				(*p)->newcon = 0; 
				tcpflushincoming(*p); 
1992/0416    
			} 
		} 
		qunlock(s); 
 
		qlock(tcb); 
1992/0826    
		localclose(s, 0); 
1992/0416    
		qunlock(tcb); 
		break; 
 
	case Closed: 
1991/12171    
	case Syn_sent: 
1992/0416    
		qlock(tcb); 
1992/0826    
		localclose(s, 0); 
1992/0416    
		qunlock(tcb); 
1991/0424    
		break; 
1992/0313    
 
1991/12171    
	case Syn_received: 
	case Established: 
1991/0424    
		tcb->sndcnt++; 
		tcb->snd.nxt++; 
1992/0903    
		tcpsetstate(s, Finwait1); 
1991/0424    
		goto output; 
1992/0313    
 
1991/12171    
	case Close_wait: 
1991/0424    
		tcb->sndcnt++; 
		tcb->snd.nxt++; 
1992/0903    
		tcpsetstate(s, Last_ack); 
1991/0424    
	output: 
		qlock(tcb); 
1992/0322    
		if(waserror()) { 
			qunlock(tcb); 
			nexterror(); 
		} 
1992/0903    
		tcpoutput(s); 
1992/0322    
		poperror(); 
1991/0424    
		qunlock(tcb); 
		break; 
	} 
} 
 
 
1992/0101    
static	short	endian	= 1; 
static	char*	aendian	= (char*)&endian; 
#define	LITTLE	*aendian 
 
1991/0424    
ushort 
1992/0101    
ptcl_bsum(uchar *addr, int len) 
{ 
	ulong losum, hisum, mdsum, x; 
	ulong t1, t2; 
 
	losum = 0; 
	hisum = 0; 
	mdsum = 0; 
 
	x = 0; 
	if((ulong)addr & 1) { 
		if(len) { 
			hisum += addr[0]; 
			len--; 
			addr++; 
		} 
		x = 1; 
	} 
	while(len >= 16) { 
		t1 = *(ushort*)(addr+0); 
		t2 = *(ushort*)(addr+2);	mdsum += t1; 
		t1 = *(ushort*)(addr+4);	mdsum += t2; 
		t2 = *(ushort*)(addr+6);	mdsum += t1; 
		t1 = *(ushort*)(addr+8);	mdsum += t2; 
		t2 = *(ushort*)(addr+10);	mdsum += t1; 
		t1 = *(ushort*)(addr+12);	mdsum += t2; 
		t2 = *(ushort*)(addr+14);	mdsum += t1; 
		mdsum += t2; 
		len -= 16; 
		addr += 16; 
	} 
	while(len >= 2) { 
		mdsum += *(ushort*)addr; 
		len -= 2; 
		addr += 2; 
	} 
	if(x) { 
		if(len) 
			losum += addr[0]; 
		if(LITTLE) 
			losum += mdsum; 
		else 
			hisum += mdsum; 
	} else { 
		if(len) 
			hisum += addr[0]; 
		if(LITTLE) 
			hisum += mdsum; 
		else 
			losum += mdsum; 
	} 
 
	losum += hisum >> 8; 
	losum += (hisum & 0xff) << 8; 
	while(hisum = losum>>16) 
		losum = hisum + (losum & 0xffff); 
 
	return losum & 0xffff; 
} 
 
ushort 
1991/0424    
ptcl_csum(Block *bp, int offset, int len) 
{ 
	uchar *addr; 
1992/0101    
	ulong losum, hisum; 
1991/0424    
	ushort csum; 
	int odd, blen, x; 
 
	/* Correct to front of data area */ 
	while(bp && offset && offset >= BLEN(bp)) { 
		offset -= BLEN(bp); 
		bp = bp->next; 
	} 
	if(bp == 0) 
		return 0; 
 
	addr = bp->rptr + offset; 
	blen = BLEN(bp) - offset; 
1992/0101    
 
	if(bp->next == 0) 
		return ~ptcl_bsum(addr, MIN(len, blen)) & 0xffff; 
 
	losum = 0; 
	hisum = 0; 
 
1991/0424    
	odd = 0; 
	while(len) { 
1992/0101    
		x = MIN(len, blen); 
		csum = ptcl_bsum(addr, x); 
		if(odd) 
			hisum += csum; 
		else 
			losum += csum; 
		odd = (odd+x) & 1; 
		len -= x; 
 
1991/0424    
		bp = bp->next; 
		if(bp == 0) 
			break; 
		blen = BLEN(bp); 
		addr = bp->rptr; 
	} 
 
	losum += hisum>>8; 
	losum += (hisum&0xff)<<8; 
	while((csum = losum>>16) != 0) 
		losum = csum + (losum & 0xffff); 
 
	return ~losum & 0xffff; 
} 
 
Block * 
btrim(Block *bp, int offset, int len) 
{ 
	Block *nb, *startb; 
	ulong l; 
 
	if(blen(bp) < offset+len) { 
		freeb(bp); 
		return 0; 
	} 
 
	while((l = BLEN(bp)) < offset) { 
		offset -= l; 
		nb = bp->next; 
		bp->next = 0; 
		freeb(bp); 
		bp = nb; 
	} 
 
	startb = bp; 
	bp->rptr += offset; 
 
	while((l = BLEN(bp)) < len) { 
		len -= l; 
		bp = bp->next; 
	} 
 
	bp->wptr -= (BLEN(bp) - len); 
	bp->flags |= S_DELIM; 
 
	if(bp->next) { 
		freeb(bp->next); 
		bp->next = 0; 
	} 
 
	return(startb); 
} 
 
Ipconv * 
1992/0626    
portused(Ipifc *ifc, Port port) 
1991/0424    
{ 
1992/0626    
	Ipconv **p, **etab; 
	Ipconv *cp; 
1991/0424    
 
1992/0406    
	if(port == 0) 
		return 0; 
 
1992/0626    
	etab = &ifc->conv[Nipconv]; 
	for(p = ifc->conv; p < etab; p++){ 
		cp = *p; 
		if(cp == 0) 
			break; 
		if(cp->psrc == port)  
			return cp; 
	} 
1991/0424    
 
	return 0; 
} 
 
1992/0128    
static Port lastport[2] = { PORTALLOC-1, PRIVPORTALLOC-1 }; 
 
1991/0424    
Port 
1992/0626    
nextport(Ipifc *ifc, int priv) 
1991/0424    
{ 
1992/0128    
	Port base; 
	Port max; 
	Port *p; 
1991/0424    
	Port i; 
 
1992/0128    
	if(priv){ 
		base = PRIVPORTALLOC; 
1992/12051    
		max = UNPRIVPORTALLOC; 
1992/0128    
		p = &lastport[1]; 
	} else { 
		base = PORTALLOC; 
		max = PORTMAX; 
		p = &lastport[0]; 
	} 
	 
	for(i = *p + 1; i < max; i++) 
1992/0626    
		if(!portused(ifc, i)) 
1992/0128    
			return(*p = i); 
	for(i = base ; i <= *p; i++) 
1992/0626    
		if(!portused(ifc, i)) 
1992/0128    
			return(*p = i); 
1991/12171    
 
1991/0424    
	return(0); 
} 
 
/* NEEDS HASHING ! */ 
 
1992/0626    
Ipconv* 
1992/0711    
ip_conn(Ipifc *ifc, Port dst, Port src, Ipaddr dest) 
1991/0424    
{ 
1992/0626    
	Ipconv **p, *s, **etab; 
1991/0424    
 
	/* Look for a conversation structure for this port */ 
1992/0626    
	etab = &ifc->conv[Nipconv]; 
	for(p = ifc->conv; p < etab; p++) { 
		s = *p; 
		if(s == 0) 
			break; 
1991/12171    
		if(s->psrc == dst) 
		if(s->pdst == src) 
		if(s->dst == dest || dest == 0) 
1991/0424    
			return s; 
	} 
 
	return 0; 
1992/0529    
} 
 
/* 
 *  Fuck me sideways with a bargepole!!! -- philw 
 * 
 *  BSD authentication protocol, used on ports 512, 513, & 514. 
 *  This makes sure that a user can only write the REAL user id. 
 * 
 *  q->ptr is number of nulls seen 
 */ 
void 
bsdopen(Queue *q, Stream *s) 
{ 
1992/0711    
	USED(s); 
1992/0529    
	RD(q)->ptr = q; 
	WR(q)->ptr = q; 
} 
void 
bsdclose(Queue *q) 
{ 
	Block *bp; 
 
	bp = allocb(0); 
	bp->type = M_HANGUP; 
	PUTNEXT(q->other, bp); 
} 
void 
bsdiput(Queue *q, Block *bp) 
{ 
	PUTNEXT(q, bp); 
} 
void 
bsdoput(Queue *q, Block *bp) 
{ 
	uchar *luser; 
	Block *nbp; 
 
	/* just pass it on if we've done authentication */ 
	if(q->ptr == 0 || bp->type != M_DATA){ 
		PUTNEXT(q, bp); 
		return; 
	} 
 
	/* collect into a single block */ 
1992/0602    
	qlock(&q->rlock); 
1992/0529    
	if(q->first == 0) 
		q->first = pullup(bp, blen(bp)); 
	else{ 
		nbp = q->first; 
		nbp->next = bp; 
		q->first = pullup(nbp, blen(nbp)); 
	} 
	bp = q->first; 
	if(bp == 0){ 
1992/0602    
		qunlock(&q->rlock); 
1992/0529    
		bsdclose(q); 
		return; 
	} 
 
	/* look for 2 nulls to indicate stderr port and local user */ 
	luser = memchr(bp->rptr, 0, BLEN(bp)); 
	if(luser == 0){ 
1992/0602    
		qunlock(&q->rlock); 
1992/0529    
		return; 
	} 
	luser++; 
	if(memchr(luser, 0, bp->wptr - luser) == 0){ 
1992/0602    
		qunlock(&q->rlock); 
1992/0529    
		return; 
	} 
 
	/* if luser is a lie, hangup */ 
	if(memcmp(luser, u->p->user, strlen(u->p->user)+1) != 0) 
		bsdclose(q); 
 
	/* mark queue as authenticated and pass data to remote side */ 
	q->ptr = 0; 
	q->first = 0; 
	bp->flags |= S_DELIM; 
	PUTNEXT(q, bp); 
1992/0602    
	qunlock(&q->rlock); 
1991/0424    
} 


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