123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- """Radiotap"""
- from pypacker import pypacker, triggerlist
- import struct
- import logging
- logger = logging.getLogger("pypacker")
- RTAP_TYPE_80211 = 0
- # Ref: http://www.radiotap.org
- # Fields Ref: http://www.radiotap.org/defined-fields/all
- # defined flags ordered by appearance (big endian)
- TSFT_MASK = 0x01000000
- FLAGS_MASK = 0x02000000
- RATE_MASK = 0x04000000
- CHANNEL_MASK = 0x08000000
- FHSS_MASK = 0x10000000
- DB_ANT_SIG_MASK = 0x20000000
- DB_ANT_NOISE_MASK = 0x40000000
- LOCK_QUAL_MASK = 0x80000000
- TX_ATTN_MASK = 0x00010000
- DB_TX_ATTN_MASK = 0x00020000
- DBM_TX_POWER_MASK = 0x00040000
- ANTENNA_MASK = 0x00080000
- ANT_SIG_MASK = 0x00100000
- ANT_NOISE_MASK = 0x00200000
- RX_FLAGS_MASK = 0x00400000
- CHANNELPLUS_MASK = 0x00000400
- HT_MASK = 0x00000800
- AMPDU_MASK = 0x00001000
- VHT_MASK = 0x00002000
- # 7 bits reserved
- RT_NS_NEXT_MASK = 0x00000020
- VENDOR_NS_NEXT = 0x00000040
- EXT_MASK = 0x00000080
- # mask -> (length, alignment)
- RADIO_FIELDS = {
- TSFT_MASK : (8, 8),
- FLAGS_MASK : (1, 1),
- RATE_MASK : (1, 1),
- # channel + flags
- CHANNEL_MASK : (4, 2),
- # fhss + pattern
- FHSS_MASK : (2, 1),
- DB_ANT_SIG_MASK : (1, 1),
- DB_ANT_NOISE_MASK : (1, 1),
- LOCK_QUAL_MASK : (2, 2),
- TX_ATTN_MASK : (2, 2),
- DB_TX_ATTN_MASK : (2, 2),
- DBM_TX_POWER_MASK : (1, 1),
- ANTENNA_MASK : (1, 1),
- ANT_SIG_MASK : (1, 1),
- ANT_NOISE_MASK : (1, 1),
- RX_FLAGS_MASK : (2, 2),
- # CHANNELPLUS_MASK :,
- HT_MASK : (3, 1),
- AMPDU_MASK : (8, 4),
- VHT_MASK : (12, 2)
- # RT_NS_NEXT_MASK :,
- # VENDOR_NS_NEXT :,
- # EXT_MASK :
- }
- RADIO_FIELDS_MASKS = [
- TSFT_MASK,
- FLAGS_MASK,
- RATE_MASK,
- # channel + flags
- CHANNEL_MASK,
- # fhss + pattern
- FHSS_MASK,
- DB_ANT_SIG_MASK,
- DB_ANT_NOISE_MASK,
- LOCK_QUAL_MASK,
- TX_ATTN_MASK,
- DB_TX_ATTN_MASK,
- DBM_TX_POWER_MASK,
- ANTENNA_MASK,
- ANT_SIG_MASK,
- ANT_NOISE_MASK,
- RX_FLAGS_MASK,
- HT_MASK,
- AMPDU_MASK,
- VHT_MASK
- ]
- class FlagTriggerList(triggerlist.TriggerList):
- # no __init__ needed: we just add tuples
- def _pack(self):
- return b"".join([flag[1] for flag in self])
- def get_channelinfo(channel_bytes):
- """
- return -- [channel_mhz, channel_flags]
- """
- return [struct.unpack("<H", channel_bytes[0:2])[0], struct.unpack("<H", channel_bytes[2:4])[0]]
- class Radiotap(pypacker.Packet):
- __hdr__ = (
- ("version", "B", 0),
- ("pad", "B", 0),
- ("len", "H", 0x0800),
- ("present_flags", "I", 0),
- ("flags", None, FlagTriggerList) # stores: (XXX_MASK, value)
- )
- # handle frame check sequence
- def __get_fcs(self):
- try:
- return self._fcs
- except AttributeError:
- return b""
- def __set_fcs(self, fcs):
- self._fcs = fcs
- fcs = property(__get_fcs, __set_fcs)
- def _dissect(self, buf):
- flags = struct.unpack(">I", buf[4:8])[0]
- fcs_present = False
- off = 0
- if flags & TSFT_MASK == TSFT_MASK:
- off = 8
- if flags & FLAGS_MASK == FLAGS_MASK and struct.unpack(">B", buf[off: off])[0] & 0x10 != 0:
- logger.debug("fcs found")
- fcs_present = True
- pos_end = len(buf)
- if fcs_present:
- self._fcs = buf[-4:]
- pos_end = -4
- size_align = RADIO_FIELDS[mask]
- size = size_align[0]
- # check alignment
- mod = off % size_align[1]
- if mod != 0:
- # enlarge size by alignment
- size += (size_align[1] - mod)
- # logger.debug("got flag %02X, length/align: %r" % (mask, size_align))
- # add all fields for the stated flag
- value = buf[off: off + size]
- # FCS present?
- if mask == FLAGS_MASK and struct.unpack(">B", value)[0] & 0x10 != 0:
- # logger.debug("fcs found")
- fcs_present = True
- # logger.debug("adding flag: %s" % str(mask))
- flags.append((mask, value))
- off += size
- def bin(self, update_auto_fields=True):
- """Custom bin(): handle FCS."""
- return pypacker.Packet.bin(self, update_auto_fields=update_auto_fields) + self.fcs
- # load handler
- from pypacker.layer12 import ieee80211
- pypacker.Packet.load_handler(Radiotap,
- {
- RTAP_TYPE_80211: ieee80211.IEEE80211
- }
- )
|