netdevmedium.c 2.6 KB

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