Files
wlan-lanforge-scripts/wifi_diag/Packet.pm

354 lines
7.3 KiB
Perl

package Packet;
use warnings;
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 => "",
seqno => -1, # block-ack will not have a seqno
bytes_on_wire => 0,
acked_by => -1,
block_acked_by => -1,
retrans => 0,
seen_ip => 0,
timestamp => 0,
datarate => 0,
dummy_tx_pkts => 0,
dummy_rx_pkts => 0,
is_last_ampdu => 0,
is_ampdu => 0,
is_msdu => 0,
is_malformed => 0,
type_subtype => "UNKNOWN",
receiver => "UNKNOWN",
transmitter => "UNKNOWN",
tid => 17, # anything that does not specify a tid gets this.
%options,
amsdu_frame_count => 0,
ssi_sig_found => 0,
};
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};
}
sub append {
my $self = shift;
my $ln = shift;
$self->{raw_pkt} .= $ln;
#print "ln: $ln\n";
if ($ln =~ /^\s*Internet Protocol Version/) {
$self->{seen_ip} = 1;
return;
}
if ($self->{seen_ip}) {
if ($ln =~ /^\s*A-MSDU Subframe/) {
$self->{seen_ip} = 0;
}
else {
# Ignore
return;
}
}
if ($ln =~ /^\s*Transmitter address: .*\((\S+)\)/) {
$self->{transmitter} = $1;
}
elsif ($ln =~ /^\s*Epoch Time:\s+(\S+)/) {
#print "timestamp: $1\n";
$self->{timestamp} = $1;
}
elsif ($ln =~ /^.* = This is the last subframe of this A-MPDU: True/) {
$self->{is_last_ampdu} = 1;
}
elsif ($ln =~ /^.* = Priority: (.*) \(.*/) {
$self->{priority} = " $1";
}
elsif ($ln =~ /^.* = Payload Type: A-MSDU/) {
$self->{is_ampdu} = 1;
}
elsif ($ln =~ /^.* = Payload Type: MSDU/) {
$self->{is_msdu} = 1;
}
elsif ($ln =~ /^\s*\[Time delta from previous captured frame:\s+(\S+)/) {
$self->{timedelta} = $1;
}
elsif ($ln =~ /^\s*Receiver address: .*\((\S+)\)/) {
$self->{receiver} = $1;
}
elsif (($ln =~ /^\s*Fragment number: (\d+)/) ||
($ln =~ /^.*\s+=\s+Fragment number: (\d+)/)) {
$self->{fragno} = $1;
}
elsif (($ln =~ /^\s*Sequence number: (\d+)/) ||
($ln =~ /^.*\s+=\s+Sequence number: (\d+)/)) {
$self->{seqno} = $1;
}
elsif ($ln =~ /^\s*Type\/Subtype: (.*)/) {
$self->{type_subtype} = $1;
}
elsif ($ln =~ /.* = Starting Sequence Number: (\d+)/) {
$self->{ba_starting_seq} = $1;
}
elsif ($ln =~ /.*Malformed Packet.*/) {
$self->{is_malformed} = 1;
}
elsif ($ln =~ /.* = TID for which a Basic BlockAck frame is requested: (\S+)/) {
#print STDERR "tid: $1\n";
$self->{ba_tid} = hex($1);
}
elsif ($ln =~ /^\s*Block Ack Bitmap: (\S+)/) {
#print "ba-bitmap: $1\n";
$self->{ba_bitmap} = $1;
}
elsif ($ln =~ /.* = Retry: Frame is being retransmitted/) {
$self->{retrans} = 1;
}
elsif ($ln =~ /^\s*VHT information/) {
$self->{is_vht} = 1;
}
elsif ($ln =~ /^\s*Bandwidth: (.*)/) {
$self->{bandwidth} = $1;
}
elsif ($ln =~ /^\s*User 0: MCS (.*)/) {
$self->{mcs} = $1;
}
elsif ($ln =~ /.* = Spatial streams 0: (.*)/) {
$self->{nss} = $1;
}
elsif ($ln =~ /.* = TID: (.*)/) {
$self->{tid} = $1;
}
elsif ($ln =~ /.* = Payload Type: (.*)/) {
$self->{payload_type} = $1;
}
elsif (($ln =~ /^\s+\[Data Rate: (.*)\]/) ||
($ln =~ /^\s*Data Rate: (.*)/)) {
my $dr = $1;
if ($dr =~ /(\S+) Mb/) {
$self->{datarate} = $1;
}
else {
print "ERROR: Unknown datarate: $dr for frame: " . $self->frame_num() . "\n";
$self->{datarate} = 0;
}
}
elsif (($ln =~ /^\s*SSI Signal: (.*)/) ||
($ln =~ /^\s*Antenna signal: (.*)/)) {
if ($self->{ssi_sig_found} == 0) {
$self->{ssi_combined} = $1;
$self->{ssi_sig_found}++;
}
elsif ($self->{ssi_sig_found} == 1) {
$self->{ssi_ant_0} = $1;
$self->{ssi_sig_found}++;
}
elsif ($self->{ssi_sig_found} == 2) {
$self->{ssi_ant_1} = $1;
$self->{ssi_sig_found}++;
}
elsif ($self->{ssi_sig_found} == 3) {
$self->{ssi_ant_2} = $1;
$self->{ssi_sig_found}++;
}
elsif ($self->{ssi_sig_found} == 4) {
$self->{ssi_ant_3} = $1;
$self->{ssi_sig_found}++;
}
}
# AMPDU and such...
elsif ($ln =~ /^\s*A-MSDU Subframe #(\d+)/) {
if ($1 > $self->{amsdu_frame_count}) {
$self->{amsdu_frame_count} = $1;
}
}
else {
if ($self->type_subtype() eq "Beacon frame (0x0008)") {
if ($ln =~ /^\s+(Ac Parameters ACI.*)/) {
$self->{wmm_info} .= $ln;
}
}
}
}
sub frame_num {
my $self = shift;
return $self->{frame_num};
}
sub type_subtype {
my $self = shift;
return $self->{type_subtype};
}
sub transmitter {
my $self = shift;
return $self->{transmitter};
}
sub datarate {
my $self = shift;
return $self->{datarate};
}
sub retrans {
my $self = shift;
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 = substr($self->receiver(), 0, 1);
if ($rcvr_b0 eq "U") {
#print STDERR "wants-ack, receiver: " . $self->receiver() . "\n";
#print STDERR $self->raw_pkt() . "\n";
#exit(1);
return 0;
}
my $rb0 = hex("$rcvr_b0");
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;
}
sub timestamp {
my $self = shift;
return $self->{timestamp};
}
sub receiver {
my $self = shift;
return $self->{receiver};
}
sub tid {
my $self = shift;
if (exists $self->{ba_tid}) {
return $self->{ba_tid};
}
return $self->{tid};
}
sub set_transmitter {
my $self = shift;
my $tx = shift;
$self->{transmitter} = $tx;
}
sub set_receiver {
my $self = shift;
my $rx = shift;
$self->{receiver} = $rx;
}
1;