First code commit
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3534f2f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,277 @@
+Eclipse Public License - v 2.0

+

+    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE

+    PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION

+    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

+

+1. DEFINITIONS

+

+"Contribution" means:

+

+  a) in the case of the initial Contributor, the initial content

+     Distributed under this Agreement, and

+

+  b) in the case of each subsequent Contributor:

+     i) changes to the Program, and

+     ii) additions to the Program;

+  where such changes and/or additions to the Program originate from

+  and are Distributed by that particular Contributor. A Contribution

+  "originates" from a Contributor if it was added to the Program by

+  such Contributor itself or anyone acting on such Contributor's behalf.

+  Contributions do not include changes or additions to the Program that

+  are not Modified Works.

+

+"Contributor" means any person or entity that Distributes the Program.

+

+"Licensed Patents" mean patent claims licensable by a Contributor which

+are necessarily infringed by the use or sale of its Contribution alone

+or when combined with the Program.

+

+"Program" means the Contributions Distributed in accordance with this

+Agreement.

+

+"Recipient" means anyone who receives the Program under this Agreement

+or any Secondary License (as applicable), including Contributors.

+

+"Derivative Works" shall mean any work, whether in Source Code or other

+form, that is based on (or derived from) the Program and for which the

+editorial revisions, annotations, elaborations, or other modifications

+represent, as a whole, an original work of authorship.

+

+"Modified Works" shall mean any work in Source Code or other form that

+results from an addition to, deletion from, or modification of the

+contents of the Program, including, for purposes of clarity any new file

+in Source Code form that contains any contents of the Program. Modified

+Works shall not include works that contain only declarations,

+interfaces, types, classes, structures, or files of the Program solely

+in each case in order to link to, bind by name, or subclass the Program

+or Modified Works thereof.

+

+"Distribute" means the acts of a) distributing or b) making available

+in any manner that enables the transfer of a copy.

+

+"Source Code" means the form of a Program preferred for making

+modifications, including but not limited to software source code,

+documentation source, and configuration files.

+

+"Secondary License" means either the GNU General Public License,

+Version 2.0, or any later versions of that license, including any

+exceptions or additional permissions as identified by the initial

+Contributor.

+

+2. GRANT OF RIGHTS

+

+  a) Subject to the terms of this Agreement, each Contributor hereby

+  grants Recipient a non-exclusive, worldwide, royalty-free copyright

+  license to reproduce, prepare Derivative Works of, publicly display,

+  publicly perform, Distribute and sublicense the Contribution of such

+  Contributor, if any, and such Derivative Works.

+

+  b) Subject to the terms of this Agreement, each Contributor hereby

+  grants Recipient a non-exclusive, worldwide, royalty-free patent

+  license under Licensed Patents to make, use, sell, offer to sell,

+  import and otherwise transfer the Contribution of such Contributor,

+  if any, in Source Code or other form. This patent license shall

+  apply to the combination of the Contribution and the Program if, at

+  the time the Contribution is added by the Contributor, such addition

+  of the Contribution causes such combination to be covered by the

+  Licensed Patents. The patent license shall not apply to any other

+  combinations which include the Contribution. No hardware per se is

+  licensed hereunder.

+

+  c) Recipient understands that although each Contributor grants the

+  licenses to its Contributions set forth herein, no assurances are

+  provided by any Contributor that the Program does not infringe the

+  patent or other intellectual property rights of any other entity.

+  Each Contributor disclaims any liability to Recipient for claims

+  brought by any other entity based on infringement of intellectual

+  property rights or otherwise. As a condition to exercising the

+  rights and licenses granted hereunder, each Recipient hereby

+  assumes sole responsibility to secure any other intellectual

+  property rights needed, if any. For example, if a third party

+  patent license is required to allow Recipient to Distribute the

+  Program, it is Recipient's responsibility to acquire that license

+  before distributing the Program.

+

+  d) Each Contributor represents that to its knowledge it has

+  sufficient copyright rights in its Contribution, if any, to grant

+  the copyright license set forth in this Agreement.

+

+  e) Notwithstanding the terms of any Secondary License, no

+  Contributor makes additional grants to any Recipient (other than

+  those set forth in this Agreement) as a result of such Recipient's

+  receipt of the Program under the terms of a Secondary License

+  (if permitted under the terms of Section 3).

+

+3. REQUIREMENTS

+

+3.1 If a Contributor Distributes the Program in any form, then:

+

+  a) the Program must also be made available as Source Code, in

+  accordance with section 3.2, and the Contributor must accompany

+  the Program with a statement that the Source Code for the Program

+  is available under this Agreement, and informs Recipients how to

+  obtain it in a reasonable manner on or through a medium customarily

+  used for software exchange; and

+

+  b) the Contributor may Distribute the Program under a license

+  different than this Agreement, provided that such license:

+     i) effectively disclaims on behalf of all other Contributors all

+     warranties and conditions, express and implied, including

+     warranties or conditions of title and non-infringement, and

+     implied warranties or conditions of merchantability and fitness

+     for a particular purpose;

+

+     ii) effectively excludes on behalf of all other Contributors all

+     liability for damages, including direct, indirect, special,

+     incidental and consequential damages, such as lost profits;

+

+     iii) does not attempt to limit or alter the recipients' rights

+     in the Source Code under section 3.2; and

+

+     iv) requires any subsequent distribution of the Program by any

+     party to be under a license that satisfies the requirements

+     of this section 3.

+

+3.2 When the Program is Distributed as Source Code:

+

+  a) it must be made available under this Agreement, or if the

+  Program (i) is combined with other material in a separate file or

+  files made available under a Secondary License, and (ii) the initial

+  Contributor attached to the Source Code the notice described in

+  Exhibit A of this Agreement, then the Program may be made available

+  under the terms of such Secondary Licenses, and

+

+  b) a copy of this Agreement must be included with each copy of

+  the Program.

+

+3.3 Contributors may not remove or alter any copyright, patent,

+trademark, attribution notices, disclaimers of warranty, or limitations

+of liability ("notices") contained within the Program from any copy of

+the Program which they Distribute, provided that Contributors may add

+their own appropriate notices.

+

+4. COMMERCIAL DISTRIBUTION

+

+Commercial distributors of software may accept certain responsibilities

+with respect to end users, business partners and the like. While this

+license is intended to facilitate the commercial use of the Program,

+the Contributor who includes the Program in a commercial product

+offering should do so in a manner which does not create potential

+liability for other Contributors. Therefore, if a Contributor includes

+the Program in a commercial product offering, such Contributor

+("Commercial Contributor") hereby agrees to defend and indemnify every

+other Contributor ("Indemnified Contributor") against any losses,

+damages and costs (collectively "Losses") arising from claims, lawsuits

+and other legal actions brought by a third party against the Indemnified

+Contributor to the extent caused by the acts or omissions of such

+Commercial Contributor in connection with its distribution of the Program

+in a commercial product offering. The obligations in this section do not

+apply to any claims or Losses relating to any actual or alleged

+intellectual property infringement. In order to qualify, an Indemnified

+Contributor must: a) promptly notify the Commercial Contributor in

+writing of such claim, and b) allow the Commercial Contributor to control,

+and cooperate with the Commercial Contributor in, the defense and any

+related settlement negotiations. The Indemnified Contributor may

+participate in any such claim at its own expense.

+

+For example, a Contributor might include the Program in a commercial

+product offering, Product X. That Contributor is then a Commercial

+Contributor. If that Commercial Contributor then makes performance

+claims, or offers warranties related to Product X, those performance

+claims and warranties are such Commercial Contributor's responsibility

+alone. Under this section, the Commercial Contributor would have to

+defend claims against the other Contributors related to those performance

+claims and warranties, and if a court requires any other Contributor to

+pay any damages as a result, the Commercial Contributor must pay

+those damages.

+

+5. NO WARRANTY

+

+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT

+PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"

+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR

+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF

+TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR

+PURPOSE. Each Recipient is solely responsible for determining the

+appropriateness of using and distributing the Program and assumes all

+risks associated with its exercise of rights under this Agreement,

+including but not limited to the risks and costs of program errors,

+compliance with applicable laws, damage to or loss of data, programs

+or equipment, and unavailability or interruption of operations.

+

+6. DISCLAIMER OF LIABILITY

+

+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT

+PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS

+SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST

+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE

+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE

+POSSIBILITY OF SUCH DAMAGES.

+

+7. GENERAL

+

+If any provision of this Agreement is invalid or unenforceable under

+applicable law, it shall not affect the validity or enforceability of

+the remainder of the terms of this Agreement, and without further

+action by the parties hereto, such provision shall be reformed to the

+minimum extent necessary to make such provision valid and enforceable.

+

+If Recipient institutes patent litigation against any entity

+(including a cross-claim or counterclaim in a lawsuit) alleging that the

+Program itself (excluding combinations of the Program with other software

+or hardware) infringes such Recipient's patent(s), then such Recipient's

+rights granted under Section 2(b) shall terminate as of the date such

+litigation is filed.

+

+All Recipient's rights under this Agreement shall terminate if it

+fails to comply with any of the material terms or conditions of this

+Agreement and does not cure such failure in a reasonable period of

+time after becoming aware of such noncompliance. If all Recipient's

+rights under this Agreement terminate, Recipient agrees to cease use

+and distribution of the Program as soon as reasonably practicable.

+However, Recipient's obligations under this Agreement and any licenses

+granted by Recipient relating to the Program shall continue and survive.

+

+Everyone is permitted to copy and distribute copies of this Agreement,

+but in order to avoid inconsistency the Agreement is copyrighted and

+may only be modified in the following manner. The Agreement Steward

+reserves the right to publish new versions (including revisions) of

+this Agreement from time to time. No one other than the Agreement

+Steward has the right to modify this Agreement. The Eclipse Foundation

+is the initial Agreement Steward. The Eclipse Foundation may assign the

+responsibility to serve as the Agreement Steward to a suitable separate

+entity. Each new version of the Agreement will be given a distinguishing

+version number. The Program (including Contributions) may always be

+Distributed subject to the version of the Agreement under which it was

+received. In addition, after a new version of the Agreement is published,

+Contributor may elect to Distribute the Program (including its

+Contributions) under the new version.

+

+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient

+receives no rights or licenses to the intellectual property of any

+Contributor under this Agreement, whether expressly, by implication,

+estoppel or otherwise. All rights in the Program not expressly granted

+under this Agreement are reserved. Nothing in this Agreement is intended

+to be enforceable by any entity that is not a Contributor or Recipient.

+No third-party beneficiary rights are created under this Agreement.

+

+Exhibit A - Form of Secondary Licenses Notice

+

+"This Source Code may also be made available under the following 

+Secondary Licenses when the conditions for such availability set forth 

+in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),

+version(s), and exceptions or additional permissions here}."

+

+  Simply including a copy of this Agreement, including this Exhibit A

+  is not sufficient to license the Source Code under Secondary Licenses.

+

+  If it is not possible or desirable to put the notice in a particular

+  file, then You may include the notice in a location (such as a LICENSE

+  file in a relevant directory) where a recipient would be likely to

+  look for such a notice.

+

+  You may add additional accurate notices of copyright ownership.
\ No newline at end of file
diff --git a/doc/GTP_Tunnel_Daemon_CNL113827_1551doc.doc b/doc/GTP_Tunnel_Daemon_CNL113827_1551doc.doc
new file mode 100644
index 0000000..5a33777
--- /dev/null
+++ b/doc/GTP_Tunnel_Daemon_CNL113827_1551doc.doc
Binary files differ
diff --git a/doc/GTP_Tunnel_Daemon_CNL113827_PRI.doc b/doc/GTP_Tunnel_Daemon_CNL113827_PRI.doc
new file mode 100644
index 0000000..b9dc899
--- /dev/null
+++ b/doc/GTP_Tunnel_Daemon_CNL113827_PRI.doc
Binary files differ
diff --git a/src/Test_port/GTP_Tunnel_PortTypes.ttcn b/src/Test_port/GTP_Tunnel_PortTypes.ttcn
new file mode 100644
index 0000000..15231d0
--- /dev/null
+++ b/src/Test_port/GTP_Tunnel_PortTypes.ttcn
@@ -0,0 +1,101 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+module GTP_Tunnel_PortTypes{
+
+type enumerated GTP_Tunnel_Result_code { OK(0), ERROR(1)}
+
+type record GTP_Tunnel_Result{
+  GTP_Tunnel_Result_code  result_code,
+  charstring              result_text
+}
+
+type enumerated GTP_address_type {IPV4(0), IPV6(1)}
+
+type enumerated GTP_Set_address_mode{DO_NOT_SET(0), SET_AS_ANY(1), SET_ONE_BY_ONE(2)}
+
+type union GTP_Tunnel_param {
+  GTP_Set_address_mode   set_address_mode
+}
+
+type record of GTP_Tunnel_param GTP_Tunnel_param_list
+
+type record GTP_Tunnel_address{
+  charstring   local_ip,
+  integer      local_port,
+  charstring   remote_ip,
+  integer      remote_port
+}
+
+type enumerated GTP_Tunnel_proto{ NOT_SPECIFIED(0), UDP(17), TCP(6)}
+
+type record GTP_Tunnel_filter{
+  GTP_Tunnel_proto proto optional,
+  integer      local_port optional,
+  octetstring   remote_ip optional,
+  integer      remote_port optional
+}
+
+type record GTP_Tunnel_init{
+  charstring          interface_name optional,
+  GTP_Tunnel_address  tunnel_addres  optional,
+  GTP_Tunnel_param_list param_list optional
+}
+
+type record GTP_Tunnel_init_ack{
+  GTP_Tunnel_Result result
+}
+
+type record GTP_Tunnel_bye{
+}
+type record GTP_Tunnel_bye_ack{
+}
+
+type record GTP_Tunnel_create{
+  octetstring        outgoing_TEID,
+  octetstring        incoming_TEID optional,
+  GTP_address_type   user_address_type,
+  octetstring        user_address,
+  GTP_Tunnel_filter  filter optional,
+  GTP_Tunnel_address tunnel_addres  optional  // Just a placeholder for the future extension
+}
+
+type record GTP_Tunnel_create_ack{
+  octetstring        outgoing_TEID,
+  octetstring        incoming_TEID optional,
+  GTP_Tunnel_Result  result,
+  octetstring        user_address
+}
+
+type record GTP_Tunnel_destroy{
+  octetstring        user_address,
+  octetstring        outgoing_TEID,
+  octetstring        incoming_TEID
+}
+
+type record GTP_Tunnel_indication{
+  GTP_Tunnel_Result result
+}
+
+type port GTP_Tunnel_control_PT message{
+  out GTP_Tunnel_init;
+  in  GTP_Tunnel_init_ack;
+  out GTP_Tunnel_bye;
+  in  GTP_Tunnel_bye_ack;
+  out GTP_Tunnel_create;
+  in  GTP_Tunnel_create_ack;
+  out GTP_Tunnel_destroy;
+  in  GTP_Tunnel_indication;
+}
+
+}
diff --git a/src/Test_port/GTP_Tunnel_control_PT.cc b/src/Test_port/GTP_Tunnel_control_PT.cc
new file mode 100644
index 0000000..730eaab
--- /dev/null
+++ b/src/Test_port/GTP_Tunnel_control_PT.cc
@@ -0,0 +1,521 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "GTP_Tunnel_control_PT.hh"
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <string.h>
+
+namespace GTP__Tunnel__PortTypes {
+
+GTP__Tunnel__control__PT::GTP__Tunnel__control__PT(const char *par_port_name)
+	: GTP__Tunnel__control__PT_BASE(par_port_name)
+{
+  daemon_fd=-1;
+  init_msg_buffer(&recv_buffer);
+}
+
+GTP__Tunnel__control__PT::~GTP__Tunnel__control__PT()
+{
+  free_msg_buffer(&recv_buffer);
+}
+
+void GTP__Tunnel__control__PT::log(const char *fmt, ...)
+{
+	if (TTCN_Logger::log_this_event(TTCN_DEBUG)) {
+		TTCN_Logger::begin_event(TTCN_DEBUG);
+		TTCN_Logger::log_event("GTP Tunnel Control test port (%s): ", get_name());
+		va_list args;
+		va_start(args, fmt);
+		TTCN_Logger::log_event_va_list(fmt, args);
+		va_end(args);
+		TTCN_Logger::end_event();
+	}
+}
+
+void GTP__Tunnel__control__PT::report_ind(GTP__Tunnel__Result__code code,const char *fmt, ...  ){
+  GTP__Tunnel__indication ind;
+		va_list args;
+		va_start(args, fmt);
+  char * str=mprintf_va_list(fmt, args);
+  ind.result().result__code()=code;
+  ind.result().result__text()=str;
+  Free(str);
+  incoming_message(ind);
+}
+
+void GTP__Tunnel__control__PT::set_parameter(const char * /*parameter_name*/,
+	const char * /*parameter_value*/)
+{
+
+}
+
+/*void GTP__Tunnel__control__PT::Handle_Fd_Event(int fd, boolean is_readable,
+	boolean is_writable, boolean is_error) {}*/
+
+void GTP__Tunnel__control__PT::Handle_Fd_Event_Error(int fd)
+{
+  Handle_Fd_Event_Readable(fd);
+}
+
+void GTP__Tunnel__control__PT::Handle_Fd_Event_Writable(int /*fd*/)
+{
+
+}
+
+void GTP__Tunnel__control__PT::Handle_Fd_Event_Readable(int fd)
+{
+  log("Handle_Fd_Event_Readable begin");
+  
+  inc_buff_size(&recv_buffer,4);  // we should be able to receive the msg length
+  int curr_pos;
+  int rd=read(fd,recv_buffer.msg+recv_buffer.pos,recv_buffer.size-recv_buffer.pos);
+  log("read returned: %d",rd);
+  if(rd<=0){  // Read error or the daemon closed the connection
+    int en=errno;
+    if(rd<0){
+      log("Read error: %d %s",en,strerror(en));
+      report_ind(GTP__Tunnel__Result__code::ERROR_,"Read error %d %s",en,strerror(en));
+    } else {
+      log("The daemon closed the connection");
+      report_ind(GTP__Tunnel__Result__code::ERROR_,"The daemon closed the connection");
+    }
+    Handler_Remove_Fd_Read(daemon_fd);
+    close(daemon_fd);
+    daemon_fd=-1;
+  } else {  // process the message
+    recv_buffer.pos+=rd;
+    
+    // read the msg length
+    curr_pos=recv_buffer.pos;  // store the write position of the buffer
+    
+    while(curr_pos){  // process all of the message in the buffer
+      recv_buffer.pos=0;  // start from the beginning
+
+      int msg_len;
+      if(get_int(&recv_buffer,&msg_len)<0) { goto msg_error;}  // read the msg length
+      log("msg length: %d",msg_len);
+      if(msg_len>curr_pos){  // we need more data
+        log("More data is needed. msg length %d received bytes %d",msg_len,curr_pos);
+        recv_buffer.pos=curr_pos;
+        inc_buff_size(&recv_buffer,msg_len-curr_pos); // reserve enough space in the buffer to receive data
+        log("Handle_Fd_Event_Readable end");
+        return;
+      }
+      if(msg_len<8) { goto msg_error;} // No msg type????
+      
+      int msg_type;
+      if(get_int(&recv_buffer,&msg_type)<0) { goto msg_error;} // read the msg type
+      log("msg type: %d",msg_type);
+
+      switch(msg_type){
+        case GTP_CTRL_MSG_INIT_ACK:{
+            GTP__Tunnel__init__ack ia;
+            log("GTP_Tunnel_init_ack received");
+            int code;
+            if(get_int(&recv_buffer,&code)<0) { break;}  // get the IE code
+            log("IE code: %d",code);
+            if(code!=GTP_CTRL_IE_RES_CODE){ break;} // check it
+            if(get_int(&recv_buffer,&code)<0) { break;}  // read the result code
+            log("IE val: %d",code);
+            ia.result().result__code()=code;
+            str_holder str;
+
+            if(get_int(&recv_buffer,&code)<0) { break;}  // get the IE code
+            log("IE code: %d",code);
+            if(code!=GTP_CTRL_IE_RES_TXT){ break;}  // check it
+            if(get_str(&recv_buffer,&str)<0) { break;}
+            ia.result().result__text()=CHARSTRING(str.str_size,(const char*)str.str_begin);
+            log("Message decoded");
+            incoming_message(ia);
+          }
+          break;
+        case GTP_CTRL_MSG_CREATE_ACK:{
+            log("GTP_Tunnel_create_ack received");
+            GTP__Tunnel__create__ack ca;
+            int code;
+            str_holder str;
+            if(get_int(&recv_buffer,&code)<0) { break;}  // get the IE code
+            log("IE code: %d",code);
+            if(code!=GTP_CTRL_IE_OUT_TEID){ break;} // check it
+            if(get_str(&recv_buffer,&str)<0) { break;}
+            ca.outgoing__TEID()=OCTETSTRING(str.str_size,str.str_begin);
+
+            if(get_int(&recv_buffer,&code)<0) { break;}  // get the IE code
+            if(code==GTP_CTRL_IE_IN_TEID){
+              log("IE code: %d",code);
+              if(get_str(&recv_buffer,&str)<0) { break;}
+              ca.incoming__TEID()()=OCTETSTRING(str.str_size,str.str_begin);
+
+              if(get_int(&recv_buffer,&code)<0) { break;}  // get the IE code
+            } else {
+              ca.incoming__TEID()=OMIT_VALUE;
+            }
+            log("IE code: %d",code);
+            if(code!=GTP_CTRL_IE_RES_CODE){ break;} // check it
+            if(get_int(&recv_buffer,&code)<0) { break;}  // read the result code
+            log("IE val: %d",code);
+            ca.result().result__code()=code;
+
+            if(get_int(&recv_buffer,&code)<0) { break;}  // get the IE code
+            log("IE code: %d",code);
+            if(code!=GTP_CTRL_IE_RES_TXT){ break;}  // check it
+            if(get_str(&recv_buffer,&str)<0) { break;}
+            ca.result().result__text()=CHARSTRING(str.str_size,(const char*)str.str_begin);
+            
+            if(get_int(&recv_buffer,&code)<0) { break;}  // get the IE code
+            log("IE code: %d",code);
+            if(code!=GTP_CTRL_IE_ADDR){ break;} // check it
+            if(get_str(&recv_buffer,&str)<0) { break;}
+            ca.user__address()=OCTETSTRING(str.str_size,str.str_begin);
+
+            log("Message decoded");
+            incoming_message(ca);
+           }  
+          break;
+        case GTP_CTRL_MSG_BYE_ACK:{
+            log("GTP_Tunnel_bye_ack received");
+            GTP__Tunnel__bye__ack ba=NULL_VALUE;
+            incoming_message(ba);
+          }
+          break;
+        case GTP_CTRL_MSG_INDICATION:{
+            log("GTP_Tunnel_indication received");
+            GTP__Tunnel__indication ia;
+            int code;
+            if(get_int(&recv_buffer,&code)<0) { break;}  // get the IE code
+            log("IE code: %d",code);
+            if(code!=GTP_CTRL_IE_RES_CODE){ break;} // check it
+            if(get_int(&recv_buffer,&code)<0) { break;}  // read the result code
+            log("IE val: %d",code);
+            ia.result().result__code()=code;
+            str_holder str;
+
+            if(get_int(&recv_buffer,&code)<0) { break;}  // get the IE code
+            log("IE code: %d",code);
+            if(code!=GTP_CTRL_IE_RES_TXT){ break;}  // check it
+            if(get_str(&recv_buffer,&str)<0) { break;}
+            ia.result().result__text()=CHARSTRING(str.str_size,(const char*)str.str_begin);
+            log("Message decoded");
+            incoming_message(ia);
+          }
+          break;
+        default:
+          log("Unknown message type. Ignored");
+          report_ind(GTP__Tunnel__Result__code::ERROR_,"Unknown message type: %d. Ignored",msg_type);
+          break;
+      }
+      log("Remove the processed message from the buffer.");
+      if(msg_len!=curr_pos){  // there is data in the buffer, move it to the beginning
+        memmove(recv_buffer.msg,recv_buffer.msg+msg_len,curr_pos-msg_len);
+      }
+      recv_buffer.pos=curr_pos-msg_len;
+      curr_pos=recv_buffer.pos;
+    }
+  }
+
+  log("Handle_Fd_Event_Readable end");
+  return;
+
+msg_error:
+  // process the message decoding error here
+  log("Something is wrong with the received message. Dropped.");
+  report_ind(GTP__Tunnel__Result__code::ERROR_,"Something is wrong with the received message. Dropped.");
+  recv_buffer.pos=0;
+  
+  log("Handle_Fd_Event_Readable end");
+
+}
+
+/*void GTP__Tunnel__control__PT::Handle_Timeout(double time_since_last_call) {}*/
+
+void GTP__Tunnel__control__PT::user_map(const char * /*system_port*/)
+{
+  log("Mapped.");
+}
+
+void GTP__Tunnel__control__PT::user_unmap(const char * /*system_port*/)
+{
+  if(daemon_fd!=-1){
+    close(daemon_fd);
+    daemon_fd=-1;
+  }
+  log("Unmapped.");
+}
+
+void GTP__Tunnel__control__PT::user_start()
+{
+
+}
+
+void GTP__Tunnel__control__PT::user_stop()
+{
+
+}
+
+void GTP__Tunnel__control__PT::send_msg(const msg_buffer* buffer){
+  log("Sending message");
+  if(::send(daemon_fd,buffer->msg,buffer->pos,0)<0){
+    int en=errno;
+    log("Message send error %d %s",en,strerror(en));
+    report_ind(GTP__Tunnel__Result__code::ERROR_,"Message send error %d %s",en,strerror(en));
+
+    if(daemon_fd != -1)
+    {
+      Handler_Remove_Fd_Read(daemon_fd);
+      close(daemon_fd);
+      daemon_fd=-1;
+    }
+  } else {
+    log("Message sent");
+  }
+}
+
+void GTP__Tunnel__control__PT::outgoing_send(const GTP__Tunnel__init& send_par)
+{
+  log("outgoing_send GTP__Tunnel__init called");
+  if(daemon_fd!=-1){
+    report_ind(GTP__Tunnel__Result__code::ERROR_,"Already connected to the daemon");
+    return;
+  }
+
+	struct sockaddr_un localAddr;
+	localAddr.sun_family = AF_UNIX;
+  localAddr.sun_path[0]='\0';  // use abstract socket
+  if( (!send_par.interface__name().ispresent()) || (send_par.interface__name()().lengthof()==0)){
+    log("No interface name was specified, using the default name: gtp_tunel_daemon");
+    snprintf(localAddr.sun_path+1,106,"gtp_tunel_daemon");
+  } else {
+    log("Interface name was specified, connecting to: gtp_tunel_daemon_%s",(const char*)send_par.interface__name()());
+    snprintf(localAddr.sun_path+1,106,"gtp_tunel_daemon_%s",(const char*)send_par.interface__name()());
+  }
+  
+	if((daemon_fd = socket(PF_UNIX,SOCK_STREAM,0))<0) {
+    int en=errno;
+    log("Socket creation error %d %s",en,strerror(en));
+    report_ind(GTP__Tunnel__Result__code::ERROR_,"Socket creation error %d %s",en,strerror(en));
+    log("outgoing_send GTP__Tunnel__init finished");
+    return;
+		
+	}
+
+	size_t addrLength = sizeof(localAddr.sun_family) + 1 + strlen(localAddr.sun_path+1);
+  log("Connecting to the daemon");
+	if(connect(daemon_fd, (struct sockaddr *) &localAddr, addrLength) != 0)
+	{
+    int en=errno;
+    log("Connect failed %d %s",en,strerror(en));
+    report_ind(GTP__Tunnel__Result__code::ERROR_,"Connect failed %d %s",en,strerror(en));
+    close(daemon_fd);
+    daemon_fd=-1;
+  } else {
+    Handler_Add_Fd_Read(daemon_fd);
+    msg_buffer msg_buff;
+    init_msg_buffer(&msg_buff);
+    
+    msg_buff.pos+=4; // skip the length, will be filled later
+    int msg_len=4;
+    
+    msg_len+=put_int(&msg_buff,GTP_CTRL_MSG_INIT);
+    if(send_par.tunnel__addres().ispresent()){
+      str_holder str;
+      
+      msg_len+=put_int(&msg_buff,GTP_CTRL_IE_LOCAL_IP);
+      str.str_begin=(const unsigned char*)(const char*)send_par.tunnel__addres()().local__ip();
+      str.str_size=send_par.tunnel__addres()().local__ip().lengthof();
+      msg_len+=put_str(&msg_buff,&str);
+
+      msg_len+=put_int(&msg_buff,GTP_CTRL_IE_LOCAL_PORT);
+      msg_len+=put_int(&msg_buff,(int)send_par.tunnel__addres()().local__port());
+
+      msg_len+=put_int(&msg_buff,GTP_CTRL_IE_REMOTE_IP);
+      str.str_begin=(const unsigned char*)(const char*)send_par.tunnel__addres()().remote__ip();
+      str.str_size=send_par.tunnel__addres()().remote__ip().lengthof();
+      msg_len+=put_str(&msg_buff,&str);
+
+      msg_len+=put_int(&msg_buff,GTP_CTRL_IE_REMOTE_PORT);
+      msg_len+=put_int(&msg_buff,(int)send_par.tunnel__addres()().remote__port());
+    }
+    if(send_par.param__list().ispresent()){
+      for(int i=0;i<send_par.param__list()().lengthof();i++){
+        switch(send_par.param__list()()[i].get_selection()){
+          case GTP__Tunnel__param::ALT_set__address__mode:
+            msg_len+=put_int(&msg_buff,GTP_CTRL_IE_PARAM_SET_ADDR_MODE);
+            msg_len+=put_int(&msg_buff,(int)send_par.param__list()()[i].set__address__mode());
+            break;
+          default:
+            break;
+        }
+      }
+    }
+    
+    int cp=msg_buff.pos;
+    msg_buff.pos=0;
+    put_int(&msg_buff,msg_len);
+    msg_buff.pos=cp;
+    send_msg(&msg_buff);
+    free_msg_buffer(&msg_buff);
+  }
+
+  log("outgoing_send GTP__Tunnel__init finished");
+}
+
+void GTP__Tunnel__control__PT::outgoing_send(const GTP__Tunnel__bye& /*send_par*/)
+{
+  if(daemon_fd==-1){
+    report_ind(GTP__Tunnel__Result__code::ERROR_,"There is no connection to the daemon");
+    return;
+  }
+  msg_buffer msg_buff;
+  init_msg_buffer(&msg_buff);
+
+  put_int(&msg_buff,8);
+  put_int(&msg_buff,GTP_CTRL_MSG_BYE);
+
+
+  send_msg(&msg_buff);
+  free_msg_buffer(&msg_buff);
+  
+}
+
+void GTP__Tunnel__control__PT::outgoing_send(const GTP__Tunnel__create& send_par)
+{
+  if(daemon_fd==-1){
+    report_ind(GTP__Tunnel__Result__code::ERROR_,"There is no connection to the daemon");
+    return;
+  }
+  str_holder str;
+
+  msg_buffer msg_buff;
+  init_msg_buffer(&msg_buff);
+
+  msg_buff.pos+=4; // skip the length, will be filled later
+  int msg_len=4;
+
+  msg_len+=put_int(&msg_buff,GTP_CTRL_MSG_CREATE);
+
+  msg_len+=put_int(&msg_buff,GTP_CTRL_IE_OUT_TEID);
+  str.str_begin=(const unsigned char*)send_par.outgoing__TEID();
+  str.str_size=send_par.outgoing__TEID().lengthof();
+  msg_len+=put_str(&msg_buff,&str);
+
+  if(send_par.incoming__TEID().ispresent()){
+    msg_len+=put_int(&msg_buff,GTP_CTRL_IE_IN_TEID);
+    str.str_begin=(const unsigned char*)send_par.incoming__TEID()();
+    str.str_size=send_par.incoming__TEID()().lengthof();
+    msg_len+=put_str(&msg_buff,&str);
+  }
+
+  msg_len+=put_int(&msg_buff,GTP_CTRL_IE_ADDR_TYPE);
+  msg_len+=put_int(&msg_buff,(int)send_par.user__address__type());
+
+  msg_len+=put_int(&msg_buff,GTP_CTRL_IE_ADDR);
+  str.str_begin=(const unsigned char*)send_par.user__address();
+  str.str_size=send_par.user__address().lengthof();
+  msg_len+=put_str(&msg_buff,&str);
+
+  if(send_par.filter().ispresent()){
+    if(send_par.filter()().proto().ispresent()){
+      msg_len+=put_int(&msg_buff,GTP_CTRL_IE_FILTER_PROTO);
+      msg_len+=put_int(&msg_buff,(int)send_par.filter()().proto()());
+    }
+    if(send_par.filter()().local__port().ispresent()){
+      msg_len+=put_int(&msg_buff,GTP_CTRL_IE_FILTER_LOCAL_PORT);
+      msg_len+=put_int(&msg_buff,(int)send_par.filter()().local__port()());
+    }
+
+    if(send_par.filter()().remote__ip().ispresent()){
+      msg_len+=put_int(&msg_buff,GTP_CTRL_IE_FILTER_REMOTE_IP);
+      str.str_begin=(const unsigned char*)send_par.filter()().remote__ip()();
+      str.str_size=send_par.filter()().remote__ip()().lengthof();
+      msg_len+=put_str(&msg_buff,&str);
+    }
+
+    if(send_par.filter()().remote__port().ispresent()){
+      msg_len+=put_int(&msg_buff,GTP_CTRL_IE_FILTER_REMOTE_PORT);
+      msg_len+=put_int(&msg_buff,(int)send_par.filter()().remote__port()());
+    }
+  }
+
+
+  if(send_par.tunnel__addres().ispresent()){
+    msg_len+=put_int(&msg_buff,GTP_CTRL_IE_LOCAL_IP);
+    str.str_begin=(const unsigned char*)(const char*)send_par.tunnel__addres()().local__ip();
+    str.str_size=send_par.tunnel__addres()().local__ip().lengthof();
+    msg_len+=put_str(&msg_buff,&str);
+
+    msg_len+=put_int(&msg_buff,GTP_CTRL_IE_LOCAL_PORT);
+    msg_len+=put_int(&msg_buff,(int)send_par.tunnel__addres()().local__port());
+
+    msg_len+=put_int(&msg_buff,GTP_CTRL_IE_REMOTE_IP);
+    str.str_begin=(const unsigned char*)(const char*)send_par.tunnel__addres()().remote__ip();
+    str.str_size=send_par.tunnel__addres()().remote__ip().lengthof();
+    msg_len+=put_str(&msg_buff,&str);
+
+    msg_len+=put_int(&msg_buff,GTP_CTRL_IE_REMOTE_PORT);
+    msg_len+=put_int(&msg_buff,(int)send_par.tunnel__addres()().remote__port());
+  }
+
+  int cp=msg_buff.pos;
+  msg_buff.pos=0;
+  put_int(&msg_buff,msg_len);
+  msg_buff.pos=cp;
+  send_msg(&msg_buff);
+  free_msg_buffer(&msg_buff);
+}
+
+void GTP__Tunnel__control__PT::outgoing_send(const GTP__Tunnel__destroy& send_par)
+{
+  if(daemon_fd==-1){
+    report_ind(GTP__Tunnel__Result__code::ERROR_,"There is no connection to the daemon");
+    return;
+  }
+  str_holder str;
+
+  msg_buffer msg_buff;
+  init_msg_buffer(&msg_buff);
+
+  msg_buff.pos+=4; // skip the length, will be filled later
+  int msg_len=4;
+
+  msg_len+=put_int(&msg_buff,GTP_CTRL_MSG_DESTROY);
+
+  msg_len+=put_int(&msg_buff,GTP_CTRL_IE_ADDR);
+  str.str_begin=(const unsigned char*)send_par.user__address();
+  str.str_size=send_par.user__address().lengthof();
+  msg_len+=put_str(&msg_buff,&str);
+
+  msg_len+=put_int(&msg_buff,GTP_CTRL_IE_OUT_TEID);
+  str.str_begin=(const unsigned char*)send_par.outgoing__TEID();
+  str.str_size=send_par.outgoing__TEID().lengthof();
+  msg_len+=put_str(&msg_buff,&str);
+
+  msg_len+=put_int(&msg_buff,GTP_CTRL_IE_IN_TEID);
+  str.str_begin=(const unsigned char*)send_par.incoming__TEID();
+  str.str_size=send_par.incoming__TEID().lengthof();
+  msg_len+=put_str(&msg_buff,&str);
+
+  int cp=msg_buff.pos;
+  msg_buff.pos=0;
+  put_int(&msg_buff,msg_len);
+  msg_buff.pos=cp;
+  send_msg(&msg_buff);
+  free_msg_buffer(&msg_buff);
+
+}
+
+} /* end of namespace */
+
diff --git a/src/Test_port/GTP_Tunnel_control_PT.hh b/src/Test_port/GTP_Tunnel_control_PT.hh
new file mode 100644
index 0000000..32e84b9
--- /dev/null
+++ b/src/Test_port/GTP_Tunnel_control_PT.hh
@@ -0,0 +1,62 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef GTP__Tunnel__control__PT_HH
+#define GTP__Tunnel__control__PT_HH
+
+#include "GTP_Tunnel_PortTypes.hh"
+#include "GTP_ctrl_handler.h"
+namespace GTP__Tunnel__PortTypes {
+
+class GTP__Tunnel__control__PT : public GTP__Tunnel__control__PT_BASE {
+public:
+	GTP__Tunnel__control__PT(const char *par_port_name = NULL);
+	~GTP__Tunnel__control__PT();
+
+	void set_parameter(const char *parameter_name,
+		const char *parameter_value);
+
+  int daemon_fd;
+
+private:
+	/* void Handle_Fd_Event(int fd, boolean is_readable,
+		boolean is_writable, boolean is_error); */
+	void Handle_Fd_Event_Error(int fd);
+	void Handle_Fd_Event_Writable(int fd);
+	void Handle_Fd_Event_Readable(int fd);
+	/* void Handle_Timeout(double time_since_last_call); */
+protected:
+	void user_map(const char *system_port);
+	void user_unmap(const char *system_port);
+
+	void user_start();
+	void user_stop();
+
+	void outgoing_send(const GTP__Tunnel__init& send_par);
+	void outgoing_send(const GTP__Tunnel__bye& send_par);
+	void outgoing_send(const GTP__Tunnel__create& send_par);
+	void outgoing_send(const GTP__Tunnel__destroy& send_par);
+
+  void report_ind(GTP__Tunnel__Result__code code, const char *fmt, ... );
+  void log(const char *fmt, ...);
+
+  void send_msg(const msg_buffer*);
+  
+  msg_buffer  recv_buffer;
+
+};
+
+} /* end of namespace */
+
+#endif
diff --git a/src/Test_port/GTP_ctrl_handler.c b/src/Test_port/GTP_ctrl_handler.c
new file mode 100644
index 0000000..068c201
--- /dev/null
+++ b/src/Test_port/GTP_ctrl_handler.c
@@ -0,0 +1,119 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+#include "GTP_ctrl_handler.h"
+#include "GTP_mem_handler.h"
+#include <string.h>
+#include <stdio.h>
+
+int put_int(msg_buffer* buffer ,const int data){
+
+  inc_buff_size(buffer,4);
+  
+  buffer->msg[buffer->pos] = (data >> 24) & 0xff;
+  buffer->pos++;
+  buffer->msg[buffer->pos] = (data >> 16) & 0xff;
+  buffer->pos++;
+  buffer->msg[buffer->pos] = (data >> 8) & 0xff;
+  buffer->pos++;
+  buffer->msg[buffer->pos] = data & 0xff;
+  buffer->pos++;
+  
+  return 4;
+}
+
+
+int get_int(msg_buffer* buffer,int* data){
+  if((buffer->pos + 4 ) >  buffer->size){  
+    return -1; // not enough octets in the buffer
+  }
+
+  *data=buffer->msg[buffer->pos];
+  (*data) <<= 8;
+
+  buffer->pos++;
+
+  *data+=buffer->msg[buffer->pos];
+  (*data) <<= 8;
+  buffer->pos++;
+  *data+=buffer->msg[buffer->pos];
+  (*data) <<= 8;
+  buffer->pos++;
+  *data+=buffer->msg[buffer->pos];
+  buffer->pos++;
+
+  return 4;
+}
+
+int put_str(msg_buffer* buffer,const str_holder* data){
+  int ret_val=put_int(buffer,data->str_size);
+  
+  inc_buff_size(buffer,data->str_size);
+  
+  memcpy(buffer->msg+buffer->pos,data->str_begin,data->str_size);
+  buffer->pos += data->str_size;
+  return ret_val + data->str_size;
+
+}
+
+int get_str(msg_buffer* buffer,str_holder* data){
+  int ret_val=-1;
+  int str_size;
+  if(get_int(buffer,&str_size)!=-1){
+    if((buffer->pos +  str_size) <=  buffer->size){
+      data->str_begin = buffer->msg+buffer->pos;
+      data->str_size = str_size;
+      ret_val = 4+ str_size;
+      buffer->pos += str_size;
+    }
+  }
+  return ret_val;
+
+}
+
+void init_msg_buffer(msg_buffer* buffer){
+  buffer->msg=(unsigned char*)Malloc(256*sizeof(unsigned char));
+  buffer->size =256;
+  buffer->pos =0;
+}
+void free_msg_buffer(msg_buffer* buffer){
+  Free(buffer->msg);
+}
+
+void inc_buff_size(msg_buffer* buffer,int new_size){
+  while((buffer->pos + new_size ) >=  buffer->size){
+    buffer->size *=2;
+    buffer->msg=(unsigned char*)Realloc(buffer->msg,buffer->size);
+  }
+}
+
+void copy_str_holder(str_holder* target, const str_holder* source){
+  unsigned char* tmp=(unsigned char*)Malloc(source->str_size*sizeof(unsigned char));
+  memcpy(tmp,source->str_begin,source->str_size);
+  target->str_size=source->str_size;
+  target->str_begin=tmp;
+}
+void free_str_holder(str_holder* str){
+  if(str->str_size>=0){
+    Free((void*)str->str_begin);
+  }
+}
+int str_eq(const str_holder &lhs, const str_holder &rhs){
+
+    if(lhs.str_size == rhs.str_size){
+      return memcmp(lhs.str_begin,rhs.str_begin,lhs.str_size);
+    }
+    return lhs.str_size - rhs.str_size;
+
+}
+
diff --git a/src/Test_port/GTP_ctrl_handler.h b/src/Test_port/GTP_ctrl_handler.h
new file mode 100644
index 0000000..de11279
--- /dev/null
+++ b/src/Test_port/GTP_ctrl_handler.h
@@ -0,0 +1,125 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+// Contains the definitions of the message handler function, msg & IE codes
+// Used by both the test port and the daemon.
+
+#ifndef GTP_CTRL_HANDLER_H_
+#define GTP_CTRL_HANDLER_H_
+#ifdef __cplusplus
+//extern "C" {
+#endif
+#include <string.h>
+// MSG structure between the TP & Daemon
+//
+//      |------------------------|
+//      |    LENGTH              |
+//      |------------------------|
+//      |    MSG code            |
+//      |------------------------|
+//      |  IE  list              |
+//      |------------------------|
+//
+//
+// IE structure
+//
+//      |------------------------|
+//      |    IE code             |
+//      |------------------------|
+//      | DATA  (int, string, IE)|
+//      |------------------------|
+//
+
+
+// MSG type and IE type codes used by messages between the App and the Daemon
+
+typedef enum {
+// MSG codes
+GTP_CTRL_MSG_INIT = 0,  GTP_CTRL_MSG_INIT_ACK = 1,
+GTP_CTRL_MSG_BYE = 2,   GTP_CTRL_MSG_BYE_ACK = 3,
+GTP_CTRL_MSG_CREATE = 4,GTP_CTRL_MSG_CREATE_ACK = 5,
+GTP_CTRL_MSG_DESTROY = 6,
+GTP_CTRL_MSG_INDICATION = 7,
+GTP_CTRL_MSG_GET_TEID = 8,
+GTP_CTRL_MSG_GET_TEID_DATA =9,
+// IE codes
+
+GTP_CTRL_IE_OUT_TEID= 1000,
+GTP_CTRL_IE_IN_TEID= 1001,
+GTP_CTRL_IE_LOCAL_PORT= 1002,
+GTP_CTRL_IE_LOCAL_IP= 1003,
+GTP_CTRL_IE_REMOTE_IP= 1004,
+GTP_CTRL_IE_REMOTE_PORT= 1005,
+GTP_CTRL_IE_IF_NAME= 1006,
+GTP_CTRL_IE_PARAM_SET_ADDR_MODE= 1007,
+GTP_CTRL_IE_RES_CODE= 1008,
+GTP_CTRL_IE_RES_TXT= 1009,
+GTP_CTRL_IE_ADDR_TYPE= 1010,
+GTP_CTRL_IE_ADDR= 1011,
+GTP_CTRL_IE_FILTER_LOCAL_PORT= 1012,
+GTP_CTRL_IE_FILTER_REMOTE_IP= 1013,
+GTP_CTRL_IE_FILTER_REMOTE_PORT= 1014,
+GTP_CTRL_IE_FILTER_PROTO= 1015,
+GTP_CTRL_IE_PROTO= 1016
+} ctrl_msg_ie_codes;
+
+
+// Buffer type
+typedef struct {
+  unsigned char* msg;
+  int size;
+  int pos;
+} msg_buffer;
+
+void init_msg_buffer(msg_buffer*);
+void free_msg_buffer(msg_buffer*);
+
+
+
+// String representation 
+
+typedef struct str_holder_struct {
+  const unsigned char* str_begin; // points to the beginning of the string
+                                  // in the storage area
+  int str_size;
+  
+  bool operator==(const struct str_holder_struct &other) const{
+    return (str_size == other.str_size) && (memcmp(str_begin,other.str_begin,str_size)==0);
+  };
+  
+} str_holder;
+
+void copy_str_holder(str_holder*, const str_holder*);
+void free_str_holder(str_holder*);
+
+// puts an int into the buffer, 4 byte, msb first
+int put_int(msg_buffer*,const int);
+// retrieves an int from a buffer
+int get_int(msg_buffer*,int*);
+
+// stores or retrieve a string (octet or char)
+// first store the length as int (in 4 octets)
+// then the string (without \0 at the end)
+// The get function sets only the pointer and the length value, doesn't copy
+
+int put_str(msg_buffer*,const str_holder*);
+int get_str(msg_buffer*,str_holder*);
+
+int str_eq(const str_holder &lhs, const str_holder &rhs);
+// increase the free space in the buffer to at least new_size octets
+void inc_buff_size(msg_buffer*,int new_size);
+
+#ifdef __cplusplus
+//}
+#endif
+#endif
diff --git a/src/Test_port/GTP_mem_handler.h b/src/Test_port/GTP_mem_handler.h
new file mode 100644
index 0000000..2975556
--- /dev/null
+++ b/src/Test_port/GTP_mem_handler.h
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef GTP_MEM_HANDLER_H_
+#define GTP_MEM_HANDLER_H_
+
+#include "memory.h"
+
+// Just to use the TITAN's memory functions in the Test port
+
+#endif
diff --git a/src/common/GTP_ctrl_handler.c b/src/common/GTP_ctrl_handler.c
new file mode 100644
index 0000000..068c201
--- /dev/null
+++ b/src/common/GTP_ctrl_handler.c
@@ -0,0 +1,119 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+#include "GTP_ctrl_handler.h"
+#include "GTP_mem_handler.h"
+#include <string.h>
+#include <stdio.h>
+
+int put_int(msg_buffer* buffer ,const int data){
+
+  inc_buff_size(buffer,4);
+  
+  buffer->msg[buffer->pos] = (data >> 24) & 0xff;
+  buffer->pos++;
+  buffer->msg[buffer->pos] = (data >> 16) & 0xff;
+  buffer->pos++;
+  buffer->msg[buffer->pos] = (data >> 8) & 0xff;
+  buffer->pos++;
+  buffer->msg[buffer->pos] = data & 0xff;
+  buffer->pos++;
+  
+  return 4;
+}
+
+
+int get_int(msg_buffer* buffer,int* data){
+  if((buffer->pos + 4 ) >  buffer->size){  
+    return -1; // not enough octets in the buffer
+  }
+
+  *data=buffer->msg[buffer->pos];
+  (*data) <<= 8;
+
+  buffer->pos++;
+
+  *data+=buffer->msg[buffer->pos];
+  (*data) <<= 8;
+  buffer->pos++;
+  *data+=buffer->msg[buffer->pos];
+  (*data) <<= 8;
+  buffer->pos++;
+  *data+=buffer->msg[buffer->pos];
+  buffer->pos++;
+
+  return 4;
+}
+
+int put_str(msg_buffer* buffer,const str_holder* data){
+  int ret_val=put_int(buffer,data->str_size);
+  
+  inc_buff_size(buffer,data->str_size);
+  
+  memcpy(buffer->msg+buffer->pos,data->str_begin,data->str_size);
+  buffer->pos += data->str_size;
+  return ret_val + data->str_size;
+
+}
+
+int get_str(msg_buffer* buffer,str_holder* data){
+  int ret_val=-1;
+  int str_size;
+  if(get_int(buffer,&str_size)!=-1){
+    if((buffer->pos +  str_size) <=  buffer->size){
+      data->str_begin = buffer->msg+buffer->pos;
+      data->str_size = str_size;
+      ret_val = 4+ str_size;
+      buffer->pos += str_size;
+    }
+  }
+  return ret_val;
+
+}
+
+void init_msg_buffer(msg_buffer* buffer){
+  buffer->msg=(unsigned char*)Malloc(256*sizeof(unsigned char));
+  buffer->size =256;
+  buffer->pos =0;
+}
+void free_msg_buffer(msg_buffer* buffer){
+  Free(buffer->msg);
+}
+
+void inc_buff_size(msg_buffer* buffer,int new_size){
+  while((buffer->pos + new_size ) >=  buffer->size){
+    buffer->size *=2;
+    buffer->msg=(unsigned char*)Realloc(buffer->msg,buffer->size);
+  }
+}
+
+void copy_str_holder(str_holder* target, const str_holder* source){
+  unsigned char* tmp=(unsigned char*)Malloc(source->str_size*sizeof(unsigned char));
+  memcpy(tmp,source->str_begin,source->str_size);
+  target->str_size=source->str_size;
+  target->str_begin=tmp;
+}
+void free_str_holder(str_holder* str){
+  if(str->str_size>=0){
+    Free((void*)str->str_begin);
+  }
+}
+int str_eq(const str_holder &lhs, const str_holder &rhs){
+
+    if(lhs.str_size == rhs.str_size){
+      return memcmp(lhs.str_begin,rhs.str_begin,lhs.str_size);
+    }
+    return lhs.str_size - rhs.str_size;
+
+}
+
diff --git a/src/common/GTP_ctrl_handler.h b/src/common/GTP_ctrl_handler.h
new file mode 100644
index 0000000..de11279
--- /dev/null
+++ b/src/common/GTP_ctrl_handler.h
@@ -0,0 +1,125 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+// Contains the definitions of the message handler function, msg & IE codes
+// Used by both the test port and the daemon.
+
+#ifndef GTP_CTRL_HANDLER_H_
+#define GTP_CTRL_HANDLER_H_
+#ifdef __cplusplus
+//extern "C" {
+#endif
+#include <string.h>
+// MSG structure between the TP & Daemon
+//
+//      |------------------------|
+//      |    LENGTH              |
+//      |------------------------|
+//      |    MSG code            |
+//      |------------------------|
+//      |  IE  list              |
+//      |------------------------|
+//
+//
+// IE structure
+//
+//      |------------------------|
+//      |    IE code             |
+//      |------------------------|
+//      | DATA  (int, string, IE)|
+//      |------------------------|
+//
+
+
+// MSG type and IE type codes used by messages between the App and the Daemon
+
+typedef enum {
+// MSG codes
+GTP_CTRL_MSG_INIT = 0,  GTP_CTRL_MSG_INIT_ACK = 1,
+GTP_CTRL_MSG_BYE = 2,   GTP_CTRL_MSG_BYE_ACK = 3,
+GTP_CTRL_MSG_CREATE = 4,GTP_CTRL_MSG_CREATE_ACK = 5,
+GTP_CTRL_MSG_DESTROY = 6,
+GTP_CTRL_MSG_INDICATION = 7,
+GTP_CTRL_MSG_GET_TEID = 8,
+GTP_CTRL_MSG_GET_TEID_DATA =9,
+// IE codes
+
+GTP_CTRL_IE_OUT_TEID= 1000,
+GTP_CTRL_IE_IN_TEID= 1001,
+GTP_CTRL_IE_LOCAL_PORT= 1002,
+GTP_CTRL_IE_LOCAL_IP= 1003,
+GTP_CTRL_IE_REMOTE_IP= 1004,
+GTP_CTRL_IE_REMOTE_PORT= 1005,
+GTP_CTRL_IE_IF_NAME= 1006,
+GTP_CTRL_IE_PARAM_SET_ADDR_MODE= 1007,
+GTP_CTRL_IE_RES_CODE= 1008,
+GTP_CTRL_IE_RES_TXT= 1009,
+GTP_CTRL_IE_ADDR_TYPE= 1010,
+GTP_CTRL_IE_ADDR= 1011,
+GTP_CTRL_IE_FILTER_LOCAL_PORT= 1012,
+GTP_CTRL_IE_FILTER_REMOTE_IP= 1013,
+GTP_CTRL_IE_FILTER_REMOTE_PORT= 1014,
+GTP_CTRL_IE_FILTER_PROTO= 1015,
+GTP_CTRL_IE_PROTO= 1016
+} ctrl_msg_ie_codes;
+
+
+// Buffer type
+typedef struct {
+  unsigned char* msg;
+  int size;
+  int pos;
+} msg_buffer;
+
+void init_msg_buffer(msg_buffer*);
+void free_msg_buffer(msg_buffer*);
+
+
+
+// String representation 
+
+typedef struct str_holder_struct {
+  const unsigned char* str_begin; // points to the beginning of the string
+                                  // in the storage area
+  int str_size;
+  
+  bool operator==(const struct str_holder_struct &other) const{
+    return (str_size == other.str_size) && (memcmp(str_begin,other.str_begin,str_size)==0);
+  };
+  
+} str_holder;
+
+void copy_str_holder(str_holder*, const str_holder*);
+void free_str_holder(str_holder*);
+
+// puts an int into the buffer, 4 byte, msb first
+int put_int(msg_buffer*,const int);
+// retrieves an int from a buffer
+int get_int(msg_buffer*,int*);
+
+// stores or retrieve a string (octet or char)
+// first store the length as int (in 4 octets)
+// then the string (without \0 at the end)
+// The get function sets only the pointer and the length value, doesn't copy
+
+int put_str(msg_buffer*,const str_holder*);
+int get_str(msg_buffer*,str_holder*);
+
+int str_eq(const str_holder &lhs, const str_holder &rhs);
+// increase the free space in the buffer to at least new_size octets
+void inc_buff_size(msg_buffer*,int new_size);
+
+#ifdef __cplusplus
+//}
+#endif
+#endif
diff --git a/src/daemon/GTP_ctrl_handler.c b/src/daemon/GTP_ctrl_handler.c
new file mode 100644
index 0000000..068c201
--- /dev/null
+++ b/src/daemon/GTP_ctrl_handler.c
@@ -0,0 +1,119 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+#include "GTP_ctrl_handler.h"
+#include "GTP_mem_handler.h"
+#include <string.h>
+#include <stdio.h>
+
+int put_int(msg_buffer* buffer ,const int data){
+
+  inc_buff_size(buffer,4);
+  
+  buffer->msg[buffer->pos] = (data >> 24) & 0xff;
+  buffer->pos++;
+  buffer->msg[buffer->pos] = (data >> 16) & 0xff;
+  buffer->pos++;
+  buffer->msg[buffer->pos] = (data >> 8) & 0xff;
+  buffer->pos++;
+  buffer->msg[buffer->pos] = data & 0xff;
+  buffer->pos++;
+  
+  return 4;
+}
+
+
+int get_int(msg_buffer* buffer,int* data){
+  if((buffer->pos + 4 ) >  buffer->size){  
+    return -1; // not enough octets in the buffer
+  }
+
+  *data=buffer->msg[buffer->pos];
+  (*data) <<= 8;
+
+  buffer->pos++;
+
+  *data+=buffer->msg[buffer->pos];
+  (*data) <<= 8;
+  buffer->pos++;
+  *data+=buffer->msg[buffer->pos];
+  (*data) <<= 8;
+  buffer->pos++;
+  *data+=buffer->msg[buffer->pos];
+  buffer->pos++;
+
+  return 4;
+}
+
+int put_str(msg_buffer* buffer,const str_holder* data){
+  int ret_val=put_int(buffer,data->str_size);
+  
+  inc_buff_size(buffer,data->str_size);
+  
+  memcpy(buffer->msg+buffer->pos,data->str_begin,data->str_size);
+  buffer->pos += data->str_size;
+  return ret_val + data->str_size;
+
+}
+
+int get_str(msg_buffer* buffer,str_holder* data){
+  int ret_val=-1;
+  int str_size;
+  if(get_int(buffer,&str_size)!=-1){
+    if((buffer->pos +  str_size) <=  buffer->size){
+      data->str_begin = buffer->msg+buffer->pos;
+      data->str_size = str_size;
+      ret_val = 4+ str_size;
+      buffer->pos += str_size;
+    }
+  }
+  return ret_val;
+
+}
+
+void init_msg_buffer(msg_buffer* buffer){
+  buffer->msg=(unsigned char*)Malloc(256*sizeof(unsigned char));
+  buffer->size =256;
+  buffer->pos =0;
+}
+void free_msg_buffer(msg_buffer* buffer){
+  Free(buffer->msg);
+}
+
+void inc_buff_size(msg_buffer* buffer,int new_size){
+  while((buffer->pos + new_size ) >=  buffer->size){
+    buffer->size *=2;
+    buffer->msg=(unsigned char*)Realloc(buffer->msg,buffer->size);
+  }
+}
+
+void copy_str_holder(str_holder* target, const str_holder* source){
+  unsigned char* tmp=(unsigned char*)Malloc(source->str_size*sizeof(unsigned char));
+  memcpy(tmp,source->str_begin,source->str_size);
+  target->str_size=source->str_size;
+  target->str_begin=tmp;
+}
+void free_str_holder(str_holder* str){
+  if(str->str_size>=0){
+    Free((void*)str->str_begin);
+  }
+}
+int str_eq(const str_holder &lhs, const str_holder &rhs){
+
+    if(lhs.str_size == rhs.str_size){
+      return memcmp(lhs.str_begin,rhs.str_begin,lhs.str_size);
+    }
+    return lhs.str_size - rhs.str_size;
+
+}
+
diff --git a/src/daemon/GTP_ctrl_handler.h b/src/daemon/GTP_ctrl_handler.h
new file mode 100644
index 0000000..de11279
--- /dev/null
+++ b/src/daemon/GTP_ctrl_handler.h
@@ -0,0 +1,125 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+// Contains the definitions of the message handler function, msg & IE codes
+// Used by both the test port and the daemon.
+
+#ifndef GTP_CTRL_HANDLER_H_
+#define GTP_CTRL_HANDLER_H_
+#ifdef __cplusplus
+//extern "C" {
+#endif
+#include <string.h>
+// MSG structure between the TP & Daemon
+//
+//      |------------------------|
+//      |    LENGTH              |
+//      |------------------------|
+//      |    MSG code            |
+//      |------------------------|
+//      |  IE  list              |
+//      |------------------------|
+//
+//
+// IE structure
+//
+//      |------------------------|
+//      |    IE code             |
+//      |------------------------|
+//      | DATA  (int, string, IE)|
+//      |------------------------|
+//
+
+
+// MSG type and IE type codes used by messages between the App and the Daemon
+
+typedef enum {
+// MSG codes
+GTP_CTRL_MSG_INIT = 0,  GTP_CTRL_MSG_INIT_ACK = 1,
+GTP_CTRL_MSG_BYE = 2,   GTP_CTRL_MSG_BYE_ACK = 3,
+GTP_CTRL_MSG_CREATE = 4,GTP_CTRL_MSG_CREATE_ACK = 5,
+GTP_CTRL_MSG_DESTROY = 6,
+GTP_CTRL_MSG_INDICATION = 7,
+GTP_CTRL_MSG_GET_TEID = 8,
+GTP_CTRL_MSG_GET_TEID_DATA =9,
+// IE codes
+
+GTP_CTRL_IE_OUT_TEID= 1000,
+GTP_CTRL_IE_IN_TEID= 1001,
+GTP_CTRL_IE_LOCAL_PORT= 1002,
+GTP_CTRL_IE_LOCAL_IP= 1003,
+GTP_CTRL_IE_REMOTE_IP= 1004,
+GTP_CTRL_IE_REMOTE_PORT= 1005,
+GTP_CTRL_IE_IF_NAME= 1006,
+GTP_CTRL_IE_PARAM_SET_ADDR_MODE= 1007,
+GTP_CTRL_IE_RES_CODE= 1008,
+GTP_CTRL_IE_RES_TXT= 1009,
+GTP_CTRL_IE_ADDR_TYPE= 1010,
+GTP_CTRL_IE_ADDR= 1011,
+GTP_CTRL_IE_FILTER_LOCAL_PORT= 1012,
+GTP_CTRL_IE_FILTER_REMOTE_IP= 1013,
+GTP_CTRL_IE_FILTER_REMOTE_PORT= 1014,
+GTP_CTRL_IE_FILTER_PROTO= 1015,
+GTP_CTRL_IE_PROTO= 1016
+} ctrl_msg_ie_codes;
+
+
+// Buffer type
+typedef struct {
+  unsigned char* msg;
+  int size;
+  int pos;
+} msg_buffer;
+
+void init_msg_buffer(msg_buffer*);
+void free_msg_buffer(msg_buffer*);
+
+
+
+// String representation 
+
+typedef struct str_holder_struct {
+  const unsigned char* str_begin; // points to the beginning of the string
+                                  // in the storage area
+  int str_size;
+  
+  bool operator==(const struct str_holder_struct &other) const{
+    return (str_size == other.str_size) && (memcmp(str_begin,other.str_begin,str_size)==0);
+  };
+  
+} str_holder;
+
+void copy_str_holder(str_holder*, const str_holder*);
+void free_str_holder(str_holder*);
+
+// puts an int into the buffer, 4 byte, msb first
+int put_int(msg_buffer*,const int);
+// retrieves an int from a buffer
+int get_int(msg_buffer*,int*);
+
+// stores or retrieve a string (octet or char)
+// first store the length as int (in 4 octets)
+// then the string (without \0 at the end)
+// The get function sets only the pointer and the length value, doesn't copy
+
+int put_str(msg_buffer*,const str_holder*);
+int get_str(msg_buffer*,str_holder*);
+
+int str_eq(const str_holder &lhs, const str_holder &rhs);
+// increase the free space in the buffer to at least new_size octets
+void inc_buff_size(msg_buffer*,int new_size);
+
+#ifdef __cplusplus
+//}
+#endif
+#endif
diff --git a/src/daemon/GTP_mem_handler.c b/src/daemon/GTP_mem_handler.c
new file mode 100644
index 0000000..3f50c0e
--- /dev/null
+++ b/src/daemon/GTP_mem_handler.c
@@ -0,0 +1,34 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+#include "GTP_mem_handler.h"
+#include <stdlib.h>
+
+void *Malloc(size_t size){
+  void *ret_val=malloc(size);
+  if(ret_val==NULL){
+    abort();
+  }
+  return ret_val;
+}
+void Free(void *ptr){
+  free(ptr);
+}
+void *Realloc(void *ptr, size_t size){
+  void *ret_val=realloc(ptr,size);
+  if(ret_val==NULL){
+    abort();
+  }
+  return ret_val;
+}
+
diff --git a/src/daemon/GTP_mem_handler.h b/src/daemon/GTP_mem_handler.h
new file mode 100644
index 0000000..e0604a3
--- /dev/null
+++ b/src/daemon/GTP_mem_handler.h
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef GTP_MEM_HANDLER_H_
+#define GTP_MEM_HANDLER_H_
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void *Malloc(size_t size);
+void Free(void *ptr);
+void *Realloc(void *ptr, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/src/daemon/Makefile b/src/daemon/Makefile
new file mode 100644
index 0000000..b6089e1
--- /dev/null
+++ b/src/daemon/Makefile
@@ -0,0 +1,181 @@
+# This Makefile was generated by the Makefile Generator
+# of the TTCN-3 Test Executor version CRL 113 200/5 R4C
+# for Gabor Szalai (ethgasz@esekilxxen1844) on Thu Jan 28 13:08:18 2016
+
+# Copyright (c) 2000-2018 Ericsson Telecom AB
+
+# The following make commands are available:
+# - make, make all      Builds the executable test suite.
+# - make archive        Archives all source files.
+# - make check          Checks the semantics of TTCN-3 and ASN.1 modules.
+# - make clean          Removes all generated files.
+# - make compile        Translates TTCN-3 and ASN.1 modules to C++.
+# - make dep            Creates/updates dependency list.
+# - make executable     Builds the executable test suite.
+# - make library        Builds the library archive.
+# - make objects        Builds the object files without linking the executable.
+#
+# Set these variables...
+#
+
+# The path of your TTCN-3 Test Executor installation:
+# Uncomment this line to override the environment variable.
+# TTCN3_DIR = 
+
+# Your platform: (SOLARIS, SOLARIS8, LINUX, FREEBSD or WIN32)
+PLATFORM = LINUX
+
+# Your C++ compiler:
+# (if you change the platform, you may need to change the compiler)
+CXX = g++ 
+
+# Flags for the C++ preprocessor (and makedepend as well):
+CPPFLAGS = -DDEBUG
+
+# Flags for the C++ compiler:
+CXXFLAGS = -Wall  -g
+
+# Flags for the linker:
+LDFLAGS = -g
+
+ifeq ($(PLATFORM), WIN32)
+# Silence linker warnings.
+LDFLAGS += -Wl,--enable-auto-import,--enable-runtime-pseudo-reloc
+endif
+
+# Utility to create library files
+AR = ar
+ARFLAGS = 
+
+# Flags for the TTCN-3 and ASN.1 compiler:
+COMPILER_FLAGS = -L 
+
+# Execution mode: (either ttcn3 or ttcn3-parallel)
+TTCN3_LIB = 
+
+# The path of your OpenSSL installation:
+# If you do not have your own one, leave it unchanged.
+OPENSSL_DIR = $(TTCN3_DIR)
+
+# The path of your libxml2 installation:
+# If you do not have your own one, leave it unchanged.
+XMLDIR = $(TTCN3_DIR)
+
+# Directory to store the archived source files:
+# Note: you can set any directory except ./archive
+ARCHIVE_DIR = backup
+
+#
+# You may change these variables. Add your files if necessary...
+#
+
+# TTCN-3 modules of this project:
+TTCN3_MODULES =
+
+# ASN.1 modules of this project:
+ASN1_MODULES =
+
+# C++ source & header files generated from the TTCN-3 & ASN.1 modules of
+# this project:
+GENERATED_SOURCES =
+GENERATED_HEADERS =
+
+# C/C++ Source & header files of Test Ports, external functions and
+# other modules:
+USER_SOURCES = GTP_ctrl_handler.c daemon.cc GTP_mem_handler.c
+USER_HEADERS = GTP_ctrl_handler.h GTP_mem_handler.h
+
+# Object files of this project that are needed for the executable test suite:
+OBJECTS = $(GENERATED_OBJECTS) $(USER_OBJECTS)
+
+GENERATED_OBJECTS =
+
+USER_OBJECTS = GTP_ctrl_handler.o daemon.o GTP_mem_handler.o
+
+# Other files of the project (Makefile, configuration files, etc.)
+# that will be added to the archived source files:
+OTHER_FILES = a.out Makefile
+
+# The name of the executable test suite:
+EXECUTABLE = GTP_daemon
+
+
+
+LIBRARY = lib$(EXECUTABLE).a
+
+TARGET = $(EXECUTABLE)
+
+#
+# Do not modify these unless you know what you are doing...
+# Platform specific additional libraries:
+#
+SOLARIS_LIBS = -lsocket -lnsl -lxml2 -lresolv
+SOLARIS8_LIBS = -lsocket -lnsl -lxml2 -lresolv
+LINUX_LIBS = -lxml2 -lpthread -lrt
+FREEBSD_LIBS = -lxml2
+WIN32_LIBS = -lxml2
+
+#
+# Rules for building the executable...
+#
+
+all: $(TARGET) ;
+
+executable: $(EXECUTABLE) ;
+
+library: $(LIBRARY) ;
+
+objects: $(OBJECTS) compile;
+
+$(EXECUTABLE): $(OBJECTS)
+	if $(CXX) $(LDFLAGS) -o $@ $(OBJECTS) \
+	-L$(XMLDIR)/lib $($(PLATFORM)_LIBS); \
+	then : ; else $(TTCN3_DIR)/bin/titanver $(OBJECTS); exit 1; fi
+	touch compile
+
+$(LIBRARY): $(OBJECTS)
+	$(AR) -r $(ARFLAGS) $(LIBRARY) $(OBJECTS)
+
+.cc.o .c.o:
+	$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $@ $<
+
+$(GENERATED_SOURCES) $(GENERATED_HEADERS): compile
+	@if [ ! -f $@ ]; then rm -f compile; $(MAKE) compile; fi
+
+check: $(TTCN3_MODULES) $(ASN1_MODULES)
+	$(TTCN3_DIR)/bin/compiler -s $(COMPILER_FLAGS) \
+	$(TTCN3_MODULES) $(PREPROCESSED_TTCN3_MODULES) $(ASN1_MODULES)
+
+compile: $(TTCN3_MODULES) $(ASN1_MODULES)
+	$(TTCN3_DIR)/bin/compiler $(COMPILER_FLAGS) \
+	$(TTCN3_MODULES) $(ASN1_MODULES) - $?
+	touch $@
+
+clean:
+	-rm -f $(EXECUTABLE) $(LIBRARY) $(OBJECTS) $(GENERATED_HEADERS) \
+	$(GENERATED_SOURCES) compile \
+	tags *.log
+
+dep: $(GENERATED_SOURCES) $(USER_SOURCES) ;
+	makedepend $(CPPFLAGS) -DMAKEDEPEND_RUN $(GENERATED_SOURCES) $(USER_SOURCES)
+
+archive:
+	mkdir -p $(ARCHIVE_DIR)
+	tar -cvhf - $(TTCN3_MODULES) $(ASN1_MODULES) \
+	$(USER_HEADERS) $(USER_SOURCES) $(OTHER_FILES) \
+	| gzip >$(ARCHIVE_DIR)/`basename $(TARGET) .exe`-`date '+%y%m%d-%H%M'`.tgz
+
+diag:
+	$(TTCN3_DIR)/bin/compiler -v 2>&1
+	$(TTCN3_DIR)/bin/mctr_cli -v 2>&1
+	$(CXX) -v 2>&1
+	$(AR) -V 2>&1
+	@echo TTCN3_DIR=$(TTCN3_DIR)
+	@echo OPENSSL_DIR=$(OPENSSL_DIR)
+	@echo XMLDIR=$(XMLDIR)
+	@echo PLATFORM=$(PLATFORM)
+
+#
+# Add your rules here if necessary...
+#
+
diff --git a/src/daemon/daemon.cc b/src/daemon/daemon.cc
new file mode 100644
index 0000000..b09c72c
--- /dev/null
+++ b/src/daemon/daemon.cc
@@ -0,0 +1,1743 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/epoll.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <time.h>
+#include <signal.h>
+#include "GTP_mem_handler.h"
+#include "daemon.hh"
+
+
+#define MAX_EVENTS_PER_THREAD 8
+
+int lastIdx = 0;
+char* tun_name=NULL;  // The interface name to use
+int pipefd[2]; // The internal pipe
+int address_set_mode=2;
+bool threads_started=false;
+
+// controll conection listen fd
+int daemon_fd=-1;
+
+// GTP Tunnel addresses
+struct sockaddr_storage default_rem_addr;
+
+// GTP Tunnel fds
+int tun_fd=-1;  // TUN device
+
+// read or write lock of the ip teid maps;
+pthread_rwlock_t   ip_teid_lock;
+
+// ip teid maps
+
+// TEID -> IP database index
+//str_int_map teid_idx_map;
+
+// IP -> IP database index
+str_int_map ip_idx_map;
+
+// The IP database
+ip_entry_t*  ip_teid_db=NULL;
+int ip_teid_db_size=0;
+int ip_teid_db_entries=0;
+
+// map that holds the incoming teid - index map
+str_int_map teidin_idx_map;
+
+// read or write lock of it;
+pthread_rwlock_t   teid_idx_lock;
+
+// database of the pending IP prefix request
+int ip_req_db_size=0;
+int volatile ip_req_num=0;
+
+ip_req_db_t* ip_req_db=0;
+
+// thread identyfiers
+int tun_handler_num=0;
+pthread_t tun_handler;
+
+// local udp endpoint/port database
+int local_ep_length=0;
+int local_ep_num=0;
+local_ep_db_t *local_ep_db=NULL;
+
+// IP:port -> endpoint db idx map
+str_int_map ep_idx_map;
+// read or write lock of it;
+pthread_rwlock_t   ep_idx_lock;
+
+
+// epoll fd
+int epfd=-1;
+
+// 1 thread is started after that many local gtp endpoint
+int gtp_per_thread=3;
+
+void print_usage(){
+
+  printf("usage: GTP_daemon [--help| --interface_name <ifname> ]\r\n");
+  printf("\r\n");
+  printf("  --help: print this help\r\n");
+  printf("  --interface_name <ifname>: use the given ifname for the TUN interface name\r\n");
+  printf("                             if not specified the automatically selected name will be used\r\n");
+  printf("                             the same name should be specified for the controlling test port\r\n");
+  printf("\r\n");
+
+}
+
+#ifdef DEBUG
+void log(const char *fmt, ...)
+{
+  time_t c_time = time(NULL);
+  if (c_time != ((time_t)-1))
+  {
+    struct tm *c_time_struct = localtime(&c_time);
+    if (c_time_struct != NULL)
+    {
+      char c_time_str[256];
+      strftime(c_time_str, 256, "%T", c_time_struct);
+      printf("%s: ", c_time_str);
+    }
+  }
+
+  va_list args;
+  va_start(args, fmt);
+  vprintf(fmt,args);
+  va_end(args);
+  printf("\r\n");
+}
+
+void log_str_holder(const str_holder* data){
+    time_t c_time = time(NULL);
+    if (c_time != ((time_t)-1))
+    {
+      struct tm *c_time_struct = localtime(&c_time);
+      if (c_time_struct != NULL) 
+      {
+        char c_time_str[256];
+        strftime(c_time_str, 256, "%T", c_time_struct);
+        printf("%s: ", c_time_str);
+      }
+    }
+    printf("length: %d value:", data->str_size);
+    for(int i=0;i<data->str_size;i++){
+      printf("%02X", data->str_begin[i]);
+    }
+    printf("\r\n");
+}    
+
+#endif
+//void close_local_ep(int idx, int force=0);
+void close_local_ep(int idx, int force=0){
+  log("Try to close local GTP endpoint...");
+  if(idx==0 && force==0){
+    log("Default one. Do not close.");
+    return;
+  }
+  
+  if(local_ep_db[idx].usage_num == 0  && local_ep_db[idx].fd!=-1){
+    close(local_ep_db[idx].fd);
+    local_ep_db[idx].fd=-1;
+    local_ep_num--;
+    ep_idx_map.erase(local_ep_db[idx].key);
+    log("closed");
+  } else {
+    log("Can't be closed, in use.");
+  }
+}
+
+void process_options(int argc, char **argv){
+  if(argc==1) {
+    return;  // no option specified
+  } else if( argc == 2) {
+    if(!strcasecmp("--interface_name",argv[1])){
+      printf("Missing ifname.\r\n");
+    } else if(strcasecmp("--help",argv[1])){
+      printf("Unknown parameter\r\n");
+    }
+    print_usage();
+    exit(1);
+  } else if(argc == 3) {
+    if(!strcasecmp("--interface_name",argv[1])){
+      tun_name=strdup(argv[2]);
+    } else {
+      printf("Unknown parameter\r\n");
+      print_usage();
+      exit(1);
+    }
+
+  } else {
+    printf("Unknown parameter\r\n");
+    print_usage();
+    exit(1);
+  }
+}
+
+int fill_addr_struct(const char* local_ip, int local_port, struct sockaddr_storage *local_addr,const char* rem_ip, int rem_port, struct sockaddr_storage *rem_addr){
+  struct addrinfo* addrinf;
+  bzero(local_addr,sizeof(struct sockaddr_storage));
+  bzero(rem_addr,sizeof(struct sockaddr_storage));
+
+  if((getaddrinfo(local_ip, NULL, NULL, &addrinf))!=0){
+    log("getaddrinfo(local_ip, NULL, NULL, &addrinf))!=0");
+    return -1;
+  }
+  if(addrinf->ai_family==AF_INET){
+    struct sockaddr_in* saddr=( struct sockaddr_in*)local_addr;
+    struct sockaddr_in* locaddr=(struct sockaddr_in*)addrinf->ai_addr;
+
+    saddr->sin_family=addrinf->ai_family;
+    saddr->sin_port=htons((unsigned short)local_port);
+    memcpy(&saddr->sin_addr,&locaddr->sin_addr,sizeof(struct in_addr));
+  } else {
+    struct sockaddr_in6* saddr=( struct sockaddr_in6*)local_addr;
+    struct sockaddr_in6* locaddr=(struct sockaddr_in6*)addrinf->ai_addr;
+
+    saddr->sin6_family=addrinf->ai_family;
+    saddr->sin6_port=htons((unsigned short)local_port);
+    memcpy(&saddr->sin6_addr,&locaddr->sin6_addr,sizeof(struct in6_addr));
+  }
+
+  if((getaddrinfo(rem_ip, NULL, NULL, &addrinf))!=0){
+    log("getaddrinfo(rem_ip, NULL, NULL, &addrinf))!=0");
+    return -1;
+  }
+  if(addrinf->ai_family==AF_INET){
+    struct sockaddr_in* addr=( struct sockaddr_in*)rem_addr;
+    struct sockaddr_in* remaddr=(struct sockaddr_in*)addrinf->ai_addr;
+
+    addr->sin_family=addrinf->ai_family;
+    addr->sin_port=htons((unsigned short)rem_port);
+    memcpy(&addr->sin_addr,&remaddr->sin_addr,sizeof(struct in_addr));
+  } else {
+    struct sockaddr_in6* addr=( struct sockaddr_in6*)rem_addr;
+    struct sockaddr_in6* remaddr=(struct sockaddr_in6*)addrinf->ai_addr;
+
+    addr->sin6_family=addrinf->ai_family;
+    addr->sin6_port=htons((unsigned short)rem_port);
+    memcpy(&addr->sin6_addr,&remaddr->sin6_addr,sizeof(struct in6_addr));
+  }
+
+  freeaddrinfo(addrinf);
+
+  if(rem_addr->ss_family!=local_addr->ss_family){
+    log("fill_addr_struct rem_addr->ss_family!=local_addr->ss_family<0");
+    return -1;
+  }
+
+  return 0;
+}
+
+int open_udp_port(struct sockaddr_storage *local_addr){
+  int fd=socket(local_addr->ss_family, SOCK_DGRAM, 0);
+  if (fd < 0) {
+  log("open_udp port fd < 0");
+    return -1;
+  }
+  int flags;
+
+  flags = fcntl (fd, F_GETFL, 0);
+  if (flags == -1) {
+    perror ("fcntl");
+    log("open_udp port flags = -1");
+    close(fd);
+    return -1;
+  }
+
+  flags |= O_NONBLOCK;
+  if (fcntl (fd, F_SETFL, flags) < 0) {
+    perror ("fcntl");
+    close(fd);
+    log("open_udp port fcntl<0");
+    return -1;
+  }
+
+  if (bind(fd, (struct sockaddr *) local_addr, sizeof(struct sockaddr_storage)) < 0) {
+    perror ("bind");
+    close(fd);
+    log("open_udp port bind<0");
+    return -1;
+  }
+  log("open_udp return fd");
+  return fd;
+}
+
+int process_msg(msg_buffer* buffer, int fd){
+
+  inc_buff_size(buffer,4);
+
+  int rd=read(fd, buffer->msg+buffer->pos, buffer->size - buffer->pos);
+
+  if(rd<=0){
+  log("Process msg rd < 0");
+    return -1;
+  }
+  buffer->pos+=rd;
+  int curr_pos=buffer->pos;
+
+  while(curr_pos>=4){
+    buffer->pos=0;
+    int msg_len;
+    if(get_int(buffer,&msg_len)<0) {
+      log("Process msg get_int < 0");
+      return -1;
+    }  // read the msg length
+    log("MSG len %d",msg_len);
+    if(msg_len>curr_pos){  // we need more data
+      log("Process msg_len>curr_pos");
+      buffer->pos=curr_pos;
+      inc_buff_size(buffer,msg_len-curr_pos); // reserve enough space in the buffer to receive data
+      return 0;
+    }
+    if(msg_len<8) {
+      log("Process msg msg_len < 0");
+      return -1;
+    } // No msg type????
+    int msg_type;
+    if(get_int(buffer,&msg_type)<0) {
+      log("Process msg get_int2 < 0");
+      return -1;
+    } // read the msg type
+    log("MSG type %d",msg_type);
+    switch(msg_type){
+      case GTP_CTRL_MSG_GET_TEID:{
+        log("GTP_CTRL_MSG_GET_TEID received");
+        str_holder local_addr;
+        local_addr.str_size=-1;
+        local_addr.str_begin=NULL;
+        str_holder remote_addr;
+        remote_addr.str_size=-1;
+        remote_addr.str_begin=NULL;
+        int local_port=-1;
+        int remote_port=-1;
+        int protocol_id=-1;
+
+        while(msg_len>buffer->pos){
+          int ie_type;
+          get_int(buffer,&ie_type);
+          switch(ie_type){
+            case GTP_CTRL_IE_LOCAL_IP:  // oct
+              get_str(buffer,&local_addr);
+              log("GTP_CTRL_MSG_GET_TEID local_addr");
+	      log_str_holder(&local_addr);
+              break;
+
+            case GTP_CTRL_IE_REMOTE_IP:  // oct
+              get_str(buffer,&remote_addr);
+              log("GTP_CTRL_MSG_GET_TEID remote_addr");
+	      log_str_holder(&remote_addr);
+              break;
+
+            case GTP_CTRL_IE_LOCAL_PORT:  // int
+              get_int(buffer,&local_port);
+              log("GTP_CTRL_MSG_GET_TEID local_port %i", local_port);
+              break;
+
+            case GTP_CTRL_IE_REMOTE_PORT:  // int
+              get_int(buffer,&remote_port);
+              log("GTP_CTRL_MSG_GET_TEID remote_port %i", remote_port);
+              break;
+
+            case GTP_CTRL_IE_PROTO:  // int
+              get_int(buffer,&protocol_id);
+              log("protocol_id %i", protocol_id);
+              break;
+
+            default:
+              break;
+          }
+        }
+
+        str_int_map::const_iterator it;
+        pthread_rwlock_rdlock(&ip_teid_lock);
+        it=ip_idx_map.find(local_addr);
+        int match_level=-1;
+        int match_idx=-1;
+        int idx=-1;
+        if(it!=ip_idx_map.end()){
+          idx=it->second;
+          // find the matching teid
+
+          for(int i=0;i<ip_teid_db[idx].teid_num;i++){
+            const filter_t* ft=&ip_teid_db[idx].teid_list[i].filter;
+            int match=0;
+            if(ft->remote_ip.str_size!=-1){
+              log("REMOTE IP:");
+	      log_str_holder(&ft->remote_ip);
+              if(str_eq(ft->remote_ip,remote_addr)==0){
+                match++;
+              } else {
+                continue;
+              }
+            }
+            log("PROTO: %i", ft->proto);
+            log("PROTOCOL_ID: %i", protocol_id);
+            if(ft->proto!=0){
+              if(ft->proto==protocol_id){
+                match++;
+                // we need proto match to handle ports
+                log("REMOTE_PORT: %i", ft->remote_port);
+                if(ft->remote_port!=-1){
+                  if(ft->remote_port==remote_port){
+                   match++;
+                  } else {
+                    continue;
+                  }
+                }
+                log("LOCAL_PORT: %i", ft->local_port);
+                if(ft->local_port!=-1){
+                  if(ft->local_port==local_port){
+                    match++;
+                  } else {
+                    continue;
+                  }
+                }
+
+              } else {
+                continue;
+              }
+            }
+
+            if(match>match_level){
+              match_level=match;
+              match_idx=i;
+            }
+
+          }
+        }
+
+        msg_buffer msg_buff;
+        init_msg_buffer(&msg_buff);
+        int out_len=put_int(&msg_buff,22);
+        out_len+=put_int(&msg_buff,GTP_CTRL_MSG_GET_TEID_DATA);
+        out_len+=put_int(&msg_buff,GTP_CTRL_IE_RES_CODE);
+
+        if(match_idx!=-1){
+          log("found the tunnel data");
+          // found the tunnel data
+          int loc_gtp_tun_fd=ip_teid_db[idx].teid_list[match_idx].local_fd;
+
+          //find the address of the local GTP endpoint
+          int ep_idx=-1;
+          for(ep_idx=0;ep_idx<local_ep_length;ep_idx++){
+            if(local_ep_db[ep_idx].fd==loc_gtp_tun_fd) break;
+          }
+
+          str_holder str;
+
+          out_len+=put_int(&msg_buff,0);
+
+          out_len+=put_int(&msg_buff,GTP_CTRL_IE_OUT_TEID);
+          out_len+=put_str(&msg_buff,&ip_teid_db[idx].teid_list[match_idx].teid_out);
+
+
+          const struct sockaddr_storage* ad=&ip_teid_db[idx].teid_list[match_idx].rem_addr;
+          if(ad->ss_family==AF_INET){
+            const struct sockaddr_in *sin=(const struct sockaddr_in *)ad;
+            out_len+=put_int(&msg_buff,GTP_CTRL_IE_REMOTE_IP);
+            str.str_begin=(const unsigned char*)&(sin->sin_addr);
+            str.str_size=4;
+            out_len+=put_str(&msg_buff,&str);
+            out_len+=put_int(&msg_buff,GTP_CTRL_IE_REMOTE_PORT);
+            out_len+=put_int(&msg_buff,ntohs(sin->sin_port));
+          } else {
+            const struct sockaddr_in6 *sin=(const struct sockaddr_in6 *)ad;
+            out_len+=put_int(&msg_buff,GTP_CTRL_IE_REMOTE_IP);
+            str.str_begin=(const unsigned char*)&(sin->sin6_addr);
+            str.str_size=16;
+            out_len+=put_str(&msg_buff,&str);
+            out_len+=put_int(&msg_buff,GTP_CTRL_IE_REMOTE_PORT);
+            out_len+=put_int(&msg_buff,ntohs(sin->sin6_port));
+          }
+          ad=(const struct sockaddr_storage*)local_ep_db[ep_idx].key.str_begin;
+          if(ad->ss_family==AF_INET){
+            const struct sockaddr_in *sin=(const struct sockaddr_in *)ad;
+            out_len+=put_int(&msg_buff,GTP_CTRL_IE_LOCAL_IP);
+            str.str_begin=(const unsigned char*)&(sin->sin_addr);
+            str.str_size=4;
+            out_len+=put_str(&msg_buff,&str);
+            out_len+=put_int(&msg_buff,GTP_CTRL_IE_LOCAL_PORT);
+            out_len+=put_int(&msg_buff,ntohs(sin->sin_port));
+          } else {
+            const struct sockaddr_in6 *sin=(const struct sockaddr_in6 *)ad;
+            out_len+=put_int(&msg_buff,GTP_CTRL_IE_LOCAL_IP);
+            str.str_begin=(const unsigned char*)&(sin->sin6_addr);
+            str.str_size=16;
+            out_len+=put_str(&msg_buff,&str);
+            out_len+=put_int(&msg_buff,GTP_CTRL_IE_LOCAL_PORT);
+            out_len+=put_int(&msg_buff,ntohs(sin->sin6_port));
+          }
+
+          pthread_rwlock_unlock(&ip_teid_lock); // the lock is not needed any more
+
+        } else {
+          log("tunnel data not found");
+          pthread_rwlock_unlock(&ip_teid_lock); // the lock is not needed any more
+          out_len+=put_int(&msg_buff,0);
+        }
+        msg_buff.pos=0;
+        put_int(&msg_buff,out_len);
+        log("output length = %i", out_len);
+        log("sending response");
+#ifdef DEBUG
+	for(int i=0;i<out_len;i++){
+	  printf("%02X", msg_buff.msg[i]);
+	}printf("\n");
+#endif
+        int s = send(fd,msg_buff.msg,out_len,0);
+        log("response sent %i", s);
+        free_msg_buffer(&msg_buff);
+
+        break;
+      }
+
+      case GTP_CTRL_MSG_INIT:{
+        log("GTP_CTRL_MSG_INIT msg");
+        char *local_addr=NULL;
+        char *remote_addr=NULL;
+        int local_port=-1;
+        int remote_port=-1;
+        while(msg_len>buffer->pos){
+          int ie_type;
+          str_holder str;
+          get_int(buffer,&ie_type);
+          switch(ie_type){
+            case GTP_CTRL_IE_LOCAL_IP:  // text
+              get_str(buffer,&str);
+              local_addr=strndup((const char*)str.str_begin,str.str_size);
+              log("GTP_CTRL_MSG_INIT local_addr %s",local_addr);
+              break;
+
+            case GTP_CTRL_IE_REMOTE_IP:  // text
+              get_str(buffer,&str);
+              remote_addr=strndup((const char*)str.str_begin,str.str_size);
+              log("remote_addr %s",remote_addr);
+              break;
+
+            case GTP_CTRL_IE_LOCAL_PORT:  // int
+              get_int(buffer,&local_port);
+              log("local_port %d",local_port);
+              break;
+
+            case GTP_CTRL_IE_REMOTE_PORT:  // int
+              get_int(buffer,&remote_port);
+              log("remote_port %d",remote_port);
+              break;
+
+            case GTP_CTRL_IE_PARAM_SET_ADDR_MODE:  // int
+              get_int(buffer,&address_set_mode);
+              break;
+            default:
+              break;
+          }
+        }
+        if( // Something wrong with the parameters
+          address_set_mode<0 || address_set_mode>2
+         ){
+            log("Something is missing");
+            Free(local_addr);
+            Free(remote_addr);
+          return -1;
+        }
+
+
+        if(!threads_started){
+          // init the local endpoint db
+          // add the default entry
+          local_ep_length=1;
+          local_ep_num=1;
+          local_ep_db = (local_ep_db_t *)Malloc(sizeof(local_ep_db_t));
+          local_ep_db[0].fd=-1;
+          local_ep_db[0].usage_num=0;
+          local_ep_db[0].key.str_begin=(const unsigned char*)Malloc(sizeof(struct sockaddr_storage));
+          local_ep_db[0].key.str_size=sizeof(struct sockaddr_storage);
+
+          // init the local endpoint db
+          // add the default entry
+
+          if(local_addr){
+            tun_handler_num=1;
+            log("Process msg local_addr");
+            //udp_to_tun
+            if(fill_addr_struct(local_addr,local_port,(struct sockaddr_storage*)local_ep_db[0].key.str_begin,remote_addr,remote_port,&default_rem_addr)<0){
+              Free(local_addr);
+              Free(remote_addr);
+              log("Process msg fill_addr_struct<0");
+              return -1;
+            }
+
+            Free(local_addr);
+            Free(remote_addr);
+            int gtp_fd;
+            if((gtp_fd=open_udp_port((struct sockaddr_storage*)local_ep_db[0].key.str_begin))<0){
+            log("Process msg open_udp_port<0");
+              return -1;
+            }
+            pthread_t gtp_handler;
+            if ( pthread_create(&gtp_handler, NULL,udp_to_tun , &gtp_fd) )
+            {
+               printf("Can't start thread (gtp_handler_0)");
+               exit(1);
+            }
+            ep_idx_map[local_ep_db[0].key]=0;
+            local_ep_db[0].usage_num=1;
+            local_ep_db[0].fd=gtp_fd;
+
+            // add fd to the epoll list
+            struct epoll_event event;
+            event.data.fd = gtp_fd; /* return the fd to us later */
+            event.events = EPOLLIN | EPOLLET ;
+
+            if(epoll_ctl (epfd, EPOLL_CTL_ADD, gtp_fd, &event)<0){
+              perror("epoll_ctl");
+            }
+
+            log("Creating tun_handler thread");
+            //udp_to_tun
+            if ( pthread_create(&tun_handler, NULL,tun_to_udp , NULL) )
+            {
+               printf("Can't start thread (tun_handler_0)");
+               exit(1);
+            }
+          }
+          log("Threads started");
+          threads_started=true;
+        }
+
+        // send back the ACK
+        msg_buffer msg_buff;
+        init_msg_buffer(&msg_buff);
+
+        put_int(&msg_buff,26);
+        put_int(&msg_buff,GTP_CTRL_MSG_INIT_ACK);
+        put_int(&msg_buff,GTP_CTRL_IE_RES_CODE);
+        put_int(&msg_buff,0);
+        put_int(&msg_buff,GTP_CTRL_IE_RES_TXT);
+
+        str_holder str;
+        str.str_begin=(const unsigned char*)"OK";
+        str.str_size=2;
+        put_str(&msg_buff,&str);
+
+        /*int r =*/ send(fd,msg_buff.msg,msg_buff.pos,0);
+
+        free_msg_buffer(&msg_buff);
+        break;
+      }
+
+      case GTP_CTRL_MSG_CREATE:{
+        str_holder teid_in;
+        teid_in.str_size=-1;
+        teid_in.str_begin=NULL;
+
+        str_holder teid_out;
+        teid_out.str_size=-1;
+        teid_out.str_begin=NULL;
+
+        str_holder ip;
+        ip.str_size=-1;
+        ip.str_begin=NULL;
+
+        int ip_type=-1;
+
+        int filter_rem_port=-1;
+        int filter_loc_port=-1;
+        int filter_proto=0;
+        str_holder filter_rem_ip;
+        filter_rem_ip.str_size=-1;
+        filter_rem_ip.str_begin=NULL;
+
+        char *local_addr=NULL;
+        char *remote_addr=NULL;
+        int local_port=-1;
+        int remote_port=-1;
+
+        while(msg_len>buffer->pos){
+          int ie_type;
+          //int ie_val;
+          str_holder str;
+          get_int(buffer,&ie_type);
+          switch(ie_type){
+            case GTP_CTRL_IE_OUT_TEID:  // oct
+              get_str(buffer,&str);
+              copy_str_holder(&teid_out,&str);
+	      log("GTP_CTRL_MSG_CREATE with %d long out TEID:",teid_out.str_size);
+	      log_str_holder(&teid_out);
+              break;
+            case GTP_CTRL_IE_IN_TEID:  // oct
+              get_str(buffer,&teid_in);
+              //copy_str_holder(&teid_in,&str);
+              break;
+
+            case GTP_CTRL_IE_ADDR:  // oct
+              get_str(buffer,&ip);
+              log("GTP_CTRL_MSG_CREATE ip");
+	      log_str_holder(&ip);
+              break;
+            case GTP_CTRL_IE_ADDR_TYPE:  // int
+              get_int(buffer,&ip_type);
+              break;
+
+
+            case GTP_CTRL_IE_LOCAL_IP:  // text
+              get_str(buffer,&str); // skip
+              local_addr=strndup((const char*)str.str_begin,str.str_size);
+              log("GTP_CTRL_MSG_CREATE local_addr %s",local_addr);
+              break;
+            case GTP_CTRL_IE_REMOTE_IP:  // text
+              get_str(buffer,&str); // skip
+              remote_addr=strndup((const char*)str.str_begin,str.str_size);
+              log("GTP_CTRL_MSG_CREATE remote_addr %s",remote_addr);
+              break;
+            case GTP_CTRL_IE_LOCAL_PORT:  // int
+              get_int(buffer,&local_port);
+              log("GTP_CTRL_MSG_CREATE local_port %d",local_port);
+              break;
+            case GTP_CTRL_IE_REMOTE_PORT:  // int
+              get_int(buffer,&remote_port);
+              log("GTP_CTRL_MSG_CREATE remote_port %d",remote_port);
+              break;
+
+
+            case GTP_CTRL_IE_FILTER_REMOTE_IP:  // oct
+              get_str(buffer,&str);
+              copy_str_holder(&filter_rem_ip,&str);
+              log("GTP_CTRL_MSG_CREATE filter remote IP: %s", str);
+              break;
+            case GTP_CTRL_IE_FILTER_LOCAL_PORT:  // int
+              get_int(buffer,&filter_loc_port);
+              log("TGTP_CTRL_MSG_CREATE filter local port: %i", filter_loc_port);
+              break;
+            case GTP_CTRL_IE_FILTER_REMOTE_PORT:  // int
+              get_int(buffer,&filter_rem_port);
+              log("GTP_CTRL_MSG_CREATE filter remote port: %i", filter_rem_port);
+              break;
+            case GTP_CTRL_IE_FILTER_PROTO:  // int
+              get_int(buffer,&filter_proto);
+              log("GTP_CTRL_MSG_CREATE filter proto: %i", filter_proto);
+              break;
+            default:
+              break;
+          }
+        }
+
+        if(teid_out.str_size == -1){
+          log("No out teid received");
+          Free(local_addr);
+          Free(remote_addr);
+          return -1;
+        }
+        if(ip.str_size == -1){
+          log("No ip received");
+          free_str_holder(&teid_out);
+          Free(local_addr);
+          Free(remote_addr);
+          return -1;
+        }
+        if(ip_type==-1){
+          log("No ip type received");
+          free_str_holder(&teid_out);
+          Free(local_addr);
+          Free(remote_addr);
+          return -1;
+        }
+
+
+        int loc_fd=-1;
+        struct sockaddr_storage *rem_addr_ptr=NULL;
+        struct sockaddr_storage rem_addr;
+        if(local_addr){
+          struct sockaddr_storage loc_addr;
+          if(fill_addr_struct(local_addr,local_port,&loc_addr,remote_addr,remote_port,&rem_addr)<0){
+            Free(local_addr);
+            Free(remote_addr);
+            free_str_holder(&teid_out);
+            send_error_ind(fd,"Can't set up tunnel addresses");
+            log("Process msg cant set up tunnel addresses");
+            return 0;
+          }
+          Free(local_addr);
+          Free(remote_addr);
+          rem_addr_ptr=&rem_addr;
+
+          str_holder ep_key;
+          ep_key.str_begin=(const unsigned char*)&loc_addr;
+          ep_key.str_size=sizeof(struct sockaddr_storage);
+
+
+          if(ep_idx_map.find(ep_key)==ep_idx_map.end()){ // local endpoint is not in the db
+            int new_gtp_fd=open_udp_port(&loc_addr);
+            if(new_gtp_fd==-1){
+               free_str_holder(&teid_out);
+               send_error_ind(fd,"Can't set up tunnel addresses, Check IP.");
+               log("Process msg cant set up tunnel addresses, check ip");
+               return 0;
+            }
+
+            if(local_ep_length==local_ep_num){ //we need to extend the list
+//                pthread_rwlock_wrlock(ep_idx_lock);
+              local_ep_length++;
+              local_ep_db = (local_ep_db_t *)Realloc(local_ep_db,local_ep_length*sizeof(local_ep_db_t));
+              local_ep_db[local_ep_num].fd=-1;
+              local_ep_db[local_ep_num].usage_num=0;
+              local_ep_db[local_ep_num].key.str_begin=(const unsigned char*)Malloc(sizeof(struct sockaddr_storage));
+              local_ep_db[local_ep_num].key.str_size=sizeof(struct sockaddr_storage);
+//                pthread_rwlock_unlock(ep_idx_lock);
+            }
+
+            //tun_to_udp
+            int i;
+            for(i=1;i<local_ep_length;i++){
+              if(local_ep_db[i].fd==-1) break;
+            }
+            local_ep_db[i].fd=new_gtp_fd;
+            local_ep_db[i].usage_num++;
+            memcpy((void *)local_ep_db[i].key.str_begin,&loc_addr,sizeof(struct sockaddr_storage));
+            ep_idx_map[local_ep_db[i].key]=i;
+            local_ep_num++;
+            loc_fd=local_ep_db[i].fd;
+
+            // add fd to the epoll list
+            struct epoll_event event;
+            event.data.fd = new_gtp_fd; /* return the fd to us later */
+            event.events = EPOLLIN | EPOLLET ;
+
+            if(epoll_ctl (epfd, EPOLL_CTL_ADD, new_gtp_fd, &event)<0){
+              perror("epoll_ctl");
+            }
+
+
+            if(local_ep_num>=(tun_handler_num*gtp_per_thread)){ // create threads if needed
+              pthread_t gtp_handler;
+
+              if ( pthread_create(&gtp_handler, NULL,udp_to_tun , &local_ep_db[i].fd) )
+              {
+                 printf("Can't start thread (gtp_handler_%i)", local_ep_num-1);
+                 exit(1);
+              }
+
+              //udp_to_tun
+              tun_handler_num++;
+              pthread_t tun_handler_local;
+              log("Creating tun_handler thread");
+              if ( pthread_create(&tun_handler_local, NULL,tun_to_udp , NULL) )
+              {
+                 printf("Can't start thread (tun_handler_%i)", tun_handler_num-1);
+                 exit(1);
+              }
+            }
+          } else {
+            int idx=ep_idx_map[ep_key];
+            loc_fd=local_ep_db[idx].fd;
+            local_ep_db[idx].usage_num++;
+          }
+
+        } else {
+          loc_fd=local_ep_db[0].fd;
+          if(loc_fd==-1){
+            free_str_holder(&teid_out);
+            send_error_ind(fd,"No tunnel addresses");
+            log("Process msg no tunnel addresses");
+            return 0;
+          }
+          local_ep_db[0].usage_num++;
+          rem_addr_ptr=&default_rem_addr;
+        }
+
+        if(ip_type==0 || ip.str_size==16){  // IPv4 or full IPv6 address received
+
+          if(address_set_mode==2){// assign the IP to the interface
+            str_int_map::iterator it=ip_idx_map.find(ip);
+            if(it==ip_idx_map.end()) {
+              set_addr(&ip);
+            }
+          }
+
+          add_teid_to_db(&ip,&teid_out,&filter_rem_ip,filter_loc_port,filter_rem_port,filter_proto,loc_fd,rem_addr_ptr);
+
+
+//            if(address_set_mode==2){// assign the IP to the interface
+//              set_addr(&ip);
+//            }
+
+          // send back the ACK
+          msg_buffer msg_buff;
+          str_holder str;
+          init_msg_buffer(&msg_buff);
+          int out_len=put_int(&msg_buff,22);
+          out_len+=put_int(&msg_buff,GTP_CTRL_MSG_CREATE_ACK);
+          out_len+=put_int(&msg_buff,GTP_CTRL_IE_OUT_TEID);
+          out_len+=put_str(&msg_buff,&teid_out);
+          out_len+=put_int(&msg_buff,GTP_CTRL_IE_IN_TEID);
+          out_len+=put_str(&msg_buff,&teid_in);
+
+          out_len+=put_int(&msg_buff,GTP_CTRL_IE_RES_CODE);
+          out_len+=put_int(&msg_buff,0);
+          out_len+=put_int(&msg_buff,GTP_CTRL_IE_RES_TXT);
+          str.str_begin=(const unsigned char*)"OK";
+          str.str_size=2;
+          out_len+=put_str(&msg_buff,&str);
+
+          out_len+=put_int(&msg_buff,GTP_CTRL_IE_ADDR);
+          out_len+=put_str(&msg_buff,&ip);
+
+          msg_buff.pos=0;
+          put_int(&msg_buff,out_len);
+          log("%X %X %X %X",msg_buff.msg[0],msg_buff.msg[1],msg_buff.msg[2],msg_buff.msg[3]);
+          int r=
+          send(fd,msg_buff.msg,out_len,0);
+          free_msg_buffer(&msg_buff);
+          log("Answer sent %d %d",out_len,r);
+        } else {  // IPv6 prefix request is needed
+          // We need a local copy of the incoming teid
+          str_holder str=teid_in;
+          copy_str_holder(&teid_in,&str);
+
+          // Put the data into the db
+          if(ip_req_db_size==ip_req_num){
+            // increase the db
+            pthread_rwlock_wrlock(&teid_idx_lock);
+            ip_req_db_size+=10;
+            ip_req_db=(ip_req_db_t*)Realloc(ip_req_db,ip_req_db_size*sizeof(ip_req_db_t));
+            pthread_rwlock_unlock(&teid_idx_lock); // The new slots won't be accessed from other thread
+
+            for(int i=ip_req_num;i<ip_req_db_size;i++){
+              ip_req_db[i].teid_in.str_size=-1;
+            }
+          }
+
+          int idx=0;
+          for(;idx<ip_req_db_size;idx++){  // search for free slots, no need to lock, only this thread write it
+            if(ip_req_db[idx].teid_in.str_size==-1) { break; }
+          }
+          ip_req_db[idx].teid_in=teid_in;
+          ip_req_db[idx].teid_out=teid_out;
+          ip_req_db[idx].fd=fd;
+          ip_req_db[idx].ip.str_begin=(unsigned char*)Malloc(16*sizeof(unsigned char));
+          memcpy((void*)(ip_req_db[idx].ip.str_begin+8),ip.str_begin,8);
+
+          ip_req_db[idx].ip.str_size=16;
+
+          ip_req_db[idx].local_ep_fd=loc_fd;
+          memcpy(&ip_req_db[idx].rem_addr,rem_addr_ptr,sizeof(struct sockaddr_storage));
+          ip_req_num++; // no problem if the thread reads the old value
+
+          pthread_rwlock_wrlock(&teid_idx_lock);
+          teidin_idx_map[teid_in]=idx;
+          pthread_rwlock_unlock(&teid_idx_lock);
+
+          // send the solicit message
+          send_solicit(&teid_out,loc_fd,rem_addr_ptr);
+        }
+        break;
+      }
+
+      case GTP_CTRL_MSG_DESTROY:{
+        str_holder teid_in;
+        teid_in.str_size=-1;
+        teid_in.str_begin=NULL;
+
+        str_holder teid_out;
+        teid_out.str_size=-1;
+        teid_out.str_begin=NULL;
+
+        str_holder ip;
+        ip.str_size=-1;
+        ip.str_begin=NULL;
+
+        while(msg_len>buffer->pos){
+          int ie_type;
+          get_int(buffer,&ie_type);
+          switch(ie_type){
+            case GTP_CTRL_IE_OUT_TEID:  // oct
+              get_str(buffer,&teid_out);
+              break;
+            case GTP_CTRL_IE_IN_TEID:  // oct
+              get_str(buffer,&teid_in);
+              break;
+            case GTP_CTRL_IE_ADDR:  // oct
+              get_str(buffer,&ip);
+              break;
+            default:
+              break;
+          }
+        }
+        if(teid_in.str_size == -1){
+          log("No in teid received");
+          return -1;
+        }
+        if(teid_out.str_size == -1){
+          log("No out teid received");
+          return -1;
+        }
+
+        remove_teid_from_db(&ip,&teid_out);
+        break;
+      }
+
+      case GTP_CTRL_MSG_BYE:{
+        msg_buffer msg_buff;
+        init_msg_buffer(&msg_buff);
+        close_local_ep(0,1);  // try to close the default endpoint
+        put_int(&msg_buff,8);
+        put_int(&msg_buff,GTP_CTRL_MSG_BYE_ACK);
+        send(fd,msg_buff.msg,msg_buff.pos,0);
+        free_msg_buffer(&msg_buff);
+        return -1; // just close the fd after sending bye ack
+
+        break;
+      }
+
+      default:
+        // Unknown message, ignore it
+        break;
+    }
+
+    if(msg_len!=curr_pos){  // there is data in the buffer, move it to the beginning
+      memmove(buffer->msg,buffer->msg+msg_len,curr_pos-msg_len);
+    }
+    buffer->pos=curr_pos-msg_len;
+    curr_pos=buffer->pos;
+  }
+
+ //log("Process msg return 0");
+ return 0;
+}
+
+void send_error_ind(int fd,const char *fmt, ...){
+}
+
+
+void send_solicit(const str_holder* teid, int fd, struct sockaddr_storage *clientaddr){
+  unsigned char  solicit_msg[]={
+  //  The GTP header struct:
+  //  octet 0:  Version, PT, reserved, flags: fixed values 0x30
+  //  octet 1:  Message type: fixed value: 0xFF, GTP-U
+  //  octet 2:  Payload length
+  //  octet 3:  Payload length
+  //  octet 4:  TEID
+  //  octet 5:  TEID
+  //  octet 6:  TEID
+  //  octet 7:  TEID
+  //  octet 8-n:  The payload
+  0x03,
+  0xFF,
+  0x00,
+  0x30,  // length 48
+  0x00,0x00,0x00,0x00, // TEID placeholder
+  0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff,   // IPv6 header
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // No ip
+  0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // Every router
+  0x85, 0x00, 0x7b, 0xb8, 0x00, 0x00, 0x00, 0x00};  // ICMPv6 Router Solicit
+
+  solicit_msg[4]=teid->str_begin[0]; // set the TEID
+  solicit_msg[5]=teid->str_begin[1];
+  solicit_msg[6]=teid->str_begin[2];
+  solicit_msg[7]=teid->str_begin[3];
+
+  sendto(fd, solicit_msg, sizeof(solicit_msg) , 0, (const struct sockaddr *)clientaddr, sizeof(*clientaddr) );
+
+}
+
+// adds the address to the TUN if
+int set_addr(const str_holder* ip){
+  // the buffer holds the ip command:
+  // ip addr add <address> dev <dev>
+  // The max size of <address>: INET6_ADDRSTRLEN
+  // the max size of <dev>: IFNAMSIZ
+  // so the required buff size is: 18 + INET6_ADDRSTRLEN + IFNAMSIZ
+  char buffer[18 + INET6_ADDRSTRLEN + IFNAMSIZ];
+  char ip_name_buff[INET6_ADDRSTRLEN];
+
+  // print the address into the buffer
+  if(inet_ntop(ip->str_size==4?AF_INET:AF_INET6,ip->str_begin,ip_name_buff,INET6_ADDRSTRLEN)==NULL){
+    //log("Address conversion failed: %d %s",errno,strerror(errno));
+    return -1;
+  }
+
+  //log("IP addr to set: %s", ip_name_buff);
+
+  // construct the ip command
+  sprintf(buffer,"ip addr add %s dev %s",ip_name_buff,tun_name);
+
+  log("command to execute: %s",buffer);
+
+  system(buffer);
+  return 0;
+}
+
+int del_addr(const str_holder* ip){
+  // the buffer holds the ip command:
+  // ip addr add <address> dev <dev>
+  // The max size of <address>: INET6_ADDRSTRLEN
+  // the max size of <dev>: IFNAMSIZ
+  // so the required buff size is: 18 + INET6_ADDRSTRLEN + IFNAMSIZ
+  char buffer[22 + INET6_ADDRSTRLEN + IFNAMSIZ];
+  char ip_name_buff[INET6_ADDRSTRLEN];
+
+  // print the address into the buffer
+  if(inet_ntop(ip->str_size==4?AF_INET:AF_INET6,ip->str_begin,ip_name_buff,INET6_ADDRSTRLEN)==NULL){
+    //log("Address conversion failed: %d %s",errno,strerror(errno));
+    return -1;
+  }
+
+  //log("IP addr to set: %s", ip_name_buff);
+
+  // construct the ip command
+  sprintf(buffer,"ip addr del %s dev %s",ip_name_buff,tun_name);
+
+  log("command to execute: %s",buffer);
+
+  system(buffer);
+  return 0;
+}
+
+void tun_set( ){
+  struct ifreq netifr;
+  int ctl_fd;
+  memset(&netifr, 0, sizeof(netifr));
+
+  if ((ctl_fd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0)
+  {
+    strncpy(netifr.ifr_name, tun_name, IFNAMSIZ);
+    // set the tx queue length
+    netifr.ifr_qlen = 65535;
+    if (ioctl (ctl_fd, SIOCSIFTXQLEN, (void *) &netifr) >= 0){
+      log("TUN/TAP TX queue length set to %d",netifr.ifr_qlen );
+    }
+    else{
+      printf("Note: Cannot set tx queue length on %s %d %s\r\n", netifr.ifr_name,errno,strerror(errno));
+    }
+    // bring up the if
+    netifr.ifr_flags = IFF_UP;
+
+    if (ioctl (ctl_fd,SIOCSIFFLAGS , (void *) &netifr) >= 0){
+      log("TUN if is up: %s", tun_name);
+    }
+    else{
+      printf("Note: Cannot up the if %s %d %s\r\n", netifr.ifr_name,errno,strerror(errno));
+    }
+
+    close (ctl_fd);
+  }
+  else
+  {
+    printf("Note: Cannot open control socket on %s", netifr.ifr_name);
+  }
+}
+
+int set_up_tun(int flags){
+  struct ifreq ifr;
+  int fd, err;
+  const char *clonedev = "/dev/net/tun";
+
+  if( (fd = open(clonedev, O_RDWR)) < 0 ) { // open the tun clone device
+    return fd;
+  }
+
+  memset(&ifr, 0, sizeof(ifr)); // clean the ifreq struct
+
+  ifr.ifr_flags = IFF_TUN | IFF_NO_PI | flags ; // TUN interface, no proto info is needed
+
+  if(tun_name) {
+     /* if a TUN interface name was specified, put it in the structure; otherwise,
+        the kernel will try to allocate the "next" device of the specified type */
+    strncpy(ifr.ifr_name, tun_name, IFNAMSIZ);
+  }
+
+   /* try to create the device */
+  if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
+    close(fd);
+    return err;
+  }
+
+  if(!tun_name) {  // store the TUN dev name if not specified
+    tun_name=strdup(ifr.ifr_name);
+  }
+
+  tun_set( );
+  return fd;
+}
+
+// Creates a listening unix socket
+// Because we target Linux only, use the abstarct socket feature
+int start_ctrl_listen(){
+  struct sockaddr_un localAddr;
+
+  localAddr.sun_family = AF_UNIX;
+  localAddr.sun_path[0]='\0';  // use abstract socket
+
+  if(tun_name){
+    snprintf(localAddr.sun_path+1,106,"gtp_tunel_daemon_%s",tun_name);
+    log("Listen on: gtp_tunel_daemon_%s",tun_name);
+  } else {
+    snprintf(localAddr.sun_path+1,106,"gtp_tunel_daemon");
+    log("Listen on: gtp_tunel_daemon");
+  }
+
+  if((daemon_fd = socket(PF_UNIX,SOCK_STREAM,0))<0) {
+    int en=errno;
+    printf("Socket creation error %d %s",en,strerror(en));
+    return -1;
+  }
+
+  size_t addrLength;
+  addrLength = sizeof(localAddr.sun_family) +1+ strlen(localAddr.sun_path+1);
+
+  if(bind(daemon_fd, (struct sockaddr *) &localAddr, addrLength )<0) {
+    int en=errno;
+    printf("bind error %d %s",en,strerror(en));
+    return -1;
+  }
+
+  if(listen(daemon_fd, 5)){
+    int en=errno;
+    printf("listen error %d %s",en,strerror(en));
+    return -1;
+  }
+
+  return daemon_fd;
+}
+
+void *tun_to_udp(void *){
+//  The GTP header struct:
+//  octet 0:  Version, PT, reserved, flags: fixed values 0x30
+//  octet 1:  Message type: fixed value: 0xFF, GTP-U
+//  octet 2:  Payload length
+//  octet 3:  Payload length
+//  octet 4:  TEID
+//  octet 5:  TEID
+//  octet 6:  TEID
+//  octet 7:  TEID
+//  octet 8-n:  The payload
+//
+
+
+  unsigned char base_buffer[MAX_UDP_PACKET+8];
+  unsigned char *buffer=base_buffer+8; // points to the data part of the GTP message
+  int nread;
+  int tun_fd_loc=tun_fd;
+
+  str_holder ip;
+
+  // init the fixed part of the GTP message
+  base_buffer[0]=0x30;
+  base_buffer[1]=0xFF; // message type
+  while(1){
+    nread = read(tun_fd_loc,buffer,MAX_UDP_PACKET);
+    if(nread < 0) {
+      perror("Reading from interface");
+      exit(1);
+    }
+    //log("Message received with %d bytes in tun_to_udp",nread);
+// check IP version to get the source address in the IP header. First octet:
+//    ipv6 version: 6   0110xxxx  & 0x20 = 0010 0000 => true
+//    ipv4 version: 4   0100xxxx  & 0x20 = 0000 0000 => false
+    bool ipv6=false;
+    if((buffer[0]&0x20)){
+      // IPv6 address starts at octet 8 length 16
+      ip.str_begin=buffer+8;
+      ip.str_size=16;
+      ipv6=true;
+    } else {
+      // IPv4 address starts at octet 12 length 4
+      ip.str_begin=buffer+12;
+      ip.str_size=4;
+    }
+    str_int_map::const_iterator it;
+    pthread_rwlock_rdlock(&ip_teid_lock);
+    it=ip_idx_map.find(ip);
+    if(it!=ip_idx_map.end()){
+      //log("it!=ip_idx_map.end()");
+      const unsigned char* teid;
+      int idx=it->second;
+      // find the matching teid
+      int match_level=-1;
+      int match_idx=-1;
+
+      const unsigned char* rem_addr=ipv6?buffer+24:buffer+16;
+      int proto=ipv6?buffer[6]:buffer[9];
+
+      int rem_port=-1;
+      int loc_port=-1;
+      //log("Captured proto = %i ", proto);
+      if(proto==17 || proto==6){
+        int start_offset=ipv6?40:(buffer[0]&0x0F)*4;
+        loc_port=buffer[start_offset]*256+buffer[start_offset+1];
+        rem_port=buffer[start_offset+2]*256+buffer[start_offset+3];
+      }
+      for(int i=0;i<ip_teid_db[idx].teid_num;i++){
+        const filter_t* ft=&ip_teid_db[idx].teid_list[i].filter;
+        int match=0;
+        if(ft->remote_ip.str_size!=-1){
+          //log("Captured ft->remote_ip.str_size!=-1");
+          //log("Captured ft->remote_ip = %s , rem_addr = %s ", ft->remote_ip.str_begin,rem_addr);
+          if(memcmp(ft->remote_ip.str_begin,rem_addr,ipv6?16:4)==0){
+            //log("Capture memcmp(ft->remote_ip.str_begin,rem_addr,ipv6?16:4)==0");
+            match++;
+          } else {
+            //log("Capture continue");
+            continue;
+          }
+        }
+        //log("Captured ft->proto = %i ", ft->proto);
+        if(ft->proto!=0){
+          if(ft->proto==proto){
+            //log("Capture ft->proto==proto");
+            match++;
+            // we need proto match to handle ports
+            if(ft->remote_port!=-1){
+              //log("Capture ft->remote_port!=-1");
+              //log("Capture ft->remote_port=%i , rem_port=%i", ft->remote_port,rem_port);
+              if(ft->remote_port==rem_port){
+               match++;
+              } else {
+                continue;
+              }
+            }
+            if(ft->local_port!=-1){
+              //log("Capture ft->local_port=%i , loc_port=%i", ft->local_port,loc_port);
+              if(ft->local_port==loc_port){
+                match++;
+              } else {
+                continue;
+              }
+            }
+
+          } else {
+            continue;
+          }
+        }
+
+        if(match>match_level){
+          //log("Capture match>match_leve");
+          match_level=match;
+          match_idx=i;
+        }
+
+      }
+      if(match_idx!=-1){
+        //log("Capture match_idx!=-1");
+        teid=ip_teid_db[idx].teid_list[match_idx].teid_out.str_begin;
+        base_buffer[4]=teid[0];
+        base_buffer[5]=teid[1];
+        base_buffer[6]=teid[2];
+        base_buffer[7]=teid[3];
+        pthread_rwlock_unlock(&ip_teid_lock); // the lock is not needed any more
+        // update msg_length
+        base_buffer[3]=nread & 0xFF;
+        base_buffer[2]=(nread>>8) & 0xFF;
+        if((sendto(ip_teid_db[idx].teid_list[match_idx].local_fd, base_buffer, nread+8, 0, (const struct sockaddr *)&ip_teid_db[idx].teid_list[match_idx].rem_addr, sizeof(struct sockaddr_storage) )) < 0) {
+          perror("Sending to peer");
+          exit(1);
+        }
+      } else {
+        pthread_rwlock_unlock(&ip_teid_lock); // the lock is not needed any more
+      }
+    } else {
+      // NO ip  -> teid map, just drop the packet
+      pthread_rwlock_unlock(&ip_teid_lock);
+    }
+
+
+
+  }
+
+}
+void *udp_to_tun(void* a){
+// for the magic number check the IPv6 RFCs
+// The IP packet starts at the 8 after the GTP-U header
+  int gtp_fd=*(int *)a;
+  unsigned char buffer[MAX_UDP_PACKET+8];
+
+  struct epoll_event events[MAX_EVENTS_PER_THREAD];
+
+  while(1) {
+    int num = epoll_wait (epfd, events,MAX_EVENTS_PER_THREAD , -1);
+    if(num < 0) {
+      continue;
+    }
+    for(int i=0;i<num;i++){
+      gtp_fd=events[i].data.fd;
+      int n=-1;
+      while((n=recvfrom(gtp_fd, buffer, MAX_UDP_PACKET+8, 0, (struct sockaddr *)NULL, 0))!=-1){
+        //log("GTP UDP received %d %d %s",n,errno,strerror(errno));
+        if(buffer[1]!=0xFF){  // we received something which is not a T-PDU
+          log("We received %d instead of T-PDU",buffer[1]);
+          continue;
+        }
+        //    IPv6                 ICMPv6                      RA
+        if((buffer[8] & 0x20) && ( buffer[14] == 0x3A )  && ( buffer[48] == 0x86 )  &&  ip_req_num){
+             // there are outgoing IP request, ICMPv6 message received
+          // check the teid in the database
+          str_holder teid_in;
+          teid_in.str_begin=buffer+4;
+          teid_in.str_size=4;
+          pthread_rwlock_rdlock(&teid_idx_lock);
+          bool found= teidin_idx_map.find(teid_in)!=teidin_idx_map.end();
+          pthread_rwlock_unlock(&teid_idx_lock);
+          if(found){
+            // This is the message we're looking for
+
+            // Get the prefix                                     // The ICMPv6 RA header size before the first option is 16
+            int option_length= buffer[12]*256 + buffer[13] - 16;
+            unsigned char* opt=buffer+64;
+            unsigned char* prefix_pt=NULL;
+            while(option_length>0){  // search for the prefix option
+              unsigned int tp=opt[0]; // option type
+              unsigned int ol=opt[1]; // option length measured in 8 octets
+              if(tp==0x03){
+                prefix_pt=opt+16;
+                break;
+              }
+              // move to the next option
+              opt+=(ol*8);
+              option_length-=(ol*8);
+            }
+            if(prefix_pt){ // The prefix is found in the msg
+              pthread_rwlock_wrlock(&teid_idx_lock);
+              str_int_map::iterator it;
+              if((it=teidin_idx_map.find(teid_in))!=teidin_idx_map.end()){ // maybe other udp_to_tun thread received a same message and sent it to the main thread already
+                int idx=it->second;
+                teidin_idx_map.erase(it);  // remove it from the index map
+                // copy the IP prefix, the place of it is
+                memcpy((void*)(ip_req_db[idx].ip.str_begin),prefix_pt,8);
+
+                pthread_rwlock_unlock(&teid_idx_lock);
+
+                write(pipefd[1],&idx,sizeof(int)); // send to the main thread
+              } else {
+                pthread_rwlock_unlock(&teid_idx_lock);
+              }
+
+            }
+            continue;
+          }
+
+        }
+
+        int nread = write(tun_fd,buffer+8,n-8); // 8 : GTP header size
+        //log("Writeing to interface %d, %d, %s",n-8,errno,strerror(errno));
+        if(nread < 0) {
+          perror("Writeing to interface");
+          //exit(1);
+        }
+      }
+    }
+  }
+
+  return 0;
+}
+int add_teid_to_db(str_holder* ip, str_holder* teid, str_holder* rem_ip,int loc_port, int rem_port, int proto, int  loc_fd,struct sockaddr_storage *rem_addr){
+  pthread_rwlock_wrlock(&ip_teid_lock);
+
+  str_int_map::iterator it=ip_idx_map.find(*ip);
+  int idx=-1;
+  if(it==ip_idx_map.end()){
+    if(ip_teid_db_size==ip_teid_db_entries){
+      if(ip_teid_db_size==0){ip_teid_db_size+=256;}
+      ip_teid_db_size*=2;
+      ip_teid_db=(ip_entry_t*)Realloc(ip_teid_db,ip_teid_db_size*sizeof(ip_entry_t));
+      for(int i=ip_teid_db_entries;i<ip_teid_db_size;i++){
+        ip_teid_db[i].teid_num=-1;
+        ip_teid_db[i].teid_list=NULL;
+      }
+    }
+    for(idx=lastIdx;idx<ip_teid_db_size;idx++){
+      if(ip_teid_db[idx].teid_num==-1) {
+        break;
+      }
+    }
+    if(idx>=ip_teid_db_size) {
+      for(idx=0;idx<lastIdx;idx++){
+        if(ip_teid_db[idx].teid_num==-1) {
+          break;
+        }
+      }
+    }
+    ip_teid_db[idx].teid_num=0;
+    copy_str_holder(&ip_teid_db[idx].ip,ip);
+    ip_idx_map[ip_teid_db[idx].ip]=idx;
+    ip_teid_db_entries++;
+    lastIdx=idx;
+  } else {
+    idx=it->second;
+  }
+  int filter_idx=ip_teid_db[idx].teid_num;
+  ip_teid_db[idx].teid_num++;
+  ip_teid_db[idx].teid_list=(teid_filter_t*)Realloc(ip_teid_db[idx].teid_list,ip_teid_db[idx].teid_num*sizeof(teid_filter_t));
+  log("Adding teid to id db idx %d, filter %d",idx,filter_idx);
+
+  ip_teid_db[idx].teid_list[filter_idx].teid_out=*teid;
+  filter_t* filter=&ip_teid_db[idx].teid_list[filter_idx].filter;
+  filter->proto=proto;
+  filter->remote_port=rem_port;
+  log("remote_port %d",rem_port);
+  filter->local_port=loc_port;
+  log("local_port %d",loc_port);
+  if(rem_ip){
+    filter->remote_ip=*rem_ip;
+  } else {
+    filter->remote_ip.str_size=-1;
+  }
+  log("rem-ip");
+  log_str_holder(&(filter->remote_ip));
+
+  ip_teid_db[idx].teid_list[filter_idx].local_fd=loc_fd;
+  memcpy(&ip_teid_db[idx].teid_list[filter_idx].rem_addr,rem_addr,sizeof(struct sockaddr_storage));
+
+  pthread_rwlock_unlock(&ip_teid_lock);
+  return 0;
+}
+
+int remove_teid_from_db(str_holder* ip,str_holder* teid){
+  pthread_rwlock_wrlock(&ip_teid_lock);
+
+  str_int_map::iterator it=ip_idx_map.find(*ip);
+  if(it!=ip_idx_map.end()){
+    int idx=it->second;
+    int i=0;
+    for(i=0;i<ip_teid_db[idx].teid_num;i++){
+      if(!str_eq(*teid,ip_teid_db[idx].teid_list[i].teid_out)){
+        free_str_holder(&ip_teid_db[idx].teid_list[i].teid_out);
+        free_str_holder(&ip_teid_db[idx].teid_list[i].filter.remote_ip);
+        for(int j=0;j<local_ep_length;j++){
+          if(local_ep_db[j].fd==ip_teid_db[idx].teid_list[i].local_fd){
+            local_ep_db[j].usage_num--;
+            close_local_ep(j);
+          }
+        }
+
+        for(int k=i;k<ip_teid_db[idx].teid_num-1;k++){
+          ip_teid_db[idx].teid_list[k]=ip_teid_db[idx].teid_list[k+1];
+        }
+        ip_teid_db[idx].teid_num--;
+        if(ip_teid_db[idx].teid_num){
+          ip_teid_db[idx].teid_list=(teid_filter_t*)Realloc(ip_teid_db[idx].teid_list,ip_teid_db[idx].teid_num*sizeof(teid_filter_t));
+        }
+//        break;  we should remove all teid entries. There can be several with different filter
+      }
+    }
+    if(ip_teid_db[idx].teid_num==0){  // the last teid was removed
+      ip_idx_map.erase(ip_teid_db[idx].ip);
+      del_addr(&ip_teid_db[idx].ip);
+      Free(ip_teid_db[idx].teid_list);
+      ip_teid_db[idx].teid_list=NULL;
+      ip_teid_db[idx].teid_num=-1;
+      free_str_holder(&ip_teid_db[idx].ip);
+      ip_teid_db_entries--;
+    }
+  }
+
+  pthread_rwlock_unlock(&ip_teid_lock);
+  return 0;
+}
+
+int main(int argc, char **argv){
+  signal(SIGPIPE, SIG_IGN);
+  process_options(argc, argv);  // check the command line options
+  pthread_rwlock_init(&ip_teid_lock, NULL);
+  pthread_rwlock_init(&teid_idx_lock, NULL);
+  pthread_rwlock_init(&ep_idx_lock, NULL);
+  log("Starting");
+  if(start_ctrl_listen()<0){
+    printf("Can't listen on control port\r\n");
+    exit(1);
+  }
+  log("Listenning...");
+  // create the TUN interface
+  log("Creating tun");
+
+  if((tun_fd=set_up_tun(0))<0){
+    printf("Can't setup TUN interface\r\n");
+    exit(1);
+  }
+  log("Tun opened: %s",tun_name);
+
+  // create the internal pipe
+  if (pipe(pipefd) == -1) {
+    printf("Can't create internal pipe: %d %s\r\n",errno,strerror(errno));
+    exit(1);
+  }
+
+  log("Internal pipe opened");
+
+  int poll_list_size=4; // The initial size is 2: one listening
+                        //                        one internal pipe
+                        //                        2 space for clients
+  int poll_nfds=2;  // The listening socket and internal pipe will be added to the list
+  struct pollfd *fds=(struct pollfd *)Malloc(poll_list_size*sizeof(struct pollfd));
+
+  memset(fds,0,poll_list_size*sizeof(struct pollfd));
+  fds[0].fd=daemon_fd;
+  fds[0].events= POLLIN | POLLPRI | POLLRDHUP;
+
+  fds[1].fd=pipefd[0];
+  fds[1].events= POLLIN | POLLPRI | POLLRDHUP;
+
+  for(int i=2;i<poll_list_size;i++){
+    fds[i].fd=-1;
+  }
+
+  epfd = epoll_create(100);  /* plan to watch ~100 fds */
+  if (epfd < 0){
+    perror ("epoll_create");
+  }
+  // create buffers for 2 client connections. As we have room for 2 client connection in the fds list
+  msg_buffer *buffers=(msg_buffer *)Malloc((poll_list_size-2)*sizeof(msg_buffer));
+
+  // Each buffer will be initialized when the connection is accepted
+
+
+  while(true){  // controll connection handler
+                //
+    int res=poll(fds,poll_list_size,-1);
+    log("poll returned %d",res);
+    if(res<0){
+      printf("poll error: %d %s\r\n",errno,strerror(errno));
+      exit(1);
+    }
+
+    // first check the client fds
+    for(int i=2;i<poll_list_size;i++){
+      if((fds[i].fd != -1) && fds[i].revents){
+        // No buffer for the first two fd
+        log("Message on fd %d",fds[i].fd );
+        if(process_msg(buffers+(i-2),fds[i].fd)<0){
+          // the test port closed the connection or something went wrong
+          log("Message processing failed");
+          close(fds[i].fd);
+          fds[i].fd = -1;
+          free_msg_buffer(buffers+(i-2));
+        }
+        fds[i].revents=0;
+      }
+    }
+
+    // check the intrnal pipe
+    if(fds[1].revents){
+      fds[1].revents=0;
+      int idx=0;
+      int rd=read(pipefd[0],&idx,sizeof(int));
+      if(rd==sizeof(int)){
+        // read was ok.
+        if(address_set_mode==2){// assign the IP to the interface
+          str_int_map::iterator it=ip_idx_map.find(ip_req_db[idx].ip);
+          if(it==ip_idx_map.end()) {
+            set_addr(&ip_req_db[idx].ip);
+          }
+        }
+
+        // put the out teid into the maps
+        add_teid_to_db(&ip_req_db[idx].ip,&ip_req_db[idx].teid_out,NULL,-1,-1,0,ip_req_db[idx].local_ep_fd,&ip_req_db[idx].rem_addr);
+
+//            if(address_set_mode==2){// assign the IP to the interface
+//              set_addr(&ip_req_db[idx].ip);
+//            }
+
+        // send back the ACK
+        msg_buffer msg_buff;
+        str_holder str;
+        init_msg_buffer(&msg_buff);
+        int out_len=put_int(&msg_buff,22);
+        out_len+=put_int(&msg_buff,GTP_CTRL_MSG_CREATE_ACK);
+        out_len+=put_int(&msg_buff,GTP_CTRL_IE_OUT_TEID);
+        out_len+=put_str(&msg_buff,&ip_req_db[idx].teid_out);
+        out_len+=put_int(&msg_buff,GTP_CTRL_IE_IN_TEID);
+        out_len+=put_str(&msg_buff,&ip_req_db[idx].teid_in);
+
+        out_len+=put_int(&msg_buff,GTP_CTRL_IE_RES_CODE);
+        out_len+=put_int(&msg_buff,0);
+        out_len+=put_int(&msg_buff,GTP_CTRL_IE_RES_TXT);
+        str.str_begin=(const unsigned char*)"OK";
+        str.str_size=2;
+        out_len+=put_str(&msg_buff,&str);
+
+        out_len+=put_int(&msg_buff,GTP_CTRL_IE_ADDR);
+        out_len+=put_str(&msg_buff,&ip_req_db[idx].ip);
+
+        msg_buff.pos=0;
+        put_int(&msg_buff,out_len);
+        //int r=
+         send(ip_req_db[idx].fd,msg_buff.msg,out_len,0);
+        free_msg_buffer(&msg_buff);
+
+        // teid in is not needed any more
+        free_str_holder(&ip_req_db[idx].teid_in);
+
+        //log("Answer sent %d %d",out_len,r);
+
+        // free the ip req db slot
+        ip_req_db[idx].teid_in.str_size=-1;
+      }
+    }
+
+    // check the listening socket
+    if(fds[0].revents){
+      int remote_fd=accept(daemon_fd, NULL, NULL);
+      if(remote_fd<0){
+        printf("accept error: %d %s\r\n",errno,strerror(errno));
+        exit(1);
+      }
+      log("Accepted %d",remote_fd);
+
+      if(poll_list_size==poll_nfds){
+        // we need some more space to store the connection
+        poll_list_size+=4;
+        fds=(struct pollfd *)Realloc(fds,poll_list_size*sizeof(struct pollfd));
+        for(int k=poll_nfds;k<poll_list_size;k++){
+          fds[k].fd=-1;
+          fds[k].events=0;
+        }
+
+        // reserve the buffers
+        buffers=(msg_buffer *)Realloc(buffers,(poll_list_size-2)*sizeof(msg_buffer));
+      }
+      poll_nfds++;
+      // find the first unused connection
+      int k;
+      for(k=2;k<poll_list_size;k++){
+        if(fds[k].fd==-1){break;}
+      }
+      fds[k].fd=remote_fd;
+      fds[k].events= POLLIN | POLLPRI | POLLRDHUP;
+      fds[k].revents= 0;
+
+      // No buffer for the first two fd
+      init_msg_buffer(buffers+(k-2));
+
+      fds[0].revents=0;
+    }
+
+  }
+
+}
diff --git a/src/daemon/daemon.hh b/src/daemon/daemon.hh
new file mode 100644
index 0000000..f51194f
--- /dev/null
+++ b/src/daemon/daemon.hh
@@ -0,0 +1,145 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2000-2018 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
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Rev:                <RnXnn>
+//  Prodnr:             CNL 113 827
+//  Contact:            http://ttcn.ericsson.se
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifndef GTP_DAEMON_H_
+#define GTP_DAEMON_H_
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "GTP_ctrl_handler.h"
+#include <string>
+#include <string.h>
+
+class str_eq{
+public:
+  bool operator() (const str_holder &lhs, const str_holder &rhs) const{
+    return (lhs.str_size == rhs.str_size) && (memcmp(lhs.str_begin,rhs.str_begin,lhs.str_size)==0);
+  }
+};
+struct str_hash{
+  std::size_t operator() (const str_holder &key) const{
+    if(key.str_size==4){ // ipv4
+      return *((uint32_t*)key.str_begin);
+    } else if(key.str_size==16) { // ipv6 
+      return *((uint32_t*)(key.str_begin+12));
+    } else {
+      return 162;
+    }
+  }
+};
+
+
+#if __cplusplus >= 201103L
+#include <unordered_map>
+
+//typedef std::unordered_map<str_holder,str_holder,str_hash > str_hash_map;
+//typedef std::unordered_map<str_holder,int,str_hash > str_int_map;
+#else
+#include <tr1/unordered_map>
+//typedef std::tr1::unordered_map<str_holder,str_holder,str_hash > str_hash_map;
+//typedef std::tr1::unordered_map<str_holder,int,str_hash > str_int_map;
+
+#endif
+#include <map>
+
+struct str_comp{
+  bool operator() (const str_holder &lhs, const str_holder &rhs) const{
+    if(lhs.str_size == rhs.str_size){
+      return memcmp(lhs.str_begin,rhs.str_begin,lhs.str_size)<0;
+    }
+    return lhs.str_size < rhs.str_size;
+  }
+};
+
+typedef std::map<str_holder,str_holder,str_comp> str_hash_map;
+
+typedef std::map<str_holder,int,str_comp> str_int_map;
+#ifdef DEBUG
+void log(const char *fmt, ...);
+#else
+
+#define log(...) 
+#define log_str_holder(...)
+#endif
+
+// outstanding IP prefix request database type
+typedef struct{
+  str_holder teid_in;
+  str_holder teid_out;
+  str_holder ip;
+  int fd;  // fd on which send the create ok
+  int local_ep_fd;  // local endpoint fd belongs to the request
+  struct sockaddr_storage rem_addr;  // The address of the remote endpoint of the tunnel
+} ip_req_db_t;
+
+// filter representation
+typedef struct{
+  int proto;               // protocol num in the IP header
+  str_holder remote_ip; 
+  int        remote_port;  // host byte order
+  int        local_port;   // host byte order
+} filter_t;
+
+// TEID's filter structure
+typedef struct{
+  str_holder teid_out;        // The TEID
+  filter_t   filter;          // filter
+  // data of the outgoing tunnel
+  struct sockaddr_storage rem_addr;  // The address of the remote endpoint of the tunnel
+  int local_fd;                       // local endpoint fd
+} teid_filter_t;
+
+
+// database type for IP->TEID mapping
+typedef struct{
+  str_holder     ip;         // holds the local IP data. 
+  int            teid_num;   // How many teid belongs to the IP
+  teid_filter_t* teid_list;  // the list of the teids
+} ip_entry_t;
+
+// local tunnel endpoint databasetypes
+typedef struct{
+  int fd;           // the fd, on which the messages should be sent & received.
+                    // one local endpoint can serve several tunnel
+  int usage_num;    // how many teids are using the local endpoint
+  str_holder  key;  // points to a struct sockaddr_storage, used as a key in the db
+} local_ep_db_t;
+
+
+void print_usage();
+
+void process_options(int argc, char **argv);
+
+int set_up_tun(int flags); // additional flags
+
+int start_ctrl_listen();
+
+int process_msg(msg_buffer* buffer, int fd);
+
+int fill_addr_struct(const char* local_ip, int local_port, struct sockaddr_storage *local_addr,const char* rem_ip, int rem_port, struct sockaddr_storage *rem_addr);
+
+int open_udp_port(struct sockaddr_storage *local_addr);
+
+void send_error_ind(int fd,const char *fmt, ...);
+
+void *tun_to_udp(void *);
+void *udp_to_tun(void* );
+#define MAX_UDP_PACKET 1500
+
+int set_addr(const str_holder*);
+
+void send_solicit(const str_holder*, int fd, struct sockaddr_storage *clientaddr);
+
+int add_teid_to_db(str_holder* ip, str_holder* teid, str_holder* rem_ip,int loc_port, int rem_port, int proto, int loc_fd,struct sockaddr_storage *rem_addr);
+int remove_teid_from_db(str_holder* ip,str_holder* teid);
+#endif