backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / packet / icmp.py
1 # Copyright (C) 2012 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
16 import abc
17 import struct
18
19 import six
20
21 from . import packet_base
22 from . import packet_utils
23 from ryu.lib import stringify
24
25
26 ICMP_ECHO_REPLY = 0
27 ICMP_DEST_UNREACH = 3
28 ICMP_SRC_QUENCH = 4
29 ICMP_REDIRECT = 5
30 ICMP_ECHO_REQUEST = 8
31 ICMP_TIME_EXCEEDED = 11
32
33 ICMP_ECHO_REPLY_CODE = 0
34 ICMP_HOST_UNREACH_CODE = 1
35 ICMP_PORT_UNREACH_CODE = 3
36 ICMP_TTL_EXPIRED_CODE = 0
37
38
39 class icmp(packet_base.PacketBase):
40     """ICMP (RFC 792) header encoder/decoder class.
41
42     An instance has the following attributes at least.
43     Most of them are same to the on-wire counterparts but in host byte order.
44     __init__ takes the corresponding args in this order.
45
46     .. tabularcolumns:: |l|L|
47
48     ============== ====================
49     Attribute      Description
50     ============== ====================
51     type           Type
52     code           Code
53     csum           CheckSum \
54                    (0 means automatically-calculate when encoding)
55     data           Payload. \
56                    Either a bytearray, or \
57                    ryu.lib.packet.icmp.echo or \
58                    ryu.lib.packet.icmp.dest_unreach or \
59                    ryu.lib.packet.icmp.TimeExceeded object \
60                    NOTE for icmp.echo: \
61                    This includes "unused" 16 bits and the following \
62                    "Internet Header + 64 bits of Original Data Datagram" of \
63                    the ICMP header. \
64                    NOTE for icmp.dest_unreach and icmp.TimeExceeded: \
65                    This includes "unused" 8 or 24 bits and the following \
66                    "Internet Header + leading octets of original datagram" \
67                    of the original packet.
68     ============== ====================
69     """
70
71     _PACK_STR = '!BBH'
72     _MIN_LEN = struct.calcsize(_PACK_STR)
73     _ICMP_TYPES = {}
74
75     @staticmethod
76     def register_icmp_type(*args):
77         def _register_icmp_type(cls):
78             for type_ in args:
79                 icmp._ICMP_TYPES[type_] = cls
80             return cls
81         return _register_icmp_type
82
83     def __init__(self, type_=ICMP_ECHO_REQUEST, code=0, csum=0, data=b''):
84         super(icmp, self).__init__()
85         self.type = type_
86         self.code = code
87         self.csum = csum
88         self.data = data
89
90     @classmethod
91     def parser(cls, buf):
92         (type_, code, csum) = struct.unpack_from(cls._PACK_STR, buf)
93         msg = cls(type_, code, csum)
94         offset = cls._MIN_LEN
95
96         if len(buf) > offset:
97             cls_ = cls._ICMP_TYPES.get(type_, None)
98             if cls_:
99                 msg.data = cls_.parser(buf, offset)
100             else:
101                 msg.data = buf[offset:]
102
103         return msg, None, None
104
105     def serialize(self, payload, prev):
106         hdr = bytearray(struct.pack(icmp._PACK_STR, self.type,
107                                     self.code, self.csum))
108
109         if self.data:
110             if self.type in icmp._ICMP_TYPES:
111                 assert isinstance(self.data, _ICMPv4Payload)
112                 hdr += self.data.serialize()
113             else:
114                 hdr += self.data
115         else:
116             self.data = echo()
117             hdr += self.data.serialize()
118
119         if self.csum == 0:
120             self.csum = packet_utils.checksum(hdr)
121             struct.pack_into('!H', hdr, 2, self.csum)
122
123         return hdr
124
125     def __len__(self):
126         return self._MIN_LEN + len(self.data)
127
128
129 @six.add_metaclass(abc.ABCMeta)
130 class _ICMPv4Payload(stringify.StringifyMixin):
131     """
132     Base class for the payload of ICMPv4 packet.
133     """
134
135
136 @icmp.register_icmp_type(ICMP_ECHO_REPLY, ICMP_ECHO_REQUEST)
137 class echo(_ICMPv4Payload):
138     """ICMP sub encoder/decoder class for Echo and Echo Reply messages.
139
140     This is used with ryu.lib.packet.icmp.icmp for
141     ICMP Echo and Echo Reply messages.
142
143     An instance has the following attributes at least.
144     Most of them are same to the on-wire counterparts but in host byte order.
145     __init__ takes the corresponding args in this order.
146
147     .. tabularcolumns:: |l|L|
148
149     ============== ====================
150     Attribute      Description
151     ============== ====================
152     id             Identifier
153     seq            Sequence Number
154     data           Internet Header + 64 bits of Original Data Datagram
155     ============== ====================
156     """
157
158     _PACK_STR = '!HH'
159     _MIN_LEN = struct.calcsize(_PACK_STR)
160
161     def __init__(self, id_=0, seq=0, data=None):
162         super(echo, self).__init__()
163         self.id = id_
164         self.seq = seq
165         self.data = data
166
167     @classmethod
168     def parser(cls, buf, offset):
169         (id_, seq) = struct.unpack_from(cls._PACK_STR, buf, offset)
170         msg = cls(id_, seq)
171         offset += cls._MIN_LEN
172
173         if len(buf) > offset:
174             msg.data = buf[offset:]
175
176         return msg
177
178     def serialize(self):
179         hdr = bytearray(struct.pack(echo._PACK_STR, self.id,
180                                     self.seq))
181
182         if self.data is not None:
183             hdr += self.data
184
185         return hdr
186
187     def __len__(self):
188         length = self._MIN_LEN
189         if self.data is not None:
190             length += len(self.data)
191         return length
192
193
194 @icmp.register_icmp_type(ICMP_DEST_UNREACH)
195 class dest_unreach(_ICMPv4Payload):
196     """ICMP sub encoder/decoder class for Destination Unreachable Message.
197
198     This is used with ryu.lib.packet.icmp.icmp for
199     ICMP Destination Unreachable Message.
200
201     An instance has the following attributes at least.
202     Most of them are same to the on-wire counterparts but in host byte order.
203     __init__ takes the corresponding args in this order.
204
205     [RFC1191] reserves bits for the "Next-Hop MTU" field.
206     [RFC4884] introduced 8-bit data length attribute.
207
208     .. tabularcolumns:: |l|p{35em}|
209
210     ============== =====================================================
211     Attribute      Description
212     ============== =====================================================
213     data_len       data length
214     mtu            Next-Hop MTU
215
216                    NOTE: This field is required when icmp code is 4
217
218                    code 4 = fragmentation needed and DF set
219     data           Internet Header + leading octets of original datagram
220     ============== =====================================================
221     """
222
223     _PACK_STR = '!xBH'
224     _MIN_LEN = struct.calcsize(_PACK_STR)
225
226     def __init__(self, data_len=0, mtu=0, data=None):
227         super(dest_unreach, self).__init__()
228
229         if ((data_len >= 0) and (data_len <= 255)):
230             self.data_len = data_len
231         else:
232             raise ValueError('Specified data length (%d) is invalid.' % data_len)
233
234         self.mtu = mtu
235         self.data = data
236
237     @classmethod
238     def parser(cls, buf, offset):
239         (data_len, mtu) = struct.unpack_from(cls._PACK_STR,
240                                              buf, offset)
241         msg = cls(data_len, mtu)
242         offset += cls._MIN_LEN
243
244         if len(buf) > offset:
245             msg.data = buf[offset:]
246
247         return msg
248
249     def serialize(self):
250         hdr = bytearray(struct.pack(dest_unreach._PACK_STR,
251                                     self.data_len, self.mtu))
252
253         if self.data is not None:
254             hdr += self.data
255
256         return hdr
257
258     def __len__(self):
259         length = self._MIN_LEN
260         if self.data is not None:
261             length += len(self.data)
262         return length
263
264
265 @icmp.register_icmp_type(ICMP_TIME_EXCEEDED)
266 class TimeExceeded(_ICMPv4Payload):
267     """ICMP sub encoder/decoder class for Time Exceeded Message.
268
269     This is used with ryu.lib.packet.icmp.icmp for
270     ICMP Time Exceeded Message.
271
272     An instance has the following attributes at least.
273     Most of them are same to the on-wire counterparts but in host byte order.
274     __init__ takes the corresponding args in this order.
275
276     [RFC4884] introduced 8-bit data length attribute.
277
278     .. tabularcolumns:: |l|L|
279
280     ============== ====================
281     Attribute      Description
282     ============== ====================
283     data_len       data length
284     data           Internet Header + leading octets of original datagram
285     ============== ====================
286     """
287
288     _PACK_STR = '!xBxx'
289     _MIN_LEN = struct.calcsize(_PACK_STR)
290
291     def __init__(self, data_len=0, data=None):
292         if (data_len >= 0) and (data_len <= 255):
293             self.data_len = data_len
294         else:
295             raise ValueError('Specified data length (%d) is invalid.' % data_len)
296
297         self.data = data
298
299     @classmethod
300     def parser(cls, buf, offset):
301         (data_len, ) = struct.unpack_from(cls._PACK_STR, buf, offset)
302         msg = cls(data_len)
303         offset += cls._MIN_LEN
304
305         if len(buf) > offset:
306             msg.data = buf[offset:]
307
308         return msg
309
310     def serialize(self):
311         hdr = bytearray(struct.pack(TimeExceeded._PACK_STR, self.data_len))
312
313         if self.data is not None:
314             hdr += self.data
315
316         return hdr
317
318     def __len__(self):
319         length = self._MIN_LEN
320         if self.data is not None:
321             length += len(self.data)
322         return length
323
324
325 icmp.set_classes(icmp._ICMP_TYPES)