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

2181 lines
66 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: udp.c$
* $Version : 3.8.14.0$
* $Date : Jun-14-2012$
*
* Comments:
*
* This file contains the implementation of the User
* Datagram Protocol. For more details, refer to RFC768.
*
*END************************************************************************/
#include <rtcs.h>
#include "rtcs_prv.h"
#include "tcpip.h"
#include "ip_prv.h"
#include "udp_prv.h"
#include "icmp_prv.h"
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_init
* Returned Values : uint_32
* Comments :
* Initialize the UDP layer.
*
*END*-----------------------------------------------------------------*/
uint_32 UDP_init
(
void
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
uint_32 status = RTCS_OK;
UDP_cfg_ptr = RTCS_mem_alloc_zero(sizeof(UDP_CFG_STRUCT));
if (UDP_cfg_ptr == NULL) {
return RTCSERR_OUT_OF_MEMORY;
}
_mem_set_type(UDP_cfg_ptr, MEM_TYPE_UDP_CFG_STRUCT);
RTCS_LIST_INIT(UDP_cfg_ptr->BOUND_UCB_HEAD);
RTCS_LIST_INIT(UDP_cfg_ptr->LBOUND_UCB_HEAD);
RTCS_LIST_INIT(UDP_cfg_ptr->GROUND_UCB_HEAD);
RTCS_LIST_INIT(UDP_cfg_ptr->OPEN_UCB_HEAD);
UDP_cfg_ptr->LAST_PORT = IPPORT_USERRESERVED;
RTCS_setcfg(UDP, UDP_cfg_ptr);
#if RTCSCFG_ENABLE_IP4
IP_open(IPPROTO_UDP, UDP_service, NULL, &status);
if(status != RTCS_OK)
{
return status;
}
#endif /*RTCSCFG_ENABLE_IP4*/
/* Initialisation of the UDP IPv6 service */
#if RTCSCFG_ENABLE_IP6
IP6_open(IPPROTO_UDP, UDP_service6, NULL, &status);
#endif
return status;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_openbind_internal
* Returned Values : error code
* Comments :
* Opens and binds a new UCB.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
uint_32 UDP_openbind_internal
(
uint_16 localport, /* [IN] local UDP port */
void (_CODE_PTR_ service)(RTCSPCB_PTR, UCB_STRUCT_PTR),
UCB_STRUCT_PTR _PTR_ ucb /* [OUT] new UCB */
)
{ /* Body */
UDP_PARM parms;
uint_32 error;
error = RTCSCMD_internal(parms, UDP_open);
if (error) {
return error;
} /* Endif */
parms.udpservice = service;
parms.ipaddress = INADDR_ANY;
parms.udpport = localport;
parms.udpword = 0;
error = RTCSCMD_internal(parms, UDP_bind);
if (error) {
RTCSCMD_internal(parms, UDP_close);
return error;
} /* Endif */
*ucb = parms.ucb;
return RTCS_OK;
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_close_internal
* Returned Values : error code
* Comments :
* Closes a UCB.
*
*END*-----------------------------------------------------------------*/
uint_32 UDP_close_internal
(
UCB_STRUCT_PTR ucb /* [IN] old UCB */
)
{ /* Body */
UDP_PARM parms;
uint_32 error;
parms.ucb = ucb;
error = RTCSCMD_internal(parms, UDP_close);
if (error) {
return error;
} /* Endif */
return RTCS_OK;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_open
* Parameters :
*
* UCB_STRUCT_PTR ucb [OUT] unbound UCB
* _CODE_PTR_ udpservice not used
* _ip_address ipaddress not used
* uint_16 udpport not used
* uint_16 udpflags not used
* pointer udpptr not used
* uint_32 udpword not used
*
* Comments :
* Creates an unbound UCB.
*
*END*-----------------------------------------------------------------*/
void UDP_open
(
UDP_PARM_PTR parms
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UCB_STRUCT_PTR ucb;
UDP_cfg_ptr = RTCS_getcfg(UDP);
ucb = RTCS_mem_alloc(sizeof(UCB_STRUCT));
if (!ucb) {
RTCSCMD_complete(parms, RTCSERR_UDP_UCB_ALLOC);
return;
} /* Endif */
_mem_set_type(ucb, MEM_TYPE_UCB_STRUCT);
ucb->PORT = 0;
ucb->REMOTE_PORT = 0;
ucb->SOCKET = 0;
ucb->REMOTE_HOST = INADDR_ANY;
ucb->BYPASS_RX = FALSE;
ucb->BYPASS_TX = FALSE;
ucb->NONBLOCK_RX = FALSE;
ucb->NONBLOCK_TX = FALSE;
RTCS_QUEUE_INIT(ucb->PHEAD, ucb->PTAIL);
RTCS_QUEUE_INIT(ucb->RHEAD, ucb->RTAIL);
/* Initialize the list of joined multicast groups */
RTCS_LIST_INIT(ucb->MCB_PTR);
ucb->IGMP_LEAVEALL = NULL;
/* Add the new UCB into the chain of ground UCBs */
RTCS_LIST_INS(UDP_cfg_ptr->GROUND_UCB_HEAD, ucb);
parms->ucb = ucb;
RTCSCMD_complete(parms, RTCS_OK);
return;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_bind
* Parameters :
*
* UCB_STRUCT_PTR ucb [IN] unbound UCB
* _CODE_PTR_ udpservice [IN] service function for incoming datagrams
* _ip_address ipaddress [IN] local IP address
* uint_16 udpport [IN] local port
* uint_16 udpflags not used
* pointer udpptr not used
* uint_32 udpword [IN] socket handle
*
* Comments :
* Binds a UCB to a local port.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
void UDP_bind
(
UDP_PARM_PTR parms
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UCB_STRUCT_PTR ucb, search_ptr, _PTR_ tmp_ptr, _PTR_ list_ptr;
uint_16 port;
_ip_address ipaddr;
UDP_cfg_ptr = RTCS_getcfg(UDP);
/* Initialize the UCB */
port = parms->udpport & 0xFFFF;
ipaddr = parms->ipaddress;
if (port) {
/*
** If port is specified, make sure its not in use with same local
** IP addr. We can only have one UCB per (IPADDR/port) combination,
** including the case were the IPADDR is INADDR_ANY.
*/
if (ipaddr) {
RTCS_LIST_SEARCH(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr) {
if (search_ptr->PORT == port &&
search_ptr->IPADDR == ipaddr)
{
RTCSCMD_complete(parms, RTCSERR_UDP_PORT_OPEN);
return;
} /* Endif */
} /* End SEARCH */
RTCS_LIST_SEARCH(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr) {
if (search_ptr->PORT == port &&
search_ptr->IPADDR == ipaddr)
{
RTCSCMD_complete(parms, RTCSERR_UDP_PORT_OPEN);
return;
} /* Endif */
} /* End SEARCH */
} else {
RTCS_LIST_SEARCH(UDP_cfg_ptr->BOUND_UCB_HEAD, search_ptr) {
if (search_ptr->PORT == port) {
RTCSCMD_complete(parms, RTCSERR_UDP_PORT_OPEN);
return;
} /* Endif */
} /* End SEARCH */
} /* Endif */
}
else
{
port = UDP_cfg_ptr->LAST_PORT;
for (;;)
{
/* Get next port */
if (--port < IPPORT_RESERVED)
{
port = IPPORT_USERRESERVED;
} /* Endif */
/* If we tested them all, return an error */
if (port == UDP_cfg_ptr->LAST_PORT)
{
RTCSCMD_complete(parms, RTCSERR_UDP_PORT_ALLOC);
return;
} /* Endif */
/*
** Check if it's in use
*/
RTCS_LIST_SEARCH(UDP_cfg_ptr->BOUND_UCB_HEAD, search_ptr)
{
if (search_ptr->PORT == port)
{
break;
} /* Endif */
} /* End SEARCH */
if (!search_ptr)
{
RTCS_LIST_SEARCH(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr)
{
if (search_ptr->PORT == port)
{
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
if (!search_ptr)
{
RTCS_LIST_SEARCH(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr)
{
if (search_ptr->PORT == port)
{
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
/* If it's not in use, keep it */
if (!search_ptr)
{
break;
} /* Endif */
} /* Endfor */
UDP_cfg_ptr->LAST_PORT = port;
} /* Endif */
ucb = parms->ucb;
ucb->PORT = port;
ucb->PCOUNT = 0;
ucb->IPADDR = ipaddr;
ucb->KEEP_IPADDR = (boolean) (ipaddr != INADDR_ANY);
ucb->SOCKET = parms->udpword;
ucb->SERVICE = parms->udpservice;
/* This is the list the UCB will be moved to */
if (ipaddr == INADDR_ANY) {
list_ptr = &(UDP_cfg_ptr->BOUND_UCB_HEAD);
} else {
list_ptr = &(UDP_cfg_ptr->LBOUND_UCB_HEAD);
} /* Endif */
/* Move the UCB fromt the GROUND list to the BOUND list */
RTCS_LIST_SEARCHMOD(UDP_cfg_ptr->GROUND_UCB_HEAD, tmp_ptr) {
if (*tmp_ptr == ucb) {
RTCS_LIST_DEL(UDP_cfg_ptr->GROUND_UCB_HEAD,tmp_ptr);
break;
} /* Endif */
} /* End SEARCH */
RTCS_LIST_INS_END((*list_ptr), ucb, tmp_ptr);
RTCSCMD_complete(parms, RTCS_OK);
return;
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_bind6
* Parameters :
*
* UCB_STRUCT_PTR ucb [IN] unbound UCB
* _CODE_PTR_ udpservice [IN] service function for incoming datagrams
* _ip_address ipaddress [IN] local IP address
* in6_addr ipv6address [IN] local IPv6 address
* uint_16 udpport [IN] local port
* uint_16 udpflags not used
* pointer udpptr not used
* uint_32 udpword [IN] socket handle
*
* Comments :
* Binds a UCB to a local port.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP6
void UDP_bind6
(
UDP_PARM_PTR parms
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UCB_STRUCT_PTR ucb, search_ptr, _PTR_ tmp_ptr, _PTR_ list_ptr;
uint_16 port;
in6_addr ipv6address;
UDP_cfg_ptr = RTCS_getcfg(UDP);
/* Initialize the UCB */
port = parms->udpport & 0xFFFF;
/* copy IPv6 addr */
IN6_ADDR_COPY(&(parms->ipv6address),&(ipv6address));//from ->to
if (port) {
/*
** If port is specified, make sure its not in use with same local
** IP addr. We can only have one UCB per (IPADDR/port) combination,
** including the case were the IPADDR is INADDR_ANY.
*/
if (!IN6_ARE_ADDR_EQUAL(&(ipv6address), &in6addr_any))
{
RTCS_LIST_SEARCH(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr)
{
if (
search_ptr->PORT == port &&
IN6_ARE_ADDR_EQUAL(&(search_ptr->IPV6ADDR), &(ipv6address))
)
{
RTCSCMD_complete(parms, RTCSERR_UDP_PORT_OPEN);
return;
} /* Endif */
} /* End SEARCH */
RTCS_LIST_SEARCH(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr)
{
if (
search_ptr->PORT == port &&
IN6_ARE_ADDR_EQUAL(&(search_ptr->IPV6ADDR), &(ipv6address))
)
{
RTCSCMD_complete(parms, RTCSERR_UDP_PORT_OPEN);
return;
} /* Endif */
} /* End SEARCH */
}else
{
RTCS_LIST_SEARCH(UDP_cfg_ptr->BOUND_UCB_HEAD, search_ptr)
{
if(search_ptr->PORT == port)
{
RTCSCMD_complete(parms, RTCSERR_UDP_PORT_OPEN);
return;
} /* Endif */
} /* End SEARCH */
} /* Endif */
} else
{
port = UDP_cfg_ptr->LAST_PORT;
for (;;)
{
/* Get next port */
if (--port < IPPORT_RESERVED)
{
port = IPPORT_USERRESERVED;
} /* Endif */
/* If we tested them all, return an error */
if (port == UDP_cfg_ptr->LAST_PORT)
{
RTCSCMD_complete(parms, RTCSERR_UDP_PORT_ALLOC);
return;
} /* Endif */
/*
** Check if it's in use
*/
RTCS_LIST_SEARCH(UDP_cfg_ptr->BOUND_UCB_HEAD, search_ptr)
{
if (search_ptr->PORT == port)
{
break;
} /* Endif */
} /* End SEARCH */
if (!search_ptr)
{
RTCS_LIST_SEARCH(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr)
{
if (search_ptr->PORT == port)
{
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
if (!search_ptr)
{
RTCS_LIST_SEARCH(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr)
{
if (search_ptr->PORT == port)
{
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
/* If it's not in use, keep it */
if (!search_ptr)
{
break;
} /* Endif */
} /* Endfor */
UDP_cfg_ptr->LAST_PORT = port;
} /* Endif */
ucb = parms->ucb;
ucb->PORT = port;
ucb->PCOUNT = 0;
IN6_ADDR_COPY(&(ipv6address), &(ucb->IPV6ADDR));//from ->to
ucb->KEEP_IPADDR = (boolean) (!IN6_ARE_ADDR_EQUAL(&(ipv6address), &in6addr_any));
ucb->SOCKET = parms->udpword;
ucb->SERVICE = parms->udpservice;
ucb->IF_SCOPE_ID = parms->if_scope_id;
/* This is the list the UCB will be moved to */
if (IN6_ARE_ADDR_EQUAL(&(ipv6address), &in6addr_any))
{
list_ptr = &(UDP_cfg_ptr->BOUND_UCB_HEAD);
}
else
{
list_ptr = &(UDP_cfg_ptr->LBOUND_UCB_HEAD);
} /* Endif */
/* Move the UCB fromt the GROUND list to the BOUND list */
RTCS_LIST_SEARCHMOD(UDP_cfg_ptr->GROUND_UCB_HEAD, tmp_ptr) {
if (*tmp_ptr == ucb) {
RTCS_LIST_DEL(UDP_cfg_ptr->GROUND_UCB_HEAD,tmp_ptr);
break;
} /* Endif */
} /* End SEARCH */
RTCS_LIST_INS_END((*list_ptr), ucb, tmp_ptr);
RTCSCMD_complete(parms, RTCS_OK);
return;
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_connect6
* Parameters :
*
* UCB_STRUCT_PTR ucb [IN] bound or open UCB
* _CODE_PTR_ udpservice not used
* in6_addr ipv6address [IN] peer IPv6 address
* uint_16 udpport [IN] peer port
* uint_16 udpflags not used
* pointer udpptr not used
* uint_32 udpword [IN] socket level error
*
* Comments :
* Connects a UCB to a peer port.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP6
void UDP_connect6
(
UDP_PARM_PTR parms
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UCB_STRUCT_PTR ucb = parms->ucb, search_ptr, _PTR_ tmp_ptr;
UCB_STRUCT_PTR _PTR_ ins_ptr, _PTR_ del_ptr;
uint_16 port;
uint_32 error = parms->udpword;
in6_addr *t_ipv6address;
UDP_cfg_ptr = RTCS_getcfg(UDP);
if (!error &&(!(parms->udpport) || IN6_ARE_ADDR_EQUAL(&(parms->ipv6address), &in6addr_any)))
{
/* Connect requires both a port AND and IP address. */
error = RTCSERR_UDP_PORT_ZERO;
}
else if (!error)
{
/* Bind a local address if none is specified */
if (IN6_ARE_ADDR_EQUAL(&(ucb->IPV6ADDR), &in6addr_any))
{
t_ipv6address = IP6_route_find(&(parms->ipv6address), 0);
IN6_ADDR_COPY(t_ipv6address,&(ucb->IPV6ADDR));
if(IN6_ARE_ADDR_EQUAL(&(ucb->IPV6ADDR), &in6addr_any))
{
error = RTCSERR_IP_UNREACH;
} else
{
/*
** Make sure this connect request does not put two UCB's into the
** same configuration.
*/
port = ucb->PORT;
RTCS_LIST_SEARCH(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr)
{
if (
search_ptr != ucb &&
search_ptr->PORT == port &&
IN6_ARE_ADDR_EQUAL(&(search_ptr->IPV6ADDR), &(ucb->IPV6ADDR))
)
{
error = RTCSERR_UDP_PORT_OPEN;
IN6_ADDR_COPY((in6_addr*)(&(in6addr_any)),&(ucb->IPV6ADDR));
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
} /* Endif */
} /*Endif */
/*
** Check for errors and location of UCB. If TRUE, UCB must be moved.
** This is an evaluates to TRUE if one of the following is true:
** A. There is an error, and there is a remote port OR
** B. There is no error, and there is no remote port
*/
if(!(error) == !(ucb->REMOTE_PORT))
{
if(ucb->REMOTE_PORT)
{
if(ucb->KEEP_IPADDR)
{
ins_ptr = &(UDP_cfg_ptr->LBOUND_UCB_HEAD);
}
else
{
ins_ptr = &(UDP_cfg_ptr->BOUND_UCB_HEAD);
}
del_ptr = &(UDP_cfg_ptr->OPEN_UCB_HEAD);
}
else
{
ins_ptr = &(UDP_cfg_ptr->OPEN_UCB_HEAD);
if(ucb->KEEP_IPADDR)
{
del_ptr = &(UDP_cfg_ptr->LBOUND_UCB_HEAD);
}
else
{
del_ptr = &(UDP_cfg_ptr->BOUND_UCB_HEAD);
}
}
/* Move the UCB from one list to the other */
RTCS_LIST_SEARCHMOD(*del_ptr, tmp_ptr)
{
if(*tmp_ptr == ucb)
{
RTCS_LIST_DEL(*del_ptr, tmp_ptr);
break;
} /* Endif */
} /* End SEARCH */
RTCS_LIST_INS_END(*ins_ptr, ucb, tmp_ptr);
} /* Endif */
/* If there was no error, set the peer endpoint */
if(!error)
{
IN6_ADDR_COPY(&(parms->ipv6address),&(ucb->REMOTE_HOST6));
ucb->REMOTE_PORT = parms->udpport;
}
else
{
/* Disconnect the UCB. It is in bound state now */
if(!ucb->KEEP_IPADDR)
{
IN6_ADDR_COPY((in6_addr*)(&(in6addr_any)),&(ucb->IPV6ADDR));
} /* Endif */
IN6_ADDR_COPY((in6_addr*)(&(in6addr_any)),&(ucb->REMOTE_HOST6));
ucb->REMOTE_PORT = 0;
} /* Endif */
/* add scope_id here */
ucb->IF_SCOPE_ID = parms->if_scope_id;
RTCSCMD_complete(parms, error);
return;
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_connect
* Parameters :
*
* UCB_STRUCT_PTR ucb [IN] bound or open UCB
* _CODE_PTR_ udpservice not used
* _ip_address ipaddress [IN] peer IP address
* uint_16 udpport [IN] peer port
* uint_16 udpflags not used
* pointer udpptr not used
* uint_32 udpword [IN] socket level error
*
* Comments :
* Connects a UCB to a peer port.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
void UDP_connect
(
UDP_PARM_PTR parms
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UCB_STRUCT_PTR ucb = parms->ucb, search_ptr, _PTR_ tmp_ptr;
UCB_STRUCT_PTR _PTR_ ins_ptr, _PTR_ del_ptr;
uint_16 port;
uint_32 error = parms->udpword;
UDP_cfg_ptr = RTCS_getcfg(UDP);
if (!error && (!(parms->udpport) || parms->ipaddress == INADDR_ANY)) {
/* Connect requires both a port AND and IP address. */
error = RTCSERR_UDP_PORT_ZERO;
} else if (!error) {
/* Bind a local address if none is specified */
if (ucb->IPADDR == INADDR_ANY) {
ucb->IPADDR = IP_route_find(parms->ipaddress, 0);
if (ucb->IPADDR == INADDR_ANY) {
error = RTCSERR_IP_UNREACH;
} else {
/*
** Make sure this connect request does not put two UCB's into the
** same configuration.
*/
port = ucb->PORT;
RTCS_LIST_SEARCH(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr) {
if (search_ptr != ucb && search_ptr->PORT == port &&
search_ptr->IPADDR == ucb->IPADDR)
{
error = RTCSERR_UDP_PORT_OPEN;
ucb->IPADDR = INADDR_ANY;
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
} /* Endif */
} /*Endif */
/*
** Check for errors and location of UCB. If TRUE, UCB must be moved.
** This is an evaluates to TRUE if one of the following is true:
** A. There is an error, and there is a remote port OR
** B. There is no error, and there is no remote port
*/
if (!(error) == !(ucb->REMOTE_PORT)) {
if (ucb->REMOTE_PORT) {
if (ucb->KEEP_IPADDR) {
ins_ptr = &(UDP_cfg_ptr->LBOUND_UCB_HEAD);
} else {
ins_ptr = &(UDP_cfg_ptr->BOUND_UCB_HEAD);
} /* Endif */
del_ptr = &(UDP_cfg_ptr->OPEN_UCB_HEAD);
} else {
ins_ptr = &(UDP_cfg_ptr->OPEN_UCB_HEAD);
if (ucb->KEEP_IPADDR) {
del_ptr = &(UDP_cfg_ptr->LBOUND_UCB_HEAD);
} else {
del_ptr = &(UDP_cfg_ptr->BOUND_UCB_HEAD);
} /* Endif */
} /* Endif */
/* Move the UCB from one list to the other */
RTCS_LIST_SEARCHMOD(*del_ptr, tmp_ptr)
{
if (*tmp_ptr == ucb) {
RTCS_LIST_DEL(*del_ptr, tmp_ptr);
break;
} /* Endif */
} /* End SEARCH */
RTCS_LIST_INS_END(*ins_ptr, ucb, tmp_ptr);
} /* Endif */
/* If there was no error, set the peer endpoint */
if (!error) {
ucb->REMOTE_HOST = parms->ipaddress;
ucb->REMOTE_PORT = parms->udpport;
} else {
/* Disconnect the UCB. It is in bound state now */
if (!ucb->KEEP_IPADDR) {
ucb->IPADDR = INADDR_ANY;
} /* Endif */
ucb->REMOTE_HOST = INADDR_ANY;
ucb->REMOTE_PORT = 0;
} /* Endif */
RTCSCMD_complete(parms, error);
return;
} /* Endbody */
#endif //RTCSCFG_ENABLE_IP4
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_receive6
* Parameters :
*
* UCB_STRUCT_PTR ucb [IN] UCB
* _CODE_PTR_ udpservice not used
* in6_addr ipv6address;
* uint_16 udpport [OUT] source UDP port
* uint_16 udpflags [IN] flags
* pointer udpptr [IN/OUT] data buffer
* uint_32 udpword [IN/OUT] length of buffer
*
* Comments :
* Processes a receive request from the application.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP6
void UDP_receive6
(
UDP_PARM_PTR parms
)
{ /* Body */
RTCSPCB_PTR pcb_ptr;
/*
** Search for a waiting packet on incoming queue
*/
RTCS_QUEUE_PEEK(parms->ucb->PHEAD, parms->ucb->PTAIL, pcb_ptr);
if(pcb_ptr)
{
if(!(parms->udpflags & RTCS_MSG_PEEK))
{
RTCS_QUEUE_DEL_NONEMPTY(parms->ucb->PHEAD, parms->ucb->PTAIL);
parms->ucb->PCOUNT--;
} /* Endif */
/*
** Return request to Socket Layer with packet
*/
IN6_ADDR_COPY((in6_addr *)(((IP_V6_HEADER_PTR)(pcb_ptr->NETWORK_LAYER))->SOURCE),&(parms->ipv6address));
parms->udpport = UDP_source(pcb_ptr);
if(parms->udpword > RTCSPCB_SIZE(pcb_ptr))
{
parms->udpword = RTCSPCB_SIZE(pcb_ptr);
} /* Endif */
RTCSPCB_memcopy(pcb_ptr, parms->udpptr, 0, parms->udpword);
((SOCKET_STRUCT_PTR)parms->ucb->SOCKET)->LINK_OPTIONS.RX = pcb_ptr->LINK_OPTIONS.RX;
if(!(parms->udpflags & RTCS_MSG_PEEK))
{
RTCSLOG_PCB_FREE(pcb_ptr, RTCS_OK);
RTCSPCB_free(pcb_ptr);
} /* Endif */
RTCSCMD_complete(parms, RTCS_OK);
return;
}else if(parms->ucb->NONBLOCK_RX || (parms->udpflags & RTCS_MSG_PEEK))
{
/*
** Return request to Socket Layer with zero bytes
*/
parms->ipaddress = INADDR_ANY;
parms->udpport = 0;
parms->udpword = 0;
RTCSCMD_complete(parms, RTCS_OK);
return;
}
else
{
/*
** Otherwise, enqueue the request
*/
RTCS_QUEUE_INS(parms->ucb->RHEAD, parms->ucb->RTAIL, parms);
} /* Endif */
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_receive
* Parameters :
*
* UCB_STRUCT_PTR ucb [IN] UCB
* _CODE_PTR_ udpservice not used
* _ip_address ipaddress [OUT] source IP address
* uint_16 udpport [OUT] source UDP port
* uint_16 udpflags [IN] flags
* pointer udpptr [IN/OUT] data buffer
* uint_32 udpword [IN/OUT] length of buffer
*
* Comments :
* Processes a receive request from the application.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
void UDP_receive
(
UDP_PARM_PTR parms
)
{ /* Body */
RTCSPCB_PTR pcb_ptr;
/*
** Search for a waiting packet on incoming queue
*/
RTCS_QUEUE_PEEK(parms->ucb->PHEAD, parms->ucb->PTAIL, pcb_ptr);
if (pcb_ptr) {
if (!(parms->udpflags & RTCS_MSG_PEEK)) {
RTCS_QUEUE_DEL_NONEMPTY(parms->ucb->PHEAD, parms->ucb->PTAIL);
parms->ucb->PCOUNT--;
} /* Endif */
/*
** Return request to Socket Layer with packet
*/
parms->ipaddress = IP_source(pcb_ptr);
parms->udpport = UDP_source(pcb_ptr);
if (parms->udpword > RTCSPCB_SIZE(pcb_ptr)) {
parms->udpword = RTCSPCB_SIZE(pcb_ptr);
} /* Endif */
RTCSPCB_memcopy(pcb_ptr, parms->udpptr, 0, parms->udpword);
((SOCKET_STRUCT_PTR)parms->ucb->SOCKET)->LINK_OPTIONS.RX = pcb_ptr->LINK_OPTIONS.RX;
if (!(parms->udpflags & RTCS_MSG_PEEK)) {
RTCSLOG_PCB_FREE(pcb_ptr, RTCS_OK);
RTCSPCB_free(pcb_ptr);
} /* Endif */
RTCSCMD_complete(parms, RTCS_OK);
return;
} else if (parms->ucb->NONBLOCK_RX || (parms->udpflags & RTCS_MSG_PEEK)) {
/*
** Return request to Socket Layer with zero bytes
*/
parms->ipaddress = INADDR_ANY;
parms->udpport = 0;
parms->udpword = 0;
RTCSCMD_complete(parms, RTCS_OK);
return;
} else {
/*
** Otherwise, enqueue the request
*/
RTCS_QUEUE_INS(parms->ucb->RHEAD, parms->ucb->RTAIL, parms);
} /* Endif */
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_send
* Parameters :
*
* UCB_STRUCT_PTR ucb [IN] UCB
* _CODE_PTR_ udpservice not used
* _ip_address ipaddress [IN] destination IP address
* uint_16 udpport [IN] destination UDP port
* uint_16 udpflags [IN] flags
* pointer udpptr [IN] data to send
* uint_32 udpword [IN] length of data to send
*
* Comments :
* Sends a UDP packet.
*
*END*-----------------------------------------------------------------*/
void UDP_send
(
UDP_PARM_PTR parms
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
RTCSPCB_PTR pcb;
register boolean nonblock;
uint_32 error;
UDP_cfg_ptr = RTCS_getcfg(UDP);
if (parms->udpport == 0) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_DISCARDED++);
RTCSCMD_complete(parms, RTCSERR_UDP_PORT_ZERO);
return;
} /* Endif */
pcb = RTCSPCB_alloc_send();
if (pcb == NULL) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
RTCSCMD_complete(parms, RTCSERR_PCB_ALLOC);
return;
} /* Endif */
if (parms->udpflags & RTCS_MSG_O_NONBLOCK) {
nonblock = parms->udpflags & RTCS_MSG_S_NONBLOCK;
} else {
nonblock = parms->ucb->NONBLOCK_TX;
} /* Endif */
if (nonblock) {
uchar_ptr udpbuffer;
udpbuffer = RTCS_mem_alloc_system(parms->udpword);
if (!udpbuffer) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
RTCSLOG_PCB_FREE(pcb, RTCSERR_PCB_ALLOC);
RTCSPCB_free(pcb);
RTCSCMD_complete(parms, RTCSERR_PCB_ALLOC);
return;
} /* Endif */
_mem_set_type(udpbuffer, MEM_TYPE_UDP_BUFFER);
error = RTCSPCB_append_fragment_autofree(pcb, parms->udpword, udpbuffer);
if (error) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
IF_UDP_STATS_ENABLED(RTCS_seterror(&UDP_cfg_ptr->STATS.ERR_TX, error, (uint_32)pcb));
_mem_free(udpbuffer);
RTCSLOG_PCB_FREE(pcb, error);
RTCSPCB_free(pcb);
RTCSCMD_complete(parms, error);
return;
} /* Endif */
_mem_copy(parms->udpptr, udpbuffer, parms->udpword);
} else {
error = RTCSPCB_append_fragment(pcb, parms->udpword, parms->udpptr);
if (error) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
IF_UDP_STATS_ENABLED(RTCS_seterror(&UDP_cfg_ptr->STATS.ERR_TX, error, (uint_32)pcb));
RTCSLOG_PCB_FREE(pcb, error);
RTCSPCB_free(pcb);
RTCSCMD_complete(parms, error);
return;
} /* Endif */
pcb->UDP_REQUEST = parms;
} /* Endif */
pcb->LINK_OPTIONS.TX = ((SOCKET_STRUCT_PTR)parms->ucb->SOCKET)->LINK_OPTIONS.TX;
parms->COMMON.ERROR = RTCS_OK;
/* Added IPv6 support */
/*
TBD :
I create UDP_send_internal6 just for compatibility and clear view.
Later it should be integrated with UDP_send_internal
*/
error=1;
#if RTCSCFG_ENABLE_IP4
if(((SOCKET_STRUCT_PTR)parms->ucb->SOCKET)->AF == AF_INET)
{
error = UDP_send_internal(parms->ucb, parms->ucb->IPADDR, parms->ipaddress, parms->udpport, pcb, parms->udpflags);
}
#if RTCSCFG_ENABLE_IP6
else
#endif
#endif
#if RTCSCFG_ENABLE_IP6
if((((SOCKET_STRUCT_PTR)parms->ucb->SOCKET)->AF == AF_INET6))
{
if(parms->if_scope_id)
{
/* parms->if_scope_id has value of scope_id from destination address.
* If it is not NULL we will use it for calculation what interface we will be used for send packet.
*/
pcb->IFSRC = ip6_if_get_by_scope_id( parms->if_scope_id);
}
else if(parms->ucb->IF_SCOPE_ID)
{/* parms->ucb->IF_SCOPE_ID has value of scope_id from local address.
* If it is not NULL we will use it for calculation what interface we will be used for send packet.
*/
pcb->IFSRC = ip6_if_get_by_scope_id( parms->ucb->IF_SCOPE_ID);
}
else
{ /*
* if scope_id was not defined( is NULL) let IP level calculate send interface
*/
pcb->IFSRC = NULL;
}
error = UDP_send_internal6(parms->ucb, parms->ucb->IPV6ADDR, parms->ipv6address, parms->udpport, pcb, parms->udpflags);
}
#endif /* RTCSCFG_ENABLE_IP6 */
if (nonblock)
{
RTCSCMD_complete(parms, error);
}
else if (error)
{
parms->COMMON.ERROR = error; /* Assumes application is lower priority */
} /* Endif */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_send_internal6
* Returned Values : error code
* Comments :
* Sends a UDP packet.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP6
uint_32 UDP_send_internal6
(
UCB_STRUCT_PTR ucb, /* [IN] UDP layer context */
in6_addr srcaddr, /* [IN] source IPv6 address */
in6_addr destaddr, /* [IN] destination IPv6 address */
uint_16 destport, /* [IN] destination UDP port */
RTCSPCB_PTR pcb_ptr, /* [IN] packet to send */
uint_32 flags /* [IN] optional flags */
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UDP_HEADER_PTR packet;
register boolean nochksum;
uint_32 error;
UDP_cfg_ptr = RTCS_getcfg(UDP);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);
error = RTCSPCB_insert_header(pcb_ptr, sizeof(UDP_HEADER));
if (error) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
IF_UDP_STATS_ENABLED(RTCS_seterror(&UDP_cfg_ptr->STATS.ERR_TX, error, (uint_32)pcb_ptr));
RTCSLOG_PCB_FREE(pcb_ptr, error);
RTCSPCB_free(pcb_ptr);
return error;
} /* Endif */
RTCSLOG_PCB_WRITE(pcb_ptr, RTCS_LOGCTRL_PROTO(IPPROTO_UDP), 0);
packet = (UDP_HEADER_PTR)RTCSPCB_DATA(pcb_ptr);
RTCSPCB_DATA_TRANSPORT(pcb_ptr) = RTCSPCB_DATA(pcb_ptr);
htons(packet->SRC_PORT, ucb->PORT);
htons(packet->DEST_PORT, destport);
htons(packet->LENGTH, RTCSPCB_SIZE(pcb_ptr));
htons(packet->CHECKSUM, 0);
if (flags & RTCS_MSG_O_NOCHKSUM) {
nochksum = flags & RTCS_MSG_S_NOCHKSUM;
} else {
nochksum = ucb->BYPASS_TX;
} /* Endif */
if (!nochksum)
{
pcb_ptr->IP_SUM = IP_Sum_PCB(RTCSPCB_SIZE(pcb_ptr), pcb_ptr);
pcb_ptr->IP_SUM_PTR = packet->CHECKSUM;
} /* Endif */
/*
Here I am checking is local IP is NULL or not
It is necessary for allow IPsend change NULL local ipv6 to correct local IPv6
*/
if(IN6_ARE_ADDR_EQUAL(&srcaddr, &in6addr_any))
{
return IP6_send(pcb_ptr, IPPROTO_UDP, NULL,&destaddr, pcb_ptr->IFSRC, 0);
}
else
{
return IP6_send(pcb_ptr, IPPROTO_UDP, &srcaddr,&destaddr, pcb_ptr->IFSRC, 0);
}
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_send_internal
* Returned Values : error code
* Comments :
* Sends a UDP packet.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
uint_32 UDP_send_internal
(
UCB_STRUCT_PTR ucb, /* [IN] UDP layer context */
_ip_address srcaddr, /* [IN] source IP address */
_ip_address destaddr, /* [IN] destination IP address */
uint_16 destport, /* [IN] destination UDP port */
RTCSPCB_PTR pcb_ptr, /* [IN] packet to send */
uint_32 flags /* [IN] optional flags */
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UDP_HEADER_PTR packet;
register boolean nochksum;
uint_32 error;
UDP_cfg_ptr = RTCS_getcfg(UDP);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);
error = RTCSPCB_insert_header(pcb_ptr, sizeof(UDP_HEADER));
if (error) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
IF_UDP_STATS_ENABLED(RTCS_seterror(&UDP_cfg_ptr->STATS.ERR_TX, error, (uint_32)pcb_ptr));
RTCSLOG_PCB_FREE(pcb_ptr, error);
RTCSPCB_free(pcb_ptr);
return error;
} /* Endif */
RTCSLOG_PCB_WRITE(pcb_ptr, RTCS_LOGCTRL_PROTO(IPPROTO_UDP), 0);
packet = (UDP_HEADER_PTR)RTCSPCB_DATA(pcb_ptr);
RTCSPCB_DATA_TRANSPORT(pcb_ptr) = RTCSPCB_DATA(pcb_ptr);
htons(packet->SRC_PORT, ucb->PORT);
htons(packet->DEST_PORT, destport);
htons(packet->LENGTH, RTCSPCB_SIZE(pcb_ptr));
htons(packet->CHECKSUM, 0);
if (flags & RTCS_MSG_O_NOCHKSUM) {
nochksum = flags & RTCS_MSG_S_NOCHKSUM;
} else {
nochksum = ucb->BYPASS_TX;
} /* Endif */
if (!nochksum) {
pcb_ptr->IP_SUM = IP_Sum_PCB(RTCSPCB_SIZE(pcb_ptr), pcb_ptr);
pcb_ptr->IP_SUM_PTR = packet->CHECKSUM;
} /* Endif */
return IP_send(pcb_ptr, IPPROTO_UDP, srcaddr, destaddr, flags);
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_send_IF
* Returned Values : uint_32 (error code)
* Comments :
* Sends a UDP packet through a specific IP interface.
*
*END*-----------------------------------------------------------------*/
uint_32 UDP_send_IF
(
UCB_STRUCT_PTR ucb, /* [IN/OUT] UDP layer context */
pointer dest_if, /* [IN] dest interface */
uint_16 dest_port, /* [IN] dest port */
RTCSPCB_PTR pcb_ptr /* [IN/OUT] packet to send */
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UDP_HEADER_PTR packet;
uint_32 error;
UDP_cfg_ptr = RTCS_getcfg(UDP);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);
if (dest_port == 0) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_DISCARDED++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCSERR_UDP_PORT_ZERO);
RTCSPCB_free(pcb_ptr);
return RTCSERR_UDP_PORT_ZERO;
} /* Endif */
error = RTCSPCB_insert_header(pcb_ptr, sizeof(UDP_HEADER));
if (error) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
IF_UDP_STATS_ENABLED(RTCS_seterror(&UDP_cfg_ptr->STATS.ERR_TX, error, (uint_32)pcb_ptr));
RTCSLOG_PCB_FREE(pcb_ptr, error);
RTCSPCB_free(pcb_ptr);
return error;
} /* Endif */
RTCSLOG_PCB_WRITE(pcb_ptr, RTCS_LOGCTRL_PROTO(IPPROTO_UDP), 0);
packet = (UDP_HEADER_PTR)RTCSPCB_DATA(pcb_ptr);
RTCSPCB_DATA_TRANSPORT(pcb_ptr) = RTCSPCB_DATA(pcb_ptr);
htons(packet->SRC_PORT, ucb->PORT);
htons(packet->DEST_PORT, dest_port);
htons(packet->LENGTH, RTCSPCB_SIZE(pcb_ptr));
htons(packet->CHECKSUM, 0);
pcb_ptr->IP_SUM = IP_Sum_PCB(RTCSPCB_SIZE(pcb_ptr), pcb_ptr);
pcb_ptr->IP_SUM_PTR = packet->CHECKSUM;
return IP_send_IF(pcb_ptr, IPPROTO_UDP, dest_if);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_service6
* Returned Values : void
* Comments :
* Process incoming UDP packets for IPv6 family. Called from IP6_service.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP6
void UDP_service6
(
RTCSPCB_PTR pcb_ptr, /* [IN/OUT] incoming packet */
pointer dummy /* [IN] not used */
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UDP_HEADER_PTR packet;
uint_16 port, src_port, len, sum;
UCB_STRUCT_PTR ucb_ptr = NULL;
UCB_STRUCT_PTR _PTR_ search_ptr;
/*IPv6 part************/
IP6_HEADER_PTR ip6_packet;
in6_addr ipv6source;
in6_addr ipv6dest;
uint_32 error;
UDP_cfg_ptr = RTCS_getcfg(UDP);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_TOTAL++);
packet = (UDP_HEADER_PTR)RTCSPCB_DATA(pcb_ptr);
RTCSPCB_DATA_TRANSPORT(pcb_ptr) = RTCSPCB_DATA(pcb_ptr);
port = ntohs(packet->DEST_PORT);
len = ntohs(packet->LENGTH);
/*
** Make sure that
** sizeof(UDP_HEADER) <= pktlen <= RTCSPCB_SIZE(pcb)
**
** Note: If RTCSPCB_SIZE(pcb) is too small, then pktlen is
** undefined. However, if the following conditions pass,
** then RTCSPCB_SIZE(pcb) >= sizeof(UDP_HEADER), and
** therefore, pktlen is valid.
*/
if(
len < sizeof(UDP_HEADER)
)
{
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCSERR_UDP_BAD_HEADER);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
if(
RTCSPCB_SIZE(pcb_ptr) < len
)
{
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_SMALL_PKT++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCSERR_UDP_BAD_HEADER);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
RTCSLOG_PCB_READ(pcb_ptr, RTCS_LOGCTRL_PROTO(IPPROTO_UDP), 0);
/*
** Port zero is an illegal destination
*/
if(
port == 0
)
{
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_BAD_PORT++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCSERR_UDP_BAD_HEADER);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
/*
** Find a listening UCB, and move it to the front.
** There are multiple lists to search. If the UNICAST bit in the pcb is not
** set, we will only check the BOUND list, because this is the only list
** that can receive Multicast or Broadcast packets. No ucb that is bound to
** a specific local IP can receive a multicast or broadcast packet.
*/
/*convert packet to IP6_HEADER_PTR type*/
ip6_packet= (IP6_HEADER_PTR)RTCSPCB_DATA_NETWORK(pcb_ptr);
/* extract source port number */
src_port = ntohs(packet->SRC_PORT);
/* using IPv6 copy macros to copy the IPv6 address structure */
IN6_ADDR_COPY((in6_addr *)ip6_packet->SOURCE, &ipv6source);
IN6_ADDR_COPY((in6_addr *)ip6_packet->DEST, &ipv6dest);
/*
** Only search this list if the packet might be unicast.
** The search criterion is matching host PORT/IP and matching peer PORT/IP
*/
if(
pcb_ptr->TYPE & RTCSPCB_TYPE_UNICAST
)
{
RTCS_LIST_PEEK(UDP_cfg_ptr->OPEN_UCB_HEAD, ucb_ptr);
if(
ucb_ptr &&(
ucb_ptr->PORT != port ||
(!IN6_ARE_ADDR_EQUAL(&(ucb_ptr->REMOTE_HOST6), &ipv6source))||
ucb_ptr->REMOTE_PORT != src_port ||
(!IN6_ARE_ADDR_EQUAL(&(ucb_ptr->IPV6ADDR), &ipv6dest))
)
)
{
ucb_ptr = NULL;
RTCS_LIST_SEARCHMOD_NOHEAD(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr)
{
if(
(*search_ptr)->PORT == port &&
(IN6_ARE_ADDR_EQUAL(&((*search_ptr)->REMOTE_HOST6), &ipv6source))&&
(*search_ptr)->REMOTE_PORT == src_port &&
(IN6_ARE_ADDR_EQUAL(&((*search_ptr)->IPV6ADDR), &ipv6dest))
)
{
ucb_ptr = *search_ptr;
RTCS_LIST_DEL(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr);
RTCS_LIST_INS(UDP_cfg_ptr->OPEN_UCB_HEAD, ucb_ptr);
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
} /* Endif */
#if RTCSCFG_UDP_ENABLE_LBOUND_MULTICAST && RTCSCFG_ENABLE_IGMP && RTCSCFG_ENABLE_IP4
/*
** If no OPEN ucb matches, search the LBOUND ucb list,
** allowing multicast. The local port must match the
** packet destination port.
*/
if(!ucb_ptr && UDP_cfg_ptr->LBOUND_UCB_HEAD)
{
/*TODO:tihs part of code looks like never was tested and work at all*/
RTCS_LIST_PEEK(UDP_cfg_ptr->LBOUND_UCB_HEAD, ucb_ptr);
if(
ucb_ptr &&
(
(ucb_ptr->PORT != port) ||
(!IN6_IS_ADDR_MULTICAST(&ipv6dest)
) ||
(
!IGMP_is_member (&ucb_ptr->MCB_PTR, pcb_ptr->IFSRC, ipdest)
)
)
{
ucb_ptr = NULL;
RTCS_LIST_SEARCHMOD_NOHEAD(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr)
{
if (
(
(*search_ptr)->PORT == port) &&
(IN_MULTICAST(ipdest)) &&
(IGMP_is_member(&(*search_ptr)->MCB_PTR, pcb_ptr->IFSRC, ipdest))
)
{
ucb_ptr = *search_ptr;
RTCS_LIST_DEL(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr);
RTCS_LIST_INS(UDP_cfg_ptr->LBOUND_UCB_HEAD, ucb_ptr);
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
} /* Endif */
#else
/*
** If no OPEN ucb matches, search the LBOUND ucb list.
** Only search this list if the packet could be unicast.
** The search criterion is a matching local IP/PORT
*/
if(
!ucb_ptr && UDP_cfg_ptr->LBOUND_UCB_HEAD &&
(pcb_ptr->TYPE & RTCSPCB_TYPE_UNICAST)
)
{
RTCS_LIST_PEEK(UDP_cfg_ptr->LBOUND_UCB_HEAD, ucb_ptr);
if(
ucb_ptr &&
ucb_ptr->PORT != port ||
(!IN6_ARE_ADDR_EQUAL(&(ucb_ptr->IPV6ADDR), &ipv6dest))
)
{
ucb_ptr = NULL;
RTCS_LIST_SEARCHMOD_NOHEAD(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr)
{
if(
(*search_ptr)->PORT == port &&
IN6_ARE_ADDR_EQUAL(&((*search_ptr)->IPV6ADDR), &ipv6dest)
)
{
ucb_ptr = *search_ptr;
RTCS_LIST_DEL(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr);
RTCS_LIST_INS(UDP_cfg_ptr->LBOUND_UCB_HEAD, ucb_ptr);
break;
} /* Endif */
} /* End SEARCH */
}/* Endif */
} /* Endif */
#endif
/*
** If no LBOUND ucb matches, search the BOUND ucb list
** Always search this list, regardless of packet type.
** The local port must match the packet destination port
*/
if(!ucb_ptr && UDP_cfg_ptr->BOUND_UCB_HEAD)
{
RTCS_LIST_PEEK(UDP_cfg_ptr->BOUND_UCB_HEAD, ucb_ptr);
if(ucb_ptr && ucb_ptr->PORT != port)
{
ucb_ptr = NULL;
RTCS_LIST_SEARCHMOD_NOHEAD(UDP_cfg_ptr->BOUND_UCB_HEAD, search_ptr)
{
if((*search_ptr)->PORT == port)
{
ucb_ptr = *search_ptr;
RTCS_LIST_DEL(UDP_cfg_ptr->BOUND_UCB_HEAD, search_ptr);
RTCS_LIST_INS(UDP_cfg_ptr->BOUND_UCB_HEAD, ucb_ptr);
break;
} /* Endif */
} /* End SEARCH */
}/* Endif */
/* Check the message was multicast, and if the ucb is a member */
if (
ucb_ptr &&
IN6_IS_ADDR_MULTICAST(&ipv6dest)
)
{
ucb_ptr = NULL;
} /* Endif */
} /* Endif */
/* Lets check scope_id there binded socket and scope _id of input packet*/
error = ip6_if_get_scope_id(pcb_ptr->IFSRC);
/*
* If scope_id of input packet is different from UCB scope_id set UCB to NULL and
* UCB to NULL, to discard packet and generate error.
*/
if(ucb_ptr->IF_SCOPE_ID)
{
if(ucb_ptr->IF_SCOPE_ID != error)
{
ucb_ptr = NULL;
}
}
/*
** If no UCB was found on the destination port, discard packet and generate
** a ICMP error packet
*/
if(!ucb_ptr)
{
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_NO_PORT++);
ICMP6_send_error (ICMP6_TYPE_DEST_UNREACH, ICMP6_CODE_DU_PORT_UNREACH,
0 /* [IN] error parameter */,
pcb_ptr /* [IN] the packet which caused the error */);
RTCSLOG_PCB_FREE(pcb_ptr, RTCS_OK);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
/*
** Verify the checksum if present
*/
if(ntohs(packet->CHECKSUM) && !ucb_ptr->BYPASS_RX)
{
/*IP6 use different method for calculation checksum*/
sum = IP6_Sum_pseudo(RTCSPCB_SIZE(pcb_ptr), pcb_ptr);
sum = IP_Sum_PCB(sum, pcb_ptr);
if (sum != 0xFFFF)
{
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_BAD_CHECKSUM++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCSERR_UDP_BAD_CHECKSUM);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
} /* Endif */
/*
** Although RTCSPCB_shrink() always shrinks the first fragment,
** this is OK, because if RTCSPCB_SIZE(pcb_ptr) != len, then the
** datagram must have originated from another host, in which
** case the PCB only has one fragment.
**
** If the packet originated on this host (and was looped back),
** the datagram could have several fragments, but in this case,
** RTCSPCB_SIZE(pcb_ptr) == len, so we'll always shrink zero bytes.
*/
error = RTCSPCB_shrink(pcb_ptr, RTCSPCB_SIZE(pcb_ptr) - len);
if(error)
{
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_ERRORS++);
IF_UDP_STATS_ENABLED(RTCS_seterror(&UDP_cfg_ptr->STATS.ERR_RX, error, (uint_32)pcb_ptr));
RTCSLOG_PCB_FREE(pcb_ptr, error);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
error = RTCSPCB_next(pcb_ptr, sizeof(UDP_HEADER));
if(error)
{
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_ERRORS++);
IF_UDP_STATS_ENABLED(RTCS_seterror(&UDP_cfg_ptr->STATS.ERR_RX, error, (uint_32)pcb_ptr));
RTCSLOG_PCB_FREE(pcb_ptr, error);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
ucb_ptr->SERVICE(pcb_ptr, ucb_ptr);
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_service
* Returned Values : void
* Comments :
* Process incoming UDP packets. Called from IP_service.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
void UDP_service
(
RTCSPCB_PTR pcb_ptr, /* [IN/OUT] incoming packet */
pointer dummy /* [IN] not used */
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UDP_HEADER_PTR packet;
uint_16 port, src_port, len, sum;
UCB_STRUCT_PTR ucb_ptr = NULL;
UCB_STRUCT_PTR _PTR_ search_ptr;
_ip_address ipdest, ipsource;
uint_32 error;
UDP_cfg_ptr = RTCS_getcfg(UDP);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_TOTAL++);
packet = (UDP_HEADER_PTR)RTCSPCB_DATA(pcb_ptr);
RTCSPCB_DATA_TRANSPORT(pcb_ptr) = RTCSPCB_DATA(pcb_ptr);
port = ntohs(packet->DEST_PORT);
len = ntohs(packet->LENGTH);
/*
** Make sure that
** sizeof(UDP_HEADER) <= pktlen <= RTCSPCB_SIZE(pcb)
**
** Note: If RTCSPCB_SIZE(pcb) is too small, then pktlen is
** undefined. However, if the following conditions pass,
** then RTCSPCB_SIZE(pcb) >= sizeof(UDP_HEADER), and
** therefore, pktlen is valid.
*/
if (len < sizeof(UDP_HEADER)) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCSERR_UDP_BAD_HEADER);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
if (RTCSPCB_SIZE(pcb_ptr) < len) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_SMALL_PKT++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCSERR_UDP_BAD_HEADER);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
RTCSLOG_PCB_READ(pcb_ptr, RTCS_LOGCTRL_PROTO(IPPROTO_UDP), 0);
/*
** Port zero is an illegal destination
*/
if (port == 0) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_BAD_PORT++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCSERR_UDP_BAD_HEADER);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
/*
** Find a listening UCB, and move it to the front.
** There are multiple lists to search. If the UNICAST bit in the pcb is not
** set, we will only check the BOUND list, because this is the only list
** that can receive Multicast or Broadcast packets. No ucb that is bound to
** a specific local IP can receive a multicast or broadcast packet.
*/
src_port = ntohs(packet->SRC_PORT);
ipsource = IP_source(pcb_ptr);
ipdest = IP_dest(pcb_ptr);
/*
** Only search this list if the packet might be unicast.
** The search criterion is matching host PORT/IP and matching peer PORT/IP
*/
if (pcb_ptr->TYPE & RTCSPCB_TYPE_UNICAST) {
RTCS_LIST_PEEK(UDP_cfg_ptr->OPEN_UCB_HEAD, ucb_ptr);
if (ucb_ptr &&
(ucb_ptr->PORT != port ||
ucb_ptr->REMOTE_HOST != ipsource ||
ucb_ptr->REMOTE_PORT != src_port ||
ucb_ptr->IPADDR != ipdest))
{
ucb_ptr = NULL;
RTCS_LIST_SEARCHMOD_NOHEAD(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr) {
if ((*search_ptr)->PORT == port &&
(*search_ptr)->REMOTE_HOST == ipsource &&
(*search_ptr)->REMOTE_PORT == src_port &&
(*search_ptr)->IPADDR == ipdest)
{
ucb_ptr = *search_ptr;
RTCS_LIST_DEL(UDP_cfg_ptr->OPEN_UCB_HEAD, search_ptr);
RTCS_LIST_INS(UDP_cfg_ptr->OPEN_UCB_HEAD, ucb_ptr);
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
} /* Endif */
#if RTCSCFG_UDP_ENABLE_LBOUND_MULTICAST && RTCSCFG_ENABLE_IGMP && RTCSCFG_ENABLE_IP4
/*
** If no OPEN ucb matches, search the LBOUND ucb list,
** allowing multicast. The local port must match the
** packet destination port.
*/
if (!ucb_ptr && UDP_cfg_ptr->LBOUND_UCB_HEAD) {
RTCS_LIST_PEEK(UDP_cfg_ptr->LBOUND_UCB_HEAD, ucb_ptr);
if (ucb_ptr && ((ucb_ptr->PORT != port) || ((IN_MULTICAST(ipdest)) && (!IGMP_is_member(&ucb_ptr->MCB_PTR, pcb_ptr->IFSRC, ipdest))))) {
ucb_ptr = NULL;
RTCS_LIST_SEARCHMOD_NOHEAD(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr) {
if ((((*search_ptr)->PORT == port) && (!IN_MULTICAST(ipdest))) ||
(((*search_ptr)->PORT == port) && (IN_MULTICAST(ipdest)) && (IGMP_is_member(&(*search_ptr)->MCB_PTR, pcb_ptr->IFSRC, ipdest)))) {
ucb_ptr = *search_ptr;
RTCS_LIST_DEL(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr);
RTCS_LIST_INS(UDP_cfg_ptr->LBOUND_UCB_HEAD, ucb_ptr);
break;
} /* Endif */
} /* End SEARCH */
} /* Endif */
} /* Endif */
#else
/*
** If no OPEN ucb matches, search the LBOUND ucb list.
** Only search this list if the packet could be unicast.
** The search criterion is a matching local IP/PORT
*/
if (!ucb_ptr && UDP_cfg_ptr->LBOUND_UCB_HEAD &&
(pcb_ptr->TYPE & RTCSPCB_TYPE_UNICAST)) {
RTCS_LIST_PEEK(UDP_cfg_ptr->LBOUND_UCB_HEAD, ucb_ptr);
if (ucb_ptr && ucb_ptr->PORT != port ||
ucb_ptr->IPADDR != ipdest)
{
ucb_ptr = NULL;
RTCS_LIST_SEARCHMOD_NOHEAD(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr) {
if ((*search_ptr)->PORT == port &&
(*search_ptr)->IPADDR == ipdest)
{
ucb_ptr = *search_ptr;
RTCS_LIST_DEL(UDP_cfg_ptr->LBOUND_UCB_HEAD, search_ptr);
RTCS_LIST_INS(UDP_cfg_ptr->LBOUND_UCB_HEAD, ucb_ptr);
break;
} /* Endif */
} /* End SEARCH */
}/* Endif */
} /* Endif */
#endif
/*
** If no LBOUND ucb matches, search the BOUND ucb list
** Always search this list, regardless of packet type.
** The local port must match the packet destination port
*/
if (!ucb_ptr && UDP_cfg_ptr->BOUND_UCB_HEAD) {
RTCS_LIST_PEEK(UDP_cfg_ptr->BOUND_UCB_HEAD, ucb_ptr);
if (ucb_ptr && ucb_ptr->PORT != port) {
ucb_ptr = NULL;
RTCS_LIST_SEARCHMOD_NOHEAD(UDP_cfg_ptr->BOUND_UCB_HEAD, search_ptr) {
if ((*search_ptr)->PORT == port) {
ucb_ptr = *search_ptr;
RTCS_LIST_DEL(UDP_cfg_ptr->BOUND_UCB_HEAD, search_ptr);
RTCS_LIST_INS(UDP_cfg_ptr->BOUND_UCB_HEAD, ucb_ptr);
break;
} /* Endif */
} /* End SEARCH */
}/* Endif */
/* Check the message was multicast, and if the ucb is a member */
if (ucb_ptr && IN_MULTICAST(ipdest)) {
#if RTCSCFG_ENABLE_IGMP && RTCSCFG_ENABLE_IP4
if (!IGMP_is_member(&ucb_ptr->MCB_PTR, pcb_ptr->IFSRC, ipdest)) {
ucb_ptr = NULL;
}
#else
ucb_ptr = NULL;
#endif
} /* Endif */
} /* Endif */
/*
** If no UCB was found on the destination port, discard packet and generate
** a ICMP error packet
*/
if (!ucb_ptr) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_NO_PORT++);
#if RTCSCFG_ENABLE_ICMP
ICMP_send_error(ICMPTYPE_DESTUNREACH, ICMPCODE_DU_PORT_UNREACH, 0, pcb_ptr, -1);
#endif
RTCSLOG_PCB_FREE(pcb_ptr, RTCS_OK);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
/*
** Verify the checksum if present
*/
if (ntohs(packet->CHECKSUM) && !ucb_ptr->BYPASS_RX) {
sum = IP_Sum_pseudo(len, pcb_ptr, -1);
sum = IP_Sum_PCB(sum, pcb_ptr);
if (sum != 0xFFFF) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.ST_RX_BAD_CHECKSUM++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCSERR_UDP_BAD_CHECKSUM);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
} /* Endif */
/*
** Although RTCSPCB_shrink() always shrinks the first fragment,
** this is OK, because if RTCSPCB_SIZE(pcb_ptr) != len, then the
** datagram must have originated from another host, in which
** case the PCB only has one fragment.
**
** If the packet originated on this host (and was looped back),
** the datagram could have several fragments, but in this case,
** RTCSPCB_SIZE(pcb_ptr) == len, so we'll always shrink zero bytes.
*/
error = RTCSPCB_shrink(pcb_ptr, RTCSPCB_SIZE(pcb_ptr) - len);
if (error) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_ERRORS++);
IF_UDP_STATS_ENABLED(RTCS_seterror(&UDP_cfg_ptr->STATS.ERR_RX, error, (uint_32)pcb_ptr));
RTCSLOG_PCB_FREE(pcb_ptr, error);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
error = RTCSPCB_next(pcb_ptr, sizeof(UDP_HEADER));
if (error) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_ERRORS++);
IF_UDP_STATS_ENABLED(RTCS_seterror(&UDP_cfg_ptr->STATS.ERR_RX, error, (uint_32)pcb_ptr));
RTCSLOG_PCB_FREE(pcb_ptr, error);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
ucb_ptr->SERVICE(pcb_ptr, ucb_ptr);
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_process6
* Returned Values : void
* Comments :
* Process valid incoming UDP packets for IPv6 family. Called from UDP_service.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP6
void UDP_process6
(
RTCSPCB_PTR pcb_ptr, /* [IN/OUT] incoming packet */
UCB_STRUCT_PTR ucb_ptr /* [IN] target UCB */
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UDP_PARM_PTR req_ptr;
UDP_cfg_ptr = RTCS_getcfg(UDP);
/*
** If there is a pending request, unblock it
*/
RTCS_QUEUE_PEEK(ucb_ptr->RHEAD, ucb_ptr->RTAIL, req_ptr);
if (req_ptr)
{
RTCS_QUEUE_DEL_NONEMPTY(ucb_ptr->RHEAD, ucb_ptr->RTAIL);
IN6_ADDR_COPY((in6_addr *)(((IP_V6_HEADER_PTR)(pcb_ptr->NETWORK_LAYER))->SOURCE),&(req_ptr->ipv6address));
req_ptr->udpport = UDP_source(pcb_ptr);
/* here we get scope_id */
req_ptr->if_scope_id = ip6_if_get_scope_id(pcb_ptr->IFSRC);
if (req_ptr->udpword > RTCSPCB_SIZE(pcb_ptr)) {
req_ptr->udpword = RTCSPCB_SIZE(pcb_ptr);
} /* Endif */
RTCSPCB_memcopy(pcb_ptr, req_ptr->udpptr, 0, req_ptr->udpword);
((SOCKET_STRUCT_PTR)ucb_ptr->SOCKET)->LINK_OPTIONS.RX = pcb_ptr->LINK_OPTIONS.RX;
RTCSLOG_PCB_FREE(pcb_ptr, RTCS_OK);
RTCSPCB_free(pcb_ptr);
RTCSCMD_complete(req_ptr, RTCS_OK);
return;
}
else if (ucb_ptr->PCOUNT >= _UDP_max_queue_size)
{
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_MISSED++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCS_OK);
RTCSPCB_free(pcb_ptr);
return;
/*
** Otherwise, enqueue the packet
*/
}
else
{
RTCS_QUEUE_INS(ucb_ptr->PHEAD, ucb_ptr->PTAIL, pcb_ptr);
ucb_ptr->PCOUNT++;
/*
** Notify socket layer in case some task is blocked on select()
** waiting for this data.
*/
SOCK_select_signal(ucb_ptr->SOCKET, UDP_SOCKET_ENQUEUED);
} /* Endif */
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_process
* Returned Values : void
* Comments :
* Process valid incoming UDP packets. Called from UDP_service.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
void UDP_process
(
RTCSPCB_PTR pcb_ptr, /* [IN/OUT] incoming packet */
UCB_STRUCT_PTR ucb_ptr /* [IN] target UCB */
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UDP_PARM_PTR req_ptr;
UDP_cfg_ptr = RTCS_getcfg(UDP);
/*
** If there is a pending request, unblock it
*/
RTCS_QUEUE_PEEK(ucb_ptr->RHEAD, ucb_ptr->RTAIL, req_ptr);
if (req_ptr) {
RTCS_QUEUE_DEL_NONEMPTY(ucb_ptr->RHEAD, ucb_ptr->RTAIL);
req_ptr->ipaddress = IP_source(pcb_ptr);
req_ptr->udpport = UDP_source(pcb_ptr);
if (req_ptr->udpword > RTCSPCB_SIZE(pcb_ptr)) {
req_ptr->udpword = RTCSPCB_SIZE(pcb_ptr);
} /* Endif */
RTCSPCB_memcopy(pcb_ptr, req_ptr->udpptr, 0, req_ptr->udpword);
((SOCKET_STRUCT_PTR)ucb_ptr->SOCKET)->LINK_OPTIONS.RX = pcb_ptr->LINK_OPTIONS.RX;
RTCSLOG_PCB_FREE(pcb_ptr, RTCS_OK);
RTCSPCB_free(pcb_ptr);
RTCSCMD_complete(req_ptr, RTCS_OK);
return;
} else if (ucb_ptr->PCOUNT >= _UDP_max_queue_size) {
IF_UDP_STATS_ENABLED(UDP_cfg_ptr->STATS.COMMON.ST_RX_MISSED++);
RTCSLOG_PCB_FREE(pcb_ptr, RTCS_OK);
RTCSPCB_free(pcb_ptr);
return;
/*
** Otherwise, enqueue the packet
*/
} else {
RTCS_QUEUE_INS(ucb_ptr->PHEAD, ucb_ptr->PTAIL, pcb_ptr);
ucb_ptr->PCOUNT++;
/*
** Notify socket layer in case some task is blocked on select()
** waiting for this data.
*/
SOCK_select_signal(ucb_ptr->SOCKET, UDP_SOCKET_ENQUEUED);
} /* Endif */
} /* Endbody */
#endif
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_close
* Parameters :
*
* UCB_STRUCT_PTR ucb [IN] UCB
* _CODE_PTR_ udpservice not used
* _ip_address ipaddress not used
* uint_16 udpport not used
* uint_16 udpflags not used
* pointer udpptr not used
* uint_32 udpword not used
*
* Comments :
* Closes a UCB.
*
*END*-----------------------------------------------------------------*/
void UDP_close
(
UDP_PARM_PTR parms
)
{ /* Body */
UDP_CFG_STRUCT_PTR UDP_cfg_ptr;
UCB_STRUCT_PTR ucb, _PTR_ tmp;
UCB_STRUCT_PTR _PTR_ search_ptr; /* Temporary UCB pointer */
UDP_PARM_PTR req, nextreq; /* Temporary request pointers */
RTCSPCB_PTR pcb, nextpcb; /* Temporary packet pointers */
uint_32 error;
UDP_cfg_ptr = RTCS_getcfg(UDP);
ucb = parms->ucb;
/*
** Remove the UCB from the chain of UCBs
*/
if (!ucb->PORT) {
tmp = &(UDP_cfg_ptr->GROUND_UCB_HEAD);
} else if (!ucb->REMOTE_HOST) {
if (ucb->IPADDR) {
tmp = &(UDP_cfg_ptr->LBOUND_UCB_HEAD);
} else {
tmp = &(UDP_cfg_ptr->BOUND_UCB_HEAD);
} /* Endif */
} else {
tmp = &(UDP_cfg_ptr->OPEN_UCB_HEAD);
} /* Endif */
RTCS_LIST_SEARCHMOD(*tmp, search_ptr) {
if (*search_ptr == ucb) {
break;
} /* Endif */
} /* End SEARCH */
if (!*search_ptr) {
RTCSCMD_complete(parms, RTCSERR_UDP_UCB_CLOSE);
return;
} /* Endif */
RTCS_LIST_DEL(tmp, search_ptr);
/*
** Free all queued packets
*/
RTCS_QUEUE_DELALL(ucb->PHEAD, ucb->PTAIL, pcb, nextpcb) {
RTCSLOG_PCB_FREE(pcb, RTCS_OK);
RTCSPCB_free(pcb);
} /* End DELALL */
/*
** Release pending receive requests from host
*/
RTCS_QUEUE_DELALL(ucb->RHEAD, ucb->RTAIL, req, nextreq) {
RTCSCMD_complete(req, RTCSERR_READ_ABORTED);
} /* End DELALL */
/*
** Notify socket layer in case some task is blocked on select()
** waiting for data on this socket.
*/
SOCK_select_signal(ucb->SOCKET, UDP_SOCKET_CLOSE);
/*
** Leave all joined multicast groups
*/
if (ucb->IGMP_LEAVEALL) {
ucb->IGMP_LEAVEALL(&ucb->MCB_PTR);
} /* Endif */
/*
** Free the UCB memory
*/
error = _mem_free(ucb);
if (error) {
RTCSCMD_complete(parms, RTCSERR_UDP_UCB_FREE);
return;
} /* Endif */
RTCSCMD_complete(parms, RTCS_OK);
return;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : UDP_source
* Returned Value : source UDP port
* Comments :
* Return source UDP port of packet.
*
*END*-----------------------------------------------------------------*/
uint_16 UDP_source
(
RTCSPCB_PTR pcb /* [IN] packet to find source of */
)
{ /* Body */
uchar_ptr srcptr = ((UDP_HEADER_PTR)RTCSPCB_DATA_TRANSPORT(pcb))->SRC_PORT;
return ntohs(srcptr);
} /* Endbody */
/* EOF */