18fd921c8SDavid du Colombier /*
28fd921c8SDavid du Colombier * snoopy - network sniffer
38fd921c8SDavid du Colombier */
49a747e4fSDavid du Colombier #include <u.h>
59a747e4fSDavid du Colombier #include <libc.h>
69a747e4fSDavid du Colombier #include <ip.h>
79a747e4fSDavid du Colombier #include <bio.h>
89a747e4fSDavid du Colombier #include <fcall.h>
99a747e4fSDavid du Colombier #include <libsec.h>
108fd921c8SDavid du Colombier #include <ndb.h>
119a747e4fSDavid du Colombier #include "dat.h"
129a747e4fSDavid du Colombier #include "protos.h"
139a747e4fSDavid du Colombier #include "y.tab.h"
149a747e4fSDavid du Colombier
159a747e4fSDavid du Colombier int Cflag;
169a747e4fSDavid du Colombier int pflag;
179a747e4fSDavid du Colombier int Nflag;
1864c7f6b6SDavid du Colombier int Mflag;
199a747e4fSDavid du Colombier int sflag;
209a747e4fSDavid du Colombier int tiflag;
219a747e4fSDavid du Colombier int toflag;
229a747e4fSDavid du Colombier
239a747e4fSDavid du Colombier char *prom = "promiscuous";
249a747e4fSDavid du Colombier
259a747e4fSDavid du Colombier enum
269a747e4fSDavid du Colombier {
279a747e4fSDavid du Colombier Pktlen= 64*1024,
289a747e4fSDavid du Colombier Blen= 16*1024,
299a747e4fSDavid du Colombier };
309a747e4fSDavid du Colombier
319a747e4fSDavid du Colombier Filter *filter;
329a747e4fSDavid du Colombier Proto *root;
339a747e4fSDavid du Colombier Biobuf out;
349a747e4fSDavid du Colombier vlong starttime, pkttime;
353ff48bf5SDavid du Colombier int pcap;
369a747e4fSDavid du Colombier
376b6b9ac8SDavid du Colombier int filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int);
389a747e4fSDavid du Colombier void printpkt(char *p, char *e, uchar *ps, uchar *pe);
399a747e4fSDavid du Colombier void mkprotograph(void);
409a747e4fSDavid du Colombier Proto* findproto(char *name);
419a747e4fSDavid du Colombier Filter* compile(Filter *f);
429a747e4fSDavid du Colombier void printfilter(Filter *f, char *tag);
43ed397113SDavid du Colombier void printhelp(char*);
449a747e4fSDavid du Colombier void tracepkt(uchar*, int);
453ff48bf5SDavid du Colombier void pcaphdr(void);
469a747e4fSDavid du Colombier
479a747e4fSDavid du Colombier void
printusage(void)48ed397113SDavid du Colombier printusage(void)
49ed397113SDavid du Colombier {
50ed397113SDavid du Colombier fprint(2, "usage: %s [-CDdpst] [-N n] [-f filter] [-h first-header] path\n", argv0);
51ed397113SDavid du Colombier fprint(2, " for protocol help: %s -? [proto]\n", argv0);
52ed397113SDavid du Colombier }
53ed397113SDavid du Colombier
54ed397113SDavid du Colombier void
usage(void)559a747e4fSDavid du Colombier usage(void)
569a747e4fSDavid du Colombier {
57ed397113SDavid du Colombier printusage();
589a747e4fSDavid du Colombier exits("usage");
599a747e4fSDavid du Colombier }
609a747e4fSDavid du Colombier
619a747e4fSDavid du Colombier void
main(int argc,char ** argv)629a747e4fSDavid du Colombier main(int argc, char **argv)
639a747e4fSDavid du Colombier {
649a747e4fSDavid du Colombier uchar *pkt;
659a747e4fSDavid du Colombier char *buf, *file, *p, *e;
669a747e4fSDavid du Colombier int fd, cfd;
679a747e4fSDavid du Colombier int n;
689a747e4fSDavid du Colombier
699a747e4fSDavid du Colombier Binit(&out, 1, OWRITE);
709a747e4fSDavid du Colombier
719a747e4fSDavid du Colombier fmtinstall('E', eipfmt);
729a747e4fSDavid du Colombier fmtinstall('V', eipfmt);
739a747e4fSDavid du Colombier fmtinstall('I', eipfmt);
749a747e4fSDavid du Colombier fmtinstall('H', encodefmt);
759a747e4fSDavid du Colombier fmtinstall('F', fcallfmt);
769a747e4fSDavid du Colombier
773ff48bf5SDavid du Colombier pkt = malloc(Pktlen+16);
783ff48bf5SDavid du Colombier pkt += 16;
799a747e4fSDavid du Colombier buf = malloc(Blen);
809a747e4fSDavid du Colombier e = buf+Blen-1;
819a747e4fSDavid du Colombier
829a747e4fSDavid du Colombier pflag = 1;
839a747e4fSDavid du Colombier Nflag = 32;
849a747e4fSDavid du Colombier sflag = 0;
859a747e4fSDavid du Colombier
869a747e4fSDavid du Colombier mkprotograph();
879a747e4fSDavid du Colombier
889a747e4fSDavid du Colombier ARGBEGIN{
89ed397113SDavid du Colombier default:
90ed397113SDavid du Colombier usage();
919a747e4fSDavid du Colombier case '?':
92ed397113SDavid du Colombier printusage();
93ed397113SDavid du Colombier printhelp(ARGF());
949a747e4fSDavid du Colombier exits(0);
959a747e4fSDavid du Colombier break;
9664c7f6b6SDavid du Colombier case 'M':
9764c7f6b6SDavid du Colombier p = EARGF(usage());
9864c7f6b6SDavid du Colombier Mflag = atoi(p);
9964c7f6b6SDavid du Colombier break;
1009a747e4fSDavid du Colombier case 'N':
101ed397113SDavid du Colombier p = EARGF(usage());
1029a747e4fSDavid du Colombier Nflag = atoi(p);
1039a747e4fSDavid du Colombier break;
1049a747e4fSDavid du Colombier case 'f':
105ed397113SDavid du Colombier p = EARGF(usage());
1069a747e4fSDavid du Colombier yyinit(p);
1079a747e4fSDavid du Colombier yyparse();
1089a747e4fSDavid du Colombier break;
1099a747e4fSDavid du Colombier case 's':
1109a747e4fSDavid du Colombier sflag = 1;
1119a747e4fSDavid du Colombier break;
1129a747e4fSDavid du Colombier case 'h':
113ed397113SDavid du Colombier p = EARGF(usage());
1149a747e4fSDavid du Colombier root = findproto(p);
1159a747e4fSDavid du Colombier if(root == nil)
1169a747e4fSDavid du Colombier sysfatal("unknown protocol: %s", p);
1179a747e4fSDavid du Colombier break;
1189a747e4fSDavid du Colombier case 'd':
1199a747e4fSDavid du Colombier toflag = 1;
1209a747e4fSDavid du Colombier break;
1213ff48bf5SDavid du Colombier case 'D':
1223ff48bf5SDavid du Colombier toflag = 1;
1233ff48bf5SDavid du Colombier pcap = 1;
1243ff48bf5SDavid du Colombier break;
1259a747e4fSDavid du Colombier case 't':
1269a747e4fSDavid du Colombier tiflag = 1;
1279a747e4fSDavid du Colombier break;
1289a747e4fSDavid du Colombier case 'C':
1299a747e4fSDavid du Colombier Cflag = 1;
1309a747e4fSDavid du Colombier break;
1312af09eb6SDavid du Colombier case 'p':
1322af09eb6SDavid du Colombier pflag = 0;
1332af09eb6SDavid du Colombier break;
1349a747e4fSDavid du Colombier }ARGEND;
1359a747e4fSDavid du Colombier
1363ff48bf5SDavid du Colombier if(pcap)
1373ff48bf5SDavid du Colombier pcaphdr();
1383ff48bf5SDavid du Colombier
1399a747e4fSDavid du Colombier if(argc == 0){
1409a747e4fSDavid du Colombier file = "/net/ether0";
1419a747e4fSDavid du Colombier if(root != nil)
1429a747e4fSDavid du Colombier root = ðer;
1439a747e4fSDavid du Colombier } else
1449a747e4fSDavid du Colombier file = argv[0];
1459a747e4fSDavid du Colombier
1469a747e4fSDavid du Colombier if((!tiflag) && strstr(file, "ether")){
1479a747e4fSDavid du Colombier if(root == nil)
1489a747e4fSDavid du Colombier root = ðer;
1499a747e4fSDavid du Colombier snprint(buf, Blen, "%s!-1", file);
1509a747e4fSDavid du Colombier fd = dial(buf, 0, 0, &cfd);
1519a747e4fSDavid du Colombier if(fd < 0)
152*853458f3SDavid du Colombier sysfatal("dialing %s: %r", buf);
1539a747e4fSDavid du Colombier if(pflag && fprint(cfd, prom, strlen(prom)) < 0)
1549a747e4fSDavid du Colombier sysfatal("setting %s", prom);
1559a747e4fSDavid du Colombier } else if((!tiflag) && strstr(file, "ipifc")){
1569a747e4fSDavid du Colombier if(root == nil)
1579a747e4fSDavid du Colombier root = &ip;
1582af09eb6SDavid du Colombier snprint(buf, Blen, "%s/snoop", file);
1599a747e4fSDavid du Colombier fd = open(buf, OREAD);
1609a747e4fSDavid du Colombier if(fd < 0)
1612af09eb6SDavid du Colombier sysfatal("opening %s: %r", buf);
1629a747e4fSDavid du Colombier } else {
1639a747e4fSDavid du Colombier if(root == nil)
1649a747e4fSDavid du Colombier root = ðer;
1659a747e4fSDavid du Colombier fd = open(file, OREAD);
1669a747e4fSDavid du Colombier if(fd < 0)
1672af09eb6SDavid du Colombier sysfatal("opening %s: %r", file);
1689a747e4fSDavid du Colombier }
1699a747e4fSDavid du Colombier filter = compile(filter);
1709a747e4fSDavid du Colombier
1719a747e4fSDavid du Colombier if(tiflag){
1723ff48bf5SDavid du Colombier /* read a trace file */
1739a747e4fSDavid du Colombier for(;;){
1749a747e4fSDavid du Colombier n = read(fd, pkt, 10);
1759a747e4fSDavid du Colombier if(n != 10)
1769a747e4fSDavid du Colombier break;
1779a747e4fSDavid du Colombier pkttime = NetL(pkt+2);
1789a747e4fSDavid du Colombier pkttime = (pkttime<<32) | NetL(pkt+6);
1799a747e4fSDavid du Colombier if(starttime == 0LL)
1809a747e4fSDavid du Colombier starttime = pkttime;
1819a747e4fSDavid du Colombier n = NetS(pkt);
1823ff48bf5SDavid du Colombier if(readn(fd, pkt, n) != n)
1839a747e4fSDavid du Colombier break;
1846b6b9ac8SDavid du Colombier if(filterpkt(filter, pkt, pkt+n, root, 1))
1859a747e4fSDavid du Colombier if(toflag)
1869a747e4fSDavid du Colombier tracepkt(pkt, n);
1879a747e4fSDavid du Colombier else
1889a747e4fSDavid du Colombier printpkt(buf, e, pkt, pkt+n);
1899a747e4fSDavid du Colombier }
1909a747e4fSDavid du Colombier } else {
1919a747e4fSDavid du Colombier /* read a real time stream */
1929a747e4fSDavid du Colombier starttime = nsec();
1939a747e4fSDavid du Colombier for(;;){
1943ff48bf5SDavid du Colombier n = root->framer(fd, pkt, Pktlen);
1959a747e4fSDavid du Colombier if(n <= 0)
1969a747e4fSDavid du Colombier break;
1979a747e4fSDavid du Colombier pkttime = nsec();
1986b6b9ac8SDavid du Colombier if(filterpkt(filter, pkt, pkt+n, root, 1))
1999a747e4fSDavid du Colombier if(toflag)
2009a747e4fSDavid du Colombier tracepkt(pkt, n);
2019a747e4fSDavid du Colombier else
2029a747e4fSDavid du Colombier printpkt(buf, e, pkt, pkt+n);
2039a747e4fSDavid du Colombier }
2049a747e4fSDavid du Colombier }
2059a747e4fSDavid du Colombier }
2069a747e4fSDavid du Colombier
2079a747e4fSDavid du Colombier /* create a new filter node */
2089a747e4fSDavid du Colombier Filter*
newfilter(void)2099a747e4fSDavid du Colombier newfilter(void)
2109a747e4fSDavid du Colombier {
2119a747e4fSDavid du Colombier Filter *f;
2129a747e4fSDavid du Colombier
2139a747e4fSDavid du Colombier f = mallocz(sizeof(*f), 1);
2149a747e4fSDavid du Colombier if(f == nil)
2159a747e4fSDavid du Colombier sysfatal("newfilter: %r");
2169a747e4fSDavid du Colombier return f;
2179a747e4fSDavid du Colombier }
2189a747e4fSDavid du Colombier
2199a747e4fSDavid du Colombier /*
2209a747e4fSDavid du Colombier * apply filter to packet
2219a747e4fSDavid du Colombier */
2229a747e4fSDavid du Colombier int
_filterpkt(Filter * f,Msg * m)2239a747e4fSDavid du Colombier _filterpkt(Filter *f, Msg *m)
2249a747e4fSDavid du Colombier {
2259a747e4fSDavid du Colombier Msg ma;
2269a747e4fSDavid du Colombier
2279a747e4fSDavid du Colombier if(f == nil)
2289a747e4fSDavid du Colombier return 1;
2299a747e4fSDavid du Colombier
2309a747e4fSDavid du Colombier switch(f->op){
2316b6b9ac8SDavid du Colombier case '!':
2326b6b9ac8SDavid du Colombier return !_filterpkt(f->l, m);
2339a747e4fSDavid du Colombier case LAND:
2349a747e4fSDavid du Colombier ma = *m;
2359a747e4fSDavid du Colombier return _filterpkt(f->l, &ma) && _filterpkt(f->r, m);
2369a747e4fSDavid du Colombier case LOR:
2379a747e4fSDavid du Colombier ma = *m;
2389a747e4fSDavid du Colombier return _filterpkt(f->l, &ma) || _filterpkt(f->r, m);
2399a747e4fSDavid du Colombier case WORD:
2406b6b9ac8SDavid du Colombier if(m->needroot){
2416b6b9ac8SDavid du Colombier if(m->pr != f->pr)
2426b6b9ac8SDavid du Colombier return 0;
2436b6b9ac8SDavid du Colombier m->needroot = 0;
2446b6b9ac8SDavid du Colombier }else{
2452cca75a1SDavid du Colombier if(m->pr && (m->pr->filter==nil || !(m->pr->filter)(f, m)))
2469a747e4fSDavid du Colombier return 0;
2476b6b9ac8SDavid du Colombier }
2489a747e4fSDavid du Colombier if(f->l == nil)
2499a747e4fSDavid du Colombier return 1;
2509a747e4fSDavid du Colombier m->pr = f->pr;
2519a747e4fSDavid du Colombier return _filterpkt(f->l, m);
2529a747e4fSDavid du Colombier }
2539a747e4fSDavid du Colombier sysfatal("internal error: filterpkt op: %d", f->op);
2549a747e4fSDavid du Colombier return 0;
2559a747e4fSDavid du Colombier }
2569a747e4fSDavid du Colombier int
filterpkt(Filter * f,uchar * ps,uchar * pe,Proto * pr,int needroot)2576b6b9ac8SDavid du Colombier filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot)
2589a747e4fSDavid du Colombier {
2599a747e4fSDavid du Colombier Msg m;
2609a747e4fSDavid du Colombier
2619a747e4fSDavid du Colombier if(f == nil)
2629a747e4fSDavid du Colombier return 1;
2639a747e4fSDavid du Colombier
2646b6b9ac8SDavid du Colombier m.needroot = needroot;
2659a747e4fSDavid du Colombier m.ps = ps;
2669a747e4fSDavid du Colombier m.pe = pe;
2679a747e4fSDavid du Colombier m.pr = pr;
2689a747e4fSDavid du Colombier return _filterpkt(f, &m);
2699a747e4fSDavid du Colombier }
2709a747e4fSDavid du Colombier
2719a747e4fSDavid du Colombier /*
2723ff48bf5SDavid du Colombier * from the Unix world
2733ff48bf5SDavid du Colombier */
2743ff48bf5SDavid du Colombier #define PCAP_VERSION_MAJOR 2
2753ff48bf5SDavid du Colombier #define PCAP_VERSION_MINOR 4
2763ff48bf5SDavid du Colombier #define TCPDUMP_MAGIC 0xa1b2c3d4
2773ff48bf5SDavid du Colombier
2783ff48bf5SDavid du Colombier struct pcap_file_header {
2793ff48bf5SDavid du Colombier ulong magic;
2803ff48bf5SDavid du Colombier ushort version_major;
2813ff48bf5SDavid du Colombier ushort version_minor;
2823ff48bf5SDavid du Colombier long thiszone; /* gmt to local correction */
2833ff48bf5SDavid du Colombier ulong sigfigs; /* accuracy of timestamps */
2843ff48bf5SDavid du Colombier ulong snaplen; /* max length saved portion of each pkt */
2853ff48bf5SDavid du Colombier ulong linktype; /* data link type (DLT_*) */
2863ff48bf5SDavid du Colombier };
2873ff48bf5SDavid du Colombier
2883ff48bf5SDavid du Colombier struct pcap_pkthdr {
2893ff48bf5SDavid du Colombier uvlong ts; /* time stamp */
2903ff48bf5SDavid du Colombier ulong caplen; /* length of portion present */
2913ff48bf5SDavid du Colombier ulong len; /* length this packet (off wire) */
2923ff48bf5SDavid du Colombier };
2933ff48bf5SDavid du Colombier
2943ff48bf5SDavid du Colombier /*
2953ff48bf5SDavid du Colombier * pcap trace header
2963ff48bf5SDavid du Colombier */
2973ff48bf5SDavid du Colombier void
pcaphdr(void)2983ff48bf5SDavid du Colombier pcaphdr(void)
2993ff48bf5SDavid du Colombier {
3003ff48bf5SDavid du Colombier struct pcap_file_header hdr;
3013ff48bf5SDavid du Colombier
3023ff48bf5SDavid du Colombier hdr.magic = TCPDUMP_MAGIC;
3033ff48bf5SDavid du Colombier hdr.version_major = PCAP_VERSION_MAJOR;
3043ff48bf5SDavid du Colombier hdr.version_minor = PCAP_VERSION_MINOR;
3053ff48bf5SDavid du Colombier
3063ff48bf5SDavid du Colombier hdr.thiszone = 0;
3073ff48bf5SDavid du Colombier hdr.snaplen = 1500;
3083ff48bf5SDavid du Colombier hdr.sigfigs = 0;
3093ff48bf5SDavid du Colombier hdr.linktype = 1;
3103ff48bf5SDavid du Colombier
3113ff48bf5SDavid du Colombier write(1, &hdr, sizeof(hdr));
3123ff48bf5SDavid du Colombier }
3133ff48bf5SDavid du Colombier
3143ff48bf5SDavid du Colombier /*
3159a747e4fSDavid du Colombier * write out a packet trace
3169a747e4fSDavid du Colombier */
3179a747e4fSDavid du Colombier void
tracepkt(uchar * ps,int len)3189a747e4fSDavid du Colombier tracepkt(uchar *ps, int len)
3199a747e4fSDavid du Colombier {
3203ff48bf5SDavid du Colombier struct pcap_pkthdr *goo;
3213ff48bf5SDavid du Colombier
32264c7f6b6SDavid du Colombier if(Mflag && len > Mflag)
32364c7f6b6SDavid du Colombier len = Mflag;
3243ff48bf5SDavid du Colombier if(pcap){
3253ff48bf5SDavid du Colombier goo = (struct pcap_pkthdr*)(ps-16);
3263ff48bf5SDavid du Colombier goo->ts = pkttime;
3273ff48bf5SDavid du Colombier goo->caplen = len;
3283ff48bf5SDavid du Colombier goo->len = len;
3293ff48bf5SDavid du Colombier write(1, goo, len+16);
3303ff48bf5SDavid du Colombier } else {
3319a747e4fSDavid du Colombier hnputs(ps-10, len);
3329a747e4fSDavid du Colombier hnputl(ps-8, pkttime>>32);
3339a747e4fSDavid du Colombier hnputl(ps-4, pkttime);
3349a747e4fSDavid du Colombier write(1, ps-10, len+10);
3359a747e4fSDavid du Colombier }
3363ff48bf5SDavid du Colombier }
3379a747e4fSDavid du Colombier
3389a747e4fSDavid du Colombier /*
3399a747e4fSDavid du Colombier * format and print a packet
3409a747e4fSDavid du Colombier */
3419a747e4fSDavid du Colombier void
printpkt(char * p,char * e,uchar * ps,uchar * pe)3429a747e4fSDavid du Colombier printpkt(char *p, char *e, uchar *ps, uchar *pe)
3439a747e4fSDavid du Colombier {
3449a747e4fSDavid du Colombier Msg m;
3459a747e4fSDavid du Colombier ulong dt;
3469a747e4fSDavid du Colombier
3479a747e4fSDavid du Colombier dt = (pkttime-starttime)/1000000LL;
3489a747e4fSDavid du Colombier m.p = seprint(p, e, "%6.6uld ms ", dt);
3499a747e4fSDavid du Colombier m.ps = ps;
3509a747e4fSDavid du Colombier m.pe = pe;
3519a747e4fSDavid du Colombier m.e = e;
3529a747e4fSDavid du Colombier m.pr = root;
3539a747e4fSDavid du Colombier while(m.p < m.e){
3549a747e4fSDavid du Colombier if(!sflag)
3559a747e4fSDavid du Colombier m.p = seprint(m.p, m.e, "\n\t");
3569a747e4fSDavid du Colombier m.p = seprint(m.p, m.e, "%s(", m.pr->name);
3579a747e4fSDavid du Colombier if((*m.pr->seprint)(&m) < 0){
3589a747e4fSDavid du Colombier m.p = seprint(m.p, m.e, "TOO SHORT");
3599a747e4fSDavid du Colombier m.ps = m.pe;
3609a747e4fSDavid du Colombier }
3619a747e4fSDavid du Colombier m.p = seprint(m.p, m.e, ")");
3629a747e4fSDavid du Colombier if(m.pr == nil || m.ps >= m.pe)
3639a747e4fSDavid du Colombier break;
3649a747e4fSDavid du Colombier }
3659a747e4fSDavid du Colombier *m.p++ = '\n';
3669a747e4fSDavid du Colombier
3679a747e4fSDavid du Colombier if(write(1, p, m.p - p) < 0)
3689a747e4fSDavid du Colombier sysfatal("stdout: %r");
3699a747e4fSDavid du Colombier }
3709a747e4fSDavid du Colombier
3719a747e4fSDavid du Colombier Proto **xprotos;
3729a747e4fSDavid du Colombier int nprotos;
3739a747e4fSDavid du Colombier
3749a747e4fSDavid du Colombier /* look up a protocol by its name */
3759a747e4fSDavid du Colombier Proto*
findproto(char * name)3769a747e4fSDavid du Colombier findproto(char *name)
3779a747e4fSDavid du Colombier {
3789a747e4fSDavid du Colombier int i;
3799a747e4fSDavid du Colombier
3809a747e4fSDavid du Colombier for(i = 0; i < nprotos; i++)
3819a747e4fSDavid du Colombier if(strcmp(xprotos[i]->name, name) == 0)
3829a747e4fSDavid du Colombier return xprotos[i];
3839a747e4fSDavid du Colombier return nil;
3849a747e4fSDavid du Colombier }
3859a747e4fSDavid du Colombier
3869a747e4fSDavid du Colombier /*
3879a747e4fSDavid du Colombier * add an undefined protocol to protos[]
3889a747e4fSDavid du Colombier */
3899a747e4fSDavid du Colombier Proto*
addproto(char * name)3909a747e4fSDavid du Colombier addproto(char *name)
3919a747e4fSDavid du Colombier {
3929a747e4fSDavid du Colombier Proto *pr;
3939a747e4fSDavid du Colombier
3949a747e4fSDavid du Colombier xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*));
3959a747e4fSDavid du Colombier pr = malloc(sizeof *pr);
3969a747e4fSDavid du Colombier *pr = dump;
3979a747e4fSDavid du Colombier pr->name = name;
3989a747e4fSDavid du Colombier xprotos[nprotos++] = pr;
3999a747e4fSDavid du Colombier return pr;
4009a747e4fSDavid du Colombier }
4019a747e4fSDavid du Colombier
4029a747e4fSDavid du Colombier /*
4039a747e4fSDavid du Colombier * build a graph of protocols, this could easily be circular. This
4049a747e4fSDavid du Colombier * links together all the multiplexing in the protocol modules.
4059a747e4fSDavid du Colombier */
4069a747e4fSDavid du Colombier void
mkprotograph(void)4079a747e4fSDavid du Colombier mkprotograph(void)
4089a747e4fSDavid du Colombier {
4099a747e4fSDavid du Colombier Proto **l;
4109a747e4fSDavid du Colombier Proto *pr;
4119a747e4fSDavid du Colombier Mux *m;
4129a747e4fSDavid du Colombier
4139a747e4fSDavid du Colombier /* copy protos into a reallocable area */
4149a747e4fSDavid du Colombier for(nprotos = 0; protos[nprotos] != nil; nprotos++)
4159a747e4fSDavid du Colombier ;
4169a747e4fSDavid du Colombier xprotos = malloc(nprotos*sizeof(Proto*));
4179a747e4fSDavid du Colombier memmove(xprotos, protos, nprotos*sizeof(Proto*));
4189a747e4fSDavid du Colombier
4199a747e4fSDavid du Colombier for(l = protos; *l != nil; l++){
4209a747e4fSDavid du Colombier pr = *l;
4219a747e4fSDavid du Colombier for(m = pr->mux; m != nil && m->name != nil; m++){
4229a747e4fSDavid du Colombier m->pr = findproto(m->name);
4239a747e4fSDavid du Colombier if(m->pr == nil)
4249a747e4fSDavid du Colombier m->pr = addproto(m->name);
4259a747e4fSDavid du Colombier }
4269a747e4fSDavid du Colombier }
4279a747e4fSDavid du Colombier }
4289a747e4fSDavid du Colombier
4299a747e4fSDavid du Colombier /*
4309a747e4fSDavid du Colombier * add in a protocol node
4319a747e4fSDavid du Colombier */
4329a747e4fSDavid du Colombier static Filter*
addnode(Filter * f,Proto * pr)4339a747e4fSDavid du Colombier addnode(Filter *f, Proto *pr)
4349a747e4fSDavid du Colombier {
4359a747e4fSDavid du Colombier Filter *nf;
4369a747e4fSDavid du Colombier nf = newfilter();
4379a747e4fSDavid du Colombier nf->pr = pr;
4389a747e4fSDavid du Colombier nf->s = pr->name;
4399a747e4fSDavid du Colombier nf->l = f;
4409a747e4fSDavid du Colombier nf->op = WORD;
4419a747e4fSDavid du Colombier return nf;
4429a747e4fSDavid du Colombier }
4439a747e4fSDavid du Colombier
4449a747e4fSDavid du Colombier /*
4459a747e4fSDavid du Colombier * recurse through the protocol graph adding missing nodes
4469a747e4fSDavid du Colombier * to the filter if we reach the filter's protocol
4479a747e4fSDavid du Colombier */
4489a747e4fSDavid du Colombier static Filter*
_fillin(Filter * f,Proto * last,int depth)4499a747e4fSDavid du Colombier _fillin(Filter *f, Proto *last, int depth)
4509a747e4fSDavid du Colombier {
4519a747e4fSDavid du Colombier Mux *m;
4529a747e4fSDavid du Colombier Filter *nf;
4539a747e4fSDavid du Colombier
4549a747e4fSDavid du Colombier if(depth-- <= 0)
4559a747e4fSDavid du Colombier return nil;
4569a747e4fSDavid du Colombier
4579a747e4fSDavid du Colombier for(m = last->mux; m != nil && m->name != nil; m++){
4589a747e4fSDavid du Colombier if(m->pr == nil)
4599a747e4fSDavid du Colombier continue;
4609a747e4fSDavid du Colombier if(f->pr == m->pr)
4619a747e4fSDavid du Colombier return f;
4629a747e4fSDavid du Colombier nf = _fillin(f, m->pr, depth);
4639a747e4fSDavid du Colombier if(nf != nil)
4649a747e4fSDavid du Colombier return addnode(nf, m->pr);
4659a747e4fSDavid du Colombier }
4669a747e4fSDavid du Colombier return nil;
4679a747e4fSDavid du Colombier }
4689a747e4fSDavid du Colombier
4699a747e4fSDavid du Colombier static Filter*
fillin(Filter * f,Proto * last)4709a747e4fSDavid du Colombier fillin(Filter *f, Proto *last)
4719a747e4fSDavid du Colombier {
4729a747e4fSDavid du Colombier int i;
4739a747e4fSDavid du Colombier Filter *nf;
4749a747e4fSDavid du Colombier
4759a747e4fSDavid du Colombier /* hack to make sure top level node is the root */
4769a747e4fSDavid du Colombier if(last == nil){
4779a747e4fSDavid du Colombier if(f->pr == root)
4789a747e4fSDavid du Colombier return f;
4799a747e4fSDavid du Colombier f = fillin(f, root);
4809a747e4fSDavid du Colombier if(f == nil)
4819a747e4fSDavid du Colombier return nil;
4829a747e4fSDavid du Colombier return addnode(f, root);
4839a747e4fSDavid du Colombier }
4849a747e4fSDavid du Colombier
4859a747e4fSDavid du Colombier /* breadth first search though the protocol graph */
4869a747e4fSDavid du Colombier nf = f;
4879a747e4fSDavid du Colombier for(i = 1; i < 20; i++){
4889a747e4fSDavid du Colombier nf = _fillin(f, last, i);
4899a747e4fSDavid du Colombier if(nf != nil)
4909a747e4fSDavid du Colombier break;
4919a747e4fSDavid du Colombier }
4929a747e4fSDavid du Colombier return nf;
4939a747e4fSDavid du Colombier }
4949a747e4fSDavid du Colombier
4959a747e4fSDavid du Colombier /*
4969a747e4fSDavid du Colombier * massage tree so that all paths from the root to a leaf
4979a747e4fSDavid du Colombier * contain a filter node for each header.
4989a747e4fSDavid du Colombier *
4999a747e4fSDavid du Colombier * also, set f->pr where possible
5009a747e4fSDavid du Colombier */
5019a747e4fSDavid du Colombier Filter*
complete(Filter * f,Proto * last)5029a747e4fSDavid du Colombier complete(Filter *f, Proto *last)
5039a747e4fSDavid du Colombier {
5049a747e4fSDavid du Colombier Proto *pr;
5059a747e4fSDavid du Colombier
5069a747e4fSDavid du Colombier if(f == nil)
5079a747e4fSDavid du Colombier return f;
5089a747e4fSDavid du Colombier
5099a747e4fSDavid du Colombier /* do a depth first traversal of the filter tree */
5109a747e4fSDavid du Colombier switch(f->op){
5116b6b9ac8SDavid du Colombier case '!':
5126b6b9ac8SDavid du Colombier f->l = complete(f->l, last);
5136b6b9ac8SDavid du Colombier break;
5149a747e4fSDavid du Colombier case LAND:
5159a747e4fSDavid du Colombier case LOR:
5169a747e4fSDavid du Colombier f->l = complete(f->l, last);
5179a747e4fSDavid du Colombier f->r = complete(f->r, last);
5189a747e4fSDavid du Colombier break;
5199a747e4fSDavid du Colombier case '=':
5209a747e4fSDavid du Colombier break;
5219a747e4fSDavid du Colombier case WORD:
5229a747e4fSDavid du Colombier pr = findproto(f->s);
5239a747e4fSDavid du Colombier f->pr = pr;
5249a747e4fSDavid du Colombier if(pr == nil){
5259a747e4fSDavid du Colombier if(f->l != nil){
5269a747e4fSDavid du Colombier fprint(2, "%s unknown proto, ignoring params\n",
5279a747e4fSDavid du Colombier f->s);
5289a747e4fSDavid du Colombier f->l = nil;
5299a747e4fSDavid du Colombier }
5309a747e4fSDavid du Colombier } else {
5319a747e4fSDavid du Colombier f->l = complete(f->l, pr);
5329a747e4fSDavid du Colombier f = fillin(f, last);
5339a747e4fSDavid du Colombier if(f == nil)
5349a747e4fSDavid du Colombier sysfatal("internal error: can't get to %s", pr->name);
5359a747e4fSDavid du Colombier }
5369a747e4fSDavid du Colombier break;
5379a747e4fSDavid du Colombier }
5389a747e4fSDavid du Colombier return f;
5399a747e4fSDavid du Colombier }
5409a747e4fSDavid du Colombier
5419a747e4fSDavid du Colombier /*
5429a747e4fSDavid du Colombier * merge common nodes under | and & moving the merged node
5439a747e4fSDavid du Colombier * above the | or &.
5449a747e4fSDavid du Colombier *
5459a747e4fSDavid du Colombier * do some constant foldong, e.g. `true & x' becomes x and
5469a747e4fSDavid du Colombier * 'true | x' becomes true.
5479a747e4fSDavid du Colombier */
5489a747e4fSDavid du Colombier static int changed;
5499a747e4fSDavid du Colombier
5509a747e4fSDavid du Colombier static Filter*
_optimize(Filter * f)5519a747e4fSDavid du Colombier _optimize(Filter *f)
5529a747e4fSDavid du Colombier {
5539a747e4fSDavid du Colombier Filter *l;
5549a747e4fSDavid du Colombier
5559a747e4fSDavid du Colombier if(f == nil)
5569a747e4fSDavid du Colombier return f;
5579a747e4fSDavid du Colombier
5589a747e4fSDavid du Colombier switch(f->op){
5596b6b9ac8SDavid du Colombier case '!':
5606b6b9ac8SDavid du Colombier /* is child also a not */
5616b6b9ac8SDavid du Colombier if(f->l->op == '!'){
5626b6b9ac8SDavid du Colombier changed = 1;
5636b6b9ac8SDavid du Colombier return f->l->l;
5646b6b9ac8SDavid du Colombier }
5656b6b9ac8SDavid du Colombier break;
5669a747e4fSDavid du Colombier case LOR:
5679a747e4fSDavid du Colombier /* are two children the same protocol? */
5689a747e4fSDavid du Colombier if(f->l->op != f->r->op || f->r->op != WORD
5699a747e4fSDavid du Colombier || f->l->pr != f->r->pr || f->l->pr == nil)
5709a747e4fSDavid du Colombier break; /* no optimization */
5719a747e4fSDavid du Colombier
5729a747e4fSDavid du Colombier changed = 1;
5739a747e4fSDavid du Colombier
5749a747e4fSDavid du Colombier /* constant folding */
5759a747e4fSDavid du Colombier /* if either child is childless, just return that */
5769a747e4fSDavid du Colombier if(f->l->l == nil)
5779a747e4fSDavid du Colombier return f->l;
5789a747e4fSDavid du Colombier else if(f->r->l == nil)
5799a747e4fSDavid du Colombier return f->r;
5809a747e4fSDavid du Colombier
5819a747e4fSDavid du Colombier /* move the common node up, thow away one node */
5829a747e4fSDavid du Colombier l = f->l;
5839a747e4fSDavid du Colombier f->l = l->l;
5849a747e4fSDavid du Colombier f->r = f->r->l;
5859a747e4fSDavid du Colombier l->l = f;
5869a747e4fSDavid du Colombier return l;
5879a747e4fSDavid du Colombier case LAND:
5889a747e4fSDavid du Colombier /* are two children the same protocol? */
5899a747e4fSDavid du Colombier if(f->l->op != f->r->op || f->r->op != WORD
5909a747e4fSDavid du Colombier || f->l->pr != f->r->pr || f->l->pr == nil)
5919a747e4fSDavid du Colombier break; /* no optimization */
5929a747e4fSDavid du Colombier
5939a747e4fSDavid du Colombier changed = 1;
5949a747e4fSDavid du Colombier
5959a747e4fSDavid du Colombier /* constant folding */
5969a747e4fSDavid du Colombier /* if either child is childless, ignore it */
5979a747e4fSDavid du Colombier if(f->l->l == nil)
5989a747e4fSDavid du Colombier return f->r;
5999a747e4fSDavid du Colombier else if(f->r->l == nil)
6009a747e4fSDavid du Colombier return f->l;
6019a747e4fSDavid du Colombier
6029a747e4fSDavid du Colombier /* move the common node up, thow away one node */
6039a747e4fSDavid du Colombier l = f->l;
6049a747e4fSDavid du Colombier f->l = _optimize(l->l);
6059a747e4fSDavid du Colombier f->r = _optimize(f->r->l);
6069a747e4fSDavid du Colombier l->l = f;
6079a747e4fSDavid du Colombier return l;
6089a747e4fSDavid du Colombier }
6099a747e4fSDavid du Colombier f->l = _optimize(f->l);
6109a747e4fSDavid du Colombier f->r = _optimize(f->r);
6119a747e4fSDavid du Colombier return f;
6129a747e4fSDavid du Colombier }
6139a747e4fSDavid du Colombier
6149a747e4fSDavid du Colombier Filter*
optimize(Filter * f)6159a747e4fSDavid du Colombier optimize(Filter *f)
6169a747e4fSDavid du Colombier {
6179a747e4fSDavid du Colombier do{
6189a747e4fSDavid du Colombier changed = 0;
6199a747e4fSDavid du Colombier f = _optimize(f);
6209a747e4fSDavid du Colombier }while(changed);
6219a747e4fSDavid du Colombier
6229a747e4fSDavid du Colombier return f;
6239a747e4fSDavid du Colombier }
6249a747e4fSDavid du Colombier
6259a747e4fSDavid du Colombier /*
6269a747e4fSDavid du Colombier * find any top level nodes that aren't the root
6279a747e4fSDavid du Colombier */
6286b6b9ac8SDavid du Colombier int
findbogus(Filter * f)6299a747e4fSDavid du Colombier findbogus(Filter *f)
6309a747e4fSDavid du Colombier {
6316b6b9ac8SDavid du Colombier int rv;
6326b6b9ac8SDavid du Colombier
6339a747e4fSDavid du Colombier if(f->op != WORD){
6346b6b9ac8SDavid du Colombier rv = findbogus(f->l);
6356b6b9ac8SDavid du Colombier if(f->r)
6366b6b9ac8SDavid du Colombier rv |= findbogus(f->r);
6376b6b9ac8SDavid du Colombier return rv;
6386b6b9ac8SDavid du Colombier } else if(f->pr != root){
6396b6b9ac8SDavid du Colombier fprint(2, "bad top-level protocol: %s\n", f->s);
6406b6b9ac8SDavid du Colombier return 1;
6416b6b9ac8SDavid du Colombier }
6426b6b9ac8SDavid du Colombier return 0;
6439a747e4fSDavid du Colombier }
6449a747e4fSDavid du Colombier
6459a747e4fSDavid du Colombier /*
6469a747e4fSDavid du Colombier * compile the filter
6479a747e4fSDavid du Colombier */
6489a747e4fSDavid du Colombier static void
_compile(Filter * f,Proto * last)6499a747e4fSDavid du Colombier _compile(Filter *f, Proto *last)
6509a747e4fSDavid du Colombier {
6519a747e4fSDavid du Colombier if(f == nil)
6529a747e4fSDavid du Colombier return;
6539a747e4fSDavid du Colombier
6549a747e4fSDavid du Colombier switch(f->op){
6556b6b9ac8SDavid du Colombier case '!':
6566b6b9ac8SDavid du Colombier _compile(f->l, last);
6576b6b9ac8SDavid du Colombier break;
6589a747e4fSDavid du Colombier case LOR:
6599a747e4fSDavid du Colombier case LAND:
6609a747e4fSDavid du Colombier _compile(f->l, last);
6619a747e4fSDavid du Colombier _compile(f->r, last);
6629a747e4fSDavid du Colombier break;
6639a747e4fSDavid du Colombier case WORD:
6642cca75a1SDavid du Colombier if(last != nil){
6652cca75a1SDavid du Colombier if(last->compile == nil)
6662cca75a1SDavid du Colombier sysfatal("unknown %s subprotocol: %s", f->pr->name, f->s);
6679a747e4fSDavid du Colombier (*last->compile)(f);
6682cca75a1SDavid du Colombier }
6699a747e4fSDavid du Colombier if(f->l)
6709a747e4fSDavid du Colombier _compile(f->l, f->pr);
6719a747e4fSDavid du Colombier break;
6729a747e4fSDavid du Colombier case '=':
6739a747e4fSDavid du Colombier if(last == nil)
6749a747e4fSDavid du Colombier sysfatal("internal error: compilewalk: badly formed tree");
6752cca75a1SDavid du Colombier
6762cca75a1SDavid du Colombier if(last->compile == nil)
6772cca75a1SDavid du Colombier sysfatal("unknown %s field: %s", f->pr->name, f->s);
6789a747e4fSDavid du Colombier (*last->compile)(f);
6799a747e4fSDavid du Colombier break;
6809a747e4fSDavid du Colombier default:
6819a747e4fSDavid du Colombier sysfatal("internal error: compilewalk op: %d", f->op);
6829a747e4fSDavid du Colombier }
6839a747e4fSDavid du Colombier }
6849a747e4fSDavid du Colombier
6859a747e4fSDavid du Colombier Filter*
compile(Filter * f)6869a747e4fSDavid du Colombier compile(Filter *f)
6879a747e4fSDavid du Colombier {
6889a747e4fSDavid du Colombier if(f == nil)
6899a747e4fSDavid du Colombier return f;
6909a747e4fSDavid du Colombier
6919a747e4fSDavid du Colombier /* fill in the missing header filters */
6929a747e4fSDavid du Colombier f = complete(f, nil);
6939a747e4fSDavid du Colombier
6949a747e4fSDavid du Colombier /* constant folding */
6959a747e4fSDavid du Colombier f = optimize(f);
6963ff48bf5SDavid du Colombier if(!toflag)
6979a747e4fSDavid du Colombier printfilter(f, "after optimize");
6989a747e4fSDavid du Colombier
6999a747e4fSDavid du Colombier /* protocol specific compilations */
7009a747e4fSDavid du Colombier _compile(f, nil);
7019a747e4fSDavid du Colombier
7029a747e4fSDavid du Colombier /* at this point, the root had better be the root proto */
7036b6b9ac8SDavid du Colombier if(findbogus(f)){
7046b6b9ac8SDavid du Colombier fprint(2, "bogus filter\n");
7056b6b9ac8SDavid du Colombier exits("bad filter");
7069a747e4fSDavid du Colombier }
7076b6b9ac8SDavid du Colombier
7086b6b9ac8SDavid du Colombier return f;
7099a747e4fSDavid du Colombier }
7109a747e4fSDavid du Colombier
7119a747e4fSDavid du Colombier /*
7129a747e4fSDavid du Colombier * parse a byte array
7139a747e4fSDavid du Colombier */
7149a747e4fSDavid du Colombier int
parseba(uchar * to,char * from)7159a747e4fSDavid du Colombier parseba(uchar *to, char *from)
7169a747e4fSDavid du Colombier {
7179a747e4fSDavid du Colombier char nip[4];
7189a747e4fSDavid du Colombier char *p;
7199a747e4fSDavid du Colombier int i;
7209a747e4fSDavid du Colombier
7219a747e4fSDavid du Colombier p = from;
7229a747e4fSDavid du Colombier for(i = 0; i < 16; i++){
7239a747e4fSDavid du Colombier if(*p == 0)
7249a747e4fSDavid du Colombier return -1;
7259a747e4fSDavid du Colombier nip[0] = *p++;
7269a747e4fSDavid du Colombier if(*p == 0)
7279a747e4fSDavid du Colombier return -1;
7289a747e4fSDavid du Colombier nip[1] = *p++;
7299a747e4fSDavid du Colombier nip[2] = 0;
7309a747e4fSDavid du Colombier to[i] = strtoul(nip, 0, 16);
7319a747e4fSDavid du Colombier }
7329a747e4fSDavid du Colombier return i;
7339a747e4fSDavid du Colombier }
7349a747e4fSDavid du Colombier
7359a747e4fSDavid du Colombier /*
7369a747e4fSDavid du Colombier * compile WORD = WORD, becomes a single node with a subop
7379a747e4fSDavid du Colombier */
7389a747e4fSDavid du Colombier void
compile_cmp(char * proto,Filter * f,Field * fld)7399a747e4fSDavid du Colombier compile_cmp(char *proto, Filter *f, Field *fld)
7409a747e4fSDavid du Colombier {
7419a747e4fSDavid du Colombier uchar x[IPaddrlen];
7428fd921c8SDavid du Colombier char *v;
7439a747e4fSDavid du Colombier
7449a747e4fSDavid du Colombier if(f->op != '=')
7459a747e4fSDavid du Colombier sysfatal("internal error: compile_cmp %s: not a cmp", proto);
7469a747e4fSDavid du Colombier
7479a747e4fSDavid du Colombier for(; fld->name != nil; fld++){
7489a747e4fSDavid du Colombier if(strcmp(f->l->s, fld->name) == 0){
7499a747e4fSDavid du Colombier f->op = WORD;
7509a747e4fSDavid du Colombier f->subop = fld->subop;
7519a747e4fSDavid du Colombier switch(fld->ftype){
7529a747e4fSDavid du Colombier case Fnum:
7539a747e4fSDavid du Colombier f->ulv = atoi(f->r->s);
7549a747e4fSDavid du Colombier break;
7559a747e4fSDavid du Colombier case Fether:
7568fd921c8SDavid du Colombier v = csgetvalue(nil, "sys", (char*)f->r->s,
7578fd921c8SDavid du Colombier "ether", 0);
7588fd921c8SDavid du Colombier if(v){
7598fd921c8SDavid du Colombier parseether(f->a, v);
7608fd921c8SDavid du Colombier free(v);
7618fd921c8SDavid du Colombier } else
7629a747e4fSDavid du Colombier parseether(f->a, f->r->s);
7639a747e4fSDavid du Colombier break;
7649a747e4fSDavid du Colombier case Fv4ip:
7658fd921c8SDavid du Colombier v = csgetvalue(nil, "sys", (char*)f->r->s,
7668fd921c8SDavid du Colombier "ip", 0);
7678fd921c8SDavid du Colombier if(v){
7688fd921c8SDavid du Colombier f->ulv = parseip(x, v);
7698fd921c8SDavid du Colombier free(v);
7708fd921c8SDavid du Colombier }else
7719a747e4fSDavid du Colombier f->ulv = parseip(x, f->r->s);
7729a747e4fSDavid du Colombier break;
7739a747e4fSDavid du Colombier case Fv6ip:
7748fd921c8SDavid du Colombier v = csgetvalue(nil, "sys", (char*)f->r->s,
7758fd921c8SDavid du Colombier "ipv6", 0);
7768fd921c8SDavid du Colombier if(v){
7778fd921c8SDavid du Colombier parseip(f->a, v);
7788fd921c8SDavid du Colombier free(v);
7798fd921c8SDavid du Colombier }else
7809a747e4fSDavid du Colombier parseip(f->a, f->r->s);
7819a747e4fSDavid du Colombier break;
7829a747e4fSDavid du Colombier case Fba:
7839a747e4fSDavid du Colombier parseba(f->a, f->r->s);
7849a747e4fSDavid du Colombier break;
7859a747e4fSDavid du Colombier default:
7869a747e4fSDavid du Colombier sysfatal("internal error: compile_cmp %s: %d",
7879a747e4fSDavid du Colombier proto, fld->ftype);
7889a747e4fSDavid du Colombier }
7899a747e4fSDavid du Colombier f->l = f->r = nil;
7909a747e4fSDavid du Colombier return;
7919a747e4fSDavid du Colombier }
7929a747e4fSDavid du Colombier }
7939a747e4fSDavid du Colombier sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s);
7949a747e4fSDavid du Colombier }
7959a747e4fSDavid du Colombier
7969a747e4fSDavid du Colombier void
_pf(Filter * f)7979a747e4fSDavid du Colombier _pf(Filter *f)
7989a747e4fSDavid du Colombier {
7996b6b9ac8SDavid du Colombier char *s;
8006b6b9ac8SDavid du Colombier
8019a747e4fSDavid du Colombier if(f == nil)
8029a747e4fSDavid du Colombier return;
8039a747e4fSDavid du Colombier
8046b6b9ac8SDavid du Colombier s = nil;
8059a747e4fSDavid du Colombier switch(f->op){
8066b6b9ac8SDavid du Colombier case '!':
8076b6b9ac8SDavid du Colombier fprint(2, "!");
8089a747e4fSDavid du Colombier _pf(f->l);
8096b6b9ac8SDavid du Colombier break;
8106b6b9ac8SDavid du Colombier case WORD:
8116b6b9ac8SDavid du Colombier fprint(2, "%s", f->s);
8126b6b9ac8SDavid du Colombier if(f->l != nil){
8136b6b9ac8SDavid du Colombier fprint(2, "(");
8146b6b9ac8SDavid du Colombier _pf(f->l);
8156b6b9ac8SDavid du Colombier fprint(2, ")");
8169a747e4fSDavid du Colombier }
8179a747e4fSDavid du Colombier break;
8189a747e4fSDavid du Colombier case LAND:
8196b6b9ac8SDavid du Colombier s = "&&";
8206b6b9ac8SDavid du Colombier goto print;
8219a747e4fSDavid du Colombier case LOR:
8226b6b9ac8SDavid du Colombier s = "||";
8236b6b9ac8SDavid du Colombier goto print;
8249a747e4fSDavid du Colombier case '=':
8256b6b9ac8SDavid du Colombier print:
8269a747e4fSDavid du Colombier _pf(f->l);
8276b6b9ac8SDavid du Colombier if(s)
8286b6b9ac8SDavid du Colombier fprint(2, " %s ", s);
8296b6b9ac8SDavid du Colombier else
8306b6b9ac8SDavid du Colombier fprint(2, " %c ", f->op);
8319a747e4fSDavid du Colombier _pf(f->r);
8329a747e4fSDavid du Colombier break;
8339a747e4fSDavid du Colombier default:
8346b6b9ac8SDavid du Colombier fprint(2, "???");
8359a747e4fSDavid du Colombier break;
8369a747e4fSDavid du Colombier }
8379a747e4fSDavid du Colombier }
8389a747e4fSDavid du Colombier
8399a747e4fSDavid du Colombier void
printfilter(Filter * f,char * tag)8409a747e4fSDavid du Colombier printfilter(Filter *f, char *tag)
8419a747e4fSDavid du Colombier {
8426b6b9ac8SDavid du Colombier fprint(2, "%s: ", tag);
8439a747e4fSDavid du Colombier _pf(f);
8446b6b9ac8SDavid du Colombier fprint(2, "\n");
8459a747e4fSDavid du Colombier }
8469a747e4fSDavid du Colombier
8479a747e4fSDavid du Colombier void
cat(void)848ed397113SDavid du Colombier cat(void)
8499a747e4fSDavid du Colombier {
850ed397113SDavid du Colombier char buf[1024];
851ed397113SDavid du Colombier int n;
852ed397113SDavid du Colombier
853ed397113SDavid du Colombier while((n = read(0, buf, sizeof buf)) > 0)
854ed397113SDavid du Colombier write(1, buf, n);
855ed397113SDavid du Colombier }
856ed397113SDavid du Colombier
857ed397113SDavid du Colombier static int fd1 = -1;
858ed397113SDavid du Colombier void
startmc(void)859ed397113SDavid du Colombier startmc(void)
860ed397113SDavid du Colombier {
861ed397113SDavid du Colombier int p[2];
862ed397113SDavid du Colombier
863ed397113SDavid du Colombier if(fd1 == -1)
864ed397113SDavid du Colombier fd1 = dup(1, -1);
865ed397113SDavid du Colombier
866ed397113SDavid du Colombier if(pipe(p) < 0)
867ed397113SDavid du Colombier return;
868ed397113SDavid du Colombier switch(fork()){
869ed397113SDavid du Colombier case -1:
870ed397113SDavid du Colombier return;
871ed397113SDavid du Colombier default:
872ed397113SDavid du Colombier close(p[0]);
873ed397113SDavid du Colombier dup(p[1], 1);
874ed397113SDavid du Colombier if(p[1] != 1)
875ed397113SDavid du Colombier close(p[1]);
876ed397113SDavid du Colombier return;
877ed397113SDavid du Colombier case 0:
878ed397113SDavid du Colombier close(p[1]);
879ed397113SDavid du Colombier dup(p[0], 0);
880ed397113SDavid du Colombier if(p[0] != 0)
881ed397113SDavid du Colombier close(p[0]);
882ed397113SDavid du Colombier execl("/bin/mc", "mc", nil);
883ed397113SDavid du Colombier cat();
884ed397113SDavid du Colombier _exits(0);
885ed397113SDavid du Colombier }
886ed397113SDavid du Colombier }
887ed397113SDavid du Colombier
888ed397113SDavid du Colombier void
stopmc(void)889ed397113SDavid du Colombier stopmc(void)
890ed397113SDavid du Colombier {
891ed397113SDavid du Colombier close(1);
892ed397113SDavid du Colombier dup(fd1, 1);
893ed397113SDavid du Colombier waitpid();
894ed397113SDavid du Colombier }
895ed397113SDavid du Colombier
896ed397113SDavid du Colombier void
printhelp(char * name)897ed397113SDavid du Colombier printhelp(char *name)
898ed397113SDavid du Colombier {
899ed397113SDavid du Colombier int len;
9009a747e4fSDavid du Colombier Proto *pr, **l;
9019a747e4fSDavid du Colombier Mux *m;
9029a747e4fSDavid du Colombier Field *f;
903ed397113SDavid du Colombier char fmt[40];
9049a747e4fSDavid du Colombier
905ed397113SDavid du Colombier if(name == nil){
906ed397113SDavid du Colombier print("protocols:\n");
907ed397113SDavid du Colombier startmc();
908ed397113SDavid du Colombier for(l=protos; (pr=*l) != nil; l++)
909ed397113SDavid du Colombier print(" %s\n", pr->name);
910ed397113SDavid du Colombier stopmc();
911ed397113SDavid du Colombier return;
9129a747e4fSDavid du Colombier }
913ed397113SDavid du Colombier
914ed397113SDavid du Colombier pr = findproto(name);
915ed397113SDavid du Colombier if(pr == nil){
916ed397113SDavid du Colombier print("unknown protocol %s\n", name);
917ed397113SDavid du Colombier return;
918ed397113SDavid du Colombier }
919ed397113SDavid du Colombier
920ed397113SDavid du Colombier if(pr->field){
921ed397113SDavid du Colombier print("%s's filter attributes:\n", pr->name);
922ed397113SDavid du Colombier len = 0;
923ed397113SDavid du Colombier for(f=pr->field; f->name; f++)
924ed397113SDavid du Colombier if(len < strlen(f->name))
925ed397113SDavid du Colombier len = strlen(f->name);
926ed397113SDavid du Colombier startmc();
927ed397113SDavid du Colombier for(f=pr->field; f->name; f++)
928ed397113SDavid du Colombier print(" %-*s - %s\n", len, f->name, f->help);
929ed397113SDavid du Colombier stopmc();
930ed397113SDavid du Colombier }
931ed397113SDavid du Colombier if(pr->mux){
9329a747e4fSDavid du Colombier print("%s's subprotos:\n", pr->name);
933ed397113SDavid du Colombier startmc();
934ed397113SDavid du Colombier snprint(fmt, sizeof fmt, " %s %%s\n", pr->valfmt);
9359a747e4fSDavid du Colombier for(m=pr->mux; m->name != nil; m++)
936ed397113SDavid du Colombier print(fmt, m->val, m->name);
937ed397113SDavid du Colombier stopmc();
9389a747e4fSDavid du Colombier }
9399a747e4fSDavid du Colombier }
9409a747e4fSDavid du Colombier
9419a747e4fSDavid du Colombier /*
9429a747e4fSDavid du Colombier * demultiplex to next prototol header
9439a747e4fSDavid du Colombier */
9449a747e4fSDavid du Colombier void
demux(Mux * mx,ulong val1,ulong val2,Msg * m,Proto * def)9459a747e4fSDavid du Colombier demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def)
9469a747e4fSDavid du Colombier {
9479a747e4fSDavid du Colombier m->pr = def;
9489a747e4fSDavid du Colombier for(mx = mx; mx->name != nil; mx++){
9499a747e4fSDavid du Colombier if(val1 == mx->val || val2 == mx->val){
9509a747e4fSDavid du Colombier m->pr = mx->pr;
9519a747e4fSDavid du Colombier break;
9529a747e4fSDavid du Colombier }
9539a747e4fSDavid du Colombier }
9549a747e4fSDavid du Colombier }
9553ff48bf5SDavid du Colombier
9563ff48bf5SDavid du Colombier /*
9573ff48bf5SDavid du Colombier * default framer just assumes the input packet is
9583ff48bf5SDavid du Colombier * a single read
9593ff48bf5SDavid du Colombier */
9603ff48bf5SDavid du Colombier int
defaultframer(int fd,uchar * pkt,int pktlen)9613ff48bf5SDavid du Colombier defaultframer(int fd, uchar *pkt, int pktlen)
9623ff48bf5SDavid du Colombier {
9633ff48bf5SDavid du Colombier return read(fd, pkt, pktlen);
9643ff48bf5SDavid du Colombier }
965