1 Star 0 Fork 0

叶海丰/ipmi-go

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
interface_lan.go 8.50 KB
一键复制 编辑 原始数据 按行查看 历史
叶海丰 提交于 1年前 . init
package ipmi
import (
"bytes"
"context"
"fmt"
"time"
)
const (
IPMIVersion15 = 0x15
IPMIVersion20 = 0x20
)
// session holds data exchanged during Session Activation stage when using lan/lanplus interface.
// see: 13.14 IPMI v1.5 LAN Session Activation, 13.15 IPMI v2.0/RMCP+ Session Activation
type session struct {
// filled after GetChannelAuthenticationCapabilities
authType AuthType
ipmiSeq uint8
v20 v20
v15 v15
}
type v15 struct {
// indicate whether or not the session is in Pre-Session stage,
// that is between "GetSessionChallenge" and "ActivateSession"
preSession bool
// indicate whether or not the IPMI 1.5 session is activated.
active bool
maxPrivilegeLevel PrivilegeLevel
sessionID uint32
// Sequence number that BMC wants remote console to use for subsequent messages in the session.
// Remote console use "inSeq" and increment it when sending Request to BMC.
// "inSeq" is first updated by returned ActivateSession response.
inSeq uint32
// "outSeq" is set by Remote Console to indicate the sequence number should picked by BMC.
// 6.12.12 IPMI v1.5 Outbound Session Sequence Number Tracking and Handling.
outSeq uint32
challenge [16]byte
}
type v20 struct {
// specific to IPMI v2 / RMCP+ sessions
state SessionState
sequence uint32 // session sequence number
// the cipher suite used during OpenSessionRequest
cipherSuiteID CipherSuiteID
// filled by RmcpOpenSessionRequest
requestedAuthAlg AuthAlg
requestedIntegrityAlg IntegrityAlg
requestedEncryptAlg CryptAlg
// filled by RmcpOpenSessionResponse
// RMCP Open Session is used for exchanging session ids
authAlg AuthAlg
integrityAlg IntegrityAlg
cryptAlg CryptAlg
maxPrivilegeLevel PrivilegeLevel // uint8 requestedRole sent in RAKP 1 message
role uint8 // whole byte of privilege level in RAKP1, will be used for computing authcode of rakp2, rakp3
consoleSessionID uint32
bmcSessionID uint32
// values required for RAKP messages
// filed in rakp1
consoleRand [16]byte // Random number generated by the console
// filled after rakp2
bmcRand [16]byte // Random number generated by the BMC
bmcGUID [16]byte // bmc GUID
sik []byte // SIK, session integrity key
k1 []byte // K1 key
k2 []byte // K2 key
rakp2ReturnCode uint8 // will be used in rakp3 message
// see 13.33
// Kuid vs Kg
// - ipmi user password (the pre-shared key), known as Kuid, which are set using the Set User Password command.
// - BMC key, known as Kg, Kg is set using the Set Channel Security Keys command.
bmcKey []byte
accumulatedPayloadSize uint32
// for xRC4 encryption
rc4EncryptIV [16]byte
rc4DecryptIV [16]byte
}
// buildRawPayload returns the PayloadType and the raw payload bytes for Command Request.
// Most command requests are of IPMI PayloadType, but some requests like RAKP messages are not.
func (c *Client) buildRawPayload(reqCmd Request) (PayloadType, []byte, error) {
var payloadType PayloadType
if _, ok := reqCmd.(*OpenSessionRequest); ok {
payloadType = PayloadTypeRmcpOpenSessionRequest
} else if _, ok := reqCmd.(*RAKPMessage1); ok {
payloadType = PayloadTypeRAKPMessage1
} else if _, ok := reqCmd.(*RAKPMessage3); ok {
payloadType = PayloadTypeRAKPMessage3
} else {
payloadType = PayloadTypeIPMI
}
var rawPayload []byte
switch payloadType {
case
PayloadTypeRmcpOpenSessionRequest,
PayloadTypeRAKPMessage1,
PayloadTypeRAKPMessage3:
// Session Setup Payload Types
rawPayload = reqCmd.Pack()
case PayloadTypeIPMI:
// Standard Payload Types
ipmiReq, err := c.BuildIPMIRequest(reqCmd)
if err != nil {
return 0, nil, fmt.Errorf("BuildIPMIRequest failed, err: %s", err)
}
c.Debug(">>>> IPMI Request", ipmiReq)
rawPayload = ipmiReq.Pack()
}
return payloadType, rawPayload, nil
}
func (c *Client) exchangeLAN(request Request, response Response) error {
c.Debug(">> Command Request", request)
rmcp, err := c.BuildRmcpRequest(request)
if err != nil {
return fmt.Errorf("build RMCP+ request msg failed, err: %s", err)
}
c.Debug(">>>>>> RMCP Request", rmcp)
sent := rmcp.Pack()
c.DebugBytes("sent", sent, 16)
ctx := context.Background()
recv, err := c.udpClient.Exchange(ctx, bytes.NewReader(sent))
if err != nil {
return fmt.Errorf("client udp exchange msg failed, err: %s", err)
}
c.DebugBytes("recv", recv, 16)
if err := c.ParseRmcpResponse(recv, response); err != nil {
// Warn, must directly return err. (DO NOT wrap err to another error)
// The error returned by ParseRmcpResponse might be of *ResponseError type.
return err
}
c.Debug("<< Command Response", response)
return nil
}
// 13.14
// IPMI v1.5 LAN Session Activation
// 1. RmcpPresencePing - RmcpPresencePong
// 2. Get Channel Authentication Capabilities
// 3. Get Session Challenge
// 4. Activate Session
func (c *Client) Connect15() error {
var (
err error
channelNumber uint8 = 0x0e // Eh = retrieve information for channel this request was issued on
privilegeLevel PrivilegeLevel = PrivilegeLevelAdministrator
)
_, err = c.GetChannelAuthenticationCapabilities(channelNumber, privilegeLevel)
if err != nil {
return fmt.Errorf("GetChannelAuthenticationCapabilities failed, err: %s", err)
}
_, err = c.GetSessionChallenge()
if err != nil {
return fmt.Errorf("GetSessionChallenge failed, err: %s", err)
}
c.session.v15.preSession = true
_, err = c.ActivateSession()
if err != nil {
return fmt.Errorf("ActivateSession failed, err: %s", err)
}
_, err = c.SetSessionPrivilegeLevel(c.session.v15.maxPrivilegeLevel)
if err != nil {
return fmt.Errorf("SetSessionPrivilegeLevel failed, err: %s", err)
}
go func() {
c.keepSessionAlive(30)
}()
return nil
}
// see 13.15 IPMI v2.0/RMCP+ Session Activation
func (c *Client) Connect20() error {
var (
err error
// 0h-Bh,Fh = specific channel number
// Eh = retrieve information for channel this request was issued on
channelNumber uint8 = 0x0e
privilegeLevel PrivilegeLevel = PrivilegeLevelAdministrator
)
_, err = c.GetChannelAuthenticationCapabilities(channelNumber, privilegeLevel)
if err != nil {
return fmt.Errorf("cmd: Get Channel Authentication Capabilities failed, err: %s", err)
}
// Todo, retry for opensession/rakp1/rakp3
_, err = c.OpenSession()
if err != nil {
return fmt.Errorf("cmd: RMCP+ Open Session failed, err: %s", err)
}
_, err = c.RAKPMessage1()
if err != nil {
return fmt.Errorf("cmd: rakp1 failed, err: %s", err)
}
_, err = c.RAKPMessage3()
if err != nil {
return fmt.Errorf("cmd: rakp3 failed, err: %s", err)
}
_, err = c.SetSessionPrivilegeLevel(c.session.v20.maxPrivilegeLevel)
if err != nil {
return fmt.Errorf("SetSessionPrivilegeLevel failed, err: %s", err)
}
go func() {
c.keepSessionAlive(30)
}()
return nil
}
// ConnectAuto detects the IPMI version supported by BMC by using
// GetChannelAuthenticationCapabilities command, then decide to use v1.5 or v2.0
// for subsequent requests.
func (c *Client) ConnectAuto() error {
var (
err error
// 0h-Bh,Fh = specific channel number
// Eh = retrieve information for channel this request was issued on
channelNumber uint8 = 0x0e
privilegeLevel PrivilegeLevel = PrivilegeLevelAdministrator
)
// force use IPMI v1.5 first
c.v20 = false
cap, err := c.GetChannelAuthenticationCapabilities(channelNumber, privilegeLevel)
if err != nil {
return fmt.Errorf("cmd: Get Channel Authentication Capabilities failed, err: %s", err)
}
if cap.SupportIPMIv20 {
c.v20 = true
return c.Connect20()
}
if cap.SupportIPMIv15 {
return c.Connect15()
}
return fmt.Errorf("client does not support IPMI v1.5 and IPMI v.20")
}
// closeLAN closes session used in LAN communication.
func (c *Client) closeLAN() error {
var sessionID uint32
if c.v20 {
sessionID = c.session.v20.bmcSessionID
} else {
sessionID = c.session.v15.sessionID
}
request := &CloseSessionRequest{
SessionID: sessionID,
}
if _, err := c.CloseSession(request); err != nil {
return fmt.Errorf("CloseSession failed, err: %s", err)
}
if err := c.udpClient.Close(); err != nil {
return fmt.Errorf("close udp connection failed, err: %s", err)
}
return nil
}
// 6.12.15 Session Inactivity Timeouts
func (c *Client) keepSessionAlive(intervalSec int) error {
var period = time.Duration(intervalSec) * time.Second
ticker := time.NewTicker(period)
defer ticker.Stop()
for range ticker.C {
if _, err := c.GetCurrentSessionInfo(); err != nil {
return fmt.Errorf("keepSessionAlive failed, GetCurrentSessionInfo failed, err: %s", err)
}
}
return nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/rogax/ipmi-go.git
git@gitee.com:rogax/ipmi-go.git
rogax
ipmi-go
ipmi-go
86ae46cfb58e

搜索帮助