1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 8 #include "ip.h" 9 #include "kernel.h" 10 11 static void netdevbind(Ipifc *ifc, int argc, char **argv); 12 static void netdevunbind(Ipifc *ifc); 13 static void netdevbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); 14 static void netdevread(void *a); 15 16 typedef struct Netdevrock Netdevrock; 17 struct Netdevrock 18 { 19 Fs *f; /* file system we belong to */ 20 Proc *readp; /* reading process */ 21 Chan *mchan; /* Data channel */ 22 }; 23 24 Medium netdevmedium = 25 { 26 .name= "netdev", 27 .hsize= 0, 28 .minmtu= 0, 29 .maxmtu= 64000, 30 .maclen= 0, 31 .bind= netdevbind, 32 .unbind= netdevunbind, 33 .bwrite= netdevbwrite, 34 .unbindonclose= 0, 35 }; 36 37 /* 38 * called to bind an IP ifc to a generic network device 39 * called with ifc qlock'd 40 */ 41 static void 42 netdevbind(Ipifc *ifc, int argc, char **argv) 43 { 44 int fd; 45 Chan *mchan; 46 Netdevrock *er; 47 48 if(argc < 2) 49 error(Ebadarg); 50 51 fd = kopen(argv[2], ORDWR); 52 if(fd < 0) 53 error("fd open failed"); 54 55 mchan = commonfdtochan(fd, ORDWR, 0, 1); 56 kclose(fd); 57 58 er = smalloc(sizeof(*er)); 59 er->mchan = mchan; 60 er->f = ifc->conv->p->f; 61 62 ifc->arg = er; 63 64 kproc("netdevread", netdevread, ifc); 65 } 66 67 /* 68 * called with ifc wlock'd 69 */ 70 static void 71 netdevunbind(Ipifc *ifc) 72 { 73 Netdevrock *er = ifc->arg; 74 75 if(er->readp != nil) 76 postnote(er->readp, 1, "unbind", 0); 77 78 /* wait for readers to die */ 79 while(er->readp != nil) 80 tsleep(&up->sleep, return0, 0, 300); 81 82 if(er->mchan != nil) 83 cclose(er->mchan); 84 85 free(er); 86 } 87 88 /* 89 * called by ipoput with a single block to write 90 */ 91 static void 92 netdevbwrite(Ipifc *ifc, Block *bp, int, uchar*) 93 { 94 Netdevrock *er = ifc->arg; 95 96 if(bp->next) 97 bp = concatblock(bp); 98 if(BLEN(bp) < ifc->minmtu) 99 bp = adjustblock(bp, ifc->minmtu); 100 101 devtab[er->mchan->type]->bwrite(er->mchan, bp, 0); 102 ifc->out++; 103 } 104 105 /* 106 * process to read from the device 107 */ 108 static void 109 netdevread(void *a) 110 { 111 Ipifc *ifc; 112 Block *bp; 113 Netdevrock *er; 114 char *argv[1]; 115 116 ifc = a; 117 er = ifc->arg; 118 er->readp = up; /* hide identity under a rock for unbind */ 119 if(waserror()){ 120 er->readp = nil; 121 pexit("hangup", 1); 122 } 123 for(;;){ 124 bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxmtu, 0); 125 if(bp == nil){ 126 /* 127 * get here if mchan is a pipe and other side hangs up 128 * clean up this interface & get out 129 ZZZ is this a good idea? 130 */ 131 poperror(); 132 er->readp = nil; 133 argv[0] = "unbind"; 134 if(!waserror()) 135 ifc->conv->p->ctl(ifc->conv, argv, 1); 136 pexit("hangup", 1); 137 } 138 if(!canrlock(ifc)){ 139 freeb(bp); 140 continue; 141 } 142 if(waserror()){ 143 runlock(ifc); 144 nexterror(); 145 } 146 ifc->in++; 147 if(ifc->lifc == nil) 148 freeb(bp); 149 else 150 ipiput(er->f, ifc->lifc->local, bp); 151 runlock(ifc); 152 poperror(); 153 } 154 } 155 156 void 157 netdevmediumlink(void) 158 { 159 addipmedium(&netdevmedium); 160 } 161