Ejemplo n.º 1
0
/*
 *===========================================================================
 *                     ipnet_udp_fast_deliver_data
 *===========================================================================
 * Description: Deliver an UDP packet to a socket that is bound to a unicast
 *              address.
 * Parameters:  sock - The socket the packet will be delivered to.
 *              pkt - The UDP packet to deliver.
 *              nat_t - NAT_T processing.
 * Returns:     IP_TRUE - The fast path processing was successful.
 *              IP_FALSE - Need to use the normal receive path.
 *
 */
IP_STATIC Ip_bool
ipnet_udp_fast_deliver_data(Ipnet_socket *sock, Ipcom_pkt *pkt, int *nat_t)
{
    Ipnet_pkt_udp       *udp_hdr;
    int                  original_start = pkt->start;
    Ipcom_socket_eventcb event_cb = sock->ipcom.event_cb;

    udp_hdr = (Ipnet_pkt_udp*) &pkt->data[pkt->tlstart];
    if (IP_UNLIKELY(pkt->end - pkt->tlstart < IPNET_UDP_HDR_SIZE
                    || pkt->end - pkt->tlstart < ip_ntohs(udp_hdr->ulen)))
        return IP_FALSE;

    if (udp_hdr->sum != 0 && IP_BIT_ISFALSE(pkt->flags, IPCOM_PKT_FLAG_LOOPED_BACK))
    {
        Ip_u16 chksum;
        /* Only check packets that was not created locally */
#ifdef IPCOM_USE_HW_CHECKSUM_RX
        if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_HW_CHECKSUM))
            chksum = 0;
        else if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_TL_CHECKSUM))
            chksum = ipcom_in_checksum_finish(pkt->chk);
        else
#endif /* IPCOM_USE_HW_CHECKSUM_RX */
        {
            pkt->chk += ipcom_in_checksum_update(&pkt->data[pkt->tlstart],
                                                 (Ip_size_t) ip_ntohs(udp_hdr->ulen));
            chksum = ipcom_in_checksum_finish(pkt->chk);
        }

        if (IP_UNLIKELY(chksum != 0))
            return IP_FALSE;
    }

    pkt->fd    = sock->ipcom.fd;
    pkt->start = pkt->tlstart + IPNET_UDP_HDR_SIZE;

    if (IP_UNLIKELY(ipnet_udp_encapsulation(sock, pkt, nat_t)))
    {
        /* Continue processing */
        ipcom_pkt_set_info(pkt, IPNET_PKT_INFO_ENCAP_UDP, sizeof(*udp_hdr), udp_hdr);
        pkt->start = original_start;
        return IP_FALSE;
    }

    if (ipnet_queue_received_packet(pkt, sock) != 0)
    {
        pkt->start = original_start;
        return IP_FALSE;
    }

    if (event_cb != IP_NULL)
        event_cb(&sock->ipcom, pkt, IP_SOEVENT_CB_INPKT);

    IPCOM_MIB2(udpInDatagrams++);
    IPCOM_MIB2_U64_INC(udpHCInDatagrams);
    return IP_TRUE;
}
/*
 *===========================================================================
 *                    ipnet_loopback_ip_output
 *===========================================================================
 * Description: Updates statistics counter and add the link trailer.
 * Parameters:  netif - The interface the packet was sent to.
 *              rt - The route followed (ignored).
 *              pkt - The packet to loopback. pkt->start is the offset to the
 *              IP header.
 * Returns:     0 = success, 0< = error code.
 *
 */
IP_STATIC int
ipnet_loopback_ip_output(Ipnet_netif *netif, Ipnet_route_entry *rt, Ipcom_pkt *pkt)
{
    Ipnet_loopback_trailer_t *tr;

    IPCOM_UNUSED_ARG(rt);

    if (IP_UNLIKELY(IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_UP)))
    {
        ipcom_pkt_free(pkt);
        return -IP_ERRNO_EHOSTDOWN;
    }

#ifdef IPCOM_ZEROCOPY
    pkt = ipcom_pkt_make_linear(pkt);
    if (IP_UNLIKELY(pkt == IP_NULL))
        /* Not enough packets to make this packet linear, not much to
           about it */
        return 0;
#endif /* IPCOM_ZEROCOPY */

    IP_BIT_CLR(pkt->flags, IPCOM_PKT_FLAG_OUTPUT);

#if defined(IPCOM_USE_INET) || defined(IPCOM_USE_INET6)
    ip_assert2((pkt->data[pkt->start] & 0xf0) == 0x40 || (pkt->data[pkt->start] & 0xf0) == 0x60);
#elif defined(IPCOM_USE_INET)
    ip_assert2((pkt->data[pkt->start] & 0xf0) == 0x40);
#else
    ip_assert2((pkt->data[pkt->start] & 0xf0) == 0x60);
#endif

    tr = (Ipnet_loopback_trailer_t *) &pkt->data[pkt->end];
    IP_SET_32ON8(&tr->scope_id, pkt->ifindex);
    pkt->ifindex = netif->ipcom.ifindex;

    return ipnet_if_output(netif, pkt);
}
/*
 *===========================================================================
 *                    ipnet_loopback_drv_output
 *===========================================================================
 * Description: Loops back the packet.
 * Parameters:  netif - The interface the packet was sent to.
 *              pkt - The packet to loopback. pkt->start is the offset to the
 *              IP header.
 * Returns:     0 = success, 0< = error code.
 *
 */
IP_STATIC int
ipnet_loopback_drv_output(Ipcom_netif *netif, Ipcom_pkt *pkt)
{
    int ret = 0;

    /* The ipcom_pkt_input_queue() frees the packet if it cannot be queued,
       add a reference so that packet is still allocated if that happens */
    IPCOM_PKT_ADD_REF(pkt);
    IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_RX);
    IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_LOOPED_BACK);
    ret = ipcom_pkt_input_queue(netif, pkt);
    if (IP_UNLIKELY(ret != -IP_ERRNO_EWOULDBLOCK))
    {
        ip_assert(IPCOM_PKT_HAS_MULTIPLE_OWNERS(pkt));
        ipcom_pkt_free(pkt);
    }
    return ret;
}
/*
 *===========================================================================
 *                    ipnet_loopback_input
 *===========================================================================
 * Description: Handles loopback packets from the input daemon.
 * Parameters:  netif - A loopback interface.
 *              pkt - The incoming packet.
 * Returns:     0 = success, <0 = error code.
 *
 */
IP_STATIC int
ipnet_loopback_input(Ipnet_netif *netif, Ipcom_pkt *pkt)
{
    Ipnet_loopback_trailer_t *tr;

    ip_assert(IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_ALLOC));

    tr = (Ipnet_loopback_trailer_t *) &pkt->data[pkt->end];
    pkt->ifindex = IP_GET_32ON8(&tr->scope_id);

    /* Verify that the indicated netif exists */
    if (IP_UNLIKELY(ipnet_if_indextonetif(pkt->vr_index, pkt->ifindex) == IP_NULL))
    {
        ipcom_pkt_free(pkt);
        return -IP_ERRNO_EINVAL;
    }

#ifndef IP_PORT_LKM
    IPCOM_PKT_ADD_REF(pkt);
    (void)ipcom_pkt_output_done(&netif->ipcom, pkt, IP_FLAG_FC_STACKCONTEXT);
#endif

    switch (pkt->data[pkt->start] & 0xf0)
    {
#ifdef IPCOM_USE_INET
    case 0x40:
        return ipnet_ip4_input(netif, pkt);
#endif
#ifdef IPCOM_USE_INET6
    case 0x60:
        return ipnet_ip6_input(netif, pkt);
#endif
    default:
        IP_PANIC2();
        ipcom_pkt_free(pkt);
        return -IP_ERRNO_EINVAL;
    }
}
Ejemplo n.º 5
0
/*
 *===========================================================================
 *                   ipnet_usr_sock_tcp_pkts_from_iov
 *===========================================================================
 * Description: Copies the user data into MSS sized packets.
 * Parameters:  sock - The socket that will be use to send.
 *              msg - 'msg_iov' contains the buffer(s) to send.
 *              flags - IP_MSG_xxx flags.
 *              offset - Number of bytes into the msg->msg_iov buffers
 *                      where the copy into packets should start.
 *              total_buf_len - the sum of the length of all
 *                      msg->msg_iov buffers in 'msg'.
 *              ppkt -  Will point to the created packet(s) if the
 *                      operation is successfil. The (*ppkt)->next
 *                      points to the next packet in case of more than
 *                      one packet was allocated.
 * Returns:     <0 = error code (-IPNET_ERRNO_xxx)
 *               0 = this operation released the socket lock, the
 *                      sendmsg operation must be restarted
 *              >0 = number of bytes that has been allocated in the
 *                      socket send buffer and copied into the
 *                      packet(s) pointed to by *ppkt.
 */
IP_STATIC int
ipnet_usr_sock_tcp_pkts_from_iov(Ipnet_socket *sock,
                                 IP_CONST struct Ip_msghdr *msg,
                                 int flags,
                                 int offset,
                                 int total_buf_len,
                                 Ipcom_pkt **ppkt)
{
    Ipcom_pkt *pkt_head;
    Ipcom_pkt *pkt_tail;
    Iptcp_tcb *tcb = sock->tcb;
    int        mss = tcb->mss;
    Ip_u8     *buf;
    int        buf_len;
    int        i = 0;
    int        len = 0;
    int        bytes_to_copy = total_buf_len - offset;
    Ip_bool    non_blocking;
    Ip_bool    urgent = IP_BIT_ISSET(flags, IP_MSG_OOB);

    *ppkt = IP_NULL;

    /*
     * If offset == total_buf_len, which can in particular happen
     * if both are zero, then the loop immediately below can
     * access beyond the end of the iovec array. Avoid this.
     */
    if (offset == total_buf_len)
        return 0;

    for (buf_len = 0; buf_len <= 0; offset = - buf_len)
    {
        struct Ip_iovec *iov = &msg->msg_iov[i++];

        buf = (Ip_u8 *) iov->iov_base + offset;
        buf_len = (int) iov->iov_len - offset;
    }

    if (IP_LIKELY(urgent == IP_FALSE))
    {
        iptcp_partial_lock(tcb->send.partial_lock);
        if (tcb->send.partial != IP_NULL)
        {
            len = ipnet_sock_tcp_append_send_data(tcb->send.partial,
                                                  &buf,
                                                  &buf_len,
                                                  mss);
            if (len > 0)
                ipcom_atomic_add(&sock->snd_bytes, len);
        }
        iptcp_partial_unlock(tcb->send.partial_lock);

        if (len == bytes_to_copy)
            /* All data that should be sent was queued to the end of the
               partial finished TCP segment */
            return len;
    }
    /* else: urgent packet must be sent in a separate signal since the
       flag field must have IP_MSG_OOB set for correct processing. */

    non_blocking = IP_BIT_ISSET(sock->flags, IPNET_SOCKET_FLAG_NONBLOCKING)
        || IP_BIT_ISSET(flags, IP_MSG_DONTWAIT);

    bytes_to_copy = 0;
    do
    {
        int bytes_to_alloc = IP_MIN(mss, buf_len - bytes_to_copy);

        if (ipcom_atomic_add_and_return(&sock->snd_bytes, bytes_to_alloc)
            < sock->send_max_bytes + bytes_to_alloc)
        {
            bytes_to_copy += bytes_to_alloc;
        }
        else
        {
            int lowat;

            ipcom_atomic_sub(&sock->snd_bytes, bytes_to_alloc);

            if (bytes_to_copy > 0 || non_blocking)
                break;

            lowat = IP_MAX(mss, (int) sock->tcb->send.lowat);
            lowat = IP_MIN(lowat, sock->send_max_bytes);
            (void)ipnet_usr_sock_wait_until_writable(sock,
                                                     lowat,
                                                     IP_NULL);
            if (sock->ipcom.so_errno)
            {
                ipcom_atomic_sub(&sock->snd_bytes, bytes_to_copy);
                return len > 0 && sock->ipcom.so_errno != IP_ERRNO_EINTR ? len : -sock->ipcom.so_errno;
            }
        }
    } while (bytes_to_copy < buf_len);

    pkt_head = IP_NULL;
    pkt_tail = IP_NULL;
    while (bytes_to_copy > 0)
    {
        Ipcom_pkt *pkt;
        int        seg_len = IP_MIN(bytes_to_copy, mss);

        pkt = ipcom_pkt_malloc(mss + sock->max_hdrspace,
                               IP_FLAG_FC_STACKCONTEXT | (non_blocking ? 0 : IP_FLAG_FC_BLOCKOK));
        if (IP_UNLIKELY(pkt == IP_NULL))
            break;

        pkt->start = (pkt->maxlen - mss) & ~0x3;
        pkt->end   = pkt->start + seg_len;

        pkt->chk = ipnet_in_checksum_memcpy(&pkt->data[pkt->start],
                                            buf,
                                            seg_len);

        /* Add this packet to the list of packets that will be sent
           to ipnetd */
        if (pkt_head == IP_NULL)
            pkt_head = pkt;

        else
            pkt_tail->next = pkt;
        pkt_tail = pkt;

        len += seg_len;
        buf += seg_len;
        bytes_to_copy -= seg_len;
    }

    if (IP_LIKELY(pkt_tail != IP_NULL))
    {
        if (IP_UNLIKELY(urgent))
            IPNET_MARK_PKT_AS_URGENT(pkt_tail);

        iptcp_partial_lock(tcb->send.partial_lock);
        tcb->send.partial = pkt_tail;
        iptcp_partial_unlock(tcb->send.partial_lock);
    }

    *ppkt = pkt_head;
    return (len == 0 ? -IP_ERRNO_EWOULDBLOCK : len);
}
Ejemplo n.º 6
0
/*
 *===========================================================================
 *                    ipcom_forwarder_get_fw_if
 *===========================================================================
 * Context:     fw
 * Description: Obtain forwarding interface index corresponding to 'msg' from fw cache
 *              In case of a match the packet referred to by 'msg' is updated
 *              with destination hw address and IP header info.
 *              source MAC must be added before packet is sent.
 * Parameters:  'msg' : packet descriptor
 * Returns:     index of interface, or -1 if no fw cache entry matches 'msg'
 *
 */
IP_STATIC __inline__ int ipcom_forwarder_get_fw_if(fw_msg_t *msg)
{
#ifdef IPCOM_USE_INET
    fw_cache_entry_v4_t *e4;
    Ip_u32 dst4;
#endif
#ifdef IPCOM_USE_INET6
    fw_cache_entry_v6_t *e6;
#endif
#ifdef IPCOM_USE_FORWARDER_VLAN
    Ip_u16 vid;
    fw_cache_entry_vlan_t *ev;
#endif

#ifdef IPCOM_USE_FORWARDER_IPSEC
    fw_ipsec_replay_t fw_ipsec_replay;

    if (msg->ipsec_dec)
    {
        int offset = LL_ETH_HDR_SZ;
#ifdef IPCOM_USE_FORWARDER_VLAN
        if (IP_UNLIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
                        msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN))
            offset = LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD;
#endif /* IPCOM_USE_FORWARDER_VLAN */

        if (ipcom_forwarder_ipsec_decrypt_packet(msg, &fw_ipsec_replay, offset) < 0)
        {
            msg->tbl[0] = IPCOM_FORWARDER_PACKET_IPSEC_DROP_PKT; /* Drop packet */
            return -1;
        }
    }
#endif /* IPCOM_USE_FORWARDER_IPSEC */

    if (IP_LIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV4))
    {
#ifdef IPCOM_USE_INET
        /* IPv4 */
        e4 = &ipcom_fw.fw_cache_tbl_v4[msg->fw_key];
        dst4 = *(Ip_u32 *)(msg->packet + LL_ETH_HDR_SZ + 16);
        if (IP_UNLIKELY(dst4 != e4->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id))
        {
#if IPCOM_FORWARDER_CACHE_WAYS > 1
            if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 2
                if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 3
                    if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 4
                        if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 5
                            if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 6
                                if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 7
                                    if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id))

#endif
#endif
#endif
#endif
#endif
#endif
#endif
                goto nomatch;
        }

        IP_INCREMENTAL_CHECKSUM(((Ipnet_pkt_ip *)(msg->packet + LL_ETH_HDR_SZ)));
#ifdef IPCOM_USE_FORWARDER_IPSEC
        if (ipcom_forwarder_ipsec_encrypt_packet(msg, &e4->mac_if, &e4->ipsec, &fw_ipsec_replay, LL_ETH_HDR_SZ) <= 0)
        {
            Ipnet_pkt_ip *ip = (Ipnet_pkt_ip *)(msg->packet + LL_ETH_HDR_SZ);

            /* Restore IPv4 header */
            ip->ttl++;
            ip->sum = 0;
            ip->sum = ipcom_in_checksum(ip, IPCOM_IP_HEADER_LENGTH);
            return -1;
        }
#endif /* IPCOM_USE_FORWARDER_IPSEC */
        *(Ip_u32 *)(msg->packet - 2) = e4->mac_if.dst_mac[0];
        *(Ip_u32 *)(msg->packet + 2) = e4->mac_if.dst_mac[1];
        *(Ip_u32 *)(msg->packet + 6) = ipcom_fw.fw_port[e4->mac_if.ix[0]].src_type[0];
        *(Ip_u16 *)(msg->packet + 10) = ipcom_fw.fw_port[e4->mac_if.ix[0]].src_type[1];
#ifdef IPCOM_USE_FORWARDER_IPSEC
        *(Ip_u16 *)(msg->packet + 12) = ip_htons(IP_IPv4);
#endif /* IPCOM_USE_FORWARDER_IPSEC */
        return e4->mac_if.ix[0];
#endif /* IPCOM_USE_INET */
    }
    else if (IP_LIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV6))
    {
#ifdef IPCOM_USE_INET6
        /* IPv6 */
        e6 = &ipcom_fw.fw_cache_tbl_v6[msg->fw_key];

        if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != e6->ip6.addr[0])) ||
            IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) ||
            IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id)
#ifdef IPCOM_USE_FORWARDER_VLAN
            || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6
#endif
            )
        {
#if IPCOM_FORWARDER_CACHE_WAYS > 1
            if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) ||
                IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) ||
                IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id)
#ifdef IPCOM_USE_FORWARDER_VLAN
                || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6
#endif
                )
#if IPCOM_FORWARDER_CACHE_WAYS > 2
                if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) ||
                    IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) ||
                    IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id)
#ifdef IPCOM_USE_FORWARDER_VLAN
                    || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6
#endif
                    )
#if IPCOM_FORWARDER_CACHE_WAYS > 3
                    if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) ||
                        IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) ||
                        IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id)
#ifdef IPCOM_USE_FORWARDER_VLAN
                        || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6
#endif
                        )
#if IPCOM_FORWARDER_CACHE_WAYS > 4
                        if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) ||
                            IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) ||
                            IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id)
#ifdef IPCOM_USE_FORWARDER_VLAN
                            || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6
#endif
                            )
#if IPCOM_FORWARDER_CACHE_WAYS > 5
                            if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) ||
                                IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) ||
                                IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id)
#ifdef IPCOM_USE_FORWARDER_VLAN
                                || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6
#endif
                                )
#if IPCOM_FORWARDER_CACHE_WAYS > 6
                                if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) ||
                                    IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) ||
                                    IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id)
#ifdef IPCOM_USE_FORWARDER_VLAN
                                    || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6
#endif
                                    )
#if IPCOM_FORWARDER_CACHE_WAYS > 7
                                    if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) ||
                                        IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) ||
                                        IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id)
#ifdef IPCOM_USE_FORWARDER_VLAN
                                        || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6
#endif
                                        )
#endif
#endif
#endif
#endif
#endif
#endif
#endif
                                        goto nomatch;
        }

        SET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ), GET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ)) - 1);
#ifdef IPCOM_USE_FORWARDER_IPSEC
        if (ipcom_forwarder_ipsec_encrypt_packet(msg, &e6->mac_if, &e6->ipsec, &fw_ipsec_replay, LL_ETH_HDR_SZ) <= 0)
        {
            /* Restore IPv6 header */
            SET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ), GET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ)) + 1);
            return -1;
        }
#endif /* IPCOM_USE_FORWARDER_IPSEC */
        *(Ip_u64 *)(msg->packet - 2) = e6->mac_if.dst_mac64;
        *(Ip_u64 *)(msg->packet + 6) = *(Ip_u64 *)&ipcom_fw.fw_port[e6->mac_if.ix[0]].src_type[0];

        return e6->mac_if.ix[0];
#endif /* IPCOM_USE_INET6 */
    }
#ifdef IPCOM_USE_FORWARDER_VLAN
    else if (IP_LIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN))
    {
#ifdef IPCOM_USE_INET
        /* IPv6 table is also used for VLAN entries, both IPv4 and IPv6 */
        ev = (fw_cache_entry_vlan_t *)&ipcom_fw.fw_cache_tbl_v6[msg->fw_key];
        dst4 = *(Ip_u32 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 16);
        vid = *(Ip_u16 *)(msg->packet + LL_ETH_HDR_SZ); /* UP/CFI/VID word */

        if (IP_UNLIKELY(ev->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
                        dst4 != ev->ipvlan.a.addr_v4 ||
                        vid != ev->ipvlan.vlan_id ||
                        ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
        {
#if IPCOM_FORWARDER_CACHE_WAYS > 1
            if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
                            dst4 != ev->ipvlan.a.addr_v4 ||
                            vid != ev->ipvlan.vlan_id ||
                            ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 2
                if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
                                dst4 != ev->ipvlan.a.addr_v4 ||
                                vid != ev->ipvlan.vlan_id ||
                                ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 3
                    if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
                                    dst4 != ev->ipvlan.a.addr_v4 ||
                                    vid != ev->ipvlan.vlan_id ||
                                    ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 4
                        if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
                                        dst4 != ev->ipvlan.a.addr_v4 ||
                                        vid != ev->ipvlan.vlan_id ||
                                        ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 5
                            if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
                                            dst4 != ev->ipvlan.a.addr_v4 ||
                                            vid != ev->ipvlan.vlan_id ||
                                            ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 6
                                if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
                                                dst4 != ev->ipvlan.a.addr_v4 ||
                                                vid != ev->ipvlan.vlan_id ||
                                                ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 7
                                    if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
                                                    dst4 != ev->ipvlan.a.addr_v4 ||
                                                    vid != ev->ipvlan.vlan_id ||
                                                    ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#endif
#endif
#endif
#endif
#endif
#endif
#endif
                                        goto nomatch;
        }

        IP_INCREMENTAL_CHECKSUM(((Ipnet_pkt_ip *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD)));
#ifdef IPCOM_USE_FORWARDER_IPSEC
        if (ipcom_forwarder_ipsec_encrypt_packet(msg, &ev->mac_if, &ev->ipsec, &fw_ipsec_replay, LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD) <= 0)
        {
            Ipnet_pkt_ip *ip = (Ipnet_pkt_ip *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD);

            /* Restore IPv4 header */
            ip->ttl--;
            ip->sum = 0;
            ip->sum = ipcom_in_checksum(ip, IPCOM_IP_HEADER_LENGTH);
            return -1;
        }
#endif /* IPCOM_USE_FORWARDER_IPSEC */
        *(Ip_u32 *)(msg->packet - 2) = ev->mac_if.dst_mac[0];
        *(Ip_u32 *)(msg->packet + 2) = ev->mac_if.dst_mac[1];
        *(Ip_u32 *)(msg->packet + 6) = ipcom_fw.fw_port[ev->mac_if.ix[0]].src_type[0];
        *(Ip_u32 *)(msg->packet + 10) = ipcom_fw.fw_port[ev->mac_if.ix[0]].src_type[1];
        *(Ip_u16 *)(msg->packet + 12) = ip_htons(IP_VLAN);
        *(Ip_u16 *)(msg->packet + 14) = ev->ipvlan.vlan_id;
#ifdef IPCOM_USE_FORWARDER_IPSEC
        *(Ip_u16 *)(msg->packet + 16) = ip_htons(IP_IPv4);
#endif
        return ev->mac_if.ix[0];
#endif /* IPCOM_USE_INET */
    }
    else if (IP_LIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN))
    {
#ifdef IPCOM_USE_INET6
        /* IPv6 table is also used for VLAN entries, both IPv4 and IPv6 */
        ev = (fw_cache_entry_vlan_t *)&ipcom_fw.fw_cache_tbl_v6[msg->fw_key];
        vid = *(Ip_u16 *)(msg->packet + LL_ETH_HDR_SZ); /* UP/CFI/VID word */

        if (IP_UNLIKELY(ev->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN ||
                        (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) ||
                        (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) ||
                        vid != ev->ipvlan.vlan_id ||
                        ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
        {
#if IPCOM_FORWARDER_CACHE_WAYS > 1
            if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN ||
                            (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) ||
                            (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) ||
                            vid != ev->ipvlan.vlan_id ||
                            ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 2
                if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN ||
                                (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) ||
                                (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) ||
                                vid != ev->ipvlan.vlan_id ||
                                ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 3
                    if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN ||
                                    (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) ||
                                    (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) ||
                                    vid != ev->ipvlan.vlan_id ||
                                    ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 4
                        if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN ||
                                        (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) ||
                                        (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) ||
                                        vid != ev->ipvlan.vlan_id ||
                                        ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 5
                            if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN ||
                                            (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) ||
                                            (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) ||
                                            vid != ev->ipvlan.vlan_id ||
                                            ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 6
                                if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN ||
                                                (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) ||
                                                (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) ||
                                                vid != ev->ipvlan.vlan_id ||
                                                ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#if IPCOM_FORWARDER_CACHE_WAYS > 7
                                    if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN ||
                                                    (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) ||
                                                    (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) ||
                                                    vid != ev->ipvlan.vlan_id ||
                                                    ev->ipvlan.rci != *ipcom_fw.rt_cache_id))
#endif
#endif
#endif
#endif
#endif
#endif
#endif
                                        goto nomatch;
        }


        SET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD),
                    GET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD)) - 1);
#ifdef IPCOM_USE_FORWARDER_IPSEC
        if (ipcom_forwarder_ipsec_encrypt_packet(msg, &ev->mac_if, &ev->ipsec, &fw_ipsec_replay, LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD) <= 0)
        {
            /* Restore IPv6 header */
            SET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD), GET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD)) + 1);
            return -1;
        }
#endif /* IPCOM_USE_FORWARDER_IPSEC */
        *(Ip_u32 *)(msg->packet - 2) = ev->mac_if.dst_mac[0];
        *(Ip_u32 *)(msg->packet + 2) = ev->mac_if.dst_mac[1];
        *(Ip_u32 *)(msg->packet + 6) = ipcom_fw.fw_port[ev->mac_if.ix[0]].src_type[0];
        *(Ip_u32 *)(msg->packet + 10) = ipcom_fw.fw_port[ev->mac_if.ix[0]].src_type[1];
        *(Ip_u16 *)(msg->packet + 12) = ip_htons(IP_VLAN);
        *(Ip_u16 *)(msg->packet + 14) = ev->ipvlan.vlan_id;
#ifdef IPCOM_USE_FORWARDER_IPSEC
        *(Ip_u16 *)(msg->packet + 16) = ip_htons(IP_IPv6);
#endif
        return ev->mac_if.ix[0];
#endif /* IPCOM_USE_INET6 */
    }
#endif /* IPCOM_USE_FORWARDER_VLAN */

nomatch:

#ifdef IPCOM_USE_FORWARDER_IPSEC
    if (msg->ipsec_dec == 0xff)
    {
        int ret, offset = LL_ETH_HDR_SZ;

        if (msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN ||
            msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN)
        {
            offset += LL_ETH_VLAN_ADD;
        }

#ifdef FW_IPSEC_DEBUG
        ipcom_printf("FW_IPSEC :: re-encrypt packet! offset=%d msg->fw_key: %x msg->len=%d(%d) msg->packet=%p(%p)\n",
                     offset, msg->fw_key, msg->len, ipcom_forwarder_ipnet_msg_len(msg),
                     msg->packet, ipcom_forwarder_ipnet_msg_packet(msg));

#endif

        /* Restore buffer pointer and length */
        msg->len    = ipcom_forwarder_ipnet_msg_len(msg);
        msg->packet = ipcom_forwarder_ipnet_msg_packet(msg);

        /* Re-encrypt packet */
        ret = ipcom_forwarder_ipsec_recrypt(&msg->packet[offset], msg->len - offset);
        if (ret < 0)
        {
#ifdef FW_IPSEC_DEBUG
            ipcom_printf("FW_IPSEC :: re-encrypt packet failed!!!\n");

#endif
            ipsec_recrypt_fail++;
            msg->tbl[0] = IPCOM_FORWARDER_PACKET_IPSEC_DROP_PKT; /* Drop packet */
            return -1;
        }
        ipsec_recrypt_ok++;
    }
#endif /* IPCOM_USE_FORWARDER_IPSEC */

    return -1;
}
Ejemplo n.º 7
0
/*
 *===========================================================================
 *                    ipnet_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, must be freed by the called if
 *              this function fails.
 *              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.
 *              nat_t   - NAT traversal; if used.
 * Returns:     0 >= number of matching sockets, <0 = error code
 *
 */
IP_GLOBAL int
ipnet_udp_input(Ipcom_pkt *pkt, Ip_bool is_multicast,
                IP_CONST void* src_addr, IP_CONST void* dst_addr,
                Ipnet_sock_lookup_f socklookup,
                int   *nat_t)
{
    Ipnet_pkt_udp *udp_hdr;
    int            retval;
    int            ulen_h;
    Ipnet_socket  *sock;
    Ip_u16         src_port;
    Ip_u16         dst_port;
    Ip_bool        pkt_no_rx_cache;


    IPCOM_WV_MARKER_1 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_VERBOSE, 1, 3, IPCOM_WV_NETDEVENT_START,
                       ipnet_udp_input, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
    IPNET_STATS(udp_input++);
    IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_UDP_INPUT);

    if (IP_UNLIKELY(pkt->end - pkt->start < IPNET_UDP_HDR_SIZE))
    {
        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                          1, 4, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_BADHLEN,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_hdr_trunc++);
        IPCOM_MIB2(udpInErrors++);
        return -IP_ERRNO_EINVAL;
    }

    udp_hdr = (Ipnet_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 (IP_UNLIKELY(pkt->end - pkt->start < ulen_h))
    {
        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                          1, 5, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_BADLEN,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_hdr_trunc++);
        IPCOM_MIB2(udpInErrors++);
        return -IP_ERRNO_EINVAL;
    }
    pkt->end = pkt->start + ulen_h;

    if (udp_hdr->sum != 0 && IP_BIT_ISFALSE(pkt->flags, IPCOM_PKT_FLAG_LOOPED_BACK))
    {
        Ip_u16 chksum;
        /* Only check packets that was not created locally */
#ifdef IPCOM_USE_HW_CHECKSUM_RX
        if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_HW_CHECKSUM))
            chksum = 0;
        else if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_TL_CHECKSUM))
            chksum = ipcom_in_checksum_finish(pkt->chk);
        else
#endif /* IPCOM_USE_HW_CHECKSUM_RX */
        {
            pkt->chk += ipcom_in_checksum_update(&pkt->data[pkt->start], (Ip_size_t) ulen_h);
            chksum = ipcom_in_checksum_finish(pkt->chk);
        }

        if (IP_UNLIKELY(chksum != 0))
        {
            /* Wrong checksum */
            IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                              1, 6, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                              ipnet_udp_input, IPCOM_WV_NETD_BADSUM,
                              IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
            IPNET_STATS(udp_input_badchksum++);
            IPCOM_MIB2(udpInErrors++);
            return -IP_ERRNO_EINVAL;
        }
    }

    /* Move the start to beginning of application data */
    pkt->start += IPNET_UDP_HDR_SIZE;

    if (is_multicast)
    {
        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_INFO,
                          1, 7, IPCOM_WV_NETDEVENT_INFO, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_INFO_RECEIVE,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_multicast++);
        retval = ipnet_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++);
            IPCOM_MIB2_U64_INC(udpHCInDatagrams);
        }
        else
        {
            IPCOM_MIB2(udpInErrors++);
        }
        return retval;
    }

    sock = socklookup(pkt->vr_index,
                      IP_IPPROTO_UDP,
                      dst_addr,
                      dst_port,
                      src_addr,
                      src_port);
    if (sock == IP_NULL)
        /* No matching socket, try the wildcard group */
        sock = socklookup(IPCOM_VR_ANY,
                          IP_IPPROTO_UDP,
                          dst_addr,
                          dst_port,
                          src_addr,
                          src_port);

    if (sock != IP_NULL)
    {
        Ipcom_socket_eventcb event_cb = sock->ipcom.event_cb;

        /* Verify NAT traversal */
        if (IP_UNLIKELY(ipnet_udp_encapsulation(sock, pkt, nat_t)))
        {
            ipcom_pkt_set_info(pkt, IPNET_PKT_INFO_ENCAP_UDP, sizeof(*udp_hdr), udp_hdr);
            pkt->start -= IPNET_UDP_HDR_SIZE;
            return 0;
        }

        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_INFO,
                          1, 8, IPCOM_WV_NETDEVENT_INFO, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_INFO_RECEIVE,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_sock_match++);
        pkt->fd = sock->ipcom.fd;
        pkt_no_rx_cache = IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_NO_RX_CACHE);

        retval = ipnet_queue_received_packet(pkt, sock);
        if (retval < 0)
        {
            IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                              1, 9, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                              ipnet_udp_input, IPCOM_WV_NETD_INFO_QUEUE_FULL,
                              IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
            IPNET_STATS(udp_input_queue_pkt_err++);
            IPCOM_MIB2(udpInErrors++);
            return retval;
        }

        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_INFO,
                          1, 10, IPCOM_WV_NETDEVENT_INFO, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_INFO_RECEIVE,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_queue_pkt_ok++);

        if (event_cb != IP_NULL)
            event_cb(&sock->ipcom, pkt, IP_SOEVENT_CB_INPKT);

        IPCOM_MIB2(udpInDatagrams++);
        IPCOM_MIB2_U64_INC(udpHCInDatagrams);

        if (IP_BIT_ISFALSE(sock->flags, IPNET_SOCKET_FLAG_RX_CACHED)
            && !pkt_no_rx_cache)
            ipnet_sock_add_to_rx_cache(sock,
                                       src_addr,
                                       src_port,
                                       dst_addr,
                                       dst_port,
                                       ipnet_udp_fast_deliver_data);

        return 1;
    }
    else
    {
        IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                          1, 13, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                          ipnet_udp_input, IPCOM_WV_NETD_NOPORT,
                          IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
        IPNET_STATS(udp_input_sock_nomatch++);
        IPCOM_MIB2(udpNoPorts++);
    }

    IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING,
                      1, 14, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV,
                      ipnet_udp_input, IPCOM_WV_NETD_NOPORT,
                      IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4);
    IPNET_STATS(udp_input_econnrefused++);
    return -IP_ERRNO_ECONNREFUSED;
}
Ejemplo n.º 8
0
/*
 *===========================================================================
 *                    ipnet_udp_nat_traversal
 *===========================================================================
 * Description: Check if this packet should be processed by the NAT
 *              traversal functionality.
 * Parameters:  sock        - The socket
 *              pkt         - The packet in question.
 * Returns:     IP_FALSE; give to UDP socket.
 *              IP_TRUE; Do NAT_T processing.
 *
 */
IP_STATIC Ip_bool
ipnet_udp_encapsulation(Ipnet_socket *sock, Ipcom_pkt *pkt, int *nat_t)
{
    /* Did we have any NAT-T's? */
    if (IP_UNLIKELY(sock->udp_encapsulation != IP_UDP_NAT_T_DISABLED))
    {
#if defined(IPNET_USE_TUNNEL) && defined(IPCOM_USE_INET)
        /* NAT-T processing? */
        if (sock->ipcom.domain == IP_AF_INET && sock->udp_encapsulation == IP_UDP_NAT_T_RFC3519)
        {
            Ip_u8               *data;
            Ip_u8               nproto;

            /* Sanity; There MUST be atleast 4 bytes available */
            if ((pkt->end - pkt->start) < 4)
            {
                /* Give to UDP socket */
                return IP_FALSE;
            }

            /* Grab the start */
            data = (Ip_u8 *) &pkt->data[pkt->start];

            /* NAT-T according to RFC3519
             * IP HEADER <tunnel endpoint - tunnel endpoint>
             * UDP HEADER
             * 4 byte NAT-T header;
             *  TYPE(1 byte) := 4
             *  NH(1 byte)   := 4, 47 or 55
             *  RESERVED(2 bytes) := 0
             */

            /* Must be 4 */
            if (data[0] != 4)
            {
                /* Give to UDP socket */
                return IP_FALSE;
            }

            /* Verify that the tunnel protocol is correct */
            nproto = data[1];
            if (nproto == IP_IPPROTO_IPIP
                || nproto == IP_IPPROTO_GRE
                || nproto == IP_IPPROTO_MOBILE)
            {
                /* Correct UDP RFC3519 encap; do process */
                *nat_t = IP_UDP_NAT_T_RFC3519;
                return IP_TRUE;
            }

            /* Feed to socket */
            return IP_FALSE;
        }
#else
        (void) pkt;
        (void) nat_t;
#endif /* IPNET_USE_TUNNEL */


#if defined(IPIPSEC2) && defined(IPCOM_USE_INET)
        if (sock->ipcom.domain == IP_AF_INET && sock->udp_encapsulation == IP_UDP_NAT_T_RFC3948)
        {
            if ((pkt->end - pkt->start == 1) && (pkt->data[pkt->start] == 0xff))
            {
                /* NAT-keepalive Packet; Give to socket */
                return IP_FALSE;
            }

            if ((pkt->end - pkt->start > 4) && (IP_GET_32ON16(&pkt->data[pkt->start]) == 0))
            {
                /* Non-ESP marker set; do give to socket - this is an IKE packet */
                return IP_FALSE;
            }

            /* Deal with the NAT-T for IKE; IPSEC */
            *nat_t = IP_UDP_NAT_T_RFC3948;

            /* Tell the world we need further processing */
            return IP_TRUE;
        }
#endif

#ifdef IPNET_USE_TUNNEL
        /* NAT-T processing? */
        if (sock->udp_encapsulation == IP_UDP_NAT_T_DSMIPV6)
        {
            /* Correct UDP RFC3519 encap; do process */
            *nat_t = IP_UDP_NAT_T_DSMIPV6;
            return IP_TRUE;
        }
#endif
    }

    return IP_FALSE;
}