Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 }
Generated on Tue Jul 12 2022 12:21:44 by
