blob: c7b72bf3dd4bcb387816afa47d734f73eb9d8a64 [file] [log] [blame]
Mikio Hara71586c32015-01-15 01:00:16 +09001// 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.
Mikio Hara60789862017-09-09 13:35:08 +090013func multipartMessageBodyDataLen(proto int, withOrigDgram bool, b []byte, exts []Extension) (bodyLen, dataLen int) {
Mikio Hara56fb0112018-12-27 04:18:42 +090014 bodyLen = 4 // length of leading octets
15 var extLen int
16 var rawExt bool // raw extension may contain an empty object
Mikio Hara71586c32015-01-15 01:00:16 +090017 for _, ext := range exts {
Mikio Hara56fb0112018-12-27 04:18:42 +090018 extLen += ext.Len(proto)
19 if _, ok := ext.(*RawExtension); ok {
20 rawExt = true
Mikio Hara60789862017-09-09 13:35:08 +090021 }
Mikio Hara56fb0112018-12-27 04:18:42 +090022 }
23 if extLen > 0 && withOrigDgram {
24 dataLen = multipartMessageOrigDatagramLen(proto, b)
Mikio Hara71586c32015-01-15 01:00:16 +090025 } else {
26 dataLen = len(b)
27 }
Mikio Hara56fb0112018-12-27 04:18:42 +090028 if extLen > 0 || rawExt {
29 bodyLen += 4 // length of extension header
30 }
31 bodyLen += dataLen + extLen
Mikio Hara71586c32015-01-15 01:00:16 +090032 return bodyLen, dataLen
33}
34
35// multipartMessageOrigDatagramLen takes b as an original datagram,
Oleksandr Redko7e3c19c2023-02-06 18:06:31 +000036// and returns a required length for a padded original datagram in wire
Mikio Hara71586c32015-01-15 01:00:16 +090037// format.
38func multipartMessageOrigDatagramLen(proto int, b []byte) int {
39 roundup := func(b []byte, align int) int {
40 // According to RFC 4884, the padded original datagram
41 // field must contain at least 128 octets.
42 if len(b) < 128 {
43 return 128
44 }
45 r := len(b)
Mikio Hara77544e62019-03-20 07:15:21 +090046 return (r + align - 1) &^ (align - 1)
Mikio Hara71586c32015-01-15 01:00:16 +090047 }
48 switch proto {
49 case iana.ProtocolICMP:
50 return roundup(b, 4)
51 case iana.ProtocolIPv6ICMP:
52 return roundup(b, 8)
53 default:
54 return len(b)
55 }
56}
57
58// marshalMultipartMessageBody takes data as an original datagram and
59// exts as extesnsions, and returns a binary encoding of message body.
60// It can be used for non-multipart message bodies when exts is nil.
Mikio Hara60789862017-09-09 13:35:08 +090061func marshalMultipartMessageBody(proto int, withOrigDgram bool, data []byte, exts []Extension) ([]byte, error) {
62 bodyLen, dataLen := multipartMessageBodyDataLen(proto, withOrigDgram, data, exts)
Mikio Hara56fb0112018-12-27 04:18:42 +090063 b := make([]byte, bodyLen)
Mikio Hara71586c32015-01-15 01:00:16 +090064 copy(b[4:], data)
Mikio Hara71586c32015-01-15 01:00:16 +090065 if len(exts) > 0 {
Mikio Hara56fb0112018-12-27 04:18:42 +090066 b[4+dataLen] = byte(extensionVersion << 4)
67 off := 4 + dataLen + 4 // leading octets, data, extension header
Mikio Hara71586c32015-01-15 01:00:16 +090068 for _, ext := range exts {
69 switch ext := ext.(type) {
70 case *MPLSLabelStack:
71 if err := ext.marshal(proto, b[off:]); err != nil {
72 return nil, err
73 }
74 off += ext.Len(proto)
Mikio Harac84eff72015-01-21 20:17:41 +090075 case *InterfaceInfo:
76 attrs, l := ext.attrsAndLen(proto)
77 if err := ext.marshal(proto, b[off:], attrs, l); err != nil {
78 return nil, err
79 }
80 off += ext.Len(proto)
Mikio Hara60789862017-09-09 13:35:08 +090081 case *InterfaceIdent:
82 if err := ext.marshal(proto, b[off:]); err != nil {
83 return nil, err
84 }
85 off += ext.Len(proto)
Mikio Hara56fb0112018-12-27 04:18:42 +090086 case *RawExtension:
87 copy(b[off:], ext.Data)
88 off += ext.Len(proto)
Mikio Hara71586c32015-01-15 01:00:16 +090089 }
90 }
Mikio Hara56fb0112018-12-27 04:18:42 +090091 s := checksum(b[4+dataLen:])
92 b[4+dataLen+2] ^= byte(s)
93 b[4+dataLen+3] ^= byte(s >> 8)
Mikio Hara60789862017-09-09 13:35:08 +090094 if withOrigDgram {
95 switch proto {
96 case iana.ProtocolICMP:
97 b[1] = byte(dataLen / 4)
98 case iana.ProtocolIPv6ICMP:
99 b[0] = byte(dataLen / 8)
100 }
Mikio Hara71586c32015-01-15 01:00:16 +0900101 }
102 }
103 return b, nil
104}
105
106// parseMultipartMessageBody parses b as either a non-multipart
107// message body or a multipart message body.
Mikio Hara60789862017-09-09 13:35:08 +0900108func parseMultipartMessageBody(proto int, typ Type, b []byte) ([]byte, []Extension, error) {
Mikio Hara71586c32015-01-15 01:00:16 +0900109 var l int
110 switch proto {
111 case iana.ProtocolICMP:
112 l = 4 * int(b[1])
113 case iana.ProtocolIPv6ICMP:
114 l = 8 * int(b[0])
115 }
116 if len(b) == 4 {
117 return nil, nil, nil
118 }
Mikio Hara60789862017-09-09 13:35:08 +0900119 exts, l, err := parseExtensions(typ, b[4:], l)
Mikio Hara71586c32015-01-15 01:00:16 +0900120 if err != nil {
121 l = len(b) - 4
122 }
Mikio Hara60789862017-09-09 13:35:08 +0900123 var data []byte
124 if l > 0 {
125 data = make([]byte, l)
126 copy(data, b[4:])
127 }
Mikio Hara71586c32015-01-15 01:00:16 +0900128 return data, exts, nil
129}