mirror of
https://github.com/qca/qca-swiss-army-knife.git
synced 2025-12-10 07:44:42 +01:00
With "ath10k: simplify pktlog htt event processing" approach, driver passes entire payload stipping the htt_response header. By this method, we could receive pktlog events that has payload size higher than mentioned in pktlog header (for alignment reasons) This issue is seen with 10.2 FW for ATH10K_PKTLOG_TYPE_TX_MSDU_ID type events. So throw exception only when payload size is lesser than the one mentioned in pktlog header
430 lines
13 KiB
Python
430 lines
13 KiB
Python
#
|
|
# Copyright (c) 2014 Qualcomm Atheros, Inc.
|
|
#
|
|
# Permission to use, copy, modify, and/or distribute this software for any
|
|
# purpose with or without fee is hereby granted, provided that the above
|
|
# copyright notice and this permission notice appear in all copies.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
#
|
|
# trace-cmd pktlog plugin for ath10k, QCA Linux wireless driver
|
|
#
|
|
# TODO:
|
|
#
|
|
# o create class for struct ieee80211_hdr each packet headers with
|
|
# pack() and unpack() methods
|
|
|
|
import struct
|
|
import binascii
|
|
|
|
DEBUG = 1
|
|
|
|
CUR_PKTLOG_VER = 10010
|
|
PKTLOG_MAGIC_NUM = 7735225
|
|
|
|
IEEE80211_FCTL_TODS = 0x0100
|
|
IEEE80211_FCTL_FROMDS = 0x0200
|
|
TARGET_NUM_MSDU_DESC = (1024 + 400)
|
|
MAX_PKT_INFO_MSDU_ID = 192
|
|
MAX_10_4_PKT_INFO_MSDU_ID = 1
|
|
PKTLOG_MAX_TXCTL_WORDS = 57
|
|
|
|
ATH10K_PKTLOG_HW_QCA988X = 0
|
|
ATH10K_PKTLOG_HW_QCA6174 = 1
|
|
ATH10K_PKTLOG_HW_QCA99X0 = 2
|
|
ATH10K_PKTLOG_HW_QCA9984 = 3
|
|
ATH10K_PKTLOG_HW_QCA9888 = 4
|
|
ATH10K_PKTLOG_HW_QCA9377 = 5
|
|
ATH10K_PKTLOG_HW_QCA40XX = 6
|
|
|
|
ATH10K_PKTLOG_TYPE_TX_CTRL = 1
|
|
ATH10K_PKTLOG_TYPE_TX_STAT = 2
|
|
ATH10K_PKTLOG_TYPE_TX_MSDU_ID = 3
|
|
ATH10K_PKTLOG_TYPE_TX_FRM_HDR = 4
|
|
ATH10K_PKTLOG_TYPE_RX_STAT = 5
|
|
ATH10K_PKTLOG_TYPE_RC_FIND = 6
|
|
ATH10K_PKTLOG_TYPE_RC_UPDATE = 7
|
|
ATH10K_PKTLOG_TYPE_TX_VIRT_ADDR = 8
|
|
ATH10K_PKTLOG_TYPE_DBG_PRINT = 9
|
|
|
|
ATH10K_PKTLOG_FLG_TYPE_LOCAL_S = 0
|
|
ATH10K_PKTLOG_FLG_TYPE_REMOTE_S = 1
|
|
ATH10K_PKTLOG_FLG_TYPE_CLONE_S = 2
|
|
ATH10K_PKTLOG_FLG_TYPE_UNKNOWN_S = 3
|
|
|
|
# sizeof(ath10k_pktlog_txctl) = 12 + 4 * 57
|
|
ATH10K_PKTLOG_TXCTL_LEN = 240
|
|
ATH10K_PKTLOG_MAX_TXCTL_WORDS = 57
|
|
# sizeof(ath10k_pktlog_10_4_txctl)2 = 16 + 4 * 153
|
|
ATH10K_PKTLOG_10_4_TXCTL_LEN = 624
|
|
ATH10K_PKTLOG_10_4_MAX_TXCTL_WORDS = 153
|
|
|
|
msdu_len_tbl = {}
|
|
output_file = None
|
|
frm_hdr = None
|
|
|
|
def dbg(msg):
|
|
if DEBUG == 0:
|
|
return
|
|
|
|
print msg
|
|
|
|
def hexdump(buf, prefix=None):
|
|
s = binascii.b2a_hex(buf)
|
|
s_len = len(s)
|
|
result = ""
|
|
|
|
if prefix == None:
|
|
prefix = ""
|
|
|
|
for i in range(s_len / 2):
|
|
if i % 16 == 0:
|
|
result = result + ("%s%04x: " % (prefix, i))
|
|
|
|
result = result + (s[2*i] + s[2*i+1] + " ")
|
|
|
|
if (i + 1) % 16 == 0:
|
|
result = result + "\n"
|
|
|
|
# FIXME: if len(s) % 16 == 0 there's an extra \n in the end
|
|
|
|
return result
|
|
|
|
# struct ath10k_pktlog_hdr {
|
|
# unsigned short flags;
|
|
# unsigned short missed_cnt;
|
|
# unsigned short log_type;
|
|
# unsigned short size;
|
|
# unsigned int timestamp;
|
|
# unsigned char payload[0];
|
|
# } __attribute__((__packed__));
|
|
class Ath10kPktlogHdr:
|
|
# 2 + 2 + 2 + 2 + 4 = 12
|
|
hdr_len = 12
|
|
struct_fmt = '<HHHHI'
|
|
|
|
def unpack(self, buf, offset=0):
|
|
(self.flags, self.missed_cnt, self.log_type,
|
|
self.size, self.timestamp) = struct.unpack_from(self.struct_fmt, buf, 0)
|
|
|
|
payload_len = len(buf) - self.hdr_len
|
|
if payload_len < self.size:
|
|
raise Exception('Payload length invalid: %d != %d' %
|
|
(payload_len, self.size))
|
|
|
|
self.payload = buf[self.hdr_len:]
|
|
|
|
# excludes payload, you have to write that separately!
|
|
def pack(self):
|
|
return struct.pack(self.struct_fmt,
|
|
self.flags,
|
|
self.missed_cnt,
|
|
self.log_type,
|
|
self.size,
|
|
self.timestamp)
|
|
|
|
def __str__(self):
|
|
return 'flags %04x miss %d log_type %d size %d timestamp %d\n' % \
|
|
(self.flags, self.missed_cnt, self.log_type, self.size, self.timestamp)
|
|
|
|
def __init__(self):
|
|
self.flags = 0
|
|
self.missed_cnt = 0
|
|
self.log_type = 0
|
|
self.size = 0
|
|
self.timestamp = 0
|
|
self.payload = []
|
|
|
|
# struct ath10k_pktlog_10_4_hdr {
|
|
# unsigned short flags;
|
|
# unsigned short missed_cnt;
|
|
# unsigned short log_type;
|
|
# unsigned short size;
|
|
# unsigned int timestamp;
|
|
# unsigned int type_specific_data;
|
|
# unsigned char payload[0];
|
|
# } __attribute__((__packed__));
|
|
class Ath10kPktlog_10_4_Hdr:
|
|
# 2 + 2 + 2 + 2 + 4 + 4 = 16
|
|
hdr_len = 16
|
|
struct_fmt = '<HHHHII'
|
|
|
|
def unpack(self, buf, offset=0):
|
|
(self.flags, self.missed_cnt, self.log_type,
|
|
self.size, self.timestamp, self.type_specific_data) = struct.unpack_from(self.struct_fmt, buf, 0)
|
|
|
|
payload_len = len(buf) - self.hdr_len
|
|
|
|
if payload_len != self.size:
|
|
raise Exception('Payload length invalid: %d != %d' %
|
|
(payload_len, self.size))
|
|
|
|
self.payload = buf[self.hdr_len:]
|
|
|
|
# excludes payload, you have to write that separately!
|
|
def pack(self):
|
|
return struct.pack(self.struct_fmt,
|
|
self.flags,
|
|
self.missed_cnt,
|
|
self.log_type,
|
|
self.size,
|
|
self.timestamp,
|
|
self.type_specific_data)
|
|
|
|
def __str__(self):
|
|
return 'flags %04x miss %d log_type %d size %d timestamp %d type_specific_data %d\n' % \
|
|
(self.flags, self.missed_cnt, self.log_type, self.size, self.timestamp, self.type_specific_data)
|
|
|
|
def __init__(self):
|
|
self.flags = 0
|
|
self.missed_cnt = 0
|
|
self.log_type = 0
|
|
self.size = 0
|
|
self.timestamp = 0
|
|
self.type_specific_data = 0
|
|
self.payload = []
|
|
|
|
def output_open():
|
|
global output_file
|
|
|
|
# apparently no way to close the file as the python plugin doesn't
|
|
# have unregister() callback
|
|
output_file = open('pktlog.dat', 'wb')
|
|
|
|
buf = struct.pack('II', PKTLOG_MAGIC_NUM, CUR_PKTLOG_VER)
|
|
output_write(buf)
|
|
|
|
def output_write(buf):
|
|
global output_file
|
|
|
|
output_file.write(buf)
|
|
|
|
def pktlog_tx_frm_hdr(frame):
|
|
global frm_hdr
|
|
|
|
try:
|
|
# struct ieee80211_hdr
|
|
(frame_control, duration_id, addr1a, addr1b, addr1c, addr2a, addr2b, addr2c, addr3a, addr3b, addr3c, seq_ctrl) = struct.unpack_from('<HHI2BI2BI2BH', frame, 0)
|
|
except struct.error as e:
|
|
dbg('failed to parse struct ieee80211_hdr: %s' % (e))
|
|
return
|
|
|
|
if frame_control & IEEE80211_FCTL_TODS:
|
|
bssid_tail = (addr1b << 8) | addr1c
|
|
sa_tail = (addr2b << 8) | addr2c
|
|
da_tail = (addr3b << 8) | addr3c
|
|
elif frame_control & IEEE80211_FCTL_FROMDS:
|
|
bssid_tail = (addr2b << 8) | addr2c
|
|
sa_tail = (addr3b << 8) | addr3c
|
|
da_tail = (addr1b << 8) | addr1c
|
|
else:
|
|
bssid_tail = (addr3b << 8) | addr3c
|
|
sa_tail = (addr2b << 8) | addr2c
|
|
da_tail = (addr1b << 8) | addr1c
|
|
|
|
resvd = 0
|
|
|
|
frm_hdr = struct.pack('HHHHHH', frame_control, seq_ctrl, bssid_tail,
|
|
sa_tail, da_tail, resvd)
|
|
dbg('frm_hdr %d B' % len(frm_hdr))
|
|
|
|
def pktlog_tx_ctrl(buf, hw_type):
|
|
global frm_hdr
|
|
|
|
if hw_type == ATH10K_PKTLOG_HW_QCA988X:
|
|
hdr = Ath10kPktlogHdr()
|
|
hdr.unpack(buf)
|
|
hdr.size = ATH10K_PKTLOG_TXCTL_LEN
|
|
num_txctls = ATH10K_PKTLOG_MAX_TXCTL_WORDS
|
|
elif hw_type == ATH10K_PKTLOG_HW_QCA99X0 or \
|
|
hw_type == ATH10K_PKTLOG_HW_QCA40XX:
|
|
hdr = Ath10kPktlog_10_4_Hdr()
|
|
hdr.unpack(buf)
|
|
hdr.size = ATH10K_PKTLOG_10_4_TXCTL_LEN
|
|
num_txctls = ATH10K_PKTLOG_10_4_MAX_TXCTL_WORDS
|
|
|
|
output_write(hdr.pack())
|
|
|
|
# write struct ath10k_pktlog_frame
|
|
if frm_hdr:
|
|
output_write(frm_hdr)
|
|
else:
|
|
tmp = struct.pack('HHHHHH', 0, 0, 0, 0, 0, 0)
|
|
output_write(tmp)
|
|
|
|
txdesc_ctl = hdr.payload[0:]
|
|
for i in range(num_txctls):
|
|
if len(txdesc_ctl) >= 4:
|
|
txctl, = struct.unpack_from('<I', txdesc_ctl)
|
|
txdesc_ctl = txdesc_ctl[4:]
|
|
else:
|
|
txctl = 0
|
|
output_write(struct.pack('I', txctl))
|
|
|
|
def pktlog_tx_msdu_id(buf, hw_type):
|
|
global msdu_len_tbl
|
|
|
|
if hw_type == ATH10K_PKTLOG_HW_QCA988X:
|
|
hdr = Ath10kPktlogHdr()
|
|
hdr.unpack(buf)
|
|
hdr.size = 4 + (192 / 8) + 2 * 192
|
|
|
|
# write struct ath10k_pktlog_hdr
|
|
output_write(hdr.pack())
|
|
|
|
# parse struct msdu_id_info
|
|
# hdr (12) + num_msdu (4) + bound_bmap (24) = 40
|
|
msdu_info = hdr.payload[0:28]
|
|
id = hdr.payload[28:]
|
|
num_msdu, = struct.unpack_from('I', msdu_info)
|
|
output_write(msdu_info)
|
|
|
|
max_pkt_info_msdu_id = MAX_PKT_INFO_MSDU_ID
|
|
elif hw_type == ATH10K_PKTLOG_HW_QCA99X0 or \
|
|
hw_type == ATH10K_PKTLOG_HW_QCA40XX:
|
|
hdr = Ath10kPktlog_10_4_Hdr()
|
|
hdr.unpack(buf)
|
|
|
|
# write struct ath10k_pktlog_10_4_hdr
|
|
output_write(hdr.pack())
|
|
|
|
# parse struct msdu_id_info
|
|
# hdr (16) + num_msdu (4) + bound_bmap (1) = 21
|
|
msdu_info = hdr.payload[0:5]
|
|
id = hdr.payload[5:]
|
|
num_msdu, = struct.unpack_from('I', msdu_info)
|
|
output_write(msdu_info)
|
|
|
|
max_pkt_info_msdu_id = MAX_10_4_PKT_INFO_MSDU_ID
|
|
|
|
for i in range(max_pkt_info_msdu_id):
|
|
if num_msdu > 0:
|
|
num_msdu = num_msdu - 1;
|
|
msdu_id, = struct.unpack_from('<H', id);
|
|
id = id[2:]
|
|
if msdu_id not in msdu_len_tbl:
|
|
dbg('msdu_id %d not found from msdu_len_tbl' % (msdu_id))
|
|
msdu_len = 0
|
|
else:
|
|
msdu_len = msdu_len_tbl[msdu_id]
|
|
else:
|
|
msdu_len = 0
|
|
output_write(struct.pack('H', msdu_len))
|
|
|
|
def ath10k_htt_pktlog_handler(pevent, trace_seq, event):
|
|
hw_type = int(event.get('hw_type', ATH10K_PKTLOG_HW_QCA988X))
|
|
|
|
buf = event['pktlog'].data
|
|
offset = 0
|
|
|
|
if hw_type == ATH10K_PKTLOG_HW_QCA988X:
|
|
hdr = Ath10kPktlogHdr()
|
|
elif hw_type == ATH10K_PKTLOG_HW_QCA99X0 or \
|
|
hw_type == ATH10K_PKTLOG_HW_QCA40XX:
|
|
hdr = Ath10kPktlog_10_4_Hdr()
|
|
|
|
hdr.unpack(buf, offset)
|
|
offset = offset + hdr.hdr_len
|
|
|
|
trace_seq.puts('%s\n' % (hdr))
|
|
|
|
if hdr.log_type == ATH10K_PKTLOG_TYPE_TX_FRM_HDR:
|
|
pktlog_tx_frm_hdr(buf[hdr.hdr_len:])
|
|
elif hdr.log_type == ATH10K_PKTLOG_TYPE_TX_CTRL:
|
|
pktlog_tx_ctrl(buf, hw_type)
|
|
elif hdr.log_type == ATH10K_PKTLOG_TYPE_TX_MSDU_ID:
|
|
pktlog_tx_msdu_id(buf, hw_type)
|
|
elif hdr.log_type == ATH10K_PKTLOG_TYPE_TX_STAT or \
|
|
hdr.log_type == ATH10K_PKTLOG_TYPE_RX_STAT or \
|
|
hdr.log_type == ATH10K_PKTLOG_TYPE_RC_FIND or \
|
|
hdr.log_type == ATH10K_PKTLOG_TYPE_RC_UPDATE:
|
|
output_write(buf[0 : offset + hdr.size])
|
|
else:
|
|
pass
|
|
|
|
def ath10k_htt_rx_desc_handler(pevent, trace_seq, event):
|
|
hw_type = int(event.get('hw_type', ATH10K_PKTLOG_HW_QCA988X))
|
|
|
|
rxdesc = event['rxdesc'].data
|
|
|
|
trace_seq.puts('len %d\n' % (len(rxdesc)))
|
|
|
|
if hw_type == ATH10K_PKTLOG_HW_QCA988X:
|
|
hdr = Ath10kPktlogHdr()
|
|
hdr.flags = (1 << ATH10K_PKTLOG_FLG_TYPE_REMOTE_S)
|
|
hdr.missed_cnt = 0
|
|
hdr.log_type = ATH10K_PKTLOG_TYPE_RX_STAT
|
|
# rx_desc size for QCA988x chipsets is 248
|
|
hdr.size = 248
|
|
output_write(hdr.pack())
|
|
output_write(rxdesc[0 : 32])
|
|
output_write(rxdesc[36 : 56])
|
|
output_write(rxdesc[76 : 208])
|
|
output_write(rxdesc[228 : ])
|
|
|
|
elif hw_type == ATH10K_PKTLOG_HW_QCA99X0 or \
|
|
hw_type == ATH10K_PKTLOG_HW_QCA40XX:
|
|
hdr = Ath10kPktlog_10_4_Hdr()
|
|
hdr.flags = (1 << ATH10K_PKTLOG_FLG_TYPE_REMOTE_S)
|
|
hdr.missed_cnt = 0
|
|
hdr.log_type = ATH10K_PKTLOG_TYPE_RX_STAT
|
|
hdr.type_specific_data = 0
|
|
hdr.size = len(rxdesc)
|
|
output_write(hdr.pack())
|
|
output_write(rxdesc)
|
|
|
|
def ath10k_htt_tx_handler(pevent, trace_seq, event):
|
|
global msdu_len_tbl
|
|
msdu_id = long(event['msdu_id'])
|
|
msdu_len = long(event['msdu_len'])
|
|
|
|
trace_seq.puts('msdu_id %d msdu_len %d\n' % (msdu_id, msdu_len))
|
|
|
|
if msdu_id > TARGET_NUM_MSDU_DESC:
|
|
dbg('Invalid msdu_id in tx: %d' % (msdu_id))
|
|
return
|
|
|
|
msdu_len_tbl[msdu_id] = msdu_len
|
|
|
|
def ath10k_txrx_tx_unref_handler(pevent, trace_seq, event):
|
|
global msdu_len_tbl
|
|
msdu_id = long(event['msdu_id'])
|
|
|
|
trace_seq.puts('msdu_id %d\n' % (msdu_id))
|
|
|
|
if msdu_id > TARGET_NUM_MSDU_DESC:
|
|
dbg('Invalid msdu_id from unref: %d' % (msdu_id))
|
|
return
|
|
|
|
msdu_len_tbl[msdu_id] = 0
|
|
|
|
def ath10k_tx_hdr_handler(pevent, trace_seq, event):
|
|
buf = event['data'].data
|
|
|
|
pktlog_tx_frm_hdr(buf[0:])
|
|
|
|
def register(pevent):
|
|
|
|
output_open()
|
|
|
|
pevent.register_event_handler("ath10k", "ath10k_htt_pktlog",
|
|
lambda *args:
|
|
ath10k_htt_pktlog_handler(pevent, *args))
|
|
pevent.register_event_handler("ath10k", "ath10k_htt_rx_desc",
|
|
lambda *args:
|
|
ath10k_htt_rx_desc_handler(pevent, *args))
|
|
pevent.register_event_handler("ath10k", "ath10k_htt_tx",
|
|
lambda *args:
|
|
ath10k_htt_tx_handler(pevent, *args))
|
|
pevent.register_event_handler("ath10k", "ath10k_txrx_tx_unref",
|
|
lambda *args:
|
|
ath10k_txrx_tx_unref_handler(pevent, *args))
|
|
pevent.register_event_handler("ath10k", "ath10k_tx_hdr",
|
|
lambda *args:
|
|
ath10k_tx_hdr_handler(pevent, *args))
|