333 lines
9.7 KiB
C
333 lines
9.7 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: iplite_udp.c,v $ $Revision: 1.23 $
|
|
* $Source: /home/interpeak/CVSRoot/iplite2/src/iplite_udp.c,v $
|
|
* $Author: hxie $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/* User datagram protocol transport layer */
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifndef IPCOM_KERNEL
|
|
#define IPCOM_KERNEL
|
|
#endif
|
|
#include "iplite_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#if !defined(IPLITE_ONE_FILE) || defined(IPLITE_C)
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_inet.h>
|
|
|
|
#include "iplite_h.h"
|
|
#include "iplite_sock.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_udp_input
|
|
*===========================================================================
|
|
* Description: Input handler for packet to UDP sockets. This function will
|
|
* NOT free the packet if the operation fails.
|
|
* Parameters: pkt - The received packet.
|
|
* is_multicast - Set to IP_TRUE if the packet was sent to a
|
|
* multicast address.
|
|
* proto - The protocol number.
|
|
* src_addr - The address (Ipv4 or IPv6) of the sender.
|
|
* dst_addr - The address (Ipv4 or IPv6) of the receiver (this system).
|
|
* socklookup - A pointer to a function that can return the socket
|
|
* that is associated with this packet.
|
|
* Returns: 0 >= number of matching sockets, <0 = error code
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
iplite_udp_input(Ipcom_pkt *pkt, Ip_bool is_multicast,
|
|
IP_CONST void* src_addr, IP_CONST void* dst_addr,
|
|
Iplite_socklookup socklookup)
|
|
{
|
|
Iplite_pkt_udp *udp_hdr;
|
|
int retval;
|
|
Ip_u16 ulen_h;
|
|
Iplite_socket *sock;
|
|
Ip_u16 src_port;
|
|
Ip_u16 dst_port;
|
|
int next;
|
|
|
|
IPLITE_STATS(udp_input++);
|
|
IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_UDP_INPUT);
|
|
|
|
if (pkt->end - pkt->start < IPLITE_UDP_HDR_SIZE)
|
|
{
|
|
IPLITE_STATS(udp_input_hdr_trunc++);
|
|
IPCOM_MIB2(udpInErrors++);
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
|
|
udp_hdr = (Iplite_pkt_udp*) &pkt->data[pkt->start];
|
|
ulen_h = ip_ntohs(udp_hdr->ulen);
|
|
src_port = ip_ntohs(udp_hdr->sport);
|
|
dst_port = ip_ntohs(udp_hdr->dport);
|
|
|
|
if (pkt->end - pkt->start < ulen_h)
|
|
{
|
|
IPLITE_STATS(udp_input_hdr_trunc++);
|
|
IPCOM_MIB2(udpInErrors++);
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
pkt->end = pkt->start + (int)ulen_h;
|
|
|
|
if (udp_hdr->sum != 0)
|
|
{
|
|
pkt->chk += ipcom_in_checksum_update(&pkt->data[pkt->start],
|
|
(Ip_size_t) ulen_h);
|
|
if (ipcom_in_checksum_finish(pkt->chk) != 0)
|
|
{
|
|
/* Wrong checksum */
|
|
IPLITE_STATS(udp_input_badchksum++);
|
|
IPCOM_MIB2(udpInErrors++);
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
}
|
|
|
|
/* Move the start to beginning of application data */
|
|
pkt->start += IPLITE_UDP_HDR_SIZE;
|
|
|
|
if (is_multicast)
|
|
{
|
|
IPLITE_STATS(udp_input_multicast++);
|
|
retval = iplite_raw_input(pkt, IP_FALSE, IP_IPPROTO_UDP,
|
|
src_addr, src_port, dst_addr, dst_port, socklookup);
|
|
|
|
if (retval >= 0)
|
|
{
|
|
/* The packet must be freed unlesss an error occured */
|
|
ipcom_pkt_free(pkt);
|
|
IPCOM_MIB2(udpInDatagrams++);
|
|
}
|
|
else
|
|
{
|
|
IPCOM_MIB2(udpInErrors++);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/* Lookup UDP socket. Honor the SO_BINDTODEVICE option. */
|
|
next = 0;
|
|
do
|
|
{
|
|
sock = socklookup(IP_IPPROTO_UDP, dst_addr, dst_port, src_addr, src_port, &next);
|
|
} while (sock != IP_NULL
|
|
&& sock->bind_to_ifindex != 0
|
|
&& sock->bind_to_ifindex != pkt->ifindex);
|
|
|
|
if (sock != IP_NULL)
|
|
{
|
|
IPLITE_STATS(udp_input_sock_match++);
|
|
pkt->fd = sock->ipcom.fd;
|
|
|
|
|
|
retval = iplite_queue_received_packet(pkt, sock);
|
|
if (sock->ipcom.event_cb)
|
|
sock->ipcom.event_cb((Ipcom_socket *)sock, pkt, IP_SOEVENT_CB_SELREAD);
|
|
|
|
|
|
|
|
if (retval < 0)
|
|
{
|
|
IPLITE_STATS(udp_input_queue_pkt_err++);
|
|
IPCOM_MIB2(udpInErrors++);
|
|
return retval;
|
|
}
|
|
else
|
|
{
|
|
IPLITE_STATS(udp_input_queue_pkt_ok++);
|
|
}
|
|
|
|
IPCOM_MIB2(udpInDatagrams++);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
IPLITE_STATS(udp_input_sock_nomatch++);
|
|
IPCOM_MIB2(udpNoPorts++);
|
|
}
|
|
|
|
IPLITE_STATS(udp_input_econnrefused++);
|
|
return -IP_ERRNO_ECONNREFUSED;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_udp_output
|
|
*===========================================================================
|
|
* Description: Adds a UDP header to the application data.
|
|
* Parameters: sock - The socket to use when sending.
|
|
* to - The destination address address, ignored if the socket
|
|
* is in connected state.
|
|
* pkt - The packet data to send.
|
|
* Returns: >0 = application bytes sent, <0 = error code.
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
iplite_udp_output(Iplite_socket *sock, IP_CONST struct Ip_sockaddr *to, Ipcom_pkt *pkt)
|
|
{
|
|
Ip_u16 to_port_n;
|
|
Iplite_pkt_udp *udp;
|
|
int ret;
|
|
|
|
IPLITE_STATS(udp_output++);
|
|
ip_assert(sock->ipcom.type == IP_SOCK_DGRAM);
|
|
ip_assert(sock->proto == IP_IPPROTO_UDP);
|
|
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_CONNECTED))
|
|
to_port_n = ip_htons(sock->dport);
|
|
else if (to == IP_NULL)
|
|
{
|
|
/* No destination address */
|
|
ret = -IP_ERRNO_EDESTADDRREQ;
|
|
goto errout;
|
|
}
|
|
else
|
|
/* Ok for both IPv4 and IPv6 */
|
|
to_port_n = ((struct Ip_sockaddr_in*) to)->sin_port;
|
|
|
|
if (pkt->start < IPLITE_UDP_HDR_SIZE)
|
|
{
|
|
/* Not enough space for UDP header */
|
|
IPLITE_STATS(udp_output_hdr_trunc++);
|
|
ret = -IP_ERRNO_EFAULT;
|
|
goto errout;
|
|
}
|
|
|
|
/* Fill in UDP header. */
|
|
pkt->start -= IPLITE_UDP_HDR_SIZE;
|
|
udp = (Iplite_pkt_udp *)&pkt->data[pkt->start];
|
|
|
|
udp->sport = ip_htons(sock->sport);
|
|
ip_assert(udp->sport != 0);
|
|
udp->dport = to_port_n;
|
|
udp->sum = 0;
|
|
udp->ulen = (Ip_u16) ip_htons(pkt->end - pkt->start);
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_ADDCHECKSUM))
|
|
{
|
|
/* Update the checksum with the UDP header */
|
|
pkt->chk += (Ip_u32)udp->sport;
|
|
pkt->chk += (Ip_u32)udp->dport;
|
|
pkt->chk += (Ip_u32)udp->ulen;
|
|
/* note: ignore sum entry since 0! */
|
|
}
|
|
|
|
switch(sock->ipcom.domain)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
IPCOM_MIB2(udpOutDatagrams++);
|
|
return iplite_ip4_sendto(sock, to, pkt);
|
|
#endif
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
IPCOM_MIB2(udpOutDatagrams++);
|
|
return iplite_ip6_sendto(sock, to, pkt);
|
|
#endif
|
|
|
|
default:
|
|
/* Invalid domain */
|
|
IP_PANIC();
|
|
IPLITE_STATS(udp_output_eafnosupport++);
|
|
ret = -IP_ERRNO_EAFNOSUPPORT;
|
|
break;
|
|
}
|
|
|
|
errout:
|
|
ipcom_pkt_free(pkt);
|
|
return ret;
|
|
}
|
|
|
|
#endif /* !defined(IPLITE_ONE_FILE) || defined(IPLITE_C) */
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|