summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry Chen <terry.chen@synaptics.corp-partner.google.com>2023-03-14 17:08:11 +0800
committerVictor Hsu <hsuvictor@google.com>2023-03-16 11:02:04 +0000
commit5b07cc110dc09a645a5713c0a682c3645df23caa (patch)
treec433e488d6cd2c4846fdc4b5cfdddf8ccc725778
parentb37b0556c00b57f9ba980b419ee0f8dd8fe30f5a (diff)
downloaddhd43752p-android-gs-felix-5.10-android13-qpr3.tar.gz
- Dump IPv6 TX/RX pkt to ring buffer for debug the connectivity issue in pure ipv6 network - Fixed dump dhcp packets by adding exception Basically, DHD dumps DHCP packets with default types. Types that DHD dumps DHCP packets as default: * DISCOVER, OFFER, REQUEST, DECLINE, ACK, NAK, RELEASE, INFORM However, if AP sends dhcp packets with another types, crash has been occured by over boundary. So, exception for other types is added to DHD Bug: 271931085 Test: Build pass, C6T6Pro verified. Change-Id: I3c50bde755cc386555af3e011ab328b936aefbed Signed-off-by: Terry Chen <terry.chen@synaptics.corp-partner.google.com>
-rw-r--r--Kbuild1
-rw-r--r--dhd_linux.c12
-rw-r--r--dhd_linux_pktdump.c264
-rw-r--r--dhd_linux_pktdump.h11
-rw-r--r--dhd_statlog.h21
-rw-r--r--include/bcmipv6.h14
6 files changed, 294 insertions, 29 deletions
diff --git a/Kbuild b/Kbuild
index f0bbef5..a119306 100644
--- a/Kbuild
+++ b/Kbuild
@@ -390,6 +390,7 @@ DHDCFLAGS += -DSUPPORT_TRIGGER_HANG_EVENT
DHDCFLAGS += -DBCMASSERT_LOG
DHDCFLAGS += -DDHD_8021X_DUMP
DHDCFLAGS += -DDHD_DHCP_DUMP
+DHDCFLAGS += -DDHD_IPV6_DUMP
DHDCFLAGS += -DDHD_ICMP_DUMP
DHDCFLAGS += -DDHD_ARP_DUMP
DHDCFLAGS += -DDHD_DNS_DUMP
diff --git a/dhd_linux.c b/dhd_linux.c
index a0a62fc..5997926 100644
--- a/dhd_linux.c
+++ b/dhd_linux.c
@@ -3917,11 +3917,15 @@ dhd_handle_pktdata(dhd_pub_t *dhdp, int ifidx, void *pkt, uint8 *pktdata, uint32
pkt_type = PKT_TYPE_DNS;
}
}
+#ifdef DHD_IPV6_DUMP
else if (ether_type == ETHER_TYPE_IPV6) {
if (dhd_check_icmpv6(pktdata, pktlen)) {
pkt_type = PKT_TYPE_ICMPV6;
+ } else if (dhd_check_dhcp6(pktdata, pktlen)) {
+ pkt_type = PKT_TYPE_DHCP6;
}
}
+#endif
else if (dhd_check_arp(pktdata, ether_type)) {
pkt_type = PKT_TYPE_ARP;
}
@@ -4017,6 +4021,14 @@ dhd_handle_pktdata(dhd_pub_t *dhdp, int ifidx, void *pkt, uint8 *pktdata, uint32
case PKT_TYPE_EAP:
dhd_dump_eapol_message(dhdp, ifidx, pktdata, pktlen, tx, &pkthash, pktfate);
break;
+#ifdef DHD_IPV6_DUMP
+ case PKT_TYPE_ICMPV6:
+ dhd_icmpv6_dump(dhdp, ifidx, pktdata, tx, &pkthash, pktfate);
+ break;
+ case PKT_TYPE_DHCP6:
+ dhd_dhcp6_dump(dhdp, ifidx, pktdata, tx, &pkthash, pktfate);
+ break;
+#endif
default:
break;
}
diff --git a/dhd_linux_pktdump.c b/dhd_linux_pktdump.c
index 5a28a2c..9a6bf19 100644
--- a/dhd_linux_pktdump.c
+++ b/dhd_linux_pktdump.c
@@ -310,6 +310,27 @@ typedef struct hdr_fmt {
struct bcmudp_hdr udph;
} PACKED_STRUCT hdr_fmt_t;
+#ifdef DHD_IPV6_DUMP
+typedef struct ipv6hdr_fmt {
+ struct ipv6_hdr ip6h;
+ struct bcmudp_hdr udph;
+} PACKED_STRUCT ipv6hdr_fmt_t;
+
+typedef struct dhcp6_fmt {
+ struct ipv6_hdr iph;
+ struct bcmudp_hdr udph;
+ uint8 msgtype;
+} PACKED_STRUCT dhcp6_fmt_t;
+
+typedef struct icmpv6 {
+ uint8 icmp6_type;
+ uint8 icmp6_code;
+ uint16 icmp6_cksum;
+ uint16 id;
+ uint16 seq;
+} PACKED_STRUCT icmpv6_hdr_t;
+#endif
+
msg_eapol_t
dhd_is_4way_msg(uint8 *pktdata)
{
@@ -883,6 +904,52 @@ dhd_check_dhcp(uint8 *pktdata)
return TRUE;
}
+#ifdef DHD_IPV6_DUMP
+bool
+dhd_check_icmpv6(uint8 *pktdata, uint32 plen)
+{
+ uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN];
+ struct ipv6_hdr *ip6h = (struct ipv6_hdr *)pkt;
+
+ /* check header length */
+ if (plen <= IPV6_MIN_HLEN) {
+ return FALSE;
+ }
+
+ if (IPV6_PROT(ip6h) != IP_PROT_ICMP6) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool
+dhd_check_dhcp6(uint8 *pktdata, uint32 plen)
+{
+ ipv6hdr_fmt_t *b = (ipv6hdr_fmt_t *)&pktdata[ETHER_HDR_LEN];
+ struct ipv6_hdr *ip6h = &b->ip6h;
+
+ /* check header length */
+ if (plen <= IPV6_MIN_HLEN) {
+ return FALSE;
+ }
+
+ if (IPV6_PROT(ip6h) != IP_PROT_UDP) {
+ return FALSE;
+ }
+
+ /* check UDP port for bootp (546, 547) */
+ if (b->udph.src_port != htons(DHCP6_PORT_SERVER) &&
+ b->udph.src_port != htons(DHCP6_PORT_CLIENT) &&
+ b->udph.dst_port != htons(DHCP6_PORT_SERVER) &&
+ b->udph.dst_port != htons(DHCP6_PORT_CLIENT)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif
+
#ifdef DHD_DHCP_DUMP
#define BOOTP_CHADDR_LEN 16
#define BOOTP_SNAME_LEN 64
@@ -913,6 +980,41 @@ dhd_check_dhcp(uint8 *pktdata)
} \
} while (0)
+#ifdef DHD_IPV6_DUMP
+#define DHCP6_PRINT(str) \
+ do { \
+ if (tx) { \
+ DHD_PKTDUMP_MEM((str " %s[%s] [TX] -" TXFATE_FMT "\n", \
+ typestr, ifname, \
+ TX_PKTHASH(pkthash), TX_FATE(pktfate), \
+ ((pktfate) && ((*pktfate) <= (WLFC_CTL_PKTFLAG_FORCED_EXPIRED))) ? \
+ (*pktfate) : (0))); \
+ } else { \
+ DHD_PKTDUMP_MEM((str " %s[%s] [RX]\n", \
+ typestr, ifname)); \
+ } \
+ } while (0)
+
+#define ICMPv6_PRINT(str) \
+ do { \
+ if (tx) { \
+ DHD_PKTDUMP_MEM((str " %s[%s] [TX] -" TXFATE_FMT "\n", \
+ typestr, ifname, \
+ TX_PKTHASH(pkthash), TX_FATE(pktfate), \
+ ((pktfate) && ((*pktfate) <= (WLFC_CTL_PKTFLAG_FORCED_EXPIRED))) ? \
+ (*pktfate) : (0))); \
+ } else { \
+ if (msgtype == ICMPV6_PKT_TYPE_RA) { \
+ DHD_PKTDUMP_MEM((str " %s[%s] flags 0x%x [RX]\n", \
+ typestr, ifname, icmp6_ra_flag)); \
+ } else { \
+ DHD_PKTDUMP_MEM((str " %s[%s] [RX]\n", \
+ typestr, ifname)); \
+ } \
+ } \
+ } while (0)
+#endif
+
typedef struct bootp_fmt {
struct ipv4_hdr iph;
struct bcmudp_hdr udph;
@@ -934,15 +1036,56 @@ typedef struct bootp_fmt {
} PACKED_STRUCT bootp_fmt_t;
static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 };
-static char dhcp_ops[][10] = {
+
+#define MAX_DHCP_OPS_STR 3
+#define MAX_DHCP_TYPES_STR 9
+static char dhcp_ops[MAX_DHCP_OPS_STR][10] = {
"NA", "REQUEST", "REPLY"
};
-static char dhcp_types[][10] = {
+static char dhcp_types[MAX_DHCP_TYPES_STR][10] = {
"NA", "DISCOVER", "OFFER", "REQUEST", "DECLINE", "ACK", "NAK", "RELEASE", "INFORM"
};
+#define DHCP_OPS_STR(ops) ((ops < MAX_DHCP_OPS_STR) ? \
+ (dhcp_ops[ops]) : "UNKNOWN_DHCP_OPS")
+#define DHCP_TYPES_STR(type) ((type < MAX_DHCP_TYPES_STR) ? \
+ (dhcp_types[type]) : "UNKNOWN_DHCP_TYPE")
+
+#ifdef DHD_IPV6_DUMP
+#define MAX_DHCP6_TYPES_STR 11
+#define MAX_DHCP6_TYPES_STAT 11
+
+static char dhcp6_types[MAX_DHCP6_TYPES_STR][10] = {
+ "NA", "SOLICIT", "ADVERTISE", "REQUEST", "CONFIRM",
+ "RENEW", "REBIND", "REPLY", "RELEASE", "DECLINE", "RECONFIG"
+};
+#define DHCP6_TYPES_STR(type) ((type < MAX_DHCP6_TYPES_STR) ? \
+ (dhcp6_types[type]) : "UNKNOWN_DHCP_TYPE")
+
+static const int dhcp6_types_stat[MAX_DHCP6_TYPES_STAT] = {
+ ST(INVALID), ST(SOLICIT), ST(ADVERTISE), ST(REQUEST),
+ ST(CONFIRM), ST(RENEW), ST(REBIND), ST(REPLY),
+ ST(RELEASE), ST(DECLINE), ST(RECONFIGURE)
+};
+#define DHCP6_TYPES_STAT(type) ((type < MAX_DHCP6_TYPES_STAT) ? \
+ (dhcp6_types_stat[type]) : ST(INVALID))
+
+
+#define MAX_ICMPV6_TYPES_STAT 10
+static const int icmpv6_types_stat[MAX_ICMPV6_TYPES_STAT] = {
+ ST(INVALID), ST(ECHO_REQ), ST(ECHO_REPLY), ST(MULTI_QUERY),
+ ST(MULTI_REPORT), ST(MULTI_DONE), ST(ROUTER_SOLIC), ST(ROUTER_ADV),
+ ST(NEIGHBOR_SOLIC), ST(NEIGHBOR_ADV)
+};
+#define ICMPV6_TYPES_STAT(type) ((type < MAX_ICMPV6_TYPES_STAT) ? \
+ (icmpv6_types_stat[type]) : ST(INVALID))
+#endif
+
#ifdef DHD_STATUS_LOGGING
-static const int dhcp_types_stat[9] = {
+#define MAX_DHCP_TYPES_STAT 9
+#define DHCP_TYPES_STAT(type) ((type < MAX_DHCP_TYPES_STAT) ? \
+ (dhcp_types_stat[type]) : ST(INVALID))
+static const int dhcp_types_stat[MAX_DHCP_TYPES_STAT] = {
ST(INVALID), ST(DHCP_DISCOVER), ST(DHCP_OFFER), ST(DHCP_REQUEST),
ST(DHCP_DECLINE), ST(DHCP_ACK), ST(DHCP_NAK), ST(DHCP_RELEASE),
ST(DHCP_INFORM)
@@ -955,7 +1098,8 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
{
bootp_fmt_t *b = (bootp_fmt_t *)&pktdata[ETHER_HDR_LEN];
uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->iph.tot_len);
- int dhcp_type = 0, len, opt_len;
+ uint8 dhcp_type = 0;
+ int len, opt_len;
char *ifname = NULL, *typestr = NULL, *opstr = NULL;
bool cond;
@@ -981,9 +1125,9 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
if (*opt == DHCP_OPT_MSGTYPE) {
if (opt[1]) {
dhcp_type = opt[2];
- typestr = dhcp_types[dhcp_type];
- opstr = dhcp_ops[b->op];
- DHD_STATLOG_DATA(dhdp, dhcp_types_stat[dhcp_type],
+ typestr = DHCP_TYPES_STR(dhcp_type);
+ opstr = DHCP_OPS_STR(b->op);
+ DHD_STATLOG_DATA(dhdp, DHCP_TYPES_STAT(dhcp_type),
ifidx, tx, cond);
DHCP_PRINT("DHCP");
break;
@@ -1011,23 +1155,6 @@ dhd_check_icmp(uint8 *pktdata)
return TRUE;
}
-bool
-dhd_check_icmpv6(uint8 *pktdata, uint32 plen)
-{
- uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN];
- struct ipv6_hdr *ip6h = (struct ipv6_hdr *)pkt;
-
- if (IPV6_PROT(ip6h) != IP_PROT_ICMP6) {
- return FALSE;
- }
-
- /* check header length */
- if (plen <= IPV6_MIN_HLEN) {
- return FALSE;
- }
- return TRUE;
-}
-
#ifdef DHD_ICMP_DUMP
#define ICMP_TYPE_DEST_UNREACH 3
#define ICMP_ECHO_SEQ_OFFSET 6
@@ -1194,6 +1321,95 @@ dhd_arp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
}
#endif /* DHD_ARP_DUMP */
+#ifdef DHD_IPV6_DUMP
+void
+dhd_dhcp6_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
+uint32 *pkthash, uint16 *pktfate)
+{
+ dhcp6_fmt_t *b = (dhcp6_fmt_t *)&pktdata[ETHER_HDR_LEN];
+ char *ifname = NULL, *typestr = NULL;
+ uint8 msgtype;
+ bool cond;
+
+ ifname = dhd_ifname(dhdp, ifidx);
+ msgtype = ntoh16(b->msgtype);
+ cond = (tx && pktfate) ? FALSE : TRUE;
+
+ /* only handle DHCPv6 msgtype from 1 ~ 10 */
+ if (msgtype > 10)
+ return;
+
+ typestr = DHCP6_TYPES_STR(msgtype);
+ DHD_STATLOG_DATA(dhdp, DHCP6_TYPES_STAT(msgtype),
+ ifidx, tx, cond);
+ DHCP6_PRINT("DHCPv6");
+ return;
+}
+
+char*
+icmpv6_types(uint8 type) {
+ switch(type) {
+ case ICMPV6_PKT_TYPE_ECHO_REQ:
+ return "Echo Request";
+ case ICMPV6_PKT_TYPE_ECHO_REPLY:
+ return "Echo Reply";
+ case ICMPV6_PKT_TYPE_MULTI_LST_QUERY:
+ return "Multicast Listener Query";
+ case ICMPV6_PKT_TYPE_MULTI_LST_REPORT:
+ return "Multicast Listener Report";
+ case ICMPV6_PKT_TYPE_MULTI_LST_DONE:
+ return "Multicast Listener Done";
+ case ICMPV6_PKT_TYPE_RS:
+ return "Router Solicitation";
+ case ICMPV6_PKT_TYPE_RA:
+ return "Router Advertisement";
+ case ICMPV6_PKT_TYPE_NS:
+ return "Neighbor Solicitation";
+ case ICMPV6_PKT_TYPE_NA:
+ return "Neighbor Advertisement";
+ default:
+ return NULL;
+ }
+}
+
+void
+dhd_icmpv6_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
+uint32 *pkthash, uint16 *pktfate)
+{
+ struct ipv6_hdr *ip6h = (struct ipv6_hdr *)&pktdata[ETHER_HDR_LEN];
+ struct icmp6_hdr *icmpv6;
+ char *ifname = NULL, *typestr = NULL;
+ uint8 icmp6_ra_flag;
+ uint8 msgtype;
+ bool cond;
+
+ uint8 nexthdr = ip6h->nexthdr;
+
+ if (nexthdr != ICMPV6_HEADER_TYPE)
+ return;
+
+ icmpv6 = (struct icmp6_hdr *) ((uint8 *)ip6h + sizeof(struct ipv6_hdr));
+ ifname = dhd_ifname(dhdp, ifidx);
+ msgtype = icmpv6->icmp6_type;
+ cond = (tx && pktfate) ? FALSE : TRUE;
+ typestr = icmpv6_types(msgtype);
+
+ /* only handle ICMPv6 msgtype from 128 ~ 136 */
+ if (!typestr)
+ return;
+
+ if (msgtype == ICMPV6_PKT_TYPE_RA) {
+ /* check IPv6 configuration is stateless or stateful DHCPv6 */
+ icmp6_ra_flag = *((uint8 *)ip6h + sizeof(struct ipv6_hdr) + ICMPV6_RA_FLAG_OFFSET);
+ }
+
+ DHD_STATLOG_DATA(dhdp, ICMPV6_TYPES_STAT(msgtype - 127),
+ ifidx, tx, cond);
+ ICMPv6_PRINT("ICMPv6");
+ return;
+}
+#endif
+
bool
dhd_check_dns(uint8 *pktdata)
{
diff --git a/dhd_linux_pktdump.h b/dhd_linux_pktdump.h
index a179c3d..414d8a9 100644
--- a/dhd_linux_pktdump.h
+++ b/dhd_linux_pktdump.h
@@ -54,7 +54,8 @@ enum pkt_type {
PKT_TYPE_ICMPV6 = 3,
PKT_TYPE_DNS = 4,
PKT_TYPE_ARP = 5,
- PKT_TYPE_EAP = 6
+ PKT_TYPE_EAP = 6,
+ PKT_TYPE_DHCP6 = 7
};
extern msg_eapol_t dhd_is_4way_msg(uint8 *pktdata);
@@ -81,6 +82,14 @@ static INLINE void dhd_rx_pkt_dump(dhd_pub_t *dhdp, int ifidx,
uint8 *pktdata, uint32 pktlen) { }
#endif /* DHD_RX_DUMP */
+#ifdef DHD_IPV6_DUMP
+extern void dhd_dhcp6_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
+ uint32 *pkthash, uint16 *pktfate);
+extern void dhd_icmpv6_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
+ uint32 *pkthash, uint16 *pktfate);
+extern bool dhd_check_dhcp6(uint8 *pktdata, uint32 plen);
+#endif
+
/* DHCP packet dump */
#ifdef DHD_DHCP_DUMP
extern void dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
diff --git a/dhd_statlog.h b/dhd_statlog.h
index dd3152d..5038963 100644
--- a/dhd_statlog.h
+++ b/dhd_statlog.h
@@ -171,7 +171,26 @@ typedef enum stat_log_stat {
ST(ASSOC_NO_NETWORKS) = 86, /* association failure due to no networks */
ST(ASSOC_OTHERS) = 87, /* association failure due to no networks */
ST(REASSOC_DONE_OTHERS) = 88, /* complete to reassoc with other reason */
- ST(MAX) = 89 /* Max Status */
+ ST(SOLICIT) = 89, /* DHCPv6 Solicit */
+ ST(ADVERTISE) = 90, /* DHCPv6 Advertise */
+ ST(REQUEST) = 91, /* DHCPv6 Request */
+ ST(CONFIRM) = 92, /* DHCPv6 Confirm */
+ ST(RENEW) = 93, /* DHCPv6 Renew */
+ ST(REBIND) = 94, /* DHCPv6 Rebind */
+ ST(REPLY) = 95, /* DHCPv6 Reply */
+ ST(RELEASE) = 96, /* DHCPv6 Release */
+ ST(DECLINE) = 97, /* DHCPv6 Decline */
+ ST(RECONFIGURE) = 98, /* ICMPv6 Reconfigure */
+ ST(ECHO_REQ) = 99, /* ICMPv6 Echo Req */
+ ST(ECHO_REPLY) = 100, /* ICMPv6 Echo Reply */
+ ST(MULTI_QUERY) = 101, /* ICMPv6 Multi Query */
+ ST(MULTI_REPORT) = 102, /* ICMPv6 Multi Report */
+ ST(MULTI_DONE) = 103, /* ICMPv6 Multi Done */
+ ST(ROUTER_SOLIC) = 104, /* ICMPv6 Router Solic */
+ ST(ROUTER_ADV) = 105, /* ICMPv6 Router Adv */
+ ST(NEIGHBOR_SOLIC) = 106, /* ICMPv6 Neighbor Solic */
+ ST(NEIGHBOR_ADV) = 107, /* ICMPv6 Neighbor Adv */
+ ST(MAX) = 108 /* Max Status */
} stat_log_stat_t;
/* functions */
diff --git a/include/bcmipv6.h b/include/bcmipv6.h
index b9861ad..ecbf740 100644
--- a/include/bcmipv6.h
+++ b/include/bcmipv6.h
@@ -54,9 +54,17 @@
/* For icmpv6 */
#define ICMPV6_HEADER_TYPE 0x3A
-#define ICMPV6_PKT_TYPE_RA 134
-#define ICMPV6_PKT_TYPE_NS 135
-#define ICMPV6_PKT_TYPE_NA 136
+#define ICMPV6_PKT_TYPE_ECHO_REQ 128
+#define ICMPV6_PKT_TYPE_ECHO_REPLY 129
+#define ICMPV6_PKT_TYPE_MULTI_LST_QUERY 130
+#define ICMPV6_PKT_TYPE_MULTI_LST_REPORT 131
+#define ICMPV6_PKT_TYPE_MULTI_LST_DONE 132
+#define ICMPV6_PKT_TYPE_RS 133
+#define ICMPV6_PKT_TYPE_RA 134
+#define ICMPV6_PKT_TYPE_NS 135
+#define ICMPV6_PKT_TYPE_NA 136
+
+#define ICMPV6_RA_FLAG_OFFSET 5
#define ICMPV6_ND_OPT_TYPE_TARGET_MAC 2
#define ICMPV6_ND_OPT_TYPE_SRC_MAC 1