/* ICMPv6 Templates in TTCN-3 * (C) 2024 by sysmocom - s.f.m.c. GmbH * 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); } }