1# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12# implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import abc
17import six
18import struct
19
20from ryu.lib import addrconv
21from ryu.lib import stringify
22from ryu.lib.packet import packet_base
23
24# Chunk Types
25TYPE_DATA = 0
26TYPE_INIT = 1
27TYPE_INIT_ACK = 2
28TYPE_SACK = 3
29TYPE_HEARTBEAT = 4
30TYPE_HEARTBEAT_ACK = 5
31TYPE_ABORT = 6
32TYPE_SHUTDOWN = 7
33TYPE_SHUTDOWN_ACK = 8
34TYPE_ERROR = 9
35TYPE_COOKIE_ECHO = 10
36TYPE_COOKIE_ACK = 11
37TYPE_ECN_ECHO = 12
38TYPE_CWR = 13
39TYPE_SHUTDOWN_COMPLETE = 14
40
41# Cause Code
42CCODE_INVALID_STREAM_ID = 1
43CCODE_MISSING_PARAM = 2
44CCODE_STALE_COOKIE = 3
45CCODE_OUT_OF_RESOURCE = 4
46CCODE_UNRESOLVABLE_ADDR = 5
47CCODE_UNRECOGNIZED_CHUNK = 6
48CCODE_INVALID_PARAM = 7
49CCODE_UNRECOGNIZED_PARAM = 8
50CCODE_NO_USERDATA = 9
51CCODE_COOKIE_WHILE_SHUTDOWN = 10
52CCODE_RESTART_WITH_NEW_ADDR = 11
53CCODE_USER_INITIATED_ABORT = 12
54CCODE_PROTOCOL_VIOLATION = 13
55
56# Chunk Parameter Types
57PTYPE_HEARTBEAT = 1
58PTYPE_IPV4 = 5
59PTYPE_IPV6 = 6
60PTYPE_STATE_COOKIE = 7
61PTYPE_UNRECOGNIZED_PARAM = 8
62PTYPE_COOKIE_PRESERVE = 9
63PTYPE_HOST_ADDR = 11
64PTYPE_SUPPORTED_ADDR = 12
65PTYPE_ECN = 32768
66
67
68class sctp(packet_base.PacketBase):
69    """Stream Control Transmission Protocol (SCTP)
70    header encoder/decoder class (RFC 4960).
71
72    An instance has the following attributes at least.
73    Most of them are same to the on-wire counterparts but in host byte order.
74    __init__ takes the corresponding args in this order.
75
76    .. tabularcolumns:: |l|L|
77
78    ============== =====================================================
79    Attribute      Description
80    ============== =====================================================
81    src_port       Source Port
82    dst_port       Destination Port
83    vtag           Verification Tag
84    csum           Checksum
85                   (0 means automatically-calculate when encoding)
86    chunks         a list of derived classes of ryu.lib.packet.sctp.chunk.
87    ============== =====================================================
88    """
89
90    _PACK_STR = '!HHII'
91    _MIN_LEN = struct.calcsize(_PACK_STR)
92    _SCTP_CHUNK_TYPE = {}
93    _class_prefixes = ['chunk_']
94
95    @staticmethod
96    def register_chunk_type(*args):
97        def _register_chunk_type(cls):
98            sctp._SCTP_CHUNK_TYPE[cls.chunk_type()] = cls
99            return cls
100        return _register_chunk_type(args[0])
101
102    def __init__(self, src_port=1, dst_port=1, vtag=0, csum=0, chunks=None):
103        super(sctp, self).__init__()
104        self.src_port = src_port
105        self.dst_port = dst_port
106        self.vtag = vtag
107        self.csum = csum
108        chunks = chunks or []
109        assert isinstance(chunks, list)
110        for one in chunks:
111            assert isinstance(one, chunk)
112        self.chunks = chunks
113
114    @classmethod
115    def parser(cls, buf):
116        (src_port, dst_port, vtag, csum) = struct.unpack_from(
117            cls._PACK_STR, buf)
118        chunks = []
119        offset = cls._MIN_LEN
120        while offset < len(buf):
121            (type_, ) = struct.unpack_from('!B', buf, offset)
122            cls_ = cls._SCTP_CHUNK_TYPE.get(type_)
123            if not cls_:
124                break
125            ins = cls_.parser(buf[offset:])
126            chunks.append(ins)
127            offset += len(ins)
128        msg = cls(src_port, dst_port, vtag, csum, chunks)
129        return msg, None, buf[offset:]
130
131    def serialize(self, payload, prev):
132        buf = bytearray(struct.pack(
133            self._PACK_STR, self.src_port, self.dst_port, self.vtag,
134            self.csum))
135        if self.chunks:
136            for one in self.chunks:
137                buf.extend(one.serialize())
138        if self.csum == 0:
139            self.csum = self._checksum(buf)
140            struct.pack_into('!I', buf, 8, self.csum)
141        return six.binary_type(buf)
142
143    def __len__(self):
144        length = self._MIN_LEN
145        if self.chunks is not None:
146            for one in self.chunks:
147                length += len(one)
148        return length
149
150    def _checksum(self, data):
151        # from RFC 3309
152        crc_c = [
153            0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
154            0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
155            0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
156            0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
157            0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
158            0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
159            0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
160            0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
161            0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
162            0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
163            0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
164            0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
165            0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
166            0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
167            0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
168            0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
169            0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
170            0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
171            0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
172            0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
173            0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
174            0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
175            0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
176            0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
177            0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
178            0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
179            0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
180            0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
181            0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
182            0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
183            0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
184            0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
185            0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
186            0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
187            0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
188            0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
189            0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
190            0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
191            0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
192            0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
193            0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
194            0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
195            0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
196            0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
197            0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
198            0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
199            0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
200            0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
201            0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
202            0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
203            0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
204            0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
205            0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
206            0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
207            0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
208            0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
209            0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
210            0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
211            0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
212            0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
213            0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
214            0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
215            0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
216            0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
217        ]
218
219        crc32 = 0xffffffff
220        for c in str(data):
221            crc32 = (crc32 >> 8) ^ crc_c[(crc32 ^ (ord(c))) & 0xFF]
222        crc32 = (~crc32) & 0xffffffff
223        return struct.unpack(">I", struct.pack("<I", crc32))[0]
224
225
226# =======================================================================
227#
228# Chunk Types
229#
230# =======================================================================
231@six.add_metaclass(abc.ABCMeta)
232class chunk(stringify.StringifyMixin):
233    _PACK_STR = '!BBH'
234    _MIN_LEN = struct.calcsize(_PACK_STR)
235
236    @classmethod
237    @abc.abstractmethod
238    def chunk_type(cls):
239        pass
240
241    @abc.abstractmethod
242    def __init__(self, type_, length):
243        self._type = type_
244        self.length = length
245
246    @classmethod
247    @abc.abstractmethod
248    def parser(cls, buf):
249        pass
250
251    def __len__(self):
252        return self.length
253
254
255@six.add_metaclass(abc.ABCMeta)
256class chunk_init_base(chunk):
257    _PACK_STR = '!BBHIIHHI'
258    _MIN_LEN = struct.calcsize(_PACK_STR)
259    _class_prefixes = ['param_']
260
261    def __init__(self, flags=0, length=0, init_tag=0, a_rwnd=0, os=0,
262                 mis=0, i_tsn=0, params=None):
263        super(chunk_init_base, self).__init__(self.chunk_type(), length)
264        self.flags = flags
265        self.init_tag = init_tag
266        self.a_rwnd = a_rwnd
267        self.os = os
268        self.mis = mis
269        self.i_tsn = i_tsn
270        params = params or []
271        assert isinstance(params, list)
272        for one in params:
273            assert isinstance(one, param)
274        self.params = params
275
276    @classmethod
277    def parser_base(cls, buf, recog):
278        (_, flags, length, init_tag, a_rwnd, os, mis, i_tsn
279         ) = struct.unpack_from(cls._PACK_STR, buf)
280        params = []
281        offset = cls._MIN_LEN
282        while offset < length:
283            (ptype, ) = struct.unpack_from('!H', buf, offset)
284            cls_ = recog.get(ptype)
285            if not cls_:
286                break
287            ins = cls_.parser(buf[offset:])
288            params.append(ins)
289            offset += len(ins)
290        msg = cls(flags, length, init_tag, a_rwnd, os, mis, i_tsn, params)
291        return msg
292
293    def serialize(self):
294        buf = bytearray(struct.pack(
295            self._PACK_STR, self.chunk_type(), self.flags,
296            self.length, self.init_tag, self.a_rwnd, self.os, self.mis,
297            self.i_tsn))
298        for one in self.params:
299            buf.extend(one.serialize())
300        if 0 == self.length:
301            self.length = len(buf)
302            struct.pack_into('!H', buf, 2, self.length)
303        return six.binary_type(buf)
304
305
306@six.add_metaclass(abc.ABCMeta)
307class chunk_heartbeat_base(chunk):
308    _class_prefixes = ['param_']
309
310    def __init__(self, flags=0, length=0, info=None):
311        super(chunk_heartbeat_base, self).__init__(
312            self.chunk_type(), length)
313        self.flags = flags
314        if info is not None:
315            assert isinstance(info, param)
316        self.info = info
317
318    @classmethod
319    def parser_base(cls, buf, recog):
320        (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
321        (ptype, ) = struct.unpack_from('!H', buf, cls._MIN_LEN)
322        cls_ = recog.get(ptype)
323        info = cls_.parser(buf[cls._MIN_LEN:])
324        msg = cls(flags, length, info)
325        return msg
326
327    def serialize(self):
328        buf = bytearray(struct.pack(
329            self._PACK_STR, self.chunk_type(), self.flags,
330            self.length))
331        if self.info is not None:
332            buf.extend(self.info.serialize())
333        if 0 == self.length:
334            self.length = len(buf)
335            struct.pack_into('!H', buf, 2, self.length)
336        return six.binary_type(buf)
337
338
339@six.add_metaclass(abc.ABCMeta)
340class chunk_ack_base(chunk):
341    def __init__(self, flags=0, length=0):
342        super(chunk_ack_base, self).__init__(self.chunk_type(), length)
343        self.flags = flags
344
345    @classmethod
346    def parser(cls, buf):
347        (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
348        return cls(flags, length)
349
350    def serialize(self):
351        if 0 == self.length:
352            self.length = self._MIN_LEN
353        buf = struct.pack(
354            self._PACK_STR, self.chunk_type(), self.flags,
355            self.length)
356        return buf
357
358
359@six.add_metaclass(abc.ABCMeta)
360class chunk_ecn_base(chunk):
361    _PACK_STR = '!BBHI'
362    _MIN_LEN = struct.calcsize(_PACK_STR)
363
364    def __init__(self, flags=0, length=0, low_tsn=0):
365        super(chunk_ecn_base, self).__init__(self.chunk_type(), length)
366        self.flags = flags
367        self.low_tsn = low_tsn
368
369    @classmethod
370    def parser(cls, buf):
371        (_, flags, length, low_tsn) = struct.unpack_from(cls._PACK_STR, buf)
372        return cls(flags, length, low_tsn)
373
374    def serialize(self):
375        if 0 == self.length:
376            self.length = self._MIN_LEN
377        buf = struct.pack(
378            self._PACK_STR, self.chunk_type(), self.flags, self.length,
379            self.low_tsn)
380        return buf
381
382
383@sctp.register_chunk_type
384class chunk_data(chunk):
385    """Stream Control Transmission Protocol (SCTP)
386    sub encoder/decoder class for Payload Data (DATA) chunk (RFC 4960).
387
388    This class is used with the following.
389
390    - ryu.lib.packet.sctp.sctp
391
392    An instance has the following attributes at least.
393    Most of them are same to the on-wire counterparts but in host byte order.
394    __init__ takes the corresponding args in this order.
395
396    .. tabularcolumns:: |l|L|
397
398    ============== =====================================================
399    Attribute      Description
400    ============== =====================================================
401    unordered      if set to '1', the receiver ignores the sequence number.
402    begin          if set to '1', this chunk is the first fragment.
403    end            if set to '1', this chunk is the last fragment.
404    length         length of this chunk containing this header.
405                   (0 means automatically-calculate when encoding)
406    tsn            Transmission Sequence Number.
407    sid            stream id.
408    seq            the sequence number.
409    payload_id     application specified protocol id. '0' means that
410                   no application id is identified.
411    payload_data   user data.
412    ============== =====================================================
413    """
414
415    _PACK_STR = '!BBHIHHI'
416    _MIN_LEN = struct.calcsize(_PACK_STR)
417
418    @classmethod
419    def chunk_type(cls):
420        return TYPE_DATA
421
422    def __init__(self, unordered=0, begin=0, end=0, length=0, tsn=0,
423                 sid=0, seq=0, payload_id=0, payload_data=None):
424        assert (1 == unordered | 1)
425        assert (1 == begin | 1)
426        assert (1 == end | 1)
427        assert (payload_data is not None)
428        super(chunk_data, self).__init__(self.chunk_type(), length)
429        self.unordered = unordered
430        self.begin = begin
431        self.end = end
432        self.tsn = tsn
433        self.sid = sid
434        self.seq = seq
435        self.payload_id = payload_id
436        self.payload_data = payload_data
437
438    @classmethod
439    def parser(cls, buf):
440        (_, flags, length, tsn, sid, seq, payload_id
441         ) = struct.unpack_from(cls._PACK_STR, buf)
442        unordered = (flags >> 2) & 1
443        begin = (flags >> 1) & 1
444        end = (flags >> 0) & 1
445        fmt = '!%ds' % (length - cls._MIN_LEN)
446        (payload_data, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
447        return cls(unordered, begin, end, length, tsn, sid, seq,
448                   payload_id, payload_data)
449
450    def serialize(self):
451        flags = (
452            (self.unordered << 2) |
453            (self.begin << 1) |
454            (self.end << 0))
455        buf = bytearray(struct.pack(
456            self._PACK_STR, self.chunk_type(), flags, self.length,
457            self.tsn, self.sid, self.seq, self.payload_id))
458        buf.extend(self.payload_data)
459        if 0 == self.length:
460            self.length = len(buf)
461            struct.pack_into('!H', buf, 2, self.length)
462        return six.binary_type(buf)
463
464
465@sctp.register_chunk_type
466class chunk_init(chunk_init_base):
467    """Stream Control Transmission Protocol (SCTP)
468    sub encoder/decoder class for Initiation (INIT) chunk (RFC 4960).
469
470    This class is used with the following.
471
472    - ryu.lib.packet.sctp.sctp
473
474    An instance has the following attributes at least.
475    Most of them are same to the on-wire counterparts but in host byte order.
476    __init__ takes the corresponding args in this order.
477
478    .. tabularcolumns:: |l|L|
479
480    ============== =====================================================
481    Attribute      Description
482    ============== =====================================================
483    flags          set to '0'. this field will be ignored.
484    length         length of this chunk containing this header.
485                   (0 means automatically-calculate when encoding)
486    init_tag       the tag that be used as Verification Tag.
487    a_rwnd         Advertised Receiver Window Credit.
488    os             number of outbound streams.
489    mis            number of inbound streams.
490    i_tsn          Transmission Sequence Number that the sender will use.
491    params         Optional/Variable-Length Parameters.
492
493                   a list of derived classes of ryu.lib.packet.sctp.param.
494    ============== =====================================================
495    """
496
497    _RECOGNIZED_PARAMS = {}
498
499    @staticmethod
500    def register_param_type(*args):
501        def _register_param_type(cls):
502            chunk_init._RECOGNIZED_PARAMS[cls.param_type()] = cls
503            return cls
504        return _register_param_type(args[0])
505
506    @classmethod
507    def chunk_type(cls):
508        return TYPE_INIT
509
510    @classmethod
511    def parser(cls, buf):
512        return super(chunk_init, cls).parser_base(
513            buf, cls._RECOGNIZED_PARAMS)
514
515
516@sctp.register_chunk_type
517class chunk_init_ack(chunk_init_base):
518    """Stream Control Transmission Protocol (SCTP)
519    sub encoder/decoder class for Initiation Acknowledgement (INIT ACK)
520    chunk (RFC 4960).
521
522    This class is used with the following.
523
524    - ryu.lib.packet.sctp.sctp
525
526    An instance has the following attributes at least.
527    Most of them are same to the on-wire counterparts but in host byte order.
528    __init__ takes the corresponding args in this order.
529
530    .. tabularcolumns:: |l|L|
531
532    ============== =====================================================
533    Attribute      Description
534    ============== =====================================================
535    flags          set to '0'. this field will be ignored.
536    length         length of this chunk containing this header.
537                   (0 means automatically-calculate when encoding)
538    init_tag       the tag that be used as Verification Tag.
539    a_rwnd         Advertised Receiver Window Credit.
540    os             number of outbound streams.
541    mis            number of inbound streams.
542    i_tsn          Transmission Sequence Number that the sender will use.
543    params         Optional/Variable-Length Parameters.
544
545                   a list of derived classes of ryu.lib.packet.sctp.param.
546    ============== =====================================================
547    """
548
549    _RECOGNIZED_PARAMS = {}
550
551    @staticmethod
552    def register_param_type(*args):
553        def _register_param_type(cls):
554            chunk_init_ack._RECOGNIZED_PARAMS[cls.param_type()] = cls
555            return cls
556        return _register_param_type(args[0])
557
558    @classmethod
559    def chunk_type(cls):
560        return TYPE_INIT_ACK
561
562    @classmethod
563    def parser(cls, buf):
564        return super(chunk_init_ack, cls).parser_base(
565            buf, cls._RECOGNIZED_PARAMS)
566
567
568@sctp.register_chunk_type
569class chunk_sack(chunk):
570    """Stream Control Transmission Protocol (SCTP)
571    sub encoder/decoder class for Selective Acknowledgement (SACK) chunk
572    (RFC 4960).
573
574    This class is used with the following.
575
576    - ryu.lib.packet.sctp.sctp
577
578    An instance has the following attributes at least.
579    Most of them are same to the on-wire counterparts but in host byte order.
580    __init__ takes the corresponding args in this order.
581
582    .. tabularcolumns:: |l|L|
583
584    ============== =====================================================
585    Attribute      Description
586    ============== =====================================================
587    flags          set to '0'. this field will be ignored.
588    length         length of this chunk containing this header.
589                   (0 means automatically-calculate when encoding)
590    tsn_ack        TSN of the last DATA chunk received in sequence
591                   before a gap.
592    a_rwnd         Advertised Receiver Window Credit.
593    gapack_num     number of Gap Ack blocks.
594    duptsn_num     number of duplicate TSNs.
595    gapacks        a list of Gap Ack blocks. one block is made of a list
596                   with the start offset and the end offset from tsn_ack.
597                   e.g.) gapacks = [[2, 3], [10, 12], [19, 21]]
598    duptsns        a list of duplicate TSN.
599    ============== =====================================================
600    """
601
602    _PACK_STR = '!BBHIIHH'
603    _MIN_LEN = struct.calcsize(_PACK_STR)
604    _GAPACK_STR = '!HH'
605    _GAPACK_LEN = struct.calcsize(_GAPACK_STR)
606    _DUPTSN_STR = '!I'
607    _DUPTSN_LEN = struct.calcsize(_DUPTSN_STR)
608
609    @classmethod
610    def chunk_type(cls):
611        return TYPE_SACK
612
613    def __init__(self, flags=0, length=0, tsn_ack=0, a_rwnd=0,
614                 gapack_num=0, duptsn_num=0, gapacks=None, duptsns=None):
615        super(chunk_sack, self).__init__(self.chunk_type(), length)
616        self.flags = flags
617        self.tsn_ack = tsn_ack
618        self.a_rwnd = a_rwnd
619        self.gapack_num = gapack_num
620        self.duptsn_num = duptsn_num
621        gapacks = gapacks or []
622        assert isinstance(gapacks, list)
623        for one in gapacks:
624            assert isinstance(one, list)
625            assert 2 == len(one)
626        self.gapacks = gapacks
627        duptsns = duptsns or []
628        assert isinstance(duptsns, list)
629        self.duptsns = duptsns
630
631    @classmethod
632    def parser(cls, buf):
633        (_, flags, length, tsn_ack, a_rwnd, gapack_num, duptsn_num
634         ) = struct.unpack_from(cls._PACK_STR, buf)
635        gapacks = []
636        offset = cls._MIN_LEN
637        for _ in range(gapack_num):
638            (gapack_start, gapack_end) = struct.unpack_from(
639                cls._GAPACK_STR, buf, offset)
640            gapacks.append([gapack_start, gapack_end])
641            offset += cls._GAPACK_LEN
642        duptsns = []
643        for _ in range(duptsn_num):
644            (duptsn, ) = struct.unpack_from(cls._DUPTSN_STR, buf, offset)
645            duptsns.append(duptsn)
646            offset += cls._DUPTSN_LEN
647        return cls(flags, length, tsn_ack, a_rwnd, gapack_num, duptsn_num,
648                   gapacks, duptsns)
649
650    def serialize(self):
651        buf = bytearray(struct.pack(
652            self._PACK_STR, self.chunk_type(), self.flags,
653            self.length, self.tsn_ack, self.a_rwnd, self.gapack_num,
654            self.duptsn_num))
655        for one in self.gapacks:
656            buf.extend(struct.pack(chunk_sack._GAPACK_STR, one[0], one[1]))
657        for one in self.duptsns:
658            buf.extend(struct.pack(chunk_sack._DUPTSN_STR, one))
659        if 0 == self.length:
660            self.length = len(buf)
661            struct.pack_into('!H', buf, 2, self.length)
662        return six.binary_type(buf)
663
664
665@sctp.register_chunk_type
666class chunk_heartbeat(chunk_heartbeat_base):
667    """Stream Control Transmission Protocol (SCTP)
668    sub encoder/decoder class for Heartbeat Request (HEARTBEAT) chunk
669    (RFC 4960).
670
671    This class is used with the following.
672
673    - ryu.lib.packet.sctp.sctp
674
675    An instance has the following attributes at least.
676    Most of them are same to the on-wire counterparts but in host byte order.
677    __init__ takes the corresponding args in this order.
678
679    .. tabularcolumns:: |l|L|
680
681    ============== =====================================================
682    Attribute      Description
683    ============== =====================================================
684    flags          set to '0'. this field will be ignored.
685    length         length of this chunk containing this header.
686                   (0 means automatically-calculate when encoding)
687    info           ryu.lib.packet.sctp.param_heartbeat.
688    ============== =====================================================
689    """
690
691    _RECOGNIZED_PARAMS = {}
692
693    @staticmethod
694    def register_param_type(*args):
695        def _register_param_type(cls):
696            chunk_heartbeat._RECOGNIZED_PARAMS[cls.param_type()] = cls
697            return cls
698        return _register_param_type(args[0])
699
700    @classmethod
701    def chunk_type(cls):
702        return TYPE_HEARTBEAT
703
704    @classmethod
705    def parser(cls, buf):
706        return super(chunk_heartbeat, cls).parser_base(
707            buf, cls._RECOGNIZED_PARAMS)
708
709
710@sctp.register_chunk_type
711class chunk_heartbeat_ack(chunk_heartbeat_base):
712    """Stream Control Transmission Protocol (SCTP)
713    sub encoder/decoder class for Heartbeat Acknowledgement
714    (HEARTBEAT ACK) chunk (RFC 4960).
715
716    This class is used with the following.
717
718    - ryu.lib.packet.sctp.sctp
719
720    An instance has the following attributes at least.
721    Most of them are same to the on-wire counterparts but in host byte order.
722    __init__ takes the corresponding args in this order.
723
724    .. tabularcolumns:: |l|L|
725
726    ============== =====================================================
727    Attribute      Description
728    ============== =====================================================
729    flags          set to '0'. this field will be ignored.
730    length         length of this chunk containing this header.
731                   (0 means automatically-calculate when encoding)
732    info           ryu.lib.packet.sctp.param_heartbeat.
733    ============== =====================================================
734    """
735
736    _RECOGNIZED_PARAMS = {}
737
738    @staticmethod
739    def register_param_type(*args):
740        def _register_param_type(cls):
741            chunk_heartbeat_ack._RECOGNIZED_PARAMS[cls.param_type()] = cls
742            return cls
743        return _register_param_type(args[0])
744
745    @classmethod
746    def chunk_type(cls):
747        return TYPE_HEARTBEAT_ACK
748
749    @classmethod
750    def parser(cls, buf):
751        return super(chunk_heartbeat_ack, cls).parser_base(
752            buf, cls._RECOGNIZED_PARAMS)
753
754
755@sctp.register_chunk_type
756class chunk_abort(chunk):
757    """Stream Control Transmission Protocol (SCTP)
758    sub encoder/decoder class for Abort Association (ABORT) chunk (RFC 4960).
759
760    This class is used with the following.
761
762    - ryu.lib.packet.sctp.sctp
763
764    An instance has the following attributes at least.
765    Most of them are same to the on-wire counterparts but in host byte order.
766    __init__ takes the corresponding args in this order.
767
768    .. tabularcolumns:: |l|L|
769
770    ============== =====================================================
771    Attribute      Description
772    ============== =====================================================
773    tflag          '0' means the Verification tag is normal. '1' means
774                   the Verification tag is copy of the sender.
775    length         length of this chunk containing this header.
776                   (0 means automatically-calculate when encoding)
777    causes         a list of derived classes of ryu.lib.packet.sctp.causes.
778    ============== =====================================================
779    """
780
781    _class_prefixes = ['cause_']
782    _RECOGNIZED_CAUSES = {}
783
784    @staticmethod
785    def register_cause_code(*args):
786        def _register_cause_code(cls):
787            chunk_abort._RECOGNIZED_CAUSES[cls.cause_code()] = cls
788            return cls
789        return _register_cause_code(args[0])
790
791    @classmethod
792    def chunk_type(cls):
793        return TYPE_ABORT
794
795    def __init__(self, tflag=0, length=0, causes=None):
796        super(chunk_abort, self).__init__(self.chunk_type(), length)
797        assert (1 == tflag | 1)
798        self.tflag = tflag
799        causes = causes or []
800        assert isinstance(causes, list)
801        for one in causes:
802            assert isinstance(one, cause)
803        self.causes = causes
804
805    @classmethod
806    def parser(cls, buf):
807        (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
808        tflag = (flags >> 0) & 1
809        causes = []
810        offset = cls._MIN_LEN
811        while offset < length:
812            (ccode, ) = struct.unpack_from('!H', buf, offset)
813            cls_ = cls._RECOGNIZED_CAUSES.get(ccode)
814            if not cls_:
815                break
816            ins = cls_.parser(buf[offset:])
817            causes.append(ins)
818            offset += len(ins)
819        return cls(tflag, length, causes)
820
821    def serialize(self):
822        flags = (self.tflag << 0)
823        buf = bytearray(struct.pack(
824            self._PACK_STR, self.chunk_type(), flags, self.length))
825        for one in self.causes:
826            buf.extend(one.serialize())
827        if 0 == self.length:
828            self.length = len(buf)
829            struct.pack_into('!H', buf, 2, self.length)
830        return six.binary_type(buf)
831
832
833@sctp.register_chunk_type
834class chunk_shutdown(chunk):
835    """Stream Control Transmission Protocol (SCTP)
836    sub encoder/decoder class for Shutdown Association (SHUTDOWN) chunk
837    (RFC 4960).
838
839    This class is used with the following.
840
841    - ryu.lib.packet.sctp.sctp
842
843    An instance has the following attributes at least.
844    Most of them are same to the on-wire counterparts but in host byte order.
845    __init__ takes the corresponding args in this order.
846
847    .. tabularcolumns:: |l|L|
848
849    ============== =====================================================
850    Attribute      Description
851    ============== =====================================================
852    flags          set to '0'. this field will be ignored.
853    length         length of this chunk containing this header.
854                   (0 means automatically-calculate when encoding)
855    tsn_ack        TSN of the last DATA chunk received in sequence
856                   before a gap.
857    ============== =====================================================
858    """
859
860    _PACK_STR = '!BBHI'
861    _MIN_LEN = struct.calcsize(_PACK_STR)
862
863    @classmethod
864    def chunk_type(cls):
865        return TYPE_SHUTDOWN
866
867    def __init__(self, flags=0, length=0, tsn_ack=0):
868        super(chunk_shutdown, self).__init__(self.chunk_type(), length)
869        self.flags = flags
870        self.tsn_ack = tsn_ack
871
872    @classmethod
873    def parser(cls, buf):
874        (_, flags, length, tsn_ack
875         ) = struct.unpack_from(cls._PACK_STR, buf)
876        msg = cls(flags, length, tsn_ack)
877        return msg
878
879    def serialize(self):
880        if 0 == self.length:
881            self.length = self._MIN_LEN
882        buf = struct.pack(
883            self._PACK_STR, self.chunk_type(), self.flags,
884            self.length, self.tsn_ack)
885        return buf
886
887
888@sctp.register_chunk_type
889class chunk_shutdown_ack(chunk_ack_base):
890    """Stream Control Transmission Protocol (SCTP)
891    sub encoder/decoder class for Shutdown Acknowledgement (SHUTDOWN ACK)
892    chunk (RFC 4960).
893
894    This class is used with the following.
895
896    - ryu.lib.packet.sctp.sctp
897
898    An instance has the following attributes at least.
899    Most of them are same to the on-wire counterparts but in host byte order.
900    __init__ takes the corresponding args in this order.
901
902    .. tabularcolumns:: |l|L|
903
904    ============== =====================================================
905    Attribute      Description
906    ============== =====================================================
907    flags          set to '0'. this field will be ignored.
908    length         length of this chunk containing this header.
909                   (0 means automatically-calculate when encoding)
910    ============== =====================================================
911    """
912
913    @classmethod
914    def chunk_type(cls):
915        return TYPE_SHUTDOWN_ACK
916
917
918@sctp.register_chunk_type
919class chunk_error(chunk):
920    """Stream Control Transmission Protocol (SCTP)
921    sub encoder/decoder class for Operation Error (ERROR) chunk (RFC 4960).
922
923    This class is used with the following.
924
925    - ryu.lib.packet.sctp.sctp
926
927    An instance has the following attributes at least.
928    Most of them are same to the on-wire counterparts but in host byte order.
929    __init__ takes the corresponding args in this order.
930
931    .. tabularcolumns:: |l|L|
932
933    ============== =====================================================
934    Attribute      Description
935    ============== =====================================================
936    flags          set to '0'. this field will be ignored.
937    length         length of this chunk containing this header.
938                   (0 means automatically-calculate when encoding)
939    causes         a list of derived classes of ryu.lib.packet.sctp.causes.
940    ============== =====================================================
941    """
942
943    _class_prefixes = ['cause_']
944    _RECOGNIZED_CAUSES = {}
945
946    @staticmethod
947    def register_cause_code(*args):
948        def _register_cause_code(cls):
949            chunk_error._RECOGNIZED_CAUSES[cls.cause_code()] = cls
950            return cls
951        return _register_cause_code(args[0])
952
953    @classmethod
954    def chunk_type(cls):
955        return TYPE_ERROR
956
957    def __init__(self, flags=0, length=0, causes=None):
958        super(chunk_error, self).__init__(self.chunk_type(), length)
959        self.flags = flags
960        causes = causes or []
961        assert isinstance(causes, list)
962        for one in causes:
963            assert isinstance(one, cause)
964        self.causes = causes
965
966    @classmethod
967    def parser(cls, buf):
968        (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
969        causes = []
970        offset = cls._MIN_LEN
971        while offset < length:
972            (ccode, ) = struct.unpack_from('!H', buf, offset)
973            cls_ = cls._RECOGNIZED_CAUSES.get(ccode)
974            if not cls_:
975                break
976            ins = cls_.parser(buf[offset:])
977            causes.append(ins)
978            offset += len(ins)
979        return cls(flags, length, causes)
980
981    def serialize(self):
982        buf = bytearray(struct.pack(
983            self._PACK_STR, self.chunk_type(), self.flags, self.length))
984        for one in self.causes:
985            buf.extend(one.serialize())
986        if 0 == self.length:
987            self.length = len(buf)
988            struct.pack_into('!H', buf, 2, self.length)
989        return six.binary_type(buf)
990
991
992@sctp.register_chunk_type
993class chunk_cookie_echo(chunk):
994    """Stream Control Transmission Protocol (SCTP)
995    sub encoder/decoder class for Cookie Echo (COOKIE ECHO) chunk (RFC 4960).
996
997    This class is used with the following.
998
999    - ryu.lib.packet.sctp.sctp
1000
1001    An instance has the following attributes at least.
1002    Most of them are same to the on-wire counterparts but in host byte order.
1003    __init__ takes the corresponding args in this order.
1004
1005    .. tabularcolumns:: |l|L|
1006
1007    ============== =====================================================
1008    Attribute      Description
1009    ============== =====================================================
1010    flags          set to '0'. this field will be ignored.
1011    length         length of this chunk containing this header.
1012                   (0 means automatically-calculate when encoding)
1013    cookie         cookie data.
1014    ============== =====================================================
1015    """
1016
1017    _PACK_STR = '!BBH'
1018    _MIN_LEN = struct.calcsize(_PACK_STR)
1019
1020    @classmethod
1021    def chunk_type(cls):
1022        return TYPE_COOKIE_ECHO
1023
1024    def __init__(self, flags=0, length=0, cookie=None):
1025        super(chunk_cookie_echo, self).__init__(self.chunk_type(), length)
1026        self.flags = flags
1027        self.cookie = cookie
1028
1029    @classmethod
1030    def parser(cls, buf):
1031        (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
1032        _len = length - cls._MIN_LEN
1033        cookie = None
1034        if _len:
1035            fmt = '%ds' % _len
1036            (cookie, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
1037        return cls(flags, length, cookie)
1038
1039    def serialize(self):
1040        buf = bytearray(struct.pack(
1041            self._PACK_STR, self.chunk_type(), self.flags,
1042            self.length))
1043        if self.cookie is not None:
1044            buf.extend(self.cookie)
1045        if 0 == self.length:
1046            self.length = len(buf)
1047            struct.pack_into('!H', buf, 2, self.length)
1048        mod = len(buf) % 4
1049        if mod:
1050            buf.extend(bytearray(4 - mod))
1051        return six.binary_type(buf)
1052
1053
1054@sctp.register_chunk_type
1055class chunk_cookie_ack(chunk_ack_base):
1056    """Stream Control Transmission Protocol (SCTP)
1057    sub encoder/decoder class for Cookie Acknowledgement (COOKIE ACK)
1058    chunk (RFC 4960).
1059
1060    This class is used with the following.
1061
1062    - ryu.lib.packet.sctp.sctp
1063
1064    An instance has the following attributes at least.
1065    Most of them are same to the on-wire counterparts but in host byte order.
1066    __init__ takes the corresponding args in this order.
1067
1068    .. tabularcolumns:: |l|L|
1069
1070    ============== =====================================================
1071    Attribute      Description
1072    ============== =====================================================
1073    flags          set to '0'. this field will be ignored.
1074    length         length of this chunk containing this header.
1075                   (0 means automatically-calculate when encoding)
1076    ============== =====================================================
1077    """
1078
1079    @classmethod
1080    def chunk_type(cls):
1081        return TYPE_COOKIE_ACK
1082
1083
1084@sctp.register_chunk_type
1085class chunk_ecn_echo(chunk_ecn_base):
1086    """Stream Control Transmission Protocol (SCTP)
1087    sub encoder/decoder class for ECN-Echo chunk (RFC 4960 Appendix A.).
1088
1089    This class is used with the following.
1090
1091    - ryu.lib.packet.sctp.sctp
1092
1093    An instance has the following attributes at least.
1094    Most of them are same to the on-wire counterparts but in host byte order.
1095    __init__ takes the corresponding args in this order.
1096
1097    .. tabularcolumns:: |l|L|
1098
1099    ============== =====================================================
1100    Attribute      Description
1101    ============== =====================================================
1102    flags          set to '0'. this field will be ignored.
1103    length         length of this chunk containing this header.
1104                   (0 means automatically-calculate when encoding)
1105    low_tsn        the lowest TSN.
1106    ============== =====================================================
1107    """
1108
1109    @classmethod
1110    def chunk_type(cls):
1111        return TYPE_ECN_ECHO
1112
1113
1114@sctp.register_chunk_type
1115class chunk_cwr(chunk_ecn_base):
1116    """Stream Control Transmission Protocol (SCTP)
1117    sub encoder/decoder class for CWR chunk (RFC 4960 Appendix A.).
1118
1119    This class is used with the following.
1120
1121    - ryu.lib.packet.sctp.sctp
1122
1123    An instance has the following attributes at least.
1124    Most of them are same to the on-wire counterparts but in host byte order.
1125    __init__ takes the corresponding args in this order.
1126
1127    .. tabularcolumns:: |l|L|
1128
1129    ============== =====================================================
1130    Attribute      Description
1131    ============== =====================================================
1132    flags          set to '0'. this field will be ignored.
1133    length         length of this chunk containing this header.
1134                   (0 means automatically-calculate when encoding)
1135    low_tsn        the lowest TSN.
1136    ============== =====================================================
1137    """
1138
1139    @classmethod
1140    def chunk_type(cls):
1141        return TYPE_CWR
1142
1143
1144@sctp.register_chunk_type
1145class chunk_shutdown_complete(chunk):
1146    """Stream Control Transmission Protocol (SCTP)
1147    sub encoder/decoder class for Shutdown Complete (SHUTDOWN COMPLETE)
1148    chunk (RFC 4960).
1149
1150    This class is used with the following.
1151
1152    - ryu.lib.packet.sctp.sctp
1153
1154    An instance has the following attributes at least.
1155    Most of them are same to the on-wire counterparts but in host byte order.
1156    __init__ takes the corresponding args in this order.
1157
1158    .. tabularcolumns:: |l|L|
1159
1160    ============== =====================================================
1161    Attribute      Description
1162    ============== =====================================================
1163    tflag          '0' means the Verification tag is normal. '1' means
1164                   the Verification tag is copy of the sender.
1165    length         length of this chunk containing this header.
1166                   (0 means automatically-calculate when encoding)
1167    ============== =====================================================
1168    """
1169
1170    _PACK_STR = '!BBH'
1171    _MIN_LEN = struct.calcsize(_PACK_STR)
1172
1173    @classmethod
1174    def chunk_type(cls):
1175        return TYPE_SHUTDOWN_COMPLETE
1176
1177    def __init__(self, tflag=0, length=0):
1178        assert (1 == tflag | 1)
1179        super(chunk_shutdown_complete, self).__init__(
1180            self.chunk_type(), length)
1181        self.tflag = tflag
1182
1183    @classmethod
1184    def parser(cls, buf):
1185        (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
1186        tflag = flags & 1
1187        msg = cls(tflag, length)
1188        return msg
1189
1190    def serialize(self):
1191        if 0 == self.length:
1192            self.length = self._MIN_LEN
1193        buf = struct.pack(
1194            self._PACK_STR, self.chunk_type(),
1195            self.tflag, self.length)
1196        return buf
1197
1198
1199# =======================================================================
1200#
1201# Cause Code
1202#
1203# =======================================================================
1204@six.add_metaclass(abc.ABCMeta)
1205class cause(stringify.StringifyMixin):
1206    _PACK_STR = '!HH'
1207    _MIN_LEN = struct.calcsize(_PACK_STR)
1208
1209    @classmethod
1210    @abc.abstractmethod
1211    def cause_code(cls):
1212        pass
1213
1214    def __init__(self, length=0):
1215        self.length = length
1216
1217    @classmethod
1218    @abc.abstractmethod
1219    def parser(cls, buf):
1220        pass
1221
1222    def serialize(self):
1223        if 0 == self.length:
1224            self.length = self._MIN_LEN
1225        buf = struct.pack(
1226            self._PACK_STR, self.cause_code(), self.length)
1227        return buf
1228
1229    def __len__(self):
1230        length = self.length
1231        mod = length % 4
1232        if mod:
1233            length += 4 - mod
1234        return length
1235
1236
1237@six.add_metaclass(abc.ABCMeta)
1238class cause_with_value(cause):
1239    def __init__(self, value=None, length=0):
1240        super(cause_with_value, self).__init__(length)
1241        self.value = value
1242
1243    @classmethod
1244    def parser(cls, buf):
1245        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
1246        value = None
1247        if (cls._MIN_LEN < length):
1248            fmt = '%ds' % (length - cls._MIN_LEN)
1249            (value, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
1250        return cls(value, length)
1251
1252    def serialize(self):
1253        buf = bytearray(struct.pack(
1254            self._PACK_STR, self.cause_code(), self.length))
1255        if self.value is not None:
1256            buf.extend(self.value)
1257        if 0 == self.length:
1258            self.length = len(buf)
1259            struct.pack_into('!H', buf, 2, self.length)
1260        mod = len(buf) % 4
1261        if mod:
1262            buf.extend(bytearray(4 - mod))
1263        return six.binary_type(buf)
1264
1265
1266@chunk_abort.register_cause_code
1267@chunk_error.register_cause_code
1268class cause_invalid_stream_id(cause_with_value):
1269    """Stream Control Transmission Protocol (SCTP)
1270    sub encoder/decoder class for Invalid Stream Identifier (RFC 4960).
1271
1272    This class is used with the following.
1273
1274    - ryu.lib.packet.sctp.chunk_abort
1275    - ryu.lib.packet.sctp.chunk_error
1276
1277    An instance has the following attributes at least.
1278    Most of them are same to the on-wire counterparts but in host byte order.
1279    __init__ takes the corresponding args in this order.
1280
1281    .. tabularcolumns:: |l|L|
1282
1283    ============== =====================================================
1284    Attribute      Description
1285    ============== =====================================================
1286    value          stream id.
1287    length         length of this cause containing this header.
1288                   (0 means automatically-calculate when encoding)
1289    ============== =====================================================
1290    """
1291
1292    _PACK_STR = '!HHH2x'
1293    _MIN_LEN = struct.calcsize(_PACK_STR)
1294
1295    @classmethod
1296    def cause_code(cls):
1297        return CCODE_INVALID_STREAM_ID
1298
1299    def __init__(self, value=0, length=0):
1300        super(cause_invalid_stream_id, self).__init__(value, length)
1301
1302    @classmethod
1303    def parser(cls, buf):
1304        (_, length, value) = struct.unpack_from(cls._PACK_STR, buf)
1305        return cls(value, length)
1306
1307    def serialize(self):
1308        if 0 == self.length:
1309            self.length = self._MIN_LEN
1310        buf = struct.pack(
1311            self._PACK_STR, self.cause_code(), self.length, self.value)
1312        return buf
1313
1314
1315@chunk_abort.register_cause_code
1316@chunk_error.register_cause_code
1317class cause_missing_param(cause):
1318    """Stream Control Transmission Protocol (SCTP)
1319    sub encoder/decoder class for Missing Mandatory Parameter (RFC 4960).
1320
1321    This class is used with the following.
1322
1323    - ryu.lib.packet.sctp.chunk_abort
1324    - ryu.lib.packet.sctp.chunk_error
1325
1326    An instance has the following attributes at least.
1327    Most of them are same to the on-wire counterparts but in host byte order.
1328    __init__ takes the corresponding args in this order.
1329
1330    .. tabularcolumns:: |l|L|
1331
1332    ============== =====================================================
1333    Attribute      Description
1334    ============== =====================================================
1335    types          a list of missing params.
1336    num            Number of missing params.
1337                   (0 means automatically-calculate when encoding)
1338    length         length of this cause containing this header.
1339                   (0 means automatically-calculate when encoding)
1340    ============== =====================================================
1341    """
1342
1343    _PACK_STR = '!HHI'
1344    _MIN_LEN = struct.calcsize(_PACK_STR)
1345
1346    @classmethod
1347    def cause_code(cls):
1348        return CCODE_MISSING_PARAM
1349
1350    def __init__(self, types=None, num=0, length=0):
1351        super(cause_missing_param, self).__init__(length)
1352        types = types or []
1353        assert isinstance(types, list)
1354        for one in types:
1355            assert isinstance(one, int)
1356        self.types = types
1357        self.num = num
1358
1359    @classmethod
1360    def parser(cls, buf):
1361        (_, length, num) = struct.unpack_from(cls._PACK_STR, buf)
1362        types = []
1363        offset = cls._MIN_LEN
1364        for count in range(num):
1365            offset = cls._MIN_LEN + (struct.calcsize('!H') * count)
1366            (one, ) = struct.unpack_from('!H', buf, offset)
1367            types.append(one)
1368        return cls(types, num, length)
1369
1370    def serialize(self):
1371        buf = bytearray(struct.pack(
1372            self._PACK_STR, self.cause_code(), self.length, self.num))
1373        for one in self.types:
1374            buf.extend(struct.pack('!H', one))
1375        if 0 == self.num:
1376            self.num = len(self.types)
1377            struct.pack_into('!I', buf, 4, self.num)
1378        if 0 == self.length:
1379            self.length = len(buf)
1380            struct.pack_into('!H', buf, 2, self.length)
1381        mod = len(buf) % 4
1382        if mod:
1383            buf.extend(bytearray(4 - mod))
1384        return six.binary_type(buf)
1385
1386
1387@chunk_abort.register_cause_code
1388@chunk_error.register_cause_code
1389class cause_stale_cookie(cause_with_value):
1390    """Stream Control Transmission Protocol (SCTP)
1391    sub encoder/decoder class for Stale Cookie Error (RFC 4960).
1392
1393    This class is used with the following.
1394
1395    - ryu.lib.packet.sctp.chunk_abort
1396    - ryu.lib.packet.sctp.chunk_error
1397
1398    An instance has the following attributes at least.
1399    Most of them are same to the on-wire counterparts but in host byte order.
1400    __init__ takes the corresponding args in this order.
1401
1402    .. tabularcolumns:: |l|L|
1403
1404    ============== =====================================================
1405    Attribute      Description
1406    ============== =====================================================
1407    value          Measure of Staleness.
1408    length         length of this cause containing this header.
1409                   (0 means automatically-calculate when encoding)
1410    ============== =====================================================
1411    """
1412
1413    @classmethod
1414    def cause_code(cls):
1415        return CCODE_STALE_COOKIE
1416
1417
1418@chunk_abort.register_cause_code
1419@chunk_error.register_cause_code
1420class cause_out_of_resource(cause):
1421    """Stream Control Transmission Protocol (SCTP)
1422    sub encoder/decoder class for Out of Resource (RFC 4960).
1423
1424    This class is used with the following.
1425
1426    - ryu.lib.packet.sctp.chunk_abort
1427    - ryu.lib.packet.sctp.chunk_error
1428
1429    An instance has the following attributes at least.
1430    Most of them are same to the on-wire counterparts but in host byte order.
1431    __init__ takes the corresponding args in this order.
1432
1433    .. tabularcolumns:: |l|L|
1434
1435    ============== =====================================================
1436    Attribute      Description
1437    ============== =====================================================
1438    length         length of this cause containing this header.
1439                   (0 means automatically-calculate when encoding)
1440    ============== =====================================================
1441    """
1442
1443    @classmethod
1444    def cause_code(cls):
1445        return CCODE_OUT_OF_RESOURCE
1446
1447    @classmethod
1448    def parser(cls, buf):
1449        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
1450        return cls(length)
1451
1452
1453@chunk_abort.register_cause_code
1454@chunk_error.register_cause_code
1455class cause_unresolvable_addr(cause_with_value):
1456    """Stream Control Transmission Protocol (SCTP)
1457    sub encoder/decoder class for Unresolvable Address (RFC 4960).
1458
1459    This class is used with the following.
1460
1461    - ryu.lib.packet.sctp.chunk_abort
1462    - ryu.lib.packet.sctp.chunk_error
1463
1464    An instance has the following attributes at least.
1465    Most of them are same to the on-wire counterparts but in host byte order.
1466    __init__ takes the corresponding args in this order.
1467
1468    .. tabularcolumns:: |l|L|
1469
1470    ============== =====================================================
1471    Attribute      Description
1472    ============== =====================================================
1473    value          Unresolvable Address. one of follows:
1474
1475                   ryu.lib.packet.sctp.param_host_addr,
1476
1477                   ryu.lib.packet.sctp.param_ipv4, or
1478
1479                   ryu.lib.packet.sctp.param_ipv6.
1480    length         length of this cause containing this header.
1481                   (0 means automatically-calculate when encoding)
1482    ============== =====================================================
1483    """
1484
1485    _class_prefixes = ['param_']
1486    _RECOGNIZED_PARAMS = {}
1487
1488    @staticmethod
1489    def register_param_type(*args):
1490        def _register_param_type(cls):
1491            cause_unresolvable_addr._RECOGNIZED_PARAMS[cls.param_type()] = cls
1492            return cls
1493        return _register_param_type(args[0])
1494
1495    @classmethod
1496    def cause_code(cls):
1497        return CCODE_UNRESOLVABLE_ADDR
1498
1499    @classmethod
1500    def parser(cls, buf):
1501        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
1502        (ptype, ) = struct.unpack_from('!H', buf, cls._MIN_LEN)
1503        cls_ = cls._RECOGNIZED_PARAMS.get(ptype)
1504        value = cls_.parser(buf[cls._MIN_LEN:])
1505        return cls(value, length)
1506
1507    def serialize(self):
1508        buf = bytearray(struct.pack(
1509            self._PACK_STR, self.cause_code(), self.length))
1510        buf.extend(self.value.serialize())
1511        if 0 == self.length:
1512            self.length = len(buf)
1513            struct.pack_into('!H', buf, 2, self.length)
1514        mod = len(buf) % 4
1515        if mod:
1516            buf.extend(bytearray(4 - mod))
1517        return six.binary_type(buf)
1518
1519
1520@chunk_abort.register_cause_code
1521@chunk_error.register_cause_code
1522class cause_unrecognized_chunk(cause_with_value):
1523    """Stream Control Transmission Protocol (SCTP)
1524    sub encoder/decoder class for Unrecognized Chunk Type (RFC 4960).
1525
1526    This class is used with the following.
1527
1528    - ryu.lib.packet.sctp.chunk_abort
1529    - ryu.lib.packet.sctp.chunk_error
1530
1531    An instance has the following attributes at least.
1532    Most of them are same to the on-wire counterparts but in host byte order.
1533    __init__ takes the corresponding args in this order.
1534
1535    .. tabularcolumns:: |l|L|
1536
1537    ============== =====================================================
1538    Attribute      Description
1539    ============== =====================================================
1540    value          Unrecognized Chunk.
1541    length         length of this cause containing this header.
1542                   (0 means automatically-calculate when encoding)
1543    ============== =====================================================
1544    """
1545
1546    @classmethod
1547    def cause_code(cls):
1548        return CCODE_UNRECOGNIZED_CHUNK
1549
1550
1551@chunk_abort.register_cause_code
1552@chunk_error.register_cause_code
1553class cause_invalid_param(cause):
1554    """Stream Control Transmission Protocol (SCTP)
1555    sub encoder/decoder class for Invalid Mandatory Parameter (RFC 4960).
1556
1557    This class is used with the following.
1558
1559    - ryu.lib.packet.sctp.chunk_abort
1560    - ryu.lib.packet.sctp.chunk_error
1561
1562    An instance has the following attributes at least.
1563    Most of them are same to the on-wire counterparts but in host byte order.
1564    __init__ takes the corresponding args in this order.
1565
1566    .. tabularcolumns:: |l|L|
1567
1568    ============== =====================================================
1569    Attribute      Description
1570    ============== =====================================================
1571    length         length of this cause containing this header.
1572                   (0 means automatically-calculate when encoding)
1573    ============== =====================================================
1574    """
1575
1576    @classmethod
1577    def cause_code(cls):
1578        return CCODE_INVALID_PARAM
1579
1580    @classmethod
1581    def parser(cls, buf):
1582        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
1583        return cls(length)
1584
1585
1586@chunk_abort.register_cause_code
1587@chunk_error.register_cause_code
1588class cause_unrecognized_param(cause_with_value):
1589    """Stream Control Transmission Protocol (SCTP)
1590    sub encoder/decoder class for Unrecognized Parameters (RFC 4960).
1591
1592    This class is used with the following.
1593
1594    - ryu.lib.packet.sctp.chunk_abort
1595    - ryu.lib.packet.sctp.chunk_error
1596
1597    An instance has the following attributes at least.
1598    Most of them are same to the on-wire counterparts but in host byte order.
1599    __init__ takes the corresponding args in this order.
1600
1601    .. tabularcolumns:: |l|L|
1602
1603    ============== =====================================================
1604    Attribute      Description
1605    ============== =====================================================
1606    value          Unrecognized Parameter.
1607    length         length of this cause containing this header.
1608                   (0 means automatically-calculate when encoding)
1609    ============== =====================================================
1610    """
1611
1612    @classmethod
1613    def cause_code(cls):
1614        return CCODE_UNRECOGNIZED_PARAM
1615
1616
1617@chunk_abort.register_cause_code
1618@chunk_error.register_cause_code
1619class cause_no_userdata(cause_with_value):
1620    """Stream Control Transmission Protocol (SCTP)
1621    sub encoder/decoder class for No User Data (RFC 4960).
1622
1623    This class is used with the following.
1624
1625    - ryu.lib.packet.sctp.chunk_abort
1626    - ryu.lib.packet.sctp.chunk_error
1627
1628    An instance has the following attributes at least.
1629    Most of them are same to the on-wire counterparts but in host byte order.
1630    __init__ takes the corresponding args in this order.
1631
1632    .. tabularcolumns:: |l|L|
1633
1634    ============== =====================================================
1635    Attribute      Description
1636    ============== =====================================================
1637    value          the TSN of the DATA chunk received with no user data
1638                   field.
1639    length         length of this cause containing this header.
1640                   (0 means automatically-calculate when encoding)
1641    ============== =====================================================
1642    """
1643
1644    @classmethod
1645    def cause_code(cls):
1646        return CCODE_NO_USERDATA
1647
1648
1649@chunk_abort.register_cause_code
1650@chunk_error.register_cause_code
1651class cause_cookie_while_shutdown(cause):
1652    """Stream Control Transmission Protocol (SCTP)
1653    sub encoder/decoder class for Cookie Received While Shutting Down
1654    (RFC 4960).
1655
1656    This class is used with the following.
1657
1658    - ryu.lib.packet.sctp.chunk_abort
1659    - ryu.lib.packet.sctp.chunk_error
1660
1661    An instance has the following attributes at least.
1662    Most of them are same to the on-wire counterparts but in host byte order.
1663    __init__ takes the corresponding args in this order.
1664
1665    .. tabularcolumns:: |l|L|
1666
1667    ============== =====================================================
1668    Attribute      Description
1669    ============== =====================================================
1670    length         length of this cause containing this header.
1671                   (0 means automatically-calculate when encoding)
1672    ============== =====================================================
1673    """
1674
1675    @classmethod
1676    def cause_code(cls):
1677        return CCODE_COOKIE_WHILE_SHUTDOWN
1678
1679    @classmethod
1680    def parser(cls, buf):
1681        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
1682        return cls(length)
1683
1684
1685@chunk_abort.register_cause_code
1686@chunk_error.register_cause_code
1687class cause_restart_with_new_addr(cause_with_value):
1688    """Stream Control Transmission Protocol (SCTP)
1689    sub encoder/decoder class for Restart of an Association with New
1690    Addresses (RFC 4960).
1691
1692    This class is used with the following.
1693
1694    - ryu.lib.packet.sctp.chunk_abort
1695    - ryu.lib.packet.sctp.chunk_error
1696
1697    An instance has the following attributes at least.
1698    Most of them are same to the on-wire counterparts but in host byte order.
1699    __init__ takes the corresponding args in this order.
1700
1701    .. tabularcolumns:: |l|L|
1702
1703    ============== =====================================================
1704    Attribute      Description
1705    ============== =====================================================
1706    value          New Address TLVs.
1707    length         length of this cause containing this header.
1708                   (0 means automatically-calculate when encoding)
1709    ============== =====================================================
1710    """
1711
1712    _class_prefixes = ['param_']
1713    _RECOGNIZED_PARAMS = {}
1714
1715    @staticmethod
1716    def register_param_type(*args):
1717        def _register_param_type(cls):
1718            cause_restart_with_new_addr._RECOGNIZED_PARAMS[
1719                cls.param_type()] = cls
1720            return cls
1721        return _register_param_type(args[0])
1722
1723    @classmethod
1724    def cause_code(cls):
1725        return CCODE_RESTART_WITH_NEW_ADDR
1726
1727    def __init__(self, value=None, length=0):
1728        if not isinstance(value, list):
1729            value = [value]
1730        super(cause_restart_with_new_addr, self).__init__(value, length)
1731
1732    @classmethod
1733    def parser(cls, buf):
1734        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
1735        value = []
1736        offset = cls._MIN_LEN
1737        while offset < length:
1738            (ptype, ) = struct.unpack_from('!H', buf, offset)
1739            cls_ = cls._RECOGNIZED_PARAMS.get(ptype)
1740            if not cls_:
1741                break
1742            ins = cls_.parser(buf[offset:])
1743            value.append(ins)
1744            offset += len(ins)
1745        return cls(value, length)
1746
1747    def serialize(self):
1748        buf = bytearray(struct.pack(
1749            self._PACK_STR, self.cause_code(), self.length))
1750        for one in self.value:
1751            buf.extend(one.serialize())
1752        if 0 == self.length:
1753            self.length = len(buf)
1754            struct.pack_into('!H', buf, 2, self.length)
1755        mod = len(buf) % 4
1756        if mod:
1757            buf.extend(bytearray(4 - mod))
1758        return six.binary_type(buf)
1759
1760
1761@chunk_abort.register_cause_code
1762@chunk_error.register_cause_code
1763class cause_user_initiated_abort(cause_with_value):
1764    """Stream Control Transmission Protocol (SCTP)
1765    sub encoder/decoder class for User-Initiated Abort (RFC 4960).
1766
1767    This class is used with the following.
1768
1769    - ryu.lib.packet.sctp.chunk_abort
1770    - ryu.lib.packet.sctp.chunk_error
1771
1772    An instance has the following attributes at least.
1773    Most of them are same to the on-wire counterparts but in host byte order.
1774    __init__ takes the corresponding args in this order.
1775
1776    .. tabularcolumns:: |l|L|
1777
1778    ============== =====================================================
1779    Attribute      Description
1780    ============== =====================================================
1781    value          Upper Layer Abort Reason.
1782    length         length of this cause containing this header.
1783                   (0 means automatically-calculate when encoding)
1784    ============== =====================================================
1785    """
1786
1787    @classmethod
1788    def cause_code(cls):
1789        return CCODE_USER_INITIATED_ABORT
1790
1791
1792@chunk_abort.register_cause_code
1793@chunk_error.register_cause_code
1794class cause_protocol_violation(cause_with_value):
1795    """Stream Control Transmission Protocol (SCTP)
1796    sub encoder/decoder class for Protocol Violation (RFC 4960).
1797
1798    This class is used with the following.
1799
1800    - ryu.lib.packet.sctp.chunk_abort
1801    - ryu.lib.packet.sctp.chunk_error
1802
1803    An instance has the following attributes at least.
1804    Most of them are same to the on-wire counterparts but in host byte order.
1805    __init__ takes the corresponding args in this order.
1806
1807    .. tabularcolumns:: |l|L|
1808
1809    ============== =====================================================
1810    Attribute      Description
1811    ============== =====================================================
1812    value          Additional Information.
1813    length         length of this cause containing this header.
1814                   (0 means automatically-calculate when encoding)
1815    ============== =====================================================
1816    """
1817
1818    @classmethod
1819    def cause_code(cls):
1820        return CCODE_PROTOCOL_VIOLATION
1821
1822
1823# =======================================================================
1824#
1825# Chunk Parameter Types
1826#
1827# =======================================================================
1828@six.add_metaclass(abc.ABCMeta)
1829class param(stringify.StringifyMixin):
1830    _PACK_STR = '!HH'
1831    _MIN_LEN = struct.calcsize(_PACK_STR)
1832
1833    @classmethod
1834    @abc.abstractmethod
1835    def param_type(cls):
1836        pass
1837
1838    def __init__(self, value=None, length=0):
1839        self.length = length
1840        self.value = value
1841
1842    @classmethod
1843    def parser(cls, buf):
1844        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
1845        value = None
1846        if (cls._MIN_LEN < length):
1847            fmt = '%ds' % (length - cls._MIN_LEN)
1848            (value, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
1849        return cls(value, length)
1850
1851    def serialize(self):
1852        buf = bytearray(struct.pack(
1853            self._PACK_STR, self.param_type(), self.length))
1854        if self.value:
1855            buf.extend(self.value)
1856        if 0 == self.length:
1857            self.length = len(buf)
1858            struct.pack_into('!H', buf, 2, self.length)
1859        mod = len(buf) % 4
1860        if mod:
1861            buf.extend(bytearray(4 - mod))
1862        return six.binary_type(buf)
1863
1864    def __len__(self):
1865        length = self.length
1866        mod = length % 4
1867        if mod:
1868            length += 4 - mod
1869        return length
1870
1871
1872@chunk_heartbeat.register_param_type
1873@chunk_heartbeat_ack.register_param_type
1874class param_heartbeat(param):
1875    """Stream Control Transmission Protocol (SCTP)
1876    sub encoder/decoder class for Heartbeat Info Parameter (RFC 4960).
1877
1878    This class is used with the following.
1879
1880    - ryu.lib.packet.sctp.chunk_heartbeat
1881    - ryu.lib.packet.sctp.chunk_heartbeat_ack
1882
1883    An instance has the following attributes at least.
1884    Most of them are same to the on-wire counterparts but in host byte order.
1885    __init__ takes the corresponding args in this order.
1886
1887    .. tabularcolumns:: |l|L|
1888
1889    ============== =====================================================
1890    Attribute      Description
1891    ============== =====================================================
1892    value          the sender-specific heartbeat information.
1893    length         length of this param containing this header.
1894                   (0 means automatically-calculate when encoding)
1895    ============== =====================================================
1896    """
1897
1898    @classmethod
1899    def param_type(cls):
1900        return PTYPE_HEARTBEAT
1901
1902
1903@chunk_init_ack.register_param_type
1904class param_state_cookie(param):
1905    """Stream Control Transmission Protocol (SCTP)
1906    sub encoder/decoder class for State Cookie Parameter (RFC 4960).
1907
1908    This class is used with the following.
1909
1910    - ryu.lib.packet.sctp.chunk_init_ack
1911
1912    An instance has the following attributes at least.
1913    Most of them are same to the on-wire counterparts but in host byte order.
1914    __init__ takes the corresponding args in this order.
1915
1916    .. tabularcolumns:: |l|L|
1917
1918    ============== =====================================================
1919    Attribute      Description
1920    ============== =====================================================
1921    value          the state cookie. see Section 5.1.3 in RFC 4960.
1922    length         length of this param containing this header.
1923                   (0 means automatically-calculate when encoding)
1924    ============== =====================================================
1925    """
1926
1927    @classmethod
1928    def param_type(cls):
1929        return PTYPE_STATE_COOKIE
1930
1931
1932@chunk_init_ack.register_param_type
1933class param_unrecognized_param(param):
1934    """Stream Control Transmission Protocol (SCTP)
1935    sub encoder/decoder class for Unrecognized Parameter (RFC 4960).
1936
1937    This class is used with the following.
1938
1939    - ryu.lib.packet.sctp.chunk_init_ack
1940
1941    An instance has the following attributes at least.
1942    Most of them are same to the on-wire counterparts but in host byte order.
1943    __init__ takes the corresponding args in this order.
1944
1945    .. tabularcolumns:: |l|L|
1946
1947    ============== =====================================================
1948    Attribute      Description
1949    ============== =====================================================
1950    value          the unrecognized parameter in the INIT chunk.
1951    length         length of this param containing this header.
1952                   (0 means automatically-calculate when encoding)
1953    ============== =====================================================
1954    """
1955
1956    @classmethod
1957    def param_type(cls):
1958        return PTYPE_UNRECOGNIZED_PARAM
1959
1960
1961@chunk_init.register_param_type
1962class param_cookie_preserve(param):
1963    """Stream Control Transmission Protocol (SCTP)
1964    sub encoder/decoder class for Cookie Preservative Parameter (RFC 4960).
1965
1966    This class is used with the following.
1967
1968    - ryu.lib.packet.sctp.chunk_init
1969
1970    An instance has the following attributes at least.
1971    Most of them are same to the on-wire counterparts but in host byte order.
1972    __init__ takes the corresponding args in this order.
1973
1974    .. tabularcolumns:: |l|L|
1975
1976    ============== =====================================================
1977    Attribute      Description
1978    ============== =====================================================
1979    value          Suggested Cookie Life-Span Increment (msec).
1980    length         length of this param containing this header.
1981                   (0 means automatically-calculate when encoding)
1982    ============== =====================================================
1983    """
1984
1985    _PACK_STR = '!HHI'
1986    _MIN_LEN = struct.calcsize(_PACK_STR)
1987
1988    @classmethod
1989    def param_type(cls):
1990        return PTYPE_COOKIE_PRESERVE
1991
1992    def __init__(self, value=0, length=0):
1993        super(param_cookie_preserve, self).__init__(value, length)
1994
1995    @classmethod
1996    def parser(cls, buf):
1997        (_, length, value) = struct.unpack_from(cls._PACK_STR, buf)
1998        return cls(value, length)
1999
2000    def serialize(self):
2001        if 0 == self.length:
2002            self.length = self._MIN_LEN
2003        buf = struct.pack(
2004            self._PACK_STR, self.param_type(), self.length, self.value)
2005        return buf
2006
2007
2008@chunk_init.register_param_type
2009@chunk_init_ack.register_param_type
2010class param_ecn(param):
2011    """Stream Control Transmission Protocol (SCTP)
2012    sub encoder/decoder class for ECN Parameter (RFC 4960 Appendix A.).
2013
2014    This class is used with the following.
2015
2016    - ryu.lib.packet.sctp.chunk_init
2017    - ryu.lib.packet.sctp.chunk_init_ack
2018
2019    An instance has the following attributes at least.
2020    Most of them are same to the on-wire counterparts but in host byte order.
2021    __init__ takes the corresponding args in this order.
2022
2023    .. tabularcolumns:: |l|L|
2024
2025    ============== =====================================================
2026    Attribute      Description
2027    ============== =====================================================
2028    value          set to None.
2029    length         length of this param containing this header.
2030                   (0 means automatically-calculate when encoding)
2031    ============== =====================================================
2032    """
2033
2034    @classmethod
2035    def param_type(cls):
2036        return PTYPE_ECN
2037
2038    def __init__(self, value=None, length=0):
2039        super(param_ecn, self).__init__(value, length)
2040        assert 4 == length or 0 == length
2041        assert None is value
2042
2043
2044@chunk_init.register_param_type
2045@chunk_init_ack.register_param_type
2046@cause_unresolvable_addr.register_param_type
2047@cause_restart_with_new_addr.register_param_type
2048class param_host_addr(param):
2049    """Stream Control Transmission Protocol (SCTP)
2050    sub encoder/decoder class for Host Name Address Parameter (RFC 4960).
2051
2052    This class is used with the following.
2053
2054    - ryu.lib.packet.sctp.chunk_init
2055    - ryu.lib.packet.sctp.chunk_init_ack
2056
2057    An instance has the following attributes at least.
2058    Most of them are same to the on-wire counterparts but in host byte order.
2059    __init__ takes the corresponding args in this order.
2060
2061    .. tabularcolumns:: |l|L|
2062
2063    ============== =====================================================
2064    Attribute      Description
2065    ============== =====================================================
2066    value          a host name that ends with null terminator.
2067    length         length of this param containing this header.
2068                   (0 means automatically-calculate when encoding)
2069    ============== =====================================================
2070    """
2071
2072    @classmethod
2073    def param_type(cls):
2074        return PTYPE_HOST_ADDR
2075
2076
2077@chunk_init.register_param_type
2078class param_supported_addr(param):
2079    """Stream Control Transmission Protocol (SCTP)
2080    sub encoder/decoder class for Supported Address Types Parameter (RFC 4960).
2081
2082    This class is used with the following.
2083
2084    - ryu.lib.packet.sctp.chunk_init
2085
2086    An instance has the following attributes at least.
2087    Most of them are same to the on-wire counterparts but in host byte order.
2088    __init__ takes the corresponding args in this order.
2089
2090    .. tabularcolumns:: |l|L|
2091
2092    ============== =====================================================
2093    Attribute      Description
2094    ============== =====================================================
2095    value          a list of parameter types. odd cases pad with 0x0000.
2096    length         length of this param containing this header.
2097                   (0 means automatically-calculate when encoding)
2098    ============== =====================================================
2099    """
2100
2101    _VALUE_STR = '!H'
2102    _VALUE_LEN = struct.calcsize(_VALUE_STR)
2103
2104    @classmethod
2105    def param_type(cls):
2106        return PTYPE_SUPPORTED_ADDR
2107
2108    def __init__(self, value=None, length=0):
2109        if not isinstance(value, list):
2110            value = [value]
2111        for one in value:
2112            assert isinstance(one, int)
2113        super(param_supported_addr, self).__init__(value, length)
2114
2115    @classmethod
2116    def parser(cls, buf):
2117        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
2118        value = []
2119        offset = cls._MIN_LEN
2120        while offset < length:
2121            (one, ) = struct.unpack_from(cls._VALUE_STR, buf, offset)
2122            value.append(one)
2123            offset += cls._VALUE_LEN
2124        return cls(value, length)
2125
2126    def serialize(self):
2127        buf = bytearray(struct.pack(
2128            self._PACK_STR, self.param_type(), self.length))
2129        for one in self.value:
2130            buf.extend(struct.pack(param_supported_addr._VALUE_STR, one))
2131        if 0 == self.length:
2132            self.length = len(buf)
2133            struct.pack_into('!H', buf, 2, self.length)
2134        mod = len(buf) % 4
2135        if mod:
2136            buf.extend(bytearray(4 - mod))
2137        return six.binary_type(buf)
2138
2139
2140@chunk_init.register_param_type
2141@chunk_init_ack.register_param_type
2142@cause_unresolvable_addr.register_param_type
2143@cause_restart_with_new_addr.register_param_type
2144class param_ipv4(param):
2145    """Stream Control Transmission Protocol (SCTP)
2146    sub encoder/decoder class for IPv4 Address Parameter (RFC 4960).
2147
2148    This class is used with the following.
2149
2150    - ryu.lib.packet.sctp.chunk_init
2151    - ryu.lib.packet.sctp.chunk_init_ack
2152
2153    An instance has the following attributes at least.
2154    Most of them are same to the on-wire counterparts but in host byte order.
2155    __init__ takes the corresponding args in this order.
2156
2157    .. tabularcolumns:: |l|L|
2158
2159    ============== =====================================================
2160    Attribute      Description
2161    ============== =====================================================
2162    value          IPv4 address of the sending endpoint.
2163    length         length of this param containing this header.
2164                   (0 means automatically-calculate when encoding)
2165    ============== =====================================================
2166    """
2167
2168    _TYPE = {'ascii': ['value']}
2169
2170    @classmethod
2171    def param_type(cls):
2172        return PTYPE_IPV4
2173
2174    def __init__(self, value='127.0.0.1', length=0):
2175        super(param_ipv4, self).__init__(value, length)
2176
2177    @classmethod
2178    def parser(cls, buf):
2179        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
2180        value = None
2181        if (cls._MIN_LEN < length):
2182            fmt = '%ds' % (length - cls._MIN_LEN)
2183            (value, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
2184        return cls(addrconv.ipv4.bin_to_text(value), length)
2185
2186    def serialize(self):
2187        buf = bytearray(struct.pack(
2188            self._PACK_STR, self.param_type(), self.length))
2189        if self.value:
2190            buf.extend(addrconv.ipv4.text_to_bin(self.value))
2191        if 0 == self.length:
2192            self.length = len(buf)
2193            struct.pack_into('!H', buf, 2, self.length)
2194        return six.binary_type(buf)
2195
2196
2197@chunk_init.register_param_type
2198@chunk_init_ack.register_param_type
2199@cause_unresolvable_addr.register_param_type
2200@cause_restart_with_new_addr.register_param_type
2201class param_ipv6(param):
2202    """Stream Control Transmission Protocol (SCTP)
2203    sub encoder/decoder class for IPv6 Address Parameter (RFC 4960).
2204
2205    This class is used with the following.
2206
2207    - ryu.lib.packet.sctp.chunk_init
2208    - ryu.lib.packet.sctp.chunk_init_ack
2209
2210    An instance has the following attributes at least.
2211    Most of them are same to the on-wire counterparts but in host byte order.
2212    __init__ takes the corresponding args in this order.
2213
2214    .. tabularcolumns:: |l|L|
2215
2216    ============== =====================================================
2217    Attribute      Description
2218    ============== =====================================================
2219    value          IPv6 address of the sending endpoint.
2220    length         length of this param containing this header.
2221                   (0 means automatically-calculate when encoding)
2222    ============== =====================================================
2223    """
2224
2225    _TYPE = {'ascii': ['value']}
2226
2227    @classmethod
2228    def param_type(cls):
2229        return PTYPE_IPV6
2230
2231    def __init__(self, value='::1', length=0):
2232        super(param_ipv6, self).__init__(value, length)
2233
2234    @classmethod
2235    def parser(cls, buf):
2236        (_, length) = struct.unpack_from(cls._PACK_STR, buf)
2237        value = None
2238        if (cls._MIN_LEN < length):
2239            fmt = '%ds' % (length - cls._MIN_LEN)
2240            (value, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
2241        return cls(addrconv.ipv6.bin_to_text(value), length)
2242
2243    def serialize(self):
2244        buf = bytearray(struct.pack(
2245            self._PACK_STR, self.param_type(), self.length))
2246        if self.value:
2247            buf.extend(addrconv.ipv6.text_to_bin(self.value))
2248        if 0 == self.length:
2249            self.length = len(buf)
2250            struct.pack_into('!H', buf, 2, self.length)
2251        return six.binary_type(buf)
2252