xref: /plan9-contrib/sys/src/9k/ip/netdevmedium.c (revision 9ef1f84b659abcb917c5c090acbce0772e494f21)
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