/*
 *===========================================================================
 *                    ipnet_sysctl_route_dump_elem_len
 *===========================================================================
 * Description: Calculates the length needed to write down address information
 *              for the specified route entry.
 * Parameters:  rt - a route entry.
 * Returns:     Length in bytes.
 *
 */
IP_STATIC Ip_u16
ipnet_sysctl_route_dump_elem_len(Ipnet_route_entry *rt)
{
    Ip_u16 len;
    Ip_u16 addr_len;

    len = sizeof(struct Ipnet_rt_msghdr);
    if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET)
        addr_len = sizeof(struct Ip_sockaddr_in);
    else
        addr_len = sizeof(struct Ip_sockaddr_in6);

    /* Length of destination address */
    len += addr_len;

    /* Length of destination mask */
    if (rt->hdr.mask)
        len += addr_len;

    /* Length of gateway address */
    if (rt->gateway)
        len += IPCOM_SA_LEN_GET(rt->gateway);
    else if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_CLONING))
        len += sizeof(struct Ip_sockaddr_dl);

    return len;
}
Ejemplo n.º 2
0
/*
 *===========================================================================
 *                    ipnet_rtnetlink_ip6_addr_event
 *===========================================================================
 * Description: Status of a network interface has changed, create a IFINFO
 *              event on NETLNK..
 * Parameters:  netif - The interface.
 * Returns:     -
 *
 */
IP_STATIC void
ipnet_rtnetlink_route_event(struct Ipnet_route_entry_struct *rt, int event)
{
    Ipcom_pkt               *pkt    = IP_NULL;
    Ipnet_netlink_mem_t     mem;
    int                     ret     = -1;
    int                     group;

    if (!ipnet_netlink_pkt_alloc(&pkt, IP_NULL, IP_TRUE, &mem, 512))
        return;

    /* Must explicitly switch to the correct VR here */
    pkt->vr_index = mem.vr = IPNET_ROUTE_GET_VR(rt->head);

#ifdef IPCOM_USE_INET
    if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET)
    {
        ret = ipnet_rtnetlink_ip4_route_fill_info (&mem,
                                                   rt,
                                                   0,
                                                   event,
                                                   0);
        group = IP_RTNLGRP_IPV4_ROUTE;
    }
#endif
#ifdef IPCOM_USE_INET6
    if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET6)
    {
        ret = ipnet_rtnetlink_ip6_route_fill_info (&mem,
                                                   rt,
                                                   0,
                                                   event,
                                                   0);
        group = IP_RTNLGRP_IPV6_ROUTE;
    }
#endif

    if (ret < 0)
        ipcom_pkt_free(pkt);
    else
    {
        pkt->end += ret;

        /* We're done; do report this pkt */
        ipnet_rtnetlink_broadcast(pkt, group);
    }
}
/*
 *===========================================================================
 *                    ipnet_sysctl_for_each_rtab_cb
 *===========================================================================
 * Description: Dumps all routes entries for every route table.
 * Parameters:  rtab - The route table to dump.
 *              d - The route dump parameters.
 * Returns:
 *
 */
IP_STATIC void
ipnet_sysctl_for_each_rtab_cb(Ipcom_route *rtab, Ipnet_sysctl_route_data *d)
{
    if (d->vr != IPNET_ROUTE_GET_VR(rtab))
        return;
    if (d->domain != 0 && d->domain != IPNET_ROUTE_GET_FAMILY(rtab))
        return;

    d->table = IPNET_ROUTE_GET_TABLE(rtab);
    ipcom_route_walk_tree(rtab,
                          (Ipcom_route_walk_cb) ipnet_sysctl_route_dump_cb,
                          d);
}
/*
 *===========================================================================
 *                    ipnet_sysctl_route_dump_cb
 *===========================================================================
 * Description: Checks if this entry should be added and adds it if it should.
 * Parameters:  rt - the route entry to add
 *              data - callback data.
 * Returns:     IP_FALSE (the entry should never be deleted).
 *
 */
IP_STATIC Ip_bool
ipnet_sysctl_route_dump_cb(Ipnet_route_entry *rt, Ipnet_sysctl_route_data *data)
{
    struct Ipnet_rt_msghdr *rt_msg;
    Ip_u16                  len;

    if (rt->next)
        (void)ipnet_sysctl_route_dump_cb(rt->next, data);

    if (rt->narrow)
        (void) ipnet_sysctl_route_dump_cb(rt->narrow, data);

    if ((rt->hdr.flags & data->flags) != data->flags)
        return IP_FALSE;

    /* Do not list the 255.255.255.255, 224.0.0.0/4 or IPv6 multicast routes. */
    if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_X_MCAST_RO | IPNET_RTF_X_BCAST_RO | IPNET_RTF_X_HIDDEN))
          return IP_FALSE;

    len = ipnet_sysctl_route_dump_elem_len(rt);
    data->bytes_written += len;

    if (data->bytes_written > data->buf_len)
    {
        /* Buffer to small */
        if (data->buf != IP_NULL)
            data->soerrno = -IP_ERRNO_ENOMEM;
        return IP_FALSE;
    }

    rt_msg = (struct Ipnet_rt_msghdr *) data->buf;
    data->buf = (Ip_u8 *) data->buf + sizeof(struct Ipnet_rt_msghdr);

    ipcom_memset(rt_msg, 0, sizeof(struct Ipnet_rt_msghdr));
    rt_msg->rtm_msglen  = len;
    rt_msg->rtm_version = IPNET_RTM_VERSION;
    rt_msg->rtm_type    = IPNET_RTM_GET;
    rt_msg->rtm_index   = rt->netif ? rt->netif->ipcom.ifindex : 0;
    rt_msg->rtm_table   = data->table;
    rt_msg->rtm_flags   = rt->hdr.flags;
    rt_msg->rtm_use     = rt->use;
    rt_msg->rtm_rmx     = rt->metrics;

    /* add destination address */
    IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_DST);
    data->buf = ipnet_sysctl_route_add_addr(data->buf, IPNET_ROUTE_GET_FAMILY(rt->head), rt->hdr.key);

    if (rt->gateway)
    {
        IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY);
        ipcom_memcpy(data->buf, rt->gateway, IPCOM_SA_LEN_GET(rt->gateway));
        data->buf = (Ip_u8 *) data->buf + IPCOM_SA_LEN_GET(rt->gateway);
    }
    else if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_CLONING))
    {
        struct Ip_sockaddr_dl  *dl = data->buf;
        IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY);
        ipcom_memset(data->buf, 0, sizeof(struct Ip_sockaddr_dl));
        IPCOM_SA_LEN_SET(dl, sizeof(struct Ip_sockaddr_dl));
        dl->sdl_family = IP_AF_LINK;
        ip_assert(rt->netif != IP_NULL);
        if (rt->netif != IP_NULL)
        {
            dl->sdl_index  = (Ip_u16)rt->netif->ipcom.ifindex;
            dl->sdl_type   = (Ip_u8)rt->netif->ipcom.type;
        }
        data->buf = (Ip_u8 *) data->buf + sizeof(struct Ip_sockaddr_dl);
    }

    if (rt->hdr.mask)
    {
        /* add destination mask */
        IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_NETMASK);
        data->buf = ipnet_sysctl_route_add_addr(data->buf, IPNET_ROUTE_GET_FAMILY(rt->head), rt->hdr.mask);
    }

    ip_assert((Ip_u16)((Ip_ptrdiff_t) data->buf - (Ip_ptrdiff_t) rt_msg) == len);

    return IP_FALSE;
}
Ejemplo n.º 5
0
/*
 *===========================================================================
 *                    ipnet_rtnetlink_route_foreach_vr
 *===========================================================================
 * Description: Hash table foreach callback. Called once for each virtual
 *              router that exists in the system.
 * Parameters:  rtab  - route table
 *              param - callback parameters.
 * Returns:     -
 *
 */
IP_STATIC void
ipnet_rtnetlink_route_foreach_vr_family(Ipcom_route *rtab, Ipnet_rtnetlink_route_family_t *param)
{
    int                new_offs = 0;
    Ip_ptrdiff_t       table    = IPNET_ROUTE_GET_TABLE(rtab);
    Ip_u16             vr       = IPNET_ROUTE_GET_VR(rtab);
    Ipnet_route_entry  *rt      = IP_NULL;

    /* This traversal is already aborted */
    if (param->state.aborted)
        return;

    /* Only handle rtabs of selected address family */
    if (IPNET_ROUTE_GET_FAMILY(rtab) != param->family)
        return;

    /* Check if specific VR shall be dumped */
    if (IP_BIT_ISFALSE(param->nlmsg->nlmsg_flags, IP_NLM_F_VR_UNSPEC) && (param->mem->vr != IPCOM_VR_ANY) && (param->mem->vr != vr))
        return;

    /*
     * If this is a trailer message buffer, make sure it
     * starts dumping where the last message ended
     */
    if (param->state.cont)
    {
        Ipnet_route_entry  *rtt = (Ipnet_route_entry*)(*param->state.rt);

        /* Verify current state */
        if (*param->state.vr != vr || *param->state.table != table)
            return;

        if (rtt != IP_NULL)
        {
            rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab),
                                         vr,
                                         table);
            while (rt != IP_NULL)
            {
                if (rt == rtt)
                    break;
                rt = ipnet_route_next_entry(rt);
            }
        }
    }


    /* Reset the continue variable; we're on the move again */
    param->state.cont = 0;

    /* Get first unless we've found one to continue from */
    if (rt == IP_NULL)
        rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab),
                                     vr,
                                     table);

    /* */
    while (rt)
    {
        /* Do not dump the 255.255.255.255, 224.0.0.0/4 or IPv6 multicast routes. */
        /* Do not dump routes that are part of multipath routes either */
        if (IP_BIT_ISFALSE(rt->hdr.flags, IPNET_RTF_X_MCAST_RO | IPNET_RTF_X_BCAST_RO | IPNET_RTF_X_HIDDEN)
            && (rt->prev == IP_NULL))
        {
#ifdef IPCOM_USE_INET
            if (param->family == IP_AF_INET)
            {
                new_offs = ipnet_rtnetlink_ip4_route_fill_info (param->mem,
                                                                rt,
                                                                param->nlmsg->nlmsg_seq,
                                                                IP_RTM_NEWROUTE,
                                                                IP_NLM_F_MULTI);
            }
            else
#endif
#ifdef IPCOM_USE_INET6
            if (param->family == IP_AF_INET6)
            {
                new_offs = ipnet_rtnetlink_ip6_route_fill_info (param->mem,
                                                                rt,
                                                                param->nlmsg->nlmsg_seq,
                                                                IP_RTM_NEWROUTE,
                                                                IP_NLM_F_MULTI);
            }
            else
#endif
            {
                IP_PANIC();
            }

            if (new_offs < 0)
                goto aborted;
        }

        rt = ipnet_route_next_entry(rt);

        /* */
        if (rt && new_offs)
            goto aborted;
    }

    return;

aborted:
    param->state.aborted = 1;
    *param->state.rt     = (Ip_ptrdiff_t)rt;
    *param->state.table  = (Ip_ptrdiff_t)table;
    *param->state.vr     = (Ip_ptrdiff_t)vr;
}
/*
 *===========================================================================
 *                    ipnet_rtnetlink_route_foreach_vr
 *===========================================================================
 * Description: Hash table foreach callback. Called once for each virtual
 *              router that exists in the system.
 * Parameters:  rtab  - route table
 *              param - callback parameters.
 * Returns:     -
 *
 */
IP_STATIC void
ipnet_rtnetlink_neigh_foreach_vr_family(Ipcom_route *rtab, Ipnet_rtnetlink_neigh_family_t *param)
{
    Ip_u16             vr       = IPNET_ROUTE_GET_VR(rtab);
    Ipnet_route_entry  *rt      = IP_NULL;

    /* This traversal is already aborted */
    if (param->state.aborted)
        return;

    /* Only handle rtabs of selected address family */
    if (param->family != IP_AF_UNSPEC && IPNET_ROUTE_GET_FAMILY(rtab) != param->family)
        return;

    /* We only have neigh values in the default table */
    if (IPNET_ROUTE_GET_TABLE(rtab) != IPCOM_ROUTE_TABLE_DEFAULT)
        return;

    /* Check if specific VR shall be dumped */
    if (IP_BIT_ISFALSE(param->nlmsg->nlmsg_flags, IP_NLM_F_VR_UNSPEC) && (param->mem->vr != IPCOM_VR_ANY) && (param->mem->vr != vr))
        return;

    /*
     * If this is a trailer message buffer, make sure it
     * starts dumping where the last message ended
     */
    if (param->state.cont)
    {
        Ipnet_route_entry  *rtt = (Ipnet_route_entry*)(*param->state.rt);

        /* Verify current state */
        if (*param->state.vr != vr)
            return;

        if (rtt != IP_NULL)
        {
            rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab),
                                         vr,
                                         IPNET_ROUTE_GET_TABLE(rtab));
            while (rt != IP_NULL)
            {
                if (rt == rtt)
                    break;
                rt = ipnet_route_next_entry(rt);
            }
        }
    }


    /* Reset the continue variable; we're on the move again */
    param->state.cont = 0;

    /* Get first unless we've found one to continue from */
    if (rt == IP_NULL)
        rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab),
                                     vr,
                                     IPNET_ROUTE_GET_TABLE(rtab));

    /* */
    while (rt)
    {
        do
        {
            if (ipnet_rtnetlink_neigh_is(rt))
                break;
            rt = ipnet_route_next_entry(rt);
        } while (rt != IP_NULL);

        if (rt != IP_NULL)
        {
            int ret = 0;
            /* Verify this particular NC entry */
#ifdef IPCOM_USE_INET
            if (IPNET_ROUTE_GET_FAMILY(rtab) == IP_AF_INET)
                ret = ipnet_rtnetlink_ip4_neigh_fill_info(param->mem, rt, param->nlmsg->nlmsg_seq, IP_RTM_NEWNEIGH, IP_NLM_F_MULTI);
#endif
#ifdef IPCOM_USE_INET6
            if (IPNET_ROUTE_GET_FAMILY(rtab) == IP_AF_INET6)
                ret = ipnet_rtnetlink_ip6_neigh_fill_info(param->mem, rt, param->nlmsg->nlmsg_seq, IP_RTM_NEWNEIGH, IP_NLM_F_MULTI);
#endif
            if (ret < 0)
                goto aborted;

            /* Get next */
            rt = ipnet_route_next_entry(rt);
        }
    }

    return;

aborted:
    param->state.aborted = 1;
    *param->state.rt     = (Ip_ptrdiff_t)rt;
    *param->state.vr     = (Ip_ptrdiff_t)vr;
}