Home | History | Annotate | Download | only in contrib
      1 # This file is part of Scapy
      2 # Scapy is free software: you can redistribute it and/or modify
      3 # it under the terms of the GNU General Public License as published by
      4 # the Free Software Foundation, either version 2 of the License, or
      5 # any later version.
      6 #
      7 # Scapy is distributed in the hope that it will be useful,
      8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     10 # GNU General Public License for more details.
     11 #
     12 # You should have received a copy of the GNU General Public License
     13 # along with Scapy. If not, see <http://www.gnu.org/licenses/>.
     14 
     15 # author: <jellch (at] harris.com>
     16 
     17 # scapy.contrib.description = PPI
     18 # scapy.contrib.status = loads
     19 
     20 
     21 """
     22 PPI (Per-Packet Information).
     23 """
     24 import logging
     25 import struct
     26 
     27 
     28 from scapy.config import conf
     29 from scapy.data import DLT_EN10MB, DLT_IEEE802_11, DLT_PPI
     30 from scapy.packet import *
     31 from scapy.fields import *
     32 from scapy.layers.l2 import Ether
     33 from scapy.layers.dot11 import Dot11
     34 
     35 # Dictionary to map the TLV type to the class name of a sub-packet
     36 _ppi_types = {}
     37 def addPPIType(id, value):
     38     _ppi_types[id] = value
     39 def getPPIType(id, default="default"):
     40     return _ppi_types.get(id, _ppi_types.get(default, None))
     41 
     42 
     43 # Default PPI Field Header
     44 class PPIGenericFldHdr(Packet):
     45     name = "PPI Field Header"
     46     fields_desc = [ LEShortField('pfh_type', 0),
     47                     FieldLenField('pfh_length', None, length_of="value", fmt='<H', adjust=lambda p,x:x+4),
     48                     StrLenField("value", "", length_from=lambda p:p.pfh_length) ]
     49 
     50     def extract_padding(self, p):
     51         return b"",p
     52 
     53 def _PPIGuessPayloadClass(p, **kargs):
     54     """ This function tells the PacketListField how it should extract the
     55         TLVs from the payload.  We pass cls only the length string
     56         pfh_len says it needs.  If a payload is returned, that means
     57         part of the sting was unused.  This converts to a Raw layer, and
     58         the remainder of p is added as Raw's payload.  If there is no
     59         payload, the remainder of p is added as out's payload.
     60     """
     61     if len(p) >= 4:
     62         t,pfh_len = struct.unpack("<HH", p[:4])
     63         # Find out if the value t is in the dict _ppi_types.
     64         # If not, return the default TLV class
     65         cls = getPPIType(t, "default")
     66         pfh_len += 4
     67         out = cls(p[:pfh_len], **kargs)
     68         if (out.payload):
     69             out.payload = conf.raw_layer(out.payload.load)
     70             out.payload.underlayer = out
     71             if (len(p) > pfh_len):
     72                 out.payload.payload = conf.padding_layer(p[pfh_len:])
     73                 out.payload.payload.underlayer = out.payload
     74         elif (len(p) > pfh_len):
     75             out.payload = conf.padding_layer(p[pfh_len:])
     76             out.payload.underlayer = out
     77     else:
     78         out = conf.raw_layer(p, **kargs)
     79     return out
     80 
     81 
     82 
     83 
     84 class PPI(Packet):
     85     name = "PPI Packet Header"
     86     fields_desc = [ ByteField('pph_version', 0),
     87                     ByteField('pph_flags', 0),
     88                     FieldLenField('pph_len', None, length_of="PPIFieldHeaders", fmt="<H", adjust=lambda p,x:x+8 ),
     89                     LEIntField('dlt', None),
     90                     PacketListField("PPIFieldHeaders", [],  _PPIGuessPayloadClass, length_from=lambda p:p.pph_len-8,) ]
     91     def guess_payload_class(self,payload):
     92         return conf.l2types.get(self.dlt, Packet.guess_payload_class(self, payload))
     93 
     94 #Register PPI
     95 addPPIType("default", PPIGenericFldHdr)
     96 
     97 conf.l2types.register(DLT_PPI, PPI)
     98 
     99 bind_layers(PPI, Dot11, dlt=DLT_IEEE802_11)
    100 bind_layers(PPI, Ether, dlt=DLT_EN10MB)
    101