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