diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 79d9efd296..756ff56697 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -3488,6 +3488,35 @@ _get_fcn_match_kernel_command_line (ARGS_GET_FCN) RETURN_STR_TO_FREE (g_string_free (str, FALSE)); } +static gconstpointer +_get_fcn_match_driver (ARGS_GET_FCN) +{ + NMSettingMatch *s_match = NM_SETTING_MATCH (setting); + GString *str = NULL; + guint i, num; + + RETURN_UNSUPPORTED_GET_TYPE (); + + num = nm_setting_match_get_num_drivers (s_match); + for (i = 0; i < num; i++) { + const char *name; + + name = nm_setting_match_get_driver (s_match, i); + if (!name || !name[0]) + continue; + if (!str) + str = g_string_new (""); + else + g_string_append_c (str, ESCAPED_TOKENS_WITH_SPACES_DELIMTER); + nm_utils_escaped_tokens_escape_gstr (name, ESCAPED_TOKENS_WITH_SPACES_DELIMTERS, str); + } + + NM_SET_OUT (out_is_default, num == 0); + if (!str) + return NULL; + RETURN_STR_TO_FREE (g_string_free (str, FALSE)); +} + static gconstpointer _get_fcn_olpc_mesh_ssid (ARGS_GET_FCN) { @@ -6254,6 +6283,22 @@ static const NMMetaPropertyInfo *const property_infos_MATCH[] = { ), ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_MATCH_DRIVER, + .property_type = DEFINE_PROPERTY_TYPE ( + .get_fcn = _get_fcn_match_driver, + .set_fcn = _set_fcn_multilist, + .set_supports_remove = TRUE, + ), + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingMatch, nm_setting_match_get_num_drivers), + .add2_fcn = MULTILIST_ADD2_FCN (NMSettingMatch, nm_setting_match_add_driver), + .remove_by_idx_fcn_u = MULTILIST_REMOVE_BY_IDX_FCN_U (NMSettingMatch, nm_setting_match_remove_driver), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingMatch, nm_setting_match_remove_driver_by_value), + .strsplit_with_spaces = TRUE, + ), + ), + ), NULL }; diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index df9dfcef3f..b51d0a1ecf 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -280,6 +280,7 @@ #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_DRIVER N_("A list of driver names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate driver name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") #define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate interface name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") #define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or if prefixed with the exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated \"=\"). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE N_("The data path type. One of \"system\", \"netdev\" or empty.") diff --git a/libnm-core/nm-setting-match.c b/libnm-core/nm-setting-match.c index 8309af6b97..6c9802e3b6 100644 --- a/libnm-core/nm-setting-match.c +++ b/libnm-core/nm-setting-match.c @@ -21,6 +21,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSettingMatch, PROP_INTERFACE_NAME, PROP_KERNEL_COMMAND_LINE, + PROP_DRIVER, ); /** @@ -34,6 +35,7 @@ struct _NMSettingMatch { NMSetting parent; GPtrArray *interface_name; GPtrArray *kernel_command_line; + GPtrArray *driver; }; struct _NMSettingMatchClass { @@ -341,6 +343,154 @@ nm_setting_match_get_kernel_command_lines (NMSettingMatch *setting, guint *lengt /*****************************************************************************/ +/** + * nm_setting_match_get_num_drivers: + * @setting: the #NMSettingMatch + * + * Returns: the number of configured drivers + * + * Since: 1.26 + **/ +guint +nm_setting_match_get_num_drivers (NMSettingMatch *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), 0); + + return setting->driver->len; +} + +/** + * nm_setting_match_get_driver: + * @setting: the #NMSettingMatch + * @idx: index number of the DNS search domain to return + * + * Returns: the driver at index @idx + * + * Since: 1.26 + **/ +const char * +nm_setting_match_get_driver (NMSettingMatch *setting, guint idx) +{ + g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), NULL); + + g_return_val_if_fail (idx < setting->driver->len, NULL); + + return setting->driver->pdata[idx]; +} + +/** + * nm_setting_match_add_driver: + * @setting: the #NMSettingMatch + * @driver: the driver to add + * + * Adds a new driver to the setting. + * + * Since: 1.26 + **/ +void +nm_setting_match_add_driver (NMSettingMatch *setting, + const char *driver) +{ + g_return_if_fail (NM_IS_SETTING_MATCH (setting)); + g_return_if_fail (driver != NULL); + g_return_if_fail (driver[0] != '\0'); + + g_ptr_array_add (setting->driver, g_strdup (driver)); + _notify (setting, PROP_DRIVER); +} + +/** + * nm_setting_match_remove_driver: + * @setting: the #NMSettingMatch + * @idx: index number of the driver + * + * Removes the driver at index @idx. + * + * Since: 1.26 + **/ +void +nm_setting_match_remove_driver (NMSettingMatch *setting, guint idx) +{ + g_return_if_fail (NM_IS_SETTING_MATCH (setting)); + + g_return_if_fail (idx < setting->driver->len); + + g_ptr_array_remove_index (setting->driver, idx); + _notify (setting, PROP_DRIVER); +} + +/** + * nm_setting_match_remove_driver_by_value: + * @setting: the #NMSettingMatch + * @driver: the driver to remove + * + * Removes @driver. + * + * Returns: %TRUE if the driver was found and removed; %FALSE if it was not. + * + * Since: 1.26 + **/ +gboolean +nm_setting_match_remove_driver_by_value (NMSettingMatch *setting, + const char *driver) +{ + guint i; + + g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), FALSE); + g_return_val_if_fail (driver != NULL, FALSE); + g_return_val_if_fail (driver[0] != '\0', FALSE); + + for (i = 0; i < setting->driver->len; i++) { + if (nm_streq (driver, setting->driver->pdata[i])) { + g_ptr_array_remove_index (setting->driver, i); + _notify (setting, PROP_DRIVER); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_match_clear_drivers: + * @setting: the #NMSettingMatch + * + * Removes all configured drivers. + * + * Since: 1.26 + **/ +void +nm_setting_match_clear_drivers (NMSettingMatch *setting) +{ + g_return_if_fail (NM_IS_SETTING_MATCH (setting)); + + if (setting->driver->len != 0) { + g_ptr_array_set_size (setting->driver, 0); + _notify (setting, PROP_DRIVER); + } +} + +/** + * nm_setting_match_get_drivers: + * @setting: the #NMSettingMatch + * + * Returns all the drivers. + * + * Returns: (transfer none): the configured drivers. + * + * Since: 1.26 + **/ +const char *const * +nm_setting_match_get_drivers (NMSettingMatch *setting, guint *length) +{ + g_return_val_if_fail (NM_IS_SETTING_MATCH (setting), NULL); + g_return_val_if_fail (length, NULL); + + NM_SET_OUT (length, setting->driver->len); + return (const char *const *) setting->driver->pdata; +} + +/*****************************************************************************/ + static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) @@ -354,6 +504,9 @@ get_property (GObject *object, guint prop_id, case PROP_KERNEL_COMMAND_LINE: g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (self->kernel_command_line)); break; + case PROP_DRIVER: + g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (self->driver)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -375,6 +528,10 @@ set_property (GObject *object, guint prop_id, g_ptr_array_unref (self->kernel_command_line); self->kernel_command_line = _nm_utils_strv_to_ptrarray (g_value_get_boxed (value)); break; + case PROP_DRIVER: + g_ptr_array_unref (self->driver); + self->driver = _nm_utils_strv_to_ptrarray (g_value_get_boxed (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -388,6 +545,7 @@ nm_setting_match_init (NMSettingMatch *setting) { setting->interface_name = g_ptr_array_new_with_free_func (g_free); setting->kernel_command_line = g_ptr_array_new_with_free_func (g_free); + setting->driver = g_ptr_array_new_with_free_func (g_free); } /** @@ -437,6 +595,19 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } + for (k = 0; k < self->driver->len; k++) { + char *kparam = (char*) g_ptr_array_index (self->driver, k); + if (nm_streq0 (kparam, "")) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("is empty")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_MATCH_SETTING_NAME, + NM_SETTING_MATCH_DRIVER); + return FALSE; + } + } + return TRUE; } @@ -447,6 +618,7 @@ finalize (GObject *object) g_ptr_array_unref (self->interface_name); g_ptr_array_unref (self->kernel_command_line); + g_ptr_array_unref (self->driver); G_OBJECT_CLASS (nm_setting_match_parent_class)->finalize (object); } @@ -504,6 +676,25 @@ nm_setting_match_class_init (NMSettingMatchClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * NMSettingMatch:driver + * + * A list of driver names to match. Each element is a shell wildcard pattern. + * When an element is prefixed with exclamation mark (!) the condition is + * inverted. A candidate driver name is considered matching when both these + * conditions are satisfied: (a) any of the elements not prefixed with '!' + * matches or there aren't such elements; (b) none of the elements prefixed + * with '!' match. + * + * Since: 1.26 + **/ + obj_properties[PROP_DRIVER] = + g_param_spec_boxed (NM_SETTING_MATCH_DRIVER, "", "", + G_TYPE_STRV, + NM_SETTING_PARAM_FUZZY_IGNORE | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); _nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_MATCH); diff --git a/libnm-core/nm-setting-match.h b/libnm-core/nm-setting-match.h index 8301d8863c..fa656037e0 100644 --- a/libnm-core/nm-setting-match.h +++ b/libnm-core/nm-setting-match.h @@ -25,6 +25,7 @@ G_BEGIN_DECLS #define NM_SETTING_MATCH_INTERFACE_NAME "interface-name" #define NM_SETTING_MATCH_KERNEL_COMMAND_LINE "kernel-command-line" +#define NM_SETTING_MATCH_DRIVER "driver" typedef struct _NMSettingMatchClass NMSettingMatchClass; @@ -69,6 +70,24 @@ void nm_setting_match_clear_kernel_command_lines (NMSettingMatch *setting); NM_AVAILABLE_IN_1_26 const char *const *nm_setting_match_get_kernel_command_lines (NMSettingMatch *setting, guint *length); + +NM_AVAILABLE_IN_1_26 +guint nm_setting_match_get_num_drivers (NMSettingMatch *setting); +NM_AVAILABLE_IN_1_26 +const char *nm_setting_match_get_driver (NMSettingMatch *setting, guint idx); +NM_AVAILABLE_IN_1_26 +void nm_setting_match_remove_driver (NMSettingMatch *setting, guint idx); +NM_AVAILABLE_IN_1_26 +gboolean nm_setting_match_remove_driver_by_value (NMSettingMatch *setting, + const char *driver); +NM_AVAILABLE_IN_1_26 +void nm_setting_match_add_driver (NMSettingMatch *setting, + const char *driver); +NM_AVAILABLE_IN_1_26 +void nm_setting_match_clear_drivers (NMSettingMatch *setting); +NM_AVAILABLE_IN_1_26 +const char *const *nm_setting_match_get_drivers (NMSettingMatch *setting, guint *length); + G_END_DECLS #endif /* NM_SETTING_MATCH_H */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 9324ea0ade..8add06a070 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1715,4 +1715,11 @@ global: nm_setting_match_get_num_kernel_command_lines; nm_setting_match_remove_kernel_command_line; nm_setting_match_remove_kernel_command_line_by_value; + nm_setting_match_add_driver; + nm_setting_match_clear_drivers; + nm_setting_match_get_driver; + nm_setting_match_get_drivers; + nm_setting_match_get_num_drivers; + nm_setting_match_remove_driver; + nm_setting_match_remove_driver_by_value; } libnm_1_24_0; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 272bf25336..e4661a7dc4 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -6103,6 +6103,19 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError ** } } } + + { /* driver */ + const char *device_driver = nm_device_get_driver (self); + + if (device_driver) { + patterns = nm_setting_match_get_drivers (s_match, &num_patterns); + if (!nm_wildcard_match_check (device_driver, patterns, num_patterns)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not satisfy match.driver property"); + return FALSE; + } + } + } } return TRUE;