def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() # Ensure the topology is formed correctly pv.verify_attached('Router_1', 'BR_1') pv.verify_attached('BR_2') # 1. Router attempts to deregister for multicast address, MA1, at BR_1. # Router unicasts an MLR.req CoAP request to BR_1 as follows: # coap://[<BR_1 RLOC>]:MM/n/mr # Where the payload contains: # IPv6 Addresses TLV: MA1 # Timeout TLV: 0 pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_2dsts(vars['BR_1_RLOC'], PBBR_ALOC) \ .filter_coap_request('/n/mr') \ .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1] and p.thread_nm.tlv.timeout == 0) \ .must_next() # 2. BR_1 responds to the multicast registration successfully, # ignoring the timeout value. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_ipv6_dst(vars['Router_1_RLOC']) \ .filter_coap_ack('/n/mr') \ .filter(lambda p: p.thread_nm.tlv.status == 0) \ .must_next() # 3. Host sends a ping packet to the multicast address, MA1. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request() \ .must_next() # 4. BR_1 forwards the ping packet with multicast address, MA1, to its # Thread Network encapsulated in an MPL packet. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 5. Router receives the MPL packet containing an encapsulated ping # packet to MA1, sent by Host, and unicasts a ping response packet back # to Host. pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() # Ensure the topology is formed correctly pv.verify_attached('Router_1', 'BR_1') # 2. TD automatically detects the Primary BBR change and registers for # multicast address, MA1, at BR_2. # TD unicasts an MLR.req CoAP request as follows: # coap://[<BR_2 RLOC or PBBR ALOC>]:MM/n/mr # Where the payload contains: # IPv6 Addresses TLV: MA1 _pkt = pkts.filter_wpan_src64(vars['TD']) \ .filter_ipv6_2dsts(vars['BR_2_RLOC'], consts.PBBR_ALOC) \ .filter_coap_request('/n/mr') \ .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1]) \ .must_next() # 3. Router_1 forwards the registration request to BR_2. pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_2dsts(vars['BR_2_RLOC'], consts.PBBR_ALOC) \ .filter_coap_request('/n/mr') \ .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1] and p.coap.mid == _pkt.coap.mid) \ .must_next() # 4. BR_2 unicasts an MLR.rsp CoAP response to TD as: 2.04 changed. # Where the payload contains: # Status TLV: ST_MLR_SUCCESS pkts.filter_wpan_src64(vars['BR_2']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_coap_ack('/n/mr') \ .filter(lambda p: p.coap.mid == _pkt.coap.mid and p.thread_nm.tlv.status == 0) \ .must_next() # 5. Router_1 forwards the response to TD. pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_coap_ack('/n/mr') \ .filter(lambda p: p.coap.mid == _pkt.coap.mid and p.thread_nm.tlv.status == 0) \ .must_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): RA_OPT_TYPE_PIO = 3 RA_OPT_TYPE_RIO = 24 pkts = pv.pkts vars = pv.vars pv.summary.show() logging.info(f'vars = {vars}') # Ensure the topology is formed correctly pv.verify_attached('Router', 'BR') # verify that radvd sends RA messages with PIO. radvd_ra = pkts.filter_eth_src(vars['BR_ETH']) \ .filter_icmpv6_nd_ra() \ .filter(lambda p: RA_OPT_TYPE_PIO in p.icmpv6.opt.type) \ .must_next() # Verify that the BR sends RA messages with the same parameters. br_ra = pkts.filter_eth_src(vars['BR_ETH']) \ .filter_icmpv6_nd_ra() \ .filter(lambda p: RA_OPT_TYPE_RIO in p.icmpv6.opt.type) \ .filter(lambda p: p.icmpv6.nd.ra.router_lifetime == radvd_ra.icmpv6.nd.ra.router_lifetime) \ .filter(lambda p: p.icmpv6.nd.ra.retrans_timer == radvd_ra.icmpv6.nd.ra.retrans_timer) \ .filter(lambda p: p.icmpv6.nd.ra.reachable_time == radvd_ra.icmpv6.nd.ra.reachable_time) \ .must_next() # Verify that radvd sends at lease one RA message with zero Router Lifetime # when it is stopped. pkts.filter_eth_src(vars['BR_ETH']) \ .filter_icmpv6_nd_ra() \ .filter(lambda p: RA_OPT_TYPE_PIO in p.icmpv6.opt.type) \ .filter(lambda p: p.icmpv6.nd.ra.router_lifetime == 0) \ .must_next() # Verify that the BR forgets radvd's RA parameters. pkts.filter_eth_src(vars['BR_ETH']) \ .filter_icmpv6_nd_ra() \ .filter(lambda p: RA_OPT_TYPE_RIO in p.icmpv6.opt.type) \ .filter(lambda p: p.icmpv6.nd.ra.router_lifetime == 0) \ .filter(lambda p: p.icmpv6.nd.ra.retrans_timer == 0) \ .filter(lambda p: p.icmpv6.nd.ra.reachable_time == 0) \ .must_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() logging.info(f'vars = {vars}') # Ensure the topology is formed correctly pv.verify_attached('Router_1', 'BR_1') pv.verify_attached('BR_2') # 1. Router_1 sends a ping packet to the multicast address, MA1, # encapsulated in an MPL packet. _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ .filter_ping_request() \ .must_next() initial_identifier = _pkt.icmpv6.echo.identifier # 2. BR_1 forwards the multicast ping packet with multicast address, # MA1, to the LAN. pkts.filter_eth_src(vars['BR_1_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() with pkts.save_index(): pv.verify_attached('Router_1', 'BR_2') # 4b. BR_2 detects the missing Primary BBR and becomes the Leader of the # Thread Network, distributing its BBR dataset. # Verify that Router_1 has received the new BBR Dataset from BR_2, # where: # • RLOC16 in Server TLV == The RLOC16 of BR_2 # All fields in the Service TLV contain valid values. pkts.filter_wpan_src64(vars['BR_2']) \ .filter_mle() \ .filter( lambda p: p.thread_nwd.tlv.server_16 is not nullField and vars['BR_2_RLOC16'] in p.thread_nwd.tlv.server_16) \ .must_next() # 5.Router_1 sends a ping packet to the multicast address, MA1, # encapsulated in an MPL packet. _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ .filter_ping_request() \ .filter(lambda p: p.icmpv6.echo.identifier != initial_identifier) \ .must_next() # 6. BR_2 forwards the multicast ping packet with multicast address, # MA1, to the LAN. pkts.filter_eth_src(vars['BR_2_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() # Ensure the topology is formed correctly pv.verify_attached('Router_1', 'BR_1') pv.verify_attached('BR_2') # 1. Host sends a ping packet to the multicast address, MA1. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request() \ .must_next() # 2. BR_1 forwards the ping packet with multicast address, MA1, to its # Thread Network encapsulated in an MPL packet. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(vars['BR_1_RLOC']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 3. Router_1 receives the MPL packet containing an encapsulated ping # packet to MA1, sent by Host, and unicasts a ping response packet back # to Host. pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 4. After (MLR_TIMEOUT_MIN+2) seconds, BR_1 multicasts an MLDv2 message # of type “Version 2 Multicast Listener Report” (see [RFC 3810] Section # 5.2) # TODO # 5. Host sends a ping packet to the multicast address, MA1. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request() \ .must_next() # 6. BR_1 does not forward the ping packet with multicast address, MA1, # to its Thread Network. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(vars['BR_1_RLOC']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next() # 7. Host sends a ping packet to the multicast address, MA1. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request() \ .must_next() # 8. BR_1 forwards the ping packet with multicast address, MA1, to its # Thread Network encapsulated in an MPL packet. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(vars['BR_1_RLOC']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 9. Router_1 receives the MPL packet containing an encapsulated ping # packet to MA1, sent by Host, and unicasts a ping response packet back # to Host. pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() # Ensure the topology is formed correctly pv.verify_attached('TD', 'BR_1') pv.verify_attached('BR_2') # 1. TD Registers for multicast address, MA1, at BR_1. # TD unicasts an MLR.req CoAP request to BR_1 as # "coap://[<BR_1 RLOC or PBBR ALOC>]:MM/n/mr". # The payload contains "IPv6Address TLV: MA1". pkts.filter_wpan_src64(vars['TD']) \ .filter_ipv6_2dsts(vars['BR_1_RLOC'], PBBR_ALOC) \ .filter_coap_request('/n/mr') \ .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1]) \ .must_next() # 3. BR_1 responds to the multicast registration. # BR_1 unicasts an MLR.rsp CoAP response to TD as "2.04 changed". # The payload contains "Status TLV: ST_MLR_SUCCESS". pkts.copy().filter_wpan_src64(vars['BR_1']) \ .filter_ipv6_dst(vars['TD_RLOC']) \ .filter_coap_ack('/n/mr') \ .filter(lambda p: p.thread_nm.tlv.status == 0) \ .must_next() # 3a. BR_2 does not respond to the multicast registration. pkts.filter_wpan_src64(vars['BR_2']) \ .filter_ipv6_dst(vars['TD_RLOC']) \ .filter_coap_ack('/n/mr') \ .must_not_next() # 4. BR_1 informs other BBRs on the network of multicast registration. # BR_1 multicasts a BMLR.ntf CoAP request to the Backbone Link including # to BR_2, as follows pkts.filter_eth_src(vars['BR_1_ETH']) \ .filter_ipv6_dst(config.ALL_NETWORK_BBRS_ADDRESS) \ .filter_coap_request('/b/bmr') \ .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1] and p.thread_bl.tlv.timeout == MLR_NOTIFICATION_TIMEOUT) \ .must_next() # 6. BR_1 multicasts an MLDv2 message to start listening to MA1. # BR_1 multicasts an MLDv2 message of type “Version 2 Multicast Listener # Report” (see [RFC 3810] Section 5.2). Where: # Nr of Mcast Address at least 1 Records (M): Multicast Address Record # The Multicast Address Record contains the following: # Record Type: 4 (CHANGE_TO_EXCLUDE_MODE) # Number of Sources (N): 0 # Multicast Address: MA1 # TODO: Implement this verification # 7. Host sends a ping packet to the multicast address, MA1. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request() \ .must_next() # 8. BR_2 does not forward the ping packet with multicast address MA1 to # its Thread Network. pkts.filter_wpan_src64(vars['BR_2']) \ .filter_AMPLFMA(mpl_seed_id=(vars['BR_2_RLOC'])) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next() # 9. BR_1 forwards the ping packet to its Thread Network. # BR_1 forwards the ping packet with multicast address, MA1, to its # Thread Network encapsulated in an MPL packet, where: # MPL Seed ID: If Source outer IP header = BR_1 RLOC, SeedID length = 0 # Else, SeedID length = 1, and Seed ID = BR_1 RLOC16 pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=(vars['BR_1_RLOC'])) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 10. TD receives the multicast ping packet and sends a ping response # packet back to Host. # TD receives the MPL packet containing an encapsulated ping packet to # MA1, sent by Host, and unicasts a ping response packet back to Host. pkts.filter_wpan_src64(vars['TD']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 11. Host sends a ping packet to the multicast address, MA2. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA2) \ .filter_ping_request() \ .must_next() # 12. BR_2 does not forward the ping packet with multicast address, MA2, # to the Thread Network in whatever way. pkts.filter_wpan_src64(vars['BR_2']) \ .filter_AMPLFMA(mpl_seed_id=(vars['BR_2_RLOC'])) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next() # 13. BR_1 does not forward the ping packet with multicast address, MA2, # to the Thread Network in whatever way. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=(vars['BR_1_RLOC'])) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next() # 14. Host sends a ping packet to the multicast address, MA1g. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1g) \ .filter_ping_request() \ .must_next() # 15. BR_2 does not forward the ping packet with multicast address MA1g, # to the Thread Network in whatever way. pkts.filter_wpan_src64(vars['BR_2']) \ .filter_AMPLFMA(mpl_seed_id=(vars['BR_2_RLOC'])) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next() # 16. BR_1 does not forward the ping packet with multicast address MA1g, # to its Thread Network in whatever way. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=(vars['BR_1_RLOC'])) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next() # 17. Host sends a ping packet to the BR_2's global unicast address, Gg. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(vars['BR_2_BGUA']) \ .filter_ping_request() \ .must_next() # 18. BR_2 receives and provides the ping response. # BR_2 Must send back the ping response to the Host. pkts.filter_eth_src(vars['BR_2_ETH']) \ .filter_ipv6_dst(vars['Host_BGUA']) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() logging.info(f'vars = {vars}') # Ensure the topology is formed correctly pv.verify_attached('Router_1', 'BR_1') pv.verify_attached('BR_2') # Initial registration # Router_1 registers for multicast address, MA1, at BR_1. # Router_1 unicasts an MLR.req CoAP request to BR_1 as # "coap://[<BR_1 RLOC or PBBR ALOC>]:MM/n/mr". # The payload contains "IPv6Address TLV: MA1". initial_registration_pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_2dsts(vars['BR_1_RLOC'], PBBR_ALOC) \ .filter_coap_request('/n/mr') \ .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1]) \ .must_next() # 1. Host sends a ping packet to the multicast address, MA1. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request() \ .must_next() # 2. BR_1 forwards the ping packet with multicast address, MA1, to its # Thread Network encapsulated in an MPL packet. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 3. Router_1 receives the MPL packet containing an encapsulated ping # packet to MA1, sent by Host, and unicasts a ping response packet back # to Host. pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 3a. Within MLR_TIMEOUT_MIN seconds of initial registration, Router_1 # re-registers for multicast address, MA1, at BR_1. # Router_1 unicasts an MLR.req CoAP request to BR_1 as # "coap://[<BR_1 RLOC or PBBR ALOC>]:MM/n/mr". # The payload contains "IPv6Address TLV: MA1". pkts.copy() \ .filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_2dsts(vars['BR_1_RLOC'], PBBR_ALOC) \ .filter_coap_request('/n/mr') \ .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1] and p.sniff_timestamp <= initial_registration_pkt.sniff_timestamp + consts.MLR_TIMEOUT_MIN) \ .must_next() # 4. Within MLR_TIMEOUT_MIN seconds, Host sends a ping packet to the # multicast address, MA1. The destination port 5683 is used for the UDP # Multicast packet transmission. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter(lambda p: p.udp.length == UDP_HEADER_LENGTH + len('PING') and p.udp.dstport == 5683) \ .must_next() # 5. BR_1 forwards the UDP ping packet with multicast address, MA1, to # its Thread Network encapsulated in an MPL packet. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ .filter(lambda p: p.udp.length == _pkt.udp.length) \ .must_next() # 6. Router_1 receives the ping packet. # Use the port 5683 (CoAP port) to verify that the # UDP Multicast packet is received. pkts.filter_wpan_src64(vars['Router_1']) \ .filter( lambda p: p.udp.length == _pkt.udp.length and p.udp.dstport == 5683) \ .must_next() # 7. After (MLR_TIMEOUT_MIN+2) seconds, Host multicasts a ping packet to # multicast address, MA1, on the backbone link. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request() \ .must_next() # 8. BR_1 does not forward the ping packet with multicast address, MA1, # to its Thread Network. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() # Ensure the topology is formed correctly pv.verify_attached('Router_1', 'BR_1') # Loop steps 1 to 4 with i := 1 to 5. for i in range(1, 6): # 1. Router_1 registers for 15 multicast addresses, MASi. # [Automatic result:] # Unicasts an MLR.req CoAP request to BR_1 as follows: # coap://[<BR_1 RLOC> or <PBBR ALOC>]:MM/n/mr # Where the payload contains: # IPv6 Addresses TLV: MASi (15 addresses) _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_2dsts(vars['BR_1_RLOC'], consts.PBBR_ALOC) \ .filter_coap_request('/n/mr') \ .filter(lambda p: set(p.thread_meshcop.tlv.ipv6_addr) == set(MAS[i][1:])) \ .must_next() # 2. BR_1 Responds to the multicast registration. # BR_1 unicasts an MLR.rsp CoAP response to Router_1 as follows: # 2.04 changed # Where the payload contains: # Status TLV: ST_MLR_SUCCESS pkts.copy().filter_wpan_src64(vars['BR_1']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_coap_ack('/n/mr') \ .filter(lambda p: p.coap.mid == _pkt.coap.mid and p.thread_nm.tlv.status == 0) \ .must_next() # 3. BR_1 informs other BBRs on the network of the multicast # registrations. # BR_1 multicasts a BMLR.ntf CoAP request to the Backbone Link, # as follows: # coap://[<All network BBRs multicast>]:BB/b/bmr # Where the payload contains: # IPv6 Addresses TLV: MASi (15 addresses) # Timeout TLV: default MLR timeout of BR_1 pkts.filter_eth_src(vars['BR_1_ETH']) \ .filter_ipv6_dst(config.ALL_NETWORK_BBRS_ADDRESS) \ .filter_coap_request('/b/bmr') \ .filter( lambda p: set(p.thread_meshcop.tlv.ipv6_addr) == set(MAS[i][1:]) and p.thread_bl.tlv.timeout == consts.MLR_TIMEOUT_MIN) \ .must_next() # 4. BR_1 multicasts an MLDv2 message of type “Version 2 # Multicast Listener Report” (see [RFC 3810] Section 5.2). # Where: # Nr of Mcast Address Records(M) >= 15 # Multicast Address Record[j]: # Each of the j := 1 ... 15 Multicast Address Record containing an # address of the set MASi contains the following: # Record Type: 4 (CHANGE_TO_EXCLUDE_MODE) # Number of Sources (N): 0 # Multicast Address: MASi[j] # Alternatively, the DUT may also send multiple of above messages # each with a portion of the 15 addresses MASi. # In this case the Nr of Mcast Address Records can be < 15 # but the sum over all messages MUST be >= 15. # TODO # Loop steps 5 to 6 with i := 1 to 5. for i in range(1, 6): # 5. Host sends a ping packet to the multicast address, # MASi[ 3 * i - 1], on the backbone link. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MAS[i][3 * i - 1]) \ .filter_ping_request() \ .must_next() # 6. BR_1 forwards the ping packet of the previous step to its # Thread Network encapsulated in an MPL packet. pkts.copy().filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 7. Host multicasts a packet to the multicast addresses, MA2. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA2) \ .filter_ping_request() \ .must_next() # 8. BR_1 does not forward the packet to its Thread Network. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA() \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() logging.info(f'vars = {vars}') # Ensure the topology is formed correctly pv.verify_attached('Router_2', 'Router_1') pv.verify_attached('Router_3', 'Router_1') # 1. Router_1 pings Router_2. _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_2dsts(vars['Router_2_RLOC'], vars['Router_2_LLA']) \ .filter_ping_request() \ .must_next() pkts.filter_wpan_src64(vars['Router_2']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 2. Router_1 pings Router_2 multiple times. for i in range(5): _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_2dsts(vars['Router_2_RLOC'], vars['Router_2_LLA']) \ .filter_ping_request() \ .must_next() pkts.filter_wpan_src64(vars['Router_2']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 3. Router_2 pings Router_1 from the link-local address to the # link-local address. _pkt = pkts.filter_wpan_src64(vars['Router_2']) \ .filter_ipv6_src_dst(vars['Router_2_LLA'], vars['Router_1_LLA']) \ .filter_ping_request() \ .must_next() pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 4. Router_2 pings Router_3 using the RLOC. _pkt = pkts.filter_wpan_src64(vars['Router_2']) \ .filter_ipv6_dst(vars['Router_3_RLOC']) \ .filter_ping_request() \ .must_next() pkts.filter_wpan_src64(vars['Router_3']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 5. Router_2 pings Router_3's link-local address. The ping should fail. _pkt = pkts.filter_wpan_src64(vars['Router_2']) \ .filter_ipv6_dst(vars['Router_3_LLA']) \ .filter_ping_request() \ .must_next() pkts.filter_wpan_src64(vars['Router_3']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next() # 5. Router_2 pings Router_3's RLOC from the link-local address. The # ping should fail. _pkt = pkts.filter_wpan_src64(vars['Router_2']) \ .filter_ipv6_src_dst(vars['Router_2_LLA'], vars['Router_3_RLOC']) \ .filter_ping_request() \ .must_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() logging.info(f'vars = {vars}') pv.verify_attached('Router_1', 'BR_1') # 1. Host pings router1's OMR from host's infra address. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_dst( vars['Router_1_OMR'][0]).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['BR_1']).filter_wpan_dst16( vars['Router_1_RLOC16']).filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_next() # 2. Host pings router1's DUA from host's infra address. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_dst( vars['Router_1_DUA']).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['BR_1']).filter_wpan_dst16( vars['Router_1_RLOC16']).filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_next() # 3. Host pings router1's OMR from router1's RLOC. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_src_dst( vars['Router_1_RLOC'], vars['Router_1_OMR'][0]).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['BR_1']).filter_wpan_dst16( vars['Router_1_RLOC16']).filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_not_next() # 4. Host pings router1's OMR from BR1's OMR. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_src_dst( vars['BR_1_OMR'][0], vars['Router_1_OMR'][0]).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['BR_1']).filter_wpan_dst64( vars['Router_1']).filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_not_next() # 5. Host pings router1's OMR from router1's MLE-ID. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_src_dst( vars['Router_1_MLEID'], vars['Router_1_OMR'][0]).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['BR_1']).filter_wpan_dst16( vars['Router_1_RLOC16']).filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_not_next() # 6. Host pings router1's RLOC from host's ULA address. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_dst( vars['Router_1_RLOC']).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['BR_1']).filter_wpan_dst16( vars['Router_1_RLOC16']).filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_not_next() # 7. Host pings router1's MLE-ID from host's ULA address. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_dst( vars['Router_1_MLEID']).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['BR_1']).filter_wpan_dst16( vars['Router_1_RLOC16']).filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_not_next() # 8. Host pings router1's link-local address from host's infra address. # Skip this scenario as for now # _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_dst( # vars['Router_1_LLA']).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['BR_1']).filter_wpan_dst16( vars['Router_1_RLOC16']).filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_not_next() # 9. Host pings MA1 from host's ULA address. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_dst(MA1).filter_ping_request().must_next() pkts.filter_wpan_src64( vars['BR_1']).filter_AMPLFMA().filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_next() # 10. Host pings MA1 from router1's RLOC. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_src_dst(vars['Router_1_RLOC'], MA1).filter_ping_request().must_next() pkts.filter_wpan_src64( vars['BR_1']).filter_AMPLFMA().filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_not_next() # 11. Host pings MA1 from router1's OMR. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_src_dst(vars['Router_1_OMR'][0], MA1).filter_ping_request().must_next() pkts.filter_wpan_src64( vars['BR_1']).filter_AMPLFMA().filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_not_next() # 12. Host pings MA1 from router1's MLE-ID. _pkt = pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_src_dst(vars['Router_1_MLEID'], MA1).filter_ping_request().must_next() pkts.filter_wpan_src64( vars['BR_1']).filter_AMPLFMA().filter_ping_request(identifier=_pkt.icmpv6.echo.identifier).must_not_next()
def verify(self, pv: pktverify.packet_verifier.PacketVerifier): pkts = pv.pkts vars = pv.vars pv.summary.show() logging.info(f'vars = {vars}') # Ensure the topology is formed correctly pv.verify_attached('Router_1', 'BR_1') # 1. Host multicasts a ping packet to the multicast address, MA1, with # the IPv6 Hop Limit field set to 59. The size of the payload is 130 # bytes. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request() \ .filter(lambda p: p.ipv6.hlim == 59 and p.ipv6.plen == 130 + ICMP_HEADER_LEN) \ .must_next() # 2. BR_1 forwards the ping packet to Router_1 as an MPL packet # encapsulating the IPv6 packet with the Hop Limit field of the inner # packet set to 58. _pkt2 = pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .filter(lambda p: p.ipv6inner.hlim == 58 and p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ .must_next() # 3. Router_1 receives the multicast ping packet. pkts.filter_wpan_src64(vars['Router_1']) \ .filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() # 4. Host multicasts a ping packet to the multicast address, MA1, with # the IPv6 Hop Limit field set to 1. The size of the payload is 130 # bytes. _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ .filter_ipv6_dst(MA1) \ .filter_ping_request() \ .filter( lambda p: p.ipv6.hlim == 1 and p.ipv6.plen == 130 + ICMP_HEADER_LEN) \ .must_next() # 5. BR_1 does not forward the ping packet. pkts.filter_wpan_src64(vars['BR_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['BR_1']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next() # 6. Router_1 sends a ping packet encapsulated in an MPL packet to the # multicast address, MA2, with the Hop Limit field of the inner # packet set to 159. The size of the payload is 130 bytes. _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ .filter_ping_request() \ .filter(lambda p: p.ipv6inner.dst == MA2 and p.ipv6inner.hlim == 159 and p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ .must_next() # 7. BR_1 forwards the multicast ping packet to the LAN with the Hop # Limit field set to 158. pkts.filter_eth_src(vars['BR_1_ETH']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .filter(lambda p: p.ipv6.hlim == 158) \ .must_next() # 8. Router_1 sends a ping packet encapsulated in an MPL multicast # packet to the multicast address, MA2, with the Hop Limit field of the # inner packet set to 2. The size of the payload is 130 bytes _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ .filter_ping_request() \ .filter(lambda p: p.ipv6inner.dst == MA2 and p.ipv6inner.hlim == 2 and p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ .must_next() # 9. BR_1 forwards the multicast packet to the LAN with the Hop Limit # field set to 1. pkts.filter_eth_src(vars['BR_1_ETH']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .filter(lambda p: p.ipv6.hlim == 1) \ .must_next() # 10. Router_1 sends a ping packet encapsulated in an MPL multicast # packet to the multicast address, MA2, with the Hop Limit field of the # inner packet set to 1. The size of the payload is 130 bytes. _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ .filter_ping_request() \ .filter(lambda p: p.ipv6inner.dst == MA2 and p.ipv6inner.hlim == 1 and p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ .must_next() # 11. BR_1 does not forward the ping packet to the LAN. pkts.filter_eth_src(vars['BR_1_ETH']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next() # 12. Router_1 sends a ping packet encapsulated in an MPL multicast # packet to the multicast address, MA2, with the Hop Limit field of the # inner packet set to 0. _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ .filter_ping_request() \ .filter(lambda p: p.ipv6inner.dst == MA2 and p.ipv6inner.hlim == 0 and p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ .must_next() # 13. BR_1 does not forward the ping packet to the LAN. pkts.filter_eth_src(vars['BR_1_ETH']) \ .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ .must_not_next()