1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*cfb92d14SAndroid Build Coastguard Worker# 3*cfb92d14SAndroid Build Coastguard Worker# Copyright (c) 2016, The OpenThread Authors. 4*cfb92d14SAndroid Build Coastguard Worker# All rights reserved. 5*cfb92d14SAndroid Build Coastguard Worker# 6*cfb92d14SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without 7*cfb92d14SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met: 8*cfb92d14SAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright 9*cfb92d14SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer. 10*cfb92d14SAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright 11*cfb92d14SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer in the 12*cfb92d14SAndroid Build Coastguard Worker# documentation and/or other materials provided with the distribution. 13*cfb92d14SAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the 14*cfb92d14SAndroid Build Coastguard Worker# names of its contributors may be used to endorse or promote products 15*cfb92d14SAndroid Build Coastguard Worker# derived from this software without specific prior written permission. 16*cfb92d14SAndroid Build Coastguard Worker# 17*cfb92d14SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18*cfb92d14SAndroid Build Coastguard Worker# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*cfb92d14SAndroid Build Coastguard Worker# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*cfb92d14SAndroid Build Coastguard Worker# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21*cfb92d14SAndroid Build Coastguard Worker# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22*cfb92d14SAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*cfb92d14SAndroid Build Coastguard Worker# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*cfb92d14SAndroid Build Coastguard Worker# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25*cfb92d14SAndroid Build Coastguard Worker# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*cfb92d14SAndroid Build Coastguard Worker# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27*cfb92d14SAndroid Build Coastguard Worker# POSSIBILITY OF SUCH DAMAGE. 28*cfb92d14SAndroid Build Coastguard Worker# 29*cfb92d14SAndroid Build Coastguard Worker 30*cfb92d14SAndroid Build Coastguard Workerimport io 31*cfb92d14SAndroid Build Coastguard Workerimport ipaddress 32*cfb92d14SAndroid Build Coastguard Workerimport struct 33*cfb92d14SAndroid Build Coastguard Worker 34*cfb92d14SAndroid Build Coastguard Workerimport common 35*cfb92d14SAndroid Build Coastguard Workerimport ipv6 36*cfb92d14SAndroid Build Coastguard Worker 37*cfb92d14SAndroid Build Coastguard Worker 38*cfb92d14SAndroid Build Coastguard Workerclass LowpanIPHC: 39*cfb92d14SAndroid Build Coastguard Worker """ 40*cfb92d14SAndroid Build Coastguard Worker Class representing a compressed IP header. 41*cfb92d14SAndroid Build Coastguard Worker 42*cfb92d14SAndroid Build Coastguard Worker More details: 43*cfb92d14SAndroid Build Coastguard Worker - URL: https://tools.ietf.org/html/rfc6282 44*cfb92d14SAndroid Build Coastguard Worker - section: 3.1. LOWPAN_IPHC Encoding Format 45*cfb92d14SAndroid Build Coastguard Worker """ 46*cfb92d14SAndroid Build Coastguard Worker 47*cfb92d14SAndroid Build Coastguard Worker def __init__(self, tf, nh, hlim, cid, sac, sam, m, dac, dam): 48*cfb92d14SAndroid Build Coastguard Worker self._tf = tf 49*cfb92d14SAndroid Build Coastguard Worker self._nh = nh 50*cfb92d14SAndroid Build Coastguard Worker self._hlim = hlim 51*cfb92d14SAndroid Build Coastguard Worker self._cid = cid 52*cfb92d14SAndroid Build Coastguard Worker self._sac = sac 53*cfb92d14SAndroid Build Coastguard Worker self._sam = sam 54*cfb92d14SAndroid Build Coastguard Worker self._m = m 55*cfb92d14SAndroid Build Coastguard Worker self._dac = dac 56*cfb92d14SAndroid Build Coastguard Worker self._dam = dam 57*cfb92d14SAndroid Build Coastguard Worker 58*cfb92d14SAndroid Build Coastguard Worker @property 59*cfb92d14SAndroid Build Coastguard Worker def tf(self): 60*cfb92d14SAndroid Build Coastguard Worker return self._tf 61*cfb92d14SAndroid Build Coastguard Worker 62*cfb92d14SAndroid Build Coastguard Worker @property 63*cfb92d14SAndroid Build Coastguard Worker def nh(self): 64*cfb92d14SAndroid Build Coastguard Worker return self._nh 65*cfb92d14SAndroid Build Coastguard Worker 66*cfb92d14SAndroid Build Coastguard Worker @property 67*cfb92d14SAndroid Build Coastguard Worker def hlim(self): 68*cfb92d14SAndroid Build Coastguard Worker return self._hlim 69*cfb92d14SAndroid Build Coastguard Worker 70*cfb92d14SAndroid Build Coastguard Worker @property 71*cfb92d14SAndroid Build Coastguard Worker def cid(self): 72*cfb92d14SAndroid Build Coastguard Worker return self._cid 73*cfb92d14SAndroid Build Coastguard Worker 74*cfb92d14SAndroid Build Coastguard Worker @property 75*cfb92d14SAndroid Build Coastguard Worker def sac(self): 76*cfb92d14SAndroid Build Coastguard Worker return self._sac 77*cfb92d14SAndroid Build Coastguard Worker 78*cfb92d14SAndroid Build Coastguard Worker @property 79*cfb92d14SAndroid Build Coastguard Worker def sam(self): 80*cfb92d14SAndroid Build Coastguard Worker return self._sam 81*cfb92d14SAndroid Build Coastguard Worker 82*cfb92d14SAndroid Build Coastguard Worker @property 83*cfb92d14SAndroid Build Coastguard Worker def m(self): 84*cfb92d14SAndroid Build Coastguard Worker return self._m 85*cfb92d14SAndroid Build Coastguard Worker 86*cfb92d14SAndroid Build Coastguard Worker @property 87*cfb92d14SAndroid Build Coastguard Worker def dac(self): 88*cfb92d14SAndroid Build Coastguard Worker return self._dac 89*cfb92d14SAndroid Build Coastguard Worker 90*cfb92d14SAndroid Build Coastguard Worker @property 91*cfb92d14SAndroid Build Coastguard Worker def dam(self): 92*cfb92d14SAndroid Build Coastguard Worker return self._dam 93*cfb92d14SAndroid Build Coastguard Worker 94*cfb92d14SAndroid Build Coastguard Worker @classmethod 95*cfb92d14SAndroid Build Coastguard Worker def from_bytes(cls, data_bytes): 96*cfb92d14SAndroid Build Coastguard Worker data_byte = data_bytes[0] 97*cfb92d14SAndroid Build Coastguard Worker 98*cfb92d14SAndroid Build Coastguard Worker hdr = (data_byte >> 5) & 0x07 99*cfb92d14SAndroid Build Coastguard Worker if hdr != 0x03: 100*cfb92d14SAndroid Build Coastguard Worker raise RuntimeError("Not a 6LowPAN packet.") 101*cfb92d14SAndroid Build Coastguard Worker 102*cfb92d14SAndroid Build Coastguard Worker tf = (data_byte >> 3) & 0x03 103*cfb92d14SAndroid Build Coastguard Worker nh = (data_byte >> 2) & 0x01 104*cfb92d14SAndroid Build Coastguard Worker hlim = data_byte & 0x03 105*cfb92d14SAndroid Build Coastguard Worker 106*cfb92d14SAndroid Build Coastguard Worker data_byte = data_bytes[1] 107*cfb92d14SAndroid Build Coastguard Worker 108*cfb92d14SAndroid Build Coastguard Worker cid = (data_byte >> 7) & 0x01 109*cfb92d14SAndroid Build Coastguard Worker sac = (data_byte >> 6) & 0x01 110*cfb92d14SAndroid Build Coastguard Worker sam = (data_byte >> 4) & 0x03 111*cfb92d14SAndroid Build Coastguard Worker m = (data_byte >> 3) & 0x01 112*cfb92d14SAndroid Build Coastguard Worker dac = (data_byte >> 2) & 0x01 113*cfb92d14SAndroid Build Coastguard Worker dam = data_byte & 0x03 114*cfb92d14SAndroid Build Coastguard Worker 115*cfb92d14SAndroid Build Coastguard Worker return cls(tf, nh, hlim, cid, sac, sam, m, dac, dam) 116*cfb92d14SAndroid Build Coastguard Worker 117*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 118*cfb92d14SAndroid Build Coastguard Worker return "LowpanIPHC(tf={}, nh={}, hlim={}, cid={}, sac={}, sam={}, m={}, dac={}, dam={})".format( 119*cfb92d14SAndroid Build Coastguard Worker self.tf, 120*cfb92d14SAndroid Build Coastguard Worker self.nh, 121*cfb92d14SAndroid Build Coastguard Worker self.hlim, 122*cfb92d14SAndroid Build Coastguard Worker self.cid, 123*cfb92d14SAndroid Build Coastguard Worker self.sac, 124*cfb92d14SAndroid Build Coastguard Worker self.sam, 125*cfb92d14SAndroid Build Coastguard Worker self.m, 126*cfb92d14SAndroid Build Coastguard Worker self.dac, 127*cfb92d14SAndroid Build Coastguard Worker self.dam, 128*cfb92d14SAndroid Build Coastguard Worker ) 129*cfb92d14SAndroid Build Coastguard Worker 130*cfb92d14SAndroid Build Coastguard Worker 131*cfb92d14SAndroid Build Coastguard Workerclass LowpanNHC: 132*cfb92d14SAndroid Build Coastguard Worker """ 133*cfb92d14SAndroid Build Coastguard Worker Class representing a compressed extension header. 134*cfb92d14SAndroid Build Coastguard Worker 135*cfb92d14SAndroid Build Coastguard Worker More details: 136*cfb92d14SAndroid Build Coastguard Worker - URL: https://tools.ietf.org/html/rfc6282 137*cfb92d14SAndroid Build Coastguard Worker - section: 4.1. LOWPAN_NHC Format 138*cfb92d14SAndroid Build Coastguard Worker 139*cfb92d14SAndroid Build Coastguard Worker """ 140*cfb92d14SAndroid Build Coastguard Worker 141*cfb92d14SAndroid Build Coastguard Worker NHC_EID_HOP_BY_HOP = 0 142*cfb92d14SAndroid Build Coastguard Worker NHC_EID_ROUTING = 1 143*cfb92d14SAndroid Build Coastguard Worker NHC_EID_FRAGMENT = 2 144*cfb92d14SAndroid Build Coastguard Worker NHC_EID_DST_OPT = 3 145*cfb92d14SAndroid Build Coastguard Worker NHC_EID_MOBILITY = 4 146*cfb92d14SAndroid Build Coastguard Worker NHC_EID_IPV6_HDR = 7 147*cfb92d14SAndroid Build Coastguard Worker 148*cfb92d14SAndroid Build Coastguard Worker def __init__(self, eid, nh): 149*cfb92d14SAndroid Build Coastguard Worker self._eid = eid 150*cfb92d14SAndroid Build Coastguard Worker self._nh = nh 151*cfb92d14SAndroid Build Coastguard Worker 152*cfb92d14SAndroid Build Coastguard Worker @property 153*cfb92d14SAndroid Build Coastguard Worker def eid(self): 154*cfb92d14SAndroid Build Coastguard Worker return self._eid 155*cfb92d14SAndroid Build Coastguard Worker 156*cfb92d14SAndroid Build Coastguard Worker @property 157*cfb92d14SAndroid Build Coastguard Worker def nh(self): 158*cfb92d14SAndroid Build Coastguard Worker return self._nh 159*cfb92d14SAndroid Build Coastguard Worker 160*cfb92d14SAndroid Build Coastguard Worker @classmethod 161*cfb92d14SAndroid Build Coastguard Worker def from_bytes(cls, data_bytes): 162*cfb92d14SAndroid Build Coastguard Worker header_byte = data_bytes[0] 163*cfb92d14SAndroid Build Coastguard Worker 164*cfb92d14SAndroid Build Coastguard Worker eid = (header_byte >> 1) & 0x07 165*cfb92d14SAndroid Build Coastguard Worker nh = header_byte & 0x01 166*cfb92d14SAndroid Build Coastguard Worker 167*cfb92d14SAndroid Build Coastguard Worker return cls(eid, nh) 168*cfb92d14SAndroid Build Coastguard Worker 169*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 170*cfb92d14SAndroid Build Coastguard Worker return "LowpanNHC(eid={}, nh={})".format(self.eid, self.nh) 171*cfb92d14SAndroid Build Coastguard Worker 172*cfb92d14SAndroid Build Coastguard Worker 173*cfb92d14SAndroid Build Coastguard Workerclass LowpanUDPHC: 174*cfb92d14SAndroid Build Coastguard Worker """ 175*cfb92d14SAndroid Build Coastguard Worker Class representing compressed UDP header. 176*cfb92d14SAndroid Build Coastguard Worker 177*cfb92d14SAndroid Build Coastguard Worker More details: 178*cfb92d14SAndroid Build Coastguard Worker - URL: https://tools.ietf.org/html/rfc6282 179*cfb92d14SAndroid Build Coastguard Worker - section: 4.3.3. UDP LOWPAN_NHC Format 180*cfb92d14SAndroid Build Coastguard Worker 181*cfb92d14SAndroid Build Coastguard Worker """ 182*cfb92d14SAndroid Build Coastguard Worker 183*cfb92d14SAndroid Build Coastguard Worker def __init__(self, c, p): 184*cfb92d14SAndroid Build Coastguard Worker self._c = c 185*cfb92d14SAndroid Build Coastguard Worker self._p = p 186*cfb92d14SAndroid Build Coastguard Worker 187*cfb92d14SAndroid Build Coastguard Worker @property 188*cfb92d14SAndroid Build Coastguard Worker def c(self): 189*cfb92d14SAndroid Build Coastguard Worker return self._c 190*cfb92d14SAndroid Build Coastguard Worker 191*cfb92d14SAndroid Build Coastguard Worker @property 192*cfb92d14SAndroid Build Coastguard Worker def p(self): 193*cfb92d14SAndroid Build Coastguard Worker return self._p 194*cfb92d14SAndroid Build Coastguard Worker 195*cfb92d14SAndroid Build Coastguard Worker @classmethod 196*cfb92d14SAndroid Build Coastguard Worker def from_bytes(cls, data_bytes): 197*cfb92d14SAndroid Build Coastguard Worker data_byte = data_bytes[0] 198*cfb92d14SAndroid Build Coastguard Worker 199*cfb92d14SAndroid Build Coastguard Worker hdr = (data_byte >> 3) & 0x1F 200*cfb92d14SAndroid Build Coastguard Worker if hdr != 0x1E: 201*cfb92d14SAndroid Build Coastguard Worker raise RuntimeError("Not a 6LowPAN UDP header.") 202*cfb92d14SAndroid Build Coastguard Worker 203*cfb92d14SAndroid Build Coastguard Worker c = (data_byte >> 2) & 0x01 204*cfb92d14SAndroid Build Coastguard Worker p = data_byte & 0x03 205*cfb92d14SAndroid Build Coastguard Worker 206*cfb92d14SAndroid Build Coastguard Worker return cls(c, p) 207*cfb92d14SAndroid Build Coastguard Worker 208*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 209*cfb92d14SAndroid Build Coastguard Worker return "LowpanUDPHC(c={}, p={})".format(self.c, self.p) 210*cfb92d14SAndroid Build Coastguard Worker 211*cfb92d14SAndroid Build Coastguard Worker 212*cfb92d14SAndroid Build Coastguard Workerclass LowpanHopByHopFactory: 213*cfb92d14SAndroid Build Coastguard Worker """ Factory that produces HopByHop extension header. """ 214*cfb92d14SAndroid Build Coastguard Worker 215*cfb92d14SAndroid Build Coastguard Worker def __init__(self, hop_by_hop_options_factory): 216*cfb92d14SAndroid Build Coastguard Worker self._hop_by_hop_options_factory = hop_by_hop_options_factory 217*cfb92d14SAndroid Build Coastguard Worker 218*cfb92d14SAndroid Build Coastguard Worker def parse(self, data, next_header, message_info): 219*cfb92d14SAndroid Build Coastguard Worker ext_header_length = ord(data.read(1)) 220*cfb92d14SAndroid Build Coastguard Worker 221*cfb92d14SAndroid Build Coastguard Worker ext_header_data = data.read(ext_header_length) 222*cfb92d14SAndroid Build Coastguard Worker 223*cfb92d14SAndroid Build Coastguard Worker options = self._hop_by_hop_options_factory.parse(io.BytesIO(ext_header_data), message_info) 224*cfb92d14SAndroid Build Coastguard Worker 225*cfb92d14SAndroid Build Coastguard Worker ext_header = ipv6.HopByHop(next_header, options) 226*cfb92d14SAndroid Build Coastguard Worker 227*cfb92d14SAndroid Build Coastguard Worker message_info.payload_length += len(ext_header) 228*cfb92d14SAndroid Build Coastguard Worker 229*cfb92d14SAndroid Build Coastguard Worker return ext_header 230*cfb92d14SAndroid Build Coastguard Worker 231*cfb92d14SAndroid Build Coastguard Worker 232*cfb92d14SAndroid Build Coastguard Workerclass LowpanExtensionHeadersFactory: 233*cfb92d14SAndroid Build Coastguard Worker """ Factory that produces extension headers. """ 234*cfb92d14SAndroid Build Coastguard Worker 235*cfb92d14SAndroid Build Coastguard Worker NHC_NH_INLINE = 0 236*cfb92d14SAndroid Build Coastguard Worker NHC_NH_COMPRESSED = 1 237*cfb92d14SAndroid Build Coastguard Worker 238*cfb92d14SAndroid Build Coastguard Worker def __init__(self, ext_headers_factories): 239*cfb92d14SAndroid Build Coastguard Worker self._ext_headers_factories = (ext_headers_factories if ext_headers_factories is not None else {}) 240*cfb92d14SAndroid Build Coastguard Worker 241*cfb92d14SAndroid Build Coastguard Worker def _decompress_nh(self, hc, data): 242*cfb92d14SAndroid Build Coastguard Worker if hc.nh == self.NHC_NH_INLINE: 243*cfb92d14SAndroid Build Coastguard Worker return ord(data.read(1)) 244*cfb92d14SAndroid Build Coastguard Worker 245*cfb92d14SAndroid Build Coastguard Worker elif hc.nh == self.NHC_NH_COMPRESSED: 246*cfb92d14SAndroid Build Coastguard Worker return None 247*cfb92d14SAndroid Build Coastguard Worker 248*cfb92d14SAndroid Build Coastguard Worker def _get_ext_headers_factory(self, eid): 249*cfb92d14SAndroid Build Coastguard Worker try: 250*cfb92d14SAndroid Build Coastguard Worker return self._ext_headers_factories[eid] 251*cfb92d14SAndroid Build Coastguard Worker 252*cfb92d14SAndroid Build Coastguard Worker except BaseException: 253*cfb92d14SAndroid Build Coastguard Worker raise RuntimeError("Could not find an extension header factory for the EID type: {}".format(eid)) 254*cfb92d14SAndroid Build Coastguard Worker 255*cfb92d14SAndroid Build Coastguard Worker def parse(self, data, message_info): 256*cfb92d14SAndroid Build Coastguard Worker nhc = LowpanNHC.from_bytes(bytearray(data.read(1))) 257*cfb92d14SAndroid Build Coastguard Worker 258*cfb92d14SAndroid Build Coastguard Worker next_header = self._decompress_nh(nhc, data) 259*cfb92d14SAndroid Build Coastguard Worker 260*cfb92d14SAndroid Build Coastguard Worker factory = self._get_ext_headers_factory(nhc.eid) 261*cfb92d14SAndroid Build Coastguard Worker 262*cfb92d14SAndroid Build Coastguard Worker return factory.parse(data, next_header, message_info) 263*cfb92d14SAndroid Build Coastguard Worker 264*cfb92d14SAndroid Build Coastguard Worker 265*cfb92d14SAndroid Build Coastguard Workerclass LowpanUdpHeaderFactory: 266*cfb92d14SAndroid Build Coastguard Worker """ Factory producing UDP header. """ 267*cfb92d14SAndroid Build Coastguard Worker 268*cfb92d14SAndroid Build Coastguard Worker UDP_HC_C_INLINE = 0 269*cfb92d14SAndroid Build Coastguard Worker UDP_HC_C_ELIDED = 1 270*cfb92d14SAndroid Build Coastguard Worker 271*cfb92d14SAndroid Build Coastguard Worker UDP_HC_P_BOTH_FULL = 0 272*cfb92d14SAndroid Build Coastguard Worker UDP_HC_P_DST_COMPR = 1 273*cfb92d14SAndroid Build Coastguard Worker UDP_HC_P_SRC_COMPR = 2 274*cfb92d14SAndroid Build Coastguard Worker UDP_HC_P_BOTH_COMPR = 3 275*cfb92d14SAndroid Build Coastguard Worker 276*cfb92d14SAndroid Build Coastguard Worker def _decompress_udp_ports(self, udphc, data): 277*cfb92d14SAndroid Build Coastguard Worker if udphc.p == self.UDP_HC_P_BOTH_FULL: 278*cfb92d14SAndroid Build Coastguard Worker src_port = struct.unpack(">H", data.read(2))[0] 279*cfb92d14SAndroid Build Coastguard Worker dst_port = struct.unpack(">H", data.read(2))[0] 280*cfb92d14SAndroid Build Coastguard Worker 281*cfb92d14SAndroid Build Coastguard Worker elif udphc.p == self.UDP_HC_P_DST_COMPR: 282*cfb92d14SAndroid Build Coastguard Worker src_port = struct.unpack(">H", data.read(2))[0] 283*cfb92d14SAndroid Build Coastguard Worker dst_port = 0xf000 + ord(data.read(1)) 284*cfb92d14SAndroid Build Coastguard Worker 285*cfb92d14SAndroid Build Coastguard Worker elif udphc.p == self.UDP_HC_P_SRC_COMPR: 286*cfb92d14SAndroid Build Coastguard Worker src_port = 0xf000 + ord(data.read(1)) 287*cfb92d14SAndroid Build Coastguard Worker dst_port = struct.unpack(">H", data.read(2))[0] 288*cfb92d14SAndroid Build Coastguard Worker 289*cfb92d14SAndroid Build Coastguard Worker elif udphc.p == self.UDP_HC_P_BOTH_COMPR: 290*cfb92d14SAndroid Build Coastguard Worker udp_ports_byte = ord(data.read(1)) 291*cfb92d14SAndroid Build Coastguard Worker src_port = 0xf0b0 + ((udp_ports_byte >> 4) & 0x0F) 292*cfb92d14SAndroid Build Coastguard Worker dst_port = 0xf0b0 + (udp_ports_byte & 0x0F) 293*cfb92d14SAndroid Build Coastguard Worker 294*cfb92d14SAndroid Build Coastguard Worker return src_port, dst_port 295*cfb92d14SAndroid Build Coastguard Worker 296*cfb92d14SAndroid Build Coastguard Worker def _decompress_udp_checksum(self, udphc, data): 297*cfb92d14SAndroid Build Coastguard Worker if udphc.c == self.UDP_HC_C_INLINE: 298*cfb92d14SAndroid Build Coastguard Worker checksum = struct.unpack(">H", data.read(2))[0] 299*cfb92d14SAndroid Build Coastguard Worker 300*cfb92d14SAndroid Build Coastguard Worker if udphc.c == self.UDP_HC_C_ELIDED: 301*cfb92d14SAndroid Build Coastguard Worker checksum = 0 302*cfb92d14SAndroid Build Coastguard Worker 303*cfb92d14SAndroid Build Coastguard Worker return checksum 304*cfb92d14SAndroid Build Coastguard Worker 305*cfb92d14SAndroid Build Coastguard Worker def parse(self, data, message_info): 306*cfb92d14SAndroid Build Coastguard Worker udphc = LowpanUDPHC.from_bytes(bytearray(data.read(1))) 307*cfb92d14SAndroid Build Coastguard Worker 308*cfb92d14SAndroid Build Coastguard Worker src_port, dst_port = self._decompress_udp_ports(udphc, data) 309*cfb92d14SAndroid Build Coastguard Worker 310*cfb92d14SAndroid Build Coastguard Worker checksum = self._decompress_udp_checksum(udphc, data) 311*cfb92d14SAndroid Build Coastguard Worker 312*cfb92d14SAndroid Build Coastguard Worker header = ipv6.UDPHeader(src_port, dst_port, checksum=checksum) 313*cfb92d14SAndroid Build Coastguard Worker 314*cfb92d14SAndroid Build Coastguard Worker return header 315*cfb92d14SAndroid Build Coastguard Worker 316*cfb92d14SAndroid Build Coastguard Worker 317*cfb92d14SAndroid Build Coastguard Workerclass Context: 318*cfb92d14SAndroid Build Coastguard Worker 319*cfb92d14SAndroid Build Coastguard Worker def __init__(self, prefix, prefix_length=None): 320*cfb92d14SAndroid Build Coastguard Worker if isinstance(prefix, str): 321*cfb92d14SAndroid Build Coastguard Worker prefix, prefix_length = prefix.split("/") 322*cfb92d14SAndroid Build Coastguard Worker prefix_length = int(prefix_length) 323*cfb92d14SAndroid Build Coastguard Worker 324*cfb92d14SAndroid Build Coastguard Worker a = ipaddress.ip_address(prefix) 325*cfb92d14SAndroid Build Coastguard Worker 326*cfb92d14SAndroid Build Coastguard Worker self._prefix = bytearray(a.packed) 327*cfb92d14SAndroid Build Coastguard Worker self._prefix_length = prefix_length 328*cfb92d14SAndroid Build Coastguard Worker 329*cfb92d14SAndroid Build Coastguard Worker elif isinstance(prefix, bytearray): 330*cfb92d14SAndroid Build Coastguard Worker self._prefix = prefix 331*cfb92d14SAndroid Build Coastguard Worker self._prefix_length = (prefix_length if prefix_length is not None else len(self._prefix) * 8) 332*cfb92d14SAndroid Build Coastguard Worker 333*cfb92d14SAndroid Build Coastguard Worker @property 334*cfb92d14SAndroid Build Coastguard Worker def prefix(self): 335*cfb92d14SAndroid Build Coastguard Worker return self._prefix[:self.prefix_length_all_bytes] 336*cfb92d14SAndroid Build Coastguard Worker 337*cfb92d14SAndroid Build Coastguard Worker @property 338*cfb92d14SAndroid Build Coastguard Worker def prefix_full_bytes(self): 339*cfb92d14SAndroid Build Coastguard Worker return self._prefix[:self.prefix_length_full_bytes] 340*cfb92d14SAndroid Build Coastguard Worker 341*cfb92d14SAndroid Build Coastguard Worker @property 342*cfb92d14SAndroid Build Coastguard Worker def prefix_length(self): 343*cfb92d14SAndroid Build Coastguard Worker return self._prefix_length 344*cfb92d14SAndroid Build Coastguard Worker 345*cfb92d14SAndroid Build Coastguard Worker @property 346*cfb92d14SAndroid Build Coastguard Worker def prefix_length_full_bytes(self): 347*cfb92d14SAndroid Build Coastguard Worker return int(self._prefix_length / 8) 348*cfb92d14SAndroid Build Coastguard Worker 349*cfb92d14SAndroid Build Coastguard Worker @property 350*cfb92d14SAndroid Build Coastguard Worker def prefix_length_rest_bits(self): 351*cfb92d14SAndroid Build Coastguard Worker return int(self._prefix_length % 8) 352*cfb92d14SAndroid Build Coastguard Worker 353*cfb92d14SAndroid Build Coastguard Worker @property 354*cfb92d14SAndroid Build Coastguard Worker def prefix_length_all_bytes(self): 355*cfb92d14SAndroid Build Coastguard Worker if self.prefix_length_rest_bits > 0: 356*cfb92d14SAndroid Build Coastguard Worker return self.prefix_length_full_bytes + 1 357*cfb92d14SAndroid Build Coastguard Worker 358*cfb92d14SAndroid Build Coastguard Worker return self.prefix_length_full_bytes 359*cfb92d14SAndroid Build Coastguard Worker 360*cfb92d14SAndroid Build Coastguard Worker 361*cfb92d14SAndroid Build Coastguard Workerclass ContextManager(dict): 362*cfb92d14SAndroid Build Coastguard Worker """ Class representing Context Manager. """ 363*cfb92d14SAndroid Build Coastguard Worker 364*cfb92d14SAndroid Build Coastguard Worker def __check_index(self, index): 365*cfb92d14SAndroid Build Coastguard Worker if index < 0 or index > 15: 366*cfb92d14SAndroid Build Coastguard Worker raise IndexError("Invalid index: {}. Valid index is in range [0, 15]".format(index)) 367*cfb92d14SAndroid Build Coastguard Worker 368*cfb92d14SAndroid Build Coastguard Worker def __check_type(self, value): 369*cfb92d14SAndroid Build Coastguard Worker if not isinstance(value, Context): 370*cfb92d14SAndroid Build Coastguard Worker raise TypeError("Invalid value type: {}".format(type(value))) 371*cfb92d14SAndroid Build Coastguard Worker 372*cfb92d14SAndroid Build Coastguard Worker def __getitem__(self, index): 373*cfb92d14SAndroid Build Coastguard Worker self.__check_index(index) 374*cfb92d14SAndroid Build Coastguard Worker 375*cfb92d14SAndroid Build Coastguard Worker return super(ContextManager, self).__getitem__(index) 376*cfb92d14SAndroid Build Coastguard Worker 377*cfb92d14SAndroid Build Coastguard Worker def __setitem__(self, index, value): 378*cfb92d14SAndroid Build Coastguard Worker self.__check_index(index) 379*cfb92d14SAndroid Build Coastguard Worker self.__check_type(value) 380*cfb92d14SAndroid Build Coastguard Worker 381*cfb92d14SAndroid Build Coastguard Worker return super(ContextManager, self).__setitem__(index, value) 382*cfb92d14SAndroid Build Coastguard Worker 383*cfb92d14SAndroid Build Coastguard Worker 384*cfb92d14SAndroid Build Coastguard Workerclass LowpanIpv6HeaderFactory: 385*cfb92d14SAndroid Build Coastguard Worker """ Factory that produces IPv6 header. """ 386*cfb92d14SAndroid Build Coastguard Worker 387*cfb92d14SAndroid Build Coastguard Worker IPV6_LINKLOCAL_PREFIX = bytearray([0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) 388*cfb92d14SAndroid Build Coastguard Worker 389*cfb92d14SAndroid Build Coastguard Worker SHORT_ADDR_PADDING_BYTES = bytearray([0x00, 0x00, 0x00, 0xff, 0xfe, 0x00]) 390*cfb92d14SAndroid Build Coastguard Worker 391*cfb92d14SAndroid Build Coastguard Worker IPHC_TF_4B = 0 392*cfb92d14SAndroid Build Coastguard Worker IPHC_TF_3B = 1 393*cfb92d14SAndroid Build Coastguard Worker IPHC_TF_1B = 2 394*cfb92d14SAndroid Build Coastguard Worker IPHC_TF_ELIDED = 3 395*cfb92d14SAndroid Build Coastguard Worker 396*cfb92d14SAndroid Build Coastguard Worker IPHC_NH_INLINE = 0 397*cfb92d14SAndroid Build Coastguard Worker IPHC_NH_COMPRESSED = 1 398*cfb92d14SAndroid Build Coastguard Worker 399*cfb92d14SAndroid Build Coastguard Worker IPHC_HLIM_CALCULATE = -1 400*cfb92d14SAndroid Build Coastguard Worker IPHC_HLIM_INLINE = 0 401*cfb92d14SAndroid Build Coastguard Worker IPHC_HLIM_1 = 1 402*cfb92d14SAndroid Build Coastguard Worker IPHC_HLIM_64 = 2 403*cfb92d14SAndroid Build Coastguard Worker IPHC_HLIM_255 = 3 404*cfb92d14SAndroid Build Coastguard Worker 405*cfb92d14SAndroid Build Coastguard Worker IPHC_CID_CLEAR = 0 406*cfb92d14SAndroid Build Coastguard Worker IPHC_CID_SET = 1 407*cfb92d14SAndroid Build Coastguard Worker 408*cfb92d14SAndroid Build Coastguard Worker IPHC_SAC_STATELESS = 0 409*cfb92d14SAndroid Build Coastguard Worker IPHC_SAC_STATEFUL = 1 410*cfb92d14SAndroid Build Coastguard Worker 411*cfb92d14SAndroid Build Coastguard Worker IPHC_SAM_128B = 0 412*cfb92d14SAndroid Build Coastguard Worker IPHC_SAM_UNSPECIFIED = 0 413*cfb92d14SAndroid Build Coastguard Worker IPHC_SAM_64B = 1 414*cfb92d14SAndroid Build Coastguard Worker IPHC_SAM_16B = 2 415*cfb92d14SAndroid Build Coastguard Worker IPHC_SAM_0B = 3 416*cfb92d14SAndroid Build Coastguard Worker IPHC_SAM_ELIDED = 3 417*cfb92d14SAndroid Build Coastguard Worker 418*cfb92d14SAndroid Build Coastguard Worker IPHC_M_NO = 0 419*cfb92d14SAndroid Build Coastguard Worker IPHC_M_YES = 1 420*cfb92d14SAndroid Build Coastguard Worker 421*cfb92d14SAndroid Build Coastguard Worker IPHC_DAC_STATELESS = 0 422*cfb92d14SAndroid Build Coastguard Worker IPHC_DAC_STATEFUL = 1 423*cfb92d14SAndroid Build Coastguard Worker 424*cfb92d14SAndroid Build Coastguard Worker IPHC_DAM_128B = 0 425*cfb92d14SAndroid Build Coastguard Worker IPHC_DAM_64B = 1 426*cfb92d14SAndroid Build Coastguard Worker IPHC_DAM_48B = 1 427*cfb92d14SAndroid Build Coastguard Worker IPHC_DAM_32B = 2 428*cfb92d14SAndroid Build Coastguard Worker IPHC_DAM_16B = 2 429*cfb92d14SAndroid Build Coastguard Worker IPHC_DAM_8B = 3 430*cfb92d14SAndroid Build Coastguard Worker IPHC_DAM_0B = 3 431*cfb92d14SAndroid Build Coastguard Worker IPHC_DAM_ELIDED = 3 432*cfb92d14SAndroid Build Coastguard Worker 433*cfb92d14SAndroid Build Coastguard Worker IPHC_M_DAM_00 = 0 434*cfb92d14SAndroid Build Coastguard Worker IPHC_M_DAM_01 = 1 435*cfb92d14SAndroid Build Coastguard Worker IPHC_M_DAM_10 = 2 436*cfb92d14SAndroid Build Coastguard Worker IPHC_M_DAM_11 = 3 437*cfb92d14SAndroid Build Coastguard Worker 438*cfb92d14SAndroid Build Coastguard Worker def __init__(self, context_manager=None): 439*cfb92d14SAndroid Build Coastguard Worker self._context_manager = context_manager 440*cfb92d14SAndroid Build Coastguard Worker 441*cfb92d14SAndroid Build Coastguard Worker def _flow_label(self, data_bytes): 442*cfb92d14SAndroid Build Coastguard Worker flow_label = (data_bytes[0] & 0x0F) << 16 443*cfb92d14SAndroid Build Coastguard Worker flow_label += data_bytes[1] << 8 444*cfb92d14SAndroid Build Coastguard Worker flow_label += data_bytes[2] 445*cfb92d14SAndroid Build Coastguard Worker return flow_label 446*cfb92d14SAndroid Build Coastguard Worker 447*cfb92d14SAndroid Build Coastguard Worker def _traffic_class(self, dscp, ecn): 448*cfb92d14SAndroid Build Coastguard Worker return (dscp << 2) | ecn 449*cfb92d14SAndroid Build Coastguard Worker 450*cfb92d14SAndroid Build Coastguard Worker def _unpack_dscp(self, data_byte): 451*cfb92d14SAndroid Build Coastguard Worker return data_byte & 0x3F 452*cfb92d14SAndroid Build Coastguard Worker 453*cfb92d14SAndroid Build Coastguard Worker def _unpack_ecn(self, data_byte): 454*cfb92d14SAndroid Build Coastguard Worker return data_byte >> 6 455*cfb92d14SAndroid Build Coastguard Worker 456*cfb92d14SAndroid Build Coastguard Worker def _decompress_tf_4bytes(self, data): 457*cfb92d14SAndroid Build Coastguard Worker data_bytes = [b for b in bytearray(data.read(4))] 458*cfb92d14SAndroid Build Coastguard Worker 459*cfb92d14SAndroid Build Coastguard Worker dscp = self._unpack_dscp(data_bytes[0]) 460*cfb92d14SAndroid Build Coastguard Worker ecn = self._unpack_ecn(data_bytes[0]) 461*cfb92d14SAndroid Build Coastguard Worker 462*cfb92d14SAndroid Build Coastguard Worker traffic_class = self._traffic_class(dscp, ecn) 463*cfb92d14SAndroid Build Coastguard Worker flow_label = self._flow_label(data_bytes[1:]) 464*cfb92d14SAndroid Build Coastguard Worker 465*cfb92d14SAndroid Build Coastguard Worker return traffic_class, flow_label 466*cfb92d14SAndroid Build Coastguard Worker 467*cfb92d14SAndroid Build Coastguard Worker def _decompress_tf_3bytes(self, data): 468*cfb92d14SAndroid Build Coastguard Worker data_bytes = [b for b in bytearray(data.read(3))] 469*cfb92d14SAndroid Build Coastguard Worker 470*cfb92d14SAndroid Build Coastguard Worker ecn = self._unpack_ecn(data_bytes[0]) 471*cfb92d14SAndroid Build Coastguard Worker 472*cfb92d14SAndroid Build Coastguard Worker traffic_class = self._traffic_class(dscp=0, ecn=ecn) 473*cfb92d14SAndroid Build Coastguard Worker flow_label = self._flow_label(data_bytes) 474*cfb92d14SAndroid Build Coastguard Worker 475*cfb92d14SAndroid Build Coastguard Worker return traffic_class, flow_label 476*cfb92d14SAndroid Build Coastguard Worker 477*cfb92d14SAndroid Build Coastguard Worker def _decompress_tf_1byte(self, data): 478*cfb92d14SAndroid Build Coastguard Worker data_byte = ord(data.read(1)) 479*cfb92d14SAndroid Build Coastguard Worker 480*cfb92d14SAndroid Build Coastguard Worker dscp = self._unpack_dscp(data_byte) 481*cfb92d14SAndroid Build Coastguard Worker ecn = self._unpack_ecn(data_byte) 482*cfb92d14SAndroid Build Coastguard Worker 483*cfb92d14SAndroid Build Coastguard Worker traffic_class = self._traffic_class(dscp, ecn) 484*cfb92d14SAndroid Build Coastguard Worker flow_label = 0 485*cfb92d14SAndroid Build Coastguard Worker 486*cfb92d14SAndroid Build Coastguard Worker return traffic_class, flow_label 487*cfb92d14SAndroid Build Coastguard Worker 488*cfb92d14SAndroid Build Coastguard Worker def _decompress_tf(self, iphc, data): 489*cfb92d14SAndroid Build Coastguard Worker if iphc.tf == self.IPHC_TF_4B: 490*cfb92d14SAndroid Build Coastguard Worker return self._decompress_tf_4bytes(data) 491*cfb92d14SAndroid Build Coastguard Worker 492*cfb92d14SAndroid Build Coastguard Worker elif iphc.tf == self.IPHC_TF_3B: 493*cfb92d14SAndroid Build Coastguard Worker return self._decompress_tf_3bytes(data) 494*cfb92d14SAndroid Build Coastguard Worker 495*cfb92d14SAndroid Build Coastguard Worker elif iphc.tf == self.IPHC_TF_1B: 496*cfb92d14SAndroid Build Coastguard Worker return self._decompress_tf_1byte(data) 497*cfb92d14SAndroid Build Coastguard Worker 498*cfb92d14SAndroid Build Coastguard Worker elif iphc.tf == self.IPHC_TF_ELIDED: 499*cfb92d14SAndroid Build Coastguard Worker return 0, 0 500*cfb92d14SAndroid Build Coastguard Worker 501*cfb92d14SAndroid Build Coastguard Worker def _decompress_nh(self, hc, data): 502*cfb92d14SAndroid Build Coastguard Worker if hc.nh == self.IPHC_NH_INLINE: 503*cfb92d14SAndroid Build Coastguard Worker return ord(data.read(1)) 504*cfb92d14SAndroid Build Coastguard Worker 505*cfb92d14SAndroid Build Coastguard Worker elif hc.nh == self.IPHC_NH_COMPRESSED: 506*cfb92d14SAndroid Build Coastguard Worker return None 507*cfb92d14SAndroid Build Coastguard Worker 508*cfb92d14SAndroid Build Coastguard Worker def _decompress_hlim(self, iphc, data): 509*cfb92d14SAndroid Build Coastguard Worker if iphc.hlim == self.IPHC_HLIM_INLINE: 510*cfb92d14SAndroid Build Coastguard Worker return ord(data.read(1)) 511*cfb92d14SAndroid Build Coastguard Worker 512*cfb92d14SAndroid Build Coastguard Worker elif iphc.hlim == self.IPHC_HLIM_1: 513*cfb92d14SAndroid Build Coastguard Worker return 1 514*cfb92d14SAndroid Build Coastguard Worker 515*cfb92d14SAndroid Build Coastguard Worker elif iphc.hlim == self.IPHC_HLIM_64: 516*cfb92d14SAndroid Build Coastguard Worker return 64 517*cfb92d14SAndroid Build Coastguard Worker 518*cfb92d14SAndroid Build Coastguard Worker elif iphc.hlim == self.IPHC_HLIM_255: 519*cfb92d14SAndroid Build Coastguard Worker return 255 520*cfb92d14SAndroid Build Coastguard Worker 521*cfb92d14SAndroid Build Coastguard Worker def _decompress_cid(self, iphc, data): 522*cfb92d14SAndroid Build Coastguard Worker if iphc.cid == self.IPHC_CID_SET: 523*cfb92d14SAndroid Build Coastguard Worker cid = ord(data.read(1)) 524*cfb92d14SAndroid Build Coastguard Worker 525*cfb92d14SAndroid Build Coastguard Worker sci = (cid >> 4) & 0x0F 526*cfb92d14SAndroid Build Coastguard Worker dci = cid & 0x0F 527*cfb92d14SAndroid Build Coastguard Worker 528*cfb92d14SAndroid Build Coastguard Worker return sci, dci 529*cfb92d14SAndroid Build Coastguard Worker 530*cfb92d14SAndroid Build Coastguard Worker elif iphc.cid == self.IPHC_CID_CLEAR: 531*cfb92d14SAndroid Build Coastguard Worker return 0, 0 532*cfb92d14SAndroid Build Coastguard Worker 533*cfb92d14SAndroid Build Coastguard Worker def _decompress_src_addr_stateless(self, iphc, src_mac_addr, data): 534*cfb92d14SAndroid Build Coastguard Worker if iphc.sam == self.IPHC_SAM_128B: 535*cfb92d14SAndroid Build Coastguard Worker return bytearray(data.read(16)) 536*cfb92d14SAndroid Build Coastguard Worker 537*cfb92d14SAndroid Build Coastguard Worker elif iphc.sam == self.IPHC_SAM_64B: 538*cfb92d14SAndroid Build Coastguard Worker return self.IPV6_LINKLOCAL_PREFIX + bytearray(data.read(8)) 539*cfb92d14SAndroid Build Coastguard Worker 540*cfb92d14SAndroid Build Coastguard Worker elif iphc.sam == self.IPHC_SAM_16B: 541*cfb92d14SAndroid Build Coastguard Worker return (self.IPV6_LINKLOCAL_PREFIX + self.SHORT_ADDR_PADDING_BYTES + bytearray(data.read(2))) 542*cfb92d14SAndroid Build Coastguard Worker 543*cfb92d14SAndroid Build Coastguard Worker elif iphc.sam == self.IPHC_SAM_ELIDED: 544*cfb92d14SAndroid Build Coastguard Worker return self.IPV6_LINKLOCAL_PREFIX + src_mac_addr.convert_to_iid() 545*cfb92d14SAndroid Build Coastguard Worker 546*cfb92d14SAndroid Build Coastguard Worker def _merge_prefix_with_address(self, prefix, prefix_length, address_bytes): 547*cfb92d14SAndroid Build Coastguard Worker required_bytes = 16 548*cfb92d14SAndroid Build Coastguard Worker 549*cfb92d14SAndroid Build Coastguard Worker prefix_length_full_bytes = int(prefix_length / 8) 550*cfb92d14SAndroid Build Coastguard Worker prefix_length_rest_bits = int(prefix_length % 8) 551*cfb92d14SAndroid Build Coastguard Worker 552*cfb92d14SAndroid Build Coastguard Worker prefix_length_all_bytes = prefix_length_full_bytes 553*cfb92d14SAndroid Build Coastguard Worker 554*cfb92d14SAndroid Build Coastguard Worker if prefix_length_rest_bits > 0: 555*cfb92d14SAndroid Build Coastguard Worker prefix_length_all_bytes += 1 556*cfb92d14SAndroid Build Coastguard Worker 557*cfb92d14SAndroid Build Coastguard Worker # Case in which some bytes overlap 558*cfb92d14SAndroid Build Coastguard Worker if (prefix_length_all_bytes + len(address_bytes)) > required_bytes: 559*cfb92d14SAndroid Build Coastguard Worker ################################################################### 560*cfb92d14SAndroid Build Coastguard Worker # Example: 561*cfb92d14SAndroid Build Coastguard Worker # 562*cfb92d14SAndroid Build Coastguard Worker # Total address length: 128 bits 563*cfb92d14SAndroid Build Coastguard Worker # * prefix length: 68 bits 564*cfb92d14SAndroid Build Coastguard Worker # * address length: 64 bits 565*cfb92d14SAndroid Build Coastguard Worker # 566*cfb92d14SAndroid Build Coastguard Worker # overlap: 4 bits ==> the last 4 bits of the address must be replaced by the last 4 bits of prefix 567*cfb92d14SAndroid Build Coastguard Worker # 568*cfb92d14SAndroid Build Coastguard Worker # Result: 569*cfb92d14SAndroid Build Coastguard Worker # +--------------------+---------------------+ 570*cfb92d14SAndroid Build Coastguard Worker # | prefix (68 bits) | address (64 bits) | 571*cfb92d14SAndroid Build Coastguard Worker # +--------------------+---------------------+ 572*cfb92d14SAndroid Build Coastguard Worker ################################################################### 573*cfb92d14SAndroid Build Coastguard Worker 574*cfb92d14SAndroid Build Coastguard Worker src_addr = prefix[:prefix_length_full_bytes] 575*cfb92d14SAndroid Build Coastguard Worker required_bytes -= prefix_length_full_bytes 576*cfb92d14SAndroid Build Coastguard Worker 577*cfb92d14SAndroid Build Coastguard Worker if prefix_length_rest_bits > 0: 578*cfb92d14SAndroid Build Coastguard Worker prefix_overlapping_byte = prefix[prefix_length_all_bytes - 1] 579*cfb92d14SAndroid Build Coastguard Worker address_overlapping_byte = address_bytes[-required_bytes] 580*cfb92d14SAndroid Build Coastguard Worker 581*cfb92d14SAndroid Build Coastguard Worker overlapping_byte = prefix_overlapping_byte & ~(0xff >> prefix_length_rest_bits) 582*cfb92d14SAndroid Build Coastguard Worker overlapping_byte |= address_overlapping_byte & (0xff >> prefix_length_rest_bits) 583*cfb92d14SAndroid Build Coastguard Worker 584*cfb92d14SAndroid Build Coastguard Worker src_addr += bytearray([overlapping_byte]) 585*cfb92d14SAndroid Build Coastguard Worker required_bytes -= 1 586*cfb92d14SAndroid Build Coastguard Worker 587*cfb92d14SAndroid Build Coastguard Worker if required_bytes > 0: 588*cfb92d14SAndroid Build Coastguard Worker src_addr += address_bytes[-required_bytes:] 589*cfb92d14SAndroid Build Coastguard Worker 590*cfb92d14SAndroid Build Coastguard Worker else: 591*cfb92d14SAndroid Build Coastguard Worker required_bytes -= prefix_length_all_bytes 592*cfb92d14SAndroid Build Coastguard Worker required_bytes -= len(address_bytes) 593*cfb92d14SAndroid Build Coastguard Worker 594*cfb92d14SAndroid Build Coastguard Worker src_addr = (prefix[:prefix_length_all_bytes] + bytearray([0x00] * required_bytes) + address_bytes) 595*cfb92d14SAndroid Build Coastguard Worker 596*cfb92d14SAndroid Build Coastguard Worker return src_addr 597*cfb92d14SAndroid Build Coastguard Worker 598*cfb92d14SAndroid Build Coastguard Worker def _decompress_src_addr_stateful(self, iphc, src_mac_addr, sci, data): 599*cfb92d14SAndroid Build Coastguard Worker if iphc.sam == self.IPHC_SAM_UNSPECIFIED: 600*cfb92d14SAndroid Build Coastguard Worker return bytearray([0x00] * 16) 601*cfb92d14SAndroid Build Coastguard Worker 602*cfb92d14SAndroid Build Coastguard Worker elif iphc.sam == self.IPHC_SAM_64B: 603*cfb92d14SAndroid Build Coastguard Worker context = self._context_manager[sci] 604*cfb92d14SAndroid Build Coastguard Worker 605*cfb92d14SAndroid Build Coastguard Worker return self._merge_prefix_with_address( 606*cfb92d14SAndroid Build Coastguard Worker prefix=context.prefix, 607*cfb92d14SAndroid Build Coastguard Worker prefix_length=context.prefix_length, 608*cfb92d14SAndroid Build Coastguard Worker address_bytes=bytearray(data.read(8)), 609*cfb92d14SAndroid Build Coastguard Worker ) 610*cfb92d14SAndroid Build Coastguard Worker 611*cfb92d14SAndroid Build Coastguard Worker elif iphc.sam == self.IPHC_SAM_16B: 612*cfb92d14SAndroid Build Coastguard Worker context = self._context_manager[sci] 613*cfb92d14SAndroid Build Coastguard Worker address_bytes = self.SHORT_ADDR_PADDING_BYTES + bytearray(data.read(2)) 614*cfb92d14SAndroid Build Coastguard Worker 615*cfb92d14SAndroid Build Coastguard Worker return self._merge_prefix_with_address( 616*cfb92d14SAndroid Build Coastguard Worker prefix=context.prefix, 617*cfb92d14SAndroid Build Coastguard Worker prefix_length=context.prefix_length, 618*cfb92d14SAndroid Build Coastguard Worker address_bytes=address_bytes, 619*cfb92d14SAndroid Build Coastguard Worker ) 620*cfb92d14SAndroid Build Coastguard Worker 621*cfb92d14SAndroid Build Coastguard Worker elif iphc.sam == self.IPHC_SAM_0B: 622*cfb92d14SAndroid Build Coastguard Worker context = self._context_manager[sci] 623*cfb92d14SAndroid Build Coastguard Worker 624*cfb92d14SAndroid Build Coastguard Worker return self._merge_prefix_with_address( 625*cfb92d14SAndroid Build Coastguard Worker prefix=context.prefix, 626*cfb92d14SAndroid Build Coastguard Worker prefix_length=context.prefix_length, 627*cfb92d14SAndroid Build Coastguard Worker address_bytes=src_mac_addr.convert_to_iid(), 628*cfb92d14SAndroid Build Coastguard Worker ) 629*cfb92d14SAndroid Build Coastguard Worker 630*cfb92d14SAndroid Build Coastguard Worker def _decompress_src_addr(self, iphc, src_mac_addr, sci, data): 631*cfb92d14SAndroid Build Coastguard Worker if iphc.sac == self.IPHC_SAC_STATELESS: 632*cfb92d14SAndroid Build Coastguard Worker return self._decompress_src_addr_stateless(iphc, src_mac_addr, data) 633*cfb92d14SAndroid Build Coastguard Worker 634*cfb92d14SAndroid Build Coastguard Worker elif iphc.sac == self.IPHC_SAC_STATEFUL: 635*cfb92d14SAndroid Build Coastguard Worker return self._decompress_src_addr_stateful(iphc, src_mac_addr, sci, data) 636*cfb92d14SAndroid Build Coastguard Worker 637*cfb92d14SAndroid Build Coastguard Worker def _decompress_unicast_dst_addr_stateless(self, iphc, dst_mac_addr, data): 638*cfb92d14SAndroid Build Coastguard Worker if iphc.dam == self.IPHC_DAM_128B: 639*cfb92d14SAndroid Build Coastguard Worker return bytearray(data.read(16)) 640*cfb92d14SAndroid Build Coastguard Worker 641*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_DAM_64B: 642*cfb92d14SAndroid Build Coastguard Worker return self.IPV6_LINKLOCAL_PREFIX + bytearray(data.read(8)) 643*cfb92d14SAndroid Build Coastguard Worker 644*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_DAM_16B: 645*cfb92d14SAndroid Build Coastguard Worker return (self.IPV6_LINKLOCAL_PREFIX + self.SHORT_ADDR_PADDING_BYTES + bytearray(data.read(2))) 646*cfb92d14SAndroid Build Coastguard Worker 647*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_DAM_ELIDED: 648*cfb92d14SAndroid Build Coastguard Worker return self.IPV6_LINKLOCAL_PREFIX + dst_mac_addr.convert_to_iid() 649*cfb92d14SAndroid Build Coastguard Worker 650*cfb92d14SAndroid Build Coastguard Worker def _decompress_unicast_dst_addr_stateful(self, iphc, dst_mac_addr, dci, data): 651*cfb92d14SAndroid Build Coastguard Worker if iphc.dam == self.IPHC_DAM_128B: 652*cfb92d14SAndroid Build Coastguard Worker raise RuntimeError("Reserved") 653*cfb92d14SAndroid Build Coastguard Worker 654*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_DAM_64B: 655*cfb92d14SAndroid Build Coastguard Worker context = self._context_manager[dci] 656*cfb92d14SAndroid Build Coastguard Worker 657*cfb92d14SAndroid Build Coastguard Worker return self._merge_prefix_with_address( 658*cfb92d14SAndroid Build Coastguard Worker prefix=context.prefix, 659*cfb92d14SAndroid Build Coastguard Worker prefix_length=context.prefix_length, 660*cfb92d14SAndroid Build Coastguard Worker address_bytes=bytearray(data.read(8)), 661*cfb92d14SAndroid Build Coastguard Worker ) 662*cfb92d14SAndroid Build Coastguard Worker 663*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_DAM_16B: 664*cfb92d14SAndroid Build Coastguard Worker context = self._context_manager[dci] 665*cfb92d14SAndroid Build Coastguard Worker address_bytes = self.SHORT_ADDR_PADDING_BYTES + bytearray(data.read(2)) 666*cfb92d14SAndroid Build Coastguard Worker 667*cfb92d14SAndroid Build Coastguard Worker return self._merge_prefix_with_address( 668*cfb92d14SAndroid Build Coastguard Worker prefix=context.prefix, 669*cfb92d14SAndroid Build Coastguard Worker prefix_length=context.prefix_length, 670*cfb92d14SAndroid Build Coastguard Worker address_bytes=address_bytes, 671*cfb92d14SAndroid Build Coastguard Worker ) 672*cfb92d14SAndroid Build Coastguard Worker 673*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_DAM_0B: 674*cfb92d14SAndroid Build Coastguard Worker context = self._context_manager[dci] 675*cfb92d14SAndroid Build Coastguard Worker 676*cfb92d14SAndroid Build Coastguard Worker return self._merge_prefix_with_address( 677*cfb92d14SAndroid Build Coastguard Worker prefix=context.prefix, 678*cfb92d14SAndroid Build Coastguard Worker prefix_length=context.prefix_length, 679*cfb92d14SAndroid Build Coastguard Worker address_bytes=dst_mac_addr.convert_to_iid(), 680*cfb92d14SAndroid Build Coastguard Worker ) 681*cfb92d14SAndroid Build Coastguard Worker 682*cfb92d14SAndroid Build Coastguard Worker def _decompress_unicast_dst_addr(self, iphc, dst_mac_addr, dci, data): 683*cfb92d14SAndroid Build Coastguard Worker if iphc.dac == self.IPHC_DAC_STATELESS: 684*cfb92d14SAndroid Build Coastguard Worker return self._decompress_unicast_dst_addr_stateless(iphc, dst_mac_addr, data) 685*cfb92d14SAndroid Build Coastguard Worker 686*cfb92d14SAndroid Build Coastguard Worker elif iphc.dac == self.IPHC_DAC_STATEFUL: 687*cfb92d14SAndroid Build Coastguard Worker return self._decompress_unicast_dst_addr_stateful(iphc, dst_mac_addr, dci, data) 688*cfb92d14SAndroid Build Coastguard Worker 689*cfb92d14SAndroid Build Coastguard Worker def _decompress_multicast_dst_addr_stateless(self, iphc, data): 690*cfb92d14SAndroid Build Coastguard Worker if iphc.dam == self.IPHC_DAM_128B: 691*cfb92d14SAndroid Build Coastguard Worker return bytearray(data.read(16)) 692*cfb92d14SAndroid Build Coastguard Worker 693*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_DAM_48B: 694*cfb92d14SAndroid Build Coastguard Worker addr48b = bytearray(data.read(6)) 695*cfb92d14SAndroid Build Coastguard Worker return (bytearray([0xff, addr48b[0]]) + bytearray([0x00] * 9) + addr48b[1:]) 696*cfb92d14SAndroid Build Coastguard Worker 697*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_DAM_32B: 698*cfb92d14SAndroid Build Coastguard Worker addr32b = bytearray(data.read(4)) 699*cfb92d14SAndroid Build Coastguard Worker return (bytearray([0xff, addr32b[0]]) + bytearray([0x00] * 11) + addr32b[1:]) 700*cfb92d14SAndroid Build Coastguard Worker 701*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_DAM_8B: 702*cfb92d14SAndroid Build Coastguard Worker return (bytearray([0xff, 0x02]) + bytearray([0x00] * 13) + data.read(1)) 703*cfb92d14SAndroid Build Coastguard Worker 704*cfb92d14SAndroid Build Coastguard Worker def _decompress_multicast_dst_addr_stateful(self, iphc, dci, data): 705*cfb92d14SAndroid Build Coastguard Worker if iphc.dam == self.IPHC_M_DAM_00: 706*cfb92d14SAndroid Build Coastguard Worker context = self._context_manager[dci] 707*cfb92d14SAndroid Build Coastguard Worker 708*cfb92d14SAndroid Build Coastguard Worker addr48b = bytearray(data.read(6)) 709*cfb92d14SAndroid Build Coastguard Worker 710*cfb92d14SAndroid Build Coastguard Worker p_bytes_count = 8 711*cfb92d14SAndroid Build Coastguard Worker 712*cfb92d14SAndroid Build Coastguard Worker prefix = context.prefix[:p_bytes_count] 713*cfb92d14SAndroid Build Coastguard Worker prefix_length = context.prefix_length 714*cfb92d14SAndroid Build Coastguard Worker 715*cfb92d14SAndroid Build Coastguard Worker missing_bytes = p_bytes_count - len(prefix) 716*cfb92d14SAndroid Build Coastguard Worker 717*cfb92d14SAndroid Build Coastguard Worker if missing_bytes > 0: 718*cfb92d14SAndroid Build Coastguard Worker prefix += bytearray([0x00] * missing_bytes) 719*cfb92d14SAndroid Build Coastguard Worker 720*cfb92d14SAndroid Build Coastguard Worker return (bytearray([0xff]) + addr48b[:2] + bytearray([prefix_length]) + prefix + addr48b[2:]) 721*cfb92d14SAndroid Build Coastguard Worker 722*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_M_DAM_01: 723*cfb92d14SAndroid Build Coastguard Worker raise RuntimeError("Reserved") 724*cfb92d14SAndroid Build Coastguard Worker 725*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_M_DAM_10: 726*cfb92d14SAndroid Build Coastguard Worker raise RuntimeError("Reserved") 727*cfb92d14SAndroid Build Coastguard Worker 728*cfb92d14SAndroid Build Coastguard Worker elif iphc.dam == self.IPHC_M_DAM_11: 729*cfb92d14SAndroid Build Coastguard Worker raise RuntimeError("Reserved") 730*cfb92d14SAndroid Build Coastguard Worker 731*cfb92d14SAndroid Build Coastguard Worker def _decompress_multicast_dst_addr(self, iphc, dci, data): 732*cfb92d14SAndroid Build Coastguard Worker if iphc.dac == self.IPHC_DAC_STATELESS: 733*cfb92d14SAndroid Build Coastguard Worker return self._decompress_multicast_dst_addr_stateless(iphc, data) 734*cfb92d14SAndroid Build Coastguard Worker 735*cfb92d14SAndroid Build Coastguard Worker elif iphc.dac == self.IPHC_DAC_STATEFUL: 736*cfb92d14SAndroid Build Coastguard Worker return self._decompress_multicast_dst_addr_stateful(iphc, dci, data) 737*cfb92d14SAndroid Build Coastguard Worker 738*cfb92d14SAndroid Build Coastguard Worker def _decompress_dst_addr(self, iphc, dst_mac_addr, dci, data): 739*cfb92d14SAndroid Build Coastguard Worker if iphc.m == self.IPHC_M_NO: 740*cfb92d14SAndroid Build Coastguard Worker return self._decompress_unicast_dst_addr(iphc, dst_mac_addr, dci, data) 741*cfb92d14SAndroid Build Coastguard Worker 742*cfb92d14SAndroid Build Coastguard Worker elif iphc.m == self.IPHC_M_YES: 743*cfb92d14SAndroid Build Coastguard Worker return self._decompress_multicast_dst_addr(iphc, dci, data) 744*cfb92d14SAndroid Build Coastguard Worker 745*cfb92d14SAndroid Build Coastguard Worker def set_lowpan_context(self, cid, prefix): 746*cfb92d14SAndroid Build Coastguard Worker self._context_manager[cid] = Context(prefix) 747*cfb92d14SAndroid Build Coastguard Worker 748*cfb92d14SAndroid Build Coastguard Worker def parse(self, data, message_info): 749*cfb92d14SAndroid Build Coastguard Worker iphc = LowpanIPHC.from_bytes(bytearray(data.read(2))) 750*cfb92d14SAndroid Build Coastguard Worker 751*cfb92d14SAndroid Build Coastguard Worker sci, dci = self._decompress_cid(iphc, data) 752*cfb92d14SAndroid Build Coastguard Worker 753*cfb92d14SAndroid Build Coastguard Worker traffic_class, flow_label = self._decompress_tf(iphc, data) 754*cfb92d14SAndroid Build Coastguard Worker 755*cfb92d14SAndroid Build Coastguard Worker next_header = self._decompress_nh(iphc, data) 756*cfb92d14SAndroid Build Coastguard Worker 757*cfb92d14SAndroid Build Coastguard Worker hop_limit = self._decompress_hlim(iphc, data) 758*cfb92d14SAndroid Build Coastguard Worker 759*cfb92d14SAndroid Build Coastguard Worker src_address = self._decompress_src_addr(iphc, message_info.source_mac_address, sci, data) 760*cfb92d14SAndroid Build Coastguard Worker 761*cfb92d14SAndroid Build Coastguard Worker dst_address = self._decompress_dst_addr(iphc, message_info.destination_mac_address, dci, data) 762*cfb92d14SAndroid Build Coastguard Worker 763*cfb92d14SAndroid Build Coastguard Worker header = ipv6.IPv6Header(src_address, dst_address, traffic_class, flow_label, hop_limit) 764*cfb92d14SAndroid Build Coastguard Worker 765*cfb92d14SAndroid Build Coastguard Worker header.next_header = next_header 766*cfb92d14SAndroid Build Coastguard Worker 767*cfb92d14SAndroid Build Coastguard Worker return header 768*cfb92d14SAndroid Build Coastguard Worker 769*cfb92d14SAndroid Build Coastguard Worker 770*cfb92d14SAndroid Build Coastguard Workerclass LowpanDecompressor: 771*cfb92d14SAndroid Build Coastguard Worker """ Class decompressing 6LoWPAN packets. """ 772*cfb92d14SAndroid Build Coastguard Worker 773*cfb92d14SAndroid Build Coastguard Worker def __init__( 774*cfb92d14SAndroid Build Coastguard Worker self, 775*cfb92d14SAndroid Build Coastguard Worker lowpan_ip_header_factory, 776*cfb92d14SAndroid Build Coastguard Worker lowpan_extension_headers_factory, 777*cfb92d14SAndroid Build Coastguard Worker lowpan_udp_header_factory, 778*cfb92d14SAndroid Build Coastguard Worker ): 779*cfb92d14SAndroid Build Coastguard Worker self._lowpan_ip_header_factory = lowpan_ip_header_factory 780*cfb92d14SAndroid Build Coastguard Worker self._lowpan_extension_headers_factory = (lowpan_extension_headers_factory) 781*cfb92d14SAndroid Build Coastguard Worker self._lowpan_udp_header_factory = lowpan_udp_header_factory 782*cfb92d14SAndroid Build Coastguard Worker 783*cfb92d14SAndroid Build Coastguard Worker def _is_ipv6_extension_header(self, header_first_byte): 784*cfb92d14SAndroid Build Coastguard Worker return ((header_first_byte >> 4) & 0x0F) == 0x0E 785*cfb92d14SAndroid Build Coastguard Worker 786*cfb92d14SAndroid Build Coastguard Worker def _is_udp_header(self, header_first_byte): 787*cfb92d14SAndroid Build Coastguard Worker return ((header_first_byte >> 4) & 0x0F) == 0x0F 788*cfb92d14SAndroid Build Coastguard Worker 789*cfb92d14SAndroid Build Coastguard Worker def _peek_n_bytes(self, data, n): 790*cfb92d14SAndroid Build Coastguard Worker read_data = data.read(n) 791*cfb92d14SAndroid Build Coastguard Worker data.seek(-n, io.SEEK_CUR) 792*cfb92d14SAndroid Build Coastguard Worker return read_data 793*cfb92d14SAndroid Build Coastguard Worker 794*cfb92d14SAndroid Build Coastguard Worker def _is_next_header_compressed(self, header): 795*cfb92d14SAndroid Build Coastguard Worker return header.next_header is None 796*cfb92d14SAndroid Build Coastguard Worker 797*cfb92d14SAndroid Build Coastguard Worker def set_lowpan_context(self, cid, prefix): 798*cfb92d14SAndroid Build Coastguard Worker self._lowpan_ip_header_factory.set_lowpan_context(cid, prefix) 799*cfb92d14SAndroid Build Coastguard Worker 800*cfb92d14SAndroid Build Coastguard Worker def decompress(self, data, message_info): 801*cfb92d14SAndroid Build Coastguard Worker ipv6_header = self._lowpan_ip_header_factory.parse(data, message_info) 802*cfb92d14SAndroid Build Coastguard Worker 803*cfb92d14SAndroid Build Coastguard Worker previous_header = ipv6_header 804*cfb92d14SAndroid Build Coastguard Worker 805*cfb92d14SAndroid Build Coastguard Worker extension_headers = [] 806*cfb92d14SAndroid Build Coastguard Worker udp_header = None 807*cfb92d14SAndroid Build Coastguard Worker 808*cfb92d14SAndroid Build Coastguard Worker if self._is_next_header_compressed(ipv6_header): 809*cfb92d14SAndroid Build Coastguard Worker 810*cfb92d14SAndroid Build Coastguard Worker while data.tell() < len(data.getvalue()): 811*cfb92d14SAndroid Build Coastguard Worker header_first_byte = ord(self._peek_n_bytes(data, 1)) 812*cfb92d14SAndroid Build Coastguard Worker 813*cfb92d14SAndroid Build Coastguard Worker if self._is_ipv6_extension_header(header_first_byte): 814*cfb92d14SAndroid Build Coastguard Worker extension_header = self._lowpan_extension_headers_factory.parse(data, message_info) 815*cfb92d14SAndroid Build Coastguard Worker extension_headers.append(extension_header) 816*cfb92d14SAndroid Build Coastguard Worker 817*cfb92d14SAndroid Build Coastguard Worker # Update next header field in the previous header 818*cfb92d14SAndroid Build Coastguard Worker previous_header.next_header = extension_header.type 819*cfb92d14SAndroid Build Coastguard Worker previous_header = extension_header 820*cfb92d14SAndroid Build Coastguard Worker 821*cfb92d14SAndroid Build Coastguard Worker if not self._is_next_header_compressed(extension_header): 822*cfb92d14SAndroid Build Coastguard Worker # There is not more compressed headers 823*cfb92d14SAndroid Build Coastguard Worker break 824*cfb92d14SAndroid Build Coastguard Worker 825*cfb92d14SAndroid Build Coastguard Worker elif self._is_udp_header(header_first_byte): 826*cfb92d14SAndroid Build Coastguard Worker udp_header = self._lowpan_udp_header_factory.parse(data, message_info) 827*cfb92d14SAndroid Build Coastguard Worker 828*cfb92d14SAndroid Build Coastguard Worker # Update next header field in the previous header 829*cfb92d14SAndroid Build Coastguard Worker previous_header.next_header = udp_header.type 830*cfb92d14SAndroid Build Coastguard Worker 831*cfb92d14SAndroid Build Coastguard Worker # There is not more headers after UDP header 832*cfb92d14SAndroid Build Coastguard Worker break 833*cfb92d14SAndroid Build Coastguard Worker 834*cfb92d14SAndroid Build Coastguard Worker return ipv6_header, extension_headers, udp_header 835*cfb92d14SAndroid Build Coastguard Worker 836*cfb92d14SAndroid Build Coastguard Worker 837*cfb92d14SAndroid Build Coastguard Workerclass LowpanMeshHeader(object): 838*cfb92d14SAndroid Build Coastguard Worker """ Class representing 6LoWPAN mesh header (RFC 4944 5.2). """ 839*cfb92d14SAndroid Build Coastguard Worker 840*cfb92d14SAndroid Build Coastguard Worker def __init__(self, hops_left, originator_address, final_destination_address): 841*cfb92d14SAndroid Build Coastguard Worker self._hops_left = hops_left 842*cfb92d14SAndroid Build Coastguard Worker self._originator_address = originator_address 843*cfb92d14SAndroid Build Coastguard Worker self._final_destination_address = final_destination_address 844*cfb92d14SAndroid Build Coastguard Worker 845*cfb92d14SAndroid Build Coastguard Worker @property 846*cfb92d14SAndroid Build Coastguard Worker def hops_left(self): 847*cfb92d14SAndroid Build Coastguard Worker return self._hops_left 848*cfb92d14SAndroid Build Coastguard Worker 849*cfb92d14SAndroid Build Coastguard Worker @property 850*cfb92d14SAndroid Build Coastguard Worker def originator_address(self): 851*cfb92d14SAndroid Build Coastguard Worker return self._originator_address 852*cfb92d14SAndroid Build Coastguard Worker 853*cfb92d14SAndroid Build Coastguard Worker @property 854*cfb92d14SAndroid Build Coastguard Worker def final_destination_address(self): 855*cfb92d14SAndroid Build Coastguard Worker return self._final_destination_address 856*cfb92d14SAndroid Build Coastguard Worker 857*cfb92d14SAndroid Build Coastguard Worker 858*cfb92d14SAndroid Build Coastguard Workerclass LowpanMeshHeaderFactory: 859*cfb92d14SAndroid Build Coastguard Worker 860*cfb92d14SAndroid Build Coastguard Worker def _parse_address(self, data, is_short): 861*cfb92d14SAndroid Build Coastguard Worker if is_short: 862*cfb92d14SAndroid Build Coastguard Worker return common.MacAddress.from_rloc16(bytearray(data.read(2))) 863*cfb92d14SAndroid Build Coastguard Worker else: 864*cfb92d14SAndroid Build Coastguard Worker return common.MacAddress.from_eui64(bytearray(data.read(8))) 865*cfb92d14SAndroid Build Coastguard Worker 866*cfb92d14SAndroid Build Coastguard Worker def parse(self, data, message_info): 867*cfb92d14SAndroid Build Coastguard Worker data_byte = ord(data.read(1)) 868*cfb92d14SAndroid Build Coastguard Worker 869*cfb92d14SAndroid Build Coastguard Worker is_short_originator_address = bool(data_byte & 0x20) 870*cfb92d14SAndroid Build Coastguard Worker is_short_final_destination_address = bool(data_byte & 0x10) 871*cfb92d14SAndroid Build Coastguard Worker 872*cfb92d14SAndroid Build Coastguard Worker if (data_byte & 0x0F) != 0x0F: 873*cfb92d14SAndroid Build Coastguard Worker hops_left = data_byte & 0x0F 874*cfb92d14SAndroid Build Coastguard Worker else: 875*cfb92d14SAndroid Build Coastguard Worker hops_left = ord(data.read(1)) 876*cfb92d14SAndroid Build Coastguard Worker 877*cfb92d14SAndroid Build Coastguard Worker originator_address = self._parse_address(data, is_short_originator_address) 878*cfb92d14SAndroid Build Coastguard Worker final_destination_address = self._parse_address(data, is_short_final_destination_address) 879*cfb92d14SAndroid Build Coastguard Worker 880*cfb92d14SAndroid Build Coastguard Worker return LowpanMeshHeader(hops_left, originator_address, final_destination_address) 881*cfb92d14SAndroid Build Coastguard Worker 882*cfb92d14SAndroid Build Coastguard Worker 883*cfb92d14SAndroid Build Coastguard Workerclass LowpanFragmentationHeader(object): 884*cfb92d14SAndroid Build Coastguard Worker 885*cfb92d14SAndroid Build Coastguard Worker def __init__(self, datagram_size, datagram_tag, datagram_offset=0): 886*cfb92d14SAndroid Build Coastguard Worker self._datagram_size = datagram_size 887*cfb92d14SAndroid Build Coastguard Worker self._datagram_tag = datagram_tag 888*cfb92d14SAndroid Build Coastguard Worker self._datagram_offset = datagram_offset 889*cfb92d14SAndroid Build Coastguard Worker 890*cfb92d14SAndroid Build Coastguard Worker @property 891*cfb92d14SAndroid Build Coastguard Worker def datagram_size(self): 892*cfb92d14SAndroid Build Coastguard Worker return self._datagram_size 893*cfb92d14SAndroid Build Coastguard Worker 894*cfb92d14SAndroid Build Coastguard Worker @property 895*cfb92d14SAndroid Build Coastguard Worker def datagram_tag(self): 896*cfb92d14SAndroid Build Coastguard Worker return self._datagram_tag 897*cfb92d14SAndroid Build Coastguard Worker 898*cfb92d14SAndroid Build Coastguard Worker @property 899*cfb92d14SAndroid Build Coastguard Worker def datagram_offset(self): 900*cfb92d14SAndroid Build Coastguard Worker return self._datagram_offset 901*cfb92d14SAndroid Build Coastguard Worker 902*cfb92d14SAndroid Build Coastguard Worker @property 903*cfb92d14SAndroid Build Coastguard Worker def is_first(self): 904*cfb92d14SAndroid Build Coastguard Worker return self.datagram_offset == 0 905*cfb92d14SAndroid Build Coastguard Worker 906*cfb92d14SAndroid Build Coastguard Worker @classmethod 907*cfb92d14SAndroid Build Coastguard Worker def from_bytes(cls, data): 908*cfb92d14SAndroid Build Coastguard Worker datagram_size = struct.unpack(">H", data.read(2))[0] 909*cfb92d14SAndroid Build Coastguard Worker has_offset = ((datagram_size >> 11) & 0x1F) == 0x1C 910*cfb92d14SAndroid Build Coastguard Worker 911*cfb92d14SAndroid Build Coastguard Worker datagram_size &= 0x7FF 912*cfb92d14SAndroid Build Coastguard Worker datagram_tag = struct.unpack(">H", data.read(2))[0] 913*cfb92d14SAndroid Build Coastguard Worker datagram_offset = 0 914*cfb92d14SAndroid Build Coastguard Worker 915*cfb92d14SAndroid Build Coastguard Worker if has_offset: 916*cfb92d14SAndroid Build Coastguard Worker datagram_offset = ord(data.read(1)) 917*cfb92d14SAndroid Build Coastguard Worker 918*cfb92d14SAndroid Build Coastguard Worker return cls(datagram_size, datagram_tag, datagram_offset) 919*cfb92d14SAndroid Build Coastguard Worker 920*cfb92d14SAndroid Build Coastguard Worker 921*cfb92d14SAndroid Build Coastguard Workerclass LowpanFragmentsBuffer(object): 922*cfb92d14SAndroid Build Coastguard Worker 923*cfb92d14SAndroid Build Coastguard Worker def __init__(self, buffer_size): 924*cfb92d14SAndroid Build Coastguard Worker self._buffer = [None] * buffer_size 925*cfb92d14SAndroid Build Coastguard Worker self._position = 0 926*cfb92d14SAndroid Build Coastguard Worker 927*cfb92d14SAndroid Build Coastguard Worker def write(self, data): 928*cfb92d14SAndroid Build Coastguard Worker if (self._position + len(data)) > len(self._buffer): 929*cfb92d14SAndroid Build Coastguard Worker raise ValueError("Write failure. Data length is bigger than the destination buffer length.") 930*cfb92d14SAndroid Build Coastguard Worker 931*cfb92d14SAndroid Build Coastguard Worker for i, byte in enumerate(data): 932*cfb92d14SAndroid Build Coastguard Worker self._buffer[self._position + i] = byte 933*cfb92d14SAndroid Build Coastguard Worker 934*cfb92d14SAndroid Build Coastguard Worker self._position += len(data) 935*cfb92d14SAndroid Build Coastguard Worker return len(data) 936*cfb92d14SAndroid Build Coastguard Worker 937*cfb92d14SAndroid Build Coastguard Worker def seek(self, offset): 938*cfb92d14SAndroid Build Coastguard Worker if offset >= len(self._buffer): 939*cfb92d14SAndroid Build Coastguard Worker raise ValueError("Could not seek current offset. Offset value is bigger than the buffer length.") 940*cfb92d14SAndroid Build Coastguard Worker 941*cfb92d14SAndroid Build Coastguard Worker self._position = offset 942*cfb92d14SAndroid Build Coastguard Worker 943*cfb92d14SAndroid Build Coastguard Worker def tell(self): 944*cfb92d14SAndroid Build Coastguard Worker return self._position 945*cfb92d14SAndroid Build Coastguard Worker 946*cfb92d14SAndroid Build Coastguard Worker def whole_packet_received(self): 947*cfb92d14SAndroid Build Coastguard Worker return all([byte is not None for byte in self._buffer]) 948*cfb92d14SAndroid Build Coastguard Worker 949*cfb92d14SAndroid Build Coastguard Worker def read(self): 950*cfb92d14SAndroid Build Coastguard Worker if not self.whole_packet_received(): 951*cfb92d14SAndroid Build Coastguard Worker raise ValueError("Only a part of the packet has been stored in the buffer.") 952*cfb92d14SAndroid Build Coastguard Worker 953*cfb92d14SAndroid Build Coastguard Worker return bytearray(self._buffer) 954*cfb92d14SAndroid Build Coastguard Worker 955*cfb92d14SAndroid Build Coastguard Worker def __len__(self): 956*cfb92d14SAndroid Build Coastguard Worker return len(self._buffer) 957*cfb92d14SAndroid Build Coastguard Worker 958*cfb92d14SAndroid Build Coastguard Worker 959*cfb92d14SAndroid Build Coastguard Workerclass LowpanFragmentsBuffersManager(object): 960*cfb92d14SAndroid Build Coastguard Worker 961*cfb92d14SAndroid Build Coastguard Worker def __init__(self): 962*cfb92d14SAndroid Build Coastguard Worker self._fragments_buffers = {} 963*cfb92d14SAndroid Build Coastguard Worker 964*cfb92d14SAndroid Build Coastguard Worker def _create_key(self, message_info, datagram_tag): 965*cfb92d14SAndroid Build Coastguard Worker key = (bytes(message_info.source_mac_address.mac_address) + 966*cfb92d14SAndroid Build Coastguard Worker bytes(message_info.destination_mac_address.mac_address) + bytes(datagram_tag)) 967*cfb92d14SAndroid Build Coastguard Worker return key 968*cfb92d14SAndroid Build Coastguard Worker 969*cfb92d14SAndroid Build Coastguard Worker def _allocate_fragments_buffer(self, key, datagram_size): 970*cfb92d14SAndroid Build Coastguard Worker if datagram_size is None or datagram_size < 0: 971*cfb92d14SAndroid Build Coastguard Worker raise ValueError("Could not allocate fragments buffer. Invalid datagram size: {}".format(datagram_size)) 972*cfb92d14SAndroid Build Coastguard Worker 973*cfb92d14SAndroid Build Coastguard Worker fragments_buffer = LowpanFragmentsBuffer(datagram_size) 974*cfb92d14SAndroid Build Coastguard Worker 975*cfb92d14SAndroid Build Coastguard Worker self._fragments_buffers[key] = fragments_buffer 976*cfb92d14SAndroid Build Coastguard Worker return fragments_buffer 977*cfb92d14SAndroid Build Coastguard Worker 978*cfb92d14SAndroid Build Coastguard Worker def get_fragments_buffer(self, message_info, datagram_tag, datagram_size=None): 979*cfb92d14SAndroid Build Coastguard Worker key = self._create_key(message_info, datagram_tag) 980*cfb92d14SAndroid Build Coastguard Worker 981*cfb92d14SAndroid Build Coastguard Worker if key not in self._fragments_buffers: 982*cfb92d14SAndroid Build Coastguard Worker self._allocate_fragments_buffer(key, datagram_size) 983*cfb92d14SAndroid Build Coastguard Worker 984*cfb92d14SAndroid Build Coastguard Worker return self._fragments_buffers[key] 985*cfb92d14SAndroid Build Coastguard Worker 986*cfb92d14SAndroid Build Coastguard Worker def free_fragments_buffer(self, message_info, datagram_tag): 987*cfb92d14SAndroid Build Coastguard Worker key = self._create_key(message_info, datagram_tag) 988*cfb92d14SAndroid Build Coastguard Worker 989*cfb92d14SAndroid Build Coastguard Worker del self._fragments_buffers[key] 990*cfb92d14SAndroid Build Coastguard Worker 991*cfb92d14SAndroid Build Coastguard Worker 992*cfb92d14SAndroid Build Coastguard Workerclass LowpanParser(object): 993*cfb92d14SAndroid Build Coastguard Worker 994*cfb92d14SAndroid Build Coastguard Worker def __init__( 995*cfb92d14SAndroid Build Coastguard Worker self, 996*cfb92d14SAndroid Build Coastguard Worker lowpan_mesh_header_factory, 997*cfb92d14SAndroid Build Coastguard Worker lowpan_decompressor, 998*cfb92d14SAndroid Build Coastguard Worker lowpan_fragements_buffers_manager, 999*cfb92d14SAndroid Build Coastguard Worker ipv6_packet_factory, 1000*cfb92d14SAndroid Build Coastguard Worker ): 1001*cfb92d14SAndroid Build Coastguard Worker self._lowpan_mesh_header_factory = lowpan_mesh_header_factory 1002*cfb92d14SAndroid Build Coastguard Worker self._lowpan_decompressor = lowpan_decompressor 1003*cfb92d14SAndroid Build Coastguard Worker self._lowpan_fragments_buffers_manager = (lowpan_fragements_buffers_manager) 1004*cfb92d14SAndroid Build Coastguard Worker self._ipv6_packet_factory = ipv6_packet_factory 1005*cfb92d14SAndroid Build Coastguard Worker 1006*cfb92d14SAndroid Build Coastguard Worker def _peek_n_bytes(self, data, n): 1007*cfb92d14SAndroid Build Coastguard Worker data_bytes = data.read(n) 1008*cfb92d14SAndroid Build Coastguard Worker data.seek(-n, io.SEEK_CUR) 1009*cfb92d14SAndroid Build Coastguard Worker return data_bytes 1010*cfb92d14SAndroid Build Coastguard Worker 1011*cfb92d14SAndroid Build Coastguard Worker def _is_mesh_header(self, first_byte): 1012*cfb92d14SAndroid Build Coastguard Worker return ((first_byte >> 6) & 0x03) == 0x02 1013*cfb92d14SAndroid Build Coastguard Worker 1014*cfb92d14SAndroid Build Coastguard Worker def _is_first_fragmentation_header(self, first_byte): 1015*cfb92d14SAndroid Build Coastguard Worker return ((first_byte >> 3) & 0x1F) == 0x18 1016*cfb92d14SAndroid Build Coastguard Worker 1017*cfb92d14SAndroid Build Coastguard Worker def _is_subsequent_fragmentation_header(self, first_byte): 1018*cfb92d14SAndroid Build Coastguard Worker return ((first_byte >> 3) & 0x1F) == 0x1C 1019*cfb92d14SAndroid Build Coastguard Worker 1020*cfb92d14SAndroid Build Coastguard Worker def _is_iphc(self, first_byte): 1021*cfb92d14SAndroid Build Coastguard Worker return ((first_byte >> 5) & 0x07) == 0x03 1022*cfb92d14SAndroid Build Coastguard Worker 1023*cfb92d14SAndroid Build Coastguard Worker def _decompress_iphc(self, data, message_info): 1024*cfb92d14SAndroid Build Coastguard Worker return self._lowpan_decompressor.decompress(data, message_info) 1025*cfb92d14SAndroid Build Coastguard Worker 1026*cfb92d14SAndroid Build Coastguard Worker def _handle_first_fragmentation_header(self, data, message_info): 1027*cfb92d14SAndroid Build Coastguard Worker fragmentation_header = LowpanFragmentationHeader.from_bytes(data) 1028*cfb92d14SAndroid Build Coastguard Worker 1029*cfb92d14SAndroid Build Coastguard Worker fragments_buffer = self._lowpan_fragments_buffers_manager.get_fragments_buffer( 1030*cfb92d14SAndroid Build Coastguard Worker message_info, 1031*cfb92d14SAndroid Build Coastguard Worker fragmentation_header.datagram_tag, 1032*cfb92d14SAndroid Build Coastguard Worker fragmentation_header.datagram_size, 1033*cfb92d14SAndroid Build Coastguard Worker ) 1034*cfb92d14SAndroid Build Coastguard Worker 1035*cfb92d14SAndroid Build Coastguard Worker ipv6_header, extension_headers, udp_header = self._decompress_iphc(data, message_info) 1036*cfb92d14SAndroid Build Coastguard Worker 1037*cfb92d14SAndroid Build Coastguard Worker uncompressed_data = data.read() 1038*cfb92d14SAndroid Build Coastguard Worker 1039*cfb92d14SAndroid Build Coastguard Worker # Update payload lengths 1040*cfb92d14SAndroid Build Coastguard Worker ipv6_header.payload_length = fragmentation_header.datagram_size - len(ipv6_header) 1041*cfb92d14SAndroid Build Coastguard Worker 1042*cfb92d14SAndroid Build Coastguard Worker fragments_buffer.seek(0) 1043*cfb92d14SAndroid Build Coastguard Worker fragments_buffer.write(ipv6_header.to_bytes()) 1044*cfb92d14SAndroid Build Coastguard Worker 1045*cfb92d14SAndroid Build Coastguard Worker for extension_header in extension_headers: 1046*cfb92d14SAndroid Build Coastguard Worker fragments_buffer.write(extension_header.to_bytes()) 1047*cfb92d14SAndroid Build Coastguard Worker 1048*cfb92d14SAndroid Build Coastguard Worker if udp_header is not None: 1049*cfb92d14SAndroid Build Coastguard Worker fragments_buffer.write(udp_header.to_bytes()) 1050*cfb92d14SAndroid Build Coastguard Worker 1051*cfb92d14SAndroid Build Coastguard Worker fragments_buffer.write(uncompressed_data) 1052*cfb92d14SAndroid Build Coastguard Worker 1053*cfb92d14SAndroid Build Coastguard Worker if fragments_buffer.whole_packet_received(): 1054*cfb92d14SAndroid Build Coastguard Worker data = io.BytesIO(fragments_buffer.read()) 1055*cfb92d14SAndroid Build Coastguard Worker 1056*cfb92d14SAndroid Build Coastguard Worker self._lowpan_fragments_buffers_manager.free_fragments_buffer(message_info, 1057*cfb92d14SAndroid Build Coastguard Worker fragmentation_header.datagram_tag) 1058*cfb92d14SAndroid Build Coastguard Worker 1059*cfb92d14SAndroid Build Coastguard Worker return self._ipv6_packet_factory.parse(data, message_info) 1060*cfb92d14SAndroid Build Coastguard Worker 1061*cfb92d14SAndroid Build Coastguard Worker return None 1062*cfb92d14SAndroid Build Coastguard Worker 1063*cfb92d14SAndroid Build Coastguard Worker def _handle_subsequent_fragmentation_header(self, data, message_info): 1064*cfb92d14SAndroid Build Coastguard Worker fragmentation_header = LowpanFragmentationHeader.from_bytes(data) 1065*cfb92d14SAndroid Build Coastguard Worker 1066*cfb92d14SAndroid Build Coastguard Worker fragments_buffer = self._lowpan_fragments_buffers_manager.get_fragments_buffer( 1067*cfb92d14SAndroid Build Coastguard Worker message_info, 1068*cfb92d14SAndroid Build Coastguard Worker fragmentation_header.datagram_tag, 1069*cfb92d14SAndroid Build Coastguard Worker fragmentation_header.datagram_size, 1070*cfb92d14SAndroid Build Coastguard Worker ) 1071*cfb92d14SAndroid Build Coastguard Worker 1072*cfb92d14SAndroid Build Coastguard Worker offset = fragmentation_header.datagram_offset * 8 1073*cfb92d14SAndroid Build Coastguard Worker 1074*cfb92d14SAndroid Build Coastguard Worker fragments_buffer.seek(offset) 1075*cfb92d14SAndroid Build Coastguard Worker fragments_buffer.write(data.read()) 1076*cfb92d14SAndroid Build Coastguard Worker 1077*cfb92d14SAndroid Build Coastguard Worker if fragments_buffer.whole_packet_received(): 1078*cfb92d14SAndroid Build Coastguard Worker data = io.BytesIO(fragments_buffer.read()) 1079*cfb92d14SAndroid Build Coastguard Worker 1080*cfb92d14SAndroid Build Coastguard Worker self._lowpan_fragments_buffers_manager.free_fragments_buffer(message_info, 1081*cfb92d14SAndroid Build Coastguard Worker fragmentation_header.datagram_tag) 1082*cfb92d14SAndroid Build Coastguard Worker 1083*cfb92d14SAndroid Build Coastguard Worker return self._ipv6_packet_factory.parse(data, message_info) 1084*cfb92d14SAndroid Build Coastguard Worker 1085*cfb92d14SAndroid Build Coastguard Worker return None 1086*cfb92d14SAndroid Build Coastguard Worker 1087*cfb92d14SAndroid Build Coastguard Worker def _handle_iphc_header(self, data, message_info): 1088*cfb92d14SAndroid Build Coastguard Worker ipv6_header, extension_headers, udp_header = self._decompress_iphc(data, message_info) 1089*cfb92d14SAndroid Build Coastguard Worker 1090*cfb92d14SAndroid Build Coastguard Worker uncompressed_data = data.read() 1091*cfb92d14SAndroid Build Coastguard Worker 1092*cfb92d14SAndroid Build Coastguard Worker decompressed_data = bytearray([]) 1093*cfb92d14SAndroid Build Coastguard Worker 1094*cfb92d14SAndroid Build Coastguard Worker for extension_header in extension_headers: 1095*cfb92d14SAndroid Build Coastguard Worker decompressed_data += extension_header.to_bytes() 1096*cfb92d14SAndroid Build Coastguard Worker 1097*cfb92d14SAndroid Build Coastguard Worker if udp_header is not None: 1098*cfb92d14SAndroid Build Coastguard Worker udp_header.payload_length = len(uncompressed_data) 1099*cfb92d14SAndroid Build Coastguard Worker 1100*cfb92d14SAndroid Build Coastguard Worker decompressed_data += udp_header.to_bytes() 1101*cfb92d14SAndroid Build Coastguard Worker 1102*cfb92d14SAndroid Build Coastguard Worker decompressed_data += uncompressed_data 1103*cfb92d14SAndroid Build Coastguard Worker 1104*cfb92d14SAndroid Build Coastguard Worker ipv6_header.payload_length = len(decompressed_data) 1105*cfb92d14SAndroid Build Coastguard Worker 1106*cfb92d14SAndroid Build Coastguard Worker decompressed_data = ipv6_header.to_bytes() + decompressed_data 1107*cfb92d14SAndroid Build Coastguard Worker 1108*cfb92d14SAndroid Build Coastguard Worker return self._ipv6_packet_factory.parse(io.BytesIO(decompressed_data), message_info) 1109*cfb92d14SAndroid Build Coastguard Worker 1110*cfb92d14SAndroid Build Coastguard Worker def set_lowpan_context(self, cid, prefix): 1111*cfb92d14SAndroid Build Coastguard Worker self._lowpan_decompressor.set_lowpan_context(cid, prefix) 1112*cfb92d14SAndroid Build Coastguard Worker 1113*cfb92d14SAndroid Build Coastguard Worker def parse(self, data, message_info): 1114*cfb92d14SAndroid Build Coastguard Worker 1115*cfb92d14SAndroid Build Coastguard Worker while data.tell() < len(data.getvalue()): 1116*cfb92d14SAndroid Build Coastguard Worker first_byte = ord(self._peek_n_bytes(data, n=1)) 1117*cfb92d14SAndroid Build Coastguard Worker 1118*cfb92d14SAndroid Build Coastguard Worker if self._is_mesh_header(first_byte): 1119*cfb92d14SAndroid Build Coastguard Worker mesh_header = self._lowpan_mesh_header_factory.parse(data, message_info) 1120*cfb92d14SAndroid Build Coastguard Worker 1121*cfb92d14SAndroid Build Coastguard Worker message_info.source_mac_address = (mesh_header.originator_address) 1122*cfb92d14SAndroid Build Coastguard Worker message_info.destination_mac_address = (mesh_header.final_destination_address) 1123*cfb92d14SAndroid Build Coastguard Worker 1124*cfb92d14SAndroid Build Coastguard Worker elif self._is_first_fragmentation_header(first_byte): 1125*cfb92d14SAndroid Build Coastguard Worker return self._handle_first_fragmentation_header(data, message_info) 1126*cfb92d14SAndroid Build Coastguard Worker 1127*cfb92d14SAndroid Build Coastguard Worker elif self._is_subsequent_fragmentation_header(first_byte): 1128*cfb92d14SAndroid Build Coastguard Worker return self._handle_subsequent_fragmentation_header(data, message_info) 1129*cfb92d14SAndroid Build Coastguard Worker 1130*cfb92d14SAndroid Build Coastguard Worker elif self._is_iphc(first_byte): 1131*cfb92d14SAndroid Build Coastguard Worker return self._handle_iphc_header(data, message_info) 1132*cfb92d14SAndroid Build Coastguard Worker 1133*cfb92d14SAndroid Build Coastguard Worker else: 1134*cfb92d14SAndroid Build Coastguard Worker raise RuntimeError("Unsupported header type: 0x{:02x}".format(first_byte)) 1135