Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1 | // Copyright 2019 The GoPacket Authors. All rights reserved. |
| 2 | // |
| 3 | // Use of this source code is governed by a BSD-style license that can be found |
| 4 | // in the LICENSE file in the root of the source tree. |
| 5 | |
| 6 | package layers |
| 7 | |
| 8 | // This file implements the RMCP ASF Presence Pong message, specified in section |
| 9 | // 3.2.4.3 of |
| 10 | // https://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf. It |
| 11 | // also contains non-competing elements from IPMI v2.0, specified in section |
| 12 | // 13.2.4 of |
| 13 | // https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.pdf. |
| 14 | |
| 15 | import ( |
| 16 | "encoding/binary" |
| 17 | "fmt" |
| 18 | |
| 19 | "github.com/google/gopacket" |
| 20 | ) |
| 21 | |
| 22 | type ( |
| 23 | // ASFEntity is the type of individual entities that a Presence Pong |
| 24 | // response can indicate support of. The entities currently implemented by |
| 25 | // the spec are IPMI and ASFv1. |
| 26 | ASFEntity uint8 |
| 27 | |
| 28 | // ASFInteraction is the type of individual interactions that a Presence |
| 29 | // Pong response can indicate support for. The interactions currently |
| 30 | // implemented by the spec are RMCP security extensions. Although not |
| 31 | // specified, IPMI uses this field to indicate support for DASH, which is |
| 32 | // supported as well. |
| 33 | ASFInteraction uint8 |
| 34 | ) |
| 35 | |
| 36 | const ( |
| 37 | // ASFDCMIEnterprise is the IANA-assigned Enterprise Number of the Data |
| 38 | // Center Manageability Interface Forum. The Presence Pong response's |
| 39 | // Enterprise field being set to this value indicates support for DCMI. The |
| 40 | // DCMI spec regards the OEM field as reserved, so these should be null. |
| 41 | ASFDCMIEnterprise uint32 = 36465 |
| 42 | |
| 43 | // ASFPresencePongEntityIPMI ANDs with Presence Pong's supported entities |
| 44 | // field if the managed system supports IPMI. |
| 45 | ASFPresencePongEntityIPMI ASFEntity = 1 << 7 |
| 46 | |
| 47 | // ASFPresencePongEntityASFv1 ANDs with Presence Pong's supported entities |
| 48 | // field if the managed system supports ASF v1.0. |
| 49 | ASFPresencePongEntityASFv1 ASFEntity = 1 |
| 50 | |
| 51 | // ASFPresencePongInteractionSecurityExtensions ANDs with Presence Pong's |
| 52 | // supported interactions field if the managed system supports RMCP v2.0 |
| 53 | // security extensions. See section 3.2.3. |
| 54 | ASFPresencePongInteractionSecurityExtensions ASFInteraction = 1 << 7 |
| 55 | |
| 56 | // ASFPresencePongInteractionDASH ANDs with Presence Pong's supported |
| 57 | // interactions field if the managed system supports DMTF DASH. See |
| 58 | // https://www.dmtf.org/standards/dash. |
| 59 | ASFPresencePongInteractionDASH ASFInteraction = 1 << 5 |
| 60 | ) |
| 61 | |
| 62 | // ASFPresencePong defines the structure of a Presence Pong message's payload. |
| 63 | // See section 3.2.4.3. |
| 64 | type ASFPresencePong struct { |
| 65 | BaseLayer |
| 66 | |
| 67 | // Enterprise is the IANA Enterprise Number of an entity that has defined |
| 68 | // OEM-specific capabilities for the managed client. If no such capabilities |
| 69 | // exist, this is set to ASF's IANA Enterprise Number. |
| 70 | Enterprise uint32 |
| 71 | |
| 72 | // OEM identifies OEM-specific capabilities. Its structure is defined by the |
| 73 | // OEM. This is set to 0s if no OEM-specific capabilities exist. This |
| 74 | // implementation does not change byte order from the wire for this field. |
| 75 | OEM [4]byte |
| 76 | |
| 77 | // We break out entities and interactions into separate booleans as |
| 78 | // discovery is the entire point of this type of message, so we assume they |
| 79 | // are accessed. It also makes gopacket's default layer printing more |
| 80 | // useful. |
| 81 | |
| 82 | // IPMI is true if IPMI is supported by the managed system. There is no |
| 83 | // explicit version in the specification, however given the dates, this is |
| 84 | // assumed to be IPMI v1.0. Support for IPMI is contained in the "supported |
| 85 | // entities" field of the presence pong payload. |
| 86 | IPMI bool |
| 87 | |
| 88 | // ASFv1 indicates support for ASF v1.0. This seems somewhat redundant as |
| 89 | // ASF must be supported in order to receive a response. This is contained |
| 90 | // in the "supported entities" field of the presence pong payload. |
| 91 | ASFv1 bool |
| 92 | |
| 93 | // SecurityExtensions indicates support for RMCP Security Extensions, |
| 94 | // specified in ASF v2.0. This will always be false for v1.x |
| 95 | // implementations. This is contained in the "supported interactions" field |
| 96 | // of the presence pong payload. This field is defined in ASF v1.0, but has |
| 97 | // no useful value. |
| 98 | SecurityExtensions bool |
| 99 | |
| 100 | // DASH is true if DMTF DASH is supported. This is not specified in ASF |
| 101 | // v2.0, but in IPMI v2.0, however the former does not preclude it, so we |
| 102 | // support it. |
| 103 | DASH bool |
| 104 | |
| 105 | // 6 bytes reserved after the entities and interactions fields, set to 0s. |
| 106 | } |
| 107 | |
| 108 | // SupportsDCMI returns whether the Presence Pong message indicates support for |
| 109 | // the Data Center Management Interface, which is an extension of IPMI v2.0. |
| 110 | func (a *ASFPresencePong) SupportsDCMI() bool { |
| 111 | return a.Enterprise == ASFDCMIEnterprise && a.IPMI && a.ASFv1 |
| 112 | } |
| 113 | |
| 114 | // LayerType returns LayerTypeASFPresencePong. It partially satisfies Layer and |
| 115 | // SerializableLayer. |
| 116 | func (*ASFPresencePong) LayerType() gopacket.LayerType { |
| 117 | return LayerTypeASFPresencePong |
| 118 | } |
| 119 | |
| 120 | // CanDecode returns LayerTypeASFPresencePong. It partially satisfies |
| 121 | // DecodingLayer. |
| 122 | func (a *ASFPresencePong) CanDecode() gopacket.LayerClass { |
| 123 | return a.LayerType() |
| 124 | } |
| 125 | |
| 126 | // DecodeFromBytes makes the layer represent the provided bytes. It partially |
| 127 | // satisfies DecodingLayer. |
| 128 | func (a *ASFPresencePong) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { |
| 129 | if len(data) < 16 { |
| 130 | df.SetTruncated() |
| 131 | return fmt.Errorf("invalid ASF presence pong payload, length %v less than 16", |
| 132 | len(data)) |
| 133 | } |
| 134 | |
| 135 | a.BaseLayer.Contents = data[:16] |
| 136 | a.BaseLayer.Payload = data[16:] |
| 137 | |
| 138 | a.Enterprise = binary.BigEndian.Uint32(data[:4]) |
| 139 | copy(a.OEM[:], data[4:8]) // N.B. no byte order change |
| 140 | a.IPMI = data[8]&uint8(ASFPresencePongEntityIPMI) != 0 |
| 141 | a.ASFv1 = data[8]&uint8(ASFPresencePongEntityASFv1) != 0 |
| 142 | a.SecurityExtensions = data[9]&uint8(ASFPresencePongInteractionSecurityExtensions) != 0 |
| 143 | a.DASH = data[9]&uint8(ASFPresencePongInteractionDASH) != 0 |
| 144 | // ignore remaining 6 bytes; should be set to 0s |
| 145 | return nil |
| 146 | } |
| 147 | |
| 148 | // NextLayerType returns LayerTypePayload, as there are no further layers to |
| 149 | // decode. This partially satisfies DecodingLayer. |
| 150 | func (a *ASFPresencePong) NextLayerType() gopacket.LayerType { |
| 151 | return gopacket.LayerTypePayload |
| 152 | } |
| 153 | |
| 154 | // SerializeTo writes the serialized fom of this layer into the SerializeBuffer, |
| 155 | // partially satisfying SerializableLayer. |
| 156 | func (a *ASFPresencePong) SerializeTo(b gopacket.SerializeBuffer, _ gopacket.SerializeOptions) error { |
| 157 | bytes, err := b.PrependBytes(16) |
| 158 | if err != nil { |
| 159 | return err |
| 160 | } |
| 161 | |
| 162 | binary.BigEndian.PutUint32(bytes[:4], a.Enterprise) |
| 163 | |
| 164 | copy(bytes[4:8], a.OEM[:]) |
| 165 | |
| 166 | bytes[8] = 0 |
| 167 | if a.IPMI { |
| 168 | bytes[8] |= uint8(ASFPresencePongEntityIPMI) |
| 169 | } |
| 170 | if a.ASFv1 { |
| 171 | bytes[8] |= uint8(ASFPresencePongEntityASFv1) |
| 172 | } |
| 173 | |
| 174 | bytes[9] = 0 |
| 175 | if a.SecurityExtensions { |
| 176 | bytes[9] |= uint8(ASFPresencePongInteractionSecurityExtensions) |
| 177 | } |
| 178 | if a.DASH { |
| 179 | bytes[9] |= uint8(ASFPresencePongInteractionDASH) |
| 180 | } |
| 181 | |
| 182 | // zero-out remaining 6 bytes |
| 183 | for i := 10; i < len(bytes); i++ { |
| 184 | bytes[i] = 0x00 |
| 185 | } |
| 186 | |
| 187 | return nil |
| 188 | } |
| 189 | |
| 190 | // decodeASFPresencePong decodes the byte slice into an RMCP-ASF Presence Pong |
| 191 | // struct. |
| 192 | func decodeASFPresencePong(data []byte, p gopacket.PacketBuilder) error { |
| 193 | return decodingLayerDecoder(&ASFPresencePong{}, data, p) |
| 194 | } |