static gboolean link_add (NMPlatform *platform, const char *name, NMLinkType type) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformLink device; LinkAddedInfo *info; link_init (&device, priv->links->len, type, name); g_array_append_val (priv->links, device); if (device.link.ifindex) { /* Platform requires LINK_ADDED signal emission from an idle handler */ info = g_new0 (LinkAddedInfo, 1); info->platform = platform; info->ifindex = device.link.ifindex; info->id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, link_added_emit, info, g_free); priv->link_added_ids = g_slist_prepend (priv->link_added_ids, GUINT_TO_POINTER (info->id)); } return TRUE; }
static GArray * ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); GArray *routes; NMPlatformIP4Route *route; guint i; g_return_val_if_fail (NM_IN_SET (mode, NM_PLATFORM_GET_ROUTE_MODE_ALL, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT), NULL); routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route)); /* Fill routes */ for (i = 0; i < priv->ip4_routes->len; i++) { route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); if (route && (!ifindex || route->ifindex == ifindex)) { if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { if (mode != NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT) g_array_append_val (routes, *route); } else { if (mode != NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT) g_array_append_val (routes, *route); } } } return routes; }
static void nm_fake_platform_finalize (GObject *object) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (object); int i; GSList *iter; for (iter = priv->link_added_ids; iter; iter = iter->next) g_source_remove (GPOINTER_TO_UINT (iter->data)); g_slist_free (priv->link_added_ids); g_hash_table_unref (priv->options); for (i = 0; i < priv->links->len; i++) { NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); g_bytes_unref (device->address); g_free (device->udi); } g_array_unref (priv->links); g_array_unref (priv->ip4_addresses); g_array_unref (priv->ip6_addresses); g_array_unref (priv->ip4_routes); g_array_unref (priv->ip6_routes); G_OBJECT_CLASS (nm_fake_platform_parent_class)->finalize (object); }
static char * sysctl_get (NMPlatform *platform, const char *path) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); return g_strdup (g_hash_table_lookup (priv->options, path)); }
static GArray * ip6_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); GArray *routes; NMPlatformIP6Route *route; int count = 0, i; /* Count routes */ for (i = 0; i < priv->ip6_routes->len; i++) { route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); if (route && route->ifindex == ifindex) count++; } routes = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Route), count); /* Fill routes */ for (i = 0; i < priv->ip6_routes->len; i++) { route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); if (route && route->ifindex == ifindex) { if (route->plen != 0 || include_default) g_array_append_val (routes, *route); } } return routes; }
static GArray * ip6_address_get_all (NMPlatform *platform, int ifindex) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); GArray *addresses; NMPlatformIP6Address *address; int count = 0, i; /* Count addresses */ for (i = 0; i < priv->ip6_addresses->len; i++) { address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); if (address && address->ifindex == ifindex) count++; } addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Address), count); /* Fill addresses */ count = 0; for (i = 0; i < priv->ip6_addresses->len; i++) { address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); if (address && address->ifindex == ifindex) g_array_append_val (addresses, *address); } return addresses; }
static gboolean sysctl_set (NMPlatform *platform, const char *path, const char *value) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); g_hash_table_insert (priv->options, g_strdup (path), g_strdup (value)); return TRUE; }
static void nm_fake_platform_init (NMFakePlatform *fake_platform) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (fake_platform); priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); priv->links = g_array_new (TRUE, TRUE, sizeof (NMFakePlatformLink)); priv->ip4_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Address)); priv->ip6_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Address)); priv->ip4_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route)); priv->ip6_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route)); }
static GArray * link_get_all (NMPlatform *platform) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); GArray *links = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformLink), priv->links->len); int i; for (i = 0; i < priv->links->len; i++) if (g_array_index (priv->links, NMFakePlatformLink, i).link.ifindex) g_array_append_val (links, g_array_index (priv->links, NMFakePlatformLink, i).link); return links; }
static gboolean link_added_emit (gpointer user_data) { LinkAddedInfo *info = user_data; NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (info->platform); NMFakePlatformLink *device; priv->link_added_ids = g_slist_remove (priv->link_added_ids, GUINT_TO_POINTER (info->id)); device = link_get (info->platform, info->ifindex); g_assert (device); g_signal_emit_by_name (info->platform, NM_PLATFORM_LINK_ADDED, info->ifindex, &device->link, NM_PLATFORM_REASON_INTERNAL); return FALSE; }
static gboolean ip4_address_exists (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); int i; for (i = 0; i < priv->ip4_addresses->len; i++) { NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); if (address->ifindex == ifindex && address->plen == plen && address->address == addr) return TRUE; } return FALSE; }
static int link_get_ifindex (NMPlatform *platform, const char *name) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); int i; for (i = 0; i < priv->links->len; i++) { NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); if (device && !g_strcmp0 (device->link.name, name)) return device->link.ifindex; } return 0; }
static gboolean link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformLink device; link_init (&device, priv->links->len, type, name); g_array_append_val (priv->links, device); if (device.link.ifindex) g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device.link.ifindex, &device, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); return TRUE; }
static gboolean ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); int i; for (i = 0; i < priv->ip6_addresses->len; i++) { NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); if (address->ifindex == ifindex && address->plen == plen && IN6_ARE_ADDR_EQUAL (&address->address, &addr)) return TRUE; } return FALSE; }
static NMPlatformIP6Route * ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); int i; for (i = 0; i < priv->ip6_routes->len; i++) { NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); if (route->ifindex == ifindex && IN6_ARE_ADDR_EQUAL (&route->network, &network) && route->plen == plen && route->metric == metric) return route; } return NULL; }
static NMPlatformIP4Route * ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); int i; for (i = 0; i < priv->ip4_routes->len; i++) { NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); if (route->ifindex == ifindex && route->network == network && route->plen == plen && route->metric == metric) return route; } return NULL; }
static NMFakePlatformLink * link_get (NMPlatform *platform, int ifindex) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformLink *device; if (ifindex >= priv->links->len) goto not_found; device = &g_array_index (priv->links, NMFakePlatformLink, ifindex); if (!device->link.ifindex) goto not_found; return device; not_found: debug ("link not found: %d", ifindex); platform->error = NM_PLATFORM_ERROR_NOT_FOUND; return NULL; }
static gboolean link_delete (NMPlatform *platform, int ifindex) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformLink *device = link_get (platform, ifindex); NMPlatformLink deleted_device; int i; if (!device || !device->link.ifindex) return FALSE; memcpy (&deleted_device, &device->link, sizeof (deleted_device)); memset (&device->link, 0, sizeof (device->link)); /* Remove addresses and routes which belong to the deleted interface */ for (i = 0; i < priv->ip4_addresses->len; i++) { NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); if (address->ifindex == ifindex) memset (address, 0, sizeof (*address)); } for (i = 0; i < priv->ip6_addresses->len; i++) { NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); if (address->ifindex == ifindex) memset (address, 0, sizeof (*address)); } for (i = 0; i < priv->ip4_routes->len; i++) { NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); if (route->ifindex == ifindex) memset (route, 0, sizeof (*route)); } for (i = 0; i < priv->ip6_routes->len; i++) { NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); if (route->ifindex == ifindex) memset (route, 0, sizeof (*route)); } g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, ifindex, &deleted_device, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); return TRUE; }
static gboolean ip4_address_add (NMPlatform *platform, int ifindex, in_addr_t addr, in_addr_t peer_addr, int plen, guint32 lifetime, guint32 preferred, const char *label) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMPlatformIP4Address address; int i; memset (&address, 0, sizeof (address)); address.source = NM_IP_CONFIG_SOURCE_KERNEL; address.ifindex = ifindex; address.address = addr; address.peer_address = peer_addr; address.plen = plen; address.timestamp = nm_utils_get_monotonic_timestamp_s (); address.lifetime = lifetime; address.preferred = preferred; if (label) g_strlcpy (address.label, label, sizeof (address.label)); for (i = 0; i < priv->ip4_addresses->len; i++) { NMPlatformIP4Address *item = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); if (item->ifindex != address.ifindex) continue; if (item->address != address.address) continue; if (item->plen != address.plen) continue; memcpy (item, &address, sizeof (address)); g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); return TRUE; } g_array_append_val (priv->ip4_addresses, address); g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, ifindex, &address, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); return TRUE; }
static void nm_fake_platform_finalize (GObject *object) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (object); int i; g_hash_table_unref (priv->options); for (i = 0; i < priv->links->len; i++) { NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); g_bytes_unref (device->address); g_free (device->udi); } g_array_unref (priv->links); g_array_unref (priv->ip4_addresses); g_array_unref (priv->ip6_addresses); g_array_unref (priv->ip4_routes); g_array_unref (priv->ip6_routes); G_OBJECT_CLASS (nm_fake_platform_parent_class)->finalize (object); }
static gboolean ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); int i; for (i = 0; i < priv->ip4_addresses->len; i++) { NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); if (address->ifindex == ifindex && address->plen == plen && address->address == addr) { NMPlatformIP4Address deleted_address; memcpy (&deleted_address, address, sizeof (deleted_address)); memset (address, 0, sizeof (*address)); g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ADDRESS_REMOVED, ifindex, &deleted_address, NM_PLATFORM_REASON_INTERNAL); return TRUE; } } return TRUE; }
static gboolean ip6_address_add (NMPlatform *platform, int ifindex, struct in6_addr addr, struct in6_addr peer_addr, int plen, guint32 lifetime, guint32 preferred, guint flags) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMPlatformIP6Address address; int i; memset (&address, 0, sizeof (address)); address.ifindex = ifindex; address.address = addr; address.peer_address = peer_addr; address.plen = plen; address.timestamp = nm_utils_get_monotonic_timestamp_s (); address.lifetime = lifetime; address.preferred = preferred; address.flags = flags; for (i = 0; i < priv->ip6_addresses->len; i++) { NMPlatformIP6Address *item = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); if (item->ifindex != address.ifindex) continue; if (!IN6_ARE_ADDR_EQUAL (&item->address, &address.address)) continue; if (item->plen != address.plen) continue; memcpy (item, &address, sizeof (address)); g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ADDRESS_CHANGED, ifindex, &address, NM_PLATFORM_REASON_INTERNAL); return TRUE; } g_array_append_val (priv->ip6_addresses, address); g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ADDRESS_ADDED, ifindex, &address, NM_PLATFORM_REASON_INTERNAL); return TRUE; }
static gboolean ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, struct in6_addr network, int plen, struct in6_addr gateway, guint32 metric, guint32 mss) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMPlatformIP6Route route; guint i; memset (&route, 0, sizeof (route)); route.source = NM_IP_CONFIG_SOURCE_KERNEL; route.ifindex = ifindex; route.source = source; route.network = network; route.plen = plen; route.gateway = gateway; route.metric = metric; route.mss = mss; for (i = 0; i < priv->ip6_routes->len; i++) { NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); if (item->ifindex != route.ifindex) continue; if (!IN6_ARE_ADDR_EQUAL (&item->network, &route.network)) continue; if (item->plen != route.plen) continue; memcpy (item, &route, sizeof (route)); g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); return TRUE; } g_array_append_val (priv->ip6_routes, route); g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, ifindex, &route, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); return TRUE; }
static gboolean ip4_route_add (NMPlatform *platform, int ifindex, in_addr_t network, int plen, in_addr_t gateway, int metric, int mss) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMPlatformIP4Route route; guint i; memset (&route, 0, sizeof (route)); route.ifindex = ifindex; route.network = network; route.plen = plen; route.gateway = gateway; route.metric = metric; route.mss = mss; for (i = 0; i < priv->ip4_routes->len; i++) { NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i); if (item->ifindex != route.ifindex) continue; if (item->network != route.network) continue; if (item->plen != route.plen) continue; memcpy (item, &route, sizeof (route)); g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ROUTE_CHANGED, ifindex, &route, NM_PLATFORM_REASON_INTERNAL); return TRUE; } g_array_append_val (priv->ip4_routes, route); g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ROUTE_ADDED, ifindex, &route, NM_PLATFORM_REASON_INTERNAL); return TRUE; }
static void link_changed (NMPlatform *platform, NMFakePlatformLink *device) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); int i; g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device->link.ifindex, &device->link, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); if (device->link.master) { NMFakePlatformLink *master = link_get (platform, device->link.master); g_return_if_fail (master != device); master->link.connected = FALSE; for (i = 0; i < priv->links->len; i++) { NMFakePlatformLink *slave = &g_array_index (priv->links, NMFakePlatformLink, i); if (slave && slave->link.master == master->link.ifindex && slave->link.connected) master->link.connected = TRUE; } link_changed (platform, master); } }