xref: /netbsd-src/external/bsd/tcpdump/dist/util-print.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
1784088dfSchristos /*
2784088dfSchristos  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3784088dfSchristos  *	The Regents of the University of California.  All rights reserved.
4784088dfSchristos  *
5784088dfSchristos  * Redistribution and use in source and binary forms, with or without
6784088dfSchristos  * modification, are permitted provided that: (1) source code distributions
7784088dfSchristos  * retain the above copyright notice and this paragraph in its entirety, (2)
8784088dfSchristos  * distributions including binary code include the above copyright notice and
9784088dfSchristos  * this paragraph in its entirety in the documentation or other materials
10784088dfSchristos  * provided with the distribution, and (3) all advertising materials mentioning
11784088dfSchristos  * features or use of this software display the following acknowledgement:
12784088dfSchristos  * ``This product includes software developed by the University of California,
13784088dfSchristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14784088dfSchristos  * the University nor the names of its contributors may be used to endorse
15784088dfSchristos  * or promote products derived from this software without specific prior
16784088dfSchristos  * written permission.
17784088dfSchristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18784088dfSchristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19784088dfSchristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20784088dfSchristos  */
21784088dfSchristos 
22784088dfSchristos /*
23784088dfSchristos  * txtproto_print() derived from original code by Hannes Gredler
2472c96ff3Schristos  * (hannes@gredler.at):
25784088dfSchristos  *
26784088dfSchristos  * Redistribution and use in source and binary forms, with or without
27784088dfSchristos  * modification, are permitted provided that: (1) source code
28784088dfSchristos  * distributions retain the above copyright notice and this paragraph
29784088dfSchristos  * in its entirety, and (2) distributions including binary code include
30784088dfSchristos  * the above copyright notice and this paragraph in its entirety in
31784088dfSchristos  * the documentation or other materials provided with the distribution.
32784088dfSchristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
33784088dfSchristos  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
34784088dfSchristos  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35784088dfSchristos  * FOR A PARTICULAR PURPOSE.
36784088dfSchristos  */
37784088dfSchristos 
38fdccd7e4Schristos #include <sys/cdefs.h>
39fdccd7e4Schristos #ifndef lint
40*26ba0b50Schristos __RCSID("$NetBSD: util-print.c,v 1.8 2024/09/02 16:15:33 christos Exp $");
41fdccd7e4Schristos #endif
42fdccd7e4Schristos 
43c74ad251Schristos #include <config.h>
44784088dfSchristos 
45c74ad251Schristos #include "netdissect-stdinc.h"
46784088dfSchristos 
47784088dfSchristos #include <sys/stat.h>
48784088dfSchristos 
49784088dfSchristos #include <stdio.h>
50784088dfSchristos #include <stdarg.h>
51784088dfSchristos #include <stdlib.h>
52784088dfSchristos #include <string.h>
53784088dfSchristos 
54c74ad251Schristos #include "netdissect-ctype.h"
55c74ad251Schristos 
56784088dfSchristos #include "netdissect.h"
57c74ad251Schristos #include "extract.h"
58784088dfSchristos #include "ascii_strcasecmp.h"
59784088dfSchristos #include "timeval-operations.h"
60784088dfSchristos 
61784088dfSchristos #define TOKBUFSIZE 128
62784088dfSchristos 
63c74ad251Schristos enum date_flag { WITHOUT_DATE = 0, WITH_DATE = 1 };
64c74ad251Schristos enum time_flag { UTC_TIME = 0, LOCAL_TIME = 1 };
65c74ad251Schristos 
66784088dfSchristos /*
67784088dfSchristos  * Print out a character, filtering out the non-printable ones
68784088dfSchristos  */
69784088dfSchristos void
70784088dfSchristos fn_print_char(netdissect_options *ndo, u_char c)
71784088dfSchristos {
72784088dfSchristos 	if (!ND_ISASCII(c)) {
73784088dfSchristos 		c = ND_TOASCII(c);
74c74ad251Schristos 		ND_PRINT("M-");
75784088dfSchristos 	}
76c74ad251Schristos 	if (!ND_ASCII_ISPRINT(c)) {
77784088dfSchristos 		c ^= 0x40;	/* DEL to ?, others to alpha */
78c74ad251Schristos 		ND_PRINT("^");
79784088dfSchristos 	}
80c74ad251Schristos 	ND_PRINT("%c", c);
81784088dfSchristos }
82784088dfSchristos 
83784088dfSchristos /*
84c74ad251Schristos  * Print a null-terminated string, filtering out non-printable characters.
85c74ad251Schristos  * DON'T USE IT with a pointer on the packet buffer because there is no
86c74ad251Schristos  * truncation check. For this use, see the nd_printX() functions below.
87784088dfSchristos  */
88c74ad251Schristos void
89c74ad251Schristos fn_print_str(netdissect_options *ndo, const u_char *s)
90784088dfSchristos {
91c74ad251Schristos 	while (*s != '\0') {
92c74ad251Schristos 		fn_print_char(ndo, *s);
93c74ad251Schristos 		s++;
94784088dfSchristos        }
95784088dfSchristos }
96784088dfSchristos 
97784088dfSchristos /*
98c74ad251Schristos  * Print out a null-terminated filename (or other ASCII string) from
99817e9a7eSchristos  * a fixed-length field in the packet buffer, or from what remains of
100817e9a7eSchristos  * the packet.
101817e9a7eSchristos  *
102817e9a7eSchristos  * n is the length of the fixed-length field, or the number of bytes
103817e9a7eSchristos  * remaining in the packet based on its on-the-network length.
104817e9a7eSchristos  *
105817e9a7eSchristos  * If ep is non-null, it should point just past the last captured byte
106817e9a7eSchristos  * of the packet, e.g. ndo->ndo_snapend.  If ep is NULL, we assume no
107817e9a7eSchristos  * truncation check, other than the checks of the field length/remaining
108817e9a7eSchristos  * packet data length, is needed.
109817e9a7eSchristos  *
110dc860a36Sspz  * Return the number of bytes of string processed, including the
111817e9a7eSchristos  * terminating null, if not truncated; as the terminating null is
112817e9a7eSchristos  * included in the count, and as there must be a terminating null,
113817e9a7eSchristos  * this will always be non-zero.  Return 0 if truncated.
114dc860a36Sspz  */
115dc860a36Sspz u_int
116c74ad251Schristos nd_printztn(netdissect_options *ndo,
117c74ad251Schristos          const u_char *s, u_int n, const u_char *ep)
118dc860a36Sspz {
119c74ad251Schristos 	u_int bytes;
120c74ad251Schristos 	u_char c;
121dc860a36Sspz 
122dc860a36Sspz 	bytes = 0;
123dc860a36Sspz 	for (;;) {
124dc860a36Sspz 		if (n == 0 || (ep != NULL && s >= ep)) {
125dc860a36Sspz 			/*
126dc860a36Sspz 			 * Truncated.  This includes "no null before we
127817e9a7eSchristos 			 * got to the end of the fixed-length buffer or
128817e9a7eSchristos 			 * the end of the packet".
129dc860a36Sspz 			 *
130dc860a36Sspz 			 * XXX - BOOTP says "null-terminated", which
131dc860a36Sspz 			 * means the maximum length of the string, in
132dc860a36Sspz 			 * bytes, is 1 less than the size of the buffer,
133dc860a36Sspz 			 * as there must always be a terminating null.
134dc860a36Sspz 			 */
135dc860a36Sspz 			bytes = 0;
136dc860a36Sspz 			break;
137dc860a36Sspz 		}
138dc860a36Sspz 
139c74ad251Schristos 		c = GET_U_1(s);
140c74ad251Schristos 		s++;
141dc860a36Sspz 		bytes++;
142dc860a36Sspz 		n--;
143dc860a36Sspz 		if (c == '\0') {
144dc860a36Sspz 			/* End of string */
145dc860a36Sspz 			break;
146dc860a36Sspz 		}
147c74ad251Schristos 		fn_print_char(ndo, c);
148dc860a36Sspz 	}
149dc860a36Sspz 	return(bytes);
150dc860a36Sspz }
151dc860a36Sspz 
152dc860a36Sspz /*
153c74ad251Schristos  * Print out a counted filename (or other ASCII string), part of
154c74ad251Schristos  * the packet buffer.
155784088dfSchristos  * If ep is NULL, assume no truncation check is needed.
156784088dfSchristos  * Return true if truncated.
157784088dfSchristos  * Stop at ep (if given) or after n bytes, whichever is first.
158784088dfSchristos  */
159784088dfSchristos int
160c74ad251Schristos nd_printn(netdissect_options *ndo,
161c74ad251Schristos           const u_char *s, u_int n, const u_char *ep)
162784088dfSchristos {
163c74ad251Schristos 	u_char c;
164784088dfSchristos 
165784088dfSchristos 	while (n > 0 && (ep == NULL || s < ep)) {
166784088dfSchristos 		n--;
167c74ad251Schristos 		c = GET_U_1(s);
168c74ad251Schristos 		s++;
169c74ad251Schristos 		fn_print_char(ndo, c);
170784088dfSchristos 	}
171784088dfSchristos 	return (n == 0) ? 0 : 1;
172784088dfSchristos }
173784088dfSchristos 
174784088dfSchristos /*
175*26ba0b50Schristos  * Print a counted filename (or other ASCII string), part of
176*26ba0b50Schristos  * the packet buffer, filtering out non-printable characters.
177*26ba0b50Schristos  * Stop if truncated (via GET_U_1/longjmp) or after n bytes,
178*26ba0b50Schristos  * whichever is first.
179*26ba0b50Schristos  * The suffix comes from: j:longJmp, n:after N bytes.
180*26ba0b50Schristos  */
181*26ba0b50Schristos void
182*26ba0b50Schristos nd_printjn(netdissect_options *ndo, const u_char *s, u_int n)
183*26ba0b50Schristos {
184*26ba0b50Schristos 	while (n > 0) {
185*26ba0b50Schristos 		fn_print_char(ndo, GET_U_1(s));
186*26ba0b50Schristos 		n--;
187*26ba0b50Schristos 		s++;
188*26ba0b50Schristos 	}
189*26ba0b50Schristos }
190*26ba0b50Schristos 
191*26ba0b50Schristos /*
192c74ad251Schristos  * Print a null-padded filename (or other ASCII string), part of
193c74ad251Schristos  * the packet buffer, filtering out non-printable characters.
194c74ad251Schristos  * Stop if truncated (via GET_U_1/longjmp) or after n bytes or before
195c74ad251Schristos  * the null char, whichever occurs first.
196c74ad251Schristos  * The suffix comes from: j:longJmp, n:after N bytes, p:null-Padded.
197784088dfSchristos  */
198c74ad251Schristos void
199c74ad251Schristos nd_printjnp(netdissect_options *ndo, const u_char *s, u_int n)
200784088dfSchristos {
201c74ad251Schristos 	u_char c;
202784088dfSchristos 
203c74ad251Schristos 	while (n > 0) {
204c74ad251Schristos 		c = GET_U_1(s);
205c74ad251Schristos 		if (c == '\0')
206c74ad251Schristos 			break;
207c74ad251Schristos 		fn_print_char(ndo, c);
208784088dfSchristos 		n--;
209c74ad251Schristos 		s++;
210784088dfSchristos 	}
211784088dfSchristos }
212784088dfSchristos 
213784088dfSchristos /*
214c74ad251Schristos  * Print the timestamp .FRAC part (Microseconds/nanoseconds)
215784088dfSchristos  */
216c74ad251Schristos static void
217*26ba0b50Schristos ts_frac_print(netdissect_options *ndo, const struct timeval *tv)
218784088dfSchristos {
219784088dfSchristos #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
220784088dfSchristos 	switch (ndo->ndo_tstamp_precision) {
221784088dfSchristos 
222784088dfSchristos 	case PCAP_TSTAMP_PRECISION_MICRO:
223*26ba0b50Schristos 		ND_PRINT(".%06u", (unsigned)tv->tv_usec);
224784088dfSchristos 		break;
225784088dfSchristos 
226784088dfSchristos 	case PCAP_TSTAMP_PRECISION_NANO:
227*26ba0b50Schristos 		ND_PRINT(".%09u", (unsigned)tv->tv_usec);
228784088dfSchristos 		break;
229784088dfSchristos 
230784088dfSchristos 	default:
231c74ad251Schristos 		ND_PRINT(".{unknown}");
232784088dfSchristos 		break;
233784088dfSchristos 	}
234784088dfSchristos #else
235*26ba0b50Schristos 	ND_PRINT(".%06u", (unsigned)tv->tv_usec);
236784088dfSchristos #endif
237784088dfSchristos }
238784088dfSchristos 
239784088dfSchristos /*
240c74ad251Schristos  * Print the timestamp as [YY:MM:DD] HH:MM:SS.FRAC.
241c74ad251Schristos  *   if time_flag == LOCAL_TIME print local time else UTC/GMT time
242c74ad251Schristos  *   if date_flag == WITH_DATE print YY:MM:DD before HH:MM:SS.FRAC
243784088dfSchristos  */
244c74ad251Schristos static void
245*26ba0b50Schristos ts_date_hmsfrac_print(netdissect_options *ndo, const struct timeval *tv,
246c74ad251Schristos 		      enum date_flag date_flag, enum time_flag time_flag)
247784088dfSchristos {
248c74ad251Schristos 	struct tm *tm;
249c74ad251Schristos 	char timebuf[32];
250c74ad251Schristos 	const char *timestr;
251784088dfSchristos 
252*26ba0b50Schristos 	if (tv->tv_sec < 0) {
253*26ba0b50Schristos 		ND_PRINT("[timestamp < 1970-01-01 00:00:00 UTC]");
254c74ad251Schristos 		return;
255784088dfSchristos 	}
256784088dfSchristos 
257c74ad251Schristos 	if (time_flag == LOCAL_TIME)
258*26ba0b50Schristos 		tm = localtime(&tv->tv_sec);
259c74ad251Schristos 	else
260*26ba0b50Schristos 		tm = gmtime(&tv->tv_sec);
261784088dfSchristos 
262c74ad251Schristos 	if (date_flag == WITH_DATE) {
263c74ad251Schristos 		timestr = nd_format_time(timebuf, sizeof(timebuf),
264c74ad251Schristos 		    "%Y-%m-%d %H:%M:%S", tm);
265c74ad251Schristos 	} else {
266c74ad251Schristos 		timestr = nd_format_time(timebuf, sizeof(timebuf),
267c74ad251Schristos 		    "%H:%M:%S", tm);
268c74ad251Schristos 	}
269c74ad251Schristos 	ND_PRINT("%s", timestr);
270c74ad251Schristos 
271*26ba0b50Schristos 	ts_frac_print(ndo, tv);
272c74ad251Schristos }
273c74ad251Schristos 
274c74ad251Schristos /*
275c74ad251Schristos  * Print the timestamp - Unix timeval style, as SECS.FRAC.
276c74ad251Schristos  */
277c74ad251Schristos static void
278*26ba0b50Schristos ts_unix_print(netdissect_options *ndo, const struct timeval *tv)
279c74ad251Schristos {
280*26ba0b50Schristos 	if (tv->tv_sec < 0) {
281*26ba0b50Schristos 		ND_PRINT("[timestamp < 1970-01-01 00:00:00 UTC]");
282c74ad251Schristos 		return;
283c74ad251Schristos 	}
284c74ad251Schristos 
285*26ba0b50Schristos 	ND_PRINT("%u", (unsigned)tv->tv_sec);
286*26ba0b50Schristos 	ts_frac_print(ndo, tv);
287784088dfSchristos }
288784088dfSchristos 
289784088dfSchristos /*
290784088dfSchristos  * Print the timestamp
291784088dfSchristos  */
292784088dfSchristos void
293784088dfSchristos ts_print(netdissect_options *ndo,
294c74ad251Schristos          const struct timeval *tvp)
295784088dfSchristos {
296784088dfSchristos 	static struct timeval tv_ref;
297784088dfSchristos 	struct timeval tv_result;
298784088dfSchristos 	int negative_offset;
299784088dfSchristos 	int nano_prec;
300784088dfSchristos 
301784088dfSchristos 	switch (ndo->ndo_tflag) {
302784088dfSchristos 
303784088dfSchristos 	case 0: /* Default */
304*26ba0b50Schristos 		ts_date_hmsfrac_print(ndo, tvp, WITHOUT_DATE, LOCAL_TIME);
305c74ad251Schristos 		ND_PRINT(" ");
306784088dfSchristos 		break;
307784088dfSchristos 
308784088dfSchristos 	case 1: /* No time stamp */
309784088dfSchristos 		break;
310784088dfSchristos 
311784088dfSchristos 	case 2: /* Unix timeval style */
312*26ba0b50Schristos 		ts_unix_print(ndo, tvp);
313c74ad251Schristos 		ND_PRINT(" ");
314784088dfSchristos 		break;
315784088dfSchristos 
316784088dfSchristos 	case 3: /* Microseconds/nanoseconds since previous packet */
317784088dfSchristos         case 5: /* Microseconds/nanoseconds since first packet */
318784088dfSchristos #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
319784088dfSchristos 		switch (ndo->ndo_tstamp_precision) {
320784088dfSchristos 		case PCAP_TSTAMP_PRECISION_MICRO:
321784088dfSchristos 			nano_prec = 0;
322784088dfSchristos 			break;
323784088dfSchristos 		case PCAP_TSTAMP_PRECISION_NANO:
324784088dfSchristos 			nano_prec = 1;
325784088dfSchristos 			break;
326784088dfSchristos 		default:
327784088dfSchristos 			nano_prec = 0;
328784088dfSchristos 			break;
329784088dfSchristos 		}
330784088dfSchristos #else
331784088dfSchristos 		nano_prec = 0;
332784088dfSchristos #endif
333784088dfSchristos 		if (!(netdissect_timevalisset(&tv_ref)))
334784088dfSchristos 			tv_ref = *tvp; /* set timestamp for first packet */
335784088dfSchristos 
336784088dfSchristos 		negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
337784088dfSchristos 		if (negative_offset)
338784088dfSchristos 			netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
339784088dfSchristos 		else
340784088dfSchristos 			netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
341784088dfSchristos 
342c74ad251Schristos 		ND_PRINT((negative_offset ? "-" : " "));
343*26ba0b50Schristos 		ts_date_hmsfrac_print(ndo, &tv_result, WITHOUT_DATE, UTC_TIME);
344c74ad251Schristos 		ND_PRINT(" ");
345784088dfSchristos 
346784088dfSchristos                 if (ndo->ndo_tflag == 3)
347784088dfSchristos 			tv_ref = *tvp; /* set timestamp for previous packet */
348784088dfSchristos 		break;
349784088dfSchristos 
350c74ad251Schristos 	case 4: /* Date + Default */
351*26ba0b50Schristos 		ts_date_hmsfrac_print(ndo, tvp, WITH_DATE, LOCAL_TIME);
352c74ad251Schristos 		ND_PRINT(" ");
353784088dfSchristos 		break;
354784088dfSchristos 	}
355784088dfSchristos }
356784088dfSchristos 
357784088dfSchristos /*
358dc860a36Sspz  * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
359784088dfSchristos  * in the form 5m1s.  This does no truncation, so 32230861 seconds
360784088dfSchristos  * is represented as 1y1w1d1h1m1s.
361784088dfSchristos  */
362784088dfSchristos void
363dc860a36Sspz unsigned_relts_print(netdissect_options *ndo,
364dc860a36Sspz                      uint32_t secs)
365784088dfSchristos {
366784088dfSchristos 	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
367dc860a36Sspz 	static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
368784088dfSchristos 	const char **l = lengths;
369dc860a36Sspz 	const u_int *s = seconds;
370784088dfSchristos 
371784088dfSchristos 	if (secs == 0) {
372c74ad251Schristos 		ND_PRINT("0s");
373784088dfSchristos 		return;
374784088dfSchristos 	}
375784088dfSchristos 	while (secs > 0) {
376784088dfSchristos 		if (secs >= *s) {
377c74ad251Schristos 			ND_PRINT("%u%s", secs / *s, *l);
378784088dfSchristos 			secs -= (secs / *s) * *s;
379784088dfSchristos 		}
380784088dfSchristos 		s++;
381784088dfSchristos 		l++;
382784088dfSchristos 	}
383784088dfSchristos }
384784088dfSchristos 
385784088dfSchristos /*
386dc860a36Sspz  * Print a signed relative number of seconds (e.g. hold time, prune timer)
387dc860a36Sspz  * in the form 5m1s.  This does no truncation, so 32230861 seconds
388dc860a36Sspz  * is represented as 1y1w1d1h1m1s.
389dc860a36Sspz  */
390dc860a36Sspz void
391dc860a36Sspz signed_relts_print(netdissect_options *ndo,
392dc860a36Sspz                    int32_t secs)
393dc860a36Sspz {
394dc860a36Sspz 	if (secs < 0) {
395c74ad251Schristos 		ND_PRINT("-");
396dc860a36Sspz 		if (secs == INT32_MIN) {
397dc860a36Sspz 			/*
398dc860a36Sspz 			 * -2^31; you can't fit its absolute value into
399dc860a36Sspz 			 * a 32-bit signed integer.
400dc860a36Sspz 			 *
401dc860a36Sspz 			 * Just directly pass said absolute value to
402dc860a36Sspz 			 * unsigned_relts_print() directly.
403dc860a36Sspz 			 *
404dc860a36Sspz 			 * (XXX - does ISO C guarantee that -(-2^n),
405dc860a36Sspz 			 * when calculated and cast to an n-bit unsigned
406dc860a36Sspz 			 * integer type, will have the value 2^n?)
407dc860a36Sspz 			 */
408dc860a36Sspz 			unsigned_relts_print(ndo, 2147483648U);
409dc860a36Sspz 		} else {
410dc860a36Sspz 			/*
411dc860a36Sspz 			 * We now know -secs will fit into an int32_t;
412dc860a36Sspz 			 * negate it and pass that to unsigned_relts_print().
413dc860a36Sspz 			 */
414dc860a36Sspz 			unsigned_relts_print(ndo, -secs);
415dc860a36Sspz 		}
416dc860a36Sspz 		return;
417dc860a36Sspz 	}
418dc860a36Sspz 	unsigned_relts_print(ndo, secs);
419dc860a36Sspz }
420dc860a36Sspz 
421dc860a36Sspz /*
422c74ad251Schristos  * Format a struct tm with strftime().
423c74ad251Schristos  * If the pointer to the struct tm is null, that means that the
424c74ad251Schristos  * routine to convert a time_t to a struct tm failed; the localtime()
425c74ad251Schristos  * and gmtime() in the Microsoft Visual Studio C library will fail,
426c74ad251Schristos  * returning null, if the value is before the UNIX Epoch.
427c74ad251Schristos  */
428c74ad251Schristos const char *
429c74ad251Schristos nd_format_time(char *buf, size_t bufsize, const char *format,
430c74ad251Schristos          const struct tm *timeptr)
431c74ad251Schristos {
432c74ad251Schristos 	if (timeptr != NULL) {
433c74ad251Schristos 		if (strftime(buf, bufsize, format, timeptr) != 0)
434c74ad251Schristos 			return (buf);
435c74ad251Schristos 		else
436c74ad251Schristos 			return ("[nd_format_time() buffer is too small]");
437c74ad251Schristos 	} else
438c74ad251Schristos 		return ("[localtime() or gmtime() couldn't convert the date and time]");
439c74ad251Schristos }
440c74ad251Schristos 
441c74ad251Schristos /* Print the truncated string */
442c74ad251Schristos void nd_print_trunc(netdissect_options *ndo)
443c74ad251Schristos {
444c74ad251Schristos 	ND_PRINT(" [|%s]", ndo->ndo_protocol);
445c74ad251Schristos }
446c74ad251Schristos 
447c74ad251Schristos /* Print the protocol name */
448c74ad251Schristos void nd_print_protocol(netdissect_options *ndo)
449c74ad251Schristos {
450c74ad251Schristos 	ND_PRINT("%s", ndo->ndo_protocol);
451c74ad251Schristos }
452c74ad251Schristos 
453c74ad251Schristos /* Print the protocol name in caps (uppercases) */
454c74ad251Schristos void nd_print_protocol_caps(netdissect_options *ndo)
455c74ad251Schristos {
456c74ad251Schristos 	const char *p;
457c74ad251Schristos         for (p = ndo->ndo_protocol; *p != '\0'; p++)
458c74ad251Schristos                 ND_PRINT("%c", ND_ASCII_TOUPPER(*p));
459c74ad251Schristos }
460c74ad251Schristos 
461c74ad251Schristos /* Print the invalid string */
462c74ad251Schristos void nd_print_invalid(netdissect_options *ndo)
463c74ad251Schristos {
464c74ad251Schristos 	ND_PRINT(" (invalid)");
465c74ad251Schristos }
466c74ad251Schristos 
467c74ad251Schristos /*
468784088dfSchristos  *  this is a generic routine for printing unknown data;
469784088dfSchristos  *  we pass on the linefeed plus indentation string to
470784088dfSchristos  *  get a proper output - returns 0 on error
471784088dfSchristos  */
472784088dfSchristos 
473784088dfSchristos int
474c74ad251Schristos print_unknown_data(netdissect_options *ndo, const u_char *cp,
475c74ad251Schristos                    const char *ident, u_int len)
476784088dfSchristos {
477c74ad251Schristos 	u_int len_to_print;
478c74ad251Schristos 
479c74ad251Schristos 	len_to_print = len;
480c74ad251Schristos 	if (!ND_TTEST_LEN(cp, 0)) {
481c74ad251Schristos 		ND_PRINT("%sDissector error: print_unknown_data called with pointer past end of packet",
482c74ad251Schristos 		    ident);
483784088dfSchristos 		return(0);
484784088dfSchristos 	}
485c74ad251Schristos 	if (ND_BYTES_AVAILABLE_AFTER(cp) < len_to_print)
486c74ad251Schristos 		len_to_print = ND_BYTES_AVAILABLE_AFTER(cp);
487c74ad251Schristos 	hex_print(ndo, ident, cp, len_to_print);
488784088dfSchristos 	return(1); /* everything is ok */
489784088dfSchristos }
490784088dfSchristos 
491784088dfSchristos /*
492784088dfSchristos  * Convert a token value to a string; use "fmt" if not found.
493784088dfSchristos  */
494c74ad251Schristos static const char *
495c74ad251Schristos tok2strbuf(const struct tok *lp, const char *fmt,
496c74ad251Schristos 	   u_int v, char *buf, size_t bufsize)
497784088dfSchristos {
498784088dfSchristos 	if (lp != NULL) {
499784088dfSchristos 		while (lp->s != NULL) {
500784088dfSchristos 			if (lp->v == v)
501784088dfSchristos 				return (lp->s);
502784088dfSchristos 			++lp;
503784088dfSchristos 		}
504784088dfSchristos 	}
505784088dfSchristos 	if (fmt == NULL)
506784088dfSchristos 		fmt = "#%d";
507784088dfSchristos 
508784088dfSchristos 	(void)snprintf(buf, bufsize, fmt, v);
509784088dfSchristos 	return (const char *)buf;
510784088dfSchristos }
511784088dfSchristos 
512784088dfSchristos /*
513784088dfSchristos  * Convert a token value to a string; use "fmt" if not found.
514c74ad251Schristos  * Uses tok2strbuf() on one of four local static buffers of size TOKBUFSIZE
515c74ad251Schristos  * in round-robin fashion.
516784088dfSchristos  */
517784088dfSchristos const char *
518c74ad251Schristos tok2str(const struct tok *lp, const char *fmt,
519c74ad251Schristos 	u_int v)
520784088dfSchristos {
521784088dfSchristos 	static char buf[4][TOKBUFSIZE];
522784088dfSchristos 	static int idx = 0;
523784088dfSchristos 	char *ret;
524784088dfSchristos 
525784088dfSchristos 	ret = buf[idx];
526784088dfSchristos 	idx = (idx+1) & 3;
527784088dfSchristos 	return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
528784088dfSchristos }
529784088dfSchristos 
530784088dfSchristos /*
531784088dfSchristos  * Convert a bit token value to a string; use "fmt" if not found.
532c74ad251Schristos  * this is useful for parsing bitfields, the output strings are separated
533784088dfSchristos  * if the s field is positive.
534c74ad251Schristos  *
535c74ad251Schristos  * A token matches iff it has one or more bits set and every bit that is set
536c74ad251Schristos  * in the token is set in v. Consequently, a 0 token never matches.
537784088dfSchristos  */
538784088dfSchristos static char *
539c74ad251Schristos bittok2str_internal(const struct tok *lp, const char *fmt,
540c74ad251Schristos 	   u_int v, const char *sep)
541784088dfSchristos {
54272c96ff3Schristos         static char buf[1024+1]; /* our string buffer */
54372c96ff3Schristos         char *bufp = buf;
54472c96ff3Schristos         size_t space_left = sizeof(buf), string_size;
545784088dfSchristos         const char * sepstr = "";
546784088dfSchristos 
547784088dfSchristos         while (lp != NULL && lp->s != NULL) {
548c74ad251Schristos             if (lp->v && (v & lp->v) == lp->v) {
549784088dfSchristos                 /* ok we have found something */
55072c96ff3Schristos                 if (space_left <= 1)
55172c96ff3Schristos                     return (buf); /* only enough room left for NUL, if that */
55272c96ff3Schristos                 string_size = strlcpy(bufp, sepstr, space_left);
55372c96ff3Schristos                 if (string_size >= space_left)
55472c96ff3Schristos                     return (buf);    /* we ran out of room */
55572c96ff3Schristos                 bufp += string_size;
55672c96ff3Schristos                 space_left -= string_size;
55772c96ff3Schristos                 if (space_left <= 1)
55872c96ff3Schristos                     return (buf); /* only enough room left for NUL, if that */
55972c96ff3Schristos                 string_size = strlcpy(bufp, lp->s, space_left);
56072c96ff3Schristos                 if (string_size >= space_left)
56172c96ff3Schristos                     return (buf);    /* we ran out of room */
56272c96ff3Schristos                 bufp += string_size;
56372c96ff3Schristos                 space_left -= string_size;
564784088dfSchristos                 sepstr = sep;
565784088dfSchristos             }
566784088dfSchristos             lp++;
567784088dfSchristos         }
568784088dfSchristos 
56972c96ff3Schristos         if (bufp == buf)
570784088dfSchristos             /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
571784088dfSchristos             (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
572784088dfSchristos         return (buf);
573784088dfSchristos }
574784088dfSchristos 
575784088dfSchristos /*
576784088dfSchristos  * Convert a bit token value to a string; use "fmt" if not found.
577c74ad251Schristos  * this is useful for parsing bitfields, the output strings are not separated.
578784088dfSchristos  */
579784088dfSchristos char *
580c74ad251Schristos bittok2str_nosep(const struct tok *lp, const char *fmt,
581c74ad251Schristos 	   u_int v)
582784088dfSchristos {
583784088dfSchristos     return (bittok2str_internal(lp, fmt, v, ""));
584784088dfSchristos }
585784088dfSchristos 
586784088dfSchristos /*
587784088dfSchristos  * Convert a bit token value to a string; use "fmt" if not found.
588c74ad251Schristos  * this is useful for parsing bitfields, the output strings are comma separated.
589784088dfSchristos  */
590784088dfSchristos char *
591c74ad251Schristos bittok2str(const struct tok *lp, const char *fmt,
592c74ad251Schristos 	   u_int v)
593784088dfSchristos {
594784088dfSchristos     return (bittok2str_internal(lp, fmt, v, ", "));
595784088dfSchristos }
596784088dfSchristos 
597784088dfSchristos /*
598784088dfSchristos  * Convert a value to a string using an array; the macro
599784088dfSchristos  * tok2strary() in <netdissect.h> is the public interface to
600784088dfSchristos  * this function and ensures that the second argument is
601784088dfSchristos  * correct for bounds-checking.
602784088dfSchristos  */
603784088dfSchristos const char *
604c74ad251Schristos tok2strary_internal(const char **lp, int n, const char *fmt,
605c74ad251Schristos 	int v)
606784088dfSchristos {
607784088dfSchristos 	static char buf[TOKBUFSIZE];
608784088dfSchristos 
609784088dfSchristos 	if (v >= 0 && v < n && lp[v] != NULL)
610784088dfSchristos 		return lp[v];
611784088dfSchristos 	if (fmt == NULL)
612784088dfSchristos 		fmt = "#%d";
613784088dfSchristos 	(void)snprintf(buf, sizeof(buf), fmt, v);
614784088dfSchristos 	return (buf);
615784088dfSchristos }
616784088dfSchristos 
617c74ad251Schristos const struct tok *
618c74ad251Schristos uint2tokary_internal(const struct uint_tokary dict[], const size_t size,
619c74ad251Schristos                      const u_int val)
620c74ad251Schristos {
621c74ad251Schristos 	size_t i;
622c74ad251Schristos 	/* Try a direct lookup before the full scan. */
623c74ad251Schristos 	if (val < size && dict[val].uintval == val)
624c74ad251Schristos 		return dict[val].tokary; /* OK if NULL */
625c74ad251Schristos 	for (i = 0; i < size; i++)
626c74ad251Schristos 		if (dict[i].uintval == val)
627c74ad251Schristos 			return dict[i].tokary; /* OK if NULL */
628c74ad251Schristos 	return NULL;
629c74ad251Schristos }
630c74ad251Schristos 
631784088dfSchristos /*
632784088dfSchristos  * Convert a 32-bit netmask to prefixlen if possible
633784088dfSchristos  * the function returns the prefix-len; if plen == -1
634784088dfSchristos  * then conversion was not possible;
635784088dfSchristos  */
636784088dfSchristos 
637784088dfSchristos int
638784088dfSchristos mask2plen(uint32_t mask)
639784088dfSchristos {
640c74ad251Schristos 	const uint32_t bitmasks[33] = {
641784088dfSchristos 		0x00000000,
642784088dfSchristos 		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
643784088dfSchristos 		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
644784088dfSchristos 		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
645784088dfSchristos 		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
646784088dfSchristos 		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
647784088dfSchristos 		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
648784088dfSchristos 		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
649784088dfSchristos 		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
650784088dfSchristos 	};
651784088dfSchristos 	int prefix_len = 32;
652784088dfSchristos 
653784088dfSchristos 	/* let's see if we can transform the mask into a prefixlen */
654784088dfSchristos 	while (prefix_len >= 0) {
655784088dfSchristos 		if (bitmasks[prefix_len] == mask)
656784088dfSchristos 			break;
657784088dfSchristos 		prefix_len--;
658784088dfSchristos 	}
659784088dfSchristos 	return (prefix_len);
660784088dfSchristos }
661784088dfSchristos 
662784088dfSchristos int
663784088dfSchristos mask62plen(const u_char *mask)
664784088dfSchristos {
665784088dfSchristos 	u_char bitmasks[9] = {
666784088dfSchristos 		0x00,
667784088dfSchristos 		0x80, 0xc0, 0xe0, 0xf0,
668784088dfSchristos 		0xf8, 0xfc, 0xfe, 0xff
669784088dfSchristos 	};
670784088dfSchristos 	int byte;
671784088dfSchristos 	int cidr_len = 0;
672784088dfSchristos 
673784088dfSchristos 	for (byte = 0; byte < 16; byte++) {
674784088dfSchristos 		u_int bits;
675784088dfSchristos 
676784088dfSchristos 		for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
677784088dfSchristos 			if (mask[byte] == bitmasks[bits]) {
678784088dfSchristos 				cidr_len += bits;
679784088dfSchristos 				break;
680784088dfSchristos 			}
681784088dfSchristos 		}
682784088dfSchristos 
683784088dfSchristos 		if (mask[byte] != 0xff)
684784088dfSchristos 			break;
685784088dfSchristos 	}
686784088dfSchristos 	return (cidr_len);
687784088dfSchristos }
688784088dfSchristos 
689784088dfSchristos /*
690784088dfSchristos  * Routine to print out information for text-based protocols such as FTP,
691784088dfSchristos  * HTTP, SMTP, RTSP, SIP, ....
692784088dfSchristos  */
693784088dfSchristos #define MAX_TOKEN	128
694784088dfSchristos 
695784088dfSchristos /*
696784088dfSchristos  * Fetch a token from a packet, starting at the specified index,
697784088dfSchristos  * and return the length of the token.
698784088dfSchristos  *
699784088dfSchristos  * Returns 0 on error; yes, this is indistinguishable from an empty
700784088dfSchristos  * token, but an "empty token" isn't a valid token - it just means
701784088dfSchristos  * either a space character at the beginning of the line (this
702784088dfSchristos  * includes a blank line) or no more tokens remaining on the line.
703784088dfSchristos  */
704784088dfSchristos static int
705784088dfSchristos fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
706784088dfSchristos     u_char *tbuf, size_t tbuflen)
707784088dfSchristos {
708784088dfSchristos 	size_t toklen = 0;
709c74ad251Schristos 	u_char c;
710784088dfSchristos 
711784088dfSchristos 	for (; idx < len; idx++) {
712c74ad251Schristos 		if (!ND_TTEST_1(pptr + idx)) {
713784088dfSchristos 			/* ran past end of captured data */
714784088dfSchristos 			return (0);
715784088dfSchristos 		}
716c74ad251Schristos 		c = GET_U_1(pptr + idx);
717c74ad251Schristos 		if (!ND_ISASCII(c)) {
718784088dfSchristos 			/* not an ASCII character */
719784088dfSchristos 			return (0);
720784088dfSchristos 		}
721c74ad251Schristos 		if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
722784088dfSchristos 			/* end of token */
723784088dfSchristos 			break;
724784088dfSchristos 		}
725c74ad251Schristos 		if (!ND_ASCII_ISPRINT(c)) {
726784088dfSchristos 			/* not part of a command token or response code */
727784088dfSchristos 			return (0);
728784088dfSchristos 		}
729784088dfSchristos 		if (toklen + 2 > tbuflen) {
730784088dfSchristos 			/* no room for this character and terminating '\0' */
731784088dfSchristos 			return (0);
732784088dfSchristos 		}
733c74ad251Schristos 		tbuf[toklen] = c;
734784088dfSchristos 		toklen++;
735784088dfSchristos 	}
736784088dfSchristos 	if (toklen == 0) {
737784088dfSchristos 		/* no token */
738784088dfSchristos 		return (0);
739784088dfSchristos 	}
740784088dfSchristos 	tbuf[toklen] = '\0';
741784088dfSchristos 
742784088dfSchristos 	/*
743784088dfSchristos 	 * Skip past any white space after the token, until we see
744784088dfSchristos 	 * an end-of-line (CR or LF).
745784088dfSchristos 	 */
746784088dfSchristos 	for (; idx < len; idx++) {
747c74ad251Schristos 		if (!ND_TTEST_1(pptr + idx)) {
748784088dfSchristos 			/* ran past end of captured data */
749784088dfSchristos 			break;
750784088dfSchristos 		}
751c74ad251Schristos 		c = GET_U_1(pptr + idx);
752c74ad251Schristos 		if (c == '\r' || c == '\n') {
753784088dfSchristos 			/* end of line */
754784088dfSchristos 			break;
755784088dfSchristos 		}
756c74ad251Schristos 		if (!ND_ASCII_ISPRINT(c)) {
757784088dfSchristos 			/* not a printable ASCII character */
758784088dfSchristos 			break;
759784088dfSchristos 		}
760c74ad251Schristos 		if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
761784088dfSchristos 			/* beginning of next token */
762784088dfSchristos 			break;
763784088dfSchristos 		}
764784088dfSchristos 	}
765784088dfSchristos 	return (idx);
766784088dfSchristos }
767784088dfSchristos 
768784088dfSchristos /*
769784088dfSchristos  * Scan a buffer looking for a line ending - LF or CR-LF.
770784088dfSchristos  * Return the index of the character after the line ending or 0 if
771784088dfSchristos  * we encounter a non-ASCII or non-printable character or don't find
772784088dfSchristos  * the line ending.
773784088dfSchristos  */
774784088dfSchristos static u_int
775c74ad251Schristos print_txt_line(netdissect_options *ndo, const char *prefix,
776c74ad251Schristos 	       const u_char *pptr, u_int idx, u_int len)
777784088dfSchristos {
778784088dfSchristos 	u_int startidx;
779784088dfSchristos 	u_int linelen;
780c74ad251Schristos 	u_char c;
781784088dfSchristos 
782784088dfSchristos 	startidx = idx;
783784088dfSchristos 	while (idx < len) {
784c74ad251Schristos 		c = GET_U_1(pptr + idx);
785c74ad251Schristos 		if (c == '\n') {
786784088dfSchristos 			/*
787784088dfSchristos 			 * LF without CR; end of line.
788784088dfSchristos 			 * Skip the LF and print the line, with the
789784088dfSchristos 			 * exception of the LF.
790784088dfSchristos 			 */
791784088dfSchristos 			linelen = idx - startidx;
792784088dfSchristos 			idx++;
793784088dfSchristos 			goto print;
794c74ad251Schristos 		} else if (c == '\r') {
795784088dfSchristos 			/* CR - any LF? */
796784088dfSchristos 			if ((idx+1) >= len) {
797784088dfSchristos 				/* not in this packet */
798784088dfSchristos 				return (0);
799784088dfSchristos 			}
800c74ad251Schristos 			if (GET_U_1(pptr + idx + 1) == '\n') {
801784088dfSchristos 				/*
802784088dfSchristos 				 * CR-LF; end of line.
803784088dfSchristos 				 * Skip the CR-LF and print the line, with
804784088dfSchristos 				 * the exception of the CR-LF.
805784088dfSchristos 				 */
806784088dfSchristos 				linelen = idx - startidx;
807784088dfSchristos 				idx += 2;
808784088dfSchristos 				goto print;
809784088dfSchristos 			}
810784088dfSchristos 
811784088dfSchristos 			/*
812784088dfSchristos 			 * CR followed by something else; treat this
813784088dfSchristos 			 * as if it were binary data, and don't print
814784088dfSchristos 			 * it.
815784088dfSchristos 			 */
816784088dfSchristos 			return (0);
817c74ad251Schristos 		} else if (!ND_ASCII_ISPRINT(c) && c != '\t') {
818784088dfSchristos 			/*
819784088dfSchristos 			 * Not a printable ASCII character and not a tab;
820784088dfSchristos 			 * treat this as if it were binary data, and
821784088dfSchristos 			 * don't print it.
822784088dfSchristos 			 */
823784088dfSchristos 			return (0);
824784088dfSchristos 		}
825784088dfSchristos 		idx++;
826784088dfSchristos 	}
827784088dfSchristos 
828784088dfSchristos 	/*
829784088dfSchristos 	 * All printable ASCII, but no line ending after that point
830*26ba0b50Schristos 	 * in the buffer.
831784088dfSchristos 	 */
832784088dfSchristos 	linelen = idx - startidx;
833c74ad251Schristos 	ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
834784088dfSchristos 	return (0);
835784088dfSchristos 
836784088dfSchristos print:
837c74ad251Schristos 	ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
838784088dfSchristos 	return (idx);
839784088dfSchristos }
840784088dfSchristos 
841c74ad251Schristos /* Assign needed before calling txtproto_print(): ndo->ndo_protocol = "proto" */
842784088dfSchristos void
843784088dfSchristos txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
844c74ad251Schristos 	       const char **cmds, u_int flags)
845784088dfSchristos {
846784088dfSchristos 	u_int idx, eol;
847784088dfSchristos 	u_char token[MAX_TOKEN+1];
848784088dfSchristos 	const char *cmd;
849c74ad251Schristos 	int print_this = 0;
850784088dfSchristos 
851784088dfSchristos 	if (cmds != NULL) {
852784088dfSchristos 		/*
853784088dfSchristos 		 * This protocol has more than just request and
854784088dfSchristos 		 * response lines; see whether this looks like a
855c74ad251Schristos 		 * request or response and, if so, print it and,
856c74ad251Schristos 		 * in verbose mode, print everything after it.
857c74ad251Schristos 		 *
858c74ad251Schristos 		 * This is for HTTP-like protocols, where we
859c74ad251Schristos 		 * want to print requests and responses, but
860c74ad251Schristos 		 * don't want to print continuations of request
861c74ad251Schristos 		 * or response bodies in packets that don't
862c74ad251Schristos 		 * contain the request or response line.
863784088dfSchristos 		 */
864784088dfSchristos 		idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
865784088dfSchristos 		if (idx != 0) {
866784088dfSchristos 			/* Is this a valid request name? */
867784088dfSchristos 			while ((cmd = *cmds++) != NULL) {
868784088dfSchristos 				if (ascii_strcasecmp((const char *)token, cmd) == 0) {
869784088dfSchristos 					/* Yes. */
870c74ad251Schristos 					print_this = 1;
871784088dfSchristos 					break;
872784088dfSchristos 				}
873784088dfSchristos 			}
874784088dfSchristos 
875784088dfSchristos 			/*
876784088dfSchristos 			 * No - is this a valid response code (3 digits)?
877784088dfSchristos 			 *
878784088dfSchristos 			 * Is this token the response code, or is the next
879784088dfSchristos 			 * token the response code?
880784088dfSchristos 			 */
881784088dfSchristos 			if (flags & RESP_CODE_SECOND_TOKEN) {
882784088dfSchristos 				/*
883784088dfSchristos 				 * Next token - get it.
884784088dfSchristos 				 */
885784088dfSchristos 				idx = fetch_token(ndo, pptr, idx, len, token,
886784088dfSchristos 				    sizeof(token));
887784088dfSchristos 			}
888784088dfSchristos 			if (idx != 0) {
889c74ad251Schristos 				if (ND_ASCII_ISDIGIT(token[0]) && ND_ASCII_ISDIGIT(token[1]) &&
890c74ad251Schristos 				    ND_ASCII_ISDIGIT(token[2]) && token[3] == '\0') {
891784088dfSchristos 					/* Yes. */
892c74ad251Schristos 					print_this = 1;
893784088dfSchristos 				}
894784088dfSchristos 			}
895784088dfSchristos 		}
896784088dfSchristos 	} else {
897784088dfSchristos 		/*
898c74ad251Schristos 		 * Either:
899c74ad251Schristos 		 *
900c74ad251Schristos 		 * 1) This protocol has only request and response lines
901c74ad251Schristos 		 *    (e.g., FTP, where all the data goes over a different
902c74ad251Schristos 		 *    connection); assume the payload is a request or
903c74ad251Schristos 		 *    response.
904c74ad251Schristos 		 *
905c74ad251Schristos 		 * or
906c74ad251Schristos 		 *
907c74ad251Schristos 		 * 2) This protocol is just text, so that we should
908c74ad251Schristos 		 *    always, at minimum, print the first line and,
909c74ad251Schristos 		 *    in verbose mode, print all lines.
910784088dfSchristos 		 */
911c74ad251Schristos 		print_this = 1;
912784088dfSchristos 	}
913784088dfSchristos 
914c74ad251Schristos 	nd_print_protocol_caps(ndo);
915784088dfSchristos 
916c74ad251Schristos 	if (print_this) {
917784088dfSchristos 		/*
918784088dfSchristos 		 * In non-verbose mode, just print the protocol, followed
919c74ad251Schristos 		 * by the first line.
920784088dfSchristos 		 *
921784088dfSchristos 		 * In verbose mode, print lines as text until we run out
922784088dfSchristos 		 * of characters or see something that's not a
923784088dfSchristos 		 * printable-ASCII line.
924784088dfSchristos 		 */
925784088dfSchristos 		if (ndo->ndo_vflag) {
926784088dfSchristos 			/*
927784088dfSchristos 			 * We're going to print all the text lines in the
928784088dfSchristos 			 * request or response; just print the length
929784088dfSchristos 			 * on the first line of the output.
930784088dfSchristos 			 */
931c74ad251Schristos 			ND_PRINT(", length: %u", len);
932784088dfSchristos 			for (idx = 0;
933c74ad251Schristos 			    idx < len && (eol = print_txt_line(ndo, "\n\t", pptr, idx, len)) != 0;
934784088dfSchristos 			    idx = eol)
935784088dfSchristos 				;
936784088dfSchristos 		} else {
937784088dfSchristos 			/*
938784088dfSchristos 			 * Just print the first text line.
939784088dfSchristos 			 */
940c74ad251Schristos 			print_txt_line(ndo, ": ", pptr, 0, len);
941784088dfSchristos 		}
942784088dfSchristos 	}
943784088dfSchristos }
944784088dfSchristos 
945c74ad251Schristos #if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
946c74ad251Schristos     (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \
947c74ad251Schristos     (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \
948c74ad251Schristos     (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \
949c74ad251Schristos     (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || \
950c74ad251Schristos     defined(__vax__)
951784088dfSchristos /*
952c74ad251Schristos  * The processor natively handles unaligned loads, so just use memcpy()
953c74ad251Schristos  * and memcmp(), to enable those optimizations.
954c74ad251Schristos  *
955c74ad251Schristos  * XXX - are those all the x86 tests we need?
956c74ad251Schristos  * XXX - do we need to worry about ARMv1 through ARMv5, which didn't
957c74ad251Schristos  * support unaligned loads, and, if so, do we need to worry about all
958c74ad251Schristos  * of them, or just some of them, e.g. ARMv5?
959c74ad251Schristos  * XXX - are those the only 68k tests we need not to generated
960c74ad251Schristos  * unaligned accesses if the target is the 68000 or 68010?
961c74ad251Schristos  * XXX - are there any tests we don't need, because some definitions are for
962c74ad251Schristos  * compilers that also predefine the GCC symbols?
963c74ad251Schristos  * XXX - do we need to test for both 32-bit and 64-bit versions of those
964c74ad251Schristos  * architectures in all cases?
965c74ad251Schristos  */
966c74ad251Schristos #else
967c74ad251Schristos /*
968c74ad251Schristos  * The processor doesn't natively handle unaligned loads,
969c74ad251Schristos  * and the compiler might "helpfully" optimize memcpy()
970c74ad251Schristos  * and memcmp(), when handed pointers that would normally
971c74ad251Schristos  * be properly aligned, into sequences that assume proper
972c74ad251Schristos  * alignment.
973c74ad251Schristos  *
974c74ad251Schristos  * Do copies and compares of possibly-unaligned data by
975c74ad251Schristos  * calling routines that wrap memcpy() and memcmp(), to
976c74ad251Schristos  * prevent that optimization.
977784088dfSchristos  */
978784088dfSchristos void
979784088dfSchristos unaligned_memcpy(void *p, const void *q, size_t l)
980784088dfSchristos {
981784088dfSchristos 	memcpy(p, q, l);
982784088dfSchristos }
983784088dfSchristos 
984784088dfSchristos /* As with memcpy(), so with memcmp(). */
985784088dfSchristos int
986784088dfSchristos unaligned_memcmp(const void *p, const void *q, size_t l)
987784088dfSchristos {
988784088dfSchristos 	return (memcmp(p, q, l));
989784088dfSchristos }
990784088dfSchristos #endif
991784088dfSchristos 
992