ipmux.c 15 KB

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