/*
 *===========================================================================
 *                    ipnet_rtnetlink_route_delroute_family
 *===========================================================================
 * Description: Delete a route 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_delroute_family(Ipnet_netlink_mem_t   *mem,
                                      struct Ip_nlmsghdr    *nlh,
                                      struct Ip_rtattr      **rta,
                                      int                   family)
{
    int                      ret = -1;
    Ip_u16                   vr;
    Ip_u32                   table;
    Ip_u32                   ifindex = 0;
    Ip_bool                  is_multipath_route = IP_FALSE;
    Ip_size_t                mpa_size = 0;
    struct Ip_rtnexthop      *nh = IP_NULL;
    struct Ip_sockaddr       *gw = IP_NULL;
    void                     *mask = IP_NULL;
    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 */

    table = IPCOM_ROUTE_TABLE_GET(rtm->rtm_table);

#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])
    {
        if (rta[IP_RTA_OIF-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32)))
			return -IP_ERRNO_EINVAL;

        ifindex = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_OIF-1]));
     }

    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, ifindex, &mask, rtm->rtm_dst_len, rta[IP_RTA_DST-1])) < 0)
        return ret;

    if ((ret = ipnet_rtnetlink_route_gw_setup(family, ifindex, &ugw, &gw, rta[IP_RTA_GATEWAY-1])) < 0)
        return ret;

    if (rta[IP_RTA_GATEWAY-1])
        gw = &ugw.sa;

#ifdef IPMPLS
    if (rta[IP_RTA_NH_PROTO-1])
    {
        Ip_u32 nh_type;

        /* IPNET MPLS pseudo-wire route */
        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));

        gw = (struct Ip_sockaddr *)&gw_mpls;
    }
#endif

    while(1)
    {
        if (is_multipath_route)
        {
            ifindex = nh->rtnh_ifindex;

            if (nh->rtnh_len > sizeof(struct Ip_rtnexthop))
            {
                /* Multihop route has gateway */
                if ((ret = ipnet_rtnetlink_route_gw_setup(family, ifindex, &ugw, &gw, IP_RTNH_DATA(nh))) < 0)
                    return ret;
            }
        }

        /* Delete the route */
        ret = ipnet_route_delete2(family,
                                  vr,
                                  table,
                                  &ukey,
                                  mask,
                                  gw,
                                  ifindex,
                                  0,
                                  0,
                                  0);

        if (is_multipath_route)
        {
            mpa_size -= IP_RTNH_ALIGN(nh->rtnh_len);
            gw = IP_NULL;

            if (mpa_size > 0)
                nh = IP_RTNH_NEXT(nh);
            else
                break;
        }
        else
            break;

    }

    return is_multipath_route ? 0 : ret;
}
/*
 *===========================================================================
 *                    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;
}