1    	/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2    	
3    	/* NetworkManager -- Network link manager
4    	 *
5    	 * Ray Strode <rstrode@redhat.com>
6    	 * Dan Williams <dcbw@redhat.com>
7    	 * Tambet Ingo <tambet@gmail.com>
8    	 *
9    	 * This library is free software; you can redistribute it and/or
10   	 * modify it under the terms of the GNU Lesser General Public
11   	 * License as published by the Free Software Foundation; either
12   	 * version 2 of the License, or (at your option) any later version.
13   	 *
14   	 * This library is distributed in the hope that it will be useful,
15   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   	 * Lesser General Public License for more details.
18   	 *
19   	 * You should have received a copy of the GNU Lesser General Public
20   	 * License along with this library; if not, write to the
21   	 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22   	 * Boston, MA 02110-1301 USA.
23   	 *
24   	 * (C) Copyright 2005 - 2013 Red Hat, Inc.
25   	 */
26   	
27   	#include "config.h"
28   	
29   	#include <string.h>
30   	#include <stdlib.h>
31   	#include <netinet/ether.h>
32   	#include <linux/if_infiniband.h>
33   	#include <uuid/uuid.h>
34   	
35   	#include "nm-utils.h"
36   	#include "nm-utils-private.h"
37   	#include "nm-glib-compat.h"
38   	#include "nm-dbus-glib-types.h"
39   	#include "crypto.h"
40   	
41   	/**
42   	 * SECTION:nm-utils
43   	 * @short_description: Utility functions
44   	 * @include: nm-utils.h
45   	 *
46   	 * A collection of utility functions for working SSIDs, IP addresses, WiFi
47   	 * access points and devices, among other things.
48   	 */
49   	
50   	struct EncodingTriplet
51   	{
52   		const char *encoding1;
53   		const char *encoding2;
54   		const char *encoding3;
55   	};
56   	
57   	struct IsoLangToEncodings
58   	{
59   		const char *	lang;
60   		struct EncodingTriplet encodings;
61   	};
62   	
63   	/* 5-letter language codes */
64   	static const struct IsoLangToEncodings isoLangEntries5[] =
65   	{
66   		/* Simplified Chinese */
67   		{ "zh_cn",	{"euc-cn",	"gb2312",			"gb18030"} },	/* PRC */
68   		{ "zh_sg",	{"euc-cn",	"gb2312",			"gb18030"} },	/* Singapore */
69   	
70   		/* Traditional Chinese */
71   		{ "zh_tw",	{"big5",		"euc-tw",			NULL} },		/* Taiwan */
72   		{ "zh_hk",	{"big5",		"euc-tw",			"big5-hkcs"} },/* Hong Kong */
73   		{ "zh_mo",	{"big5",		"euc-tw",			NULL} },		/* Macau */
74   	
75   		/* Table end */
76   		{ NULL, {NULL, NULL, NULL} }
77   	};
78   	
79   	/* 2-letter language codes; we don't care about the other 3 in this table */
80   	static const struct IsoLangToEncodings isoLangEntries2[] =
81   	{
82   		/* Japanese */
83   		{ "ja",		{"euc-jp",	"shift_jis",		"iso-2022-jp"} },
84   	
85   		/* Korean */
86   		{ "ko",		{"euc-kr",	"iso-2022-kr",		"johab"} },
87   	
88   		/* Thai */
89   		{ "th",		{"iso-8859-11","windows-874",		NULL} },
90   	
91   		/* Central European */
92   		{ "hu",		{"iso-8859-2",	"windows-1250",	NULL} },	/* Hungarian */
93   		{ "cs",		{"iso-8859-2",	"windows-1250",	NULL} },	/* Czech */
94   		{ "hr",		{"iso-8859-2",	"windows-1250",	NULL} },	/* Croatian */
95   		{ "pl",		{"iso-8859-2",	"windows-1250",	NULL} },	/* Polish */
96   		{ "ro",		{"iso-8859-2",	"windows-1250",	NULL} },	/* Romanian */
97   		{ "sk",		{"iso-8859-2",	"windows-1250",	NULL} },	/* Slovakian */
98   		{ "sl",		{"iso-8859-2",	"windows-1250",	NULL} },	/* Slovenian */
99   		{ "sh",		{"iso-8859-2",	"windows-1250",	NULL} },	/* Serbo-Croatian */
100  	
101  		/* Cyrillic */
102  		{ "ru",		{"koi8-r",	"windows-1251",	"iso-8859-5"} },	/* Russian */
103  		{ "be",		{"koi8-r",	"windows-1251",	"iso-8859-5"} },	/* Belorussian */
104  		{ "bg",		{"windows-1251","koi8-r",		"iso-8859-5"} },	/* Bulgarian */
105  		{ "mk",		{"koi8-r",	"windows-1251",	"iso-8859-5"} },	/* Macedonian */
106  		{ "sr",		{"koi8-r",	"windows-1251",	"iso-8859-5"} },	/* Serbian */
107  		{ "uk",		{"koi8-u",	"koi8-r",			"windows-1251"} },	/* Ukranian */
108  	
109  		/* Arabic */
110  		{ "ar",		{"iso-8859-6",	"windows-1256",	NULL} },
111  	
112  		/* Baltic */
113  		{ "et",		{"iso-8859-4",	"windows-1257",	NULL} },	/* Estonian */
114  		{ "lt",		{"iso-8859-4",	"windows-1257",	NULL} },	/* Lithuanian */
115  		{ "lv",		{"iso-8859-4",	"windows-1257",	NULL} },	/* Latvian */
116  	
117  		/* Greek */
118  		{ "el",		{"iso-8859-7",	"windows-1253",	NULL} },
119  	
120  		/* Hebrew */
121  		{ "he",		{"iso-8859-8",	"windows-1255",	NULL} },
122  		{ "iw",		{"iso-8859-8",	"windows-1255",	NULL} },
123  	
124  		/* Turkish */
125  		{ "tr",		{"iso-8859-9",	"windows-1254",	NULL} },
126  	
127  		/* Table end */
128  		{ NULL, {NULL, NULL, NULL} }
129  	};
130  	
131  	
132  	static GHashTable * langToEncodings5 = NULL;
133  	static GHashTable * langToEncodings2 = NULL;
134  	
135  	static void
136  	init_lang_to_encodings_hash (void)
137  	{
138  		struct IsoLangToEncodings *enc;
139  	
140  		if (G_UNLIKELY (langToEncodings5 == NULL)) {
141  			/* Five-letter codes */
142  			enc = (struct IsoLangToEncodings *) &isoLangEntries5[0];
143  			langToEncodings5 = g_hash_table_new (g_str_hash, g_str_equal);
144  			while (enc->lang) {
145  				g_hash_table_insert (langToEncodings5, (gpointer) enc->lang,
146  						(gpointer) &enc->encodings);
147  				enc++;
148  			}
149  		}
150  	
151  		if (G_UNLIKELY (langToEncodings2 == NULL)) {
152  			/* Two-letter codes */
153  			enc = (struct IsoLangToEncodings *) &isoLangEntries2[0];
154  			langToEncodings2 = g_hash_table_new (g_str_hash, g_str_equal);
155  			while (enc->lang) {
156  				g_hash_table_insert (langToEncodings2, (gpointer) enc->lang,
157  						(gpointer) &enc->encodings);
158  				enc++;
159  			}
160  		}
161  	}
162  	
163  	
164  	static gboolean
165  	get_encodings_for_lang (const char *lang,
166  	                        char **encoding1,
167  	                        char **encoding2,
168  	                        char **encoding3)
169  	{
170  		struct EncodingTriplet *	encodings;
171  		gboolean				success = FALSE;
172  		char *				tmp_lang;
173  	
174  		g_return_val_if_fail (lang != NULL, FALSE);
175  		g_return_val_if_fail (encoding1 != NULL, FALSE);
176  		g_return_val_if_fail (encoding2 != NULL, FALSE);
177  		g_return_val_if_fail (encoding3 != NULL, FALSE);
178  	
179  		*encoding1 = "iso-8859-1";
180  		*encoding2 = "windows-1251";
181  		*encoding3 = NULL;
182  	
183  		init_lang_to_encodings_hash ();
184  	
185  		tmp_lang = g_strdup (lang);
186  		if ((encodings = g_hash_table_lookup (langToEncodings5, tmp_lang)))
187  		{
188  			*encoding1 = (char *) encodings->encoding1;
189  			*encoding2 = (char *) encodings->encoding2;
190  			*encoding3 = (char *) encodings->encoding3;
191  			success = TRUE;
192  		}
193  	
194  		/* Truncate tmp_lang to length of 2 */
195  		if (strlen (tmp_lang) > 2)
196  			tmp_lang[2] = '\0';
197  		if (!success && (encodings = g_hash_table_lookup (langToEncodings2, tmp_lang)))
198  		{
199  			*encoding1 = (char *) encodings->encoding1;
200  			*encoding2 = (char *) encodings->encoding2;
201  			*encoding3 = (char *) encodings->encoding3;
202  			success = TRUE;
203  		}
204  	
205  		g_free (tmp_lang);
206  		return success;
207  	}
208  	
209  	/* init, deinit for libnm_util */
210  	
211  	static gboolean initialized = FALSE;
212  	
213  	/**
214  	 * nm_utils_init:
215  	 * @error: location to store error, or %NULL
216  	 *
217  	 * Initializes libnm-util; should be called when starting and program that
218  	 * uses libnm-util.  Sets up an atexit() handler to ensure de-initialization
219  	 * is performed, but calling nm_utils_deinit() to explicitly deinitialize
220  	 * libnm-util can also be done.  This function can be called more than once.
221  	 * 
222  	 * Returns: TRUE if the initialization was successful, FALSE on failure.
223  	 **/
224  	gboolean
225  	nm_utils_init (GError **error)
226  	{
227  		if (!initialized) {
228  			initialized = TRUE;
229  	
230  			if (!crypto_init (error))
231  				return FALSE;
232  	
233  			_nm_value_transforms_register ();
234  		}
235  		return TRUE;
236  	}
237  	
238  	/**
239  	 * nm_utils_deinit:
240  	 *
241  	 * Frees all resources used internally by libnm-util.  This function is called
242  	 * from an atexit() handler, set up by nm_utils_init(), but is safe to be called
243  	 * more than once.  Subsequent calls have no effect until nm_utils_init() is
244  	 * called again.
245  	 **/
246  	void
247  	nm_utils_deinit (void)
248  	{
249  		if (initialized) {
250  			crypto_deinit ();
251  			initialized = FALSE;
252  		}
253  	}
254  	
255  	/* ssid helpers */
256  	
257  	/**
258  	 * nm_utils_ssid_to_utf8:
259  	 * @ssid: a byte array containing the SSID data
260  	 *
261  	 * WiFi SSIDs are byte arrays, they are _not_ strings.  Thus, an SSID may
262  	 * contain embedded NULLs and other unprintable characters.  Often it is
263  	 * useful to print the SSID out for debugging purposes, but that should be the
264  	 * _only_ use of this function.  Do not use this function for any persistent
265  	 * storage of the SSID, since the printable SSID returned from this function
266  	 * cannot be converted back into the real SSID of the access point.
267  	 *
268  	 * This function does almost everything humanly possible to convert the input
269  	 * into a printable UTF-8 string, using roughly the following procedure:
270  	 *
271  	 * 1) if the input data is already UTF-8 safe, no conversion is performed
272  	 * 2) attempts to get the current system language from the LANG environment
273  	 *    variable, and depending on the language, uses a table of alternative
274  	 *    encodings to try.  For example, if LANG=hu_HU, the table may first try
275  	 *    the ISO-8859-2 encoding, and if that fails, try the Windows-1250 encoding.
276  	 *    If all fallback encodings fail, replaces non-UTF-8 characters with '?'.
277  	 * 3) If the system language was unable to be determined, falls back to the
278  	 *    ISO-8859-1 encoding, then to the Windows-1251 encoding.
279  	 * 4) If step 3 fails, replaces non-UTF-8 characters with '?'.
280  	 *
281  	 * Again, this function should be used for debugging and display purposes
282  	 * _only_.
283  	 *
284  	 * Returns: (transfer full): an allocated string containing a UTF-8
285  	 * representation of the SSID, which must be freed by the caller using g_free().
286  	 * Returns %NULL on errors.
287  	 **/
288  	char *
289  	nm_utils_ssid_to_utf8 (const GByteArray *ssid)
290  	{
291  		char *converted = NULL;
292  		char *lang, *e1 = NULL, *e2 = NULL, *e3 = NULL;
293  	
294  		g_return_val_if_fail (ssid != NULL, NULL);
295  	
296  		if (g_utf8_validate ((const gchar *) ssid->data, ssid->len, NULL))
297  			return g_strndup ((const gchar *) ssid->data, ssid->len);
298  	
299  		/* LANG may be a good encoding hint */
300  		g_get_charset ((const char **)(&e1));
301  		if ((lang = getenv ("LANG"))) {
302  			char * dot;
303  	
304  			lang = g_ascii_strdown (lang, -1);
305  			if ((dot = strchr (lang, '.')))
306  				*dot = '\0';
307  	
308  			get_encodings_for_lang (lang, &e1, &e2, &e3);
309  			g_free (lang);
310  		}
311  	
312  		converted = g_convert ((const gchar *) ssid->data, ssid->len, "UTF-8", e1, NULL, NULL, NULL);
313  		if (!converted && e2)
314  			converted = g_convert ((const gchar *) ssid->data, ssid->len, "UTF-8", e2, NULL, NULL, NULL);
315  	
316  		if (!converted && e3)
317  			converted = g_convert ((const gchar *) ssid->data, ssid->len, "UTF-8", e3, NULL, NULL, NULL);
318  	
319  		if (!converted) {
320  			converted = g_convert_with_fallback ((const gchar *) ssid->data, ssid->len,
321  			                                     "UTF-8", e1, "?", NULL, NULL, NULL);
322  		}
323  	
324  		return converted;
325  	}
326  	
327  	/* Shamelessly ripped from the Linux kernel ieee80211 stack */
328  	/**
329  	 * nm_utils_is_empty_ssid:
330  	 * @ssid: pointer to a buffer containing the SSID data
331  	 * @len: length of the SSID data in @ssid
332  	 *
333  	 * Different manufacturers use different mechanisms for not broadcasting the
334  	 * AP's SSID.  This function attempts to detect blank/empty SSIDs using a
335  	 * number of known SSID-cloaking methods.
336  	 *
337  	 * Returns: TRUE if the SSID is "empty", FALSE if it is not
338  	 **/
339  	gboolean
340  	nm_utils_is_empty_ssid (const guint8 * ssid, int len)
341  	{
342  	        /* Single white space is for Linksys APs */
343  	        if (len == 1 && ssid[0] == ' ')
344  	                return TRUE;
345  	
346  	        /* Otherwise, if the entire ssid is 0, we assume it is hidden */
347  	        while (len--) {
348  	                if (ssid[len] != '\0')
349  	                        return FALSE;
350  	        }
351  	        return TRUE;
352  	}
353  	
354  	#define ESSID_MAX_SIZE 32
355  	
356  	/**
357  	 * nm_utils_escape_ssid:
358  	 * @ssid: pointer to a buffer containing the SSID data
359  	 * @len: length of the SSID data in @ssid
360  	 *
361  	 * This function does a quick printable character conversion of the SSID, simply
362  	 * replacing embedded NULLs and non-printable characters with the hexadecimal
363  	 * representation of that character.  Intended for debugging only, should not
364  	 * be used for display of SSIDs.
365  	 *
366  	 * Returns: pointer to the escaped SSID, which uses an internal static buffer
367  	 * and will be overwritten by subsequent calls to this function
368  	 **/
369  	const char *
370  	nm_utils_escape_ssid (const guint8 * ssid, guint32 len)
371  	{
372  		static char escaped[ESSID_MAX_SIZE * 2 + 1];
373  		const guint8 *s = ssid;
374  		char *d = escaped;
375  	
376  		if (nm_utils_is_empty_ssid (ssid, len)) {
377  			memcpy (escaped, "<hidden>", sizeof ("<hidden>"));
378  			return escaped;
379  		}
380  	
381  		len = MIN (len, (guint32) ESSID_MAX_SIZE);
382  		while (len--) {
383  			if (*s == '\0') {
384  				*d++ = '\\';
385  				*d++ = '0';
386  				s++;
387  			} else {
388  				*d++ = *s++;
389  			}
390  		}
391  		*d = '\0';
392  		return escaped;
393  	}
394  	
395  	/**
396  	 * nm_utils_same_ssid:
397  	 * @ssid1: first SSID data to compare
398  	 * @ssid2: second SSID data to compare
399  	 * @ignore_trailing_null: TRUE to ignore one trailing NULL byte
400  	 *
401  	 * Earlier versions of the Linux kernel added a NULL byte to the end of the
402  	 * SSID to enable easy printing of the SSID on the console or in a terminal,
403  	 * but this behavior was problematic (SSIDs are simply byte arrays, not strings)
404  	 * and thus was changed.  This function compensates for that behavior at the
405  	 * cost of some compatibility with odd SSIDs that may legitimately have trailing
406  	 * NULLs, even though that is functionally pointless.
407  	 *
408  	 * Returns: TRUE if the SSIDs are the same, FALSE if they are not
409  	 **/
410  	gboolean
411  	nm_utils_same_ssid (const GByteArray * ssid1,
412  	                    const GByteArray * ssid2,
413  	                    gboolean ignore_trailing_null)
414  	{
415  		guint32 ssid1_len, ssid2_len;
416  	
417  		if (ssid1 == ssid2)
418  			return TRUE;
419  		if ((ssid1 && !ssid2) || (!ssid1 && ssid2))
420  			return FALSE;
421  	
422  		ssid1_len = ssid1->len;
423  		ssid2_len = ssid2->len;
424  		if (ssid1_len && ssid2_len && ignore_trailing_null) {
425  			if (ssid1->data[ssid1_len - 1] == '\0')
426  				ssid1_len--;
427  			if (ssid2->data[ssid2_len - 1] == '\0')
428  				ssid2_len--;
429  		}
430  	
431  		if (ssid1_len != ssid2_len)
432  			return FALSE;
433  	
434  		return memcmp (ssid1->data, ssid2->data, ssid1_len) == 0 ? TRUE : FALSE;
435  	}
436  	
437  	static void
438  	value_destroy (gpointer data)
439  	{
440  		GValue *value = (GValue *) data;
441  	
442  		g_value_unset (value);
443  		g_slice_free (GValue, value);
444  	}
445  	
446  	static void
447  	value_dup (gpointer key, gpointer val, gpointer user_data)
448  	{
449  		GHashTable *table = (GHashTable *) user_data;
450  		GValue *value = (GValue *) val;
451  		GValue *dup_value;
452  	
453  		dup_value = g_slice_new0 (GValue);
454  		g_value_init (dup_value, G_VALUE_TYPE (val));
455  		g_value_copy (value, dup_value);
456  	
457  		g_hash_table_insert (table, g_strdup ((char *) key), dup_value);
458  	}
459  	
460  	/**
461  	 * nm_utils_gvalue_hash_dup:
462  	 * @hash: a #GHashTable mapping string:GValue
463  	 *
464  	 * Utility function to duplicate a hash table of #GValues.
465  	 *
466  	 * Returns: (transfer container) (element-type utf8 GObject.Value): a newly allocated duplicated #GHashTable, caller must free the
467  	 * returned hash with g_hash_table_unref() or g_hash_table_destroy()
468  	 **/
469  	GHashTable *
470  	nm_utils_gvalue_hash_dup (GHashTable *hash)
471  	{
472  		GHashTable *table;
473  	
474  		g_return_val_if_fail (hash != NULL, NULL);
475  	
476  		table = g_hash_table_new_full (g_str_hash, g_str_equal,
477  							    (GDestroyNotify) g_free,
478  							    value_destroy);
479  	
480  		g_hash_table_foreach (hash, value_dup, table);
481  	
482  		return table;
483  	}
484  	
485  	/**
486  	 * nm_utils_slist_free: (skip)
487  	 * @list: a #GSList
488  	 * @elem_destroy_fn: user function called for each element in @list
489  	 *
490  	 * Utility function to free a #GSList.
491  	 *
492  	 * Deprecated: use g_slist_free_full().
493  	 **/
494  	void
495  	nm_utils_slist_free (GSList *list, GDestroyNotify elem_destroy_fn)
496  	{
497  		g_slist_free_full (list, elem_destroy_fn);
498  	}
499  	
500  	gboolean
501  	_nm_utils_string_in_list (const char *str, const char **valid_strings)
502  	{
503  		int i;
504  	
505  		for (i = 0; valid_strings[i]; i++)
506  			if (strcmp (str, valid_strings[i]) == 0)
507  				break;
508  	
509  		return valid_strings[i] != NULL;
510  	}
511  	
512  	gboolean
513  	_nm_utils_string_slist_validate (GSList *list, const char **valid_values)
514  	{
515  		GSList *iter;
516  	
517  		for (iter = list; iter; iter = iter->next) {
518  			if (!_nm_utils_string_in_list ((char *) iter->data, valid_values))
519  				return FALSE;
520  		}
521  	
522  		return TRUE;
523  	}
524  	
525  	gboolean
526  	_nm_utils_gvalue_array_validate (GValueArray *elements, guint n_expected, ...)
527  	{
528  		va_list args;
529  		GValue *tmp;
530  		int i;
531  		gboolean valid = FALSE;
532  	
533  		if (n_expected != elements->n_values)
534  			return FALSE;
535  	
536  		va_start (args, n_expected);
537  		for (i = 0; i < n_expected; i++) {
538  			tmp = g_value_array_get_nth (elements, i);
539  			if (G_VALUE_TYPE (tmp) != va_arg (args, GType))
540  				goto done;
541  		}
542  		valid = TRUE;
543  	
544  	done:
545  		va_end (args);
546  		return valid;
547  	}
548  	
549  	static gboolean
550  	device_supports_ap_ciphers (guint32 dev_caps,
551  	                            guint32 ap_flags,
552  	                            gboolean static_wep)
553  	{
554  		gboolean have_pair = FALSE;
555  		gboolean have_group = FALSE;
556  		/* Device needs to support at least one pairwise and one group cipher */
557  	
558  		/* Pairwise */
559  		if (static_wep) {
560  			/* Static WEP only uses group ciphers */
561  			have_pair = TRUE;
562  		} else {
563  			if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
564  				if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP40)
565  					have_pair = TRUE;
566  			if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
567  				if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP104)
568  					have_pair = TRUE;
569  			if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
570  				if (ap_flags & NM_802_11_AP_SEC_PAIR_TKIP)
571  					have_pair = TRUE;
572  			if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
573  				if (ap_flags & NM_802_11_AP_SEC_PAIR_CCMP)
574  					have_pair = TRUE;
575  		}
576  	
577  		/* Group */
578  		if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
579  			if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP40)
580  				have_group = TRUE;
581  		if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
582  			if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP104)
583  				have_group = TRUE;
584  		if (!static_wep) {
585  			if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
586  				if (ap_flags & NM_802_11_AP_SEC_GROUP_TKIP)
587  					have_group = TRUE;
588  			if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
589  				if (ap_flags & NM_802_11_AP_SEC_GROUP_CCMP)
590  					have_group = TRUE;
591  		}
592  	
593  		return (have_pair && have_group);
594  	}
595  	
596  	/**
597  	 * nm_utils_ap_mode_security_valid:
598  	 * @type: the security type to check device capabilties against,
599  	 * e.g. #NMU_SEC_STATIC_WEP
600  	 * @wifi_caps: bitfield of the capabilities of the specific WiFi device, e.g.
601  	 * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
602  	 *
603  	 * Given a set of device capabilities, and a desired security type to check
604  	 * against, determines whether the combination of device capabilities and
605  	 * desired security type are valid for AP/Hotspot connections.
606  	 *
607  	 * Returns: TRUE if the device capabilities are compatible with the desired
608  	 * @type, FALSE if they are not.
609  	 *
610  	 * Since: 0.9.8
611  	 **/
612  	gboolean
613  	nm_utils_ap_mode_security_valid (NMUtilsSecurityType type,
614  	                                 NMDeviceWifiCapabilities wifi_caps)
615  	{
616  		if (!(wifi_caps & NM_WIFI_DEVICE_CAP_AP))
617  			return FALSE;
618  	
619  		/* Return TRUE for any security that wpa_supplicant's lightweight AP
620  		 * mode can handle: which is open, WEP, and WPA/WPA2 PSK.
621  		 */
622  		switch (type) {
623  		case NMU_SEC_NONE:
624  		case NMU_SEC_STATIC_WEP:
625  		case NMU_SEC_WPA_PSK:
626  		case NMU_SEC_WPA2_PSK:
627  			return TRUE;
628  		default:
629  			break;
630  		}
631  		return FALSE;
632  	}
633  	
634  	/**
635  	 * nm_utils_security_valid:
636  	 * @type: the security type to check AP flags and device capabilties against,
637  	 * e.g. #NMU_SEC_STATIC_WEP
638  	 * @wifi_caps: bitfield of the capabilities of the specific WiFi device, e.g.
639  	 * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
640  	 * @have_ap: whether the @ap_flags, @ap_wpa, and @ap_rsn arguments are valid
641  	 * @adhoc: whether the capabilities being tested are from an Ad-Hoc AP (IBSS)
642  	 * @ap_flags: bitfield of AP capabilities, e.g. #NM_802_11_AP_FLAGS_PRIVACY
643  	 * @ap_wpa: bitfield of AP capabilties derived from the AP's WPA beacon,
644  	 * e.g. (#NM_802_11_AP_SEC_PAIR_TKIP | #NM_802_11_AP_SEC_KEY_MGMT_PSK)
645  	 * @ap_rsn: bitfield of AP capabilties derived from the AP's RSN/WPA2 beacon,
646  	 * e.g. (#NM_802_11_AP_SEC_PAIR_CCMP | #NM_802_11_AP_SEC_PAIR_TKIP)
647  	 *
648  	 * Given a set of device capabilities, and a desired security type to check
649  	 * against, determines whether the combination of device, desired security
650  	 * type, and AP capabilities intersect.
651  	 *
652  	 * NOTE: this function cannot handle checking security for AP/Hotspot mode;
653  	 * use nm_utils_ap_mode_security_valid() instead.
654  	 *
655  	 * Returns: TRUE if the device capabilities and AP capabilties intersect and are
656  	 * compatible with the desired @type, FALSE if they are not
657  	 **/
658  	gboolean
659  	nm_utils_security_valid (NMUtilsSecurityType type,
660  	                         NMDeviceWifiCapabilities wifi_caps,
661  	                         gboolean have_ap,
662  	                         gboolean adhoc,
663  	                         NM80211ApFlags ap_flags,
664  	                         NM80211ApSecurityFlags ap_wpa,
665  	                         NM80211ApSecurityFlags ap_rsn)
666  	{
667  		gboolean good = TRUE;
668  	
669  		if (!have_ap) {
670  			if (type == NMU_SEC_NONE)
671  				return TRUE;
672  			if (   (type == NMU_SEC_STATIC_WEP)
673  			    || ((type == NMU_SEC_DYNAMIC_WEP) && !adhoc)
674  			    || ((type == NMU_SEC_LEAP) && !adhoc)) {
675  				if (wifi_caps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104))
676  					return TRUE;
677  				else 
678  					return FALSE;
679  			}
680  		}
681  	
682  		switch (type) {
683  		case NMU_SEC_NONE:
684  			g_assert (have_ap);
685  			if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
686  				return FALSE;
687  			if (ap_wpa || ap_rsn)
688  				return FALSE;
689  			break;
690  		case NMU_SEC_LEAP: /* require PRIVACY bit for LEAP? */
691  			if (adhoc)
692  				return FALSE;
693  			/* Fall through */
694  		case NMU_SEC_STATIC_WEP:
695  			g_assert (have_ap);
696  			if (!(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
697  				return FALSE;
698  			if (ap_wpa || ap_rsn) {
699  				if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, TRUE))
700  					if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, TRUE))
701  						return FALSE;
702  			}
703  			break;
704  		case NMU_SEC_DYNAMIC_WEP:
705  			if (adhoc)
706  				return FALSE;
707  			g_assert (have_ap);
708  			if (ap_rsn || !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
709  				return FALSE;
710  			/* Some APs broadcast minimal WPA-enabled beacons that must be handled */
711  			if (ap_wpa) {
712  				if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
713  					return FALSE;
714  				if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
715  					return FALSE;
716  			}
717  			break;
718  		case NMU_SEC_WPA_PSK:
(1) Event cond_const: Condition "adhoc", taking false branch. Now the value of "adhoc" is equal to 0.
Also see events: [const][dead_error_condition][dead_error_line]
719  			if (adhoc)
720  				return FALSE;  /* FIXME: Kernel WPA Ad-Hoc support is buggy */
721  			if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
722  				return FALSE;
723  			if (have_ap) {
724  				/* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
725  				 * they don't have any pairwise ciphers. */
(2) Event const: At condition "adhoc", the value of "adhoc" must be equal to 0.
(3) Event dead_error_condition: The condition "adhoc" cannot be true.
Also see events: [cond_const][dead_error_line]
726  				if (adhoc) {
(4) Event dead_error_line: Execution cannot reach this statement "if (ap_wpa & 0x40U && wifi_...".
Also see events: [cond_const][const][dead_error_condition]
727  					if (   (ap_wpa & NM_802_11_AP_SEC_GROUP_TKIP)
728  					    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
729  						return TRUE;
730  					if (   (ap_wpa & NM_802_11_AP_SEC_GROUP_CCMP)
731  					    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
732  						return TRUE;
733  				} else {
734  					if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
735  						if (   (ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
736  						    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
737  							return TRUE;
738  						if (   (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
739  						    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
740  							return TRUE;
741  					}
742  				}
743  				return FALSE;
744  			}
745  			break;
746  		case NMU_SEC_WPA2_PSK:
747  			if (adhoc)
748  				return FALSE;  /* FIXME: Kernel WPA Ad-Hoc support is buggy */
749  			if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
750  				return FALSE;
751  			if (have_ap) {
752  				/* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
753  				 * they don't have any pairwise ciphers, nor any RSA flags yet. */
754  				if (adhoc) {
755  					if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
756  						return TRUE;
757  					if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
758  						return TRUE;
759  				} else {
760  					if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
761  						if (   (ap_rsn & NM_802_11_AP_SEC_PAIR_TKIP)
762  						    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
763  							return TRUE;
764  						if (   (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
765  						    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
766  							return TRUE;
767  					}
768  				}
769  				return FALSE;
770  			}
771  			break;
772  		case NMU_SEC_WPA_ENTERPRISE:
773  			if (adhoc)
774  				return FALSE;
775  			if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
776  				return FALSE;
777  			if (have_ap) {
778  				if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
779  					return FALSE;
780  				/* Ensure at least one WPA cipher is supported */
781  				if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
782  					return FALSE;
783  			}
784  			break;
785  		case NMU_SEC_WPA2_ENTERPRISE:
786  			if (adhoc)
787  				return FALSE;
788  			if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
789  				return FALSE;
790  			if (have_ap) {
791  				if (!(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
792  					return FALSE;
793  				/* Ensure at least one WPA cipher is supported */
794  				if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, FALSE))
795  					return FALSE;
796  			}
797  			break;
798  		default:
799  			good = FALSE;
800  			break;
801  		}
802  	
803  		return good;
804  	}
805  	
806  	/**
807  	 * nm_utils_wep_key_valid:
808  	 * @key: a string that might be a WEP key
809  	 * @wep_type: the #NMWepKeyType type of the WEP key
810  	 *
811  	 * Checks if @key is a valid WEP key
812  	 *
813  	 * Returns: %TRUE if @key is a WEP key, %FALSE if not
814  	 *
815  	 * Since: 0.9.8
816  	 */
817  	gboolean
818  	nm_utils_wep_key_valid (const char *key, NMWepKeyType wep_type)
819  	{
820  		int keylen, i;
821  	
822  		if (!key)
823  			return FALSE;
824  	
825  		keylen = strlen (key);
826  		if (   wep_type == NM_WEP_KEY_TYPE_KEY
827  		    || wep_type == NM_WEP_KEY_TYPE_UNKNOWN) {
828  			if (keylen == 10 || keylen == 26) {
829  				/* Hex key */
830  				for (i = 0; i < keylen; i++) {
831  					if (!g_ascii_isxdigit (key[i]))
832  						return FALSE;
833  				}
834  			} else if (keylen == 5 || keylen == 13) {
835  				/* ASCII key */
836  				for (i = 0; i < keylen; i++) {
837  					if (!g_ascii_isprint (key[i]))
838  						return FALSE;
839  				}
840  			} else
841  				return FALSE;
842  	
843  		} else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
844  			if (!keylen || keylen > 64)
845  				return FALSE;
846  		}
847  	
848  		return TRUE;
849  	}
850  	
851  	/**
852  	 * nm_utils_wpa_psk_valid:
853  	 * @psk: a string that might be a WPA PSK
854  	 *
855  	 * Checks if @psk is a valid WPA PSK
856  	 *
857  	 * Returns: %TRUE if @psk is a WPA PSK, %FALSE if not
858  	 *
859  	 * Since: 0.9.8
860  	 */
861  	gboolean
862  	nm_utils_wpa_psk_valid (const char *psk)
863  	{
864  		int psklen, i;
865  	
866  		if (!psk)
867  			return FALSE;
868  	
869  		psklen = strlen (psk);
870  		if (psklen < 8 || psklen > 64)
871  			return FALSE;
872  	
873  		if (psklen == 64) {
874  			/* Hex PSK */
875  			for (i = 0; i < psklen; i++) {
876  				if (!g_ascii_isxdigit (psk[i]))
877  					return FALSE;
878  			}
879  		}
880  	
881  		return TRUE;
882  	}
883  	
884  	/**
885  	 * nm_utils_ip4_addresses_from_gvalue:
886  	 * @value: #GValue containing a #GPtrArray of #GArrays of #guint32s
887  	 *
888  	 * Utility function to convert a #GPtrArray of #GArrays of #guint32s representing
889  	 * a list of NetworkManager IPv4 addresses (which is a tuple of address, gateway,
890  	 * and prefix) into a #GSList of #NMIP4Address objects.  The specific format of
891  	 * this serialization is not guaranteed to be stable and the #GArray may be
892  	 * extended in the future.
893  	 *
894  	 * Returns: (transfer full) (element-type NetworkManager.IP4Address): a newly allocated #GSList of #NMIP4Address objects
895  	 **/
896  	GSList *
897  	nm_utils_ip4_addresses_from_gvalue (const GValue *value)
898  	{
899  		GPtrArray *addresses;
900  		int i;
901  		GSList *list = NULL;
902  	
903  		addresses = (GPtrArray *) g_value_get_boxed (value);
904  		for (i = 0; addresses && (i < addresses->len); i++) {
905  			GArray *array = (GArray *) g_ptr_array_index (addresses, i);
906  			NMIP4Address *addr;
907  	
908  			if (array->len < 3) {
909  				g_warning ("Ignoring invalid IP4 address");
910  				continue;
911  			}
912  			
913  			addr = nm_ip4_address_new ();
914  			nm_ip4_address_set_address (addr, g_array_index (array, guint32, 0));
915  			nm_ip4_address_set_prefix (addr, g_array_index (array, guint32, 1));
916  			nm_ip4_address_set_gateway (addr, g_array_index (array, guint32, 2));
917  			list = g_slist_prepend (list, addr);
918  		}
919  	
920  		return g_slist_reverse (list);
921  	}
922  	
923  	/**
924  	 * nm_utils_ip4_addresses_to_gvalue:
925  	 * @list: (element-type NMIP4Address): a list of #NMIP4Address objects
926  	 * @value: a pointer to a #GValue into which to place the converted addresses,
927  	 * which should be unset by the caller (when no longer needed) with
928  	 * g_value_unset().
929  	 *
930  	 * Utility function to convert a #GSList of #NMIP4Address objects into a
931  	 * #GPtrArray of #GArrays of #guint32s representing a list of NetworkManager IPv4
932  	 * addresses (which is a tuple of address, gateway, and prefix).   The specific
933  	 * format of this serialization is not guaranteed to be stable and may be
934  	 * extended in the future.
935  	 **/
936  	void
937  	nm_utils_ip4_addresses_to_gvalue (GSList *list, GValue *value)
938  	{
939  		GPtrArray *addresses;
940  		GSList *iter;
941  	
942  		addresses = g_ptr_array_new ();
943  	
944  		for (iter = list; iter; iter = iter->next) {
945  			NMIP4Address *addr = (NMIP4Address *) iter->data;
946  			GArray *array;
947  			guint32 tmp;
948  	
949  			array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
950  	
951  			tmp = nm_ip4_address_get_address (addr);
952  			g_array_append_val (array, tmp);
953  	
954  			tmp = nm_ip4_address_get_prefix (addr);
955  			g_array_append_val (array, tmp);
956  	
957  			tmp = nm_ip4_address_get_gateway (addr);
958  			g_array_append_val (array, tmp);
959  	
960  			g_ptr_array_add (addresses, array);
961  		}
962  	
963  		g_value_take_boxed (value, addresses);
964  	}
965  	
966  	/**
967  	 * nm_utils_ip4_routes_from_gvalue:
968  	 * @value: #GValue containing a #GPtrArray of #GArrays of #guint32s
969  	 *
970  	 * Utility function to convert a #GPtrArray of #GArrays of #guint32s representing
971  	 * a list of NetworkManager IPv4 routes (which is a tuple of route, next hop,
972  	 * prefix, and metric) into a #GSList of #NMIP4Route objects.  The specific
973  	 * format of this serialization is not guaranteed to be stable and may be
974  	 * extended in the future.
975  	 *
976  	 * Returns: (transfer full) (element-type NetworkManager.IP4Route): a newly allocated #GSList of #NMIP4Route objects
977  	 **/
978  	GSList *
979  	nm_utils_ip4_routes_from_gvalue (const GValue *value)
980  	{
981  		GPtrArray *routes;
982  		int i;
983  		GSList *list = NULL;
984  	
985  		routes = (GPtrArray *) g_value_get_boxed (value);
986  		for (i = 0; routes && (i < routes->len); i++) {
987  			GArray *array = (GArray *) g_ptr_array_index (routes, i);
988  			NMIP4Route *route;
989  	
990  			if (array->len < 4) {
991  				g_warning ("Ignoring invalid IP4 route");
992  				continue;
993  			}
994  			
995  			route = nm_ip4_route_new ();
996  			nm_ip4_route_set_dest (route, g_array_index (array, guint32, 0));
997  			nm_ip4_route_set_prefix (route, g_array_index (array, guint32, 1));
998  			nm_ip4_route_set_next_hop (route, g_array_index (array, guint32, 2));
999  			nm_ip4_route_set_metric (route, g_array_index (array, guint32, 3));
1000 			list = g_slist_prepend (list, route);
1001 		}
1002 	
1003 		return g_slist_reverse (list);
1004 	}
1005 	
1006 	/**
1007 	 * nm_utils_ip4_routes_to_gvalue:
1008 	 * @list: (element-type NMIP4Route): a list of #NMIP4Route objects
1009 	 * @value: a pointer to a #GValue into which to place the converted routes,
1010 	 * which should be unset by the caller (when no longer needed) with
1011 	 * g_value_unset().
1012 	 *
1013 	 * Utility function to convert a #GSList of #NMIP4Route objects into a
1014 	 * #GPtrArray of #GArrays of #guint32s representing a list of NetworkManager IPv4
1015 	 * routes (which is a tuple of route, next hop, prefix, and metric).   The
1016 	 * specific format of this serialization is not guaranteed to be stable and may
1017 	 * be extended in the future.
1018 	 **/
1019 	void
1020 	nm_utils_ip4_routes_to_gvalue (GSList *list, GValue *value)
1021 	{
1022 		GPtrArray *routes;
1023 		GSList *iter;
1024 	
1025 		routes = g_ptr_array_new ();
1026 	
1027 		for (iter = list; iter; iter = iter->next) {
1028 			NMIP4Route *route = (NMIP4Route *) iter->data;
1029 			GArray *array;
1030 			guint32 tmp;
1031 	
1032 			array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
1033 	
1034 			tmp = nm_ip4_route_get_dest (route);
1035 			g_array_append_val (array, tmp);
1036 	
1037 			tmp = nm_ip4_route_get_prefix (route);
1038 			g_array_append_val (array, tmp);
1039 	
1040 			tmp = nm_ip4_route_get_next_hop (route);
1041 			g_array_append_val (array, tmp);
1042 	
1043 			tmp = nm_ip4_route_get_metric (route);
1044 			g_array_append_val (array, tmp);
1045 	
1046 			g_ptr_array_add (routes, array);
1047 		}
1048 	
1049 		g_value_take_boxed (value, routes);
1050 	}
1051 	
1052 	/**
1053 	 * nm_utils_ip4_netmask_to_prefix:
1054 	 * @netmask: an IPv4 netmask in network byte order
1055 	 *
1056 	 * Returns: the CIDR prefix represented by the netmask
1057 	 **/
1058 	guint32
1059 	nm_utils_ip4_netmask_to_prefix (guint32 netmask)
1060 	{
1061 		guchar *p, *end;
1062 		guint32 prefix = 0;
1063 	
1064 		p = (guchar *) &netmask;
1065 		end = p + sizeof (guint32);
1066 	
1067 		while ((*p == 0xFF) && p < end) {
1068 			prefix += 8;
1069 			p++;
1070 		}
1071 	
1072 		if (p < end) {
1073 			guchar v = *p;
1074 	
1075 			while (v) {
1076 				prefix++;
1077 				v <<= 1;
1078 			}
1079 		}
1080 	
1081 		return prefix;
1082 	}
1083 	
1084 	/**
1085 	 * nm_utils_ip4_prefix_to_netmask:
1086 	 * @prefix: a CIDR prefix
1087 	 *
1088 	 * Returns: the netmask represented by the prefix, in network byte order
1089 	 **/
1090 	guint32
1091 	nm_utils_ip4_prefix_to_netmask (guint32 prefix)
1092 	{
1093 		guint32 msk = 0x80000000;
1094 		guint32 netmask = 0;
1095 	
1096 		while (prefix > 0) {
1097 			netmask |= msk;
1098 			msk >>= 1;
1099 			prefix--;
1100 		}
1101 	
1102 		return (guint32) htonl (netmask);
1103 	}
1104 	
1105 	
1106 	/**
1107 	 * nm_utils_ip4_get_default_prefix:
1108 	 * @ip: an IPv4 address (in network byte order)
1109 	 *
1110 	 * When the Internet was originally set up, various ranges of IP addresses were
1111 	 * segmented into three network classes: A, B, and C.  This function will return
1112 	 * a prefix that is associated with the IP address specified defining where it
1113 	 * falls in the predefined classes.
1114 	 *
1115 	 * Returns: the default class prefix for the given IP
1116 	 **/
1117 	/* The function is originally from ipcalc.c of Red Hat's initscripts. */
1118 	guint32
1119 	nm_utils_ip4_get_default_prefix (guint32 ip)
1120 	{
1121 		if (((ntohl (ip) & 0xFF000000) >> 24) <= 127)
1122 			return 8;  /* Class A - 255.0.0.0 */
1123 		else if (((ntohl (ip) & 0xFF000000) >> 24) <= 191)
1124 			return 16;  /* Class B - 255.255.0.0 */
1125 	
1126 		return 24;  /* Class C - 255.255.255.0 */
1127 	}
1128 	
1129 	/**
1130 	 * nm_utils_ip6_addresses_from_gvalue:
1131 	 * @value: gvalue containing a GPtrArray of GValueArrays of (GArray of guchars) and #guint32
1132 	 *
1133 	 * Utility function to convert a #GPtrArray of #GValueArrays of (#GArray of guchars) and #guint32
1134 	 * representing a list of NetworkManager IPv6 addresses (which is a tuple of address,
1135 	 * prefix, and gateway), into a #GSList of #NMIP6Address objects.  The specific format of
1136 	 * this serialization is not guaranteed to be stable and the #GValueArray may be
1137 	 * extended in the future.
1138 	 *
1139 	 * Returns: (transfer full) (element-type NetworkManager.IP6Address): a newly allocated #GSList of #NMIP6Address objects
1140 	 **/
1141 	GSList *
1142 	nm_utils_ip6_addresses_from_gvalue (const GValue *value)
1143 	{
1144 		GPtrArray *addresses;
1145 		int i;
1146 		GSList *list = NULL;
1147 	
1148 		addresses = (GPtrArray *) g_value_get_boxed (value);
1149 	
1150 		for (i = 0; addresses && (i < addresses->len); i++) {
1151 			GValueArray *elements = (GValueArray *) g_ptr_array_index (addresses, i);
1152 			GValue *tmp;
1153 			GByteArray *ba_addr;
1154 			GByteArray *ba_gw = NULL;
1155 			NMIP6Address *addr;
1156 			guint32 prefix;
1157 	
1158 			if (elements->n_values < 2 || elements->n_values > 3) {
1159 				g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1160 				continue;
1161 			}
1162 	
1163 			/* Third element (gateway) is optional */
1164 			if (   !_nm_utils_gvalue_array_validate (elements, 2, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT)
1165 			    && !_nm_utils_gvalue_array_validate (elements, 3, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY)) {
1166 				g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1167 				continue;
1168 			}
1169 	
1170 			tmp = g_value_array_get_nth (elements, 0);
1171 			ba_addr = g_value_get_boxed (tmp);
1172 			if (ba_addr->len != 16) {
1173 				g_warning ("%s: ignoring invalid IP6 address of length %d",
1174 				            __func__, ba_addr->len);
1175 				continue;
1176 			}
1177 	
1178 			tmp = g_value_array_get_nth (elements, 1);
1179 			prefix = g_value_get_uint (tmp);
1180 			if (prefix > 128) {
1181 				g_warning ("%s: ignoring invalid IP6 prefix %d",
1182 				            __func__, prefix);
1183 				continue;
1184 			}
1185 	
1186 			if (elements->n_values == 3) {
1187 				tmp = g_value_array_get_nth (elements, 2);
1188 				ba_gw = g_value_get_boxed (tmp);
1189 				if (ba_gw->len != 16) {
1190 					g_warning ("%s: ignoring invalid IP6 gateway address of length %d",
1191 					            __func__, ba_gw->len);
1192 					continue;
1193 				}
1194 			}
1195 	
1196 			addr = nm_ip6_address_new ();
1197 			nm_ip6_address_set_prefix (addr, prefix);
1198 			nm_ip6_address_set_address (addr, (const struct in6_addr *) ba_addr->data);
1199 			if (ba_gw)
1200 				nm_ip6_address_set_gateway (addr, (const struct in6_addr *) ba_gw->data);
1201 	
1202 			list = g_slist_prepend (list, addr);
1203 		}
1204 	
1205 		return g_slist_reverse (list);
1206 	}
1207 	
1208 	/**
1209 	 * nm_utils_ip6_addresses_to_gvalue:
1210 	 * @list: (element-type NMIP6Address): a list of #NMIP6Address objects
1211 	 * @value: a pointer to a #GValue into which to place the converted addresses,
1212 	 * which should be unset by the caller (when no longer needed) with
1213 	 * g_value_unset().
1214 	 *
1215 	 * Utility function to convert a #GSList of #NMIP6Address objects into a
1216 	 * #GPtrArray of #GValueArrays representing a list of NetworkManager IPv6 addresses
1217 	 * (which is a tuple of address, prefix, and gateway). The specific format of
1218 	 * this serialization is not guaranteed to be stable and may be extended in the
1219 	 * future.
1220 	 **/
1221 	void
1222 	nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value)
1223 	{
1224 		GPtrArray *addresses;
1225 		GSList *iter;
1226 	
1227 		addresses = g_ptr_array_new ();
1228 	
1229 		for (iter = list; iter; iter = iter->next) {
1230 			NMIP6Address *addr = (NMIP6Address *) iter->data;
1231 			GValueArray *array;
1232 			GValue element = G_VALUE_INIT;
1233 			GByteArray *ba;
1234 	
1235 			array = g_value_array_new (3);
1236 	
1237 			/* IP address */
1238 			g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1239 			ba = g_byte_array_new ();
1240 			g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_address (addr), 16);
1241 			g_value_take_boxed (&element, ba);
1242 			g_value_array_append (array, &element);
1243 			g_value_unset (&element);
1244 	
1245 			/* Prefix */
1246 			g_value_init (&element, G_TYPE_UINT);
1247 			g_value_set_uint (&element, nm_ip6_address_get_prefix (addr));
1248 			g_value_array_append (array, &element);
1249 			g_value_unset (&element);
1250 	
1251 			/* Gateway */
1252 			g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1253 			ba = g_byte_array_new ();
1254 			g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_gateway (addr), 16);
1255 			g_value_take_boxed (&element, ba);
1256 			g_value_array_append (array, &element);
1257 			g_value_unset (&element);
1258 	
1259 			g_ptr_array_add (addresses, array);
1260 		}
1261 	
1262 		g_value_take_boxed (value, addresses);
1263 	}
1264 	
1265 	/**
1266 	 * nm_utils_ip6_routes_from_gvalue:
1267 	 * @value: #GValue containing a #GPtrArray of #GValueArrays of (#GArray of #guchars), #guint32,
1268 	 * (#GArray of #guchars), and #guint32
1269 	 *
1270 	 * Utility function #GPtrArray of #GValueArrays of (#GArray of #guchars), #guint32,
1271 	 * (#GArray of #guchars), and #guint32 representing a list of NetworkManager IPv6
1272 	 * routes (which is a tuple of destination, prefix, next hop, and metric)
1273 	 * into a #GSList of #NMIP6Route objects.  The specific format of this serialization
1274 	 * is not guaranteed to be stable and may be extended in the future.
1275 	 *
1276 	 * Returns: (transfer full) (element-type NetworkManager.IP6Route): a newly allocated #GSList of #NMIP6Route objects
1277 	 **/
1278 	GSList *
1279 	nm_utils_ip6_routes_from_gvalue (const GValue *value)
1280 	{
1281 		GPtrArray *routes;
1282 		int i;
1283 		GSList *list = NULL;
1284 	
1285 		routes = (GPtrArray *) g_value_get_boxed (value);
1286 		for (i = 0; routes && (i < routes->len); i++) {
1287 			GValueArray *route_values = (GValueArray *) g_ptr_array_index (routes, i);
1288 			GByteArray *dest, *next_hop;
1289 			guint prefix, metric;
1290 			NMIP6Route *route;
1291 	
1292 			if (!_nm_utils_gvalue_array_validate (route_values, 4,
1293 			                                      DBUS_TYPE_G_UCHAR_ARRAY,
1294 			                                      G_TYPE_UINT,
1295 			                                      DBUS_TYPE_G_UCHAR_ARRAY,
1296 			                                      G_TYPE_UINT)) {
1297 				g_warning ("Ignoring invalid IP6 route");
1298 				continue;
1299 			}
1300 	
1301 			dest = g_value_get_boxed (g_value_array_get_nth (route_values, 0));
1302 			if (dest->len != 16) {
1303 				g_warning ("%s: ignoring invalid IP6 dest address of length %d",
1304 				            __func__, dest->len);
1305 				continue;
1306 			}
1307 	
1308 			prefix = g_value_get_uint (g_value_array_get_nth (route_values, 1));
1309 	
1310 			next_hop = g_value_get_boxed (g_value_array_get_nth (route_values, 2));
1311 			if (next_hop->len != 16) {
1312 				g_warning ("%s: ignoring invalid IP6 next_hop address of length %d",
1313 				            __func__, next_hop->len);
1314 				continue;
1315 			}
1316 	
1317 			metric = g_value_get_uint (g_value_array_get_nth (route_values, 3));
1318 	
1319 			route = nm_ip6_route_new ();
1320 			nm_ip6_route_set_dest (route, (struct in6_addr *)dest->data);
1321 			nm_ip6_route_set_prefix (route, prefix);
1322 			nm_ip6_route_set_next_hop (route, (struct in6_addr *)next_hop->data);
1323 			nm_ip6_route_set_metric (route, metric);
1324 			list = g_slist_prepend (list, route);
1325 		}
1326 	
1327 		return g_slist_reverse (list);
1328 	}
1329 	
1330 	/**
1331 	 * nm_utils_ip6_routes_to_gvalue:
1332 	 * @list: (element-type NMIP6Route): a list of #NMIP6Route objects
1333 	 * @value: a pointer to a #GValue into which to place the converted routes,
1334 	 * which should be unset by the caller (when no longer needed) with
1335 	 * g_value_unset().
1336 	 *
1337 	 * Utility function to convert a #GSList of #NMIP6Route objects into a #GPtrArray of
1338 	 * #GValueArrays of (#GArray of #guchars), #guint32, (#GArray of #guchars), and #guint32
1339 	 * representing a list of NetworkManager IPv6 routes (which is a tuple of destination,
1340 	 * prefix, next hop, and metric).  The specific format of this serialization is not 
1341 	 * guaranteed to be stable and may be extended in the future.
1342 	 **/
1343 	void
1344 	nm_utils_ip6_routes_to_gvalue (GSList *list, GValue *value)
1345 	{
1346 		GPtrArray *routes;
1347 		GSList *iter;
1348 	
1349 		routes = g_ptr_array_new ();
1350 	
1351 		for (iter = list; iter; iter = iter->next) {
1352 			NMIP6Route *route = (NMIP6Route *) iter->data;
1353 			GValueArray *array;
1354 			const struct in6_addr *addr;
1355 			GByteArray *ba;
1356 			GValue element = G_VALUE_INIT;
1357 	
1358 			array = g_value_array_new (4);
1359 	
1360 			g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1361 			addr = nm_ip6_route_get_dest (route);
1362 			ba = g_byte_array_new ();
1363 			g_byte_array_append (ba, (guchar *)addr, sizeof (*addr));
1364 			g_value_take_boxed (&element, ba);
1365 			g_value_array_append (array, &element);
1366 			g_value_unset (&element);
1367 	
1368 			g_value_init (&element, G_TYPE_UINT);
1369 			g_value_set_uint (&element, nm_ip6_route_get_prefix (route));
1370 			g_value_array_append (array, &element);
1371 			g_value_unset (&element);
1372 	
1373 			g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1374 			addr = nm_ip6_route_get_next_hop (route);
1375 			ba = g_byte_array_new ();
1376 			g_byte_array_append (ba, (guchar *)addr, sizeof (*addr));
1377 			g_value_take_boxed (&element, ba);
1378 			g_value_array_append (array, &element);
1379 			g_value_unset (&element);
1380 	
1381 			g_value_init (&element, G_TYPE_UINT);
1382 			g_value_set_uint (&element, nm_ip6_route_get_metric (route));
1383 			g_value_array_append (array, &element);
1384 			g_value_unset (&element);
1385 	
1386 			g_ptr_array_add (routes, array);
1387 		}
1388 	
1389 		g_value_take_boxed (value, routes);
1390 	}
1391 	
1392 	/**
1393 	 * nm_utils_ip6_dns_from_gvalue: (skip)
1394 	 * @value: a #GValue
1395 	 *
1396 	 * Converts a #GValue containing a #GPtrArray of IP6 DNS, represented as
1397 	 * #GByteArrays into a #GSList of <literal><type>struct in6_addr</type></literal>s.
1398 	 *
1399 	 * Returns: a #GSList of IP6 addresses.
1400 	 */
1401 	GSList *
1402 	nm_utils_ip6_dns_from_gvalue (const GValue *value)
1403 	{
1404 		GPtrArray *dns;
1405 		int i;
1406 		GSList *list = NULL;
1407 	
1408 		dns = (GPtrArray *) g_value_get_boxed (value);
1409 		for (i = 0; dns && (i < dns->len); i++) {
1410 			GByteArray *bytearray = (GByteArray *) g_ptr_array_index (dns, i);
1411 			struct in6_addr *addr;
1412 	
1413 			if (bytearray->len != 16) {
1414 				g_warning ("%s: ignoring invalid IP6 address of length %d",
1415 				           __func__, bytearray->len);
1416 				continue;
1417 			}
1418 	
1419 			addr = g_malloc0 (sizeof (struct in6_addr));
1420 			memcpy (addr->s6_addr, bytearray->data, bytearray->len);
1421 			list = g_slist_prepend (list, addr);
1422 		}
1423 	
1424 		return g_slist_reverse (list);
1425 	}
1426 	
1427 	/**
1428 	 * nm_utils_ip6_dns_to_gvalue: (skip)
1429 	 * @list: a list of #NMIP6Route objects
1430 	 * @value: a pointer to a #GValue into which to place the converted DNS server
1431 	 * addresses, which should be unset by the caller (when no longer needed) with
1432 	 * g_value_unset().
1433 	 *
1434 	 * Utility function to convert a #GSList of <literal><type>struct
1435 	 * in6_addr</type></literal> structs into a #GPtrArray of #GByteArrays
1436 	 * representing each server's IPv6 addresses in network byte order.
1437 	 * The specific format of this serialization is not guaranteed to be
1438 	 * stable and may be extended in the future.
1439 	 */
1440 	void
1441 	nm_utils_ip6_dns_to_gvalue (GSList *list, GValue *value)
1442 	{
1443 		GPtrArray *dns;
1444 		GSList *iter;
1445 	
1446 		dns = g_ptr_array_new ();
1447 	
1448 		for (iter = list; iter; iter = iter->next) {
1449 			struct in6_addr *addr = (struct in6_addr *) iter->data;
1450 			GByteArray *bytearray;
1451 	
1452 			bytearray = g_byte_array_sized_new (16);
1453 			g_byte_array_append (bytearray, (guint8 *) addr->s6_addr, 16);
1454 			g_ptr_array_add (dns, bytearray);
1455 		}
1456 	
1457 		g_value_take_boxed (value, dns);
1458 	}
1459 	
1460 	/**
1461 	 * nm_utils_uuid_generate:
1462 	 *
1463 	 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
1464 	 * object's #NMSettingConnection:id: property.  Should be freed with g_free()
1465 	 **/
1466 	char *
1467 	nm_utils_uuid_generate (void)
1468 	{
1469 		uuid_t uuid;
1470 		char *buf;
1471 	
1472 		buf = g_malloc0 (37);
1473 		uuid_generate_random (uuid);
1474 		uuid_unparse_lower (uuid, &buf[0]);
1475 		return buf;
1476 	}
1477 	
1478 	/**
1479 	 * nm_utils_uuid_generate_from_string:
1480 	 * @s: a string to use as the seed for the UUID
1481 	 *
1482 	 * For a given @s, this function will always return the same UUID.
1483 	 *
1484 	 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
1485 	 * object's #NMSettingConnection:id: property
1486 	 **/
1487 	char *
1488 	nm_utils_uuid_generate_from_string (const char *s)
1489 	{
1490 		GError *error = NULL;
1491 		uuid_t *uuid;
1492 		char *buf = NULL;
1493 	
1494 		if (!nm_utils_init (&error)) {
1495 			g_warning ("error initializing crypto: (%d) %s",
1496 			           error ? error->code : 0,
1497 			           error ? error->message : "unknown");
1498 			if (error)
1499 				g_error_free (error);
1500 			return NULL;
1501 		}
1502 	
1503 		uuid = g_malloc0 (sizeof (*uuid));
1504 		if (!crypto_md5_hash (NULL, 0, s, strlen (s), (char *) uuid, sizeof (*uuid), &error)) {
1505 			g_warning ("error generating UUID: (%d) %s",
1506 			           error ? error->code : 0,
1507 			           error ? error->message : "unknown");
1508 			if (error)
1509 				g_error_free (error);
1510 			goto out;
1511 		}
1512 	
1513 		buf = g_malloc0 (37);
1514 		uuid_unparse_lower (*uuid, &buf[0]);
1515 	
1516 	out:
1517 		g_free (uuid);
1518 		return buf;
1519 	}
1520 	
1521 	static char *
1522 	make_key (const char *salt,
1523 	          const gsize salt_len,
1524 	          const char *password,
1525 	          gsize *out_len,
1526 	          GError **error)
1527 	{
1528 		char *key;
1529 		guint32 digest_len = 24; /* DES-EDE3-CBC */
1530 	
1531 		g_return_val_if_fail (salt != NULL, NULL);
1532 		g_return_val_if_fail (salt_len >= 8, NULL);
1533 		g_return_val_if_fail (password != NULL, NULL);
1534 		g_return_val_if_fail (out_len != NULL, NULL);
1535 	
1536 		key = g_malloc0 (digest_len + 1);
1537 	
1538 		if (!crypto_md5_hash (salt, salt_len, password, strlen (password), key, digest_len, error)) {
1539 			*out_len = 0;
1540 			memset (key, 0, digest_len);
1541 			g_free (key);
1542 			key = NULL;
1543 		} else
1544 			*out_len = digest_len;
1545 	
1546 		return key;
1547 	}
1548 	
1549 	/**
1550 	 * nm_utils_rsa_key_encrypt:
1551 	 * @data: RSA private key data to be encrypted
1552 	 * @in_password: (allow-none): existing password to use, if any
1553 	 * @out_password: (out) (allow-none): if @in_password was %NULL, a random password will be generated
1554 	 *  and returned in this argument
1555 	 * @error: detailed error information on return, if an error occurred
1556 	 *
1557 	 * Encrypts the given RSA private key data with the given password (or generates
1558 	 * a password if no password was given) and converts the data to PEM format
1559 	 * suitable for writing to a file.
1560 	 *
1561 	 * Returns: (transfer full): on success, PEM-formatted data suitable for writing to a PEM-formatted
1562 	 * certificate/private key file.
1563 	 **/
1564 	GByteArray *
1565 	nm_utils_rsa_key_encrypt (const GByteArray *data,
1566 	                          const char *in_password,
1567 	                          char **out_password,
1568 	                          GError **error)
1569 	{
1570 		char salt[8];
1571 		char *key = NULL, *enc = NULL, *pw_buf[32];
1572 		gsize key_len = 0, enc_len = 0;
1573 		GString *pem = NULL;
1574 		char *tmp, *tmp_password = NULL;
1575 		int left;
1576 		const char *p;
1577 		GByteArray *ret = NULL;
1578 	
1579 		g_return_val_if_fail (data != NULL, NULL);
1580 		g_return_val_if_fail (data->len > 0, NULL);
1581 		if (out_password)
1582 			g_return_val_if_fail (*out_password == NULL, NULL);
1583 	
1584 		/* Make the password if needed */
1585 		if (!in_password) {
1586 			if (!crypto_randomize (pw_buf, sizeof (pw_buf), error))
1587 				return NULL;
1588 			in_password = tmp_password = nm_utils_bin2hexstr ((const char *) pw_buf, sizeof (pw_buf), -1);
1589 		}
1590 	
1591 		if (!crypto_randomize (salt, sizeof (salt), error))
1592 			goto out;
1593 	
1594 		key = make_key (&salt[0], sizeof (salt), in_password, &key_len, error);
1595 		if (!key)
1596 			goto out;
1597 	
1598 		enc = crypto_encrypt (CIPHER_DES_EDE3_CBC, data, salt, sizeof (salt), key, key_len, &enc_len, error);
1599 		if (!enc)
1600 			goto out;
1601 	
1602 		pem = g_string_sized_new (enc_len * 2 + 100);
1603 		g_string_append (pem, "-----BEGIN RSA PRIVATE KEY-----\n");
1604 		g_string_append (pem, "Proc-Type: 4,ENCRYPTED\n");
1605 	
1606 		/* Convert the salt to a hex string */
1607 		tmp = nm_utils_bin2hexstr ((const char *) salt, sizeof (salt), 16);
1608 		g_string_append_printf (pem, "DEK-Info: DES-EDE3-CBC,%s\n\n", tmp);
1609 		g_free (tmp);
1610 	
1611 		/* Convert the encrypted key to a base64 string */
1612 		p = tmp = g_base64_encode ((const guchar *) enc, enc_len);
1613 		left = strlen (tmp);
1614 		while (left > 0) {
1615 			g_string_append_len (pem, p, (left < 64) ? left : 64);
1616 			g_string_append_c (pem, '\n');
1617 			left -= 64;
1618 			p += 64;
1619 		}
1620 		g_free (tmp);
1621 	
1622 		g_string_append (pem, "-----END RSA PRIVATE KEY-----\n");
1623 	
1624 		ret = g_byte_array_sized_new (pem->len);
1625 		g_byte_array_append (ret, (const unsigned char *) pem->str, pem->len);
1626 		if (tmp_password && out_password)
1627 			*out_password = g_strdup (tmp_password);
1628 	
1629 	out:
1630 		if (key) {
1631 			memset (key, 0, key_len);
1632 			g_free (key);
1633 		}
1634 		if (enc) {
1635 			memset (enc, 0, enc_len);
1636 			g_free (enc);
1637 		}
1638 		if (pem)
1639 			g_string_free (pem, TRUE);
1640 	
1641 		if (tmp_password) {
1642 			memset (tmp_password, 0, strlen (tmp_password));
1643 			g_free (tmp_password);
1644 		}
1645 	
1646 		return ret;
1647 	}
1648 	
1649 	/**
1650 	 * nm_utils_file_is_pkcs12:
1651 	 * @filename: name of the file to test
1652 	 *
1653 	 * Utility function to find out if the @filename is in PKCS#12 format.
1654 	 *
1655 	 * Returns: TRUE if the file is PKCS#12, FALSE if it is not
1656 	 **/
1657 	gboolean
1658 	nm_utils_file_is_pkcs12 (const char *filename)
1659 	{
1660 		return crypto_is_pkcs12_file (filename, NULL);
1661 	}
1662 	
1663 	/* Band, channel/frequency stuff for wireless */
1664 	struct cf_pair {
1665 		guint32 chan;
1666 		guint32 freq;
1667 	};
1668 	
1669 	static struct cf_pair a_table[] = {
1670 		/* A band */
1671 		{  7, 5035 },
1672 		{  8, 5040 },
1673 		{  9, 5045 },
1674 		{ 11, 5055 },
1675 		{ 12, 5060 },
1676 		{ 16, 5080 },
1677 		{ 34, 5170 },
1678 		{ 36, 5180 },
1679 		{ 38, 5190 },
1680 		{ 40, 5200 },
1681 		{ 42, 5210 },
1682 		{ 44, 5220 },
1683 		{ 46, 5230 },
1684 		{ 48, 5240 },
1685 		{ 50, 5250 },
1686 		{ 52, 5260 },
1687 		{ 56, 5280 },
1688 		{ 58, 5290 },
1689 		{ 60, 5300 },
1690 		{ 64, 5320 },
1691 		{ 100, 5500 },
1692 		{ 104, 5520 },
1693 		{ 108, 5540 },
1694 		{ 112, 5560 },
1695 		{ 116, 5580 },
1696 		{ 120, 5600 },
1697 		{ 124, 5620 },
1698 		{ 128, 5640 },
1699 		{ 132, 5660 },
1700 		{ 136, 5680 },
1701 		{ 140, 5700 },
1702 		{ 149, 5745 },
1703 		{ 152, 5760 },
1704 		{ 153, 5765 },
1705 		{ 157, 5785 },
1706 		{ 160, 5800 },
1707 		{ 161, 5805 },
1708 		{ 165, 5825 },
1709 		{ 183, 4915 },
1710 		{ 184, 4920 },
1711 		{ 185, 4925 },
1712 		{ 187, 4935 },
1713 		{ 188, 4945 },
1714 		{ 192, 4960 },
1715 		{ 196, 4980 },
1716 		{ 0, -1 }
1717 	};
1718 	
1719 	static struct cf_pair bg_table[] = {
1720 		/* B/G band */
1721 		{ 1, 2412 },
1722 		{ 2, 2417 },
1723 		{ 3, 2422 },
1724 		{ 4, 2427 },
1725 		{ 5, 2432 },
1726 		{ 6, 2437 },
1727 		{ 7, 2442 },
1728 		{ 8, 2447 },
1729 		{ 9, 2452 },
1730 		{ 10, 2457 },
1731 		{ 11, 2462 },
1732 		{ 12, 2467 },
1733 		{ 13, 2472 },
1734 		{ 14, 2484 },
1735 		{ 0, -1 }
1736 	};
1737 	
1738 	/**
1739 	 * nm_utils_wifi_freq_to_channel:
1740 	 * @freq: frequency
1741 	 *
1742 	 * Utility function to translate a WiFi frequency to its corresponding channel.
1743 	 *
1744 	 * Returns: the channel represented by the frequency or 0
1745 	 **/
1746 	guint32
1747 	nm_utils_wifi_freq_to_channel (guint32 freq)
1748 	{
1749 		int i = 0;
1750 	
1751 		if (freq > 4900) {
1752 			while (a_table[i].chan && (a_table[i].freq != freq))
1753 				i++;
1754 			return a_table[i].chan;
1755 		} else {
1756 			while (bg_table[i].chan && (bg_table[i].freq != freq))
1757 				i++;
1758 			return bg_table[i].chan;
1759 		}
1760 	
1761 		return 0;
1762 	}
1763 	
1764 	/**
1765 	 * nm_utils_wifi_channel_to_freq:
1766 	 * @channel: channel
1767 	 * @band: frequency band for wireless ("a" or "bg")
1768 	 *
1769 	 * Utility function to translate a WiFi channel to its corresponding frequency.
1770 	 *
1771 	 * Returns: the frequency represented by the channel of the band,
1772 	 *          or -1 when the freq is invalid, or 0 when the band
1773 	 *          is invalid
1774 	 **/
1775 	guint32
1776 	nm_utils_wifi_channel_to_freq (guint32 channel, const char *band)
1777 	{
1778 		int i = 0;
1779 	
1780 		if (!strcmp (band, "a")) {
1781 			while (a_table[i].chan && (a_table[i].chan != channel))
1782 				i++;
1783 			return a_table[i].freq;
1784 		} else if (!strcmp (band, "bg")) {
1785 			while (bg_table[i].chan && (bg_table[i].chan != channel))
1786 				i++;
1787 			return bg_table[i].freq;
1788 		}
1789 	
1790 		return 0;
1791 	}
1792 	
1793 	/**
1794 	 * nm_utils_wifi_find_next_channel:
1795 	 * @channel: current channel
1796 	 * @direction: whether going downward (0 or less) or upward (1 or more)
1797 	 * @band: frequency band for wireless ("a" or "bg")
1798 	 *
1799 	 * Utility function to find out next/previous WiFi channel for a channel.
1800 	 *
1801 	 * Returns: the next channel in the specified direction or 0
1802 	 **/
1803 	guint32
1804 	nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band)
1805 	{
1806 		size_t a_size = sizeof (a_table) / sizeof (struct cf_pair);
1807 		size_t bg_size = sizeof (bg_table) / sizeof (struct cf_pair);
1808 		struct cf_pair *pair = NULL;
1809 	
1810 		if (!strcmp (band, "a")) {
1811 			if (channel < a_table[0].chan)
1812 				return a_table[0].chan;
1813 			if (channel > a_table[a_size - 2].chan)
1814 				return a_table[a_size - 2].chan;
1815 			pair = &a_table[0];
1816 		} else if (!strcmp (band, "bg")) {
1817 			if (channel < bg_table[0].chan)
1818 				return bg_table[0].chan;
1819 			if (channel > bg_table[bg_size - 2].chan)
1820 				return bg_table[bg_size - 2].chan;
1821 			pair = &bg_table[0];
1822 		} else {
1823 			g_assert_not_reached ();
1824 			return 0;
1825 		}
1826 	
1827 		while (pair->chan) {
1828 			if (channel == pair->chan)
1829 				return channel;
1830 			if ((channel < (pair+1)->chan) && (channel > pair->chan)) {
1831 				if (direction > 0)	
1832 					return (pair+1)->chan;
1833 				else
1834 					return pair->chan;
1835 			}
1836 			pair++;
1837 		}
1838 		return 0;
1839 	}
1840 	
1841 	/**
1842 	 * nm_utils_wifi_is_channel_valid:
1843 	 * @channel: channel
1844 	 * @band: frequency band for wireless ("a" or "bg")
1845 	 *
1846 	 * Utility function to verify WiFi channel validity.
1847 	 *
1848 	 * Returns: TRUE or FALSE
1849 	 **/
1850 	gboolean
1851 	nm_utils_wifi_is_channel_valid (guint32 channel, const char *band)
1852 	{
1853 		struct cf_pair *table = NULL;
1854 		int i = 0;
1855 	
1856 		if (!strcmp (band, "a"))
1857 			table = a_table;
1858 		else if (!strcmp (band, "bg"))
1859 			table = bg_table;
1860 		else
1861 			return FALSE;
1862 	
1863 		while (table[i].chan && (table[i].chan != channel))
1864 			i++;
1865 	
1866 		if (table[i].chan != 0)
1867 			return TRUE;
1868 		else
1869 			return FALSE;
1870 	}
1871 	
1872 	/**
1873 	 * nm_utils_hwaddr_len:
1874 	 * @type: the type of address; either %ARPHRD_ETHER or %ARPHRD_INFINIBAND
1875 	 *
1876 	 * Returns the length in octets of a hardware address of type @type.
1877 	 *
1878 	 * Note that this only accepts %ARPHRD_ETHER and %ARPHRD_INFINIBAND,
1879 	 * not other types.
1880 	 *
1881 	 * Return value: the length
1882 	 */
1883 	int
1884 	nm_utils_hwaddr_len (int type)
1885 	{
1886 		if (type == ARPHRD_ETHER)
1887 			return ETH_ALEN;
1888 		else if (type == ARPHRD_INFINIBAND)
1889 			return INFINIBAND_ALEN;
1890 		else
1891 			g_return_val_if_reached (-1);
1892 	}
1893 	
1894 	/**
1895 	 * nm_utils_hwaddr_type:
1896 	 * @len: the length of hardware address in bytes
1897 	 *
1898 	 * Returns the type (either %ARPHRD_ETHER or %ARPHRD_INFINIBAND) of
1899 	 * the raw address given its length.
1900 	 *
1901 	 * Return value: the type, either %ARPHRD_ETHER or %ARPHRD_INFINIBAND.
1902 	 *
1903 	 * Deprecated: This could not be extended to cover other types, since
1904 	 * there is not a one-to-one mapping between types and lengths. This
1905 	 * was mostly only used to get a type to pass to
1906 	 * nm_utils_hwaddr_ntoa() or nm_utils_hwaddr_aton() when you only had
1907 	 * a length; but you can just use nm_utils_hwaddr_ntoa_len() or
1908 	 * nm_utils_hwaddr_aton_len() now instead.
1909 	 */
1910 	int
1911 	nm_utils_hwaddr_type (int len)
1912 	{
1913 		if (len == ETH_ALEN)
1914 			return ARPHRD_ETHER;
1915 		else if (len == INFINIBAND_ALEN)
1916 			return ARPHRD_INFINIBAND;
1917 		else
1918 			g_return_val_if_reached (-1);
1919 	}
1920 	
1921 	#define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
1922 	
1923 	/**
1924 	 * nm_utils_hwaddr_aton:
1925 	 * @asc: the ASCII representation of a hardware address
1926 	 * @type: the type of address; either %ARPHRD_ETHER or %ARPHRD_INFINIBAND
1927 	 * @buffer: buffer to store the result into
1928 	 *
1929 	 * Parses @asc and converts it to binary form in @buffer. See
1930 	 * nm_utils_hwaddr_atoba() if you'd rather have the result in a
1931 	 * #GByteArray.
1932 	 *
1933 	 * See also nm_utils_hwaddr_aton_len(), which takes an output length
1934 	 * instead of a type.
1935 	 *
1936 	 * Return value: @buffer, or %NULL if @asc couldn't be parsed
1937 	 */
1938 	guint8 *
1939 	nm_utils_hwaddr_aton (const char *asc, int type, gpointer buffer)
1940 	{
1941 		return nm_utils_hwaddr_aton_len (asc, buffer, nm_utils_hwaddr_len (type));
1942 	}
1943 	
1944 	/**
1945 	 * nm_utils_hwaddr_atoba:
1946 	 * @asc: the ASCII representation of a hardware address
1947 	 * @type: the type of address; either %ARPHRD_ETHER or %ARPHRD_INFINIBAND
1948 	 *
1949 	 * Parses @asc and converts it to binary form in a #GByteArray. See
1950 	 * nm_utils_hwaddr_aton() if you don't want a #GByteArray.
1951 	 *
1952 	 * Return value: (transfer full): a new #GByteArray, or %NULL if @asc couldn't
1953 	 * be parsed
1954 	 */
1955 	GByteArray *
1956 	nm_utils_hwaddr_atoba (const char *asc, int type)
1957 	{
1958 		GByteArray *ba;
1959 		int len = nm_utils_hwaddr_len (type);
1960 	
1961 		ba = g_byte_array_sized_new (len);
1962 		ba->len = len;
1963 		if (!nm_utils_hwaddr_aton (asc, type, ba->data)) {
1964 			g_byte_array_unref (ba);
1965 			return NULL;
1966 		}
1967 	
1968 		return ba;
1969 	}
1970 	
1971 	/**
1972 	 * nm_utils_hwaddr_ntoa:
1973 	 * @addr: a binary hardware address
1974 	 * @type: the type of address; either %ARPHRD_ETHER or %ARPHRD_INFINIBAND
1975 	 *
1976 	 * Converts @addr to textual form.
1977 	 *
1978 	 * See also nm_utils_hwaddr_ntoa_len(), which takes a length instead of
1979 	 * a type.
1980 	 *
1981 	 * Return value: (transfer full): the textual form of @addr
1982 	 */
1983 	char *
1984 	nm_utils_hwaddr_ntoa (gconstpointer addr, int type)
1985 	{
1986 		return nm_utils_hwaddr_ntoa_len (addr, nm_utils_hwaddr_len (type));
1987 	}
1988 	
1989 	/**
1990 	 * nm_utils_hwaddr_aton_len:
1991 	 * @asc: the ASCII representation of a hardware address
1992 	 * @buffer: buffer to store the result into
1993 	 * @length: the expected length in bytes of the result
1994 	 *
1995 	 * Parses @asc and converts it to binary form in @buffer.
1996 	 * Bytes in @asc can be sepatared by colons (:), or hyphens (-), but not mixed.
1997 	 *
1998 	 * Return value: @buffer, or %NULL if @asc couldn't be parsed
1999 	 *   or would be shorter or longer than @length.
2000 	 *
2001 	 * Since: 0.9.10
2002 	 */
2003 	guint8 *
2004 	nm_utils_hwaddr_aton_len (const char *asc, gpointer buffer, gsize length)
2005 	{
2006 		const char *in = asc;
2007 		guint8 *out = (guint8 *)buffer;
2008 		char delimiter = '\0';
2009 	
2010 		while (length && *in) {
2011 			guint8 d1 = in[0], d2 = in[1];
2012 	
2013 			if (!g_ascii_isxdigit (d1))
2014 				return NULL;
2015 	
2016 			/* If there's no leading zero (ie "aa:b:cc") then fake it */
2017 			if (d2 && g_ascii_isxdigit (d2)) {
2018 				*out++ = (HEXVAL (d1) << 4) + HEXVAL (d2);
2019 				in += 2;
2020 			} else {
2021 				/* Fake leading zero */
2022 				*out++ = (HEXVAL ('0') << 4) + HEXVAL (d1);
2023 				in += 1;
2024 			}
2025 	
2026 			length--;
2027 			if (*in) {
2028 				if (delimiter == '\0') {
2029 					if (*in == ':' || *in == '-')
2030 						delimiter = *in;
2031 					else
2032 						return NULL;
2033 				} else {
2034 					if (*in != delimiter)
2035 						return NULL;
2036 				}
2037 				in++;
2038 			}
2039 		}
2040 	
2041 		if (length == 0 && !*in)
2042 			return buffer;
2043 		else
2044 			return NULL;
2045 	}
2046 	
2047 	/**
2048 	 * nm_utils_hwaddr_ntoa_len:
2049 	 * @addr: a binary hardware address
2050 	 * @length: the length of @addr
2051 	 *
2052 	 * Converts @addr to textual form.
2053 	 *
2054 	 * Return value: (transfer full): the textual form of @addr
2055 	 *
2056 	 * Since: 0.9.10
2057 	 */
2058 	char *
2059 	nm_utils_hwaddr_ntoa_len (gconstpointer addr, gsize length)
2060 	{
2061 		const guint8 *in = addr;
2062 		GString *out = g_string_new (NULL);
2063 	
2064 		while (length--) {
2065 			if (out->len)
2066 				g_string_append_c (out, ':');
2067 			g_string_append_printf (out, "%02X", *in++);
2068 		}
2069 	
2070 		return g_string_free (out, FALSE);
2071 	}
2072 	
2073 	/**
2074 	 * nm_utils_hwaddr_valid:
2075 	 * @asc: the ASCII representation of a hardware address
2076 	 *
2077 	 * Parses @asc to see if it is a valid hardware address of some type.
2078 	 *
2079 	 * Return value: %TRUE if @asc appears to be a valid hardware address
2080 	 *   of some type, %FALSE if not.
2081 	 *
2082 	 * Since: 0.9.10
2083 	 */
2084 	gboolean
2085 	nm_utils_hwaddr_valid (const char *asc)
2086 	{
2087 		guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
2088 		int in_len = strlen (asc), out_len;
2089 	
2090 		if ((in_len + 1) % 3 != 0)
2091 			return FALSE;
2092 		out_len = (in_len + 1) / 3;
2093 		if (out_len > NM_UTILS_HWADDR_LEN_MAX)
2094 			return FALSE;
2095 		return nm_utils_hwaddr_aton_len (asc, buf, out_len) != NULL;
2096 	}
2097 	
2098 	/**
2099 	 * nm_utils_bin2hexstr:
2100 	 * @bytes: an array of bytes
2101 	 * @len: the length of the @bytes array
2102 	 * @final_len: an index where to cut off the returned string, or -1
2103 	 *
2104 	 * Converts a byte-array @bytes into a hexadecimal string.
2105 	 * If @final_len is greater than -1, the returned string is terminated at
2106 	 * that index (returned_string[final_len] == '\0'),
2107 	 *
2108 	 * Return value: (transfer full): the textual form of @bytes
2109 	 *
2110 	 * Since: 0.9.10
2111 	 *
2112 	 * Code originally by Alex Larsson <alexl@redhat.com> and
2113 	 *  copyright Red Hat, Inc. under terms of the LGPL.
2114 	 */
2115 	char *
2116 	nm_utils_bin2hexstr (const char *bytes, int len, int final_len)
2117 	{
2118 		static char hex_digits[] = "0123456789abcdef";
2119 		char *result;
2120 		int i;
2121 		gsize buflen = (len * 2) + 1;
2122 	
2123 		g_return_val_if_fail (bytes != NULL, NULL);
2124 		g_return_val_if_fail (len > 0, NULL);
2125 		g_return_val_if_fail (len < 4096, NULL);   /* Arbitrary limit */
2126 		if (final_len > -1)
2127 			g_return_val_if_fail (final_len < buflen, NULL);
2128 	
2129 		result = g_malloc0 (buflen);
2130 		for (i = 0; i < len; i++)
2131 		{
2132 			result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
2133 			result[2*i+1] = hex_digits[bytes[i] & 0xf];
2134 		}
2135 		/* Cut converted key off at the correct length for this cipher type */
2136 		if (final_len > -1)
2137 			result[final_len] = '\0';
2138 		else
2139 			result[buflen - 1] = '\0';
2140 	
2141 		return result;
2142 	}
2143 	
2144 	/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
2145 	/**
2146 	 * nm_utils_hex2byte:
2147 	 * @hex: a string representing a hex byte
2148 	 *
2149 	 * Converts a hex string (2 characters) into its byte representation.
2150 	 *
2151 	 * Return value: a byte, or -1 if @hex doesn't represent a hex byte
2152 	 *
2153 	 * Since: 0.9.10
2154 	 */
2155 	int
2156 	nm_utils_hex2byte (const char *hex)
2157 	{
2158 		int a, b;
2159 		a = g_ascii_xdigit_value (*hex++);
2160 		if (a < 0)
2161 			return -1;
2162 		b = g_ascii_xdigit_value (*hex++);
2163 		if (b < 0)
2164 			return -1;
2165 		return (a << 4) | b;
2166 	}
2167 	
2168 	/**
2169 	 * nm_utils_hexstr2bin:
2170 	 * @hex: an hex string
2171 	 * @len: the length of the @hex string (it has to be even)
2172 	 *
2173 	 * Converts a hexadecimal string @hex into a byte-array. The returned array
2174 	 * length is @len/2.
2175 	 *
2176 	 * Return value: (transfer full): a array of bytes, or %NULL on error
2177 	 *
2178 	 * Since: 0.9.10
2179 	 */
2180 	char *
2181 	nm_utils_hexstr2bin (const char *hex, size_t len)
2182 	{
2183 		size_t       i;
2184 		int          a;
2185 		const char * ipos = hex;
2186 		char *       buf = NULL;
2187 		char *       opos;
2188 	
2189 		/* Length must be a multiple of 2 */
2190 		if ((len % 2) != 0)
2191 			return NULL;
2192 	
2193 		opos = buf = g_malloc0 ((len / 2) + 1);
2194 		for (i = 0; i < len; i += 2) {
2195 			a = nm_utils_hex2byte (ipos);
2196 			if (a < 0) {
2197 				g_free (buf);
2198 				return NULL;
2199 			}
2200 			*opos++ = a;
2201 			ipos += 2;
2202 		}
2203 		return buf;
2204 	}
2205 	/* End from hostap */
2206 	
2207 	/**
2208 	 * nm_utils_iface_valid_name:
2209 	 * @name: Name of interface
2210 	 *
2211 	 * This function is a 1:1 copy of the kernel's interface validation
2212 	 * function in net/core/dev.c.
2213 	 *
2214 	 * Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
2215 	 *
2216 	 * Since: 0.9.8
2217 	 */
2218 	gboolean
2219 	nm_utils_iface_valid_name (const char *name)
2220 	{
2221 		g_return_val_if_fail (name != NULL, FALSE);
2222 	
2223 		if (*name == '\0')
2224 			return FALSE;
2225 	
2226 		if (strlen (name) >= 16)
2227 			return FALSE;
2228 	
2229 		if (!strcmp (name, ".") || !strcmp (name, ".."))
2230 			return FALSE;
2231 	
2232 		while (*name) {
2233 			if (*name == '/' || g_ascii_isspace (*name))
2234 				return FALSE;
2235 			name++;
2236 		}
2237 	
2238 		return TRUE;
2239 	}
2240 	
2241 	/**
2242 	 * nm_utils_is_uuid:
2243 	 * @str: a string that might be a UUID
2244 	 *
2245 	 * Checks if @str is a UUID
2246 	 *
2247 	 * Returns: %TRUE if @str is a UUID, %FALSE if not
2248 	 *
2249 	 * Since: 0.9.8
2250 	 */
2251 	gboolean
2252 	nm_utils_is_uuid (const char *str)
2253 	{
2254 		const char *p = str;
2255 		int num_dashes = 0;
2256 	
2257 		while (*p) {
2258 			if (*p == '-')
2259 				num_dashes++;
2260 			else if (!g_ascii_isxdigit (*p))
2261 				return FALSE;
2262 			p++;
2263 		}
2264 	
2265 		if ((num_dashes == 4) && (p - str == 36))
2266 			return TRUE;
2267 	
2268 		/* Backwards compat for older configurations */
2269 		if ((num_dashes == 0) && (p - str == 40))
2270 			return TRUE;
2271 	
2272 		return FALSE;
2273 	}
2274