/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: iplite_raw.c,v $ $Revision: 1.31 $ * $Source: /home/interpeak/CVSRoot/iplite2/src/iplite_raw.c,v $ * $Author: hxie $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* Raw socket address family functions */ /* **************************************************************************** * 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 #include "iplite_h.h" #include "iplite_sock.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * iplite_packet_socklookup *=========================================================================== * Description: Returns IP_AF_PACKET sockets that match the frame type. * Parameters: frame_type - The frame type that the matching socket must have. * unused1 - * unused2 - * unused3 - * unused4 - * next - [in] The first socket to look at. [out] the next socket * to look at. Can be IP_NULL if only the first match should be * returned. * Returns: >0 = application bytes sent, <0 = error code. * */ #ifdef IPCOM_USE_PACKET IP_STATIC Iplite_socket * iplite_packet_socklookup(int frame_type, IP_CONST void *unused1, Ip_u16 unused2, IP_CONST void *unused3, Ip_u16 unused4, int *next) { int i; Iplite_socket *sock; (void)unused1; (void)unused2; (void)unused3; (void)unused4; for (i = (next == IP_NULL ? 0 : *next); i < IPLITE_CONF_MAX_SOCKETS; i++) { sock = iplite.sockets[i]; if (sock == IP_NULL) continue; if (sock->ipcom.domain != IP_AF_PACKET) continue; if (sock->proto != 0 && sock->proto != frame_type) continue; if (next != IP_NULL) *next = i + 1; return sock; } return IP_NULL; } #endif /* IPCOM_USE_PACKET */ /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ #ifdef IPCOM_USE_PACKET /* *=========================================================================== * iplite_packet_output *=========================================================================== * Description: Sends a raw frame directly to the driver (IP_SOCK_RAW) or * directly to the link layer to get a link header * (IP_SOCK_DGRAM) (but no ARP or simlilar is performed). * 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_packet_output(Iplite_socket *sock, IP_CONST struct Ip_sockaddr *to, Ipcom_pkt *pkt) { struct Ip_sockaddr_ll *ll_addr = (struct Ip_sockaddr_ll *) to; Iplite_netif *netif; int ret; int max_pkt_len; if (ll_addr->sll_family != IP_AF_PACKET) { IPCOM_LOG2(DEBUG2, "RAW: sll_family must be IP_AF_PACKET (%d), got %d", IP_AF_PACKET, (int)ll_addr->sll_family); return -IP_ERRNO_EPROTOTYPE; } netif = iplite_if_indextonetif(ll_addr->sll_ifindex); if (netif == IP_NULL) { IPCOM_LOG1(DEBUG2, "RAW: %d is not a valid interface index", (int)ll_addr->sll_ifindex); return -IP_ERRNO_ENXIO; } pkt->ifindex = netif->ipcom.ifindex; if (sock->ipcom.type == IP_SOCK_RAW) /* Link layer header included */ max_pkt_len = netif->ipcom.mtu + netif->ipcom.link_hdr_size; else if (sock->ipcom.type == IP_SOCK_DGRAM) /* Link layer must be added by the stack */ max_pkt_len = netif->ipcom.mtu; else { max_pkt_len = 0; IP_PANIC(); } if (pkt->end - pkt->start > max_pkt_len) { IPCOM_LOG2(DEBUG2, "RAW: packet to big (%d bytes), allowed size is %d bytes", (int)(pkt->end - pkt->start), max_pkt_len); return -IP_ERRNO_ENOBUFS; } if (sock->ipcom.type == IP_SOCK_DGRAM) { if (netif->link_raw_output == IP_NULL) { IPCOM_LOG1(DEBUG2, "RAW: interface %s does not support" "IP_SOCK_DGRAM type IP_AF_PACKET sockets", netif->ipcom.name); return -IP_ERRNO_ENOSYS; } if (ll_addr->sll_protocol == 0) { if (sock->proto == 0) { IPCOM_LOG1(DEBUG2, "RAW: protocol was neither specified when the socket %d was created" " nor in the 'to' address", (int)sock->ipcom.fd); return -IP_ERRNO_EFAULT; } ll_addr->sll_protocol = sock->proto; } iplite_if_lock(netif); ret = netif->link_raw_output(netif, ll_addr, pkt); goto leave; } ip_assert(netif->ipcom.drv_output != IP_NULL); iplite_if_lock(netif); ret = iplite_if_output(netif, pkt); leave: (void)iplite_if_unlock(netif); return ret; } /* *=========================================================================== * iplite_packet_input *=========================================================================== * Context: Any non-interrupt context. * Description: Inputs a packet to the stack. * Parameters: netif - The interface the packet was received on. * pkt - The received packet. pkt->start is the offset to the * the link layer header. * Returns: * */ IP_GLOBAL Ip_bool iplite_packet_input(Iplite_netif *netif, Ipcom_pkt *pkt) { int i; Ip_u16 frame_type; Ip_bool continue_process = IP_TRUE; ip_assert(iplite.num_packet_sock > 0); if (netif->link_get_frame_info == IP_NULL) { IPCOM_LOG1(DEBUG2, "RAW: packet sockets is not supported by interface %d", (int)netif->ipcom.ifindex); return IP_TRUE; } i = netif->link_get_frame_info(netif, pkt, IP_NULL, &frame_type, IP_NULL, IP_NULL); if (i < 0) { IPCOM_LOG1(DEBUG2, "RAW: failed to get information about the frame (%d)", -i); return IP_TRUE; } pkt->ipstart = pkt->start; /* to avoid assert in clone() */ /* Give to all sockets that matches the protocol */ if (iplite_raw_input(pkt, IP_FALSE, frame_type, IP_NULL, 0, IP_NULL, 0, (Iplite_socklookup)iplite_packet_socklookup) == -IP_ERRNO_ENODATA) continue_process = IP_FALSE; /* Give to all sockets that should match any protocol -> all packets */ if (iplite_raw_input(pkt, IP_FALSE, 0, IP_NULL, 0, IP_NULL, 0, (Iplite_socklookup)iplite_packet_socklookup) == -IP_ERRNO_ENODATA) continue_process = IP_FALSE; if (!continue_process) ipcom_pkt_free(pkt); return continue_process; } #endif /* IPCOM_USE_PACKET */ /* *=========================================================================== * iplite_raw_input *=========================================================================== * Description: Generic input handler for packet. * Parameters: pkt - The received packet. * take_ownership - Set to IP_TRUE if this function should control * the lifetime of the packet. * proto - The protocol number. * src_addr - The address (Ipv4 or IPv6) of the sender. * src_port - The source port. * dst_addr - The address (Ipv4 or IPv6) of the receiver (this system). * src_port - The destination port. * 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_raw_input(Ipcom_pkt *pkt, Ip_bool take_ownership, int proto, IP_CONST void *src_addr, Ip_u16 src_port, IP_CONST void *dst_addr, Ip_u16 dst_port, Iplite_socklookup socklookup) { int next = 0; /* start from 0 because bound sockets start from 0 */ Ip_bool org_pkt_queued = IP_FALSE; int matching_sock = 0; Iplite_socket *sock; Ipcom_pkt *clone; Ip_u32 checksum; Ip_bool checksum_ok = IP_FALSE; #ifdef IP_PORT_OSE5 iplite.raw_input_id++; #endif while (IP_NULL != (sock = socklookup(proto, dst_addr, dst_port, src_addr, src_port, &next))) { if (checksum_ok == IP_FALSE && IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_ADDCHECKSUM) && sock->proto != IP_IPPROTO_ICMPV6 && sock->proto != IP_IPPROTO_UDP) { /* The checksum must be checked for this packet UDP and ICMPv6 packets has already been checked */ checksum = ipcom_in_checksum_update(&pkt->data[pkt->start], (Ip_size_t) (pkt->end - pkt->start)); if (ipcom_in_checksum_finish(checksum + pkt->chk) != 0) { /* Wrong checksum */ IPLITE_STATS(raw_input_badchksum++); matching_sock = -IP_ERRNO_EINVAL; goto leave; } checksum_ok = IP_TRUE; } #ifdef IP_PORT_OSE5 if (iplite.raw_input_id == sock->raw_input_id) continue; sock->raw_input_id = iplite.raw_input_id; #endif if (org_pkt_queued || !take_ownership) { clone = iplite_pkt_clone(pkt); if (clone == IP_NULL) break; } else clone = pkt; clone->fd = sock->ipcom.fd; if (sock->ipcom.event_cb) sock->ipcom.event_cb((Ipcom_socket *)sock, clone, IP_SOEVENT_CB_INPKT); if (iplite_queue_received_packet(clone, sock) < 0) { if(clone != pkt) ipcom_pkt_free(clone); continue; } if (sock->ipcom.event_cb) sock->ipcom.event_cb((Ipcom_socket *)sock, pkt, IP_SOEVENT_CB_SELREAD); if (pkt == clone) org_pkt_queued = IP_TRUE; matching_sock++; } leave: if (take_ownership && !org_pkt_queued) ipcom_pkt_free(pkt); return matching_sock; } /* *=========================================================================== * iplite_raw_output *=========================================================================== * Description: Dispatches the call to the appropriate output handler. * 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_raw_output(Iplite_socket *sock, IP_CONST struct Ip_sockaddr *to, Ipcom_pkt *pkt) { ip_assert(sock->ipcom.type == IP_SOCK_RAW); switch (sock->ipcom.domain) { #ifdef IPCOM_USE_INET case IP_AF_INET : return iplite_ip4_sendto(sock, to, pkt); #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6 : return iplite_ip6_sendto(sock, to, pkt); #endif #ifdef IPIPSEC2 case IP_AF_KEY : return ipipsec_pfkeyv2_input((Ipcom_socket *)sock, IP_NULL, pkt); #endif default : /* Invalid domain */ return -IP_ERRNO_EAFNOSUPPORT; } } #endif /* !defined(IPLITE_ONE_FILE) || defined(IPLITE_C) */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */