All of lore.kernel.org
 help / color / mirror / Atom feed
From: Brian Gix <brian.gix@intel.com>
To: linux-bluetooth@vger.kernel.org
Cc: johan.hedberg@gmail.com, inga.stotland@intel.com,
	marcel@holtmann.org, brian.gix@intel.com
Subject: [PATCH BlueZ v5 10/30] mesh: Initiator side provisioning implementation
Date: Tue, 18 Dec 2018 20:19:56 -0800	[thread overview]
Message-ID: <20181219042016.25538-11-brian.gix@intel.com> (raw)
In-Reply-To: <20181219042016.25538-1-brian.gix@intel.com>

---
 mesh/prov-initiator.c | 641 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 641 insertions(+)
 create mode 100644 mesh/prov-initiator.c

diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c
new file mode 100644
index 000000000..669cf340d
--- /dev/null
+++ b/mesh/prov-initiator.c
@@ -0,0 +1,641 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2018  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <time.h>
+#include <ell/ell.h>
+
+#include "mesh/mesh-defs.h"
+#include "src/shared/ecc.h"
+
+#include "mesh/util.h"
+#include "mesh/net_keys.h"
+#include "mesh/crypto.h"
+#include "mesh/net.h"
+#include "mesh/error.h"
+#include "mesh/prov.h"
+#include "mesh/provision.h"
+#include "mesh/pb-adv.h"
+#include "mesh/mesh.h"
+#include "mesh/agent.h"
+
+/* Quick size sanity check */
+static const uint16_t expected_pdu_size[] = {
+	2,	/* PROV_INVITE */
+	12,	/* PROV_CAPS */
+	6,	/* PROV_START */
+	65,	/* PROV_PUB_KEY */
+	1,	/* PROV_INP_CMPLT */
+	17,	/* PROV_CONFIRM */
+	17,	/* PROV_RANDOM */
+	34,	/* PROV_DATA */
+	1,	/* PROV_COMPLETE */
+	2,	/* PROV_FAILED */
+};
+
+#define BEACON_TYPE_UNPROVISIONED		0x00
+
+static const uint8_t pkt_filter = MESH_AD_TYPE_PROVISION;
+
+enum int_state {
+	INT_PROV_IDLE = 0,
+	INT_PROV_INVITE_SENT,
+	INT_PROV_INVITE_ACKED,
+	INT_PROV_START_SENT,
+	INT_PROV_START_ACKED,
+	INT_PROV_KEY_SENT,
+	INT_PROV_KEY_ACKED,
+	INT_PROV_CONF_SENT,
+	INT_PROV_CONF_ACKED,
+	INT_PROV_RAND_SENT,
+	INT_PROV_RAND_ACKED,
+	INT_PROV_DATA_SENT,
+	INT_PROV_DATA_ACKED,
+};
+
+#define MAT_REMOTE_PUBLIC	0x01
+#define MAT_LOCAL_PRIVATE	0x02
+#define MAT_RAND_AUTH		0x04
+#define MAT_SECRET	(MAT_REMOTE_PUBLIC | MAT_LOCAL_PRIVATE)
+
+struct mesh_prov_initiator {
+	mesh_prov_initiator_complete_func_t cmplt;
+	prov_trans_tx_t trans_tx;
+	void *agent;
+	void *caller_data;
+	void *trans_data;
+	struct l_timeout *timeout;
+	uint32_t to_secs;
+	enum int_state	state;
+	enum trans_type transport;
+	uint8_t material;
+	uint8_t expected;
+	int8_t previous;
+	struct conf_input conf_inputs;
+	uint8_t calc_key[16];
+	uint8_t salt[16];
+	uint8_t confirm[16];
+	uint8_t s_key[16];
+	uint8_t s_nonce[13];
+	uint8_t private_key[32];
+	uint8_t secret[32];
+	uint8_t rand_auth_workspace[48];
+};
+
+static struct mesh_prov_initiator *prov = NULL;
+
+static void initiator_free(void)
+{
+
+	if (prov)
+		l_timeout_remove(prov->timeout);
+
+	mesh_send_cancel(&pkt_filter, sizeof(pkt_filter));
+
+	l_free(prov);
+	prov = NULL;
+}
+
+static void int_prov_close(void *user_data, uint8_t reason)
+{
+	/* TODO: Handle Close */
+}
+
+static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
+				void *trans_data, uint8_t transport)
+{
+	struct mesh_prov_initiator *rx_prov = user_data;
+	uint8_t invite[] = { PROV_INVITE, 30 };
+
+	/* Only one provisioning session may be open at a time */
+	if (rx_prov != prov)
+		return;
+
+	/* Only one provisioning session may be open at a time */
+	if (prov->trans_tx && prov->trans_tx != trans_tx &&
+					prov->transport != transport)
+		return;
+
+	/* We only care here if transport does *not* match */
+	if (transport != prov->transport)
+		return;
+
+	/* Always use an ephemeral key when Initiator */
+	ecc_make_key(prov->conf_inputs.prv_pub_key, prov->private_key);
+	prov->material |= MAT_LOCAL_PRIVATE;
+
+	prov->trans_tx = trans_tx;
+	prov->trans_data = trans_data;
+	prov->state = INT_PROV_INVITE_SENT;
+	prov->expected = PROV_CAPS;
+
+	prov->conf_inputs.invite.attention = invite[1];
+	prov->trans_tx(prov->trans_data, invite, sizeof(invite));
+	return;
+}
+
+static void swap_u256_bytes(uint8_t *u256)
+{
+	int i;
+
+	/* End-to-End byte reflection of 32 octet buffer */
+	for (i = 0; i < 16; i++) {
+		u256[i] ^= u256[31 - i];
+		u256[31 - i] ^= u256[i];
+		u256[i] ^= u256[31 - i];
+	}
+}
+
+static void prov_calc_secret(const uint8_t *pub, const uint8_t *priv,
+							uint8_t *secret)
+{
+	uint8_t tmp[64];
+
+	/* Convert to ECC byte order */
+	memcpy(tmp, pub, 64);
+	swap_u256_bytes(tmp);
+	swap_u256_bytes(tmp + 32);
+
+	ecdh_shared_secret(tmp, priv, secret);
+
+	/* Convert to Mesh byte order */
+	swap_u256_bytes(secret);
+}
+
+static void int_credentials(struct mesh_prov_initiator *prov)
+{
+	prov_calc_secret(prov->conf_inputs.dev_pub_key,
+			prov->private_key, prov->secret);
+
+	mesh_crypto_s1(&prov->conf_inputs,
+			sizeof(prov->conf_inputs), prov->salt);
+
+	mesh_crypto_prov_conf_key(prov->secret, prov->salt,
+			prov->calc_key);
+
+	l_getrandom(prov->rand_auth_workspace, 16);
+
+	print_packet("PublicKeyProv", prov->conf_inputs.prv_pub_key, 64);
+	print_packet("PublicKeyDev", prov->conf_inputs.dev_pub_key, 64);
+	print_packet("PrivateKeyLocal", prov->private_key, 32);
+	print_packet("ConfirmationInputs", &prov->conf_inputs,
+						sizeof(prov->conf_inputs));
+	print_packet("ECDHSecret", prov->secret, 32);
+	print_packet("LocalRandom", prov->rand_auth_workspace, 16);
+	print_packet("ConfirmationSalt", prov->salt, 16);
+	print_packet("ConfirmationKey", prov->calc_key, 16);
+}
+
+static uint8_t u16_high_bit(uint16_t mask)
+{
+	uint8_t cnt = 0;
+
+	if (!mask)
+		return 0xff;
+
+	while (mask & 0xfffe) {
+		cnt++;
+		mask >>= 1;
+	}
+
+	return cnt;
+}
+
+static uint32_t digit_mod(uint8_t power)
+{
+	uint32_t ret = 1;
+
+	while (power--)
+		ret *= 10;
+
+	return ret;
+}
+
+static void calc_local_material(const uint8_t *random)
+{
+	/* Calculate SessionKey while the data is fresh */
+	mesh_crypto_prov_prov_salt(prov->salt,
+			prov->rand_auth_workspace, random,
+			prov->salt);
+	mesh_crypto_session_key(prov->secret, prov->salt,
+			prov->s_key);
+	mesh_crypto_nonce(prov->secret, prov->salt, prov->s_nonce);
+
+	print_packet("SessionKey", prov->s_key, sizeof(prov->s_key));
+	print_packet("Nonce", prov->s_nonce, sizeof(prov->s_nonce));
+	print_packet("RandomDevice", prov->rand_auth_workspace, 16);
+}
+
+static void number_cb(void *user_data, int err, uint32_t number)
+{
+	struct mesh_prov_initiator *rx_prov = user_data;
+	uint8_t out[2];
+
+	if (prov != rx_prov)
+		return;
+
+	if (err) {
+		out[0] = PROV_FAILED;
+		out[1] = PROV_ERR_UNEXPECTED_ERR;
+		prov->trans_tx(prov->trans_data, out, 2);
+		return;
+	}
+
+	/* Save two copies, to generate two confirmation values */
+	l_put_be32(number, prov->rand_auth_workspace + 28);
+	l_put_be32(number, prov->rand_auth_workspace + 44);
+	prov->material |= MAT_RAND_AUTH;
+}
+
+static void static_cb(void *user_data, int err, uint8_t *key, uint32_t len)
+{
+	struct mesh_prov_initiator *rx_prov = user_data;
+	uint8_t out[2];
+
+	if (prov != rx_prov)
+		return;
+
+	if (err || !key || len != 16) {
+		out[0] = PROV_FAILED;
+		out[1] = PROV_ERR_UNEXPECTED_ERR;
+		prov->trans_tx(prov->trans_data, out, 2);
+		return;
+	}
+
+	memcpy(prov->rand_auth_workspace + 16, key, 16);
+	memcpy(prov->rand_auth_workspace + 32, key, 16);
+	prov->material |= MAT_RAND_AUTH;
+}
+
+static void pub_key_cb(void *user_data, int err, uint8_t *key, uint32_t len)
+{
+	struct mesh_prov_initiator *rx_prov = user_data;
+	uint8_t out[2];
+
+	if (prov != rx_prov)
+		return;
+
+	if (err || !key || len != 64) {
+		out[0] = PROV_FAILED;
+		out[1] = PROV_ERR_UNEXPECTED_ERR;
+		prov->trans_tx(prov->trans_data, out, 2);
+		return;
+	}
+
+		memcpy(prov->conf_inputs.dev_pub_key, key, 64);
+		prov->material |= MAT_REMOTE_PUBLIC;
+
+		if ((prov->material & MAT_SECRET) == MAT_SECRET)
+			int_credentials(prov);
+}
+
+static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
+{
+	struct mesh_prov_initiator *rx_prov = user_data;
+	uint8_t *out;
+	uint8_t type = *data++;
+	uint8_t fail_code[2];
+	uint32_t oob_key;
+	uint64_t mic;
+
+	if (rx_prov != prov || !prov->trans_tx)
+		return;
+
+	l_debug("Provisioning packet received type: %2.2x (%u octets)",
+								type, len);
+
+	if (type == prov->previous) {
+		l_error("Ignore repeated %2.2x packet", type);
+		return;
+	} else if (type > prov->expected || type < prov->previous) {
+		l_error("Expected %2.2x, Got:%2.2x", prov->expected, type);
+		fail_code[1] = PROV_ERR_UNEXPECTED_PDU;
+		goto failure;
+	}
+
+	if (type >= L_ARRAY_SIZE(expected_pdu_size) ||
+					len != expected_pdu_size[type]) {
+		l_error("Expected PDU size %d, Got %d (type: %2.2x)",
+			len, expected_pdu_size[type], type);
+		fail_code[1] = PROV_ERR_INVALID_FORMAT;
+		goto failure;
+	}
+
+	switch (type) {
+	case PROV_CAPS: /* Capabilities */
+		prov->state = INT_PROV_INVITE_ACKED;
+		memcpy(&prov->conf_inputs.caps, data,
+					sizeof(prov->conf_inputs.caps));
+
+		l_debug("Got Num Ele %d", data[0]);
+		l_debug("Got alg %4.4x", l_get_be16(data + 1));
+		l_debug("Got pub_type %d", data[3]);
+		l_debug("Got static_type %d", data[4]);
+		l_debug("Got output_size %d", data[5]);
+		l_debug("Got output_action %d", l_get_be16(data + 6));
+		l_debug("Got input_size %d", data[8]);
+		l_debug("Got input_action %d", l_get_be16(data + 9));
+
+		if (!(l_get_be16(data + 1) & 0x0001)) {
+			l_error("Unsupported Algorithm");
+			fail_code[1] = PROV_ERR_INVALID_FORMAT;
+			goto failure;
+		}
+
+		/* If Public Key available Out of Band, use it */
+		if (prov->conf_inputs.caps.pub_type) {
+			prov->conf_inputs.start.pub_key = 0x01;
+			prov->expected = PROV_CONFIRM;
+			/* Prompt Agent for remote Public Key */
+			mesh_agent_request_public_key(prov->agent,
+							pub_key_cb, prov);
+
+			/* Nothing else for us to do now */
+		} else
+			prov->expected = PROV_PUB_KEY;
+
+		/* Parse OOB Options, prefer static, then out, then in */
+		if (prov->conf_inputs.caps.static_type) {
+
+			prov->conf_inputs.start.auth_method = 0x01;
+
+		} else if (prov->conf_inputs.caps.output_size &&
+				prov->conf_inputs.caps.output_action) {
+
+			prov->conf_inputs.start.auth_method = 0x02;
+			prov->conf_inputs.start.auth_action =
+					u16_high_bit(l_get_be16(data + 6));
+			prov->conf_inputs.start.auth_size =
+						(data[5] > 8 ? 8 : data[5]);
+
+		} else if (prov->conf_inputs.caps.input_size &&
+				prov->conf_inputs.caps.input_action) {
+
+			prov->conf_inputs.start.auth_method = 0x03;
+			prov->conf_inputs.start.auth_action =
+					u16_high_bit(l_get_be16(data + 9));
+			prov->conf_inputs.start.auth_size =
+						(data[8] > 8 ? 8 : data[8]);
+
+		}
+
+		out = l_malloc(1 + sizeof(prov->conf_inputs.start));
+		out[0] = PROV_START;
+		memcpy(out + 1, &prov->conf_inputs.start,
+					sizeof(prov->conf_inputs.start));
+
+		prov->state = INT_PROV_START_SENT;
+		prov->trans_tx(prov->trans_data, out,
+					sizeof(prov->conf_inputs.start) + 1);
+		l_free(out);
+		break;
+
+	case PROV_PUB_KEY: /* Public Key */
+		/* If we expected Pub Key Out-Of-Band, then fail */
+		if (prov->conf_inputs.start.pub_key) {
+			fail_code[1] = PROV_ERR_INVALID_PDU;
+			goto failure;
+		}
+
+		memcpy(prov->conf_inputs.dev_pub_key, data, 64);
+		prov->material |= MAT_REMOTE_PUBLIC;
+		prov->expected = PROV_CONFIRM;
+
+		if ((prov->material & MAT_SECRET) != MAT_SECRET)
+			return;
+
+		int_credentials(prov);
+		prov->state = INT_PROV_KEY_ACKED;
+
+		prov->expected = PROV_CONFIRM;
+
+		memset(prov->rand_auth_workspace + 16, 0, 32);
+		switch (prov->conf_inputs.start.auth_method) {
+		default:
+		case 0:
+			/* Auth Type 3c - No OOB */
+			prov->material |= MAT_RAND_AUTH;
+			break;
+		case 1:
+			/* Auth Type 3c - Static OOB */
+			/* Prompt Agent for Static OOB */
+			fail_code[1] = mesh_agent_request_static(prov->agent,
+					static_cb, prov);
+
+			if (fail_code[1])
+				goto failure;
+
+			break;
+		case 2:
+			/* Auth Type 3a - Output OOB */
+			/* Prompt Agent for Output OOB */
+			if (prov->conf_inputs.start.auth_action ==
+							PROV_ACTION_OUT_ALPHA) {
+				fail_code[1] = mesh_agent_prompt_alpha(
+					prov->agent,
+					static_cb, prov);
+			} else {
+				fail_code[1] = mesh_agent_prompt_number(
+					prov->agent, true,
+					prov->conf_inputs.start.auth_action,
+					number_cb, prov);
+			}
+
+			if (fail_code[1])
+				goto failure;
+
+			break;
+
+
+		case 3:
+			/* Auth Type 3b - input OOB */
+			l_getrandom(&oob_key, sizeof(oob_key));
+			oob_key %= digit_mod(prov->conf_inputs.start.auth_size);
+
+			/* Save two copies, for two confirmation values */
+			l_put_be32(oob_key, prov->rand_auth_workspace + 28);
+			l_put_be32(oob_key, prov->rand_auth_workspace + 44);
+			prov->material |= MAT_RAND_AUTH;
+			/* Ask Agent to Display U32 */
+			if (prov->conf_inputs.start.auth_action ==
+							PROV_ACTION_IN_ALPHA) {
+				/* TODO: Construst NUL-term string to pass */
+				fail_code[1] = mesh_agent_display_string(
+					prov->agent, NULL, NULL, prov);
+			} else {
+				fail_code[1] = mesh_agent_display_number(
+					prov->agent, false,
+					prov->conf_inputs.start.auth_action,
+					oob_key, NULL, prov);
+			}
+
+			if (fail_code[1])
+				goto failure;
+
+			break;
+
+
+		}
+		break;
+
+	case PROV_INP_CMPLT: /* Provisioning Input Complete */
+		/* TODO: Cancel Agent prompt */
+		prov->expected = PROV_CONFIRM;
+		out = l_malloc(17);
+		out[0] = PROV_CONFIRM;
+		mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace,
+								32, out + 1);
+		prov->trans_tx(prov->trans_data, out, 17);
+		l_free(out);
+		break;
+
+	case PROV_CONFIRM: /* Confirmation */
+		prov->state = INT_PROV_CONF_ACKED;
+		/* RXed Device Confirmation */
+		memcpy(prov->confirm, data, 16);
+		print_packet("ConfirmationDevice", prov->confirm, 16);
+		prov->expected = PROV_RANDOM;
+		out = l_malloc(17);
+		out[0] = PROV_RANDOM;
+		memcpy(out + 1, prov->rand_auth_workspace, 16);
+		prov->trans_tx(prov->trans_data, out, 17);
+		l_free(out);
+		break;
+
+	case PROV_RANDOM: /* Random */
+		prov->state = INT_PROV_RAND_ACKED;
+
+		/* RXed Device Confirmation */
+		memcpy(prov->rand_auth_workspace + 16, data, 16);
+		print_packet("RandomDevice", data, 16);
+		calc_local_material(data);
+
+		mesh_crypto_aes_cmac(prov->calc_key,
+						prov->rand_auth_workspace + 16,
+						32, prov->rand_auth_workspace);
+
+		if (memcmp(prov->rand_auth_workspace, prov->confirm, 16)) {
+			l_error("Provisioning Failed-Confirm compare)");
+			fail_code[1] = PROV_ERR_CONFIRM_FAILED;
+			goto failure;
+		}
+
+		if (prov->state == INT_PROV_RAND_ACKED) {
+			prov->expected = PROV_COMPLETE;
+			out = l_malloc(34);
+			out[0] = PROV_DATA;
+			/* TODO: Fill Prov Data Structure */
+			/* Encrypt Prov Data */
+			mesh_crypto_aes_ccm_encrypt(prov->s_nonce, prov->s_key,
+					NULL, 0,
+					out + 1,
+					25,
+					out + 1,
+					&mic, sizeof(mic));
+			prov->trans_tx(prov->trans_data, out, 34);
+			l_free(out);
+		}
+		break;
+
+	case PROV_COMPLETE: /* Complete */
+		l_info("Provisioning Complete");
+		prov->state = INT_PROV_IDLE;
+		//mesh_prov_close(prov, 0);
+		break;
+
+	case PROV_FAILED: /* Failed */
+		l_error("Provisioning Failed (reason: %d)", data[0]);
+		//mesh_prov_close(prov, data[0]);
+		break;
+
+	default:
+		l_error("Unknown Pkt %2.2x", type);
+		fail_code[1] = PROV_ERR_UNEXPECTED_PDU;
+		goto failure;
+	}
+
+	prov->previous = type;
+	return;
+
+failure:
+	fail_code[0] = PROV_FAILED;
+	prov->trans_tx(prov->trans_data, fail_code, 2);
+	/* TODO: Call Complete Callback (Fail)*/
+}
+
+static void int_prov_ack(void *user_data, uint8_t msg_num)
+{
+	/* TODO: Handle PB-ADV Ack */
+}
+
+
+bool initiator_start(enum trans_type transport,
+		uint8_t uuid[16],
+		uint16_t max_ele,
+		uint16_t server, /* Only valid for PB-Remote */
+		uint32_t timeout, /* in seconds from mesh.conf */
+		struct mesh_agent *agent,
+		mesh_prov_initiator_complete_func_t complete_cb,
+		void *caller_data)
+{
+	bool result;
+
+	/* Invoked from Add() method in mesh-api.txt, to add a
+	 * remote unprovisioned device network.
+	 */
+
+	if (prov)
+		return false;
+
+	prov = l_new(struct mesh_prov_initiator, 1);
+	prov->to_secs = timeout;
+	prov->agent = agent;
+	prov->cmplt = complete_cb;
+	prov->caller_data = caller_data;
+	prov->previous = -1;
+
+	/* Always register for PB-ADV */
+	result = pb_adv_reg(int_prov_open, int_prov_close, int_prov_rx,
+						int_prov_ack, uuid, prov);
+
+	if (result)
+		return true;
+
+	initiator_free();
+	return false;
+}
+
+void initiator_cancel(void *user_data)
+{
+	initiator_free();
+}
-- 
2.14.5


  parent reply	other threads:[~2018-12-19  4:21 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-19  4:19 [PATCH BlueZ v5 00/30] Major rewrite for Multi-Node and DBus Brian Gix
2018-12-19  4:19 ` [PATCH BlueZ v5 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
2018-12-24 20:56   ` Marcel Holtmann
2018-12-19  4:19 ` [PATCH BlueZ v5 02/30] mesh: Delete obsolete files Brian Gix
2018-12-24 20:57   ` Marcel Holtmann
2018-12-19  4:19 ` [PATCH BlueZ v5 03/30] mesh: Utilities for DBus support Brian Gix
2018-12-24 21:01   ` Marcel Holtmann
2018-12-19  4:19 ` [PATCH BlueZ v5 04/30] mesh: Internal errors Brian Gix
2018-12-24 21:03   ` Marcel Holtmann
2018-12-19  4:19 ` [PATCH BlueZ v5 05/30] mesh: Rewrite storage for Multiple Nodes Brian Gix
2018-12-24 21:05   ` Marcel Holtmann
2018-12-19  4:19 ` [PATCH BlueZ v5 06/30] mesh: Rewrite Node handling for multiple nodes Brian Gix
2018-12-19  4:19 ` [PATCH BlueZ v5 07/30] mesh: Rewrite Network layer " Brian Gix
2018-12-19  4:19 ` [PATCH BlueZ v5 08/30] mesh: Direction agnostic PB-Adv implementation Brian Gix
2018-12-19  4:19 ` [PATCH BlueZ v5 09/30] mesh: Acceptor side provisioning implementation Brian Gix
2018-12-19  4:19 ` Brian Gix [this message]
2018-12-19  4:19 ` [PATCH BlueZ v5 11/30] mesh: Rewrite Controler interface for full init Brian Gix
2018-12-19  4:19 ` [PATCH BlueZ v5 12/30] mesh: Unchanged variables set to const Brian Gix
2018-12-19  4:19 ` [PATCH BlueZ v5 13/30] mesh: centralize generic utilities Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 14/30] mesh: re-arrange provisioning for DBus API Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 15/30] mesh: Re-architect " Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 16/30] mesh: Make config model handle multiple nodes Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 18/30] mesh: restructure I/O for " Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 19/30] mesh: Restructure DB to support " Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 20/30] mesh: restructure model services for " Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 21/30] mesh: DBUS interface for Provisioning Agent Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 22/30] mesh: restructure App Key storage Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 23/30] mesh: Clean-up Comment style Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 24/30] mesh: Update for DBus API and multi-node support Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 25/30] mesh: Add default location for Mesh Node storage Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 26/30] mesh: Add structural changes for mesh Brian Gix
2018-12-19  4:20 ` [PATCH BlueZ v5 27/30] mesh: Sample Provisioning Agent Brian Gix
2018-12-24 21:09   ` Marcel Holtmann
2018-12-27 19:22     ` Gix, Brian
2018-12-19  4:20 ` [PATCH BlueZ v5 28/30] mesh: Sample On/Off Client and Server Brian Gix
2018-12-24 21:10   ` Marcel Holtmann
2018-12-19  4:20 ` [PATCH BlueZ v5 30/30] mesh: Enable building Mesh Daemon Brian Gix
2018-12-24 21:12   ` Marcel Holtmann
2018-12-23 17:54 ` [PATCH BlueZ v5 00/30] Major rewrite for Multi-Node and DBus Gix, Brian
     [not found] ` <20181219042016.25538-30-brian.gix@intel.com>
2018-12-24 21:10   ` [PATCH BlueZ v5 29/30] mesh: Sample Mesh Joiner (provision acceptor) Marcel Holtmann

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=20181219042016.25538-11-brian.gix@intel.com \
    --to=brian.gix@intel.com \
    --cc=inga.stotland@intel.com \
    --cc=johan.hedberg@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=marcel@holtmann.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.