class MPacketPreamble(Packet): # IEEE 802.3br Figure 99-3 name = "MPacket Preamble" fields_desc = [ StrFixedLenField("preamble", b"", length=8), FCSField("fcs", 0, fmt="!I") ]
class Dot15d4FCS(Dot15d4): ''' This class is a drop-in replacement for the Dot15d4 class above, except it expects a FCS/checksum in the input, and produces one in the output. This provides the user flexibility, as many 802.15.4 interfaces will have an AUTO_CRC setting # noqa: E501 that will validate the FCS/CRC in firmware, and add it automatically when transmitting. # noqa: E501 ''' name = "802.15.4 - FCS" match_subclass = True fields_desc = Dot15d4.fields_desc + [FCSField("fcs", None, fmt="<H")] def compute_fcs(self, data): # Do a CRC-CCITT Kermit 16bit on the data given # Returns a CRC that is the FCS for the frame # Implemented using pseudocode from: June 1986, Kermit Protocol Manual # See also: # http://regregex.bbcmicro.net/crc-catalogue.htm#crc.cat.kermit crc = 0 for i in range(0, len(data)): c = orb(data[i]) q = (crc ^ c) & 15 # Do low-order 4 bits crc = (crc // 16) ^ (q * 4225) q = (crc ^ (c // 16)) & 15 # And high 4 bits crc = (crc // 16) ^ (q * 4225) return struct.pack('<H', crc) # return as bytes in little endian order def post_build(self, p, pay): # construct the packet with the FCS at the end p = Dot15d4.post_build(self, p, pay) if self.fcs is None: p = p[:-2] p = p + self.compute_fcs(p) return p
class Dot11FCS(Dot11): name = "802.11-FCS" match_subclass = True fields_desc = Dot11.fields_desc + [FCSField("fcs", None, fmt="<I")] def compute_fcs(self, s): return struct.pack("!I", crc32(s) & 0xffffffff)[::-1] def post_build(self, p, pay): p += pay if self.fcs is None: p = p[:-4] + self.compute_fcs(p) return p
class BTH(Packet): name = "BTH" fields_desc = [ ByteEnumField("opcode", 0, _bth_opcodes), BitField("solicited", 0, 1), BitField("migreq", 0, 1), BitField("padcount", 0, 2), BitField("version", 0, 4), XShortField("pkey", 0xffff), BitField("fecn", 0, 1), BitField("becn", 0, 1), BitField("resv6", 0, 6), BitField("dqpn", 0, 24), BitField("ackreq", 0, 1), BitField("resv7", 0, 7), BitField("psn", 0, 24), FCSField("icrc", None, fmt="!I")] @staticmethod def pack_icrc(icrc): return struct.pack("!I", icrc & 0xffffffff)[::-1] def compute_icrc(self, p): udp = self.underlayer if udp is None or not isinstance(udp, UDP): warning("Expecting UDP underlayer to compute checksum. Got %s.", udp and udp.name) return self.pack_icrc(0) ip = udp.underlayer if isinstance(ip, IP): # pseudo-LRH / IP / UDP / BTH / payload pshdr = Raw(b'\xff' * 8) / ip.copy() pshdr.chksum = 0xffff pshdr.ttl = 0xff pshdr.tos = 0xff pshdr[UDP].chksum = 0xffff pshdr[BTH].fecn = 1 pshdr[BTH].becn = 1 pshdr[BTH].resv6 = 0xff bth = pshdr[BTH].self_build() payload = raw(pshdr[BTH].payload) # add ICRC placeholder just to get the right IP.totlen and # UDP.length icrc_placeholder = b'\xff\xff\xff\xff' pshdr[UDP].payload = Raw(bth + payload + icrc_placeholder) icrc = crc32(raw(pshdr)[:-4]) & 0xffffffff return self.pack_icrc(icrc) else: # TODO support IPv6 warning("The underlayer protocol %s is not supported.", ip and ip.name) return self.pack_icrc(0) # RoCE packets end with ICRC - a 32-bit CRC of the packet payload and # pseudo-header. Add the ICRC header if it is missing and calculate its # value. def post_build(self, p, pay): p += pay if self.icrc is None: p = p[:-4] + self.compute_icrc(p) return p