#!/usr/bin/perl
#
# $Copyright_v6PC$
#
# $Copyright$
#
# $TAHI: ct/nd/sendNsBasicLinkGlob.seq,v 1.41 2004/04/02 02:28:24 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;

$wait_dad=3;
$wait_ns=$nd::RETRANS_TIMER * $nd::MAX_MULTICAST_SOLICIT;
$wait_echo=2;
$wait_stale=$nd::REACHABLE_TIME * $nd::MAX_RANDOM_FACTOR + 1;
$wait_probe=$nd::DELAY_FIRST_PROBE_TIME + 1;

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

goto error if nd2NoNce($IF) != 0;

#
# Start capture buffer
#
vLogHTML("<FONT SIZE=\"+1\">Test</FONT><BR>");
vCapture($IF);

#
#
#
#if(($type eq 'router') || ($type eq 'special')) {
if($type ne 'router') {
    #
    # Send an unsolicited RA w/ SLLA (src:x's link, dst:all-node)
    # to advertise a global prefix to the target.
    # SLLA makes sure that the target is in STALE state where
    # the target doesn't send a NA for the address.
    #
    $pktdesc{unsol_ra}="Send an unsolicited RA<BR>";
    vSend($IF, unsol_ra);
    vLogHTML("Ignore DAD packets for $wait_dad sec.<BR>");
    vRecv($IF, $wait_dad, 0, 0);
}

#
# Set neighbor cache entry to REACHABLE
#
$pktdesc{echo_request}="Send an echo-request (link-local ==> global)";
vSend($IF, echo_request);

vLogHTML("Wait NS if any<BR>");
vSleep(1);

$pktdesc{na_to_global}="Send a NA (link-local ==> global)";
$pktdesc{unicast_ns_from_global}= 'Got unicast NS';
$pktdesc{unicast_ns_from_global_sll}= 'Got unicast NS';
$pktdesc{unicast_ns_from_link}= 'Got unicast NS';
$pktdesc{unicast_ns_from_link_sll}= 'Got unicast NS';
$pktdesc{multicast_ns_from_global}= 'Got multicast NS';
$pktdesc{multicast_ns_from_link}= 'Got multicast NS';
$pktdesc{echo_reply}= 'Got echo-reply (link-local <== global)';
$count=0;

while(1) {
	$s = check($wait_echo, 0, 1);
	if ($s eq ECHO_REPLY) {
		last;
	}
	elsif($s eq TIMEOUT) {
		vLogHTML(ndErrmsg("ERROR: Never got echo-reply<BR>"));
		goto error;
	}
	$count++;
	if ($count > $nd::MAX_MULTICAST_SOLICIT) {
		vLogHTML(ndErrmsg("ERROR: Never got echo-reply<BR>"));
		goto error;
	}
	vSend($IF, na_to_global);
}
vLogHTML("Then REACHABLE<BR>");

#
# Wait for being STALE state.
#
vLogHTML("Wait for being STALE ($wait_stale sec.)<BR>");
vSleep($wait_stale);
vLogHTML("Then STALE<BR>");

#
#
#
$pktdesc{echo_request}="Send an echo-request (link-local ==> global)";
%ret=vSend($IF, echo_request);

$pktdesc{unicast_ns_from_global}=
    ndErrmsg('ERROR: Got unicast NS');
$pktdesc{unicast_ns_from_global_sll}=
    ndErrmsg('ERROR: Got unicast NS');
$pktdesc{unicast_ns_from_link}=
    ndErrmsg('ERROR: Got unicast NS');
$pktdesc{unicast_ns_from_link_sll}=
    ndErrmsg('ERROR: Got unicast NS');
$pktdesc{multicast_ns_from_link}=
    ndErrmsg('ERROR: Got multicast NS');
$pktdesc{multicast_ns_from_global}=
    ndErrmsg('ERROR: Got multicast NS');
$pktdesc{echo_reply}=
    'Got echo-reply, then DELAY';
$s=check($wait_echo, $ret{sentTime1}, 1);
if($s ne ECHO_REPLY) {
    vLogHTML(ndErrmsg("ERROR: Never got echo-reply<BR>"));
    goto error;
}

#
# Should capture an unicast NS (src:nut's link or global, dst:tn's link)
# that should be sent in PROBE state.
#
vLogHTML("Wait for being PROBE ($wait_probe sec.)<BR>");
$pktdesc{unicast_ns_from_global}= 'Got unicast NS, then PROBE';
$pktdesc{unicast_ns_from_global_sll}= 'Got unicast NS, then PROBE';
$pktdesc{unicast_ns_from_link}= 'Got unicast NS, then PROBE';
$pktdesc{unicast_ns_from_link_sll}= 'Got unicast NS, then PROBE';
$pktdesc{multicast_ns_from_global}= ndErrmsg('ERROR: Got multicast NS');
$pktdesc{multicast_ns_from_link}= ndErrmsg('ERROR: Got multicast NS');
$pktdesc{echo_reply}= ndErrmsg('ERROR: Got echo-reply (link-local <== global)');
$count=0;
while(1) {
    $s=check($wait_probe, 0, 1);
    if($s eq UNICAST_NS_G2L || $s eq UNICAST_NS_L2L) {
	$count++;
        if($count > $nd::MAX_MULTICAST_SOLICIT) {
            vLogHTML("Too many unicast NS (> $nd::MAX_UNICAST_SOLICIT)");
            $exit_rtn=$V6evalTool::exitFail;
            last;
        }
    } elsif($s eq TIMEOUT) {
	last;
    } else {
        $exit_rtn=$V6evalTool::exitFail;
    }
}
if($count==0) {
    vLogHTML(ndErrmsg("ERROR: Never got unicast NS<BR>"));
    goto error;
}
vLogHTML("Then, No neighbor cache entry<BR>");

#
#
#
$pktdesc{echo_request}="Send an echo-request (link-local\TN ==> global\@NUT)";
%ret=vSend($IF, echo_request);

#
# Should capture a multicast NS (src:nut's global, dst:tn's link)
#
vLogHTML("Wait for a multicast NS<BR>");
$pktdesc{unicast_ns_from_global}= ndErrmsg('ERROR: Got unicast NS');
$pktdesc{unicast_ns_from_global_sll}= ndErrmsg('ERROR: Got unicast NS');
$pktdesc{unicast_ns_from_link}= ndErrmsg('ERROR: Got unicast NS');
$pktdesc{unicast_ns_from_link_sll}= ndErrmsg('ERROR: Got unicast NS');
$pktdesc{multicast_ns_from_global}= 'Got multicast NS, then INCOMPLETE';
$pktdesc{multicast_ns_from_link}=
    ndErrmsg('ERROR: Got multicast NS, then INCOMPLETE');
$pktdesc{echo_reply}=
    ndErrmsg('ERROR: Got echo-reply (link-local <== global)');
$count=0;
while(1) {
    $s=check($wait_ns, $ret{sentTime1}, 1);
    if($s eq TIMEOUT) {
	last;
    } elsif($s eq MULTICAST_NS_G2L || $s eq MULTICAST_NS_L2L) {
	$count++;
#        if($s eq MULTICAST_NS_L2L) {
#            vLogHTML(ndErrmsg("ERROR: NS's source address ".
#			      "should be global.<BR>"));
#            $exit_rtn=$V6evalTool::exitFail;
#        }
        if($count > $nd::MAX_MULTICAST_SOLICIT) {
            vLogHTML("Too many unicast NS (> $nd::MAX_MULTICAST_SOLICIT)");
            $exit_rtn=$V6evalTool::exitFail;
            last;
	}
    } else {
	$exit_rtn=$V6evalTool::exitFail;
    }
}
if($count==0) {
    vLogHTML(ndErrmsg("ERROR: Never got multicast NS<BR>"));
    goto error;
}
vLogHTML("Then No neighbor cache entry<BR>");

#
# needless
#
#vLogHTML("<FONT SIZE=\"+1\">Termination</FONT><BR>");
#clear();

#
#
#
if($exit_rtn == $V6evalTool::exitPass) {
    vLogHTML("OK<BR>");
} else {
    vLogHTML("NG<BR>");
	readout($IF, $wait_readout);
}
exit $exit_rtn;

error:
    vLogHTML("<FONT SIZE=\"+1\">Termination</FONT><BR>");
    clear();
    vLogHTML(vErrmsg(%ret)."<BR>");
    vLogHTML(ndErrmsg("NG<BR>"));
	readout($IF, $wait_readout);
    exit $V6evalTool::exitFail;

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

#
#
#
sub clear()
{
#    return if $type eq router;
    return if $type ne 'host';
    $pktdesc{unsol_ra_clrrtr}="Clear the Default Router List";
    vSend($IF, unsol_ra_clrrtr);
}

#
#
#
sub check($$$)
{
    my($timeout, $recvtime, $count)=@_;

    my(%ret)=vRecv($IF, $timeout, $recvtime, $count,
		   unicast_ns_from_global,
		   unicast_ns_from_global_sll,
		   unicast_ns_from_link,
		   unicast_ns_from_link_sll,
		   multicast_ns_from_global,
		   multicast_ns_from_link,
                   echo_reply,
                   );
    if($ret{status} == 1) {
        return TIMEOUT;
    } elsif($ret{status} == 0) {
        if($ret{recvFrame} eq unicast_ns_from_global ||
           $ret{recvFrame} eq unicast_ns_from_global_sll) {
            return UNICAST_NS_G2L;
        } elsif($ret{recvFrame} eq unicast_ns_from_link ||
		$ret{recvFrame} eq unicast_ns_from_link_sll) {
            return UNICAST_NS_L2L;
        } elsif($ret{recvFrame} eq multicast_ns_from_global) {
            return MULTICAST_NS_G2L;
        } elsif($ret{recvFrame} eq multicast_ns_from_link) {
            return MULTICAST_NS_L2L;
        } else {
            return ECHO_REPLY;
        }
    } else {
        vLogHTML(vErrmsg(%ret)."<BR>");
        return ERROR;
    }
}

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

=head1 NAME

sendNsBasicLinkGlob - Verify that NUT send NSs (global ==> link)

=head1 TARGET

Host/Router/Special

=head1 SYNOPSIS

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

=head1 INITIALIZATION

=head2 A CASE OF A HOST

=begin html
<OL>
  <LI>Set a global prefix (3ffe:501:ffff:100::/64) with RA.
  <LI>Set neighbor cache state for TN to REACHABLE
</OL>

=end html

  TN                 NUT
  ----------------------

  State: any (for TN, X)

  ==== multicast RA ===>
       src=X's link-local
       dst=all-node
       M=0, O=0,
       Lifetime=600, ReachableTime=0, RetransTimer=0
       w/ SLLA
       Prefix:
           F=1, A=1,
           ValidLifetime=2592000, PreferredLifetime=604800
           Prefix=3ffe:501:ffff:100::, PrefixLength=64

  Wait (3 sec.)
	Ignoring DAD packets.

  State: any (for TN), STALE (for X)

  ==== echo-request ===>
       src=TN's link-local
       dst=NUT's global

  <=== multicast NS ====
       src=NUT's global or link-local
       dst=TN's sol-node
       w/ SLLA

  ==== solicited NA ===>
       src=TN's link-local
       dst=NUT's global
       R=0, S=1, O=1
       w/ TLLA

  State: REACHABLE (for TN), STALE (for X)

  <=== echo-reply   ====
       src=NUT's global
       dst=TN's link-local

=head2 A CASE OF A ROUTER

=begin html
<OL>
  <LI>NUT must be configured its interface under test (Link0)
      to have a global prefix of "3ffe:501:ffff:100::/64".
  <LI>Set neighbor cache state for TN to REACHABLE
</OL>

  TN                 NUT
  ----------------------

  State: any (for TN)

  ==== echo-request ===>
       src=TN's link-local
       dst=NUT's global

  ==== solicited NA ===>
       src=TN's link-local
       dst=NUT's global
       R=0, S=1, O=1
       w/ TLLA

  State: REACHABLE (for TN)

=head1 TEST PROCEDURE

B<sendNsBasicLinkGlob> verifies that NUT send valid NSs
in both INCOMPLETE state and PROBE state.

=begin html
<PRE>
  TN                 NUT
  ----------------------
<BR>
  State: REACHABLE (for TN)
<BR>
  Wait (REACHABLE_TIME * MAX_RANDOM_FACTOR)
<BR>
  State: STALE (for TN)
<BR>
  ==== echo-request ===>
       src=TN's link-local
       dst=NUT's global
<BR>
  <=== <A HREF="#JDG1">Judgment #1</A>: echo-reply   ====
       src=NUT's global
       dst=TN's link-local
       timeout: 2 sec
<BR>
  State: DELAY (for TN)
<BR>
  Wait (DELAY_FIRST_PROBE_TIME)
<BR>
  State: PROBE (for TN)
<BR>
  <=== <A HREF="#JDG2">Judgment #2</A>: unicast NS   ====
       src=NUT's global or link-local
       dst:TN's link-local
       w/ or w/o SLLA
       timeout: RETRANS_TIMER * MAX_UNICAST_SOLICIT
<BR>
  State: No neighbor cache entry (for TN)
<BR>
  ==== echo-request ===>
       src=TN's link-local
       dst=NUT's global
<BR>
  State: INCOMPLETE (for TN)
<BR>
  <=== <A HREF="#JDG3">Judgment #3</A>: multicast NS ====
       src=NUT's global
       dst=sol-node[TN's link-local]
       w/ SLLA
       timeout: RETRANS_TIMER * MAX_MULTICAST_SOLICIT
<BR>
  State: No neighbor cache entry (for TN)
</PRE>

=end html

=head1 JUDGMENT

=begin html
<PRE>
<A NAME="JDG1"></A>
  1. NUT must send an echo-reply:
     src: global, dst: link
<A NAME="JDG2"></A>
  2. NUT must send at the least one unicast NS:
     src: link/global, dst: link, w/ or w/o SLLA
<A NAME="JDG3"></A>
  3. NUT must send at the least one multicast NS:
     sec: global, dst: sol-node[link], w/ SLLA
</PRE>

=end html

=head1 TERMINATION

  Send RA with RouterLifetime=0 to flush the Default Router List.

=head1 NOTE

=begin html
<PRE>
  1. The test does not invoke any remote command.
</PRE>

=end html

=head1 REFERENCE

=begin html
<PRE>
RFC2461
<HR>
7.2.2.  Sending Neighbor Solicitations
<BR>
   When a node has a unicast packet to send to a neighbor, but does not
   know the neighbor's link-layer address, it performs address
   resolution.  For multicast-capable interfaces this entails creating a
   Neighbor Cache entry in the INCOMPLETE state and transmitting a
   Neighbor Solicitation message targeted at the neighbor.  The
   solicitation is sent to the solicited-node multicast address
   corresponding to the target address.
<BR>
   <B>If the source address of the packet prompting the solicitation is the
   same as one of the addresses assigned to the outgoing interface, that
   address SHOULD be placed in the IP Source Address of the outgoing
   solicitation.</B> Otherwise, any one of the addresses assigned to the
   interface should be used.  Using the prompting packet's source
   address when possible insures that the recipient of the Neighbor
   Solicitation installs in its Neighbor Cache the IP address that is
   highly likely to be used in subsequent return traffic belonging to
   the prompting packet's "connection".
</PRE>

=end html

=head1 SEE ALSO

  perldoc V6evalTool
  perldoc V6evalRemote

=cut
