gre.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  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. /*
  10. * Generic Routing Encapsulation over IPv4, rfc1702
  11. */
  12. #include "u.h"
  13. #include "../port/lib.h"
  14. #include "mem.h"
  15. #include "dat.h"
  16. #include "fns.h"
  17. #include "../port/error.h"
  18. #include "ip.h"
  19. enum {
  20. GRE_IPONLY = 12, /* size of ip header */
  21. GRE_IPPLUSGRE = 12, /* minimum size of GRE header */
  22. IP_GREPROTO = 47,
  23. GRErxms = 200,
  24. GREtickms = 100,
  25. GREmaxxmit = 10,
  26. K = 1024,
  27. GREqlen = 256 * K,
  28. GRE_cksum = 0x8000,
  29. GRE_routing = 0x4000,
  30. GRE_key = 0x2000,
  31. GRE_seq = 0x1000,
  32. Nring = 1 << 10, /* power of two, please */
  33. Ringmask = Nring - 1,
  34. GREctlraw = 0,
  35. GREctlcooked,
  36. GREctlretunnel,
  37. GREctlreport,
  38. GREctldlsuspend,
  39. GREctlulsuspend,
  40. GREctldlresume,
  41. GREctlulresume,
  42. GREctlforward,
  43. GREctlulkey,
  44. Ncmds,
  45. };
  46. typedef struct GREhdr GREhdr;
  47. struct GREhdr{
  48. /* ip header */
  49. uint8_t vihl; /* Version and header length */
  50. uint8_t tos; /* Type of service */
  51. uint8_t len[2]; /* packet length (including headers) */
  52. uint8_t id[2]; /* Identification */
  53. uint8_t frag[2]; /* Fragment information */
  54. uint8_t ttl;
  55. uint8_t proto; /* Protocol */
  56. uint8_t cksum[2]; /* checksum */
  57. uint8_t src[4]; /* Ip source */
  58. uint8_t dst[4]; /* Ip destination */
  59. /* gre header */
  60. uint8_t flags[2];
  61. uint8_t eproto[2]; /* encapsulation protocol */
  62. };
  63. typedef struct GREpriv GREpriv;
  64. struct GREpriv{
  65. /* non-MIB stats */
  66. uint32_t lenerr; /* short packet */
  67. };
  68. typedef struct Bring Bring;
  69. struct Bring{
  70. Block *ring[Nring];
  71. int32_t produced;
  72. int32_t consumed;
  73. };
  74. typedef struct GREconv GREconv;
  75. struct GREconv{
  76. int raw;
  77. /* Retunnelling information. v4 only */
  78. uint8_t north[4]; /* HA */
  79. uint8_t south[4]; /* Base station */
  80. uint8_t hoa[4]; /* Home address */
  81. uint8_t coa[4]; /* Careof address */
  82. uint32_t seq; /* Current sequence # */
  83. int dlsusp; /* Downlink suspended? */
  84. int ulsusp; /* Uplink suspended? */
  85. uint32_t ulkey; /* GRE key */
  86. QLock lock; /* Lock for rings */
  87. Bring dlpending; /* Ring of pending packets */
  88. Bring dlbuffered; /* Received while suspended */
  89. Bring ulbuffered; /* Received while suspended */
  90. };
  91. typedef struct Metablock Metablock;
  92. struct Metablock{
  93. uint8_t *rp;
  94. uint32_t seq;
  95. };
  96. static char *grectlcooked(Conv *, int, char **);
  97. static char *grectldlresume(Conv *, int, char **);
  98. static char *grectldlsuspend(Conv *, int, char **);
  99. static char *grectlforward(Conv *, int, char **);
  100. static char *grectlraw(Conv *, int, char **);
  101. static char *grectlreport(Conv *, int, char **);
  102. static char *grectlretunnel(Conv *, int, char **);
  103. static char *grectlulkey(Conv *, int, char **);
  104. static char *grectlulresume(Conv *, int, char **);
  105. static char *grectlulsuspend(Conv *, int, char **);
  106. static struct{
  107. char *cmd;
  108. int argc;
  109. char *(*f)(Conv *, int, char **);
  110. } grectls[Ncmds] = {
  111. [GREctlraw] = { "raw", 1, grectlraw, },
  112. [GREctlcooked] = { "cooked", 1, grectlcooked, },
  113. [GREctlretunnel]= { "retunnel", 5, grectlretunnel, },
  114. [GREctlreport] = { "report", 2, grectlreport, },
  115. [GREctldlsuspend]= { "dlsuspend", 1, grectldlsuspend,},
  116. [GREctlulsuspend]= { "ulsuspend", 1, grectlulsuspend,},
  117. [GREctldlresume]= { "dlresume", 1, grectldlresume, },
  118. [GREctlulresume]= { "ulresume", 1, grectlulresume, },
  119. [GREctlforward] = { "forward", 2, grectlforward, },
  120. [GREctlulkey] = { "ulkey", 2, grectlulkey, },
  121. };
  122. static uint8_t nulladdr[4];
  123. static char *sessend = "session end";
  124. static void grekick(void *x, Block *bp);
  125. //static char *gresetup(Conv *, char *, char *, char *);
  126. uint32_t grepdin, grepdout, grebdin, grebdout;
  127. uint32_t grepuin, grepuout, grebuin, grebuout;
  128. static Block *
  129. getring(Bring *r)
  130. {
  131. Block *bp;
  132. if(r->consumed == r->produced)
  133. return nil;
  134. bp = r->ring[r->consumed & Ringmask];
  135. r->ring[r->consumed & Ringmask] = nil;
  136. r->consumed++;
  137. return bp;
  138. }
  139. static void
  140. addring(Bring *r, Block *bp)
  141. {
  142. Block *tbp;
  143. if(r->produced - r->consumed > Ringmask){
  144. /* Full! */
  145. tbp = r->ring[r->produced & Ringmask];
  146. assert(tbp);
  147. freeb(tbp);
  148. r->consumed++;
  149. }
  150. r->ring[r->produced & Ringmask] = bp;
  151. r->produced++;
  152. }
  153. static char *
  154. greconnect(Conv *c, char **argv, int argc)
  155. {
  156. Proto *p;
  157. char *err;
  158. Conv *tc, **cp, **ecp;
  159. err = Fsstdconnect(c, argv, argc);
  160. if(err != nil)
  161. return err;
  162. /* make sure noone's already connected to this other sys */
  163. p = c->p;
  164. qlock(&p->ql);
  165. ecp = &p->conv[p->nc];
  166. for(cp = p->conv; cp < ecp; cp++){
  167. tc = *cp;
  168. if(tc == nil)
  169. break;
  170. if(tc == c)
  171. continue;
  172. if(tc->rport == c->rport && ipcmp(tc->raddr, c->raddr) == 0){
  173. err = "already connected to that addr/proto";
  174. ipmove(c->laddr, IPnoaddr);
  175. ipmove(c->raddr, IPnoaddr);
  176. break;
  177. }
  178. }
  179. qunlock(&p->ql);
  180. if(err != nil)
  181. return err;
  182. Fsconnected(c, nil);
  183. return nil;
  184. }
  185. static void
  186. grecreate(Conv *c)
  187. {
  188. c->rq = qopen(GREqlen, Qmsg, 0, c);
  189. c->wq = qbypass(grekick, c);
  190. }
  191. static int
  192. grestate(Conv *c, char *state, int n)
  193. {
  194. GREconv *grec;
  195. char *ep, *p;
  196. grec = c->ptcl;
  197. p = state;
  198. ep = p + n;
  199. p = seprint(p, ep, "%s%s%s%shoa %V north %V south %V seq %lx "
  200. "pending %lu %lu buffered dl %lu %lu ul %lu %lu ulkey %.8lx\n",
  201. c->inuse? "Open ": "Closed ",
  202. grec->raw? "raw ": "",
  203. grec->dlsusp? "DL suspended ": "",
  204. grec->ulsusp? "UL suspended ": "",
  205. grec->hoa, grec->north, grec->south, grec->seq,
  206. grec->dlpending.consumed, grec->dlpending.produced,
  207. grec->dlbuffered.consumed, grec->dlbuffered.produced,
  208. grec->ulbuffered.consumed, grec->ulbuffered.produced,
  209. grec->ulkey);
  210. return p - state;
  211. }
  212. static char*
  213. greannounce(Conv* conv, char** c, int i)
  214. {
  215. return "gre does not support announce";
  216. }
  217. static void
  218. greclose(Conv *c)
  219. {
  220. GREconv *grec;
  221. Block *bp;
  222. grec = c->ptcl;
  223. /* Make sure we don't forward any more packets */
  224. memset(grec->hoa, 0, sizeof grec->hoa);
  225. memset(grec->north, 0, sizeof grec->north);
  226. memset(grec->south, 0, sizeof grec->south);
  227. qlock(&grec->lock);
  228. while((bp = getring(&grec->dlpending)) != nil)
  229. freeb(bp);
  230. while((bp = getring(&grec->dlbuffered)) != nil)
  231. freeb(bp);
  232. while((bp = getring(&grec->ulbuffered)) != nil)
  233. freeb(bp);
  234. grec->dlpending.produced = grec->dlpending.consumed = 0;
  235. grec->dlbuffered.produced = grec->dlbuffered.consumed = 0;
  236. grec->ulbuffered.produced = grec->ulbuffered.consumed = 0;
  237. qunlock(&grec->lock);
  238. grec->raw = 0;
  239. grec->seq = 0;
  240. grec->dlsusp = grec->ulsusp = 1;
  241. qhangup(c->rq, sessend);
  242. qhangup(c->wq, sessend);
  243. qhangup(c->eq, sessend);
  244. ipmove(c->laddr, IPnoaddr);
  245. ipmove(c->raddr, IPnoaddr);
  246. c->lport = c->rport = 0;
  247. }
  248. static void
  249. grekick(void *x, Block *bp)
  250. {
  251. Conv *c;
  252. GREconv *grec;
  253. GREhdr *gre;
  254. uint8_t laddr[IPaddrlen], raddr[IPaddrlen];
  255. if(bp == nil)
  256. return;
  257. c = x;
  258. grec = c->ptcl;
  259. /* Make space to fit ip header (gre header already there) */
  260. bp = padblock(bp, GRE_IPONLY);
  261. if(bp == nil)
  262. return;
  263. /* make sure the message has a GRE header */
  264. bp = pullupblock(bp, GRE_IPONLY+GRE_IPPLUSGRE);
  265. if(bp == nil)
  266. return;
  267. gre = (GREhdr *)bp->rp;
  268. gre->vihl = IP_VER4;
  269. if(grec->raw == 0){
  270. v4tov6(raddr, gre->dst);
  271. if(ipcmp(raddr, v4prefix) == 0)
  272. memmove(gre->dst, c->raddr + IPv4off, IPv4addrlen);
  273. v4tov6(laddr, gre->src);
  274. if(ipcmp(laddr, v4prefix) == 0){
  275. if(ipcmp(c->laddr, IPnoaddr) == 0)
  276. /* pick interface closest to dest */
  277. findlocalip(c->p->f, c->laddr, raddr);
  278. memmove(gre->src, c->laddr + IPv4off, sizeof gre->src);
  279. }
  280. hnputs(gre->eproto, c->rport);
  281. }
  282. gre->proto = IP_GREPROTO;
  283. gre->frag[0] = gre->frag[1] = 0;
  284. grepdout++;
  285. grebdout += BLEN(bp);
  286. ipoput4(c->p->f, bp, 0, c->ttl, c->tos, nil);
  287. }
  288. static void
  289. gredownlink(Conv *c, Block *bp)
  290. {
  291. Metablock *m;
  292. GREconv *grec;
  293. GREhdr *gre;
  294. int hdrlen, suspended, extra;
  295. uint16_t flags;
  296. uint32_t seq;
  297. gre = (GREhdr *)bp->rp;
  298. if(gre->ttl == 1){
  299. freeb(bp);
  300. return;
  301. }
  302. /*
  303. * We've received a packet with a GRE header and we need to
  304. * re-adjust the packet header to strip all unwanted parts
  305. * but leave room for only a sequence number.
  306. */
  307. grec = c->ptcl;
  308. flags = nhgets(gre->flags);
  309. hdrlen = 0;
  310. if(flags & GRE_cksum)
  311. hdrlen += 2;
  312. if(flags & GRE_routing){
  313. print("%V routing info present. Discarding packet", gre->src);
  314. freeb(bp);
  315. return;
  316. }
  317. if(flags & (GRE_cksum|GRE_routing))
  318. hdrlen += 2; /* Offset field */
  319. if(flags & GRE_key)
  320. hdrlen += 4;
  321. if(flags & GRE_seq)
  322. hdrlen += 4;
  323. /*
  324. * The outgoing packet only has the sequence number set. Make room
  325. * for the sequence number.
  326. */
  327. if(hdrlen != sizeof(uint32_t)){
  328. extra = hdrlen - sizeof(uint32_t);
  329. if(extra < 0 && bp->rp - bp->base < -extra){
  330. print("gredownlink: cannot add sequence number\n");
  331. freeb(bp);
  332. return;
  333. }
  334. memmove(bp->rp + extra, bp->rp, sizeof(GREhdr));
  335. bp->rp += extra;
  336. assert(BLEN(bp) >= sizeof(GREhdr) + sizeof(uint32_t));
  337. gre = (GREhdr *)bp->rp;
  338. }
  339. seq = grec->seq++;
  340. hnputs(gre->flags, GRE_seq);
  341. hnputl(bp->rp + sizeof(GREhdr), seq);
  342. /*
  343. * Keep rp and seq at the base. ipoput4 consumes rp for
  344. * refragmentation.
  345. */
  346. assert(bp->rp - bp->base >= sizeof(Metablock));
  347. m = (Metablock *)bp->base;
  348. m->rp = bp->rp;
  349. m->seq = seq;
  350. /*
  351. * Here we make a decision what we're doing with the packet. We're
  352. * doing this w/o holding a lock which means that later on in the
  353. * process we may discover we've done the wrong thing. I don't want
  354. * to call ipoput with the lock held.
  355. */
  356. restart:
  357. suspended = grec->dlsusp;
  358. if(suspended){
  359. if(!canqlock(&grec->lock)){
  360. /*
  361. * just give up. too bad, we lose a packet. this
  362. * is just too hard and my brain already hurts.
  363. */
  364. freeb(bp);
  365. return;
  366. }
  367. if(!grec->dlsusp){
  368. /*
  369. * suspend race. We though we were suspended, but
  370. * we really weren't.
  371. */
  372. qunlock(&grec->lock);
  373. goto restart;
  374. }
  375. /* Undo the incorrect ref count addition */
  376. addring(&grec->dlbuffered, bp);
  377. qunlock(&grec->lock);
  378. return;
  379. }
  380. /*
  381. * When we get here, we're not suspended. Proceed to send the
  382. * packet.
  383. */
  384. memmove(gre->src, grec->coa, sizeof gre->dst);
  385. memmove(gre->dst, grec->south, sizeof gre->dst);
  386. /*
  387. * Make sure the packet does not go away.
  388. */
  389. //_xinc(&bp->ref);
  390. ainc(&bp->ref);
  391. assert(bp->ref == 2);
  392. ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
  393. grepdout++;
  394. grebdout += BLEN(bp);
  395. /*
  396. * Now make sure we didn't do the wrong thing.
  397. */
  398. if(!canqlock(&grec->lock)){
  399. freeb(bp); /* The packet just goes away */
  400. return;
  401. }
  402. /* We did the right thing */
  403. addring(&grec->dlpending, bp);
  404. qunlock(&grec->lock);
  405. }
  406. static void
  407. greuplink(Conv *c, Block *bp)
  408. {
  409. GREconv *grec;
  410. GREhdr *gre;
  411. uint16_t flags;
  412. gre = (GREhdr *)bp->rp;
  413. if(gre->ttl == 1)
  414. return;
  415. grec = c->ptcl;
  416. memmove(gre->src, grec->coa, sizeof gre->src);
  417. memmove(gre->dst, grec->north, sizeof gre->dst);
  418. /*
  419. * Add a key, if needed.
  420. */
  421. if(grec->ulkey){
  422. flags = nhgets(gre->flags);
  423. if(flags & (GRE_cksum|GRE_routing)){
  424. print("%V routing info present. Discarding packet\n",
  425. gre->src);
  426. freeb(bp);
  427. return;
  428. }
  429. if((flags & GRE_key) == 0){
  430. /* Make room for the key */
  431. if(bp->rp - bp->base < sizeof(uint32_t)){
  432. print("%V can't add key\n", gre->src);
  433. freeb(bp);
  434. return;
  435. }
  436. bp->rp -= 4;
  437. memmove(bp->rp, bp->rp + 4, sizeof(GREhdr));
  438. gre = (GREhdr *)bp->rp;
  439. hnputs(gre->flags, flags | GRE_key);
  440. }
  441. /* Add the key */
  442. hnputl(bp->rp + sizeof(GREhdr), grec->ulkey);
  443. }
  444. if(!canqlock(&grec->lock)){
  445. freeb(bp);
  446. return;
  447. }
  448. if(grec->ulsusp)
  449. addring(&grec->ulbuffered, bp);
  450. else{
  451. ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
  452. grepuout++;
  453. grebuout += BLEN(bp);
  454. }
  455. qunlock(&grec->lock);
  456. }
  457. static void
  458. greiput(Proto *proto, Ipifc *ipifc, Block *bp)
  459. {
  460. int len, hdrlen;
  461. uint16_t eproto, flags;
  462. uint8_t raddr[IPaddrlen];
  463. Conv *c, **p;
  464. GREconv *grec;
  465. GREhdr *gre;
  466. GREpriv *gpriv;
  467. Ip4hdr *ip;
  468. /*
  469. * We don't want to deal with block lists. Ever. The problem is
  470. * that when the block is forwarded, devether.c puts the block into
  471. * a queue that also uses ->next. Just do not use ->next here!
  472. */
  473. if(bp->next){
  474. len = blocklen(bp);
  475. bp = pullupblock(bp, len);
  476. assert(BLEN(bp) == len && bp->next == nil);
  477. }
  478. gre = (GREhdr *)bp->rp;
  479. if(BLEN(bp) < sizeof(GREhdr) || gre->proto != IP_GREPROTO){
  480. freeb(bp);
  481. return;
  482. }
  483. v4tov6(raddr, gre->src);
  484. eproto = nhgets(gre->eproto);
  485. flags = nhgets(gre->flags);
  486. hdrlen = sizeof(GREhdr);
  487. if(flags & GRE_cksum)
  488. hdrlen += 2;
  489. if(flags & GRE_routing){
  490. print("%I routing info present. Discarding packet\n", raddr);
  491. freeb(bp);
  492. return;
  493. }
  494. if(flags & (GRE_cksum|GRE_routing))
  495. hdrlen += 2; /* Offset field */
  496. if(flags & GRE_key)
  497. hdrlen += 4;
  498. if(flags & GRE_seq)
  499. hdrlen += 4;
  500. if(BLEN(bp) - hdrlen < sizeof(Ip4hdr)){
  501. print("greretunnel: packet too short (s=%V d=%V)\n",
  502. gre->src, gre->dst);
  503. freeb(bp);
  504. return;
  505. }
  506. ip = (Ip4hdr *)(bp->rp + hdrlen);
  507. qlock(&proto->ql);
  508. /*
  509. * Look for a conversation structure for this port and address, or
  510. * match the retunnel part, or match on the raw flag.
  511. */
  512. for(p = proto->conv; *p; p++) {
  513. c = *p;
  514. if(c->inuse == 0)
  515. continue;
  516. /*
  517. * Do not stop this session - blocking here
  518. * implies that etherread is blocked.
  519. */
  520. grec = c->ptcl;
  521. if(memcmp(ip->dst, grec->hoa, sizeof ip->dst) == 0){
  522. grepdin++;
  523. grebdin += BLEN(bp);
  524. gredownlink(c, bp);
  525. qunlock(&proto->ql);
  526. return;
  527. }
  528. if(memcmp(ip->src, grec->hoa, sizeof ip->src) == 0){
  529. grepuin++;
  530. grebuin += BLEN(bp);
  531. greuplink(c, bp);
  532. qunlock(&proto->ql);
  533. return;
  534. }
  535. }
  536. /*
  537. * when we get here, none of the forwarding tunnels matched. now
  538. * try to match on raw and conversational sessions.
  539. */
  540. for(c = nil, p = proto->conv; *p; p++) {
  541. c = *p;
  542. if(c->inuse == 0)
  543. continue;
  544. /*
  545. * Do not stop this session - blocking here
  546. * implies that etherread is blocked.
  547. */
  548. grec = c->ptcl;
  549. if(c->rport == eproto &&
  550. (grec->raw || ipcmp(c->raddr, raddr) == 0))
  551. break;
  552. }
  553. qunlock(&proto->ql);
  554. if(*p == nil){
  555. freeb(bp);
  556. return;
  557. }
  558. /*
  559. * Trim the packet down to data size
  560. */
  561. len = nhgets(gre->len) - GRE_IPONLY;
  562. if(len < GRE_IPPLUSGRE){
  563. freeb(bp);
  564. return;
  565. }
  566. bp = trimblock(bp, GRE_IPONLY, len);
  567. if(bp == nil){
  568. gpriv = proto->priv;
  569. gpriv->lenerr++;
  570. return;
  571. }
  572. /*
  573. * Can't delimit packet so pull it all into one block.
  574. */
  575. if(qlen(c->rq) > GREqlen)
  576. freeb(bp);
  577. else{
  578. bp = concatblock(bp);
  579. if(bp == 0)
  580. panic("greiput");
  581. qpass(c->rq, bp);
  582. }
  583. }
  584. int
  585. grestats(Proto *gre, char *buf, int len)
  586. {
  587. GREpriv *gpriv;
  588. gpriv = gre->priv;
  589. return snprint(buf, len,
  590. "gre: %lu %lu %lu %lu %lu %lu %lu %lu, lenerrs %lu\n",
  591. grepdin, grepdout, grepuin, grepuout,
  592. grebdin, grebdout, grebuin, grebuout, gpriv->lenerr);
  593. }
  594. static char *
  595. grectlraw(Conv *c, int i, char **argv)
  596. {
  597. GREconv *grec;
  598. grec = c->ptcl;
  599. grec->raw = 1;
  600. return nil;
  601. }
  602. static char *
  603. grectlcooked(Conv *c, int i, char **argv)
  604. {
  605. GREconv *grec;
  606. grec = c->ptcl;
  607. grec->raw = 0;
  608. return nil;
  609. }
  610. static char *
  611. grectlretunnel(Conv *c, int i, char **argv)
  612. {
  613. GREconv *grec;
  614. uint8_t ipaddr[4];
  615. grec = c->ptcl;
  616. if(memcmp(grec->hoa, nulladdr, sizeof grec->hoa))
  617. return "tunnel already set up";
  618. v4parseip(ipaddr, argv[1]);
  619. if(memcmp(ipaddr, nulladdr, sizeof ipaddr) == 0)
  620. return "bad hoa";
  621. memmove(grec->hoa, ipaddr, sizeof grec->hoa);
  622. v4parseip(ipaddr, argv[2]);
  623. memmove(grec->north, ipaddr, sizeof grec->north);
  624. v4parseip(ipaddr, argv[3]);
  625. memmove(grec->south, ipaddr, sizeof grec->south);
  626. v4parseip(ipaddr, argv[4]);
  627. memmove(grec->coa, ipaddr, sizeof grec->coa);
  628. grec->ulsusp = 1;
  629. grec->dlsusp = 0;
  630. return nil;
  631. }
  632. static char *
  633. grectlreport(Conv *c, int i, char **argv)
  634. {
  635. uint32_t seq;
  636. Block *bp;
  637. Bring *r;
  638. GREconv *grec;
  639. Metablock *m;
  640. grec = c->ptcl;
  641. seq = strtoul(argv[1], nil, 0);
  642. qlock(&grec->lock);
  643. r = &grec->dlpending;
  644. while(r->produced - r->consumed > 0){
  645. bp = r->ring[r->consumed & Ringmask];
  646. assert(bp && bp->rp - bp->base >= sizeof(Metablock));
  647. m = (Metablock *)bp->base;
  648. if((int32_t)(seq - m->seq) <= 0)
  649. break;
  650. r->ring[r->consumed & Ringmask] = nil;
  651. r->consumed++;
  652. freeb(bp);
  653. }
  654. qunlock(&grec->lock);
  655. return nil;
  656. }
  657. static char *
  658. grectldlsuspend(Conv *c, int i, char **argv)
  659. {
  660. GREconv *grec;
  661. grec = c->ptcl;
  662. if(grec->dlsusp)
  663. return "already suspended";
  664. grec->dlsusp = 1;
  665. return nil;
  666. }
  667. static char *
  668. grectlulsuspend(Conv *c, int i, char **argv)
  669. {
  670. GREconv *grec;
  671. grec = c->ptcl;
  672. if(grec->ulsusp)
  673. return "already suspended";
  674. grec->ulsusp = 1;
  675. return nil;
  676. }
  677. static char *
  678. grectldlresume(Conv *c, int i, char **argv)
  679. {
  680. GREconv *grec;
  681. GREhdr *gre;
  682. Block *bp;
  683. grec = c->ptcl;
  684. qlock(&grec->lock);
  685. if(!grec->dlsusp){
  686. qunlock(&grec->lock);
  687. return "not suspended";
  688. }
  689. while((bp = getring(&grec->dlbuffered)) != nil){
  690. gre = (GREhdr *)bp->rp;
  691. qunlock(&grec->lock);
  692. /*
  693. * Make sure the packet does not go away.
  694. */
  695. //_xinc(&bp->ref);
  696. ainc(&bp->ref);
  697. assert(bp->ref == 2);
  698. ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
  699. qlock(&grec->lock);
  700. addring(&grec->dlpending, bp);
  701. }
  702. grec->dlsusp = 0;
  703. qunlock(&grec->lock);
  704. return nil;
  705. }
  706. static char *
  707. grectlulresume(Conv *c, int i, char **argv)
  708. {
  709. GREconv *grec;
  710. GREhdr *gre;
  711. Block *bp;
  712. grec = c->ptcl;
  713. qlock(&grec->lock);
  714. while((bp = getring(&grec->ulbuffered)) != nil){
  715. gre = (GREhdr *)bp->rp;
  716. qunlock(&grec->lock);
  717. ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
  718. qlock(&grec->lock);
  719. }
  720. grec->ulsusp = 0;
  721. qunlock(&grec->lock);
  722. return nil;
  723. }
  724. static char *
  725. grectlforward(Conv *c, int i, char **argv)
  726. {
  727. int len;
  728. Block *bp, *nbp;
  729. GREconv *grec;
  730. GREhdr *gre;
  731. Metablock *m;
  732. grec = c->ptcl;
  733. v4parseip(grec->south, argv[1]);
  734. memmove(grec->north, grec->south, sizeof grec->north);
  735. qlock(&grec->lock);
  736. if(!grec->dlsusp){
  737. qunlock(&grec->lock);
  738. return "not suspended";
  739. }
  740. grec->dlsusp = 0;
  741. grec->ulsusp = 0;
  742. while((bp = getring(&grec->dlpending)) != nil){
  743. assert(bp->rp - bp->base >= sizeof(Metablock));
  744. m = (Metablock *)bp->base;
  745. assert(m->rp >= bp->base && m->rp < bp->lim);
  746. /*
  747. * If the packet is still held inside the IP transmit
  748. * system, make a copy of the packet first.
  749. */
  750. if(bp->ref > 1){
  751. len = bp->wp - m->rp;
  752. nbp = allocb(len);
  753. memmove(nbp->wp, m->rp, len);
  754. nbp->wp += len;
  755. freeb(bp);
  756. bp = nbp;
  757. }
  758. else{
  759. /* Patch up rp */
  760. bp->rp = m->rp;
  761. }
  762. gre = (GREhdr *)bp->rp;
  763. memmove(gre->src, grec->coa, sizeof gre->dst);
  764. memmove(gre->dst, grec->south, sizeof gre->dst);
  765. qunlock(&grec->lock);
  766. ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
  767. qlock(&grec->lock);
  768. }
  769. while((bp = getring(&grec->dlbuffered)) != nil){
  770. gre = (GREhdr *)bp->rp;
  771. memmove(gre->src, grec->coa, sizeof gre->dst);
  772. memmove(gre->dst, grec->south, sizeof gre->dst);
  773. qunlock(&grec->lock);
  774. ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
  775. qlock(&grec->lock);
  776. }
  777. while((bp = getring(&grec->ulbuffered)) != nil){
  778. gre = (GREhdr *)bp->rp;
  779. memmove(gre->src, grec->coa, sizeof gre->dst);
  780. memmove(gre->dst, grec->south, sizeof gre->dst);
  781. qunlock(&grec->lock);
  782. ipoput4(c->p->f, bp, 0, gre->ttl - 1, gre->tos, nil);
  783. qlock(&grec->lock);
  784. }
  785. qunlock(&grec->lock);
  786. return nil;
  787. }
  788. static char *
  789. grectlulkey(Conv *c, int i, char **argv)
  790. {
  791. GREconv *grec;
  792. grec = c->ptcl;
  793. grec->ulkey = strtoul(argv[1], nil, 0);
  794. return nil;
  795. }
  796. char *
  797. grectl(Conv *c, char **f, int n)
  798. {
  799. int i;
  800. if(n < 1)
  801. return "too few arguments";
  802. for(i = 0; i < Ncmds; i++)
  803. if(strcmp(f[0], grectls[i].cmd) == 0)
  804. break;
  805. if(i == Ncmds)
  806. return "no such command";
  807. if(grectls[i].argc != 0 && grectls[i].argc != n)
  808. return "incorrect number of arguments";
  809. return grectls[i].f(c, n, f);
  810. }
  811. void
  812. greinit(Fs *fs)
  813. {
  814. Proto *gre;
  815. gre = smalloc(sizeof(Proto));
  816. gre->priv = smalloc(sizeof(GREpriv));
  817. gre->name = "gre";
  818. gre->connect = greconnect;
  819. gre->announce = greannounce;
  820. gre->state = grestate;
  821. gre->create = grecreate;
  822. gre->close = greclose;
  823. gre->rcv = greiput;
  824. gre->ctl = grectl;
  825. gre->advise = nil;
  826. gre->stats = grestats;
  827. gre->ipproto = IP_GREPROTO;
  828. gre->nc = 64;
  829. gre->ptclsize = sizeof(GREconv);
  830. Fsproto(fs, gre);
  831. }