github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/icmp/multipart.go (about) 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 }