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