vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

netdevmedium.c (2664B)


      1 #include "u.h"
      2 #include "lib.h"
      3 #include "mem.h"
      4 #include "dat.h"
      5 #include "fns.h"
      6 #include "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 }