1/*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22/*
23 * txtproto_print() derived from original code by Hannes Gredler
24 * (hannes@juniper.net):
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that: (1) source code
28 * distributions retain the above copyright notice and this paragraph
29 * in its entirety, and (2) distributions including binary code include
30 * the above copyright notice and this paragraph in its entirety in
31 * the documentation or other materials provided with the distribution.
32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
33 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
34 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
36 */
37
38#define NETDISSECT_REWORKED
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42
43#include <tcpdump-stdinc.h>
44
45#include <sys/stat.h>
46
47#ifdef HAVE_FCNTL_H
48#include <fcntl.h>
49#endif
50#include <stdio.h>
51#include <stdarg.h>
52#include <stdlib.h>
53#include <string.h>
54
55#include "interface.h"
56
57/*
58 * Print out a null-terminated filename (or other ascii string).
59 * If ep is NULL, assume no truncation check is needed.
60 * Return true if truncated.
61 */
62int
63fn_print(netdissect_options *ndo,
64         register const u_char *s, register const u_char *ep)
65{
66	register int ret;
67	register u_char c;
68
69	ret = 1;			/* assume truncated */
70	while (ep == NULL || s < ep) {
71		c = *s++;
72		if (c == '\0') {
73			ret = 0;
74			break;
75		}
76		if (!ND_ISASCII(c)) {
77			c = ND_TOASCII(c);
78			ND_PRINT((ndo, "M-"));
79		}
80		if (!ND_ISPRINT(c)) {
81			c ^= 0x40;	/* DEL to ?, others to alpha */
82			ND_PRINT((ndo, "^"));
83		}
84		ND_PRINT((ndo, "%c", c));
85	}
86	return(ret);
87}
88
89/*
90 * Print out a counted filename (or other ascii string).
91 * If ep is NULL, assume no truncation check is needed.
92 * Return true if truncated.
93 */
94int
95fn_printn(netdissect_options *ndo,
96          register const u_char *s, register u_int n, register const u_char *ep)
97{
98	register u_char c;
99
100	while (n > 0 && (ep == NULL || s < ep)) {
101		n--;
102		c = *s++;
103		if (!ND_ISASCII(c)) {
104			c = ND_TOASCII(c);
105			ND_PRINT((ndo, "M-"));
106		}
107		if (!ND_ISPRINT(c)) {
108			c ^= 0x40;	/* DEL to ?, others to alpha */
109			ND_PRINT((ndo, "^"));
110		}
111		ND_PRINT((ndo, "%c", c));
112	}
113	return (n == 0) ? 0 : 1;
114}
115
116/*
117 * Print out a null-padded filename (or other ascii string).
118 * If ep is NULL, assume no truncation check is needed.
119 * Return true if truncated.
120 */
121int
122fn_printzp(netdissect_options *ndo,
123           register const u_char *s, register u_int n,
124           register const u_char *ep)
125{
126	register int ret;
127	register u_char c;
128
129	ret = 1;			/* assume truncated */
130	while (n > 0 && (ep == NULL || s < ep)) {
131		n--;
132		c = *s++;
133		if (c == '\0') {
134			ret = 0;
135			break;
136		}
137		if (!ND_ISASCII(c)) {
138			c = ND_TOASCII(c);
139			ND_PRINT((ndo, "M-"));
140		}
141		if (!ND_ISPRINT(c)) {
142			c ^= 0x40;	/* DEL to ?, others to alpha */
143			ND_PRINT((ndo, "^"));
144		}
145		ND_PRINT((ndo, "%c", c));
146	}
147	return (n == 0) ? 0 : ret;
148}
149
150/*
151 * Format the timestamp
152 */
153static char *
154ts_format(netdissect_options *ndo
155#ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
156_U_
157#endif
158, int sec, int usec)
159{
160	static char buf[sizeof("00:00:00.000000000")];
161	const char *format;
162
163#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
164	switch (ndo->ndo_tstamp_precision) {
165
166	case PCAP_TSTAMP_PRECISION_MICRO:
167		format = "%02d:%02d:%02d.%06u";
168		break;
169
170	case PCAP_TSTAMP_PRECISION_NANO:
171		format = "%02d:%02d:%02d.%09u";
172		break;
173
174	default:
175		format = "%02d:%02d:%02d.{unknown precision}";
176		break;
177	}
178#else
179	format = "%02d:%02d:%02d.%06u";
180#endif
181
182	snprintf(buf, sizeof(buf), format,
183                 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
184
185        return buf;
186}
187
188/*
189 * Print the timestamp
190 */
191void
192ts_print(netdissect_options *ndo,
193         register const struct timeval *tvp)
194{
195	register int s;
196	struct tm *tm;
197	time_t Time;
198	static unsigned b_sec;
199	static unsigned b_usec;
200	int d_usec;
201	int d_sec;
202
203	switch (ndo->ndo_tflag) {
204
205	case 0: /* Default */
206		s = (tvp->tv_sec + thiszone) % 86400;
207		ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec)));
208		break;
209
210	case 1: /* No time stamp */
211		break;
212
213	case 2: /* Unix timeval style */
214		ND_PRINT((ndo, "%u.%06u ",
215			     (unsigned)tvp->tv_sec,
216			     (unsigned)tvp->tv_usec));
217		break;
218
219	case 3: /* Microseconds since previous packet */
220        case 5: /* Microseconds since first packet */
221		if (b_sec == 0) {
222                        /* init timestamp for first packet */
223                        b_usec = tvp->tv_usec;
224                        b_sec = tvp->tv_sec;
225                }
226
227                d_usec = tvp->tv_usec - b_usec;
228                d_sec = tvp->tv_sec - b_sec;
229
230                while (d_usec < 0) {
231                    d_usec += 1000000;
232                    d_sec--;
233                }
234
235                ND_PRINT((ndo, "%s ", ts_format(ndo, d_sec, d_usec)));
236
237                if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */
238                    b_sec = tvp->tv_sec;
239                    b_usec = tvp->tv_usec;
240                }
241		break;
242
243	case 4: /* Default + Date*/
244		s = (tvp->tv_sec + thiszone) % 86400;
245		Time = (tvp->tv_sec + thiszone) - s;
246		tm = gmtime (&Time);
247		if (!tm)
248			ND_PRINT((ndo, "Date fail  "));
249		else
250			ND_PRINT((ndo, "%04d-%02d-%02d %s ",
251                               tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
252                               ts_format(ndo, s, tvp->tv_usec)));
253		break;
254	}
255}
256
257/*
258 * Print a relative number of seconds (e.g. hold time, prune timer)
259 * in the form 5m1s.  This does no truncation, so 32230861 seconds
260 * is represented as 1y1w1d1h1m1s.
261 */
262void
263relts_print(netdissect_options *ndo,
264            int secs)
265{
266	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
267	static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
268	const char **l = lengths;
269	const int *s = seconds;
270
271	if (secs == 0) {
272		ND_PRINT((ndo, "0s"));
273		return;
274	}
275	if (secs < 0) {
276		ND_PRINT((ndo, "-"));
277		secs = -secs;
278	}
279	while (secs > 0) {
280		if (secs >= *s) {
281			ND_PRINT((ndo, "%d%s", secs / *s, *l));
282			secs -= (secs / *s) * *s;
283		}
284		s++;
285		l++;
286	}
287}
288
289/*
290 *  this is a generic routine for printing unknown data;
291 *  we pass on the linefeed plus indentation string to
292 *  get a proper output - returns 0 on error
293 */
294
295int
296print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
297{
298	if (len < 0) {
299          ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
300		    ident));
301		return(0);
302	}
303	if (ndo->ndo_snapend - cp < len)
304		len = ndo->ndo_snapend - cp;
305	if (len < 0) {
306          ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
307		    ident));
308		return(0);
309	}
310        hex_print(ndo, ident,cp,len);
311	return(1); /* everything is ok */
312}
313
314/*
315 * Convert a token value to a string; use "fmt" if not found.
316 */
317const char *
318tok2strbuf(register const struct tok *lp, register const char *fmt,
319	   register u_int v, char *buf, size_t bufsize)
320{
321	if (lp != NULL) {
322		while (lp->s != NULL) {
323			if (lp->v == v)
324				return (lp->s);
325			++lp;
326		}
327	}
328	if (fmt == NULL)
329		fmt = "#%d";
330
331	(void)snprintf(buf, bufsize, fmt, v);
332	return (const char *)buf;
333}
334
335/*
336 * Convert a token value to a string; use "fmt" if not found.
337 */
338const char *
339tok2str(register const struct tok *lp, register const char *fmt,
340	register u_int v)
341{
342	static char buf[4][128];
343	static int idx = 0;
344	char *ret;
345
346	ret = buf[idx];
347	idx = (idx+1) & 3;
348	return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
349}
350
351/*
352 * Convert a bit token value to a string; use "fmt" if not found.
353 * this is useful for parsing bitfields, the output strings are seperated
354 * if the s field is positive.
355 */
356static char *
357bittok2str_internal(register const struct tok *lp, register const char *fmt,
358	   register u_int v, const char *sep)
359{
360        static char buf[256]; /* our stringbuffer */
361        int buflen=0;
362        register u_int rotbit; /* this is the bit we rotate through all bitpositions */
363        register u_int tokval;
364        const char * sepstr = "";
365
366	while (lp != NULL && lp->s != NULL) {
367            tokval=lp->v;   /* load our first value */
368            rotbit=1;
369            while (rotbit != 0) {
370                /*
371                 * lets AND the rotating bit with our token value
372                 * and see if we have got a match
373                 */
374		if (tokval == (v&rotbit)) {
375                    /* ok we have found something */
376                    buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
377                                     sepstr, lp->s);
378                    sepstr = sep;
379                    break;
380                }
381                rotbit=rotbit<<1; /* no match - lets shift and try again */
382            }
383            lp++;
384	}
385
386        if (buflen == 0)
387            /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
388            (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
389        return (buf);
390}
391
392/*
393 * Convert a bit token value to a string; use "fmt" if not found.
394 * this is useful for parsing bitfields, the output strings are not seperated.
395 */
396char *
397bittok2str_nosep(register const struct tok *lp, register const char *fmt,
398	   register u_int v)
399{
400    return (bittok2str_internal(lp, fmt, v, ""));
401}
402
403/*
404 * Convert a bit token value to a string; use "fmt" if not found.
405 * this is useful for parsing bitfields, the output strings are comma seperated.
406 */
407char *
408bittok2str(register const struct tok *lp, register const char *fmt,
409	   register u_int v)
410{
411    return (bittok2str_internal(lp, fmt, v, ", "));
412}
413
414/*
415 * Convert a value to a string using an array; the macro
416 * tok2strary() in <interface.h> is the public interface to
417 * this function and ensures that the second argument is
418 * correct for bounds-checking.
419 */
420const char *
421tok2strary_internal(register const char **lp, int n, register const char *fmt,
422	register int v)
423{
424	static char buf[128];
425
426	if (v >= 0 && v < n && lp[v] != NULL)
427		return lp[v];
428	if (fmt == NULL)
429		fmt = "#%d";
430	(void)snprintf(buf, sizeof(buf), fmt, v);
431	return (buf);
432}
433
434/*
435 * Convert a 32-bit netmask to prefixlen if possible
436 * the function returns the prefix-len; if plen == -1
437 * then conversion was not possible;
438 */
439
440int
441mask2plen(uint32_t mask)
442{
443	uint32_t bitmasks[33] = {
444		0x00000000,
445		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
446		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
447		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
448		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
449		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
450		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
451		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
452		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
453	};
454	int prefix_len = 32;
455
456	/* let's see if we can transform the mask into a prefixlen */
457	while (prefix_len >= 0) {
458		if (bitmasks[prefix_len] == mask)
459			break;
460		prefix_len--;
461	}
462	return (prefix_len);
463}
464
465#ifdef INET6
466int
467mask62plen(const u_char *mask)
468{
469	u_char bitmasks[9] = {
470		0x00,
471		0x80, 0xc0, 0xe0, 0xf0,
472		0xf8, 0xfc, 0xfe, 0xff
473	};
474	int byte;
475	int cidr_len = 0;
476
477	for (byte = 0; byte < 16; byte++) {
478		u_int bits;
479
480		for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
481			if (mask[byte] == bitmasks[bits]) {
482				cidr_len += bits;
483				break;
484			}
485		}
486
487		if (mask[byte] != 0xff)
488			break;
489	}
490	return (cidr_len);
491}
492#endif /* INET6 */
493
494/*
495 * Routine to print out information for text-based protocols such as FTP,
496 * HTTP, SMTP, RTSP, SIP, ....
497 */
498#define MAX_TOKEN	128
499
500/*
501 * Fetch a token from a packet, starting at the specified index,
502 * and return the length of the token.
503 *
504 * Returns 0 on error; yes, this is indistinguishable from an empty
505 * token, but an "empty token" isn't a valid token - it just means
506 * either a space character at the beginning of the line (this
507 * includes a blank line) or no more tokens remaining on the line.
508 */
509static int
510fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
511    u_char *tbuf, size_t tbuflen)
512{
513	size_t toklen = 0;
514
515	for (; idx < len; idx++) {
516		if (!ND_TTEST(*(pptr + idx))) {
517			/* ran past end of captured data */
518			return (0);
519		}
520		if (!isascii(*(pptr + idx))) {
521			/* not an ASCII character */
522			return (0);
523		}
524		if (isspace(*(pptr + idx))) {
525			/* end of token */
526			break;
527		}
528		if (!isprint(*(pptr + idx))) {
529			/* not part of a command token or response code */
530			return (0);
531		}
532		if (toklen + 2 > tbuflen) {
533			/* no room for this character and terminating '\0' */
534			return (0);
535		}
536		tbuf[toklen] = *(pptr + idx);
537		toklen++;
538	}
539	if (toklen == 0) {
540		/* no token */
541		return (0);
542	}
543	tbuf[toklen] = '\0';
544
545	/*
546	 * Skip past any white space after the token, until we see
547	 * an end-of-line (CR or LF).
548	 */
549	for (; idx < len; idx++) {
550		if (!ND_TTEST(*(pptr + idx))) {
551			/* ran past end of captured data */
552			break;
553		}
554		if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
555			/* end of line */
556			break;
557		}
558		if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
559			/* not a printable ASCII character */
560			break;
561		}
562		if (!isspace(*(pptr + idx))) {
563			/* beginning of next token */
564			break;
565		}
566	}
567	return (idx);
568}
569
570/*
571 * Scan a buffer looking for a line ending - LF or CR-LF.
572 * Return the index of the character after the line ending or 0 if
573 * we encounter a non-ASCII or non-printable character or don't find
574 * the line ending.
575 */
576static u_int
577print_txt_line(netdissect_options *ndo, const char *protoname,
578    const char *prefix, const u_char *pptr, u_int idx, u_int len)
579{
580	u_int startidx;
581	u_int linelen;
582
583	startidx = idx;
584	while (idx < len) {
585		ND_TCHECK(*(pptr+idx));
586		if (*(pptr+idx) == '\n') {
587			/*
588			 * LF without CR; end of line.
589			 * Skip the LF and print the line, with the
590			 * exception of the LF.
591			 */
592			linelen = idx - startidx;
593			idx++;
594			goto print;
595		} else if (*(pptr+idx) == '\r') {
596			/* CR - any LF? */
597			if ((idx+1) >= len) {
598				/* not in this packet */
599				return (0);
600			}
601			ND_TCHECK(*(pptr+idx+1));
602			if (*(pptr+idx+1) == '\n') {
603				/*
604				 * CR-LF; end of line.
605				 * Skip the CR-LF and print the line, with
606				 * the exception of the CR-LF.
607				 */
608				linelen = idx - startidx;
609				idx += 2;
610				goto print;
611			}
612
613			/*
614			 * CR followed by something else; treat this
615			 * as if it were binary data, and don't print
616			 * it.
617			 */
618			return (0);
619		} else if (!isascii(*(pptr+idx)) ||
620		    (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
621			/*
622			 * Not a printable ASCII character and not a tab;
623			 * treat this as if it were binary data, and
624			 * don't print it.
625			 */
626			return (0);
627		}
628		idx++;
629	}
630
631	/*
632	 * All printable ASCII, but no line ending after that point
633	 * in the buffer; treat this as if it were truncated.
634	 */
635trunc:
636	linelen = idx - startidx;
637	ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
638	    protoname));
639	return (0);
640
641print:
642	ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
643	return (idx);
644}
645
646void
647txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
648    const char *protoname, const char **cmds, u_int flags)
649{
650	u_int idx, eol;
651	u_char token[MAX_TOKEN+1];
652	const char *cmd;
653	int is_reqresp = 0;
654	const char *pnp;
655
656	if (cmds != NULL) {
657		/*
658		 * This protocol has more than just request and
659		 * response lines; see whether this looks like a
660		 * request or response.
661		 */
662		idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
663		if (idx != 0) {
664			/* Is this a valid request name? */
665			while ((cmd = *cmds++) != NULL) {
666				if (strcasecmp((const char *)token, cmd) == 0) {
667					/* Yes. */
668					is_reqresp = 1;
669					break;
670				}
671			}
672
673			/*
674			 * No - is this a valid response code (3 digits)?
675			 *
676			 * Is this token the response code, or is the next
677			 * token the response code?
678			 */
679			if (flags & RESP_CODE_SECOND_TOKEN) {
680				/*
681				 * Next token - get it.
682				 */
683				idx = fetch_token(ndo, pptr, idx, len, token,
684				    sizeof(token));
685			}
686			if (idx != 0) {
687				if (isdigit(token[0]) && isdigit(token[1]) &&
688				    isdigit(token[2]) && token[3] == '\0') {
689					/* Yes. */
690					is_reqresp = 1;
691				}
692			}
693		}
694	} else {
695		/*
696		 * This protocol has only request and response lines
697		 * (e.g., FTP, where all the data goes over a
698		 * different connection); assume the payload is
699		 * a request or response.
700		 */
701		is_reqresp = 1;
702	}
703
704	/* Capitalize the protocol name */
705	for (pnp = protoname; *pnp != '\0'; pnp++)
706		ND_PRINT((ndo, "%c", toupper(*pnp)));
707
708	if (is_reqresp) {
709		/*
710		 * In non-verbose mode, just print the protocol, followed
711		 * by the first line as the request or response info.
712		 *
713		 * In verbose mode, print lines as text until we run out
714		 * of characters or see something that's not a
715		 * printable-ASCII line.
716		 */
717		if (ndo->ndo_vflag) {
718			/*
719			 * We're going to print all the text lines in the
720			 * request or response; just print the length
721			 * on the first line of the output.
722			 */
723			ND_PRINT((ndo, ", length: %u", len));
724			for (idx = 0;
725			    idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
726			    idx = eol)
727				;
728		} else {
729			/*
730			 * Just print the first text line.
731			 */
732			print_txt_line(ndo, protoname, ": ", pptr, 0, len);
733		}
734	}
735}
736
737/* VARARGS */
738void
739error(const char *fmt, ...)
740{
741	va_list ap;
742
743	(void)fprintf(stderr, "%s: ", program_name);
744	va_start(ap, fmt);
745	(void)vfprintf(stderr, fmt, ap);
746	va_end(ap);
747	if (*fmt) {
748		fmt += strlen(fmt);
749		if (fmt[-1] != '\n')
750			(void)fputc('\n', stderr);
751	}
752	exit(1);
753	/* NOTREACHED */
754}
755
756/* VARARGS */
757void
758warning(const char *fmt, ...)
759{
760	va_list ap;
761
762	(void)fprintf(stderr, "%s: WARNING: ", program_name);
763	va_start(ap, fmt);
764	(void)vfprintf(stderr, fmt, ap);
765	va_end(ap);
766	if (*fmt) {
767		fmt += strlen(fmt);
768		if (fmt[-1] != '\n')
769			(void)fputc('\n', stderr);
770	}
771}
772
773/*
774 * Copy arg vector into a new buffer, concatenating arguments with spaces.
775 */
776char *
777copy_argv(register char **argv)
778{
779	register char **p;
780	register u_int len = 0;
781	char *buf;
782	char *src, *dst;
783
784	p = argv;
785	if (*p == 0)
786		return 0;
787
788	while (*p)
789		len += strlen(*p++) + 1;
790
791	buf = (char *)malloc(len);
792	if (buf == NULL)
793		error("copy_argv: malloc");
794
795	p = argv;
796	dst = buf;
797	while ((src = *p++) != NULL) {
798		while ((*dst++ = *src++) != '\0')
799			;
800		dst[-1] = ' ';
801	}
802	dst[-1] = '\0';
803
804	return buf;
805}
806
807/*
808 * On Windows, we need to open the file in binary mode, so that
809 * we get all the bytes specified by the size we get from "fstat()".
810 * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
811 * we define it as 0 if it's not defined, so it does nothing.
812 */
813#ifndef O_BINARY
814#define O_BINARY	0
815#endif
816
817char *
818read_infile(char *fname)
819{
820	register int i, fd, cc;
821	register char *cp;
822	struct stat buf;
823
824	fd = open(fname, O_RDONLY|O_BINARY);
825	if (fd < 0)
826		error("can't open %s: %s", fname, pcap_strerror(errno));
827
828	if (fstat(fd, &buf) < 0)
829		error("can't stat %s: %s", fname, pcap_strerror(errno));
830
831	cp = malloc((u_int)buf.st_size + 1);
832	if (cp == NULL)
833		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
834			fname, pcap_strerror(errno));
835	cc = read(fd, cp, (u_int)buf.st_size);
836	if (cc < 0)
837		error("read %s: %s", fname, pcap_strerror(errno));
838	if (cc != buf.st_size)
839		error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
840
841	close(fd);
842	/* replace "# comment" with spaces */
843	for (i = 0; i < cc; i++) {
844		if (cp[i] == '#')
845			while (i < cc && cp[i] != '\n')
846				cp[i++] = ' ';
847	}
848	cp[cc] = '\0';
849	return (cp);
850}
851
852void
853safeputs(netdissect_options *ndo,
854         const u_char *s, const u_int maxlen)
855{
856	u_int idx = 0;
857
858	while (*s && idx < maxlen) {
859		safeputchar(ndo, *s);
860		idx++;
861		s++;
862	}
863}
864
865void
866safeputchar(netdissect_options *ndo,
867            const u_char c)
868{
869	ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
870}
871
872#ifdef LBL_ALIGN
873/*
874 * Some compilers try to optimize memcpy(), using the alignment constraint
875 * on the argument pointer type.  by using this function, we try to avoid the
876 * optimization.
877 */
878void
879unaligned_memcpy(void *p, const void *q, size_t l)
880{
881	memcpy(p, q, l);
882}
883
884/* As with memcpy(), so with memcmp(). */
885int
886unaligned_memcmp(const void *p, const void *q, size_t l)
887{
888	return (memcmp(p, q, l));
889}
890#endif
891