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 5package icmp 6 7import "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. 13func multipartMessageBodyDataLen(proto int, withOrigDgram bool, b []byte, exts []Extension) (bodyLen, dataLen int) { 14 for _, ext := range exts { 15 bodyLen += ext.Len(proto) 16 } 17 if bodyLen > 0 { 18 if withOrigDgram { 19 dataLen = multipartMessageOrigDatagramLen(proto, b) 20 } 21 bodyLen += 4 // length of extension header 22 } else { 23 dataLen = len(b) 24 } 25 bodyLen += dataLen 26 return bodyLen, dataLen 27} 28 29// multipartMessageOrigDatagramLen takes b as an original datagram, 30// and returns a required length for a padded orignal datagram in wire 31// format. 32func multipartMessageOrigDatagramLen(proto int, b []byte) int { 33 roundup := func(b []byte, align int) int { 34 // According to RFC 4884, the padded original datagram 35 // field must contain at least 128 octets. 36 if len(b) < 128 { 37 return 128 38 } 39 r := len(b) 40 return (r + align - 1) & ^(align - 1) 41 } 42 switch proto { 43 case iana.ProtocolICMP: 44 return roundup(b, 4) 45 case iana.ProtocolIPv6ICMP: 46 return roundup(b, 8) 47 default: 48 return len(b) 49 } 50} 51 52// marshalMultipartMessageBody takes data as an original datagram and 53// exts as extesnsions, and returns a binary encoding of message body. 54// It can be used for non-multipart message bodies when exts is nil. 55func marshalMultipartMessageBody(proto int, withOrigDgram bool, data []byte, exts []Extension) ([]byte, error) { 56 bodyLen, dataLen := multipartMessageBodyDataLen(proto, withOrigDgram, data, exts) 57 b := make([]byte, 4+bodyLen) 58 copy(b[4:], data) 59 off := dataLen + 4 60 if len(exts) > 0 { 61 b[dataLen+4] = byte(extensionVersion << 4) 62 off += 4 // length of object header 63 for _, ext := range exts { 64 switch ext := ext.(type) { 65 case *MPLSLabelStack: 66 if err := ext.marshal(proto, b[off:]); err != nil { 67 return nil, err 68 } 69 off += ext.Len(proto) 70 case *InterfaceInfo: 71 attrs, l := ext.attrsAndLen(proto) 72 if err := ext.marshal(proto, b[off:], attrs, l); err != nil { 73 return nil, err 74 } 75 off += ext.Len(proto) 76 case *InterfaceIdent: 77 if err := ext.marshal(proto, b[off:]); err != nil { 78 return nil, err 79 } 80 off += ext.Len(proto) 81 } 82 } 83 s := checksum(b[dataLen+4:]) 84 b[dataLen+4+2] ^= byte(s) 85 b[dataLen+4+3] ^= byte(s >> 8) 86 if withOrigDgram { 87 switch proto { 88 case iana.ProtocolICMP: 89 b[1] = byte(dataLen / 4) 90 case iana.ProtocolIPv6ICMP: 91 b[0] = byte(dataLen / 8) 92 } 93 } 94 } 95 return b, nil 96} 97 98// parseMultipartMessageBody parses b as either a non-multipart 99// message body or a multipart message body. 100func parseMultipartMessageBody(proto int, typ Type, b []byte) ([]byte, []Extension, error) { 101 var l int 102 switch proto { 103 case iana.ProtocolICMP: 104 l = 4 * int(b[1]) 105 case iana.ProtocolIPv6ICMP: 106 l = 8 * int(b[0]) 107 } 108 if len(b) == 4 { 109 return nil, nil, nil 110 } 111 exts, l, err := parseExtensions(typ, b[4:], l) 112 if err != nil { 113 l = len(b) - 4 114 } 115 var data []byte 116 if l > 0 { 117 data = make([]byte, l) 118 copy(data, b[4:]) 119 } 120 return data, exts, nil 121} 122