You've already forked Frequency_Inverter
mirror of
https://github.com/Indemsys/Frequency_Inverter.git
synced 2026-05-09 14:12:58 +00:00
1311 lines
43 KiB
C
1311 lines
43 KiB
C
/**HEADER********************************************************************
|
|
*
|
|
* Copyright (c) 2008-2009 Freescale Semiconductor;
|
|
* All Rights Reserved
|
|
*
|
|
* Copyright (c) 1989-2008 ARC International;
|
|
* All Rights Reserved
|
|
*
|
|
***************************************************************************
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
**************************************************************************
|
|
*
|
|
* $FileName: iproute.c$
|
|
* $Version : 3.8.14.0$
|
|
* $Date : Sep-19-2012$
|
|
*
|
|
* Comments:
|
|
*
|
|
* This file contains the interface to the IP routing table.
|
|
*
|
|
*END************************************************************************/
|
|
|
|
#include <rtcs.h>
|
|
|
|
#if RTCSCFG_ENABLE_IP4
|
|
|
|
#include "rtcs_prv.h"
|
|
#include "tcpip.h"
|
|
#include "ip_prv.h"
|
|
#include "route.h"
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_init
|
|
* Returned Value : void
|
|
* Comments :
|
|
* Initializes the head of the routing table.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
void IP_route_init
|
|
(
|
|
IP_ROUTE_PTR head /* Pointer to the head of the IPRADIX tree */
|
|
)
|
|
{ /* Body */
|
|
IPRADIX_init(&head->NODE);
|
|
head->DIRECT = NULL;
|
|
head->INDIRECT = NULL;
|
|
head->VIRTUAL = NULL;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_insert
|
|
* Returned Value : void
|
|
* Comments :
|
|
* Adds a route to the routing table. Called by IPRADIX_insert.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
struct ip_route_insert {
|
|
uint_32 error;
|
|
pointer route;
|
|
uint_32 index;
|
|
void (_CODE_PTR_ sort)(pointer, pointer);
|
|
};
|
|
|
|
static void IP_route_insert
|
|
(
|
|
pointer _PTR_ node,
|
|
pointer data
|
|
)
|
|
{ /* Body */
|
|
struct ip_route_insert _PTR_ insertdata = data;
|
|
IP_ROUTE_PRV_PTR route;
|
|
IP_ROUTE_DIRECT_PTR new_route = insertdata->route;
|
|
uint_32 i = insertdata->index;
|
|
|
|
/* Make sure the node is initialized */
|
|
if (!*node) {
|
|
*node = node;
|
|
_mem_zero(((IP_ROUTE_PRV_PTR)*node)->ROUTETYPE, sizeof(route->ROUTETYPE));
|
|
} /* endif */
|
|
|
|
route = *node;
|
|
if (!route->ROUTETYPE[i]) {
|
|
new_route->NEXT = new_route;
|
|
route->ROUTETYPE[i] = new_route;
|
|
} else if (insertdata->sort) {
|
|
insertdata->sort(&route->ROUTETYPE[i], new_route);
|
|
} else {
|
|
new_route->NEXT = route->ROUTETYPE[i]->NEXT;
|
|
route->ROUTETYPE[i]->NEXT = new_route;
|
|
} /* Endif */
|
|
|
|
insertdata->error = RTCS_OK;
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_delete
|
|
* Returned Value : void
|
|
* Comments :
|
|
* Removes a route from the IP routing table. Called by IPRADIX_insert.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
struct ip_route_delete {
|
|
uint_32 index;
|
|
boolean (_CODE_PTR_ test)(pointer, pointer);
|
|
pointer data;
|
|
IP_ROUTE_FN_PTR fn;
|
|
};
|
|
|
|
static void IP_route_delete
|
|
(
|
|
pointer _PTR_ node, /* ptr to address of the IPRADIX_NODE DATA ptr */
|
|
pointer data /* ptr to data that can ID node to be deleted */
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_PRV_PTR route = *node;
|
|
IP_ROUTE_DIRECT_PTR tmp_ptr, search_ptr;
|
|
struct ip_route_delete _PTR_ remdata = data;
|
|
uint_32 i = remdata->index;
|
|
IP_ROUTE_FN_PTR fn;
|
|
|
|
if (route && route->ROUTETYPE[i]) { /* Make sure the node is valid */
|
|
|
|
/*
|
|
** Search the circular list for the correct node.
|
|
** tmp_ptr will always point to the node BEFORE search_ptr
|
|
*/
|
|
tmp_ptr = route->ROUTETYPE[i];
|
|
search_ptr = tmp_ptr->NEXT;
|
|
do {
|
|
|
|
if (remdata->test(search_ptr, remdata->data)) {
|
|
tmp_ptr->NEXT = search_ptr->NEXT; /* De-thread the node */
|
|
if (route->ROUTETYPE[i] == search_ptr) {
|
|
/* Update head if needed */
|
|
route->ROUTETYPE[i] = search_ptr->NEXT;
|
|
} /* Endif */
|
|
if (route->ROUTETYPE[i] == search_ptr) {
|
|
/* There is 1 node */
|
|
route->ROUTETYPE[i] = NULL;
|
|
if (route->ROUTETYPE[0] == NULL &&
|
|
route->ROUTETYPE[1] == NULL &&
|
|
route->ROUTETYPE[2] == NULL)
|
|
{
|
|
*node = NULL; /* Free data ptr if needed */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
for (fn = remdata->fn; fn; fn = fn->NEXT) {
|
|
fn->REM_RT((IP_ROUTE_INDIRECT_PTR)search_ptr);
|
|
} /* Endfor */
|
|
RTCS_part_free(search_ptr);
|
|
break;
|
|
} /* Endif */
|
|
|
|
/* Move on to the next node */
|
|
tmp_ptr = search_ptr;
|
|
search_ptr = search_ptr->NEXT;
|
|
} while (search_ptr != route->ROUTETYPE[i]->NEXT);
|
|
} /* Endif */
|
|
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_add_direct
|
|
* Returned Value : RTCS_OK or error code
|
|
* Comments :
|
|
* Adds a direct route to the IP routing table. Assumes the
|
|
* address, netmask and interfaces are valid.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
uint_32 IP_route_add_direct
|
|
(
|
|
_ip_address address, /* Address or network address of destif */
|
|
_ip_address netmask, /* Mask for the address parameter */
|
|
IP_IF_PTR netif, /* Interface for incomming packets */
|
|
IP_IF_PTR destif /* Interface for outgoing packets */
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
IP_ROUTE_DIRECT_PTR route;
|
|
IP_ROUTE_FN_PTR fn;
|
|
struct ip_route_insert insertdata;
|
|
|
|
route = RTCS_part_alloc(IP_cfg_ptr->ROUTE_PARTID);
|
|
if (!route) {
|
|
return RTCSERR_IP_ROUTE_ALLOC;
|
|
} /* Endif */
|
|
|
|
route->ADDRESS = address;
|
|
route->NETIF = netif;
|
|
route->DESTIF = destif;
|
|
route->FLAGS = RTF_STATIC | RTF_UP;
|
|
|
|
insertdata.error = RTCSERR_IP_ROUTE_ALLOC;
|
|
insertdata.route = route;
|
|
insertdata.index = 0;
|
|
insertdata.sort = NULL;
|
|
|
|
IPRADIX_insert(&IP_cfg_ptr->ROUTE_ROOT.NODE, address & netmask, netmask,
|
|
IP_cfg_ptr->RADIX_PARTID,
|
|
IP_route_insert, &insertdata);
|
|
|
|
if (insertdata.error) {
|
|
RTCS_part_free(route);
|
|
} else if (!~netmask) {
|
|
ROUTE_new_bindif(route); /* If the route is a leaf (has a full IP) */
|
|
} else if (route->DESTIF != RTCS_IF_LOCALHOST_PRV) {
|
|
fn = IP_cfg_ptr->ROUTE_FN; /* If the route is a network connection */
|
|
while (fn) {
|
|
fn->INIT_RT((IP_ROUTE_INDIRECT_PTR)((void _PTR_)route), 0);
|
|
fn = fn->NEXT;
|
|
} /* Endwhile */
|
|
} /* Endif */
|
|
|
|
return insertdata.error;
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_remove_direct
|
|
* Returned Value : void
|
|
* Comments :
|
|
* Removes a direct route from the IP routing table, if the node
|
|
* is present.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
struct ip_route_remove_direct {
|
|
_ip_address ipaddress;
|
|
IP_IF_PTR netif;
|
|
};
|
|
|
|
static boolean IP_route_delete_direct_test
|
|
(
|
|
pointer routeptr,
|
|
pointer dataptr
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_DIRECT_PTR route = routeptr;
|
|
struct ip_route_remove_direct _PTR_ data = dataptr;
|
|
|
|
return (route->ADDRESS == data->ipaddress && route->NETIF == data->netif);
|
|
} /* Endbody */
|
|
|
|
void IP_route_remove_direct
|
|
(
|
|
_ip_address address, /* IP address of route to remove */
|
|
_ip_address netmask, /* IP netmask of route to remove */
|
|
IP_IF_PTR netif /* pointer to the route interface */
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct ip_route_remove_direct removedata;
|
|
struct ip_route_delete deldata;
|
|
|
|
removedata.ipaddress = address;
|
|
removedata.netif = netif;
|
|
|
|
deldata.data = &removedata;
|
|
deldata.index = 0;
|
|
deldata.test = IP_route_delete_direct_test;
|
|
deldata.fn = IP_cfg_ptr->ROUTE_FN;
|
|
|
|
IPRADIX_insert(&IP_cfg_ptr->ROUTE_ROOT.NODE, address & netmask, netmask,
|
|
0, IP_route_delete, &deldata);
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_add_indirect
|
|
* Returned Value : RTCS_OK or error code
|
|
* Comments :
|
|
* Adds an indirect route to the IP routing table. Assumes the
|
|
* address and netmask are valid. The caller has to set flag to
|
|
* RTF_STATIC if ipif_bind or RTF_REDIRECT if icmpredirect.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void IP_route_add_indirect_sort
|
|
(
|
|
pointer head,
|
|
pointer new_node
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_INDIRECT_PTR _PTR_ head_ptr = head;
|
|
IP_ROUTE_INDIRECT_PTR node = new_node, search = *head_ptr, last;
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
IP_ROUTE_FN_PTR fn;
|
|
|
|
search = *head_ptr;
|
|
|
|
/*
|
|
** Check if there is non static route here. Remove it if there is because
|
|
** static routes take precedence over dynamic routes. This function is only
|
|
** called if there is already a node, and if this node is a dynamic node
|
|
** there will only be one. We can simply replace it with the new node.
|
|
*/
|
|
if (!(search->FLAGS & RTF_STATIC)) {
|
|
for (fn = IP_cfg_ptr->ROUTE_FN; fn; fn = fn->NEXT) {
|
|
fn->REM_RT(search);
|
|
} /* Endfor */
|
|
RTCS_part_free(search);
|
|
*head_ptr = node;
|
|
return;
|
|
} /* Endif */
|
|
|
|
/* Find the place to insert the new node */
|
|
last = NULL;
|
|
while (search->METRIC < node->METRIC) {
|
|
last = search;
|
|
search = search->NEXT;
|
|
if (search == *head_ptr) {
|
|
break;
|
|
} /* Endif */
|
|
} /* Endwhile */
|
|
|
|
/*
|
|
** At this point we found the place to insert. We need to special case
|
|
** insertion into the front of the list, but the other cases are easy.
|
|
*/
|
|
if (!last) {
|
|
/*
|
|
** The new node has to be the first in the list. We need a pointer to the
|
|
** last element in the list to complete the insertion. The following
|
|
** insertion works for any number of nodes.
|
|
*/
|
|
last = search->NEXT;
|
|
while (last->NEXT != search) {
|
|
last = last->NEXT;
|
|
} /* Endwhile */
|
|
|
|
/* Update the head_ptr to point to the new node */
|
|
*head_ptr = node;
|
|
} /* Endif */
|
|
|
|
/* Link in the new node */
|
|
node->NEXT = search;
|
|
last->NEXT = node;
|
|
|
|
return;
|
|
} /* Endbody */
|
|
|
|
#if RTCSCFG_ENABLE_GATEWAYS
|
|
uint_32 IP_route_add_indirect
|
|
(
|
|
_ip_address address, /* Gateway address */
|
|
_ip_address netmask, /* Network mask */
|
|
_ip_address network, /* Network address */
|
|
uint_32 flag, /* [IN] RTF_* */
|
|
uint_16 metric /* [IN] the route metric [0,65535] */
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
IP_ROUTE_INDIRECT_PTR route;
|
|
struct ip_route_insert insertdata;
|
|
IP_ROUTE_FN_PTR fn;
|
|
|
|
route = RTCS_part_alloc(IP_cfg_ptr->GATE_PARTID);
|
|
if (!route) {
|
|
return RTCSERR_IP_GATE_ALLOC;
|
|
} /* Endif */
|
|
|
|
route->GATEWAY = address;
|
|
route->FLAGS = flag | RTF_UP;
|
|
route->IS_DIRECT = NULL;
|
|
route->METRIC = metric;
|
|
|
|
insertdata.error = RTCSERR_IP_GATE_ALLOC;
|
|
insertdata.route = route;
|
|
insertdata.index = 1;
|
|
insertdata.sort = IP_route_add_indirect_sort;
|
|
|
|
IPRADIX_insert(&IP_cfg_ptr->ROUTE_ROOT.NODE, network & netmask, netmask,
|
|
IP_cfg_ptr->RADIX_PARTID,
|
|
IP_route_insert, &insertdata);
|
|
|
|
if (insertdata.error) {
|
|
RTCS_part_free(route);
|
|
} else {
|
|
fn = IP_cfg_ptr->ROUTE_FN;
|
|
while (fn) {
|
|
fn->INIT_RT(route, metric);
|
|
fn = fn->NEXT;
|
|
} /* Endwhile */
|
|
} /* Endif */
|
|
|
|
return insertdata.error;
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_remove_indirect
|
|
* Returned Value : void
|
|
* Comments :
|
|
* Removes one or all indirect routes from the IP routing table,
|
|
* if the node is present.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void IP_route_delete_indirect_all
|
|
(
|
|
pointer _PTR_ node, /* ptr to address of the IPRADIX_NODE DATA ptr */
|
|
pointer data /* ptr to the gateway address to be removed */
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_PTR route = *node;
|
|
IP_ROUTE_INDIRECT_PTR tmp_ptr, search_ptr;
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
IP_ROUTE_FN_PTR fn;
|
|
|
|
if (route && route->INDIRECT) { /* Make sure the node is valid */
|
|
|
|
search_ptr = route->INDIRECT->NEXT; /* search with next element */
|
|
tmp_ptr = search_ptr->NEXT;
|
|
/* if we have only one elment while loop will not execute */
|
|
while (search_ptr != route->INDIRECT) {
|
|
for (fn = IP_cfg_ptr->ROUTE_FN; fn; fn = fn->NEXT) {
|
|
fn->REM_RT(search_ptr);
|
|
} /* Endfor */
|
|
RTCS_part_free(search_ptr);
|
|
search_ptr = tmp_ptr;
|
|
tmp_ptr = search_ptr->NEXT;
|
|
} /* Endwhile */
|
|
/* Free the first element */
|
|
for (fn = IP_cfg_ptr->ROUTE_FN; fn; fn = fn->NEXT) {
|
|
fn->REM_RT(search_ptr);
|
|
} /* Endfor */
|
|
RTCS_part_free(search_ptr);
|
|
if (route->DIRECT == NULL && route->VIRTUAL == NULL) {
|
|
*node = NULL; /* Free data ptr if needed */
|
|
} else {
|
|
route->INDIRECT = NULL;
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
} /* Endbody */
|
|
|
|
static boolean IP_route_delete_indirect_test
|
|
(
|
|
pointer routeptr,
|
|
pointer dataptr
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_INDIRECT_PTR route = routeptr;
|
|
struct {
|
|
_ip_address gate;
|
|
uint_32 flag;
|
|
uint_16 metric;
|
|
} _PTR_ testdata = dataptr;
|
|
|
|
return (route->GATEWAY == testdata->gate &&
|
|
(route->FLAGS & testdata->flag) == testdata->flag &&
|
|
route->METRIC == testdata->metric);
|
|
} /* Endbody */
|
|
|
|
void IP_route_remove_indirect
|
|
(
|
|
_ip_address gateway, /* Gateway address */
|
|
_ip_address netmask, /* Network mask */
|
|
_ip_address network, /* Network address */
|
|
uint_32 flag, /* [IN] RTF_* */
|
|
uint_16 metric /* [IN] the route metric [0,65535] */
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct ip_route_delete deldata;
|
|
struct {
|
|
_ip_address gate;
|
|
uint_32 flag;
|
|
uint_16 metric;
|
|
} testdata;
|
|
|
|
if (gateway) {
|
|
testdata.gate = gateway;
|
|
testdata.flag = flag;
|
|
testdata.metric = metric;
|
|
|
|
deldata.index = 1;
|
|
deldata.data = &testdata;
|
|
deldata.test = IP_route_delete_indirect_test;
|
|
deldata.fn = IP_cfg_ptr->ROUTE_FN;
|
|
|
|
IPRADIX_insert(&IP_cfg_ptr->ROUTE_ROOT.NODE, network & netmask, netmask,
|
|
0, IP_route_delete, &deldata);
|
|
} else {
|
|
IPRADIX_insert(&IP_cfg_ptr->ROUTE_ROOT.NODE, network & netmask, netmask,
|
|
0, IP_route_delete_indirect_all, &gateway);
|
|
} /* Endif */
|
|
|
|
} /* Endbody */
|
|
#endif
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_add_virtual
|
|
* Returned Value : RTCS_OK or error code
|
|
* Comments :
|
|
* Adds a virtual route to the IP routing table. Assumes the
|
|
* address, netmask and interfaces are valid.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
uint_32 IP_route_add_virtual
|
|
(
|
|
_ip_address address, /* Destination address */
|
|
_ip_address netmask, /* Mask for the address parameter */
|
|
_ip_address source, /* Source address for interface */
|
|
_ip_address source_net, /* Allowed source network */
|
|
_ip_address source_mask, /* Allowes source network mask */
|
|
IP_IF_PTR destif, /* Interface for outgoing packets */
|
|
pointer data /* Route information */
|
|
)
|
|
{ /* Body */
|
|
#if RTCSCFG_ENABLE_VIRTUAL_ROUTES
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
IP_ROUTE_VIRTUAL_PTR route;
|
|
struct ip_route_insert insdata;
|
|
IP_ROUTE_FN_PTR fn;
|
|
|
|
route = RTCS_part_alloc(IP_cfg_ptr->VIRTUAL_PARTID);
|
|
if (!route) {
|
|
return RTCSERR_IP_VIRTUAL_ALLOC;
|
|
} /* Endif */
|
|
|
|
route->ADDRESS = source;
|
|
route->IS_DIRECT = NULL;
|
|
route->DESTIF = destif;
|
|
route->FLAGS = RTF_STATIC | RTF_UP;
|
|
route->SOURCE_NET = source_net;
|
|
route->SOURCE_MASK = source_mask;
|
|
route->DATA = data;
|
|
|
|
insdata.error = RTCSERR_IP_VIRTUAL_ALLOC;
|
|
insdata.route = route;
|
|
insdata.index = 2;
|
|
insdata.sort = NULL;
|
|
|
|
IPRADIX_insert(&IP_cfg_ptr->ROUTE_ROOT.NODE, address & netmask, netmask,
|
|
IP_cfg_ptr->RADIX_PARTID, IP_route_insert, &insdata);
|
|
|
|
if (insdata.error) {
|
|
RTCS_part_free(route);
|
|
} else if (!~netmask) {
|
|
fn = IP_cfg_ptr->ROUTE_FN;
|
|
while (fn) {
|
|
fn->INIT_RT((IP_ROUTE_INDIRECT_PTR)route, 0);
|
|
fn = fn->NEXT;
|
|
} /* Endwhile */
|
|
} /* Endif */
|
|
|
|
return insdata.error;
|
|
#else
|
|
return RTCSERR_IP_VIRTUAL_ALLOC;
|
|
#endif
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_remove_virtual
|
|
* Returned Value : void
|
|
* Comments :
|
|
* Removes a virtual route from the IP routing table, if the node
|
|
* is present.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
struct ip_route_remove_virtual {
|
|
_ip_address source;
|
|
_ip_address source_net;
|
|
_ip_address source_mask;
|
|
IP_IF_PTR netif;
|
|
};
|
|
|
|
static boolean IP_route_delete_virtual_test
|
|
(
|
|
pointer routeptr,
|
|
pointer dataptr
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_VIRTUAL_PTR route = routeptr;
|
|
struct ip_route_remove_virtual _PTR_ data = dataptr;
|
|
|
|
return (route->ADDRESS == data->source &&
|
|
route->SOURCE_NET == data->source_net &&
|
|
route->SOURCE_MASK == data->source_mask &&
|
|
route->DESTIF == data->netif);
|
|
} /* Endbody */
|
|
|
|
void IP_route_remove_virtual
|
|
(
|
|
_ip_address address, /* IP address of route to remove */
|
|
_ip_address netmask, /* IP netmask of route to remove */
|
|
_ip_address source, /* IP of interface */
|
|
_ip_address source_net, /* Allowed source network */
|
|
_ip_address source_mask, /* Allowed source source netmak */
|
|
IP_IF_PTR netif /* pointer to the route interface */
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct ip_route_remove_virtual removedata;
|
|
struct ip_route_delete deldata;
|
|
|
|
removedata.source = source;
|
|
removedata.source_net = source_net;
|
|
removedata.source_mask = source_mask;
|
|
removedata.netif = netif;
|
|
|
|
deldata.data = &removedata;
|
|
deldata.index = 2;
|
|
deldata.test = IP_route_delete_virtual_test;
|
|
deldata.fn = IP_cfg_ptr->ROUTE_FN;
|
|
|
|
IPRADIX_insert(&IP_cfg_ptr->ROUTE_ROOT.NODE, address & netmask, netmask,
|
|
0, IP_route_delete, &deldata);
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_local
|
|
* Returned Value : RTCS_OK or error code
|
|
* Comments :
|
|
* Decides whether or not to keep a packet.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
struct ip_route_local_test {
|
|
IP_IF_PTR ifdest;
|
|
_ip_address ipdest;
|
|
RTCSPCB_PTR pcb;
|
|
};
|
|
|
|
static boolean IP_route_local_test
|
|
(
|
|
pointer node,
|
|
pointer data
|
|
)
|
|
{ /* Body */
|
|
struct ip_route_local_test _PTR_ testdata = data;
|
|
IP_ROUTE_PTR route = node;
|
|
IP_ROUTE_DIRECT_PTR search_ptr = route->DIRECT;
|
|
_ip_address ip_bcast;
|
|
|
|
/* Don't process IP unicast packets without link-layer unicast bit set */
|
|
if (!~route->NODE.MASK && !(testdata->pcb->TYPE & RTCSPCB_TYPE_UNICAST)) {
|
|
return TRUE;
|
|
} /* Endif */
|
|
|
|
#if RTCSCFG_IP_DISABLE_DIRECTED_BROADCAST
|
|
/*
|
|
** This node matches a unicast address if MASK == 0xFFFFFFFF, and a
|
|
** directed broadcast if MASK != 0xFFFFFFFF. Here we return IP_UNREACH
|
|
** for directed broadcast packets.
|
|
*/
|
|
if (~route->NODE.MASK) {
|
|
return TRUE;
|
|
} /* Endif */
|
|
#endif
|
|
|
|
/* Calculate this route's broadcast address */
|
|
ip_bcast = route->NODE.IP | ~route->NODE.MASK;
|
|
|
|
if (search_ptr) {
|
|
do {
|
|
/*
|
|
** 1. Only check interfaces on which the packet was received, unless
|
|
** IP_forwarding is enabled.
|
|
** 2. Accept broadcast, or unicast packets with destinations that
|
|
** match node address.
|
|
*/
|
|
if ((testdata->pcb->IFSRC == search_ptr->NETIF || _IP_forward) &&
|
|
(testdata->ipdest == ip_bcast))
|
|
{
|
|
testdata->ifdest = search_ptr->DESTIF;
|
|
return TRUE;
|
|
} /* Endif */
|
|
|
|
search_ptr = search_ptr->NEXT;
|
|
} while (search_ptr != route->DIRECT);
|
|
} /* Endif */
|
|
|
|
return FALSE;
|
|
} /* Endbody */
|
|
|
|
uint_32 IP_route_local
|
|
(
|
|
RTCSPCB_PTR pcb,
|
|
/* [IN] the packet to send */
|
|
_ip_address ipdest
|
|
/* [IN] the ultimate destination */
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct ip_route_local_test testdata;
|
|
|
|
/*
|
|
** RFC 2131 says:
|
|
** "In the case of a client using DHCP for initial configuration (before
|
|
** the client's TCP/IP software has been completely configured), DHCP
|
|
** requires creative use of the client's TCP/IP software and liberal
|
|
** interpretation of RFC 1122. The TCP/IP software SHOULD accept and
|
|
** forward to the IP layer any IP packets delivered to the client's
|
|
** hardware address before the IP address is configured."
|
|
**
|
|
** So if the broadcast flag is disabled, we check, and if the packet's
|
|
** source interface is not bound, we send the packet to IF_LOCALHOST.
|
|
** This is paired with the same test in ip.c:IP_service(), which sends
|
|
** the packet here.
|
|
*/
|
|
if ((ipdest == INADDR_BROADCAST)
|
|
|| IN_MULTICAST(ipdest)
|
|
|| (!_DHCP_broadcast && (IP_get_ipif_addr(pcb->IFSRC) == INADDR_ANY))) {
|
|
/* Accept broadcasts and multicasts and unbound unicasts */
|
|
testdata.ifdest = RTCS_IF_LOCALHOST_PRV;
|
|
} else {
|
|
|
|
/* If unicast, check routing table */
|
|
testdata.ifdest = NULL;
|
|
testdata.ipdest = ipdest;
|
|
testdata.pcb = pcb;
|
|
IPRADIX_findbest(&IP_cfg_ptr->ROUTE_ROOT.NODE, ipdest,
|
|
IP_route_local_test, &testdata);
|
|
} /* Endif */
|
|
|
|
/* Send the packet to the interface. */
|
|
if (testdata.ifdest) {
|
|
return IP_send_dgram( RTCS_IF_LOCALHOST_PRV, pcb, 0, ipdest, ipdest, 0, NULL);
|
|
} /* Endif */
|
|
|
|
/* No interface was found. Discard the packet */
|
|
IF_IP_STATS_ENABLED(IP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
|
|
IF_IP_STATS_ENABLED(IP_cfg_ptr->STATS.ST_RX_ADDR_ERRORS++);
|
|
RTCSLOG_PCB_FREE(pcb, RTCSERR_IP_UNREACH);
|
|
RTCSPCB_free(pcb);
|
|
return RTCSERR_IP_UNREACH;
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route_multi
|
|
* Returned Value : RTCS_OK or error code
|
|
* Comments :
|
|
* Chooses one or more routes for a multicast or limited broadcast
|
|
* packet and sends it. Note: at the very least, the packet will
|
|
* be sent up to the localhost's transport layer.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
struct ip_route_multi_struct {
|
|
RTCSPCB_PTR pcb;
|
|
uint_32 protocol;
|
|
_ip_address ipsrc;
|
|
_ip_address ipdest;
|
|
uint_32 flags;
|
|
};
|
|
|
|
static boolean IP_route_multi_test
|
|
(
|
|
_ip_address node_ip,
|
|
_ip_address node_mask,
|
|
pointer node_data,
|
|
pointer data
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct ip_route_multi_struct _PTR_ testdata = data;
|
|
IP_ROUTE_PTR route = node_data;
|
|
IP_ROUTE_DIRECT_PTR direct;
|
|
IP_ROUTE_VIRTUAL_PTR virtual;
|
|
_ip_address ip_bcast;
|
|
RTCSPCB_PTR dup_pcb;
|
|
|
|
if (!route) {
|
|
return FALSE;
|
|
} /* Endif */
|
|
|
|
/* Calculate this route's broadcast address */
|
|
ip_bcast = node_ip | ~node_mask;
|
|
|
|
direct = route->DIRECT;
|
|
if (direct) {
|
|
do {
|
|
/* Note:
|
|
** 1. The packet is sent to LOCALHOST in IP_route_multi.
|
|
** 2. The source address must match one of the interface's address(es).
|
|
** 3. If the source address is broadcast or if it is specified, use
|
|
** this interface.
|
|
*/
|
|
if (direct->DESTIF != RTCS_IF_LOCALHOST_PRV &&
|
|
(testdata->ipsrc == INADDR_ANY ||
|
|
testdata->ipsrc == INADDR_BROADCAST ||
|
|
testdata->ipsrc == ip_bcast ||
|
|
testdata->ipsrc == direct->ADDRESS))
|
|
{
|
|
/*
|
|
** Make sure not to send the packet back to the interface it was
|
|
** received on.
|
|
*/
|
|
if (!(testdata->flags & IPROUTEOPT_RECVIF) ||
|
|
(testdata->pcb->IFSRC != direct->DESTIF))
|
|
{
|
|
/* We've chosen an interface. Duplicate the PCB and send it */
|
|
dup_pcb = RTCSPCB_alloc_dup(testdata->pcb);
|
|
if (dup_pcb) {
|
|
//RTCSLOG_PCB_ALLOC(dup_pcb);
|
|
IP_send_dgram(direct->DESTIF, dup_pcb, direct->ADDRESS,
|
|
testdata->ipdest, testdata->ipdest, testdata->protocol,
|
|
NULL);
|
|
} else {
|
|
IF_IP_STATS_ENABLED(IP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
direct = direct->NEXT;
|
|
} while (direct != route->DIRECT);
|
|
} /* Endif */
|
|
|
|
virtual = route->VIRTUAL;
|
|
if (virtual) {
|
|
do {
|
|
/*
|
|
** This section is similar to the direct route case above.
|
|
** However, we only want to send to numbered interfaces.
|
|
*/
|
|
if (virtual->DESTIF != RTCS_IF_LOCALHOST_PRV &&
|
|
virtual->ADDRESS &&
|
|
(testdata->ipsrc == INADDR_ANY ||
|
|
testdata->ipsrc == INADDR_BROADCAST ||
|
|
testdata->ipsrc == virtual->ADDRESS))
|
|
{
|
|
/*
|
|
** Make sure not to send the packet back to the interface it was
|
|
** received on.
|
|
*/
|
|
if (!(testdata->flags & IPROUTEOPT_RECVIF) ||
|
|
(testdata->pcb->IFSRC != virtual->DESTIF))
|
|
{
|
|
/* We've chosen an interface. Duplicate the PCB and send it */
|
|
dup_pcb = RTCSPCB_alloc_dup(testdata->pcb);
|
|
if (dup_pcb) {
|
|
//RTCSLOG_PCB_ALLOC(dup_pcb);
|
|
IP_send_dgram(virtual->DESTIF, dup_pcb, virtual->ADDRESS,
|
|
testdata->ipdest, testdata->ipdest, testdata->protocol,
|
|
NULL);
|
|
} else {
|
|
IF_IP_STATS_ENABLED(IP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
virtual = virtual->NEXT;
|
|
} while (virtual != route->VIRTUAL);
|
|
} /* Endif */
|
|
|
|
return FALSE;
|
|
} /* Endbody */
|
|
|
|
uint_32 IP_route_multi
|
|
(
|
|
RTCSPCB_PTR pcb,
|
|
/* [IN] the packet to send */
|
|
uint_32 protocol,
|
|
/* [IN] the transport layer protocol */
|
|
_ip_address ipsrc,
|
|
/* [IN] the destination interface (0 = any) */
|
|
_ip_address ipdest,
|
|
/* [IN] the ultimate destination */
|
|
uint_32 flags
|
|
/* [IN] optional flags */
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct ip_route_multi_struct testdata;
|
|
|
|
testdata.pcb = pcb;
|
|
testdata.protocol = protocol;
|
|
testdata.ipsrc = ipsrc;
|
|
testdata.ipdest = ipdest;
|
|
testdata.flags = flags;
|
|
|
|
IPRADIX_walk(&IP_cfg_ptr->ROUTE_ROOT.NODE, IP_route_multi_test, &testdata);
|
|
|
|
/*
|
|
** At this point, we've sent the packet out each interface it's
|
|
** intended for. Only the local host is left.
|
|
*/
|
|
|
|
if ((flags & IPROUTEOPT_RECVIF) &&
|
|
(pcb->IFSRC == RTCS_IF_LOCALHOST_PRV))
|
|
{
|
|
RTCSLOG_PCB_FREE(pcb, RTCS_OK);
|
|
RTCSPCB_free(pcb);
|
|
return RTCS_OK;
|
|
} /* Endif */
|
|
|
|
return IP_send_dgram( RTCS_IF_LOCALHOST_PRV, pcb, INADDR_LOOPBACK,
|
|
ipdest, ipdest, protocol, NULL);
|
|
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : IP_route
|
|
* Returned Value : RTCS_OK or error code
|
|
* Comments :
|
|
* Chooses a route for a packet and sends it. Note: this
|
|
* includes sending the packet up to the localhost's transport
|
|
* layer (by choosing ifdest == RTCS_IF_LOCALHOST_PRV).
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
struct ip_route_struct {
|
|
RTCSPCB_PTR pcb;
|
|
_ip_address ipsrc;
|
|
_ip_address ipdest;
|
|
uint_32 flags;
|
|
|
|
uint_32 retval;
|
|
boolean check_gateway;
|
|
IP_IF_PTR ifdest;
|
|
_ip_address hopdest;
|
|
_ip_address hopsrc;
|
|
RTCSPCB_PTR keep_pcb;
|
|
|
|
boolean sendit; /* Should we send out the packet ? */
|
|
boolean keepit; /* Should we send a copy to the localhost ? */
|
|
boolean hopsrcislocal;
|
|
pointer data; /* Routing entry data */
|
|
};
|
|
|
|
static boolean IP_route_test
|
|
(
|
|
pointer node_data,
|
|
pointer data
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct ip_route_struct _PTR_ testdata = data;
|
|
IP_ROUTE_PTR route = node_data;
|
|
IP_ROUTE_DIRECT_PTR direct = route->DIRECT;
|
|
IP_ROUTE_INDIRECT_PTR indirect = route->INDIRECT;
|
|
IP_ROUTE_VIRTUAL_PTR virtual = route->VIRTUAL;
|
|
_ip_address ip_bcast, source;
|
|
|
|
if (direct) {
|
|
|
|
/* Calculate this route's broadcast address */
|
|
ip_bcast = route->NODE.IP | ~route->NODE.MASK;
|
|
|
|
/* Reject a packet with a destination of 0 for the host IP */
|
|
if (~route->NODE.MASK && testdata->ipdest == route->NODE.IP) {
|
|
IF_IP_STATS_ENABLED(IP_cfg_ptr->STATS.COMMON.ST_TX_DISCARDED++);
|
|
return TRUE;
|
|
} /* Endif */
|
|
|
|
do {
|
|
/* source address must match (one of) the interface's address(es) */
|
|
if (testdata->hopsrc == INADDR_ANY||
|
|
testdata->hopsrc == INADDR_BROADCAST ||
|
|
testdata->hopsrc == ip_bcast ||
|
|
testdata->hopsrc == direct->ADDRESS ||
|
|
_IP_forward)
|
|
{
|
|
/*
|
|
** At this point we've chosen an interface.
|
|
** Now decide whether destination is unicast or
|
|
** directed broadcast.
|
|
*/
|
|
|
|
/* Use this interface's source address if we don't have one */
|
|
if (!testdata->hopsrcislocal) {
|
|
testdata->hopsrc = direct->ADDRESS;
|
|
} /* Endif */
|
|
|
|
/*
|
|
** Decide if we should send a copy to the local host. We want to
|
|
** send a copy to the local host if it is a directed broadcast.
|
|
*/
|
|
testdata->keepit = (~route->NODE.MASK && testdata->ipdest == ip_bcast);
|
|
testdata->sendit = TRUE;
|
|
|
|
#if RTCSCFG_IP_DISABLE_DIRECTED_BROADCAST
|
|
if (testdata->keepit) {
|
|
/*
|
|
** If this is a directed broadcast, discard it. Don't even
|
|
** keep a copy for the localhost.
|
|
*/
|
|
testdata->keepit = FALSE;
|
|
testdata->sendit = FALSE;
|
|
} /* Endif */
|
|
#endif
|
|
|
|
/*
|
|
** IPROUTEOPT_RECVIF means that we must not send the packet
|
|
** out the interface it was received on. This is turned on
|
|
** when we receive a broadcast (because everyone on that
|
|
** network already received a copy), and also when originating
|
|
** a packet with the MSG_NOLOOP flag.
|
|
*/
|
|
if (testdata->flags & IPROUTEOPT_RECVIF) {
|
|
if (testdata->keepit) {
|
|
/*
|
|
** If broadcast packet, set hopdest to INADDR_BROADCAST.
|
|
*/
|
|
testdata->hopdest = INADDR_BROADCAST;
|
|
} /* Endif */
|
|
testdata->keepit = testdata->keepit && (testdata->pcb->IFSRC != RTCS_IF_LOCALHOST_PRV);
|
|
testdata->sendit = testdata->sendit && (testdata->pcb->IFSRC != direct->DESTIF);
|
|
} /* Endif */
|
|
|
|
/*
|
|
** This #if is purely for code size reduction. If directed
|
|
** broadcasts are disabled, keepit will always be false.
|
|
*/
|
|
#if !RTCSCFG_IP_DISABLE_DIRECTED_BROADCAST
|
|
|
|
if (testdata->keepit) {
|
|
|
|
/*
|
|
** If keepit and sendit:
|
|
**
|
|
** We will need two PCB's. One to send out of the interface and
|
|
** one to send up to the localhost. The packet is being sent to both
|
|
** interfaces because it is a broadcast packet, so we set hopdest to
|
|
** INADDR_BROADCAST. We also set the destif to the network interface
|
|
** and we don't bother saving a pointer to the locahost interface
|
|
** because it is already accessible in the IP_CFG_STRUCT.
|
|
*/
|
|
if (testdata->sendit) {
|
|
testdata->ifdest = direct->DESTIF;
|
|
testdata->hopdest = INADDR_BROADCAST;
|
|
|
|
testdata->keep_pcb = RTCSPCB_alloc_dup(testdata->pcb);
|
|
if (!testdata->keep_pcb) {
|
|
IF_IP_STATS_ENABLED(IP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
/* If keepit and !sendit:
|
|
**
|
|
** This means that a direct broadcast was received, and the network
|
|
** it was received from is the destination network.
|
|
** eg: The packet is received from an interface connected to a
|
|
** network 192.168.1.0 and the packet destination is 192.168.1.255
|
|
** If it was received on its destination network everybody on that
|
|
** network also received a copy. There is no reason to send it back
|
|
** out, so we send it to the localhost only.
|
|
** The packet was a broadcast packet, so hopdest = INADDR_BROADCAST.
|
|
** But IP_route will know this if keepit is true, so we don't bother
|
|
** setting hopdest.
|
|
*/
|
|
else {
|
|
testdata->keep_pcb = testdata->pcb;
|
|
} /* Endif */
|
|
|
|
} else
|
|
#endif
|
|
|
|
/* If !keepit and sendit:
|
|
**
|
|
** This is the case when we receive a unicast packet. We simply send
|
|
** it out of the chosen interface (set ifdest). We could be sending
|
|
** this packet directly to the destination, or we could be sending
|
|
** it to a gateway. If we are sending it to a gateway, hopdest is
|
|
** already set to the address of the gateway, so we don't modify it.
|
|
** Otherwise, if we are sending directly to the destination, set
|
|
** hopdest to the destination IP.
|
|
*/
|
|
if (testdata->sendit) {
|
|
testdata->ifdest = direct->DESTIF;
|
|
if (!testdata->hopdest) {
|
|
testdata->hopdest = testdata->ipdest;
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
/* If !keepit and !sendit:
|
|
**
|
|
** Do nothing, and IP_route will silently discard the packet.
|
|
*/
|
|
else { } /* Endif */
|
|
|
|
/* Use a different interface next time */
|
|
route->DIRECT = route->DIRECT->NEXT;
|
|
testdata->retval = RTCS_OK;
|
|
return TRUE;
|
|
} /* Endif */
|
|
|
|
direct = direct->NEXT;
|
|
} while(direct != route->DIRECT);
|
|
} /* Endif */
|
|
|
|
/*
|
|
** Reaching this point means that the destination isn't directly connected
|
|
** to us. Check for a virtual route (tunnel, unnumbered interface or other).
|
|
** Only send packets out of interfaces, never directly to localhost
|
|
*/
|
|
|
|
if (virtual && !(testdata->flags & IPROUTEOPT_NOVIRTUAL)) {
|
|
|
|
/*
|
|
** If we are forwarding the packet, ipsrc is set to the source address
|
|
** of the IP header. If we are originating a packet, hopsrc is set to the
|
|
** IP address of the local originating interface
|
|
*/
|
|
source = testdata->ipsrc ? testdata->ipsrc : testdata->hopsrc;
|
|
|
|
do {
|
|
/*
|
|
** The following THREE conditions must be TRUE:
|
|
**
|
|
** 1. One of the following:
|
|
** a) source address must be INADDR_ANY (means pick the source of
|
|
** the interface), OR
|
|
** b) source address must be INADDR_BROADCAST, in which case the
|
|
** IP source address becomes the source of the interface, OR
|
|
** c) the source address matches the interface address, OR
|
|
** d) IP forwarding is enabled
|
|
**
|
|
** 2. If we are not forwarding a packet, the local hop source must be
|
|
** specified (hopsrc != INADDR_ANY) or the interface must have a
|
|
** source address (which we will use when we have no hopsrc).
|
|
** NOTE: (testdata->ipsrc != INADDR_ANY) means we are forwarding
|
|
**
|
|
** 3. The source IP of the packet must be within the source network
|
|
** allowed by the interface
|
|
*/
|
|
if ((testdata->hopsrc == INADDR_ANY ||
|
|
testdata->hopsrc == INADDR_BROADCAST ||
|
|
testdata->hopsrc == virtual->ADDRESS ||
|
|
_IP_forward) &&
|
|
(virtual->ADDRESS || testdata->ipsrc || testdata->hopsrcislocal) &&
|
|
((source & virtual->SOURCE_MASK) == virtual->SOURCE_NET))
|
|
{
|
|
/*
|
|
** At this point we've chosen an interface.
|
|
*/
|
|
|
|
/* Use this interface's source address if we don't have one */
|
|
if (!testdata->hopsrcislocal) {
|
|
testdata->hopsrc = virtual->ADDRESS;
|
|
if (!testdata->hopsrc) {
|
|
testdata->hopsrc = testdata->ipsrc;
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
/*
|
|
**
|
|
** This is the case when we receive a unicast packet. We simply send
|
|
** it out of the chosen interface (set ifdest). We could be sending
|
|
** this packet directly to the destination, or we could be sending
|
|
** it to a gateway. If we are sending it to a gateway, hopdest is
|
|
** already set to the address of the gateway, so we don't modify it.
|
|
** Otherwise, if we are sending directly to the destination, set
|
|
** hopdest to the destination IP.
|
|
*/
|
|
|
|
testdata->ifdest = virtual->DESTIF;
|
|
if (!testdata->hopdest) {
|
|
testdata->hopdest = testdata->ipdest;
|
|
} /* Endif */
|
|
|
|
/* Use a different interface next time */
|
|
route->VIRTUAL = route->VIRTUAL->NEXT;
|
|
testdata->sendit = TRUE;
|
|
testdata->retval = RTCS_OK;
|
|
testdata->data = virtual->DATA;
|
|
return TRUE;
|
|
} /* Endif */
|
|
|
|
virtual = virtual->NEXT;
|
|
} while(virtual != route->VIRTUAL);
|
|
|
|
} /* Endif */
|
|
|
|
/*
|
|
** Reaching this point means that the destination isn't directly connected
|
|
** to us. Check for a gateway (if we haven't done so already).
|
|
*/
|
|
|
|
if (indirect && testdata->check_gateway) {
|
|
do {
|
|
if (indirect->FLAGS & RTF_UP) {
|
|
testdata->hopdest = indirect->GATEWAY;
|
|
|
|
/* Notify calling function that a gateway was found */
|
|
testdata->check_gateway = FALSE;
|
|
|
|
return TRUE;
|
|
} /* Endif */
|
|
|
|
indirect = indirect->NEXT;
|
|
} while(indirect != route->INDIRECT);
|
|
} /* Endif */
|
|
|
|
return FALSE;
|
|
} /* Endbody */
|
|
|
|
|
|
uint_32 IP_route
|
|
(
|
|
RTCSPCB_PTR pcb,
|
|
/* [IN] the packet to send */
|
|
uint_32 protocol,
|
|
/* [IN] the transport layer protocol */
|
|
_ip_address hopsrc,
|
|
/* [IN] the destination interface (0 = any) */
|
|
_ip_address ipsrc,
|
|
/* [IN]the ultimate source */
|
|
_ip_address ipdest,
|
|
/* [IN] the ultimate destination */
|
|
uint_32 flags
|
|
/* [IN] optional flags */
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct ip_route_struct testdata;
|
|
|
|
RTCSLOG_FNE4(RTCSLOG_FN_IP_route, pcb, protocol, hopsrc);
|
|
|
|
testdata.pcb = pcb;
|
|
testdata.ipsrc = ipsrc;
|
|
testdata.ipdest = ipdest;
|
|
testdata.flags = flags;
|
|
|
|
testdata.retval = RTCSERR_IP_UNREACH;
|
|
testdata.check_gateway = TRUE;
|
|
testdata.ifdest = NULL;
|
|
testdata.hopdest = INADDR_ANY;
|
|
testdata.keep_pcb = NULL;
|
|
|
|
testdata.keepit = FALSE;
|
|
testdata.sendit = FALSE;
|
|
testdata.hopsrc = hopsrc;
|
|
testdata.hopsrcislocal = IP_is_local(NULL, hopsrc);
|
|
testdata.data = NULL;
|
|
|
|
IPRADIX_findbest(&IP_cfg_ptr->ROUTE_ROOT.NODE, ipdest, IP_route_test, &testdata);
|
|
|
|
/* If we have found a gateway, find an interface for the gateway */
|
|
if (!testdata.check_gateway) {
|
|
IPRADIX_findbest(&IP_cfg_ptr->ROUTE_ROOT.NODE, testdata.hopdest,
|
|
IP_route_test, &testdata);
|
|
} /* Endif */
|
|
|
|
/* Discard the packet */
|
|
if (testdata.retval || (!testdata.keepit && !testdata.sendit)) {
|
|
RTCSLOG_PCB_FREE(pcb, testdata.retval);
|
|
RTCSPCB_free(pcb);
|
|
RTCSLOG_FNX2(RTCSLOG_FN_IP_route, testdata.retval);
|
|
return testdata.retval;
|
|
} /* Endif */
|
|
|
|
/* Should we send to localhost? */
|
|
if (testdata.keepit && testdata.keep_pcb) {
|
|
testdata.retval = IP_send_dgram( RTCS_IF_LOCALHOST_PRV,
|
|
testdata.keep_pcb, testdata.hopsrc, INADDR_BROADCAST, ipdest, protocol,
|
|
NULL);
|
|
} /* Endif */
|
|
|
|
/* Should we send it out? */
|
|
if (testdata.sendit) {
|
|
testdata.retval = IP_send_dgram(testdata.ifdest, pcb, testdata.hopsrc,
|
|
testdata.hopdest, ipdest, protocol, testdata.data);
|
|
} /* Endid */
|
|
|
|
RTCSLOG_FNX2(RTCSLOG_FN_IP_route, testdata.retval);
|
|
return testdata.retval;
|
|
} /* Endbody */
|
|
|
|
|
|
#endif /* RTCSCFG_ENABLE_IP4 */
|
|
|
|
|
|
/* EOF */
|