xref: /aosp_15_r20/external/openthread/tests/scripts/thread-cert/lowpan.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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