From: Guy Harris Date: Tue, 1 Aug 2023 09:02:56 +0000 (-0700) Subject: Redo DLT_/LINKTYPE_ translation. X-Git-Url: https://git.tcpdump.org/libpcap/commitdiff_plain/5daaba1b5d45d111cbd4348d6d4e77fca12953a9 Redo DLT_/LINKTYPE_ translation. Do it with a bunch of ifs rather than with a translation table; that lets the logic work differently for DLT_ -> LINKTYPE_ mapping and LINKTYPE_ -> DLT_ mapping. Have two "matching" ranges, so that the linktypes that preceded the BSDs all going off in their own directions can be handled as a matching range. Avoid doing mapping if the corresponding LINKTYPE_ and DLT_ codes have the same numerical value. For LINKTYPE_ -> DLT_ mapping, don't map link-layer type values outside either of the matching ranges if we don't have a specific mapping set up for them, just treat the LINKTYPE_ value as if it's a DLT_ value. That makes us handle some DLT_ codes outside the high mapping range to which we assigned matching LINKTYPE_ codes, as well as attempting, as best we can, files written with platform-dependent DLT_ codes (such as DLT_RAW) as link-layer type codes (programs *on that platform* will handle them correctly; programs will not do so on other platforms, but that's better than not handling them correctly anywhere). Update various comments. --- diff --git a/gencode.c b/gencode.c index 8f055492..21ad1733 100644 --- a/gencode.c +++ b/gencode.c @@ -1722,15 +1722,15 @@ init_linktype(compiler_state_t *cstate, pcap_t *p) * For values in the range in which we've assigned new * DLT_ values, only raw "link[N:M]" filtering is supported. */ - if (cstate->linktype >= DLT_MATCHING_MIN && - cstate->linktype <= DLT_MATCHING_MAX) { + if (cstate->linktype >= DLT_HIGH_MATCHING_MIN && + cstate->linktype <= DLT_HIGH_MATCHING_MAX) { cstate->off_linktype.constant_part = OFFSET_NOT_SET; cstate->off_linkpl.constant_part = OFFSET_NOT_SET; cstate->off_nl = OFFSET_NOT_SET; cstate->off_nl_nosnap = OFFSET_NOT_SET; } else { bpf_set_error(cstate, "unknown data link type %d (min %d, max %d)", - cstate->linktype, DLT_MATCHING_MIN, DLT_MATCHING_MAX); + cstate->linktype, DLT_HIGH_MATCHING_MIN, DLT_HIGH_MATCHING_MAX); return (-1); } break; diff --git a/pcap-common.c b/pcap-common.c index 21cf204c..5eb3370b 100644 --- a/pcap-common.c +++ b/pcap-common.c @@ -99,6 +99,17 @@ * defining DLT_* values that collide with those * LINKTYPE_* values, either). */ + +/* + * These values the DLT_ values for which are the same on all platforms, + * and that have been defined by for ages. + * + * For those, the LINKTYPE_ values are equal to the DLT_ values. + * + * LINKTYPE_LOW_MATCHING_MIN is the lowest such value; + * LINKTYPE_LOW_MATCHING_MAX is the highest such value. + */ +#define LINKTYPE_LOW_MATCHING_MIN 0 /* lowest value in this "matching" range */ #define LINKTYPE_NULL DLT_NULL #define LINKTYPE_ETHERNET DLT_EN10MB /* also for 100Mb and up */ #define LINKTYPE_EXP_ETHERNET DLT_EN3MB /* 3Mb experimental Ethernet */ @@ -111,6 +122,8 @@ #define LINKTYPE_PPP DLT_PPP #define LINKTYPE_FDDI DLT_FDDI +#define LINKTYPE_LOW_MATCHING_MAX LINKTYPE_FDDI /* highest value in this "matching" range */ + /* * LINKTYPE_PPP is for use when there might, or might not, be an RFC 1662 * PPP in HDLC-like framing header (with 0xff 0x03 before the PPP protocol @@ -150,10 +163,10 @@ * and the LINKTYPE_ value that appears in capture files, are the * same. * - * LINKTYPE_MATCHING_MIN is the lowest such value; LINKTYPE_MATCHING_MAX - * is the highest such value. + * LINKTYPE_HIGH_MATCHING_MIN is the lowest such value; + * LINKTYPE_HIGH_MATCHING_MAX is the highest such value. */ -#define LINKTYPE_MATCHING_MIN 104 /* lowest value in the "matching" range */ +#define LINKTYPE_HIGH_MATCHING_MIN 104 /* lowest value in the "matching" range */ #define LINKTYPE_C_HDLC 104 /* Cisco HDLC */ #define LINKTYPE_IEEE802_11 105 /* IEEE 802.11 (wireless) */ @@ -917,7 +930,6 @@ * shiny new link-layer header type value that doesn't collide with * anything, in the hopes that future pfsync savefiles, if any, * won't require special hacks to distinguish from other savefiles. - * */ #define LINKTYPE_PFSYNC 246 @@ -1257,168 +1269,287 @@ */ #define LINKTYPE_FIRA_UCI 299 -#define LINKTYPE_MATCHING_MAX 299 /* highest value in the "matching" range */ +#define LINKTYPE_HIGH_MATCHING_MAX 299 /* highest value in the "matching" range */ /* * The DLT_ and LINKTYPE_ values in the "matching" range should be the - * same, so DLT_MATCHING_MAX and LINKTYPE_MATCHING_MAX should be the + * same, so DLT_HIGH_MATCHING_MAX and LINKTYPE_HIGH_MATCHING_MAX should be the * same. */ -#if LINKTYPE_MATCHING_MAX != DLT_MATCHING_MAX -#error The LINKTYPE_ matching range does not match the DLT_ matching range +#if LINKTYPE_HIGH_MATCHING_MAX != DLT_HIGH_MATCHING_MAX +#error The LINKTYPE_ high matching range does not match the DLT_ matching range #endif -static struct linktype_map { - int dlt; - int linktype; -} map[] = { +/* + * Map a DLT_* code to the corresponding LINKTYPE_* code. + * Used to generate link-layer types written to savefiles. + */ +int +dlt_to_linktype(int dlt) +{ /* - * These DLT_* codes have LINKTYPE_* codes with values identical - * to the values of the corresponding DLT_* code. + * All values in the low matching range were handed out before + * assigning DLT_* codes became a free-for-all, so they're the + * same on all platforms, and thus are given LINKTYPE_* codes + * with the same numerical values as the corresponding DLT_* + * code. */ - { DLT_NULL, LINKTYPE_NULL }, - { DLT_EN10MB, LINKTYPE_ETHERNET }, - { DLT_EN3MB, LINKTYPE_EXP_ETHERNET }, - { DLT_AX25, LINKTYPE_AX25 }, - { DLT_PRONET, LINKTYPE_PRONET }, - { DLT_CHAOS, LINKTYPE_CHAOS }, - { DLT_IEEE802, LINKTYPE_IEEE802_5 }, - { DLT_ARCNET, LINKTYPE_ARCNET_BSD }, - { DLT_SLIP, LINKTYPE_SLIP }, - { DLT_PPP, LINKTYPE_PPP }, - { DLT_FDDI, LINKTYPE_FDDI }, - { DLT_SYMANTEC_FIREWALL, LINKTYPE_SYMANTEC_FIREWALL }, + if (dlt >= DLT_LOW_MATCHING_MIN && dlt <= DLT_LOW_MATCHING_MAX) + return (dlt); +#if DLT_PFSYNC != LINKTYPE_PFSYNC /* - * These DLT_* codes have different values on different - * platforms; we map them to LINKTYPE_* codes that - * have values that should never be equal to any DLT_* - * code. + * DLT_PFSYNC has a code on several platforms that's in the + * non-matching range, a code on FreeBSD that's in the high + * matching range and that's *not* equal to LINKTYPE_PFSYNC, + * and has a code on the rmaining platforms that's equal + * to LINKTYPE_PFSYNC, which is in the high matching range. + * + * Map it to LINKTYPE_PFSYNC if it's not equal to LINKTYPE_PFSYNC. */ -#ifdef DLT_FR - /* BSD/OS Frame Relay */ - { DLT_FR, LINKTYPE_FRELAY }, + if (dlt == DLT_PFSYNC) + return (LINKTYPE_PFSYNC); #endif - { DLT_ATM_RFC1483, LINKTYPE_ATM_RFC1483 }, - { DLT_RAW, LINKTYPE_RAW }, - { DLT_SLIP_BSDOS, LINKTYPE_SLIP_BSDOS }, - { DLT_PPP_BSDOS, LINKTYPE_PPP_BSDOS }, - { DLT_HDLC, LINKTYPE_NETBSD_HDLC }, - - /* BSD/OS Cisco HDLC */ - { DLT_C_HDLC, LINKTYPE_C_HDLC }, - /* - * These DLT_* codes are not on all platforms, but, so far, - * there don't appear to be any platforms that define - * other codes with those values; we map them to - * different LINKTYPE_* values anyway, just in case. + * DLT_PKTAP is defined as DLT_USER2 - which is in the high + * matching range - on Darwin because Apple used DLT_USER2 + * on systems that users ran, not just as an internal thing. + * + * We map it to LINKTYPE_PKTAP if it's not equal to LINKTYPE_PKTAP + * so that DLT_PKTAP captures from Apple machines can be read by + * software that either doesn't handle DLT_USER2 or that handles it + * as something other than Apple PKTAP. */ - - /* Linux ATM Classical IP */ - { DLT_ATM_CLIP, LINKTYPE_ATM_CLIP }, - - /* NetBSD sync/async serial PPP (or Cisco HDLC) */ - { DLT_PPP_SERIAL, LINKTYPE_PPP_HDLC }, - - /* NetBSD PPP over Ethernet */ - { DLT_PPP_ETHER, LINKTYPE_PPP_ETHER }, +#if DLT_PKTAP != LINKTYPE_PKTAP + if (dlt == DLT_PKTAP) + return (LINKTYPE_PKTAP); +#endif /* - * All LINKTYPE_ values between LINKTYPE_MATCHING_MIN - * and LINKTYPE_MATCHING_MAX are mapped to identical - * DLT_ values. + * For all other DLT_* codes in the high matching range, the DLT + * code value is the same as the LINKTYPE_* code value. */ + if (dlt >= DLT_HIGH_MATCHING_MIN && dlt <= DLT_HIGH_MATCHING_MAX) + return (dlt); - { -1, -1 } -}; - -int -dlt_to_linktype(int dlt) -{ - int i; + /* + * These DLT_* codes have different values on different + * platforms, so we assigned them LINKTYPE_* codes just + * below the lower bound of the high matchig range; + * those values should never be equal to any DLT_* + * code, so that should avoid collisions. + * + * That way, for example, "raw IP" packets will have + * LINKTYPE_RAW as the code in all savefiles for + * which the code that writes them maps to that + * value, regardless of the platform on whih they + * were written, so they should be readable on all + * platforms without having to determine on which + * platform they were written. + * + * We map the DLT_* codes on this platform, whatever + * it might be, to the corresponding LINKTYPE_* codes. + */ + if (dlt == DLT_ATM_RFC1483) + return (LINKTYPE_ATM_RFC1483); + if (dlt == DLT_RAW) + return (LINKTYPE_RAW); + if (dlt == DLT_SLIP_BSDOS) + return (LINKTYPE_SLIP_BSDOS); + if (dlt == DLT_PPP_BSDOS) + return (LINKTYPE_PPP_BSDOS); /* - * DLTs that, on some platforms, have values in the matching range - * but that *don't* have the same value as the corresponding - * LINKTYPE because, for some reason, not all OSes have the - * same value for that DLT (note that the DLT's value might be - * outside the matching range on some of those OSes). + * These DLT_* codes were originally defined on some platform, + * and weren't defined on other platforms. + * + * At least some of them have values, on at least one platform, + * that collide with other DLT_* codes on other platforms, e.g. + * DLT_LOOP, so we don't just define them, on all platforms, + * as having the same value as on the original platform. + * + * Therefore, we assigned new LINKTYPE_* codes to them, and, + * on the platforms where they weren't originally defined, + * define the DLT_* codes to have the same value as the + * corresponding LINKTYPE_* codes. + * + * This means that, for capture files with the original + * platform's DLT_* code rather than the LINKTYPE_* code + * as a link-layer type, we will recognize those types + * on that platform, but not on other platforms. */ - if (dlt == DLT_PFSYNC) - return (LINKTYPE_PFSYNC); - if (dlt == DLT_PKTAP) - return (LINKTYPE_PKTAP); +#ifdef DLT_FR + /* BSD/OS Frame Relay */ + if (dlt = DLT_FR) + return (LINKTYPE_FRELAY); +#endif +#if DLT_HDLC != LINKTYPE_NETBSD_HDLC + /* NetBSD HDLC */ + if (dlt == DLT_HDLC) + return (LINKTYPE_NETBSD_HDLC); +#endif +#if DLT_C_HDLC != LINKTYPE_C_HDLC + /* BSD/OS Cisco HDLC */ + if (dlt == DLT_C_HDLC) + return (LINKTYPE_C_HDLC); +#endif +#if DLT_LOOP != LINKTYPE_LOOP + /* OpenBSD DLT_LOOP */ + if (dlt == DLT_LOOP) + return (LINKTYPE_LOOP); +#endif +#if DLT_ENC != LINKTYPE_ENC + /* OpenBSD DLT_ENC */ + if (dlt == DLT_ENC) + return (LINKTYPE_ENC); +#endif /* - * For all other values in the matching range, the DLT - * value is the same as the LINKTYPE value. + * These DLT_* codes are not on all platforms, but, so far, + * there don't appear to be any platforms that define + * other codes with those values; we map them to + * different LINKTYPE_* codes anyway, just in case. */ - if (dlt >= DLT_MATCHING_MIN && dlt <= DLT_MATCHING_MAX) - return (dlt); + /* Linux ATM Classical IP */ + if (dlt == DLT_ATM_CLIP) + return (LINKTYPE_ATM_CLIP); /* - * Map the values outside that range. + * A few other values, defined on some platforms, not in + * either matching range, but not colliding with anything + * else, so they're given the same LINKTYPE_* code as + * their DLT_* code. */ - for (i = 0; map[i].dlt != -1; i++) { - if (map[i].dlt == dlt) - return (map[i].linktype); - } + if (dlt == DLT_REDBACK_SMARTEDGE || dlt == DLT_PPP_SERIAL || + dlt == DLT_PPP_ETHER || dlt == DLT_SYMANTEC_FIREWALL) + return (dlt); /* - * If we don't have a mapping for this DLT, return an - * error; that means that this is a value with no corresponding - * LINKTYPE, and we need to assign one. + * If we don't have a mapping for this DLT_* code, return an + * error; that means that this is a DLT_* value with no + * corresponding LINKTYPE_ value, and we need to assign one. */ return (-1); } +/* + * Map a LINKTYPE_* code to the corresponding DLT_* code. + * Used to translate link-layer types in savefiles to the + * DLT_* codes to provide to callers of libpcap. + */ int linktype_to_dlt(int linktype) { - int i; + /* + * All values in the low matching range were handed out before + * assigning DLT_* codes became a free-for-all, so they're the + * same on all platforms, and are thus used as the LINKTYPE_* + * codes in capture files. + */ + if (linktype >= LINKTYPE_LOW_MATCHING_MIN && + linktype <= LINKTYPE_LOW_MATCHING_MAX) + return (linktype); +#if LINKTYPE_PFSYNC != DLT_PFSYNC /* - * LINKTYPEs in the matching range that *don't* - * have the same value as the corresponding DLTs - * because, for some reason, not all OSes have the - * same value for that DLT. + * DLT_PFSYNC has a code on several platforms that's in the + * non-matching range, a code on FreeBSD that's in the high + * matching range and that's *not* equal to LINKTYPE_PFSYNC, + * and has a code on the rmaining platforms that's equal + * to LINKTYPE_PFSYNC, which is in the high matching range. + * + * Map LINKTYPE_PFSYNC to whatever DLT_PFSYNC is on this + * platform, if the two aren't equal. */ if (linktype == LINKTYPE_PFSYNC) return (DLT_PFSYNC); +#endif + + /* + * DLT_PKTAP is defined as DLT_USER2 - which is in the high + * matching range - on Darwin because Apple used DLT_USER2 + * on systems that users ran, not just as an internal thing. + * + * We map LINKTYPE_PKTAP to the platform's DLT_PKTAP for + * the benefit of software that's expecting DLT_PKTAP + * (even if that's DLT_USER2) for an Apple PKTAP capture. + * + * (Yes, this is an annoyance if you want to read a + * LINKTYPE_USER2 packet as something other than DLT_PKTAP + * on a Darwin-based OS, as, on that OS, DLT_PKTAP and DLT_USER2 + * are the same. Feel free to complain to Apple about this.) + */ +#if LINKTYPE_PKTAP != DLT_PKTAP if (linktype == LINKTYPE_PKTAP) return (DLT_PKTAP); +#endif /* - * For all other values in the matching range, except for - * LINKTYPE_ATM_CLIP, the LINKTYPE value is the same as - * the DLT value. + * These DLT_* codes have different values on different + * platforms, so we assigned them LINKTYPE_* codes just + * below the lower bound of the high matchig range; + * those values should never be equal to any DLT_* + * code, so that should avoid collisions. + * + * That way, for example, "raw IP" packets will have + * LINKTYPE_RAW as the code in all savefiles for + * which the code that writes them maps to that + * value, regardless of the platform on whih they + * were written, so they should be readable on all + * platforms without having to determine on which + * platform they were written. + * + * We map the LINKTYPE_* codes to the corresponding + * DLT_* code on this platform. + */ + if (linktype == LINKTYPE_ATM_RFC1483) + return (DLT_ATM_RFC1483); + if (linktype == LINKTYPE_RAW) + return (DLT_RAW); + if (linktype == LINKTYPE_SLIP_BSDOS) + return (DLT_SLIP_BSDOS); + if (linktype == LINKTYPE_PPP_BSDOS) + return (DLT_PPP_BSDOS); + + /* + * These DLT_* codes are not on all platforms, but, so far, + * there don't appear to be any platforms that define + * other codes with those values; we map them to + * different LINKTYPE_* values anyway, just in case. * * LINKTYPE_ATM_CLIP is a special case. DLT_ATM_CLIP is * not on all platforms, but, so far, there don't appear * to be any platforms that define it as anything other * than 19; we define LINKTYPE_ATM_CLIP as something * other than 19, just in case. That value is in the - * matching range, so we have to check for it. - */ - if (linktype >= LINKTYPE_MATCHING_MIN && - linktype <= LINKTYPE_MATCHING_MAX && - linktype != LINKTYPE_ATM_CLIP) - return (linktype); - - /* - * Map the values outside that range. + * high matching range, so we have to check for it. */ - for (i = 0; map[i].linktype != -1; i++) { - if (map[i].linktype == linktype) - return (map[i].dlt); - } + /* Linux ATM Classical IP */ + if (linktype == LINKTYPE_ATM_CLIP) + return (DLT_ATM_CLIP); /* - * If we don't have an entry for this LINKTYPE, return - * the link type value; it may be a DLT from an newer - * version of libpcap. + * For all other values, return the linktype code as the + * DLT_* code. + * + * If the code is in the high matching range, the + * DLT_* code is the same as the LINKTYPE_* code. + * + * If the code is greater than the maximum value in + * the high matching range, it may be a value from + * a newer version of libpcap; we provide it in case + * the program' capable of handling it. + * + * If the code is less than the minimum value in the + * high matching range, it might be from a capture + * written by code that doesn't map non-matching range + * DLT_* codes to the appropriate LINKTYPE_* code, so + * we'll just pass it through, so that *if it was written + * on this platform* it will be interpreted correctly. + * (We don't know whether it was written on this platform, + * but at least this way there's *some* chance that it + * can be read.) */ return linktype; } diff --git a/pcap/dlt.h b/pcap/dlt.h index e7f8cedf..21558918 100644 --- a/pcap/dlt.h +++ b/pcap/dlt.h @@ -58,7 +58,12 @@ /* * These are the types that are the same on all platforms, and that * have been defined by for ages. + * + * DLT_LOW_MATCHING_MIN is the lowest such value; DLT_LOW_MATCHING_MAX + * is the highest such value. */ +#define DLT_LOW_MATCHING_MIN 0 + #define DLT_NULL 0 /* BSD loopback encapsulation */ #define DLT_EN10MB 1 /* Ethernet (10Mb) */ #define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ @@ -71,6 +76,25 @@ #define DLT_PPP 9 /* Point-to-point Protocol */ #define DLT_FDDI 10 /* FDDI */ +/* + * In case the code that includes this file (directly or indirectly) + * has also included OS files that happen to define DLT_LOW_MATCHING_MAX, + * with a different value (perhaps because that OS hasn't picked up + * the latest version of our DLT definitions), we undefine the + * previous value of DLT_LOW_MATCHING_MAX. + * + * (They shouldn't, because only those 10 values were assigned in + * the Good Old Days, before DLT_ code assignment became a bit of + * a free-for-all. Perhaps 11 is DLT_ATM_RFC1483 everywhere 11 + * is used at all, but 12 is DLT_RAW on some platforms but not + * OpenBSD, and the fun continues for several other values.) + */ +#ifdef DLT_LOW_MATCHING_MAX +#undef DLT_LOW_MATCHING_MAX +#endif + +#define DLT_LOW_MATCHING_MAX DLT_FDDI /* highest value in this "matching" range */ + /* * These are types that are different on some platforms, and that * have been defined by for ages. We use #ifdefs to @@ -78,7 +102,9 @@ * libpcap * * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, - * but I don't know what the right #define is for BSD/OS. + * but I don't know what the right #define is for BSD/OS. The last + * release was in October 2003; if anybody cares about making this + * work on BSD/OS, give us a pull request for a change to make it work. */ #define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ @@ -186,12 +212,10 @@ * anything and doesn't appear to have ever used it for anything.) * * We define it as 18 on those platforms; it is, unfortunately, used - * for DLT_CIP in SUSE 6.3, so we don't define it as DLT_PFSYNC - * in general. As the packet format for it, like that for - * DLT_PFLOG, is not only OS-dependent but OS-version-dependent, - * we don't support printing it in tcpdump except on OSes that - * have the relevant header files, so it's not that useful on - * other platforms. + * for DLT_CIP in SUSE 6.3, so we don't define it as 18 on all + * platforms. We define it as 121 on FreeBSD and as the same + * value that we assigned to LINKTYPE_PFSYNC on all remaining + * platforms. */ #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) #define DLT_PFSYNC 18 @@ -236,10 +260,10 @@ * and the LINKTYPE_ value that appears in capture files, are the * same. * - * DLT_MATCHING_MIN is the lowest such value; DLT_MATCHING_MAX is + * DLT_HIGH_MATCHING_MIN is the lowest such value; DLT_HIGH_MATCHING_MAX is * the highest such value. */ -#define DLT_MATCHING_MIN 104 +#define DLT_HIGH_MATCHING_MIN 104 /* * This value was defined by libpcap 0.5; platforms that have defined @@ -1616,15 +1640,15 @@ /* * In case the code that includes this file (directly or indirectly) - * has also included OS files that happen to define DLT_MATCHING_MAX, + * has also included OS files that happen to define DLT_HIGH_MATCHING_MAX, * with a different value (perhaps because that OS hasn't picked up * the latest version of our DLT definitions), we undefine the - * previous value of DLT_MATCHING_MAX. + * previous value of DLT_HIGH_MATCHING_MAX. */ -#ifdef DLT_MATCHING_MAX -#undef DLT_MATCHING_MAX +#ifdef DLT_HIGH_MATCHING_MAX +#undef DLT_HIGH_MATCHING_MAX #endif -#define DLT_MATCHING_MAX 299 /* highest value in the "matching" range */ +#define DLT_HIGH_MATCHING_MAX 299 /* highest value in the "matching" range */ #endif /* !defined(lib_pcap_dlt_h) */