takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers adaptation_interface.c Source File

adaptation_interface.c

00001 /*
00002  * Copyright (c) 2016-2018, 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/MAC/mpx_api.h"
00039 #include "6LoWPAN/Mesh/mesh.h"
00040 #include "6LoWPAN/IPHC_Decode/iphc_decompress.h"
00041 #include "lowpan_adaptation_interface.h"
00042 #include "MLE/mle.h"
00043 #ifdef HAVE_RPL
00044 #include "RPL/rpl_data.h"
00045 #endif
00046 #include "6LoWPAN/ws/ws_common.h"
00047 #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
00048 #include "6LoWPAN/Thread/thread_common.h"
00049 #include "6LoWPAN/ws/ws_common.h"
00050 
00051 #define TRACE_GROUP "6lAd"
00052 
00053 typedef void (adaptation_etx_update_cb)(protocol_interface_info_entry_t *cur, buffer_t *buf, const mcps_data_conf_t *confirm);
00054 
00055 // #define EXTRA_DEBUG_EXTRA
00056 #ifdef EXTRA_DEBUG_EXTRA
00057 #define tr_debug_extra(...) tr_debug(__VA_ARGS__)
00058 #else
00059 #define tr_debug_extra(...)
00060 #endif
00061 
00062 typedef struct {
00063     uint16_t tag;   /*!< Fragmentation datagram TAG ID */
00064     uint16_t size;  /*!< Datagram Total Size (uncompressed) */
00065     uint16_t orig_size; /*!< Datagram Original Size (compressed) */
00066     uint16_t frag_max;  /*!< Maximum fragment size (MAC payload) */
00067     uint16_t offset; /*!< Data offset from datagram start */
00068     int16_t pattern; /*!< Size of compressed LoWPAN headers */
00069     uint16_t unfrag_ptr; /*!< Offset within buf of headers that precede the FRAG header */
00070     uint16_t frag_len;
00071     uint8_t unfrag_len; /*!< Length of headers that precede the FRAG header */
00072     bool fragmented_data:1;
00073     bool first_fragment:1;
00074     bool indirect_data:1;
00075     bool indirect_data_cached:1; /* Data cached for delayed transmission as mac request is already active */
00076     buffer_t *buf;
00077     uint8_t *fragmenter_buf;
00078     ns_list_link_t      link; /*!< List link entry */
00079 } fragmenter_tx_entry_t;
00080 
00081 
00082 typedef NS_LIST_HEAD (fragmenter_tx_entry_t, link) fragmenter_tx_list_t;
00083 
00084 typedef struct {
00085     int8_t interface_id;
00086     uint16_t local_frag_tag;
00087     uint8_t msduHandle;
00088     fragmenter_tx_list_t indirect_tx_queue;
00089     uint8_t *fragment_indirect_tx_buffer; //Used for write fragmentation header
00090     uint16_t mtu_size;
00091     fragmenter_tx_entry_t active_unicast_tx_buf; //Current active direct unicast tx process
00092     fragmenter_tx_entry_t active_broadcast_tx_buf; //Current active direct broadcast tx process
00093     buffer_list_t directTxQueue; //Waiting free tx process
00094     uint16_t indirect_big_packet_threshold;
00095     uint16_t max_indirect_big_packets_total;
00096     uint16_t max_indirect_small_packets_per_child;
00097     bool fragmenter_active; /*!< Fragmenter state */
00098     adaptation_etx_update_cb *etx_update_cb;
00099     mpx_api_t *mpx_api;
00100     uint16_t mpx_user_id;
00101     ns_list_link_t      link; /*!< List link entry */
00102 } fragmenter_interface_t;
00103 
00104 static NS_LIST_DEFINE(fragmenter_interface_list, fragmenter_interface_t, link);
00105 
00106 /* Adaptation interface local functions */
00107 static fragmenter_interface_t *lowpan_adaptation_interface_discover(int8_t interfaceId);
00108 
00109 /* Interface direct message pending queue functions */
00110 static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_ptr , buffer_t *buf);
00111 static buffer_t * lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur);
00112 
00113 /* Data direction and message length validation */
00114 static bool lowpan_adaptation_indirect_data_request(mac_neighbor_table_entry_t *mle_entry);
00115 static bool lowpan_adaptation_request_longer_than_mtu(protocol_interface_info_entry_t *cur, buffer_t *buf, fragmenter_interface_t *interface_ptr);
00116 
00117 /* Common data tx request process functions */
00118 static void lowpan_active_buffer_state_reset(fragmenter_tx_entry_t *tx_buffer);
00119 static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *interface_ptr);
00120 static fragmenter_tx_entry_t *lowpan_indirect_entry_allocate(uint16_t fragment_buffer_size);
00121 static fragmenter_tx_entry_t * lowpan_adaptation_tx_process_init(fragmenter_interface_t *interface_ptr, bool indirect, bool fragmented, bool is_unicast);
00122 static void lowpan_adaptation_data_request_primitiv_set(const buffer_t *buf, mcps_data_req_t *dataReq, protocol_interface_info_entry_t *cur);
00123 static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buffer_t *buf, fragmenter_tx_entry_t *tx_ptr, fragmenter_interface_t *interface_ptr);
00124 
00125 /* Tx confirmation local functions */
00126 static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf);
00127 static fragmenter_tx_entry_t * lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue);
00128 static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event);
00129 static uint8_t map_mlme_status_to_socket_event(uint8_t mlme_status);
00130 static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr);
00131 
00132 /* Fragmentation local functions */
00133 static int8_t lowpan_message_fragmentation_init(buffer_t *buf, fragmenter_tx_entry_t *frag_entry, protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr);
00134 static bool lowpan_message_fragmentation_message_write(const fragmenter_tx_entry_t *frag_entry, mcps_data_req_t *dataReq);
00135 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);
00136 
00137 static fragmenter_tx_entry_t* lowpan_adaptation_indirect_mac_data_request_active(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr);
00138 
00139 static void lowpan_adaptation_etx_update_cb(protocol_interface_info_entry_t *cur, buffer_t *buf, const mcps_data_conf_t *confirm)
00140 {
00141     switch (confirm->status) {
00142         case MLME_TX_NO_ACK:
00143         case MLME_NO_DATA:
00144         case MLME_SUCCESS:
00145             if (buf->link_specific.ieee802_15_4.requestAck) {
00146                 if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_MLE) {
00147                     bool success = false;
00148                     if (confirm->status == MLME_SUCCESS) {
00149                         success = true;
00150                     }
00151                     // Gets table entry
00152                     mac_neighbor_table_entry_t *neigh_table_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), buf->dst_sa .address  + PAN_ID_LEN, buf->dst_sa .addr_type );
00153                     if (neigh_table_ptr) {
00154                         etx_transm_attempts_update(cur->id, 1 + confirm->tx_retries , success, neigh_table_ptr->index );
00155                         // Updates ETX statistics
00156                         etx_storage_t * etx_entry = etx_storage_entry_get(cur->id, neigh_table_ptr->index );
00157                         if (etx_entry) {
00158                             if (neigh_table_ptr->link_role  == PRIORITY_PARENT_NEIGHBOUR) {
00159                                 protocol_stats_update(STATS_ETX_1ST_PARENT, etx_entry->etx >> 4);
00160                             } else if (neigh_table_ptr->link_role  == SECONDARY_PARENT_NEIGHBOUR) {
00161                                 protocol_stats_update(STATS_ETX_2ND_PARENT, etx_entry->etx >> 4);
00162                             }
00163                         }
00164                     }
00165                 }
00166             }
00167             break;
00168         default:
00169 
00170             break;
00171 
00172     }
00173 }
00174 
00175 
00176 //Discover
00177 static fragmenter_interface_t *lowpan_adaptation_interface_discover(int8_t interfaceId)
00178 {
00179 
00180     ns_list_foreach(fragmenter_interface_t, interface_ptr, &fragmenter_interface_list) {
00181         if (interfaceId == interface_ptr->interface_id) {
00182             return interface_ptr;
00183         }
00184     }
00185 
00186     return NULL;
00187 }
00188 
00189 static struct protocol_interface_info_entry *lowpan_adaptation_network_interface_discover(const mpx_api_t* api)
00190 {
00191 
00192     ns_list_foreach(fragmenter_interface_t, interface_ptr, &fragmenter_interface_list) {
00193         if (api == interface_ptr->mpx_api) {
00194             return protocol_stack_interface_info_get_by_id(interface_ptr->interface_id);
00195         }
00196     }
00197 
00198     return NULL;
00199 }
00200 
00201 
00202 static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_ptr , buffer_t *buf)
00203 {
00204     buffer_t *lower_priority_buf = NULL;
00205 
00206     ns_list_foreach(buffer_t, cur, &interface_ptr->directTxQueue) {
00207         if (cur->priority < buf->priority) {
00208             lower_priority_buf = cur;
00209             break;
00210         }
00211     }
00212 
00213     if (lower_priority_buf) {
00214         ns_list_add_before(&interface_ptr->directTxQueue, lower_priority_buf, buf);
00215     } else {
00216         ns_list_add_to_end(&interface_ptr->directTxQueue, buf);
00217     }
00218 }
00219 
00220 static buffer_t * lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur)
00221 {
00222     /* Currently this function is called only when data confirm is received for previously sent packet.
00223      * Data confirm has freed the corresponding "active buffer" and this function will look for new buffer to be set as active buffer.
00224      */
00225     ns_list_foreach_safe(buffer_t, buf, &interface_ptr->directTxQueue) {
00226         bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr);
00227         //Check that we not trig second active fragmentation process
00228         if (fragmented_needed && interface_ptr->fragmenter_active) {
00229             tr_debug("Do not trig Second active fragmentation");
00230         } else if ((buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_unicast_tx_buf.buf)
00231                 || (!buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_broadcast_tx_buf.buf)) {
00232             ns_list_remove(&interface_ptr->directTxQueue, buf);
00233             return buf;
00234         }
00235     }
00236     return NULL;
00237 }
00238 
00239 //fragmentation needed
00240 
00241 static bool lowpan_adaptation_request_longer_than_mtu(protocol_interface_info_entry_t *cur, buffer_t *buf, fragmenter_interface_t *interface_ptr)
00242 {
00243     uint_fast16_t overhead = mac_helper_frame_overhead(cur, buf);
00244 
00245     if (interface_ptr->mpx_api) {
00246         overhead += interface_ptr->mpx_api->mpx_headroom_size_get(interface_ptr->mpx_api, interface_ptr->mpx_user_id);
00247     }
00248 
00249 
00250     if (buffer_data_length(buf) > (int16_t)mac_helper_max_payload_size(cur, overhead)) {
00251         return true;
00252     } else {
00253         return false;
00254     }
00255 }
00256 
00257 static bool lowpan_adaptation_indirect_data_request(mac_neighbor_table_entry_t *entry_ptr)
00258 {
00259     if (entry_ptr && !(entry_ptr->rx_on_idle )) {
00260         return true;
00261     }
00262     return false;
00263 }
00264 
00265 
00266 static void lowpan_active_buffer_state_reset(fragmenter_tx_entry_t *tx_buffer)
00267 {
00268     if (tx_buffer->buf) {
00269         buffer_free(tx_buffer->buf);
00270         tx_buffer->buf = NULL;
00271     }
00272     tx_buffer->fragmented_data = false;
00273     tx_buffer->first_fragment = true;
00274 }
00275 
00276 static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf)
00277 {
00278 
00279     if (buf && buf->seq  == handle) {
00280         return true;
00281     }
00282 
00283 
00284     return false;
00285 }
00286 
00287 
00288 
00289 static fragmenter_tx_entry_t * lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue)
00290 {
00291     ns_list_foreach(fragmenter_tx_entry_t, entry, indirect_tx_queue) {
00292         if (entry->buf->seq == handle) {
00293             return entry;
00294         }
00295     }
00296     return NULL;
00297 }
00298 
00299 
00300 
00301 static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *interface_ptr)
00302 {
00303     bool valid_info = false;
00304     uint8_t handle;
00305     while(!valid_info) {
00306         handle = interface_ptr->msduHandle++;
00307         if (!lowpan_active_tx_handle_verify(handle,interface_ptr->active_unicast_tx_buf.buf)
00308                 && !lowpan_active_tx_handle_verify(handle,interface_ptr->active_broadcast_tx_buf.buf)
00309                 && !lowpan_indirect_tx_handle_verify(handle, &interface_ptr->indirect_tx_queue)) {
00310             valid_info = true;
00311         }
00312     }
00313     return handle;
00314 
00315 }
00316 
00317 static void lowpan_indirect_entry_free(fragmenter_tx_list_t *list , fragmenter_tx_entry_t *entry)
00318 {
00319     ns_list_remove(list, entry);
00320     if (entry->buf) {
00321         buffer_free(entry->buf);
00322     }
00323     ns_dyn_mem_free(entry->fragmenter_buf);
00324     ns_dyn_mem_free(entry);
00325 }
00326 
00327 static void lowpan_indirect_queue_free(fragmenter_tx_list_t *list)
00328 {
00329     while(!ns_list_is_empty(list)) {
00330         fragmenter_tx_entry_t *entry = ns_list_get_first(list);
00331         lowpan_indirect_entry_free(list, entry);
00332     }
00333 }
00334 
00335 
00336 int8_t lowpan_adaptation_interface_init(int8_t interface_id, uint16_t mac_mtu_size)
00337 {
00338     if (mac_mtu_size == 0) {
00339         return -2;
00340     }
00341     //Remove old interface
00342     lowpan_adaptation_interface_free(interface_id);
00343 
00344     //Allocate new
00345     fragmenter_interface_t *interface_ptr = ns_dyn_mem_alloc(sizeof(fragmenter_interface_t));
00346     uint8_t *tx_buffer = ns_dyn_mem_alloc(mac_mtu_size);
00347     if (!interface_ptr  || !tx_buffer) {
00348         ns_dyn_mem_free(interface_ptr);
00349         ns_dyn_mem_free(tx_buffer);
00350         return -1;
00351     }
00352 
00353     memset(interface_ptr, 0 ,sizeof(fragmenter_interface_t));
00354     interface_ptr->interface_id = interface_id;
00355     interface_ptr->fragment_indirect_tx_buffer = tx_buffer;
00356     interface_ptr->mtu_size = mac_mtu_size;
00357     interface_ptr->msduHandle = randLIB_get_8bit();
00358     interface_ptr->local_frag_tag = randLIB_get_16bit();
00359 
00360     ns_list_init(&interface_ptr->indirect_tx_queue);
00361     ns_list_init(&interface_ptr->directTxQueue);
00362 
00363     ns_list_add_to_end(&fragmenter_interface_list, interface_ptr);
00364 
00365     return 0;
00366 }
00367 
00368 void lowpan_adaptation_interface_etx_update_enable(int8_t interface_id)
00369 {
00370     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
00371     if (interface_ptr) {
00372         interface_ptr->etx_update_cb = lowpan_adaptation_etx_update_cb;
00373     }
00374 }
00375 
00376 int8_t lowpan_adaptation_interface_free(int8_t interface_id)
00377 {
00378     //Discover
00379     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
00380     if (!interface_ptr) {
00381         return -1;
00382     }
00383 
00384     ns_list_remove(&fragmenter_interface_list, interface_ptr);
00385     //free active tx process
00386     lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf);
00387     lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
00388 
00389     //Free Indirect entry
00390     lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue);
00391 
00392     buffer_free_list(&interface_ptr->directTxQueue);
00393 
00394     //Free Dynamic allocated entries
00395     ns_dyn_mem_free(interface_ptr->fragment_indirect_tx_buffer);
00396     ns_dyn_mem_free(interface_ptr);
00397 
00398     return 0;
00399 }
00400 
00401 
00402 int8_t lowpan_adaptation_interface_reset(int8_t interface_id)
00403 {
00404     //Discover
00405     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
00406     if (!interface_ptr) {
00407         return -1;
00408     }
00409 
00410     //free active tx process
00411     lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf);
00412     lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf);
00413     //Clean fragmented message flag
00414     interface_ptr->fragmenter_active = false;
00415 
00416     //Free Indirect entry
00417     lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue);
00418 
00419     buffer_free_list(&interface_ptr->directTxQueue);
00420 
00421     return 0;
00422 }
00423 
00424 static void lowpan_adaptation_mpx_data_confirm(const mpx_api_t* api, const struct mcps_data_conf_s *data)
00425 {
00426     protocol_interface_info_entry_t * interface = lowpan_adaptation_network_interface_discover(api);
00427 
00428     lowpan_adaptation_interface_tx_confirm(interface, data);
00429 }
00430 
00431 static void lowpan_adaptation_mpx_data_indication(const mpx_api_t* api, const struct mcps_data_ind_s *data)
00432 {
00433     protocol_interface_info_entry_t * interface = lowpan_adaptation_network_interface_discover(api);
00434     lowpan_adaptation_interface_data_ind(interface, data);
00435 }
00436 
00437 
00438 
00439 
00440 int8_t lowpan_adaptation_interface_mpx_register(int8_t interface_id, struct mpx_api_s *mpx_api, uint16_t mpx_user_id)
00441 {
00442     //Discover
00443     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
00444     if (!interface_ptr) {
00445         return -1;
00446     }
00447     if (!mpx_api && interface_ptr->mpx_api) {
00448         //Disable Data Callbacks from MPX Class
00449         interface_ptr->mpx_api->mpx_user_registration(interface_ptr->mpx_api, NULL, NULL, interface_ptr->mpx_user_id);
00450     }
00451 
00452     interface_ptr->mpx_api = mpx_api;
00453     interface_ptr->mpx_user_id = mpx_user_id;
00454 
00455     if (interface_ptr->mpx_api) {
00456         //Register MPX callbacks: confirmation and indication
00457         interface_ptr->mpx_api->mpx_user_registration(interface_ptr->mpx_api, lowpan_adaptation_mpx_data_confirm, lowpan_adaptation_mpx_data_indication, interface_ptr->mpx_user_id);
00458     }
00459     return 0;
00460 }
00461 
00462 
00463 static fragmenter_tx_entry_t *lowpan_indirect_entry_allocate(uint16_t fragment_buffer_size)
00464 {
00465     fragmenter_tx_entry_t *indirec_entry = ns_dyn_mem_temporary_alloc(sizeof(fragmenter_tx_entry_t));
00466     if (!indirec_entry) {
00467         return NULL;
00468     }
00469 
00470     if (fragment_buffer_size) {
00471         indirec_entry->fragmenter_buf = ns_dyn_mem_temporary_alloc(fragment_buffer_size);
00472         if (!indirec_entry->fragmenter_buf) {
00473             ns_dyn_mem_free(indirec_entry);
00474             return NULL;
00475         }
00476     } else {
00477         indirec_entry->fragmenter_buf = NULL;
00478     }
00479 
00480 
00481     indirec_entry->buf = NULL;
00482     indirec_entry->fragmented_data = false;
00483     indirec_entry->first_fragment = true;
00484     indirec_entry->indirect_data_cached = false;
00485 
00486     return indirec_entry;
00487 }
00488 
00489 static int8_t lowpan_message_fragmentation_init(buffer_t *buf, fragmenter_tx_entry_t *frag_entry, protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr)
00490 {
00491     uint8_t *ptr;
00492     uint16_t uncompressed_size;
00493 
00494     /* Look for pre-fragmentation headers - strip off and store away */
00495     frag_entry->unfrag_ptr = buf->buf_ptr ;
00496     frag_entry->unfrag_len = 0;
00497     ptr = buffer_data_pointer(buf);
00498 
00499     if ((ptr[0] & LOWPAN_MESH_MASK) == LOWPAN_MESH) {
00500         uint_fast8_t size = mesh_header_len_from_type_byte(ptr[0]);
00501         ptr += size;
00502         buf->buf_ptr  += size;
00503     }
00504 
00505     if (ptr[0] == LOWPAN_DISPATCH_BC0) {
00506         ptr += 2;
00507         buf->buf_ptr  += 2;
00508     }
00509 
00510     frag_entry->unfrag_len = buf->buf_ptr  - frag_entry->unfrag_ptr;
00511 
00512     frag_entry->pattern = iphc_header_scan(buf, &uncompressed_size);
00513     frag_entry->size = buffer_data_length(buf);
00514     frag_entry->orig_size = frag_entry->size;
00515     frag_entry->size += (uncompressed_size - frag_entry->pattern);
00516 
00517     uint_fast16_t overhead = mac_helper_frame_overhead(cur, buf);
00518     if (interface_ptr->mpx_api) {
00519         overhead += interface_ptr->mpx_api->mpx_headroom_size_get(interface_ptr->mpx_api, interface_ptr->mpx_user_id);
00520     }
00521 
00522     frag_entry->frag_max = mac_helper_max_payload_size(cur, overhead);
00523 
00524 
00525     /* RFC 4944 says MTU and hence maximum size here is 1280, but that's
00526      * arbitrary, and some have argued that 6LoWPAN should have a larger
00527      * MTU, to avoid the need for IP fragmentation. So we don't enforce
00528      * that, leaving MTU decisions to upper layer config, and only look
00529      * for the "real" MTU from the FRAG header format, which would allow up
00530      * to 0x7FF (2047).
00531      */
00532     if (frag_entry->size > LOWPAN_HARD_MTU_LIMIT) {
00533         tr_error("Packet too big");
00534         return -1;
00535     }
00536 
00537     frag_entry->offset = uncompressed_size / 8;
00538     frag_entry->frag_len = frag_entry->pattern;
00539     if (frag_entry->unfrag_len + 4 + frag_entry->frag_len > frag_entry->frag_max) {
00540         tr_error("Too long 6LoWPAN header for fragment");
00541         return -1;
00542     }
00543 
00544     /* Now, frag_len is compressed payload bytes (just IPHC headers), and
00545      * frag_ptr->offset is uncompressed payload 8-octet units (just uncompressed
00546      * IPHC headers). Add post-IPHC payload to bring total compressed size up
00547      * to maximum fragment size.
00548      */
00549     while (frag_entry->unfrag_len + 4 + frag_entry->frag_len + 8 <= frag_entry->frag_max) {
00550         frag_entry->offset++;
00551         frag_entry->frag_len += 8;
00552     }
00553     frag_entry->fragmented_data = true;
00554 
00555     return 0;
00556 
00557 }
00558 
00559 /**
00560  * Return true when there is more fragmented packet for this message
00561  */
00562 static bool lowpan_message_fragmentation_message_write(const fragmenter_tx_entry_t *frag_entry, mcps_data_req_t *dataReq)
00563 {
00564     uint8_t *ptr = dataReq->msdu;
00565     if (frag_entry->unfrag_len) {
00566         memcpy(ptr, frag_entry->buf->buf  + frag_entry->unfrag_ptr, frag_entry->unfrag_len);
00567         ptr += frag_entry->unfrag_len;
00568     }
00569     if (frag_entry->first_fragment) {
00570         ptr = common_write_16_bit(((uint16_t) LOWPAN_FRAG1 << 8) | frag_entry->size, ptr);
00571         ptr = common_write_16_bit(frag_entry->tag, ptr);
00572     } else {
00573         ptr = common_write_16_bit(((uint16_t) LOWPAN_FRAGN << 8) | frag_entry->size, ptr);
00574         ptr = common_write_16_bit(frag_entry->tag, ptr);
00575         *ptr++ = frag_entry->offset;
00576     }
00577     memcpy(ptr, buffer_data_pointer(frag_entry->buf), frag_entry->frag_len);
00578     ptr += frag_entry->frag_len;
00579     dataReq->msduLength = ptr - dataReq->msdu;
00580     return frag_entry->offset * 8 + frag_entry->frag_len < frag_entry->size;
00581 }
00582 
00583 static fragmenter_tx_entry_t * lowpan_adaptation_tx_process_init(fragmenter_interface_t *interface_ptr, bool indirect, bool fragmented, bool is_unicast)
00584 {
00585     fragmenter_tx_entry_t *tx_entry;
00586     if (!indirect) {
00587         if (is_unicast) {
00588             tx_entry = &interface_ptr->active_unicast_tx_buf;
00589         } else {
00590             tx_entry = &interface_ptr->active_broadcast_tx_buf;
00591         }
00592         tx_entry->fragmenter_buf = interface_ptr->fragment_indirect_tx_buffer;
00593     } else {
00594         if (fragmented) {
00595             tx_entry = lowpan_indirect_entry_allocate(interface_ptr->mtu_size);
00596         } else {
00597             tx_entry = lowpan_indirect_entry_allocate(0);
00598         }
00599     }
00600 
00601     if (!tx_entry) {
00602         return NULL;
00603     }
00604 
00605     lowpan_active_buffer_state_reset(tx_entry);
00606 
00607     tx_entry->indirect_data = indirect;
00608 
00609     return tx_entry;
00610 }
00611 
00612 buffer_t * lowpan_adaptation_data_process_tx_preprocess(protocol_interface_info_entry_t *cur, buffer_t *buf)
00613 {
00614     mac_neighbor_table_entry_t *neigh_entry_ptr = NULL;
00615 
00616     //Validate is link known and set indirect, datareq and security key id mode
00617     if (buf->dst_sa .addr_type  == ADDR_NONE ) {
00618         goto tx_error_handler;
00619     }
00620 
00621     /* If MLE is enabled, we will talk if we have an MLE association */
00622     if (buf->dst_sa .addr_type  == ADDR_802_15_4_LONG  ) {
00623         neigh_entry_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), buf->dst_sa .address  + 2, buf->dst_sa .addr_type );
00624 
00625     } else if(buf->dst_sa .addr_type  == ADDR_802_15_4_SHORT  && (common_read_16_bit(buf->dst_sa .address  + 2)) != 0xffff) {
00626         neigh_entry_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), buf->dst_sa .address  + 2, buf->dst_sa .addr_type );
00627     }
00628 
00629     //Validate neighbour
00630     if (!buf->options .ll_security_bypass_tx  && neigh_entry_ptr) {
00631 
00632         if (neigh_entry_ptr->connected_device  ||  neigh_entry_ptr->trusted_device ) {
00633 
00634         } else {
00635             //tr_warn("Drop TX to unassociated %s", trace_sockaddr(&buf->dst_sa, true));
00636             goto tx_error_handler;
00637         }
00638     }
00639 
00640     //Check indirect
00641 
00642 
00643     if (addr_check_broadcast(buf->dst_sa .address , buf->dst_sa .addr_type ) == eOK) {
00644         buf->dst_sa .addr_type  = ADDR_802_15_4_SHORT ;
00645         buf->dst_sa .address [2] = 0xff;
00646         buf->dst_sa .address [3] = 0xff;
00647         buf->link_specific.ieee802_15_4.indirectTxProcess = false;
00648         buf->link_specific.ieee802_15_4.requestAck = false;
00649     } else {
00650         buf->link_specific.ieee802_15_4.requestAck = true;
00651         buf->link_specific.ieee802_15_4.indirectTxProcess = lowpan_adaptation_indirect_data_request(neigh_entry_ptr);
00652     }
00653 
00654     if (buf->link_specific.ieee802_15_4.key_id_mode != B_SECURITY_KEY_ID_2) {
00655 
00656         if (!buf->link_specific.ieee802_15_4.requestAck ) {
00657             buf->link_specific.ieee802_15_4.key_id_mode = B_SECURITY_KEY_ID_MODE_DEFAULT;
00658         } else if (ws_info(cur) || (neigh_entry_ptr && !neigh_entry_ptr->trusted_device )) {
00659             buf->link_specific.ieee802_15_4.key_id_mode  = B_SECURITY_KEY_ID_MODE_DEFAULT;
00660         } else {
00661             buf->link_specific.ieee802_15_4.key_id_mode  = B_SECURITY_KEY_ID_IMPLICIT;
00662         }
00663     }
00664 
00665     return buf;
00666 
00667     tx_error_handler:
00668     if (neigh_entry_ptr && neigh_entry_ptr->nud_active ) {
00669         mac_neighbor_info(cur)->active_nud_process--;
00670         neigh_entry_ptr->nud_active  = false;
00671 
00672     }
00673     socket_tx_buffer_event_and_free(buf, SOCKET_TX_FAIL);
00674     return NULL;
00675 
00676 }
00677 
00678 static void lowpan_adaptation_data_request_primitiv_set(const buffer_t *buf, mcps_data_req_t *dataReq, protocol_interface_info_entry_t *cur)
00679 {
00680     memset(dataReq, 0, sizeof(mcps_data_req_t));
00681 
00682     //Check do we need fragmentation
00683 
00684     dataReq->InDirectTx = buf->link_specific.ieee802_15_4.indirectTxProcess;
00685     dataReq->TxAckReq = buf->link_specific.ieee802_15_4.requestAck;
00686     dataReq->SrcAddrMode = buf->src_sa .addr_type ;
00687     dataReq->DstAddrMode = buf->dst_sa .addr_type ;
00688     memcpy(dataReq->DstAddr, &buf->dst_sa .address [2], 8);
00689 
00690     if (buf->link_specific.ieee802_15_4.useDefaultPanId) {
00691         dataReq->DstPANId = mac_helper_panid_get(cur);
00692     } else {
00693         dataReq->DstPANId = buf->link_specific.ieee802_15_4.dstPanId;
00694     }
00695 
00696     //Allocate message msdu handle
00697     dataReq->msduHandle = buf->seq ;
00698 
00699     //Set Messages
00700     if (!buf->options .ll_security_bypass_tx ) {
00701         dataReq->Key.SecurityLevel = mac_helper_default_security_level_get(cur);
00702         if (dataReq->Key.SecurityLevel) {
00703             switch (buf->link_specific.ieee802_15_4.key_id_mode) {
00704                 case B_SECURITY_KEY_ID_MODE_DEFAULT:
00705                     dataReq->Key.KeyIndex = mac_helper_default_key_index_get(cur);
00706                     dataReq->Key.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur);
00707                     break;
00708                 case B_SECURITY_KEY_ID_IMPLICIT:
00709                     dataReq->Key.KeyIdMode = MAC_KEY_ID_MODE_IMPLICIT;
00710                     break;
00711 
00712                 case B_SECURITY_KEY_ID_2:
00713                     dataReq->Key.KeyIndex = 0xff;
00714                     dataReq->Key.KeyIdMode = MAC_KEY_ID_MODE_SRC4_IDX;
00715                     common_write_32_bit(0xffffffff, dataReq->Key.Keysource);
00716                     break;
00717             }
00718         }
00719     }
00720 }
00721 
00722 static bool lowpan_adaptation_indirect_cache_sanity_check(protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr)
00723 {
00724     fragmenter_tx_entry_t *active_tx_entry;
00725     ns_list_foreach(fragmenter_tx_entry_t, fragmenter_tx_entry, &interface_ptr->indirect_tx_queue) {
00726         if (fragmenter_tx_entry->indirect_data_cached == false) {
00727             // active entry, jump to next one
00728             continue;
00729         }
00730 
00731         // cached entry found, check if it has pending data reguest
00732         active_tx_entry = lowpan_adaptation_indirect_mac_data_request_active(interface_ptr, fragmenter_tx_entry);
00733 
00734         if (active_tx_entry == NULL) {
00735             // entry is in cache and is not sent to mac => trigger this
00736             tr_debug_extra("sanity check, push seq %d to addr %s", fragmenter_tx_entry->buf->seq, trace_ipv6(fragmenter_tx_entry->buf->dst_sa.address));
00737             fragmenter_tx_entry->indirect_data_cached = false;
00738             lowpan_data_request_to_mac(cur, fragmenter_tx_entry->buf, fragmenter_tx_entry, interface_ptr);
00739             return true;
00740         }
00741     }
00742 
00743     return false;
00744 }
00745 
00746 static bool lowpan_adaptation_indirect_cache_trigger(protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr)
00747 {
00748     tr_debug_extra("lowpan_adaptation_indirect_cache_trigger()");
00749 
00750     if (ns_list_count(&interface_ptr->indirect_tx_queue) == 0) {
00751         return false;
00752     }
00753 
00754     /* Trigger first cached entry */
00755     ns_list_foreach(fragmenter_tx_entry_t, fragmenter_tx_entry, &interface_ptr->indirect_tx_queue) {
00756         if (fragmenter_tx_entry->indirect_data_cached) {
00757             if (addr_ipv6_equal(tx_ptr->buf->dst_sa.address, fragmenter_tx_entry->buf->dst_sa.address)) {
00758                 tr_debug_extra("pushing seq %d to addr %s", fragmenter_tx_entry->buf->seq, trace_ipv6(fragmenter_tx_entry->buf->dst_sa.address));
00759                 fragmenter_tx_entry->indirect_data_cached = false;
00760                 lowpan_data_request_to_mac(cur, fragmenter_tx_entry->buf, fragmenter_tx_entry, interface_ptr);
00761                 return true;
00762             }
00763         }
00764     }
00765 
00766     /* Sanity check, If nothing can be triggered from own address, check cache queue */
00767     return lowpan_adaptation_indirect_cache_sanity_check(cur, interface_ptr);
00768 }
00769 
00770 static fragmenter_tx_entry_t* lowpan_adaptation_indirect_mac_data_request_active(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr)
00771 {
00772     ns_list_foreach(fragmenter_tx_entry_t, fragmenter_tx_entry, &interface_ptr->indirect_tx_queue) {
00773         if (fragmenter_tx_entry->indirect_data_cached == false) {
00774             if (addr_ipv6_equal(tx_ptr->buf->dst_sa.address, fragmenter_tx_entry->buf->dst_sa.address)) {
00775                 tr_debug_extra("active seq: %d", fragmenter_tx_entry->buf->seq);
00776                 return fragmenter_tx_entry;
00777             }
00778         }
00779     }
00780     return NULL;
00781 }
00782 
00783 static fragmenter_tx_entry_t* lowpan_adaptation_indirect_first_cached_request_get(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr)
00784 {
00785     ns_list_foreach(fragmenter_tx_entry_t, fragmenter_tx_entry, &interface_ptr->indirect_tx_queue) {
00786         if (fragmenter_tx_entry->indirect_data_cached == true) {
00787             if (addr_ipv6_equal(tx_ptr->buf->dst_sa.address, fragmenter_tx_entry->buf->dst_sa.address)) {
00788                 tr_debug_extra("first cached seq: %d", fragmenter_tx_entry->buf->seq);
00789                 return fragmenter_tx_entry;
00790             }
00791         }
00792     }
00793     return NULL;
00794 }
00795 
00796 static void lowpan_adaptation_make_room_for_small_packet(protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr, mac_neighbor_table_entry_t *neighbour_to_count)
00797 {
00798     if (interface_ptr->max_indirect_small_packets_per_child == 0) {
00799         return;
00800     }
00801 
00802     uint_fast16_t count = 0;
00803 
00804     ns_list_foreach_reverse_safe(fragmenter_tx_entry_t, tx_entry, &interface_ptr->indirect_tx_queue) {
00805         mac_neighbor_table_entry_t *tx_neighbour = mac_neighbor_table_address_discover(mac_neighbor_info(cur), tx_entry->buf->dst_sa.address + 2, tx_entry->buf->dst_sa.addr_type);
00806         if (tx_neighbour == neighbour_to_count && buffer_data_length(tx_entry->buf) <= interface_ptr->indirect_big_packet_threshold) {
00807             if (++count >= interface_ptr->max_indirect_small_packets_per_child) {
00808                 lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry);
00809             }
00810         }
00811     }
00812 }
00813 
00814 static void lowpan_adaptation_make_room_for_big_packet(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr)
00815 {
00816     if (interface_ptr->max_indirect_big_packets_total == 0) {
00817         return;
00818     }
00819 
00820     uint_fast16_t count = 0;
00821 
00822     ns_list_foreach_reverse_safe(fragmenter_tx_entry_t, tx_entry, &interface_ptr->indirect_tx_queue) {
00823         if (buffer_data_length(tx_entry->buf) > interface_ptr->indirect_big_packet_threshold) {
00824             if (++count >= interface_ptr->max_indirect_big_packets_total) {
00825                 tr_debug_extra("free seq: %d", tx_entry->buf->seq);
00826                 lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry);
00827             }
00828         }
00829     }
00830 }
00831 
00832 static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buffer_t *buf, fragmenter_tx_entry_t *tx_ptr, fragmenter_interface_t *interface_ptr)
00833 {
00834     mcps_data_req_t dataReq;
00835 
00836     lowpan_adaptation_data_request_primitiv_set(buf, &dataReq, cur);
00837     if (tx_ptr->fragmented_data) {
00838         dataReq.msdu = tx_ptr->fragmenter_buf;
00839         //Call fragmenter
00840         bool more_fragments = lowpan_message_fragmentation_message_write(tx_ptr, &dataReq);
00841         if (dataReq.InDirectTx) {
00842             dataReq.PendingBit |= more_fragments;
00843         }
00844     } else {
00845         dataReq.msduLength = buffer_data_length(buf);
00846         dataReq.msdu = buffer_data_pointer(buf);
00847     }
00848     if (buf->link_specific.ieee802_15_4.rf_channel_switch) {
00849         //Switch channel if selected channel is different
00850         if (cur->mac_parameters->mac_channel != buf->link_specific.ieee802_15_4.selected_channel) {
00851             uint8_t channel = cur->mac_parameters->mac_channel;
00852             mac_helper_mac_channel_set(cur, buf->link_specific.ieee802_15_4.selected_channel);
00853             buf->link_specific.ieee802_15_4.selected_channel = channel;
00854         } else {
00855             buf->link_specific.ieee802_15_4.rf_channel_switch = false;
00856         }
00857     }
00858 
00859     if (interface_ptr->mpx_api) {
00860         interface_ptr->mpx_api->mpx_data_request(interface_ptr->mpx_api, &dataReq, interface_ptr->mpx_user_id);
00861     } else {
00862         cur->mac_api->mcps_data_req(cur->mac_api, &dataReq);
00863     }
00864 }
00865 
00866 int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buffer_t *buf)
00867 {
00868     if (!buf) {
00869         return -1;
00870     }
00871 
00872     if (!cur || !cur->mac_api || !cur->mac_api->mcps_data_req) {
00873         goto tx_error_handler;
00874     }
00875 
00876     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
00877     if (!interface_ptr) {
00878         goto tx_error_handler;
00879     }
00880 
00881     //Check packet size
00882     bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr);
00883     bool is_unicast = buf->link_specific.ieee802_15_4.requestAck;
00884     bool indirect = buf->link_specific.ieee802_15_4.indirectTxProcess;
00885     if (!indirect) {
00886         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)) {
00887             lowpan_adaptation_tx_queue_write(interface_ptr, buf);
00888             return 0; //Return here
00889         }
00890     }
00891 
00892     //Allocate Handle
00893     buf->seq  = lowpan_data_request_unique_handle_get(interface_ptr);
00894 
00895     if (buf->options .ll_sec_bypass_frag_deny  && fragmented_needed) {
00896         // force security for fragmented packets
00897         buf->options .ll_security_bypass_tx  = false;
00898     }
00899 
00900     fragmenter_tx_entry_t *tx_ptr = lowpan_adaptation_tx_process_init(interface_ptr, indirect, fragmented_needed, is_unicast);
00901     if (!tx_ptr) {
00902         goto tx_error_handler;
00903     }
00904 
00905     tx_ptr->buf = buf;
00906 
00907     if (fragmented_needed) {
00908         //Fragmentation init
00909         if (lowpan_message_fragmentation_init(buf, tx_ptr, cur, interface_ptr) ) {
00910             tr_error("Fragment init fail");
00911             if (indirect) {
00912                 ns_dyn_mem_free(tx_ptr->fragmenter_buf);
00913                 ns_dyn_mem_free(tx_ptr);
00914             }
00915             goto tx_error_handler;
00916         }
00917 
00918         tx_ptr->tag = interface_ptr->local_frag_tag++;
00919         if (!indirect) {
00920             interface_ptr->fragmenter_active = true;
00921         }
00922     }
00923 
00924     if (indirect) {
00925         //Add to indirectQUue
00926         fragmenter_tx_entry_t *tx_ptr_cached;
00927         mac_neighbor_table_entry_t *neigh_entry_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), buf->dst_sa .address  + PAN_ID_LEN, buf->dst_sa .addr_type );
00928         if (neigh_entry_ptr) {
00929             buf->link_specific.ieee802_15_4.indirectTTL = (uint32_t) neigh_entry_ptr->link_lifetime  * 1000;
00930         } else {
00931             buf->link_specific.ieee802_15_4.indirectTTL = cur->mac_parameters->mac_in_direct_entry_timeout;
00932         }
00933 
00934         tr_debug_extra("indirect seq: %d, addr=%s", tx_ptr->buf->seq, trace_ipv6(buf->dst_sa .address ));
00935 
00936         // Make room for new message if needed */
00937         if (buffer_data_length(buf) <= interface_ptr->indirect_big_packet_threshold) {
00938             lowpan_adaptation_make_room_for_small_packet(cur, interface_ptr, neigh_entry_ptr);
00939         } else {
00940             lowpan_adaptation_make_room_for_big_packet(cur, interface_ptr);
00941         }
00942 
00943         if (lowpan_adaptation_indirect_mac_data_request_active(interface_ptr, tx_ptr)) {
00944             // mac is handling previous data request, add new one to be cached */
00945             tr_debug_extra("caching seq: %d", tx_ptr->buf->seq);
00946             tx_ptr->indirect_data_cached = true;
00947         }
00948 
00949         ns_list_add_to_end(&interface_ptr->indirect_tx_queue, tx_ptr);
00950 
00951         // Check if current message can be delivered to MAC or should some cached message be delivered first
00952         tx_ptr_cached = lowpan_adaptation_indirect_first_cached_request_get(interface_ptr, tx_ptr);
00953         if (tx_ptr->indirect_data_cached == false && tx_ptr_cached) {
00954             tr_debug_extra("sending cached seq: %d", tx_ptr_cached->buf->seq);
00955             // set current message to cache
00956             tx_ptr->indirect_data_cached = true;
00957             // swap entries
00958             tx_ptr = tx_ptr_cached;
00959             tx_ptr->indirect_data_cached = false;
00960             buf = tx_ptr_cached->buf ;
00961         } else if (tx_ptr->indirect_data_cached == true) {
00962             // There is mac data request ongoing and new req was sent to cache
00963             return 0;
00964         }
00965     }
00966 
00967     lowpan_data_request_to_mac(cur, buf, tx_ptr, interface_ptr);
00968     return 0;
00969 
00970 
00971 tx_error_handler:
00972     socket_tx_buffer_event_and_free(buf, SOCKET_NO_RAM);
00973     return -1;
00974 
00975 }
00976 
00977 static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr)
00978 {
00979     if (!tx_ptr->fragmented_data) {
00980         if (tx_ptr->buf->ip_routed_up) {
00981             protocol_stats_update(STATS_IP_ROUTE_UP, buffer_data_length(tx_ptr->buf));
00982         } else {
00983             protocol_stats_update(STATS_IP_TX_COUNT, buffer_data_length(tx_ptr->buf));
00984         }
00985         return true;
00986     }
00987 
00988 
00989 
00990     //Update data pointer by last packet length
00991     buffer_data_strip_header(tx_ptr->buf, tx_ptr->frag_len);
00992     //Update offset
00993     if (!tx_ptr->first_fragment) {
00994         tx_ptr->offset += tx_ptr->frag_len / 8;
00995     } else {
00996         tx_ptr->first_fragment = false;
00997     }
00998 
00999     /* Check Is still Data what have to send */
01000     tx_ptr->frag_len = buffer_data_length(tx_ptr->buf);
01001 
01002 
01003     if (tx_ptr->frag_len == 0) {
01004         //Release current data
01005         if (tx_ptr->buf->ip_routed_up) {
01006             protocol_stats_update(STATS_IP_ROUTE_UP, tx_ptr->orig_size);
01007         } else {
01008             protocol_stats_update(STATS_IP_TX_COUNT, tx_ptr->orig_size);
01009         }
01010         return true;
01011     }
01012 
01013     //Continue Process
01014 
01015     if (tx_ptr->unfrag_len + 5 + tx_ptr->frag_len > tx_ptr->frag_max) {
01016         tx_ptr->frag_len = tx_ptr->frag_max - 5 - tx_ptr->unfrag_len;
01017         tx_ptr->frag_len &= ~7;
01018     }
01019 
01020     return false;
01021 }
01022 
01023 static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event)
01024 {
01025     buffer_t *buf = tx_ptr->buf ;
01026     tx_ptr->buf = NULL;
01027     if (buf->link_specific.ieee802_15_4.indirectTxProcess) {
01028         //release from list and free entry
01029         lowpan_indirect_entry_free(&interface_ptr->indirect_tx_queue, tx_ptr);
01030     }
01031 
01032     socket_tx_buffer_event_and_free(buf, socket_event);
01033 }
01034 
01035 
01036 int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *cur, const mcps_data_conf_t *confirm)
01037 {
01038     if( !cur || !confirm ){
01039         return -1;
01040     }
01041 
01042     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
01043     if (!interface_ptr) {
01044         return -1;
01045     }
01046 
01047     //Check first
01048     fragmenter_tx_entry_t *tx_ptr;
01049     bool active_direct_confirm;
01050     bool is_unicast = true;
01051 
01052     if (lowpan_active_tx_handle_verify(confirm->msduHandle,interface_ptr->active_unicast_tx_buf.buf)) {
01053         active_direct_confirm = true;
01054         tx_ptr = &interface_ptr->active_unicast_tx_buf;
01055     } else if (lowpan_active_tx_handle_verify(confirm->msduHandle,interface_ptr->active_broadcast_tx_buf.buf)) {
01056         active_direct_confirm = true;
01057         tx_ptr = &interface_ptr->active_broadcast_tx_buf;
01058         is_unicast = false;
01059     } else {
01060         active_direct_confirm = false;
01061         tx_ptr = lowpan_indirect_tx_handle_verify(confirm->msduHandle, &interface_ptr->indirect_tx_queue);
01062     }
01063 
01064     if (!tx_ptr) {
01065         tr_error("No data request for this confirmation %u", confirm->msduHandle);
01066         return -1;
01067     }
01068 
01069     //Check status for
01070     buffer_t *buf = tx_ptr->buf ;
01071 
01072     //Indirect data expiration
01073     if (confirm->status == MLME_TRANSACTION_EXPIRED && !active_direct_confirm) {
01074         if (buf->link_specific.ieee802_15_4.indirectTTL > 7000)
01075         {
01076             buf->link_specific.ieee802_15_4.indirectTTL -= 7000;
01077             //Push Back to MAC
01078             lowpan_data_request_to_mac(cur, buf, tx_ptr, interface_ptr);
01079             return 0;
01080         }
01081     }
01082 
01083     if (interface_ptr->etx_update_cb) {
01084         interface_ptr->etx_update_cb(cur, buf, confirm);
01085     }
01086 
01087     //Switch original channel back
01088     if (buf->link_specific.ieee802_15_4.rf_channel_switch) {
01089         mac_helper_mac_channel_set(cur, buf->link_specific.ieee802_15_4.selected_channel);
01090         buf->link_specific.ieee802_15_4.rf_channel_switch = false;
01091     }
01092 
01093     switch (confirm->status) {
01094 
01095         case MLME_BUSY_CHAN:
01096             lowpan_data_request_to_mac(cur, buf, tx_ptr, interface_ptr);
01097             break;
01098         case MLME_SUCCESS:
01099 
01100             //Check is there more packets
01101             if (lowpan_adaptation_tx_process_ready(tx_ptr)) {
01102                 bool triggered_from_indirect_cache = false;
01103                 if (tx_ptr->fragmented_data && active_direct_confirm) {
01104                     //Clean
01105                     interface_ptr->fragmenter_active = false;
01106                 }
01107 
01108                 if (tx_ptr->buf->link_specific.ieee802_15_4.indirectTxProcess) {
01109                     triggered_from_indirect_cache = lowpan_adaptation_indirect_cache_trigger(cur, interface_ptr, tx_ptr);
01110                 }
01111 
01112                 lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, map_mlme_status_to_socket_event(confirm->status));
01113 
01114                 if (triggered_from_indirect_cache) {
01115                     return 0;
01116                 }
01117             } else {
01118                 lowpan_data_request_to_mac(cur, buf, tx_ptr, interface_ptr);
01119             }
01120 
01121             break;
01122         case MLME_TX_NO_ACK:
01123         case MLME_SECURITY_FAIL:
01124         case MLME_TRANSACTION_EXPIRED:
01125         default:
01126             tr_error("MCPS Data fail by status %u", confirm->status);
01127             if (buf->dst_sa .addr_type  == ADDR_802_15_4_SHORT ) {
01128                 tr_info("Dest addr: %x", common_read_16_bit(buf->dst_sa .address +2));
01129             } else if (buf->dst_sa .addr_type  == ADDR_802_15_4_LONG ) {
01130                 tr_info("Dest addr: %s", trace_array(buf->dst_sa .address +2, 8));
01131             }
01132 
01133 #ifdef HAVE_RPL
01134             if (confirm->status == MLME_TX_NO_ACK) {
01135                 if (buf->route && rpl_data_is_rpl_parent_route(buf->route->route_info.source)) {
01136                     protocol_stats_update(STATS_RPL_PARENT_TX_FAIL, 1);
01137                 }
01138             }
01139 #endif
01140             if (tx_ptr->fragmented_data) {
01141                 tx_ptr->buf->buf_ptr = tx_ptr->buf->buf_end;
01142                 tx_ptr->buf->buf_ptr -= tx_ptr->orig_size;
01143                 if (active_direct_confirm) {
01144                     interface_ptr->fragmenter_active = false;
01145                 }
01146             }
01147 
01148             lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, map_mlme_status_to_socket_event(confirm->status));
01149             break;
01150 
01151     }
01152 
01153     if ((is_unicast && !interface_ptr->active_unicast_tx_buf.buf) || (!is_unicast && !interface_ptr->active_broadcast_tx_buf.buf)) {
01154         //Read Buffer and trig next direct request
01155         lowpan_adaptation_interface_tx(cur, lowpan_adaptation_tx_queue_read(interface_ptr, cur));
01156     }
01157 
01158     return 0;
01159 
01160 }
01161 
01162 static bool mac_data_is_broadcast_addr(const sockaddr_t *addr)
01163 {
01164     return (addr->addr_type  == ADDR_802_15_4_SHORT ) &&
01165            (addr->address [2] == 0xFF && addr->address [3] == 0xFF);
01166 }
01167 
01168 static bool mcps_data_indication_neighbor_validate(protocol_interface_info_entry_t *cur, const sockaddr_t *addr)
01169 {
01170     if (thread_info(cur) || ws_info(cur) || (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_MLE)) {
01171         mac_neighbor_table_entry_t * neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), addr->address  + 2, addr->addr_type );
01172         if (neighbor && (neighbor->connected_device  ||  neighbor->trusted_device )) {
01173             return true;
01174         }
01175 
01176         /* Otherwise, we don't know them */
01177         return false;
01178     } else {
01179         //6lowpan without MLE don't can't do validation
01180         return true;
01181     }
01182 
01183 }
01184 
01185 void lowpan_adaptation_interface_data_ind(protocol_interface_info_entry_t *cur, const mcps_data_ind_t *data_ind)
01186 {
01187     buffer_t *buf = buffer_get(data_ind->msduLength);
01188     if (!buf || !cur) {
01189         return;
01190     }
01191     uint8_t *ptr;
01192     buffer_data_add(buf, data_ind->msdu_ptr, data_ind->msduLength);
01193     //tr_debug("MAC Paylod size %u %s",data_ind->msduLength, trace_array(data_ind->msdu_ptr, 8));
01194     buf->options .lqi  = data_ind->mpduLinkQuality;
01195     buf->options .dbm  = data_ind->signal_dbm;
01196     buf->src_sa .addr_type  = (addrtype_t)data_ind->SrcAddrMode;
01197     ptr = common_write_16_bit(data_ind->SrcPANId, buf->src_sa .address );
01198     memcpy(ptr, data_ind->SrcAddr, 8);
01199     buf->dst_sa .addr_type  = (addrtype_t)data_ind->DstAddrMode;
01200     ptr = common_write_16_bit(data_ind->DstPANId, buf->dst_sa .address );
01201     memcpy(ptr, data_ind->DstAddr, 8);
01202     //Set Link spesific stuff to seperately
01203     buf->link_specific.ieee802_15_4.srcPanId = data_ind->SrcPANId;
01204     buf->link_specific.ieee802_15_4.dstPanId = data_ind->DstPANId;
01205 
01206     if (mac_data_is_broadcast_addr(&buf->dst_sa )) {
01207         buf->options .ll_broadcast_rx  = true;
01208     }
01209     buf->interface  = cur;
01210     if (data_ind->Key.SecurityLevel) {
01211         buf->link_specific.ieee802_15_4.fc_security = true;
01212 
01213         if (cur->mac_security_key_usage_update_cb) {
01214             cur->mac_security_key_usage_update_cb(cur, &data_ind->Key);
01215         }
01216     } else {
01217         buf->link_specific.ieee802_15_4.fc_security = false;
01218         if (mac_helper_default_security_level_get(cur) ||
01219                 !mcps_data_indication_neighbor_validate(cur, &buf->src_sa )) {
01220             //SET By Pass
01221             buf->options .ll_security_bypass_rx  = true;
01222         }
01223     }
01224 
01225     buf->info  = (buffer_info_t)(B_TO_IPV6_TXRX | B_FROM_MAC | B_DIR_UP);
01226     protocol_push(buf);
01227 }
01228 
01229 static uint8_t map_mlme_status_to_socket_event(uint8_t mlme_status)
01230 {
01231     uint8_t socket_event;
01232 
01233     switch (mlme_status) {
01234         case MLME_SUCCESS:
01235             socket_event = SOCKET_TX_DONE;
01236             break;
01237         case MLME_TX_NO_ACK:
01238         case MLME_SECURITY_FAIL:
01239         case MLME_TRANSACTION_EXPIRED:
01240         default:
01241             socket_event = SOCKET_TX_FAIL;
01242             break;
01243     }
01244 
01245     return (socket_event);
01246 }
01247 
01248 bool lowpan_adaptation_tx_active(int8_t interface_id)
01249 {
01250     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id);
01251 
01252     if (!interface_ptr || (!interface_ptr->active_unicast_tx_buf.buf && !interface_ptr->active_broadcast_tx_buf.buf)) {
01253         return false;
01254     }
01255     return true;
01256 }
01257 
01258 static bool lowpan_tx_buffer_address_compare(sockaddr_t *dst_sa, uint8_t *address_ptr, addrtype_t adr_type)
01259 {
01260 
01261     if (dst_sa->addr_type  != adr_type) {
01262         return false;
01263     }
01264 
01265     uint8_t compare_length;
01266     switch (adr_type) {
01267         case ADDR_802_15_4_SHORT :
01268             compare_length = 2;
01269             break;
01270         case ADDR_802_15_4_LONG :
01271             compare_length = 8;
01272             break;
01273         default:
01274             return false;
01275     }
01276 
01277 
01278     if (memcmp(&dst_sa->address [2], address_ptr, compare_length)) {
01279         return false;
01280     }
01281     return true;
01282 }
01283 
01284 static void lowpan_adaptation_purge_from_mac(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr,  uint8_t msduhandle)
01285 {
01286     mcps_purge_t purge_req;
01287     purge_req.msduHandle = msduhandle;
01288     if (interface_ptr->mpx_api) {
01289         interface_ptr->mpx_api->mpx_data_purge(interface_ptr->mpx_api, &purge_req, interface_ptr->mpx_user_id);
01290     } else {
01291         if (cur->mac_api->mcps_purge_req) {
01292             cur->mac_api->mcps_purge_req(cur->mac_api, &purge_req);
01293         }
01294     }
01295 }
01296 
01297 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)
01298 {
01299     tr_debug("Purge from indirect handle %u", tx_ptr->buf->seq);
01300     lowpan_adaptation_purge_from_mac(cur, interface_ptr, tx_ptr->buf->seq);
01301     lowpan_adaptation_data_process_clean(interface_ptr, tx_ptr, SOCKET_TX_FAIL);
01302 }
01303 
01304 void lowpan_adaptation_remove_free_indirect_table(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *entry_ptr)
01305 {
01306     //Free firts by defined short address
01307     if (entry_ptr->mac16  < 0xfffe) {
01308         uint8_t temp_address[2];
01309         common_write_16_bit(entry_ptr->mac16 , temp_address);
01310         lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, temp_address, ADDR_802_15_4_SHORT );
01311     }
01312     lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, entry_ptr->mac64 , ADDR_802_15_4_LONG );
01313 }
01314 
01315 
01316 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)
01317 {
01318     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
01319 
01320     if (!interface_ptr ) {
01321         return -1;
01322     }
01323 
01324     //Check first indirect queue
01325     ns_list_foreach_safe(fragmenter_tx_entry_t, entry, &interface_ptr->indirect_tx_queue) {
01326 
01327         if (lowpan_tx_buffer_address_compare(&entry->buf->dst_sa, address_ptr, adr_type)) {
01328             //Purge from mac
01329             lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, entry);
01330         }
01331     }
01332 
01333     return 0;
01334 
01335 }
01336 
01337 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)
01338 {
01339     fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id);
01340 
01341     if (!interface_ptr) {
01342         return -1;
01343     }
01344 
01345     interface_ptr->indirect_big_packet_threshold = indirect_big_packet_threshold;
01346     interface_ptr->max_indirect_big_packets_total = max_indirect_big_packets_total;
01347     interface_ptr->max_indirect_small_packets_per_child = max_indirect_small_packets_per_child;
01348 
01349     return 0;
01350 }