BA / Mbed OS BaBoRo1
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers buffer_dyn.c Source File

buffer_dyn.c

00001 /*
00002  * Copyright (c) 2011-2017, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "nsconfig.h"
00019 #include "string.h"
00020 #include "ns_types.h"
00021 #include "nsdynmemLIB.h"
00022 #include "Core/include/address.h"
00023 #include "Core/include/ns_buffer.h"
00024 #include "Core/include/socket.h"
00025 #include "ns_trace.h"
00026 #include "platform/arm_hal_interrupt.h"
00027 #include "NWK_INTERFACE/Include/protocol_stats.h"
00028 #include "ip_fsc.h"
00029 #include "net_interface.h"
00030 
00031 #define TRACE_GROUP "buff"
00032 
00033 volatile unsigned int buffer_count = 0;
00034 
00035 uint8_t *(buffer_corrupt_check)(buffer_t *buf)
00036 {
00037     if (buf == NULL) {
00038         return NULL;
00039     }
00040 
00041     if (buf->buf_ptr  > buf->buf_end ) {
00042         tr_error("Buffer pointer end not set");
00043     } else if (buffer_data_length(buf) < 0) {
00044         tr_error("Buffer length overflow");
00045         while (1);
00046     } else if (buf->buf_end  > buf->size  || buf->buf_ptr  > buf->size ) {
00047         tr_error("buffer pointer overridden");
00048         while (1);
00049     }
00050     return buffer_data_pointer(buf);
00051 }
00052 
00053 buffer_t *buffer_get(uint16_t size)
00054 {
00055     return buffer_get_specific(BUFFER_DEFAULT_HEADROOM, size, BUFFER_DEFAULT_MIN_SIZE);
00056 }
00057 
00058 buffer_t *buffer_get_minimal(uint16_t size)
00059 {
00060     return buffer_get_specific(0, size, 0);
00061 }
00062 
00063 /**
00064  * Get pointer to a buffer_t structure and reserve memory for it from the dynamic heap.
00065  *
00066  * \param headroom required headroom in addition to basic size
00067  * \param size basic size of data allocate memory for
00068  * \param minspace minimum size of buffer
00069  * \return a pointer of type buffer_t to the allocated memory area
00070  *
00071  */
00072 buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspace)
00073 {
00074     buffer_t *buf;
00075     uint16_t total_size;
00076 
00077     total_size = headroom + size;
00078     if (total_size < minspace) {
00079         total_size = minspace;
00080     }
00081 
00082     /* Round total size up to at least be a neat multiple - allocation must
00083      * anyway be this much aligned. */
00084     total_size = (total_size + 3) &~ 3;
00085 
00086     // Note - as well as this alloc+init, buffers can also be "realloced"
00087     // in buffer_headroom()
00088 
00089     buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + total_size);
00090     if (buf) {
00091         platform_enter_critical();
00092         buffer_count++;
00093         platform_exit_critical();
00094         memset(buf, 0, sizeof(buffer_t));
00095         buf->buf_ptr  = total_size - size;
00096         buf->buf_end  = buf->buf_ptr ;
00097         buf->socket  = NULL;
00098         buf->interface  = NULL;
00099         //buf->bad_channel = 0xffff;
00100         //buf->bc_sending_superframe = 0xff;
00101         buf->rpl_instance = 0xff;
00102         // Socket TX always overrides this, so this is the default for non-socket buffers.
00103         // Setting it to 0 would remove flow labels on internal ICMP messages without affecting sockets.
00104         buf->options .flow_label  = IPV6_FLOW_UNSPECIFIED;
00105         buf->options .hop_limit  = 255;
00106         buf->options .mpl_permitted  = true;
00107         buf->link_specific.ieee802_15_4.useDefaultPanId = true;
00108 #ifndef NO_IPV6_PMTUD
00109         buf->options .ipv6_use_min_mtu  = -1;
00110 #endif
00111         buf->size  = total_size;
00112     } else {
00113         tr_error("buffer_get failed: alloc(%zd)", sizeof(buffer_t) + total_size);
00114     }
00115 
00116     protocol_stats_update(STATS_BUFFER_ALLOC, 1);
00117     return (buf);
00118 }
00119 
00120 /**
00121  * Make sure buffer has enough room for header.
00122  *
00123  * \param buf buffer to check
00124  * \param size required header space
00125  * \return a pointer of type buffer_t to the newly allocated buffer (or the original one)
00126  *
00127  */
00128 buffer_t *buffer_headroom(buffer_t *buf, uint16_t size)
00129 {
00130     uint16_t curr_len = buffer_data_length(buf);
00131 
00132     if (buf->size  < (curr_len + size)) {
00133         /* This buffer isn't big enough at all - allocate a new block */
00134         // TODO - should we be giving them extra? probably
00135         uint16_t new_total = (curr_len + size + 3) &~ 3;
00136         buffer_t *restrict new_buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + new_total);
00137         if (new_buf) {
00138             // Copy the buffer_t header
00139             *new_buf = *buf;
00140             // Set new pointers, leaving specified headroom
00141             new_buf->buf_ptr  = size;
00142             new_buf->buf_end = size + curr_len;
00143             new_buf->size = new_total;
00144             // Copy the current data
00145             memcpy(buffer_data_pointer(new_buf), buffer_data_pointer(buf), curr_len);
00146             protocol_stats_update(STATS_BUFFER_HEADROOM_REALLOC, 1);
00147             ns_dyn_mem_free(buf);
00148             buf = new_buf;
00149         } else {
00150             tr_error("HeadRoom Fail");
00151             protocol_stats_update(STATS_BUFFER_HEADROOM_FAIL, 1);
00152             socket_tx_buffer_event_and_free(buf, SOCKET_NO_RAM);
00153             buf = NULL;
00154         }
00155     } else if (buf->buf_ptr  < size) {
00156         /* This buffer is big enough, but not enough headroom - shuffle */
00157         // TODO - surely better to shuffle all the way to the end in one go?
00158         uint8_t *orig_ptr = buffer_data_pointer(buf);
00159         buf->buf_ptr  = size;
00160         buf->buf_end  = size + curr_len;
00161         if (curr_len != 0) {
00162             memmove(buffer_data_pointer(buf), orig_ptr, curr_len);
00163             protocol_stats_update(STATS_BUFFER_HEADROOM_SHUFFLE, 1);
00164         }
00165     }
00166     buffer_corrupt_check(buf);
00167     return buf;
00168 }
00169 
00170 buffer_t *buffer_free_route(buffer_t *buf)
00171 {
00172     if (buf->route) {
00173         if (--buf->route->ref_count == 0) {
00174             ns_dyn_mem_free(buf->route);
00175         }
00176         buf->route = NULL;
00177     }
00178     return buf;
00179 }
00180 
00181 /**
00182  * Free a memory block from the heap.
00183  *
00184  * \param buf pointer to buffer to be freed
00185  * \return (buffer_t *) NULL
00186  *
00187  */
00188 buffer_t *buffer_free(buffer_t *buf)
00189 {
00190     if (buf) {
00191         platform_enter_critical();
00192         if (buffer_count) {
00193             buffer_count--;
00194         } else {
00195             tr_error("bc neg");
00196         }
00197         platform_exit_critical();
00198 
00199         buf = buffer_free_route(buf);
00200         socket_dereference(buf->socket );
00201         ns_dyn_mem_free(buf->predecessor );
00202         ns_dyn_mem_free(buf->rpl_option);
00203         ns_dyn_mem_free(buf);
00204 
00205     } else {
00206         tr_error("nullp F");
00207     }
00208     return NULL;
00209 }
00210 
00211 void buffer_free_list(buffer_list_t *list)
00212 {
00213     ns_list_foreach_safe(buffer_t, buf, list) {
00214         ns_list_remove(list, buf);
00215         buffer_free(buf);
00216     }
00217 }
00218 
00219 /* Prepare a buffer that came from a received packet for use as a new
00220  * transmission (eg ICMP error response). Kill fields which should not be
00221  * carried over. This is distinct from a packet we are forwarding.
00222  */
00223 buffer_t *buffer_turnaround(buffer_t *buf)
00224 {
00225     if (buf->predecessor ) {
00226         ns_dyn_mem_free(buf->predecessor );
00227         buf->predecessor  = NULL;
00228     }
00229 
00230     if (buf->rpl_option) {
00231         ns_dyn_mem_free(buf->rpl_option);
00232         buf->rpl_option = NULL;
00233     }
00234     buf->options .tunnelled  = false;
00235     buf->rpl_flag_error = 0;
00236     buf->rpl_instance_known = false;
00237     buf->link_specific.ieee802_15_4.useDefaultPanId = true;
00238 
00239     buffer_socket_set(buf, NULL);
00240 
00241     /* Most cases this will be a response to an RX, so no existing routing
00242      * info, but in the case of TX resolution failure, we're reversing and
00243      * need to re-evaluate routing.
00244      */
00245     return buffer_free_route(buf);
00246 }
00247 
00248 void buffer_note_predecessor(buffer_t *buf, const sockaddr_t *addr)
00249 {
00250     if (buf->options .need_predecessor  && !buf->predecessor ) {
00251         buf->predecessor  = ns_dyn_mem_temporary_alloc(sizeof *buf->predecessor );
00252         if (buf->predecessor ) {
00253             memcpy(buf->predecessor , addr, sizeof *buf->predecessor );
00254         }
00255     }
00256 }
00257 
00258 socket_t *buffer_socket_set(buffer_t *buf, socket_t *socket)
00259 {
00260     buf->socket  = socket_dereference(buf->socket );
00261     buf->socket  = socket_reference(socket);
00262     return buf->socket ;
00263 }
00264 
00265 /* Copy metadata information from src into dst.
00266  *
00267  * Data size and pointers left unmodified in destination.
00268  * Other in-buffer metadata copied from src.
00269  * Any route information pointer cloned from src (reference count increased).
00270  * Other metadata pointers transfered either to dst or left in src, as requested
00271  */
00272 void buffer_copy_metadata(buffer_t *dst, buffer_t *src, bool non_clonable_to_dst)
00273 {
00274     uint16_t buf_size = dst->size ;
00275     uint16_t buf_end = dst->buf_end ;
00276     uint16_t buf_ptr = dst->buf_ptr ;
00277     *dst = *src;
00278     if (dst->route) {
00279         dst->route->ref_count++;
00280     }
00281     dst->size  = buf_size;
00282     dst->buf_ptr  = buf_ptr;
00283     dst->buf_end  = buf_end;
00284 
00285     /* Extra data pointers now attached to both buffers - there can be only one */
00286     buffer_t *to_wipe = non_clonable_to_dst ? src : dst;
00287     to_wipe->rpl_option = NULL;
00288     to_wipe->predecessor  = NULL;
00289     to_wipe->socket  = NULL;
00290 }
00291 
00292 /**
00293  * Add buffer at the end of data.
00294  *
00295  * \param buf pointer to buffer where data is added
00296  * \param data_ptr data pointer where data is copied
00297  * \data_len length of data copied.
00298  *
00299  */
00300 void buffer_data_add(buffer_t *buf, const uint8_t *data_ptr, uint16_t data_len)
00301 {
00302     memcpy(buffer_data_end(buf), data_ptr, data_len);
00303     buffer_data_end_set(buf, buffer_data_end(buf) + data_len);
00304 #ifdef EXTRA_CONSISTENCY_CHECKS
00305     buffer_corrupt_check(buf);
00306 #endif
00307     return;
00308 }
00309 
00310 /**
00311  * Create new buffer that has the same data and fields.
00312  *
00313  * \param buf pointer to buffer to be freed
00314  * \return (buffer_t *) new clone.
00315  *
00316  */
00317 buffer_t *buffer_clone(buffer_t *buf)
00318 {
00319     buffer_t *result_ptr = NULL;
00320 
00321     if (buf == NULL) {
00322         return NULL;
00323     }
00324 
00325     result_ptr = buffer_get(buffer_data_length(buf));
00326 
00327     if (result_ptr == NULL) {
00328         return NULL;
00329     }
00330 
00331     uint16_t buf_ptr = result_ptr->buf_ptr ;
00332     uint16_t buf_end = result_ptr->buf_end ;
00333     uint16_t size = result_ptr->size ;
00334 
00335     *result_ptr = *buf;
00336     result_ptr->predecessor  = NULL;
00337     result_ptr->route = NULL; // Don't clone routing info
00338     result_ptr->socket  = NULL; // Don't clone Socket info
00339     result_ptr->options .multicast_loop  = false; // Don't loop back more copies!
00340     result_ptr->rpl_option = NULL;
00341     result_ptr->buf_ptr  = buf_ptr;
00342     result_ptr->buf_end  = buf_end;
00343     result_ptr->size  = size;
00344     buffer_data_add(result_ptr, buffer_data_pointer(buf), buffer_data_length(buf));
00345 
00346     return result_ptr;
00347 }
00348 
00349 uint16_t buffer_ipv6_fcf(const buffer_t *buf, uint8_t next_header)
00350 {
00351     return ipv6_fcf(buf->src_sa .address , buf->dst_sa .address ,
00352                     buffer_data_length(buf), buffer_data_pointer(buf),
00353                     next_header);
00354 }