Adds chaninfo()
[akaros.git] / kern / src / net / pppmedium.c
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         ktask("pppreader", pppreader, ifc);
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                 udelay_sched(300 * 1000);
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 }