Refactored icmpkick6
[akaros.git] / kern / src / net / netdevmedium.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 static void netdevbind(struct Ipifc *ifc, int argc, char **argv);
17 static void netdevunbind(struct Ipifc *ifc);
18 static void netdevbwrite(struct Ipifc *ifc, struct block *bp, int version,
19                                                  uint8_t * ip);
20 static void netdevread(void *a);
21
22 typedef struct Netdevrock Netdevrock;
23 struct Netdevrock {
24         struct Fs *f;                           /* file system we belong to */
25         struct proc *readp;                     /* reading process */
26         struct chan *mchan;                     /* Data channel */
27 };
28
29 struct medium netdevmedium = {
30         .name = "netdev",
31         .hsize = 0,
32         .mintu = 0,
33         .maxtu = 64000,
34         .maclen = 0,
35         .bind = netdevbind,
36         .unbind = netdevunbind,
37         .bwrite = netdevbwrite,
38         .unbindonclose = 0,
39 };
40
41 /*
42  *  called to bind an IP ifc to a generic network device
43  *  called with ifc qlock'd
44  */
45 static void netdevbind(struct Ipifc *ifc, int argc, char **argv)
46 {
47         struct chan *mchan;
48         Netdevrock *er;
49
50         if (argc < 2)
51                 error(Ebadarg);
52
53         mchan = namec(argv[2], Aopen, ORDWR, 0);
54
55         er = kzmalloc(sizeof(*er), 0);
56         er->mchan = mchan;
57         er->f = ifc->conv->p->f;
58
59         ifc->arg = er;
60
61         ktask("netdevread", netdevread, ifc);
62 }
63
64 /*
65  *  called with ifc wlock'd
66  */
67 static void netdevunbind(struct Ipifc *ifc)
68 {
69         Netdevrock *er = ifc->arg;
70 /*
71         if(er->readp != NULL)
72                 postnote(er->readp, 1, "unbind", 0);
73 */
74         printk("%s is messed up, shouldn't track procs\n", __FUNCTION__);
75         /* wait for readers to die */
76         while (er->readp != NULL)
77                 udelay_sched(300 * 1000);
78
79         if (er->mchan != NULL)
80                 cclose(er->mchan);
81
82         kfree(er);
83 }
84
85 /*
86  *  called by ipoput with a single block to write
87  */
88 static void
89 netdevbwrite(struct Ipifc *ifc, struct block *bp, int unused_int,
90                          uint8_t * unused_uint8_p_t)
91 {
92         Netdevrock *er = ifc->arg;
93
94         if (bp->next)
95                 bp = concatblock(bp);
96         if (BLEN(bp) < ifc->mintu)
97                 bp = adjustblock(bp, ifc->mintu);
98
99         ptclcsum_finalize(bp, 0);
100         devtab[er->mchan->type].bwrite(er->mchan, bp, 0);
101         ifc->out++;
102 }
103
104 /*
105  *  process to read from the device
106  */
107 static void netdevread(void *a)
108 {
109         ERRSTACK(2);
110         struct Ipifc *ifc;
111         struct block *bp;
112         Netdevrock *er;
113         char *argv[1];
114
115         ifc = a;
116         er = ifc->arg;
117         er->readp = current;    /* hide identity under a rock for unbind */
118         if (waserror()) {
119                 er->readp = NULL;
120                 warn("netdevread returns unexpectedly");
121                 poperror();
122                 return;
123         }
124         for (;;) {
125                 bp = devtab[er->mchan->type].bread(er->mchan, ifc->maxtu, 0);
126                 if (bp == NULL) {
127                         /*
128                          * get here if mchan is a pipe and other side hangs up
129                          * clean up this interface & get out
130                          ZZZ is this a good idea?  (watch your errors btw)
131                          */
132                         poperror();
133                         er->readp = NULL;
134                         argv[0] = "unbind";
135                         if (!waserror())
136                                 ifc->conv->p->ctl(ifc->conv, argv, 1);
137                         poperror();
138                         warn("netdevread returns unexpectedly");
139                         return;
140                 }
141                 if (!canrlock(&ifc->rwlock)) {
142                         freeb(bp);
143                         continue;
144                 }
145                 if (waserror()) {
146                         runlock(&ifc->rwlock);
147                         nexterror();
148                 }
149                 ifc->in++;
150                 if (ifc->lifc == NULL)
151                         freeb(bp);
152                 else
153                         ipiput4(er->f, ifc, bp);
154                 runlock(&ifc->rwlock);
155                 poperror();
156         }
157         poperror();
158 }
159
160 void netdevmediumlink(void)
161 {
162         addipmedium(&netdevmedium);
163 }