kernel: avoid possible sysctl integer overflow in acpi_thinkpad(4)
[dragonfly.git] / contrib / tcpdump / util-print.c
blob0e30d7900d415211aac45f012ed61725080f6cf0
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
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.
23 * txtproto_print() derived from original code by Hannes Gredler
24 * (hannes@gredler.at):
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.
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
42 #include <netdissect-stdinc.h>
44 #include <sys/stat.h>
46 #ifdef HAVE_FCNTL_H
47 #include <fcntl.h>
48 #endif
49 #include <ctype.h>
50 #include <stdio.h>
51 #include <stdarg.h>
52 #include <stdlib.h>
53 #include <string.h>
55 #include "netdissect.h"
56 #include "ascii_strcasecmp.h"
57 #include "timeval-operations.h"
59 int32_t thiszone; /* seconds offset from gmt to local time */
60 /* invalid string to print '(invalid)' for malformed or corrupted packets */
61 const char istr[] = " (invalid)";
64 * timestamp display buffer size, the biggest size of both formats is needed
65 * sizeof("0000000000.000000000") > sizeof("00:00:00.000000000")
67 #define TS_BUF_SIZE sizeof("0000000000.000000000")
69 #define TOKBUFSIZE 128
72 * Print out a character, filtering out the non-printable ones
74 void
75 fn_print_char(netdissect_options *ndo, u_char c)
77 if (!ND_ISASCII(c)) {
78 c = ND_TOASCII(c);
79 ND_PRINT((ndo, "M-"));
81 if (!ND_ISPRINT(c)) {
82 c ^= 0x40; /* DEL to ?, others to alpha */
83 ND_PRINT((ndo, "^"));
85 ND_PRINT((ndo, "%c", c));
89 * Print out a null-terminated filename (or other ascii string).
90 * If ep is NULL, assume no truncation check is needed.
91 * Return true if truncated.
92 * Stop at ep (if given) or before the null char, whichever is first.
94 int
95 fn_print(netdissect_options *ndo,
96 register const u_char *s, register const u_char *ep)
98 register int ret;
99 register u_char c;
101 ret = 1; /* assume truncated */
102 while (ep == NULL || s < ep) {
103 c = *s++;
104 if (c == '\0') {
105 ret = 0;
106 break;
108 if (!ND_ISASCII(c)) {
109 c = ND_TOASCII(c);
110 ND_PRINT((ndo, "M-"));
112 if (!ND_ISPRINT(c)) {
113 c ^= 0x40; /* DEL to ?, others to alpha */
114 ND_PRINT((ndo, "^"));
116 ND_PRINT((ndo, "%c", c));
118 return(ret);
122 * Print out a null-terminated filename (or other ascii string) from
123 * a fixed-length field in the packet buffer, or from what remains of
124 * the packet.
126 * n is the length of the fixed-length field, or the number of bytes
127 * remaining in the packet based on its on-the-network length.
129 * If ep is non-null, it should point just past the last captured byte
130 * of the packet, e.g. ndo->ndo_snapend. If ep is NULL, we assume no
131 * truncation check, other than the checks of the field length/remaining
132 * packet data length, is needed.
134 * Return the number of bytes of string processed, including the
135 * terminating null, if not truncated; as the terminating null is
136 * included in the count, and as there must be a terminating null,
137 * this will always be non-zero. Return 0 if truncated.
139 u_int
140 fn_printztn(netdissect_options *ndo,
141 register const u_char *s, register u_int n, register const u_char *ep)
143 register u_int bytes;
144 register u_char c;
146 bytes = 0;
147 for (;;) {
148 if (n == 0 || (ep != NULL && s >= ep)) {
150 * Truncated. This includes "no null before we
151 * got to the end of the fixed-length buffer or
152 * the end of the packet".
154 * XXX - BOOTP says "null-terminated", which
155 * means the maximum length of the string, in
156 * bytes, is 1 less than the size of the buffer,
157 * as there must always be a terminating null.
159 bytes = 0;
160 break;
163 c = *s++;
164 bytes++;
165 n--;
166 if (c == '\0') {
167 /* End of string */
168 break;
170 if (!ND_ISASCII(c)) {
171 c = ND_TOASCII(c);
172 ND_PRINT((ndo, "M-"));
174 if (!ND_ISPRINT(c)) {
175 c ^= 0x40; /* DEL to ?, others to alpha */
176 ND_PRINT((ndo, "^"));
178 ND_PRINT((ndo, "%c", c));
180 return(bytes);
184 * Print out a counted filename (or other ascii string).
185 * If ep is NULL, assume no truncation check is needed.
186 * Return true if truncated.
187 * Stop at ep (if given) or after n bytes, whichever is first.
190 fn_printn(netdissect_options *ndo,
191 register const u_char *s, register u_int n, register const u_char *ep)
193 register u_char c;
195 while (n > 0 && (ep == NULL || s < ep)) {
196 n--;
197 c = *s++;
198 if (!ND_ISASCII(c)) {
199 c = ND_TOASCII(c);
200 ND_PRINT((ndo, "M-"));
202 if (!ND_ISPRINT(c)) {
203 c ^= 0x40; /* DEL to ?, others to alpha */
204 ND_PRINT((ndo, "^"));
206 ND_PRINT((ndo, "%c", c));
208 return (n == 0) ? 0 : 1;
212 * Print out a null-padded filename (or other ascii string).
213 * If ep is NULL, assume no truncation check is needed.
214 * Return true if truncated.
215 * Stop at ep (if given) or after n bytes or before the null char,
216 * whichever is first.
219 fn_printzp(netdissect_options *ndo,
220 register const u_char *s, register u_int n,
221 register const u_char *ep)
223 register int ret;
224 register u_char c;
226 ret = 1; /* assume truncated */
227 while (n > 0 && (ep == NULL || s < ep)) {
228 n--;
229 c = *s++;
230 if (c == '\0') {
231 ret = 0;
232 break;
234 if (!ND_ISASCII(c)) {
235 c = ND_TOASCII(c);
236 ND_PRINT((ndo, "M-"));
238 if (!ND_ISPRINT(c)) {
239 c ^= 0x40; /* DEL to ?, others to alpha */
240 ND_PRINT((ndo, "^"));
242 ND_PRINT((ndo, "%c", c));
244 return (n == 0) ? 0 : ret;
248 * Format the timestamp
250 static char *
251 ts_format(netdissect_options *ndo
252 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
254 #endif
255 , int sec, int usec, char *buf)
257 const char *format;
259 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
260 switch (ndo->ndo_tstamp_precision) {
262 case PCAP_TSTAMP_PRECISION_MICRO:
263 format = "%02d:%02d:%02d.%06u";
264 break;
266 case PCAP_TSTAMP_PRECISION_NANO:
267 format = "%02d:%02d:%02d.%09u";
268 break;
270 default:
271 format = "%02d:%02d:%02d.{unknown}";
272 break;
274 #else
275 format = "%02d:%02d:%02d.%06u";
276 #endif
278 snprintf(buf, TS_BUF_SIZE, format,
279 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
281 return buf;
285 * Format the timestamp - Unix timeval style
287 static char *
288 ts_unix_format(netdissect_options *ndo
289 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
291 #endif
292 , int sec, int usec, char *buf)
294 const char *format;
296 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
297 switch (ndo->ndo_tstamp_precision) {
299 case PCAP_TSTAMP_PRECISION_MICRO:
300 format = "%u.%06u";
301 break;
303 case PCAP_TSTAMP_PRECISION_NANO:
304 format = "%u.%09u";
305 break;
307 default:
308 format = "%u.{unknown}";
309 break;
311 #else
312 format = "%u.%06u";
313 #endif
315 snprintf(buf, TS_BUF_SIZE, format,
316 (unsigned)sec, (unsigned)usec);
318 return buf;
322 * Print the timestamp
324 void
325 ts_print(netdissect_options *ndo,
326 register const struct timeval *tvp)
328 register int s;
329 struct tm *tm;
330 time_t Time;
331 char buf[TS_BUF_SIZE];
332 static struct timeval tv_ref;
333 struct timeval tv_result;
334 int negative_offset;
335 int nano_prec;
337 switch (ndo->ndo_tflag) {
339 case 0: /* Default */
340 s = (tvp->tv_sec + thiszone) % 86400;
341 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec, buf)));
342 break;
344 case 1: /* No time stamp */
345 break;
347 case 2: /* Unix timeval style */
348 ND_PRINT((ndo, "%s ", ts_unix_format(ndo,
349 tvp->tv_sec, tvp->tv_usec, buf)));
350 break;
352 case 3: /* Microseconds/nanoseconds since previous packet */
353 case 5: /* Microseconds/nanoseconds since first packet */
354 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
355 switch (ndo->ndo_tstamp_precision) {
356 case PCAP_TSTAMP_PRECISION_MICRO:
357 nano_prec = 0;
358 break;
359 case PCAP_TSTAMP_PRECISION_NANO:
360 nano_prec = 1;
361 break;
362 default:
363 nano_prec = 0;
364 break;
366 #else
367 nano_prec = 0;
368 #endif
369 if (!(netdissect_timevalisset(&tv_ref)))
370 tv_ref = *tvp; /* set timestamp for first packet */
372 negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
373 if (negative_offset)
374 netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
375 else
376 netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
378 ND_PRINT((ndo, (negative_offset ? "-" : " ")));
380 ND_PRINT((ndo, "%s ", ts_format(ndo,
381 tv_result.tv_sec, tv_result.tv_usec, buf)));
383 if (ndo->ndo_tflag == 3)
384 tv_ref = *tvp; /* set timestamp for previous packet */
385 break;
387 case 4: /* Default + Date */
388 s = (tvp->tv_sec + thiszone) % 86400;
389 Time = (tvp->tv_sec + thiszone) - s;
390 tm = gmtime (&Time);
391 if (!tm)
392 ND_PRINT((ndo, "Date fail "));
393 else
394 ND_PRINT((ndo, "%04d-%02d-%02d %s ",
395 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
396 ts_format(ndo, s, tvp->tv_usec, buf)));
397 break;
402 * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
403 * in the form 5m1s. This does no truncation, so 32230861 seconds
404 * is represented as 1y1w1d1h1m1s.
406 void
407 unsigned_relts_print(netdissect_options *ndo,
408 uint32_t secs)
410 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
411 static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
412 const char **l = lengths;
413 const u_int *s = seconds;
415 if (secs == 0) {
416 ND_PRINT((ndo, "0s"));
417 return;
419 while (secs > 0) {
420 if (secs >= *s) {
421 ND_PRINT((ndo, "%d%s", secs / *s, *l));
422 secs -= (secs / *s) * *s;
424 s++;
425 l++;
430 * Print a signed relative number of seconds (e.g. hold time, prune timer)
431 * in the form 5m1s. This does no truncation, so 32230861 seconds
432 * is represented as 1y1w1d1h1m1s.
434 void
435 signed_relts_print(netdissect_options *ndo,
436 int32_t secs)
438 if (secs < 0) {
439 ND_PRINT((ndo, "-"));
440 if (secs == INT32_MIN) {
442 * -2^31; you can't fit its absolute value into
443 * a 32-bit signed integer.
445 * Just directly pass said absolute value to
446 * unsigned_relts_print() directly.
448 * (XXX - does ISO C guarantee that -(-2^n),
449 * when calculated and cast to an n-bit unsigned
450 * integer type, will have the value 2^n?)
452 unsigned_relts_print(ndo, 2147483648U);
453 } else {
455 * We now know -secs will fit into an int32_t;
456 * negate it and pass that to unsigned_relts_print().
458 unsigned_relts_print(ndo, -secs);
460 return;
462 unsigned_relts_print(ndo, secs);
466 * this is a generic routine for printing unknown data;
467 * we pass on the linefeed plus indentation string to
468 * get a proper output - returns 0 on error
472 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
474 if (len < 0) {
475 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
476 ident));
477 return(0);
479 if (ndo->ndo_snapend - cp < len)
480 len = ndo->ndo_snapend - cp;
481 if (len < 0) {
482 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
483 ident));
484 return(0);
486 hex_print(ndo, ident,cp,len);
487 return(1); /* everything is ok */
491 * Convert a token value to a string; use "fmt" if not found.
493 const char *
494 tok2strbuf(register const struct tok *lp, register const char *fmt,
495 register u_int v, char *buf, size_t bufsize)
497 if (lp != NULL) {
498 while (lp->s != NULL) {
499 if (lp->v == v)
500 return (lp->s);
501 ++lp;
504 if (fmt == NULL)
505 fmt = "#%d";
507 (void)snprintf(buf, bufsize, fmt, v);
508 return (const char *)buf;
512 * Convert a token value to a string; use "fmt" if not found.
514 const char *
515 tok2str(register const struct tok *lp, register const char *fmt,
516 register u_int v)
518 static char buf[4][TOKBUFSIZE];
519 static int idx = 0;
520 char *ret;
522 ret = buf[idx];
523 idx = (idx+1) & 3;
524 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
528 * Convert a bit token value to a string; use "fmt" if not found.
529 * this is useful for parsing bitfields, the output strings are seperated
530 * if the s field is positive.
532 static char *
533 bittok2str_internal(register const struct tok *lp, register const char *fmt,
534 register u_int v, const char *sep)
536 static char buf[1024+1]; /* our string buffer */
537 char *bufp = buf;
538 size_t space_left = sizeof(buf), string_size;
539 register u_int rotbit; /* this is the bit we rotate through all bitpositions */
540 register u_int tokval;
541 const char * sepstr = "";
543 while (lp != NULL && lp->s != NULL) {
544 tokval=lp->v; /* load our first value */
545 rotbit=1;
546 while (rotbit != 0) {
548 * lets AND the rotating bit with our token value
549 * and see if we have got a match
551 if (tokval == (v&rotbit)) {
552 /* ok we have found something */
553 if (space_left <= 1)
554 return (buf); /* only enough room left for NUL, if that */
555 string_size = strlcpy(bufp, sepstr, space_left);
556 if (string_size >= space_left)
557 return (buf); /* we ran out of room */
558 bufp += string_size;
559 space_left -= string_size;
560 if (space_left <= 1)
561 return (buf); /* only enough room left for NUL, if that */
562 string_size = strlcpy(bufp, lp->s, space_left);
563 if (string_size >= space_left)
564 return (buf); /* we ran out of room */
565 bufp += string_size;
566 space_left -= string_size;
567 sepstr = sep;
568 break;
570 rotbit=rotbit<<1; /* no match - lets shift and try again */
572 lp++;
575 if (bufp == buf)
576 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
577 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
578 return (buf);
582 * Convert a bit token value to a string; use "fmt" if not found.
583 * this is useful for parsing bitfields, the output strings are not seperated.
585 char *
586 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
587 register u_int v)
589 return (bittok2str_internal(lp, fmt, v, ""));
593 * Convert a bit token value to a string; use "fmt" if not found.
594 * this is useful for parsing bitfields, the output strings are comma seperated.
596 char *
597 bittok2str(register const struct tok *lp, register const char *fmt,
598 register u_int v)
600 return (bittok2str_internal(lp, fmt, v, ", "));
604 * Convert a value to a string using an array; the macro
605 * tok2strary() in <netdissect.h> is the public interface to
606 * this function and ensures that the second argument is
607 * correct for bounds-checking.
609 const char *
610 tok2strary_internal(register const char **lp, int n, register const char *fmt,
611 register int v)
613 static char buf[TOKBUFSIZE];
615 if (v >= 0 && v < n && lp[v] != NULL)
616 return lp[v];
617 if (fmt == NULL)
618 fmt = "#%d";
619 (void)snprintf(buf, sizeof(buf), fmt, v);
620 return (buf);
624 * Convert a 32-bit netmask to prefixlen if possible
625 * the function returns the prefix-len; if plen == -1
626 * then conversion was not possible;
630 mask2plen(uint32_t mask)
632 uint32_t bitmasks[33] = {
633 0x00000000,
634 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
635 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
636 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
637 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
638 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
639 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
640 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
641 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
643 int prefix_len = 32;
645 /* let's see if we can transform the mask into a prefixlen */
646 while (prefix_len >= 0) {
647 if (bitmasks[prefix_len] == mask)
648 break;
649 prefix_len--;
651 return (prefix_len);
655 mask62plen(const u_char *mask)
657 u_char bitmasks[9] = {
658 0x00,
659 0x80, 0xc0, 0xe0, 0xf0,
660 0xf8, 0xfc, 0xfe, 0xff
662 int byte;
663 int cidr_len = 0;
665 for (byte = 0; byte < 16; byte++) {
666 u_int bits;
668 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
669 if (mask[byte] == bitmasks[bits]) {
670 cidr_len += bits;
671 break;
675 if (mask[byte] != 0xff)
676 break;
678 return (cidr_len);
682 * Routine to print out information for text-based protocols such as FTP,
683 * HTTP, SMTP, RTSP, SIP, ....
685 #define MAX_TOKEN 128
688 * Fetch a token from a packet, starting at the specified index,
689 * and return the length of the token.
691 * Returns 0 on error; yes, this is indistinguishable from an empty
692 * token, but an "empty token" isn't a valid token - it just means
693 * either a space character at the beginning of the line (this
694 * includes a blank line) or no more tokens remaining on the line.
696 static int
697 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
698 u_char *tbuf, size_t tbuflen)
700 size_t toklen = 0;
702 for (; idx < len; idx++) {
703 if (!ND_TTEST(*(pptr + idx))) {
704 /* ran past end of captured data */
705 return (0);
707 if (!isascii(*(pptr + idx))) {
708 /* not an ASCII character */
709 return (0);
711 if (isspace(*(pptr + idx))) {
712 /* end of token */
713 break;
715 if (!isprint(*(pptr + idx))) {
716 /* not part of a command token or response code */
717 return (0);
719 if (toklen + 2 > tbuflen) {
720 /* no room for this character and terminating '\0' */
721 return (0);
723 tbuf[toklen] = *(pptr + idx);
724 toklen++;
726 if (toklen == 0) {
727 /* no token */
728 return (0);
730 tbuf[toklen] = '\0';
733 * Skip past any white space after the token, until we see
734 * an end-of-line (CR or LF).
736 for (; idx < len; idx++) {
737 if (!ND_TTEST(*(pptr + idx))) {
738 /* ran past end of captured data */
739 break;
741 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
742 /* end of line */
743 break;
745 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
746 /* not a printable ASCII character */
747 break;
749 if (!isspace(*(pptr + idx))) {
750 /* beginning of next token */
751 break;
754 return (idx);
758 * Scan a buffer looking for a line ending - LF or CR-LF.
759 * Return the index of the character after the line ending or 0 if
760 * we encounter a non-ASCII or non-printable character or don't find
761 * the line ending.
763 static u_int
764 print_txt_line(netdissect_options *ndo, const char *protoname,
765 const char *prefix, const u_char *pptr, u_int idx, u_int len)
767 u_int startidx;
768 u_int linelen;
770 startidx = idx;
771 while (idx < len) {
772 ND_TCHECK(*(pptr+idx));
773 if (*(pptr+idx) == '\n') {
775 * LF without CR; end of line.
776 * Skip the LF and print the line, with the
777 * exception of the LF.
779 linelen = idx - startidx;
780 idx++;
781 goto print;
782 } else if (*(pptr+idx) == '\r') {
783 /* CR - any LF? */
784 if ((idx+1) >= len) {
785 /* not in this packet */
786 return (0);
788 ND_TCHECK(*(pptr+idx+1));
789 if (*(pptr+idx+1) == '\n') {
791 * CR-LF; end of line.
792 * Skip the CR-LF and print the line, with
793 * the exception of the CR-LF.
795 linelen = idx - startidx;
796 idx += 2;
797 goto print;
801 * CR followed by something else; treat this
802 * as if it were binary data, and don't print
803 * it.
805 return (0);
806 } else if (!isascii(*(pptr+idx)) ||
807 (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
809 * Not a printable ASCII character and not a tab;
810 * treat this as if it were binary data, and
811 * don't print it.
813 return (0);
815 idx++;
819 * All printable ASCII, but no line ending after that point
820 * in the buffer; treat this as if it were truncated.
822 trunc:
823 linelen = idx - startidx;
824 ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
825 protoname));
826 return (0);
828 print:
829 ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
830 return (idx);
833 void
834 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
835 const char *protoname, const char **cmds, u_int flags)
837 u_int idx, eol;
838 u_char token[MAX_TOKEN+1];
839 const char *cmd;
840 int is_reqresp = 0;
841 const char *pnp;
843 if (cmds != NULL) {
845 * This protocol has more than just request and
846 * response lines; see whether this looks like a
847 * request or response.
849 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
850 if (idx != 0) {
851 /* Is this a valid request name? */
852 while ((cmd = *cmds++) != NULL) {
853 if (ascii_strcasecmp((const char *)token, cmd) == 0) {
854 /* Yes. */
855 is_reqresp = 1;
856 break;
861 * No - is this a valid response code (3 digits)?
863 * Is this token the response code, or is the next
864 * token the response code?
866 if (flags & RESP_CODE_SECOND_TOKEN) {
868 * Next token - get it.
870 idx = fetch_token(ndo, pptr, idx, len, token,
871 sizeof(token));
873 if (idx != 0) {
874 if (isdigit(token[0]) && isdigit(token[1]) &&
875 isdigit(token[2]) && token[3] == '\0') {
876 /* Yes. */
877 is_reqresp = 1;
881 } else {
883 * This protocol has only request and response lines
884 * (e.g., FTP, where all the data goes over a
885 * different connection); assume the payload is
886 * a request or response.
888 is_reqresp = 1;
891 /* Capitalize the protocol name */
892 for (pnp = protoname; *pnp != '\0'; pnp++)
893 ND_PRINT((ndo, "%c", toupper((u_char)*pnp)));
895 if (is_reqresp) {
897 * In non-verbose mode, just print the protocol, followed
898 * by the first line as the request or response info.
900 * In verbose mode, print lines as text until we run out
901 * of characters or see something that's not a
902 * printable-ASCII line.
904 if (ndo->ndo_vflag) {
906 * We're going to print all the text lines in the
907 * request or response; just print the length
908 * on the first line of the output.
910 ND_PRINT((ndo, ", length: %u", len));
911 for (idx = 0;
912 idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
913 idx = eol)
915 } else {
917 * Just print the first text line.
919 print_txt_line(ndo, protoname, ": ", pptr, 0, len);
924 void
925 safeputs(netdissect_options *ndo,
926 const u_char *s, const u_int maxlen)
928 u_int idx = 0;
930 while (idx < maxlen && *s) {
931 safeputchar(ndo, *s);
932 idx++;
933 s++;
937 void
938 safeputchar(netdissect_options *ndo,
939 const u_char c)
941 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
944 #ifdef LBL_ALIGN
946 * Some compilers try to optimize memcpy(), using the alignment constraint
947 * on the argument pointer type. by using this function, we try to avoid the
948 * optimization.
950 void
951 unaligned_memcpy(void *p, const void *q, size_t l)
953 memcpy(p, q, l);
956 /* As with memcpy(), so with memcmp(). */
958 unaligned_memcmp(const void *p, const void *q, size_t l)
960 return (memcmp(p, q, l));
962 #endif