| /* ICMPv6 Templates in TTCN-3 |
| * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> |
| * All rights reserved. |
| * |
| * Released under the terms of GNU General Public License, Version 2 or |
| * (at your option) any later version. |
| * |
| * SPDX-License-Identifier: GPL-2.0-or-later |
| */ |
| |
| module ICMPv6_Templates { |
| |
| import from General_Types all; |
| import from IP_Types all; |
| import from ICMPv6_Types all; |
| |
| /* template to generate a 'Prefix Information' ICMPv6 option */ |
| template (value) OptionField ts_ICMP6_OptPrefix(OCT16 prefix, INT1 prefix_len) := { |
| prefixInformation := { |
| typeField := 3, |
| lengthIndicator := 8, |
| prefixLength := prefix_len, |
| reserved1 := '000000'B, |
| a_Bit := '0'B, |
| l_Bit := '0'B, |
| validLifetime := oct2int('FFFFFFFF'O), |
| preferredLifetime := oct2int('FFFFFFFF'O), |
| reserved2 := '00000000'O, |
| prefix := prefix |
| } |
| } |
| |
| /* template for sending an ICMPv6 echo request */ |
| template (value) PDU_ICMPv6 ts_ICMPv6_ERQ := { |
| echoRequest := { |
| typeField := 128, |
| code := 0, |
| checksum := '0000'O, |
| identifier := 0, |
| sequenceNr := 0, |
| data := ''O |
| } |
| } |
| |
| /* template for sending an ICMPv6 router solicitation */ |
| template (value) PDU_ICMPv6 ts_ICMPv6_RS := { |
| routerSolicitation := { |
| typeField := 133, |
| code := 0, |
| checksum := '0000'O, |
| reserved := '00000000'O, |
| /* TODO: do we need 'Source link-layer address' ? */ |
| options := omit |
| } |
| } |
| |
| /* template for sending an ICMPv6 router advertisement */ |
| template (value) PDU_ICMPv6 ts_ICMPv6_RA(OCT16 prefix, INT1 prefix_len) := { |
| routerAdvertisement := { |
| typeField := 134, |
| code := 0, |
| checksum := '0000'O, |
| curHopLimit := 0, |
| reserved := '000000'B, |
| o_Bit := '0'B, |
| m_Bit := '0'B, |
| routerLifetime := oct2int('FFFF'O), |
| reachableTime := oct2int('FFFFFFFF'O), |
| retransTimer := oct2int('FFFFFFFF'O), |
| options := { |
| ts_ICMP6_OptPrefix(prefix, prefix_len) |
| } |
| } |
| } |
| |
| /* template for sending an ICMPv6 neighbor solicitation */ |
| template (value) PDU_ICMPv6 ts_ICMPv6_NS(OCT16 target_addr) := { |
| neighborSolicitation := { |
| typeField := 135, |
| code := 0, |
| checksum := '0000'O, |
| reserved := '00000000'O, |
| targetAddress := target_addr, |
| /* TODO: do we need 'Source link-layer address' ? */ |
| options := omit |
| } |
| } |
| |
| /* derive ICMPv6 link-local address from lower 64bit of link_id */ |
| /* template for receiving/matching an ICMPv6 'Prefix Information' option */ |
| template (present) OptionField tr_ICMP6_OptPrefix(template (present) OCT16 prefix, template (present) INT1 prefix_len) := { |
| prefixInformation := { |
| typeField := 3, |
| lengthIndicator := 4, |
| prefixLength := prefix_len, |
| reserved1 := ?, |
| a_Bit := ?, |
| l_Bit := ?, |
| validLifetime := ?, |
| preferredLifetime := ?, |
| reserved2 := ?, |
| prefix := prefix |
| } |
| } |
| |
| /* template for receiving/matching an ICMPv6 'MTU' option, rfc4861 4.6.4 */ |
| template (present) OptionField tr_ICMP6_OptMTU(template (present) integer mtu := ?) := { |
| mTU := { |
| typeField := 5, |
| lengthIndicator := 1, |
| reserved := ?, |
| mTU_Value := mtu |
| } |
| } |
| |
| /* template for receiving/matching an ICMPv6 router advertisement */ |
| template (present) PDU_ICMPv6 tr_ICMPv6_RA(template (present) OCT16 prefix, template (present) INT1 prefix_len) := { |
| routerAdvertisement := { |
| typeField := 134, |
| code := 0, |
| checksum := ?, |
| curHopLimit := ?, |
| reserved := ?, |
| o_Bit := '0'B, |
| m_Bit := '0'B, |
| routerLifetime := ?, |
| reachableTime := ?, |
| retransTimer := ?, |
| options := ({ tr_ICMP6_OptPrefix(prefix, prefix_len) }, |
| { tr_ICMP6_OptPrefix(prefix, prefix_len), tr_ICMP6_OptMTU } |
| ) |
| } |
| } |
| |
| /* template for receiving/matching an ICMPv6 Destination Unreachable */ |
| template (present) PDU_ICMPv6 tr_ICMPv6_DU := { |
| destinationUnreachable := { |
| typeField := 1, |
| code := ?, |
| checksum := ?, |
| unused := ?, |
| originalIpMsg := ? |
| } |
| } |
| |
| /* template for receiving/matching an ICMPv6 echo request */ |
| template (present) PDU_ICMPv6 tr_ICMPv6_ERQ := { |
| echoRequest := { |
| typeField := 128, |
| code := 0, |
| checksum := ?, |
| identifier := ?, |
| sequenceNr := ?, |
| data := ? |
| } |
| } |
| |
| /* template for receiving/matching an ICMPv6 echo reply */ |
| template (present) PDU_ICMPv6 tr_ICMPv6_ERP(template octetstring data := *) := { |
| echoReply := { |
| typeField := 129, |
| code := 0, |
| checksum := ?, |
| identifier := ?, |
| sequenceNr := ?, |
| data := data |
| } |
| } |
| |
| /* template to construct IPv6_packet from input arguments, ready for use in f_IPv6_enc() */ |
| template (value) IPv6_packet ts_IP6(OCT16 srcaddr, OCT16 dstaddr, LIN1 nexthead, octetstring payload, LIN1 hlim := 255) := { |
| header := { |
| ver := 6, |
| trclass := 0, |
| flabel := 0, |
| plen := 0, |
| nexthead := nexthead, |
| hlim := hlim, |
| srcaddr := srcaddr, |
| dstaddr := dstaddr |
| }, |
| ext_headers := omit, |
| payload := payload |
| } |
| |
| function f_ipv6_link_local(in OCT16 link_id) return OCT16 { |
| return 'FE80000000000000'O & substr(link_id, 8, 8); |
| } |
| |
| function f_ipv6_global(in OCT16 link_id) return OCT16 { |
| return substr(link_id, 0, 8) & '1234123412341234'O; |
| } |
| |
| /* Create a new different IPv6 addr from input. Starts mangling at byte prefix. */ |
| function f_ipv6_mangle(in OCT16 addr, in integer prefix := 0) return OCT16 { |
| var integer i; |
| var octetstring res := substr(addr, 0, prefix); |
| for (i := prefix; i < lengthof(addr); i := i + 1) { |
| var octetstring a := addr[i] xor4b '11'O; |
| res := res & a; |
| } |
| return res; |
| } |
| |
| /* Send an ICMPv6 echo msg through GTP given pdp ctx, and ip src and dst addr */ |
| function f_gen_icmpv6_echo(OCT16 saddr, OCT16 daddr) return octetstring { |
| var octetstring tmp := f_enc_PDU_ICMPv6(valueof(ts_ICMPv6_ERQ), saddr, daddr); |
| var IPv6_packet ip6 := valueof(ts_IP6(saddr, daddr, 58, tmp)); |
| var octetstring data := f_IPv6_enc(ip6); |
| return data; |
| } |
| |
| /* Compute solicited-node multicast address as per RFC4291 2.7.1 */ |
| function f_ipv6_sol_node_mcast(in OCT16 addr) return OCT16 { |
| return 'FF0200000000000000000001FF'O & substr(addr, 13, 3); |
| } |
| |
| /* generate and encode ICMPv6 router solicitation */ |
| function f_gen_icmpv6_router_solicitation(in OCT16 link_id) return octetstring { |
| const OCT16 c_ip6_all_router_mcast := 'FF020000000000000000000000000002'O; |
| var OCT16 saddr := f_ipv6_link_local(link_id); |
| |
| var octetstring tmp; |
| tmp := f_enc_PDU_ICMPv6(valueof(ts_ICMPv6_RS), saddr, c_ip6_all_router_mcast); |
| var IPv6_packet ip6 := valueof(ts_IP6(saddr, c_ip6_all_router_mcast, 58, tmp)); |
| |
| return f_IPv6_enc(ip6); |
| } |
| |
| /* generate and encode ICMPv6 neighbor solicitation */ |
| function f_gen_icmpv6_neigh_solicit(in OCT16 saddr, in OCT16 daddr, in OCT16 tgt_addr) return octetstring { |
| var octetstring tmp; |
| tmp := f_enc_PDU_ICMPv6(valueof(ts_ICMPv6_NS(tgt_addr)), saddr, daddr); |
| var IPv6_packet ip6 := valueof(ts_IP6(saddr, daddr, 58, tmp)); |
| return f_IPv6_enc(ip6); |
| } |
| |
| } |