negative testing added
diff --git a/src/negative_testing/Mqtt_v3.1.1_EncDec.cc b/src/negative_testing/Mqtt_v3.1.1_EncDec.cc
new file mode 100644
index 0000000..d32d997
--- /dev/null
+++ b/src/negative_testing/Mqtt_v3.1.1_EncDec.cc
@@ -0,0 +1,792 @@
+/******************************************************************************
+* Copyright (c) 2016 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:
+* Mate Kovacs - initial implementation and initial documentation
+* Bence Janos Szabo - negative testing branch
+******************************************************************************/
+//
+// File: Mqtt_v3.1.1_EncDec.cc
+// Rev: R1A
+// Prodnr: CNL 113 831
+
+#include "MQTT_v3_1_1_Types.hh"
+
+namespace MQTT__v3__1__1__Types {
+
+unsigned int encodeFlags(BIT4n bits);
+int encodePacketIdentifier(TTCN_Buffer &buffer, int identifier);
+int encodeUtf8(TTCN_Buffer &stream, const UNIVERSAL_CHARSTRING& str, const INTEGER& length);
+int encodeOctetstring(TTCN_Buffer &stream, const OCTETSTRING& str, const INTEGER& length);
+int decodeInteger(const unsigned char* &str, const int position, const int length);
+
+INTEGER
+f__MQTT__v3__1__1__dec(OCTETSTRING const &str, MQTT__v3__1__1__Message &msg)
+{
+ if(TTCN_Logger::log_this_event(TTCN_DEBUG)){
+ TTCN_Logger::begin_event(TTCN_DEBUG);
+ TTCN_Logger::log_event("Decoding MQTT 3.1.1 message: ");
+ str.log();
+ TTCN_Logger::end_event();
+ }
+
+ if(str.lengthof() >= 2){
+ const unsigned char lookup[16] = {
+ 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
+ 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf};
+ const unsigned char* str_ptr = (const unsigned char*) str;
+ int packetType = str_ptr[0] >> 4;
+ unsigned char bitstr = lookup[str_ptr[0] & 15];
+ int position = 1;
+ int prePosition = 1;
+ int count = 0;
+ int multiplier = 1;
+ int length = 0;
+ unsigned char encodedByte;
+ int tmpLength;
+ unsigned char flag;
+
+ //get packet length
+ do{
+ if(str.lengthof() < position){
+ msg.raw__message() = str;
+ return 1;
+ }
+ encodedByte = str_ptr[position];
+ length += (encodedByte & 127) * multiplier;
+ multiplier *= 128;
+ if(multiplier > 128*128*128){
+ msg.raw__message() = str;
+ return 1;
+ }
+ position++;
+ prePosition++;
+ }while((encodedByte & 128) != 0);
+ switch(packetType){
+ case 1:
+ msg.msg().connect__msg().header().packetType() = int2bit(packetType, 4);
+ msg.msg().connect__msg().header().flags() = BITSTRING(4, &bitstr);
+ if(str.lengthof() < position+1){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().connect__msg().header().remLength() = int2oct(length, 4);
+ tmpLength = decodeInteger(str_ptr, position, 2);
+ if(str.lengthof() < position+8+tmpLength){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().connect__msg().nameLength() = tmpLength;
+ msg.msg().connect__msg().name().decode_utf8(tmpLength, &str_ptr[position+2]);
+ position += 2+tmpLength;
+ msg.msg().connect__msg().protocol__level() = decodeInteger(str_ptr, position, 1);
+ position++;
+ //flags
+ flag = (str_ptr[position] & 128) >> 7;
+ msg.msg().connect__msg().flags().user__name__flag() = BITSTRING(1, &flag);
+ flag = (str_ptr[position] & 64) >> 6;
+ msg.msg().connect__msg().flags().password__flag() = BITSTRING(1, &flag);
+ flag = (str_ptr[position] & 32) >> 5;
+ msg.msg().connect__msg().flags().will__retain() = BITSTRING(1, &flag);
+ msg.msg().connect__msg().flags().will__qos() = (str_ptr[position] >> 3) & 3;
+ flag = (str_ptr[position] & 4) >> 2;
+ msg.msg().connect__msg().flags().will__flag() = BITSTRING(1, &flag);
+ flag = (str_ptr[position] & 2) >> 1;
+ msg.msg().connect__msg().flags().clean__session() = BITSTRING(1, &flag);
+ flag = str_ptr[position];
+ msg.msg().connect__msg().flags().reserved() = BITSTRING(1, &flag);
+ position++;
+ msg.msg().connect__msg().keep__alive() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ //payload
+ tmpLength = decodeInteger(str_ptr, position, 2);
+
+ if(str.lengthof() < position+2+tmpLength){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().connect__msg().payload().client__identifier().stringLength() = tmpLength;
+ msg.msg().connect__msg().payload().client__identifier().stringItem().decode_utf8(tmpLength, &str_ptr[position+2]);
+ position += 2+tmpLength;
+ if(msg.msg().connect__msg().flags().will__flag()[0].get_bit() == 1){
+ if(str.lengthof() < position+2){
+ msg.raw__message() = str;
+ return 1;
+ }
+ tmpLength = decodeInteger(str_ptr, position, 2);
+ if(str.lengthof() < position+4+tmpLength){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().connect__msg().payload().will__topic()().stringLength() = tmpLength;
+ msg.msg().connect__msg().payload().will__topic()().stringItem().decode_utf8(tmpLength, &str_ptr[position+2]);
+ position += 2+tmpLength;
+
+ tmpLength = decodeInteger(str_ptr, position, 2);
+ if(str.lengthof() < position+2+tmpLength){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().connect__msg().payload().will__message()().stringLength() = tmpLength;
+ msg.msg().connect__msg().payload().will__message()().stringItem() = OCTETSTRING(tmpLength, &str_ptr[position+2]);
+ position += 2+tmpLength;
+ }else{
+ msg.msg().connect__msg().payload().will__topic() = OMIT_VALUE;
+ msg.msg().connect__msg().payload().will__message() = OMIT_VALUE;
+ }
+ if(msg.msg().connect__msg().flags().user__name__flag()[0].get_bit() == 1){
+ if(str.lengthof() < position+2){
+ msg.raw__message() = str;
+ return 1;
+ }
+ tmpLength = decodeInteger(str_ptr, position, 2);
+ if(str.lengthof() < position+2+tmpLength){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().connect__msg().payload().user__name()().stringLength() = tmpLength;
+ msg.msg().connect__msg().payload().user__name()().stringItem().decode_utf8(tmpLength, &str_ptr[position+2]);
+ position += 2+tmpLength;
+ }else{
+ msg.msg().connect__msg().payload().user__name() = OMIT_VALUE;
+ }
+ if(msg.msg().connect__msg().flags().password__flag()[0].get_bit() == 1){
+ if(str.lengthof() < position+2){
+ msg.raw__message() = str;
+ return 1;
+ }
+ tmpLength = decodeInteger(str_ptr, position, 2);
+ if(str.lengthof() < position+2+tmpLength){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().connect__msg().payload().password()().stringLength() = tmpLength;
+ msg.msg().connect__msg().payload().password()().stringItem() = OCTETSTRING(tmpLength, &str_ptr[position+2]);
+ position += 2+tmpLength;
+ }else{
+ msg.msg().connect__msg().payload().password() = OMIT_VALUE;
+ }
+ break;
+ case 2:
+ msg.msg().connack().header().packetType() = int2bit(packetType, 4);
+ msg.msg().connack().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().connack().header().remLength() = int2oct(length, 4);
+ if(str.lengthof() >= position+2){
+ bitstr = str_ptr[position] & 1;
+ msg.msg().connack().session__present__flag() = BITSTRING(1, &bitstr);
+ msg.msg().connack().connect__return__code() = decodeInteger(str_ptr, position+1, 1);
+ position += 2;
+ }
+ break;
+ case 3:
+ msg.msg().publish().header().packetType() = int2bit(packetType, 4);
+ msg.msg().publish().header().dup__flag() = BITSTRING(1, &bitstr);
+ msg.msg().publish().header().qos__level() = lookup[bitstr & 6] >> 1;
+ flag = (bitstr >> 3) & 1;
+ msg.msg().publish().header().retain__flag() = BITSTRING(1, &flag);
+ if(str.lengthof() < position+2){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().publish().header().remLength() = int2oct(length, 4);
+ tmpLength = decodeInteger(str_ptr, position, 2);
+ if(str.lengthof() < position+2+tmpLength){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().publish().nameLength() = tmpLength;
+ msg.msg().publish().topic__name().decode_utf8(tmpLength, &str_ptr[position+2]);
+ position += 2+tmpLength;
+ if((msg.msg().publish().header().qos__level() == MQTT__v3__1__1__Types::QoS::AT__LEAST__ONCE__DELIVERY || msg.msg().publish().header().qos__level() == MQTT__v3__1__1__Types::QoS::EXACTLY__ONE__DELIVERY) && str.lengthof() >= position+2){
+ if(str.lengthof() < position+2){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().publish().packet__identifier()() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ }else{
+ msg.msg().publish().packet__identifier() = OMIT_VALUE;
+ }
+ msg.msg().publish().payload() = OCTETSTRING(length - position + prePosition, &str_ptr[position]);
+ position += (length - position + prePosition);
+ break;
+ case 4:
+ msg.msg().puback().header().packetType() = int2bit(packetType, 4);
+ msg.msg().puback().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().puback().header().remLength() = int2oct(length, 4);
+ if(str.lengthof() >= position+2){
+ msg.msg().puback().packet__identifier() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ }else{
+ msg.raw__message() = str;
+ return 1;
+ }
+ break;
+ case 5:
+ msg.msg().pubrec().header().packetType() = int2bit(packetType, 4);
+ msg.msg().pubrec().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().pubrec().header().remLength() = int2oct(length, 4);
+ if(str.lengthof() >= position+2){
+ msg.msg().pubrec().packet__identifier() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ }else{
+ msg.raw__message() = str;
+ return 1;
+ }
+ break;
+ case 6:
+ msg.msg().pubrel().header().packetType() = int2bit(packetType, 4);
+ msg.msg().pubrel().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().pubrel().header().remLength() = int2oct(length, 4);
+ if(str.lengthof() >= position+2){
+ msg.msg().pubrel().packet__identifier() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ }else{
+ msg.raw__message() = str;
+ return 1;
+ }
+ break;
+ case 7:
+ msg.msg().pubcomp().header().packetType() = int2bit(packetType, 4);
+ msg.msg().pubcomp().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().pubcomp().header().remLength() = int2oct(length, 4);
+ if(str.lengthof() >= position+2){
+ msg.msg().pubcomp().packet__identifier() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ }else{
+ msg.raw__message() = str;
+ return 1;
+ }
+ break;
+ case 8:
+ msg.msg().subscribe().header().packetType() = int2bit(packetType, 4);
+ msg.msg().subscribe().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().subscribe().header().remLength() = int2oct(length, 4);
+ if(str.lengthof() >= position+2){
+ msg.msg().subscribe().packet__identifier() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ }else{
+ msg.raw__message() = str;
+ return 1;
+ }
+ while(str.lengthof() > position){
+ if(str.lengthof() < position+2){
+ msg.raw__message() = str;
+ return 1;
+ }
+ tmpLength = decodeInteger(str_ptr, position, 2);
+ if(str.lengthof() < position+3+tmpLength){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().subscribe().payload()[count].filterLength() = tmpLength;
+ msg.msg().subscribe().payload()[count].topic__filter().decode_utf8(tmpLength, &str_ptr[position+2]);
+ msg.msg().subscribe().payload()[count].requested__qos() = str_ptr[position+tmpLength+2];
+ count++;
+ position += 3+tmpLength;
+ }
+ if(count == 0){
+ msg.msg().subscribe().payload() = MQTT__v3__1__1__Types::MQTT__v3__1__1__SubscribePayloadList(NULL_VALUE);
+ }
+ break;
+ case 9:
+ msg.msg().suback().header().packetType() = int2bit(packetType, 4);
+ msg.msg().suback().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().suback().header().remLength() = int2oct(length, 4);
+ if(str.lengthof() >= position+2){
+ msg.msg().suback().packet__identifier() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ }else{
+ msg.raw__message() = str;
+ return 1;
+ }
+ while(str.lengthof() > position){
+ if(str.lengthof() < position+1){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().suback().payload().return__code()[count] = decodeInteger(str_ptr, position, 1);
+ count++;
+ position++;
+ }
+ if(count == 0){
+ msg.msg().suback().payload().return__code() = MQTT__v3__1__1__Types::IntegerList(NULL_VALUE);
+ }
+ break;
+ case 10:
+ msg.msg().unsubscribe().header().packetType() = int2bit(packetType, 4);
+ msg.msg().unsubscribe().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().unsubscribe().header().remLength() = int2oct(length, 4);
+ if(str.lengthof() >= position+2){
+ msg.msg().unsubscribe().packet__identifier() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ }else{
+ msg.raw__message() = str;
+ return 1;
+ }
+ while(str.lengthof() > position){
+ if(str.lengthof() < position+2){
+ msg.raw__message() = str;
+ return 1;
+ }
+ tmpLength = decodeInteger(str_ptr, position, 2);
+ if(str.lengthof() < position+2+tmpLength){
+ msg.raw__message() = str;
+ return 1;
+ }
+ msg.msg().unsubscribe().payload()[count].filterLength() = tmpLength;
+ msg.msg().unsubscribe().payload()[count].topic__filter().decode_utf8(tmpLength, &str_ptr[position+2]);
+ position += 2+tmpLength;
+ count++;
+ }
+ if(count == 0){
+ msg.msg().unsubscribe().payload() = MQTT__v3__1__1__Types::MQTT__v3__1__1__UnsubscribePayloadList(NULL_VALUE);
+ }
+ break;
+ case 11:
+ msg.msg().unsuback().header().packetType() = int2bit(packetType, 4);
+ msg.msg().unsuback().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().unsuback().header().remLength() = int2oct(length, 4);
+ if(str.lengthof() >= position+2){
+ msg.msg().unsuback().packet__identifier() = decodeInteger(str_ptr, position, 2);
+ position += 2;
+ }else{
+ msg.raw__message() = str;
+ return 1;
+ }
+ break;
+ case 12:
+ msg.msg().pingreq().header().packetType() = int2bit(packetType, 4);
+ msg.msg().pingreq().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().pingreq().header().remLength() = int2oct(length, 4);
+ break;
+ case 13:
+ msg.msg().pingresp().header().packetType() = int2bit(packetType, 4);
+ msg.msg().pingresp().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().pingresp().header().remLength() = int2oct(length, 4);
+ break;
+ case 14:
+ msg.msg().disconnect__msg().header().packetType() = int2bit(packetType, 4);
+ msg.msg().disconnect__msg().header().flags() = BITSTRING(4, &bitstr);
+ msg.msg().disconnect__msg().header().remLength() = int2oct(length, 4);
+ break;
+ case 0:
+ case 15:
+ default:
+ msg.raw__message() = str;
+ return 0;
+ break;
+ }
+ if(str.lengthof() > position or length != (position-prePosition)){
+ msg.raw__message() = str;
+ return 1;
+ }
+ }else{
+ msg.raw__message() = str;
+ return 1;
+ }
+
+ if(TTCN_Logger::log_this_event(TTCN_DEBUG)){
+ TTCN_Logger::begin_event(TTCN_DEBUG);
+ TTCN_Logger::log_event("Decoded MQTT 3.1.1 message: ");
+ msg.log();
+ TTCN_Logger::end_event();
+ }
+
+ return 0;
+}
+
+INTEGER
+f__MQTT__v3__1__1__enc(MQTT__v3__1__1__Message const &msg, OCTETSTRING &str)
+{
+ TTCN_Buffer stream_beginning;
+ TTCN_Buffer stream;
+ unsigned char chr = 0;
+ long long int length = 0;
+
+ if(TTCN_Logger::log_this_event(TTCN_DEBUG)){
+ TTCN_Logger::begin_event(TTCN_DEBUG);
+ TTCN_Logger::log_event("Encoding MQTT 3.1.1 message: ");
+ msg.log();
+ TTCN_Logger::end_event();
+ }
+
+ switch(msg.get_selection()){
+ case MQTT__v3__1__1__Message::ALT_raw__message:
+ stream.put_os(msg.raw__message());
+ stream.get_string(str);
+ return 0;
+ break;
+ case MQTT__v3__1__1__Message::ALT_msg:
+ default:
+ break;
+ }
+
+ switch(msg.msg().get_selection()){
+ case MQTT__v3__1__1__ReqResp::ALT_connect__msg:
+ chr = (int)(bit2int(msg.msg().connect__msg().header().packetType()) << 4);
+ if(msg.msg().connect__msg().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().connect__msg().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().connect__msg().header().remLength()).get_long_long_val();
+ //variable header
+ if(encodeUtf8(stream, msg.msg().connect__msg().name(), msg.msg().connect__msg().nameLength()) != 0){
+ return 1;
+ }
+ if(0 <= msg.msg().connect__msg().protocol__level() && msg.msg().connect__msg().protocol__level() <= 255){
+ chr = (int) msg.msg().connect__msg().protocol__level();
+ stream.put_c(chr);
+ }else{
+ return 1;
+ }
+ //flags
+ if(msg.msg().connect__msg().flags().user__name__flag().lengthof() == 1 && msg.msg().connect__msg().flags().password__flag().lengthof() == 1 &&
+ msg.msg().connect__msg().flags().will__retain().lengthof() == 1 && msg.msg().connect__msg().flags().will__flag().lengthof() == 1 &&
+ msg.msg().connect__msg().flags().clean__session().lengthof() == 1){
+ chr = msg.msg().connect__msg().flags().user__name__flag()[0].get_bit() << 7;
+ chr += msg.msg().connect__msg().flags().password__flag()[0].get_bit() << 6;
+ chr += msg.msg().connect__msg().flags().will__retain()[0].get_bit() << 5;
+ chr += ((int) msg.msg().connect__msg().flags().will__qos()) << 3;
+ chr += msg.msg().connect__msg().flags().will__flag()[0].get_bit() << 2;
+ chr += msg.msg().connect__msg().flags().clean__session()[0].get_bit() << 1;
+ chr += msg.msg().connect__msg().flags().reserved()[0].get_bit();
+ stream.put_c(chr);
+ }else{
+ return 1;
+ }
+ if(0 <= msg.msg().connect__msg().keep__alive() && msg.msg().connect__msg().keep__alive() <= 65535){
+ chr = (int) msg.msg().connect__msg().keep__alive() >> 8;
+ stream.put_c(chr);
+ chr = (int) msg.msg().connect__msg().keep__alive();
+ stream.put_c(chr);
+ }else{
+ return 1;
+ }
+ //payload
+ if(encodeUtf8(stream, msg.msg().connect__msg().payload().client__identifier().stringItem(), msg.msg().connect__msg().payload().client__identifier().stringLength()) != 0){
+ return 1;
+ }
+ if(msg.msg().connect__msg().payload().will__topic().ispresent()){
+ if(encodeUtf8(stream, msg.msg().connect__msg().payload().will__topic()().stringItem(), msg.msg().connect__msg().payload().will__topic()().stringLength()) != 0){
+ return 1;
+ }
+ }
+ if(msg.msg().connect__msg().payload().will__message().ispresent()){
+ if(encodeOctetstring(stream, msg.msg().connect__msg().payload().will__message()().stringItem(), msg.msg().connect__msg().payload().will__message()().stringLength()) != 0){
+ return 1;
+ }
+ }
+ if(msg.msg().connect__msg().payload().user__name().ispresent()){
+ if(encodeUtf8(stream, msg.msg().connect__msg().payload().user__name()().stringItem(), msg.msg().connect__msg().payload().user__name()().stringLength()) != 0){
+ return 1;
+ }
+ }
+ if(msg.msg().connect__msg().payload().password().ispresent()){
+ if(encodeOctetstring(stream, msg.msg().connect__msg().payload().password()().stringItem(), msg.msg().connect__msg().payload().password()().stringLength()) != 0){
+ return 1;
+ }
+ }
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_connack:
+ chr = (int)(bit2int(msg.msg().connack().header().packetType()) << 4);
+ if(msg.msg().connack().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().connack().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().connack().header().remLength()).get_long_long_val();
+ //variable header
+ if(msg.msg().connack().session__present__flag().lengthof() == 1){
+ chr = msg.msg().connack().session__present__flag()[0].get_bit();
+ stream.put_c(chr);
+ }else{
+ return 1;
+ }
+ if((int) msg.msg().connack().connect__return__code() < 0 || 255 < (int) msg.msg().connack().connect__return__code()){
+ return 1;
+ }
+ chr = (int) msg.msg().connack().connect__return__code();
+ stream.put_c(chr);
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_publish:
+ const unsigned char* tmp;
+ chr = (int)(bit2int(msg.msg().publish().header().packetType()) << 4);
+ if(msg.msg().publish().header().dup__flag().lengthof() == 1 && msg.msg().publish().header().retain__flag().lengthof() == 1){
+ tmp = (const unsigned char*) msg.msg().publish().header().dup__flag();
+ chr += tmp[0] << 3;
+ chr += msg.msg().publish().header().qos__level() << 1;
+ tmp = (const unsigned char*) msg.msg().publish().header().retain__flag();
+ chr += tmp[0];
+ }else{
+ return 1;
+ }
+ stream_beginning.put_c(chr);
+ length = oct2int(msg.msg().publish().header().remLength()).get_long_long_val();
+ //variable header
+ if(encodeUtf8(stream, msg.msg().publish().topic__name(), msg.msg().publish().nameLength()) != 0){
+ return 1;
+ }
+ if(msg.msg().publish().packet__identifier().is_present()){
+ if(encodePacketIdentifier(stream, (int) msg.msg().publish().packet__identifier()()) != 0){
+ return 1;
+ }
+ }
+ //payload
+ stream.put_os(msg.msg().publish().payload());
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_puback:
+ chr = (int)(bit2int(msg.msg().puback().header().packetType()) << 4);
+ if(msg.msg().puback().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().puback().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().puback().header().remLength()).get_long_long_val();
+ //variable header
+ if(encodePacketIdentifier(stream, (int) msg.msg().puback().packet__identifier()) != 0){
+ return 1;
+ }
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_pubrec:
+ chr = (int)(bit2int(msg.msg().pubrec().header().packetType()) << 4);
+ if(msg.msg().pubrec().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().pubrec().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().pubrec().header().remLength()).get_long_long_val();
+
+ //variable header
+ if(encodePacketIdentifier(stream, (int) msg.msg().pubrec().packet__identifier()) != 0){
+ return 1;
+ }
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_pubrel:
+ chr = (int)(bit2int(msg.msg().pubrel().header().packetType()) << 4);
+ if(msg.msg().pubrel().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().pubrel().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().pubrel().header().remLength()).get_long_long_val();
+ //variable header
+ if(encodePacketIdentifier(stream, (int) msg.msg().pubrel().packet__identifier()) != 0){
+ return 1;
+ }
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_pubcomp:
+ chr = (int)(bit2int(msg.msg().pubcomp().header().packetType()) << 4);
+ if(msg.msg().pubcomp().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().pubcomp().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().pubcomp().header().remLength()).get_long_long_val();
+ //variable header
+ if(encodePacketIdentifier(stream, (int) msg.msg().pubcomp().packet__identifier()) != 0){
+ return 1;
+ }
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_subscribe:
+ chr = (int)(bit2int(msg.msg().subscribe().header().packetType()) << 4);
+ if(msg.msg().subscribe().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().subscribe().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().subscribe().header().remLength()).get_long_long_val();
+ //variable header
+ if(encodePacketIdentifier(stream, (int) msg.msg().subscribe().packet__identifier()) != 0){
+ return 1;
+ }
+ //payload
+ for(int i = 0; i < msg.msg().subscribe().payload().size_of(); i++){
+ if(encodeUtf8(stream, msg.msg().subscribe().payload()[i].topic__filter(), msg.msg().subscribe().payload()[i].filterLength()) != 0){
+ return 1;
+ }
+ chr = msg.msg().subscribe().payload()[i].requested__qos();
+ stream.put_c(chr);
+ }
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_suback:
+ chr = (int)(bit2int(msg.msg().suback().header().packetType()) << 4);
+ if(msg.msg().suback().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().suback().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().suback().header().remLength()).get_long_long_val();
+ //variable header
+ if(encodePacketIdentifier(stream, (int) msg.msg().suback().packet__identifier()) != 0){
+ return 1;
+ }
+ //payload
+ for(int i = 0; i < msg.msg().suback().payload().return__code().size_of(); i++){
+ if(msg.msg().suback().payload().return__code()[i] < 0 || 255 < msg.msg().suback().payload().return__code()[i]){
+ return 1;
+ }
+ chr = msg.msg().suback().payload().return__code()[i];
+ stream.put_c(chr);
+ }
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_unsubscribe:
+ chr = (int)(bit2int(msg.msg().unsubscribe().header().packetType()) << 4);
+ if(msg.msg().unsubscribe().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().unsubscribe().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().unsubscribe().header().remLength()).get_long_long_val();
+
+ //variable header
+ if(encodePacketIdentifier(stream, (int) msg.msg().unsubscribe().packet__identifier()) != 0){
+ return 1;
+ }
+ //payload
+ for(int i = 0; i < msg.msg().unsubscribe().payload().size_of(); i++){
+ if(encodeUtf8(stream, msg.msg().unsubscribe().payload()[i].topic__filter(), msg.msg().unsubscribe().payload()[i].filterLength()) != 0){
+ return 1;
+ }
+ }
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_unsuback:
+ chr = (int)(bit2int(msg.msg().unsuback().header().packetType()) << 4);
+ if(msg.msg().unsuback().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().unsuback().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().unsuback().header().remLength()).get_long_long_val();
+ //variable header
+ if(encodePacketIdentifier(stream, (int) msg.msg().unsuback().packet__identifier()) != 0){
+ return 1;
+ }
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_pingreq:
+ chr = (int)(bit2int(msg.msg().pingreq().header().packetType()) << 4);
+ if(msg.msg().pingreq().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().pingreq().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().pingreq().header().remLength()).get_long_long_val();
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_pingresp:
+ chr = (int)(bit2int(msg.msg().pingresp().header().packetType()) << 4);
+ if(msg.msg().pingresp().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().pingresp().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().pingresp().header().remLength()).get_long_long_val();
+ break;
+ case MQTT__v3__1__1__ReqResp::ALT_disconnect__msg:
+ chr = (int)(bit2int(msg.msg().disconnect__msg().header().packetType()) << 4);
+ if(msg.msg().disconnect__msg().header().flags().lengthof() == 4){
+ chr += encodeFlags(msg.msg().disconnect__msg().header().flags());
+ stream_beginning.put_c(chr);
+ }else{
+ return 1;
+ }
+ length = oct2int(msg.msg().disconnect__msg().header().remLength()).get_long_long_val();
+ break;
+ default:
+ return 1;
+ break;
+ }
+
+ TTCN_Logger::begin_event(TTCN_DEBUG);
+ TTCN_Logger::log_event("Encoded MQTT 3.1.1 message: ");
+ stream_beginning.log();
+ TTCN_Logger::end_event();
+ do{
+ unsigned char encodedByte = length % 128;
+ length /= 128;
+ if(length > 0){
+ encodedByte = encodedByte | 128;
+ }
+ stream_beginning.put_c(encodedByte);
+ }while(length > 0);
+ stream_beginning.put_buf(stream);
+ stream_beginning.get_string(str);
+
+ return 0;
+}
+
+unsigned int encodeFlags(BIT4n bits){
+ const unsigned char* chr;
+ const unsigned char lookup[16] = {
+ 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
+ 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf};
+
+ chr = (const unsigned char*) bits;
+ return lookup[chr[0]];
+}
+
+int encodePacketIdentifier(TTCN_Buffer &buffer, int identifier){
+ if(0 <= identifier && identifier <= 65535){
+ unsigned char chr;
+ chr = (identifier >> 8) & 255;
+ buffer.put_c(chr);
+ chr = identifier & 255;
+ buffer.put_c(chr);
+ return 0;
+ }else{
+ return 1;
+ }
+}
+
+int encodeUtf8(TTCN_Buffer &stream, const UNIVERSAL_CHARSTRING& str, const INTEGER& length){
+ if(0 <= length && length <= 65535){
+ unsigned char chr = (int)(length) >> 8;
+ stream.put_c(chr);
+ chr = (int)length;
+ stream.put_c(chr);
+ str.encode_utf8(stream, false);
+ return 0;
+ }else{
+ return 1;
+ }
+}
+
+int encodeOctetstring(TTCN_Buffer &stream, const OCTETSTRING& str, const INTEGER& length){
+ if(0 <= length && length <= 65535){
+ unsigned char chr = (int)(length) >> 8;
+ stream.put_c(chr);
+ chr = (int)length;
+ stream.put_c(chr);
+ stream.put_os(str);
+ return 0;
+ }else{
+ return 1;
+ }
+}
+
+int decodeInteger(const unsigned char* &str, const int position, const int length){
+ int value = 0;
+
+ for(int i = 0; i < length; i++){
+ value += (str[position+i] << (8 * (length-i-1)));
+ }
+ return value;
+}
+
+}
diff --git a/src/negative_testing/Mqtt_v3.1.1_Size.cc b/src/negative_testing/Mqtt_v3.1.1_Size.cc
new file mode 100644
index 0000000..6c53de3
--- /dev/null
+++ b/src/negative_testing/Mqtt_v3.1.1_Size.cc
@@ -0,0 +1,43 @@
+/******************************************************************************
+* Copyright (c) 2017 Easy Global Market
+* 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:
+* Spaseski Naum - initial implementation
+* Bence Janos Szabo - negative testing branch
+******************************************************************************/
+
+#include "Mqtt_v3_1_1_IPL4SizeFunction.hh"
+
+
+namespace Mqtt__v3__1__1__IPL4SizeFunction {
+
+INTEGER f__calc__MQTT__length(const OCTETSTRING& data){
+
+ int multiplier, value, i, j;
+ i = 0; // encoded byte
+ j = 2; // additional real size
+ multiplier = 1;
+ value = 0;
+ do {
+ i++;
+ value += (oct2int(data[i]) & 127) * multiplier + j;
+ multiplier *= 128;
+ if (multiplier > 128*128*128){
+ if(TTCN_Logger::log_this_event(LOG_ALL)){
+ TTCN_Logger::begin_event(LOG_ALL);
+ TTCN_Logger::log_event("Error: Wrong size of the message!");
+ TTCN_Logger::end_event();
+ }
+ return -1; //error case, bigger than the MQTT limit
+ }
+ j = 1;
+ }while((oct2int(data[i]) & 128) != 0);
+
+ return value;
+}
+
+}
diff --git a/src/negative_testing/Mqtt_v3.1.1_Types.ttcn b/src/negative_testing/Mqtt_v3.1.1_Types.ttcn
new file mode 100644
index 0000000..28cdcea
--- /dev/null
+++ b/src/negative_testing/Mqtt_v3.1.1_Types.ttcn
@@ -0,0 +1,343 @@
+/******************************************************************************
+* Copyright (c) 2016 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:
+* Mate Kovacs - initial implementation and initial documentation
+* Bence Janos Szabo - negative testing branch
+******************************************************************************/
+//
+// File: Mqtt_v3.1.1_Types.ttcn
+// Rev: R1A
+// Prodnr: CNL 113 831
+
+module MQTT_v3_1_1_Types
+{
+
+ // RAW encoding will produce a remLength of 4 bytes;
+ // this function reads this 4 bytes and encodes as
+ // it is written in the MQTT standard
+ function f_adjustLength(in octetstring p_os) return octetstring
+ {
+ // get the remLength from thr RAW encoded octetstring
+ var integer remLength := oct2int(substr(p_os, 1, 4));
+ var octetstring encodedRemLenght := ''O;
+ var integer encodedByte;
+
+ do {
+ encodedByte := remLength mod 128;
+ remLength := remLength / 128;
+ if (remLength > 0) {
+ encodedByte := bit2int(int2bit(encodedByte, 8) or4b '10000000'B);
+ }
+ encodedRemLenght := encodedRemLenght & int2oct(encodedByte, 1);
+ } while (remLength > 0 );
+
+ p_os := replace(p_os, 1, 4, encodedRemLenght);
+ return p_os
+ }
+
+
+
+function f_trimLength(in octetstring p_os) return octetstring
+{
+
+//decoding expects remLength of 4 bytes ; anything shorter will b4 completed to 4 bytes
+
+ var octetstring v_os:=''O;
+ var integer v_l:= lengthof(p_os) //unadjusted length
+
+ //X Y 0N--127N
+
+ if((v_l >=0+2) and (v_l<=127+2))//1 octet for length
+ {
+ v_os:= substr(p_os,0,1)&'000000'O&substr(p_os,1,v_l-1 )
+ }
+ else if ((v_l >= 128+2) and (v_l <=16383+2 )) //2 octets for length
+ {
+ v_os:= substr(p_os,0,1)&'0000'O&substr(p_os,1,v_l-1 )
+ }
+ else if ((v_l >= 16384+2) and (v_l <=2097151+2 ))//3 octets for length
+ {
+
+ v_os:= substr(p_os,0,1)&'00'O&substr(p_os,1,v_l-1 )
+ }
+
+ else if ((v_l >= 2097152+2) and (v_l <=268435455+2 ))//4 octets for length
+ {
+
+ v_os:=p_os
+ }
+
+ else {}
+
+ return v_os
+}
+
+ external function f_MQTT_v3_1_1_enc(in MQTT_v3_1_1_Message msg, out octetstring str) return integer;
+ external function f_MQTT_v3_1_1_dec(in octetstring str, out MQTT_v3_1_1_Message msg) return integer;
+
+ external function f_MQTT_enc(in MQTT_v3_1_1_Message msg) return octetstring
+ with { extension "prototype(convert) encode(RAW)" };
+
+ // RAW decoding does not work correctly.
+ external function f_MQTT_dec(in octetstring stream) return MQTT_v3_1_1_Message
+ with { extension "prototype(convert) decode(RAW)" };
+
+ function f_MQTT_decode(in octetstring msg) return MQTT_v3_1_1_Message
+ {
+ return f_MQTT_dec(f_trimLength(msg))
+ }
+
+ function f_MQTT_encode(in MQTT_v3_1_1_Message msg) return octetstring
+ {
+ return f_adjustLength(f_MQTT_enc(msg))
+ }
+
+
+ type octetstring OCT0_65535 length(0..65535);
+ type universal charstring UCHAR0_65535 length(0..65535) with { variant ""; };
+ type bitstring BIT1n length(1) with { variant "FIELDLENGTH(1),BITORDER(msb)"; };
+ type bitstring BIT4n length(4) with { variant "FIELDLENGTH(4)"; };
+ type octetstring OCT4 length(4) with { variant "FIELDLENGTH(4)"; };
+ type integer INT0_255 (0..255) with { variant "FIELDLENGTH(8)"; };
+ type integer INT_BIT16_MSB (0..65335) with { variant "FIELDLENGTH(16), BITORDER(msb)"; };
+
+ type record UTF8EncodedString
+ {
+ INT_BIT16_MSB stringLength,
+ UCHAR0_65535 stringItem
+ } with {
+ variant "FIELDORDER(msb)"
+ variant (stringLength) "BITORDERINFIELD(msb)" ;
+ variant (stringLength) "LENGTHTO(stringItem)" ;
+ }
+
+ type record OctStringWithLength
+ {
+ INT_BIT16_MSB stringLength,
+ OCT0_65535 stringItem
+ } with {
+ variant "FIELDORDER(msb)"
+ variant (stringLength) "BITORDERINFIELD(msb)" ;
+ variant (stringLength) "LENGTHTO(stringItem)" ;
+ }
+
+ type enumerated QoS
+ {
+ AT_MOST_ONCE_DELIVERY(0),
+ AT_LEAST_ONCE_DELIVERY(1),
+ EXACTLY_ONE_DELIVERY(2),
+ RESERVED(3)
+ } with { variant "FIELDLENGTH(2)"; }
+
+ type record Header
+ {
+ BIT4n packetType,
+ BIT4n flags,
+ OCT4 remLength
+ } with {
+ variant "FIELDORDER(msb)";
+ }
+
+ type record MQTT_v3_1_1_PublishHeader
+ {
+ BIT4n packetType,
+ BIT1n dup_flag,
+ QoS qos_level,
+ BIT1n retain_flag,
+ OCT4 remLength
+ } with { variant "FIELDORDER(msb)"; }
+
+ type record MQTT_v3_1_1_ConnectFlags
+ {
+ BIT1n user_name_flag,
+ BIT1n password_flag,
+ BIT1n will_retain,
+ QoS will_qos,
+ BIT1n will_flag,
+ BIT1n clean_session,
+ BIT1n reserved
+ } with { variant "FIELDORDER(msb)"; }
+
+ type record MQTT_v3_1_1_ConnectPayload
+ {
+ UTF8EncodedString client_identifier,
+ UTF8EncodedString will_topic optional,
+ OctStringWithLength will_message optional,
+ UTF8EncodedString user_name optional,
+ OctStringWithLength password optional
+ } with { variant "FIELDORDER(msb)"; }
+
+ type record MQTT_v3_1_1_Connect
+ {
+ Header header,
+ INT_BIT16_MSB nameLength,
+ UCHAR0_65535 name,
+ integer protocol_level (0..255),
+ MQTT_v3_1_1_ConnectFlags flags,
+ integer keep_alive (0..65535),
+ MQTT_v3_1_1_ConnectPayload payload
+ } with {
+ variant "FIELDORDER(msb)";
+ variant (nameLength) "BITORDERINFIELD(msb)";
+ variant (nameLength) "LENGTHTO(name)";
+ variant (protocol_level) "FIELDLENGTH(8)";
+ variant (keep_alive) "FIELDLENGTH(16)";
+ }
+
+ type record MQTT_v3_1_1_Connack
+ {
+ Header header,
+ BIT1n session_present_flag,
+ integer connect_return_code (0..255)
+ } with {
+ variant "FIELDORDER(msb)";
+ variant (session_present_flag) "BITORDERINFIELD(msb)" ;
+ variant (session_present_flag) "FIELDLENGTH(8)";
+ variant (connect_return_code) "BITORDERINFIELD(lsb)";
+ variant (connect_return_code) "FIELDLENGTH(8)";
+ }
+
+ type record MQTT_v3_1_1_Publish
+ {
+ MQTT_v3_1_1_PublishHeader header,
+ INT_BIT16_MSB nameLength,
+ UCHAR0_65535 topic_name,
+ integer packet_identifier (0..65535) optional,
+ octetstring payload
+ } with {
+ variant "FIELDORDER(msb)";
+ variant (packet_identifier) "BYTEORDER(last)" ;
+ variant (packet_identifier) "FIELDLENGTH(16)";
+ variant (nameLength) "BITORDERINFIELD(msb)" ;
+ variant (nameLength) "LENGTHTO(topic_name)";
+ }
+
+ type record MQTT_v3_1_1_Identifier
+ {
+ Header header,
+ integer packet_identifier (0..65535)
+ } with {
+ variant "FIELDORDER(msb)";
+ variant (header.remLength) "LENGTHTO(packet_identifier)" ;
+ variant (packet_identifier) "BYTEORDER(last)";
+ variant (packet_identifier) "FIELDLENGTH(16)";
+ }
+
+ type record MQTT_v3_1_1_SubscribePayload
+ {
+ INT_BIT16_MSB filterLength,
+ UCHAR0_65535 topic_filter,
+ QoS requested_qos
+ } with {
+ variant "FIELDORDER(msb)";
+ variant (filterLength) "BITORDERINFIELD(msb)" ;
+ variant (filterLength) "LENGTHTO(topic_filter)";
+ variant (requested_qos) "BITORDERINFIELD(msb)" ;
+ variant (requested_qos) "FIELDLENGTH(8)" ;
+ variant (requested_qos) "BITORDER(msb)" ;
+ }
+
+ type record of MQTT_v3_1_1_SubscribePayload MQTT_v3_1_1_SubscribePayloadList;
+
+ type record MQTT_v3_1_1_Subscribe
+ {
+ Header header,
+ integer packet_identifier (0..65535),
+ MQTT_v3_1_1_SubscribePayloadList payload
+ } with {
+ variant "FIELDORDER(msb)";
+ variant (packet_identifier) "BYTEORDER(last)";
+ variant (packet_identifier) "FIELDLENGTH(16)";
+ }
+
+ type record of INT0_255 IntegerList;
+
+ type record MQTT_v3_1_1_SubackPayload
+ {
+ IntegerList return_code
+ }
+
+ type record MQTT_v3_1_1_Suback
+ {
+ Header header,
+ integer packet_identifier (0..65535),
+ MQTT_v3_1_1_SubackPayload payload
+ } with {
+ variant "FIELDORDER(msb)";
+ variant (packet_identifier) "BYTEORDER(last)";
+ variant (packet_identifier) "FIELDLENGTH(16)";
+ }
+
+ type record MQTT_v3_1_1_UnsubscribePayload
+ {
+ INT_BIT16_MSB filterLength,
+ UCHAR0_65535 topic_filter
+ } with {
+ variant "FIELDORDER(msb)";
+ variant (filterLength) "BITORDERINFIELD(msb)" ;
+ variant (filterLength) "LENGTHTO(topic_filter)";
+ }
+
+ type record of MQTT_v3_1_1_UnsubscribePayload MQTT_v3_1_1_UnsubscribePayloadList
+
+ type record MQTT_v3_1_1_Unsubscribe
+ {
+ Header header,
+ integer packet_identifier (0..65535),
+ MQTT_v3_1_1_UnsubscribePayloadList payload
+ } with {
+ variant "FIELDORDER(msb)";
+ variant (packet_identifier) "BYTEORDER(last)";
+ variant (packet_identifier) "FIELDLENGTH(16)";
+ }
+
+ type record MQTT_v3_1_1_Empty
+ {
+ Header header
+ }
+
+ type union MQTT_v3_1_1_ReqResp
+ {
+ MQTT_v3_1_1_Connect connect_msg,
+ MQTT_v3_1_1_Connack connack,
+ MQTT_v3_1_1_Publish publish,
+ MQTT_v3_1_1_Identifier puback,
+ MQTT_v3_1_1_Identifier pubrec,
+ MQTT_v3_1_1_Identifier pubrel,
+ MQTT_v3_1_1_Identifier pubcomp,
+ MQTT_v3_1_1_Subscribe subscribe,
+ MQTT_v3_1_1_Suback suback,
+ MQTT_v3_1_1_Unsubscribe unsubscribe,
+ MQTT_v3_1_1_Identifier unsuback,
+ MQTT_v3_1_1_Empty pingreq,
+ MQTT_v3_1_1_Empty pingresp,
+ MQTT_v3_1_1_Empty disconnect_msg
+ } with { variant "TAG(
+ connect_msg, header.packetType = '0001'B;
+ connack, header.packetType = '0010'B;
+ publish, header.packetType = '0011'B;
+ puback, header.packetType = '0100'B;
+ pubrec, header.packetType = '0101'B;
+ pubrel, header.packetType = '0110'B;
+ pubcomp, header.packetType = '0111'B;
+ subscribe, header.packetType = '1000'B;
+ suback, header.packetType = '1001'B;
+ unsubscribe, header.packetType = '1010'B;
+ unsuback, header.packetType = '1011'B;
+ pingreq, header.packetType = '1100'B;
+ pingresp, header.packetType = '1101'B;
+ disconnect_msg, header.packetType = '1110'B; )"
+}
+
+ type union MQTT_v3_1_1_Message
+ {
+ MQTT_v3_1_1_ReqResp msg,
+ octetstring raw_message
+ } with { variant "" }
+
+} with { encode "RAW" }
diff --git a/src/negative_testing/Mqtt_v3_1_1_IPL4SizeFunction.ttcn b/src/negative_testing/Mqtt_v3_1_1_IPL4SizeFunction.ttcn
new file mode 100644
index 0000000..dae630a
--- /dev/null
+++ b/src/negative_testing/Mqtt_v3_1_1_IPL4SizeFunction.ttcn
@@ -0,0 +1,40 @@
+/******************************************************************************
+* Copyright (c) 2017 Easy Global Market
+* 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:
+* Spaseski Naum - initial implementation
+* Bence Janos Szabo - negative testing branch
+******************************************************************************/
+
+//*********************************************************************
+// To use this function with the IPL4 port, *
+// you should add these lines to your TTCN-3 code: *
+// *
+// var f_IPL4_getMsgLen getMsg_Func := refers(f_GetMsgLengthMQTT); *
+// f_IPL4_setGetMsgLen(IPL4_port,connectionId, getMsg_Func, {}); *
+//*********************************************************************
+
+module Mqtt_v3_1_1_IPL4SizeFunction{
+
+
+import from Socket_API_Definitions all;
+
+//-----------------------------------------------------------------------------
+//External functions
+//-----------------------------------------------------------------------------
+
+external function f_calc_MQTT_length(in octetstring data) return integer;
+
+
+//*************************************************************************
+function f_GetMsgLengthMQTT( in octetstring stream, inout ro_integer args) return integer
+//*************************************************************************
+
+{
+ return f_calc_MQTT_length(stream) ;
+}
+}
diff --git a/src/negative_testing/README b/src/negative_testing/README
new file mode 100644
index 0000000..0e9f89c
--- /dev/null
+++ b/src/negative_testing/README
@@ -0,0 +1,8 @@
+The MQTT protocol module was written initially with an external codec (see http://git.eclipse.org/c/titan/titan.ProtocolModules.MQTT.git/)
+
+The reason for this was that the variable length encoding of remLength cannot be directly handled by RAW alone; some external assistance is needed;
+A new protocol module has been written (based on the RAW codec), which can handle encoding directions. But for the decoding the external codec should be used.
+
+To enable more throughout fuzzing (negative testing) the TTCN-3 types were extended with fields that stores the length of fields of the length of payload, based on the MQTT standard.
+
+The RAW encoder cannot compute correctly the remLength field, but calling the f_adjustLength function on the result of the RAW encoding will produce the correct remLength and the correct message to be sent.
\ No newline at end of file