summaryrefslogtreecommitdiff
path: root/include/hardware_legacy/wifi_logger.h
blob: 465c00b734a6b39b573566279a32a8869bcfbfe1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
#include "wifi_hal.h"

#ifndef __WIFI_HAL_LOGGER_H
#define __WIFI_HAL_LOGGER_H

#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */

#define LOGGER_MAJOR_VERSION    1
#define LOGGER_MINOR_VERSION    0
#define LOGGER_MICRO_VERSION    0



/**
 * WiFi logger life cycle is as follow:
 *
 * - At initialization time, framework will call wifi_get_ring_buffers_status
 *   so as to obtain the names and list of supported buffers.
 * - When WiFi operation start framework will call wifi_start_logging
 *   so as to trigger log collection.
 * - Developper UI will provide an option to the user, so as it can set the verbose level
 *   of individual buffer as reported by wifi_get_ring_buffers_status.
 * - During wifi operations, driver will periodically report per ring data to framework
 *   by invoking the on_ring_buffer_data call back.
 * - when capturing a bug report, framework will indicate to driver that all the data
 *   has to be uploaded, urgently, by calling wifi_get_ring_data.
 *
 * The data uploaded by driver will be stored by framework in separate files, with one stream
 *   of file per ring.
 * Framework will store the files in pcapng format, allowing for easy merging and parsing
 *   with network analyzer tools.
 */


typedef int wifi_radio;
typedef int wifi_ring_buffer_id;

#define PER_PACKET_ENTRY_FLAGS_DIRECTION_TX  1    // 0: TX, 1: RX
#define PER_PACKET_ENTRY_FLAGS_TX_SUCCESS    2    // whether packet was transmitted or
                                                  // received/decrypted successfully
#define PER_PACKET_ENTRY_FLAGS_80211_HEADER  4    // has full 802.11 header, else has 802.3 header
#define PER_PACKET_ENTRY_FLAGS_PROTECTED     8    // whether packet was encrypted

typedef struct {
    u8 flags;
    u8 tid;     // transmit or received tid
    u16 MCS;    // modulation and bandwidth
    u8 rssi;    // TX: RSSI of ACK for that packet
                // RX: RSSI of packet
    u8 num_retries;                   // number of attempted retries
    u16 last_transmit_rate;           // last transmit rate in .5 mbps
    u16 link_layer_transmit_sequence; // transmit/reeive sequence for that MPDU packet
    u64 firmware_entry_timestamp;     // TX: firmware timestamp (us) when packet is queued within
                                      // firmware buffer for SDIO/HSIC or into PCIe buffer
                                      // RX: firmware receive timestamp
    u64 start_contention_timestamp; // firmware timestamp (us) when packet start contending for the
                                    // medium for the first time, at head of its AC queue,
                                    // or as part of an MPDU or A-MPDU. This timestamp is
                                    // not updated for each retry, only the first transmit attempt.
    u64 transmit_success_timestamp; // fimrware timestamp (us) when packet is successfully
                                    // transmitted or aborted because it has exhausted
                                    // its maximum number of retries.
    u8 data[0]; // packet data. The length of packet data is determined by the entry_size field of
                // the wifi_ring_buffer_entry structure. It is expected that first bytes of the
                // packet, or packet headers only (up to TCP or RTP/UDP headers)
                // will be copied into the ring
} __attribute__((packed)) wifi_ring_per_packet_status_entry;


/* Below events refer to the wifi_connectivity_event ring and shall be supported */
#define WIFI_EVENT_ASSOCIATION_REQUESTED    0  // driver receives association command from kernel
#define WIFI_EVENT_AUTH_COMPLETE            1
#define WIFI_EVENT_ASSOC_COMPLETE           2
#define WIFI_EVENT_FW_AUTH_STARTED          3  // fw event indicating auth frames are sent
#define WIFI_EVENT_FW_ASSOC_STARTED         4  // fw event indicating assoc frames are sent
#define WIFI_EVENT_FW_RE_ASSOC_STARTED      5  // fw event indicating reassoc frames are sent
#define WIFI_EVENT_DRIVER_SCAN_REQUESTED    6
#define WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND 7
#define WIFI_EVENT_DRIVER_SCAN_COMPLETE     8
#define WIFI_EVENT_G_SCAN_STARTED           9
#define WIFI_EVENT_G_SCAN_COMPLETE          10
#define WIFI_EVENT_DISASSOCIATION_REQUESTED 11
#define WIFI_EVENT_RE_ASSOCIATION_REQUESTED 12
#define WIFI_EVENT_ROAM_REQUESTED           13
#define WIFI_EVENT_BEACON_RECEIVED          14  // received beacon from AP (event enabled
                                                // only in verbose mode)
#define WIFI_EVENT_ROAM_SCAN_STARTED        15  // firmware has triggered a roam scan (not g-scan)
#define WIFI_EVENT_ROAM_SCAN_COMPLETE       16  // firmware has completed a roam scan (not g-scan)
#define WIFI_EVENT_ROAM_SEARCH_STARTED      17  // firmware has started searching for roam
                                                // candidates (with reason =xx)
#define WIFI_EVENT_ROAM_SEARCH_STOPPED      18  // firmware has stopped searching for roam
                                                // candidates (with reason =xx)
#define WIFI_EVENT_CHANNEL_SWITCH_ANOUNCEMENT     20 // received channel switch anouncement from AP
#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START  21 // fw start transmit eapol frame, with
                                                     // EAPOL index 1-4
#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP   22 // fw gives up eapol frame, with rate,
                                                     // success/failure and number retries
#define WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED 23 // kernel queue EAPOL for transmission
                                                            // in driver with EAPOL index 1-4
#define WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED        24 // with rate, regardless of the fact that
                                                     // EAPOL frame is accepted or rejected by fw
#define WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED    26 // with rate, and eapol index, driver has
                                                     // received EAPOL frame and will queue it up
                                                     // to wpa_supplicant
#define WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE 27 // with success/failure, parameters
#define WIFI_EVENT_BT_COEX_BT_SCO_START     28
#define WIFI_EVENT_BT_COEX_BT_SCO_STOP      29
#define WIFI_EVENT_BT_COEX_BT_SCAN_START    30  // for paging/scan etc., when BT starts transmiting
                                                // twice per BT slot
#define WIFI_EVENT_BT_COEX_BT_SCAN_STOP     31
#define WIFI_EVENT_BT_COEX_BT_HID_START     32
#define WIFI_EVENT_BT_COEX_BT_HID_STOP      33
#define WIFI_EVENT_ROAM_AUTH_STARTED        34  // fw sends auth frame in roaming to next candidate
#define WIFI_EVENT_ROAM_AUTH_COMPLETE       35  // fw receive auth confirm from ap
#define WIFI_EVENT_ROAM_ASSOC_STARTED       36  // firmware sends assoc/reassoc frame in
                                                // roaming to next candidate
#define WIFI_EVENT_ROAM_ASSOC_COMPLETE      37  // firmware receive assoc/reassoc confirm from ap
#define WIFI_EVENT_G_SCAN_STOP              38  // firmware sends stop G_SCAN
#define WIFI_EVENT_G_SCAN_CYCLE_STARTED     39  // firmware indicates G_SCAN scan cycle started
#define WIFI_EVENT_G_SCAN_CYCLE_COMPLETED   40  // firmware indicates G_SCAN scan cycle completed
#define WIFI_EVENT_G_SCAN_BUCKET_STARTED    41  // firmware indicates G_SCAN scan start
                                                // for a particular bucket
#define WIFI_EVENT_G_SCAN_BUCKET_COMPLETED  42  // firmware indicates G_SCAN scan completed for
                                                // for a particular bucket
#define WIFI_EVENT_G_SCAN_RESULTS_AVAILABLE 43  // Event received from firmware about G_SCAN scan
                                                // results being available
#define WIFI_EVENT_G_SCAN_CAPABILITIES      44  // Event received from firmware with G_SCAN
                                                // capabilities
#define WIFI_EVENT_ROAM_CANDIDATE_FOUND     45  // Event received from firmware when eligible
                                                // candidate is found
#define WIFI_EVENT_ROAM_SCAN_CONFIG         46  // Event received from firmware when roam scan
                                                // configuration gets enabled or disabled
#define WIFI_EVENT_AUTH_TIMEOUT             47  // firmware/driver timed out authentication
#define WIFI_EVENT_ASSOC_TIMEOUT            48  // firmware/driver timed out association
#define WIFI_EVENT_MEM_ALLOC_FAILURE        49  // firmware/driver encountered allocation failure
#define WIFI_EVENT_DRIVER_PNO_ADD           50  // driver added a PNO network in firmware
#define WIFI_EVENT_DRIVER_PNO_REMOVE        51  // driver removed a PNO network in firmware
#define WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND 52  // driver received PNO networks
                                                // found indication from firmware
#define WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED 53  // driver triggered a scan for PNO networks
#define WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND 54  // driver received scan results
                                                    // of PNO networks
#define WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE 55  // driver updated scan results from
                                                // PNO networks to cfg80211

/**
 * Parameters of wifi logger events are TLVs
 * Event parameters tags are defined as:
 */
#define WIFI_TAG_VENDOR_SPECIFIC    0   // take a byte stream as parameter
#define WIFI_TAG_BSSID              1   // takes a 6 bytes MAC address as parameter
#define WIFI_TAG_ADDR               2   // takes a 6 bytes MAC address as parameter
#define WIFI_TAG_SSID               3   // takes a 32 bytes SSID address as parameter
#define WIFI_TAG_STATUS             4   // takes an integer as parameter
#define WIFI_TAG_CHANNEL_SPEC       5   // takes one or more wifi_channel_spec as parameter
#define WIFI_TAG_WAKE_LOCK_EVENT    6   // takes a wake_lock_event struct as parameter
#define WIFI_TAG_ADDR1              7   // takes a 6 bytes MAC address as parameter
#define WIFI_TAG_ADDR2              8   // takes a 6 bytes MAC address as parameter
#define WIFI_TAG_ADDR3              9   // takes a 6 bytes MAC address as parameter
#define WIFI_TAG_ADDR4              10  // takes a 6 bytes MAC address as parameter
#define WIFI_TAG_TSF                11  // take a 64 bits TSF value as parameter
#define WIFI_TAG_IE                 12  // take one or more specific 802.11 IEs parameter,
                                        // IEs are in turn indicated in TLV format as per 
                                        // 802.11 spec
#define WIFI_TAG_INTERFACE          13  // take interface name as parameter
#define WIFI_TAG_REASON_CODE        14  // take a reason code as per 802.11 as parameter
#define WIFI_TAG_RATE_MBPS          15  // take a wifi rate in 0.5 mbps
#define WIFI_TAG_REQUEST_ID         16  // take an integer as parameter
#define WIFI_TAG_BUCKET_ID          17  // take an integer as parameter
#define WIFI_TAG_GSCAN_PARAMS       18  // takes a wifi_scan_cmd_params struct as parameter
#define WIFI_TAG_GSCAN_CAPABILITIES 19  // takes a wifi_gscan_capabilities struct as parameter
#define WIFI_TAG_SCAN_ID            20  // take an integer as parameter
#define WIFI_TAG_RSSI               21  // take an integer as parameter
#define WIFI_TAG_CHANNEL            22  // take an integer as parameter
#define WIFI_TAG_LINK_ID            23  // take an integer as parameter
#define WIFI_TAG_LINK_ROLE          24  // take an integer as parameter
#define WIFI_TAG_LINK_STATE         25  // take an integer as parameter
#define WIFI_TAG_LINK_TYPE          26  // take an integer as parameter
#define WIFI_TAG_TSCO               27  // take an integer as parameter
#define WIFI_TAG_RSCO               28  // take an integer as parameter
#define WIFI_TAG_EAPOL_MESSAGE_TYPE 29  // take an integer as parameter
                                        // M1-1, M2-2, M3-3, M4-4

typedef struct {
    u16 tag;
    u16 length; // length of value
    u8 value[0];
} __attribute__((packed)) tlv_log;

typedef struct {
    u16 event;
    tlv_log tlvs[0];   // separate parameter structure per event to be provided and optional data
                       // the event_data is expected to include an official android part, with some
                       // parameter as transmit rate, num retries, num scan result found etc...
                       // as well, event_data can include a vendor proprietary part which is
                       // understood by the developer only.
} __attribute__((packed)) wifi_ring_buffer_driver_connectivity_event;


/**
 * Ring buffer name for power events ring. note that power event are extremely frequents
 * and thus should be stored in their own ring/file so as not to clobber connectivity events.
 */
typedef struct {
    int status;      // 0 taken, 1 released
    int reason;      // reason why this wake lock is taken
    char name[0];    // null terminated
} __attribute__((packed)) wake_lock_event;

typedef struct {
    u16 event;
    tlv_log tlvs[0];
} __attribute__((packed)) wifi_power_event;


/**
 * This structure represent a logger entry within a ring buffer.
 * Wifi driver are responsible to manage the ring buffer and write the debug
 * information into those rings.
 *
 * In general, the debug entries can be used to store meaningful 802.11 information (SME, MLME,
 * connection and packet statistics) as well as vendor proprietary data that is specific to a
 * specific driver or chipset.
 * Binary entries can be used so as to store packet data or vendor specific information and
 * will be treated as blobs of data by android.
 *
 * A user land process will be started by framework so as to periodically retrieve the
 * data logged by drivers into their ring buffer, store the data into log files and include
 * the logs into android bugreports.
 */
enum {
    RING_BUFFER_ENTRY_FLAGS_HAS_BINARY = (1 << (0)),    // set for binary entries
    RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1))  // set if 64 bits timestamp is present
};

enum {
    ENTRY_TYPE_CONNECT_EVENT = 1,
    ENTRY_TYPE_PKT,
    ENTRY_TYPE_WAKE_LOCK,
    ENTRY_TYPE_POWER_EVENT,
    ENTRY_TYPE_DATA
};

typedef struct {
    u16 entry_size; // the size of payload excluding the header.
    u8 flags;
    u8 type;        // entry type
    u64 timestamp;  // present if has_timestamp bit is set.
} __attribute__((packed)) wifi_ring_buffer_entry;

#define WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES 0x00000001   // set if binary entries are present
#define WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES  0x00000002   // set if ascii entries are present


/* ring buffer params */
/**
 * written_bytes and read_bytes implement a producer consumer API
 *     hence written_bytes >= read_bytes
 * a modulo arithmetic of the buffer size has to be applied to those counters:
 * actual offset into ring buffer = written_bytes % ring_buffer_byte_size
 *
 */
typedef struct {
    u8 name[32];
    u32 flags;
    wifi_ring_buffer_id ring_id; // unique integer representing the ring
    u32 ring_buffer_byte_size;   // total memory size allocated for the buffer
    u32 verbose_level;           // verbose level for ring buffer
    u32 written_bytes;           // number of bytes that was written to the buffer by driver,
                                 // monotonously increasing integer
    u32 read_bytes;              // number of bytes that was read from the buffer by user land,
                                 // monotonously increasing integer
    u32 written_records;         // number of records that was written to the buffer by driver,
                                 // monotonously increasing integer
} wifi_ring_buffer_status;


/**
 * Callback for reporting ring data
 *
 * The ring buffer data collection is event based:
 *   - Driver calls on_ring_buffer_data when new records are available, the wifi_ring_buffer_status
 *     passed up to framework in the call back indicates to framework if more data is available in
 *     the ring buffer. It is not expected that driver will necessarily always empty the ring
 *     immediately as data is available, instead driver will report data every X seconds or if
 *     N bytes are available.
 *   - In the case where a bug report has to be captured, framework will require driver to upload
 *     all data immediately. This is indicated to driver when framework calls wifi_get_ringdata.
 *     When framework calls wifi_get_ring_data, driver will start sending all available data in the
 *     indicated ring by repeatedly invoking the on_ring_buffer_data callback.
 *
 * The callback is called by log handler whenever ring data comes in driver.
 */
typedef struct {
  void (*on_ring_buffer_data) (char *ring_name, char *buffer, int buffer_size,
        wifi_ring_buffer_status *status);
} wifi_ring_buffer_data_handler;

/**
 * API to set the log handler for getting ring data
 *  - Only a single instance of log handler can be instantiated for each ring buffer.
 */
wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface,
    wifi_ring_buffer_data_handler handler);

/* API to reset the log handler */
wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface);


/**
 * Callback for reporting FW dump
 *
 * The buffer data collection is event based such as FW health check or FW dump.
 * The callback is called by alert handler.
 */
typedef struct {
   void (*on_alert) (wifi_request_id id, char *buffer, int buffer_size, int err_code);
} wifi_alert_handler;

/*
 * API to set the alert handler for the alert case in Wi-Fi Chip
 *  - Only a single instance of alert handler can be instantiated.
 */
wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,
    wifi_alert_handler handler);

/* API to reset the alert handler */
wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface);

/* API for framework to indicate driver has to upload and drain all data of a given ring */
wifi_error wifi_get_ring_data(wifi_interface_handle iface, char *ring_name);


/**
 * API to trigger the debug collection.
 *  Unless his API is invoked - logging is not triggered.
 *  - Verbose_level 0 corresponds to no collection,
 *    and it makes log handler stop by no more events from driver.
 *  - Verbose_level 1 correspond to normal log level, with minimal user impact.
 *    This is the default value.
 *  - Verbose_level 2 are enabled when user is lazily trying to reproduce a problem,
 *    wifi performances and power can be impacted but device should not otherwise be
 *    significantly impacted.
 *  - Verbose_level 3+ are used when trying to actively debug a problem.
 *
 * ring_name represent the name of the ring for which data collection shall start.
 *
 * flags: TBD parameter used to enable/disable specific events on a ring
 * max_interval: maximum interval in seconds for driver to invoke on_ring_buffer_data,
 *               ignore if zero
 * min_data_size: minimum data size in buffer for driver to invoke on_ring_buffer_data,
 *                ignore if zero
 */
wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level, u32 flags,
    u32 max_interval_sec, u32 min_data_size, char *ring_name);

/**
 * API to get the status of all ring buffers supported by driver.
 *  - Caller is responsible to allocate / free ring buffer status.
 *  - Maximum no of ring buffer would be 10.
 */
wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface, u32 *num_rings,
    wifi_ring_buffer_status *status);

/**
 * Synchronous memory dump by user request.
 *  - Caller is responsible to store memory dump data into a local,
 *      e.g., /data/misc/wifi/memdump.bin
 */
typedef struct {
    void (*on_firmware_memory_dump) (char *buffer, int buffer_size);
} wifi_firmware_memory_dump_handler;

/**
 * API to collect a firmware memory dump for a given iface by async memdump event.
 *  - Triggered by Alerthandler, esp. when FW problem or FW health check happens
 *  - Caller is responsible to store fw dump data into a local,
 *      e.g., /data/misc/wifi/alertdump-1.bin
 */
wifi_error wifi_get_firmware_memory_dump(wifi_interface_handle iface,
    wifi_firmware_memory_dump_handler handler);

/**
 * API to collect a firmware version string.
 *  - Caller is responsible to allocate / free a buffer to retrieve firmware verion info.
 *  - Max string will be at most 256 bytes.
 */
wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char *buffer, int buffer_size);

/**
 * API to collect a driver version string.
 *  - Caller is responsible to allocate / free a buffer to retrieve driver verion info.
 *  - Max string will be at most 256 bytes.
 */
wifi_error wifi_get_driver_version(wifi_interface_handle iface, char *buffer, int buffer_size);


/* Feature set */
enum {
    WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)),             // Memory dump of FW
    WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), // PKT status
    WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)),           // Connectivity event
    WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)),             // POWER of Driver
    WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)),               // WAKE LOCK of Driver
    WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)),                 // verbose log of FW
    WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6)),          // monitor the health of FW
    WIFI_LOGGER_DRIVER_DUMP_SUPPORTED = (1 << (7)),             // dumps driver state
    WIFI_LOGGER_PACKET_FATE_SUPPORTED = (1 << (8)),             // tracks connection packets' fate
};

/**
 * API to retrieve the current supportive features.
 *  - An integer variable is enough to have bit mapping info by caller.
 */
wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
    unsigned int *support);

typedef struct {
    /* Buffer is to be allocated and freed by HAL implementation. */
    void (*on_driver_memory_dump) (char *buffer, int buffer_size);
} wifi_driver_memory_dump_callbacks;

/**
    API to collect driver state.

    Framework will call this API soon before or after (but not
    concurrently with) wifi_get_firmware_memory_dump(). Capturing
    firmware and driver dumps is intended to help identify
    inconsistent state between these components.

    - In response to this call, HAL implementation should make one or
      more calls to callbacks.on_driver_memory_dump(). Framework will
      copy data out of the received |buffer|s, and concatenate the
      contents thereof.
    - HAL implemention will indicate completion of the driver memory
      dump by returning from this call.
*/
wifi_error wifi_get_driver_memory_dump(
    wifi_interface_handle iface,
    wifi_driver_memory_dump_callbacks callbacks);


/* packet fate logs */

#define MD5_PREFIX_LEN             4
#define MAX_FATE_LOG_LEN           32
#define MAX_FRAME_LEN_ETHERNET     1518
#define MAX_FRAME_LEN_80211_MGMT   2352  // 802.11-2012 Fig. 8-34

typedef enum {
    // Sent over air and ACKed.
    TX_PKT_FATE_ACKED,

    // Sent over air but not ACKed. (Normal for broadcast/multicast.)
    TX_PKT_FATE_SENT,

    // Queued within firmware, but not yet sent over air.
    TX_PKT_FATE_FW_QUEUED,

    // Dropped by firmware as invalid. E.g. bad source address, bad checksum,
    // or invalid for current state.
    TX_PKT_FATE_FW_DROP_INVALID,

    // Dropped by firmware due to lack of buffer space.
    TX_PKT_FATE_FW_DROP_NOBUFS,

    // Dropped by firmware for any other reason. Includes frames that
    // were sent by driver to firmware, but unaccounted for by
    // firmware.
    TX_PKT_FATE_FW_DROP_OTHER,

    // Queued within driver, not yet sent to firmware.
    TX_PKT_FATE_DRV_QUEUED,

    // Dropped by driver as invalid. E.g. bad source address, or
    // invalid for current state.
    TX_PKT_FATE_DRV_DROP_INVALID,

    // Dropped by driver due to lack of buffer space.
    TX_PKT_FATE_DRV_DROP_NOBUFS,

    // Dropped by driver for any other reason.
    TX_PKT_FATE_DRV_DROP_OTHER,
} wifi_tx_packet_fate;

typedef enum {
    // Valid and delivered to network stack (e.g., netif_rx()).
    RX_PKT_FATE_SUCCESS,

    // Queued within firmware, but not yet sent to driver.
    RX_PKT_FATE_FW_QUEUED,

    // Dropped by firmware due to host-programmable filters.
    RX_PKT_FATE_FW_DROP_FILTER,

    // Dropped by firmware as invalid. E.g. bad checksum, decrypt failed,
    // or invalid for current state.
    RX_PKT_FATE_FW_DROP_INVALID,

    // Dropped by firmware due to lack of buffer space.
    RX_PKT_FATE_FW_DROP_NOBUFS,

    // Dropped by firmware for any other reason.
    RX_PKT_FATE_FW_DROP_OTHER,

    // Queued within driver, not yet delivered to network stack.
    RX_PKT_FATE_DRV_QUEUED,

    // Dropped by driver due to filter rules.
    RX_PKT_FATE_DRV_DROP_FILTER,

    // Dropped by driver as invalid. E.g. not permitted in current state.
    RX_PKT_FATE_DRV_DROP_INVALID,

    // Dropped by driver due to lack of buffer space.
    RX_PKT_FATE_DRV_DROP_NOBUFS,

    // Dropped by driver for any other reason.
    RX_PKT_FATE_DRV_DROP_OTHER,
} wifi_rx_packet_fate;

typedef enum {
    FRAME_TYPE_UNKNOWN,
    FRAME_TYPE_ETHERNET_II,
    FRAME_TYPE_80211_MGMT,
} frame_type;

typedef struct {
    // The type of MAC-layer frame that this frame_info holds.
    // - For data frames, use FRAME_TYPE_ETHERNET_II.
    // - For management frames, use FRAME_TYPE_80211_MGMT.
    // - If the type of the frame is unknown, use FRAME_TYPE_UNKNOWN.
    frame_type payload_type;

    // The number of bytes included in |frame_content|. If the frame
    // contents are missing (e.g. RX frame dropped in firmware),
    // |frame_len| should be set to 0.
    size_t frame_len;

    // Host clock when this frame was received by the driver (either
    // outbound from the host network stack, or inbound from the
    // firmware).
    // - The timestamp should be taken from a clock which includes time
    //   the host spent suspended (e.g. ktime_get_boottime()).
    // - If no host timestamp is available (e.g. RX frame was dropped in
    //   firmware), this field should be set to 0.
    u32 driver_timestamp_usec;

    // Firmware clock when this frame was received by the firmware
    // (either outbound from the host, or inbound from a remote
    // station).
    // - The timestamp should be taken from a clock which includes time
    //   firmware spent suspended (if applicable).
    // - If no firmware timestamp is available (e.g. TX frame was
    //   dropped by driver), this field should be set to 0.
    // - Consumers of |frame_info| should _not_ assume any
    //   synchronization between driver and firmware clocks.
    u32 firmware_timestamp_usec;

    // Actual frame content.
    // - Should be provided for TX frames originated by the host.
    // - Should be provided for RX frames received by the driver.
    // - Optionally provided for TX frames originated by firmware. (At
    //   discretion of HAL implementation.)
    // - Optionally provided for RX frames dropped in firmware. (At
    //   discretion of HAL implementation.)
    // - If frame content is not provided, |frame_len| should be set
    //   to 0.
    union {
      char ethernet_ii_bytes[MAX_FRAME_LEN_ETHERNET];
      char ieee_80211_mgmt_bytes[MAX_FRAME_LEN_80211_MGMT];
    } frame_content;
} frame_info;

typedef struct {
    // Prefix of MD5 hash of |frame_inf.frame_content|. If frame
    // content is not provided, prefix of MD5 hash over the same data
    // that would be in frame_content, if frame content were provided.
    char md5_prefix[MD5_PREFIX_LEN];
    wifi_tx_packet_fate fate;
    frame_info frame_inf;
} wifi_tx_report;

typedef struct {
    // Prefix of MD5 hash of |frame_inf.frame_content|. If frame
    // content is not provided, prefix of MD5 hash over the same data
    // that would be in frame_content, if frame content were provided.
    char md5_prefix[MD5_PREFIX_LEN];
    wifi_rx_packet_fate fate;
    frame_info frame_inf;
} wifi_rx_report;

/**
    API to start packet fate monitoring.
    - Once stared, monitoring should remain active until HAL is unloaded.
    - When HAL is unloaded, all packet fate buffers should be cleared.
*/
wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle);

/**
    API to retrieve fates of outbound packets.
    - HAL implementation should fill |tx_report_bufs| with fates of
      _first_ min(n_requested_fates, actual packets) frames
      transmitted for the most recent association. The fate reports
      should follow the same order as their respective packets.
    - HAL implementation may choose (but is not required) to include
      reports for management frames.
    - Packets reported by firmware, but not recognized by driver,
      should be included.  However, the ordering of the corresponding
      reports is at the discretion of HAL implementation.
    - Framework may call this API multiple times for the same association.
    - Framework will ensure |n_requested_fates <= MAX_FATE_LOG_LEN|.
    - Framework will allocate and free the referenced storage.
*/
wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle,
        wifi_tx_report *tx_report_bufs,
        size_t n_requested_fates,
        size_t *n_provided_fates);

/**
    API to retrieve fates of inbound packets.
    - HAL implementation should fill |rx_report_bufs| with fates of
      _first_ min(n_requested_fates, actual packets) frames
      received for the most recent association. The fate reports
      should follow the same order as their respective packets.
    - HAL implementation may choose (but is not required) to include
      reports for management frames.
    - Packets reported by firmware, but not recognized by driver,
      should be included.  However, the ordering of the corresponding
      reports is at the discretion of HAL implementation.
    - Framework may call this API multiple times for the same association.
    - Framework will ensure |n_requested_fates <= MAX_FATE_LOG_LEN|.
    - Framework will allocate and free the referenced storage.
*/
wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle,
        wifi_rx_report *rx_report_bufs,
        size_t n_requested_fates,
        size_t *n_provided_fates);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /*__WIFI_HAL_STATS_ */