diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d81e3e7dd175e6423a034c523e710803571fc41e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+# titan.ProtocolModules.WebSocket
+
+Main project page:
+
+https://projects.eclipse.org/projects/tools.titan
+
+The source code of the TTCN-3 compiler and executor:
+
+https://github.com/eclipse/titan.core
diff --git a/WebSocket_CNL113782.tpd b/WebSocket_CNL113782.tpd
new file mode 100644
index 0000000000000000000000000000000000000000..59ec59d1ec0ab197e2646bbbe8bc3e68e452e298
--- /dev/null
+++ b/WebSocket_CNL113782.tpd
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Ericsson
+
+  All rights reserved. This program and the accompanying materials
+  are made available under the terms of the Eclipse Public License v1.0
+  which accompanies this distribution, and is available at
+  http://www.eclipse.org/legal/epl-v10.html
+
+
+   File:               WebSocket_CNL113782.tpd
+   Description:        tpd project file
+   Rev:                R2A
+   Prodnr:             CNL 113 782
+
+ -->
+<TITAN_Project_File_Information version="1.0">
+  <ProjectName>WebSocket_CNL113782</ProjectName>
+  <Files>
+    <FileResource projectRelativePath="WebSocket_EncDec.cc" relativeURI="src/WebSocket_EncDec.cc"/>
+    <FileResource projectRelativePath="WebSocket_Types.ttcn" relativeURI="src/WebSocket_Types.ttcn"/>
+  </Files>
+  <ActiveConfiguration>Default</ActiveConfiguration>
+  <Configurations>
+    <Configuration name="Default">
+      <ProjectProperties>
+        <MakefileSettings>
+          <generateInternalMakefile>true</generateInternalMakefile>
+          <GNUMake>true</GNUMake>
+          <incrementalDependencyRefresh>true</incrementalDependencyRefresh>
+          <targetExecutable>bin/WebSocket_CNL113782</targetExecutable>
+        </MakefileSettings>
+        <LocalBuildSettings>
+          <workingDirectory>bin</workingDirectory>
+        </LocalBuildSettings>
+        <NamingCoventions>
+          <enableProjectSpecificSettings>true</enableProjectSpecificSettings>
+          <externalFunction>f_.*</externalFunction>
+        </NamingCoventions>
+      </ProjectProperties>
+    </Configuration>
+  </Configurations>
+</TITAN_Project_File_Information>
diff --git a/doc/WebSocket_CNL113782_1551.doc b/doc/WebSocket_CNL113782_1551.doc
new file mode 100644
index 0000000000000000000000000000000000000000..76145e1f40bc7add8812e53dfeea3b046d44a1ec
Binary files /dev/null and b/doc/WebSocket_CNL113782_1551.doc differ
diff --git a/doc/WebSocket_CNL113782_PRI.doc b/doc/WebSocket_CNL113782_PRI.doc
new file mode 100644
index 0000000000000000000000000000000000000000..46dc020acaeaacf7f5f48bf04ed48dbfe1073412
Binary files /dev/null and b/doc/WebSocket_CNL113782_PRI.doc differ
diff --git a/src/WebSocket_CNL113782.grp b/src/WebSocket_CNL113782.grp
new file mode 100644
index 0000000000000000000000000000000000000000..94597dabc2f1e04b9788f010c9cbbf4aa3a7d7ed
--- /dev/null
+++ b/src/WebSocket_CNL113782.grp
@@ -0,0 +1,19 @@
+<!--
+/******************************************************************************
+* Copyright (c) 2005, 2015  Ericsson AB
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*
+* Contributors:
+* Gabor Szalai
+******************************************************************************/
+-->
+<!DOCTYPE TITAN_GUI_FileGroup_file>
+<FileGroup TITAN_version="3.1.pl0" >
+    <File_Group name="WebSocket_CNL113782" >
+        <File path="WebSocket_EncDec.cc" />
+        <File path="WebSocket_Types.ttcn" />
+    </File_Group>
+</FileGroup>
diff --git a/src/WebSocket_EncDec.cc b/src/WebSocket_EncDec.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a329fcf3420bd927221904f7391844aaa10d16d8
--- /dev/null
+++ b/src/WebSocket_EncDec.cc
@@ -0,0 +1,300 @@
+/******************************************************************************
+* Copyright (c) 2005, 2015  Ericsson AB
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*
+* Contributors:
+* Gabor Szalai
+******************************************************************************/
+//
+//  File:               WebSocket_EncDec.cc
+//  Prodnr:             CNL 113 782
+//  Rev:                R2A
+
+
+#include "WebSocket_Types.hh"
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+
+static const unsigned char zero_data[]={0,0,0,0};
+static const OCTETSTRING zero_oct=OCTETSTRING(4,&zero_data[0]);
+
+
+namespace WebSocket__Types {
+
+void do_mask(const unsigned char* key, const unsigned char* source, 
+             unsigned char* target, size_t size){
+  int key_idx=0;
+  for(size_t i=0;i<size;i++){
+    target[i]=source[i]^key[key_idx];
+    key_idx++;
+    key_idx&=0x3;
+  }
+}
+
+void f__WebSocket__Encode(const WebSocket__PDU& pl__pdu, OCTETSTRING& pl__data,
+                   const BOOLEAN& pl__gen__maks, const BOOLEAN& pl__auto__maks){
+  TTCN_Buffer buff;
+  unsigned char* data_ptr=NULL;
+  size_t payload_size=0;
+  if(pl__pdu.payload__data().ispresent()){
+    if(pl__pdu.payload__data()().ischosen(WebSocket__payloads::ALT_data)){
+      payload_size=pl__pdu.payload__data()().data().lengthof();
+    } else {
+      payload_size=2;
+      if(pl__pdu.payload__data()().close__data().data().ispresent()){
+        payload_size+=pl__pdu.payload__data()().close__data().data()().lengthof();
+      }
+    }
+  }
+  size_t data_size=14+payload_size; // max header size + payload size
+  
+  buff.get_end(data_ptr,data_size);
+  unsigned char* begin_ptr=data_ptr;
+  memset(data_ptr,0,data_size);
+
+  *data_ptr|=((*((const unsigned char*)pl__pdu.fin__bit()))&0x1)<<7;
+  *data_ptr|=((*((const unsigned char*)pl__pdu.rsv1__bit()))&0x1)<<6;
+  *data_ptr|=((*((const unsigned char*)pl__pdu.rsv2__bit()))&0x1)<<5;
+  *data_ptr|=((*((const unsigned char*)pl__pdu.rsv3__bit()))&0x1)<<4;
+  *data_ptr|=((int)pl__pdu.opcode())&0xf;
+  data_ptr++;
+
+  *data_ptr|=((*((const unsigned char*)pl__pdu.mask__bit()))&0x1)<<7;
+
+  // encode size
+  if(payload_size<126){
+    *data_ptr|=(payload_size&0x7);
+    data_ptr++;
+  } else if (payload_size<65536) { // 16 bit unsigned max
+    size_t orig_p_size=payload_size; 
+    *data_ptr|=126;
+    data_ptr++;
+    data_ptr[1]=orig_p_size&0xff;
+    orig_p_size>>=8;
+    data_ptr[0]=orig_p_size&0xff;
+    data_ptr+=2;
+  } else {
+    size_t orig_p_size=payload_size; 
+    *data_ptr|=127;
+    data_ptr++;
+    data_ptr[7]=orig_p_size&0xff;
+    orig_p_size>>=8;
+    data_ptr[6]=orig_p_size&0xff;
+    orig_p_size>>=8;
+    data_ptr[5]=orig_p_size&0xff;
+    orig_p_size>>=8;
+    data_ptr[4]=orig_p_size&0xff;
+    orig_p_size>>=8;
+    data_ptr[3]=orig_p_size&0xff;
+    orig_p_size>>=8;
+    data_ptr[2]=orig_p_size&0xff;
+    orig_p_size>>=8;
+    data_ptr[1]=orig_p_size&0xff;
+    orig_p_size>>=8;
+    data_ptr[0]=orig_p_size&0xff;
+    data_ptr+=8;
+  }
+  
+  unsigned char* mask_ptr=NULL;
+  if(((*((const unsigned char*)pl__pdu.mask__bit()))&0x1) &&
+      pl__gen__maks &&
+      (!pl__pdu.masking__key().ispresent() || 
+                                           pl__pdu.masking__key()()==zero_oct)){
+    // generate masking key
+    mask_ptr=data_ptr;
+    OCTETSTRING mk=f__WebSocket__Generate__Masking__Key();
+    memcpy(data_ptr,(const unsigned char *)mk,4);
+    data_ptr+=4;
+  } else if(pl__pdu.masking__key().ispresent()) { // use the provided key
+    mask_ptr=data_ptr;
+    memcpy(data_ptr,(const unsigned char *)pl__pdu.masking__key()(),4);
+    data_ptr+=4;
+  }
+  
+  if(pl__pdu.payload__data().ispresent()){
+    if(pl__pdu.payload__data()().ischosen(WebSocket__payloads::ALT_data)){
+      memcpy(data_ptr,
+             (const unsigned char *)pl__pdu.payload__data()().data(),
+             pl__pdu.payload__data()().data().lengthof());
+    } else {
+      int st_code=(int)pl__pdu.payload__data()().close__data().status__code();
+      data_ptr[1]=st_code&0xFF;
+      st_code>>=8;
+      data_ptr[0]=st_code&0xFF;
+      if(pl__pdu.payload__data()().close__data().data().ispresent()){
+        memcpy(data_ptr+2, // skip status code
+        (const unsigned char *)pl__pdu.payload__data()().close__data().data()(),
+             pl__pdu.payload__data()().close__data().data()().lengthof());
+      }
+    }
+  }
+  
+  if(mask_ptr && pl__auto__maks){ // apply mask
+    do_mask(mask_ptr,data_ptr,data_ptr,payload_size);
+  }
+  
+  buff.increase_length(data_ptr-begin_ptr+payload_size);
+  buff.get_string(pl__data);
+  
+}
+
+INTEGER f__WebSocket__Decode(const OCTETSTRING& pl__data, 
+                        WebSocket__PDU& pl__pdu, const BOOLEAN& pl__auto__maks){
+  size_t data_len=pl__data.lengthof();
+  if(data_len>=2){
+    const unsigned char* data_ptr=(const unsigned char*)pl__data;
+    size_t base_length=(data_ptr[1]&0x80)?6:2;
+    size_t payload_length=data_ptr[1]&0x7F;
+    size_t len_len=0;
+    if (payload_length==126) {
+      if(data_len>=4){
+        payload_length=(data_ptr[2]<<8)+data_ptr[3];
+        len_len=2;
+      } else {
+        return 1; // NOT_MY_TYPE not enough bits in the buffer
+      }
+    } else if (payload_length==127) {
+      if(data_len>=10){
+        len_len=8;
+        long long int large_payload_length=(((long long int)data_ptr[2])<<56)+
+          (((long long int)data_ptr[3])<<48)+(((long long int)data_ptr[4])<<40)+
+          (((long long int)data_ptr[5])<<32)+(((long long int)data_ptr[6])<<24)+
+          (((long long int)data_ptr[7])<<16)+(((long long int)data_ptr[8])<<8)+
+          (long long int)data_ptr[9];
+        payload_length=large_payload_length;
+        if(large_payload_length!=(long long int)payload_length){ // overflow
+          TTCN_warning("The received WebSocket messages is too large");
+          return 1; // NOT_MY_TYPE message too largo to handle
+        }
+      } else {
+        return 1; // NOT_MY_TYPE not enough bits in the buffer
+      }
+    }
+    
+    if(data_len<(payload_length+base_length)){
+      return 1; // NOT_MY_TYPE not enough bits in the buffer
+    }
+    
+    // Now the decodeing can be started.
+    unsigned char bit_temp;
+    
+    bit_temp=(data_ptr[0]>>7)&0x1;
+    pl__pdu.fin__bit()=BITSTRING(1,&bit_temp);
+    bit_temp=(data_ptr[0]>>6)&0x1;
+    pl__pdu.rsv1__bit()=BITSTRING(1,&bit_temp);
+    bit_temp=(data_ptr[0]>>5)&0x1;
+    pl__pdu.rsv2__bit()=BITSTRING(1,&bit_temp);
+    bit_temp=(data_ptr[0]>>4)&0x1;
+    pl__pdu.rsv3__bit()=BITSTRING(1,&bit_temp);
+    
+    pl__pdu.opcode()=data_ptr[0]&0xf;
+    
+    bit_temp=(data_ptr[1]>>7)&0x1;
+    bool masked=bit_temp;
+    pl__pdu.mask__bit()=BITSTRING(1,&bit_temp);
+    pl__pdu.payload__len()=payload_length;
+    
+    data_ptr+=len_len+2;
+    
+    unsigned char* unmasked=NULL;
+    if(masked){
+      pl__pdu.masking__key()=OCTETSTRING(4,data_ptr);
+      if(pl__auto__maks && payload_length){
+        unmasked=(unsigned char*)Malloc(payload_length*sizeof(unsigned char));
+        do_mask(data_ptr,data_ptr+4,unmasked,payload_length);
+        data_ptr=unmasked;
+      } else {
+        data_ptr+=4;
+      }
+    } else {
+      pl__pdu.masking__key()=OMIT_VALUE;
+    }
+    
+    if(payload_length){
+      if(pl__pdu.opcode()==WebSocket__opcode::Connection__Close){
+        if(payload_length>=2){
+          pl__pdu.payload__data()().close__data().status__code()= 
+                                                 (data_ptr[0]<<8) + data_ptr[1];
+          if(payload_length>2){
+            pl__pdu.payload__data()().close__data().data()()=
+                                       OCTETSTRING(payload_length-2,data_ptr+2);
+          } else {
+            pl__pdu.payload__data()().close__data().data()=OMIT_VALUE;
+          }
+        } else {
+          return 1; // NOT_MY_TYPE not enough bits in the buffer
+        }
+      } else {
+        pl__pdu.payload__data()().data()=OCTETSTRING(payload_length,data_ptr);
+      }
+      
+    } else {
+      pl__pdu.payload__data()=OMIT_VALUE;
+    }
+    
+    if(unmasked) {
+      Free(unmasked);
+    }
+    
+  } else {
+    return 1; // NOT_MY_TYPE not enough bits in the buffer
+  }
+  return 0;
+}
+
+INTEGER f__WebSocket__calc__length(const OCTETSTRING& pl__data){
+  size_t data_len=pl__data.lengthof();
+  if(data_len>=2){
+    const unsigned char* data_ptr=(const unsigned char*)pl__data;
+    int base_length=(data_ptr[1]&0x80)?6:2;
+    int payload_length=data_ptr[1]&0x7F;
+    if(payload_length<126){
+      return payload_length+base_length;
+    } else if (payload_length==126) {
+      if(data_len>=4){
+        payload_length=(data_ptr[2]<<8)+data_ptr[3];
+        return payload_length+base_length+2;
+      }
+    } else {
+      if(data_len>=10){
+        long long int large_payload_length=(((long long int)data_ptr[2])<<56)+
+          (((long long int)data_ptr[3])<<48)+(((long long int)data_ptr[4])<<40)+
+          (((long long int)data_ptr[5])<<32)+(((long long int)data_ptr[6])<<24)+
+          (((long long int)data_ptr[7])<<16)+(((long long int)data_ptr[8])<<8)+
+          (long long int)data_ptr[9]+(long long int)base_length+8;
+        INTEGER large_ret_val;
+        large_ret_val.set_long_long_val(large_payload_length);
+        return large_ret_val;
+      }
+    }
+  }
+  return -1;
+}
+
+OCTETSTRING f__WebSocket__Generate__Masking__Key(){
+  static bool inited=false;
+  if(!inited){
+    time_t t1;
+    time(&t1);
+	  srand48((long) t1);
+    inited=true;
+  }
+  unsigned char mkey[4];
+  long int key=mrand48();
+  mkey[0]= key & 0xFF;
+  key>>=8;
+  mkey[1]= key & 0xFF;
+  key>>=8;
+  mkey[2]= key & 0xFF;
+  key>>=8;
+  mkey[3]= key & 0xFF;
+  return OCTETSTRING(4,&mkey[0]);
+}
+
+
+}
+
diff --git a/src/WebSocket_Types.ttcn b/src/WebSocket_Types.ttcn
new file mode 100644
index 0000000000000000000000000000000000000000..04caf74c6d9b3a0b66f45eaa6f7dc4ed1825b3bf
--- /dev/null
+++ b/src/WebSocket_Types.ttcn
@@ -0,0 +1,73 @@
+/******************************************************************************
+* Copyright (c) 2005, 2015  Ericsson AB
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*
+* Contributors:
+* Gabor Szalai
+******************************************************************************/
+//
+//  File:               WebSocket_Types.ttcn
+//  Rev:                R2A
+//  Prodnr:             CNL 113 782
+//  Reference:          RFC 6455
+
+module WebSocket_Types {
+
+  modulepar boolean m_Websocket_generate_masking_key:=true;
+  modulepar boolean m_Websocket_auto_masking:=true;
+
+  external function f_WebSocket_Encode(in WebSocket_PDU pl_pdu,
+                       out octetstring pl_data,
+                       in boolean pl_gen_maks:=m_Websocket_generate_masking_key,
+                       in boolean pl_auto_maks:= m_Websocket_auto_masking);
+
+  external function f_WebSocket_Decode(in octetstring pl_data,
+                       out WebSocket_PDU pl_pdu,
+                       in boolean pl_auto_maks:= m_Websocket_auto_masking) 
+                       return integer;
+
+  external function f_WebSocket_calc_length(in octetstring pl_data)
+                       return integer;
+
+  external function f_WebSocket_Generate_Masking_Key() return octetstring;
+
+  type record Websocket_close {
+    integer           status_code,
+    octetstring       data optional
+  };
+
+  type enumerated WebSocket_opcode {Continuation_frame (0), Text_frame (1),
+                                    Binary_frame (2), Reserved_non_control3 (3),
+                                    Reserved_non_control4 (4),
+                                    Reserved_non_control5 (5),
+                                    Reserved_non_control6 (6),
+                                    Reserved_non_control7 (7),
+                                    Connection_Close(8), Ping(9), Pong (10),
+                                    Reserved_control11 (11),
+                                    Reserved_control12 (12),
+                                    Reserved_control13 (13),
+                                    Reserved_control14 (14),
+                                    Reserved_control15 (15)
+                                  };
+
+  type union WebSocket_payloads {
+    octetstring       data,
+    Websocket_close   close_data
+  };
+  
+  type record WebSocket_PDU {
+    bitstring           fin_bit length(1),
+    bitstring           rsv1_bit length(1),
+    bitstring           rsv2_bit length(1),
+    bitstring           rsv3_bit length(1),
+    WebSocket_opcode    opcode,
+    bitstring           mask_bit length(1),
+    integer             payload_len,
+    octetstring         masking_key length(4) optional,
+    WebSocket_payloads  payload_data optional
+  };
+
+}