1    	/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2    	/* nm-platform.c - Handle runtime kernel networking configuration
3    	 *
4    	 * This program is free software; you can redistribute it and/or modify
5    	 * it under the terms of the GNU General Public License as published by
6    	 * the Free Software Foundation; either version 2, or (at your option)
7    	 * any later version.
8    	 *
9    	 * This program is distributed in the hope that it will be useful,
10   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   	 * GNU General Public License for more details.
13   	 *
14   	 * You should have received a copy of the GNU General Public License along
15   	 * with this program; if not, write to the Free Software Foundation, Inc.,
16   	 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17   	 *
18   	 * Copyright (C) 2013 Red Hat, Inc.
19   	 */
20   	
21   	#include <stdlib.h>
22   	#include <stdio.h>
23   	#include <string.h>
24   	#include <arpa/inet.h>
25   	
26   	#include "nm-platform.h"
27   	#include "nm-linux-platform.h"
28   	#include "nm-fake-platform.h"
29   	
30   	#define error(...) fprintf (stderr, __VA_ARGS__)
31   	
32   	typedef gboolean boolean_t;
33   	typedef int decimal_t;
34   	typedef const char *string_t;
35   	
36   	#define print_boolean(value) printf ("%s\n", value ? "yes" : "no")
37   	#define print_decimal(value) printf ("%d\n", value)
38   	#define print_string(value) printf ("%s\n", value)
39   	
40   	static gboolean
41   	do_sysctl_set (char **argv)
42   	{
43   		return nm_platform_sysctl_set (argv[0], argv[1]);
44   	}
45   	
46   	static gboolean
47   	do_sysctl_get (char **argv)
48   	{
49   		auto_g_free char *value = nm_platform_sysctl_get (argv[0]);
50   	
51   		printf ("%s\n", value);
52   	
53   		return !!value;
54   	}
55   	
56   	static int
57   	parse_ifindex (const char *str)
58   	{
59   		char *endptr;
60   		int ifindex = 0;
61   	
62   		ifindex = strtol (str, &endptr, 10);
63   	
64   		if (*endptr) {
65   			ifindex = nm_platform_link_get_ifindex (str);
66   		}
67   	
68   		return ifindex;
69   	}
70   	
71   	static gboolean
72   	do_link_get_all (char **argv)
73   	{
74   		GArray *links;
75   		NMPlatformLink *device;
76   		int i;
77   	
78   		links = nm_platform_link_get_all ();
79   		for (i = 0; i < links->len; i++) {
80   			device = &g_array_index (links, NMPlatformLink, i);
81   	
82   			printf ("%d: %s type %d\n", device->ifindex, device->name, device->type);
83   		}
84   		g_array_unref (links);
85   	
86   		return TRUE;
87   	}
88   	
89   	static gboolean
90   	do_dummy_add (char **argv)
91   	{
92   		return nm_platform_dummy_add (argv[0]);
93   	}
94   	
95   	static gboolean
96   	do_bridge_add (char **argv)
97   	{
98   		return nm_platform_bridge_add (argv[0]);
99   	}
100  	
101  	static gboolean
102  	do_bond_add (char **argv)
103  	{
104  		return nm_platform_bond_add (argv[0]);
105  	}
106  	
107  	static gboolean
108  	do_team_add (char **argv)
109  	{
110  		return nm_platform_team_add (argv[0]);
111  	}
112  	
113  	static gboolean
114  	do_vlan_add (char **argv)
115  	{
116  		const char *name = *argv++;
117  		int parent = parse_ifindex (*argv++);
118  		int vlanid = strtol (*argv++, NULL, 10);
119  		guint32 vlan_flags = strtol (*argv++, NULL, 10);
120  	
121  		return nm_platform_vlan_add (name, parent, vlanid, vlan_flags);
122  	}
123  	
124  	static gboolean
125  	do_link_exists (char **argv)
126  	{
127  		gboolean value = nm_platform_link_exists (argv[0]);
128  	
129  		print_boolean (value);
130  	
131  		return TRUE;
132  	}
133  	
134  	#define LINK_CMD(cmdname) \
135  		static gboolean \
136  		do_link_##cmdname (char **argv) \
137  		{ \
138  			int ifindex = parse_ifindex (argv[0]); \
139  			return ifindex ? nm_platform_link_##cmdname (ifindex) : FALSE; \
140  		}
141  	
142  	#define LINK_CMD_GET_FULL(cmdname, type, cond) \
143  		static gboolean \
144  		do_link_##cmdname (char **argv) \
145  		{ \
146  			int ifindex = parse_ifindex (argv[0]); \
147  			if (ifindex) { \
148  				type##_t value = nm_platform_link_##cmdname (ifindex); \
149  				if (cond) { \
150  					print_##type (value); \
151  					return TRUE; \
152  				} \
153  			} \
154  			return FALSE; \
155  		}
156  	#define LINK_CMD_GET(cmdname, type) LINK_CMD_GET_FULL (cmdname, type, TRUE);
157  	
158  	LINK_CMD (delete)
159  	
160  	/* do_link_delete_by_ifname:
161  	 *
162  	 * We don't need this as we allow ifname instead of ifindex anyway.
163  	 */
164  	
165  	static gboolean
166  	do_link_get_ifindex (char **argv)
167  	{
168  		int ifindex = nm_platform_link_get_ifindex (argv[0]);
169  	
170  		if (ifindex)
171  			printf ("%d\n", ifindex);
172  	
173  		return !!ifindex;
174  	}
175  	
176  	LINK_CMD_GET_FULL (get_name, string, value)
177  	LINK_CMD_GET_FULL (get_type, decimal, value > 0)
178  	LINK_CMD_GET (is_software, boolean)
179  	LINK_CMD_GET (supports_slaves, boolean)
180  	
181  	LINK_CMD (set_up)
182  	LINK_CMD (set_down)
183  	LINK_CMD (set_arp)
184  	LINK_CMD (set_noarp)
185  	LINK_CMD_GET (is_up, boolean)
186  	LINK_CMD_GET (is_connected, boolean)
187  	LINK_CMD_GET (uses_arp, boolean)
188  	
189  	static gboolean
190  	do_link_set_address (char **argv)
191  	{
192  		int ifindex = parse_ifindex (*argv++);
193  		char *hex = *argv++;
194  		int hexlen = strlen (hex);
195  		char address[hexlen/2];
196  		char *endptr;
197  		int i;
198  	
199  		g_assert (!(hexlen % 2));
200  	
201  		for (i = 0; i < sizeof (address); i++) {
202  			char digit[3];
203  	
204  			digit[0] = hex[2*i];
205  			digit[1] = hex[2*i+1];
206  			digit[2] = '\0';
207  	
208  			address[i] = strtoul (digit, &endptr, 16);
209  			g_assert (!*endptr);
210  		}
211  	
212  		return nm_platform_link_set_address (ifindex, address, sizeof (address));
213  	}
214  	
215  	static gboolean
216  	do_link_get_address (char **argv)
217  	{
218  		int ifindex = parse_ifindex (*argv++);
219  		const char *address;
220  		size_t length;
221  		int i;
222  	
223  		address = nm_platform_link_get_address (ifindex, &length);
224  	
225  		if (!address || length <= 0)
226  			return FALSE;
227  	
228  		for (i = 0; i < length; i++)
229  			printf ("%02x", address[i]);
230  		printf ("\n");
231  	
232  		return TRUE;
233  	}
234  	
235  	static gboolean
236  	do_link_set_mtu (char **argv)
237  	{
238  		int ifindex = parse_ifindex (*argv++);
239  		int mtu = strtoul (*argv++, NULL, 10);
240  	
241  		return nm_platform_link_set_mtu (ifindex, mtu);
242  	}
243  	
244  	LINK_CMD_GET (get_mtu, decimal);
245  	LINK_CMD_GET (supports_carrier_detect, boolean)
246  	LINK_CMD_GET (supports_vlans, boolean)
247  	
248  	static gboolean
249  	do_link_enslave (char **argv)
250  	{
251  		int master = parse_ifindex (*argv++);
252  		int slave = parse_ifindex (*argv++);
253  	
254  		return nm_platform_link_enslave (master, slave);
255  	}
256  	
257  	static gboolean
258  	do_link_release (char **argv)
259  	{
260  		int master = parse_ifindex (*argv++);
261  		int slave = parse_ifindex (*argv++);
262  	
263  		return nm_platform_link_release (master, slave);
264  	}
265  	
266  	LINK_CMD_GET (get_master, decimal)
267  	
268  	static gboolean
269  	do_master_set_option (char **argv)
270  	{
271  		int ifindex = parse_ifindex (*argv++);
272  		const char *option = *argv++;
273  		const char *value = *argv++;
274  	
275  		return nm_platform_master_set_option (ifindex, option, value);
276  	}
277  	
278  	static gboolean
279  	do_master_get_option (char **argv)
280  	{
281  		int ifindex = parse_ifindex (*argv++);
282  		const char *option = *argv++;
283  		auto_g_free char *value = nm_platform_master_get_option (ifindex, option);
284  	
285  		printf ("%s\n", value);
286  	
287  		return !!value;
288  	}
289  	
290  	static gboolean
291  	do_slave_set_option (char **argv)
292  	{
293  		int ifindex = parse_ifindex (*argv++);
294  		const char *option = *argv++;
295  		const char *value = *argv++;
296  	
297  		return nm_platform_slave_set_option (ifindex, option, value);
298  	}
299  	
300  	static gboolean
301  	do_slave_get_option (char **argv)
302  	{
303  		int ifindex = parse_ifindex (*argv++);
304  		const char *option = *argv++;
305  		auto_g_free char *value = nm_platform_slave_get_option (ifindex, option);
306  	
307  		printf ("%s\n", value);
308  	
309  		return !!value;
310  	}
311  	
312  	static gboolean
313  	do_vlan_get_info (char **argv)
314  	{
315  		int ifindex = parse_ifindex (*argv++);
316  		int parent;
317  		int vlanid;
318  	
(18) Event example_checked: Example3: "nm_platform_vlan_get_info(ifindex, &parent, &vlanid)" has its value checked in "nm_platform_vlan_get_info(ifindex, &parent, &vlanid)".
Also see events: [check_return][example_checked][example_checked][example_checked][example_checked][unchecked_value]
319  		if (!nm_platform_vlan_get_info (ifindex, &parent, &vlanid))
320  			return FALSE;
321  	
322  		printf ("%d %d\n", parent, vlanid);
323  	
324  		return TRUE;
325  	}
326  	
327  	static gboolean
328  	do_vlan_set_ingress_map (char **argv)
329  	{
330  		int ifindex = parse_ifindex (*argv++);
331  		int from = strtol (*argv++, NULL, 10);
332  		int to = strtol (*argv++, NULL, 10);
333  	
334  		return nm_platform_vlan_set_ingress_map (ifindex, from, to);
335  	}
336  	
337  	static gboolean
338  	do_vlan_set_egress_map (char **argv)
339  	{
340  		int ifindex = parse_ifindex (*argv++);
341  		int from = strtol (*argv++, NULL, 10);
342  		int to = strtol (*argv++, NULL, 10);
343  	
344  		return nm_platform_vlan_set_egress_map (ifindex, from, to);
345  	}
346  	
347  	static gboolean
348  	do_veth_get_properties (char **argv)
349  	{
350  		int ifindex = parse_ifindex (*argv++);
351  		NMPlatformVethProperties props;
352  	
353  		if (!nm_platform_veth_get_properties (ifindex, &props))
354  			return FALSE;
355  	
356  		printf ("peer: %d\n", props.peer);
357  	
358  		return TRUE;
359  	}
360  	
361  	static gboolean
362  	do_tun_get_properties (char **argv)
363  	{
364  		int ifindex = parse_ifindex (*argv++);
365  		NMPlatformTunProperties props;
366  	
367  		if (!nm_platform_tun_get_properties (ifindex, &props))
368  			return FALSE;
369  	
370  		printf ("mode: %s\n", props.mode);
371  		if (props.owner == -1)
372  			printf ("owner: none\n");
373  		else
374  			printf ("owner: %lu\n", (gulong) props.owner);
375  		if (props.group == -1)
376  			printf ("group: none\n");
377  		else
378  			printf ("group: %lu\n", (gulong) props.group);
379  		printf ("no-pi: ");
380  		print_boolean (props.no_pi);
381  		printf ("vnet-hdr: ");
382  		print_boolean (props.vnet_hdr);
383  		printf ("multi-queue: ");
384  		print_boolean (props.multi_queue);
385  	
386  		return TRUE;
387  	}
388  	
389  	static gboolean
390  	do_macvlan_get_properties (char **argv)
391  	{
392  		int ifindex = parse_ifindex (*argv++);
393  		NMPlatformMacvlanProperties props;
394  	
395  		if (!nm_platform_macvlan_get_properties (ifindex, &props))
396  			return FALSE;
397  	
398  		printf ("parent: %d\n", props.parent_ifindex);
399  		printf ("mode: %s\n", props.mode);
400  		printf ("no-promisc: ");
401  		print_boolean (props.no_promisc);
402  		return TRUE;
403  	}
404  	
405  	static gboolean
406  	do_gre_get_properties (char **argv)
407  	{
408  		int ifindex = parse_ifindex (*argv++);
409  		NMPlatformGreProperties props;
410  		char addrstr[INET_ADDRSTRLEN];
411  	
412  		if (!nm_platform_gre_get_properties (ifindex, &props))
413  			return FALSE;
414  	
415  		printf ("parent-ifindex: %u\n", props.parent_ifindex);
416  		printf ("input-flags: %u\n", props.input_flags);
417  		printf ("output-flags: %u\n", props.input_flags);
418  		printf ("input-key: %u\n", props.input_key);
419  		printf ("output-key: %u\n", props.output_key);
420  		if (props.local)
421  			inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr));
422  		else
423  			strcpy (addrstr, "-");
424  		printf ("local: %s\n", addrstr);
425  		if (props.remote)
426  			inet_ntop (AF_INET, &props.remote, addrstr, sizeof (addrstr));
427  		else
428  			strcpy (addrstr, "-");
429  		printf ("remote: %s\n", addrstr);
430  		printf ("ttl: %u\n", props.ttl);
431  		printf ("tos: %u\n", props.tos);
432  		printf ("path-mtu-discovery: ");
433  		print_boolean (props.path_mtu_discovery);
434  	
435  		return TRUE;
436  	}
437  	
438  	static gboolean
439  	do_ip4_address_get_all (char **argv)
440  	{
441  		int ifindex = parse_ifindex (argv[0]);
442  		GArray *addresses;
443  		NMPlatformIP4Address *address;
444  		char addrstr[INET_ADDRSTRLEN];
445  		int i;
446  	
447  		if (ifindex) {
448  			addresses = nm_platform_ip4_address_get_all (ifindex);
449  			for (i = 0; i < addresses->len; i++) {
450  				address = &g_array_index (addresses, NMPlatformIP4Address, i);
451  				inet_ntop (AF_INET, &address->address, addrstr, sizeof (addrstr));
452  				printf ("%s/%d\n", addrstr, address->plen);
453  			}
454  			g_array_unref (addresses);
455  		}
456  	
457  		return !!ifindex;
458  	}
459  	
460  	static gboolean
461  	do_ip6_address_get_all (char **argv)
462  	{
463  		int ifindex = parse_ifindex (argv[0]);
464  		GArray *addresses;
465  		NMPlatformIP6Address *address;
466  		char addrstr[INET6_ADDRSTRLEN];
467  		int i;
468  	
469  		if (ifindex) {
470  			addresses = nm_platform_ip6_address_get_all (ifindex);
471  			for (i = 0; i < addresses->len; i++) {
472  				address = &g_array_index (addresses, NMPlatformIP6Address, i);
473  				inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr));
474  				printf ("%s/%d\n", addrstr, address->plen);
475  			}
476  			g_array_unref (addresses);
477  		}
478  	
479  		return !!ifindex;
480  	}
481  	
482  	static gboolean
483  	parse_ip_address (int family, char *str, gpointer address, int *plen)
484  	{
485  		char *endptr;
486  	
487  		if (plen) {
488  			char *ptr = strchr (str, '/');
489  			if (ptr) {
490  				*ptr++ = '\0';
491  				*plen = strtol (ptr, &endptr, 10);
492  				if (*endptr)
493  					ptr = NULL;
494  			}
495  			if (!ptr) {
496  				error ("Bad format of IP address, expected address/plen.\n");
497  				return FALSE;
498  			}
499  		}
500  	
501  		if (inet_pton (family, str, address))
502  			return TRUE;
503  	
504  		error ("Bad format of IP address, expected address%s.\n", plen ? "/plen" : "");
505  		return FALSE;
506  	}
507  	
508  	typedef in_addr_t ip4_t;
509  	typedef struct in6_addr ip6_t;
510  	
511  	#define parse_ip4_address(s, a, p) parse_ip_address (AF_INET, s, a, p)
512  	#define parse_ip6_address(s, a, p) parse_ip_address (AF_INET6, s, a, p)
513  	
514  	static gboolean
515  	do_ip4_address_add (char **argv)
516  	{
517  		int ifindex = parse_ifindex (*argv++);
518  		ip4_t address;
519  		int plen;
520  	
521  		if (ifindex && parse_ip4_address (*argv++, &address, &plen)) {
522  			guint32 lifetime = strtol (*argv++, NULL, 10);
523  			guint32 preferred = strtol (*argv++, NULL, 10);
524  	
525  			gboolean value = nm_platform_ip4_address_add (ifindex, address, plen, lifetime, preferred);
526  			return value;
527  		} else
528  			return FALSE;
529  	}
530  	
531  	static gboolean
532  	do_ip6_address_add (char **argv)
533  	{
534  		int ifindex = parse_ifindex (*argv++);
535  		ip6_t address;
536  		int plen;
537  	
538  		if (ifindex && parse_ip6_address (*argv++, &address, &plen)) {
539  			guint32 lifetime = strtol (*argv++, NULL, 10);
540  			guint32 preferred = strtol (*argv++, NULL, 10);
541  	
542  			gboolean value = nm_platform_ip6_address_add (ifindex, address, plen, lifetime, preferred);
543  			return value;
544  		} else
545  			return FALSE;
546  	}
547  	
548  	#define ADDR_CMD_FULL(v, cmdname, print) \
549  		static gboolean \
550  		do_##v##_address_##cmdname (char **argv) \
551  		{ \
552  			int ifindex = parse_ifindex (*argv++); \
553  			v##_t address; \
554  			int plen; \
555  			if (ifindex && parse_##v##_address (*argv++, &address, &plen)) { \
556  				gboolean value = nm_platform_##v##_address_##cmdname (ifindex, address, plen); \
557  				if (print) { \
558  					print_boolean (value); \
559  					return TRUE; \
560  				} else \
561  					return value; \
562  			} else \
563  				return FALSE; \
564  		}
565  	#define ADDR_CMD(cmdname) ADDR_CMD_FULL (ip4, cmdname, FALSE) ADDR_CMD_FULL (ip6, cmdname, FALSE)
566  	#define ADDR_CMD_PRINT(cmdname) ADDR_CMD_FULL (ip4, cmdname, TRUE) ADDR_CMD_FULL (ip6, cmdname, TRUE)
567  	
568  	ADDR_CMD (delete)
569  	ADDR_CMD_PRINT (exists)
570  	
571  	static gboolean
572  	do_ip4_route_get_all (char **argv)
573  	{
574  		int ifindex = parse_ifindex (argv[0]);
575  		GArray *routes;
576  		NMPlatformIP4Route *route;
577  		char networkstr[INET_ADDRSTRLEN], gatewaystr[INET_ADDRSTRLEN];
578  		int i;
579  	
580  		if (ifindex) {
581  			routes = nm_platform_ip4_route_get_all (ifindex, TRUE);
582  			for (i = 0; i < routes->len; i++) {
583  				route = &g_array_index (routes, NMPlatformIP4Route, i);
584  				inet_ntop (AF_INET, &route->network, networkstr, sizeof (networkstr));
585  				inet_ntop (AF_INET, &route->gateway, gatewaystr, sizeof (gatewaystr));
586  				printf ("%s/%d via %s metric %d\n",
587  						networkstr, route->plen, gatewaystr, route->metric);
588  			}
589  			g_array_unref (routes);
590  		}
591  	
592  		return !!ifindex;
593  	}
594  	
595  	static gboolean
596  	do_ip6_route_get_all (char **argv)
597  	{
598  		int ifindex = parse_ifindex (argv[0]);
599  		GArray *routes;
600  		NMPlatformIP6Route *route;
601  		char networkstr[INET6_ADDRSTRLEN], gatewaystr[INET6_ADDRSTRLEN];
602  		int i;
603  	
604  		if (ifindex) {
605  			routes = nm_platform_ip6_route_get_all (ifindex, TRUE);
606  			for (i = 0; i < routes->len; i++) {
607  				route = &g_array_index (routes, NMPlatformIP6Route, i);
608  				inet_ntop (AF_INET6, &route->network, networkstr, sizeof (networkstr));
609  				inet_ntop (AF_INET6, &route->gateway, gatewaystr, sizeof (gatewaystr));
610  				printf ("%s/%d via %s metric %d\n",
611  						networkstr, route->plen, gatewaystr, route->metric);
612  			}
613  			g_array_unref (routes);
614  		}
615  	
616  		return !!ifindex;
617  	}
618  	
619  	static gboolean
620  	do_ip4_route_add (char **argv)
621  	{
622  		int ifindex = parse_ifindex (*argv++);
623  		in_addr_t network, gateway;
624  		int plen, metric, mss;
625  	
626  		parse_ip4_address (*argv++, &network, &plen);
627  		parse_ip4_address (*argv++, &gateway, NULL);
628  		metric = strtol (*argv++, NULL, 10);
629  		mss = strtol (*argv++, NULL, 10);
630  	
631  		return nm_platform_ip4_route_add (ifindex, network, plen, gateway, metric, mss);
632  	}
633  	
634  	static gboolean
635  	do_ip6_route_add (char **argv)
636  	{
637  		int ifindex = parse_ifindex (*argv++);
638  		struct in6_addr network, gateway;
639  		int plen, metric, mss;
640  	
641  		parse_ip6_address (*argv++, &network, &plen);
642  		parse_ip6_address (*argv++, &gateway, NULL);
643  		metric = strtol (*argv++, NULL, 10);
644  		mss = strtol (*argv++, NULL, 10);
645  		return nm_platform_ip6_route_add (ifindex, network, plen, gateway, metric, mss);
646  	}
647  	
648  	static gboolean
649  	do_ip4_route_delete (char **argv)
650  	{
651  		int ifindex = parse_ifindex (*argv++);
652  		in_addr_t network;
653  		int plen, metric;
654  	
655  		parse_ip4_address (*argv++, &network, &plen);
656  		metric = strtol (*argv++, NULL, 10);
657  	
658  		return nm_platform_ip4_route_delete (ifindex, network, plen, metric);
659  	}
660  	
661  	static gboolean
662  	do_ip6_route_delete (char **argv)
663  	{
664  		int ifindex = parse_ifindex (*argv++);
665  		struct in6_addr network;
666  		int plen, metric;
667  	
668  		parse_ip6_address (*argv++, &network, &plen);
669  		metric = strtol (*argv++, NULL, 10);
670  	
671  		return nm_platform_ip6_route_delete (ifindex, network, plen, metric);
672  	}
673  	
674  	static gboolean
675  	do_ip4_route_exists (char **argv)
676  	{
677  		int ifindex = parse_ifindex (*argv++);
678  		in_addr_t network;
679  		int plen, metric;
680  	
681  		parse_ip4_address (*argv++, &network, &plen);
682  		metric = strtol (*argv++, NULL, 10);
683  	
684  		print_boolean (nm_platform_ip4_route_exists (ifindex, network, plen, metric));
685  		return TRUE;
686  	}
687  	
688  	static gboolean
689  	do_ip6_route_exists (char **argv)
690  	{
691  		int ifindex = parse_ifindex (*argv++);
692  		struct in6_addr network;
693  		int plen, metric;
694  	
695  		parse_ip6_address (*argv++, &network, &plen);
696  		metric = strtol (*argv++, NULL, 10);
697  	
698  		print_boolean (nm_platform_ip6_route_exists (ifindex, network, plen, metric));
699  		return TRUE;
700  	}
701  	
702  	typedef struct {
703  		const char *name;
704  		const char *help;
705  		int (*handler) (char **argv);
706  		int argc;
707  		const char *arghelp;
708  	} command_t;
709  	
710  	static const command_t commands[] = {
711  		{ "sysctl-set", "get /proc/sys or /sys value", do_sysctl_set, 2, "<path> <value>" },
712  		{ "sysctl-get", "get /proc/sys or /sys value", do_sysctl_get, 1, "<value>" },
713  		{ "link-get-all", "print all links", do_link_get_all, 0, "" },
714  		{ "dummy-add", "add dummy interface", do_dummy_add, 1, "<ifname>" },
715  		{ "bridge-add", "add bridge interface", do_bridge_add, 1, "<ifname>" },
716  		{ "bond-add", "add bond interface", do_bond_add, 1, "<ifname>" },
717  		{ "team-add", "add team interface", do_team_add, 1, "<ifname>" },
718  		{ "vlan-add", "add vlan interface", do_vlan_add, 4, "<ifname> <parent> <vlanid> <vlanflags>" },
719  		{ "link-exists", "check ifname for existance", do_link_exists, 1, "<ifname>" },
720  		{ "link-delete", "delete interface", do_link_delete, 1, "<ifname/ifindex>" },
721  		{ "link-get-ifindex>", "get interface index", do_link_get_ifindex, 1, "<ifname>" },
722  		{ "link-get-name", "get interface name", do_link_get_name, 1, "<ifindex>" },
723  		{ "link-get-type", "get interface type", do_link_get_type, 1, "<ifname/ifindex>" },
724  		{ "link-is-software", "check if interface is a software one", do_link_is_software, 1, "<ifname/ifindex>" },
725  		{ "link-supports-slaves", "check if interface supports slaves", do_link_supports_slaves, 1, "<ifname/ifindex>" },
726  		{ "link-set-up", "set interface up", do_link_set_up, 1, "<ifname/ifindex>" },
727  		{ "link-set-down", "set interface down", do_link_set_down, 1, "<ifname/ifindex>" },
728  		{ "link-set-arp", "activate interface arp", do_link_set_arp, 1, "<ifname/ifindex>" },
729  		{ "link-set-noarp", "deactivate interface arp", do_link_set_noarp, 1, "<ifname/ifindex>" },
730  		{ "link-is-up", "check if interface is up", do_link_is_up, 1, "<ifname/ifindex>" },
731  		{ "link-is-connected", "check interface carrier", do_link_is_connected, 1, "<ifname/ifindex>" },
732  		{ "link-uses-arp", "check whether interface uses arp", do_link_uses_arp, 1, "<ifname/ifindex>" },
733  		{ "link-get-address", "print link address", do_link_get_address, 1, "<ifname/ifindex>" },
734  		{ "link-set-address", "set link address", do_link_set_address, 2, "<ifname/ifindex> <hex>" },
735  		{ "link-get-mtu", "print link mtu", do_link_get_mtu, 1, "<ifname/ifindex>" },
736  		{ "link-set-mtu", "set link mtu", do_link_set_mtu, 2, "<ifname/ifindex> <mtu>" },
737  		{ "link-supports-carrier-detect", "check whether interface supports carrier detect",
738  			do_link_supports_carrier_detect, 1, "<ifname/ifindex>" },
739  		{ "link-supports-vlans", "check whether interface supports VLANs",
740  			do_link_supports_vlans, 1, "<ifname/ifindex>" },
741  		{ "link-enslave", "enslave slave interface with master", do_link_enslave, 2, "<master> <slave>" },
742  		{ "link-release", "release save interface from master", do_link_release, 2, "<master> <slave>" },
743  		{ "link-get-master", "print master interface of a slave", do_link_get_master, 1, "<ifname/ifindex>" },
744  		{ "link-master-set-option", "set master option", do_master_set_option, 3,
745  			"<ifname/ifindex> <option> <value>" },
746  		{ "link-master-get-option", "get master option", do_master_get_option, 2,
747  			"<ifname/ifindex> <option>" },
748  		{ "link-slave-set-option", "set slave option", do_slave_set_option, 3,
749  			"<ifname/ifindex> <option>" },
750  		{ "link-slave-get-option", "get slave option", do_slave_get_option, 2,
751  			"<ifname/ifindex> <option>" },
752  		{ "vlan-get-info", "get vlan info", do_vlan_get_info, 1, "<ifname/ifindex>" },
753  		{ "vlan-set-ingress-map", "set vlan ingress map", do_vlan_set_ingress_map, 3,
754  			"<ifname/ifindex> <from> <to>" },
755  		{ "vlan-set-egress-map", "set vlan egress map", do_vlan_set_egress_map, 3,
756  			"<ifname/ifindex> <from> <to>" },
757  		{ "veth-get-properties", "get veth properties", do_veth_get_properties, 1,
758  		  "<ifname/ifindex>" },
759  		{ "tun-get-properties", "get tun/tap properties", do_tun_get_properties, 1,
760  		  "<ifname/ifindex>" },
761  		{ "macvlan-get-properties", "get macvlan properties", do_macvlan_get_properties, 1,
762  		  "<ifname/ifindex>" },
763  		{ "gre-get-properties", "get gre properties", do_gre_get_properties, 1,
764  		  "<ifname/ifindex>" },
765  		{ "ip4-address-get-all", "print all IPv4 addresses", do_ip4_address_get_all, 1, "<ifname/ifindex>" },
766  		{ "ip6-address-get-all", "print all IPv6 addresses", do_ip6_address_get_all, 1, "<ifname/ifindex>" },
767  		{ "ip4-address-add", "add IPv4 address", do_ip4_address_add, 4, "<ifname/ifindex> <address>/<plen> <lifetime> <>" },
768  		{ "ip6-address-add", "add IPv6 address", do_ip6_address_add, 4, "<ifname/ifindex> <address>/<plen> <lifetime> <>" },
769  		{ "ip4-address-delete", "delete IPv4 address", do_ip4_address_delete, 2,
770  			"<ifname/ifindex> <address>/<plen>" },
771  		{ "ip6-address-delete", "delete IPv6 address", do_ip6_address_delete, 2,
772  			"<ifname/ifindex> <address>/<plen>" },
773  		{ "ip4-address-exists", "check for existence of IPv4 address", do_ip4_address_exists, 2,
774  			"<ifname/ifindex> <address>/<plen>" },
775  		{ "ip6-address-exists", "check for existence of IPv6 address", do_ip6_address_exists, 2,
776  			"<ifname/ifindex> <address>/<plen>" },
777  		{ "ip4-route-get-all", "print all IPv4 routes", do_ip4_route_get_all, 1, "<ifname/ifindex>" },
778  		{ "ip6-route-get-all", "print all IPv6 routes", do_ip6_route_get_all, 1, "<ifname/ifindex>" },
779  		{ "ip4-route-add", "add IPv4 route", do_ip4_route_add, 5,
780  			"<ifname/ifindex> <network>/<plen> <gateway> <metric> <mss>" },
781  		{ "ip6-route-add", "add IPv6 route", do_ip6_route_add, 5,
782  			"<ifname/ifindex> <network>/<plen> <gateway> <metric> <mss>" },
783  		{ "ip4-route-delete", "delete IPv4 route", do_ip4_route_delete, 3,
784  			"<ifname/ifindex> <network>/<plen> <metric>" },
785  		{ "ip6-route-delete", "delete IPv6 route", do_ip6_route_delete, 3,
786  			"<ifname/ifindex> <network>/<plen> <metric>" },
787  		{ "ip4-route-exists", "check for existence of IPv4 route", do_ip4_route_exists, 3,
788  			"<ifname/ifindex> <network>/<plen> <metric>" },
789  		{ "ip6-route-exists", "check for existence of IPv6 route", do_ip6_route_exists, 3,
790  			"<ifname/ifindex> <network>/<plen> <metric>" },
791  		{ NULL, NULL, NULL, 0, NULL },
792  	};
793  	
794  	int
795  	main (int argc, char **argv)
796  	{
797  		const char *arg0 = *argv++;
798  		const command_t *command = NULL;
799  		gboolean status = TRUE;
800  		int error;
801  	
802  		g_type_init ();
803  	
804  		if (*argv && !g_strcmp0 (argv[1], "--fake")) {
805  			nm_fake_platform_setup ();
806  		} else
807  			nm_linux_platform_setup ();
808  	
809  		if (*argv)
810  			for (command = commands; command->name; command++)
811  				if (g_str_has_prefix (command->name, *argv))
812  					break;
813  	
814  		if (command && command->name) {
815  			argv++;
816  			if (g_strv_length (argv) == command->argc)
817  				status = command->handler (argv);
818  			else {
819  				error ("Wrong number of arguments to '%s' (expected %d).\n\nUsage: %s %s %s\n-- %s\n",
820  						command->name, command->argc,
821  						arg0, command->name, command->arghelp, command->help);
822  				return EXIT_FAILURE;
823  			}
824  		} else {
825  			error ("Usage: %s COMMAND\n\n", arg0);
826  			error ("COMMAND\n");
827  			for (command = commands; command->name; command++)
828  				error ("  %s %s\n    -- %s\n", command->name, command->arghelp, command->help);
829  			error ("\n");
830  		}
831  	
832  		error = nm_platform_get_error ();
833  		if (error) {
834  			const char *msg = nm_platform_get_error_msg ();
835  	
836  			error ("nm-platform: %s\n", msg);
837  		}
838  	
839  		return !!error;
840  	}
841