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