Wednesday, May 19, 2004

Cisco's IOS Source Code (ipv6_discovery_test.c)

/*------------------------------------------------------------------
* ipv6_discovery_test.c -- Neighbor Discovery unit tests.
*
* August 2003, Ole Troan
*
* Copyright (c) 2003-2004 by cisco Systems, Inc.
* All rights reserved.
*------------------------------------------------------------------
*/
#include "interface.h"
#include "interface_private.h"
#include "../ipv6.h"
#include "../ipv6_discovery.h"
#include "sys_registry.h"
#include "subsys.h"
#include COMP_INC(cutest, cu_test.h)

idbtype lidb;
hwidbtype hwidb;
ipv6_idbtype ipv6_sb;
in6_addr_t target;

/*
* setup_subsys_init
*/
extern list_header subsyslist[SUBSYS_CLASS_MAX];
static void
setup_subsys_init (subsys_class category, char *name)
{
list_element *element;
subsystype *subsys;

FOR_ALL_DATA_IN_LIST(&subsyslist[category], element, subsys) {
if (!strcmp(name, subsys->namestring)) {
if (subsys->entry) {
(*subsys->entry)(subsys);
break;
}
}
}
}


static void
setup (void) {
setup_subsys_init(SUBSYS_CLASS_PROTOCOL, "ipv6_nd");
reg_add_printf((long)'P', ipv6_printf, "ipv6_printf");

/*
* Create an IDB and Enable IPv6 on it
*/
lidb.hwptr = &hwidb;
hwidb.firstsw = &lidb;
hwidb.status = IDB_ETHER;
lidb.ipv6_data = &ipv6_sb;

target.s6_addr32[0] = 0x2001000;
target.s6_addr32[3] = 0x0000001;
}


/*
* nd_test_create
*/
CU_TEST_START (nd_test_create, tc)
{
ipv6_nd_entry *e;

printf("\nAdding %P to ND cache", &target);

e = ipv6_nd_table_create(&target, &lidb);
cu_ok(tc, (e != NULL), "%s", "create ND entry");
cu_ok(tc, (e->idb == &lidb) &&
IN6_ARE_ADDR_EQUAL(&e->address, &target), "%s",
"verify ND entry");
}
CU_TEST_END


/*
* nd_test_lookup
*/
CU_TEST_START (nd_test_lookup, tc)
{
ipv6_nd_entry *e;

e = ipv6_nd_table_lookup(&target, &lidb);
cu_ok(tc, (e != NULL), "%s", "ND lookup");
}
CU_TEST_END


/*
* nd_test_delete
*/
CU_TEST_START (nd_test_delete, tc)
{
ipv6_nd_entry *e;

ipv6_nd_table_delete(&target, &lidb);
e = ipv6_nd_table_lookup(&target, &lidb);
cu_ok(tc, (e == NULL), "ND delete");
}
CU_TEST_END


/*
* nd_test_suite
*/
cu_suite_t *
nd_test_suite (void)
{
cu_suite_t *s = cu_suite_new();

CU_SUITE_ADD_TEST(s, nd_test_create);
CU_SUITE_ADD_TEST(s, nd_test_lookup);
CU_SUITE_ADD_TEST(s, nd_test_delete);

return (s);
}


CU_TEST_MAIN()
{
int res;
cu_suite_t *suite = cu_suite_new();

cu_init();
cu_suite_add_suite(suite, nd_test_suite());
setup();
res = cu_suite_run(suite);
cu_suite_summary(suite);

CU_TEST_MAIN_RETURN(res);
}

Cisco's IOS Source Code (ipv6_tcp.c)

/*------------------------------------------------------------------
* ipv6_tcp.c -- IP version 6 support functions for TCP
*
* June 1996, Kirk Lougheed
*
* This should be the only file in the TCP sources that
* explicitly references an IPv6 header or IPv6 addresses.
*
* Copyright (c) 1996-2003 by cisco Systems, Inc.
* All rights reserved.
*------------------------------------------------------------------
*/

#include "master.h"
#include "address.h"
#include "packet.h"
#include "interface_private.h"
#include "../ipv6/ipv6.h"
#include "../ipv6/ipv6_private.h"
#include "../ipv6/ipv6_stats.h"
#include "../ipv6/ipv6_idb.h"
#include "icmp6.h"
#include "ipv6_debug.h"
#include "../tcp/tcp.h"
#include "../tcp/tcpinternal.h"
#include "../tcp/tcp_debug.h"


/*
* ipv6_receive_tcp_header
*
* Pass a TCP segment to the main TCP layer.
* We checksum it and set up private pointers.
*/
void
ipv6_receive_tcp_header (paktype *pak)
{
ip6_hdr_t *ip;
tcptype *tcp;
ipv6addr_listtype *ifa;

/*
* Checksum the TCP packet.
* Errors are counted by the IPv4 code.
*/
ip = (ip6_hdr_t *)pak->network_start;
tcp = (tcptype *)pak->transport_start;

/*
* Don't accept TCP connections to multicast or anycast addresses
*/
ifa = ipv6_address_find(pak->if_input, &ip->ip6_dst);
if ((ifa && (ifa->flags & IPV6_IFF_ANYCAST)) ||

IN6_IS_ADDR_MULTICAST(&ip->ip6_dst)) {
if (tcp_debug)

buginf("\nTCP: anycast or multicast address <%P,%d> <%P,%d>",


&ip->ip6_src, tcp->sourceport,

&ip->ip6_dst, tcp->destinationport);

retbuffer(pak);

return;
}

if (ipv6_checksum(ip, tcp, IPPROTO_TCP)) {
if (tcp_debug)
buginf("\nTCP: checksum failure <%P,%d> <%P,%d>",


&ip->ip6_src, tcp->sourceport,

&ip->ip6_dst, tcp->destinationport);

tcp_traffic.checksumerr++;

ipv6_stats_update_idb(IPV6_STATS_TCP_CHECKSUM_ERROR, pak->if_input);

retbuffer(pak);

return;
}

/*
* Setup TCP's private pointers
* pak->length is total length less IP header bytes (including extensions)
*/
pak->dataptr = (uchar *)tcp;
pak->length = ip->ip6_plen + IPV6_HEADERBYTES - ((int)tcp - (int)ip);

/*
* Hand TCP segment off to TCP
*/
ipv6_stats_update_idb(IPV6_STATS_TCP_INPUT, pak->if_input);

if (gettcpack(tcp)) {
ipv6_reachable(&ip->ip6_src);
}
tcp_inputsegment(pak);
}


/*
* ipv6_tcp_write
* Write a TCP datagram to network using IPv6 network layer.
*
* Warning: the code that sends a RST about connectionless packets
* calls us with a NULL tcb pointer.
*/
void
ipv6_tcp_write (tcbtype * tcb, paktype *pak,


addrtype *destination, addrtype *source)
{
ip6_hdr_t *ip;
tcptype *tcp;
int bytes;

/*
* Put on standard IPV6 header.
* Figure out extension headers some other time.
*/
ip = (ip6_hdr_t *)pak->network_start;
ipv6_init_header(ip, IPV6_PRIORITY_INTERACTIVE, IPV6_DEFAULT_FLOW,


pak->length - IPV6_HEADERBYTES, IPPROTO_TCP,


ipv6_hop_limit,

(in6_addr_t *)&source->ipv6_addr,


(in6_addr_t *)&destination->ipv6_addr);

/*
* Compute TCP header checksum
*/
tcp = (tcptype *)pak->transport_start;
tcp->checksum = 0;
tcp->checksum = ipv6_checksum(ip, tcp, IPPROTO_TCP);

/*
* Do connection based accounting and fiddling.
*/
if (tcb) {
/*

* Do some bean counting
*/

if (pak->us_retransno != 0) {
tcp_traffic.retrans++;

tcb->pakoutretrans++;
ipv6_stats_update_idb(IPV6_STATS_TCP_RETRANSMITTED,




pak->if_output);
if (tcppkt_debug)


tcp_print(tcb, pak, tcp, 'R');
} else {
bytes = pak->length - tcp_ipbytes(tcb) + (tcp->dataoffset << 2);
if (bytes > 0) {

tcb->bytesoutcount += bytes;

tcb->pakoutdata++;

}
tcb->pakoutcount++;

if (tcppkt_debug)

tcp_print(tcb, pak, tcp, 'O');

}

/*

* We're sending an ACK, so stop the ACK timer

*/
tcp_stoptimer(tcb, ACKTIMEOUT);
}

/*
* Write datagram to network.
* Routing is done by IPv6.
*/
pak->if_output = NULL;
ipv6_write(pak, IPV6_STATS_TCP_OUTPUT);
}


/*
* ipv6_tcp_icmp_received
*
* We received an ICMP error message about some datagram.
* Check if it is for a TCP packet of ours belonging to an
* active socket. Return TRUE if we absorbed it.
*/
boolean
ipv6_tcp_icmp_received (paktype *pak, ip6_hdr_t *ip, icmp6_hdr_t *icmp)
{
tcptype *tcp;
tcbtype *tcb;
addrtype address;

/*
* We are looking for a returned TCP packet inside this ICMP message.
*/
tcp = ipv6_icmp_find_ulp(pak, NULL, IPPROTO_TCP);
if (!tcp) {
return (FALSE);
}

/*
* Check that enough of the originating packet was returned
* that we can correctly examine the tcp sport and dport.
* We need everything up to (but not including) the "window" field.
*/
if (ip->ip6_plen + IPV6_HEADERBYTES -

((char *)tcp - (char *)pak->network_start)

< FIELDOFFSET(tcptype, window)) {

ICMPV6_DEBUG("Not enough data returned - dropping packet");
return (FALSE);
}

/*
* Find a matching TCB.
*/
ipv6_addrtype_create(&ip->ip6_src, &address);
tcb = find_tcb(GETSHORT(&tcp->destinationport), GETSHORT(&tcp->sourceport),


&address, NULL, FALSE, FALSE, 0);
if (tcb) {
if (icmp->icmp6_type == ICMP6_PACKET_TOO_BIG) {
tcp_pmtu_response(tcb, icmp->icmp6_mtu);

} else if (tcb->state != ESTAB && tcb->state != CLOSEWAIT) {
/*
* Throw away TCBs that applications either don't know
* about or don't care anymore.
*/
if ((tcb->flags & TCB_GENTCBS && tcb->state == SYNRCVD) ||
tcb->flags & TCB_APP_CLOSED) {
tcp_async_cleanup(tcb, UNREACHABLE);
} else {
/*
* Application is expected to close the connection
* upon notification of the state change.
*/
tcp_deallocatetcb(tcb, UNREACHABLE);
}
}
}
retbuffer(pak);
return (TRUE);
}