xref: /plan9/sys/src/cmd/ip/snoopy/main.c (revision 6b6b9ac8b0b103b1e30e4d019522a78c950fce74)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <ip.h>
49a747e4fSDavid du Colombier #include <bio.h>
59a747e4fSDavid du Colombier #include <fcall.h>
69a747e4fSDavid du Colombier #include <libsec.h>
79a747e4fSDavid du Colombier #include "dat.h"
89a747e4fSDavid du Colombier #include "protos.h"
99a747e4fSDavid du Colombier #include "y.tab.h"
109a747e4fSDavid du Colombier 
119a747e4fSDavid du Colombier int Cflag;
129a747e4fSDavid du Colombier int pflag;
139a747e4fSDavid du Colombier int Nflag;
149a747e4fSDavid du Colombier int sflag;
159a747e4fSDavid du Colombier int tiflag;
169a747e4fSDavid du Colombier int toflag;
179a747e4fSDavid du Colombier 
189a747e4fSDavid du Colombier char *prom = "promiscuous";
199a747e4fSDavid du Colombier 
209a747e4fSDavid du Colombier enum
219a747e4fSDavid du Colombier {
229a747e4fSDavid du Colombier 	Pktlen=	64*1024,
239a747e4fSDavid du Colombier 	Blen=	16*1024,
249a747e4fSDavid du Colombier };
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier Filter *filter;
279a747e4fSDavid du Colombier Proto *root;
289a747e4fSDavid du Colombier Biobuf out;
299a747e4fSDavid du Colombier vlong starttime, pkttime;
303ff48bf5SDavid du Colombier int pcap;
319a747e4fSDavid du Colombier 
32*6b6b9ac8SDavid du Colombier int	filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int);
339a747e4fSDavid du Colombier void	printpkt(char *p, char *e, uchar *ps, uchar *pe);
349a747e4fSDavid du Colombier void	mkprotograph(void);
359a747e4fSDavid du Colombier Proto*	findproto(char *name);
369a747e4fSDavid du Colombier Filter*	compile(Filter *f);
379a747e4fSDavid du Colombier void	printfilter(Filter *f, char *tag);
389a747e4fSDavid du Colombier void	printhelp(void);
399a747e4fSDavid du Colombier void	tracepkt(uchar*, int);
403ff48bf5SDavid du Colombier void	pcaphdr(void);
419a747e4fSDavid du Colombier 
429a747e4fSDavid du Colombier void
439a747e4fSDavid du Colombier usage(void)
449a747e4fSDavid du Colombier {
459a747e4fSDavid du Colombier 	fprint(2, "usage: %s [-std?] [-c] [-N n] [-f filter] [-h first-header] path", argv0);
469a747e4fSDavid du Colombier 	exits("usage");
479a747e4fSDavid du Colombier }
489a747e4fSDavid du Colombier 
499a747e4fSDavid du Colombier void
509a747e4fSDavid du Colombier main(int argc, char **argv)
519a747e4fSDavid du Colombier {
529a747e4fSDavid du Colombier 	uchar *pkt;
539a747e4fSDavid du Colombier 	char *buf, *file, *p, *e;
549a747e4fSDavid du Colombier 	int fd, cfd;
559a747e4fSDavid du Colombier 	int n;
569a747e4fSDavid du Colombier 
579a747e4fSDavid du Colombier 	Binit(&out, 1, OWRITE);
589a747e4fSDavid du Colombier 
599a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
609a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
619a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
629a747e4fSDavid du Colombier 	fmtinstall('H', encodefmt);
639a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
649a747e4fSDavid du Colombier 
653ff48bf5SDavid du Colombier 	pkt = malloc(Pktlen+16);
663ff48bf5SDavid du Colombier 	pkt += 16;
679a747e4fSDavid du Colombier 	buf = malloc(Blen);
689a747e4fSDavid du Colombier 	e = buf+Blen-1;
699a747e4fSDavid du Colombier 
709a747e4fSDavid du Colombier 	pflag = 1;
719a747e4fSDavid du Colombier 	Nflag = 32;
729a747e4fSDavid du Colombier 	sflag = 0;
739a747e4fSDavid du Colombier 
749a747e4fSDavid du Colombier 	mkprotograph();
759a747e4fSDavid du Colombier 
769a747e4fSDavid du Colombier 	ARGBEGIN{
779a747e4fSDavid du Colombier 	case '?':
789a747e4fSDavid du Colombier 		printhelp();
799a747e4fSDavid du Colombier 		exits(0);
809a747e4fSDavid du Colombier 		break;
819a747e4fSDavid du Colombier 	case 'N':
829a747e4fSDavid du Colombier 		p = ARGF();
839a747e4fSDavid du Colombier 		if(p == nil)
849a747e4fSDavid du Colombier 			usage();
859a747e4fSDavid du Colombier 		Nflag = atoi(p);
869a747e4fSDavid du Colombier 		break;
879a747e4fSDavid du Colombier 	case 'f':
889a747e4fSDavid du Colombier 		p = ARGF();
899a747e4fSDavid du Colombier 		if(p == nil)
909a747e4fSDavid du Colombier 			usage();
919a747e4fSDavid du Colombier 		yyinit(p);
929a747e4fSDavid du Colombier 		yyparse();
939a747e4fSDavid du Colombier 		break;
949a747e4fSDavid du Colombier 	case 's':
959a747e4fSDavid du Colombier 		sflag = 1;
969a747e4fSDavid du Colombier 		break;
979a747e4fSDavid du Colombier 	case 'h':
989a747e4fSDavid du Colombier 		p = ARGF();
999a747e4fSDavid du Colombier 		if(p == nil)
1009a747e4fSDavid du Colombier 			usage();
1019a747e4fSDavid du Colombier 		root = findproto(p);
1029a747e4fSDavid du Colombier 		if(root == nil)
1039a747e4fSDavid du Colombier 			sysfatal("unknown protocol: %s", p);
1049a747e4fSDavid du Colombier 		break;
1059a747e4fSDavid du Colombier 	case 'd':
1069a747e4fSDavid du Colombier 		toflag = 1;
1079a747e4fSDavid du Colombier 		break;
1083ff48bf5SDavid du Colombier 	case 'D':
1093ff48bf5SDavid du Colombier 		toflag = 1;
1103ff48bf5SDavid du Colombier 		pcap = 1;
1113ff48bf5SDavid du Colombier 		break;
1129a747e4fSDavid du Colombier 	case 't':
1139a747e4fSDavid du Colombier 		tiflag = 1;
1149a747e4fSDavid du Colombier 		break;
1159a747e4fSDavid du Colombier 	case 'C':
1169a747e4fSDavid du Colombier 		Cflag = 1;
1179a747e4fSDavid du Colombier 		break;
1189a747e4fSDavid du Colombier 	}ARGEND;
1199a747e4fSDavid du Colombier 
1203ff48bf5SDavid du Colombier 	if(pcap)
1213ff48bf5SDavid du Colombier 		pcaphdr();
1223ff48bf5SDavid du Colombier 
1239a747e4fSDavid du Colombier 	if(argc == 0){
1249a747e4fSDavid du Colombier 		file = "/net/ether0";
1259a747e4fSDavid du Colombier 		if(root != nil)
1269a747e4fSDavid du Colombier 			root = &ether;
1279a747e4fSDavid du Colombier 	} else
1289a747e4fSDavid du Colombier 		file = argv[0];
1299a747e4fSDavid du Colombier 
1309a747e4fSDavid du Colombier 	if((!tiflag) && strstr(file, "ether")){
1319a747e4fSDavid du Colombier 		if(root == nil)
1329a747e4fSDavid du Colombier 			root = &ether;
1339a747e4fSDavid du Colombier 		snprint(buf, Blen, "%s!-1", file);
1349a747e4fSDavid du Colombier 		fd = dial(buf, 0, 0, &cfd);
1359a747e4fSDavid du Colombier 		if(fd < 0)
1369a747e4fSDavid du Colombier 			sysfatal("dialing %s", buf);
1379a747e4fSDavid du Colombier 		if(pflag && fprint(cfd, prom, strlen(prom)) < 0)
1389a747e4fSDavid du Colombier 			sysfatal("setting %s", prom);
1399a747e4fSDavid du Colombier 	} else if((!tiflag) && strstr(file, "ipifc")){
1409a747e4fSDavid du Colombier 		if(root == nil)
1419a747e4fSDavid du Colombier 			root = &ip;
1429a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "%s/snoopy", file);
1439a747e4fSDavid du Colombier 		fd = open(buf, OREAD);
1449a747e4fSDavid du Colombier 		if(fd < 0)
1459a747e4fSDavid du Colombier 			sysfatal("opening %s", buf);
1469a747e4fSDavid du Colombier 	} else {
1479a747e4fSDavid du Colombier 		if(root == nil)
1489a747e4fSDavid du Colombier 			root = &ether;
1499a747e4fSDavid du Colombier 		fd = open(file, OREAD);
1509a747e4fSDavid du Colombier 		if(fd < 0)
1519a747e4fSDavid du Colombier 			sysfatal("opening %s", file);
1529a747e4fSDavid du Colombier 	}
1539a747e4fSDavid du Colombier 	filter = compile(filter);
1549a747e4fSDavid du Colombier 
1559a747e4fSDavid du Colombier 	if(tiflag){
1563ff48bf5SDavid du Colombier 		/* read a trace file */
1579a747e4fSDavid du Colombier 		for(;;){
1589a747e4fSDavid du Colombier 			n = read(fd, pkt, 10);
1599a747e4fSDavid du Colombier 			if(n != 10)
1609a747e4fSDavid du Colombier 				break;
1619a747e4fSDavid du Colombier 			pkttime = NetL(pkt+2);
1629a747e4fSDavid du Colombier 			pkttime = (pkttime<<32) | NetL(pkt+6);
1639a747e4fSDavid du Colombier 			if(starttime == 0LL)
1649a747e4fSDavid du Colombier 				starttime = pkttime;
1659a747e4fSDavid du Colombier 			n = NetS(pkt);
1663ff48bf5SDavid du Colombier 			if(readn(fd, pkt, n) != n)
1679a747e4fSDavid du Colombier 				break;
168*6b6b9ac8SDavid du Colombier 			if(filterpkt(filter, pkt, pkt+n, root, 1))
1699a747e4fSDavid du Colombier 				if(toflag)
1709a747e4fSDavid du Colombier 					tracepkt(pkt, n);
1719a747e4fSDavid du Colombier 				else
1729a747e4fSDavid du Colombier 					printpkt(buf, e, pkt, pkt+n);
1739a747e4fSDavid du Colombier 		}
1749a747e4fSDavid du Colombier 	} else {
1759a747e4fSDavid du Colombier 		/* read a real time stream */
1769a747e4fSDavid du Colombier 		starttime = nsec();
1779a747e4fSDavid du Colombier 		for(;;){
1783ff48bf5SDavid du Colombier 			n = root->framer(fd, pkt, Pktlen);
1799a747e4fSDavid du Colombier 			if(n <= 0)
1809a747e4fSDavid du Colombier 				break;
1819a747e4fSDavid du Colombier 			pkttime = nsec();
182*6b6b9ac8SDavid du Colombier 			if(filterpkt(filter, pkt, pkt+n, root, 1))
1839a747e4fSDavid du Colombier 				if(toflag)
1849a747e4fSDavid du Colombier 					tracepkt(pkt, n);
1859a747e4fSDavid du Colombier 				else
1869a747e4fSDavid du Colombier 					printpkt(buf, e, pkt, pkt+n);
1879a747e4fSDavid du Colombier 		}
1889a747e4fSDavid du Colombier 	}
1899a747e4fSDavid du Colombier }
1909a747e4fSDavid du Colombier 
1919a747e4fSDavid du Colombier /* create a new filter node */
1929a747e4fSDavid du Colombier Filter*
1939a747e4fSDavid du Colombier newfilter(void)
1949a747e4fSDavid du Colombier {
1959a747e4fSDavid du Colombier 	Filter *f;
1969a747e4fSDavid du Colombier 
1979a747e4fSDavid du Colombier 	f = mallocz(sizeof(*f), 1);
1989a747e4fSDavid du Colombier 	if(f == nil)
1999a747e4fSDavid du Colombier 		sysfatal("newfilter: %r");
2009a747e4fSDavid du Colombier 	return f;
2019a747e4fSDavid du Colombier }
2029a747e4fSDavid du Colombier 
2039a747e4fSDavid du Colombier /*
2049a747e4fSDavid du Colombier  *  apply filter to packet
2059a747e4fSDavid du Colombier  */
2069a747e4fSDavid du Colombier int
2079a747e4fSDavid du Colombier _filterpkt(Filter *f, Msg *m)
2089a747e4fSDavid du Colombier {
2099a747e4fSDavid du Colombier 	Msg ma;
2109a747e4fSDavid du Colombier 
2119a747e4fSDavid du Colombier 	if(f == nil)
2129a747e4fSDavid du Colombier 		return 1;
2139a747e4fSDavid du Colombier 
2149a747e4fSDavid du Colombier 	switch(f->op){
215*6b6b9ac8SDavid du Colombier 	case '!':
216*6b6b9ac8SDavid du Colombier 		return !_filterpkt(f->l, m);
2179a747e4fSDavid du Colombier 	case LAND:
2189a747e4fSDavid du Colombier 		ma = *m;
2199a747e4fSDavid du Colombier 		return _filterpkt(f->l, &ma) && _filterpkt(f->r, m);
2209a747e4fSDavid du Colombier 	case LOR:
2219a747e4fSDavid du Colombier 		ma = *m;
2229a747e4fSDavid du Colombier 		return _filterpkt(f->l, &ma) || _filterpkt(f->r, m);
2239a747e4fSDavid du Colombier 	case WORD:
224*6b6b9ac8SDavid du Colombier 		if(m->needroot){
225*6b6b9ac8SDavid du Colombier 			if(m->pr != f->pr)
226*6b6b9ac8SDavid du Colombier 				return 0;
227*6b6b9ac8SDavid du Colombier 			m->needroot = 0;
228*6b6b9ac8SDavid du Colombier 		}else{
2299a747e4fSDavid du Colombier 			if(m->pr != nil && !(m->pr->filter)(f, m))
2309a747e4fSDavid du Colombier 				return 0;
231*6b6b9ac8SDavid du Colombier 		}
2329a747e4fSDavid du Colombier 		if(f->l == nil)
2339a747e4fSDavid du Colombier 			return 1;
2349a747e4fSDavid du Colombier 		m->pr = f->pr;
2359a747e4fSDavid du Colombier 		return _filterpkt(f->l, m);
2369a747e4fSDavid du Colombier 	}
2379a747e4fSDavid du Colombier 	sysfatal("internal error: filterpkt op: %d", f->op);
2389a747e4fSDavid du Colombier 	return 0;
2399a747e4fSDavid du Colombier }
2409a747e4fSDavid du Colombier int
241*6b6b9ac8SDavid du Colombier filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot)
2429a747e4fSDavid du Colombier {
2439a747e4fSDavid du Colombier 	Msg m;
2449a747e4fSDavid du Colombier 
2459a747e4fSDavid du Colombier 	if(f == nil)
2469a747e4fSDavid du Colombier 		return 1;
2479a747e4fSDavid du Colombier 
248*6b6b9ac8SDavid du Colombier 	m.needroot = needroot;
2499a747e4fSDavid du Colombier 	m.ps = ps;
2509a747e4fSDavid du Colombier 	m.pe = pe;
2519a747e4fSDavid du Colombier 	m.pr = pr;
2529a747e4fSDavid du Colombier 	return _filterpkt(f, &m);
2539a747e4fSDavid du Colombier }
2549a747e4fSDavid du Colombier 
2559a747e4fSDavid du Colombier /*
2563ff48bf5SDavid du Colombier  *  from the Unix world
2573ff48bf5SDavid du Colombier  */
2583ff48bf5SDavid du Colombier #define PCAP_VERSION_MAJOR 2
2593ff48bf5SDavid du Colombier #define PCAP_VERSION_MINOR 4
2603ff48bf5SDavid du Colombier #define TCPDUMP_MAGIC 0xa1b2c3d4
2613ff48bf5SDavid du Colombier 
2623ff48bf5SDavid du Colombier struct pcap_file_header {
2633ff48bf5SDavid du Colombier 	ulong		magic;
2643ff48bf5SDavid du Colombier 	ushort		version_major;
2653ff48bf5SDavid du Colombier 	ushort		version_minor;
2663ff48bf5SDavid du Colombier 	long		thiszone;    /* gmt to local correction */
2673ff48bf5SDavid du Colombier 	ulong		sigfigs;    /* accuracy of timestamps */
2683ff48bf5SDavid du Colombier 	ulong		snaplen;    /* max length saved portion of each pkt */
2693ff48bf5SDavid du Colombier 	ulong		linktype;   /* data link type (DLT_*) */
2703ff48bf5SDavid du Colombier };
2713ff48bf5SDavid du Colombier 
2723ff48bf5SDavid du Colombier struct pcap_pkthdr {
2733ff48bf5SDavid du Colombier         uvlong	ts;	/* time stamp */
2743ff48bf5SDavid du Colombier         ulong	caplen;	/* length of portion present */
2753ff48bf5SDavid du Colombier         ulong	len;	/* length this packet (off wire) */
2763ff48bf5SDavid du Colombier };
2773ff48bf5SDavid du Colombier 
2783ff48bf5SDavid du Colombier /*
2793ff48bf5SDavid du Colombier  *  pcap trace header
2803ff48bf5SDavid du Colombier  */
2813ff48bf5SDavid du Colombier void
2823ff48bf5SDavid du Colombier pcaphdr(void)
2833ff48bf5SDavid du Colombier {
2843ff48bf5SDavid du Colombier 	struct pcap_file_header hdr;
2853ff48bf5SDavid du Colombier 
2863ff48bf5SDavid du Colombier 	hdr.magic = TCPDUMP_MAGIC;
2873ff48bf5SDavid du Colombier 	hdr.version_major = PCAP_VERSION_MAJOR;
2883ff48bf5SDavid du Colombier 	hdr.version_minor = PCAP_VERSION_MINOR;
2893ff48bf5SDavid du Colombier 
2903ff48bf5SDavid du Colombier 	hdr.thiszone = 0;
2913ff48bf5SDavid du Colombier 	hdr.snaplen = 1500;
2923ff48bf5SDavid du Colombier 	hdr.sigfigs = 0;
2933ff48bf5SDavid du Colombier 	hdr.linktype = 1;
2943ff48bf5SDavid du Colombier 
2953ff48bf5SDavid du Colombier 	write(1, &hdr, sizeof(hdr));
2963ff48bf5SDavid du Colombier }
2973ff48bf5SDavid du Colombier 
2983ff48bf5SDavid du Colombier /*
2999a747e4fSDavid du Colombier  *  write out a packet trace
3009a747e4fSDavid du Colombier  */
3019a747e4fSDavid du Colombier void
3029a747e4fSDavid du Colombier tracepkt(uchar *ps, int len)
3039a747e4fSDavid du Colombier {
3043ff48bf5SDavid du Colombier 	struct pcap_pkthdr *goo;
3053ff48bf5SDavid du Colombier 
3063ff48bf5SDavid du Colombier 	if(pcap){
3073ff48bf5SDavid du Colombier 		goo = (struct pcap_pkthdr*)(ps-16);
3083ff48bf5SDavid du Colombier 		goo->ts = pkttime;
3093ff48bf5SDavid du Colombier 		goo->caplen = len;
3103ff48bf5SDavid du Colombier 		goo->len = len;
3113ff48bf5SDavid du Colombier 		write(1, goo, len+16);
3123ff48bf5SDavid du Colombier 	} else {
3139a747e4fSDavid du Colombier 		hnputs(ps-10, len);
3149a747e4fSDavid du Colombier 		hnputl(ps-8, pkttime>>32);
3159a747e4fSDavid du Colombier 		hnputl(ps-4, pkttime);
3169a747e4fSDavid du Colombier 		write(1, ps-10, len+10);
3179a747e4fSDavid du Colombier 	}
3183ff48bf5SDavid du Colombier }
3199a747e4fSDavid du Colombier 
3209a747e4fSDavid du Colombier /*
3219a747e4fSDavid du Colombier  *  format and print a packet
3229a747e4fSDavid du Colombier  */
3239a747e4fSDavid du Colombier void
3249a747e4fSDavid du Colombier printpkt(char *p, char *e, uchar *ps, uchar *pe)
3259a747e4fSDavid du Colombier {
3269a747e4fSDavid du Colombier 	Msg m;
3279a747e4fSDavid du Colombier 	ulong dt;
3289a747e4fSDavid du Colombier 
3299a747e4fSDavid du Colombier 	dt = (pkttime-starttime)/1000000LL;
3309a747e4fSDavid du Colombier 	m.p = seprint(p, e, "%6.6uld ms ", dt);
3319a747e4fSDavid du Colombier 	m.ps = ps;
3329a747e4fSDavid du Colombier 	m.pe = pe;
3339a747e4fSDavid du Colombier 	m.e = e;
3349a747e4fSDavid du Colombier 	m.pr = root;
3359a747e4fSDavid du Colombier 	while(m.p < m.e){
3369a747e4fSDavid du Colombier 		if(!sflag)
3379a747e4fSDavid du Colombier 			m.p = seprint(m.p, m.e, "\n\t");
3389a747e4fSDavid du Colombier 		m.p = seprint(m.p, m.e, "%s(", m.pr->name);
3399a747e4fSDavid du Colombier 		if((*m.pr->seprint)(&m) < 0){
3409a747e4fSDavid du Colombier 			m.p = seprint(m.p, m.e, "TOO SHORT");
3419a747e4fSDavid du Colombier 			m.ps = m.pe;
3429a747e4fSDavid du Colombier 		}
3439a747e4fSDavid du Colombier 		m.p = seprint(m.p, m.e, ")");
3449a747e4fSDavid du Colombier 		if(m.pr == nil || m.ps >= m.pe)
3459a747e4fSDavid du Colombier 			break;
3469a747e4fSDavid du Colombier 	}
3479a747e4fSDavid du Colombier 	*m.p++ = '\n';
3489a747e4fSDavid du Colombier 
3499a747e4fSDavid du Colombier 	if(write(1, p, m.p - p) < 0)
3509a747e4fSDavid du Colombier 		sysfatal("stdout: %r");
3519a747e4fSDavid du Colombier }
3529a747e4fSDavid du Colombier 
3539a747e4fSDavid du Colombier Proto **xprotos;
3549a747e4fSDavid du Colombier int nprotos;
3559a747e4fSDavid du Colombier 
3569a747e4fSDavid du Colombier /* look up a protocol by its name */
3579a747e4fSDavid du Colombier Proto*
3589a747e4fSDavid du Colombier findproto(char *name)
3599a747e4fSDavid du Colombier {
3609a747e4fSDavid du Colombier 	int i;
3619a747e4fSDavid du Colombier 
3629a747e4fSDavid du Colombier 	for(i = 0; i < nprotos; i++)
3639a747e4fSDavid du Colombier 		if(strcmp(xprotos[i]->name, name) == 0)
3649a747e4fSDavid du Colombier 			return xprotos[i];
3659a747e4fSDavid du Colombier 	return nil;
3669a747e4fSDavid du Colombier }
3679a747e4fSDavid du Colombier 
3689a747e4fSDavid du Colombier /*
3699a747e4fSDavid du Colombier  *  add an undefined protocol to protos[]
3709a747e4fSDavid du Colombier  */
3719a747e4fSDavid du Colombier Proto*
3729a747e4fSDavid du Colombier addproto(char *name)
3739a747e4fSDavid du Colombier {
3749a747e4fSDavid du Colombier 	Proto *pr;
3759a747e4fSDavid du Colombier 
3769a747e4fSDavid du Colombier 	xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*));
3779a747e4fSDavid du Colombier 	pr = malloc(sizeof *pr);
3789a747e4fSDavid du Colombier 	*pr = dump;
3799a747e4fSDavid du Colombier 	pr->name = name;
3809a747e4fSDavid du Colombier 	xprotos[nprotos++] = pr;
3819a747e4fSDavid du Colombier 	return pr;
3829a747e4fSDavid du Colombier }
3839a747e4fSDavid du Colombier 
3849a747e4fSDavid du Colombier /*
3859a747e4fSDavid du Colombier  *  build a graph of protocols, this could easily be circular.  This
3869a747e4fSDavid du Colombier  *  links together all the multiplexing in the protocol modules.
3879a747e4fSDavid du Colombier  */
3889a747e4fSDavid du Colombier void
3899a747e4fSDavid du Colombier mkprotograph(void)
3909a747e4fSDavid du Colombier {
3919a747e4fSDavid du Colombier 	Proto **l;
3929a747e4fSDavid du Colombier 	Proto *pr;
3939a747e4fSDavid du Colombier 	Mux *m;
3949a747e4fSDavid du Colombier 
3959a747e4fSDavid du Colombier 	/* copy protos into a reallocable area */
3969a747e4fSDavid du Colombier 	for(nprotos = 0; protos[nprotos] != nil; nprotos++)
3979a747e4fSDavid du Colombier 		;
3989a747e4fSDavid du Colombier 	xprotos = malloc(nprotos*sizeof(Proto*));
3999a747e4fSDavid du Colombier 	memmove(xprotos, protos, nprotos*sizeof(Proto*));
4009a747e4fSDavid du Colombier 
4019a747e4fSDavid du Colombier 	for(l = protos; *l != nil; l++){
4029a747e4fSDavid du Colombier 		pr = *l;
4039a747e4fSDavid du Colombier 		for(m = pr->mux; m != nil && m->name != nil; m++){
4049a747e4fSDavid du Colombier 			m->pr = findproto(m->name);
4059a747e4fSDavid du Colombier 			if(m->pr == nil)
4069a747e4fSDavid du Colombier 				m->pr = addproto(m->name);
4079a747e4fSDavid du Colombier 		}
4089a747e4fSDavid du Colombier 	}
4099a747e4fSDavid du Colombier }
4109a747e4fSDavid du Colombier 
4119a747e4fSDavid du Colombier /*
4129a747e4fSDavid du Colombier  *  add in a protocol node
4139a747e4fSDavid du Colombier  */
4149a747e4fSDavid du Colombier static Filter*
4159a747e4fSDavid du Colombier addnode(Filter *f, Proto *pr)
4169a747e4fSDavid du Colombier {
4179a747e4fSDavid du Colombier 	Filter *nf;
4189a747e4fSDavid du Colombier 	nf = newfilter();
4199a747e4fSDavid du Colombier 	nf->pr = pr;
4209a747e4fSDavid du Colombier 	nf->s = pr->name;
4219a747e4fSDavid du Colombier 	nf->l = f;
4229a747e4fSDavid du Colombier 	nf->op = WORD;
4239a747e4fSDavid du Colombier 	return nf;
4249a747e4fSDavid du Colombier }
4259a747e4fSDavid du Colombier 
4269a747e4fSDavid du Colombier /*
4279a747e4fSDavid du Colombier  *  recurse through the protocol graph adding missing nodes
4289a747e4fSDavid du Colombier  *  to the filter if we reach the filter's protocol
4299a747e4fSDavid du Colombier  */
4309a747e4fSDavid du Colombier static Filter*
4319a747e4fSDavid du Colombier _fillin(Filter *f, Proto *last, int depth)
4329a747e4fSDavid du Colombier {
4339a747e4fSDavid du Colombier 	Mux *m;
4349a747e4fSDavid du Colombier 	Filter *nf;
4359a747e4fSDavid du Colombier 
4369a747e4fSDavid du Colombier 	if(depth-- <= 0)
4379a747e4fSDavid du Colombier 		return nil;
4389a747e4fSDavid du Colombier 
4399a747e4fSDavid du Colombier 	for(m = last->mux; m != nil && m->name != nil; m++){
4409a747e4fSDavid du Colombier 		if(m->pr == nil)
4419a747e4fSDavid du Colombier 			continue;
4429a747e4fSDavid du Colombier 		if(f->pr == m->pr)
4439a747e4fSDavid du Colombier 			return f;
4449a747e4fSDavid du Colombier 		nf = _fillin(f, m->pr, depth);
4459a747e4fSDavid du Colombier 		if(nf != nil)
4469a747e4fSDavid du Colombier 			return addnode(nf, m->pr);
4479a747e4fSDavid du Colombier 	}
4489a747e4fSDavid du Colombier 	return nil;
4499a747e4fSDavid du Colombier }
4509a747e4fSDavid du Colombier 
4519a747e4fSDavid du Colombier static Filter*
4529a747e4fSDavid du Colombier fillin(Filter *f, Proto *last)
4539a747e4fSDavid du Colombier {
4549a747e4fSDavid du Colombier 	int i;
4559a747e4fSDavid du Colombier 	Filter *nf;
4569a747e4fSDavid du Colombier 
4579a747e4fSDavid du Colombier 	/* hack to make sure top level node is the root */
4589a747e4fSDavid du Colombier 	if(last == nil){
4599a747e4fSDavid du Colombier 		if(f->pr == root)
4609a747e4fSDavid du Colombier 			return f;
4619a747e4fSDavid du Colombier 		f = fillin(f, root);
4629a747e4fSDavid du Colombier 		if(f == nil)
4639a747e4fSDavid du Colombier 			return nil;
4649a747e4fSDavid du Colombier 		return addnode(f, root);
4659a747e4fSDavid du Colombier 	}
4669a747e4fSDavid du Colombier 
4679a747e4fSDavid du Colombier 	/* breadth first search though the protocol graph */
4689a747e4fSDavid du Colombier 	nf = f;
4699a747e4fSDavid du Colombier 	for(i = 1; i < 20; i++){
4709a747e4fSDavid du Colombier 		nf = _fillin(f, last, i);
4719a747e4fSDavid du Colombier 		if(nf != nil)
4729a747e4fSDavid du Colombier 			break;
4739a747e4fSDavid du Colombier 	}
4749a747e4fSDavid du Colombier 	return nf;
4759a747e4fSDavid du Colombier }
4769a747e4fSDavid du Colombier 
4779a747e4fSDavid du Colombier /*
4789a747e4fSDavid du Colombier  *  massage tree so that all paths from the root to a leaf
4799a747e4fSDavid du Colombier  *  contain a filter node for each header.
4809a747e4fSDavid du Colombier  *
4819a747e4fSDavid du Colombier  *  also, set f->pr where possible
4829a747e4fSDavid du Colombier  */
4839a747e4fSDavid du Colombier Filter*
4849a747e4fSDavid du Colombier complete(Filter *f, Proto *last)
4859a747e4fSDavid du Colombier {
4869a747e4fSDavid du Colombier 	Proto *pr;
4879a747e4fSDavid du Colombier 
4889a747e4fSDavid du Colombier 	if(f == nil)
4899a747e4fSDavid du Colombier 		return f;
4909a747e4fSDavid du Colombier 
4919a747e4fSDavid du Colombier 	/* do a depth first traversal of the filter tree */
4929a747e4fSDavid du Colombier 	switch(f->op){
493*6b6b9ac8SDavid du Colombier 	case '!':
494*6b6b9ac8SDavid du Colombier 		f->l = complete(f->l, last);
495*6b6b9ac8SDavid du Colombier 		break;
4969a747e4fSDavid du Colombier 	case LAND:
4979a747e4fSDavid du Colombier 	case LOR:
4989a747e4fSDavid du Colombier 		f->l = complete(f->l, last);
4999a747e4fSDavid du Colombier 		f->r = complete(f->r, last);
5009a747e4fSDavid du Colombier 		break;
5019a747e4fSDavid du Colombier 	case '=':
5029a747e4fSDavid du Colombier 		break;
5039a747e4fSDavid du Colombier 	case WORD:
5049a747e4fSDavid du Colombier 		pr = findproto(f->s);
5059a747e4fSDavid du Colombier 		f->pr = pr;
5069a747e4fSDavid du Colombier 		if(pr == nil){
5079a747e4fSDavid du Colombier 			if(f->l != nil){
5089a747e4fSDavid du Colombier 				fprint(2, "%s unknown proto, ignoring params\n",
5099a747e4fSDavid du Colombier 					f->s);
5109a747e4fSDavid du Colombier 				f->l = nil;
5119a747e4fSDavid du Colombier 			}
5129a747e4fSDavid du Colombier 		} else {
5139a747e4fSDavid du Colombier 			f->l = complete(f->l, pr);
5149a747e4fSDavid du Colombier 			f = fillin(f, last);
5159a747e4fSDavid du Colombier 			if(f == nil)
5169a747e4fSDavid du Colombier 				sysfatal("internal error: can't get to %s", pr->name);
5179a747e4fSDavid du Colombier 		}
5189a747e4fSDavid du Colombier 		break;
5199a747e4fSDavid du Colombier 	}
5209a747e4fSDavid du Colombier 	return f;
5219a747e4fSDavid du Colombier }
5229a747e4fSDavid du Colombier 
5239a747e4fSDavid du Colombier /*
5249a747e4fSDavid du Colombier  *  merge common nodes under | and & moving the merged node
5259a747e4fSDavid du Colombier  *  above the | or &.
5269a747e4fSDavid du Colombier  *
5279a747e4fSDavid du Colombier  *  do some constant foldong, e.g. `true & x' becomes x and
5289a747e4fSDavid du Colombier  *  'true | x' becomes true.
5299a747e4fSDavid du Colombier  */
5309a747e4fSDavid du Colombier static int changed;
5319a747e4fSDavid du Colombier 
5329a747e4fSDavid du Colombier static Filter*
5339a747e4fSDavid du Colombier _optimize(Filter *f)
5349a747e4fSDavid du Colombier {
5359a747e4fSDavid du Colombier 	Filter *l;
5369a747e4fSDavid du Colombier 
5379a747e4fSDavid du Colombier 	if(f == nil)
5389a747e4fSDavid du Colombier 		return f;
5399a747e4fSDavid du Colombier 
5409a747e4fSDavid du Colombier 	switch(f->op){
541*6b6b9ac8SDavid du Colombier 	case '!':
542*6b6b9ac8SDavid du Colombier 		/* is child also a not */
543*6b6b9ac8SDavid du Colombier 		if(f->l->op == '!'){
544*6b6b9ac8SDavid du Colombier 			changed = 1;
545*6b6b9ac8SDavid du Colombier 			return f->l->l;
546*6b6b9ac8SDavid du Colombier 		}
547*6b6b9ac8SDavid du Colombier 		break;
5489a747e4fSDavid du Colombier 	case LOR:
5499a747e4fSDavid du Colombier 		/* are two children the same protocol? */
5509a747e4fSDavid du Colombier 		if(f->l->op != f->r->op || f->r->op != WORD
5519a747e4fSDavid du Colombier 		|| f->l->pr != f->r->pr || f->l->pr == nil)
5529a747e4fSDavid du Colombier 			break;	/* no optimization */
5539a747e4fSDavid du Colombier 
5549a747e4fSDavid du Colombier 		changed = 1;
5559a747e4fSDavid du Colombier 
5569a747e4fSDavid du Colombier 		/* constant folding */
5579a747e4fSDavid du Colombier 		/* if either child is childless, just return that */
5589a747e4fSDavid du Colombier 		if(f->l->l == nil)
5599a747e4fSDavid du Colombier 			return f->l;
5609a747e4fSDavid du Colombier 		else if(f->r->l == nil)
5619a747e4fSDavid du Colombier 			return f->r;
5629a747e4fSDavid du Colombier 
5639a747e4fSDavid du Colombier 		/* move the common node up, thow away one node */
5649a747e4fSDavid du Colombier 		l = f->l;
5659a747e4fSDavid du Colombier 		f->l = l->l;
5669a747e4fSDavid du Colombier 		f->r = f->r->l;
5679a747e4fSDavid du Colombier 		l->l = f;
5689a747e4fSDavid du Colombier 		return l;
5699a747e4fSDavid du Colombier 	case LAND:
5709a747e4fSDavid du Colombier 		/* are two children the same protocol? */
5719a747e4fSDavid du Colombier 		if(f->l->op != f->r->op || f->r->op != WORD
5729a747e4fSDavid du Colombier 		|| f->l->pr != f->r->pr || f->l->pr == nil)
5739a747e4fSDavid du Colombier 			break;	/* no optimization */
5749a747e4fSDavid du Colombier 
5759a747e4fSDavid du Colombier 		changed = 1;
5769a747e4fSDavid du Colombier 
5779a747e4fSDavid du Colombier 		/* constant folding */
5789a747e4fSDavid du Colombier 		/* if either child is childless, ignore it */
5799a747e4fSDavid du Colombier 		if(f->l->l == nil)
5809a747e4fSDavid du Colombier 			return f->r;
5819a747e4fSDavid du Colombier 		else if(f->r->l == nil)
5829a747e4fSDavid du Colombier 			return f->l;
5839a747e4fSDavid du Colombier 
5849a747e4fSDavid du Colombier 		/* move the common node up, thow away one node */
5859a747e4fSDavid du Colombier 		l = f->l;
5869a747e4fSDavid du Colombier 		f->l = _optimize(l->l);
5879a747e4fSDavid du Colombier 		f->r = _optimize(f->r->l);
5889a747e4fSDavid du Colombier 		l->l = f;
5899a747e4fSDavid du Colombier 		return l;
5909a747e4fSDavid du Colombier 	}
5919a747e4fSDavid du Colombier 	f->l = _optimize(f->l);
5929a747e4fSDavid du Colombier 	f->r = _optimize(f->r);
5939a747e4fSDavid du Colombier 	return f;
5949a747e4fSDavid du Colombier }
5959a747e4fSDavid du Colombier 
5969a747e4fSDavid du Colombier Filter*
5979a747e4fSDavid du Colombier optimize(Filter *f)
5989a747e4fSDavid du Colombier {
5999a747e4fSDavid du Colombier 	do{
6009a747e4fSDavid du Colombier 		changed = 0;
6019a747e4fSDavid du Colombier 		f = _optimize(f);
6029a747e4fSDavid du Colombier 	}while(changed);
6039a747e4fSDavid du Colombier 
6049a747e4fSDavid du Colombier 	return f;
6059a747e4fSDavid du Colombier }
6069a747e4fSDavid du Colombier 
6079a747e4fSDavid du Colombier /*
6089a747e4fSDavid du Colombier  *  find any top level nodes that aren't the root
6099a747e4fSDavid du Colombier  */
610*6b6b9ac8SDavid du Colombier int
6119a747e4fSDavid du Colombier findbogus(Filter *f)
6129a747e4fSDavid du Colombier {
613*6b6b9ac8SDavid du Colombier 	int rv;
614*6b6b9ac8SDavid du Colombier 
6159a747e4fSDavid du Colombier 	if(f->op != WORD){
616*6b6b9ac8SDavid du Colombier 		rv = findbogus(f->l);
617*6b6b9ac8SDavid du Colombier 		if(f->r)
618*6b6b9ac8SDavid du Colombier 			rv |= findbogus(f->r);
619*6b6b9ac8SDavid du Colombier 		return rv;
620*6b6b9ac8SDavid du Colombier 	} else if(f->pr != root){
621*6b6b9ac8SDavid du Colombier 		fprint(2, "bad top-level protocol: %s\n", f->s);
622*6b6b9ac8SDavid du Colombier 		return 1;
623*6b6b9ac8SDavid du Colombier 	}
624*6b6b9ac8SDavid du Colombier 	return 0;
6259a747e4fSDavid du Colombier }
6269a747e4fSDavid du Colombier 
6279a747e4fSDavid du Colombier /*
6289a747e4fSDavid du Colombier  *  compile the filter
6299a747e4fSDavid du Colombier  */
6309a747e4fSDavid du Colombier static void
6319a747e4fSDavid du Colombier _compile(Filter *f, Proto *last)
6329a747e4fSDavid du Colombier {
6339a747e4fSDavid du Colombier 	if(f == nil)
6349a747e4fSDavid du Colombier 		return;
6359a747e4fSDavid du Colombier 
6369a747e4fSDavid du Colombier 	switch(f->op){
637*6b6b9ac8SDavid du Colombier 	case '!':
638*6b6b9ac8SDavid du Colombier 		_compile(f->l, last);
639*6b6b9ac8SDavid du Colombier 		break;
6409a747e4fSDavid du Colombier 	case LOR:
6419a747e4fSDavid du Colombier 	case LAND:
6429a747e4fSDavid du Colombier 		_compile(f->l, last);
6439a747e4fSDavid du Colombier 		_compile(f->r, last);
6449a747e4fSDavid du Colombier 		break;
6459a747e4fSDavid du Colombier 	case WORD:
6469a747e4fSDavid du Colombier 		if(last != nil)
6479a747e4fSDavid du Colombier 			(*last->compile)(f);
6489a747e4fSDavid du Colombier 		if(f->l)
6499a747e4fSDavid du Colombier 			_compile(f->l, f->pr);
6509a747e4fSDavid du Colombier 		break;
6519a747e4fSDavid du Colombier 	case '=':
6529a747e4fSDavid du Colombier 		if(last == nil)
6539a747e4fSDavid du Colombier 			sysfatal("internal error: compilewalk: badly formed tree");
6549a747e4fSDavid du Colombier 		(*last->compile)(f);
6559a747e4fSDavid du Colombier 		break;
6569a747e4fSDavid du Colombier 	default:
6579a747e4fSDavid du Colombier 		sysfatal("internal error: compilewalk op: %d", f->op);
6589a747e4fSDavid du Colombier 	}
6599a747e4fSDavid du Colombier }
6609a747e4fSDavid du Colombier 
6619a747e4fSDavid du Colombier Filter*
6629a747e4fSDavid du Colombier compile(Filter *f)
6639a747e4fSDavid du Colombier {
6649a747e4fSDavid du Colombier 	if(f == nil)
6659a747e4fSDavid du Colombier 		return f;
6669a747e4fSDavid du Colombier 
6679a747e4fSDavid du Colombier 	/* fill in the missing header filters */
6689a747e4fSDavid du Colombier 	f = complete(f, nil);
6699a747e4fSDavid du Colombier 
6709a747e4fSDavid du Colombier 	/* constant folding */
6719a747e4fSDavid du Colombier 	f = optimize(f);
6723ff48bf5SDavid du Colombier 	if(!toflag)
6739a747e4fSDavid du Colombier 		printfilter(f, "after optimize");
6749a747e4fSDavid du Colombier 
6759a747e4fSDavid du Colombier 	/* protocol specific compilations */
6769a747e4fSDavid du Colombier 	_compile(f, nil);
6779a747e4fSDavid du Colombier 
6789a747e4fSDavid du Colombier 	/* at this point, the root had better be the root proto */
679*6b6b9ac8SDavid du Colombier 	if(findbogus(f)){
680*6b6b9ac8SDavid du Colombier 		fprint(2, "bogus filter\n");
681*6b6b9ac8SDavid du Colombier 		exits("bad filter");
6829a747e4fSDavid du Colombier 	}
683*6b6b9ac8SDavid du Colombier 
684*6b6b9ac8SDavid du Colombier 	return f;
6859a747e4fSDavid du Colombier }
6869a747e4fSDavid du Colombier 
6879a747e4fSDavid du Colombier /*
6889a747e4fSDavid du Colombier  *  parse a byte array
6899a747e4fSDavid du Colombier  */
6909a747e4fSDavid du Colombier int
6919a747e4fSDavid du Colombier parseba(uchar *to, char *from)
6929a747e4fSDavid du Colombier {
6939a747e4fSDavid du Colombier 	char nip[4];
6949a747e4fSDavid du Colombier 	char *p;
6959a747e4fSDavid du Colombier 	int i;
6969a747e4fSDavid du Colombier 
6979a747e4fSDavid du Colombier 	p = from;
6989a747e4fSDavid du Colombier 	for(i = 0; i < 16; i++){
6999a747e4fSDavid du Colombier 		if(*p == 0)
7009a747e4fSDavid du Colombier 			return -1;
7019a747e4fSDavid du Colombier 		nip[0] = *p++;
7029a747e4fSDavid du Colombier 		if(*p == 0)
7039a747e4fSDavid du Colombier 			return -1;
7049a747e4fSDavid du Colombier 		nip[1] = *p++;
7059a747e4fSDavid du Colombier 		nip[2] = 0;
7069a747e4fSDavid du Colombier 		to[i] = strtoul(nip, 0, 16);
7079a747e4fSDavid du Colombier 	}
7089a747e4fSDavid du Colombier 	return i;
7099a747e4fSDavid du Colombier }
7109a747e4fSDavid du Colombier 
7119a747e4fSDavid du Colombier /*
7129a747e4fSDavid du Colombier  *  compile WORD = WORD, becomes a single node with a subop
7139a747e4fSDavid du Colombier  */
7149a747e4fSDavid du Colombier void
7159a747e4fSDavid du Colombier compile_cmp(char *proto, Filter *f, Field *fld)
7169a747e4fSDavid du Colombier {
7179a747e4fSDavid du Colombier 	uchar x[IPaddrlen];
7189a747e4fSDavid du Colombier 
7199a747e4fSDavid du Colombier 	if(f->op != '=')
7209a747e4fSDavid du Colombier 		sysfatal("internal error: compile_cmp %s: not a cmp", proto);
7219a747e4fSDavid du Colombier 
7229a747e4fSDavid du Colombier 	for(; fld->name != nil; fld++){
7239a747e4fSDavid du Colombier 		if(strcmp(f->l->s, fld->name) == 0){
7249a747e4fSDavid du Colombier 			f->op = WORD;
7259a747e4fSDavid du Colombier 			f->subop = fld->subop;
7269a747e4fSDavid du Colombier 			switch(fld->ftype){
7279a747e4fSDavid du Colombier 			case Fnum:
7289a747e4fSDavid du Colombier 				f->ulv = atoi(f->r->s);
7299a747e4fSDavid du Colombier 				break;
7309a747e4fSDavid du Colombier 			case Fether:
7319a747e4fSDavid du Colombier 				parseether(f->a, f->r->s);
7329a747e4fSDavid du Colombier 				break;
7339a747e4fSDavid du Colombier 			case Fv4ip:
7349a747e4fSDavid du Colombier 				f->ulv = parseip(x, f->r->s);
7359a747e4fSDavid du Colombier 				break;
7369a747e4fSDavid du Colombier 			case Fv6ip:
7379a747e4fSDavid du Colombier 				parseip(f->a, f->r->s);
7389a747e4fSDavid du Colombier 				break;
7399a747e4fSDavid du Colombier 			case Fba:
7409a747e4fSDavid du Colombier 				parseba(f->a, f->r->s);
7419a747e4fSDavid du Colombier 				break;
7429a747e4fSDavid du Colombier 			default:
7439a747e4fSDavid du Colombier 				sysfatal("internal error: compile_cmp %s: %d",
7449a747e4fSDavid du Colombier 					proto, fld->ftype);
7459a747e4fSDavid du Colombier 			}
7469a747e4fSDavid du Colombier 			f->l = f->r = nil;
7479a747e4fSDavid du Colombier 			return;
7489a747e4fSDavid du Colombier 		}
7499a747e4fSDavid du Colombier 	}
7509a747e4fSDavid du Colombier 	sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s);
7519a747e4fSDavid du Colombier }
7529a747e4fSDavid du Colombier 
7539a747e4fSDavid du Colombier void
7549a747e4fSDavid du Colombier _pf(Filter *f)
7559a747e4fSDavid du Colombier {
756*6b6b9ac8SDavid du Colombier 	char *s;
757*6b6b9ac8SDavid du Colombier 
7589a747e4fSDavid du Colombier 	if(f == nil)
7599a747e4fSDavid du Colombier 		return;
7609a747e4fSDavid du Colombier 
761*6b6b9ac8SDavid du Colombier 	s = nil;
7629a747e4fSDavid du Colombier 	switch(f->op){
763*6b6b9ac8SDavid du Colombier 	case '!':
764*6b6b9ac8SDavid du Colombier 		fprint(2, "!");
7659a747e4fSDavid du Colombier 		_pf(f->l);
766*6b6b9ac8SDavid du Colombier 		break;
767*6b6b9ac8SDavid du Colombier 	case WORD:
768*6b6b9ac8SDavid du Colombier 		fprint(2, "%s", f->s);
769*6b6b9ac8SDavid du Colombier 		if(f->l != nil){
770*6b6b9ac8SDavid du Colombier 			fprint(2, "( ");
771*6b6b9ac8SDavid du Colombier 			_pf(f->l);
772*6b6b9ac8SDavid du Colombier 			fprint(2, " )");
7739a747e4fSDavid du Colombier 		}
7749a747e4fSDavid du Colombier 		break;
7759a747e4fSDavid du Colombier 	case LAND:
776*6b6b9ac8SDavid du Colombier 		s = "&&";
777*6b6b9ac8SDavid du Colombier 		goto print;
7789a747e4fSDavid du Colombier 	case LOR:
779*6b6b9ac8SDavid du Colombier 		s = "||";
780*6b6b9ac8SDavid du Colombier 		goto print;
7819a747e4fSDavid du Colombier 	case '=':
782*6b6b9ac8SDavid du Colombier 	print:
7839a747e4fSDavid du Colombier 		_pf(f->l);
784*6b6b9ac8SDavid du Colombier 		if(s)
785*6b6b9ac8SDavid du Colombier 			fprint(2, " %s ", s);
786*6b6b9ac8SDavid du Colombier 		else
787*6b6b9ac8SDavid du Colombier 			fprint(2, " %c ", f->op);
7889a747e4fSDavid du Colombier 		_pf(f->r);
7899a747e4fSDavid du Colombier 		break;
7909a747e4fSDavid du Colombier 	default:
791*6b6b9ac8SDavid du Colombier 		fprint(2, "???");
7929a747e4fSDavid du Colombier 		break;
7939a747e4fSDavid du Colombier 	}
7949a747e4fSDavid du Colombier }
7959a747e4fSDavid du Colombier 
7969a747e4fSDavid du Colombier void
7979a747e4fSDavid du Colombier printfilter(Filter *f, char *tag)
7989a747e4fSDavid du Colombier {
799*6b6b9ac8SDavid du Colombier 	fprint(2, "%s: ", tag);
8009a747e4fSDavid du Colombier 	_pf(f);
801*6b6b9ac8SDavid du Colombier 	fprint(2, "\n");
8029a747e4fSDavid du Colombier }
8039a747e4fSDavid du Colombier 
8049a747e4fSDavid du Colombier void
8059a747e4fSDavid du Colombier printhelp(void)
8069a747e4fSDavid du Colombier {
8079a747e4fSDavid du Colombier 	Proto *pr, **l;
8089a747e4fSDavid du Colombier 	Mux *m;
8099a747e4fSDavid du Colombier 	Field *f;
8109a747e4fSDavid du Colombier 
8119a747e4fSDavid du Colombier 	for(l = protos; *l != nil; l++){
8129a747e4fSDavid du Colombier 		pr = *l;
8139a747e4fSDavid du Colombier 		if(pr->field != nil){
8149a747e4fSDavid du Colombier 			print("%s's filter attr:\n", pr->name);
8159a747e4fSDavid du Colombier 			for(f = pr->field; f->name != nil; f++)
8169a747e4fSDavid du Colombier 				print("\t%s\t- %s\n", f->name, f->help);
8179a747e4fSDavid du Colombier 		}
8189a747e4fSDavid du Colombier 		if(pr->mux != nil){
8199a747e4fSDavid du Colombier 			print("%s's subprotos:\n", pr->name);
8209a747e4fSDavid du Colombier 			for(m = pr->mux; m->name != nil; m++)
8219a747e4fSDavid du Colombier 				print("\t%s\n", m->name);
8229a747e4fSDavid du Colombier 		}
8239a747e4fSDavid du Colombier 	}
8249a747e4fSDavid du Colombier }
8259a747e4fSDavid du Colombier 
8269a747e4fSDavid du Colombier /*
8279a747e4fSDavid du Colombier  *  demultiplex to next prototol header
8289a747e4fSDavid du Colombier  */
8299a747e4fSDavid du Colombier void
8309a747e4fSDavid du Colombier demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def)
8319a747e4fSDavid du Colombier {
8329a747e4fSDavid du Colombier 	m->pr = def;
8339a747e4fSDavid du Colombier 	for(mx = mx; mx->name != nil; mx++){
8349a747e4fSDavid du Colombier 		if(val1 == mx->val || val2 == mx->val){
8359a747e4fSDavid du Colombier 			m->pr = mx->pr;
8369a747e4fSDavid du Colombier 			break;
8379a747e4fSDavid du Colombier 		}
8389a747e4fSDavid du Colombier 	}
8399a747e4fSDavid du Colombier }
8403ff48bf5SDavid du Colombier 
8413ff48bf5SDavid du Colombier /*
8423ff48bf5SDavid du Colombier  *  default framer just assumes the input packet is
8433ff48bf5SDavid du Colombier  *  a single read
8443ff48bf5SDavid du Colombier  */
8453ff48bf5SDavid du Colombier int
8463ff48bf5SDavid du Colombier defaultframer(int fd, uchar *pkt, int pktlen)
8473ff48bf5SDavid du Colombier {
8483ff48bf5SDavid du Colombier 	return read(fd, pkt, pktlen);
8493ff48bf5SDavid du Colombier }
850