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