FreeBSD/Linux Kernel Cross Reference
sys/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 }
Cache object: 59a0ad7531a0f4b2019881604928e639
|