Documentation
¶
Overview ¶
Package bmc holds the runtime state of a Baseboard Management Controller.
Nothing in this package does I/O; it is pure in-memory state backed by the abstractions in pkg/hal. The server layer (pkg/server) wires transport, clock, and HAL together with this state to produce a working BMC.
Index ¶
- Constants
- Variables
- func FormatV15AuthTypes(types []V15AuthType) string
- func GenerateChallenge(dst *[16]byte) error
- func GenerateInboundSeq() (uint32, error)
- func InboundSeqValid(last, seq uint32) bool
- func PackSessionIDLE(id uint32) []byte
- func StorageMissing(err error) bool
- func SupportedCipherSuite(id types.CipherSuiteID) bool
- func V15AuthTypeName(t V15AuthType) string
- func V15AuthTypeToCapsBit(t V15AuthType) uint8
- func V15InboundSeqValid(sess *V15Session, seq uint32) bool
- type BMC
- func (b *BMC) Clock() clock.Clock
- func (b *BMC) FRUInventory() *FRUInventory
- func (b *BMC) HAL() hal.HAL
- func (b *BMC) HasKG() bool
- func (b *BMC) ResolvedCipherSuites() []types.CipherSuiteID
- func (b *BMC) ResolvedKG() []byte
- func (b *BMC) ResolvedV15AuthTypes() []V15AuthType
- func (b *BMC) SDRRepository() *SDRRepository
- func (b *BMC) SetCipherSuites(ids []types.CipherSuiteID)
- func (b *BMC) V15AuthTypeEnabled(authType V15AuthType) bool
- func (b *BMC) V15LANEnabled() bool
- type Channel
- type ChannelAccessMode
- type ChannelMedium
- type ChannelStore
- type DeviceInfo
- type FRUInventory
- type Option
- type PrivilegeLevel
- type ReconnectPolicy
- type SDRCapabilities
- type SDRRepoAllocInfo
- type SDRRepoInfo
- type SDRRepoStore
- type SDRRepository
- func (r *SDRRepository) AllocInfo(ctx context.Context) (*SDRRepoAllocInfo, error)
- func (r *SDRRepository) GetRecord(ctx context.Context, recordID uint16) (record []byte, nextID uint16, err error)
- func (r *SDRRepository) Info(ctx context.Context) (*SDRRepoInfo, error)
- func (r *SDRRepository) RecordIDs(ctx context.Context) ([]uint16, error)
- type SOLConfig
- type SOLInstance
- type SOLSendFunc
- type SOLSenderFactory
- type SOLStore
- func (s *SOLStore) Activate(ctx context.Context, sess *Session, wantEnc, wantAuth bool) (*SOLInstance, error)
- func (s *SOLStore) ActivationStatus() (capacity uint8, active1to8, active9to16 uint8)
- func (s *SOLStore) ActiveSessionID(instance uint8) uint32
- func (s *SOLStore) CloseAll()
- func (s *SOLStore) Config() *SOLConfig
- func (s *SOLStore) Deactivate(sess *Session) error
- func (s *SOLStore) DeactivateBySession(bmcID uint32)
- func (s *SOLStore) InstanceBySession(bmcID uint32) *SOLInstance
- func (s *SOLStore) ProcessPacket(ctx context.Context, sessionID uint32, in *types.SOLPayloadPacket) *types.SOLPayloadPacket
- func (s *SOLStore) SetReconnectPolicy(p *ReconnectPolicy)
- func (s *SOLStore) SetSenderFactory(f SOLSenderFactory)
- func (s *SOLStore) Supported() bool
- func (s *SOLStore) SuspendResumeEncryption(sess *Session, op uint8) error
- type Session
- type SessionState
- type SessionStore
- func (s *SessionStore) Activate(bmcID uint32) error
- func (s *SessionStore) Allocate(consoleID uint32, authAlg types.AuthAlg, integrityAlg types.IntegrityAlg, ...) (*Session, error)
- func (s *SessionStore) Cap() int
- func (s *SessionStore) Close(bmcID uint32) error
- func (s *SessionStore) Count() int
- func (s *SessionStore) EvictExpired() int
- func (s *SessionStore) Get(bmcID uint32) (*Session, error)
- func (s *SessionStore) SetOnRemove(fn func(bmcID uint32))
- func (s *SessionStore) Touch(bmcID uint32)
- type SessionStoreOption
- type User
- type UserChannelAccess
- type UserPayloadAccess
- type UserStore
- func (s *UserStore) Add(id uint8, name string) (*User, error)
- func (s *UserStore) Count() int
- func (s *UserStore) CountEnabled() int
- func (s *UserStore) Delete(id uint8) error
- func (s *UserStore) FindEnabledByNameOnChannel(name string, channel uint8) (*User, error)
- func (s *UserStore) Get(id uint8) (*User, error)
- func (s *UserStore) GetByName(name string) (*User, error)
- func (s *UserStore) MaxUserCount() uint8
- func (s *UserStore) Update(id uint8, fn func(*User) error) error
- func (s *UserStore) Upsert(id uint8, fn func(*User) error) error
- type UserStoreOption
- type V15AuthType
- type V15Session
- type V15SessionState
- type V15SessionStore
- func (s *V15SessionStore) Activate(pending *V15Session, permanentID, inboundSeq, outboundSeq uint32, ...) error
- func (s *V15SessionStore) Cap() int
- func (s *V15SessionStore) Close(id uint32) error
- func (s *V15SessionStore) Count() int
- func (s *V15SessionStore) CountActiveSessions() int
- func (s *V15SessionStore) CountActiveSessionsForUser(userID uint8) int
- func (s *V15SessionStore) CountActiveSessionsWithMaxPrivilegeAtLeast(min PrivilegeLevel) int
- func (s *V15SessionStore) CreatePending(authType V15AuthType, user *User, challenge [16]byte, channel uint8) (*V15Session, error)
- func (s *V15SessionStore) EvictExpired() int
- func (s *V15SessionStore) Get(id uint32) (*V15Session, error)
- func (s *V15SessionStore) Touch(id uint32)
Constants ¶
const ( // SOLMaxInstances is the number of simultaneously activatable SOL payload // instances (spec v2.0 Table 24-6, 1-based). One instance matches the // single shared serial port of the reference hardware model (§15.3). SOLMaxInstances = 1 // SOLMaxPayloadChars bounds character data per SOL packet. The Accepted // Character Count field is one byte (Table 15-2) and the 4-byte SOL // packet header shares the 255-byte reported payload size. SOLMaxPayloadChars = 251 // SOLRXBufferCap bounds console output buffered between remote-console // polls. A full buffer applies backpressure (draining pauses until the // console catches up) — the in-tree equivalent of the BMC deasserting // CTS (§15.6) — so buffered data is never silently dropped. SOLRXBufferCap = 4096 // SOLPayloadUDPPortDefault is the primary RMCP port reported when the // server transport does not expose its bound address. SOLPayloadUDPPortDefault = 623 )
const ( SOLEncryptionOpSuspend = 0 SOLEncryptionOpResume = 1 SOLEncryptionOpRegenIV = 2 )
Table 24-5 operations for Suspend/Resume Payload Encryption.
const ( MaxUsers = 63 // IPMI spec allows user IDs 1-63 MaxUserNameLen = 16 MaxPasswordLen = 20 // 20 bytes for IPMI 2.0 passwords )
const DefaultInactivityTimeout = 60 * time.Second
Session inactivity timeout per IPMI spec:
- v1.5 §6.11.13 Session Inactivity Timeout
- v2.0 §6.12.15 Session Inactivity Timeout
const DefaultInactivityTimeoutTolerance = 3 * time.Second
DefaultInactivityTimeoutTolerance is the LAN inactivity tolerance per IPMI v1.5 Table 6-7 (+/- 3 seconds).
const DefaultSessionEvictInterval = 3 * time.Second
DefaultSessionEvictInterval is how often the server scans for idle sessions. The spec defines the 60-second inactivity limit, not the scan period.
const MaxSessions = 4
MaxSessions is the minimum number of concurrent sessions required by the spec.
Variables ¶
var ( // ErrSOLAlreadyActive → CodeActivatePayloadAlreadyActive (Table 24-2). ErrSOLAlreadyActive = errors.New("SOL payload already active") // ErrSOLDisabled → CodeActivatePayloadTypeDisabled (Table 24-2). ErrSOLDisabled = errors.New("SOL payload type is disabled") // ErrSOLPrivilege → CodeInsufficientPrivilege: session privilege below the // configured SOL level. ErrSOLPrivilege = errors.New("insufficient privilege to activate SOL") // (Table 24-2): the session negotiated no encryption algorithm. ErrSOLEncryptionUnavailable = errors.New("cannot activate SOL with encryption") // ErrSOLEncryptionRequired → CodeActivatePayloadCannotActivateWithoutEncryption // (Table 24-2): policy forces encryption the console declined. ErrSOLEncryptionRequired = errors.New("cannot activate SOL without encryption") // defines no authentication-specific completion code, so an unsatisfiable // authentication request/policy falls back to the generic invalid-data-field // code. ErrSOLAuthenticationUnavailable = errors.New("cannot activate SOL with authentication") // ErrSOLInstanceNotActive → CodeSuspendResumePayloadEncryptionNotActive // (Table 24-5): the session owns no active SOL payload instance. ErrSOLInstanceNotActive = errors.New("SOL payload instance not active") // ErrSOLEncryptionForced → CodeSuspendResumePayloadEncryptionNotAllowed // (Table 24-5): SOL configuration parameter #2 forces encryption, so // suspending it is not allowed. ErrSOLEncryptionForced = errors.New("SOL encryption forced by configuration") // CodeSuspendResumePayloadEncryptionNotAvailable (Table 24-5): the session // negotiated no encryption algorithm at open time. ErrSOLEncryptionUnavailableForSession = errors.New("encryption not available for session") // ErrSOLOperationUnsupported → CodeSuspendResumePayloadEncryptionNotSupported // (Table 24-5): IV regeneration is xRC4-specific; AES-CBC payloads draw a // fresh IV per packet already. ErrSOLOperationUnsupported = errors.New("operation not supported for SOL payload") // ErrSOLNotActive → CodeDeactivatePayloadAlreadyDeactivated (Table 24-3). ErrSOLNotActive = errors.New("SOL payload not active") // ErrSOLNotOwner → CodeInsufficientPrivilege (Deactivate): session owns no // instance and lacks the privilege to force-deactivate another session's // payload. ErrSOLNotOwner = errors.New("SOL payload owned by another session") )
SOL activation failure reasons, mapped by the Activate Payload handler to the command-specific completion codes named in pkg/types (spec v2.0 Table 24-2 / Table 24-3 / Table 24-5).
var DefaultCipherSuites = []types.CipherSuiteID{types.CipherSuiteID3, types.CipherSuiteID17}
DefaultCipherSuites is the cipher suite set advertised when no explicit configuration is provided. It contains the spec-mandatory suite 3 plus the recommended SHA256 suite 17.
var DefaultReconnectPolicy = ReconnectPolicy{Initial: time.Second, Factor: 2, Cap: 30 * time.Second}
DefaultReconnectPolicy is the built-in strategy: retry after 1s, then double to a 30s cap, forever. VM-migration-scale outages (minutes) are covered by the cap holding: attempts keep coming, just no more often than every 30s.
var DefaultV15AuthTypes = []V15AuthType{V15AuthTypeMD5}
DefaultV15AuthTypes is the default set of v1.5 auth types the reference BMC advertises and accepts.
var ErrChannelNotFound = errors.New("channel not found")
ErrChannelNotFound is returned when the requested channel number is not configured.
var ErrInvalidUserID = errors.New("user ID must be between 1 and 63")
ErrInvalidUserID is returned for user IDs outside the valid range 1-63.
var ErrNoSession = errors.New("session not found")
ErrNoSession is returned when the session ID is not in the store.
var ErrSessionFull = errors.New("no session slots available")
ErrSessionFull is returned when the store has reached capacity.
var ErrUserNotFound = errors.New("user not found")
ErrUserNotFound is returned when a user ID or name does not exist.
var ErrUsernameTaken = errors.New("username already taken")
ErrUsernameTaken is returned when trying to create a user with an already-used name.
Functions ¶
func FormatV15AuthTypes ¶
func FormatV15AuthTypes(types []V15AuthType) string
FormatV15AuthTypes formats auth types for logging (e.g. "md5,md2").
func GenerateChallenge ¶
GenerateChallenge fills dst with random bytes for Get Session Challenge.
func GenerateInboundSeq ¶
GenerateInboundSeq returns a non-zero initial inbound sequence number.
func InboundSeqValid ¶
InboundSeqValid checks whether seq is within the acceptable sliding window defined by the IPMI spec (section 6.12.13): +15 / -16 of the last accepted value. Session sequence numbers start at 1; 0 is reserved for pre-session packets.
func PackSessionIDLE ¶
PackSessionIDLE is a helper for auth code input construction.
func StorageMissing ¶
StorageMissing reports whether err indicates a missing FRU device or SDR record (mapped to completion code CBh by storage handlers).
func SupportedCipherSuite ¶
func SupportedCipherSuite(id types.CipherSuiteID) bool
SupportedCipherSuite reports whether the reference server implements every algorithm in the named cipher suite. Configuring an unsupported suite would cause a runtime handshake failure, so callers validate with this before installing a cipher suite list.
func V15AuthTypeName ¶
func V15AuthTypeName(t V15AuthType) string
V15AuthTypeName returns a human-readable name for t.
func V15AuthTypeToCapsBit ¶
func V15AuthTypeToCapsBit(t V15AuthType) uint8
V15AuthTypeToCapsBit maps an auth type to the corresponding bit in Get Channel Authentication Capabilities response byte 3 (bits [5:0]).
func V15InboundSeqValid ¶
func V15InboundSeqValid(sess *V15Session, seq uint32) bool
V15InboundSeqValid reports whether seq is acceptable under Option 1 without mutating session state (for tests).
Types ¶
type BMC ¶
type BMC struct {
Info DeviceInfo
GUID [16]byte
Users *UserStore
Channels *ChannelStore
Sessions *SessionStore
// V15Sessions tracks IPMI v1.5 LAN sessions (separate from RMCP+ sessions).
V15Sessions *V15SessionStore
// SDRRepo tracks SDR repository reservation state (v2.0§33.11).
SDRRepo *SDRRepoStore
// SOL holds the SOL payload configuration (v2.0 Table 26-5) and the
// active SOL instance state machine (v2.0 §15).
SOL *SOLStore
// contains filtered or unexported fields
}
BMC is the central state object for an IPMI server.
Callers create a BMC via New and pass it to the server together with a transport and HAL. The BMC does not own any goroutines; lifecycle management belongs to the server.
func New ¶
New creates a BMC with sane defaults.
h is required; it provides hardware access. opts are applied in order.
func (*BMC) FRUInventory ¶
func (b *BMC) FRUInventory() *FRUInventory
FRUInventory returns the FRU inventory , or nil when the backing HAL provides no FRU storage.
func (*BMC) HasKG ¶ added in v0.9.1
HasKG reports whether a BMC key (Kg) is configured, without copying it.
func (*BMC) ResolvedCipherSuites ¶
func (b *BMC) ResolvedCipherSuites() []types.CipherSuiteID
ResolvedCipherSuites returns a copy of the cipher suite list to use for advertisement, falling back to DefaultCipherSuites when none was configured.
func (*BMC) ResolvedKG ¶ added in v0.9.1
ResolvedKG returns a copy of the BMC key (Kg), or nil in one-key mode.
func (*BMC) ResolvedV15AuthTypes ¶
func (b *BMC) ResolvedV15AuthTypes() []V15AuthType
ResolvedV15AuthTypes returns a copy of the v1.5 auth type list, defaulting to MD5.
func (*BMC) SDRRepository ¶
func (b *BMC) SDRRepository() *SDRRepository
SDRRepository returns the cached SDR record repository, or nil when the backing HAL provides no SDR storage.
func (*BMC) SetCipherSuites ¶
func (b *BMC) SetCipherSuites(ids []types.CipherSuiteID)
SetCipherSuites replaces the configured cipher suite list. Each ID must be supported by the reference server (SupportedCipherSuite); an unsupported ID panics, failing at configuration time rather than at handshake time.
func (*BMC) V15AuthTypeEnabled ¶
func (b *BMC) V15AuthTypeEnabled(authType V15AuthType) bool
V15AuthTypeEnabled reports whether authType is configured on this BMC.
func (*BMC) V15LANEnabled ¶
V15LANEnabled reports whether the BMC advertises and accepts IPMI v1.5 sessions.
type Channel ¶
type Channel struct {
Number uint8
// Medium is the channel's physical medium. It is security-relevant: the
// handler privilege check treats a session-less request on a
// [ChannelMediumSystemIF] channel as locally authorized (the system
// interface is inherently local), so labeling a network-reachable channel
// as the system interface, or attaching a session to the system-interface
// channel, would grant unauthenticated callers full privilege.
Medium ChannelMedium
AccessMode ChannelAccessMode
// MaxPrivilege is the maximum privilege level allowed on this channel.
MaxPrivilege PrivilegeLevel
// PerMessageAuth and UserLevelAuth reflect the channel security settings.
PerMessageAuth bool
UserLevelAuth bool
// PEFAlerts controls whether PEF alerting is enabled on this channel.
PEFAlerts bool
}
Channel holds the configuration for a single IPMI channel.
type ChannelAccessMode ¶
type ChannelAccessMode uint8
ChannelAccessMode controls whether a channel accepts connections.
const ( ChannelAccessDisabled ChannelAccessMode = 0x00 ChannelAccessPreBootOnly ChannelAccessMode = 0x01 ChannelAccessAlways ChannelAccessMode = 0x02 )
type ChannelMedium ¶
type ChannelMedium uint8
ChannelMedium identifies the physical medium of a channel (LAN, serial, etc.).
const ( ChannelMediumIPMBv10 ChannelMedium = 0x01 ChannelMediumICMB ChannelMedium = 0x02 ChannelMediumLAN ChannelMedium = 0x04 ChannelMediumSerial ChannelMedium = 0x05 ChannelMediumSMBus ChannelMedium = 0x06 ChannelMediumSMBusv20 ChannelMedium = 0x07 ChannelMediumUSBv1 ChannelMedium = 0x08 ChannelMediumUSBv2 ChannelMedium = 0x09 ChannelMediumSystemIF ChannelMedium = 0x0C )
type ChannelStore ¶
type ChannelStore struct {
// contains filtered or unexported fields
}
ChannelStore holds the configuration for all BMC channels.
Channel numbers follow the IPMI spec:
- 0x00 – primary IPMB
- 0x01-0x0B – implementation-specific
- 0x0E – current channel (self-reference, resolved by caller)
- 0x0F – system interface
func NewChannelStore ¶
func NewChannelStore() *ChannelStore
NewChannelStore returns a ChannelStore pre-populated with a default LAN channel (1) and the system interface (15 / 0x0F).
func (*ChannelStore) All ¶
func (s *ChannelStore) All() []*Channel
All returns snapshot copies of all configured channels.
func (*ChannelStore) Get ¶
func (s *ChannelStore) Get(n uint8) (*Channel, error)
Get returns a snapshot copy of the channel at number n, or ErrChannelNotFound. Channel is all scalar fields, so the copy is a complete, independent snapshot; mutate the store via ChannelStore.Set.
func (*ChannelStore) Set ¶
func (s *ChannelStore) Set(ch *Channel)
Set adds or replaces the channel at number n, storing a private copy so the caller cannot mutate stored state afterwards.
type DeviceInfo ¶
type DeviceInfo struct {
DeviceID uint8
DeviceRevision uint8
FirmwareMajor uint8 // major revision (bits 6:0)
FirmwareMinor uint8 // minor revision, BCD
IPMIVersion uint8 // 0x20 for IPMI 2.0
ManufacturerID uint32
ProductID uint16
AuxFirmwareRev [4]byte
// AdditionalDeviceSupport bitfield per Table 20-2.
AdditionalDeviceSupport uint8
}
DeviceInfo contains the identification data returned by Get Device ID.
type FRUInventory ¶
type FRUInventory struct {
// contains filtered or unexported fields
}
FRUInventory reads FRU inventory blobs from hal.FRUStore and implements FRU Device semantics for Storage NetFn handlers (v2.0§34).
func NewFRUInventory ¶
func NewFRUInventory(store hal.FRUStore) *FRUInventory
NewFRUInventory returns an inventory backed by store.
type Option ¶
type Option func(*BMC)
Option configures a BMC.
func WithCipherSuites ¶
func WithCipherSuites(ids []types.CipherSuiteID) Option
WithCipherSuites sets the RMCP+ cipher suites the server advertises and accepts. Each ID must be a suite the reference server implements (SupportedCipherSuite); otherwise an error is returned by New and the default suite list is kept. Pass nil/empty to restore DefaultCipherSuites.
func WithClock ¶
WithClock injects a custom clock.Clock. Defaults to clock.Real.
func WithKG ¶
WithKG sets the BMC-level key (Kg) used for two-key RAKP authentication. Leave unset (or pass nil) to use one-key mode (Kuid only).
func WithV15AuthTypes ¶
func WithV15AuthTypes(types []V15AuthType) Option
WithV15AuthTypes sets the IPMI v1.5 authentication types the BMC advertises and accepts. Pass nil/empty to restore DefaultV15AuthTypes.
func WithV15Disabled ¶
func WithV15Disabled() Option
WithV15Disabled turns off IPMI v1.5 LAN session support. RMCP+ (v2.0) is unaffected.
type PrivilegeLevel ¶
type PrivilegeLevel uint8
PrivilegeLevel mirrors types.PrivilegeLevel so bmc stays free of wire-type conversions in session state; handlers map to types before sending responses.
const ( PrivilegeLevelCallback PrivilegeLevel = 0x01 PrivilegeLevelUser PrivilegeLevel = 0x02 PrivilegeLevelOperator PrivilegeLevel = 0x03 PrivilegeLevelAdministrator PrivilegeLevel = 0x04 PrivilegeLevelOEM PrivilegeLevel = 0x05 PrivilegeLevelNoAccess PrivilegeLevel = 0x0F )
type ReconnectPolicy ¶ added in v0.9.1
type ReconnectPolicy struct {
// Initial is the delay after the first failure; 0 retries immediately.
Initial time.Duration
// Factor multiplies the delay on each failure (>= 1).
Factor float64
// Jitter adds a random delay of up to Jitter × the computed delay
// (0..1) to desynchronize concurrent reconnection attempts; 0 = none.
Jitter float64
// Cap bounds the delay; <= 0 means unbounded.
Cap time.Duration
// Steps bounds the number of reconnect attempts (1-based); once
// exhausted the instance gives up and behaves as if reconnection were
// disabled. 0 means retry forever.
Steps int
}
ReconnectPolicy controls when the pump retries attaching to a failed console, after reconnection has been enabled via SOLStore.SetReconnectPolicy. By default reconnection is disabled: the payload stays active, reports status bit [5] (Table 15-2), and recovers only via deactivate/reactivate — the spec's own behavior.
Field semantics follow k8s.io/apimachinery/pkg/util/wait.Backoff. The delay for attempt n (n ≥ 1, counting from the first failure) is
Initial * Factor^(n-1), capped at Cap, plus a jitter of up to Jitter × the capped value.
Console failures and reconnection are invisible to the remote console: ipmitool keeps its SOL session alive with a Get Device ID keepalive every 15s (ipmi_sol.c, SOL_KEEPALIVE_TIMEOUT) and only exits after 6 missed keepalives (~90s), so the server may back off as long as its RMCP+ path stays up. Keystrokes typed during the outage are lost either way: ipmitool treats a NACK as delivered and never retransmits.
type SDRCapabilities ¶
type SDRCapabilities struct {
ModalUpdate bool
NonModalUpdate bool
DeleteSDR bool
PartialAddSDR bool
ReserveRepo bool
GetAllocInfo bool
}
SDRCapabilities describes which SDR repository operations this BMC supports. Handlers map these flags onto storage.SDROperationSupport (v2.0§33.9).
type SDRRepoAllocInfo ¶
type SDRRepoAllocInfo struct {
PossibleAllocUnits uint16
AllocUnitSize uint16
FreeAllocUnits uint16
LargestFreeBlock uint16
MaximumRecordSize uint8
}
SDRRepoAllocInfo is BMC-side allocation accounting (not a wire response). Handlers map this to storage.GetSDRRepoAllocInfoResponse (v2.0§33.10).
type SDRRepoInfo ¶
type SDRRepoInfo struct {
SDRVersion uint8
RecordCount uint16
FreeBytes int // raw free capacity; §33.9 wire encoding is the handler's job
MostRecentAdd time.Time
MostRecentErase time.Time
Overflow bool
Capabilities SDRCapabilities
}
SDRRepoInfo is BMC-side repository status (not a wire response). Handlers map this to storage.GetSDRRepoInfoResponse (v2.0§33.9).
type SDRRepoStore ¶
type SDRRepoStore struct {
// contains filtered or unexported fields
}
SDRRepoStore tracks the active SDR repository reservation (v2.0§33.11).
func NewSDRRepoStore ¶
func NewSDRRepoStore() *SDRRepoStore
NewSDRRepoStore returns an empty SDR reservation tracker.
func (*SDRRepoStore) Reserve ¶
func (s *SDRRepoStore) Reserve() uint16
Reserve invalidates any prior reservation and returns a new non-zero ID.
func (*SDRRepoStore) Validate ¶
func (s *SDRRepoStore) Validate(id uint16) bool
Validate reports whether id matches the active reservation.
type SDRRepository ¶
type SDRRepository struct {
// contains filtered or unexported fields
}
SDRRepository reads SDR records from hal.SDRStore and implements repository semantics for Storage NetFn handlers (v2.0§33).
func NewSDRRepository ¶
func NewSDRRepository(store hal.SDRStore, clk clock.Clock) *SDRRepository
NewSDRRepository returns a repository backed by store.
func (*SDRRepository) AllocInfo ¶
func (r *SDRRepository) AllocInfo(ctx context.Context) (*SDRRepoAllocInfo, error)
AllocInfo returns BMC-side allocation accounting per v2.0§33.10 semantics.
func (*SDRRepository) GetRecord ¶
func (r *SDRRepository) GetRecord(ctx context.Context, recordID uint16) (record []byte, nextID uint16, err error)
GetRecord returns the wire record and next Record ID for repository traversal. Per v2.0§33.12: recordID 0000h maps to the first SDR; FFFFh maps to the last.
func (*SDRRepository) Info ¶
func (r *SDRRepository) Info(ctx context.Context) (*SDRRepoInfo, error)
Info returns BMC-side SDR repository status per v2.0§33.9 semantics.
type SOLConfig ¶ added in v0.9.1
type SOLConfig struct {
// PayloadPort is the RMCP port carrying the SOL payload (Table 26-5 #8).
// Server-internal, written once at construction and never settable via
// IPMI (#7/#8 are read-only per SetParam), so a plain field suffices.
PayloadPort uint16
// contains filtered or unexported fields
}
SOLConfig holds the SOL configuration parameters of spec v2.0 Table 26-5. Only Set In Progress (#0) and the volatile bit rate (#6) are volatile; the volatile bit rate is reloaded from the non-volatile one on every payload activation (§15.8). Defaults are manufacturer choices (the spec leaves them open): SOL enabled, ADMINISTRATOR privilege, 115.2 kbps.
func NewSOLConfig ¶ added in v0.9.1
func NewSOLConfig() *SOLConfig
NewSOLConfig returns a SOLConfig with manufacturer defaults.
func (*SOLConfig) GetParam ¶ added in v0.9.1
GetParam returns the parameter data bytes for selector (Table 26-5), or false when the selector is not a supported parameter.
func (*SOLConfig) ResetVolatile ¶ added in v0.9.1
func (c *SOLConfig) ResetVolatile()
ResetVolatile clears the volatile SOL configuration — only #0 set in progress and #6 volatile bit rate are volatile (Table 26-5) — as after a BMC cold reset / power cycle, which aborts any parameter set in progress (Table 26-3 "set complete" rule).
type SOLInstance ¶ added in v0.9.1
type SOLInstance struct {
SessionID uint32 // BMC session ID owning the activation
// contains filtered or unexported fields
}
SOLInstance is one activated SOL payload: the binding between an RMCP+ session and the system console, plus the payload-level sequence state of Table 15-2. All methods are safe for concurrent use.
func (*SOLInstance) OutboundEncrypted ¶ added in v0.9.1
func (inst *SOLInstance) OutboundEncrypted() bool
OutboundEncrypted reports whether BMC→console SOL data is currently encrypted: the activation-negotiated setting unless the console toggled it via Suspend/Resume Payload Encryption (Table 24-5). The command only governs data from the BMC ("encryption on all transfers of specified payload data from the BMC"); inbound packets keep their own packet flags.
func (*SOLInstance) ProcessPacket ¶ added in v0.9.1
func (inst *SOLInstance) ProcessPacket(ctx context.Context, in *types.SOLPayloadPacket) *types.SOLPayloadPacket
ProcessPacket handles one inbound SOL payload packet (spec v2.0 §15.9/§15.11, Table 15-3) and produces the response packet.
func (*SOLInstance) SetTracef ¶ added in v0.9.1
func (inst *SOLInstance) SetTracef(f func(format string, args ...any))
SetTracef installs the diagnostic sink for console lifecycle events. The server wires it to its solDebug-gated SOL trace; a nil sink (the default) keeps the library silent. Callable from any goroutine; events are emitted from the pump.
The sink is printf-shaped, so printf-style loggers plug in directly — logrus.Printf and zap's SugaredLogger.Infof match this signature as-is.
type SOLSendFunc ¶ added in v0.9.1
type SOLSendFunc func(pkt *types.SOLPayloadPacket) error
SOLSendFunc transmits one BMC→console SOL payload packet. The server supplies it; it owns session-level encryption, sequencing, and transport.
type SOLSenderFactory ¶ added in v0.9.1
type SOLSenderFactory func(sess *Session, inst *SOLInstance) SOLSendFunc
SOLSenderFactory builds the send function for an activation. sess.Addr must already hold the console's transport address.
type SOLStore ¶ added in v0.9.1
type SOLStore struct {
// contains filtered or unexported fields
}
SOLStore owns the SOL configuration and active instances. Packet sequencing lives in SOLInstance; asynchronous output is pushed by the instance pump (spec v2.0 §15.3: the BMC sends SOL data unrequested).
func NewSOLStore ¶ added in v0.9.1
NewSOLStore creates a SOLStore. h may be nil or return a nil ConsoleHAL, in which case SOL stays inactive and unadvertised. Console reconnection is disabled by default; enable it with SOLStore.SetReconnectPolicy.
func (*SOLStore) Activate ¶ added in v0.9.1
func (s *SOLStore) Activate(ctx context.Context, sess *Session, wantEnc, wantAuth bool) (*SOLInstance, error)
Activate attaches the system console to sess (spec v2.0 §24.1). wantEnc / wantAuth are the remote console's Encryption/Authentication Activation bits from the Activate Payload auxiliary request data. The returned error maps to a Table 24-2 completion code in the handler.
func (*SOLStore) ActivationStatus ¶ added in v0.9.1
ActivationStatus reports the Table 24-6 instance bitmask: bit (n-1) set when instance n is active.
func (*SOLStore) ActiveSessionID ¶ added in v0.9.1
ActiveSessionID returns the owning session ID for instance (1-based), or 0 when not activated (Table 24-7).
func (*SOLStore) CloseAll ¶ added in v0.9.1
func (s *SOLStore) CloseAll()
CloseAll deactivates every instance; called when the server shuts down.
func (*SOLStore) Deactivate ¶ added in v0.9.1
Deactivate detaches the console (spec v2.0 §24.2). The owning session may always deactivate; another session may force-deactivate when its privilege meets the configured SOL level (Table 26-5 #2) — this is the recovery path for payloads orphaned by a crashed console.
func (*SOLStore) DeactivateBySession ¶ added in v0.9.1
DeactivateBySession drops the instance owned by bmcID, if any. Wired to SessionStore removals: session termination automatically deactivates its payloads (spec v2.0 §24.2 note).
func (*SOLStore) InstanceBySession ¶ added in v0.9.1
func (s *SOLStore) InstanceBySession(bmcID uint32) *SOLInstance
InstanceBySession returns the instance owned by bmcID, or nil. The server reads the negotiated protection flags from it before processing packets.
func (*SOLStore) ProcessPacket ¶ added in v0.9.1
func (s *SOLStore) ProcessPacket(ctx context.Context, sessionID uint32, in *types.SOLPayloadPacket) *types.SOLPayloadPacket
ProcessPacket handles one inbound SOL payload packet from the owning session and produces the response packet (spec v2.0 §15.9/§15.11, Table 15-3). It returns nil when the session owns no active instance.
func (*SOLStore) SetReconnectPolicy ¶ added in v0.9.1
func (s *SOLStore) SetReconnectPolicy(p *ReconnectPolicy)
SetReconnectPolicy enables and configures console reconnection: after a console failure the pump retries the HAL Open on the policy's schedule (see ReconnectPolicy). A nil policy (the default) disables reconnection: the payload reports status bit [5] and recovers only via deactivate/reactivate. Takes effect on the next activation.
func (*SOLStore) SetSenderFactory ¶ added in v0.9.1
func (s *SOLStore) SetSenderFactory(f SOLSenderFactory)
SetSenderFactory installs the factory used to build per-activation senders. Called by the server once the transport exists.
func (*SOLStore) Supported ¶ added in v0.9.1
Supported reports whether the SOL payload type can be activated at all, i.e. a console exists and the type is enabled (Table 26-5 #1).
func (*SOLStore) SuspendResumeEncryption ¶ added in v0.9.1
SuspendResumeEncryption applies a Table 24-5 operation to the instance owned by sess. Only BMC→console encryption is affected; authentication is untouched and inbound packets keep their activation-negotiated protection.
type Session ¶
type Session struct {
// BMCID is the session ID assigned by the BMC (sent in Open Session Response).
BMCID uint32
// ConsoleID is the session ID chosen by the remote console.
ConsoleID uint32
// Handle is the one-byte session handle Get Session Info reports
// (spec v2.0§22.20). Assigned at allocation, unique among the store's live
// sessions, never 0x00 ("no session") or the reserved 0xFF.
Handle uint8
State SessionState
// Negotiated algorithms
AuthAlg types.AuthAlg
IntegrityAlg types.IntegrityAlg
CryptAlg types.CryptAlg
// Sequence tracking.
// InboundSeq is the last accepted sequence number from the console.
// OutboundSeq is the next sequence number the BMC will use.
InboundSeq uint32
OutboundSeq uint32
Addr net.Addr
// ProcMu serializes per-session packet processing. The server spawns a
// goroutine per inbound packet; without this lock, a burst of packets
// from one session is processed in scheduler order — scrambling SOL
// keystroke bytes and racing the inbound-seq check-then-set. The RAKP
// handlers take it too: duplicate handshake messages for one pending
// session otherwise race on the nonces, derived keys, and state below.
// ProcMu may be held while taking the store lock, never the reverse.
ProcMu sync.Mutex
// Session keys derived during RAKP.
SIK []byte
K1 []byte
K2 []byte
// RAKP exchange state (zeroed once session is active).
ConsoleRand [16]byte
BMCRand [16]byte
Role uint8 // whole byte from RAKP1, used in HMAC input
// User and privilege
User *User
PrivilegeLevel PrivilegeLevel
MaxPrivilege PrivilegeLevel
// Channel this session arrived on.
Channel uint8
// Timing. LastActivity is guarded by the store lock: it is refreshed via
// [SessionStore.Touch] when a validated packet is processed and read by
// eviction, both under that lock. CreatedAt is set before the session is
// published into the store and never written again.
CreatedAt time.Time
LastActivity time.Time
// contains filtered or unexported fields
}
Session holds all state for one active or pending IPMI session.
func (*Session) GetAddr ¶ added in v0.9.1
GetAddr returns the console's transport address, safe to call from any goroutine (the SOL pump targets asynchronous data at it).
func (*Session) NextOutboundSeq ¶ added in v0.9.1
NextOutboundSeq returns the session sequence number for the next outbound packet, advancing the counter shared by command responses and async SOL packets (§15.5).
type SessionState ¶
type SessionState uint8
SessionState tracks which phase of session negotiation has been reached.
const ( // SessionStatePending means Open Session was received but RAKP is incomplete. SessionStatePending SessionState = iota // SessionStateActive means RAKP completed and commands may flow. SessionStateActive // SessionStateClosed means the session was explicitly closed or timed out. SessionStateClosed )
type SessionStore ¶
type SessionStore struct {
// contains filtered or unexported fields
}
SessionStore is a thread-safe registry of active and pending sessions.
func NewSessionStore ¶
func NewSessionStore(clk clock.Clock) *SessionStore
NewSessionStore creates a SessionStore limited to MaxSessions concurrent sessions with the default inactivity timeout.
func NewSessionStoreWithOptions ¶
func NewSessionStoreWithOptions(clk clock.Clock, opts ...SessionStoreOption) *SessionStore
NewSessionStoreWithOptions creates a SessionStore with custom options.
func (*SessionStore) Activate ¶ added in v0.9.1
func (s *SessionStore) Activate(bmcID uint32) error
Activate marks the session active after RAKP completes, or returns ErrNoSession when the session was evicted in the meantime (capacity pressure evicts the oldest pending session, which can be one whose RAKP3 is in flight); activating the orphaned struct would hand the console a successful RAKP4 for a session that no longer exists. It takes the store lock because the pending-session eviction scan reads State under it, while the caller holds Session.ProcMu, so a reader under either lock observes a consistent value.
func (*SessionStore) Allocate ¶
func (s *SessionStore) Allocate(consoleID uint32, authAlg types.AuthAlg, integrityAlg types.IntegrityAlg, cryptAlg types.CryptAlg, maxPriv PrivilegeLevel, channel uint8) (*Session, error)
Allocate creates a new pending session and returns it. If capacity is reached, it evicts the oldest pending session (LRU per spec). Returns ErrSessionFull only when all slots are occupied by active sessions.
maxPriv and channel are stored before the session is inserted into the map so the struct is fully initialized before it becomes reachable to other goroutines; callers must not write session fields after Allocate returns without holding Session.ProcMu.
func (*SessionStore) Cap ¶ added in v0.9.1
func (s *SessionStore) Cap() int
Cap returns the maximum number of concurrent sessions the store can hold, i.e. the number of slots in the session table.
func (*SessionStore) Close ¶
func (s *SessionStore) Close(bmcID uint32) error
Close marks a session as closed and removes it from the store.
func (*SessionStore) Count ¶
func (s *SessionStore) Count() int
Count returns the number of sessions currently in the store.
func (*SessionStore) EvictExpired ¶
func (s *SessionStore) EvictExpired() int
EvictExpired removes all sessions that have been inactive beyond the timeout. Called periodically by the server.
func (*SessionStore) Get ¶
func (s *SessionStore) Get(bmcID uint32) (*Session, error)
Get returns the session for bmcID, or ErrNoSession. It is a pure lookup: activity is refreshed separately via SessionStore.Touch, only once a packet has passed integrity and sequence validation. Refreshing on lookup would let packets that fail validation, or that merely name a session ID, keep the session alive forever.
func (*SessionStore) SetOnRemove ¶ added in v0.9.1
func (s *SessionStore) SetOnRemove(fn func(bmcID uint32))
SetOnRemove registers the hook fired when a session leaves the store.
func (*SessionStore) Touch ¶ added in v0.9.1
func (s *SessionStore) Touch(bmcID uint32)
Touch refreshes the session's inactivity clock. The server calls it for every packet that passed integrity and sequence validation. Handshake packets never touch: RAKP messages carry no authenticator, so the inactivity budget stamped at allocation bounds the whole handshake instead.
type SessionStoreOption ¶
type SessionStoreOption func(*SessionStore)
Option configures a SessionStore.
func WithInactivityTimeout ¶
func WithInactivityTimeout(d time.Duration) SessionStoreOption
WithInactivityTimeout overrides the default 60-second inactivity timeout.
func WithMaxSessions ¶
func WithMaxSessions(n int) SessionStoreOption
WithMaxSessions overrides the default session limit.
type User ¶
type User struct {
// ID is the IPMI user slot (1-63). Slot 1 is the anonymous/null user.
ID uint8
Name string
// Password is stored as a 20-byte padded value per the IPMI 2.0 spec.
// Index 0 is valid; a zero-length slice means no password is set.
Password [MaxPasswordLen]byte
// Password20 records whether the password was stored with the 20-byte size
// tag (spec v2.0§22.30). The size is part of the credential: a test with the
// other size must fail, and a 20-byte password exists only in IPMI 2.0, so
// it must not authenticate a v1.5 session.
Password20 bool
Enabled bool
// ChannelAccess holds per-channel access settings keyed by channel number.
ChannelAccess map[uint8]UserChannelAccess
// PayloadAccess holds per-channel payload activation rights keyed by
// channel number (spec v2.0 §24.6/§24.7). Like every other mutable User
// field it follows the store's snapshot discipline: lookups hand out
// deep copies, and a runtime change goes through [UserStore.Update].
PayloadAccess map[uint8]UserPayloadAccess
}
User represents a single BMC user account.
func (*User) PasswordV15Padded ¶
PasswordV15Padded returns the user's password zero-padded to 16 bytes per IPMI v1.5 AuthCode algorithms (spec v1.5§18.15.1 / v2.0§22.17.1).
func (*User) PayloadAccessFor ¶ added in v0.9.1
func (u *User) PayloadAccessFor(channel uint8) UserPayloadAccess
PayloadAccessFor returns the user's payload access entry for channel, or the default rights (SOL enabled) when none was ever set.
func (*User) SetPassword ¶
SetPassword copies up to MaxPasswordLen bytes from raw into the User's password field. The size class is inferred from the input length: anything longer than 16 bytes is a 20-byte (IPMI 2.0 only) password. Pass the wire-tagged length unmodified so the class survives trailing zero bytes.
func (*User) SetPayloadAccess ¶ added in v0.9.1
SetPayloadAccess applies an enable/disable update to the user's payload access entry for channel (spec v2.0 Table 24-8: on enable, 1-bits set and 0-bits leave unchanged; on disable, 1-bits clear). Like any other User mutation, call it at construction time or on the live user inside a UserStore.Update callback, never on a store-returned snapshot.
func (*User) VerifyPassword ¶
VerifyPassword returns true when the supplied raw bytes match the stored password. Uses constant-time comparison to avoid timing attacks.
type UserChannelAccess ¶
type UserChannelAccess struct {
// MaxPrivilege is the highest privilege the user may request on this channel.
MaxPrivilege PrivilegeLevel
// CallbackOnly restricts the user to callback sessions only.
CallbackOnly bool
// Enabled controls whether the user is allowed on this channel at all.
Enabled bool
// LinkAuth records the link-authentication enable bit (spec v2.0§22.26).
// Nothing enforces it on a LAN channel; it is stored so Get User Access
// round-trips what Set User Access accepted.
LinkAuth bool
}
UserChannelAccess records per-channel privilege settings for a user.
type UserPayloadAccess ¶ added in v0.9.1
type UserPayloadAccess struct {
// Standard1 mirrors "Standard Payload enables 1": bit [1] = SOL.
Standard1 uint8
// OEM1 mirrors "OEM Payload Enables 1".
OEM1 uint8
}
UserPayloadAccess records a user's payload activation rights on one channel, mirroring the bitfields of spec v2.0 Table 24-8/24-9.
func (UserPayloadAccess) SOLEnabled ¶ added in v0.9.1
func (a UserPayloadAccess) SOLEnabled() bool
SOLEnabled reports whether the user may activate the SOL payload.
type UserStore ¶
type UserStore struct {
// contains filtered or unexported fields
}
UserStore is a thread-safe registry of BMC users.
func NewUserStore ¶
func NewUserStore(opts ...UserStoreOption) *UserStore
NewUserStore creates a UserStore with the mandatory anonymous user (ID 1).
func (*UserStore) Add ¶
Add creates a new user at the given ID and returns the live *User for construction-time seeding. Mutating the returned pointer is only safe before the server starts serving; use UserStore.Update for runtime changes. Returns ErrInvalidUserID for IDs outside the store's advertised range, or ErrUsernameTaken if name is non-empty and already in use. Bounding by the advertised maximum keeps the whole store consistent: no slot can exist that enumerators cannot see but authentication still finds.
func (*UserStore) CountEnabled ¶ added in v0.9.1
CountEnabled returns the number of enabled users, in one pass under one read lock. Get User Access reports this on every query, and counting through per-slot snapshot lookups would deep-copy the whole table each time.
func (*UserStore) FindEnabledByNameOnChannel ¶
FindEnabledByNameOnChannel scans user IDs in order up to the store maximum and returns a snapshot copy of the first enabled user with a matching name and channel access (spec v1.5§18.24 / v2.0§22.27).
func (*UserStore) Get ¶
Get returns a snapshot copy of the user at the given ID, or ErrUserNotFound. The returned *User is a private copy; mutate the store via UserStore.Update.
func (*UserStore) GetByName ¶
GetByName returns a snapshot copy of the user with the given name, or ErrUserNotFound. An empty name matches the anonymous user (ID 1).
Slots are scanned in ID order, so the lookup is deterministic even when several slots share a name: user-management commands can create additional empty-named slots at runtime, and iterating the map directly would make the RAKP null-user lookup resolve to a random one of them.
func (*UserStore) MaxUserCount ¶ added in v0.9.1
MaxUserCount returns the highest user ID the store advertises (default MaxUsers). Get User Access reports this so in-band enumerators know how many slots to walk.
func (*UserStore) Update ¶ added in v0.9.1
Update runs fn against the live *User for id under the store write lock, the race-free way to mutate a user at runtime (e.g. from a Set User Password handler). Returns ErrUserNotFound if id is not present.
fn runs with the store lock held: it must not call back into the store (that self-deadlocks on the non-reentrant lock) and must not retain the *User past its return, since using the live pointer outside the lock recreates the race the snapshot lookups exist to prevent.
func (*UserStore) Upsert ¶ added in v0.9.1
Upsert applies fn to the user in slot id under a single write-lock hold, creating the slot first (respecting the store max) when it does not exist. This is the atomic create-or-mutate path handlers use so two concurrent creates on the same empty slot cannot interleave and lose a field, which a separate Add-then-Update sequence would allow.
fn runs against a working copy, so a rejected mutation leaves stored state untouched: the slot is committed only when fn returns nil and the resulting non-empty name does not collide with a different slot. A colliding name is rejected with ErrUsernameTaken to keep name-based session lookup deterministic. Returns ErrInvalidUserID for an id outside 1..max.
type UserStoreOption ¶ added in v0.9.1
type UserStoreOption func(*UserStore)
UserStoreOption configures a UserStore at construction time.
func WithMaxUsers ¶ added in v0.9.1
func WithMaxUsers(n uint8) UserStoreOption
WithMaxUsers sets the highest user ID the store advertises via Get User Access. n is clamped to the spec range 1..MaxUsers; the default is MaxUsers (63).
type V15AuthType ¶
type V15AuthType uint8
V15AuthType mirrors IPMI v1.5 authentication type codes.
const ( V15AuthTypeNone V15AuthType = 0x00 V15AuthTypeMD2 V15AuthType = 0x01 V15AuthTypeMD5 V15AuthType = 0x02 V15AuthTypePassword V15AuthType = 0x04 V15AuthTypeOEM V15AuthType = 0x05 )
func ParseV15AuthType ¶
func ParseV15AuthType(name string) (V15AuthType, error)
ParseV15AuthType parses a single auth type name (case-insensitive).
func ParseV15AuthTypes ¶
func ParseV15AuthTypes(raw string) ([]V15AuthType, error)
ParseV15AuthTypes parses a comma-separated list of v1.5 auth type names.
type V15Session ¶
type V15Session struct {
// ProcMu serializes per-session packet processing. The server spawns a
// goroutine per inbound packet; without this lock, concurrent packets of
// one session race on the sequence window check-then-set and the counters.
ProcMu sync.Mutex
TempSessionID uint32
SessionID uint32
// Handle is the one-byte session handle Get Session Info reports
// (spec v2.0§22.20). Assigned at creation, unique among the store's live
// sessions, never 0x00 ("no session") or the reserved 0xFF.
Handle uint8
State V15SessionState
AuthType V15AuthType
Challenge [16]byte
InboundSeq uint32
InboundRcvd uint8 // bitmap: bit i => (InboundSeq - i) received
OutboundSeq uint32
User *User
PrivilegeLevel PrivilegeLevel
MaxPrivilege PrivilegeLevel
Channel uint8
CreatedAt time.Time
LastActivity time.Time
}
V15Session holds IPMI v1.5 session state.
Concurrency: it follows the same pattern as the v2.0 Session. ProcMu serializes per-session packet processing and guards the per-packet fields written during dispatch: the sequence counters, InboundRcvd, and PrivilegeLevel. SessionID, State, and MaxPrivilege are written after publication only by V15SessionStore.Activate, which runs under the store lock while its caller holds ProcMu, so a reader under either lock observes a consistent value (the Count* helpers read them under the store lock). LastActivity is guarded by the store lock and refreshed via V15SessionStore.Touch. TempSessionID, Handle, AuthType, Challenge, Channel, User, and CreatedAt are set before the session is published and never written again. ProcMu may be held while taking the store lock, never the reverse.
func (*V15Session) NextOutboundSeq ¶
func (sess *V15Session) NextOutboundSeq() uint32
NextOutboundSeq returns the sequence number for the current outbound message and advances the counter for the next one. Sequence 0 is reserved for pre-session packets and is skipped on wrap (v1.5§6.11.9 / v2.0§6.12.9).
func (*V15Session) TryAcceptInboundSeq ¶
func (sess *V15Session) TryAcceptInboundSeq(seq uint32) bool
TryAcceptInboundSeq implements spec v1.5§6.11.11 Option 1 / v2.0§6.12.11 Option 1 (+/-8 window, no dupes).
type V15SessionState ¶
type V15SessionState uint8
V15SessionState tracks IPMI v1.5 session negotiation progress.
const ( V15SessionStatePending V15SessionState = iota V15SessionStateActive V15SessionStateClosed )
type V15SessionStore ¶
type V15SessionStore struct {
// contains filtered or unexported fields
}
V15SessionStore is a thread-safe registry of IPMI v1.5 sessions.
func NewV15SessionStore ¶
func NewV15SessionStore(clk clock.Clock) *V15SessionStore
NewV15SessionStore creates a V15SessionStore with the default limits.
func (*V15SessionStore) Activate ¶
func (s *V15SessionStore) Activate(pending *V15Session, permanentID, inboundSeq, outboundSeq uint32, maxPrivilege PrivilegeLevel) error
Activate transitions a pending session to active with a new permanent ID. maxPrivilege is the requested ceiling; initial privilege is USER per v1.5§6.8 / v2.0§6.8 (Callback when max is Callback).
inboundSeq is the Activate Session response "Session inbound sequence number" (spec v1.5§18.15 / v2.0§6.12.9): the starting sequence the remote console must use on its first authenticated packet. InboundSeq on the session tracks the highest sequence already accepted, so it is seeded to inboundSeq-1 (wrapping) with an empty receive bitmap — otherwise the first packet (seq == inboundSeq) is rejected as a duplicate and clients such as ipmitool stall for a full LAN timeout before retrying with inboundSeq+1.
Precondition: the caller must hold pending's ProcMu. Activate mutates fields of an already-published session (SessionID, State, MaxPrivilege, PrivilegeLevel, the seq counters, and LastActivity) under the store lock; per-packet readers hold ProcMu and the store's Count* and eviction scans hold the store lock, so with the writer holding both, a reader under either lock observes a consistent session.
A session evicted between lookup and activation is reported as not pending rather than silently re-inserted.
func (*V15SessionStore) Cap ¶ added in v0.9.1
func (s *V15SessionStore) Cap() int
Cap returns the maximum number of concurrent v1.5 sessions the store can hold, i.e. the number of slots in the session table.
func (*V15SessionStore) Close ¶
func (s *V15SessionStore) Close(id uint32) error
Close removes a session by permanent or temp ID.
func (*V15SessionStore) Count ¶ added in v0.9.1
func (s *V15SessionStore) Count() int
Count returns the number of sessions currently in the store, pending or active, mirroring SessionStore.Count.
func (*V15SessionStore) CountActiveSessions ¶
func (s *V15SessionStore) CountActiveSessions() int
CountActiveSessions returns the number of active v1.5 sessions.
func (*V15SessionStore) CountActiveSessionsForUser ¶
func (s *V15SessionStore) CountActiveSessionsForUser(userID uint8) int
CountActiveSessionsForUser returns active sessions owned by userID.
func (*V15SessionStore) CountActiveSessionsWithMaxPrivilegeAtLeast ¶
func (s *V15SessionStore) CountActiveSessionsWithMaxPrivilegeAtLeast(min PrivilegeLevel) int
CountActiveSessionsWithMaxPrivilegeAtLeast counts active sessions whose negotiated maximum privilege is >= min (for Table 18-17 completion 0x83).
func (*V15SessionStore) CreatePending ¶
func (s *V15SessionStore) CreatePending(authType V15AuthType, user *User, challenge [16]byte, channel uint8) (*V15Session, error)
CreatePending allocates a pending v1.5 session after Get Session Challenge. The session is fully initialized before it is inserted into the map, so no unguarded field write happens after it becomes reachable to other goroutines.
func (*V15SessionStore) EvictExpired ¶
func (s *V15SessionStore) EvictExpired() int
EvictExpired removes inactive v1.5 sessions past the timeout. Eviction reads LastActivity and deletes under the store lock only; it never takes a session's ProcMu, so a handler holding one can trigger eviction safely.
func (*V15SessionStore) Get ¶
func (s *V15SessionStore) Get(id uint32) (*V15Session, error)
Get returns a session by its current lookup ID. It is a pure lookup: activity is refreshed separately via V15SessionStore.Touch, only once a packet has passed authentication and sequence validation. Refreshing on lookup would let packets that fail validation, or that merely name a session ID, keep the session alive forever.
func (*V15SessionStore) Touch ¶
func (s *V15SessionStore) Touch(id uint32)
Touch refreshes the session's inactivity clock. The server calls it for every packet that passed authentication and sequence validation.