gre.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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);
  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 = qopen(64*1024, Qkick, 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)
  106. {
  107. Conv *c = x;
  108. GREhdr *ghp;
  109. Block *bp;
  110. uchar laddr[IPaddrlen], raddr[IPaddrlen];
  111. bp = qget(c->wq);
  112. if(bp == nil)
  113. return;
  114. /* Make space to fit ip header (gre header already there) */
  115. bp = padblock(bp, GRE_IPONLY);
  116. if(bp == nil)
  117. return;
  118. /* make sure the message has a GRE header */
  119. bp = pullupblock(bp, GRE_IPONLY+GRE_IPPLUSGRE);
  120. if(bp == nil)
  121. return;
  122. ghp = (GREhdr *)(bp->rp);
  123. ghp->vihl = IP_VER4;
  124. v4tov6(raddr, ghp->dst);
  125. if(ipcmp(raddr, v4prefix) == 0)
  126. memmove(ghp->dst, c->raddr + IPv4off, IPv4addrlen);
  127. v4tov6(laddr, ghp->src);
  128. if(ipcmp(laddr, v4prefix) == 0){
  129. if(ipcmp(c->laddr, IPnoaddr) == 0)
  130. findlocalip(c->p->f, c->laddr, raddr); /* pick interface closest to dest */
  131. memmove(ghp->src, c->laddr + IPv4off, IPv4addrlen);
  132. }
  133. ghp->proto = IP_GREPROTO;
  134. hnputs(ghp->eproto, c->rport);
  135. ghp->frag[0] = 0;
  136. ghp->frag[1] = 0;
  137. ipoput4(c->p->f, bp, 0, c->ttl, c->tos);
  138. }
  139. static void
  140. greiput(Proto *gre, Ipifc*, Block *bp)
  141. {
  142. int len;
  143. GREhdr *ghp;
  144. Conv *c, **p;
  145. ushort eproto;
  146. uchar raddr[IPaddrlen];
  147. GREpriv *gpriv;
  148. gpriv = gre->priv;
  149. ghp = (GREhdr*)(bp->rp);
  150. v4tov6(raddr, ghp->src);
  151. eproto = nhgets(ghp->eproto);
  152. qlock(gre);
  153. /* Look for a conversation structure for this port and address */
  154. c = nil;
  155. for(p = gre->conv; *p; p++) {
  156. c = *p;
  157. if(c->inuse == 0)
  158. continue;
  159. if(c->rport == eproto && ipcmp(c->raddr, raddr) == 0)
  160. break;
  161. }
  162. if(*p == nil) {
  163. qunlock(gre);
  164. freeblist(bp);
  165. return;
  166. }
  167. qunlock(gre);
  168. /*
  169. * Trim the packet down to data size
  170. */
  171. len = nhgets(ghp->len) - GRE_IPONLY;
  172. if(len < GRE_IPPLUSGRE){
  173. freeblist(bp);
  174. return;
  175. }
  176. bp = trimblock(bp, GRE_IPONLY, len);
  177. if(bp == nil){
  178. gpriv->lenerr++;
  179. return;
  180. }
  181. /*
  182. * Can't delimit packet so pull it all into one block.
  183. */
  184. if(qlen(c->rq) > 64*1024)
  185. freeblist(bp);
  186. else{
  187. bp = concatblock(bp);
  188. if(bp == 0)
  189. panic("greiput");
  190. qpass(c->rq, bp);
  191. }
  192. }
  193. int
  194. grestats(Proto *gre, char *buf, int len)
  195. {
  196. GREpriv *gpriv;
  197. gpriv = gre->priv;
  198. return snprint(buf, len, "gre: len %lud\n", gpriv->lenerr);
  199. }
  200. void
  201. greinit(Fs *fs)
  202. {
  203. Proto *gre;
  204. gre = smalloc(sizeof(Proto));
  205. gre->priv = smalloc(sizeof(GREpriv));
  206. gre->name = "gre";
  207. gre->connect = greconnect;
  208. gre->announce = greannounce;
  209. gre->state = grestate;
  210. gre->create = grecreate;
  211. gre->close = greclose;
  212. gre->rcv = greiput;
  213. gre->ctl = nil;
  214. gre->advise = nil;
  215. gre->stats = grestats;
  216. gre->ipproto = IP_GREPROTO;
  217. gre->nc = 64;
  218. gre->ptclsize = 0;
  219. Fsproto(fs, gre);
  220. }