Repository: secdev/scapy

Issue:
IPv6 would be added to contrib/pim.py
The current contrib/pim.py did not support IPv6, so I update it to support IPv6.
I have upload the files(diff_pim.txt & pim6.py), could you please check it and update original?

[pim6.zip](https://github.com/secdev/scapy/files/14203330/pim6.zip)



Discussion:
Thanks for your interest in Scapy. Please provide a pull request with your modifications and corresponding unit tests. We will review then when ready.


Resolving patch:
diff --git a/scapy/contrib/pim.py b/scapy/contrib/pim.py
--- a/scapy/contrib/pim.py
+++ b/scapy/contrib/pim.py
@@ -12,9 +12,10 @@
 import struct
 from scapy.packet import Packet, bind_layers
 from scapy.fields import BitFieldLenField, BitField, BitEnumField, ByteField, \
-    ShortField, XShortField, IPField, PacketListField, \
-    IntField, FieldLenField, BoundStrLenField
+    ShortField, XShortField, IPField, IP6Field, PacketListField, \
+    IntField, FieldLenField, BoundStrLenField, MultipleTypeField
 from scapy.layers.inet import IP
+from scapy.layers.inet6 import IPv6, in6_chksum, _IPv6ExtHdr
 from scapy.utils import checksum
 from scapy.compat import orb
 from scapy.config import conf
@@ -53,8 +54,21 @@ def post_build(self, p, pay):
         """
         p += pay
         if self.chksum is None:
-            ck = checksum(p)
-            p = p[:2] + struct.pack("!H", ck) + p[4:]
+            if isinstance(self.underlayer, IP):
+                ck = checksum(p)
+                # ck = in4_chksum(103, self.underlayer, p)
+                # According to RFC768 if the result checksum is 0, it should be set to 0xFFFF  # noqa: E501
+                if ck == 0:
+                    ck = 0xFFFF
+                p = p[:2] + struct.pack("!H", ck) + p[4:]
+
+            elif isinstance(self.underlayer, IPv6) or isinstance(self.underlayer, _IPv6ExtHdr):  # noqa: E501
+                ck = in6_chksum(103, self.underlayer, p)  # noqa: E501
+                # According to RFC2460 if the result checksum is 0, it should be set to 0xFFFF  # noqa: E501
+                if ck == 0:
+                    ck = 0xFFFF
+                p = p[:2] + struct.pack("!H", ck) + p[4:]
+
         return p
 
 
@@ -170,12 +184,34 @@ class PIMv2HelloStateRefresh(_PIMv2GenericHello):
     ]
 
 
+class PIMv2HelloAddrListValue(_PIMv2GenericHello):
+    name = "PIMv2 Hello Options : Address List Value"
+    fields_desc = [
+        ByteField("addr_family", 1),
+        ByteField("encoding_type", 0),
+        IP6Field("prefix", "::"),
+    ]
+
+
+class PIMv2HelloAddrList(_PIMv2GenericHello):
+    name = "PIMv2 Hello Options : Address List"
+    fields_desc = [
+        ShortField("type", 24),
+        FieldLenField(
+            "length", None, length_of="value" , fmt="!H"
+        ),
+        PacketListField("value", PIMv2HelloAddrListValue(),
+                        PIMv2HelloAddrListValue)
+    ]
+
+
 PIMv2_HELLO_CLASSES = {
     1: PIMv2HelloHoldtime,
     2: PIMv2HelloLANPruneDelay,
     19: PIMv2HelloDRPriority,
     20: PIMv2HelloGenerationID,
     21: PIMv2HelloStateRefresh,
+    24: PIMv2HelloAddrList,
     None: _PIMv2GenericHello,
 }
 
@@ -192,7 +228,11 @@ class PIMv2JoinPruneAddrsBase(_PIMGenericTlvBase):
         BitField("wildcard", 0, 1),
         BitField("rpt", 1, 1),
         ByteField("mask_len", 32),
-        IPField("src_ip", "0.0.0.0")
+        MultipleTypeField(
+            [(IP6Field("src_ip", "::"),
+              lambda pkt: pkt.addr_family == 2)],
+            IPField("src_ip", "0.0.0.0")
+        ),
 
     ]
 
@@ -214,7 +254,11 @@ class PIMv2GroupAddrs(_PIMGenericTlvBase):
         BitField("reserved", 0, 6),
         BitField("admin_scope_zone", 0, 1),
         ByteField("mask_len", 32),
-        IPField("gaddr", "0.0.0.0"),
+        MultipleTypeField(
+            [(IP6Field("gaddr", "::"),
+              lambda pkt: pkt.addr_family == 2)],
+            IPField("gaddr", "0.0.0.0")
+        ),
         BitFieldLenField("num_joins", None, size=16, count_of="join_ips"),
         BitFieldLenField("num_prunes", None, size=16, count_of="prune_ips"),
         PacketListField("join_ips", [], PIMv2JoinAddrs,
@@ -229,7 +273,11 @@ class PIMv2JoinPrune(_PIMGenericTlvBase):
     fields_desc = [
         ByteField("up_addr_family", 1),
         ByteField("up_encoding_type", 0),
-        IPField("up_neighbor_ip", "0.0.0.0"),
+        MultipleTypeField(
+            [(IP6Field("up_neighbor_ip", "::"),
+              lambda pkt: pkt.up_addr_family == 2)],
+            IPField("up_neighbor_ip", "0.0.0.0")
+        ),
         ByteField("reserved", 0),
         FieldLenField("num_group", None, count_of="jp_ips", fmt="B"),
         ShortField("holdtime", 210),
@@ -239,5 +287,6 @@ class PIMv2JoinPrune(_PIMGenericTlvBase):
 
 
 bind_layers(IP, PIMv2Hdr, proto=103)
+bind_layers(IPv6, PIMv2Hdr, nh=103)
 bind_layers(PIMv2Hdr, PIMv2Hello, type=0)
 bind_layers(PIMv2Hdr, PIMv2JoinPrune, type=3)


Test patch:
diff --git a/test/contrib/pim.uts b/test/contrib/pim.uts
--- a/test/contrib/pim.uts
+++ b/test/contrib/pim.uts
@@ -83,33 +83,32 @@ assert (jp_pkt[PIMv2JoinPrune].jp_ips[2].prune_ips[0][PIMv2PruneAddrs].src_ip ==
 = PIMv2 Hello - build
 
 hello_delay_pkt = Ether(dst="01:00:5e:00:00:0d", src="00:d0:cb:00:ba:e4")/IP(version=4, ihl=5, tos=0xc0, id=23037, ttl=1, proto=103, src="21.21.21.21", dst="224.0.0.13")/\
-                       PIMv2Hdr(version=2, type=0, reserved=0)/\
-                       PIMv2Hello(option=[PIMv2HelloHoldtime(type=1, holdtime=105), PIMv2HelloDRPriority(type=19, dr_priority=0), 
-                                                 PIMv2HelloLANPruneDelay(type=2, value=[PIMv2HelloLANPruneDelayValue(t=0, propagation_delay=500, override_interval=2500)]),
-                                                 PIMv2HelloGenerationID(type=20, generation_id=459007194)])
+                  PIMv2Hdr(version=2, type=0, reserved=0)/\
+                  PIMv2Hello(option=[PIMv2HelloHoldtime(type=1, holdtime=105), PIMv2HelloDRPriority(type=19, dr_priority=0), 
+                  PIMv2HelloLANPruneDelay(type=2, value=[PIMv2HelloLANPruneDelayValue(t=0, propagation_delay=500, override_interval=2500)]),
+                  PIMv2HelloGenerationID(type=20, generation_id=459007194)])
 
 assert raw(hello_delay_pkt) == b'\x01\x00^\x00\x00\r\x00\xd0\xcb\x00\xba\xe4\x08\x00E\xc0\x006Y\xfd\x00\x00\x01gTm\x15\x15\x15\x15\xe0\x00\x00\r \x00\xd3p\x00\x01\x00\x02\x00i\x00\x13\x00\x04\x00\x00\x00\x00\x00\x02\x00\x04\x01\xf4\t\xc4\x00\x14\x00\x04\x1b[\xe4\xda'
 
 hello_refresh_pkt = Ether(dst="01:00:5e:00:00:0d", src="c2:01:52:72:00:00")/IP(version=4, ihl=5, tos=0xc0, id=121, ttl=1, proto=103, src="10.0.0.1", dst="224.0.0.13")/\
-                         PIMv2Hdr(version=2, type=0, reserved=0)/\
-                         PIMv2Hello(option=[PIMv2HelloHoldtime(type=1, holdtime=105), PIMv2HelloGenerationID(type=20, generation_id=3613938422),
-                                                  PIMv2HelloDRPriority(type=19, dr_priority=1), 
-                                                  PIMv2HelloStateRefresh(type=21, value=[PIMv2HelloStateRefreshValue(version=1, interval=0, reserved=0)])])
+                    PIMv2Hdr(version=2, type=0, reserved=0)/\
+                    PIMv2Hello(option=[PIMv2HelloHoldtime(type=1, holdtime=105), PIMv2HelloGenerationID(type=20, generation_id=3613938422),
+                    PIMv2HelloDRPriority(type=19, dr_priority=1), 
+                    PIMv2HelloStateRefresh(type=21, value=[PIMv2HelloStateRefreshValue(version=1, interval=0, reserved=0)])])
 
 assert raw(hello_refresh_pkt) == b'\x01\x00^\x00\x00\r\xc2\x01Rr\x00\x00\x08\x00E\xc0\x006\x00y\x00\x00\x01g\xce\x1a\n\x00\x00\x01\xe0\x00\x00\r \x00\xb3\xeb\x00\x01\x00\x02\x00i\x00\x14\x00\x04\xd7hR\xf6\x00\x13\x00\x04\x00\x00\x00\x01\x00\x15\x00\x04\x01\x00\x00\x00'
 
 = PIMv2 Join/Prune - build
 
 join_pkt = Ether(dst="01:00:5e:00:00:0d", src="c2:02:3d:80:00:01")/IP(version=4, ihl=5, tos=0xc0, id=139, ttl=1, proto=103, src="10.0.0.14", dst="224.0.0.13")/\
-             PIMv2Hdr(version=2, type=3, reserved=0)/\
-             PIMv2JoinPrune(up_addr_family=1, up_encoding_type=0, up_neighbor_ip="10.0.0.13", reserved=0, num_group=1, holdtime=210,
-                                 jp_ips=[PIMv2GroupAddrs(addr_family=1, encoding_type=0, bidirection=0, reserved=0, admin_scope_zone=0,
-                                                                  mask_len=32, gaddr="239.123.123.123", 
-                                                                  join_ips=[PIMv2JoinAddrs(addr_family=1, encoding_type=0, rsrvd=0, sparse=1, wildcard=1,
-                                                                                                  rpt=1, mask_len=32, src_ip="1.1.1.1")], 
-                                                                  prune_ips=[])
-                                           ]
-                                  )
+           PIMv2Hdr(version=2, type=3, reserved=0)/\
+           PIMv2JoinPrune(up_addr_family=1, up_encoding_type=0, up_neighbor_ip="10.0.0.13", reserved=0, num_group=1, holdtime=210,
+           jp_ips=[PIMv2GroupAddrs(addr_family=1, encoding_type=0, bidirection=0, reserved=0, admin_scope_zone=0,
+           mask_len=32, gaddr="239.123.123.123", 
+           join_ips=[PIMv2JoinAddrs(addr_family=1, encoding_type=0, rsrvd=0, sparse=1, wildcard=1,
+             rpt=1, mask_len=32, src_ip="1.1.1.1")], 
+           prune_ips=[])
+           ] )
      
 
 assert raw(join_pkt) == b'\x01\x00^\x00\x00\r\xc2\x02=\x80\x00\x01\x08\x00E\xc0\x006\x00\x8b\x00\x00\x01g\xcd\xfb\n\x00\x00\x0e\xe0\x00\x00\r#\x00Z\xe5\x01\x00\n\x00\x00\r\x00\x01\x00\xd2\x01\x00\x00 \xef{{{\x00\x01\x00\x00\x01\x00\x07 \x01\x01\x01\x01'
@@ -117,14 +116,160 @@ assert raw(join_pkt) == b'\x01\x00^\x00\x00\r\xc2\x02=\x80\x00\x01\x08\x00E\xc0\
 
 
 prune_pkt = Ether(dst="01:00:5e:00:00:0d", src="c2:02:3d:80:00:01")/IP(version=4, ihl=5, tos=0xc0, id=139, ttl=1, proto=103, src="10.0.0.2", dst="224.0.0.13")/\
-                PIMv2Hdr(version=2, type=3, reserved=0)/\
-                PIMv2JoinPrune(up_addr_family=1, up_encoding_type=0, up_neighbor_ip="10.0.0.1", reserved=0, num_group=1, holdtime=210,
-                                    jp_ips=[PIMv2GroupAddrs(addr_family=1, encoding_type=0, bidirection=0, reserved=0, admin_scope_zone=0,
-                                                                     mask_len=32, gaddr="239.123.123.123",
-                                                                     prune_ips=[PIMv2PruneAddrs(addr_family=1, encoding_type=0, rsrvd=0, sparse=0, wildcard=0, rpt=0,
-                                                                                                          mask_len=32, src_ip="172.16.40.10")])
+            PIMv2Hdr(version=2, type=3, reserved=0)/\
+            PIMv2JoinPrune(up_addr_family=1, up_encoding_type=0, up_neighbor_ip="10.0.0.1", reserved=0, num_group=1, holdtime=210,
+            jp_ips=[PIMv2GroupAddrs(addr_family=1, encoding_type=0, bidirection=0, reserved=0, admin_scope_zone=0,
+             mask_len=32, gaddr="239.123.123.123",
+             prune_ips=[PIMv2PruneAddrs(addr_family=1, encoding_type=0, rsrvd=0, sparse=0, wildcard=0, rpt=0,
+             mask_len=32, src_ip="172.16.40.10")])
                                               ]
                                     )
 
 assert raw(prune_pkt) == b'\x01\x00^\x00\x00\r\xc2\x02=\x80\x00\x01\x08\x00E\xc0\x006\x00\x8b\x00\x00\x01g\xce\x07\n\x00\x00\x02\xe0\x00\x00\r#\x00\x8f\xd8\x01\x00\n\x00\x00\x01\x00\x01\x00\xd2\x01\x00\x00 \xef{{{\x00\x00\x00\x01\x01\x00\x00 \xac\x10(\n'
 
+
+
+
+
+####################################################################################
+# IPv6 added
+####################################################################################
+
+
+= IPv6 PIMv2 Hello - instantiation
+
+hello_data6 = b'33\x00\x00\x00\r\x02\x00\x00\x00\x00\x01\x86\xddk\x80\x00\x00\x008g\x01\xfe\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x01\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r \x00\xe4G\x00\x01\x00\x02\x00i\x00\x02\x00\x04\x01\xf4\t\xc4\x00\x13\x00\x04\x00\x00\x00\x01\x00\x14\x00\x04:I\x8b\xa3\x00\x18\x00\x12\x02\x00 \x01\xa7\xff@\n"\t\x00\x00\x00\x00\x00\x00\x00\x02'
+
+hello_pkt6 = Ether(hello_data6)
+
+assert (hello_pkt6[PIMv2Hdr].version == 2)
+assert (hello_pkt6[PIMv2Hdr].type == 0)
+assert (len(hello_pkt6[PIMv2Hello].option) == 5)
+assert (hello_pkt6[PIMv2Hello].option[0][PIMv2HelloHoldtime].type == 1)
+assert (hello_pkt6[PIMv2Hello].option[0][PIMv2HelloHoldtime].holdtime == 105)
+assert (hello_pkt6[PIMv2Hello].option[1][PIMv2HelloLANPruneDelay].type == 2)
+assert (hello_pkt6[PIMv2Hello].option[1][PIMv2HelloLANPruneDelay].value[0][PIMv2HelloLANPruneDelayValue].t == 0)
+assert (hello_pkt6[PIMv2Hello].option[1][PIMv2HelloLANPruneDelay].value[0][PIMv2HelloLANPruneDelayValue].propagation_delay == 500)
+assert (hello_pkt6[PIMv2Hello].option[1][PIMv2HelloLANPruneDelay].value[0][PIMv2HelloLANPruneDelayValue].override_interval == 2500)
+assert (hello_pkt6[PIMv2Hello].option[2][PIMv2HelloDRPriority].type == 19)
+assert (hello_pkt6[PIMv2Hello].option[2][PIMv2HelloDRPriority].dr_priority == 1)
+assert (hello_pkt6[PIMv2Hello].option[3][PIMv2HelloGenerationID].type == 20)
+
+repr(PIMv2HelloLANPruneDelayValue(t=1))
+
+= IPv6 PIMv2 Join/Prune - instantiation
+
+jp_data6join = b'33\x00\x00\x00\r\x02\x00\x00\x00\x00\x01\x86\xddk\x80\x00\x00\x00Fg\x01\xfe\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x01\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r#\x00\xc6X\x02\x00\xfe\x80\x00\x00\x00\x00\x00\x00\xfc\x87\xff\xff\xfe\x00\x01A\x00\x01\x00\xd2\x02\x00\x00\x80\xff>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x01\x00\x01\x00\x00\x02\x00\x04\x80$\x04\x80\x00\x00\x01\xf0\x01\x00\x00\x00\x00\x00\x00\x00\x01'
+
+jp_pkt6 = Ether(jp_data6join)
+
+assert (jp_pkt6[PIMv2Hdr].version == 2)
+assert (jp_pkt6[PIMv2Hdr].type == 3)
+assert (jp_pkt6[PIMv2JoinPrune].up_addr_family == 2)
+assert (jp_pkt6[PIMv2JoinPrune].up_encoding_type == 0)
+assert (jp_pkt6[PIMv2JoinPrune].up_neighbor_ip == 'fe80::fc87:ffff:fe00:141')
+assert (jp_pkt6[PIMv2JoinPrune].reserved == 0)
+assert (jp_pkt6[PIMv2JoinPrune].num_group == 1)
+assert (jp_pkt6[PIMv2JoinPrune].holdtime == 210)
+assert (jp_pkt6[PIMv2JoinPrune].num_group == len(jp_pkt6[PIMv2JoinPrune].jp_ips))
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].addr_family == 2)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].encoding_type == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].bidirection == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].reserved == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].admin_scope_zone == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].mask_len == 128)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].gaddr == 'ff3e::8000:1')
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].num_joins == 1)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].num_joins == len(jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips))
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips[0][PIMv2JoinAddrs].addr_family == 2)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips[0][PIMv2JoinAddrs].encoding_type == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips[0][PIMv2JoinAddrs].rsrvd == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips[0][PIMv2JoinAddrs].sparse == 1)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips[0][PIMv2JoinAddrs].wildcard == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips[0][PIMv2JoinAddrs].rpt == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips[0][PIMv2JoinAddrs].mask_len == 128)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips[0][PIMv2JoinAddrs].src_ip == '2404:8000:1:f001::1')
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].num_prunes == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].num_prunes == len(jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips))
+
+
+
+jp_data6prune = b'33\x00\x00\x00\r\x02\x00\x00\x00\x00\x01\x86\xddk\x80\x00\x00\x00Fg\x01\xfe\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x01\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r#\x00\xc6X\x02\x00\xfe\x80\x00\x00\x00\x00\x00\x00\xfc\x87\xff\xff\xfe\x00\x01A\x00\x01\x00\xd2\x02\x00\x00\x80\xff>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x01\x00\x00\x00\x01\x02\x00\x04\x80$\x04\x80\x00\x00\x01\xf0\x01\x00\x00\x00\x00\x00\x00\x00\x01'
+
+jp_pkt6 = Ether(jp_data6prune)
+
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].addr_family == 2)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].encoding_type == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].bidirection == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].reserved == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].admin_scope_zone == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].mask_len == 128)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].gaddr == 'ff3e::8000:1')
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].num_joins == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].num_joins == len(jp_pkt6[PIMv2JoinPrune].jp_ips[0].join_ips))
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].num_prunes == 1)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].num_prunes == len(jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips))
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips[0][PIMv2PruneAddrs].addr_family == 2)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips[0][PIMv2PruneAddrs].encoding_type == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips[0][PIMv2PruneAddrs].rsrvd == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips[0][PIMv2PruneAddrs].sparse == 1)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips[0][PIMv2PruneAddrs].wildcard == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips[0][PIMv2PruneAddrs].rpt == 0)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips[0][PIMv2PruneAddrs].mask_len == 128)
+assert (jp_pkt6[PIMv2JoinPrune].jp_ips[0].prune_ips[0][PIMv2PruneAddrs].src_ip == '2404:8000:1:f001::1')
+
+
+
+
+= IPv6 PIMv2 Hello - build
+
+hello_delay_pkt6 = Ether(dst='33:33:00:00:00:0d', src='02:00:00:00:00:01')/ \
+                   IPv6(tc=0xb8, nh=103, hlim=1, src='fe80::ff:fe00:1', dst='ff02::d')/ \
+                   PIMv2Hdr()/ \
+                   PIMv2Hello(option=[ \
+                    PIMv2HelloHoldtime(holdtime=105),
+                    PIMv2HelloLANPruneDelay(value=[PIMv2HelloLANPruneDelayValue(propagation_delay=500, override_interval=2500)]),
+                    PIMv2HelloDRPriority(dr_priority=1),
+                    PIMv2HelloGenerationID(generation_id=977898403),
+                    PIMv2HelloAddrList(value=[PIMv2HelloAddrListValue(addr_family=2,prefix='2001:a7ff:400a:2209::2')]),
+                  ])
+
+
+assert raw(hello_delay_pkt6) == hello_data6 
+
+
+
+
+
+= IPv6 PIMv2 Join/Prune - build
+
+     
+join_pkt6 = Ether(dst='33:33:00:00:00:0d', src='02:00:00:00:00:01')/\
+           IPv6(tc=184, nh=103, hlim=1, src='fe80::ff:fe00:1', dst='ff02::d')/ \
+           PIMv2Hdr(version=2, type=3, reserved=0)/ \
+           PIMv2JoinPrune(jp_ips=[ \
+             PIMv2GroupAddrs(join_ips=[
+               PIMv2JoinAddrs(addr_family=2, sparse=1, wildcard=0, rpt=0, mask_len=128, src_ip='2404:8000:1:f001::1')],
+               addr_family=2, admin_scope_zone=0, mask_len=128, gaddr='ff3e::8000:1',
+               num_joins=1, num_prunes=0)],
+             up_addr_family=2, up_neighbor_ip='fe80::fc87:ffff:fe00:141', num_group=1, holdtime=210)
+
+
+assert raw(join_pkt6) == jp_data6join
+
+
+
+prune_pkt6 = Ether(dst='33:33:00:00:00:0d', src='02:00:00:00:00:01')/ \
+             IPv6(tc=184, nh=103, hlim=1, src='fe80::ff:fe00:1', dst='ff02::d')/ \
+             PIMv2Hdr()/ \
+             PIMv2JoinPrune(jp_ips=[ \
+               PIMv2GroupAddrs(prune_ips=[ \
+                 PIMv2PruneAddrs(addr_family=2, sparse=1, wildcard=0, rpt=0, mask_len=128, src_ip='2404:8000:1:f001::1')],
+               addr_family=2, mask_len=128, gaddr='ff3e::8000:1',
+               num_joins=0, num_prunes=1)],
+               up_addr_family=2, up_neighbor_ip='fe80::fc87:ffff:fe00:141', num_group=1, holdtime=210)
+
+
+assert raw(prune_pkt6) == jp_data6prune
+
+