/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 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 #include #include #include #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 **************************************************************************** */