/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_rtnetlink_link.c,v $ $Revision: 1.18.2.3 $ * $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_rtnetlink_link.c,v $ * $Author: hsun $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation Jonas Rendel ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** * Contains netlink handlers for managing interfaces */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPNET_USE_NETLINK #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #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" #ifdef IP_PORT_LKM #include "ipcom_lkm.h" /* Needed for Linux PPP interface config */ #endif /* IP_PORT_LKM */ #ifdef IPMIP #include #endif #include "ipnet_eth.h" #ifdef IPCOM_USE_FORWARDER_VLAN_STACKING #include "ipnet_svlan_netlink.h" #endif #ifdef IPCOM_FORWARDER_NAE #include #endif /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ #ifdef IPCOM_USE_TCP IP_EXTERN IP_GLOBAL void iptcp_ao_rtnetlink_init(void); #endif /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC int ipnet_rtnetlink_link_dump_all(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlmsg, int family, Ip_ptrdiff_t *args) { Ip_ptrdiff_t *done = &args[0]; Ip_ptrdiff_t *cfamily = &args[1]; Ip_ptrdiff_t i; Ipnet_rtnetlink_config_t *rtcfg = ipnet->netlink_data[IP_NETLINK_ROUTE]; (void)family; for (i = *cfamily; i < IP_AF_MAX; i++) { Ipnet_rtnetlink_table_t **tbl; if (i == IP_AF_PACKET || i == IP_AF_UNSPEC) continue; if ((tbl = rtcfg->family_event[i]) != IP_NULL) { /* Continue until termination */ if (tbl[nlmsg->nlmsg_type - IP_RTM_BASE] && tbl[nlmsg->nlmsg_type - IP_RTM_BASE]->nl_func_table.nl_dump) { (*tbl[nlmsg->nlmsg_type - IP_RTM_BASE]->nl_func_table.nl_dump) (mem, nlmsg, (int) i, &args[2]); /* Done pointer */ if (!args[2]) goto exit_out; } } /* Clear the args area */ ipcom_memset(&args[2], 0, sizeof(Ip_ptrdiff_t) * 6); } /* All done */ *done = 1; exit_out: *cfamily = i; return (int) mem->used; } #ifdef IPNET_USE_NETLINKSOCK /* *=========================================================================== * ipnet_rtnetlink_link_stats_get *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipnet_rtnetlink_link_stats_retrieve(Ipnet_netif *netif, struct Ip_rtnl_link_stats *devstats, struct Ip_rtnl_link_stats64 *devstats64) { /* Map our internal statistics to the rtnl_link_stats */ ipcom_memset(devstats, 0, sizeof(*devstats)); devstats->rx_bytes = netif->ibytes; devstats->rx_packets = netif->ipackets; devstats->rx_errors = netif->ierrors; devstats->rx_dropped = netif->iqdrops; devstats->collisions = netif->collisions; devstats->multicast = netif->imcasts; devstats->tx_bytes = netif->obytes; devstats->tx_packets = netif->opackets; devstats->tx_errors = netif->oerrors; ipcom_memset(devstats64, 0, sizeof(*devstats64)); devstats64->rx_bytes = netif->ibytes; devstats64->rx_packets = netif->ipackets; devstats64->rx_errors = netif->ierrors; devstats64->rx_dropped = netif->iqdrops; devstats64->collisions = netif->collisions; devstats64->multicast = netif->imcasts; devstats64->tx_bytes = netif->obytes; devstats64->tx_packets = netif->opackets; devstats64->tx_errors = netif->oerrors; } /* *========================================================================== * ipnet_rtnetlink_link_sz_fillifinfo *=========================================================================== * Description: Get interface info via NETLINK * Parameters: data - Message payload. * len - Length of message. * cb - NETLINK callback entry * * Returns: 0 - Success * <0 - Failure * */ IP_STATIC int ipnet_rtnetlink_link_sz_fillifinfo(Ipnet_netlink_mem_t *mem, int event, Ip_u16 eflags, Ip_u32 seq, Ip_u32 change, Ipnet_netif *netif) { Ip_size_t ifname_len = ipcom_strlen(netif->ipcom.name); struct Ip_ifinfomsg *ifinfo; Ip_u32 tmp32; struct Ip_nlmsghdr *nlh; nlh = ipnet_netlink_nlmsg_sz_begin(mem, seq, event, eflags); if (!nlh) return -1; /* Setup the IFINFO header */ ifinfo = ipnet_netlink_sz_put(mem, IP_NULL, sizeof(*ifinfo)); if (!ifinfo) return -1; ifinfo->ifi_family = IP_AF_UNSPEC; ifinfo->ifi_type = (Ip_u16)IPCOM_ARPHRD_TYPE(&netif->ipcom); ifinfo->ifi_index = (Ip_s32) netif->ipcom.ifindex; ifinfo->ifi_flags = netif->ipcom.flags; /* Shouldn't this be mapped? */ ifinfo->ifi_change = change; if (netif->ipcom.link_addr_size) if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_ADDRESS, netif->ipcom.link_addr_size, netif->ipcom.link_addr)) return -1; /* Ethernet specific 'patch' */ if (ifinfo->ifi_type == IP_IFT_ETHER) { Ip_u16 bcast[3]; IPNET_SET_ETHADDR_BROADCAST(bcast); if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_BROADCAST, sizeof(bcast), bcast)) return -1; #ifdef IPNET_USE_BOND if (IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_SLAVE)) { Ipnet_netif *master = ipnet_bond_get_master(netif); if (master != IP_NULL) { tmp32 = master->ipcom.ifindex; if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_MASTER, sizeof(tmp32), &tmp32)) return -1; } } #endif } if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_IFNAME, ifname_len + 1, netif->ipcom.name)) return -1; tmp32 = netif->ipcom.mtu; if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_MTU, sizeof(tmp32), &tmp32)) return -1; tmp32 = netif->vr_index; if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_VR, sizeof(tmp32), &tmp32)) return -1; if (IP_NULL != netif->snd_queue) if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_QDISC, ipcom_strlen(netif->snd_queue->type) + 1, netif->snd_queue->type)) return -1; /* Do the statistics */ { struct Ip_rtattr *rtas; struct Ip_rtattr *rtas2; rtas = ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_STATS, sizeof(struct Ip_rtnl_link_stats), IP_NULL); if (!rtas) return -1; rtas2 = ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_STATS64, sizeof(struct Ip_rtnl_link_stats64), IP_NULL); if (!rtas2) return -1; ipnet_rtnetlink_link_stats_retrieve(netif, (struct Ip_rtnl_link_stats *)IP_RTA_DATA(rtas), (struct Ip_rtnl_link_stats64 *)IP_RTA_DATA(rtas2)); } if (netif->rtnetlink_ops != IP_NULL) { int ret; struct Ip_rtattr *rta; if (netif->rtnetlink_ops->fill_link) { ret = (*netif->rtnetlink_ops->fill_link) (mem, netif); if (ret < 0) return -1; } rta = ipnet_rtnetlink_rta_sz_nested_begin(mem, IP_IFLA_LINKINFO); if (!rta) return -1; if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_INFO_KIND, ipcom_strlen(netif->rtnetlink_ops->kind) + 1, netif->rtnetlink_ops->kind)) return -1; if (netif->rtnetlink_ops->fill_info != IP_NULL) { struct Ip_rtattr *info = ipnet_rtnetlink_rta_sz_nested_begin(mem, IP_IFLA_INFO_DATA); if (!info) return -1; ret = (*netif->rtnetlink_ops->fill_info) (mem, netif); if (ret < 0) return -1; ipnet_rtnetlink_rta_sz_nested_end(mem, info); } ipnet_rtnetlink_rta_sz_nested_end(mem, rta); } return ipnet_netlink_nlmsg_sz_end(mem, nlh); } /* *========================================================================== * ipnet_rtnetlink_link_dump *=========================================================================== * Description: Get interface info via NETLINK * Parameters: data - Message payload. * len - Length of message. * cb - NETLINK callback entry * * Returns: 0 - Success * <0 - Failure * */ IP_STATIC int ipnet_rtnetlink_link_dump_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlmsg, int family, Ip_ptrdiff_t *args) { Ip_ptrdiff_t *done = &args[0]; Ip_ptrdiff_t *ifx = &args[1]; unsigned int i; Ipnet_netif *netif; Ip_u32 sindex = (Ip_u32) *ifx; Ip_u16 vr = IPCOM_VR_ANY; (void)family; if (*done) goto exit_out; if (IP_BIT_ISFALSE(nlmsg->nlmsg_flags, IP_NLM_F_VR_UNSPEC) && (mem->vr != IPCOM_VR_ANY)) vr = mem->vr; /* * IPNET_NETIF_FOR_EACH_ON_VR sets netif to NULL after the for loop, * this is a performance optimized defination */ /* coverity[result_independent_of_operands] */ IPNET_NETIF_FOR_EACH_ON_VR(netif, vr, i) { int ret; if (sindex != 0 && sindex != netif->ipcom.ifindex) continue; sindex = 0; *ifx = (Ip_ptrdiff_t) netif->ipcom.ifindex; /* */ IPNET_IF_LOCK(netif); ret = ipnet_rtnetlink_link_sz_fillifinfo(mem, IP_RTM_NEWLINK, IP_NLM_F_MULTI, nlmsg->nlmsg_seq, 0, netif); IPNET_IF_UNLOCK(netif); if (ret < 0) goto exit_out; } /* We're done */ *done = 1; exit_out: return (int) mem->used; } IP_STATIC int ipnet_rtnetlink_link_parse_linkops(struct Ip_rtattr **rta, struct Ip_rtnl_link_ops **ops, struct Ip_rtattr ***linkdata) { struct Ip_rtattr **linkinfo = IP_NULL; int ret = 0; if (rta[IP_IFLA_LINKINFO - 1] != IP_NULL) { char *kind; /* Need the 'KIND*' */ ret = ipnet_netlink_parse(IP_IFLA_INFO_MAX, IP_RTA_DATA(rta[IP_IFLA_LINKINFO - 1]), IP_RTA_PAYLOAD(rta[IP_IFLA_LINKINFO - 1]), &linkinfo); if (ret < 0) goto done; /* Got the linkinfo */ if ((kind = ipnet_netlink_strdup((struct Ip_nlattr *)linkinfo[IP_IFLA_INFO_KIND - 1])) != IP_NULL) { *ops = ipnet_rtnetlink_get_ops(kind); ipcom_free(kind); } /* Parse link data, if we have it */ if (*ops != IP_NULL) { if ((*ops)->maxtype != 0 && linkinfo[IP_IFLA_INFO_DATA - 1] != IP_NULL) { ret = ipnet_netlink_parse((*ops)->maxtype, IP_RTA_DATA(linkinfo[IP_IFLA_INFO_DATA - 1]), IP_RTA_PAYLOAD(linkinfo[IP_IFLA_INFO_DATA - 1]), linkdata); if (ret < 0) goto done; } if ((*ops)->validate) { ret = (*(*ops)->validate) ( (struct Ip_nlattr**) rta, (struct Ip_nlattr**) linkdata); if (ret < 0) goto done; } } } done: if (linkinfo) ipcom_free(linkinfo); return ret; } IP_STATIC int ipnet_rtnetlink_link_setlink_family_linkops(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlmsg, struct Ip_rtattr **rta, int family, struct Ip_rtnl_link_ops *ops, struct Ip_rtattr **linkdata) { /**/ struct Ip_ifinfomsg *ifm; char *ifname = IP_NULL; Ipnet_netif *netif = IP_NULL; struct Ip_ifreq ifreq; int ret = 0; Ip_u16 vr; (void) family; /* Copy or zero */ ifname = ipnet_netlink_strdup((struct Ip_nlattr *)rta[IP_IFLA_IFNAME - 1]); ifm = IP_NLMSG_DATA(nlmsg); vr = ipnet_rtnetlink_vr(rta[IP_IFLA_VR - 1], mem->vr); if (ifm->ifi_index > 0) netif = ipnet_if_indextonetif(vr, (Ip_u32) ifm->ifi_index); else if (ifname) netif = ipnet_if_nametonetif(vr, ifname); /* Didnt find the device? */ if (netif == IP_NULL) { ret = -IP_ERRNO_ENODEV; goto done; } if (linkdata != IP_NULL && ops->changelink == IP_NULL) { ret = -IP_ERRNO_EOPNOTSUPP; goto done; } ipcom_strcpy(ifreq.ifr_name, netif->ipcom.name); /* Device address */ if (rta[IP_IFLA_ADDRESS - 1]) { if (IP_RTA_PAYLOAD(rta[IP_IFLA_ADDRESS - 1]) != netif->ipcom.link_addr_size) { ret = -IP_ERRNO_EINVAL; goto done; } if (ipcom_memcmp(IP_RTA_DATA(rta[IP_IFLA_ADDRESS - 1]), netif->ipcom.link_addr, netif->ipcom.link_addr_size)) { ipcom_memcpy(ifreq.ifr_ifru.ifru_addr.sa_data, IP_RTA_DATA(rta[IP_IFLA_ADDRESS - 1]), IP_RTA_PAYLOAD(rta[IP_IFLA_ADDRESS - 1])); ret = ipnet_if_link_ioctl(netif, IP_SIOCSIFLLADDR, &ifreq); if (ret < 0) goto done; IP_BIT_SET(netif->flags2, IPNET_IFF2_RTNETLINK_EVENT); } } #ifdef IPNET_USE_BOND if ((IP_BIT_ISSET(ifm->ifi_flags, IP_IFF_SLAVE) && IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_SLAVE)) || (IP_BIT_ISFALSE(ifm->ifi_flags, IP_IFF_SLAVE) && IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_SLAVE))) { /* Bonding operation */ if (IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_SLAVE)) { /* Enslave this netif to an link aggregation */ if (rta[IP_IFLA_MASTER -1]) { Ipnet_netif *master; Ip_u32 ifindex; ipcom_memcpy(&ifindex, IP_RTA_DATA(rta[IP_IFLA_MASTER - 1]), sizeof(Ip_u32)); master = ipnet_if_indextonetif(vr, ifindex); if (master == IP_NULL) { /* Master interface not found */ ret = -IP_ERRNO_ENODEV; goto done; } ret = ipnet_bond_if_enslave(master, netif); if (ret < 0) goto done; } else { /* Can not enslave without master */ ret = -IP_ERRNO_ENODEV; goto done; } } else { /* Release this netif from an link aggregation */ ret = ipnet_bond_if_release(netif); if (ret < 0) goto done; } } #endif /* IPNET_USE_BOND */ if (rta[IP_IFLA_MTU - 1]) { ifreq.ifr_ifru.ifru_mtu = (int) IP_GET_32ON8(IP_RTA_DATA(rta[IP_IFLA_MTU - 1])); ret = ipnet_if_link_ioctl(netif, IP_SIOCSIFMTU, &ifreq); if (ret == 0 || ret == -IP_ERRNO_EOPNOTSUPP || ret == -IP_ERRNO_EINVAL) { /* * ioctl either successful, or not supported by the link * layer (IP_ERRNO_EOPNOSUPP) or by the driver * (IP_ERRNO_EINVAL). The 2 errors are accepted since that * is how setting the MTU used to work, i.e. no * notification to the driver at all. * The driver has to be notifed on VxWorks to enable * Ethernet jumbograms (9k frames). */ if (netif->ipcom.mtu != (Ip_u32) ifreq.ifr_ifru.ifru_mtu) { netif->ipcom.mtu = (Ip_u32) ifreq.ifr_ifru.ifru_mtu; /* * Must flush the destination cache in order to * handle the re-evaluation of path mtu properly */ ipnet_dst_cache_flush(netif->vr_index, 0); IP_BIT_SET(netif->flags2, IPNET_IFF2_RTNETLINK_EVENT); } ret = 0; } if (ret < 0) goto done; } if (ifm->ifi_flags || ifm->ifi_change) { ret = ipnet_netif_change_flags(&netif, ifm->ifi_flags, ifm->ifi_change); if (!netif) goto done; } if (linkdata) { ret = (*ops->changelink) (netif, (struct Ip_nlattr**)rta, (struct Ip_nlattr**)linkdata); if (ret < 0) goto done; } if (IP_BIT_ISSET(netif->flags2, IPNET_IFF2_RTNETLINK_EVENT)) ipnet_rtnetlink_link_change(netif); done: if (ifname) ipcom_free(ifname); return ret; } /* *=========================================================================== * ipnet_rtnetlink_link_setlink *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipnet_rtnetlink_link_setlink_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlmsg, struct Ip_rtattr **rta, int family) { struct Ip_rtattr **linkdata = IP_NULL; struct Ip_rtnl_link_ops *ops = IP_NULL; int ret = 0; if (0 > (ret = ipnet_rtnetlink_link_parse_linkops(rta, &ops, &linkdata))) goto done; ret = ipnet_rtnetlink_link_setlink_family_linkops(mem, nlmsg, rta, family, ops, linkdata); done: if (linkdata) ipcom_free(linkdata); return ret; } /* *=========================================================================== * ipnet_rtnetlink_link_setlink *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipnet_rtnetlink_link_newlink_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlmsg, struct Ip_rtattr **rta, int family) { /**/ struct Ip_ifinfomsg *ifm; char *ifname = IP_NULL; Ipnet_netif *netif = IP_NULL; struct Ip_rtattr **linkdata = IP_NULL; int ret = 0; struct Ip_rtnl_link_ops *ops = IP_NULL; Ipnet_netif *nif = IP_NULL; Ip_u16 vr; /* Copy or zero */ ifname = ipnet_netlink_strdup((struct Ip_nlattr *)rta[IP_IFLA_IFNAME - 1]); ifm = IP_NLMSG_DATA(nlmsg); vr = ipnet_rtnetlink_vr(rta[IP_IFLA_VR - 1], mem->vr); if (ifm->ifi_index > 0) netif = ipnet_if_indextonetif(vr, (Ip_u32) ifm->ifi_index); else if (ifname) netif = ipnet_if_nametonetif(vr, ifname); if (0 > (ret = ipnet_rtnetlink_link_parse_linkops(rta, &ops, &linkdata))) goto done; /* Didnt find the device? */ if (netif != IP_NULL) { if (nlmsg->nlmsg_flags & IP_NLM_F_EXCL) { ret = -IP_ERRNO_EEXIST; goto done; } if (nlmsg->nlmsg_flags & IP_NLM_F_REPLACE) { ret = -IP_ERRNO_EOPNOTSUPP; goto done; } /* Do setlink */ ret = ipnet_rtnetlink_link_setlink_family_linkops(mem, nlmsg, rta, family, ops, linkdata); } else { if (ops == IP_NULL || ops->newlink == IP_NULL) { #ifdef IPCOM_FORWARDER_NAE ops = ipnet_rtnetlink_get_ops("nae_shadow"); if (IP_NULL == ops) { ret = -IP_ERRNO_EOPNOTSUPP; goto done; } #else ret = -IP_ERRNO_EOPNOTSUPP; goto done; #endif } #ifndef IPCOM_FORWARDER_NAE /* Control node has likely specified an interface index to use */ if (!(nlmsg->nlmsg_flags & IP_NLM_F_CREATE) || ifm->ifi_index) { ret = -IP_ERRNO_ENODEV; goto done; } #endif /* OK - We need to create the correct interface here */ nif = (Ipnet_netif *)ipcom_if_malloc(ops->ift_type); if (!nif) { ret = -IP_ERRNO_ENOMEM; goto done; } /**/ nif->vr_index = vr; #if IPCOM_VR_MAX > 1 /* Must switch the effective VR - Or we'll fail config */ ipnet->effective_vr = vr; #endif #ifdef IPCOM_FORWARDER_NAE /* Control node has specified an interface index to use */ if (ifm->ifi_index > 0) nif->ipcom.ifindex = ifm->ifi_index; #endif /* IPCOM_FORWARDER_NAE */ /* Find a valid interface name */ if (!ifname) { char tmpif[IP_IFNAMSIZ + 1]; int i; /**/ for (i = 0; i < 1024; i++) { ipcom_snprintf(tmpif, sizeof(tmpif), "%s%d", ops->kind, i); if (!ipnet_if_nametonetif(vr, tmpif)) { ifname = ipcom_strdup(tmpif); break; } } } if (!ifname) { ret = -IP_ERRNO_ENOMEM; goto done; } /* Store name */ ipcom_strncpy(nif->ipcom.name, ifname, IP_IFNAMSIZ); /* Do we have the setup callback? */ if (ops->setup) { /* We've gotten an interface; invoke setup routine */ (*ops->setup) (nif); } /* Store MTU, if specified */ if (rta[IP_IFLA_MTU - 1]) nif->ipcom.mtu = (Ip_u32) IP_GET_32ON8(IP_RTA_DATA(rta[IP_IFLA_MTU - 1])); /* Successful creation? Dont allow the cleanup routine to destroy nif */ if ((ret = (*ops->newlink) (nif, (struct Ip_nlattr**)rta, (struct Ip_nlattr**)linkdata)) >= 0) { /* Do the extranous paramters, but no link ops */ ret = ipnet_rtnetlink_link_setlink_family_linkops(mem, nlmsg, rta, family, IP_NULL, IP_NULL); nif = IP_NULL; } } done: if (ifname) ipcom_free(ifname); if (linkdata) ipcom_free(linkdata); if (nif) IPNET_IF_UNLOCK(nif); return ret; } /* *=========================================================================== * ipnet_rtnetlink_link_setlink *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipnet_rtnetlink_link_getlink_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlmsg, struct Ip_rtattr **rta, int family) { /**/ struct Ip_ifinfomsg *ifm; char *ifname = IP_NULL; Ipnet_netif *netif = IP_NULL; int ret = 0; Ip_u16 vr; (void)family; ifm = IP_NLMSG_DATA(nlmsg); vr = ipnet_rtnetlink_vr(rta[IP_IFLA_VR - 1], mem->vr); if (ifm->ifi_index > 0) netif = ipnet_if_indextonetif(vr, (Ip_u32) ifm->ifi_index); else if ((ifname = ipnet_netlink_strdup((struct Ip_nlattr *)rta[IP_IFLA_IFNAME - 1])) != IP_NULL) netif = ipnet_if_nametonetif(vr, ifname); /* Didnt find the device? */ if (netif == IP_NULL) { ret = -IP_ERRNO_ENODEV; goto done; } /* */ IPNET_IF_LOCK(netif); ret = ipnet_rtnetlink_link_sz_fillifinfo(mem, IP_RTM_NEWLINK, 0, nlmsg->nlmsg_seq, 0xFFFFFFFF, netif); IPNET_IF_UNLOCK(netif); done: if (ifname) ipcom_free(ifname); return ret; } /* *=========================================================================== * ipnet_rtnetlink_link_dellink_family *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipnet_rtnetlink_link_dellink_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlmsg, struct Ip_rtattr **rta, int family) { /**/ struct Ip_ifinfomsg *ifm; char *ifname = IP_NULL; Ipnet_netif *netif = IP_NULL; int ret = 0; Ip_u16 vr; (void) family; /* Copy or zero */ ifname = ipnet_netlink_strdup((struct Ip_nlattr *)rta[IP_IFLA_IFNAME - 1]); ifm = IP_NLMSG_DATA(nlmsg); vr = ipnet_rtnetlink_vr(rta[IP_IFLA_VR - 1], mem->vr); if (ifm->ifi_index > 0) netif = ipnet_if_indextonetif(vr, (Ip_u32) ifm->ifi_index); else if (ifname) netif = ipnet_if_nametonetif(vr, ifname); /* Didnt find the device? */ if (netif == IP_NULL) { ret = -IP_ERRNO_ENODEV; goto done; } if (netif->rtnetlink_ops == IP_NULL || netif->rtnetlink_ops->dellink == IP_NULL) { ret = -IP_ERRNO_EOPNOTSUPP; goto done; } (*netif->rtnetlink_ops->dellink) (netif); done: if (ifname) ipcom_free(ifname); return ret; } #endif /* IPNET_USE_NETLINKSOCK */ /* *=========================================================================== * ipnet_rtnetlink_link_if_change *=========================================================================== * Description: Status of a network interface has changed, create a IFINFO * event on NETLNK.. * Parameters: netif - The interface. * Returns: - * */ IP_STATIC void ipnet_rtnetlink_link_if_event(Ipnet_netif *netif, int event) { #ifdef IPNET_USE_NETLINKSOCK Ipcom_pkt *pkt = IP_NULL; Ipnet_netlink_mem_t mem; int ret; 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 = netif->vr_index; ret = ipnet_rtnetlink_link_sz_fillifinfo(&mem, event, 0, 0, netif->rtnetlink_last_iflags ^ netif->ipcom.flags, netif); if (ret < 0) ipcom_pkt_free(pkt); else { pkt->end += ret; IP_BIT_CLR(netif->flags2, IPNET_IFF2_RTNETLINK_EVENT); /* Remember current link flags */ netif->rtnetlink_last_iflags = netif->ipcom.flags; /* We're done; do report this pkt */ ipnet_rtnetlink_broadcast(pkt, IP_RTNLGRP_LINK); } #else (void)netif; #endif } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipnet_rtnetlink_link_change(struct Ipnet_netif_struct *netif) { ipnet_rtnetlink_link_if_event(netif, IP_RTM_NEWLINK); } IP_GLOBAL void ipnet_rtnetlink_link_add(struct Ipnet_netif_struct *netif) { ipnet_rtnetlink_link_if_event(netif, IP_RTM_NEWLINK); } IP_GLOBAL void ipnet_rtnetlink_link_delete(struct Ipnet_netif_struct *netif) { ipnet_rtnetlink_link_if_event(netif, IP_RTM_DELLINK); } IP_GLOBAL void ipnet_rtnetlink_link_init(void) { #ifdef IPNET_USE_NETLINKSOCK /* AF_UNSPEC */ ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_DELLINK, IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg), ipnet_rtnetlink_link_dellink_family, IP_NULL); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_NEWLINK, IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg), ipnet_rtnetlink_link_newlink_family, IP_NULL); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_SETLINK, IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg), ipnet_rtnetlink_link_setlink_family, IP_NULL); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETLINK, IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg), ipnet_rtnetlink_link_getlink_family, ipnet_rtnetlink_link_dump_family); #endif /* IPNET_USE_NETLINKSOCK */ ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETADDR, IP_IFA_MAX, sizeof(struct Ip_ifaddrmsg), IP_NULL, ipnet_rtnetlink_link_dump_all); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETMULTICAST, IP_IFA_MAX, sizeof(struct Ip_ifaddrmsg), IP_NULL, ipnet_rtnetlink_link_dump_all); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETANYCAST, IP_IFA_MAX, sizeof(struct Ip_ifaddrmsg), IP_NULL, ipnet_rtnetlink_link_dump_all); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETROUTE, IP_RTA_MAX, sizeof(struct Ip_rtmsg), IP_NULL, ipnet_rtnetlink_link_dump_all); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETRULE, IP_RTA_MAX, sizeof(struct Ip_rtmsg), IP_NULL, ipnet_rtnetlink_link_dump_all); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETNEIGH, IP_NDA_MAX, sizeof(struct Ip_ndmsg), IP_NULL, ipnet_rtnetlink_link_dump_all); #if defined(IPNET_USE_VLAN) && defined(IPNET_USE_NETLINKSOCK) ipnet_vlan_rtnetlink_init(); #endif /* IPNET_USE_VLAN && IPNET_USE_NETLINKSOCK */ #if defined(IPNET_USE_BOND) && defined(IPNET_USE_NETLINKSOCK) ipnet_bond_rtnetlink_init(); #endif /* IPNET_USE_VLAN && IPNET_USE_NETLINKSOCK */ #ifdef IPCOM_FORWARDER_NAE ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETFWCACHE, IP_FWC_MAX, sizeof(struct Ip_fwcmsg), IP_NULL, ipnet_rtnetlink_link_dump_all); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETNAE, IP_NAE_MAX, sizeof(struct Ip_naemsg), ipnet_rtnetlink_nae_getnae_family, IP_NULL); ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_SETNAE, IP_NAE_MAX, sizeof(struct Ip_naemsg), ipnet_rtnetlink_nae_setnae_family, IP_NULL); ipnet_nae_rtnetlink_init(); #endif #ifdef IPCOM_USE_FORWARDER_IPSEC ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETSACACHE, IP_SAC_MAX, sizeof(struct Ip_sacmsg), IP_NULL, ipnet_rtnetlink_link_dump_all); #endif /* Init the neigh module */ ipnet_rtnetlink_vr_init(); #ifdef IPMIP ipmip_rtnetlink_init(); #endif #ifdef IPCOM_USE_FORWARDER_VLAN_STACKING /* register VLAN stacking netlink msg handler */ ipnet_svlan_rtnetlink_init(); #endif #ifdef IPCOM_USE_TCP iptcp_ao_rtnetlink_init(); #endif } #endif /* IPNET_USE_NETLINK */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */