12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <ip.h>
- #define LOG "pptpd"
- typedef struct Call Call;
- typedef struct Event Event;
- #define SDB if(debug) fprint(2,
- #define EDB );
- enum {
- Magic = 0x1a2b3c4d,
- Nhash = 17,
- Nchan = 10, /* maximum number of channels */
- Window = 8, /* default window size */
- Timeout = 60, /* timeout in seconds for control channel */
- Pktsize = 2000, /* maximum packet size */
- Tick = 500, /* tick length in milliseconds */
- Sendtimeout = 4, /* in ticks */
- };
- enum {
- Syncframe = 0x1,
- Asyncframe = 0x2,
- Analog = 0x1,
- Digital = 0x2,
- Version = 0x100,
- };
- enum {
- Tstart = 1,
- Rstart = 2,
- Tstop = 3,
- Rstop = 4,
- Techo = 5,
- Recho = 6,
- Tcallout = 7,
- Rcallout = 8,
- Tcallreq = 9,
- Rcallreq = 10,
- Acallcon = 11,
- Tcallclear = 12,
- Acalldis = 13,
- Awaninfo = 14,
- Alinkinfo = 15,
- };
- struct Event {
- QLock;
- QLock waitlk;
- int wait;
- int ready;
- };
- struct Call {
- int ref;
- QLock lk;
- int id;
- int serial;
- int pppfd;
- int closed;
- int pac; /* server is acting as a PAC */
- int recvwindow; /* recv windows */
- int sendwindow; /* send windows */
- int delay;
- int sendaccm;
- int recvaccm;
- uint seq; /* current seq number - for send */
- uint ack; /* current acked mesg - for send */
- uint rseq; /* highest recv seq number for in order packet */
- uint rack; /* highest ack sent */
- Event eack; /* recved ack - for send */
- uint32_t tick;
- uint8_t remoteip[IPaddrlen]; /* remote ip address */
- int dhcpfd[2]; /* pipe to dhcpclient */
- /* error stats */
- struct {
- int crc;
- int frame;
- int hardware;
- int overrun;
- int timeout;
- int align;
- } err;
- struct {
- int send;
- int sendack;
- int recv;
- int recvack;
- int dropped;
- int missing;
- int sendwait;
- int sendtimeout;
- } stat;
- Call *next;
- };
- struct {
- QLock lk;
- int start;
- int grefd;
- int grecfd;
- uint8_t local[IPaddrlen];
- uint8_t remote[IPaddrlen];
- char *tcpdir;
- uint8_t ipaddr[IPaddrlen]; /* starting ip addresss to allocate */
- int recvwindow;
- char *pppdir;
- char *pppexec;
- double rcvtime; /* time at which last request was received */
- int echoid; /* id of last echo request */
- Call *hash[Nhash];
- } srv;
- /* GRE flag bits */
- enum {
- GRE_chksum = (1<<15),
- GRE_routing = (1<<14),
- GRE_key = (1<<13),
- GRE_seq = (1<<12),
- GRE_srcrt = (1<<11),
- GRE_recur = (7<<8),
- GRE_ack = (1<<7),
- GRE_ver = 0x7,
- };
- /* GRE protocols */
- enum {
- GRE_ppp = 0x880b,
- };
- int debug;
- double drop;
- void myfatal(char *fmt, ...);
- #define PSHORT(p, v) ((p)[0]=(((v)>>8)&0xFF), (p)[1]=((v)&0xFF))
- #define PLONG(p, v) (PSHORT(p, (v)>>16), PSHORT(p+2, (v)))
- #define PSTRING(d,s,n) strncpy((char*)(d), s, n)
- #define GSHORT(p) (((p)[0]<<8) | ((p)[1]<<0))
- #define GLONG(p) ((GSHORT((p))<<16) | ((GSHORT((p)+2))<<0))
- #define GSTRING(d,s,n) strncpy(d, (char*)(s), n), d[(n)-1] = 0
- void serve(void);
- int sstart(uint8_t*, int);
- int sstop(uint8_t*, int);
- int secho(uint8_t*, int);
- int scallout(uint8_t*, int);
- int scallreq(uint8_t*, int);
- int scallcon(uint8_t*, int);
- int scallclear(uint8_t*, int);
- int scalldis(uint8_t*, int);
- int swaninfo(uint8_t*, int);
- int slinkinfo(uint8_t*, int);
- Call *callalloc(int id);
- void callclose(Call*);
- void callfree(Call*);
- Call *calllookup(int id);
- void gretimeout(void*);
- void pppread(void*);
- void srvinit(void);
- void greinit(void);
- void greread(void*);
- void greack(Call *c);
- void timeoutthread(void*);
- int argatoi(char *p);
- void usage(void);
- int ipaddralloc(Call *c);
- void *emallocz(int size);
- void esignal(Event *e);
- void ewait(Event *e);
- int proc(char **argv, int fd0, int fd1, int fd2);
- double realtime(void);
- uint32_t thread(void(*f)(void*), void *a);
- void
- main(int argc, char *argv[])
- {
- ARGBEGIN{
- case 'd': debug++; break;
- case 'p': srv.pppdir = ARGF(); break;
- case 'P': srv.pppexec = ARGF(); break;
- case 'w': srv.recvwindow = argatoi(ARGF()); break;
- case 'D': drop = atof(ARGF()); break;
- default:
- usage();
- }ARGEND
- fmtinstall('I', eipfmt);
- fmtinstall('E', eipfmt);
- fmtinstall('V', eipfmt);
- fmtinstall('M', eipfmt);
- rfork(RFNOTEG|RFREND);
- if(argc != 1)
- usage();
- srv.tcpdir = argv[0];
- srvinit();
- syslog(0, LOG, ": src=%I: pptp started: %d", srv.remote, getpid());
- SDB "\n\n\n%I: pptp started\n", srv.remote EDB
- greinit();
- thread(timeoutthread, 0);
- serve();
- syslog(0, LOG, ": src=%I: server exits", srv.remote);
- exits(0);
- }
- void
- usage(void)
- {
- fprint(2, "usage: pptpd [-dD] [-p ppp-net] [-w window] tcpdir\n");
- exits("usage");
- }
- void
- serve(void)
- {
- uint8_t buf[2000], *p;
- int n, n2, len;
- int magic;
- int op, type;
- n = 0;
- for(;;) {
- n2 = read(0, buf+n, sizeof(buf)-n);
- if(n2 < 0)
- myfatal("bad read on ctl channel: %r");
- if(n2 == 0)
- break;
- n += n2;
- p = buf;
- for(;;) {
- if(n < 12)
- break;
- qlock(&srv.lk);
- srv.rcvtime = realtime();
- qunlock(&srv.lk);
- len = GSHORT(p);
- type = GSHORT(p+2);
- magic = GLONG(p+4);
- op = GSHORT(p+8);
- if(magic != Magic)
- myfatal("bad magic number: got %x", magic);
- if(type != 1)
- myfatal("bad message type: %d", type);
- switch(op) {
- default:
- myfatal("unknown control op: %d", op);
- case Tstart: /* start-control-connection-request */
- n2 = sstart(p, n);
- break;
- case Tstop:
- n2 = sstop(p, n);
- if(n2 > 0)
- return;
- break;
- case Techo:
- n2 = secho(p, n);
- break;
- case Tcallout:
- n2 = scallout(p, n);
- break;
- case Tcallreq:
- n2 = scallreq(p, n);
- break;
- case Acallcon:
- n2 = scallcon(p, n);
- break;
- case Tcallclear:
- n2 = scallclear(p, n);
- break;
- case Acalldis:
- n2 = scalldis(p, n);
- break;
- case Awaninfo:
- n2 = swaninfo(p, n);
- break;
- case Alinkinfo:
- n2 = slinkinfo(p, n);
- break;
- }
- if(n2 == 0)
- break;
- if(n2 != len)
- myfatal("op=%d: bad length: got %d expected %d", op, len, n2);
- n -= n2;
- p += n2;
- }
- /* move down partial message */
- if(p != buf && n != 0)
- memmove(buf, p, n);
- }
- }
- int
- sstart(uint8_t *p, int n)
- {
- int ver, frame, bearer, maxchan, firm;
- char host[64], vendor[64], *sysname;
- uint8_t buf[156];
- if(n < 156)
- return 0;
- ver = GSHORT(p+12);
- frame = GLONG(p+16);
- bearer = GLONG(p+20);
- maxchan = GSHORT(p+24);
- firm = GSHORT(p+26);
- GSTRING(host, p+28, 64);
- GSTRING(vendor, p+92, 64);
- SDB "%I: start ver = %x f = %d b = %d maxchan = %d firm = %d host = %s vendor = %s\n",
- srv.remote, ver, frame, bearer, maxchan, firm, host, vendor EDB
- if(ver != Version)
- myfatal("bad version: got %x expected %x", ver, Version);
- if(srv.start)
- myfatal("multiple start messages");
- srv.start = 1;
- sysname = getenv("sysname");
- if(sysname == 0)
- strcpy(host, "gnot");
- else
- strncpy(host, sysname, 64);
- free(sysname);
- memset(buf, 0, sizeof(buf));
- PSHORT(buf+0, sizeof(buf)); /* length */
- PSHORT(buf+2, 1); /* message type */
- PLONG(buf+4, Magic); /* magic */
- PSHORT(buf+8, Rstart); /* op */
- PSHORT(buf+12, Version); /* version */
- buf[14] = 1; /* result = ok */
- PLONG(buf+16, Syncframe|Asyncframe); /* frameing */
- PLONG(buf+20, Digital|Analog); /* berear capabilities */
- PSHORT(buf+24, Nchan); /* max channels */
- PSHORT(buf+26, 1); /* driver version */
- PSTRING(buf+28, host, 64); /* host name */
- PSTRING(buf+92, "plan 9", 64); /* vendor */
- if(write(1, buf, sizeof(buf)) < sizeof(buf))
- myfatal("write failed: %r");
- return 156;
- }
- int
- sstop(uint8_t *p, int n)
- {
- int reason;
- uint8_t buf[16];
- if(n < 16)
- return 0;
- reason = p[12];
- SDB "%I: stop %d\n", srv.remote, reason EDB
- memset(buf, 0, sizeof(buf));
- PSHORT(buf+0, sizeof(buf)); /* length */
- PSHORT(buf+2, 1); /* message type */
- PLONG(buf+4, Magic); /* magic */
- PSHORT(buf+8, Rstop); /* op */
- buf[12] = 1; /* ok */
- if(write(1, buf, sizeof(buf)) < sizeof(buf))
- myfatal("write failed: %r");
- return 16;
- }
- int
- secho(uint8_t *p, int n)
- {
- int id;
- uint8_t buf[20];
- if(n < 16)
- return 0;
- id = GLONG(p+12);
- SDB "%I: echo %d\n", srv.remote, id EDB
- memset(buf, 0, sizeof(buf));
- PSHORT(buf+0, sizeof(buf)); /* length */
- PSHORT(buf+2, 1); /* message type */
- PLONG(buf+4, Magic); /* magic */
- PSHORT(buf+8, Recho); /* op */
- PLONG(buf+12, id); /* id */
- p[16] = 1; /* ok */
- if(write(1, buf, sizeof(buf)) < sizeof(buf))
- myfatal("write failed: %r");
- return 16;
- }
- int
- scallout(uint8_t *p, int n)
- {
- int id, serial;
- int minbps, maxbps, bearer, frame;
- int window, delay;
- int nphone;
- char phone[64], sub[64], buf[32];
- Call *c;
- if(n < 168)
- return 0;
- if(!srv.start)
- myfatal("%I: did not recieve start message", srv.remote);
- id = GSHORT(p+12);
- serial = GSHORT(p+14);
- minbps = GLONG(p+16);
- maxbps = GLONG(p+20);
- bearer = GLONG(p+24);
- frame = GLONG(p+28);
- window = GSHORT(p+32);
- delay = GSHORT(p+34);
- nphone = GSHORT(p+36);
- GSTRING(phone, p+40, 64);
- GSTRING(sub, p+104, 64);
- SDB "%I: callout id = %d serial = %d bps=[%d,%d] b=%x f=%x win = %d delay = %d np=%d phone=%s sub=%s\n",
- srv.remote, id, serial, minbps, maxbps, bearer, frame, window, delay, nphone, phone, sub EDB
- c = callalloc(id);
- c->sendwindow = window;
- c->delay = delay;
- c->pac = 1;
- c->recvwindow = srv.recvwindow;
- memset(buf, 0, sizeof(buf));
- PSHORT(buf+0, sizeof(buf)); /* length */
- PSHORT(buf+2, 1); /* message type */
- PLONG(buf+4, Magic); /* magic */
- PSHORT(buf+8, Rcallout); /* op */
- PSHORT(buf+12, id); /* call id */
- PSHORT(buf+14, id); /* peer id */
- buf[16] = 1; /* ok */
- PLONG(buf+20, 10000000); /* speed */
- PSHORT(buf+24, c->recvwindow); /* window size */
- PSHORT(buf+26, 0); /* delay */
- PLONG(buf+28, 0); /* channel id */
- if(write(1, buf, sizeof(buf)) < sizeof(buf))
- myfatal("write failed: %r");
- return 168;
- }
- int
- scallreq(uint8_t *p, int n)
- {
- USED(p);
- USED(n);
- myfatal("callreq: not done yet");
- return 0;
- }
- int
- scallcon(uint8_t *p, int n)
- {
- USED(p);
- USED(n);
- myfatal("callcon: not done yet");
- return 0;
- }
- int
- scallclear(uint8_t *p, int n)
- {
- Call *c;
- int id;
- uint8_t buf[148];
- if(n < 16)
- return 0;
- id = GSHORT(p+12);
- SDB "%I: callclear id=%d\n", srv.remote, id EDB
- if(c = calllookup(id)) {
- callclose(c);
- callfree(c);
- }
- memset(buf, 0, sizeof(buf));
- PSHORT(buf+0, sizeof(buf)); /* length */
- PSHORT(buf+2, 1); /* message type */
- PLONG(buf+4, Magic); /* magic */
- PSHORT(buf+8, Acalldis); /* op */
- PSHORT(buf+12, id); /* id */
- buf[14] = 3; /* reply to callclear */
- if(write(1, buf, sizeof(buf)) < sizeof(buf))
- myfatal("write failed: %r");
- return 16;
- }
- int
- scalldis(uint8_t *p, int n)
- {
- Call *c;
- int id, res;
- if(n < 148)
- return 0;
- id = GSHORT(p+12);
- res = p[14];
- SDB "%I: calldis id=%d res=%d\n", srv.remote, id, res EDB
- if(c = calllookup(id)) {
- callclose(c);
- callfree(c);
- }
- return 148;
- }
- int
- swaninfo(uint8_t *p, int n)
- {
- Call *c;
- int id;
- if(n < 40)
- return 0;
- id = GSHORT(p+12);
- SDB "%I: waninfo id = %d\n", srv.remote, id EDB
- c = calllookup(id);
- if(c != 0) {
- c->err.crc = GLONG(p+16);
- c->err.frame = GLONG(p+20);
- c->err.hardware = GLONG(p+24);
- c->err.overrun = GLONG(p+28);
- c->err.timeout = GLONG(p+32);
- c->err.align = GLONG(p+36);
- callfree(c);
- }
- return 40;
- }
- int
- slinkinfo(uint8_t *p, int n)
- {
- Call *c;
- int id;
- int sendaccm, recvaccm;
- if(n < 24)
- return 0;
- id = GSHORT(p+12);
- sendaccm = GLONG(p+16);
- recvaccm = GLONG(p+20);
- SDB "%I: linkinfo id=%d saccm=%x raccm=%x\n", srv.remote, id, sendaccm, recvaccm EDB
- if(c = calllookup(id)) {
- c->sendaccm = sendaccm;
- c->recvaccm = recvaccm;
- callfree(c);
- }
- return 24;
- }
- Call*
- callalloc(int id)
- {
- uint h;
- Call *c;
- char buf[300], *argv[30], local[20], remote[20], **p;
- int fd, pfd[2], n;
- h = id%Nhash;
- qlock(&srv.lk);
- for(c=srv.hash[h]; c; c=c->next)
- if(c->id == id)
- myfatal("callalloc: duplicate id: %d", id);
- c = emallocz(sizeof(Call));
- c->ref = 1;
- c->id = id;
- c->sendaccm = ~0;
- c->recvaccm = ~0;
- if(!ipaddralloc(c))
- myfatal("callalloc: could not alloc remote ip address");
- if(pipe(pfd) < 0)
- myfatal("callalloc: pipe failed: %r");
- sprint(buf, "%s/ipifc/clone", srv.pppdir);
- fd = open(buf, OWRITE);
- if(fd < 0)
- myfatal("callalloc: could not open %s: %r", buf);
- n = sprint(buf, "iprouting");
- if(write(fd, buf, n) < n)
- myfatal("callalloc: write to ifc failed: %r");
- close(fd);
- p = argv;
- *p++ = srv.pppexec;
- *p++ = "-SC";
- *p++ = "-x";
- *p++ = srv.pppdir;
- if(debug)
- *p++ = "-d";
- sprint(local, "%I", srv.ipaddr);
- *p++ = local;
- sprint(remote, "%I", c->remoteip);
- *p++ = remote;
- *p = 0;
- proc(argv, pfd[0], pfd[0], 2);
- close(pfd[0]);
- c->pppfd = pfd[1];
- c->next = srv.hash[h];
- srv.hash[h] = c;
- qunlock(&srv.lk);
- c->ref++;
- thread(pppread, c);
- c->ref++;
- thread(gretimeout, c);
- syslog(0, LOG, ": src=%I: call started: id=%d: remote ip=%I", srv.remote, id, c->remoteip);
- return c;
- }
- void
- callclose(Call *c)
- {
- Call *oc;
- int id;
- uint h;
- syslog(0, LOG, ": src=%I: call closed: id=%d: send=%d sendack=%d recv=%d recvack=%d dropped=%d missing=%d sendwait=%d sendtimeout=%d",
- srv.remote, c->id, c->stat.send, c->stat.sendack, c->stat.recv, c->stat.recvack,
- c->stat.dropped, c->stat.missing, c->stat.sendwait, c->stat.sendtimeout);
- qlock(&srv.lk);
- if(c->closed) {
- qunlock(&srv.lk);
- return;
- }
- c->closed = 1;
- close(c->dhcpfd[0]);
- close(c->dhcpfd[1]);
- close(c->pppfd);
- c->pppfd = -1;
- h = c->id%Nhash;
- id = c->id;
- for(c=srv.hash[h],oc=0; c; oc=c,c=c->next)
- if(c->id == id)
- break;
- if(oc == 0)
- srv.hash[h] = c->next;
- else
- oc->next = c->next;
- c->next = 0;
- qunlock(&srv.lk);
- callfree(c);
- }
- void
- callfree(Call *c)
- {
- int ref;
- qlock(&srv.lk);
- ref = --c->ref;
- qunlock(&srv.lk);
- if(ref > 0)
- return;
- /* already unhooked from hash list - see callclose */
- assert(c->closed == 1);
- assert(ref == 0);
- assert(c->next == 0);
- SDB "call free\n" EDB
- free(c);
- }
- Call*
- calllookup(int id)
- {
- uint h;
- Call *c;
- h = id%Nhash;
- qlock(&srv.lk);
- for(c=srv.hash[h]; c; c=c->next)
- if(c->id == id)
- break;
- if(c != 0)
- c->ref++;
- qunlock(&srv.lk);
- return c;
- }
- void
- srvinit(void)
- {
- char buf[100];
- int fd, n;
- sprint(buf, "%s/local", srv.tcpdir);
- if((fd = open(buf, OREAD)) < 0)
- myfatal("could not open %s: %r", buf);
- if((n = read(fd, buf, sizeof(buf))) < 0)
- myfatal("could not read %s: %r", buf);
- buf[n] = 0;
- parseip(srv.local, buf);
- close(fd);
- sprint(buf, "%s/remote", srv.tcpdir);
- if((fd = open(buf, OREAD)) < 0)
- myfatal("could not open %s: %r", buf);
- if((n = read(fd, buf, sizeof(buf))) < 0)
- myfatal("could not read %s: %r", buf);
- buf[n] = 0;
- parseip(srv.remote, buf);
- close(fd);
- if(srv.pppdir == 0)
- srv.pppdir = "/net";
- if(srv.pppexec == 0)
- srv.pppexec = "/bin/ip/ppp";
- if(myipaddr(srv.ipaddr, srv.pppdir) < 0)
- myfatal("could not read local ip addr: %r");
- if(srv.recvwindow == 0)
- srv.recvwindow = Window;
- }
- void
- greinit(void)
- {
- char addr[100], *p;
- int fd, cfd;
- SDB "srv.tcpdir = %s\n", srv.tcpdir EDB
- strcpy(addr, srv.tcpdir);
- p = strrchr(addr, '/');
- if(p == 0)
- myfatal("bad tcp dir: %s", srv.tcpdir);
- *p = 0;
- p = strrchr(addr, '/');
- if(p == 0)
- myfatal("bad tcp dir: %s", srv.tcpdir);
- sprint(p, "/gre!%I!34827", srv.remote);
- SDB "addr = %s\n", addr EDB
- fd = dial(addr, 0, 0, &cfd);
- if(fd < 0)
- myfatal("%I: dial %s failed: %r", srv.remote, addr);
- srv.grefd = fd;
- srv.grecfd = cfd;
- thread(greread, 0);
- }
- void
- greread(void *v)
- {
- uint8_t buf[Pktsize], *p;
- int n, i;
- int flag, prot, len, callid;
- uint8_t src[IPaddrlen], dst[IPaddrlen];
- uint rseq, ack;
- Call *c;
- static double t, last;
- for(;;) {
- n = read(srv.grefd, buf, sizeof(buf));
- if(n < 0)
- myfatal("%I: bad read on gre: %r", srv.remote);
- if(n == sizeof(buf))
- myfatal("%I: gre read: buf too small", srv.remote);
- p = buf;
- v4tov6(src, p);
- v4tov6(dst, p+4);
- flag = GSHORT(p+8);
- prot = GSHORT(p+10);
- p += 12; n -= 12;
- if(ipcmp(src, srv.remote) != 0 || ipcmp(dst, srv.local) != 0)
- myfatal("%I: gre read bad address src=%I dst=%I", srv.remote, src, dst);
- if(prot != GRE_ppp)
- myfatal("%I: gre read gave bad protocol", srv.remote);
- if(flag & (GRE_chksum|GRE_routing)){
- p += 4; n -= 4;
- }
- if(!(flag&GRE_key))
- myfatal("%I: gre packet does not contain a key: f=%x",
- srv.remote, flag);
- len = GSHORT(p);
- callid = GSHORT(p+2);
- p += 4; n -= 4;
- c = calllookup(callid);
- if(c == 0) {
- SDB "%I: unknown callid: %d\n", srv.remote, callid EDB
- continue;
- }
- qlock(&c->lk);
- c->stat.recv++;
- if(flag&GRE_seq) {
- rseq = GLONG(p);
- p += 4; n -= 4;
- } else
- rseq = c->rseq;
- if(flag&GRE_ack){
- ack = GLONG(p);
- p += 4; n -= 4;
- } else
- ack = c->ack;
- /* skip routing if present */
- if(flag&GRE_routing) {
- while((i=p[3]) != 0) {
- n -= i;
- p += i;
- }
- }
- if(len > n)
- myfatal("%I: bad len in gre packet", srv.remote);
- if((int)(ack-c->ack) > 0) {
- c->ack = ack;
- esignal(&c->eack);
- }
- if(debug)
- t = realtime();
- if(len == 0) {
- /* ack packet */
- c->stat.recvack++;
- SDB "%I: %.3f (%.3f): gre %d: recv ack a=%x n=%d flag=%x\n", srv.remote, t, t-last,
- c->id, ack, n, flag EDB
- } else {
- SDB "%I: %.3f (%.3f): gre %d: recv s=%x a=%x len=%d\n", srv.remote, t, t-last,
- c->id, rseq, ack, len EDB
- /*
- * the following handles the case of a single pair of packets
- * received out of order
- */
- n = rseq-c->rseq;
- if(n > 0 && (drop == 0. || frand() > drop)) {
- c->stat.missing += n-1;
- /* current packet */
- write(c->pppfd, p, len);
- } else {
- /* out of sequence - drop on the floor */
- c->stat.dropped++;
- SDB "%I: %.3f: gre %d: recv out of order or dup packet: seq=%x len=%d\n",
- srv.remote, realtime(), c->id, rseq, len EDB
- }
- }
- if((int)(rseq-c->rseq) > 0)
- c->rseq = rseq;
- if(debug)
- last=t;
- /* open up client window */
- if((int)(c->rseq-c->rack) > (c->recvwindow>>1))
- greack(c);
- qunlock(&c->lk);
- callfree(c);
- }
- }
- void
- greack(Call *c)
- {
- uint8_t buf[20];
- c->stat.sendack++;
- SDB "%I: %.3f: gre %d: send ack %x\n", srv.remote, realtime(), c->id, c->rseq EDB
- v6tov4(buf+0, srv.local); /* source */
- v6tov4(buf+4, srv.remote); /* source */
- PSHORT(buf+8, GRE_key|GRE_ack|1);
- PSHORT(buf+10, GRE_ppp);
- PSHORT(buf+12, 0);
- PSHORT(buf+14, c->id);
- PLONG(buf+16, c->rseq);
- write(srv.grefd, buf, sizeof(buf));
- c->rack = c->rseq;
- }
- void
- gretimeout(void *a)
- {
- Call *c;
- c = a;
- while(!c->closed) {
- sleep(Tick);
- qlock(&c->lk);
- c->tick++;
- qunlock(&c->lk);
- esignal(&c->eack);
- }
- callfree(c);
- exits(0);
- }
- void
- pppread(void *a)
- {
- Call *c;
- uint8_t buf[2000], *p;
- int n;
- uintptr tick;
- c = a;
- for(;;) {
- p = buf+24;
- n = read(c->pppfd, p, sizeof(buf)-24);
- if(n <= 0)
- break;
- qlock(&c->lk);
- /* add gre header */
- c->seq++;
- tick = c->tick;
- while(c->seq-c->ack>c->sendwindow && c->tick-tick<Sendtimeout && !c->closed) {
- c->stat.sendwait++;
- SDB "window full seq = %d ack = %x window = %x\n", c->seq, c->ack, c->sendwindow EDB
- qunlock(&c->lk);
- ewait(&c->eack);
- qlock(&c->lk);
- }
- if(c->tick-tick >= Sendtimeout) {
- c->stat.sendtimeout++;
- SDB "send timeout = %d ack = %x window = %x\n", c->seq, c->ack, c->sendwindow EDB
- }
- v6tov4(buf+0, srv.local); /* source */
- v6tov4(buf+4, srv.remote); /* source */
- PSHORT(buf+8, GRE_key|GRE_seq|GRE_ack|1);
- PSHORT(buf+10, GRE_ppp);
- PSHORT(buf+12, n);
- PSHORT(buf+14, c->id);
- PLONG(buf+16, c->seq);
- PLONG(buf+20, c->rseq);
- c->stat.send++;
- c->rack = c->rseq;
- SDB "%I: %.3f: gre %d: send s=%x a=%x len=%d\n", srv.remote, realtime(),
- c->id, c->seq, c->rseq, n EDB
- if(drop == 0. || frand() > drop)
- if(write(srv.grefd, buf, n+24)<n+24)
- myfatal("pppread: write failed: %r");
- qunlock(&c->lk);
- }
- SDB "pppread exit: %d\n", c->id);
- callfree(c);
- exits(0);
- }
- void
- timeoutthread(void *v)
- {
- for(;;) {
- sleep(30*1000);
- qlock(&srv.lk);
- if(realtime() - srv.rcvtime > 5*60)
- myfatal("server timedout");
- qunlock(&srv.lk);
- }
- }
- /* use syslog() rather than fprint(2, ...) */
- void
- myfatal(char *fmt, ...)
- {
- char sbuf[512];
- va_list arg;
- uint8_t buf[16];
- /* NT don't seem to like us just going away */
- memset(buf, 0, sizeof(buf));
- PSHORT(buf+0, sizeof(buf)); /* length */
- PSHORT(buf+2, 1); /* message type */
- PLONG(buf+4, Magic); /* magic */
- PSHORT(buf+8, Tstop); /* op */
- buf[12] = 3; /* local shutdown */
- write(1, buf, sizeof(buf));
- va_start(arg, fmt);
- vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
- va_end(arg);
- SDB "%I: fatal: %s\n", srv.remote, sbuf EDB
- syslog(0, LOG, ": src=%I: fatal: %s", srv.remote, sbuf);
- close(0);
- close(1);
- close(srv.grefd);
- close(srv.grecfd);
- postnote(PNGROUP, getpid(), "die");
- exits(sbuf);
- }
- int
- argatoi(char *p)
- {
- char *q;
- int i;
- if(p == 0)
- usage();
- i = strtol(p, &q, 0);
- if(q == p)
- usage();
- return i;
- }
- void
- dhcpclientwatch(void *a)
- {
- Call *c = a;
- uint8_t buf[1];
- for(;;) {
- if(read(c->dhcpfd[0], buf, sizeof(buf)) <= 0)
- break;
- }
- if(!c->closed)
- myfatal("dhcpclient terminated");
- callfree(c);
- exits(0);
- }
- int
- ipaddralloc(Call *c)
- {
- int pfd[2][2];
- char *argv[4], *p;
- Biobuf bio;
- argv[0] = "/bin/ip/dhcpclient";
- argv[1] = "-x";
- argv[2] = srv.pppdir;
- argv[3] = 0;
- if(pipe(pfd[0])<0)
- myfatal("ipaddralloc: pipe failed: %r");
- if(pipe(pfd[1])<0)
- myfatal("ipaddralloc: pipe failed: %r");
- if(proc(argv, pfd[0][0], pfd[1][1], 2) < 0)
- myfatal("ipaddralloc: proc failed: %r");
- close(pfd[0][0]);
- close(pfd[1][1]);
- c->dhcpfd[0] = pfd[1][0];
- c->dhcpfd[1] = pfd[0][1];
- Binit(&bio, pfd[1][0], OREAD);
- for(;;) {
- p = Brdline(&bio, '\n');
- if(p == 0)
- break;
- if(strncmp(p, "ip=", 3) == 0) {
- p += 3;
- parseip(c->remoteip, p);
- } else if(strncmp(p, "end\n", 4) == 0)
- break;
- }
- Bterm(&bio);
- c->ref++;
- thread(dhcpclientwatch, c);
- return ipcmp(c->remoteip, IPnoaddr) != 0;
- }
- void
- esignal(Event *e)
- {
- qlock(e);
- if(e->wait == 0) {
- e->ready = 1;
- qunlock(e);
- return;
- }
- assert(e->ready == 0);
- e->wait = 0;
- rendezvous(e, (void*)1);
- qunlock(e);
- }
- void
- ewait(Event *e)
- {
- qlock(&e->waitlk);
- qlock(e);
- assert(e->wait == 0);
- if(e->ready) {
- e->ready = 0;
- } else {
- e->wait = 1;
- qunlock(e);
- rendezvous(e, (void*)2);
- qlock(e);
- }
- qunlock(e);
- qunlock(&e->waitlk);
- }
- uint32_t
- thread(void(*f)(void*), void *a)
- {
- int pid;
- pid=rfork(RFNOWAIT|RFMEM|RFPROC);
- if(pid < 0)
- myfatal("rfork failed: %r");
- if(pid != 0)
- return pid;
- (*f)(a);
- return 0; // never reaches here
- }
- double
- realtime(void)
- {
- int32_t times(int32_t*);
- return times(0) / 1000.0;
- }
- void *
- emallocz(int size)
- {
- void *p;
- p = malloc(size);
- if(p == 0)
- myfatal("malloc failed: %r");
- memset(p, 0, size);
- return p;
- }
- static void
- fdclose(void)
- {
- int fd, n, i;
- Dir *d, *p;
- if((fd = open("#d", OREAD)) < 0)
- return;
- n = dirreadall(fd, &d);
- for(p = d; n > 0; n--, p++) {
- i = atoi(p->name);
- if(i > 2)
- close(i);
- }
- free(d);
- }
- int
- proc(char **argv, int fd0, int fd1, int fd2)
- {
- int r, flag;
- char *arg0, file[200];
- arg0 = argv[0];
- strcpy(file, arg0);
- if(access(file, 1) < 0) {
- if(strncmp(arg0, "/", 1)==0
- || strncmp(arg0, "#", 1)==0
- || strncmp(arg0, "./", 2)==0
- || strncmp(arg0, "../", 3)==0)
- return 0;
- sprint(file, "/bin/%s", arg0);
- if(access(file, 1) < 0)
- return 0;
- }
- flag = RFPROC|RFFDG|RFENVG|RFNOWAIT;
- if((r = rfork(flag)) != 0) {
- if(r < 0)
- return 0;
- return r;
- }
- if(fd0 != 0) {
- if(fd1 == 0)
- fd1 = dup(0, -1);
- if(fd2 == 0)
- fd2 = dup(0, -1);
- close(0);
- if(fd0 >= 0)
- dup(fd0, 0);
- }
- if(fd1 != 1) {
- if(fd2 == 1)
- fd2 = dup(1, -1);
- close(1);
- if(fd1 >= 0)
- dup(fd1, 1);
- }
- if(fd2 != 2) {
- close(2);
- if(fd2 >= 0)
- dup(fd2, 2);
- }
- fdclose();
- exec(file, argv);
- myfatal("proc: exec failed: %r");
- return 0;
- }
|