nm-fake-platform.c 43.3 KB
Newer Older
Pavel Šimerda's avatar
Pavel Šimerda committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-platform-fake.c - Fake platform interaction code for testing NetworkManager
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Copyright (C) 2012–2013 Red Hat, Inc.
 */

21
#include "nm-default.h"
22

23 24
#include "nm-fake-platform.h"

Pavel Šimerda's avatar
Pavel Šimerda committed
25 26 27 28
#include <errno.h>
#include <unistd.h>
#include <netinet/icmp6.h>
#include <netinet/in.h>
29
#include <linux/rtnetlink.h>
Pavel Šimerda's avatar
Pavel Šimerda committed
30

31
#include "nm-utils.h"
32 33

#include "nm-core-utils.h"
34
#include "nm-platform-utils.h"
35
#include "nm-platform-private.h"
36
#include "nmp-object.h"
Pavel Šimerda's avatar
Pavel Šimerda committed
37

38
#include "nm-test-utils-core.h"
39

40
/*****************************************************************************/
41

42
typedef struct {
43
	const NMPObject *obj;
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
	char *udi;
	struct in6_addr ip6_lladdr;
} NMFakePlatformLink;

typedef struct {
	GHashTable *options;
	GArray *links;
} NMFakePlatformPrivate;

struct _NMFakePlatform {
	NMPlatform parent;
	NMFakePlatformPrivate _priv;
};

struct _NMFakePlatformClass {
	NMPlatformClass parent;
};

G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM)

#define NM_FAKE_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMFakePlatform, NM_IS_FAKE_PLATFORM)

/*****************************************************************************/

68 69 70 71 72 73 74 75 76 77 78 79
#define _NMLOG_PREFIX_NAME                "platform-fake"
#define _NMLOG_DOMAIN                     LOGD_PLATFORM
#define _NMLOG(level, ...)                _LOG(level, _NMLOG_DOMAIN,  platform, __VA_ARGS__)

#define _LOG(level, domain, self, ...) \
    G_STMT_START { \
        const NMLogLevel __level = (level); \
        const NMLogDomain __domain = (domain); \
        \
        if (nm_logging_enabled (__level, __domain)) { \
            char __prefix[32]; \
            const char *__p_prefix = _NMLOG_PREFIX_NAME; \
80
            NMPlatform *const __self = (self); \
81
            \
82
            if (__self && nm_platform_get_log_with_ptr (self)) { \
83 84 85
                g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
                __p_prefix = __prefix; \
            } \
86
            _nm_log (__level, __domain, 0, NULL, NULL, \
87 88 89 90 91
                     "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
                     __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
        } \
    } G_STMT_END

92
/*****************************************************************************/
Pavel Šimerda's avatar
Pavel Šimerda committed
93

94 95 96 97
static void link_changed (NMPlatform *platform,
                          NMFakePlatformLink *device,
                          NMPCacheOpsType cache_op,
                          const NMPObject *obj_old);
98

99 100 101 102 103 104 105
static gboolean ipx_address_delete (NMPlatform *platform,
                                    int addr_family,
                                    int ifindex,
                                    gconstpointer addr,
                                    const guint8 *plen,
                                    gconstpointer peer_addr);

106 107 108
static gboolean ipx_route_delete (NMPlatform *platform,
                                  int addr_family,
                                  int ifindex,
109
                                  const NMPObject *obj);
110

111 112 113
static gboolean ip6_address_add (NMPlatform *platform,
                                 int ifindex,
                                 struct in6_addr addr,
114
                                 guint8 plen,
115 116 117 118
                                 struct in6_addr peer_addr,
                                 guint32 lifetime,
                                 guint32 preferred,
                                 guint flags);
119
static gboolean ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, guint8 plen);
120

121
/*****************************************************************************/
122

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
#define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \
	G_STMT_START { \
		const char *const _pathid = (pathid); \
		const int _dirfd = (dirfd); \
		const char *const _path = (path); \
		\
		g_assert (_path && _path[0]); \
		g_assert (!strstr (_path, "/../")); \
		if (_dirfd < 0) { \
			g_assert (!_pathid); \
			g_assert (_path[0] == '/'); \
			g_assert (   g_str_has_prefix (_path, "/proc/sys/") \
			          || g_str_has_prefix (_path, "/sys/")); \
		} else { \
			g_assert_not_reached (); \
		} \
	} G_STMT_END

141
static gboolean
142
sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value)
143
{
144
	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
145

146 147
	ASSERT_SYSCTL_ARGS (pathid, dirfd, path);

148 149 150 151 152 153
	g_hash_table_insert (priv->options, g_strdup (path), g_strdup (value));

	return TRUE;
}

static char *
154
sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *path)
155
{
156
	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
157

158 159
	ASSERT_SYSCTL_ARGS (pathid, dirfd, path);

160 161 162
	return g_strdup (g_hash_table_lookup (priv->options, path));
}

163
static NMFakePlatformLink *
Pavel Šimerda's avatar
Pavel Šimerda committed
164 165
link_get (NMPlatform *platform, int ifindex)
{
166
	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
167
	NMFakePlatformLink *device;
168 169 170 171
	int idx;

	if (ifindex <= 0)
		g_return_val_if_reached (NULL);
Pavel Šimerda's avatar
Pavel Šimerda committed
172

173 174
	idx = ifindex - 1;
	if (idx >= priv->links->len)
Pavel Šimerda's avatar
Pavel Šimerda committed
175
		goto not_found;
176 177 178

	device = &g_array_index (priv->links, NMFakePlatformLink, idx);
	if (!device->obj)
Pavel Šimerda's avatar
Pavel Šimerda committed
179 180
		goto not_found;

181 182 183
	g_assert (ifindex == NMP_OBJECT_CAST_LINK (device->obj)->ifindex);
	g_assert (device->obj == nm_platform_link_get_obj (platform, ifindex, FALSE));

Pavel Šimerda's avatar
Pavel Šimerda committed
184 185
	return device;
not_found:
186
	_LOGD ("link not found: %d", ifindex);
Pavel Šimerda's avatar
Pavel Šimerda committed
187 188 189
	return NULL;
}

190 191 192 193
static void
link_add_prepare (NMPlatform *platform,
                  NMFakePlatformLink *device,
                  NMPObject *obj_tmp)
Pavel Šimerda's avatar
Pavel Šimerda committed
194
{
195
	gboolean connected;
Pavel Šimerda's avatar
Pavel Šimerda committed
196

197 198 199
	/* we must clear the driver, because platform cache want's to set it */
	g_assert (obj_tmp->link.driver == g_intern_string (obj_tmp->link.driver));
	obj_tmp->link.driver = NULL;
Pavel Šimerda's avatar
Pavel Šimerda committed
200

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
	if (NM_IN_SET (obj_tmp->link.type, NM_LINK_TYPE_BRIDGE,
	                                   NM_LINK_TYPE_BOND)) {
		connected = FALSE;
		if (NM_FLAGS_HAS (obj_tmp->link.n_ifi_flags, IFF_UP)) {
			NMPLookup lookup;
			NMDedupMultiIter iter;
			const NMPObject *slave_candidate = NULL;

			nmp_cache_iter_for_each (&iter,
			                         nmp_cache_lookup (nm_platform_get_cache (platform),
			                                           nmp_lookup_init_obj_type (&lookup,
			                                                                     NMP_OBJECT_TYPE_LINK)),
			                         &slave_candidate) {
				if (nmp_cache_link_connected_for_slave (obj_tmp->link.ifindex, slave_candidate)) {
					connected = TRUE;
					break;
				}
			}
		}
	} else
		connected = NM_FLAGS_HAS (obj_tmp->link.n_ifi_flags, IFF_UP);
222

223 224
	obj_tmp->link.n_ifi_flags = NM_FLAGS_ASSIGN (obj_tmp->link.n_ifi_flags, IFF_LOWER_UP, connected);
	obj_tmp->link.connected = connected;
225 226
}

227 228 229 230 231 232
static NMFakePlatformLink *
link_add_pre (NMPlatform *platform,
              const char *name,
              NMLinkType type,
              const void *address,
              size_t address_len)
233
{
234
	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
235 236 237 238 239
	NMFakePlatformLink *device;
	int ifindex;
	NMPObject *o;
	NMPlatformLink *link;
	gs_free char *ip6_lladdr = NULL;
240

241
	g_assert (!name || strlen (name) < IFNAMSIZ);
242

243 244 245
	g_array_set_size (priv->links, priv->links->len + 1);
	device = &g_array_index (priv->links, NMFakePlatformLink, priv->links->len - 1);
	ifindex = priv->links->len;
246

247
	memset (device, 0, sizeof (*device));
248

249 250
	o = nmp_object_new_link (ifindex);
	link = NMP_OBJECT_CAST_LINK (o);
251

252
	ip6_lladdr = ifindex > 0 ? g_strdup_printf ("fe80::fa1e:%0x:%0x", ifindex / 256, ifindex % 256) : NULL;
253

254 255 256 257 258 259 260 261 262 263 264 265 266
	link->ifindex = name ? ifindex : 0;
	link->type = type;
	link->kind = g_intern_string (nm_link_type_to_string (type));
	link->initialized = TRUE;
	if (name)
		strcpy (link->name, name);
	switch (link->type) {
	case NM_LINK_TYPE_DUMMY:
		link->n_ifi_flags = NM_FLAGS_SET (link->n_ifi_flags, IFF_NOARP);
		break;
	default:
		link->n_ifi_flags = NM_FLAGS_UNSET (link->n_ifi_flags, IFF_NOARP);
		break;
267 268
	}

269
	o->_link.netlink.is_in_netlink = TRUE;
270

271 272 273 274 275 276
	if (address) {
		g_assert (address_len > 0 && address_len <= sizeof (link->addr.data));
		memcpy (link->addr.data, address, address_len);
		link->addr.len = address_len;
	} else
		g_assert (address_len == 0);
277

278 279 280
	device->obj = o;
	device->udi = g_strdup_printf ("fake:%d", ifindex);
	device->ip6_lladdr = *nmtst_inet6_from_string (ip6_lladdr);
281

282
	return device;
283 284
}

Pavel Šimerda's avatar
Pavel Šimerda committed
285
static gboolean
286 287 288
link_add (NMPlatform *platform,
          const char *name,
          NMLinkType type,
289
          const char *veth_peer,
290 291
          const void *address,
          size_t address_len,
292
          const NMPlatformLink **out_link)
Pavel Šimerda's avatar
Pavel Šimerda committed
293
{
294 295 296 297 298 299 300 301
	NMFakePlatformLink *device;
	NMFakePlatformLink *device_veth = NULL;
	nm_auto_nmpobj const NMPObject *obj_old = NULL;
	nm_auto_nmpobj const NMPObject *obj_new = NULL;
	nm_auto_nmpobj const NMPObject *obj_old_veth = NULL;
	nm_auto_nmpobj const NMPObject *obj_new_veth = NULL;
	NMPCacheOpsType cache_op;
	NMPCacheOpsType cache_op_veth = NMP_CACHE_OPS_UNCHANGED;
302

303
	device = link_add_pre (platform, name, type, address, address_len);
Pavel Šimerda's avatar
Pavel Šimerda committed
304

305
	if (veth_peer) {
306 307
		g_assert (type == NM_LINK_TYPE_VETH);
		device_veth = link_add_pre (platform, veth_peer, type, NULL, 0);
308 309 310
	} else
		g_assert (type != NM_LINK_TYPE_VETH);

311 312 313
	link_add_prepare (platform, device, (NMPObject *) device->obj);
	cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
	                                     (NMPObject *) device->obj,
314
	                                     FALSE,
315 316 317 318 319 320 321 322
	                                     &obj_old, &obj_new);
	g_assert (cache_op == NMP_CACHE_OPS_ADDED);
	nmp_object_unref (device->obj);
	device->obj = nmp_object_ref (obj_new);
	if (veth_peer) {
		link_add_prepare (platform, device_veth, (NMPObject *) device_veth->obj);
		cache_op_veth = nmp_cache_update_netlink (nm_platform_get_cache (platform),
		                                          (NMPObject *) device_veth->obj,
323
		                                          FALSE,
324 325 326 327 328
		                                          &obj_old_veth, &obj_new_veth);
		g_assert (cache_op == NMP_CACHE_OPS_ADDED);
		nmp_object_unref (device->obj);
		device->obj = nmp_object_ref (obj_new);
	}
329 330

	if (out_link)
331
		*out_link = NMP_OBJECT_CAST_LINK (device->obj);
332

333 334 335
	link_changed (platform, device, cache_op, NULL);
	if (veth_peer)
		link_changed (platform, device_veth, cache_op_veth, NULL);
Pavel Šimerda's avatar
Pavel Šimerda committed
336

337 338
	return TRUE;
}
339

340 341 342 343 344 345 346 347 348 349 350 351 352
static NMFakePlatformLink *
link_add_one (NMPlatform *platform,
              const char *name,
              NMLinkType link_type,
              void (*prepare_fcn) (NMPlatform *platform, NMFakePlatformLink *device, gconstpointer user_data),
              gconstpointer user_data,
              const NMPlatformLink **out_link)
{
	NMFakePlatformLink *device;
	nm_auto_nmpobj const NMPObject *obj_old = NULL;
	nm_auto_nmpobj const NMPObject *obj_new = NULL;
	NMPCacheOpsType cache_op;
	int ifindex;
353

354
	device = link_add_pre (platform, name, NM_LINK_TYPE_VLAN, NULL, 0);
355

356 357 358 359 360 361 362 363
	ifindex = NMP_OBJECT_CAST_LINK (device->obj)->ifindex;

	if (prepare_fcn)
		prepare_fcn (platform, device, user_data);

	link_add_prepare (platform, device, (NMPObject *) device->obj);
	cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
	                                     (NMPObject *) device->obj,
364
	                                     FALSE,
365 366 367 368 369 370 371 372 373 374 375 376 377
	                                     &obj_old, &obj_new);
	g_assert (cache_op == NMP_CACHE_OPS_ADDED);
	nmp_object_unref (device->obj);
	device->obj = nmp_object_ref (obj_new);

	link_changed (platform, device, cache_op, obj_old);

	device = link_get (platform, ifindex);
	if (!device)
		g_assert_not_reached ();

	NM_SET_OUT (out_link, NMP_OBJECT_CAST_LINK (device->obj));
	return device;
Pavel Šimerda's avatar
Pavel Šimerda committed
378 379 380 381 382
}

static gboolean
link_delete (NMPlatform *platform, int ifindex)
{
383
	NMFakePlatformLink *device = link_get (platform, ifindex);
384 385 386
	nm_auto_nmpobj const NMPObject *obj_old = NULL;
	nm_auto_nmpobj const NMPObject *obj_old2 = NULL;
	NMPCacheOpsType cache_op;
Pavel Šimerda's avatar
Pavel Šimerda committed
387

388
	if (!device)
Pavel Šimerda's avatar
Pavel Šimerda committed
389 390
		return FALSE;

391
	obj_old = g_steal_pointer (&device->obj);
392
	g_clear_pointer (&device->udi, g_free);
Pavel Šimerda's avatar
Pavel Šimerda committed
393

394 395 396
	cache_op = nmp_cache_remove (nm_platform_get_cache (platform),
	                             obj_old,
	                             FALSE,
397
	                             FALSE,
398 399 400 401 402
	                             &obj_old2);
	g_assert (cache_op == NMP_CACHE_OPS_REMOVED);
	g_assert (obj_old2);
	g_assert (obj_old == obj_old2);

403
	/* Remove addresses and routes which belong to the deleted interface */
404 405
	ipx_address_delete (platform, AF_INET, ifindex, NULL, NULL, NULL);
	ipx_address_delete (platform, AF_INET6, ifindex, NULL, NULL, NULL);
406 407
	ipx_route_delete (platform, AF_INET, ifindex, NULL);
	ipx_route_delete (platform, AF_INET6, ifindex, NULL);
408

409 410 411 412
	nm_platform_cache_update_emit_signal (platform,
	                                      cache_op,
	                                      obj_old2,
	                                      NULL);
Pavel Šimerda's avatar
Pavel Šimerda committed
413 414 415
	return TRUE;
}

416 417 418 419
static void
link_set_obj (NMPlatform *platform,
              NMFakePlatformLink *device,
              NMPObject *obj_tmp)
420
{
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
	nm_auto_nmpobj const NMPObject *obj_new = NULL;
	nm_auto_nmpobj const NMPObject *obj_old = NULL;
	nm_auto_nmpobj NMPObject *obj_tmp_tmp = NULL;
	NMPCacheOpsType cache_op;

	g_assert (device);
	g_assert (NMP_OBJECT_GET_TYPE (device->obj) == NMP_OBJECT_TYPE_LINK);

	if (!obj_tmp) {
		obj_tmp_tmp = nmp_object_clone (device->obj, FALSE);
		obj_tmp = obj_tmp_tmp;
	}

	g_assert (NMP_OBJECT_GET_TYPE (obj_tmp) == NMP_OBJECT_TYPE_LINK);

	link_add_prepare (platform, device, obj_tmp);
	cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
438 439 440
	                                     obj_tmp,
	                                     FALSE,
	                                     &obj_old, &obj_new);
441 442 443 444 445 446 447 448 449
	g_assert (NM_IN_SET (cache_op, NMP_CACHE_OPS_UNCHANGED,
	                               NMP_CACHE_OPS_UPDATED));
	g_assert (obj_old == device->obj);
	g_assert (obj_new);

	nmp_object_unref (device->obj);
	device->obj = nmp_object_ref (obj_new);

	link_changed (platform, device, cache_op, obj_old);
450 451
}

452
static void
453 454 455
link_set_flags (NMPlatform *platform,
                NMFakePlatformLink *device,
                guint n_ifi_flags)
456
{
457
	nm_auto_nmpobj NMPObject *obj_tmp = NULL;
458

459 460
	g_assert (device);
	g_assert (NMP_OBJECT_GET_TYPE (device->obj) == NMP_OBJECT_TYPE_LINK);
461

462 463 464 465
	obj_tmp = nmp_object_clone (device->obj, FALSE);
	obj_tmp->link.n_ifi_flags = n_ifi_flags;
	link_set_obj (platform, device, obj_tmp);
}
466

467 468 469 470 471 472 473
static void
link_changed (NMPlatform *platform,
              NMFakePlatformLink *device,
              NMPCacheOpsType cache_op,
              const NMPObject *obj_old)
{
	g_assert (device->obj);
474

475 476
	g_assert (!nmp_cache_link_connected_needs_toggle (nm_platform_get_cache (platform),
	                                                  device->obj, NULL, NULL));
477

478 479 480 481
	nm_platform_cache_update_emit_signal (platform,
	                                      cache_op,
	                                      obj_old,
	                                      device->obj);
482

483 484 485 486 487 488
	if (!IN6_IS_ADDR_UNSPECIFIED (&device->ip6_lladdr)) {
		if (device->obj->link.connected)
			ip6_address_add (platform, device->obj->link.ifindex, in6addr_any, 64, device->ip6_lladdr, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0);
		else
			ip6_address_delete (platform, device->obj->link.ifindex, device->ip6_lladdr, 64);
	}
489

490 491
	if (device->obj->link.master) {
		NMFakePlatformLink *master;
492

493 494
		master = link_get (platform, device->obj->link.master);
		link_set_obj (platform, master, NULL);
495
	}
496 497 498
}

static gboolean
499
link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware)
500
{
501
	NMFakePlatformLink *device = link_get (platform, ifindex);
502

503 504 505
	if (out_no_firmware)
		*out_no_firmware = FALSE;

506 507
	if (!device) {
		_LOGE ("failure changing link: netlink error (No such device)");
508
		return FALSE;
509
	}
510

511 512 513
	link_set_flags (platform,
	                device,
	                NM_FLAGS_ASSIGN (device->obj->link.n_ifi_flags, IFF_UP, TRUE));
514 515 516 517 518 519
	return TRUE;
}

static gboolean
link_set_down (NMPlatform *platform, int ifindex)
{
520
	NMFakePlatformLink *device = link_get (platform, ifindex);
521

522 523
	if (!device) {
		_LOGE ("failure changing link: netlink error (No such device)");
524
		return FALSE;
525
	}
526

527 528 529
	link_set_flags (platform,
	                device,
	                NM_FLAGS_UNSET (device->obj->link.n_ifi_flags, IFF_UP));
530 531 532 533 534 535
	return TRUE;
}

static gboolean
link_set_arp (NMPlatform *platform, int ifindex)
{
536
	NMFakePlatformLink *device = link_get (platform, ifindex);
537

538 539
	if (!device) {
		_LOGE ("failure changing link: netlink error (No such device)");
540
		return FALSE;
541
	}
542

543 544 545
	link_set_flags (platform,
	                device,
	                NM_FLAGS_UNSET (device->obj->link.n_ifi_flags, IFF_NOARP));
546 547 548 549 550 551
	return TRUE;
}

static gboolean
link_set_noarp (NMPlatform *platform, int ifindex)
{
552
	NMFakePlatformLink *device = link_get (platform, ifindex);
553

554 555
	if (!device) {
		_LOGE ("failure changing link: netlink error (No such device)");
556
		return FALSE;
557
	}
558

559 560 561
	link_set_flags (platform,
	                device,
	                NM_FLAGS_SET (device->obj->link.n_ifi_flags, IFF_NOARP));
562 563 564
	return TRUE;
}

565
static NMPlatformError
566 567 568
link_set_address (NMPlatform *platform, int ifindex, gconstpointer addr, size_t len)
{
	NMFakePlatformLink *device = link_get (platform, ifindex);
569
	nm_auto_nmpobj NMPObject *obj_tmp = NULL;
570

571
	if (   len == 0
572 573
	    || len > NM_UTILS_HWADDR_LEN_MAX
	    || !addr)
574
		g_return_val_if_reached (NM_PLATFORM_ERROR_BUG);
575

576 577 578 579 580 581 582
	if (!device)
		return NM_PLATFORM_ERROR_EXISTS;

	obj_tmp = nmp_object_clone (device->obj, FALSE);
	obj_tmp->link.addr.len = len;
	memset (obj_tmp->link.addr.data, 0, sizeof (obj_tmp->link.addr.data));
	memcpy (obj_tmp->link.addr.data, addr, len);
583

584
	link_set_obj (platform, device, obj_tmp);
585
	return NM_PLATFORM_ERROR_SUCCESS;
586 587
}

Pavel Šimerda's avatar
Pavel Šimerda committed
588 589 590 591
static gboolean
link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
{
	NMFakePlatformLink *device = link_get (platform, ifindex);
592
	nm_auto_nmpobj NMPObject *obj_tmp = NULL;
Pavel Šimerda's avatar
Pavel Šimerda committed
593

594
	if (!device) {
595
		_LOGE ("failure changing link: netlink error (No such device)");
596 597
		return FALSE;
	}
Pavel Šimerda's avatar
Pavel Šimerda committed
598

599 600 601 602
	obj_tmp = nmp_object_clone (device->obj, FALSE);
	obj_tmp->link.mtu = mtu;
	link_set_obj (platform, device, obj_tmp);
	return TRUE;
Pavel Šimerda's avatar
Pavel Šimerda committed
603 604
}

605 606 607 608 609 610
static gboolean
link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs)
{
	return TRUE;
}

611 612 613 614 615 616 617 618 619 620
static const char *
link_get_udi (NMPlatform *platform, int ifindex)
{
	NMFakePlatformLink *device = link_get (platform, ifindex);

	if (!device)
		return NULL;
	return device->udi;
}

621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
static gboolean
link_get_driver_info (NMPlatform *platform,
                      int ifindex,
                      char **out_driver_name,
                      char **out_driver_version,
                      char **out_fw_version)
{
	if (out_driver_name)
		*out_driver_name = NULL;
	if (out_driver_version)
		*out_driver_version = NULL;
	if (out_fw_version)
		*out_fw_version = NULL;

	return TRUE;
}

638 639 640
static gboolean
link_supports_carrier_detect (NMPlatform *platform, int ifindex)
{
641
	NMFakePlatformLink *device = link_get (platform, ifindex);
642 643 644 645

	if (!device)
		return FALSE;

646
	switch (device->obj->link.type) {
647 648 649 650 651 652 653 654 655 656
	case NM_LINK_TYPE_DUMMY:
		return FALSE;
	default:
		return TRUE;
	}
}

static gboolean
link_supports_vlans (NMPlatform *platform, int ifindex)
{
657
	NMFakePlatformLink *device = link_get (platform, ifindex);
658 659 660 661

	if (!device)
		return FALSE;

662
	switch (device->obj->link.type) {
663 664 665 666 667 668 669
	case NM_LINK_TYPE_LOOPBACK:
		return FALSE;
	default:
		return TRUE;
	}
}

670 671 672 673 674 675 676 677
static gboolean
link_supports_sriov (NMPlatform *platform, int ifindex)
{
	NMFakePlatformLink *device = link_get (platform, ifindex);

	if (!device)
		return FALSE;

678
	switch (device->obj->link.type) {
679 680 681 682 683 684 685
	case NM_LINK_TYPE_LOOPBACK:
		return FALSE;
	default:
		return TRUE;
	}
}

686 687 688
static gboolean
link_enslave (NMPlatform *platform, int master, int slave)
{
689
	NMFakePlatformLink *device = link_get (platform, slave);
690
	NMFakePlatformLink *master_device = link_get (platform, master);
691 692

	g_return_val_if_fail (device, FALSE);
693
	g_return_val_if_fail (master_device, FALSE);
694

695 696
	if (device->obj->link.master != master) {
		nm_auto_nmpobj NMPObject *obj_tmp = NULL;
697

698 699 700 701 702
		obj_tmp = nmp_object_clone (device->obj, FALSE);
		obj_tmp->link.master = master;
		if (NM_IN_SET (master_device->obj->link.type, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM))
			obj_tmp->link.n_ifi_flags = NM_FLAGS_SET (device->obj->link.n_ifi_flags, IFF_UP);
		link_set_obj (platform, device, obj_tmp);
703
	}
704 705 706 707 708 709 710

	return TRUE;
}

static gboolean
link_release (NMPlatform *platform, int master_idx, int slave_idx)
{
711 712
	NMFakePlatformLink *master = link_get (platform, master_idx);
	NMFakePlatformLink *slave = link_get (platform, slave_idx);
713
	nm_auto_nmpobj NMPObject *obj_tmp = NULL;
714 715 716 717

	g_return_val_if_fail (master, FALSE);
	g_return_val_if_fail (slave, FALSE);

718
	if (slave->obj->link.master != master->obj->link.ifindex)
719 720
		return FALSE;

721 722 723
	obj_tmp = nmp_object_clone (slave->obj, FALSE);
	obj_tmp->link.master = 0;
	link_set_obj (platform, slave, obj_tmp);
724 725 726
	return TRUE;
}

727 728 729 730 731
struct vlan_add_data {
	guint32 vlan_flags;
	int parent;
	int vlan_id;
};
Pavel Šimerda's avatar
Pavel Šimerda committed
732

733 734 735 736 737 738 739 740
static void
_vlan_add_prepare (NMPlatform *platform,
                   NMFakePlatformLink *device,
                   gconstpointer user_data)
{
	const struct vlan_add_data *d = user_data;
	NMPObject *obj_tmp;
	NMPObject *lnk;
Pavel Šimerda's avatar
Pavel Šimerda committed
741

742
	obj_tmp = (NMPObject *) device->obj;
Pavel Šimerda's avatar
Pavel Šimerda committed
743

744 745 746
	lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL);
	lnk->lnk_vlan.id = d->vlan_id;
	lnk->lnk_vlan.flags = d->vlan_flags;
Pavel Šimerda's avatar
Pavel Šimerda committed
747

748 749 750
	obj_tmp->link.parent = d->parent;
	obj_tmp->_link.netlink.lnk = lnk;
}
Pavel Šimerda's avatar
Pavel Šimerda committed
751

752 753 754 755 756 757 758 759 760 761 762
static gboolean
vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, const NMPlatformLink **out_link)
{
	const struct vlan_add_data d = {
		.parent = parent,
		.vlan_id = vlan_id,
		.vlan_flags = vlan_flags,
	};

	link_add_one (platform, name, NM_LINK_TYPE_VLAN,
	              _vlan_add_prepare, &d, out_link);
Pavel Šimerda's avatar
Pavel Šimerda committed
763 764 765 766
	return TRUE;
}

static gboolean
767 768 769 770 771 772 773 774 775 776
link_vlan_change (NMPlatform *platform,
                  int ifindex,
                  NMVlanFlags flags_mask,
                  NMVlanFlags flags_set,
                  gboolean ingress_reset_all,
                  const NMVlanQosMapping *ingress_map,
                  gsize n_ingress_map,
                  gboolean egress_reset_all,
                  const NMVlanQosMapping *egress_map,
                  gsize n_egress_map)
Pavel Šimerda's avatar
Pavel Šimerda committed
777
{
778
	return FALSE;
Pavel Šimerda's avatar
Pavel Šimerda committed
779 780
}

781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
static void
_vxlan_add_prepare (NMPlatform *platform,
                    NMFakePlatformLink *device,
                    gconstpointer user_data)
{
	const NMPlatformLnkVxlan *props = user_data;
	NMPObject *obj_tmp;
	NMPObject *lnk;

	obj_tmp = (NMPObject *) device->obj;

	lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL);
	lnk->lnk_vxlan = *props;

	obj_tmp->link.parent = props->parent_ifindex;
	obj_tmp->_link.netlink.lnk = lnk;
}

799 800 801
static gboolean
link_vxlan_add (NMPlatform *platform,
                const char *name,
802
                const NMPlatformLnkVxlan *props,
803
                const NMPlatformLink **out_link)
804
{
805 806 807 808
	link_add_one (platform, name, NM_LINK_TYPE_VXLAN,
	              _vxlan_add_prepare, props, out_link);
	return TRUE;
}
809

810 811 812 813
struct infiniband_add_data {
	int parent;
	int p_key;
};
814

815 816 817 818 819 820 821 822
static void
_infiniband_add_prepare (NMPlatform *platform,
                         NMFakePlatformLink *device,
                         gconstpointer user_data)
{
	const struct infiniband_add_data *d = user_data;
	NMPObject *obj_tmp;
	NMPObject *lnk;
823

824
	obj_tmp = (NMPObject *) device->obj;
825

826 827 828
	lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_INFINIBAND, NULL);
	lnk->lnk_infiniband.p_key = d->p_key;
	lnk->lnk_infiniband.mode = "datagram";
829

830 831
	obj_tmp->link.parent = d->parent;
	obj_tmp->_link.netlink.lnk = lnk;
832 833
}

834
static gboolean
835
infiniband_partition_add (NMPlatform *platform, int parent, int p_key, const NMPlatformLink **out_link)
836
{
837
	NMFakePlatformLink *parent_device;
838
	char name[IFNAMSIZ];
839 840 841 842
	const struct infiniband_add_data d = {
		.parent = parent,
		.p_key = p_key,
	};
843 844 845 846

	parent_device = link_get (platform, parent);
	g_return_val_if_fail (parent_device != NULL, FALSE);

847
	nm_utils_new_infiniband_name (name, parent_device->obj->link.name, p_key);
848

849 850
	link_add_one (platform, name, NM_LINK_TYPE_INFINIBAND,
	              _infiniband_add_prepare, &d, out_link);
851 852 853
	return TRUE;
}

854 855 856 857 858 859 860 861 862
static gboolean
infiniband_partition_delete (NMPlatform *platform, int parent, int p_key)
{
	NMFakePlatformLink *parent_device;
	gs_free char *name = NULL;

	parent_device = link_get (platform, parent);
	g_return_val_if_fail (parent_device != NULL, FALSE);

863
	nm_utils_new_infiniband_name (name, parent_device->obj->link.name, p_key);
864 865 866
	return link_delete (platform, nm_platform_link_get_ifindex (platform, name));
}

867 868 869 870 871 872 873
static gboolean
wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabilities *caps)
{
	NMFakePlatformLink *device = link_get (platform, ifindex);

	g_return_val_if_fail (device, FALSE);

874
	if (device->obj->link.type != NM_LINK_TYPE_WIFI)
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
		return FALSE;

	if (caps) {
		*caps = (  NM_WIFI_DEVICE_CAP_CIPHER_WEP40
		         | NM_WIFI_DEVICE_CAP_CIPHER_WEP104
		         | NM_WIFI_DEVICE_CAP_CIPHER_TKIP
		         | NM_WIFI_DEVICE_CAP_CIPHER_CCMP
		         | NM_WIFI_DEVICE_CAP_WPA
		         | NM_WIFI_DEVICE_CAP_RSN
		         | NM_WIFI_DEVICE_CAP_AP
		         | NM_WIFI_DEVICE_CAP_ADHOC);
	}
	return TRUE;
}

static gboolean
891
wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid)
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
{
	return FALSE;
}

static GByteArray *
wifi_get_ssid (NMPlatform *platform, int ifindex)
{
	return NULL;
}

static guint32
wifi_get_frequency (NMPlatform *platform, int ifindex)
{
	return 0;
}

static int
wifi_get_quality (NMPlatform *platform, int ifindex)
{
	return 0;
}

static guint32
wifi_get_rate (NMPlatform *platform, int ifindex)
{
	return 0;
}

static NM80211Mode
wifi_get_mode (NMPlatform *platform, int ifindex)
{
	return NM_802_11_MODE_UNKNOWN;
}

static void
wifi_set_mode (NMPlatform *platform, int ifindex, NM80211Mode mode)
{
	;
}

static guint32
wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs)
{
	return freqs[0];
}

static void
wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running)
{
	;
}

static guint32
mesh_get_channel (NMPlatform *platform, int ifindex)
{
	return 0;
}

static gboolean
mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel)
{
	return FALSE;
}

static gboolean
957
mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
958 959 960 961
{
	return FALSE;
}

962
/*****************************************************************************/
Pavel Šimerda's avatar
Pavel Šimerda committed
963

964 965
static gboolean
ipx_address_add (NMPlatform *platform, int addr_family, const NMPlatformObject *address)
Pavel Šimerda's avatar
Pavel Šimerda committed
966
{
967 968 969 970 971
	nm_auto_nmpobj NMPObject *obj = NULL;
	NMPCacheOpsType cache_op;
	nm_auto_nmpobj const NMPObject *obj_old = NULL;
	nm_auto_nmpobj const NMPObject *obj_new = NULL;
	NMPCache *cache = nm_platform_get_cache (platform);
Pavel Šimerda's avatar
Pavel Šimerda committed
972

973
	g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
Pavel Šimerda's avatar
Pavel Šimerda committed
974

975 976 977 978
	obj = nmp_object_new (addr_family == AF_INET
	                        ? NMP_OBJECT_TYPE_IP4_ADDRESS
	                        : NMP_OBJECT_TYPE_IP6_ADDRESS,
	                      address);
Pavel Šimerda's avatar
Pavel Šimerda committed
979

980
	cache_op = nmp_cache_update_netlink (cache, obj, FALSE, &obj_old, &obj_new);
981 982
	nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
	return TRUE;
Pavel Šimerda's avatar
Pavel Šimerda committed
983 984 985
}

static gboolean
986 987 988
ip4_address_add (NMPlatform *platform,
                 int ifindex,
                 in_addr_t addr,
989
                 guint8 plen,
990 991 992
                 in_addr_t peer_addr,
                 guint32 lifetime,
                 guint32 preferred,
993
                 guint32 flags,
994
                 const char *label)
Pavel Šimerda's avatar
Pavel Šimerda committed
995 996 997 998
{
	NMPlatformIP4Address address;

	memset (&address, 0, sizeof (address));
999
	address.addr_source = NM_IP_CONFIG_SOURCE_KERNEL;
Pavel Šimerda's avatar
Pavel Šimerda committed
1000 1001
	address.ifindex = ifindex;
	address.address = addr;
1002
	address.peer_address = peer_addr;
Pavel Šimerda's avatar
Pavel Šimerda committed
1003
	address.plen = plen;
1004
	address.timestamp = nm_utils_get_monotonic_timestamp_s ();
1005 1006
	address.lifetime = lifetime;
	address.preferred = preferred;
1007
	address.n_ifa_flags = flags;
1008 1009
	if (label)
		g_strlcpy (address.label, label, sizeof (address.label));
Pavel Šimerda's avatar
Pavel Šimerda committed
1010

1011
	return ipx_address_add (platform, AF_INET, (const NMPlatformObject *) &address);
Pavel Šimerda's avatar
Pavel Šimerda committed
1012 1013 1014
}

static gboolean
1015 1016 1017
ip6_address_add (NMPlatform *platform,
                 int ifindex,
                 struct in6_addr addr,
1018
                 guint8 plen,
1019 1020
                 struct in6_addr peer_addr,
                 guint32 lifetime,
1021 1022
                 guint32 preferred,
                 guint32 flags)
Pavel Šimerda's avatar
Pavel Šimerda committed
1023 1024 1025 1026
{
	NMPlatformIP6Address address;

	memset (&address, 0, sizeof (address));
1027
	address.addr_source = NM_IP_CONFIG_SOURCE_KERNEL;
Pavel Šimerda's avatar
Pavel Šimerda committed
1028 1029
	address.ifindex = ifindex;
	address.address = addr;
1030
	address.peer_address = (IN6_IS_ADDR_UNSPECIFIED (&peer_addr) || IN6_ARE_ADDR_EQUAL (&addr, &peer_addr)) ? in6addr_any : peer_addr;
Pavel Šimerda's avatar
Pavel Šimerda committed
1031
	address.plen = plen;
1032
	address.timestamp = nm_utils_get_monotonic_timestamp_s ();
1033 1034
	address.lifetime = lifetime;
	address.preferred = preferred;
1035
	address.n_ifa_flags = flags;
Pavel Šimerda's avatar
Pavel Šimerda committed
1036

1037
	return ipx_address_add (platform, AF_INET6, (const NMPlatformObject *) &address);
Pavel Šimerda's avatar
Pavel Šimerda committed
1038 1039 1040
}

static gboolean
1041 1042 1043 1044 1045 1046
ipx_address_delete (NMPlatform *platform,
                    int addr_family,
                    int ifindex,
                    gconstpointer addr,
                    const guint8 *plen,
                    gconstpointer peer_addr)
Pavel Šimerda's avatar
Pavel Šimerda committed
1047
{
1048 1049 1050 1051 1052
	gs_unref_ptrarray GPtrArray *objs = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
	NMDedupMultiIter iter;
	const NMPObject *o = NULL;
	guint i;
	guint32 peer_addr_i;
Pavel Šimerda's avatar
Pavel Šimerda committed
1053

1054
	g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
Pavel Šimerda's avatar
Pavel Šimerda committed
1055

1056
	peer_addr_i = peer_addr ? *((guint32 *) peer_addr) : 0;
Pavel Šimerda's avatar
Pavel Šimerda committed
1057

1058 1059 1060