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