gre.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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. #define DPRINT if(0)print
  9. enum
  10. {
  11. GRE_IPONLY = 12, /* size of ip header */
  12. GRE_IPPLUSGRE = 12, /* minimum size of GRE header */
  13. IP_GREPROTO = 47,
  14. GRErxms = 200,
  15. GREtickms = 100,
  16. GREmaxxmit = 10,
  17. };
  18. typedef struct GREhdr
  19. {
  20. /* ip header */
  21. uchar vihl; /* Version and header length */
  22. uchar tos; /* Type of service */
  23. uchar len[2]; /* packet length (including headers) */
  24. uchar id[2]; /* Identification */
  25. uchar frag[2]; /* Fragment information */
  26. uchar Unused;
  27. uchar proto; /* Protocol */
  28. uchar cksum[2]; /* checksum */
  29. uchar src[4]; /* Ip source */
  30. uchar dst[4]; /* Ip destination */
  31. /* gre header */
  32. uchar flags[2];
  33. uchar eproto[2]; /* encapsulation protocol */
  34. } GREhdr;
  35. typedef struct GREpriv GREpriv;
  36. struct GREpriv
  37. {
  38. /* non-MIB stats */
  39. ulong csumerr; /* checksum errors */
  40. ulong lenerr; /* short packet */
  41. };
  42. static void grekick(void *x, Block *bp);
  43. static char*
  44. greconnect(Conv *c, char **argv, int argc)
  45. {
  46. Proto *p;
  47. char *err;
  48. Conv *tc, **cp, **ecp;
  49. err = Fsstdconnect(c, argv, argc);
  50. if(err != nil)
  51. return err;
  52. /* make sure noone's already connected to this other sys */
  53. p = c->p;
  54. qlock(p);
  55. ecp = &p->conv[p->nc];
  56. for(cp = p->conv; cp < ecp; cp++){
  57. tc = *cp;
  58. if(tc == nil)
  59. break;
  60. if(tc == c)
  61. continue;
  62. if(tc->rport == c->rport && ipcmp(tc->raddr, c->raddr) == 0){
  63. err = "already connected to that addr/proto";
  64. ipmove(c->laddr, IPnoaddr);
  65. ipmove(c->raddr, IPnoaddr);
  66. break;
  67. }
  68. }
  69. qunlock(p);
  70. if(err != nil)
  71. return err;
  72. Fsconnected(c, nil);
  73. return nil;
  74. }
  75. static void
  76. grecreate(Conv *c)
  77. {
  78. c->rq = qopen(64*1024, Qmsg, 0, c);
  79. c->wq = qbypass(grekick, c);
  80. }
  81. static int
  82. grestate(Conv *c, char *state, int n)
  83. {
  84. USED(c);
  85. return snprint(state, n, "%s", "Datagram");
  86. }
  87. static char*
  88. greannounce(Conv*, char**, int)
  89. {
  90. return "pktifc does not support announce";
  91. }
  92. static void
  93. greclose(Conv *c)
  94. {
  95. qclose(c->rq);
  96. qclose(c->wq);
  97. qclose(c->eq);
  98. ipmove(c->laddr, IPnoaddr);
  99. ipmove(c->raddr, IPnoaddr);
  100. c->lport = 0;
  101. c->rport = 0;
  102. }
  103. int drop;
  104. static void
  105. grekick(void *x, Block *bp)
  106. {
  107. Conv *c = x;
  108. GREhdr *ghp;
  109. uchar laddr[IPaddrlen], raddr[IPaddrlen];
  110. if(bp == nil)
  111. return;
  112. /* Make space to fit ip header (gre header already there) */
  113. bp = padblock(bp, GRE_IPONLY);
  114. if(bp == nil)
  115. return;
  116. /* make sure the message has a GRE header */
  117. bp = pullupblock(bp, GRE_IPONLY+GRE_IPPLUSGRE);
  118. if(bp == nil)
  119. return;
  120. ghp = (GREhdr *)(bp->rp);
  121. ghp->vihl = IP_VER4;
  122. v4tov6(raddr, ghp->dst);
  123. if(ipcmp(raddr, v4prefix) == 0)
  124. memmove(ghp->dst, c->raddr + IPv4off, IPv4addrlen);
  125. v4tov6(laddr, ghp->src);
  126. if(ipcmp(laddr, v4prefix) == 0){
  127. if(ipcmp(c->laddr, IPnoaddr) == 0)
  128. findlocalip(c->p->f, c->laddr, raddr); /* pick interface closest to dest */
  129. memmove(ghp->src, c->laddr + IPv4off, IPv4addrlen);
  130. }
  131. ghp->proto = IP_GREPROTO;
  132. hnputs(ghp->eproto, c->rport);
  133. ghp->frag[0] = 0;
  134. ghp->frag[1] = 0;
  135. ipoput4(c->p->f, bp, 0, c->ttl, c->tos, nil);
  136. }
  137. static void
  138. greiput(Proto *gre, Ipifc*, Block *bp)
  139. {
  140. int len;
  141. GREhdr *ghp;
  142. Conv *c, **p;
  143. ushort eproto;
  144. uchar raddr[IPaddrlen];
  145. GREpriv *gpriv;
  146. gpriv = gre->priv;
  147. ghp = (GREhdr*)(bp->rp);
  148. v4tov6(raddr, ghp->src);
  149. eproto = nhgets(ghp->eproto);
  150. qlock(gre);
  151. /* Look for a conversation structure for this port and address */
  152. c = nil;
  153. for(p = gre->conv; *p; p++) {
  154. c = *p;
  155. if(c->inuse == 0)
  156. continue;
  157. if(c->rport == eproto && ipcmp(c->raddr, raddr) == 0)
  158. break;
  159. }
  160. if(*p == nil) {
  161. qunlock(gre);
  162. freeblist(bp);
  163. return;
  164. }
  165. qunlock(gre);
  166. /*
  167. * Trim the packet down to data size
  168. */
  169. len = nhgets(ghp->len) - GRE_IPONLY;
  170. if(len < GRE_IPPLUSGRE){
  171. freeblist(bp);
  172. return;
  173. }
  174. bp = trimblock(bp, GRE_IPONLY, len);
  175. if(bp == nil){
  176. gpriv->lenerr++;
  177. return;
  178. }
  179. /*
  180. * Can't delimit packet so pull it all into one block.
  181. */
  182. if(qlen(c->rq) > 64*1024)
  183. freeblist(bp);
  184. else{
  185. bp = concatblock(bp);
  186. if(bp == 0)
  187. panic("greiput");
  188. qpass(c->rq, bp);
  189. }
  190. }
  191. int
  192. grestats(Proto *gre, char *buf, int len)
  193. {
  194. GREpriv *gpriv;
  195. gpriv = gre->priv;
  196. return snprint(buf, len, "gre: len %lud\n", gpriv->lenerr);
  197. }
  198. void
  199. greinit(Fs *fs)
  200. {
  201. Proto *gre;
  202. gre = smalloc(sizeof(Proto));
  203. gre->priv = smalloc(sizeof(GREpriv));
  204. gre->name = "gre";
  205. gre->connect = greconnect;
  206. gre->announce = greannounce;
  207. gre->state = grestate;
  208. gre->create = grecreate;
  209. gre->close = greclose;
  210. gre->rcv = greiput;
  211. gre->ctl = nil;
  212. gre->advise = nil;
  213. gre->stats = grestats;
  214. gre->ipproto = IP_GREPROTO;
  215. gre->nc = 64;
  216. gre->ptclsize = 0;
  217. Fsproto(fs, gre);
  218. }