]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ip/netdevmedium.c
merge
[plan9front.git] / sys / src / 9 / ip / netdevmedium.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
10 static void     netdevbind(Ipifc *ifc, int argc, char **argv);
11 static void     netdevunbind(Ipifc *ifc);
12 static void     netdevbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
13 static void     netdevread(void *a);
14
15 typedef struct  Netdevrock Netdevrock;
16 struct Netdevrock
17 {
18         Fs      *f;             /* file system we belong to */
19         Proc    *readp;         /* reading process */
20         Chan    *mchan;         /* Data channel */
21 };
22
23 Medium netdevmedium =
24 {
25 .name=          "netdev",
26 .hsize=         0,
27 .mintu= 0,
28 .maxtu= 64000,
29 .maclen=        0,
30 .bind=          netdevbind,
31 .unbind=        netdevunbind,
32 .bwrite=        netdevbwrite,
33 .unbindonclose= 0,
34 };
35
36 /*
37  *  called to bind an IP ifc to a generic network device
38  *  called with ifc qlock'd
39  */
40 static void
41 netdevbind(Ipifc *ifc, int argc, char **argv)
42 {
43         Chan *mchan;
44         Netdevrock *er;
45
46         if(argc < 2)
47                 error(Ebadarg);
48
49         mchan = namec(argv[2], Aopen, ORDWR, 0);
50
51         er = smalloc(sizeof(*er));
52         er->mchan = mchan;
53         er->f = ifc->conv->p->f;
54
55         ifc->arg = er;
56
57         kproc("netdevread", netdevread, ifc);
58 }
59
60 /*
61  *  called with ifc wlock'd
62  */
63 static void
64 netdevunbind(Ipifc *ifc)
65 {
66         Netdevrock *er = ifc->arg;
67
68         if(er->readp != nil)
69                 postnote(er->readp, 1, "unbind", 0);
70
71         /* wait for readers to die */
72         while(er->readp != nil)
73                 tsleep(&up->sleep, return0, 0, 300);
74
75         if(er->mchan != nil)
76                 cclose(er->mchan);
77
78         free(er);
79 }
80
81 /*
82  *  called by ipoput with a single block to write
83  */
84 static void
85 netdevbwrite(Ipifc *ifc, Block *bp, int, uchar*)
86 {
87         Netdevrock *er = ifc->arg;
88
89         if(bp->next)
90                 bp = concatblock(bp);
91         if(BLEN(bp) < ifc->mintu)
92                 bp = adjustblock(bp, ifc->mintu);
93
94         devtab[er->mchan->type]->bwrite(er->mchan, bp, 0);
95         ifc->out++;
96 }
97
98 /*
99  *  process to read from the device
100  */
101 static void
102 netdevread(void *a)
103 {
104         Ipifc *ifc;
105         Block *bp;
106         Netdevrock *er;
107         char *argv[1];
108
109         ifc = a;
110         er = ifc->arg;
111         er->readp = up; /* hide identity under a rock for unbind */
112         if(waserror()){
113                 er->readp = nil;
114                 pexit("hangup", 1);
115         }
116         for(;;){
117                 bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxtu, 0);
118                 if(bp == nil){
119                         /*
120                          * get here if mchan is a pipe and other side hangs up
121                          * clean up this interface & get out
122 ZZZ is this a good idea?
123                          */
124                         poperror();
125                         er->readp = nil;
126                         argv[0] = "unbind";
127                         if(!waserror())
128                                 ifc->conv->p->ctl(ifc->conv, argv, 1);
129                         pexit("hangup", 1);
130                 }
131                 if(!canrlock(ifc)){
132                         freeb(bp);
133                         continue;
134                 }
135                 if(waserror()){
136                         runlock(ifc);
137                         nexterror();
138                 }
139                 ifc->in++;
140                 if(ifc->lifc == nil)
141                         freeb(bp);
142                 else
143                         ipiput4(er->f, ifc, bp);
144                 runlock(ifc);
145                 poperror();
146         }
147 }
148
149 void
150 netdevmediumlink(void)
151 {
152         addipmedium(&netdevmedium);
153 }