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