ref: 6723fdf7b7c7fc3231bb1868139c768301ff03b9
parent: 15a23fd99be64e7f22b97d0321cf1f6c954f5626
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed May 10 13:34:10 EDT 2023
ip/pppoe: aaand the code ;)
--- a/sys/src/cmd/ip/pppoe.c
+++ b/sys/src/cmd/ip/pppoe.c
@@ -14,8 +14,10 @@
int pppoe(char*);
void execppp(int);
+int forked;
int alarmed;
int debug;
+int rflag;
int sessid;
char *keyspec;
int primary;
@@ -34,10 +36,27 @@
void
usage(void)
{
- fprint(2, "usage: pppoe [-PdcC] [-A acname] [-S srvname] [-k keyspec] [-m mtu] [-b baud] [-x pppnet] [ether0]\n");
+ fprint(2, "usage: %s [-rPdcC] [-A acname] [-S srvname] [-k keyspec] [-m mtu] [-b baud] [-x pppnet] [ether0]\n", argv0);
exits("usage");
}
+void
+fatal(char *fmt, ...)
+{
+ va_list a;
+
+ fprint(2, "%s: ", argv0);
+
+ va_start(a, fmt);
+ vfprint(2, fmt, a);
+ va_end(a);
+
+ if(forked)
+ postnote(PNGROUP, getpid(), "die");
+
+ exits("fatal");
+}
+
int
catchalarm(void *a, char *msg)
{
@@ -55,7 +74,6 @@
void
main(int argc, char **argv)
{
- int fd;
char *dev;
ARGBEGIN{
@@ -68,6 +86,9 @@
case 'S':
srvname = EARGF(usage());
break;
+ case 'r':
+ rflag++;
+ break;
case 'd':
debug++;
break;
@@ -107,8 +128,7 @@
fmtinstall('E', eipfmt);
atnotify(catchalarm, 1);
- fd = pppoe(dev);
- execppp(fd);
+ execppp(pppoe(dev));
}
typedef struct Etherhdr Etherhdr;
@@ -160,6 +180,7 @@
CodeDiscOffer = 0x07, /* discovery offer */
CodeDiscReq = 0x19, /* discovery request */
CodeDiscSess = 0x65, /* session confirmation */
+ CodeDiscTerm = 0xa7,
/* Session codes */
CodeSession = 0x00,
@@ -253,7 +274,7 @@
rerrstr(e, sizeof e);
strcpy(path, "unknown");
fd2path(fd, path, sizeof path);
- sysfatal("write %d to %s: %s", nbuf, path, e);
+ fatal("write %d to %s: %s\n", nbuf, path, e);
}
}
@@ -264,7 +285,7 @@
v = malloc(n);
if(v == nil)
- sysfatal("out of memory");
+ fatal("out of memory\n");
return v;
}
@@ -280,9 +301,9 @@
if(alarmed)
return -1;
if(n < 0)
- sysfatal("read: %r");
+ fatal("read: %r\n");
if(n == 0)
- sysfatal("short read");
+ fatal("short read\n");
return n;
}
@@ -417,22 +438,36 @@
}
int
+wantterm(uchar *pkt)
+{
+ Pppoehdr *ph;
+
+ ph = (Pppoehdr*)(pkt+EtherHdrSz);
+ if(ph->code != CodeDiscTerm)
+ return bad("not a PADT");
+ if(nhgets(ph->sessid) != sessid)
+ return bad("bad session id");
+ return 1;
+}
+
+int
pppoe(char *ether)
{
- char buf[64];
+ char buf[128];
uchar pkt[1520];
- int dfd, p[2], n, sfd, sz, timeout;
+ int dfd, sfd, p[2], n, sz, timeout;
Pppoehdr *ph;
ph = (Pppoehdr*)(pkt+EtherHdrSz);
snprint(buf, sizeof buf, "%s!%d", ether, EtherPppoeDiscovery);
if((dfd = dial(buf, nil, nil, nil)) < 0)
- sysfatal("dial %s: %r", buf);
+ fatal("dial %s: %r\n", buf);
snprint(buf, sizeof buf, "%s!%d", ether, EtherPppoeSession);
if((sfd = dial(buf, nil, nil, nil)) < 0)
- sysfatal("dial %s: %r", buf);
+ fatal("dial %s: %r\n", buf);
+Restart:
for(timeout=250; timeout<16000; timeout*=2){
clearstate();
memset(pkt, 0, sizeof pkt);
@@ -456,23 +491,70 @@
if(pktread(timeout, dfd, pkt, sizeof pkt, wantsession) < 0)
continue;
-
break;
}
- if(sessid < 0)
- sysfatal("could not establish session");
+ if(sessid < 0){
+ if(rflag) {
+ if(forked || rfork(RFFDG|RFREND|RFPROC|RFNOWAIT|RFNOTEG) == 0){
+ forked = 1;
+ goto Restart;
+ }
+ fprint(2, "%s: warning: could not establish session, retrying\n", argv0);
+ exits(nil);
+ }
+ fatal("could not establish session\n");
+ }
- rfork(RFNOTEG);
if(pipe(p) < 0)
- sysfatal("pipe: %r");
+ fatal("pipe: %r\n");
+ switch(rfork(RFFDG|RFREND|RFPROC|RFNOWAIT|RFNOTEG)){
+ case -1:
+ fatal("fork: %r\n");
+ case 0:
+ forked = 1;
+ close(p[1]);
+ break;
+ default:
+ forked = 0;
+ close(dfd);
+ close(sfd);
+ close(p[0]);
+ return p[1];
+ }
+
switch(fork()){
case -1:
- sysfatal("fork: %r");
+ fatal("fork: %r\n");
default:
break;
case 0:
- close(p[1]);
+ close(dfd);
+ while((n = read(sfd, pkt, sizeof pkt)) > 0){
+ if(malformed(pkt, n, EtherPppoeSession)
+ || ph->code != 0x00 || nhgets(ph->sessid) != sessid){
+ if(debug)
+ fprint(2, "malformed session pkt: %r\n");
+ if(debug)
+ dumppkt(pkt);
+ continue;
+ }
+ if(write(p[0], pkt+Hdr, nhgets(ph->length)) < 0){
+ if(debug)
+ fprint(2, "write to ppp failed: %r\n");
+ break;
+ }
+ }
+ exits(nil);
+ }
+
+ switch(fork()){
+ case -1:
+ fatal("fork: %r\n");
+ default:
+ break;
+ case 0:
+ close(dfd);
while((n = read(p[0], pkt+Hdr, sizeof pkt-Hdr)) > 0){
etherhdr(pkt, etherdst, EtherPppoeSession);
pppoehdr(pkt+EtherHdrSz, 0x00, sessid);
@@ -487,38 +569,38 @@
if(write(sfd, pkt, sz) < 0){
if(debug)
fprint(2, "write to ether failed: %r");
- _exits(nil);
+ break;
}
}
- _exits(nil);
+ exits(nil);
}
+ close(p[0]);
switch(fork()){
case -1:
- sysfatal("fork: %r");
+ fatal("fork: %r\n");
default:
break;
case 0:
- close(p[1]);
- while((n = read(sfd, pkt, sizeof pkt)) > 0){
- if(malformed(pkt, n, EtherPppoeSession)
- || ph->code != 0x00 || nhgets(ph->sessid) != sessid){
- if(debug)
- fprint(2, "malformed session pkt: %r\n");
- if(debug)
- dumppkt(pkt);
- continue;
- }
- if(write(p[0], pkt+Hdr, nhgets(ph->length)) < 0){
- if(debug)
- fprint(2, "write to ppp failed: %r\n");
- _exits(nil);
- }
+ close(sfd);
+ for (;;) {
+ if(pktread(0, dfd, pkt, sizeof pkt, wantterm) > 0)
+ break;
}
- _exits(nil);
+ exits(nil);
}
- close(p[0]);
- return p[1];
+
+ /* wait for any of our children to exit */
+ waitpid();
+ postnote(PNGROUP, getpid(), "die");
+ if(!rflag)
+ exits(nil);
+
+ /* wait for all to exit, then restart */
+ sleep(5000);
+ waitpid();
+ waitpid();
+ goto Restart;
}
void
@@ -558,7 +640,7 @@
dup(fd, 0);
dup(fd, 1);
exec(pppname, argv);
- sysfatal("exec: %r");
+ fatal("exec: %r\n");
}
uchar*
@@ -659,8 +741,7 @@
ph = (Pppoehdr*)(pkt+EtherHdrSz);
et = nhgets(eh->type);
- fprint(2, "%E -> %E type 0x%x\n",
- eh->src, eh->dst, et);
+ fprint(2, "%E -> %E type 0x%x\n", eh->src, eh->dst, et);
switch(et){
case EtherPppoeDiscovery:
case EtherPppoeSession: