1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 8 #include "ip.h" 9 #include "kernel.h" 10 #include "ppp.h" 11 12 static void pppreader(void *a); 13 static void pppbind(Ipifc *ifc, int argc, char **argv); 14 static void pppunbind(Ipifc *ifc); 15 static void pppbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); 16 static void deadremote(Ipifc *ifc); 17 18 Medium pppmedium = 19 { 20 .name= "ppp", 21 .hsize= 4, 22 .mintu= Minmtu, 23 .maxtu= Maxmtu, 24 .maclen= 0, 25 .bind= pppbind, 26 .unbind= pppunbind, 27 .bwrite= pppbwrite, 28 .unbindonclose= 0, /* don't unbind on last close */ 29 }; 30 31 /* 32 * called to bind an IP ifc to an ethernet device 33 * called with ifc wlock'd 34 */ 35 static void 36 pppbind(Ipifc *ifc, int argc, char **argv) 37 { 38 PPP *ppp; 39 Ipaddr ipaddr, remip; 40 int mtu, framing; 41 char *chapname, *secret; 42 43 if(argc < 3) 44 error(Ebadarg); 45 46 ipmove(ipaddr, IPnoaddr); 47 ipmove(remip, IPnoaddr); 48 mtu = Defmtu; 49 framing = 1; 50 chapname = nil; 51 secret = nil; 52 53 switch(argc){ 54 default: 55 case 9: 56 if(argv[8][0] != '-') 57 secret = argv[8]; 58 case 8: 59 if(argv[7][0] != '-') 60 chapname = argv[7]; 61 case 7: 62 if(argv[6][0] != '-') 63 framing = strtoul(argv[6], 0, 0); 64 case 6: 65 if(argv[5][0] != '-') 66 mtu = strtoul(argv[5], 0, 0); 67 case 5: 68 if(argv[4][0] != '-') 69 parseip(remip, argv[4]); 70 case 4: 71 if(argv[3][0] != '-') 72 parseip(ipaddr, argv[3]); 73 case 3: 74 break; 75 } 76 77 ppp = smalloc(sizeof(*ppp)); 78 ppp->ifc = ifc; 79 ppp->f = ifc->conv->p->f; 80 ifc->arg = ppp; 81 if(waserror()){ 82 pppunbind(ifc); 83 nexterror(); 84 } 85 if(pppopen(ppp, argv[2], ipaddr, remip, mtu, framing, chapname, secret) == nil) 86 error("ppp open failed"); 87 poperror(); 88 kproc("pppreader", pppreader, ifc, KPDUPPG|KPDUPFDG); 89 } 90 91 static void 92 pppreader(void *a) 93 { 94 Ipifc *ifc; 95 Block *bp; 96 PPP *ppp; 97 98 ifc = a; 99 ppp = ifc->arg; 100 ppp->readp = up; /* hide identity under a rock for unbind */ 101 setpri(PriHi); 102 103 if(waserror()){ 104 netlog(ppp->f, Logppp, "pppreader: %I: %s\n", ppp->local, up->env->errstr); 105 ppp->readp = 0; 106 deadremote(ifc); 107 pexit("hangup", 1); 108 } 109 110 for(;;){ 111 bp = pppread(ppp); 112 if(bp == nil) 113 error("hungup"); 114 if(!canrlock(ifc)){ 115 freeb(bp); 116 continue; 117 } 118 if(waserror()){ 119 runlock(ifc); 120 nexterror(); 121 } 122 ifc->in++; 123 if(ifc->lifc == nil) 124 freeb(bp); 125 else 126 ipiput(ppp->f, ifc, bp); 127 runlock(ifc); 128 poperror(); 129 } 130 } 131 132 /* 133 * called with ifc wlock'd 134 */ 135 static void 136 pppunbind(Ipifc *ifc) 137 { 138 PPP *ppp = ifc->arg; 139 140 if(ppp == nil) 141 return; 142 if(ppp->readp) 143 postnote(ppp->readp, 1, "unbind", 0); 144 if(ppp->timep) 145 postnote(ppp->timep, 1, "unbind", 0); 146 147 /* wait for kprocs to die */ 148 while(ppp->readp != 0 || ppp->timep != 0) 149 tsleep(&up->sleep, return0, 0, 300); 150 151 pppclose(ppp); 152 qclose(ifc->conv->eq); 153 ifc->arg = nil; 154 } 155 156 /* 157 * called by ipoput with a single packet to write with ifc rlock'd 158 */ 159 static void 160 pppbwrite(Ipifc *ifc, Block *bp, int, uchar*) 161 { 162 PPP *ppp = ifc->arg; 163 164 pppwrite(ppp, bp); 165 ifc->out++; 166 } 167 168 /* 169 * If the other end hangs up, we have to unbind the interface. An extra 170 * unbind (in the case where we are hanging up) won't do any harm. 171 */ 172 static void 173 deadremote(Ipifc *ifc) 174 { 175 int fd; 176 char path[128]; 177 PPP *ppp; 178 179 ppp = ifc->arg; 180 snprint(path, sizeof path, "#I%d/ipifc/%d/ctl", ppp->f->dev, ifc->conv->x); 181 fd = kopen(path, ORDWR); 182 if(fd < 0) 183 return; 184 kwrite(fd, "unbind", sizeof("unbind")-1); 185 kclose(fd); 186 } 187 188 void 189 pppmediumlink(void) 190 { 191 addipmedium(&pppmedium); 192 } 193