sixtop: support draft-ietf-6tisch-6top-protocol-07

This commit is contained in:
Yasuyuki Tanaka 2017-07-10 11:36:24 +09:00
parent a5fadb2ebe
commit 7530c560c5
11 changed files with 1939 additions and 396 deletions

View File

@ -59,38 +59,11 @@ typedef struct sixp_nbr {
struct sixp_nbr *next;
linkaddr_t addr;
uint8_t next_seqno;
uint8_t gtx;
uint8_t grx;
uint8_t gen;
} sixp_nbr_t;
static int advance_generation_counter(uint8_t *gc);
NBR_TABLE(sixp_nbr_t, sixp_nbrs);
/*---------------------------------------------------------------------------*/
static int
advance_generation_counter(uint8_t *gc)
{
assert(gc != NULL);
if(gc == NULL) {
return -1;
}
switch(*gc) {
case 0x00:
case 0x02:
*gc = 0x01;
break;
case 0x01:
*gc = 0x02;
break;
default:
/* unexpected condition */
PRINTF("6P-nbr: advance_generation_counter() has unexpected gc %02x\n",
*gc);
return -1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
sixp_nbr_t *
sixp_nbr_find(const linkaddr_t *addr)
@ -130,8 +103,7 @@ sixp_nbr_alloc(const linkaddr_t *addr)
linkaddr_copy(&nbr->addr, addr);
nbr->next_seqno = SIXP_INITIAL_SEQUENCE_NUMBER;
nbr->gtx = 0;
nbr->grx = 0;
nbr->gen = 0;
return nbr;
}
@ -146,47 +118,36 @@ sixp_nbr_free(sixp_nbr_t *nbr)
}
/*---------------------------------------------------------------------------*/
int16_t
sixp_nbr_get_gtx(sixp_nbr_t *nbr)
sixp_nbr_get_gen(sixp_nbr_t *nbr)
{
assert(nbr != NULL);
if(nbr == NULL) {
PRINTF("6P-nbr: sixp_nbr_get_gtx() fails because of invalid argument\n");
return -1;
}
return nbr->gtx;
}
/*---------------------------------------------------------------------------*/
int8_t
sixp_nbr_get_grx(sixp_nbr_t *nbr)
{
assert(nbr != NULL);
if(nbr == NULL) {
PRINTF("6P-nbr: sixp_nbr_get_grx() fails because of invalid argument\n");
return -1;
}
return nbr->grx;
return nbr->gen;
}
/*---------------------------------------------------------------------------*/
int
sixp_nbr_advance_gtx(sixp_nbr_t *nbr)
sixp_nbr_advance_gen(sixp_nbr_t *nbr)
{
assert(nbr != NULL);
if(nbr == NULL) {
PRINTF("6P-nbr: sixp_nbr_advance_gtx() fails because of invalid arg\n");
PRINTF("6P-nbr: sixp_nbr_advance_gen() fails because of invalid arg\n");
return -1;
}
return advance_generation_counter(&nbr->gtx);
}
/*---------------------------------------------------------------------------*/
int
sixp_nbr_advance_grx(sixp_nbr_t *nbr)
{
assert(nbr != NULL);
if(nbr == NULL) {
PRINTF("6P-nbr: sixp_nbr_advance_grx() fails because of invalid arg\n");
if(nbr->gen == 0x00 || nbr->gen == 0x09) {
nbr->gen = 0x01;
} else if(nbr->gen < 0x09) {
nbr->gen++;
} else {
/* unexpected condition */
PRINTF("6P-nbr: nbr %p has an invalid generation number %02x\n",
nbr, nbr->gen);
return -1;
}
return advance_generation_counter(&nbr->grx);
return 0;
}
/*---------------------------------------------------------------------------*/
int

View File

@ -63,33 +63,18 @@ sixp_nbr_t *sixp_nbr_alloc(const linkaddr_t *addr);
void sixp_nbr_free(sixp_nbr_t *nbr);
/**
* \brief Return GTX of a neighbor
* \brief Return GEN (Generation Number) of a neighbor
* \param nbr The pointer to a neighbor
* \return A value of GTX, -1 on failure
* \return A value of GEN, -1 on failure
*/
int16_t sixp_nbr_get_gtx(sixp_nbr_t *nbr);
/**
* \brief Return GRX of a neighbor
* \param nbr The pointer to a neighbor
* \return A value of GRX
*/
int16_t sixp_nbr_get_grx(sixp_nbr_t *nbr);
int16_t sixp_nbr_get_gen(sixp_nbr_t *nbr);
/**
* \brief Advance GTX of a neighbor
* \param nbr The pointer to a neighbor
* \return 0 on success, -1 on failure
*/
int sixp_nbr_advance_gtx(sixp_nbr_t *nbr);
/**
* \brief Advance GRX of a neighbor
* \param nbr The pointer to a neighbor
* \return 0 on success, -1 on failure
*/
int sixp_nbr_advance_grx(sixp_nbr_t *nbr);
int sixp_nbr_advance_gen(sixp_nbr_t *nbr);
/**
* \brief Get the next sequence number of a neighbor

View File

@ -61,6 +61,11 @@ static int32_t get_offset_offset(sixp_pkt_type_t type, sixp_pkt_code_t code);
static int32_t get_max_num_cells_offset(sixp_pkt_type_t type,
sixp_pkt_code_t code);
static int32_t get_cell_list_offset(sixp_pkt_type_t type, sixp_pkt_code_t code);
static int32_t get_rel_cell_list_offset(sixp_pkt_type_t type,
sixp_pkt_code_t code);
static int32_t get_total_num_cells_offset(sixp_pkt_type_t type,
sixp_pkt_code_t code);
/*---------------------------------------------------------------------------*/
static int32_t
get_metadata_offset(sixp_pkt_type_t type, sixp_pkt_code_t code)
@ -77,7 +82,8 @@ get_cell_options_offset(sixp_pkt_type_t type, sixp_pkt_code_t code)
if(type == SIXP_PKT_TYPE_REQUEST &&
(code.cmd == SIXP_PKT_CMD_ADD ||
code.cmd == SIXP_PKT_CMD_DELETE ||
code.cmd == SIXP_PKT_CMD_STATUS ||
code.cmd == SIXP_PKT_CMD_RELOCATE ||
code.cmd == SIXP_PKT_CMD_COUNT ||
code.cmd == SIXP_PKT_CMD_LIST)) {
return sizeof(sixp_pkt_metadata_t);
}
@ -88,11 +94,10 @@ static int32_t
get_num_cells_offset(sixp_pkt_type_t type, sixp_pkt_code_t code)
{
if(type == SIXP_PKT_TYPE_REQUEST &&
(code.value == SIXP_PKT_CMD_ADD || code.value == SIXP_PKT_CMD_DELETE)) {
(code.value == SIXP_PKT_CMD_ADD ||
code.value == SIXP_PKT_CMD_DELETE ||
code.value == SIXP_PKT_CMD_RELOCATE)) {
return sizeof(sixp_pkt_metadata_t) + sizeof(sixp_pkt_cell_options_t);
} else if(type == SIXP_PKT_TYPE_RESPONSE &&
code.value == SIXP_PKT_RC_SUCCESS) {
return 0;
}
return -1;
@ -143,13 +148,33 @@ get_cell_list_offset(sixp_pkt_type_t type, sixp_pkt_code_t code)
sizeof(sixp_pkt_num_cells_t));
} else if((type == SIXP_PKT_TYPE_RESPONSE ||
type == SIXP_PKT_TYPE_CONFIRMATION) &&
code.value == SIXP_PKT_RC_SUCCESS) {
(code.value == SIXP_PKT_RC_SUCCESS ||
code.value == SIXP_PKT_RC_EOL)) {
return 0;
}
return -1;
}
/*---------------------------------------------------------------------------*/
int
static int32_t
get_rel_cell_list_offset(sixp_pkt_type_t type, sixp_pkt_code_t code)
{
if(type == SIXP_PKT_TYPE_REQUEST && code.value == SIXP_PKT_CMD_RELOCATE) {
return (sizeof(sixp_pkt_metadata_t) +
sizeof(sixp_pkt_cell_options_t) +
sizeof(sixp_pkt_num_cells_t));
}
return -1;
}
/*---------------------------------------------------------------------------*/
static int32_t
get_total_num_cells_offset(sixp_pkt_type_t type, sixp_pkt_code_t code)
{
if(type == SIXP_PKT_TYPE_RESPONSE && code.value == SIXP_PKT_RC_SUCCESS) {
return 0;
}
return -1;
}
/*---------------------------------------------------------------------------*/int
sixp_pkt_set_metadata(sixp_pkt_type_t type, sixp_pkt_code_t code,
sixp_pkt_metadata_t metadata,
uint8_t *body, uint16_t body_len)
@ -294,13 +319,7 @@ sixp_pkt_set_num_cells(sixp_pkt_type_t type, sixp_pkt_code_t code,
return -1;
}
if(body_len < (offset + sizeof(num_cells))) {
PRINTF("6P-pkt: cannot set num_cells; body is too short\n");
return -1;
}
/* NumCells is an 8-bit unsigned integer */
memcpy(body + offset, &num_cells, sizeof(num_cells));
memcpy(body + offset, &num_cells, sizeof(uint8_t));
return 0;
}
@ -549,7 +568,7 @@ sixp_pkt_set_cell_list(sixp_pkt_type_t type, sixp_pkt_code_t code,
return -1;
}
offset += cell_offset * sizeof(sixp_pkt_cell_t);
offset += cell_offset;
if(body_len < (offset + cell_list_len)) {
PRINTF("6P-pkt: cannot set cell_list; body is too short\n");
@ -560,6 +579,7 @@ sixp_pkt_set_cell_list(sixp_pkt_type_t type, sixp_pkt_code_t code,
}
memcpy(body + offset, cell_list, cell_list_len);
return 0;
}
/*---------------------------------------------------------------------------*/
@ -572,7 +592,7 @@ sixp_pkt_get_cell_list(sixp_pkt_type_t type, sixp_pkt_code_t code,
int32_t offset;
if(cell_list_len == NULL || body == NULL) {
PRINTF("6P-pkt: cannot get cell_list; invalid argument\n");
PRINTF("6P-pkt: cannot get cell_list\n");
return -1;
}
@ -596,6 +616,242 @@ sixp_pkt_get_cell_list(sixp_pkt_type_t type, sixp_pkt_code_t code,
}
*cell_list_len = body_len - offset;
return 0;
}
/*---------------------------------------------------------------------------*/
int
sixp_pkt_set_rel_cell_list(sixp_pkt_type_t type, sixp_pkt_code_t code,
const uint8_t *rel_cell_list,
uint16_t rel_cell_list_len,
uint16_t cell_offset,
uint8_t *body, uint16_t body_len)
{
int32_t offset;
sixp_pkt_num_cells_t num_cells;
if(rel_cell_list == NULL || body == NULL) {
PRINTF("6P-pkt: cannot set rel_cell_list; invalid argument\n");
return -1;
}
if(sixp_pkt_get_num_cells(type, code, &num_cells, body, body_len) < 0) {
PRINTF("6P-pkt: cannot set rel_cell_list; no NumCells field\n");
return -1;
}
if((offset = get_rel_cell_list_offset(type, code)) < 0) {
PRINTF("6P-pkt: cannot set rel_cell_list; ");
PRINTF("packet [type=%u, code=%u] won't have RelCellList\n",
type, code.value);
return -1;
}
offset += cell_offset;
if(body_len < (offset + rel_cell_list_len)) {
PRINTF("6P-pkt: cannot set rel_cell_list; body is too short\n");
return -1;
} else if((offset + rel_cell_list_len) >
(offset + num_cells * sizeof(sixp_pkt_cell_t))) {
PRINTF("6P-pkt: cannot set rel_cell_list; RelCellList is too long\n");
return -1;
} else if((rel_cell_list_len % sizeof(sixp_pkt_cell_t)) != 0) {
PRINTF("6P-pkt: cannot set rel_cell_list; invalid body_len\n");
return -1;
}
memcpy(body + offset, rel_cell_list, rel_cell_list_len);
return 0;
}
/*---------------------------------------------------------------------------*/
int
sixp_pkt_get_rel_cell_list(sixp_pkt_type_t type, sixp_pkt_code_t code,
const uint8_t **rel_cell_list,
sixp_pkt_offset_t *rel_cell_list_len,
const uint8_t *body, uint16_t body_len)
{
int32_t offset;
sixp_pkt_num_cells_t num_cells;
if(rel_cell_list_len == NULL || body == NULL) {
PRINTF("6P-pkt: cannot get rel_cell_list; invalid argument\n");
return -1;
}
if(sixp_pkt_get_num_cells(type, code, &num_cells, body, body_len) < 0) {
PRINTF("6P-pkt: cannot get rel_cell_list; no NumCells field\n");
return -1;
}
if((offset = get_rel_cell_list_offset(type, code)) < 0) {
PRINTF("6P-pkt: cannot get rel_cell_list; ");
PRINTF("packet [type=%u, code=%u] won't have RelCellList\n",
type, code.value);
return -1;
}
if(body_len < (offset + (num_cells * sizeof(sixp_pkt_cell_t)))) {
PRINTF("6P-pkt: cannot set rel_cell_list; body is too short\n");
return -1;
} else if(((body_len - offset) % sizeof(sixp_pkt_cell_t)) != 0) {
PRINTF("6P-pkt: cannot set rel_cell_list; invalid body_len\n");
return -1;
}
if(rel_cell_list != NULL) {
*rel_cell_list = body + offset;
}
*rel_cell_list_len = num_cells * sizeof(sixp_pkt_cell_t);
return 0;
}
/*---------------------------------------------------------------------------*/
int
sixp_pkt_set_cand_cell_list(sixp_pkt_type_t type, sixp_pkt_code_t code,
const uint8_t *cand_cell_list,
uint16_t cand_cell_list_len,
uint16_t cell_offset,
uint8_t *body, uint16_t body_len)
{
int32_t offset;
sixp_pkt_num_cells_t num_cells;
if(cand_cell_list == NULL || body == NULL) {
PRINTF("6P-pkt: cannot set cand_cell_list; invalid argument\n");
return -1;
}
if(sixp_pkt_get_num_cells(type, code, &num_cells, body, body_len) < 0) {
PRINTF("6P-pkt: cannot set cand_cell_list; no NumCells field\n");
return -1;
}
if((offset = get_rel_cell_list_offset(type, code)) < 0) {
PRINTF("6P-pkt: cannot set cand_cell_list; ");
PRINTF("packet [type=%u, code=%u] won't have RelCellList\n",
type, code.value);
return -1;
}
offset += cell_offset + num_cells * sizeof(sixp_pkt_cell_t);
if(body_len < (offset + cand_cell_list_len)) {
PRINTF("6P-pkt: cannot set cand_cell_list; body is too short\n");
return -1;
} else if((cand_cell_list_len % sizeof(sixp_pkt_cell_t)) != 0) {
PRINTF("6P-pkt: cannot set cand_cell_list; invalid body_len\n");
return -1;
}
memcpy(body + offset, cand_cell_list, cand_cell_list_len);
return 0;
}
/*---------------------------------------------------------------------------*/
int
sixp_pkt_get_cand_cell_list(sixp_pkt_type_t type, sixp_pkt_code_t code,
const uint8_t **cand_cell_list,
sixp_pkt_offset_t *cand_cell_list_len,
const uint8_t *body, uint16_t body_len)
{
int32_t offset;
sixp_pkt_num_cells_t num_cells;
if(cand_cell_list_len == NULL || body == NULL) {
PRINTF("6P-pkt: cannot get cand_cell_list; invalid argument\n");
return -1;
}
if(sixp_pkt_get_num_cells(type, code, &num_cells, body, body_len) < 0) {
PRINTF("6P-pkt: cannot get cand_cell_list; no NumCells field\n");
return -1;
}
if((offset = get_rel_cell_list_offset(type, code)) < 0) {
PRINTF("6P-pkt: cannot get cand_cell_list; ");
PRINTF("packet [type=%u, code=%u] won't have RelCellList\n",
type, code.value);
return -1;
}
offset += num_cells * sizeof(sixp_pkt_cell_t);
if(body_len < offset) {
PRINTF("6P-pkt: cannot set cand_cell_list; body is too short\n");
return -1;
} else if(((body_len - offset) % sizeof(sixp_pkt_cell_t)) != 0) {
PRINTF("6P-pkt: cannot set cand_cell_list; invalid body_len\n");
return -1;
}
if(cand_cell_list != NULL) {
*cand_cell_list = body + offset;
}
*cand_cell_list_len = body_len - offset;
return 0;
}
/*---------------------------------------------------------------------------*/
int
sixp_pkt_set_total_num_cells(sixp_pkt_type_t type, sixp_pkt_code_t code,
sixp_pkt_total_num_cells_t total_num_cells,
uint8_t *body, uint16_t body_len)
{
int32_t offset;
if(body == NULL) {
PRINTF("6P-pkt: cannot set num_cells; body is null\n");
return -1;
}
if((offset = get_total_num_cells_offset(type, code)) < 0) {
PRINTF("6P-pkt: cannot set total_num_cells; ");
PRINTF("packet [type=%u, code=%u] won't have TotalNumCells\n",
type, code.value);
return -1;
}
/*
* TotalNumCells for 6P Response is a 16-bit unsigned integer, little-endian.
*/
body[offset] = (uint8_t)(total_num_cells & 0xff);
body[offset + 1] = (uint8_t)(total_num_cells >> 8);
return 0;
}
/*---------------------------------------------------------------------------*/
int
sixp_pkt_get_total_num_cells(sixp_pkt_type_t type, sixp_pkt_code_t code,
sixp_pkt_total_num_cells_t *total_num_cells,
const uint8_t *body, uint16_t body_len)
{
int32_t offset;
if(total_num_cells == NULL || body == NULL) {
PRINTF("6P-pkt: cannot get num_cells; invalid argument\n");
return -1;
}
if((offset = get_total_num_cells_offset(type, code)) < 0) {
PRINTF("6P-pkt: cannot get num_cells; ");
PRINTF("packet [type=%u, code=%u] won't have TotalNumCells\n",
type, code.value);
return -1;
}
if(body_len < (offset + sizeof(sixp_pkt_total_num_cells_t))) {
PRINTF("6P-pkt: cannot get num_cells; body is too short\n");
return -1;
}
/* TotalNumCells is a 16-bit unsigned integer, little-endian. */
*total_num_cells = body[0];
*total_num_cells += ((uint16_t)body[1]) << 8;
return 0;
}
/*---------------------------------------------------------------------------*/
@ -626,8 +882,7 @@ sixp_pkt_parse(const uint8_t *buf, uint16_t len,
pkt->code.value = buf[1];
pkt->sfid = buf[2];
pkt->seqno = buf[3] & 0x0f;
pkt->gab = (buf[3] & 0x30) >> 4;
pkt->gba = (buf[3] & 0xc0) >> 6;
pkt->gen = (buf[3] & 0xf0) >> 4;
buf += 4;
len -= 4;
@ -649,7 +904,16 @@ sixp_pkt_parse(const uint8_t *buf, uint16_t len,
return -1;
}
break;
case SIXP_PKT_CMD_STATUS:
case SIXP_PKT_CMD_RELOCATE:
if(len < (sizeof(sixp_pkt_metadata_t) +
sizeof(sixp_pkt_cell_options_t) +
sizeof(sixp_pkt_num_cells_t)) ||
(len % sizeof(uint32_t)) != 0) {
PRINTF("6P-pkt: sixp_pkt_parse() fails because of invalid length\n");
return -1;
}
break;
case SIXP_PKT_CMD_COUNT:
if(len != (sizeof(sixp_pkt_metadata_t) +
sizeof(sixp_pkt_cell_options_t))) {
PRINTF("6P-pkt: sixp_pkt_parse() fails because of invalid length\n");
@ -683,23 +947,30 @@ sixp_pkt_parse(const uint8_t *buf, uint16_t len,
/*
* The "Other Field" contains
* - Res to CLEAR: Empty (length 0)
* - Res to STATUS: "Num. Cells"
* - Res to STATUS: "Num. Cells" (total_num_cells)
* - Res to ADD, DELETE, LIST: 0, 1, or multiple 6P cells
*/
if(len != 0 &&
len != sizeof(sixp_pkt_num_cells_t) &&
len != sizeof(sixp_pkt_total_num_cells_t) &&
(len % sizeof(uint32_t)) != 0) {
PRINTF("6P-pkt: sixp_pkt_parse() fails because of invalid length\n");
return -1;
}
break;
case SIXP_PKT_RC_ERR_VER:
case SIXP_PKT_RC_ERR_SFID:
case SIXP_PKT_RC_ERR_GEN:
case SIXP_PKT_RC_ERR_BUSY:
case SIXP_PKT_RC_ERR_NORES:
case SIXP_PKT_RC_ERR_RESET:
case SIXP_PKT_RC_ERR:
case SIXP_PKT_RC_EOL:
if((len % sizeof(uint32_t)) != 0) {
PRINTF("6P-pkt: sixp_pkt_parse() fails because of invalid length\n");
return -1;
}
break;
case SIXP_PKT_RC_ERROR:
case SIXP_PKT_RC_RESET:
case SIXP_PKT_RC_VERSION:
case SIXP_PKT_RC_SFID:
case SIXP_PKT_RC_GEN:
case SIXP_PKT_RC_BUSY:
case SIXP_PKT_RC_NORES:
case SIXP_PKT_RC_CELLLIST:
if(len != 0) {
PRINTF("6P-pkt: sixp_pkt_parse() fails because of invalid length\n");
return -1;
@ -722,7 +993,7 @@ sixp_pkt_parse(const uint8_t *buf, uint16_t len,
/*---------------------------------------------------------------------------*/
int
sixp_pkt_create(sixp_pkt_type_t type, sixp_pkt_code_t code,
uint8_t sfid, uint8_t seqno, uint8_t gab, uint8_t gba,
uint8_t sfid, uint8_t seqno, uint8_t gen,
const uint8_t *body, uint16_t body_len, sixp_pkt_t *pkt)
{
uint8_t *hdr;
@ -753,7 +1024,7 @@ sixp_pkt_create(sixp_pkt_type_t type, sixp_pkt_code_t code,
hdr[0] = (type << 4) | SIXP_PKT_VERSION;
hdr[1] = code.value;
hdr[2] = sfid;
hdr[3] = (gab << 4) | (gba << 6) | seqno;
hdr[3] = (gen << 4) | seqno;
/* data: write body */
if(body_len > 0 && body != NULL) {
@ -767,8 +1038,7 @@ sixp_pkt_create(sixp_pkt_type_t type, sixp_pkt_code_t code,
pkt->code = code;
pkt->sfid = sfid;
pkt->seqno = seqno;
pkt->gab = gab;
pkt->gba = gba;
pkt->gen = gen;
pkt->body = body;
pkt->body_len = body_len;
}

View File

@ -43,7 +43,7 @@
#ifndef _SIXTOP_6P_PACKET_H_
#define _SIXTOP_6P_PACKET_H_
#define SIXP_PKT_VERSION 0x01
#define SIXP_PKT_VERSION 0x00
/* typedefs for code readability */
typedef uint8_t sixp_pkt_cell_options_t;
@ -53,6 +53,7 @@ typedef uint16_t sixp_pkt_metadata_t;
typedef uint16_t sixp_pkt_max_num_cells_t;
typedef uint16_t sixp_pkt_offset_t;
typedef uint32_t sixp_pkt_cell_t;
typedef uint16_t sixp_pkt_total_num_cells_t;
/**
* \brief 6P Message Types
@ -70,24 +71,27 @@ typedef enum {
typedef enum {
SIXP_PKT_CMD_ADD = 0x01, /**< CMD_ADD */
SIXP_PKT_CMD_DELETE = 0x02, /**< CMD_DELETE */
SIXP_PKT_CMD_STATUS = 0x03, /**< CMD_STATUS */
SIXP_PKT_CMD_LIST = 0x04, /**< CMD_LIST */
SIXP_PKT_CMD_CLEAR = 0x05, /**< CMD_CLEAR */
SIXP_PKT_CMD_UNAVAILABLE /**< for internal use */
SIXP_PKT_CMD_RELOCATE = 0x03, /**< CMD_STATUS */
SIXP_PKT_CMD_COUNT = 0x04, /**< CMD_STATUS */
SIXP_PKT_CMD_LIST = 0x05, /**< CMD_LIST */
SIXP_PKT_CMD_CLEAR = 0x06, /**< CMD_CLEAR */
SIXP_PKT_CMD_UNAVAILABLE = 0xff, /**< for internal use */
} sixp_pkt_cmd_t;
/**
* \brief 6P Return Codes
*/
typedef enum {
SIXP_PKT_RC_SUCCESS = 0x06, /**< RC_SUCCESS */
SIXP_PKT_RC_ERR_VER = 0x07, /**< RC_ERR_VER */
SIXP_PKT_RC_ERR_SFID = 0x08, /**< RC_ERR_SFID */
SIXP_PKT_RC_ERR_GEN = 0x09, /**< RC_ERR_GEN */
SIXP_PKT_RC_ERR_BUSY = 0x0a, /**< RC_ERR_BUSY */
SIXP_PKT_RC_ERR_NORES = 0x0b, /**< RC_ERR_NORES */
SIXP_PKT_RC_ERR_RESET = 0x0c, /**< RC_ERR_RESET */
SIXP_PKT_RC_ERR = 0x0d, /**< RC_ERR */
SIXP_PKT_RC_SUCCESS = 0x00, /**< RC_SUCCESS */
SIXP_PKT_RC_ERROR = 0x01, /**< RC_ERROR */
SIXP_PKT_RC_EOL = 0x02, /**< RC_EOL */
SIXP_PKT_RC_RESET = 0x03, /**< RC_RESET */
SIXP_PKT_RC_VERSION = 0x04, /**< RC_ERR_VER */
SIXP_PKT_RC_SFID = 0x05, /**< RC_ERR_SFID */
SIXP_PKT_RC_GEN = 0x06, /**< RC_ERR_GEN */
SIXP_PKT_RC_BUSY = 0x07, /**< RC_ERR_BUSY */
SIXP_PKT_RC_NORES = 0x08, /**< RC_ERR_NORES */
SIXP_PKT_RC_CELLLIST = 0x09, /**< RC_ERR_CELLLIST */
} sixp_pkt_rc_t;
/**
@ -116,8 +120,7 @@ typedef struct {
sixp_pkt_code_t code; /**< Code */
uint8_t sfid; /**< SFID */
uint8_t seqno; /**< SeqNum */
uint8_t gab; /**< GAB */
uint8_t gba; /**< GBA */
uint8_t gen; /**< GEN */
const uint8_t *body; /**< Other Fields... */
uint16_t body_len; /**< The length of Other Fields */
} sixp_pkt_t;
@ -426,8 +429,7 @@ int sixp_pkt_parse(const uint8_t *buf, uint16_t len,
* \param code 6P Message Code, Command Identifier or Return Code
* \param sfid Scheduling Function Identifier
* \param seqno Sequence Number
* \param gab GAB
* \param gba GBA
* \param gen GEN
* \param body The pointer to "Other Fields" in a buffer
* \param body_len The length of body, typically "Other Fields" length
* \param pkt The pointer to a sixp_pkt_t structure to store packet info
@ -435,7 +437,7 @@ int sixp_pkt_parse(const uint8_t *buf, uint16_t len,
* \return 0 on success, -1 on failure
*/
int sixp_pkt_create(sixp_pkt_type_t type, sixp_pkt_code_t code,
uint8_t sfid, uint8_t seqno, uint8_t gab, uint8_t gba,
uint8_t sfid, uint8_t seqno, uint8_t gen,
const uint8_t *body, uint16_t body_len,
sixp_pkt_t *pkt);

View File

@ -120,9 +120,7 @@ send_back_error(sixp_pkt_type_t type, sixp_pkt_code_t code,
const linkaddr_t *dest_addr)
{
/* create a 6P packet within packetbuf */
/* XXX: set 0 as GAB and GBA for a error response */
/* XXX: how can we make a confirmation having an error return value? */
if(sixp_pkt_create(type, code, sfid, seqno, 0, 0, NULL, 0, NULL) < 0) {
if(sixp_pkt_create(type, code, sfid, seqno, 0, NULL, 0, NULL) < 0) {
PRINTF("6P: failed to create a 6P packet to return an error [rc:%u]\n",
code.value);
return -1;
@ -141,6 +139,7 @@ sixp_input(const uint8_t *buf, uint16_t len, const linkaddr_t *src_addr)
sixp_trans_t *trans;
const sixtop_sf_t *sf;
int16_t seqno;
int16_t gen;
int ret;
assert(buf != NULL && src_addr != NULL);
@ -169,7 +168,7 @@ sixp_input(const uint8_t *buf, uint16_t len, const linkaddr_t *src_addr)
* sent back?
*/
if(send_back_error(SIXP_PKT_TYPE_RESPONSE,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_RC_ERR_SFID,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_RC_SFID,
pkt.sfid, pkt.seqno, src_addr) < 0) {
PRINTF("6P: sixp_input() fails to return an error response\n");
};
@ -182,22 +181,20 @@ sixp_input(const uint8_t *buf, uint16_t len, const linkaddr_t *src_addr)
/* Not need to validate generation counters in a case of CMD_CLEAR */
invalid_schedule_generation = 0;
} else if(nbr == NULL) {
if(pkt.gab == 0 && pkt.gba == 0) {
if(pkt.gen == 0) {
invalid_schedule_generation = 0; /* valid combination */
} else {
PRINTF("6P: GAB/GBA should be 0 because of no corresponding nbr\n");
PRINTF("6P: GEN should be 0 because of no corresponding nbr\n");
invalid_schedule_generation = 1;
}
} else {
PRINTF("6P: GAB: %u, GBA: %u, GTX: %u, GRX: %u\n",
pkt.gab, pkt.gba, sixp_nbr_get_grx(nbr), sixp_nbr_get_gtx(nbr));
if(((pkt.type == SIXP_PKT_TYPE_REQUEST ||
pkt.type == SIXP_PKT_TYPE_CONFIRMATION) &&
pkt.gab == sixp_nbr_get_grx(nbr) &&
pkt.gba == sixp_nbr_get_gtx(nbr)) ||
(pkt.type == SIXP_PKT_TYPE_RESPONSE &&
pkt.gab == sixp_nbr_get_gtx(nbr) &&
pkt.gba == sixp_nbr_get_grx(nbr))) {
if((gen = sixp_nbr_get_gen(nbr)) < 0) {
PRINTF("6P: unexpected error; cannot get our GEN\n");
return;
}
PRINTF("6P: received GEN %u, our GEN: %u\n",
pkt.gen, sixp_nbr_get_gen(nbr));
if(pkt.gen == gen) {
invalid_schedule_generation = 0; /* valid combination */
} else {
invalid_schedule_generation = 1;
@ -218,7 +215,7 @@ sixp_input(const uint8_t *buf, uint16_t len, const linkaddr_t *src_addr)
PRINTLLADDR((const uip_lladdr_t *)src_addr);
PRINTF(" seqno:%u] is in process\n", sixp_trans_get_seqno(trans));
if(send_back_error(SIXP_PKT_TYPE_RESPONSE,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_RC_ERR_BUSY,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_RC_BUSY,
pkt.sfid, pkt.seqno, src_addr) < 0) {
PRINTF("6P: sixp_input() fails to return an error response");
}
@ -226,7 +223,7 @@ sixp_input(const uint8_t *buf, uint16_t len, const linkaddr_t *src_addr)
} else if((trans = sixp_trans_alloc(&pkt, src_addr)) == NULL) {
PRINTF("6P: sixp_input() fails because of lack of memory\n");
if(send_back_error(SIXP_PKT_TYPE_RESPONSE,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_RC_ERR_NORES,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_RC_NORES,
pkt.sfid, pkt.seqno, src_addr) < 0) {
PRINTF("6P: sixp_input() fails to return an error response\n");
}
@ -291,7 +288,7 @@ sixp_output(sixp_pkt_type_t type, sixp_pkt_code_t code, uint8_t sfid,
sixp_trans_t *trans;
sixp_nbr_t *nbr;
sixp_pkt_cmd_t cmd;
int16_t seqno, gab, gba;
int16_t seqno, gen;
sixp_pkt_t pkt;
assert(dest_addr != NULL);
@ -378,31 +375,17 @@ sixp_output(sixp_pkt_type_t type, sixp_pkt_code_t code, uint8_t sfid,
}
}
/* set GAB and GBA */
/* set GEN */
if(nbr == NULL) {
gab = gba = 0;
} else {
if(type == SIXP_PKT_TYPE_REQUEST ||
type == SIXP_PKT_TYPE_CONFIRMATION) {
gab = sixp_nbr_get_gtx(nbr);
gba = sixp_nbr_get_grx(nbr);
} else if(type == SIXP_PKT_TYPE_RESPONSE) {
gba = sixp_nbr_get_gtx(nbr);
gab = sixp_nbr_get_grx(nbr);
} else {
/* never come here */
PRINTF("6P: sixp_output() fails because of an unexpected condition\n");
return -1;
}
}
if(gab < 0 || gba < 0) {
PRINTF("6P: sixp_output() fails to get GAB or GBA\n");
gen = 0;
} else if((gen = sixp_nbr_get_gen(nbr)) < 0) {
PRINTF("6P: sixp_output() fails to get GEN\n");
return -1;
}
/* create a 6P packet within packetbuf */
if(sixp_pkt_create(type, code, sfid,
(uint8_t)seqno, (uint8_t)gab, (uint8_t)gba,
(uint8_t)seqno, (uint8_t)gen,
body, body_len,
type == SIXP_PKT_TYPE_REQUEST ? &pkt : NULL) < 0) {
PRINTF("6P: sixp_output() fails to create a 6P packet\n");

View File

@ -141,7 +141,7 @@ sixtop_output(const linkaddr_t *dest_addr, mac_callback_t callback, void *arg)
return;
}
p = packetbuf_hdrptr();
p[0] = SIXP_SUBIE_ID;
p[0] = SIXTOP_SUBIE_ID;
/*
* prepend Payload IE header; 2 octets
@ -234,6 +234,7 @@ sixtop_input(void)
*/
assert(frame.fcf.frame_version == FRAME802154_IEEE802154_2015);
assert(frame.fcf.frame_type == FRAME802154_DATAFRAME);
memset(&ies, 0, sizeof(ies));
if(frame.fcf.ie_list_present &&
frame802154e_parse_information_elements(payload_ptr,
payload_len, &ies) >= 0 &&

View File

@ -50,6 +50,8 @@
#include "sixp-pkt.h"
#define SIXTOP_SUBIE_ID 0xc9
/**
* \brief Input Handler of Scheduling Function
* \param type 6P Message Type of an input packet

View File

@ -103,9 +103,9 @@ UNIT_TEST(test_alloc_and_free)
UNIT_TEST_END();
}
UNIT_TEST_REGISTER(test_gtx_management,
"test GTX Management");
UNIT_TEST(test_gtx_management)
UNIT_TEST_REGISTER(test_gen_management,
"test GEN Management");
UNIT_TEST(test_gen_management)
{
sixp_nbr_t *nbr;
@ -113,43 +113,37 @@ UNIT_TEST(test_gtx_management)
test_setup();
UNIT_TEST_ASSERT((nbr = sixp_nbr_alloc(&peer_addr_1)) != NULL);
UNIT_TEST_ASSERT(sixp_nbr_get_gtx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x00);
UNIT_TEST_ASSERT(sixp_nbr_advance_gtx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gtx(nbr) == 0x01);
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x01);
UNIT_TEST_ASSERT(sixp_nbr_advance_gtx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gtx(nbr) == 0x02);
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x02);
UNIT_TEST_ASSERT(sixp_nbr_advance_gtx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gtx(nbr) == 0x01);
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x03);
UNIT_TEST_ASSERT(sixp_nbr_advance_gtx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gtx(nbr) == 0x02);
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x04);
UNIT_TEST_END();
}
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x05);
UNIT_TEST_REGISTER(test_grx_management,
"test GRX Management");
UNIT_TEST(test_grx_management)
{
sixp_nbr_t *nbr;
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x06);
UNIT_TEST_BEGIN();
test_setup();
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x07);
UNIT_TEST_ASSERT((nbr = sixp_nbr_alloc(&peer_addr_1)) != NULL);
UNIT_TEST_ASSERT(sixp_nbr_get_grx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x08);
UNIT_TEST_ASSERT(sixp_nbr_advance_grx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_grx(nbr) == 0x01);
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x09);
UNIT_TEST_ASSERT(sixp_nbr_advance_grx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_grx(nbr) == 0x02);
UNIT_TEST_ASSERT(sixp_nbr_advance_grx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_grx(nbr) == 0x01);
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_get_gen(nbr) == 0x01);
UNIT_TEST_END();
}
@ -211,10 +205,8 @@ PROCESS_THREAD(test_process, ev, data)
/* alloc / free */
UNIT_TEST_RUN(test_alloc_and_free);
/* GTX */
UNIT_TEST_RUN(test_gtx_management);
/* GRX */
UNIT_TEST_RUN(test_grx_management);
/* GEN */
UNIT_TEST_RUN(test_gen_management);
/* next sequence number */
UNIT_TEST_RUN(test_next_seqno);

File diff suppressed because it is too large Load Diff

View File

@ -93,7 +93,7 @@ UNIT_TEST(test_input_no_sf)
memset(&body, 0, sizeof(body));
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
UNKNOWN_SF_SFID, 10, 0, 0,
UNKNOWN_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
NULL) == 0);
UNIT_TEST_ASSERT(test_mac_send_function_is_called() == 0);
@ -113,9 +113,9 @@ UNIT_TEST(test_input_no_sf)
UNIT_TEST_ASSERT(p[3] == 0xa8);
/* 6top IE */
UNIT_TEST_ASSERT(p[4] == 0x00);
UNIT_TEST_ASSERT(p[5] == 0x11);
UNIT_TEST_ASSERT(p[6] == 0x08);
UNIT_TEST_ASSERT(p[4] == 0xc9);
UNIT_TEST_ASSERT(p[5] == 0x10);
UNIT_TEST_ASSERT(p[6] == 0x05);
UNIT_TEST_ASSERT(p[7] == UNKNOWN_SF_SFID);
UNIT_TEST_ASSERT(p[8] == 0x0a);
@ -152,7 +152,7 @@ UNIT_TEST(test_input_busy)
memset(&body, 0, sizeof(body));
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 0, 0,
TEST_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
NULL) == 0);
UNIT_TEST_ASSERT(test_mac_send_function_is_called() == 0);
@ -172,9 +172,9 @@ UNIT_TEST(test_input_busy)
UNIT_TEST_ASSERT(p[3] == 0xa8);
/* 6top IE */
UNIT_TEST_ASSERT(p[4] == 0x00);
UNIT_TEST_ASSERT(p[5] == 0x11);
UNIT_TEST_ASSERT(p[6] == 0x0a);
UNIT_TEST_ASSERT(p[4] == 0xc9);
UNIT_TEST_ASSERT(p[5] == 0x10);
UNIT_TEST_ASSERT(p[6] == 0x07);
UNIT_TEST_ASSERT(p[7] == TEST_SF_SFID);
UNIT_TEST_ASSERT(p[8] == 0x0a);
@ -201,7 +201,7 @@ UNIT_TEST(test_input_no_memory)
memset(&body, 0, sizeof(body));
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 0, 0,
TEST_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
&pkt) == 0);
memset(&addr, 0, sizeof(addr));
@ -230,9 +230,9 @@ UNIT_TEST(test_input_no_memory)
UNIT_TEST_ASSERT(p[3] == 0xa8);
/* 6top IE */
UNIT_TEST_ASSERT(p[4] == 0x00);
UNIT_TEST_ASSERT(p[5] == 0x11);
UNIT_TEST_ASSERT(p[6] == 0x0b);
UNIT_TEST_ASSERT(p[4] == 0xc9);
UNIT_TEST_ASSERT(p[5] == 0x10);
UNIT_TEST_ASSERT(p[6] == 0x08);
UNIT_TEST_ASSERT(p[7] == TEST_SF_SFID);
UNIT_TEST_ASSERT(p[8] == 0x0a);
@ -257,24 +257,21 @@ UNIT_TEST(test_input_schedule_generation)
memset(&body, 0, sizeof(body));
UNIT_TEST_ASSERT((nbr = sixp_nbr_alloc(&peer_addr)) != NULL);
/* nbr has GTX 0 and GRX 0 now */
/* nbr has GEN 0 now */
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 1, 1,
TEST_SF_SFID, 10, 1,
(const uint8_t *)&body, sizeof(body),
NULL) == 0);
sixp_input(packetbuf_hdrptr(), packetbuf_totlen(), &peer_addr);
UNIT_TEST_ASSERT(test_sf_input_is_called == 0);
UNIT_TEST_ASSERT(sixp_nbr_advance_gtx(nbr) == 0);
sixp_input(packetbuf_hdrptr(), packetbuf_totlen(), &peer_addr);
UNIT_TEST_ASSERT(test_sf_input_is_called == 0);
UNIT_TEST_ASSERT(sixp_nbr_advance_grx(nbr) == 0);
UNIT_TEST_ASSERT(sixp_nbr_advance_gen(nbr) == 0);
sixp_input(packetbuf_hdrptr(), packetbuf_totlen(), &peer_addr);
UNIT_TEST_ASSERT(test_sf_input_is_called == 1);
UNIT_TEST_ASSERT((trans = sixp_trans_find(&peer_addr)) != NULL);
UNIT_TEST_ASSERT(sixp_trans_get_state(trans) ==
SIXP_TRANS_STATE_REQUEST_RECEIVED);
@ -297,7 +294,7 @@ UNIT_TEST(test_output_request_1)
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 0, 0,
TEST_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
&pkt) == 0);
UNIT_TEST_ASSERT((trans = sixp_trans_alloc(&pkt, &peer_addr)) != NULL);
@ -363,7 +360,7 @@ UNIT_TEST(test_output_response_2)
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 0, 0,
TEST_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
&pkt) == 0);
UNIT_TEST_ASSERT((trans = sixp_trans_alloc(&pkt, &peer_addr)) != NULL);
@ -391,7 +388,7 @@ UNIT_TEST(test_output_response_3)
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 0, 0,
TEST_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
&pkt) == 0);
UNIT_TEST_ASSERT((trans = sixp_trans_alloc(&pkt, &peer_addr)) != NULL);
@ -421,7 +418,7 @@ UNIT_TEST(test_output_response_4)
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 0, 0,
TEST_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
&pkt) == 0);
UNIT_TEST_ASSERT((trans = sixp_trans_alloc(&pkt, &peer_addr)) != NULL);
@ -470,7 +467,7 @@ UNIT_TEST(test_output_confirmation_2)
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 0, 0,
TEST_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
&pkt) == 0);
UNIT_TEST_ASSERT((trans = sixp_trans_alloc(&pkt, &peer_addr)) != NULL);
@ -498,7 +495,7 @@ UNIT_TEST(test_output_confirmation_3)
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 0, 0,
TEST_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
&pkt) == 0);
UNIT_TEST_ASSERT((trans = sixp_trans_alloc(&pkt, &peer_addr)) != NULL);
@ -530,7 +527,7 @@ UNIT_TEST(test_output_confirmation_4)
UNIT_TEST_ASSERT(sixp_pkt_create(SIXP_PKT_TYPE_REQUEST,
(sixp_pkt_code_t)(uint8_t)SIXP_PKT_CMD_ADD,
TEST_SF_SFID, 10, 0, 0,
TEST_SF_SFID, 10, 0,
(const uint8_t *)&body, sizeof(body),
&pkt) == 0);
UNIT_TEST_ASSERT((trans = sixp_trans_alloc(&pkt, &peer_addr)) != NULL);

View File

@ -206,7 +206,7 @@ UNIT_TEST(test_output)
UNIT_TEST_ASSERT(p[3] == 0xa8);
/* 6top IE Sub-ID */
UNIT_TEST_ASSERT(p[4] == 0x00);
UNIT_TEST_ASSERT(p[4] == 0xc9);
/* test data set above */
UNIT_TEST_ASSERT(p[5] == 0xca);
UNIT_TEST_ASSERT(p[6] == 0xfe);