aboutsummaryrefslogtreecommitdiffstats
path: root/library/ICMPv6_Templates.ttcn
blob: 687aad45f761e631594e35865a8ff952c33cf657 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/* 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);
	}

}