1f7d24e3fSHanoh Haim## This file is (hopefully) part of Scapy
2f7d24e3fSHanoh Haim## See http://www.secdev.org/projects/scapy for more informations
3f7d24e3fSHanoh Haim## <jellch@harris.com>
4f7d24e3fSHanoh Haim## This program is published under a GPLv2 license
5f7d24e3fSHanoh Haim
6f7d24e3fSHanoh Haim# scapy.contrib.description = PPI
7f7d24e3fSHanoh Haim# scapy.contrib.status = loads
8f7d24e3fSHanoh Haim
9f7d24e3fSHanoh Haim
10f7d24e3fSHanoh Haim"""
11f7d24e3fSHanoh HaimPPI (Per-Packet Information).
12f7d24e3fSHanoh Haim"""
13f7d24e3fSHanoh Haimimport logging,struct
14f7d24e3fSHanoh Haimfrom scapy.config import conf
15f7d24e3fSHanoh Haimfrom scapy.packet import *
16f7d24e3fSHanoh Haimfrom scapy.fields import *
17f7d24e3fSHanoh Haimfrom scapy.layers.l2 import Ether
18f7d24e3fSHanoh Haimfrom scapy.layers.dot11 import Dot11
19f7d24e3fSHanoh Haim
20f7d24e3fSHanoh Haim# Dictionary to map the TLV type to the class name of a sub-packet
21f7d24e3fSHanoh Haim_ppi_types = {}
22f7d24e3fSHanoh Haimdef addPPIType(id, value):
23f7d24e3fSHanoh Haim    _ppi_types[id] = value
24f7d24e3fSHanoh Haimdef getPPIType(id, default="default"):
25f7d24e3fSHanoh Haim    return _ppi_types.get(id, _ppi_types.get(default, None))
26f7d24e3fSHanoh Haim
27f7d24e3fSHanoh Haim
28f7d24e3fSHanoh Haim# Default PPI Field Header
29f7d24e3fSHanoh Haimclass PPIGenericFldHdr(Packet):
30f7d24e3fSHanoh Haim    name = "PPI Field Header"
31f7d24e3fSHanoh Haim    fields_desc = [ LEShortField('pfh_type', 0),
32f7d24e3fSHanoh Haim                    FieldLenField('pfh_length', None, length_of="value", fmt='<H', adjust=lambda p,x:x+4),
33f7d24e3fSHanoh Haim                    StrLenField("value", "", length_from=lambda p:p.pfh_length) ]
34f7d24e3fSHanoh Haim
35f7d24e3fSHanoh Haim    def extract_padding(self, p):
36f7d24e3fSHanoh Haim        return "",p
37f7d24e3fSHanoh Haim
38f7d24e3fSHanoh Haimdef _PPIGuessPayloadClass(p, **kargs):
39f7d24e3fSHanoh Haim    """ This function tells the PacketListField how it should extract the
40f7d24e3fSHanoh Haim        TLVs from the payload.  We pass cls only the length string
41f7d24e3fSHanoh Haim        pfh_len says it needs.  If a payload is returned, that means
42f7d24e3fSHanoh Haim        part of the sting was unused.  This converts to a Raw layer, and
43f7d24e3fSHanoh Haim        the remainder of p is added as Raw's payload.  If there is no
44f7d24e3fSHanoh Haim        payload, the remainder of p is added as out's payload.
45f7d24e3fSHanoh Haim    """
46f7d24e3fSHanoh Haim    if len(p) >= 4:
47f7d24e3fSHanoh Haim        t,pfh_len = struct.unpack("<HH", p[:4])
48f7d24e3fSHanoh Haim        # Find out if the value t is in the dict _ppi_types.
49f7d24e3fSHanoh Haim        # If not, return the default TLV class
50f7d24e3fSHanoh Haim        cls = getPPIType(t, "default")
51f7d24e3fSHanoh Haim        pfh_len += 4
52f7d24e3fSHanoh Haim        out = cls(p[:pfh_len], **kargs)
53f7d24e3fSHanoh Haim        if (out.payload):
54f7d24e3fSHanoh Haim            out.payload = conf.raw_layer(out.payload.load)
55f7d24e3fSHanoh Haim            if (len(p) > pfh_len):
56f7d24e3fSHanoh Haim                out.payload.payload = conf.padding_layer(p[pfh_len:])
57f7d24e3fSHanoh Haim        elif (len(p) > pfh_len):
58f7d24e3fSHanoh Haim            out.payload = conf.padding_layer(p[pfh_len:])
59f7d24e3fSHanoh Haim
60f7d24e3fSHanoh Haim    else:
61f7d24e3fSHanoh Haim        out = conf.raw_layer(p, **kargs)
62f7d24e3fSHanoh Haim    return out
63f7d24e3fSHanoh Haim
64f7d24e3fSHanoh Haim
65f7d24e3fSHanoh Haim
66f7d24e3fSHanoh Haim
67f7d24e3fSHanoh Haimclass PPI(Packet):
68f7d24e3fSHanoh Haim    name = "PPI Packet Header"
69f7d24e3fSHanoh Haim    fields_desc = [ ByteField('pph_version', 0),
70f7d24e3fSHanoh Haim                    ByteField('pph_flags', 0),
71f7d24e3fSHanoh Haim                    FieldLenField('pph_len', None, length_of="PPIFieldHeaders", fmt="<H", adjust=lambda p,x:x+8 ),
72f7d24e3fSHanoh Haim                    LEIntField('dlt', None),
73f7d24e3fSHanoh Haim                    PacketListField("PPIFieldHeaders", [],  _PPIGuessPayloadClass, length_from=lambda p:p.pph_len-8,) ]
74f7d24e3fSHanoh Haim    def guess_payload_class(self,payload):
75f7d24e3fSHanoh Haim        return conf.l2types.get(self.dlt, Packet.guess_payload_class(self, payload))
76f7d24e3fSHanoh Haim
77f7d24e3fSHanoh Haim#Register PPI
78f7d24e3fSHanoh HaimaddPPIType("default", PPIGenericFldHdr)
79f7d24e3fSHanoh Haim
80f7d24e3fSHanoh Haimconf.l2types.register(192, PPI)
81f7d24e3fSHanoh Haimconf.l2types.register_num2layer(192, PPI)
82f7d24e3fSHanoh Haim
83f7d24e3fSHanoh Haimbind_layers(PPI, Dot11, dlt=conf.l2types.get(Dot11))
84f7d24e3fSHanoh Haimbind_layers(Dot11, PPI)
85f7d24e3fSHanoh Haimbind_layers(PPI, Ether, dlt=conf.l2types.get(Ether))
86f7d24e3fSHanoh Haimbind_layers(Dot11, Ether)