netdevmedium.c 3.1 KB

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