GGSN IPv6: Transmit Router Solicit, receive RouterAdv, transmit NeightSolicit

This commit is contained in:
Harald Welte 2017-08-09 17:16:31 +02:00
parent f1471e79cc
commit 231b94190c
1 changed files with 210 additions and 7 deletions

View File

@ -8,6 +8,8 @@ module GGSN_Tests {
import from GTP_CodecPort_CtrlFunct all;
import from GTPC_Types all;
import from GTPU_Types all;
import from IP_Types all;
import from ICMPv6_Types all;
const integer GTP0_PORT := 3386;
const integer GTP1C_PORT := 2123;
@ -20,6 +22,7 @@ module GGSN_Tests {
octetstring msisdn optional,
octetstring apn,
EndUserAddress eua,
OCT16 ip6_prefix optional,
BIT4 nsapi,
/* TEI (Data) local side */
OCT4 teid,
@ -336,7 +339,7 @@ module GGSN_Tests {
/* GTP-U */
template PDU_GTPU tr_GTP1U_PDU(template OCT1 msg_type, template OCT4 teid) := {
template PDU_GTPU tr_GTP1U_PDU(template OCT1 msg_type, template OCT4 teid, template GTPU_IEs ies := ?) := {
pn_bit := ?,
s_bit := ?,
e_bit := ?,
@ -349,7 +352,7 @@ module GGSN_Tests {
lengthf := ?,
teid := teid,
opt_part := *,
gtpu_IEs := ?
gtpu_IEs := ies
}
/* generalized GTP-U send template */
@ -386,9 +389,20 @@ module GGSN_Tests {
}
/* template matching reception of GTP-C echo-request */
/* template matching reception of GTP-U echo-request */
template Gtp1uUnitdata tr_GTPU_PING(template GtpPeer peer) := tr_GTPU_MsgType(peer, echoRequest, '00000000'O);
/* template matching reception of GTP-U GPDU */
template GTPU_IEs t_GPDU(template octetstring data) := {
g_PDU_IEs := {
data := data
}
}
template Gtp1uUnitdata tr_GTPU_GPDU(template GtpPeer peer, template OCT4 teid, template octetstring data := ?) := {
peer := peer,
gtpu := tr_GTP1U_PDU('FF'O, teid, t_GPDU(data))
}
template GTPU_IEs ts_UEchoRespPDU(OCT1 restart_counter) := {
echoResponse_IEs := {
recovery_gtpu := {
@ -466,8 +480,8 @@ module GGSN_Tests {
}
/* send GTP-U for a given context and increment sequence number */
function f_send_gtpu(inout PdpContext ctx, in template Gtp1uUnitdata data) runs on GT_CT {
GTPU.send(data);
function f_send_gtpu(inout PdpContext ctx, in octetstring data) runs on GT_CT {
GTPU.send(ts_GTP1U_GPDU(g_peer_u, ctx.d_seq_nr, ctx.teid_remote, data));
ctx.d_seq_nr := ctx.d_seq_nr + 1;
}
@ -488,6 +502,7 @@ module GGSN_Tests {
if (cpr.cause.causevalue == '80'O) {
ctx.teid_remote := cpr.teidDataI.teidDataI;
ctx.teic_remote := cpr.teidControlPlane.teidControlPlane;
ctx.eua := cpr.endUserAddress;
setverdict(pass);
} else {
setverdict(fail);
@ -528,12 +543,200 @@ module GGSN_Tests {
f_pdp_ctx_act(ctx);
}
/* template to generate a 'Prefix Information' ICMPv6 option */
template 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 an ICMPv6 router solicitation */
template 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 an ICMPv6 router advertisement */
template PDU_ICMPv6 ts_ICMPv6_RA(OCT16 prefix, INT1 prefix_len) := {
routerAdvertisement := {
typeField := 134,
code := 0,
checksum := '0000'O,
curHopLimit := ?,
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 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 OptionField tr_ICMP6_OptPrefix(template OCT16 prefix, template 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 router advertisement */
template PDU_ICMPv6 tr_ICMPv6_RA(template OCT16 prefix, template 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)
}
}
}
/* template to construct IPv6_packet from input arguments, ready for use in f_IPv6_enc() */
template 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);
}
/* 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);
}
/* create ICMPv6 router solicitation deriving link-id from PDP Context EUA */
function f_icmpv6_rs_for_pdp(in PdpContext ctx) return octetstring {
var OCT16 interface_id := ctx.eua.endUserAddress.endUserAddressIPv6.ipv6_address;
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 := ctx.eua.endUserAddress.endUserAddressIPv6.ipv6_address;
var OCT16 link_local := f_ipv6_link_local(interface_id);
var OCT16 daddr := f_ipv6_sol_node_mcast(link_local);
return f_gen_icmpv6_neigh_solicit(link_local, daddr, link_local);
}
/* wait for GGSN to send us an ICMPv6 router advertisement */
function f_wait_rtr_adv(PdpContext ctx) runs on GT_CT {
var Gtp1uUnitdata ud;
T_default.start;
alt {
//'6???????????3aff'O
[] GTPU.receive(tr_GTPU_GPDU(g_peer_u, ?)) -> value ud {
var octetstring gpdu := ud.gtpu.gtpu_IEs.g_PDU_IEs.data;
var IPv6_packet ip6 := f_IPv6_dec(gpdu);
if (ip6.header.ver != 6 or ip6.header.nexthead != 58 or ip6.header.hlim != 255) {
repeat;
}
var PDU_ICMPv6 icmp6 := f_dec_PDU_ICMPv6(ip6.payload);
if (not match(icmp6, tr_ICMPv6_RA(?, 64))) {
repeat;
}
ctx.ip6_prefix := icmp6.routerAdvertisement.options[0].prefixInformation.prefix;
log("RA with /64 prefix ", ctx.ip6_prefix);
}
[] GTPU.receive(tr_GTPU_GPDU(?, ?)) { repeat; }
[] GTPU.receive { setverdict(fail); }
[] T_default.timeout { setverdict(fail); }
}
T_default.stop;
}
testcase TC_activate_pdp6() runs on GT_CT {
f_init();
var PdpContext ctx := valueof(t_DefinePDP('262420123456789'H, '1234'O, valueof(t_ApnInternet), valueof(t_EuaIPv6Dyn)));
f_pdp_ctx_act(ctx);
f_send_gtpu(ctx, ts_GTP1U_GPDU(g_peer_u, ctx.d_seq_nr, ctx.teid_remote, c_router_solicit));
f_send_gtpu(ctx, ts_GTP1U_GPDU(g_peer_u, ctx.d_seq_nr, ctx.teid_remote, c_neigh_solicit));
//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);
f_send_gtpu(ctx, f_gen_icmpv6_neigh_solicit_for_pdp(ctx));
f_pdp_ctx_del(ctx, '1'B);
}