OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / icmp / multipart.go
1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package icmp
6
7 import "golang.org/x/net/internal/iana"
8
9 // multipartMessageBodyDataLen takes b as an original datagram and
10 // exts as extensions, and returns a required length for message body
11 // and a required length for a padded original datagram in wire
12 // format.
13 func multipartMessageBodyDataLen(proto int, b []byte, exts []Extension) (bodyLen, dataLen int) {
14         for _, ext := range exts {
15                 bodyLen += ext.Len(proto)
16         }
17         if bodyLen > 0 {
18                 dataLen = multipartMessageOrigDatagramLen(proto, b)
19                 bodyLen += 4 // length of extension header
20         } else {
21                 dataLen = len(b)
22         }
23         bodyLen += dataLen
24         return bodyLen, dataLen
25 }
26
27 // multipartMessageOrigDatagramLen takes b as an original datagram,
28 // and returns a required length for a padded orignal datagram in wire
29 // format.
30 func multipartMessageOrigDatagramLen(proto int, b []byte) int {
31         roundup := func(b []byte, align int) int {
32                 // According to RFC 4884, the padded original datagram
33                 // field must contain at least 128 octets.
34                 if len(b) < 128 {
35                         return 128
36                 }
37                 r := len(b)
38                 return (r + align - 1) & ^(align - 1)
39         }
40         switch proto {
41         case iana.ProtocolICMP:
42                 return roundup(b, 4)
43         case iana.ProtocolIPv6ICMP:
44                 return roundup(b, 8)
45         default:
46                 return len(b)
47         }
48 }
49
50 // marshalMultipartMessageBody takes data as an original datagram and
51 // exts as extesnsions, and returns a binary encoding of message body.
52 // It can be used for non-multipart message bodies when exts is nil.
53 func marshalMultipartMessageBody(proto int, data []byte, exts []Extension) ([]byte, error) {
54         bodyLen, dataLen := multipartMessageBodyDataLen(proto, data, exts)
55         b := make([]byte, 4+bodyLen)
56         copy(b[4:], data)
57         off := dataLen + 4
58         if len(exts) > 0 {
59                 b[dataLen+4] = byte(extensionVersion << 4)
60                 off += 4 // length of object header
61                 for _, ext := range exts {
62                         switch ext := ext.(type) {
63                         case *MPLSLabelStack:
64                                 if err := ext.marshal(proto, b[off:]); err != nil {
65                                         return nil, err
66                                 }
67                                 off += ext.Len(proto)
68                         case *InterfaceInfo:
69                                 attrs, l := ext.attrsAndLen(proto)
70                                 if err := ext.marshal(proto, b[off:], attrs, l); err != nil {
71                                         return nil, err
72                                 }
73                                 off += ext.Len(proto)
74                         }
75                 }
76                 s := checksum(b[dataLen+4:])
77                 b[dataLen+4+2] ^= byte(s)
78                 b[dataLen+4+3] ^= byte(s >> 8)
79                 switch proto {
80                 case iana.ProtocolICMP:
81                         b[1] = byte(dataLen / 4)
82                 case iana.ProtocolIPv6ICMP:
83                         b[0] = byte(dataLen / 8)
84                 }
85         }
86         return b, nil
87 }
88
89 // parseMultipartMessageBody parses b as either a non-multipart
90 // message body or a multipart message body.
91 func parseMultipartMessageBody(proto int, b []byte) ([]byte, []Extension, error) {
92         var l int
93         switch proto {
94         case iana.ProtocolICMP:
95                 l = 4 * int(b[1])
96         case iana.ProtocolIPv6ICMP:
97                 l = 8 * int(b[0])
98         }
99         if len(b) == 4 {
100                 return nil, nil, nil
101         }
102         exts, l, err := parseExtensions(b[4:], l)
103         if err != nil {
104                 l = len(b) - 4
105         }
106         data := make([]byte, l)
107         copy(data, b[4:])
108         return data, exts, nil
109 }