summaryrefslogtreecommitdiffhomepage
path: root/ryu/lib/packet/icmpv6.py
diff options
context:
space:
mode:
Diffstat (limited to 'ryu/lib/packet/icmpv6.py')
-rw-r--r--ryu/lib/packet/icmpv6.py241
1 files changed, 241 insertions, 0 deletions
diff --git a/ryu/lib/packet/icmpv6.py b/ryu/lib/packet/icmpv6.py
index ac1d5349..1ad2e68e 100644
--- a/ryu/lib/packet/icmpv6.py
+++ b/ryu/lib/packet/icmpv6.py
@@ -214,8 +214,192 @@ class nd_neighbor(stringify.StringifyMixin):
return hdr
+@icmpv6.register_icmpv6_type(ND_ROUTER_SOLICIT)
+class nd_router_solicit(stringify.StringifyMixin):
+ """ICMPv6 sub encoder/decoder class for Router Solicitation messages.
+ (RFC 4861)
+
+ This is used with ryu.lib.packet.icmpv6.icmpv6.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{35em}|
+
+ ============== ====================
+ 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.
+ ============== ====================
+ """
+
+ _PACK_STR = '!I'
+ _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
+ return cls
+ return _register_nd_option_type
+
+ def __init__(self, res, type_=None, length=None, data=None):
+ self.res = res
+ self.type_ = type_
+ self.length = length
+ self.data = data
+
+ @classmethod
+ def parser(cls, buf, offset):
+ res = struct.unpack_from(cls._PACK_STR, buf, offset)
+ msg = cls(res)
+ offset += cls._MIN_LEN
+ 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)
+ else:
+ msg.data = buf[offset:]
+
+ 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
+
+
+@icmpv6.register_icmpv6_type(ND_ROUTER_ADVERT)
+class nd_router_advert(stringify.StringifyMixin):
+ """ICMPv6 sub encoder/decoder class for Router Advertisement messages.
+ (RFC 4861)
+
+ This is used with ryu.lib.packet.icmpv6.icmpv6.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{35em}|
+
+ ============== ====================
+ Attribute Description
+ ============== ====================
+ ch_l Cur Hop Limit.
+ res M,O Flags for Router Advertisement.
+ 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.
+ ============== ====================
+ """
+
+ _PACK_STR = '!BBHII'
+ _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
+ return cls
+ return _register_nd_option_type
+
+ def __init__(self, ch_l, res, rou_l, rea_t, ret_t, type_=None, length=None,
+ data=None):
+ self.ch_l = ch_l
+ self.res = res << 6
+ self.rou_l = rou_l
+ self.rea_t = rea_t
+ self.ret_t = ret_t
+ self.type_ = type_
+ self.length = length
+ self.data = data
+
+ @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)
+ offset += cls._MIN_LEN
+ msg.type_ = list()
+ msg.length = list()
+ msg.data = list()
+ 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
+ if cls_:
+ msg.data.append(cls_.parser(buf[:offset+cls_._MIN_LEN],
+ offset))
+ offset += cls_._MIN_LEN
+ else:
+ msg.data.append(buf[offset:])
+ offset = len(buf)
+
+ 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])
+
+ return hdr
+
+
@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):
"""ICMPv6 sub encoder/decoder class for Neighbor discovery
Source/Target Link-Layer Address Option. (RFC 4861)
@@ -270,6 +454,63 @@ class nd_option_la(stringify.StringifyMixin):
return hdr
+@nd_router_advert.register_nd_option_type(nd_router_advert.ND_OPTION_PI)
+class nd_option_pi(stringify.StringifyMixin):
+ """ICMPv6 sub encoder/decoder class for Neighbor discovery
+ Prefix Information Option. (RFC 4861)
+
+ This is used with ryu.lib.packet.icmpv6.nd_neighbor.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{35em}|
+
+ ============== ====================
+ Attribute Description
+ ============== ====================
+ pl Prefix Length.
+ res1 L,A,R* Flags for Prefix Information.
+ val_l Valid Lifetime.
+ pre_l Preferred Lifetime.
+ res2 This field is unused. It MUST be initialized to zero.
+ prefix An IP address or a prefix of an IP address.
+ ============== ====================
+
+ *R flag is defined in (RFC 3775)
+ """
+
+ _PACK_STR = '!BBIII16s'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ def __init__(self, pl, res1, val_l, pre_l, res2, prefix):
+ self.pl = pl
+ self.res1 = res1 << 5
+ self.val_l = val_l
+ self.pre_l = pre_l
+ self.res2 = res2
+ self.prefix = prefix
+
+ @classmethod
+ def parser(cls, buf, offset):
+ (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
+
+
@icmpv6.register_icmpv6_type(ICMPV6_ECHO_REPLY, ICMPV6_ECHO_REQUEST)
class echo(stringify.StringifyMixin):
"""ICMPv6 sub encoder/decoder class for Echo Request and Echo Reply