github.com/gopacket/gopacket@v1.1.0/layers/asf.go (about) 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 ASF RMCP payload specified in section 3.2.2.3 of 9 // https://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf 10 11 import ( 12 "encoding/binary" 13 "fmt" 14 15 "github.com/gopacket/gopacket" 16 ) 17 18 const ( 19 // ASFRMCPEnterprise is the IANA-assigned Enterprise Number of the ASF-RMCP. 20 ASFRMCPEnterprise uint32 = 4542 21 ) 22 23 // ASFDataIdentifier encapsulates fields used to uniquely identify the format of 24 // the data block. 25 // 26 // While the enterprise number is almost always 4542 (ASF-RMCP), we support 27 // registering layers using structs of this type as a key in case any users are 28 // using OEM-extensions. 29 type ASFDataIdentifier struct { 30 31 // Enterprise is the IANA Enterprise Number associated with the entity that 32 // defines the message type. A list can be found at 33 // https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers. 34 // This can be thought of as the namespace for the message type. 35 Enterprise uint32 36 37 // Type is the message type, defined by the entity associated with the 38 // enterprise above. No pressure, but in the context of EN 4542, 1 byte is 39 // the difference between sending a ping and telling a machine to do an 40 // unconditional power down (0x80 and 0x12 respectively). 41 Type uint8 42 } 43 44 // LayerType returns the payload layer type corresponding to an ASF message 45 // type. 46 func (a ASFDataIdentifier) LayerType() gopacket.LayerType { 47 if lt := asfDataLayerTypes[a]; lt != 0 { 48 return lt 49 } 50 51 // some layer types don't have a payload, e.g. ASF-RMCP Presence Ping. 52 return gopacket.LayerTypePayload 53 } 54 55 // RegisterASFLayerType allows specifying that the data block of ASF packets 56 // with a given enterprise number and type should be processed by a given layer 57 // type. This overrides any existing registrations, including defaults. 58 func RegisterASFLayerType(a ASFDataIdentifier, l gopacket.LayerType) { 59 asfDataLayerTypes[a] = l 60 } 61 62 var ( 63 // ASFDataIdentifierPresencePong is the message type of the response to a 64 // Presence Ping message. It indicates the sender is ASF-RMCP-aware. 65 ASFDataIdentifierPresencePong = ASFDataIdentifier{ 66 Enterprise: ASFRMCPEnterprise, 67 Type: 0x40, 68 } 69 70 // ASFDataIdentifierPresencePing is a message type sent to a managed client 71 // to solicit a Presence Pong response. Clients may ignore this if the RMCP 72 // version is unsupported. Sending this message with a sequence number <255 73 // is the recommended way of finding out whether an implementation sends 74 // RMCP ACKs (e.g. iDRAC does, Super Micro does not). 75 // 76 // Systems implementing IPMI must respond to this ping to conform to the 77 // spec, so it is a good substitute for an ICMP ping. 78 ASFDataIdentifierPresencePing = ASFDataIdentifier{ 79 Enterprise: ASFRMCPEnterprise, 80 Type: 0x80, 81 } 82 83 // asfDataLayerTypes is used to find the next layer for a given ASF header. 84 asfDataLayerTypes = map[ASFDataIdentifier]gopacket.LayerType{ 85 ASFDataIdentifierPresencePong: LayerTypeASFPresencePong, 86 } 87 ) 88 89 // ASF defines ASF's generic RMCP message Data block format. See section 90 // 3.2.2.3. 91 type ASF struct { 92 BaseLayer 93 ASFDataIdentifier 94 95 // Tag is used to match request/response pairs. The tag of a response is set 96 // to that of the message it is responding to. If a message is 97 // unidirectional, i.e. not part of a request/response pair, this is set to 98 // 255. 99 Tag uint8 100 101 // 1 byte reserved, set to 0x00. 102 103 // Length is the length of this layer's payload in bytes. 104 Length uint8 105 } 106 107 // LayerType returns LayerTypeASF. It partially satisfies Layer and 108 // SerializableLayer. 109 func (*ASF) LayerType() gopacket.LayerType { 110 return LayerTypeASF 111 } 112 113 // CanDecode returns LayerTypeASF. It partially satisfies DecodingLayer. 114 func (a *ASF) CanDecode() gopacket.LayerClass { 115 return a.LayerType() 116 } 117 118 // DecodeFromBytes makes the layer represent the provided bytes. It partially 119 // satisfies DecodingLayer. 120 func (a *ASF) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { 121 if len(data) < 8 { 122 df.SetTruncated() 123 return fmt.Errorf("invalid ASF data header, length %v less than 8", 124 len(data)) 125 } 126 127 a.BaseLayer.Contents = data[:8] 128 a.BaseLayer.Payload = data[8:] 129 130 a.Enterprise = binary.BigEndian.Uint32(data[:4]) 131 a.Type = uint8(data[4]) 132 a.Tag = uint8(data[5]) 133 // 1 byte reserved 134 a.Length = uint8(data[7]) 135 return nil 136 } 137 138 // NextLayerType returns the layer type corresponding to the message type of 139 // this ASF data layer. This partially satisfies DecodingLayer. 140 func (a *ASF) NextLayerType() gopacket.LayerType { 141 return a.ASFDataIdentifier.LayerType() 142 } 143 144 // SerializeTo writes the serialized fom of this layer into the SerializeBuffer, 145 // partially satisfying SerializableLayer. 146 func (a *ASF) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 147 payload := b.Bytes() 148 bytes, err := b.PrependBytes(8) 149 if err != nil { 150 return err 151 } 152 binary.BigEndian.PutUint32(bytes[:4], a.Enterprise) 153 bytes[4] = uint8(a.Type) 154 bytes[5] = a.Tag 155 bytes[6] = 0x00 156 if opts.FixLengths { 157 a.Length = uint8(len(payload)) 158 } 159 bytes[7] = a.Length 160 return nil 161 } 162 163 // decodeASF decodes the byte slice into an RMCP-ASF data struct. 164 func decodeASF(data []byte, p gopacket.PacketBuilder) error { 165 return decodingLayerDecoder(&ASF{}, data, p) 166 }