diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 1f2a21a17c..7ccc5cffd5 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -833,47 +833,72 @@ nm_utils_find_helper(const char *progname, const char *try_first, GError **error #define MAC_TAG "mac:" #define INTERFACE_NAME_TAG "interface-name:" #define SUBCHAN_TAG "s390-subchannels:" +#define EXCEPT_TAG "except:" -gboolean +static const char * +_match_except (const char *spec_str, gboolean *out_except) +{ + if (!g_ascii_strncasecmp (spec_str, EXCEPT_TAG, STRLEN (EXCEPT_TAG))) { + spec_str += STRLEN (EXCEPT_TAG); + *out_except = TRUE; + } else + *out_except = FALSE; + return spec_str; +} + +NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr) { const GSList *iter; + NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH; - g_return_val_if_fail (hwaddr != NULL, FALSE); + g_return_val_if_fail (hwaddr != NULL, NM_MATCH_SPEC_NO_MATCH); for (iter = specs; iter; iter = g_slist_next (iter)) { const char *spec_str = iter->data; + gboolean except; if (!spec_str || !*spec_str) continue; + spec_str = _match_except (spec_str, &except); + if ( !g_ascii_strncasecmp (spec_str, INTERFACE_NAME_TAG, STRLEN (INTERFACE_NAME_TAG)) || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG))) continue; if (!g_ascii_strncasecmp (spec_str, MAC_TAG, STRLEN (MAC_TAG))) spec_str += STRLEN (MAC_TAG); + else if (except) + continue; - if (nm_utils_hwaddr_matches (spec_str, -1, hwaddr, -1)) - return TRUE; + if (nm_utils_hwaddr_matches (spec_str, -1, hwaddr, -1)) { + if (except) + return NM_MATCH_SPEC_NEG_MATCH; + match = NM_MATCH_SPEC_MATCH; + } } - return FALSE; + return match; } -gboolean +NMMatchSpecMatchType nm_match_spec_interface_name (const GSList *specs, const char *interface_name) { const GSList *iter; + NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH; - g_return_val_if_fail (interface_name != NULL, FALSE); + g_return_val_if_fail (interface_name != NULL, NM_MATCH_SPEC_NO_MATCH); for (iter = specs; iter; iter = g_slist_next (iter)) { const char *spec_str = iter->data; gboolean use_pattern = FALSE; + gboolean except; if (!spec_str || !*spec_str) continue; + spec_str = _match_except (spec_str, &except); + if ( !g_ascii_strncasecmp (spec_str, MAC_TAG, STRLEN (MAC_TAG)) || !g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG))) continue; @@ -887,14 +912,17 @@ nm_match_spec_interface_name (const GSList *specs, const char *interface_name) spec_str += 1; use_pattern=TRUE; } - } + } else if (except) + continue; - if (!strcmp (spec_str, interface_name)) - return TRUE; - if (use_pattern && g_pattern_match_simple (spec_str, interface_name)) - return TRUE; + if ( !strcmp (spec_str, interface_name) + || (use_pattern && g_pattern_match_simple (spec_str, interface_name))) { + if (except) + return NM_MATCH_SPEC_NEG_MATCH; + match = NM_MATCH_SPEC_MATCH; + } } - return FALSE; + return match; } #define BUFSIZE 10 @@ -963,34 +991,40 @@ parse_subchannels (const char *subchannels, guint32 *a, guint32 *b, guint32 *c) return TRUE; } -gboolean +NMMatchSpecMatchType nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels) { const GSList *iter; guint32 a = 0, b = 0, c = 0; guint32 spec_a = 0, spec_b = 0, spec_c = 0; + NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH; - g_return_val_if_fail (subchannels != NULL, FALSE); + g_return_val_if_fail (subchannels != NULL, NM_MATCH_SPEC_NO_MATCH); if (!parse_subchannels (subchannels, &a, &b, &c)) - return FALSE; + return NM_MATCH_SPEC_NO_MATCH; for (iter = specs; iter; iter = g_slist_next (iter)) { const char *spec_str = iter->data; + gboolean except; if (!spec_str || !*spec_str) continue; + spec_str = _match_except (spec_str, &except); + if (!g_ascii_strncasecmp (spec_str, SUBCHAN_TAG, STRLEN (SUBCHAN_TAG))) { spec_str += STRLEN (SUBCHAN_TAG); if (parse_subchannels (spec_str, &spec_a, &spec_b, &spec_c)) { - if (a == spec_a && b == spec_b && c == spec_c) - return TRUE; + if (a == spec_a && b == spec_b && c == spec_c) { + if (except) + return NM_MATCH_SPEC_NEG_MATCH; + match = NM_MATCH_SPEC_MATCH; + } } } } - - return FALSE; + return match; } const char * diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index d11f1fa204..c0f313c2f5 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -94,9 +94,15 @@ const char *nm_utils_find_helper (const char *progname, const char *try_first, GError **error); -gboolean nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr); -gboolean nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels); -gboolean nm_match_spec_interface_name (const GSList *specs, const char *interface_name); +typedef enum { + NM_MATCH_SPEC_NO_MATCH = 0, + NM_MATCH_SPEC_MATCH = 1, + NM_MATCH_SPEC_NEG_MATCH = 2, +} NMMatchSpecMatchType; + +NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr); +NMMatchSpecMatchType nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels); +NMMatchSpecMatchType nm_match_spec_interface_name (const GSList *specs, const char *interface_name); const char *nm_utils_get_shared_wifi_permission (NMConnection *connection); diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 0bab1f5b97..7fa3d3a41e 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -1495,15 +1495,19 @@ new_default_connection (NMDevice *self) return connection; } -static gboolean +static NMMatchSpecMatchType spec_match_list (NMDevice *device, const GSList *specs) { + NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m; NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); - if (priv->subchannels && nm_match_spec_s390_subchannels (specs, priv->subchannels)) - return TRUE; - - return NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs); + if (priv->subchannels) + matched = nm_match_spec_s390_subchannels (specs, priv->subchannels); + if (matched != NM_MATCH_SPEC_NEG_MATCH) { + m = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->spec_match_list (device, specs); + matched = MAX (matched, m); + } + return matched; } static void diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index a5059fdf34..649b1c8ec9 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -8209,27 +8209,30 @@ nm_device_spec_match_list (NMDevice *self, const GSList *specs) if (!specs) return FALSE; - return NM_DEVICE_GET_CLASS (self)->spec_match_list (self, specs); + return NM_DEVICE_GET_CLASS (self)->spec_match_list (self, specs) == NM_MATCH_SPEC_MATCH; } -static gboolean +static NMMatchSpecMatchType spec_match_list (NMDevice *self, const GSList *specs) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean matched = FALSE; + NMMatchSpecMatchType matched = NM_MATCH_SPEC_NO_MATCH, m; const GSList *iter; for (iter = specs; iter; iter = g_slist_next (iter)) { - if (!strcmp ((const char *) iter->data, "*")) - return TRUE; + if (!strcmp ((const char *) iter->data, "*")) { + matched = NM_MATCH_SPEC_MATCH; + break; + } + } + if (priv->hw_addr_len) { + m = nm_match_spec_hwaddr (specs, priv->hw_addr); + matched = MAX (matched, m); + } + if (matched != NM_MATCH_SPEC_NEG_MATCH) { + m = nm_match_spec_interface_name (specs, nm_device_get_iface (self)); + matched = MAX (matched, m); } - - if (priv->hw_addr_len) - matched = nm_match_spec_hwaddr (specs, priv->hw_addr); - - if (!matched) - matched = nm_match_spec_interface_name (specs, nm_device_get_iface (self)); - return matched; } diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index c7971b4cb5..67bc18b0fd 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -213,7 +213,7 @@ typedef struct { /* Sync deactivating (in the DISCONNECTED phase) */ void (* deactivate) (NMDevice *self); - gboolean (* spec_match_list) (NMDevice *self, const GSList *specs); + NMMatchSpecMatchType (* spec_match_list) (NMDevice *self, const GSList *specs); /* Update the connection with currently configured L2 settings */ void (* update_connection) (NMDevice *device, NMConnection *connection); diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 15320191ba..b26b0e2aec 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -803,7 +803,7 @@ _test_match_spec_contains (const char **matches, const char *match) } static void -test_match_spec_ifname (const char *spec_str, const char **matches) +test_match_spec_ifname (const char *spec_str, const char **matches, const char **neg_matches) { const char *m; char **spec_str_split; @@ -819,14 +819,20 @@ test_match_spec_ifname (const char *spec_str, const char **matches) specs = g_slist_reverse (g_slist_copy (specs_reverse)); for (i = 0; matches && matches[i]; i++) { - g_assert (nm_match_spec_interface_name (specs, matches[i])); - g_assert (nm_match_spec_interface_name (specs_reverse, matches[i])); + g_assert (nm_match_spec_interface_name (specs, matches[i]) == NM_MATCH_SPEC_MATCH); + g_assert (nm_match_spec_interface_name (specs_reverse, matches[i]) == NM_MATCH_SPEC_MATCH); + } + for (i = 0; neg_matches && neg_matches[i]; i++) { + g_assert (nm_match_spec_interface_name (specs, neg_matches[i]) == NM_MATCH_SPEC_NEG_MATCH); + g_assert (nm_match_spec_interface_name (specs_reverse, neg_matches[i]) == NM_MATCH_SPEC_NEG_MATCH); } for (i = 0; (m = _test_match_spec_all[i]); i++) { if (_test_match_spec_contains (matches, m)) continue; - g_assert (!nm_match_spec_interface_name (specs, m)); - g_assert (!nm_match_spec_interface_name (specs_reverse, m)); + if (_test_match_spec_contains (neg_matches, m)) + continue; + g_assert (nm_match_spec_interface_name (specs, m) == NM_MATCH_SPEC_NO_MATCH); + g_assert (nm_match_spec_interface_name (specs_reverse, m) == NM_MATCH_SPEC_NO_MATCH); } g_slist_free (specs_reverse); @@ -839,20 +845,34 @@ test_nm_match_spec_interface_name (void) { #define S(...) ((const char *[]) { __VA_ARGS__, NULL } ) test_match_spec_ifname ("em1", - S ("em1")); + S ("em1"), + NULL); test_match_spec_ifname ("em1,em2", - S ("em1", "em2")); + S ("em1", "em2"), + NULL); test_match_spec_ifname ("em1,em2,interface-name:em2", - S ("em1", "em2")); + S ("em1", "em2"), + NULL); test_match_spec_ifname ("interface-name:em1", - S ("em1")); + S ("em1"), + NULL); test_match_spec_ifname ("interface-name:em*", - S ("em", "em*", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em1", "em11", "em2", "em3")); + S ("em", "em*", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em1", "em11", "em2", "em3"), + NULL); test_match_spec_ifname ("interface-name:em\\*", - S ("em\\", "em\\*", "em\\1", "em\\11", "em\\2")); + S ("em\\", "em\\*", "em\\1", "em\\11", "em\\2"), + NULL); test_match_spec_ifname ("interface-name:~em\\*", - S ("em\\", "em\\*", "em\\1", "em\\11", "em\\2")); + S ("em\\", "em\\*", "em\\1", "em\\11", "em\\2"), + NULL); test_match_spec_ifname ("interface-name:=em*", + S ("em*"), + NULL); + test_match_spec_ifname ("interface-name:em*,except:interface-name:em1*", + S ("em", "em*", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em2", "em3"), + S ("em1", "em11")); + test_match_spec_ifname ("interface-name:em*,except:interface-name:=em*", + S ("em", "em\\", "em\\*", "em\\1", "em\\11", "em\\2", "em1", "em11", "em2", "em3"), S ("em*")); #undef S }