#!/usr/bin/perl
#
# $Copyright_v6PC$
#
# $Copyright$
#
# $TAHI: ct/nd/ncStateByNs4Probe.seq,v 1.43 2004/04/02 02:28:22 akisada Exp $

########################################################################
BEGIN { $V6evalTool::TestVersion = '$Name:  $ '; }
 
use V6evalTool;
use nd;

my $wait_readout = $nd::DELAY_FIRST_PROBE_TIME +
    $nd::RETRANS_TIMER * $nd::MAX_UNICAST_SOLICIT + 1;

ndOptions(@ARGV);

# The following generate debugging messages.
$nd::debug=$ndOpt_v|$ndOpt_vv;

# You can specifies debug options to a remote control program.
# If you want to know more detail, please see the following:
# - V6evalTool.pm: perldoc V6evalTool
# - V6evalRemote.pm: perldoc V6evalRemote
$nd::remote_debug="-o1" if $ndOpt_vv;

$IF=Link0;
$exit_rtn=$V6evalTool::exitPass;
$idx=0;

#
#
#
$type=$V6evalTool::NutDef{Type};
#if($type ne host && $type ne router) {
#    vLogHTML(ndErrmsg("ERROR: $V6evalTool::NutDef{Type}: ".
#		      "Unknown target type<BR>"));
#    exit $V6evalTool::exitFail;
#}

#
# sub test definition:
# - sending pattern,
# - SLLA vs cached LLA
# - expected state
# - message
#
$idx_ptn=0;
$idx_lla=1;
$idx_exp=2;
$idx_explla=3;
$idx_msg=4;
$idx_inc_ip=5;
$idx_prb_ip=6;
$idx_rpy_ip=7;
$idx_ign_ip=8;
$idx_non_n=9;
$idx_rpy_n=10;
$idx_ign_n=11;
$idx_stl_sr=12;
$idx_ign_sr=13;
@null=();

#
if($type eq 'host') {
	@ignore_unicast_ns_tn2nut=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll);
} elsif($type eq 'router') {
	@ignore_unicast_ns_tn2nut=
		(unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
} else {
	@ignore_unicast_ns_tn2nut=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll,
		 unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
}
@def_unicast_ns_tn2nut=
    (
     unicast_ns_tn2nut,
     same,
     PROBE,
     unchanged,
     'unicast NS w/o SLL',
     \@null, \@null, \@null, \@ignore_unicast_ns_tn2nut,
     \@null, \@null, \@null,
     \@null, \@null
     );

#
if($type eq 'host') {
	@ignore_unicast_ns_tn2nut_sll=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll);
} elsif($type eq 'router') {
	@ignore_unicast_ns_tn2nut_sll=
		(unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
} else {
	@ignore_unicast_ns_tn2nut_sll=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll,
		 unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
}
@def_unicast_ns_tn2nut_sll=
    (
     unicast_ns_tn2nut_sll,
     same,
     PROBE,
     unchanged,
     'unicast NS w/ SLL',
     \@null, \@null, \@null, \@ignore_unicast_ns_tn2nut_sll,
     \@null, \@null, \@null,
     \@null, \@null
     );

#
if($type eq 'host') {
	@ignore_multicast_ns_tn2nut_sll=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll);
} elsif($type eq 'router') {
	@ignore_multicast_ns_tn2nut_sll=
		(unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
} else {
	@ignore_multicast_ns_tn2nut_sll=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll,
		 unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
}
@def_multicast_ns_tn2nut_sll=
    (
     multicast_ns_tn2nut_sll,
     same,
     PROBE,
     unchanged,
     'multicast NS w/ SLL',
     \@null, \@null, \@null, \@ignore_multicast_ns_tn2nut_sll,
     \@null, \@null, \@null,
     \@null, \@null
     );

#
@probe_ip_unicast_ns_tn2nut_diff=
    (nd_unicast_ns_to_z, nd_unicast_ns_sll_to_z);
if($type eq 'host') {
	@ignore_ip_unicast_ns_tn2nut_diff=
		(nd_unicast_na_rSo_to_z, nd_unicast_na_rSO_tll_to_z);
} elsif($type eq 'router') {
	@ignore_ip_unicast_ns_tn2nut_diff=
		(nd_unicast_na_RSo_to_z, nd_unicast_na_RSO_tll_to_z);
} else {
	@ignore_ip_unicast_ns_tn2nut_diff=
		(nd_unicast_na_rSo_to_z, nd_unicast_na_rSO_tll_to_z,
		 nd_unicast_na_RSo_to_z, nd_unicast_na_RSO_tll_to_z);
}
@def_unicast_ns_tn2nut_diff=
    (
     unicast_ns_tn2nut,
     diff,
     PROBE,
     updated,
     'unicast NS w/o SLL, diff. LLA',
     \@null, \@probe_ip_unicast_ns_tn2nut_diff, \@null, \@ignore_ip_unicast_ns_tn2nut_diff,
     \@null, \@null, \@null,
     \@null, \@null
     );

#
if($type eq 'host') {
	@reply_unicast_ns_tn2nut_sll_diff=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll);
} elsif($type eq 'router') {
	@reply_unicast_ns_tn2nut_sll_diff=
		(unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
} else {
	@reply_unicast_ns_tn2nut_sll_diff=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll,
		 unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
}
@def_unicast_ns_tn2nut_sll_diff=
    (
     unicast_ns_tn2nut_sll,
     diff,
     STALE,
     updated,
     'unicast NS w/ SLL, diff. LLA',
     \@null, \@null, \@reply_unicast_ns_tn2nut_sll_diff, \@null,
     \@null, \@null, \@null,
     \@null, \@null
     );

#
if($type eq 'host') {
	@reply_multicast_ns_tn2nut_sll_diff=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll);
} elsif($type eq 'router') {
	@reply_multicast_ns_tn2nut_sll_diff=
		(unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
} else {
	@reply_multicast_ns_tn2nut_sll_diff=
		(unicast_na_nut2tn_rSo, unicast_na_nut2tn_rSO_tll,
		 unicast_na_nut2tn_RSo, unicast_na_nut2tn_RSO_tll);
}
@def_multicast_ns_tn2nut_sll_diff=
    (
     multicast_ns_tn2nut_sll,
     diff,
     STALE,
     updated,
     'multicast NS w/ SLL, diff. LLA',
     \@null, \@null, \@reply_multicast_ns_tn2nut_sll_diff, \@null,
     \@null, \@null, \@null,
     \@null, \@null
     );

#
#
#
@defs=
    (
#     \@def_unicast_ns_tn2nut,
     \@def_unicast_ns_tn2nut_sll,
     \@def_multicast_ns_tn2nut_sll,
     \@def_unicast_ns_tn2nut_sll_diff,
     \@def_multicast_ns_tn2nut_sll_diff,
     );

#
#
#
vCapture($IF);


#
#
#
$idx=0;
foreach(@defs) {
    $exp=@$_[$idx_exp];
    $explla=@$_[$idx_explla];
    $msg=@$_[$idx_msg];
    vLogHTML("<HR>");
    vLogHTML("<FONT SIZE=\"+2\">*** PROBE vs. $msg ***</FONT><BR>");
    $s=checkState($_);
    $c=ndCachedLLA($explla);
    if($s eq $exp && $c eq $explla) {
        $result{$idx}=$V6evalTool::exitPass;
        vLogHTML("<A NAME=\"T$idx\">OK: The target was $s/$c</A><BR>");
    } else {
        $exit_rtn=$V6evalTool::exitFail;
        $result{$idx}=$exit_rtn;
        vLogHTML("<A NAME=\"T$idx\">".
		 ndErrmsg("NG: The target was $s/$c")."</A><BR>");
	readout($IF, $wait_readout);
    }
    $title{$idx}="<TD>$msg</TD><TD>exp:$exp/$explla</TD><TD>result:$s/$c</TD>";
    $idx++;
}
$idx--;

#
#
#
@col=('PTN', 'EXP(State/Cached LLA)', 'RESULT(State/Cached LLA)');
ndPrintSummaryHTML("*** Test Summary: PROBE vs. NS ***", @col,
		   %title, %result, $idx);

#
#
#
vLogHTML("*** EOT ***<BR>");
exit $exit_rtn;

sub readout($$) {
	my ($if, $timeout) = @_;
	return(vRecv($if, $timeout, 0, 0));
}

#
#
#
sub checkState(\@) {
    my($def)=@_;
    my($ptn)=@$def[$idx_ptn];
    my($lla)=@$def[$idx_lla];
    my($exp)=@$def[$idx_exp];
    my($msg)=@$def[$idx_msg];

    my($inc_ip)=@$def[$idx_inc_ip];
    my($prb_ip)=@$def[$idx_prb_ip];
    my($rpy_ip)=@$def[$idx_rpy_ip];
    my($ign_ip)=@$def[$idx_ign_ip];

    my($non_n)=@$def[$idx_non_n];
    my($rpy_n)=@$def[$idx_rpy_n];
    my($ign_n)=@$def[$idx_ign_n];

    my($stl_sr)=@$def[$idx_stl_sr];
    my($ign_sr)=@$def[$idx_ign_sr];

    vLogHTML("<FONT SIZE=\"+1\">Initialization</FONT><BR>");
    if($lla eq same) {
        goto error if nd2Probe($IF) != 0;
    } else {
        goto error if nd2ProbeZ($IF) != 0;
    }
    vClear($IF);

    vLogHTML("<FONT SIZE=\"+1\">Test</FONT><BR>");
    $pktdesc{$ptn}="Send $msg";
    my(%ret)=vSend($IF, $ptn);
    my($s)=ndStatusNum2Str(ndStatus(
                                    $IF, $ret{sentTime1},
                                    @$inc_ip, @$prb_ip, @$rpy_ip, @$ign_ip,
                                    @$non_n, @$rpy_n, @$ign_n,
                                    @$stl_sr, @$ign_sr,
                                    )
                       );
    return $s;

error:
    return("ERROR");
}

########################################################################
__END__

=head1 NAME

ncStateByNs4Probe - Verifying State Machine: NS vs. PROBE

=head1 TARGET

Host/Router/Special

=head1 SYNOPSIS

  ncStateByNs4Probe.seq [-tooloption ...] -p ncStateByNs4Probe.def

=head1 INITIALIZATION

=begin html
<OL>
  <LI>Set the state of neighbor cache entry to REACHABLE.
  <LI>Cache either <A HREF="#Cache_a_LLA_of_TN">TN's LLA</A>, or
      <A HREF="#Cache_a_bogus_LLA">a bogus LLA</A>
</OL>

=head2 Cache a LLA of TN

=begin html
<PRE>
  TN                 NUT
  ----------------------
  State: No neighbor cache entry (for TN)
<BR>
  ==== echo-request ===>
        src=TN's link-local
        dst=NUT's link-local
<BR>
  State: INCOMPLETE (for TN)
<BR>
  <=== multicast NS ====
        src=NUT's link-local or global
        dst=solicited-node[TN's link-local]
        target=TN's link-local
        w/ SLLA
        timeout: RETRANS_TIMER * MAX_MULTICAST_SOLICIT
<BR>
  ==== solicited NA ===>
        src=TN's link-local
        dst=NUT's link-local
        target=TN's link-local
        <B>TLLA=TN's LLA</B>
<BR>
  State: REACHABLE (for TN)
<BR>
  <=== echo-reply ====
        src=NUT's link-local
        dst=TN's link-local
        timeout: 2 sec
<BR>
  Wait (REACHABLE_TIME * MAX_RANDOM_FACTOR)
<BR>
  State: STALE (for TN)
<BR>
  ==== echo-request ===>
        src=TN's link-local
        dst=NUT's link-local
<BR>
  <=== echo-reply ====
        src=NUT's link-local
        dst=TN's link-local
        timeout: 2 sec
<BR>
  State: DELAY (for TN)
<BR>
  Wait (DELAY_FIRST_PROBE_TIME)
<BR>
  State: PROBE (for TN)
</PRE>

=end html

=head2 Cache a bogus LLA

=begin html
<PRE>
  TN                 NUT
  ----------------------
  State: No neighbor cache entry (for TN)
<BR>
  ==== echo-request ===>
        src=TN's link-local
        dst=NUT's link-local
<BR>
  State: INCOMPLETE (for TN)
<BR>
  <=== multicast NS ====
        src=NUT's link-local or global
        dst=solicited-node[TN's link-local]
        target=TN's link-local
        w/ SLLA
        timeout: RETRANS_TIMER * MAX_MULTICAST_SOLICIT
<BR>
  ==== solicited NA ===>
        src=TN's link-local
        dst=NUT's link-local
        target=TN's link-local
        <B>TLLA=a bogus LLA</B>
<BR>
  State: REACHABLE (for TN)
<BR>
  <=== echo-reply ====
        src=NUT's link-local
        dst=TN's link-local
        timeout: 2 sec
<BR>
  Wait (REACHABLE_TIME * MAX_RANDOM_FACTOR)
<BR>
  State: STALE (for TN)
<BR>
  ==== echo-request ===>
        src=TN's link-local
        dst=NUT's link-local
<BR>
  <=== echo-reply ====
        src=NUT's link-local
        dst=TN's link-local
        timeout: 2 sec
<BR>
  State: DELAY (for TN)
<BR>
  Wait (DELAY_FIRST_PROBE_TIME)
<BR>
  State: PROBE (for TN)
</PRE>

=end html

=head1 TEST PROCEDURE

B<ncStateByNs4Probe> verifies that state transition for a NUT
in PROBE state when receiving an NS.

=begin html
<PRE>
  TN                 NUT
  ----------------------
<BR>
  State: PROBE (for TN)
<BR>
  ==== <A HREF="#JDG1">NS</A> ===>
        src=TN's link-local
        dst=NUT's link-local or solicited-node[NUT's link-local]
        w/o or w/ SLLA
<BR>
  <A HREF="#JDG1">Judgment</A>: <A HREF="nd.html">Examining NUT's neighbor cache state</A>
</PRE>

=end html

=head1 JUDGMENT

=begin html
<A NAME="JDG1"></A>
<PRE>
  ===============================+==========+=========+=================
  NS                             |New State |LLA       Comments
  ---------+-----------+---------+          |
  Source IP|Destination|SLLA     |          |
           |IP         |         |          |
  =========+===========+=========+==========+=========+=================
  TN's link Unicast     same      PROBE      unchanged
  ---------+-----------+---------+----------+---------+-----------------
  TN's link Multicast   same      PROBE      unchanged
  =========+===========+=========+==========+=========+=================
  TN's link Unicast     different STALE      changed
  ---------+-----------+---------+----------+---------+-----------------
  TN's link Multicast   different STALE      changed
  =========+===========+=========+==========+=========+=================
</PRE>

=end html

=head1 TERMINATION

  N/A

=head1 NOTE

  The test does not invoke any remote command.

=head1 REFERENCE

=begin html
<pre>
RFC2461
<hr>
7.2.3.  Receipt of Neighbor Solicitations<BR>
   A valid Neighbor Solicitation that does not meet any the following
   requirements MUST be silently discarded:<BR>
    - The Target Address is a "valid" unicast or anycast address
      assigned to the receiving interface [ADDRCONF],<BR>
    - The Target Address is a unicast address for which the node is
      offering proxy service, or<BR>
    - The Target Address is a "tentative" address on which Duplicate
      Address Detection is being performed [ADDRCONF].<BR>
   If the Target Address is tentative, the Neighbor Solicitation should
   be processed as described in [ADDRCONF].  Otherwise, the following
   description applies.  If the Source Address is not the unspecified
   address and, on link layers that have addresses, the solicitation
   includes a Source Link-Layer Address option, then the recipient
   SHOULD create or update the Neighbor Cache entry for the IP Source
   Address of the solicitation.  If an entry does not already exist, the
   node SHOULD create a new one and set its reachability state to STALE
   as specified in Section 7.3.3.  <B>If an entry already exists, and the
   cached link-layer address differs from the one in the received Source
   Link-Layer option, the cached address should be replaced by the
   received address and the entry's reachability state MUST be set to
   STALE.</B>
</pre>

=end html

=head1 SEE ALSO

  perldoc V6evalTool
  perldoc V6evalRemote

=cut
