From: Guy Harris Date: Sun, 23 Jan 2022 09:44:16 +0000 (-0800) Subject: Support more Realtek protocols than RRCP. X-Git-Tag: tcpdump-4.99.2~141 X-Git-Url: https://git.tcpdump.org/tcpdump/commitdiff_plain/9083c1c58a1b181c667475ffbbc75c1cea8936c3 Support more Realtek protocols than RRCP. The Ethertype 0x8899 is used by Realtek for several over-the-wire protocols, as well as for supplying tag information to a host CPU from a Realtek chip. Add code to handle protocols other than RRCP, although we don't fully dissect all of them. (cherry picked from commit 2122c3a243089426fb4a31733f2abf78d3ba941a) --- diff --git a/ethertype.h b/ethertype.h index a757a39c..8f8acff0 100644 --- a/ethertype.h +++ b/ethertype.h @@ -176,8 +176,8 @@ #ifndef ETHERTYPE_EAPOL #define ETHERTYPE_EAPOL 0x888e #endif -#ifndef ETHERTYPE_RRCP -#define ETHERTYPE_RRCP 0x8899 +#ifndef ETHERTYPE_REALTEK +#define ETHERTYPE_REALTEK 0x8899 /* Realtek layer 2 protocols and switch tags */ #endif #ifndef ETHERTYPE_AOE #define ETHERTYPE_AOE 0x88a2 diff --git a/netdissect.h b/netdissect.h index a3c92586..37cce592 100644 --- a/netdissect.h +++ b/netdissect.h @@ -694,9 +694,9 @@ extern void resp_print(netdissect_options *, const u_char *, u_int); extern void rip_print(netdissect_options *, const u_char *, u_int); extern void ripng_print(netdissect_options *, const u_char *, unsigned int); extern void rpki_rtr_print(netdissect_options *, const u_char *, u_int); -extern void rrcp_print(netdissect_options *, const u_char *, u_int, const struct lladdr_info *, const struct lladdr_info *); extern void rsvp_print(netdissect_options *, const u_char *, u_int); extern int rt6_print(netdissect_options *, const u_char *, const u_char *); +extern void rtl_print(netdissect_options *, const u_char *, u_int, const struct lladdr_info *, const struct lladdr_info *); extern void rtsp_print(netdissect_options *, const u_char *, u_int); extern void rx_print(netdissect_options *, const u_char *, u_int, uint16_t, uint16_t, const u_char *); extern void sctp_print(netdissect_options *, const u_char *, const u_char *, u_int); diff --git a/print-ether.c b/print-ether.c index a6c55c1c..976ab4b6 100644 --- a/print-ether.c +++ b/print-ether.c @@ -86,7 +86,7 @@ const struct tok ethertype_values[] = { { ETHERTYPE_PPPOED, "PPPoE D" }, { ETHERTYPE_PPPOES, "PPPoE S" }, { ETHERTYPE_EAPOL, "EAPOL" }, - { ETHERTYPE_RRCP, "RRCP" }, + { ETHERTYPE_REALTEK, "Realtek protocols" }, { ETHERTYPE_MS_NLB_HB, "MS NLB heartbeat" }, { ETHERTYPE_JUMBO, "Jumbo" }, { ETHERTYPE_NSH, "NSH" }, @@ -584,8 +584,8 @@ ethertype_print(netdissect_options *ndo, eapol_print(ndo, p); return (1); - case ETHERTYPE_RRCP: - rrcp_print(ndo, p, length, src, dst); + case ETHERTYPE_REALTEK: + rtl_print(ndo, p, length, src, dst); return (1); case ETHERTYPE_PPP: diff --git a/print-rrcp.c b/print-rrcp.c index 9803f75f..416d041e 100644 --- a/print-rrcp.c +++ b/print-rrcp.c @@ -17,11 +17,13 @@ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * Format and print Realtek Remote Control Protocol (RRCP) - * and Realtek Echo Protocol (RRCP-REP) packets. + * Format and print Realtek Remote Control Protocol (RRCP), Realtek + * Loop Detection Protocol (RLDP), and Realtek Echo Protocol (REP) packets, + * as well as tag formats used by some Realtek switch chips to supply + * tag information to a host CPU for a switch. */ -/* \summary: Realtek Remote Control Protocol (RRCP) printer */ +/* \summary: printer for various Realtek protocols */ /* * See, for example, section 8.20 "Realtek Remote Control Protocol" of @@ -36,8 +38,37 @@ * * http://openrrcp.org.ru/wiki/rrcp_protocol * + * for information on RRCP. + * + * See, for example, section 8.21 "Network Loop Connection Fault + * Detection" of + * + * http://realtek.info/pdf/rtl8324.pdf + * + * and section 7.23 "Network Loop Connection Fault Detection" of + * + * http://realtek.info/pdf/rtl8326.pdf + * + * for information on RLDP. + * + * See, for example, section 8.22 "Realtek Echo Protocol" of + * + * http://realtek.info/pdf/rtl8324.pdf + * + * and section 7.24 "Realtek Echo Protocol" of + * + * http://realtek.info/pdf/rtl8326.pdf + * + * for information on REP. + * * NOTE: none of them indicate the byte order of multi-byte fields in any * obvious fashion. + * + * See section 8.10 "CPU Tag Function" of + * + * http://realtek.info/pdf/rtl8306sd%28m%29_datasheet_1.1.pdf + * + * for the RTL8306 DSA protocol tag format. */ #ifdef HAVE_CONFIG_H @@ -50,11 +81,36 @@ #include "addrtoname.h" #include "extract.h" -#define RRCP_OPCODE_MASK 0x7F /* 0x00 = hello, 0x01 = get, 0x02 = set */ -#define RRCP_ISREPLY 0x80 /* 0 = request to switch, 0x80 = reply from switch */ +#define RTL_FRAME_TYPE_OFFSET 0 /* frame type and other data - 1 byte */ + +/* + * The upper 4 bits of the first octet of Realtek 0x8899 frames indicates + * the frame type. + */ +#define RTL_FRAME_TYPE_MASK 0xF0 +#define RTL_FRAME_TYPE_SUBTYPE 0x00 /* lower 4 bits are a subtype */ +#define RTL_FRAME_TYPE_8306_DSA 0x90 /* RTL8306 DSA protocol */ +#define RTL_FRAME_TYPE_8366RB_DSA 0xA0 /* RTL8366RB DSA protocol */ +#define RTL_FRAME_TYPE_SHIFT 4 + +/* + * The lower 4 bits are a subtype if the upper 4 bits are 0. + */ +#define RTL_FRAME_SUBTYPE_MASK 0x0F +#define RTL_FRAME_SUBTYPE_RRCP 0x01 /* RRCP */ +#define RTL_FRAME_SUBTYPE_REP 0x02 /* REP */ +#define RTL_FRAME_SUBTYPE_RLDP 0x03 /* RLDP */ +#define RTL_FRAME_SUBTYPE_XXX_DSA 0x04 /* DSA protocol for some chip(s) */ -#define RRCP_PROTO_OFFSET 0 /* proto - 1 byte, must be 1 */ #define RRCP_OPCODE_ISREPLY_OFFSET 1 /* opcode and isreply flag - 1 byte */ + +#define RRCP_OPCODE_MASK 0x7F /* 0x00 = hello, 0x01 = get, 0x02 = set */ +#define RRCP_ISREPLY 0x80 /* 0 = request to switch, 0x80 = reply from switch */ + +#define RRCP_OPCODE_HELLO 0x00 +#define RRCP_OPCODE_GET_CONFIGURATION 0x01 +#define RRCP_OPCODE_SET_CONFIGURATION 0x02 + #define RRCP_AUTHKEY_OFFSET 2 /* authorization key - 2 bytes, 0x2379 by default */ /* most packets */ @@ -70,57 +126,36 @@ #define RRCP_CHIP_ID_OFFSET 12 /* 2 bytes */ #define RRCP_VENDOR_ID_OFFSET 14 /* 4 bytes */ -static const struct tok proto_values[] = { - { 1, "RRCP" }, - { 2, "RRCP-REP" }, - { 0, NULL } -}; - static const struct tok opcode_values[] = { - { 0, "hello" }, - { 1, "get" }, - { 2, "set" }, + { RRCP_OPCODE_HELLO, "hello" }, + { RRCP_OPCODE_GET_CONFIGURATION, "get" }, + { RRCP_OPCODE_SET_CONFIGURATION, "set" }, { 0, NULL } }; /* - * Print RRCP requests + * Print RRCP packets */ -void +static void rrcp_print(netdissect_options *ndo, - const u_char *cp, - u_int length _U_, - const struct lladdr_info *src, - const struct lladdr_info *dst) + const u_char *cp) { - uint8_t rrcp_proto; uint8_t rrcp_opcode; ndo->ndo_protocol = "rrcp"; - rrcp_proto = GET_U_1(cp + RRCP_PROTO_OFFSET); rrcp_opcode = GET_U_1((cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_OPCODE_MASK; - if (src != NULL && dst != NULL) { - ND_PRINT("%s > %s, ", - (src->addr_string)(ndo, src->addr), - (dst->addr_string)(ndo, dst->addr)); - } - ND_PRINT("%s %s", - tok2str(proto_values,"RRCP-0x%02x",rrcp_proto), - ((GET_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY) ? "reply" : "query"); - if (rrcp_proto==1){ - ND_PRINT(": %s", - tok2str(opcode_values,"unknown opcode (0x%02x)",rrcp_opcode)); - } - if (rrcp_opcode==1 || rrcp_opcode==2){ + ND_PRINT("RRCP %s: %s", + ((GET_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY) ? "reply" : "query", + tok2str(opcode_values,"unknown opcode (0x%02x)",rrcp_opcode)); + if (rrcp_opcode==RRCP_OPCODE_GET_CONFIGURATION || + rrcp_opcode==RRCP_OPCODE_SET_CONFIGURATION){ ND_PRINT(" addr=0x%04x, data=0x%08x", GET_LE_U_2(cp + RRCP_REG_ADDR_OFFSET), GET_LE_U_4(cp + RRCP_REG_DATA_OFFSET)); } - if (rrcp_proto==1){ - ND_PRINT(", auth=0x%04x", - GET_BE_U_2(cp + RRCP_AUTHKEY_OFFSET)); - } - if (rrcp_proto==1 && rrcp_opcode==0 && + ND_PRINT(", auth=0x%04x", + GET_BE_U_2(cp + RRCP_AUTHKEY_OFFSET)); + if (rrcp_opcode==RRCP_OPCODE_HELLO && ((GET_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY)){ ND_PRINT(" downlink_port=%u, uplink_port=%u, uplink_mac=%s, vendor_id=%08x ,chip_id=%04x ", GET_U_1(cp + RRCP_DOWNLINK_PORT_OFFSET), @@ -128,9 +163,84 @@ rrcp_print(netdissect_options *ndo, GET_ETHERADDR_STRING(cp + RRCP_UPLINK_MAC_OFFSET), GET_BE_U_4(cp + RRCP_VENDOR_ID_OFFSET), GET_BE_U_2(cp + RRCP_CHIP_ID_OFFSET)); - }else if (rrcp_opcode==1 || rrcp_opcode==2 || rrcp_proto==2){ + }else if (rrcp_opcode==RRCP_OPCODE_GET_CONFIGURATION || + rrcp_opcode==RRCP_OPCODE_SET_CONFIGURATION){ ND_PRINT(", cookie=0x%08x%08x ", GET_BE_U_4(cp + RRCP_COOKIE2_OFFSET), GET_BE_U_4(cp + RRCP_COOKIE1_OFFSET)); } } + +/* + * Print Realtek packets + */ +void +rtl_print(netdissect_options *ndo, + const u_char *cp, + u_int length _U_, + const struct lladdr_info *src, + const struct lladdr_info *dst) +{ + uint8_t rtl_proto; + + ndo->ndo_protocol = "rtl"; + + if (src != NULL && dst != NULL) { + ND_PRINT("%s > %s, ", + (src->addr_string)(ndo, src->addr), + (dst->addr_string)(ndo, dst->addr)); + } + + rtl_proto = GET_U_1(cp + RTL_FRAME_TYPE_OFFSET); + + switch (rtl_proto & RTL_FRAME_TYPE_MASK) { + + case RTL_FRAME_TYPE_SUBTYPE: + /* + * Test the subtype. + */ + switch (rtl_proto & RTL_FRAME_SUBTYPE_MASK) { + + case RTL_FRAME_SUBTYPE_RRCP: + rrcp_print(ndo, cp); + break; + + case RTL_FRAME_SUBTYPE_REP: + /* + * REP packets have no payload. + */ + ND_PRINT("REP"); + break; + + case RTL_FRAME_SUBTYPE_RLDP: + /* + * RLDP packets have no payload. + */ + ND_PRINT("RLDP"); + break; + + case RTL_FRAME_SUBTYPE_XXX_DSA: + ND_PRINT("Realtek 8-byte DSA tag"); + break; + + default: + ND_PRINT("Realtek unknown subtype 0x%01x", + rtl_proto & RTL_FRAME_SUBTYPE_MASK); + break; + } + break; + + case RTL_FRAME_TYPE_8306_DSA: + ND_PRINT("Realtek RTL8306 4-byte DSA tag"); + break; + + case RTL_FRAME_TYPE_8366RB_DSA: + ND_PRINT("Realtek RTL8366RB 4-byte DSA tag"); + break; + + default: + ND_PRINT("Realtek unknown type 0x%01x", + (rtl_proto & RTL_FRAME_TYPE_MASK) >> RTL_FRAME_TYPE_SHIFT); + break; + } +}