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