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  }