main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. #include <bio.h>
  5. #include <fcall.h>
  6. #include <libsec.h>
  7. #include "dat.h"
  8. #include "protos.h"
  9. #include "y.tab.h"
  10. int Cflag;
  11. int pflag;
  12. int Nflag;
  13. int sflag;
  14. int tiflag;
  15. int toflag;
  16. char *prom = "promiscuous";
  17. enum
  18. {
  19. Pktlen= 64*1024,
  20. Blen= 16*1024,
  21. };
  22. Filter *filter;
  23. Proto *root;
  24. Biobuf out;
  25. vlong starttime, pkttime;
  26. int pcap;
  27. int filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int);
  28. void printpkt(char *p, char *e, uchar *ps, uchar *pe);
  29. void mkprotograph(void);
  30. Proto* findproto(char *name);
  31. Filter* compile(Filter *f);
  32. void printfilter(Filter *f, char *tag);
  33. void printhelp(char*);
  34. void tracepkt(uchar*, int);
  35. void pcaphdr(void);
  36. void
  37. printusage(void)
  38. {
  39. fprint(2, "usage: %s [-CDdpst] [-N n] [-f filter] [-h first-header] path\n", argv0);
  40. fprint(2, " for protocol help: %s -? [proto]\n", argv0);
  41. }
  42. void
  43. usage(void)
  44. {
  45. printusage();
  46. exits("usage");
  47. }
  48. void
  49. main(int argc, char **argv)
  50. {
  51. uchar *pkt;
  52. char *buf, *file, *p, *e;
  53. int fd, cfd;
  54. int n;
  55. Binit(&out, 1, OWRITE);
  56. fmtinstall('E', eipfmt);
  57. fmtinstall('V', eipfmt);
  58. fmtinstall('I', eipfmt);
  59. fmtinstall('H', encodefmt);
  60. fmtinstall('F', fcallfmt);
  61. pkt = malloc(Pktlen+16);
  62. pkt += 16;
  63. buf = malloc(Blen);
  64. e = buf+Blen-1;
  65. pflag = 1;
  66. Nflag = 32;
  67. sflag = 0;
  68. mkprotograph();
  69. ARGBEGIN{
  70. default:
  71. usage();
  72. case '?':
  73. printusage();
  74. printhelp(ARGF());
  75. exits(0);
  76. break;
  77. case 'N':
  78. p = EARGF(usage());
  79. Nflag = atoi(p);
  80. break;
  81. case 'f':
  82. p = EARGF(usage());
  83. yyinit(p);
  84. yyparse();
  85. break;
  86. case 's':
  87. sflag = 1;
  88. break;
  89. case 'h':
  90. p = EARGF(usage());
  91. root = findproto(p);
  92. if(root == nil)
  93. sysfatal("unknown protocol: %s", p);
  94. break;
  95. case 'd':
  96. toflag = 1;
  97. break;
  98. case 'D':
  99. toflag = 1;
  100. pcap = 1;
  101. break;
  102. case 't':
  103. tiflag = 1;
  104. break;
  105. case 'C':
  106. Cflag = 1;
  107. break;
  108. case 'p':
  109. pflag = 0;
  110. break;
  111. }ARGEND;
  112. if(pcap)
  113. pcaphdr();
  114. if(argc == 0){
  115. file = "/net/ether0";
  116. if(root != nil)
  117. root = &ether;
  118. } else
  119. file = argv[0];
  120. if((!tiflag) && strstr(file, "ether")){
  121. if(root == nil)
  122. root = &ether;
  123. snprint(buf, Blen, "%s!-1", file);
  124. fd = dial(buf, 0, 0, &cfd);
  125. if(fd < 0)
  126. sysfatal("dialing %s", buf);
  127. if(pflag && fprint(cfd, prom, strlen(prom)) < 0)
  128. sysfatal("setting %s", prom);
  129. } else if((!tiflag) && strstr(file, "ipifc")){
  130. if(root == nil)
  131. root = &ip;
  132. snprint(buf, Blen, "%s/snoop", file);
  133. fd = open(buf, OREAD);
  134. if(fd < 0)
  135. sysfatal("opening %s: %r", buf);
  136. } else {
  137. if(root == nil)
  138. root = &ether;
  139. fd = open(file, OREAD);
  140. if(fd < 0)
  141. sysfatal("opening %s: %r", file);
  142. }
  143. filter = compile(filter);
  144. if(tiflag){
  145. /* read a trace file */
  146. for(;;){
  147. n = read(fd, pkt, 10);
  148. if(n != 10)
  149. break;
  150. pkttime = NetL(pkt+2);
  151. pkttime = (pkttime<<32) | NetL(pkt+6);
  152. if(starttime == 0LL)
  153. starttime = pkttime;
  154. n = NetS(pkt);
  155. if(readn(fd, pkt, n) != n)
  156. break;
  157. if(filterpkt(filter, pkt, pkt+n, root, 1))
  158. if(toflag)
  159. tracepkt(pkt, n);
  160. else
  161. printpkt(buf, e, pkt, pkt+n);
  162. }
  163. } else {
  164. /* read a real time stream */
  165. starttime = nsec();
  166. for(;;){
  167. n = root->framer(fd, pkt, Pktlen);
  168. if(n <= 0)
  169. break;
  170. pkttime = nsec();
  171. if(filterpkt(filter, pkt, pkt+n, root, 1))
  172. if(toflag)
  173. tracepkt(pkt, n);
  174. else
  175. printpkt(buf, e, pkt, pkt+n);
  176. }
  177. }
  178. }
  179. /* create a new filter node */
  180. Filter*
  181. newfilter(void)
  182. {
  183. Filter *f;
  184. f = mallocz(sizeof(*f), 1);
  185. if(f == nil)
  186. sysfatal("newfilter: %r");
  187. return f;
  188. }
  189. /*
  190. * apply filter to packet
  191. */
  192. int
  193. _filterpkt(Filter *f, Msg *m)
  194. {
  195. Msg ma;
  196. if(f == nil)
  197. return 1;
  198. switch(f->op){
  199. case '!':
  200. return !_filterpkt(f->l, m);
  201. case LAND:
  202. ma = *m;
  203. return _filterpkt(f->l, &ma) && _filterpkt(f->r, m);
  204. case LOR:
  205. ma = *m;
  206. return _filterpkt(f->l, &ma) || _filterpkt(f->r, m);
  207. case WORD:
  208. if(m->needroot){
  209. if(m->pr != f->pr)
  210. return 0;
  211. m->needroot = 0;
  212. }else{
  213. if(m->pr != nil && !(m->pr->filter)(f, m))
  214. return 0;
  215. }
  216. if(f->l == nil)
  217. return 1;
  218. m->pr = f->pr;
  219. return _filterpkt(f->l, m);
  220. }
  221. sysfatal("internal error: filterpkt op: %d", f->op);
  222. return 0;
  223. }
  224. int
  225. filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot)
  226. {
  227. Msg m;
  228. if(f == nil)
  229. return 1;
  230. m.needroot = needroot;
  231. m.ps = ps;
  232. m.pe = pe;
  233. m.pr = pr;
  234. return _filterpkt(f, &m);
  235. }
  236. /*
  237. * from the Unix world
  238. */
  239. #define PCAP_VERSION_MAJOR 2
  240. #define PCAP_VERSION_MINOR 4
  241. #define TCPDUMP_MAGIC 0xa1b2c3d4
  242. struct pcap_file_header {
  243. ulong magic;
  244. ushort version_major;
  245. ushort version_minor;
  246. long thiszone; /* gmt to local correction */
  247. ulong sigfigs; /* accuracy of timestamps */
  248. ulong snaplen; /* max length saved portion of each pkt */
  249. ulong linktype; /* data link type (DLT_*) */
  250. };
  251. struct pcap_pkthdr {
  252. uvlong ts; /* time stamp */
  253. ulong caplen; /* length of portion present */
  254. ulong len; /* length this packet (off wire) */
  255. };
  256. /*
  257. * pcap trace header
  258. */
  259. void
  260. pcaphdr(void)
  261. {
  262. struct pcap_file_header hdr;
  263. hdr.magic = TCPDUMP_MAGIC;
  264. hdr.version_major = PCAP_VERSION_MAJOR;
  265. hdr.version_minor = PCAP_VERSION_MINOR;
  266. hdr.thiszone = 0;
  267. hdr.snaplen = 1500;
  268. hdr.sigfigs = 0;
  269. hdr.linktype = 1;
  270. write(1, &hdr, sizeof(hdr));
  271. }
  272. /*
  273. * write out a packet trace
  274. */
  275. void
  276. tracepkt(uchar *ps, int len)
  277. {
  278. struct pcap_pkthdr *goo;
  279. if(pcap){
  280. goo = (struct pcap_pkthdr*)(ps-16);
  281. goo->ts = pkttime;
  282. goo->caplen = len;
  283. goo->len = len;
  284. write(1, goo, len+16);
  285. } else {
  286. hnputs(ps-10, len);
  287. hnputl(ps-8, pkttime>>32);
  288. hnputl(ps-4, pkttime);
  289. write(1, ps-10, len+10);
  290. }
  291. }
  292. /*
  293. * format and print a packet
  294. */
  295. void
  296. printpkt(char *p, char *e, uchar *ps, uchar *pe)
  297. {
  298. Msg m;
  299. ulong dt;
  300. dt = (pkttime-starttime)/1000000LL;
  301. m.p = seprint(p, e, "%6.6uld ms ", dt);
  302. m.ps = ps;
  303. m.pe = pe;
  304. m.e = e;
  305. m.pr = root;
  306. while(m.p < m.e){
  307. if(!sflag)
  308. m.p = seprint(m.p, m.e, "\n\t");
  309. m.p = seprint(m.p, m.e, "%s(", m.pr->name);
  310. if((*m.pr->seprint)(&m) < 0){
  311. m.p = seprint(m.p, m.e, "TOO SHORT");
  312. m.ps = m.pe;
  313. }
  314. m.p = seprint(m.p, m.e, ")");
  315. if(m.pr == nil || m.ps >= m.pe)
  316. break;
  317. }
  318. *m.p++ = '\n';
  319. if(write(1, p, m.p - p) < 0)
  320. sysfatal("stdout: %r");
  321. }
  322. Proto **xprotos;
  323. int nprotos;
  324. /* look up a protocol by its name */
  325. Proto*
  326. findproto(char *name)
  327. {
  328. int i;
  329. for(i = 0; i < nprotos; i++)
  330. if(strcmp(xprotos[i]->name, name) == 0)
  331. return xprotos[i];
  332. return nil;
  333. }
  334. /*
  335. * add an undefined protocol to protos[]
  336. */
  337. Proto*
  338. addproto(char *name)
  339. {
  340. Proto *pr;
  341. xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*));
  342. pr = malloc(sizeof *pr);
  343. *pr = dump;
  344. pr->name = name;
  345. xprotos[nprotos++] = pr;
  346. return pr;
  347. }
  348. /*
  349. * build a graph of protocols, this could easily be circular. This
  350. * links together all the multiplexing in the protocol modules.
  351. */
  352. void
  353. mkprotograph(void)
  354. {
  355. Proto **l;
  356. Proto *pr;
  357. Mux *m;
  358. /* copy protos into a reallocable area */
  359. for(nprotos = 0; protos[nprotos] != nil; nprotos++)
  360. ;
  361. xprotos = malloc(nprotos*sizeof(Proto*));
  362. memmove(xprotos, protos, nprotos*sizeof(Proto*));
  363. for(l = protos; *l != nil; l++){
  364. pr = *l;
  365. for(m = pr->mux; m != nil && m->name != nil; m++){
  366. m->pr = findproto(m->name);
  367. if(m->pr == nil)
  368. m->pr = addproto(m->name);
  369. }
  370. }
  371. }
  372. /*
  373. * add in a protocol node
  374. */
  375. static Filter*
  376. addnode(Filter *f, Proto *pr)
  377. {
  378. Filter *nf;
  379. nf = newfilter();
  380. nf->pr = pr;
  381. nf->s = pr->name;
  382. nf->l = f;
  383. nf->op = WORD;
  384. return nf;
  385. }
  386. /*
  387. * recurse through the protocol graph adding missing nodes
  388. * to the filter if we reach the filter's protocol
  389. */
  390. static Filter*
  391. _fillin(Filter *f, Proto *last, int depth)
  392. {
  393. Mux *m;
  394. Filter *nf;
  395. if(depth-- <= 0)
  396. return nil;
  397. for(m = last->mux; m != nil && m->name != nil; m++){
  398. if(m->pr == nil)
  399. continue;
  400. if(f->pr == m->pr)
  401. return f;
  402. nf = _fillin(f, m->pr, depth);
  403. if(nf != nil)
  404. return addnode(nf, m->pr);
  405. }
  406. return nil;
  407. }
  408. static Filter*
  409. fillin(Filter *f, Proto *last)
  410. {
  411. int i;
  412. Filter *nf;
  413. /* hack to make sure top level node is the root */
  414. if(last == nil){
  415. if(f->pr == root)
  416. return f;
  417. f = fillin(f, root);
  418. if(f == nil)
  419. return nil;
  420. return addnode(f, root);
  421. }
  422. /* breadth first search though the protocol graph */
  423. nf = f;
  424. for(i = 1; i < 20; i++){
  425. nf = _fillin(f, last, i);
  426. if(nf != nil)
  427. break;
  428. }
  429. return nf;
  430. }
  431. /*
  432. * massage tree so that all paths from the root to a leaf
  433. * contain a filter node for each header.
  434. *
  435. * also, set f->pr where possible
  436. */
  437. Filter*
  438. complete(Filter *f, Proto *last)
  439. {
  440. Proto *pr;
  441. if(f == nil)
  442. return f;
  443. /* do a depth first traversal of the filter tree */
  444. switch(f->op){
  445. case '!':
  446. f->l = complete(f->l, last);
  447. break;
  448. case LAND:
  449. case LOR:
  450. f->l = complete(f->l, last);
  451. f->r = complete(f->r, last);
  452. break;
  453. case '=':
  454. break;
  455. case WORD:
  456. pr = findproto(f->s);
  457. f->pr = pr;
  458. if(pr == nil){
  459. if(f->l != nil){
  460. fprint(2, "%s unknown proto, ignoring params\n",
  461. f->s);
  462. f->l = nil;
  463. }
  464. } else {
  465. f->l = complete(f->l, pr);
  466. f = fillin(f, last);
  467. if(f == nil)
  468. sysfatal("internal error: can't get to %s", pr->name);
  469. }
  470. break;
  471. }
  472. return f;
  473. }
  474. /*
  475. * merge common nodes under | and & moving the merged node
  476. * above the | or &.
  477. *
  478. * do some constant foldong, e.g. `true & x' becomes x and
  479. * 'true | x' becomes true.
  480. */
  481. static int changed;
  482. static Filter*
  483. _optimize(Filter *f)
  484. {
  485. Filter *l;
  486. if(f == nil)
  487. return f;
  488. switch(f->op){
  489. case '!':
  490. /* is child also a not */
  491. if(f->l->op == '!'){
  492. changed = 1;
  493. return f->l->l;
  494. }
  495. break;
  496. case LOR:
  497. /* are two children the same protocol? */
  498. if(f->l->op != f->r->op || f->r->op != WORD
  499. || f->l->pr != f->r->pr || f->l->pr == nil)
  500. break; /* no optimization */
  501. changed = 1;
  502. /* constant folding */
  503. /* if either child is childless, just return that */
  504. if(f->l->l == nil)
  505. return f->l;
  506. else if(f->r->l == nil)
  507. return f->r;
  508. /* move the common node up, thow away one node */
  509. l = f->l;
  510. f->l = l->l;
  511. f->r = f->r->l;
  512. l->l = f;
  513. return l;
  514. case LAND:
  515. /* are two children the same protocol? */
  516. if(f->l->op != f->r->op || f->r->op != WORD
  517. || f->l->pr != f->r->pr || f->l->pr == nil)
  518. break; /* no optimization */
  519. changed = 1;
  520. /* constant folding */
  521. /* if either child is childless, ignore it */
  522. if(f->l->l == nil)
  523. return f->r;
  524. else if(f->r->l == nil)
  525. return f->l;
  526. /* move the common node up, thow away one node */
  527. l = f->l;
  528. f->l = _optimize(l->l);
  529. f->r = _optimize(f->r->l);
  530. l->l = f;
  531. return l;
  532. }
  533. f->l = _optimize(f->l);
  534. f->r = _optimize(f->r);
  535. return f;
  536. }
  537. Filter*
  538. optimize(Filter *f)
  539. {
  540. do{
  541. changed = 0;
  542. f = _optimize(f);
  543. }while(changed);
  544. return f;
  545. }
  546. /*
  547. * find any top level nodes that aren't the root
  548. */
  549. int
  550. findbogus(Filter *f)
  551. {
  552. int rv;
  553. if(f->op != WORD){
  554. rv = findbogus(f->l);
  555. if(f->r)
  556. rv |= findbogus(f->r);
  557. return rv;
  558. } else if(f->pr != root){
  559. fprint(2, "bad top-level protocol: %s\n", f->s);
  560. return 1;
  561. }
  562. return 0;
  563. }
  564. /*
  565. * compile the filter
  566. */
  567. static void
  568. _compile(Filter *f, Proto *last)
  569. {
  570. if(f == nil)
  571. return;
  572. switch(f->op){
  573. case '!':
  574. _compile(f->l, last);
  575. break;
  576. case LOR:
  577. case LAND:
  578. _compile(f->l, last);
  579. _compile(f->r, last);
  580. break;
  581. case WORD:
  582. if(last != nil)
  583. (*last->compile)(f);
  584. if(f->l)
  585. _compile(f->l, f->pr);
  586. break;
  587. case '=':
  588. if(last == nil)
  589. sysfatal("internal error: compilewalk: badly formed tree");
  590. (*last->compile)(f);
  591. break;
  592. default:
  593. sysfatal("internal error: compilewalk op: %d", f->op);
  594. }
  595. }
  596. Filter*
  597. compile(Filter *f)
  598. {
  599. if(f == nil)
  600. return f;
  601. /* fill in the missing header filters */
  602. f = complete(f, nil);
  603. /* constant folding */
  604. f = optimize(f);
  605. if(!toflag)
  606. printfilter(f, "after optimize");
  607. /* protocol specific compilations */
  608. _compile(f, nil);
  609. /* at this point, the root had better be the root proto */
  610. if(findbogus(f)){
  611. fprint(2, "bogus filter\n");
  612. exits("bad filter");
  613. }
  614. return f;
  615. }
  616. /*
  617. * parse a byte array
  618. */
  619. int
  620. parseba(uchar *to, char *from)
  621. {
  622. char nip[4];
  623. char *p;
  624. int i;
  625. p = from;
  626. for(i = 0; i < 16; i++){
  627. if(*p == 0)
  628. return -1;
  629. nip[0] = *p++;
  630. if(*p == 0)
  631. return -1;
  632. nip[1] = *p++;
  633. nip[2] = 0;
  634. to[i] = strtoul(nip, 0, 16);
  635. }
  636. return i;
  637. }
  638. /*
  639. * compile WORD = WORD, becomes a single node with a subop
  640. */
  641. void
  642. compile_cmp(char *proto, Filter *f, Field *fld)
  643. {
  644. uchar x[IPaddrlen];
  645. if(f->op != '=')
  646. sysfatal("internal error: compile_cmp %s: not a cmp", proto);
  647. for(; fld->name != nil; fld++){
  648. if(strcmp(f->l->s, fld->name) == 0){
  649. f->op = WORD;
  650. f->subop = fld->subop;
  651. switch(fld->ftype){
  652. case Fnum:
  653. f->ulv = atoi(f->r->s);
  654. break;
  655. case Fether:
  656. parseether(f->a, f->r->s);
  657. break;
  658. case Fv4ip:
  659. f->ulv = parseip(x, f->r->s);
  660. break;
  661. case Fv6ip:
  662. parseip(f->a, f->r->s);
  663. break;
  664. case Fba:
  665. parseba(f->a, f->r->s);
  666. break;
  667. default:
  668. sysfatal("internal error: compile_cmp %s: %d",
  669. proto, fld->ftype);
  670. }
  671. f->l = f->r = nil;
  672. return;
  673. }
  674. }
  675. sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s);
  676. }
  677. void
  678. _pf(Filter *f)
  679. {
  680. char *s;
  681. if(f == nil)
  682. return;
  683. s = nil;
  684. switch(f->op){
  685. case '!':
  686. fprint(2, "!");
  687. _pf(f->l);
  688. break;
  689. case WORD:
  690. fprint(2, "%s", f->s);
  691. if(f->l != nil){
  692. fprint(2, "(");
  693. _pf(f->l);
  694. fprint(2, ")");
  695. }
  696. break;
  697. case LAND:
  698. s = "&&";
  699. goto print;
  700. case LOR:
  701. s = "||";
  702. goto print;
  703. case '=':
  704. print:
  705. _pf(f->l);
  706. if(s)
  707. fprint(2, " %s ", s);
  708. else
  709. fprint(2, " %c ", f->op);
  710. _pf(f->r);
  711. break;
  712. default:
  713. fprint(2, "???");
  714. break;
  715. }
  716. }
  717. void
  718. printfilter(Filter *f, char *tag)
  719. {
  720. fprint(2, "%s: ", tag);
  721. _pf(f);
  722. fprint(2, "\n");
  723. }
  724. void
  725. cat(void)
  726. {
  727. char buf[1024];
  728. int n;
  729. while((n = read(0, buf, sizeof buf)) > 0)
  730. write(1, buf, n);
  731. }
  732. static int fd1 = -1;
  733. void
  734. startmc(void)
  735. {
  736. int p[2];
  737. if(fd1 == -1)
  738. fd1 = dup(1, -1);
  739. if(pipe(p) < 0)
  740. return;
  741. switch(fork()){
  742. case -1:
  743. return;
  744. default:
  745. close(p[0]);
  746. dup(p[1], 1);
  747. if(p[1] != 1)
  748. close(p[1]);
  749. return;
  750. case 0:
  751. close(p[1]);
  752. dup(p[0], 0);
  753. if(p[0] != 0)
  754. close(p[0]);
  755. execl("/bin/mc", "mc", nil);
  756. cat();
  757. _exits(0);
  758. }
  759. }
  760. void
  761. stopmc(void)
  762. {
  763. close(1);
  764. dup(fd1, 1);
  765. waitpid();
  766. }
  767. void
  768. printhelp(char *name)
  769. {
  770. int len;
  771. Proto *pr, **l;
  772. Mux *m;
  773. Field *f;
  774. char fmt[40];
  775. if(name == nil){
  776. print("protocols:\n");
  777. startmc();
  778. for(l=protos; (pr=*l) != nil; l++)
  779. print(" %s\n", pr->name);
  780. stopmc();
  781. return;
  782. }
  783. pr = findproto(name);
  784. if(pr == nil){
  785. print("unknown protocol %s\n", name);
  786. return;
  787. }
  788. if(pr->field){
  789. print("%s's filter attributes:\n", pr->name);
  790. len = 0;
  791. for(f=pr->field; f->name; f++)
  792. if(len < strlen(f->name))
  793. len = strlen(f->name);
  794. startmc();
  795. for(f=pr->field; f->name; f++)
  796. print(" %-*s - %s\n", len, f->name, f->help);
  797. stopmc();
  798. }
  799. if(pr->mux){
  800. print("%s's subprotos:\n", pr->name);
  801. startmc();
  802. snprint(fmt, sizeof fmt, " %s %%s\n", pr->valfmt);
  803. for(m=pr->mux; m->name != nil; m++)
  804. print(fmt, m->val, m->name);
  805. stopmc();
  806. }
  807. }
  808. /*
  809. * demultiplex to next prototol header
  810. */
  811. void
  812. demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def)
  813. {
  814. m->pr = def;
  815. for(mx = mx; mx->name != nil; mx++){
  816. if(val1 == mx->val || val2 == mx->val){
  817. m->pr = mx->pr;
  818. break;
  819. }
  820. }
  821. }
  822. /*
  823. * default framer just assumes the input packet is
  824. * a single read
  825. */
  826. int
  827. defaultframer(int fd, uchar *pkt, int pktlen)
  828. {
  829. return read(fd, pkt, pktlen);
  830. }