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