• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Packet dump helper functions
4  *
5  * Copyright (C) 1999-2019, Broadcom.
6  *
7  *      Unless you and Broadcom execute a separate written software license
8  * agreement governing use of this software, this software is licensed to you
9  * under the terms of the GNU General Public License version 2 (the "GPL"),
10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11  * following added to such license:
12  *
13  *      As a special exception, the copyright holders of this software give you
14  * permission to link this software with independent modules, and to copy and
15  * distribute the resulting executable under terms of your choice, provided that
16  * you also meet, for each linked independent module, the terms and conditions of
17  * the license of that module.  An independent module is a module which is not
18  * derived from this software.  The special exception does not apply to any
19  * modifications of the software.
20  *
21  *      Notwithstanding the above, under no circumstances may you combine this
22  * software in any way with any other Broadcom software provided under a license
23  * other than the GPL, without Broadcom's express prior written consent.
24  *
25  *
26  * <<Broadcom-WL-IPTag/Open:>>
27  *
28  * $Id: dhd_linux_pktdump.c 820929 2019-05-21 14:09:11Z $
29  */
30 
31 #include <typedefs.h>
32 #include <ethernet.h>
33 #include <bcmutils.h>
34 #include <bcmevent.h>
35 #include <bcmendian.h>
36 #include <bcmtlv.h>
37 #include <dngl_stats.h>
38 #include <dhd.h>
39 #include <dhd_dbg.h>
40 #include <bcmip.h>
41 #include <bcmudp.h>
42 #include <bcmdhcp.h>
43 #include <bcmarp.h>
44 #include <bcmicmp.h>
45 #include <dhd_linux_pktdump.h>
46 #include <dhd_config.h>
47 #include <wl_android.h>
48 
49 #define DHD_PKTDUMP(arg)	printk arg
50 #define DHD_PKTDUMP_MEM(arg)	printk arg
51 #define PACKED_STRUCT __attribute__ ((packed))
52 
53 #define EAPOL_HDR_LEN		4
54 
55 /* EAPOL types */
56 #define EAP_PACKET		0
57 #define EAPOL_START		1
58 #define EAPOL_LOGOFF		2
59 #define EAPOL_KEY		3
60 #define EAPOL_ASF		4
61 
62 /* EAPOL-Key types */
63 #define EAPOL_RC4_KEY		1
64 #define EAPOL_WPA2_KEY		2	/* 802.11i/WPA2 */
65 #define EAPOL_WPA_KEY		254	/* WPA */
66 
67 /* EAPOL-Key header field size */
68 #define AKW_BLOCK_LEN		8
69 #define WPA_KEY_REPLAY_LEN	8
70 #define WPA_KEY_NONCE_LEN	32
71 #define WPA_KEY_IV_LEN		16
72 #define WPA_KEY_RSC_LEN		8
73 #define WPA_KEY_ID_LEN		8
74 #define WPA_KEY_MIC_LEN		16
75 #define WPA_MAX_KEY_SIZE	32
76 #define WPA_KEY_DATA_LEN	(WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN)
77 
78 /* Key information bit */
79 #define KEYINFO_TYPE_MASK	(1 << 3)
80 #define KEYINFO_INSTALL_MASK	(1 << 6)
81 #define KEYINFO_KEYACK_MASK	(1 << 7)
82 #define KEYINFO_KEYMIC_MASK	(1 << 8)
83 #define KEYINFO_SECURE_MASK	(1 << 9)
84 #define KEYINFO_ERROR_MASK	(1 << 10)
85 #define KEYINFO_REQ_MASK	(1 << 11)
86 
87 /* EAP Code */
88 #define EAP_CODE_REQUEST	1	/* Request */
89 #define EAP_CODE_RESPONSE	2	/* Response */
90 #define EAP_CODE_SUCCESS	3	/* Success */
91 #define EAP_CODE_FAILURE	4	/* Failure */
92 
93 /* EAP Type */
94 #define EAP_TYPE_RSVD		0	/* Reserved */
95 #define EAP_TYPE_IDENT		1	/* Identify */
96 #define EAP_TYPE_NOTI		2	/* Notification */
97 #define EAP_TYPE_TLS		13	/* EAP-TLS */
98 #define EAP_TYPE_LEAP		17	/* Cisco-LEAP */
99 #define EAP_TYPE_TTLS		21	/* EAP-TTLS */
100 #define EAP_TYPE_AKA		23	/* EAP-AKA */
101 #define EAP_TYPE_PEAP		25	/* EAP-PEAP */
102 #define EAP_TYPE_FAST		43	/* EAP-FAST */
103 #define EAP_TYPE_PSK		47	/* EAP-PSK */
104 #define EAP_TYPE_AKAP		50	/* EAP-AKA' */
105 #define EAP_TYPE_EXP		254	/* Reserved for Expended Type */
106 
107 /* WSC */
108 #define EAP_HDR_LEN		5
109 #define EAP_WSC_NONCE_OFFSET	10
110 #define EAP_WSC_DATA_OFFSET	(OFFSETOF(eap_wsc_fmt_t, data))
111 #define EAP_WSC_MIN_DATA_LEN	((EAP_HDR_LEN) + (EAP_WSC_DATA_OFFSET))
112 #define WFA_VID			"\x00\x37\x2A"	/* WFA SMI code */
113 #define WFA_VID_LEN		3		/* WFA VID length */
114 #define WFA_VTYPE		1u		/* WFA Vendor type */
115 
116 /* WSC opcode */
117 #define WSC_OPCODE_UPNP		0
118 #define WSC_OPCODE_START	1
119 #define WSC_OPCODE_ACK		2
120 #define WSC_OPCODE_NACK		3
121 #define WSC_OPCODE_MSG		4
122 #define WSC_OPCODE_DONE		5
123 #define WSC_OPCODE_FRAG_ACK	6
124 
125 /* WSC flag */
126 #define WSC_FLAG_MF		1	/* more fragements */
127 #define WSC_FLAG_LF		2	/* length field */
128 
129 /* WSC message code */
130 #define WSC_ATTR_MSG		0x1022
131 #define WSC_MSG_M1		0x04
132 #define WSC_MSG_M2		0x05
133 #define WSC_MSG_M3		0x07
134 #define WSC_MSG_M4		0x08
135 #define WSC_MSG_M5		0x09
136 #define WSC_MSG_M6		0x0A
137 #define WSC_MSG_M7		0x0B
138 #define WSC_MSG_M8		0x0C
139 
140 /* Debug prints */
141 typedef enum pkt_cnt_type {
142 	PKT_CNT_TYPE_INVALID	= 0,
143 	PKT_CNT_TYPE_ARP	= 1,
144 	PKT_CNT_TYPE_DNS	= 2,
145 	PKT_CNT_TYPE_MAX	= 3
146 } pkt_cnt_type_t;
147 
148 typedef struct pkt_cnt {
149 	uint32 tx_cnt;
150 	uint32 tx_err_cnt;
151 	uint32 rx_cnt;
152 } pkt_cnt_t;
153 
154 typedef struct pkt_cnt_log {
155 	bool enabled;
156 	uint16 reason;
157 	timer_list_compat_t pktcnt_timer;
158 	pkt_cnt_t arp_cnt;
159 	pkt_cnt_t dns_cnt;
160 } pkt_cnts_log_t;
161 
162 #define PKT_CNT_TIMER_INTERNVAL_MS		5000	/* packet count timeout(ms) */
163 #define PKT_CNT_RSN_VALID(rsn)	\
164 	(((rsn) > (PKT_CNT_RSN_INVALID)) && ((rsn) < (PKT_CNT_RSN_MAX)))
165 
166 #ifdef DHD_PKTDUMP_ROAM
167 static const char pkt_cnt_msg[][20] = {
168 	"INVALID",
169 	"ROAM_SUCCESS",
170 	"GROUP_KEY_UPDATE",
171 	"CONNECT_SUCCESS",
172 	"INVALID"
173 };
174 #endif
175 
176 static const char tx_pktfate[][30] = {
177 	"TX_PKT_FATE_ACKED",		/* 0: WLFC_CTL_PKTFLAG_DISCARD */
178 	"TX_PKT_FATE_FW_QUEUED",	/* 1: WLFC_CTL_PKTFLAG_D11SUPPRESS */
179 	"TX_PKT_FATE_FW_QUEUED",	/* 2: WLFC_CTL_PKTFLAG_WLSUPPRESS */
180 	"TX_PKT_FATE_FW_DROP_INVALID",	/* 3: WLFC_CTL_PKTFLAG_TOSSED_BYWLC */
181 	"TX_PKT_FATE_SENT",		/* 4: WLFC_CTL_PKTFLAG_DISCARD_NOACK */
182 	"TX_PKT_FATE_FW_DROP_OTHER",	/* 5: WLFC_CTL_PKTFLAG_SUPPRESS_ACKED */
183 	"TX_PKT_FATE_FW_DROP_EXPTIME",	/* 6: WLFC_CTL_PKTFLAG_EXPIRED */
184 	"TX_PKT_FATE_FW_DROP_OTHER",	/* 7: WLFC_CTL_PKTFLAG_DROPPED */
185 	"TX_PKT_FATE_FW_PKT_FREE",	/* 8: WLFC_CTL_PKTFLAG_MKTFREE */
186 };
187 
188 #define DBGREPLAY		" Replay Counter: %02x%02x%02x%02x%02x%02x%02x%02x"
189 #define REPLAY_FMT(key)		((const eapol_key_hdr_t *)(key))->replay[0], \
190 				((const eapol_key_hdr_t *)(key))->replay[1], \
191 				((const eapol_key_hdr_t *)(key))->replay[2], \
192 				((const eapol_key_hdr_t *)(key))->replay[3], \
193 				((const eapol_key_hdr_t *)(key))->replay[4], \
194 				((const eapol_key_hdr_t *)(key))->replay[5], \
195 				((const eapol_key_hdr_t *)(key))->replay[6], \
196 				((const eapol_key_hdr_t *)(key))->replay[7]
197 #define TXFATE_FMT		" TX_PKTHASH:0x%X TX_PKT_FATE:%s"
198 #define TX_PKTHASH(pkthash)		((pkthash) ? (*pkthash) : (0))
199 #define TX_FATE_STR(fate)	(((*fate) <= (WLFC_CTL_PKTFLAG_MKTFREE)) ? \
200 				(tx_pktfate[(*fate)]) : "TX_PKT_FATE_FW_DROP_OTHER")
201 #define TX_FATE(fate)		((fate) ? (TX_FATE_STR(fate)) : "N/A")
202 #define TX_FATE_ACKED(fate)	((fate) ? ((*fate) == (WLFC_CTL_PKTFLAG_DISCARD)) : (0))
203 
204 #define EAP_PRINT(x, args...) \
205 	do { \
206 		if (dump_msg_level & DUMP_EAPOL_VAL) { \
207 			if (tx) { \
208 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [TX] : (%s) %s (%s)"TXFATE_FMT"\n", \
209 					ifname, ## args, \
210 					tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
211 					TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
212 			} else { \
213 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [RX] : (%s) %s (%s)\n", \
214 					ifname, ## args, \
215 					tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf)); \
216 			} \
217 		} \
218 	} while (0)
219 
220 #define EAP_PRINT_REPLAY(x, args...) \
221 	do { \
222 		if (dump_msg_level & DUMP_EAPOL_VAL) { \
223 			if (tx) { \
224 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [TX] : (%s) %s (%s)"DBGREPLAY TXFATE_FMT"\n", \
225 					ifname, ## args, \
226 					tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
227 					REPLAY_FMT(eap_key), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
228 			} else { \
229 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [RX] : (%s) %s (%s)"DBGREPLAY"\n", \
230 					ifname, ## args, \
231 					tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
232 					REPLAY_FMT(eap_key))); \
233 			} \
234 		} \
235 	} while (0)
236 
237 #define EAP_PRINT_OTHER(x, args...) \
238 	do { \
239 		if (dump_msg_level & DUMP_EAPOL_VAL) { \
240 			if (tx) { \
241 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [TX] : (%s) %s (%s) " \
242 					"ver %d, type %d"TXFATE_FMT"\n", \
243 					ifname, ## args, \
244 					tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
245 					eapol_hdr->version, eapol_hdr->type, \
246 					TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
247 			} else { \
248 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [RX] : (%s) %s (%s) " \
249 					"ver %d, type %d\n", \
250 					ifname, ## args, \
251 					tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
252 					eapol_hdr->version, eapol_hdr->type)); \
253 			} \
254 		} \
255 	} while (0)
256 
257 #define EAP_PRINT_OTHER_4WAY(x, args...) \
258 	do { \
259 		if (dump_msg_level & DUMP_EAPOL_VAL) { \
260 			if (tx) { \
261 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [TX] : (%s) %s (%s) " \
262 					"ver %d type %d keytype %d keyinfo 0x%02X"TXFATE_FMT"\n", \
263 					ifname, ## args, \
264 					tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
265 					eapol_hdr->version, eapol_hdr->type, eap_key->type, \
266 					(uint32)hton16(eap_key->key_info), \
267 					TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
268 			} else { \
269 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [RX] : (%s) %s (%s) " \
270 					"ver %d type %d keytype %d keyinfo 0x%02X\n", \
271 					ifname, ## args, \
272 					tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
273 					eapol_hdr->version, eapol_hdr->type, eap_key->type, \
274 					(uint32)hton16(eap_key->key_info))); \
275 			} \
276 		} \
277 	} while (0)
278 
279 /* EAPOL header */
280 typedef struct eapol_header {
281 	struct ether_header eth;	/* 802.3/Ethernet header */
282 	uint8 version;			/* EAPOL protocol version */
283 	uint8 type;			/* EAPOL type */
284 	uint16 length;			/* Length of body */
285 	uint8 body[1];			/* Body (optional) */
286 } PACKED_STRUCT eapol_header_t;
287 
288 /* EAP header */
289 typedef struct eap_header_fmt {
290 	uint8 code;
291 	uint8 id;
292 	uint16 len;
293 	uint8 type;
294 	uint8 data[1];
295 } PACKED_STRUCT eap_header_fmt_t;
296 
297 /* WSC EAP format */
298 typedef struct eap_wsc_fmt {
299 	uint8 oui[3];
300 	uint32 ouitype;
301 	uint8 opcode;
302 	uint8 flags;
303 	uint8 data[1];
304 } PACKED_STRUCT eap_wsc_fmt_t;
305 
306 /* EAPOL-Key */
307 typedef struct eapol_key_hdr {
308 	uint8 type;				/* Key Descriptor Type */
309 	uint16 key_info;			/* Key Information (unaligned) */
310 	uint16 key_len;				/* Key Length (unaligned) */
311 	uint8 replay[WPA_KEY_REPLAY_LEN];	/* Replay Counter */
312 	uint8 nonce[WPA_KEY_NONCE_LEN];		/* Nonce */
313 	uint8 iv[WPA_KEY_IV_LEN];		/* Key IV */
314 	uint8 rsc[WPA_KEY_RSC_LEN];		/* Key RSC */
315 	uint8 id[WPA_KEY_ID_LEN];		/* WPA:Key ID, 802.11i/WPA2: Reserved */
316 	uint8 mic[WPA_KEY_MIC_LEN];		/* Key MIC */
317 	uint16 data_len;			/* Key Data Length */
318 	uint8 data[WPA_KEY_DATA_LEN];		/* Key data */
319 } PACKED_STRUCT eapol_key_hdr_t;
320 
321 msg_eapol_t
dhd_is_4way_msg(uint8 * pktdata)322 dhd_is_4way_msg(uint8 *pktdata)
323 {
324 	eapol_header_t *eapol_hdr;
325 	eapol_key_hdr_t *eap_key;
326 	msg_eapol_t type = EAPOL_OTHER;
327 	bool pair, ack, mic, kerr, req, sec, install;
328 	uint16 key_info;
329 
330 	if (!pktdata) {
331 		DHD_PKTDUMP(("%s: pktdata is NULL\n", __FUNCTION__));
332 		return type;
333 	}
334 
335 	eapol_hdr = (eapol_header_t *)pktdata;
336 	eap_key = (eapol_key_hdr_t *)(eapol_hdr->body);
337 	if (eap_key->type != EAPOL_WPA2_KEY && eap_key->type != EAPOL_WPA_KEY) {
338 		return type;
339 	}
340 
341 	key_info = hton16(eap_key->key_info);
342 	pair = !!(key_info & KEYINFO_TYPE_MASK);
343 	ack = !!(key_info & KEYINFO_KEYACK_MASK);
344 	mic = !!(key_info & KEYINFO_KEYMIC_MASK);
345 	kerr = !!(key_info & KEYINFO_ERROR_MASK);
346 	req = !!(key_info & KEYINFO_REQ_MASK);
347 	sec = !!(key_info & KEYINFO_SECURE_MASK);
348 	install = !!(key_info & KEYINFO_INSTALL_MASK);
349 
350 	if (eap_key->type == EAPOL_WPA2_KEY) {
351 		if (pair && !install && ack && !mic && !sec && !kerr && !req) {
352 			type = EAPOL_4WAY_M1;
353 		} else if (pair && !install && !ack && mic && !sec && !kerr && !req) {
354 			type = EAPOL_4WAY_M2;
355 		} else if (pair && ack && mic && sec && !kerr && !req) {
356 			type = EAPOL_4WAY_M3;
357 		} else if (pair && !install && !ack && mic && sec && !req && !kerr) {
358 			type = EAPOL_4WAY_M4;
359 		} else if (!pair && !install && ack && mic && sec && !req && !kerr) {
360 			type = EAPOL_GROUPKEY_M1;
361 		} else if (!pair && !install && !ack && mic && sec && !req && !kerr) {
362 			type = EAPOL_GROUPKEY_M2;
363 		} else {
364 			type = EAPOL_OTHER;
365 			if (dump_msg_level & DUMP_EAPOL_VAL) {
366 				printf("WPA2: key_info=0x%x, pair=%d, ack=%d, mic=%d, sec=%d, kerr=%d, req=%d\n",
367 					key_info, pair, ack, mic, sec, kerr, req);
368 			}
369 		}
370 	}
371 	else if (eap_key->type == EAPOL_WPA_KEY) {
372 		if (pair && !install && ack && !mic && !sec && !kerr && !req) {
373 			type = EAPOL_4WAY_M1;
374 		} else if (pair && !install && !ack && mic && !sec && !kerr && !req && eap_key->data_len) {
375 			type = EAPOL_4WAY_M2;
376 		} else if (pair && install && ack && mic && !sec && !kerr && !req) {
377 			type = EAPOL_4WAY_M3;
378 		} else if (pair && !install && !ack && mic && !sec && !req && !kerr) {
379 			type = EAPOL_4WAY_M4;
380 		} else if (!pair && !install && ack && mic && sec && !req && !kerr) {
381 			type = EAPOL_GROUPKEY_M1;
382 		} else if (!pair && !install && !ack && mic && sec && !req && !kerr) {
383 			type = EAPOL_GROUPKEY_M2;
384 		} else {
385 			type = EAPOL_OTHER;
386 			if (dump_msg_level & DUMP_EAPOL_VAL) {
387 				printf("WPA: key_info=0x%x, pair=%d, ack=%d, mic=%d, sec=%d, kerr=%d, req=%d\n",
388 					key_info, pair, ack, mic, sec, kerr, req);
389 			}
390 		}
391 	}
392 	else {
393 		type = EAPOL_OTHER;
394 		if (dump_msg_level & DUMP_EAPOL_VAL) {
395 			printf("OTHER: key_info=0x%x, pair=%d, ack=%d, mic=%d, sec=%d, kerr=%d, req=%d\n",
396 				key_info, pair, ack, mic, sec, kerr, req);
397 		}
398 	}
399 
400 	return type;
401 }
402 
403 void
dhd_dump_pkt(dhd_pub_t * dhdp,int ifidx,uint8 * pktdata,uint32 pktlen,bool tx,uint32 * pkthash,uint16 * pktfate)404 dhd_dump_pkt(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen,
405 	bool tx, uint32 *pkthash, uint16 *pktfate)
406 {
407 	struct ether_header *eh;
408 	uint16 ether_type;
409 
410 	if (!pktdata || pktlen < ETHER_HDR_LEN) {
411 		return;
412 	}
413 
414 	eh = (struct ether_header *)pktdata;
415 	ether_type = ntoh16(eh->ether_type);
416 	if (ether_type == ETHER_TYPE_802_1X) {
417 		dhd_dump_eapol_message(dhdp, ifidx, pktdata, pktlen,
418 			tx, pkthash, pktfate);
419 	}
420 	if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
421 		dhd_dhcp_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
422 		dhd_icmp_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
423 		dhd_dns_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
424 	}
425 	if (ntoh16(eh->ether_type) == ETHER_TYPE_ARP) {
426 		dhd_arp_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
427 	}
428 	dhd_trx_pkt_dump(dhdp, ifidx, pktdata, pktlen, tx);
429 }
430 
431 #ifdef DHD_PKTDUMP_ROAM
432 static void
dhd_dump_pkt_cnts_inc(dhd_pub_t * dhdp,bool tx,uint16 * pktfate,uint16 pkttype)433 dhd_dump_pkt_cnts_inc(dhd_pub_t *dhdp, bool tx, uint16 *pktfate, uint16 pkttype)
434 {
435 	pkt_cnts_log_t *pktcnts;
436 	pkt_cnt_t *cnt;
437 
438 	if (!dhdp) {
439 		DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
440 		return;
441 	}
442 
443 	pktcnts = (pkt_cnts_log_t *)(dhdp->pktcnts);
444 	if (!pktcnts) {
445 		DHD_ERROR(("%s: pktcnts is NULL\n", __FUNCTION__));
446 		return;
447 	}
448 
449 	if (!pktcnts->enabled || (tx && !pktfate)) {
450 		return;
451 	}
452 
453 	if (pkttype == PKT_CNT_TYPE_ARP) {
454 		cnt = (pkt_cnt_t *)&pktcnts->arp_cnt;
455 	} else if (pkttype == PKT_CNT_TYPE_DNS) {
456 		cnt = (pkt_cnt_t *)&pktcnts->dns_cnt;
457 	} else {
458 		/* invalid packet type */
459 		return;
460 	}
461 
462 	if (tx) {
463 		TX_FATE_ACKED(pktfate) ? cnt->tx_cnt++ : cnt->tx_err_cnt++;
464 	} else {
465 		cnt->rx_cnt++;
466 	}
467 }
468 
469 static void
dhd_dump_pkt_timer(unsigned long data)470 dhd_dump_pkt_timer(unsigned long data)
471 {
472 	dhd_pub_t *dhdp = (dhd_pub_t *)data;
473 	pkt_cnts_log_t *pktcnts = (pkt_cnts_log_t *)(dhdp->pktcnts);
474 
475 	pktcnts->enabled = FALSE;
476 
477 	/* print out the packet counter value */
478 	DHD_PKTDUMP(("============= PACKET COUNT SUMMARY ============\n"));
479 	DHD_PKTDUMP(("- Reason: %s\n", pkt_cnt_msg[pktcnts->reason]));
480 	DHD_PKTDUMP(("- Duration: %d msec(s)\n", PKT_CNT_TIMER_INTERNVAL_MS));
481 	DHD_PKTDUMP(("- ARP PACKETS: tx_success:%d tx_fail:%d rx_cnt:%d\n",
482 		pktcnts->arp_cnt.tx_cnt, pktcnts->arp_cnt.tx_err_cnt,
483 		pktcnts->arp_cnt.rx_cnt));
484 	DHD_PKTDUMP(("- DNS PACKETS: tx_success:%d tx_fail:%d rx_cnt:%d\n",
485 		pktcnts->dns_cnt.tx_cnt, pktcnts->dns_cnt.tx_err_cnt,
486 		pktcnts->dns_cnt.rx_cnt));
487 	DHD_PKTDUMP(("============= END OF COUNT SUMMARY ============\n"));
488 }
489 
490 void
dhd_dump_mod_pkt_timer(dhd_pub_t * dhdp,uint16 rsn)491 dhd_dump_mod_pkt_timer(dhd_pub_t *dhdp, uint16 rsn)
492 {
493 	pkt_cnts_log_t *pktcnts;
494 
495 	if (!dhdp || !dhdp->pktcnts) {
496 		DHD_ERROR(("%s: dhdp or dhdp->pktcnts is NULL\n",
497 			__FUNCTION__));
498 		return;
499 	}
500 
501 	if (!PKT_CNT_RSN_VALID(rsn)) {
502 		DHD_ERROR(("%s: invalid reason code %d\n",
503 			__FUNCTION__, rsn));
504 		return;
505 	}
506 
507 	pktcnts = (pkt_cnts_log_t *)(dhdp->pktcnts);
508 	if (timer_pending(&pktcnts->pktcnt_timer)) {
509 		del_timer_sync(&pktcnts->pktcnt_timer);
510 	}
511 
512 	bzero(&pktcnts->arp_cnt, sizeof(pkt_cnt_t));
513 	bzero(&pktcnts->dns_cnt, sizeof(pkt_cnt_t));
514 	pktcnts->reason = rsn;
515 	pktcnts->enabled = TRUE;
516 	mod_timer(&pktcnts->pktcnt_timer,
517 		jiffies + msecs_to_jiffies(PKT_CNT_TIMER_INTERNVAL_MS));
518 	DHD_PKTDUMP(("%s: Arm the pktcnt timer. reason=%d\n",
519 		__FUNCTION__, rsn));
520 }
521 
522 void
dhd_dump_pkt_init(dhd_pub_t * dhdp)523 dhd_dump_pkt_init(dhd_pub_t *dhdp)
524 {
525 	pkt_cnts_log_t *pktcnts;
526 
527 	if (!dhdp) {
528 		DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
529 		return;
530 	}
531 
532 	pktcnts = (pkt_cnts_log_t *)MALLOCZ(dhdp->osh, sizeof(pkt_cnts_log_t));
533 	if (!pktcnts) {
534 		DHD_ERROR(("%s: failed to allocate memory for pktcnts\n",
535 			__FUNCTION__));
536 		return;
537 	}
538 
539 	/* init timers */
540 	init_timer_compat(&pktcnts->pktcnt_timer, dhd_dump_pkt_timer, dhdp);
541 	dhdp->pktcnts = pktcnts;
542 }
543 
544 void
dhd_dump_pkt_deinit(dhd_pub_t * dhdp)545 dhd_dump_pkt_deinit(dhd_pub_t *dhdp)
546 {
547 	pkt_cnts_log_t *pktcnts;
548 
549 	if (!dhdp || !dhdp->pktcnts) {
550 		DHD_ERROR(("%s: dhdp or pktcnts is NULL\n", __FUNCTION__));
551 		return;
552 	}
553 
554 	pktcnts = (pkt_cnts_log_t *)(dhdp->pktcnts);
555 	pktcnts->enabled = FALSE;
556 	del_timer_sync(&pktcnts->pktcnt_timer);
557 	MFREE(dhdp->osh, dhdp->pktcnts, sizeof(pkt_cnts_log_t));
558 	dhdp->pktcnts = NULL;
559 }
560 
561 void
dhd_dump_pkt_clear(dhd_pub_t * dhdp)562 dhd_dump_pkt_clear(dhd_pub_t *dhdp)
563 {
564 	pkt_cnts_log_t *pktcnts;
565 
566 	if (!dhdp || !dhdp->pktcnts) {
567 		DHD_ERROR(("%s: dhdp or pktcnts is NULL\n", __FUNCTION__));
568 		return;
569 	}
570 
571 	pktcnts = (pkt_cnts_log_t *)(dhdp->pktcnts);
572 	pktcnts->enabled = FALSE;
573 	del_timer_sync(&pktcnts->pktcnt_timer);
574 	pktcnts->reason = 0;
575 	bzero(&pktcnts->arp_cnt, sizeof(pkt_cnt_t));
576 	bzero(&pktcnts->dns_cnt, sizeof(pkt_cnt_t));
577 }
578 
579 bool
dhd_dump_pkt_enabled(dhd_pub_t * dhdp)580 dhd_dump_pkt_enabled(dhd_pub_t *dhdp)
581 {
582 	pkt_cnts_log_t *pktcnts;
583 
584 	if (!dhdp || !dhdp->pktcnts) {
585 		return FALSE;
586 	}
587 
588 	pktcnts = (pkt_cnts_log_t *)(dhdp->pktcnts);
589 
590 	return pktcnts->enabled;
591 }
592 #else
593 static INLINE void
dhd_dump_pkt_cnts_inc(dhd_pub_t * dhdp,bool tx,uint16 * pktfate,uint16 pkttype)594 dhd_dump_pkt_cnts_inc(dhd_pub_t *dhdp, bool tx, uint16 *pktfate, uint16 pkttype) { }
595 static INLINE bool
dhd_dump_pkt_enabled(dhd_pub_t * dhdp)596 dhd_dump_pkt_enabled(dhd_pub_t *dhdp) { return FALSE; }
597 #endif /* DHD_PKTDUMP_ROAM */
598 
599 #ifdef DHD_8021X_DUMP
600 static void
dhd_dump_wsc_message(dhd_pub_t * dhd,int ifidx,uint8 * pktdata,uint32 pktlen,bool tx,uint32 * pkthash,uint16 * pktfate)601 dhd_dump_wsc_message(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
602 	uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate)
603 {
604 	eapol_header_t *eapol_hdr;
605 	eap_header_fmt_t *eap_hdr;
606 	eap_wsc_fmt_t *eap_wsc;
607 	char *ifname;
608 	uint16 eap_len;
609 	bool cond;
610 	char seabuf[ETHER_ADDR_STR_LEN]="";
611 	char deabuf[ETHER_ADDR_STR_LEN]="";
612 
613 	if (!pktdata) {
614 		DHD_ERROR(("%s: pktdata is NULL\n", __FUNCTION__));
615 		return;
616 	}
617 
618 	if (pktlen < (ETHER_HDR_LEN + EAPOL_HDR_LEN)) {
619 		DHD_ERROR(("%s: invalid pkt length\n", __FUNCTION__));
620 		return;
621 	}
622 
623 	bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf);
624 	bcm_ether_ntoa((struct ether_addr *)(pktdata+6), seabuf);
625 
626 	eapol_hdr = (eapol_header_t *)pktdata;
627 	eap_hdr = (eap_header_fmt_t *)(eapol_hdr->body);
628 	if (eap_hdr->type != EAP_TYPE_EXP) {
629 		return;
630 	}
631 
632 	eap_len = ntoh16(eap_hdr->len);
633 	if (eap_len < EAP_WSC_MIN_DATA_LEN) {
634 		return;
635 	}
636 
637 	eap_wsc = (eap_wsc_fmt_t *)(eap_hdr->data);
638 	if (bcmp(eap_wsc->oui, (const uint8 *)WFA_VID, WFA_VID_LEN) ||
639 		(ntoh32(eap_wsc->ouitype) != WFA_VTYPE)) {
640 		return;
641 	}
642 
643 	if (eap_wsc->flags) {
644 		return;
645 	}
646 
647 	ifname = dhd_ifname(dhd, ifidx);
648 	cond = (tx && pktfate) ? FALSE : TRUE;
649 
650 	if (eap_wsc->opcode == WSC_OPCODE_MSG) {
651 		const uint8 *tlv_buf = (const uint8 *)(eap_wsc->data);
652 		const uint8 *msg;
653 		uint16 msglen;
654 		uint16 wsc_data_len = (uint16)(eap_len - EAP_HDR_LEN - EAP_WSC_DATA_OFFSET);
655 		bcm_xtlv_opts_t opt = BCM_XTLV_OPTION_IDBE | BCM_XTLV_OPTION_LENBE;
656 
657 		msg = bcm_get_data_from_xtlv_buf(tlv_buf, wsc_data_len,
658 			WSC_ATTR_MSG, &msglen, opt);
659 		if (msg && msglen) {
660 			switch (*msg) {
661 			case WSC_MSG_M1:
662 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M1);
663 				DHD_STATLOG_DATA(dhd, ST(WPS_M1), ifidx, tx, cond);
664 				EAP_PRINT("EAP Packet, WPS M1");
665 				break;
666 			case WSC_MSG_M2:
667 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M2);
668 				DHD_STATLOG_DATA(dhd, ST(WPS_M2), ifidx, tx, cond);
669 				EAP_PRINT("EAP Packet, WPS M2");
670 				break;
671 			case WSC_MSG_M3:
672 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M3);
673 				DHD_STATLOG_DATA(dhd, ST(WPS_M3), ifidx, tx, cond);
674 				EAP_PRINT("EAP Packet, WPS M3");
675 				break;
676 			case WSC_MSG_M4:
677 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M4);
678 				DHD_STATLOG_DATA(dhd, ST(WPS_M4), ifidx, tx, cond);
679 				EAP_PRINT("EAP Packet, WPS M4");
680 				break;
681 			case WSC_MSG_M5:
682 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M5);
683 				DHD_STATLOG_DATA(dhd, ST(WPS_M5), ifidx, tx, cond);
684 				EAP_PRINT("EAP Packet, WPS M5");
685 				break;
686 			case WSC_MSG_M6:
687 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M6);
688 				DHD_STATLOG_DATA(dhd, ST(WPS_M6), ifidx, tx, cond);
689 				EAP_PRINT("EAP Packet, WPS M6");
690 				break;
691 			case WSC_MSG_M7:
692 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M7);
693 				DHD_STATLOG_DATA(dhd, ST(WPS_M7), ifidx, tx, cond);
694 				EAP_PRINT("EAP Packet, WPS M7");
695 				break;
696 			case WSC_MSG_M8:
697 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M8);
698 				DHD_STATLOG_DATA(dhd, ST(WPS_M8), ifidx, tx, cond);
699 				EAP_PRINT("EAP Packet, WPS M8");
700 				break;
701 			default:
702 				break;
703 			}
704 		}
705 	} else if (eap_wsc->opcode == WSC_OPCODE_START) {
706 		wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WSC_START);
707 		DHD_STATLOG_DATA(dhd, ST(WSC_START), ifidx, tx, cond);
708 		EAP_PRINT("EAP Packet, WSC Start");
709 	} else if (eap_wsc->opcode == WSC_OPCODE_DONE) {
710 		wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WSC_DONE);
711 		DHD_STATLOG_DATA(dhd, ST(WSC_DONE), ifidx, tx, cond);
712 		EAP_PRINT("EAP Packet, WSC Done");
713 	}
714 }
715 
716 static void
dhd_dump_eap_packet(dhd_pub_t * dhd,int ifidx,uint8 * pktdata,uint32 pktlen,bool tx,uint32 * pkthash,uint16 * pktfate)717 dhd_dump_eap_packet(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
718 	uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate)
719 {
720 	eapol_header_t *eapol_hdr;
721 	eap_header_fmt_t *eap_hdr;
722 	char *ifname;
723 	bool cond;
724 	char seabuf[ETHER_ADDR_STR_LEN]="";
725 	char deabuf[ETHER_ADDR_STR_LEN]="";
726 
727 	if (!pktdata) {
728 		DHD_PKTDUMP(("%s: pktdata is NULL\n", __FUNCTION__));
729 		return;
730 	}
731 
732 	bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf);
733 	bcm_ether_ntoa((struct ether_addr *)(pktdata+6), seabuf);
734 
735 	eapol_hdr = (eapol_header_t *)pktdata;
736 	eap_hdr = (eap_header_fmt_t *)(eapol_hdr->body);
737 	ifname = dhd_ifname(dhd, ifidx);
738 	cond = (tx && pktfate) ? FALSE : TRUE;
739 
740 	if (eap_hdr->code == EAP_CODE_REQUEST ||
741 		eap_hdr->code == EAP_CODE_RESPONSE) {
742 		bool isreq = (eap_hdr->code == EAP_CODE_REQUEST);
743 		switch (eap_hdr->type) {
744 		case EAP_TYPE_IDENT:
745 			if (isreq) {
746 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_REQID);
747 				DHD_STATLOG_DATA(dhd, ST(EAP_REQ_IDENTITY), ifidx, tx, cond);
748 				EAP_PRINT("EAP Packet, Request, Identity");
749 			} else {
750 				wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_RSPID);
751 				DHD_STATLOG_DATA(dhd, ST(EAP_RESP_IDENTITY), ifidx, tx, cond);
752 				EAP_PRINT("EAP Packet, Response, Identity");
753 			}
754 			break;
755 		case EAP_TYPE_TLS:
756 			if (isreq) {
757 				DHD_STATLOG_DATA(dhd, ST(EAP_REQ_TLS), ifidx, tx, cond);
758 				EAP_PRINT("EAP Packet, Request, TLS");
759 			} else {
760 				DHD_STATLOG_DATA(dhd, ST(EAP_RESP_TLS), ifidx, tx, cond);
761 				EAP_PRINT("EAP Packet, Response, TLS");
762 			}
763 			break;
764 		case EAP_TYPE_LEAP:
765 			if (isreq) {
766 				DHD_STATLOG_DATA(dhd, ST(EAP_REQ_LEAP), ifidx, tx, cond);
767 				EAP_PRINT("EAP Packet, Request, LEAP");
768 			} else {
769 				DHD_STATLOG_DATA(dhd, ST(EAP_RESP_LEAP), ifidx, tx, cond);
770 				EAP_PRINT("EAP Packet, Response, LEAP");
771 			}
772 			break;
773 		case EAP_TYPE_TTLS:
774 			if (isreq) {
775 				DHD_STATLOG_DATA(dhd, ST(EAP_REQ_TTLS), ifidx, tx, cond);
776 				EAP_PRINT("EAP Packet, Request, TTLS");
777 			} else {
778 				DHD_STATLOG_DATA(dhd, ST(EAP_RESP_TTLS), ifidx, tx, cond);
779 				EAP_PRINT("EAP Packet, Response, TTLS");
780 			}
781 			break;
782 		case EAP_TYPE_AKA:
783 			if (isreq) {
784 				DHD_STATLOG_DATA(dhd, ST(EAP_REQ_AKA), ifidx, tx, cond);
785 				EAP_PRINT("EAP Packet, Request, AKA");
786 			} else {
787 				DHD_STATLOG_DATA(dhd, ST(EAP_RESP_AKA), ifidx, tx, cond);
788 				EAP_PRINT("EAP Packet, Response, AKA");
789 			}
790 			break;
791 		case EAP_TYPE_PEAP:
792 			if (isreq) {
793 				DHD_STATLOG_DATA(dhd, ST(EAP_REQ_PEAP), ifidx, tx, cond);
794 				EAP_PRINT("EAP Packet, Request, PEAP");
795 			} else {
796 				DHD_STATLOG_DATA(dhd, ST(EAP_RESP_PEAP), ifidx, tx, cond);
797 				EAP_PRINT("EAP Packet, Response, PEAP");
798 			}
799 			break;
800 		case EAP_TYPE_FAST:
801 			if (isreq) {
802 				DHD_STATLOG_DATA(dhd, ST(EAP_REQ_FAST), ifidx, tx, cond);
803 				EAP_PRINT("EAP Packet, Request, FAST");
804 			} else {
805 				DHD_STATLOG_DATA(dhd, ST(EAP_RESP_FAST), ifidx, tx, cond);
806 				EAP_PRINT("EAP Packet, Response, FAST");
807 			}
808 			break;
809 		case EAP_TYPE_PSK:
810 			if (isreq) {
811 				DHD_STATLOG_DATA(dhd, ST(EAP_REQ_PSK), ifidx, tx, cond);
812 				EAP_PRINT("EAP Packet, Request, PSK");
813 			} else {
814 				DHD_STATLOG_DATA(dhd, ST(EAP_RESP_PSK), ifidx, tx, cond);
815 				EAP_PRINT("EAP Packet, Response, PSK");
816 			}
817 			break;
818 		case EAP_TYPE_AKAP:
819 			if (isreq) {
820 				DHD_STATLOG_DATA(dhd, ST(EAP_REQ_AKAP), ifidx, tx, cond);
821 				EAP_PRINT("EAP Packet, Request, AKAP");
822 			} else {
823 				DHD_STATLOG_DATA(dhd, ST(EAP_RESP_AKAP), ifidx, tx, cond);
824 				EAP_PRINT("EAP Packet, Response, AKAP");
825 			}
826 			break;
827 		case EAP_TYPE_EXP:
828 			dhd_dump_wsc_message(dhd, ifidx, pktdata, pktlen, tx,
829 				pkthash, pktfate);
830 			break;
831 		default:
832 			break;
833 		}
834 	} else if (eap_hdr->code == EAP_CODE_SUCCESS) {
835 		DHD_STATLOG_DATA(dhd, ST(EAP_SUCCESS), ifidx, tx, cond);
836 		EAP_PRINT("EAP Packet, Success");
837 	} else if (eap_hdr->code == EAP_CODE_FAILURE) {
838 		DHD_STATLOG_DATA(dhd, ST(EAP_FAILURE), ifidx, tx, cond);
839 		EAP_PRINT("EAP Packet, Failure");
840 	}
841 }
842 
843 static void
dhd_dump_eapol_4way_message(dhd_pub_t * dhd,int ifidx,uint8 * pktdata,bool tx,uint32 * pkthash,uint16 * pktfate)844 dhd_dump_eapol_4way_message(dhd_pub_t *dhd, int ifidx, uint8 *pktdata, bool tx,
845 	uint32 *pkthash, uint16 *pktfate)
846 {
847 	eapol_header_t *eapol_hdr;
848 	eapol_key_hdr_t *eap_key;
849 	msg_eapol_t type;
850 	char *ifname;
851 	bool cond;
852 	char seabuf[ETHER_ADDR_STR_LEN]="";
853 	char deabuf[ETHER_ADDR_STR_LEN]="";
854 
855 	if (!pktdata) {
856 		DHD_PKTDUMP(("%s: pktdata is NULL\n", __FUNCTION__));
857 		return;
858 	}
859 
860 	bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf);
861 	bcm_ether_ntoa((struct ether_addr *)(pktdata+6), seabuf);
862 
863 	type = dhd_is_4way_msg(pktdata);
864 	ifname = dhd_ifname(dhd, ifidx);
865 	eapol_hdr = (eapol_header_t *)pktdata;
866 	eap_key = (eapol_key_hdr_t *)(eapol_hdr->body);
867 	cond = (tx && pktfate) ? FALSE : TRUE;
868 
869 	if (eap_key->type != EAPOL_WPA2_KEY && eap_key->type != EAPOL_WPA_KEY) {
870 		EAP_PRINT_OTHER("NON EAPOL_WPA2_KEY %d", eap_key->type);
871 		return;
872 	}
873 
874 	switch (type) {
875 	case EAPOL_4WAY_M1:
876 		wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_4WAY_M1);
877 		DHD_STATLOG_DATA(dhd, ST(EAPOL_M1), ifidx, tx, cond);
878 		EAP_PRINT("EAPOL Packet, 4-way handshake, M1");
879 		break;
880 	case EAPOL_4WAY_M2:
881 		wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_4WAY_M2);
882 		DHD_STATLOG_DATA(dhd, ST(EAPOL_M2), ifidx, tx, cond);
883 		EAP_PRINT("EAPOL Packet, 4-way handshake, M2");
884 		break;
885 	case EAPOL_4WAY_M3:
886 		wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_4WAY_M3);
887 		DHD_STATLOG_DATA(dhd, ST(EAPOL_M3), ifidx, tx, cond);
888 		EAP_PRINT("EAPOL Packet, 4-way handshake, M3");
889 		break;
890 	case EAPOL_4WAY_M4:
891 		wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_4WAY_M4);
892 		DHD_STATLOG_DATA(dhd, ST(EAPOL_M4), ifidx, tx, cond);
893 		EAP_PRINT("EAPOL Packet, 4-way handshake, M4");
894 		break;
895 	case EAPOL_GROUPKEY_M1:
896 		wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_GROUPKEY_M1);
897 		DHD_STATLOG_DATA(dhd, ST(EAPOL_GROUPKEY_M1), ifidx, tx, cond);
898 		EAP_PRINT_REPLAY("EAPOL Packet, GROUP Key handshake, M1");
899 		break;
900 	case EAPOL_GROUPKEY_M2:
901 		wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_GROUPKEY_M2);
902 		DHD_STATLOG_DATA(dhd, ST(EAPOL_GROUPKEY_M2), ifidx, tx, cond);
903 		EAP_PRINT_REPLAY("EAPOL Packet, GROUP Key handshake, M2");
904 		if (ifidx == 0 && tx && pktfate) {
905 			dhd_dump_mod_pkt_timer(dhd, PKT_CNT_RSN_GRPKEY_UP);
906 		}
907 		break;
908 	default:
909 		DHD_STATLOG_DATA(dhd, ST(8021X_OTHER), ifidx, tx, cond);
910 		EAP_PRINT_OTHER("OTHER 4WAY type=%d", type);
911 		break;
912 	}
913 }
914 
915 void
dhd_dump_eapol_message(dhd_pub_t * dhd,int ifidx,uint8 * pktdata,uint32 pktlen,bool tx,uint32 * pkthash,uint16 * pktfate)916 dhd_dump_eapol_message(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
917 	uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate)
918 {
919 	char *ifname;
920 	eapol_header_t *eapol_hdr = (eapol_header_t *)pktdata;
921 	bool cond;
922 	char seabuf[ETHER_ADDR_STR_LEN]="";
923 	char deabuf[ETHER_ADDR_STR_LEN]="";
924 
925 	if (!pktdata) {
926 		DHD_ERROR(("%s: pktdata is NULL\n", __FUNCTION__));
927 		return;
928 	}
929 
930 	bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf);
931 	bcm_ether_ntoa((struct ether_addr *)(pktdata+6), seabuf);
932 
933 	eapol_hdr = (eapol_header_t *)pktdata;
934 	ifname = dhd_ifname(dhd, ifidx);
935 	cond = (tx && pktfate) ? FALSE : TRUE;
936 
937 	if (eapol_hdr->type == EAP_PACKET) {
938 		dhd_dump_eap_packet(dhd, ifidx, pktdata, pktlen, tx,
939 			pkthash, pktfate);
940 	} else if (eapol_hdr->type == EAPOL_START) {
941 		DHD_STATLOG_DATA(dhd, ST(EAPOL_START), ifidx, tx, cond);
942 		EAP_PRINT("EAP Packet, EAPOL-Start");
943 	} else if (eapol_hdr->type == EAPOL_KEY) {
944 		dhd_dump_eapol_4way_message(dhd, ifidx, pktdata, tx,
945 			pkthash, pktfate);
946 	} else {
947 		DHD_STATLOG_DATA(dhd, ST(8021X_OTHER), ifidx, tx, cond);
948 		EAP_PRINT_OTHER("OTHER 8021X");
949 	}
950 }
951 #endif /* DHD_8021X_DUMP */
952 
953 #ifdef DHD_DHCP_DUMP
954 #define BOOTP_CHADDR_LEN		16
955 #define BOOTP_SNAME_LEN			64
956 #define BOOTP_FILE_LEN			128
957 #define BOOTP_MIN_DHCP_OPT_LEN		312
958 #define BOOTP_MAGIC_COOKIE_LEN		4
959 
960 #define DHCP_MSGTYPE_DISCOVER		1
961 #define DHCP_MSGTYPE_OFFER		2
962 #define DHCP_MSGTYPE_REQUEST		3
963 #define DHCP_MSGTYPE_DECLINE		4
964 #define DHCP_MSGTYPE_ACK		5
965 #define DHCP_MSGTYPE_NAK		6
966 #define DHCP_MSGTYPE_RELEASE		7
967 #define DHCP_MSGTYPE_INFORM		8
968 
969 #define DHCP_PRINT(str) \
970 	do { \
971 		if (tx) { \
972 			DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] " str " %8s[%8s] [TX] : %s(%s) %s %s(%s)"TXFATE_FMT"\n", \
973 				ifname, typestr, opstr, tx?sabuf:dabuf, tx?seabuf:deabuf, \
974 				tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
975 				TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
976 		} else { \
977 			DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] " str " %8s[%8s] [RX] : %s(%s) %s %s(%s)\n", \
978 				ifname, typestr, opstr, tx?sabuf:dabuf, tx?seabuf:deabuf, \
979 				tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf)); \
980 		} \
981 	} while (0)
982 
983 typedef struct bootp_fmt {
984 	struct ipv4_hdr iph;
985 	struct bcmudp_hdr udph;
986 	uint8 op;
987 	uint8 htype;
988 	uint8 hlen;
989 	uint8 hops;
990 	uint32 transaction_id;
991 	uint16 secs;
992 	uint16 flags;
993 	uint32 client_ip;
994 	uint32 assigned_ip;
995 	uint32 server_ip;
996 	uint32 relay_ip;
997 	uint8 hw_address[BOOTP_CHADDR_LEN];
998 	uint8 server_name[BOOTP_SNAME_LEN];
999 	uint8 file_name[BOOTP_FILE_LEN];
1000 	uint8 options[BOOTP_MIN_DHCP_OPT_LEN];
1001 } PACKED_STRUCT bootp_fmt_t;
1002 
1003 static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 };
1004 static char dhcp_ops[][10] = {
1005 	"NA", "REQUEST", "REPLY"
1006 };
1007 static char dhcp_types[][10] = {
1008 	"NA", "DISCOVER", "OFFER", "REQUEST", "DECLINE", "ACK", "NAK", "RELEASE", "INFORM"
1009 };
1010 
1011 static const int dhcp_types_stat[9] = {
1012 	ST(INVALID), ST(DHCP_DISCOVER), ST(DHCP_OFFER), ST(DHCP_REQUEST),
1013 	ST(DHCP_DECLINE), ST(DHCP_ACK), ST(DHCP_NAK), ST(DHCP_RELEASE),
1014 	ST(DHCP_INFORM)
1015 };
1016 
1017 void
dhd_dhcp_dump(dhd_pub_t * dhdp,int ifidx,uint8 * pktdata,bool tx,uint32 * pkthash,uint16 * pktfate)1018 dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
1019 	uint32 *pkthash, uint16 *pktfate)
1020 {
1021 	bootp_fmt_t *b = (bootp_fmt_t *)&pktdata[ETHER_HDR_LEN];
1022 	struct ipv4_hdr *iph = &b->iph;
1023 	uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->iph.tot_len);
1024 	int dhcp_type = 0, len, opt_len;
1025 	char *ifname = NULL, *typestr = NULL, *opstr = NULL;
1026 	bool cond;
1027 	char sabuf[20]="", dabuf[20]="";
1028 	char seabuf[ETHER_ADDR_STR_LEN]="";
1029 	char deabuf[ETHER_ADDR_STR_LEN]="";
1030 
1031 	if (!(dump_msg_level & DUMP_DHCP_VAL))
1032 		return;
1033 
1034 	/* check IP header */
1035 	if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) ||
1036 		IP_VER(iph) != IP_VER_4 ||
1037 		IPV4_PROT(iph) != IP_PROT_UDP) {
1038 		return;
1039 	}
1040 
1041 	/* check UDP port for bootp (67, 68) */
1042 	if (b->udph.src_port != htons(DHCP_PORT_SERVER) &&
1043 		b->udph.src_port != htons(DHCP_PORT_CLIENT) &&
1044 		b->udph.dst_port != htons(DHCP_PORT_SERVER) &&
1045 		b->udph.dst_port != htons(DHCP_PORT_CLIENT)) {
1046 		return;
1047 	}
1048 
1049 	/* check header length */
1050 	if (ntohs(iph->tot_len) < ntohs(b->udph.len) + sizeof(struct bcmudp_hdr)) {
1051 		return;
1052 	}
1053 	bcm_ip_ntoa((struct ipv4_addr *)iph->src_ip, sabuf);
1054 	bcm_ip_ntoa((struct ipv4_addr *)iph->dst_ip, dabuf);
1055 	bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf);
1056 	bcm_ether_ntoa((struct ether_addr *)(pktdata+6), seabuf);
1057 
1058 	ifname = dhd_ifname(dhdp, ifidx);
1059 	cond = (tx && pktfate) ? FALSE : TRUE;
1060 	len = ntohs(b->udph.len) - sizeof(struct bcmudp_hdr);
1061 	opt_len = len - (sizeof(*b) - sizeof(struct ipv4_hdr) -
1062 		sizeof(struct bcmudp_hdr) - sizeof(b->options));
1063 
1064 	/* parse bootp options */
1065 	if (opt_len >= BOOTP_MAGIC_COOKIE_LEN &&
1066 		!memcmp(b->options, bootp_magic_cookie, BOOTP_MAGIC_COOKIE_LEN)) {
1067 		ptr = &b->options[BOOTP_MAGIC_COOKIE_LEN];
1068 		while (ptr < end && *ptr != 0xff) {
1069 			opt = ptr++;
1070 			if (*opt == 0) {
1071 				continue;
1072 			}
1073 			ptr += *ptr + 1;
1074 			if (ptr >= end) {
1075 				break;
1076 			}
1077 			if (*opt == DHCP_OPT_MSGTYPE) {
1078 				if (opt[1]) {
1079 					dhcp_type = opt[2];
1080 					typestr = dhcp_types[dhcp_type];
1081 					opstr = dhcp_ops[b->op];
1082 					DHD_STATLOG_DATA(dhdp, dhcp_types_stat[dhcp_type],
1083 						ifidx, tx, cond);
1084 					DHCP_PRINT("DHCP");
1085 					break;
1086 				}
1087 			}
1088 		}
1089 	}
1090 }
1091 #endif /* DHD_DHCP_DUMP */
1092 
1093 #ifdef DHD_ICMP_DUMP
1094 #define ICMP_TYPE_DEST_UNREACH		3
1095 #define ICMP_ECHO_SEQ_OFFSET		6
1096 #define ICMP_ECHO_SEQ(h) (*(uint16 *)((uint8 *)(h) + (ICMP_ECHO_SEQ_OFFSET)))
1097 #define ICMP_PING_PRINT(str) \
1098 	do { \
1099 		if (tx) { \
1100 			DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s) SEQNUM=%d" \
1101 				TXFATE_FMT"\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1102 				tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, seqnum, \
1103 				TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1104 		} else { \
1105 			DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [RX] : %s(%s) %s %s(%s) SEQNUM=%d\n", \
1106 				ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1107 				tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, seqnum)); \
1108 		} \
1109 	} while (0)
1110 
1111 #define ICMP_PRINT(str) \
1112 	do { \
1113 		if (tx) { \
1114 			DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s) TYPE=%d, CODE=%d" \
1115 				TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1116 				tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, type, code, \
1117 				TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1118 		} else { \
1119 			DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [RX] : %s(%s) %s %s(%s) TYPE=%d," \
1120 				" CODE=%d\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1121 				tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, type, code)); \
1122 		} \
1123 	} while (0)
1124 
1125 void
dhd_icmp_dump(dhd_pub_t * dhdp,int ifidx,uint8 * pktdata,bool tx,uint32 * pkthash,uint16 * pktfate)1126 dhd_icmp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
1127 	uint32 *pkthash, uint16 *pktfate)
1128 {
1129 	uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN];
1130 	struct ipv4_hdr *iph = (struct ipv4_hdr *)pkt;
1131 	struct bcmicmp_hdr *icmph;
1132 	char *ifname;
1133 	bool cond;
1134 	uint16 seqnum, type, code;
1135 	char sabuf[20]="", dabuf[20]="";
1136 	char seabuf[ETHER_ADDR_STR_LEN]="";
1137 	char deabuf[ETHER_ADDR_STR_LEN]="";
1138 
1139 	if (!(dump_msg_level & DUMP_ICMP_VAL))
1140 		return;
1141 
1142 	/* check IP header */
1143 	if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) ||
1144 		IP_VER(iph) != IP_VER_4 ||
1145 		IPV4_PROT(iph) != IP_PROT_ICMP) {
1146 		return;
1147 	}
1148 
1149 	/* check header length */
1150 	if (ntohs(iph->tot_len) - IPV4_HLEN(iph) < sizeof(struct bcmicmp_hdr)) {
1151 		return;
1152 	}
1153 
1154 	ifname = dhd_ifname(dhdp, ifidx);
1155 	cond = (tx && pktfate) ? FALSE : TRUE;
1156 	icmph = (struct bcmicmp_hdr *)((uint8 *)pkt + sizeof(struct ipv4_hdr));
1157 	seqnum = 0;
1158 	type = icmph->type;
1159 	code = icmph->code;
1160 	bcm_ip_ntoa((struct ipv4_addr *)iph->src_ip, sabuf);
1161 	bcm_ip_ntoa((struct ipv4_addr *)iph->dst_ip, dabuf);
1162 	bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf);
1163 	bcm_ether_ntoa((struct ether_addr *)(pktdata+6), seabuf);
1164 	if (type == ICMP_TYPE_ECHO_REQUEST) {
1165 		seqnum = ntoh16(ICMP_ECHO_SEQ(icmph));
1166 		DHD_STATLOG_DATA(dhdp, ST(ICMP_PING_REQ), ifidx, tx, cond);
1167 		ICMP_PING_PRINT("PING REQUEST");
1168 	} else if (type == ICMP_TYPE_ECHO_REPLY) {
1169 		seqnum = ntoh16(ICMP_ECHO_SEQ(icmph));
1170 		DHD_STATLOG_DATA(dhdp, ST(ICMP_PING_RESP), ifidx, tx, cond);
1171 		ICMP_PING_PRINT("PING REPLY  ");
1172 	} else if (type == ICMP_TYPE_DEST_UNREACH) {
1173 		DHD_STATLOG_DATA(dhdp, ST(ICMP_DEST_UNREACH), ifidx, tx, cond);
1174 		ICMP_PRINT("ICMP DEST UNREACH");
1175 	} else {
1176 		DHD_STATLOG_DATA(dhdp, ST(ICMP_OTHER), ifidx, tx, cond);
1177 		ICMP_PRINT("ICMP OTHER");
1178 	}
1179 }
1180 #endif /* DHD_ICMP_DUMP */
1181 
1182 #ifdef DHD_ARP_DUMP
1183 #define ARP_PRINT(str) \
1184 	do { \
1185 		if (tx) { \
1186 			if (dump_enabled && pktfate && !TX_FATE_ACKED(pktfate)) { \
1187 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s)"TXFATE_FMT"\n", \
1188 					ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1189 					tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
1190 					TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1191 			} else { \
1192 				DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s)"TXFATE_FMT"\n", \
1193 					ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1194 					tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
1195 					TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1196 			} \
1197 		} else { \
1198 			DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [RX] : %s(%s) %s %s(%s)\n", \
1199 				ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1200 				tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf)); \
1201 		} \
1202 	} while (0) \
1203 
1204 #define ARP_PRINT_OTHER(str) \
1205 	do { \
1206 		if (tx) { \
1207 			if (dump_enabled && pktfate && !TX_FATE_ACKED(pktfate)) { \
1208 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s) op_code=%d" \
1209 					TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1210 					tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, opcode, \
1211 					TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1212 			} else { \
1213 				DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s) op_code=%d" \
1214 				TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1215 					tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, opcode, \
1216 				TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1217 			} \
1218 		} else { \
1219 			DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [RX] : %s(%s) %s %s(%s) op_code=%d\n", \
1220 				ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1221 					tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, opcode)); \
1222 		} \
1223 	} while (0)
1224 
1225 void
dhd_arp_dump(dhd_pub_t * dhdp,int ifidx,uint8 * pktdata,bool tx,uint32 * pkthash,uint16 * pktfate)1226 dhd_arp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
1227 	uint32 *pkthash, uint16 *pktfate)
1228 {
1229 	uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN];
1230 	struct bcmarp *arph = (struct bcmarp *)pkt;
1231 	char *ifname;
1232 	uint16 opcode;
1233 	bool cond, dump_enabled;
1234 	char sabuf[20]="", dabuf[20]="";
1235 	char seabuf[ETHER_ADDR_STR_LEN]="";
1236 	char deabuf[ETHER_ADDR_STR_LEN]="";
1237 
1238 	if (!(dump_msg_level & DUMP_ARP_VAL))
1239 		return;
1240 
1241 	/* validation check */
1242 	if (arph->htype != hton16(HTYPE_ETHERNET) ||
1243 		arph->hlen != ETHER_ADDR_LEN ||
1244 		arph->plen != 4) {
1245 		return;
1246 	}
1247 
1248 	ifname = dhd_ifname(dhdp, ifidx);
1249 	opcode = ntoh16(arph->oper);
1250 	cond = (tx && pktfate) ? FALSE : TRUE;
1251 	dump_enabled = dhd_dump_pkt_enabled(dhdp);
1252 	bcm_ip_ntoa((struct ipv4_addr *)arph->src_ip, sabuf);
1253 	bcm_ip_ntoa((struct ipv4_addr *)arph->dst_ip, dabuf);
1254 	bcm_ether_ntoa((struct ether_addr *)arph->dst_eth, deabuf);
1255 	bcm_ether_ntoa((struct ether_addr *)arph->src_eth, seabuf);
1256 	if (opcode == ARP_OPC_REQUEST) {
1257 		DHD_STATLOG_DATA(dhdp, ST(ARP_REQ), ifidx, tx, cond);
1258 		ARP_PRINT("ARP REQUEST ");
1259 	} else if (opcode == ARP_OPC_REPLY) {
1260 		DHD_STATLOG_DATA(dhdp, ST(ARP_RESP), ifidx, tx, cond);
1261 		ARP_PRINT("ARP RESPONSE");
1262 	} else {
1263 		ARP_PRINT_OTHER("ARP OTHER");
1264 	}
1265 
1266 	if (ifidx == 0) {
1267 		dhd_dump_pkt_cnts_inc(dhdp, tx, pktfate, PKT_CNT_TYPE_ARP);
1268 	}
1269 }
1270 #endif /* DHD_ARP_DUMP */
1271 
1272 #ifdef DHD_DNS_DUMP
1273 typedef struct dns_fmt {
1274 	struct ipv4_hdr iph;
1275 	struct bcmudp_hdr udph;
1276 	uint16 id;
1277 	uint16 flags;
1278 	uint16 qdcount;
1279 	uint16 ancount;
1280 	uint16 nscount;
1281 	uint16 arcount;
1282 } PACKED_STRUCT dns_fmt_t;
1283 
1284 #define UDP_PORT_DNS		53
1285 #define DNS_QR_LOC		15
1286 #define DNS_OPCODE_LOC		11
1287 #define DNS_RCODE_LOC		0
1288 #define DNS_QR_MASK		((0x1) << (DNS_QR_LOC))
1289 #define DNS_OPCODE_MASK		((0xF) << (DNS_OPCODE_LOC))
1290 #define DNS_RCODE_MASK		((0xF) << (DNS_RCODE_LOC))
1291 #define GET_DNS_QR(flags)	(((flags) & (DNS_QR_MASK)) >> (DNS_QR_LOC))
1292 #define GET_DNS_OPCODE(flags)	(((flags) & (DNS_OPCODE_MASK)) >> (DNS_OPCODE_LOC))
1293 #define GET_DNS_RCODE(flags)	(((flags) & (DNS_RCODE_MASK)) >> (DNS_RCODE_LOC))
1294 #define DNS_UNASSIGNED_OPCODE(flags) ((GET_DNS_OPCODE(flags) >= (6)))
1295 
1296 static const char dns_opcode_types[][11] = {
1297 	"QUERY", "IQUERY", "STATUS", "UNASSIGNED", "NOTIFY", "UPDATE"
1298 };
1299 
1300 #define DNSOPCODE(op)	\
1301 	(DNS_UNASSIGNED_OPCODE(flags) ? "UNASSIGNED" : dns_opcode_types[op])
1302 
1303 #define DNS_REQ_PRINT(str) \
1304 	do { \
1305 		if (tx) { \
1306 			if (dump_enabled && pktfate && !TX_FATE_ACKED(pktfate)) { \
1307 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s" \
1308 					TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1309 					tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
1310 					id, DNSOPCODE(opcode), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1311 			} else { \
1312 				DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s" \
1313 					TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1314 					tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
1315 					id, DNSOPCODE(opcode), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1316 			} \
1317 		} else { \
1318 			DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] " str " [RX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s\n", \
1319 				ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, tx?"->":"<-", \
1320 				tx?dabuf:sabuf, tx?deabuf:seabuf, id, DNSOPCODE(opcode))); \
1321 		} \
1322 	} while (0)
1323 
1324 #define DNS_RESP_PRINT(str) \
1325 	do { \
1326 		if (tx) { \
1327 			if (dump_enabled && pktfate && !TX_FATE_ACKED(pktfate)) { \
1328 				DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s RCODE:%d" \
1329 					TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1330 					tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, id, DNSOPCODE(opcode), \
1331 					GET_DNS_RCODE(flags), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1332 			} else { \
1333 				DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s RCODE:%d" \
1334 					TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1335 					tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, id, DNSOPCODE(opcode), \
1336 					GET_DNS_RCODE(flags), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
1337 			} \
1338 		} else { \
1339 			DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] " str " [RX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s RCODE:%d\n", \
1340 				ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
1341 				tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
1342 				id, DNSOPCODE(opcode), GET_DNS_RCODE(flags))); \
1343 		} \
1344 	} while (0)
1345 
1346 void
dhd_dns_dump(dhd_pub_t * dhdp,int ifidx,uint8 * pktdata,bool tx,uint32 * pkthash,uint16 * pktfate)1347 dhd_dns_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
1348 	uint32 *pkthash, uint16 *pktfate)
1349 {
1350 	dns_fmt_t *dnsh = (dns_fmt_t *)&pktdata[ETHER_HDR_LEN];
1351 	struct ipv4_hdr *iph = &dnsh->iph;
1352 	uint16 flags, opcode, id;
1353 	char *ifname;
1354 	bool cond, dump_enabled;
1355 	char sabuf[20]="", dabuf[20]="";
1356 	char seabuf[ETHER_ADDR_STR_LEN]="";
1357 	char deabuf[ETHER_ADDR_STR_LEN]="";
1358 
1359 	if (!(dump_msg_level & DUMP_DNS_VAL))
1360 		return;
1361 
1362 	/* check IP header */
1363 	if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) ||
1364 		IP_VER(iph) != IP_VER_4 ||
1365 		IPV4_PROT(iph) != IP_PROT_UDP) {
1366 		return;
1367 	}
1368 
1369 	/* check UDP port for DNS */
1370 	if (dnsh->udph.src_port != hton16(UDP_PORT_DNS) &&
1371 		dnsh->udph.dst_port != hton16(UDP_PORT_DNS)) {
1372 		return;
1373 	}
1374 
1375 	/* check header length */
1376 	if (ntoh16(iph->tot_len) < (ntoh16(dnsh->udph.len) +
1377 		sizeof(struct bcmudp_hdr))) {
1378 		return;
1379 	}
1380 
1381 	ifname = dhd_ifname(dhdp, ifidx);
1382 	cond = (tx && pktfate) ? FALSE : TRUE;
1383 	dump_enabled = dhd_dump_pkt_enabled(dhdp);
1384 	flags = hton16(dnsh->flags);
1385 	opcode = GET_DNS_OPCODE(flags);
1386 	id = hton16(dnsh->id);
1387 	bcm_ip_ntoa((struct ipv4_addr *)iph->src_ip, sabuf);
1388 	bcm_ip_ntoa((struct ipv4_addr *)iph->dst_ip, dabuf);
1389 	bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf);
1390 	bcm_ether_ntoa((struct ether_addr *)(pktdata+6), seabuf);
1391 	if (GET_DNS_QR(flags)) {
1392 		/* Response */
1393 		DHD_STATLOG_DATA(dhdp, ST(DNS_RESP), ifidx, tx, cond);
1394 		DNS_RESP_PRINT("DNS RESPONSE");
1395 	} else {
1396 		/* Request */
1397 		DHD_STATLOG_DATA(dhdp, ST(DNS_QUERY), ifidx, tx, cond);
1398 		DNS_REQ_PRINT("DNS REQUEST");
1399 	}
1400 
1401 	if (ifidx == 0) {
1402 		dhd_dump_pkt_cnts_inc(dhdp, tx, pktfate, PKT_CNT_TYPE_DNS);
1403 	}
1404 }
1405 #endif /* DHD_DNS_DUMP */
1406 
1407 #ifdef DHD_TRX_DUMP
1408 void
dhd_trx_pkt_dump(dhd_pub_t * dhdp,int ifidx,uint8 * pktdata,uint32 pktlen,bool tx)1409 dhd_trx_pkt_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen, bool tx)
1410 {
1411 	struct ether_header *eh;
1412 	uint16 protocol;
1413 	char *pkttype = "UNKNOWN";
1414 
1415 	if (!(dump_msg_level & DUMP_TRX_VAL))
1416 		return;
1417 
1418 	if (!dhdp) {
1419 		DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
1420 		return;
1421 	}
1422 
1423 	if (!pktdata) {
1424 		DHD_ERROR(("%s: pktdata is NULL\n", __FUNCTION__));
1425 		return;
1426 	}
1427 
1428 	eh = (struct ether_header *)pktdata;
1429 	protocol = hton16(eh->ether_type);
1430 	BCM_REFERENCE(pktlen);
1431 
1432 	switch (protocol) {
1433 	case ETHER_TYPE_IP:
1434 		pkttype = "IP";
1435 		break;
1436 	case ETHER_TYPE_ARP:
1437 		pkttype = "ARP";
1438 		break;
1439 	case ETHER_TYPE_BRCM:
1440 		pkttype = "BRCM";
1441 		break;
1442 	case ETHER_TYPE_802_1X:
1443 		pkttype = "802.1X";
1444 		break;
1445 	case ETHER_TYPE_WAI:
1446 		pkttype = "WAPI";
1447 		break;
1448 	default:
1449 		break;
1450 	}
1451 
1452 	if (protocol != ETHER_TYPE_BRCM) {
1453 		if (pktdata[0] == 0xFF) {
1454 			DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] %s BROADCAST DUMP - %s\n",
1455 				dhd_ifname(dhdp, ifidx), tx?"TX":"RX", pkttype));
1456 		} else if (pktdata[0] & 1) {
1457 			DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] %s MULTICAST DUMP " MACDBG " - %s\n",
1458 				dhd_ifname(dhdp, ifidx), tx?"TX":"RX", MAC2STRDBG(pktdata), pkttype));
1459 		} else {
1460 			DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] %s DUMP - %s\n",
1461 				dhd_ifname(dhdp, ifidx), tx?"TX":"RX", pkttype));
1462 		}
1463 #ifdef DHD_RX_FULL_DUMP
1464 		prhex("Data", pktdata, pktlen);
1465 #endif /* DHD_RX_FULL_DUMP */
1466 	}
1467 	else {
1468 		DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] %s DUMP - %s\n",
1469 			dhd_ifname(dhdp, ifidx), tx?"TX":"RX", pkttype));
1470 	}
1471 }
1472 #endif /* DHD_RX_DUMP */
1473