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