wifi-diag: Better no-ack detection and some cleanup.

It now reports expected 'no-ack' frames at least in a fairly
simplistic test case.
This commit is contained in:
Ben Greear
2019-01-04 17:07:14 -08:00
parent fab5fc8987
commit 95612cbac7
4 changed files with 193 additions and 43 deletions

View File

@@ -6,11 +6,15 @@ use strict;
use bignum;
use bigint;
our $d_counter = 0;
sub new {
my $class = shift;
my %options = @_;
my $self = {
ba_valid => 0,
dbg => "NA",
priority => "",
wmm_info => "",
raw_pkt => "",
@@ -37,9 +41,28 @@ sub new {
};
bless($self, $class);
if ($self->frame_num() == -1) {
$self->{dummy_counter} = $d_counter;
$d_counter++;
print "Creating dummy pkt: " . $self->{dummy_counter} . "\n";
}
else {
$self->{dummy_counter} = -1;
}
return($self);
}
sub desc {
my $self = shift;
my $rv = $self->frame_num() . " len: " . $self->{bytes_on_wire};
if ($self->frame_num() == -1) {
$rv = $rv . " dummy-counter: " . $self->{dummy_counter} . " dbg: " . $self->{dbg}
}
return $rv;
}
sub raw_pkt {
my $self = shift;
return $self->{raw_pkt};
@@ -248,6 +271,35 @@ sub wants_ack {
if ($rb0 & 0x1) {
return 0; # Don't ack bcast/bcast frames
}
if ($self->type_subtype() eq "802.11 Block Ack (0x0019)") {
return 0;
}
if ($self->type_subtype() eq "802.11 Block Ack Req (0x0018)") {
return 0;
}
if ($self->type_subtype() eq "VHT NDP Announcement (0x0015)") {
return 0;
}
if ($self->type_subtype() eq "Clear-to-send (0x001c)") {
return 0;
}
if ($self->type_subtype() eq "Request-to-send (0x001b)") {
return 0;
}
if ($self->type_subtype() eq "Acknowledgement (0x001d)") {
return 0;
}
if ($self->type_subtype() eq "Action No Ack (0x000e)") {
return 0;
}
# TODO: Need to parse QoS no-ack frames too, this will return false positives currently
return 1;
}

View File

@@ -81,40 +81,65 @@ sub find_or_create_tid {
return $tid;
}
sub tx_no_ack_found {
sub sum_tids {
my $self = shift;
my $var = shift;
my $tid_count = @{$self->{tids}};
my $rv = 0;
my $i;
for ($i = 0; $i < $tid_count; $i++) {
#print "Checking tid: $i\n";
if (exists $self->{tids}[$i]) {
#print "Printing tid: $i\n";
$rv += $self->{tids}[$i]->tx_no_ack_found();
#print "Done printing tid: $i\n";
if ($var == 0) {
$rv += $self->{tids}[$i]->tx_no_ack_found_all();
}
elsif ($var == 1) {
$rv += $self->{tids}[$i]->tx_no_ack_found_big();
}
elsif ($var == 2) {
$rv += $self->{tids}[$i]->rx_no_ack_found_all();
}
elsif ($var == 3) {
$rv += $self->{tids}[$i]->rx_no_ack_found_big();
}
}
}
return $rv;
}
sub rx_no_ack_found {
sub tx_no_ack_found_all {
my $self = shift;
return $self->sum_tids(0);
}
sub tx_no_ack_found_big {
my $self = shift;
return $self->sum_tids(1);
}
sub rx_no_ack_found_all {
my $self = shift;
return $self->sum_tids(2);
}
sub rx_no_ack_found_big {
my $self = shift;
return $self->sum_tids(3);
}
sub notify_done {
my $self = shift;
my $tid_count = @{$self->{tids}};
my $rv = 0;
my $i;
for ($i = 0; $i < $tid_count; $i++) {
#print "Checking tid: $i\n";
if (exists $self->{tids}[$i]) {
#print "Printing tid: $i\n";
$rv += $self->{tids}[$i]->rx_no_ack_found();
#print "Done printing tid: $i\n";
$self->{tids}[$i]->check_remaining_pkts();
}
}
return $rv;
}
sub printme {

View File

@@ -15,8 +15,10 @@ sub new {
my $self = {
pkts => [],
rx_no_ack_found => 0,
tx_no_ack_found => 0,
rx_no_ack_found_all => 0,
rx_no_ack_found_big => 0,
tx_no_ack_found_all => 0,
tx_no_ack_found_big => 0,
tx_retrans_pkts => 0,
rx_retrans_pkts => 0,
tx_amsdu_retrans_pkts => 0,
@@ -181,7 +183,8 @@ sub add_pkt {
$missing_str .= $missing_seqno . " ";
# Add a dummy pkt
my $dummy = Packet->new(frame_num => -1,
my $dummy = Packet->new(dbg => "tid-add-pkt",
frame_num => -1,
receiver => $pkt->transmitter(),
transmitter => $pkt->receiver(),
data_subtype => "DUMMY_BA_ACKED",
@@ -229,12 +232,25 @@ sub add_pkt {
($pkt_count > $max_pkt_store)) {
if (! $tmp->was_acked()) {
if ($tmp->wants_ack()) {
print "WARNING: did not find ack for frame: " . $tmp->frame_num() . ", removing after processing frame: " . $pkt->frame_num() . "\n";
if ($tmp->transmitter() eq $self->{addr_a}) {
$self->{tx_no_ack_found}++;
$self->{tx_no_ack_found_all}++;
if ($tmp->{bytes_on_wire} > 1000) {
print "WARNING: did not find ack for BIG TX frame: " . $tmp->desc() . ", removing after processing frame: " . $pkt->frame_num() . "\n";
$self->{tx_no_ack_found_big}++;
}
else {
print "WARNING: did not find ack for small TX frame: " . $tmp->desc() . ", removing after processing frame: " . $pkt->frame_num() . "\n";
}
}
else {
$self->{rx_no_ack_found}++;
$self->{rx_no_ack_found_all}++;
if ($tmp->{bytes_on_wire} > 1000) {
print "WARNING: did not find ack for BIG RX frame: " . $tmp->desc() . ", removing after processing frame: " . $pkt->frame_num() . "\n";
$self->{rx_no_ack_found_big}++;
}
else {
print "WARNING: did not find ack for small RX frame: " . $tmp->desc() . ", removing after processing frame: " . $pkt->frame_num() . "\n";
}
}
}
}
@@ -308,19 +324,65 @@ sub add_pkt {
push(@{$self->{pkts}}, $pkt);
}
sub check_remaining_pkts {
my $self = shift;
my $pkt_count = @{$self->{pkts}};
# Shift off old frames.
while ($pkt_count > 0) {
my $tmp = shift(@{$self->{pkts}});
if (! $tmp->was_acked()) {
if ($tmp->wants_ack()) {
if ($tmp->transmitter() eq $self->{addr_a}) {
$self->{tx_no_ack_found_all}++;
if ($tmp->{bytes_on_wire} > 1000) {
print "WARNING: did not find ack for BIG TX frame: " . $tmp->desc() . ", removing at end of file.\n";
$self->{tx_no_ack_found_big}++;
}
else {
print "WARNING: did not find ack for small TX frame: " . $tmp->desc() . ", removing at end of file.\n";
}
}
else {
$self->{rx_no_ack_found_all}++;
if ($tmp->{bytes_on_wire} > 1000) {
print "WARNING: did not find ack for BIG RX frame: " . $tmp->desc() . ", removing at end of file.\n";
$self->{rx_no_ack_found_big}++;
}
else {
print "WARNING: did not find ack for small RX frame: " . $tmp->desc() . ", removing at end of file.\n";
}
}
}
}
$pkt_count--;
}
}
sub get_pkts {
my $self = shift;
return @{$self->{pkts}};
}
sub tx_no_ack_found {
sub tx_no_ack_found_all {
my $self = shift;
return $self->{tx_no_ack_found};
return $self->{tx_no_ack_found_all};
}
sub rx_no_ack_found {
sub tx_no_ack_found_big {
my $self = shift;
return $self->{rx_no_ack_found};
return $self->{tx_no_ack_found_big};
}
sub rx_no_ack_found_all {
my $self = shift;
return $self->{rx_no_ack_found_all};
}
sub rx_no_ack_found_big {
my $self = shift;
return $self->{rx_no_ack_found_big};
}
sub printme {
@@ -328,7 +390,8 @@ sub printme {
print " tidno: " . $self->tidno() . " pkt-count: " . $self->get_pkts()
. " tx-pkts: " . $self->{tx_pkts} . " tx-retrans: " . $self->{tx_retrans_pkts}
. " rx-pkts: " . $self->{rx_pkts} . " rx-retrans: " . $self->{rx_retrans_pkts}
. " tx-no-acks: " . $self->{tx_no_ack_found} . " rx-no-acks: " . $self->{rx_no_ack_found}
. " tx-no-acks-all: " . $self->{tx_no_ack_found_all} . " tx-no-acks-big: " . $self->{tx_no_ack_found_big}
. " rx-no-acks-all: " . $self->{rx_no_ack_found_all} . " rx-no-acks-big: " . $self->{rx_no_ack_found_big}
. "\n";
}

View File

@@ -37,11 +37,11 @@ my $input_line_count = 0;
my $pkts_sofar = 0;
my $start_time = time();
my $cur_pkt = Packet->new(raw_pkt => "", frame_num => -1);
my $last_pkt = Packet->new(raw_pkt => "", frame_num => -1, is_rx => 0);
my $first_ampdu_pkt = Packet->new(raw_pkt => "", frame_num => -1);
my $last_ba_rx_pkt = Packet->new(raw_pkt => "", frame_num => -1);
my $last_ba_tx_pkt = Packet->new(raw_pkt => "", frame_num => -1);
my $cur_pkt = Packet->new(raw_pkt => "", frame_num => -1, dbg => "cur_pkt");
my $last_pkt = Packet->new(raw_pkt => "", frame_num => -1, is_rx => 0, dbg => "last_pkt");
my $first_ampdu_pkt = Packet->new(raw_pkt => "", frame_num => -1, dbg => "first_ampdu_pkt");
my $last_ba_rx_pkt = Packet->new(raw_pkt => "", frame_num => -1, dbg => "last_ba_rx_pkt");
my $last_ba_tx_pkt = Packet->new(raw_pkt => "", frame_num => -1, dbg => "last_ba_tx_pkt");
my $glb_fh_ba_tx;
@@ -52,8 +52,10 @@ my $glb_fh_mcs_rx;
my $glb_fh_rtx_tx;
my $glb_fh_rtx_rx;
my $tx_no_ack_found = 0;
my $rx_no_ack_found = 0;
my $tx_no_ack_found_big = 0;
my $rx_no_ack_found_big = 0;
my $tx_no_ack_found_all = 0;
my $rx_no_ack_found_all = 0;
my %glb_mcs_tx_hash = ();
my %glb_mcs_rx_hash = ();
@@ -187,8 +189,9 @@ while (<>) {
processPkt($cur_pkt);
}
$cur_pkt = Packet->new(frame_num => $1,
bytes_on_write => $2,
raw_pkt => $ln);
bytes_on_wire => $2,
raw_pkt => $ln,
dbg => "main-$1");
} else {
$cur_pkt->append($ln);
}
@@ -202,8 +205,11 @@ printProgress();
# Sum up some stats
for my $conn (values %peer_conns) {
$tx_no_ack_found += $conn->tx_no_ack_found();
$rx_no_ack_found += $conn->rx_no_ack_found();
$conn->notify_done();
$tx_no_ack_found_big += $conn->tx_no_ack_found_big();
$rx_no_ack_found_big += $conn->rx_no_ack_found_big();
$tx_no_ack_found_all += $conn->tx_no_ack_found_all();
$rx_no_ack_found_all += $conn->rx_no_ack_found_all();
}
$report_html .= genGlobalReports();
@@ -341,8 +347,10 @@ sub htmlMcsHistogram {
}
$html .= "TX (Big) Retransmit count: $tx_retrans_pkts_big<br>\n";
$html .= "RX no-ack-found: $rx_no_ack_found<br>\n";
$html .= "TX no-ack-found: $tx_no_ack_found<br>\n";
$html .= "RX (All) no-ack-found: $rx_no_ack_found_all<br>\n";
$html .= "RX (Big) no-ack-found: $rx_no_ack_found_big<br>\n";
$html .= "TX (All) no-ack-found: $tx_no_ack_found_all<br>\n";
$html .= "TX (Big) no-ack-found: $tx_no_ack_found_big<br>\n";
if ($delta_time_tx_count) {
$html .= "TX average gap between AMPDU frames (ms): " . (($delta_time_tx * 1000.0) / $delta_time_tx_count) . "<br>\n";
@@ -584,22 +592,22 @@ sub processPkt {
if ($pkt->{is_ampdu} || $pkt->{is_msdu}) {
if ($last_pkt->frame_num() != -1 && (!($last_pkt->{is_ampdu} || $last_pkt->{is_msdu}))) {
# This is first ampdu since a non-ampdu frame. Calculate diff between that and last BA
if ($pkt->{is_rx} && ($last_ba_tx_pkt->frame_num() != -1)) {
if ($pkt->{is_rx} && ($last_ba_tx_pkt->{ba_valid})) {
my $diff = $pkt->timestamp() - $last_ba_tx_pkt->timestamp();
$ba_ampdu_gap_rx += $diff;
$ba_ampdu_gap_rx_count++;
if ($diff > 0.001) {
print "INFO: TX BA to RX AMPDU gap: $diff between frames: " . $last_ba_tx_pkt->frame_num() . " and: " . $pkt->frame_num() . "\n";
}
$last_ba_tx_pkt->{frame_num} = -1;
} elsif ((!$pkt->{is_rx}) && ($last_ba_rx_pkt->frame_num() != -1)) {
$last_ba_tx_pkt->{ba_valid} = 0;
} elsif ((!$pkt->{is_rx}) && ($last_ba_rx_pkt->{ba_valid})) {
my $diff = $pkt->timestamp() - $last_ba_rx_pkt->timestamp();
$ba_ampdu_gap_tx += $diff;
$ba_ampdu_gap_tx_count++;
if ($diff > 0.001) {
print "INFO: RX BA to TX AMPDU gap: $diff between frames: " . $last_ba_rx_pkt->frame_num() . " and: " . $pkt->frame_num() . "\n";
}
$last_ba_rx_pkt->{frame_num} = -1;
$last_ba_rx_pkt->{ba_valid} = 0;
}
}
@@ -642,18 +650,20 @@ sub processPkt {
if ($pkt->type_subtype() eq "802.11 Block Ack (0x0019)") {
# Only grab the initial BA in case we have one side ignoring BA
if ($pkt->{is_rx}) {
if ($last_ba_rx_pkt->{frame_num} == -1) {
if (!$last_ba_rx_pkt->{ba_valid}) {
$last_ba_rx_pkt = $pkt;
$last_ba_rx_pkt->{ba_valid} = 1;
} else {
print "NOTE: Multiple RX block-acks seen without ampdu between them, first BA frame: " . $last_ba_rx_pkt->frame_num()
. " this BA frame num: " . $pkt->frame_num() . "\n";
$dup_ba_rx++;
}
} else {
if ($last_ba_tx_pkt->{frame_num} == -1) {
if (!$last_ba_tx_pkt->{ba_valid}) {
$last_ba_tx_pkt = $pkt;
$last_ba_tx_pkt->{ba_valid} = 1;
} else {
print "NOTE: Multiple TX block-acks seen without ampdu between them, first BA frame: " . $last_ba_rx_pkt->frame_num()
print "NOTE: Multiple TX block-acks seen without ampdu between them, first BA frame: " . $last_ba_tx_pkt->frame_num()
. " this BA frame num: " . $pkt->frame_num() . "\n";
$dup_ba_tx++;
}