nRF5 SDK for Mesh v1.0.1
provisioner.c
1 /* Copyright (c) 2010 - 2017, Nordic Semiconductor ASA
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form, except as embedded into a Nordic
11  * Semiconductor ASA integrated circuit in a product or a software update for
12  * such product, must reproduce the above copyright notice, this list of
13  * conditions and the following disclaimer in the documentation and/or other
14  * materials provided with the distribution.
15  *
16  * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
17  * contributors may be used to endorse or promote products derived from this
18  * software without specific prior written permission.
19  *
20  * 4. This software, with or without modification, must only be used with a
21  * Nordic Semiconductor ASA integrated circuit.
22  *
23  * 5. Any software provided in binary form under this license must not be reverse
24  * engineered, decompiled, modified and/or disassembled.
25  *
26  * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
27  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
29  * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
32  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include "provisioner.h"
39 
40 #include <stdint.h>
41 #include <stdbool.h>
42 #include <string.h>
43 
44 #include "log.h"
45 #include "nrf_mesh_assert.h"
46 
47 #include "nrf_mesh_prov.h"
48 #include "nrf_mesh_prov_bearer_adv.h"
49 #include "nrf_mesh_events.h"
50 #include "device_state_manager.h"
51 
52 #include "config_client.h"
53 #include "access_config.h"
54 #include "simple_on_off_server.h"
55 #include "health_common.h"
56 
57 #include "nrf_mesh_sdk.h"
58 
59 typedef enum
60 {
61  PROV_STATE_IDLE,
62  PROV_STATE_WAIT,
63  PROV_STATE_PROV,
64  PROV_STATE_CONFIG_FIRST,
65  PROV_STATE_CONFIG_COMPOSITION_GET,
66  PROV_STATE_CONFIG_APPKEY_ADD,
67  PROV_STATE_CONFIG_APPKEY_BIND_HEALTH,
68  PROV_STATE_CONFIG_APPKEY_BIND_ONOFF,
69  PROV_STATE_CONFIG_PUBLICATION_HEALTH,
70  PROV_STATE_CONFIG_PUBLICATION_ONOFF,
71  PROV_STATE_CONFIG_SUBSCRIPTION
72 } prov_state_t;
73 
74 /* Provisioning encryption key storage (this is not how you should store your keys). */
75 static uint8_t m_public_key[NRF_MESH_PROV_PUBKEY_SIZE];
76 static uint8_t m_private_key[NRF_MESH_PROV_PRIVKEY_SIZE];
77 
78 static nrf_mesh_prov_bearer_adv_t m_prov_bearer_adv;
79 static nrf_mesh_prov_ctx_t m_prov_ctx;
80 
81 static prov_state_t m_prov_state;
82 static uint16_t m_target_address;
83 
84 
85 static void start_provisioning(const uint8_t * p_uuid)
86 {
88  {
89  .netkey = NETKEY,
90  .netkey_index = NETKEY_INDEX,
91  .iv_index = 0,
92  .address = m_target_address,
93  .flags.iv_update = false,
94  .flags.key_refresh = false
95  };
96  ERROR_CHECK(nrf_mesh_prov_provision(&m_prov_ctx, p_uuid, &prov_data, NRF_MESH_PROV_BEARER_ADV));
97  m_prov_state = PROV_STATE_PROV;
98 }
99 
100 static void do_config_step(void)
101 {
102  switch (m_prov_state)
103  {
104  case PROV_STATE_CONFIG_FIRST:
105  m_prov_state = PROV_STATE_CONFIG_COMPOSITION_GET;
106  /* fall through */
107 
108  /* Read the composition data from the node: */
109  case PROV_STATE_CONFIG_COMPOSITION_GET:
110  {
111  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Getting composition data\n");
112  ERROR_CHECK(config_client_composition_data_get());
113  break;
114  }
115 
116  /* Add the application key to the node: */
117  case PROV_STATE_CONFIG_APPKEY_ADD:
118  {
119  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Adding appkey\n");
120  uint8_t appkey[NRF_MESH_KEY_SIZE] = APPKEY;
121  ERROR_CHECK(config_client_appkey_add(NETKEY_INDEX, APPKEY_INDEX, appkey));
122  break;
123  }
124 
125  /* Bind the health server to the application key: */
126  case PROV_STATE_CONFIG_APPKEY_BIND_HEALTH:
127  {
128  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Binding appkey to the Health model\n");
129  access_model_id_t model_id;
131  model_id.model_id = HEALTH_SERVER_MODEL_ID;
132  uint16_t element_address = m_target_address;
133  ERROR_CHECK(config_client_model_app_bind(element_address, APPKEY_INDEX, model_id));
134  break;
135  }
136 
137  /* Bind the On/Off server to the application key: */
138  case PROV_STATE_CONFIG_APPKEY_BIND_ONOFF:
139  {
140  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Binding appkey to the Simple On/Off model\n");
141  access_model_id_t model_id;
144  uint16_t element_address = m_target_address;
145  ERROR_CHECK(config_client_model_app_bind(element_address, APPKEY_INDEX, model_id));
146  break;
147  }
148 
149  /* Configure the publication parameters for the On/Off server: */
150  case PROV_STATE_CONFIG_PUBLICATION_HEALTH:
151  {
152  config_publication_state_t pubstate = {0};
153  pubstate.element_address = m_target_address;
155  pubstate.publish_address.value = PROVISIONER_ADDRESS;
156  pubstate.appkey_index = 0;
157  pubstate.frendship_credential_flag = false;
158  pubstate.publish_ttl = SERVER_COUNT;
159  pubstate.publish_period.step_num = 1;
161  pubstate.retransmit_count = 1;
162  pubstate.retransmit_interval = 0;
165  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting publication address for the health server to 0x%04x\n", pubstate.publish_address.value);
166 
167  ERROR_CHECK(config_client_model_publication_set(&pubstate));
168  break;
169  }
170 
171  /* Configure the publication parameters for the On/Off server: */
172  case PROV_STATE_CONFIG_PUBLICATION_ONOFF:
173  {
174  config_publication_state_t pubstate = {0};
175  pubstate.element_address = m_target_address;
177  pubstate.publish_address.value = PROVISIONER_ADDRESS + m_target_address - UNPROV_START_ADDRESS;
178  pubstate.appkey_index = 0;
179  pubstate.frendship_credential_flag = false;
180  pubstate.publish_ttl = SERVER_COUNT;
181  pubstate.publish_period.step_num = 0;
183  pubstate.retransmit_count = 1;
184  pubstate.retransmit_interval = 0;
187  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Setting publication address for the On/Off server to 0x%04x\n", pubstate.publish_address.value);
188 
189  ERROR_CHECK(config_client_model_publication_set(&pubstate));
190  break;
191  }
192 
193  /* Add a subscription to the group address to the node: */
194  case PROV_STATE_CONFIG_SUBSCRIPTION:
195  {
196  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Adding subscription\n");
197  uint16_t element_address = m_target_address;
200  address.value = GROUP_ADDRESS;
201  access_model_id_t model_id;
204  ERROR_CHECK(config_client_model_subscription_add(element_address, address, model_id));
205  break;
206  }
207 
208  default:
209  NRF_MESH_ASSERT(false);
210  break;
211  }
212 }
213 
214 static void prov_evt_handler(const nrf_mesh_prov_evt_t * p_evt)
215 {
216  switch (p_evt->type)
217  {
219  if (m_prov_state == PROV_STATE_WAIT)
220  {
221  start_provisioning(p_evt->params.unprov.device_uuid);
222  m_prov_state = PROV_STATE_PROV;
223  }
224  break;
225 
227  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Local provisioning link closed\n");
228  if (m_prov_state == PROV_STATE_PROV)
229  {
230  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Provisioning failed. Retrying...\n");
231  m_prov_state = PROV_STATE_WAIT;
232  }
233  else if (m_prov_state == PROV_STATE_CONFIG_FIRST)
234  {
235  do_config_step();
236  }
237  break;
238 
240  m_prov_state = PROV_STATE_IDLE;
241  provisioner_prov_complete_cb(&p_evt->params.complete);
242  break;
243 
245  {
246  uint32_t status = nrf_mesh_prov_oob_use(p_evt->params.oob_caps_received.p_context,
248  0,
250  if (status != NRF_SUCCESS)
251  {
252  __LOG(LOG_SRC_APP, LOG_LEVEL_ERROR,
253  "Provisioning OOB selection rejected, error code %d. Retrying...\n", status);
254  m_prov_state = PROV_STATE_WAIT;
255  }
256  else
257  {
258  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Using static authentication\n");
259  }
260  break;
261  }
262 
264  {
265  uint8_t static_data[16] = STATIC_AUTH_DATA;
266  ERROR_CHECK(nrf_mesh_prov_auth_data_provide(p_evt->params.static_request.p_context, static_data, 16));
267  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Static authentication data provided\n");
268  break;
269  }
270 
272  __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Local provisioning link established\n");
273  break;
274 
275  default:
276  break;
277  }
278 }
279 
280 void provisioner_configure(uint16_t address)
281 {
282  m_target_address = address;
283  if (m_prov_state == PROV_STATE_PROV)
284  {
285  /* Wait for the NRF_MESH_PROV_EVT_LINK_CLOSED event. */
286  m_prov_state = PROV_STATE_CONFIG_FIRST;
287  }
288  else
289  {
290  m_prov_state = PROV_STATE_CONFIG_FIRST;
291  do_config_step();
292  }
293 }
294 
295 void provisioner_wait_for_unprov(uint16_t address)
296 {
297  m_target_address = address;
298  m_prov_state = PROV_STATE_WAIT;
299 }
300 
301 void config_client_event_cb(config_client_event_type_t event_type, const config_client_event_t * p_event, uint16_t length)
302 {
303  if (event_type == CONFIG_CLIENT_EVENT_TYPE_TIMEOUT)
304  {
305  provisioner_config_failed_cb();
306  return;
307  }
308 
309  NRF_MESH_ASSERT(p_event != NULL);
310 
312  m_prov_state == PROV_STATE_CONFIG_COMPOSITION_GET)
313  {
314  __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, "Composition data", ((const uint8_t *) &p_event->p_msg->composition_data_status), length);
315  m_prov_state = PROV_STATE_CONFIG_APPKEY_ADD;
316  do_config_step();
317  }
318  else if (p_event->opcode == CONFIG_OPCODE_APPKEY_STATUS &&
319  m_prov_state == PROV_STATE_CONFIG_APPKEY_ADD)
320  {
321  NRF_MESH_ASSERT(p_event->p_msg->appkey_status.status == ACCESS_STATUS_SUCCESS ||
322  p_event->p_msg->appkey_status.status == ACCESS_STATUS_KEY_INDEX_ALREADY_STORED);
323  m_prov_state = PROV_STATE_CONFIG_APPKEY_BIND_HEALTH;
324  do_config_step();
325  }
326  else if (p_event->opcode == CONFIG_OPCODE_MODEL_APP_STATUS &&
327  m_prov_state == PROV_STATE_CONFIG_APPKEY_BIND_HEALTH)
328  {
329  NRF_MESH_ASSERT(p_event->p_msg->app_status.status == ACCESS_STATUS_SUCCESS);
330  m_prov_state = PROV_STATE_CONFIG_APPKEY_BIND_ONOFF;
331  do_config_step();
332  }
333  else if (p_event->opcode == CONFIG_OPCODE_MODEL_APP_STATUS &&
334  m_prov_state == PROV_STATE_CONFIG_APPKEY_BIND_ONOFF)
335  {
336  NRF_MESH_ASSERT(p_event->p_msg->app_status.status == ACCESS_STATUS_SUCCESS);
337  m_prov_state = PROV_STATE_CONFIG_PUBLICATION_HEALTH;
338  do_config_step();
339  }
340  else if (p_event->opcode == CONFIG_OPCODE_MODEL_PUBLICATION_STATUS &&
341  m_prov_state == PROV_STATE_CONFIG_PUBLICATION_HEALTH)
342  {
343  NRF_MESH_ASSERT(p_event->p_msg->publication_status.status == ACCESS_STATUS_SUCCESS);
344  m_prov_state = PROV_STATE_CONFIG_PUBLICATION_ONOFF;
345  do_config_step();
346  }
347  else if (p_event->opcode == CONFIG_OPCODE_MODEL_PUBLICATION_STATUS &&
348  m_prov_state == PROV_STATE_CONFIG_PUBLICATION_ONOFF)
349  {
350  NRF_MESH_ASSERT(p_event->p_msg->publication_status.status == ACCESS_STATUS_SUCCESS);
351  m_prov_state = PROV_STATE_CONFIG_SUBSCRIPTION;
352  do_config_step();
353  }
354  else if (p_event->opcode == CONFIG_OPCODE_MODEL_SUBSCRIPTION_STATUS &&
355  m_prov_state == PROV_STATE_CONFIG_SUBSCRIPTION)
356  {
357  NRF_MESH_ASSERT(p_event->p_msg->subscription_status.status == ACCESS_STATUS_SUCCESS);
358  m_prov_state = PROV_STATE_IDLE;
359  provisioner_config_successful_cb();
360  }
361  else
362  {
363  /* Do nothing. */
364  }
365 }
366 
367 void provisioner_init(void)
368 {
369  m_prov_state = PROV_STATE_IDLE;
371 
372  ERROR_CHECK(nrf_mesh_prov_generate_keys(m_public_key, m_private_key));
373  ERROR_CHECK(nrf_mesh_prov_init(&m_prov_ctx, m_public_key, m_private_key, &capabilities, prov_evt_handler));
374  ERROR_CHECK(nrf_mesh_prov_bearer_add(&m_prov_ctx, nrf_mesh_prov_bearer_adv_interface_get(&m_prov_bearer_adv)));
375  ERROR_CHECK(nrf_mesh_prov_scan_start(prov_evt_handler));
376 }
377 
Provisioning completed.
Step resolution: 100ms / step.
Definition: access.h:298
uint32_t config_client_appkey_add(uint16_t netkey_index, uint16_t appkey_index, const uint8_t *p_appkey)
Sends an application key add request.
uint8_t status
Status code.
Invalid address.
Definition: nrf_mesh.h:356
Command successfully processed.
Definition: access_status.h:49
uint16_t company_id
Company ID.
Definition: access.h:149
#define SIMPLE_ON_OFF_SERVER_MODEL_ID
Simple OnOff Server model ID.
#define NRF_MESH_PROV_PUBKEY_SIZE
Size of the elliptic curve public key.
Provisioning event structure.
uint8_t retransmit_interval
Retransmit interval (in multiples of 50 ms).
Definition: config_client.h:83
#define NRF_MESH_KEY_SIZE
Size (in octets) of an encryption key.
uint16_t value
Address value.
Definition: nrf_mesh.h:375
#define NRF_MESH_ASSERT(cond)
Run-time assertion.
nrf_mesh_address_t publish_address
Publish address.
Definition: config_client.h:65
uint8_t step_res
Step resolution.
Definition: access.h:287
uint32_t nrf_mesh_prov_auth_data_provide(nrf_mesh_prov_ctx_t *p_ctx, const uint8_t *p_data, uint8_t size)
Provides out-of-band authentication data input to the provisioning stack.
#define ACCESS_COMPANY_ID_NORDIC
Company ID value for Nordic Semiconductor.
Definition: access.h:73
#define NRF_MESH_PROV_OOB_CAPS_DEFAULT(NUM_ELEMENTS)
Sets the default authentication capabilities.
Definition: nrf_mesh_prov.h:66
Provisioning link established.
uint32_t config_client_model_app_bind(uint16_t element_address, uint16_t appkey_index, access_model_id_t model_id)
Sends a application bind request.
Static OOB authentication method.
nrf_mesh_prov_evt_unprov_t unprov
Unprovisioned beacon received event.
uint32_t config_client_model_subscription_add(uint16_t element_address, nrf_mesh_address_t address, access_model_id_t model_id)
Sends a subscription add request.
Opcode for the "Config Model Subscription Status" message.
#define NRF_MESH_PROV_PRIVKEY_SIZE
Size of the elliptic curve private key.
uint16_t element_address
Element address of the model to set the publication state.
Definition: config_client.h:60
Provisioning link lost.
uint8_t step_num
Number of steps.
Definition: access.h:289
Advertising-based provisioning bearer, PB-ADV.
nrf_mesh_prov_ctx_t * p_context
Provisioning context where the capabilities were received.
uint32_t nrf_mesh_prov_provision(nrf_mesh_prov_ctx_t *p_ctx, const uint8_t *p_target_uuid, const nrf_mesh_prov_provisioning_data_t *p_data, nrf_mesh_prov_bearer_type_t bearer)
Provisions a device.
nrf_mesh_prov_ctx_t * p_context
Provisioning context pointer.
PB-ADV context structure.
Opcode for the "Config Model Publication Status" message.
Received an unprovisioned node beacon.
uint8_t device_uuid[NRF_MESH_UUID_SIZE]
Device UUID of the unprovisioned node.
Configuration client event structure.
Opcode for the "AppKey Status" message.
prov_bearer_t * nrf_mesh_prov_bearer_adv_interface_get(nrf_mesh_prov_bearer_adv_t *p_bearer_adv)
Gets the provisioning bearer interface for the PB-ADV bearer.
Publication state parameter structure.
Definition: config_client.h:57
access_model_id_t model_id
Model identifier.
Definition: config_client.h:85
nrf_mesh_prov_evt_caps_received_t oob_caps_received
Provisioning capabilities received.
nrf_mesh_address_type_t type
Address type.
Definition: nrf_mesh.h:373
uint32_t config_client_composition_data_get(void)
Sends a composition data GET request.
uint32_t nrf_mesh_prov_generate_keys(uint8_t *p_public, uint8_t *p_private)
Generates a valid keypair for use with the provisioning cryptography.
const config_msg_t * p_msg
Pointer to message structure.
uint16_t model_id
Model ID.
Definition: access.h:147
#define ACCESS_COMPANY_ID_NONE
Company ID value for Bluetooth SIG opcodes or models.
Definition: access.h:71
uint16_t appkey_index
Application key index.
Definition: config_client.h:67
Provisioning authentication capabilities.
#define HEALTH_SERVER_MODEL_ID
Model ID for the Health Server model.
Definition: health_common.h:49
Step resolution: 10s / step.
Definition: access.h:302
uint32_t nrf_mesh_prov_bearer_add(nrf_mesh_prov_ctx_t *p_ctx, prov_bearer_t *p_prov_bearer)
Adds a new bearer to the provisioning context structure.
uint32_t config_client_model_publication_set(const config_publication_state_t *p_publication_state)
Sends a model publication set request.
config_client_event_type_t
Configuration client event types.
Definition: config_client.h:89
Bluetooth Mesh address.
Definition: nrf_mesh.h:370
uint32_t nrf_mesh_prov_scan_start(nrf_mesh_prov_evt_handler_cb_t event_handler)
Starts the scanning for unprovisioned devices.
nrf_mesh_prov_evt_complete_t complete
Provisioning complete.
Provisioning data to transmit to a device.
uint32_t nrf_mesh_prov_oob_use(nrf_mesh_prov_ctx_t *p_ctx, nrf_mesh_prov_oob_method_t method, uint8_t action, uint8_t size)
Selects which out-of-band authentication method to use.
Access layer model ID.
Definition: access.h:144
uint8_t publish_ttl
Publish TTL value.
Definition: config_client.h:77
Provisioning static data request.
uint32_t nrf_mesh_prov_init(nrf_mesh_prov_ctx_t *p_ctx, const uint8_t *p_public_key, const uint8_t *p_private_key, const nrf_mesh_prov_oob_caps_t *p_caps, nrf_mesh_prov_evt_handler_cb_t event_handler)
Initializes the provisioning context structure.
Opcode for the "Composition Data Status" message.
config_opcode_t opcode
Opcode of the status reply.
bool frendship_credential_flag
Set true to use friendship credentials for publishing.
Definition: config_client.h:72
uint8_t retransmit_count
Retransmit count.
Definition: config_client.h:81
Provisionee capabilities received.
uint8_t status
Status code.
Opcode for the "Model App Status" message.
The key with given index is already stored in the node with a different value.
Definition: access_status.h:55
access_publish_period_t publish_period
Publish period.
Definition: config_client.h:79
#define ACCESS_ELEMENT_COUNT
The number of elements in the application.
Unicast address.
Definition: nrf_mesh.h:358
nrf_mesh_prov_evt_static_request_t static_request
Static provisioning data requested.
uint8_t netkey[NRF_MESH_KEY_SIZE]
Network key for the device.

Documentation feedback | Developer Zone | Subscribe | Updated