/
wisun_tasklet.c
336 lines (301 loc) · 12.9 KB
/
wisun_tasklet.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*
* Copyright (c) 2018 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h> //memset
#include "eventOS_event_timer.h"
#include "common_functions.h"
#include "ip6string.h" //ip6tos
#include "nsdynmemLIB.h"
#include "include/wisun_tasklet.h"
#include "include/mesh_system.h"
#include "ns_event_loop.h"
#include "fhss_api.h"
#include "fhss_config.h"
#include "multicast_api.h"
#include "mac_api.h"
#include "sw_mac.h"
#include "ws_management_api.h" //ws_management_node_init
#ifdef MBED_CONF_MBED_MESH_API_CERTIFICATE_HEADER
#include MBED_CONF_MBED_MESH_API_CERTIFICATE_HEADER
#endif
// For tracing we need to define flag, have include and define group
//#define HAVE_DEBUG
#define TRACE_GROUP "WSND"
#include "ns_trace.h"
// Tasklet timer events
#define TIMER_EVENT_START_BOOTSTRAP 1
#define INVALID_INTERFACE_ID (-1)
#define INTERFACE_NAME "WiSunInterface"
/*
* Mesh tasklet states.
*/
typedef enum {
TASKLET_STATE_CREATED = 0,
TASKLET_STATE_INITIALIZED,
TASKLET_STATE_BOOTSTRAP_STARTED,
TASKLET_STATE_BOOTSTRAP_FAILED,
TASKLET_STATE_BOOTSTRAP_READY
} tasklet_state_t;
/*
* Mesh tasklet data structure.
*/
typedef struct {
void (*mesh_api_cb)(mesh_connection_status_t nwk_status);
tasklet_state_t tasklet_state;
int8_t tasklet;
net_6lowpan_mode_e operating_mode;
net_6lowpan_mode_extension_e operating_mode_extension;
int8_t network_interface_id;
} wisun_tasklet_data_str_t;
/* Tasklet data */
static wisun_tasklet_data_str_t *wisun_tasklet_data_ptr = NULL;
static mac_api_t *mac_api = NULL;
static char *network_name = MBED_CONF_MBED_MESH_API_WISUN_NETWORK_NAME;
extern fhss_timer_t fhss_functions;
/* private function prototypes */
static void wisun_tasklet_main(arm_event_s *event);
static void wisun_tasklet_network_state_changed(mesh_connection_status_t status);
static void wisun_tasklet_parse_network_event(arm_event_s *event);
static void wisun_tasklet_configure_and_connect_to_network(void);
/*
* \brief A function which will be eventually called by NanoStack OS when ever the OS has an event to deliver.
* @param event, describes the sender, receiver and event type.
*
* NOTE: Interrupts requested by HW are possible during this function!
*/
static void wisun_tasklet_main(arm_event_s *event)
{
arm_library_event_type_e event_type;
event_type = (arm_library_event_type_e) event->event_type;
switch (event_type) {
case ARM_LIB_NWK_INTERFACE_EVENT:
/* This event is delivered every and each time when there is new
* information of network connectivity.
*/
wisun_tasklet_parse_network_event(event);
break;
case ARM_LIB_TASKLET_INIT_EVENT:
/* Event with type EV_INIT is an initializer event of NanoStack OS.
* The event is delivered when the NanoStack OS is running fine.
* This event should be delivered ONLY ONCE.
*/
mesh_system_send_connect_event(wisun_tasklet_data_ptr->tasklet);
break;
case ARM_LIB_SYSTEM_TIMER_EVENT:
eventOS_event_timer_cancel(event->event_id, wisun_tasklet_data_ptr->tasklet);
if (event->event_id == TIMER_EVENT_START_BOOTSTRAP) {
tr_debug("Restart bootstrap");
wisun_tasklet_configure_and_connect_to_network();
}
break;
case APPLICATION_EVENT:
if (event->event_id == APPL_EVENT_CONNECT) {
wisun_tasklet_configure_and_connect_to_network();
}
break;
default:
break;
} // switch(event_type)
}
/**
* \brief Network state event handler.
* \param event show network start response or current network state.
*
* - ARM_NWK_BOOTSTRAP_READY: Save NVK persistent data to NVM and Net role
* - ARM_NWK_NWK_SCAN_FAIL: Link Layer Active Scan Fail, Stack is Already at Idle state
* - ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL: No WS Router at current Channel Stack is Already at Idle state
* - ARM_NWK_NWK_CONNECTION_DOWN: Connection to Access point is lost wait for Scan Result
* - ARM_NWK_NWK_PARENT_POLL_FAIL: Host should run net start without any PAN-id filter and all channels
* - ARM_NWK_AUHTENTICATION_FAIL: Pana Authentication fail, Stack is Already at Idle state
*/
static void wisun_tasklet_parse_network_event(arm_event_s *event)
{
arm_nwk_interface_status_type_e status = (arm_nwk_interface_status_type_e) event->event_data;
tr_debug("app_parse_network_event() %d", status);
switch (status) {
case ARM_NWK_BOOTSTRAP_READY:
/* Network is ready and node is connected to Access Point */
if (wisun_tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) {
tr_info("Wi-SUN bootstrap ready");
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_READY;
wisun_tasklet_network_state_changed(MESH_CONNECTED);
}
break;
case ARM_NWK_NWK_SCAN_FAIL:
/* Link Layer Active Scan Fail, Stack is Already at Idle state */
tr_debug("Link Layer Scan Fail: No Beacons");
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
break;
case ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL:
/* No WS Router at current Channel Stack is Already at Idle state */
tr_debug("WS Scan/ GP REG fail");
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
break;
case ARM_NWK_NWK_CONNECTION_DOWN:
/* Connection to Access point is lost wait for Scan Result */
tr_debug("WS/RPL scan new network");
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
break;
case ARM_NWK_NWK_PARENT_POLL_FAIL:
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
break;
case ARM_NWK_AUHTENTICATION_FAIL:
tr_debug("Network authentication fail");
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
break;
default:
tr_warn("Unknown event %d", status);
break;
}
if (wisun_tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY &&
wisun_tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
// Set 5s timer for new network scan
eventOS_event_timer_request(TIMER_EVENT_START_BOOTSTRAP,
ARM_LIB_SYSTEM_TIMER_EVENT,
wisun_tasklet_data_ptr->tasklet,
5000);
}
}
/*
* \brief Configure and establish network connection
*
*/
static void wisun_tasklet_configure_and_connect_to_network(void)
{
int8_t status;
fhss_timer_t *fhss_timer_ptr = &fhss_functions;
wisun_tasklet_data_ptr->operating_mode = NET_6LOWPAN_ROUTER;
wisun_tasklet_data_ptr->operating_mode_extension = NET_6LOWPAN_WS;
arm_nwk_interface_configure_6lowpan_bootstrap_set(
wisun_tasklet_data_ptr->network_interface_id,
wisun_tasklet_data_ptr->operating_mode,
wisun_tasklet_data_ptr->operating_mode_extension);
ws_management_node_init(wisun_tasklet_data_ptr->network_interface_id,
MBED_CONF_MBED_MESH_API_WISUN_REGULATORY_DOMAIN,
network_name,
fhss_timer_ptr);
#if defined(MBED_CONF_MBED_MESH_API_CERTIFICATE_HEADER)
arm_certificate_chain_entry_s chain_info;
memset(&chain_info, 0, sizeof(arm_certificate_chain_entry_s));
chain_info.cert_chain[0] = (const uint8_t *) MBED_CONF_MBED_MESH_API_ROOT_CERTIFICATE;
chain_info.cert_len[0] = strlen((const char *) MBED_CONF_MBED_MESH_API_ROOT_CERTIFICATE) + 1;
chain_info.cert_chain[1] = (const uint8_t *) MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE;
chain_info.cert_len[1] = strlen((const char *) MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE) + 1;
chain_info.key_chain[1] = (const uint8_t *) MBED_CONF_MBED_MESH_API_OWN_CERTIFICATE_KEY;
chain_info.chain_length = 2;
arm_network_certificate_chain_set((const arm_certificate_chain_entry_s *) &chain_info);
#endif
status = arm_nwk_interface_up(wisun_tasklet_data_ptr->network_interface_id);
if (status >= 0) {
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_STARTED;
tr_info("Start Wi-SUN Bootstrap");
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
} else {
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
tr_err("Bootstrap start failed, %d", status);
wisun_tasklet_network_state_changed(MESH_BOOTSTRAP_START_FAILED);
}
}
/*
* Inform application about network state change
*/
static void wisun_tasklet_network_state_changed(mesh_connection_status_t status)
{
if (wisun_tasklet_data_ptr->mesh_api_cb) {
(wisun_tasklet_data_ptr->mesh_api_cb)(status);
}
}
/* Public functions */
int8_t wisun_tasklet_get_router_ip_address(char *address, int8_t len)
{
network_layer_address_s nd_address;
if ((len >= 40) && (0 == arm_nwk_nd_address_read(wisun_tasklet_data_ptr->network_interface_id, &nd_address))) {
ip6tos(nd_address.border_router, address);
tr_debug("Router IP address: %s", address);
return 0;
} else {
return -1;
}
}
int8_t wisun_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id)
{
int8_t re_connecting = true;
int8_t tasklet_id = wisun_tasklet_data_ptr->tasklet;
if (wisun_tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
return -3; // already connected to network
}
if (wisun_tasklet_data_ptr->tasklet_state == TASKLET_STATE_CREATED) {
re_connecting = false;
}
memset(wisun_tasklet_data_ptr, 0, sizeof(wisun_tasklet_data_str_t));
wisun_tasklet_data_ptr->mesh_api_cb = callback;
wisun_tasklet_data_ptr->network_interface_id = nwk_interface_id;
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_INITIALIZED;
if (re_connecting == false) {
wisun_tasklet_data_ptr->tasklet = eventOS_event_handler_create(&wisun_tasklet_main,
ARM_LIB_TASKLET_INIT_EVENT);
if (wisun_tasklet_data_ptr->tasklet < 0) {
// -1 handler already used by other tasklet
// -2 memory allocation failure
return wisun_tasklet_data_ptr->tasklet;
}
} else {
wisun_tasklet_data_ptr->tasklet = tasklet_id;
mesh_system_send_connect_event(wisun_tasklet_data_ptr->tasklet);
}
return wisun_tasklet_data_ptr->tasklet;
}
int8_t wisun_tasklet_disconnect(bool send_cb)
{
int8_t status = -1;
if (wisun_tasklet_data_ptr != NULL) {
if (wisun_tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
status = arm_nwk_interface_down(wisun_tasklet_data_ptr->network_interface_id);
wisun_tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
if (send_cb == true) {
wisun_tasklet_network_state_changed(MESH_DISCONNECTED);
}
}
wisun_tasklet_data_ptr->mesh_api_cb = NULL;
}
return status;
}
void wisun_tasklet_init(void)
{
if (wisun_tasklet_data_ptr == NULL) {
wisun_tasklet_data_ptr = ns_dyn_mem_alloc(sizeof(wisun_tasklet_data_str_t));
memset(wisun_tasklet_data_ptr, 0, sizeof(wisun_tasklet_data_str_t));
wisun_tasklet_data_ptr->tasklet_state = TASKLET_STATE_CREATED;
wisun_tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
}
}
int8_t wisun_tasklet_network_init(int8_t device_id)
{
// TODO, read interface name from configuration
mac_description_storage_size_t storage_sizes;
storage_sizes.device_decription_table_size = 32;
storage_sizes.key_description_table_size = 4;
storage_sizes.key_lookup_size = 1;
storage_sizes.key_usage_size = 3;
if (!mac_api) {
mac_api = ns_sw_mac_create(device_id, &storage_sizes);
}
return arm_nwk_interface_lowpan_init(mac_api, INTERFACE_NAME);
}