You've already forked Frequency_Inverter
mirror of
https://github.com/Indemsys/Frequency_Inverter.git
synced 2026-05-05 13:17:53 +00:00
1296 lines
39 KiB
C
1296 lines
39 KiB
C
/**HEADER********************************************************************
|
|
*
|
|
* Copyright (c) 2008 Freescale Semiconductor;
|
|
* All Rights Reserved
|
|
*
|
|
* Copyright (c) 2004-2008 Embedded Access Inc.;
|
|
* 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: rip.c$
|
|
* $Version : 3.8.12.0$
|
|
* $Date : Sep-19-2012$
|
|
*
|
|
* Comments:
|
|
*
|
|
* This file contains the implementation of RIPv1 and v2,
|
|
* the Routing Information Protocol. For more details,
|
|
* refer to RFC2453.
|
|
* KNOWN BUGS:
|
|
* - just after the shutdown advertise all the routes with an max (no infinite)
|
|
* metric aka 15. thus the other routers doesnt have to wait for the end of
|
|
* the timeout. question: how do i know when the board shutdown?
|
|
* it seems impossible :( perhaps with a network call... snmp set
|
|
* - how to do the router administration ? etc.. snmp set? and the security ?
|
|
* - how to advertize particular route such as default. currently i dont
|
|
* adertize it.
|
|
* - passwd and md5 authentification extensions are not handled.
|
|
* - i missed something in the nexthop field and the reverse poison, the
|
|
* metric must be advertized with a infinite metric on the interface
|
|
* from which it has been learned.
|
|
* ok BUT only if this route has been learned with RIP. not if it is a external
|
|
* route/no static route (because there is not source interface).
|
|
* and perhaps other cases... like on demand circuit.
|
|
* > > in which case the nexthop field is usefull ?
|
|
* >
|
|
* > One obvious case -- exporting from a foreign routing protocol (like
|
|
* > OSPF or BGP).
|
|
* >
|
|
* > Another very useful case for the next hop field in RIPv2 is to allow
|
|
* > for better handling of routes on demand circuits. In the Annex, we
|
|
* > put the next hop into the advertisement even if it wasn't directly
|
|
* > reachable on that same subnet. I think Gary wrote an applicability
|
|
* > statement concerning this use afterwards.
|
|
* >
|
|
* > Suppose you have nodes A and B which can both dial into C on demand.
|
|
* > A dials in and learns a number of routes from C and advertises them on
|
|
* > a local network that B sees. A hangs up from C and then B dials in.
|
|
* >
|
|
* > When B learns routes from C, it advertises C as the next hop. When A
|
|
* > sees this, it immediately sets its local copies of those routes to
|
|
* > infinity and purges them from the world by doing a triggered
|
|
* > advertisement. That way, other hosts don't have to wait for A's old
|
|
* > routes to age out and B's to become preferred.
|
|
* TODO:
|
|
* - the icmp/redirect route must be modified to.
|
|
* - handle the case of removing the interface or the device.
|
|
* - must handle several route for a given destination with the same metric.
|
|
* - check response validity.
|
|
* - if a route metric reaches the max, the route is down.
|
|
* - the debian routed send the packet to the network broadcast and not
|
|
* the limited broadcast, what is the proper behaviour ? gated routed do
|
|
* the same. DONE i have decided it was the good one.
|
|
* - if an static route is removed, start the deletion process. dont simply
|
|
* remove it. thus the route is advertized with an infinite metric.
|
|
* - implement the POLL unofficial/gated command. i.e. a response
|
|
* without splithorizon/reverse poison.
|
|
* - DONE send/received multicast for ripv2 (and ospf) (change igmp to do
|
|
* it without socket. directly in ucb) seb said ok
|
|
*
|
|
*END************************************************************************/
|
|
|
|
|
|
/* local include */
|
|
#include <rtcs.h>
|
|
#include "rtcs_prv.h"
|
|
#include "tcpip.h"
|
|
#include "ip_prv.h"
|
|
#include "udp_prv.h"
|
|
#include "rip.h"
|
|
#include "route.h"
|
|
#if RTCSCFG_ENABLE_RIP && RTCSCFG_ENABLE_IP4
|
|
|
|
#define RND_RANGE(min,max) ((min) + RTCS_rand()%(((max)-(min))?((max)-(min)):1))
|
|
#ifndef min
|
|
#define min(a,b) ((a)<(b)?(a):(b))
|
|
#endif
|
|
|
|
#define RIP_PKT_MAXLEN 500 /* find the right number */
|
|
#define RIP_AF_INET 2 /* MUST be 2. rtcs AF_INET is 1! */
|
|
#define DEFAULT_ROUTE_TAG 0
|
|
#define NETWORK_COST 1 /* must be at least 1 */
|
|
#define SPLIT_HORIZON_WITHOUT_POISONNED_REVERSE 0
|
|
#define ADV_VERSION RIP_V2
|
|
|
|
|
|
static void RIP_trig_upd(void);
|
|
static boolean RIP_expire_periodic(TCPIP_EVENT_PTR);
|
|
static uint_32 RIP_send_req(void);
|
|
void RIP_service(RTCSPCB_PTR, UCB_STRUCT_PTR);
|
|
|
|
IP_ROUTE_FN RIP_routefn = {
|
|
NULL,
|
|
RIP_new_bindif,
|
|
RIP_init_static_rt,
|
|
RIP_remove_rt
|
|
};
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_init
|
|
* Returned Values : uint_32
|
|
* Comments : Initialize the RIP layer.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
uint_32 RIP_init (void)
|
|
{ /* Body */
|
|
RIP_CFG_STRUCT_PTR cfg = RTCS_getcfg(RIP);
|
|
uint_32 err;
|
|
|
|
if (RTCS_getcfg(RIP)) return RTCS_OK;
|
|
/* allocate the memory */
|
|
cfg = RTCS_mem_alloc_zero(sizeof(*cfg));
|
|
if (!cfg) return RTCSERR_OUT_OF_MEMORY;
|
|
/* bind the udp port */
|
|
err = UDP_openbind_internal(IPPORT_RIP, RIP_service, &cfg->UCB);
|
|
if (err){
|
|
_mem_free(cfg);
|
|
return err;
|
|
}
|
|
|
|
RTCS_setcfg(RIP, cfg);
|
|
ROUTE_register(&RIP_routefn);
|
|
|
|
/* Start the retransmission timer to start sending immediately */
|
|
cfg->TIMER_PERIODIC.TIME = 0;
|
|
cfg->TIMER_PERIODIC.EVENT = RIP_expire_periodic;
|
|
cfg->TIMER_PERIODIC.PRIVATE = NULL;
|
|
TCPIP_Event_add(&cfg->TIMER_PERIODIC);
|
|
|
|
/* probe all the interfaces now to build the route table faster */
|
|
err = RIP_send_req();
|
|
|
|
return RTCS_OK;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_cpu_metric
|
|
* Returned Values :
|
|
* Comments : rfc2453.3.9.2
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 RIP_cpu_metric(
|
|
RTCSPCB_PTR pcb, /* [IN] incoming packet */
|
|
uint_32 oldmetric
|
|
)
|
|
{ /* Body */
|
|
uint_32 metric = NETWORK_COST + oldmetric;
|
|
/* if a cost per interface is required, do that here. But before that,
|
|
** think about the unit problem between the routing protocols.
|
|
*/
|
|
return min(metric, RIP_MAX_METRIC);
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_build_header
|
|
* Returned Values : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void RIP_build_header(
|
|
uchar_ptr buf, /* [OUT] the rip header */
|
|
uint_8 cmd, /* [IN] the commande */
|
|
uint_8 version /* [IN] the version */
|
|
)
|
|
{ /* Body */
|
|
RIP_HEADER_PTR hd = (RIP_HEADER_PTR)buf;
|
|
_mem_zero(buf, sizeof(RIP_HEADER));
|
|
htonc(hd->COMMAND, cmd);
|
|
htonc(hd->VERSION, version);
|
|
htons(hd->MBZ, 0);
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_build_rte
|
|
* Returned Values : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void RIP_build_rte(
|
|
uchar_ptr buf, /* [OUT] the route entry */
|
|
uint_16 family,
|
|
uint_16 rt_tag,
|
|
_ip_address net_addr,
|
|
_ip_address net_mask,
|
|
_ip_address next_hop,
|
|
uint_32 metric,
|
|
uint_32 rip_vers
|
|
)
|
|
{ /* Body */
|
|
RIP_ENTRY_PTR rte = (RIP_ENTRY_PTR)buf;
|
|
if (rip_vers == RIP_V2){
|
|
htons(rte->RT_TAG, rt_tag);
|
|
htonl(rte->NETMASK, net_mask);
|
|
htonl(rte->NEXTHOP, next_hop);
|
|
}else{
|
|
_mem_zero(buf, sizeof(RIP_ENTRY));
|
|
}
|
|
htons(rte->FAMILY, family);
|
|
htonl(rte->NETADDR, net_addr);
|
|
htonl(rte->METRIC, metric);
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_send_pkt
|
|
* Returned Values :
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 RIP_send_pkt(
|
|
IP_IF_PTR ipif, /* [IN] the outgoing interface */
|
|
_ip_address ipdst, /* [IN] the destination ip */
|
|
uint_16 portdst,/* [IN] the destination port */
|
|
uchar_ptr data, /* [IN] the data to send */
|
|
uint_32 len /* [IN] the length of data to send */
|
|
)
|
|
{ /* Body */
|
|
RTCSPCB_PTR pcb;
|
|
RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP);
|
|
RIP_HEADER_PTR hd = (RIP_HEADER_PTR)data;
|
|
uint_32 err;
|
|
_ip_address ipsrc = IP_get_ipif_addr(ipif);
|
|
|
|
if (ipsrc == INADDR_ANY) {
|
|
_mem_free(data);
|
|
return RTCS_OK;
|
|
} /* Endif */
|
|
|
|
/* Allocate a PCB */
|
|
pcb = RTCSPCB_alloc_send();
|
|
if (pcb == NULL) {
|
|
_mem_free(data);
|
|
return RTCSERR_PCB_ALLOC;
|
|
} /* Endif */
|
|
|
|
//RTCSLOG_PCB_ALLOC(pcb);
|
|
|
|
/* add my data in the pcb */
|
|
err = RTCSPCB_append_fragment_autofree(pcb, len, data);
|
|
if (err) {
|
|
_mem_free(data);
|
|
RTCSLOG_PCB_FREE(pcb, err);
|
|
RTCSPCB_free(pcb);
|
|
return err;
|
|
} /* Endif */
|
|
|
|
RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PORT(IPPORT_RIP), ntohc(hd->VERSION));
|
|
|
|
/* dont advertize in limited broadcast but in ip broadcast */
|
|
if (ipdst == INADDR_BROADCAST){
|
|
_ip_address netmask;
|
|
|
|
ipdst = IP_get_ipif_addr(ipif); /* Get IP address of interface */
|
|
IP_get_netmask(ipif, ipdst, &netmask); /* Get netmask */
|
|
|
|
ipdst = ipdst | ~netmask;
|
|
} /* Endif */
|
|
|
|
/* send it */
|
|
/* use a flag to prevent the broadcast/multicast packet from
|
|
** looping back to us.
|
|
*/
|
|
return UDP_send_internal(ripcfg->UCB, ipsrc, ipdst, portdst, pcb, RTCS_MSG_NOLOOP);
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_is_valid_rte
|
|
* Returned Values :
|
|
* Comments : rfc2453.3.9.2
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 RIP_is_valid_rte(
|
|
RIP_ENTRY_PTR rte
|
|
)
|
|
{ /* Body */
|
|
uint_32 metric = ntohl(rte->METRIC);
|
|
_ip_address netaddr = ntohl(rte->NETADDR);
|
|
if (ntohs(rte->FAMILY) != RIP_AF_INET) return 0;
|
|
if (metric > RIP_MAX_METRIC || metric < RIP_MIN_METRIC) return 0;
|
|
if (IN_MULTICAST(netaddr) || IN_EXPERIMENTAL(netaddr)) return 0;
|
|
if (IN_LOOPBACK(netaddr)) return 0;
|
|
|
|
{
|
|
_ip_address nexthop = ntohl(rte->NEXTHOP);
|
|
|
|
if (nexthop!= 0) {
|
|
if (IP_is_local(NULL, nexthop)) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_is_valid_resp
|
|
* Returned Values :
|
|
* Comments : rfc2453.3.9.2
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 RIP_is_valid_resp(
|
|
RTCSPCB_PTR pcb /* [IN/OUT] incoming packet */
|
|
)
|
|
{ /* Body */
|
|
uint_32 ipsrc = IP_source(pcb);
|
|
uint_16 srcport = UDP_source(pcb);
|
|
/*
|
|
** check the source port is IPPORT_ROUTE, just a weak security.
|
|
** On BSD-like network stack, accessing to the ports < 1024
|
|
** requires privileges.
|
|
*/
|
|
if (srcport != IPPORT_RIP) return FALSE;
|
|
/*
|
|
** if the ipsrc is NOT on a directly connected network which
|
|
** received the packet, it is not valid
|
|
*/
|
|
if (IP_is_direct(pcb->IFSRC,ipsrc) == FALSE) return FALSE;
|
|
/*
|
|
** If this packet is one of mine, it is not valid.
|
|
** It can happen in case of more than one interfaces are
|
|
** directly connected to the same network.
|
|
*/
|
|
if (IP_is_local(NULL,ipsrc) == TRUE) return FALSE;
|
|
return 1;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_send_resp_ipif
|
|
* Returned Values : boolean
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
struct RIP_send_resp_ipif_struct {
|
|
IP_IF_PTR ipif;
|
|
_ip_address ipdest;
|
|
uint_32 rip_vers;
|
|
uint_32 onlyChangeF;
|
|
uchar_ptr pkt;
|
|
uchar_ptr curs;
|
|
uint_16 portdst;
|
|
};
|
|
|
|
static boolean RIP_send_resp_ipif_test
|
|
(
|
|
_ip_address node_ip,
|
|
_ip_address node_mask,
|
|
pointer node_data,
|
|
pointer data
|
|
)
|
|
{ /* Body */
|
|
struct RIP_send_resp_ipif_struct _PTR_ testdata = data;
|
|
IP_ROUTE_PTR route = node_data;
|
|
IP_ROUTE_INDIRECT_PTR gate, end;
|
|
_ip_address nexthop, iplist[2];
|
|
uint_32 metric, rtype, vcount;
|
|
boolean complete = FALSE;
|
|
pointer rstart[3];
|
|
|
|
/* If this node has no entries, return */
|
|
if (!route) {
|
|
return FALSE;
|
|
} /* Endif */
|
|
|
|
rstart[0] = route->DIRECT;
|
|
rstart[1] = route->VIRTUAL;
|
|
rstart[2] = route->INDIRECT;
|
|
|
|
/*
|
|
** If there are no connected networks, return. If the node_mask is other than
|
|
** 255.255.255.255 there is a connected network. There can be a virutal
|
|
** network even when all the netmask bits are set if the node_ip is different
|
|
** than the VIRTUAL ADDRESS (like in the case of PPP)
|
|
*/
|
|
if (!~node_mask) {
|
|
if (!(route->VIRTUAL && node_ip != route->VIRTUAL->ADDRESS)) {
|
|
return FALSE;
|
|
} /* Endif */
|
|
|
|
/* Only check the VIRTUAL routes */
|
|
rstart[0] = NULL;
|
|
rstart[2] = NULL;
|
|
} /* Endif */
|
|
|
|
for (rtype = 0, gate = NULL; rtype <= 2 && !gate; rtype++) {
|
|
gate = rstart[rtype];
|
|
} /* Endfor */
|
|
|
|
if (!gate) {
|
|
return FALSE;
|
|
} /* Endif */
|
|
|
|
end = gate;
|
|
iplist[1] = node_ip;
|
|
do {
|
|
do {
|
|
vcount = 2;
|
|
do {
|
|
/* Don't gather information about tunnels */
|
|
if (gate == rstart[1] && !route->VIRTUAL->ADDRESS) {
|
|
break;
|
|
} /* Endif */
|
|
|
|
if (vcount == 1) {
|
|
iplist[0] = route->VIRTUAL->ADDRESS;
|
|
} /* Endif */
|
|
|
|
/* allocate the packet memory */
|
|
if (!testdata->pkt) {
|
|
testdata->pkt = testdata->curs = RTCS_mem_alloc_system(RIP_MAX_PKTLEN);
|
|
if (!testdata->pkt) return RTCSERR_OUT_OF_MEMORY;
|
|
|
|
/* build the header */
|
|
RIP_build_header(testdata->curs, RIPCMD_RESPONSE, testdata->rip_vers);
|
|
testdata->curs += sizeof(RIP_HEADER);
|
|
} /* Endif */
|
|
|
|
if (testdata->onlyChangeF && !gate->RIP.CHANGED_F) {
|
|
break;
|
|
} /* Endif */
|
|
|
|
/* dont advertize the icmp redirect route */
|
|
if (gate->FLAGS & RTF_REDIRECT) {
|
|
break;
|
|
} /* Endif */
|
|
|
|
metric = gate->RIP.METRIC;
|
|
|
|
#if SPLIT_HORIZON_WITHOUT_POISONNED_REVERSE
|
|
/* split horizon. rfc2453.3.4.3.
|
|
** DONT advertize a route on the interface on
|
|
** which you received it.
|
|
*/
|
|
if (gate->RIP.IPIFSRC == testdata->ipif) {
|
|
break;
|
|
} /* Endif */
|
|
#else
|
|
/* split horizon with poisoned reverse. rfc2453.3.4.3
|
|
** DO advertize a route on the interface on
|
|
** which you received it BUT with a infinit metric.
|
|
*/
|
|
if (gate->RIP.IPIFSRC == testdata->ipif) {
|
|
metric = RIP_MAX_METRIC;
|
|
} /* Endif */
|
|
#endif
|
|
/* the outgoing nexthop. rfc2453.4.4. */
|
|
nexthop = 0;
|
|
if (IP_is_direct(testdata->ipif, gate->GATEWAY)) {
|
|
if (end == route->INDIRECT) {
|
|
nexthop = gate->GATEWAY;
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
|
|
/* build the route entry */
|
|
RIP_build_rte(testdata->curs, RIP_AF_INET, gate->RIP.RT_TAG
|
|
, iplist[vcount - 1], node_mask
|
|
, nexthop, metric, testdata->rip_vers);
|
|
|
|
/* check if it is valid before sending it */
|
|
if (!RIP_is_valid_rte((RIP_ENTRY_PTR)testdata->curs)) {
|
|
break;
|
|
} /* Endif */
|
|
|
|
|
|
testdata->curs += sizeof(RIP_ENTRY);
|
|
|
|
/* if the packet is full, send it and come back later */
|
|
if (testdata->curs-testdata->pkt >= sizeof(RIP_HEADER)+RIP_MAX_PKTLEN) {
|
|
RIP_send_pkt(testdata->ipif, testdata->ipdest, testdata->portdst,
|
|
testdata->pkt, testdata->curs-testdata->pkt);
|
|
/* pkt is freed, reset pointer to NULL */
|
|
testdata->pkt = NULL;
|
|
} /* Endif */
|
|
vcount--;
|
|
} while (end && end == (pointer)route->VIRTUAL && vcount);
|
|
gate = gate->NEXT;
|
|
} while (gate != end);
|
|
|
|
for (gate = NULL; rtype <= 2 && !gate; rtype++) {
|
|
gate = rstart[rtype];
|
|
} /* Endfor */
|
|
end = gate;
|
|
} while(gate);
|
|
return FALSE;
|
|
} /* Endbody */
|
|
|
|
static uint_32 RIP_send_resp_ipif (
|
|
IP_IF_PTR ipif, /* [IN] the destination interface */
|
|
_ip_address ipdest, /* [IN] the destination ip address */
|
|
uint_16 portdst, /* [IN] the destination port */
|
|
uint_32 rip_vers,/* [IN] the rip version */
|
|
uint_32 onlyChangeF /* [IN] TRUE if only the changed routes are sent */
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct RIP_send_resp_ipif_struct testdata;
|
|
|
|
testdata.ipif = ipif;
|
|
testdata.ipdest = ipdest;
|
|
testdata.portdst = portdst;
|
|
testdata.onlyChangeF = onlyChangeF;
|
|
testdata.rip_vers = rip_vers;
|
|
testdata.pkt = NULL;
|
|
testdata.curs = NULL;
|
|
|
|
IPRADIX_walk(&IP_cfg_ptr->ROUTE_ROOT.NODE, RIP_send_resp_ipif_test, &testdata);
|
|
|
|
/* if the packet is empty, dont send it */
|
|
if (testdata.curs-testdata.pkt == sizeof(RIP_HEADER)){
|
|
_mem_free(testdata.pkt);
|
|
} else {
|
|
/* send the packet */
|
|
RIP_send_pkt(ipif, ipdest, portdst, testdata.pkt,
|
|
testdata.curs - testdata.pkt);
|
|
} /* Endif */
|
|
|
|
return RTCS_OK;
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_send_resp
|
|
* Returned Values : boolean
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
struct RIP_send_resp_struct {
|
|
IP_IF_PTR localhost;
|
|
uint_32 onlyChangeF;
|
|
_ip_address ipdest;
|
|
uint_32 rip_vers;
|
|
uint_32 nb_try;
|
|
uint_32 nb_fail;
|
|
};
|
|
|
|
static boolean RIP_send_resp_test
|
|
(
|
|
_ip_address node_ip,
|
|
_ip_address node_mask,
|
|
pointer node_data,
|
|
pointer data
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_PTR route = node_data;
|
|
struct RIP_send_resp_struct _PTR_ testdata = data;
|
|
uint_32 error;
|
|
|
|
if (route && route->DIRECT) {
|
|
/* Don't advertise on local interface */
|
|
if (route->DIRECT->DESTIF != testdata->localhost) {
|
|
testdata->nb_try++;
|
|
error = RIP_send_resp_ipif(route->DIRECT->DESTIF, testdata->ipdest,
|
|
IPPORT_RIP, testdata->rip_vers, testdata->onlyChangeF);
|
|
if (error != RTCS_OK) {
|
|
testdata->nb_fail++;
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
if (route && route->VIRTUAL && route->VIRTUAL->ADDRESS) {
|
|
/* Don't advertise on local interface */
|
|
if (route->VIRTUAL->DESTIF != testdata->localhost) {
|
|
testdata->nb_try++;
|
|
error = RIP_send_resp_ipif(route->VIRTUAL->DESTIF, testdata->ipdest,
|
|
IPPORT_RIP, testdata->rip_vers, testdata->onlyChangeF);
|
|
if (error != RTCS_OK) {
|
|
testdata->nb_fail++;
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
return FALSE;
|
|
} /* Endbody */
|
|
|
|
static boolean RIP_send_resp_test2
|
|
(
|
|
_ip_address node_ip,
|
|
_ip_address node_mask,
|
|
pointer node_data,
|
|
pointer data
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_PTR route = node_data;
|
|
IP_ROUTE_INDIRECT_PTR indirect;
|
|
pointer p[3];
|
|
uint_32 i;
|
|
|
|
if (!route) {
|
|
return FALSE;
|
|
} /* Endif */
|
|
|
|
p[0] = route->DIRECT;
|
|
p[1] = route->INDIRECT;
|
|
p[2] = route->VIRTUAL;
|
|
|
|
for (i = 0; i <= 2; i++) {
|
|
if (!p[i]) {
|
|
continue;
|
|
} /* Endif */
|
|
|
|
indirect = p[i];
|
|
do {
|
|
indirect->RIP.CHANGED_F = FALSE;
|
|
indirect = indirect->NEXT;
|
|
} while(indirect != p[i]);
|
|
} /* Endfor */
|
|
|
|
return FALSE;
|
|
} /* Endbody */
|
|
|
|
static uint_32 RIP_send_resp(
|
|
uint_32 rip_vers, /* [IN] the rip version */
|
|
uint_32 onlyChangeF /* [IN] TRUE if only the changed routes are sent */
|
|
)
|
|
{ /* Body */
|
|
RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP);
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct RIP_send_resp_struct testdata;
|
|
|
|
testdata.nb_try = 0;
|
|
testdata.nb_fail = 0;
|
|
testdata.localhost = RTCS_IF_LOCALHOST_PRV;
|
|
testdata.rip_vers = rip_vers;
|
|
testdata.onlyChangeF = onlyChangeF;
|
|
|
|
if (rip_vers == RIP_V1) testdata.ipdest = INADDR_BROADCAST;
|
|
else testdata.ipdest = INADDR_RIP_GROUP;
|
|
|
|
IPRADIX_walk(&IP_cfg_ptr->ROUTE_ROOT.NODE, RIP_send_resp_test, &testdata);
|
|
|
|
/* test if the routes has been all advertized (nbFail==0 && nbTry > 0)*/
|
|
if (testdata.nb_fail) return (uint_32)RTCS_ERROR;
|
|
if (testdata.nb_try == 0) return RTCS_OK;
|
|
|
|
/* clear the flags only if required */
|
|
if (ripcfg->RT_CHANGED_F == FALSE) return RTCS_OK;
|
|
|
|
/* update the flag */
|
|
ripcfg->RT_CHANGED_F = FALSE;
|
|
|
|
/* clear the flag in all changed route entries */
|
|
IPRADIX_walk(&IP_cfg_ptr->ROUTE_ROOT.NODE, RIP_send_resp_test2, NULL);
|
|
|
|
return RTCS_OK;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_process_inreq
|
|
* Returned Values : void
|
|
* Comments : check only the header
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 RIP_process_inreq(
|
|
RTCSPCB_PTR pcb /* [IN/OUT] incoming packet */
|
|
)
|
|
{ /* Body */
|
|
RIP_HEADER_PTR hd = (RIP_HEADER_PTR)RTCSPCB_DATA(pcb);
|
|
RIP_ENTRY_PTR rte = (RIP_ENTRY_PTR)((uchar_ptr)hd
|
|
+ sizeof(RIP_HEADER));
|
|
uint_32 pktlen = RTCSPCB_SIZE(pcb);
|
|
uint_32 err = RTCS_OK;
|
|
|
|
/* handle the general query. rfc2453.3.9.1 */
|
|
if (pktlen == sizeof(RIP_ENTRY) + sizeof(RIP_HEADER)
|
|
&& ntohs(rte->FAMILY) == 0
|
|
&& ntohl(rte->METRIC) == RIP_MAX_METRIC){
|
|
_ip_address ipsrc = IP_source(pcb);
|
|
uint_16 srcport = UDP_source(pcb);
|
|
uint_8 version = ntohc(hd->VERSION);
|
|
return RIP_send_resp_ipif (pcb->IFSRC,ipsrc,srcport,version,0);
|
|
}
|
|
/* WORK: here handle particular routes request */
|
|
|
|
return err;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_expire_gc
|
|
* Returned Values : boolean
|
|
* Comments : rfc2453.3.8
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean RIP_expire_gc(
|
|
TCPIP_EVENT_PTR event /* [IN/OUT] the resend event */
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_INDIRECT_PTR gate = event->PRIVATE;
|
|
|
|
if (!gate->IS_DIRECT) {
|
|
ROUTE_remove(gate);
|
|
} /* Endif */
|
|
|
|
return FALSE;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_expire_rte
|
|
* Returned Values : boolean
|
|
* Comments : rfc2453.3.8
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean RIP_expire_rte(
|
|
TCPIP_EVENT_PTR event /* [IN/OUT] the resend event */
|
|
)
|
|
{ /* Body */
|
|
RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP);
|
|
IP_ROUTE_INDIRECT_PTR gate = event->PRIVATE;
|
|
|
|
/* update the route entry */
|
|
gate->FLAGS &= ~RTF_UP;
|
|
gate->RIP.METRIC = RIP_MAX_METRIC;
|
|
ripcfg->RT_CHANGED_F = gate->RIP.CHANGED_F = TRUE;
|
|
|
|
RIP_trig_upd();
|
|
|
|
/* start the garbage collector timer. */
|
|
gate->RIP.TIMEOUT.TIME = RIP_TIMEOUT_GC;
|
|
gate->RIP.TIMEOUT.EVENT = RIP_expire_gc;
|
|
return TRUE;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_init_timer
|
|
* Returned Values :
|
|
* Comments : rfc2453.3.9.2
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void RIP_init_timer(
|
|
IP_ROUTE_INDIRECT_PTR gate,
|
|
uint_32 metric
|
|
)
|
|
{ /* Body */
|
|
|
|
if (metric < RIP_MAX_METRIC){ /* init the timeout */
|
|
gate->RIP.TIMEOUT.TIME = RIP_TIMEOUT_DEL;
|
|
gate->RIP.TIMEOUT.EVENT = RIP_expire_rte;
|
|
}else{ /* init the garbage collection */
|
|
gate->RIP.TIMEOUT.TIME = RIP_TIMEOUT_GC;
|
|
gate->RIP.TIMEOUT.EVENT = RIP_expire_gc;
|
|
}
|
|
gate->RIP.TIMEOUT.PRIVATE = gate;
|
|
TCPIP_Event_add(&gate->RIP.TIMEOUT);
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_adopt_rt
|
|
* Returned Values :
|
|
* Comments : rfc2453.3.9.2
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void RIP_adopt_rt(
|
|
RTCSPCB_PTR pcb, /* [IN] incoming packet */
|
|
IP_ROUTE_INDIRECT_PTR gate,
|
|
RIP_ENTRY_PTR rte,
|
|
uint_32 metric,
|
|
_ip_address _PTR_ network_ptr,
|
|
_ip_address _PTR_ netmask_ptr
|
|
)
|
|
{ /* Body */
|
|
RIP_HEADER_PTR hd = (RIP_HEADER_PTR)RTCSPCB_DATA(pcb);
|
|
uint_16 rip_vers = ntohc(hd->VERSION);
|
|
_ip_address ipsrc = IP_source(pcb);
|
|
|
|
/* init the common part */
|
|
*network_ptr = ntohl(rte->NETADDR);
|
|
gate->GATEWAY = ipsrc;
|
|
if (rip_vers == RIP_V2){
|
|
_ip_address nexthop = ntohl(rte->NEXTHOP);
|
|
*netmask_ptr = ntohl(rte->NETMASK);
|
|
/* incoming nexthop. rfc2453.4.4 */
|
|
if (nexthop && IP_is_direct(pcb->IFSRC, nexthop))
|
|
gate->GATEWAY = nexthop;
|
|
}else{
|
|
*netmask_ptr = IN_DEFAULT_NET(*network_ptr);
|
|
}
|
|
|
|
/* if the metric is >= than the RIP_MAX_METRIC, the ourte is down */
|
|
if (metric < RIP_MAX_METRIC) {
|
|
gate->FLAGS |= RTF_UP;
|
|
} else {
|
|
gate->FLAGS &= ~RTF_UP;
|
|
} /* Endif */
|
|
|
|
/* init the RIP part */
|
|
gate->RIP.METRIC = metric;
|
|
gate->RIP.RT_TAG = ntohs(rte->RT_TAG);
|
|
|
|
gate->RIP.CHANGED_F = TRUE;
|
|
|
|
gate->RIP.IPIFSRC = pcb->IFSRC;
|
|
|
|
RIP_init_timer(gate, gate->RIP.METRIC);
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_update_rt
|
|
* Returned Values :
|
|
* Comments : rfc2453.3.9.2
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void RIP_update_rt(
|
|
IP_ROUTE_INDIRECT_PTR gate,
|
|
RTCSPCB_PTR pcb, /* [IN] incoming packet */
|
|
RIP_ENTRY_PTR rte
|
|
)
|
|
{ /* Body */
|
|
RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP);
|
|
uint_32 nmetric= RIP_cpu_metric(pcb,ntohl(rte->METRIC));
|
|
_ip_address ipsrc = IP_source(pcb);
|
|
|
|
|
|
/* dont modify a static route */
|
|
if (gate->FLAGS & RTF_STATIC)
|
|
return;
|
|
|
|
/*
|
|
** if the source isnt "authoritative" (i.e. not the current
|
|
** gateway) and have a bigger metric, ignore the route.
|
|
*/
|
|
if (ipsrc != gate->GATEWAY && nmetric > gate->RIP.METRIC)
|
|
return;
|
|
|
|
/*
|
|
** if the source isnt "authoritative" (i.e. not the current
|
|
** gateway) and have a equal metric and will "soon" timed out,
|
|
** update the route entry.
|
|
*/
|
|
if (ipsrc != gate->GATEWAY && nmetric == gate->RIP.METRIC){
|
|
uint_32 timeout = TCPIP_Event_expire(&gate->RIP.TIMEOUT);
|
|
/* if the both metrics are infinite, dont update the route. */
|
|
if (nmetric >= RIP_MAX_METRIC) return;
|
|
if (timeout > RIP_ALMOST_EXPIRED_TIME) return;
|
|
}
|
|
|
|
/* cancel the timeout/gc timer */
|
|
TCPIP_Event_cancel(&gate->RIP.TIMEOUT);
|
|
|
|
/* If the sources and the metrics are equal, just reinit the timer. */
|
|
if (ipsrc == gate->GATEWAY && gate->RIP.METRIC == nmetric){
|
|
if (nmetric < RIP_MAX_METRIC){
|
|
RIP_init_timer(gate, gate->RIP.METRIC);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** Reinit the route and the timer. ipsrc no longer needed, just used
|
|
** to fill all of the function parameters
|
|
*/
|
|
RIP_adopt_rt(pcb, gate, rte, nmetric, &ipsrc, &ipsrc);
|
|
|
|
/* flag it as changed */
|
|
ripcfg->RT_CHANGED_F = TRUE;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_create_rt
|
|
* Returned Values :
|
|
* Comments : rfc2453.3.9.2
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void RIP_create_rt(
|
|
RTCSPCB_PTR pcb, /* [IN] incoming packet */
|
|
RIP_ENTRY_PTR rte,
|
|
uint_8 rip_vers
|
|
)
|
|
{ /* Body */
|
|
uint_32 nmetric= RIP_cpu_metric(pcb,ntohl(rte->METRIC));
|
|
RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP);
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
IP_ROUTE_INDIRECT_PTR gate;
|
|
_ip_address network, netmask;
|
|
|
|
gate = RTCS_part_alloc(IP_cfg_ptr->GATE_PARTID);
|
|
if (!gate) return;
|
|
_mem_zero(gate, sizeof(*gate));
|
|
|
|
/* init the route */
|
|
RIP_adopt_rt(pcb, gate, rte, nmetric, &network, &netmask);
|
|
|
|
/* insert it in the table */
|
|
ROUTE_insert(gate, network, netmask);
|
|
|
|
/* flag it as changed */
|
|
ripcfg->RT_CHANGED_F = TRUE;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_process_inresp
|
|
* Returned Values :
|
|
* Comments : rfc2453.3.9.2
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void RIP_process_inresp(
|
|
RTCSPCB_PTR pcb /* [IN/OUT] incoming packet */
|
|
)
|
|
{ /* Body */
|
|
RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP);
|
|
uchar_ptr pkt = RTCSPCB_DATA(pcb);
|
|
RIP_HEADER_PTR hd = (RIP_HEADER_PTR)RTCSPCB_DATA(pcb);
|
|
RIP_ENTRY_PTR rte = (RIP_ENTRY_PTR)(pkt + sizeof(RIP_HEADER));
|
|
uint_32 pktlen = RTCSPCB_SIZE(pcb);
|
|
uint_16 rip_vers = ntohc(hd->VERSION);
|
|
IP_ROUTE_INDIRECT_PTR gate;
|
|
_ip_address netaddr, netmask;
|
|
|
|
if (pktlen < sizeof(RIP_HEADER)) {
|
|
return;
|
|
} /* Endif */
|
|
|
|
pktlen -= sizeof(RIP_HEADER);
|
|
|
|
if (RIP_is_valid_resp(pcb) == FALSE){
|
|
return;
|
|
} /* Endif */
|
|
|
|
for (; pktlen >= sizeof(RIP_ENTRY); pktlen -= sizeof(RIP_ENTRY), rte++){
|
|
if (!RIP_is_valid_rte(rte))
|
|
continue;
|
|
netaddr = ntohl(rte->NETADDR);
|
|
if (rip_vers == RIP_V2) netmask = ntohl(rte->NETMASK);
|
|
else netmask = IN_DEFAULT_NET(netaddr);
|
|
gate = ROUTE_get(netaddr, netmask);
|
|
if (!gate) RIP_create_rt(pcb, rte, rip_vers);
|
|
else RIP_update_rt(gate, pcb, rte);
|
|
}
|
|
/* if this incoming response has changed routes, do a triggered update*/
|
|
if (ripcfg->RT_CHANGED_F)
|
|
RIP_trig_upd();
|
|
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_service
|
|
* Returned Values : void
|
|
* Comments : Process incoming RIP packets. Called from UDP
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
void RIP_service(
|
|
RTCSPCB_PTR pcb, /* [IN/OUT] incoming packet */
|
|
UCB_STRUCT_PTR ucb_ptr /* [IN] target UCB */
|
|
)
|
|
{ /* Body */
|
|
RIP_HEADER_PTR hd = (RIP_HEADER_PTR)RTCSPCB_DATA(pcb);
|
|
|
|
|
|
/* check the version number */
|
|
if (ntohc(hd->VERSION) != RIP_V1 && ntohc(hd->VERSION) != RIP_V2) {
|
|
RTCSLOG_PCB_FREE(pcb, RTCS_OK);
|
|
RTCSPCB_free(pcb);
|
|
} /* Endif */
|
|
|
|
RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PORT(IPPORT_RIP), ntohc(hd->VERSION));
|
|
|
|
switch (ntohc(hd->COMMAND)) {
|
|
case RIPCMD_REQUEST:
|
|
RIP_process_inreq(pcb);
|
|
break;
|
|
case RIPCMD_RESPONSE:
|
|
RIP_process_inresp(pcb);
|
|
break;
|
|
default:
|
|
break;
|
|
} /* Endswitch */
|
|
|
|
RTCSLOG_PCB_FREE(pcb, RTCS_OK);
|
|
RTCSPCB_free(pcb);
|
|
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_send_req_ipif
|
|
* Returned Values : boolean
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 RIP_send_req_ipif (
|
|
IP_IF_PTR ipif
|
|
)
|
|
{ /* Body */
|
|
uchar_ptr pkt;
|
|
uint_32 err;
|
|
_ip_address ipdest;
|
|
|
|
/* allocate the packet memory */
|
|
pkt = RTCS_mem_alloc_system(RIP_MAX_PKTLEN);
|
|
if (!pkt) return RTCSERR_OUT_OF_MEMORY;
|
|
|
|
/* build the header */
|
|
RIP_build_header(pkt, RIPCMD_REQUEST, ADV_VERSION);
|
|
|
|
/* build handle the general query. rfc2453.3.9.1 */
|
|
RIP_build_rte(pkt+sizeof(RIP_HEADER), 0, DEFAULT_ROUTE_TAG, INADDR_ANY
|
|
, INADDR_ANY,INADDR_ANY, RIP_MAX_METRIC
|
|
, ADV_VERSION);
|
|
|
|
if (ADV_VERSION == RIP_V1) ipdest = INADDR_BROADCAST;
|
|
else ipdest = INADDR_RIP_GROUP;
|
|
|
|
/* send the packet */
|
|
err = RIP_send_pkt(ipif, ipdest, IPPORT_RIP, pkt
|
|
, sizeof(RIP_HEADER) + sizeof(RIP_ENTRY));
|
|
if (err != RTCS_OK){
|
|
return err;
|
|
}
|
|
return RTCS_OK;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_send_req
|
|
* Returned Values : boolean
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
struct RIP_send_req_struct {
|
|
IP_IF_PTR localhost;
|
|
};
|
|
|
|
static boolean RIP_send_req_test
|
|
(
|
|
_ip_address node_ip,
|
|
_ip_address node_mask,
|
|
pointer node_data,
|
|
pointer data
|
|
)
|
|
{ /* Body */
|
|
IP_ROUTE_PTR route = node_data;
|
|
struct RIP_send_req_struct _PTR_ testdata = data;
|
|
|
|
if (route && route->DIRECT && !~node_mask) {
|
|
/* Don't advertise on local interface */
|
|
if (route->DIRECT->DESTIF != testdata->localhost) {
|
|
RIP_send_req_ipif(route->DIRECT->DESTIF);
|
|
} /* Endif */
|
|
} else if (route && route->VIRTUAL && route->VIRTUAL->ADDRESS) {
|
|
/* Don't advertise on local interface */
|
|
if (route->VIRTUAL->DESTIF != testdata->localhost) {
|
|
RIP_send_req_ipif(route->VIRTUAL->DESTIF);
|
|
} /* Endif */
|
|
|
|
} /* Endif */
|
|
|
|
return FALSE;
|
|
} /* Endbody */
|
|
|
|
static uint_32 RIP_send_req(
|
|
void
|
|
)
|
|
{ /* Body */
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
struct RIP_send_req_struct testdata;
|
|
|
|
testdata.localhost = RTCS_IF_LOCALHOST_PRV;
|
|
IPRADIX_walk(&IP_cfg_ptr->ROUTE_ROOT.NODE, RIP_send_req_test, &testdata);
|
|
|
|
return RTCS_OK;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_expire_periodic
|
|
* Returned Values : boolean
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean RIP_expire_periodic(
|
|
TCPIP_EVENT_PTR event /* [IN/OUT] the resend event */
|
|
)
|
|
{ /* Body */
|
|
|
|
RIP_send_resp(ADV_VERSION, FALSE);
|
|
|
|
event->TIME = RND_RANGE(RIP_TIME_MIN_PERIODIC,
|
|
RIP_TIME_MAX_PERIODIC);
|
|
return TRUE;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_expire_trig_upd
|
|
* Returned Values : boolean
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean RIP_expire_trig_upd(
|
|
TCPIP_EVENT_PTR event /* [IN/OUT] the resend event */
|
|
)
|
|
{ /* Body */
|
|
RIP_CFG_STRUCT_PTR ripcfg = event->PRIVATE;
|
|
|
|
/* if no route has been during the timer run, just leave */
|
|
if (ripcfg->RT_CHANGED_F == FALSE) {
|
|
/* update the internal flag to know if the timer is running or not */
|
|
ripcfg->TIMER_TRIG_UPD.PRIVATE = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
/* send the changed routes */
|
|
RIP_send_resp(ADV_VERSION, TRUE);
|
|
|
|
/* restart the timer */
|
|
event->TIME = RND_RANGE(RIP_TIME_MIN_TRIG_UPD, RIP_TIME_MAX_TRIG_UPD);
|
|
return TRUE;
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_trig_udp
|
|
* Returned Values : boolean
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void RIP_trig_upd(
|
|
void
|
|
)
|
|
{ /* Body */
|
|
RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP);
|
|
|
|
if (RTCS_getcfg(RIP) == NULL) return;
|
|
|
|
/* if the timer is currently running, dont send the data */
|
|
if (ripcfg->TIMER_TRIG_UPD.PRIVATE)
|
|
return;
|
|
|
|
/* send the changed routes */
|
|
RIP_send_resp(ADV_VERSION, TRUE);
|
|
|
|
/* start the timer */
|
|
ripcfg->TIMER_TRIG_UPD.TIME = RND_RANGE(RIP_TIME_MIN_TRIG_UPD,
|
|
RIP_TIME_MAX_TRIG_UPD);
|
|
ripcfg->TIMER_TRIG_UPD.EVENT = RIP_expire_trig_upd;
|
|
ripcfg->TIMER_TRIG_UPD.PRIVATE = ripcfg;
|
|
TCPIP_Event_add(&ripcfg->TIMER_TRIG_UPD);
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_new_bindif
|
|
* Parameters :
|
|
* Comments :
|
|
* : - can be called before RIP_init
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
void RIP_new_bindif (
|
|
IP_ROUTE_DIRECT_PTR bindif /* [IN] the outgoing binded interface */
|
|
)
|
|
{ /* Body */
|
|
RIP_CFG_STRUCT_PTR cfg = RTCS_getcfg(RIP);
|
|
IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP);
|
|
ip_mreq mreq;
|
|
|
|
if (!cfg) {
|
|
return;
|
|
} /* Endif */
|
|
|
|
/* do not init the routing on the local interface */
|
|
if (bindif->NETIF == RTCS_IF_LOCALHOST_PRV) {
|
|
return;
|
|
} /* Endif */
|
|
|
|
/* init the multicast group */
|
|
mreq.imr_multiaddr.s_addr = INADDR_RIP_GROUP;
|
|
mreq.imr_interface.s_addr = bindif->ADDRESS;
|
|
IGMP_join_group(&cfg->UCB->MCB_PTR, &mreq, &cfg->UCB->IGMP_LEAVEALL);
|
|
|
|
if (bindif->NETIF) {
|
|
RIP_send_req_ipif(bindif->NETIF);
|
|
} else {
|
|
RIP_send_req_ipif(bindif->DESTIF);
|
|
} /* Endif */
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_init_static_rt
|
|
* Returned Values : void
|
|
* Comments : - called to init the RIP part of a static route
|
|
* created by ipif_add()
|
|
* : - can be called before RIP_init
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
void RIP_init_static_rt
|
|
(
|
|
IP_ROUTE_INDIRECT_PTR gate, /* [IN] the route to init */
|
|
uint_16 metric /* [IN] metric of this route. [0,65535] */
|
|
)
|
|
{ /* Body */
|
|
RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP);
|
|
|
|
_mem_zero(&gate->RIP, sizeof(gate->RIP));
|
|
gate->RIP.METRIC = metric / 4096;
|
|
/* sanity check */
|
|
if (gate->RIP.METRIC < RIP_MIN_METRIC) {
|
|
gate->RIP.METRIC = RIP_MIN_METRIC;
|
|
} /* Endif */
|
|
if (gate->RIP.METRIC > RIP_MAX_METRIC) {
|
|
gate->RIP.METRIC = RIP_MAX_METRIC;
|
|
} /* Endif */
|
|
/* no src interface for a static route */
|
|
gate->RIP.IPIFSRC = NULL;
|
|
gate->RIP.CHANGED_F = TRUE;
|
|
if (ripcfg){
|
|
ripcfg->RT_CHANGED_F = TRUE;
|
|
RIP_trig_upd();
|
|
}
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : RIP_remove_rt
|
|
* Returned Values : void
|
|
* Comments : - called to close the RIP part of a route
|
|
* created by ROUTE_remove()
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
void RIP_remove_rt(IP_ROUTE_INDIRECT_PTR gate)
|
|
{ /* Body */
|
|
/* cancel the timeout/gc timer */
|
|
TCPIP_Event_cancel(&gate->RIP.TIMEOUT);
|
|
_mem_zero(&gate->RIP, sizeof(gate->RIP));
|
|
} /* Endbody */
|
|
|
|
#endif
|
|
/* EOF */
|