/* * 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 */ ulong tick; uchar 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; uchar local[IPaddrlen]; uchar remote[IPaddrlen]; char *tcpdir; uchar 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), (p)[1]=(v))#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(uchar*, int);int sstop(uchar*, int);int secho(uchar*, int);int scallout(uchar*, int);int scallreq(uchar*, int);int scallcon(uchar*, int);int scallclear(uchar*, int);int scalldis(uchar*, int);int swaninfo(uchar*, int);int slinkinfo(uchar*, 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);ulong thread(void(*f)(void*), void *a); voidmain(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);} voidusage(void){ fprint(2, "usage: pptpd [-dD] [-p ppp-net] [-w window] tcpdir\n"); exits("usage");} voidserve(void){ uchar 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); } } intsstart(uchar *p, int n){ int ver, frame, bearer, maxchan, firm; char host[64], vendor[64], *sysname; uchar 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;} intsstop(uchar *p, int n){ int reason; uchar 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;} intsecho(uchar *p, int n){ int id; uchar 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;} intscallout(uchar *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 */ Lines 1–500 of 1350. Load more
/* * 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 */ ulong tick; uchar 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; uchar local[IPaddrlen]; uchar remote[IPaddrlen]; char *tcpdir; uchar 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), (p)[1]=(v)) #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(uchar*, int); int sstop(uchar*, int); int secho(uchar*, int); int scallout(uchar*, int); int scallreq(uchar*, int); int scallcon(uchar*, int); int scallclear(uchar*, int); int scalldis(uchar*, int); int swaninfo(uchar*, int); int slinkinfo(uchar*, 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); ulong 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) { uchar 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(uchar *p, int n) { int ver, frame, bearer, maxchan, firm; char host[64], vendor[64], *sysname; uchar 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(uchar *p, int n) { int reason; uchar 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(uchar *p, int n) { int id; uchar 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(uchar *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 */