Skip to content

Commit

Permalink
Updated the osi.transport.igmp templates to add preliminary support f…
Browse files Browse the repository at this point in the history
…or IGMPv3.
  • Loading branch information
arizvisa committed Jun 6, 2024
1 parent d4d7af2 commit dfb16f0
Showing 1 changed file with 124 additions and 15 deletions.
139 changes: 124 additions & 15 deletions template/osi/transport/igmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,24 @@ def checksum(bytes):
checksum = shifted + (seed & 0XFFFF)
return 0xFFFF & ~checksum

class IGMP_(pint.enum, u_char):
class igmp_type(pint.enum, u_char):
_values_ = [
('MEMBERSHIP_QUERY', 0x11), # membership query
('V1_MEMBERSHIP_REPORT', 0x12), # Ver. 1 membership report
('V2_MEMBERSHIP_REPORT', 0x16), # Ver. 2 membership report
('V2_LEAVE_GROUP', 0x17), # Leave-group message
('DVMRP', 0x13), # DVMRP routing message
('PIM', 0x14), # PIM routing message
('MTRACE_RESP', 0x1e), # traceroute resp.(to sender)
('MTRACE', 0x1f), # mcast traceroute messages
('MEMBERSHIP_QUERY', 0x11), # membership query
('V1_MEMBERSHIP_REPORT', 0x12), # Ver. 1 membership report
('DVMRP', 0x13), # DVMRP routing message
('PIM', 0x14), # PIMv1 message (historic)
('V2_MEMBERSHIP_REPORT', 0x16), # Ver. 2 membership report
('HOST_LEAVE_MESSAGE', 0x17), # Leave-group message
('MTRACE_REPLY', 0x1e), # mtrace(8) reply
('MTRACE_QUERY', 0x1f), # mtrace(8) probe
('v3_HOST_MEMBERSHIP_REPORT', 0x22), # Ver. 3 membership report
]

@network.layer.define
#@network.layer.define
class igmp(pstruct.type, stackable):
type = 2
_fields_ = [
(IGMP_, 'igmp_type'), # version & type of IGMP message
(igmp_type, 'igmp_type'), # version & type of IGMP message
(u_char, 'igmp_code'), # subtype for routing msgs
(u_char, 'igmp_cksum'), # IP-style checksum
(in_addr, 'igmp_group'), # group address being reported (zero for queries)
Expand All @@ -53,7 +54,115 @@ def alloc(self, **fields):
res['igmp_cksum'].set(checksum(bytearray(data)))
return res

def layer(self):
layer, id, remaining = super(header, self).layer()
res = self['length'].li
return layer, id, max(0, res.int() - sum(self[fld].li.size() for fld in ['source port', 'dest port', 'length', 'checksum']))
class igmp_grouprec(pstruct.type):
def __ig_sources(self):
res = self['ig_numsrc'].li
return dyn.array(in_addr, res.int())
_fields_ = [
(u_char, 'ig_type'), # record type
(u_char, 'ig_datalen'), # length of auxiliary data
(u_short, 'ig_numsrc'), # number of sources
(in_addr, 'ig_group'), # group address being reported
(__ig_sources, 'ig_sources'), # source addresses
]
def alloc(self, **fields):
res = super(igmp_grouprec, self).alloc(**fields)
if 'ig_numsrc' not in fields:
res['ig_numsrc'].set(len(res['ig_sources']))
if 'ig_datalen' not in fields:
pass # FIXME
return res

class igmp_report_mode(pint.enum):
_values_ = [
('IGMP_DO_NOTHING', 0), # don't send a record
('IGMP_MODE_IS_INCLUDE', 1), # MODE_IN
('IGMP_MODE_IS_EXCLUDE', 2), # MODE_EX
('IGMP_CHANGE_TO_INCLUDE_MODE', 3), # TO_IN
('IGMP_CHANGE_TO_EXCLUDE_MODE', 4), # TO_EX
('IGMP_ALLOW_NEW_SOURCES', 5), # ALLOW_NEW
('IGMP_BLOCK_OLD_SOURCES', 6), # BLOCK_OLD
]

class igmp_report(pstruct.type):
def __ir_groups(self):
res = self['ir_numgrps'].li
return dyn.array(igmp_grouprec, res.int())
_fields_ = [
(u_char, 'ir_type'), # IGMP_v3_HOST_MEMBERSHIP_REPORT
(u_char, 'ir_rsv1'), # must be zero
(u_short, 'ir_cksum'), # checksum
(u_short, 'ir_rsv2'), # must be zero
(u_short, 'ir_numgrps'), # number of group records
(__ir_groups, 'ir_groups'), # group records
]

def alloc(self, **fields):
res = super(igmp_report, self).alloc(**fields)
if 'ir_numgrps' not in fields:
res['ir_numgrps'].set(len(res['ir_groups']))
if 'ir_cksum' not in fields:
data = res.set(ir_cksum=0).serialize()
res['ir_cksum'].set(checksum(bytearray(data)))
return res

class IGMP_V3_(pint.enum):
_fields_ = [
('GENERAL_QUERY', 1),
('GROUP_QUERY', 2),
('GROUP_SOURCE_QUERY', 3),
]

class igmpv3_float(pfloat.float_t):
components = 1, 3, 4

@network.layer.define
class igmpv3(pstruct.type, stackable):
type = 2
class _igmp_misc(pbinary.flags):
_fields_ = [
(3, 'QRV'),
(1, 'S'),
(4, 'RESV'),
]

def __igmp_sources(self):
res = self['igmp_numsrc'].li
return dyn.array(in_addr, res.int())

def v3(type):
'''Conditionally return a missing type if the packet isn't IGMPv3.'''
if not isinstance(type, type.__class__.__class__):
missing = parray.type
elif issubclass(type, pint.uint_t):
missing = pint.uint_t
elif issubclass(type, pint.sint_t):
missing = pint.sint_t
elif issubclass(type, pfloat.type):
missing = dyn.clone(pfloat.float_t, components=(0, 0, 0))
else:
missing = ptype.undefined
def v3(self):
res = self['igmp_type'].li
return type if res.int() in {0x11, 0x22} else missing
return v3

_fields_ = [
(igmp_type, 'igmp_type'), # version & type of IGMP message
(igmpv3_float, 'igmp_code'), # subtype for routing msgs
(u_short, 'igmp_cksum'), # IP-style checksum
(in_addr, 'igmp_group'), # group address being reported (zero for queries)
(v3(_igmp_misc), 'igmp_misc'), # reserved/suppress/robustness
(v3(igmpv3_float), 'igmp_qqi'), # querier's query interval
(v3(u_short), 'igmp_numsrc'), # number of sources
(v3(__igmp_sources), 'igmp_sources'), # source addresses
]

def alloc(self, **fields):
res = super(igmpv3, self).alloc(**fields)
if 'igmp_numsrc' not in fields and isinstance(res['igmp_numsrc'], pint.type):
res['igmp_numsrc'].set(len(res['igmp_sources']))
if 'igmp_cksum' not in fields:
data = res.set(igmp_cksum=0).serialize()
res['igmp_cksum'].set(checksum(bytearray(data)))
return res

0 comments on commit dfb16f0

Please sign in to comment.