def test_message_incoming(self) -> None: self.assertEqual(ETHERNET_FRAME.incoming(INITIAL), []) self.assertEqual( ETHERNET_FRAME.incoming(Field("Type_Length")), [ Link( Field("Type_Length_TPID"), Field("Type_Length"), NotEqual(Variable("Type_Length_TPID"), Number(0x8100, 16)), first=First("Type_Length_TPID"), ), Link(Field("TCI"), Field("Type_Length")), ], ) self.assertEqual( ETHERNET_FRAME.incoming(FINAL), [ Link( Field("Payload"), FINAL, And( GreaterEqual(Div(Length("Payload"), Number(8)), Number(46)), LessEqual(Div(Length("Payload"), Number(8)), Number(1500)), ), ) ], )
def test_exclusive_with_length_invalid() -> None: f1 = Field(ID("F1", Location((98, 10)))) structure = [ Link(INITIAL, f1, length=Number(32)), Link(f1, FINAL, condition=Equal(Length("F1"), Number(32), Location((10, 2)))), Link(f1, Field("F2"), condition=Equal(Length("F1"), Number(32), Location((12, 4)))), Link(Field("F2"), FINAL), ] types = { Field("F1"): Opaque(), Field("F2"): RANGE_INTEGER, } assert_message_model_error( structure, types, r"^" r'<stdin>:98:10: model: error: conflicting conditions for field "F1"\n' r"<stdin>:10:2: model: info: condition 0 [(]F1 -> Final[)]: F1\'Length = 32\n" r"<stdin>:12:4: model: info: condition 1 [(]F1 -> F2[)]: F1\'Length = 32" r"$", )
def __link_expression(self, link: Link) -> Expr: name = link.target.name return And( *[ Equal(First(name), self.__target_first(link)), Equal(Length(name), self.__target_length(link)), Equal(Last(name), self.__target_last(link)), GreaterEqual(First("Message"), Number(0)), GreaterEqual(Last("Message"), Last(name)), GreaterEqual(Last("Message"), First("Message")), Equal(Length("Message"), Add(Sub(Last("Message"), First("Message")), Number(1))), link.condition, ] )
def test_valid_use_message_length() -> None: structure = [ Link(INITIAL, Field("Verify_Data"), length=Length("Message")), Link(Field("Verify_Data"), FINAL), ] types = {Field("Verify_Data"): Opaque()} Message("P.M", structure, types)
def assign(self, value: str, check: bool = True) -> None: prefixed_value = ( ID(value) if value.startswith(str(self._type.package)) or not self.__imported or self.__builtin else self._type.package * value) if Variable(prefixed_value) not in self.literals: raise KeyError(f"{value} is not a valid enum value") r = (And(*self._type.constraints( "__VALUE__", check, not self.__imported)).substituted( mapping={ **self.literals, **{ Variable("__VALUE__"): self._type.literals[prefixed_value.name] }, **{ Length("__VALUE__"): self._type.size }, }).simplified()) assert r == TRUE self._value = ( str(prefixed_value) if self.__imported and not self.__builtin else str(prefixed_value.name), self._type.literals[prefixed_value.name], )
def enumeration_functions(enum: Enumeration) -> List[Subprogram]: common_precondition = And( Less(Value('Offset'), Number(8)), Equal( Length('Buffer'), Add( Div(Add(Size(enum.base_name), Value('Offset'), Number(-1)), Number(8)), Number(1)))) control_expression = LogCall( f'Convert_To_{enum.base_name} (Buffer, Offset)') validation_expression: Expr if enum.always_valid: validation_expression = Value('True') else: validation_cases: List[Tuple[Expr, Expr]] = [] validation_cases.extend( (value, Value('True')) for value in enum.literals.values()) validation_cases.append((Value('others'), Value('False'))) validation_expression = CaseExpression(control_expression, validation_cases) validation_function = ExpressionFunction( f'Valid_{enum.name}', 'Boolean', [('Buffer', 'Types.Bytes'), ('Offset', 'Natural')], validation_expression, [Precondition(common_precondition)]) function_name = f'Convert_To_{enum.name}' parameters = [('Buffer', 'Types.Bytes'), ('Offset', 'Natural')] precondition = Precondition( And(common_precondition, LogCall(f'Valid_{enum.name} (Buffer, Offset)'))) conversion_cases: List[Tuple[Expr, Expr]] = [] conversion_function: Subprogram if enum.always_valid: conversion_cases.extend((value, Aggregate(Value('True'), Value(key))) for key, value in enum.literals.items()) conversion_cases.append( (Value('others'), Aggregate(Value('False'), Value('Raw')))) conversion_function = Function( function_name, enum.name, parameters, [Declaration('Raw', enum.base_name, control_expression)], [ReturnStatement(CaseExpression(Value('Raw'), conversion_cases))], [precondition]) else: conversion_cases.extend( (value, Value(key)) for key, value in enum.literals.items()) conversion_cases.append( (Value('others'), LogCall(f'Unreachable_{enum.name}'))) conversion_function = ExpressionFunction( function_name, enum.name, parameters, CaseExpression(control_expression, conversion_cases), [precondition]) return [validation_function, conversion_function]
def create_facts(facts: Dict[Attribute, MathExpr], edge: Edge) -> Dict[Attribute, MathExpr]: facts = dict(facts) facts[Length(edge.target.name)] = edge.length.simplified(facts) facts[First(edge.target.name)] = edge.first.simplified(facts) facts[Last(edge.target.name)] = Add(edge.first, edge.length, Number(-1)).simplified(facts) return facts
def parse_attribute(string: str, location: int, tokens: list) -> Attribute: if tokens[2] == 'First': return First(tokens[0]) if tokens[2] == 'Last': return Last(tokens[0]) if tokens[2] == 'Length': return Length(tokens[0]) raise ParseFatalException(string, location, 'unexpected attribute')
def parse_attribute(string: str, location: int, tokens: ParseResults) -> Attribute: if tokens[2] == "First": return First(tokens[0]) if tokens[2] == "Last": return Last(tokens[0]) if tokens[2] == "Length": return Length(tokens[0]) raise ParseFatalException(string, location, "unexpected attribute")
def buffer_constraints(last: MathExpr) -> LogExpr: last = last.simplified() index_constraint = LessEqual(First('Buffer'), Div(Last('Types.Index_Type'), Number(2))) if last != Last('Buffer'): length_constraint = GreaterEqual( Length('Buffer'), Add(last, -First('Buffer'), Number(1))) return And(length_constraint, index_constraint) return index_constraint
def assign(self, value: int, check: bool = True) -> None: if (And(*self._type.constraints("__VALUE__", check)).substituted( mapping={ Variable("__VALUE__"): Number(value), Length("__VALUE__"): self._type.size }).simplified() != TRUE): raise ValueError( f"value {value} not in type range {self._first} .. {self._last}" ) self._value = value
def test_attribute() -> None: assert isinstance(Size("X"), Attribute) assert isinstance(Length("X"), Attribute) assert isinstance(First("X"), Attribute) assert isinstance(Last("X"), Attribute) assert isinstance(Range("X"), Attribute) assert isinstance(Old("X"), Attribute) assert isinstance(Result("X"), Attribute) assert isinstance(Constrained("X"), Attribute) assert First("X") == First(Variable("X")) assert First("X") == First(ID("X")) assert First("X") == First(Variable(ID("X")))
def test_message_invalid_use_of_length_attribute() -> None: structure = [ Link(INITIAL, Field("F1")), Link(Field("F1"), FINAL, Equal(Length("F1"), Number(32), Location((400, 17)))), ] types = {Field("F1"): MODULAR_INTEGER} assert_message_model_error( structure, types, r'^<stdin>:400:17: model: error: invalid use of length attribute for "F1"$', )
def substitution(self, message: Message, prefix: bool = True) -> Mapping[Name, Expr]: def prefixed(name: str) -> Expr: return Selected(Name("Ctx"), name) if prefix else Name(name) first = prefixed("First") last = prefixed("Last") cursors = prefixed("Cursors") return { **{First("Message"): first}, **{Last("Message"): last}, **{ First(f.name): Selected(Indexed(cursors, Name(f.affixed_name)), "First") for f in message.fields }, **{ Last(f.name): Selected(Indexed(cursors, Name(f.affixed_name)), "Last") for f in message.fields }, **{ Length(f.name): Add( Sub( Selected(Indexed(cursors, Name(f.affixed_name)), "Last"), Selected(Indexed(cursors, Name(f.affixed_name)), "First"), ), Number(1), ) for f in message.fields }, **{ Variable(f.name): Call( self.types.bit_length, [Selected(Indexed(cursors, Name(f.affixed_name)), f"Value.{f.name}_Value")], ) for f, t in message.types.items() if not isinstance(t, Enumeration) }, **{ Variable(f.name): Call( self.types.bit_length, [Selected(Indexed(cursors, Name(f.affixed_name)), f"Value.{f.name}_Value")], ) for f, t in message.types.items() if isinstance(t, Enumeration) }, **{ Variable(l): Call(self.types.bit_length, [Call("Convert", [Name(l)])]) for l in itertools.chain.from_iterable( t.literals.keys() for t in message.types.values() if isinstance(t, Enumeration) ) }, }
def test_exclusive_with_length_valid() -> None: structure = [ Link(INITIAL, Field("F1"), length=Number(32)), Link( Field("F1"), FINAL, condition=And(Equal(Length("F1"), Number(32)), Less(Variable("F1"), Number(50))), ), Link( Field("F1"), Field("F2"), condition=And(Equal(Length("F1"), Number(32)), Greater(Variable("F1"), Number(80))), ), Link(Field("F2"), FINAL), ] types = { Field("F1"): Opaque(), Field("F2"): MODULAR_INTEGER, } Message("P.M", structure, types)
def create_ethernet_pdu() -> PDU: uint48 = ModularInteger('UINT48', Pow(Number(2), Number(48))) uint16 = RangeInteger('UINT16', Number(0), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)) payload_array = Array('Payload_Array') initial = InitialNode() destination = Node('Destination', uint48) source = Node('Source', uint48) tpid = Node('TPID', uint16) tci = Node('TCI', uint16) ether_type = Node('EtherType', uint16) payload = Node('Payload', payload_array) initial.edges = [Edge(destination)] destination.edges = [Edge(source)] source.edges = [Edge(tpid)] tpid.edges = [Edge(tci, Equal(Value('TPID'), Number(0x8100))), Edge(ether_type, NotEqual(Value('TPID'), Number(0x8100)), first=First('TPID'))] tci.edges = [Edge(ether_type)] ether_type.edges = [Edge(payload, LessEqual(Value('EtherType'), Number(1500)), Mul(LengthValue('EtherType'), Number(8))), Edge(payload, GreaterEqual(Value('EtherType'), Number(1536)), Sub(Last('Message'), Last('EtherType')))] payload.edges = [Edge(FINAL, And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))))] return PDU('Ethernet.Frame', initial)
def __update_simplified_mapping(self) -> None: field_values: Mapping[Name, Expr] = { **{ Variable(k): v.typeval.expr for k, v in self._fields.items() if isinstance( v.typeval, ScalarValue) and v.set }, **{ Length(k): v.typeval.size for k, v in self._fields.items() if v.set }, **{First(k): v.first for k, v in self._fields.items() if v.set}, **{Last(k): v.last for k, v in self._fields.items() if v.set}, } self._simplified_mapping = {**field_values, **self.__type_literals}
def public_substitution(self, message: Message) -> Mapping[Name, Expr]: return { **{First("Message"): Selected(Name("Ctx"), "First")}, **{Last("Message"): Selected(Name("Ctx"), "Last")}, **{ First(f.name): Call("Field_First", [Name("Ctx"), Name(f.affixed_name)]) for f in message.fields }, **{ Last(f.name): Call("Field_Last", [Name("Ctx"), Name(f.affixed_name)]) for f in message.fields }, **{ Length(f.name): Call("Field_Length", [Name("Ctx"), Name(f.affixed_name)]) for f in message.fields }, **{ Variable(f.name): Call( self.types.bit_length, [Call(f"Get_{f.name}", [Name("Ctx")])] ) for f, t in message.types.items() if not isinstance(t, Enumeration) }, **{ Variable(f.name): Call( self.types.bit_length, [Call("Convert", [Call(f"Get_{f.name}", [Name("Ctx")])])] ) for f, t in message.types.items() if isinstance(t, Enumeration) }, **{ Variable(l): Call(self.types.bit_length, [Call("Convert", [Name(l)])]) for l in itertools.chain.from_iterable( t.literals.keys() for t in message.types.values() if isinstance(t, Enumeration) ) }, }
def __process_pdus(self, pdus: List[PDU]) -> None: seen_types: List[str] = [] for pdu in pdus: if pdu.package not in self.__units: self.__units[pdu.package] = Unit(COMMON_CONTEXT, Package(pdu.package, [], [])) context: List[ContextItem] = [] package = Package(pdu.full_name, [], []) self.__units[pdu.full_name] = Unit(context, package) package.subprograms.extend(contain_functions()) facts: Dict[Attribute, MathExpr] = { First('Message'): Mul(First('Buffer'), Number(8)), Last('Message'): Mul(Last('Buffer'), Number(8)), Length('Message'): Sub(Add(Mul(Last('Buffer'), Number(8)), Number(8)), Mul(First('Buffer'), Number(8))) } fields = pdu.fields(facts, First('Buffer')) self.__pdu_fields[pdu.full_name] = list(fields.keys()) for field in fields.values(): if field.name == 'FINAL': continue if f'{pdu.package}.{field.type.name}' not in seen_types: seen_types.append(f'{pdu.package}.{field.type.name}') self.__create_type(field.type, pdu.package) if isinstance(field.type, Array) and 'Payload' not in field.type.name: with_clause = WithClause( [f'{pdu.package}.{field.type.name}']) if with_clause not in context: context.append(with_clause) for variant_id, variant in field.variants.items(): package.subprograms.append( variant_validation_function(field, variant_id, variant)) package.subprograms.extend( variant_accessor_functions(field, variant_id, variant)) package.subprograms.append(field_validation_function(field)) package.subprograms.extend( field_accessor_functions(field, pdu.package)) package.subprograms.append( message_validation_function( list(fields['FINAL'].variants.values()))) package.subprograms.append( message_length_function(list( fields['FINAL'].variants.values()))) self.__create_unreachable_functions(pdus)
def test_pdu_fields_length_after_payload(self) -> None: int_type = ModularInteger('T', Number(256)) payload_type = Array('Payload_Type') initial = InitialNode() version = Node('Version', int_type) payload = Node('Payload', payload_type) length = Node('Length', int_type) initial.edges = [Edge(version, TRUE)] version.edges = [Edge(payload, length=Value('Length'))] payload.edges = [Edge(length, first=Add(Last('Buffer'), -Length('Length'), Number(1)))] length.edges = [Edge(FINAL)] pdu = PDU('Foo', initial) expected = OrderedDict([ ('Version', Field('Version', int_type, TRUE, { '0': Variant( [], TRUE, { Length('Version'): Number(8), First('Version'): Number(0), Last('Version'): Number(7) }) })), ('Payload', Field('Payload', payload_type, TRUE, { '00': Variant( [('Version', '0')], TRUE, { Length('Version'): Number(8), First('Version'): Number(0), Last('Version'): Number(7), Length('Payload'): Value('Length'), First('Payload'): Number(8), Last('Payload'): Add(Value('Length'), Number(7)) }) })), ('Length', Field('Length', int_type, TRUE, { '000': Variant( [('Version', '0'), ('Payload', '00')], TRUE, { Length('Version'): Number(8), First('Version'): Number(0), Last('Version'): Number(7), Length('Payload'): Value('Length'), First('Payload'): Number(8), Last('Payload'): Add(Value('Length'), Number(7)), Length('Length'): Number(8), First('Length'): Add(Last('Buffer'), Number(-7)), Last('Length'): Last('Buffer') }) })), ('FINAL', Field('FINAL', Null(), TRUE, { '0000': Variant( [('Version', '0'), ('Payload', '00'), ('Length', '000')], TRUE, { Length('Version'): Number(8), First('Version'): Number(0), Last('Version'): Number(7), Length('Payload'): Value('Length'), First('Payload'): Number(8), Last('Payload'): Add(Value('Length'), Number(7)), Length('Length'): Number(8), First('Length'): Add(Last('Buffer'), Number(-7)), Last('Length'): Last('Buffer') }) })) ]) self.assertEqual(pdu.fields(), expected)
def create_ethernet_frame() -> Message: address_type = ModularInteger("Ethernet.Address", Pow(Number(2), Number(48))) type_length_type = RangeInteger("Ethernet.Type_Length", Number(46), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)) tpid_type = RangeInteger("Ethernet.TPID", Number(0x8100, 16), Number(0x8100, 16), Number(16)) tci_type = ModularInteger("Ethernet.TCI", Pow(Number(2), Number(16))) structure = [ Link(INITIAL, Field("Destination")), Link(Field("Destination"), Field("Source")), Link(Field("Source"), Field("Type_Length_TPID")), Link( Field("Type_Length_TPID"), Field("TPID"), Equal(Variable("Type_Length_TPID"), Number(0x8100, 16)), first=First("Type_Length_TPID"), ), Link( Field("Type_Length_TPID"), Field("Type_Length"), NotEqual(Variable("Type_Length_TPID"), Number(0x8100, 16)), first=First("Type_Length_TPID"), ), Link(Field("TPID"), Field("TCI")), Link(Field("TCI"), Field("Type_Length")), Link( Field("Type_Length"), Field("Payload"), LessEqual(Variable("Type_Length"), Number(1500)), Mul(Variable("Type_Length"), Number(8)), ), Link( Field("Type_Length"), Field("Payload"), GreaterEqual(Variable("Type_Length"), Number(1536)), Sub(Last("Message"), Last("Type_Length")), ), Link( Field("Payload"), FINAL, And( GreaterEqual(Div(Length("Payload"), Number(8)), Number(46)), LessEqual(Div(Length("Payload"), Number(8)), Number(1500)), ), ), ] types = { Field("Destination"): address_type, Field("Source"): address_type, Field("Type_Length_TPID"): type_length_type, Field("TPID"): tpid_type, Field("TCI"): tci_type, Field("Type_Length"): type_length_type, Field("Payload"): Payload(), } return Message("Ethernet.Frame", structure, types)
def test_length_z3variables(self) -> None: self.assertEqual(Length("Z").variables(True), [Variable("Z'Length")])
def test_length_z3variables() -> None: assert Length("Z").variables() == [Variable("Z")]
def test_ethernet_spec() -> None: spec = { "Ethernet": Specification( ContextSpec([]), PackageSpec( "Ethernet", [ ModularInteger("__PACKAGE__.Address", Pow(Number(2), Number(48))), RangeInteger( "__PACKAGE__.Type_Length", Number(46), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16), ), RangeInteger( "__PACKAGE__.TPID", Number(0x8100, 16), Number(0x8100, 16), Number(16) ), ModularInteger("__PACKAGE__.TCI", Pow(Number(2), Number(16))), MessageSpec( "__PACKAGE__.Frame", [ Component("Destination", "Address"), Component("Source", "Address"), Component( "Type_Length_TPID", "Type_Length", [ Then( "TPID", First("Type_Length_TPID"), UNDEFINED, Equal(Variable("Type_Length_TPID"), Number(33024, 16)), ), Then( "Type_Length", First("Type_Length_TPID"), UNDEFINED, NotEqual(Variable("Type_Length_TPID"), Number(33024, 16)), ), ], ), Component("TPID", "TPID"), Component("TCI", "TCI"), Component( "Type_Length", "Type_Length", [ Then( "Payload", UNDEFINED, Mul(Variable("Type_Length"), Number(8)), LessEqual(Variable("Type_Length"), Number(1500)), ), Then( "Payload", UNDEFINED, Sub(Last("Message"), Last("Type_Length")), GreaterEqual(Variable("Type_Length"), Number(1536)), ), ], ), Component( "Payload", "Opaque", [ Then( condition=And( GreaterEqual( Div(Length("Payload"), Number(8)), Number(46), ), LessEqual( Div(Length("Payload"), Number(8)), Number(1500), ), ), ) ], ), ], ), ], ), ) } assert_specifications_files([f"{SPECDIR}/ethernet.rflx"], spec)
def substitution_facts( message: Message, embedded: bool = False, public: bool = False, target_type: ID = const.TYPES_U64, ) -> Mapping[Name, Expr]: def prefixed(name: str) -> Expr: return Variable(f"Ctx.{name}") if not embedded else Variable(name) first = prefixed("First") last = prefixed("Last") cursors = prefixed("Cursors") def field_first(field: Field) -> Expr: if public: return Call("Field_First", [Variable("Ctx"), Variable(field.affixed_name)]) return Selected(Indexed(cursors, Variable(field.affixed_name)), "First") def field_last(field: Field) -> Expr: if public: return Call("Field_Last", [Variable("Ctx"), Variable(field.affixed_name)]) return Selected(Indexed(cursors, Variable(field.affixed_name)), "Last") def field_length(field: Field) -> Expr: if public: return Call("Field_Length", [Variable("Ctx"), Variable(field.affixed_name)]) return Add( Sub( Selected(Indexed(cursors, Variable(field.affixed_name)), "Last"), Selected(Indexed(cursors, Variable(field.affixed_name)), "First"), ), Number(1), ) def field_value(field: Field, field_type: Type) -> Expr: if isinstance(field_type, Enumeration): if public: return Call( target_type, [Call("To_Base", [Call(f"Get_{field.name}", [Variable("Ctx")])])], ) return Call( target_type, [ Selected( Indexed(cursors, Variable(field.affixed_name)), f"Value.{field.name}_Value" ) ], ) if isinstance(field_type, Scalar): if public: return Call(target_type, [Call(f"Get_{field.name}", [Variable("Ctx")])]) return Call( target_type, [ Selected( Indexed(cursors, Variable(field.affixed_name)), f"Value.{field.name}_Value" ) ], ) if isinstance(field_type, Composite): return Variable(field.name) assert False, f'unexpected type "{type(field_type).__name__}"' return UNDEFINED return { **{First("Message"): first}, **{Last("Message"): last}, **{Length("Message"): Add(last, -first, Number(1))}, **{First(f.name): field_first(f) for f in message.fields}, **{Last(f.name): field_last(f) for f in message.fields}, **{Length(f.name): field_length(f) for f in message.fields}, **{Variable(f.name): field_value(f, t) for f, t in message.types.items()}, **{ Variable(l): Call(target_type, [Call("To_Base", [Variable(l)])]) for t in message.types.values() if isinstance(t, Enumeration) for l in t.literals.keys() }, **{ Variable(t.package * l): Call(target_type, [Call("To_Base", [Variable(t.package * l)])]) for t in message.types.values() if isinstance(t, Enumeration) for l in t.literals.keys() }, }
Field("Type_Length"), Field("Payload"), LessEqual(Variable("Type_Length"), Number(1500)), Mul(Variable("Type_Length"), Number(8)), ), Link( Field("Type_Length"), Field("Payload"), GreaterEqual(Variable("Type_Length"), Number(1536)), Sub(Last("Message"), Last("Type_Length")), ), Link( Field("Payload"), FINAL, And( GreaterEqual(Div(Length("Payload"), Number(8)), Number(46)), LessEqual(Div(Length("Payload"), Number(8)), Number(1500)), ), ), ], { Field("Destination"): ETHERNET_ADDRESS, Field("Source"): ETHERNET_ADDRESS, Field("Type_Length_TPID"): ETHERNET_TYPE_LENGTH, Field("TPID"): ETHERNET_TPID, Field("TCI"): ETHERNET_TCI, Field("Type_Length"): ETHERNET_TYPE_LENGTH, Field("Payload"): Opaque(), }, ) ETHERNET_MODEL = Model([
def test_pdu_fields_ethernet(self) -> None: expected = OrderedDict([ ('Destination', Field('Destination', ModularInteger('UINT48', Pow(Number(2), Number(48))), TRUE, { '0': Variant( [], TRUE, { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47) }) })), ('Source', Field('Source', ModularInteger('UINT48', Pow(Number(2), Number(48))), TRUE, { '00': Variant( [ ('Destination', '0') ], TRUE, { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95) }) })), ('TPID', Field('TPID', RangeInteger('UINT16', Number(0), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)), Or(NotEqual(Value('TPID'), Number(0x8100)), Equal(Value('TPID'), Number(0x8100))), { '000': Variant( [ ('Destination', '0'), ('Source', '00') ], TRUE, { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111) }) })), ('TCI', Field('TCI', RangeInteger('UINT16', Number(0), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)), TRUE, { '0000': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000') ], Equal(Value('TPID'), Number(0x8100)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127) }) })), ('EtherType', Field('EtherType', RangeInteger('UINT16', Number(0), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)), Or(GreaterEqual(Value('EtherType'), Number(1536)), LessEqual(Value('EtherType'), Number(1500))), { '00000': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000') ], TRUE, { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143) }), '0001': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000') ], NotEqual(Value('TPID'), Number(0x8100)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111) }) })), ('Payload', Field('Payload', Array('Payload_Array'), And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { '000000': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000'), ('EtherType', '00000') ], LessEqual(Value('EtherType'), Number(1500)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143), Length('Payload'): Mul(LengthValue('EtherType'), Number(8)), First('Payload'): Number(144), Last('Payload'): Add(Mul(LengthValue('EtherType'), Number(8)), Number(143)) }), '000001': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000'), ('EtherType', '00000') ], GreaterEqual(Value('EtherType'), Number(1536)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143), Length('Payload'): Add(Last('Message'), Number(-143)), First('Payload'): Number(144), Last('Payload'): Last('Message') }), '00010': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('EtherType', '0001') ], LessEqual(Value('EtherType'), Number(1500)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111), Length('Payload'): Mul(LengthValue('EtherType'), Number(8)), First('Payload'): Number(112), Last('Payload'): Add(Mul(LengthValue('EtherType'), Number(8)), Number(111)) }), '00011': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('EtherType', '0001') ], GreaterEqual(Value('EtherType'), Number(1536)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111), Length('Payload'): Add(Last('Message'), Number(-111)), First('Payload'): Number(112), Last('Payload'): Last('Message') }) })), ('FINAL', Field('FINAL', Null(), TRUE, { '0000000': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000'), ('EtherType', '00000'), ('Payload', '000000') ], And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143), Length('Payload'): Mul(LengthValue('EtherType'), Number(8)), First('Payload'): Number(144), Last('Payload'): Add(Mul(LengthValue('EtherType'), Number(8)), Number(143)) }), '0000010': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000'), ('EtherType', '00000'), ('Payload', '000001') ], And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143), Length('Payload'): Add(Last('Message'), Number(-143)), First('Payload'): Number(144), Last('Payload'): Last('Message') }), '000100': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('EtherType', '0001'), ('Payload', '00010') ], And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111), Length('Payload'): Mul(LengthValue('EtherType'), Number(8)), First('Payload'): Number(112), Last('Payload'): Add(Mul(LengthValue('EtherType'), Number(8)), Number(111)) }), '000110': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('EtherType', '0001'), ('Payload', '00011') ], And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111), Length('Payload'): Add(Last('Message'), Number(-111)), First('Payload'): Number(112), Last('Payload'): Last('Message') }) })) ]) self.assertEqual(ETHERNET_PDU.fields(), expected)
def test_length_simplified(self) -> None: self.assertEqual(Length('X').simplified(), Length('X')) self.assertEqual( Length('X').simplified({Length('X'): Number(42)}), Number(42)) self.assertEqual(-Length('X').simplified({Length('X'): Number(42)}), Number(-42))