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  }