blob: d698bd0e53a45b72fb39566db6a6f3dedc6b4358 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// 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
6package 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
11import (
12 "encoding/binary"
13 "fmt"
14
15 "github.com/google/gopacket"
16)
17
18const (
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.
29type 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.
46func (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.
58func RegisterASFLayerType(a ASFDataIdentifier, l gopacket.LayerType) {
59 asfDataLayerTypes[a] = l
60}
61
62var (
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.
91type 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.
109func (*ASF) LayerType() gopacket.LayerType {
110 return LayerTypeASF
111}
112
113// CanDecode returns LayerTypeASF. It partially satisfies DecodingLayer.
114func (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.
120func (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.
140func (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.
146func (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.
164func decodeASF(data []byte, p gopacket.PacketBuilder) error {
165 return decodingLayerDecoder(&ASF{}, data, p)
166}