~kris/9p

9hist

f230709ddb4b27d7766f25d41d42b5ef0a27c32e — David du Colombier 34 years ago 5d5bc03
Plan 9 from Bell Labs 1992-03-13
7 files changed, 172 insertions(+), 88 deletions(-)

M port/devip.c
M port/devmnt.c
M port/ipdat.h
M port/page.c
M port/portfns.h
M port/tcpinput.c
M port/tcpoutput.c
M port/devip.c => port/devip.c +34 -14
@@ 160,18 160,18 @@ ipincoming(Ipconv *base, Ipconv *from)
	etab = &base[conf.ip];
	for(new = base; new < etab; new++) {
		if(new->ref == 0 && canqlock(new)) {
			if(new->ref ||
		          (new->stproto == &tcpinfo && new->tcpctl.state != Closed) ||
			  (new->stproto == &ilinfo && new->ilctl.state != Ilclosed)) {
			if(new->ref || ipconbusy(new)) {
				qunlock(new);
				continue;
			}
			if(from)
				/* copy ownership from listening channel */
				netown(new->net, new->index, new->net->prot[from->index].owner, 0);
				netown(new->net, new->index,
				       new->net->prot[from->index].owner, 0);
			else
				/* current user becomes owner */
				netown(new->net, new->index, u->p->user, 0);

			new->ref = 1;
			new->newcon = 0;
			qunlock(new);


@@ 242,9 242,8 @@ ipwrite(Chan *c, char *a, long n, ulong offset)
		error(Ebadarg);

	if(strcmp(field[0], "connect") == 0) {
		if((cp->stproto == &tcpinfo && cp->tcpctl.state != Closed) ||
		   (cp->stproto == &ilinfo && cp->ilctl.state != Ilclosed))
				error(Enetbusy);
		if(ipconbusy(cp))
			error(Enetbusy);

		if(m != 2)
			error(Ebadarg);


@@ 284,9 283,8 @@ ipwrite(Chan *c, char *a, long n, ulong offset)
		cp->pdst = 0;
	}
	else if(strcmp(field[0], "announce") == 0) {
		if((cp->stproto == &tcpinfo && cp->tcpctl.state != Closed) ||
		   (cp->stproto == &ilinfo && cp->ilctl.state != Ilclosed))
				error(Enetbusy);
		if(ipconbusy(cp))
			error(Enetbusy);

		if(m != 2)
			error(Ebadarg);


@@ 325,6 323,19 @@ ipwrite(Chan *c, char *a, long n, ulong offset)
	return n;
}

int
ipconbusy(Ipconv  *cp)
{
	if(cp->stproto == &tcpinfo)
	if(cp->tcpctl.state != Closed)
		return 1;

	if(cp->stproto == &ilinfo)
	if(cp->ilctl.state != Ilclosed)
		return 1;

	return 0;
}

void
udpstiput(Queue *q, Block *bp)


@@ 369,8 380,9 @@ udprcvmsg(Ipconv *muxed, Block *bp)
	/* Look for a conversation structure for this port */
	etab = &muxed[conf.ip];
	for(ifc = muxed; ifc < etab; ifc++) {
		if(ifc->psrc == dport && ifc->ref &&
		   (ifc->pdst == 0 || ifc->pdst == sport)) {
		if(ifc->ref)
		if(ifc->psrc == dport)
		if(ifc->pdst == 0 || ifc->pdst == sport) {
			/* Trim the packet down to data size */
			len = len - (UDP_HDRSIZE-UDP_PHDRSIZE);
			bp = btrim(bp, UDP_EHSIZE+UDP_HDRSIZE, len);


@@ 512,6 524,7 @@ tcpstoput(Queue *q, Block *bp)
		tcb->flags |= ACTIVE;
		send_syn(tcb);
		setstate(s, Syn_sent);

		/* No break */
	case Syn_sent:
	case Syn_received:


@@ 530,6 543,7 @@ tcpstoput(Queue *q, Block *bp)
		tcp_output(s);
		qunlock(tcb);
		break;

	default:
		freeb(bp);
		error(Ehungup);


@@ 629,8 643,12 @@ iplisten(Chan *c)
	s = &ipconv[c->dev][connection];
	base = ipconv[c->dev];

	if((s->stproto == &tcpinfo && s->tcpctl.state != Listen) ||
	   (s->stproto == &ilinfo && s->ilctl.state != Illistening))
	if(s->stproto == &tcpinfo)
	if(s->tcpctl.state != Listen)
		error(Enolisten);

	if(s->stproto == &ilinfo)
	if(s->ilctl.state != Illistening)
		error(Enolisten);

	qlock(&s->listenq);


@@ 677,12 695,14 @@ tcpstclose(Queue *q)
	case Syn_sent:
		close_self(s, 0);
		break;

	case Syn_received:
	case Established:
		tcb->sndcnt++;
		tcb->snd.nxt++;
		setstate(s, Finwait1);
		goto output;

	case Close_wait:
		tcb->sndcnt++;
		tcb->snd.nxt++;

M port/devmnt.c => port/devmnt.c +0 -1
@@ 516,7 516,6 @@ mountrpc(Mnt *m, Mntrpc *r)
	if(r->reply.type != r->request.type+1) {
		print("devmnt: mismatched reply 0x%lux T%d R%d tags req %d fls %d rep %d\n",
		r, r->request.type, r->reply.type, r->request.tag, r->flushtag, r->reply.tag);
		mntdump();
		error(Emountrpc);
	}
}

M port/ipdat.h => port/ipdat.h +3 -1
@@ 499,6 499,7 @@ void	ipremotefill(Chan*, char*, int);
void	ipstatusfill(Chan*, char*, int);
int	ipforme(uchar*);
void	ipsetaddrs(void);
int	ipconbusy(Ipconv*);

#define	fmtaddr(xx)	(xx>>24)&0xff,(xx>>16)&0xff,(xx>>8)&0xff,xx&0xff
#define	MIN(a, b)	((a) < (b) ? (a) : (b))


@@ 525,7 526,8 @@ extern Qinfo arpinfo;
extern Queue *Ipoutput;

/* offsets into Myip */
enum {
enum
{
	Myself=		0,
	Mybcast=	1,
	Mynet=		3,

M port/page.c => port/page.c +109 -24
@@ 49,56 49,141 @@ unlockpage(Page *p)
	p->lock = 0;
}

typedef struct Region	Region;
struct Region
{
	ulong	start;
	ulong	end;
};

enum
{
	Nregion=	10,
};
Region region[Nregion];


/*
 *  Called to allocate permanent data structures, before calling pageinit().
 *  We assume all of text+data+bss is in the first memory bank.
 *
 *  alignment is in number of bytes
 *
 *  WARNING: You can't cross a crevasse!
 */
void
addsplit(Region *r, ulong start, ulong end)
{
	Region *rr;
	int len = end - start;

	/* first look for an unused one */
	for(rr = region; rr < &region[Nregion]; rr++){
		if(rr == r)
			continue;
		if(rr->end - rr->start == 0){
			rr->start = start;
			rr->end = end;
			return;
		}
	}

	/* then look for a smaller one */
	for(rr = region; rr < &region[Nregion]; rr++){
		if(rr == r)
			continue;
		if(rr->end - rr->start < len){
			rr->start = start;
			rr->end = end;
			return;
		}
	}
}
void*
ialloc(ulong n, int align)
iallocspan(ulong n, int align, ulong crevasse)
{
	ulong p;
	ulong *ap;
	Region *r;
	int m;
	int ledge;

	if(palloc.active && n!=0)
		print("ialloc bad\n");

	if(palloc.addr0 == 0){
		/* addr0 and addr1 are physical addresses */
		palloc.addr0 = (((ulong)&end)&~KZERO) + conf.base0;
		palloc.addr1 = conf.base1;
		region[Nregion-2].start = (((ulong)&end)&~KZERO) + conf.base0;
		region[Nregion-2].end = conf.base0 + (conf.npage0<<PGSHIFT);
		region[Nregion-1].start = conf.base1;
		region[Nregion-1].end = conf.base1 + (conf.npage1<<PGSHIFT);

		palloc.addr0 = region[Nregion-2].start;
		palloc.addr1 = region[Nregion-1].start;
	}

	/*
	 *  try first bank
	 *  alignment also applies to length
	 */
	p = align ? PGROUND(palloc.addr0) : palloc.addr0;
	if(p+n > conf.base0 + (conf.npage0<<PGSHIFT)){
		/*
		 *  no room in first bank, try second bank
		 */
		if(conf.npage1 <= 0)
			panic("keep bill joy away 1");
		p = align ? PGROUND(palloc.addr1) : palloc.addr1;
		ap = &palloc.addr1;
	} else
		ap = &palloc.addr0;

	if(p >= conf.maxialloc)
		panic("keep bill joy away 2");
	if(align){
		m = n % align;
		if(m)
			n += align - m;
	}

	p = 0;
	for(r = region; r < &region[Nregion]; r++){
		/* allign region */
		p = r->start;
		if(align){
			m = p % align;
			if(m)
				p += align - m;
		}

		/* check for crossing a crevasse */
		if(crevasse){
			ledge = p / crevasse;
			if(ledge != ((p+n-1) / crevasse))
				p = ((p+n-1) / crevasse) * crevasse;
		}

		/* see if it fits */
		if(p + n > r->end)
			continue;

		/* split the region */
		if(p != r->start)
			addsplit(r, r->start, p);
		r->start = p + n;
		break;
	}
	if(r == &region[Nregion])
		panic("out of memory");

	/*
	 *  zero it
	 *  remember high water marks
	 */
	memset((void*)(p|KZERO), 0, n);
	if(palloc.addr0 < r->start && r->start <= conf.base0+(conf.npage0<<PGSHIFT))
		palloc.addr0 = r->start;
	else if(palloc.addr1 < r->start && r->start <= conf.base1+(conf.npage1<<PGSHIFT))
		palloc.addr1 = r->start;

	/*
	 *  don't put anything else into a page aligned ialloc
	 *  zero it
	 */
	*ap = align ? PGROUND(p+n) : (p+n);
	memset((void*)(p|KZERO), 0, n);

	return (void*)(p|KZERO);
}

/*
 *  allocate with possible page alignment
 */
void*
ialloc(ulong n, int align)
{
	return iallocspan(n, align ? BY2PG : 0, 0);
}

void
pageinit(void)
{

M port/portfns.h => port/portfns.h +1 -0
@@ 88,6 88,7 @@ void	grpinit(void);
int	hwcursmove(int, int);
int	hwcursset(uchar*, uchar*, int, int);
void*	ialloc(ulong, int);
void*	iallocspan(ulong, int, ulong);
long	ibrk(ulong, int);
int	incref(Ref*);
void	initq(IOQ*);

M port/tcpinput.c => port/tcpinput.c +17 -45
@@ 156,11 156,13 @@ process:
			goto done;
		}

		if((seg.flags & ACK) && PREC(tos) != PREC(tcb->tos)){
		if(seg.flags & ACK)
		if(PREC(tos) != PREC(tcb->tos)){
			freeb(bp);
			reset(source, dest, tos, length, &seg);
			goto done;
		}

		if(seg.flags & SYN) {
			proc_syn(s, tos, &seg);
			if(seg.flags & ACK){


@@ 193,7 195,8 @@ process:
	/* If we have no opens and the other end is sending data then
	 * reply with a reset
	 */
	if(s->readq == 0 && length) {
	if(length)
	if(s->readq == 0) {
		freeb(bp);
		reset(source, dest, tos, length, &seg);
		goto done;


@@ 293,7 296,8 @@ process:
			case Finwait2:
				/* Place on receive queue */
				tcb->rcvcnt += blen(bp);
				if(s->readq && bp) {
				if(bp)
				if(s->readq) {
					PUTNEXT(s->readq, bp);
					bp = 0;
				}


@@ 358,42 362,6 @@ done:
}

void
tcp_icmp(Ipconv *ipc, Ipaddr source, Ipaddr dest, char type, char code, Block **bpp)
{
	Tcp seg;
	Tcpctl *tcb;
	Ipconv *s;

	ntohtcp(&seg, bpp);
	if(!(s = ip_conn(ipc, seg.source, seg.dest, dest, IP_TCPPROTO)))
		return;

	tcb = &s->tcpctl;

	if(!seq_within(seg.seq, tcb->snd.una, tcb->snd.nxt))
		return;

	switch((uchar)type) {
	case ICMP_UNREACH:
		tcb->type = type;
		tcb->code = code;
		if(tcb->state == Syn_sent || tcb->state == Syn_received)
			close_self(s, Enetunreach);
		break;
	case ICMP_TIMXCEED:
		tcb->type = type;
		tcb->code = code;
		if(tcb->state == Syn_sent || tcb->state == Syn_received)
			close_self(s, Etimedout);
		break;
	case ICMP_SOURCEQUENCH:
		tcb->cwind = tcb->cwind/2;
		tcb->cwind = MAX(tcb->mss,tcb->cwind);
		break;
	}
}

void
reset(Ipaddr source, Ipaddr dest, char tos, ushort length, Tcp *seg)
{
	Block *hbp;


@@ 455,10 423,12 @@ update(Ipconv *s, Tcp *seg)
		return;
	}

	if(seq_gt(seg->seq,tcb->snd.wl1) || ((seg->seq == tcb->snd.wl1) 
	 && seq_ge(seg->ack,tcb->snd.wl2))) {
		if(tcb->snd.wnd == 0 && seg->wnd != 0)
	if(seq_ge(seg->ack,tcb->snd.wl2))
	if(seq_gt(seg->seq,tcb->snd.wl1) || (seg->seq == tcb->snd.wl1)) {
		if(seg->wnd != 0)
		if(tcb->snd.wnd == 0)
			tcb->snd.ptr = tcb->snd.una;

		tcb->snd.wnd = seg->wnd;
		tcb->snd.wl1 = seg->seq;
		tcb->snd.wl2 = seg->ack;


@@ 483,10 453,11 @@ update(Ipconv *s, Tcp *seg)
	}

	/* Round trip time estimation */
	if(run_timer(&tcb->rtt_timer) && seq_ge(seg->ack, tcb->rttseq)) {
	if(run_timer(&tcb->rtt_timer))
	if(seq_ge(seg->ack, tcb->rttseq)) {
		stop_timer(&tcb->rtt_timer);
		if(!(tcb->flags & RETRAN)) {

		if(!(tcb->flags & RETRAN)) {
			rtt = tcb->rtt_timer.start - tcb->rtt_timer.count;
			rtt *= MSPTICK;	
			if(rtt > tcb->srtt &&


@@ 654,7 625,8 @@ trim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
		len++;

	if(tcb->rcv.wnd == 0) {
		if(seg->seq == tcb->rcv.nxt && len == 0)
		if(len == 0)
		if(seg->seq == tcb->rcv.nxt)
			return 0;
	}
	else {

M port/tcpoutput.c => port/tcpoutput.c +8 -3
@@ 36,7 36,8 @@ tcp_output(Ipconv *s)
		sndq = tcb->sndq;

		/* Don't send anything else until our SYN has been acked */
		if(sent != 0 && !(tcb->flags & SYNACK))
		if(sent != 0)
		if((tcb->flags & SYNACK) == 0)
			break;

		if(tcb->snd.wnd == 0){


@@ 50,7 51,8 @@ tcp_output(Ipconv *s)
			 * limited by the congestion window
			 */
			usable = MIN(tcb->snd.wnd,tcb->cwind) - sent;
			if(sent != 0 && qlen - sent < tcb->mss) 
			if(sent != 0)
			if(qlen - sent < tcb->mss) 
				usable = 0;
		}



@@ 60,7 62,8 @@ tcp_output(Ipconv *s)
		seg.up = 0;

		DPRINT("tcp_out: ssize = %lux\n", ssize);
		if(ssize == 0 && (tcb->flags & FORCE) == 0)
		if(ssize == 0)
		if((tcb->flags & FORCE) == 0)
			break;

		/* Stop ack timer if one will be piggy backed on data */


@@ 175,9 178,11 @@ tcp_timeout(void *arg)
	switch(tcb->state){
	case Closed:
		panic("tcptimeout");

	case Time_wait:
		close_self(s, 0);
		break;

	case Established:
		if(tcb->backoff < MAXBACKOFF)
			tcb->backoff++;