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 }