| /////////////////////////////////////////////////////////////////////////////// |
| // Copyright (c) 2000-2019 Ericsson Telecom AB |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v2.0 |
| // which accompanies this distribution, and is available at |
| // https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // File: SCTP_Engine_ExternalFunctions.cc |
| // Description: function definition of the SCTP Engine |
| // Rev: <RnXnn> |
| // Prodnr: CNL 113 840 |
| // |
| #include "SCTP_Engine_Functions.hh" |
| #include <map> |
| #include <vector> |
| #include <queue> |
| #include <stdint.h> |
| #include <openssl/md5.h> |
| #include <openssl/hmac.h> |
| #include <time.h> |
| |
| typedef std::map<uint64_t,int> id_map_t; |
| typedef id_map_t::iterator id_map_it_t; |
| |
| typedef std::map<uint64_t,uint64_t> ii_map_t; |
| typedef ii_map_t::iterator ii_map_it_t; |
| |
| // Map to store assoc-id <-> (transport_id,local_port,remote_port) mapping |
| // The (transport_id,local_port,remote_port) concatenated into a |
| // 64 unsigned int value to form the key |
| static id_map_t id_map; |
| |
| |
| |
| // Event scheduler types and map |
| // std::multimap type is used, because it stores the elements in a |
| // specific order |
| // We need to order the event by the scheduled time -> use the time as key |
| typedef std::multimap<double,int> event_map_t; |
| typedef event_map_t::iterator event_map_it_t; |
| static event_map_t event_map; |
| |
| |
| // We need int2int maps for every association |
| // - outgoing stream-id -> queue index |
| // - incoming stream-id -> queue index |
| // |
| // These maps are allocated at the assoc creation and freed at the assoc deletion |
| // |
| |
| static std::vector<ii_map_t*> ii_map_vector; |
| static std::queue<int> ii_empty_queue; // stores the index of free/reusable elements |
| |
| namespace SCTP__Engine__Functions { |
| |
| //***************************************************************************// |
| // |
| // int2int map handler functions |
| // |
| //***************************************************************************// |
| INTEGER SCTP__int2int__new(){ |
| int idx=-1; |
| if(ii_empty_queue.empty()){ |
| // No free item, add one |
| idx=ii_map_vector.size(); |
| ii_map_vector.push_back(NULL); |
| |
| } else { |
| // get the index of the free item |
| idx=ii_empty_queue.front(); |
| ii_empty_queue.pop(); |
| } |
| ii_map_vector[idx]=new ii_map_t; |
| |
| return idx; |
| |
| } |
| |
| void SCTP__int2int__delete(INTEGER const&pl_map_id){ |
| int idx=(int)pl_map_id; |
| if( idx>=0 && idx<(int)ii_map_vector.size() && ii_map_vector[idx] != NULL){ |
| // valid index |
| // delete the map |
| delete ii_map_vector[idx]; |
| ii_map_vector[idx]=NULL; |
| // put the map index into the empty queue |
| ii_empty_queue.push(idx); |
| } |
| } |
| |
| INTEGER SCTP__int2int__add(INTEGER const& pl_map_id, INTEGER const& pl_key, INTEGER const& pl_value){ |
| int idx=(int)pl_map_id; |
| if( idx>=0 && idx<(int)ii_map_vector.size() && ii_map_vector[idx] != NULL){ |
| // valid index |
| |
| (*(ii_map_vector[idx]))[(uint64_t)pl_key.get_long_long_val()]=(uint64_t)pl_value.get_long_long_val(); |
| return 0; |
| } |
| return -1; |
| } |
| |
| INTEGER SCTP__int2int__get(INTEGER const& pl_map_id, INTEGER const& pl_key, INTEGER& pl_value){ |
| int idx=(int)pl_map_id; |
| if( idx>=0 && idx<(int)ii_map_vector.size() && ii_map_vector[idx] != NULL){ |
| // valid index |
| ii_map_it_t it=(ii_map_vector[idx])->find((uint64_t)pl_key.get_long_long_val()); |
| if(it!=(ii_map_vector[idx])->end()){ |
| // valid key |
| pl_value.set_long_long_val(it->second); |
| return 0; |
| } |
| } |
| |
| return -1; |
| } |
| //***************************************************************************// |
| // |
| // assoc-id <-> (transport_id,local_port,remote_port) map handler functions |
| // |
| //***************************************************************************// |
| |
| // Constructs the 64 bit key value |
| uint64_t get_id(const int64_t tr_id, const uint64_t loc_port, const uint64_t rem_port){ |
| uint64_t vl_tr_id=0; |
| // the tr_id can be -1 => all transport => translate to all 1's |
| if(tr_id>=0){ |
| vl_tr_id = tr_id; |
| } else { |
| vl_tr_id = ~vl_tr_id; |
| } |
| return (vl_tr_id << 32 ) | ((loc_port & 0xff) << 16 ) | (rem_port & 0xff); |
| } |
| |
| INTEGER SCTP__add__id__map(INTEGER const& vl_assoc_id, |
| INTEGER const& vl_transport_id, |
| INTEGER const& vl_local_port, |
| INTEGER const& vl_remote_port){ |
| |
| uint64_t key=get_id(vl_transport_id.get_long_long_val(),(int)vl_local_port,(int)vl_remote_port); |
| |
| if(id_map.find(key) == id_map.end()){ |
| // if the key is not found, we can insert it |
| id_map[key]=(int)vl_assoc_id; |
| |
| return 0; |
| } |
| // the key is found, return error |
| return -1; |
| } |
| INTEGER SCTP__del__id__map(INTEGER const& vl_transport_id, |
| INTEGER const& vl_local_port, |
| INTEGER const& vl_remote_port){ |
| uint64_t key=get_id(vl_transport_id.get_long_long_val(),(int)vl_local_port,(int)vl_remote_port); |
| id_map_it_t it=id_map.find(key); |
| if(it != id_map.end()){ |
| // found the key, delete it. |
| id_map.erase(it); |
| return 0; // Success |
| } |
| // the key is not found, return error |
| return -1; |
| |
| } |
| INTEGER SCTP__find__id__map(INTEGER const& vl_transport_id, |
| INTEGER const& vl_local_port, |
| INTEGER const& vl_remote_port){ |
| uint64_t key=get_id(vl_transport_id.get_long_long_val(),(int)vl_local_port,(int)vl_remote_port); |
| id_map_it_t it=id_map.find(key); |
| if(it != id_map.end()){ |
| // found the key, return the assoc_id. |
| |
| return it->second; // Success |
| } |
| // the key is not found, return error |
| return -1; |
| |
| } |
| |
| //***************************************************************************// |
| // |
| // State cookie handler functions |
| // |
| //***************************************************************************// |
| |
| OCTETSTRING SCTP__gen__state__cookie(INTEGER const& pl_lifespan, |
| INTEGER const& pl_own_init_tag, |
| INTEGER const& pl_remote_init_tag, |
| INTEGER const& pl_tie_tag, |
| INTEGER const& pl_remote_tsn, |
| INTEGER const& pl_remote_os, |
| INTEGER const& pl_remote_mis, |
| INTEGER const& pl_remote_a_rwnd, |
| BOOLEAN const& pl_idata_flag, |
| BOOLEAN const& pl_reconf_flag, |
| BOOLEAN const& pl_forward_tsn_flag, |
| OCTETSTRING const& pl_key){ |
| |
| time_t tstamp_t=time(NULL); |
| int tstamp_i = (tstamp_t &0x7fffffff ); // to calculate the lifespan of teh cookie |
| // the lowest 31 bit is enough |
| |
| int lifespan = (int)pl_lifespan & 0xffff; |
| |
| int zero = 0; |
| int ones = ~0; |
| |
| OCTETSTRING ret_val= int2oct(tstamp_i,4) + int2oct(lifespan,2) + |
| int2oct(pl_own_init_tag,4)+ int2oct(pl_remote_init_tag,4) |
| + int2oct(pl_tie_tag,4) |
| + int2oct(pl_remote_tsn,4)+ int2oct(pl_remote_os,2) |
| + int2oct(pl_remote_mis,2)+ int2oct(pl_remote_a_rwnd,4)+ |
| bit2oct( (pl_idata_flag?BITSTRING(1,(const unsigned char*)&ones):BITSTRING(1,(const unsigned char*)&zero)) |
| + (pl_reconf_flag?BITSTRING(1,(const unsigned char*)&ones):BITSTRING(1,(const unsigned char*)&zero)) |
| + (pl_forward_tsn_flag?BITSTRING(1,(const unsigned char*)&ones):BITSTRING(1,(const unsigned char*)&zero)) |
| + BITSTRING(5,(const unsigned char*)&zero) ) |
| ; |
| |
| unsigned int out_length; |
| unsigned char output[EVP_MAX_MD_SIZE]; |
| HMAC(EVP_md5(), (const unsigned char*)pl_key, (size_t) pl_key.lengthof(), |
| (const unsigned char*)ret_val, (size_t) ret_val.lengthof(), |
| output, &out_length); |
| |
| return ret_val + OCTETSTRING(16,output); |
| |
| } |
| |
| INTEGER SCTP__check__state__cookie(OCTETSTRING const& pl_cookie, |
| OCTETSTRING const& pl_key){ |
| |
| if(pl_cookie.lengthof()!= 47){ |
| // We use 46 octet length state cookie |
| return -1; |
| } |
| |
| // check the MAC |
| unsigned int out_length; |
| unsigned char output[EVP_MAX_MD_SIZE]; |
| HMAC(EVP_md5(), (const unsigned char*)pl_key, (size_t) pl_key.lengthof(), |
| (const unsigned char*)pl_cookie, 31, |
| output, &out_length); |
| |
| if(substr(pl_cookie,31,16)!=OCTETSTRING(16,output)){ |
| // MAC error |
| return -1; |
| } |
| |
| // check lifespan |
| time_t tstamp_t=time(NULL); |
| unsigned int tstamp_i = (tstamp_t &0x7fffffff ); // to calculate the lifespan of teh cookie |
| // the lowest 31 bit is enough |
| unsigned int lifespan = (int)oct2int(substr(pl_cookie,4,2)); |
| unsigned int orig_ts= (int)oct2int(substr(pl_cookie,0,4)); |
| |
| if( orig_ts<(tstamp_i-lifespan) ){ |
| // expired |
| return 1; |
| } |
| // cookie ok |
| return 0; |
| } |
| |
| //***************************************************************************// |
| // |
| // Event map handler functions |
| // |
| //***************************************************************************// |
| void SCTP__event__add__map(INTEGER const& pl_event_id, |
| FLOAT const& pl_event_time){ |
| // Just insert it |
| event_map.insert(std::pair<double,int>((double)pl_event_time,(int)pl_event_id)); |
| } |
| |
| void SCTP__event__del__map(INTEGER const& pl_event_id, |
| FLOAT const& pl_event_time){ |
| // find the the time,id pair. |
| // Note that several event can be scheduled at the same time |
| // so it is not enough to delete the key. |
| |
| event_map_it_t it=event_map.find((double)pl_event_time); |
| while( (it != event_map.end()) && (it->second != (int)pl_event_id ) ){ |
| it++; |
| } |
| |
| // now the it point to either the event ot delete or to the end |
| if(it != event_map.end()){ |
| // delete the event |
| event_map.erase(it); |
| } |
| |
| } |
| |
| INTEGER SCTP__event__get__map() { |
| // return the event id of the first event. |
| // the map is ordered by the event time |
| event_map_it_t it=event_map.begin(); |
| if(it != event_map.end()){ |
| return it->second; // return the event id |
| } |
| return -1; // map is empty |
| |
| } |
| |
| OCTETSTRING SCTP__misc__float2oct(FLOAT const& pl_in){ |
| double fl=(double)pl_in; |
| return OCTETSTRING(sizeof(double),(const unsigned char*)&fl); |
| |
| } |
| FLOAT SCTP__misc__oct2float( OCTETSTRING const& pl_in){ |
| return FLOAT(*((float*)(const unsigned char*)pl_in)); |
| } |
| |
| } |
| |