/** * nm_netlink_foreach_route: * @ifindex: the interface index to filter routes for * @family: the address family to filter routes for * @scope: route scope, eg RT_SCOPE_LINK * @ignore_inet6_ll_mc: if %TRUE ignore IPv6 link-local and multi-cast routes * @callback: function called when a route matches the filter * @user_data: data passed to @callback * * Filters each route in the routing table against the given @ifindex and * @family (if given) and calls @callback for each matching route. * * Returns: a route if @callback returned one; the caller must dispose of the * route using rtnl_route_put() when it is no longer required. **/ struct rtnl_route * nm_netlink_foreach_route (int ifindex, int family, int scope, gboolean ignore_inet6_ll_mc, NlRouteForeachFunc callback, gpointer user_data) { struct nl_cache *cache; ForeachRouteInfo info; memset (&info, 0, sizeof (info)); info.ifindex = ifindex; info.family = family; info.scope = scope; info.ignore_inet6_ll_mc = ignore_inet6_ll_mc; info.callback = callback; info.user_data = user_data; info.iface = nm_netlink_index_to_iface (ifindex); rtnl_route_alloc_cache (nm_netlink_get_default_handle (), family, 0, &cache); g_warn_if_fail (cache != NULL); if (cache) { nl_cache_foreach (cache, foreach_route_cb, &info); nl_cache_free (cache); } g_free (info.iface); return info.out_route; }
static void nm_ip6_manager_init (NMIP6Manager *manager) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) nm_ip6_device_destroy); priv->monitor = nm_netlink_monitor_get (); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_ROUTE, NULL); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL); priv->netlink_id = g_signal_connect (priv->monitor, "notification", G_CALLBACK (netlink_notification), manager); priv->nlh = nm_netlink_get_default_handle (); rtnl_addr_alloc_cache (priv->nlh, &priv->addr_cache); g_warn_if_fail (priv->addr_cache != NULL); rtnl_route_alloc_cache (priv->nlh, NETLINK_ROUTE, NL_AUTO_PROVIDE, &priv->route_cache); g_warn_if_fail (priv->route_cache != NULL); }
/** * nm_netlink_route_delete: * @route: the route to delete * * Returns: %TRUE if the request was successful, %FALSE if it failed **/ gboolean nm_netlink_route_delete (struct rtnl_route *route) { struct nl_sock *nlh; int err = 0; g_return_val_if_fail (route != NULL, FALSE); nlh = nm_netlink_get_default_handle (); err = rtnl_route_delete (nlh, route, 0); if (err) nm_log_dbg (LOGD_IP4 | LOGD_IP6, "%s (%d)", nl_geterror(err), err); /* Workaround libnl BUG: ESRCH is aliased to generic NLE_FAILURE * See: http://git.kernel.org/?p=libs/netlink/libnl.git;a=commit;h=7e9d5f */ if (err == -NLE_FAILURE) err = -NLE_OBJ_NOTFOUND; return (err && (err != -NLE_OBJ_NOTFOUND) && (err != -NLE_RANGE) ) ? FALSE : TRUE; }
/** * nm_netlink_find_address: * @ifindex: interface index * @family: address family, either AF_INET or AF_INET6 * @addr: binary address, either struct in_addr* or struct in6_addr* * @prefix: prefix length * * Searches for a matching address on the given interface. * * Returns: %TRUE if the given address was found on the interface, %FALSE if it * was not found or an error occurred. **/ gboolean nm_netlink_find_address (int ifindex, int family, void *addr, /* struct in_addr or struct in6_addr */ int prefix) { struct nl_sock *nlh = NULL; struct nl_cache *cache = NULL; FindAddrInfo info; g_return_val_if_fail (ifindex > 0, FALSE); g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); g_return_val_if_fail (addr != NULL, FALSE); g_return_val_if_fail (prefix >= 0, FALSE); memset (&info, 0, sizeof (info)); info.ifindex = ifindex; info.family = family; info.prefix = prefix; info.addr = addr; if (family == AF_INET) info.addrlen = sizeof (struct in_addr); else if (family == AF_INET6) info.addrlen = sizeof (struct in6_addr); else g_assert_not_reached (); nlh = nm_netlink_get_default_handle (); if (nlh) { rtnl_addr_alloc_cache(nlh, &cache); if (cache) { nl_cache_mngt_provide (cache); nl_cache_foreach (cache, find_one_address, &info); nl_cache_free (cache); } } return info.found; }
/** * _route_add: * @route: the route to add * @family: address family, either %AF_INET or %AF_INET6 * @dest: the route destination address, either a struct in_addr or a struct * in6_addr depending on @family * @dest_prefix: the CIDR prefix of @dest * @gateway: the gateway through which to reach @dest, if any; given as a * struct in_addr or struct in6_addr depending on @family * @flags: flags to pass to rtnl_route_add(), eg %NLM_F_REPLACE * * Returns: zero if succeeded or the netlink error otherwise. **/ static int _route_add (struct rtnl_route *route, int family, const void *dest, /* in_addr or in6_addr */ int dest_prefix, const void *gateway, /* in_addr or in6_addr */ int flags) { struct nl_sock *sk; struct nl_addr *dest_addr, *gw_addr; void *tmp_addr; int addrlen, err, log; if (family == AF_INET) { addrlen = sizeof (struct in_addr); log = LOGD_IP4; } else if (family == AF_INET6) { addrlen = sizeof (struct in6_addr); log = LOGD_IP6; } else g_assert_not_reached (); sk = nm_netlink_get_default_handle (); /* Build up the destination address */ if (dest) { /* Copy to preserve const */ tmp_addr = g_malloc0 (addrlen); memcpy (tmp_addr, dest, addrlen); dest_addr = nl_addr_build (family, tmp_addr, addrlen); g_free (tmp_addr); g_return_val_if_fail (dest_addr != NULL, -NLE_INVAL); nl_addr_set_prefixlen (dest_addr, dest_prefix); rtnl_route_set_dst (route, dest_addr); nl_addr_put (dest_addr); } /* Build up the gateway address */ if (gateway) { tmp_addr = g_malloc0 (addrlen); memcpy (tmp_addr, gateway, addrlen); gw_addr = nl_addr_build (family, tmp_addr, addrlen); g_free (tmp_addr); if (gw_addr) { nl_addr_set_prefixlen (gw_addr, 0); rtnl_route_set_gateway (route, gw_addr); rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); nl_addr_put (gw_addr); } else nm_log_err (LOGD_DEVICE | log, "Invalid gateway"); } err = rtnl_route_add (sk, route, flags); /* LIBNL Bug: Aliased ESRCH */ if (err == -NLE_FAILURE) err = -NLE_OBJ_NOTFOUND; return err; }