The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#
# $Id: 8021Q.pm 7 2010-06-03 12:35:18Z gomor $
#
package Net::Frame::Layer::8021Q;
use strict; use warnings;

our $VERSION = '1.02';

use Net::Frame::Layer qw(:consts);
use Exporter;
our @ISA = qw(Net::Frame::Layer Exporter);

our %EXPORT_TAGS = (
   consts => [qw(
      NF_8021Q_HDR_LEN
      NF_8021Q_TYPE_IPv4
      NF_8021Q_TYPE_X25
      NF_8021Q_TYPE_ARP
      NF_8021Q_TYPE_CGMP
      NF_8021Q_TYPE_80211
      NF_8021Q_TYPE_PPPIPCP
      NF_8021Q_TYPE_RARP
      NF_8021Q_TYPE_DDP
      NF_8021Q_TYPE_AARP
      NF_8021Q_TYPE_PPPCCP
      NF_8021Q_TYPE_WCP
      NF_8021Q_TYPE_8021Q
      NF_8021Q_TYPE_IPX
      NF_8021Q_TYPE_STP
      NF_8021Q_TYPE_IPv6
      NF_8021Q_TYPE_WLCCP
      NF_8021Q_TYPE_MPLS
      NF_8021Q_TYPE_PPPoED
      NF_8021Q_TYPE_PPPoES
      NF_8021Q_TYPE_8021X
      NF_8021Q_TYPE_AoE
      NF_8021Q_TYPE_80211I
      NF_8021Q_TYPE_LLDP
      NF_8021Q_TYPE_LLTD
      NF_8021Q_TYPE_LOOP
      NF_8021Q_TYPE_VLAN
      NF_8021Q_TYPE_PPPPAP
      NF_8021Q_TYPE_PPPCHAP
   )],
);
our @EXPORT_OK = (
   @{$EXPORT_TAGS{consts}},
);

use constant NF_8021Q_HDR_LEN        => 4;
use constant NF_8021Q_TYPE_IPv4      => 0x0800;
use constant NF_8021Q_TYPE_X25       => 0x0805;
use constant NF_8021Q_TYPE_ARP       => 0x0806;
use constant NF_8021Q_TYPE_CGMP      => 0x2001;
use constant NF_8021Q_TYPE_80211     => 0x2452;
use constant NF_8021Q_TYPE_PPPIPCP   => 0x8021;
use constant NF_8021Q_TYPE_RARP      => 0x8035;
use constant NF_8021Q_TYPE_DDP       => 0x809b;
use constant NF_8021Q_TYPE_AARP      => 0x80f3;
use constant NF_8021Q_TYPE_PPPCCP    => 0x80fd;
use constant NF_8021Q_TYPE_WCP       => 0x80ff;
use constant NF_8021Q_TYPE_8021Q     => 0x8100;
use constant NF_8021Q_TYPE_IPX       => 0x8137;
use constant NF_8021Q_TYPE_STP       => 0x8181;
use constant NF_8021Q_TYPE_IPv6      => 0x86dd;
use constant NF_8021Q_TYPE_WLCCP     => 0x872d;
use constant NF_8021Q_TYPE_MPLS      => 0x8847;
use constant NF_8021Q_TYPE_PPPoED    => 0x8863;
use constant NF_8021Q_TYPE_PPPoES    => 0x8864;
use constant NF_8021Q_TYPE_8021X     => 0x888e;
use constant NF_8021Q_TYPE_AoE       => 0x88a2;
use constant NF_8021Q_TYPE_80211I    => 0x88c7;
use constant NF_8021Q_TYPE_LLDP      => 0x88cc;
use constant NF_8021Q_TYPE_LLTD      => 0x88d9;
use constant NF_8021Q_TYPE_LOOP      => 0x9000;
use constant NF_8021Q_TYPE_VLAN      => 0x9100;
use constant NF_8021Q_TYPE_PPPPAP    => 0xc023;
use constant NF_8021Q_TYPE_PPPCHAP   => 0xc223;

our @AS = qw(
   priority
   cfi
   id
   type
);
__PACKAGE__->cgBuildIndices;
__PACKAGE__->cgBuildAccessorsScalar(\@AS);

no strict 'vars';

require Bit::Vector;

sub new {
   shift->SUPER::new(
      priority => 0,
      cfi      => 0,
      id       => 0,
      type     => NF_8021Q_TYPE_IPv4,
      @_,
   );
}

sub getLength { NF_8021Q_HDR_LEN }

sub pack {
   my $self = shift;

   my $v3  = Bit::Vector->new_Dec( 3, $self->[$__priority]);
   my $v1  = Bit::Vector->new_Dec( 1, $self->[$__cfi]);
   my $v12 = Bit::Vector->new_Dec(12, $self->[$__id]);
   my $v16 = $v3->Concat_List($v1, $v12);

   $self->[$__raw] = $self->SUPER::pack('nn',
      $v16->to_Dec,
      $self->[$__type],
   ) or return undef;

   $self->[$__raw];
}

sub unpack {
   my $self = shift;

   my ($pCfiId, $type, $payload) =
      $self->SUPER::unpack('nn a*', $self->[$__raw])
         or return undef;

   my $v16 = Bit::Vector->new_Dec(16, $pCfiId);

   $self->[$__priority] = $v16->Chunk_Read( 3, 13);
   $self->[$__cfi]      = $v16->Chunk_Read( 1, 12);
   $self->[$__id]       = $v16->Chunk_Read(12,  0);
   $self->[$__type]     = $type;
   $self->[$__payload]  = $payload;

   $self;
}

sub encapsulate {
   my $self = shift;

   return $self->[$__nextLayer] if $self->[$__nextLayer];

   my $types = {
      NF_8021Q_TYPE_IPv4()    => 'IPv4',
      NF_8021Q_TYPE_X25()     => 'X25',
      NF_8021Q_TYPE_ARP()     => 'ARP',
      NF_8021Q_TYPE_CGMP()    => 'CGMP',
      NF_8021Q_TYPE_80211()   => '80211',
      NF_8021Q_TYPE_PPPIPCP() => 'PPPIPCP',
      NF_8021Q_TYPE_RARP()    => 'RARP',
      NF_8021Q_TYPE_DDP()     => 'DDP',
      NF_8021Q_TYPE_AARP()    => 'AARP',
      NF_8021Q_TYPE_PPPCCP()  => 'PPPCCP',
      NF_8021Q_TYPE_WCP()     => 'WCP',
      NF_8021Q_TYPE_8021Q()   => '8021Q',
      NF_8021Q_TYPE_IPX()     => 'IPX',
      NF_8021Q_TYPE_STP()     => 'STP',
      NF_8021Q_TYPE_IPv6()    => 'IPv6',
      NF_8021Q_TYPE_WLCCP()   => 'WLCCP',
      NF_8021Q_TYPE_MPLS()    => 'MPLS',
      NF_8021Q_TYPE_PPPoED()  => 'PPPoED',
      NF_8021Q_TYPE_PPPoES()  => 'PPPoES',
      NF_8021Q_TYPE_8021X()   => '8021X',
      NF_8021Q_TYPE_AoE()     => 'AoE',
      NF_8021Q_TYPE_80211I()  => '80211I',
      NF_8021Q_TYPE_LLDP()    => 'LLDP',
      NF_8021Q_TYPE_LLTD()    => 'LLTD',
      NF_8021Q_TYPE_LOOP()    => 'LOOP',
      NF_8021Q_TYPE_VLAN()    => 'VLAN',
      NF_8021Q_TYPE_PPPPAP()  => 'PPPPAP',
      NF_8021Q_TYPE_PPPCHAP() => 'PPPCHAP',
   };

   if ($self->[$__type] <= 1500 && $self->[$__payload]) {
      my $payload = CORE::unpack('H*', $self->[$__payload]);
      if ($payload =~ /^aaaa/) {
         return 'LLC';
      }
      return NF_LAYER_UNKNOWN;
   }

   $types->{$self->type} || NF_LAYER_UNKNOWN;
}

sub print {
   my $self = shift;

   my $l = $self->layer;
   sprintf "$l: priority:0x%01x  cfi:0x%01x  id:%d  type:0x%02x",
      $self->[$__priority], $self->[$__cfi], $self->[$__id], $self->[$__type];
}

1;

__END__

=head1 NAME

Net::Frame::Layer::8021Q - 802.1Q layer object

=head1 SYNOPSIS

   use Net::Frame::Layer::8021Q qw(:consts);

   # Build a layer
   my $layer = Net::Frame::Layer::8021Q->new(
      priority => 0,
      cfi      => 0,
      id       => 0,
      type     => NF_8021Q_TYPE_IPv4,
   );
   $layer->pack;

   print 'RAW: '.$layer->dump."\n";

   # Read a raw layer
   my $layer = Net::Frame::Layer::8021Q->new(raw => $raw);

   print $layer->print."\n";
   print 'PAYLOAD: '.unpack('H*', $layer->payload)."\n"
      if $layer->payload;

=head1 DESCRIPTION

This modules implements the encoding and decoding of the 802.1Q layer.

Details: http://standards.ieee.org/getieee802/802.1.html

See also B<Net::Frame::Layer> for other attributes and methods.

=head1 ATTRIBUTES

=over 4

=item B<priority>

The priority field.

=item B<cfi>

The cfi field. It is only one bit long, so set it to 0 or 1.

=item B<id>

8021Q tag id. You'll love it.

=item B<type>

Which type the next encapsulated layer is.

=back

The following are inherited attributes. See B<Net::Frame::Layer> for more information.

=over 4

=item B<raw>

=item B<payload>

=item B<nextLayer>

=back

=head1 METHODS

=over 4

=item B<new>

=item B<new> (hash)

Object constructor. You can pass attributes that will overwrite default ones. See B<SYNOPSIS> for default values.

=back

The following are inherited methods. Some of them may be overriden in this layer, and some others may not be meaningful in this layer. See B<Net::Frame::Layer> for more information.

=over 4

=item B<layer>

=item B<computeLengths>

=item B<computeChecksums>

=item B<pack>

=item B<unpack>

=item B<encapsulate>

=item B<getLength>

=item B<getPayloadLength>

=item B<print>

=item B<dump>

=back

=head1 CONSTANTS

Load them: use Net::Frame::Layer::8021Q qw(:consts);

=over 4

=item B<NF_8021Q_TYPE_IPv4>

=item B<NF_8021Q_TYPE_X25>

=item B<NF_8021Q_TYPE_ARP>

=item B<NF_8021Q_TYPE_CGMP>

=item B<NF_8021Q_TYPE_80211>

=item B<NF_8021Q_TYPE_PPPIPCP>

=item B<NF_8021Q_TYPE_RARP>

=item B<NF_8021Q_TYPE_DDP>

=item B<NF_8021Q_TYPE_AARP>

=item B<NF_8021Q_TYPE_PPPCCP>

=item B<NF_8021Q_TYPE_WCP>

=item B<NF_8021Q_TYPE_8021Q>

=item B<NF_8021Q_TYPE_IPX>

=item B<NF_8021Q_TYPE_STP>

=item B<NF_8021Q_TYPE_IPv6>

=item B<NF_8021Q_TYPE_WLCCP>

=item B<NF_8021Q_TYPE_MPLS>

=item B<NF_8021Q_TYPE_PPPoED>

=item B<NF_8021Q_TYPE_PPPoES>

=item B<NF_8021Q_TYPE_8021X>

=item B<NF_8021Q_TYPE_AoE>

=item B<NF_8021Q_TYPE_80211I>

=item B<NF_8021Q_TYPE_LLDP>

=item B<NF_8021Q_TYPE_LLTD>

=item B<NF_8021Q_TYPE_LOOP>

=item B<NF_8021Q_TYPE_VLAN>

=item B<NF_8021Q_TYPE_PPPPAP>

=item B<NF_8021Q_TYPE_PPPCHAP>

Various supported encapsulated layer types.

=back

=head1 SEE ALSO

L<Net::Frame::Layer>

=head1 AUTHOR

Patrice E<lt>GomoRE<gt> Auffret

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2006-2010, Patrice E<lt>GomoRE<gt> Auffret

You may distribute this module under the terms of the Artistic license.
See LICENSE.Artistic file in the source distribution archive.

=cut