20 files changed, 16 insertions(+), 9218 deletions(-)
D port/arp.h
D port/bootp.h
D port/devarp.c
D port/devdk.c
D port/devip.c
D port/deviproute.c
D port/ipdat.h
M port/proc.c
M port/qio.c
D port/stasync.c
D port/stfcall.c
D port/stil.c
D port/stip.c
D port/streboot.c
D port/stsplice.c
D port/sturp.c
D port/tcpif.c
D port/tcpinput.c
D port/tcpoutput.c
D port/tcptimer.c
D port/arp.h => port/arp.h +0 -45
@@ 1,45 0,0 @@
-/*
- * this file used by (at least) the kernel, arpd, snoopy, tboot
- */
-typedef struct Arppkt Arppkt;
-typedef struct Arpentry Arpentry;
-typedef struct Arpstats Arpstats;
-
-/* Format of ethernet arp request */
-struct Arppkt {
- uchar d[6];
- uchar s[6];
- uchar type[2];
- uchar hrd[2];
- uchar pro[2];
- uchar hln;
- uchar pln;
- uchar op[2];
- uchar sha[6];
- uchar spa[4];
- uchar tha[6];
- uchar tpa[4];
- };
-
-#define ARPSIZE 42
-
-/* Format of request from starp to user level arpd */
-struct Arpentry {
- uchar etaddr[6];
- uchar ipaddr[4];
- };
-
-/* Arp cache statistics */
-struct Arpstats {
- int hit;
- int miss;
- int failed;
- };
-
-#define ET_ARP 0x0806
-#define ET_RARP 0x8035
-
-#define ARP_REQUEST 1
-#define ARP_REPLY 2
-#define RARP_REQUEST 3
-#define RARP_REPLY 4
D port/bootp.h => port/bootp.h +0 -29
@@ 1,29 0,0 @@
-/*
- * this file used by (at least) snoopy, tboot and bootp
- */
-enum
-{
- Bootrequest = 1,
- Bootreply = 2,
-};
-
-typedef struct Bootp Bootp;
-struct Bootp
-{
- uchar op; /* opcode */
- uchar htype; /* hardware type */
- uchar hlen; /* hardware address len */
- uchar hops; /* hops */
- uchar xid[4]; /* a random number */
- uchar secs[2]; /* elapsed snce client started booting */
- uchar pad[2];
- uchar ciaddr[4]; /* client IP address (client tells server) */
- uchar yiaddr[4]; /* client IP address (server tells client) */
- uchar siaddr[4]; /* server IP address */
- uchar giaddr[4]; /* gateway IP address */
- uchar chaddr[16]; /* client hardware address */
- char sname[64]; /* server host name (optional) */
- char file[128]; /* boot file name */
- char vend[128]; /* vendor-specific goo */
-};
-
D port/devarp.c => port/devarp.c +0 -489
@@ 1,489 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "arp.h"
-#include "ipdat.h"
-
-#include "devtab.h"
-
-#define ARP_FREE 0
-#define ARP_OK 1
-#define ARP_ASKED 2
-#define ARP_TEMP 0
-#define ARP_PERM 1
-#define Arphashsize 32
-#define ARPHASH(p) arphash[((p[2]^p[3])%Arphashsize)]
-
-typedef struct Arpcache Arpcache;
-struct Arpcache
-{
- uchar status;
- uchar type;
- uchar eip[4];
- uchar et[6];
- Arpcache *hash;
- Arpcache **hashhd;
- Arpcache *frwd;
- Arpcache *prev;
-};
-
-Arpstats arpstats;
-Arpcache *arplruhead, *arplrutail;
-Arpcache *arp, **arphash;
-Queue *Servq;
-Lock larphash;
-
-void arpiput(Queue *, Block *);
-void arpoput(Queue *, Block *);
-void arpopn(Queue *, Stream *);
-void arpcls(Queue *);
-void arpenter(Arpentry*, int);
-void arpflush(void);
-int arpdelete(char*);
-void arplinkhead(Arpcache*);
-int arplookup(uchar*, uchar*);
-
-Qinfo arpinfo = { arpiput, arpoput, arpopn, arpcls, "arp" };
-
-#define ARP_ENTRYLEN 50
-char *padstr = " ";
-
-enum{
- arpdirqid,
- arpdir2qid,
- arpstatqid,
- arpctlqid,
- arpdataqid,
-};
-
-Dirtab arptab[]={
- "stats", {arpstatqid}, 0, 0444,
- "ctl", {arpctlqid}, 0, 0664,
- "data", {arpdataqid}, 0, 0664,
-};
-#define Narptab (sizeof(arptab)/sizeof(Dirtab))
-
-/*
- * create a 2-level directory
- */
-int
-arpgen(Chan *c, void *vp, int ntab, int i, Dir *dp)
-{
- Qid q;
-
- USED(vp);
- USED(ntab);
-
- q.vers = 0;
-
- /* top level directory contains the directory arp */
- if(c->qid.path == CHDIR){
- if(i)
- return -1;
- q.path = CHDIR | arpdir2qid;
- devdir(c, q, "arp", 0, eve, 0555, dp);
- return 1;
- }
-
- /* next level uses table */
- return devgen(c, arptab, Narptab, i, dp);
-}
-
-void
-arpreset(void)
-{
- Arpcache *ap, *ep;
-
- arp = xalloc(sizeof(Arpcache) * conf.arp);
- arphash = (Arpcache **)xalloc(sizeof(Arpcache *) * Arphashsize);
-
- ep = &arp[conf.arp];
- for(ap = arp; ap < ep; ap++) {
- ap->frwd = ap+1;
- ap->prev = ap-1;
- ap->type = ARP_FREE;
- ap->status = ARP_TEMP;
- }
-
- arp[0].prev = 0;
- arplruhead = arp;
- ap = &arp[conf.arp-1];
- ap->frwd = 0;
- arplrutail = ap;
- newqinfo(&arpinfo);
-}
-
-void
-arpinit(void)
-{
-}
-
-Chan *
-arpattach(char *spec)
-{
- return devattach('a', spec);
-}
-
-Chan *
-arpclone(Chan *c, Chan *nc)
-{
- return devclone(c, nc);
-}
-
-int
-arpwalk(Chan *c, char *name)
-{
- return devwalk(c, name, 0, 0, arpgen);
-}
-
-void
-arpstat(Chan *c, char *db)
-{
- devstat(c, db, 0, 0, arpgen);
-}
-
-Chan *
-arpopen(Chan *c, int omode)
-{
- if(c->qid.path&CHDIR){
- if(omode != OREAD)
- error(Eperm);
- }
-
- switch(STREAMTYPE(c->qid.path)) {
- case arpdataqid:
- break;
- case arpstatqid:
- if(omode != OREAD)
- error(Ebadarg);
- break;
- case arpctlqid:
- break;
- }
-
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
-}
-
-void
-arpcreate(Chan *c, char *name, int omode, ulong perm)
-{
- USED(c, name, omode, perm);
- error(Eperm);
-}
-
-void
-arpremove(Chan *c)
-{
- USED(c);
- error(Eperm);
-}
-
-void
-arpwstat(Chan *c, char *dp)
-{
- USED(c, dp);
- error(Eperm);
-}
-
-void
-arpclose(Chan *c)
-{
- streamclose(c);
-}
-
-long
-arpread(Chan *c, void *a, long n, ulong offset)
-{
- char buf[100];
- Arpcache *ap;
- int part, bytes, size;
- char *ststr;
-
- if(c->qid.path&CHDIR)
- return devdirread(c, a, n, arptab, Narptab, arpgen);
-
- switch((int)(c->qid.path&~CHDIR)){
- case arpdataqid:
- bytes = c->offset;
- while(bytes < conf.arp*ARP_ENTRYLEN && n) {
- ap = &arp[bytes/ARP_ENTRYLEN];
- part = bytes%ARP_ENTRYLEN;
-
- if(ap->status != ARP_OK)
- ststr = "invalid";
- else
- ststr = (ap->type == ARP_TEMP ? "temp" : "perm");
-
- sprint(buf,"%d.%d.%d.%d to %.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s%s",
- ap->eip[0], ap->eip[1], ap->eip[2], ap->eip[3],
- ap->et[0], ap->et[1], ap->et[2], ap->et[3],
- ap->et[4], ap->et[5],
- ststr, padstr);
-
- buf[ARP_ENTRYLEN-1] = '\n';
-
- size = ARP_ENTRYLEN - part;
- size = MIN(n, size);
- memmove(a, buf+part, size);
-
- a = (void *)((int)a + size);
- n -= size;
- bytes += size;
- }
- return bytes - c->offset;
- break;
- case arpstatqid:
- sprint(buf, "hits: %d miss: %d failed: %d\n",
- arpstats.hit, arpstats.miss, arpstats.failed);
-
- return readstr(offset, a, n, buf);
- default:
- n=0;
- break;
- }
- return n;
-}
-
-long
-arpwrite(Chan *c, char *a, long n, ulong offset)
-{
- Arpentry entry;
- char buf[20], *field[5];
- int m;
-
- USED(offset);
-
- switch(STREAMTYPE(c->qid.path)) {
- case arpctlqid:
-
- strncpy(buf, a, sizeof buf);
- m = getfields(buf, field, 5, ' ');
-
- if(strncmp(field[0], "flush", 5) == 0)
- arpflush();
- else
- if(strcmp(field[0], "delete") == 0) {
- if(m != 2)
- error(Ebadarg);
-
- if(arpdelete(field[1]) < 0)
- error(Enetaddr);
- }
- break;
-
- case arpdataqid:
- if(n != sizeof(Arpentry))
- error(Emsgsize);
- memmove(&entry, a, sizeof(Arpentry));
- arpenter(&entry, ARP_TEMP);
- break;
-
- default:
- error(Ebadusefd);
- }
-
- return n;
-}
-
-void
-arpopn(Queue *q, Stream *s)
-{
- USED(q, s);
-}
-
-void
-arpcls(Queue *q)
-{
- if(q == Servq)
- Servq = 0;
-}
-
-void
-arpiput(Queue *q, Block *bp)
-{
- PUTNEXT(q, bp);
-}
-
-void
-arpoput(Queue *q, Block *bp)
-{
- uchar ip[4];
- Etherhdr *eh;
- Ipaddr addr;
- static int dropped;
-
- if(bp->type != M_DATA) {
- if(Servq == 0 && streamparse("arpd", bp)) {
- Servq = RD(q);
- freeb(bp);
- }
- else
- PUTNEXT(q, bp);
- return;
- }
-
- eh = (Etherhdr *)bp->rptr;
- if(nhgets(eh->type) != ET_IP) {
- PUTNEXT(q, bp);
- return;
- }
-
- /* if ip broadcast, use ether bcast address */
- addr = nhgetl(eh->dst);
- if(Myip[Myself] == 0 || addr == Myip[Mybcast] || addr == Myip[Mynet]
- || ((addr & Mymask) == Myip[Mynet+1] && (addr & ~Mynetmask) == ~Mynetmask)){
- memset(eh->d, 0xff, sizeof(eh->d));
- PUTNEXT(q, bp);
- return;
- }
-
- iproute(eh->dst, ip);
-
- /* if a known ip addr, send downstream to the ethernet */
- if(arplookup(ip, eh->d)) {
- PUTNEXT(q, bp);
- return;
- }
-
- /* Push the packet up to the arp server for address resolution */
- if(!Servq) {
- if((dropped++ % 1000) == 0)
- print("arp: No server, packet dropped %d.%d.%d.%d\n",
- eh->dst[0], eh->dst[1], eh->dst[2], eh->dst[3]);
- freeb(bp);
- return;
- }
- memmove(eh->d, ip, sizeof(ip));
- PUTNEXT(Servq, bp);
-}
-
-int
-arplookup(uchar *ip, uchar *et)
-{
- Arpcache *ap;
-
- lock(&larphash);
- for(ap = ARPHASH(ip); ap; ap = ap->hash) {
- if(ap->status == ARP_OK && memcmp(ap->eip, ip, sizeof(ap->eip)) == 0) {
- memmove(et, ap->et, sizeof(ap->et));
- arplinkhead(ap);
- unlock(&larphash);
- arpstats.hit++;
- return 1;
- }
- }
- arpstats.miss++;
- unlock(&larphash);
- return 0;
-}
-
-void
-arpflush(void)
-{
- Arpcache *ap, *ep;
-
- ep = &arp[conf.arp];
- for(ap = arp; ap < ep; ap++)
- ap->status = ARP_FREE;
-}
-
-void
-arpenter(Arpentry *ape, int type)
-{
- Arpcache *ap, **l, *d;
-
-
- /* Update an entry if we have one already */
- l = &ARPHASH(ape->ipaddr);
- lock(&larphash);
- for(ap = *l; ap; ap = ap->hash) {
- if(ap->status == ARP_OK && memcmp(ap->eip, ape->ipaddr, sizeof(ap->eip)) == 0) {
- if(ap->type != ARP_PERM) {
- ap->type = type;
- memmove(ap->et, ape->etaddr, sizeof(ap->et));
- ap->status = ARP_OK;
- }
- unlock(&larphash);
- return;
- }
- }
-
- /* Find an entry to replace */
- for(ap = arplrutail; ap && ap->type == ARP_PERM; ap = ap->prev)
- ;
-
- if(!ap) {
- print("arp: too many permanent entries\n");
- unlock(&larphash);
- return;
- }
-
- if(ap->hashhd) {
- for(d = *ap->hashhd; d; d = d->hash) {
- if(d == ap) {
- *(ap->hashhd) = ap->hash;
- break;
- }
- ap->hashhd = &d->hash;
- }
- }
-
- ap->type = type;
- ap->status = ARP_OK;
- memmove(ap->eip, ape->ipaddr, sizeof(ape->ipaddr));
- memmove(ap->et, ape->etaddr, sizeof(ape->etaddr));
- ap->hashhd = l;
- ap->hash = *l;
- *l = ap;
- arplinkhead(ap);
- unlock(&larphash);
-}
-
-int
-arpdelete(char *addr)
-{
- Arpcache *ap;
- uchar ip[4];
- Ipaddr i;
- int rv;
-
- rv = -1;
- i = ipparse(addr);
- hnputl(ip, i);
- lock(&larphash);
- for(ap = arplruhead; ap; ap = ap->frwd) {
- if(memcmp(ap->eip, ip, sizeof(ap->eip)) == 0) {
- ap->status = ARP_FREE;
- rv = 0;
- break;
- }
- }
- unlock(&larphash);
- return rv;
-}
-
-void
-arplinkhead(Arpcache *ap)
-{
- if(ap != arplruhead) {
- if(ap->prev)
- ap->prev->frwd = ap->frwd;
- else
- arplruhead = ap->frwd;
-
- if(ap->frwd)
- ap->frwd->prev = ap->prev;
- else
- arplrutail = ap->prev;
-
- ap->frwd = arplruhead;
- ap->prev = 0;
- arplruhead = ap;
- }
-}
D port/devdk.c => port/devdk.c +0 -1636
@@ 1,1636 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-#define DPRINT if(0) print
-
-#define NOW (MACHP(0)->ticks)
-
-typedef struct Dkmsg Dkmsg;
-typedef struct Line Line;
-typedef struct Dk Dk;
-
-enum {
- Maxdk = 4,
-};
-
-/*
- * types of possible dkcalls
- */
-enum {
- Dial,
- Announce,
- Redial
-};
-
-/*
- * format of messages to/from the datakit controller on the common
- * signalling line
- */
-struct Dkmsg {
- uchar type;
- uchar srv;
- uchar param0l;
- uchar param0h;
- uchar param1l;
- uchar param1h;
- uchar param2l;
- uchar param2h;
- uchar param3l;
- uchar param3h;
- uchar param4l;
- uchar param4h;
-};
-
-/*
- * message codes (T_xxx == dialin.type, D_xxx == dialin.srv)
- */
-#define T_SRV 1 /* service request */
-#define D_SERV 1 /* (host to dkmux) announce a service */
-#define D_DIAL 2 /* (host to dkmux) connect to a service */
-#define D_XINIT 7 /* (dkmux to host) line has been spliced */
-#define T_REPLY 2 /* reply to T_SRV/D_SERV or T_SRV/D_DIAL */
-#define D_OK 1 /* not used */
-#define D_OPEN 2 /* (dkmux to host) connection established */
-#define D_FAIL 3 /* (dkmux to host) connection failed */
-#define T_CHG 3 /* change the status of a connection */
-#define D_CLOSE 1 /* close the connection */
-#define D_ISCLOSED 2 /* (dkmux to host) confirm a close */
-#define D_CLOSEALL 3 /* (dkmux to host) close all connections */
-#define D_REDIAL 6 /* (host to dkmux) redial a call */
-#define T_ALIVE 4 /* (host to dkmux) keep alive message */
-#define D_CONTINUE 0 /* host has not died since last msg */
-#define D_RESTART 1 /* host has restarted */
-#define D_MAXCHAN 2 /* request maximum line number */
-#define T_RESTART 8 /* (dkmux to host) datakit restarted */
-
-/*
- * macros for cracking/forming the window negotiation parameter
- */
-#define MIN(x,y) (x < y ? x : y)
-#define W_WINDOW(o,d,t) ((o<<8) | (d<<4) | t | 0100000)
-#define W_VALID(x) ((x) & 0100000)
-#define W_ORIG(x) (((x)>>8) & 017)
-#define W_DEST(x) (((x)>>4) & 017)
-#define W_TRAF(x) ((x) & 017)
-#define W_DESTMAX(x,y) (W_WINDOW(W_ORIG(x),MIN(W_DEST(x),y),W_TRAF(x)))
-#define W_LIMIT(x,y) (W_WINDOW(MIN(W_ORIG(x),y),MIN(W_DEST(x),y),W_TRAF(x)))
-#define W_VALUE(x) (1<<((x)+4))
-
-struct Line {
- QLock;
- Netprot; /* stat info */
- int lineno;
- Rendez r; /* wait here for dial */
- int state; /* dial state */
- int err; /* dialing error (if non zero) */
- int window; /* negotiated window */
- int timestamp; /* timestamp of last call received on this line */
- int calltolive; /* multiple of 15 seconds for dialing state to last */
- Queue *rq;
- char addr[64];
- char raddr[64];
- char ruser[32];
- Dk *dp; /* interface contianing this line */
-};
-
-/*
- * a dkmux dk. one exists for every stream that a
- * dkmux line discipline is pushed onto.
- */
-struct Dk
-{
- QLock netlock;
- Network net; /* stat info */
- Line **linep; /* array of line structures */
-
- QLock csclock;
- Chan *csc;
-
- char name[64]; /* dk name */
- Queue *wq; /* dk output queue */
- int ncsc; /* csc line number */
- int lines; /* number of lines */
- int restart;
- int urpwindow;
- Rendez timer;
- int closeall; /* set when we receive a closeall message */
- Rendez closeallr; /* wait here for a closeall */
-};
-Lock dklock;
-Dk *dk[Maxdk];
-
-/*
- * conversation states (for Line.state)
- */
-typedef enum {
- Lclosed=0,
- Lopened, /* opened but no call out */
- Lconnected, /* opened and a call set up on htis line */
- Lrclose, /* remote end has closed down */
- Llclose, /* local end has closed down */
- Ldialing, /* dialing a new call */
- Llistening, /* this line listening for calls */
- Lackwait, /* incoming call waiting for ack/nak */
- Laccepting, /* waiting for user to accept or reject the call */
-} Lstate;
-char *dkstate[] =
-{
- [Lclosed] "Closed",
- [Lopened] "Opened",
- [Lconnected] "Established",
- [Lrclose] "Rclose",
- [Llclose] "Lclose",
- [Ldialing] "Dialing",
- [Llistening] "Listen",
- [Lackwait] "Ackwait",
- [Laccepting] "Accepting",
-};
-
-/*
- * map datakit error to errno
- */
-enum {
- DKok,
- DKbusy,
- DKnetotl,
- DKdestotl,
- DKbadnet,
- DKnetbusy,
- DKinuse,
- DKreject,
-};
-char* dkerr[]={
- [DKok] "",
- [DKbusy] "devdk: destination busy",
- [DKnetotl] "devdk: network not answering",
- [DKdestotl] "devdk: destination not answering",
- [DKbadnet] "devdk: unknown address",
- [DKnetbusy] "devdk: network busy",
- [DKinuse] "devdk: service in use",
- [DKreject] "devdk: connection refused",
-};
-#define DKERRS sizeof(dkerr)/sizeof(char*)
-
-/*
- * imported
- */
-extern Qinfo urpinfo;
-
-/*
- * predeclared
- */
-Chan* dkattach(char*);
-static void dkmuxconfig(Queue*, Block*);
-static Chan* dkopenline(Dk*, int);
-static Chan* dkopencsc(Dk*);
-static int dkmesg(Chan*, int, int, int, int);
-static void dkcsckproc(void*);
-static void dkanswer(Chan*, int, int);
-static void dkwindow(Chan*);
-static void dkcall(int, Chan*, char*, char*, char*);
-static void dktimer(void*);
-static void dkchgmesg(Chan*, Dk*, Dkmsg*, int);
-static void dkreplymesg(Dk*, Dkmsg*, int);
-Chan* dkopen(Chan*, int);
-static void dkhangup(Line*);
-
-/*
- * for standard network interface (net.c)
- */
-static int dkcloneline(Chan*);
-static int dklisten(Chan*);
-static void dkfilladdr(Chan*, char*, int);
-static void dkfillraddr(Chan*, char*, int);
-static void dkfillruser(Chan*, char*, int);
-static void dkfillstatus(Chan*, char*, int);
-
-extern Qinfo dkinfo;
-
-/*
- * the datakit multiplexor stream module definition
- */
-static Streamopen dkmuxopen;
-static Streamput dkmuxoput;
-static Streamput dkmuxiput;
-Qinfo dkmuxinfo =
-{
- dkmuxiput,
- dkmuxoput,
- dkmuxopen,
- 0,
- "dkmux"
-};
-
-/*
- * allocate a line if it doesn't exist
- */
-static Line*
-linealloc(Dk *dp, int lineno, int dolock)
-{
- Line *lp;
-
- if(dolock)
- qlock(&dp->netlock);
- if(lineno > dp->lines)
- panic("linealloc");
- lp = dp->linep[lineno];
- if(lp == 0){
- lp = smalloc(sizeof(Line));
- lp->lineno = lineno;
- netadd(&dp->net, lp, lineno);
- dp->linep[lineno] = lp;
- }
- if(dolock)
- qunlock(&dp->netlock);
- return lp;
-}
-
-/*
- * a new dkmux. hold the stream in place so it can never be closed down.
- */
-static void
-dkmuxopen(Queue *q, Stream *s)
-{
- RD(q)->ptr = 0;
- WR(q)->ptr = 0;
-
- naildownstream(s);
-}
-
-/*
- * handle configuration
- */
-static void
-dkmuxoput(Queue *q, Block *bp)
-{
- if(bp->type != M_DATA){
- if(streamparse("config", bp))
- dkmuxconfig(q, bp);
- else
- PUTNEXT(q, bp);
- return;
- }
- PUTNEXT(q, bp);
-}
-
-/*
- * gather a message and send it up the appropriate stream
- *
- * The first two bytes of each message contains the channel
- * number, low order byte first.
- *
- * Simplifying assumption: one put == one message && the channel number
- * is in the first block. If this isn't true, demultiplexing will not
- * work.
- */
-static void
-dkmuxiput(Queue *q, Block *bp)
-{
- Dk *dp;
- Line *lp;
- int line;
-
- /*
- * not configured yet
- */
- if(q->other->ptr == 0){
- freeb(bp);
- return;
- }
-
- dp = (Dk *)q->ptr;
- if(bp->type != M_DATA){
- PUTNEXT(q, bp);
- return;
- }
-
- line = bp->rptr[0] | (bp->rptr[1]<<8);
- bp->rptr += 2;
- if(line<0 || line>=dp->lines){
- DPRINT("dkmuxiput bad line %d\n", line);
- freeb(bp);
- return;
- }
-
- lp = linealloc(dp, line, 1);
- if(lp && canqlock(lp)){
- if(lp->rq)
- PUTNEXT(lp->rq, bp);
- else{
- DPRINT("dkmuxiput unopened line %d\n", line);
- freeb(bp);
- }
- qunlock(lp);
- } else {
- DPRINT("dkmuxiput unopened line %d\n", line);
- freeb(bp);
- }
-}
-
-/*
- * the datakit line stream module definition
- */
-static Streamopen dkstopen;
-static Streamclose dkstclose;
-static Streamput dkoput, dkiput;
-Qinfo dkinfo =
-{
- dkiput,
- dkoput,
- dkstopen,
- dkstclose,
- "dk"
-};
-
-/*
- * open and save a pointer to the conversation
- */
-static void
-dkstopen(Queue *q, Stream *s)
-{
- Dk *dp;
- Line *lp;
-
- dp = dk[s->dev];
- q->other->ptr = q->ptr = lp = dp->linep[s->id];
- lp->dp = dp;
- lp->rq = q;
- if(lp->state==Lclosed)
- lp->state = Lopened;
-}
-
-/*
- * close down a datakit conversation
- */
-static void
-dkstclose(Queue *q)
-{
- Dk *dp;
- Line *lp;
- Chan *c;
-
- lp = (Line *)q->ptr;
- dp = lp->dp;
-
- /*
- * if we never got going, we're done
- */
- if(lp->rq == 0){
- lp->state = Lclosed;
- return;
- }
-
- /*
- * these states don't need the datakit
- */
- switch(lp->state){
- case Lclosed:
- case Llclose:
- case Lopened:
- lp->state = Lclosed;
- goto out;
- }
-
- c = 0;
- if(waserror()){
- lp->state = Lclosed;
- if(c)
- close(c);
- goto out;
- }
- c = dkopencsc(dp);
-
- /*
- * shake hands with dk
- */
- switch(lp->state){
- case Lrclose:
- dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
- lp->state = Lclosed;
- break;
-
- case Lackwait:
- dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
- lp->state = Llclose;
- break;
-
- case Llistening:
- dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
- lp->state = Llclose;
- break;
-
- case Lconnected:
- dkmesg(c, T_CHG, D_CLOSE, lp->lineno, 0);
- lp->state = Llclose;
- break;
- }
- poperror();
- close(c);
-
-out:
- qlock(lp);
- lp->rq = 0;
- qunlock(lp);
-
- netdisown(lp);
- lp->window = 0;
-}
-
-/*
- * this is only called by hangup
- */
-static void
-dkiput(Queue *q, Block *bp)
-{
- PUTNEXT(q, bp);
-}
-
-/*
- * we assume that each put is a message.
- *
- * add a 2 byte channel number to the start of each message,
- * low order byte first. Make sure the first block contains
- * both the 2 channel bytes and the control byte.
- */
-static void
-dkoput(Queue *q, Block *bp)
-{
- Line *lp;
- Dk *dp;
- int line;
-
- if(bp->type != M_DATA){
- freeb(bp);
- error(Ebadarg);
- }
-
- lp = (Line *)q->ptr;
- dp = lp->dp;
- line = lp->lineno;
-
- bp = padb(bp, 2);
- bp->rptr[0] = line;
- bp->rptr[1] = line>>8;
-
- FLOWCTL(dp->wq, bp);
-}
-
-/*
- * configure a datakit multiplexor. this takes 5 arguments separated
- * by spaces:
- * the line number of the common signalling channel (must be > 0)
- * the number of lines in the device (optional)
- * the word `restart' or `norestart' (optional/default==restart)
- * the name of the dk (default==dk)
- * the urp window size (default==2048)
- *
- * we can configure only once
- */
-static int
-haveca(void *arg)
-{
- Dk *dp;
-
- dp = arg;
- return dp->closeall;
-}
-static void
-dkmuxconfig(Queue *q, Block *bp)
-{
- Dk *dp;
- char *fields[5];
- int n;
- char buf[64];
- char name[NAMELEN];
- int lines;
- int ncsc;
- int restart;
- int window;
-
- if(WR(q)->ptr){
- freeb(bp);
- error(Egreg);
- }
-
- /*
- * defaults
- */
- ncsc = 1;
- restart = 1;
- lines = 16;
- window = 2048;
- strcpy(name, "dk");
-
- /*
- * parse
- */
- n = getfields((char *)bp->rptr, fields, 5, ' ');
- switch(n){
- case 5:
- window = strtoul(fields[4], 0, 0);
- if(window < 16)
- window = 1<<(window+4);
- case 4:
- strncpy(name, fields[3], sizeof(name));
- name[sizeof(name)-1] = 0;
- case 3:
- if(strcmp(fields[2], "restart")!=0)
- restart = 0;
- case 2:
- lines = strtoul(fields[1], 0, 0);
- case 1:
- ncsc = strtoul(fields[0], 0, 0);
- break;
- default:
- freeb(bp);
- error(Ebadarg);
- }
- freeb(bp);
- if(ncsc <= 0 || lines <= ncsc)
- error(Ebadarg);
-
- /*
- * find a free dk slot. it name is already configured
- * or no slots are left, error.
- */
- lock(&dklock);
- if(waserror()){
- unlock(&dklock);
- nexterror();
- }
- for(n = 0; n < Maxdk; n++){
- dp = dk[n];
- if(dp == 0)
- break;
- if(strcmp(name, dp->name) == 0)
- error(Einuse);
- }
- if(n == Maxdk)
- error(Enoifc);
-
- /*
- * allocate both a dk structure and an array of pointers to line
- * structures
- */
- dp = smalloc(sizeof(Dk));
- dp->ncsc = ncsc;
- dp->lines = lines;
- dp->linep = smalloc(sizeof(Line*) * dp->lines);
- strcpy(dp->name, name);
- dp->net.name = dp->name;
- dp->net.nconv = dp->lines;
- dp->net.devp = &dkinfo;
- dp->net.protop = &urpinfo;
- dp->net.listen = dklisten;
- dp->net.clone = dkcloneline;
- dp->net.ninfo = 5;
- dp->net.info[0].name = "local";
- dp->net.info[0].fill = dkfilladdr;
- dp->net.info[1].name = "remote";
- dp->net.info[1].fill = dkfillraddr;
- dp->net.info[2].name = "ruser";
- dp->net.info[2].fill = dkfillruser;
- dp->net.info[3].name = "urpstats";
- dp->net.info[3].fill = urpfillstats;
- dp->net.info[4].name = "status";
- dp->net.info[4].fill = dkfillstatus;
- dp->restart = restart;
- dp->urpwindow = window;
- dp->wq = WR(q);
- q->ptr = q->other->ptr = dp;
- dk[n] = dp;
- unlock(&dklock);
- poperror();
-
- /*
- * open csc here so that boot, dktimer, and dkcsckproc aren't
- * all fighting for it at once.
- */
- dkopencsc(dp);
-
- /*
- * start a process to listen to csc messages
- */
- sprint(buf, "csc.%s.%d", dp->name, dp->ncsc);
- kproc(buf, dkcsckproc, dp);
-
- /*
- * tell datakit we've rebooted. It should close all channels.
- * do this here to get it done before trying to open a channel.
- */
- if(dp->restart) {
- DPRINT("dktimer: restart %s\n", dp->name);
- dp->closeall = 0;
- dkmesg(dp->csc, T_ALIVE, D_RESTART, 0, 0);
- }
- tsleep(&dp->closeallr, haveca, dp, 15000);
-
- /*
- * start a keepalive process
- */
- sprint(buf, "timer.%s.%d", dp->name, dp->ncsc);
- kproc(buf, dktimer, dp);
-}
-
-void
-dkreset(void)
-{
- newqinfo(&dkmuxinfo);
-}
-
-void
-dkinit(void)
-{
-}
-
-Chan*
-dkattach(char *spec)
-{
- Chan *c;
- Dk *dp;
- int dev;
-
- /*
- * find a multiplexor with the same name (default dk)
- */
- if(*spec == 0)
- spec = "dk";
- for(dev = 0; dev < Maxdk; dev++){
- dp = dk[dev];
- if(dp && strcmp(dp->name, spec) == 0)
- break;
- }
- if(dev == Maxdk)
- error(Enoifc);
-
- /*
- * return the new channel
- */
- c = devattach('k', spec);
- c->dev = dev;
- return c;
-}
-
-Chan*
-dkclone(Chan *c, Chan *nc)
-{
- return devclone(c, nc);
-}
-
-int
-dkwalk(Chan *c, char *name)
-{
- return netwalk(c, name, &dk[c->dev]->net);
-}
-
-void
-dkstat(Chan *c, char *dp)
-{
- netstat(c, dp, &dk[c->dev]->net);
-}
-
-Chan*
-dkopen(Chan *c, int omode)
-{
- Dk *dp;
-
- dp = dk[c->dev];
- linealloc(dp, STREAMID(c->qid.path), 1);
- return netopen(c, omode, &dp->net);
-}
-
-void
-dkcreate(Chan *c, char *name, int omode, ulong perm)
-{
- USED(c);
- USED(name);
- USED(omode);
- USED(perm);
- error(Eperm);
-}
-
-void
-dkclose(Chan *c)
-{
- if(c->stream)
- streamclose(c);
-}
-
-long
-dkread(Chan *c, void *a, long n, ulong offset)
-{
- return netread(c, a, n, offset, &dk[c->dev]->net);
-}
-
-long
-dkwrite(Chan *c, void *a, long n, ulong offset)
-{
- int t;
- char buf[256];
- char *field[5];
- int m;
-
- USED(offset);
- t = STREAMTYPE(c->qid.path);
-
- /*
- * get data dispatched as quickly as possible
- */
- if(t == Sdataqid)
- return streamwrite(c, a, n, 0);
-
- /*
- * easier to do here than in dkoput
- */
- if(t == Sctlqid){
- if(n > sizeof buf - 1)
- n = sizeof buf - 1;
- strncpy(buf, a, n);
- buf[n] = '\0';
- m = getfields(buf, field, 5, ' ');
- if(strcmp(field[0], "connect")==0){
- if(m < 2)
- error(Ebadarg);
- dkcall(Dial, c, field[1], 0, 0);
- } else if(strcmp(field[0], "announce")==0){
- if(m < 2)
- error(Ebadarg);
- dkcall(Announce, c, field[1], 0, 0);
- } else if(strcmp(field[0], "redial")==0){
- if(m < 4)
- error(Ebadarg);
- dkcall(Redial, c, field[1], field[2], field[3]);
- } else if(strcmp(field[0], "accept")==0){
- if(m < 2)
- error(Ebadarg);
- dkanswer(c, strtoul(field[1], 0, 0), 0);
- } else if(strcmp(field[0], "reject")==0){
- if(m < 3)
- error(Ebadarg);
- for(m = 0; m < DKERRS-1; m++)
- if(strcmp(field[2], dkerr[m]) == 0)
- break;
- dkanswer(c, strtoul(field[1], 0, 0), m);
- } else
- return streamwrite(c, a, n, 0);
- return n;
- }
-
- error(Eperm);
- return -1; /* never reached */
-}
-
-void
-dkremove(Chan *c)
-{
- USED(c);
- error(Eperm);
-}
-
-void
-dkwstat(Chan *c, char *dp)
-{
- netwstat(c, dp, &dk[c->dev]->net);
-}
-
-/*
- * return the number of an unused line (reserve it)
- */
-static int
-dkcloneline(Chan *c)
-{
- Line *lp;
- Dk *dp;
- int line;
-
- dp = dk[c->dev];
- /*
- * get an unused device and open its control file
- */
- qlock(&dp->netlock);
- for(line = dp->ncsc+1; line < dp->lines; line++){
- lp = dp->linep[line];
- if(lp == 0 || lp->state == Lclosed){
- lp = linealloc(dp, line, 0);
- lp->state = Lopened;
-
- /* current user becomes owner */
- netown(lp, up->user, 0);
-
- qunlock(&dp->netlock);
- return lp->lineno;
- }
- }
- qunlock(&dp->netlock);
- error(Enodev);
- return -1; /* never reached */
-}
-
-static Chan*
-dkopenline(Dk *dp, int line)
-{
- Chan *c;
-
- c = 0;
- if(waserror()){
- if(c)
- close(c);
- nexterror();
- }
- c = dkattach(dp->name);
- c->qid.path = STREAMQID(line, Sdataqid);
- dkopen(c, ORDWR);
- poperror();
-
- return c;
-}
-
-/*
- * open the common signalling channel (dp->csc's reference count never goes below 1)
- */
-static Chan*
-dkopencsc(Dk *dp)
-{
- qlock(&dp->csclock);
- if(dp->csc == 0)
- dp->csc = dkopenline(dp, dp->ncsc);
- incref(dp->csc);
- qunlock(&dp->csclock);
- return dp->csc;
-}
-
-/*
- * return the contents of the info files
- */
-void
-dkfilladdr(Chan *c, char *buf, int len)
-{
- if(len < sizeof(dk[0]->linep[0]->addr)+2)
- error(Ebadarg);
- sprint(buf, "%s\n", dk[c->dev]->linep[STREAMID(c->qid.path)]->addr);
-}
-void
-dkfillraddr(Chan *c, char *buf, int len)
-{
- if(len < sizeof(dk[0]->linep[0]->raddr)+2)
- error(Ebadarg);
- sprint(buf, "%s\n", dk[c->dev]->linep[STREAMID(c->qid.path)]->raddr);
-}
-void
-dkfillruser(Chan *c, char *buf, int len)
-{
- if(len < sizeof(dk[0]->linep[0]->ruser)+2)
- error(Ebadarg);
- sprint(buf, "%s\n", dk[c->dev]->linep[STREAMID(c->qid.path)]->ruser);
-}
-void
-dkfillstatus(Chan *c, char *buf, int len)
-{
- Dk *dp;
- Line *lp;
- int line;
- char lbuf[65];
-
- line = STREAMID(c->qid.path);
- dp = dk[c->dev];
- lp = linealloc(dp, line, 1);
- sprint(lbuf, "%s/%d %d %s window %d\n", dp->name, line,
- lp->state != Lclosed ? 1 : 0, dkstate[lp->state], lp->window);
- strncpy(buf, lbuf, len);
-}
-
-/*
- * send a message to the datakit on the common signaling line
- */
-static int
-dkmesg(Chan *c, int type, int srv, int p0, int p1)
-{
- Dkmsg d;
-
- if(waserror()){
- print("dkmesg: error\n");
- return -1;
- }
- d.type = type;
- d.srv = srv;
- d.param0l = p0;
- d.param0h = p0>>8;
- d.param1l = p1;
- d.param1h = p1>>8;
- d.param2l = 0;
- d.param2h = 0;
- d.param3l = 0;
- d.param3h = 0;
- d.param4l = 0;
- d.param4h = 0;
- streamwrite(c, (char *)&d, sizeof(Dkmsg), 1);
- poperror();
- return 0;
-}
-
-/*
- * call out on a datakit
- */
-static int
-calldone(void *a)
-{
- Line *lp;
-
- lp = (Line *)a;
- return lp->state != Ldialing;
-}
-static void
-dkcall(int type, Chan *c, char *addr, char *nuser, char *machine)
-{
- char dialstr[66];
- int line, win;
- char dialtone;
- int t_val, d_val;
- Dk *dp;
- Line *lp;
- Chan *dc;
- Chan *csc;
- char *bang, *dot;
-
- line = STREAMID(c->qid.path);
- dp = dk[c->dev];
- lp = linealloc(dp, line, 1);
-
- /*
- * only dial on virgin lines
- */
- if(lp->state != Lopened)
- error(Ebadarg);
-
- DPRINT("dkcall(line=%d, type=%d, dest=%s)\n", line, type, addr);
-
- /*
- * build dial string
- * - guard against new lines
- * - change ! into . to delimit service
- */
- if(strchr(addr, '\n'))
- error(Ebadarg);
- if(strlen(addr)+strlen(up->user)+2 >= sizeof(dialstr))
- error(Ebadarg);
- strcpy(dialstr, addr);
- bang = strchr(dialstr, '!');
- if(bang){
- dot = strchr(dialstr, '.');
- if(dot==0 || dot > bang)
- *bang = '.';
- }
- switch(type){
- case Dial:
- t_val = T_SRV;
- d_val = D_DIAL;
- strcat(dialstr, "\n");
- strcat(dialstr, up->user);
- strcat(dialstr, "\n");
- break;
- case Announce:
- t_val = T_SRV;
- d_val = D_SERV;
- break;
- case Redial:
- t_val = T_CHG;
- d_val = D_REDIAL;
- strcat(dialstr, "\n");
- strcat(dialstr, nuser);
- strcat(dialstr, "\n");
- strcat(dialstr, machine);
- strcat(dialstr, "\n");
- break;
- default:
- t_val = 0;
- d_val = 0;
- panic("bad dial type");
- }
-
- /*
- * open the data file
- */
- dc = dkopenline(dp, line);
- if(waserror()){
- close(dc);
- nexterror();
- }
- lp->calltolive = 4;
- lp->state = Ldialing;
-
- /*
- * tell the controller we want to make a call
- */
- DPRINT("dialout\n");
- csc = dkopencsc(dp);
- if(waserror()){
- close(csc);
- nexterror();
- }
- for(win = 0; ; win++)
- if(W_VALUE(win) >= dp->urpwindow || win == 15)
- break;
- dkmesg(csc, t_val, d_val, line, W_WINDOW(win, win, 2));
- poperror();
- close(csc);
-
- /*
- * if redial, wait for a dial tone (otherwise we might send
- * the dialstr to the previous other end and not the controller)
- */
- if(type==Redial){
- if(streamread(dc, &dialtone, 1L) != 1L){
- lp->state = Lconnected;
- error(Ebadarg);
- }
- }
-
- /*
- * make the call
- */
- DPRINT("dialstr %s\n", dialstr);
- streamwrite(dc, dialstr, (long)strlen(dialstr), 1);
- close(dc);
- poperror();
-
- /*
- * redial's never get a reply, assume it worked
- */
- if(type == Redial) {
- lp->state = Lconnected;
- return;
- }
-
- /*
- * wait for a reply
- */
- DPRINT("reply wait\n");
- sleep(&lp->r, calldone, lp);
-
- /*
- * if there was an error, translate it to a plan 9
- * errno and report it to the user.
- */
- DPRINT("got reply %d\n", lp->state);
- if(lp->state != Lconnected) {
- if(lp->err >= DKERRS)
- error(dkerr[0]);
- else
- error(dkerr[lp->err]);
- }
-
- /*
- * change state if serving
- */
- if(type == D_SERV){
- lp->state = Llistening;
- }
- DPRINT("connected!\n");
-
- /*
- * decode the window size
- */
- if (W_VALID(lp->window)){
- /*
- * a 1127 window negotiation
- */
- lp->window = W_VALUE(W_DEST(lp->window));
- } else if(lp->window>2 && lp->window<31){
- /*
- * a generic window negotiation
- */
- lp->window = 1<<lp->window;
- } else
- lp->window = 0;
-
- /*
- * tag the connection
- */
- strncpy(lp->addr, addr, sizeof(lp->addr)-1);
- strncpy(lp->raddr, addr, sizeof(lp->raddr)-1);
-
- /*
- * reset the protocol
- */
- dkwindow(c);
-}
-
-/*
- * listen for a call, reflavor the
- */
-static int
-dklisten(Chan *c)
-{
- char dialstr[512];
- char *line[12];
- char *field[8];
- Line *lp;
- Dk *dp;
- int n, lineno, ts, window;
- int from;
- Chan *dc;
- static int dts;
- char *cp;
-
- dp = dk[c->dev];
- from = STREAMID(c->qid.path);
-
- /*
- * open the data file
- */
- dc = dkopenline(dp, STREAMID(c->qid.path));
- if(waserror()){
- close(dc);
- nexterror();
- }
-
- /*
- * wait for a call in
- */
- for(;;){
- /*
- * read the dialstring and null terminate it
- */
- n = streamread(dc, dialstr, sizeof(dialstr)-1);
- DPRINT("returns %d\n", n);
- if(n <= 0)
- error(Eio);
- dialstr[n] = 0;
- DPRINT("dialstr = %s\n", dialstr);
-
- /*
- * break the dial string into lines
- */
- n = getfields(dialstr, line, 12, '\n');
- if (n < 2) {
- DPRINT("bad dialstr from dk (1 line)\n");
- error(Eio);
- }
-
- /*
- * line 0 is `line.tstamp.traffic[.urpparms.window]'
- */
- window = 0;
- switch(getfields(line[0], field, 5, '.')){
- case 5:
- /*
- * generic way of passing window
- */
- window = strtoul(field[4], 0, 0);
- if(window > 0 && window <31)
- window = 1<<window;
- else
- window = 0;
- /*
- * intentional fall through
- */
- case 3:
- /*
- * 1127 way of passing window
- */
- if(window == 0){
- window = strtoul(field[2], 0, 0);
- if(W_VALID(window))
- window = W_VALUE(W_ORIG(window));
- else
- window = 0;
- }
- break;
- default:
- print("bad message from dk(bad first line)\n");
- continue;
- }
- lineno = strtoul(field[0], 0, 0);
- if(lineno >= dp->lines){
- print("dklisten: illegal line %d\n", lineno);
- continue;
- }
- lp = linealloc(dp, lineno, 1);
- ts = strtoul(field[1], 0, 0);
-
- /*
- * this could be a duplicate request
- */
- if(ts == lp->timestamp){
- if((dts++ % 1000) == 0)
- print("dklisten: repeat timestamp %d\n", lineno);
- if(lp->state != Lconnected)
- dkanswer(c, lineno, DKbusy);
- continue;
- }
-
- /*
- * take care of glare (datakit picked an inuse channel
- * for the call to come in on).
- */
- if(!canqlock(lp)){
- DPRINT("DKbusy1\n");
- dkanswer(c, lineno, DKbusy);
- continue;
- } else {
- if(lp->state != Lclosed){
- qunlock(lp);
- DPRINT("DKbusy2 %ux\n", lp->state);
- dkanswer(c, lineno, DKbusy);
- continue;
- }
- }
- lp->window = window;
-
- /*
- * Line 1 is `my-dk-name.service[.more-things]'.
- * Special characters are escaped by '\'s. Convert to
- * a plan 9 address, i.e. system!service.
- */
- strncpy(lp->addr, line[1], sizeof(lp->addr)-1);
- if(cp = strchr(lp->addr, '.')){
- *cp = '!';
- if(cp = strchr(cp, '.'))
- *cp = 0;
- }
-
- /*
- * the rest is variable length
- */
- switch(n) {
- case 2:
- /* no more lines */
- lp->ruser[0] = 0;
- lp->raddr[0] = 0;
- break;
- case 3:
- /* line 2 is `source.user.param1.param2' */
- getfields(line[2], field, 3, '.');
- strncpy(lp->raddr, field[0], sizeof(lp->raddr)-1);
- strncpy(lp->ruser, field[1], sizeof(lp->ruser)-1);
- break;
- case 4:
- /* line 2 is `user.param1.param2' */
- getfields(line[2], field, 2, '.');
- strncpy(lp->ruser, field[0], sizeof(lp->ruser)-1);
-
- /* line 3 is `source.node.mod.line' */
- strncpy(lp->raddr, line[3], sizeof(lp->raddr)-1);
- break;
- default:
- print("bad message from dk(>4 line)\n");
- qunlock(lp);
- error(Ebadarg);
- }
-
- DPRINT("src(%s)user(%s)dest(%s)w(%d)\n", lp->raddr, lp->ruser,
- lp->addr, W_TRAF(lp->window));
-
- lp->timestamp = ts;
- lp->state = Lconnected;
-
- /* listener becomes owner */
- netown(lp, dp->linep[from]->owner, 0);
-
- qunlock(lp);
- close(dc);
- poperror();
- DPRINT("dklisten returns %d\n", lineno);
- return lineno;
- }
- panic("dklisten terminates strangely\n");
- return -1; /* never reached */
-}
-
-/*
- * answer a call
- */
-static void
-dkanswer(Chan *c, int line, int code)
-{
- char reply[64];
- Chan *dc;
- Line *lp;
- Dk *dp;
-
- dp = dk[c->dev];
- lp = linealloc(dp, line, 1);
-
- /*
- * open the data file (c is a control file)
- */
- dc = dkattach(dp->name);
- if(waserror()){
- close(dc);
- nexterror();
- }
- dc->qid.path = STREAMQID(STREAMID(c->qid.path), Sdataqid);
- dkopen(dc, ORDWR);
-
- /*
- * send the reply
- */
- sprint(reply, "%ud.%ud.%ud", line, lp->timestamp, code);
- DPRINT("dkanswer %s\n", reply);
- streamwrite(dc, reply, strlen(reply), 1);
- close(dc);
- poperror();
-
- /*
- * set window size
- */
- if(code == 0){
- if(waserror()){
- close(dc);
- nexterror();
- }
- sprint(reply, "init %d %d", lp->window, Streamhi);
- dc = dkopenline(dp, line);
- dc->qid.path = STREAMQID(line, Sctlqid);
- streamwrite(dc, reply, strlen(reply), 1);
- close(dc);
- poperror();
- }
-}
-
-/*
- * set the window size and reset the protocol
- */
-static void
-dkwindow(Chan *c)
-{
- char buf[64];
- Line *lp;
-
- lp = linealloc(dk[c->dev], STREAMID(c->qid.path), 1);
- if(lp->window == 0)
- lp->window = 64;
- sprint(buf, "init %d %d", lp->window, Streamhi);
- streamwrite(c, buf, strlen(buf), 1);
-}
-
-/*
- * hangup a datakit connection
- */
-static void
-dkhangup(Line *lp)
-{
- Block *bp;
-
- qlock(lp);
- if(lp->rq){
- bp = allocb(0);
- bp->type = M_HANGUP;
- PUTNEXT(lp->rq, bp);
- }
- qunlock(lp);
-}
-
-/*
- * A process which listens to all input on a csc line
- */
-static void
-dkcsckproc(void *a)
-{
- long n;
- Dk *dp;
- Dkmsg d;
- int line;
-
- dp = a;
-
- if(waserror()){
- close(dp->csc);
- return;
- }
- DPRINT("dkcsckproc: %d\n", dp->ncsc);
-
- /*
- * loop forever listening
- */
- for(;;){
- n = streamread(dp->csc, (char *)&d, (long)sizeof(d));
- if(n != sizeof(d)){
- if(n == 0)
- error(Ehungup);
- print("strange csc message %d\n", n);
- continue;
- }
- line = (d.param0h<<8) + d.param0l;
- DPRINT("t(%d)s(%d)l(%d)\n", d.type, d.srv, line);
- switch (d.type) {
-
- case T_CHG: /* controller wants to close a line */
- dkchgmesg(dp->csc, dp, &d, line);
- break;
-
- case T_REPLY: /* reply to a dial request */
- dkreplymesg(dp, &d, line);
- break;
-
- case T_SRV: /* ignore it, it's useless */
-/* print("dksrvmesg(%d)\n", line); /**/
- break;
-
- case T_RESTART: /* datakit reboot */
- if(line >=0 && line<dp->lines)
- dp->lines = line+1;
- break;
-
- default:
- print("unrecognized csc message %o.%o(%o)\n",
- d.type, d.srv, line);
- break;
- }
- }
-}
-
-/*
- * datakit requests or confirms closing a line
- */
-static void
-dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
-{
- Line *lp;
-
- switch (dialp->srv) {
-
- case D_CLOSE: /* remote shutdown */
- if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0) {
- /* tell controller this line is not in use */
- dkmesg(c, T_CHG, D_CLOSE, line, 0);
- return;
- }
- switch (lp->state) {
-
- case Ldialing:
- /* simulate a failed connection */
- dkreplymesg(dp, (Dkmsg *)0, line);
- lp->state = Lrclose;
- break;
-
- case Lrclose:
- case Lconnected:
- case Llistening:
- case Lackwait:
- dkhangup(lp);
- lp->state = Lrclose;
- break;
-
- case Lopened:
- dkmesg(c, T_CHG, D_CLOSE, line, 0);
- break;
-
- case Llclose:
- case Lclosed:
- dkhangup(lp);
- dkmesg(c, T_CHG, D_CLOSE, line, 0);
- lp->state = Lclosed;
- break;
- }
- break;
-
- case D_ISCLOSED: /* acknowledging a local shutdown */
- if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0)
- return;
- switch (lp->state) {
- case Llclose:
- case Lclosed:
- lp->state = Lclosed;
- break;
-
- case Lrclose:
- case Lconnected:
- case Llistening:
- case Lackwait:
- break;
- }
- break;
-
- case D_CLOSEALL:
- /*
- * datakit wants us to close all lines
- */
- for(line = dp->ncsc+1; line < dp->lines; line++){
- lp = dp->linep[line];
- if(lp == 0)
- continue;
- switch (lp->state) {
-
- case Ldialing:
- /* simulate a failed connection */
- dkreplymesg(dp, (Dkmsg *)0, line);
- lp->state = Lrclose;
- break;
-
- case Lrclose:
- case Lconnected:
- case Llistening:
- case Lackwait:
- lp->state = Lrclose;
- dkhangup(lp);
- break;
-
- case Lopened:
- break;
-
- case Llclose:
- case Lclosed:
- lp->state = Lclosed;
- break;
- }
- }
- dp->closeall = 1;
- wakeup(&dp->closeallr);
- break;
-
- default:
- print("unrecognized T_CHG\n");
- }
-}
-
-/*
- * datakit replies to a dialout. capture reply code and traffic parameters
- */
-static void
-dkreplymesg(Dk *dp, Dkmsg *dialp, int line)
-{
- Line *lp;
-
- DPRINT("dkreplymesg(%d)\n", line);
-
- if(line < 0 || line >= dp->lines || (lp = dp->linep[line]) == 0)
- return;
-
- if(lp->state != Ldialing)
- return;
-
- if(dialp){
- /*
- * a reply from the dk
- */
- lp->state = (dialp->srv==D_OPEN) ? Lconnected : Lrclose;
- lp->err = (dialp->param1h<<8) + dialp->param1l;
- lp->window = lp->err;
- DPRINT("dkreplymesg: %d\n", lp->state);
- } else {
- /*
- * a local abort
- */
- lp->state = Lrclose;
- lp->err = 0;
- }
-
- if(lp->state==Lrclose){
- dkhangup(lp);
- }
- wakeup(&lp->r);
-}
-
-/*
- * send a I'm alive message every 7.5 seconds and remind the dk of
- * any closed channels it hasn't acknowledged.
- */
-static void
-dktimer(void *a)
-{
- int i;
- Dk *dp;
- Line *lp;
- Chan *c;
-
- dp = (Dk *)a;
- c = dkopencsc(dp);
-
- while(waserror());
-
- for(;;){
- /*
- * send keep alive
- */
- DPRINT("keep alive\n");
- dkmesg(c, T_ALIVE, D_CONTINUE, 0, 0);
-
- /*
- * remind controller of dead lines and
- * timeout calls that take to long
- */
- for (i=dp->ncsc+1; i<dp->lines; i++){
- lp = dp->linep[i];
- if(lp == 0)
- continue;
- switch(lp->state){
- case Llclose:
- dkmesg(c, T_CHG, D_CLOSE, i, 0);
- break;
-
- case Ldialing:
- if(lp->calltolive==0 || --lp->calltolive!=0)
- break;
- dkreplymesg(dp, (Dkmsg *)0, i);
- break;
- }
- }
- tsleep(&dp->timer, return0, 0, 7500);
- }
-}
D port/devip.c => port/devip.c +0 -1206
@@ 1,1206 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "arp.h"
-#include "ipdat.h"
-
-#include "devtab.h"
-
-enum
-{
- Nrprotocol = 3, /* Number of protocols supported by this driver */
- Nipsubdir = 4, /* Number of subdirectory entries per connection */
- Nfrag = 32, /* Ip reassembly queue entries */
- Nifc = 4, /* max interfaces */
-};
-
-int udpsum = 1;
-Queue *Ipoutput; /* Control message stream for tcp/il */
-Ipifc *ipifc[Nrprotocol+1];
-QLock ipalloc; /* Protocol port allocation lock */
-Ipconv **tcpbase;
-
-Streamput udpstiput, udpstoput, tcpstiput, tcpstoput;
-Streamput iliput, iloput, bsdiput, bsdoput;
-Streamopen udpstopen, tcpstopen, ilopen, bsdopen;
-Streamclose udpstclose, tcpstclose, ilclose, bsdclose;
-
-Qinfo tcpinfo = { tcpstiput, tcpstoput, tcpstopen, tcpstclose, "tcp", 0, 1 };
-Qinfo udpinfo = { udpstiput, udpstoput, udpstopen, udpstclose, "udp" };
-Qinfo ilinfo = { iliput, iloput, ilopen, ilclose, "il" };
-Qinfo bsdinfo = { bsdiput, bsdoput, bsdopen, bsdclose, "bsd", 0, 1 };
-
-Qinfo *protocols[] = { &tcpinfo, &udpinfo, &ilinfo, 0 };
-
-void
-ipinitifc(Ipifc *ifc, Qinfo *stproto)
-{
- ifc->conv = xalloc(Nipconv * sizeof(Ipconv*));
- ifc->protop = stproto;
- ifc->nconv = Nipconv;
- ifc->devp = &ipinfo;
- if(stproto != &udpinfo)
- 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;
-}
-
-void
-ipreset(void)
-{
- int i;
-
- for(i = 0; protocols[i]; i++) {
- ipifc[i] = xalloc(sizeof(Ipifc));
- ipinitifc(ipifc[i], protocols[i]);
- newqinfo(protocols[i]);
- }
-
- initfrag(Nfrag);
-}
-
-void
-ipinit(void)
-{
-}
-
-Chan *
-ipattach(char *spec)
-{
- int i;
- Chan *c;
-
- /* fail if ip is not yet configured */
- if(Ipoutput == 0)
- error(Enoproto);
-
- for(i = 0; protocols[i]; i++) {
- if(strcmp(spec, protocols[i]->name) == 0) {
- c = devattach('I', spec);
- c->dev = i;
-
- return (c);
- }
- }
-
- error(Enoproto);
- return 0; /* not reached */
-}
-
-Chan *
-ipclone(Chan *c, Chan *nc)
-{
- return devclone(c, nc);
-}
-
-int
-ipwalk(Chan *c, char *name)
-{
- return netwalk(c, name, ipifc[c->dev]);
-}
-
-void
-ipstat(Chan *c, char *db)
-{
- netstat(c, db, ipifc[c->dev]);
-}
-
-Chan *
-ipopen(Chan *c, int omode)
-{
- return netopen(c, omode, ipifc[c->dev]);
-}
-
-int
-ipclonecon(Chan *c)
-{
- Ipconv *new;
-
- new = ipincoming(ipifc[c->dev], 0);
- if(new == 0)
- error(Enodev);
- return new->id;
-}
-
-/*
- * create a new conversation structure if none exists for this conversation slot
- */
-Ipconv*
-ipcreateconv(Ipifc *ifc, int id)
-{
- Ipconv **p;
- Ipconv *new;
-
- 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;
- Ipconv **p, **etab;
-
- /* look for an unused existing conversation */
- etab = &ifc->conv[Nipconv];
- for(p = ifc->conv; p < etab; p++) {
- new = *p;
- if(new == 0)
- break;
- if(new->ref == 0 && canqlock(new)) {
- if(new->ref || ipconbusy(new)) {
- qunlock(new);
- continue;
- }
- if(from) /* copy ownership from listening channel */
- netown(new, from->owner, 0);
- else /* current user becomes owner */
- netown(new, up->user, 0);
-
- new->ref = 1;
- qunlock(new);
- return new;
- }
- }
-
- /* 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);
- poperror();
- if(from) /* copy ownership from listening channel */
- netown(new, from->owner, 0);
- else /* current user becomes owner */
- netown(new, up->user, 0);
- new->ref = 1;
- qunlock(new);
- return new;
-}
-
-void
-ipcreate(Chan *c, char *name, int omode, ulong perm)
-{
- USED(c, name, omode, perm);
- error(Eperm);
-}
-
-void
-ipremove(Chan *c)
-{
- USED(c);
- error(Eperm);
-}
-
-void
-ipwstat(Chan *c, char *dp)
-{
- netwstat(c, dp, ipifc[c->dev]);
-}
-
-void
-ipclose(Chan *c)
-{
- if(c->stream)
- streamclose(c);
-}
-
-long
-ipread(Chan *c, void *a, long n, ulong offset)
-{
- return netread(c, a, n, offset, ipifc[c->dev]);
-}
-
-long
-ipwrite(Chan *c, char *a, long n, ulong offset)
-{
- int m, backlog, type, priv;
- char *field[5], *ctlarg[5], buf[256];
- Port port;
- Ipconv *cp;
-
- USED(offset);
- type = STREAMTYPE(c->qid.path);
- if (type == Sdataqid)
- return streamwrite(c, a, n, 0);
-
- if (type != Sctlqid)
- error(Eperm);
-
- cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path));
-
- m = n;
- if(m > sizeof(buf)-1)
- m = sizeof(buf)-1;
- strncpy(buf, a, m);
- buf[m] = '\0';
-
- m = getfields(buf, field, 5, ' ');
- if(m < 1)
- error(Ebadarg);
-
- if(strcmp(field[0], "connect") == 0) {
- if(ipconbusy(cp))
- error(Enetbusy);
-
- if(m != 2)
- error(Ebadarg);
-
- switch(getfields(field[1], ctlarg, 5, '!')) {
- default:
- error(Eneedservice);
- case 2:
- priv = 0;
- break;
- case 3:
- if(strcmp(ctlarg[2], "r") != 0)
- error(Eperm);
- priv = 1;
- break;
- }
- cp->dst = ipparse(ctlarg[0]);
- cp->pdst = atoi(ctlarg[1]);
-
- /* If we have no local port assign one */
- if(cp->psrc == 0){
- qlock(&ipalloc);
- cp->psrc = nextport(ipifc[c->dev], priv);
- qunlock(&ipalloc);
- }
-
- if(cp->ifc->protop == &tcpinfo)
- tcpstart(cp, TCP_ACTIVE, Streamhi, 0);
- else if(cp->ifc->protop == &ilinfo)
- ilstart(cp, IL_ACTIVE, 20);
-
- /*
- * 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;
- }
- }
- else if(strcmp(field[0], "disconnect") == 0) {
- if(cp->ifc->protop != &udpinfo)
- error(Eperm);
-
- cp->dst = 0;
- cp->pdst = 0;
- }
- else if(strcmp(field[0], "announce") == 0) {
- if(ipconbusy(cp))
- error(Enetbusy);
-
- if(m != 2)
- error(Ebadarg);
-
- port = atoi(field[1]);
-
- if(port){
- qlock(&ipalloc);
- if(portused(ipifc[c->dev], port)) {
- qunlock(&ipalloc);
- error(Einuse);
- }
- cp->psrc = port;
- qunlock(&ipalloc);
- } else if(*field[1] != '*'){
- qlock(&ipalloc);
- cp->psrc = nextport(ipifc[c->dev], 0);
- qunlock(&ipalloc);
- } else
- cp->psrc = 0;
-
- if(cp->ifc->protop == &tcpinfo)
- tcpstart(cp, TCP_PASSIVE, Streamhi, 0);
- else if(cp->ifc->protop == &ilinfo)
- ilstart(cp, IL_PASSIVE, 10);
-
- if(cp->backlog == 0)
- cp->backlog = 3;
- }
- 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;
- }
- else if(strcmp(field[0], "headers") == 0) {
- cp->headers = 1; /* include addr/port in user packet */
- }
- else
- return streamwrite(c, a, n, 0);
-
- return n;
-}
-
-int
-ipconbusy(Ipconv *cp)
-{
- if(cp->ifc->protop == &tcpinfo)
- if(cp->tcpctl.state != Closed)
- return 1;
-
- if(cp->ifc->protop == &ilinfo)
- if(cp->ilctl.state != Ilclosed)
- return 1;
-
- return 0;
-}
-
-void
-udpstiput(Queue *q, Block *bp)
-{
- PUTNEXT(q, bp);
-}
-
-/*
- * udprcvmsg - called by stip to multiplex udp ports onto conversations
- */
-void
-udprcvmsg(Ipifc *ifc, Block *bp)
-{
- Ipconv *cp, **p, **etab;
- Udphdr *uh;
- Port dport, sport;
- ushort sum, len;
- Ipaddr addr;
- Block *nbp;
-
- 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);
- sport = nhgets(uh->udpsport);
-
- /* Look for a conversation structure for this port */
- 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) {
- /* 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;
-
- 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;
- }
- PUTNEXT(cp->readq, bp);
- return;
- }
- }
-
- freeb(bp);
-}
-
-void
-udpstoput(Queue *q, Block *bp)
-{
- Ipconv *cp;
- Udphdr *uh;
- int dlen, ptcllen, newlen;
- Ipaddr addr;
- Port port;
-
- if(bp->type == M_CTL) {
- PUTNEXT(q, bp);
- return;
- }
-
- cp = (Ipconv *)(q->ptr);
- if(cp->psrc == 0)
- 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);
- }
-
- /*
- * 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;
-
- /* 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;
- uh->frag[0] = 0;
- uh->frag[1] = 0;
- hnputs(uh->udpplen, ptcllen);
- hnputl(uh->udpsrc, Myip[Myself]);
- hnputs(uh->udpsport, cp->psrc);
- if(cp->headers) {
- hnputl(uh->udpdst, addr);
- hnputs(uh->udpdport, port);
- }
- else {
- hnputl(uh->udpdst, cp->dst);
- hnputs(uh->udpdport, cp->pdst);
- }
- 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);
-
- ipc->headers = 0;
- ipc->psrc = 0;
- ipc->pdst = 0;
- ipc->dst = 0;
-}
-
-void
-udpstopen(Queue *q, Stream *s)
-{
- Ipconv *ipc;
-
- ipc = ipcreateconv(ipifc[s->dev], s->id);
- initipifc(ipifc[s->dev], IP_UDPPROTO, udprcvmsg, 1500, 512, ETHER_HDR);
-
- ipc->readq = RD(q);
- RD(q)->ptr = (void *)ipc;
- WR(q)->next->ptr = (void *)ipc->ifc;
- WR(q)->ptr = (void *)ipc;
-}
-
-void
-tcpstiput(Queue *q, Block *bp)
-{
- PUTNEXT(q, bp);
-}
-
-tcproominq(void *a)
-{
- return !((Tcpctl *)a)->sndfull;
-}
-
-void
-tcpstoput(Queue *q, Block *bp)
-{
- Ipconv *s;
- Tcpctl *tcb;
- Block *f;
-
- s = (Ipconv *)(q->ptr);
- tcb = &s->tcpctl;
-
- if(bp->type == M_CTL) {
- PUTNEXT(q, bp);
- return;
- }
-
- if(s->psrc == 0)
- error(Enoport);
-
- /* Report asynchronous errors */
- if(s->err)
- error(s->err);
-
- switch(tcb->state) {
- case Listen:
- tcb->flags |= ACTIVE;
- tcpsndsyn(tcb);
- tcpsetstate(s, Syn_sent);
-
- /* No break */
- case Syn_sent:
- case Syn_received:
- case Established:
- case Close_wait:
- /*
- * Process flow control
- */
- if(tcb->sndfull){
- qlock(&tcb->sndrlock);
- if(waserror()) {
- qunlock(&tcb->sndrlock);
- nexterror();
- }
- sleep(&tcb->sndr, tcproominq, tcb);
- poperror();
- qunlock(&tcb->sndrlock);
- }
-
- /*
- * Push data
- */
- qlock(tcb);
- if(waserror()) {
- qunlock(tcb);
- nexterror();
- }
- tcb->sndcnt += blen(bp);
- if(tcb->sndcnt > Streamhi)
- tcb->sndfull = 1;
- if(tcb->sndq == 0)
- tcb->sndq = bp;
- else {
- for(f = tcb->sndq; f->next; f = f->next)
- ;
- f->next = bp;
- }
- tcprcvwin(s);
- tcpoutput(s);
- poperror();
- qunlock(tcb);
- break;
-
- default:
- freeb(bp);
- error(Ehungup);
- }
-}
-
-void
-tcpstopen(Queue *q, Stream *s)
-{
- Ipconv *ipc;
- Ipifc *ifc;
- Tcpctl *tcb;
- Block *bp;
- static int tcpkprocs;
-
- if(!Ipoutput) {
- Ipoutput = WR(q);
- s->opens++;
- s->inuse++;
- }
-
- /* Flow control and tcp timer processes */
- if(tcpkprocs == 0) {
- tcpkprocs = 1;
- kproc("tcpack", tcpackproc, 0);
- kproc("tcpflow", tcpflow, ipifc[s->dev]);
-
- }
-
- if(tcpbase == 0)
- tcpbase = ipifc[s->dev]->conv;
- ifc = ipifc[s->dev];
- initipifc(ifc, IP_TCPPROTO, tcpinput, 1500, 512, ETHER_HDR);
- ipc = ipcreateconv(ifc, s->id);
-
- ipc->readq = RD(q);
- ipc->readq->rp = &tcpflowr;
- ipc->err = 0;
-
- RD(q)->ptr = (void *)ipc;
- WR(q)->next->ptr = (void *)ipc->ifc;
- WR(q)->ptr = (void *)ipc;
-
- /* pass any waiting data upstream */
- tcb = &ipc->tcpctl;
- qlock(tcb);
- while(bp = getb(&tcb->rcvq))
- PUTNEXT(ipc->readq, bp);
- qunlock(tcb);
-}
-
-void
-ipremotefill(Chan *c, char *buf, int len)
-{
- Ipconv *cp;
-
- if(len < 32)
- error(Etoosmall);
- cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path));
- sprint(buf, "%d.%d.%d.%d!%d\n", fmtaddr(cp->dst), cp->pdst);
-}
-
-void
-iplocalfill(Chan *c, char *buf, int len)
-{
- Ipconv *cp;
-
- if(len < 32)
- error(Etoosmall);
- cp = ipcreateconv(ipifc[c->dev], STREAMID(c->qid.path));
- sprint(buf, "%d.%d.%d.%d!%d\n", fmtaddr(Myip[Myself]), cp->psrc);
-}
-
-void
-ipstatusfill(Chan *c, char *buf, int len)
-{
- Ipconv *cp;
- int connection;
-
- if(len < 64)
- error(Ebadarg);
- connection = STREAMID(c->qid.path);
- cp = ipcreateconv(ipifc[c->dev], connection);
- if(cp->ifc->protop == &tcpinfo)
- sprint(buf, "tcp/%d %d %s %s\n", connection, cp->ref,
- tcpstate[cp->tcpctl.state],
- cp->tcpctl.flags & CLONE ? "listen" : "connect");
- else if(cp->ifc->protop == &ilinfo)
- sprint(buf, "il/%d %d %s rtt %d ms %d csum\n", connection, cp->ref,
- ilstate[cp->ilctl.state], cp->ilctl.rtt,
- cp->ifc ? cp->ifc->chkerrs : 0);
- else
- sprint(buf, "%s/%d %d Datagram\n",
- cp->ifc->protop->name, connection, cp->ref);
-}
-
-int
-iphavecon(Ipconv *s)
-{
- return s->curlog;
-}
-
-int
-iplisten(Chan *c)
-{
- Ipconv *s;
- int connection;
- Ipconv **p, **etab, *new;
-
- connection = STREAMID(c->qid.path);
- s = ipcreateconv(ipifc[c->dev], connection);
-
- if(s->ifc->protop == &tcpinfo)
- if(s->tcpctl.state != Listen)
- error(Enolisten);
-
- if(s->ifc->protop == &ilinfo)
- if(s->ilctl.state != Illistening)
- error(Enolisten);
-
- for(;;) {
- qlock(&s->listenq); /* single thread for the sleep */
- if(waserror()) {
- qunlock(&s->listenq);
- nexterror();
- }
- sleep(&s->listenr, iphavecon, s);
- poperror();
- etab = &ipifc[c->dev]->conv[Nipconv];
- for(p = ipifc[c->dev]->conv; p < etab; p++) {
- new = *p;
- if(new == 0)
- break;
- if(new->newcon == s) {
- qlock(s);
- s->curlog--;
- qunlock(s);
- new->newcon = 0;
- qunlock(&s->listenq);
- return new->id;
- }
- }
- qunlock(&s->listenq);
- print("iplisten: no newcon\n");
- }
- return -1; /* not reached */
-}
-
-void
-tcpstclose(Queue *q)
-{
- Ipconv *s;
- Ipconv **etab, **p;
- Tcpctl *tcb;
-
- s = (Ipconv *)(q->ptr);
- tcb = &s->tcpctl;
-
- /* Not interested in data anymore */
- qlock(s);
- s->readq = 0;
- qunlock(s);
-
- switch(tcb->state){
- case Listen:
- /*
- * reset any incoming calls to this listener
- */
- qlock(s);
- s->backlog = 0;
- s->curlog = 0;
- etab = &tcpbase[Nipconv];
- for(p = tcpbase; p < etab && *p; p++){
- if((*p)->newcon == s) {
- (*p)->newcon = 0;
- tcpflushincoming(*p);
- }
- }
- qunlock(s);
-
- qlock(tcb);
- localclose(s, 0);
- qunlock(tcb);
- break;
-
- case Closed:
- case Syn_sent:
- qlock(tcb);
- localclose(s, 0);
- qunlock(tcb);
- break;
-
- case Syn_received:
- case Established:
- tcb->sndcnt++;
- tcb->snd.nxt++;
- tcpsetstate(s, Finwait1);
- goto output;
-
- case Close_wait:
- tcb->sndcnt++;
- tcb->snd.nxt++;
- tcpsetstate(s, Last_ack);
- output:
- qlock(tcb);
- if(waserror()) {
- qunlock(tcb);
- nexterror();
- }
- tcpoutput(s);
- poperror();
- qunlock(tcb);
- break;
- }
-}
-
-
-static short endian = 1;
-static char* aendian = (char*)&endian;
-#define LITTLE *aendian
-
-ushort
-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
-ptcl_csum(Block *bp, int offset, int len)
-{
- uchar *addr;
- ulong losum, hisum;
- 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;
-
- if(bp->next == 0)
- return ~ptcl_bsum(addr, MIN(len, blen)) & 0xffff;
-
- losum = 0;
- hisum = 0;
-
- odd = 0;
- while(len) {
- x = MIN(len, blen);
- csum = ptcl_bsum(addr, x);
- if(odd)
- hisum += csum;
- else
- losum += csum;
- odd = (odd+x) & 1;
- len -= x;
-
- 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 *
-portused(Ipifc *ifc, Port port)
-{
- Ipconv **p, **etab;
- Ipconv *cp;
-
- if(port == 0)
- return 0;
-
- etab = &ifc->conv[Nipconv];
- for(p = ifc->conv; p < etab; p++){
- cp = *p;
- if(cp == 0)
- break;
- if(cp->psrc == port)
- return cp;
- }
-
- return 0;
-}
-
-static Port lastport[2] = { PORTALLOC-1, PRIVPORTALLOC-1 };
-
-Port
-nextport(Ipifc *ifc, int priv)
-{
- Port base;
- Port max;
- Port *p;
- Port i;
-
- if(priv){
- base = PRIVPORTALLOC;
- max = UNPRIVPORTALLOC;
- p = &lastport[1];
- } else {
- base = PORTALLOC;
- max = PORTMAX;
- p = &lastport[0];
- }
-
- for(i = *p + 1; i < max; i++)
- if(!portused(ifc, i))
- return(*p = i);
- for(i = base ; i <= *p; i++)
- if(!portused(ifc, i))
- return(*p = i);
-
- return(0);
-}
-
-/* NEEDS HASHING ! */
-
-Ipconv*
-ip_conn(Ipifc *ifc, Port dst, Port src, Ipaddr dest)
-{
- Ipconv **p, *s, **etab;
-
- /* Look for a conversation structure for this port */
- etab = &ifc->conv[Nipconv];
- for(p = ifc->conv; p < etab; p++) {
- s = *p;
- if(s == 0)
- break;
- if(s->psrc == dst)
- if(s->pdst == src)
- if(s->dst == dest || dest == 0)
- return s;
- }
-
- return 0;
-}
-
-/*
- * 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)
-{
- USED(s);
- 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 */
- qlock(&q->rlock);
- 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){
- qunlock(&q->rlock);
- bsdclose(q);
- return;
- }
-
- /* look for 2 nulls to indicate stderr port and local user */
- luser = memchr(bp->rptr, 0, BLEN(bp));
- if(luser == 0){
- qunlock(&q->rlock);
- return;
- }
- luser++;
- if(memchr(luser, 0, bp->wptr - luser) == 0){
- qunlock(&q->rlock);
- return;
- }
-
- /* if luser is a lie, hangup */
- if(memcmp(luser, up->user, strlen(up->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);
- qunlock(&q->rlock);
-}
D port/deviproute.c => port/deviproute.c +0 -377
@@ 1,377 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "arp.h"
-#include "ipdat.h"
-
-#include "devtab.h"
-
-/*
- * All ip numbers and masks are stored as ulongs.
- * All interfaces to this code uses the standard byte
- * string representation.
- */
-
-typedef struct Iproute Iproute;
-typedef struct Iprtab Iprtab;
-
-enum
-{
- Nroutes= 256,
-};
-
-/*
- * routes
- */
-struct Iproute {
- ulong dst;
- ulong gate;
- ulong mask;
- Iproute *next;
- int inuse;
-};
-struct Iprtab {
- Lock;
- int n; /* number of valid routes */
- Iproute *first; /* list of valid routes */
- Iproute r[Nroutes]; /* all routes */
-};
-Iprtab iprtab;
-
-/*
- * The chosen route is the one obeys the constraint
- * r->mask & dst == r->dst
- *
- * If there are several matches, the one whose mask has the most
- * leading ones (and hence is the most specific) wins. This is
- * forced by storing the routes in decreasing number of ones order
- * and returning the first match. The default gateway has no ones
- * in the mask and is thus the last matched.
- */
-void
-iproute(uchar *dst, uchar *gate)
-{
- Iproute *r;
- ulong udst;
-
- udst = nhgetl(dst);
- if((udst&Mynetmask) == (Myip[Myself]&Mynetmask)){
- memmove(gate, dst, 4);
- return;
- }
-
- /*
- * first check routes
- */
- for(r = iprtab.first; r; r = r->next){
- if((r->mask&udst) == r->dst){
- hnputl(gate, r->gate);
- return;
- }
- }
-
- /*
- * else just return the same address
- */
- memmove(gate, dst, 4);
-}
-
-/*
- * Add a route, create a mask if the first mask is 0.
- *
- * All routes are stored sorted by the length of leading
- * ones in the mask.
- *
- * NOTE: A default route has an all zeroes mask and dst.
- */
-void
-ipaddroute(ulong dst, ulong mask, ulong gate)
-{
- Iproute *r, *e, *free;
-
- /*
- * filter out impossible requests
- */
- if((dst&mask) != dst)
- error(Enetaddr);
-
- /*
- * see if we already have a route for
- * the destination
- */
- lock(&iprtab);
- free = 0;
- for(r = iprtab.r; r < &iprtab.r[Nroutes]; r++){
- if(r->inuse == 0){
- free = r;
- continue;
- }
- if(dst==r->dst && mask==r->mask){
- r->gate = gate;
- unlock(&iprtab);
- return;
- }
- }
- if(free == 0){
- unlock(&iprtab);
- exhausted("routes");
- }
-
- /*
- * add the new route in sorted order
- */
- free->dst = dst;
- free->mask = mask;
- free->gate = gate;
- free->inuse = 1;
- for(r = e = iprtab.first; r; r = r->next){
- if(mask > r->mask)
- break;
- e = r;
- }
- free->next = r;
- if(r == iprtab.first)
- iprtab.first = free;
- else
- e->next = free;
- iprtab.n++;
- unlock(&iprtab);
-}
-
-/*
- * remove a route
- */
-void
-ipremroute(ulong dst, ulong mask)
-{
- Iproute *r, *e;
-
- lock(&iprtab);
- for(r = e = iprtab.first; r; r = r->next){
- if(dst==r->dst && mask==r->mask){
- if(r == iprtab.first)
- iprtab.first = r->next;
- else
- e->next = r->next;
- r->inuse = 0;
- iprtab.n--;
- break;
- }
- e = r;
- }
- unlock(&iprtab);
-}
-
-/*
- * remove all routes
- */
-void
-ipflushroute(void)
-{
- Iproute *r;
-
- lock(&iprtab);
- for(r = iprtab.first; r; r = r->next)
- r->inuse = 0;
- iprtab.first = 0;
- iprtab.n = 0;
- unlock(&iprtab);
-}
-
-/*
- * device interface
- */
-enum{
- Qdir,
- Qdata,
-};
-Dirtab iproutetab[]={
- "iproute", {Qdata}, 0, 0666,
-};
-#define Niproutetab (sizeof(iproutetab)/sizeof(Dirtab))
-
-void
-iproutereset(void)
-{
-}
-
-void
-iprouteinit(void)
-{
-}
-
-Chan *
-iprouteattach(char *spec)
-{
- return devattach('P', spec);
-}
-
-Chan *
-iprouteclone(Chan *c, Chan *nc)
-{
- return devclone(c, nc);
-}
-
-int
-iproutewalk(Chan *c, char *name)
-{
- return devwalk(c, name, iproutetab, (long)Niproutetab, devgen);
-}
-
-void
-iproutestat(Chan *c, char *db)
-{
- devstat(c, db, iproutetab, (long)Niproutetab, devgen);
-}
-
-Chan *
-iprouteopen(Chan *c, int omode)
-{
- if(c->qid.path == CHDIR){
- if(omode != OREAD)
- error(Eperm);
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
-}
-
-void
-iproutecreate(Chan *c, char *name, int omode, ulong perm)
-{
- USED(c, name, omode, perm);
- error(Eperm);
-}
-
-void
-iprouteremove(Chan *c)
-{
- USED(c);
- error(Eperm);
-}
-
-void
-iproutewstat(Chan *c, char *dp)
-{
- USED(c, dp);
- error(Eperm);
-}
-
-void
-iprouteclose(Chan *c)
-{
- USED(c);
-}
-
-#define IPR_ENTRYLEN 54
-#define PAD " "
-
-long
-iprouteread(Chan *c, void *a, long n, ulong offset)
-{
- char buf[IPR_ENTRYLEN*3];
- Iproute *r;
- int part, bytes, size;
- uchar dst[4], mask[4], gate[4];
-
- switch((int)(c->qid.path&~CHDIR)){
- case Qdir:
- return devdirread(c, a, n, iproutetab, Niproutetab, devgen);
- case Qdata:
- lock(&iprtab);
- part = offset/IPR_ENTRYLEN;
- for(r = iprtab.first; part && r; r = r->next)
- part--;
- bytes = offset;
- while(r && bytes < iprtab.n*IPR_ENTRYLEN && n){
- part = bytes%IPR_ENTRYLEN;
-
- hnputl(dst, r->dst);
- hnputl(mask, r->mask);
- hnputl(gate, r->gate);
- sprint(buf,"%d.%d.%d.%d & %d.%d.%d.%d -> %d.%d.%d.%d%s",
- dst[0], dst[1], dst[2], dst[3],
- mask[0], mask[1], mask[2], mask[3],
- gate[0], gate[1], gate[2], gate[3],
- PAD);
-
- buf[IPR_ENTRYLEN-1] = '\n';
-
- size = IPR_ENTRYLEN - part;
- if(size > n)
- size = n;
- memmove(a, buf+part, size);
-
- a = (void *)((int)a + size);
- n -= size;
- bytes += size;
- r = r->next;
- }
- unlock(&iprtab);
- return bytes - offset;
- break;
- default:
- n=0;
- break;
- }
- return n;
-}
-
-long
-iproutewrite(Chan *c, char *a, long n, ulong offset)
-{
- char buf[IPR_ENTRYLEN];
- char *field[4];
- Ipaddr mask, dst, gate;
- int m;
-
- USED(offset);
-
- switch((int)(c->qid.path&~CHDIR)){
- case Qdata:
- strncpy(buf, a, sizeof buf);
- m = getfields(buf, field, 4, ' ');
-
- if(strncmp(field[0], "flush", 5) == 0)
- ipflushroute();
- else if(strcmp(field[0], "add") == 0){
- switch(m){
- case 4:
- dst = ipparse(field[1]);
- mask = ipparse(field[2]);
- gate = ipparse(field[3]);
- ipaddroute(dst, mask, gate);
- break;
- case 3:
- dst = ipparse(field[1]);
- gate = ipparse(field[2]);
- ipaddroute(dst, classmask[dst>>30], gate);
- break;
- default:
- error(Ebadarg);
- }
- } else if(strcmp(field[0], "delete") == 0){
- switch(m){
- case 3:
- dst = ipparse(field[1]);
- mask = ipparse(field[2]);
- ipremroute(dst, mask);
- break;
- case 2:
- dst = ipparse(field[1]);
- ipremroute(dst, classmask[dst>>30]);
- break;
- default:
- error(Ebadarg);
- }
- }
- break;
- default:
- error(Ebadusefd);
- }
- return n;
-}
D port/ipdat.h => port/ipdat.h +0 -533
@@ 1,533 0,0 @@
-typedef struct Etherhdr Etherhdr;
-typedef struct Fragq Fragq;
-typedef struct Ilcb Ilcb;
-typedef struct Ilhdr Ilhdr;
-typedef ulong Ipaddr;
-typedef struct Ipconv Ipconv;
-typedef struct Ipfrag Ipfrag;
-typedef struct Ipifc Ipifc;
-typedef ushort Port;
-typedef struct Reseq Reseq;
-typedef struct Tcp Tcp;
-typedef struct Tcpctl Tcpctl;
-typedef struct Tcphdr Tcphdr;
-typedef struct Timer Timer;
-typedef struct Udphdr Udphdr;
-
-struct Etherhdr
-{
-#define ETHER_HDR 14
- uchar d[6];
- uchar s[6];
- uchar type[2];
-
- /* Now we have the ip fields */
-#define ETHER_IPHDR 20
- uchar vihl; /* Version and header length */
- uchar tos; /* Type of service */
- uchar length[2]; /* packet length */
- uchar id[2]; /* Identification */
- uchar frag[2]; /* Fragment information */
- uchar ttl; /* Time to live */
- uchar proto; /* Protocol */
- uchar cksum[2]; /* Header checksum */
- uchar src[4]; /* Ip source */
- uchar dst[4]; /* Ip destination */
-};
-
-/* Ethernet packet types */
-#define ET_IP 0x0800
-
-struct Udphdr
-{
-#define UDP_EHSIZE 22
- uchar d[6]; /* Ethernet destination */
- uchar s[6]; /* Ethernet source */
- uchar type[2]; /* Ethernet packet type */
-
- uchar vihl; /* Version and header length */
- uchar tos; /* Type of service */
- uchar length[2]; /* packet length */
- uchar id[2]; /* Identification */
- uchar frag[2]; /* Fragment information */
-
- /* Udp pseudo ip really starts here */
-#define UDP_PHDRSIZE 12
-#define UDP_HDRSIZE 20
- uchar Unused;
- uchar udpproto; /* Protocol */
- uchar udpplen[2]; /* Header plus data length */
- uchar udpsrc[4]; /* Ip source */
- uchar udpdst[4]; /* Ip destination */
- uchar udpsport[2]; /* Source port */
- uchar udpdport[2]; /* Destination port */
- uchar udplen[2]; /* data length */
- uchar udpcksum[2]; /* Checksum */
-};
-
-struct Ilhdr
-{
-#define IL_EHSIZE 34
- uchar d[6]; /* Ethernet destination */
- uchar s[6]; /* Ethernet source */
- uchar type[2]; /* Ethernet packet type */
-
- uchar vihl; /* Version and header length */
- uchar tos; /* Type of service */
- uchar length[2]; /* packet length */
- uchar id[2]; /* Identification */
- uchar frag[2]; /* Fragment information */
- uchar ttl; /* Time to live */
- uchar proto; /* Protocol */
- uchar cksum[2]; /* Header checksum */
- uchar src[4]; /* Ip source */
- uchar dst[4]; /* Ip destination */
-#define IL_HDRSIZE 18
- uchar ilsum[2]; /* Checksum including header */
- uchar illen[2]; /* Packet length */
- uchar iltype; /* Packet type */
- uchar ilspec; /* Special */
- uchar ilsrc[2]; /* Src port */
- uchar ildst[2]; /* Dst port */
- uchar ilid[4]; /* Sequence id */
- uchar ilack[4]; /* Acked sequence */
-};
-
-struct Ilcb /* Control block */
-{
- int state; /* Connection state */
-
- Rendez syncer; /* where syncer waits for a connect */
-
- QLock ackq; /* Unacknowledged queue */
- Block *unacked;
- Block *unackedtail;
-
- QLock outo; /* Out of order packet queue */
- Block *outoforder;
-
- Lock nxl;
- ulong next; /* Id of next to send */
- ulong recvd; /* Last packet received */
- ulong start; /* Local start id */
- ulong rstart; /* Remote start id */
-
- int timeout; /* Time out counter */
- int slowtime; /* Slow time counter */
- int fasttime; /* Retransmission timer */
- int acktime; /* Acknowledge timer */
- int querytime; /* Query timer */
- int deathtime; /* Time to kill connection */
-
- int rtt; /* Average round trip time */
- ulong rttack; /* The ack we are waiting for */
- ulong ackms; /* Time we issued */
-
- int window; /* Maximum receive window */
-};
-
-enum /* Packet types */
-{
- Ilsync,
- Ildata,
- Ildataquery,
- Ilack,
- Ilquerey,
- Ilstate,
- Ilclose,
-};
-
-enum /* Connection state */
-{
- Ilclosed,
- Ilsyncer,
- Ilsyncee,
- Ilestablished,
- Illistening,
- Ilclosing,
-};
-
-#define TCP_PKT (TCP_EHSIZE+TCP_IPLEN+TCP_PHDRSIZE)
-
-struct Tcphdr
-{
-#define TCP_EHSIZE 14
- uchar d[6]; /* Ethernet destination */
- uchar s[6]; /* Ethernet source */
- uchar type[2]; /* Ethernet packet type */
-#define TCP_IPLEN 8
- uchar vihl; /* Version and header length */
- uchar tos; /* Type of service */
- uchar length[2]; /* packet length */
- uchar id[2]; /* Identification */
- uchar frag[2]; /* Fragment information */
-
-#define TCP_PHDRSIZE 12
- uchar Unused;
- uchar proto;
- uchar tcplen[2];
- uchar tcpsrc[4];
- uchar tcpdst[4];
-
-#define TCP_HDRSIZE 20
- uchar tcpsport[2];
- uchar tcpdport[2];
- uchar tcpseq[4];
- uchar tcpack[4];
- uchar tcpflag[2];
- uchar tcpwin[2];
- uchar tcpcksum[2];
- uchar tcpurg[2];
-
- /* Options segment */
- uchar tcpopt[2];
- uchar tcpmss[2];
-};
-
-enum
-{
- TimerOFF = 0,
- TimerON = 1,
- TimerDONE = 2,
-};
-
-struct Timer
-{
- Timer *next;
- Timer *prev;
- int state;
- int start;
- int count;
- void (*func)(void*);
- void *arg;
-};
-
-struct Tctl
-{
- uchar state; /* Connection state */
- uchar type; /* Listening or active connection */
- uchar code; /* Icmp code */
- struct {
- int una; /* Unacked data pointer */
- int nxt; /* Next sequence expected */
- int ptr; /* Data pointer */
- ushort wnd; /* Tcp send window */
- int up; /* Urgent data pointer */
- int wl1;
- int wl2;
- } snd;
- struct {
- int nxt; /* Receive pointer to next byte slot */
- ushort wnd; /* Receive window incoming */
- int up; /* Urgent pointer */
- } rcv;
- int iss; /* Initial sequence number */
- ushort cwind; /* Congestion window */
- ushort ssthresh; /* Slow start threshold */
- int resent; /* Bytes just resent */
- int irs; /* Initial received squence */
- ushort mss; /* Mean segment size */
- int rerecv; /* Overlap of data rerecevived */
- ushort window; /* Recevive window */
- int max_snd; /* Max send */
- int last_ack; /* Last acknowledege received */
- char backoff; /* Exponential backoff counter */
- char flags; /* State flags */
- char tos; /* Type of service */
-
- Blist rcvq; /* Received data */
- ulong rcvcnt; /* Bytes queued for upstream */
-
- Block *sndq; /* List of data going out */
- ulong sndcnt; /* Amount of data in send queue */
- Rendez sndr; /* process flow control */
- QLock sndrlock;
- int sndfull;
-
- Reseq *reseq; /* Resequencing queue */
- Timer timer; /* Activity timer */
- Timer acktimer; /* Acknoledge timer */
- Timer rtt_timer; /* Round trip timer */
- int rttseq; /* Round trip sequence */
- int srtt; /* Shortened round trip */
- int mdev; /* Mean deviation of round trip */
-};
-
-struct Tcpctl
-{
- QLock;
- Rendez syner;
- struct Tctl;
-};
-
-struct Tcp
-{
- Port source;
- Port dest;
- int seq;
- int ack;
- char flags;
- ushort wnd;
- ushort up;
- ushort mss;
-};
-
-struct Reseq
-{
- Reseq *next;
- Tcp seg;
- Block *bp;
- ushort length;
- char tos;
-};
-
-/* An ip interface used for UDP/TCP/IL */
-struct Ipconv
-{
- QLock; /* Ref count lock */
- Netprot; /* stat info */
- int ref;
- Ipaddr dst; /* Destination from connect */
- Port psrc; /* Source port */
- Port pdst; /* Destination port */
-
- Ipifc *ifc; /* Ip protocol interface */
- Queue *readq; /* Pointer to upstream read q */
- QLock listenq; /* List of people waiting incoming cons */
- Rendez listenr; /* Some where to sleep while waiting */
-
- char *err; /* Async protocol error */
- int backlog; /* Maximum number of waiting connections */
- int headers; /* include header in packet */
- int curlog; /* Number of waiting connections */
- Ipconv *newcon; /* This is the start of a connection */
-
- union {
- Tcpctl tcpctl; /* Tcp control block */
- Ilcb ilctl; /* Il control block */
- };
-};
-
-enum
-{
- MAX_TIME = (1<<20), /* Forever */
- TCP_ACK = 200, /* Timed ack sequence every 200ms */
-
- URG = 0x20, /* Data marked urgent */
- ACK = 0x10, /* Aknowledge is valid */
- PSH = 0x08, /* Whole data pipe is pushed */
- RST = 0x04, /* Reset connection */
- SYN = 0x02, /* Pkt. is synchronise */
- FIN = 0x01, /* Start close down */
-
- EOL_KIND = 0,
- NOOP_KIND = 1,
- MSS_KIND = 2,
-
- MSS_LENGTH = 4, /* Mean segment size */
- MSL2 = 10,
- MSPTICK = 100, /* Milliseconds per timer tick */
- DEF_MSS = 1024, /* Default mean segment */
- DEF_RTT = 1000, /* Default round trip */
-
- TCP_PASSIVE = 0, /* Listen connection */
- TCP_ACTIVE = 1, /* Outgoing connection */
- IL_PASSIVE = 0,
- IL_ACTIVE = 1,
-
- MAXBACKOFF = 5,
- FORCE = 1,
- CLONE = 2,
- RETRAN = 4,
- ACTIVE = 8,
- SYNACK = 16,
- AGAIN = 8,
- DGAIN = 4,
-};
-
-#define set_timer(t,x) (((t)->start) = (x)/MSPTICK)
-#define run_timer(t) ((t)->state == TimerON)
-
-enum /* Tcp connection states */
-{
- Closed = 0,
- Listen,
- Syn_sent,
- Syn_received,
- Established,
- Finwait1,
- Finwait2,
- Close_wait,
- Closing,
- Last_ack,
- Time_wait
-};
-
-enum
-{
- Nipconv= 512, /* max conversations per interface */
- Udphdrsize= 6, /* size if a to/from user Udp header */
-};
-
-/*
- * Ip interface structure. We have one for each active protocol driver
- */
-struct Ipifc
-{
- QLock;
- Network; /* user level network interface */
- Ipifc *next;
- int inited;
- uchar protocol; /* Ip header protocol number */
- void (*iprcv) (Ipifc*, Block*); /* Receive demultiplexor */
- int maxmtu; /* Maximum transfer unit */
- int minmtu; /* Minumum tranfer unit */
- int hsize; /* Media header size */
- ulong chkerrs; /* checksum errors */
- Ipconv **conv; /* conversations */
-};
-
-
-struct Fragq
-{
- QLock;
- Block *blist;
- Fragq *next;
- Ipaddr src;
- Ipaddr dst;
- ushort id;
- ulong age;
-};
-
-struct Ipfrag
-{
- ushort foff;
- ushort flen;
-};
-
-enum {
- IP_VER = 0x40, /* Using IP version 4 */
- IP_HLEN = 0x05, /* Header length in characters */
- IP_DF = 0x4000, /* Don't fragment */
- IP_MF = 0x2000, /* More fragments */
-
- /* Sizes */
- IP_MAX = (32*1024), /* Maximum Internet packet size */
- UDP_MAX = (IP_MAX-ETHER_IPHDR), /* Maximum UDP datagram size */
- UDP_DATMAX = (UDP_MAX-UDP_HDRSIZE),/* Maximum amount of udp data */
- IL_DATMAX = (IP_MAX-IL_HDRSIZE), /* Maximum IL data in one ip packet */
-
- /* Protocol numbers */
- IP_UDPPROTO = 17,
- IP_TCPPROTO = 6,
- IP_ILPROTO = 40,
-
- /* Protocol port numbers */
- PORTALLOC = 5000, /* First automatic allocated port */
- PRIVPORTALLOC = 600, /* First priveleged port allocated */
- UNPRIVPORTALLOC = 1024, /* First unpriveleged port allocated */
- PORTMAX = 30000, /* Last port to allocte */
-};
-
-void add_reseq(Tcpctl *, char, Tcp *, Block *, ushort);
-int arp_lookup(uchar*, uchar*);
-int backoff(int);
-Block* btrim(Block*, int, int);
-void localclose(Ipconv *, char []);
-int dupb(Block **, Block *, int, int);
-void extract_oob(Block **, Block **, Tcp *);
-void get_reseq(Tcpctl *, char *, Tcp *, Block **, ushort *);
-void hnputl(uchar*, ulong);
-void hnputs(uchar*, ushort);
-Block* htontcp(Tcp *, Block *, Tcphdr *);
-Block* htontcp(Tcp *, Block *, Tcphdr *);
-void iloutoforder(Ipconv*, Ilhdr*, Block*);
-void ilstart(Ipconv *, int, int);
-int inb_window(Tcpctl *, int);
-void init_tcpctl(Ipconv *);
-void initfrag(int);
-void initipifc(Ipifc*, uchar, void (*)(Ipifc*, Block*), int, int, int);
-Ipconv* ip_conn(Ipifc*, Port, Port, Ipaddr dest);
-ushort ip_csum(uchar*);
-Block* ip_reassemble(int, Block*, Etherhdr*);
-int ipclonecon(Chan *);
-int ipconbusy(Ipconv*);
-Ipconv* ipcreateconv(Ipifc*, int);
-int ipforme(uchar*);
-Fragq* ipfragallo(void);
-void ipfragfree(Fragq*, int);
-Ipconv* ipincoming(Ipifc*, Ipconv*);
-int iplisten(Chan *);
-void iplocalfill(Chan*, char*, int);
-void ipmkdir(Qinfo *, Dirtab *, Ipconv *);
-Ipaddr ipparse(char*);
-void ipremotefill(Chan*, char*, int);
-void iproute(uchar*, uchar*);
-void ipsetaddrs(void);
-void ipstatusfill(Chan*, char*, int);
-Port nextport(Ipifc*, int);
-ushort nhgets(uchar*);
-ulong nhgetl(uchar*);
-int ntohtcp(Tcp *, Block **);
-int ntohtcp(Tcp*, Block**);
-Ipconv* portused(Ipifc*, Port);
-void ppkt(Block*);
-void proc_syn(Ipconv*, char, Tcp*);
-ushort ptcl_csum(Block*bp, int, int);
-int pullb(Block **, int);
-void reset(Ipaddr, Ipaddr, char, ushort, Tcp*);
-void tcpsndsyn(Tcpctl*);
-int seq_ge(int, int);
-int seq_gt(int, int);
-int seq_gt(int, int);
-int seq_le(int, int);
-int seq_lt(int, int);
-int seq_within(int, int, int);
-int seq_within(int, int, int);
-void tcpsetstate(Ipconv *, char);
-void tcpgo(Timer *);
-void tcphalt(Timer *);
-void tcpxstate(Ipconv*, char oldstate, char newstate);
-void tcpacktimer(void *);
-void tcpinput(Ipifc*, Block *);
-void tcpoutput(Ipconv*);
-void tcptimeout(void *);
-void tcpackproc(void*);
-void tcpflow(void*);
-void tcpflushincoming(Ipconv*);
-void tcprcvwin(Ipconv *);
-void tcpstart(Ipconv *, int, ushort, char);
-int trim(Tcpctl *, Tcp *, Block **, ushort *);
-void udprcvmsg(Ipifc*, Block*);
-void update(Ipconv *, Tcp *);
-
-#define fmtaddr(xx) (xx>>24)&0xff,(xx>>16)&0xff,(xx>>8)&0xff,xx&0xff
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define BLKIP(xp) ((Etherhdr *)((xp)->rptr))
-#define BLKFRAG(xp) ((Ipfrag *)((xp)->base))
-#define PREC(x) ((x)>>5 & 7)
-
-extern Ipaddr Myip[7];
-extern Ipaddr Mymask;
-extern Ipaddr Mynetmask;
-extern Ipaddr classmask[4];
-extern Ipifc *ipifc[];
-extern char *tcpstate[];
-extern char *ilstate[];
-extern Rendez tcpflowr;
-extern Qinfo tcpinfo;
-extern Qinfo ipinfo;
-extern Qinfo udpinfo;
-extern Qinfo ilinfo;
-extern Qinfo arpinfo;
-extern Queue *Ipoutput;
-
-/* offsets into Myip */
-enum
-{
- Myself = 0,
- Mybcast = 1,
- Mynet = 3,
- Mysubnet = 5,
-};
M port/proc.c => port/proc.c +0 -1
@@ 84,7 84,6 @@ schedinit(void) /* never returns */
void
sched(void)
{
- kmapinval();
if(up) {
splhi();
m->cs++;
M port/qio.c => port/qio.c +16 -9
@@ 115,9 115,10 @@ iallockproc(void *arg)
unlock(cl);
splx(x);
- for(; first; first = p){
+ while(first != 0) {
p = first->next;
free(first);
+ first = p;
}
}
@@ 146,10 147,12 @@ iallockproc(void *arg)
first = 0;
l = &first;
- for(i = x = cl->goal - cl->have; x > 0; x--){
+ i = cl->goal - cl->have;
+ for(x = i; x > 0; x--){
p = malloc(1<<pow);
if(p == 0)
break;
+
*l = p;
l = &p->next;
}
@@ 190,7 193,7 @@ iallocb(int size)
Block *b;
size += sizeof(Block);
- for(pow = Minpow; pow <= Maxpow; pow++)
+ for(pow = Minpow; pow <= Maxpow; pow++){
if(size <= (1<<pow)){
cl = &arena.alloc[pow];
lock(cl);
@@ 205,10 208,13 @@ iallocb(int size)
b = (Block *)p;
memset(b, 0, sizeof(Block));
b->base = (uchar*)(b+1);
- b->wp = b->rp = b->base;
+ b->wp = b->base;
+ b->rp = b->base;
b->lim = b->base + (1<<pow) - sizeof(Block);
return b;
}
+ }
+
panic("iallocb %d\n", size);
return 0; /* not reached */
}
@@ 239,9 245,9 @@ allocb(int size)
if(b == 0)
exhausted("Blocks");
- memset(b, 0, sizeof(Block));
b->base = (uchar*)(b+1);
- b->rp = b->wp = b->base;
+ b->rp = b->base;
+ b->wp = b->base;
b->lim = b->base + size;
b->flag = 0;
@@ 549,9 555,10 @@ qclose(Queue *q)
splx(x);
/* free queued blocks */
- while(b = bfirst){
- bfirst = b->next;
- free(b);
+ while(bfirst){
+ b = bfirst->next;
+ free(bfirst);
+ bfirst = b;
}
/* wake up readers/writers */
D port/stasync.c => port/stasync.c +0 -477
@@ 1,477 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-
-#define DPRINT if(asyncdebug)kprint
-
-/*
- * configuration
- */
-enum {
- MAXFRAME= 256, /* also known to tsm8 code */
-};
-
-/* input states */
-enum
-{
- Hunt,
- Framing,
- Framed,
- Data,
- Escape
-};
-
-typedef struct Async Async;
-struct Async
-{
- QLock;
- Async *list;
- int id;
-
- int inuse;
- Queue *wq;
-
- /* output state */
- QLock xmit; /* transmit lock */
- int chan; /* current urp channel */
- Block *bp; /* current output buffer */
- int count;
- ushort crc;
-
- /* input state */
- int state; /* input state */
- uchar buf[MAXFRAME]; /* current input buffer */
- int icount;
- ushort icrc;
-
- /* statistics */
- ulong chan0;
- ulong toolong;
- ulong tooshort;
- ulong badcrc;
- ulong badescape;
- ulong in; /* bytes in */
- ulong out; /* bytes out */
-};
-
-int nasync;
-
-/* list of allocated async structures (never freed) */
-struct
-{
- Lock;
- Async *async;
-} asyncalloc;
-
-/*
- * async stream module definition
- */
-static void asynciput(Queue*, Block*);
-static void asyncoput(Queue*, Block*);
-static void asyncopen(Queue*, Stream*);
-static void asyncclose(Queue*);
-static void asyncreset(void);
-Qinfo asyncinfo =
-{
- asynciput,
- asyncoput,
- asyncopen,
- asyncclose,
- "async",
- asyncreset
-};
-
-static int debugcount = 6;
-int asyncdebug;
-int asyncerror;
-
-static ushort crc_table[256] = {
-#include "../port/crc_16.h"
-};
-
-#define BOT 0050 /* begin trailer */
-#define BOTM 0051 /* begin trailer, more data follows */
-#define BOTS 0052 /* seq update alg. on this trailer */
-
-#define FRAME 0x7e
-#define STUF 0x9d
-
-#define CRCSTART (crc_table[0xff])
-#define CRCFUNC(crc,x) (crc_table[((crc)^(x))&0xff]^((crc)>>8))
-
-/*
- * create the async structures
- */
-static void
-asyncreset(void)
-{
-}
-
-/*
- * allocate an async structure
- */
-static void
-asyncopen(Queue *q, Stream *s)
-{
- Async *ap;
-
- DPRINT("asyncopen %d\n", s->dev);
-
- for(ap = asyncalloc.async; ap; ap = ap->list){
- qlock(ap);
- if(ap->inuse == 0)
- break;
- qunlock(ap);
- }
- if(ap == 0){
- ap = smalloc(sizeof(Async));
- qlock(ap);
- lock(&asyncalloc);
- ap->list = asyncalloc.async;
- asyncalloc.async = ap;
- ap->id = nasync++;
- unlock(&asyncalloc);
- }
- q->ptr = q->other->ptr = ap;
-
- ap->inuse = 1;
- ap->bp = 0;
- ap->chan = -1;
- ap->count = 0;
- ap->toolong = 0;
- ap->tooshort = 0;
- ap->badcrc = 0;
- ap->badescape = 0;
- ap->chan0 = 0;
- ap->in = 0;
- ap->out = 0;
- ap->wq = WR(q);
- ap->state = Hunt;
- qunlock(ap);
-}
-
-static void
-asyncclose(Queue * q)
-{
- Async *ap = (Async *)q->ptr;
-
- DPRINT("asyncstclose %d\n", ap->id);
- qlock(ap);
- ap->inuse = 0;
- qunlock(ap);
-}
-
-/*
- * free all blocks of a message in `q', `bp' is the first block
- * of the message
- */
-static void
-freemsg(Queue *q, Block *bp)
-{
- for(; bp; bp = getq(q)){
- if(bp->flags & S_DELIM){
- freeb(bp);
- return;
- }
- freeb(bp);
- }
-}
-
-static void
-showframe(char *t, Async *ap, uchar *buf, int n)
-{
- kprint("a%d %s [", ap->id, t);
- while (--n >= 0)
- kprint(" %2.2ux", *buf++);
- kprint(" ]\n");
-}
-
-void
-aswrite(Async *ap)
-{
- if(ap->bp->rptr == ap->bp->wptr)
- return;
- FLOWCTL(ap->wq, ap->bp);
- ap->bp = 0;
-}
-
-void
-asputf(Async *ap)
-{
- uchar *p;
- int c;
-
- p = ap->bp->wptr;
- if(ap->count > 0) {
- if(asyncerror)
- ap->crc^=1, asyncerror=0;
- *p++ = c = ap->crc&0xff;
- if(c == FRAME)
- *p++ = 0x00;
- *p++ = c = (ap->crc>>8)&0xff;
- if(c == FRAME)
- *p++ = 0x00;
- ap->count = 0;
- }
- *p++ = FRAME;
- *p++ = FRAME;
- ap->bp->wptr = p;
- if(asyncdebug > 2)
- showframe("out", ap, ap->bp->rptr, BLEN(ap->bp));
- aswrite(ap);
-}
-
-void
-asputc(Async *ap, int c)
-{
- int d;
- uchar *p;
-
- if(ap->bp == 0)
- ap->bp = allocb(MAXFRAME+4);
- p = ap->bp->wptr;
- if(ap->count <= 0) {
- *p++ = d = 0x80|((ap->chan>>5)&0x7e);
- ap->crc = CRCFUNC(CRCSTART, d);
- *p++ = d = 0x80|((ap->chan<<1)&0x7e);
- ap->crc = CRCFUNC(ap->crc, d);
- }
- *p++ = c;
- if(c == FRAME)
- *p++ = 0x00;
- ap->crc = CRCFUNC(ap->crc, c);
- ap->bp->wptr = p;
- if(++ap->count >= MAXFRAME-4)
- asputf(ap);
- else if(ap->bp->lim - p < 8)
- aswrite(ap);
-}
-
-/*
- * output a block
- *
- * the first 2 bytes of every message are the channel number,
- * low order byte first. the third is a possible trailing control
- * character.
- */
-void
-asyncoput(Queue *q, Block *bp)
-{
- Async *ap = (Async *)q->ptr;
- int c, chan, ctl;
- Block *msg;
-
- if(bp->type != M_DATA){
- if(streamparse("debug", bp)){
- asyncdebug = 3;
- freeb(bp);
- } else {
- PUTNEXT(q, bp);
- }
- return;
- }
-
- /*
- * each datakit message has a 2 byte channel number followed by
- * one control byte
- */
- msg = pullup(bp, 3);
- if(msg == 0){
- print("asyncoput msglen < 3\n");
- return;
- }
- chan = msg->rptr[0] | (msg->rptr[1]<<8);
- ctl = msg->rptr[2];
- msg->rptr += 3;
-
- qlock(&ap->xmit);
- if(waserror()){
- qunlock(&ap->xmit);
- freeb(msg);
- nexterror();
- }
-
- /*
- * new frame if the channel number has changed
- */
- if(chan != ap->chan && ap->count > 0)
- asputf(ap);
- ap->chan = chan;
-
- if(asyncdebug > 1)
- kprint("a%d->(%d)%3.3uo %d\n",
- ap->id, chan, ctl, bp->wptr-bp->rptr);
-
- /*
- * send the 8 bit data
- */
- for(bp = msg; bp; bp = bp->next){
- while (bp->rptr < bp->wptr) {
- asputc(ap, c = *bp->rptr++);
- if(c == STUF)
- asputc(ap, 0);
- }
- }
-
- /*
- * send the control byte if there is one
- */
- if(ctl){
- asputc(ap, STUF);
- asputc(ap, ctl);
- switch (ctl) {
- case BOT:
- case BOTM:
- case BOTS:
- break;
- default:
- asputf(ap);
- }
- }
- if(debugcount > 0 && --debugcount == 0)
- asyncdebug = 1;
-
- freeb(msg);
- qunlock(&ap->xmit);
- poperror();
- return;
-}
-
-/*
- * Read bytes from the raw input.
- */
-
-void
-asdeliver(Queue *q, Async *ap)
-{
- int chan, c;
- Block *bp = 0;
- uchar *p = ap->buf;
- int n = ap->icount;
-
- chan = *p++ & 0x7e;
- chan = (chan<<5)|((*p++ & 0x7e)>>1);
- if(chan==0) {
- DPRINT("a%d deliver chan 0\n", ap->id);
- ap->chan0++;
- return;
- }
- for (n-=4; n>0; n--) {
- if(!bp) {
- bp = allocb(n+2);
- bp->flags |= S_DELIM;
- bp->wptr[0] = chan;
- bp->wptr[1] = chan>>8;
- bp->wptr[2] = 0;
- bp->wptr += 3;
- }
- if((c = *p++) == STUF) {
- --n;
- if((c = *p++) != 0) {
- bp->rptr[2] = c;
- if(asyncdebug > 1)
- kprint("a%d<-(%d)%3.3uo %d\n",
- ap->id, chan, bp->rptr[2],
- bp->wptr - bp->rptr - 3);
- PUTNEXT(q, bp);
- bp = 0;
- continue;
- } else
- c = STUF;
- }
- *bp->wptr++ = c;
- }
- if(bp) {
- if(asyncdebug > 1)
- kprint("a%d<-(%d)%3.3uo %d\n",
- ap->id, chan, bp->rptr[2],
- bp->wptr - bp->rptr - 3);
- PUTNEXT(q, bp);
- }
-}
-
-static void
-asynciput(Queue *q, Block *bp)
-{
- int c;
- Async *ap = q->ptr;
- int state = ap->state;
-
- while(bp->wptr > bp->rptr){
- c = *bp->rptr++;
- switch(state) {
- case Hunt: /* wait for framing byte */
- if(c == FRAME)
- state = Framing;
- break;
-
- case Framing: /* saw 1 framing byte after Hunt */
- if(c == FRAME)
- state = Framed;
- else
- state = Hunt;
- break;
-
- case Framed: /* saw 2 or more framing bytes */
- if(c == FRAME)
- break;
- state = Data;
- ap->icrc = CRCSTART;
- ap->icount = 0;
- goto Datachar;
-
- case Data: /* mid-frame */
- if(c == FRAME) {
- state = Escape;
- break;
- }
- Datachar:
- if(ap->icount >= MAXFRAME) {
- DPRINT("a%d pkt too long\n", ap->id);
- ap->toolong++;
- state = Hunt;
- break;
- }
- ap->icrc = CRCFUNC(ap->icrc, c);
- ap->buf[ap->icount++] = c;
- break;
-
- case Escape: /* saw framing byte in Data */
- switch (c) {
- case FRAME:
- if(asyncdebug > 2)
- showframe("in", ap, ap->buf, ap->icount);
- if(ap->icount < 5) {
- DPRINT("a%d pkt too short\n", ap->id);
- if(asyncdebug && asyncdebug<=2)
- showframe("shortin", ap, ap->buf, ap->icount);
- ap->tooshort++;
- } else if(ap->icrc != 0) {
- DPRINT("a%d bad crc\n", ap->id);
- if(asyncdebug && asyncdebug<=2)
- showframe("badin", ap, ap->buf, ap->icount);
- ap->badcrc++;
- } else {
- asdeliver(q, ap);
- }
- state = Framed;
- break;
- case 0:
- c = FRAME;
- state = Data;
- goto Datachar;
- default:
- DPRINT("a%d bad escape\n", ap->id);
- ap->badescape++;
- state = Hunt;
- break;
- }
- break;
- }
- }
- ap->state = state;
- freeb(bp);
-}
D port/stfcall.c => port/stfcall.c +0 -172
@@ 1,172 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-
-enum
-{
- Twritehdr = 16, /* Min bytes for Twrite */
- Rreadhdr = 8, /* Min bytes for Rread */
- Twritecnt = 13, /* Offset in byte stream of write count */
- Rreadcnt = 5, /* Offset for Readcnt */
-};
-
-static void fcalliput(Queue*, Block*);
-static void fcalloput(Queue*, Block*);
-static void fcallopen(Queue*, Stream*);
-static void fcallclose(Queue*);
-static void fcallreset(void);
-Qinfo fcallinfo = { fcalliput, fcalloput, fcallopen, fcallclose, "fcall", fcallreset };
-
-static uchar msglen[256] =
-{
- [Tnop] 3,
- [Rnop] 3,
- [Tsession] 3,
- [Rsession] 3,
- [Terror] 0,
- [Rerror] 67,
- [Tflush] 5,
- [Rflush] 3,
- [Tattach] 89,
- [Rattach] 13,
- [Tclone] 7,
- [Rclone] 5,
- [Twalk] 33,
- [Rwalk] 13,
- [Topen] 6,
- [Ropen] 13,
- [Tcreate] 38,
- [Rcreate] 13,
- [Tread] 15,
- [Rread] 8,
- [Twrite] 16,
- [Rwrite] 7,
- [Tclunk] 5,
- [Rclunk] 5,
- [Tremove] 5,
- [Rremove] 5,
- [Tstat] 5,
- [Rstat] 121,
- [Twstat] 121,
- [Rwstat] 5,
- [Tclwalk] 35,
- [Rclwalk] 13,
- [Tauth] 69,
- [Rauth] 35,
-};
-
-static void
-fcallreset(void)
-{
-}
-
-static void
-fcallopen(Queue *q, Stream *s)
-{
- USED(q, s);
-}
-
-static void
-fcallclose(Queue * q)
-{
- USED(q);
-}
-
-void
-fcalloput(Queue *q, Block *bp)
-{
- PUTNEXT(q, bp);
-}
-
-void
-upstream(Queue *q, ulong len)
-{
- Block *bl, **tail, *bp;
- ulong l;
-
- tail = &bl;
- while(len) {
- l = BLEN(q->first);
- if(l > len)
- break;
- bp = getq(q); /* Consume all of block */
- *tail = bp;
- tail = &bp->next;
- len -= l;
- }
- if(len) { /* Consume partial block */
- lock(q);
- *tail = copyb(q->first, len);
- q->first->rptr += len;
- q->len -= len;
- unlock(q);
- }
- for(bp = bl; bp->next; bp = bp->next)
- ;
- bp->flags |= S_DELIM;
- PUTNEXT(q, bl);
-}
-
-static void
-fcalliput(Queue *q, Block *bp)
-{
- ulong len, need, off;
-
- if(bp->type != M_DATA) {
- PUTNEXT(q, bp);
- return;
- }
- if(BLEN(bp) == 0) {
- freeb(bp);
- return;
- }
-
- /* Stash the data */
- bp->flags &= ~S_DELIM;
- putq(q, bp);
-
- for(;;) {
- bp = q->first;
- if(bp == 0)
- return;
- switch(bp->rptr[0]) { /* This is the type */
- default:
- len = msglen[bp->rptr[0]];
- if(len == 0){
- bp = allocb(0);
- bp->type = M_HANGUP;
- PUTNEXT(q, bp);
- return;
- }
- if(q->len < len)
- return;
-
- upstream(q, len);
- continue;
-
- case Twrite: /* Fmt: TGGFFOOOOOOOOCC */
- len = Twritehdr; /* T = type, G = tag, F = fid */
- off = Twritecnt; /* O = offset, C = count */
- break;
-
- case Rread: /* Fmt: TGGFFCC */
- len = Rreadhdr;
- off = Rreadcnt;
- break;
- }
-
- if(q->len < len)
- return;
-
- pullup(q->first, len);
- bp = q->first;
- need = len+bp->rptr[off]+(bp->rptr[off+1]<<8);
- if(q->len < need)
- return;
-
- upstream(q, need);
- }
-}
D port/stil.c => port/stil.c +0 -877
@@ 1,877 0,0 @@
-/*
- * stil - Internet link protocol
- */
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-#include "arp.h"
-#include "ipdat.h"
-
-#define DBG if(0)print
-int ilcksum = 1;
-static int initseq = 26000;
-static Rendez ilackr;
-
-char *ilstate[] =
-{
- "Closed",
- "Syncer",
- "Syncee",
- "Established",
- "Listening",
- "Closing"
-};
-
-char *iltype[] =
-{
- "sync",
- "data",
- "dataquerey",
- "ack",
- "querey",
- "state",
- "close"
-};
-static char *etime = "connection timed out";
-
-/* Always Acktime < Fasttime < Slowtime << Ackkeepalive */
-enum
-{
- Iltickms = 100,
- Slowtime = 200*Iltickms,
- Fasttime = 4*Iltickms,
- Acktime = 2*Iltickms,
- Ackkeepalive = 6000*Iltickms,
- Querytime = 60*Iltickms, /* time between queries */
- Keepalivetime = 10*Querytime, /* keep alive time */
- Defaultwin = 20,
- ILgain = 8,
-};
-
-#define Starttimer(s) {(s)->timeout = 0; \
- (s)->fasttime = (Fasttime*(s)->rtt)/Iltickms; \
- (s)->slowtime = (Slowtime*(s)->rtt)/Iltickms; }
-
-void ilrcvmsg(Ipifc*, Block*);
-void ilackproc(void*);
-void ilsendctl(Ipconv*, Ilhdr*, int, ulong, ulong);
-void ilackq(Ilcb*, Block*);
-void ilprocess(Ipconv*, Ilhdr*, Block*);
-void ilpullup(Ipconv*);
-void ilhangup(Ipconv*, char *);
-void ilfreeq(Ilcb*);
-void ilrexmit(Ilcb*);
-void ilbackoff(Ilcb*);
-
-void
-ilopen(Queue *q, Stream *s)
-{
- Ipconv *ipc;
- static int ilkproc;
-
- if(!Ipoutput) {
- Ipoutput = WR(q);
- s->opens++;
- s->inuse++;
- }
-
- if(ilkproc == 0) {
- ilkproc = 1;
- kproc("ilack", ilackproc, ipifc[s->dev]);
- }
-
- ipc = ipcreateconv(ipifc[s->dev], s->id);
- initipifc(ipc->ifc, IP_ILPROTO, ilrcvmsg, 1500, 60, ETHER_HDR);
-
- ipc->readq = RD(q);
- RD(q)->ptr = (void *)ipc;
- WR(q)->next->ptr = (void *)ipc->ifc;
- WR(q)->ptr = (void *)ipc;
-}
-
-void
-ilclose(Queue *q)
-{
- Ipconv *s;
- Ilcb *ic;
-
- s = (Ipconv *)(q->ptr);
- ic = &s->ilctl;
- qlock(s);
- s->readq = 0;
- qunlock(s);
-
- switch(ic->state) {
- case Ilclosing:
- case Ilclosed:
- break;
- case Ilsyncer:
- case Ilsyncee:
- case Ilestablished:
- ilfreeq(ic);
- ic->state = Ilclosing;
- ilsendctl(s, 0, Ilclose, ic->next, ic->recvd);
- break;
- case Illistening:
- ic->state = Ilclosed;
- s->psrc = 0;
- s->pdst = 0;
- s->dst = 0;
- break;
- }
-}
-
-void
-iloput(Queue *q, Block *bp)
-{
- Ipconv *ipc;
- Ilhdr *ih;
- Ilcb *ic;
- int dlen;
- Block *f;
- ulong id;
-
- ipc = (Ipconv *)(q->ptr);
- if(ipc->psrc == 0)
- error(Enoport);
-
- ic = &ipc->ilctl;
- switch(ic->state) {
- case Ilclosed:
- case Illistening:
- case Ilclosing:
- error(Ehungup);
- }
-
- if(bp->type != M_DATA) {
- freeb(bp);
- error(Ebadctl);
- }
-
- /* Only allow atomic Il writes to form datagrams */
- for(f = bp; f->next; f = f->next)
- ;
- if((f->flags & S_DELIM) == 0) {
- freeb(bp);
- error(Emsgsize);
- }
-
- dlen = blen(bp);
- if(dlen > IL_DATMAX) {
- freeb(bp);
- error(Emsgsize);
- }
-
- /* Make space to fit il & ip & ethernet header */
- bp = padb(bp, IL_EHSIZE+IL_HDRSIZE);
- ih = (Ilhdr *)(bp->rptr);
-
- /* Ip fields */
- ih->frag[0] = 0;
- ih->frag[1] = 0;
- hnputl(ih->src, Myip[Myself]);
- hnputl(ih->dst, ipc->dst);
- ih->proto = IP_ILPROTO;
- /* Il fields */
- hnputs(ih->illen, dlen+IL_HDRSIZE);
- hnputs(ih->ilsrc, ipc->psrc);
- hnputs(ih->ildst, ipc->pdst);
-
- lock(&ic->nxl);
- id = ic->next++;
- unlock(&ic->nxl);
- hnputl(ih->ilid, id);
-
- hnputl(ih->ilack, ic->recvd);
- ih->iltype = Ildata;
- ih->ilspec = 0;
- ih->ilsum[0] = 0;
- ih->ilsum[1] = 0;
-
- /* Checksum of ilheader plus data (not ip & no pseudo header) */
- if(ilcksum)
- hnputs(ih->ilsum, ptcl_csum(bp, IL_EHSIZE, dlen+IL_HDRSIZE));
- ilackq(ic, bp);
-
- /* Start the round trip timer for this packet if the timer is free */
- if(ic->rttack == 0) {
- ic->rttack = id;
- ic->ackms = MACHP(0)->ticks;
- }
- ic->acktime = Ackkeepalive;
-
- PUTNEXT(q, bp);
-}
-
-void
-ilackq(Ilcb *ic, Block *bp)
-{
- Block *np;
-
- /* Enqueue a copy on the unacked queue in case this one gets lost */
- np = copyb(bp, blen(bp));
- qlock(&ic->ackq);
- if(ic->unacked)
- ic->unackedtail->list = np;
- else {
- /* Start timer since we may have been idle for some time */
- Starttimer(ic);
- ic->unacked = np;
- }
- ic->unackedtail = np;
- np->list = 0;
- qunlock(&ic->ackq);
-}
-
-void
-ilackto(Ilcb *ic, ulong ackto)
-{
- Ilhdr *h;
- Block *bp;
- ulong id, t;
-
- if(ic->rttack == ackto) {
- t = TK2MS(MACHP(0)->ticks - ic->ackms);
- /* Guard against the ulong zero wrap if MACP->ticks */
- if(t < 100*ic->rtt)
- ic->rtt = (ic->rtt*(ILgain-1)+t)/ILgain;
- if(ic->rtt < Iltickms)
- ic->rtt = Iltickms;
- }
-
- /* Cancel if we lost the packet we were interested in */
- if(ic->rttack <= ackto)
- ic->rttack = 0;
-
- qlock(&ic->ackq);
- while(ic->unacked) {
- h = (Ilhdr *)ic->unacked->rptr;
- id = nhgetl(h->ilid);
- if(ackto < id)
- break;
-
- bp = ic->unacked;
- ic->unacked = bp->list;
- bp->list = 0;
- freeb(bp);
- }
- qunlock(&ic->ackq);
-}
-
-void
-iliput(Queue *q, Block *bp)
-{
- PUTNEXT(q, bp);
-}
-
-void
-ilrcvmsg(Ipifc *ifc, Block *bp)
-{
- Ilhdr *ih;
- Ilcb *ic;
- int plen, illen;
- Ipconv *s, **p, **etab, *new, *spec, *gen;
- short sp, dp;
- Ipaddr dst;
-
- ih = (Ilhdr *)bp->rptr;
- plen = blen(bp);
- if(plen < IL_EHSIZE+IL_HDRSIZE)
- goto drop;
-
- illen = nhgets(ih->illen);
- if(illen+IL_EHSIZE > plen)
- goto drop;
-
- sp = nhgets(ih->ildst);
- dp = nhgets(ih->ilsrc);
- dst = nhgetl(ih->src);
-
- if(ilcksum && ptcl_csum(bp, IL_EHSIZE, illen) != 0) {
- ifc->chkerrs++;
-/* st = (ih->iltype < 0 || ih->iltype > Ilclose) ? "?" : iltype[ih->iltype];
- print("il: cksum error, pkt(%s id %lud ack %lud %d.%d.%d.%d/%d->%d)\n",
- st, nhgetl(ih->ilid), nhgetl(ih->ilack), fmtaddr(dst), sp, dp); /**/
- goto drop;
- }
-
- etab = &ifc->conv[Nipconv];
- for(p = ifc->conv; p < etab; p++) {
- s = *p;
- if(s == 0)
- break;
- if(s->psrc == sp)
- if(s->pdst == dp)
- if(s->dst == dst) {
- ilprocess(s, ih, bp);
- return;
- }
- }
-
- if(ih->iltype != Ilsync)
- goto drop;
-
- gen = 0;
- spec = 0;
- etab = &ifc->conv[Nipconv];
- for(p = ifc->conv; p < etab && *p; p++) {
- s = *p;
- if(s->ilctl.state == Illistening)
- if(s->pdst == 0)
- if(s->dst == 0) {
- if(s->psrc == sp){
- spec = s;
- break;
- }
- if(s->psrc == 0)
- gen = s;
- }
- }
-
- if(spec)
- s = spec;
- else if(gen)
- s = gen;
- else
- goto drop;
-
- if(s->curlog > s->backlog)
- goto reset;
-
- new = ipincoming(ifc, s);
- if(new == 0)
- goto reset;
-
- new->newcon = s;
- new->ifc = s->ifc;
- new->psrc = sp;
- new->pdst = dp;
- new->dst = nhgetl(ih->src);
-
- ic = &new->ilctl;
- ic->state = Ilsyncee;
- initseq += TK2MS(MACHP(0)->ticks);
- ic->start = initseq & 0xffffff;
- ic->next = ic->start+1;
- ic->recvd = 0;
- ic->rstart = nhgetl(ih->ilid);
- ic->slowtime = Slowtime;
- ic->rtt = Iltickms;
- ic->querytime = Keepalivetime;
- ic->deathtime = Keepalivetime;
- ic->window = Defaultwin;
- ilprocess(new, ih, bp);
-
- s->curlog++;
- wakeup(&s->listenr);
- return;
-
-drop:
- freeb(bp);
- return;
-reset:
- ilsendctl(0, ih, Ilclose, 0, 0);
- freeb(bp);
-}
-
-void
-_ilprocess(Ipconv *s, Ilhdr *h, Block *bp)
-{
- Ilcb *ic;
- ulong id, ack;
-
- id = nhgetl(h->ilid);
- ack = nhgetl(h->ilack);
- ic = &s->ilctl;
-
- ic->querytime = Keepalivetime;
- ic->deathtime = Keepalivetime;
- switch(ic->state) {
- default:
- panic("il unknown state");
- case Ilclosed:
- freeb(bp);
- break;
- case Ilsyncer:
- switch(h->iltype) {
- default:
- break;
- case Ilsync:
- if(ack != ic->start)
- ilhangup(s, "connection rejected");
- else {
- ic->recvd = id;
- ic->rstart = id;
- ilsendctl(s, 0, Ilack, ic->next, ic->recvd);
- ic->state = Ilestablished;
- wakeup(&ic->syncer);
- ilpullup(s);
- Starttimer(ic);
- }
- break;
- case Ilclose:
- if(ack == ic->start)
- ilhangup(s, "remote close");
- break;
- }
- freeb(bp);
- break;
- case Ilsyncee:
- switch(h->iltype) {
- default:
- break;
- case Ilsync:
- if(id != ic->rstart || ack != 0)
- ic->state = Ilclosed;
- else {
- ic->recvd = id;
- ilsendctl(s, 0, Ilsync, ic->start, ic->recvd);
- Starttimer(ic);
- }
- break;
- case Ilack:
- if(ack == ic->start) {
- ic->state = Ilestablished;
- ilpullup(s);
- Starttimer(ic);
- }
- break;
- case Ilclose:
- if(id == ic->next)
- ilhangup(s, "remote close");
- break;
- }
- freeb(bp);
- break;
- case Ilestablished:
- switch(h->iltype) {
- case Ilsync:
- if(id != ic->rstart)
- ilhangup(s, "remote close");
- else {
- ilsendctl(s, 0, Ilack, ic->next, ic->rstart);
- Starttimer(ic);
- }
- freeb(bp);
- break;
- case Ildata:
- Starttimer(ic);
- ilackto(ic, ack);
- ic->acktime = Acktime;
- iloutoforder(s, h, bp);
- ilpullup(s);
- break;
- case Ildataquery:
- Starttimer(ic);
- ilackto(ic, ack);
- ic->acktime = Acktime;
- iloutoforder(s, h, bp);
- ilpullup(s);
- ilsendctl(s, 0, Ilstate, ic->next, ic->recvd);
- break;
- case Ilack:
- ilackto(ic, ack);
- Starttimer(ic);
- freeb(bp);
- break;
- case Ilquerey:
- ilackto(ic, ack);
- ilsendctl(s, 0, Ilstate, ic->next, ic->recvd);
- Starttimer(ic);
- freeb(bp);
- break;
- case Ilstate:
- ilackto(ic, ack);
- ilrexmit(ic);
- Starttimer(ic);
- freeb(bp);
- break;
- case Ilclose:
- freeb(bp);
- if(ack < ic->start || ack > ic->next)
- break;
- ilsendctl(s, 0, Ilclose, ic->next, ic->recvd);
- ic->state = Ilclosing;
- ilfreeq(ic);
- Starttimer(ic);
- break;
- }
- break;
- case Illistening:
- freeb(bp);
- break;
- case Ilclosing:
- switch(h->iltype) {
- case Ilclose:
- ic->recvd = id;
- ilsendctl(s, 0, Ilclose, ic->next, ic->recvd);
- if(ack == ic->next)
- ilhangup(s, 0);
- Starttimer(ic);
- break;
- default:
- break;
- }
- freeb(bp);
- break;
- }
-}
-
-void
-ilrexmit(Ilcb *ic)
-{
- Block *nb;
- Ilhdr *h;
-
- nb = 0;
- qlock(&ic->ackq);
- if(ic->unacked)
- nb = copyb(ic->unacked, blen(ic->unacked));
- qunlock(&ic->ackq);
-
- if(nb == 0)
- return;
-
- h = (Ilhdr*)nb->rptr;
- DBG("rxmit %d.", nhgetl(h->ilid));
-
- h->iltype = Ildataquery;
- hnputl(h->ilack, ic->recvd);
- h->ilsum[0] = 0;
- h->ilsum[1] = 0;
- if(ilcksum)
- hnputs(h->ilsum, ptcl_csum(nb, IL_EHSIZE, nhgets(h->illen)));
-
- PUTNEXT(Ipoutput, nb);
-}
-
-/* DEBUG */
-void
-ilprocess(Ipconv *s, Ilhdr *h, Block *bp)
-{
- Ilcb *ic = &s->ilctl;
-
- USED(ic);
- DBG("%11s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ",
- ilstate[ic->state], ic->rstart, ic->recvd, ic->start, ic->next,
- iltype[h->iltype], nhgetl(h->ilid), nhgetl(h->ilack),
- nhgets(h->ilsrc), nhgets(h->ildst));
-
- _ilprocess(s, h, bp);
-
- DBG("%11s rcv %d snt %d\n", ilstate[ic->state], ic->recvd, ic->next);
-}
-
-void
-ilhangup(Ipconv *s, char *msg)
-{
- Block *nb;
- int l;
- Ilcb *ic;
- int callout;
-
- DBG("hangup! %s %d/%d\n", msg ? msg : "??", s->psrc, s->pdst);
-
- ic = &s->ilctl;
- callout = ic->state == Ilsyncer;
- ic->state = Ilclosed;
- qlock(s);
- if(s->readq) {
- if(msg) {
- l = strlen(msg);
- nb = allocb(l);
- strcpy((char*)nb->wptr, msg);
- nb->wptr += l;
- }
- else
- nb = allocb(0);
- nb->type = M_HANGUP;
- nb->flags |= S_DELIM;
- PUTNEXT(s->readq, nb);
- }
- qunlock(s);
- if(callout)
- wakeup(&ic->syncer);
-
- s->psrc = 0;
-}
-
-void
-ilpullup(Ipconv *s)
-{
- Ilcb *ic;
- Ilhdr *oh;
- Block *bp;
- ulong oid, dlen;
-
- if(s->readq == 0)
- return;
-
- ic = &s->ilctl;
- if(ic->state != Ilestablished)
- return;
-
- qlock(&ic->outo);
- while(ic->outoforder) {
- bp = ic->outoforder;
- oh = (Ilhdr*)bp->rptr;
- oid = nhgetl(oh->ilid);
- if(oid <= ic->recvd) {
- ic->outoforder = bp->list;
- freeb(bp);
- continue;
- }
- if(oid != ic->recvd+1)
- break;
-
- ic->recvd = oid;
- ic->outoforder = bp->list;
-
- qunlock(&ic->outo);
- bp->list = 0;
- dlen = nhgets(oh->illen)-IL_HDRSIZE;
- bp = btrim(bp, IL_EHSIZE+IL_HDRSIZE, dlen);
- PUTNEXT(s->readq, bp);
- qlock(&ic->outo);
- }
- qunlock(&ic->outo);
-}
-
-void
-iloutoforder(Ipconv *s, Ilhdr *h, Block *bp)
-{
- Block *f, **l;
- Ilcb *ic;
- ulong id;
- uchar *lid;
-
- ic = &s->ilctl;
- bp->list = 0;
-
-
- id = nhgetl(h->ilid);
- /* Window checks */
- if(id <= ic->recvd || id > ic->recvd+ic->window) {
- freeb(bp);
- return;
- }
-
- /* Packet is acceptable so sort onto receive queue for pullup */
- qlock(&ic->outo);
- if(ic->outoforder == 0)
- ic->outoforder = bp;
- else {
- l = &ic->outoforder;
- for(f = *l; f; f = f->list) {
- lid = ((Ilhdr*)(f->rptr))->ilid;
- if(id < nhgetl(lid)) {
- bp->list = f;
- *l = bp;
- qunlock(&ic->outo);
- return;
- }
- l = &f->list;
- }
- *l = bp;
- }
- qunlock(&ic->outo);
-}
-
-void
-ilsendctl(Ipconv *ipc, Ilhdr *inih, int type, ulong id, ulong ack)
-{
- Ilhdr *ih;
- Ilcb *ic;
- Block *bp;
-
- bp = allocb(IL_EHSIZE+IL_HDRSIZE);
- bp->wptr += IL_EHSIZE+IL_HDRSIZE;
- bp->flags |= S_DELIM;
-
- ih = (Ilhdr *)(bp->rptr);
- ic = &ipc->ilctl;
-
- /* Ip fields */
- ih->proto = IP_ILPROTO;
- hnputl(ih->src, Myip[Myself]);
- hnputs(ih->illen, IL_HDRSIZE);
- ih->frag[0] = 0;
- ih->frag[1] = 0;
- if(inih) {
- hnputl(ih->dst, nhgetl(inih->src));
- hnputs(ih->ilsrc, nhgets(inih->ildst));
- hnputs(ih->ildst, nhgets(inih->ilsrc));
- hnputl(ih->ilid, nhgetl(inih->ilack));
- hnputl(ih->ilack, nhgetl(inih->ilid));
- }
- else {
- hnputl(ih->dst, ipc->dst);
- hnputs(ih->ilsrc, ipc->psrc);
- hnputs(ih->ildst, ipc->pdst);
- hnputl(ih->ilid, id);
- hnputl(ih->ilack, ack);
- ic->acktime = Ackkeepalive;
- }
- ih->iltype = type;
- ih->ilspec = 0;
- ih->ilsum[0] = 0;
- ih->ilsum[1] = 0;
-
- if(ilcksum)
- hnputs(ih->ilsum, ptcl_csum(bp, IL_EHSIZE, IL_HDRSIZE));
-
-/* DBG("\nctl(%s id %d ack %d %d->%d)\n",
- iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack),
- nhgets(ih->ilsrc), nhgets(ih->ildst));
-*/
- PUTNEXT(Ipoutput, bp);
-}
-
-void
-ilackproc(void *a)
-{
- Ipifc *ifc;
- Ipconv **base, **p, **end, *s;
- Ilcb *ic;
-
- ifc = (Ipifc*)a;
- base = ifc->conv;
- end = &base[Nipconv];
-
- for(;;) {
- tsleep(&ilackr, return0, 0, Iltickms);
- for(p = base; p < end && *p; p++) {
- s = *p;
- ic = &s->ilctl;
- ic->timeout += Iltickms;
- switch(ic->state) {
- case Ilclosed:
- case Illistening:
- break;
- case Ilclosing:
- if(ic->timeout >= ic->fasttime) {
- ilsendctl(s, 0, Ilclose, ic->next, ic->recvd);
- ilbackoff(ic);
- }
- if(ic->timeout >= ic->slowtime)
- ilhangup(s, 0);
- break;
- case Ilsyncee:
- case Ilsyncer:
- if(ic->timeout >= ic->fasttime) {
- ilsendctl(s, 0, Ilsync, ic->start, ic->recvd);
- ilbackoff(ic);
- }
- if(ic->timeout >= ic->slowtime)
- ilhangup(s, etime);
- break;
- case Ilestablished:
- ic->acktime -= Iltickms;
- if(ic->acktime <= 0)
- ilsendctl(s, 0, Ilack, ic->next, ic->recvd);
-
- ic->querytime -= Iltickms;
- if(ic->querytime <= 0){
- ic->deathtime -= Querytime;
- if(ic->deathtime < 0){
- ilhangup(s, etime);
- break;
- }
- ilsendctl(s, 0, Ilquerey, ic->next, ic->recvd);
- ic->querytime = Querytime;
- }
- if(ic->unacked == 0) {
- ic->timeout = 0;
- break;
- }
- if(ic->timeout >= ic->fasttime) {
- ilrexmit(ic);
- ilbackoff(ic);
- }
- if(ic->timeout >= ic->slowtime) {
- ilhangup(s, etime);
- break;
- }
- break;
- }
- }
- }
-}
-
-void
-ilbackoff(Ilcb *ic)
-{
- if(ic->fasttime < Slowtime/2)
- ic->fasttime += Fasttime;
- else
- ic->fasttime = (ic->fasttime)*3/2;
-}
-
-static int
-notsyncer(void *ic)
-{
- Ilcb *i;
-
- i = ic;
- return i->state != Ilsyncer;
-}
-
-void
-ilstart(Ipconv *ipc, int type, int window)
-{
- Ilcb *ic = &ipc->ilctl;
-
- if(ic->state != Ilclosed)
- return;
-
- ic->unacked = 0;
- ic->outoforder = 0;
- ic->slowtime = Slowtime;
- ic->rtt = Iltickms;
- Starttimer(ic);
-
- initseq += TK2MS(MACHP(0)->ticks);
- ic->start = initseq & 0xffffff;
- ic->next = ic->start+1;
- ic->recvd = 0;
- ic->window = window;
-
- switch(type) {
- case IL_PASSIVE:
- ic->state = Illistening;
- break;
- case IL_ACTIVE:
- ic->state = Ilsyncer;
- ilsendctl(ipc, 0, Ilsync, ic->start, ic->recvd);
- sleep(&ic->syncer, notsyncer, ic);
- if(ic->state == Ilclosed)
- error(Etimedout);
- break;
- }
-}
-
-void
-ilfreeq(Ilcb *ic)
-{
- Block *bp, *next;
-
- qlock(&ic->ackq);
- for(bp = ic->unacked; bp; bp = next) {
- next = bp->list;
- freeb(bp);
- }
- ic->unacked = 0;
- qunlock(&ic->ackq);
-
- qlock(&ic->outo);
- for(bp = ic->outoforder; bp; bp = next) {
- next = bp->list;
- freeb(bp);
- }
- ic->outoforder = 0;
- qunlock(&ic->outo);
-}
D port/stip.c => port/stip.c +0 -635
@@ 1,635 0,0 @@
-/*
- * ethernet specific multiplexor for ip
- *
- * this line discipline gets pushed onto an ethernet channel
- * to demultiplex/multiplex ip conversations.
- */
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-#include "arp.h"
-#include "ipdat.h"
-
-#define DPRINT if(pip)print
-int pip = 0;
-int ipcksum = 1;
-int Id = 1;
-
-Fragq *flisthead;
-Fragq *fragfree;
-QLock fraglock;
-
-Queue *Etherq;
-
-Ipaddr Myip[7];
-Ipaddr Mymask;
-Ipaddr Mynetmask;
-uchar Netmyip[4]; /* In Network byte order */
-uchar bcast[4] = { 0xff, 0xff, 0xff, 0xff };
-
-/* Predeclaration */
-static void ipetherclose(Queue*);
-static void ipetheriput(Queue*, Block*);
-static void ipetheropen(Queue*, Stream*);
-static void ipetheroput(Queue*, Block*);
-
-/*
- * the ethernet multiplexor stream module definition
- */
-Qinfo ipinfo =
-{
- ipetheriput,
- ipetheroput,
- ipetheropen,
- ipetherclose,
- "internet"
-};
-
-void
-initfrag(int size)
-{
- Fragq *fq, *eq;
-
- fragfree = (Fragq*)xalloc(sizeof(Fragq) * size);
-
- eq = &fragfree[size];
- for(fq = fragfree; fq < eq; fq++)
- fq->next = fq+1;
-
- fragfree[size-1].next = 0;
-}
-
-/*
- * set up an ether interface
- */
-static void
-ipetheropen(Queue *q, Stream *s)
-{
- Ipconv *ipc;
-
- /* First open is by ipconfig and sets up channel
- * to ethernet
- */
- if(!Etherq) {
- Etherq = WR(q);
- s->opens++; /* Hold this queue in place */
- s->inuse++;
- ipsetaddrs();
- } else {
- ipc = ipcreateconv(ipifc[s->dev], s->id);
- RD(q)->ptr = (void *)ipc;
- WR(q)->ptr = (void *)ipc;
- ipc->ref = 1;
- }
-
- DPRINT("ipetheropen EQ %lux dev=%d id=%d RD %lux WR %lux\n",
- Etherq, s->dev, s->id, RD(q), WR(q));
-}
-
-/*
- * initipifc - set parameters of an ip protocol interface
- */
-void
-initipifc(Ipifc *ifc, uchar ptcl, void (*recvfun)(Ipifc*, Block *bp), int max,
- int min, int hdrsize)
-{
- qlock(ifc);
- ifc->iprcv = recvfun;
-
- /* If media supports large transfer units limit maxmtu
- * to max ip size */
- if(max > IP_MAX)
- max = IP_MAX;
- ifc->maxmtu = max;
- ifc->minmtu = min;
- ifc->hsize = hdrsize;
-
- ifc->protocol = ptcl;
- ifc->inited = 1;
-
- qunlock(ifc);
-}
-
-static void
-ipetherclose(Queue *q)
-{
- Ipconv *ipc;
-
- ipc = (Ipconv *)(q->ptr);
- if(ipc){
- netdisown(ipc);
- ipc->ref = 0;
- }
-}
-
-static void
-ipetheroput(Queue *q, Block *bp)
-{
- Etherhdr *eh, *feh;
- int lid, len, seglen, chunk, dlen, blklen, offset;
- Ipifc *ifp;
- ushort fragoff;
- Block *xp, *nb;
- uchar *ptr;
-
- if(bp->type != M_DATA){
- /* Allow one setting of the ip address */
- if(streamparse("setip", bp)) {
- if(strncmp(eve, up->user, sizeof(eve)) != 0)
- error(Eperm);
- ptr = bp->rptr;
- Myip[Myself] = ipparse((char *)ptr);
- Netmyip[0] = (Myip[Myself]>>24)&0xff;
- Netmyip[1] = (Myip[Myself]>>16)&0xff;
- Netmyip[2] = (Myip[Myself]>>8)&0xff;
- Netmyip[3] = Myip[Myself]&0xff;
- Mymask = classmask[Myip[Myself]>>30];
- while(*ptr != ' ' && *ptr)
- ptr++;
- if(*ptr)
- Mynetmask = ipparse((char *)ptr);
- else
- Mynetmask = Mymask;
- freeb(bp);
- ipsetaddrs();
- }
- else
- PUTNEXT(Etherq, bp);
- return;
- }
-
- ifp = (Ipifc *)(q->ptr);
-
- /* Number of bytes in ip and media header to write */
- len = blen(bp);
-
- /* Fill out the ip header */
- eh = (Etherhdr *)(bp->rptr);
- eh->vihl = IP_VER|IP_HLEN;
- eh->tos = 0;
- eh->ttl = 255;
-
- /* If we dont need to fragment just send it */
- if(len <= ifp->maxmtu) {
- hnputs(eh->length, len-ETHER_HDR);
- hnputs(eh->id, Id++);
- eh->frag[0] = 0;
- eh->frag[1] = 0;
- eh->cksum[0] = 0;
- eh->cksum[1] = 0;
- hnputs(eh->cksum, ip_csum(&eh->vihl));
-
- /* Finally put in the type and pass down to the arp layer */
- hnputs(eh->type, ET_IP);
- PUTNEXT(Etherq, bp);
- return;
- }
-
- if(eh->frag[0] & (IP_DF>>8))
- goto drop;
-
- seglen = (ifp->maxmtu - (ETHER_HDR+ETHER_IPHDR)) & ~7;
- if(seglen < 8)
- goto drop;
-
- /* Make prototype output header */
- hnputs(eh->type, ET_IP);
-
- dlen = len - (ETHER_HDR+ETHER_IPHDR);
- xp = bp;
- lid = Id++;
-
- offset = ETHER_HDR+ETHER_IPHDR;
- while(xp && offset && offset >= BLEN(xp)) {
- offset -= BLEN(xp);
- xp = xp->next;
- }
- xp->rptr += offset;
-
- for(fragoff = 0; fragoff < dlen; fragoff += seglen) {
- nb = allocb(ETHER_HDR+ETHER_IPHDR+seglen);
- feh = (Etherhdr *)(nb->rptr);
-
- memmove(nb->wptr, eh, ETHER_HDR+ETHER_IPHDR);
- nb->wptr += ETHER_HDR+ETHER_IPHDR;
-
- if((fragoff + seglen) >= dlen) {
- seglen = dlen - fragoff;
- hnputs(feh->frag, fragoff>>3);
- }
- else {
- hnputs(feh->frag, (fragoff>>3)|IP_MF);
- }
-
- hnputs(feh->length, seglen + ETHER_IPHDR);
- hnputs(feh->id, lid);
-
- /* Copy up the data area */
- chunk = seglen;
- while(chunk) {
- if(!xp) {
- freeb(nb);
- goto drop;
- }
- blklen = MIN(BLEN(xp), chunk);
- memmove(nb->wptr, xp->rptr, blklen);
- nb->wptr += blklen;
- xp->rptr += blklen;
- chunk -= blklen;
- if(xp->rptr == xp->wptr)
- xp = xp->next;
- }
-
- feh->cksum[0] = 0;
- feh->cksum[1] = 0;
- hnputs(feh->cksum, ip_csum(&feh->vihl));
- nb->flags |= S_DELIM;
- PUTNEXT(Etherq, nb);
- }
-drop:
- freeb(bp);
-}
-
-
-/*
- * Input a packet and use the ip protocol to select the correct
- * device to pass it to.
- *
- */
-static void
-ipetheriput(Queue *q, Block *bp)
-{
- Ipifc *ifc, **ifp;
- Etherhdr *h;
- ushort frag;
-
- if(bp->type != M_DATA){
- PUTNEXT(q, bp);
- return;
- }
-
- h = (Etherhdr *)(bp->rptr);
-
- /* Ensure we have enough data to process */
- if(BLEN(bp) < (ETHER_HDR+ETHER_IPHDR)) {
- bp = pullup(bp, ETHER_HDR+ETHER_IPHDR);
- if(bp == 0)
- return;
- }
-
- /* Look to see if its for me before we waste time checksuming it */
- if(ipforme(h->dst) == 0)
- goto drop;
-
-
- if(ipcksum && ip_csum(&h->vihl)) {
- print("ip: checksum error (from %d.%d.%d.%d ?)\n",
- h->src[0], h->src[1], h->src[2], h->src[3]);
- goto drop;
- }
-
- /* Check header length and version */
- if(h->vihl != (IP_VER|IP_HLEN))
- goto drop;
-
- frag = nhgets(h->frag);
- if(frag) {
- h->tos = frag & IP_MF ? 1 : 0;
- bp = ip_reassemble(frag, bp, h);
- if(!bp)
- return;
- }
-
- /*
- * Look for an ip interface attached to this protocol
- */
- for(ifp = ipifc; ; ifp++){
- ifc = *ifp;
- if(ifc == 0)
- break;
- if(ifc->protocol == h->proto) {
- (*ifc->iprcv)(ifc, bp);
- return;
- }
- }
-
-drop:
- freeb(bp);
-}
-
-void
-ipsetaddrs(void)
-{
- Myip[Mybcast] = ~0; /* local broadcast */
- Myip[2] = 0; /* local broadcast - old */
- Myip[Mysubnet] = Myip[Myself] | ~Mynetmask; /* subnet broadcast */
- Myip[Mysubnet+1] = Myip[Myself] & Mynetmask; /* subnet broadcast - old */
- Myip[Mynet] = Myip[Myself] | ~Mymask; /* net broadcast */
- Myip[Mynet+1] = Myip[Myself] & Mymask; /* net broadcast - old */
-}
-
-int
-ipforme(uchar *addr)
-{
- Ipaddr haddr;
- Ipaddr *p;
-
- haddr = nhgetl(addr);
-
- /* try my address plus all the forms of ip broadcast */
- for(p = Myip; p < &Myip[7]; p++)
- if(haddr == *p);
- return 1;
-
- /* if we haven't set an address yet, accept anything we get */
- if(Myip[Myself] == 0)
- return 1;
-
- return 0;
-}
-
-typedef struct Fragstat Fragstat;
-struct Fragstat
-{
- ulong prev;
- ulong prevall;
- ulong succ;
- ulong succall;
-};
-Fragstat fragstat;
-
-Block *
-ip_reassemble(int offset, Block *bp, Etherhdr *ip)
-{
- Fragq *f;
- Ipaddr src, dst;
- ushort id;
- Block *bl, **l, *last, *prev;
- int ovlap, len, fragsize, pktposn;
- int end;
-
- /* Check ethrnet has handed us a contiguous buffer */
- if(bp->next)
- panic("ip: reass ?");
-
- src = nhgetl(ip->src);
- dst = nhgetl(ip->dst);
- id = nhgets(ip->id);
-
- /*
- * find a reassembly queue for this fragment
- */
- qlock(&fraglock);
- for(f = flisthead; f; f = f->next)
- if(f->src == src && f->dst == dst && f->id == id)
- break;
- qunlock(&fraglock);
-
- /*
- * if this isn't a fragmented packet, accept it
- * and get rid of any fragments that might go
- * with it.
- */
- if(!ip->tos && (offset & ~(IP_MF|IP_DF)) == 0) {
- if(f != 0) {
- qlock(f);
- ipfragfree(f, 1);
- }
- return bp;
- }
-
- BLKFRAG(bp)->foff = offset<<3;
- BLKFRAG(bp)->flen = nhgets(ip->length) - ETHER_IPHDR; /* Ip data length */
- bp->flags &= ~S_DELIM;
-
- /* First fragment allocates a reassembly queue */
- if(f == 0) {
- f = ipfragallo();
- qlock(f);
- f->id = id;
- f->src = src;
- f->dst = dst;
-
- f->blist = bp;
-
- qunlock(f);
- return 0;
- }
- qlock(f);
-
- /*
- * find the new fragment's position in the queue
- */
- prev = 0;
- l = &f->blist;
- for(bl = f->blist; bl && BLKFRAG(bp)->foff > BLKFRAG(bl)->foff; bl = bl->next) {
- prev = bl;
- l = &bl->next;
- }
-
- /* Check overlap of a previous fragment - trim away as necessary */
- if(prev) {
- ovlap = BLKFRAG(prev)->foff + BLKFRAG(prev)->flen - BLKFRAG(bp)->foff;
- if(ovlap > 0) {
- fragstat.prev++;
- if(ovlap >= BLKFRAG(bp)->flen) {
- fragstat.prevall++;
- freeb(bp);
- qunlock(f);
- return 0;
- }
- BLKFRAG(prev)->flen -= ovlap;
- }
- }
-
- /* Link onto assembly queue */
- bp->next = *l;
- *l = bp;
-
- /* Check to see if succeeding segments overlap */
- if(bp->next) {
- l = &bp->next;
- end = BLKFRAG(bp)->foff + BLKFRAG(bp)->flen;
- /* Take completely covered segements out */
- while(*l){
- ovlap = end - BLKFRAG(*l)->foff;
- if(ovlap <= 0)
- break;
- fragstat.succ++;
- if(ovlap < BLKFRAG(*l)->flen) {
- fragstat.succall++;
- BLKFRAG(*l)->flen -= ovlap;
- BLKFRAG(*l)->foff += ovlap;
- /* move up ether+ip hdrs */
- memmove((*l)->rptr + ovlap, (*l)->rptr,
- ETHER_HDR+ETHER_IPHDR);
- (*l)->rptr += ovlap;
- break;
- }
- last = (*l)->next;
- (*l)->next = 0;
- freeb(*l);
- *l = last;
- }
- }
-
- /*
- * look for a complete packet. if we get to a fragment
- * without IP_MF set, we're done.
- */
- pktposn = 0;
- for(bl = f->blist; bl; bl = bl->next) {
- if(BLKFRAG(bl)->foff != pktposn)
- break;
- if((BLKIP(bl)->frag[0]&(IP_MF>>8)) == 0)
- goto complete;
-
- pktposn += BLKFRAG(bl)->flen;
- }
- qunlock(f);
- return 0;
-
-complete:
- bl = f->blist;
- last = bl;
- len = nhgets(BLKIP(bl)->length);
- bl->wptr = bl->rptr + len + ETHER_HDR;
-
- /* Pullup all the fragment headers and return a complete packet */
- for(bl = bl->next; bl; bl = bl->next) {
- fragsize = BLKFRAG(bl)->flen;
- len += fragsize;
- bl->rptr += (ETHER_HDR+ETHER_IPHDR);
- bl->wptr = bl->rptr + fragsize;
- last = bl;
- }
-
- last->flags |= S_DELIM;
- bl = f->blist;
- f->blist = 0;
- ipfragfree(f, 1);
-
- ip = BLKIP(bl);
- hnputs(ip->length, len);
-
- return(bl);
-}
-
-/*
- * ipfragfree - Free a list of fragments, fragment list must be locked
- */
-
-void
-ipfragfree(Fragq *frag, int lockq)
-{
- Fragq *fl, **l;
-
- if(frag->blist)
- freeb(frag->blist);
-
- frag->src = 0;
- frag->id = 0;
- frag->blist = 0;
- qunlock(frag);
-
- if(lockq)
- qlock(&fraglock);
-
- l = &flisthead;
- for(fl = *l; fl; fl = fl->next) {
- if(fl == frag) {
- *l = frag->next;
- break;
- }
- l = &fl->next;
- }
-
- frag->next = fragfree;
- fragfree = frag;
-
- if(lockq)
- qunlock(&fraglock);
-}
-
-/*
- * ipfragallo - allocate a reassembly queue
- */
-Fragq *
-ipfragallo(void)
-{
- Fragq *f;
-
- qlock(&fraglock);
- while(fragfree == 0) {
- for(f = flisthead; f; f = f->next)
- if(canqlock(f)) {
- ipfragfree(f, 0);
- break;
- }
- }
- f = fragfree;
- fragfree = f->next;
- f->next = flisthead;
- flisthead = f;
- f->age = TK2MS(MACHP(0)->ticks) + 30000;
-
- qunlock(&fraglock);
- return f;
-}
-
-/*
- * ip_csum - Compute internet header checksums
- */
-ushort
-ip_csum(uchar *addr)
-{
- int len;
- ulong sum = 0;
-
- len = (addr[0]&0xf)<<2;
-
- while(len > 0) {
- sum += addr[0]<<8 | addr[1] ;
- len -= 2;
- addr += 2;
- }
-
- sum = (sum & 0xffff) + (sum >> 16);
- sum = (sum & 0xffff) + (sum >> 16);
- return (sum^0xffff);
-}
-
-/*
- * ipparse - Parse an ip address out of a string
- */
-
-Ipaddr classmask[4] = {
- 0xff000000,
- 0xff000000,
- 0xffff0000,
- 0xffffff00
-};
-
-Ipaddr
-ipparse(char *ipa)
-{
- Ipaddr address = 0;
- int shift;
- Ipaddr net;
-
- shift = 24;
-
- while(shift >= 0 && ipa != (char *)1) {
- address |= atoi(ipa) << shift;
- shift -= 8;
- ipa = strchr(ipa, '.')+1;
- }
- net = address & classmask[address>>30];
-
- shift += 8;
- return net | ((address & ~classmask[address>>30])>>shift);
-}
D port/streboot.c => port/streboot.c +0 -48
@@ 1,48 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-
-/*
- * reboot stream module definition
- */
-static void rebootopen(Queue*, Stream*);
-static void rebootiput(Queue*, Block*);
-static void rebootoput(Queue*, Block*);
-static void rebootreset(void);
-Qinfo rebootinfo =
-{
- rebootiput,
- rebootoput,
- rebootopen,
- 0,
- "reboot",
- 0
-};
-
-static void
-rebootopen(Queue *q, Stream *s)
-{
- USED(q);
- USED(s);
- if(strcmp(up->user, eve) != 0)
- error(Eperm);
-}
-
-void
-rebootoput(Queue *q, Block *bp)
-{
- PUTNEXT(q, bp);
-}
-
-static void
-rebootiput(Queue *q, Block *bp)
-{
- if(bp->type == M_HANGUP){
- print("lost connection to fs, rebooting");
- exit(0);
- }
- PUTNEXT(q, bp);
-}
D port/stsplice.c => port/stsplice.c +0 -80
@@ 1,80 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-#define splicedebug 1
-
-#define DPRINT if(splicedebug)kprint
-
-/*
- * Splice line discipline.
- */
-
-static void spliceopen(Queue*, Stream*);
-static void spliceclose(Queue*);
-static void spliceoput(Queue*, Block*);
-static void spliceiput(Queue*, Block*);
-Qinfo spliceinfo =
-{
- spliceiput,
- spliceoput,
- spliceopen,
- spliceclose,
- "splice"
-};
-
-static void
-spliceopen(Queue *q, Stream *s)
-{
- DPRINT("spliceopen q=0x%ux s=0x%ux\n", q, s);
-
- WR(q)->ptr = s; /* pointer to ourselves */
- RD(q)->ptr = 0; /* pointer to other side */
-}
-
-static void
-spliceclose(Queue *q)
-{
- DPRINT("spliceclose q=0x%ux us=0x%ux them=0x%ux\n",
- q, WR(q)->ptr, RD(q)->ptr);
-
- RD(q)->ptr = 0;
- WR(q)->ptr = 0;
-}
-
-static void
-spliceoput(Queue *q, Block *bp)
-{
- int fd;
- Chan *c;
- Stream *s;
-
- if(bp->type != M_CTL){
- PUTNEXT(q, bp);
- return;
- }
- fd = strtol((char *)bp->rptr, 0, 0);
- freeb(bp);
- if(RD(q)->ptr)
- error("stream already spliced");
- c = fdtochan(fd, ORDWR, 0, 0);
- s = c->stream;
- if(s == 0)
- error("splice attempt on non-stream");
- pushq(s, &spliceinfo);
- RD(q)->ptr = s;
- RD(s->procq->next)->ptr = WR(q)->ptr;
-}
-
-static void
-spliceiput(Queue *q, Block *bp)
-{
- if(bp->type == M_HANGUP)
- PUTNEXT(q, bp);
- else
- FLOWCTL(((Stream *)q->ptr)->procq, bp);
-}
D port/sturp.c => port/sturp.c +0 -1072
@@ 1,1072 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "io.h"
-#include "../port/error.h"
-
-enum {
- MSrexmit= 1000,
- Nmask= 0x7,
-};
-
-#define DPRINT if(q->flag&QDEBUG)kprint
-
-typedef struct Urp Urp;
-
-#define NOW (MACHP(0)->ticks*MS2HZ)
-
-/*
- * URP status
- */
-struct urpstat {
- ulong input; /* bytes read from urp */
- ulong output; /* bytes output to urp */
- ulong rexmit; /* retransmit rejected urp msg */
- ulong rjtrs; /* reject, trailer size */
- ulong rjpks; /* reject, packet size */
- ulong rjseq; /* reject, sequence number */
- ulong levelb; /* unknown level b */
- ulong enqsx; /* enqs sent */
- ulong enqsr; /* enqs rcved */
-} urpstat;
-
-struct Urp {
- QLock;
- Urp *list; /* list of all urp structures */
- short state; /* flags */
- Rendez r; /* process waiting for output to finish */
-
- /* input */
- QLock ack; /* ack lock */
- Queue *rq; /* input queue */
- uchar iseq; /* last good input sequence number */
- uchar lastecho; /* last echo/rej sent */
- uchar trbuf[3]; /* trailer being collected */
- short trx; /* # bytes in trailer being collected */
- int blocks;
-
- /* output */
- QLock xmit; /* output lock, only one process at a time */
- Queue *wq; /* output queue */
- int maxout; /* maximum outstanding unacked blocks */
- int maxblock; /* max block size */
- int next; /* next block to send */
- int unechoed; /* first unechoed block */
- int unacked; /* first unacked block */
- int nxb; /* next xb to use */
- Block *xb[8]; /* the xmit window buffer */
- QLock xl[8];
- ulong timer; /* timeout for xmit */
- int rexmit;
-};
-
-/* list of allocated urp structures (never freed) */
-struct
-{
- Lock;
- Urp *urp;
-} urpalloc;
-
-Rendez urpkr;
-QLock urpkl;
-int urpkstarted;
-
-#define WINDOW(u) ((u)->unechoed>(u)->next ? (u)->unechoed+(u)->maxout-(u)->next-8 :\
- (u)->unechoed+(u)->maxout-(u)->next)
-#define IN(x, f, n) (f<=n ? (x>=f && x<n) : (x<n || x>=f))
-#define NEXT(x) (((x)+1)&Nmask)
-
-/*
- * Protocol control bytes
- */
-#define SEQ 0010 /* sequence number, ends trailers */
-#undef ECHO
-#define ECHO 0020 /* echos, data given to next queue */
-#define REJ 0030 /* rejections, transmission error */
-#define ACK 0040 /* acknowledgments */
-#define BOT 0050 /* beginning of trailer */
-#define BOTM 0051 /* beginning of trailer, more data follows */
-#define BOTS 0052 /* seq update algorithm on this trailer */
-#define SOU 0053 /* start of unsequenced trailer */
-#define EOU 0054 /* end of unsequenced trailer */
-#define ENQ 0055 /* xmitter requests flow/error status */
-#define CHECK 0056 /* xmitter requests error status */
-#define INITREQ 0057 /* request initialization */
-#define INIT0 0060 /* disable trailer processing */
-#define INIT1 0061 /* enable trailer procesing */
-#define AINIT 0062 /* response to INIT0/INIT1 */
-#undef DELAY
-#define DELAY 0100 /* real-time printing delay */
-#define BREAK 0110 /* Send/receive break (new style) */
-
-#define REJECTING 0x1
-#define INITING 0x2
-#define HUNGUP 0x4
-#define OPEN 0x8
-#define CLOSING 0x10
-
-/*
- * predeclared
- */
-static void urpreset(void);
-static void urpciput(Queue*, Block*);
-static void urpiput(Queue*, Block*);
-static void urpoput(Queue*, Block*);
-static void urpopen(Queue*, Stream*);
-static void urpclose(Queue *);
-static void output(Urp*);
-static void sendblock(Urp*, int);
-static void rcvack(Urp*, int);
-static void flushinput(Urp*);
-static void sendctl(Urp*, int);
-static void sendack(Urp*);
-static void sendrej(Urp*);
-static void initoutput(Urp*, int);
-static void initinput(Urp*);
-static void urpkproc(void *arg);
-static void urpvomit(char*, Urp*);
-static void tryoutput(Urp*);
-
-Qinfo urpinfo =
-{
- urpciput,
- urpoput,
- urpopen,
- urpclose,
- "urp",
- urpreset
-};
-
-static void
-urpreset(void)
-{
-}
-
-static void
-urpopen(Queue *q, Stream *s)
-{
- Urp *urp;
-
- USED(s);
- if(!urpkstarted){
- qlock(&urpkl);
- if(!urpkstarted){
- urpkstarted = 1;
- kproc("urpkproc", urpkproc, 0);
- }
- qunlock(&urpkl);
- }
-
- /*
- * find an unused urp structure
- */
- for(urp = urpalloc.urp; urp; urp = urp->list){
- if(urp->state == 0){
- qlock(urp);
- if(urp->state == 0)
- break;
- qunlock(urp);
- }
- }
- if(urp == 0){
- /*
- * none available, create a new one, they are never freed
- */
- urp = smalloc(sizeof(Urp));
- qlock(urp);
- lock(&urpalloc);
- urp->list = urpalloc.urp;
- urpalloc.urp = urp;
- unlock(&urpalloc);
- }
- q->ptr = q->other->ptr = urp;
- q->rp = &urpkr;
- urp->rq = q;
- urp->wq = q->other;
- urp->state = OPEN;
- qunlock(urp);
- initinput(urp);
- initoutput(urp, 0);
-}
-
-/*
- * Shut down the connection and kill off the kernel process
- */
-static int
-isflushed(void *a)
-{
- Urp *urp;
-
- urp = (Urp *)a;
- return (urp->state&HUNGUP) || (urp->unechoed==urp->nxb && urp->wq->len==0);
-}
-static void
-urpclose(Queue *q)
-{
- Urp *urp;
- int i;
-
- urp = (Urp *)q->ptr;
- if(urp == 0)
- return;
-
- /*
- * wait for all outstanding messages to drain, tell kernel
- * process we're closing.
- *
- * if 2 minutes elapse, give it up
- */
- urp->state |= CLOSING;
- if(!waserror()){
- tsleep(&urp->r, isflushed, urp, 2*60*1000);
- poperror();
- }
- urp->state |= HUNGUP;
-
- qlock(&urp->xmit);
- /*
- * ack all outstanding messages
- */
- i = urp->next - 1;
- if(i < 0)
- i = 7;
- rcvack(urp, ECHO+i);
-
- /*
- * free all staged but unsent messages
- */
- for(i = 0; i < 7; i++)
- if(urp->xb[i]){
- freeb(urp->xb[i]);
- urp->xb[i] = 0;
- }
- qunlock(&urp->xmit);
-
- qlock(urp);
- urp->state = 0;
- qunlock(urp);
-}
-
-/*
- * upstream control messages
- */
-static void
-urpctliput(Urp *urp, Queue *q, Block *bp)
-{
- switch(bp->type){
- case M_HANGUP:
- urp->state |= HUNGUP;
- wakeup(&urp->r);
- break;
- }
- PUTNEXT(q, bp);
-}
-
-/*
- * character mode input.
- *
- * the first byte in every message is a ctl byte (which belongs at the end).
- */
-void
-urpciput(Queue *q, Block *bp)
-{
- Urp *urp;
- int i;
- int ctl;
-
- urp = (Urp *)q->ptr;
- if(urp == 0)
- return;
- if(bp->type != M_DATA){
- urpctliput(urp, q, bp);
- return;
- }
-
- /*
- * get the control character
- */
- ctl = *bp->rptr++;
- if(ctl < 0)
- return;
-
- /*
- * take care of any data
- */
- if(BLEN(bp)>0 && q->next->len<2*Streamhi && q->next->nb<2*Streambhi){
- bp->flags |= S_DELIM;
- urpstat.input += BLEN(bp);
- PUTNEXT(q, bp);
- } else
- freeb(bp);
-
- /*
- * handle the control character
- */
- switch(ctl){
- case 0:
- break;
- case ENQ:
- DPRINT("rENQ(c)\n");
- urpstat.enqsr++;
- sendctl(urp, urp->lastecho);
- sendctl(urp, ACK+urp->iseq);
- break;
-
- case CHECK:
- DPRINT("rCHECK(c)\n");
- sendctl(urp, ACK+urp->iseq);
- break;
-
- case AINIT:
- DPRINT("rAINIT(c)\n");
- urp->state &= ~INITING;
- flushinput(urp);
- tryoutput(urp);
- break;
-
- case INIT0:
- case INIT1:
- DPRINT("rINIT%d(c)\n", ctl-INIT0);
- sendctl(urp, AINIT);
- if(ctl == INIT1)
- q->put = urpiput;
- initinput(urp);
- break;
-
- case INITREQ:
- DPRINT("rINITREQ(c)\n");
- initoutput(urp, 0);
- break;
-
- case BREAK:
- break;
-
- case REJ+0: case REJ+1: case REJ+2: case REJ+3:
- case REJ+4: case REJ+5: case REJ+6: case REJ+7:
- DPRINT("rREJ%d(c)\n", ctl-REJ);
- rcvack(urp, ctl);
- break;
-
- case ACK+0: case ACK+1: case ACK+2: case ACK+3:
- case ACK+4: case ACK+5: case ACK+6: case ACK+7:
- case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3:
- case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7:
- DPRINT("%s%d(c)\n", (ctl&ECHO)?"rECHO":"rACK", ctl&7);
- rcvack(urp, ctl);
- break;
-
- case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3:
- case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7:
- DPRINT("rSEQ%d(c)\n", ctl-SEQ);
- qlock(&urp->ack);
- i = ctl & Nmask;
- if(!QFULL(q->next))
- sendctl(urp, urp->lastecho = ECHO+i);
- urp->iseq = i;
- qunlock(&urp->ack);
- break;
- }
-}
-
-/*
- * block mode input.
- *
- * the first byte in every message is a ctl byte (which belongs at the end).
- *
- * Simplifying assumption: one put == one message && the control byte
- * is in the first block. If this isn't true, strange bytes will be
- * used as control bytes.
- *
- * There's no input lock. The channel could be closed while we're
- * processing a message.
- */
-void
-urpiput(Queue *q, Block *bp)
-{
- Urp *urp;
- int i, len;
- int ctl;
-
- urp = (Urp *)q->ptr;
- if(urp == 0)
- return;
- if(bp->type != M_DATA){
- urpctliput(urp, q, bp);
- return;
- }
-
- /*
- * get the control character
- */
- ctl = *bp->rptr++;
-
- /*
- * take care of any block count(trx)
- */
- while(urp->trx){
- if(BLEN(bp)<=0)
- break;
- switch (urp->trx) {
- case 1:
- case 2:
- urp->trbuf[urp->trx++] = *bp->rptr++;
- continue;
- default:
- urp->trx = 0;
- break;
- }
- }
-
- /*
- * queue the block(s)
- */
- if(BLEN(bp) > 0){
- bp->flags &= ~S_DELIM;
- putq(q, bp);
- if(q->len > 4*1024){
- flushinput(urp);
- return;
- }
- } else
- freeb(bp);
-
- /*
- * handle the control character
- */
- switch(ctl){
- case 0:
- break;
- case ENQ:
- DPRINT("rENQ %d %uo %uo\n", urp->blocks, urp->lastecho, ACK+urp->iseq);
- urp->blocks = 0;
- urpstat.enqsr++;
- sendctl(urp, urp->lastecho);
- sendctl(urp, ACK+urp->iseq);
- flushinput(urp);
- break;
-
- case CHECK:
- DPRINT("rCHECK\n");
- sendctl(urp, ACK+urp->iseq);
- break;
-
- case AINIT:
- DPRINT("rAINIT\n");
- urp->state &= ~INITING;
- flushinput(urp);
- tryoutput(urp);
- break;
-
- case INIT0:
- case INIT1:
- DPRINT("rINIT%d\n", ctl-INIT0);
- sendctl(urp, AINIT);
- if(ctl == INIT0)
- q->put = urpciput;
- initinput(urp);
- break;
-
- case INITREQ:
- DPRINT("rINITREQ\n");
- initoutput(urp, 0);
- break;
-
- case BREAK:
- break;
-
- case BOT:
- case BOTM:
- case BOTS:
- DPRINT("rBOT%c...", " MS"[ctl-BOT]);
- urp->trx = 1;
- urp->trbuf[0] = ctl;
- break;
-
- case REJ+0: case REJ+1: case REJ+2: case REJ+3:
- case REJ+4: case REJ+5: case REJ+6: case REJ+7:
- DPRINT("rREJ%d\n", ctl-REJ);
- rcvack(urp, ctl);
- break;
-
- case ACK+0: case ACK+1: case ACK+2: case ACK+3:
- case ACK+4: case ACK+5: case ACK+6: case ACK+7:
- case ECHO+0: case ECHO+1: case ECHO+2: case ECHO+3:
- case ECHO+4: case ECHO+5: case ECHO+6: case ECHO+7:
- DPRINT("%s%d\n", (ctl&ECHO)?"rECHO":"rACK", ctl&7);
- rcvack(urp, ctl);
- break;
-
- /*
- * if the sequence number is the next expected
- * and the trailer length == 3
- * and the block count matches the bytes received
- * then send the bytes upstream.
- */
- case SEQ+0: case SEQ+1: case SEQ+2: case SEQ+3:
- case SEQ+4: case SEQ+5: case SEQ+6: case SEQ+7:
- len = urp->trbuf[1] + (urp->trbuf[2]<<8);
- DPRINT("rSEQ%d(%d,%d,%d)...", ctl-SEQ, urp->trx, len, q->len);
- i = ctl & Nmask;
- if(urp->trx != 3){
- urpstat.rjtrs++;
- sendrej(urp);
- break;
- }else if(q->len != len){
- urpstat.rjpks++;
- sendrej(urp);
- break;
- }else if(i != ((urp->iseq+1)&Nmask)){
- urpstat.rjseq++;
- sendrej(urp);
- break;
- }else if(q->next->len > (3*Streamhi)/2
- || q->next->nb > (3*Streambhi)/2){
- DPRINT("next->len=%d, next->nb=%d\n",
- q->next->len, q->next->nb);
- flushinput(urp);
- break;
- }
- DPRINT("accept %d\n", q->len);
-
- /*
- * send data upstream
- */
- if(q->first) {
- if(urp->trbuf[0] != BOTM)
- q->last->flags |= S_DELIM;
- while(bp = getq(q)){
- urpstat.input += BLEN(bp);
- PUTNEXT(q, bp);
- }
- } else {
- bp = allocb(0);
- if(urp->trbuf[0] != BOTM)
- bp->flags |= S_DELIM;
- PUTNEXT(q, bp);
- }
- urp->trx = 0;
-
- /*
- * acknowledge receipt
- */
- qlock(&urp->ack);
- urp->iseq = i;
- if(!QFULL(q->next))
- sendctl(urp, urp->lastecho = ECHO|i);
- qunlock(&urp->ack);
- break;
- }
-}
-
-/*
- * downstream control
- */
-static void
-urpctloput(Urp *urp, Queue *q, Block *bp)
-{
- char *fields[2];
- int outwin;
-
- switch(bp->type){
- case M_CTL:
- if(streamparse("break", bp)){
- /*
- * send a break as part of the data stream
- */
- urpstat.output++;
- bp->wptr = bp->lim;
- bp->rptr = bp->wptr - 1;
- *bp->rptr = BREAK;
- putq(q, bp);
- output(urp);
- return;
- }
- if(streamparse("init", bp)){
- outwin = strtoul((char*)bp->rptr, 0, 0);
- initoutput(urp, outwin);
- freeb(bp);
- return;
- }
- if(streamparse("debug", bp)){
- switch(getfields((char *)bp->rptr, fields, 2, ' ')){
- case 1:
- if (strcmp(fields[0], "on") == 0) {
- q->flag |= QDEBUG;
- q->other->flag |= QDEBUG;
- }
- if (strcmp(fields[0], "off") == 0) {
- q->flag &= ~QDEBUG;
- q->other->flag &= ~QDEBUG;
- }
- }
- freeb(bp);
- return;
- }
- }
- PUTNEXT(q, bp);
-}
-
-/*
- * accept data from a writer
- */
-static void
-urpoput(Queue *q, Block *bp)
-{
- Urp *urp;
-
- urp = (Urp *)q->ptr;
-
- if(bp->type != M_DATA){
- urpctloput(urp, q, bp);
- return;
- }
-
- urpstat.output += BLEN(bp);
- putq(q, bp);
- output(urp);
-}
-
-/*
- * start output
- */
-static void
-output(Urp *urp)
-{
- Block *bp, *nbp;
- ulong now;
- Queue *q;
- int i;
-
- if(!canqlock(&urp->xmit))
- return;
-
- if(waserror()){
- print("urp output error\n");
- qunlock(&urp->xmit);
- nexterror();
- }
-
- /*
- * if still initing and it's time to rexmit, send an INIT1
- */
- now = NOW;
- if(urp->state & INITING){
- if(now > urp->timer){
- q = urp->wq;
- DPRINT("INITING timer (%d, %d): ", now, urp->timer);
- sendctl(urp, INIT1);
- urp->timer = now + MSrexmit;
- }
- goto out;
- }
-
- /*
- * fill the transmit buffers, `nxb' can never overtake `unechoed'
- */
- q = urp->wq;
- i = NEXT(urp->nxb);
- if(i != urp->unechoed) {
- for(bp = getq(q); bp && i!=urp->unechoed; i = NEXT(i)){
- if(urp->xb[urp->nxb] != 0)
- urpvomit("output", urp);
- if(BLEN(bp) > urp->maxblock){
- nbp = urp->xb[urp->nxb] = allocb(0);
- nbp->rptr = bp->rptr;
- nbp->wptr = bp->rptr = bp->rptr + urp->maxblock;
- } else {
- urp->xb[urp->nxb] = bp;
- bp = getq(q);
- }
- urp->nxb = i;
- }
- if(bp)
- putbq(q, bp);
- }
-
- /*
- * retransmit cruft
- */
- if(urp->rexmit){
- /*
- * if a retransmit is requested, move next back to
- * the unacked blocks
- */
- urpstat.rexmit++;
- urp->rexmit = 0;
- urp->next = urp->unacked;
- } else if(urp->unechoed!=urp->next && NOW>urp->timer){
- /*
- * if a retransmit time has elapsed since a transmit,
- * send an ENQ
- */
- DPRINT("OUTPUT timer (%d, %d): ", NOW, urp->timer);
- urp->timer = NOW + MSrexmit;
- urp->state &= ~REJECTING;
- urpstat.enqsx++;
- sendctl(urp, ENQ);
- goto out;
- }
-
- /*
- * if there's a window open, push some blocks out
- *
- * the lock is to synchronize with acknowledges that free
- * blocks.
- */
- while(WINDOW(urp)>0 && urp->next!=urp->nxb){
- i = urp->next;
- qlock(&urp->xl[i]);
- if(waserror()){
- qunlock(&urp->xl[i]);
- nexterror();
- }
- sendblock(urp, i);
- qunlock(&urp->xl[i]);
- urp->next = NEXT(urp->next);
- poperror();
- }
-out:
- qunlock(&urp->xmit);
- poperror();
-}
-
-/*
- * try output, this is called by an input process
- */
-void
-tryoutput(Urp *urp)
-{
- if(!waserror()){
- output(urp);
- poperror();
- }
-}
-
-/*
- * send a control byte, put the byte at the end of the allocated
- * space in case a lower layer needs header room.
- */
-static void
-sendctl(Urp *urp, int ctl)
-{
- Block *bp;
- Queue *q;
-
- q = urp->wq;
- if(QFULL(q->next))
- return;
- bp = allocb(1);
- bp->wptr = bp->lim;
- bp->rptr = bp->lim-1;
- *bp->rptr = ctl;
- bp->flags |= S_DELIM;
- DPRINT("sCTL %ulx\n", ctl);
- PUTNEXT(q, bp);
-}
-
-/*
- * send a reject
- */
-static void
-sendrej(Urp *urp)
-{
- Queue *q = urp->wq;
- flushinput(urp);
- qlock(&urp->ack);
- if((urp->lastecho&~Nmask) == ECHO){
- DPRINT("REJ %d\n", urp->iseq);
- sendctl(urp, urp->lastecho = REJ|urp->iseq);
- }
- qunlock(&urp->ack);
-}
-
-/*
- * send an acknowledge
- */
-static void
-sendack(Urp *urp)
-{
- /*
- * check the precondition for acking
- */
- if(QFULL(urp->rq->next) || (urp->lastecho&Nmask)==urp->iseq)
- return;
-
- if(!canqlock(&urp->ack))
- return;
-
- /*
- * check again now that we've locked
- */
- if(QFULL(urp->rq->next) || (urp->lastecho&Nmask)==urp->iseq){
- qunlock(&urp->ack);
- return;
- }
-
- /*
- * send the ack
- */
- { Queue *q = urp->wq; DPRINT("sendack: "); }
- sendctl(urp, urp->lastecho = ECHO|urp->iseq);
- qunlock(&urp->ack);
-}
-
-/*
- * send a block.
- */
-static void
-sendblock(Urp *urp, int bn)
-{
- int n;
- Queue *q;
- Block *bp, *m, *nbp;
-
- q = urp->wq;
- urp->timer = NOW + MSrexmit;
- if(QFULL(q->next))
- return;
-
- /*
- * message 1, the BOT and the data
- */
- bp = urp->xb[bn];
- if(bp == 0)
- return;
- m = allocb(1);
- m->rptr = m->lim - 1;
- m->wptr = m->lim;
- *m->rptr = (bp->flags & S_DELIM) ? BOT : BOTM;
- nbp = allocb(0);
- nbp->rptr = bp->rptr;
- nbp->wptr = bp->wptr;
- nbp->base = bp->base;
- nbp->lim = bp->lim;
- nbp->flags |= S_DELIM;
- if(bp->type == M_CTL){
- PUTNEXT(q, nbp);
- m->flags |= S_DELIM;
- PUTNEXT(q, m);
- } else {
- m->next = nbp;
- PUTNEXT(q, m);
- }
-
- /*
- * message 2, the block length and the SEQ
- */
- m = allocb(3);
- m->rptr = m->lim - 3;
- m->wptr = m->lim;
- n = BLEN(bp);
- m->rptr[0] = SEQ | bn;
- m->rptr[1] = n;
- m->rptr[2] = n<<8;
- m->flags |= S_DELIM;
- PUTNEXT(q, m);
- DPRINT("sb %d (%d)\n", bn, urp->timer);
-}
-
-/*
- * receive an acknowledgement
- */
-static void
-rcvack(Urp *urp, int msg)
-{
- int seqno;
- int next;
- int i;
-
- seqno = msg&Nmask;
- next = NEXT(seqno);
-
- /*
- * release any acknowledged blocks
- */
- if(IN(seqno, urp->unacked, urp->next)){
- for(; urp->unacked != next; urp->unacked = NEXT(urp->unacked)){
- i = urp->unacked;
- qlock(&urp->xl[i]);
- if(urp->xb[i])
- freeb(urp->xb[i]);
- else
- urpvomit("rcvack", urp);
- urp->xb[i] = 0;
- qunlock(&urp->xl[i]);
- }
- }
-
- switch(msg & 0370){
- case ECHO:
- if(IN(seqno, urp->unechoed, urp->next)) {
- urp->unechoed = next;
- }
- /*
- * the next reject at the start of a window starts a
- * retransmission.
- */
- urp->state &= ~REJECTING;
- break;
- case REJ:
- if(IN(seqno, urp->unechoed, urp->next))
- urp->unechoed = next;
- /*
- * ... FALL THROUGH ...
- */
- case ACK:
- /*
- * start a retransmission if we aren't retransmitting
- * and this is the start of a window.
- */
- if(urp->unechoed==next && !(urp->state & REJECTING)){
- urp->state |= REJECTING;
- urp->rexmit = 1;
- }
- break;
- }
-
- tryoutput(urp);
- if(urp->state & CLOSING)
- wakeup(&urp->r);
-}
-
-/*
- * throw away any partially collected input
- */
-static void
-flushinput(Urp *urp)
-{
- Block *bp;
-
- while (bp = getq(urp->rq))
- freeb(bp);
- urp->trx = 0;
-}
-
-/*
- * initialize output
- */
-static void
-initoutput(Urp *urp, int window)
-{
- int i;
-
- /*
- * set output window
- */
- urp->maxblock = window/4;
- if(urp->maxblock < 64)
- urp->maxblock = 64;
- urp->maxblock -= 4;
- urp->maxout = 4;
-
- /*
- * set sequence varialbles
- */
- urp->unechoed = 1;
- urp->unacked = 1;
- urp->next = 1;
- urp->nxb = 1;
- urp->rexmit = 0;
-
- /*
- * free any outstanding blocks
- */
- for(i = 0; i < 8; i++){
- qlock(&urp->xl[i]);
- if(urp->xb[i])
- freeb(urp->xb[i]);
- urp->xb[i] = 0;
- qunlock(&urp->xl[i]);
- }
-
- /*
- * tell the other side we've inited
- */
- urp->state |= INITING;
- urp->timer = NOW + MSrexmit;
- { Queue *q = urp->wq; DPRINT("initoutput (%d): ", urp->timer); }
- sendctl(urp, INIT1);
-}
-
-/*
- * initialize input
- */
-static void
-initinput(Urp *urp)
-{
- /*
- * restart all sequence parameters
- */
- urp->blocks = 0;
- urp->trx = 0;
- urp->iseq = 0;
- urp->lastecho = ECHO+0;
- flushinput(urp);
-}
-
-static void
-urpkproc(void *arg)
-{
- Urp *urp;
-
- USED(arg);
-
- if(waserror())
- ;
-
- for(;;){
- for(urp = urpalloc.urp; urp; urp = urp->list){
- if(urp->state==0 || (urp->state&HUNGUP))
- continue;
- if(!canqlock(urp))
- continue;
- if(waserror()){
- qunlock(urp);
- continue;
- }
- if(urp->state==0 || (urp->state&HUNGUP)){
- qunlock(urp);
- poperror();
- continue;
- }
- if(urp->iseq!=(urp->lastecho&7) && !QFULL(urp->rq->next))
- sendack(urp);
- output(urp);
- qunlock(urp);
- poperror();
- }
- tsleep(&urpkr, return0, 0, 500);
- }
-}
-
-/*
- * urp got very confused, complain
- */
-static void
-urpvomit(char *msg, Urp* urp)
-{
- print("urpvomit: %s %ux next %d unechoed %d unacked %d nxb %d\n",
- msg, urp, urp->next, urp->unechoed, urp->unacked, urp->nxb);
- print("\txb: %ux %ux %ux %ux %ux %ux %ux %ux\n",
- urp->xb[0], urp->xb[1], urp->xb[2], urp->xb[3], urp->xb[4],
- urp->xb[5], urp->xb[6], urp->xb[7]);
- print("\tiseq: %uo lastecho: %uo trx: %d trbuf: %uo %uo %uo\n",
- urp->iseq, urp->lastecho, urp->trx, urp->trbuf[0], urp->trbuf[1],
- urp->trbuf[2]);
- print("\tupq: %ux %d %d\n", &urp->rq->next->r, urp->rq->next->nb,
- urp->rq->next->len);
-}
-
-void
-urpfillstats(Chan *c, char *buf, int len)
-{
- char b[256];
-
- USED(c);
- sprint(b, "in: %d\nout: %d\nrexmit: %d\nrjtrs: %d\nrjpks: %d\nrjseq: %d\nenqsx: %d\nenqsr: %d\n",
- urpstat.input, urpstat.output, urpstat.rexmit, urpstat.rjtrs,
- urpstat.rjpks, urpstat.rjseq, urpstat.enqsx, urpstat.enqsr);
- strncpy(buf, b, len);
-}
D port/tcpif.c => port/tcpif.c +0 -108
@@ 1,108 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "arp.h"
-#include "ipdat.h"
-
-extern int tcpdbg;
-#define DPRINT if(tcpdbg) print
-
-void
-tcpxstate(Ipconv *s, char oldstate, char newstate)
-{
- int len;
- Block *bp;
- Tcpctl *tcb;
-
- if(oldstate == newstate)
- return;
-
- tcb = &s->tcpctl;
- switch(newstate) {
- case Closed:
- s->psrc = 0; /* This connection is toast */
- s->pdst = 0;
- s->dst = 0;
-
- case Close_wait: /* Remote closes */
- if(s->err) {
- len = strlen(s->err);
- bp = allocb(len);
- strcpy((char *)bp->wptr, s->err);
- bp->wptr += len;
- }
- else
- bp = allocb(0);
-
- bp->flags |= S_DELIM;
- bp->type = M_HANGUP;
- qlock(s);
- if(waserror()) {
- qunlock(s);
- nexterror();
- }
- if(s->readq == 0) {
- if(newstate == Close_wait)
- putb(&tcb->rcvq, bp);
- else
- freeb(bp);
- } else
- PUTNEXT(s->readq, bp);
- poperror();
- qunlock(s);
- break;
- }
-
- if(oldstate == Syn_sent)
- wakeup(&tcb->syner);
-}
-
-static int
-notsyner(void *ic)
-{
- return ((Tcpctl*)ic)->state != Syn_sent;
-}
-
-void
-tcpstart(Ipconv *s, int mode, ushort window, char tos)
-{
- Tcpctl *tcb;
-
- tcb = &s->tcpctl;
- if(tcb->state != Closed)
- return;
-
- init_tcpctl(s);
-
- tcb->window = window;
- tcb->rcv.wnd = window;
- tcb->tos = tos;
-
- switch(mode){
- case TCP_PASSIVE:
- tcb->flags |= CLONE;
- tcpsetstate(s, Listen);
- break;
-
- case TCP_ACTIVE:
- /* Send SYN, go into SYN_SENT state */
- tcb->flags |= ACTIVE;
- qlock(tcb);
- if(waserror()) {
- qunlock(tcb);
- nexterror();
- }
- tcpsndsyn(tcb);
- tcpsetstate(s, Syn_sent);
- tcpoutput(s);
- poperror();
- qunlock(tcb);
- tsleep(&tcb->syner, notsyner, tcb, 120*1000);
- if(tcb->state != Established && tcb->state != Syn_received)
- error(Etimedout);
- break;
- }
-}
D port/tcpinput.c => port/tcpinput.c +0 -1026
@@ 1,1026 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "arp.h"
-#include "ipdat.h"
-
-int tcpdbg = 0;
-ushort tcp_mss = DEF_MSS; /* Maximum segment size to be sent with SYN */
-int tcp_irtt = DEF_RTT; /* Initial guess at round trip time */
-
-#define DPRINT if(tcpdbg) print
-#define LPRINT if(tcpdbg) print
-
-char *tcpstate[] =
-{
- "Closed", "Listen", "Syn_sent", "Syn_received",
- "Established", "Finwait1", "Finwait2", "Close_wait",
- "Closing", "Last_ack", "Time_wait"
-};
-
-void
-sndrst(Ipaddr source, Ipaddr dest, ushort length, Tcp *seg)
-{
- Block *hbp;
- Port tmp;
- char rflags;
- Tcphdr ph;
-
- if(seg->flags & RST)
- return;
-
- hnputl(ph.tcpsrc, dest);
- hnputl(ph.tcpdst, source);
- ph.proto = IP_TCPPROTO;
- hnputs(ph.tcplen, TCP_HDRSIZE);
-
- /* Swap port numbers */
- tmp = seg->dest;
- seg->dest = seg->source;
- seg->source = tmp;
-
- rflags = RST;
-
- /* convince the other end that this reset is in band */
- if(seg->flags & ACK) {
- seg->seq = seg->ack;
- seg->ack = 0;
- }
- else {
- rflags |= ACK;
- seg->ack = seg->seq;
- seg->seq = 0;
- if(seg->flags & SYN)
- seg->ack++;
- seg->ack += length;
- if(seg->flags & FIN)
- seg->ack++;
- }
- seg->flags = rflags;
- seg->wnd = 0;
- seg->up = 0;
- seg->mss = 0;
- if((hbp = htontcp(seg, 0, &ph)) == 0)
- return;
-
- PUTNEXT(Ipoutput, hbp);
-}
-
-/*
- * flush an incoming call; send a reset to the remote side and close the
- * conversation
- */
-void
-tcpflushincoming(Ipconv *s)
-{
- Tcp seg;
- Tcpctl *tcb;
-
- tcb = &s->tcpctl;
- seg.source = s->pdst;
- seg.dest = s->psrc;
- seg.flags = ACK;
- seg.seq = tcb->snd.ptr;
- seg.ack = tcb->last_ack = tcb->rcv.nxt;
-
- sndrst(s->dst, Myip[Myself], 0, &seg);
- localclose(s, 0);
-}
-
-static void
-tcpmove(struct Tctl *to, struct Tctl *from)
-{
- memmove(to, from, sizeof(struct Tctl));
-}
-
-Ipconv*
-tcpincoming(Ipifc *ifc, Ipconv *s, Tcp *segp, Ipaddr source)
-{
- Ipconv *new;
-
- qlock(s);
- if(s->curlog >= s->backlog){
- qunlock(s);
- return 0;
- }
-
- new = ipincoming(ifc, s);
- if(new == 0){
- qunlock(s);
- return 0;
- }
-
- s->curlog++;
- qunlock(s);
- new->psrc = segp->dest;
- new->pdst = segp->source;
- new->dst = source;
- tcpmove(&new->tcpctl, &s->tcpctl);
- new->tcpctl.flags &= ~CLONE;
- new->tcpctl.timer.arg = new;
- new->tcpctl.timer.state = TimerOFF;
- new->tcpctl.acktimer.arg = new;
- new->tcpctl.acktimer.state = TimerOFF;
- new->newcon = s;
-
- wakeup(&s->listenr);
- return new;
-}
-
-void
-tcpinput(Ipifc *ifc, Block *bp)
-{
- Tcp seg;
- char tos;
- Tcphdr *h;
- int hdrlen;
- Tcpctl *tcb;
- ushort length;
- Ipconv *spec, *gen;
- Ipaddr source, dest;
- Ipconv *s, **p, **etab;
-
- h = (Tcphdr *)(bp->rptr);
- dest = nhgetl(h->tcpdst);
- source = nhgetl(h->tcpsrc);
-
- tos = h->tos;
- length = nhgets(h->length);
-
- h->Unused = 0;
- hnputs(h->tcplen, length - (TCP_IPLEN+TCP_PHDRSIZE));
- if(ptcl_csum(bp, TCP_EHSIZE+TCP_IPLEN, length - TCP_IPLEN)) {
- freeb(bp);
- return;
- }
-
- if((hdrlen = ntohtcp(&seg, &bp)) < 0)
- return;
-
- /* trim the packet to the size claimed by the datagram */
- length -= (hdrlen+TCP_IPLEN+TCP_PHDRSIZE);
- bp = btrim(bp, hdrlen+TCP_PKT, length);
- if(bp == 0)
- return;
-
- /* Look for a connection. failing that look for a listener. */
- s = ip_conn(ifc, seg.dest, seg.source, source);
- if (s == 0) {
- if(seg.flags & SYN){
- /*
- * find a listener specific to this port (spec) or,
- * failing that, a general one (gen)
- */
- spec = 0;
- gen = 0;
- etab = &ifc->conv[Nipconv];
- for(p = ifc->conv; p < etab && *p; p++) {
- s = *p;
- if(s->tcpctl.state == Listen)
- if(s->pdst == 0)
- if(s->dst == 0) {
- if(s->psrc == seg.dest){
- spec = s;
- break;
- }
- if(s->psrc == 0)
- gen = s;
- }
- }
- if(spec)
- s = tcpincoming(ifc, spec, &seg, source);
- else if(gen)
- s = tcpincoming(ifc, gen, &seg, source);
- else
- s = 0;
- }
- if(s == 0){
- freeb(bp);
- sndrst(source, dest, length, &seg);
- return;
- }
- }
-
- /* The rest of the input state machine is run with the control block
- * locked and implements the state machine directly out of the RFC
- * Out-of-band data is ignored - it was always a bad idea.
- */
- tcb = &s->tcpctl;
- qlock(tcb);
-
- switch(tcb->state) {
- case Closed:
- freeb(bp);
- sndrst(source, dest, length, &seg);
- goto done;
- case Listen:
- if(seg.flags & RST) {
- freeb(bp);
- goto done;
- }
- if(seg.flags & ACK) {
- freeb(bp);
- sndrst(source, dest, length, &seg);
- goto done;
- }
- if(seg.flags & SYN) {
- proc_syn(s, tos, &seg);
- tcpsndsyn(tcb);
- tcpsetstate(s, Syn_received);
- if(length != 0 || (seg.flags & FIN))
- break;
- freeb(bp);
- goto output;
- }
- freeb(bp);
- goto done;
- case Syn_sent:
- if(seg.flags & ACK) {
- if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) {
- freeb(bp);
- sndrst(source, dest, length, &seg);
- goto done;
- }
- }
- if(seg.flags & RST) {
- if(seg.flags & ACK)
- localclose(s, Econrefused);
- freeb(bp);
- goto done;
- }
-
- if(seg.flags & ACK)
- if(PREC(tos) != PREC(tcb->tos)){
- freeb(bp);
- sndrst(source, dest, length, &seg);
- goto done;
- }
-
- if(seg.flags & SYN) {
- proc_syn(s, tos, &seg);
- if(seg.flags & ACK){
- update(s, &seg);
- tcpsetstate(s, Established);
- }
- else
- tcpsetstate(s, Syn_received);
-
- if(length != 0 || (seg.flags & FIN))
- break;
-
- freeb(bp);
- goto output;
- }
- else
- freeb(bp);
- goto done;
- }
-
- /* Cut the data to fit the receive window */
- if(trim(tcb, &seg, &bp, &length) == -1) {
- if(!(seg.flags & RST)) {
- tcb->flags |= FORCE;
- goto output;
- }
- goto done;
- }
-
- /* Cannot accept so answer with a rst */
- if(length)
- if(s->readq == 0)
- if(tcb->state == Closed) {
- freeb(bp);
- sndrst(source, dest, length, &seg);
- goto done;
- }
-
- /* The segment is beyond the current receive pointer so
- * queue the data in the resequence queue
- */
- if(seg.seq != tcb->rcv.nxt)
- if(length != 0 || (seg.flags & (SYN|FIN))) {
- add_reseq(tcb, tos, &seg, bp, length);
- tcb->flags |= FORCE;
- goto output;
- }
-
- for(;;) {
- if(seg.flags & RST) {
- if(tcb->state == Syn_received
- && !(tcb->flags & (CLONE|ACTIVE)))
- tcpsetstate(s, Listen);
- else
- localclose(s, Econrefused);
-
- freeb(bp);
- goto done;
- }
-
- /* This tos stuff should be removed */
- if(PREC(tos) != PREC(tcb->tos) || (seg.flags & SYN)){
- freeb(bp);
- sndrst(source, dest, length, &seg);
- goto done;
- }
-
- if(!(seg.flags & ACK)) {
- freeb(bp);
- goto done;
- }
-
- switch(tcb->state) {
- case Syn_received:
- if(!seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){
- freeb(bp);
- sndrst(source, dest, length, &seg);
- goto done;
- }
- update(s, &seg);
- tcpsetstate(s, Established);
- case Established:
- case Close_wait:
- update(s, &seg);
- break;
- case Finwait1:
- update(s, &seg);
- if(tcb->sndcnt == 0)
- tcpsetstate(s, Finwait2);
- break;
- case Finwait2:
- update(s, &seg);
- break;
- case Closing:
- update(s, &seg);
- if(tcb->sndcnt == 0) {
- tcpsetstate(s, Time_wait);
- tcb->timer.start = MSL2 * (1000 / MSPTICK);
- tcpgo(&tcb->timer);
- }
- break;
- case Last_ack:
- update(s, &seg);
- if(tcb->sndcnt == 0) {
- freeb(bp);
- localclose(s, Enoerror);
- goto done;
- }
- case Time_wait:
- tcb->flags |= FORCE;
- tcpgo(&tcb->timer);
- }
-
- if((seg.flags&URG) && seg.up) {
- if(seq_gt(seg.up + seg.seq, tcb->rcv.up)) {
- tcb->rcv.up = seg.up + seg.seq;
- pullb(&bp, seg.up);
- }
- }
- else if(seq_gt(tcb->rcv.nxt, tcb->rcv.up))
- tcb->rcv.up = tcb->rcv.nxt;
-
- if(length == 0){
- if(bp)
- freeb(bp);
- }
- else {
- switch(tcb->state){
- default:
- /* Ignore segment text */
- if(bp)
- freeb(bp);
- break;
-
- case Syn_received:
- case Established:
- case Finwait1:
- /* If we still have some data place on receive queue */
- tcb->rcvcnt += blen(bp);
- if(bp){
- if(s->readq)
- PUTNEXT(s->readq, bp);
- else
- putb(&tcb->rcvq, bp);
- bp = 0;
- }
- tcb->rcv.nxt += length;
-
- tcprcvwin(s);
-
- tcpgo(&tcb->acktimer);
-
- if(tcb->max_snd <= tcb->rcv.nxt-tcb->last_ack)
- tcb->flags |= FORCE;
- break;
- case Finwait2:
- /* no process to read the data, send a reset */
- if(bp)
- freeb(bp);
- sndrst(source, dest, length, &seg);
- goto done;
- }
- }
-
- if(seg.flags & FIN) {
- tcb->flags |= FORCE;
-
- switch(tcb->state) {
- case Syn_received:
- case Established:
- tcb->rcv.nxt++;
- tcpsetstate(s, Close_wait);
- break;
- case Finwait1:
- tcb->rcv.nxt++;
- if(tcb->sndcnt == 0) {
- tcpsetstate(s, Time_wait);
- tcb->timer.start = MSL2 * (1000/MSPTICK);
- tcpgo(&tcb->timer);
- }
- else
- tcpsetstate(s, Closing);
- break;
- case Finwait2:
- tcb->rcv.nxt++;
- tcpsetstate(s, Time_wait);
- tcb->timer.start = MSL2 * (1000/MSPTICK);
- tcpgo(&tcb->timer);
- break;
- case Close_wait:
- case Closing:
- case Last_ack:
- break;
- case Time_wait:
- tcpgo(&tcb->timer);
- break;
- }
- }
-
- while(tcb->reseq) {
- if(seq_ge(tcb->rcv.nxt, tcb->reseq->seg.seq) == 0)
- break;
-
- get_reseq(tcb, &tos, &seg, &bp, &length);
-
- if(trim(tcb, &seg, &bp, &length) == 0)
- break;
- }
- break;
- }
-output:
- tcpoutput(s);
-done:
- qunlock(tcb);
-}
-
-void
-update(Ipconv *s, Tcp *seg)
-{
- int rtt;
- ushort acked;
- ushort expand;
- Tcpctl *tcb = &s->tcpctl;
-
- if(seq_gt(seg->ack, tcb->snd.nxt)) {
- tcb->flags |= FORCE;
- return;
- }
-
- 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;
- }
-
- if(!seq_gt(seg->ack, tcb->snd.una))
- return;
-
- /* Compute the new send window size */
- acked = seg->ack - tcb->snd.una;
- if(tcb->cwind < tcb->snd.wnd) {
- if(tcb->cwind < tcb->ssthresh)
- expand = MIN(acked,tcb->mss);
- else
- expand = ((long)tcb->mss * tcb->mss) / tcb->cwind;
-
- if(tcb->cwind + expand < tcb->cwind)
- expand = 65535 - tcb->cwind;
- if(tcb->cwind + expand > tcb->snd.wnd)
- expand = tcb->snd.wnd - tcb->cwind;
- if(expand != 0)
- tcb->cwind += expand;
- }
-
- /* Adjust the timers acorrding to the round trip time */
- if(run_timer(&tcb->rtt_timer))
- if(seq_ge(seg->ack, tcb->rttseq)) {
- tcphalt(&tcb->rtt_timer);
- if((tcb->flags&RETRAN) == 0) {
- tcb->backoff = 0;
- rtt = tcb->rtt_timer.start - tcb->rtt_timer.count;
- rtt *= MSPTICK;
- if(rtt > tcb->srtt &&
- (tcb->state == Syn_sent || tcb->state == Syn_received))
- tcb->srtt = rtt;
- else {
- tcb->srtt = ((AGAIN-1)*tcb->srtt + rtt) / AGAIN;
- rtt = abs(rtt - tcb->srtt);
- tcb->mdev = ((DGAIN-1)*tcb->mdev + rtt) / DGAIN;
- }
- }
- }
-
- if((tcb->flags & SYNACK) == 0){
- tcb->flags |= SYNACK;
- acked--;
- tcb->sndcnt--;
- }
-
- pullb(&tcb->sndq, acked);
-
- tcb->sndcnt -= acked;
- tcb->snd.una = seg->ack;
- if(seq_gt(seg->ack, tcb->snd.up))
- tcb->snd.up = seg->ack;
-
- tcphalt(&tcb->timer);
- if(tcb->snd.una != tcb->snd.nxt)
- tcpgo(&tcb->timer);
-
- if(seq_lt(tcb->snd.ptr, tcb->snd.una))
- tcb->snd.ptr = tcb->snd.una;
-
- tcb->flags &= ~RETRAN;
- tcb->backoff = 0;
-
- if(tcb->sndfull && tcb->sndcnt < Streamhi/2){
- wakeup(&tcb->sndr);
- tcb->sndfull = 0;
- }
-}
-
-int
-in_window(Tcpctl *tcb, int seq)
-{
- return seq_within(seq, tcb->rcv.nxt, (int)(tcb->rcv.nxt+tcb->rcv.wnd-1));
-}
-
-void
-proc_syn(Ipconv *s, char tos, Tcp *seg)
-{
- Tcpctl *tcb = &s->tcpctl;
- ushort mtu;
-
-
- tcb->flags |= FORCE;
-
- if(PREC(tos) > PREC(tcb->tos))
- tcb->tos = tos;
-
- tcb->rcv.up = tcb->rcv.nxt = seg->seq + 1;
- tcb->snd.wl1 = tcb->irs = seg->seq;
- tcb->snd.wnd = seg->wnd;
-
- if(seg->mss != 0)
- tcb->mss = seg->mss;
-
- tcb->max_snd = seg->wnd;
- if((mtu = s->ifc->maxmtu) != 0) {
- mtu -= TCP_HDRSIZE + TCP_EHSIZE + TCP_PHDRSIZE;
- tcb->cwind = tcb->mss = MIN(mtu, tcb->mss);
- }
-}
-
-/* Generate an initial sequence number and put a SYN on the send queue */
-void
-tcpsndsyn(Tcpctl *tcb)
-{
- static int start;
-
- start += 250000;
- tcb->iss = start;
- tcb->rttseq = tcb->iss;
- tcb->snd.wl2 = tcb->iss;
- tcb->snd.una = tcb->iss;
- tcb->snd.ptr = tcb->snd.nxt = tcb->rttseq;
- tcb->sndcnt++;
- tcb->flags |= FORCE;
-}
-
-void
-add_reseq(Tcpctl *tcb, char tos, Tcp *seg, Block *bp, ushort length)
-{
- Reseq *rp, *rp1;
-
- rp = malloc(sizeof(Reseq));
- if(rp == 0){
- freeb(bp); /* bp always consumed by add_reseq */
- return;
- }
-
- rp->seg = *seg;
- rp->tos = tos;
- rp->bp = bp;
- rp->length = length;
-
- /* Place on reassembly list sorting by starting seq number */
- rp1 = tcb->reseq;
- if(rp1 == 0 || seq_lt(seg->seq, rp1->seg.seq)) {
- rp->next = rp1;
- tcb->reseq = rp;
- return;
- }
-
- for(;;) {
- if(rp1->next == 0 || seq_lt(seg->seq, rp1->next->seg.seq)) {
- rp->next = rp1->next;
- rp1->next = rp;
- break;
- }
- rp1 = rp1->next;
- }
-}
-
-void
-get_reseq(Tcpctl *tcb, char *tos, Tcp *seg, Block **bp, ushort *length)
-{
- Reseq *rp;
-
- rp = tcb->reseq;
- if(rp == 0)
- return;
-
- tcb->reseq = rp->next;
-
- *tos = rp->tos;
- *seg = rp->seg;
- *bp = rp->bp;
- *length = rp->length;
-
- free(rp);
-}
-
-int
-trim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
-{
- Block *nbp;
- long dupcnt;
- long excess;
- ushort len;
- char accept;
-
- accept = 0;
- len = *length;
- if(seg->flags & SYN)
- len++;
- if(seg->flags & FIN)
- len++;
-
- if(tcb->rcv.wnd == 0) {
- if(len == 0)
- if(seg->seq == tcb->rcv.nxt)
- return 0;
- }
- else {
- /* Some part of the segment should be in the window */
- if(in_window(tcb,seg->seq))
- accept++;
- else
- if(len != 0) {
- if(in_window(tcb, (int)(seg->seq+len-1)) ||
- seq_within(tcb->rcv.nxt, seg->seq,(int)(seg->seq+len-1)))
- accept++;
- }
- }
- if(!accept) {
- freeb(*bp);
- return -1;
- }
- dupcnt = tcb->rcv.nxt - seg->seq;
- if(dupcnt > 0){
- tcb->rerecv += dupcnt;
- if(seg->flags & SYN){
- seg->flags &= ~SYN;
- seg->seq++;
-
- if (seg->up > 1)
- seg->up--;
- else
- seg->flags &= ~URG;
- dupcnt--;
- }
- if(dupcnt > 0){
- pullb(bp, (ushort)dupcnt);
- seg->seq += dupcnt;
- *length -= dupcnt;
-
- if (seg->up > dupcnt)
- seg->up -= dupcnt;
- else {
- seg->flags &= ~URG;
- seg->up = 0;
- }
- }
- }
- excess = seg->seq + *length - (tcb->rcv.nxt + tcb->rcv.wnd);
- if(excess > 0) {
- tcb->rerecv += excess;
- *length -= excess;
- nbp = copyb(*bp, *length);
- freeb(*bp);
- *bp = nbp;
- seg->flags &= ~FIN;
- }
- return 0;
-}
-
-int
-pullb(Block **bph, int count)
-{
- int n, bytes;
- Block *bp;
-
- bytes = 0;
- if(bph == 0)
- return 0;
-
- while(*bph && count != 0) {
- bp = *bph;
- n = MIN(count, BLEN(bp));
- bytes += n;
- count -= n;
- bp->rptr += n;
- if(BLEN(bp) == 0) {
- *bph = bp->next;
- bp->next = 0;
- freeb(bp);
- }
- }
- return bytes;
-}
-
-int
-dupb(Block **hp, Block *bp, int offset, int count)
-{
- int i, blen, bytes = 0;
- uchar *addr;
-
- *hp = allocb(count);
- if(*hp == 0)
- return 0;
-
- /* 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;
-
- while(count) {
- i = MIN(count, blen);
- memmove((*hp)->wptr, addr, i);
- (*hp)->wptr += i;
- bytes += i;
- count -= i;
- bp = bp->next;
- if(!bp)
- break;
- blen = BLEN(bp);
- addr = bp->rptr;
- }
-
- return bytes;
-}
-
-static void
-cleartcp(struct Tctl *a)
-{
- memset(a, 0, sizeof(struct Tctl));
-}
-
-void
-init_tcpctl(Ipconv *s)
-{
-
- Tcpctl *tcb = &s->tcpctl;
-
- cleartcp(tcb);
-
- tcb->cwind = tcb->mss = tcp_mss;
- tcb->ssthresh = 65535;
- tcb->srtt = tcp_irtt;
-
- tcb->timer.start = tcb->srtt / MSPTICK;
- tcb->timer.func = tcptimeout;
- tcb->timer.arg = s;
- tcb->rtt_timer.start = MAX_TIME;
- tcb->acktimer.start = TCP_ACK / MSPTICK;
- tcb->acktimer.func = tcpacktimer;
- tcb->acktimer.arg = s;
-}
-
-/*
- * called with tcb locked
- */
-void
-localclose(Ipconv *s, char reason[])
-{
- Reseq *rp,*rp1;
- Tcpctl *tcb = &s->tcpctl;
- Block *bp;
-
- tcphalt(&tcb->timer);
- tcphalt(&tcb->rtt_timer);
- s->err = reason;
-
- /* flush receive queue */
- while(bp = getb(&tcb->rcvq))
- freeb(bp);
-
- /* Flush reassembly queue; nothing more can arrive */
- for(rp = tcb->reseq;rp != 0;rp = rp1){
- rp1 = rp->next;
- freeb(rp->bp);
- free(rp);
- }
-
- tcb->reseq = 0;
- s->err = reason;
- tcpsetstate(s, Closed);
-}
-
-int
-seq_within(int x, int low, int high)
-{
- if(low <= high){
- if(low <= x && x <= high)
- return 1;
- }
- else {
- if(low >= x && x >= high)
- return 1;
- }
- return 0;
-}
-
-int
-seq_lt(int x, int y)
-{
- return (long)(x-y) < 0;
-}
-
-int
-seq_le(int x, int y)
-{
- return (long)(x-y) <= 0;
-}
-
-int
-seq_gt(int x, int y)
-{
- return (long)(x-y) > 0;
-}
-
-int
-seq_ge(int x, int y)
-{
- return (long)(x-y) >= 0;
-}
-
-void
-tcpsetstate(Ipconv *s, char newstate)
-{
- Tcpctl *tcb;
- char oldstate;
-
- tcb = &s->tcpctl;
-
- oldstate = tcb->state;
- tcb->state = newstate;
- tcpxstate(s, oldstate, newstate);
-}
-
-Block *
-htontcp(Tcp *tcph, Block *data, Tcphdr *ph)
-{
- int dlen;
- Tcphdr *h;
- Block *bp;
- ushort csum;
- ushort hdrlen;
-
- hdrlen = TCP_HDRSIZE;
- if(tcph->mss)
- hdrlen += MSS_LENGTH;
-
- if(data) {
- dlen = blen(data);
- data = padb(data, hdrlen + TCP_PKT);
- if(data == 0)
- return 0;
- /* If we collected blocks delimit the end of the chain */
- for(bp = data; bp->next; bp = bp->next)
- bp->flags &= ~S_DELIM;
- bp->flags |= S_DELIM;
- }
- else {
- dlen = 0;
- data = allocb(hdrlen + TCP_PKT);
- if(data == 0)
- return 0;
- data->wptr += hdrlen + TCP_PKT;
- data->flags |= S_DELIM;
- }
-
-
- memmove(data->rptr, ph, TCP_PKT);
-
- h = (Tcphdr *)(data->rptr);
- h->proto = IP_TCPPROTO;
- h->frag[0] = 0;
- h->frag[1] = 0;
- hnputs(h->tcplen, hdrlen + dlen);
- hnputs(h->tcpsport, tcph->source);
- hnputs(h->tcpdport, tcph->dest);
- hnputl(h->tcpseq, tcph->seq);
- hnputl(h->tcpack, tcph->ack);
- hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags);
- hnputs(h->tcpwin, tcph->wnd);
- h->tcpcksum[0] = 0;
- h->tcpcksum[1] = 0;
- h->Unused = 0;
- hnputs(h->tcpurg, tcph->up);
-
- if(tcph->mss != 0){
- h->tcpopt[0] = MSS_KIND;
- h->tcpopt[1] = MSS_LENGTH;
- hnputs(h->tcpmss, tcph->mss);
- }
- csum = ptcl_csum(data, TCP_EHSIZE+TCP_IPLEN, hdrlen+dlen+TCP_PHDRSIZE);
- hnputs(h->tcpcksum, csum);
-
- return data;
-}
-
-int
-ntohtcp(Tcp *tcph, Block **bpp)
-{
- ushort hdrlen;
- ushort i, optlen;
- Tcphdr *h;
- uchar *optr;
-
- *bpp = pullup(*bpp, TCP_PKT+TCP_HDRSIZE);
- if(*bpp == 0)
- return -1;
-
- h = (Tcphdr *)((*bpp)->rptr);
- tcph->source = nhgets(h->tcpsport);
- tcph->dest = nhgets(h->tcpdport);
- tcph->seq = nhgetl(h->tcpseq);
- tcph->ack = nhgetl(h->tcpack);
-
- hdrlen = (h->tcpflag[0] & 0xf0) >> 2;
- if(hdrlen < TCP_HDRSIZE) {
- freeb(*bpp);
- return -1;
- }
-
- tcph->flags = h->tcpflag[1];
- tcph->wnd = nhgets(h->tcpwin);
- tcph->up = nhgets(h->tcpurg);
- tcph->mss = 0;
-
- *bpp = pullup(*bpp, hdrlen+TCP_PKT);
- if(!*bpp)
- return -1;
-
- optr = h->tcpopt;
- for(i = TCP_HDRSIZE; i < hdrlen;) {
- switch(*optr++){
- case EOL_KIND:
- return hdrlen;
- case NOOP_KIND:
- i++;
- break;
- case MSS_KIND:
- optlen = *optr++;
- if(optlen == MSS_LENGTH)
- tcph->mss = nhgets(optr);
- i += optlen;
- break;
- }
- }
- return hdrlen;
-}
D port/tcpoutput.c => port/tcpoutput.c +0 -273
@@ 1,273 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "arp.h"
-#include "ipdat.h"
-
-#define DPRINT if(tcpdbg) print
-
-extern int tcpdbg;
-extern ushort tcp_mss;
- int tcptimertype;
-
-void
-tcpoutput(Ipconv *s)
-{
- Tcp seg;
- int qlen;
- Tcphdr ph;
- Tcpctl *tcb;
- Block *hbp,*dbp, *sndq;
- ushort ssize, dsize, usable, sent;
-
- tcb = &s->tcpctl;
-
- switch(tcb->state) {
- case Listen:
- case Closed:
- return;
- }
-
- for(;;) {
- qlen = tcb->sndcnt;
- sent = tcb->snd.ptr - tcb->snd.una;
- sndq = tcb->sndq;
-
- /* Don't send anything else until our SYN has been acked */
- if(sent != 0)
- if((tcb->flags & SYNACK) == 0)
- break;
-
- /* Compute usable segment based on offered window and limit
- * window probes to one
- */
- if(tcb->snd.wnd == 0){
- if(sent != 0) {
- if (tcb->flags&FORCE)
- tcb->snd.ptr = tcb->snd.una;
- else
- break;
- }
- usable = 1;
- }
- else {
- usable = MIN(tcb->snd.wnd,tcb->cwind) - sent;
- if(sent != 0)
- if(qlen - sent < tcb->mss)
- usable = 0;
- }
-
- ssize = MIN(qlen - sent, usable);
- ssize = MIN(ssize, tcb->mss);
- dsize = ssize;
- seg.up = 0;
-
- if(ssize == 0)
- if((tcb->flags&FORCE) == 0)
- break;
-
- tcphalt(&tcb->acktimer);
-
- tcb->flags &= ~FORCE;
- tcprcvwin(s);
-
- /* By default we will generate an ack */
- seg.source = s->psrc;
- seg.dest = s->pdst;
- seg.flags = ACK;
- seg.mss = 0;
-
- switch(tcb->state){
- case Syn_sent:
- seg.flags = 0;
- /* No break */
- case Syn_received:
- if(tcb->snd.ptr == tcb->iss){
- seg.flags |= SYN;
- dsize--;
- seg.mss = tcp_mss;
- }
- break;
- }
- seg.seq = tcb->snd.ptr;
- seg.ack = tcb->last_ack = tcb->rcv.nxt;
- seg.wnd = tcb->rcv.wnd;
-
- /* Pull out data to send */
- dbp = 0;
- if(dsize != 0){
- if(dupb(&dbp, sndq, sent, dsize) != dsize) {
- seg.flags |= FIN;
- dsize--;
- }
- DPRINT("dupb: %d\n", dbp->rptr[0]);
- }
-
- if(sent+dsize == qlen)
- seg.flags |= PSH;
-
- /*
- * keep track of balance of resent data */
- if(tcb->snd.ptr < tcb->snd.nxt)
- tcb->resent += MIN((int)tcb->snd.nxt - (int)tcb->snd.ptr,(int)ssize);
-
- tcb->snd.ptr += ssize;
-
- /* Pull up the send pointer so we can accept acks for this window */
- if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
- tcb->snd.nxt = tcb->snd.ptr;
-
- /* Fill in fields of pseudo IP header */
- hnputl(ph.tcpdst, s->dst);
- hnputl(ph.tcpsrc, Myip[Myself]);
- hnputs(ph.tcpsport, s->psrc);
- hnputs(ph.tcpdport, s->pdst);
-
- /* Build header, link data and compute cksum */
- if((hbp = htontcp(&seg, dbp, &ph)) == 0) {
- freeb(dbp);
- return;
- }
-
- /* Start the transmission timers if there is new data and we
- * expect acknowledges
- */
- if(ssize != 0){
- tcb->timer.start = backoff(tcb->backoff) *
- (2 * tcb->mdev + tcb->srtt + MSPTICK) / MSPTICK;
- if(!run_timer(&tcb->timer))
- tcpgo(&tcb->timer);
-
- /* If round trip timer isn't running, start it */
- if(!run_timer(&tcb->rtt_timer)){
- tcpgo(&tcb->rtt_timer);
- tcb->rttseq = tcb->snd.ptr;
- }
- }
- PUTNEXT(Ipoutput, hbp);
- }
-}
-
-void
-tcprxmit(Ipconv *s)
-{
- Tcpctl *tcb;
-
- tcb = &s->tcpctl;
- qlock(tcb);
- tcb->flags |= RETRAN|FORCE;
- tcb->snd.ptr = tcb->snd.una;
-
- /* Pull window down to a single packet and halve the slow
- * start threshold
- */
- tcb->ssthresh = tcb->cwind / 2;
- tcb->ssthresh = MAX(tcb->ssthresh, tcb->mss);
-
- tcb->cwind = tcb->mss;
- tcpoutput(s);
- qunlock(tcb);
-}
-
-void
-tcptimeout(void *arg)
-{
- Tcpctl *tcb;
- Ipconv *s;
-
- s = (Ipconv *)arg;
- tcb = &s->tcpctl;
- switch(tcb->state){
- default:
- tcb->backoff++;
- if (tcb->backoff >= MAXBACKOFF && tcb->snd.wnd > 0) {
- localclose(s, Etimedout);
- break;
- }
- tcprxmit(s);
- break;
-
- case Time_wait:
- localclose(s, 0);
- break;
- }
-}
-
-int
-backoff(int n)
-{
- if(tcptimertype == 1)
- return n+1;
-
- if(n <= 4)
- return 1 << n;
-
- return n*n;
-}
-
-void
-tcpacktimer(Ipconv *s)
-{
- Tcpctl *tcb = &s->tcpctl;
-
- qlock(tcb);
- tcb->flags |= FORCE;
- tcprcvwin(s);
- tcpoutput(s);
- qunlock(tcb);
-}
-
-void
-tcprcvwin(Ipconv *s) /* Call with tcb locked */
-{
- int w;
- Tcpctl *tcb;
-
- tcb = &s->tcpctl;
- qlock(s);
- if(s->readq) {
- w = Streamhi - s->readq->next->len;
- if(w < 0)
- tcb->rcv.wnd = 0;
- else
- tcb->rcv.wnd = w;
- }
- else
- tcb->rcv.wnd = Streamhi;
- qunlock(s);
-}
-
-/*
- * Network byte order functions
- */
-
-void
-hnputs(uchar *ptr, ushort val)
-{
- ptr[0] = val>>8;
- ptr[1] = val;
-}
-
-void
-hnputl(uchar *ptr, ulong val)
-{
- ptr[0] = val>>24;
- ptr[1] = val>>16;
- ptr[2] = val>>8;
- ptr[3] = val;
-}
-
-ulong
-nhgetl(uchar *ptr)
-{
- return ((ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3]);
-}
-
-ushort
-nhgets(uchar *ptr)
-{
- return ((ptr[0]<<8) | ptr[1]);
-}
D port/tcptimer.c => port/tcptimer.c +0 -125
@@ 1,125 0,0 @@
-#include "u.h"
-#include "../port/lib.h"
-#include "mem.h"
-#include "dat.h"
-#include "fns.h"
-#include "../port/error.h"
-#include "arp.h"
-#include "ipdat.h"
-
-static Timer *timers; /* List of active timers */
-static QLock tl; /* Protect timer list */
-static Rendez Tcpack;
-Rendez tcpflowr;
-
-static void
-deltimer(Timer *t)
-{
- if(timers == t)
- timers = t->next;
-
- if(t->next)
- t->next->prev = t->prev;
-
- if(t->prev)
- t->prev->next = t->next;
-}
-
-/*
- * Poke each tcp connection to recompute window size and
- * acknowledgement timer
- */
-
-void
-tcpflow(void *x)
-{
- Ipifc *ifc;
- Ipconv *cp, **p, **etab;
-
- ifc = x;
- etab = &ifc->conv[Nipconv];
-
- for(;;) {
- sleep(&tcpflowr, return0, 0);
-
- for(p = ifc->conv; p < etab; p++) {
- cp = *p;
- if(cp == 0)
- break;
- if(cp->readq && cp->ref != 0 && !QFULL(cp->readq->next)) {
- tcprcvwin(cp);
- tcpacktimer(cp);
- }
- }
- }
-}
-
-void
-tcpackproc(void *junk)
-{
- Timer *t, *tp, *timeo;
-
- USED(junk);
- for(;;) {
- timeo = 0;
-
- qlock(&tl);
- for(t = timers;t != 0; t = tp) {
- tp = t->next;
- if(t->state == TimerON) {
- t->count--;
- if(t->count == 0) {
- deltimer(t);
- t->state = TimerDONE;
- t->next = timeo;
- timeo = t;
- }
- }
- }
- qunlock(&tl);
-
- for(;;) {
- t = timeo;
- if(t == 0)
- break;
-
- timeo = t->next;
- if(t->state == TimerDONE)
- if(t->func)
- (*t->func)(t->arg);
- }
- tsleep(&Tcpack, return0, 0, MSPTICK);
- }
-}
-
-void
-tcpgo(Timer *t)
-{
- if(t == 0 || t->start == 0)
- return;
-
- qlock(&tl);
- t->count = t->start;
- if(t->state != TimerON) {
- t->state = TimerON;
- t->prev = 0;
- t->next = timers;
- if(t->next)
- t->next->prev = t;
- timers = t;
- }
- qunlock(&tl);
-}
-
-void
-tcphalt(Timer *t)
-{
- if(t == 0)
- return;
-
- qlock(&tl);
- if(t->state == TimerON)
- deltimer(t);
- t->state = TimerOFF;
- qunlock(&tl);
-}