Contiki-NG
sixp-trans.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, Yasuyuki Tanaka
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /**
31  * \addtogroup sixtop
32  * @{
33  */
34 /**
35  * \file
36  * Transaction Management for 6top Protocol (6P)
37  * \author
38  * Yasuyuki Tanaka <yasuyuki.tanaka@inf.ethz.ch>
39  */
40 
41 #include "contiki-lib.h"
42 #include "lib/assert.h"
43 
44 #include "sixtop.h"
45 #include "sixtop-conf.h"
46 #include "sixp-nbr.h"
47 #include "sixp-trans.h"
48 
49 /* Log configuration */
50 #include "sys/log.h"
51 #define LOG_MODULE "6top"
52 #define LOG_LEVEL LOG_LEVEL_6TOP
53 
54 /**
55  * \brief 6P Transaction Data Structure (for internal use)
56  */
57 typedef struct sixp_trans {
58  struct sixp_trans *next;
59  const sixtop_sf_t *sf;
60  linkaddr_t peer_addr;
61  uint8_t seqno;
62  sixp_pkt_cmd_t cmd;
63  sixp_trans_state_t state;
64  sixp_trans_mode_t mode;
65  struct {
67  void *arg;
68  uint16_t arg_len;
69  } callback;
70  struct ctimer timer;
71 } sixp_trans_t;
72 
73 static void handle_trans_timeout(void *ptr);
74 static void process_trans(void *ptr);
75 static void schedule_trans_process(sixp_trans_t *trans);
76 static void free_trans(sixp_trans_t *trans);
77 static sixp_trans_mode_t determine_trans_mode(const sixp_pkt_t *req);
78 
80 LIST(trans_list);
81 
82 /*---------------------------------------------------------------------------*/
83 static void
84 handle_trans_timeout(void *ptr)
85 {
86  sixp_trans_t *trans = (sixp_trans_t *)ptr;
87 
88  assert(trans != NULL);
89  if(trans == NULL) {
90  return;
91  }
92 
93  if(trans->sf->timeout != NULL) {
94  trans->sf->timeout(trans->cmd,
95  (const linkaddr_t *)&trans->peer_addr);
96  }
97 
98  (void)sixp_trans_transit_state(trans, SIXP_TRANS_STATE_TERMINATING);
99 }
100 /*---------------------------------------------------------------------------*/
101 static void
102 start_trans_timer(sixp_trans_t *trans)
103 {
104  ctimer_set(&trans->timer, trans->sf->timeout_interval,
105  handle_trans_timeout, trans);
106 }
107 /*---------------------------------------------------------------------------*/
108 static void
109 process_trans(void *ptr)
110 {
111  sixp_trans_t *trans = (sixp_trans_t *)ptr;
112 
113  assert(trans != NULL);
114  if(trans == NULL) {
115  return;
116  }
117 
118  /* make sure that the timer is stopped */
119  ctimer_stop(&trans->timer);
120 
121  /* state-specific operation */
122  if(trans->state == SIXP_TRANS_STATE_TERMINATING) {
123  /* handle the terminating state first */
124  LOG_INFO("6P-trans: trans [peer_addr:");
125  LOG_INFO_LLADDR((const linkaddr_t *)&trans->peer_addr);
126  LOG_INFO_(", seqno:%u] is going to be freed\n", trans->seqno);
127  free_trans(trans);
128  return;
129  }
130 
131  switch(trans->state) {
132  /* do for others */
133  case SIXP_TRANS_STATE_RESPONSE_SENT:
134  case SIXP_TRANS_STATE_RESPONSE_RECEIVED:
135  if(trans->mode == SIXP_TRANS_MODE_2_STEP) {
136  (void)sixp_trans_transit_state(trans, SIXP_TRANS_STATE_TERMINATING);
137  }
138  break;
139  case SIXP_TRANS_STATE_CONFIRMATION_SENT:
140  case SIXP_TRANS_STATE_CONFIRMATION_RECEIVED:
141  (void)sixp_trans_transit_state(trans, SIXP_TRANS_STATE_TERMINATING);
142  break;
143  case SIXP_TRANS_STATE_TERMINATING:
144  default:
145  break;
146  }
147 
148  if(trans->state != SIXP_TRANS_STATE_TERMINATING) {
149  /* set the timer with a timeout values defined by the SF */
150  start_trans_timer(trans);
151  }
152 }
153 /*---------------------------------------------------------------------------*/
154 static void
155 schedule_trans_process(sixp_trans_t *trans)
156 {
157  assert(trans != NULL);
158  if(trans == NULL) {
159  return;
160  }
161 
162  ctimer_stop(&trans->timer);
163  ctimer_set(&trans->timer, 0, process_trans, trans); /* expires immediately */
164 }
165 /*---------------------------------------------------------------------------*/
166 static void
167 free_trans(sixp_trans_t *trans)
168 {
169  assert(trans != NULL);
170  if(trans == NULL) {
171  return;
172  }
173 
174  list_remove(trans_list, trans);
175  memb_free(&trans_memb, trans);
176 }
177 /*---------------------------------------------------------------------------*/
178 static sixp_trans_mode_t
179 determine_trans_mode(const sixp_pkt_t *req)
180 {
181  uint16_t cell_list_len;
182 
183  assert(req != NULL);
184  if(req == NULL) {
185  return SIXP_TRANS_MODE_UNAVAILABLE;
186  }
187 
188  /*
189  * We consider a transaction as 3-step if and only if its request command is
190  * either Add or Delete AND its cell_list is empty. Otherwise, 2-step.
191  */
192  if(req->type == SIXP_PKT_TYPE_REQUEST &&
193  (req->code.cmd == SIXP_PKT_CMD_ADD ||
194  req->code.cmd == SIXP_PKT_CMD_DELETE) &&
196  NULL, &cell_list_len,
197  req->body, req->body_len) == 0 &&
198  cell_list_len == 0) {
199  return SIXP_TRANS_MODE_3_STEP;
200  }
201 
202  return SIXP_TRANS_MODE_2_STEP;
203 }
204 /*---------------------------------------------------------------------------*/
205 int
207 {
208  sixp_nbr_t *nbr;
209 
210  assert(trans != NULL);
211  if(trans == NULL) {
212  LOG_ERR("6top: invalid argument, trans is NULL\n");
213  return -1;
214  }
215 
216  /* enforce state transition rules */
217  if(new_state == SIXP_TRANS_STATE_TERMINATING ||
218  (new_state == SIXP_TRANS_STATE_REQUEST_SENT &&
219  trans->state == SIXP_TRANS_STATE_INIT) ||
220  (new_state == SIXP_TRANS_STATE_REQUEST_RECEIVED &&
221  trans->state == SIXP_TRANS_STATE_INIT) ||
222  (new_state == SIXP_TRANS_STATE_RESPONSE_SENT &&
223  trans->state == SIXP_TRANS_STATE_REQUEST_RECEIVED) ||
224  (new_state == SIXP_TRANS_STATE_RESPONSE_RECEIVED &&
225  trans->state == SIXP_TRANS_STATE_REQUEST_SENT) ||
226  (new_state == SIXP_TRANS_STATE_CONFIRMATION_RECEIVED &&
227  trans->state == SIXP_TRANS_STATE_RESPONSE_SENT &&
228  trans->mode == SIXP_TRANS_MODE_3_STEP) ||
229  (new_state == SIXP_TRANS_STATE_CONFIRMATION_SENT &&
230  trans->state == SIXP_TRANS_STATE_RESPONSE_RECEIVED &&
231  trans->mode == SIXP_TRANS_MODE_3_STEP)) {
232  LOG_INFO("6P-trans: trans %p state changes from %u to %u\n",
233  trans, trans->state, new_state);
234 
235  if(new_state == SIXP_TRANS_STATE_REQUEST_SENT) {
236  /*
237  * that is, the request is acknowledged by the peer; increment
238  * next_seqno
239  */
240  if((nbr = sixp_nbr_find(&trans->peer_addr)) == NULL) {
241  LOG_ERR("6top: cannot increment next_seqno\n");
242  } else {
243  if(trans->cmd == SIXP_PKT_CMD_CLEAR) {
244  /* next_seqno must have been reset to 0 already. */
245  assert(sixp_nbr_get_next_seqno(nbr) == 0);
246  } else {
248  }
249  }
250  } else if(new_state == SIXP_TRANS_STATE_RESPONSE_SENT) {
251  if((nbr = sixp_nbr_find(&trans->peer_addr)) == NULL) {
252  LOG_ERR("6top: cannot update next_seqno\n");
253  } else {
254  /* override next_seqno with the received one unless it's zero */
255  if(trans->seqno != 0) {
256  sixp_nbr_set_next_seqno(nbr, trans->seqno);
257  }
259  }
260  }
261 
262  trans->state = new_state;
263  schedule_trans_process(trans);
264  return 0;
265  }
266 
267  /* invalid transition */
268  LOG_ERR("6P-trans: invalid transaction, from %u to %u, detected on trans %p\n",
269  trans->state, new_state, trans);
270  return -1;
271 }
272 /*---------------------------------------------------------------------------*/
275 {
276  assert(trans != NULL);
277  if(trans == NULL) {
279  }
280  return trans->cmd;
281 }
282 /*---------------------------------------------------------------------------*/
285 {
286  assert(trans != NULL);
287  if(trans == NULL) {
288  return SIXP_TRANS_STATE_UNAVAILABLE;
289  }
290  return trans->state;
291 }
292 /*---------------------------------------------------------------------------*/
293 int16_t
295 {
296  assert(trans != NULL);
297  if(trans == NULL) {
298  LOG_ERR("6P-trans: sixp_trans_get_seqno() fails because trans is NULL\n");
299  return -1;
300  }
301  return trans->seqno;
302 }
303 /*---------------------------------------------------------------------------*/
306 {
307  assert(trans != NULL);
308  if(trans == NULL) {
309  LOG_ERR("6P-trans: sixp_trans_get_mode() fails because trans is NULL\n");
310  return SIXP_TRANS_STATE_UNAVAILABLE;
311  }
312  return trans->mode;
313 }
314 /*---------------------------------------------------------------------------*/
315 void
317 {
318  assert(trans != NULL);
319 
320  if(trans == NULL || trans->callback.func == NULL) {
321  return;
322  }
323  trans->callback.func(trans->callback.arg, trans->callback.arg_len,
324  &trans->peer_addr, status);
325 }
326 /*---------------------------------------------------------------------------*/
327 void
329  sixp_sent_callback_t func, void *arg, uint16_t arg_len)
330 {
331  assert(trans != NULL);
332  if(trans == NULL) {
333  return;
334  }
335  trans->callback.func = func;
336  trans->callback.arg = arg;
337  trans->callback.arg_len = arg_len;
338 }
339 /*---------------------------------------------------------------------------*/
340 sixp_trans_t *
341 sixp_trans_alloc(const sixp_pkt_t *pkt, const linkaddr_t *peer_addr)
342 {
343  const sixtop_sf_t *sf;
344  sixp_trans_t *trans;
345 
346  assert(pkt != NULL && peer_addr != NULL);
347  if(pkt == NULL || peer_addr == NULL) {
348  LOG_ERR("6P-trans: sixp_trans_alloc() fails because of invalid argument\n");
349  return NULL;
350  }
351 
352  if((sf = sixtop_find_sf(pkt->sfid)) == NULL) {
353  LOG_ERR("6P-trans: sixp_trans_alloc() fails; no suitable SF [sfid:%u]\n",
354  pkt->sfid);
355  return NULL;
356  }
357 
358  if(sixp_trans_find(peer_addr) != NULL) {
359  LOG_ERR("6P-trans: sixp_trans_alloc() fails because another trans with ");
360  LOG_ERR_LLADDR((const linkaddr_t *)peer_addr);
361  LOG_ERR_("is in process\n");
362  return NULL;
363  }
364 
365  if((trans = memb_alloc(&trans_memb)) == NULL) {
366  LOG_ERR("6P-trans: sixp_trans_alloc() fails because of lack of memory\n");
367  return NULL;
368  }
369 
370  memset(trans, 0, sizeof(sixp_trans_t));
371  trans->sf = sf;
372  trans->peer_addr = *peer_addr;
373  trans->seqno = pkt->seqno;
374  trans->cmd = pkt->code.value;
375  trans->state = SIXP_TRANS_STATE_INIT;
376  trans->mode = determine_trans_mode(pkt);
377  list_add(trans_list, trans);
378  start_trans_timer(trans);
379 
380  return trans;
381 }
382 /*---------------------------------------------------------------------------*/
383 sixp_trans_t *
384 sixp_trans_find(const linkaddr_t *peer_addr)
385 {
386  sixp_trans_t *trans;
387 
388  assert(peer_addr != NULL);
389  if(peer_addr == NULL) {
390  return NULL;
391  }
392 
393  /*
394  * XXX: we don't support concurrent 6P transactions which is mentioned in
395  * Section 4.3.3, draft-ietf-6tisch-6top-protocol-03.
396  *
397  * The assumption here is that there is one transactions for a single peer at
398  * most.
399  */
400  for(trans = list_head(trans_list);
401  trans != NULL; trans = trans->next) {
402  if(memcmp(peer_addr, &trans->peer_addr, sizeof(linkaddr_t)) == 0) {
403  return trans;
404  }
405  }
406 
407  return NULL;
408 }
409 /*---------------------------------------------------------------------------*/
410 int
412 {
413  sixp_trans_t *trans, *next_trans;
414 
415  /* make sure there's no timer task left before the initialization */
416  for(trans = list_head(trans_list);
417  trans != NULL; trans = next_trans) {
418  next_trans = trans->next;
419  ctimer_stop(&trans->timer);
420  free_trans(trans);
421  }
422 
423  list_init(trans_list);
424  memb_init(&trans_memb);
425  return 0;
426 }
427 /*---------------------------------------------------------------------------*/
428 /** @} */
Transaction Management APIs for 6top Protocol (6P)
sixp_pkt_cmd_t
6P Command Identifiers
Definition: sixp-pkt.h:72
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:149
sixp_trans_mode_t
6P Transaction Modes (for internal use)
Definition: sixp-trans.h:62
struct sixp_nbr sixp_nbr_t
6P Neighbor Data Structure (for internal use)
int sixp_trans_init(void)
Initialize Memory and List for 6P transactions This function removes and frees existing transactions...
Definition: sixp-trans.c:411
/brief Scheduling Function Driver
Definition: sixtop.h:79
sixp_pkt_code_t code
Code.
Definition: sixp-pkt.h:124
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:106
CMD_CLEAR.
Definition: sixp-pkt.h:79
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:78
void sixp_trans_set_callback(sixp_trans_t *trans, sixp_sent_callback_t func, void *arg, uint16_t arg_len)
Set an output callback to a specified transaction.
Definition: sixp-trans.c:328
uint16_t body_len
The length of Other Fields.
Definition: sixp-pkt.h:128
uint8_t seqno
SeqNum.
Definition: sixp-pkt.h:126
const sixtop_sf_t * sixtop_find_sf(uint8_t sfid)
Find a SF which has been added by SFID.
Definition: sixtop.c:110
Neighbor Management APIs for 6top Protocol (6P)
void sixp_trans_invoke_callback(sixp_trans_t *trans, sixp_output_status_t status)
Invoke the output callback of a specified transaction.
Definition: sixp-trans.c:316
struct sixp_trans sixp_trans_t
6P Transaction Data Structure (for internal use)
A timer.
Definition: timer.h:82
int sixp_pkt_get_cell_list(sixp_pkt_type_t type, sixp_pkt_code_t code, const uint8_t **cell_list, sixp_pkt_offset_t *cell_list_len, const uint8_t *body, uint16_t body_len)
Read CellList in "Other Fields" of 6P packet.
Definition: sixp-pkt.c:608
int sixp_nbr_increment_next_seqno(sixp_nbr_t *nbr)
Increment the next sequence number of a neighbor.
Definition: sixp-nbr.c:156
uint8_t value
8-bit unsigned integer value
Definition: sixp-pkt.h:106
sixp_pkt_cmd_t sixp_trans_get_cmd(sixp_trans_t *trans)
Return the command associated with a specified transaction.
Definition: sixp-trans.c:274
6P Request
Definition: sixp-pkt.h:63
uint8_t sfid
SFID.
Definition: sixp-pkt.h:125
#define SIXTOP_MAX_TRANSACTIONS
The maximum number of transactions which the sixtop module can handle at the same time...
Definition: sixtop-conf.h:61
for internal use
Definition: sixp-pkt.h:80
6P Codes integrating Command IDs and Return Codes
Definition: sixp-pkt.h:103
sixp_trans_t * sixp_trans_find(const linkaddr_t *peer_addr)
Find a transaction.
Definition: sixp-trans.c:384
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
void(* sixp_sent_callback_t)(void *arg, uint16_t arg_len, const linkaddr_t *dest_addr, sixp_output_status_t status)
6P Packet Sent Handler
Definition: sixp.h:73
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
const uint8_t * body
Other Fields...
Definition: sixp-pkt.h:127
sixp_trans_state_t sixp_trans_get_state(sixp_trans_t *trans)
Return the state of a specified transaction.
Definition: sixp-trans.c:284
sixp_pkt_type_t type
Type.
Definition: sixp-pkt.h:123
CMD_DELETE.
Definition: sixp-pkt.h:74
6TiSCH Operation Sublayer (6top) APIs
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
void list_init(list_t list)
Initialize a list.
Definition: list.c:65
6top IE Structure
Definition: sixp-pkt.h:121
#define LIST(name)
Declare a linked list.
Definition: list.h:89
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
sixp_trans_state_t
6P Transaction States (for internal use)
Definition: sixp-trans.h:47
sixp_pkt_cmd_t cmd
6P Command Identifier
Definition: sixp-pkt.h:104
int16_t sixp_trans_get_seqno(sixp_trans_t *trans)
Return the sequence number associated with a specified transaction.
Definition: sixp-trans.c:294
int sixp_nbr_get_next_seqno(sixp_nbr_t *nbr)
Get the next sequence number of a neighbor.
Definition: sixp-nbr.c:121
sixp_nbr_t * sixp_nbr_find(const linkaddr_t *addr)
Find a neighbor.
Definition: sixp-nbr.c:70
sixp_output_status_t
6P Send Status, which represents sixp_output() result.
Definition: sixp.h:65
sixp_trans_t * sixp_trans_alloc(const sixp_pkt_t *pkt, const linkaddr_t *peer_addr)
Allocate a transaction.
Definition: sixp-trans.c:341
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
int sixp_nbr_set_next_seqno(sixp_nbr_t *nbr, uint16_t seqno)
Set the specified value to the next sequence number of a neighbor.
Definition: sixp-nbr.c:132
int sixp_trans_transit_state(sixp_trans_t *trans, sixp_trans_state_t new_state)
Change the state of a specified transaction.
Definition: sixp-trans.c:206
Header file for the logging system
CMD_ADD.
Definition: sixp-pkt.h:73
sixp_trans_mode_t sixp_trans_get_mode(sixp_trans_t *trans)
Return the mode, 2-step or 3-step, of a specified transaction.
Definition: sixp-trans.c:305
6top Configuration
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:237
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:90