ipmux.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  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. * IP packet filter
  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. #include "ipv6.h"
  20. typedef struct Ipmuxrock Ipmuxrock;
  21. typedef struct Ipmux Ipmux;
  22. typedef struct Myip4hdr Myip4hdr;
  23. struct Myip4hdr
  24. {
  25. uint8_t vihl; /* Version and header length */
  26. uint8_t tos; /* Type of service */
  27. uint8_t length[2]; /* packet length */
  28. uint8_t id[2]; /* ip->identification */
  29. uint8_t frag[2]; /* Fragment information */
  30. uint8_t ttl; /* Time to live */
  31. uint8_t proto; /* Protocol */
  32. uint8_t cksum[2]; /* Header checksum */
  33. uint8_t src[4]; /* IP source */
  34. uint8_t dst[4]; /* IP destination */
  35. uint8_t data[1]; /* start of data */
  36. };
  37. Myip4hdr *ipoff = 0;
  38. enum
  39. {
  40. Tproto,
  41. Tdata,
  42. Tiph,
  43. Tdst,
  44. Tsrc,
  45. Tifc,
  46. Cother = 0,
  47. Cbyte, /* single byte */
  48. Cmbyte, /* single byte with mask */
  49. Cshort, /* single short */
  50. Cmshort, /* single short with mask */
  51. Cint32_t, /* single int32_t */
  52. Cmint32_t, /* single int32_t with mask */
  53. Cifc,
  54. Cmifc,
  55. };
  56. char *ftname[] =
  57. {
  58. [Tproto] = "proto",
  59. [Tdata] = "data",
  60. [Tiph] = "iph",
  61. [Tdst] = "dst",
  62. [Tsrc] = "src",
  63. [Tifc] = "ifc",
  64. };
  65. /*
  66. * a node in the decision tree
  67. */
  68. struct Ipmux
  69. {
  70. Ipmux *yes;
  71. Ipmux *no;
  72. uint8_t type; /* type of field(Txxxx) */
  73. uint8_t ctype; /* tupe of comparison(Cxxxx) */
  74. uint8_t len; /* length in bytes of item to compare */
  75. uint8_t n; /* number of items val points to */
  76. short off; /* offset of comparison */
  77. short eoff; /* end offset of comparison */
  78. uint8_t skiphdr; /* should offset start after ipheader */
  79. uint8_t *val;
  80. uint8_t *mask;
  81. uint8_t *e; /* val+n*len*/
  82. int ref; /* so we can garbage collect */
  83. Conv *conv;
  84. };
  85. /*
  86. * someplace to hold per conversation data
  87. */
  88. struct Ipmuxrock
  89. {
  90. Ipmux *chain;
  91. };
  92. static int ipmuxsprint(Ipmux*, int, char*, int);
  93. static void ipmuxkick(void *x);
  94. static char*
  95. skipwhite(char *p)
  96. {
  97. while(*p == ' ' || *p == '\t')
  98. p++;
  99. return p;
  100. }
  101. static char*
  102. follows(char *p, char c)
  103. {
  104. char *f;
  105. f = strchr(p, c);
  106. if(f == nil)
  107. return nil;
  108. *f++ = 0;
  109. f = skipwhite(f);
  110. if(*f == 0)
  111. return nil;
  112. return f;
  113. }
  114. static Ipmux*
  115. parseop(char **pp)
  116. {
  117. char *p = *pp;
  118. int type, off, end, len;
  119. Ipmux *f;
  120. p = skipwhite(p);
  121. if(strncmp(p, "dst", 3) == 0){
  122. type = Tdst;
  123. off = (int64_t)(ipoff->dst);
  124. len = IPv4addrlen;
  125. p += 3;
  126. }
  127. else if(strncmp(p, "src", 3) == 0){
  128. type = Tsrc;
  129. off = (int64_t)(ipoff->src);
  130. len = IPv4addrlen;
  131. p += 3;
  132. }
  133. else if(strncmp(p, "ifc", 3) == 0){
  134. type = Tifc;
  135. off = -IPv4addrlen;
  136. len = IPv4addrlen;
  137. p += 3;
  138. }
  139. else if(strncmp(p, "proto", 5) == 0){
  140. type = Tproto;
  141. off = (int64_t)&(ipoff->proto);
  142. len = 1;
  143. p += 5;
  144. }
  145. else if(strncmp(p, "data", 4) == 0 || strncmp(p, "iph", 3) == 0){
  146. if(strncmp(p, "data", 4) == 0) {
  147. type = Tdata;
  148. p += 4;
  149. }
  150. else {
  151. type = Tiph;
  152. p += 3;
  153. }
  154. p = skipwhite(p);
  155. if(*p != '[')
  156. return nil;
  157. p++;
  158. off = strtoul(p, &p, 0);
  159. if(off < 0 || off > (64-IP4HDR))
  160. return nil;
  161. p = skipwhite(p);
  162. if(*p != ':')
  163. end = off;
  164. else {
  165. p++;
  166. p = skipwhite(p);
  167. end = strtoul(p, &p, 0);
  168. if(end < off)
  169. return nil;
  170. p = skipwhite(p);
  171. }
  172. if(*p != ']')
  173. return nil;
  174. p++;
  175. len = end - off + 1;
  176. }
  177. else
  178. return nil;
  179. f = smalloc(sizeof(*f));
  180. f->type = type;
  181. f->len = len;
  182. f->off = off;
  183. f->val = nil;
  184. f->mask = nil;
  185. f->n = 1;
  186. f->ref = 1;
  187. if(type == Tdata)
  188. f->skiphdr = 1;
  189. else
  190. f->skiphdr = 0;
  191. return f;
  192. }
  193. static int
  194. htoi(char x)
  195. {
  196. if(x >= '0' && x <= '9')
  197. x -= '0';
  198. else if(x >= 'a' && x <= 'f')
  199. x -= 'a' - 10;
  200. else if(x >= 'A' && x <= 'F')
  201. x -= 'A' - 10;
  202. else
  203. x = 0;
  204. return x;
  205. }
  206. static int
  207. hextoi(char *p)
  208. {
  209. return (htoi(p[0])<<4) | htoi(p[1]);
  210. }
  211. static void
  212. parseval(uint8_t *v, char *p, int len)
  213. {
  214. while(*p && len-- > 0){
  215. *v++ = hextoi(p);
  216. p += 2;
  217. }
  218. }
  219. static Ipmux*
  220. parsemux(char *p)
  221. {
  222. int n, nomask;
  223. Ipmux *f;
  224. char *val;
  225. char *mask;
  226. char *vals[20];
  227. uint8_t *v;
  228. /* parse operand */
  229. f = parseop(&p);
  230. if(f == nil)
  231. return nil;
  232. /* find value */
  233. val = follows(p, '=');
  234. if(val == nil)
  235. goto parseerror;
  236. /* parse mask */
  237. mask = follows(p, '&');
  238. if(mask != nil){
  239. switch(f->type){
  240. case Tsrc:
  241. case Tdst:
  242. case Tifc:
  243. f->mask = smalloc(f->len);
  244. v4parseip(f->mask, mask);
  245. break;
  246. case Tdata:
  247. case Tiph:
  248. f->mask = smalloc(f->len);
  249. parseval(f->mask, mask, f->len);
  250. break;
  251. default:
  252. goto parseerror;
  253. }
  254. nomask = 0;
  255. } else {
  256. nomask = 1;
  257. f->mask = smalloc(f->len);
  258. memset(f->mask, 0xff, f->len);
  259. }
  260. /* parse vals */
  261. f->n = getfields(val, vals, sizeof(vals)/sizeof(char*), 1, "|");
  262. if(f->n == 0)
  263. goto parseerror;
  264. f->val = smalloc(f->n*f->len);
  265. v = f->val;
  266. for(n = 0; n < f->n; n++){
  267. switch(f->type){
  268. case Tsrc:
  269. case Tdst:
  270. case Tifc:
  271. v4parseip(v, vals[n]);
  272. break;
  273. case Tproto:
  274. case Tdata:
  275. case Tiph:
  276. parseval(v, vals[n], f->len);
  277. break;
  278. }
  279. v += f->len;
  280. }
  281. f->eoff = f->off + f->len;
  282. f->e = f->val + f->n*f->len;
  283. f->ctype = Cother;
  284. if(f->n == 1){
  285. switch(f->len){
  286. case 1:
  287. f->ctype = nomask ? Cbyte : Cmbyte;
  288. break;
  289. case 2:
  290. f->ctype = nomask ? Cshort : Cmshort;
  291. break;
  292. case 4:
  293. if(f->type == Tifc)
  294. f->ctype = nomask ? Cifc : Cmifc;
  295. else
  296. f->ctype = nomask ? Cint32_t : Cmint32_t;
  297. break;
  298. }
  299. }
  300. return f;
  301. parseerror:
  302. if(f->mask)
  303. free(f->mask);
  304. if(f->val)
  305. free(f->val);
  306. free(f);
  307. return nil;
  308. }
  309. /*
  310. * Compare relative ordering of two ipmuxs. This doesn't compare the
  311. * values, just the fields being looked at.
  312. *
  313. * returns: <0 if a is a more specific match
  314. * 0 if a and b are matching on the same fields
  315. * >0 if b is a more specific match
  316. */
  317. static int
  318. ipmuxcmp(Ipmux *a, Ipmux *b)
  319. {
  320. int n;
  321. /* compare types, lesser ones are more important */
  322. n = a->type - b->type;
  323. if(n != 0)
  324. return n;
  325. /* compare offsets, call earlier ones more specific */
  326. n = (a->off+((int)a->skiphdr)*(int64_t)ipoff->data) -
  327. (b->off+((int)b->skiphdr)*(int64_t)ipoff->data);
  328. if(n != 0)
  329. return n;
  330. /* compare match lengths, int32_ter ones are more specific */
  331. n = b->len - a->len;
  332. if(n != 0)
  333. return n;
  334. /*
  335. * if we get here we have two entries matching
  336. * the same bytes of the record. Now check
  337. * the mask for equality. Longer masks are
  338. * more specific.
  339. */
  340. if(a->mask != nil && b->mask == nil)
  341. return -1;
  342. if(a->mask == nil && b->mask != nil)
  343. return 1;
  344. if(a->mask != nil && b->mask != nil){
  345. n = memcmp(b->mask, a->mask, a->len);
  346. if(n != 0)
  347. return n;
  348. }
  349. return 0;
  350. }
  351. /*
  352. * Compare the values of two ipmuxs. We're assuming that ipmuxcmp
  353. * returned 0 comparing them.
  354. */
  355. static int
  356. ipmuxvalcmp(Ipmux *a, Ipmux *b)
  357. {
  358. int n;
  359. n = b->len*b->n - a->len*a->n;
  360. if(n != 0)
  361. return n;
  362. return memcmp(a->val, b->val, a->len*a->n);
  363. }
  364. /*
  365. * add onto an existing ipmux chain in the canonical comparison
  366. * order
  367. */
  368. static void
  369. ipmuxchain(Ipmux **l, Ipmux *f)
  370. {
  371. for(; *l; l = &(*l)->yes)
  372. if(ipmuxcmp(f, *l) < 0)
  373. break;
  374. f->yes = *l;
  375. *l = f;
  376. }
  377. /*
  378. * copy a tree
  379. */
  380. static Ipmux*
  381. ipmuxcopy(Ipmux *f)
  382. {
  383. Ipmux *nf;
  384. if(f == nil)
  385. return nil;
  386. nf = smalloc(sizeof *nf);
  387. *nf = *f;
  388. nf->no = ipmuxcopy(f->no);
  389. nf->yes = ipmuxcopy(f->yes);
  390. nf->val = smalloc(f->n*f->len);
  391. nf->e = nf->val + f->len*f->n;
  392. memmove(nf->val, f->val, f->n*f->len);
  393. return nf;
  394. }
  395. static void
  396. ipmuxfree(Ipmux *f)
  397. {
  398. if(f->val != nil)
  399. free(f->val);
  400. free(f);
  401. }
  402. static void
  403. ipmuxtreefree(Ipmux *f)
  404. {
  405. if(f == nil)
  406. return;
  407. if(f->no != nil)
  408. ipmuxfree(f->no);
  409. if(f->yes != nil)
  410. ipmuxfree(f->yes);
  411. ipmuxfree(f);
  412. }
  413. /*
  414. * merge two trees
  415. */
  416. static Ipmux*
  417. ipmuxmerge(Ipmux *a, Ipmux *b)
  418. {
  419. int n;
  420. Ipmux *f;
  421. if(a == nil)
  422. return b;
  423. if(b == nil)
  424. return a;
  425. n = ipmuxcmp(a, b);
  426. if(n < 0){
  427. f = ipmuxcopy(b);
  428. a->yes = ipmuxmerge(a->yes, b);
  429. a->no = ipmuxmerge(a->no, f);
  430. return a;
  431. }
  432. if(n > 0){
  433. f = ipmuxcopy(a);
  434. b->yes = ipmuxmerge(b->yes, a);
  435. b->no = ipmuxmerge(b->no, f);
  436. return b;
  437. }
  438. if(ipmuxvalcmp(a, b) == 0){
  439. a->yes = ipmuxmerge(a->yes, b->yes);
  440. a->no = ipmuxmerge(a->no, b->no);
  441. a->ref++;
  442. ipmuxfree(b);
  443. return a;
  444. }
  445. a->no = ipmuxmerge(a->no, b);
  446. return a;
  447. }
  448. /*
  449. * remove a chain from a demux tree. This is like merging accept that
  450. * we remove instead of insert.
  451. */
  452. static int
  453. ipmuxremove(Ipmux **l, Ipmux *f)
  454. {
  455. int n, rv;
  456. Ipmux *ft;
  457. if(f == nil)
  458. return 0; /* we've removed it all */
  459. if(*l == nil)
  460. return -1;
  461. ft = *l;
  462. n = ipmuxcmp(ft, f);
  463. if(n < 0){
  464. /* *l is maching an earlier field, descend both paths */
  465. rv = ipmuxremove(&ft->yes, f);
  466. rv += ipmuxremove(&ft->no, f);
  467. return rv;
  468. }
  469. if(n > 0){
  470. /* f represents an earlier field than *l, this should be impossible */
  471. return -1;
  472. }
  473. /* if we get here f and *l are comparing the same fields */
  474. if(ipmuxvalcmp(ft, f) != 0){
  475. /* different values mean mutually exclusive */
  476. return ipmuxremove(&ft->no, f);
  477. }
  478. /* we found a match */
  479. if(--(ft->ref) == 0){
  480. /*
  481. * a dead node implies the whole yes side is also dead.
  482. * since our chain is constrained to be on that side,
  483. * we're done.
  484. */
  485. ipmuxtreefree(ft->yes);
  486. *l = ft->no;
  487. ipmuxfree(ft);
  488. return 0;
  489. }
  490. /*
  491. * free the rest of the chain. it is constrained to match the
  492. * yes side.
  493. */
  494. return ipmuxremove(&ft->yes, f->yes);
  495. }
  496. /*
  497. * connection request is a semi separated list of filters
  498. * e.g. proto=17;data[0:4]=11aa22bb;ifc=135.104.9.2&255.255.255.0
  499. *
  500. * there's no protection against overlapping specs.
  501. */
  502. static char*
  503. ipmuxconnect(Conv *c, char **argv, int argc)
  504. {
  505. int i, n;
  506. char *field[10];
  507. Ipmux *mux, *chain;
  508. Ipmuxrock *r;
  509. Fs *f;
  510. f = c->p->f;
  511. if(argc != 2)
  512. return Ebadarg;
  513. n = getfields(argv[1], field, nelem(field), 1, ";");
  514. if(n <= 0)
  515. return Ebadarg;
  516. chain = nil;
  517. mux = nil;
  518. for(i = 0; i < n; i++){
  519. mux = parsemux(field[i]);
  520. if(mux == nil){
  521. ipmuxtreefree(chain);
  522. return Ebadarg;
  523. }
  524. ipmuxchain(&chain, mux);
  525. }
  526. if(chain == nil)
  527. return Ebadarg;
  528. mux->conv = c;
  529. /* save a copy of the chain so we can later remove it */
  530. mux = ipmuxcopy(chain);
  531. r = (Ipmuxrock*)(c->ptcl);
  532. r->chain = chain;
  533. /* add the chain to the protocol demultiplexor tree */
  534. wlock(&f->rwl);
  535. f->ipmux->priv = ipmuxmerge(f->ipmux->priv, mux);
  536. wunlock(&f->rwl);
  537. Fsconnected(c, nil);
  538. return nil;
  539. }
  540. static int
  541. ipmuxstate(Conv *c, char *state, int n)
  542. {
  543. Ipmuxrock *r;
  544. r = (Ipmuxrock*)(c->ptcl);
  545. return ipmuxsprint(r->chain, 0, state, n);
  546. }
  547. static void
  548. ipmuxcreate(Conv *c)
  549. {
  550. Ipmuxrock *r;
  551. c->rq = qopen(64*1024, Qmsg, 0, c);
  552. c->wq = qopen(64*1024, Qkick, ipmuxkick, c);
  553. r = (Ipmuxrock*)(c->ptcl);
  554. r->chain = nil;
  555. }
  556. static char*
  557. ipmuxannounce(Conv *conv, char **argv, int i)
  558. {
  559. return "ipmux does not support announce";
  560. }
  561. static void
  562. ipmuxclose(Conv *c)
  563. {
  564. Ipmuxrock *r;
  565. Fs *f = c->p->f;
  566. r = (Ipmuxrock*)(c->ptcl);
  567. qclose(c->rq);
  568. qclose(c->wq);
  569. qclose(c->eq);
  570. ipmove(c->laddr, IPnoaddr);
  571. ipmove(c->raddr, IPnoaddr);
  572. c->lport = 0;
  573. c->rport = 0;
  574. wlock(&f->rwl);
  575. ipmuxremove((struct Ipmux **)&(c->p->priv), r->chain);
  576. wunlock(&f->rwl);
  577. ipmuxtreefree(r->chain);
  578. r->chain = nil;
  579. }
  580. /*
  581. * takes a fully formed ip packet and just passes it down
  582. * the stack
  583. */
  584. static void
  585. ipmuxkick(void *x)
  586. {
  587. Conv *c = x;
  588. Block *bp;
  589. bp = qget(c->wq);
  590. if(bp != nil) {
  591. Myip4hdr *ih4 = (Myip4hdr*)(bp->rp);
  592. if((ih4->vihl & 0xF0) != IP_VER6)
  593. ipoput4(c->p->f, bp, 0, ih4->ttl, ih4->tos, nil);
  594. else
  595. ipoput6(c->p->f, bp, 0, ((Ip6hdr*)ih4)->ttl, 0, nil);
  596. }
  597. }
  598. static void
  599. ipmuxiput(Proto *p, Ipifc *ifc, Block *bp)
  600. {
  601. int len, hl;
  602. Fs *f = p->f;
  603. uint8_t *m, *h, *v, *e, *ve, *hp;
  604. Conv *c;
  605. Ipmux *mux;
  606. Myip4hdr *ip;
  607. Ip6hdr *ip6;
  608. ip = (Myip4hdr*)bp->rp;
  609. hl = (ip->vihl&0x0F)<<2;
  610. if(p->priv == nil)
  611. goto nomatch;
  612. h = bp->rp;
  613. len = BLEN(bp);
  614. /* run the v4 filter */
  615. rlock(&f->rwl);
  616. c = nil;
  617. mux = f->ipmux->priv;
  618. while(mux != nil){
  619. if(mux->eoff > len){
  620. mux = mux->no;
  621. continue;
  622. }
  623. hp = h + mux->off + ((int)mux->skiphdr)*hl;
  624. switch(mux->ctype){
  625. case Cbyte:
  626. if(*mux->val == *hp)
  627. goto yes;
  628. break;
  629. case Cmbyte:
  630. if((*hp & *mux->mask) == *mux->val)
  631. goto yes;
  632. break;
  633. case Cshort:
  634. if(*((uint16_t*)mux->val) == *(uint16_t*)hp)
  635. goto yes;
  636. break;
  637. case Cmshort:
  638. if((*(uint16_t*)hp & (*((uint16_t*)mux->mask))) == *((uint16_t*)mux->val))
  639. goto yes;
  640. break;
  641. case Cint32_t:
  642. if(*((uint32_t*)mux->val) == *(uint32_t*)hp)
  643. goto yes;
  644. break;
  645. case Cmint32_t:
  646. if((*(uint32_t*)hp & (*((uint32_t*)mux->mask))) == *((uint32_t*)mux->val))
  647. goto yes;
  648. break;
  649. case Cifc:
  650. if(*((uint32_t*)mux->val) == *(uint32_t*)(ifc->lifc->local + IPv4off))
  651. goto yes;
  652. break;
  653. case Cmifc:
  654. if((*(uint32_t*)(ifc->lifc->local + IPv4off) & (*((uint32_t*)mux->mask))) == *((uint32_t*)mux->val))
  655. goto yes;
  656. break;
  657. default:
  658. v = mux->val;
  659. for(e = mux->e; v < e; v = ve){
  660. m = mux->mask;
  661. hp = h + mux->off;
  662. for(ve = v + mux->len; v < ve; v++){
  663. if((*hp++ & *m++) != *v)
  664. break;
  665. }
  666. if(v == ve)
  667. goto yes;
  668. }
  669. }
  670. mux = mux->no;
  671. continue;
  672. yes:
  673. if(mux->conv != nil)
  674. c = mux->conv;
  675. mux = mux->yes;
  676. }
  677. runlock(&f->rwl);
  678. if(c != nil){
  679. /* tack on interface address */
  680. bp = padblock(bp, IPaddrlen);
  681. ipmove(bp->rp, ifc->lifc->local);
  682. bp = concatblock(bp);
  683. if(bp != nil)
  684. if(qpass(c->rq, bp) < 0)
  685. print("ipmuxiput: qpass failed\n");
  686. return;
  687. }
  688. nomatch:
  689. /* doesn't match any filter, hand it to the specific protocol handler */
  690. ip = (Myip4hdr*)bp->rp;
  691. if((ip->vihl & 0xF0) == IP_VER4) {
  692. p = f->t2p[ip->proto];
  693. } else {
  694. ip6 = (Ip6hdr*)bp->rp;
  695. p = f->t2p[ip6->proto];
  696. }
  697. if(p && p->rcv)
  698. (*p->rcv)(p, ifc, bp);
  699. else
  700. freeblist(bp);
  701. return;
  702. }
  703. static int
  704. ipmuxsprint(Ipmux *mux, int level, char *buf, int len)
  705. {
  706. int i, j, n;
  707. uint8_t *v;
  708. n = 0;
  709. for(i = 0; i < level; i++)
  710. n += snprint(buf+n, len-n, " ");
  711. if(mux == nil){
  712. n += snprint(buf+n, len-n, "\n");
  713. return n;
  714. }
  715. n += snprint(buf+n, len-n, "h[%d:%d]&",
  716. mux->off+((int)mux->skiphdr)*((int64_t)ipoff->data),
  717. mux->off+(((int)mux->skiphdr)*((int64_t)ipoff->data))+mux->len-1);
  718. for(i = 0; i < mux->len; i++)
  719. n += snprint(buf+n, len - n, "%2.2x", mux->mask[i]);
  720. n += snprint(buf+n, len-n, "=");
  721. v = mux->val;
  722. for(j = 0; j < mux->n; j++){
  723. for(i = 0; i < mux->len; i++)
  724. n += snprint(buf+n, len - n, "%2.2x", *v++);
  725. n += snprint(buf+n, len-n, "|");
  726. }
  727. n += snprint(buf+n, len-n, "\n");
  728. level++;
  729. n += ipmuxsprint(mux->no, level, buf+n, len-n);
  730. n += ipmuxsprint(mux->yes, level, buf+n, len-n);
  731. return n;
  732. }
  733. static int
  734. ipmuxstats(Proto *p, char *buf, int len)
  735. {
  736. int n;
  737. Fs *f = p->f;
  738. rlock(&f->rwl);
  739. n = ipmuxsprint(p->priv, 0, buf, len);
  740. runlock(&f->rwl);
  741. return n;
  742. }
  743. void
  744. ipmuxinit(Fs *f)
  745. {
  746. Proto *ipmux;
  747. ipmux = smalloc(sizeof(Proto));
  748. ipmux->priv = nil;
  749. ipmux->name = "ipmux";
  750. ipmux->connect = ipmuxconnect;
  751. ipmux->announce = ipmuxannounce;
  752. ipmux->state = ipmuxstate;
  753. ipmux->create = ipmuxcreate;
  754. ipmux->close = ipmuxclose;
  755. ipmux->rcv = ipmuxiput;
  756. ipmux->ctl = nil;
  757. ipmux->advise = nil;
  758. ipmux->stats = ipmuxstats;
  759. ipmux->ipproto = -1;
  760. ipmux->nc = 64;
  761. ipmux->ptclsize = sizeof(Ipmuxrock);
  762. f->ipmux = ipmux; /* hack for Fsrcvpcol */
  763. Fsproto(f, ipmux);
  764. }