0
mirror of https://github.com/Indemsys/Frequency_Inverter.git synced 2026-05-09 14:12:58 +00:00
Files
2022-01-04 12:22:53 +02:00

489 lines
15 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: nat.c$
* $Version : 3.8.6.0$
* $Date : Oct-9-2012$
*
* Comments:
*
* This file contains the NAT implementation.
*
*END************************************************************************/
#include <rtcsrtos.h>
#include <rtcs.h>
#include <rtcs_prv.h>
#if RTCSCFG_ENABLE_NAT
#include "nat.h"
#include "nat_prv.h"
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_init_internal2
* Parameters :
*
* _ip_address IP_PRV [IN] The private network address
* _ip_address IP_MASK [IN] The private network mask
*
* Returned Value : void
* Comments :
* Starts and initializes NAT.
*
*END*-----------------------------------------------------------------*/
static uint_32 NAT_init_internal2
(
NAT_PARM_PTR parm_ptr /* [IN] Initialization parameters */
)
{ /* Body */
NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT);
uint_32 error;
/*
** Make sure the netmask is valid. We use the fact that
** (x & x+1) == 0 <=> x = 2^n-1.
*/
if (~parm_ptr->IP_MASK & (~parm_ptr->IP_MASK + 1)) {
return RTCSERR_INVALID_PARAMETER;
} /* Endif */
/* Make sure other parameters have been supplied */
if (!parm_ptr->IP_PRV) {
return RTCSERR_INVALID_PARAMETER;
} /* Endif */
/*
** If the configuration structure has already been allocated,
** just add another private network and return
*/
if (nat_cfg_ptr) {
error = NAT_add_private_network(&nat_cfg_ptr->PRIVATE_NETWORKS, parm_ptr->IP_PRV, parm_ptr->IP_MASK);
if (error == RTCS_OK) {
nat_cfg_ptr->NAT_EXEC = NAT_apply;
}
return error;
} /* Endif */
// First time through the initialization,
// Allocate the NAT configuration structure
nat_cfg_ptr = _mem_alloc_system_zero(sizeof(NAT_CFG_STRUCT));
if (nat_cfg_ptr == NULL) {
return RTCSERR_OUT_OF_MEMORY;
} /* Endif */
/* Record the private network information */
error = NAT_add_private_network(&nat_cfg_ptr->PRIVATE_NETWORKS, parm_ptr->IP_PRV, parm_ptr->IP_MASK);
if (error == RTCS_OK) {
nat_cfg_ptr->NAT_EXEC = NAT_apply;
nat_cfg_ptr->INITIAL_PRV_NET = parm_ptr->IP_PRV;
nat_cfg_ptr->INITIAL_PRV_MASK = parm_ptr->IP_MASK;
nat_cfg_ptr->TCP_TOUT.PRIVATE = &nat_cfg_ptr->TCP_HEAD;
nat_cfg_ptr->UDP_TOUT.PRIVATE = &nat_cfg_ptr->UDP_HEAD;
nat_cfg_ptr->FIN_TOUT.PRIVATE = &nat_cfg_ptr->FIN_HEAD;
nat_cfg_ptr->ICMP_TOUT.PRIVATE = &nat_cfg_ptr->ICMP_HEAD;
/* Initialize radix trees */
IPRADIX_init(&nat_cfg_ptr->ROOT_IN);
IPRADIX_init(&nat_cfg_ptr->ROOT_OUT);
/* Initialize timeout functions */
nat_cfg_ptr->UDP_TOUT.EVENT = NAT_expire;
nat_cfg_ptr->TCP_TOUT.EVENT = NAT_expire;
nat_cfg_ptr->FIN_TOUT.EVENT = NAT_expire;
nat_cfg_ptr->ICMP_TOUT.EVENT = NAT_expire;
nat_cfg_ptr->TIMEOUT_TCP = NAT_DEFAULT_TIMEOUT_TCP;
nat_cfg_ptr->TIMEOUT_UDP = NAT_DEFAULT_TIMEOUT_UDP;
nat_cfg_ptr->TIMEOUT_FIN = NAT_DEFAULT_TIMEOUT_FIN;
nat_cfg_ptr->TIMEOUT_ICMP = NAT_DEFAULT_TIMEOUT_ICMP;
/* Initialize last used port numbers */
nat_cfg_ptr->TCP_PORT = NAT_DEFAULT_PORT_MIN;
nat_cfg_ptr->UDP_PORT = NAT_DEFAULT_PORT_MIN;
nat_cfg_ptr->ICMP_ID = NAT_DEFAULT_PORT_MIN;
nat_cfg_ptr->PORT_MAX = NAT_DEFAULT_PORT_MAX;
nat_cfg_ptr->PORT_MIN = NAT_DEFAULT_PORT_MIN;
/* Inititalize ALGs */
error = NAT_init_algs(nat_cfg_ptr);
}
/* Allocate partitions */
if (error == RTCS_OK) {
nat_cfg_ptr->SESSION_PART = RTCS_part_create(sizeof(NAT_SESSION_STRUCT),
NAT_SESSION_INITIAL_COUNT, NAT_SESSION_GROW_COUNT, NAT_SESSION_MAX,
NULL, NULL);
if (nat_cfg_ptr->SESSION_PART == NULL) {
error = RTCSERR_OUT_OF_MEMORY;
} /* Endif */
} /* Endif */
if (error == RTCS_OK) {
nat_cfg_ptr->RADIX_IN = RTCS_part_create(sizeof(IPRADIX_NODE),
NAT_SESSION_INITIAL_COUNT, NAT_SESSION_GROW_COUNT, NAT_SESSION_MAX,
NULL, NULL);
if (nat_cfg_ptr->RADIX_IN == NULL) {
error = RTCSERR_OUT_OF_MEMORY;
} /* Endif */
} /* Endif */
if (error == RTCS_OK) {
nat_cfg_ptr->RADIX_OUT = RTCS_part_create(sizeof(IPRADIX_NODE),
NAT_SESSION_INITIAL_COUNT, NAT_SESSION_GROW_COUNT, NAT_SESSION_MAX,
NULL, NULL);
if (nat_cfg_ptr->RADIX_OUT == NULL) {
error = RTCSERR_OUT_OF_MEMORY;
} /* Endif */
} /* Endif */
if (error == RTCS_OK) {
// Initialize queue of DNAT Rules
_queue_init( &nat_cfg_ptr->RULE_QUEUE, 0 );
RTCS_setcfg(NAT, nat_cfg_ptr);
} else {
if (nat_cfg_ptr != NULL) {
if (nat_cfg_ptr->RADIX_IN != NULL) RTCS_part_destroy(nat_cfg_ptr->RADIX_IN);
if (nat_cfg_ptr->RADIX_OUT != NULL) RTCS_part_destroy(nat_cfg_ptr->RADIX_OUT);
if (nat_cfg_ptr->SESSION_PART != NULL) RTCS_part_destroy(nat_cfg_ptr->SESSION_PART);
_mem_free(nat_cfg_ptr);
}
} /* Endif */
return error;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_init_internal
* Parameters :
*
* _ip_address IP_PRV [IN] The private network address
* _ip_address IP_MASK [IN] The private network mask
*
* Returned Value : void
* Comments :
* Starts and initializes NAT.
*
*END*-----------------------------------------------------------------*/
void NAT_init_internal
(
NAT_PARM_PTR parm_ptr /* [IN] Initialization parameters */
)
{
RTCSCMD_complete(parm_ptr, NAT_init_internal2(parm_ptr));
}
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_add_network_internal
* Returned Value : void
* Comments :
* Add a new private network.
*
*END*-----------------------------------------------------------------*/
void NAT_add_network_internal
(
NAT_PARM_PTR parm_ptr /* [IN] Initialization parameters */
)
{ /* Body */
NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT);
uint_32 error;
// Make sure NAT is already up
if (nat_cfg_ptr == NULL) {
error = RTCSERR_NAT_NOT_INITIALIZED;
/*
** Make sure the netmask is valid. We use the fact that
** (x & x+1) == 0 <=> x = 2^n-1.
*/
} else if (~parm_ptr->IP_MASK & (~parm_ptr->IP_MASK + 1)) {
error = RTCSERR_INVALID_PARAMETER;
/* Make sure other parameters have been supplied */
} else if (!parm_ptr->IP_PRV) {
error = RTCSERR_INVALID_PARAMETER;
} else {
error = NAT_add_private_network(&nat_cfg_ptr->PRIVATE_NETWORKS, parm_ptr->IP_PRV, parm_ptr->IP_MASK);
}
RTCSCMD_complete(parm_ptr, error);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_remove_network_internal
* Returned Value : void
* Comments :
* Remove a private network.
*
*END*-----------------------------------------------------------------*/
void NAT_remove_network_internal
(
NAT_PARM_PTR parm_ptr /* [IN] Initialization parameters */
)
{ /* Body */
NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT);
uint_32 error;
// Make sure NAT is already up
if (nat_cfg_ptr == NULL) {
error = RTCSERR_NAT_NOT_INITIALIZED;
/*
** Make sure the netmask is valid. We use the fact that
** (x & x+1) == 0 <=> x = 2^n-1.
*/
} else if (~parm_ptr->IP_MASK & (~parm_ptr->IP_MASK + 1)) {
error = RTCSERR_INVALID_PARAMETER;
/* Make sure other parameters have been supplied */
} else if (!parm_ptr->IP_PRV) {
error = RTCSERR_INVALID_PARAMETER;
} else {
// Try to remove the private network
error=NAT_remove_private_network(&nat_cfg_ptr->PRIVATE_NETWORKS, parm_ptr->IP_PRV, parm_ptr->IP_MASK);
}
RTCSCMD_complete(parm_ptr, error);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_close_internal
* Returned Value : void
* Comments :
* Stops NAT.
*
*END*-----------------------------------------------------------------*/
void NAT_close_internal
(
NAT_PARM_PTR parm_ptr /* [IN] Unused */
)
{ /* Body */
NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT);
uint_32 error;
if (nat_cfg_ptr == NULL) {
error = RTCSERR_NAT_NOT_INITIALIZED;
} else {
nat_cfg_ptr->NAT_EXEC = NULL;
error = RTCS_OK;
}
RTCSCMD_complete(parm_ptr, error);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_config_timeouts
* Returned Value : RTCS_OK or uint_32 error code
* Comments :
* Dynamically updates NAT timeouts
*
*END*-----------------------------------------------------------------*/
void NAT_config_timeouts
(
NAT_TIMEOUTS_STRUCT_PTR nat_timeouts_ptr /* [IN] New values for timeouts */
)
{ /* Body */
NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT);
if (nat_timeouts_ptr->timeout_tcp) {
nat_cfg_ptr->TIMEOUT_TCP = nat_timeouts_ptr->timeout_tcp;
NAT_tout_max(&nat_cfg_ptr->TCP_TOUT, nat_cfg_ptr->TIMEOUT_TCP);
} /* Endif */
if (nat_timeouts_ptr->timeout_fin) {
nat_cfg_ptr->TIMEOUT_FIN = nat_timeouts_ptr->timeout_fin;
NAT_tout_max(&nat_cfg_ptr->FIN_TOUT, nat_cfg_ptr->TIMEOUT_FIN);
} /* Endif */
if (nat_timeouts_ptr->timeout_udp) {
nat_cfg_ptr->TIMEOUT_UDP = nat_timeouts_ptr->timeout_udp;
NAT_tout_max(&nat_cfg_ptr->UDP_TOUT, nat_cfg_ptr->TIMEOUT_UDP);
} /* Endif */
if (nat_timeouts_ptr->timeout_icmp) {
nat_cfg_ptr->TIMEOUT_ICMP = nat_timeouts_ptr->timeout_icmp;
NAT_tout_max(&nat_cfg_ptr->ICMP_TOUT, nat_cfg_ptr->TIMEOUT_ICMP);
} /* Endif */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_config_ports
* Returned Value : RTCS_OK or uint_32 error code
* Comments :
* Dynamically updates NAT minimum and maximum port numbers
*
*END*-----------------------------------------------------------------*/
void NAT_config_ports
(
NAT_PORTS_STRUCT_PTR nat_ports_ptr /* [IN] New values for port ranges */
)
{ /* Body */
NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT);
if (nat_ports_ptr->port_min) {
if (nat_ports_ptr->port_min > nat_cfg_ptr->PORT_MAX) {
nat_cfg_ptr->PORT_MIN = nat_cfg_ptr->PORT_MAX;
} else {
nat_cfg_ptr->PORT_MIN = nat_ports_ptr->port_min;
} /* Endif */
} /* Endif */
if (nat_ports_ptr->port_max) {
if (nat_ports_ptr->port_max < nat_cfg_ptr->PORT_MIN) {
nat_cfg_ptr->PORT_MAX = nat_cfg_ptr->PORT_MIN;
} else {
nat_cfg_ptr->PORT_MAX = nat_ports_ptr->port_max;
} /* Endif */
/* Fix the last used port numbers so that they don't exceed max */
nat_cfg_ptr->TCP_PORT = nat_cfg_ptr->PORT_MIN;
nat_cfg_ptr->UDP_PORT = nat_cfg_ptr->PORT_MIN;
nat_cfg_ptr->ICMP_ID = nat_cfg_ptr->PORT_MIN;
} /* Endif */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_is_private_addr
* Returned Value : TRUE if ipaddr is within one of the private networks
* Comments :
*
*END*-----------------------------------------------------------------*/
boolean NAT_is_private_addr(NAT_NETWORK_STRUCT_PTR nat_network_ptr, _ip_address ipaddr)
{
uint_32 i;
for (i=0;i<nat_network_ptr->NUM_PRV_NETS;i++) {
if ((ipaddr & nat_network_ptr->PRV_MASK[i]) == nat_network_ptr->PRV_NET[i]) {
return TRUE;
}
}
return FALSE;
}
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_add_private_network
* Returned Value : RTCS_OK if ipaddr is added as a private network
* Comments :
*
*END*-----------------------------------------------------------------*/
uint_32 NAT_add_private_network(NAT_NETWORK_STRUCT_PTR nat_network_ptr, _ip_address netaddr, _ip_address netmask)
{
_ip_address new_netaddr = netaddr & netmask;
uint_32 i;
// First, check to see if it is already installed
for (i=0;i<nat_network_ptr->NUM_PRV_NETS;i++) {
if ((new_netaddr == nat_network_ptr->PRV_NET[i]) && (netmask == nat_network_ptr->PRV_MASK[i])) {
// It is, return OK
return RTCS_OK;
}
}
// It isn't - is there room for one more?
if (nat_network_ptr->NUM_PRV_NETS >= NAT_MAX_PRIVATE_NETWORKS) {
// No, there is not
return RTCSERR_NAT_MAX_PRIVATE_NETWORKS;
}
// Yes there is, so add it
nat_network_ptr->PRV_NET[nat_network_ptr->NUM_PRV_NETS] = new_netaddr;
nat_network_ptr->PRV_MASK[nat_network_ptr->NUM_PRV_NETS] = netmask;
nat_network_ptr->NUM_PRV_NETS++;
return RTCS_OK;
}
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : NAT_remove_private_network
* Returned Value :
* Comments :
*
*END*-----------------------------------------------------------------*/
uint_32 NAT_remove_private_network(NAT_NETWORK_STRUCT_PTR nat_network_ptr, _ip_address netaddr, _ip_address netmask)
{
uint_32 i;
_ip_address new_netaddr = netaddr & netmask;
// First, check to see if it is already installed
for (i=0;i<nat_network_ptr->NUM_PRV_NETS;i++) {
if ((new_netaddr == nat_network_ptr->PRV_NET[i]) && (netmask == nat_network_ptr->PRV_MASK[i])) {
// It is, delete it
nat_network_ptr->NUM_PRV_NETS--;
nat_network_ptr->PRV_NET[i] = nat_network_ptr->PRV_NET[nat_network_ptr->NUM_PRV_NETS];
nat_network_ptr->PRV_MASK[i] = nat_network_ptr->PRV_MASK[nat_network_ptr->NUM_PRV_NETS];
nat_network_ptr->PRV_NET[nat_network_ptr->NUM_PRV_NETS] = 0;
nat_network_ptr->PRV_MASK[nat_network_ptr->NUM_PRV_NETS] = 0;
return RTCS_OK;
}
}
return RTCSERR_NAT_INVALID_PRIVATE_NETWORK;
}
#endif
/* EOF */