ip.c is in
[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         kproc("netdevread", netdevread, ifc, 0);
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                 //      pexit("hangup", 1);
124         }
125         for(;;){
126                 bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxtu, 0);
127                 if(bp == NULL){
128                         /*
129                          * get here if mchan is a pipe and other side hangs up
130                          * clean up this interface & get out
131 ZZZ is this a good idea?
132                          */
133                         poperror();
134                         er->readp = NULL;
135                         argv[0] = "unbind";
136                         if(!waserror())
137                                 ifc->conv->p->ctl(ifc->conv, argv, 1);
138                         //              pexit("hangup", 1);
139                 }
140                 if(!canrlock(&ifc->rwlock)){
141                         freeb(bp);
142                         continue;
143                 }
144                 if(waserror()){
145                         runlock(&ifc->rwlock);
146                         nexterror();
147                 }
148                 ifc->in++;
149                 if(ifc->lifc == NULL)
150                         freeb(bp);
151                 else
152                         ipiput4(er->f, ifc, bp);
153                 runlock(&ifc->rwlock);
154                 poperror();
155         }
156 }
157
158 void
159 netdevmediumlink(void)
160 {
161         addipmedium(&netdevmedium);
162 }