diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/ip/pppmedium.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/ip/pppmedium.c')
| -rw-r--r-- | os/ip/pppmedium.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/os/ip/pppmedium.c b/os/ip/pppmedium.c new file mode 100644 index 00000000..2354728a --- /dev/null +++ b/os/ip/pppmedium.c @@ -0,0 +1,192 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "ip.h" +#include "kernel.h" +#include "ppp.h" + +static void pppreader(void *a); +static void pppbind(Ipifc *ifc, int argc, char **argv); +static void pppunbind(Ipifc *ifc); +static void pppbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); +static void deadremote(Ipifc *ifc); + +Medium pppmedium = +{ +.name= "ppp", +.hsize= 4, +.mintu= Minmtu, +.maxtu= Maxmtu, +.maclen= 0, +.bind= pppbind, +.unbind= pppunbind, +.bwrite= pppbwrite, +.unbindonclose= 0, /* don't unbind on last close */ +}; + +/* + * called to bind an IP ifc to an ethernet device + * called with ifc wlock'd + */ +static void +pppbind(Ipifc *ifc, int argc, char **argv) +{ + PPP *ppp; + Ipaddr ipaddr, remip; + int mtu, framing; + char *chapname, *secret; + + if(argc < 3) + error(Ebadarg); + + ipmove(ipaddr, IPnoaddr); + ipmove(remip, IPnoaddr); + mtu = Defmtu; + framing = 1; + chapname = nil; + secret = nil; + + switch(argc){ + default: + case 9: + if(argv[8][0] != '-') + secret = argv[8]; + case 8: + if(argv[7][0] != '-') + chapname = argv[7]; + case 7: + if(argv[6][0] != '-') + framing = strtoul(argv[6], 0, 0); + case 6: + if(argv[5][0] != '-') + mtu = strtoul(argv[5], 0, 0); + case 5: + if(argv[4][0] != '-') + parseip(remip, argv[4]); + case 4: + if(argv[3][0] != '-') + parseip(ipaddr, argv[3]); + case 3: + break; + } + + ppp = smalloc(sizeof(*ppp)); + ppp->ifc = ifc; + ppp->f = ifc->conv->p->f; + ifc->arg = ppp; + if(waserror()){ + pppunbind(ifc); + nexterror(); + } + if(pppopen(ppp, argv[2], ipaddr, remip, mtu, framing, chapname, secret) == nil) + error("ppp open failed"); + poperror(); + kproc("pppreader", pppreader, ifc, KPDUPPG|KPDUPFDG); +} + +static void +pppreader(void *a) +{ + Ipifc *ifc; + Block *bp; + PPP *ppp; + + ifc = a; + ppp = ifc->arg; + ppp->readp = up; /* hide identity under a rock for unbind */ + setpri(PriHi); + + if(waserror()){ + netlog(ppp->f, Logppp, "pppreader: %I: %s\n", ppp->local, up->env->errstr); + ppp->readp = 0; + deadremote(ifc); + pexit("hangup", 1); + } + + for(;;){ + bp = pppread(ppp); + if(bp == nil) + error("hungup"); + if(!canrlock(ifc)){ + freeb(bp); + continue; + } + if(waserror()){ + runlock(ifc); + nexterror(); + } + ifc->in++; + if(ifc->lifc == nil) + freeb(bp); + else + ipiput(ppp->f, ifc, bp); + runlock(ifc); + poperror(); + } +} + +/* + * called with ifc wlock'd + */ +static void +pppunbind(Ipifc *ifc) +{ + PPP *ppp = ifc->arg; + + if(ppp == nil) + return; + if(ppp->readp) + postnote(ppp->readp, 1, "unbind", 0); + if(ppp->timep) + postnote(ppp->timep, 1, "unbind", 0); + + /* wait for kprocs to die */ + while(ppp->readp != 0 || ppp->timep != 0) + tsleep(&up->sleep, return0, 0, 300); + + pppclose(ppp); + qclose(ifc->conv->eq); + ifc->arg = nil; +} + +/* + * called by ipoput with a single packet to write with ifc rlock'd + */ +static void +pppbwrite(Ipifc *ifc, Block *bp, int, uchar*) +{ + PPP *ppp = ifc->arg; + + pppwrite(ppp, bp); + ifc->out++; +} + +/* + * If the other end hangs up, we have to unbind the interface. An extra + * unbind (in the case where we are hanging up) won't do any harm. + */ +static void +deadremote(Ipifc *ifc) +{ + int fd; + char path[128]; + PPP *ppp; + + ppp = ifc->arg; + snprint(path, sizeof path, "#I%d/ipifc/%d/ctl", ppp->f->dev, ifc->conv->x); + fd = kopen(path, ORDWR); + if(fd < 0) + return; + kwrite(fd, "unbind", sizeof("unbind")-1); + kclose(fd); +} + +void +pppmediumlink(void) +{ + addipmedium(&pppmedium); +} |
