diff --git a/wifi_diag/Packet.pm b/wifi_diag/Packet.pm index c4442dae..332a95a8 100644 --- a/wifi_diag/Packet.pm +++ b/wifi_diag/Packet.pm @@ -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; } diff --git a/wifi_diag/PeerConn.pm b/wifi_diag/PeerConn.pm index c6cb744f..ed315412 100644 --- a/wifi_diag/PeerConn.pm +++ b/wifi_diag/PeerConn.pm @@ -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 { diff --git a/wifi_diag/Tid.pm b/wifi_diag/Tid.pm index 7db63175..aa2c91b5 100644 --- a/wifi_diag/Tid.pm +++ b/wifi_diag/Tid.pm @@ -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"; } diff --git a/wifi_diag/wifi_pcap_diag.pl b/wifi_diag/wifi_pcap_diag.pl index e6e616d3..77045878 100755 --- a/wifi_diag/wifi_pcap_diag.pl +++ b/wifi_diag/wifi_pcap_diag.pl @@ -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
\n"; - $html .= "RX no-ack-found: $rx_no_ack_found
\n"; - $html .= "TX no-ack-found: $tx_no_ack_found
\n"; + $html .= "RX (All) no-ack-found: $rx_no_ack_found_all
\n"; + $html .= "RX (Big) no-ack-found: $rx_no_ack_found_big
\n"; + $html .= "TX (All) no-ack-found: $tx_no_ack_found_all
\n"; + $html .= "TX (Big) no-ack-found: $tx_no_ack_found_big
\n"; if ($delta_time_tx_count) { $html .= "TX average gap between AMPDU frames (ms): " . (($delta_time_tx * 1000.0) / $delta_time_tx_count) . "
\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++; }