/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6_netlink.c,v $ $Revision: 1.23.10.1 $ * $Source: /home/interpeak/CVSRoot/ipmip6/src/ipmip6_netlink.c,v $ * $Author: svc-cmnet $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmip6_netlink_process_newlink *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipmip6_netlink_process_route(Ipmip6_context_t *ctx, Ipmip_proc_t *proc, struct Ip_nlmsghdr *hdr) { struct Ip_rtmsg *rtm; struct Ip_rtattr *rtattr[IP_RTA_MAX + 1]; Ipmip6_if_t *ife = IP_NULL; rtm = IP_NLMSG_DATA(hdr); ipmip_netlink_nlmsghdr_rta_parse(IP_RTA_MAX + 1, IP_RTM_RTA(rtm), IP_RTM_PAYLOAD(hdr), rtattr); if (rtattr[IP_RTA_OIF]) { if ((ife = ipmip6_if_lockbyindex(ctx, proc, IP_GET_32ON8(IP_RTA_DATA(rtattr[IP_RTA_OIF])))) == IP_NULL) return; } /**/ if (ife != IP_NULL) { ife->iff_changes++; ipmip6_if_release_iflocked(ctx, proc, ife); } else { do { Ipmip6_if_t *nife; if (ife) { /* Lock the interface; touch the changes counter */ ipmip_timer_lock_acquire(&ctx->ipmip, proc, ife->iff_lock); ife->iff_changes++; } /* Acquire next interface */ ipmip_timer_lock_acquire(&ctx->ipmip, proc, ctx->iff.iflock); nife = (Ipmip6_if_t *)(ife? IPCOM_LIST_NEXT(&ife->iff.next) : IPCOM_LIST_FIRST(&ctx->iff.interfaces)); if (nife) ipmip6_if_reference_locked(ctx, proc, nife); ipmip_timer_lock_release(&ctx->ipmip, proc, ctx->iff.iflock); /* Release this lock; will schedule the update */ if (ife) ipmip6_if_release_iflocked(ctx, proc, ife); /* Do next */ ife = nife; } while (ife != IP_NULL); } } /* *=========================================================================== * ipmip6_netlink_process_newlink *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipmip6_netlink_process_link(Ipmip6_context_t *ctx, Ipmip_proc_t *proc, struct Ip_nlmsghdr *hdr) { struct Ip_ifinfomsg *ifm; struct Ip_rtattr *iflattr[IP_IFLA_MAX + 1]; Ipmip6_if_t *ife = IP_NULL; ifm = IP_NLMSG_DATA(hdr); ipmip_netlink_nlmsghdr_rta_parse(IP_IFLA_MAX + 1, IP_IFLA_RTA(ifm), IP_IFLA_PAYLOAD(hdr), iflattr); if (iflattr[IP_IFLA_IFNAME]) { /**/ ife = ipmip6_if_lockbyname(ctx, proc, ipmip_ntop_strn(proc, IP_RTA_DATA(iflattr[IP_IFLA_IFNAME]), IP_RTA_PAYLOAD(iflattr[IP_IFLA_IFNAME]))); } else if (ifm->ifi_index != 0) { ife = ipmip6_if_lockbyindex(ctx, proc, ifm->ifi_index); } /**/ if (ife != IP_NULL) { /**/ if (hdr->nlmsg_type == IP_RTM_DELLINK) { ipmip6_if_link_down_iflocked(ctx, proc, ife); } else { if ((ifm->ifi_flags & (IP_IFF_UP|IP_IFF_RUNNING)) == (IP_IFF_UP|IP_IFF_RUNNING)) { ipmip6_if_link_up_iflocked(ctx, proc, ife, ifm->ifi_index); } else ipmip6_if_link_down_iflocked(ctx, proc, ife); } ipmip6_if_release_iflocked(ctx, proc, ife); } } /* *=========================================================================== * ipmip6_netlink_process_newlink *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipmip6_netlink_process_addr(Ipmip6_context_t *ctx, Ipmip_proc_t *proc, struct Ip_nlmsghdr *hdr) { struct Ip_ifaddrmsg *ifa; struct Ip_rtattr *ifattr[IP_IFA_MAX + 1]; Ipmip6_if_t *ife; ifa = IP_NLMSG_DATA(hdr); /**/ ipmip_netlink_nlmsghdr_rta_parse(IP_IFA_MAX + 1, IP_IFA_RTA(ifa), IP_IFA_PAYLOAD(hdr), ifattr); if (ifattr[IP_IFA_LOCAL]) { ife = ipmip6_if_lockbyindex(ctx, proc, ifa->ifa_index); /**/ if (ife != IP_NULL) { /**/ if (hdr->nlmsg_type == IP_RTM_DELADDR) { /**/ if (ifa->ifa_family == IP_AF_INET6) { ipmip6_if_inet6_del_iflocked(ctx, proc, ife, (struct Ip_in6_addr *)IP_RTA_DATA(ifattr[IP_IFA_LOCAL])); } #ifdef IPMIP_USE_INET else if (ifa->ifa_family == IP_AF_INET) { ipmip6_if_inet_del_iflocked(ctx, proc, ife, IP_GET_32ON8(IP_RTA_DATA(ifattr[IP_IFA_LOCAL]))); } #endif } else { if (ifa->ifa_family == IP_AF_INET6) { ipmip6_if_inet6_add_iflocked(ctx, proc, ife, (struct Ip_in6_addr *)IP_RTA_DATA(ifattr[IP_IFA_LOCAL]), ifa->ifa_prefixlen, ifa->ifa_scope, ifa->ifa_flags); } #ifdef IPMIP_USE_INET else if (ifa->ifa_family == IP_AF_INET) { ipmip6_if_inet_add_iflocked(ctx, proc, ife, IP_GET_32ON8(IP_RTA_DATA(ifattr[IP_IFA_LOCAL]))); } #endif } ipmip6_if_release_iflocked(ctx, proc, ife); } } } IP_STATIC int ipmip6_netlink_prefix_do(Ipmip6_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ip_u16 type, Ip_u32 ifindex, const void *prefix, Ip_u32 prefix_length, Ipmip_buffer_t *reply) { Ipmip_buffer_t rbuf; Ip_size_t hdr_off; struct Ip_mipmsg *msg; int ret; ipmip_buffer_init(&rbuf); /* Create NLMSG HDR */ ipmip_netlink_nlmsghdr_request(&rbuf, 0, 0, cmd, 0); msg = ipmip_buffer_offset(&rbuf, ipmip_netlink_nlmsghdr_put(&rbuf, IP_NULL, sizeof(*msg))); msg->mip_family = IP_AF_INET6; msg->mip_type = type; msg->mip_flags = 0; /* Create the nested HoA attribute */ hdr_off = ipmip_netlink_nlmsghdr_rta_begin(&rbuf, IP_MIP_ENCAP); ipmip_netlink_nlmsghdr_rta_put_in6(&rbuf, IP_WRMOB6_PREFIX_PREFIX, prefix); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_PREFIX_IFINDEX, ifindex); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_PREFIX_LENGTH, prefix_length); ipmip_netlink_nlmsghdr_rta_end(&rbuf, hdr_off); /* Complete the buffer */ ipmip_netlink_nlmsghdr_done(&rbuf, 0); /* NETLINK request */ ret = ipmip_netlink_request(&ctx->ipmip, proc, ctx->ipmip.nl_req, 0, 0, (struct Ip_nlmsghdr *)IPMIP_BUFFER_PTR(&rbuf), reply); /**/ ipmip_buffer_release(&rbuf); return ret; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmip6_netlink_process(Ipmip6_context_t *ctx, Ipmip_proc_t *proc, struct Ip_nlmsghdr *hdr) { switch (hdr->nlmsg_type) { case IP_RTM_NEWLINK: case IP_RTM_DELLINK: ipmip6_netlink_process_link(ctx, proc, hdr); break; case IP_RTM_NEWADDR: case IP_RTM_DELADDR: ipmip6_netlink_process_addr(ctx, proc, hdr); break; case IP_RTM_NEWROUTE: case IP_RTM_DELROUTE: ipmip6_netlink_process_route(ctx, proc, hdr); break; default: break; } } IP_GLOBAL int ipmip6_netlink_route_mip_do(Ipmip6_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ip_u16 type, Ip_u8 flags, Ip_u32 table, Ip_u32 ifindex, const void *prefix, Ip_size_t psize, Ip_u32 prefix_len, const void *nexthop, Ip_size_t nsize, Ip_u32 nat_port, const Ipmip_netlink_kern_compare_t *srccmp, const Ipmip_netlink_kern_handle_t *handle, int link, Ip_u32 *gre_key, Ip_u32 rtf_flags) { Ipmip_buffer_t rbuf; Ip_size_t hdr_off; struct Ip_mipmsg *msg; int ret; ipmip_buffer_init(&rbuf); /* Create NLMSG HDR */ ipmip_netlink_nlmsghdr_request(&rbuf, 0, 0, cmd, 0); msg = ipmip_buffer_offset(&rbuf, ipmip_netlink_nlmsghdr_put(&rbuf, IP_NULL, sizeof(*msg))); msg->mip_family = IP_AF_INET6; msg->mip_type = type; msg->mip_flags = flags; /* Create the nested HoA attribute */ hdr_off = ipmip_netlink_nlmsghdr_rta_begin(&rbuf, IP_MIP_ENCAP); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_IFINDEX, ifindex); ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_DST, psize, prefix); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_DST_LEN, prefix_len); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_TABLE, table); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_FLAGS, rtf_flags); if ((nat_port & 0xFFFF) != 0) ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_NAT_PORT, nat_port); if (nexthop) ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_GW, nsize, nexthop); if (srccmp) ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_SRCMAC, sizeof(*srccmp), srccmp); if (handle) ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_HANDLE, sizeof(*handle), handle); if (gre_key) ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_GRE_KEY, *gre_key); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_LINK, link); ipmip_netlink_nlmsghdr_rta_end(&rbuf, hdr_off); /* Complete the buffer */ ipmip_netlink_nlmsghdr_done(&rbuf, 0); /* NETLINK request */ ret = ipmip_netlink_request(&ctx->ipmip, proc, ctx->ipmip.nl_req, 0, 0, (struct Ip_nlmsghdr *)IPMIP_BUFFER_PTR(&rbuf), IP_NULL); /**/ ipmip_buffer_release(&rbuf); if (ret < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip, proc, "Unable to perform MIP6 command %d/%d = %d", cmd, type, -ret)); } return ret; } /* *=========================================================================== * ipmip6_netlink_activate_address *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL int ipmip6_netlink_route_do(Ipmip6_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ip_u16 type, Ip_u8 flags, Ip_u32 table, Ip_u32 ifindex, const struct Ip_in6_addr *hoa, const struct Ip_in6_addr *coa, const void *prefix, Ip_size_t psize, Ip_u32 prefix_len, const void *nexthop, Ip_size_t nsize, Ip_u32 nat_port, const Ipmip_netlink_kern_compare_t *srccmp, Ip_u32 *gre_key, Ipmip_buffer_t *reply, Ip_u32 rtf_flags) { Ipmip_buffer_t rbuf; Ip_size_t hdr_off; struct Ip_mipmsg *msg; int ret; ipmip_buffer_init(&rbuf); /* Create NLMSG HDR */ ipmip_netlink_nlmsghdr_request(&rbuf, 0, 0, cmd, 0); msg = ipmip_buffer_offset(&rbuf, ipmip_netlink_nlmsghdr_put(&rbuf, IP_NULL, sizeof(*msg))); msg->mip_family = IP_AF_INET6; msg->mip_type = type; msg->mip_flags = flags; /* Create the nested HoA attribute */ hdr_off = ipmip_netlink_nlmsghdr_rta_begin(&rbuf, IP_MIP_ENCAP); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_IFINDEX, ifindex); ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_DST, psize, prefix); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_DST_LEN, prefix_len); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_TABLE, table); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_FLAGS, rtf_flags); if ((nat_port & 0xFFFF) != 0) ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_NAT_PORT, nat_port); if (hoa) ipmip_netlink_nlmsghdr_rta_put_in6(&rbuf, IP_WRMOB6_ROUTE_HOA, hoa); if (coa) ipmip_netlink_nlmsghdr_rta_put_in6(&rbuf, IP_WRMOB6_ROUTE_COA, coa); if (nexthop) ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_GW, nsize, nexthop); if (srccmp) ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_SRCMAC, sizeof(*srccmp), srccmp); if (gre_key) ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_GRE_KEY, *gre_key); ipmip_netlink_nlmsghdr_rta_end(&rbuf, hdr_off); /* Complete the buffer */ ipmip_netlink_nlmsghdr_done(&rbuf, 0); /* NETLINK request */ ret = ipmip_netlink_request(&ctx->ipmip, proc, ctx->ipmip.nl_req, 0, 0, (struct Ip_nlmsghdr *)IPMIP_BUFFER_PTR(&rbuf), reply); /**/ ipmip_buffer_release(&rbuf); return ret; } /* *=========================================================================== * ipmip6_netlink_address_statistics *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL int ipmip6_netlink_address_do(Ipmip6_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ip_u16 type, Ip_u8 flags, Ip_u32 ifindex, Ip_u8 family, const void *addr, Ipmip_buffer_t *reply) { Ipmip_buffer_t rbuf; Ip_size_t hdr_off; struct Ip_mipmsg *msg; int ret; ipmip_buffer_init(&rbuf); /* Create NLMSG HDR */ ipmip_netlink_nlmsghdr_request(&rbuf, 0, 0, cmd, 0); msg = ipmip_buffer_offset(&rbuf, ipmip_netlink_nlmsghdr_put(&rbuf, IP_NULL, sizeof(*msg))); msg->mip_family = IP_AF_INET6; msg->mip_type = type; msg->mip_flags = flags; /* Create the nested HoA attribute */ hdr_off = ipmip_netlink_nlmsghdr_rta_begin(&rbuf, IP_MIP_ENCAP); if (addr) ipmip_netlink_nlmsghdr_rta_put_inX(&rbuf, IP_WRMOB6_HOA_ADDRESS, family, addr); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_HOA_IFINDEX, ifindex); ipmip_netlink_nlmsghdr_rta_end(&rbuf, hdr_off); /* Complete the buffer */ ipmip_netlink_nlmsghdr_done(&rbuf, 0); /* NETLINK request */ ret = ipmip_netlink_request(&ctx->ipmip, proc, ctx->ipmip.nl_req, 0, 0, (struct Ip_nlmsghdr *)IPMIP_BUFFER_PTR(&rbuf), reply); /**/ ipmip_buffer_release(&rbuf); return ret; } /* *=========================================================================== * ipmip6_netlink_address_statistics *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_bool ipmip6_netlink_prefix_generate(Ipmip6_context_t *ctx, Ipmip_proc_t *proc, Ip_u32 ifindex, const void *prefix, Ip_u32 prefix_length, Ipmip6_address_t *reply) { Ipmip_buffer_t rbuf; Ip_bool ret = IP_FALSE; if (ifindex == 0) return IP_FALSE; ipmip_buffer_init(&rbuf); if (ipmip6_netlink_prefix_do(ctx, proc, IP_RTM_GETMIP, IP_WRMOB6_GET_PREFIX_ADDR, ifindex, prefix, prefix_length, &rbuf) == 0) { struct Ip_nlmsghdr *nlhdr = IPMIP_BUFFER_PTR(&rbuf); struct Ip_rtattr *rta = ipmip_netlink_nlmsghdr_rta_find(IP_MIP_RTA(IP_NLMSG_DATA(nlhdr)), IP_MIP_PAYLOAD(nlhdr), IP_MIP_ENCAP); if (rta) { struct Ip_rtattr *pattr[IP_WRMOB6_PREFIX_MAX + 1]; /* parse it */ ipmip_netlink_nlmsghdr_rta_parse(IP_WRMOB6_PREFIX_MAX + 1, IP_RTA_DATA(rta), IP_RTA_PAYLOAD(rta), pattr); if (pattr[IP_WRMOB6_PREFIX_PREFIX] && pattr[IP_WRMOB6_PREFIX_LENGTH]) { ipcom_memcpy(&reply->prefix, IP_RTA_DATA(pattr[IP_WRMOB6_PREFIX_PREFIX]), sizeof(reply->prefix)); reply->len = (Ip_u8) IP_GET_32ON8(IP_RTA_DATA(pattr[IP_WRMOB6_PREFIX_LENGTH])); ret = IP_TRUE; } } } ipmip_buffer_release(&rbuf); return ret; } IP_GLOBAL int ipmip6_netlink_del_handle(struct Ipmip6_context *ctx, struct Ipmip_proc *proc, Ip_u32 facility, Ip_u32 identity) { Ipmip_buffer_t rbuf; Ip_size_t hdr_off; struct Ip_mipmsg *msg; int ret; Ipmip_netlink_kern_handle_t handle; ipmip_buffer_init(&rbuf); /* Create NLMSG HDR */ ipmip_netlink_nlmsghdr_request(&rbuf, 0, 0, IP_RTM_DELMIP, 0); msg = ipmip_buffer_offset(&rbuf, ipmip_netlink_nlmsghdr_put(&rbuf, IP_NULL, sizeof(*msg))); msg->mip_family = IP_AF_INET6; msg->mip_type = IP_WRMOB6_DEL_HANDLE; msg->mip_flags = 0; /* Create the nested HoA attribute */ hdr_off = ipmip_netlink_nlmsghdr_rta_begin(&rbuf, IP_MIP_ENCAP); /* Identity */ handle.mip_facility = facility; handle.mip_ident = identity; ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_HANDLE, sizeof(handle), &handle); ipmip_netlink_nlmsghdr_rta_end(&rbuf, hdr_off); /* Complete the buffer */ ipmip_netlink_nlmsghdr_done(&rbuf, 0); /* NETLINK request */ ret = ipmip_netlink_request(&ctx->ipmip, proc, ctx->ipmip.nl_req, 0, 0, (struct Ip_nlmsghdr *)IPMIP_BUFFER_PTR(&rbuf), IP_NULL); /**/ ipmip_buffer_release(&rbuf); if (ret < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip, proc, "Unable to perform MIP6 DEL HANDLE = %d", -ret)); } return ret; } IP_GLOBAL int ipmip6_netlink_new_handle(struct Ipmip6_context *ctx, struct Ipmip_proc *proc, Ip_u32 facility, Ip_u32 identity) { Ipmip_buffer_t rbuf; Ip_size_t hdr_off; struct Ip_mipmsg *msg; int ret; Ipmip_netlink_kern_handle_t handle; ipmip_buffer_init(&rbuf); /* Create NLMSG HDR */ ipmip_netlink_nlmsghdr_request(&rbuf, 0, 0, IP_RTM_NEWMIP, 0); msg = ipmip_buffer_offset(&rbuf, ipmip_netlink_nlmsghdr_put(&rbuf, IP_NULL, sizeof(*msg))); msg->mip_family = IP_AF_INET6; msg->mip_type = IP_WRMOB6_NEW_HANDLE; msg->mip_flags = 0; /* Create the nested HoA attribute */ hdr_off = ipmip_netlink_nlmsghdr_rta_begin(&rbuf, IP_MIP_ENCAP); /* Identity */ handle.mip_facility = facility; handle.mip_ident = identity; ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_HANDLE, sizeof(handle), &handle); ipmip_netlink_nlmsghdr_rta_end(&rbuf, hdr_off); /* Complete the buffer */ ipmip_netlink_nlmsghdr_done(&rbuf, 0); /* NETLINK request */ ret = ipmip_netlink_request(&ctx->ipmip, proc, ctx->ipmip.nl_req, 0, 0, (struct Ip_nlmsghdr *)IPMIP_BUFFER_PTR(&rbuf), IP_NULL); /**/ ipmip_buffer_release(&rbuf); if (ret < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip, proc, "Unable to perform MIP6 NEW HANDLE = %d", -ret)); } return ret; } IP_GLOBAL Ip_bool ipmip6_netlink_get_handle_stat(struct Ipmip6_context *ctx, struct Ipmip_proc *proc, Ipmip_netlink_kern_handle_t *handle, Ipmip6_netlink_kern_statistics_t *link_recv, Ipmip6_netlink_kern_statistics_t *link_send) { Ipmip_buffer_t rbuf; Ip_size_t hdr_off; struct Ip_mipmsg *msg; int ret; Ipmip_buffer_t reply; ipmip_buffer_init(&rbuf); ipmip_buffer_init(&reply); /* Create NLMSG HDR */ ipmip_netlink_nlmsghdr_request(&rbuf, 0, 0, IP_RTM_GETMIP, 0); msg = ipmip_buffer_offset(&rbuf, ipmip_netlink_nlmsghdr_put(&rbuf, IP_NULL, sizeof(*msg))); msg->mip_family = IP_AF_INET6; msg->mip_type = IP_WRMOB6_GET_HANDLE_STAT; msg->mip_flags = 0; /* Create the nested HoA attribute */ hdr_off = ipmip_netlink_nlmsghdr_rta_begin(&rbuf, IP_MIP_ENCAP); ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_HANDLE, sizeof(*handle), handle); ipmip_netlink_nlmsghdr_rta_end(&rbuf, hdr_off); /* Complete the buffer */ ipmip_netlink_nlmsghdr_done(&rbuf, 0); /* NETLINK request */ ret = ipmip_netlink_request(&ctx->ipmip, proc, ctx->ipmip.nl_req, 0, 0, (struct Ip_nlmsghdr *)IPMIP_BUFFER_PTR(&rbuf), &reply); /**/ ipmip_buffer_release(&rbuf); if (ret >= 0) { struct Ip_nlmsghdr *nlhdr = IPMIP_BUFFER_PTR(&reply); Ip_size_t sz = IPMIP_BUFFER_SIZE(&reply); while (IP_NLMSG_OK(nlhdr, sz)) { if (nlhdr->nlmsg_type == IP_RTM_GETMIP) { struct Ip_rtattr *rta = IP_MIP_RTA(IP_NLMSG_DATA(nlhdr)); Ip_size_t rta_sz = IP_MIP_PAYLOAD(nlhdr); while (IP_RTA_OK(rta, rta_sz)) { if (rta->rta_type == IP_MIP_ENCAP) { /**/ struct Ip_rtattr *srta[IP_WRMOB6_STATS_MAX + 1]; ipmip_netlink_nlmsghdr_rta_parse(IP_WRMOB6_STATS_MAX + 1, IP_RTA_DATA(rta), IP_RTA_PAYLOAD(rta), srta); /* Add statistics */ ipcom_memcpy(link_recv, IP_RTA_DATA(srta[IP_WRMOB6_STATS_LINK_RECV]), sizeof(*link_recv)); ipcom_memcpy(link_send, IP_RTA_DATA(srta[IP_WRMOB6_STATS_LINK_SEND]), sizeof(*link_send)); ipmip_buffer_release(&reply); return IP_TRUE; } rta = IP_RTA_NEXT(rta, rta_sz); } } nlhdr = IP_NLMSG_NEXT(nlhdr, sz); } } ipmip_buffer_release(&reply); return IP_FALSE; } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */