/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_rtnetlink.c,v $ $Revision: 1.11.10.1 $ * $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_rtnetlink.c,v $ * $Author: svc-cmnet $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include "ipnet_h.h" #include "ipnet_ctrl.h" #include "ipnet_route.h" #include "ipnet_netlink_h.h" #include "ipnet_rtnetlink_h.h" #include "ipcom_sock.h" #include "ipnet_eth.h" #ifdef IPNET_USE_NETLINK /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_netlink_register_ops *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL void ipnet_rtnetlink_register_family_event(int family, int cmd, Ip_size_t maxattr, Ip_size_t min_size, Ipnet_rtnetlink_do_t doit, Ipnet_netlink_dump_t dumpit) { Ipnet_rtnetlink_table_t *table; Ipnet_rtnetlink_config_t *rtcfg = ipnet->netlink_data[IP_NETLINK_ROUTE]; /**/ if (rtcfg->family_event[family] == IP_NULL) { rtcfg->family_event[family] = ipcom_calloc(IP_RTM_NR_MSGTYPES, sizeof(Ipnet_rtnetlink_table_t *)); ip_assert(rtcfg->family_event[family] != IP_NULL); } ip_assert(rtcfg->family_event[family][cmd - IP_RTM_BASE] == IP_NULL); rtcfg->family_event[family][cmd - IP_RTM_BASE] = ipcom_calloc(1, sizeof(Ipnet_rtnetlink_table_t)); ip_assert(rtcfg->family_event[family][cmd - IP_RTM_BASE] != IP_NULL); table = rtcfg->family_event[family][cmd - IP_RTM_BASE]; table->nl_cmd = cmd; table->nl_func_table.nl_rta_max = maxattr; table->nl_func_table.nl_size_min = IP_NLMSG_LENGTH(min_size); table->nl_func_table.nl_do = doit; table->nl_func_table.nl_dump = dumpit; } #ifdef IPNET_USE_NETLINKSOCK /* *=========================================================================== * ipnet_rtnetlink_register_ops *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL void ipnet_rtnetlink_register_ops(struct Ip_rtnl_link_ops *ops) { ops->next = ipnet->rtnetlink_ops; ipnet->rtnetlink_ops = ops; } /* *=========================================================================== * ipnet_rtnetlink_get_ops *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL struct Ip_rtnl_link_ops * ipnet_rtnetlink_get_ops(const char *kind) { struct Ip_rtnl_link_ops *ops = ipnet->rtnetlink_ops; while (ops != IP_NULL) { if (ipcom_strcmp(ops->kind, kind) == 0) return ops; ops = ops->next; } return IP_NULL; } #endif /* IPNET_USE_NETLINK_SOCK */ /* *=========================================================================== * ipnet_rtnetlink_rta_sz_put *=========================================================================== * Description: Add a NETLINK route attribute to a NETLINK message. * Parameters: nlh - Current NLMSG * sz - Total size * attrtype - Attribute type * attrlen - Lenght of attribute * data - Attribute data * * Returns: * */ IP_GLOBAL void * ipnet_rtnetlink_rta_sz_put(Ipnet_netlink_mem_t *mem, Ip_u16 attrtype, Ip_size_t attrlen, IP_CONST void *data) { struct Ip_rtattr *rta = ipnet_netlink_sz_put(mem, IP_NULL, IP_RTA_LENGTH(attrlen)); if (!rta) return IP_NULL; rta->rta_type = (Ip_u16) attrtype; rta->rta_len = (Ip_u16) IP_RTA_LENGTH (attrlen); if (data) ipcom_memcpy(IP_RTA_DATA(rta), data, attrlen); return rta; } /* *=========================================================================== * ipnet_rtnetlink_rta_sz_put_u32 *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL void * ipnet_rtnetlink_rta_sz_put_u32(Ipnet_netlink_mem_t *mem, Ip_u16 atype, Ip_u32 val) { /* Reinvoke */ return ipnet_rtnetlink_rta_sz_put(mem, atype, sizeof(val), &val); } /* *=========================================================================== * ipnet_rtnetlink_rta_sz_nested_begin *=========================================================================== * Description: Begin a nested NETLINK route attribute to a NETLINK message. * Parameters: nlh - Current NLMSG * sz - Total size * attrtype - Attribute type * * Returns: * */ IP_GLOBAL void * ipnet_rtnetlink_rta_sz_nested_begin(Ipnet_netlink_mem_t *mem, Ip_u16 attrtype) { struct Ip_rtattr *rta = ipnet_netlink_sz_put(mem, IP_NULL, IP_RTA_LENGTH(0)); if (!rta) return IP_NULL; rta->rta_type = (Ip_u16) attrtype; rta->rta_len = (Ip_u16) IP_RTA_LENGTH (0); return rta; } /* *=========================================================================== * ipnet_rtnetlink_rta_sz_nested_end *=========================================================================== * Description: Terminates a nested RTA. * Parameters: nlh - Current NLMSG * rta - Total size * attrtype - Attribute type * * Returns: * */ IP_GLOBAL void ipnet_rtnetlink_rta_sz_nested_end(Ipnet_netlink_mem_t *mem, void *nested) { char *eptr = &mem->ptr[mem->used + mem->offset]; struct Ip_rtattr *rta = nested; rta->rta_len = (Ip_u16) (eptr - (char *)rta); } IP_GLOBAL Ipnet_rtnetlink_func_table_t * ipnet_rtnetlink_family_get_do(struct Ipnet_rtnetlink_table ***table, int family, int cmd) { if (family < IP_AF_MAX && cmd >= IP_RTM_BASE && cmd-IP_RTM_BASE <= IP_RTM_NR_MSGTYPES) { Ipnet_rtnetlink_table_t **tbl = table[family]; if (tbl) { if (tbl[cmd - IP_RTM_BASE] && tbl[cmd - IP_RTM_BASE]->nl_func_table.nl_do) return &tbl[cmd - IP_RTM_BASE]->nl_func_table; } if (family != IP_AF_UNSPEC) return ipnet_rtnetlink_family_get_do(table, IP_AF_UNSPEC, cmd); } return IP_NULL; } IP_GLOBAL Ipnet_rtnetlink_func_table_t * ipnet_rtnetlink_family_get_dump(struct Ipnet_rtnetlink_table ***table, int family, int cmd) { if (family < IP_AF_MAX && cmd >= IP_RTM_BASE && cmd-IP_RTM_BASE <= IP_RTM_NR_MSGTYPES) { Ipnet_rtnetlink_table_t **tbl = table[family]; if (tbl) { if (tbl[cmd - IP_RTM_BASE] && tbl[cmd - IP_RTM_BASE]->nl_func_table.nl_dump) return &tbl[cmd - IP_RTM_BASE]->nl_func_table; } if (family != IP_AF_UNSPEC) return ipnet_rtnetlink_family_get_dump(table, IP_AF_UNSPEC, cmd); } return IP_NULL; } #ifdef IPNET_USE_NETLINKSOCK /* *=========================================================================== * ipnet_netlink_dump *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipnet_rtnetlink_do(Ipnet_rtnetlink_do_t do_it, int family, Ipnet_socket *sock, struct Ip_nlmsghdr *nlmsg, Ip_bool non_blocking, struct Ip_rtattr **rta) { Ipcom_pkt *pkt = IP_NULL; Ipnet_netlink_mem_t mem; int ret; /* Is it a 'get'? */ if (((nlmsg->nlmsg_type - IP_RTM_BASE) & 0x3) == 2) { /**/ if (!ipnet_netlink_pkt_alloc(&pkt, sock, non_blocking, &mem, 512)) return -IP_ERRNO_ENOMEM; } else { /**/ ipnet_netlink_pkt_mem(IP_NULL, sock, &mem); } /* */ ret = (*do_it) (&mem, nlmsg, rta, family); /* */ if (pkt != IP_NULL && ret > 0) { pkt->end += ret; if (!ipnet_netlink_pkt_queue(&pkt, sock)) ret = -IP_ERRNO_ENOBUFS; } if (pkt) ipcom_pkt_free(pkt); return ret < 0? ret : 0; } /* *=========================================================================== * ipnet_rtnetlink_sock_send *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL int ipnet_rtnetlink_sock_send(Ipnet_socket *sock, Ip_bool non_blocking, struct Ip_nlmsghdr *nlmsg) { struct Ip_rtattr **rta = IP_NULL; int ret = 0; Ipnet_rtnetlink_func_table_t *tbl; int family; Ipnet_rtnetlink_config_t *rtcfg = ipnet->netlink_data[IP_NETLINK_ROUTE]; /* Need to retrieve the family byte */ if (nlmsg->nlmsg_len < IP_NLMSG_LENGTH(sizeof(struct Ip_rtgenmsg))) return 0; /* These messages are to be ignored */ if (nlmsg->nlmsg_type < IP_RTM_BASE) return 0; /**/ family = ((struct Ip_rtgenmsg*)IP_NLMSG_DATA(nlmsg))->rtgen_family; /* Dump */ if (IP_BIT_ISSET(nlmsg->nlmsg_flags, IP_NLM_F_DUMP) && ((nlmsg->nlmsg_type - IP_RTM_BASE) & 0x3) == 2) { ret = -IP_ERRNO_EAFNOSUPPORT; tbl = ipnet_rtnetlink_family_get_dump(rtcfg->family_event, family, nlmsg->nlmsg_type); if (tbl == IP_NULL) goto error_out; ret = ipnet_netlink_dump(tbl->nl_dump, family, sock, nlmsg, non_blocking); goto error_out; } tbl = ipnet_rtnetlink_family_get_do(rtcfg->family_event, family, nlmsg->nlmsg_type); if (tbl == IP_NULL) { ret = -IP_ERRNO_EAFNOSUPPORT; goto error_out; } else { struct Ip_rtattr *attr = IP_NULL; Ip_size_t attrlen = 0; /* Check minimum length. */ if (nlmsg->nlmsg_len < tbl->nl_size_min) { ret = -IP_ERRNO_EINVAL; goto error_out; } /* */ if (nlmsg->nlmsg_len > tbl->nl_size_min) { attrlen = nlmsg->nlmsg_len - IP_NLMSG_ALIGN(tbl->nl_size_min); attr = (struct Ip_rtattr*)((char *)nlmsg + IP_NLMSG_ALIGN(tbl->nl_size_min)); } ret = ipnet_netlink_parse(tbl->nl_rta_max, attr, attrlen, &rta); if (ret < 0) goto error_out; } /* DO */ ret = ipnet_rtnetlink_do(tbl->nl_do, family, sock, nlmsg, non_blocking, (void *)rta); error_out: if (rta) ipcom_free(rta); return IP_MIN(ret, 0); } #endif /* IPNET_USE_NETLINK_SOCK */ /* *=========================================================================== * ipnet_netlink_broadcast *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL void ipnet_rtnetlink_broadcast(Ipcom_pkt *pkt, int msg_group) { ipnet_netlink_broadcast(pkt, IP_NETLINK_ROUTE, msg_group); } /* *=========================================================================== * ipnet_rtnetlink_vr *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_u16 ipnet_rtnetlink_vr(struct Ip_rtattr *rta, Ip_u16 vr) { if (rta) return (Ip_u16)IP_GET_32ON8(IP_RTA_DATA(rta)); return vr; } /* *=========================================================================== * ipnet_rtnetlink_dump_family *=========================================================================== * Description: Generic netlink address dumper. * Parameters: * Returns: * */ IP_GLOBAL int ipnet_rtnetlink_addr_dump_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlh, int family, Ip_ptrdiff_t *args) { int req_type; /**/ switch (nlh->nlmsg_type) { case IP_RTM_GETMULTICAST: req_type = IPNET_ADDR_TYPE_MULTICAST; break; case IP_RTM_GETANYCAST: req_type = IPNET_ADDR_TYPE_ANYCAST; break; default: req_type = IPNET_ADDR_TYPE_UNICAST; break; } switch (family) { #ifdef IPCOM_USE_INET case IP_AF_INET: return ipnet_rtnetlink_ip4_addr_dump(mem, nlh, req_type, args); #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: return ipnet_rtnetlink_ip6_addr_dump(mem, nlh, req_type, args); #endif default: return -IP_ERRNO_EAFNOSUPPORT; } } /* *=========================================================================== * ipnet_rtnetlink_addr_newaddr_family *=========================================================================== * Description: Generic netlink address add handler * Parameters: * Returns: * */ IP_GLOBAL int ipnet_rtnetlink_addr_newaddr_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlh, struct Ip_rtattr **rta, int family) { switch (family) { #ifdef IPCOM_USE_INET case IP_AF_INET: return ipnet_rtnetlink_ip4_newaddr(mem, nlh, rta); #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: return ipnet_rtnetlink_ip6_newaddr(mem, nlh, rta); #endif default: return -IP_ERRNO_EAFNOSUPPORT;; } } /* *=========================================================================== * ipnet_rtnetlink_addr_deladdr_family *=========================================================================== * Description: Generic netlink address delete handler * Parameters: * Returns: * */ IP_GLOBAL int ipnet_rtnetlink_addr_deladdr_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlh, struct Ip_rtattr **rta, int family) { switch (family) { #ifdef IPCOM_USE_INET case IP_AF_INET: return ipnet_rtnetlink_ip4_deladdr(mem, nlh, rta); #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: return ipnet_rtnetlink_ip6_deladdr(mem, nlh, rta); #endif default: return -IP_ERRNO_EAFNOSUPPORT; } } IP_GLOBAL void ipnet_rtnetlink_init(void) { ipnet->netlink_data[IP_NETLINK_ROUTE] = ipcom_calloc(1, sizeof(Ipnet_rtnetlink_config_t)); ipnet_rtnetlink_link_init(); } #endif /* IPNET_USE_NETLINK */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */