summaryrefslogtreecommitdiff
path: root/common/lib
diff options
context:
space:
mode:
Diffstat (limited to 'common/lib')
-rw-r--r--common/lib/scammer/__init__.py10
-rw-r--r--common/lib/scammer/beacon.py379
-rw-r--r--common/lib/scammer/cc.py189
-rw-r--r--common/lib/scammer/cm.py187
-rw-r--r--common/lib/scammer/common.py72
-rw-r--r--common/lib/scammer/commonfields.py107
-rw-r--r--common/lib/scammer/cp.py10
-rw-r--r--common/lib/scammer/drv.py140
-rw-r--r--common/lib/scammer/nn.py9
-rw-r--r--common/lib/scammer/scammer.py53
-rw-r--r--common/lib/scammer/vs.py109
11 files changed, 1265 insertions, 0 deletions
diff --git a/common/lib/scammer/__init__.py b/common/lib/scammer/__init__.py
new file mode 100644
index 0000000000..0c9901a33a
--- /dev/null
+++ b/common/lib/scammer/__init__.py
@@ -0,0 +1,10 @@
+from cc import *
+from cp import *
+from nn import *
+from cm import *
+from vs import *
+from drv import *
+from beacon import BENTRY_HDR
+from scammer import MME, get_sniffed_mme
+from common import HPAV_MMTYPES, HPAV_MMTYPES_REVERSE, HPAV_RESULT, HPAV_PEKS
+from common import HPAV_PID
diff --git a/common/lib/scammer/beacon.py b/common/lib/scammer/beacon.py
new file mode 100644
index 0000000000..91e97323dc
--- /dev/null
+++ b/common/lib/scammer/beacon.py
@@ -0,0 +1,379 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#
+# Beacon description in a VS_SNIFFER.IND MME
+#
+# See scpay/layers/inet.py for IPOptions construction.
+#
+# To add a new beacon entry in the script, you need to create a new class
+# which derives Bentry class.
+# In this new class, the header must be filled as class attribute.
+#############################################################################
+
+from scapy.all import Packet, SourceMACField
+from scapy.fields import *
+from common import ETHER_TYPES, HPAV_CCO_LEVEL
+from commonfields import *
+
+BENTRY_HDR = {
+ "NON_PERSISTENT_SCHEDULE": 0x00,
+ "PERSISTENT_SCHEDULE": 0x01,
+ "REGIONS": 0x02,
+ "MAC_ADDRESS": 0x03,
+ "DISCOVER": 0x04,
+ "DISCOVERED_INFO": 0x05,
+ "BEACON_PERIOD_START_TIME_OFFSET": 0x06,
+ "ENCRYPTION_KEY_CHANGE": 0x07,
+ "CCO_HANDOVER": 0x08,
+ "BEACON_RELOCATION": 0x09,
+ "AC_LINE_SYNC_COUNTDOWN": 0x0A,
+ "CHANGE_NUMSLOTS": 0x0B,
+ "CHANGE_HM": 0x0C,
+ "CHANGE_SNID": 0x0D,
+ }
+
+class BEntryHDR (Packet):
+ """Beacon entry header."""
+ # Use the BENTRY_HDR dict to compose a new dict with the keyword
+ # inverted. i.e. bentry['CHANHE_SNID'] will be _bentry[0xd].
+ _bentry = {}
+ for i in BENTRY_HDR:
+ _bentry[BENTRY_HDR[i]] = i
+ fields_desc = [
+ ByteEnumField ("header", 0, _bentry),
+ ByteField ("length", 0)
+ ]
+
+class BEntry (Packet):
+ """Beacon entries are different depending on the Beacon Entry Header. So
+ we need to parse each header to know to which beacon entry it
+ corresponds."""
+ fields_desc = [
+ BEntryHDR,
+ ]
+
+ registered_bentry = {}
+ @classmethod
+ def register_variant(cls):
+ cls.registered_bentry [cls.header.default] = cls
+ @classmethod
+ def dispatch_hook(cls, pkt=None, *args, **kargs):
+ if pkt:
+ header = struct.unpack ('B', pkt[0])[0]
+ if header in cls.registered_bentry:
+ return cls.registered_bentry [header]
+ return cls
+
+ def extract_padding(self, s):
+ return "",s
+
+class BEntrySchedulesAllocations (Packet):
+ """Session Allocation Information."""
+ # The stpf flag indicates if there is a start time in the allocation or
+ # not.
+ fields_desc = [
+ LEBitField ("stpf", 0, 1),
+ LEBitField ("glid", 0, 7),
+ ConditionalField (LEBitField ("st_atu", 0, 12), lambda p: p.stpf),
+ LEBitField ("et_atu", 0, 12),
+ ConditionalField (LEBitField("pad", 0, 4), lambda p: not p.stpf),
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class BEntryNonPersistentSchedule (BEntry):
+ """Beacon entry Non Persistent Schedule."""
+ header = BENTRY_HDR['NON_PERSISTENT_SCHEDULE']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("ns", 0, 6),
+ LEBitField ("benpsf_rsvd1", 0, 2),
+ PacketListField ("sai", None, BEntrySchedulesAllocations,
+ count_from=lambda p:p.ns),
+ ]
+
+class BEntryPersistentSchedule (BEntry):
+ """Beacon entry Non Persistent Schedule."""
+ header = BENTRY_HDR['PERSISTENT_SCHEDULE']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("pscd", 0, 3),
+ LEBitField ("cscd", 0, 3),
+ LEBitField ("bepsf_rsvd1", 0, 2),
+ LEBitField ("ns", 0, 6),
+ LEBitField ("bepsf_rsvd2", 0, 2),
+ PacketListField ("sai", None, BEntrySchedulesAllocations,
+ count_from=lambda p:p.ns),
+ ]
+
+class BEntryRegionsDesc (Packet):
+ """Region definition."""
+ fields_desc = [
+ LEBitField ("rt", 0, 4),
+ LEBitField ("ret", 0, 12),
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class BEntryRegions (BEntry):
+ """Region beacon entry."""
+ header = BENTRY_HDR['REGIONS']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("nr", 0, 6),
+ LEBitField ("ber_rvsd", 0, 2),
+ PacketListField ("rlist", None, BEntryRegionsDesc,
+ count_from=lambda p:p.nr),
+ ]
+
+class BEntryMacAddress (BEntry):
+ """Beacon entry for the mac address."""
+ header = BENTRY_HDR['MAC_ADDRESS']
+ fields_desc = [
+ BEntryHDR,
+ MACField("mac", ETHER_ANY),
+ ]
+
+class BEntryDiscover (BEntry):
+ """Discover beacon entry."""
+ header = BENTRY_HDR['DISCOVER']
+ fields_desc = [
+ BEntryHDR,
+ ByteField ("tei", 0),
+ ]
+
+class BEntryDiscoveredInfo (BEntry):
+ """Discover info beacon entry."""
+ header = BENTRY_HDR['DISCOVERED_INFO']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("updated", 0, 1),
+ LEBitField ("cco_cap", 0, 2),
+ LEBitField ("proxy_networking_cap", 0, 1),
+ LEBitField ("backup_cco_cap", 0, 1),
+ LEBitField ("cco_status", 0, 1),
+ LEBitField ("pco_status", 0, 1),
+ LEBitField ("backup_cco_status", 0, 1),
+ ByteField ("numdissta", 0),
+ ByteField ("numdisnet", 0),
+ LEBitField ("authentication_status", 0, 1),
+ LEBitField ("user_appointed", 0, 1),
+ LEBitField ("bedi_rsvd", 0, 6),
+ ]
+
+class BEntryBeaconPeriodStartTimeOffset (BEntry):
+ """Beacon Period Start Time Offset."""
+ header = BENTRY_HDR['BEACON_PERIOD_START_TIME_OFFSET']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("bpsto", 0, 24),
+ ]
+
+class BEntryEncryptionKeyChange (BEntry):
+ """Encryption Key change."""
+ header = BENTRY_HDR['ENCRYPTION_KEY_CHANGE']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("kccd", 0, 6),
+ LEBitField ("kbc", 0, 1),
+ LEBitField ("beckc_rsvd", 0, 1),
+ LEBitField ("neweks", 0, 4),
+ LEBitField ("beckc_rsvd2", 0, 4),
+ ]
+
+class BEntryCcoHandover (BEntry):
+ """CCo Handover."""
+ header = BENTRY_HDR['CCO_HANDOVER']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("hcd", 0, 6),
+ LEBitField ("bech_rsvd", 0, 2),
+ ByteField ("nctei", 0),
+ ]
+
+class BEntryBeaconRelocation (BEntry):
+ """Beacon Relocation"""
+ header = BENTRY_HDR['BEACON_RELOCATION']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("rcd", 0, 6),
+ LEBitField ("rlt", 0, 1),
+ LEBitField ("lgf", 0, 1),
+ LEBitField ("rlo", 0, 17),
+ LEBitField ("rlslotid", 0, 3),
+ LEBitField ("bebr_rsvd", 0, 4),
+ ]
+
+class BEntryAcLineSyncCountdown (BEntry):
+ """AC Line Sync Countdown."""
+ header = BENTRY_HDR['AC_LINE_SYNC_COUNTDOWN']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("countdown", 0, 6),
+ LEBitField ("beaclsc_rsvd1", 0, 2),
+ LEBitField ("reasoncode", 0, 2),
+ LEBitField ("beaclsc_rsvd2", 0, 6),
+ ]
+
+class BEntryChangeNumslots (BEntry):
+ """Change NumSlots."""
+ header = BENTRY_HDR['CHANGE_NUMSLOTS']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("nsccd", 0, 6),
+ LEBitField ("becns_rsvd1", 0, 2),
+ LEBitField ("newnumslot", 0, 3),
+ LEBitField ("becns_rsvd2", 0, 5),
+ ]
+
+class BEntryChangeHm (BEntry):
+ """Change Hybrid Mode."""
+ header = BENTRY_HDR['CHANGE_HM']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("hmccd", 0, 6),
+ LEBitField ("newhm", 0, 2),
+ ]
+
+class BEntryChangeSnid (BEntry):
+ """Change SNID."""
+ header = BENTRY_HDR['CHANGE_SNID']
+ fields_desc = [
+ BEntryHDR,
+ LEBitField ("sccd", 0, 4),
+ LEBitField ("newsnid", 0, 4),
+ ]
+
+class BeaconSniff (Packet):
+ """Beacon description inside a VS_SNIFFER.IND MME"""
+ name = "Beacon description inside a VS_SNIFFER.IND MME"
+ fields_desc = [
+ XLEBitField ("nid", 0, 54),
+ XLEBitField ("hm", 0, 2),
+ XByteField ("stei", 0),
+ XLEBitField ("bt", 0, 3),
+ XLEBitField ("ncnr", 0, 1),
+ XLEBitField ("npsm", 0, 1),
+ XLEBitField ("numslots", 0, 3),
+ XLEBitField ("slotusage", 7, 8),
+ XLEBitField ("slotid", 0, 3),
+ XLEBitField ("aclss", 0, 3),
+ XLEBitField ("hoip", 0, 1),
+ XLEBitField ("rtsbf", 0, 1),
+ XLEBitField ("nm", 0, 2),
+ XLEBitField ("ccocap", 0, 2),
+ XLEBitField ("rsvd", 0, 4),
+ FieldLenField("nbe", None, count_of="bentry",fmt="B"),
+ # From here the beacon entry are like Header, Length (in bytes),
+ # entry.
+ # Entries may have N repeated structure i.e. schedules, regions...
+ # So entries does not have the same length, all we know is that
+ # the beacon entries are ordered and there is nbe beacon entries
+ # in the beacon.
+ PacketListField("bentry", None, BEntry, count_from=lambda p:p.nbe),
+ ]
+
+if __name__ == '__main__':
+ """Create a beacon to check if the dissector is correct."""
+ from scapy.utils import str2mac
+ mac = '00:13:d7:00:00:%02x'
+ # Non Persistent schedules.
+ non_peristent_sais = [
+ BEntrySchedulesAllocations (stpf = False , glid = 1,
+ et_atu=50),
+ BEntrySchedulesAllocations (stpf = True, glid = 2,
+ st_atu=50, et_atu=1500),
+ ]
+ bnps = BEntryNonPersistentSchedule (
+ header=BENTRY_HDR['NON_PERSISTENT_SCHEDULE'],
+ length=11 ,ns=3, sai=non_peristent_sais)
+ # Persistent schedules.
+ persistent_sais = [
+ BEntrySchedulesAllocations (stpf = True, glid = 3,
+ st_atu=1500, et_atu=3907)
+ ]
+ bps = BEntryPersistentSchedule (
+ header=BENTRY_HDR['PERSISTENT_SCHEDULE'],
+ length=5, pscd=7, cscd=7, ns=1, sai=persistent_sais)
+ # Create regions.
+ r = BEntryRegions (
+ header = BENTRY_HDR['REGIONS'],
+ length = 4,
+ nr = 2,
+ rlist = [
+ BEntryRegionsDesc (rt=0, ret=50),
+ BEntryRegionsDesc (rt=1, ret=3907)
+ ])
+ # Store the mac address.
+ m = BEntryMacAddress (
+ header = BENTRY_HDR['MAC_ADDRESS'],
+ length = 6,
+ mac = mac % 5)
+ # Discover entry.
+ d = BEntryDiscover (
+ header = BENTRY_HDR['DISCOVER'],
+ length = 1,
+ tei = 0xA)
+ # Discover info entry.
+ di = BEntryDiscoveredInfo (
+ header = BENTRY_HDR['DISCOVERED_INFO'],
+ length = 4,
+ updated = False,
+ cco_cap = 1,
+ proxy_networking_cap = False,
+ backup_cco_cap = True,
+ cco_status = True,
+ pco_status = False,
+ backup_cco_status = False,
+ numdissta = 4,
+ numdisnet = 3,
+ authentication_status = True,
+ user_appointed = False)
+ # Beacon period start time offset.
+ bpsto = BEntryBeaconPeriodStartTimeOffset (
+ header = BENTRY_HDR['BEACON_PERIOD_START_TIME_OFFSET'],
+ length = 3,
+ bpsto = 1204)
+ # Encryption key change.
+ ekc = BEntryEncryptionKeyChange (
+ header = BENTRY_HDR['ENCRYPTION_KEY_CHANGE'],
+ length = 2,
+ kccd = 4,
+ kbc = 1,
+ neweks = 2)
+ # CCo handover.
+ ccoh = BEntryCcoHandover (
+ header = BENTRY_HDR['CCO_HANDOVER'],
+ length = 2,
+ hcd = 3, nctei = 0xb)
+ # Beacon relocation.
+ br = BEntryBeaconRelocation (
+ header = BENTRY_HDR['BEACON_RELOCATION'],
+ length = 4, rcd = 4, rlt = 1, lgf = 1, rlo = 1240, rlslotid = 2)
+ # Ac Line Sync Countdown
+ alsc = BEntryAcLineSyncCountdown (
+ header = BENTRY_HDR['AC_LINE_SYNC_COUNTDOWN'],
+ length = 2, countdown = 3, reasoncode = 1)
+ # Change num slots.
+ cn = BEntryChangeNumslots (
+ header = BENTRY_HDR['CHANGE_NUMSLOTS'],
+ length = 2, nsccd = 3, newnumslot = 2)
+ # Change Hybrid mode.
+ chm = BEntryChangeHm (
+ header = BENTRY_HDR['CHANGE_HM'],
+ length = 1, hmccd = 2, newhm = 1)
+ # Change snid.
+ csnid = BEntryChangeSnid (
+ header = BENTRY_HDR['CHANGE_SNID'],
+ length = 1, sccd = 3, newsnid = 2)
+ # Create the beacon.
+ m = BeaconSniff (nid=0x12345789abc, hm=0, stei=1, bt=1, ncnr=0,
+ npsm=0, numslots=7, slotusage=1, slotid=1, aclss=0, hoip=0,
+ rtsbf=0, nm=2, ccocap=1, rsvd=0,
+ bentry=[bnps, bps, r, m, d, di, bpsto, ekc, ccoh, br, alsc,
+ cn, chm, csnid])
+ m.show ()
diff --git a/common/lib/scammer/cc.py b/common/lib/scammer/cc.py
new file mode 100644
index 0000000000..a5936de884
--- /dev/null
+++ b/common/lib/scammer/cc.py
@@ -0,0 +1,189 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#############################################################################
+
+from scapy.all import Packet
+from scapy.fields import *
+from commonfields import *
+from common import HPAV_CCO_LEVEL, HPAV_RESULT
+from scammer import MMEPayload
+
+class CC_WHO_RU_REQ (MMEPayload):
+ """Handles the CC_WHO_RU.REQ MME."""
+ name = "HomePlug AV CC_WHO_RU.REQ"""
+ fields_desc = [
+ HPAVNIDField ("nid", 0),
+ ]
+
+class CC_WHO_RU_CNF (MMEPayload):
+ """Handles the CC_WHO_RU.CNF MME."""
+ name = "HomePlug AV CC_WHO_RU.CNF"""
+ fields_desc = [
+ HPAVNIDField ("nid", 0),
+ MACField ("mac", ETHER_ANY),
+ StrFixedLenField ("hfid", 0, 64),
+ ]
+
+class CC_LEAVE_REQ (MMEPayload):
+ """Handles the CC_LEAVE.REQ MME."""
+ name = "HomePlug AV CC_LEAVE.REQ"""
+ fields_desc = [
+ ByteEnumField ("reason", 0, {
+ 0: "USER_REQUEST",
+ 1: "POWER_DOWN",
+ }),
+ ]
+
+class CC_LEAVE_CNF (MMEPayload):
+ """Handles the CC_LEAVE.CNF MME."""
+ name = "HomePlug AV CC_LEAVE.CNF"""
+ fields_desc = [
+ ]
+
+class CC_LEAVE_IND (MMEPayload):
+ """Handles the CC_LEAVE.IND MME."""
+ name = "HomePlug AV CC_LEAVE.IND"""
+ fields_desc = [
+ XByteField ("reason", 0),
+ HPAVNIDField ("nid", 0),
+ ]
+
+class CC_LEAVE_RSP (MMEPayload):
+ """Handles the CC_LEAVE.RSP MME."""
+ name = "HomePlug AV CC_LEAVE.RSP"""
+ fields_desc = [
+ ]
+
+class CC_HANDOVER_REQ (MMEPayload):
+ """Handles the CC_HANDOVER.REQ MME."""
+ name = "HomePlug AV CC_HANDOVER.REQ"""
+ fields_desc = [
+ ByteEnumField ("soft_hard", 0, {
+ 0: "SOFT",
+ 1: "HARD",
+ }),
+ ByteEnumField ("reason", 0, {
+ 0x00: "USER_APPOINTED",
+ 0x01: "CCO_SELECTION",
+ 0x02: "CCO_LEAVING",
+ }),
+ ]
+
+class CC_HANDOVER_CNF (MMEPayload):
+ """Handles the CC_HANDOVER.CNF MME."""
+ name = "HomePlug AV CC_HANDOVER.CNF"""
+ fields_desc = [
+ ByteEnumField ("result", 0,
+ {
+ 0: "ACCEPT",
+ 1: "REJECT_SOFT_HANDOVER",
+ 2: "REJECT_ANY_HANDOVER",
+ }),
+ ]
+
+class CC_HANDOVER_INFO_IND_sta_info (Packet):
+ """Handles the CC_HANDOVER_INFO.IND MME."""
+ name = "HomePlug AV CC_HANDOVER_INFO.IND."
+ fields_desc = [
+ ByteField ("tei", 0),
+ MACField ("mac", 0),
+ ByteEnumField ("status", 0,
+ {
+ 0: "ASSOCIATED",
+ 1: "AUTHENTICATED",
+ }),
+ ByteField ("ptei", 0),
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class CC_HANDOVER_INFO_IND (MMEPayload):
+ """Handles the CC_HANDOVER_INFO.IND MME."""
+ name = "HomePlug AV CC_HANDOVER_INFO.IND"
+ fields_desc = [
+ ByteEnumField ("rsc", 0,
+ {
+ 0: "HOIP",
+ 1: "UPDATE_BCCO",
+ }),
+ ByteField ("backupcco", 0),
+ FieldLenField("num", None, count_of="stas",fmt="B"),
+ PacketListField ("stas", None, CC_HANDOVER_INFO_IND_sta_info,
+ count_from=lambda p: p.num),
+ ]
+
+class CC_HANDOVER_INFO_RSP (MMEPayload):
+ """Handles the CC_HANDOVER_INFO.RSP MME."""
+ name = "HomePlug AV CC_HANDOVER_INFO.RSP"
+ fields_desc = [
+ ]
+
+class CC_SET_TEI_MAP_REQ (MMEPayload):
+ """Handles the CC_SET_TEI_MAP.REQ MME."""
+ name = "HomePlug AV CC_SET_TEI_MAP.REQ"
+ fields_desc = [
+ ]
+
+class CC_SET_TEI_MAP_IND_station (Packet):
+ """Handle the station description within the CC_SET_TEI_MAP.IND."""
+ fields_desc = [
+ ByteField ("tei", 0),
+ MACField ("mac", 0),
+ ByteEnumField ("status", 0,
+ {
+ 0: "ASSOCIATED",
+ 1: "AUTHENTICATED",
+ 2: "DISASSOCIATED",
+ }),
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class CC_SET_TEI_MAP_IND (MMEPayload):
+ """Handles the CC_SET_TEI_MAP.IND MME."""
+ name = "HomePlug AV CC_SET_TEI_MAP.IND"
+ fields_desc = [
+ ByteEnumField ("mode", 0,
+ {
+ 0: "UPDATE",
+ 1: "ADD",
+ 2: "DELETE",
+ }),
+ FieldLenField("num", None, count_of="stations",fmt="B"),
+ PacketListField ("stations", None, CC_SET_TEI_MAP_IND_station,
+ count_from = lambda p: p.num),
+ ]
+
+class CC_ASSOC_REQ (MMEPayload):
+ """Handles the CC_ASSOC.REQ MME."""
+ name = "HomePlug AV CC_ASSOC.REQ"
+ fields_desc = [
+ ByteEnumField ("reqtype", 0, {
+ 0: "NEW",
+ 1: "RENEW",
+ }),
+ HPAVNIDField ("nid", 0),
+ ByteEnumField ("cco_cap", 0, HPAV_CCO_LEVEL),
+ ByteField ("proxy_cap", 0)
+ ]
+
+class CC_ASSOC_CNF (MMEPayload):
+ """Handles the CC_ASSOC.CNF MME."""
+ name = "HomePlug AV CC_ASSOC.CNF"
+ fields_desc = [
+ ByteEnumField ("result", 0, HPAV_RESULT),
+ HPAVNIDField ("nid", 0),
+ ByteField ("snid", 0),
+ ByteField ("stei", 0),
+ LEShortField ("tei_lease", 0),
+ ]
+
+if __name__ == '__main__':
+ m = CC_WHO_RU_REQ (nid = 0x03c3ffdd7d22d5)
+ hexdump (str (m))
+ s = CC_WHO_RU_REQ (str (m))
+ print hex (s.nid)
diff --git a/common/lib/scammer/cm.py b/common/lib/scammer/cm.py
new file mode 100644
index 0000000000..e83ffe4dfe
--- /dev/null
+++ b/common/lib/scammer/cm.py
@@ -0,0 +1,187 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#
+# All CM MME.
+#############################################################################
+
+from scapy.all import Packet
+from scapy.fields import *
+from common import HPAV_CCO_LEVEL, HPAV_PEKS, HPAV_PID, HPAV_KEY_TYPE
+from common import HPAV_RESULT
+from commonfields import *
+from scammer import MMEPayload
+
+class CM_UNASSOCIATED_STA_IND (MMEPayload):
+ """Handles the CM_UNASSOCIATED_STA.IND MME. """
+ name = "HomePlug AV CM_UNASSOCIATED_STA.IND"
+ fields_desc = [
+ HPAVNIDField ("nid", 0),
+ ByteEnumField ("cco_cap", 0, HPAV_CCO_LEVEL),
+ ]
+
+class CM_ENCRYPTED_PAYLOAD_IND (MMEPayload):
+ """Handles the CM_ENCRYPTED_PAYLOAD.IND MME."""
+ name = "HomePlug AV CM_ENCRYPTED_PAYLOAD.IND """
+ fields_desc = [
+ ByteEnumField ("peks", 0, HPAV_PEKS),
+ ByteField ("avln_status", 0),
+ ByteEnumField ("pid", 0, HPAV_PID),
+ LEShortField ("prn", 0),
+ ByteField ("pmn", 0),
+ BitField ("uuid", 0, 128),
+ ByteField ("length", 0),
+ ]
+
+class CM_BRG_INFO_REQ (MMEPayload):
+ """Handles the CM_BRG_INFO.REQ MME."""
+ name = "HomePlug AV CM_BRG_INFO.REQ """
+ fields_desc = [
+ ]
+
+class CM_BRG_INFO_CNF_bda (Packet):
+ """Handles CM_BRG_INFO.CNF bridge entry."""
+ name = "HomePlug AV CM_BRG_INFO.CNF bridge entry"""
+ fields_desc = [
+ MACField ("mac", ETHER_ANY),
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class CM_BRG_INFO_CNF (MMEPayload):
+ """Handles the CM_BRG_INFO.CNF MME."""
+ name = "HomePlug AV CM_BRG_INFO.CNF """
+ fields_desc = [
+ ByteField ("bsf", 0),
+ ByteField ("btei", 0),
+ FieldLenField ("nbda", None, count_of="bdas", fmt="B"),
+ PacketListField ("bdas", None, CM_BRG_INFO_CNF_bda,
+ count_from = lambda p: p.nbda),
+ ]
+
+class CM_SC_JOIN_REQ (MMEPayload):
+ """Handles the CM_SC_JOIN.REQ MME."""
+ name = "HomePlug AV CM_SC_JOIN.REQ """
+ fields_desc = [
+ BitField ("cco_cap", 0, 2),
+ BitField ("rsvd", 0, 6),
+ ]
+
+class CM_SC_JOIN_CNF (MMEPayload):
+ """Handles the CM_SC_JOIN.CNF MME."""
+ name = "HomePlug AV CM_SC_JOIN.CNF """
+ fields_desc = [
+ HPAVNIDField ("nid", 0),
+ BitField ("avln_status", 0, 1),
+ BitField ("cco_cap", 0, 2),
+ BitField ("proxy_cap", 0, 1),
+ BitField ("backup_cco_cap", 0, 1),
+ BitField ("cco_status", 0, 1),
+ BitField ("pco_status", 0, 1),
+ BitField ("backup_cco_status", 0, 1),
+ ]
+
+class CM_GET_KEY_REQ (MMEPayload):
+ """Handles the CM_GET_KEY.REQ MME."""
+ name = "HomePlug AV CM_GET_KEY.REQ """
+ fields_desc = [
+ ByteEnumField ("req_type", 0, {0: "DIRECT", 1: "RELAYED"}),
+ ByteEnumField ("req_keytype", 0, HPAV_KEY_TYPE),
+ HPAVNIDField ("nid", 0),
+ IntField ("my_nonce", 0),
+ ByteField ("pid", 0),
+ LEShortField ("prn", 0),
+ ByteField ("pmn", 0),
+ ConditionalField (StrLenField ("hash_key", "", length_from=384),
+ lambda p:p.req_keytype==4),
+ ]
+
+class CM_GET_KEY_CNF (MMEPayload):
+ """Handles the CM_GET_KEY.CNF MME."""
+ name = "HomePlug AV CM_GET_KEY.CNF """
+ fields_desc = [
+ ByteEnumField ("result", 0, HPAV_RESULT),
+ ByteEnumField ("req_keytype", 0, HPAV_KEY_TYPE),
+ IntField ("my_nonce", 0),
+ IntField ("your_nonce", 0),
+ HPAVNIDField ("nid", 0),
+ ByteField ("eks", 0),
+ ByteField ("pid", 0),
+ LEShortField ("prn", 0),
+ ByteField ("pmn", 0),
+ ConditionalField (BitField ("key", 0, 176),
+ lambda p:p.req_keytype!=4),
+ ConditionalField (BitField ("hash_key", 0, 3072),
+ lambda p:p.req_keytype==4),
+ ]
+
+class CM_NW_STATS_REQ (MMEPayload):
+ """Handles the CM_NW_STATS.REQ MME."""
+ name = "HomePlug AV CM_NW_STATS.REQ """
+ fields_desc = [
+ ]
+
+class CM_NW_STATS_CNF_station (Packet):
+ """Handles the CM_NW_STATS.CNF MME."""
+ name = "HomePlug AV CM_NW_STATS.CNF """
+ fields_desc = [
+ MACField ("mac", 0),
+ ByteField ("avgphydr_tx", 0),
+ ByteField ("avgphydr_rx", 0),
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class CM_NW_STATS_CNF (MMEPayload):
+ """Handles the CM_NW_STATS.CNF MME."""
+ name = "HomePlug AV CM_NW_STATS.CNF """
+ fields_desc = [
+ FieldLenField("num", None, count_of="stations",fmt="B"),
+ PacketListField ("stations", None, CM_NW_STATS_CNF_station,
+ count_from = lambda p: p.num)
+ ]
+
+class CM_NW_INFO_REQ (MMEPayload):
+ """Handles the CM_NW_INFO.REQ MME."""
+ name = "HomePlug AV CM_NW_INFO.REQ """
+ fields_desc = [
+ ]
+
+class CM_NW_INFO_CNF_nwinfo (Packet):
+ """Handles CM_NW_INFO_CNF.CNF network information entry."""
+ name = "HomePlug AV CM_NW_INFO_CNF.CNF network information entry"""
+ fields_desc = [
+ HPAVNIDField ("nid", 0),
+ ByteField ("snid", 0),
+ ByteField ("tei", 0),
+ ByteEnumField ("stationrole", 0, {
+ 0: "STA",
+ 1: "PROXY_COORDINATOR",
+ 2: "CCO" }),
+ MACField ("mac", ETHER_ANY),
+ ByteEnumField ("access", 0, {
+ 0: "IN_HOME",
+ 1: "ACCESS"
+ })
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class CM_NW_INFO_CNF (MMEPayload):
+ """Handles the CM_NW_INFO_CNF.CNF MME."""
+ name = "HomePlug AV CM_BRG_INFO.CNF """
+ fields_desc = [
+ FieldLenField ("numnws", None, count_of="nwinfo", fmt="B"),
+ PacketListField ("nwinfo", None, CM_NW_INFO_CNF_nwinfo,
+ count_from = lambda p: p.numnws),
+ ]
+
+if __name__ == '__main__':
+ # CM_UNASSOCIATED_STA_IND
+ m = CM_UNASSOCIATED_STA_IND (nid=0x123456789abc, cco_cap = 0)
+ p = CM_UNASSOCIATED_STA_IND (str (m))
+ p.show ()
diff --git a/common/lib/scammer/common.py b/common/lib/scammer/common.py
new file mode 100644
index 0000000000..519fcf4e09
--- /dev/null
+++ b/common/lib/scammer/common.py
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#############################################################################
+
+from scapy.all import ETHER_TYPES
+import os
+import re
+import sys
+
+def find_base ():
+ """Find the base of the project."""
+ base = os.path.abspath (__file__)
+ m = re.match (r'(.*/)common/lib.*', base)
+ return m.group (1)
+
+# Add HPAV Ethernet type to the ETHER_TYPES of scapy.
+ETHER_TYPES['HPAV'] = 0x88e1
+
+# Add the CCo Level/Capability
+HPAV_CCO_LEVEL = {0:'CCo Level 0', 1:'CCo Level 1', 2:'CCo Level 2'}
+
+# SPC OUI
+SPC_OUI = 0x0013d7
+
+# Get the MME Types.
+base = find_base ()
+sys.path.append ("%s/cesar/maximus/python/lib/cesar/" % base)
+from defineparser import define_parser
+HPAV_MMTYPES_TEMP = define_parser ("%s/cesar/cp/mme.h" % base)
+HPAV_MMTYPES = {}
+types = ["_REQ", "_CNF", "_IND", "_RSP"]
+for i in HPAV_MMTYPES_TEMP:
+ if not i.startswith ('CP_MME_') and not i.endswith ('_MIN') \
+ and not i.endswith ('_MAX'):
+ for j in range (len (types)):
+ HPAV_MMTYPES["%s%s" % (i, types[j])] = \
+ HPAV_MMTYPES_TEMP[i] + j
+ elif i.endswith ('_MIN') or i.endswith ('_MAX'):
+ HPAV_MMTYPES[i] = HPAV_MMTYPES_TEMP[i]
+del base
+del types
+del HPAV_MMTYPES_TEMP
+
+# Dict with the keywords base on the hexadecimal value.
+HPAV_MMTYPES_REVERSE = {}
+for i in HPAV_MMTYPES:
+ HPAV_MMTYPES_REVERSE[HPAV_MMTYPES[i]] = i
+
+HPAV_RESULT = {'success':0, 'failure': 1}
+
+HPAV_PEKS = {0: "DAK", 1: "NMK"}
+for i in range (2, 0xf):
+ HPAV_PEKS[i] = "TEK"
+HPAV_PEKS[0xf] = "None"
+
+HPAV_PID = { 0: "AUTHENTICATION_REQUEST",
+ 1: "PROVISIONING_AUTH_STA_NEK_BY_CCO",
+ 2: "PROVISIONING_STA_WITH_NMK_USING_DAK",
+ 3: "PROVISIONING_STA_WITH_NMK_USING_UKE",
+ 4: "HLE",
+ }
+
+HPAV_KEY_TYPE = {
+ 0: "DAK",
+ 1: "NMK",
+ 2: "NEK",
+ 3: "TEK",
+ 4: "HASH_KEY",
+ 5: "NONCE_ONLY"
+ }
diff --git a/common/lib/scammer/commonfields.py b/common/lib/scammer/commonfields.py
new file mode 100644
index 0000000000..82f4eaad14
--- /dev/null
+++ b/common/lib/scammer/commonfields.py
@@ -0,0 +1,107 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#############################################################################
+
+from scapy.fields import *
+
+class XLEShortField (LEShortField):
+ """This class is used to represent LEShortField (scapy) in Hexadecimal
+ representation, this functionality should exist in the future version of
+ scapy called 'XLEShortField' """
+ def i2repr(self, pkt, x):
+ if x is None:
+ x = 0
+ return lhex(self.i2h(pkt, x))
+
+class LEBitField (BitField):
+ def __init__(self, name, default, size):
+ BitField.__init__(self, name, default, size)
+
+ def addfield (self, pkt, s, val):
+ val = self.i2m(pkt, val)
+ if type(s) is tuple:
+ s,bitsdone,v = s
+ else:
+ bitsdone = 0
+ v = 0
+ if self.rev:
+ val = self.reverse(val)
+ v |= val << bitsdone
+ bitsdone += self.size
+ while bitsdone >= 8:
+ bitsdone -= 8
+ s = s+struct.pack("B", v >> bitsdone)
+ v &= (1L<<bitsdone)-1
+ if bitsdone:
+ return s,bitsdone,v
+ else:
+ return s
+
+ def getfield(self, pkt, s):
+ if type(s) is tuple:
+ s,bn = s
+ else:
+ bn = 0
+ # we don't want to process all the string
+ nb_bytes = (self.size+bn-1)/8 + 1
+ w = s[:nb_bytes]
+
+ # split the substring byte by byte
+ bytes = struct.unpack('%dB' % nb_bytes , w)
+
+ b = 0L
+ for c in range(nb_bytes):
+ b |= long(bytes[nb_bytes - 1 - c]) << (nb_bytes-c-1)*8
+
+ # Decal of bn.
+ b = b >> bn
+ # get rid of high order bits
+ b &= (1L << (self.size)) - 1
+
+ if self.rev:
+ b = self.reverse(b)
+
+ bn += self.size
+ s = s[bn/8:]
+ if bn % 8 != 0:
+ sbyte = struct.unpack ('B', s[0])[0]
+ decal_bits = (8 - (nb_bytes * 8 - self.size))
+ sbyte &= ~((1 << decal_bits) - 1)
+ sbyte = struct.pack ('B', sbyte)
+ s = sbyte + s[1:]
+
+ bn = bn%8
+ b = self.m2i(pkt, b)
+ if bn:
+ return (s,bn),b
+ else:
+ return s,b
+
+class XLEBitField (LEBitField):
+ """This class is used to represent LEShortField (scapy) in Hexadecimal
+ representation, this functionality should exist in the future version of
+ scapy called 'XLEShortField' """
+ def i2repr(self, pkt, x):
+ if x is None:
+ x = 0
+ return lhex(self.i2h(pkt, x))
+
+class HPAVNIDField (Field):
+ """Special Field for NID HPAV field."""
+ def __init__(self, name, default):
+ Field.__init__(self, name, default, "7s")
+
+ def addfield (self, pkt, s, val):
+ nb_bytes = 7
+ w = struct.pack ('Q', val)
+ w = w[:nb_bytes]
+ return s + w
+
+ def getfield (self, pkt, s):
+ nb_bytes = 7
+ w = "%s\0" % s[0:nb_bytes]
+ w = struct.unpack ('Q', w)[0]
+ s = s[nb_bytes:]
+ return s,w
diff --git a/common/lib/scammer/cp.py b/common/lib/scammer/cp.py
new file mode 100644
index 0000000000..0472be116a
--- /dev/null
+++ b/common/lib/scammer/cp.py
@@ -0,0 +1,10 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#
+#############################################################################
+
+from scapy.all import Packet
+from scapy.fields import *
+from commonfields import *
diff --git a/common/lib/scammer/drv.py b/common/lib/scammer/drv.py
new file mode 100644
index 0000000000..b1ff6f5610
--- /dev/null
+++ b/common/lib/scammer/drv.py
@@ -0,0 +1,140 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#############################################################################
+
+from scapy.all import Packet
+from scapy.fields import *
+from commonfields import *
+from scammer import MMEPayload
+from common import HPAV_RESULT
+
+class DRV_STA_MAC_STOP_REQ (MMEPayload):
+ """Handles the DRV_STA_MAC_STOP.REQ MME."""
+ name = "HomePlug AV DRV_STA_MAC_STOP.REQ"""
+ fields_desc = [
+ ]
+
+class DRV_STA_MAC_STOP_CNF (MMEPayload):
+ """Handles the DRV_STA_MAC_STOP.CNF MME."""
+ name = "HomePlug AV DRV_STA_MAC_STOP.CNF"""
+ fields_desc = [
+ XByteField ("result", 0),
+ ]
+
+class DRV_STA_STATUS_IND (MMEPayload):
+ """Handles the DRV_STA_STATUS.IND MME."""
+ name = "HomePlug AV DRV_STA_STATUS.IND"""
+ fields_desc = [
+ ByteEnumField ("status", 0,
+ {0: "unassociated",
+ 1: "associated",
+ 2: "authenticated"}
+ ),
+ ByteEnumField ("role", 0,
+ {0: "Station",
+ 1: "Proxy CCo",
+ 2: "CCo",
+ }
+ ),
+ XByteField ("user_appoint_cco", 0),
+ XByteField ("backup_cco", 0),
+ XByteField ("simple_connect", 0),
+ ByteEnumField ("PLC_sync_freq", 0,
+ {0: "unknown",
+ 1: "50Hz",
+ 2: "60Hz",
+ 3: "Co-axial_Cable",
+ }
+ ),
+ ]
+
+class DRV_STA_SC_REQ (MMEPayload):
+ """Handles the DRV_STA_SC.REQ MME."""
+ name = "HomePlug AV DRV_STA_SC.REQ"""
+ fields_desc = [
+ ByteEnumField ("sc_join", 0, { 0: "SC_ADD", 1: "SC_JOIN" }),
+ ]
+
+class DRV_STA_SC_CNF (MMEPayload):
+ """Handles the DRV_STA_SC.CNF MME."""
+ name = "HomePlug AV DRV_STA_SC.CNF"""
+ fields_desc = [
+ ByteEnumField ("result", 0, HPAV_RESULT),
+ ]
+
+class DRV_MCAST_SET_LIST_REQ_member (Packet):
+ """Handles the DRV_MCAST_SET_LIST.REQ_member MME."""
+ name = "HomePlug AV DRV_MCAST_SET_LIST.REQ_member"""
+ fields_desc = [
+ MACField ("mac", ETHER_ANY),
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class DRV_MCAST_SET_LIST_REQ_group (Packet):
+ """Handles the DRV_MCAST_SET_LIST.REQ_group MME."""
+ name = "HomePlug AV DRV_MCAST_SET_LIST.REQ_group"""
+ fields_desc = [
+ MACField ("mac_group", ETHER_ANY),
+ FieldLenField("nbmembers", None, count_of="members",fmt="B"),
+ PacketListField ("members", None,
+ DRV_MCAST_SET_LIST_REQ_member,
+ count_from = lambda p: p.nbmembers),
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class DRV_MCAST_SET_LIST_REQ (MMEPayload):
+ """Handles the DRV_MCAST_SET_LIST.REQ MME."""
+ name = "HomePlug AV DRV_MCAST_SET_LIST.REQ"""
+ fields_desc = [
+ FieldLenField("nbgrps", None, count_of="groups",fmt="B"),
+ PacketListField ("groups", None, DRV_MCAST_SET_LIST_REQ_group,
+ count_from = lambda p: p.nbgrps),
+ ]
+
+class DRV_MCAST_SET_LIST_CNF (MMEPayload):
+ """Handles the DRV_MCAST_SET_LIST.CNF MME."""
+ name = "HomePlug AV DRV_MCAST_SET_LIST.CNF"""
+ fields_desc = [
+ ByteEnumField ("result", 0, HPAV_RESULT),
+ ]
+
+class DRV_STA_SET_KEY_REQ (MMEPayload):
+ """Handles the DRV_STA_SET_KEY.REQ MME."""
+ name = "HomePlug AV DRV_STA_SET_KEY.REQ"""
+ fields_desc = [
+ BitField ("nmk", 0, 128),
+ ByteEnumField ("type", 0,
+ {
+ 0: "CHANGE_NID",
+ 1: "CHANGE_SECURITY_LEVEL",
+ }),
+ HPAVNIDField ("nid", 0),
+ ByteField ("sl", 0),
+ ]
+
+class DRV_STA_SET_KEY_CNF (MMEPayload):
+ """Handles the DRV_STA_SET_KEY.CNF MME."""
+ name = "HomePlug AV DRV_STA_SET_KEY.CNF"""
+ fields_desc = [
+ ByteEnumField ("result", 0, HPAV_RESULT),
+ ]
+
+class DRV_STA_SET_KEY_IND (MMEPayload):
+ """Handles the DRV_STA_SET_KEY.IND MME."""
+ name = "HomePlug AV DRV_STA_SET_KEY.IND"""
+ fields_desc = [
+ BitField ("nmk", 0, 128),
+ ByteEnumField ("type", 0,
+ {
+ 0: "CHANGE_NID",
+ 1: "CHANGE_SECURITY_LEVEL",
+ }),
+ HPAVNIDField ("nid", 0),
+ ByteField ("sl", 0),
+ ]
diff --git a/common/lib/scammer/nn.py b/common/lib/scammer/nn.py
new file mode 100644
index 0000000000..d96c5d7ff5
--- /dev/null
+++ b/common/lib/scammer/nn.py
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#############################################################################
+
+from scapy.all import Packet
+from scapy.fields import *
+from commonfields import *
diff --git a/common/lib/scammer/scammer.py b/common/lib/scammer/scammer.py
new file mode 100644
index 0000000000..c4ebdb42be
--- /dev/null
+++ b/common/lib/scammer/scammer.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#
+# MME handler based on scapy.
+#
+# See http://www.secdev.org/projects/scapy/doc/build_dissect.html
+#
+# To see dissection errors add conf.debug_dissector = 1 anywhere in the
+# script.
+#############################################################################
+
+from scapy.all import Ether, Packet, bind_layers
+from scapy.fields import *
+from commonfields import *
+from common import ETHER_TYPES, HPAV_MMTYPES, HPAV_MMTYPES_REVERSE
+
+class MME (Packet):
+ """Create an Ethernet packet."""
+ name = "HomePlug AV MME"
+ fields_desc = [
+ XByteField("mmv", 1),
+ EnumField("mmtype", 0,
+ HPAV_MMTYPES_REVERSE,
+ fmt = "<H"),
+ ConditionalField (XBitField("nf_mi", 0, 4), lambda p:p.mmv==0x1),
+ ConditionalField (XBitField("fn_mi", 0, 4), lambda p:p.mmv==0x1),
+ ConditionalField (XByteField("fmsn", 0), lambda p:p.mmv==0x1),
+ ]
+
+bind_layers (Ether, MME, type = ETHER_TYPES['HPAV'])
+
+class MMEPayload (Packet):
+ """MME Payload Metaclass"""
+
+ @classmethod
+ def register_variant(cls):
+ if cls.__name__ in HPAV_MMTYPES:
+ bind_layers (MME, cls, mmtype = HPAV_MMTYPES[cls.__name__])
+
+def get_sniffed_mme (mme):
+ """Get the MME embedded in the VS_SNIFFER.IND."""
+ assert mme.mmtype == HPAV_MMTYPES['VS_SNIFFER_IND']
+ return mme.getlayer (3)
+
+if __name__ == '__main__':
+ mac = '00:13:d7:00:00:%02x'
+ m = Ether (dst=mac % 2, src=mac % 1) \
+ / MME (mmtype=0x6002, nf_mi=0, fn_mi=0, fmsn=0)
+ print "mme", repr (str (m))
+ p = Ether (str (m))
+ p.show ()
diff --git a/common/lib/scammer/vs.py b/common/lib/scammer/vs.py
new file mode 100644
index 0000000000..5ffef98020
--- /dev/null
+++ b/common/lib/scammer/vs.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+
+#############################################################################
+# Copyright (C) 2011 Spidcom
+#
+# All VS MME.
+#############################################################################
+
+from scapy.all import Packet, Ether, bind_layers
+from scapy.fields import *
+from commonfields import *
+from common import SPC_OUI, HPAV_RESULT
+from scammer import MMEPayload
+from beacon import BeaconSniff
+
+class VS_HEADER (Packet):
+ """The vendor specific MME."""
+ name = "HomePlug AV VS MME"
+ fields_desc = [
+ XBitField ("oui", SPC_OUI, 24),
+ ]
+
+class VS_SNIFFER_REQ_CNF_command (Packet):
+ """Handles the command bit field of the VS_SNIFFER.REQ/CNF MME."""
+ name = "HomePlug AV VS_SNIFFER.REQ/CNF command bit field MME"
+ fields_desc = [
+ LEBitField ("mme_tx", 0, 1),
+ LEBitField ("mme_rx", 0, 1),
+ LEBitField ("beacon_tx", 0, 1),
+ LEBitField ("beacon_rx", 0, 1),
+ LEBitField ("fc_rx", 0, 1),
+ LEBitField ("mpdu_rx", 0, 1),
+ LEBitField ("rsvd", 0, 2),
+ ]
+
+class VS_SNIFFER_REQ (MMEPayload):
+ """Handles the VS_SNIFFER.REQ MME."""
+ name = "HomePlug AV VS_SNIFFER.REQ MME"
+ fields_desc = [
+ VS_HEADER,
+ VS_SNIFFER_REQ_CNF_command,
+ ]
+
+class VS_SNIFFER_CNF (MMEPayload):
+ """Handles the VS_SNIFFER.CNF MME."""
+ name = "HomePlug AV VS_SNIFFER.CNF MME"
+ fields_desc = [
+ VS_HEADER,
+ ByteEnumField ("result", 0, HPAV_RESULT),
+ VS_SNIFFER_REQ_CNF_command,
+ MACField ("dmac", ETHER_ANY),
+ ]
+
+class VS_SNIFFER_IND (MMEPayload):
+ """Handles a VS_SNIFFER.IND MME. """
+ name = "HomePlug AV VS_SNIFFER.IND"
+ fields_desc = [
+ VS_HEADER,
+ ByteEnumField ("sniff_type", 0, {0:'MME', 1:'Beacon', 2:'MPDU'}),
+ ByteEnumField ("direction", 0, {0:'transmitted', 1:'received'}),
+ ]
+
+bind_layers (VS_SNIFFER_IND, Ether, sniff_type = 0)
+bind_layers (VS_SNIFFER_IND, BeaconSniff, sniff_type = 1)
+
+class VS_GET_MACTOTEI_REQ (MMEPayload):
+ """Handles a VS_GET_MACTOTEI.REQ MME. """
+ name = "HomePlug AV VS_GET_MACTOTEI.REQ MME"
+ fields_desc = [
+ VS_HEADER,
+ ]
+
+class VS_GET_MACTOTEI_CNF_entry (Packet):
+ """Handles a VS_GET_MACTOTEI.CNF mac entry MME. """
+ name = "HomePlug AV VS_GET_MACTOTEI.CNF mac entry MME"
+ fields_desc = [
+ MACField ("mac", 0),
+ ByteField ("tei", 0),
+ ByteField ("tag", 0),
+ ]
+
+ def extract_padding(self, s):
+ return "",s
+
+class VS_GET_MACTOTEI_CNF (MMEPayload):
+ """Handles a VS_GET_MACTOTEI.CNF MME. """
+ name = "HomePlug AV VS_GET_MACTOTEI.CNF MME"
+ fields_desc = [
+ VS_HEADER,
+ FieldLenField ("nb", None, count_of="entries", fmt="<H"),
+ PacketListField ("entries", None, VS_GET_MACTOTEI_CNF_entry,
+ count_from = lambda p: p.nb),
+ ]
+
+if __name__ == '__main__':
+ from scapy.all import Ether
+ from scammer import MME
+ mac = '00:13:d7:00:00:%02x'
+ # VS_SNIFFER_IND
+ m = VS_SNIFFER_IND (sniff_type=1, direction=0)
+ p = VS_SNIFFER_IND (str (m))
+ p.show ()
+ # A full MME.
+ m = Ether (dst=mac % 2, src=mac % 1) \
+ / MME () \
+ / VS_SNIFFER_IND (sniff_type=1, direction=0)
+ m.show ()
+ p = Ether (str (m))
+ p.show ()