17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <ip.h>
57dd7cddfSDavid du Colombier
67dd7cddfSDavid du Colombier #define LOG "pptpd"
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier typedef struct Call Call;
97dd7cddfSDavid du Colombier typedef struct Event Event;
107dd7cddfSDavid du Colombier
117dd7cddfSDavid du Colombier #define SDB if(debug) fprint(2,
127dd7cddfSDavid du Colombier #define EDB );
137dd7cddfSDavid du Colombier
147dd7cddfSDavid du Colombier enum {
157dd7cddfSDavid du Colombier Magic = 0x1a2b3c4d,
167dd7cddfSDavid du Colombier Nhash = 17,
177dd7cddfSDavid du Colombier Nchan = 10, /* maximum number of channels */
187dd7cddfSDavid du Colombier Window = 8, /* default window size */
197dd7cddfSDavid du Colombier Timeout = 60, /* timeout in seconds for control channel */
207dd7cddfSDavid du Colombier Pktsize = 2000, /* maximum packet size */
217dd7cddfSDavid du Colombier Tick = 500, /* tick length in milliseconds */
227dd7cddfSDavid du Colombier Sendtimeout = 4, /* in ticks */
237dd7cddfSDavid du Colombier };
247dd7cddfSDavid du Colombier
257dd7cddfSDavid du Colombier enum {
267dd7cddfSDavid du Colombier Syncframe = 0x1,
277dd7cddfSDavid du Colombier Asyncframe = 0x2,
287dd7cddfSDavid du Colombier Analog = 0x1,
297dd7cddfSDavid du Colombier Digital = 0x2,
307dd7cddfSDavid du Colombier Version = 0x100,
317dd7cddfSDavid du Colombier };
327dd7cddfSDavid du Colombier
337dd7cddfSDavid du Colombier enum {
347dd7cddfSDavid du Colombier Tstart = 1,
357dd7cddfSDavid du Colombier Rstart = 2,
367dd7cddfSDavid du Colombier Tstop = 3,
377dd7cddfSDavid du Colombier Rstop = 4,
387dd7cddfSDavid du Colombier Techo = 5,
397dd7cddfSDavid du Colombier Recho = 6,
407dd7cddfSDavid du Colombier Tcallout = 7,
417dd7cddfSDavid du Colombier Rcallout = 8,
427dd7cddfSDavid du Colombier Tcallreq = 9,
437dd7cddfSDavid du Colombier Rcallreq = 10,
447dd7cddfSDavid du Colombier Acallcon = 11,
457dd7cddfSDavid du Colombier Tcallclear = 12,
467dd7cddfSDavid du Colombier Acalldis = 13,
477dd7cddfSDavid du Colombier Awaninfo = 14,
487dd7cddfSDavid du Colombier Alinkinfo = 15,
497dd7cddfSDavid du Colombier };
507dd7cddfSDavid du Colombier
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier struct Event {
537dd7cddfSDavid du Colombier QLock;
547dd7cddfSDavid du Colombier QLock waitlk;
557dd7cddfSDavid du Colombier int wait;
567dd7cddfSDavid du Colombier int ready;
577dd7cddfSDavid du Colombier };
587dd7cddfSDavid du Colombier
597dd7cddfSDavid du Colombier struct Call {
607dd7cddfSDavid du Colombier int ref;
617dd7cddfSDavid du Colombier QLock lk;
627dd7cddfSDavid du Colombier int id;
637dd7cddfSDavid du Colombier int serial;
647dd7cddfSDavid du Colombier int pppfd;
657dd7cddfSDavid du Colombier
667dd7cddfSDavid du Colombier int closed;
677dd7cddfSDavid du Colombier
687dd7cddfSDavid du Colombier int pac; /* server is acting as a PAC */
697dd7cddfSDavid du Colombier
707dd7cddfSDavid du Colombier int recvwindow; /* recv windows */
717dd7cddfSDavid du Colombier int sendwindow; /* send windows */
727dd7cddfSDavid du Colombier int delay;
737dd7cddfSDavid du Colombier
747dd7cddfSDavid du Colombier int sendaccm;
757dd7cddfSDavid du Colombier int recvaccm;
767dd7cddfSDavid du Colombier
777dd7cddfSDavid du Colombier uint seq; /* current seq number - for send */
787dd7cddfSDavid du Colombier uint ack; /* current acked mesg - for send */
797dd7cddfSDavid du Colombier uint rseq; /* highest recv seq number for in order packet */
807dd7cddfSDavid du Colombier uint rack; /* highest ack sent */
817dd7cddfSDavid du Colombier
827dd7cddfSDavid du Colombier Event eack; /* recved ack - for send */
837dd7cddfSDavid du Colombier ulong tick;
847dd7cddfSDavid du Colombier
857dd7cddfSDavid du Colombier uchar remoteip[IPaddrlen]; /* remote ip address */
867dd7cddfSDavid du Colombier int dhcpfd[2]; /* pipe to dhcpclient */
877dd7cddfSDavid du Colombier
887dd7cddfSDavid du Colombier /* error stats */
897dd7cddfSDavid du Colombier struct {
907dd7cddfSDavid du Colombier int crc;
917dd7cddfSDavid du Colombier int frame;
927dd7cddfSDavid du Colombier int hardware;
937dd7cddfSDavid du Colombier int overrun;
947dd7cddfSDavid du Colombier int timeout;
957dd7cddfSDavid du Colombier int align;
967dd7cddfSDavid du Colombier } err;
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier struct {
997dd7cddfSDavid du Colombier int send;
1007dd7cddfSDavid du Colombier int sendack;
1017dd7cddfSDavid du Colombier int recv;
1027dd7cddfSDavid du Colombier int recvack;
1037dd7cddfSDavid du Colombier int dropped;
1047dd7cddfSDavid du Colombier int missing;
1057dd7cddfSDavid du Colombier int sendwait;
1067dd7cddfSDavid du Colombier int sendtimeout;
1077dd7cddfSDavid du Colombier } stat;
1087dd7cddfSDavid du Colombier
1097dd7cddfSDavid du Colombier Call *next;
1107dd7cddfSDavid du Colombier };
1117dd7cddfSDavid du Colombier
1127dd7cddfSDavid du Colombier struct {
1137dd7cddfSDavid du Colombier QLock lk;
1147dd7cddfSDavid du Colombier int start;
1157dd7cddfSDavid du Colombier int grefd;
1167dd7cddfSDavid du Colombier int grecfd;
1177dd7cddfSDavid du Colombier uchar local[IPaddrlen];
1187dd7cddfSDavid du Colombier uchar remote[IPaddrlen];
1197dd7cddfSDavid du Colombier char *tcpdir;
1207dd7cddfSDavid du Colombier uchar ipaddr[IPaddrlen]; /* starting ip addresss to allocate */
1217dd7cddfSDavid du Colombier
1227dd7cddfSDavid du Colombier int recvwindow;
1237dd7cddfSDavid du Colombier
1247dd7cddfSDavid du Colombier char *pppdir;
12580ee5cbfSDavid du Colombier char *pppexec;
1267dd7cddfSDavid du Colombier
1277dd7cddfSDavid du Colombier double rcvtime; /* time at which last request was received */
1287dd7cddfSDavid du Colombier int echoid; /* id of last echo request */
1297dd7cddfSDavid du Colombier
1307dd7cddfSDavid du Colombier Call *hash[Nhash];
1317dd7cddfSDavid du Colombier } srv;
1327dd7cddfSDavid du Colombier
1337dd7cddfSDavid du Colombier /* GRE flag bits */
1347dd7cddfSDavid du Colombier enum {
1357dd7cddfSDavid du Colombier GRE_chksum = (1<<15),
1367dd7cddfSDavid du Colombier GRE_routing = (1<<14),
1377dd7cddfSDavid du Colombier GRE_key = (1<<13),
1387dd7cddfSDavid du Colombier GRE_seq = (1<<12),
1397dd7cddfSDavid du Colombier GRE_srcrt = (1<<11),
1407dd7cddfSDavid du Colombier GRE_recur = (7<<8),
1417dd7cddfSDavid du Colombier GRE_ack = (1<<7),
1427dd7cddfSDavid du Colombier GRE_ver = 0x7,
1437dd7cddfSDavid du Colombier };
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier /* GRE protocols */
1467dd7cddfSDavid du Colombier enum {
1477dd7cddfSDavid du Colombier GRE_ppp = 0x880b,
1487dd7cddfSDavid du Colombier };
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier int debug;
1517dd7cddfSDavid du Colombier double drop;
1527dd7cddfSDavid du Colombier
1537dd7cddfSDavid du Colombier void myfatal(char *fmt, ...);
1547dd7cddfSDavid du Colombier
1557dd7cddfSDavid du Colombier #define PSHORT(p, v) ((p)[0]=((v)>>8), (p)[1]=(v))
1567dd7cddfSDavid du Colombier #define PLONG(p, v) (PSHORT(p, (v)>>16), PSHORT(p+2, (v)))
1577dd7cddfSDavid du Colombier #define PSTRING(d,s,n) strncpy((char*)(d), s, n)
1587dd7cddfSDavid du Colombier #define GSHORT(p) (((p)[0]<<8) | ((p)[1]<<0))
1597dd7cddfSDavid du Colombier #define GLONG(p) ((GSHORT((p))<<16) | ((GSHORT((p)+2))<<0))
1607dd7cddfSDavid du Colombier #define GSTRING(d,s,n) strncpy(d, (char*)(s), n), d[(n)-1] = 0
1617dd7cddfSDavid du Colombier
1627dd7cddfSDavid du Colombier void serve(void);
1637dd7cddfSDavid du Colombier
1647dd7cddfSDavid du Colombier int sstart(uchar*, int);
1657dd7cddfSDavid du Colombier int sstop(uchar*, int);
1667dd7cddfSDavid du Colombier int secho(uchar*, int);
1677dd7cddfSDavid du Colombier int scallout(uchar*, int);
1687dd7cddfSDavid du Colombier int scallreq(uchar*, int);
1697dd7cddfSDavid du Colombier int scallcon(uchar*, int);
1707dd7cddfSDavid du Colombier int scallclear(uchar*, int);
1717dd7cddfSDavid du Colombier int scalldis(uchar*, int);
1727dd7cddfSDavid du Colombier int swaninfo(uchar*, int);
1737dd7cddfSDavid du Colombier int slinkinfo(uchar*, int);
1747dd7cddfSDavid du Colombier
1757dd7cddfSDavid du Colombier Call *callalloc(int id);
1767dd7cddfSDavid du Colombier void callclose(Call*);
1777dd7cddfSDavid du Colombier void callfree(Call*);
1787dd7cddfSDavid du Colombier Call *calllookup(int id);
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier void gretimeout(void*);
1817dd7cddfSDavid du Colombier void pppread(void*);
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier void srvinit(void);
1847dd7cddfSDavid du Colombier void greinit(void);
1857dd7cddfSDavid du Colombier void greread(void*);
1867dd7cddfSDavid du Colombier void greack(Call *c);
1877dd7cddfSDavid du Colombier
1887dd7cddfSDavid du Colombier void timeoutthread(void*);
1897dd7cddfSDavid du Colombier
1907dd7cddfSDavid du Colombier int argatoi(char *p);
1917dd7cddfSDavid du Colombier void usage(void);
1927dd7cddfSDavid du Colombier int ipaddralloc(Call *c);
1937dd7cddfSDavid du Colombier
194*ea58ad6fSDavid du Colombier void *emallocz(int size);
1957dd7cddfSDavid du Colombier void esignal(Event *e);
1967dd7cddfSDavid du Colombier void ewait(Event *e);
1977dd7cddfSDavid du Colombier int proc(char **argv, int fd0, int fd1, int fd2);
198*ea58ad6fSDavid du Colombier double realtime(void);
199*ea58ad6fSDavid du Colombier ulong thread(void(*f)(void*), void *a);
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier void
main(int argc,char * argv[])2027dd7cddfSDavid du Colombier main(int argc, char *argv[])
2037dd7cddfSDavid du Colombier {
2047dd7cddfSDavid du Colombier ARGBEGIN{
2057dd7cddfSDavid du Colombier case 'd': debug++; break;
2067dd7cddfSDavid du Colombier case 'p': srv.pppdir = ARGF(); break;
20780ee5cbfSDavid du Colombier case 'P': srv.pppexec = ARGF(); break;
2087dd7cddfSDavid du Colombier case 'w': srv.recvwindow = argatoi(ARGF()); break;
2097dd7cddfSDavid du Colombier case 'D': drop = atof(ARGF()); break;
2107dd7cddfSDavid du Colombier default:
2117dd7cddfSDavid du Colombier usage();
2127dd7cddfSDavid du Colombier }ARGEND
2137dd7cddfSDavid du Colombier
2149a747e4fSDavid du Colombier fmtinstall('I', eipfmt);
2159a747e4fSDavid du Colombier fmtinstall('E', eipfmt);
2169a747e4fSDavid du Colombier fmtinstall('V', eipfmt);
2179a747e4fSDavid du Colombier fmtinstall('M', eipfmt);
2187dd7cddfSDavid du Colombier
2197dd7cddfSDavid du Colombier rfork(RFNOTEG|RFREND);
2207dd7cddfSDavid du Colombier
2217dd7cddfSDavid du Colombier if(argc != 1)
2227dd7cddfSDavid du Colombier usage();
2237dd7cddfSDavid du Colombier
2247dd7cddfSDavid du Colombier srv.tcpdir = argv[0];
2257dd7cddfSDavid du Colombier
2267dd7cddfSDavid du Colombier srvinit();
2277dd7cddfSDavid du Colombier
2287dd7cddfSDavid du Colombier syslog(0, LOG, ": src=%I: pptp started: %d", srv.remote, getpid());
2297dd7cddfSDavid du Colombier
2307dd7cddfSDavid du Colombier SDB "\n\n\n%I: pptp started\n", srv.remote EDB
2317dd7cddfSDavid du Colombier
2327dd7cddfSDavid du Colombier greinit();
2337dd7cddfSDavid du Colombier
2347dd7cddfSDavid du Colombier thread(timeoutthread, 0);
2357dd7cddfSDavid du Colombier
2367dd7cddfSDavid du Colombier serve();
2377dd7cddfSDavid du Colombier
2387dd7cddfSDavid du Colombier syslog(0, LOG, ": src=%I: server exits", srv.remote);
2397dd7cddfSDavid du Colombier
2407dd7cddfSDavid du Colombier exits(0);
2417dd7cddfSDavid du Colombier }
2427dd7cddfSDavid du Colombier
2437dd7cddfSDavid du Colombier void
usage(void)2447dd7cddfSDavid du Colombier usage(void)
2457dd7cddfSDavid du Colombier {
24659cc4ca5SDavid du Colombier fprint(2, "usage: pptpd [-dD] [-p ppp-net] [-w window] tcpdir\n");
2477dd7cddfSDavid du Colombier exits("usage");
2487dd7cddfSDavid du Colombier }
2497dd7cddfSDavid du Colombier
2507dd7cddfSDavid du Colombier void
serve(void)2517dd7cddfSDavid du Colombier serve(void)
2527dd7cddfSDavid du Colombier {
2537dd7cddfSDavid du Colombier uchar buf[2000], *p;
2547dd7cddfSDavid du Colombier int n, n2, len;
2557dd7cddfSDavid du Colombier int magic;
2567dd7cddfSDavid du Colombier int op, type;
2577dd7cddfSDavid du Colombier
2587dd7cddfSDavid du Colombier n = 0;
2597dd7cddfSDavid du Colombier for(;;) {
2607dd7cddfSDavid du Colombier n2 = read(0, buf+n, sizeof(buf)-n);
2617dd7cddfSDavid du Colombier if(n2 < 0)
2627dd7cddfSDavid du Colombier myfatal("bad read on ctl channel: %r");
2637dd7cddfSDavid du Colombier if(n2 == 0)
2647dd7cddfSDavid du Colombier break;
2657dd7cddfSDavid du Colombier n += n2;
2667dd7cddfSDavid du Colombier p = buf;
2677dd7cddfSDavid du Colombier for(;;) {
2687dd7cddfSDavid du Colombier if(n < 12)
2697dd7cddfSDavid du Colombier break;
2707dd7cddfSDavid du Colombier
2717dd7cddfSDavid du Colombier qlock(&srv.lk);
2727dd7cddfSDavid du Colombier srv.rcvtime = realtime();
2737dd7cddfSDavid du Colombier qunlock(&srv.lk);
2747dd7cddfSDavid du Colombier
2757dd7cddfSDavid du Colombier len = GSHORT(p);
2767dd7cddfSDavid du Colombier type = GSHORT(p+2);
2777dd7cddfSDavid du Colombier magic = GLONG(p+4);
2787dd7cddfSDavid du Colombier op = GSHORT(p+8);
2797dd7cddfSDavid du Colombier if(magic != Magic)
2807dd7cddfSDavid du Colombier myfatal("bad magic number: got %x", magic);
2817dd7cddfSDavid du Colombier if(type != 1)
2827dd7cddfSDavid du Colombier myfatal("bad message type: %d", type);
2837dd7cddfSDavid du Colombier switch(op) {
2847dd7cddfSDavid du Colombier default:
2857dd7cddfSDavid du Colombier myfatal("unknown control op: %d", op);
2867dd7cddfSDavid du Colombier case Tstart: /* start-control-connection-request */
2877dd7cddfSDavid du Colombier n2 = sstart(p, n);
2887dd7cddfSDavid du Colombier break;
2897dd7cddfSDavid du Colombier case Tstop:
2907dd7cddfSDavid du Colombier n2 = sstop(p, n);
2917dd7cddfSDavid du Colombier if(n2 > 0)
2927dd7cddfSDavid du Colombier return;
2937dd7cddfSDavid du Colombier break;
2947dd7cddfSDavid du Colombier case Techo:
2957dd7cddfSDavid du Colombier n2 = secho(p, n);
2967dd7cddfSDavid du Colombier break;
2977dd7cddfSDavid du Colombier case Tcallout:
2987dd7cddfSDavid du Colombier n2 = scallout(p, n);
2997dd7cddfSDavid du Colombier break;
3007dd7cddfSDavid du Colombier case Tcallreq:
3017dd7cddfSDavid du Colombier n2 = scallreq(p, n);
3027dd7cddfSDavid du Colombier break;
3037dd7cddfSDavid du Colombier case Acallcon:
3047dd7cddfSDavid du Colombier n2 = scallcon(p, n);
3057dd7cddfSDavid du Colombier break;
3067dd7cddfSDavid du Colombier case Tcallclear:
3077dd7cddfSDavid du Colombier n2 = scallclear(p, n);
3087dd7cddfSDavid du Colombier break;
3097dd7cddfSDavid du Colombier case Acalldis:
3107dd7cddfSDavid du Colombier n2 = scalldis(p, n);
3117dd7cddfSDavid du Colombier break;
3127dd7cddfSDavid du Colombier case Awaninfo:
3137dd7cddfSDavid du Colombier n2 = swaninfo(p, n);
3147dd7cddfSDavid du Colombier break;
3157dd7cddfSDavid du Colombier case Alinkinfo:
3167dd7cddfSDavid du Colombier n2 = slinkinfo(p, n);
3177dd7cddfSDavid du Colombier break;
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier if(n2 == 0)
3207dd7cddfSDavid du Colombier break;
3217dd7cddfSDavid du Colombier if(n2 != len)
3227dd7cddfSDavid du Colombier myfatal("op=%d: bad length: got %d expected %d", op, len, n2);
3237dd7cddfSDavid du Colombier n -= n2;
3247dd7cddfSDavid du Colombier p += n2;
3257dd7cddfSDavid du Colombier
3267dd7cddfSDavid du Colombier }
3277dd7cddfSDavid du Colombier
3287dd7cddfSDavid du Colombier /* move down partial message */
3297dd7cddfSDavid du Colombier if(p != buf && n != 0)
3307dd7cddfSDavid du Colombier memmove(buf, p, n);
3317dd7cddfSDavid du Colombier }
3327dd7cddfSDavid du Colombier
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier
3357dd7cddfSDavid du Colombier int
sstart(uchar * p,int n)3367dd7cddfSDavid du Colombier sstart(uchar *p, int n)
3377dd7cddfSDavid du Colombier {
3387dd7cddfSDavid du Colombier int ver, frame, bearer, maxchan, firm;
3397dd7cddfSDavid du Colombier char host[64], vendor[64], *sysname;
3407dd7cddfSDavid du Colombier uchar buf[156];
3417dd7cddfSDavid du Colombier
3427dd7cddfSDavid du Colombier if(n < 156)
3437dd7cddfSDavid du Colombier return 0;
3447dd7cddfSDavid du Colombier ver = GSHORT(p+12);
3457dd7cddfSDavid du Colombier frame = GLONG(p+16);
3467dd7cddfSDavid du Colombier bearer = GLONG(p+20);
3477dd7cddfSDavid du Colombier maxchan = GSHORT(p+24);
3487dd7cddfSDavid du Colombier firm = GSHORT(p+26);
3497dd7cddfSDavid du Colombier GSTRING(host, p+28, 64);
3507dd7cddfSDavid du Colombier GSTRING(vendor, p+92, 64);
3517dd7cddfSDavid du Colombier
3527dd7cddfSDavid du Colombier SDB "%I: start ver = %x f = %d b = %d maxchan = %d firm = %d host = %s vendor = %s\n",
3537dd7cddfSDavid du Colombier srv.remote, ver, frame, bearer, maxchan, firm, host, vendor EDB
3547dd7cddfSDavid du Colombier
3557dd7cddfSDavid du Colombier if(ver != Version)
3567dd7cddfSDavid du Colombier myfatal("bad version: got %x expected %x", ver, Version);
3577dd7cddfSDavid du Colombier
3587dd7cddfSDavid du Colombier if(srv.start)
3597dd7cddfSDavid du Colombier myfatal("multiple start messages");
3607dd7cddfSDavid du Colombier
3617dd7cddfSDavid du Colombier srv.start = 1;
3627dd7cddfSDavid du Colombier
3637dd7cddfSDavid du Colombier sysname = getenv("sysname");
3647dd7cddfSDavid du Colombier if(sysname == 0)
3657dd7cddfSDavid du Colombier strcpy(host, "gnot");
3667dd7cddfSDavid du Colombier else
3677dd7cddfSDavid du Colombier strncpy(host, sysname, 64);
3687dd7cddfSDavid du Colombier free(sysname);
3697dd7cddfSDavid du Colombier
3707dd7cddfSDavid du Colombier memset(buf, 0, sizeof(buf));
3717dd7cddfSDavid du Colombier
3727dd7cddfSDavid du Colombier PSHORT(buf+0, sizeof(buf)); /* length */
3737dd7cddfSDavid du Colombier PSHORT(buf+2, 1); /* message type */
3747dd7cddfSDavid du Colombier PLONG(buf+4, Magic); /* magic */
3757dd7cddfSDavid du Colombier PSHORT(buf+8, Rstart); /* op */
3767dd7cddfSDavid du Colombier PSHORT(buf+12, Version); /* version */
3777dd7cddfSDavid du Colombier buf[14] = 1; /* result = ok */
3787dd7cddfSDavid du Colombier PLONG(buf+16, Syncframe|Asyncframe); /* frameing */
3797dd7cddfSDavid du Colombier PLONG(buf+20, Digital|Analog); /* berear capabilities */
3807dd7cddfSDavid du Colombier PSHORT(buf+24, Nchan); /* max channels */
3817dd7cddfSDavid du Colombier PSHORT(buf+26, 1); /* driver version */
3827dd7cddfSDavid du Colombier PSTRING(buf+28, host, 64); /* host name */
3837dd7cddfSDavid du Colombier PSTRING(buf+92, "plan 9", 64); /* vendor */
3847dd7cddfSDavid du Colombier
3857dd7cddfSDavid du Colombier if(write(1, buf, sizeof(buf)) < sizeof(buf))
3867dd7cddfSDavid du Colombier myfatal("write failed: %r");
3877dd7cddfSDavid du Colombier
3887dd7cddfSDavid du Colombier return 156;
3897dd7cddfSDavid du Colombier }
3907dd7cddfSDavid du Colombier
3917dd7cddfSDavid du Colombier int
sstop(uchar * p,int n)3927dd7cddfSDavid du Colombier sstop(uchar *p, int n)
3937dd7cddfSDavid du Colombier {
3947dd7cddfSDavid du Colombier int reason;
3957dd7cddfSDavid du Colombier uchar buf[16];
3967dd7cddfSDavid du Colombier
3977dd7cddfSDavid du Colombier if(n < 16)
3987dd7cddfSDavid du Colombier return 0;
3997dd7cddfSDavid du Colombier reason = p[12];
4007dd7cddfSDavid du Colombier
4017dd7cddfSDavid du Colombier SDB "%I: stop %d\n", srv.remote, reason EDB
4027dd7cddfSDavid du Colombier
4037dd7cddfSDavid du Colombier memset(buf, 0, sizeof(buf));
4047dd7cddfSDavid du Colombier PSHORT(buf+0, sizeof(buf)); /* length */
4057dd7cddfSDavid du Colombier PSHORT(buf+2, 1); /* message type */
4067dd7cddfSDavid du Colombier PLONG(buf+4, Magic); /* magic */
4077dd7cddfSDavid du Colombier PSHORT(buf+8, Rstop); /* op */
4087dd7cddfSDavid du Colombier buf[12] = 1; /* ok */
4097dd7cddfSDavid du Colombier
4107dd7cddfSDavid du Colombier if(write(1, buf, sizeof(buf)) < sizeof(buf))
4117dd7cddfSDavid du Colombier myfatal("write failed: %r");
4127dd7cddfSDavid du Colombier
4137dd7cddfSDavid du Colombier return 16;
4147dd7cddfSDavid du Colombier }
4157dd7cddfSDavid du Colombier
4167dd7cddfSDavid du Colombier int
secho(uchar * p,int n)4177dd7cddfSDavid du Colombier secho(uchar *p, int n)
4187dd7cddfSDavid du Colombier {
4197dd7cddfSDavid du Colombier int id;
4207dd7cddfSDavid du Colombier uchar buf[20];
4217dd7cddfSDavid du Colombier
4227dd7cddfSDavid du Colombier if(n < 16)
4237dd7cddfSDavid du Colombier return 0;
4247dd7cddfSDavid du Colombier id = GLONG(p+12);
4257dd7cddfSDavid du Colombier
4267dd7cddfSDavid du Colombier SDB "%I: echo %d\n", srv.remote, id EDB
4277dd7cddfSDavid du Colombier
4287dd7cddfSDavid du Colombier memset(buf, 0, sizeof(buf));
4297dd7cddfSDavid du Colombier PSHORT(buf+0, sizeof(buf)); /* length */
4307dd7cddfSDavid du Colombier PSHORT(buf+2, 1); /* message type */
4317dd7cddfSDavid du Colombier PLONG(buf+4, Magic); /* magic */
4327dd7cddfSDavid du Colombier PSHORT(buf+8, Recho); /* op */
4337dd7cddfSDavid du Colombier PLONG(buf+12, id); /* id */
4347dd7cddfSDavid du Colombier p[16] = 1; /* ok */
4357dd7cddfSDavid du Colombier
4367dd7cddfSDavid du Colombier if(write(1, buf, sizeof(buf)) < sizeof(buf))
4377dd7cddfSDavid du Colombier myfatal("write failed: %r");
4387dd7cddfSDavid du Colombier
4397dd7cddfSDavid du Colombier return 16;
4407dd7cddfSDavid du Colombier }
4417dd7cddfSDavid du Colombier
4427dd7cddfSDavid du Colombier int
scallout(uchar * p,int n)4437dd7cddfSDavid du Colombier scallout(uchar *p, int n)
4447dd7cddfSDavid du Colombier {
4457dd7cddfSDavid du Colombier int id, serial;
4467dd7cddfSDavid du Colombier int minbps, maxbps, bearer, frame;
4477dd7cddfSDavid du Colombier int window, delay;
4487dd7cddfSDavid du Colombier int nphone;
4497dd7cddfSDavid du Colombier char phone[64], sub[64], buf[32];
4507dd7cddfSDavid du Colombier Call *c;
4517dd7cddfSDavid du Colombier
4527dd7cddfSDavid du Colombier if(n < 168)
4537dd7cddfSDavid du Colombier return 0;
4547dd7cddfSDavid du Colombier
4557dd7cddfSDavid du Colombier if(!srv.start)
4567dd7cddfSDavid du Colombier myfatal("%I: did not recieve start message", srv.remote);
4577dd7cddfSDavid du Colombier
4587dd7cddfSDavid du Colombier id = GSHORT(p+12);
4597dd7cddfSDavid du Colombier serial = GSHORT(p+14);
4607dd7cddfSDavid du Colombier minbps = GLONG(p+16);
4617dd7cddfSDavid du Colombier maxbps = GLONG(p+20);
4627dd7cddfSDavid du Colombier bearer = GLONG(p+24);
4637dd7cddfSDavid du Colombier frame = GLONG(p+28);
4647dd7cddfSDavid du Colombier window = GSHORT(p+32);
4657dd7cddfSDavid du Colombier delay = GSHORT(p+34);
4667dd7cddfSDavid du Colombier nphone = GSHORT(p+36);
4677dd7cddfSDavid du Colombier GSTRING(phone, p+40, 64);
4687dd7cddfSDavid du Colombier GSTRING(sub, p+104, 64);
4697dd7cddfSDavid du Colombier
4707dd7cddfSDavid du Colombier 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",
4717dd7cddfSDavid du Colombier srv.remote, id, serial, minbps, maxbps, bearer, frame, window, delay, nphone, phone, sub EDB
4727dd7cddfSDavid du Colombier
4737dd7cddfSDavid du Colombier c = callalloc(id);
4747dd7cddfSDavid du Colombier c->sendwindow = window;
4757dd7cddfSDavid du Colombier c->delay = delay;
4767dd7cddfSDavid du Colombier c->pac = 1;
4777dd7cddfSDavid du Colombier c->recvwindow = srv.recvwindow;
4787dd7cddfSDavid du Colombier
4797dd7cddfSDavid du Colombier memset(buf, 0, sizeof(buf));
4807dd7cddfSDavid du Colombier PSHORT(buf+0, sizeof(buf)); /* length */
4817dd7cddfSDavid du Colombier PSHORT(buf+2, 1); /* message type */
4827dd7cddfSDavid du Colombier PLONG(buf+4, Magic); /* magic */
4837dd7cddfSDavid du Colombier PSHORT(buf+8, Rcallout); /* op */
4847dd7cddfSDavid du Colombier PSHORT(buf+12, id); /* call id */
4857dd7cddfSDavid du Colombier PSHORT(buf+14, id); /* peer id */
4867dd7cddfSDavid du Colombier buf[16] = 1; /* ok */
4877dd7cddfSDavid du Colombier PLONG(buf+20, 10000000); /* speed */
4887dd7cddfSDavid du Colombier PSHORT(buf+24, c->recvwindow); /* window size */
4897dd7cddfSDavid du Colombier PSHORT(buf+26, 0); /* delay */
4907dd7cddfSDavid du Colombier PLONG(buf+28, 0); /* channel id */
4917dd7cddfSDavid du Colombier
4927dd7cddfSDavid du Colombier if(write(1, buf, sizeof(buf)) < sizeof(buf))
4937dd7cddfSDavid du Colombier myfatal("write failed: %r");
4947dd7cddfSDavid du Colombier
4957dd7cddfSDavid du Colombier return 168;
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier
4987dd7cddfSDavid du Colombier int
scallreq(uchar * p,int n)4997dd7cddfSDavid du Colombier scallreq(uchar *p, int n)
5007dd7cddfSDavid du Colombier {
5017dd7cddfSDavid du Colombier USED(p);
5027dd7cddfSDavid du Colombier USED(n);
5037dd7cddfSDavid du Colombier
5047dd7cddfSDavid du Colombier myfatal("callreq: not done yet");
5057dd7cddfSDavid du Colombier return 0;
5067dd7cddfSDavid du Colombier }
5077dd7cddfSDavid du Colombier
5087dd7cddfSDavid du Colombier int
scallcon(uchar * p,int n)5097dd7cddfSDavid du Colombier scallcon(uchar *p, int n)
5107dd7cddfSDavid du Colombier {
5117dd7cddfSDavid du Colombier USED(p);
5127dd7cddfSDavid du Colombier USED(n);
5137dd7cddfSDavid du Colombier
5147dd7cddfSDavid du Colombier myfatal("callcon: not done yet");
5157dd7cddfSDavid du Colombier return 0;
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier
5187dd7cddfSDavid du Colombier int
scallclear(uchar * p,int n)5197dd7cddfSDavid du Colombier scallclear(uchar *p, int n)
5207dd7cddfSDavid du Colombier {
5217dd7cddfSDavid du Colombier Call *c;
5227dd7cddfSDavid du Colombier int id;
5237dd7cddfSDavid du Colombier uchar buf[148];
5247dd7cddfSDavid du Colombier
5257dd7cddfSDavid du Colombier if(n < 16)
5267dd7cddfSDavid du Colombier return 0;
5277dd7cddfSDavid du Colombier id = GSHORT(p+12);
5287dd7cddfSDavid du Colombier
5297dd7cddfSDavid du Colombier SDB "%I: callclear id=%d\n", srv.remote, id EDB
5307dd7cddfSDavid du Colombier
5317dd7cddfSDavid du Colombier if(c = calllookup(id)) {
5327dd7cddfSDavid du Colombier callclose(c);
5337dd7cddfSDavid du Colombier callfree(c);
5347dd7cddfSDavid du Colombier }
5357dd7cddfSDavid du Colombier
5367dd7cddfSDavid du Colombier memset(buf, 0, sizeof(buf));
5377dd7cddfSDavid du Colombier PSHORT(buf+0, sizeof(buf)); /* length */
5387dd7cddfSDavid du Colombier PSHORT(buf+2, 1); /* message type */
5397dd7cddfSDavid du Colombier PLONG(buf+4, Magic); /* magic */
5407dd7cddfSDavid du Colombier PSHORT(buf+8, Acalldis); /* op */
5417dd7cddfSDavid du Colombier PSHORT(buf+12, id); /* id */
5427dd7cddfSDavid du Colombier buf[14] = 3; /* reply to callclear */
5437dd7cddfSDavid du Colombier
5447dd7cddfSDavid du Colombier if(write(1, buf, sizeof(buf)) < sizeof(buf))
5457dd7cddfSDavid du Colombier myfatal("write failed: %r");
5467dd7cddfSDavid du Colombier
5477dd7cddfSDavid du Colombier return 16;
5487dd7cddfSDavid du Colombier }
5497dd7cddfSDavid du Colombier
5507dd7cddfSDavid du Colombier int
scalldis(uchar * p,int n)5517dd7cddfSDavid du Colombier scalldis(uchar *p, int n)
5527dd7cddfSDavid du Colombier {
5537dd7cddfSDavid du Colombier Call *c;
5547dd7cddfSDavid du Colombier int id, res;
5557dd7cddfSDavid du Colombier
5567dd7cddfSDavid du Colombier if(n < 148)
5577dd7cddfSDavid du Colombier return 0;
5587dd7cddfSDavid du Colombier id = GSHORT(p+12);
5597dd7cddfSDavid du Colombier res = p[14];
5607dd7cddfSDavid du Colombier
5617dd7cddfSDavid du Colombier SDB "%I: calldis id=%d res=%d\n", srv.remote, id, res EDB
5627dd7cddfSDavid du Colombier
5637dd7cddfSDavid du Colombier if(c = calllookup(id)) {
5647dd7cddfSDavid du Colombier callclose(c);
5657dd7cddfSDavid du Colombier callfree(c);
5667dd7cddfSDavid du Colombier }
5677dd7cddfSDavid du Colombier
5687dd7cddfSDavid du Colombier return 148;
5697dd7cddfSDavid du Colombier }
5707dd7cddfSDavid du Colombier
5717dd7cddfSDavid du Colombier int
swaninfo(uchar * p,int n)5727dd7cddfSDavid du Colombier swaninfo(uchar *p, int n)
5737dd7cddfSDavid du Colombier {
5747dd7cddfSDavid du Colombier Call *c;
5757dd7cddfSDavid du Colombier int id;
5767dd7cddfSDavid du Colombier
5777dd7cddfSDavid du Colombier if(n < 40)
5787dd7cddfSDavid du Colombier return 0;
5797dd7cddfSDavid du Colombier
5807dd7cddfSDavid du Colombier id = GSHORT(p+12);
5817dd7cddfSDavid du Colombier SDB "%I: waninfo id = %d\n", srv.remote, id EDB
5827dd7cddfSDavid du Colombier
5837dd7cddfSDavid du Colombier c = calllookup(id);
5847dd7cddfSDavid du Colombier if(c != 0) {
5857dd7cddfSDavid du Colombier c->err.crc = GLONG(p+16);
5867dd7cddfSDavid du Colombier c->err.frame = GLONG(p+20);
5877dd7cddfSDavid du Colombier c->err.hardware = GLONG(p+24);
5887dd7cddfSDavid du Colombier c->err.overrun = GLONG(p+28);
5897dd7cddfSDavid du Colombier c->err.timeout = GLONG(p+32);
5907dd7cddfSDavid du Colombier c->err.align = GLONG(p+36);
5917dd7cddfSDavid du Colombier
5927dd7cddfSDavid du Colombier callfree(c);
5937dd7cddfSDavid du Colombier }
5947dd7cddfSDavid du Colombier
5957dd7cddfSDavid du Colombier
5967dd7cddfSDavid du Colombier return 40;
5977dd7cddfSDavid du Colombier }
5987dd7cddfSDavid du Colombier
5997dd7cddfSDavid du Colombier int
slinkinfo(uchar * p,int n)6007dd7cddfSDavid du Colombier slinkinfo(uchar *p, int n)
6017dd7cddfSDavid du Colombier {
6027dd7cddfSDavid du Colombier Call *c;
6037dd7cddfSDavid du Colombier int id;
6047dd7cddfSDavid du Colombier int sendaccm, recvaccm;
6057dd7cddfSDavid du Colombier
6067dd7cddfSDavid du Colombier if(n < 24)
6077dd7cddfSDavid du Colombier return 0;
6087dd7cddfSDavid du Colombier id = GSHORT(p+12);
6097dd7cddfSDavid du Colombier sendaccm = GLONG(p+16);
6107dd7cddfSDavid du Colombier recvaccm = GLONG(p+20);
6117dd7cddfSDavid du Colombier
6127dd7cddfSDavid du Colombier SDB "%I: linkinfo id=%d saccm=%ux raccm=%ux\n", srv.remote, id, sendaccm, recvaccm EDB
6137dd7cddfSDavid du Colombier
6147dd7cddfSDavid du Colombier if(c = calllookup(id)) {
6157dd7cddfSDavid du Colombier c->sendaccm = sendaccm;
6167dd7cddfSDavid du Colombier c->recvaccm = recvaccm;
6177dd7cddfSDavid du Colombier
6187dd7cddfSDavid du Colombier callfree(c);
6197dd7cddfSDavid du Colombier }
6207dd7cddfSDavid du Colombier
6217dd7cddfSDavid du Colombier return 24;
6227dd7cddfSDavid du Colombier }
6237dd7cddfSDavid du Colombier
6247dd7cddfSDavid du Colombier Call*
callalloc(int id)6257dd7cddfSDavid du Colombier callalloc(int id)
6267dd7cddfSDavid du Colombier {
6277dd7cddfSDavid du Colombier uint h;
6287dd7cddfSDavid du Colombier Call *c;
6297dd7cddfSDavid du Colombier char buf[300], *argv[30], local[20], remote[20], **p;
6307dd7cddfSDavid du Colombier int fd, pfd[2], n;
6317dd7cddfSDavid du Colombier
6327dd7cddfSDavid du Colombier h = id%Nhash;
6337dd7cddfSDavid du Colombier
6347dd7cddfSDavid du Colombier qlock(&srv.lk);
6357dd7cddfSDavid du Colombier for(c=srv.hash[h]; c; c=c->next)
6367dd7cddfSDavid du Colombier if(c->id == id)
6377dd7cddfSDavid du Colombier myfatal("callalloc: duplicate id: %d", id);
6387dd7cddfSDavid du Colombier c = emallocz(sizeof(Call));
6397dd7cddfSDavid du Colombier c->ref = 1;
6407dd7cddfSDavid du Colombier c->id = id;
6417dd7cddfSDavid du Colombier c->sendaccm = ~0;
6427dd7cddfSDavid du Colombier c->recvaccm = ~0;
6437dd7cddfSDavid du Colombier
6447dd7cddfSDavid du Colombier if(!ipaddralloc(c))
6457dd7cddfSDavid du Colombier myfatal("callalloc: could not alloc remote ip address");
6467dd7cddfSDavid du Colombier
6477dd7cddfSDavid du Colombier if(pipe(pfd) < 0)
6487dd7cddfSDavid du Colombier myfatal("callalloc: pipe failed: %r");
6497dd7cddfSDavid du Colombier
6507dd7cddfSDavid du Colombier sprint(buf, "%s/ipifc/clone", srv.pppdir);
6517dd7cddfSDavid du Colombier fd = open(buf, OWRITE);
6527dd7cddfSDavid du Colombier if(fd < 0)
6537dd7cddfSDavid du Colombier myfatal("callalloc: could not open %s: %r", buf);
6547dd7cddfSDavid du Colombier
6557dd7cddfSDavid du Colombier n = sprint(buf, "iprouting");
6567dd7cddfSDavid du Colombier if(write(fd, buf, n) < n)
6577dd7cddfSDavid du Colombier myfatal("callalloc: write to ifc failed: %r");
6587dd7cddfSDavid du Colombier close(fd);
6597dd7cddfSDavid du Colombier
6607dd7cddfSDavid du Colombier p = argv;
66180ee5cbfSDavid du Colombier *p++ = srv.pppexec;
66259cc4ca5SDavid du Colombier *p++ = "-SC";
6637dd7cddfSDavid du Colombier *p++ = "-x";
6647dd7cddfSDavid du Colombier *p++ = srv.pppdir;
6657dd7cddfSDavid du Colombier if(debug)
6667dd7cddfSDavid du Colombier *p++ = "-d";
6677dd7cddfSDavid du Colombier sprint(local, "%I", srv.ipaddr);
6687dd7cddfSDavid du Colombier *p++ = local;
6697dd7cddfSDavid du Colombier sprint(remote, "%I", c->remoteip);
6707dd7cddfSDavid du Colombier *p++ = remote;
6717dd7cddfSDavid du Colombier *p = 0;
6727dd7cddfSDavid du Colombier
6737dd7cddfSDavid du Colombier proc(argv, pfd[0], pfd[0], 2);
6747dd7cddfSDavid du Colombier
6757dd7cddfSDavid du Colombier close(pfd[0]);
6767dd7cddfSDavid du Colombier
6777dd7cddfSDavid du Colombier c->pppfd = pfd[1];
6787dd7cddfSDavid du Colombier
6797dd7cddfSDavid du Colombier c->next = srv.hash[h];
6807dd7cddfSDavid du Colombier srv.hash[h] = c;
6817dd7cddfSDavid du Colombier
6827dd7cddfSDavid du Colombier qunlock(&srv.lk);
6837dd7cddfSDavid du Colombier
6847dd7cddfSDavid du Colombier c->ref++;
6857dd7cddfSDavid du Colombier thread(pppread, c);
6867dd7cddfSDavid du Colombier c->ref++;
6877dd7cddfSDavid du Colombier thread(gretimeout, c);
6887dd7cddfSDavid du Colombier
6897dd7cddfSDavid du Colombier syslog(0, LOG, ": src=%I: call started: id=%d: remote ip=%I", srv.remote, id, c->remoteip);
6907dd7cddfSDavid du Colombier
6917dd7cddfSDavid du Colombier return c;
6927dd7cddfSDavid du Colombier }
6937dd7cddfSDavid du Colombier
6947dd7cddfSDavid du Colombier void
callclose(Call * c)6957dd7cddfSDavid du Colombier callclose(Call *c)
6967dd7cddfSDavid du Colombier {
6977dd7cddfSDavid du Colombier Call *oc;
6987dd7cddfSDavid du Colombier int id;
6997dd7cddfSDavid du Colombier uint h;
7007dd7cddfSDavid du Colombier
7017dd7cddfSDavid du Colombier 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",
7027dd7cddfSDavid du Colombier srv.remote, c->id, c->stat.send, c->stat.sendack, c->stat.recv, c->stat.recvack,
7037dd7cddfSDavid du Colombier c->stat.dropped, c->stat.missing, c->stat.sendwait, c->stat.sendtimeout);
7047dd7cddfSDavid du Colombier
7057dd7cddfSDavid du Colombier qlock(&srv.lk);
7067dd7cddfSDavid du Colombier if(c->closed) {
7077dd7cddfSDavid du Colombier qunlock(&srv.lk);
7087dd7cddfSDavid du Colombier return;
7097dd7cddfSDavid du Colombier }
7107dd7cddfSDavid du Colombier c->closed = 1;
7117dd7cddfSDavid du Colombier
7127dd7cddfSDavid du Colombier close(c->dhcpfd[0]);
7137dd7cddfSDavid du Colombier close(c->dhcpfd[1]);
7147dd7cddfSDavid du Colombier close(c->pppfd);
7157dd7cddfSDavid du Colombier c->pppfd = -1;
7167dd7cddfSDavid du Colombier
7177dd7cddfSDavid du Colombier h = c->id%Nhash;
7187dd7cddfSDavid du Colombier id = c->id;
7197dd7cddfSDavid du Colombier for(c=srv.hash[h],oc=0; c; oc=c,c=c->next)
7207dd7cddfSDavid du Colombier if(c->id == id)
7217dd7cddfSDavid du Colombier break;
7227dd7cddfSDavid du Colombier if(oc == 0)
7237dd7cddfSDavid du Colombier srv.hash[h] = c->next;
7247dd7cddfSDavid du Colombier else
7257dd7cddfSDavid du Colombier oc->next = c->next;
7267dd7cddfSDavid du Colombier c->next = 0;
7277dd7cddfSDavid du Colombier qunlock(&srv.lk);
7287dd7cddfSDavid du Colombier
7297dd7cddfSDavid du Colombier callfree(c);
7307dd7cddfSDavid du Colombier }
7317dd7cddfSDavid du Colombier
7327dd7cddfSDavid du Colombier void
callfree(Call * c)7337dd7cddfSDavid du Colombier callfree(Call *c)
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier int ref;
7367dd7cddfSDavid du Colombier
7377dd7cddfSDavid du Colombier qlock(&srv.lk);
7387dd7cddfSDavid du Colombier ref = --c->ref;
7397dd7cddfSDavid du Colombier qunlock(&srv.lk);
7407dd7cddfSDavid du Colombier if(ref > 0)
7417dd7cddfSDavid du Colombier return;
7427dd7cddfSDavid du Colombier
7437dd7cddfSDavid du Colombier /* already unhooked from hash list - see callclose */
7447dd7cddfSDavid du Colombier assert(c->closed == 1);
7457dd7cddfSDavid du Colombier assert(ref == 0);
7467dd7cddfSDavid du Colombier assert(c->next == 0);
7477dd7cddfSDavid du Colombier
7487dd7cddfSDavid du Colombier SDB "call free\n" EDB
7497dd7cddfSDavid du Colombier free(c);
7507dd7cddfSDavid du Colombier }
7517dd7cddfSDavid du Colombier
7527dd7cddfSDavid du Colombier Call*
calllookup(int id)7537dd7cddfSDavid du Colombier calllookup(int id)
7547dd7cddfSDavid du Colombier {
7557dd7cddfSDavid du Colombier uint h;
7567dd7cddfSDavid du Colombier Call *c;
7577dd7cddfSDavid du Colombier
7587dd7cddfSDavid du Colombier h = id%Nhash;
7597dd7cddfSDavid du Colombier
7607dd7cddfSDavid du Colombier qlock(&srv.lk);
7617dd7cddfSDavid du Colombier for(c=srv.hash[h]; c; c=c->next)
7627dd7cddfSDavid du Colombier if(c->id == id)
7637dd7cddfSDavid du Colombier break;
7647dd7cddfSDavid du Colombier if(c != 0)
7657dd7cddfSDavid du Colombier c->ref++;
7667dd7cddfSDavid du Colombier qunlock(&srv.lk);
7677dd7cddfSDavid du Colombier
7687dd7cddfSDavid du Colombier return c;
7697dd7cddfSDavid du Colombier }
7707dd7cddfSDavid du Colombier
7719a747e4fSDavid du Colombier
7727dd7cddfSDavid du Colombier void
srvinit(void)7737dd7cddfSDavid du Colombier srvinit(void)
7747dd7cddfSDavid du Colombier {
7757dd7cddfSDavid du Colombier char buf[100];
7767dd7cddfSDavid du Colombier int fd, n;
7777dd7cddfSDavid du Colombier
7787dd7cddfSDavid du Colombier sprint(buf, "%s/local", srv.tcpdir);
7797dd7cddfSDavid du Colombier if((fd = open(buf, OREAD)) < 0)
7807dd7cddfSDavid du Colombier myfatal("could not open %s: %r", buf);
7817dd7cddfSDavid du Colombier if((n = read(fd, buf, sizeof(buf))) < 0)
7827dd7cddfSDavid du Colombier myfatal("could not read %s: %r", buf);
7837dd7cddfSDavid du Colombier buf[n] = 0;
7847dd7cddfSDavid du Colombier parseip(srv.local, buf);
7857dd7cddfSDavid du Colombier close(fd);
7867dd7cddfSDavid du Colombier
7877dd7cddfSDavid du Colombier sprint(buf, "%s/remote", srv.tcpdir);
7887dd7cddfSDavid du Colombier if((fd = open(buf, OREAD)) < 0)
7897dd7cddfSDavid du Colombier myfatal("could not open %s: %r", buf);
7907dd7cddfSDavid du Colombier if((n = read(fd, buf, sizeof(buf))) < 0)
7917dd7cddfSDavid du Colombier myfatal("could not read %s: %r", buf);
7927dd7cddfSDavid du Colombier buf[n] = 0;
7937dd7cddfSDavid du Colombier parseip(srv.remote, buf);
7947dd7cddfSDavid du Colombier close(fd);
7957dd7cddfSDavid du Colombier
7967dd7cddfSDavid du Colombier if(srv.pppdir == 0)
7977dd7cddfSDavid du Colombier srv.pppdir = "/net";
7987dd7cddfSDavid du Colombier
79980ee5cbfSDavid du Colombier if(srv.pppexec == 0)
80080ee5cbfSDavid du Colombier srv.pppexec = "/bin/ip/ppp";
8017dd7cddfSDavid du Colombier
8029a747e4fSDavid du Colombier if(myipaddr(srv.ipaddr, srv.pppdir) < 0)
80380ee5cbfSDavid du Colombier myfatal("could not read local ip addr: %r");
8047dd7cddfSDavid du Colombier if(srv.recvwindow == 0)
8057dd7cddfSDavid du Colombier srv.recvwindow = Window;
8067dd7cddfSDavid du Colombier }
8077dd7cddfSDavid du Colombier
8087dd7cddfSDavid du Colombier void
greinit(void)8097dd7cddfSDavid du Colombier greinit(void)
8107dd7cddfSDavid du Colombier {
8117dd7cddfSDavid du Colombier char addr[100], *p;
8127dd7cddfSDavid du Colombier int fd, cfd;
8137dd7cddfSDavid du Colombier
8147dd7cddfSDavid du Colombier SDB "srv.tcpdir = %s\n", srv.tcpdir EDB
8157dd7cddfSDavid du Colombier strcpy(addr, srv.tcpdir);
8167dd7cddfSDavid du Colombier p = strrchr(addr, '/');
8177dd7cddfSDavid du Colombier if(p == 0)
8187dd7cddfSDavid du Colombier myfatal("bad tcp dir: %s", srv.tcpdir);
8197dd7cddfSDavid du Colombier *p = 0;
8207dd7cddfSDavid du Colombier p = strrchr(addr, '/');
8217dd7cddfSDavid du Colombier if(p == 0)
8227dd7cddfSDavid du Colombier myfatal("bad tcp dir: %s", srv.tcpdir);
8237dd7cddfSDavid du Colombier sprint(p, "/gre!%I!34827", srv.remote);
8247dd7cddfSDavid du Colombier
8257dd7cddfSDavid du Colombier SDB "addr = %s\n", addr EDB
8267dd7cddfSDavid du Colombier
8277dd7cddfSDavid du Colombier fd = dial(addr, 0, 0, &cfd);
8287dd7cddfSDavid du Colombier
8297dd7cddfSDavid du Colombier if(fd < 0)
8307dd7cddfSDavid du Colombier myfatal("%I: dial %s failed: %r", srv.remote, addr);
8317dd7cddfSDavid du Colombier
8327dd7cddfSDavid du Colombier srv.grefd = fd;
8337dd7cddfSDavid du Colombier srv.grecfd = cfd;
8347dd7cddfSDavid du Colombier
8357dd7cddfSDavid du Colombier thread(greread, 0);
8367dd7cddfSDavid du Colombier }
8377dd7cddfSDavid du Colombier
8387dd7cddfSDavid du Colombier void
greread(void *)8397dd7cddfSDavid du Colombier greread(void *)
8407dd7cddfSDavid du Colombier {
8417dd7cddfSDavid du Colombier uchar buf[Pktsize], *p;
8427dd7cddfSDavid du Colombier int n, i;
8437dd7cddfSDavid du Colombier int flag, prot, len, callid;
8447dd7cddfSDavid du Colombier uchar src[IPaddrlen], dst[IPaddrlen];
8457dd7cddfSDavid du Colombier uint rseq, ack;
8467dd7cddfSDavid du Colombier Call *c;
8477dd7cddfSDavid du Colombier static double t, last;
8487dd7cddfSDavid du Colombier
8497dd7cddfSDavid du Colombier for(;;) {
8507dd7cddfSDavid du Colombier n = read(srv.grefd, buf, sizeof(buf));
8517dd7cddfSDavid du Colombier if(n < 0)
8527dd7cddfSDavid du Colombier myfatal("%I: bad read on gre: %r", srv.remote);
8537dd7cddfSDavid du Colombier if(n == sizeof(buf))
8547dd7cddfSDavid du Colombier myfatal("%I: gre read: buf too small", srv.remote);
8557dd7cddfSDavid du Colombier
8567dd7cddfSDavid du Colombier p = buf;
8577dd7cddfSDavid du Colombier v4tov6(src, p);
8587dd7cddfSDavid du Colombier v4tov6(dst, p+4);
8597dd7cddfSDavid du Colombier flag = GSHORT(p+8);
8607dd7cddfSDavid du Colombier prot = GSHORT(p+10);
8617dd7cddfSDavid du Colombier p += 12; n -= 12;
8627dd7cddfSDavid du Colombier
8637dd7cddfSDavid du Colombier if(ipcmp(src, srv.remote) != 0 || ipcmp(dst, srv.local) != 0)
8647dd7cddfSDavid du Colombier myfatal("%I: gre read bad address src=%I dst=%I", srv.remote, src, dst);
8657dd7cddfSDavid du Colombier
8667dd7cddfSDavid du Colombier if(prot != GRE_ppp)
8677dd7cddfSDavid du Colombier myfatal("%I: gre read gave bad protocol", srv.remote);
8687dd7cddfSDavid du Colombier
8697dd7cddfSDavid du Colombier if(flag & (GRE_chksum|GRE_routing)){
8707dd7cddfSDavid du Colombier p += 4; n -= 4;
8717dd7cddfSDavid du Colombier }
8727dd7cddfSDavid du Colombier
8737dd7cddfSDavid du Colombier if(!(flag&GRE_key))
8747dd7cddfSDavid du Colombier myfatal("%I: gre packet does not contain a key: f=%ux",
8757dd7cddfSDavid du Colombier srv.remote, flag);
8767dd7cddfSDavid du Colombier
8777dd7cddfSDavid du Colombier len = GSHORT(p);
8787dd7cddfSDavid du Colombier callid = GSHORT(p+2);
8797dd7cddfSDavid du Colombier p += 4; n -= 4;
8807dd7cddfSDavid du Colombier
8817dd7cddfSDavid du Colombier c = calllookup(callid);
8827dd7cddfSDavid du Colombier if(c == 0) {
8837dd7cddfSDavid du Colombier SDB "%I: unknown callid: %d\n", srv.remote, callid EDB
8847dd7cddfSDavid du Colombier continue;
8857dd7cddfSDavid du Colombier }
8867dd7cddfSDavid du Colombier
8877dd7cddfSDavid du Colombier qlock(&c->lk);
8887dd7cddfSDavid du Colombier
8897dd7cddfSDavid du Colombier c->stat.recv++;
8907dd7cddfSDavid du Colombier
8917dd7cddfSDavid du Colombier if(flag&GRE_seq) {
8927dd7cddfSDavid du Colombier rseq = GLONG(p);
8937dd7cddfSDavid du Colombier p += 4; n -= 4;
8947dd7cddfSDavid du Colombier } else
8957dd7cddfSDavid du Colombier rseq = c->rseq;
8967dd7cddfSDavid du Colombier
8977dd7cddfSDavid du Colombier if(flag&GRE_ack){
8987dd7cddfSDavid du Colombier ack = GLONG(p);
8997dd7cddfSDavid du Colombier p += 4; n -= 4;
9007dd7cddfSDavid du Colombier } else
9017dd7cddfSDavid du Colombier ack = c->ack;
9027dd7cddfSDavid du Colombier
9037dd7cddfSDavid du Colombier /* skip routing if present */
9047dd7cddfSDavid du Colombier if(flag&GRE_routing) {
9057dd7cddfSDavid du Colombier while((i=p[3]) != 0) {
9067dd7cddfSDavid du Colombier n -= i;
9077dd7cddfSDavid du Colombier p += i;
9087dd7cddfSDavid du Colombier }
9097dd7cddfSDavid du Colombier }
9107dd7cddfSDavid du Colombier
9117dd7cddfSDavid du Colombier if(len > n)
9127dd7cddfSDavid du Colombier myfatal("%I: bad len in gre packet", srv.remote);
9137dd7cddfSDavid du Colombier
9147dd7cddfSDavid du Colombier if((int)(ack-c->ack) > 0) {
9157dd7cddfSDavid du Colombier c->ack = ack;
9167dd7cddfSDavid du Colombier esignal(&c->eack);
9177dd7cddfSDavid du Colombier }
9187dd7cddfSDavid du Colombier
9197dd7cddfSDavid du Colombier if(debug)
9207dd7cddfSDavid du Colombier t = realtime();
9217dd7cddfSDavid du Colombier
9227dd7cddfSDavid du Colombier if(len == 0) {
9237dd7cddfSDavid du Colombier /* ack packet */
9247dd7cddfSDavid du Colombier c->stat.recvack++;
9257dd7cddfSDavid du Colombier
9267dd7cddfSDavid du Colombier SDB "%I: %.3f (%.3f): gre %d: recv ack a=%ux n=%d flag=%ux\n", srv.remote, t, t-last,
9277dd7cddfSDavid du Colombier c->id, ack, n, flag EDB
9287dd7cddfSDavid du Colombier
9297dd7cddfSDavid du Colombier } else {
9307dd7cddfSDavid du Colombier
9317dd7cddfSDavid du Colombier SDB "%I: %.3f (%.3f): gre %d: recv s=%ux a=%ux len=%d\n", srv.remote, t, t-last,
9327dd7cddfSDavid du Colombier c->id, rseq, ack, len EDB
9337dd7cddfSDavid du Colombier
9347dd7cddfSDavid du Colombier /*
9357dd7cddfSDavid du Colombier * the following handles the case of a single pair of packets
9367dd7cddfSDavid du Colombier * received out of order
9377dd7cddfSDavid du Colombier */
9387dd7cddfSDavid du Colombier n = rseq-c->rseq;
9397dd7cddfSDavid du Colombier if(n > 0 && (drop == 0. || frand() > drop)) {
9407dd7cddfSDavid du Colombier c->stat.missing += n-1;
9417dd7cddfSDavid du Colombier /* current packet */
9427dd7cddfSDavid du Colombier write(c->pppfd, p, len);
9437dd7cddfSDavid du Colombier } else {
9447dd7cddfSDavid du Colombier /* out of sequence - drop on the floor */
9457dd7cddfSDavid du Colombier c->stat.dropped++;
9467dd7cddfSDavid du Colombier
9477dd7cddfSDavid du Colombier SDB "%I: %.3f: gre %d: recv out of order or dup packet: seq=%ux len=%d\n",
9487dd7cddfSDavid du Colombier srv.remote, realtime(), c->id, rseq, len EDB
9497dd7cddfSDavid du Colombier
9507dd7cddfSDavid du Colombier }
9517dd7cddfSDavid du Colombier }
9527dd7cddfSDavid du Colombier
9537dd7cddfSDavid du Colombier if((int)(rseq-c->rseq) > 0)
9547dd7cddfSDavid du Colombier c->rseq = rseq;
9557dd7cddfSDavid du Colombier
9567dd7cddfSDavid du Colombier if(debug)
9577dd7cddfSDavid du Colombier last=t;
9587dd7cddfSDavid du Colombier
9597dd7cddfSDavid du Colombier /* open up client window */
9607dd7cddfSDavid du Colombier if((int)(c->rseq-c->rack) > (c->recvwindow>>1))
9617dd7cddfSDavid du Colombier greack(c);
9627dd7cddfSDavid du Colombier
9637dd7cddfSDavid du Colombier qunlock(&c->lk);
9647dd7cddfSDavid du Colombier
9657dd7cddfSDavid du Colombier
9667dd7cddfSDavid du Colombier callfree(c);
9677dd7cddfSDavid du Colombier }
9687dd7cddfSDavid du Colombier }
9697dd7cddfSDavid du Colombier
9707dd7cddfSDavid du Colombier void
greack(Call * c)9717dd7cddfSDavid du Colombier greack(Call *c)
9727dd7cddfSDavid du Colombier {
9737dd7cddfSDavid du Colombier uchar buf[20];
9747dd7cddfSDavid du Colombier
9757dd7cddfSDavid du Colombier c->stat.sendack++;
9767dd7cddfSDavid du Colombier
9777dd7cddfSDavid du Colombier SDB "%I: %.3f: gre %d: send ack %ux\n", srv.remote, realtime(), c->id, c->rseq EDB
9787dd7cddfSDavid du Colombier
9797dd7cddfSDavid du Colombier v6tov4(buf+0, srv.local); /* source */
9807dd7cddfSDavid du Colombier v6tov4(buf+4, srv.remote); /* source */
9817dd7cddfSDavid du Colombier PSHORT(buf+8, GRE_key|GRE_ack|1);
9827dd7cddfSDavid du Colombier PSHORT(buf+10, GRE_ppp);
9837dd7cddfSDavid du Colombier PSHORT(buf+12, 0);
9847dd7cddfSDavid du Colombier PSHORT(buf+14, c->id);
9857dd7cddfSDavid du Colombier PLONG(buf+16, c->rseq);
9867dd7cddfSDavid du Colombier
9877dd7cddfSDavid du Colombier write(srv.grefd, buf, sizeof(buf));
9887dd7cddfSDavid du Colombier
9897dd7cddfSDavid du Colombier c->rack = c->rseq;
9907dd7cddfSDavid du Colombier
9917dd7cddfSDavid du Colombier }
9927dd7cddfSDavid du Colombier
9937dd7cddfSDavid du Colombier void
gretimeout(void * a)9947dd7cddfSDavid du Colombier gretimeout(void *a)
9957dd7cddfSDavid du Colombier {
9967dd7cddfSDavid du Colombier Call *c;
9977dd7cddfSDavid du Colombier
9987dd7cddfSDavid du Colombier c = a;
9997dd7cddfSDavid du Colombier
10007dd7cddfSDavid du Colombier while(!c->closed) {
10017dd7cddfSDavid du Colombier sleep(Tick);
10027dd7cddfSDavid du Colombier qlock(&c->lk);
10037dd7cddfSDavid du Colombier c->tick++;
10047dd7cddfSDavid du Colombier qunlock(&c->lk);
10057dd7cddfSDavid du Colombier esignal(&c->eack);
10067dd7cddfSDavid du Colombier }
10077dd7cddfSDavid du Colombier callfree(c);
10087dd7cddfSDavid du Colombier exits(0);
10097dd7cddfSDavid du Colombier }
10107dd7cddfSDavid du Colombier
10117dd7cddfSDavid du Colombier
10127dd7cddfSDavid du Colombier void
pppread(void * a)10137dd7cddfSDavid du Colombier pppread(void *a)
10147dd7cddfSDavid du Colombier {
10157dd7cddfSDavid du Colombier Call *c;
10167dd7cddfSDavid du Colombier uchar buf[2000], *p;
10177dd7cddfSDavid du Colombier int n;
10187dd7cddfSDavid du Colombier ulong tick;
10197dd7cddfSDavid du Colombier
10207dd7cddfSDavid du Colombier c = a;
10217dd7cddfSDavid du Colombier for(;;) {
10227dd7cddfSDavid du Colombier p = buf+24;
10237dd7cddfSDavid du Colombier n = read(c->pppfd, p, sizeof(buf)-24);
10247dd7cddfSDavid du Colombier if(n <= 0)
10257dd7cddfSDavid du Colombier break;
10267dd7cddfSDavid du Colombier
10277dd7cddfSDavid du Colombier qlock(&c->lk);
10287dd7cddfSDavid du Colombier
10297dd7cddfSDavid du Colombier /* add gre header */
10307dd7cddfSDavid du Colombier c->seq++;
10317dd7cddfSDavid du Colombier tick = c->tick;
10327dd7cddfSDavid du Colombier
10337dd7cddfSDavid du Colombier while(c->seq-c->ack>c->sendwindow && c->tick-tick<Sendtimeout && !c->closed) {
10347dd7cddfSDavid du Colombier c->stat.sendwait++;
10357dd7cddfSDavid du Colombier SDB "window full seq = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
10367dd7cddfSDavid du Colombier qunlock(&c->lk);
10377dd7cddfSDavid du Colombier ewait(&c->eack);
10387dd7cddfSDavid du Colombier qlock(&c->lk);
10397dd7cddfSDavid du Colombier }
10407dd7cddfSDavid du Colombier
10417dd7cddfSDavid du Colombier if(c->tick-tick >= Sendtimeout) {
10427dd7cddfSDavid du Colombier c->stat.sendtimeout++;
10437dd7cddfSDavid du Colombier SDB "send timeout = %d ack = %ux window = %ux\n", c->seq, c->ack, c->sendwindow EDB
10447dd7cddfSDavid du Colombier }
10457dd7cddfSDavid du Colombier
10467dd7cddfSDavid du Colombier v6tov4(buf+0, srv.local); /* source */
10477dd7cddfSDavid du Colombier v6tov4(buf+4, srv.remote); /* source */
10487dd7cddfSDavid du Colombier PSHORT(buf+8, GRE_key|GRE_seq|GRE_ack|1);
10497dd7cddfSDavid du Colombier PSHORT(buf+10, GRE_ppp);
10507dd7cddfSDavid du Colombier PSHORT(buf+12, n);
10517dd7cddfSDavid du Colombier PSHORT(buf+14, c->id);
10527dd7cddfSDavid du Colombier PLONG(buf+16, c->seq);
10537dd7cddfSDavid du Colombier PLONG(buf+20, c->rseq);
10547dd7cddfSDavid du Colombier
10557dd7cddfSDavid du Colombier c->stat.send++;
10567dd7cddfSDavid du Colombier c->rack = c->rseq;
10577dd7cddfSDavid du Colombier
10587dd7cddfSDavid du Colombier SDB "%I: %.3f: gre %d: send s=%ux a=%ux len=%d\n", srv.remote, realtime(),
10597dd7cddfSDavid du Colombier c->id, c->seq, c->rseq, n EDB
10607dd7cddfSDavid du Colombier
10617dd7cddfSDavid du Colombier if(drop == 0. || frand() > drop)
10627dd7cddfSDavid du Colombier if(write(srv.grefd, buf, n+24)<n+24)
10637dd7cddfSDavid du Colombier myfatal("pppread: write failed: %r");
10647dd7cddfSDavid du Colombier
10657dd7cddfSDavid du Colombier qunlock(&c->lk);
10667dd7cddfSDavid du Colombier }
10677dd7cddfSDavid du Colombier
10687dd7cddfSDavid du Colombier SDB "pppread exit: %d\n", c->id);
10697dd7cddfSDavid du Colombier
10707dd7cddfSDavid du Colombier callfree(c);
10717dd7cddfSDavid du Colombier exits(0);
10727dd7cddfSDavid du Colombier }
10737dd7cddfSDavid du Colombier
10747dd7cddfSDavid du Colombier void
timeoutthread(void *)10757dd7cddfSDavid du Colombier timeoutthread(void*)
10767dd7cddfSDavid du Colombier {
10777dd7cddfSDavid du Colombier for(;;) {
10787dd7cddfSDavid du Colombier sleep(30*1000);
10797dd7cddfSDavid du Colombier
10807dd7cddfSDavid du Colombier qlock(&srv.lk);
10817dd7cddfSDavid du Colombier if(realtime() - srv.rcvtime > 5*60)
10827dd7cddfSDavid du Colombier myfatal("server timedout");
10837dd7cddfSDavid du Colombier qunlock(&srv.lk);
10847dd7cddfSDavid du Colombier }
10857dd7cddfSDavid du Colombier }
10867dd7cddfSDavid du Colombier
10877dd7cddfSDavid du Colombier
10887dd7cddfSDavid du Colombier /* use syslog() rather than fprint(2, ...) */
10897dd7cddfSDavid du Colombier void
myfatal(char * fmt,...)10907dd7cddfSDavid du Colombier myfatal(char *fmt, ...)
10917dd7cddfSDavid du Colombier {
10927dd7cddfSDavid du Colombier char sbuf[512];
10937dd7cddfSDavid du Colombier va_list arg;
10947dd7cddfSDavid du Colombier uchar buf[16];
10957dd7cddfSDavid du Colombier
10967dd7cddfSDavid du Colombier /* NT don't seem to like us just going away */
10977dd7cddfSDavid du Colombier memset(buf, 0, sizeof(buf));
10987dd7cddfSDavid du Colombier PSHORT(buf+0, sizeof(buf)); /* length */
10997dd7cddfSDavid du Colombier PSHORT(buf+2, 1); /* message type */
11007dd7cddfSDavid du Colombier PLONG(buf+4, Magic); /* magic */
11017dd7cddfSDavid du Colombier PSHORT(buf+8, Tstop); /* op */
11027dd7cddfSDavid du Colombier buf[12] = 3; /* local shutdown */
11037dd7cddfSDavid du Colombier
11047dd7cddfSDavid du Colombier write(1, buf, sizeof(buf));
11057dd7cddfSDavid du Colombier
11067dd7cddfSDavid du Colombier va_start(arg, fmt);
11079a747e4fSDavid du Colombier vseprint(sbuf, sbuf+sizeof(sbuf), fmt, arg);
11087dd7cddfSDavid du Colombier va_end(arg);
11097dd7cddfSDavid du Colombier
11107dd7cddfSDavid du Colombier SDB "%I: fatal: %s\n", srv.remote, sbuf EDB
11117dd7cddfSDavid du Colombier syslog(0, LOG, ": src=%I: fatal: %s", srv.remote, sbuf);
11127dd7cddfSDavid du Colombier
11137dd7cddfSDavid du Colombier close(0);
11147dd7cddfSDavid du Colombier close(1);
11157dd7cddfSDavid du Colombier close(srv.grefd);
11167dd7cddfSDavid du Colombier close(srv.grecfd);
11177dd7cddfSDavid du Colombier
11187dd7cddfSDavid du Colombier postnote(PNGROUP, getpid(), "die");
11197dd7cddfSDavid du Colombier exits(sbuf);
11207dd7cddfSDavid du Colombier }
11217dd7cddfSDavid du Colombier
11227dd7cddfSDavid du Colombier int
argatoi(char * p)11237dd7cddfSDavid du Colombier argatoi(char *p)
11247dd7cddfSDavid du Colombier {
11257dd7cddfSDavid du Colombier char *q;
11267dd7cddfSDavid du Colombier int i;
11277dd7cddfSDavid du Colombier
11287dd7cddfSDavid du Colombier if(p == 0)
11297dd7cddfSDavid du Colombier usage();
11307dd7cddfSDavid du Colombier
11317dd7cddfSDavid du Colombier i = strtol(p, &q, 0);
11327dd7cddfSDavid du Colombier if(q == p)
11337dd7cddfSDavid du Colombier usage();
11347dd7cddfSDavid du Colombier return i;
11357dd7cddfSDavid du Colombier }
11367dd7cddfSDavid du Colombier
11377dd7cddfSDavid du Colombier void
dhcpclientwatch(void * a)11387dd7cddfSDavid du Colombier dhcpclientwatch(void *a)
11397dd7cddfSDavid du Colombier {
11407dd7cddfSDavid du Colombier Call *c = a;
11417dd7cddfSDavid du Colombier uchar buf[1];
11427dd7cddfSDavid du Colombier
11437dd7cddfSDavid du Colombier for(;;) {
11447dd7cddfSDavid du Colombier if(read(c->dhcpfd[0], buf, sizeof(buf)) <= 0)
11457dd7cddfSDavid du Colombier break;
11467dd7cddfSDavid du Colombier }
11477dd7cddfSDavid du Colombier if(!c->closed)
11487dd7cddfSDavid du Colombier myfatal("dhcpclient terminated");
11497dd7cddfSDavid du Colombier callfree(c);
11507dd7cddfSDavid du Colombier exits(0);
11517dd7cddfSDavid du Colombier }
11527dd7cddfSDavid du Colombier
11537dd7cddfSDavid du Colombier int
ipaddralloc(Call * c)11547dd7cddfSDavid du Colombier ipaddralloc(Call *c)
11557dd7cddfSDavid du Colombier {
11567dd7cddfSDavid du Colombier int pfd[2][2];
11577dd7cddfSDavid du Colombier char *argv[4], *p;
11587dd7cddfSDavid du Colombier Biobuf bio;
11597dd7cddfSDavid du Colombier
11607dd7cddfSDavid du Colombier argv[0] = "/bin/ip/dhcpclient";
11617dd7cddfSDavid du Colombier argv[1] = "-x";
11627dd7cddfSDavid du Colombier argv[2] = srv.pppdir;
11637dd7cddfSDavid du Colombier argv[3] = 0;
11647dd7cddfSDavid du Colombier
11657dd7cddfSDavid du Colombier if(pipe(pfd[0])<0)
11667dd7cddfSDavid du Colombier myfatal("ipaddralloc: pipe failed: %r");
11677dd7cddfSDavid du Colombier if(pipe(pfd[1])<0)
11687dd7cddfSDavid du Colombier myfatal("ipaddralloc: pipe failed: %r");
11697dd7cddfSDavid du Colombier
11707dd7cddfSDavid du Colombier if(proc(argv, pfd[0][0], pfd[1][1], 2) < 0)
11717dd7cddfSDavid du Colombier myfatal("ipaddralloc: proc failed: %r");
11727dd7cddfSDavid du Colombier
11737dd7cddfSDavid du Colombier close(pfd[0][0]);
11747dd7cddfSDavid du Colombier close(pfd[1][1]);
11757dd7cddfSDavid du Colombier c->dhcpfd[0] = pfd[1][0];
11767dd7cddfSDavid du Colombier c->dhcpfd[1] = pfd[0][1];
11777dd7cddfSDavid du Colombier
11787dd7cddfSDavid du Colombier Binit(&bio, pfd[1][0], OREAD);
11797dd7cddfSDavid du Colombier for(;;) {
11807dd7cddfSDavid du Colombier p = Brdline(&bio, '\n');
11817dd7cddfSDavid du Colombier if(p == 0)
11827dd7cddfSDavid du Colombier break;
11837dd7cddfSDavid du Colombier if(strncmp(p, "ip=", 3) == 0) {
11847dd7cddfSDavid du Colombier p += 3;
11857dd7cddfSDavid du Colombier parseip(c->remoteip, p);
11867dd7cddfSDavid du Colombier } else if(strncmp(p, "end\n", 4) == 0)
11877dd7cddfSDavid du Colombier break;
11887dd7cddfSDavid du Colombier }
11897dd7cddfSDavid du Colombier
11907dd7cddfSDavid du Colombier Bterm(&bio);
11917dd7cddfSDavid du Colombier
11927dd7cddfSDavid du Colombier c->ref++;
11937dd7cddfSDavid du Colombier
11947dd7cddfSDavid du Colombier thread(dhcpclientwatch, c);
11957dd7cddfSDavid du Colombier
11967dd7cddfSDavid du Colombier return ipcmp(c->remoteip, IPnoaddr) != 0;
11977dd7cddfSDavid du Colombier }
11987dd7cddfSDavid du Colombier
11997dd7cddfSDavid du Colombier
12007dd7cddfSDavid du Colombier void
esignal(Event * e)12017dd7cddfSDavid du Colombier esignal(Event *e)
12027dd7cddfSDavid du Colombier {
12037dd7cddfSDavid du Colombier qlock(e);
12047dd7cddfSDavid du Colombier if(e->wait == 0) {
12057dd7cddfSDavid du Colombier e->ready = 1;
12067dd7cddfSDavid du Colombier qunlock(e);
12077dd7cddfSDavid du Colombier return;
12087dd7cddfSDavid du Colombier }
12097dd7cddfSDavid du Colombier assert(e->ready == 0);
12107dd7cddfSDavid du Colombier e->wait = 0;
121174f16c81SDavid du Colombier rendezvous(e, (void*)1);
12127dd7cddfSDavid du Colombier qunlock(e);
12137dd7cddfSDavid du Colombier }
12147dd7cddfSDavid du Colombier
12157dd7cddfSDavid du Colombier void
ewait(Event * e)12167dd7cddfSDavid du Colombier ewait(Event *e)
12177dd7cddfSDavid du Colombier {
12187dd7cddfSDavid du Colombier qlock(&e->waitlk);
12197dd7cddfSDavid du Colombier qlock(e);
12207dd7cddfSDavid du Colombier assert(e->wait == 0);
12217dd7cddfSDavid du Colombier if(e->ready) {
12227dd7cddfSDavid du Colombier e->ready = 0;
12237dd7cddfSDavid du Colombier } else {
12247dd7cddfSDavid du Colombier e->wait = 1;
12257dd7cddfSDavid du Colombier qunlock(e);
122674f16c81SDavid du Colombier rendezvous(e, (void*)2);
12277dd7cddfSDavid du Colombier qlock(e);
12287dd7cddfSDavid du Colombier }
12297dd7cddfSDavid du Colombier qunlock(e);
12307dd7cddfSDavid du Colombier qunlock(&e->waitlk);
12317dd7cddfSDavid du Colombier }
12327dd7cddfSDavid du Colombier
12337dd7cddfSDavid du Colombier ulong
thread(void (* f)(void *),void * a)12347dd7cddfSDavid du Colombier thread(void(*f)(void*), void *a)
12357dd7cddfSDavid du Colombier {
12367dd7cddfSDavid du Colombier int pid;
12377dd7cddfSDavid du Colombier pid=rfork(RFNOWAIT|RFMEM|RFPROC);
12387dd7cddfSDavid du Colombier if(pid < 0)
12397dd7cddfSDavid du Colombier myfatal("rfork failed: %r");
12407dd7cddfSDavid du Colombier if(pid != 0)
12417dd7cddfSDavid du Colombier return pid;
12427dd7cddfSDavid du Colombier (*f)(a);
12437dd7cddfSDavid du Colombier return 0; // never reaches here
12447dd7cddfSDavid du Colombier }
12457dd7cddfSDavid du Colombier
12467dd7cddfSDavid du Colombier double
realtime(void)12477dd7cddfSDavid du Colombier realtime(void)
12487dd7cddfSDavid du Colombier {
12497dd7cddfSDavid du Colombier long times(long*);
12507dd7cddfSDavid du Colombier
12517dd7cddfSDavid du Colombier return times(0) / 1000.0;
12527dd7cddfSDavid du Colombier }
12537dd7cddfSDavid du Colombier
12547dd7cddfSDavid du Colombier void *
emallocz(int size)12557dd7cddfSDavid du Colombier emallocz(int size)
12567dd7cddfSDavid du Colombier {
12577dd7cddfSDavid du Colombier void *p;
12587dd7cddfSDavid du Colombier p = malloc(size);
12597dd7cddfSDavid du Colombier if(p == 0)
12607dd7cddfSDavid du Colombier myfatal("malloc failed: %r");
12617dd7cddfSDavid du Colombier memset(p, 0, size);
12627dd7cddfSDavid du Colombier return p;
12637dd7cddfSDavid du Colombier }
12647dd7cddfSDavid du Colombier
12657dd7cddfSDavid du Colombier static void
fdclose(void)12667dd7cddfSDavid du Colombier fdclose(void)
12677dd7cddfSDavid du Colombier {
12687dd7cddfSDavid du Colombier int fd, n, i;
12699a747e4fSDavid du Colombier Dir *d, *p;
12707dd7cddfSDavid du Colombier
12717dd7cddfSDavid du Colombier if((fd = open("#d", OREAD)) < 0)
12727dd7cddfSDavid du Colombier return;
12737dd7cddfSDavid du Colombier
12749a747e4fSDavid du Colombier n = dirreadall(fd, &d);
12759a747e4fSDavid du Colombier for(p = d; n > 0; n--, p++) {
12767dd7cddfSDavid du Colombier i = atoi(p->name);
12777dd7cddfSDavid du Colombier if(i > 2)
12787dd7cddfSDavid du Colombier close(i);
12797dd7cddfSDavid du Colombier }
12809a747e4fSDavid du Colombier free(d);
12817dd7cddfSDavid du Colombier }
12827dd7cddfSDavid du Colombier
12837dd7cddfSDavid du Colombier int
proc(char ** argv,int fd0,int fd1,int fd2)12847dd7cddfSDavid du Colombier proc(char **argv, int fd0, int fd1, int fd2)
12857dd7cddfSDavid du Colombier {
12867dd7cddfSDavid du Colombier int r, flag;
12877dd7cddfSDavid du Colombier char *arg0, file[200];
12887dd7cddfSDavid du Colombier
12897dd7cddfSDavid du Colombier arg0 = argv[0];
12907dd7cddfSDavid du Colombier
12917dd7cddfSDavid du Colombier strcpy(file, arg0);
12927dd7cddfSDavid du Colombier
12937dd7cddfSDavid du Colombier if(access(file, 1) < 0) {
12947dd7cddfSDavid du Colombier if(strncmp(arg0, "/", 1)==0
12957dd7cddfSDavid du Colombier || strncmp(arg0, "#", 1)==0
12967dd7cddfSDavid du Colombier || strncmp(arg0, "./", 2)==0
12977dd7cddfSDavid du Colombier || strncmp(arg0, "../", 3)==0)
12987dd7cddfSDavid du Colombier return 0;
12997dd7cddfSDavid du Colombier sprint(file, "/bin/%s", arg0);
13007dd7cddfSDavid du Colombier if(access(file, 1) < 0)
13017dd7cddfSDavid du Colombier return 0;
13027dd7cddfSDavid du Colombier }
13037dd7cddfSDavid du Colombier
13047dd7cddfSDavid du Colombier flag = RFPROC|RFFDG|RFENVG|RFNOWAIT;
13057dd7cddfSDavid du Colombier if((r = rfork(flag)) != 0) {
13067dd7cddfSDavid du Colombier if(r < 0)
13077dd7cddfSDavid du Colombier return 0;
13087dd7cddfSDavid du Colombier return r;
13097dd7cddfSDavid du Colombier }
13107dd7cddfSDavid du Colombier
13117dd7cddfSDavid du Colombier if(fd0 != 0) {
13127dd7cddfSDavid du Colombier if(fd1 == 0)
13137dd7cddfSDavid du Colombier fd1 = dup(0, -1);
13147dd7cddfSDavid du Colombier if(fd2 == 0)
13157dd7cddfSDavid du Colombier fd2 = dup(0, -1);
13167dd7cddfSDavid du Colombier close(0);
13177dd7cddfSDavid du Colombier if(fd0 >= 0)
13187dd7cddfSDavid du Colombier dup(fd0, 0);
13197dd7cddfSDavid du Colombier }
13207dd7cddfSDavid du Colombier
13217dd7cddfSDavid du Colombier if(fd1 != 1) {
13227dd7cddfSDavid du Colombier if(fd2 == 1)
13237dd7cddfSDavid du Colombier fd2 = dup(1, -1);
13247dd7cddfSDavid du Colombier close(1);
13257dd7cddfSDavid du Colombier if(fd1 >= 0)
13267dd7cddfSDavid du Colombier dup(fd1, 1);
13277dd7cddfSDavid du Colombier }
13287dd7cddfSDavid du Colombier
13297dd7cddfSDavid du Colombier if(fd2 != 2) {
13307dd7cddfSDavid du Colombier close(2);
13317dd7cddfSDavid du Colombier if(fd2 >= 0)
13327dd7cddfSDavid du Colombier dup(fd2, 2);
13337dd7cddfSDavid du Colombier }
13347dd7cddfSDavid du Colombier
13357dd7cddfSDavid du Colombier fdclose();
13367dd7cddfSDavid du Colombier
13377dd7cddfSDavid du Colombier exec(file, argv);
13387dd7cddfSDavid du Colombier myfatal("proc: exec failed: %r");
13397dd7cddfSDavid du Colombier return 0;
13407dd7cddfSDavid du Colombier }
13417dd7cddfSDavid du Colombier
1342