mbed-os/source/Core/include/ns_buffer.h

411 lines
16 KiB
C

/*
* Copyright (c) 2008-2019, Arm Limited and affiliates.
* 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.
*/
/**
*
* \file buffer.h
* \brief buffer type definitions.
*
* nanoStack: buffer carrier structure.
*
*/
#ifndef _NS_BUFFER_H
#define _NS_BUFFER_H
#ifndef _NANOSTACK_SOURCE_CONFIG_H
#error "Why haven't you included config.h before all other headers?"
#endif
#include "ns_types.h"
#include "Core/include/ns_address_internal.h"
#include "NWK_INTERFACE/Include/protocol_abstract.h"
#include "ns_list.h"
#include "ipv6_stack/ipv6_routing_table.h"
#ifndef BUFFERS_MAX
#define BUFFERS_MAX 10
#endif
#ifndef BUFFER_SIZE
#define BUFFER_SIZE 128
#endif
#ifndef ACK_BUFFER_SIZE
#define ACK_BUFFER_SIZE 5
#endif
/*
* headroom given to buffers by default.
* if buffer value is below 107 bytes then remaining value is allocated as headroom.
*/
#define BUFFER_DEFAULT_HEADROOM 40
/*
* default minimum size for buffers.
* if size is below this then extra space is allocated as headroom.
*/
#define BUFFER_DEFAULT_MIN_SIZE 127
/* The new, really-configurable default hop limit (RFC 4861 CurHopLimit);
* this can be overridden at compile-time, or changed on a per-socket basis
* with socket_setsockopt. It can also be overridden by Router Advertisements.
*/
#ifndef UNICAST_HOP_LIMIT_DEFAULT
#define UNICAST_HOP_LIMIT_DEFAULT 64
#endif
typedef enum {
B_SECURITY_KEY_ID_MODE_DEFAULT = 0,
B_SECURITY_KEY_ID_2,
B_SECURITY_KEY_ID_IMPLICIT,
} buffer_security_key_id_mode;
/** link-specific buffer data */
typedef struct buffer_link_ieee802_15_4 {
bool fc_security: 1; // Security Enabled flag from frame control
bool ack_fc_frame_pending: 1; // Frame Pending flag that was transmitted in Ack for this frame (used in Data Request)
bool useDefaultPanId: 1; // Transmit to broadcast PAN ID (0xffff)
bool indirectTxProcess: 1;
bool requestAck: 1;
bool rf_channel_switch: 1;
buffer_security_key_id_mode key_id_mode;
uint8_t selected_channel;
uint32_t indirectTTL;
uint16_t srcPanId;
uint16_t dstPanId;
} buffer_link_ieee802_15_4_t;
typedef union buffer_link_info {
buffer_link_ieee802_15_4_t ieee802_15_4;
} buffer_link_info_t;
/* Flags to indicate presence of extension headers in _current_ IP layer */
/* (As opposed to, eg, rpl_option, which is any-layer metadata) */
/* Placed as a non-bitfield in ip_extflags so that IP core can bulk clear */
#define IPEXT_HBH_RPL 0x01 /*!< RPL hop-by-hop option */
#define IPEXT_SRH_RPL 0x02 /*!< RPL Routing Header */
#define IPEXT_HBH_ROUTER_ALERT 0x04 /*!< Router alert */
#define IPEXT_HBH_MPL 0x08 /*!< MPL hop-by-hop option */
#define IPEXT_HBH_MPL_UNFILLED 0x10 /*!< MPL option is unfilled */
#define IPEXT_FRAGMENT 0x20 /*!< Fragment header present - if set on entry to IP parsing this was reassembled packet */
/** buffer option fields */
typedef struct buffer_options {
uint8_t lqi; /*!< LQI from RF */
int8_t dbm; /*!< Signal level */
uint8_t hop_limit; /*!< IPv6 hop limit */
uint8_t type; /*!< ICMP type, IP next header, MAC frame type... */
uint8_t code; /*!< ICMP code, TCP flags, MAC ack request... */
uint8_t ip_extflags; /*!< IPv6 extension header flags */
bool ll_security_bypass_tx: 1; /*!< Tx without link-layer security */
bool ll_sec_bypass_frag_deny: 1; /*!< Deny ll_security_bypass_tx usage in fragmented packets */
bool ll_security_bypass_rx: 1; /*!< Was received without link-layer security, when security was enabled */
bool ll_broadcast_tx: 1; /*!< Tx as link-layer broadcast (set to override multicast-as-unicast) */
bool ll_broadcast_rx: 1; /*!< Was received as link-layer broadcast */
bool ll_multicast_rx: 1; /*!< Was received as link-layer multicast */
bool ll_not_ours_rx: 1; /*!< Not addressed to us at link layer - snooped */
bool lowpan_mesh_rx: 1; /*!< Had a 6LoWPAN mesh header */
bool tunnelled: 1; /*!< We tunnelled it as part of (RPL?) routing */
bool need_predecessor: 1; /*!< Used as an indicator that predecessor address needed */
bool multicast_loop: 1; /*!< We want loopback if we're a group member (TX), or this IS the loopback if RX */
bool mpl_permitted: 1; /*!< MPL will be used if enabled on interface and scope >=3 */
bool edfe_mode: 1; /*!< Use Extended Directed Frame Exchange pattern in MAC layer */
#ifndef NO_IP_FRAGMENT_TX
bool ipv6_dontfrag: 1; /*!< Don't IPv6 fragment (RFC 3542) */
#endif
#ifndef NO_IPV6_PMTUD
signed ipv6_use_min_mtu: 2; /*!< Use minimum 1280-byte MTU (RFC 3542) - three settings +1, 0, -1 */
#endif
uint8_t traffic_class; /*!< Traffic class */
int_least24_t flow_label; /*!< IPv6 flow label; -1 means unspecified (may auto-generate); -2 means auto-generate required */
} buffer_options_t;
#define IPV6_FLOW_UNSPECIFIED (-1)
#define IPV6_FLOW_AUTOGENERATE (-2)
typedef enum {
B_TO_NONE = 0x0000,
B_TO_MAC = 0x0001,
B_TO_IPV6 = 0x0002,
B_TO_UDP = 0x0003,
B_TO_ICMP = 0x0004,
B_TO_NAP = 0x0005,
B_TO_FRAGMENTATION = 0x0006,
B_TO_TCP = 0x0007,
B_TO_MLME = 0x0008,
B_TO_IPV6_TXRX = 0x0009,
B_TO_DNSSD = 0x000A,
B_TO_IPV6_FWD = 0x000B,
B_TO_TLS = 0x000C,
B_TO_MESH_ROUTING = 0x000D,
B_TO_PHY = 0x000E,
B_TO_APP = 0x000F,
B_TO_MASK = 0x000F,
B_FROM_NONE = 0x0000,
B_FROM_MAC = 0x0010,
B_FROM_IPV6 = 0x0020,
B_FROM_UDP = 0x0030,
B_FROM_ICMP = 0x0040,
B_FROM_NAP = 0x0050,
B_FROM_FRAGMENTATION = 0x0060,
B_FROM_TCP = 0x0070,
B_FROM_MLME = 0x0080,
B_FROM_IPV6_TXRX = 0x0090,
B_FROM_DNSSD = 0x00A0,
B_FROM_IPV6_FWD = 0x00B0,
B_FROM_LOCAL = 0x00C0,
B_FROM_MESH_ROUTING = 0x00D0,
B_FROM_APP = 0x00F0,
B_FROM_MASK = 0x00F0,
B_DIR_DOWN = 0x0000,
B_DIR_UP = 0x0800,
B_DIR_MASK = 0x0800,
} buffer_info_t;
typedef enum {
QOS_NORMAL = 0,
QOS_HIGH = 1,
QOS_NETWORK_CTRL = 2,
QOS_EXPEDITE_FORWARD = 3,
QOS_MAC_BEACON = 4
} buffer_priority_t;
#define B_TO_MAC_MLME_MASK (B_DIR_MASK + B_FROM_MASK + B_TO_MASK )
#define B_TO_MAC_FROM_MAC (B_DIR_UP + B_FROM_MAC + B_TO_MAC )
struct socket;
typedef struct buffer_routing_info {
ipv6_route_info_t route_info;
const uint8_t *ip_dest;
uint8_t ref_count;
} buffer_routing_info_t;
/** buffer structure */
/* If adding pointers to this, ensure buffer_free and buffer_copy_metadata are informed */
typedef struct buffer {
ns_list_link_t link;
sockaddr_t dst_sa; /*!< Destination sockaddr */
sockaddr_t src_sa; /*!< Source sockaddr */
sockaddr_t *predecessor; /*!< Predecessor - used by RPL */
protocol_interface_info_entry_t *interface; /*!< Pointer to interface */
struct socket *socket; /*!< Indicate is data came trough socket */
buffer_info_t info; /*!< Protocol information */
uint8_t seq; /*!< Packet MAC header sequence number */
uint16_t buf_ptr; /*!< Current pointer in the buffer */
uint16_t buf_end; /*!< End pointer in the buffer */
uint16_t size; /*!< Buffer size */
uint16_t offset; /*!< Offset indicator (used in some upward paths) */
//uint16_t queue_timer;
uint16_t payload_length; /*!< Socket payload length */
uint8_t IPHC_NH;
uint8_t rpl_instance;
bool rpl_instance_known: 1;
bool ip_routed_up: 1;
uint8_t rpl_flag_error;
//uint8_t bc_sending_superframe; /*FHSS uses this randomly chosen superframe to send this packet (if broadcast)*/
//uint8_t fhss_channel_retries_left;
//uint8_t ip_transmission_prev_seq; /*!< XXX: this stores the data packet seq. number, which is needed for re-transmission. */
//uint16_t bad_channel;
void *session_ptr;
uint8_t *rpl_option;
buffer_priority_t priority;
buffer_link_info_t link_specific;
uint16_t mpl_option_data_offset;
uint8_t trickle_data_len;
uint8_t trickle_data_field[4];
buffer_options_t options; /*!< Additional signal info etc */
buffer_routing_info_t *route; /* A pointer last to try to get neat alignment for data */
void (*ack_receive_cb)(struct buffer *buffer_ptr, uint8_t status); /*!< ACK receive callback. If set, will be called when TX is done */
uint8_t buf[]; /*!< Trailing buffer data */
} buffer_t;
typedef NS_LIST_HEAD(buffer_t, link) buffer_list_t;
NS_STATIC_ASSERT(offsetof(buffer_t, link) == 0, "Some use NS_LIST_HEAD_INCOMPLETE")
#define SYST_WDCLEAR 0xff
#define SYST_TX_TO 0xfe
/** Macro to check buffer corruptions with debug flagging. */
#ifdef EXTRA_CONSISTENCY_CHECKS
#define buffer_data_pointer_after_adjustment(x) buffer_corrupt_check(x)
#define _buffer_corruption_check(x) buffer_corrupt_check(x)
#else
#define buffer_data_pointer_after_adjustment(x) buffer_data_pointer(x)
#define _buffer_corruption_check(x)
#endif
/** Allocate memory for a buffer_t from the heap */
extern buffer_t *buffer_get(uint16_t size);
/** Allocate memory for a buffer_t from the heap, with more detailed sizing */
extern buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspace);
/** Allocate memory for a minimal buffer (no headroom or extra space) */
extern buffer_t *buffer_get_minimal(uint16_t size);
/** Free a buffer from the heap, and return NULL */
extern buffer_t *buffer_free(buffer_t *buf);
/** Free a linked buffer list from the heap */
void buffer_free_list(buffer_list_t *list);
/** Free any routing info in the buffer, returning the buffer pointer */
extern buffer_t *buffer_free_route(buffer_t *buf);
/** Compute IPv6 checksum for buffer data + IPv6 pseudo-header */
uint16_t buffer_ipv6_fcf(const buffer_t *buf, uint8_t next_header);
/** Check for corrupt buffers should only be used when testing.*/
#ifdef EXTRA_CONSISTENCY_CHECKS
uint8_t *buffer_corrupt_check(buffer_t *buf);
#else
#define buffer_corrupt_check(b) ((void)0)
#endif
/** Allocate header space in buffer */
extern buffer_t *buffer_headroom(buffer_t *buf, uint16_t size);
/** Add buffer at the end of current buffer.
* Modifies all pointer and indexes correctly.
*
*/
void buffer_data_add(buffer_t *buf, const uint8_t *data_ptr, uint16_t data_len);
/** create new buffer and copy all fields and data
*
* Notice that data can have different headroom reserved. so the actual data might
* be located in different part of buffer than in original.*/
buffer_t *buffer_clone(buffer_t *buf);
/** prepare an input buffer to become a response - clear unwanted metadata */
buffer_t *buffer_turnaround(buffer_t *buf);
/** copy metadata from src to dst - see definition for more info */
void buffer_copy_metadata(buffer_t *dst, buffer_t *src, bool non_clonable_to_dst);
/** remember the predecessor address, if needed */
void buffer_note_predecessor(buffer_t *buf, const sockaddr_t *addr);
/** set the socket pointer in the buffer (dealing with reference counting) */
struct socket *buffer_socket_set(buffer_t *buf, struct socket *socket);
/** set buffer_priority */
#define buffer_priority_set(x,z) ((x)->priority = (z))
/** get pointer to data*/
#define buffer_data_pointer(x) (&(x)->buf[(x)->buf_ptr])
/** get pointer to end of data*/
#define buffer_data_end(x) (&(x)->buf[(x)->buf_end])
/** get pointer to data*/
#define buffer_data_pointer_set(x,new_start_ptr) ((x)->buf_ptr = (new_start_ptr) - (x)->buf)
/** get pointer to end of data*/
#define buffer_data_end_set(x,new_end_ptr) do {\
((x)->buf_end = (new_end_ptr) - (x)->buf);\
_buffer_corruption_check(x);\
} while(0)
/** get data length*/
#define buffer_data_length(x) (int)(x->buf_end - x->buf_ptr)
/** get data length Set*/
#define buffer_data_length_set(x,z) ((x)->buf_end = (x)->buf_ptr + (z))
/** free data bytes in buffer */
#define buffer_data_free_length(x) ((x)->size - (x)->buf_end)
/** Clears buffer to initial value
* uint8_t *buffer_data_clear(buffer_t *x)
* */
#define buffer_data_clear(x) ((x)->buf_ptr = (x)->buf_end = BUFFER_DEFAULT_HEADROOM, buffer_data_pointer_after_adjustment(x))
/** Clears buffer and sets the headroom */
#define buffer_data_clear_with_headroom(x,z) ((x)->buf_ptr = (x)->buf_end = (z))
/** Removes z amount of bytes from the begining of buffer
* uint8_t *buffer_data_strip_header(buffer_t *x, uint16_t z)
* */
static inline uint8_t *buffer_data_strip_header(buffer_t *x, uint16_t z)
{
x->buf_ptr += z;
return buffer_data_pointer_after_adjustment(x);
}
/** Adds z amount of bytes to the begining of buffer check if this is allowed using buffer_headroom method.
* uint8_t *buffer_data_reserve_header(buffer_t *x, uint16_t z)
* */
static inline uint8_t *buffer_data_reserve_header(buffer_t *x, uint16_t z)
{
x->buf_ptr -= z;
return buffer_data_pointer_after_adjustment(x);
}
/** append 1 byte to data*/
#define buffer_push_uint8(x, z) do {\
(x)->buf[x->buf_end++] = (z);\
_buffer_corruption_check(x);\
} while(0)
/** append 2 byte to data*/
#define buffer_push_uint16(x, z) do {\
(x)->buf[x->buf_end++] = (uint8_t)( (z) >> 8);\
(x)->buf[x->buf_end++] = (uint8_t) (z);\
_buffer_corruption_check(x);\
} while(0)
/** append 4 byte to data*/
#define buffer_push_uint32(x, z) do {\
(x)->buf[(x)->buf_end++] = (uint8_t) ((z) >> 24);\
(x)->buf[(x)->buf_end++] = (uint8_t) ((z) >> 16);\
(x)->buf[(x)->buf_end++] = (uint8_t) ((z) >> 8);\
(x)->buf[(x)->buf_end++] = (uint8_t) ((z));\
_buffer_corruption_check(x);\
} while(0)
/** append 2 byte to data on little endian order or inverse*/
#define buffer_push_uint16_i(x, z) do {\
(x)->buf[(x)->buf_end++] = (uint8_t)(z);\
(x)->buf[(x)->buf_end++] = (uint8_t)((z) >> 8);\
_buffer_corruption_check(x);\
} while(0)
/** read 1 byte out of the buffer*/
#define buffer_pull_uint8(x) (x)->buf[(x)->buf_ptr++]
/** read 2 byte out of the buffer*/
#define buffer_pull_uint16(x) \
((x)->buf_ptr += 2,\
((uint16_t)(x)->buf[(x)->buf_ptr - 2] << 8 ) |\
(uint16_t)(x)->buf[(x)->buf_ptr - 1])
/** read 4 byte out of the buffer*/
#define buffer_pull_uint32(x) \
((x)->buf_ptr += 4,\
((uint32_t)(x)->buf[(x)->buf_ptr - 4] << 24 ) |\
((uint32_t)(x)->buf[(x)->buf_ptr - 3] << 16 ) |\
((uint32_t)(x)->buf[(x)->buf_ptr - 2] << 8 ) |\
(uint32_t)(x)->buf[(x)->buf_ptr - 1])
#endif