| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- // Copyright 2019 The GoPacket Authors. All rights reserved.
- //
- // Use of this source code is governed by a BSD-style license that can be found
- // in the LICENSE file in the root of the source tree.
- package layers
- // This file implements the ASF RMCP payload specified in section 3.2.2.3 of
- // https://www.dmtf.org/sites/default/files/standards/documents/DSP0136.pdf
- import (
- "encoding/binary"
- "fmt"
- "github.com/google/gopacket"
- )
- const (
- // ASFRMCPEnterprise is the IANA-assigned Enterprise Number of the ASF-RMCP.
- ASFRMCPEnterprise uint32 = 4542
- )
- // ASFDataIdentifier encapsulates fields used to uniquely identify the format of
- // the data block.
- //
- // While the enterprise number is almost always 4542 (ASF-RMCP), we support
- // registering layers using structs of this type as a key in case any users are
- // using OEM-extensions.
- type ASFDataIdentifier struct {
- // Enterprise is the IANA Enterprise Number associated with the entity that
- // defines the message type. A list can be found at
- // https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers.
- // This can be thought of as the namespace for the message type.
- Enterprise uint32
- // Type is the message type, defined by the entity associated with the
- // enterprise above. No pressure, but in the context of EN 4542, 1 byte is
- // the difference between sending a ping and telling a machine to do an
- // unconditional power down (0x80 and 0x12 respectively).
- Type uint8
- }
- // LayerType returns the payload layer type corresponding to an ASF message
- // type.
- func (a ASFDataIdentifier) LayerType() gopacket.LayerType {
- if lt := asfDataLayerTypes[a]; lt != 0 {
- return lt
- }
- // some layer types don't have a payload, e.g. ASF-RMCP Presence Ping.
- return gopacket.LayerTypePayload
- }
- // RegisterASFLayerType allows specifying that the data block of ASF packets
- // with a given enterprise number and type should be processed by a given layer
- // type. This overrides any existing registrations, including defaults.
- func RegisterASFLayerType(a ASFDataIdentifier, l gopacket.LayerType) {
- asfDataLayerTypes[a] = l
- }
- var (
- // ASFDataIdentifierPresencePong is the message type of the response to a
- // Presence Ping message. It indicates the sender is ASF-RMCP-aware.
- ASFDataIdentifierPresencePong = ASFDataIdentifier{
- Enterprise: ASFRMCPEnterprise,
- Type: 0x40,
- }
- // ASFDataIdentifierPresencePing is a message type sent to a managed client
- // to solicit a Presence Pong response. Clients may ignore this if the RMCP
- // version is unsupported. Sending this message with a sequence number <255
- // is the recommended way of finding out whether an implementation sends
- // RMCP ACKs (e.g. iDRAC does, Super Micro does not).
- //
- // Systems implementing IPMI must respond to this ping to conform to the
- // spec, so it is a good substitute for an ICMP ping.
- ASFDataIdentifierPresencePing = ASFDataIdentifier{
- Enterprise: ASFRMCPEnterprise,
- Type: 0x80,
- }
- // asfDataLayerTypes is used to find the next layer for a given ASF header.
- asfDataLayerTypes = map[ASFDataIdentifier]gopacket.LayerType{
- ASFDataIdentifierPresencePong: LayerTypeASFPresencePong,
- }
- )
- // ASF defines ASF's generic RMCP message Data block format. See section
- // 3.2.2.3.
- type ASF struct {
- BaseLayer
- ASFDataIdentifier
- // Tag is used to match request/response pairs. The tag of a response is set
- // to that of the message it is responding to. If a message is
- // unidirectional, i.e. not part of a request/response pair, this is set to
- // 255.
- Tag uint8
- // 1 byte reserved, set to 0x00.
- // Length is the length of this layer's payload in bytes.
- Length uint8
- }
- // LayerType returns LayerTypeASF. It partially satisfies Layer and
- // SerializableLayer.
- func (*ASF) LayerType() gopacket.LayerType {
- return LayerTypeASF
- }
- // CanDecode returns LayerTypeASF. It partially satisfies DecodingLayer.
- func (a *ASF) CanDecode() gopacket.LayerClass {
- return a.LayerType()
- }
- // DecodeFromBytes makes the layer represent the provided bytes. It partially
- // satisfies DecodingLayer.
- func (a *ASF) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
- if len(data) < 8 {
- df.SetTruncated()
- return fmt.Errorf("invalid ASF data header, length %v less than 8",
- len(data))
- }
- a.BaseLayer.Contents = data[:8]
- a.BaseLayer.Payload = data[8:]
- a.Enterprise = binary.BigEndian.Uint32(data[:4])
- a.Type = uint8(data[4])
- a.Tag = uint8(data[5])
- // 1 byte reserved
- a.Length = uint8(data[7])
- return nil
- }
- // NextLayerType returns the layer type corresponding to the message type of
- // this ASF data layer. This partially satisfies DecodingLayer.
- func (a *ASF) NextLayerType() gopacket.LayerType {
- return a.ASFDataIdentifier.LayerType()
- }
- // SerializeTo writes the serialized fom of this layer into the SerializeBuffer,
- // partially satisfying SerializableLayer.
- func (a *ASF) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
- payload := b.Bytes()
- bytes, err := b.PrependBytes(8)
- if err != nil {
- return err
- }
- binary.BigEndian.PutUint32(bytes[:4], a.Enterprise)
- bytes[4] = uint8(a.Type)
- bytes[5] = a.Tag
- bytes[6] = 0x00
- if opts.FixLengths {
- a.Length = uint8(len(payload))
- }
- bytes[7] = a.Length
- return nil
- }
- // decodeASF decodes the byte slice into an RMCP-ASF data struct.
- func decodeASF(data []byte, p gopacket.PacketBuilder) error {
- return decodingLayerDecoder(&ASF{}, data, p)
- }
|