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