mirror of
https://github.com/Telecominfraproject/wlan-lanforge-scripts.git
synced 2025-11-02 11:48:03 +00:00
wifi-diag: Start on block-ack parsing and sanity checks.
This commit is contained in:
@@ -8,16 +8,19 @@ sub new {
|
|||||||
my %options = @_;
|
my %options = @_;
|
||||||
|
|
||||||
my $self = {
|
my $self = {
|
||||||
|
seqno => -1, # block-ack will not have a seqno
|
||||||
|
acked_by => -1,
|
||||||
|
block_acked_by => -1,
|
||||||
retrans => 0,
|
retrans => 0,
|
||||||
timestamp => 0,
|
timestamp => 0,
|
||||||
datarate => 0,
|
datarate => 0,
|
||||||
type_subtype => "UNKNOWN",
|
type_subtype => "UNKNOWN",
|
||||||
receiver => "UNKNOWN",
|
receiver => "UNKNOWN",
|
||||||
transmitter => "UNKNOWN",
|
transmitter => "UNKNOWN",
|
||||||
|
tid => 17, # anything that does not specify a tid gets this.
|
||||||
%options,
|
%options,
|
||||||
amsdu_frame_count => 0,
|
amsdu_frame_count => 0,
|
||||||
ssi_sig_found => 0,
|
ssi_sig_found => 0,
|
||||||
tid => 17, # anything that does not specify a tid gets this.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bless($self, $class);
|
bless($self, $class);
|
||||||
@@ -60,9 +63,10 @@ sub append {
|
|||||||
$self->{ba_starting_seq} = $1;
|
$self->{ba_starting_seq} = $1;
|
||||||
}
|
}
|
||||||
elsif ($ln =~ /.* = TID for which a Basic BlockAck frame is requested: (\S+)/) {
|
elsif ($ln =~ /.* = TID for which a Basic BlockAck frame is requested: (\S+)/) {
|
||||||
$self->{ba_tid} = $1;
|
$self->{ba_tid} = hex($1);
|
||||||
}
|
}
|
||||||
elsif ($ln =~ /^\s*Block Ack Bitmap: (\S+)/) {
|
elsif ($ln =~ /^\s*Block Ack Bitmap: (\S+)/) {
|
||||||
|
#print "ba-bitmap: $1\n";
|
||||||
$self->{ba_bitmap} = $1;
|
$self->{ba_bitmap} = $1;
|
||||||
}
|
}
|
||||||
elsif ($ln =~ /.* = Retry: Frame is being retransmitted/) {
|
elsif ($ln =~ /.* = Retry: Frame is being retransmitted/) {
|
||||||
@@ -152,6 +156,54 @@ sub retrans {
|
|||||||
return $self->{retrans};
|
return $self->{retrans};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub seqno {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{seqno};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub block_acked_by {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{block_acked_by};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub acked_by {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{acked_by};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_block_acked_by {
|
||||||
|
my $self = shift;
|
||||||
|
$self->{block_acked_by} = shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_acked_by {
|
||||||
|
my $self = shift;
|
||||||
|
$self->{acked_by} = shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub was_acked {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
if ($self->block_acked_by() != -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ($self->acked_by() != -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub wants_ack {
|
||||||
|
my $self = shift;
|
||||||
|
my $rcvr_b0 = substring(self->receiver(), 0, 1);
|
||||||
|
my $rb0 = hex("$rcvr_b0");
|
||||||
|
if ($rb0 & 0x1) {
|
||||||
|
return 0; # Don't ack bcast/bcast frames
|
||||||
|
}
|
||||||
|
# TODO: Need to parse QoS no-ack frames too, this will return false positives currently
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
sub timestamp {
|
sub timestamp {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return $self->{timestamp};
|
return $self->{timestamp};
|
||||||
@@ -164,6 +216,9 @@ sub receiver {
|
|||||||
|
|
||||||
sub tid {
|
sub tid {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
if (exists $self->{ba_tid}) {
|
||||||
|
return $self->{ba_tid};
|
||||||
|
}
|
||||||
return $self->{tid};
|
return $self->{tid};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package Tid;
|
|||||||
|
|
||||||
use warnings;
|
use warnings;
|
||||||
use strict;
|
use strict;
|
||||||
|
use bigint;
|
||||||
|
|
||||||
|
my $warn_dup_ba_once = 1;
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
@@ -47,6 +50,99 @@ sub add_pkt {
|
|||||||
$self->{tx_retrans}++;
|
$self->{tx_retrans}++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $pkt_count = @{$self->{pkts}};
|
||||||
|
|
||||||
|
# If this is a block-ack, then check for previous frames that would match.
|
||||||
|
if ($pkt->type_subtype() eq "802.11 Block Ack (0x0019)") {
|
||||||
|
my $transmitter = $pkt->transmitter();
|
||||||
|
my $starting_seqno = $pkt->{ba_starting_seq};
|
||||||
|
my $i;
|
||||||
|
my $bitmap = $pkt->{ba_bitmap}; # 0100000000000000 for instance
|
||||||
|
my $bi_as_long = 0;
|
||||||
|
my $bi_mask = 0;
|
||||||
|
my $q;
|
||||||
|
for ($q = 0; $q < 8; $q++) {
|
||||||
|
my $bmap_octet = substr($bitmap, $q * 2, 2);
|
||||||
|
my $bmi = hex($bmap_octet);
|
||||||
|
#print "bmap-octet: $bmap_octet bmi: " . hex($bmi) . "\n";
|
||||||
|
$bi_as_long |= ($bmi << ($q * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i<$pkt_count; $i++) {
|
||||||
|
my $tmp = $self->{pkts}[$i];
|
||||||
|
#print "checking tmp-pkt: " . $tmp->seqno();
|
||||||
|
#print " transmitter: " . $tmp->transmitter();
|
||||||
|
#print " pkt-rcvr: " . $pkt->receiver() . "\n";
|
||||||
|
if ($tmp->transmitter() eq $pkt->receiver()) {
|
||||||
|
if ($tmp->seqno() >= $starting_seqno && $tmp->seqno() < ($starting_seqno + 64)) {
|
||||||
|
# tmp pkt might match this BA bitmap..check closer.
|
||||||
|
my $diff = $tmp->seqno() - $starting_seqno;
|
||||||
|
|
||||||
|
if ($bi_as_long & (1 << $diff)) {
|
||||||
|
# Found a matching frame.
|
||||||
|
$bi_mask |= (1 << $diff);
|
||||||
|
|
||||||
|
if ($tmp->block_acked_by() != -1) {
|
||||||
|
# This seems to be a common thing, warn once and not again.
|
||||||
|
if ($warn_dup_ba_once) {
|
||||||
|
print "WARNING: block-ack frame: " . $pkt->frame_num() . " acking frame: " .
|
||||||
|
$tmp->frame_num() . " already block-acked by frame: " . $tmp->block_acked_by() . ". This warning will not be shown again.\n";
|
||||||
|
$warn_dup_ba_once = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ($tmp->acked_by() != -1) {
|
||||||
|
print "WARNING: block-ack frame: " . $pkt->frame_num() . " acking frame: " .
|
||||||
|
$tmp->frame_num() . " already acked by frame: " . $tmp->acked_by() . "\n";
|
||||||
|
}
|
||||||
|
$tmp->set_block_acked_by($pkt->frame_num());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}# for all pkts
|
||||||
|
|
||||||
|
# See if we block-acked anything we could not find?
|
||||||
|
if ($bi_mask != $bi_as_long) {
|
||||||
|
my $missing = $bi_mask ^ $bi_as_long;
|
||||||
|
my $missing_str = "";
|
||||||
|
for ($i = 0; $i<64; $i++) {
|
||||||
|
if ($missing & (1<<$i)) {
|
||||||
|
my $missing_seqno = $starting_seqno + $i;
|
||||||
|
$missing_str .= $missing_seqno . " ";
|
||||||
|
|
||||||
|
# Add a dummy pkt
|
||||||
|
my $dummy = Packet->new(transmitter => $pkt->receiver(),
|
||||||
|
data_subtype => "DUMMY_BA_ACKED",
|
||||||
|
timestamp => $pkt->timestamp(),
|
||||||
|
seqno => $missing_seqno,
|
||||||
|
tid => $self->tidno());
|
||||||
|
$dummy->block_acked_by($pkt->frame_num());
|
||||||
|
push(@{$self->{pkts}}, $dummy);
|
||||||
|
#print "pushing dummy pkt, seqno: $missing_seqno\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "WARNING: block-ack frame: " . $pkt->frame_num() . " acked frames we did not capture, found-these: " . $bi_mask->as_hex .
|
||||||
|
" acked these: " . $bi_as_long->as_hex . " missing: " . $missing->as_hex . "($missing_str), starting-seq-no: $starting_seqno\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Shift off old frames.
|
||||||
|
while ($pkt_count > 0) {
|
||||||
|
my $tmp = shift(@{$self->{pkts}});
|
||||||
|
if (($tmp->timestamp() + 60 < $pkt->timestamp()) ||
|
||||||
|
($pkt_count > 1000)) {
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$pkt_count--;
|
||||||
|
next; # Drop frames when we have more than 1000 or they are older than 1 minute ago
|
||||||
|
}
|
||||||
|
# Put this one back on
|
||||||
|
unshift(@{$self->{pkts}}, $tmp);
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
# Generate reporting data for this pkt
|
# Generate reporting data for this pkt
|
||||||
my $fh = $self->{mcs_fh};
|
my $fh = $self->{mcs_fh};
|
||||||
print $fh "" . $pkt->timestamp() . "\t" . $self->tidno() . "\t" . $pkt->datarate() . "\t" . $pkt->retrans() . "\n";
|
print $fh "" . $pkt->timestamp() . "\t" . $self->tidno() . "\t" . $pkt->datarate() . "\t" . $pkt->retrans() . "\n";
|
||||||
|
|||||||
@@ -56,6 +56,17 @@ sub processPkt {
|
|||||||
if ($pkt->type_subtype() eq "Acknowledgement (0x001d)") {
|
if ($pkt->type_subtype() eq "Acknowledgement (0x001d)") {
|
||||||
if ($last_pkt->transmitter() eq $pkt->receiver()) {
|
if ($last_pkt->transmitter() eq $pkt->receiver()) {
|
||||||
$pkt->set_transmitter($last_pkt->receiver());
|
$pkt->set_transmitter($last_pkt->receiver());
|
||||||
|
if ($last_pkt->acked_by() != -1) {
|
||||||
|
print "WARNING: ack frame: " . $pkt->frame_num() . " acking frame: " .
|
||||||
|
$last_pkt->frame_num() . " already acked by frame: " . $last_pkt->acked_by() . "\n";
|
||||||
|
}
|
||||||
|
elsif ($last_pkt->block_acked_by() != -1) {
|
||||||
|
print "WARNING: ack frame: " . $pkt->frame_num() . " acking frame: " .
|
||||||
|
$last_pkt->frame_num() . " already block-acked by frame: " . $last_pkt->block_acked_by() . "\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$last_pkt->set_acked_by($pkt->frame_num());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
print "ERROR: Frame " . $pkt->frame_num() . " is ACK for unknown packet.\n";
|
print "ERROR: Frame " . $pkt->frame_num() . " is ACK for unknown packet.\n";
|
||||||
|
|||||||
Reference in New Issue
Block a user