def test_message_field_condition(self) -> None: self.assertEqual(ETHERNET_FRAME.field_condition(INITIAL), TRUE) self.assertEqual( ETHERNET_FRAME.field_condition(Field("TPID")), Equal(Variable("Type_Length_TPID"), Number(33024, 16)), ) self.assertEqual( ETHERNET_FRAME.field_condition(Field("Type_Length")), Or( NotEqual(Variable("Type_Length_TPID"), Number(33024, 16)), Equal(Variable("Type_Length_TPID"), Number(33024, 16)), ), ) self.assertEqual( ETHERNET_FRAME.field_condition(Field("Payload")), Or( And( Or( NotEqual(Variable("Type_Length_TPID"), Number(33024, 16)), Equal(Variable("Type_Length_TPID"), Number(33024, 16)), ), LessEqual(Variable("Type_Length"), Number(1500)), ), And( Or( NotEqual(Variable("Type_Length_TPID"), Number(33024, 16)), Equal(Variable("Type_Length_TPID"), Number(33024, 16)), ), GreaterEqual(Variable("Type_Length"), Number(1536)), ), ), )
def test_aggregate_equal_array_invalid_length() -> None: magic = Field(ID("Magic", Location((3, 5)))) structure = [ Link(INITIAL, magic, length=Number(40, location=Location((19, 17)))), Link( magic, FINAL, condition=NotEqual(Variable("Magic"), Aggregate(Number(1), Number(2)), Location((17, 3))), ), ] types = { Field("Magic"): Array( "P.Arr", ModularInteger("P.Modular", Number(128), location=Location((66, 3)))), } assert_message_model_error( structure, types, r"^" r'<stdin>:17:3: model: error: contradicting condition in "P.M"\n' r'<stdin>:3:5: model: info: on path: "Magic"\n' r'<stdin>:17:3: model: info: unsatisfied "2 [*] Modular\'Length = Magic\'Length"\n' r'<stdin>:66:3: model: info: unsatisfied "Modular\'Length = 7"\n' r'<stdin>:19:17: model: info: unsatisfied "Magic\'Length = 40"', )
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_tlv_message_with_not_operator_exhausting() -> None: message = Message( "TLV::Message_With_Not_Operator_Exhausting", [ Link(INITIAL, Field("Tag")), Link( Field("Tag"), Field("Length"), Not(Not(Not(NotEqual(Variable("Tag"), Variable("Msg_Data"))))), ), Link( Field("Tag"), FINAL, reduce( lambda acc, f: f(acc), [Not, Not] * 16, Not( Or( Not( Not( Equal(Variable("Tag"), Variable("Msg_Data")))), Not(Equal(Variable("Tag"), Variable("Msg_Error"))), )), ), ), Link(Field("Length"), Field("Value"), size=Mul(Variable("Length"), Number(8))), Link(Field("Value"), FINAL), ], { Field("Tag"): TLV_TAG, Field("Length"): TLV_LENGTH, Field("Value"): OPAQUE }, ) with pytest.raises( FatalError, match=re.escape( "failed to simplify complex expression `not (not (not (not " "(not (not (not (not (not (not (not (not (not (not (not (not " "(not (not (not (not (not (not (not (not (not (not (not (not " "(not (not (not (not (not (not (not (Tag = TLV::Msg_Data))\n" " " "or not (Tag = TLV::Msg_Error))))))))))))))))))))))))))))))))))` " "after `16` iterations, best effort: " "`not (not (not (not (not (not (not (not (not (not (not (not (not " "(not (not (not (not (Tag = TLV::Msg_Data\n" " or Tag /= TLV::Msg_Error)))))))))))))))))`"), ): model = PyRFLX(model=Model([TLV_TAG, TLV_LENGTH, message])) pkg = model.package("TLV") msg = pkg.new_message("Message_With_Not_Operator_Exhausting") test_bytes = b"\x01\x00\x04\x00\x00\x00\x00" msg.parse(test_bytes)
def parse_relation(string: str, location: int, tokens: list) -> Relation: if tokens[1] == '<': return Less(tokens[0], tokens[2]) if tokens[1] == '<=': return LessEqual(tokens[0], tokens[2]) if tokens[1] == '=': return Equal(tokens[0], tokens[2]) if tokens[1] == '>=': return GreaterEqual(tokens[0], tokens[2]) if tokens[1] == '>': return Greater(tokens[0], tokens[2]) if tokens[1] == '/=': return NotEqual(tokens[0], tokens[2]) raise ParseFatalException(string, location, 'unexpected relation operator')
def test_aggregate_equal_array_valid_length() -> None: structure = [ Link(INITIAL, Field("Magic"), length=Number(14)), Link( Field("Magic"), FINAL, condition=NotEqual(Variable("Magic"), Aggregate(Number(1), Number(2))), ), ] types = { Field("Magic"): Array("P.Arr", ModularInteger("P.Modular", Number(128))), } Message("P.M", structure, types)
def parse_relation(string: str, location: int, tokens: ParseResults) -> Relation: if tokens[1] == "<": return Less(tokens[0], tokens[2]) if tokens[1] == "<=": return LessEqual(tokens[0], tokens[2]) if tokens[1] == "=": return Equal(tokens[0], tokens[2]) if tokens[1] == ">=": return GreaterEqual(tokens[0], tokens[2]) if tokens[1] == ">": return Greater(tokens[0], tokens[2]) if tokens[1] == "/=": return NotEqual(tokens[0], tokens[2]) raise ParseFatalException(string, location, "unexpected relation operator")
def test_aggregate_inequal_valid_length() -> None: structure = [ Link(INITIAL, Field("Magic"), length=Number(40)), Link( Field("Magic"), FINAL, condition=NotEqual( Variable("Magic"), Aggregate(Number(1), Number(2), Number(3), Number(4), Number(4)), ), ), ] types = { Field("Magic"): Opaque(), } Message("P.M", structure, types)
def test_tlv_message_with_not_operator() -> None: message = Message( "TLV::Message_With_Not_Operator", [ Link(INITIAL, Field("Tag")), Link( Field("Tag"), Field("Length"), Not(Not(Not(NotEqual(Variable("Tag"), Variable("Msg_Data"))))), ), Link( Field("Tag"), FINAL, Not( Not( Not( Or( Not( Not( Equal(Variable("Tag"), Variable("Msg_Data")))), Not( Equal(Variable("Tag"), Variable("Msg_Error"))), )))), ), Link(Field("Length"), Field("Value"), size=Mul(Variable("Length"), Number(8))), Link(Field("Value"), FINAL), ], { Field("Tag"): TLV_TAG, Field("Length"): TLV_LENGTH, Field("Value"): OPAQUE }, ) model = PyRFLX(model=Model([TLV_TAG, TLV_LENGTH, message])) pkg = model.package("TLV") msg = pkg.new_message("Message_With_Not_Operator") test_bytes = b"\x01\x00\x04\x00\x00\x00\x00" msg.parse(test_bytes) assert msg.valid_message assert msg.bytestring == test_bytes
def parse_relation(string: str, location: int, tokens: ParseResults) -> Relation: def locn() -> Location: return Location(tokens[0].location.start, tokens[0].location.source, tokens[2].location.end) if tokens[1] == "<": return Less(tokens[0], tokens[2], locn()) if tokens[1] == "<=": return LessEqual(tokens[0], tokens[2], locn()) if tokens[1] == "=": return Equal(tokens[0], tokens[2], locn()) if tokens[1] == ">=": return GreaterEqual(tokens[0], tokens[2], locn()) if tokens[1] == ">": return Greater(tokens[0], tokens[2], locn()) if tokens[1] == "/=": return NotEqual(tokens[0], tokens[2], locn()) raise ParseFatalException(string, location, "unexpected relation operator")
def test_tlv_valid_enum() -> None: structure = [ Link(INITIAL, Field("L")), Link(Field("L"), Field("T")), Link( Field("T"), Field("V"), length=Mul(Number(8), Variable("L")), condition=And(NotEqual(Variable("T"), Variable("TWO")), LessEqual(Variable("L"), Number(8192))), ), Link(Field("V"), FINAL), ] types = { Field("L"): RANGE_INTEGER, Field("T"): ENUMERATION, Field("V"): Opaque(), } Message("P.M", structure, types)
def test_bin_expr_substituted() -> None: assert_equal( Less(Variable("X"), Number(1)).substituted( lambda x: Variable(f"P_{x}") if isinstance(x, Variable) else x ), Less(Variable("P_X"), Number(1)), ) assert_equal( Sub(Variable("X"), Number(1)).substituted( lambda x: Variable("Y") if x == Sub(Variable("X"), Number(1)) else x ), Variable("Y"), ) assert_equal( NotEqual(Variable("X"), Number(1)).substituted( lambda x: Variable(f"P_{x}") if isinstance(x, Variable) else (Equal(x.left, x.right) if isinstance(x, NotEqual) else x) ), Equal(Variable("P_X"), Number(1)), )
def test_aggregate_inequal_invalid_length() -> None: structure = [ Link(INITIAL, Field("Magic"), length=Number(40)), Link( Field("Magic"), FINAL, condition=NotEqual(Variable("Magic"), Aggregate(Number(1), Number(2))), ), ] types = { Field("Magic"): Opaque(), } assert_message_model_error( structure, types, r"^" r'model: error: contradicting condition in "P.M"\n' r'model: info: on path: "Magic"\n' r'model: info: unsatisfied "2 [*] 8 = Magic\'Length"\n' r'model: info: unsatisfied "Magic\'Length = 40"', )
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 context_predicate(self, message: Message, composite_fields: Sequence[Field]) -> Expr: def valid_predecessors_invariant() -> Expr: return AndThen( *[ If( [ ( Call( "Structural_Valid", [Indexed("Cursors", Name(f.affixed_name))] ), Or( *[ AndThen( Call( "Structural_Valid" if l.source in composite_fields else "Valid", [Indexed("Cursors", Name(l.source.affixed_name))], ), Equal( Selected( Indexed("Cursors", Name(f.affixed_name)), "Predecessor", ), Name(l.source.affixed_name), ), l.condition, ).simplified(self.substitution(message, False)) for l in message.incoming(f) ] ), ) ] ) for f in message.fields if f not in message.direct_successors(INITIAL) ] ) def invalid_successors_invariant() -> Expr: return AndThen( *[ If( [ ( AndThen( *[ Call("Invalid", [Indexed("Cursors", Name(p.affixed_name))]) for p in message.direct_predecessors(f) ] ), Call("Invalid", [Indexed("Cursors", Name(f.affixed_name))]), ) ] ) for f in message.fields if f not in message.direct_successors(INITIAL) ] ) return AndThen( If( [ ( NotEqual(Name(Name("Buffer")), NULL), And( Equal(First(Name("Buffer")), Name(Name("Buffer_First"))), Equal(Last(Name("Buffer")), Name(Name("Buffer_Last"))), ), ) ] ), GreaterEqual( Call(self.types.byte_index, [Name(Name("First"))]), Name(Name("Buffer_First")) ), LessEqual(Call(self.types.byte_index, [Name(Name("Last"))]), Name(Name("Buffer_Last"))), LessEqual(Name(Name("First")), Name(Name("Last"))), LessEqual(Name(Name("Last")), Div(Last(self.types.bit_index), Number(2))), ForAllIn( "F", ValueRange(First("Field"), Last("Field")), If( [ ( Call("Structural_Valid", [Indexed(Name("Cursors"), Name("F"))]), And( GreaterEqual( Selected(Indexed(Name("Cursors"), Name("F")), "First"), Name(Name("First")), ), LessEqual( Selected(Indexed(Name("Cursors"), Name("F")), "Last"), Name(Name("Last")), ), LessEqual( Selected(Indexed(Name("Cursors"), Name("F")), "First"), Add( Selected(Indexed(Name("Cursors"), Name("F")), "Last"), Number(1), ), ), Equal( Selected( Selected(Indexed(Name("Cursors"), Name("F")), "Value"), "Fld", ), Name("F"), ), ), ) ] ), ), valid_predecessors_invariant(), invalid_successors_invariant(), self.message_structure_invariant(message, prefix=False), )
ETHERNET_FRAME = Message( "Ethernet::Frame", [ 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)), ),
ETHERNET_FRAME = Message( "Ethernet.Frame", [ 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")),
def test_not_equal() -> None: assert NotEqual(Number(100), Number(1)).z3expr() == (z3.IntVal(100) != z3.IntVal(1))
def test_not_equal_simplified(self) -> None: self.assertEqual( NotEqual(Value('X'), Add(Number(21), Number(21))).simplified(), NotEqual(Value('X'), Number(42)))
def test_not_equal_simplified() -> None: assert NotEqual(Number(0), Number(1)).simplified() == TRUE assert NotEqual(Number(1), Number(1)).simplified() == FALSE assert NotEqual(Number(2), Number(1)).simplified() == TRUE
def test_not_equal_simplified(self) -> None: self.assertEqual( NotEqual(Variable("X"), Add(Number(21), Number(21))).simplified(), NotEqual(Variable("X"), Number(42)), )
def test_not_equal_neg(self) -> None: self.assertEqual(-NotEqual(Variable("X"), Number(1)), Equal(Variable("X"), Number(1)))
def test_not_equal(self) -> None: self.assertEqual( NotEqual(Number(100), Number(1)).z3expr(), z3.IntVal(100) != z3.IntVal(1))
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 create_internal_functions( self, message: Message, composite_fields: Sequence[Field] ) -> UnitPart: def result(field: Field, message: Message) -> NamedAggregate: aggregate: List[Tuple[str, Expr]] = [("Fld", Name(field.affixed_name))] if field in message.fields and isinstance(message.types[field], Scalar): aggregate.append( ( f"{field.name}_Value", Call( "Extract", [ Slice("Ctx.Buffer.all", Name("Buffer_First"), Name("Buffer_Last")), Name("Offset"), ], ), ) ) return NamedAggregate(*aggregate) return UnitPart( [], [ ExpressionFunctionDeclaration( FunctionSpecification( "Sufficient_Buffer_Length", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")], ), And( NotEqual(Name("Ctx.Buffer"), NULL), LessEqual(Name("Ctx.First"), Div(Last(self.types.bit_index), Number(2))), LessEqual( Call("Field_First", [Name("Ctx"), Name("Fld")]), Div(Last(self.types.bit_index), Number(2)), ), GreaterEqual(Call("Field_Length", [Name("Ctx"), Name("Fld")]), Number(0)), LessEqual( Call("Field_Length", [Name("Ctx"), Name("Fld")]), Div(Last(self.types.bit_length), Number(2)), ), LessEqual( Add( Call("Field_First", [Name("Ctx"), Name("Fld")]), Call("Field_Length", [Name("Ctx"), Name("Fld")]), ), Div(Last(self.types.bit_length), Number(2)), ), LessEqual( Name("Ctx.First"), Call("Field_First", [Name("Ctx"), Name("Fld")]) ), GreaterEqual( Name("Ctx.Last"), Call("Field_Last", [Name("Ctx"), Name("Fld")]) ), ), [ Precondition( And( Call("Has_Buffer", [Name("Ctx")]), Call("Valid_Next", [Name("Ctx"), Name("Fld")]), ) ) ], ), ExpressionFunctionDeclaration( FunctionSpecification( "Composite_Field", "Boolean", [Parameter(["Fld"], "Field")] ), Case( Name("Fld"), [ (Name(f.affixed_name), TRUE if f in composite_fields else FALSE) for f in message.fields ], ), ), SubprogramBody( FunctionSpecification( "Get_Field_Value", "Field_Dependent_Value", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")], ), [ *self.common.field_bit_location_declarations(Name("Fld")), *self.common.field_byte_location_declarations(), ], [ ReturnStatement( Case( Name("Fld"), [ (Name(f.affixed_name), result(f, message)) for f in message.fields ], ) ) ], [ Precondition( AndThen( Call("Has_Buffer", [Name("Ctx")]), Call("Valid_Next", [Name("Ctx"), Name("Fld")]), Call("Sufficient_Buffer_Length", [Name("Ctx"), Name("Fld")]), ) ), Postcondition( Equal(Selected(Result("Get_Field_Value"), "Fld"), Name("Fld")) ), ], ), ], )
def test_not_equal_neg() -> None: assert -NotEqual(Variable("X"), Number(1)) == Equal(Variable("X"), Number(1))
def context_predicate(message: Message, composite_fields: Sequence[Field], prefix: str) -> Expr: def valid_predecessors_invariant() -> Expr: return AndThen( *[ If( [ ( Call( "Structural_Valid", [Indexed(Variable("Cursors"), Variable(f.affixed_name))], ), Or( *[ AndThen( Call( "Structural_Valid" if l.source in composite_fields else "Valid", [ Indexed( Variable("Cursors"), Variable(l.source.affixed_name), ) ], ), Equal( Selected( Indexed( Variable("Cursors"), Variable(f.affixed_name), ), "Predecessor", ), Variable(l.source.affixed_name), ), l.condition.substituted( substitution(message, embedded=True) ), ).simplified() for l in message.incoming(f) ] ), ) ] ) for f in message.fields if f not in message.direct_successors(INITIAL) ] ) def invalid_successors_invariant() -> Expr: return AndThen( *[ If( [ ( AndThen( *[ Call( "Invalid", [Indexed(Variable("Cursors"), Variable(p.affixed_name))], ) for p in message.direct_predecessors(f) ] ), Call( "Invalid", [Indexed(Variable("Cursors"), Variable(f.affixed_name))], ), ) ] ) for f in message.fields if f not in message.direct_successors(INITIAL) ] ) return AndThen( If( [ ( NotEqual(Variable("Buffer"), Variable("null")), And( Equal(First("Buffer"), Variable("Buffer_First")), Equal(Last("Buffer"), Variable("Buffer_Last")), ), ) ] ), public_context_predicate(), ForAllIn( "F", ValueRange(First("Field"), Last("Field")), If( [ ( Call("Structural_Valid", [Indexed(Variable("Cursors"), Variable("F"))]), And( GreaterEqual( Selected(Indexed(Variable("Cursors"), Variable("F")), "First"), Variable("First"), ), LessEqual( Selected(Indexed(Variable("Cursors"), Variable("F")), "Last"), Variable("Last"), ), LessEqual( Selected(Indexed(Variable("Cursors"), Variable("F")), "First"), Add( Selected(Indexed(Variable("Cursors"), Variable("F")), "Last"), Number(1), ), ), Equal( Selected( Selected(Indexed(Variable("Cursors"), Variable("F")), "Value"), "Fld", ), Variable("F"), ), ), ) ] ), ), valid_predecessors_invariant(), invalid_successors_invariant(), message_structure_invariant(message, prefix, embedded=True), )
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 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)