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