/* * 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