dhd_linux_pktdump.c 37 KB

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