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