Repository: openschc/openschc (language: python)

Issue:
Mooc finalisé
Version for Coursera MOOC Nov 2024


Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 873f666e..5395f36f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -138,3 +138,4 @@ src/tests/__pycache__
 src/test_failed/__pycache__
 src/.pytest_cache
 src/tests/test_compress_main.py
+openschc.code-workspace
diff --git a/README.rst b/README.rst
index e6665a0b..9f4a4dff 100644
--- a/README.rst
+++ b/README.rst
@@ -1,5 +1,5 @@
 What is OpenSCHC ?
-==================
+===================
 
 OpenSCHC
 --------
diff --git a/examples/MOOC-1/ipv6.json b/examples/MOOC-1/ipv6.json
new file mode 100644
index 00000000..202a8994
--- /dev/null
+++ b/examples/MOOC-1/ipv6.json
@@ -0,0 +1,52 @@
+[{
+    "RuleIDValue" : 5,
+    "RuleIDLength": 3,
+    "Compression": [
+      {"FID": "IPV6.VER", 
+       "TV": 6, "MO": "equal",     
+       "CDA": "not-sent"},
+      {"FID": "IPV6.TC",  
+       "TV": 1, "MO": "equal",     
+       "CDA": "not-sent"},
+      {"FID": "IPV6.FL",  
+       "TV": 144470, "MO": "equal",
+       "CDA": "not-sent"},
+      {"FID": "IPV6.LEN",           
+       "MO": "ignore",   
+       "CDA": "compute-length"},
+      {"FID": "IPV6.NXT", 
+       "TV": 17, "MO": "equal",  
+       "CDA": "not-sent"},
+      {"FID": "IPV6.HOP_LMT",       
+       "MO": "ignore",   
+       "CDA": "value-sent"},
+      {"FID": "IPV6.DEV_PREFIX",
+       "TV": ["FE80::/64",
+             "2001:41D0:302:2200::/64"], "MO": "match-mapping",
+       "CDA": "mapping-sent"},
+      {"FID": "IPV6.DEV_IID", 
+       "TV": "::13b3", "MO": "equal",
+       "CDA": "not-sent"},
+      {"FID": "IPV6.APP_PREFIX",
+       "TV": ["2001:41d0:404:200::/64",
+              "FE80::/64"], "MO": "match-mapping",
+       "CDA": "mapping-sent"},
+      {"FID": "IPV6.APP_IID", 
+       "TV": 2,"MO": "equal",  
+       "CDA": "not-sent"},
+      {"FID": "UDP.DEV_PORT",         
+       "MO": "ignore", 
+       "CDA": "value-sent"},
+      {"FID": "UDP.APP_PORT",  
+       "TV": 5680,"MO": "MSB", 
+       "MO.VAL": 12, "CDA" : "LSB"},
+      {"FID": "UDP.LEN",       
+       "TV": 0,   
+       "MO": "ignore",
+       "CDA": "compute-length"},
+      {"FID": "UDP.CKSUM",     
+       "TV": 0, "MO": "ignore", 
+       "CDA": "compute-checksum"}
+      ]          
+  }
+]
diff --git a/examples/MOOC-1/pcap_coap.py b/examples/MOOC-1/pcap_coap.py
new file mode 100755
index 00000000..d47a937d
--- /dev/null
+++ b/examples/MOOC-1/pcap_coap.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+from scapy.all import *
+
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from compr_parser import Parser
+from gen_parameters import *
+from gen_rulemanager import RuleManager
+
+import pprint
+
+# rdpcap comes from scapy and loads in our pcap file
+packets = rdpcap('trace_coap.pcap')
+
+parser = Parser()
+
+RM = RuleManager()
+RM.Add(file="ipv6-sol-bi-fl.json")
+RM.Print()
+
+# Let's iterate through every packet
+for packet in packets:
+    hexdump(packet[IPv6])
+    packet[IPv6].show()
+
+    if packet[Ether].src == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_DW
+    elif packet[Ether].dst == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_UP
+    else: # skipping
+        break
+
+    print ("Packet direction ", direction)
+
+    parsed = parser.parse (bytes(packet[Raw]), 
+                           direction, 
+                           start="CoAP",
+                           layers=["CoAP"])
+    pprint.pprint (parsed)
+
+    if parsed[0] != None:
+        rule = RM.FindRuleFromPacket(pkt=parsed[0], 
+                                     direction=direction, 
+                                     failed_field=True)
+        
+        print ("Rule for packet")
+        pprint.pprint(rule)
+
diff --git a/examples/MOOC-1/pcap_compress.py b/examples/MOOC-1/pcap_compress.py
new file mode 100755
index 00000000..ed758e2e
--- /dev/null
+++ b/examples/MOOC-1/pcap_compress.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+from scapy.all import *
+
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from compr_parser import Parser
+from gen_parameters import *
+from gen_rulemanager import RuleManager
+from compr_core import Compressor
+
+import pprint
+
+# rdpcap comes from scapy and loads in our pcap file
+packets = rdpcap('trace_coap.pcap')
+
+parser = Parser()
+
+RM = RuleManager()
+RM.Add(file="ipv6-sol-bi-fl.json")
+RM.Print()
+
+compress = Compressor()
+
+# Let's iterate through every packet
+for packet in packets:
+    #hexdump(packet[IPv6])
+    #packet[IPv6].show()
+
+    if packet[Ether].src == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_DW
+    elif packet[Ether].dst == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_UP
+    else: # skipping
+        break
+
+    print ("Packet direction ", direction)
+
+    parsed = parser.parse (bytes(packet[IPv6]), 
+                           direction, 
+                           layers=["IPv6", "UDP"])
+    pprint.pprint (parsed)
+
+    if parsed[0] != None:
+        rule = RM.FindRuleFromPacket(pkt=parsed[0], 
+                                     direction=direction, 
+                                     failed_field=True)
+        
+        print ("Rule for packet")
+        pprint.pprint(rule)
+
+        if rule:
+            SCHC_pkt = compress.compress(rule=rule,
+                                         parsed_packet=parsed[0],
+                                         data= parsed[1],
+                                         direction=direction,
+                                         verbose=True)
+            
+            print("SCHC packet in hex")
+            SCHC_pkt.display()
+
+            print("SCHC packet in binary")
+            SCHC_pkt.display(format="bin")
+
+
+
diff --git a/examples/MOOC-1/pcap_decompress.py b/examples/MOOC-1/pcap_decompress.py
new file mode 100755
index 00000000..7b7d6826
--- /dev/null
+++ b/examples/MOOC-1/pcap_decompress.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+from scapy.all import *
+
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from compr_parser import Parser, Unparser
+from gen_parameters import *
+from gen_rulemanager import RuleManager
+from compr_core import Compressor, Decompressor
+
+import pprint
+import binascii
+
+# rdpcap comes from scapy and loads in our pcap file
+packets = rdpcap('trace_coap.pcap')
+
+parser = Parser()
+Unparser = Unparser()
+
+RM = RuleManager()
+RM.Add(file="ipv6-sol-bi-fl.json")
+RM.Print()
+
+compress = Compressor()
+decompress = Decompressor()
+
+def show_diff(s1, s2):
+    from termcolor import colored
+
+    if len(s1) != len(s2):
+        print("size is different")
+        return
+    
+    differ = False
+    for o, c in zip(s1, s2):
+        #print(o, c)
+        if o == c:
+            print(colored(chr(o), "green"), end="")
+        else:
+            print(colored(chr(o), "red"), end="")  
+            differ = True 
+    print()         
+    if differ:
+        print (s2.decode()) 
+
+
+# Let's iterate through every packet
+for packet in packets:
+    #hexdump(packet[IPv6])
+    #packet[IPv6].show()
+
+    if packet[Ether].src == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_DW
+    elif packet[Ether].dst == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_UP
+    else: # skipping
+        break
+
+    print ("Packet direction ", direction)
+
+    parsed = parser.parse (bytes(packet[IPv6]), 
+                           direction, 
+                           layers=["IPv6", "UDP"])
+    pprint.pprint (parsed)
+
+    if parsed[0] != None:
+        rule = RM.FindRuleFromPacket(pkt=parsed[0], 
+                                     direction=direction, 
+                                     failed_field=True)
+        
+        print ("Rule for packet")
+        pprint.pprint(rule)
+
+        if rule:
+            SCHC_pkt = compress.compress(rule=rule,
+                                         parsed_packet=parsed[0],
+                                         data= parsed[1],
+                                         direction=direction,
+                                         verbose=True)
+            
+            print("SCHC packet in hex")
+            SCHC_pkt.display()
+
+            print("SCHC packet in binary")
+            SCHC_pkt.display(format="bin")
+
+            field_description = decompress.decompress(rule=rule, 
+                                                  schc=SCHC_pkt, 
+                                                direction=direction)
+            print(field_description)
+            SCHC_pkt.display(format="bin")
+            data = SCHC_pkt.get_remaining_content()
+            print ("payload:", binascii.hexlify(data))
+
+            pkt = Unparser.unparse(header_d=field_description, 
+                                   data=data, 
+                                   direction=direction)
+
+            show_diff(binascii.hexlify(bytes(packet)[14:]), 
+                      binascii.hexlify(bytes(pkt)))
+                      
+ 
+
diff --git a/examples/MOOC-1/pcap_match.py b/examples/MOOC-1/pcap_match.py
new file mode 100755
index 00000000..2bd50648
--- /dev/null
+++ b/examples/MOOC-1/pcap_match.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+from scapy.all import *
+
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from compr_parser import Parser
+from gen_parameters import *
+from gen_rulemanager import RuleManager
+
+import pprint
+
+# rdpcap comes from scapy and loads in our pcap file
+packets = rdpcap('trace_coap.pcap')
+
+parser = Parser()
+
+RM = RuleManager()
+RM.Add(file="ipv6-sol-bi-fl.json")
+RM.Print()
+
+# Let's iterate through every packet
+for packet in packets:
+    #hexdump(packet[IPv6])
+    #packet[IPv6].show()
+
+    if packet[Ether].src == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_DW
+    elif packet[Ether].dst == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_UP
+    else: # skipping
+        break
+
+    print ("Packet direction ", direction)
+
+    parsed = parser.parse (bytes(packet[IPv6]), 
+                           direction, 
+                           layers=["IPv6", "UDP"])
+    pprint.pprint (parsed)
+
+    if parsed[0] != None:
+        rule = RM.FindRuleFromPacket(pkt=parsed[0], 
+                                     direction=direction, 
+                                     failed_field=True)
+        
+        print ("Rule for packet")
+        pprint.pprint(rule)
+
diff --git a/examples/MOOC-1/pcap_parse.py b/examples/MOOC-1/pcap_parse.py
new file mode 100755
index 00000000..cb0502dc
--- /dev/null
+++ b/examples/MOOC-1/pcap_parse.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+from scapy.all import *
+
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from compr_parser import Parser
+from gen_parameters import *
+
+import pprint
+
+# rdpcap comes from scapy and loads in our pcap file
+packets = rdpcap('trace_coap.pcap')
+
+parser = Parser()
+
+# Let's iterate through every packet
+for packet in packets:
+    hexdump(packet[IPv6])
+    packet[IPv6].show()
+
+    if packet[Ether].src == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_DW
+    elif packet[Ether].dst == "fa:16:3e:1e:cc:2c":
+        direction = T_DIR_UP
+    else: # skipping
+        break
+
+    print ("Packet direction ", direction)
+
+    parsed = parser.parse (bytes(packet[IPv6]), 
+                           direction, 
+                           layers=["IPv6", "UDP"])
+    pprint.pprint (parsed)
+
diff --git a/examples/MOOC-1/pcap_read.py b/examples/MOOC-1/pcap_read.py
new file mode 100644
index 00000000..485def7a
--- /dev/null
+++ b/examples/MOOC-1/pcap_read.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python3
+from scapy.all import *
+
+# rdpcap comes from scapy and loads in our pcap file
+packets = rdpcap('trace_coap.pcap')
+
+for packet in packets:
+    packet.show()
+
+    hexdump(packet)
+
+    print ("="*40)
\ No newline at end of file
diff --git a/examples/MOOC-1/rm1.py b/examples/MOOC-1/rm1.py
new file mode 100644
index 00000000..098062df
--- /dev/null
+++ b/examples/MOOC-1/rm1.py
@@ -0,0 +1,27 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from gen_rulemanager import *
+
+RM = RuleManager()
+
+rule1100 =   {
+  "RuleID" : 12,
+  "RuleIDLength" : 4,
+  "Compression" : []
+}
+
+rule001100 =   {
+  "RuleID" : 12,
+  "RuleIDLength" : 6,
+  "Fragmentation" :  {
+    "FRMode" : "NoAck",
+    "FRDirection" : "UP"
+  }
+}
+
+RM.Add(dev_info=rule1100)
+RM.Add(dev_info=rule001100)
+
+RM.Print()
diff --git a/examples/MOOC-1/rm2.py b/examples/MOOC-1/rm2.py
new file mode 100644
index 00000000..a7012a31
--- /dev/null
+++ b/examples/MOOC-1/rm2.py
@@ -0,0 +1,26 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from gen_rulemanager import *
+
+RM = RuleManager()
+
+rule1100 =   {
+ "RuleID" : 12,
+ "RuleIDLength" : 4,
+ "Compression" : []
+}
+
+rule001100 =   {
+ "RuleID" : 12,
+ "RuleIDLength" : 6,
+ "Fragmentation" : {
+   "FRMode": "NoAck",
+   "FRDirection" : "UP"
+ }
+}
+
+RM.Add(dev_info=[rule1100, rule001100])
+
+RM.Print()
diff --git a/examples/MOOC-1/trace_coap.pcap b/examples/MOOC-1/trace_coap.pcap
new file mode 100644
index 00000000..78502234
Binary files /dev/null and b/examples/MOOC-1/trace_coap.pcap differ
diff --git a/examples/MOOC-2/icmp-bi.json b/examples/MOOC-2/icmp-bi.json
new file mode 100644
index 00000000..2e11d19b
--- /dev/null
+++ b/examples/MOOC-2/icmp-bi.json
@@ -0,0 +1,30 @@
+ {
+    "DeviceID" : "udp:10.0.0.20:8888",
+    "SoR" : [  
+	 {
+	    "RuleID": 6,
+	    "RuleIDLength": 3,
+	    "Compression": [
+		{"FID": "IPV6.VER", "TV": 6, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.TC",  "TV": 0, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.FL",  "TV": 0, "MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.LEN",          "MO": "ignore","CDA": "compute-length"},
+		{"FID": "IPV6.NXT", "TV": 58, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.HOP_LMT", "TV" : 255,"MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_PREFIX","TV": "AAAA::/64",
+                                               "MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_IID", "TV": "::1","MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.APP_PREFIX",         "MO": "ignore","CDA": "value-sent"},
+		{"FID": "IPV6.APP_IID",            "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.TYPE",  "TV": 128, "DI" : "DW", "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.TYPE",  "TV": 129, "DI" : "UP", "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CODE",  "TV": 0,   "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CKSUM", "TV": 0,   "MO": "ignore","CDA": "compute-checksum"},
+		{"FID": "ICMPV6.IDENT", "TV": 0,   "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.SEQNO", "TV": 0,   "MO": "ignore", "CDA": "value-sent"},
+		{"FID": "ICMPV6.PAYLOAD", "TV": 0,"MO": "ignore","CDA": "value-sent"}
+	    ]
+	 }
+    ]
+  }
+
diff --git a/examples/MOOC-2/icmp-single.json b/examples/MOOC-2/icmp-single.json
new file mode 100644
index 00000000..4d3c4bfd
--- /dev/null
+++ b/examples/MOOC-2/icmp-single.json
@@ -0,0 +1,31 @@
+ {
+    "DeviceID" : "udp:10.0.0.20:8888",
+    "SoR" : [  
+	 {
+	    "RuleID": 6,
+	    "RuleIDLength": 3,
+	    "Compression": [
+		{"FID": "IPV6.VER", "TV": 6, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.TC",  "TV": 0, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.FL",  "TV": 0, "MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.LEN",          "MO": "ignore","CDA": "compute-length"},
+		{"FID": "IPV6.NXT", "TV": 58, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.HOP_LMT", "TV" : 255,"MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_PREFIX","TV": "AAAA::/64",
+                                               "MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_IID", "TV": "::1","MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.APP_PREFIX","TV": "2001:0:0:1::/64",
+                                               "MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.APP_IID", "TV": "::15","MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.TYPE",  "TV": 128, "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CODE",  "TV": 0,   "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CKSUM", "TV": 0,   "MO": "ignore","CDA": "compute-checksum"},
+		{"FID": "ICMPV6.IDENT", "TV": 0,   "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.SEQNO", "TV": 0,   "MO": "MSB", "MO.VAL" : 12,
+                                                "CDA": "LSB"},
+		{"FID": "ICMPV6.PAYLOAD", "TV": 0,"MO": "ignore","CDA": "value-sent"}
+	    ]
+	 }
+    ]
+  }
+
diff --git a/examples/MOOC-2/icmp.json b/examples/MOOC-2/icmp.json
new file mode 100644
index 00000000..5174b0a3
--- /dev/null
+++ b/examples/MOOC-2/icmp.json
@@ -0,0 +1,29 @@
+ {
+    "DeviceID" : "udp:10.0.0.20:8888",
+    "SoR" : [  
+	 {
+	    "RuleID": 6,
+	    "RuleIDLength": 3,
+	    "Compression": [
+		{"FID": "IPV6.VER", "TV": 6, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.TC",  "TV": 0, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.FL",  "TV": 0, "MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.LEN",          "MO": "ignore","CDA": "compute-length"},
+		{"FID": "IPV6.NXT", "TV": 58, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.HOP_LMT", "TV" : 255,"MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_PREFIX","TV": "AAAA::/64",
+                                               "MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_IID", "TV": "::1","MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.APP_PREFIX",         "MO": "ignore","CDA": "value-sent"},
+		{"FID": "IPV6.APP_IID",            "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.TYPE",  "TV": 128, "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CODE",  "TV": 0,   "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CKSUM", "TV": 0,   "MO": "ignore","CDA": "compute-checksum"},
+		{"FID": "ICMPV6.IDENT", "TV": 0,   "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.SEQNO", "TV": 0,   "MO": "ignore", "CDA": "value-sent"},
+		{"FID": "ICMPV6.PAYLOAD", "TV": 0,"MO": "ignore","CDA": "value-sent"}
+	    ]
+	 }
+    ]
+  }
+
diff --git a/examples/MOOC-2/ping_core.py b/examples/MOOC-2/ping_core.py
new file mode 100644
index 00000000..178cfe16
--- /dev/null
+++ b/examples/MOOC-2/ping_core.py
@@ -0,0 +1,40 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from scapy.all import *
+
+import gen_rulemanager as RM
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_CORE
+
+# Create a Rule Manager and upload the rules.
+
+rm = RM.RuleManager()
+rm.Add(file="icmp.json")
+rm.Print()
+
+def processPkt(pkt):
+
+    scheduler.run(session=schc_machine)
+
+    if pkt.getlayer(Ether) != None: 
+        e_type = pkt.getlayer(Ether).type
+        if e_type == 0x86dd:
+            schc_machine.schc_send(bytes(pkt)[14:], verbose=True)
+
+
+# Start SCHC Machine
+POSITION = T_POSITION_CORE
+
+schc_machine = SCHCProtocol(role=POSITION)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+
+
+sniff(prn=processPkt, iface="eth1") 
+
+
+
+
+ 
diff --git a/examples/MOOC-2/ping_core1.py b/examples/MOOC-2/ping_core1.py
new file mode 100644
index 00000000..66a7492d
--- /dev/null
+++ b/examples/MOOC-2/ping_core1.py
@@ -0,0 +1,51 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from scapy.all import *
+
+import gen_rulemanager as RM
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_CORE
+
+# Create a Rule Manager and upload the rules.
+
+rm = RM.RuleManager()
+rm.Add(file="icmp-bi.json")
+rm.Print()
+
+def processPkt(pkt):
+
+    scheduler.run(session=schc_machine)
+
+    if pkt.getlayer(Ether) != None: 
+        e_type = pkt.getlayer(Ether).type
+        if e_type == 0x86dd:
+            schc_machine.schc_send(bytes(pkt)[14:])
+        elif e_type == 0x0800:
+            if pkt[IP].proto == 17 and pkt[UDP].dport == 0x5C4C:
+                # got a packet in the socket
+                SCHC_pkt, device = tunnel.recvfrom(1000)
+
+                other_end = 'udp:'+device[0]+':'+str(device[1])
+
+                origin, full_packet = schc_machine.schc_recv(
+                                   schc_packet=SCHC_pkt, 
+                                   device_id=other_end, 
+                                   iface='eth1',
+                                   verbose=True)
+
+# Start SCHC Machine
+POSITION = T_POSITION_CORE
+
+schc_machine = SCHCProtocol(role=POSITION)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+tunnel = schc_machine.get_tunnel()
+
+sniff(prn=processPkt, iface=["eth0", "eth1", "lo"]) 
+
+
+
+
+ 
diff --git a/examples/MOOC-2/ping_dev.py b/examples/MOOC-2/ping_dev.py
new file mode 100644
index 00000000..a93f7d0a
--- /dev/null
+++ b/examples/MOOC-2/ping_dev.py
@@ -0,0 +1,46 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+import gen_rulemanager as RM
+from gen_parameters import *
+
+
+rm = RM.RuleManager()
+rm.Add(file="icmp-bi.json")
+rm.Print()
+
+import socket
+import binascii
+import netifaces as ni
+
+addr = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
+
+PORT = 8888
+deviceID = "udp:"+addr+":"+str(PORT)
+
+print("device ID is", deviceID)
+
+tunnel = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+tunnel.bind (("0.0.0.0", PORT)) # same port as in the DeviceID
+
+while True:
+    SCHC_pkt, sender = tunnel.recvfrom(1000)
+    print ("SCHC Packet:", binascii.hexlify(SCHC_pkt), 
+                          "from", sender)
+    rule = rm.FindRuleFromSCHCpacket(schc=SCHC_pkt, device=deviceID)
+    if rule: # Echo Request Rule
+        print ("Rule {}/{}".format(rule[T_RULEID],
+                                   rule[T_RULEIDLENGTH]))
+        if rule[T_RULEID] == 6 and rule[T_RULEIDLENGTH] == 3:
+            tunnel.sendto(SCHC_pkt, sender)
+        else:
+            print ("Not the Echo Request rule")
+    else:
+        print ("rule not found")
+
+
+
+
+
+
+ 
diff --git a/examples/MOOC-2/ping_packet_descr.py b/examples/MOOC-2/ping_packet_descr.py
new file mode 100644
index 00000000..9b15dd79
--- /dev/null
+++ b/examples/MOOC-2/ping_packet_descr.py
@@ -0,0 +1,19 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+from compr_parser import Parser
+from gen_parameters import *
+
+from scapy.all import *
+
+
+import pprint
+
+P = Parser()
+
+def processPkt(pkt):
+     if pkt[Ether].type == 0x86dd and pkt[IPv6].nh == 0x3A: #ICMPv6
+        pkt_desc = P.parse(pkt=bytes(pkt)[14:], direction=T_DIR_DW)
+        pprint.pprint(pkt_desc)
+
+sniff(prn=processPkt, iface=["eth1", "lo"]) 
diff --git a/examples/MOOC-2/ping_packet_rule.py b/examples/MOOC-2/ping_packet_rule.py
new file mode 100644
index 00000000..854b7fce
--- /dev/null
+++ b/examples/MOOC-2/ping_packet_rule.py
@@ -0,0 +1,24 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+from compr_parser import Parser
+from gen_rulemanager import RuleManager
+from gen_parameters import *
+
+from scapy.all import *
+
+import pprint
+
+P = Parser()
+RM = RuleManager()
+RM.Add(file="icmp-single.json")
+RM.Print()
+
+def processPkt(pkt):
+     if pkt[Ether].type == 0x86dd and pkt[IPv6].nh == 0x3A: #ICMPv6
+        pkt_desc = P.parse(pkt=bytes(pkt)[14:], direction=T_DIR_DW)
+        if pkt_desc[2] is None: # No parsing error
+            rule = RM.FindRuleFromPacket(pkt_desc[0], T_DIR_DW, True)
+            print (rule)
+
+sniff(prn=processPkt, iface=["eth1", "lo"]) 
diff --git a/examples/MOOC-3/coap-server.py b/examples/MOOC-3/coap-server.py
new file mode 100755
index 00000000..2edcb675
--- /dev/null
+++ b/examples/MOOC-3/coap-server.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+
+# This file is part of the Python aiocoap library project.
+#
+# Copyright (c) 2012-2014 Maciej Wasilak <http://sixpinetrees.blogspot.com/>,
+#               2013-2014 Christian Amsüss <c.amsuess@energyharvesting.at>
+#
+# aiocoap is free software, this file is published under the MIT license as
+# described in the accompanying LICENSE file.
+
+"""This is a usage example of aiocoap that demonstrates how to implement a
+simple server. See the "Usage Examples" section in the aiocoap documentation
+for some more information."""
+
+""" This program receives POST from devices, direclty from Wi-Fi and through
+generic_coap_relay.py for LPWAN devices.
+
+It takes a CBOR coded Time Series and trandform it on a JSON structure for
+beebotte to display graphs. beebotte credentials are stored un config_bbt.py 
+file.
+"""
+
+import logging
+import binascii
+import asyncio
+
+import aiocoap.resource as resource
+import aiocoap
+
+import cbor2 as cbor
+
+
+# Class to process data posted on /temperature.
+        
+class sensor_reading(resource.Resource):
+    async def render_post(self, request):
+
+        print ("Request URI:", request.get_request_uri())
+        print ("Content-format:", request.opt.content_format)
+        print ("Payload:", binascii.hexlify(request.payload))
+ 
+        return aiocoap.Message(code=aiocoap.CHANGED)
+
+# logging setup
+
+logging.basicConfig(level=logging.INFO)
+#logging.getLogger("coap-server").setLevel(logging.DEBUG)
+
+def main():
+    # Resource tree creation
+    root = resource.Site()
+
+    # add resource processing, /proxy is not used here, see comments in generic_sensor()
+    root.add_resource(['temp'], sensor_reading())
+    #root.add_resource(['pres'], sensor_reading())
+    root.add_resource(['humi'], sensor_reading())
+    
+    # associate resource tree and socket
+    asyncio.Task(aiocoap.Context.create_server_context(root))
+
+    # let's go forever
+    asyncio.get_event_loop().run_forever()
+
+if __name__ == "__main__":
+    main()
diff --git a/examples/MOOC-3/coap.json b/examples/MOOC-3/coap.json
new file mode 100644
index 00000000..bfdfe65e
--- /dev/null
+++ b/examples/MOOC-3/coap.json
@@ -0,0 +1,37 @@
+ {
+    "DeviceID" : "udp:10.0.0.20:8888",
+    "SoR" : [  
+	 {
+	    "RuleID": 0,
+	    "RuleIDLength": 1,
+        "Description" : "GET/POST and correct answer from the device",
+	    "Compression": [
+            {"FID": "COAP.VER", "TV": 1,                   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.TYPE","TV": 0,      "DI": "DW",  "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.TYPE","TV": 2,      "DI": "UP",  "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.TKL", "TV": 0,                   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.CODE","TV": [1, 2], "DI": "DW",  "MO": "match-mapping","CDA": "mapping-sent"},
+            {"FID": "COAP.CODE","TV": [65, 67], "DI": "UP","MO": "match-mapping","CDA": "mapping-sent"},
+            {"FID": "COAP.MID", "TV": 0,                   "MO": "MSB", "MO.VAL": 15, "CDA": "LSB"},
+            {"FID": "COAP.Uri-Path", "FL": "var", "FP": 1, "DI": "DW", "TV": ["foo1", "foo2", "foo3", "foo4"]
+                                                            ,"MO": "match-mapping","CDA": "mapping-sent"},
+
+            {"FID": "COAP.Accept",  "DI": "DW", "TV": 30, "MO": "equal", "CDA": "not-sent"}
+            {"FID": "COAP.Content-Format", "DI": "UP", "TV": 30, "MO": "equal", "CDA": "not-sent"}
+      
+	    ]
+	 },	 {
+	    "RuleID": 7,
+	    "RuleIDLength": 3,
+        "Description" : "Error messages: RST and NOT Found",
+	    "Compression": [
+            {"FID": "COAP.VER", "TV": 1,                   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.TYPE","TV": [2,3],      "DI": "UP",  "MO": "match-mapping","CDA": "mapping-sent"},
+            {"FID": "COAP.TKL", "TV": 0,                   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.CODE","TV": [0, 132],   "DI": "UP",  "MO": "match-mapping","CDA": "mapping-sent"},
+            {"FID": "COAP.MID", "TV": 0,                   "MO": "MSB", "MO.VAL": 15, "CDA": "LSB"},
+	    ]
+	 }
+    ]
+  }
+
diff --git a/examples/MOOC-3/core.py b/examples/MOOC-3/core.py
new file mode 100644
index 00000000..c184bc84
--- /dev/null
+++ b/examples/MOOC-3/core.py
@@ -0,0 +1,54 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from scapy.all import *
+
+import gen_rulemanager as RM
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_CORE
+import binascii
+
+# Create a Rule Manager and upload the rules.
+
+rm = RM.RuleManager()
+rm.Add(file="lpwan.json")
+rm.Print()
+
+def processPkt(pkt):
+
+    scheduler.run(session=schc_machine)
+
+    if pkt.getlayer(Ether) != None: 
+        e_type = pkt.getlayer(Ether).type
+        if e_type == 0x86dd and pkt[IPv6].nh == 17: # just UDP
+            print ("<----", "downlink traffic")
+            hexdump(pkt)
+            schc_machine.schc_send(bytes(pkt)[14:], verbose=False)
+        elif e_type == 0x0800:
+            if pkt[IP].proto == 17 and pkt[UDP].dport == 0x5C4C:
+                # got a packet in the socket
+                SCHC_pkt, device = tunnel.recvfrom(1000)
+
+                other_end = 'udp:'+device[0]+':'+str(device[1])
+                print ("from:", other_end, binascii.hexlify(SCHC_pkt))
+                origin, full_packet = schc_machine.schc_recv(
+                                   schc_packet=SCHC_pkt, 
+                                   device_id=other_end, 
+                                   iface='eth1',
+                                   verbose=True)
+
+# Start SCHC Machine
+POSITION = T_POSITION_CORE
+
+schc_machine = SCHCProtocol(role=POSITION)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+tunnel = schc_machine.get_tunnel()
+
+sniff(prn=processPkt, iface=["eth0", "eth1", "lo"]) 
+
+
+
+
+ 
diff --git a/examples/MOOC-3/dev-lpwan.py b/examples/MOOC-3/dev-lpwan.py
new file mode 100644
index 00000000..95588937
--- /dev/null
+++ b/examples/MOOC-3/dev-lpwan.py
@@ -0,0 +1,116 @@
+import socket
+import select
+import cbor2 as cbor
+import random
+import time
+import struct
+import binascii
+
+import pprint
+
+CORE_SCHC = ("10.0.0.21", 0x5C4C)
+MID_LENGTH=3
+KNOWN_URI = ["temp", "humi", "pres"]
+
+MID = 1
+
+tunnel = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+tunnel.bind(("0.0.0.0", 8888))
+
+def coap_send_measurement(value, uri):
+    global MID
+
+    if uri not in KNOWN_URI:
+        print("unknown URI", uri)
+        return None
+    
+    if type(value) is not bytes: # not cbor
+        value = cbor.dumps(value)
+
+    uri_idx = KNOWN_URI.index(uri)
+    print ("MID", MID, "URI", uri,  
+            "(index:", uri_idx, ")", 
+            "value", binascii.hexlify(value) )
+
+    schc_residue = (0x00 & 0b0000_0111) << 5 | \
+                   (MID & 0b0000_0111) << 2 | \
+                   (uri_idx) & 0b0000_0011
+    
+    if MID == 0b0000_0111:
+        MID = 1
+    else:
+        MID += 1
+    
+    schc_pkt = struct.pack("!B", schc_residue) + value
+    print ("sending:", binascii.hexlify(schc_pkt))
+    tunnel.sendto(schc_pkt, CORE_SCHC)
+
+def wait_ack():
+    # wait a SCHC pkt for 1 second
+    readable, _, _ = select.select ([tunnel], [], [], 1)
+    if len(readable) == 1: # A message
+        msg = tunnel.recv(1000)
+        if msg == b"\xff": # ruleID 255/8 = server error
+            print ("Rule 255/8: Server Error")
+            return True
+        
+    return False
+
+class sensor():
+    def __init__ (self, uri, period, init_value, evolution):
+        self.uri = uri
+        self.period = period
+        self.current_value = init_value
+        self.evolution=evolution
+
+    def get_uri(self):
+        return self.uri
+    
+    def get_period(self):
+        return self.period
+
+    def get_value(self):
+        self.current_value += random.randint(-self.evolution, 
+                                             +self.evolution)
+        return self.current_value
+    
+    def __str__(self):
+        return "sensor "+self.uri
+    
+    def __repr__(self):
+        return "sensor "+self.uri
+
+
+temperature = sensor("temp", 60, 20, 1)
+humidity    = sensor("humi", 120, 50, 5)
+pressure    = sensor("pres", 90, 1000, 10)
+
+start_time = int(time.time())
+
+event_queue = [(temperature, start_time+1), 
+               (humidity, start_time+40), 
+               (pressure, start_time+30)]
+
+
+while True:
+    # sort event queue on expiration time
+    event_queue.sort(key=lambda x: x[1]) 
+
+    #sleep until next event expiration
+    next_event = event_queue.pop(0)
+    wait_time = next_event[1] - int(time.time())
+    print ("sleeping", wait_time, "sec.")
+    if wait_time > 0: # oops we are late
+        time.sleep(wait_time)
+
+    sensor = next_event[0]
+    coap_send_measurement(sensor.get_value(), sensor.get_uri())
+
+    if not wait_ack():
+        event_queue.append((sensor, int(time.time() + \
+                                        sensor.get_period())))
+    else:
+        print ("Long sleep for", sensor.uri)
+        event_queue.append((sensor, int(time.time() + 300)))
+
+
diff --git a/examples/MOOC-3/lpwan.json b/examples/MOOC-3/lpwan.json
new file mode 100644
index 00000000..fbcc9372
--- /dev/null
+++ b/examples/MOOC-3/lpwan.json
@@ -0,0 +1,66 @@
+{
+    "DeviceID" : "udp:10.0.0.20:8888",
+    "SoR" : [{
+        "RuleIDValue" : 0,
+        "RuleIDLength": 3,
+        "Compression": [	 
+            {"FID": "IPV6.VER", "TV": 6, "MO": "equal", "CDA": "not-sent"},
+            {"FID": "IPV6.TC",  "TV": 0, "MO": "equal", "CDA": "not-sent"},
+            {"FID": "IPV6.FL",  "TV": 0, "MO": "ignore","CDA": "not-sent"},
+            {"FID": "IPV6.LEN",          "MO": "ignore","CDA": "compute-length"},
+            {"FID": "IPV6.NXT", "TV": 17, "MO": "equal", "CDA": "not-sent"},
+            {"FID": "IPV6.HOP_LMT", "TV" : 255,"MO": "ignore","CDA": "not-sent"},
+            {"FID": "IPV6.DEV_PREFIX","TV": "AAAA::/64",
+                                                "MO": "equal","CDA": "not-sent"},
+            {"FID": "IPV6.DEV_IID", "TV": "::1","MO": "equal","CDA": "not-sent"},
+            {"FID": "IPV6.APP_PREFIX", "TV": "2001:0:0:1::/64",
+                                                "MO": "equal","CDA": "not-sent"},
+            {"FID": "IPV6.APP_IID", "TV": "::15",
+                                            "MO": "equal","CDA": "not-sent"},
+
+            {"FID": "UDP.DEV_PORT",  "TV": 5388,"MO": "equal",  "CDA": "not-sent"},
+            {"FID": "UDP.APP_PORT",  "TV": 5683,"MO": "equal",  "CDA": "not-sent"},
+            {"FID": "UDP.LEN",       "TV": 0,   "MO": "ignore", "CDA": "compute-length"},
+            {"FID": "UDP.CKSUM",     "TV": 0,   "MO": "ignore", "CDA": "compute-checksum"},
+
+            {"FID": "COAP.VER",  "DI": "BI", "TV": 1,   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.TYPE", "DI": "BI", "TV": 1,   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.TKL",  "DI": "BI", "TV": 0,   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.CODE", "DI": "BI", "TV": 2,   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.MID",  "DI": "BI", "TV": 0,               "MO": "MSB", "MO.VAL": 13, "CDA": "LSB"},
+            {"FID": "COAP.Uri-Path", "FP": 1, "DI": "UP", 
+                                "TV": ["temp", "humi", "pres"], 
+                                "MO": "match-mapping","CDA": "mapping-sent"},
+            {"FID": "COAP.Content-Format", "DI": "UP", "TV": 30, "MO": "equal", "CDA": "not-sent"},        
+            {"FID": "COAP.No-Response",     "DI": "UP", "TV": 2, "MO": "equal", "CDA": "not-sent"}        
+        ]},
+        {
+            "RuleIDValue" : 255,
+            "RuleIDLength": 8,
+            "Compression": [	 
+                {"FID": "IPV6.VER", "TV": 6, "MO": "equal", "CDA": "not-sent"},
+                {"FID": "IPV6.TC",  "TV": 0, "MO": "equal", "CDA": "not-sent"},
+                {"FID": "IPV6.FL",  "TV": 0, "MO": "ignore","CDA": "not-sent"},
+                {"FID": "IPV6.LEN",          "MO": "ignore","CDA": "compute-length"},
+                {"FID": "IPV6.NXT", "TV": 17, "MO": "equal", "CDA": "not-sent"},
+                {"FID": "IPV6.HOP_LMT", "TV" : 255,"MO": "ignore","CDA": "not-sent"},
+                {"FID": "IPV6.DEV_PREFIX","TV": "AAAA::/64",
+                                                    "MO": "equal","CDA": "not-sent"},
+                {"FID": "IPV6.DEV_IID", "TV": "::1","MO": "equal","CDA": "not-sent"},
+                {"FID": "IPV6.APP_PREFIX", "TV": "2001:0:0:1::/64",
+                                                    "MO": "equal","CDA": "not-sent"},
+                {"FID": "IPV6.APP_IID", "TV": "::15",
+                                                "MO": "equal","CDA": "not-sent"},
+    
+                {"FID": "UDP.DEV_PORT",  "TV": 5388,"MO": "equal",  "CDA": "not-sent"},
+                {"FID": "UDP.APP_PORT",  "TV": 5683,"MO": "equal",  "CDA": "not-sent"},
+                {"FID": "UDP.LEN",       "TV": 0,   "MO": "ignore", "CDA": "compute-length"},
+                {"FID": "UDP.CKSUM",     "TV": 0,   "MO": "ignore", "CDA": "compute-checksum"},
+                {"FID": "COAP.VER",  "DI": "DW", "TV": 1,   "MO": "equal","CDA": "not-sent"},
+                {"FID": "COAP.TYPE", "DI": "DW", "TV": 1,   "MO": "equal","CDA": "not-sent"},
+                {"FID": "COAP.TKL",  "DI": "DW", "TV": 0,   "MO": "equal","CDA": "not-sent"},
+                {"FID": "COAP.CODE", "DI": "DW", "TV": 132,   "MO": "equal","CDA": "not-sent"},
+                {"FID": "COAP.MID",  "DI": "DW", "TV": 0,   "MO": "ignore","CDA": "not-sent"}     
+            ]}
+    ]
+}
diff --git a/examples/MOOC-3/server.py b/examples/MOOC-3/server.py
new file mode 100755
index 00000000..ae89c9c1
--- /dev/null
+++ b/examples/MOOC-3/server.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+
+# SPDX-FileCopyrightText: Christian Amsüss and the aiocoap contributors
+#
+# SPDX-License-Identifier: MIT
+
+"""This is a usage example of aiocoap that demonstrates how to implement a
+simple server. See the "Usage Examples" section in the aiocoap documentation
+for some more information."""
+
+import datetime
+import logging
+
+import asyncio
+
+import aiocoap.resource as resource
+from aiocoap.numbers.contentformat import ContentFormat
+import aiocoap
+
+class Welcome(resource.Resource):
+    representations = {
+            ContentFormat.TEXT: b"Welcome to the demo server",
+            ContentFormat.LINKFORMAT: b"</.well-known/core>,ct=40",
+            # ad-hoc for application/xhtml+xml;charset=utf-8
+            ContentFormat(65000):
+                b'<html xmlns="http://www.w3.org/1999/xhtml">'
+                b'<head><title>aiocoap demo</title></head>'
+                b'<body><h1>Welcome to the aiocoap demo server!</h1>'
+                b'<ul><li><a href="time">Current time</a></li>'
+                b'<li><a href="whoami">Report my network address</a></li>'
+                b'</ul></body></html>',
+            }
+
+    default_representation = ContentFormat.TEXT
+
+    async def render_get(self, request):
+        cf = self.default_representation if request.opt.accept is None else request.opt.accept
+        try:
+            return aiocoap.Message(payload=self.representations[cf], content_format=cf)
+        except KeyError:
+            raise aiocoap.error.UnsupportedContentFormat
+
+class BlockResource(resource.Resource):
+    """Example resource which supports the GET and PUT methods. It sends large
+    responses, which trigger blockwise transfer."""
+
+    def __init__(self):
+        super().__init__()
+        self.set_content(b"This is the resource's default content. It is padded "
+                b"with numbers to be large enough to trigger blockwise "
+                b"transfer.\n")
+
+    def set_content(self, content):
+        self.content = content
+        while len(self.content) <= 1024:
+            self.content = self.content + b"0123456789\n"
+
+    async def render_get(self, request):
+        return aiocoap.Message(payload=self.content)
+
+    async def render_put(self, request):
+        print('PUT payload: %s' % request.payload)
+        self.set_content(request.payload)
+        return aiocoap.Message(code=aiocoap.CHANGED, payload=self.content)
+
+
+class SeparateLargeResource(resource.Resource):
+    """Example resource which supports the GET method. It uses asyncio.sleep to
+    simulate a long-running operation, and thus forces the protocol to send
+    empty ACK first. """
+
+    def get_link_description(self):
+        # Publish additional data in .well-known/core
+        return dict(**super().get_link_description(), title="A large resource")
+
+    async def render_get(self, request):
+        await asyncio.sleep(3)
+
+        payload = "Three rings for the elven kings under the sky, seven rings "\
+                "for dwarven lords in their halls of stone, nine rings for "\
+                "mortal men doomed to die, one ring for the dark lord on his "\
+                "dark throne.".encode('ascii')
+        return aiocoap.Message(payload=payload)
+
+class TimeResource(resource.ObservableResource):
+    """Example resource that can be observed. The `notify` method keeps
+    scheduling itself, and calles `update_state` to trigger sending
+    notifications."""
+
+    def __init__(self):
+        super().__init__()
+
+        self.handle = None
+
+    def notify(self):
+        self.updated_state()
+        self.reschedule()
+
+    def reschedule(self):
+        self.handle = asyncio.get_event_loop().call_later(5, self.notify)
+
+    def update_observation_count(self, count):
+        if count and self.handle is None:
+            print("Starting the clock")
+            self.reschedule()
+        if count == 0 and self.handle:
+            print("Stopping the clock")
+            self.handle.cancel()
+            self.handle = None
+
+    async def render_get(self, request):
+        payload = datetime.datetime.now().\
+                strftime("%Y-%m-%d %H:%M").encode('ascii')
+        return aiocoap.Message(payload=payload)
+
+class WhoAmI(resource.Resource):
+    async def render_get(self, request):
+        text = ["Used protocol: %s." % request.remote.scheme]
+
+        text.append("Request came from %s." % request.remote.hostinfo)
+        text.append("The server address used %s." % request.remote.hostinfo_local)
+
+        claims = list(request.remote.authenticated_claims)
+        if claims:
+            text.append("Authenticated claims of the client: %s." % ", ".join(repr(c) for c in claims))
+        else:
+            text.append("No claims authenticated.")
+
+        return aiocoap.Message(content_format=0,
+                payload="\n".join(text).encode('utf8'))
+
+# logging setup
+
+logging.basicConfig(level=logging.INFO)
+logging.getLogger("coap-server").setLevel(logging.DEBUG)
+
+async def main():
+    # Resource tree creation
+    root = resource.Site()
+
+    root.add_resource(['.well-known', 'core'],
+            resource.WKCResource(root.get_resources_as_linkheader))
+    root.add_resource([], Welcome())
+    root.add_resource(['time'], TimeResource())
+    root.add_resource(['other', 'block'], BlockResource())
+    root.add_resource(['other', 'separate'], SeparateLargeResource())
+    root.add_resource(['whoami'], WhoAmI())
+
+    await aiocoap.Context.create_server_context(root)
+
+    # Run forever
+    await asyncio.get_running_loop().create_future()
+
+if __name__ == "__main__":
+    asyncio.run(main())
diff --git a/examples/MOOC-4/coap-client.py b/examples/MOOC-4/coap-client.py
new file mode 100644
index 00000000..c52d7beb
--- /dev/null
+++ b/examples/MOOC-4/coap-client.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python3
+
+# SPDX-FileCopyrightText: Christian Amsüss and the aiocoap contributors
+#
+# SPDX-License-Identifier: MIT
+
+"""This is a usage example of aiocoap that demonstrates how to implement a
+simple client. See the "Usage Examples" section in the aiocoap documentation
+for some more information."""
+
+import logging
+import asyncio
+import random
+
+import time
+
+from aiocoap import *
+
+logging.basicConfig(level=logging.INFO)
+
+async def main():
+    protocol = await Context.create_client_context()
+
+    if random.randint(0, 10) % 3 == 0: # wrong URI
+        request = Message(code=GET, uri='coap://[aaaa::1]]/humi')
+    else: #right URI
+         request = Message(code=GET, uri='coap://[aaaa::1]]/temp')
+       
+    try:
+        response = await protocol.request(request).response
+    except Exception as e:
+        print('Failed to fetch resource:')
+        print(e)
+    else:
+        print('Result: %s\n%r'%(response.code, response.payload))
+
+if __name__ == "__main__":
+    while True:
+        asyncio.run(main())
+        time.sleep(3)
\ No newline at end of file
diff --git a/examples/MOOC-4/core.py b/examples/MOOC-4/core.py
new file mode 100644
index 00000000..a4e116ea
--- /dev/null
+++ b/examples/MOOC-4/core.py
@@ -0,0 +1,52 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from scapy.all import *
+
+import gen_rulemanager as RM
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_CORE
+import binascii
+
+# Create a Rule Manager and upload the rules.
+
+rm = RM.RuleManager()
+rm.Add(file="underwater.json")
+rm.Print()
+
+def processPkt(pkt):
+
+    scheduler.run(session=schc_machine)
+
+    if pkt.getlayer(Ether) != None: 
+        e_type = pkt.getlayer(Ether).type
+        if e_type == 0x86dd and pkt[IPv6].nh == 17: # just UDP
+            schc_machine.schc_send(bytes(pkt)[14:], verbose=False)
+        elif e_type == 0x0800:
+            if pkt[IP].proto == 17 and pkt[UDP].dport == 0x5C4C:
+                # got a packet in the socket
+                SCHC_pkt, device = tunnel.recvfrom(1000)
+
+                other_end = 'udp:'+device[0]+':'+str(device[1])
+                #print ("from:", other_end, binascii.hexlify(SCHC_pkt))
+                origin, full_packet = schc_machine.schc_recv(
+                                   schc_packet=SCHC_pkt, 
+                                   device_id=other_end, 
+                                   iface='eth1',
+                                   verbose=False)
+
+# Start SCHC Machine
+POSITION = T_POSITION_CORE
+
+schc_machine = SCHCProtocol(role=POSITION)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+tunnel = schc_machine.get_tunnel()
+
+sniff(prn=processPkt, iface=["eth0", "eth1", "lo"]) 
+
+
+
+
+ 
diff --git a/examples/MOOC-4/dev-server.py b/examples/MOOC-4/dev-server.py
new file mode 100644
index 00000000..c93fcadd
--- /dev/null
+++ b/examples/MOOC-4/dev-server.py
@@ -0,0 +1,52 @@
+import socket
+import binascii
+import random
+import cbor2 as cbor
+
+import sys
+
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+import gen_bitarray as ba
+
+tunnel = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+tunnel.bind(('0.0.0.0', 8888))
+
+while True:
+    data, addr = tunnel.recvfrom(1500)
+    print (binascii.hexlify(data))
+
+    schc_msg = ba.BitBuffer(data)
+
+    ruleID=schc_msg.get_bits(3)
+
+    if ruleID == 1: # rule 1/3
+        app_port = schc_msg.get_bits(16)
+        mid = schc_msg.get_bits(16)
+        token = schc_msg.get_bits(16)
+        uri_idx = schc_msg.get_bits(2)
+
+        uri = ["temp", "humi", "pres", None][uri_idx]
+
+        print(app_port, mid, token, uri_idx, uri)
+
+        schc_resp = ba.BitBuffer()
+        schc_resp.add_bits(0b0000_0001, nb_bits=3) # ruleID
+
+        if uri == "temp":
+            schc_resp.add_bits(app_port, nb_bits=16) # app port
+            schc_resp.add_bits(0b010_00101,nb_bits=8) # 2.05
+            schc_resp.add_bits(mid, nb_bits=16) # Message ID
+            schc_resp.add_bits(token, nb_bits=16) # Token
+
+            data = cbor.dumps(random.randint(10, 100))
+            schc_resp.add_bytes(data)
+
+        else: # 4.04 not found
+            schc_resp.add_bits(app_port, nb_bits=16) # app port
+            schc_resp.add_bits(0b100_00100,nb_bits=8) # 4.04
+            schc_resp.add_bits(mid, nb_bits=16) # Message ID
+            schc_resp.add_bits(token, nb_bits=16) # Token
+
+        tunnel.sendto(schc_resp.get_content(), addr)
\ No newline at end of file
diff --git a/examples/MOOC-4/underwater.json b/examples/MOOC-4/underwater.json
new file mode 100644
index 00000000..fa0a98b1
--- /dev/null
+++ b/examples/MOOC-4/underwater.json
@@ -0,0 +1,41 @@
+{
+    "DeviceID" : "udp:10.0.0.20:8888",
+    "SoR" : [{
+        "RuleIDValue" : 1,
+        "RuleIDLength": 3,
+        "Compression": [	 
+            {"FID": "IPV6.VER", "TV": 6, "MO": "equal", "CDA": "not-sent"},
+            {"FID": "IPV6.TC",  "TV": 0, "MO": "equal", "CDA": "not-sent"},
+            {"FID": "IPV6.FL",  "TV": 0, "MO": "ignore","CDA": "not-sent"},
+            {"FID": "IPV6.LEN",          "MO": "ignore","CDA": "compute-length"},
+            {"FID": "IPV6.NXT", "TV": 17, "MO": "equal", "CDA": "not-sent"},
+            {"FID": "IPV6.HOP_LMT", "TV" : 255,"MO": "ignore","CDA": "not-sent"},
+            {"FID": "IPV6.DEV_PREFIX","TV": "AAAA::/64",
+                                                "MO": "equal","CDA": "not-sent"},
+            {"FID": "IPV6.DEV_IID", "TV": "::1","MO": "equal","CDA": "not-sent"},
+            {"FID": "IPV6.APP_PREFIX", "TV": "2001:0:0:1::/64",
+                                                "MO": "equal","CDA": "not-sent"},
+            {"FID": "IPV6.APP_IID", "TV": "::15",
+                                            "MO": "equal","CDA": "not-sent"},
+
+            {"FID": "UDP.DEV_PORT",  "TV": 5683,"MO": "equal",  "CDA": "not-sent"},
+            {"FID": "UDP.APP_PORT",             "MO": "ignore",  "CDA": "value-sent"},
+            {"FID": "UDP.LEN",       "TV": 0,   "MO": "ignore", "CDA": "compute-length"},
+            {"FID": "UDP.CKSUM",     "TV": 0,   "MO": "ignore", "CDA": "compute-checksum"},
+
+            {"FID": "COAP.VER",  "DI": "BI", "TV": 1,   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.TYPE", "DI": "DW", "TV": 0,   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.TYPE", "DI": "UP", "TV": 2,   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.TKL",  "DI": "BI", "TV": 2,   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.CODE", "DI": "DW", "TV": 1,   "MO": "equal","CDA": "not-sent"},
+            {"FID": "COAP.CODE", "DI": "UP",            "MO": "ignore","CDA": "value-sent"},
+            {"FID": "COAP.MID",  "DI": "BI", "TV": 0,   "MO": "ignore", "CDA": "value-sent"},
+            {"FID": "COAP.TOKEN",  "DI": "BI", "TV": 0, "MO": "ignore", "CDA": "value-sent"},
+            {"FID": "COAP.Uri-Path", "FP": 1, "DI": "DW", 
+                                "TV": ["temp", "humi", "pres"], 
+                                "MO": "match-mapping","CDA": "mapping-sent"},
+            {"FID": "COAP.ACCEPT", "DI": "DW", "TV": 30, "MO": "equal", "CDA": "not-sent"},        
+            {"FID": "COAP.Content-Format", "DI": "UP", "TV": 30, "MO": "equal", "CDA": "not-sent"}        
+        ]}
+    ]
+}
diff --git a/examples/MOOC-5/icmp-bi.json b/examples/MOOC-5/icmp-bi.json
new file mode 100644
index 00000000..2e11d19b
--- /dev/null
+++ b/examples/MOOC-5/icmp-bi.json
@@ -0,0 +1,30 @@
+ {
+    "DeviceID" : "udp:10.0.0.20:8888",
+    "SoR" : [  
+	 {
+	    "RuleID": 6,
+	    "RuleIDLength": 3,
+	    "Compression": [
+		{"FID": "IPV6.VER", "TV": 6, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.TC",  "TV": 0, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.FL",  "TV": 0, "MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.LEN",          "MO": "ignore","CDA": "compute-length"},
+		{"FID": "IPV6.NXT", "TV": 58, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.HOP_LMT", "TV" : 255,"MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_PREFIX","TV": "AAAA::/64",
+                                               "MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_IID", "TV": "::1","MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.APP_PREFIX",         "MO": "ignore","CDA": "value-sent"},
+		{"FID": "IPV6.APP_IID",            "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.TYPE",  "TV": 128, "DI" : "DW", "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.TYPE",  "TV": 129, "DI" : "UP", "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CODE",  "TV": 0,   "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CKSUM", "TV": 0,   "MO": "ignore","CDA": "compute-checksum"},
+		{"FID": "ICMPV6.IDENT", "TV": 0,   "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.SEQNO", "TV": 0,   "MO": "ignore", "CDA": "value-sent"},
+		{"FID": "ICMPV6.PAYLOAD", "TV": 0,"MO": "ignore","CDA": "value-sent"}
+	    ]
+	 }
+    ]
+  }
+
diff --git a/examples/MOOC-5/ping_core1.py b/examples/MOOC-5/ping_core1.py
new file mode 100644
index 00000000..66a7492d
--- /dev/null
+++ b/examples/MOOC-5/ping_core1.py
@@ -0,0 +1,51 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from scapy.all import *
+
+import gen_rulemanager as RM
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_CORE
+
+# Create a Rule Manager and upload the rules.
+
+rm = RM.RuleManager()
+rm.Add(file="icmp-bi.json")
+rm.Print()
+
+def processPkt(pkt):
+
+    scheduler.run(session=schc_machine)
+
+    if pkt.getlayer(Ether) != None: 
+        e_type = pkt.getlayer(Ether).type
+        if e_type == 0x86dd:
+            schc_machine.schc_send(bytes(pkt)[14:])
+        elif e_type == 0x0800:
+            if pkt[IP].proto == 17 and pkt[UDP].dport == 0x5C4C:
+                # got a packet in the socket
+                SCHC_pkt, device = tunnel.recvfrom(1000)
+
+                other_end = 'udp:'+device[0]+':'+str(device[1])
+
+                origin, full_packet = schc_machine.schc_recv(
+                                   schc_packet=SCHC_pkt, 
+                                   device_id=other_end, 
+                                   iface='eth1',
+                                   verbose=True)
+
+# Start SCHC Machine
+POSITION = T_POSITION_CORE
+
+schc_machine = SCHCProtocol(role=POSITION)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+tunnel = schc_machine.get_tunnel()
+
+sniff(prn=processPkt, iface=["eth0", "eth1", "lo"]) 
+
+
+
+
+ 
diff --git a/examples/MOOC-5/ping_dev.py b/examples/MOOC-5/ping_dev.py
new file mode 100644
index 00000000..18d5eb29
--- /dev/null
+++ b/examples/MOOC-5/ping_dev.py
@@ -0,0 +1,70 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+import gen_rulemanager as RM
+from gen_parameters import *
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_DEVICE
+
+from scapy.all import *
+
+rm = RM.RuleManager()
+rm.Add(file="icmp-bi.json")
+rm.Print()
+
+import socket
+import binascii
+import netifaces as ni
+
+addr = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
+
+PORT = 8888
+deviceID = "udp:"+addr+":"+str(PORT)
+
+print("device ID is", deviceID)
+
+tunnel = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+tunnel.bind (("0.0.0.0", PORT)) # same port as in the DeviceID
+
+POSITION = T_POSITION_DEVICE
+
+schc_machine = SCHCProtocol(role=POSITION)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+ 
+def processPkt(pkt):
+
+    scheduler.run(session=schc_machine)
+
+    e_type = pkt.getlayer(Ether).type
+    if e_type == 0x0800 and pkt[IP].proto == 17 and pkt[UDP].sport == 0x5C4C:
+        SCHC_pkt, device = tunnel.recvfrom(1000)
+
+        core_id = "udp:"+device[0]+":"+str(device[1])
+
+        origin, full_packet = schc_machine.schc_recv(
+                            schc_packet=SCHC_pkt, 
+                            device_id=deviceID, 
+                            verbose=True)
+        
+        if full_packet is not None and ICMPv6EchoRequest in full_packet:
+            print ("ici", origin, full_packet)
+            response =             IPv6Header = IPv6 (
+                version= full_packet[IPv6].version,
+                tc     = full_packet[IPv6].tc,
+                fl     = full_packet[IPv6].fl,
+                hlim   = 64,
+                src    = full_packet[IPv6].dst,
+                dst    = full_packet[IPv6].src
+            ) / ICMPv6EchoReply (
+                id = full_packet[ICMPv6EchoRequest].id,
+                seq = full_packet[ICMPv6EchoRequest].seq,
+                data = full_packet[ICMPv6EchoRequest].data
+            )
+            response.show()
+            schc_machine.schc_send(bytes(response), core_id = core_id, verbose=True)
+
+sniff(prn=processPkt, iface=["eth0", "lo"]) 
+
+
+
diff --git a/examples/MOOC-5/ping_dev1.py b/examples/MOOC-5/ping_dev1.py
new file mode 100644
index 00000000..62057e6f
--- /dev/null
+++ b/examples/MOOC-5/ping_dev1.py
@@ -0,0 +1,73 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from scapy.all import *
+
+import gen_rulemanager as RM
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_DEVICE
+
+import netifaces as ni
+
+import socket
+import select
+import time
+
+addr = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
+
+PORT = 8888
+deviceID = "udp:"+addr+":"+str(PORT)
+
+print("device ID is", deviceID)
+
+tunnel = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+tunnel.bind (("0.0.0.0", PORT)) # same port as in the DeviceID
+# Create a Rule Manager and upload the rules.
+
+rm = RM.RuleManager()
+rm.Add(file="icmp-bi.json")
+rm.Print()
+
+core_id = None
+
+# Start SCHC Machine
+POSITION = T_POSITION_DEVICE
+
+schc_machine = SCHCProtocol(role=POSITION, tunnel=tunnel)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+tunnel = schc_machine.get_tunnel()
+
+t = AsyncSniffer(iface="eth0", store=False) 
+t.start()
+print ("sniff started")
+while True:
+    scheduler.run(session=schc_machine)
+
+    s_in, _, _ = select.select([tunnel], [], [], 0.1)
+    if len(s_in) > 0: # data on the socket
+        SCHC_pkt, device = tunnel.recvfrom(1000)
+
+        core_id = "udp:"+device[0]+":"+str(device[1])
+
+        origin, full_packet = schc_machine.schc_recv(
+                            schc_packet=SCHC_pkt, 
+                            device_id=deviceID, 
+                            verbose=True)
+        
+        if full_packet is not None and ICMPv6EchoRequest in full_packet:
+            response =             IPv6Header = IPv6 (
+                version= full_packet[IPv6].version,
+                tc     = full_packet[IPv6].tc,
+                fl     = full_packet[IPv6].fl,
+                hlim   = 64,
+                src    = full_packet[IPv6].dst,
+                dst    = full_packet[IPv6].src
+            ) / ICMPv6EchoReply (
+                id = full_packet[ICMPv6EchoRequest].id,
+                seq = full_packet[ICMPv6EchoRequest].seq,
+                data = full_packet[ICMPv6EchoRequest].data
+            )
+            schc_machine.schc_send(bytes(response), core_id = core_id, verbose=True)
+    time.sleep(0.1)
diff --git a/examples/MOOC-6/icmp-bi.json b/examples/MOOC-6/icmp-bi.json
new file mode 100644
index 00000000..27739b0c
--- /dev/null
+++ b/examples/MOOC-6/icmp-bi.json
@@ -0,0 +1,44 @@
+ {
+    "DeviceID" : "udp:10.0.0.20:8888",
+    "SoR" : [  
+	 {
+	    "RuleID": 6,
+	    "RuleIDLength": 3,
+	    "Compression": [
+		{"FID": "IPV6.VER", "TV": 6, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.TC",  "TV": 0, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.FL",  "TV": 0, "MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.LEN",          "MO": "ignore","CDA": "compute-length"},
+		{"FID": "IPV6.NXT", "TV": 58, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.HOP_LMT", "TV" : 255,"MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_PREFIX","TV": "AAAA::/64",
+                                               "MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_IID", "TV": "::1","MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.APP_PREFIX",         "MO": "ignore","CDA": "value-sent"},
+		{"FID": "IPV6.APP_IID",            "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.TYPE",  "TV": 128, "DI" : "DW", "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.TYPE",  "TV": 129, "DI" : "UP", "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CODE",  "TV": 0,   "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CKSUM", "TV": 0,   "MO": "ignore","CDA": "compute-checksum"},
+		{"FID": "ICMPV6.IDENT", "TV": 0,   "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.SEQNO", "TV": 0,   "MO": "ignore", "CDA": "value-sent"},
+		{"FID": "ICMPV6.PAYLOAD", "TV": 0,"MO": "ignore","CDA": "value-sent"}
+	    ]
+	 },{
+		"RuleID" : 12,
+		"RuleIDLength" : 11,
+		"Fragmentation" : {
+			"FRMode": "NoAck",
+			"FRDirection": "DW"
+	 	}
+	 },{	
+		"RuleID" : 13,
+		"RuleIDLength" : 11,
+		"Fragmentation" : {
+		"FRMode": "NoAck",
+		"FRDirection": "UP"
+		} 
+	}
+    ]
+  }
+
diff --git a/examples/MOOC-6/icmp.json b/examples/MOOC-6/icmp.json
new file mode 100644
index 00000000..5174b0a3
--- /dev/null
+++ b/examples/MOOC-6/icmp.json
@@ -0,0 +1,29 @@
+ {
+    "DeviceID" : "udp:10.0.0.20:8888",
+    "SoR" : [  
+	 {
+	    "RuleID": 6,
+	    "RuleIDLength": 3,
+	    "Compression": [
+		{"FID": "IPV6.VER", "TV": 6, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.TC",  "TV": 0, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.FL",  "TV": 0, "MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.LEN",          "MO": "ignore","CDA": "compute-length"},
+		{"FID": "IPV6.NXT", "TV": 58, "MO": "equal", "CDA": "not-sent"},
+		{"FID": "IPV6.HOP_LMT", "TV" : 255,"MO": "ignore","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_PREFIX","TV": "AAAA::/64",
+                                               "MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.DEV_IID", "TV": "::1","MO": "equal","CDA": "not-sent"},
+		{"FID": "IPV6.APP_PREFIX",         "MO": "ignore","CDA": "value-sent"},
+		{"FID": "IPV6.APP_IID",            "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.TYPE",  "TV": 128, "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CODE",  "TV": 0,   "MO": "equal","CDA": "not-sent"},
+		{"FID": "ICMPV6.CKSUM", "TV": 0,   "MO": "ignore","CDA": "compute-checksum"},
+		{"FID": "ICMPV6.IDENT", "TV": 0,   "MO": "ignore","CDA": "value-sent"},
+		{"FID": "ICMPV6.SEQNO", "TV": 0,   "MO": "ignore", "CDA": "value-sent"},
+		{"FID": "ICMPV6.PAYLOAD", "TV": 0,"MO": "ignore","CDA": "value-sent"}
+	    ]
+	 }
+    ]
+  }
+
diff --git a/examples/MOOC-6/ping_core.py b/examples/MOOC-6/ping_core.py
new file mode 100644
index 00000000..178cfe16
--- /dev/null
+++ b/examples/MOOC-6/ping_core.py
@@ -0,0 +1,40 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from scapy.all import *
+
+import gen_rulemanager as RM
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_CORE
+
+# Create a Rule Manager and upload the rules.
+
+rm = RM.RuleManager()
+rm.Add(file="icmp.json")
+rm.Print()
+
+def processPkt(pkt):
+
+    scheduler.run(session=schc_machine)
+
+    if pkt.getlayer(Ether) != None: 
+        e_type = pkt.getlayer(Ether).type
+        if e_type == 0x86dd:
+            schc_machine.schc_send(bytes(pkt)[14:], verbose=True)
+
+
+# Start SCHC Machine
+POSITION = T_POSITION_CORE
+
+schc_machine = SCHCProtocol(role=POSITION)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+
+
+sniff(prn=processPkt, iface="eth1") 
+
+
+
+
+ 
diff --git a/examples/MOOC-6/ping_core1.py b/examples/MOOC-6/ping_core1.py
new file mode 100644
index 00000000..4704b4f0
--- /dev/null
+++ b/examples/MOOC-6/ping_core1.py
@@ -0,0 +1,51 @@
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from scapy.all import *
+
+import gen_rulemanager as RM
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_CORE
+
+# Create a Rule Manager and upload the rules.
+
+rm = RM.RuleManager()
+rm.Add(file="icmp-bi.json")
+rm.Print()
+
+def processPkt(pkt):
+
+    scheduler.run(session=schc_machine)
+
+    if pkt.getlayer(Ether) != None: 
+        e_type = pkt.getlayer(Ether).type
+        if e_type == 0x86dd:
+            schc_machine.schc_send(bytes(pkt)[14:], verbose=True)
+        elif e_type == 0x0800:
+            if pkt[IP].proto == 17 and pkt[UDP].dport == 0x5C4C:
+                # got a packet in the socket
+                SCHC_pkt, device = tunnel.recvfrom(1000)
+
+                other_end = 'udp:'+device[0]+':'+str(device[1])
+
+                origin, full_packet = schc_machine.schc_recv(
+                                   schc_packet=SCHC_pkt, 
+                                   device_id=other_end, 
+                                   iface='eth1',
+                                   verbose=True)
+
+# Start SCHC Machine
+POSITION = T_POSITION_CORE
+
+schc_machine = SCHCProtocol(role=POSITION)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+tunnel = schc_machine.get_tunnel()
+
+sniff(prn=processPkt, iface=["eth0", "eth1", "lo"]) 
+
+
+
+
+ 
diff --git a/examples/MOOC-6/ping_dev1.py b/examples/MOOC-6/ping_dev1.py
new file mode 100644
index 00000000..029d55ef
--- /dev/null
+++ b/examples/MOOC-6/ping_dev1.py
@@ -0,0 +1,134 @@
+import binascii
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from scapy.all import *
+
+import gen_rulemanager as RM
+from protocol import SCHCProtocol
+from gen_parameters import T_POSITION_DEVICE
+
+import netifaces as ni
+
+import socket
+import select
+import time
+
+addr = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
+
+PORT = 8888
+deviceID = "udp:"+addr+":"+str(PORT)
+
+print("device ID is", deviceID)
+
+tunnel = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+tunnel.bind (("0.0.0.0", PORT)) # same port as in the DeviceID
+# Create a Rule Manager and upload the rules.
+
+rm = RM.RuleManager()
+rm.Add(file="icmp-bi.json")
+rm.Print()
+
+core_id = None
+
+def processPkt(pkt):
+    global core_id
+
+    print("+", end="")
+
+    if pkt.getlayer(Ether) != None: 
+        print ("-", end="")
+        e_type = pkt.getlayer(Ether).type
+        pkt.show()
+        if e_type == 0x86dd:
+            print ("*", end="")
+            if pkt[Ether].src == "00:00:00:00:00:00": # on loopback
+                if pkt[IPv6].nh == 58: # ICMPv6 
+                    print("get from sniff")
+                    pkt.show()
+                    if core_id: # core is identified, can answer
+                        schc_machine.schc_send(bytes(pkt)[14:], core_id = core_id, verbose=True)
+                    else:
+                        print ("core not yet identified, do not send SCHC pkt")
+            else:
+                print ("IPv6 not on loopback")
+ 
+    s_in, _, _ = select.select([tunnel], [], [])
+ 
+    if len(s_in) > 0: # data on the socket
+        SCHC_pkt, device = tunnel.recvfrom(1000)
+
+        core_id = "udp:"+device[0]+":"+str(device[1])
+
+        origin, full_packet = schc_machine.schc_recv(
+                            schc_packet=SCHC_pkt, 
+                            device_id=deviceID, 
+                            verbose=True)
+        print("result", full_packet)
+
+# Start SCHC Machine
+POSITION = T_POSITION_DEVICE
+
+schc_machine = SCHCProtocol(role=POSITION, tunnel=tunnel)           
+schc_machine.set_rulemanager(rm)
+scheduler = schc_machine.system.get_scheduler()
+tunnel = schc_machine.get_tunnel()
+
+t = AsyncSniffer(prn=processPkt, iface=["lo"], store=False) 
+t.start()
+print ("sniff started")
+while True:
+    scheduler.run(session=schc_machine)
+
+    s_in, _, _ = select.select([tunnel], [], [])
+    if len(s_in) > 0: # data on the socket
+        SCHC_pkt, device = tunnel.recvfrom(1000)
+
+        core_id = "udp:"+device[0]+":"+str(device[1])
+
+        resp = schc_machine.schc_recv(
+                            schc_packet=SCHC_pkt, 
+                            device_id=deviceID, 
+                            verbose=True)
+        
+        origin = resp[0]
+        full_packet = resp[1]
+        
+        #print ("---->", type(origin), origin, full_packet)
+
+        if full_packet != None:
+        
+            #print ("RESULT", full_packet)
+            if ICMPv6EchoRequest in full_packet:
+                IPv6Header = IPv6 (
+                    version= full_packet.version ,
+                    tc     = full_packet.tc,
+                    fl     = full_packet.fl,
+                    nh     = full_packet.nh,
+                    hlim   = full_packet.hlim,
+                    src    = full_packet.dst, 
+                    dst    = full_packet.src
+                ) 
+
+                ICMPv6Header = ICMPv6EchoReply(
+                    id = full_packet.id,
+                    seq =  full_packet.seq,
+                    data = full_packet.data)
+
+                Echoreply = IPv6Header / ICMPv6Header
+
+                schc_machine.schc_send(
+                        bytes(Echoreply), 
+                        core_id = core_id,
+                        verbose=True)
+            
+                #print (Echoreply)
+
+    time.sleep(0.1)
+
+t.stop()
+
+
+
+ 
diff --git a/src/basic_connection.py b/src/basic_connection.py
new file mode 100644
index 00000000..801dd275
--- /dev/null
+++ b/src/basic_connection.py
@@ -0,0 +1,228 @@
+import time
+import sys
+# insert at 1, 0 is the script path (or '' in REPL)
+sys.path.insert(1, '../../src/')
+
+from gen_utils import dprint, sanitize_value
+from compr_core import *
+import frag_send # to get types
+import frag_recv
+
+from scapy.all import hexdump
+
+import binascii
+import cbor2 as cbor
+
+class ScapyLowerLayer:
+    def __init__(self, position, socket=None, other_end=None):
+        self.protocol = None
+        self.position = position
+        self.other_end = other_end
+        self.sender_delay = 0
+        self.sock = socket
+
+    # ----- AbstractLowerLayer interface (see: architecture.py)
+        
+    def _set_protocol(self, protocol):
+        self.protocol = protocol
+        self._actual_init()
+
+    def send_packet(self, packet, dest, transmit_callback=None):
+        #print ("L2_connection.py: send_pkt, dest ", dest, "packet", packet)
+        if dest != None and dest.find("udp") == 0:
+            destination = (dest.split(":")[1], int(dest.split(":")[2]))
+
+            res = self.sock.sendto(packet, destination)
+            #print ("send status", res, "bytes to", destination )
+
+        elif dest != None and dest.find("lorawan") == 0:
+            destination = ("127.0.0.1", 12345)
+            device_id = dest.split(":")[1]
+
+            print (destination, device_id)
+
+            msg = {
+                1: 1,
+                2: binascii.unhexlify(device_id),
+                4: packet
+            }
+
+            print (binascii.hexlify(cbor.dumps(msg)))
+            self.sock.sendto(cbor.dumps(msg), destination)
+
+        else:
+            print ("No destination found, not sent:", packet, dest)
+            return False
+
+#        else:
+#            destination = self.other_end
+
+
+        # define error_rate rand ou un vecteur avec 0 et 1
+        # if error then not send
+
+        if transmit_callback is not None:
+            print ("OLD BEHAVIOR", transmit_callback)
+            transmit_callback(1)
+        #print (self.protocol.sender_delay)
+        time.sleep(self.protocol.sender_delay)
+
+    def get_mtu_size(self):
+        return 400 # XXX
+
+    # ----- end AbstractLowerLayer interface
+
+    def _actual_init(self):
+        pass
+
+    def event_packet_received(self):
+        """Called but the SelectScheduler when an UDP packet is received"""
+        packet, address = self.sd.recvfrom(MAX_PACKET_SIZE)
+        sender_address = address_to_string(address)
+        position = self.position
+        print ("sender address", sender_address)
+        if position == T_POSITION_DEVICE:
+            self.protocol.schc_recv(core_id = sender_address, schc_packet = packet)
+        else :
+            self.protocol.schc_recv(device_id = sender_address, schc_packet = packet)
+
+
+
+class ScapyScheduler:
+    def __init__(self):
+        self.queue = []
+        self.clock = 0
+        self.next_event_id = 0
+        self.current_event_id = None
+        self.observer = None
+        self.item=0
+        self.fd_callback_table = {}
+        self.last_show = 0 
+        self.session_id = None
+
+
+    # ----- AbstractScheduler Interface (see: architecture.py)
+
+    def get_clock(self):
+        return time.time()
+         
+    def add_event(self, rel_time, callback, args, session_id = None): #TODO
+        assert rel_time >= 0
+        event_id = self.next_event_id
+        self.next_event_id += 1
+        self.session_id = session_id
+        clock = self.get_clock()
+        abs_time = clock + rel_time
+        self.queue.append((abs_time, event_id, callback, args, session_id))
+        return event_id
+
+    def cancel_event(self, event):
+        item_pos = 0
+        item_found = False
+        elm = None
+        for q in self.queue:
+            if q[1] == event:
+                item_found = True
+                break
+            item_pos += 1
+
+        if item_found:
+            elm = self.queue.pop(item_pos)
+
+        return elm
+
+    def cancel_session(self, session_id = None): #TODO
+        elm = []
+        indices = [i for i, x in enumerate(self.queue) if x[4] == session_id]
+        self.queue = [i for j, i in enumerate(self.queue) if j not in indices]
+        return elm
+
+    # ----- Additional methods
+
+    def _sleep(self, delay):
+        """Implements a delayfunc for sched.scheduler
+        This delayfunc sleeps for `delay` seconds at most (in real-time,
+        but if any event appears in the fd_table (e.g. packet arrival),
+        the associated callbacks are called and the wait is stop.
+        """
+        self.wait_one_callback_until(delay)
+
+
+    def wait_one_callback_until(self, max_delay):
+        """Wait at most `max_delay` second, for available input (e.g. packet).
+        If so, all associated callbacks are run until there is no input.
+        """
+        fd_list = list(sorted(self.fd_callback_table.keys()))
+        print (fd_list)
+        while True:
+            rlist, unused, unused = select.select(fd_list, [], [], max_delay)
+            if len(rlist) == 0:
+                break
+            for fd in rlist:
+                callback, args = self.fd_callback_table[fd]
+                callback(*args)
+            # note that sched impl. allows to return before sleeping `delay`
+
+    def add_fd_callback(self, fd, callback, args):
+        assert fd not in self.fd_callback_table
+        self.fd_callback_table[fd] = (callback, args)
+
+    def run(self, session=None, display_period=None): 
+        factor= 10
+        if self.item % factor == 0:
+            seq = ["|", "/", "-", "\\", "-"]
+            print ("{:s}".format(seq[(self.item//factor)%len(seq)]),end="\b", flush=True)
+        self.item +=1
+
+        if display_period and time.time() - self.last_show > display_period: # display the event queue every minute
+            print ("*"*40)
+            print ("EVENT QUEUE")
+            self.last_show = time.time()
+            for q in self.queue:
+                print ("{0:6.2f}: id.{1:04d}".format(q[0]-time.time(), q[1]), q[2])
+
+            if session:
+                print ("-"*30)
+                for s in session.session_manager.session_table:
+                    s_id = "{}-{}/{}-{}".format(s[0], s[1], s[2],s[3])
+                    print ("{:10} |".format(s_id), end="")
+                    if isinstance(session.session_manager.session_table[s], frag_send.FragmentNoAck):
+                        print ("Sending NoAck")
+                    elif isinstance(session.session_manager.session_table[s], frag_recv.ReassemblerNoAck):
+                        print ("Receiving NoAck ", end="")
+                        print (len(session.session_manager.session_table[s].tile_list), "tiles")
+                    else:
+                        print (session.session_manager.session_table[s])
+            print ("*"*40)
+
+        while len(self.queue) > 0:
+            self.queue.sort()
+
+            wake_up_time = self.queue[0][0]
+            if time.time() < wake_up_time:
+                return
+
+            event_info = self.queue.pop(0)
+            self.clock, event_id, callback, args, session_id = event_info
+            self.current_event_id = event_id
+            if self.observer is not None:
+                self.observer("sched-pre-event", event_info)
+            callback(*args)
+            if self.observer is not None:
+                self.observer("sched-post-event", event_info)
+            if display_period:
+                print("Queue running event -> {}, callback -> {}".format(event_id, callback.__name__))
+
+# --------------------------------------------------        
+
+class ScapySystem:
+    def __init__(self):
+        self.scheduler = ScapyScheduler()
+
+    def get_scheduler(self):
+        return self.scheduler
+
+    def log(self, name, message):
+        print(name, message)
+
+# --------------------------------------------------
\ No newline at end of file
diff --git a/src/compr_core.py b/src/compr_core.py
index 0313c411..8a0aa521 100644
--- a/src/compr_core.py
+++ b/src/compr_core.py
@@ -42,7 +42,7 @@
 
 class Compressor:
 
-    def __init__(self, protocol):
+    def __init__(self, protocol=None):
         self.protocol = protocol
 
         self.__func_tx_cda = {
@@ -132,7 +132,7 @@ def tx_cda_lsb(self, field, rule, output, device_id=None):
 
             bit_value = value[pos_byte] & (1 << pos_bit)
 
-            print (bit_position, pos_byte, pos_bit, bit_value)
+            #print (bit_position, pos_byte, pos_bit, bit_value)
             output.set_bit(bit_value)
 
             bit_position += 1
@@ -190,7 +190,7 @@ def tx_cda_notyet(self, field, rule, output, device_id=None):
     #         packet_bbuf, output_bbuf))
     #     return output_bbuf
 
-    def compress(self, rule, parsed_packet, data, direction=T_DIR_UP, device_id = None):
+    def compress(self, rule, parsed_packet, data, direction=T_DIR_UP, device_id = None, verbose=False):
         """
         Take a compression rule and a parsed packet and return a SCHC pkt
         """
@@ -199,26 +199,27 @@ def compress(self, rule, parsed_packet, data, direction=T_DIR_UP, device_id = No
         # set ruleID first.
         if rule[T_RULEID] is not None and rule[T_RULEIDLENGTH] is not None:
             output_bbuf.add_bits(rule[T_RULEID], rule[T_RULEIDLENGTH])
-            dprint("rule {}/{}".format(rule[T_RULEID], rule[T_RULEIDLENGTH]))
+            #dprint("rule {}/{}".format(rule[T_RULEID], rule[T_RULEIDLENGTH]))
             #output_bbuf.display(format="bin")
 
         for r in rule["Compression"]:
-            print("rule item:", r)
+            #print("rule item:", r)
 
             if r[T_DI] in [T_DIR_BI, direction]:
                 if (r[T_FID], r[T_FP]) in parsed_packet:
-                    dprint("in packet")
+                    #dprint("in packet")
                     self.__func_tx_cda[r[T_CDA]](field=parsed_packet[(r[T_FID], r[T_FP])],
                                                 rule = r,
                                                 output= output_bbuf,
                                                 device_id=device_id)
                 else: # not find in packet, but is variable length can be coded as 0
-                    dprint("send variable length")
+                    #dprint("send variable length")
                     self.__func_tx_cda[T_CDA_VAL_SENT](field = [0, 0, "Null Field"], rule = r, output = output_bbuf)
             else:
-                dprint("rule skipped, bad direction")
-
-            output_bbuf.display(format="bin")
+                #dprint("rule skipped, bad direction")
+                pass
+            if verbose:
+                output_bbuf.display(format="bin")
 
         output_bbuf.add_bytes(data)
 
@@ -322,16 +323,18 @@ def rx_cda_val_sent(self, rule, in_bbuf):
             if size == 0:
                 return (None, 0)
         elif rule[T_FL] == "tkl":
-            size = self.parsed_packet[(T_COAP_TKL, 1)][0]*8
-            dprint("token size", size)
+            size_byte = self.parsed_packet[(T_COAP_TKL, 1)][0]
+            size = int.from_bytes(size_byte, "big")*8
+            #print("token size", size)
         elif type (rule[T_FL]) == int:
             size = rule[T_FL]
         else:
             raise ValueError("cannot read field length")
         #in_bbuf.display("bin")
         val = in_bbuf.get_bits(size)
+        val_ba = adapt_value(val)
 
-        return [val, size]
+        return [val_ba, size]
 
 
     def rx_cda_map_sent(self, rule, in_bbuf):
@@ -339,19 +342,21 @@ def rx_cda_map_sent(self, rule, in_bbuf):
         # The number of bits sent is the minimal size for coding all the
         # possible indices.
 
+        assert (type(rule[T_TV]) is list)
 
-        size = len(bin(len(rule[T_TV])-1)[2:])
-        val = in_bbuf.get_bits(size)
+        read_size = len(bin(len(rule[T_TV])-1)[2:])
+        index = in_bbuf.get_bits(read_size)
 
-        #dprint("====>", rule[T_TV][val], len(rule[T_TV][val]), rule[T_FL])
- 
 
-        if rule[T_FL] == "var":
-            size = len(rule[T_TV][val]) * 8
+        if index < len(rule[T_TV]):
+            value = rule[T_TV][index]
+            size = len(value)*8
         else:
-            size = rule[T_FL]
+            print("Warning: Mapping index ({}) larger than TV size ({}), set to None".format(index, len(rule[T_TV])))
+            value = None
+            size = 0
 
-        return [rule[T_TV][val], size]
+        return [value, size]
 
     def rx_cda_lsb(self, rule, in_bbuf):
         assert rule[T_MO] == T_MO_MSB
@@ -372,11 +377,16 @@ def rx_cda_lsb(self, rule, in_bbuf):
             total_size = rule[T_FL]
             send_length = rule[T_FL] - rule[T_MO_VAL]
 
-        tmp_bbuf.add_value(rule[T_TV], rule[T_MO_VAL])
+        value = int.from_bytes(rule[T_TV], "big")
+
+        for i in range(total_size, send_length, -1):
+            bit = value & (0x01 << (i-1))
+            tmp_bbuf.set_bit(bit)
+
         val = in_bbuf.get_bits(send_length)
         tmp_bbuf.add_value(val, send_length)
 
-        return [bytes(tmp_bbuf.get_content()), total_size]
+        return [bytes(tmp_bbuf.get_remaining_content()), total_size]
 
     def rx_cda_comp_len(self, rule, in_bbuf):
         # will update the length field later.
@@ -465,10 +475,10 @@ def decompress(self, schc, rule, direction):
         assert (rule_send == rule["RuleID"])
 
         for r in rule["Compression"]:
-            dprint(r)
+            #dprint(r)
             if r[T_DI] in [T_DIR_BI, direction]:
                 full_field = self.__func_rx_cda[r[T_CDA]](r, schc)
-                dprint("<<<", full_field)
+                #dprint("<<<", full_field)
                 self.parsed_packet[(r[T_FID], r[T_FP])] = full_field
                 #pprint.pprint (self.parsed_packet)
 
diff --git a/src/compr_parser.py b/src/compr_parser.py
index 4a0ee71c..fb90abad 100644
--- a/src/compr_parser.py
+++ b/src/compr_parser.py
@@ -40,33 +40,13 @@
     258: T_COAP_OPT_NO_RESP
 }
 
+coap_options = {value: key for key, value in option_names.items()}
+
 icmpv6_types = {
     T_ICMPV6_TYPE_ECHO_REQUEST: 128,
     T_ICMPV6_TYPE_ECHO_REPLY: 129
 }
 
-coap_options = {'If-Match':1,
-            'Uri-Host':3,
-            'ETag':4,
-            'If-None-Match':5,
-            'Observe':6,
-            'Uri-Port':7,
-            'Location-Path':8,
-            'Uri-Path':11,
-            'Content-Format':12,
-            'Max-Age':14,
-            'Uri-Query':15,
-            'Accept':17,
-            'Location-Query':20,
-            'Block2':23,
-            'Block1':27,
-            'Size2':28,
-            'Proxy-Uri':35,
-            'Proxy-Scheme':39,
-            'Size1':60,
-            'No-Response': 258}
-
-
 class Parser:
     """
     Parser takes a bytearray and transforms it into a dictionary indexed by field id.
@@ -76,7 +56,9 @@ def __init__(self, protocol=None):
         self.protocol = protocol
         self.header_fields = {}
 
-    def parse(self, pkt, direction, layers=["IPv6", "ICMP", "UDP", "COAP"], start="IPv6"):
+    def parse(self, pkt, direction, layers=["IPv6", "ICMP", "UDP", "CoAP"], 
+              coap_port = 5683,
+              start="IPv6"):
         """
         Parsing a byte array:
         - pkt is the bytearray to be parsed
@@ -87,8 +69,8 @@ def parse(self, pkt, direction, layers=["IPv6", "ICMP", "UDP", "COAP"], start="I
         to stop before CoAP layers = ["IPv6, "UDP"]
         """
 
-        assert direction in [T_DIR_UP, T_DIR_DW, T_DIR_BI]  # rigth value
-        dprint("direction in parser:", direction)
+        assert direction in [T_DIR_UP, T_DIR_DW]  # rigth value
+        #dprint("direction in parser:", direction)
 
         pos = 0
         self.header_fields = {}
@@ -154,7 +136,8 @@ def parse(self, pkt, direction, layers=["IPv6", "ICMP", "UDP", "COAP"], start="I
 
             pos += 8
 
-            next_layer = "COAP"
+            if udpBytes[0] == coap_port or udpBytes[1] == coap_port:
+                next_layer = "CoAP"
 
         if "ICMP" in layers and next_layer == "ICMP":
             icmpBytes = unpack('!BBH', pkt[pos:pos+4])
@@ -173,10 +156,13 @@ def parse(self, pkt, direction, layers=["IPv6", "ICMP", "UDP", "COAP"], start="I
                 unused = unpack('!L', pkt[pos:pos+4])
                 self.header_fields[T_ICMPV6_UNUSED, 1]       = [adapt_value(unused[0]), 32]
                 pos += 4
+
+            if True:  # current draft propose to parse even the payload for all ICMPv6 packets
                 self.header_fields[T_ICMPV6_PAYLOAD, 1]       = [adapt_value(pkt[pos:]), (len(pkt)- pos)*8]
                 pos = len(pkt)
+
                 
-        if "COAP" in layers and next_layer == "COAP":
+        if "CoAP" in layers and next_layer == "CoAP":
             field_position = {}
             coapBytes = unpack('!BBH', pkt[pos:pos+4])
 
@@ -253,7 +239,7 @@ class Unparser:
     def _init(self):
         pass
 
-    def unparse (self, header_d, data, direction, d_rule=None, iface=None):
+    def unparse (self, header_d, data, direction, d_rule=None, iface=None, verbose=False):
         #dprint ("unparse: ", header_d, data, direction)
 
         L2header = None
@@ -299,23 +285,27 @@ def unparse (self, header_d, data, direction, d_rule=None, iface=None):
             ipv6_next = int.from_bytes(header_d[(T_IPV6_NXT, 1)][0], byteorder="big" )
 
             if ipv6_next == 58 and (T_ICMPV6_TYPE, 1) in header_d: #IPv6 /  ICMPv6
-                for i in icmpv6_types:
-                    icmp_type = int.from_bytes(header_d[(ICMPV6.TYPE, 1)][0], byteorder="big" )
-                    if icmp_type == icmpv6_types[T_ICMPV6_TYPE_ECHO_REPLY]:
-                        IPv6Src = DevStr
-                        IPv6Dst = AppStr
-                        ICMPv6Header = ICMPv6EchoReply(
-                            id =  int.from_bytes(header_d[(T_ICMPV6_IDENT, 1)][0], byteorder="big" ),
-                            seq =   int.from_bytes(header_d[(T_ICMPV6_SEQNO, 1)][0], byteorder="big" ),
-                            data = data)
-                    if icmp_type == icmpv6_types[T_ICMPV6_TYPE_ECHO_REQUEST]:
-                        IPv6Src = AppStr
-                        IPv6Dst = DevStr 
-                        ICMPv6Header = ICMPv6EchoRequest(
-                            id =  int.from_bytes(header_d[(T_ICMPV6_IDENT, 1)][0], byteorder="big" ),
-                            seq =   int.from_bytes(header_d[(T_ICMPV6_SEQNO, 1)][0], byteorder="big" ),
-                            data = data)
-                    L4header = ICMPv6Header
+                icmp_type = int.from_bytes(header_d[(T_ICMPV6_TYPE, 1)][0], byteorder="big" )
+
+                if icmp_type == 129: #icmpv6_types[T_ICMPV6_TYPE_ECHO_REPLY]:
+                    IPv6Src = DevStr
+                    IPv6Dst = AppStr
+                    ICMPv6Header = ICMPv6EchoReply(
+                        id =  int.from_bytes(header_d[(T_ICMPV6_IDENT, 1)][0], byteorder="big" ),
+                        seq =   int.from_bytes(header_d[(T_ICMPV6_SEQNO, 1)][0], byteorder="big" ),
+                        data = header_d[(T_ICMPV6_PAYLOAD, 1)][0])
+                elif icmp_type == 128: #icmpv6_types[T_ICMPV6_TYPE_ECHO_REQUEST]:
+                    IPv6Src = AppStr
+                    IPv6Dst = DevStr 
+                    ICMPv6Header = ICMPv6EchoRequest(
+                        id =  int.from_bytes(header_d[(T_ICMPV6_IDENT, 1)][0], byteorder="big" ),
+                        seq =   int.from_bytes(header_d[(T_ICMPV6_SEQNO, 1)][0], byteorder="big" ),
+                        data = header_d[(T_ICMPV6_PAYLOAD, 1)][0])
+                else:
+                    print ("ICMPv6 not covered")
+                    ICMPv6Header = None
+
+                L4header = ICMPv6Header
 
             elif ipv6_next == 17: # UDP
                 dev_port = header_d[(T_UDP_DEV_PORT, 1)][0]
@@ -360,8 +350,8 @@ def unparse (self, header_d, data, direction, d_rule=None, iface=None):
                     opt_val  = opt[1][0]
                     opt_len  = opt[1][1]//8
                     
-                    delta_t = coap_options[opt_name] - cumul_t
-                    cumul_t = coap_options[opt_name]
+                    delta_t = coap_options["COAP."+opt_name] - cumul_t
+                    cumul_t = coap_options["COAP."+opt_name]
                     #print (opt_name, coap_options[opt_name], delta_t)
                     
                     if delta_t < 13:
@@ -405,5 +395,10 @@ def unparse (self, header_d, data, direction, d_rule=None, iface=None):
         else:
             full_packet = L3header / Raw(load=data)
 
-        #hexdump(full_packet)
+        if full_packet and iface:
+            if verbose:
+                print ("Sending to ", iface)
+                hexdump(full_packet)
+            send(full_packet, iface=iface, verbose=False) #scapy
+
         return full_packet
diff --git a/src/frag_recv.py b/src/frag_recv.py
index 568a77f0..55b4fb01 100644
--- a/src/frag_recv.py
+++ b/src/frag_recv.py
@@ -121,7 +121,7 @@ def cancel_inactive_timer(self):
         // TODO : Redaction (here is frag_recv.py)
 
         """
-        print ("CANCEL Inactivity Timer", self.event_id_inactive_timer)
+        #print ("CANCEL Inactivity Timer", self.event_id_inactive_timer)
         if self.event_id_inactive_timer is None:
             return
 
@@ -142,7 +142,7 @@ class ReassemblerNoAck(ReassembleBase):
     // Todo : Redaction
 
     """
-    def receive_frag(self, bbuf, dtag, protocol, core_id=None, device_id=None):
+    def receive_frag(self, bbuf, dtag, protocol, core_id=None, device_id=None, iface=None, verbose=False):
         """
         return 
         - None if fragmentation is not finished
@@ -151,8 +151,8 @@ def receive_frag(self, bbuf, dtag, protocol, core_id=None, device_id=None):
         - False if abort is received
         
         """
-        dprint('state: {}, received fragment -> {}, rule-> {}'.format(self.state,
-                                                                     bbuf, self.rule))
+        #dprint('state: {}, received fragment -> {}, rule-> {}'.format(self.state,
+        #                                                             bbuf, self.rule))
         assert (T_FRAG in self.rule)
 
         if (protocol.position == T_POSITION_CORE and self.rule[T_FRAG][T_FRAG_DIRECTION] == T_DIR_DW) or\
@@ -162,39 +162,50 @@ def receive_frag(self, bbuf, dtag, protocol, core_id=None, device_id=None):
                 print ("aborting, removing state")
                 protocol.session_manager.delete_session(self._session_id)
                 print(protocol.session_manager.session_table)
-            return False
-        else:
-            print ("frag data")
-        
+            return device_id, False
+        else:        
             schc_frag = frag_msg.frag_receiver_rx(self.rule, bbuf)
-            dprint("receiver frag received:", schc_frag.__dict__)
-
-            if schc_frag.rule[T_FRAG][T_FRAG_PROF][T_FRAG_DTAG_SIZE] == 0:
-                w_dtag = '-'
-            else:
-                w_dtag = schc_frag.dtag
-
-            if schc_frag.rule[T_FRAG][T_FRAG_PROF][T_FRAG_W_SIZE] == 0:
-                w_w = '-'
-            else:
-                w_w = schc_frag.win
+            #dprint("receiver frag received:", schc_frag.__dict__)
 
-            all1 = 2**self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_FCN]-1
-            if schc_frag.fcn == all1:
-                w_fcn = "All-1"
-            elif schc_frag.fcn == 0:
-                w_fcn = "All-0"
-            else:
-                w_fcn = schc_frag.fcn
+            if verbose:
+                if schc_frag.rule[T_FRAG][T_FRAG_PROF][T_FRAG_DTAG_SIZE] == 0:
+                    w_dtag = '-'
+                else:
+                    w_dtag = schc_frag.dtag
 
-            dtrace ("\t\t\tr:{}/{} (noA) DTAG={} W={} FCN={}".format(
-                schc_frag.rule[T_RULEID],
-                schc_frag.rule[T_RULEIDLENGTH],
-                w_dtag,
-                w_w,
-                w_fcn
-                ))
+                if schc_frag.rule[T_FRAG][T_FRAG_PROF][T_FRAG_W_SIZE] == 0:
+                    w_w = '-'
+                else:
+                    w_w = schc_frag.win
 
+                all1 = 2**self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_FCN]-1
+                if schc_frag.fcn == all1:
+                    w_fcn = "All-1"
+                elif schc_frag.fcn == 0:
+                    w_fcn = "All-0"
+                else:
+                    w_fcn = schc_frag.fcn
+
+                if protocol.position == T_POSITION_CORE:
+                    print ("|--{:3}--> r:{}/{} (noA) DTAG={} W={} FCN={}".format(
+                        len(schc_frag.packet_bbuf._content),
+                        schc_frag.rule[T_RULEID],
+                        schc_frag.rule[T_RULEIDLENGTH],
+                        w_dtag,
+                        w_w,
+                        w_fcn
+                        ))
+                elif protocol.position == T_POSITION_DEVICE:
+                    print ("r:{}/{} (noA) DTAG={} W={} FCN={}|<--{:3}--".format(
+                        schc_frag.rule[T_RULEID],
+                        schc_frag.rule[T_RULEIDLENGTH],
+                        w_dtag,
+                        w_w,
+                        w_fcn, 
+                        len(schc_frag.packet_bbuf._content)                        
+                        ))
+                else:
+                    print ("Unknown position to display fragment.")
             # XXX how to authenticate the message from the peer. without
             # authentication, any nodes can cancel the invactive timer.
             self.cancel_inactive_timer()
@@ -203,9 +214,9 @@ def receive_frag(self, bbuf, dtag, protocol, core_id=None, device_id=None):
             if schc_frag.abort == True:
                 dprint("----------------------- Sender-Abort ---------------------------")
                 # XXX needs to release all resources.
-                return False
+                return device_id, False
             self.tile_list.append(schc_frag.payload)
-            print (self.tile_list)
+            #print (self.tile_list)
             #
             if schc_frag.fcn == frag_msg.get_fcn_all_1(self.rule):
                 dprint("----------------------- Final Reassembly -----------------------")
@@ -217,7 +228,7 @@ def receive_frag(self, bbuf, dtag, protocol, core_id=None, device_id=None):
                 schc_packet = BitBuffer()
                 for i in self.tile_list:
                     schc_packet += i
-                dtrace (binascii.hexlify(schc_packet.get_content()))
+                #dtrace (binascii.hexlify(schc_packet.get_content()))
 
                 mic_calced = self.get_mic(schc_packet.get_content())
                 if schc_frag.mic != mic_calced:
@@ -231,28 +242,22 @@ def receive_frag(self, bbuf, dtag, protocol, core_id=None, device_id=None):
                         schc_frag.mic, mic_calced))
                     #return schc_packet.get_content()
                 # decompression
-                print("----------------------- Decompression -----------------------")
-
-                args = False 
-                if not self.protocol.config.get("debug-fragment"):
-                    # XXX
-                    # XXX in hack105, we have separate databases for C/D and F/R.
-                    # XXX need to merge them into one.  Then, here searching database will
-                    # XXX be moved into somewhere.
-                    # XXX
-                    rule = self.protocol.rule_manager.FindRuleFromSCHCpacket(schc=schc_packet, device=device_id)
-                    dprint("debug: No-ack FindRuleFromSCHCpacket", rule, device_id)
-                    args = self.protocol.decompress_only(schc_packet, rule, device_id)
-                print("Packet decompressed at receive_frag: ", args)
+                #print("----------------------- Decompression -----------------------")
+
+                dev_id  = None 
+                pkt = False
+                rule = self.protocol.rule_manager.FindRuleFromSCHCpacket(schc=schc_packet, device=device_id)
+                #print("debug: No-ack FindRuleFromSCHCpacket", rule, device_id)
+                dev_id, pkt = self.protocol.decompress_only(schc_packet, rule, device_id, iface=iface)
                 self.state = 'DONE_NO_ACK'
                 self.protocol.session_manager.delete_session(self._session_id)
-                dprint(self.state)
-                return args  # all-1 return the packet reassembled and fragmented or False
+                #print('@', self.state)
+                return dev_id, pkt  # all-1 return the packet reassembled and fragmented or False
             # set inactive timer.
             #self.event_id_inactive_timer = self.protocol.scheduler.add_event(
             #        self.inactive_timer, self.event_inactive, tuple())
-            dprint("---", schc_frag.fcn)
-            return None
+            #dprint("---", schc_frag.fcn)
+            return device_id, None
 
 
     def get_state_info(self, **kw):
diff --git a/src/frag_send.py b/src/frag_send.py
index bbe8e260..3b581b26 100644
--- a/src/frag_send.py
+++ b/src/frag_send.py
@@ -57,11 +57,12 @@ def __init__(self, rule, mtu_in_bytes, protocol=None, context=None, dtag=None):
         self.number_of_ack_waits = 0
         self.sender_abort_sent = False
         self.last_send_time = None
+        self.verbose = None
 
     def set_packet(self, packet_bbuf):
         """ store the packet of bitbuffer for later use,
         return dtag for the packet """
-        packet_bbuf.display()
+        #packet_bbuf.display()
         self.packet_bbuf = packet_bbuf.copy()
         self.mic_base = packet_bbuf.copy()
         # XXX:remove - dtag management is in protocol.py:
@@ -171,10 +172,10 @@ def set_packet(self, packet_bbuf):
         # because draft-18 requires that in No-ACK mode, each fragment must
         # contain exactly one tile and the tile size must be at least the size
         # of an L2 Word.
-        print(self.rule)
+        #print(self.rule)
         min_size = (frag_msg.get_sender_header_size(self.rule) +
                         frag_msg.get_mic_size(self.rule) + self.l2word)   
-        print ('MTU = ', self.protocol.connectivity_manager.get_mtu("toto"), min_size)
+        #print ('MTU = ', self.protocol.connectivity_manager.get_mtu("toto"), min_size)
         if self.protocol.connectivity_manager.get_mtu("toto") < min_size:
             raise ValueError("the MTU={} is not enough to carry the SCHC fragment of No-ACK mode={}".format(self.mtu, min_size))
 
@@ -198,11 +199,11 @@ def send_frag(self):
         #                                                       |<- L2 Word
         mtu = self.protocol.connectivity_manager.get_mtu("toto")
         mtu = self.protocol.layer2.get_mtu_size()
-        print("MTU = ", mtu)
+        #print("MTU = ", mtu)
         payload_size = (mtu - frag_msg.get_sender_header_size(self.rule))
         remaining_data_size = self.packet_bbuf.count_remaining_bits()
         if remaining_data_size >= payload_size:
-            dprint("----------------------- Fragmentation process -----------------------")
+            #dprint("----------------------- Fragmentation process -----------------------")
             # put remaining_size of bits of packet into the tile.
             tile = self.packet_bbuf.get_bits_as_buffer(payload_size)
 
@@ -215,7 +216,7 @@ def send_frag(self):
                 Statsct.set_msg_type("SCHC_FRAG")
                 Statsct.set_header_size(frag_msg.get_sender_header_size(self.rule))
         elif remaining_data_size < payload_size:
-            dprint("----------------------- Fragmentation process -----------------------")
+            #dprint("----------------------- Fragmentation process -----------------------")
             if remaining_data_size <= (
                     payload_size - frag_msg.get_mic_size(self.rule)):
                 tile = None
@@ -264,45 +265,56 @@ def send_frag(self):
             dest = self._session_id[1] # device address
 
         args = (schc_frag.packet.get_content(), dest)
-        dprint ("dbug: frag_send.py: Fragment args", args)
-        dprint("frag sent:", schc_frag.__dict__)
-        if self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_DTAG_SIZE] == 0:
-            w_dtag = '-'
-        else:
-            w_dtag = schc_frag.dtag
+        #dprint ("dbug: frag_send.py: Fragment args", args)
+        #dprint("frag sent:", schc_frag.__dict__)
+    
+
+        if self.verbose:
+            if self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_DTAG_SIZE] == 0:
+                w_dtag = '-'
+            else:
+                w_dtag = schc_frag.dtag
+
+            if self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_W_SIZE] == 0:
+                w_w = '-'
+            else:
+                w_w = schc_frag.win
+
+            all1 = 2**self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_FCN]-1
+            if schc_frag.fcn == all1:
+                w_fcn = "All-1"
+            elif schc_frag.fcn == 0:
+                w_fcn = "All-0"
+            else:
+                w_fcn = schc_frag.fcn
+
+            if self.protocol.position == T_POSITION_CORE:
+                print ("<--{:3}--| r:{}/{} (noA) DTAG={} W={} FCN={}  ".format(
+                    len(schc_frag.packet._content),
+                    self.rule[T_RULEID],
+                    self.rule[T_RULEIDLENGTH],
+                    w_dtag,
+                    w_w,
+                    w_fcn
+                    ))
+            elif self.protocol.position == T_POSITION_DEVICE:
+                print ("r:{}/{} (noA) DTAG={} W={} FCN={}  |--{:3}-->".format(
+                    self.rule[T_RULEID],
+                    self.rule[T_RULEIDLENGTH],
+                    w_dtag,
+                    w_w,
+                    w_fcn,
+                    len(schc_frag.packet._content)
+                    ))
+            else:
+                print("Unknown position to display frag")
 
-        if self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_W_SIZE] == 0:
-            w_w = '-'
-        else:
-            w_w = schc_frag.win
 
-        all1 = 2**self.rule[T_FRAG][T_FRAG_PROF][T_FRAG_FCN]-1
-        if schc_frag.fcn == all1:
-            w_fcn = "All-1"
-        elif schc_frag.fcn == 0:
-            w_fcn = "All-0"
-        else:
-            w_fcn = schc_frag.fcn
-
-        dtrace ("r:{}/{} (noA) DTAG={} W={} FCN={}".format(
-            self.rule[T_RULEID],
-            self.rule[T_RULEIDLENGTH],
-            w_dtag,
-            w_w,
-            w_fcn
-            ))
-        dtrace ("|----{:3}------------->".format(len(schc_frag.packet._content)))
-        print("frag_send.py, NoAck, args: ", args)
-        print("frag_send.py, _session_id: ", self._session_id)
-        print("FCN size=", fcn)
-        print('dtag', frag_msg.get_max_dtag(self.rule))
-        print('dtag', frag_msg.get_max_fcn(self.rule))
-        print("session_id", self._session_id)
         self.protocol.scheduler.add_event(0, self.protocol.layer2.send_packet,
                                           args, session_id = self._session_id) # Add session_id
 
     def event_sent_frag(self, status=0): # status == nb actually sent (for now)
-        print("event_sent_frag")
+        #print("event_sent_frag")
         # delay = 10 #self.protocol.config.get("tx_interval", 0)
         delay = self.protocol.config.get("tx_interval", 0)
         self.protocol.scheduler.add_event(delay, self.send_frag, {})
diff --git a/src/gen_bitarray.py b/src/gen_bitarray.py
index 2f5deb5b..e159c090 100644
--- a/src/gen_bitarray.py
+++ b/src/gen_bitarray.py
@@ -119,6 +119,7 @@ def add_bits(self, bits_as_long, nb_bits, position=None):
         if position == None:
             for i in range(nb_bits, 0, -1):
                 self.set_bit(bits_as_long & (0x01 << (i-1)))
+
         else:
             for i in range(0, nb_bits):
                 self.set_bit(bits_as_long & (0x01 << (nb_bits-i -1)), position=position+i)
@@ -152,10 +153,10 @@ def add_length(self, size):
 
         """
         if size < 0xF:
-            print ("size =======>", size)
+            #print ("size =======>", size)
             self.add_bits(size, 4)
         elif size < 0xFF:
-            print ("size =================>", size)
+            #print ("size =================>", size)
             self.add_bits(0x0F, 4)
             self.add_bits(size, 8)
         elif size < 0xFFFF:
@@ -166,7 +167,6 @@ def add_length(self, size):
          
     def get_length (self):
         val = self.get_bits(4)
-        print ("read length =", val)
         if val == 0xF:
             val = self.get_bits(8)
             if val == 0xFF:
@@ -231,12 +231,12 @@ def get_remaining_content(self):
 
         while self._wpos - self._rpos >= 8:
             x = self.get_bits(nb_bits=8)
-            print (hex(x))
+            #print (hex(x))
             res.append(x)
 
         return res
 
-#to be optimized
+# Used by test procedures
     def get_bits_as_buffer(self, nb_bits=None):
         """ _rpos does change.
         If nb_bits is None, return all remaining bits.
@@ -284,6 +284,8 @@ def to_bit_list(self, position=None):
             bit_list.append(self.get_bits(1, i))
         return bit_list
 
+# 
+
     def display(self, format=None, file=sys.stdout):
         """ Display the content, if format is set to "bin" the 
         buffer is in binary, underline shows its size.
diff --git a/src/gen_parameters.py b/src/gen_parameters.py
index 29692a57..b7b91477 100644
--- a/src/gen_parameters.py
+++ b/src/gen_parameters.py
@@ -56,26 +56,26 @@
 T_COAP_MID = "COAP.MID"
 T_COAP_TOKEN = "COAP.TOKEN"
 # CoAP options string (written exactly as in standards)
-T_COAP_OPT_IF_MATCH =  "COAP.If-Match"
-T_COAP_OPT_URI_HOST = "COAP.Uri-Host"
-T_COAP_OPT_ETAG = "COAP.ETag"
-T_COAP_OPT_IF_NONE_MATCH =  "COAP.If-None-Match"
-T_COAP_OPT_OBS =  "COAP.Observe"
-T_COAP_OPT_URI_PORT =  "COAP.Uri-Port"
-T_COAP_OPT_LOC_PATH = "COAP.Location-Path"
-T_COAP_OPT_URI_PATH =  "COAP.Uri-Path"
-T_COAP_OPT_CONT_FORMAT =  "COAP.Content-Format"
-T_COAP_OPT_MAX_AGE =  "COAP.Max-Age"
-T_COAP_OPT_URI_QUERY =  "COAP.Uri-Query"
-T_COAP_OPT_ACCEPT =  "COAP.Accept"
-T_COAP_OPT_LOC_QUERY =  "COAP.Location-Query"
-T_COAP_OPT_BLOCK2 =  "COAP.Block2"
-T_COAP_OPT_BLOCK1 =  "COAP.Block1"
-T_COAP_OPT_SIZE2 =  "COAP.Size2"
-T_COAP_OPT_PROXY_URI =  "COAP.Proxy-Uri"
-T_COAP_OPT_PROXY_SCHEME =  "COAP.Proxy-Scheme"
-T_COAP_OPT_SIZE1 =  "COAP.Size1"
-T_COAP_OPT_NO_RESP = "COAP.No-Response"
+T_COAP_OPT_IF_MATCH =  "COAP.IF-MATCH"
+T_COAP_OPT_URI_HOST = "COAP.URI-HOST"
+T_COAP_OPT_ETAG = "COAP.ETAG"
+T_COAP_OPT_IF_NONE_MATCH =  "COAP.IF-NONE-MATCH"
+T_COAP_OPT_OBS =  "COAP.OBSERVE"
+T_COAP_OPT_URI_PORT =  "COAP.URI-PORT"
+T_COAP_OPT_LOC_PATH = "COAP.LOCATION-PATH"
+T_COAP_OPT_URI_PATH =  "COAP.URI-PATH"
+T_COAP_OPT_CONT_FORMAT =  "COAP.CONTENT-FORMAT"
+T_COAP_OPT_MAX_AGE =  "COAP.MAX-AGE"
+T_COAP_OPT_URI_QUERY =  "COAP.URI-QUERY"
+T_COAP_OPT_ACCEPT =  "COAP.ACCEPT"
+T_COAP_OPT_LOC_QUERY =  "COAP.LOCATION-QUERY"
+T_COAP_OPT_BLOCK2 =  "COAP.BLOCK2"
+T_COAP_OPT_BLOCK1 =  "COAP.BLOCK1"
+T_COAP_OPT_SIZE2 =  "COAP.SIZE2"
+T_COAP_OPT_PROXY_URI =  "COAP.PROXY-URI"
+T_COAP_OPT_PROXY_SCHEME =  "COAP.PROXY-SCHEME"
+T_COAP_OPT_SIZE1 =  "COAP.SIZE1"
+T_COAP_OPT_NO_RESP = "COAP.NO-RESPONSE"
 T_COAP_OPT_END = "COAP.End"
 
 T_FUNCTION_VAR = "var"
@@ -295,6 +295,14 @@
 def adapt_value(value, length=None, FID=None): 
     """transform any value of any type in the smallest bytearray.
     FID allows to convert properly the string to IPv6 address."""
+
+    if type(value) is list:
+        result = []
+        for e in value:
+            result.append(adapt_value(e, length, FID))
+
+        return value
+    
     if type(value) is int:
 
         if FID in [T_IPV6_APP_IID, T_IPV6_APP_PREFIX, T_IPV6_DEV_IID, T_IPV6_DEV_PREFIX] and length != None:
@@ -333,5 +341,7 @@ def adapt_value(value, length=None, FID=None):
             return value.encode()              
     elif type(value) is bytes:
         return value
+    elif value == None:
+        return None
     else:
         raise ValueError("Unknown type", type(value))
diff --git a/src/gen_rulemanager.py b/src/gen_rulemanager.py
index 376cb4c5..584d4c80 100644
--- a/src/gen_rulemanager.py
+++ b/src/gen_rulemanager.py
@@ -321,8 +321,10 @@ class IPv6address:
     T_COAP_CODE            : {"FL": 8,  "TYPE": int, "ALGO": "DIRECT"  },
     T_COAP_MID             : {"FL": 16,  "TYPE": int, "ALGO": "DIRECT"  },
     T_COAP_TOKEN           : {"FL": "tkl",  "TYPE": int, "ALGO": "DIRECT"  },
+    T_COAP_OPT_URI_HOST    : {"FL": "var", "TYPE": str, "ALGO": "COAP_OPTION" },
     T_COAP_OPT_URI_PATH    : {"FL": "var", "TYPE": str, "ALGO": "COAP_OPTION" },
     T_COAP_OPT_CONT_FORMAT : {"FL": "var", "TYPE": int, "ALGO": "COAP_OPTION"},
+    T_COAP_OPT_ACCEPT      : {"FL": "var", "TYPE": int, "ALGO": "COAP_OPTION"},
     T_COAP_OPT_URI_QUERY   : {"FL": "var", "TYPE": str, "ALGO": "COAP_OPTION" },
     T_COAP_OPT_NO_RESP     : {"FL": "var", "TYPE": int, "ALGO": "COAP_OPTION"}
 }
@@ -396,7 +398,7 @@ def Add(self, device=None, dev_info=None, file=None, compression=True):
             self._ctxt.append(d)
 
         d[T_META] = {T_LAST_USED: None}
-        print ("@@@@@", d)
+        #print ("@@@@@", d)
 
         for n_rule in sor:
             if T_RULEID in n_rule:
@@ -481,7 +483,7 @@ def _default_value (ar, nr, idx, default=None, failed=False):
                 if nrule[T_FRAG][T_FRAG_MODE] == T_FRAG_NO_ACK:
                     _default_value(arule, nrule, T_FRAG_DTAG_SIZE, 2)
                     _default_value (arule, nrule, T_FRAG_W_SIZE, 0)
-                    _default_value (arule, nrule, T_FRAG_FCN, 3)
+                    _default_value (arule, nrule, T_FRAG_FCN, 1)
                     _default_value(arule, nrule, T_FRAG_L2WORDSIZE, 8)
                 elif nrule[T_FRAG][T_FRAG_MODE] == T_FRAG_ACK_ALWAYS:
                     _default_value (arule, nrule, T_FRAG_W_SIZE, 1)
@@ -557,13 +559,13 @@ def _create_compression_rule (self, nrule, device_id = None):
                 # which is still generated by the parser but was not handled by this code.
                 warnings.warn("Note: T_COAP_OPT_END is ignored")
                 continue
-            if not r["FID"] in FIELD__DEFAULT_PROPERTY:
+            if not r["FID"].upper() in FIELD__DEFAULT_PROPERTY:
                 raise ValueError( "Unkwown field id {} in rule {}/{}".format(
                     r["FID"], arule[T_RULEID],  arule[T_RULEIDLENGTH]
                 ))
 
             entry = {}
-            FID = r[T_FID]
+            FID = r[T_FID].upper()
             entry[T_FID] = FID
             entry[T_FL] = self._return_default(r, T_FL, FIELD__DEFAULT_PROPERTY[FID][T_FL])
             entry[T_FP] = self._return_default(r, T_FP, 1)
@@ -773,31 +775,38 @@ def MO_EQUAL (self, TV, FV,  rlength, flength, arg, direction=None):
         return True
 
     def MO_MSB (self, TV, FV, rlength, flength, arg, direction=None):
-        print ("MSB")
-        print (TV, FV, rlength, flength, arg)
+        #print ("MSB")
+        #print (TV, FV, rlength, flength, arg)
 
         if rlength == T_FUNCTION_VAR:
             rlength = flength
 
         ignore_bit = rlength - arg
 
-        for b in range(arg):
+        for b in range(ignore_bit, rlength):
             pos = b%8
             byte_pos = b//8
 
-            right_byte_tv = TV[byte_pos]
-            right_byte_fv = FV[byte_pos]
+            if byte_pos < len(TV):
+                right_byte_tv = TV[byte_pos]
+            else:
+                right_byte_tv = 0
+
+            if byte_pos < len (FV):
+                right_byte_fv = FV[byte_pos]
+            else:
+                right_byte_fv = 0
 
-            bit_tv = right_byte_tv & (1 << (7 -pos))
-            bit_fv = right_byte_fv & (1 << (7 -pos))
+            bit_tv = right_byte_tv & (1 << pos)
+            bit_fv = right_byte_fv & (1 << pos)
 
-            print (b, pos, ignore_bit,'|', TV, FV, '|', right_byte_tv, right_byte_fv, '-',bit_tv, bit_fv)
+            #print (b, pos, ignore_bit,'|', TV, FV, '|', right_byte_tv, right_byte_fv, '-',bit_tv, bit_fv)
 
             if bit_tv != bit_fv:
-                print ("comparison failed")
+                #print ("comparison failed")
                 return False
                 
-        print ("comparison succeeded")
+        #print ("comparison succeeded")
         return True
 
 
@@ -836,6 +845,9 @@ def FindRuleFromSCHCpacket (self, schc, device=None):
         beginning of the SCHC packet.
         """
 
+        if type(schc) is bytes:
+            schc = BitBuffer(schc)
+
         for d in self._ctxt:
             dprint (d["DeviceID"])
             if d["DeviceID"] == device: #look for a specific device
@@ -860,10 +872,12 @@ def FindRuleFromPacket(self, pkt, direction=T_DIR_BI, failed_field=False):
                 if "Compression" in rule:
                     matches = 0
                     for r in rule["Compression"]:
-                        print(r)
-                        #print (pkt[(r[T_FID], r[T_FP])][0])
+                        if failed_field:
+                            print(r)
                         if r[T_DI] == T_DIR_BI or r[T_DI] == direction:
                             if (r[T_FID], r[T_FP]) in pkt:
+                                #print (pkt[(r[T_FID], r[T_FP])][0])
+
                                 if T_MO_VAL in r:
                                     arg = r[T_MO_VAL]
                                 else:
@@ -876,12 +890,21 @@ def FindRuleFromPacket(self, pkt, direction=T_DIR_BI, failed_field=False):
                                         matches += 1
                                 else:
                                     if failed_field:
-                                        print("rule {}/{}: field {}  does not match TV={} FV={} rlen={} flen={} arg={}".format(
-                                            rule[T_RULEID], rule[T_RULEIDLENGTH],
-                                            r[T_FID],
-                                            r[T_TV], pkt[(r[T_FID], r[T_FP])][0],
-                                            r[T_FL], pkt[(r[T_FID], r[T_FP])][1],
-                                            arg))
+                                        if type(r[T_TV]) is bytes:
+                                            print("rule {}/{}: field {}  does not match TV={} FV={} rlen={} flen={} arg={}".format(
+                                                rule[T_RULEID], rule[T_RULEIDLENGTH],
+                                                r[T_FID],
+                                                binascii.hexlify(r[T_TV]), 
+                                                binascii.hexlify(pkt[(r[T_FID], r[T_FP])][0]),
+                                                r[T_FL], pkt[(r[T_FID], r[T_FP])][1],
+                                                arg))
+                                        elif type(r[T_TV]) is list:
+                                            print("rule {}/{}: field {}  FV={} not in matching list rlen={} flen={} arg={}".format(
+                                                rule[T_RULEID], rule[T_RULEIDLENGTH],
+                                                r[T_FID],
+                                                binascii.hexlify(pkt[(r[T_FID], r[T_FP])][0]),
+                                                r[T_FL], pkt[(r[T_FID], r[T_FP])][1],
+                                                arg))                                           
                                     break # field does not match, rule does not match
                             else:
                                 if r[T_FL] == "var":  # entry not found, but variable length => accept
@@ -890,8 +913,8 @@ def FindRuleFromPacket(self, pkt, direction=T_DIR_BI, failed_field=False):
                                 else:
                                     dprint("field from rule not found in pkt")
                                     break # field from rule not found in pkt, go to next
-                            print ("->", matches)
-                    print("-"*10, "matches:", matches, len(pkt), rule[T_META][T_UP_RULES], rule[T_META][T_DW_RULES])
+                            #print ("->", matches)
+                    #print("-"*10, "matches:", matches, len(pkt), rule[T_META][T_UP_RULES], rule[T_META][T_DW_RULES])
                     if direction == T_DIR_UP and matches == rule[T_META][T_UP_RULES]: return rule
                     if direction == T_DIR_DW and matches == rule[T_META][T_DW_RULES]: return rule
         return None
diff --git a/src/protocol.py b/src/protocol.py
index 2a46f129..ac5fc203 100644
--- a/src/protocol.py
+++ b/src/protocol.py
@@ -104,8 +104,8 @@ def create_reassembly_session(self, context, rule, session_id): #TODO
         print("protocol.py : create_reassembly_session, core_id, device_id", core_id, device_id)
         return session
 
-    def create_fragmentation_session(self, core_id, device_id, context, rule):
-        print("create frag session: core_id, device_id", core_id, device_id )
+    def create_fragmentation_session(self, core_id, device_id, context, rule,verbose=None):
+        #print("create frag session: core_id, device_id", core_id, device_id )
         if self.unique_peer:
             l2_address = None #TODO
 
@@ -124,10 +124,10 @@ def create_fragmentation_session(self, core_id, device_id, context, rule):
             self.protocol.log("cannot create session, no dtag available")
             return None
         
-        dprint("protocol.py: creating frag_session with session_id: ", session_id)
+        #dprint("protocol.py: creating frag_session with session_id: ", session_id)
 
         mode = rule[T_FRAG][T_FRAG_MODE]
-        print ('fragmentation mode:' , mode)
+        #print ('fragmentation mode:' , mode)
         if mode == T_FRAG_NO_ACK:
             session = FragmentNoAck(rule, 12, self.protocol, context, dtag) #TODO : refactor MTU
         elif mode == T_FRAG_ACK_ALWAYS:
@@ -139,6 +139,9 @@ def create_fragmentation_session(self, core_id, device_id, context, rule):
             # see above for param order
         else:
             raise ValueError("invalid FRMode: {}".format(mode))
+        
+        session.verbose = verbose
+
         self._add_session(session_id, session)        
         setattr(session, "_session_id", session_id)
         return session
@@ -155,16 +158,35 @@ class SCHCProtocol:
 
     """
 
-    def __init__(self, layer2, system, role, config={},  layer3=None,  unique_peer=False, verbose=True):
-        print("role at protocol.py", role)
+
+    def __init__(self, layer2=None, system=None, role=None, config={}, tunnel=None, layer3=None,  unique_peer=False, verbose=True):
         assert role in [T_POSITION_CORE, T_POSITION_DEVICE]
         self.config = config
         self.unique_peer = unique_peer
         self.role = role # should be remove for position
         self.position = self.role #position gives if the SCHC is for device or core to define UP and DOWN
-        self.system = system
-        self.scheduler = system.get_scheduler()
-        self.layer2 = layer2
+
+        if system:
+            self.system = system
+
+        if layer2:
+            self.layer2 = layer2 # old stuff to be removed
+        else: # use a L2 connectio by default
+            import basic_connection
+            import socket 
+
+            if tunnel is None:
+                self.tunnel = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+                self.tunnel.bind(("0.0.0.0", 0x5C4C))
+            else:
+                self.tunnel = tunnel
+
+            self.layer2 = basic_connection.ScapyLowerLayer(position=role, socket=self.tunnel, other_end=None)
+            self.system = basic_connection.ScapySystem()
+
+        self.scheduler = self.system.get_scheduler()
+
+
         self.layer2._set_protocol(self)
         self.compressor = Compressor(self)
         self.decompressor = Decompressor(self)
@@ -201,14 +223,16 @@ def set_l2_send_fct(self, fct):
 
     def get_system(self):
         return self.system
+    
+    def get_tunnel(self):
+        return self.tunnel
 
     #CLEANUP remove dst_l3_address
-    def _apply_compression(self, device_id, raw_packet, parsing=None, reverse_direction=False):
+    def _apply_compression(self, device_id, raw_packet, parsing=None, reverse_direction=False, verbose=False):
         """Apply matching compression rule if one exists.
         
         In any case return a SCHC packet (compressed or not) as a BitBuffer
         """
-        #context = self.rule_manager.find_context_bydstiid(dst_l3_address)
         # Parse packet as IP packet and apply compression rule
         P = Parser(self)
         if self.position == T_POSITION_CORE:
@@ -217,51 +241,53 @@ def _apply_compression(self, device_id, raw_packet, parsing=None, reverse_direct
             t_dir = T_DIR_UP
         else:
             raise ValueError ("Unknown position")
-        
+
+
         if reverse_direction:
             if t_dir == T_DIR_DW:
                 t_dir = T_DIR_UP
             else:
                 t_dir = T_DIR_DW 
 
+
         if parsing != None:
              parsed_packet, residue, parsing_error = P.parse(raw_packet, t_dir, layers=parsing)
         else: 
              parsed_packet, residue, parsing_error = P.parse(raw_packet, t_dir)
-        self._log("parser {} {} {}".format(parsed_packet, residue, parsing_error))
+        #self._log("parser {} {} {}".format(parsed_packet, residue, parsing_error))
 
         if parsed_packet is None:
+            print ("schc_send:", parsing_error)
             return BitBuffer(raw_packet), None
 
         # Apply compression rule
 
-        rule = self.rule_manager.FindRuleFromPacket(parsed_packet, direction=t_dir)
-        print("compr rule", rule)
-        self._log("compression rule {}".format(rule))
+
+        rule = self.rule_manager.FindRuleFromPacket(parsed_packet, direction=t_dir, failed_field=verbose)
         if rule is None:
             rule = self.rule_manager.FindNoCompressionRule(device_id) # /!\ SHOULD NOT WORK SINCE device_ID is not none
-            print("No Compress rule:", rule)
-            self._log("no-compression rule {}".format(rule))
 
             if rule is None:
                 # XXX: not putting any SCHC compression header? - need fix
-                self._log("rule for compression/no-compression not found")
+                if verbose:
+                    print("rule for compression/no-compression not found, abort sending.")
                 return None, device_id
-                
+
+            if verbose:
+                print ("use a no-compression rule {}/{}".format(rule[T_RULEID], rule[T_RULEIDLENGTH]))                
             schc_packet = self.compressor.no_compress(rule, raw_packet)
-            print("raw_packet", raw_packet)
             return schc_packet, device_id
 
         device_id = rule[T_META][T_DEVICEID]
+
+        if verbose:
+            print ("Use compression rule {}/{}".format(rule[T_RULEID], rule[T_RULEIDLENGTH]))
         
         schc_packet = self.compressor.compress(rule, parsed_packet, residue, t_dir, device_id)
-        dprint(schc_packet)
-        #schc_packet.display("bin")
-        self._log("compression result {}".format(schc_packet))
 
         return schc_packet, device_id
 
-    def _make_frag_session(self, core_id, device_id, direction):
+    def _make_frag_session(self, core_id, device_id, direction, verbose=None):
         print("make_frag_session, device_id: ", device_id, "core_id", core_id, "direction", direction)
         """Search a fragmentation rule, create a session for it, return None if not found"""
         frag_rule = self.rule_manager.FindFragmentationRule(
@@ -271,14 +297,15 @@ def _make_frag_session(self, core_id, device_id, direction):
             self._log("fragmentation rule not found")
             return None
         
-        print("rule_id found :", frag_rule[T_RULEID])
+        if verbose:       
+            print("rule_id found :", frag_rule[T_RULEID])
         # Perform fragmentation
         rule = frag_rule
         context = None  # LT: don't know why context is needed, should be self.rule_manager which handle the context
-        self._log("fragmentation rule_id={}".format(rule[T_RULEID]))
+        #self._log("fragmentation rule_id={}".format(rule[T_RULEID]))
 
         session = self.session_manager.create_fragmentation_session(
-            core_id, device_id, context, rule)
+            core_id, device_id, context, rule, verbose=verbose)
         if session is None:
             self._log("fragmentation session could not be created") # XXX warning
             return None
@@ -286,13 +313,13 @@ def _make_frag_session(self, core_id, device_id, direction):
         return session
 
     # CLEANUP: dst_l2 and l3 should be removed
-    def schc_send(self, raw_packet, core_id=None, device_id=None, sender_delay=0, parsing=None):
+    def schc_send(self, raw_packet, core_id=None, device_id=None, sender_delay=0, parsing=None, verbose=False):
         """Starting to send SCHC packet after called by Application.       
         If self.position is T_POSITION_DEVICE and 
         this function is for sending from device to core.
         TODO: If only compress retun True If Compres and Frag, return context
         """
-        self._log("schc_send {} {}".format(core_id, device_id))
+        #self._log("schc_send {} {}".format(core_id, device_id))
 
 	#, raw_packet))
 
@@ -303,13 +330,10 @@ def schc_send(self, raw_packet, core_id=None, device_id=None, sender_delay=0, pa
 
         self.sender_delay = sender_delay
 
+        packet_bbuf, device_id = self._apply_compression(device_id, raw_packet, parsing, verbose=verbose)
 
-                
-        packet_bbuf, device_id = self._apply_compression(device_id, raw_packet, parsing)
-        print("+++ packet_bbuf", packet_bbuf)
-        print("+++ device_id", device_id)
-        print("+++ position", self.position)
-
+        if packet_bbuf is None: # No compression rule found
+            return
 
         if self.position == T_POSITION_DEVICE:
             direction = T_DIR_UP
@@ -318,7 +342,8 @@ def schc_send(self, raw_packet, core_id=None, device_id=None, sender_delay=0, pa
             direction = T_DIR_DW
             destination = device_id
 
-        print("protocol.py, schc_send, core_id: ", core_id, "device_id: ", device_id, "sender_delay", sender_delay, "destination", destination, "position", self.position)
+        if verbose:
+            print("protocol.py, schc_send, core_id: ", core_id, "device_id: ", device_id, "length in bits", packet_bbuf.count_added_bits() )
 
         if packet_bbuf == None: # No compression rule found
             return 
@@ -326,34 +351,31 @@ def schc_send(self, raw_packet, core_id=None, device_id=None, sender_delay=0, pa
         # Start a fragmentation session from rule database
         # Check if fragmentation is needed.
         if packet_bbuf.count_added_bits() < self.connectivity_manager.get_mtu(device_id):
-            self._log("fragmentation not needed size={}".format(
-            packet_bbuf.count_added_bits()))
+            if verbose:
+                print("fragmentation not needed")
             args = (packet_bbuf.get_content(), destination)
-            print("protocol.py destination", destination)
+
             self.scheduler.add_event(0, self.layer2.send_packet, args) # XXX: what about directly send?            
-            print("AAAAA protocol.py", args)
             return 
 
-        frag_session = self._make_frag_session(core_id=core_id, device_id=device_id, direction=direction)
+        frag_session = self._make_frag_session(core_id=core_id, device_id=device_id, direction=direction, verbose=verbose)
         if frag_session is not None:
             frag_session.set_packet(packet_bbuf)
             frag_session.start_sending() 
         
         return frag_session
 
-    def schc_recv(self, schc_packet, core_id=None,  device_id=None):
-        dprint ("schc_recv, core_id: " , core_id, "device_id: " , device_id, "position:", self.position)
+    def schc_recv(self, schc_packet, core_id=None,  device_id=None, iface=None, verbose=False):
+        #dprint ("schc_recv, core_id: " , core_id, "device_id: " , device_id, "position:", self.position)
         """Receiving a SCHC packet from a lower layer."""
 
-        print("schc_packet at schc_recv", schc_packet)
         packet_bbuf = BitBuffer(schc_packet)
-        dprint('SCHC: recv from L2:', b2hex(packet_bbuf.get_content()))
 
         rule = self.rule_manager.FindRuleFromSCHCpacket(packet_bbuf, device=device_id)
 
         if rule == None:
             print ("No rule found")
-            return None
+            return (None, None)
 
         if T_COMP in rule:
             if self.position == T_POSITION_DEVICE:
@@ -369,8 +391,8 @@ def schc_recv(self, schc_packet, core_id=None,  device_id=None):
                 octet = packet_bbuf.get_bits(nb_bits=8)
                 pkt_data.append(octet)
 
-            print("The HEADER D:", header_d, pkt_data)
-            pkt = unparser.unparse(header_d, pkt_data,  direction, rule,)
+            #print("The HEADER D:", header_d, pkt_data)
+            pkt = unparser.unparse(header_d, pkt_data,  direction, rule, iface, verbose)
             return device_id, pkt
         elif T_NO_COMP in rule:
             #remove ruleID
@@ -382,20 +404,11 @@ def schc_recv(self, schc_packet, core_id=None,  device_id=None):
 
             return device_id, pkt_data
     
-        elif T_NO_COMP in rule:
-            #remove ruleID
-            ruleID = packet_bbuf.get_bits(nb_bits=rule[T_RULEIDLENGTH])
-            pkt_data = bytearray()
-            while (packet_bbuf._wpos - packet_bbuf._rpos) >= 8:
-                octet = packet_bbuf.get_bits(nb_bits=8)
-                pkt_data.append(octet)
-            return device_id, pkt_data
 
         # fragmentation rule
 
         frag_rule = rule
 
-        dtrace ('\t\t\t-----------{:3}--------->|'.format(len(packet_bbuf._content)))
 
         dtag_length = frag_rule[T_FRAG][T_FRAG_PROF][T_FRAG_DTAG_SIZE]
         if dtag_length > 0:
@@ -406,13 +419,14 @@ def schc_recv(self, schc_packet, core_id=None,  device_id=None):
         rule_id = frag_rule[T_RULEID]
         rule_id_length = frag_rule[T_RULEIDLENGTH]
         session_id = (core_id, device_id, rule_id, rule_id_length, dtag) 
-        print ("protocol.py: session_id ", session_id)
+        #print ("protocol.py: session_id ", session_id)
         session = self.session_manager.find_session(session_id)
 
         if session is not None:
-            print("{} session found".format(
-                session.get_session_type().capitalize()),
-                session.__class__.__name__)
+            #print("{} session found".format(
+            #    session.get_session_type().capitalize()),
+            #    session.__class__.__name__)
+            pass
         else:
             context = None
             session = self.session_manager.create_reassembly_session(
@@ -422,9 +436,15 @@ def schc_recv(self, schc_packet, core_id=None,  device_id=None):
         dprint("core_id, device_id:", core_id , device_id)
         dprint("device or core?", self.role) 
 
-        return session.receive_frag(bbuf=packet_bbuf, dtag=dtag, protocol=self, core_id=core_id, device_id=device_id)
+        return session.receive_frag(bbuf=packet_bbuf, 
+                                    dtag=dtag, 
+                                    protocol=self, 
+                                    core_id=core_id, 
+                                    device_id=device_id,
+                                    iface = iface,
+                                    verbose = verbose)
 
-    def decompress_only (self, packet_bbuf, rule, device_id=None): # called after reassembly      
+    def decompress_only (self, packet_bbuf, rule, device_id=None, iface=None): # called after reassembly      
 
         dprint ("debug: protocol.py, decompress_only : ", packet_bbuf, rule, device_id)
         if rule == None:
@@ -442,12 +462,12 @@ def decompress_only (self, packet_bbuf, rule, device_id=None): # called after re
             decomp = Decompressor()
             unparser = Unparser()
             header_d = decomp.decompress(schc=packet_bbuf, rule=rule, direction=direction)
-            dprint("header_d:", header_d)
+            #dprint("header_d:", header_d)
             pkt_data = bytearray()
             while (packet_bbuf._wpos - packet_bbuf._rpos) >= 8:
                 octet = packet_bbuf.get_bits(nb_bits=8)
                 pkt_data.append(octet)
-            pkt = unparser.unparse(header_d, pkt_data,  direction, rule,)
+            pkt = unparser.unparse(header_d, pkt_data,  direction, rule, iface=iface)
             return device_id, pkt
 
 


Test patch:
diff --git a/src/tests/test_compress.py b/src/tests/test_compress.py
index 54ab71e4..47d0db1b 100644
--- a/src/tests/test_compress.py
+++ b/src/tests/test_compress.py
@@ -53,3 +53,4 @@ def test_compress():
             pbis = D.decompress(schc_packet, rbis, direction=T_DIR_UP)
             pprint.pprint (v[0])
             pprint.pprint(pbis)
+