EL4121 Embedded System / mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers adaptation_interface.c Source File

adaptation_interface.c

00001 /*
00002  * Copyright (c) 2016-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 "ns_types.h"
00020 #include "eventOS_event.h"
00021 #include "string.h"
00022 #include "ns_trace.h"
00023 #include "ns_list.h"
00024 #include "randLIB.h"
00025 #include "nsdynmemLIB.h"
00026 #include "Core/include/address.h"
00027 #include "Core/include/socket.h"
00028 #include "mac_api.h"
00029 #include "mac_mcps.h"
00030 #include "mac_common_defines.h"
00031 #include "common_functions.h"
00032 #include "NWK_INTERFACE/Include/protocol.h"
00033 #include "NWK_INTERFACE/Include/protocol_stats.h"
00034 #include "6LoWPAN/IPHC_Decode/cipv6.h"
00035 #include "NWK_INTERFACE/Include/protocol_timer.h"
00036 #include "Service_Libs/etx/etx.h"
00037 #include "6LoWPAN/MAC/mac_helper.h"
00038 #include "6LoWPAN/Mesh/mesh.h"
00039 #include "6LoWPAN/IPHC_Decode/iphc_decompress.h"
00040 #include "lowpan_adaptation_interface.h"
00041 #include "MLE/mle.h"
00042 #ifdef HAVE_RPL
00043 #include "RPL/rpl_data.h"
00044 #endif
00045 
00046 #define TRACE_GROUP "6lAd"
00047 
00048 typedef struct {
00049     uint16_t tag;   /*!< Fragmentation datagram TAG ID */
00050     uint16_t size;  /*!< Datagram Total Size (uncompressed) */
00051     uint16_t orig_size; /*!< Datagram Original Size (compressed) */
00052     uint16_t frag_max;  /*!< Maximum fragment size (MAC payload) */
00053     uint16_t offset; /*!< Data offset from datagram start */
00054     int16_t pattern; /*!< Size of compressed LoWPAN headers */
00055     uint16_t unfrag_ptr; /*!< Offset within buf of headers that precede the FRAG header */
00056     uint16_t frag_len;
00057     uint8_t unfrag_len; /*!< Length of headers that precede the FRAG header */
00058     bool fragmented_data:1;
00059     bool first_fragment:1;
00060     bool indirectData:1;
00061     buffer_t *buf;
00062     uint8_t *fragmenter_buf;
00063     ns_list_link_t      link; /*!< List link entry */
00064 } fragmenter_tx_entry_t;
00065 
00066 
00067 typedef NS_LIST_HEAD (fragmenter_tx_entry_t, link) fragmenter_tx_list_t;
00068 
00069 typedef struct {
00070     int8_t interface_id;
00071     uint16_t local_frag_tag;
00072     uint8_t msduHandle;
00073     fragmenter_tx_list_t indirect_tx_queue;
00074     uint8_t *fragment_indirect_tx_buffer; //Used for write fragmentation header
00075     uint16_t mtu_size;
00076     fragmenter_tx_entry_t active_unicast_tx_buf; //Current active direct unicast tx process
00077     fragmenter_tx_entry_t active_broadcast_tx_buf; //Current active direct broadcast tx process
00078     buffer_list_t directTxQueue; //Waiting free tx process
00079     uint16_t indirect_big_packet_threshold;
00080     uint16_t max_indirect_big_packets_total;
00081     uint16_t max_indirect_small_packets_per_child;
00082     bool fragmenter_active; /*!< Fragmenter state */
00083     ns_list_link_t      link; /*!< List link entry */
00084 } fragmenter_interface_t;
00085 
00086 static NS_LIST_DEFINE(fragmenter_interface_list, fragmenter_interface_t, link);
00087 
00088 /* Adaptation interface local functions */
00089 static fragmenter_interface_t *lowpan_adaptation_interface_discover(int8_t interfaceId);
00090 
00091 /* Interface direct message pending queue functions */
00092 static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_ptr , buffer_t *buf);
00093 static buffer_t * lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur);
00094 
00095 /* Data direction and message length validation */
00096 static bool lowpan_adaptation_indirect_data_request(mle_neigh_table_entry_t *mle_entry);
00097 static bool lowpan_adaptation_request_longer_than_mtu(protocol_interface_info_entry_t *cur, buffer_t *buf);
00098 
00099 /* Common data tx request process functions */
00100 static void lowpan_active_buffer_state_reset(fragmenter_tx_entry_t *tx_buffer);
00101 static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *interface_ptr);
00102 static fragmenter_tx_entry_t *lowpan_indirect_entry_allocate(uint16_t fragment_buffer_size);
00103 static fragmenter_tx_entry_t * lowpan_adaptation_tx_process_init(fragmenter_interface_t *interface_ptr, bool indirect, bool fragmented, bool is_unicast);
00104 static void lowpan_adaptation_data_request_primitiv_set(const buffer_t *buf, mcps_data_req_t *dataReq, protocol_interface_info_entry_t *cur);
00105 static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buffer_t *buf, fragmenter_tx_entry_t *tx_ptr);
00106 
00107 /* Tx confirmation local functions */
00108 static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf);
00109 static fragmenter_tx_entry_t * lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue);
00110 static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event);
00111 static uint8_t map_mlme_status_to_socket_event(uint8_t mlme_status);
00112 static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr);
00113 
00114 /* Fragmentation local functions */
00115 static int8_t lowpan_message_fragmentation_init(buffer_t *buf, fragmenter_tx_entry_t *frag_entry, protocol_interface_info_entry_t *cur);
00116 static bool lowpan_message_fragmentation_message_write(const fragmenter_tx_entry_t *frag_entry, mcps_data_req_t *dataReq);
00117 static void lowpan_adaptation_indirect_queue_free_message(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr);
00118 
00119 //Discover
00120 static fragmenter_interface_t *lowpan_adaptation_interface_discover(int8_t interfaceId)
00121 {
00122 
00123     ns_list_foreach(fragmenter_interface_t, interface_ptr, &fragmenter_interface_list) {
00124         if (interfaceId == interface_ptr->interface_id) {
00125             return interface_ptr;
00126         }
00127     }
00128 
00129     return NULL;
00130 }
00131 
00132 
00133 static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_ptr , buffer_t *buf)
00134 {
00135     buffer_t *lower_priority_buf = NULL;
00136 
00137     ns_list_foreach(buffer_t, cur, &interface_ptr->directTxQueue) {
00138         if (cur->priority < buf->priority) {
00139             lower_priority_buf = cur;
00140             break;
00141         }
00142     }
00143 
00144     if (lower_priority_buf) {
00145         ns_list_add_before(&interface_ptr->directTxQueue, lower_priority_buf, buf);
00146     } else {
00147         ns_list_add_to_end(&interface_ptr->directTxQueue, buf);
00148     }
00149 }
00150 
00151 static buffer_t * lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur)
00152 {
00153     /* Currently this function is called only when data confirm is received for previously sent packet.
00154      * Data confirm has freed the corresponding "active buffer" and this function will look for new buffer to be set as active buffer.
00155      */
00156     ns_list_foreach_safe(buffer_t, buf, &interface_ptr->directTxQueue) {
00157         bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf);
00158         //Check that we not trig second active fragmentation process
00159         if (fragmented_needed && interface_ptr->fragmenter_active) {
00160             tr_debug("Do not trig Second active fragmentation");
00161         } else if ((buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_unicast_tx_buf.buf)
00162                 || (!buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_broadcast_tx_buf.buf)) {
00163             ns_list_remove(&interface_ptr->directTxQueue, buf);
00164             return buf;
00165         }
00166     }
00167     return NULL;
00168 }
00169 
00170 //fragmentation needed
00171 
00172 static bool lowpan_adaptation_request_longer_than_mtu(protocol_interface_info_entry_t *cur, buffer_t *buf)
00173 {
00174     uint_fast8_t overhead = mac_helper_frame_overhead(cur, buf);
00175 
00176 
00177     if (buffer_data_length(buf) > (int16_t)mac_helper_max_payload_size(cur, overhead)) {
00178         return true;
00179     } else {
00180         return false;
00181     }
00182 }
00183 
00184 static bool lowpan_adaptation_indirect_data_request(mle_neigh_table_entry_t *mle_entry)
00185 {
00186     if (mle_entry && !(mle_entry->mode & MLE_RX_ON_IDLE)) {
00187         return true;
00188     }
00189     return false;
00190 }
00191 
00192 
00193 static void lowpan_active_buffer_state_reset(fragmenter_tx_entry_t *tx_buffer)
00194 {
00195     if (tx_buffer->buf) {
00196         buffer_free(tx_buffer->buf);
00197         tx_buffer->buf = NULL;
00198     }
00199     tx_buffer->fragmented_data = false;
00200     tx_buffer->first_fragment = true;
00201 }
00202 
00203 static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf)
00204 {
00205 
00206     if (buf && buf->seq  == handle) {
00207         return true;
00208     }
00209 
00210 
00211     return false;
00212 }
00213 
00214 
00215 
00216 static fragmenter_tx_entry_t * lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue)
00217 {
00218     ns_list_foreach(fragmenter_tx_entry_t, entry, indirect_tx_queue) {
00219         if (entry->buf->seq == handle) {
00220             return entry;
00221         }
00222     }
00223     return NULL;
00224 }
00225 
00226 
00227 
00228 static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *interface_ptr)
00229 {
00230     bool valid_info = false;
00231     uint8_t handle;
00232     while(!valid_info) {
00233         handle = interface_ptr->msduHandle++;
00234         if (!lowpan_active_tx_handle_verify(handle,interface_ptr->active_unicast_tx_buf.buf)
00235                 && !lowpan_active_tx_handle_verify(handle,interface_ptr->active_broadcast_tx_buf.buf)
00236                 && !lowpan_indirect_tx_handle_verify(handle, &interface_ptr->indirect_tx_queue)) {
00237             valid_info = true;
00238         }
00239     }
00240     return handle;
00241 
00242 }
00243 
00244 static void lowpan_indirect_entry_free(fragmenter_tx_list_t *list , fragmenter_tx_entry_t *entry)
00245 {
00246     ns_list_remove(list, entry);
00247     if (entry->buf) {
00248         buffer_free(entry->buf);
00249     }
00250     ns_dyn_mem_free(entry->fragmenter_buf);
00251     ns_dyn_mem_free(entry);
00252 }
00253 
00254 static void lowpan_indirect_queue_free(fragmenter_tx_list_t *list)
00255 {
00256     while(!ns_list_is_empty(list)) {
00257         fragmenter_tx_entry_t *entry = ns_list_get_first(list);
00258         lowpan_indirect_entry_free(list, entry);
00259     }
00260 }
00261 
00262 
00263 int8_t lowpan_adaptation_interface_init(int8_t interface_id, uint16_t mac_mtu_size)
00264 {
00265     if (mac_mtu_size == 0) {
00266         return -2;
00267     }
00268     //Remove old interface
00269     lowpan_adaptation_interface_free(interface_id);
00270 
00271     //Allocate new
00272     fragmenter_interface_t *interface_ptr = ns_dyn_mem_alloc(sizeof(fragmenter_interface_t));
00273     uint8_t *tx_buffer = ns_dyn_mem_alloc(mac_mtu_size);
00274     if (!interface_ptr  || !tx_buffer) {
00275         ns_dyn_mem_free(interface_ptr);
00276         ns_dyn_mem_free(tx_buffer);
00277         return -1;
00278     }
00279 
00280     memset(interface_ptr, 0 ,sizeof(fragmenter_interface_t));
00281     interface_ptr->interface_id = interface_id;
00282     interface_ptr->fragment_indirect_tx_buffer = tx_buffer;
00283     interface_ptr->mtu_size = mac_mtu_size;
00284     interface_ptr->msduHandle = randLIB_get_8bit();
00285     interface_ptr->local_frag_tag = randLIB_get_16bit();
00286 
00287     ns_list_init(&interface_ptr->indirect_tx_queue);
00288     ns_list_init(&interface_ptr->directTxQueue);
00289 
00290     ns_list_add_to_end(&fragmenter_interface_list, interface_ptr);
00291 
00292     return 0;
00293 }
00294 
00295 int8_t lowpan_adaptation_interface_free(int8_t interface_id)
00296 {
00297     //Discover
00298     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
00299     if (!interface_ptr) {
00300         return -1;
00301     }
00302 
00303     ns_list_remove(&fragmenter_interface_list, interface_ptr);
00304     //free active tx process
00305     lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf);
00306     lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
00307 
00308     //Free Indirect entry
00309     lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue);
00310 
00311     buffer_free_list(&interface_ptr->directTxQueue);
00312 
00313     //Free Dynamic allocated entries
00314     ns_dyn_mem_free(interface_ptr->fragment_indirect_tx_buffer);
00315     ns_dyn_mem_free(interface_ptr);
00316 
00317     return 0;
00318 }
00319 
00320 
00321 int8_t lowpan_adaptation_interface_reset(int8_t interface_id)
00322 {
00323     //Discover
00324     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
00325     if (!interface_ptr) {
00326         return -1;
00327     }
00328 
00329     //free active tx process
00330     lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf);
00331     lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
00332     //Clean fragmented message flag
00333     interface_ptr->fragmenter_active = false;
00334 
00335     //Free Indirect entry
00336     lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue);
00337 
00338     buffer_free_list(&interface_ptr->directTxQueue);
00339 
00340     return 0;
00341 }
00342 
00343 
00344 static fragmenter_tx_entry_t *lowpan_indirect_entry_allocate(uint16_t fragment_buffer_size)
00345 {
00346     fragmenter_tx_entry_t *indirec_entry = ns_dyn_mem_temporary_alloc(sizeof(fragmenter_tx_entry_t));
00347     if (!indirec_entry) {
00348         return NULL;
00349     }
00350 
00351     if (fragment_buffer_size) {
00352         indirec_entry->fragmenter_buf = ns_dyn_mem_temporary_alloc(fragment_buffer_size);
00353         if (!indirec_entry->fragmenter_buf) {
00354             ns_dyn_mem_free(indirec_entry);
00355             return NULL;
00356         }
00357     } else {
00358         indirec_entry->fragmenter_buf = NULL;
00359     }
00360 
00361 
00362     indirec_entry->buf = NULL;
00363     indirec_entry->fragmented_data = false;
00364     indirec_entry->first_fragment = true;
00365 
00366     return indirec_entry;
00367 }
00368 
00369 static int8_t lowpan_message_fragmentation_init(buffer_t *buf, fragmenter_tx_entry_t *frag_entry, protocol_interface_info_entry_t *cur)
00370 {
00371     uint8_t *ptr;
00372     uint16_t uncompressed_size;
00373 
00374     /* Look for pre-fragmentation headers - strip off and store away */
00375     frag_entry->unfrag_ptr = buf->buf_ptr ;
00376     frag_entry->unfrag_len = 0;
00377     ptr = buffer_data_pointer(buf);
00378 
00379     if ((ptr[0] & LOWPAN_MESH_MASK) == LOWPAN_MESH) {
00380         uint_fast8_t size = mesh_header_len_from_type_byte(ptr[0]);
00381         ptr += size;
00382         buf->buf_ptr  += size;
00383     }
00384 
00385     if (ptr[0] == LOWPAN_DISPATCH_BC0) {
00386         ptr += 2;
00387         buf->buf_ptr  += 2;
00388     }
00389 
00390     frag_entry->unfrag_len = buf->buf_ptr  - frag_entry->unfrag_ptr;
00391 
00392     frag_entry->pattern = iphc_header_scan(buf, &uncompressed_size);
00393     frag_entry->size = buffer_data_length(buf);
00394     frag_entry->orig_size = frag_entry->size;
00395     frag_entry->size += (uncompressed_size - frag_entry->pattern);
00396 
00397     uint_fast8_t overhead = mac_helper_frame_overhead(cur, buf);
00398     frag_entry->frag_max = mac_helper_max_payload_size(cur, overhead);
00399 
00400 
00401     /* RFC 4944 says MTU and hence maximum size here is 1280, but that's
00402      * arbitrary, and some have argued that 6LoWPAN should have a larger
00403      * MTU, to avoid the need for IP fragmentation. So we don't enforce
00404      * that, leaving MTU decisions to upper layer config, and only look
00405      * for the "real" MTU from the FRAG header format, which would allow up
00406      * to 0x7FF (2047).
00407      */
00408     if (frag_entry->size > LOWPAN_HARD_MTU_LIMIT) {
00409         tr_error("Packet too big");
00410         return -1;
00411     }
00412 
00413     frag_entry->offset = uncompressed_size / 8;
00414     frag_entry->frag_len = frag_entry->pattern;
00415     if (frag_entry->unfrag_len + 4 + frag_entry->frag_len > frag_entry->frag_max) {
00416         tr_error("Too long 6LoWPAN header for fragment");
00417         return -1;
00418     }
00419 
00420     /* Now, frag_len is compressed payload bytes (just IPHC headers), and
00421      * frag_ptr->offset is uncompressed payload 8-octet units (just uncompressed
00422      * IPHC headers). Add post-IPHC payload to bring total compressed size up
00423      * to maximum fragment size.
00424      */
00425     while (frag_entry->unfrag_len + 4 + frag_entry->frag_len + 8 <= frag_entry->frag_max) {
00426         frag_entry->offset++;
00427         frag_entry->frag_len += 8;
00428     }
00429     frag_entry->fragmented_data = true;
00430 
00431     return 0;
00432 
00433 }
00434 
00435 /**
00436  * Return true when there is more fragmented packet for this message
00437  */
00438 static bool lowpan_message_fragmentation_message_write(const fragmenter_tx_entry_t *frag_entry, mcps_data_req_t *dataReq)
00439 {
00440     uint8_t *ptr = dataReq->msdu;
00441     if (frag_entry->unfrag_len) {
00442         memcpy(ptr, frag_entry->buf->buf  + frag_entry->unfrag_ptr, frag_entry->unfrag_len);
00443         ptr += frag_entry->unfrag_len;
00444     }
00445     if (frag_entry->first_fragment) {
00446         ptr = common_write_16_bit(((uint16_t) LOWPAN_FRAG1 << 8) | frag_entry->size, ptr);
00447         ptr = common_write_16_bit(frag_entry->tag, ptr);
00448     } else {
00449         ptr = common_write_16_bit(((uint16_t) LOWPAN_FRAGN << 8) | frag_entry->size, ptr);
00450         ptr = common_write_16_bit(frag_entry->tag, ptr);
00451         *ptr++ = frag_entry->offset;
00452     }
00453     memcpy(ptr, buffer_data_pointer(frag_entry->buf), frag_entry->frag_len);
00454     ptr += frag_entry->frag_len;
00455     dataReq->msduLength = ptr - dataReq->msdu;
00456     return frag_entry->offset * 8 + frag_entry->frag_len < frag_entry->size;
00457 }
00458 
00459 static fragmenter_tx_entry_t * lowpan_adaptation_tx_process_init(fragmenter_interface_t *interface_ptr, bool indirect, bool fragmented, bool is_unicast)
00460 {
00461     fragmenter_tx_entry_t *tx_entry;
00462     if (!indirect) {
00463         if (is_unicast) {
00464             tx_entry = &interface_ptr->active_unicast_tx_buf;
00465         } else {
00466             tx_entry = &interface_ptr->active_broadcast_tx_buf;
00467         }
00468         tx_entry->fragmenter_buf = interface_ptr->fragment_indirect_tx_buffer;
00469     } else {
00470         if (fragmented) {
00471             tx_entry = lowpan_indirect_entry_allocate(interface_ptr->mtu_size);
00472         } else {
00473             tx_entry = lowpan_indirect_entry_allocate(0);
00474         }
00475     }
00476 
00477     if (!tx_entry) {
00478         return NULL;
00479     }
00480 
00481     lowpan_active_buffer_state_reset(tx_entry);
00482 
00483     tx_entry->indirectData = indirect;
00484 
00485     return tx_entry;
00486 }
00487 
00488 buffer_t * lowpan_adaptation_data_process_tx_preprocess(protocol_interface_info_entry_t *cur, buffer_t *buf)
00489 {
00490     //Validate is link known and set indirect, datareq and security key id mode
00491     if (buf->dst_sa .addr_type  == ADDR_NONE ) {
00492         goto tx_error_handler;
00493     }
00494 
00495     mle_neigh_table_entry_t *mle_entry = NULL;
00496     /* If MLE is enabled, we will talk if we have an MLE association */
00497     if (buf->dst_sa .addr_type  == ADDR_802_15_4_LONG  ) {
00498         mle_entry = mle_class_get_by_link_address(cur->id, buf->dst_sa .address  + 2, buf->dst_sa .addr_type );
00499 
00500     } else if(buf->dst_sa .addr_type  == ADDR_802_15_4_SHORT  && (common_read_16_bit(buf->dst_sa .address  + 2)) != 0xffff) {
00501         mle_entry = mle_class_get_by_link_address(cur->id, buf->dst_sa .address  + 2, buf->dst_sa .addr_type );
00502     }
00503 
00504     //Validate neighbour
00505     if (!buf->options .ll_security_bypass_tx  && mle_entry) {
00506 
00507         if (mle_entry->handshakeReady ||  mle_entry->thread_commission) {
00508 
00509         } else {
00510             //tr_warn("Drop TX to unassociated %s", trace_sockaddr(&buf->dst_sa, true));
00511             goto tx_error_handler;
00512         }
00513     }
00514 
00515     //Check indirect
00516 
00517 
00518     if (addr_check_broadcast(buf->dst_sa .address , buf->dst_sa .addr_type ) == eOK) {
00519         buf->dst_sa .addr_type  = ADDR_802_15_4_SHORT ;
00520         buf->dst_sa .address [2] = 0xff;
00521         buf->dst_sa .address [3] = 0xff;
00522         buf->link_specific.ieee802_15_4.indirectTxProcess = false;
00523         buf->link_specific.ieee802_15_4.requestAck = false;
00524     } else {
00525         buf->link_specific.ieee802_15_4.requestAck = true;
00526         buf->link_specific.ieee802_15_4.indirectTxProcess = lowpan_adaptation_indirect_data_request(mle_entry);
00527     }
00528 
00529     if (buf->link_specific.ieee802_15_4.key_id_mode != B_SECURITY_KEY_ID_2) {
00530 
00531         if (!buf->link_specific.ieee802_15_4.requestAck ) {
00532             buf->link_specific.ieee802_15_4.key_id_mode = B_SECURITY_KEY_ID_MODE_DEFAULT;
00533         } else if (mle_entry && !mle_entry->thread_commission) {
00534             buf->link_specific.ieee802_15_4.key_id_mode  = B_SECURITY_KEY_ID_MODE_DEFAULT;
00535         } else {
00536             buf->link_specific.ieee802_15_4.key_id_mode  = B_SECURITY_KEY_ID_IMPLICIT;
00537         }
00538     }
00539 
00540     return buf;
00541 
00542     tx_error_handler:
00543     socket_tx_buffer_event_and_free(buf, SOCKET_TX_FAIL);
00544     return NULL;
00545 
00546 }
00547 
00548 static void lowpan_adaptation_data_request_primitiv_set(const buffer_t *buf, mcps_data_req_t *dataReq, protocol_interface_info_entry_t *cur)
00549 {
00550     memset(dataReq, 0, sizeof(mcps_data_req_t));
00551 
00552     //Check do we need fragmentation
00553 
00554     dataReq->InDirectTx = buf->link_specific.ieee802_15_4.indirectTxProcess;
00555     dataReq->TxAckReq = buf->link_specific.ieee802_15_4.requestAck;
00556     dataReq->SrcAddrMode = buf->src_sa .addr_type ;
00557     dataReq->DstAddrMode = buf->dst_sa .addr_type ;
00558     memcpy(dataReq->DstAddr, &buf->dst_sa .address [2], 8);
00559 
00560     if (buf->link_specific.ieee802_15_4.useDefaultPanId) {
00561         dataReq->DstPANId = mac_helper_panid_get(cur);
00562     } else {
00563         dataReq->DstPANId = buf->link_specific.ieee802_15_4.dstPanId;
00564     }
00565 
00566     //Allocate message msdu handle
00567     dataReq->msduHandle = buf->seq ;
00568 
00569     //Set Messages
00570     if (!buf->options .ll_security_bypass_tx ) {
00571         dataReq->Key.SecurityLevel = mac_helper_default_security_level_get(cur);
00572         if (dataReq->Key.SecurityLevel) {
00573             switch (buf->link_specific.ieee802_15_4.key_id_mode) {
00574                 case B_SECURITY_KEY_ID_MODE_DEFAULT:
00575                     dataReq->Key.KeyIndex = mac_helper_default_key_index_get(cur);
00576                     dataReq->Key.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur);
00577                     break;
00578                 case B_SECURITY_KEY_ID_IMPLICIT:
00579                     dataReq->Key.KeyIdMode = MAC_KEY_ID_MODE_IMPLICIT;
00580                     break;
00581 
00582                 case B_SECURITY_KEY_ID_2:
00583                     dataReq->Key.KeyIndex = 0xff;
00584                     dataReq->Key.KeyIdMode = MAC_KEY_ID_MODE_SRC4_IDX;
00585                     common_write_32_bit(0xffffffff, dataReq->Key.Keysource);
00586                     break;
00587             }
00588         }
00589     }
00590 }
00591 
00592 static void lowpan_adaptation_make_room_for_small_packet(protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr, mle_neigh_table_entry_t *neighbour_to_count)
00593 {
00594     if (interface_ptr->max_indirect_small_packets_per_child == 0) {
00595         return;
00596     }
00597 
00598     uint_fast16_t count = 0;
00599 
00600     ns_list_foreach_reverse_safe(fragmenter_tx_entry_t, tx_entry, &interface_ptr->indirect_tx_queue) {
00601         mle_neigh_table_entry_t *tx_neighbour = mle_class_get_by_link_address(cur->id, tx_entry->buf->dst_sa.address + 2, tx_entry->buf->dst_sa.addr_type);
00602         if (tx_neighbour == neighbour_to_count && buffer_data_length(tx_entry->buf) <= interface_ptr->indirect_big_packet_threshold) {
00603             if (++count >= interface_ptr->max_indirect_small_packets_per_child) {
00604                 lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry);
00605             }
00606         }
00607     }
00608 }
00609 
00610 static void lowpan_adaptation_make_room_for_big_packet(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr)
00611 {
00612     if (interface_ptr->max_indirect_big_packets_total == 0) {
00613         return;
00614     }
00615 
00616     uint_fast16_t count = 0;
00617 
00618     ns_list_foreach_reverse_safe(fragmenter_tx_entry_t, tx_entry, &interface_ptr->indirect_tx_queue) {
00619         if (buffer_data_length(tx_entry->buf) > interface_ptr->indirect_big_packet_threshold) {
00620             if (++count >= interface_ptr->max_indirect_big_packets_total) {
00621                 lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry);
00622             }
00623         }
00624     }
00625 }
00626 
00627 static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buffer_t *buf, fragmenter_tx_entry_t *tx_ptr)
00628 {
00629     mcps_data_req_t dataReq;
00630 
00631     lowpan_adaptation_data_request_primitiv_set(buf, &dataReq, cur);
00632     if (tx_ptr->fragmented_data) {
00633         dataReq.msdu = tx_ptr->fragmenter_buf;
00634         //Call fragmenter
00635         bool more_fragments = lowpan_message_fragmentation_message_write(tx_ptr, &dataReq);
00636         if (dataReq.InDirectTx) {
00637             dataReq.PendingBit |= more_fragments;
00638         }
00639     } else {
00640         dataReq.msduLength = buffer_data_length(buf);
00641         dataReq.msdu = buffer_data_pointer(buf);
00642     }
00643     if (buf->link_specific.ieee802_15_4.rf_channel_switch) {
00644         //Switch channel if selected channel is different
00645         if (cur->mac_parameters->mac_channel != buf->link_specific.ieee802_15_4.selected_channel) {
00646             uint8_t channel = cur->mac_parameters->mac_channel;
00647             mac_helper_mac_channel_set(cur, buf->link_specific.ieee802_15_4.selected_channel);
00648             buf->link_specific.ieee802_15_4.selected_channel = channel;
00649         } else {
00650             buf->link_specific.ieee802_15_4.rf_channel_switch = false;
00651         }
00652     }
00653 
00654     cur->mac_api->mcps_data_req(cur->mac_api, &dataReq);
00655 }
00656 
00657 int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buffer_t *buf)
00658 {
00659     if (!buf) {
00660         return -1;
00661     }
00662 
00663     if (!cur || !cur->mac_api || !cur->mac_api->mcps_data_req) {
00664         goto tx_error_handler;
00665     }
00666 
00667     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
00668     if (!interface_ptr) {
00669         goto tx_error_handler;
00670     }
00671 
00672     //Check packet size
00673     bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf);
00674     bool is_unicast = buf->link_specific.ieee802_15_4.requestAck;
00675     bool indirect = buf->link_specific.ieee802_15_4.indirectTxProcess;
00676     if (!indirect) {
00677         if (((is_unicast && interface_ptr->active_unicast_tx_buf.buf) || (!is_unicast && interface_ptr->active_broadcast_tx_buf.buf)) || (fragmented_needed && interface_ptr->fragmenter_active)) {
00678             lowpan_adaptation_tx_queue_write(interface_ptr, buf);
00679             return 0; //Return here
00680         }
00681     }
00682 
00683     //Allocate Handle
00684     buf->seq  = lowpan_data_request_unique_handle_get(interface_ptr);
00685 
00686     if (buf->options .ll_sec_bypass_frag_deny  && fragmented_needed) {
00687         // force security for fragmented packets
00688         buf->options .ll_security_bypass_tx  = false;
00689     }
00690 
00691     fragmenter_tx_entry_t *tx_ptr = lowpan_adaptation_tx_process_init(interface_ptr, indirect, fragmented_needed, is_unicast);
00692     if (!tx_ptr) {
00693         goto tx_error_handler;
00694     }
00695 
00696     tx_ptr->buf = buf;
00697 
00698     if (fragmented_needed) {
00699         //Fragmentation init
00700         if (lowpan_message_fragmentation_init(buf, tx_ptr, cur) ) {
00701             tr_error("Fragment init fail");
00702             if (indirect) {
00703                 ns_dyn_mem_free(tx_ptr->fragmenter_buf);
00704                 ns_dyn_mem_free(tx_ptr);
00705             }
00706             goto tx_error_handler;
00707         }
00708 
00709         tx_ptr->tag = interface_ptr->local_frag_tag++;
00710         if (!indirect) {
00711             interface_ptr->fragmenter_active = true;
00712         }
00713     }
00714 
00715     if (indirect) {
00716         //Add to indirectQUue
00717         mle_neigh_table_entry_t *mle_entry = mle_class_get_by_link_address(cur->id, buf->dst_sa .address  + 2, buf->dst_sa .addr_type );
00718 
00719         if (buffer_data_length(buf) <= interface_ptr->indirect_big_packet_threshold) {
00720             lowpan_adaptation_make_room_for_small_packet(cur, interface_ptr, mle_entry);
00721         } else {
00722             lowpan_adaptation_make_room_for_big_packet(cur, interface_ptr);
00723         }
00724 
00725         ns_list_add_to_end(&interface_ptr->indirect_tx_queue, tx_ptr);
00726         if (mle_entry) {
00727             buf->link_specific.ieee802_15_4.indirectTTL = (uint32_t) mle_entry->timeout_rx * MLE_TIMER_TICKS_MS;
00728         } else {
00729             buf->link_specific.ieee802_15_4.indirectTTL = cur->mac_parameters->mac_in_direct_entry_timeout;
00730         }
00731 
00732     }
00733 
00734     lowpan_data_request_to_mac(cur, buf, tx_ptr);
00735     return 0;
00736 
00737 
00738 tx_error_handler:
00739     socket_tx_buffer_event_and_free(buf, SOCKET_NO_RAM);
00740     return -1;
00741 
00742 }
00743 
00744 
00745 static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr)
00746 {
00747     if (!tx_ptr->fragmented_data) {
00748         if (tx_ptr->buf->ip_routed_up) {
00749             protocol_stats_update(STATS_IP_ROUTE_UP, buffer_data_length(tx_ptr->buf));
00750         } else {
00751             protocol_stats_update(STATS_IP_TX_COUNT, buffer_data_length(tx_ptr->buf));
00752         }
00753         return true;
00754     }
00755 
00756 
00757 
00758     //Update data pointer by last packet length
00759     buffer_data_strip_header(tx_ptr->buf, tx_ptr->frag_len);
00760     //Update offset
00761     if (!tx_ptr->first_fragment) {
00762         tx_ptr->offset += tx_ptr->frag_len / 8;
00763     } else {
00764         tx_ptr->first_fragment = false;
00765     }
00766 
00767     /* Check Is still Data what have to send */
00768     tx_ptr->frag_len = buffer_data_length(tx_ptr->buf);
00769 
00770 
00771     if (tx_ptr->frag_len == 0) {
00772         //Release current data
00773         if (tx_ptr->buf->ip_routed_up) {
00774             protocol_stats_update(STATS_IP_ROUTE_UP, tx_ptr->orig_size);
00775         } else {
00776             protocol_stats_update(STATS_IP_TX_COUNT, tx_ptr->orig_size);
00777         }
00778         return true;
00779     }
00780 
00781     //Continue Process
00782 
00783     if (tx_ptr->unfrag_len + 5 + tx_ptr->frag_len > tx_ptr->frag_max) {
00784         tx_ptr->frag_len = tx_ptr->frag_max - 5 - tx_ptr->unfrag_len;
00785         tx_ptr->frag_len &= ~7;
00786     }
00787 
00788     return false;
00789 }
00790 
00791 static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event)
00792 {
00793     buffer_t *buf = tx_ptr->buf ;
00794     tx_ptr->buf = NULL;
00795     if (buf->link_specific.ieee802_15_4.indirectTxProcess) {
00796         //release from list and free entry
00797         lowpan_indirect_entry_free(&interface_ptr->indirect_tx_queue, tx_ptr);
00798     }
00799 
00800     socket_tx_buffer_event_and_free(buf, socket_event);
00801 }
00802 
00803 
00804 int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *cur, const mcps_data_conf_t *confirm)
00805 {
00806     if( !cur || !confirm ){
00807         return -1;
00808     }
00809 
00810     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
00811     if (!interface_ptr) {
00812         return -1;
00813     }
00814 
00815     //Check first
00816     fragmenter_tx_entry_t *tx_ptr;
00817     bool active_direct_confirm;
00818     bool is_unicast = true;
00819 
00820     if (lowpan_active_tx_handle_verify(confirm->msduHandle,interface_ptr->active_unicast_tx_buf.buf)) {
00821         active_direct_confirm = true;
00822         tx_ptr = &interface_ptr->active_unicast_tx_buf;
00823     } else if (lowpan_active_tx_handle_verify(confirm->msduHandle,interface_ptr->active_broadcast_tx_buf.buf)) {
00824         active_direct_confirm = true;
00825         tx_ptr = &interface_ptr->active_broadcast_tx_buf;
00826         is_unicast = false;
00827     } else {
00828         active_direct_confirm = false;
00829         tx_ptr = lowpan_indirect_tx_handle_verify(confirm->msduHandle, &interface_ptr->indirect_tx_queue);
00830     }
00831 
00832     if (!tx_ptr) {
00833         tr_error("No data request for this confirmation %u", confirm->msduHandle);
00834         return -1;
00835     }
00836 
00837     //Check status for
00838     buffer_t *buf = tx_ptr->buf ;
00839 
00840     //Indirect data expiration
00841     if (confirm->status == MLME_TRANSACTION_EXPIRED && !active_direct_confirm) {
00842         if (buf->link_specific.ieee802_15_4.indirectTTL > 7000)
00843         {
00844             buf->link_specific.ieee802_15_4.indirectTTL -= 7000;
00845             //Push Back to MAC
00846             lowpan_data_request_to_mac(cur, buf, tx_ptr);
00847             return 0;
00848         }
00849     }
00850 
00851     switch (confirm->status) {
00852         case MLME_TX_NO_ACK:
00853         case MLME_NO_DATA:
00854         case MLME_SUCCESS:
00855             if (buf->link_specific.ieee802_15_4.requestAck) {
00856                 bool success = false;
00857                 if (confirm->status == MLME_SUCCESS) {
00858                     success = true;
00859                 }
00860                 etx_transm_attempts_update(cur->id, 1 + confirm->tx_retries , success, buf->dst_sa .addr_type , buf->dst_sa .address );
00861             }
00862             break;
00863         default:
00864 
00865             break;
00866 
00867     }
00868     //Switch original channel back
00869     if (buf->link_specific.ieee802_15_4.rf_channel_switch) {
00870         mac_helper_mac_channel_set(cur, buf->link_specific.ieee802_15_4.selected_channel);
00871         buf->link_specific.ieee802_15_4.rf_channel_switch = false;
00872     }
00873 
00874     switch (confirm->status) {
00875 
00876         case MLME_BUSY_CHAN:
00877             lowpan_data_request_to_mac(cur, buf, tx_ptr);
00878             break;
00879         case MLME_SUCCESS:
00880 
00881             //Check is there more packets
00882             if (lowpan_adaptation_tx_process_ready(tx_ptr)) {
00883                 if (tx_ptr->fragmented_data && active_direct_confirm) {
00884                     //Clean
00885                     interface_ptr->fragmenter_active = false;
00886                 }
00887                 lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, map_mlme_status_to_socket_event(confirm->status));
00888             } else {
00889                 lowpan_data_request_to_mac(cur, buf, tx_ptr);
00890             }
00891 
00892             break;
00893         case MLME_TX_NO_ACK:
00894         case MLME_SECURITY_FAIL:
00895         case MLME_TRANSACTION_EXPIRED:
00896         default:
00897             tr_error("MCPS Data fail by status %u", confirm->status);
00898 #ifdef HAVE_RPL
00899             if (confirm->status == MLME_TX_NO_ACK) {
00900                 if (buf->route && rpl_data_is_rpl_parent_route(buf->route->route_info.source)) {
00901                     protocol_stats_update(STATS_RPL_PARENT_TX_FAIL, 1);
00902                 }
00903             }
00904 #endif
00905             if (tx_ptr->fragmented_data) {
00906                 tx_ptr->buf->buf_ptr = tx_ptr->buf->buf_end;
00907                 tx_ptr->buf->buf_ptr -= tx_ptr->orig_size;
00908                 if (active_direct_confirm) {
00909                     interface_ptr->fragmenter_active = false;
00910                 }
00911             }
00912 
00913             lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, map_mlme_status_to_socket_event(confirm->status));
00914             break;
00915 
00916     }
00917 
00918     if ((is_unicast && !interface_ptr->active_unicast_tx_buf.buf) || (!is_unicast && !interface_ptr->active_broadcast_tx_buf.buf)) {
00919         //Read Buffer and trig next direct request
00920         lowpan_adaptation_interface_tx(cur, lowpan_adaptation_tx_queue_read(interface_ptr, cur));
00921     }
00922 
00923     return 0;
00924 
00925 }
00926 
00927 static uint8_t map_mlme_status_to_socket_event(uint8_t mlme_status)
00928 {
00929     uint8_t socket_event;
00930 
00931     switch (mlme_status) {
00932         case MLME_SUCCESS:
00933             socket_event = SOCKET_TX_DONE;
00934             break;
00935         case MLME_TX_NO_ACK:
00936         case MLME_SECURITY_FAIL:
00937         case MLME_TRANSACTION_EXPIRED:
00938         default:
00939             socket_event = SOCKET_TX_FAIL;
00940             break;
00941     }
00942 
00943     return (socket_event);
00944 }
00945 
00946 bool lowpan_adaptation_tx_active(int8_t interface_id)
00947 {
00948     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
00949 
00950     if (!interface_ptr || (!interface_ptr->active_unicast_tx_buf.buf && !interface_ptr->active_broadcast_tx_buf.buf)) {
00951         return false;
00952     }
00953     return true;
00954 }
00955 
00956 static bool lowpan_tx_buffer_address_compare(sockaddr_t *dst_sa, uint8_t *address_ptr, addrtype_t adr_type)
00957 {
00958 
00959     if (dst_sa->addr_type  != adr_type) {
00960         return false;
00961     }
00962 
00963     uint8_t compare_length;
00964     switch (adr_type) {
00965         case ADDR_802_15_4_SHORT :
00966             compare_length = 2;
00967             break;
00968         case ADDR_802_15_4_LONG :
00969             compare_length = 8;
00970             break;
00971         default:
00972             return false;
00973     }
00974 
00975 
00976     if (memcmp(&dst_sa->address [2], address_ptr, compare_length)) {
00977         return false;
00978     }
00979     return true;
00980 }
00981 
00982 static void lowpan_adaptation_purge_from_mac(struct protocol_interface_info_entry *cur, uint8_t msduhandle)
00983 {
00984     mcps_purge_t purge_req;
00985     purge_req.msduHandle = msduhandle;
00986     cur->mac_api->mcps_purge_req(cur->mac_api, &purge_req);
00987 }
00988 
00989 static void lowpan_adaptation_indirect_queue_free_message(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr)
00990 {
00991     tr_debug("Purge from indirect handle %u", tx_ptr->buf->seq);
00992     if (cur->mac_api->mcps_purge_req) {
00993         lowpan_adaptation_purge_from_mac(cur, tx_ptr->buf->seq);
00994     }
00995     lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, SOCKET_TX_FAIL);
00996 }
00997 
00998 int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type)
00999 {
01000     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
01001 
01002     if (!interface_ptr ) {
01003         return -1;
01004     }
01005 
01006     //Check first indirect queue
01007     ns_list_foreach_safe(fragmenter_tx_entry_t, entry, &interface_ptr->indirect_tx_queue) {
01008 
01009         if (lowpan_tx_buffer_address_compare(&entry->buf->dst_sa, address_ptr, adr_type)) {
01010             //Purge from mac
01011             lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, entry);
01012         }
01013     }
01014 
01015     return 0;
01016 
01017 }
01018 
01019 int8_t lowpan_adaptation_indirect_queue_params_set(struct protocol_interface_info_entry *cur, uint16_t indirect_big_packet_threshold, uint16_t max_indirect_big_packets_total, uint16_t max_indirect_small_packets_per_child)
01020 {
01021     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
01022 
01023     if (!interface_ptr) {
01024         return -1;
01025     }
01026 
01027     interface_ptr->indirect_big_packet_threshold = indirect_big_packet_threshold;
01028     interface_ptr->max_indirect_big_packets_total = max_indirect_big_packets_total;
01029     interface_ptr->max_indirect_small_packets_per_child = max_indirect_small_packets_per_child;
01030 
01031     return 0;
01032 }