1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
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.
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.
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.
19 * Copyright 2005 - 2013 Red Hat, Inc.
22 #include "nm-default.h"
28 #include <netinet/ether.h>
29 #include <linux/if_infiniband.h>
30 #include <uuid/uuid.h>
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"
40 /* Embed the commit id in the build binary */
41 static const char *const __nm_git_sha = NM_STRLEN (NM_GIT_SHA) > 0 ? "NM_GIT_SHA:"NM_GIT_SHA : "";
45 * @short_description: Utility functions
46 * @include: nm-utils.h
48 * A collection of utility functions for working with SSIDs, IP addresses, Wi-Fi
49 * access points and devices, among other things.
52 struct EncodingTriplet
54 const char *encoding1;
55 const char *encoding2;
56 const char *encoding3;
59 struct IsoLangToEncodings
62 struct EncodingTriplet encodings;
65 /* 5-letter language codes */
66 static const struct IsoLangToEncodings isoLangEntries5[] =
68 /* Simplified Chinese */
69 { "zh_cn", {"euc-cn", "gb2312", "gb18030"} }, /* PRC */
70 { "zh_sg", {"euc-cn", "gb2312", "gb18030"} }, /* Singapore */
72 /* Traditional Chinese */
73 { "zh_tw", {"big5", "euc-tw", NULL} }, /* Taiwan */
74 { "zh_hk", {"big5", "euc-tw", "big5-hkcs"} },/* Hong Kong */
75 { "zh_mo", {"big5", "euc-tw", NULL} }, /* Macau */
78 { NULL, {NULL, NULL, NULL} }
81 /* 2-letter language codes; we don't care about the other 3 in this table */
82 static const struct IsoLangToEncodings isoLangEntries2[] =
85 { "ja", {"euc-jp", "shift_jis", "iso-2022-jp"} },
88 { "ko", {"euc-kr", "iso-2022-kr", "johab"} },
91 { "th", {"iso-8859-11","windows-874", NULL} },
93 /* Central European */
94 { "hu", {"iso-8859-2", "windows-1250", NULL} }, /* Hungarian */
95 { "cs", {"iso-8859-2", "windows-1250", NULL} }, /* Czech */
96 { "hr", {"iso-8859-2", "windows-1250", NULL} }, /* Croatian */
97 { "pl", {"iso-8859-2", "windows-1250", NULL} }, /* Polish */
98 { "ro", {"iso-8859-2", "windows-1250", NULL} }, /* Romanian */
99 { "sk", {"iso-8859-2", "windows-1250", NULL} }, /* Slovakian */
100 { "sl", {"iso-8859-2", "windows-1250", NULL} }, /* Slovenian */
101 { "sh", {"iso-8859-2", "windows-1250", NULL} }, /* Serbo-Croatian */
104 { "ru", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Russian */
105 { "be", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Belorussian */
106 { "bg", {"windows-1251","koi8-r", "iso-8859-5"} }, /* Bulgarian */
107 { "mk", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Macedonian */
108 { "sr", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Serbian */
109 { "uk", {"koi8-u", "koi8-r", "windows-1251"} }, /* Ukranian */
112 { "ar", {"iso-8859-6", "windows-1256", NULL} },
115 { "et", {"iso-8859-4", "windows-1257", NULL} }, /* Estonian */
116 { "lt", {"iso-8859-4", "windows-1257", NULL} }, /* Lithuanian */
117 { "lv", {"iso-8859-4", "windows-1257", NULL} }, /* Latvian */
120 { "el", {"iso-8859-7", "windows-1253", NULL} },
123 { "he", {"iso-8859-8", "windows-1255", NULL} },
124 { "iw", {"iso-8859-8", "windows-1255", NULL} },
127 { "tr", {"iso-8859-9", "windows-1254", NULL} },
130 { NULL, {NULL, NULL, NULL} }
134 static GHashTable * langToEncodings5 = NULL;
135 static GHashTable * langToEncodings2 = NULL;
138 init_lang_to_encodings_hash (void)
140 struct IsoLangToEncodings *enc;
142 if (G_UNLIKELY (langToEncodings5 == NULL)) {
143 /* Five-letter codes */
144 enc = (struct IsoLangToEncodings *) &isoLangEntries5[0];
145 langToEncodings5 = g_hash_table_new (g_str_hash, g_str_equal);
147 g_hash_table_insert (langToEncodings5, (gpointer) enc->lang,
148 (gpointer) &enc->encodings);
153 if (G_UNLIKELY (langToEncodings2 == NULL)) {
154 /* Two-letter codes */
155 enc = (struct IsoLangToEncodings *) &isoLangEntries2[0];
156 langToEncodings2 = g_hash_table_new (g_str_hash, g_str_equal);
158 g_hash_table_insert (langToEncodings2, (gpointer) enc->lang,
159 (gpointer) &enc->encodings);
167 get_encodings_for_lang (const char *lang,
172 struct EncodingTriplet * encodings;
173 gboolean success = FALSE;
176 g_return_val_if_fail (lang != NULL, FALSE);
177 g_return_val_if_fail (encoding1 != NULL, FALSE);
178 g_return_val_if_fail (encoding2 != NULL, FALSE);
179 g_return_val_if_fail (encoding3 != NULL, FALSE);
181 *encoding1 = "iso-8859-1";
182 *encoding2 = "windows-1251";
185 init_lang_to_encodings_hash ();
187 tmp_lang = g_strdup (lang);
188 if ((encodings = g_hash_table_lookup (langToEncodings5, tmp_lang))) {
189 *encoding1 = (char *) encodings->encoding1;
190 *encoding2 = (char *) encodings->encoding2;
191 *encoding3 = (char *) encodings->encoding3;
195 /* Truncate tmp_lang to length of 2 */
196 if (strlen (tmp_lang) > 2)
198 if (!success && (encodings = g_hash_table_lookup (langToEncodings2, tmp_lang))) {
199 *encoding1 = (char *) encodings->encoding1;
200 *encoding2 = (char *) encodings->encoding2;
201 *encoding3 = (char *) encodings->encoding3;
209 /* init, deinit for libnm_util */
211 static void __attribute__((constructor))
212 _check_symbols (void)
217 self = g_module_open (NULL, 0);
218 if (g_module_symbol (self, "nm_device_state_get_type", &func))
219 g_error ("libnm symbols detected; Mixing libnm with libnm-util/libnm-glib is not supported");
220 g_module_close (self);
223 static gboolean initialized = FALSE;
227 * @error: location to store error, or %NULL
229 * Initializes libnm-util; should be called when starting any program that
230 * uses libnm-util. This function can be called more than once.
232 * Returns: %TRUE if the initialization was successful, %FALSE on failure.
235 nm_utils_init (GError **error)
242 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
243 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
245 if (!crypto_init (error))
248 _nm_value_transforms_register ();
256 * No-op. Although this function still exists for ABI compatibility reasons, it
257 * does not have any effect, and does not ever need to be called.
260 nm_utils_deinit (void)
267 * nm_utils_ssid_to_utf8:
268 * @ssid: a byte array containing the SSID data
270 * Wi-Fi SSIDs are byte arrays, they are _not_ strings. Thus, an SSID may
271 * contain embedded NULLs and other unprintable characters. Often it is
272 * useful to print the SSID out for debugging purposes, but that should be the
273 * _only_ use of this function. Do not use this function for any persistent
274 * storage of the SSID, since the printable SSID returned from this function
275 * cannot be converted back into the real SSID of the access point.
277 * This function does almost everything humanly possible to convert the input
278 * into a printable UTF-8 string, using roughly the following procedure:
280 * 1) if the input data is already UTF-8 safe, no conversion is performed
281 * 2) attempts to get the current system language from the LANG environment
282 * variable, and depending on the language, uses a table of alternative
283 * encodings to try. For example, if LANG=hu_HU, the table may first try
284 * the ISO-8859-2 encoding, and if that fails, try the Windows-1250 encoding.
285 * If all fallback encodings fail, replaces non-UTF-8 characters with '?'.
286 * 3) If the system language was unable to be determined, falls back to the
287 * ISO-8859-1 encoding, then to the Windows-1251 encoding.
288 * 4) If step 3 fails, replaces non-UTF-8 characters with '?'.
290 * Again, this function should be used for debugging and display purposes
293 * Returns: (transfer full): an allocated string containing a UTF-8
294 * representation of the SSID, which must be freed by the caller using g_free().
295 * Returns %NULL on errors.
298 nm_utils_ssid_to_utf8 (const GByteArray *ssid)
300 char *converted = NULL;
301 char *lang, *e1 = NULL, *e2 = NULL, *e3 = NULL;
303 g_return_val_if_fail (ssid != NULL, NULL);
305 if (g_utf8_validate ((const gchar *) ssid->data, ssid->len, NULL))
306 return g_strndup ((const gchar *) ssid->data, ssid->len);
308 /* LANG may be a good encoding hint */
309 g_get_charset ((const char **)(&e1));
310 if ((lang = getenv ("LANG"))) {
313 lang = g_ascii_strdown (lang, -1);
314 if ((dot = strchr (lang, '.')))
317 get_encodings_for_lang (lang, &e1, &e2, &e3);
321 converted = g_convert ((const gchar *) ssid->data, ssid->len, "UTF-8", e1, NULL, NULL, NULL);
322 if (!converted && e2)
323 converted = g_convert ((const gchar *) ssid->data, ssid->len, "UTF-8", e2, NULL, NULL, NULL);
325 if (!converted && e3)
326 converted = g_convert ((const gchar *) ssid->data, ssid->len, "UTF-8", e3, NULL, NULL, NULL);
329 converted = g_convert_with_fallback ((const gchar *) ssid->data, ssid->len,
330 "UTF-8", e1, "?", NULL, NULL, NULL);
334 /* If there is still no converted string, the SSID probably
335 * contains characters not valid in the current locale. Convert
336 * the string to ASCII instead.
339 /* Use the printable range of 0x20-0x7E */
340 gchar *valid_chars = " !\"#$%&'()*+,-./0123456789:;<=>?@"
341 "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
342 "abcdefghijklmnopqrstuvwxyz{|}~";
344 converted = g_strndup ((const gchar *)ssid->data, ssid->len);
345 g_strcanon (converted, valid_chars, '?');
351 /* Shamelessly ripped from the Linux kernel ieee80211 stack */
353 * nm_utils_is_empty_ssid:
354 * @ssid: pointer to a buffer containing the SSID data
355 * @len: length of the SSID data in @ssid
357 * Different manufacturers use different mechanisms for not broadcasting the
358 * AP's SSID. This function attempts to detect blank/empty SSIDs using a
359 * number of known SSID-cloaking methods.
361 * Returns: %TRUE if the SSID is "empty", %FALSE if it is not
364 nm_utils_is_empty_ssid (const guint8 * ssid, int len)
366 /* Single white space is for Linksys APs */
367 if (len == 1 && ssid[0] == ' ')
370 /* Otherwise, if the entire ssid is 0, we assume it is hidden */
372 if (ssid[len] != '\0')
378 #define ESSID_MAX_SIZE 32
381 * nm_utils_escape_ssid:
382 * @ssid: pointer to a buffer containing the SSID data
383 * @len: length of the SSID data in @ssid
385 * This function does a quick printable character conversion of the SSID, simply
386 * replacing embedded NULLs and non-printable characters with the hexadecimal
387 * representation of that character. Intended for debugging only, should not
388 * be used for display of SSIDs.
390 * Returns: pointer to the escaped SSID, which uses an internal static buffer
391 * and will be overwritten by subsequent calls to this function
394 nm_utils_escape_ssid (const guint8 * ssid, guint32 len)
396 static char escaped[ESSID_MAX_SIZE * 2 + 1];
397 const guint8 *s = ssid;
400 if (nm_utils_is_empty_ssid (ssid, len)) {
401 memcpy (escaped, "<hidden>", sizeof ("<hidden>"));
405 len = MIN (len, (guint32) ESSID_MAX_SIZE);
420 * nm_utils_same_ssid:
421 * @ssid1: first SSID data to compare
422 * @ssid2: second SSID data to compare
423 * @ignore_trailing_null: %TRUE to ignore one trailing NULL byte
425 * Earlier versions of the Linux kernel added a NULL byte to the end of the
426 * SSID to enable easy printing of the SSID on the console or in a terminal,
427 * but this behavior was problematic (SSIDs are simply byte arrays, not strings)
428 * and thus was changed. This function compensates for that behavior at the
429 * cost of some compatibility with odd SSIDs that may legitimately have trailing
430 * NULLs, even though that is functionally pointless.
432 * Returns: %TRUE if the SSIDs are the same, %FALSE if they are not
435 nm_utils_same_ssid (const GByteArray * ssid1,
436 const GByteArray * ssid2,
437 gboolean ignore_trailing_null)
439 guint32 ssid1_len, ssid2_len;
443 if (!ssid1 || !ssid2)
446 ssid1_len = ssid1->len;
447 ssid2_len = ssid2->len;
448 if (ssid1_len && ssid2_len && ignore_trailing_null) {
449 if (ssid1->data[ssid1_len - 1] == '\0')
451 if (ssid2->data[ssid2_len - 1] == '\0')
455 if (ssid1_len != ssid2_len)
458 return memcmp (ssid1->data, ssid2->data, ssid1_len) == 0 ? TRUE : FALSE;
462 value_destroy (gpointer data)
464 GValue *value = (GValue *) data;
466 g_value_unset (value);
467 g_slice_free (GValue, value);
471 value_dup (gpointer key, gpointer val, gpointer user_data)
473 GHashTable *table = (GHashTable *) user_data;
474 GValue *value = (GValue *) val;
477 dup_value = g_slice_new0 (GValue);
478 g_value_init (dup_value, G_VALUE_TYPE (val));
479 g_value_copy (value, dup_value);
481 g_hash_table_insert (table, g_strdup ((char *) key), dup_value);
485 * nm_utils_gvalue_hash_dup:
486 * @hash: a #GHashTable mapping string:GValue
488 * Utility function to duplicate a hash table of #GValues.
490 * Returns: (transfer container) (element-type utf8 GObject.Value): a newly allocated duplicated #GHashTable, caller must free the
491 * returned hash with g_hash_table_unref() or g_hash_table_destroy()
494 nm_utils_gvalue_hash_dup (GHashTable *hash)
498 g_return_val_if_fail (hash != NULL, NULL);
500 table = g_hash_table_new_full (g_str_hash, g_str_equal,
501 (GDestroyNotify) g_free,
504 g_hash_table_foreach (hash, value_dup, table);
510 * nm_utils_slist_free: (skip)
512 * @elem_destroy_fn: user function called for each element in @list
514 * Utility function to free a #GSList.
516 * Deprecated: use g_slist_free_full().
519 nm_utils_slist_free (GSList *list, GDestroyNotify elem_destroy_fn)
521 g_slist_free_full (list, elem_destroy_fn);
525 _nm_utils_string_in_list (const char *str, const char **valid_strings)
529 for (i = 0; valid_strings[i]; i++)
530 if (strcmp (str, valid_strings[i]) == 0)
533 return valid_strings[i] != NULL;
537 _nm_utils_string_slist_validate (GSList *list, const char **valid_values)
541 for (iter = list; iter; iter = iter->next) {
542 if (!_nm_utils_string_in_list ((char *) iter->data, valid_values))
550 _nm_utils_gvalue_array_validate (GValueArray *elements, guint n_expected, ...)
555 gboolean valid = FALSE;
557 if (n_expected != elements->n_values)
560 va_start (args, n_expected);
561 for (i = 0; i < n_expected; i++) {
562 tmp = g_value_array_get_nth (elements, i);
563 if (G_VALUE_TYPE (tmp) != va_arg (args, GType))
574 device_supports_ap_ciphers (guint32 dev_caps,
578 gboolean have_pair = FALSE;
579 gboolean have_group = FALSE;
580 /* Device needs to support at least one pairwise and one group cipher */
584 /* Static WEP only uses group ciphers */
587 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
588 if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP40)
590 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
591 if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP104)
593 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
594 if (ap_flags & NM_802_11_AP_SEC_PAIR_TKIP)
596 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
597 if (ap_flags & NM_802_11_AP_SEC_PAIR_CCMP)
602 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
603 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP40)
605 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
606 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP104)
609 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
610 if (ap_flags & NM_802_11_AP_SEC_GROUP_TKIP)
612 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
613 if (ap_flags & NM_802_11_AP_SEC_GROUP_CCMP)
617 return (have_pair && have_group);
621 * nm_utils_ap_mode_security_valid:
622 * @type: the security type to check device capabilties against,
623 * e.g. #NMU_SEC_STATIC_WEP
624 * @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
625 * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
627 * Given a set of device capabilities, and a desired security type to check
628 * against, determines whether the combination of device capabilities and
629 * desired security type are valid for AP/Hotspot connections.
631 * Returns: %TRUE if the device capabilities are compatible with the desired
632 * @type, %FALSE if they are not.
637 nm_utils_ap_mode_security_valid (NMUtilsSecurityType type,
638 NMDeviceWifiCapabilities wifi_caps)
640 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_AP))
643 /* Return TRUE for any security that wpa_supplicant's lightweight AP
644 * mode can handle: which is open, WEP, and WPA/WPA2 PSK.
648 case NMU_SEC_STATIC_WEP:
649 case NMU_SEC_WPA_PSK:
650 case NMU_SEC_WPA2_PSK:
659 * nm_utils_security_valid:
660 * @type: the security type to check AP flags and device capabilties against,
661 * e.g. #NMU_SEC_STATIC_WEP
662 * @wifi_caps: bitfield of the capabilities of the specific Wi-Fi device, e.g.
663 * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
664 * @have_ap: whether the @ap_flags, @ap_wpa, and @ap_rsn arguments are valid
665 * @adhoc: whether the capabilities being tested are from an Ad-Hoc AP (IBSS)
666 * @ap_flags: bitfield of AP capabilities, e.g. #NM_802_11_AP_FLAGS_PRIVACY
667 * @ap_wpa: bitfield of AP capabilties derived from the AP's WPA beacon,
668 * e.g. (#NM_802_11_AP_SEC_PAIR_TKIP | #NM_802_11_AP_SEC_KEY_MGMT_PSK)
669 * @ap_rsn: bitfield of AP capabilties derived from the AP's RSN/WPA2 beacon,
670 * e.g. (#NM_802_11_AP_SEC_PAIR_CCMP | #NM_802_11_AP_SEC_PAIR_TKIP)
672 * Given a set of device capabilities, and a desired security type to check
673 * against, determines whether the combination of device, desired security
674 * type, and AP capabilities intersect.
676 * NOTE: this function cannot handle checking security for AP/Hotspot mode;
677 * use nm_utils_ap_mode_security_valid() instead.
679 * Returns: %TRUE if the device capabilities and AP capabilties intersect and are
680 * compatible with the desired @type, %FALSE if they are not
683 nm_utils_security_valid (NMUtilsSecurityType type,
684 NMDeviceWifiCapabilities wifi_caps,
687 NM80211ApFlags ap_flags,
688 NM80211ApSecurityFlags ap_wpa,
689 NM80211ApSecurityFlags ap_rsn)
691 gboolean good = TRUE;
694 if (type == NMU_SEC_NONE)
696 if ( (type == NMU_SEC_STATIC_WEP)
697 || ((type == NMU_SEC_DYNAMIC_WEP) && !adhoc)
698 || ((type == NMU_SEC_LEAP) && !adhoc)) {
699 if (wifi_caps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104))
709 if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
711 if (ap_wpa || ap_rsn)
714 case NMU_SEC_LEAP: /* require PRIVACY bit for LEAP? */
718 case NMU_SEC_STATIC_WEP:
720 if (!(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
722 if (ap_wpa || ap_rsn) {
723 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, TRUE))
724 if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, TRUE))
728 case NMU_SEC_DYNAMIC_WEP:
732 if (ap_rsn || !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
734 /* Some APs broadcast minimal WPA-enabled beacons that must be handled */
736 if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
738 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
742 case NMU_SEC_WPA_PSK:
744 return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
745 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
748 /* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
749 * they don't have any pairwise ciphers. */
751 /* coverity[dead_error_line] */
752 if ( (ap_wpa & NM_802_11_AP_SEC_GROUP_TKIP)
753 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
755 if ( (ap_wpa & NM_802_11_AP_SEC_GROUP_CCMP)
756 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
759 if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
760 if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
761 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
763 if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
764 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
771 case NMU_SEC_WPA2_PSK:
773 return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
774 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
777 /* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
778 * they don't have any pairwise ciphers, nor any RSA flags yet. */
780 /* coverity[dead_error_line] */
781 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
783 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
786 if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
787 if ( (ap_rsn & NM_802_11_AP_SEC_PAIR_TKIP)
788 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
790 if ( (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
791 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
798 case NMU_SEC_WPA_ENTERPRISE:
801 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
804 if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
806 /* Ensure at least one WPA cipher is supported */
807 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
811 case NMU_SEC_WPA2_ENTERPRISE:
814 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
817 if (!(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
819 /* Ensure at least one WPA cipher is supported */
820 if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, FALSE))
833 * nm_utils_wep_key_valid:
834 * @key: a string that might be a WEP key
835 * @wep_type: the #NMWepKeyType type of the WEP key
837 * Checks if @key is a valid WEP key
839 * Returns: %TRUE if @key is a WEP key, %FALSE if not
844 nm_utils_wep_key_valid (const char *key, NMWepKeyType wep_type)
851 keylen = strlen (key);
852 if ( wep_type == NM_WEP_KEY_TYPE_KEY
853 || wep_type == NM_WEP_KEY_TYPE_UNKNOWN) {
854 if (keylen == 10 || keylen == 26) {
856 for (i = 0; i < keylen; i++) {
857 if (!g_ascii_isxdigit (key[i]))
860 } else if (keylen == 5 || keylen == 13) {
862 for (i = 0; i < keylen; i++) {
863 if (!g_ascii_isprint (key[i]))
869 } else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
870 if (!keylen || keylen > 64)
878 * nm_utils_wpa_psk_valid:
879 * @psk: a string that might be a WPA PSK
881 * Checks if @psk is a valid WPA PSK
883 * Returns: %TRUE if @psk is a WPA PSK, %FALSE if not
888 nm_utils_wpa_psk_valid (const char *psk)
895 psklen = strlen (psk);
896 if (psklen < 8 || psklen > 64)
901 for (i = 0; i < psklen; i++) {
902 if (!g_ascii_isxdigit (psk[i]))
911 * nm_utils_ip4_addresses_from_gvalue:
912 * @value: #GValue containing a #GPtrArray of #GArrays of #guint32s
914 * Utility function to convert a #GPtrArray of #GArrays of #guint32s representing
915 * a list of NetworkManager IPv4 addresses (which is a tuple of address, gateway,
916 * and prefix) into a #GSList of #NMIP4Address objects. The specific format of
917 * this serialization is not guaranteed to be stable and the #GArray may be
918 * extended in the future.
920 * Returns: (transfer full) (element-type NMIP4Address): a newly allocated #GSList of #NMIP4Address objects
923 nm_utils_ip4_addresses_from_gvalue (const GValue *value)
925 GPtrArray *addresses;
929 addresses = (GPtrArray *) g_value_get_boxed (value);
930 for (i = 0; addresses && (i < addresses->len); i++) {
931 GArray *array = (GArray *) g_ptr_array_index (addresses, i);
934 if (array->len < 3) {
935 g_warning ("Ignoring invalid IP4 address");
939 addr = nm_ip4_address_new ();
940 nm_ip4_address_set_address (addr, g_array_index (array, guint32, 0));
941 nm_ip4_address_set_prefix (addr, g_array_index (array, guint32, 1));
942 nm_ip4_address_set_gateway (addr, g_array_index (array, guint32, 2));
943 list = g_slist_prepend (list, addr);
946 return g_slist_reverse (list);
950 * nm_utils_ip4_addresses_to_gvalue:
951 * @list: (element-type NMIP4Address): a list of #NMIP4Address objects
952 * @value: a pointer to a #GValue into which to place the converted addresses,
953 * which should be unset by the caller (when no longer needed) with
956 * Utility function to convert a #GSList of #NMIP4Address objects into a
957 * #GPtrArray of #GArrays of #guint32s representing a list of NetworkManager IPv4
958 * addresses (which is a tuple of address, gateway, and prefix). The specific
959 * format of this serialization is not guaranteed to be stable and may be
960 * extended in the future.
963 nm_utils_ip4_addresses_to_gvalue (GSList *list, GValue *value)
965 GPtrArray *addresses;
968 addresses = g_ptr_array_new ();
970 for (iter = list; iter; iter = iter->next) {
971 NMIP4Address *addr = (NMIP4Address *) iter->data;
975 array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
977 tmp = nm_ip4_address_get_address (addr);
978 g_array_append_val (array, tmp);
980 tmp = nm_ip4_address_get_prefix (addr);
981 g_array_append_val (array, tmp);
983 tmp = nm_ip4_address_get_gateway (addr);
984 g_array_append_val (array, tmp);
986 g_ptr_array_add (addresses, array);
989 g_value_take_boxed (value, addresses);
993 * nm_utils_ip4_routes_from_gvalue:
994 * @value: #GValue containing a #GPtrArray of #GArrays of #guint32s
996 * Utility function to convert a #GPtrArray of #GArrays of #guint32s representing
997 * a list of NetworkManager IPv4 routes (which is a tuple of route, next hop,
998 * prefix, and metric) into a #GSList of #NMIP4Route objects. The specific
999 * format of this serialization is not guaranteed to be stable and may be
1000 * extended in the future.
1002 * Returns: (transfer full) (element-type NMIP4Route): a newly allocated #GSList of #NMIP4Route objects
1005 nm_utils_ip4_routes_from_gvalue (const GValue *value)
1009 GSList *list = NULL;
1011 routes = (GPtrArray *) g_value_get_boxed (value);
1012 for (i = 0; routes && (i < routes->len); i++) {
1013 GArray *array = (GArray *) g_ptr_array_index (routes, i);
1016 if (array->len < 4) {
1017 g_warning ("Ignoring invalid IP4 route");
1021 route = nm_ip4_route_new ();
1022 nm_ip4_route_set_dest (route, g_array_index (array, guint32, 0));
1023 nm_ip4_route_set_prefix (route, g_array_index (array, guint32, 1));
1024 nm_ip4_route_set_next_hop (route, g_array_index (array, guint32, 2));
1025 nm_ip4_route_set_metric (route, g_array_index (array, guint32, 3));
1026 list = g_slist_prepend (list, route);
1029 return g_slist_reverse (list);
1033 * nm_utils_ip4_routes_to_gvalue:
1034 * @list: (element-type NMIP4Route): a list of #NMIP4Route objects
1035 * @value: a pointer to a #GValue into which to place the converted routes,
1036 * which should be unset by the caller (when no longer needed) with
1039 * Utility function to convert a #GSList of #NMIP4Route objects into a
1040 * #GPtrArray of #GArrays of #guint32s representing a list of NetworkManager IPv4
1041 * routes (which is a tuple of route, next hop, prefix, and metric). The
1042 * specific format of this serialization is not guaranteed to be stable and may
1043 * be extended in the future.
1046 nm_utils_ip4_routes_to_gvalue (GSList *list, GValue *value)
1051 routes = g_ptr_array_new ();
1053 for (iter = list; iter; iter = iter->next) {
1054 NMIP4Route *route = (NMIP4Route *) iter->data;
1058 array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
1060 tmp = nm_ip4_route_get_dest (route);
1061 g_array_append_val (array, tmp);
1063 tmp = nm_ip4_route_get_prefix (route);
1064 g_array_append_val (array, tmp);
1066 tmp = nm_ip4_route_get_next_hop (route);
1067 g_array_append_val (array, tmp);
1069 tmp = nm_ip4_route_get_metric (route);
1070 g_array_append_val (array, tmp);
1072 g_ptr_array_add (routes, array);
1075 g_value_take_boxed (value, routes);
1079 * nm_utils_ip4_netmask_to_prefix:
1080 * @netmask: an IPv4 netmask in network byte order
1082 * Returns: the CIDR prefix represented by the netmask
1085 nm_utils_ip4_netmask_to_prefix (guint32 netmask)
1089 const guint8 *p = (guint8 *) &netmask;
1114 * nm_utils_ip4_prefix_to_netmask:
1115 * @prefix: a CIDR prefix
1117 * Returns: the netmask represented by the prefix, in network byte order
1120 nm_utils_ip4_prefix_to_netmask (guint32 prefix)
1122 return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
1127 * nm_utils_ip4_get_default_prefix:
1128 * @ip: an IPv4 address (in network byte order)
1130 * When the Internet was originally set up, various ranges of IP addresses were
1131 * segmented into three network classes: A, B, and C. This function will return
1132 * a prefix that is associated with the IP address specified defining where it
1133 * falls in the predefined classes.
1135 * Returns: the default class prefix for the given IP
1137 /* The function is originally from ipcalc.c of Red Hat's initscripts. */
1139 nm_utils_ip4_get_default_prefix (guint32 ip)
1141 if (((ntohl (ip) & 0xFF000000) >> 24) <= 127)
1142 return 8; /* Class A - 255.0.0.0 */
1143 else if (((ntohl (ip) & 0xFF000000) >> 24) <= 191)
1144 return 16; /* Class B - 255.255.0.0 */
1146 return 24; /* Class C - 255.255.255.0 */
1150 * nm_utils_ip6_addresses_from_gvalue:
1151 * @value: gvalue containing a GPtrArray of GValueArrays of (GArray of guchars) and #guint32
1153 * Utility function to convert a #GPtrArray of #GValueArrays of (#GArray of guchars) and #guint32
1154 * representing a list of NetworkManager IPv6 addresses (which is a tuple of address,
1155 * prefix, and gateway), into a #GSList of #NMIP6Address objects. The specific format of
1156 * this serialization is not guaranteed to be stable and the #GValueArray may be
1157 * extended in the future.
1159 * Returns: (transfer full) (element-type NMIP6Address): a newly allocated #GSList of #NMIP6Address objects
1162 nm_utils_ip6_addresses_from_gvalue (const GValue *value)
1164 GPtrArray *addresses;
1166 GSList *list = NULL;
1168 addresses = (GPtrArray *) g_value_get_boxed (value);
1170 for (i = 0; addresses && (i < addresses->len); i++) {
1171 GValueArray *elements = (GValueArray *) g_ptr_array_index (addresses, i);
1173 GByteArray *ba_addr;
1174 GByteArray *ba_gw = NULL;
1178 if (elements->n_values < 2 || elements->n_values > 3) {
1179 g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1183 /* Third element (gateway) is optional */
1184 if ( !_nm_utils_gvalue_array_validate (elements, 2, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT)
1185 && !_nm_utils_gvalue_array_validate (elements, 3, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY)) {
1186 g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1190 tmp = g_value_array_get_nth (elements, 0);
1191 ba_addr = g_value_get_boxed (tmp);
1192 if (ba_addr->len != 16) {
1193 g_warning ("%s: ignoring invalid IP6 address of length %d",
1194 __func__, ba_addr->len);
1198 tmp = g_value_array_get_nth (elements, 1);
1199 prefix = g_value_get_uint (tmp);
1201 g_warning ("%s: ignoring invalid IP6 prefix %d",
1206 if (elements->n_values == 3) {
1207 tmp = g_value_array_get_nth (elements, 2);
1208 ba_gw = g_value_get_boxed (tmp);
1209 if (ba_gw->len != 16) {
1210 g_warning ("%s: ignoring invalid IP6 gateway address of length %d",
1211 __func__, ba_gw->len);
1216 addr = nm_ip6_address_new ();
1217 nm_ip6_address_set_prefix (addr, prefix);
1218 nm_ip6_address_set_address (addr, (const struct in6_addr *) ba_addr->data);
1220 nm_ip6_address_set_gateway (addr, (const struct in6_addr *) ba_gw->data);
1222 list = g_slist_prepend (list, addr);
1225 return g_slist_reverse (list);
1229 * nm_utils_ip6_addresses_to_gvalue:
1230 * @list: (element-type NMIP6Address): a list of #NMIP6Address objects
1231 * @value: a pointer to a #GValue into which to place the converted addresses,
1232 * which should be unset by the caller (when no longer needed) with
1235 * Utility function to convert a #GSList of #NMIP6Address objects into a
1236 * #GPtrArray of #GValueArrays representing a list of NetworkManager IPv6 addresses
1237 * (which is a tuple of address, prefix, and gateway). The specific format of
1238 * this serialization is not guaranteed to be stable and may be extended in the
1242 nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value)
1244 GPtrArray *addresses;
1247 addresses = g_ptr_array_new ();
1249 for (iter = list; iter; iter = iter->next) {
1250 NMIP6Address *addr = (NMIP6Address *) iter->data;
1252 GValue element = G_VALUE_INIT;
1255 array = g_value_array_new (3);
1258 g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1259 ba = g_byte_array_new ();
1260 g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_address (addr), 16);
1261 g_value_take_boxed (&element, ba);
1262 g_value_array_append (array, &element);
1263 g_value_unset (&element);
1266 g_value_init (&element, G_TYPE_UINT);
1267 g_value_set_uint (&element, nm_ip6_address_get_prefix (addr));
1268 g_value_array_append (array, &element);
1269 g_value_unset (&element);
1272 g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1273 ba = g_byte_array_new ();
1274 g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_gateway (addr), 16);
1275 g_value_take_boxed (&element, ba);
1276 g_value_array_append (array, &element);
1277 g_value_unset (&element);
1279 g_ptr_array_add (addresses, array);
1282 g_value_take_boxed (value, addresses);
1286 * nm_utils_ip6_routes_from_gvalue:
1287 * @value: #GValue containing a #GPtrArray of #GValueArrays of (#GArray of #guchars), #guint32,
1288 * (#GArray of #guchars), and #guint32
1290 * Utility function #GPtrArray of #GValueArrays of (#GArray of #guchars), #guint32,
1291 * (#GArray of #guchars), and #guint32 representing a list of NetworkManager IPv6
1292 * routes (which is a tuple of destination, prefix, next hop, and metric)
1293 * into a #GSList of #NMIP6Route objects. The specific format of this serialization
1294 * is not guaranteed to be stable and may be extended in the future.
1296 * Returns: (transfer full) (element-type NMIP6Route): a newly allocated #GSList of #NMIP6Route objects
1299 nm_utils_ip6_routes_from_gvalue (const GValue *value)
1303 GSList *list = NULL;
1305 routes = (GPtrArray *) g_value_get_boxed (value);
1306 for (i = 0; routes && (i < routes->len); i++) {
1307 GValueArray *route_values = (GValueArray *) g_ptr_array_index (routes, i);
1308 GByteArray *dest, *next_hop;
1309 guint prefix, metric;
1312 if (!_nm_utils_gvalue_array_validate (route_values, 4,
1313 DBUS_TYPE_G_UCHAR_ARRAY,
1315 DBUS_TYPE_G_UCHAR_ARRAY,
1317 g_warning ("Ignoring invalid IP6 route");
1321 dest = g_value_get_boxed (g_value_array_get_nth (route_values, 0));
1322 if (dest->len != 16) {
1323 g_warning ("%s: ignoring invalid IP6 dest address of length %d",
1324 __func__, dest->len);
1328 prefix = g_value_get_uint (g_value_array_get_nth (route_values, 1));
1330 next_hop = g_value_get_boxed (g_value_array_get_nth (route_values, 2));
1331 if (next_hop->len != 16) {
1332 g_warning ("%s: ignoring invalid IP6 next_hop address of length %d",
1333 __func__, next_hop->len);
1337 metric = g_value_get_uint (g_value_array_get_nth (route_values, 3));
1339 route = nm_ip6_route_new ();
1340 nm_ip6_route_set_dest (route, (struct in6_addr *)dest->data);
1341 nm_ip6_route_set_prefix (route, prefix);
1342 nm_ip6_route_set_next_hop (route, (struct in6_addr *)next_hop->data);
1343 nm_ip6_route_set_metric (route, metric);
1344 list = g_slist_prepend (list, route);
1347 return g_slist_reverse (list);
1351 * nm_utils_ip6_routes_to_gvalue:
1352 * @list: (element-type NMIP6Route): a list of #NMIP6Route objects
1353 * @value: a pointer to a #GValue into which to place the converted routes,
1354 * which should be unset by the caller (when no longer needed) with
1357 * Utility function to convert a #GSList of #NMIP6Route objects into a #GPtrArray of
1358 * #GValueArrays of (#GArray of #guchars), #guint32, (#GArray of #guchars), and #guint32
1359 * representing a list of NetworkManager IPv6 routes (which is a tuple of destination,
1360 * prefix, next hop, and metric). The specific format of this serialization is not
1361 * guaranteed to be stable and may be extended in the future.
1364 nm_utils_ip6_routes_to_gvalue (GSList *list, GValue *value)
1369 routes = g_ptr_array_new ();
1371 for (iter = list; iter; iter = iter->next) {
1372 NMIP6Route *route = (NMIP6Route *) iter->data;
1374 const struct in6_addr *addr;
1376 GValue element = G_VALUE_INIT;
1378 array = g_value_array_new (4);
1380 g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1381 addr = nm_ip6_route_get_dest (route);
1382 ba = g_byte_array_new ();
1383 g_byte_array_append (ba, (guchar *)addr, sizeof (*addr));
1384 g_value_take_boxed (&element, ba);
1385 g_value_array_append (array, &element);
1386 g_value_unset (&element);
1388 g_value_init (&element, G_TYPE_UINT);
1389 g_value_set_uint (&element, nm_ip6_route_get_prefix (route));
1390 g_value_array_append (array, &element);
1391 g_value_unset (&element);
1393 g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1394 addr = nm_ip6_route_get_next_hop (route);
1395 ba = g_byte_array_new ();
1396 g_byte_array_append (ba, (guchar *)addr, sizeof (*addr));
1397 g_value_take_boxed (&element, ba);
1398 g_value_array_append (array, &element);
1399 g_value_unset (&element);
1401 g_value_init (&element, G_TYPE_UINT);
1402 g_value_set_uint (&element, nm_ip6_route_get_metric (route));
1403 g_value_array_append (array, &element);
1404 g_value_unset (&element);
1406 g_ptr_array_add (routes, array);
1409 g_value_take_boxed (value, routes);
1413 * nm_utils_ip6_dns_from_gvalue: (skip)
1416 * Converts a #GValue containing a #GPtrArray of IP6 DNS, represented as
1417 * #GByteArrays into a #GSList of <literal><type>struct in6_addr</type></literal>s.
1419 * Returns: a #GSList of IP6 addresses.
1422 nm_utils_ip6_dns_from_gvalue (const GValue *value)
1426 GSList *list = NULL;
1428 dns = (GPtrArray *) g_value_get_boxed (value);
1429 for (i = 0; dns && (i < dns->len); i++) {
1430 GByteArray *bytearray = (GByteArray *) g_ptr_array_index (dns, i);
1431 struct in6_addr *addr;
1433 if (bytearray->len != 16) {
1434 g_warning ("%s: ignoring invalid IP6 address of length %d",
1435 __func__, bytearray->len);
1439 addr = g_malloc0 (sizeof (struct in6_addr));
1440 memcpy (addr->s6_addr, bytearray->data, bytearray->len);
1441 list = g_slist_prepend (list, addr);
1444 return g_slist_reverse (list);
1448 * nm_utils_ip6_dns_to_gvalue: (skip)
1449 * @list: a list of #NMIP6Route objects
1450 * @value: a pointer to a #GValue into which to place the converted DNS server
1451 * addresses, which should be unset by the caller (when no longer needed) with
1454 * Utility function to convert a #GSList of <literal><type>struct
1455 * in6_addr</type></literal> structs into a #GPtrArray of #GByteArrays
1456 * representing each server's IPv6 addresses in network byte order.
1457 * The specific format of this serialization is not guaranteed to be
1458 * stable and may be extended in the future.
1461 nm_utils_ip6_dns_to_gvalue (GSList *list, GValue *value)
1466 dns = g_ptr_array_new ();
1468 for (iter = list; iter; iter = iter->next) {
1469 struct in6_addr *addr = (struct in6_addr *) iter->data;
1470 GByteArray *bytearray;
1472 bytearray = g_byte_array_sized_new (16);
1473 g_byte_array_append (bytearray, (guint8 *) addr->s6_addr, 16);
1474 g_ptr_array_add (dns, bytearray);
1477 g_value_take_boxed (value, dns);
1481 * nm_utils_uuid_generate:
1483 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
1484 * object's #NMSettingConnection:id: property. Should be freed with g_free()
1487 nm_utils_uuid_generate (void)
1492 buf = g_malloc0 (37);
1493 uuid_generate_random (uuid);
1494 uuid_unparse_lower (uuid, &buf[0]);
1499 * nm_utils_uuid_generate_from_string:
1500 * @s: a string to use as the seed for the UUID
1502 * For a given @s, this function will always return the same UUID.
1504 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
1505 * object's #NMSettingConnection:id: property
1508 nm_utils_uuid_generate_from_string (const char *s)
1510 GError *error = NULL;
1514 g_return_val_if_fail (s && *s, NULL);
1516 if (!nm_utils_init (&error)) {
1517 g_warning ("error initializing crypto: %s", error->message);
1518 g_error_free (error);
1522 if (!crypto_md5_hash (NULL, 0, s, strlen (s), (char *) uuid, sizeof (uuid), &error)) {
1523 g_warning ("error generating UUID: %s", error->message);
1524 g_error_free (error);
1528 buf = g_malloc0 (37);
1529 uuid_unparse_lower (uuid, &buf[0]);
1535 make_key (const char *cipher,
1537 const gsize salt_len,
1538 const char *password,
1543 guint32 digest_len = 24; /* DES-EDE3-CBC */
1545 g_return_val_if_fail (salt != NULL, NULL);
1546 g_return_val_if_fail (salt_len >= 8, NULL);
1547 g_return_val_if_fail (password != NULL, NULL);
1548 g_return_val_if_fail (out_len != NULL, NULL);
1550 if (!strcmp (cipher, "DES-EDE3-CBC"))
1552 else if (!strcmp (cipher, "AES-128-CBC"))
1555 key = g_malloc0 (digest_len + 1);
1557 if (!crypto_md5_hash (salt, salt_len, password, strlen (password), key, digest_len, error)) {
1559 memset (key, 0, digest_len);
1563 *out_len = digest_len;
1569 * nm_utils_rsa_key_encrypt_helper:
1570 * @cipher: cipher to use for encryption ("DES-EDE3-CBC" or "AES-128-CBC")
1571 * @data: RSA private key data to be encrypted
1572 * @in_password: (allow-none): existing password to use, if any
1573 * @out_password: (out) (allow-none): if @in_password was %NULL, a random password will be generated
1574 * and returned in this argument
1575 * @error: detailed error information on return, if an error occurred
1577 * Encrypts the given RSA private key data with the given password (or generates
1578 * a password if no password was given) and converts the data to PEM format
1579 * suitable for writing to a file.
1581 * Returns: (transfer full): on success, PEM-formatted data suitable for writing to a PEM-formatted
1582 * certificate/private key file.
1585 nm_utils_rsa_key_encrypt_helper (const char *cipher,
1586 const GByteArray *data,
1587 const char *in_password,
1588 char **out_password,
1593 char *key = NULL, *enc = NULL, *pw_buf[32];
1594 gsize key_len = 0, enc_len = 0;
1595 GString *pem = NULL;
1596 char *tmp, *tmp_password = NULL;
1599 GByteArray *ret = NULL;
1601 g_return_val_if_fail (!g_strcmp0 (cipher, CIPHER_DES_EDE3_CBC) || !g_strcmp0 (cipher, CIPHER_AES_CBC), NULL);
1602 g_return_val_if_fail (data != NULL, NULL);
1603 g_return_val_if_fail (data->len > 0, NULL);
1605 g_return_val_if_fail (*out_password == NULL, NULL);
1607 /* Make the password if needed */
1609 if (!crypto_randomize (pw_buf, sizeof (pw_buf), error))
1611 in_password = tmp_password = nm_utils_bin2hexstr ((const char *) pw_buf, sizeof (pw_buf), -1);
1614 if (g_strcmp0 (cipher, CIPHER_AES_CBC) == 0)
1619 if (!crypto_randomize (salt, salt_len, error))
1622 key = make_key (cipher, &salt[0], salt_len, in_password, &key_len, error);
1626 enc = crypto_encrypt (cipher, data, salt, salt_len, key, key_len, &enc_len, error);
1630 pem = g_string_sized_new (enc_len * 2 + 100);
1631 g_string_append (pem, "-----BEGIN RSA PRIVATE KEY-----\n");
1632 g_string_append (pem, "Proc-Type: 4,ENCRYPTED\n");
1634 /* Convert the salt to a hex string */
1635 tmp = nm_utils_bin2hexstr ((const char *) salt, salt_len, salt_len * 2);
1636 g_string_append_printf (pem, "DEK-Info: %s,%s\n\n", cipher, tmp);
1639 /* Convert the encrypted key to a base64 string */
1640 p = tmp = g_base64_encode ((const guchar *) enc, enc_len);
1641 left = strlen (tmp);
1643 g_string_append_len (pem, p, (left < 64) ? left : 64);
1644 g_string_append_c (pem, '\n');
1650 g_string_append (pem, "-----END RSA PRIVATE KEY-----\n");
1652 ret = g_byte_array_sized_new (pem->len);
1653 g_byte_array_append (ret, (const unsigned char *) pem->str, pem->len);
1654 if (tmp_password && out_password)
1655 *out_password = g_strdup (tmp_password);
1659 memset (key, 0, key_len);
1663 memset (enc, 0, enc_len);
1667 g_string_free (pem, TRUE);
1670 memset (tmp_password, 0, strlen (tmp_password));
1671 g_free (tmp_password);
1678 * nm_utils_rsa_key_encrypt:
1679 * @data: RSA private key data to be encrypted
1680 * @in_password: (allow-none): existing password to use, if any
1681 * @out_password: (out) (allow-none): if @in_password was %NULL, a random password will be generated
1682 * and returned in this argument
1683 * @error: detailed error information on return, if an error occurred
1685 * Encrypts the given RSA private key data with the given password (or generates
1686 * a password if no password was given) and converts the data to PEM format
1687 * suitable for writing to a file. It uses Triple DES cipher for the encryption.
1689 * Returns: (transfer full): on success, PEM-formatted data suitable for writing to a PEM-formatted
1690 * certificate/private key file.
1693 nm_utils_rsa_key_encrypt (const GByteArray *data,
1694 const char *in_password,
1695 char **out_password,
1700 return nm_utils_rsa_key_encrypt_helper (CIPHER_DES_EDE3_CBC,
1708 * nm_utils_rsa_key_encrypt_aes:
1709 * @data: RSA private key data to be encrypted
1710 * @in_password: (allow-none): existing password to use, if any
1711 * @out_password: (out) (allow-none): if @in_password was %NULL, a random password will be generated
1712 * and returned in this argument
1713 * @error: detailed error information on return, if an error occurred
1715 * Encrypts the given RSA private key data with the given password (or generates
1716 * a password if no password was given) and converts the data to PEM format
1717 * suitable for writing to a file. It uses AES cipher for the encryption.
1719 * Returns: (transfer full): on success, PEM-formatted data suitable for writing to a PEM-formatted
1720 * certificate/private key file.
1723 nm_utils_rsa_key_encrypt_aes (const GByteArray *data,
1724 const char *in_password,
1725 char **out_password,
1729 return nm_utils_rsa_key_encrypt_helper (CIPHER_AES_CBC,
1737 * nm_utils_file_is_pkcs12:
1738 * @filename: name of the file to test
1740 * Utility function to find out if the @filename is in PKCS#<!-- -->12 format.
1742 * Returns: %TRUE if the file is PKCS#<!-- -->12, %FALSE if it is not
1745 nm_utils_file_is_pkcs12 (const char *filename)
1747 return crypto_is_pkcs12_file (filename, NULL);
1750 /**********************************************************************************************/
1753 * nm_utils_file_search_in_paths:
1754 * @progname: the helper program name, like "iptables"
1755 * Must be a non-empty string, without path separator (/).
1756 * @try_first: (allow-none): a custom path to try first before searching.
1757 * It is silently ignored if it is empty or not an absolute path.
1758 * @paths: (allow-none): a %NULL terminated list of search paths.
1759 * Can be empty or %NULL, in which case only @try_first is checked.
1760 * @file_test_flags: the flags passed to g_file_test() when searching
1761 * for @progname. Set it to 0 to skip the g_file_test().
1762 * @predicate: (scope call): if given, pass the file name to this function
1763 * for additional checks. This check is performed after the check for
1764 * @file_test_flags. You cannot omit both @file_test_flags and @predicate.
1765 * @user_data: (closure): (allow-none): user data for @predicate function.
1766 * @error: (allow-none): on failure, set a "not found" error %G_IO_ERROR %G_IO_ERROR_NOT_FOUND.
1768 * Searches for a @progname file in a list of search @paths.
1770 * Returns: (transfer none): the full path to the helper, if found, or %NULL if not found.
1771 * The returned string is not owned by the caller, but later
1772 * invocations of the function might overwrite it.
1775 nm_utils_file_search_in_paths (const char *progname,
1776 const char *try_first,
1777 const char *const *paths,
1778 GFileTest file_test_flags,
1779 NMUtilsFileSearchInPathsPredicate predicate,
1786 g_return_val_if_fail (!error || !*error, NULL);
1787 g_return_val_if_fail (progname && progname[0] && !strchr (progname, '/'), NULL);
1788 g_return_val_if_fail (file_test_flags || predicate, NULL);
1790 /* Only consider @try_first if it is a valid, absolute path. This makes
1791 * it simpler to pass in a path from configure checks. */
1793 && try_first[0] == '/'
1794 && (file_test_flags == 0 || g_file_test (try_first, file_test_flags))
1795 && (!predicate || predicate (try_first, user_data)))
1796 return g_intern_string (try_first);
1798 if (!paths || !*paths)
1801 tmp = g_string_sized_new (50);
1802 for (; *paths; paths++) {
1805 g_string_append (tmp, *paths);
1806 if (tmp->str[tmp->len - 1] != '/')
1807 g_string_append_c (tmp, '/');
1808 g_string_append (tmp, progname);
1809 if ( (file_test_flags == 0 || g_file_test (tmp->str, file_test_flags))
1810 && (!predicate || predicate (tmp->str, user_data))) {
1811 ret = g_intern_string (tmp->str);
1812 g_string_free (tmp, TRUE);
1815 g_string_set_size (tmp, 0);
1817 g_string_free (tmp, TRUE);
1820 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Could not find \"%s\" binary"), progname);
1824 /**********************************************************************************************/
1826 /* Band, channel/frequency stuff for wireless */
1832 static struct cf_pair a_table[] = {
1882 static struct cf_pair bg_table[] = {
1902 * nm_utils_wifi_freq_to_channel:
1905 * Utility function to translate a Wi-Fi frequency to its corresponding channel.
1907 * Returns: the channel represented by the frequency or 0
1910 nm_utils_wifi_freq_to_channel (guint32 freq)
1915 while (a_table[i].chan && (a_table[i].freq != freq))
1917 return a_table[i].chan;
1919 while (bg_table[i].chan && (bg_table[i].freq != freq))
1921 return bg_table[i].chan;
1928 * nm_utils_wifi_channel_to_freq:
1930 * @band: frequency band for wireless ("a" or "bg")
1932 * Utility function to translate a Wi-Fi channel to its corresponding frequency.
1934 * Returns: the frequency represented by the channel of the band,
1935 * or -1 when the freq is invalid, or 0 when the band
1939 nm_utils_wifi_channel_to_freq (guint32 channel, const char *band)
1943 if (!strcmp (band, "a")) {
1944 while (a_table[i].chan && (a_table[i].chan != channel))
1946 return a_table[i].freq;
1947 } else if (!strcmp (band, "bg")) {
1948 while (bg_table[i].chan && (bg_table[i].chan != channel))
1950 return bg_table[i].freq;
1957 * nm_utils_wifi_find_next_channel:
1958 * @channel: current channel
1959 * @direction: whether going downward (0 or less) or upward (1 or more)
1960 * @band: frequency band for wireless ("a" or "bg")
1962 * Utility function to find out next/previous Wi-Fi channel for a channel.
1964 * Returns: the next channel in the specified direction or 0
1967 nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band)
1969 size_t a_size = sizeof (a_table) / sizeof (struct cf_pair);
1970 size_t bg_size = sizeof (bg_table) / sizeof (struct cf_pair);
1971 struct cf_pair *pair = NULL;
1973 if (!strcmp (band, "a")) {
1974 if (channel < a_table[0].chan)
1975 return a_table[0].chan;
1976 if (channel > a_table[a_size - 2].chan)
1977 return a_table[a_size - 2].chan;
1979 } else if (!strcmp (band, "bg")) {
1980 if (channel < bg_table[0].chan)
1981 return bg_table[0].chan;
1982 if (channel > bg_table[bg_size - 2].chan)
1983 return bg_table[bg_size - 2].chan;
1984 pair = &bg_table[0];
1986 g_assert_not_reached ();
1990 while (pair->chan) {
1991 if (channel == pair->chan)
1993 if ((channel < (pair+1)->chan) && (channel > pair->chan)) {
1995 return (pair+1)->chan;
2005 * nm_utils_wifi_is_channel_valid:
2007 * @band: frequency band for wireless ("a" or "bg")
2009 * Utility function to verify Wi-Fi channel validity.
2011 * Returns: %TRUE or %FALSE
2014 nm_utils_wifi_is_channel_valid (guint32 channel, const char *band)
2016 struct cf_pair *table = NULL;
2019 if (!strcmp (band, "a"))
2021 else if (!strcmp (band, "bg"))
2026 while (table[i].chan && (table[i].chan != channel))
2029 if (table[i].chan != 0)
2036 * nm_utils_hwaddr_len:
2037 * @type: the type of address; either <literal>ARPHRD_ETHER</literal> or
2038 * <literal>ARPHRD_INFINIBAND</literal>
2040 * Returns the length in octets of a hardware address of type @type.
2042 * Return value: the positive length, or -1 if the type is unknown/unsupported.
2045 nm_utils_hwaddr_len (int type)
2047 if (type == ARPHRD_ETHER)
2049 else if (type == ARPHRD_INFINIBAND)
2050 return INFINIBAND_ALEN;
2056 * nm_utils_hwaddr_type:
2057 * @len: the length of hardware address in bytes
2059 * Returns the type (either <literal>ARPHRD_ETHER</literal> or
2060 * <literal>ARPHRD_INFINIBAND</literal>) of the raw address given its length.
2062 * Return value: the type, either <literal>ARPHRD_ETHER</literal> or
2063 * <literal>ARPHRD_INFINIBAND</literal>. If the length is unexpected, return -1
2064 * (unsupported type/length).
2066 * Deprecated: This could not be extended to cover other types, since
2067 * there is not a one-to-one mapping between types and lengths. This
2068 * was mostly only used to get a type to pass to
2069 * nm_utils_hwaddr_ntoa() or nm_utils_hwaddr_aton() when you only had
2070 * a length; but you can just use nm_utils_hwaddr_ntoa_len() or
2071 * nm_utils_hwaddr_aton_len() now instead.
2074 nm_utils_hwaddr_type (int len)
2076 if (len == ETH_ALEN)
2077 return ARPHRD_ETHER;
2078 else if (len == INFINIBAND_ALEN)
2079 return ARPHRD_INFINIBAND;
2084 #define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
2087 * nm_utils_hwaddr_aton:
2088 * @asc: the ASCII representation of a hardware address
2089 * @type: the type of address; either <literal>ARPHRD_ETHER</literal> or
2090 * <literal>ARPHRD_INFINIBAND</literal>
2091 * @buffer: buffer to store the result into
2093 * Parses @asc and converts it to binary form in @buffer. See
2094 * nm_utils_hwaddr_atoba() if you'd rather have the result in a
2097 * See also nm_utils_hwaddr_aton_len(), which takes an output length
2098 * instead of a type.
2100 * Return value: @buffer, or %NULL if @asc couldn't be parsed
2103 nm_utils_hwaddr_aton (const char *asc, int type, gpointer buffer)
2105 int len = nm_utils_hwaddr_len (type);
2108 g_return_val_if_reached (NULL);
2111 return nm_utils_hwaddr_aton_len (asc, buffer, len);
2115 * nm_utils_hwaddr_atoba:
2116 * @asc: the ASCII representation of a hardware address
2117 * @type: the type of address; either <literal>ARPHRD_ETHER</literal> or
2118 * <literal>ARPHRD_INFINIBAND</literal>
2120 * Parses @asc and converts it to binary form in a #GByteArray. See
2121 * nm_utils_hwaddr_aton() if you don't want a #GByteArray.
2123 * Return value: (transfer full): a new #GByteArray, or %NULL if @asc couldn't
2127 nm_utils_hwaddr_atoba (const char *asc, int type)
2130 int len = nm_utils_hwaddr_len (type);
2133 g_return_val_if_reached (NULL);
2137 ba = g_byte_array_sized_new (len);
2138 g_byte_array_set_size (ba, len);
2139 if (!nm_utils_hwaddr_aton_len (asc, ba->data, len)) {
2140 g_byte_array_unref (ba);
2148 * nm_utils_hwaddr_ntoa:
2149 * @addr: a binary hardware address
2150 * @type: the type of address; either <literal>ARPHRD_ETHER</literal> or
2151 * <literal>ARPHRD_INFINIBAND</literal>
2153 * Converts @addr to textual form.
2155 * See also nm_utils_hwaddr_ntoa_len(), which takes a length instead of
2158 * Return value: (transfer full): the textual form of @addr
2161 nm_utils_hwaddr_ntoa (gconstpointer addr, int type)
2163 int len = nm_utils_hwaddr_len (type);
2166 g_return_val_if_reached (NULL);
2170 return nm_utils_hwaddr_ntoa_len (addr, len);
2174 * nm_utils_hwaddr_aton_len:
2175 * @asc: the ASCII representation of a hardware address
2176 * @buffer: buffer to store the result into
2177 * @length: the expected length in bytes of the result and
2178 * the size of the buffer in bytes.
2180 * Parses @asc and converts it to binary form in @buffer.
2181 * Bytes in @asc can be sepatared by colons (:), or hyphens (-), but not mixed.
2183 * Return value: @buffer, or %NULL if @asc couldn't be parsed
2184 * or would be shorter or longer than @length.
2189 nm_utils_hwaddr_aton_len (const char *asc, gpointer buffer, gsize length)
2191 const char *in = asc;
2192 guint8 *out = (guint8 *)buffer;
2193 char delimiter = '\0';
2196 g_return_val_if_reached (NULL);
2199 g_return_val_if_fail (buffer, NULL);
2200 g_return_val_if_fail (length, NULL);
2202 while (length && *in) {
2203 guint8 d1 = in[0], d2 = in[1];
2205 if (!g_ascii_isxdigit (d1))
2208 /* If there's no leading zero (ie "aa:b:cc") then fake it */
2209 if (d2 && g_ascii_isxdigit (d2)) {
2210 *out++ = (HEXVAL (d1) << 4) + HEXVAL (d2);
2213 /* Fake leading zero */
2214 *out++ = (HEXVAL ('0') << 4) + HEXVAL (d1);
2220 if (delimiter == '\0') {
2221 if (*in == ':' || *in == '-')
2226 if (*in != delimiter)
2233 if (length == 0 && !*in)
2240 * nm_utils_hwaddr_ntoa_len:
2241 * @addr: a binary hardware address
2242 * @length: the length of @addr
2244 * Converts @addr to textual form.
2246 * Return value: (transfer full): the textual form of @addr
2251 nm_utils_hwaddr_ntoa_len (gconstpointer addr, gsize length)
2253 const guint8 *in = addr;
2255 const char *LOOKUP = "0123456789ABCDEF";
2257 g_return_val_if_fail (addr != NULL, g_strdup (""));
2258 g_return_val_if_fail (length != 0, g_strdup (""));
2260 result = out = g_malloc (length * 3);
2264 *out++ = LOOKUP[v >> 4];
2265 *out++ = LOOKUP[v & 0x0F];
2266 if (--length == 0) {
2275 * nm_utils_hwaddr_valid:
2276 * @asc: the ASCII representation of a hardware address
2278 * Parses @asc to see if it is a valid hardware address of some type.
2280 * Return value: %TRUE if @asc appears to be a valid hardware address
2281 * of some type, %FALSE if not.
2286 nm_utils_hwaddr_valid (const char *asc)
2288 guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
2289 gsize in_len, out_len;
2293 in_len = strlen (asc);
2294 if ((in_len + 1) % 3 != 0)
2296 out_len = (in_len + 1) / 3;
2297 if (out_len > NM_UTILS_HWADDR_LEN_MAX)
2299 return nm_utils_hwaddr_aton_len (asc, buf, out_len) != NULL;
2303 * nm_utils_bin2hexstr:
2304 * @bytes: an array of bytes
2305 * @len: the length of the @bytes array
2306 * @final_len: an index where to cut off the returned string, or -1
2308 * Converts a byte-array @bytes into a hexadecimal string.
2309 * If @final_len is greater than -1, the returned string is terminated at
2310 * that index (returned_string[final_len] == '\0'),
2312 * Return value: (transfer full): the textual form of @bytes
2317 * Code originally by Alex Larsson <alexl@redhat.com> and
2318 * copyright Red Hat, Inc. under terms of the LGPL.
2321 nm_utils_bin2hexstr (const char *bytes, int len, int final_len)
2323 static char hex_digits[] = "0123456789abcdef";
2326 gsize buflen = (len * 2) + 1;
2328 g_return_val_if_fail (bytes != NULL, NULL);
2329 g_return_val_if_fail (len > 0, NULL);
2330 g_return_val_if_fail (len < 4096, NULL); /* Arbitrary limit */
2332 g_return_val_if_fail (final_len < buflen, NULL);
2334 result = g_malloc0 (buflen);
2335 for (i = 0; i < len; i++) {
2336 result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
2337 result[2*i+1] = hex_digits[bytes[i] & 0xf];
2339 /* Cut converted key off at the correct length for this cipher type */
2341 result[final_len] = '\0';
2343 result[buflen - 1] = '\0';
2348 /* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
2350 * nm_utils_hex2byte:
2351 * @hex: a string representing a hex byte
2353 * Converts a hex string (2 characters) into its byte representation.
2355 * Return value: a byte, or -1 if @hex doesn't represent a hex byte
2360 nm_utils_hex2byte (const char *hex)
2363 a = g_ascii_xdigit_value (*hex++);
2366 b = g_ascii_xdigit_value (*hex++);
2369 return (a << 4) | b;
2373 * nm_utils_hexstr2bin:
2374 * @hex: an hex string
2375 * @len: the length of the @hex string (it has to be even)
2377 * Converts a hexadecimal string @hex into a byte-array. The returned array
2380 * Return value: (transfer full): a array of bytes, or %NULL on error
2385 nm_utils_hexstr2bin (const char *hex, size_t len)
2389 const char * ipos = hex;
2393 /* Length must be a multiple of 2 */
2397 opos = buf = g_malloc0 ((len / 2) + 1);
2398 for (i = 0; i < len; i += 2) {
2399 a = nm_utils_hex2byte (ipos);
2409 /* End from hostap */
2412 * nm_utils_iface_valid_name:
2413 * @name: Name of interface
2415 * This function is a 1:1 copy of the kernel's interface validation
2416 * function in net/core/dev.c.
2418 * Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
2423 nm_utils_iface_valid_name (const char *name)
2425 g_return_val_if_fail (name != NULL, FALSE);
2430 if (strlen (name) >= 16)
2433 if (!strcmp (name, ".") || !strcmp (name, ".."))
2437 if (*name == '/' || g_ascii_isspace (*name))
2447 * @str: a string that might be a UUID
2449 * Checks if @str is a UUID
2451 * Returns: %TRUE if @str is a UUID, %FALSE if not
2456 nm_utils_is_uuid (const char *str)
2458 const char *p = str;
2464 else if (!g_ascii_isxdigit (*p))
2469 if ((num_dashes == 4) && (p - str == 36))
2472 /* Backwards compat for older configurations */
2473 if ((num_dashes == 0) && (p - str == 40))
2479 static char _nm_utils_inet_ntop_buffer[NM_UTILS_INET_ADDRSTRLEN];
2482 * nm_utils_inet4_ntop: (skip)
2483 * @inaddr: the address that should be converted to string.
2484 * @dst: the destination buffer, it must contain at least
2485 * <literal>INET_ADDRSTRLEN</literal> or %NM_UTILS_INET_ADDRSTRLEN
2486 * characters. If set to %NULL, it will return a pointer to an internal, static
2487 * buffer (shared with nm_utils_inet6_ntop()). Beware, that the internal
2488 * buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
2489 * nm_utils_inet6_ntop() that does not provied it's own @dst buffer. Also,
2490 * using the internal buffer is not thread safe. When in doubt, pass your own
2491 * @dst buffer to avoid these issues.
2493 * Wrapper for inet_ntop.
2495 * Returns: the input buffer @dst, or a pointer to an
2496 * internal, static buffer. This function cannot fail.
2501 nm_utils_inet4_ntop (in_addr_t inaddr, char *dst)
2503 return inet_ntop (AF_INET, &inaddr, dst ? dst : _nm_utils_inet_ntop_buffer,
2508 * nm_utils_inet6_ntop: (skip)
2509 * @in6addr: the address that should be converted to string.
2510 * @dst: the destination buffer, it must contain at least
2511 * <literal>INET6_ADDRSTRLEN</literal> or %NM_UTILS_INET_ADDRSTRLEN
2512 * characters. If set to %NULL, it will return a pointer to an internal, static
2513 * buffer (shared with nm_utils_inet4_ntop()). Beware, that the internal
2514 * buffer will be overwritten with ever new call of nm_utils_inet4_ntop() or
2515 * nm_utils_inet6_ntop() that does not provied it's own @dst buffer. Also,
2516 * using the internal buffer is not thread safe. When in doubt, pass your own
2517 * @dst buffer to avoid these issues.
2519 * Wrapper for inet_ntop.
2521 * Returns: the input buffer @dst, or a pointer to an
2522 * internal, static buffer. %NULL is not allowed as @in6addr,
2523 * otherwise, this function cannot fail.
2528 nm_utils_inet6_ntop (const struct in6_addr *in6addr, char *dst)
2530 g_return_val_if_fail (in6addr, NULL);
2531 return inet_ntop (AF_INET6, in6addr, dst ? dst : _nm_utils_inet_ntop_buffer,
2536 * nm_utils_check_virtual_device_compatibility:
2537 * @virtual_type: a virtual connection type
2538 * @other_type: a connection type to test against @virtual_type
2540 * Determines if a connection of type @virtual_type can (in the
2541 * general case) work with connections of type @other_type.
2543 * If @virtual_type is %NM_TYPE_SETTING_VLAN, then this checks if
2544 * @other_type is a valid type for the parent of a VLAN.
2546 * If @virtual_type is a "master" type (eg, %NM_TYPE_SETTING_BRIDGE),
2547 * then this checks if @other_type is a valid type for a slave of that
2550 * Note that even if this returns %TRUE it is not guaranteed that
2551 * <emphasis>every</emphasis> connection of type @other_type is
2552 * compatible with @virtual_type; it may depend on the exact
2553 * configuration of the two connections, or on the capabilities of an
2554 * underlying device driver.
2556 * Returns: %TRUE or %FALSE
2561 nm_utils_check_virtual_device_compatibility (GType virtual_type, GType other_type)
2563 g_return_val_if_fail (_nm_setting_type_is_base_type (virtual_type), FALSE);
2564 g_return_val_if_fail (_nm_setting_type_is_base_type (other_type), FALSE);
2566 if (virtual_type == NM_TYPE_SETTING_BOND) {
2567 return ( other_type == NM_TYPE_SETTING_INFINIBAND
2568 || other_type == NM_TYPE_SETTING_WIRED
2569 || other_type == NM_TYPE_SETTING_BRIDGE
2570 || other_type == NM_TYPE_SETTING_BOND
2571 || other_type == NM_TYPE_SETTING_TEAM
2572 || other_type == NM_TYPE_SETTING_VLAN);
2573 } else if (virtual_type == NM_TYPE_SETTING_BRIDGE) {
2574 return ( other_type == NM_TYPE_SETTING_WIRED
2575 || other_type == NM_TYPE_SETTING_BOND
2576 || other_type == NM_TYPE_SETTING_TEAM
2577 || other_type == NM_TYPE_SETTING_VLAN);
2578 } else if (virtual_type == NM_TYPE_SETTING_TEAM) {
2579 return ( other_type == NM_TYPE_SETTING_WIRED
2580 || other_type == NM_TYPE_SETTING_BRIDGE
2581 || other_type == NM_TYPE_SETTING_BOND
2582 || other_type == NM_TYPE_SETTING_TEAM
2583 || other_type == NM_TYPE_SETTING_VLAN);
2584 } else if (virtual_type == NM_TYPE_SETTING_VLAN) {
2585 return ( other_type == NM_TYPE_SETTING_WIRED
2586 || other_type == NM_TYPE_SETTING_WIRELESS
2587 || other_type == NM_TYPE_SETTING_BRIDGE
2588 || other_type == NM_TYPE_SETTING_BOND
2589 || other_type == NM_TYPE_SETTING_TEAM
2590 || other_type == NM_TYPE_SETTING_VLAN);
2592 g_warn_if_reached ();
2597 /***********************************************************/
2599 /* Unused prototypes to make the compiler happy */
2600 gconstpointer nm_utils_get_private (void);
2601 gconstpointer nm_util_get_private (void);
2605 * nm_utils_get_private:
2607 * Entry point for NetworkManager-internal API. You should not use this
2608 * function for any reason.
2610 * Returns: Who knows? It's a mystery.
2615 nm_utils_get_private (void)
2617 /* We told you not to use it! */
2618 g_assert_not_reached ();
2622 * nm_util_get_private:
2624 * You should not use this function for any reason.
2626 * Returns: Who knows? It's a mystery.
2631 nm_util_get_private (void)
2633 /* We told you not to use it! */
2634 g_assert_not_reached ();