1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*cfb92d14SAndroid Build Coastguard Worker# 3*cfb92d14SAndroid Build Coastguard Worker# Copyright (c) 2019, 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 Workerfrom typing import Tuple, List 30*cfb92d14SAndroid Build Coastguard Worker 31*cfb92d14SAndroid Build Coastguard Workerfrom pktverify.consts import COAP_CODE_POST, COAP_CODE_ACK 32*cfb92d14SAndroid Build Coastguard Workerfrom pktverify.layers import Layer 33*cfb92d14SAndroid Build Coastguard Worker 34*cfb92d14SAndroid Build Coastguard Worker 35*cfb92d14SAndroid Build Coastguard Workerclass CoapTlvParser(object): 36*cfb92d14SAndroid Build Coastguard Worker 37*cfb92d14SAndroid Build Coastguard Worker @staticmethod 38*cfb92d14SAndroid Build Coastguard Worker def parse(t, v: bytearray) -> List[Tuple[str, str]]: 39*cfb92d14SAndroid Build Coastguard Worker assert isinstance(v, bytearray) 40*cfb92d14SAndroid Build Coastguard Worker return [] 41*cfb92d14SAndroid Build Coastguard Worker 42*cfb92d14SAndroid Build Coastguard Worker 43*cfb92d14SAndroid Build Coastguard Workerclass CoapLayer(Layer): 44*cfb92d14SAndroid Build Coastguard Worker """ 45*cfb92d14SAndroid Build Coastguard Worker Represents a COAP layer. 46*cfb92d14SAndroid Build Coastguard Worker """ 47*cfb92d14SAndroid Build Coastguard Worker 48*cfb92d14SAndroid Build Coastguard Worker def __init__(self, packet, layer_name): 49*cfb92d14SAndroid Build Coastguard Worker super().__init__(packet, layer_name) 50*cfb92d14SAndroid Build Coastguard Worker 51*cfb92d14SAndroid Build Coastguard Worker @property 52*cfb92d14SAndroid Build Coastguard Worker def is_post(self) -> bool: 53*cfb92d14SAndroid Build Coastguard Worker """ 54*cfb92d14SAndroid Build Coastguard Worker Returns if the COAP layer is using code POST. 55*cfb92d14SAndroid Build Coastguard Worker """ 56*cfb92d14SAndroid Build Coastguard Worker return self.code == COAP_CODE_POST 57*cfb92d14SAndroid Build Coastguard Worker 58*cfb92d14SAndroid Build Coastguard Worker @property 59*cfb92d14SAndroid Build Coastguard Worker def is_ack(self) -> bool: 60*cfb92d14SAndroid Build Coastguard Worker """ 61*cfb92d14SAndroid Build Coastguard Worker Returns if the COAP layer is using code ACK. 62*cfb92d14SAndroid Build Coastguard Worker """ 63*cfb92d14SAndroid Build Coastguard Worker return self.code == COAP_CODE_ACK 64*cfb92d14SAndroid Build Coastguard Worker 65*cfb92d14SAndroid Build Coastguard Worker def __getattr__(self, name): 66*cfb92d14SAndroid Build Coastguard Worker super_attr = super().__getattr__(name) 67*cfb92d14SAndroid Build Coastguard Worker if name == 'tlv': 68*cfb92d14SAndroid Build Coastguard Worker self._parse_coap_payload() 69*cfb92d14SAndroid Build Coastguard Worker 70*cfb92d14SAndroid Build Coastguard Worker return super_attr 71*cfb92d14SAndroid Build Coastguard Worker 72*cfb92d14SAndroid Build Coastguard Worker def _parse_coap_payload(self): 73*cfb92d14SAndroid Build Coastguard Worker payload = self.payload 74*cfb92d14SAndroid Build Coastguard Worker 75*cfb92d14SAndroid Build Coastguard Worker r = 0 76*cfb92d14SAndroid Build Coastguard Worker while True: 77*cfb92d14SAndroid Build Coastguard Worker t, tvs, r = self._parse_next_tlv(payload, r) 78*cfb92d14SAndroid Build Coastguard Worker if t is None: 79*cfb92d14SAndroid Build Coastguard Worker break 80*cfb92d14SAndroid Build Coastguard Worker 81*cfb92d14SAndroid Build Coastguard Worker self._add_field('coap.tlv.type', hex(t)) 82*cfb92d14SAndroid Build Coastguard Worker for k, v in tvs: 83*cfb92d14SAndroid Build Coastguard Worker assert isinstance(k, str), (t, k, v) 84*cfb92d14SAndroid Build Coastguard Worker assert isinstance(v, str), (t, k, v) 85*cfb92d14SAndroid Build Coastguard Worker self._add_field('coap.tlv.' + k, v) 86*cfb92d14SAndroid Build Coastguard Worker 87*cfb92d14SAndroid Build Coastguard Worker @staticmethod 88*cfb92d14SAndroid Build Coastguard Worker def _parse_next_tlv(payload, read_pos) -> tuple: 89*cfb92d14SAndroid Build Coastguard Worker assert read_pos <= len(payload) 90*cfb92d14SAndroid Build Coastguard Worker if read_pos == len(payload): 91*cfb92d14SAndroid Build Coastguard Worker return None, None, read_pos 92*cfb92d14SAndroid Build Coastguard Worker 93*cfb92d14SAndroid Build Coastguard Worker t = payload[read_pos] 94*cfb92d14SAndroid Build Coastguard Worker len_ = payload[read_pos + 1] 95*cfb92d14SAndroid Build Coastguard Worker assert (len(payload) - read_pos - 2 >= len_) 96*cfb92d14SAndroid Build Coastguard Worker kvs = CoapTlvParser.parse(t, payload[read_pos + 2:read_pos + 2 + len_]) 97*cfb92d14SAndroid Build Coastguard Worker return t, kvs, read_pos + len_ + 2 98