Contiki-NG
sixp.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  * 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 "sixp-nbr.h"
46 #include "sixp-pkt.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 static void mac_callback(void *ptr, int status, int transmissions);
55 static int send_back_error(sixp_pkt_type_t type, sixp_pkt_code_t code,
56  uint8_t sfid, uint8_t seqno,
57  const linkaddr_t *dest_addr);
58 /*---------------------------------------------------------------------------*/
59 static void
60 mac_callback(void *ptr, int status, int transmissions)
61 {
62  sixp_trans_t *trans = (sixp_trans_t *)ptr;
63  sixp_trans_state_t new_state, current_state;
64 
65  assert(trans != NULL);
66  if(trans == NULL) {
67  LOG_ERR("6P: mac_callback() fails because trans is NULL\n");
68  return;
69  }
70 
71  current_state = sixp_trans_get_state(trans);
72  if(status == MAC_TX_OK) {
73  switch(current_state) {
74  case SIXP_TRANS_STATE_INIT:
75  new_state = SIXP_TRANS_STATE_REQUEST_SENT;
76  break;
77  case SIXP_TRANS_STATE_REQUEST_RECEIVED:
78  new_state = SIXP_TRANS_STATE_RESPONSE_SENT;
79  break;
80  case SIXP_TRANS_STATE_RESPONSE_RECEIVED:
81  new_state = SIXP_TRANS_STATE_CONFIRMATION_SENT;
82  break;
83  default:
84  LOG_ERR("6P: mac_callback() fails because of an unexpected state (%u)\n",
85  current_state);
86  return;
87  }
88  } else {
89  /*
90  * In a case of transmission failure of a request, a corresponding SF would
91  * retransmit the request with a new transaction. For a response or a
92  * confirmation, the same transaction will be used for retransmission as
93  * long as it doesn't have timeout.
94  */
95  if(current_state == SIXP_TRANS_STATE_INIT) {
96  /* request case */
97  new_state = SIXP_TRANS_STATE_TERMINATING;
98  } else {
99  /* response or confirmation case: stay the same state */
100  new_state = current_state;
101  }
102  }
103 
104  if(new_state != current_state &&
105  sixp_trans_transit_state(trans, new_state) != 0) {
106  LOG_ERR("6P: mac_callback() fails because of state transition failure\n");
107  LOG_ERR("6P: something wrong; we're terminating the trans %p\n", trans);
108  (void)sixp_trans_transit_state(trans, SIXP_TRANS_STATE_TERMINATING);
109  return;
110  }
111 
113  status == MAC_TX_OK ?
116  sixp_trans_set_callback(trans, NULL, NULL, 0);
117 }
118 /*---------------------------------------------------------------------------*/
119 static int
120 send_back_error(sixp_pkt_type_t type, sixp_pkt_code_t code,
121  uint8_t sfid, uint8_t seqno,
122  const linkaddr_t *dest_addr)
123 {
124  /* create a 6P packet within packetbuf */
125  if(sixp_pkt_create(type, code, sfid, seqno, NULL, 0, NULL) < 0) {
126  LOG_ERR("6P: failed to create a 6P packet to return an error [rc:%u]\n",
127  code.value);
128  return -1;
129  }
130  /* we don't care about how the transmission goes; no need to set callback */
131  sixtop_output(dest_addr, NULL, NULL);
132  return 0;
133 }
134 /*---------------------------------------------------------------------------*/
135 void
136 sixp_input(const uint8_t *buf, uint16_t len, const linkaddr_t *src_addr)
137 {
138  sixp_pkt_t pkt;
139  sixp_trans_t *trans;
140  sixp_nbr_t *nbr;
141  const sixtop_sf_t *sf;
142  int16_t seqno;
143  int ret;
144 
145  assert(buf != NULL && src_addr != NULL);
146  if(buf == NULL || src_addr == NULL) {
147  return;
148  }
149 
150  if(sixp_pkt_parse(buf, len, &pkt) < 0) {
151  if(pkt.version != SIXP_PKT_VERSION) {
152  LOG_ERR("6P: sixp_input() unsupported version %u\n", pkt.version);
153  if(send_back_error(SIXP_PKT_TYPE_RESPONSE,
155  pkt.sfid, pkt.seqno,
156  src_addr) < 0) {
157  LOG_ERR("6P: sixp_input() fails to send RC_ERR_VERSION\n");
158  return;
159  }
160  }
161  LOG_ERR("6P: sixp_input() fails because of a malformed 6P packet\n");
162  return;
163  }
164 
165  if(pkt.type != SIXP_PKT_TYPE_REQUEST &&
166  pkt.type != SIXP_PKT_TYPE_RESPONSE &&
168  LOG_ERR("6P: sixp_input() fails because of unsupported type [type:%u]\n",
169  pkt.type);
170  return;
171  }
172 
173  if((sf = sixtop_find_sf(pkt.sfid)) == NULL) {
174  LOG_ERR("6P: sixp_input() fails because SF [sfid:%u] is unavailable\n",
175  pkt.sfid);
176  /*
177  * XXX: what if the incoming packet is a response? confirmation should be
178  * sent back?
179  */
180  if(send_back_error(SIXP_PKT_TYPE_RESPONSE,
182  pkt.sfid, pkt.seqno, src_addr) < 0) {
183  LOG_ERR("6P: sixp_input() fails to return an error response\n");
184  };
185  return;
186  }
187 
188  /* Transaction Management */
189  trans = sixp_trans_find(src_addr);
190 
191  if(pkt.type == SIXP_PKT_TYPE_REQUEST) {
192  if(trans != NULL) {
193  /* Error: not supposed to have another transaction with the peer. */
194  LOG_ERR("6P: sixp_input() fails because another request [peer_addr:");
195  LOG_ERR_LLADDR((const linkaddr_t *)src_addr);
196  LOG_ERR_(" seqno:%u] is in process\n", sixp_trans_get_seqno(trans));
197  if(send_back_error(SIXP_PKT_TYPE_RESPONSE,
199  pkt.sfid, pkt.seqno, src_addr) < 0) {
200  LOG_ERR("6P: sixp_input() fails to return an error response");
201  }
202  return;
203  }
204 
205  if((pkt.code.cmd == SIXP_PKT_CMD_CLEAR) &&
206  (nbr = sixp_nbr_find(src_addr)) != NULL) {
207  LOG_INFO("6P: sixp_input() reset nbr's next_seqno by CLEAR Request\n");
209  }
210 
211  if((trans = sixp_trans_alloc(&pkt, src_addr)) == NULL) {
212  LOG_ERR("6P: sixp_input() fails because of lack of memory\n");
213  if(send_back_error(SIXP_PKT_TYPE_RESPONSE,
215  pkt.sfid, pkt.seqno, src_addr) < 0) {
216  LOG_ERR("6P: sixp_input() fails to return an error response\n");
217  }
218  return;
219  }
220 
221  /* Inconsistency Management */
222  if(pkt.code.cmd != SIXP_PKT_CMD_CLEAR &&
223  (((nbr = sixp_nbr_find(src_addr)) == NULL &&
224  (pkt.seqno != 0)) ||
225  ((nbr != NULL) &&
226  (sixp_nbr_get_next_seqno(nbr) != 0) &&
227  pkt.seqno == 0))) {
228  if(trans != NULL) {
230  SIXP_TRANS_STATE_REQUEST_RECEIVED);
231 
232  }
233  if(send_back_error(SIXP_PKT_TYPE_RESPONSE,
235  pkt.sfid,
236  nbr == NULL ? 0 : sixp_nbr_get_next_seqno(nbr),
237  src_addr) < 0) {
238  LOG_ERR("6P: sixp_input() fails to return an error response\n");
239  }
240  return;
241  }
242 
243  } else if(pkt.type == SIXP_PKT_TYPE_RESPONSE ||
245  if(trans == NULL) {
246  /* Error: should have a transaction for incoming packet */
247  LOG_ERR("6P: sixp_input() fails because of no trans [peer_addr:");
248  LOG_ERR_LLADDR((const linkaddr_t *)src_addr);
249  LOG_ERR_("]\n");
250  return;
251  } else if((seqno = sixp_trans_get_seqno(trans)) < 0 ||
252  seqno != pkt.seqno) {
253  LOG_ERR("6P: sixp_input() fails because of invalid seqno [seqno:%u, %u]\n",
254  seqno, pkt.seqno);
255  return;
256  }
257  }
258 
259  /* state transition */
260  assert(trans != NULL);
261  switch(pkt.type) {
263  ret = sixp_trans_transit_state(trans,
264  SIXP_TRANS_STATE_REQUEST_RECEIVED);
265  break;
267  ret = sixp_trans_transit_state(trans,
268  SIXP_TRANS_STATE_RESPONSE_RECEIVED);
269  break;
271  ret = sixp_trans_transit_state(trans,
272  SIXP_TRANS_STATE_CONFIRMATION_RECEIVED);
273  break;
274  default:
275  LOG_ERR("6P: sixp_input() fails because of unsupported type [type:%u]\n",
276  pkt.type);
277  return;
278  }
279  if(ret < 0) {
280  LOG_ERR("6P: sixp_input() fails because of state transition failure\n");
281  LOG_ERR("6P: something wrong; we're terminating the trans %p\n", trans);
282  (void)sixp_trans_transit_state(trans, SIXP_TRANS_STATE_TERMINATING);
283  return;
284  }
285 
286  if(sf->input != NULL) {
287  sf->input(pkt.type, pkt.code, pkt.body, pkt.body_len, src_addr);
288  }
289 
290  return;
291 }
292 /*---------------------------------------------------------------------------*/
293 int
294 sixp_output(sixp_pkt_type_t type, sixp_pkt_code_t code, uint8_t sfid,
295  const uint8_t *body, uint16_t body_len,
296  const linkaddr_t *dest_addr,
297  sixp_sent_callback_t func, void *arg, uint16_t arg_len)
298 {
299  sixp_trans_t *trans;
300  sixp_nbr_t *nbr;
301  sixp_pkt_cmd_t cmd;
302  int16_t seqno;
303  sixp_pkt_t pkt;
304 
305  assert(dest_addr != NULL);
306 
307  /* validate the state of a transaction with a specified peer */
308  trans = sixp_trans_find(dest_addr);
309  if(type == SIXP_PKT_TYPE_REQUEST) {
310  if(trans != NULL) {
311  LOG_ERR("6P: sixp_output() fails because another trans for [peer_addr:");
312  LOG_ERR_LLADDR((const linkaddr_t *)dest_addr);
313  LOG_ERR_("] is in process\n");
314  return -1;
315  } else {
316  /* ready to send a request */
317  /* we're going to allocate a new transaction later */
318  }
319  } else if(type == SIXP_PKT_TYPE_RESPONSE) {
320  if(trans == NULL) {
321  LOG_ERR("6P: sixp_output() fails because of no transaction [peer_addr:");
322  LOG_ERR_LLADDR((const linkaddr_t *)dest_addr);
323  LOG_ERR_("]\n");
324  return -1;
325  } else if(sixp_trans_get_state(trans) !=
326  SIXP_TRANS_STATE_REQUEST_RECEIVED) {
327  LOG_ERR("6P: sixp_output() fails because of invalid transaction state\n");
328  return -1;
329  } else {
330  /* ready to send a response */
331  }
332  } else if(type == SIXP_PKT_TYPE_CONFIRMATION) {
333  if(trans == NULL) {
334  LOG_ERR("6P: sixp_output() fails because of no transaction [peer_addr:");
335  LOG_ERR_LLADDR((const linkaddr_t *)dest_addr);
336  LOG_ERR_("]\n");
337  return -1;
338  } else if(sixp_trans_get_state(trans) !=
339  SIXP_TRANS_STATE_RESPONSE_RECEIVED) {
340  LOG_ERR("6P: sixp_output() fails because of invalid transaction state\n");
341  return -1;
342  } else {
343  /* ready to send a confirmation */
344  }
345  } else {
346  LOG_ERR("6P: sixp_output() fails because of unsupported type [type:%u]\n",
347  type);
348  return -1;
349  }
350 
351  nbr = sixp_nbr_find(dest_addr);
352 
353  /*
354  * Make sure we have a nbr for the peer if the packet is a response with
355  * success so that we can manage the schedule generation.
356  */
357  if(nbr == NULL &&
358  type == SIXP_PKT_TYPE_RESPONSE && code.value == SIXP_PKT_RC_SUCCESS &&
359  ((cmd = sixp_trans_get_cmd(trans)) == SIXP_PKT_CMD_ADD ||
360  cmd == SIXP_PKT_CMD_DELETE) &&
361  (nbr = sixp_nbr_alloc(dest_addr)) == NULL) {
362  LOG_ERR("6P: sixp_output() fails because of no memory for another nbr\n");
363  return -1;
364  }
365 
366  /* set SeqNum */
367  if(type == SIXP_PKT_TYPE_REQUEST) {
368  if(nbr == NULL &&
369  (nbr = sixp_nbr_alloc(dest_addr)) == NULL) {
370  LOG_ERR("6P: sixp_output() fails because it fails to allocate a nbr\n");
371  return -1;
372  }
373  if((seqno = sixp_nbr_get_next_seqno(nbr)) < 0){
374  LOG_ERR("6P: sixp_output() fails to get the next sequence number\n");
375  return -1;
376  }
377  if(code.cmd == SIXP_PKT_CMD_CLEAR) {
378  LOG_INFO("6P: sixp_output() reset nbr's next_seqno by CLEAR Request\n");
380  }
381  } else {
382  assert(trans != NULL);
383  if((seqno = sixp_trans_get_seqno(trans)) < 0) {
384  LOG_ERR("6P: sixp_output() fails because it fails to get seqno\n");
385  return -1;
386  }
387  }
388 
389  /* create a 6P packet within packetbuf */
390  if(sixp_pkt_create(type, code, sfid,
391  (uint8_t)seqno,
392  body, body_len,
393  type == SIXP_PKT_TYPE_REQUEST ? &pkt : NULL) < 0) {
394  LOG_ERR("6P: sixp_output() fails to create a 6P packet\n");
395  return -1;
396  }
397 
398  /* allocate a transaction for a sending request */
399  if(type == SIXP_PKT_TYPE_REQUEST) {
400  assert(trans == NULL);
401  if((trans = sixp_trans_alloc(&pkt, dest_addr)) == NULL) {
402  LOG_ERR("6P: sixp_output() is aborted because of no memory\n");
403  return -1;
404  } else {
405  /* ready for proceed */
406  }
407  }
408 
409  assert(trans != NULL);
410  sixp_trans_set_callback(trans, func, arg, arg_len);
411  sixtop_output(dest_addr, mac_callback, trans);
412 
413  return 0;
414 }
415 /*---------------------------------------------------------------------------*/
416 void
418 {
419  sixp_nbr_init();
420  sixp_trans_init();
421 }
422 /*---------------------------------------------------------------------------*/
423 /** @} */
Transaction Management APIs for 6top Protocol (6P)
sixp_pkt_cmd_t
6P Command Identifiers
Definition: sixp-pkt.h:72
sixp_pkt_type_t
6P Message Types
Definition: sixp-pkt.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 sixp_nbr_reset_next_seqno(sixp_nbr_t *nbr)
Reset the next sequence number of a neighbor to zero.
Definition: sixp-nbr.c:144
RC_ERR_SFID.
Definition: sixp-pkt.h:92
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)
uint8_t value
8-bit unsigned integer value
Definition: sixp-pkt.h:106
The MAC layer transmission was OK.
Definition: mac.h:87
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
RC_ERR_BUSY.
Definition: sixp-pkt.h:95
uint8_t sfid
SFID.
Definition: sixp-pkt.h:125
sixtop_sf_input input
Input Handler.
Definition: sixtop.h:83
6P Codes integrating Command IDs and Return Codes
Definition: sixp-pkt.h:103
6P Response
Definition: sixp-pkt.h:64
sixp_trans_t * sixp_trans_find(const linkaddr_t *peer_addr)
Find a transaction.
Definition: sixp-trans.c:384
RC_SUCCESS.
Definition: sixp-pkt.h:87
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
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
void sixtop_output(const linkaddr_t *dest_addr, mac_callback_t callback, void *arg)
Output a 6P packet which is supposestored in packetbuf.
Definition: sixtop.c:125
sixp_pkt_type_t type
Type.
Definition: sixp-pkt.h:123
RC_ERR_VERSION.
Definition: sixp-pkt.h:91
sixp_nbr_t * sixp_nbr_alloc(const linkaddr_t *addr)
Allocate a neighbor.
Definition: sixp-nbr.c:80
CMD_DELETE.
Definition: sixp-pkt.h:74
6TiSCH Operation Sublayer (6top) APIs
int sixp_output(sixp_pkt_type_t type, sixp_pkt_code_t code, uint8_t sfid, const uint8_t *body, uint16_t body_len, const linkaddr_t *dest_addr, sixp_sent_callback_t func, void *arg, uint16_t arg_len)
Output a 6P packet.
Definition: sixp.c:294
6P Confirmation
Definition: sixp-pkt.h:65
void sixp_init(void)
Initialize 6P Module It invokes sixp_nbr_init() and sixp_trans_init().
Definition: sixp.c:417
6top IE Structure
Definition: sixp-pkt.h:121
6top Protocol (6P) Packet Manipulation APIs
int sixp_nbr_init(void)
Initialize 6p Neighbor Table.
Definition: sixp-nbr.c:175
int sixp_pkt_parse(const uint8_t *buf, uint16_t len, sixp_pkt_t *pkt)
Parse a 6P packet.
Definition: sixp-pkt.c:947
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
int sixp_pkt_create(sixp_pkt_type_t type, sixp_pkt_code_t code, uint8_t sfid, uint8_t seqno, const uint8_t *body, uint16_t body_len, sixp_pkt_t *pkt)
Create a 6P packet.
Definition: sixp-pkt.c:1081
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 sixp_input(const uint8_t *buf, uint16_t len, const linkaddr_t *src_addr)
Input a 6P packet.
Definition: sixp.c:136
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
RC_ERR_SEQNUM.
Definition: sixp-pkt.h:93
Header file for the logging system
CMD_ADD.
Definition: sixp-pkt.h:73
sixp_pkt_version_t version
Version.
Definition: sixp-pkt.h:122