asf.go 5.3 KB

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