class PacketGen::Header::Dot11

IEEE 802.11 header @abstract This is a base class to demultiplex different IEEE 802.11 frames when

parsing.

A IEEE 802.11 header may consist of at least:

Depending on frame type and subtype, it may also contains:

Header accessors

As Dot11 header types are defined under Dot11 namespace, Dot11 header accessors have a specific name. By example, to access to a {Dot11::Beacon} header, accessor is #dot11_beacon.

Create Dot11 packets

As {Dot11} is an abstract class, you have to use one of its subclasses to instanciate a IEEE802.11 header.

IEEE802.11 control frames

Control frames may be created this way:

pkt = PacketGen.gen('Dot11::Control', subtype: 13) # Ack control frame
pkt.dot11_control     # => PacketGen::Header::Dot11::Control
# #dot11 is a shortcut for #dot11_control
pkt.dot11             # => PacketGen::Header::Dot11::Control

IEEE802.11 management frames

Management frames may be created this way:

pkt = PacketGen.gen('Dot11::Management')
pkt.dot11_management     # => PacketGen::Header::Dot11::Management
# #dot11 is a shortcut for #dot11_management
pkt.dot11                # => PacketGen::Header::Dot11::Management

Management frames are usually specialized, AssociationRequest by example:

pkt.add('Dot11::AssoReq')
pkt.dot11_assoreq        # => PacketGen::Header::Dot11::AssoReq

Management frames also may contain some elements (see IEEE 802.11 standard):

pkt.dot11_assoreq.add_elements(type: 'SSID', value: "My SSID")
pkt.dot11_assoreq.add_elements(type: 'Rates', value: supported_rates)

IEEE802.11 data frames

Data frames may be created this way:

pkt = PacketGen.gen('Dot11::Data')
pkt.dot11_data     # => PacketGen::Header::Dot11::Data
# #dot11 is a shortcut for #dot11_data
pkt.dot11          # => PacketGen::Header::Dot11::Data

Parse Dot11 packets

When parsing a Dot11 packet, Dot11 subclass is created from type value. Dot11 header should then be accessed through +Packet#dot11+, whatever the frame type is. But, specialized methods also exist: by example, for a control frame, +Packet#dot11_control+ may also be used.

Send Dot11 packets

To send a Dot11 packet, a RadioTap header is needed:

pkt = PacketGen.gen('RadioTap')
pkt.add('Dot11::Management', mac1: client, mac2: bssid, mac3: bssid)
pkt.add('Dot11::Beacon')
pkt.dot11_beacon.add_element(type: 'SSID', value: 'My SSID')
pkt.dot11_beacon.add_element(type: 'Rates', value: "\x85\x0c")
pkt.calc
pkt.to_w('wlan0')

@author Sylvain Daubert @since 1.4.0

Constants

Element

@!parse

# IEEE 802.11 information element
#
# An {Element} is a piece of data contained in a Dot11 management frame.
# @since 1.4.0
# @since 3.1.0 subclass of {Types::AbstractTLV}
class Element < Types::AbstractTLV; end

@private

TYPES

Frame types

Attributes

fcs[RW]

Set a flag for parsing Dot11 packets. If set to true, parse FCS field, else don't. Default is true. @return [Boolean]

fcs?[RW]

Set a flag for parsing Dot11 packets. If set to true, parse FCS field, else don't. Default is true. @return [Boolean]

Public Class Methods

new(options={}) click to toggle source

@param [Hash] options @see Base#initialize

Calls superclass method PacketGen::Header::Base::new
# File lib/packetgen/header/dot11.rb, line 262
def initialize(options={})
  super
  @applicable_fields = old_fields
end

Public Instance Methods

added_to_packet(packet) click to toggle source

Callback called when a Dot11 header is added to a packet Here, add #dot11 method as a shortcut to existing +#dot11_(control|management|data)+. @param [Packet] packet @return [void]

# File lib/packetgen/header/dot11.rb, line 355
def added_to_packet(packet)
  return if packet.respond_to? :dot11

  packet.instance_eval("def dot11(arg=nil); header(#{self.class}, arg); end")
end
calc_checksum() click to toggle source

Compute checksum and set fcs field @return [Integer]

# File lib/packetgen/header/dot11.rb, line 306
def calc_checksum
  fcs = Zlib.crc32(to_s[0...-4])
  self.fcs = fcs
  fcs
end
fields() click to toggle source

Get all used field names @return [Array<Symbol>]

# File lib/packetgen/header/dot11.rb, line 269
def fields
  @applicable_fields
end
Also aliased as: old_fields
human_type() click to toggle source

Get human readable type @return [String]

# File lib/packetgen/header/dot11.rb, line 320
def human_type
  TYPES[type]
end
inspect() click to toggle source

@return [String]

# File lib/packetgen/header/dot11.rb, line 325
def inspect
  str = if self.instance_of? Dot11
          Inspect.dashed_line("#{self.class} #{human_type}", 1)
        elsif self.respond_to? :human_subtype
          Inspect.dashed_line("#{self.class} #{human_subtype}", 1)
        else
          Inspect.dashed_line(self.class.to_s, 1)
        end

  define_applicable_fields
  @applicable_fields.each do |attr|
    next if attr == :body

    str << Inspect.inspect_attribute(attr, @fields[attr], 1)
  end
  str
end
old_fields()

@private

Alias for: fields
old_read(str)

@private

Alias for: read
read(str) click to toggle source

Populate object from a binary string @param [String] str @return [Dot11] may return a subclass object if a more specific class

may be determined
# File lib/packetgen/header/dot11.rb, line 280
def read(str)
  fcs = Dot11.fcs?

  if self.instance_of? Dot11
    return self if str.nil?

    force_binary str
    self[:frame_ctrl].read str[0, 2]

    case type
    when 0
      Dot11::Management.new.read str
    when 1
      Dot11::Control.new.read str
    when 2
      Dot11::Data.new.read str
    else
      private_read str, fcs
    end
  else
    private_read str, fcs
  end
end
Also aliased as: old_read
to_s() click to toggle source

@return [String]

# File lib/packetgen/header/dot11.rb, line 313
def to_s
  define_applicable_fields
  @applicable_fields.map { |f| force_binary @fields[f].to_s }.join
end
to_w(iface) click to toggle source

send Dot11 packet on wire. @param [String] iface interface name @return [void]

# File lib/packetgen/header/dot11.rb, line 346
def to_w(iface)
  Inject.inject(iface: iface, data: self)
end

Private Instance Methods

define_applicable_fields() click to toggle source
# File lib/packetgen/header/dot11.rb, line 395
def define_applicable_fields
  handle_mac4
  handle_ht_ctrl
  handle_fcs
end
handle_fcs() click to toggle source
# File lib/packetgen/header/dot11.rb, line 387
def handle_fcs
  if Dot11.fcs?
    @applicable_fields << :fcs unless @applicable_fields.include? :fcs
  else
    remove_from_applicable_fields :fcs
  end
end
handle_ht_ctrl() click to toggle source
# File lib/packetgen/header/dot11.rb, line 376
def handle_ht_ctrl
  if order?
    unless @applicable_fields.include? :ht_ctrl
      idx = @applicable_fields.index(:body)
      @applicable_fields[idx, 0] = :ht_ctrl
    end
  else
    remove_from_applicable_fields %i[ht_ctrl]
  end
end
handle_mac4() click to toggle source
# File lib/packetgen/header/dot11.rb, line 368
def handle_mac4
  if to_ds? && from_ds?
    @applicable_fields[6, 0] = :mac4 unless @applicable_fields.include? :mac4
  else
    remove_from_applicable_fields :mac4
  end
end
private_read(str, fcs) click to toggle source
# File lib/packetgen/header/dot11.rb, line 401
def private_read(str, fcs)
  self[:frame_ctrl].read str[0, 2]
  define_applicable_fields
  if fcs
    old_read str[0...-4]
    self[:fcs].read str[-4..-1]
  else
    old_read str
  end
  self
end
remove_from_applicable_fields(fields) click to toggle source
# File lib/packetgen/header/dot11.rb, line 363
def remove_from_applicable_fields(fields)
  fields = [fields] unless fields.is_a? Array
  @applicable_fields -= fields
end