pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/36130?usp=email )
Change subject: ggsn_tests: Split out generic ICMP(v6) related templates and functions ......................................................................
ggsn_tests: Split out generic ICMP(v6) related templates and functions
Change-Id: I53a5da05caeef4cdd59778840a6f4eed489f1b93 --- M ggsn_tests/GGSN_Tests.ttcn M ggsn_tests/gen_links.sh A library/ICMP_Templates.ttcn A library/ICMPv6_Templates.ttcn 4 files changed, 346 insertions(+), 308 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/30/36130/1
diff --git a/ggsn_tests/GGSN_Tests.ttcn b/ggsn_tests/GGSN_Tests.ttcn index 68157f3..55720ee 100644 --- a/ggsn_tests/GGSN_Tests.ttcn +++ b/ggsn_tests/GGSN_Tests.ttcn @@ -31,6 +31,8 @@ import from IP_Types all; import from ICMP_Types all; import from ICMPv6_Types all; + import from ICMP_Templates all; + import from ICMPv6_Templates all; import from Native_Functions all; import from Osmocom_VTY_Functions all; import from TELNETasp_PortType all; @@ -819,285 +821,6 @@ T_default.stop; }
- /* IPv6 router solicitation fe80::2 -> ff02::2 from 02:88:b5:1f:25:59 */ - const octetstring c_router_solicit := '6000000000103afffe800000000000000000000000000002ff02000000000000000000000000000285009f2b0000000001010288b51f2559'O; - /* IPv6 neighbor solicitation fe80::2 -> ff02::1:ff00:2 from 02:88:b5:1f:25:59 */ - const octetstring c_neigh_solicit:= '6000000000203afffe800000000000000000000000000002ff0200000000000000000001ff00000287009f9600000000fe80000000000000000000000000000201010288b51f2559'O; - - /* template for sending an ICMPv4 echo request */ - template (value) PDU_ICMP ts_ICMPv4_ERQ(octetstring data := ''O) := { - echo := { - type_field := 8, - code := 0, - checksum := '0000'O, - identifier := '0345'O, - sequence_number := '0001'O, - data := data - } - } - - /* template for receiving/matching an ICMPv4 echo request */ - template (present) PDU_ICMP tr_ICMPv4_ERQ := { - echo := { - type_field := 8, - code := 0, - checksum := ?, - identifier := ?, - sequence_number := ?, - data := ? - } - } - - /* template for receiving/matching an ICMPv4 echo reply */ - template (present) PDU_ICMP tr_ICMPv4_ERP(template octetstring data := *) := { - echo_reply := { - type_field := 0, - code := 0, - checksum := ?, - identifier := ?, - sequence_number := ?, - data := data - } - } - - /* template for receiving/matching an ICMPv6 Destination Unreachable */ - template (present) PDU_ICMP tr_ICMPv4_DU := { - destination_unreachable := { - type_field := 1, - code := ?, - checksum := ?, - unused := ?, - original_ip_msg := ? - } - } - - /* template to construct IPv4_packet from input arguments, ready for use in f_IPv4_enc() */ - template (value) IPv4_packet ts_IP4(OCT4 srcaddr, OCT4 dstaddr, LIN1 proto, LIN2_BO_LAST tlen, octetstring payload) := { - header := { - ver := 4, - hlen := 5, - tos := 0, - tlen := tlen, - id := 35902, - res := '0'B, - dfrag := '1'B, - mfrag := '0'B, - foffset := 0, - ttl := 64, - proto := proto, - cksum := 0, - srcaddr := srcaddr, - dstaddr := dstaddr - }, - ext_headers := omit, - payload := payload - } - - /* 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; - } - - /* 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); - } - /* Get link-id from PDP Context EUA */ function f_ctx_get_ipv6_interface_id(in PdpContext ctx) return OCT16 { var OCT16 interface_id; @@ -1117,14 +840,6 @@ return f_gen_icmpv6_router_solicitation(interface_id); }
- /* 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); - } - /* generate and encode ICMPv6 neighbor solicitation for PDP Context */ function f_gen_icmpv6_neigh_solicit_for_pdp(in PdpContext ctx) return octetstring { var OCT16 interface_id := f_ctx_get_ipv6_interface_id(ctx); @@ -1134,25 +849,6 @@ return f_gen_icmpv6_neigh_solicit(link_local, daddr, link_local); }
- /* Send an ICMPv4 echo msg through GTP given pdp ctx, and ip src and dst addr */ - function f_gen_icmpv4_echo(OCT4 saddr, OCT4 daddr, octetstring pl := ''O) return octetstring { - var octetstring tmp := f_enc_PDU_ICMP(valueof(ts_ICMPv4_ERQ(pl))); - var IPv4_packet ip4 := valueof(ts_IP4(saddr, daddr, 1, 50, tmp)); - var octetstring data := f_IPv4_enc(ip4); - var OCT2 cksum := f_IPv4_checksum(data); - data[10] := cksum[0]; - data[11] := cksum[1]; - return data; - } - - /* 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; - } - /* Wait for ICMPv4 from GTP */ function f_wait_icmp4(PdpContext ctx, template PDU_ICMP expected) runs on GT_CT { var Gtp1uUnitdata ud; @@ -1340,8 +1036,6 @@ f_pdp_ctx_act(ctx);
f_PCO_ensure_no_duplicates(ctx.pco_neg); - //f_send_gtpu(ctx, c_router_solicit); - //f_send_gtpu(ctx, c_neigh_solicit);
f_send_gtpu(ctx, f_icmpv6_rs_for_pdp(ctx)); f_wait_rtr_adv(ctx); diff --git a/ggsn_tests/gen_links.sh b/ggsn_tests/gen_links.sh index ebeb94b..c79e4a8 100755 --- a/ggsn_tests/gen_links.sh +++ b/ggsn_tests/gen_links.sh @@ -63,6 +63,7 @@ FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Templates.ttcn " FILES+="DIAMETER_Types.ttcn DIAMETER_CodecPort.ttcn DIAMETER_CodecPort_CtrlFunct.ttcn DIAMETER_CodecPort_CtrlFunctDef.cc DIAMETER_Emulation.ttcn " FILES+="DIAMETER_Templates.ttcn DIAMETER_ts29_212_Templates.ttcn DIAMETER_ts29_272_Templates.ttcn DIAMETER_ts32_299_Templates.ttcn " +FILES+="ICMP_Templates.ttcn ICMPv6_Templates.ttcn " FILES+="Osmocom_VTY_Functions.ttcn " gen_links $DIR $FILES
diff --git a/library/ICMP_Templates.ttcn b/library/ICMP_Templates.ttcn new file mode 100644 index 0000000..cf88e93 --- /dev/null +++ b/library/ICMP_Templates.ttcn @@ -0,0 +1,96 @@ +/* ICMP 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 ICMP_Templates { + + import from General_Types all; + import from IP_Types all; + import from ICMP_Types all; + + /* template for sending an ICMPv4 echo request */ + template (value) PDU_ICMP ts_ICMPv4_ERQ(octetstring data := ''O) := { + echo := { + type_field := 8, + code := 0, + checksum := '0000'O, + identifier := '0345'O, + sequence_number := '0001'O, + data := data + } + } + + /* template for receiving/matching an ICMPv4 echo request */ + template (present) PDU_ICMP tr_ICMPv4_ERQ := { + echo := { + type_field := 8, + code := 0, + checksum := ?, + identifier := ?, + sequence_number := ?, + data := ? + } + } + + /* template for receiving/matching an ICMPv4 echo reply */ + template (present) PDU_ICMP tr_ICMPv4_ERP(template octetstring data := *) := { + echo_reply := { + type_field := 0, + code := 0, + checksum := ?, + identifier := ?, + sequence_number := ?, + data := data + } + } + + /* template for receiving/matching an ICMPv6 Destination Unreachable */ + template (present) PDU_ICMP tr_ICMPv4_DU := { + destination_unreachable := { + type_field := 1, + code := ?, + checksum := ?, + unused := ?, + original_ip_msg := ? + } + } + + /* template to construct IPv4_packet from input arguments, ready for use in f_IPv4_enc() */ + template (value) IPv4_packet ts_IP4(OCT4 srcaddr, OCT4 dstaddr, LIN1 proto, LIN2_BO_LAST tlen, octetstring payload) := { + header := { + ver := 4, + hlen := 5, + tos := 0, + tlen := tlen, + id := 35902, + res := '0'B, + dfrag := '1'B, + mfrag := '0'B, + foffset := 0, + ttl := 64, + proto := proto, + cksum := 0, + srcaddr := srcaddr, + dstaddr := dstaddr + }, + ext_headers := omit, + payload := payload + } + + /* Send an ICMPv4 echo msg through GTP given pdp ctx, and ip src and dst addr */ + function f_gen_icmpv4_echo(OCT4 saddr, OCT4 daddr, octetstring pl := ''O) return octetstring { + var octetstring tmp := f_enc_PDU_ICMP(valueof(ts_ICMPv4_ERQ(pl))); + var IPv4_packet ip4 := valueof(ts_IP4(saddr, daddr, 1, 50, tmp)); + var octetstring data := f_IPv4_enc(ip4); + var OCT2 cksum := f_IPv4_checksum(data); + data[10] := cksum[0]; + data[11] := cksum[1]; + return data; + } +} \ No newline at end of file diff --git a/library/ICMPv6_Templates.ttcn b/library/ICMPv6_Templates.ttcn new file mode 100644 index 0000000..687aad4 --- /dev/null +++ b/library/ICMPv6_Templates.ttcn @@ -0,0 +1,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); + } + +} \ No newline at end of file