linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Stotland, Inga" <inga.stotland@intel.com>
To: "michal.lowas-rzechonek@silvair.com" 
	<michal.lowas-rzechonek@silvair.com>,
	"linux-bluetooth@vger.kernel.org"
	<linux-bluetooth@vger.kernel.org>
Cc: "Gix, Brian" <brian.gix@intel.com>
Subject: Re: [PATCH BlueZ v4 2/5] mesh: Validate application by comparing composition data
Date: Fri, 26 Jul 2019 03:58:31 +0000	[thread overview]
Message-ID: <95d9c217acc327860dc72f53bcab03d6439acf76.camel@intel.com> (raw)
In-Reply-To: <20190725194933.7321-3-michal.lowas-rzechonek@silvair.com>

[-- Attachment #1: Type: text/plain, Size: 20173 bytes --]

Hi Michal,

On Thu, 2019-07-25 at 21:49 +0200, Michał Lowas-Rzechonek wrote:
> Instead of validating application by enumerating D-Bus objects,
> create a
> temporary node instance and check if composition data generated for
> the
> temporary matches the node loaded from storage.
> 
> This allows node validation logic (primary element, mandatory models
> etc)
> to be confined in node_generate_comp() function.
> 
> This also streamlines code implementing Attach(), Join() and
> CreateNetwork() calls.
> ---
>  mesh/mesh-defs.h |   2 +
>  mesh/node.c      | 434 +++++++++++++++++++++----------------------
> ----
>  2 files changed, 197 insertions(+), 239 deletions(-)
> 
> diff --git a/mesh/mesh-defs.h b/mesh/mesh-defs.h
> index 82be91d75..d14aa5af3 100644
> --- a/mesh/mesh-defs.h
> +++ b/mesh/mesh-defs.h
> @@ -79,6 +79,8 @@
>  #define MAX_MODEL_COUNT		0xff
>  #define MAX_ELE_COUNT		0xff
>  
> +#define MAX_MSG_LEN 380
> +
>  #define IS_UNASSIGNED(x)	((x) == UNASSIGNED_ADDRESS)
>  #define IS_UNICAST(x)		(((x) > UNASSIGNED_ADDRESS) &&
> \
>  					((x) < VIRTUAL_ADDRESS_LOW))
> diff --git a/mesh/node.c b/mesh/node.c
> index e51913edf..f824d6170 100644
> --- a/mesh/node.c
> +++ b/mesh/node.c
> @@ -112,16 +112,16 @@ struct mesh_node {
>  };
>  
>  struct managed_obj_request {
> -	union {
> -		const uint8_t *uuid;
> -		struct mesh_node *node;
> -	};
> +	struct mesh_node *node;
>  	union {
>  		node_ready_func_t ready_cb;
>  		node_join_ready_func_t join_ready_cb;
>  	};
>  	struct l_dbus_message *pending_msg;
>  	enum request_type type;
> +	union {
> +		struct mesh_node *attach;
> +	};
>  };
>  
>  static struct l_queue *nodes;
> @@ -160,14 +160,6 @@ static bool match_element_idx(const void *a,
> const void *b)
>  	return (element->idx == index);
>  }
>  
> -static bool match_model_id(const void *a, const void *b)
> -{
> -	const struct mesh_model *mod = a;
> -	uint32_t mod_id = L_PTR_TO_UINT(b);
> -
> -	return mod_id == mesh_model_get_model_id(mod);
> -}
> -
>  static bool match_element_path(const void *a, const void *b)
>  {
>  	const struct node_element *element = a;
> @@ -212,11 +204,6 @@ static struct mesh_node *node_new(const uint8_t
> uuid[16])
>  	node->net = mesh_net_new(node);
>  	memcpy(node->uuid, uuid, sizeof(node->uuid));
>  
> -	if (!nodes)
> -		nodes = l_queue_new();
> -
> -	l_queue_push_tail(nodes, node);
> -
>  	return node;
>  }
>  
> @@ -412,6 +399,11 @@ static bool init_from_storage(struct
> mesh_config_node *db_node,
>  
>  	struct mesh_node *node = node_new(uuid);
>  
> +	if (!nodes)
> +		nodes = l_queue_new();
> +
> +	l_queue_push_tail(nodes, node);
> +
>  	node->comp = l_new(struct node_composition, 1);
>  	node->comp->cid = db_node->cid;
>  	node->comp->pid = db_node->pid;
> @@ -436,7 +428,7 @@ static bool init_from_storage(struct
> mesh_config_node *db_node,
>  	memcpy(node->token, db_node->token, 8);
>  
>  	num_ele = l_queue_length(db_node->elements);
> -	if (num_ele > 0xff)
> +	if (num_ele > MAX_ELE_COUNT)
>  		goto fail;
>  
>  	node->num_ele = num_ele;
> @@ -1140,58 +1132,6 @@ static void app_disc_cb(struct l_dbus *bus,
> void *user_data)
>  	free_node_dbus_resources(node);
>  }
>  
> -static bool validate_model_property(struct node_element *ele,
> -					struct l_dbus_message_iter
> *property,
> -					uint8_t *num_models, bool
> vendor)
> -{
> -	struct l_dbus_message_iter ids;
> -	uint16_t mod_id, vendor_id;
> -	uint8_t count;
> -	const char *signature = !vendor ? "aq" : "a(qq)";
> -
> -	if (!l_dbus_message_iter_get_variant(property, signature,
> &ids)) {
> -		/* Allow empty elements */
> -		if (l_queue_length(ele->models) == 0) {
> -			*num_models = 0;
> -			return true;
> -		} else
> -			return false;
> -	}
> -
> -	count = 0;
> -	if (!vendor) {
> -		/* Bluetooth SIG defined models */
> -		while (l_dbus_message_iter_next_entry(&ids, &mod_id)) {
> -			struct mesh_model *mod;
> -
> -			/* Skip internally implemented models */
> -			if ((VENDOR_ID_MASK | mod_id) ==
> CONFIG_SRV_MODEL)
> -				continue;
> -
> -			mod = l_queue_find(ele->models, match_model_id,
> -					L_UINT_TO_PTR(VENDOR_ID_MASK |
> mod_id));
> -			if (!mod)
> -				return false;
> -			count++;
> -		}
> -	} else {
> -		/* Vendor defined models */
> -		while (l_dbus_message_iter_next_entry(&ids, &vendor_id,
> -								&mod_id
> )) {
> -			struct mesh_model *mod;
> -
> -			mod = l_queue_find(ele->models, match_model_id,
> -				L_UINT_TO_PTR((vendor_id << 16) |
> mod_id));
> -			if (!mod)
> -				return false;
> -			count++;
> -		}
> -	}
> -
> -	*num_models = count;
> -	return true;
> -}
> -
>  static void get_models_from_properties(struct node_element *ele,
>  					struct l_dbus_message_iter
> *property,
>  								bool
> vendor)
> @@ -1231,94 +1171,60 @@ static void get_models_from_properties(struct
> node_element *ele,
>  }
>  
>  static bool get_element_properties(struct mesh_node *node, const
> char *path,
> -					struct l_dbus_message_iter
> *properties,
> -								bool
> is_new)
> +					struct l_dbus_message_iter
> *properties)
>  {
> -	struct node_element *ele;
> +	struct node_element *ele = l_new(struct node_element, 1);
>  	const char *key;
>  	struct l_dbus_message_iter var;
> -	bool have_index = false;
> -	uint8_t idx, mod_cnt, vendor_cnt;
> +	bool idx = false;
> +	bool mods = false;
> +	bool vendor_mods = false;
>  
>  	l_debug("path %s", path);
>  
> +	ele->location = DEFAULT_LOCATION;
> +
>  	while (l_dbus_message_iter_next_entry(properties, &key, &var))
> {
> -		if (!strcmp(key, "Index")) {
> -			if (!l_dbus_message_iter_get_variant(&var, "y",
> &idx))
> -				return false;
> -			have_index = true;
> -			break;
> +		if (!idx && !strcmp(key, "Index")) {
> +			if (!l_dbus_message_iter_get_variant(&var, "y",
> +								&ele-
> >idx))
> +				goto fail;
> +			idx = true;
> +			continue;
>  		}
> -	}
> -
> -	if (!have_index) {
> -		l_debug("Mandatory property \"Index\" not found");
> -		return false;
> -	}
>  
> -	if (!is_new) {
> -		/* Validate composition: check the element index */
> -		ele = l_queue_find(node->elements, match_element_idx,
> -							L_UINT_TO_PTR(i
> dx));
> -		if (!ele) {
> -			l_debug("Element with index %u not found",
> idx);
> -			return false;
> +		if (!mods && !strcmp(key, "Models")) {
> +			get_models_from_properties(ele, &var, false);
> +			mods = true;
> +			continue;
>  		}
> -	} else {
> -		ele = l_new(struct node_element, 1);
> -		ele->location = DEFAULT_LOCATION;
> -		ele->idx = idx;
> -	}
>  
> -	mod_cnt = 0;
> -	vendor_cnt = 0;
> +		if (!vendor_mods && !strcmp(key, "VendorModels")) {
> +			get_models_from_properties(ele, &var, true);
> +			vendor_mods = true;
> +			continue;
> +		}
>  
> -	while (l_dbus_message_iter_next_entry(properties, &key, &var))
> {
>  		if (!strcmp(key, "Location")) {
> -			uint16_t loc;
> -
> -			l_dbus_message_iter_get_variant(&var, "q",
> &loc);
> -
> -			/* Validate composition: location match */
> -			if (!is_new && (ele->location != loc))
> -				return false;
> -
> -			ele->location = loc;
> -
> -		} else if (!strcmp(key, "Models")) {
> -
> -			if (is_new)
> -				get_models_from_properties(ele, &var,
> false);
> -			else if (!validate_model_property(ele, &var,
> &mod_cnt,
> -									
> false))
> -				return false;
> -
> -		} else if (!strcmp(key, "VendorModels")) {
> -
> -			if (is_new)
> -				get_models_from_properties(ele, &var,
> true);
> -			else if (!validate_model_property(ele, &var,
> -							&vendor_cnt,
> true))
> -				return false;
> -
> +			if (!l_dbus_message_iter_get_variant(&var, "q",
> +							&ele-
> >location))
> +				goto fail;
> +			continue;
>  		}
>  	}
>  
> -	if (is_new) {
> -		l_queue_push_tail(node->elements, ele);
> -	} else {
> -		/* Account for internal Configuration Server model */
> -		if (idx == 0)
> -			mod_cnt += 1;
> +	if (!idx || !mods || !vendor_mods)
> +		goto fail;
>  
> -		/* Validate composition: number of models must match */
> -		if (l_queue_length(ele->models) != (mod_cnt +
> vendor_cnt))
> -			return false;
> +	l_queue_push_tail(node->elements, ele);
>  
> -		ele->path = l_strdup(path);
> -	}
> +	ele->path = l_strdup(path);
>  
>  	return true;
> +fail:
> +	l_free(ele);
> +
> +	return false;
>  }
>  
>  static void convert_node_to_storage(struct mesh_node *node,
> @@ -1415,65 +1321,61 @@ static void set_defaults(struct mesh_node
> *node)
>  }
>  
>  static bool get_app_properties(struct mesh_node *node, const char
> *path,
> -					struct l_dbus_message_iter
> *properties,
> -								bool
> is_new)
> +					struct l_dbus_message_iter
> *properties)
>  {
>  	const char *key;
>  	struct l_dbus_message_iter variant;
> -	uint16_t value;
> +	bool cid = false;
> +	bool pid = false;
> +	bool vid = false;
>  
>  	l_debug("path %s", path);
>  
> -	if (is_new) {
> -		node->comp = l_new(struct node_composition, 1);
> -		node->comp->crpl = DEFAULT_CRPL;
> -	}
> +	node->comp = l_new(struct node_composition, 1);
> +	node->comp->crpl = DEFAULT_CRPL;
>  
>  	while (l_dbus_message_iter_next_entry(properties, &key,
> &variant)) {
> -
> -		if (!strcmp(key, "CompanyID")) {
> +		if (!cid && !strcmp(key, "CompanyID")) {
>  			if (!l_dbus_message_iter_get_variant(&variant,
> "q",
> -									
> &value))
> -				return false;
> -
> -			if (!is_new && node->comp->cid != value)
> -				return false;
> -
> -			node->comp->cid = value;
> +							&node->comp-
> >cid))
> +				goto fail;
> +			cid = true;
> +			continue;
> +		}
>  
> -		} else if (!strcmp(key, "ProductID")) {
> +		if (!pid && !strcmp(key, "ProductID")) {
>  			if (!l_dbus_message_iter_get_variant(&variant,
> "q",
> -									
> &value))
> -				return false;
> -
> -			if (!is_new && node->comp->pid != value)
> -				return false;
> -
> -			node->comp->pid = value;
> +							&node->comp-
> >pid))
> +				goto fail;
> +			pid = true;
> +			continue;
> +		}
>  
> -		} else if (!strcmp(key, "VersionID")) {
> +		if (!vid && !strcmp(key, "VersionID")) {
>  			if (!l_dbus_message_iter_get_variant(&variant,
> "q",
> -									
> &value))
> -				return false;
> -
> -			if (!is_new && node->comp->vid != value)
> +							&node->comp-
> >vid))
>  				return false;
> +			vid = true;
> +			continue;
> +		}
>  
> -			node->comp->vid = value;
> -
> -		} else if (!strcmp(key, "CRPL")) {
> +		if (!strcmp(key, "CRPL")) {
>  			if (!l_dbus_message_iter_get_variant(&variant,
> "q",
> -									
> &value))
> -				return false;
> -
> -			if (!is_new && node->comp->crpl != value)
> -				return false;
> -
> -			node->comp->crpl = value;
> +							&node->comp-
> >crpl))
> +				goto fail;
> +			continue;
>  		}
>  	}
>  
> +	if (!cid || !pid || !vid)
> +		goto fail;
> +
>  	return true;
> +fail:
> +	l_free(node->comp);
> +	node->comp = NULL;
> +
> +	return false;
>  }
>  
>  static bool add_local_node(struct mesh_node *node, uint16_t unicast,
> bool kr,
> @@ -1552,18 +1454,83 @@ static bool init_storage_dir(struct mesh_node
> *node)
>  	return true;
>  }
>  
> +static bool check_req_node(struct managed_obj_request *req)
> +{
> +	uint8_t node_comp[MAX_MSG_LEN - 2];
> +	uint8_t attach_comp[MAX_MSG_LEN - 2];
> +
> +	uint16_t node_len = node_generate_comp(req->node, node_comp,
> +							sizeof(node_com
> p));
> +
> +	if (!node_len)
> +		return false;
> +
> +	if (req->type == REQUEST_TYPE_ATTACH) {
> +		uint16_t attach_len = node_generate_comp(req->attach,
> +					attach_comp,
> sizeof(attach_comp));
> +
> +		if (node_len != attach_len ||
> +				memcmp(node_comp, attach_comp,
> node_len)) {
> +			l_debug("Failed to verify app's composition
> data");
> +			return false;
> +		}
> +	}
> +
> +	return true;
> +}
> +
> +static struct mesh_node *attach_req_node(struct mesh_node *attach,
> +							struct
> mesh_node *node)
> +{
> +	const struct l_queue_entry *attach_entry;
> +	const struct l_queue_entry *node_entry;
> +
> +	attach_entry = l_queue_get_entries(attach->elements);
> +	node_entry = l_queue_get_entries(node->elements);
> +
> +	/*
> +	 * Update existing node with paths collected in temporary node,
> +	 * then remove the temporary.
> +	 * */

*/ on a separate line

> +	while (attach_entry && node_entry)
> +	{
> +		struct node_element *attach_ele = node_entry->data;

attach_ele = attach_entry->data

> +		struct node_element *node_ele = node_entry->data;
> +
> +		l_free(attach_ele->path);

I don't think we need l_free() here. The element path of the daemon-
owned node should be depopulated at this point. If this is not the
case, we have a logic hole somewhere.

> +		attach_ele->path = node_ele->path;
> +		node_ele->path = NULL;
> +
> +		attach_entry = attach_entry->next;
> +		node_entry = node_entry->next;
> +	}
> +
> +	mesh_agent_remove(attach->agent);
+	attach->agent = node->agent;
> +	node->agent = NULL;
> +
> +	attach->app_path = node->app_path;
> +	node->app_path = NULL;
> +
> +	attach->owner = node->owner;
> +	node->owner = NULL;
> +
> +	node_remove(node);
> +
> +	return attach;
> +}
> +
>  static void get_managed_objects_cb(struct l_dbus_message *msg, void
> *user_data)
>  {
>  	struct l_dbus_message_iter objects, interfaces;
>  	struct managed_obj_request *req = user_data;
>  	const char *path;
> -	struct mesh_node *node = NULL;
> +	struct mesh_node *node = req->node;
>  	void *agent = NULL;
>  	bool have_app = false;
> -	bool is_new;
> -	uint8_t num_ele;
> -
> -	is_new = (req->type != REQUEST_TYPE_ATTACH);
> +	unsigned int num_ele;
>  
>  	if (l_dbus_message_is_error(msg)) {
>  		l_error("Failed to get app's dbus objects");
> @@ -1575,14 +1542,8 @@ static void get_managed_objects_cb(struct
> l_dbus_message *msg, void *user_data)
>  		goto fail;
>  	}
>  
> -	if (is_new) {
> -		node = l_new(struct mesh_node, 1);
> +	if (!node->elements)
>  		node->elements = l_queue_new();
> -	} else {
> -		node = req->node;
> -	}
> -
> -	num_ele = 0;
>  
>  	while (l_dbus_message_iter_next_entry(&objects, &path,
> &interfaces)) {
>  		struct l_dbus_message_iter properties;
> @@ -1593,21 +1554,14 @@ static void get_managed_objects_cb(struct
> l_dbus_message *msg, void *user_data)
>  			bool res;
>  
>  			if (!strcmp(MESH_ELEMENT_INTERFACE, interface))
> {
> -
> -				if (num_ele == MAX_ELE_COUNT)
> -					goto fail;
> -
>  				res = get_element_properties(node,
> path,
> -							&properties,
> is_new);
> +								&proper
> ties);
>  				if (!res)
>  					goto fail;
> -
> -				num_ele++;
> -
>  			} else if (!strcmp(MESH_APPLICATION_INTERFACE,
>  								interfa
> ce)) {
>  				res = get_app_properties(node, path,
> -							&properties,
> is_new);
> +								&proper
> ties);
>  				if (!res)
>  					goto fail;
>  
> @@ -1637,7 +1591,7 @@ static void get_managed_objects_cb(struct
> l_dbus_message *msg, void *user_data)
>  		goto fail;
>  	}
>  
> -	if (num_ele == 0) {
> +	if (l_queue_isempty(node->elements)) {
>  		l_error("Interface %s not found",
> MESH_ELEMENT_INTERFACE);
>  		goto fail;
>  	}
> @@ -1649,17 +1603,23 @@ static void get_managed_objects_cb(struct
> l_dbus_message *msg, void *user_data)
>  		goto fail;
>  	}
>  
> +	set_defaults(node);
> +	num_ele = l_queue_length(node->elements);
> +
> +	if (num_ele > MAX_ELE_COUNT)
> +		goto fail;
> +
> +	node->num_ele = num_ele;
> +
> +	if (!check_req_node(req))
> +		goto fail;
> +
>  	if (req->type == REQUEST_TYPE_ATTACH) {
> -		if (num_ele != node->num_ele)
> -			goto fail;
> +		struct l_dbus *bus = dbus_get_bus();
>  
> -		if (register_node_object(node)) {
> -			struct l_dbus *bus = dbus_get_bus();
> +		node = attach_req_node(req->attach, node);
>  
> -			node->disc_watch =
> l_dbus_add_disconnect_watch(bus,
> -					node->owner, app_disc_cb, node,
> NULL);
> -			req->ready_cb(req->pending_msg,
> MESH_ERROR_NONE, node);
> -		} else
> +		if (!register_node_object(node))
>  			goto fail;
>  
>  		/*
> @@ -1670,30 +1630,24 @@ static void get_managed_objects_cb(struct
> l_dbus_message *msg, void *user_data)
>  		 */
>  		init_storage_dir(node);
>  
> +		node->disc_watch = l_dbus_add_disconnect_watch(bus,
> +				node->owner, app_disc_cb, node, NULL);
> +
>  	} else if (req->type == REQUEST_TYPE_JOIN) {
> -		if (!agent) {
> +		if (!node->agent) {
>  			l_error("Interface %s not found",
>  						MESH_PROVISION_AGENT_IN
> TERFACE);
>  			goto fail;
>  		}
>  
> -		node->num_ele = num_ele;
> -		set_defaults(node);
> -		memcpy(node->uuid, req->uuid, 16);
> -
>  		if (!create_node_config(node, node->uuid))
>  			goto fail;
>  
> -		req->join_ready_cb(node, agent);
>  	} else {
>  		/* Callback for create node request */
>  		struct keyring_net_key net_key;
>  		uint8_t dev_key[16];
>  
> -		node->num_ele = num_ele;
> -		set_defaults(node);
> -		memcpy(node->uuid, req->uuid, 16);
> -
>  		if (!create_node_config(node, node->uuid))
>  			goto fail;
>  
> @@ -1713,35 +1667,32 @@ static void get_managed_objects_cb(struct
> l_dbus_message *msg, void *user_data)
>  		init_storage_dir(node);
>  
>  		if (!keyring_put_remote_dev_key(node,
> DEFAULT_NEW_UNICAST,
> -							num_ele,
> dev_key))
> +						node->num_ele,
> dev_key))
>  			goto fail;
>  
>  		if (!keyring_put_net_key(node, PRIMARY_NET_IDX,
> &net_key))
>  			goto fail;
>  
> -		req->ready_cb(req->pending_msg, MESH_ERROR_NONE, node);
>  	}
>  
> +	if (req->type == REQUEST_TYPE_JOIN)
> +		req->join_ready_cb(node, node->agent);
> +	else
> +		req->ready_cb(req->pending_msg, MESH_ERROR_NONE, node);
> +
>  	return;
>  fail:
>  	if (agent)
>  		mesh_agent_remove(agent);
>  
> -	if (!is_new) {
> -		free_node_dbus_resources(node);
> +	/* Handle failed requests */
> +	if (node)
> +		node_remove(node);
>  
> -		req->ready_cb(req->pending_msg, MESH_ERROR_FAILED,
> node);
> -	} else {
> -		/* Handle failed Join and Create requests */
> -		if (node)
> -			node_remove(node);
> -
> -		if (req->type == REQUEST_TYPE_JOIN)
> -			req->join_ready_cb(NULL, NULL);
> -		else
> -			req->ready_cb(req->pending_msg,
> MESH_ERROR_FAILED,
> -									
> NULL);
> -	}
> +	if (req->type == REQUEST_TYPE_JOIN)
> +		req->join_ready_cb(NULL, NULL);
> +	else
> +		req->ready_cb(req->pending_msg, MESH_ERROR_FAILED,
> NULL);
>  }
>  
>  /* Establish relationship between application and mesh node */
> @@ -1761,13 +1712,18 @@ int node_attach(const char *app_path, const
> char *sender, uint64_t token,
>  		return MESH_ERROR_ALREADY_EXISTS;
>  	}
>  
> -	node->app_path = l_strdup(app_path);
> -	node->owner = l_strdup(sender);
> -
>  	req = l_new(struct managed_obj_request, 1);
> -	req->node = node;
> +
> +	/*
> +	 * Create a temporary node to collect composition data from
> attaching
> +	 * application. Existing node is passed in req->attach.
> +	 */
> +	req->node = node_new(node->uuid);
> +	req->node->app_path = l_strdup(app_path);
> +	req->node->owner = l_strdup(sender);
>  	req->ready_cb = cb;
>  	req->pending_msg = user_data;
> +	req->attach = node;
>  	req->type = REQUEST_TYPE_ATTACH;
>  
>  	l_dbus_method_call(dbus_get_bus(), sender, app_path,
> @@ -1789,7 +1745,7 @@ void node_join(const char *app_path, const char
> *sender, const uint8_t *uuid,
>  	l_debug("");
>  
>  	req = l_new(struct managed_obj_request, 1);
> -	req->uuid = uuid;
> +	req->node = node_new(uuid);
>  	req->join_ready_cb = cb;
>  	req->type = REQUEST_TYPE_JOIN;
>  
> @@ -1808,7 +1764,7 @@ void node_create(const char *app_path, const
> char *sender, const uint8_t *uuid,
>  	l_debug("");
>  
>  	req = l_new(struct managed_obj_request, 1);
> -	req->uuid = uuid;
> +	req->node = node_new(uuid);
>  	req->ready_cb = cb;
>  	req->pending_msg = user_data;
>  	req->type = REQUEST_TYPE_CREATE;


Regards,
Inga

[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3265 bytes --]

  reply	other threads:[~2019-07-26  3:58 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-25 19:49 [PATCH BlueZ v4 0/5] Use composition data to validate app against the node Michał Lowas-Rzechonek
2019-07-25 19:49 ` [PATCH BlueZ v4 1/5] mesh: Convert void pointers to anonymous unions in managed_obj_request Michał Lowas-Rzechonek
2019-07-25 19:49 ` [PATCH BlueZ v4 2/5] mesh: Validate application by comparing composition data Michał Lowas-Rzechonek
2019-07-26  3:58   ` Stotland, Inga [this message]
2019-07-25 19:49 ` [PATCH BlueZ v4 3/5] mesh: Keep element and model lists sorted and unique Michał Lowas-Rzechonek
2019-07-25 19:49 ` [PATCH BlueZ v4 4/5] mesh: Check that element indexes are consecutive Michał Lowas-Rzechonek
2019-07-25 19:49 ` [PATCH BlueZ v4 5/5] mesh: Check that config server is present in primary element Michał Lowas-Rzechonek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=95d9c217acc327860dc72f53bcab03d6439acf76.camel@intel.com \
    --to=inga.stotland@intel.com \
    --cc=brian.gix@intel.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=michal.lowas-rzechonek@silvair.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).