Pau Espin Pedrol | e16e928 | 2024-03-01 14:45:22 +0100 | [diff] [blame] | 1 | /* ICMPv6 Templates in TTCN-3 |
| 2 | * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Released under the terms of GNU General Public License, Version 2 or |
| 6 | * (at your option) any later version. |
| 7 | * |
| 8 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 9 | */ |
| 10 | |
| 11 | module ICMPv6_Templates { |
| 12 | |
| 13 | import from General_Types all; |
| 14 | import from IP_Types all; |
| 15 | import from ICMPv6_Types all; |
| 16 | |
| 17 | /* template to generate a 'Prefix Information' ICMPv6 option */ |
| 18 | template (value) OptionField ts_ICMP6_OptPrefix(OCT16 prefix, INT1 prefix_len) := { |
| 19 | prefixInformation := { |
| 20 | typeField := 3, |
| 21 | lengthIndicator := 8, |
| 22 | prefixLength := prefix_len, |
| 23 | reserved1 := '000000'B, |
| 24 | a_Bit := '0'B, |
| 25 | l_Bit := '0'B, |
| 26 | validLifetime := oct2int('FFFFFFFF'O), |
| 27 | preferredLifetime := oct2int('FFFFFFFF'O), |
| 28 | reserved2 := '00000000'O, |
| 29 | prefix := prefix |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | /* template for sending an ICMPv6 echo request */ |
| 34 | template (value) PDU_ICMPv6 ts_ICMPv6_ERQ := { |
| 35 | echoRequest := { |
| 36 | typeField := 128, |
| 37 | code := 0, |
| 38 | checksum := '0000'O, |
| 39 | identifier := 0, |
| 40 | sequenceNr := 0, |
| 41 | data := ''O |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | /* template for sending an ICMPv6 router solicitation */ |
| 46 | template (value) PDU_ICMPv6 ts_ICMPv6_RS := { |
| 47 | routerSolicitation := { |
| 48 | typeField := 133, |
| 49 | code := 0, |
| 50 | checksum := '0000'O, |
| 51 | reserved := '00000000'O, |
| 52 | /* TODO: do we need 'Source link-layer address' ? */ |
| 53 | options := omit |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | /* template for sending an ICMPv6 router advertisement */ |
| 58 | template (value) PDU_ICMPv6 ts_ICMPv6_RA(OCT16 prefix, INT1 prefix_len) := { |
| 59 | routerAdvertisement := { |
| 60 | typeField := 134, |
| 61 | code := 0, |
| 62 | checksum := '0000'O, |
| 63 | curHopLimit := 0, |
| 64 | reserved := '000000'B, |
| 65 | o_Bit := '0'B, |
| 66 | m_Bit := '0'B, |
| 67 | routerLifetime := oct2int('FFFF'O), |
| 68 | reachableTime := oct2int('FFFFFFFF'O), |
| 69 | retransTimer := oct2int('FFFFFFFF'O), |
| 70 | options := { |
| 71 | ts_ICMP6_OptPrefix(prefix, prefix_len) |
| 72 | } |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | /* template for sending an ICMPv6 neighbor solicitation */ |
| 77 | template (value) PDU_ICMPv6 ts_ICMPv6_NS(OCT16 target_addr) := { |
| 78 | neighborSolicitation := { |
| 79 | typeField := 135, |
| 80 | code := 0, |
| 81 | checksum := '0000'O, |
| 82 | reserved := '00000000'O, |
| 83 | targetAddress := target_addr, |
| 84 | /* TODO: do we need 'Source link-layer address' ? */ |
| 85 | options := omit |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | /* derive ICMPv6 link-local address from lower 64bit of link_id */ |
| 90 | /* template for receiving/matching an ICMPv6 'Prefix Information' option */ |
| 91 | template (present) OptionField tr_ICMP6_OptPrefix(template (present) OCT16 prefix, template (present) INT1 prefix_len) := { |
| 92 | prefixInformation := { |
| 93 | typeField := 3, |
| 94 | lengthIndicator := 4, |
| 95 | prefixLength := prefix_len, |
| 96 | reserved1 := ?, |
| 97 | a_Bit := ?, |
| 98 | l_Bit := ?, |
| 99 | validLifetime := ?, |
| 100 | preferredLifetime := ?, |
| 101 | reserved2 := ?, |
| 102 | prefix := prefix |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | /* template for receiving/matching an ICMPv6 'MTU' option, rfc4861 4.6.4 */ |
| 107 | template (present) OptionField tr_ICMP6_OptMTU(template (present) integer mtu := ?) := { |
| 108 | mTU := { |
| 109 | typeField := 5, |
| 110 | lengthIndicator := 1, |
| 111 | reserved := ?, |
| 112 | mTU_Value := mtu |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | /* template for receiving/matching an ICMPv6 router advertisement */ |
| 117 | template (present) PDU_ICMPv6 tr_ICMPv6_RA(template (present) OCT16 prefix, template (present) INT1 prefix_len) := { |
| 118 | routerAdvertisement := { |
| 119 | typeField := 134, |
| 120 | code := 0, |
| 121 | checksum := ?, |
| 122 | curHopLimit := ?, |
| 123 | reserved := ?, |
| 124 | o_Bit := '0'B, |
| 125 | m_Bit := '0'B, |
| 126 | routerLifetime := ?, |
| 127 | reachableTime := ?, |
| 128 | retransTimer := ?, |
| 129 | options := ({ tr_ICMP6_OptPrefix(prefix, prefix_len) }, |
| 130 | { tr_ICMP6_OptPrefix(prefix, prefix_len), tr_ICMP6_OptMTU } |
| 131 | ) |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | /* template for receiving/matching an ICMPv6 Destination Unreachable */ |
| 136 | template (present) PDU_ICMPv6 tr_ICMPv6_DU := { |
| 137 | destinationUnreachable := { |
| 138 | typeField := 1, |
| 139 | code := ?, |
| 140 | checksum := ?, |
| 141 | unused := ?, |
| 142 | originalIpMsg := ? |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | /* template for receiving/matching an ICMPv6 echo request */ |
| 147 | template (present) PDU_ICMPv6 tr_ICMPv6_ERQ := { |
| 148 | echoRequest := { |
| 149 | typeField := 128, |
| 150 | code := 0, |
| 151 | checksum := ?, |
| 152 | identifier := ?, |
| 153 | sequenceNr := ?, |
| 154 | data := ? |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | /* template for receiving/matching an ICMPv6 echo reply */ |
| 159 | template (present) PDU_ICMPv6 tr_ICMPv6_ERP(template octetstring data := *) := { |
| 160 | echoReply := { |
| 161 | typeField := 129, |
| 162 | code := 0, |
| 163 | checksum := ?, |
| 164 | identifier := ?, |
| 165 | sequenceNr := ?, |
| 166 | data := data |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | /* template to construct IPv6_packet from input arguments, ready for use in f_IPv6_enc() */ |
| 171 | template (value) IPv6_packet ts_IP6(OCT16 srcaddr, OCT16 dstaddr, LIN1 nexthead, octetstring payload, LIN1 hlim := 255) := { |
| 172 | header := { |
| 173 | ver := 6, |
| 174 | trclass := 0, |
| 175 | flabel := 0, |
| 176 | plen := 0, |
| 177 | nexthead := nexthead, |
| 178 | hlim := hlim, |
| 179 | srcaddr := srcaddr, |
| 180 | dstaddr := dstaddr |
| 181 | }, |
| 182 | ext_headers := omit, |
| 183 | payload := payload |
| 184 | } |
| 185 | |
| 186 | function f_ipv6_link_local(in OCT16 link_id) return OCT16 { |
| 187 | return 'FE80000000000000'O & substr(link_id, 8, 8); |
| 188 | } |
| 189 | |
| 190 | function f_ipv6_global(in OCT16 link_id) return OCT16 { |
| 191 | return substr(link_id, 0, 8) & '1234123412341234'O; |
| 192 | } |
| 193 | |
| 194 | /* Create a new different IPv6 addr from input. Starts mangling at byte prefix. */ |
| 195 | function f_ipv6_mangle(in OCT16 addr, in integer prefix := 0) return OCT16 { |
| 196 | var integer i; |
| 197 | var octetstring res := substr(addr, 0, prefix); |
| 198 | for (i := prefix; i < lengthof(addr); i := i + 1) { |
| 199 | var octetstring a := addr[i] xor4b '11'O; |
| 200 | res := res & a; |
| 201 | } |
| 202 | return res; |
| 203 | } |
| 204 | |
| 205 | /* Send an ICMPv6 echo msg through GTP given pdp ctx, and ip src and dst addr */ |
| 206 | function f_gen_icmpv6_echo(OCT16 saddr, OCT16 daddr) return octetstring { |
| 207 | var octetstring tmp := f_enc_PDU_ICMPv6(valueof(ts_ICMPv6_ERQ), saddr, daddr); |
| 208 | var IPv6_packet ip6 := valueof(ts_IP6(saddr, daddr, 58, tmp)); |
| 209 | var octetstring data := f_IPv6_enc(ip6); |
| 210 | return data; |
| 211 | } |
| 212 | |
| 213 | /* Compute solicited-node multicast address as per RFC4291 2.7.1 */ |
| 214 | function f_ipv6_sol_node_mcast(in OCT16 addr) return OCT16 { |
| 215 | return 'FF0200000000000000000001FF'O & substr(addr, 13, 3); |
| 216 | } |
| 217 | |
| 218 | /* generate and encode ICMPv6 router solicitation */ |
| 219 | function f_gen_icmpv6_router_solicitation(in OCT16 link_id) return octetstring { |
| 220 | const OCT16 c_ip6_all_router_mcast := 'FF020000000000000000000000000002'O; |
| 221 | var OCT16 saddr := f_ipv6_link_local(link_id); |
| 222 | |
| 223 | var octetstring tmp; |
| 224 | tmp := f_enc_PDU_ICMPv6(valueof(ts_ICMPv6_RS), saddr, c_ip6_all_router_mcast); |
| 225 | var IPv6_packet ip6 := valueof(ts_IP6(saddr, c_ip6_all_router_mcast, 58, tmp)); |
| 226 | |
| 227 | return f_IPv6_enc(ip6); |
| 228 | } |
| 229 | |
| 230 | /* generate and encode ICMPv6 neighbor solicitation */ |
| 231 | function f_gen_icmpv6_neigh_solicit(in OCT16 saddr, in OCT16 daddr, in OCT16 tgt_addr) return octetstring { |
| 232 | var octetstring tmp; |
| 233 | tmp := f_enc_PDU_ICMPv6(valueof(ts_ICMPv6_NS(tgt_addr)), saddr, daddr); |
| 234 | var IPv6_packet ip6 := valueof(ts_IP6(saddr, daddr, 58, tmp)); |
| 235 | return f_IPv6_enc(ip6); |
| 236 | } |
| 237 | |
| 238 | } |