diff options
| author | Michael Biebl <biebl@debian.org> | 2020-04-11 21:28:04 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2020-04-11 21:28:04 +0200 |
| commit | 1e5977b62f896e844b548c3007ace9e1dfa7f9ed (patch) | |
| tree | 7a7416ed410e72b6200f3d860fd315ec11cc106b /src/nm-core-utils.c | |
| parent | b012fa6e1d808e0736c009799c62d835cbfcc1dd (diff) | |
New upstream version 1.23.90 upstream/1.23.90
Diffstat (limited to 'src/nm-core-utils.c')
| -rw-r--r-- | src/nm-core-utils.c | 455 |
1 files changed, 436 insertions, 19 deletions
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index e059994a..a9f50a0f 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -436,7 +436,7 @@ static const char * _kc_waited_to_string (char *buf, gint64 wait_start_us) #define _kc_waited_to_string(buf, wait_start_us) ( G_STATIC_ASSERT_EXPR(sizeof (buf) == KC_WAITED_TO_STRING && sizeof ((buf)[0]) == 1), _kc_waited_to_string (buf, wait_start_us) ) { - g_snprintf (buf, KC_WAITED_TO_STRING, " (%ld usec elapsed)", (long) (nm_utils_get_monotonic_timestamp_us () - wait_start_us)); + g_snprintf (buf, KC_WAITED_TO_STRING, " (%ld usec elapsed)", (long) (nm_utils_get_monotonic_timestamp_usec () - wait_start_us)); return buf; } @@ -476,7 +476,7 @@ _kc_cb_timeout_grace_period (void *user_data) } } else { nm_log_dbg (data->log_domain, "%s: process not terminated after %ld usec. Sending SIGKILL signal", - data->log_name, (long) (nm_utils_get_monotonic_timestamp_us () - data->async.wait_start_us)); + data->log_name, (long) (nm_utils_get_monotonic_timestamp_usec () - data->async.wait_start_us)); } return G_SOURCE_REMOVE; @@ -591,7 +591,7 @@ nm_utils_kill_child_async (pid_t pid, int sig, NMLogDomain log_domain, } data = _kc_async_data_alloc (pid, log_domain, log_name, callback, user_data); - data->async.wait_start_us = nm_utils_get_monotonic_timestamp_us (); + data->async.wait_start_us = nm_utils_get_monotonic_timestamp_usec (); if (sig != SIGKILL && wait_before_kill_msec > 0) { data->async.source_timeout_kill_id = g_timeout_add (wait_before_kill_msec, _kc_cb_timeout_grace_period, data); @@ -694,7 +694,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char goto out; } - wait_start_us = nm_utils_get_monotonic_timestamp_us (); + wait_start_us = nm_utils_get_monotonic_timestamp_usec (); /* wait for the process to terminated... */ if (sig != SIGKILL) { @@ -728,7 +728,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char if (!wait_until) break; - now = nm_utils_get_monotonic_timestamp_us (); + now = nm_utils_get_monotonic_timestamp_usec (); if (now >= wait_until) break; @@ -871,7 +871,7 @@ nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain /* wait for the process to terminate... */ - wait_start_us = nm_utils_get_monotonic_timestamp_us (); + wait_start_us = nm_utils_get_monotonic_timestamp_usec (); sleep_duration_usec = _sleep_duration_convert_ms_to_us (sleep_duration_msec); if (sig != SIGKILL && wait_before_kill_msec) @@ -922,7 +922,7 @@ nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain } sleep_time = sleep_duration_usec; - now = nm_utils_get_monotonic_timestamp_us (); + now = nm_utils_get_monotonic_timestamp_usec (); if ( max_wait_until != 0 && now >= max_wait_until) { @@ -2434,7 +2434,7 @@ _host_id_read_timestamp (gboolean use_secret_key_file, && stat (SECRET_KEY_FILE, &st) == 0) { /* don't check for overflow or timestamps in the future. We get whatever * (bogus) date is on the file. */ - *out_timestamp_ns = nm_utils_timespec_to_ns (&st.st_mtim); + *out_timestamp_ns = nm_utils_timespec_to_nsec (&st.st_mtim); return TRUE; } @@ -2453,13 +2453,13 @@ _host_id_read_timestamp (gboolean use_secret_key_file, * is not stable across restarts, but apparently neither is the host-id * nor the secret_key itself. */ -#define EPOCH_TWO_YEARS (G_GINT64_CONSTANT (2 * 365 * 24 * 3600) * NM_UTILS_NS_PER_SECOND) +#define EPOCH_TWO_YEARS (G_GINT64_CONSTANT (2 * 365 * 24 * 3600) * NM_UTILS_NSEC_PER_SEC) v = nm_hash_siphash42 (1156657133u, host_id, host_id_len); now = time (NULL); *out_timestamp_ns = NM_MAX ((gint64) 1, - (now * NM_UTILS_NS_PER_SECOND) - ((gint64) (v % ((guint64) (EPOCH_TWO_YEARS))))); + (now * NM_UTILS_NSEC_PER_SEC) - ((gint64) (v % ((guint64) (EPOCH_TWO_YEARS))))); return FALSE; } @@ -2741,6 +2741,59 @@ nm_utils_boot_id_bin (void) /*****************************************************************************/ +const char * +nm_utils_proc_cmdline (void) +{ + static const char *volatile proc_cmdline_cached = NULL; + const char *proc_cmdline; + +again: + proc_cmdline = g_atomic_pointer_get (&proc_cmdline_cached); + if (G_UNLIKELY (!proc_cmdline)) { + gs_free char *str = NULL; + + g_file_get_contents ("/proc/cmdline", &str, NULL, NULL); + str = nm_str_realloc (str); + + proc_cmdline = str ?: ""; + if (!g_atomic_pointer_compare_and_exchange (&proc_cmdline_cached, NULL, proc_cmdline)) + goto again; + + g_steal_pointer (&str); + } + + return proc_cmdline; +} + +const char *const* +nm_utils_proc_cmdline_split (void) +{ + static const char *const*volatile proc_cmdline_cached = NULL; + const char *const*proc_cmdline; + +again: + proc_cmdline = g_atomic_pointer_get (&proc_cmdline_cached); + if (G_UNLIKELY (!proc_cmdline)) { + gs_free const char **split = NULL; + + /* TODO: support quotation, like systemd's proc_cmdline_extract_first(). + * For that, add a new NMUtilsStrsplitSetFlags flag. */ + split = nm_utils_strsplit_set_full (nm_utils_proc_cmdline (), + NM_ASCII_WHITESPACES, + NM_UTILS_STRSPLIT_SET_FLAGS_NONE); + proc_cmdline = split + ?: NM_PTRARRAY_EMPTY (const char *); + if (!g_atomic_pointer_compare_and_exchange (&proc_cmdline_cached, NULL, proc_cmdline)) + goto again; + + g_steal_pointer (&split); + } + + return proc_cmdline; +} + +/*****************************************************************************/ + /** * nm_utils_arp_type_detect_from_hwaddrlen: * @hwaddr_len: the length of the hardware address in bytes. @@ -2999,12 +3052,14 @@ nm_utils_ipv6_interface_identifier_get_from_token (NMUtilsIPv6IfaceId *iid, * Returns: the input buffer filled with the id as string. */ const char * -nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid, char *buf) +nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid, + char buf[static INET6_ADDRSTRLEN]) { struct in6_addr i6_token = { .s6_addr = { 0, } }; + nm_assert (buf); nm_utils_ipv6_addr_set_interface_identifier (&i6_token, iid); - return nm_utils_inet6_ntop (&i6_token, buf); + return _nm_utils_inet6_ntop (&i6_token, buf); } /*****************************************************************************/ @@ -3721,7 +3776,7 @@ nm_utils_lifetime_get (guint32 timestamp, } if (now <= 0) - now = nm_utils_get_monotonic_timestamp_s (); + now = nm_utils_get_monotonic_timestamp_sec (); t_lifetime = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now); if (!t_lifetime) { @@ -4053,24 +4108,386 @@ GVariant * nm_utils_strdict_to_variant (GHashTable *options) { GVariantBuilder builder; - gs_free const char **keys = NULL; + gs_free NMUtilsNamedValue *values = NULL; guint i; - guint nkeys; + guint n; - keys = nm_utils_strdict_get_keys (options, TRUE, &nkeys); + values = nm_utils_named_values_from_str_dict (options, &n); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - for (i = 0; i < nkeys; i++) { + for (i = 0; i < n; i++) { g_variant_builder_add (&builder, "{sv}", - keys[i], - g_variant_new_string (g_hash_table_lookup (options, keys[i]))); + values[i].name, + g_variant_new_string (values[i].value_str)); } return g_variant_builder_end (&builder); } /*****************************************************************************/ +static guint32 +get_max_rate_ht_20 (int mcs) +{ + switch (mcs) { + case 0: return 6500000; + case 1: + case 8: return 13000000; + case 2: + case 16: return 19500000; + case 3: + case 9: + case 24: return 26000000; + case 4: + case 10: + case 17: return 39000000; + case 5: + case 11: + case 25: return 52000000; + case 6: + case 18: return 58500000; + case 7: return 65000000; + case 12: + case 19: + case 26: return 78000000; + case 13: + case 27: return 104000000; + case 14: + case 20: return 117000000; + case 15: return 130000000; + case 21: + case 28: return 156000000; + case 22: return 175500000; + case 23: return 195000000; + case 29: return 208000000; + case 30: return 234000000; + case 31: return 260000000; + } + return 0; +} + +static guint32 +get_max_rate_ht_40 (int mcs) +{ + switch (mcs) { + case 0: return 13500000; + case 1: + case 8: return 27000000; + case 2: return 40500000; + case 3: + case 9: + case 24: return 54000000; + case 4: + case 10: + case 17: return 81000000; + case 5: + case 11: + case 25: return 108000000; + case 6: + case 18: return 121500000; + case 7: return 135000000; + case 12: + case 19: + case 26: return 162000000; + case 13: + case 27: return 216000000; + case 14: + case 20: return 243000000; + case 15: return 270000000; + case 16: return 40500000; + case 21: + case 28: return 324000000; + case 22: return 364500000; + case 23: return 405000000; + case 29: return 432000000; + case 30: return 486000000; + case 31: return 540000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_80_ss1 (int mcs) +{ + switch (mcs) { + case 0: return 29300000; + case 1: return 58500000; + case 2: return 87800000; + case 3: return 117000000; + case 4: return 175500000; + case 5: return 234000000; + case 6: return 263300000; + case 7: return 292500000; + case 8: return 351000000; + case 9: return 390000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_80_ss2 (int mcs) +{ + switch (mcs) { + case 0: return 58500000; + case 1: return 117000000; + case 2: return 175500000; + case 3: return 234000000; + case 4: return 351000000; + case 5: return 468000000; + case 6: return 526500000; + case 7: return 585000000; + case 8: return 702000000; + case 9: return 780000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_80_ss3 (int mcs) +{ + switch (mcs) { + case 0: return 87800000; + case 1: return 175500000; + case 2: return 263300000; + case 3: return 351000000; + case 4: return 526500000; + case 5: return 702000000; + case 6: return 0; + case 7: return 877500000; + case 8: return 105300000; + case 9: return 117000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_160_ss1 (int mcs) +{ + switch (mcs) { + case 0: return 58500000; + case 1: return 117000000; + case 2: return 175500000; + case 3: return 234000000; + case 4: return 351000000; + case 5: return 468000000; + case 6: return 526500000; + case 7: return 585000000; + case 8: return 702000000; + case 9: return 780000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_160_ss2 (int mcs) +{ + switch (mcs) { + case 0: return 117000000; + case 1: return 234000000; + case 2: return 351000000; + case 3: return 468000000; + case 4: return 702000000; + case 5: return 936000000; + case 6: return 1053000000; + case 7: return 1170000000; + case 8: return 1404000000; + case 9: return 1560000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_160_ss3 (int mcs) +{ + switch (mcs) { + case 0: return 175500000; + case 1: return 351000000; + case 2: return 526500000; + case 3: return 702000000; + case 4: return 1053000000; + case 5: return 1404000000; + case 6: return 1579500000; + case 7: return 1755000000; + case 8: return 2106000000; + case 9: return 0; + } + return 0; +} + +static gboolean +get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) +{ + guint32 i; + guint8 ht_cap_info; + const guint8 *supported_mcs_set; + guint32 rate; + + /* http://standards.ieee.org/getieee802/download/802.11-2012.pdf + * https://mrncciew.com/2014/10/19/cwap-ht-capabilities-ie/ + */ + + if (len != 26) + return FALSE; + + ht_cap_info = bytes[0]; + supported_mcs_set = &bytes[3]; + *out_maxrate = 0; + + /* Find the maximum supported mcs rate */ + for (i = 0; i <= 76; i++) { + const unsigned mcs_octet = i / 8; + const unsigned MCS_RATE_BIT = 1 << i % 8; + + if (supported_mcs_set[mcs_octet] & MCS_RATE_BIT) { + /* Check for 40Mhz wide channel support */ + if (ht_cap_info & (1 << 1)) + rate = get_max_rate_ht_40 (i); + else + rate = get_max_rate_ht_20 (i); + + if (rate > *out_maxrate) + *out_maxrate = rate; + } + } + + return TRUE; +} + +static gboolean +get_max_rate_vht (const guint8 *bytes, guint len, guint32 *out_maxrate) +{ + guint32 mcs, m; + guint8 vht_cap, tx_map; + + /* https://tda802dot11.blogspot.it/2014/10/vht-capabilities-element-vht.html + * http://chimera.labs.oreilly.com/books/1234000001739/ch03.html#management_frames */ + + if (len != 12) + return FALSE; + + vht_cap = bytes[0]; + tx_map = bytes[8]; + + /* Check for mcs rates 8 and 9 support */ + if (tx_map & 0x2a) + mcs = 9; + else if (tx_map & 0x15) + mcs = 8; + else + mcs = 7; + + /* Check for 160Mhz wide channel support and + * spatial stream support */ + if (vht_cap & (1 << 2)) { + if (tx_map & 0x30) + m = get_max_rate_vht_160_ss3 (mcs); + else if (tx_map & 0x0C) + m = get_max_rate_vht_160_ss2 (mcs); + else + m = get_max_rate_vht_160_ss1 (mcs); + } else { + if (tx_map & 0x30) + m = get_max_rate_vht_80_ss3 (mcs); + else if (tx_map & 0x0C) + m = get_max_rate_vht_80_ss2 (mcs); + else + m = get_max_rate_vht_80_ss1 (mcs); + } + + *out_maxrate = m; + return TRUE; +} + +/* Management Frame Information Element IDs, ieee80211_eid */ +#define WLAN_EID_HT_CAPABILITY 45 +#define WLAN_EID_VHT_CAPABILITY 191 +#define WLAN_EID_VENDOR_SPECIFIC 221 + +void +nm_wifi_utils_parse_ies (const guint8 *bytes, + gsize len, + guint32 *out_max_rate, + gboolean *out_metered, + gboolean *out_owe_transition_mode) +{ + guint8 id, elem_len; + guint32 m; + + NM_SET_OUT (out_max_rate, 0); + NM_SET_OUT (out_metered, FALSE); + NM_SET_OUT (out_owe_transition_mode, FALSE); + + while (len) { + if (len < 2) + break; + + id = *bytes++; + elem_len = *bytes++; + len -= 2; + + if (elem_len > len) + break; + + switch (id) { + case WLAN_EID_HT_CAPABILITY: + if (out_max_rate) { + if (get_max_rate_ht (bytes, elem_len, &m)) + *out_max_rate = NM_MAX (*out_max_rate, m); + } + break; + case WLAN_EID_VHT_CAPABILITY: + if (out_max_rate) { + if (get_max_rate_vht (bytes, elem_len, &m)) + *out_max_rate = NM_MAX (*out_max_rate, m); + } + break; + case WLAN_EID_VENDOR_SPECIFIC: + if (out_metered) { + if ( len == 8 + && bytes[0] == 0x00 /* OUI: Microsoft */ + && bytes[1] == 0x50 + && bytes[2] == 0xf2 + && bytes[3] == 0x11) /* OUI type: Network cost */ + *out_metered = (bytes[7] > 1); /* Cost level > 1 */ + } + if ( out_owe_transition_mode + && elem_len >= 10 + && bytes[0] == 0x50 /* OUI: WiFi Alliance */ + && bytes[1] == 0x6f + && bytes[2] == 0x9a + && bytes[3] == 0x1c) /* OUI type: OWE Transition Mode */ + *out_owe_transition_mode = TRUE; + break; + } + + len -= elem_len; + bytes += elem_len; + } +} + +/*****************************************************************************/ + +guint8 +nm_wifi_utils_level_to_quality (int val) +{ + if (val < 0) { + /* Assume dBm already; rough conversion: best = -40, worst = -100 */ + val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */ + val = 100 - (int) ((100.0 * (double) val) / 60.0); + } else if (val > 110 && val < 256) { + /* assume old-style WEXT 8-bit unsigned signal level */ + val -= 256; /* subtract 256 to convert to dBm */ + val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */ + val = 100 - (int) ((100.0 * (double) val) / 60.0); + } else { + /* Assume signal is a "quality" percentage */ + } + + return CLAMP (val, 0, 100); +} + +/*****************************************************************************/ + NM_UTILS_ENUM2STR_DEFINE (nm_icmpv6_router_pref_to_string, NMIcmpv6RouterPref, NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_LOW, "low"), NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_MEDIUM, "medium"), |