gre.c 19 KB

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