Changes v1 -> v2:

- add default args other than nd_router_advert
- correct the size of bytearray options
- add unittests about default args


I am going to add the default args to each constructor of the classes of
the packet libraries now. When length parameter is omitted, it is due to
make it calculated automatically. Since nd_router_advert class can have
multiple options, each option should calculate length automatically.

However, the args of the current nd_router_advert class consist of the
list of type, length, and data, so it is hard to calculate the length
for every option.

e.g.)
ra = icmpv6.nd_router_advert(
    0, 0, 0, 0, 0,
    [1, 3],    # <- types of each option
    [1, 4],    # <- lengths of each option
    [nd_option_la('00:00:00:00:00:00'), nd_option_pi(...)])

Therefore, I would like to change them as follows:

e.g.)
ra = icmpv6.nd_router_advert(
    0, 0, 0, 0, 0,
    [nd_option_la(1, 1, '00:00:00:00:00:00'),
     nd_option_pi(3, 4, ...)])     # <- option including type and length

In fact, the type is fixed for every class and the length is
automatically calculated, so it is as follows.

e.g.)
ra = icmpv6.nd_router_advert(
    0, 0, 0, 0, 0,
    [nd_option_sla('00:00:00:00:00:00'),
     nd_option_pi(...)])

Source code will be changed sharply.

Any comments?


Signed-off-by: Yuichi Ito <[email protected]>
---
 ryu/lib/packet/icmpv6.py             |  398 +++++++++++++++------------
 ryu/tests/unit/packet/test_icmpv6.py |  491 +++++++++++++++++++++++++++++++---
 2 files changed, 670 insertions(+), 219 deletions(-)

diff --git a/ryu/lib/packet/icmpv6.py b/ryu/lib/packet/icmpv6.py
index 4da7fa2..bda0dc0 100644
--- a/ryu/lib/packet/icmpv6.py
+++ b/ryu/lib/packet/icmpv6.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.

+import abc
 import struct
 import sys
 import array
@@ -56,6 +57,13 @@ ICMPV6_NI_REPLY = 140     # node information reply

 ICMPV6_MAXTYPE = 201

+# ND_OPTIONS from RFC 4861
+ND_OPTION_SLA = 1  # Source Link-Layer Address
+ND_OPTION_TLA = 2  # Target Link-Layer Address
+ND_OPTION_PI = 3   # Prefix Information
+ND_OPTION_RH = 4   # Redirected Header
+ND_OPTION_MTU = 5  # MTU
+

 class icmpv6(packet_base.PacketBase):
     """ICMPv6 (RFC 2463) header encoder/decoder class.
@@ -94,7 +102,7 @@ class icmpv6(packet_base.PacketBase):
             return cls
         return _register_icmpv6_type

-    def __init__(self, type_, code, csum, data=None):
+    def __init__(self, type_=0, code=0, csum=0, data=None):
         super(icmpv6, self).__init__()
         self.type_ = type_
         self.code = code
@@ -150,14 +158,8 @@ class nd_neighbor(stringify.StringifyMixin):
     res            R,S,O Flags for Neighbor Advertisement. \
                    The 3 MSBs of "Reserved" field for Neighbor Solicitation.
     dst            Target Address
-    type\_         "Type" field of the first option.  None if no options. \
-                   NOTE: This implementation doesn't support two or more \
-                   options.
-    length         "Length" field of the first option.  None if no options.
-    data           An object to describe the first option. \
-                   None if no options. \
-                   Either ryu.lib.packet.icmpv6.nd_option_la object \
-                   or a bytearray.
+    option         a derived object of ryu.lib.packet.icmpv6.nd_option \
+                   or a bytearray. None if no options.
     ============== ====================
     """

@@ -165,56 +167,44 @@ class nd_neighbor(stringify.StringifyMixin):
     _MIN_LEN = struct.calcsize(_PACK_STR)
     _ND_OPTION_TYPES = {}

-    # ND option type
-    ND_OPTION_SLA = 1  # Source Link-Layer Address
-    ND_OPTION_TLA = 2  # Target Link-Layer Address
-    ND_OPTION_PI = 3   # Prefix Information
-    ND_OPTION_RH = 4   # Redirected Header
-    ND_OPTION_MTU = 5  # MTU
-
     @staticmethod
     def register_nd_option_type(*args):
         def _register_nd_option_type(cls):
-            for type_ in args:
-                nd_neighbor._ND_OPTION_TYPES[type_] = cls
+            nd_neighbor._ND_OPTION_TYPES[cls.option_type()] = cls
             return cls
-        return _register_nd_option_type
+        return _register_nd_option_type(args[0])

-    def __init__(self, res, dst, type_=None, length=None, data=None):
-        self.res = res << 29
+    def __init__(self, res=0, dst='::', option=None):
+        self.res = res
         self.dst = dst
-        self.type_ = type_
-        self.length = length
-        self.data = data
+        self.option = option

     @classmethod
     def parser(cls, buf, offset):
         (res, dst) = struct.unpack_from(cls._PACK_STR, buf, offset)
-        msg = cls(res >> 29, addrconv.ipv6.bin_to_text(dst))
         offset += cls._MIN_LEN
+        option = None
         if len(buf) > offset:
-            (msg.type_, msg.length) = struct.unpack_from('!BB', buf, offset)
-            cls_ = cls._ND_OPTION_TYPES.get(msg.type_, None)
-            offset += 2
-            if cls_:
-                msg.data = cls_.parser(buf, offset)
+            (type_, ) = struct.unpack_from('!B', buf, offset)
+            cls_ = cls._ND_OPTION_TYPES.get(type_)
+            if cls_ is not None:
+                option = cls_.parser(buf, offset)
             else:
-                msg.data = buf[offset:]
-
+                option = buf[offset:]
+        msg = cls(res >> 29, addrconv.ipv6.bin_to_text(dst), option)
         return msg

     def serialize(self):
-        hdr = bytearray(struct.pack(nd_neighbor._PACK_STR, self.res,
-                                    addrconv.ipv6.text_to_bin(self.dst)))
-
-        if self.type_ is not None:
-            hdr += bytearray(struct.pack('!BB', self.type_, self.length))
-            if self.type_ in nd_neighbor._ND_OPTION_TYPES:
-                hdr += self.data.serialize()
-            elif self.data is not None:
-                hdr += bytearray(self.data)
-
-        return hdr
+        res = self.res << 29
+        hdr = bytearray(struct.pack(
+            nd_neighbor._PACK_STR, res,
+            addrconv.ipv6.text_to_bin(self.dst)))
+        if self.option is not None:
+            if isinstance(self.option, nd_option):
+                hdr.extend(self.option.serialize())
+            else:
+                hdr.extend(self.option)
+        return str(hdr)


 @icmpv6.register_icmpv6_type(ND_ROUTER_SOLICIT)
@@ -234,14 +224,8 @@ class nd_router_solicit(stringify.StringifyMixin):
     Attribute      Description
     ============== ====================
     res            This field is unused.  It MUST be initialized to zero.
-    type\_         "Type" field of the first option.  None if no options. \
-                   NOTE: This implementation doesn't support two or more \
-                   options.
-    length         "Length" field of the first option.  None if no options.
-    data           An object to describe the first option. \
-                   None if no options. \
-                   Either ryu.lib.packet.icmpv6.nd_option_la object \
-                   or a bytearray.
+    option         a derived object of ryu.lib.packet.icmpv6.nd_option \
+                   or a bytearray. None if no options.
     ============== ====================
     """

@@ -249,50 +233,41 @@ class nd_router_solicit(stringify.StringifyMixin):
     _MIN_LEN = struct.calcsize(_PACK_STR)
     _ND_OPTION_TYPES = {}

-    # ND option type
-    ND_OPTION_SLA = 1  # Source Link-Layer Address
-
     @staticmethod
     def register_nd_option_type(*args):
         def _register_nd_option_type(cls):
-            for type_ in args:
-                nd_router_solicit._ND_OPTION_TYPES[type_] = cls
+            nd_router_solicit._ND_OPTION_TYPES[cls.option_type()] = cls
             return cls
-        return _register_nd_option_type
+        return _register_nd_option_type(args[0])

-    def __init__(self, res, type_=None, length=None, data=None):
+    def __init__(self, res=0, option=None):
         self.res = res
-        self.type_ = type_
-        self.length = length
-        self.data = data
+        self.option = option

     @classmethod
     def parser(cls, buf, offset):
-        res = struct.unpack_from(cls._PACK_STR, buf, offset)
-        msg = cls(res)
+        (res, ) = struct.unpack_from(cls._PACK_STR, buf, offset)
         offset += cls._MIN_LEN
+        option = None
         if len(buf) > offset:
-            (msg.type_, msg.length) = struct.unpack_from('!BB', buf, offset)
-            cls_ = cls._ND_OPTION_TYPES.get(msg.type_, None)
-            offset += 2
-            if cls_:
-                msg.data = cls_.parser(buf, offset)
+            (type_, ) = struct.unpack_from('!B', buf, offset)
+            cls_ = cls._ND_OPTION_TYPES.get(type_)
+            if cls_ is not None:
+                option = cls_.parser(buf, offset)
             else:
-                msg.data = buf[offset:]
-
+                option = buf[offset:]
+        msg = cls(res, option)
         return msg

     def serialize(self):
-        hdr = bytearray(struct.pack(nd_router_solicit._PACK_STR, self.res))
-
-        if self.type_ is not None:
-            hdr += bytearray(struct.pack('!BB', self.type_, self.length))
-            if self.type_ in nd_router_solicit._ND_OPTION_TYPES:
-                hdr += self.data.serialize()
-            elif self.data is not None:
-                hdr += bytearray(self.data)
-
-        return hdr
+        hdr = bytearray(struct.pack(
+            nd_router_solicit._PACK_STR, self.res))
+        if self.option is not None:
+            if isinstance(self.option, nd_option):
+                hdr.extend(self.option.serialize())
+            else:
+                hdr.extend(self.option)
+        return str(hdr)


 @icmpv6.register_icmpv6_type(ND_ROUTER_ADVERT)
@@ -316,17 +291,9 @@ class nd_router_advert(stringify.StringifyMixin):
     rou_l          Router Lifetime.
     rea_t          Reachable Time.
     ret_t          Retrans Timer.
-    type\_         List of option type. Each index refers to an option. \
-                   None if no options. \
-                   NOTE: This implementation support one or more \
-                   options.
-    length         List of option length. Each index refers to an option. \
-                   None if no options. \
-    data           List of option data. Each index refers to an option. \
-                   None if no options. \
-                   ryu.lib.packet.icmpv6.nd_option_la object, \
-                   ryu.lib.packet.icmpv6.nd_option_pi object \
-                   or a bytearray.
+    options        List of a derived object of \
+                   ryu.lib.packet.icmpv6.nd_option or a bytearray. \
+                   None if no options.
     ============== ====================
     """

@@ -334,79 +301,129 @@ class nd_router_advert(stringify.StringifyMixin):
     _MIN_LEN = struct.calcsize(_PACK_STR)
     _ND_OPTION_TYPES = {}

-    # ND option type
-    ND_OPTION_SLA = 1  # Source Link-Layer Address
-    ND_OPTION_PI = 3   # Prefix Information
-    ND_OPTION_MTU = 5  # MTU
-
     @staticmethod
     def register_nd_option_type(*args):
         def _register_nd_option_type(cls):
-            for type_ in args:
-                nd_router_advert._ND_OPTION_TYPES[type_] = cls
+            nd_router_advert._ND_OPTION_TYPES[cls.option_type()] = cls
             return cls
-        return _register_nd_option_type
+        return _register_nd_option_type(args[0])

-    def __init__(self, ch_l, res, rou_l, rea_t, ret_t, type_=None, length=None,
-                 data=None):
+    def __init__(self, ch_l=0, res=0, rou_l=0, rea_t=0, ret_t=0, options=None):
         self.ch_l = ch_l
-        self.res = res << 6
+        self.res = res
         self.rou_l = rou_l
         self.rea_t = rea_t
         self.ret_t = ret_t
-        self.type_ = type_
-        self.length = length
-        self.data = data
+        options = options or []
+        assert isinstance(options, list)
+        self.options = options

     @classmethod
     def parser(cls, buf, offset):
-        (ch_l, res, rou_l, rea_t, ret_t) = struct.unpack_from(cls._PACK_STR,
-                                                              buf, offset)
-        msg = cls(ch_l, res >> 6, rou_l, rea_t, ret_t)
+        (ch_l, res, rou_l, rea_t, ret_t
+         ) = struct.unpack_from(cls._PACK_STR, buf, offset)
         offset += cls._MIN_LEN
-        msg.type_ = list()
-        msg.length = list()
-        msg.data = list()
+        options = []
         while len(buf) > offset:
             (type_, length) = struct.unpack_from('!BB', buf, offset)
-            msg.type_.append(type_)
-            msg.length.append(length)
-            cls_ = cls._ND_OPTION_TYPES.get(type_, None)
-            offset += 2
-            byte_len = length * 8 - 2
-            if cls_:
-                msg.data.append(cls_.parser(buf[:offset+cls_._MIN_LEN],
-                                            offset))
-                offset += cls_._MIN_LEN
+            cls_ = cls._ND_OPTION_TYPES.get(type_)
+            if cls_ is not None:
+                option = cls_.parser(buf, offset)
             else:
-                msg.data.append(buf[offset:offset + byte_len])
-                offset += byte_len
-
+                option = buf[offset:offset + (length * 8 - 2)]
+            options.append(option)
+            offset += len(option)
+        msg = cls(ch_l, res >> 6, rou_l, rea_t, ret_t, options)
         return msg

     def serialize(self):
-        hdr = bytearray(struct.pack(nd_router_advert._PACK_STR, self.ch_l,
-                                    self.res, self.rou_l, self.rea_t,
-                                    self.ret_t))
-        if self.type_ is not None:
-            for i in range(len(self.type_)):
-                hdr += bytearray(struct.pack('!BB', self.type_[i],
-                                             self.length[i]))
-                if self.type_[i] in nd_router_advert._ND_OPTION_TYPES:
-                    hdr += self.data[i].serialize()
-                elif self.data[i] is not None:
-                    hdr += bytearray(self.data[i])
+        res = self.res << 6
+        hdr = bytearray(struct.pack(
+            nd_router_advert._PACK_STR, self.ch_l, res, self.rou_l,
+            self.rea_t, self.ret_t))
+        for option in self.options:
+            if isinstance(option, nd_option):
+                hdr.extend(option.serialize())
+            else:
+                hdr.extend(option)
+        return str(hdr)

-        return hdr
+
+class nd_option(stringify.StringifyMixin):
+
+    __metaclass__ = abc.ABCMeta
+
+    @classmethod
+    @abc.abstractmethod
+    def option_type(cls):
+        pass
+
+    @abc.abstractmethod
+    def __init__(self, _type, length):
+        self._type = _type
+        self.length = length
+
+    @classmethod
+    @abc.abstractmethod
+    def parser(cls, buf):
+        pass
+
+    @abc.abstractmethod
+    def serialize(self):
+        pass
+
+    def __len__(self):
+        return self._MIN_LEN
+
+
+class nd_option_la(nd_option):
+
+    _PACK_STR = '!BB6s'
+    _MIN_LEN = struct.calcsize(_PACK_STR)
+
+    @abc.abstractmethod
+    def __init__(self, length, hw_src, data):
+        super(nd_option_la, self).__init__(self.option_type(), length)
+        self.hw_src = hw_src
+        self.data = data
+
+    @classmethod
+    def parser(cls, buf, offset):
+        (_, length, hw_src) = struct.unpack_from(cls._PACK_STR, buf, offset)
+        msg = cls(length, addrconv.mac.bin_to_text(hw_src))
+        offset += cls._MIN_LEN
+        if len(buf) > offset:
+            msg.data = buf[offset:]
+
+        return msg
+
+    def serialize(self):
+        buf = bytearray(struct.pack(
+            self._PACK_STR, self.option_type(), self.length,
+            addrconv.mac.text_to_bin(self.hw_src)))
+        if self.data is not None:
+            buf.extend(self.data)
+        mod = len(buf) % 8
+        if mod:
+            buf.extend(bytearray(8 - mod))
+        if 0 == self.length:
+            self.length = len(buf) / 8
+            struct.pack_into('!B', buf, 1, self.length)
+        return str(buf)
+
+    def __len__(self):
+        length = self._MIN_LEN
+        if self.data is not None:
+            length += len(self.data)
+        return length


-@nd_neighbor.register_nd_option_type(nd_neighbor.ND_OPTION_SLA,
-                                     nd_neighbor.ND_OPTION_TLA)
-@nd_router_solicit.register_nd_option_type(nd_router_solicit.ND_OPTION_SLA)
-@nd_router_advert.register_nd_option_type(nd_router_advert.ND_OPTION_SLA)
-class nd_option_la(stringify.StringifyMixin):
+@nd_neighbor.register_nd_option_type
+@nd_router_solicit.register_nd_option_type
+@nd_router_advert.register_nd_option_type
+class nd_option_sla(nd_option_la):
     """ICMPv6 sub encoder/decoder class for Neighbor discovery
-    Source/Target Link-Layer Address Option. (RFC 4861)
+    Source Link-Layer Address Option. (RFC 4861)

     This is used with ryu.lib.packet.icmpv6.nd_neighbor,
     ryu.lib.packet.icmpv6.nd_router_solicit or
@@ -421,6 +438,8 @@ class nd_option_la(stringify.StringifyMixin):
     ============== ====================
     Attribute      Description
     ============== ====================
+    length         length of the option. \
+                   (0 means automatically-calculate when encoding)
     hw_src         Link-Layer Address. \
                    NOTE: If the address is longer than 6 octets this contains \
                    the first 6 octets in the address. \
@@ -433,35 +452,54 @@ class nd_option_la(stringify.StringifyMixin):
     ============== ====================
     """

-    _PACK_STR = '!6s'
-    _MIN_LEN = struct.calcsize(_PACK_STR)
+    @classmethod
+    def option_type(cls):
+        return ND_OPTION_SLA

-    def __init__(self, hw_src, data=None):
-        self.hw_src = hw_src
-        self.data = data
+    def __init__(self, length=0, hw_src='00:00:00:00:00:00', data=None):
+        super(nd_option_sla, self).__init__(length, hw_src, data)

-    @classmethod
-    def parser(cls, buf, offset):
-        (hw_src, ) = struct.unpack_from(cls._PACK_STR, buf, offset)
-        msg = cls(addrconv.mac.bin_to_text(hw_src))
-        offset += cls._MIN_LEN
-        if len(buf) > offset:
-            msg.data = buf[offset:]

-        return msg
+@nd_neighbor.register_nd_option_type
+class nd_option_tla(nd_option_la):
+    """ICMPv6 sub encoder/decoder class for Neighbor discovery
+    Target Link-Layer Address Option. (RFC 4861)

-    def serialize(self):
-        hdr = bytearray(struct.pack(self._PACK_STR,
-                                    addrconv.mac.text_to_bin(self.hw_src)))
+    This is used with ryu.lib.packet.icmpv6.nd_neighbor.

-        if self.data is not None:
-            hdr += bytearray(self.data)
+    An instance has the following attributes at least.
+    Most of them are same to the on-wire counterparts but in host byte order.
+    __init__ takes the corresponding args in this order.

-        return hdr
+    .. tabularcolumns:: |l|p{35em}|

+    ============== ====================
+    Attribute      Description
+    ============== ====================
+    length         length of the option. \
+                   (0 means automatically-calculate when encoding)
+    hw_src         Link-Layer Address. \
+                   NOTE: If the address is longer than 6 octets this contains \
+                   the first 6 octets in the address. \
+                   This implementation assumes the address has at least \
+                   6 octets.
+    data           A bytearray which contains the rest of Link-Layer Address \
+                   and padding.  When encoding a packet, it's user's \
+                   responsibility to provide necessary padding for 8-octets \
+                   alignment required by the protocol.
+    ============== ====================
+    """
+
+    @classmethod
+    def option_type(cls):
+        return ND_OPTION_TLA

-@nd_router_advert.register_nd_option_type(nd_router_advert.ND_OPTION_PI)
-class nd_option_pi(stringify.StringifyMixin):
+    def __init__(self, length=0, hw_src='00:00:00:00:00:00', data=None):
+        super(nd_option_tla, self).__init__(length, hw_src, data)
+
+
+@nd_router_advert.register_nd_option_type
+class nd_option_pi(nd_option):
     """ICMPv6 sub encoder/decoder class for Neighbor discovery
     Prefix Information Option. (RFC 4861)

@@ -476,6 +514,8 @@ class nd_option_pi(stringify.StringifyMixin):
     ============== ====================
     Attribute      Description
     ============== ====================
+    length         length of the option. \
+                   (0 means automatically-calculate when encoding)
     pl             Prefix Length.
     res1           L,A,R\* Flags for Prefix Information.
     val_l          Valid Lifetime.
@@ -487,12 +527,18 @@ class nd_option_pi(stringify.StringifyMixin):
     \*R flag is defined in (RFC 3775)
     """

-    _PACK_STR = '!BBIII16s'
+    _PACK_STR = '!BBBBIII16s'
     _MIN_LEN = struct.calcsize(_PACK_STR)

-    def __init__(self, pl, res1, val_l, pre_l, res2, prefix):
+    @classmethod
+    def option_type(cls):
+        return ND_OPTION_PI
+
+    def __init__(self, length=0, pl=0, res1=0, val_l=0, pre_l=0, res2=0,
+                 prefix='::'):
+        super(nd_option_pi, self).__init__(self.option_type(), length)
         self.pl = pl
-        self.res1 = res1 << 5
+        self.res1 = res1
         self.val_l = val_l
         self.pre_l = pre_l
         self.res2 = res2
@@ -500,21 +546,23 @@ class nd_option_pi(stringify.StringifyMixin):

     @classmethod
     def parser(cls, buf, offset):
-        (pl, res1, val_l, pre_l, res2, prefix) = struct.unpack_from(cls.
-                                                                    _PACK_STR,
-                                                                    buf,
-                                                                    offset)
+        (_, length, pl, res1, val_l, pre_l, res2, prefix
+         ) = struct.unpack_from(cls._PACK_STR, buf, offset)
         msg = cls(pl, res1 >> 5, val_l, pre_l, res2,
                   addrconv.ipv6.bin_to_text(prefix))

         return msg

     def serialize(self):
-        hdr = bytearray(struct.pack(self._PACK_STR, self.pl, self.res1,
-                                    self.val_l, self.pre_l, self.res2,
-                                    addrconv.ipv6.text_to_bin(self.prefix)))
-
-        return hdr
+        res1 = self.res1 << 5
+        buf = bytearray(struct.pack(
+            self._PACK_STR, self.option_type(), self.length, self.pl,
+            res1, self.val_l, self.pre_l, self.res2,
+            addrconv.ipv6.text_to_bin(self.prefix)))
+        if 0 == self.length:
+            self.length = len(buf) / 8
+            struct.pack_into('!B', buf, 1, self.length)
+        return str(buf)


 @icmpv6.register_icmpv6_type(ICMPV6_ECHO_REPLY, ICMPV6_ECHO_REQUEST)
@@ -541,7 +589,7 @@ class echo(stringify.StringifyMixin):
     _PACK_STR = '!HH'
     _MIN_LEN = struct.calcsize(_PACK_STR)

-    def __init__(self, id_, seq, data=None):
+    def __init__(self, id_=0, seq=0, data=None):
         self.id = id_
         self.seq = seq
         self.data = data
diff --git a/ryu/tests/unit/packet/test_icmpv6.py 
b/ryu/tests/unit/packet/test_icmpv6.py
index 0a33ca0..79daed5 100644
--- a/ryu/tests/unit/packet/test_icmpv6.py
+++ b/ryu/tests/unit/packet/test_icmpv6.py
@@ -89,6 +89,15 @@ class Test_icmpv6_header(unittest.TestCase):
         m_short_buf = self.buf[1:self.icmp._MIN_LEN]
         self.icmp.parser(m_short_buf)

+    def test_default_args(self):
+        prev = ipv6()
+        ic = icmpv6.icmpv6()
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf))
+
+        eq_(res[0], 0)
+        eq_(res[1], 0)
+

 class Test_icmpv6_echo_request(unittest.TestCase):
     type_ = 128
@@ -182,6 +191,21 @@ class Test_icmpv6_echo_request(unittest.TestCase):
         eq_(str(ic), ic_str)
         eq_(repr(ic), ic_str)

+    def test_default_args(self):
+        prev = ipv6()
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ICMPV6_ECHO_REQUEST, data=icmpv6.echo())
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ICMPV6_ECHO_REQUEST)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.echo._PACK_STR, str(buf[4:]))
+
+        eq_(res[0], 0)
+        eq_(res[1], 0)
+

 class Test_icmpv6_echo_reply(Test_icmpv6_echo_request):
     def setUp(self):
@@ -189,8 +213,23 @@ class Test_icmpv6_echo_reply(Test_icmpv6_echo_request):
         self.csum = 0xa472
         self.buf = '\x81\x00\xa4\x72\x76\x20\x00\x00'

+    def test_default_args(self):
+        prev = ipv6()
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ICMPV6_ECHO_REPLY, data=icmpv6.echo())
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ICMPV6_ECHO_REPLY)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.echo._PACK_STR, str(buf[4:]))
+
+        eq_(res[0], 0)
+        eq_(res[1], 0)
+

-class Test_icmpv6_neighbor_solict(unittest.TestCase):
+class Test_icmpv6_neighbor_solicit(unittest.TestCase):
     type_ = 135
     code = 0
     csum = 0x952d
@@ -214,11 +253,9 @@ class Test_icmpv6_neighbor_solict(unittest.TestCase):

     def test_init(self):
         nd = icmpv6.nd_neighbor(self.res, self.dst)
-        eq_(nd.res >> 29, self.res)
+        eq_(nd.res, self.res)
         eq_(nd.dst, self.dst)
-        eq_(nd.type_, None)
-        eq_(nd.length, None)
-        eq_(nd.data, None)
+        eq_(nd.option, None)

     def _test_parser(self, data=None):
         buf = self.buf + str(data or '')
@@ -227,16 +264,16 @@ class Test_icmpv6_neighbor_solict(unittest.TestCase):
         eq_(msg.type_, self.type_)
         eq_(msg.code, self.code)
         eq_(msg.csum, self.csum)
-        eq_(msg.data.res >> 29, self.res)
+        eq_(msg.data.res, self.res)
         eq_(addrconv.ipv6.text_to_bin(msg.data.dst),
             addrconv.ipv6.text_to_bin(self.dst))
         eq_(n, None)
         if data:
-            nd = msg.data
-            eq_(nd.type_, self.nd_type)
+            nd = msg.data.option
+            LOG.info(nd)
             eq_(nd.length, self.nd_length)
-            eq_(nd.data.hw_src, self.nd_hw_src)
-            eq_(nd.data.data, None)
+            eq_(nd.hw_src, self.nd_hw_src)
+            eq_(nd.data, None)

     def test_parser_without_data(self):
         self._test_parser()
@@ -264,9 +301,8 @@ class Test_icmpv6_neighbor_solict(unittest.TestCase):
         eq_(data, '')

     def test_serialize_with_data(self):
-        nd_opt = icmpv6.nd_option_la(self.nd_hw_src)
-        nd = icmpv6.nd_neighbor(
-            self.res, self.dst, self.nd_type, self.nd_length, nd_opt)
+        nd_opt = icmpv6.nd_option_sla(self.nd_length, self.nd_hw_src)
+        nd = icmpv6.nd_neighbor(self.res, self.dst, nd_opt)
         prev = ipv6(6, 0, 0, 32, 64, 255, self.src_ipv6, self.dst_ipv6)
         nd_csum = icmpv6_csum(prev, self.buf + self.data)

@@ -276,7 +312,7 @@ class Test_icmpv6_neighbor_solict(unittest.TestCase):
         (type_, code, csum) = struct.unpack_from(icmp._PACK_STR, buf, 0)
         (res, dst) = struct.unpack_from(nd._PACK_STR, buf, icmp._MIN_LEN)
         (nd_type, nd_length, nd_hw_src) = struct.unpack_from(
-            '!BB6s', buf, icmp._MIN_LEN + nd._MIN_LEN)
+            nd_opt._PACK_STR, buf, icmp._MIN_LEN + nd._MIN_LEN)
         data = buf[(icmp._MIN_LEN + nd._MIN_LEN + 8):]

         eq_(type_, self.type_)
@@ -289,23 +325,21 @@ class Test_icmpv6_neighbor_solict(unittest.TestCase):
         eq_(nd_hw_src, addrconv.mac.text_to_bin(self.nd_hw_src))

     def test_to_string(self):
-        nd_opt = icmpv6.nd_option_la(self.nd_hw_src)
-        nd = icmpv6.nd_neighbor(
-            self.res, self.dst, self.nd_type, self.nd_length, nd_opt)
+        nd_opt = icmpv6.nd_option_sla(self.nd_length, self.nd_hw_src)
+        nd = icmpv6.nd_neighbor(self.res, self.dst, nd_opt)
         ic = icmpv6.icmpv6(self.type_, self.code, self.csum, nd)

-        nd_opt_values = {'hw_src': self.nd_hw_src,
+        nd_opt_values = {'length': self.nd_length,
+                         'hw_src': self.nd_hw_src,
                          'data': None}
         _nd_opt_str = ','.join(['%s=%s' % (k, repr(nd_opt_values[k]))
                                 for k, v in inspect.getmembers(nd_opt)
                                 if k in nd_opt_values])
-        nd_opt_str = '%s(%s)' % (icmpv6.nd_option_la.__name__, _nd_opt_str)
+        nd_opt_str = '%s(%s)' % (icmpv6.nd_option_sla.__name__, _nd_opt_str)

         nd_values = {'res': repr(nd.res),
                      'dst': repr(self.dst),
-                     'type_': repr(self.nd_type),
-                     'length': repr(self.nd_length),
-                     'data': nd_opt_str}
+                     'option': nd_opt_str}
         _nd_str = ','.join(['%s=%s' % (k, nd_values[k])
                             for k, v in inspect.getmembers(nd)
                             if k in nd_values])
@@ -323,8 +357,45 @@ class Test_icmpv6_neighbor_solict(unittest.TestCase):
         eq_(str(ic), ic_str)
         eq_(repr(ic), ic_str)

+    def test_default_args(self):
+        prev = ipv6()
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_NEIGHBOR_SOLICIT, data=icmpv6.nd_neighbor())
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_NEIGHBOR_SOLICIT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_neighbor._PACK_STR, str(buf[4:]))
+
+        eq_(res[0], 0)
+        eq_(res[1], addrconv.ipv6.text_to_bin('::'))
+
+        # with nd_option_sla
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_NEIGHBOR_SOLICIT,
+            data=icmpv6.nd_neighbor(
+                option=icmpv6.nd_option_sla()))
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_NEIGHBOR_SOLICIT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_neighbor._PACK_STR, str(buf[4:24]))
+
+        eq_(res[0], 0)
+        eq_(res[1], addrconv.ipv6.text_to_bin('::'))
+
+        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf[24:]))
+
+        eq_(res[0], icmpv6.ND_OPTION_SLA)
+        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
+        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
+

-class Test_icmpv6_neighbor_advert(Test_icmpv6_neighbor_solict):
+class Test_icmpv6_neighbor_advert(Test_icmpv6_neighbor_solicit):
     def setUp(self):
         self.type_ = 136
         self.csum = 0xb8ba
@@ -339,8 +410,103 @@ class 
Test_icmpv6_neighbor_advert(Test_icmpv6_neighbor_solict):
             + '\x3f\xfe\x05\x07\x00\x00\x00\x01' \
             + '\x02\x60\x97\xff\xfe\x07\x69\xea'

+    def test_serialize_with_data(self):
+        nd_opt = icmpv6.nd_option_tla(self.nd_length, self.nd_hw_src)
+        nd = icmpv6.nd_neighbor(self.res, self.dst, nd_opt)
+        prev = ipv6(6, 0, 0, 32, 64, 255, self.src_ipv6, self.dst_ipv6)
+        nd_csum = icmpv6_csum(prev, self.buf + self.data)
+
+        icmp = icmpv6.icmpv6(self.type_, self.code, 0, nd)
+        buf = buffer(icmp.serialize(bytearray(), prev))
+
+        (type_, code, csum) = struct.unpack_from(icmp._PACK_STR, buf, 0)
+        (res, dst) = struct.unpack_from(nd._PACK_STR, buf, icmp._MIN_LEN)
+        (nd_type, nd_length, nd_hw_src) = struct.unpack_from(
+            nd_opt._PACK_STR, buf, icmp._MIN_LEN + nd._MIN_LEN)
+        data = buf[(icmp._MIN_LEN + nd._MIN_LEN + 8):]
+
+        eq_(type_, self.type_)
+        eq_(code, self.code)
+        eq_(csum, nd_csum)
+        eq_(res >> 29, self.res)
+        eq_(dst, addrconv.ipv6.text_to_bin(self.dst))
+        eq_(nd_type, self.nd_type)
+        eq_(nd_length, self.nd_length)
+        eq_(nd_hw_src, addrconv.mac.text_to_bin(self.nd_hw_src))
+
+    def test_to_string(self):
+        nd_opt = icmpv6.nd_option_tla(self.nd_length, self.nd_hw_src)
+        nd = icmpv6.nd_neighbor(self.res, self.dst, nd_opt)
+        ic = icmpv6.icmpv6(self.type_, self.code, self.csum, nd)
+
+        nd_opt_values = {'length': self.nd_length,
+                         'hw_src': self.nd_hw_src,
+                         'data': None}
+        _nd_opt_str = ','.join(['%s=%s' % (k, repr(nd_opt_values[k]))
+                                for k, v in inspect.getmembers(nd_opt)
+                                if k in nd_opt_values])
+        nd_opt_str = '%s(%s)' % (icmpv6.nd_option_tla.__name__, _nd_opt_str)
+
+        nd_values = {'res': repr(nd.res),
+                     'dst': repr(self.dst),
+                     'option': nd_opt_str}
+        _nd_str = ','.join(['%s=%s' % (k, nd_values[k])
+                            for k, v in inspect.getmembers(nd)
+                            if k in nd_values])
+        nd_str = '%s(%s)' % (icmpv6.nd_neighbor.__name__, _nd_str)
+
+        icmp_values = {'type_': repr(self.type_),
+                       'code': repr(self.code),
+                       'csum': repr(self.csum),
+                       'data': nd_str}
+        _ic_str = ','.join(['%s=%s' % (k, icmp_values[k])
+                            for k, v in inspect.getmembers(ic)
+                            if k in icmp_values])
+        ic_str = '%s(%s)' % (icmpv6.icmpv6.__name__, _ic_str)
+
+        eq_(str(ic), ic_str)
+        eq_(repr(ic), ic_str)
+
+    def test_default_args(self):
+        prev = ipv6()
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_NEIGHBOR_ADVERT, data=icmpv6.nd_neighbor())
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_NEIGHBOR_ADVERT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_neighbor._PACK_STR, str(buf[4:]))
+
+        eq_(res[0], 0)
+        eq_(res[1], addrconv.ipv6.text_to_bin('::'))
+
+        # with nd_option_tla
+        prev = ipv6()
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_NEIGHBOR_ADVERT,
+            data=icmpv6.nd_neighbor(
+                option=icmpv6.nd_option_tla()))
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_NEIGHBOR_ADVERT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_neighbor._PACK_STR, str(buf[4:24]))
+
+        eq_(res[0], 0)
+        eq_(res[1], addrconv.ipv6.text_to_bin('::'))
+
+        res = struct.unpack(icmpv6.nd_option_tla._PACK_STR, str(buf[24:]))
+
+        eq_(res[0], icmpv6.ND_OPTION_TLA)
+        eq_(res[1], len(icmpv6.nd_option_tla()) / 8)
+        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
+

-class Test_icmpv6_router_solict(unittest.TestCase):
+class Test_icmpv6_router_solicit(unittest.TestCase):
     type_ = 133
     code = 0
     csum = 0x97d9
@@ -362,9 +528,7 @@ class Test_icmpv6_router_solict(unittest.TestCase):
     def test_init(self):
         rs = icmpv6.nd_router_solicit(self.res)
         eq_(rs.res, self.res)
-        eq_(rs.type_, None)
-        eq_(rs.length, None)
-        eq_(rs.data, None)
+        eq_(rs.option, None)

     def _test_parser(self, data=None):
         buf = self.buf + str(data or '')
@@ -374,14 +538,13 @@ class Test_icmpv6_router_solict(unittest.TestCase):
         eq_(msg.code, self.code)
         eq_(msg.csum, self.csum)
         if data is not None:
-            eq_(msg.data.res[0], self.res)
+            eq_(msg.data.res, self.res)
         eq_(n, None)
         if data:
-            rs = msg.data
-            eq_(rs.type_, self.nd_type)
+            rs = msg.data.option
             eq_(rs.length, self.nd_length)
-            eq_(rs.data.hw_src, self.nd_hw_src)
-            eq_(rs.data.data, None)
+            eq_(rs.hw_src, self.nd_hw_src)
+            eq_(rs.data, None)

     def test_parser_without_data(self):
         self._test_parser()
@@ -408,9 +571,8 @@ class Test_icmpv6_router_solict(unittest.TestCase):
         eq_(data, '')

     def test_serialize_with_data(self):
-        nd_opt = icmpv6.nd_option_la(self.nd_hw_src)
-        rs = icmpv6.nd_router_solicit(self.res, self.nd_type, self.nd_length,
-                                      nd_opt)
+        nd_opt = icmpv6.nd_option_sla(self.nd_length, self.nd_hw_src)
+        rs = icmpv6.nd_router_solicit(self.res, nd_opt)
         prev = ipv6(6, 0, 0, 16, 64, 255, self.src_ipv6, self.dst_ipv6)
         rs_csum = icmpv6_csum(prev, self.buf + self.data)

@@ -420,7 +582,7 @@ class Test_icmpv6_router_solict(unittest.TestCase):
         (type_, code, csum) = struct.unpack_from(icmp._PACK_STR, buf, 0)
         res = struct.unpack_from(rs._PACK_STR, buf, icmp._MIN_LEN)
         (nd_type, nd_length, nd_hw_src) = struct.unpack_from(
-            '!BB6s', buf, icmp._MIN_LEN + rs._MIN_LEN)
+            nd_opt._PACK_STR, buf, icmp._MIN_LEN + rs._MIN_LEN)
         data = buf[(icmp._MIN_LEN + rs._MIN_LEN + 8):]

         eq_(type_, self.type_)
@@ -432,22 +594,20 @@ class Test_icmpv6_router_solict(unittest.TestCase):
         eq_(nd_hw_src, addrconv.mac.text_to_bin(self.nd_hw_src))

     def test_to_string(self):
-        nd_opt = icmpv6.nd_option_la(self.nd_hw_src)
-        rs = icmpv6.nd_router_solicit(
-            self.res, self.nd_type, self.nd_length, nd_opt)
+        nd_opt = icmpv6.nd_option_sla(self.nd_length, self.nd_hw_src)
+        rs = icmpv6.nd_router_solicit(self.res, nd_opt)
         ic = icmpv6.icmpv6(self.type_, self.code, self.csum, rs)

-        nd_opt_values = {'hw_src': self.nd_hw_src,
+        nd_opt_values = {'length': self.nd_length,
+                         'hw_src': self.nd_hw_src,
                          'data': None}
         _nd_opt_str = ','.join(['%s=%s' % (k, repr(nd_opt_values[k]))
                                 for k, v in inspect.getmembers(nd_opt)
                                 if k in nd_opt_values])
-        nd_opt_str = '%s(%s)' % (icmpv6.nd_option_la.__name__, _nd_opt_str)
+        nd_opt_str = '%s(%s)' % (icmpv6.nd_option_sla.__name__, _nd_opt_str)

         rs_values = {'res': repr(rs.res),
-                     'type_': repr(self.nd_type),
-                     'length': repr(self.nd_length),
-                     'data': nd_opt_str}
+                     'option': nd_opt_str}
         _rs_str = ','.join(['%s=%s' % (k, rs_values[k])
                             for k, v in inspect.getmembers(rs)
                             if k in rs_values])
@@ -464,3 +624,246 @@ class Test_icmpv6_router_solict(unittest.TestCase):

         eq_(str(ic), ic_str)
         eq_(repr(ic), ic_str)
+
+    def test_default_args(self):
+        prev = ipv6()
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_ROUTER_SOLICIT, data=icmpv6.nd_router_solicit())
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_ROUTER_SOLICIT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_router_solicit._PACK_STR, str(buf[4:]))
+
+        eq_(res[0], 0)
+
+        # with nd_option_sla
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_ROUTER_SOLICIT,
+            data=icmpv6.nd_router_solicit(
+                option=icmpv6.nd_option_sla()))
+
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_ROUTER_SOLICIT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_router_solicit._PACK_STR, str(buf[4:8]))
+
+        eq_(res[0], 0)
+
+        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf[8:]))
+
+        eq_(res[0], icmpv6.ND_OPTION_SLA)
+        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
+        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
+
+
+class Test_icmpv6_router_advert(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_default_args(self):
+        prev = ipv6()
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_ROUTER_ADVERT, data=icmpv6.nd_router_advert())
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_ROUTER_ADVERT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_router_advert._PACK_STR, str(buf[4:]))
+
+        eq_(res[0], 0)
+        eq_(res[1], 0)
+        eq_(res[2], 0)
+        eq_(res[3], 0)
+        eq_(res[4], 0)
+
+        # with nd_option_sla
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_ROUTER_ADVERT,
+            data=icmpv6.nd_router_advert(
+                options=[icmpv6.nd_option_sla()]))
+
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_ROUTER_ADVERT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_router_advert._PACK_STR, str(buf[4:16]))
+
+        eq_(res[0], 0)
+        eq_(res[1], 0)
+        eq_(res[2], 0)
+        eq_(res[3], 0)
+        eq_(res[4], 0)
+
+        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf[16:]))
+
+        eq_(res[0], icmpv6.ND_OPTION_SLA)
+        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
+        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
+
+        # with nd_option_pi
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_ROUTER_ADVERT,
+            data=icmpv6.nd_router_advert(
+                options=[icmpv6.nd_option_pi()]))
+
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_ROUTER_ADVERT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_router_advert._PACK_STR, str(buf[4:16]))
+
+        eq_(res[0], 0)
+        eq_(res[1], 0)
+        eq_(res[2], 0)
+        eq_(res[3], 0)
+        eq_(res[4], 0)
+
+        res = struct.unpack(icmpv6.nd_option_pi._PACK_STR, str(buf[16:]))
+
+        eq_(res[0], icmpv6.ND_OPTION_PI)
+        eq_(res[1], 4)
+        eq_(res[2], 0)
+        eq_(res[3], 0)
+        eq_(res[4], 0)
+        eq_(res[5], 0)
+        eq_(res[6], 0)
+        eq_(res[7], addrconv.ipv6.text_to_bin('::'))
+
+        # with nd_option_sla and nd_option_pi
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_ROUTER_ADVERT,
+            data=icmpv6.nd_router_advert(
+                options=[icmpv6.nd_option_sla(), icmpv6.nd_option_pi()]))
+
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_ROUTER_ADVERT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_router_advert._PACK_STR, str(buf[4:16]))
+
+        eq_(res[0], 0)
+        eq_(res[1], 0)
+        eq_(res[2], 0)
+        eq_(res[3], 0)
+        eq_(res[4], 0)
+
+        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf[16:24]))
+
+        eq_(res[0], icmpv6.ND_OPTION_SLA)
+        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
+        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
+
+        res = struct.unpack(icmpv6.nd_option_pi._PACK_STR, str(buf[24:]))
+
+        eq_(res[0], icmpv6.ND_OPTION_PI)
+        eq_(res[1], len(icmpv6.nd_option_pi()) / 8)
+        eq_(res[2], 0)
+        eq_(res[3], 0)
+        eq_(res[4], 0)
+        eq_(res[5], 0)
+        eq_(res[6], 0)
+        eq_(res[7], addrconv.ipv6.text_to_bin('::'))
+
+
+class Test_icmpv6_nd_option_la(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_default_args(self):
+        la = icmpv6.nd_option_sla()
+        buf = la.serialize()
+        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf))
+
+        eq_(res[0], icmpv6.ND_OPTION_SLA)
+        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
+        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
+
+        # with nd_neighbor
+        prev = ipv6()
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_NEIGHBOR_ADVERT,
+            data=icmpv6.nd_neighbor(
+                option=icmpv6.nd_option_tla()))
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_NEIGHBOR_ADVERT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_neighbor._PACK_STR, str(buf[4:24]))
+
+        eq_(res[0], 0)
+        eq_(res[1], addrconv.ipv6.text_to_bin('::'))
+
+        res = struct.unpack(icmpv6.nd_option_tla._PACK_STR, str(buf[24:]))
+
+        eq_(res[0], icmpv6.ND_OPTION_TLA)
+        eq_(res[1], len(icmpv6.nd_option_tla()) / 8)
+        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
+
+        # with nd_router_solicit
+        ic = icmpv6.icmpv6(
+            type_=icmpv6.ND_ROUTER_SOLICIT,
+            data=icmpv6.nd_router_solicit(
+                option=icmpv6.nd_option_sla()))
+
+        buf = ic.serialize(bytearray(), prev)
+        res = struct.unpack(icmpv6.icmpv6._PACK_STR, str(buf[:4]))
+
+        eq_(res[0], icmpv6.ND_ROUTER_SOLICIT)
+        eq_(res[1], 0)
+
+        res = struct.unpack(icmpv6.nd_router_solicit._PACK_STR, str(buf[4:8]))
+
+        eq_(res[0], 0)
+
+        res = struct.unpack(icmpv6.nd_option_sla._PACK_STR, str(buf[8:]))
+
+        eq_(res[0], icmpv6.ND_OPTION_SLA)
+        eq_(res[1], len(icmpv6.nd_option_sla()) / 8)
+        eq_(res[2], addrconv.mac.text_to_bin('00:00:00:00:00:00'))
+
+
+class Test_icmpv6_nd_option_pi(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_default_args(self):
+        pi = icmpv6.nd_option_pi()
+        buf = pi.serialize()
+        res = struct.unpack(icmpv6.nd_option_pi._PACK_STR, str(buf))
+
+        eq_(res[0], icmpv6.ND_OPTION_PI)
+        eq_(res[1], len(icmpv6.nd_option_pi()) / 8)
+        eq_(res[2], 0)
+        eq_(res[3], 0)
+        eq_(res[4], 0)
+        eq_(res[5], 0)
+        eq_(res[6], 0)
+        eq_(res[7], addrconv.ipv6.text_to_bin('::'))
--
1.7.10.4


------------------------------------------------------------------------------
November Webinars for C, C++, Fortran Developers
Accelerate application performance with scalable programming models. Explore
techniques for threading, error checking, porting, and tuning. Get the most 
from the latest Intel processors and coprocessors. See abstracts and register
http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to