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