/*
 *===========================================================================
 *                    ipnet_sockdev_destroy
 *===========================================================================
 * Description: Detach and free an application device interface.
 * Parameters:
 * Returns:
 *
 */
IP_STATIC void
ipnet_sockdev_destroy(Ipnet_socket *sock)
{
    Ipnet_netif *netif = ipnet_if_indextonetif(sock->vr_index, sock->bind_to_ifindex);

    netif->ipcom.plink = IP_NULL;
    (void) ipnet_if_link_ioctl(netif, IP_SIOCXCLOSE, IP_NULL);
    (void)ipcom_if_detach(&netif->ipcom);
    (void)ipcom_if_free(&netif->ipcom);
}
コード例 #2
0
/*
 *===========================================================================
 *                    ipnet_is_loopback
 *===========================================================================
 * Description: Returns IP_TRUE if the 'ifindex' is a loopback interface.
 * Parameters:  ifindex - A index of a network interface.
 * Returns:
 *
 */
IP_GLOBAL Ip_bool
ipnet_is_loopback(Ip_u16 vr, Ip_u32 ifindex)
{
    Ipnet_netif *netif;

    netif = ipnet_if_indextonetif(vr, ifindex);
    if (netif == IP_NULL)
        return IP_FALSE;
    return IP_BIT_ISTRUE(netif->ipcom.flags, IP_IFF_LOOPBACK);
}
/*
 *===========================================================================
 *                  ipnet_sockdev_send
 *===========================================================================
 * Description: Inputs a packet to the sockdev interface.
 * Parameters:  sock - The socket to use when sending.
 *              msg - Contains the data to send.
 *              flags - IP_MSG_xxx flags.
 * Returns:     >0 = application bytes sent, <0 = error code.
 *
 */
IP_STATIC int
ipnet_sockdev_send(Ipnet_socket *sock, IP_CONST struct Ip_msghdr *msg, int flags)
{
    int          ret;
    int          length;
    Ipcom_pkt   *pkt;
    Ipnet_netif *netif = ipnet_if_indextonetif(sock->vr_index, sock->bind_to_ifindex);

    length = ipnet_sock_create_pkt_from_user_iov(sock, msg, flags, &pkt);
    if (length < 0)
        return length;

    IPNET_CODE_UNLOCK();
    ipcom_pkt_input(&netif->ipcom, pkt);
    IPNET_CODE_LOCK_READ();

    return ret < 0 ? ret : length;
}
コード例 #4
0
/*
 *===========================================================================
 *                    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;
    }
}
コード例 #5
0
ファイル: ipnet_if_mib.c プロジェクト: rgmabs19357/Huawei-
/*
 *===========================================================================
 *                      ipnet_if_mib_table_search_ifTable
 *===========================================================================
 * Description: Searches ifTable and ifXTable for a matching entry
 * Parameters: id, buf, best, cmd
 * Returns:    The best matching interface or IP_NULL if no match was found,
 *             error code is stored in 'ret' in that case.
 *
 */
IP_STATIC Ipnet_netif *
ipnet_if_mib_table_search_ifTable(char *id,
                                  char *buf,
                                  char *best,
                                  Ip_s32 cmd,
                                  Ip_s32 *error_code)
{
    Ip_u32       bestindex = 0;
    Ip_u32       ifIndex;
    Ip_u32      *ifindexes;
    unsigned     ifTable_num_entries;
    unsigned     i;

    ifindexes = ipnet_if_get_index_array(IPCOM_VR_ANY, 0, &ifTable_num_entries);
    if (ifindexes == IP_NULL)
    {
        *error_code = IPSNMP_ERROR_GENERROR;
        return IP_NULL;
    }

    for (i = 0; i < ifTable_num_entries; i++)
    {
        Ip_s32 lex, len = 0;

        buf[0] = '\0';

        ifIndex = ifindexes[i];

        if (ipcom_snprintf(&buf[len], IPSNMP_CONFIG_MAX_OBJECT_ID-len, "%d.", (int)ifIndex) < 0)
        {
            *error_code = IPSNMP_ERROR_GENERROR;
            ipcom_free(ifindexes);
            return IP_NULL;
        }
        len = ipcom_strlen(buf);
        if (len)
            buf[len - 1] = '\0';

        lex = ipsnmp_util_lexcmp_oid(buf, id);
        if (cmd == IPSNMP_MIB_COMMAND_NEXT)
        {
            if (lex > 0)
            {
                if (bestindex == 0 || ipsnmp_util_lexcmp_oid(buf, best) < 0)
                {
                    ipcom_strcpy(best, buf);
                    bestindex = ifIndex;
                }
            }
        }
        else
        {
            if (lex == 0)
            {
                ipcom_strcpy(best, buf);
                bestindex = ifIndex;
                break;
            }
        }
    }

    if (bestindex == 0)
        *error_code = IPSNMP_ERROR_NOSUCHNAME;
    ipcom_free(ifindexes);
    return ipnet_if_indextonetif(IPCOM_VR_ANY, bestindex);
}
コード例 #6
0
/*
 *===========================================================================
 *                    ipnet_rtnetlink_route_newroute_family
 *===========================================================================
 * Description: Add a new rotue via NETLINK.
 * Parameters:  data - Message payload
 *              len  - Length of message.
 *              nlh  - NETLINK message header
 *              arg  - Reference to route attributes.
 *
 * Returns:     0 - Success
 *             <0 - Failure
 *
 */
IP_GLOBAL int
ipnet_rtnetlink_route_newroute_family(Ipnet_netlink_mem_t   *mem,
                                      struct Ip_nlmsghdr    *nlh,
                                      struct Ip_rtattr      **rta,
                                      int                   family)
{
    Ipnet_netif                   *netif = IP_NULL;
    Ipnet_ppp_peer                *p = IP_NULL;
    int                           ret  = -1;
    Ip_u16                        vr;
    Ip_u32                        table;
    Ip_bool                       is_multipath_route = IP_FALSE;
    Ip_ssize_t                    mpa_size = 0;
    struct Ip_rtnexthop           *nh = IP_NULL;
    struct Ipnet_rt_metrics       metrics;
    struct Ip_sockaddr            *gw   = IP_NULL;
    void                          *mask = IP_NULL;
    struct Ip_sockaddr_dl         gw_dl;
    struct Ipnet_route_add_param  param;
    struct Ip_rtmsg               *rtm   = IP_NLMSG_DATA(nlh);

    union Ip_sockaddr_union       ugw;
    Ipnet_rtnetlink_key_t         ukey;

#ifdef IPMPLS
    struct Ip_sockaddr_mpls       gw_mpls;
#endif /* IPMPLS */
#ifdef IPNET_USE_ROUTE_COOKIES
    Ipnet_rt_cookie               cookie;
#endif /* IPNET_USE_ROUTE_COOKIES */

    table = IPCOM_ROUTE_TABLE_GET(rtm->rtm_table);

    /* Prepare route parameters */
    ipcom_memset(&param, 0, sizeof(param));
    ipcom_memset(&metrics,0,sizeof(metrics));
    param.flags = IPNET_RTF_STATIC | IPNET_RTF_UP | IPNET_RTF_DONE;

#ifdef IPNET_USE_ROUTE_TABLE_NAMES
    if (rta[IP_RTA_TABLE_NAME -1])
    {
        if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_RTA_TABLE_NAME - 1]),
                                               &vr,
                                               &table) < 0)
            return -IP_ERRNO_ESRCH;
    }
    else
#endif
    {
        if (mem->vr == IPCOM_VR_ANY)
            return -IP_ERRNO_EINVAL;

        vr = ipnet_rtnetlink_vr(rta[IP_RTA_VR - 1], mem->vr);

        if (rta[IP_RTA_TABLE - 1])
            table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_TABLE - 1]));
    }

    if (rta[IP_RTA_OIF -1])
    {
        int ifindex = 0;

        if (rta[IP_RTA_OIF-1]->rta_len != IP_RTA_LENGTH(sizeof(int)))
			return -IP_ERRNO_EINVAL;

        ifindex = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_OIF-1]));
        netif = ipnet_if_indextonetif(vr, ifindex);
        if (netif)
            p = netif->private_data;
    }

    if (rta[IP_RTA_MULTIPATH -1])
    {
        is_multipath_route = IP_TRUE;
        nh = IP_RTA_DATA(rta[IP_RTA_MULTIPATH-1]);
        mpa_size = IP_RTA_PAYLOAD(rta[IP_RTA_MULTIPATH-1]);

        if ((nh == IP_NULL) || (mpa_size == 0))
            return -IP_ERRNO_EINVAL;
    }

    if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, netif? netif->ipcom.ifindex : 0, &mask, rtm->rtm_dst_len, rta[IP_RTA_DST-1])) < 0)
        return ret;

    if ((ret = ipnet_rtnetlink_route_gw_setup(family, netif? netif->ipcom.ifindex : 0, &ugw, &gw, rta[IP_RTA_GATEWAY-1])) < 0)
        return ret;

#ifdef IPCOM_USE_INET
    if (family == IP_AF_INET)
    {
        if (gw != IP_NULL)
        {
            /* Check if it is a pure gateway or not */
            if (p == IP_NULL || p->peer4.s_addr != ugw.sin.sin_addr.s_addr)
                param.flags |= IPNET_RTF_GATEWAY;
        }
    }
    else
#endif
#ifdef IPCOM_USE_INET6
    if (family == IP_AF_INET6)
    {
        if (gw != IP_NULL)
        {
            /* Check if it is a pure gateway or not */
            if (p == IP_NULL || !IP_IN6_ARE_ADDR_EQUAL(&ugw.sin6.sin6_addr, &p->peer6))
                param.flags |= IPNET_RTF_GATEWAY;
        }
    }
    else
#endif
    {
        return -IP_ERRNO_EAFNOSUPPORT;
    }

    if (!mask)
        param.flags |= IPNET_RTF_HOST;

    if (rtm->rtm_type == IP_RTN_PROXY)
    {
        /* This is a proxy arp network route */
        IP_BIT_CLR(param.flags, IPNET_RTF_CLONING);
        IP_BIT_SET(param.flags, IPNET_RTF_PROTO2);

        if (rta[IP_RTA_PROXY_ARP_LLADDR - 1])
        {
            /* This is a network proxy arp with specific lladdr */
            if (netif == IP_NULL)
               return -IP_ERRNO_EINVAL;

            ipcom_memset(&gw_dl, 0, sizeof(struct Ip_sockaddr_dl));

            IPCOM_SA_LEN_SET(&gw_dl, sizeof(struct Ip_sockaddr_dl));
            gw_dl.sdl_family = IP_AF_LINK;
            gw_dl.sdl_index  = (Ip_u16)netif->ipcom.ifindex;
            gw_dl.sdl_alen   = (Ip_u8) netif->ipcom.link_addr_size;
            gw_dl.sdl_type   = (Ip_u8) netif->ipcom.type;

            ipcom_memcpy(IP_SOCKADDR_DL_LLADDR(&gw_dl),
                         IP_RTA_DATA(rta[IP_RTA_PROXY_ARP_LLADDR - 1]),
                         IPNET_ETH_ADDR_SIZE);

            gw = (struct Ip_sockaddr *) &gw_dl;
            IP_BIT_SET(param.flags, IPNET_RTF_LLINFO);
        }
    }
    else if (rtm->rtm_type == IP_RTN_PROHIBIT)
        IP_BIT_SET(param.flags, IPNET_RTF_REJECT);
    else if (rtm->rtm_type == IP_RTN_THROW)
        IP_BIT_SET(param.flags, IPNET_RTF_SKIP);
    else if (rtm->rtm_type == IP_RTN_UNREACHABLE)
    {
        if (netif == IP_NULL)
            netif = ipnet_loopback_get_netif(vr);
        IP_BIT_CLR(param.flags, IPNET_RTF_UP);
    }
    else if (rtm->rtm_type == IP_RTN_CLONE)
        IP_BIT_SET(param.flags, IPNET_RTF_CLONING);
    else if (rtm->rtm_type == IP_RTN_BLACKHOLE)
        IP_BIT_SET(param.flags, IPNET_RTF_BLACKHOLE);

#ifdef IPMPLS
    /* Check for IPNET MPLS pseudo-wire route */
    if (rta[IP_RTA_NH_PROTO-1])
    {
        Ip_u32 nh_type;

        if (rta[IP_RTA_NH_PROTO-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32)))
            return -IP_ERRNO_EINVAL;

        if (rta[IP_RTA_NH_PROTO_DATA-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32)))
            return -IP_ERRNO_EINVAL;

        ipcom_memcpy(&nh_type, IP_RTA_DATA(rta[IP_RTA_NH_PROTO-1]), sizeof(Ip_u32));

        if (nh_type !=  IPNET_ETH_P_MPLS_UNICAST)
            return -IP_ERRNO_EINVAL;

        ipcom_memset(&gw_mpls, 0, sizeof(gw_mpls));
        gw_mpls.smpls_family = IP_AF_MPLS;
        IPCOM_SA_LEN_SET(&gw_mpls, sizeof (struct Ip_sockaddr_mpls));

        ipcom_memcpy(&gw_mpls.smpls_key,
                     IP_RTA_DATA(rta[IP_RTA_NH_PROTO_DATA-1]),
                     sizeof(Ip_u32));

        IP_BIT_CLR(param.flags,IPNET_RTF_GATEWAY);
        gw = (struct Ip_sockaddr *)&gw_mpls;
    }
    else
    {
        /* Check if cloning flag shall be set */
        if (IP_BIT_ISFALSE(param.flags, IPNET_RTF_HOST | IPNET_RTF_GATEWAY | IPNET_RTF_REJECT | IPNET_RTF_BLACKHOLE))
            IP_BIT_SET(param.flags, IPNET_RTF_CLONING);
    }
#endif

    if (rta[IP_RTA_METRICS-1])
    {
        int rlen = (int)IP_RTA_PAYLOAD(rta[IP_RTA_METRICS-1]);
        Ip_u32 dummy = 0;
        struct Ip_rtattr *rtax = (struct Ip_rtattr*)IP_RTA_DATA(rta[IP_RTA_METRICS-1]);

        metrics.rmx_expire = IPCOM_ADDR_INFINITE;
        param.metrics      = &metrics;

        for(;rlen > 0; rlen -= (int)rtax->rta_len,rtax = IP_RTA_NEXT(rtax,dummy))
        {
            switch (rtax->rta_type)
            {
            case IP_RTAX_MTU:
                ipcom_memcpy(&metrics.rmx_mtu, IP_RTA_DATA(rtax), sizeof(Ip_u32));
                break;
            case IP_RTAX_RTT:
                ipcom_memcpy(&metrics.rmx_rtt, IP_RTA_DATA(rtax), sizeof(Ip_u32));
                break;
            case IP_RTAX_RTTVAR:
                ipcom_memcpy(&metrics.rmx_rttvar, IP_RTA_DATA(rtax), sizeof(Ip_u32));
                break;
            }
        }
    }

#ifdef IPNET_USE_ROUTE_COOKIES
    if (rta[IP_RTA_COOKIE-1])
    {
        if (IP_RTA_PAYLOAD(rta[IP_RTA_COOKIE-1]) > sizeof(cookie))
            return -IP_ERRNO_EINVAL;

        ipcom_memset(&cookie, 0, sizeof(cookie));
        ipcom_memcpy(&cookie,
                     IP_RTA_DATA(rta[IP_RTA_COOKIE-1]),
                     IP_RTA_PAYLOAD(rta[IP_RTA_COOKIE-1]));

        param.cookie = &cookie;
    }
#endif /* IPNET_USE_ROUTE_COOKIES */

    while (1)
    {
        if (is_multipath_route && (gw == IP_NULL))
        {
            netif                = ipnet_if_indextonetif(vr, nh->rtnh_ifindex);
            metrics.rmx_hopcount = nh->rtnh_hops;
            metrics.rmx_expire   = IPCOM_ADDR_INFINITE;
            param.metrics        = &metrics;

            if (nh->rtnh_len > sizeof(struct Ip_rtnexthop))
            {
                /* Multihop route has gateway */
                IP_BIT_CLR(param.flags, IPNET_RTF_CLONING);
                IP_BIT_SET(param.flags, IPNET_RTF_GATEWAY);

                if ((ret = ipnet_rtnetlink_route_gw_setup(family, netif? netif->ipcom.ifindex : 0, &ugw, &gw, IP_RTNH_DATA(nh))) < 0)
                    return ret;
            }
            mpa_size -= IP_RTNH_ALIGN(nh->rtnh_len);
            if (mpa_size > 0)
                nh = IP_RTNH_NEXT(nh);
        }

        param.domain       = family;
        param.vr           = vr;
        param.table        = table;
        param.netif        = netif;
        param.key          = &ukey;
        param.netmask      = mask;
        param.gateway      = gw;
        param.pid          = mem->pid;
        param.seq          = nlh->nlmsg_seq;
        param.no_ref_count = IP_TRUE;

        /* Try to add the route */
        if (netif)
            IPNET_IF_LOCK(netif);

        ret = ipnet_route_add(&param);

        if (netif != IP_NULL)
            IPNET_IF_UNLOCK(netif);

        if (is_multipath_route)
        {
            gw = IP_NULL;

            if (ret < 0 && ret != -IP_ERRNO_EEXIST)
                goto rollback;

            if (mpa_size == 0)
            {
                ret = 0;
                break;
            }
            else if (mpa_size < 0)
            {
                /* Malformed packet */
                ret = -IP_ERRNO_EINVAL;
                goto rollback;
            }
        }
        else
            break;
    }

    return ret;

rollback:
    (void)ipnet_rtnetlink_route_delroute_family(mem, nlh, rta, family);
    return ret;
}
コード例 #7
0
/*
 *===========================================================================
 *                    ipnet_fragment_packet
 *===========================================================================
 * Description: Splits a packet that is to big to fit into the MTU of the
 *              network interface.
 * Parameters:  pkt - The packet to split. pkt->start is the offset to the
 *              extension header (or transport layer protocol) with the
 *              id of 'next_hdr'. This packet is released by this function.
 *              ip_hdr_size - The size of the IP header.
 *              other_hdr_size - The size of other headers that will be
 *              added due to fragmentation.
 *              mtu - The MTU of the network interface.
 *              has_more_fragments - function that returns IP_TRUE if the
 *              packet passed as an argument has more fragments. This
 *              parameter might be IP_NULL.
 * Returns:     A list of fragments or IP_NULL if not enough memory could
 *              be allocated to create all fragments.
 */
IP_GLOBAL Ipcom_pkt *
ipnet_fragment_packet(Ipcom_pkt *pkt,
                      int ip_hdr_size,
                      int other_hdr_size,
                      int mtu,
                      Ipnet_more_fragments_func more_fragments)
{
    Ipcom_pkt *frag_pkt_head;
    Ipcom_pkt *frag_pkt_tail;
    Ipcom_pkt *frag_pkt;
    int        frag_size;
    int        total_size;
    int        size_of_this_fragment;
    int        frag_offset;
    Ipnet_pkt_info_sock_snd_buf *ssb;

    total_size = pkt->end - pkt->start;
    frag_size = (mtu - ip_hdr_size - other_hdr_size) & 0xfff8;
    frag_pkt_head = IP_NULL;
    frag_pkt_tail = IP_NULL;
    frag_offset = 0;

    while (frag_offset < total_size)
    {
        if (total_size - frag_offset > frag_size)
            size_of_this_fragment = frag_size;
        else
            size_of_this_fragment = total_size - frag_offset;

        frag_pkt = ipcom_pkt_malloc(mtu, IP_FLAG_FC_STACKCONTEXT);
        if (frag_pkt == IP_NULL)
        {
            IPCOM_WV_MARKER_1 ( IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_CRITICAL, 1, 1, IPCOM_WV_NETD_NOBUFS,
                                ipnet_fragment_packet, IPCOM_WV_IPNET_FRAG_MODULE, IPCOM_WV_NETD_IP_REASSEMBLE);
            IPNET_STATS(pkt_frag_nomem++);
            ipcom_pkt_free(pkt);
            if (frag_pkt_head != IP_NULL)
                ipcom_pkt_free(frag_pkt_head);
            return IP_NULL;
        }

#ifdef IPCOM_USE_MIB2
        if(other_hdr_size == 0)
        {
#ifdef IPCOM_USE_INET
            Ipnet_netif *netif = ipnet_if_indextonetif(pkt->vr_index, pkt->ifindex);

            IPCOM_MIB2(ipFragCreates++);
            if (netif != IP_NULL)
            {
                IPCOM_MIB2_SYSWI_U32_ADD(v4, ipSystemStatsOutFragCreates, 1);
                IPCOM_MIB2_PERIF_U32_ADD(v4, ipIfStatsOutFragCreates, 1, netif);
            }
#endif
        }
        else
        {
#ifdef IPCOM_USE_INET6
            Ipnet_netif *netif = ipnet_if_indextonetif(pkt->vr_index, pkt->ifindex);

            IPCOM_MIB2_NETIF(ipv6IfStatsOutFragCreates++);
            if (netif != IP_NULL)
            {
                IPCOM_MIB2_SYSWI_U32_ADD(v6, ipSystemStatsOutFragCreates, 1);
                IPCOM_MIB2_PERIF_U32_ADD(v6, ipIfStatsOutFragCreates, 1, netif);
            }
#endif
        }
#endif /* IPCOM_USE_MIB2 */

        if (frag_pkt_head == IP_NULL)
            frag_pkt_head = frag_pkt;
        else
            frag_pkt_tail->next_fragment = frag_pkt;
        frag_pkt_tail = frag_pkt;

        IPCOM_PKT_TRACE(frag_pkt, IPCOM_PKT_ID_FRAG);
        frag_pkt->fd       = pkt->fd;
        frag_pkt->ifindex  = pkt->ifindex;
        frag_pkt->flags    = pkt->flags;
        frag_pkt->vr_index = pkt->vr_index;
        /* Copy IP packet payload */
        frag_pkt->start      = (frag_pkt->maxlen - size_of_this_fragment) & ~0x3;
        frag_pkt->end        = frag_pkt->start + size_of_this_fragment;
        ip_assert(frag_pkt->start < frag_pkt->maxlen);
        ipcom_memcpy(&frag_pkt->data[frag_pkt->start],
                     &pkt->data[pkt->start + frag_offset],
                     (Ip_size_t)size_of_this_fragment);

        frag_pkt->offset     = (Ip_u16) (frag_offset + pkt->offset);
        frag_offset += size_of_this_fragment;
        IP_BIT_SET(frag_pkt->flags, IPCOM_PKT_FLAG_MORE_FRAG);
    }

    if (IP_BIT_ISFALSE(pkt->flags, IPCOM_PKT_FLAG_FRAGMENT)
        || (more_fragments && IP_FALSE == more_fragments(pkt)))
        /* This is either an IP datagram sourced from this node or the
           last fragment of an IP datagram that has been forwarded by
           this node. */
        IP_BIT_CLR(frag_pkt_tail->flags, IPCOM_PKT_FLAG_MORE_FRAG);

    ip_assert(pkt->start + frag_offset == pkt->end);
    ip_assert(frag_pkt_head != IP_NULL);
    if (IP_NULL != (ssb = ipcom_pkt_get_info(pkt, IPNET_PKT_INFO_SOCK_SND_BUF)))
    {
        /* Transfer the socket send buffer allocation from the
           original packet to the last fragment to make sure that the
           send flow control is still driven by TX done events. */
        ipcom_pkt_set_info(frag_pkt_tail,
                           IPNET_PKT_INFO_SOCK_SND_BUF,
                           sizeof(Ipnet_pkt_info_sock_snd_buf),
                           ssb);
        frag_pkt_tail->dtor = pkt->dtor;
        pkt->dtor = IP_NULL;
    }

    /* Do not free original yet, since it might hold the
       callers signal buffer. Put it in the fragment tails
       next original instead and it will be freed when the
       last segment has been transmitted */
    if (frag_pkt_tail != IP_NULL)
        frag_pkt_tail->next_original = pkt;
    else
        ipcom_pkt_free(pkt);

    return frag_pkt_head;
}
コード例 #8
0
/*
 *===========================================================================
 *                    ipnet_rtnetlink_neigh_newneigh_family
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_GLOBAL int
ipnet_rtnetlink_neigh_newneigh_family(Ipnet_netlink_mem_t  *mem,
                                      struct Ip_nlmsghdr   *nlmsg,
                                      struct Ip_rtattr     **rta,
                                      int                  family)
{
    Ipnet_netif                  *netif;
    Ipnet_route_entry            *rt;
    int                          nd_state;
    int                          ret = -IP_ERRNO_EAFNOSUPPORT;
    Ip_u16                       vr;
    Ip_u32                       table = IPCOM_ROUTE_TABLE_DEFAULT;
    struct Ip_sockaddr_dl        dl;
    struct Ip_ndmsg              *ndm = IP_NLMSG_DATA(nlmsg);
    void                         *link_addr = IP_NULL;
    Ipnet_rtnetlink_key_t        ukey;

     /* Destination address required */
    if (rta[IP_NDA_DST-1] == IP_NULL)
        return -IP_ERRNO_EINVAL;

#ifdef IPNET_USE_ROUTE_TABLE_NAMES
    if (rta[IP_NDA_TABLE_NAME -1])
    {
        /* Extract router and table from name */
        if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_NDA_TABLE_NAME - 1]),
                                               &vr,
                                               &table) < 0)
            return -IP_ERRNO_ESRCH;
    }
    else
#endif /* IPNET_USE_ROUTE_TABLE_NAMES */
    {
        if (mem->vr == IPCOM_VR_ANY)
            return -IP_ERRNO_EINVAL;

        vr = ipnet_rtnetlink_vr(rta[IP_NDA_VR - 1], mem->vr);

        if (rta[IP_NDA_TABLE - 1])
            table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_NDA_TABLE - 1]));
    }

    netif = ipnet_if_indextonetif(vr, ndm->ndm_ifindex);

    if (netif && (netif->vr_index != vr))
         return -IP_ERRNO_EINVAL;

    if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, netif? netif->ipcom.ifindex : 0, IP_NULL, -1, rta[IP_NDA_DST-1])) < 0)
        return ret;

    if (rta[IP_NDA_LLADDR-1])
        /* Neighbors link layer address */
        link_addr = IP_RTA_DATA(rta[IP_NDA_LLADDR-1]);
    else if (IP_BIT_ISSET(ndm->ndm_flags, IP_NTF_PROXY))
    {
        /* Proxy ARP entry. Use Link layer address of local netif */
        if (netif == IP_NULL)
            return -IP_ERRNO_EINVAL;

        link_addr = netif->ipcom.link_addr;
    }

    /* Check if neighbor route exists */
    ret = ipnet_route_lookup(family,
                             vr,
                             table,
                             IPNET_RTL_FLAG_LINK_LOCAL | IPNET_RTL_FLAG_DONTCLONE,
                             &ukey,
                             netif ? netif->ipcom.ifindex : 0,
                             netif ? netif->ipcom.ifindex : 0,
                             &rt);

    if ((ret == IPNET_ROUTE_PERFECT_MATCH)
        && (rt->netif == netif)
        && IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_HOST)
        && IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_LLINFO))
    {
        if (rt->data == IP_NULL)
            return -IP_ERRNO_EINVAL;

        /* Get the neighbour state */
        nd_state = *(Ipnet_nd_state_t *)rt->data;

        if (((ndm->ndm_state == IP_NUD_INCOMPLETE)
             && (nd_state != IPNET_ND_UNINITIALIZED)
             && (nd_state != IPNET_ND_INCOMPLETE))
            || ((ndm->ndm_state == IP_NUD_DELAY)
                && (nd_state != IPNET_ND_STALE)))
        {
            return -IP_ERRNO_EINVAL;
        }
    }
    else
    {
        struct Ipnet_rt_metrics      metrics;
        struct Ipnet_route_add_param param;

        /* Create new neighbor entry */
        if (ndm->ndm_state == IP_NUD_DELAY)
            ndm->ndm_state = IP_NUD_INCOMPLETE;

        ipcom_memset(&param, 0, sizeof(struct Ipnet_route_add_param));
        ipcom_memset(&dl, 0, sizeof(struct Ip_sockaddr_dl));

        param.domain     = family;
        param.vr         = vr;
        param.table      = table;
        param.key        = &ukey;
        param.netif      = netif;
        param.flags      = IPNET_RTF_UP | IPNET_RTF_HOST | IPNET_RTF_LLINFO | IPNET_RTF_DONE;
        param.gateway    = (struct Ip_sockaddr*) &dl;

        if (ndm->ndm_state != IP_NUD_PERMANENT)
        {
            ipcom_memset(&metrics, 0, sizeof(metrics));
            /* The correct timeout will be set when the ND state is set,
               but must be != infinite for now */
            metrics.rmx_expire = 1;
            param.metrics = &metrics;
        }

        IPCOM_SA_LEN_SET(&dl, sizeof(struct Ip_sockaddr_dl));
        dl.sdl_family    = IP_AF_LINK;
        dl.sdl_index     = (Ip_u16)(netif ? netif->ipcom.ifindex : 0);
        dl.sdl_alen      = 6;
        dl.sdl_type      = IP_IFT_ETHER;

        if (link_addr)
            ipcom_memcpy(&dl.sdl_data[0], link_addr,dl.sdl_alen);

        if (netif)
            IPNET_IF_LOCK(netif);

        /* Add new neighbor */
        ret = ipnet_route_add(&param);

        if (netif)
            IPNET_IF_UNLOCK(netif);

        if (ret < 0)
            return ret;

        /* Get the new neighbor route entry */
        ret = ipnet_route_lookup(family,
                                 vr,
                                 table,
                                 IPNET_RTL_FLAG_LINK_LOCAL | IPNET_RTL_FLAG_DONTCLONE,
                                 &ukey,
                                 netif ? netif->ipcom.ifindex : 0,
                                 netif ? netif->ipcom.ifindex : 0,
                                 &rt);
        if (ret < 0)
            return ret;
    }

#ifdef IPNET_COMPENSATE_UNRELIABLE_NETLINK
    /* Set neighbor acknowledge bit */
    IP_BIT_SET(rt->hdr.flags, IPNET_RTF_X_NEIGH_ACK);
#endif

    if (IP_BIT_ISSET(ndm->ndm_flags,IP_NTF_PROXY))
        /* Proxy ARP entry */
        IP_BIT_SET(rt->hdr.flags, IPNET_RTF_PROTO2);

    if (IP_BIT_ISSET(ndm->ndm_state, IP_NUD_PERMANENT))
        ipnet_route_set_lifetime(rt, IPCOM_ADDR_INFINITE);

    nd_state = ipnet_rtnetlink_neigh_nud2nc(ndm->ndm_state);

#ifdef IPCOM_USE_INET
    if (family == IP_AF_INET)
        ret = ipnet_rtnetlink_ip4_neigh_setup(&ukey, ndm, rt, nd_state, link_addr, rta);
    else
#endif
#ifdef IPCOM_USE_INET6
    if (family == IP_AF_INET6)
        ret = ipnet_rtnetlink_ip6_neigh_setup(&ukey, ndm, rt, nd_state, link_addr, rta);
    else
#endif
        return -IP_ERRNO_EAFNOSUPPORT;

    return ret;
}
コード例 #9
0
/*
 *===========================================================================
 *                    ipnet_rtnetlink_neigh_delneigh_family
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_GLOBAL int
ipnet_rtnetlink_neigh_delneigh_family(Ipnet_netlink_mem_t  *mem,
                                      struct Ip_nlmsghdr   *nlmsg,
                                      struct Ip_rtattr     **rta,
                                      int                  family)
{
    /**/
    Ip_u16                vr;
    Ip_u32                table = IPCOM_ROUTE_TABLE_DEFAULT;
    Ipnet_netif           *netif;
    int                   ret = -IP_ERRNO_EAFNOSUPPORT;
    struct Ip_ndmsg       *ndm = IP_NLMSG_DATA(nlmsg);
    Ipnet_rtnetlink_key_t ukey;

    /* Destination address required */
    if (rta[IP_NDA_DST-1] == IP_NULL)
        return -IP_ERRNO_EINVAL;

#ifdef IPNET_USE_ROUTE_TABLE_NAMES
    if (rta[IP_NDA_TABLE_NAME -1])
    {
        /* Extract router and table from name */
        if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_NDA_TABLE_NAME - 1]),
                                               &vr,
                                               &table) < 0)
            return -IP_ERRNO_ESRCH;
    }
    else
#endif
    {
        if (mem->vr == IPCOM_VR_ANY)
            return -IP_ERRNO_EINVAL;

        vr = ipnet_rtnetlink_vr(rta[IP_NDA_VR - 1], mem->vr);

        if (rta[IP_NDA_TABLE - 1])
            table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_NDA_TABLE - 1]));

    }

    netif = ipnet_if_indextonetif(vr, ndm->ndm_ifindex);

    if (netif && (netif->vr_index != vr))
        return -IP_ERRNO_EINVAL;

    /* */
    if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, netif? netif->ipcom.ifindex : 0, IP_NULL, -1, rta[IP_NDA_DST-1])) < 0)
        return ret;

    /* Delete neighbor */
    ret = ipnet_route_delete2(family,
                              vr,
                              table,
                              &ukey,
                              IP_NULL,
                              IP_NULL,
                              netif ? netif->ipcom.ifindex : 0,
                              0,
                              0,
                              0);

    return ret;
}