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 uvlong ts; /* time stamp */
290 ulong caplen; /* length of portion present */
291 ulong len; /* length this packet (off wire) */
292 };
293
294 /*
295 * pcap trace header
296 */
297 void
pcaphdr(void)298 pcaphdr(void)
299 {
300 struct pcap_file_header hdr;
301
302 hdr.magic = TCPDUMP_MAGIC;
303 hdr.version_major = PCAP_VERSION_MAJOR;
304 hdr.version_minor = PCAP_VERSION_MINOR;
305
306 hdr.thiszone = 0;
307 hdr.snaplen = 1500;
308 hdr.sigfigs = 0;
309 hdr.linktype = 1;
310
311 write(1, &hdr, sizeof(hdr));
312 }
313
314 /*
315 * write out a packet trace
316 */
317 void
tracepkt(uchar * ps,int len)318 tracepkt(uchar *ps, int len)
319 {
320 struct pcap_pkthdr *goo;
321
322 if(Mflag && len > Mflag)
323 len = Mflag;
324 if(pcap){
325 goo = (struct pcap_pkthdr*)(ps-16);
326 goo->ts = pkttime;
327 goo->caplen = len;
328 goo->len = len;
329 write(1, goo, len+16);
330 } else {
331 hnputs(ps-10, len);
332 hnputl(ps-8, pkttime>>32);
333 hnputl(ps-4, pkttime);
334 write(1, ps-10, len+10);
335 }
336 }
337
338 /*
339 * format and print a packet
340 */
341 void
printpkt(char * p,char * e,uchar * ps,uchar * pe)342 printpkt(char *p, char *e, uchar *ps, uchar *pe)
343 {
344 Msg m;
345 ulong dt;
346
347 dt = (pkttime-starttime)/1000000LL;
348 m.p = seprint(p, e, "%6.6uld ms ", dt);
349 m.ps = ps;
350 m.pe = pe;
351 m.e = e;
352 m.pr = root;
353 while(m.p < m.e){
354 if(!sflag)
355 m.p = seprint(m.p, m.e, "\n\t");
356 m.p = seprint(m.p, m.e, "%s(", m.pr->name);
357 if((*m.pr->seprint)(&m) < 0){
358 m.p = seprint(m.p, m.e, "TOO SHORT");
359 m.ps = m.pe;
360 }
361 m.p = seprint(m.p, m.e, ")");
362 if(m.pr == nil || m.ps >= m.pe)
363 break;
364 }
365 *m.p++ = '\n';
366
367 if(write(1, p, m.p - p) < 0)
368 sysfatal("stdout: %r");
369 }
370
371 Proto **xprotos;
372 int nprotos;
373
374 /* look up a protocol by its name */
375 Proto*
findproto(char * name)376 findproto(char *name)
377 {
378 int i;
379
380 for(i = 0; i < nprotos; i++)
381 if(strcmp(xprotos[i]->name, name) == 0)
382 return xprotos[i];
383 return nil;
384 }
385
386 /*
387 * add an undefined protocol to protos[]
388 */
389 Proto*
addproto(char * name)390 addproto(char *name)
391 {
392 Proto *pr;
393
394 xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*));
395 pr = malloc(sizeof *pr);
396 *pr = dump;
397 pr->name = name;
398 xprotos[nprotos++] = pr;
399 return pr;
400 }
401
402 /*
403 * build a graph of protocols, this could easily be circular. This
404 * links together all the multiplexing in the protocol modules.
405 */
406 void
mkprotograph(void)407 mkprotograph(void)
408 {
409 Proto **l;
410 Proto *pr;
411 Mux *m;
412
413 /* copy protos into a reallocable area */
414 for(nprotos = 0; protos[nprotos] != nil; nprotos++)
415 ;
416 xprotos = malloc(nprotos*sizeof(Proto*));
417 memmove(xprotos, protos, nprotos*sizeof(Proto*));
418
419 for(l = protos; *l != nil; l++){
420 pr = *l;
421 for(m = pr->mux; m != nil && m->name != nil; m++){
422 m->pr = findproto(m->name);
423 if(m->pr == nil)
424 m->pr = addproto(m->name);
425 }
426 }
427 }
428
429 /*
430 * add in a protocol node
431 */
432 static Filter*
addnode(Filter * f,Proto * pr)433 addnode(Filter *f, Proto *pr)
434 {
435 Filter *nf;
436 nf = newfilter();
437 nf->pr = pr;
438 nf->s = pr->name;
439 nf->l = f;
440 nf->op = WORD;
441 return nf;
442 }
443
444 /*
445 * recurse through the protocol graph adding missing nodes
446 * to the filter if we reach the filter's protocol
447 */
448 static Filter*
_fillin(Filter * f,Proto * last,int depth)449 _fillin(Filter *f, Proto *last, int depth)
450 {
451 Mux *m;
452 Filter *nf;
453
454 if(depth-- <= 0)
455 return nil;
456
457 for(m = last->mux; m != nil && m->name != nil; m++){
458 if(m->pr == nil)
459 continue;
460 if(f->pr == m->pr)
461 return f;
462 nf = _fillin(f, m->pr, depth);
463 if(nf != nil)
464 return addnode(nf, m->pr);
465 }
466 return nil;
467 }
468
469 static Filter*
fillin(Filter * f,Proto * last)470 fillin(Filter *f, Proto *last)
471 {
472 int i;
473 Filter *nf;
474
475 /* hack to make sure top level node is the root */
476 if(last == nil){
477 if(f->pr == root)
478 return f;
479 f = fillin(f, root);
480 if(f == nil)
481 return nil;
482 return addnode(f, root);
483 }
484
485 /* breadth first search though the protocol graph */
486 nf = f;
487 for(i = 1; i < 20; i++){
488 nf = _fillin(f, last, i);
489 if(nf != nil)
490 break;
491 }
492 return nf;
493 }
494
495 /*
496 * massage tree so that all paths from the root to a leaf
497 * contain a filter node for each header.
498 *
499 * also, set f->pr where possible
500 */
501 Filter*
complete(Filter * f,Proto * last)502 complete(Filter *f, Proto *last)
503 {
504 Proto *pr;
505
506 if(f == nil)
507 return f;
508
509 /* do a depth first traversal of the filter tree */
510 switch(f->op){
511 case '!':
512 f->l = complete(f->l, last);
513 break;
514 case LAND:
515 case LOR:
516 f->l = complete(f->l, last);
517 f->r = complete(f->r, last);
518 break;
519 case '=':
520 break;
521 case WORD:
522 pr = findproto(f->s);
523 f->pr = pr;
524 if(pr == nil){
525 if(f->l != nil){
526 fprint(2, "%s unknown proto, ignoring params\n",
527 f->s);
528 f->l = nil;
529 }
530 } else {
531 f->l = complete(f->l, pr);
532 f = fillin(f, last);
533 if(f == nil)
534 sysfatal("internal error: can't get to %s", pr->name);
535 }
536 break;
537 }
538 return f;
539 }
540
541 /*
542 * merge common nodes under | and & moving the merged node
543 * above the | or &.
544 *
545 * do some constant foldong, e.g. `true & x' becomes x and
546 * 'true | x' becomes true.
547 */
548 static int changed;
549
550 static Filter*
_optimize(Filter * f)551 _optimize(Filter *f)
552 {
553 Filter *l;
554
555 if(f == nil)
556 return f;
557
558 switch(f->op){
559 case '!':
560 /* is child also a not */
561 if(f->l->op == '!'){
562 changed = 1;
563 return f->l->l;
564 }
565 break;
566 case LOR:
567 /* are two children the same protocol? */
568 if(f->l->op != f->r->op || f->r->op != WORD
569 || f->l->pr != f->r->pr || f->l->pr == nil)
570 break; /* no optimization */
571
572 changed = 1;
573
574 /* constant folding */
575 /* if either child is childless, just return that */
576 if(f->l->l == nil)
577 return f->l;
578 else if(f->r->l == nil)
579 return f->r;
580
581 /* move the common node up, thow away one node */
582 l = f->l;
583 f->l = l->l;
584 f->r = f->r->l;
585 l->l = f;
586 return l;
587 case LAND:
588 /* are two children the same protocol? */
589 if(f->l->op != f->r->op || f->r->op != WORD
590 || f->l->pr != f->r->pr || f->l->pr == nil)
591 break; /* no optimization */
592
593 changed = 1;
594
595 /* constant folding */
596 /* if either child is childless, ignore it */
597 if(f->l->l == nil)
598 return f->r;
599 else if(f->r->l == nil)
600 return f->l;
601
602 /* move the common node up, thow away one node */
603 l = f->l;
604 f->l = _optimize(l->l);
605 f->r = _optimize(f->r->l);
606 l->l = f;
607 return l;
608 }
609 f->l = _optimize(f->l);
610 f->r = _optimize(f->r);
611 return f;
612 }
613
614 Filter*
optimize(Filter * f)615 optimize(Filter *f)
616 {
617 do{
618 changed = 0;
619 f = _optimize(f);
620 }while(changed);
621
622 return f;
623 }
624
625 /*
626 * find any top level nodes that aren't the root
627 */
628 int
findbogus(Filter * f)629 findbogus(Filter *f)
630 {
631 int rv;
632
633 if(f->op != WORD){
634 rv = findbogus(f->l);
635 if(f->r)
636 rv |= findbogus(f->r);
637 return rv;
638 } else if(f->pr != root){
639 fprint(2, "bad top-level protocol: %s\n", f->s);
640 return 1;
641 }
642 return 0;
643 }
644
645 /*
646 * compile the filter
647 */
648 static void
_compile(Filter * f,Proto * last)649 _compile(Filter *f, Proto *last)
650 {
651 if(f == nil)
652 return;
653
654 switch(f->op){
655 case '!':
656 _compile(f->l, last);
657 break;
658 case LOR:
659 case LAND:
660 _compile(f->l, last);
661 _compile(f->r, last);
662 break;
663 case WORD:
664 if(last != nil){
665 if(last->compile == nil)
666 sysfatal("unknown %s subprotocol: %s", f->pr->name, f->s);
667 (*last->compile)(f);
668 }
669 if(f->l)
670 _compile(f->l, f->pr);
671 break;
672 case '=':
673 if(last == nil)
674 sysfatal("internal error: compilewalk: badly formed tree");
675
676 if(last->compile == nil)
677 sysfatal("unknown %s field: %s", f->pr->name, f->s);
678 (*last->compile)(f);
679 break;
680 default:
681 sysfatal("internal error: compilewalk op: %d", f->op);
682 }
683 }
684
685 Filter*
compile(Filter * f)686 compile(Filter *f)
687 {
688 if(f == nil)
689 return f;
690
691 /* fill in the missing header filters */
692 f = complete(f, nil);
693
694 /* constant folding */
695 f = optimize(f);
696 if(!toflag)
697 printfilter(f, "after optimize");
698
699 /* protocol specific compilations */
700 _compile(f, nil);
701
702 /* at this point, the root had better be the root proto */
703 if(findbogus(f)){
704 fprint(2, "bogus filter\n");
705 exits("bad filter");
706 }
707
708 return f;
709 }
710
711 /*
712 * parse a byte array
713 */
714 int
parseba(uchar * to,char * from)715 parseba(uchar *to, char *from)
716 {
717 char nip[4];
718 char *p;
719 int i;
720
721 p = from;
722 for(i = 0; i < 16; i++){
723 if(*p == 0)
724 return -1;
725 nip[0] = *p++;
726 if(*p == 0)
727 return -1;
728 nip[1] = *p++;
729 nip[2] = 0;
730 to[i] = strtoul(nip, 0, 16);
731 }
732 return i;
733 }
734
735 /*
736 * compile WORD = WORD, becomes a single node with a subop
737 */
738 void
compile_cmp(char * proto,Filter * f,Field * fld)739 compile_cmp(char *proto, Filter *f, Field *fld)
740 {
741 uchar x[IPaddrlen];
742 char *v;
743
744 if(f->op != '=')
745 sysfatal("internal error: compile_cmp %s: not a cmp", proto);
746
747 for(; fld->name != nil; fld++){
748 if(strcmp(f->l->s, fld->name) == 0){
749 f->op = WORD;
750 f->subop = fld->subop;
751 switch(fld->ftype){
752 case Fnum:
753 f->ulv = atoi(f->r->s);
754 break;
755 case Fether:
756 v = csgetvalue(nil, "sys", (char*)f->r->s,
757 "ether", 0);
758 if(v){
759 parseether(f->a, v);
760 free(v);
761 } else
762 parseether(f->a, f->r->s);
763 break;
764 case Fv4ip:
765 v = csgetvalue(nil, "sys", (char*)f->r->s,
766 "ip", 0);
767 if(v){
768 f->ulv = parseip(x, v);
769 free(v);
770 }else
771 f->ulv = parseip(x, f->r->s);
772 break;
773 case Fv6ip:
774 v = csgetvalue(nil, "sys", (char*)f->r->s,
775 "ipv6", 0);
776 if(v){
777 parseip(f->a, v);
778 free(v);
779 }else
780 parseip(f->a, f->r->s);
781 break;
782 case Fba:
783 parseba(f->a, f->r->s);
784 break;
785 default:
786 sysfatal("internal error: compile_cmp %s: %d",
787 proto, fld->ftype);
788 }
789 f->l = f->r = nil;
790 return;
791 }
792 }
793 sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s);
794 }
795
796 void
_pf(Filter * f)797 _pf(Filter *f)
798 {
799 char *s;
800
801 if(f == nil)
802 return;
803
804 s = nil;
805 switch(f->op){
806 case '!':
807 fprint(2, "!");
808 _pf(f->l);
809 break;
810 case WORD:
811 fprint(2, "%s", f->s);
812 if(f->l != nil){
813 fprint(2, "(");
814 _pf(f->l);
815 fprint(2, ")");
816 }
817 break;
818 case LAND:
819 s = "&&";
820 goto print;
821 case LOR:
822 s = "||";
823 goto print;
824 case '=':
825 print:
826 _pf(f->l);
827 if(s)
828 fprint(2, " %s ", s);
829 else
830 fprint(2, " %c ", f->op);
831 _pf(f->r);
832 break;
833 default:
834 fprint(2, "???");
835 break;
836 }
837 }
838
839 void
printfilter(Filter * f,char * tag)840 printfilter(Filter *f, char *tag)
841 {
842 fprint(2, "%s: ", tag);
843 _pf(f);
844 fprint(2, "\n");
845 }
846
847 void
cat(void)848 cat(void)
849 {
850 char buf[1024];
851 int n;
852
853 while((n = read(0, buf, sizeof buf)) > 0)
854 write(1, buf, n);
855 }
856
857 static int fd1 = -1;
858 void
startmc(void)859 startmc(void)
860 {
861 int p[2];
862
863 if(fd1 == -1)
864 fd1 = dup(1, -1);
865
866 if(pipe(p) < 0)
867 return;
868 switch(fork()){
869 case -1:
870 return;
871 default:
872 close(p[0]);
873 dup(p[1], 1);
874 if(p[1] != 1)
875 close(p[1]);
876 return;
877 case 0:
878 close(p[1]);
879 dup(p[0], 0);
880 if(p[0] != 0)
881 close(p[0]);
882 execl("/bin/mc", "mc", nil);
883 cat();
884 _exits(0);
885 }
886 }
887
888 void
stopmc(void)889 stopmc(void)
890 {
891 close(1);
892 dup(fd1, 1);
893 waitpid();
894 }
895
896 void
printhelp(char * name)897 printhelp(char *name)
898 {
899 int len;
900 Proto *pr, **l;
901 Mux *m;
902 Field *f;
903 char fmt[40];
904
905 if(name == nil){
906 print("protocols:\n");
907 startmc();
908 for(l=protos; (pr=*l) != nil; l++)
909 print(" %s\n", pr->name);
910 stopmc();
911 return;
912 }
913
914 pr = findproto(name);
915 if(pr == nil){
916 print("unknown protocol %s\n", name);
917 return;
918 }
919
920 if(pr->field){
921 print("%s's filter attributes:\n", pr->name);
922 len = 0;
923 for(f=pr->field; f->name; f++)
924 if(len < strlen(f->name))
925 len = strlen(f->name);
926 startmc();
927 for(f=pr->field; f->name; f++)
928 print(" %-*s - %s\n", len, f->name, f->help);
929 stopmc();
930 }
931 if(pr->mux){
932 print("%s's subprotos:\n", pr->name);
933 startmc();
934 snprint(fmt, sizeof fmt, " %s %%s\n", pr->valfmt);
935 for(m=pr->mux; m->name != nil; m++)
936 print(fmt, m->val, m->name);
937 stopmc();
938 }
939 }
940
941 /*
942 * demultiplex to next prototol header
943 */
944 void
demux(Mux * mx,ulong val1,ulong val2,Msg * m,Proto * def)945 demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def)
946 {
947 m->pr = def;
948 for(mx = mx; mx->name != nil; mx++){
949 if(val1 == mx->val || val2 == mx->val){
950 m->pr = mx->pr;
951 break;
952 }
953 }
954 }
955
956 /*
957 * default framer just assumes the input packet is
958 * a single read
959 */
960 int
defaultframer(int fd,uchar * pkt,int pktlen)961 defaultframer(int fd, uchar *pkt, int pktlen)
962 {
963 return read(fd, pkt, pktlen);
964 }
965