netdevmedium.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) 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 }