xref: /plan9/sys/src/9/ip/netdevmedium.c (revision 3f69512988c55e1bb3bc10cc4fa9825ba0b07fec)
159cc4ca5SDavid du Colombier #include "u.h"
259cc4ca5SDavid du Colombier #include "../port/lib.h"
359cc4ca5SDavid du Colombier #include "mem.h"
459cc4ca5SDavid du Colombier #include "dat.h"
559cc4ca5SDavid du Colombier #include "fns.h"
659cc4ca5SDavid du Colombier #include "../port/error.h"
759cc4ca5SDavid du Colombier 
859cc4ca5SDavid du Colombier #include "ip.h"
959cc4ca5SDavid du Colombier 
1059cc4ca5SDavid du Colombier static void	netdevbind(Ipifc *ifc, int argc, char **argv);
1159cc4ca5SDavid du Colombier static void	netdevunbind(Ipifc *ifc);
1259cc4ca5SDavid du Colombier static void	netdevbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
1359cc4ca5SDavid du Colombier static void	netdevread(void *a);
1459cc4ca5SDavid du Colombier 
1559cc4ca5SDavid du Colombier typedef struct	Netdevrock Netdevrock;
1659cc4ca5SDavid du Colombier struct Netdevrock
1759cc4ca5SDavid du Colombier {
1859cc4ca5SDavid du Colombier 	Fs	*f;		/* file system we belong to */
1959cc4ca5SDavid du Colombier 	Proc	*readp;		/* reading process */
2059cc4ca5SDavid du Colombier 	Chan	*mchan;		/* Data channel */
2159cc4ca5SDavid du Colombier };
2259cc4ca5SDavid du Colombier 
2359cc4ca5SDavid du Colombier Medium netdevmedium =
2459cc4ca5SDavid du Colombier {
2559cc4ca5SDavid du Colombier .name=		"netdev",
2659cc4ca5SDavid du Colombier .hsize=		0,
27*3f695129SDavid du Colombier .mintu=	0,
28*3f695129SDavid du Colombier .maxtu=	64000,
2959cc4ca5SDavid du Colombier .maclen=	0,
3059cc4ca5SDavid du Colombier .bind=		netdevbind,
3159cc4ca5SDavid du Colombier .unbind=	netdevunbind,
3259cc4ca5SDavid du Colombier .bwrite=	netdevbwrite,
3359cc4ca5SDavid du Colombier .unbindonclose=	0,
3459cc4ca5SDavid du Colombier };
3559cc4ca5SDavid du Colombier 
3659cc4ca5SDavid du Colombier /*
3759cc4ca5SDavid du Colombier  *  called to bind an IP ifc to a generic network device
3859cc4ca5SDavid du Colombier  *  called with ifc qlock'd
3959cc4ca5SDavid du Colombier  */
4059cc4ca5SDavid du Colombier static void
netdevbind(Ipifc * ifc,int argc,char ** argv)4159cc4ca5SDavid du Colombier netdevbind(Ipifc *ifc, int argc, char **argv)
4259cc4ca5SDavid du Colombier {
4359cc4ca5SDavid du Colombier 	Chan *mchan;
4459cc4ca5SDavid du Colombier 	Netdevrock *er;
4559cc4ca5SDavid du Colombier 
4659cc4ca5SDavid du Colombier 	if(argc < 2)
4759cc4ca5SDavid du Colombier 		error(Ebadarg);
4859cc4ca5SDavid du Colombier 
4980ee5cbfSDavid du Colombier 	mchan = namec(argv[2], Aopen, ORDWR, 0);
5059cc4ca5SDavid du Colombier 
5159cc4ca5SDavid du Colombier 	er = smalloc(sizeof(*er));
5259cc4ca5SDavid du Colombier 	er->mchan = mchan;
5359cc4ca5SDavid du Colombier 	er->f = ifc->conv->p->f;
5459cc4ca5SDavid du Colombier 
5559cc4ca5SDavid du Colombier 	ifc->arg = er;
5659cc4ca5SDavid du Colombier 
5759cc4ca5SDavid du Colombier 	kproc("netdevread", netdevread, ifc);
5859cc4ca5SDavid du Colombier }
5959cc4ca5SDavid du Colombier 
6059cc4ca5SDavid du Colombier /*
6159cc4ca5SDavid du Colombier  *  called with ifc wlock'd
6259cc4ca5SDavid du Colombier  */
6359cc4ca5SDavid du Colombier static void
netdevunbind(Ipifc * ifc)6459cc4ca5SDavid du Colombier netdevunbind(Ipifc *ifc)
6559cc4ca5SDavid du Colombier {
6659cc4ca5SDavid du Colombier 	Netdevrock *er = ifc->arg;
6759cc4ca5SDavid du Colombier 
6859cc4ca5SDavid du Colombier 	if(er->readp != nil)
6959cc4ca5SDavid du Colombier 		postnote(er->readp, 1, "unbind", 0);
7059cc4ca5SDavid du Colombier 
7159cc4ca5SDavid du Colombier 	/* wait for readers to die */
7259cc4ca5SDavid du Colombier 	while(er->readp != nil)
7359cc4ca5SDavid du Colombier 		tsleep(&up->sleep, return0, 0, 300);
7459cc4ca5SDavid du Colombier 
7559cc4ca5SDavid du Colombier 	if(er->mchan != nil)
7659cc4ca5SDavid du Colombier 		cclose(er->mchan);
7759cc4ca5SDavid du Colombier 
7859cc4ca5SDavid du Colombier 	free(er);
7959cc4ca5SDavid du Colombier }
8059cc4ca5SDavid du Colombier 
8159cc4ca5SDavid du Colombier /*
8259cc4ca5SDavid du Colombier  *  called by ipoput with a single block to write
8359cc4ca5SDavid du Colombier  */
8459cc4ca5SDavid du Colombier static void
netdevbwrite(Ipifc * ifc,Block * bp,int,uchar *)8559cc4ca5SDavid du Colombier netdevbwrite(Ipifc *ifc, Block *bp, int, uchar*)
8659cc4ca5SDavid du Colombier {
8759cc4ca5SDavid du Colombier 	Netdevrock *er = ifc->arg;
8859cc4ca5SDavid du Colombier 
8959cc4ca5SDavid du Colombier 	if(bp->next)
9059cc4ca5SDavid du Colombier 		bp = concatblock(bp);
91*3f695129SDavid du Colombier 	if(BLEN(bp) < ifc->mintu)
92*3f695129SDavid du Colombier 		bp = adjustblock(bp, ifc->mintu);
9359cc4ca5SDavid du Colombier 
9459cc4ca5SDavid du Colombier 	devtab[er->mchan->type]->bwrite(er->mchan, bp, 0);
9559cc4ca5SDavid du Colombier 	ifc->out++;
9659cc4ca5SDavid du Colombier }
9759cc4ca5SDavid du Colombier 
9859cc4ca5SDavid du Colombier /*
9959cc4ca5SDavid du Colombier  *  process to read from the device
10059cc4ca5SDavid du Colombier  */
10159cc4ca5SDavid du Colombier static void
netdevread(void * a)10259cc4ca5SDavid du Colombier netdevread(void *a)
10359cc4ca5SDavid du Colombier {
10459cc4ca5SDavid du Colombier 	Ipifc *ifc;
10559cc4ca5SDavid du Colombier 	Block *bp;
10659cc4ca5SDavid du Colombier 	Netdevrock *er;
10759cc4ca5SDavid du Colombier 	char *argv[1];
10859cc4ca5SDavid du Colombier 
10959cc4ca5SDavid du Colombier 	ifc = a;
11059cc4ca5SDavid du Colombier 	er = ifc->arg;
11159cc4ca5SDavid du Colombier 	er->readp = up;	/* hide identity under a rock for unbind */
11259cc4ca5SDavid du Colombier 	if(waserror()){
11359cc4ca5SDavid du Colombier 		er->readp = nil;
11459cc4ca5SDavid du Colombier 		pexit("hangup", 1);
11559cc4ca5SDavid du Colombier 	}
11659cc4ca5SDavid du Colombier 	for(;;){
117*3f695129SDavid du Colombier 		bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxtu, 0);
11859cc4ca5SDavid du Colombier 		if(bp == nil){
11959cc4ca5SDavid du Colombier 			/*
12059cc4ca5SDavid du Colombier 			 * get here if mchan is a pipe and other side hangs up
12159cc4ca5SDavid du Colombier 			 * clean up this interface & get out
12259cc4ca5SDavid du Colombier ZZZ is this a good idea?
12359cc4ca5SDavid du Colombier 			 */
12459cc4ca5SDavid du Colombier 			poperror();
12559cc4ca5SDavid du Colombier 			er->readp = nil;
12659cc4ca5SDavid du Colombier 			argv[0] = "unbind";
12759cc4ca5SDavid du Colombier 			if(!waserror())
12859cc4ca5SDavid du Colombier 				ifc->conv->p->ctl(ifc->conv, argv, 1);
12959cc4ca5SDavid du Colombier 			pexit("hangup", 1);
13059cc4ca5SDavid du Colombier 		}
13159cc4ca5SDavid du Colombier 		if(!canrlock(ifc)){
13259cc4ca5SDavid du Colombier 			freeb(bp);
13359cc4ca5SDavid du Colombier 			continue;
13459cc4ca5SDavid du Colombier 		}
13559cc4ca5SDavid du Colombier 		if(waserror()){
13659cc4ca5SDavid du Colombier 			runlock(ifc);
13759cc4ca5SDavid du Colombier 			nexterror();
13859cc4ca5SDavid du Colombier 		}
13959cc4ca5SDavid du Colombier 		ifc->in++;
14059cc4ca5SDavid du Colombier 		if(ifc->lifc == nil)
14159cc4ca5SDavid du Colombier 			freeb(bp);
14259cc4ca5SDavid du Colombier 		else
1433ff48bf5SDavid du Colombier 			ipiput4(er->f, ifc, bp);
14459cc4ca5SDavid du Colombier 		runlock(ifc);
14559cc4ca5SDavid du Colombier 		poperror();
14659cc4ca5SDavid du Colombier 	}
14759cc4ca5SDavid du Colombier }
14859cc4ca5SDavid du Colombier 
14959cc4ca5SDavid du Colombier void
netdevmediumlink(void)15059cc4ca5SDavid du Colombier netdevmediumlink(void)
15159cc4ca5SDavid du Colombier {
15259cc4ca5SDavid du Colombier 	addipmedium(&netdevmedium);
15359cc4ca5SDavid du Colombier }
154