444 lines
14 KiB
C
444 lines
14 KiB
C
/*
|
|
******************************************************************************
|
|
* 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 <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 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 <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_syslog.h>
|
|
|
|
#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
|
|
****************************************************************************
|
|
*/
|
|
|