pax_global_header00006660000000000000000000000064147411052710014514gustar00rootroot0000000000000052 comment=bd08d4c38fa1e8407fb8b3834523b1987f3d2c09 golang-github-bougou-go-ipmi-0.7.2/000077500000000000000000000000001474110527100171065ustar00rootroot00000000000000golang-github-bougou-go-ipmi-0.7.2/.github/000077500000000000000000000000001474110527100204465ustar00rootroot00000000000000golang-github-bougou-go-ipmi-0.7.2/.github/workflows/000077500000000000000000000000001474110527100225035ustar00rootroot00000000000000golang-github-bougou-go-ipmi-0.7.2/.github/workflows/build.yml000066400000000000000000000005601474110527100243260ustar00rootroot00000000000000--- name: Build and Test on: push: branches: - "main" jobs: build: name: Build runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Go uses: actions/setup-go@v2 with: go-version: "1.20" - name: Build & test run: | make dependencies make build-all golang-github-bougou-go-ipmi-0.7.2/.github/workflows/release.yml000066400000000000000000000010631474110527100246460ustar00rootroot00000000000000--- name: Release on: push: tags: - "v*" jobs: release: name: Build and Release runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Go uses: actions/setup-go@v2 with: go-version: "1.20" - name: Build & test run: | make dependencies make build-all - uses: marvinpinto/action-automatic-releases@latest with: repo_token: "${{ secrets.GITHUB_TOKEN }}" prerelease: false files: | _output/* golang-github-bougou-go-ipmi-0.7.2/.gitignore000066400000000000000000000006671474110527100211070ustar00rootroot00000000000000# Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ cover.out e2e-reports/ # Translations *.mo *.pot # emacs .\#* # vim *.swp # ignore bin /bin/ _output # ignore vscode .vscode # goland .idea # Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out .DS_Store goipmitest # asdf .tool-versions golang-github-bougou-go-ipmi-0.7.2/CONTRIBUTING.md000066400000000000000000000050521474110527100213410ustar00rootroot00000000000000# Contributing Each command defined in the IPMI specification is a pair of request/response messages. These IPMI commands are implemented as methods of the `ipmi.Client` struct in this library. `ipmitool` as example, some `ipmitool` cmdline are realized by calling just one underlying IPMI command, but many others are not. Like `ipmitool sdr list`, it's a loop of `GetSDR` IPMI command. So this library also implements some methods that are not IPMI commands defined in IPMI specification, but just some common helpers, like `GetSDRs` to get all SDRs. ## IPMI Command Guideline For a IPMI Command `DoSomething`: - Must define `DoSomethingRequest` which conforms to the `ipmi.Request` interface, it holds the request message data. - Must define `DoSomethingResponse` which conforms to the `ipmi.Response` interface, it holds the response message data. - Must define `DoSomething` method on `ipmi.Client` For `DoSomething` method, you can pass `DoSomethingRequest` directly as the input parameter, like: ```go func (c *Client) DoSomething(ctx context.Context, request *DoSomethingRequest) (response *DoSomethingResponse, err error) { response = &DoSomethingResponse{} err := c.Exchange(ctx,request, response) return } ``` or, you can pass some plain parameters, and construct the `DoSomethingRequest` in method body, like: ```go func (c *Client) DoSomething(ctx context.Context, param1 string, param2 string) (response *DoSomethingResponse, err error) { request := &DoSomethingRequest{ // construct by using input params } response = &DoSomethingResponse{} err := c.Exchange(ctx,request, response) return } ``` Calling `Exchange` method of `ipmi.Client` will fullfil all other complex underlying works. ## ipmi.Request interface ```go type Request interface { // Pack encodes the object to data bytes Pack() []byte // Command return the IPMI command info (NetFn/Cmd). // All IPMI specification specified commands are already predefined in this file. Command() Command } ``` ## ipmi.Response interface ```go type Response interface { // Unpack decodes the object from data bytes Unpack(data []byte) error // CompletionCodes returns a map of command-specific completion codes CompletionCodes() map[uint8]string // Format return a formatted human friendly string Format() string } ``` ## IPMI Command Request ## IPMI Command Response - Define necessary fields per IPMI specification, but DO NOT define the completion code field in Response struct. - If there is no command-specific completion codes, just return an empty map for `CompletionCodes()` method. golang-github-bougou-go-ipmi-0.7.2/LICENSE000066400000000000000000000261351474110527100201220ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. golang-github-bougou-go-ipmi-0.7.2/Makefile000066400000000000000000000037631474110527100205570ustar00rootroot00000000000000APP_VERSION ?= $(shell git describe --abbrev=5 --dirty --tags --always) GIT_COMMIT := $(shell git rev-parse --short=8 HEAD) BUILD_TIME := $(shell date -u +'%Y-%m-%dT%H:%M:%SZ') BINDIR := $(PWD)/bin OUTPUT_DIR := $(PWD)/_output GOOS ?= $(shell uname -s | tr '[:upper:]' '[:lower:]') GOARCH ?= amd64 LDFLAGS := $(LDFLAGS) -X github.com/bougou/go-ipmi/cmd/goipmi/commands.Version=$(APP_VERSION) LDFLAGS := $(LDFLAGS) -X github.com/bougou/go-ipmi/cmd/goipmi/commands.Commit=$(GIT_COMMIT) LDFLAGS := $(LDFLAGS) -X github.com/bougou/go-ipmi/cmd/goipmi/commands.BuildAt=$(BUILD_TIME) PATH := $(BINDIR):$(PATH) SHELL := env PATH='$(PATH)' /bin/sh all: build # Run tests test: fmt vet @# Disable --race until https://github.com/kubernetes-sigs/controller-runtime/issues/1171 is fixed. ginkgo --randomizeAllSpecs --randomizeSuites --failOnPending --flakeAttempts=2 \ --cover --coverprofile cover.out --trace --progress $(TEST_ARGS)\ ./pkg/... ./cmd/... # Build goipmi binary build: fmt vet go build -ldflags "$(LDFLAGS)" -o $(OUTPUT_DIR)/goipmi ./cmd/goipmi # Cross compiler build-all: fmt vet CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -a -o $(OUTPUT_DIR)/goipmi-$(APP_VERSION)-linux-amd64 ./cmd/goipmi CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "$(LDFLAGS)" -a -o $(OUTPUT_DIR)/goipmi-$(APP_VERSION)-linux-arm64 ./cmd/goipmi CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "$(LDFLAGS)" -a -o $(OUTPUT_DIR)/goipmi-$(APP_VERSION)-darwin-amd64 ./cmd/goipmi CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "$(LDFLAGS)" -a -o $(OUTPUT_DIR)/goipmi-$(APP_VERSION)-darwin-arm64 ./cmd/goipmi # Run go fmt against code fmt: go fmt ./... # Run go vet against code vet: go vet ./... lint: $(BINDIR)/golangci-lint run --timeout 2m0s ./... dependencies: test -d $(BINDIR) || mkdir $(BINDIR) GOBIN=$(BINDIR) go install github.com/onsi/ginkgo/ginkgo@v1.16.4 curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $(BINDIR) latest golang-github-bougou-go-ipmi-0.7.2/README.md000066400000000000000000000637641474110527100204050ustar00rootroot00000000000000 # [go-ipmi](https://github.com/bougou/go-ipmi) [`go-ipmi`](https://github.com/bougou/go-ipmi) is a pure golang native IPMI library. It DOES NOT wraps `ipmitool`. ## Usage ```go import ( "fmt" "github.com/bougou/go-ipmi" ) func main() { host := "10.0.0.1" port := 623 username := "root" password := "123456" client, err := ipmi.NewClient(host, port, username, password) // Support local mode client if runs directly on linux // client, err := ipmi.NewOpenClient() if err != nil { panic(err) } // you can optionally open debug switch // client.WithDebug(true) // you can set interface type, enum range: open/lan/lanplus/tool, default open // client.WithInterface(ipmi.InterfaceLanplus) // !!! Note !!!, // From v0.6.0, all IPMI command methods of the Client accept a context as the first argument. ctx := context.Background() // Connect will create an authenticated session for you. if err := client.Connect(ctx); err != nil { panic(err) } // Now you can execute other IPMI commands that need authentication. res, err := client.GetDeviceID(ctx) if err != nil { panic(err) } fmt.Println(res.Format()) selEntries, err := client.GetSELEntries(ctx, 0) if err != nil { panic(err) } fmt.Println(ipmi.FormatSELs(selEntries, nil)) } ``` ## `goipmi` binary The `goipmi` is a binary tool which provides the same command usages like `ipmitool`. The `goipmi` calls `go-ipmi` library underlying. The purpose of creating `goipmi` tool was not intended to substitute `ipmitool`. It was just used to verify the correctness of `go-ipmi` library. ## Functions Comparison with ipmitool Each command defined in the IPMI specification is a pair of request/response messages. These IPMI commands are implemented as methods of the `ipmi.Client` struct in this library. Some `ipmitool` cmdline usages are implemented by calling just one IPMI command, but others are not. Like `ipmitool sdr list`, it's a loop of `GetSDR` IPMI command. So this library also implements some methods that are not IPMI commands defined in IPMI specification, but just some common helpers, like `GetSDRs` to get all SDRs. These methods are marked with an asterisk (*) after the method name in the following docs. The implementation logic of IPMI commands are almost same. See [Contributing](./CONTRIBUTING.md) > More commands are ongoing ... ### IPM Device Global Commands | Method | Status | corresponding ipmitool usage | | ---------------------------------- | ------------------ | ----------------------------- | | GetDeviceID | :white_check_mark: | mc info | | ColdReset | :white_check_mark: | mc reset cold | | WarmReset | :white_check_mark: | mc reset warm | | GetSelfTestResults | :white_check_mark: | mc selftest, chassis selftest | | ManufacturingTestOn | :white_check_mark: | | | SetACPIPowerState | :white_check_mark: | | | GetACPIPowerState | :white_check_mark: | | | GetDeviceGUID | :white_check_mark: | | | GetNetFnSupport | :white_check_mark: | | | GetCommandSupport | :white_check_mark: | | | GetCommandSubfunctionSupport | | | | GetConfigurableCommands | :white_check_mark: | | | GetConfigurableCommandSubfunctions | | | | SetCommandEnables | | | | GetCommandEnables | :white_check_mark: | | | GetCommandSubfunctionsEnables | :white_check_mark: | | | GetSubfunctionsEnables | | | | GetOEMNetFnIanaSupport | | | ### BMC Watchdog Timer Commands | Method | Status | corresponding ipmitool usage | | ------------------ | ------------------ | ---------------------------- | | ResetWatchdogTimer | :white_check_mark: | mc watchdog reset | | SetWatchdogTimer | :white_check_mark: | | | GetWatchdogTimer | :white_check_mark: | mc watchdog get | ### BMC Device and Messaging Commands | Method | Status | corresponding ipmitool usage | | ------------------------------ | ------------------ | ---------------------------- | | SetBMCGlobalEnables | :white_check_mark: | | | GetBMCGlobalEnables | :white_check_mark: | | | ClearMessageFlags | :white_check_mark: | | | GetMessageFlags | :white_check_mark: | | | EnableMessageChannelReceive | :white_check_mark: | | | GetMessage | :white_check_mark: | | | SendMessage | :white_check_mark: | | | ReadEventMessageBuffer | :white_check_mark: | | | GetBTInterfaceCapabilities | | | | GetSystemGUID | :white_check_mark: | mc guid | | SetSystemInfoParam | | | | GetSystemInfoParam | :white_check_mark: | | | GetSystemInfoParamFor (*) | :white_check_mark: | | | GetSystemInfoParams (*) | :white_check_mark: | | | GetSystemInfoParamsFor (*) | :white_check_mark: | | | GetSystemInfo (*) | :white_check_mark: | | | GetChannelAuthCapabilities | :white_check_mark: | | | GetSessionChallenge | :white_check_mark: | | | ActivateSession | :white_check_mark: | | | SetSessionPrivilegeLevel | :white_check_mark: | | | CloseSession | :white_check_mark: | | | GetSessionInfo | :white_check_mark: | session info | | GetAuthCode | :white_check_mark: | | | SetChannelAccess | :white_check_mark: | channel setaccess | | GetChannelAccess | :white_check_mark: | channel info/getaccess | | GetChannelInfo | :white_check_mark: | channel info | | SetUserAccess | :white_check_mark: | | | GetUserAccess | :white_check_mark: | user summary | | GetUsers (*) | :white_check_mark: | user list | | SetUsername | :white_check_mark: | user set name | | DisableUser (*) | :white_check_mark: | user disable | | EnableUser (*) | :white_check_mark: | user enable | | GetUsername | :white_check_mark: | | SetUserPassword | :white_check_mark: | user set password | | TestUserPassword (*) | :white_check_mark: | user test | | ActivatePayload | | | | DeactivatePayload | | | | GetPayloadActivationStatus | | | | GetPayloadInstanceInfo | | | | SetUserPayloadAccess | | | | GetUserPayloadAccess | | sol payload status | | GetChannelPayloadSupport | | | | GetChannelPayloadVersion | | | | GetChannelOEMPayloadInfo | | | | MasterWriteRead | | | | GetChannelCipherSuites | :white_check_mark: | | | SuspendOrResumeEncryption | | | | SetChannelCipherSuites | | | | GetSystemInterfaceCapabilities | :white_check_mark: | | ### Chassis Device Commands | Method | Status | corresponding ipmitool usage | | --------------------------------- | ------------------ | ------------------------------------------------- | | GetChassisCapabilities | :white_check_mark: | | | GetChassisStatus | :white_check_mark: | chassis status, chassis power status | | ChassisControl | :white_check_mark: | chassis power on/off/cycle/reset/diag/soft | | ChassisReset | :white_check_mark: | | | ChassisIdentify | :white_check_mark: | chassis identify | | SetChassisCapabilities | :white_check_mark: | | | SetPowerRestorePolicy | :white_check_mark: | chassis policy list/always-on/previous/always-off | | GetSystemRestartCause | :white_check_mark: | chassis restart_cause | | SetBootParamBootFlags (*) | :white_check_mark: | chassis bootdev | | SetBootDevice (*) | :white_check_mark: | chassis bootdev | | SetSystemBootOptionsParam | :white_check_mark: | chassis bootparam set | | GetSystemBootOptionsParam | :white_check_mark: | chassis bootparam get | | GetSystemBootOptionsParamFor (*) | :white_check_mark: | chassis bootparam get | | GetSystemBootOptionsParams (*) | :white_check_mark: | chassis bootparam get | | GetSystemBootOptionsParamsFor (*) | :white_check_mark: | chassis bootparam get | | SetFrontPanelEnables | :white_check_mark: | | | SetPowerCycleInterval | :white_check_mark: | | | GetPOHCounter | :white_check_mark: | chassis poh | ### Event Commands | Method | Status | corresponding ipmitool usage | | -------------------- | ------------------ | ---------------------------- | | SetEventReceiver | :white_check_mark: | | | GetEventReceiver | :white_check_mark: | | | PlatformEventMessage | :white_check_mark: | | ### PEF and Alerting Commands | Method | Status | corresponding ipmitool usage | | ------------------------- | ------------------ | ---------------------------- | | GetPEFCapabilities | :white_check_mark: | pef capabilities | | ArmPEFPostponeTimer | | | | SetPEFConfigParam | | | | GetPEFConfigParam | | | | GetPEFConfigParamFor (*) | | | | GetPEFConfigParams (*) | | | | GetPEFConfigParamsFor (*) | | | | SetLastProcessedEventId | | | | GetLastProcessedEventId | | | | AlertImmediate | | | | PEFAck | | | ### Sensor Device Commands | Method | Status | corresponding ipmitool usage | | ------------------------------ | ------------------ | ---------------------------- | | GetDeviceSDRInfo | :white_check_mark: | | | GetDeviceSDR | :white_check_mark: | | | ReserveDeviceSDRRepo | :white_check_mark: | | | GetSensorReadingFactors | :white_check_mark: | | | SetSensorHysteresis | :white_check_mark: | | | GetSensorHysteresis | :white_check_mark: | | | SetSensorThresholds | :white_check_mark: | | | GetSensorThresholds | :white_check_mark: | | | SetSensorEventEnable | | | | GetSensorEventEnable | :white_check_mark: | | | RearmSensorEvents | | | | GetSensorEventStatus | :white_check_mark: | | | GetSensorReading | :white_check_mark: | | | SetSensorType | :white_check_mark: | | | GetSensorType | :white_check_mark: | | | SetSensorReadingAndEventStatus | :white_check_mark: | | | GetSensors (*) | :white_check_mark: | sensor list, sdr type | | GetSensorByID (*) | :white_check_mark: | | | GetSensorByName (*) | :white_check_mark: | sensor get | ### FRU Device Commands | Method | Status | corresponding ipmitool usage | | ----------------------- | ------------------ | ---------------------------- | | GetFRUInventoryAreaInfo | :white_check_mark: | | | ReadFRUData | :white_check_mark: | | | WriteFRUData | :white_check_mark: | | | GetFRU (*) | :white_check_mark: | fru print | | GetFRUs (*) | :white_check_mark: | fru print | ### SDR Device Commands | Method | Status | corresponding ipmitool usage | | ---------------------- | ------------------ | ---------------------------- | | GetSDRRepoInfo | :white_check_mark: | sdr info | | GetSDRRepoAllocInfo | :white_check_mark: | sdr info | | ReserveSDRRepo | | | | GetSDR | :white_check_mark: | | | GetSDRs (*) | :white_check_mark: | | | GetSDRBySensorID (*) | :white_check_mark: | | | GetSDRBySensorName (*) | :white_check_mark: | | | AddSDR | | | | PartialAddSDR | | | | DeleteSDR | | | | ClearSDRRepo | | | | GetSDRRepoTime | | | | SetSDRRepoTime | | | | EnterSDRRepoUpdateMode | | | | ExitSDRRepoUpdateMode | | | | RunInitializationAgent | | | ### SEL Device Commands | Method | Status | corresponding ipmitool usage | | ------------------- | ------------------ | ---------------------------- | | GetSELInfo | :white_check_mark: | sel info | | GetSELAllocInfo | :white_check_mark: | sel info | | ReserveSEL | :white_check_mark: | | | GetSELEntry | :white_check_mark: | | | AddSELEntry | :white_check_mark: | | | PartialAddSELEntry | | | | DeleteSELEntry | :white_check_mark: | | | ClearSEL | :white_check_mark: | sel clear | | GetSELTime | :white_check_mark: | | | SetSELTime | :white_check_mark: | | | GetAuxLogStatus | | | | SetAuxLogStatus | | | | GetSELTimeUTCOffset | :white_check_mark: | | | SetSELTimeUTCOffset | :white_check_mark: | | ### LAN Device Commands | Method | Status | corresponding ipmitool usage | | ------------------------- | ------------------ | ---------------------------- | | SetLanConfigParam | :white_check_mark: | lan set | | SetLanConfigParamFor (*) | :white_check_mark: | lan set | | GetLanConfigParam | :white_check_mark: | | | GetLanConfigParamFor (*) | :white_check_mark: | lan print | | GetLanConfigParams (*) | :white_check_mark: | lan print | | GetLanConfigParamsFor (*) | :white_check_mark: | lan print | | GetLanConfig (*) | :white_check_mark: | lan print | | SuspendARPs | :white_check_mark: | | | GetIPStatistics | :white_check_mark: | | ### Serial/Modem Device Commands | Method | Status | corresponding ipmitool usage | | ------------------------- | ------------------ | ---------------------------- | | SetSerialConfig | | | | GetSerialConfig | | | | SetSerialMux | | | | GetTapResponseCodes | | | | SetPPPTransmitData | | | | GetPPPTransmitData | | | | SendPPPPacket | | | | GetPPPReceiveData | | | | SerialConnectionActive | | | | Callback | | | | SetUserCallbackOptions | | | | GetUserCallbackOptions | | | | SetSerialRoutingMux | | | | SOLActivating | :white_check_mark: | | | SetSOLConfigParam | :white_check_mark: | | | SetSOLConfigParamFor (*) | :white_check_mark: | | | GetSOLConfigParam | :white_check_mark: | | | GetSOLConfigParamFor (*) | :white_check_mark: | | | GetSOLConfigParams (*) | :white_check_mark: | sol info | | GetSOLConfigParamsFor (*) | :white_check_mark: | sol info | ### Command Forwarding Commands | Method | Status | corresponding ipmitool usage | | --------------- | ------ | ---------------------------- | | Forwarded | | | | SetForwarded | | | | GetForwarded | | | | EnableForwarded | | | ### Bridge Management Commands (ICMB) | Method | Status | corresponding ipmitool usage | | --------------------- | ------ | ---------------------------- | | GetBridgeState | | | | SetBridgeState | | | | GetICMBAddress | | | | SetICMBAddress | | | | SetBridgeProxyAddress | | | | GetBridgeStatistics | | | | GetICMBCapabilities | | | | ClearBridgeStatistics | | | | GetBridgeProxyAddress | | | | GetICMBConnectorInfo | | | | GetICMBConnectionID | | | | SendICMBConnectionID | | | ### Discovery Commands (ICMB) | Method | Status | corresponding ipmitool usage | | ------------------- | ------ | ---------------------------- | | PrepareForDiscovery | | | | GetAddresses | | | | SetDiscovered | | | | GetChassisDeviceId | | | | SetChassisDeviceId | | | ### Bridging Commands (ICMB) | Method | Status | corresponding ipmitool usage | | ------------- | ------ | ---------------------------- | | BridgeRequest | | | | BridgeMessage | | | ### Event Commands (ICMB) | Method | Status | corresponding ipmitool usage | | ---------------------- | ------ | ---------------------------- | | GetEventCount | | | | SetEventDestination | | | | SetEventReceptionState | | | | SendICMBEventMessage | | | | GetEventDestination | | | | GetEventReceptionState | | | ### Other Bridge Commands | Method | Status | corresponding ipmitool usage | | ----------- | ------ | ---------------------------- | | ErrorReport | | | ### DCMI Commands | Method | Status | corresponding ipmitool usage | | ------------------------------- | ------------------ | ---------------------------- | | GetDCMICapParam | :white_check_mark: | dcmi discovery | | GetDCMICapParamFor (*) | :white_check_mark: | dcmi discovery | | GetDCMICapParams (*) | :white_check_mark: | dcmi discovery | | GetDCMICapParamsFor (*) | :white_check_mark: | dcmi discovery | | GetDCMIPowerReading | :white_check_mark: | dcmi power reading | | GetDCMIPowerLimit | :white_check_mark: | dcmi power get_limit | | SetDCMIPowerLimit | :white_check_mark: | dcmi power set_limit | | ActivateDCMIPowerLimit | :white_check_mark: | dcmi activate/deactivate | | GetDCMIAssetTag | :white_check_mark: | dcmi asset_tag | | GetDCMIAssetTagFull (*) | :white_check_mark: | dcmi asset_tag | | GetDCMISensorInfo | :white_check_mark: | dcmi sensors | | SetDCMIAssetTag | :white_check_mark: | dcmi set_asset_tag | | GetDCMIMgmtControllerIdentifier | :white_check_mark: | dcmi get_mc_id_string | | SetDCMIMgmtControllerIdentifier | :white_check_mark: | dcmi set_mc_id_string | | SetDCMIThermalLimit | :white_check_mark: | dcmi thermalpolicy get | | GetDCMIThermalLimit | :white_check_mark: | dcmi thermalpolicy set | | GetDCMITemperatureReadings | :white_check_mark: | dcmi get_temp_reading | | SetDCMIConfigParam | :white_check_mark: | dcmi set_conf_param | | GetDCMIConfigParam | :white_check_mark: | dcmi get_conf_param | | GetDCMIConfigParamFor (*) | :white_check_mark: | dcmi get_conf_param | | GetDCMIConfigParams (*) | :white_check_mark: | dcmi get_conf_param | | GetDCMIConfigParamsFor (*) | :white_check_mark: | dcmi get_conf_param | ## Reference - [Intelligent Platform Management Interface Specification Second Generation v2.0](https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/ipmi-intelligent-platform-mgt-interface-spec-2nd-gen-v2-0-spec-update.pdf) - [Platform Management FRU Information Storage Definition](https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/ipmi-platform-mgt-fru-info-storage-def-v1-0-rev-1-3-spec-update.pdf) - [PC SDRAM Serial Presence Detect (SPD) Specification](https://cdn.hackaday.io/files/10119432931296/Spdsd12b.pdf) - [DCMI Group Extension Specification v1.5](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/dcmi-v1-5-rev-spec.pdf) golang-github-bougou-go-ipmi-0.7.2/_config.yml000066400000000000000000000005151474110527100212360ustar00rootroot00000000000000lsi: false safe: true incremental: false gist: noscript: false markdown: kramdown highlighter: rouge permalink: pretty repos: - name: go-ipmi description: IPMI library in pure Go url: https://github.com/bougou/go-ipmi brand_color: "#DA253B" kramdown: math_engine: mathjax syntax_highlighter: rouge plugins: - jemoji golang-github-bougou-go-ipmi-0.7.2/client.go000066400000000000000000000131201474110527100207100ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "sync" "time" "golang.org/x/net/proxy" ) type Interface string const ( InterfaceLan Interface = "lan" InterfaceLanplus Interface = "lanplus" InterfaceOpen Interface = "open" InterfaceTool Interface = "tool" DefaultExchangeTimeoutSec int = 20 DefaultKeepAliveIntervalSec int = 30 DefaultBufferSize int = 1024 ) type Client struct { Host string Port int Username string // length must <= 16 Password string Interface Interface debug bool maxPrivilegeLevel PrivilegeLevel responderAddr uint8 responderLUN uint8 requesterAddr uint8 requesterLUN uint8 openipmi *openipmi session *session // this flags controls which IPMI version (1.5 or 2.0) be used by Client to send Request v20 bool udpClient *UDPClient timeout time.Duration bufferSize int l sync.Mutex // closedCh is closed when Client.Close() is called. // used to notify other goroutines that Client is closed. closedCh chan bool } func NewOpenClient() (*Client, error) { myAddr := BMC_SA return &Client{ Interface: "open", timeout: time.Second * time.Duration(DefaultExchangeTimeoutSec), bufferSize: DefaultBufferSize, openipmi: &openipmi{ myAddr: myAddr, targetAddr: myAddr, }, }, nil } // NewToolClient creates an IPMI client based ipmitool. // You should pass the file path of ipmitool binary or path of a wrapper script // that would be executed. func NewToolClient(path string) (*Client, error) { return &Client{ Host: path, Interface: "tool", }, nil } func NewClient(host string, port int, user string, pass string) (*Client, error) { if len(user) > IPMI_MAX_USER_NAME_LENGTH { return nil, fmt.Errorf("user name (%s) too long, exceed (%d) characters", user, IPMI_MAX_USER_NAME_LENGTH) } c := &Client{ Host: host, Port: port, Username: user, Password: pass, Interface: InterfaceLanplus, v20: true, timeout: time.Second * time.Duration(DefaultExchangeTimeoutSec), bufferSize: DefaultBufferSize, maxPrivilegeLevel: PrivilegeLevelUnspecified, responderAddr: BMC_SA, responderLUN: uint8(IPMB_LUN_BMC), requesterAddr: RemoteConsole_SWID, requesterLUN: 0x00, session: &session{ // IPMI Request Sequence, start from 1 ipmiSeq: 1, v20: v20{ state: SessionStatePreSession, cipherSuiteID: CipherSuiteIDReserved, }, v15: v15{ active: false, }, }, closedCh: make(chan bool), } c.udpClient = &UDPClient{ Host: host, Port: port, timeout: c.timeout, bufferSize: c.bufferSize, } return c, nil } func (c *Client) WithInterface(intf Interface) *Client { c.Interface = intf return c } func (c *Client) WithDebug(debug bool) *Client { c.debug = debug return c } func (c *Client) WithUDPProxy(proxy proxy.Dialer) *Client { if c.udpClient != nil { c.udpClient.SetProxy(proxy) } return c } func (c *Client) WithTimeout(timeout time.Duration) *Client { c.timeout = timeout if c.udpClient != nil { c.udpClient.timeout = timeout } return c } func (c *Client) WithBufferSize(bufferSize int) *Client { c.bufferSize = bufferSize if c.udpClient != nil { c.udpClient.bufferSize = bufferSize } return c } // WithCipherSuiteID sets a custom cipher suite which is used during OpenSession command. // It is only valid for client with IPMI lanplus interface. // For the custom cipherSuiteID to take effect, you must call WithCipherSuiteID before calling Connect method. func (c *Client) WithCipherSuiteID(cipherSuiteID CipherSuiteID) *Client { if c.session != nil { c.session.v20.cipherSuiteID = cipherSuiteID } return c } // WithMaxPrivilegeLevel sets a specified session privilege level to use. func (c *Client) WithMaxPrivilegeLevel(privilegeLevel PrivilegeLevel) *Client { c.maxPrivilegeLevel = privilegeLevel return c } func (c *Client) WithResponderAddr(responderAddr, responderLUN uint8) { c.responderAddr = responderAddr c.responderLUN = responderLUN } func (c *Client) WithRequesterAddr(requesterAddr, requesterLUN uint8) { c.requesterAddr = requesterAddr c.requesterLUN = requesterLUN } func (c *Client) SessionPrivilegeLevel() PrivilegeLevel { return c.maxPrivilegeLevel } // Connect connects to the bmc by specified Interface. func (c *Client) Connect(ctx context.Context) error { // Optional RMCP Ping/Pong mechanism // pongRes, err := c.RmcpPing() // if err != nil { // return fmt.Errorf("RMCP Ping failed, err: %w", err) // } // if pongRes.IPMISupported { // return fmt.Errorf("ipmi not supported") // } switch c.Interface { case "", InterfaceOpen: var devnum int32 = 0 return c.ConnectOpen(ctx, devnum) case InterfaceTool: var devnum int32 = 0 return c.ConnectTool(ctx, devnum) case InterfaceLanplus: c.v20 = true return c.Connect20(ctx) case InterfaceLan: c.v20 = false return c.Connect15(ctx) default: return fmt.Errorf("not supported interface, supported: lan,lanplus,open") } } func (c *Client) Close(ctx context.Context) error { switch c.Interface { case "", InterfaceOpen: return c.closeOpen(ctx) case InterfaceTool: return c.closeTool(ctx) case InterfaceLan, InterfaceLanplus: return c.closeLAN(ctx) } return nil } func (c *Client) Exchange(ctx context.Context, request Request, response Response) error { switch c.Interface { case "", InterfaceOpen: return c.exchangeOpen(ctx, request, response) case InterfaceTool: return c.exchangeTool(ctx, request, response) case InterfaceLan, InterfaceLanplus: return c.exchangeLAN(ctx, request, response) } return nil } func (c *Client) lock() { c.l.Lock() } func (c *Client) unlock() { c.l.Unlock() } golang-github-bougou-go-ipmi-0.7.2/client_auth_code.go000066400000000000000000000304441474110527100227330ustar00rootroot00000000000000package ipmi import ( "crypto/md5" "fmt" "github.com/bougou/go-ipmi/utils/md2" ) // 22.17.1 AuthCode Algorithms // Single Session AuthCode carried in IPMI message data for Activate Session Command // to fill ActiveSessionRequest.Challenge type AuthCodeSingleSessionInput struct { Password string SessionID uint32 Challenge []byte } func (a AuthCodeSingleSessionInput) AuthCode(authType AuthType) []byte { password := padBytes(a.Password, 16, 0x00) inputLength := 16 + 4 + len(a.Challenge) + 16 var input = make([]byte, inputLength) packBytes(password, input, 0) packUint32L(a.SessionID, input, 16) packBytes(a.Challenge[:], input, 20) packBytes(password, input, 20+len(a.Challenge)) var authCode []byte switch authType { case AuthTypePassword: authCode = password case AuthTypeMD2: authCode = md2.New().Sum(input) authCode = authCode[:16] case AuthTypeMD5: c := md5.Sum(input) // can not use md5.New().Sum(input) authCode = c[:] } return authCode[:16] } // 22.17.1 AuthCode Algorithms // Multi-Session AuthCode carried in session header for all authenticated packets type AuthCodeMultiSessionInput struct { Password string SessionID uint32 SessionSeq uint32 IPMIData []byte } func (i *AuthCodeMultiSessionInput) AuthCode(authType AuthType) []byte { password := padBytes(i.Password, 16, 0x00) ipmiData := i.IPMIData // The Integrity Algorithm Number specifies the algorithm used to generate the contents // for the AuthCode signature field that accompanies authenticated IPMI v2.0/RMCP+ messages once the session has been // established. // Unless otherwise specified, the integrity algorithm is applied to the packet data starting with the // AuthType/Format field up to and including the field that immediately precedes the AuthCode field itself. authCodeInputLength := len(password) + 4 + // session od uint32 len(ipmiData) + 4 + // session seq uint32 len(password) var input = make([]byte, authCodeInputLength) packBytes(password, input, 0) packUint32L(i.SessionID, input, 16) packBytes(ipmiData, input, 20) packUint32L(i.SessionSeq, input, 20+len(ipmiData)) packBytes(password, input, 20+len(ipmiData)+4) // c := md5.Sum(input) // authCode := c[:] var authCode []byte switch authType { case AuthTypePassword: authCode = password case AuthTypeMD2: authCode = md2.New().Sum(input) authCode = authCode[:16] case AuthTypeMD5: c := md5.Sum(input) // can not use md5.New().Sum(input) authCode = c[:] } return authCode[:16] } func (c *Client) genAuthCodeForSingleSession() []byte { input := &AuthCodeSingleSessionInput{ Password: c.Password, SessionID: c.session.v15.sessionID, Challenge: c.session.v15.challenge[:], } authCode := input.AuthCode(c.session.authType) c.DebugBytes(fmt.Sprintf("authtype (%d) gen authcode", c.session.authType), authCode, 16) return authCode } // only be used for ActivateSession (IPMI v1.5) // see 22.17.1 AuthCode Algorithms func (c *Client) genAuthCodeForMultiSession(ipmiMsg []byte) []byte { input := &AuthCodeMultiSessionInput{ Password: c.Password, SessionID: c.session.v15.sessionID, SessionSeq: c.session.v15.inSeq, IPMIData: ipmiMsg, } authCode := input.AuthCode(c.session.authType) c.DebugBytes(fmt.Sprintf("authtype (%d) gen authcode", c.session.authType), authCode, 16) return authCode } // When the HMAC-SHA1-96 Integrity Algorithm is used the resulting AuthCode field is 12 bytes (96 bits). // When the HMAC-SHA256-128 and HMAC-MD5-128 Integrity Algorithms are used the resulting AuthCode field is 16-bytes (128 bits). func (c *Client) genIntegrityAuthCode(input []byte) ([]byte, error) { switch c.session.v20.integrityAlg { case IntegrityAlg_None: // If the Integrity Algorithm is none the AuthCode value is not calculated and // the AuthCode field in the message is not present (zero bytes). return []byte{}, nil case IntegrityAlg_MD5_128: data := []byte{} data = append(data, []byte(c.Password)[:]...) data = append(data, input...) data = append(data, []byte(c.Password)[:]...) h := md5.Sum(data) return h[:], nil case IntegrityAlg_HMAC_MD5_128: b, err := generate_hmac("md5", input, c.session.v20.k1) if err != nil { return nil, fmt.Errorf("generate hmac failed") } return b[0:16], nil case IntegrityAlg_HMAC_SHA1_96: b, err := generate_hmac("sha1", input, c.session.v20.k1) if err != nil { return nil, fmt.Errorf("generate hmac failed") } return b[0:12], nil case IntegrityAlg_HMAC_SHA256_128: b, err := generate_hmac("sha256", input, c.session.v20.k1) if err != nil { return nil, fmt.Errorf("generate hmac failed") } return b[0:16], nil default: return nil, fmt.Errorf("not support for integrity algorithm %x", c.session.v20.integrityAlg) } } // sik (Session Integrity Key) // Both the remote console and the managed system generate sik by using // the same hmackey and hmac data, so they should be same. // see 13.31 func (c *Client) generate_sik() ([]byte, error) { input := make([]byte, 34+len(c.Username)) packBytes(c.session.v20.consoleRand[:], input, 0) // 16 bytes packBytes(c.session.v20.bmcRand[:], input, 16) // 16 bytes packUint8(c.session.v20.role, input, 32) // 1 bytes, Requested privilege level (entire byte) packUint8(uint8(len(c.Username)), input, 33) // 1 bytes, Username length packBytes([]byte(c.Username), input, 34) // N bytes, Username (absent for null usernames) c.DebugBytes("sik mac input", input, 16) var hmacKey []byte // hmacKey should use 160-bit key Kg // and Kuid is used in place of Kg if "one-key" logins are being used. if len(c.session.v20.bmcKey) != 0 { hmacKey = c.session.v20.bmcKey } else { hmacKey = padBytes(c.Password, 20, 0x00) // 160 bit = 20 bytes } c.DebugBytes("sik mac key", hmacKey, 16) b, err := generate_auth_hmac(c.session.v20.authAlg, input, hmacKey) if err != nil { return nil, fmt.Errorf("generate hmac failed, err: %w", err) } c.DebugBytes("sik mac computed by the remote console:", b, 16) return b, nil } // see 13.32 Generating Additional Keying Material // // generate K1 key, the session integrity key (SIK) is used as hmac key. func (c *Client) generate_k1() ([]byte, error) { var CONST_1 = [20]byte{ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, } if c.session.v20.sik == nil { return nil, fmt.Errorf("sik not exists, generate sik first") } hmacKey := c.session.v20.sik b, err := generate_auth_hmac(c.session.v20.authAlg, CONST_1[:], hmacKey) if err != nil { return nil, fmt.Errorf("generate hmac failed, err: %w", err) } c.DebugBytes("generated k1:", b, 16) return b, nil } // see 13.32 Generating Additional Keying Material // // generate K2 key, the session integrity key (SIK) is used as hmac key. func (c *Client) generate_k2() ([]byte, error) { var CONST_2 = [20]byte{ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, } if c.session.v20.sik == nil { return nil, fmt.Errorf("sik not exists, generate sik first") } hmacKey := c.session.v20.sik b, err := generate_auth_hmac(c.session.v20.authAlg, CONST_2[:], hmacKey) if err != nil { return nil, fmt.Errorf("generate hmac failed, err: %w", err) } c.DebugBytes("generated k2:", b, 16) return b, nil } // used for verify rakp2 func (c *Client) generate_rakp2_authcode() ([]byte, error) { c.DebugBytes("bmc rand", c.session.v20.bmcRand[:], 16) bufferLen := 4 + 4 + 16 + 16 + 16 + 1 + 1 + len(c.Username) var buffer = make([]byte, bufferLen) packUint32L(c.session.v20.consoleSessionID, buffer, 0) // 4 bytes, Console session ID (SID) packUint32L(c.session.v20.bmcSessionID, buffer, 4) // 4 bytes, bmc session ID (SID) packBytes(c.session.v20.consoleRand[:], buffer, 8) // 16 bytes, Remote console random number packBytes(c.session.v20.bmcRand[:], buffer, 24) // 16 bytes, BMC random number (RC) packBytes(c.session.v20.bmcGUID[:], buffer, 40) // 16 bytes, BMC guid packUint8(c.session.v20.role, buffer, 56) // 1 bytes, entire byte of privilege level of rakp1 packUint8(uint8(len(c.Username)), buffer, 57) // 1 bytes, Username length packBytes([]byte(c.Username), buffer, 58) // N bytes, Username (absent for null usernames) c.DebugBytes("rakp2 authcode input", buffer, 16) // The bmc also use user password to calculate authcode, so if the authcode does not match, // it may indicates the password is not right. hmacKey := padBytes(c.Password, 20, 0x00) c.DebugBytes("rakp2 authcode key", hmacKey, 16) b, err := generate_auth_hmac(c.session.v20.authAlg, buffer, hmacKey) if err != nil { return nil, fmt.Errorf("generate hmac failed, err: %w", err) } c.DebugBytes("rakp2 generated authcode", b, 16) var out = b switch c.session.v20.authAlg { case AuthAlgRAKP_None: // nothing need to do case AuthAlgRAKP_HMAC_MD5: // need to copy 16 bytes if len(b) < 16 { err = fmt.Errorf("hmac md5 length should be at least 16 bytes") } out = b[0:16] case AuthAlgRAKP_HMAC_SHA1: // need to copy 20 bytes if len(b) < 20 { err = fmt.Errorf("hmac sha1 length should be at least 20 bytes") } out = b[0:20] case AuthAlgRAKP_HMAC_SHA256: if len(b) < 32 { err = fmt.Errorf("hmac sha256 length should be at least 32 bytes") } out = b[0:32] default: err = fmt.Errorf("rakp2 message: no support for authentication algorithm 0x%x", c.session.v20.authAlg) } c.DebugBytes("rakp2 used authcode", out, 16) return out, err } // 22.17.1 AuthCode Algorithms func (c *Client) generate_rakp3_authcode() ([]byte, error) { // The auth code is an HMAC generated with the following content var input []byte = []byte{} input = append(input, c.session.v20.bmcRand[:]...) // 16 bytes, BMC random number (RC) buffer := make([]byte, 4) packUint32L(c.session.v20.consoleSessionID, buffer, 0) input = append(input, buffer...) // 4 bytes, Console session ID (SID) input = append(input, byte(c.session.v20.role)) // 1 bytes, Requested privilege level (entire byte) input = append(input, byte(len([]byte(c.Username)))) // 1 bytes, Username length input = append(input, []byte(c.Username)...) // N bytes, Username (absent for null usernames) c.DebugBytes("rakp3 auth code input", input, 16) hmacKey := padBytes(c.Password, 20, 0x00) c.DebugBytes("rakp3 auth code key", hmacKey, 16) b, err := generate_auth_hmac(c.session.v20.authAlg, input, hmacKey) if err != nil { return nil, fmt.Errorf("generate hmac failed, err: %w", err) } c.DebugBytes("rakp3 generated authcode", b, 16) var out = b c.DebugBytes("rakp3 used authcode", out, 16) return out, err } // 13.31 RMCP+ Authenticated Key-Exchange Protocol (RAKP) // 13.28 // the client use this method to verify the authcode returned in rakp4 func (c *Client) generate_rakp4_authcode() ([]byte, error) { var input []byte = []byte{} input = append(input, c.session.v20.consoleRand[:]...) // 16 bytes, Console random number buffer := make([]byte, 4) packUint32L(c.session.v20.bmcSessionID, buffer, 0) input = append(input, buffer...) // 4 bytes, BMC session ID (SID) input = append(input, c.session.v20.bmcGUID[:]...) // 16 bytes c.DebugBytes("rakp4 auth code input", input, 16) hmacKey := c.session.v20.sik c.DebugBytes("rakp4 auth code key", hmacKey, 16) b, err := generate_auth_hmac(c.session.v20.integrityAlg, input, hmacKey) if err != nil { return nil, fmt.Errorf("generate hmac failed, err: %w", err) } c.DebugBytes("rakp4 generated authcode", b, 16) var errHmacLen = func(length int, integrityAlg IntegrityAlg) error { return fmt.Errorf("the length of generated mac is not long enough, should be at least (%d) for integrity algorithm (%0x)", len(b), integrityAlg) } var out = b integrityAlg := c.session.v20.integrityAlg switch integrityAlg { case IntegrityAlg_None: // nothing need to do case IntegrityAlg_HMAC_MD5_128: // need to copy 16 bytes if len(b) < 16 { err = errHmacLen(len(b), integrityAlg) } out = b[0:16] case IntegrityAlg_HMAC_SHA1_96: // need to copy 12 bytes if len(b) < 12 { err = errHmacLen(len(b), integrityAlg) } out = b[0:12] case IntegrityAlg_HMAC_SHA256_128: if len(b) < 16 { err = errHmacLen(len(b), integrityAlg) } out = b[0:16] default: err = fmt.Errorf("rakp4 message: no support for integrity algorithm %x", c.session.v20.integrityAlg) } c.DebugBytes("rakp4 used authcode", out, 16) return out, err } golang-github-bougou-go-ipmi-0.7.2/client_auth_code_test.go000066400000000000000000000043571474110527100237760ustar00rootroot00000000000000package ipmi import "testing" func Test_ActivateSessionAuthCode(t *testing.T) { tests := []struct { name string commandRequest Request ipmiRequest *IPMIRequest input *AuthCodeMultiSessionInput expect []byte }{ { name: "test1", commandRequest: &ActivateSessionRequest{ AuthTypeForSession: 0x02, MaxPrivilegeLevel: 0x04, Challenge: [16]byte{0x82, 0x8f, 0xa9, 0xbf, 0x25, 0x51, 0x6b, 0x2a, 0xf5, 0xf8, 0xfb, 0x3f, 0x37, 0xae, 0x6e, 0x69}, InitialOutboundSequenceNumber: 0xa2605e12, }, ipmiRequest: &IPMIRequest{ ResponderAddr: 0x20, ResponderLUN: 0x0, NetFn: NetFnAppRequest, RequesterAddr: 0x81, RequesterLUN: 0x0, RequesterSequence: 0x03, Command: 0x3a, }, input: &AuthCodeMultiSessionInput{ // cSpell:disable Password: "vtA9kBPODBPBy", // cSpell:enable SessionID: 0xb215d500, SessionSeq: 0x00000000, }, expect: []byte{0xec, 0xb1, 0x65, 0xeb, 0xdc, 0xf7, 0x9f, 0xd9, 0x96, 0xa3, 0xfa, 0x6b, 0xae, 0x18, 0x69, 0x54}, }, { name: "test2", commandRequest: &SetSessionPrivilegeLevelRequest{ PrivilegeLevel: PrivilegeLevelAdministrator, }, ipmiRequest: &IPMIRequest{ ResponderAddr: 0x20, ResponderLUN: 0x0, NetFn: CommandSetSessionPrivilegeLevel.NetFn, RequesterAddr: 0x81, RequesterLUN: 0x0, RequesterSequence: 0x04, Command: CommandSetSessionPrivilegeLevel.ID, }, input: &AuthCodeMultiSessionInput{ // cSpell:disable Password: "vtA9kBPODBPBy", // cSpell:enable SessionID: 0xa26f8e00, SessionSeq: 0xdabbb496, }, expect: []byte{0x69, 0xe8, 0x3e, 0x2b, 0x99, 0xe3, 0xf6, 0xa9, 0x3d, 0x1c, 0xf0, 0x47, 0x8b, 0x0e, 0xfe, 0xba}, }, } for _, tt := range tests { commandData := tt.commandRequest.Pack() tt.ipmiRequest.CommandData = commandData tt.ipmiRequest.ComputeChecksum() ipmiData := tt.ipmiRequest.Pack() tt.input.IPMIData = ipmiData got := tt.input.AuthCode(AuthTypeMD5) expected := tt.expect if !isByteSliceEqual(got, expected) { t.Errorf("test %s failed, not equal, got: %v, expected: %v", tt.name, got, expected) } } } golang-github-bougou-go-ipmi-0.7.2/cmd/000077500000000000000000000000001474110527100176515ustar00rootroot00000000000000golang-github-bougou-go-ipmi-0.7.2/cmd/.gitignore000066400000000000000000000000121474110527100216320ustar00rootroot00000000000000testtools golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/000077500000000000000000000000001474110527100211355ustar00rootroot00000000000000golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/.gitignore000066400000000000000000000000071474110527100231220ustar00rootroot00000000000000goipmi golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/README.md000066400000000000000000000004441474110527100224160ustar00rootroot00000000000000# goipmi The `goipmi` is a binary tool which provides the same command usages like `ipmitool`. The `goipmi` calls `go-ipmi` library underlying. The purpose of creating `goipmi` tool was not intended to substitute `ipmitool`. It was just used to verify the correctness of `go-ipmi` library. golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/000077500000000000000000000000001474110527100227365ustar00rootroot00000000000000golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/channel.go000066400000000000000000000053631474110527100247040ustar00rootroot00000000000000package commands import ( "context" "fmt" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) func NewCmdChannel() *cobra.Command { cmd := &cobra.Command{ Use: "channel", Short: "channel", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdChannelInfo()) cmd.AddCommand(NewCmdChannelGetCiphers()) return cmd } func NewCmdChannelInfo() *cobra.Command { cmd := &cobra.Command{ Use: "info", Short: "info", Run: func(cmd *cobra.Command, args []string) { var channelNumber uint8 if len(args) == 0 { channelNumber = ipmi.ChannelNumberSelf } if len(args) >= 1 { i, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid channel number, err: %w", err)) } channelNumber = uint8(i) } ctx := context.Background() res, err := client.GetChannelInfo(ctx, channelNumber) if err != nil { CheckErr(fmt.Errorf("GetChannelInfo failed, err: %w", err)) } fmt.Println(res.Format()) if res.SessionSupport == 0 { return } res2, err := client.GetChannelAccess(ctx, channelNumber, ipmi.ChannelAccessOption_Volatile) if err != nil { CheckErr(fmt.Errorf("GetChannelAccess failed, err: %w", err)) } fmt.Println(" Volatile(active) Settings") fmt.Println(res2.Format()) res3, err := client.GetChannelAccess(ctx, channelNumber, ipmi.ChannelAccessOption_NonVolatile) if err != nil { CheckErr(fmt.Errorf("GetChannelAccess failed, err: %w", err)) } fmt.Println(" Non-Volatile Settings") fmt.Println(res3.Format()) }, } return cmd } func NewCmdChannelGetCiphers() *cobra.Command { cmd := &cobra.Command{ Use: "getciphers", Short: "getciphers", Run: func(cmd *cobra.Command, args []string) { var channelNumber uint8 if len(args) == 0 { channelNumber = ipmi.ChannelNumberSelf } if len(args) >= 1 { i, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid channel number, err: %w", err)) } channelNumber = uint8(i) } ctx := context.Background() cipherSuiteRecords, err := client.GetAllChannelCipherSuites(ctx, channelNumber) if err != nil { CheckErr(fmt.Errorf("GetChannelInfo failed, err: %w", err)) } fmt.Println("ID IANA Auth Alg Integrity Alg Confidentiality Alg") for _, record := range cipherSuiteRecords { fmt.Printf("%-5d%-8d%-16s%-16s%-s\n", record.CipherSuitID, record.OEMIanaID, ipmi.AuthAlg(record.AuthAlg), ipmi.IntegrityAlg(record.IntegrityAlgs[0]), ipmi.CryptAlg(record.CryptAlgs[0])) } }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/chassis.go000066400000000000000000000260141474110527100247250ustar00rootroot00000000000000package commands import ( "context" "errors" "fmt" "strings" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) const ( bootParamGetUsage = ` bootparam get available param # 0 : Set In Progress (volatile) 1 : service partition selector (semi-volatile) 2 : service partition scan (non-volatile) 3 : BMC boot flag valid bit clearing (semi-volatile) 4 : boot info acknowledge (semi-volatile) 5 : boot flags (semi-volatile) 6 : boot initiator info (semi-volatile) 7 : boot initiator mailbox (semi-volatile)` bootParamSetUsage = ` bootparam set bootflag [options=...] Legal devices are: none : No override force_pxe : Force PXE boot force_disk : Force boot from default Hard-drive force_safe : Force boot from default Hard-drive, request Safe Mode force_diag : Force boot from Diagnostic Partition force_cdrom : Force boot from CD/DVD force_bios : Force boot into BIOS Setup Legal options are: help : print this message PEF : Clear valid bit on reset/power cycle cause by PEF timeout : Automatically clear boot flag valid bit on timeout watchdog: Clear valid bit on reset/power cycle cause by watchdog reset : Clear valid bit on push button reset/soft reset power : Clear valid bit on power up via power push button or wake event Any Option may be prepended with no- to invert sense of operation` ) func NewCmdChassis() *cobra.Command { cmd := &cobra.Command{ Use: "chassis", Short: "chassis", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdChassisStatus()) cmd.AddCommand(NewCmdChassisPolicy()) cmd.AddCommand(NewCmdChassisPower()) cmd.AddCommand(NewCmdChassisCapabilities()) cmd.AddCommand(NewCmdChassisRestartCause()) cmd.AddCommand(NewCmdChassisBootParam()) cmd.AddCommand(NewCmdChassisBootdev()) cmd.AddCommand(NewCmdChassisPoh()) return cmd } func NewCmdChassisStatus() *cobra.Command { cmd := &cobra.Command{ Use: "status", Short: "status", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() status, err := client.GetChassisStatus(ctx) if err != nil { CheckErr(fmt.Errorf("GetChassisStatus failed, err: %w", err)) } fmt.Println(status.Format()) }, } return cmd } func NewCmdChassisPolicy() *cobra.Command { usage := `chassis policy list : return supported policies always-on : turn on when power is restored previous : return to previous state when power is restored always-off : stay off after power is restored` cmd := &cobra.Command{ Use: "policy", Short: "policy", Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { fmt.Println(usage) return } ctx := context.Background() if len(args) >= 1 { switch args[0] { case "list": fmt.Printf("Supported chassis power policy: %s\n", strings.Join(ipmi.SupportedPowerRestorePolicies, " ")) return case "always-on": _, err := client.SetPowerRestorePolicy(ctx, ipmi.PowerRestorePolicyAlwaysOn) if err != nil { CheckErr(fmt.Errorf("SetPowerRestorePolicy failed, err: %w", err)) } case "previous": _, err := client.SetPowerRestorePolicy(ctx, ipmi.PowerRestorePolicyPrevious) if err != nil { CheckErr(fmt.Errorf("SetPowerRestorePolicy failed, err: %w", err)) } case "always-off": _, err := client.SetPowerRestorePolicy(ctx, ipmi.PowerRestorePolicyAlwaysOff) if err != nil { CheckErr(fmt.Errorf("SetPowerRestorePolicy failed, err: %w", err)) } default: fmt.Println(usage) } } }, } return cmd } func NewCmdChassisPower() *cobra.Command { usage := "chassis power Commands: status, on, off, cycle, reset, diag, soft" cmd := &cobra.Command{ Use: "power", Short: "power", Run: func(cmd *cobra.Command, args []string) { var c ipmi.ChassisControl if len(args) == 0 { fmt.Println(usage) return } ctx := context.Background() if len(args) >= 1 { switch args[0] { case "status": status, err := client.GetChassisStatus(ctx) if err != nil { CheckErr(fmt.Errorf("GetChassisStatus failed, err: %w", err)) } powerStatus := "off" if status.PowerIsOn { powerStatus = "on" } fmt.Printf("Chassis Power is %s\n", powerStatus) return case "on": c = ipmi.ChassisControlPowerUp case "off": c = ipmi.ChassisControlPowerDown case "cycle": c = ipmi.ChassisControlPowerCycle case "reset": c = ipmi.ChassisControlHardReset case "diag": c = ipmi.ChassisControlDiagnosticInterrupt case "soft": c = ipmi.ChassisControlSoftShutdown default: CheckErr(errors.New(usage)) return } if _, err := client.ChassisControl(ctx, c); err != nil { CheckErr(fmt.Errorf("ChassisControl failed, err: %w", err)) return } } }, } return cmd } func NewCmdChassisCapabilities() *cobra.Command { usage := "chassis cap Commands: get or set" cmd := &cobra.Command{ Use: "cap", Short: "cap", Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { fmt.Println(usage) return } ctx := context.Background() if len(args) >= 1 { switch args[0] { case "get": cap, err := client.GetChassisCapabilities(ctx) if err != nil { CheckErr(fmt.Errorf("GetChassisCapabilities failed, err: %w", err)) return } fmt.Println(cap.Format()) return case "set": } } }, } return cmd } func NewCmdChassisRestartCause() *cobra.Command { cmd := &cobra.Command{ Use: "restart_cause", Short: "restart_cause", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() res, err := client.GetSystemRestartCause(ctx) if err != nil { CheckErr(fmt.Errorf("GetSystemRestartCause failed, err: %w", err)) } fmt.Println(res.Format()) }, } return cmd } func NewCmdChassisBootParam() *cobra.Command { cmd := &cobra.Command{ Use: "bootparam", Short: "bootparam", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { fmt.Println(bootParamGetUsage) fmt.Println(bootParamSetUsage) return } }, } cmd.AddCommand(NewCmdChassisBootParamGet()) cmd.AddCommand(NewCmdChassisBootParamSet()) return cmd } func NewCmdChassisBootParamGet() *cobra.Command { cmd := &cobra.Command{ Use: "get", Short: "get", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { fmt.Println(bootParamGetUsage) return } ctx := context.Background() paramSelector := args[0] i, err := parseStringToInt64(paramSelector) if err != nil { CheckErr(fmt.Errorf("param %s must be a valid integer in range (0-127), err: %s", paramSelector, err)) } res, err := client.GetSystemBootOptionsParam(ctx, ipmi.BootOptionParamSelector(i), 0x00, 0x00) if err != nil { CheckErr(fmt.Errorf("GetSystemBootOptionsParam failed, err: %w", err)) } fmt.Println(res.Format()) }, } return cmd } func NewCmdChassisBootParamSet() *cobra.Command { cmd := &cobra.Command{ Use: "set", Short: "set", Run: func(cmd *cobra.Command, args []string) { if len(args) < 3 { fmt.Println(bootParamSetUsage) return } paramSelector := args[0] // currently only support set bootflag if paramSelector != "bootflag" { fmt.Println(bootParamSetUsage) return } var f = func(bootDevice string) ipmi.BootDeviceSelector { m := map[string]ipmi.BootDeviceSelector{ "none": ipmi.BootDeviceSelectorNoOverride, "force_pxe": ipmi.BootDeviceSelectorForcePXE, "force_disk": ipmi.BootDeviceSelectorForceHardDrive, "force_safe": ipmi.BootDeviceSelectorForceHardDriveSafe, "force_diag": ipmi.BootDeviceSelectorForceDiagnosticPartition, "force_cdrom": ipmi.BootDeviceSelectorForceCDROM, "force_bios": ipmi.BootDeviceSelectorForceBIOSSetup, } if s, ok := m[bootDevice]; ok { return s } return ipmi.BootDeviceSelectorNoOverride } bootDeviceSelector := f(args[1]) param := &ipmi.BootOptionParam_BootFlags{ BootFlagsValid: true, Persist: false, BIOSBootType: ipmi.BIOSBootTypeLegacy, BootDeviceSelector: bootDeviceSelector, } ctx := context.Background() if err := client.SetSystemBootOptionsParamFor(ctx, param); err != nil { CheckErr(fmt.Errorf("SetSystemBootOptionsFor failed, err: %w", err)) } fmt.Println("Set Succeeded.") }, } return cmd } func NewCmdChassisPoh() *cobra.Command { cmd := &cobra.Command{ Use: "poh", Short: "poh", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() res, err := client.GetPOHCounter(ctx) if err != nil { CheckErr(fmt.Errorf("GetSystemRestartCause failed, err: %w", err)) } fmt.Println(res.Format()) }, } return cmd } func NewCmdChassisBootdev() *cobra.Command { usage := `bootdev [clear-cmos=yes|no] bootdev [options=help,...] none : Do not change boot device order pxe : Force PXE boot disk : Force boot from default Hard-drive safe : Force boot from default Hard-drive, request Safe Mode diag : Force boot from Diagnostic Partition cdrom : Force boot from CD/DVD bios : Force boot into BIOS Setup floppy: Force boot from Floppy/primary removable media` cmd := &cobra.Command{ Use: "bootdev", Short: "bootdev", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { fmt.Println(usage) return } var dev ipmi.BootDeviceSelector switch args[0] { case "none": dev = ipmi.BootDeviceSelectorNoOverride case "pxe": dev = ipmi.BootDeviceSelectorForcePXE case "disk": dev = ipmi.BootDeviceSelectorForceHardDrive case "safe": dev = ipmi.BootDeviceSelectorForceHardDriveSafe case "diag": dev = ipmi.BootDeviceSelectorForceDiagnosticPartition case "cdrom": dev = ipmi.BootDeviceSelectorForceCDROM case "floppy": dev = ipmi.BootDeviceSelectorForceFloppy case "bios": dev = ipmi.BootDeviceSelectorForceBIOSSetup default: return } bootFlags := &ipmi.BootOptionParam_BootFlags{ BootDeviceSelector: dev, } if len(args) > 1 { var optionsStr string if args[1] == "clear-cmos=yes" { optionsStr = "clear-cmos" } else if strings.HasPrefix(args[1], "options=") { optionsStr = strings.TrimPrefix(args[1], "options=") } options := strings.Split(optionsStr, ",") for _, option := range options { if option == "help" { fmt.Println(bootFlags.OptionsHelp()) return } } if err := bootFlags.ParseFromOptions(options); err != nil { CheckErr(fmt.Errorf("ParseFromOptions failed, err: %w", err)) return } } ctx := context.Background() if err := client.SetBootParamBootFlags(ctx, bootFlags); err != nil { CheckErr(fmt.Errorf("SetBootParamBootFlags failed, err: %w", err)) } fmt.Printf("Set Boot Device to %s\n", args[0]) }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/dcmi.go000066400000000000000000000350231474110527100242040ustar00rootroot00000000000000package commands import ( "context" "fmt" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) func NewCmdDCMI() *cobra.Command { cmd := &cobra.Command{ Use: "dcmi", Short: "dcmi", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { cmd.Help() return } subcmd := args[0] if !contains([]string{ "power", "asset_tag", "set_asset_tag", "discover", "get_conf_param", "get_mc_id_string", "set_mc_id_string", "thermalpolicy", }, subcmd) { fmt.Printf("unknown dcmi subcommand (%s)\n", subcmd) cmd.Help() return } }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdDCMIPower()) cmd.AddCommand(NewCmdDCMIAssetTag()) cmd.AddCommand(NewCmdDCMISetAssetTag()) cmd.AddCommand(NewCmdDCMIDiscover()) cmd.AddCommand(NewCmdDCMIGetConfigParam()) cmd.AddCommand(NewCmdDCMISensors()) cmd.AddCommand(NewCmdDCMIGetMCIDString()) cmd.AddCommand(NewCmdDCMISetMCIDString()) cmd.AddCommand(NewCmdDCMIThermalPolicy()) cmd.AddCommand(NewCmdDCMIGetTempReading()) return cmd } func contains(s []string, e string) bool { for _, a := range s { if a == e { return true } } return false } func NewCmdDCMIDiscover() *cobra.Command { cmd := &cobra.Command{ Use: "discover", Short: "discover", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() dcmiCapParams, err := client.GetDCMICapParams(ctx) if err != nil { CheckErr(fmt.Errorf("GetDCMICapParams failed, err: %w", err)) } fmt.Println(dcmiCapParams.Format()) }, } return cmd } func NewCmdDCMIGetConfigParam() *cobra.Command { cmd := &cobra.Command{ Use: "get_conf_param", Short: "get_conf_param", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() dcmiConfigParams, err := client.GetDCMIConfigParams(ctx) if err != nil { CheckErr(fmt.Errorf("GetDCMIConfigParams failed, err: %w", err)) } fmt.Println(dcmiConfigParams.Format()) }, } return cmd } func NewCmdDCMIPower() *cobra.Command { cmd := &cobra.Command{ Use: "power", Short: "power", Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { cmd.Help() } }, } cmd.AddCommand(newCmdDCMIPowerRead()) cmd.AddCommand(newCmdDCMIPowerGetLimit()) cmd.AddCommand(newCmdDCMIPowerSetLimit()) cmd.AddCommand(newCmdDCMIPowerActivate()) cmd.AddCommand(newCmdDCMIPowerDeactivate()) return cmd } func newCmdDCMIPowerRead() *cobra.Command { cmd := &cobra.Command{ Use: "reading", Short: "reading", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() resp, err := client.GetDCMIPowerReading(ctx) if err != nil { CheckErr(fmt.Errorf("GetDCMIPowerReading failed, err: %w", err)) } fmt.Println(resp.Format()) }, } return cmd } func newCmdDCMIPowerGetLimit() *cobra.Command { cmd := &cobra.Command{ Use: "get_limit", Short: "get_limit", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() resp, err := client.GetDCMIPowerLimit(ctx) if err != nil { CheckErr(fmt.Errorf("GetDCMIPowerLimit failed, err: %w", err)) } fmt.Println(resp.Format()) }, } return cmd } func newCmdDCMIPowerSetLimit() *cobra.Command { cmd := &cobra.Command{ Use: `set_limit set_limit action limit correction sample `, Short: "set_limit", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { cmd.Help() return } param := args[0] value := args[1] if !contains([]string{"action", "limit", "correction", "sample"}, param) { cmd.Help() return } ctx := context.Background() req := &ipmi.SetDCMIPowerLimitRequest{} { resp, err := client.GetDCMIPowerLimit(ctx) if err != nil { CheckErr(fmt.Errorf("GetDCMIPowerLimit failed, err: %w", err)) } req.ExceptionAction = resp.ExceptionAction req.PowerLimitRequested = resp.PowerLimitRequested req.CorrectionTimeLimitMilliSec = resp.CorrectionTimeLimitMilliSec req.StatisticsSamplingPeriodSec = resp.StatisticsSamplingPeriodSec } switch param { case "action": if value == "no_action" { req.ExceptionAction = ipmi.DCMIExceptionAction_NoAction } else if value == "sel_logging" { req.ExceptionAction = ipmi.DCMIExceptionAction_LogSEL } else if value == "power_off" { req.ExceptionAction = ipmi.DCMIExceptionAction_PowerOffAndLogSEL } else { CheckErr(fmt.Errorf("invalid value for parameter action: %s", value)) } case "limit": limit, err := parseStringToInt64(value) if err != nil { CheckErr(fmt.Errorf("invalid value for parameter limit: %s", value)) } req.PowerLimitRequested = uint16(limit) case "correction": correction, err := parseStringToInt64(value) if err != nil { CheckErr(fmt.Errorf("invalid value for parameter correction: %s", value)) } req.CorrectionTimeLimitMilliSec = uint32(correction) case "sample": sample, err := parseStringToInt64(value) if err != nil { CheckErr(fmt.Errorf("invalid value for parameter sample: %s", value)) } req.StatisticsSamplingPeriodSec = uint16(sample) default: CheckErr(fmt.Errorf("invalid parameter: %s", param)) } _, err := client.SetDCMIPowerLimit(ctx, req) if err != nil { CheckErr(fmt.Errorf("SetDCMIPowerLimit failed, err: %w", err)) } resp, err := client.GetDCMIPowerLimit(ctx) if err != nil { CheckErr(fmt.Errorf("GetDCMIPowerLimit failed, err: %w", err)) } fmt.Println(resp.Format()) }, } return cmd } func newCmdDCMIPowerActivate() *cobra.Command { cmd := &cobra.Command{ Use: "activate", Short: "activate", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() _, err := client.ActivateDCMIPowerLimit(ctx, true) if err != nil { CheckErr(fmt.Errorf("ActivateDCMIPowerLimit (activate) failed, err: %w", err)) } fmt.Println("Power limit successfully activated") }, } return cmd } func newCmdDCMIPowerDeactivate() *cobra.Command { cmd := &cobra.Command{ Use: "deactivate", Short: "deactivate", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() _, err := client.ActivateDCMIPowerLimit(ctx, false) if err != nil { CheckErr(fmt.Errorf("ActivateDCMIPowerLimit (deactivate) failed, err: %w", err)) } fmt.Println("Power limit successfully deactivated") }, } return cmd } func NewCmdDCMIAssetTag() *cobra.Command { cmd := &cobra.Command{ Use: "asset_tag", Short: "asset_tag", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() assetTagRaw, typeLength, err := client.GetDCMIAssetTagFull(ctx) if err != nil { CheckErr(fmt.Errorf("GetDCMIAssetTagFull failed, err: %w", err)) } assetTag, err := typeLength.Chars(assetTagRaw) if err != nil { CheckErr(fmt.Errorf("convert raw to chars failed, err: %w", err)) } fmt.Printf("Asset tag: %s\nTypeLength: %s\n", assetTag, typeLength) }, } return cmd } func NewCmdDCMISetAssetTag() *cobra.Command { cmd := &cobra.Command{ Use: "set_asset_tag [asset_tag]", Short: "set_asset_tag", Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { cmd.Help() return } var assetTag = []byte(args[0]) ctx := context.Background() if err := client.SetDCMIAssetTagFull(ctx, assetTag); err != nil { CheckErr(fmt.Errorf("SetDCMIAssetTagFull failed, err: %w", err)) } }, } return cmd } func NewCmdDCMISensors() *cobra.Command { cmd := &cobra.Command{ Use: "sensors", Short: "sensors", Run: func(cmd *cobra.Command, args []string) { const EntityID_DCMI_Inlet ipmi.EntityID = 0x40 const EntityID_DCMI_CPU ipmi.EntityID = 0x41 const EntityID_DCMI_Baseboard ipmi.EntityID = 0x42 ctx := context.Background() { sdrs, err := client.GetDCMISensors(ctx, EntityID_DCMI_Inlet) if err != nil { CheckErr(fmt.Errorf("GetDCMISensors for entityID (%#02x) failed, err: %s", EntityID_DCMI_Inlet, err)) } fmt.Printf("Inlet: %d temperature sensors found\n", len(sdrs)) if len(sdrs) > 0 { fmt.Println(ipmi.FormatSDRs(sdrs)) } } { sdrs, err := client.GetDCMISensors(ctx, EntityID_DCMI_CPU) if err != nil { CheckErr(fmt.Errorf("GetDCMISensors for entityID (%#02x) failed, err: %s", EntityID_DCMI_Inlet, err)) } fmt.Printf("CPU: %d temperature sensors found\n", len(sdrs)) if len(sdrs) > 0 { fmt.Println(ipmi.FormatSDRs(sdrs)) } } { sdrs, err := client.GetDCMISensors(ctx, EntityID_DCMI_Baseboard) if err != nil { CheckErr(fmt.Errorf("GetDCMISensors for entityID (%#02x) failed, err: %s", EntityID_DCMI_Inlet, err)) } fmt.Printf("Baseboard: %d temperature sensors found\n", len(sdrs)) if len(sdrs) > 0 { fmt.Println(ipmi.FormatSDRs(sdrs)) } } }, } return cmd } func NewCmdDCMIGetMCIDString() *cobra.Command { cmd := &cobra.Command{ Use: "get_mc_id_string", Short: "get_mc_id_string", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() id, err := client.GetDCMIMgmtControllerIdentifierFull(ctx) if err != nil { CheckErr(fmt.Errorf("GetDCMIMgmtControllerIdentifierFull failed, err: %w", err)) } fmt.Printf("Management Controller Identifier String: %s\n", id) }, } return cmd } func NewCmdDCMISetMCIDString() *cobra.Command { cmd := &cobra.Command{ Use: "set_mc_id_string [id_str]", Short: "set_mc_id_string", Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { cmd.Help() return } var idStr = []byte(args[0]) ctx := context.Background() if err := client.SetDCMIMgmtControllerIdentifierFull(ctx, idStr); err != nil { CheckErr(fmt.Errorf("SetDCMIMgmtControllerIdentifierFull failed, err: %w", err)) } }, } return cmd } func NewCmdDCMIThermalPolicy() *cobra.Command { cmd := &cobra.Command{ Use: "thermalpolicy", Short: "thermalpolicy", Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { cmd.Help() } }, } cmd.AddCommand(newCmdDCMIThermalPolicyGet()) cmd.AddCommand(newCmdDCMIThermalPolicySet()) return cmd } func newCmdDCMIThermalPolicyGet() *cobra.Command { cmd := &cobra.Command{ Use: "get ", Short: "get", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { cmd.Help() return } entityID, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("parse entityID (%s) failed, err: %s", args[0], err)) } entityInstance, err := parseStringToInt64(args[1]) if err != nil { CheckErr(fmt.Errorf("parse entityInstance (%s) failed, err: %s", args[1], err)) } ctx := context.Background() resp, err := client.GetDCMIThermalLimit(ctx, ipmi.EntityID(entityID), ipmi.EntityInstance(entityInstance)) if err != nil { CheckErr(fmt.Errorf("GetDCMIThermalLimit failed, err: %w", err)) } fmt.Println(resp.Format()) }, } return cmd } func newCmdDCMIThermalPolicySet() *cobra.Command { cmd := &cobra.Command{ Use: `set thermalpolicy instance parameters: valid volatile parameters: valid poweroff parameters: valid sel parameters: volatile Current Power Cycle nonvolatile Set across power cycles poweroff Hard Power Off system nopoweroff No 'Hard Power Off' action sel Log event to SEL nosel No 'Log event to SEL' action disabled Disabled`, Short: "set", Run: func(cmd *cobra.Command, args []string) { if len(args) < 7 { cmd.Help() return } entityID, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("parse entityID (%s) failed, err: %s", args[0], err)) } entityInstance, err := parseStringToInt64(args[1]) if err != nil { CheckErr(fmt.Errorf("parse entityInstance (%s) failed, err: %s", args[1], err)) } var powerOff bool powerParam := args[3] switch powerParam { case "poweroff": powerOff = true case "nopoweroff", "disabled": powerOff = false case "default": CheckErr(fmt.Errorf("invalid poweroff parameter: %s", powerParam)) } var sel bool selParam := args[4] switch selParam { case "sel": sel = true case "nosel", "disabled": sel = false case "default": CheckErr(fmt.Errorf("invalid sel parameter: %s", selParam)) } temperatureLimit, err := parseStringToInt64(args[5]) if err != nil { CheckErr(fmt.Errorf("parse temperatureLimit (%s) failed, err: %s", args[5], err)) } exceptionTime, err := parseStringToInt64(args[6]) if err != nil { CheckErr(fmt.Errorf("parse exceptionTime (%s) failed, err: %s", args[6], err)) } req := &ipmi.SetDCMIThermalLimitRequest{ EntityID: ipmi.EntityID(entityID), EntityInstance: ipmi.EntityInstance(entityInstance), ExceptionAction_PowerOffAndLogSEL: powerOff, ExceptionAction_LogSELOnly: sel, TemperatureLimit: uint8(temperatureLimit), ExceptionTimeSec: uint16(exceptionTime), } ctx := context.Background() if _, err := client.SetDCMIThermalLimit(ctx, req); err != nil { CheckErr(fmt.Errorf("SetDCMIThermalLimit failed, err: %w", err)) } fmt.Println("SetDCMIThermalLimit succeeded:") }, } return cmd } func NewCmdDCMIGetTempReading() *cobra.Command { cmd := &cobra.Command{ Use: "get_temp_reading", Short: "get_temp_reading", Run: func(cmd *cobra.Command, args []string) { const EntityID_DCMI_Inlet ipmi.EntityID = 0x40 const EntityID_DCMI_CPU ipmi.EntityID = 0x41 const EntityID_DCMI_Baseboard ipmi.EntityID = 0x42 ctx := context.Background() readings, err := client.GetDCMITemperatureReadingsForEntities(ctx, EntityID_DCMI_Inlet, EntityID_DCMI_CPU, EntityID_DCMI_Baseboard) if err != nil { CheckErr(fmt.Errorf("GetDCMISensors for entityID (%#02x) failed, err: %s", EntityID_DCMI_Inlet, err)) } fmt.Printf("Got: %d temperature readings found\n", len(readings)) fmt.Println(ipmi.FormatDCMITemperatureReadings(readings)) }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/fru.go000066400000000000000000000023071474110527100240630ustar00rootroot00000000000000package commands import ( "context" "fmt" "github.com/spf13/cobra" ) func NewCmdFRU() *cobra.Command { cmd := &cobra.Command{ Use: "fru", Short: "fru", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdFRUPrint()) return cmd } func NewCmdFRUPrint() *cobra.Command { cmd := &cobra.Command{ Use: "print", Short: "print", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() if len(args) < 1 { frus, err := client.GetFRUs(ctx) if err != nil { CheckErr(fmt.Errorf("GetFRUs failed, err: %w", err)) } for _, fru := range frus { fmt.Println(fru.String()) } } else { id, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid FRU Device ID passed, err: %w", err)) } fruID := uint8(id) fru, err := client.GetFRU(ctx, fruID, "") if err != nil { CheckErr(fmt.Errorf("GetFRU failed, err: %w", err)) } fmt.Println(fru.String()) } }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/helper.go000066400000000000000000000027201474110527100245450ustar00rootroot00000000000000package commands import ( "bytes" "fmt" "os" "strings" "github.com/olekukonko/tablewriter" ) const ( DefaultErrorExitCode = 1 ) // ErrExit may be passed to CheckErr to instruct it to output nothing but exit with status code 1. var ErrExit = fmt.Errorf("exit") func CheckErr(err error) { checkErr(err, fatalErrHandler) } // checkErr formats a given error as a string and calls the passed handleErr // func with that string and an exit code. func checkErr(err error, handleErr func(string, int)) { if err == nil { return } switch { case err == ErrExit: handleErr("", DefaultErrorExitCode) default: switch err := err.(type) { // other err type, can return different code default: msg := err.Error() if !strings.HasPrefix(msg, "error: ") { msg = fmt.Sprintf("error: %s", msg) } handleErr(msg, DefaultErrorExitCode) } } } var fatalErrHandler = fatal // fatal prints the message (if provided) and then exits. func fatal(msg string, code int) { if len(msg) > 0 { // add newline if needed if !strings.HasSuffix(msg, "\n") { msg += "\n" } fmt.Fprint(os.Stderr, msg) } os.Exit(code) } func formatTable(headers []string, rows [][]string) string { var buf = new(bytes.Buffer) table := tablewriter.NewWriter(buf) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetHeader(headers) table.SetFooter(headers) for _, row := range rows { table.Append(row) } table.Render() return buf.String() } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/lan.go000066400000000000000000000043101474110527100240350ustar00rootroot00000000000000package commands import ( "context" "fmt" "github.com/spf13/cobra" ) func NewCmdLan() *cobra.Command { cmd := &cobra.Command{ Use: "lan", Short: "lan", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdLanStats()) cmd.AddCommand(NewCmdLanPrint()) return cmd } func NewCmdLanStats() *cobra.Command { usage := ` stats get [] stats clear [] ` cmd := &cobra.Command{ Use: "stats", Short: "stats", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { CheckErr(fmt.Errorf("usage: %s", usage)) } action := args[0] id, err := parseStringToInt64(args[1]) if err != nil { CheckErr(fmt.Errorf("invalid channel number passed, err: %w", err)) } channelNumber := uint8(id) ctx := context.Background() switch action { case "get": res, err := client.GetIPStatistics(ctx, channelNumber, false) if err != nil { CheckErr(fmt.Errorf("GetIPStatistics failed, err: %w", err)) } fmt.Println(res.Format()) case "clear": res, err := client.GetIPStatistics(ctx, channelNumber, true) if err != nil { CheckErr(fmt.Errorf("GetIPStatistics failed, err: %w", err)) } fmt.Println(res.Format()) default: CheckErr(fmt.Errorf("usage: %s", usage)) } }, } return cmd } func NewCmdLanPrint() *cobra.Command { usage := ` print [] ` cmd := &cobra.Command{ Use: "print", Short: "print", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(fmt.Errorf("usage: %s", usage)) } id, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid channel number passed, err: %w", err)) } channelNumber := uint8(id) ctx := context.Background() lanConfig, err := client.GetLanConfigParams(ctx, channelNumber) if err != nil { CheckErr(fmt.Errorf("GetLanConfigParams failed, err: %w", err)) } client.Debug("Lan Config", lanConfig) fmt.Println(lanConfig.Format()) }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/mc.go000066400000000000000000000066041474110527100236720ustar00rootroot00000000000000package commands import ( "context" "fmt" "github.com/spf13/cobra" ) func NewCmdMC() *cobra.Command { cmd := &cobra.Command{ Use: "mc", Short: "mc", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdMCInfo()) cmd.AddCommand(NewCmdMCReset()) cmd.AddCommand(NewCmdMC_ACPI()) cmd.AddCommand(NewCmdMC_GUID()) cmd.AddCommand(NewCmdMC_Watchdog()) return cmd } func NewCmdMCInfo() *cobra.Command { cmd := &cobra.Command{ Use: "info", Short: "info", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() res, err := client.GetDeviceID(ctx) if err != nil { CheckErr(fmt.Errorf("GetDeviceID failed, err: %w", err)) } fmt.Println(res.Format()) }, } return cmd } func NewCmdMCReset() *cobra.Command { usage := "reset " cmd := &cobra.Command{ Use: "reset", Short: "reset", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(fmt.Errorf("usage: %s", usage)) } ctx := context.Background() switch args[0] { case "warm": if err := client.WarmReset(ctx); err != nil { CheckErr(fmt.Errorf("WarmReset failed, err: %w", err)) } case "cold": if err := client.ColdReset(ctx); err != nil { CheckErr(fmt.Errorf("ColdReset failed, err: %w", err)) } default: CheckErr(fmt.Errorf("usage: %s", usage)) } }, } return cmd } func NewCmdMC_ACPI() *cobra.Command { usage := "acpi " cmd := &cobra.Command{ Use: "acpi", Short: "acpi", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(fmt.Errorf("usage: %s", usage)) } ctx := context.Background() switch args[0] { case "get": res, err := client.GetACPIPowerState(ctx) if err != nil { CheckErr(fmt.Errorf("GetACPIPowerState failed, err: %w", err)) } fmt.Println(res.Format()) case "set": // default: CheckErr(fmt.Errorf("usage: %s", usage)) } }, } return cmd } func NewCmdMC_GUID() *cobra.Command { cmd := &cobra.Command{ Use: "guid", Short: "guid", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() res, err := client.GetSystemGUID(ctx) if err != nil { CheckErr(fmt.Errorf("GetSystemGUID failed, err: %w", err)) } fmt.Println(res.Format()) }, } return cmd } func NewCmdMC_Watchdog() *cobra.Command { usage := `watchdog get : Get Current Watchdog settings reset : Restart Watchdog timer based on most recent settings off : Shut off a running Watchdog timer ` cmd := &cobra.Command{ Use: "watchdog", Short: "watchdog", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(fmt.Errorf("usage: %s", usage)) } ctx := context.Background() switch args[0] { case "get": res, err := client.GetWatchdogTimer(ctx) if err != nil { CheckErr(fmt.Errorf("GetWatchdogTimer failed, err: %w", err)) } fmt.Println(res.Format()) case "reset": if _, err := client.ResetWatchdogTimer(ctx); err != nil { CheckErr(fmt.Errorf("ResetWatchdogTimer failed, err: %w", err)) } case "off": // default: CheckErr(fmt.Errorf("usage: %s", usage)) } }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/pef.go000066400000000000000000000147171474110527100240510ustar00rootroot00000000000000package commands import ( "context" "fmt" "strconv" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) func NewCmdPEF() *cobra.Command { cmd := &cobra.Command{ Use: "pef", Short: "pef", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { cmd.Help() return } if !contains([]string{ "capabilities", "status", "filter", "info", "policy", }, args[1]) { cmd.Help() return } }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdPEFCapabilities()) cmd.AddCommand(NewCmdPEFStatus()) cmd.AddCommand(NewCmdPEFFilter()) cmd.AddCommand(NewCmdPEFInfo()) cmd.AddCommand(NewCmdPEFPolicy()) return cmd } func NewCmdPEFCapabilities() *cobra.Command { cmd := &cobra.Command{ Use: "capabilities", Short: "capabilities", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() res, err := client.GetPEFCapabilities(ctx) if err != nil { CheckErr(fmt.Errorf("GetPEFCapabilities failed, err: %w", err)) } fmt.Println(res.Format()) }, } return cmd } func NewCmdPEFStatus() *cobra.Command { cmd := &cobra.Command{ Use: "status", Short: "status", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() { res, err := client.GetLastProcessedEventId(ctx) if err != nil { CheckErr(fmt.Errorf("GetLastProcessedEventId failed, err: %w", err)) } fmt.Println(res.Format()) } { param := &ipmi.PEFConfigParam_Control{} if err := client.GetPEFConfigParamFor(ctx, param); err != nil { CheckErr(fmt.Errorf("GetLastProcessedEventId failed, err: %w", err)) } fmt.Println(param.Format()) } { param := &ipmi.PEFConfigParam_ActionGlobalControl{} if err := client.GetPEFConfigParamFor(ctx, param); err != nil { CheckErr(fmt.Errorf("GetLastProcessedEventId failed, err: %w", err)) } fmt.Println(param.Format()) } }, } return cmd } func NewCmdPEFFilter() *cobra.Command { cmd := &cobra.Command{ Use: "filter", Short: "filter", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { cmd.Help() } }, } cmd.AddCommand(NewCmdPEFFilterList()) return cmd } func NewCmdPEFFilterList() *cobra.Command { cmd := &cobra.Command{ Use: "list", Short: "list", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() var numberOfEventFilters uint8 { param := &ipmi.PEFConfigParam_EventFiltersCount{} if err := client.GetPEFConfigParamFor(ctx, param); err != nil { CheckErr(fmt.Errorf("get number of event filters failed, err: %w", err)) } numberOfEventFilters = param.Value } var eventFilters = make([]*ipmi.PEFEventFilter, numberOfEventFilters) for i := uint8(0); i < numberOfEventFilters; i++ { // 1-based filterNumber := i + 1 param := &ipmi.PEFConfigParam_EventFilter{ SetSelector: filterNumber, } if err := client.GetPEFConfigParamFor(ctx, param); err != nil { CheckErr(fmt.Errorf("get event filter entry %d failed, err: %s", filterNumber, err)) } eventFilters[i] = param.Filter } fmt.Println(ipmi.FormatEventFilters(eventFilters)) }, } return cmd } func NewCmdPEFInfo() *cobra.Command { cmd := &cobra.Command{ Use: "info", Short: "info", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() { param := &ipmi.PEFConfigParam_SystemGUID{} if err := client.GetPEFConfigParamFor(ctx, param); err != nil { CheckErr(err) } fmt.Println(param.Format()) if !param.UseGUID { res, err := client.GetSystemGUID(ctx) if err != nil { CheckErr(err) } fmt.Println(ipmi.FormatGUIDDetails(res.GUID)) } } { param := &ipmi.PEFConfigParam_AlertPoliciesCount{} if err := client.GetPEFConfigParamFor(ctx, param); err != nil { CheckErr(err) } fmt.Println(param.Format()) } { res, err := client.GetPEFCapabilities(ctx) if err != nil { CheckErr(err) } fmt.Println(res.Format()) } }, } return cmd } func NewCmdPEFPolicy() *cobra.Command { cmd := &cobra.Command{ Use: "policy", Short: "policy", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { cmd.Help() } }, } cmd.AddCommand(NewCmdPEFPolicyList()) return cmd } func NewCmdPEFPolicyList() *cobra.Command { cmd := &cobra.Command{ Use: "list", Short: "list", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() numberOfAlertPolicies := uint8(0) { param := &ipmi.PEFConfigParam_AlertPoliciesCount{} if err := client.GetPEFConfigParamFor(ctx, param); err != nil { CheckErr(err) } numberOfAlertPolicies = param.Value } { headers := []string{ "Entry", "PolicyNumber", "PolicyState", "PolicyAction", "Channel", "ChannelMedium", "Destination", "IsEventSpecific", "AlertStringKey", } rows := make([][]string, numberOfAlertPolicies) for i := uint8(0); i < numberOfAlertPolicies; i++ { entry := i + 1 param := &ipmi.PEFConfigParam_AlertPolicy{ SetSelector: entry, } if err := client.GetPEFConfigParamFor(ctx, param); err != nil { CheckErr(fmt.Errorf("get alert policy number (%d) failed, err: %s", entry, err)) } alertPolicy := param.Policy channelNumber := param.Policy.ChannelNumber resp, err := client.GetChannelInfo(ctx, channelNumber) if err != nil { CheckErr(fmt.Errorf("get channel info (%d) failed, err: %s", channelNumber, err)) } // Todo Get Lan Config Param // if resp.ChannelMedium == ipmi.ChannelMediumLAN { // Number of Destinations : 0x11 (17) // Destination Type : 0x12 (18) // Community String : 0x10 (16) // Destination Address: 0x13 (19) // } row := []string{ strconv.Itoa(int(entry)), fmt.Sprintf("%d", alertPolicy.PolicyNumber), fmt.Sprintf("%v", alertPolicy.PolicyState), alertPolicy.PolicyAction.ShortString(), fmt.Sprintf("%d", alertPolicy.ChannelNumber), resp.ChannelMedium.String(), fmt.Sprintf("%d", alertPolicy.Destination), fmt.Sprintf("%v", alertPolicy.IsEventSpecific), fmt.Sprintf("%d", alertPolicy.AlertStringKey), } rows[i] = row } fmt.Println(formatTable(headers, rows)) } }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/root.go000066400000000000000000000072001474110527100242470ustar00rootroot00000000000000package commands import ( "context" "flag" "fmt" "strings" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) const homePage = "https://github.com/bougou/go-ipmi" var ( host string port int username string password string intf string debug bool privilegeLevel string showVersion bool client *ipmi.Client ) func initClient() error { if debug { fmt.Printf("Version: %s\n", Version) fmt.Printf("Commit: %s\n", Commit) fmt.Printf("BuildAt: %s\n", BuildAt) } switch intf { case "", "open": c, err := ipmi.NewOpenClient() if err != nil { return fmt.Errorf("create open client failed, err: %w", err) } client = c case "lan", "lanplus": c, err := ipmi.NewClient(host, port, username, password) if err != nil { return fmt.Errorf("create lan or lanplus client failed, err: %w", err) } client = c case "tool": c, err := ipmi.NewToolClient(host) if err != nil { return fmt.Errorf("create client based on ipmitool (%s) failed, err: %s", host, err) } client = c } client.WithDebug(debug) client.WithInterface(ipmi.Interface(intf)) var privLevel ipmi.PrivilegeLevel = ipmi.PrivilegeLevelUnspecified switch strings.ToUpper(privilegeLevel) { case "CALLBACK": privLevel = ipmi.PrivilegeLevelCallback case "USER": privLevel = ipmi.PrivilegeLevelUser case "OPERATOR": privLevel = ipmi.PrivilegeLevelOperator case "ADMINISTRATOR": privLevel = ipmi.PrivilegeLevelAdministrator } if privLevel != ipmi.PrivilegeLevelUnspecified { client.WithMaxPrivilegeLevel(privLevel) } ctx := context.Background() if err := client.Connect(ctx); err != nil { return fmt.Errorf("client connect failed, err: %w", err) } return nil } func closeClient() error { ctx := context.Background() if err := client.Close(ctx); err != nil { return fmt.Errorf("close client failed, err: %w", err) } return nil } func NewRootCommand() *cobra.Command { rootCmd := &cobra.Command{ Use: "goipmi", Short: "goipmi", Long: fmt.Sprintf("goipmi\n\nFind more information at: %s\n\n", homePage), PersistentPreRunE: func(cmd *cobra.Command, args []string) error { if showVersion { fmt.Printf("Version: %s\n", Version) fmt.Printf("Commit: %s\n", Commit) fmt.Printf("BuildAt: %s\n", BuildAt) } return nil }, Run: func(cmd *cobra.Command, args []string) { }, } rootCmd.PersistentFlags().StringVarP(&host, "host", "H", "", "host") rootCmd.PersistentFlags().IntVarP(&port, "port", "p", 623, "port") rootCmd.PersistentFlags().StringVarP(&username, "user", "U", "", "username") rootCmd.PersistentFlags().StringVarP(&password, "pass", "P", "", "password") rootCmd.PersistentFlags().StringVarP(&intf, "interface", "I", "open", "interface, supported (open,lan,lanplus)") rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "debug") rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "V", false, "version") rootCmd.PersistentFlags().StringVarP(&privilegeLevel, "priv-level", "L", "ADMINISTRATOR", "Force session privilege level. Can be CALLBACK, USER, OPERATOR, ADMINISTRATOR.") rootCmd.Flags().AddGoFlagSet(flag.CommandLine) rootCmd.AddCommand(NewCmdMC()) rootCmd.AddCommand(NewCmdSEL()) rootCmd.AddCommand(NewCmdSDR()) rootCmd.AddCommand(NewCmdChassis()) rootCmd.AddCommand(NewCmdChannel()) rootCmd.AddCommand(NewCmdLan()) rootCmd.AddCommand(NewCmdUser()) rootCmd.AddCommand(NewCmdSession()) rootCmd.AddCommand(NewCmdSensor()) rootCmd.AddCommand(NewCmdFRU()) rootCmd.AddCommand(NewCmdSOL()) rootCmd.AddCommand(NewCmdPEF()) rootCmd.AddCommand(NewCmdDCMI()) rootCmd.AddCommand(NewCmdX()) rootCmd.SilenceUsage = true rootCmd.SilenceErrors = true return rootCmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/sdr.go000066400000000000000000000142561474110527100240650ustar00rootroot00000000000000package commands import ( "context" "fmt" "strconv" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) func NewCmdSDR() *cobra.Command { cmd := &cobra.Command{ Use: "sdr", Short: "sdr", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { fmt.Println("sdr ...") }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdSDRInfo()) cmd.AddCommand(NewCmdSDRGet()) cmd.AddCommand(NewCmdSDRList()) cmd.AddCommand(NewCmdSDRType()) return cmd } func NewCmdSDRInfo() *cobra.Command { cmd := &cobra.Command{ Use: "info", Short: "info", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() sdrRepoInfo, err := client.GetSDRRepoInfo(ctx) if err != nil { CheckErr(fmt.Errorf("GetSDRRepoInfo failed, err: %w", err)) } fmt.Println(sdrRepoInfo.Format()) }, } return cmd } func parseStringToInt64(s string) (int64, error) { if len(s) > 2 { if s[0] == '0' { return strconv.ParseInt(s, 0, 64) } } return strconv.ParseInt(s, 10, 64) } func NewCmdSDRGet() *cobra.Command { usage := `sdr get or , sensorName should be quoted if contains space` cmd := &cobra.Command{ Use: "get", Short: "get", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(fmt.Errorf("no Sensor ID or Sensor Name supplied, usage: %s", usage)) } ctx := context.Background() var sdr *ipmi.SDR var err error id, err := parseStringToInt64(args[0]) if err != nil { // suppose args is sensor name sdr, err = client.GetSDRBySensorName(ctx, args[0]) if err != nil { CheckErr(fmt.Errorf("GetSDRBySensorName failed, err: %w", err)) } } else { sensorID := uint8(id) sdr, err = client.GetSDRBySensorID(ctx, sensorID) if err != nil { CheckErr(fmt.Errorf("GetSDRBySensorID failed, err: %w", err)) } } client.Debug("SDR", sdr) fmt.Println(sdr) }, } return cmd } func NewCmdSDRType() *cobra.Command { sensorTypesText := ` Sensor Types: Temperature (0x01) Voltage (0x02) Current (0x03) Fan (0x04) Physical Security (0x05) Platform Security (0x06) Processor (0x07) Power Supply (0x08) Power Unit (0x09) Cooling Device (0x0a) Other (0x0b) Memory (0x0c) Drive Slot / Bay (0x0d) POST Memory Resize (0x0e) System Firmwares (0x0f) Event Logging Disabled (0x10) Watchdog1 (0x11) System Event (0x12) Critical Interrupt (0x13) Button (0x14) Module / Board (0x15) Microcontroller (0x16) Add-in Card (0x17) Chassis (0x18) Chip Set (0x19) Other FRU (0x1a) Cable / Interconnect (0x1b) Terminator (0x1c) System Boot Initiated (0x1d) Boot Error (0x1e) OS Boot (0x1f) OS Critical Stop (0x20) Slot / Connector (0x21) System ACPI Power State (0x22) Watchdog2 (0x23) Platform Alert (0x24) Entity Presence (0x25) Monitor ASIC (0x26) LAN (0x27) Management Subsys Health (0x28) Battery (0x29) Session Audit (0x2a) Version Change (0x2b) FRU State (0x2c) ` // usage := `sdr type [all||]` cmd := &cobra.Command{ Use: "type", Short: "type", Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { fmt.Println(sensorTypesText) return } if len(args) >= 1 { ctx := context.Background() if args[0] == "all" { sensors, err := client.GetSensors(ctx) if err != nil { fmt.Printf("failed to get all sensors: %s", err) return } fmt.Println(ipmi.FormatSensors(true, sensors...)) return } sensorType, err := ipmi.SensorTypeFromNameOrNumber(args[0]) if err != nil { fmt.Printf("invalid sensor type: %s", args[0]) return } sensors, err := client.GetSensors(ctx, ipmi.SensorFilterOptionIsSensorType(sensorType)) if err != nil { fmt.Printf("failed to get (%s) sensors: %s", sensorType, err) return } fmt.Println(ipmi.FormatSensors(true, sensors...)) } }, } return cmd } func NewCmdSDRList() *cobra.Command { usage := `sdr list ` cmd := &cobra.Command{ Use: "list", Short: "list", Run: func(cmd *cobra.Command, args []string) { recordTypes := []ipmi.SDRRecordType{} // default only get Full and Compact SDR if len(args) == 0 { recordTypes = append(recordTypes, ipmi.SDRRecordTypeFullSensor, ipmi.SDRRecordTypeCompactSensor) } ctx := context.Background() if len(args) >= 1 { switch args[0] { case "all": // no filter, recordTypes is empty. case "full": recordTypes = append(recordTypes, ipmi.SDRRecordTypeFullSensor) case "compact": recordTypes = append(recordTypes, ipmi.SDRRecordTypeCompactSensor) case "event": recordTypes = append(recordTypes, ipmi.SDRRecordTypeEventOnly) case "mcloc": recordTypes = append(recordTypes, ipmi.SDRRecordTypeManagementControllerDeviceLocator) case "fru": recordTypes = append(recordTypes, ipmi.SDRRecordTypeFRUDeviceLocator) sdrs, err := client.GetSDRs(ctx, recordTypes...) if err != nil { CheckErr(fmt.Errorf("GetSDRs failed, err: %w", err)) } fmt.Println(ipmi.FormatSDRs_FRU(sdrs)) return case "generic": recordTypes = append(recordTypes, ipmi.SDRRecordTypeGenericLocator) default: CheckErr(fmt.Errorf("unknown supported record type (%s), usage: %s", args[0], usage)) return } } sdrs, err := client.GetSDRs(ctx, recordTypes...) if err != nil { CheckErr(fmt.Errorf("GetSDRs failed, err: %w", err)) } fmt.Println(ipmi.FormatSDRs(sdrs)) }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/sel.go000066400000000000000000000053641474110527100240600ustar00rootroot00000000000000package commands import ( "context" "errors" "fmt" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) func NewCmdSEL() *cobra.Command { cmd := &cobra.Command{ Use: "sel", Short: "sel", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdSELInfo()) cmd.AddCommand(NewCmdSELGet()) cmd.AddCommand(NewCmdSELList()) cmd.AddCommand(NewCmdSELElist()) return cmd } func NewCmdSELInfo() *cobra.Command { cmd := &cobra.Command{ Use: "info", Short: "info", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() selInfo, err := client.GetSELInfo(ctx) if err != nil { CheckErr(fmt.Errorf("GetSELInfo failed, err: %w", err)) } fmt.Println(selInfo.Format()) selAllocInfo, err := client.GetSELAllocInfo(ctx) if err != nil { CheckErr(fmt.Errorf("GetSELInfo failed, err: %w", err)) } fmt.Println(selAllocInfo.Format()) }, } return cmd } func NewCmdSELGet() *cobra.Command { cmd := &cobra.Command{ Use: "get", Short: "get", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(errors.New("no Record ID supplied")) } id, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid Record ID passed, err: %w", err)) } recordID := uint16(id) ctx := context.Background() selEntryRes, err := client.GetSELEntry(ctx, 0x0, recordID) if err != nil { CheckErr(fmt.Errorf("GetSELEntry failed, err: %w", err)) } sel, err := ipmi.ParseSEL(selEntryRes.Data) if err != nil { CheckErr(fmt.Errorf("ParseSEL failed, err: %w", err)) } fmt.Println(ipmi.FormatSELs([]*ipmi.SEL{sel}, nil)) }, } return cmd } func NewCmdSELList() *cobra.Command { cmd := &cobra.Command{ Use: "list", Short: "list", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() selEntries, err := client.GetSELEntries(ctx, 0) if err != nil { CheckErr(fmt.Errorf("GetSELInfo failed, err: %w", err)) } fmt.Println(ipmi.FormatSELs(selEntries, nil)) }, } return cmd } func NewCmdSELElist() *cobra.Command { cmd := &cobra.Command{ Use: "elist", Short: "elist", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() sdrsMap, err := client.GetSDRsMap(ctx) if err != nil { CheckErr(fmt.Errorf("GetSDRsMap failed, err: %w", err)) } selEntries, err := client.GetSELEntries(ctx, 0) if err != nil { CheckErr(fmt.Errorf("GetSELInfo failed, err: %w", err)) } fmt.Println(ipmi.FormatSELs(selEntries, sdrsMap)) }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/sensor.go000066400000000000000000000204001474110527100245720ustar00rootroot00000000000000package commands import ( "context" "fmt" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) func NewCmdSensor() *cobra.Command { cmd := &cobra.Command{ Use: "sensor", Short: "sensor", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdSensorDeviceSDRInfo()) cmd.AddCommand(NewCmdSensorGet()) cmd.AddCommand(NewCmdSensorList()) cmd.AddCommand(NewCmdSensorThreshold()) cmd.AddCommand(NewCmdSensorEventEnable()) cmd.AddCommand(NewCmdSensorEventStatus()) cmd.AddCommand(NewCmdSensorReading()) cmd.AddCommand(NewCmdSensorReadingFactors()) cmd.AddCommand(NewCmdSensorDetail()) return cmd } func NewCmdSensorDeviceSDRInfo() *cobra.Command { cmd := &cobra.Command{ Use: "info", Short: "info", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() res, err := client.GetDeviceSDRInfo(ctx, true) if err != nil { CheckErr(fmt.Errorf("GetDeviceSDRInfo failed, err: %w", err)) } fmt.Println(res.Format()) }, } return cmd } func NewCmdSensorList() *cobra.Command { var extended bool var filterThreshold bool var filterReadingValid bool cmd := &cobra.Command{ Use: "list", Short: "list", Run: func(cmd *cobra.Command, args []string) { filterOptions := make([]ipmi.SensorFilterOption, 0) if filterThreshold { filterOptions = append(filterOptions, ipmi.SensorFilterOptionIsThreshold) } if filterReadingValid { filterOptions = append(filterOptions, ipmi.SensorFilterOptionIsReadingValid) } ctx := context.Background() sensors, err := client.GetSensors(ctx, filterOptions...) if err != nil { CheckErr(fmt.Errorf("GetSensors failed, err: %w", err)) } fmt.Println(ipmi.FormatSensors(extended, sensors...)) }, } cmd.PersistentFlags().BoolVarP(&extended, "extended", "", false, "extended print") cmd.PersistentFlags().BoolVarP(&filterThreshold, "threshold", "", false, "filter threshold sensor class") cmd.PersistentFlags().BoolVarP(&filterReadingValid, "valid", "", false, "filter sensor that has valid reading") return cmd } func NewCmdSensorGet() *cobra.Command { usage := `sensor get or , sensorName should be quoted if contains space` cmd := &cobra.Command{ Use: "get", Short: "get", Run: func(cmd *cobra.Command, args []string) { var sensorNumber uint8 if len(args) < 1 { CheckErr(fmt.Errorf("no Sensor ID or Sensor Name supplied, usage: %s", usage)) } ctx := context.Background() var sensor *ipmi.Sensor var err error id, err := parseStringToInt64(args[0]) if err != nil { // suppose args is sensor name sensor, err = client.GetSensorByName(ctx, args[0]) if err != nil { CheckErr(fmt.Errorf("GetSensorByName failed, err: %w", err)) } } else { sensorNumber = uint8(id) sensor, err = client.GetSensorByID(ctx, sensorNumber) if err != nil { CheckErr(fmt.Errorf("GetSensorByID failed, err: %w", err)) } } client.Debug("sensor", sensor) fmt.Println(sensor) }, } return cmd } func NewCmdSensorThreshold() *cobra.Command { usage := ` sensor threshold get ` cmd := &cobra.Command{ Use: "threshold", Short: "threshold", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { CheckErr(fmt.Errorf("usage: %s", usage)) } action := args[0] var sensorNumber uint8 i, err := parseStringToInt64(args[1]) if err != nil { CheckErr(fmt.Errorf("invalid sensor number, err: %w", err)) } sensorNumber = uint8(i) ctx := context.Background() switch action { case "get": res, err := client.GetSensorThresholds(ctx, sensorNumber) if err != nil { CheckErr(fmt.Errorf("GetSensorThresholds failed, err: %w", err)) } fmt.Println(res.Format()) case "set": default: CheckErr(fmt.Errorf("usage: %s", usage)) } }, } return cmd } func NewCmdSensorEventStatus() *cobra.Command { usage := ` sensor event-status get ` cmd := &cobra.Command{ Use: "event-status ", Short: "event-status ", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { CheckErr(fmt.Errorf("usage: %s", usage)) } action := args[0] var sensorNumber uint8 i, err := parseStringToInt64(args[1]) if err != nil { CheckErr(fmt.Errorf("invalid sensor number, err: %w", err)) } sensorNumber = uint8(i) ctx := context.Background() switch action { case "get": res, err := client.GetSensorEventStatus(ctx, sensorNumber) if err != nil { CheckErr(fmt.Errorf("GetSensorEventStatus failed, err: %w", err)) } fmt.Println(res.Format()) case "set": default: CheckErr(fmt.Errorf("usage: %s", usage)) } }, } return cmd } func NewCmdSensorEventEnable() *cobra.Command { usage := ` sensor event-enable get ` cmd := &cobra.Command{ Use: "event-enable ", Short: "event-enable ", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { CheckErr(fmt.Errorf("usage: %s", usage)) } action := args[0] var sensorNumber uint8 i, err := parseStringToInt64(args[1]) if err != nil { CheckErr(fmt.Errorf("invalid sensor number, err: %w", err)) } sensorNumber = uint8(i) ctx := context.Background() switch action { case "get": res, err := client.GetSensorEventEnable(ctx, sensorNumber) if err != nil { CheckErr(fmt.Errorf("GetSensorEventEnable failed, err: %w", err)) } fmt.Println(res.Format()) case "set": default: CheckErr(fmt.Errorf("usage: %s", usage)) } }, } return cmd } func NewCmdSensorReading() *cobra.Command { usage := ` sensor reading get ` cmd := &cobra.Command{ Use: "reading", Short: "reading", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { CheckErr(fmt.Errorf("usage: %s", usage)) } action := args[0] var sensorNumber uint8 i, err := parseStringToInt64(args[1]) if err != nil { CheckErr(fmt.Errorf("invalid sensor number, err: %w", err)) } sensorNumber = uint8(i) ctx := context.Background() switch action { case "get": res, err := client.GetSensorReading(ctx, sensorNumber) if err != nil { CheckErr(fmt.Errorf("GetSensorReading failed, err: %w", err)) } fmt.Println(res.Format()) case "set": default: CheckErr(fmt.Errorf("usage: %s", usage)) } }, } return cmd } func NewCmdSensorReadingFactors() *cobra.Command { usage := ` sensor reading-factors get ` cmd := &cobra.Command{ Use: "reading-factors", Short: "reading-factors", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { CheckErr(fmt.Errorf("usage: %s", usage)) } action := args[0] var sensorNumber uint8 i, err := parseStringToInt64(args[1]) if err != nil { CheckErr(fmt.Errorf("invalid sensor number, err: %w", err)) } sensorNumber = uint8(i) ctx := context.Background() switch action { case "get": res0, err := client.GetSensorReading(ctx, sensorNumber) if err != nil { CheckErr(fmt.Errorf("GetSensorReading failed, err: %w", err)) } fmt.Println(res0.Format()) res, err := client.GetSensorReadingFactors(ctx, sensorNumber, res0.Reading) if err != nil { CheckErr(fmt.Errorf("GetSensorReadingFactors failed, err: %w", err)) } fmt.Println(res.Format()) case "set": default: CheckErr(fmt.Errorf("usage: %s", usage)) } }, } return cmd } func NewCmdSensorDetail() *cobra.Command { usage := ` sensor detail ` cmd := &cobra.Command{ Use: "detail", Short: "detail", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(fmt.Errorf("usage: %s", usage)) } var sensorNumber uint8 if len(args) >= 1 { i, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid sensor number, err: %w", err)) } sensorNumber = uint8(i) } ctx := context.Background() sensor, err := client.GetSensorByID(ctx, sensorNumber) if err != nil { CheckErr(fmt.Errorf("GetSensorByID failed, err: %w", err)) } fmt.Println(sensor) }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/session.go000066400000000000000000000022631474110527100247530ustar00rootroot00000000000000package commands import ( "context" "fmt" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) func NewCmdSession() *cobra.Command { cmd := &cobra.Command{ Use: "session", Short: "session", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdSessionInfo()) return cmd } func NewCmdSessionInfo() *cobra.Command { // cSpell: disable usage := `Session Commands: info ` // cSpell: enable cmd := &cobra.Command{ Use: "info", Short: "info", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { fmt.Println(usage) return } ctx := context.Background() switch args[0] { case "active": request := &ipmi.GetSessionInfoRequest{ SessionIndex: 0, // current active } res, err := client.GetSessionInfo(ctx, request) if err != nil { CheckErr(fmt.Errorf("GetSessionInfo failed, err: %w", err)) } fmt.Println(res.Format()) } }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/sol.go000066400000000000000000000015271474110527100240670ustar00rootroot00000000000000package commands import ( "context" "fmt" "github.com/spf13/cobra" ) func NewCmdSOL() *cobra.Command { cmd := &cobra.Command{ Use: "sol", Short: "sol", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdSOLInfo()) return cmd } func NewCmdSOLInfo() *cobra.Command { cmd := &cobra.Command{ Use: "info", Short: "info", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() solConfigParams, err := client.GetSOLConfigParams(ctx, 0x0e) if err != nil { CheckErr(fmt.Errorf("GetDeviceID failed, err: %w", err)) } fmt.Println(solConfigParams.Format()) }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/user.go000066400000000000000000000036671474110527100242570ustar00rootroot00000000000000package commands import ( "context" "fmt" "github.com/bougou/go-ipmi" "github.com/spf13/cobra" ) func NewCmdUser() *cobra.Command { cmd := &cobra.Command{ Use: "user", Short: "user", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdUserList()) cmd.AddCommand(NewCmdUserSummary()) return cmd } func NewCmdUserList() *cobra.Command { cmd := &cobra.Command{ Use: "list []", Short: "list []", Run: func(cmd *cobra.Command, args []string) { var channelNumber uint8 if len(args) == 0 { channelNumber = ipmi.ChannelNumberSelf } if len(args) > 1 { id, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid channel number passed, err: %w", err)) } channelNumber = uint8(id) } ctx := context.Background() users, err := client.ListUser(ctx, channelNumber) if err != nil { CheckErr(fmt.Errorf("ListUser failed, err: %w", err)) } fmt.Println(ipmi.FormatUsers(users)) }, } return cmd } func NewCmdUserSummary() *cobra.Command { cmd := &cobra.Command{ Use: "summary []", Short: "summary []", Run: func(cmd *cobra.Command, args []string) { var channelNumber uint8 if len(args) == 0 { channelNumber = ipmi.ChannelNumberSelf } if len(args) > 1 { id, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid channel number passed, err: %w", err)) } channelNumber = uint8(id) } ctx := context.Background() res, err := client.GetUserAccess(ctx, channelNumber, 0x01) if err != nil { CheckErr(fmt.Errorf("GetUserAccess failed, err: %w", err)) } fmt.Println(res.Format()) }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/version.go000066400000000000000000000001121474110527100247440ustar00rootroot00000000000000package commands var ( Version string Commit string BuildAt string ) golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/commands/x.go000066400000000000000000000236551474110527100235470ustar00rootroot00000000000000package commands import ( "context" "fmt" "time" "github.com/bougou/go-ipmi" "github.com/kr/pretty" "github.com/spf13/cobra" ) const timeFormat = time.RFC3339 // x Experimental commands. func NewCmdX() *cobra.Command { cmd := &cobra.Command{ Use: "x", Short: "x", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initClient() }, Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { cmd.Help() } }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { return closeClient() }, } cmd.AddCommand(NewCmdXGetSDRs()) cmd.AddCommand(NewCmdXGetSensors()) cmd.AddCommand(NewCmdXGetDeviceSDRs()) cmd.AddCommand(NewCmdXGetPayloadActivationStatus()) cmd.AddCommand(NewCmdXGetDeviceGUID()) cmd.AddCommand(NewCmdXGetSystemGUID()) cmd.AddCommand(NewCmdXGetPEFConfigParams()) cmd.AddCommand(NewCmdXGetLanConfigParamsFor()) cmd.AddCommand(NewCmdXGetLanConfigParamsFull()) cmd.AddCommand(NewCmdXGetLanConfig()) cmd.AddCommand(NewCmdXGetDCMIConfigParams()) cmd.AddCommand(NewCmdXGetBootOptions()) cmd.AddCommand(NewCmdXGetSystemInfoParams()) cmd.AddCommand(NewCmdXGetSystemInfoParamsFor()) cmd.AddCommand(NewCmdXGetSystemInfo()) return cmd } func NewCmdXGetSDRs() *cobra.Command { var show bool var loop bool cmd := &cobra.Command{ Use: "get-sdr", Short: "get-sdr", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() for { fmt.Printf("\n\nGet SDRs at %s\n", time.Now().Format(timeFormat)) res, err := client.GetSDRs(ctx) if err != nil { fmt.Printf("GetSDRs failed, err: %s", err) if loop { goto WAIT } else { return } } fmt.Printf("GetSDRs succeeded, %d records\n", len(res)) if show { fmt.Println(ipmi.FormatSDRs(res)) } if loop { goto WAIT } else { return } WAIT: fmt.Println("wait for next loop") time.Sleep(30 * time.Second) } }, } cmd.PersistentFlags().BoolVarP(&show, "show", "s", false, "show table of result") cmd.PersistentFlags().BoolVarP(&loop, "loop", "l", false, "loop") return cmd } func NewCmdXGetSensors() *cobra.Command { var show bool var loop bool cmd := &cobra.Command{ Use: "get-sensor", Short: "get-sensor", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() for { fmt.Printf("\n\nGet Sensors at %s\n", time.Now().Format(timeFormat)) res, err := client.GetSensors(ctx) if err != nil { fmt.Printf("GetSensors failed, err: %s", err) if loop { goto WAIT } else { return } } fmt.Printf("GetSensors succeeded, %d records\n", len(res)) if show { fmt.Println(ipmi.FormatSensors(true, res...)) } if loop { goto WAIT } else { return } WAIT: fmt.Println("wait for next loop") time.Sleep(30 * time.Second) } }, } cmd.PersistentFlags().BoolVarP(&show, "show", "s", false, "show table of result") cmd.PersistentFlags().BoolVarP(&loop, "loop", "l", false, "loop") return cmd } func NewCmdXGetDeviceSDRs() *cobra.Command { var show bool cmd := &cobra.Command{ Use: "get-device-sdr", Short: "get-device-sdr", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() fmt.Printf("\n\nGet Device SDR at %s\n", time.Now().Format(timeFormat)) res, err := client.GetDeviceSDRs(ctx) if err != nil { fmt.Printf("GetDeviceSDRs failed, err: %s", err) return } fmt.Printf("GetDeviceSDRs succeeded, %d records\n", len(res)) if show { fmt.Println(ipmi.FormatSDRs(res)) } }, } cmd.PersistentFlags().BoolVarP(&show, "show", "s", false, "show table of result") return cmd } func NewCmdXGetPayloadActivationStatus() *cobra.Command { cmd := &cobra.Command{ Use: "get-payload-activation-status", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { fmt.Println("usage: get-payload-activation-status {payload-type}") return } payloadType, err := parseStringToInt64(args[0]) if err != nil { fmt.Println(err) } ctx := context.Background() res, err := client.GetPayloadActivationStatus(ctx, ipmi.PayloadType(payloadType)) if err != nil { fmt.Println(err) } fmt.Println(res.Format()) }, } return cmd } func NewCmdXGetSystemGUID() *cobra.Command { cmd := &cobra.Command{ Use: "get-system-guid", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() res, err := client.GetSystemGUID(ctx) if err != nil { fmt.Println(err) return } fmt.Println(res.Format()) fmt.Println("\nDetail of GUID\n==============") fmt.Println() fmt.Println(ipmi.FormatGUIDDetails(res.GUID)) }, } return cmd } func NewCmdXGetDeviceGUID() *cobra.Command { cmd := &cobra.Command{ Use: "get-device-guid", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() res, err := client.GetDeviceGUID(ctx) if err != nil { fmt.Println(err) return } fmt.Println(res.Format()) fmt.Println("\nDetail of GUID\n==============") fmt.Println() fmt.Println(ipmi.FormatGUIDDetails(res.GUID)) }, } return cmd } func NewCmdXGetPEFConfigParams() *cobra.Command { cmd := &cobra.Command{ Use: "get-pef-config-params", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() pefConfigParams, err := client.GetPEFConfigParams(ctx) if err != nil { fmt.Println(err) return } fmt.Println(pefConfigParams.Format()) }, } return cmd } func NewCmdXGetLanConfigParamsFor() *cobra.Command { usage := ` get-lan-config-params-for [] ` cmd := &cobra.Command{ Use: "get-lan-config-params-for", Short: "get-lan-config-params-for", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(fmt.Errorf("usage: %s", usage)) } id, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid channel number passed, err: %w", err)) } channelNumber := uint8(id) ctx := context.Background() lanConfigParams := ipmi.LanConfigParams{ IP: &ipmi.LanConfigParam_IP{}, SubnetMask: &ipmi.LanConfigParam_SubnetMask{}, DefaultGatewayIP: &ipmi.LanConfigParam_DefaultGatewayIP{}, } if err := client.GetLanConfigParamsFor(ctx, channelNumber, &lanConfigParams); err != nil { CheckErr(fmt.Errorf("GetLanConfigParamsFor failed, err: %w", err)) } client.Debug("Lan Config", lanConfigParams) fmt.Println(lanConfigParams.Format()) }, } return cmd } func NewCmdXGetLanConfigParamsFull() *cobra.Command { usage := ` get-lan-config-params-full [] ` cmd := &cobra.Command{ Use: "get-lan-config-params-full", Short: "get-lan-config-params-full", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(fmt.Errorf("usage: %s", usage)) } id, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid channel number passed, err: %w", err)) } channelNumber := uint8(id) ctx := context.Background() lanConfigParams, err := client.GetLanConfigParamsFull(ctx, channelNumber) if err != nil { CheckErr(fmt.Errorf("GetLanConfigParamsFull failed, err: %w", err)) } client.Debug("Lan Config", lanConfigParams) fmt.Println(lanConfigParams.Format()) }, } return cmd } func NewCmdXGetLanConfig() *cobra.Command { usage := ` get-lan-config [] ` cmd := &cobra.Command{ Use: "get-lan-config", Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { CheckErr(fmt.Errorf("usage: %s", usage)) } id, err := parseStringToInt64(args[0]) if err != nil { CheckErr(fmt.Errorf("invalid channel number passed, err: %w", err)) } channelNumber := uint8(id) ctx := context.Background() lanConfig, err := client.GetLanConfig(ctx, channelNumber) if err != nil { fmt.Println(err) return } fmt.Println(lanConfig.Format()) }, } return cmd } func NewCmdXGetDCMIConfigParams() *cobra.Command { cmd := &cobra.Command{ Use: "get-dcmi-config-params", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() dcmiConfigParams, err := client.GetDCMIConfigParams(ctx) if err != nil { fmt.Println(err) return } fmt.Println(dcmiConfigParams.Format()) }, } return cmd } func NewCmdXGetBootOptions() *cobra.Command { cmd := &cobra.Command{ Use: "get-boot-options", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() bootOptionsParams, err := client.GetSystemBootOptionsParams(ctx) if err != nil { fmt.Println(err) return } fmt.Println(bootOptionsParams.Format()) }, } return cmd } func NewCmdXGetSystemInfoParams() *cobra.Command { cmd := &cobra.Command{ Use: "get-system-info-params", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() systemInfoParams, err := client.GetSystemInfoParams(ctx) if err != nil { fmt.Println(err) return } fmt.Println(systemInfoParams.Format()) }, } return cmd } func NewCmdXGetSystemInfoParamsFor() *cobra.Command { cmd := &cobra.Command{ Use: "get-system-info-params-for", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() systemInfoParams := &ipmi.SystemInfoParams{ SetInProgress: nil, SystemFirmwareVersions: nil, SystemNames: make([]*ipmi.SystemInfoParam_SystemName, 0), } pretty.Println(systemInfoParams) if err := client.GetSystemInfoParamsFor(ctx, systemInfoParams); err != nil { fmt.Println(err) return } fmt.Println(systemInfoParams.Format()) }, } return cmd } func NewCmdXGetSystemInfo() *cobra.Command { cmd := &cobra.Command{ Use: "get-system-info", Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() systemInfo, err := client.GetSystemInfo(ctx) if err != nil { fmt.Println(err) return } fmt.Println(systemInfo.Format()) }, } return cmd } golang-github-bougou-go-ipmi-0.7.2/cmd/goipmi/main.go000066400000000000000000000003511474110527100224070ustar00rootroot00000000000000package main import ( "fmt" "os" "github.com/bougou/go-ipmi/cmd/goipmi/commands" ) func main() { rootCmd := commands.NewRootCommand() if err := rootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } golang-github-bougou-go-ipmi-0.7.2/cmd_activate_dcmi_power_limit.go000066400000000000000000000025761474110527100255000ustar00rootroot00000000000000package ipmi import "context" // [DCMI specification v1.5]: 6.6.4 Activate/Deactivate Power Limit type ActivateDCMIPowerLimitRequest struct { Activate bool } type ActivateDCMIPowerLimitResponse struct { } func (req *ActivateDCMIPowerLimitRequest) Pack() []byte { activate := uint8(0x00) if req.Activate { activate = 0x01 } return []byte{GroupExtensionDCMI, activate, 0x00, 0x00} } func (req *ActivateDCMIPowerLimitRequest) Command() Command { return CommandActivateDCMIPowerLimit } func (res *ActivateDCMIPowerLimitResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *ActivateDCMIPowerLimitResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } return nil } func (res *ActivateDCMIPowerLimitResponse) Format() string { return "" } // ActivateDCMIPowerLimit activate or deactivate the power limit set. // Setting the param 'activate' to true means to activate the power limit, false means to deactivate the power limit func (c *Client) ActivateDCMIPowerLimit(ctx context.Context, activate bool) (response *ActivateDCMIPowerLimitResponse, err error) { request := &ActivateDCMIPowerLimitRequest{ Activate: activate, } response = &ActivateDCMIPowerLimitResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_activate_session.go000066400000000000000000000144731474110527100236340ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 22.17 type ActivateSessionRequest struct { // Authentication Type for session. // The selected type will be used for session activation and for all subsequent authenticated packets under the session, unless "Per-message Authentication" or "User Level Authentication" are disabled. // (See 6.12.4, Per-Message and User Level Authentication Disables, for more information.) // // This value must match with the Authentication Type used in the Get Session Challenge request for the session. In addition, for multi-session channels this value must also match the authentication type used in the Session Header. AuthTypeForSession AuthType // Maximum privilege level requested. Indicates the highest privilege level that // may be requested for this session. This privilege level must be less than // or equal to the privilege limit for the channel and the privilege limit for the // user in order for the Activate Session command to be successful // (completion code = 00h). Once the Activate Session command has been // successful, the requested privilege level becomes a 'session limit' that // cannot be raised beyond the requested level, even if the user and/or // channel privilege level limits would allow it. I.e. it takes precedence over // the channel and user privilege level limits. // // [7:4] - reserved // [3:0] - Requested Maximum Privilege Level // 0h = reserved // 1h = Callback level // 2h = User level // 3h = Operator level // 4h = Administrator level // 5h = OEM Proprietary level // all other = reserved MaxPrivilegeLevel PrivilegeLevel // For multi-session channels: (e.g. LAN channel): // Challenge String data from corresponding Get Session Challenge response. // // For single-session channels that lack session header (e.g. serial/modem in Basic Mode): // Clear text password or AuthCode. See 22.17.1, AuthCode Algorithms. Challenge [16]byte // uint16 // Initial Outbound Sequence Number = Starting sequence number that remote console wants used for messages from the BMC. (LS byte first). Must be non-null in order to establish a session. 0000_0000h = reserved. Can be any random value. // // The BMC must increment the outbound session sequence number by one (1) for // each subsequent outbound message from the BMC (include ActivateSessionResponse) // // The BMC sets the incremented number to Sequence field of SessionHeader. InitialOutboundSequenceNumber uint32 } func (req *ActivateSessionRequest) Pack() []byte { out := make([]byte, 22) packUint8(uint8(req.AuthTypeForSession), out, 0) packUint8(uint8(req.MaxPrivilegeLevel), out, 1) packBytes(req.Challenge[:], out, 2) packUint32L(req.InitialOutboundSequenceNumber, out, 18) return out } func (req *ActivateSessionRequest) Command() Command { return CommandActivateSession } type ActivateSessionResponse struct { // Authentication Type for remainder of session AuthType AuthType // use this for remainder of session. // While atypical, the BMC is allowed to change the Session ID from the one that passed in the request. SessionID uint32 // Initial inbound seq# = Sequence number that BMC wants remote console to use for subsequent messages in the session. The BMC returns a non-null value for multi-session connections and returns null (all 0s) for single-session connections. // // The remote console must increment the inbound session sequence number by one (1) for each subsequent message it sends to the BMC. InitialInboundSequenceNumber uint32 // Maximum privilege level allowed for this session // [7:4] - reserved // [3:0] - Maximum Privilege Level allowed // 0h = reserved // 1h = Callback level // 2h = User level // 3h = Operator level // 4h = Administrator level // 5h = OEM Proprietary level // all other = reserved MaxPrivilegeLevel uint8 } func (res *ActivateSessionResponse) Unpack(data []byte) error { if len(data) < 10 { return ErrUnpackedDataTooShortWith(len(data), 10) } res.AuthType = AuthType(data[0]) res.SessionID, _, _ = unpackUint32L(data, 1) res.InitialInboundSequenceNumber, _, _ = unpackUint32L(data, 5) res.MaxPrivilegeLevel = data[9] return nil } func (*ActivateSessionResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "No session slot available (BMC cannot accept any more sessions)", 0x82: "No slot available for given user. (Limit of user sessions allowed under that name has been reached)", // (An implementation may only be able to support a certain number of // sessions based on what authentication resources are required. For // example, if User Level Authentication is disabled, an implementation // may be able to allow a larger number of users that are limited to User // Level privilege, than users that require higher privilege.) 0x83: "No slot available to support user due to maximum privilege capability", 0x84: "session sequence number out-of-range", 0x85: "invalid Session ID in request", 0x86: "requested maximum privilege level exceeds user and/or channel privilege limit", } } func (res *ActivateSessionResponse) Format() string { return fmt.Sprintf("%v", res) } // ActivateSession is only used for IPMI v1.5 func (c *Client) ActivateSession(ctx context.Context) (response *ActivateSessionResponse, err error) { request := &ActivateSessionRequest{ AuthTypeForSession: c.session.authType, MaxPrivilegeLevel: c.maxPrivilegeLevel, Challenge: c.session.v15.challenge, // the outbound session sequence number is set by the remote console and can be any random value. InitialOutboundSequenceNumber: randomUint32(), } c.session.v15.outSeq = request.InitialOutboundSequenceNumber response = &ActivateSessionResponse{} // The Activate Session packet is typically authenticated. // We set session to active here to indicate this request should be authenticated // but if ActivateSession Command failed, we should set session active to false err = c.Exchange(ctx, request, response) if err != nil { return } c.session.v15.active = true c.session.v15.preSession = false // to use for the remainder of the session // Todo, validate the SessionID c.session.v15.sessionID = response.SessionID // The remote console must increment the inbound session sequence number // by one (1) for each subsequent message it sends to the BMC c.session.v15.inSeq = response.InitialInboundSequenceNumber return } golang-github-bougou-go-ipmi-0.7.2/cmd_add_sel_entry.go000066400000000000000000000021701474110527100230740ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 31.6 Add SEL Entry Command type AddSELEntryRequest struct { SEL *SEL } type AddSELEntryResponse struct { RecordID uint16 // Record ID for added record, LS Byte first } func (req *AddSELEntryRequest) Command() Command { return CommandAddSELEntry } func (req *AddSELEntryRequest) Pack() []byte { return req.SEL.Pack() } func (res *AddSELEntryResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.RecordID, _, _ = unpackUint16L(msg, 0) return nil } func (res *AddSELEntryResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "operation not supported for this Record Type", 0x81: "cannot execute command, SEL erase in progress", } } func (res *AddSELEntryResponse) Format() string { return fmt.Sprintf("Record ID : %d (%#02x)", res.RecordID, res.RecordID) } func (c *Client) AddSELEntry(ctx context.Context, sel *SEL) (response *AddSELEntryResponse, err error) { request := &AddSELEntryRequest{ SEL: sel, } response = &AddSELEntryResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_alert_immediate.go000066400000000000000000000037561474110527100234200ustar00rootroot00000000000000package ipmi import "context" type AlertImmediateOperation uint8 const ( AlertImmediateOperationInitiateAlert AlertImmediateOperation = 0b00 AlertImmediateOperationGetStatus AlertImmediateOperation = 0b01 AlertImmediateOperationClearStatus AlertImmediateOperation = 0b10 AlertImmediateOperationReserved AlertImmediateOperation = 0b11 ) type AlertImmediateStatus uint8 const ( AlertImmediateStatusNoStatus AlertImmediateStatus = 0x00 AlertImmediateStatusNormalEnd AlertImmediateStatus = 0x01 AlertImmediateStatusFailedRetry AlertImmediateStatus = 0x02 AlertImmediateStatusFailedWaitACK AlertImmediateStatus = 0x03 AlertImmediateStatusInProgress AlertImmediateStatus = 0xff ) // 30.7 Alert Immediate Command type AlertImmediateRequest struct { ChannelNumber uint8 DestinationSelector uint8 Operation uint8 SendAlertString bool AlertStringSelector uint8 GeneratorID uint8 EvMRev uint8 SensorType SensorType SensorNumber SensorNumber EventDir EventDir EventReadingType EventReadingType EventData EventData } type AlertImmediateResponse struct { AlertImmediateStatus uint8 } func (req *AlertImmediateRequest) Pack() []byte { out := make([]byte, 1) return out } func (req *AlertImmediateRequest) Command() Command { return CommandAlertImmediate } func (res *AlertImmediateResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "Alert Immediate rejected due to alert already in progress", 0x82: "Alert Immediate rejected due to IPMI messaging session active on this channel", 0x83: "Platform Event Parameters (4:11) not supported", } } func (res *AlertImmediateResponse) Unpack(msg []byte) error { return nil } func (res *AlertImmediateResponse) Format() string { return "" } func (c *Client) AlertImmediate(ctx context.Context, request *AlertImmediateRequest) (response *AlertImmediateResponse, err error) { response = &AlertImmediateResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_arm_pef_postpone_timer.go000066400000000000000000000041321474110527100250200ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 30.2 Arm PEF Postpone Timer Command type ArmPEFPostponeTimerRequest struct { // PEF Postpone Timeout, in seconds. 01h -> 1 second. // // 00h = disable Postpone Timer (PEF will immediately handle events, if enabled). // The BMC automatically disables the timer whenever the system // enters a sleep state, is powered down, or reset. // 01h - FDh = arm timer. // Timer will automatically start counting down from given value // when the last-processed event Record ID is not equal to the last // received event's Record ID. // FEh = Temporary PEF disable. // The PEF Postpone timer does not countdown from the value. // The BMC automatically re-enables PEF (if enabled in the PEF configuration parameters) // and sets the PEF Postpone timeout to 00h whenever the system // enters a sleep state, is powered down, or reset. Software can // cancel this disable by setting this parameter to 00h or 01h-FDh. // FFh = get present countdown value Timeout uint8 } type ArmPEFPostponeTimerResponse struct { // Present timer countdown value PresentValue uint8 } func (req *ArmPEFPostponeTimerRequest) Command() Command { return CommandArmPEFPostponeTimer } func (req *ArmPEFPostponeTimerRequest) Pack() []byte { // empty request data return []byte{req.Timeout} } func (res *ArmPEFPostponeTimerResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShort } res.PresentValue = msg[0] return nil } func (r *ArmPEFPostponeTimerResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *ArmPEFPostponeTimerResponse) Format() string { return fmt.Sprintf(`Present timer countdown value : %d (%#02x)`, res.PresentValue, res.PresentValue, ) } func (c *Client) ArmPEFPostponeTimer(ctx context.Context, timeout uint8) (response *ArmPEFPostponeTimerResponse, err error) { request := &ArmPEFPostponeTimerRequest{ Timeout: timeout, } response = &ArmPEFPostponeTimerResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_chassis_control.go000066400000000000000000000024221474110527100234550ustar00rootroot00000000000000package ipmi import "context" type ChassisControl uint8 const ( ChassisControlPowerDown ChassisControl = 0 // down, off ChassisControlPowerUp ChassisControl = 1 ChassisControlPowerCycle ChassisControl = 2 ChassisControlHardReset ChassisControl = 3 ChassisControlDiagnosticInterrupt ChassisControl = 4 ChassisControlSoftShutdown ChassisControl = 5 ) // 28.3 Chassis Control Command type ChassisControlRequest struct { ChassisControl ChassisControl } type ChassisControlResponse struct { } func (req *ChassisControlRequest) Pack() []byte { out := make([]byte, 1) packUint8(uint8(req.ChassisControl), out, 0) return out } func (req *ChassisControlRequest) Command() Command { return CommandChassisControl } func (res *ChassisControlResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *ChassisControlResponse) Unpack(msg []byte) error { return nil } func (res *ChassisControlResponse) Format() string { return "" } func (c *Client) ChassisControl(ctx context.Context, control ChassisControl) (response *ChassisControlResponse, err error) { request := &ChassisControlRequest{ ChassisControl: control, } response = &ChassisControlResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_chassis_identify.go000066400000000000000000000025541474110527100236160ustar00rootroot00000000000000package ipmi import "context" // 28.5 Chassis Identify Command // 用来定位设备,机箱定位 (机箱定位灯默认亮 interval 秒) type ChassisIdentifyRequest struct { IdentifyInterval uint8 ForceIdentifyOn bool } type ChassisIdentifyResponse struct { // empty } func (req *ChassisIdentifyRequest) Pack() []byte { out := make([]byte, 2) packUint8(uint8(req.IdentifyInterval), out, 0) var force uint8 = 0 if req.ForceIdentifyOn { force = 1 } packUint8(force, out, 1) return out } func (req *ChassisIdentifyRequest) Command() Command { return CommandChassisIdentify } func (res *ChassisIdentifyResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *ChassisIdentifyResponse) Unpack(msg []byte) error { return nil } func (res *ChassisIdentifyResponse) Format() string { return "" } // This command causes the chassis to physically identify itself by a mechanism // chosen by the system implementation; such as turning on blinking user-visible lights // or emitting beeps via a speaker, LCD panel, etc. func (c *Client) ChassisIdentify(ctx context.Context, interval uint8, force bool) (response *ChassisIdentifyResponse, err error) { request := &ChassisIdentifyRequest{ IdentifyInterval: interval, ForceIdentifyOn: force, } response = &ChassisIdentifyResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_chassis_reset.go000066400000000000000000000016611474110527100231230ustar00rootroot00000000000000package ipmi import "context" // 28.4 Chassis Reset Command type ChassisResetRequest struct { // empty } type ChassisResetResponse struct { // empty } func (req *ChassisResetRequest) Pack() []byte { return []byte{} } func (req *ChassisResetRequest) Command() Command { return CommandChassisReset } func (res *ChassisResetResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *ChassisResetResponse) Unpack(msg []byte) error { return nil } func (res *ChassisResetResponse) Format() string { return "" } // This command was used with early versions of the ICMB. // It has been superseded by the Chassis Control command // For host systems, this corresponds to a system hard reset. func (c *Client) ChassisReset(ctx context.Context) (response *ChassisResetResponse, err error) { request := &ChassisResetRequest{} response = &ChassisResetResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_clear_message_flags.go000066400000000000000000000026061474110527100242320ustar00rootroot00000000000000package ipmi import "context" // 22.3 Clear Message Flags Command type ClearMessageFlagsRequest struct { ClearOEM2 bool ClearOEM1 bool ClearOEM0 bool ClearWatchdogPreTimeoutInterruptFlag bool ClearEventMessageBuffer bool ClearReceiveMessageQueue bool } type ClearMessageFlagsResponse struct { } func (req *ClearMessageFlagsRequest) Command() Command { return CommandClearMessageFlags } func (req *ClearMessageFlagsRequest) Pack() []byte { var b uint8 = 0 if req.ClearOEM2 { b = setBit7(b) } if req.ClearOEM1 { b = setBit6(b) } if req.ClearOEM0 { b = setBit5(b) } if req.ClearWatchdogPreTimeoutInterruptFlag { b = setBit3(b) } if req.ClearEventMessageBuffer { b = setBit1(b) } if req.ClearReceiveMessageQueue { b = setBit0(b) } return []byte{b} } func (res *ClearMessageFlagsResponse) Unpack(msg []byte) error { return nil } func (*ClearMessageFlagsResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *ClearMessageFlagsResponse) Format() string { // Todo return "" } func (c *Client) ClearMessageFlags(ctx context.Context, request *ClearMessageFlagsRequest) (response *ClearMessageFlagsResponse, err error) { response = &ClearMessageFlagsResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_clear_sel.go000066400000000000000000000025751474110527100222220ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 31.9 Clear SEL Command type ClearSELRequest struct { ReservationID uint16 // LS Byte first GetErasureStatusFlag bool } type ClearSELResponse struct { ErasureProgressStatus uint8 } func (req *ClearSELRequest) Pack() []byte { var out = make([]byte, 6) packUint16L(req.ReservationID, out, 0) packUint8('C', out, 2) // fixed 'C' char packUint8('L', out, 3) // fixed 'L' char packUint8('R', out, 4) // fixed 'R' char if req.GetErasureStatusFlag { packUint8(0x00, out, 5) // get erasure status } else { packUint8(0xaa, out, 5) // initiate erase } return out } func (req *ClearSELRequest) Command() Command { return CommandClearSEL } func (res *ClearSELResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } res.ErasureProgressStatus, _, _ = unpackUint8(msg, 0) return nil } func (res *ClearSELResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *ClearSELResponse) Format() string { return fmt.Sprintf("%v", res) } func (c *Client) ClearSEL(ctx context.Context, reservationID uint16) (response *ClearSELResponse, err error) { request := &ClearSELRequest{ ReservationID: reservationID, GetErasureStatusFlag: false, } response = &ClearSELResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_close_session.go000066400000000000000000000025201474110527100231270ustar00rootroot00000000000000package ipmi import "context" // 22.19 type CloseSessionRequest struct { // For IPMI v2.0/RMCP+ this is the Managed System Session ID value that was generated by the BMC, not the ID from the remote console. If Session ID = 0000_0000h then an implementation can optionally enable this command to take an additional byte of parameter data that allows a session handle to be used to close a session. SessionID uint32 // Session Handle. (only present if Session ID = 0000_0000h) SessionHandle uint8 } type CloseSessionResponse struct { } func (req *CloseSessionRequest) Pack() []byte { msg := make([]byte, 4) packUint32L(req.SessionID, msg, 0) if req.SessionID == 0 { msg = append(msg, 0) packUint8(req.SessionHandle, msg, 4) } return msg } func (req *CloseSessionRequest) Command() Command { return CommandCloseSession } func (res *CloseSessionResponse) Unpack(msg []byte) error { return nil } func (res *CloseSessionResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x87: "Invalid session id", 0x88: "Invalid session handle", } } func (res *CloseSessionResponse) Format() string { return "" } func (c *Client) CloseSession(ctx context.Context, request *CloseSessionRequest) (response *CloseSessionResponse, err error) { response = &CloseSessionResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_cold_reset.go000066400000000000000000000012631474110527100224050ustar00rootroot00000000000000package ipmi import "context" // 20.2 Cold Reset Command type ColdResetRequest struct { // empty } type ColdResetResponse struct { } func (req *ColdResetRequest) Command() Command { return CommandColdReset } func (req *ColdResetRequest) Pack() []byte { return []byte{} } func (res *ColdResetResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *ColdResetResponse) Unpack(msg []byte) error { return nil } func (res *ColdResetResponse) Format() string { return "" } func (c *Client) ColdReset(ctx context.Context) (err error) { request := &ColdResetRequest{} response := &ColdResetResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_delete_sel_entry.go000066400000000000000000000024701474110527100236110ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 31.8 Delete SEL Entry Command type DeleteSELEntryRequest struct { ReservationID uint16 RecordID uint16 } type DeleteSELEntryResponse struct { RecordID uint16 } func (req *DeleteSELEntryRequest) Command() Command { return CommandDeleteSELEntry } func (req *DeleteSELEntryRequest) Pack() []byte { out := make([]byte, 4) packUint16L(req.ReservationID, out, 0) packUint16L(req.RecordID, out, 2) return out } func (res *DeleteSELEntryResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.RecordID, _, _ = unpackUint16L(msg, 0) return nil } func (res *DeleteSELEntryResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "operation not supported for this Record Type", 0x81: "cannot execute command, SEL erase in progress", } } func (res *DeleteSELEntryResponse) Format() string { return fmt.Sprintf("Record ID : %d (%#02x)", res.RecordID, res.RecordID) } func (c *Client) DeleteSELEntry(ctx context.Context, recordID uint16, reservationID uint16) (response *DeleteSELEntryResponse, err error) { request := &DeleteSELEntryRequest{ ReservationID: reservationID, RecordID: recordID, } response = &DeleteSELEntryResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_enable_message_channel_receive.go000066400000000000000000000031201474110527100264000ustar00rootroot00000000000000package ipmi import "context" // 22.5 Enable Message Channel Receive Command type EnableMessageChannelReceiveRequest struct { ChannelNumber uint8 // [7:2] - reserved // [1:0] - 00b = disable channel // 01b = enable channel // 10b = get channel enable/disable state // 11b = reserved ChannelState uint8 } type EnableMessageChannelReceiveResponse struct { ChannelNumber uint8 ChannelEnabled bool } func (req *EnableMessageChannelReceiveRequest) Command() Command { return CommandEnableMessageChannelReceive } func (req *EnableMessageChannelReceiveRequest) Pack() []byte { out := make([]byte, 2) packUint8(req.ChannelNumber, out, 0) packUint8(req.ChannelState, out, 1) return out } func (res *EnableMessageChannelReceiveResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.ChannelNumber, _, _ = unpackUint8(msg, 0) b, _, _ := unpackUint8(msg, 1) res.ChannelEnabled = isBit0Set(b) return nil } func (*EnableMessageChannelReceiveResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *EnableMessageChannelReceiveResponse) Format() string { // Todo return "" } func (c *Client) EnableMessageChannelReceive(ctx context.Context, channelNumber uint8, channelState uint8) (response *EnableMessageChannelReceiveResponse, err error) { request := &EnableMessageChannelReceiveRequest{ ChannelNumber: channelNumber, ChannelState: channelState, } response = &EnableMessageChannelReceiveResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_acpi_power_state.go000066400000000000000000000025461474110527100244560ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 20.7 Get ACPI Power State Command type GetACPIPowerStateRequest struct { // empty } type GetACPIPowerStateResponse struct { SystemPowerState SystemPowerState DevicePowerState DevicePowerState } func (req *GetACPIPowerStateRequest) Pack() []byte { return nil } func (req *GetACPIPowerStateRequest) Command() Command { return CommandGetACPIPowerState } func (res *GetACPIPowerStateResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetACPIPowerStateResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } b1, _, _ := unpackUint8(msg, 0) res.SystemPowerState = SystemPowerState(b1 & 0x7f) b2, _, _ := unpackUint8(msg, 1) res.DevicePowerState = DevicePowerState(b2 & 0x7f) return nil } func (res *GetACPIPowerStateResponse) Format() string { return fmt.Sprintf(`ACPI System Power State: %s ACPI Device Power State: %s`, res.SystemPowerState, res.DevicePowerState, ) } // This command is provided to allow system software to tell a controller the present ACPI power state of the system. func (c *Client) GetACPIPowerState(ctx context.Context) (response *GetACPIPowerStateResponse, err error) { request := &GetACPIPowerStateRequest{} response = &GetACPIPowerStateResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_auth_code.go000066400000000000000000000015351474110527100230560ustar00rootroot00000000000000package ipmi // see 22.21 // // This command is used to send a block of data to the BMC, whereupon the BMC will // return a hash of the data together concatenated with the internally stored password for the given channel and user type GetAuthCodeRequest struct { AuthType AuthType ChannelNumber uint8 UserID uint8 // data to hash (must be 16 bytes) Data [16]byte } type GetAuthCodeResponse struct { CompletionCode // For IPMI v1.5 AuthCode Number: AuthCode [16]byte // ForIPMI v2.0 Integrity Algorithm Number // Resultant hash, per selected Integrity algorithm. Up to 20 bytes. An // implementation can elect to return a variable length field based on the size of // the hash for the given integrity algorithm, or can return a fixed field where the // hash data is followed by 00h bytes as needed to pad the data to 20 bytes. Hash []byte } golang-github-bougou-go-ipmi-0.7.2/cmd_get_bmc_global_enables.go000066400000000000000000000027661474110527100247040ustar00rootroot00000000000000package ipmi import "context" // 22.2 Get BMC Global Enables Command type GetBMCGlobalEnablesRequest struct { // empty } type GetBMCGlobalEnablesResponse struct { OEM2Enabled bool OEM1Enabled bool OEM0Enabled bool SystemEventLoggingEnabled bool EventMessageBufferEnabled bool EventMessageBufferFullInterruptEnabled bool ReceiveMessageQueueInterruptEnabled bool } func (req *GetBMCGlobalEnablesRequest) Command() Command { return CommandGetBMCGlobalEnables } func (req *GetBMCGlobalEnablesRequest) Pack() []byte { return []byte{} } func (res *GetBMCGlobalEnablesResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } b, _, _ := unpackUint8(msg, 0) res.OEM2Enabled = isBit7Set(b) res.OEM1Enabled = isBit6Set(b) res.OEM0Enabled = isBit5Set(b) res.SystemEventLoggingEnabled = isBit3Set(b) res.EventMessageBufferEnabled = isBit2Set(b) res.EventMessageBufferFullInterruptEnabled = isBit1Set(b) res.ReceiveMessageQueueInterruptEnabled = isBit0Set(b) return nil } func (*GetBMCGlobalEnablesResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetBMCGlobalEnablesResponse) Format() string { // Todo return "" } func (c *Client) GetBMCGlobalEnables(ctx context.Context) (response *GetBMCGlobalEnablesResponse, err error) { request := &GetBMCGlobalEnablesRequest{} response = &GetBMCGlobalEnablesResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_bt_interface_capabilities.go000066400000000000000000000030401474110527100262520ustar00rootroot00000000000000package ipmi import "context" // 22.10 Get BT Interface Capabilities Command type GetBTInterfaceCapabilitiesRequest struct { // empty } type GetBTInterfaceCapabilitiesResponse struct { OutstandingRequestsCountSupported uint8 InputBufferMessageSizeBytes uint8 OutputBufferMessageSizeBytes uint8 BMCRequestToResponseTimeSec uint8 RecommendedRetries uint8 } func (req *GetBTInterfaceCapabilitiesRequest) Command() Command { return CommandGetBTInterfaceCapabilities } func (req *GetBTInterfaceCapabilitiesRequest) Pack() []byte { return []byte{} } func (res *GetBTInterfaceCapabilitiesResponse) Unpack(msg []byte) error { // at least 3 bytes if len(msg) < 5 { return ErrUnpackedDataTooShortWith(len(msg), 5) } res.OutstandingRequestsCountSupported, _, _ = unpackUint8(msg, 0) res.InputBufferMessageSizeBytes, _, _ = unpackUint8(msg, 1) res.OutputBufferMessageSizeBytes, _, _ = unpackUint8(msg, 2) res.BMCRequestToResponseTimeSec, _, _ = unpackUint8(msg, 3) res.RecommendedRetries, _, _ = unpackUint8(msg, 4) return nil } func (*GetBTInterfaceCapabilitiesResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetBTInterfaceCapabilitiesResponse) Format() string { return "" } func (c *Client) GetBTInterfaceCapabilities(ctx context.Context) (response *GetBTInterfaceCapabilitiesResponse, err error) { request := &GetBTInterfaceCapabilitiesRequest{} response = &GetBTInterfaceCapabilitiesResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_channel_access.go000066400000000000000000000041321474110527100240500ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 22.23 Get Channel Access Command type GetChannelAccessRequest struct { ChannelNumber uint8 AccessOption ChannelAccessOption } type GetChannelAccessResponse struct { PEFAlertingDisabled bool PerMsgAuthDisabled bool UserLevelAuthDisabled bool AccessMode ChannelAccessMode MaxPrivilegeLevel PrivilegeLevel } func (req *GetChannelAccessRequest) Pack() []byte { out := make([]byte, 2) packUint8(req.ChannelNumber, out, 0) packUint8(uint8(req.AccessOption)<<6, out, 1) return out } func (req *GetChannelAccessRequest) Command() Command { return CommandGetChannelAccess } func (res *GetChannelAccessResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x82: "set not supported on selected channel (e.g. channel is session-less.)", 0x83: "access mode not supported", } } func (res *GetChannelAccessResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } b0, _, _ := unpackUint8(msg, 0) res.PEFAlertingDisabled = isBit5Set(b0) res.PerMsgAuthDisabled = isBit4Set(b0) res.UserLevelAuthDisabled = isBit3Set(b0) res.AccessMode = ChannelAccessMode(b0 & 0x07) b1, _, _ := unpackUint8(msg, 1) res.MaxPrivilegeLevel = PrivilegeLevel(b1 & 0x0f) return nil } func (res *GetChannelAccessResponse) Format() string { return fmt.Sprintf(` Alerting : %s Per-message Auth : %s User Level Auth : %s Access Mode : %s Max Privilege Level : %s`, formatBool(res.PEFAlertingDisabled, "disabled", "enabled"), formatBool(res.PerMsgAuthDisabled, "disabled", "enabled"), formatBool(res.UserLevelAuthDisabled, "disabled", "enabled"), res.AccessMode, res.MaxPrivilegeLevel.String(), ) } func (c *Client) GetChannelAccess(ctx context.Context, channelNumber uint8, accessOption ChannelAccessOption) (response *GetChannelAccessResponse, err error) { request := &GetChannelAccessRequest{ ChannelNumber: channelNumber, AccessOption: accessOption, } response = &GetChannelAccessResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_channel_authentication_capabilities.go000066400000000000000000000163301474110527100303420ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 13.14 // 22.13 type GetChannelAuthenticationCapabilitiesRequest struct { // [7] // - 1b = get IPMI v2.0+ extended data. // If the given channel supports authentication but does not support RMCP+ // (e.g. a serial channel), then the Response data should return with bit [5] of byte 4 = 0b, byte 5 should return 01h, // // - 0b = Backward compatible with IPMI v1.5. Response data only returns // bytes 1:9, bit [7] of byte 3 (Authentication Type Support) and bit [5] of byte 4 returns as 0b, bit [5] of byte byte 5 returns 00h. // [6:4] - reserved IPMIv20Extended bool // [3:0] - channel number. // 0h-Bh, Fh = channel numbers // Eh = retrieve information for channel this request was issued on ChannelNumber uint8 // Requested Maximum Privilege Level MaximumPrivilegeLevel PrivilegeLevel } type GetChannelAuthenticationCapabilitiesResponse struct { // Channel number that the Authentication Capabilities is being returned for. // If the channel number in the request was set to Eh, this will return // the channel number for the channel that the request was received on ChannelNumber uint8 // Returns the setting of the Authentication Type Enable field from the // configuration parameters for the given channel that corresponds to // the Requested Maximum Privilege Level. // [7] - // 1b = IPMI v2.0+ extended capabilities available. See Extended Capabilities field, below. // 0b = IPMI v1.5 support only. IPMIv20ExtendedAvailable bool // [5:0] - IPMI v1.5 Authentication type(s) enabled for given Requested Maximum Privilege Level AuthTypeNoneSupported bool // bit 0 AuthTypeMD2Supported bool // bit 1 AuthTypeMD5Supported bool // bit 2 AuthTypePasswordSupported bool // bit 4 AuthTypeOEMProprietarySupported bool // bit 5 // [5] - Kg status (two-key login status). // Applies to v2.0/RMCP+ RAKP Authentication only. Otherwise, ignore as reserved. // 0b = Kg is set to default (all 0s). // 1b = Kg is set to non-zero value. KgStatus bool // [4] - Per-message Authentication status // 0b = Per-message Authentication is enabled. // 1b = Per-message Authentication is disabled. // Authentication Type "none" accepted for packets to the BMC after the session has been activated. PerMessageAuthenticationDisabled bool // [3] - User Level Authentication status // 0b = User Level Authentication is enabled. // 1b = User Level Authentication is disabled. // Authentication Type "none" accepted for User Level commands to the BMC. UserLevelAuthenticationDisabled bool // [2:0] - Anonymous Login status // This parameter returns values that tells the remote console whether // there are users on the system that have "null" usernames. // This can be used to guide the way the remote console presents login options to the user. // (see IPMI v1.5 specification sections 6.9.1, "Anonymous Login" Convention and 6.9.2, Anonymous Login ) // [2] - 1b = Non-null usernames enabled. (One or more users are enabled that have non-null usernames). // [1] - 1b = Null usernames enabled (One or more users that have a null username, but non-null password, are presently enabled) // [0] - 1b = Anonymous Login enabled (A user that has a null username and null password is presently enabled) NonNullUsernamesEnabled bool NullUsernamesEnabled bool AnonymousLoginEnabled bool // For IPMI v1.5: - reserved // For IPMI v2.0+: - Extended Capabilities // [7:2] - reserved // [1] - 1b = channel supports IPMI v2.0 connections. // [0] - 1b = channel supports IPMI v1.5 connections. SupportIPMIv15 bool SupportIPMIv20 bool // IANA Enterprise Number for OEM/Organization that specified the particular // OEM Authentication Type for RMCP. Least significant byte first. // ONLY 3 bytes occupied. Return 00h, 00h, 00h if no OEM authentication type available. OEMID uint32 // Additional OEM-specific information for the OEM Authentication Type for RMCP. // Return 00h if no OEM authentication type available. OEMAuxiliaryData uint8 } func (req *GetChannelAuthenticationCapabilitiesRequest) Pack() []byte { var msg = make([]byte, 2) byte1 := req.ChannelNumber if req.IPMIv20Extended { byte1 = byte1 | 0x80 } packUint8(byte1, msg, 0) packUint8(uint8(req.MaximumPrivilegeLevel), msg, 1) return msg } func (req *GetChannelAuthenticationCapabilitiesRequest) Command() Command { return CommandGetChannelAuthCapabilities } func (res *GetChannelAuthenticationCapabilitiesResponse) Unpack(msg []byte) error { if len(msg) < 8 { return ErrUnpackedDataTooShortWith(len(msg), 8) } res.ChannelNumber, _, _ = unpackUint8(msg, 0) b, _, _ := unpackUint8(msg, 1) res.IPMIv20ExtendedAvailable = isBit7Set(b) res.AuthTypeOEMProprietarySupported = isBit5Set(b) res.AuthTypePasswordSupported = isBit4Set(b) res.AuthTypeMD5Supported = isBit2Set(b) res.AuthTypeMD2Supported = isBit1Set(b) c, _, _ := unpackUint8(msg, 2) res.KgStatus = isBit5Set(c) res.PerMessageAuthenticationDisabled = isBit4Set(c) res.UserLevelAuthenticationDisabled = isBit3Set(c) res.NonNullUsernamesEnabled = isBit2Set(c) res.NullUsernamesEnabled = isBit1Set(c) res.AnonymousLoginEnabled = isBit0Set(c) d, _, _ := unpackUint8(msg, 3) if res.IPMIv20ExtendedAvailable { res.SupportIPMIv20 = isBit1Set(d) res.SupportIPMIv15 = isBit0Set(d) } res.OEMID, _, _ = unpackUint24L(msg, 4) res.OEMAuxiliaryData, _, _ = unpackUint8(msg, 7) return nil } func (*GetChannelAuthenticationCapabilitiesResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetChannelAuthenticationCapabilitiesResponse) chooseAuthType() AuthType { if res.AuthTypeMD2Supported { return AuthTypeMD2 } if res.AuthTypeMD5Supported { return AuthTypeMD5 } if res.AuthTypePasswordSupported { return AuthTypePassword } if res.AuthTypeOEMProprietarySupported { return AuthTypeOEM } if res.AuthTypeNoneSupported { return AuthTypeNone } return AuthTypeNone } func (res *GetChannelAuthenticationCapabilitiesResponse) Format() string { return fmt.Sprintf("%v", res) } // GetChannelAuthenticationCapabilities is used to retrieve capability information // about the channel that the message is delivered over, or for a particular channel. // The command returns the authentication algorithm support for the given privilege level. // // This command is sent in unauthenticated (clear) format. // // When activating a session, the privilege level passed in this command will // normally be the same Requested Maximum Privilege level that will be used // for a subsequent Activate Session command. func (c *Client) GetChannelAuthenticationCapabilities(ctx context.Context, channelNumber uint8, privilegeLevel PrivilegeLevel) (response *GetChannelAuthenticationCapabilitiesResponse, err error) { request := &GetChannelAuthenticationCapabilitiesRequest{ IPMIv20Extended: true, ChannelNumber: channelNumber, MaximumPrivilegeLevel: privilegeLevel, } response = &GetChannelAuthenticationCapabilitiesResponse{} err = c.Exchange(ctx, request, response) if err != nil { return } if !response.AnonymousLoginEnabled { if c.Username == "" { return nil, fmt.Errorf("anonymous login is not enabled, username (%s) is empty", c.Username) } } c.session.authType = response.chooseAuthType() return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_channel_cipher_suites.go000066400000000000000000000104551474110527100254620ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) const ( MaxCipherSuiteListIndex uint8 = 0x3f ) // 22.15 Get Channel Cipher Suites Command type GetChannelCipherSuitesRequest struct { // 0h-Bh, Fh = channel numbers // Eh = retrieve information for channel this request was issued on ChannelNumber uint8 PayloadType PayloadType ListIndex uint8 } type GetChannelCipherSuitesResponse struct { ChannelNumber uint8 CipherSuiteRecords []byte } func (req *GetChannelCipherSuitesRequest) Command() Command { return CommandGetChannelCipherSuites } func (req *GetChannelCipherSuitesRequest) Pack() []byte { var msg = make([]byte, 3) packUint8(req.ChannelNumber, msg, 0) packUint8(uint8(req.PayloadType), msg, 1) packUint8(LIST_ALGORITHMS_BY_CIPHER_SUITE|req.ListIndex, msg, 2) return msg } func (res *GetChannelCipherSuitesResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } res.ChannelNumber, _, _ = unpackUint8(msg, 0) if len(msg) > 1 { res.CipherSuiteRecords, _, _ = unpackBytesMost(msg, 1, 16) } return nil } func (*GetChannelCipherSuitesResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetChannelCipherSuitesResponse) Format() string { return fmt.Sprintf("%v", res) } // This command can be executed prior to establishing a session with the BMC. // The command is used to look up what authentication, integrity, and confidentiality algorithms are supported. // The algorithms are used in combination as 'Cipher Suites'. // This command only applies to implementations that support IPMI v2.0/RMCP+ sessions. func (c *Client) GetChannelCipherSuites(ctx context.Context, channelNumber uint8, index uint8) (response *GetChannelCipherSuitesResponse, err error) { request := &GetChannelCipherSuitesRequest{ ChannelNumber: channelNumber, PayloadType: PayloadTypeIPMI, ListIndex: index, } response = &GetChannelCipherSuitesResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetAllChannelCipherSuites(ctx context.Context, channelNumber uint8) ([]CipherSuiteRecord, error) { var index uint8 = 0 var cipherSuitesData = make([]byte, 0) for ; index < MaxCipherSuiteListIndex; index++ { res, err := c.GetChannelCipherSuites(ctx, channelNumber, index) if err != nil { return nil, fmt.Errorf("cmd GetChannelCipherSuites failed, err: %w", err) } cipherSuitesData = append(cipherSuitesData, res.CipherSuiteRecords...) if len(res.CipherSuiteRecords) < 16 { break } } c.DebugBytes("cipherSuitesData", cipherSuitesData, 16) return parseCipherSuitesData(cipherSuitesData) } func parseCipherSuitesData(cipherSuitesData []byte) ([]CipherSuiteRecord, error) { offset := 0 records := []CipherSuiteRecord{} for offset < len(cipherSuitesData) { csRecord := CipherSuiteRecord{} startOfRecord := cipherSuitesData[offset] csRecord.StartOfRecord = startOfRecord switch startOfRecord { case StandardCipherSuite: // id + 3 algs (4 bytes) if offset+4 > len(cipherSuitesData)-1 { return records, fmt.Errorf("incomplete cipher suite data") } offset++ csRecord.CipherSuitID = CipherSuiteID(cipherSuitesData[offset]) case OEMCipherSuite: // id + iana (3) + 3 algs (7 bytes) if offset+7 > len(cipherSuitesData)-1 { return records, fmt.Errorf("incomplete cipher suite data") } offset++ csRecord.CipherSuitID = CipherSuiteID(cipherSuitesData[offset]) offset++ csRecord.OEMIanaID, _, _ = unpackUint24L(cipherSuitesData, offset) default: return records, fmt.Errorf("bad start of record byte in the cipher suite data, value %x", startOfRecord) } for { offset++ if offset > len(cipherSuitesData)-1 { break } algByte := cipherSuitesData[offset] if algByte == StandardCipherSuite || algByte == OEMCipherSuite { break } algTag := algByte & CipherAlgTagBitMask // clear lowest 6 bits algNumber := algByte & CipherAlgMask // clear highest 2 bits switch algTag { case CipherAlgTagBitAuthMask: csRecord.AuthAlg = algNumber case CipherAlgTagBitIntegrityMask: csRecord.IntegrityAlgs = append(csRecord.IntegrityAlgs, algNumber) case CipherAlgTagBitEncryptionMask: csRecord.CryptAlgs = append(csRecord.CryptAlgs, algNumber) } } records = append(records, csRecord) } return records, nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_channel_info.go000066400000000000000000000054531474110527100235510ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 22.24 Get Channel Info Command type GetChannelInfoRequest struct { ChannelNumber uint8 } type GetChannelInfoResponse struct { ActualChannelNumber uint8 ChannelMedium ChannelMedium // Channel Medium Type Numbers ChannelProtocol ChannelProtocol // Channel Protocol Type Numbers SessionSupport uint8 ActiveSessionCount uint8 VendorID uint32 // (IANA Enterprise Number) for OEM/Organization that specified the Channel Protocol. // Auxiliary Channel Info Auxiliary []byte // Auxiliary Channel Info Raw Data, 2 bytes // For Channel = Fh (System Interface) SMSInterruptType InterruptType EventMessageBufferInterruptType InterruptType } type InterruptType uint8 func (typ InterruptType) String() string { if typ <= 0x0f { return fmt.Sprintf("IRQ %d", uint8(typ)) } if typ >= 0x10 && typ <= 0x13 { return fmt.Sprintf("PCI %X", uint8(typ)) } if typ == 0x14 { return "SMI" } if typ == 0x15 { return "SCI" } if typ >= 20 && typ <= 0x5f { return fmt.Sprintf("system interrupt %d", uint8(typ-32)) } if typ == 0x60 { return "assigned by ACPI / Plug in Play BIOS" } if typ == 0xff { return "no interrupt" } return "reserved" } func (req *GetChannelInfoRequest) Pack() []byte { return []byte{req.ChannelNumber} } func (req *GetChannelInfoRequest) Command() Command { return CommandGetChannelInfo } func (res *GetChannelInfoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetChannelInfoResponse) Unpack(msg []byte) error { if len(msg) < 9 { return ErrUnpackedDataTooShortWith(len(msg), 9) } res.ActualChannelNumber, _, _ = unpackUint8(msg, 0) cm, _, _ := unpackUint8(msg, 1) res.ChannelMedium = ChannelMedium(cm) cp, _, _ := unpackUint8(msg, 2) res.ChannelProtocol = ChannelProtocol(cp) s, _, _ := unpackUint8(msg, 3) res.SessionSupport = s >> 6 res.ActiveSessionCount = s & 0x3f res.VendorID, _, _ = unpackUint24L(msg, 4) res.Auxiliary, _, _ = unpackBytes(msg, 7, 2) res.SMSInterruptType = InterruptType(res.Auxiliary[0]) res.EventMessageBufferInterruptType = InterruptType(res.Auxiliary[1]) return nil } func (res *GetChannelInfoResponse) Format() string { return fmt.Sprintf(`Channel %#02x info: Channel Medium Type : %s Channel Protocol Type : %s Session Support : %d Active Session Count : %d Protocol Vendor ID : %d`, res.ActualChannelNumber, res.ChannelMedium, res.ChannelProtocol, res.SessionSupport, res.ActiveSessionCount, res.VendorID, ) } func (c *Client) GetChannelInfo(ctx context.Context, channelNumber uint8) (response *GetChannelInfoResponse, err error) { request := &GetChannelInfoRequest{ ChannelNumber: channelNumber, } response = &GetChannelInfoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_chassis_capabilities.go000066400000000000000000000035001474110527100252630ustar00rootroot00000000000000package ipmi import "context" // 28.1 Get Chassis Capabilities Command type GetChassisCapabilitiesRequest struct { // empty } type GetChassisCapabilitiesResponse struct { ProvidePowerInterlock bool ProvideDiagnosticInterrupt bool ProvideFrontPanelLockout bool ProvideIntrusionSensor bool // Chassis FRU Device FRUDeviceAddress uint8 SDRDeviceAddress uint8 SELDeviceAddress uint8 SystemManagementDeviceAddress uint8 // If this field is not provided, the address is assumed to be the BMC address (20h). BridgeDeviceAddress uint8 } func (req *GetChassisCapabilitiesRequest) Pack() []byte { return []byte{} } func (req *GetChassisCapabilitiesRequest) Command() Command { return CommandGetChassisCapabilities } func (res *GetChassisCapabilitiesResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetChassisCapabilitiesResponse) Unpack(msg []byte) error { if len(msg) < 5 { return ErrUnpackedDataTooShortWith(len(msg), 5) } b1, _, _ := unpackUint8(msg, 0) res.ProvidePowerInterlock = isBit3Set(b1) res.ProvideDiagnosticInterrupt = isBit2Set(b1) res.ProvideFrontPanelLockout = isBit1Set(b1) res.ProvideIntrusionSensor = isBit0Set(b1) res.FRUDeviceAddress, _, _ = unpackUint8(msg, 1) res.SDRDeviceAddress, _, _ = unpackUint8(msg, 2) res.SELDeviceAddress, _, _ = unpackUint8(msg, 3) res.SystemManagementDeviceAddress, _, _ = unpackUint8(msg, 4) if len(msg) == 6 { res.BridgeDeviceAddress, _, _ = unpackUint8(msg, 5) } return nil } func (res *GetChassisCapabilitiesResponse) Format() string { return "todo" } func (c *Client) GetChassisCapabilities(ctx context.Context) (response *GetChassisCapabilitiesResponse, err error) { request := &GetChassisCapabilitiesRequest{} response = &GetChassisCapabilitiesResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_chassis_status.go000066400000000000000000000147531474110527100241710ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 28.2 Get Chassis Status Command type GetChassisStatusRequest struct { // empty } type GetChassisStatusResponse struct { // Current Power State PowerRestorePolicy PowerRestorePolicy PowerControlFault bool // Controller attempted to turn system power on or off, but system did not enter desired state. PowerFault bool // fault detected in main power subsystem InterLock bool // chassis is presently shut down because a chassis panel interlock switch is active PowerOverload bool // system shutdown because of power overload condition. PowerIsOn bool // 系统电源:上电 // Last Power Event LastPowerOnByCommand bool LastPowerDownByPowerFault bool LastPowerDownByPowerInterlockActivated bool LastPowerDownByPowerOverload bool ACFailed bool // Last Power Event // Misc. Chassis State ChassisIdentifySupported bool ChassisIdentifyState ChassisIdentifyState CollingFanFault bool DriveFault bool FrontPanelLockoutActive bool // (power off and reset via chassis push-buttons disabled. 前面板锁定) ChassisIntrusionActive bool // 机箱入侵:(机箱盖被打开) // Front Panel Button Capabilities and disable/enable status (Optional) SleepButtonDisableAllowed bool DiagnosticButtonDisableAllowed bool ResetButtonDisableAllowed bool PoweroffButtonDisableAllowed bool SleepButtonDisabled bool DiagnosticButtonDisabled bool ResetButtonDisabled bool PoweroffButtonDisabled bool } type ChassisIdentifyState uint8 const ( ChassisIdentifyStateOff ChassisIdentifyState = 0 ChassisIdentifyStateTemporaryOn ChassisIdentifyState = 1 ChassisIdentifyStateIndefiniteOn ChassisIdentifyState = 2 ) func (c ChassisIdentifyState) String() string { m := map[ChassisIdentifyState]string{ 0: "Off", 1: "Temporary (timed) On", 2: "Indefinite On", } s, ok := m[c] if ok { return s } return "reserved" } // PowerRestorePolicy // 通电开机策略 type PowerRestorePolicy uint8 const ( PowerRestorePolicyAlwaysOff PowerRestorePolicy = 0 // 保持下电(关机) PowerRestorePolicyPrevious PowerRestorePolicy = 1 // 与之前保持一致(恢复断电前状态) PowerRestorePolicyAlwaysOn PowerRestorePolicy = 2 // 保持上电(开机) ) var SupportedPowerRestorePolicies = []string{ "always-off", "always-on", "previous", } func (p PowerRestorePolicy) String() string { m := map[PowerRestorePolicy]string{ 0: "always-off", // chassis stays powered off after AC/mains returns 1: "previous", // after AC returns, power is restored to the state that was in effect when AC/mains was lost 2: "always-on", // chassis always powers up after AC/mains returns } s, ok := m[p] if ok { return s } return "unknown" } func (req *GetChassisStatusRequest) Pack() []byte { return []byte{} } func (req *GetChassisStatusRequest) Command() Command { return CommandGetChassisStatus } func (res *GetChassisStatusResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetChassisStatusResponse) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } b1, _, _ := unpackUint8(msg, 0) // first clear bit 7, then shift right 5 bits b := (b1 & 0x7f) >> 5 res.PowerRestorePolicy = PowerRestorePolicy(b) res.PowerControlFault = isBit4Set(b1) res.PowerFault = isBit3Set(b1) res.InterLock = isBit2Set(b1) res.PowerOverload = isBit1Set(b1) res.PowerIsOn = isBit0Set(b1) b2, _, _ := unpackUint8(msg, 1) res.LastPowerOnByCommand = isBit4Set(b2) res.LastPowerDownByPowerFault = isBit3Set(b2) res.LastPowerDownByPowerInterlockActivated = isBit2Set(b2) res.LastPowerDownByPowerOverload = isBit1Set(b2) res.ACFailed = isBit0Set(b2) b3, _, _ := unpackUint8(msg, 2) res.ChassisIdentifySupported = isBit6Set(b3) res.ChassisIdentifyState = ChassisIdentifyState((b3 & 0x30) >> 4) res.CollingFanFault = isBit3Set(b3) res.DriveFault = isBit2Set(b3) res.FrontPanelLockoutActive = isBit1Set(b3) res.ChassisIntrusionActive = isBit0Set(b3) if len(msg) == 4 { b4, _, _ := unpackUint8(msg, 3) res.SleepButtonDisableAllowed = isBit7Set(b4) res.DiagnosticButtonDisableAllowed = isBit6Set(b4) res.ResetButtonDisableAllowed = isBit5Set(b4) res.PoweroffButtonDisableAllowed = isBit4Set(b4) res.SleepButtonDisabled = isBit3Set(b4) res.DiagnosticButtonDisabled = isBit2Set(b4) res.ResetButtonDisabled = isBit1Set(b4) res.PoweroffButtonDisabled = isBit0Set(b4) } return nil } func (res *GetChassisStatusResponse) Format() string { return "System Power : " + formatBool(res.PowerIsOn, "on", "off") + "\n" + "Power Overload : " + fmt.Sprintf("%v", res.PowerOverload) + "\n" + "Power Interlock : " + formatBool(res.InterLock, "active", "inactive") + "\n" + "Main Power Fault : " + fmt.Sprintf("%v", res.PowerFault) + "\n" + "Power Control Fault : " + fmt.Sprintf("%v", res.PowerControlFault) + "\n" + "Power Restore Policy : " + res.PowerRestorePolicy.String() + "\n" + "Last Power Event : " + formatBool(res.ChassisIntrusionActive, "active", "inactive") + "\n" + "Chassis Intrusion : " + formatBool(res.ChassisIntrusionActive, "active", "inactive") + "\n" + "Front-Panel Lockout : " + formatBool(res.FrontPanelLockoutActive, "active", "inactive") + "\n" + "Drive Fault : " + fmt.Sprintf("%v", res.DriveFault) + "\n" + "Cooling/Fan Fault : " + fmt.Sprintf("%v", res.CollingFanFault) + "\n" + "Sleep Button Disable : " + formatBool(res.SleepButtonDisableAllowed, "allowed", "disallowed") + "\n" + "Diag Button Disable : " + formatBool(res.DiagnosticButtonDisableAllowed, "allowed", "disallowed") + "\n" + "Reset Button Disable : " + formatBool(res.ResetButtonDisableAllowed, "allowed", "disallowed") + "\n" + "Power Button Disable : " + formatBool(res.PoweroffButtonDisableAllowed, "allowed", "disallowed") + "\n" + "Sleep Button Disabled: " + fmt.Sprintf("%v", res.SleepButtonDisabled) + "\n" + "Diag Button Disabled : " + fmt.Sprintf("%v", res.DiagnosticButtonDisabled) + "\n" + "Reset Button Disabled: " + fmt.Sprintf("%v", res.ResetButtonDisabled) + "\n" + "Power Button Disabled: " + fmt.Sprintf("%v", res.PoweroffButtonDisabled) } func (c *Client) GetChassisStatus(ctx context.Context) (response *GetChassisStatusResponse, err error) { request := &GetChassisStatusRequest{} response = &GetChassisStatusResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_command_enables.go000066400000000000000000000034561474110527100242360ustar00rootroot00000000000000package ipmi import "context" // 21.8 Get Command Enables Command type GetCommandEnablesRequest struct { ChannelNumber uint8 CommandRangeMask CommandRangeMask NetFn NetFn LUN uint8 CodeForNetFn2C uint8 OEM_IANA uint32 // 3 bytes only } type GetCommandEnablesResponse struct { // Todo CommandEnableMask []byte } func (req *GetCommandEnablesRequest) Command() Command { return CommandGetCommandEnables } func (req *GetCommandEnablesRequest) Pack() []byte { out := make([]byte, 6) packUint8(req.ChannelNumber, out, 0) netfn := uint8(req.NetFn) & (uint8(req.CommandRangeMask) << 6) packUint8(netfn, out, 1) packUint8(req.LUN&0x03, out, 2) if uint8(req.NetFn) == 0x2c { packUint8(req.CodeForNetFn2C, out, 3) return out[0:4] } if uint8(req.NetFn) == 0x2e { packUint24L(req.OEM_IANA, out, 3) return out[0:6] } return out[0:3] } func (res *GetCommandEnablesResponse) Unpack(msg []byte) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } res.CommandEnableMask, _, _ = unpackBytes(msg, 0, 16) return nil } func (*GetCommandEnablesResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetCommandEnablesResponse) Format() string { // Todo return "" } func (c *Client) GetCommandEnables(ctx context.Context, channelNumber uint8, commandRangeMask CommandRangeMask, netFn NetFn, lun uint8, code uint8, oemIANA uint32) (response *GetCommandEnablesResponse, err error) { request := &GetCommandEnablesRequest{ ChannelNumber: channelNumber, CommandRangeMask: commandRangeMask, NetFn: netFn, LUN: lun, CodeForNetFn2C: code, OEM_IANA: oemIANA, } response = &GetCommandEnablesResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_command_subfunction_support.go000066400000000000000000000042051474110527100267510ustar00rootroot00000000000000package ipmi import "context" // 21.4 Get Command Sub-function Support Command type GetCommandSubfunctionSupportRequest struct { ChannelNumber uint8 NetFn NetFn LUN uint8 Cmd uint8 CodeForNetFn2C uint8 OEM_IANA uint32 // 3 bytes only } type GetCommandSubfunctionSupportResponse struct { SpecificationType uint8 ErrataVersion uint8 OEMGroupBody uint8 SpecificationVersion uint8 SpecificationRevision uint8 // Todo SupportMask []byte } func (req *GetCommandSubfunctionSupportRequest) Command() Command { return CommandGetCommandSubfunctionSupport } func (req *GetCommandSubfunctionSupportRequest) Pack() []byte { out := make([]byte, 7) packUint8(req.ChannelNumber, out, 0) packUint8(uint8(req.NetFn)&0x3f, out, 1) packUint8(req.LUN&0x03, out, 2) packUint8(req.Cmd, out, 3) if uint8(req.NetFn) == 0x2c { packUint8(req.CodeForNetFn2C, out, 4) return out[0:5] } if uint8(req.NetFn) == 0x2e { packUint24L(req.OEM_IANA, out, 4) return out[0:7] } return out[0:4] } func (res *GetCommandSubfunctionSupportResponse) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } b, _, _ := unpackUint8(msg, 0) res.SpecificationType = b >> 4 res.ErrataVersion = b & 0x0f res.OEMGroupBody = b res.SpecificationVersion, _, _ = unpackUint8(msg, 1) res.SpecificationRevision, _, _ = unpackUint8(msg, 2) res.SupportMask, _, _ = unpackBytes(msg, 3, 4) return nil } func (*GetCommandSubfunctionSupportResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetCommandSubfunctionSupportResponse) Format() string { // Todo return "" } func (c *Client) GetCommandSubfunctionSupport(ctx context.Context, channelNumber uint8, netFn NetFn, lun uint8, code uint8, oemIANA uint32) (response *GetCommandSubfunctionSupportResponse, err error) { request := &GetCommandSubfunctionSupportRequest{ ChannelNumber: channelNumber, NetFn: netFn, LUN: lun, CodeForNetFn2C: code, OEM_IANA: oemIANA, } response = &GetCommandSubfunctionSupportResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_command_support.go000066400000000000000000000036361474110527100243410ustar00rootroot00000000000000package ipmi import "context" // 21.3 Get Command Support Command type GetCommandSupportRequest struct { ChannelNumber uint8 CommandRangeMask CommandRangeMask NetFn NetFn LUN uint8 CodeForNetFn2C uint8 OEM_IANA uint32 // 3 bytes only } type GetCommandSupportResponse struct { // Todo CommandSupportMask []byte } type CommandRangeMask uint8 const ( CommandRangeMask007F uint8 = 0x00 CommandRangeMask80FF uint8 = 0x01 ) func (req *GetCommandSupportRequest) Command() Command { return CommandGetCommandSupport } func (req *GetCommandSupportRequest) Pack() []byte { out := make([]byte, 6) packUint8(req.ChannelNumber, out, 0) netfn := uint8(req.NetFn) & (uint8(req.CommandRangeMask) << 6) packUint8(netfn, out, 1) packUint8(req.LUN&0x03, out, 2) if uint8(req.NetFn) == 0x2c { packUint8(req.CodeForNetFn2C, out, 3) return out[0:4] } if uint8(req.NetFn) == 0x2e { packUint24L(req.OEM_IANA, out, 3) return out[0:6] } return out[0:3] } func (res *GetCommandSupportResponse) Unpack(msg []byte) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } res.CommandSupportMask, _, _ = unpackBytes(msg, 0, 16) return nil } func (*GetCommandSupportResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetCommandSupportResponse) Format() string { // Todo return "" } func (c *Client) GetCommandSupport(ctx context.Context, channelNumber uint8, commandRangeMask CommandRangeMask, netFn NetFn, lun uint8, code uint8, oemIANA uint32) (response *GetCommandSupportResponse, err error) { request := &GetCommandSupportRequest{ ChannelNumber: channelNumber, CommandRangeMask: commandRangeMask, NetFn: netFn, LUN: lun, CodeForNetFn2C: code, OEM_IANA: oemIANA, } response = &GetCommandSupportResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_configurable_commands.go000066400000000000000000000035761474110527100254530ustar00rootroot00000000000000package ipmi import "context" // 21.5 Get Configurable Commands Command type GetConfigurableCommandsRequest struct { ChannelNumber uint8 CommandRangeMask CommandRangeMask NetFn NetFn LUN uint8 CodeForNetFn2C uint8 OEM_IANA uint32 // 3 bytes only } type GetConfigurableCommandsResponse struct { // Todo CommandSupportMask []byte } func (req *GetConfigurableCommandsRequest) Command() Command { return CommandGetConfigurableCommands } func (req *GetConfigurableCommandsRequest) Pack() []byte { out := make([]byte, 6) packUint8(req.ChannelNumber, out, 0) netfn := uint8(req.NetFn) & (uint8(req.CommandRangeMask) << 6) packUint8(netfn, out, 1) packUint8(req.LUN&0x03, out, 2) if uint8(req.NetFn) == 0x2c { packUint8(req.CodeForNetFn2C, out, 3) return out[0:4] } if uint8(req.NetFn) == 0x2e { packUint24L(req.OEM_IANA, out, 3) return out[0:6] } return out[0:3] } func (res *GetConfigurableCommandsResponse) Unpack(msg []byte) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } res.CommandSupportMask, _, _ = unpackBytes(msg, 0, 16) return nil } func (*GetConfigurableCommandsResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetConfigurableCommandsResponse) Format() string { // Todo return "" } func (c *Client) GetConfigurableCommands(ctx context.Context, channelNumber uint8, commandRangeMask CommandRangeMask, netFn NetFn, lun uint8, code uint8, oemIANA uint32) (response *GetConfigurableCommandsResponse, err error) { request := &GetConfigurableCommandsRequest{ ChannelNumber: channelNumber, CommandRangeMask: commandRangeMask, NetFn: netFn, LUN: lun, CodeForNetFn2C: code, OEM_IANA: oemIANA, } response = &GetConfigurableCommandsResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_dcmi_asset_tag.go000066400000000000000000000064401474110527100240710ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // GetDCMIAssetTagRequest represents a "Get Asset Tag" request according // to section 6.4.2 of the [DCMI specification v1.5]. // // While the asset tag is allowed to be up to 64 bytes, each request will always // return at most 16 bytes. The response also indicates the total length of the // asset tag. If it is greater than 16 bytes, additional requests have to be // performed, setting the offset accordingly. // // [DCMI specification v1.5]: https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/dcmi-v1-5-rev-spec.pdf type GetDCMIAssetTagRequest struct { Offset uint8 } type GetDCMIAssetTagResponse struct { // At most 16 bytes of the asset tag, starting from the request's offset AssetTag []byte // The total length of the asset tag TotalLength uint8 } func (req *GetDCMIAssetTagRequest) Pack() []byte { // Number of bytes to read (16 bytes maximum) // using the fixed (maximum) value is OK here. var readBytes = uint8(0x10) return []byte{GroupExtensionDCMI, req.Offset, readBytes} } func (req *GetDCMIAssetTagRequest) Command() Command { return CommandGetDCMIAssetTag } func (res *GetDCMIAssetTagResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "Encoding type in FRU is binary / unspecified", 0x81: "Encoding type in FRU is BCD Plus", 0x82: "Encoding type in FRU is 6-bit ASCII Packed", 0x83: "Encoding type in FRU is set to ASCII+Latin1, but language code is not set to English (indicating data is 2-byte UNICODE)", } } func (res *GetDCMIAssetTagResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } res.TotalLength, _, _ = unpackUint8(msg, 1) if len(msg) > 2 { res.AssetTag, _, _ = unpackBytesMost(msg, 2, 16) } return nil } func (res *GetDCMIAssetTagResponse) Format() string { return fmt.Sprintf("%s (length: %d, total length: %d)", string(res.AssetTag), len(res.AssetTag), res.TotalLength) } // GetDCMIAssetTag sends a DCMI "Get Asset Tag" command. // See [GetDCMIAssetTagRequest] for details. func (c *Client) GetDCMIAssetTag(ctx context.Context, offset uint8) (response *GetDCMIAssetTagResponse, err error) { request := &GetDCMIAssetTagRequest{Offset: offset} response = &GetDCMIAssetTagResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetDCMIAssetTagFull(ctx context.Context) (assetTagRaw []byte, typeLength TypeLength, err error) { assetTagRaw = make([]byte, 0) typeCode := uint8(0) offset := uint8(0) for { resp, err := c.GetDCMIAssetTag(ctx, offset) if err != nil { if err, ok := err.(*ResponseError); ok { cc := uint8(err.CompletionCode()) switch cc { // align the completion code with the FRU Type Length Byte Format case 0x80: typeCode = 0b00 case 0x81: typeCode = 0b01 case 0x82: typeCode = 0x10 case 0x83: typeCode = 0x11 default: return nil, 0, fmt.Errorf("GetDCMIAssetTag failed, err: %w", err) } } } assetTagRaw = append(assetTagRaw, resp.AssetTag...) if resp.TotalLength <= offset+uint8(len(resp.AssetTag)) { break } offset += uint8(len(resp.AssetTag)) } typeLength = TypeLength(typeCode<<6 | uint8(len(assetTagRaw))) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_dcmi_cap_param.go000066400000000000000000000111371474110527100240410ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // GetDCMICapParamRequest provides version information for DCMI and information about // the mandatory and optional DCMI capabilities that are available on the particular platform. // // The command is session-less and can be called similar to the Get Authentication Capability command. // This command is a bare-metal provisioning command, and the availability of features does not imply // the features are configured. // // [DCMI specification v1.5] 6.1.1 Get DCMI Capabilities Info Command type GetDCMICapParamRequest struct { ParamSelector DCMICapParamSelector } type GetDCMICapParamResponse struct { MajorVersion uint8 MinorVersion uint8 ParamRevision uint8 ParamData []byte } func (req *GetDCMICapParamRequest) Pack() []byte { return []byte{GroupExtensionDCMI, byte(req.ParamSelector)} } func (req *GetDCMICapParamRequest) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } req.ParamSelector = DCMICapParamSelector(msg[1]) return nil } func (req *GetDCMICapParamRequest) Command() Command { return CommandGetDCMICapParam } func (res *GetDCMICapParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetDCMICapParamResponse) Pack() []byte { out := make([]byte, 4+len(res.ParamData)) out[0] = GroupExtensionDCMI out[1] = res.MajorVersion out[2] = res.MinorVersion out[3] = res.ParamRevision copy(out[4:], res.ParamData) return out } func (res *GetDCMICapParamResponse) Unpack(msg []byte) error { if len(msg) < 5 { return ErrUnpackedDataTooShortWith(len(msg), 5) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } res.MajorVersion, _, _ = unpackUint8(msg, 1) res.MinorVersion, _, _ = unpackUint8(msg, 2) res.ParamRevision, _, _ = unpackUint8(msg, 3) res.ParamData, _, _ = unpackBytes(msg, 4, len(msg)-4) return nil } func (res *GetDCMICapParamResponse) Format() string { return fmt.Sprintf(` Major version : %d Minor version : %d Param revision : %d Param data : %v`, res.MajorVersion, res.MinorVersion, res.ParamRevision, res.ParamData, ) } func (c *Client) GetDCMICapParam(ctx context.Context, paramSelector DCMICapParamSelector) (response *GetDCMICapParamResponse, err error) { request := &GetDCMICapParamRequest{ParamSelector: paramSelector} response = &GetDCMICapParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetDCMICapParamFor(ctx context.Context, param DCMICapParameter) error { if isNilDCMICapParameter(param) { return nil } paramSelector := param.DCMICapParameter() request := &GetDCMICapParamRequest{ParamSelector: paramSelector} response := &GetDCMICapParamResponse{} if err := c.Exchange(ctx, request, response); err != nil { return err } if err := param.Unpack(response.ParamData); err != nil { return fmt.Errorf("unpack param data failed, err: %w", err) } return nil } func (c *Client) GetDCMICapParams(ctx context.Context) (*DCMICapParams, error) { dcmiCapParams := &DCMICapParams{ SupportedDCMICapabilities: &DCMICapParam_SupportedDCMICapabilities{}, MandatoryPlatformAttributes: &DCMICapParam_MandatoryPlatformAttributes{}, OptionalPlatformAttributes: &DCMICapParam_OptionalPlatformAttributes{}, ManageabilityAccessAttributes: &DCMICapParam_ManageabilityAccessAttributes{}, EnhancedSystemPowerStatisticsAttributes: &DCMICapParam_EnhancedSystemPowerStatisticsAttributes{}, } if err := c.GetDCMICapParamsFor(ctx, dcmiCapParams); err != nil { return nil, err } return dcmiCapParams, nil } func (c *Client) GetDCMICapParamsFor(ctx context.Context, dcmiCapParams *DCMICapParams) error { if dcmiCapParams == nil { return nil } if dcmiCapParams.SupportedDCMICapabilities != nil { if err := c.GetDCMICapParamFor(ctx, dcmiCapParams.SupportedDCMICapabilities); err != nil { return err } } if dcmiCapParams.MandatoryPlatformAttributes != nil { if err := c.GetDCMICapParamFor(ctx, dcmiCapParams.MandatoryPlatformAttributes); err != nil { return err } } if dcmiCapParams.OptionalPlatformAttributes != nil { if err := c.GetDCMICapParamFor(ctx, dcmiCapParams.OptionalPlatformAttributes); err != nil { return err } } if dcmiCapParams.ManageabilityAccessAttributes != nil { if err := c.GetDCMICapParamFor(ctx, dcmiCapParams.ManageabilityAccessAttributes); err != nil { return err } } if dcmiCapParams.EnhancedSystemPowerStatisticsAttributes != nil { if err := c.GetDCMICapParamFor(ctx, dcmiCapParams.EnhancedSystemPowerStatisticsAttributes); err != nil { return err } } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_dcmi_config_params.go000066400000000000000000000073131474110527100247270ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // [DCMI specification v1.5] 6.1.3 Get DCMI Configuration Parameters Command type GetDCMIConfigParamRequest struct { ParamSelector DCMIConfigParamSelector SetSelector uint8 // use 00h for parameters that only have one set } type GetDCMIConfigParamResponse struct { MajorVersion uint8 MinorVersion uint8 ParamRevision uint8 ParamData []byte } func (req *GetDCMIConfigParamRequest) Pack() []byte { out := make([]byte, 3) packUint8(GroupExtensionDCMI, out, 0) packUint8(uint8(req.ParamSelector), out, 1) packUint8(req.SetSelector, out, 2) return out } func (req *GetDCMIConfigParamRequest) Command() Command { return CommandGetDCMIConfigParam } func (res *GetDCMIConfigParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetDCMIConfigParamResponse) Unpack(msg []byte) error { if len(msg) < 5 { return ErrUnpackedDataTooShortWith(len(msg), 5) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } res.MajorVersion, _, _ = unpackUint8(msg, 1) res.MinorVersion, _, _ = unpackUint8(msg, 2) res.ParamRevision, _, _ = unpackUint8(msg, 3) res.ParamData, _, _ = unpackBytes(msg, 4, len(msg)-4) return nil } func (res *GetDCMIConfigParamResponse) Format() string { return "" } func (c *Client) GetDCMIConfigParam(ctx context.Context, paramSelector DCMIConfigParamSelector, setSelector uint8) (response *GetDCMIConfigParamResponse, err error) { request := &GetDCMIConfigParamRequest{ ParamSelector: paramSelector, SetSelector: setSelector, } response = &GetDCMIConfigParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetDCMIConfigParamFor(ctx context.Context, param DCMIConfigParameter) error { if isNilDCMIConfigParameter(param) { return nil } paramSelector, setSelector := param.DCMIConfigParameter() request := &GetDCMIConfigParamRequest{ParamSelector: paramSelector, SetSelector: setSelector} response := &GetDCMIConfigParamResponse{} if err := c.Exchange(ctx, request, response); err != nil { return err } if err := param.Unpack(response.ParamData); err != nil { return fmt.Errorf("unpack param (%s[%d]) failed, err: %w", paramSelector.String(), paramSelector, err) } return nil } func (c *Client) GetDCMIConfigParams(ctx context.Context) (*DCMIConfigParams, error) { dcmiConfigParams := &DCMIConfigParams{ ActivateDHCP: &DCMIConfigParam_ActivateDHCP{}, DiscoveryConfiguration: &DCMIConfigParam_DiscoveryConfiguration{}, DHCPTiming1: &DCMIConfigParam_DHCPTiming1{}, DHCPTiming2: &DCMIConfigParam_DHCPTiming2{}, DHCPTiming3: &DCMIConfigParam_DHCPTiming3{}, } if err := c.GetDCMIConfigParamsFor(ctx, dcmiConfigParams); err != nil { return nil, err } return dcmiConfigParams, nil } func (c *Client) GetDCMIConfigParamsFor(ctx context.Context, dcmiConfigParams *DCMIConfigParams) error { if dcmiConfigParams == nil { return nil } if dcmiConfigParams.ActivateDHCP != nil { if err := c.GetDCMIConfigParamFor(ctx, dcmiConfigParams.ActivateDHCP); err != nil { return err } } if dcmiConfigParams.DiscoveryConfiguration != nil { if err := c.GetDCMIConfigParamFor(ctx, dcmiConfigParams.DiscoveryConfiguration); err != nil { return err } } if dcmiConfigParams.DHCPTiming1 != nil { if err := c.GetDCMIConfigParamFor(ctx, dcmiConfigParams.DHCPTiming1); err != nil { return err } } if dcmiConfigParams.DHCPTiming2 != nil { if err := c.GetDCMIConfigParamFor(ctx, dcmiConfigParams.DHCPTiming2); err != nil { return err } } if dcmiConfigParams.DHCPTiming3 != nil { if err := c.GetDCMIConfigParamFor(ctx, dcmiConfigParams.DHCPTiming3); err != nil { return err } } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_dcmi_mgmt_controller_identifier.go000066400000000000000000000046621474110527100275340ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // [DCMI specification v1.5]: 6.4.6.1 Get Management Controller Identifier String Command type GetDCMIMgmtControllerIdentifierRequest struct { Offset uint8 } type GetDCMIMgmtControllerIdentifierResponse struct { // ID String Length Count of non-null characters starting from offset 0 up to the first null. // Note: The Maximum length of the Identifier String is specified as 64 bytes including the null character, // therefore the range for this return is 0-63. IDStrLength uint8 IDStr []byte } func (req *GetDCMIMgmtControllerIdentifierRequest) Pack() []byte { // Number of bytes to read (16 bytes maximum) // using the fixed (maximum) value is OK here. var readBytes = uint8(0x10) return []byte{GroupExtensionDCMI, req.Offset, readBytes} } func (req *GetDCMIMgmtControllerIdentifierRequest) Command() Command { return CommandGetDCMIMgmtControllerIdentifier } func (res *GetDCMIMgmtControllerIdentifierResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetDCMIMgmtControllerIdentifierResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } res.IDStrLength = msg[1] res.IDStr, _, _ = unpackBytes(msg, 2, len(msg)-2) return nil } func (res *GetDCMIMgmtControllerIdentifierResponse) Format() string { return fmt.Sprintf("[%s] (returned length: %d,total length: %d)", string(res.IDStr), len(res.IDStr), res.IDStrLength) } // GetDCMIMgmtControllerIdentifier sends a DCMI "Get Asset Tag" command. // See [GetDCMIMgmtControllerIdentifierRequest] for details. func (c *Client) GetDCMIMgmtControllerIdentifier(ctx context.Context, offset uint8) (response *GetDCMIMgmtControllerIdentifierResponse, err error) { request := &GetDCMIMgmtControllerIdentifierRequest{Offset: offset} response = &GetDCMIMgmtControllerIdentifierResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetDCMIMgmtControllerIdentifierFull(ctx context.Context) ([]byte, error) { id := make([]byte, 0) offset := uint8(0) for { resp, err := c.GetDCMIMgmtControllerIdentifier(ctx, offset) if err != nil { return nil, fmt.Errorf("GetDCMIMgmtControllerIdentifier failed, err: %w", err) } id = append(id, resp.IDStr...) if resp.IDStrLength <= offset+uint8(len(resp.IDStr)) { break } offset += uint8(len(resp.IDStr)) } return id, nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_dcmi_power_limit.go000066400000000000000000000042621474110527100244510ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // [DCMI specification v1.5]: 6.6.2 Get Power Limit type GetDCMIPowerLimitRequest struct { } type GetDCMIPowerLimitResponse struct { ExceptionAction DCMIExceptionAction // Power Limit Requested in Watts PowerLimitRequested uint16 // Maximum time taken to limit the power after the platform power has reached // the power limit before the Exception Action will be taken. CorrectionTimeLimitMilliSec uint32 // Management application Statistics Sampling period in seconds StatisticsSamplingPeriodSec uint16 } func (req *GetDCMIPowerLimitRequest) Pack() []byte { return []byte{GroupExtensionDCMI, 0x00, 0x00} } func (req *GetDCMIPowerLimitRequest) Command() Command { return CommandGetDCMIPowerLimit } func (res *GetDCMIPowerLimitResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "No Active Set Power Limit", } } func (res *GetDCMIPowerLimitResponse) Unpack(msg []byte) error { if len(msg) < 14 { return ErrUnpackedDataTooShortWith(len(msg), 14) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } exceptionAction, _, _ := unpackUint8(msg, 3) res.ExceptionAction = DCMIExceptionAction(exceptionAction) res.PowerLimitRequested, _, _ = unpackUint16L(msg, 4) res.CorrectionTimeLimitMilliSec, _, _ = unpackUint32L(msg, 6) res.StatisticsSamplingPeriodSec, _, _ = unpackUint16L(msg, 12) return nil } func (res *GetDCMIPowerLimitResponse) Format() string { return "Power limit exception action : " + res.ExceptionAction.String() + "\n" + "Power limit requested : " + fmt.Sprintf("%d", res.PowerLimitRequested) + " Watts\n" + "Correction Time Limit : " + fmt.Sprintf("%d", res.CorrectionTimeLimitMilliSec) + " Milliseconds\n" + "Statistics Sampling period : " + fmt.Sprintf("%d", res.StatisticsSamplingPeriodSec) + " Seconds\n" } // GetDCMIPowerLimit sends a DCMI "Get Power Reading" command. // See [GetDCMIPowerLimitRequest] for details. func (c *Client) GetDCMIPowerLimit(ctx context.Context) (response *GetDCMIPowerLimitResponse, err error) { request := &GetDCMIPowerLimitRequest{} response = &GetDCMIPowerLimitResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_dcmi_power_reading.go000066400000000000000000000070771474110527100247530ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "time" ) // GetDCMIPowerReadingRequest represents a "Get Power Reading" request according // to section 6.6.1 of the [DCMI specification v1.5]. // // Currently, only the basic "System Power Statistics" mode is supported, not // the extended mode. // // [DCMI specification v1.5]: https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/dcmi-v1-5-rev-spec.pdf type GetDCMIPowerReadingRequest struct { // TODO add support for extended mode... } // GetDCMIPowerReadingResponse represents a response to a [GetDCMIPowerReadingRequest]. type GetDCMIPowerReadingResponse struct { // Current Power in watts CurrentPower uint16 // Minimum Power over sampling duration in watts MinimumPower uint16 // Maximum Power over sampling duration in watts MaximumPower uint16 // Average Power over sampling duration in watts AveragePower uint16 // IPMI Specification based Time Stamp // // For Mode 02h (not yet supported), the time stamp specifies the end of the // averaging window. Timestamp uint32 // Statistics reporting time period // // For Mode 01h, time-frame in milliseconds, over which the controller // collects statistics. For Mode 02h (not yet supported), time-frame reflects // the Averaging Time period in units. ReportingPeriod uint32 // True if power measurements are available, false otherwise. PowerMeasurementActive bool } func (req *GetDCMIPowerReadingRequest) Pack() []byte { // second byte 0x01 = "basic" System Power Statistics return []byte{GroupExtensionDCMI, 0x01, 0x00, 0x00} } func (req *GetDCMIPowerReadingRequest) Command() Command { return CommandGetDCMIPowerReading } func (res *GetDCMIPowerReadingResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetDCMIPowerReadingResponse) Unpack(msg []byte) error { if len(msg) < 18 { return ErrUnpackedDataTooShortWith(len(msg), 19) } var off int if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } res.CurrentPower, off, _ = unpackUint16L(msg, 1) res.MinimumPower, off, _ = unpackUint16L(msg, off) res.MaximumPower, off, _ = unpackUint16L(msg, off) res.AveragePower, off, _ = unpackUint16L(msg, off) res.Timestamp, off, _ = unpackUint32L(msg, off) res.ReportingPeriod, off, _ = unpackUint32L(msg, off) state, _, _ := unpackUint8(msg, off) res.PowerMeasurementActive = isBit6Set(state) return nil } func (res *GetDCMIPowerReadingResponse) Format() string { ts := time.Unix(int64(res.Timestamp), 0) return "Instantaneous power reading: " + fmt.Sprintf("%5d", res.CurrentPower) + " Watts\n" + "Minimum during sampling period: " + fmt.Sprintf("%5d", res.MinimumPower) + " Watts\n" + "Maximum during sampling period: " + fmt.Sprintf("%5d", res.MaximumPower) + " Watts\n" + "Average power reading over sample period: " + fmt.Sprintf("%5d", res.CurrentPower) + " Watts\n" + "IPMI timestamp: " + ts.Format("01/02/06 15:04:05 UTC") + "\n" + "Sampling period: " + fmt.Sprintf("%08d", res.ReportingPeriod/1000) + " Seconds\n" + "Power reading state is: " + formatBool(res.PowerMeasurementActive, "activated", "deactivated") } // GetDCMIPowerReading sends a DCMI "Get Power Reading" command. // See [GetDCMIPowerReadingRequest] for details. func (c *Client) GetDCMIPowerReading(ctx context.Context) (response *GetDCMIPowerReadingResponse, err error) { request := &GetDCMIPowerReadingRequest{} response = &GetDCMIPowerReadingResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_dcmi_sensor_info.go000066400000000000000000000055401474110527100244430ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // [DCMI specification v1.5]: 6.5.2 Get DCMI Sensor Info Command type GetDCMISensorInfoRequest struct { SensorType SensorType EntityID EntityID // 00h Retrieve information about all instances associated with Entity ID // 01h - FFh Retrieve only the information about particular instance. EntityInstance EntityInstance EntityInstanceStart uint8 } type GetDCMISensorInfoResponse struct { TotalEntityInstances uint8 RecordsCount uint8 SDRRecordID []uint16 } func (req *GetDCMISensorInfoRequest) Pack() []byte { out := make([]byte, 5) packUint8(GroupExtensionDCMI, out, 0) packUint8(uint8(req.SensorType), out, 1) packUint8(byte(req.EntityID), out, 2) packUint8(byte(req.EntityInstance), out, 3) packUint8(req.EntityInstanceStart, out, 4) return out } func (req *GetDCMISensorInfoRequest) Command() Command { return CommandGetDCMISensorInfo } func (res *GetDCMISensorInfoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetDCMISensorInfoResponse) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } res.TotalEntityInstances = msg[1] res.RecordsCount = msg[2] if len(msg) < 3+int(res.RecordsCount)*2 { return ErrUnpackedDataTooShortWith(len(msg), 3+int(res.RecordsCount)*2) } res.SDRRecordID = make([]uint16, res.RecordsCount) for i := 0; i < int(res.RecordsCount); i++ { res.SDRRecordID[i], _, _ = unpackUint16L(msg, 3+i*2) } return nil } func (res *GetDCMISensorInfoResponse) Format() string { return fmt.Sprintf(` Total entity instances: %d Number of records: %d SDR Record ID: %v `, res.TotalEntityInstances, res.RecordsCount, res.SDRRecordID, ) } // GetDCMISensorInfo sends a DCMI "Get Power Reading" command. // See [GetDCMISensorInfoRequest] for details. func (c *Client) GetDCMISensorInfo(ctx context.Context, request *GetDCMISensorInfoRequest) (response *GetDCMISensorInfoResponse, err error) { response = &GetDCMISensorInfoResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetDCMISensors(ctx context.Context, entityIDs ...EntityID) ([]*SDR, error) { out := make([]*SDR, 0) for _, entityID := range entityIDs { request := &GetDCMISensorInfoRequest{ SensorType: SensorTypeTemperature, EntityID: entityID, EntityInstance: 0x00, EntityInstanceStart: 0, } response := &GetDCMISensorInfoResponse{} if err := c.Exchange(ctx, request, response); err != nil { return nil, err } for _, recordID := range response.SDRRecordID { sdr, err := c.GetSDREnhanced(ctx, recordID) if err != nil { return nil, fmt.Errorf("GetSDRDetail failed for recordID (%#02x), err: %s", recordID, err) } out = append(out, sdr) } } return out, nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_dcmi_temperature_readings.go000066400000000000000000000074121474110527100263300ustar00rootroot00000000000000package ipmi import ( "bytes" "context" "fmt" "github.com/olekukonko/tablewriter" ) // [DCMI specification v1.5]: 6.7.3 Get Temperature Readings Command type GetDCMITemperatureReadingsRequest struct { SensorType SensorType EntityID EntityID EntityInstance EntityInstance EntityInstanceStart uint8 } type GetDCMITemperatureReadingsResponse struct { entityID EntityID TotalEntityInstances uint8 TemperatureReadingsCount uint8 TemperatureReadings []DCMITemperatureReading } type DCMITemperatureReading struct { TemperatureReading int8 EntityInstance EntityInstance EntityID EntityID } func (req *GetDCMITemperatureReadingsRequest) Pack() []byte { return []byte{GroupExtensionDCMI, byte(req.SensorType), byte(req.EntityID), byte(req.EntityInstance), req.EntityInstanceStart} } func (req *GetDCMITemperatureReadingsRequest) Command() Command { return CommandGetDCMITemperatureReadings } func (res *GetDCMITemperatureReadingsResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "No Active Set Power Limit", } } func (res *GetDCMITemperatureReadingsResponse) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } res.TotalEntityInstances = msg[1] res.TemperatureReadingsCount = msg[2] if len(msg) < 3+int(res.TemperatureReadingsCount)*2 { return ErrUnpackedDataTooShortWith(len(msg), 3+int(res.TemperatureReadingsCount)*2) } tempReadings := make([]DCMITemperatureReading, 0) for i := 0; i < int(res.TemperatureReadingsCount); i++ { r := DCMITemperatureReading{} v := msg[3+i*2] r.TemperatureReading = int8(v) r.EntityInstance = EntityInstance(msg[3+i*2+1]) r.EntityID = res.entityID tempReadings = append(tempReadings, r) } res.TemperatureReadings = tempReadings return nil } func (res *GetDCMITemperatureReadingsResponse) Format() string { return fmt.Sprintf(`Total entity instances: %d Number of temperature readings: %d Temperature Readings: %v`, res.TotalEntityInstances, res.TemperatureReadingsCount, res.TemperatureReadings) } func (c *Client) GetDCMITemperatureReadings(ctx context.Context, request *GetDCMITemperatureReadingsRequest) (response *GetDCMITemperatureReadingsResponse, err error) { response = &GetDCMITemperatureReadingsResponse{ entityID: request.EntityID, } err = c.Exchange(ctx, request, response) return } func (c *Client) GetDCMITemperatureReadingsForEntities(ctx context.Context, entityIDs ...EntityID) ([]DCMITemperatureReading, error) { out := make([]DCMITemperatureReading, 0) for _, entityID := range entityIDs { request := &GetDCMITemperatureReadingsRequest{ SensorType: SensorTypeTemperature, EntityID: entityID, EntityInstance: 0x00, EntityInstanceStart: 0, } response, err := c.GetDCMITemperatureReadings(ctx, request) if err != nil { return nil, fmt.Errorf("GetDCMITemperatureReadings failed for entityID (%#02x), err: %s", entityID, err) } out = append(out, response.TemperatureReadings...) } return out, nil } func FormatDCMITemperatureReadings(readings []DCMITemperatureReading) string { var buf = new(bytes.Buffer) table := tablewriter.NewWriter(buf) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) headers := []string{ "Entity ID", "Entity Instance", "Temp. Readings", } table.SetHeader(headers) table.SetFooter(headers) for _, reading := range readings { rowContent := []string{ fmt.Sprintf("%s(%#02x)", reading.EntityID.String(), uint8(reading.EntityID)), fmt.Sprintf("%d", reading.EntityInstance), fmt.Sprintf("%+d C", reading.TemperatureReading), } table.Append(rowContent) } table.Render() return buf.String() } golang-github-bougou-go-ipmi-0.7.2/cmd_get_dcmi_thermal_limit.go000066400000000000000000000055131474110527100247510ustar00rootroot00000000000000package ipmi import ( "context" "errors" "fmt" ) // [DCMI specification v1.5]: 6.7.1 Get Thermal Limit Command type GetDCMIThermalLimitRequest struct { EntityID EntityID // Entity ID = 37h or 40h (Inlet Temperature) EntityInstance EntityInstance } type GetDCMIThermalLimitResponse struct { ExceptionAction_PowerOffAndLogSEL bool ExceptionAction_LogSELOnly bool // ignored if ExceptionAction_PowerOffAndLogSEL is true // Temperature Limit set in units defined by the SDR record. // Note: the management controller is not required to check this parameter for validity against the SDR contents. TemperatureLimit uint8 // Interval in seconds over which the temperature must continuously be sampled as exceeding the set limit // before the specified Exception Action will be taken. // Samples are taken at the rate specified by the sampling frequency value in parameter #5 of the DCMI Capabilities // parameters (see Table 6-3, DCMI Capabilities Parameters). ExceptionTimeSec uint16 } func (req *GetDCMIThermalLimitRequest) Pack() []byte { return []byte{GroupExtensionDCMI, byte(req.EntityID), byte(req.EntityInstance)} } func (req *GetDCMIThermalLimitRequest) Command() Command { return CommandGetDCMIThermalLimit } func (res *GetDCMIThermalLimitResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetDCMIThermalLimitResponse) Unpack(msg []byte) error { if len(msg) < 5 { return ErrUnpackedDataTooShortWith(len(msg), 5) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } b1, _, _ := unpackUint8(msg, 1) res.ExceptionAction_PowerOffAndLogSEL = isBit6Set(b1) res.ExceptionAction_LogSELOnly = isBit5Set(b1) res.TemperatureLimit, _, _ = unpackUint8(msg, 2) res.ExceptionTimeSec, _, _ = unpackUint16L(msg, 3) return nil } func (res *GetDCMIThermalLimitResponse) Format() string { return fmt.Sprintf(` Exception Actions, taken if the Temperature Limit exceeded: Hard Power Off system and log event: %s Log event to SEL only: %s Temperature Limit %d degrees Exception Time %d seconds`, formatBool(res.ExceptionAction_PowerOffAndLogSEL, "active", "inactive"), formatBool(res.ExceptionAction_LogSELOnly, "active", "inactive"), res.TemperatureLimit, res.ExceptionTimeSec) } func (c *Client) GetDCMIThermalLimit(ctx context.Context, entityID EntityID, entityInstance EntityInstance) (response *GetDCMIThermalLimitResponse, err error) { if uint8(entityID) != 0x37 && uint8(entityID) != 0x40 { return nil, errors.New("only Inlet Temperature entityID (0x37 or 0x40) is supported") } request := &GetDCMIThermalLimitRequest{ EntityID: entityID, EntityInstance: entityInstance, } response = &GetDCMIThermalLimitResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_device_guid.go000066400000000000000000000021401474110527100233630ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 20.8 Get Device GUID Command type GetDeviceGUIDRequest struct { // empty } type GetDeviceGUIDResponse struct { GUID [16]byte } func (req *GetDeviceGUIDRequest) Command() Command { return CommandGetDeviceGUID } func (req *GetDeviceGUIDRequest) Pack() []byte { return []byte{} } func (res *GetDeviceGUIDResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetDeviceGUIDResponse) Unpack(msg []byte) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } guid, _, _ := unpackBytes(msg, 0, 16) res.GUID = array16(guid) return nil } func (res *GetDeviceGUIDResponse) Format() string { guidMode := GUIDModeSMBIOS u, err := ParseGUID(res.GUID[:], guidMode) if err != nil { return fmt.Sprintf(" (%s)", err) } return fmt.Sprintf("GUID: %s", u.String()) } func (c *Client) GetDeviceGUID(ctx context.Context) (response *GetDeviceGUIDResponse, err error) { request := &GetDeviceGUIDRequest{} response = &GetDeviceGUIDResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_device_id.go000066400000000000000000000161511474110527100230360ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "strings" ) // 20.1 Get Device ID Command type GetDeviceIDRequest struct { // empty } type GetDeviceIDResponse struct { DeviceID uint8 // [7] 1 = device provides Device SDRs // 0 = device does not provide Device SDRs // [6:4] reserved. Return as 0. ProvideDeviceSDRs bool // [3:0] Device Revision, binary encoded DeviceRevision uint8 // [7] Device available: 0=normal operation, 1= device firmware, SDR // Repository update or self-initialization in progress. [Firmware / SDR // Repository updates can be differentiated by issuing a Get SDR // command and checking the completion code.] DeviceAvailable bool // [6:0] Major Firmware Revision, binary encoded MajorFirmwareRevision uint8 // BCD encoded MinorFirmwareRevision uint8 // Holds IPMI Command Specification Version. BCD encoded. // 00h = reserved. // Bits 7:4 hold the Least Significant digit of the revision, while // bits 3:0 hold the Most Significant bits. // E.g. a value of 51h indicates revision 1.5 functionality. // 02h for implementations that provide IPMI v2.0 capabilities // per this specification. MajorIPMIVersion uint8 MinorIPMIVersion uint8 AdditionalDeviceSupport // Manufacturer ID, LS Byte first. The manufacturer ID is a 20-bit value that is // derived from the IANA Private Enterprise ID (see below). // Most significant four bits = reserved (0000b). // 000000h = unspecified. 0FFFFFh = reserved. This value is binary encoded. // E.g. the ID for the IPMI forum is 7154 decimal, which is 1BF2h, which would // be stored in this record as F2h, 1Bh, 00h for bytes 8 through 10, respectively ManufacturerID uint32 // only 3 bytes used // Product ID, LS Byte first. This field can be used to provide a number that // identifies a particular system, module, add-in card, or board set. The number // is specified according to the manufacturer given by Manufacturer ID (see // below). // 0000h = unspecified. FFFFh = reserved. ProductID uint16 // Auxiliary Firmware Revision Information. This field is optional. If present, it // holds additional information about the firmware revision, such as boot block or // internal data structure version numbers. The meanings of the numbers are // specific to the vendor identified by Manufacturer ID (see below). When the // vendor-specific definition is not known, generic utilities should display each // byte as 2-digit hexadecimal numbers, with byte 13 displayed first as the most-significant byte. AuxiliaryFirmwareRevision []byte // 4 bytes } // Additional Device Support (formerly called IPM Device Support). Lists the // IPMI 'logical device' commands and functions that the controller supports that // are in addition to the mandatory IPM and Application commands. // [7] Chassis Device (device functions as chassis device per ICMB spec.) // [6] Bridge (device responds to Bridge NetFn commands) // [5] IPMB Event Generator (device generates event messages [platform // event request messages] onto the IPMB) // [4] IPMB Event Receiver (device accepts event messages [platform event // request messages] from the IPMB) // [3] FRU Inventory Device // [2] SEL Device // [1] SDR Repository Device // [0] Sensor Device type AdditionalDeviceSupport struct { SupportChassis bool SupportBridge bool SupportIPMBEventGenerator bool SupportIPMBEventReceiver bool SupportFRUInventory bool SupportSEL bool SupportSDRRepo bool SupportSensor bool } func (req *GetDeviceIDRequest) Command() Command { return CommandGetDeviceID } func (req *GetDeviceIDRequest) Pack() []byte { return []byte{} } func (res *GetDeviceIDResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetDeviceIDResponse) Unpack(msg []byte) error { if len(msg) < 11 { return ErrUnpackedDataTooShortWith(len(msg), 11) } res.DeviceID, _, _ = unpackUint8(msg, 0) b2, _, _ := unpackUint8(msg, 1) res.ProvideDeviceSDRs = isBit7Set(b2) res.DeviceRevision = b2 & 0x0f b3, _, _ := unpackUint8(msg, 2) res.DeviceAvailable = !isBit7Set(b3) res.MajorFirmwareRevision = b3 & 0x7f // binary encoded b4, _, _ := unpackUint8(msg, 3) // BCD encoded res.MinorFirmwareRevision = bcdUint8(b4) ipmiVersionBCD, _, _ := unpackUint8(msg, 4) // BCD encoded res.MajorIPMIVersion = ipmiVersionBCD & 0x0f res.MinorIPMIVersion = ipmiVersionBCD >> 4 b6, _, _ := unpackUint8(msg, 5) res.SupportChassis = isBit7Set(b6) res.SupportBridge = isBit6Set(b6) res.SupportIPMBEventGenerator = isBit5Set(b6) res.SupportIPMBEventReceiver = isBit4Set(b6) res.SupportFRUInventory = isBit3Set(b6) res.SupportSEL = isBit2Set(b6) res.SupportSDRRepo = isBit1Set(b6) res.SupportSensor = isBit0Set(b6) res.ManufacturerID, _, _ = unpackUint24L(msg, 6) res.ProductID, _, _ = unpackUint16L(msg, 9) if len(msg) > 11 && len(msg) < 15 { return ErrUnpackedDataTooShortWith(len(msg), 15) } else { res.AuxiliaryFirmwareRevision, _, _ = unpackBytes(msg, 11, 4) } return nil } func (res *GetDeviceIDResponse) FirmwareVersionStr() string { return fmt.Sprintf("%d.%d", res.MajorFirmwareRevision, res.MinorFirmwareRevision) } func (res *GetDeviceIDResponse) Format() string { deviceSupport := []string{} if res.SupportChassis { deviceSupport = append(deviceSupport, " Chassis Device") } if res.SupportBridge { deviceSupport = append(deviceSupport, " Bridge Device") } if res.SupportIPMBEventGenerator { deviceSupport = append(deviceSupport, " IPMB Event Generator") } if res.SupportIPMBEventReceiver { deviceSupport = append(deviceSupport, " IPMB Event Receiver") } if res.SupportFRUInventory { deviceSupport = append(deviceSupport, " FRU Inventory Device") } if res.SupportSEL { deviceSupport = append(deviceSupport, " SEL Device") } if res.SupportSDRRepo { deviceSupport = append(deviceSupport, " SDR Repo Device") } if res.SupportSensor { deviceSupport = append(deviceSupport, " Sensor Device") } auxFirmwareInfo := []string{} for _, v := range res.AuxiliaryFirmwareRevision { auxFirmwareInfo = append(auxFirmwareInfo, fmt.Sprintf(" %#02x", v)) } return fmt.Sprintf(`Device ID : %d Device Revision : %d Firmware Revision : %d.%d IPMI Version : %d.%d Manufacturer ID : %d (%#02x) Manufacturer Name : %s Product ID : %d (%#04x) Product Name : %#02x Device Available : %s Provides Device SDRs : %s Additional Device Support : %s Aux Firmware Rev Info : %s`, res.DeviceID, res.DeviceRevision, res.MajorFirmwareRevision, res.MinorFirmwareRevision, res.MajorIPMIVersion, res.MinorIPMIVersion, res.ManufacturerID, res.ManufacturerID, OEM(res.ManufacturerID), res.ProductID, res.ProductID, res.ProductID, formatBool(res.DeviceAvailable, "yes", "no"), formatBool(res.ProvideDeviceSDRs, "yes", "no"), strings.Join(deviceSupport, " \n"), strings.Join(auxFirmwareInfo, " \n"), ) } func (c *Client) GetDeviceID(ctx context.Context) (response *GetDeviceIDResponse, err error) { request := &GetDeviceIDRequest{} response = &GetDeviceIDResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_device_sdr.go000066400000000000000000000124701474110527100232320ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 35.3 Get Device SDR Command type GetDeviceSDRRequest struct { ReservationID uint16 RecordID uint16 ReadOffset uint8 ReadBytes uint8 // FFh means read entire record } type GetDeviceSDRResponse struct { NextRecordID uint16 RecordData []byte } func (req *GetDeviceSDRRequest) Command() Command { return CommandGetDeviceSDR } func (req *GetDeviceSDRRequest) Pack() []byte { out := make([]byte, 6) packUint16L(req.ReservationID, out, 0) packUint16L(req.RecordID, out, 2) packUint8(req.ReadOffset, out, 4) packUint8(req.ReadBytes, out, 5) return out } func (res *GetDeviceSDRResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.NextRecordID, _, _ = unpackUint16L(msg, 0) res.RecordData, _, _ = unpackBytes(msg, 2, len(msg)-2) return nil } func (r *GetDeviceSDRResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "record changed", } } func (res *GetDeviceSDRResponse) Format() string { return "" } // The Get Device SDR command allows SDR information for sensors for a Sensor Device // (typically implemented in a satellite management controller) to be returned. // // The Get Device SDR Command can return any type of SDR, not just Types 01h and 02h. // This is an optional command for Static Sensor Devices, and mandatory for Dynamic Sensor Devices. // The format and action of this command is similar to that for the Get SDR command // for SDR Repository Devices. // // Sensor Devices that support the Get Device SDR command return SDR Records that // match the SDR Repository formats. func (c *Client) GetDeviceSDR(ctx context.Context, recordID uint16) (response *GetDeviceSDRResponse, err error) { request := &GetDeviceSDRRequest{ ReservationID: 0, RecordID: recordID, ReadOffset: 0, ReadBytes: 0xff, } response = &GetDeviceSDRResponse{} err = c.Exchange(ctx, request, response) if resErr, ok := err.(*ResponseError); ok { if resErr.CompletionCode() == CompletionCodeCannotReturnRequestedDataBytes { return c.getDeviceSDR(ctx, recordID) } } return } // getDeviceSDR reads the Device SDR record in partial read way. func (c *Client) getDeviceSDR(ctx context.Context, recordID uint16) (response *GetDeviceSDRResponse, err error) { var data []byte // the actual data length of the SDR can only be determined after the first GetSDR request/response. dataLength := uint8(0) reservationID := uint16(0) readBytes := uint8(16) readTotal := uint8(0) readOffset := uint8(0) for { request := &GetDeviceSDRRequest{ ReservationID: reservationID, RecordID: recordID, ReadOffset: readOffset, ReadBytes: readBytes, } response = &GetDeviceSDRResponse{} if err = c.Exchange(ctx, request, response); err != nil { return } // determine the total data length by parsing the SDR Header part if readOffset == 0 { if len(response.RecordData) < SDRRecordHeaderSize { return nil, fmt.Errorf("too short record data for SDR header (%d/%d)", len(response.RecordData), SDRRecordHeaderSize) } dataLength = response.RecordData[4] + uint8(SDRRecordHeaderSize) data = make([]byte, dataLength) } copy(data[readOffset:readOffset+readBytes], response.RecordData[:]) readOffset += uint8(len(response.RecordData)) readTotal += uint8(len(response.RecordData)) if readTotal >= dataLength { break } if readOffset+readBytes > dataLength { // decrease the readBytes for the last read. readBytes = dataLength - readOffset } rsp, err := c.ReserveDeviceSDRRepo(ctx) if err == nil { reservationID = rsp.ReservationID } else { reservationID = 0 } } return &GetDeviceSDRResponse{ NextRecordID: response.NextRecordID, RecordData: data, }, nil } func (c *Client) GetDeviceSDRBySensorID(ctx context.Context, sensorNumber uint8) (*SDR, error) { if SensorNumber(sensorNumber) == SensorNumberReserved { return nil, fmt.Errorf("not valid sensorNumber, %#0x is reserved", sensorNumber) } var recordID uint16 = 0 for { res, err := c.GetDeviceSDR(ctx, recordID) if err != nil { return nil, fmt.Errorf("GetDeviceSDR for recordID (%#0x) failed, err: %s", recordID, err) } sdr, err := ParseSDR(res.RecordData, res.NextRecordID) if err != nil { return nil, fmt.Errorf("ParseSDR for recordID (%#0x) failed, err: %s", recordID, err) } if uint8(sdr.SensorNumber()) == sensorNumber { return sdr, nil } recordID = res.NextRecordID if recordID == 0xffff { break } } return nil, fmt.Errorf("not found SDR for sensor id (%#0x)", sensorNumber) } func (c *Client) GetDeviceSDRs(ctx context.Context, recordTypes ...SDRRecordType) ([]*SDR, error) { var out = make([]*SDR, 0) var recordID uint16 = 0 for { res, err := c.GetDeviceSDR(ctx, recordID) if err != nil { return nil, fmt.Errorf("GetDeviceSDR for recordID (%#0x) failed, err: %s", recordID, err) } sdr, err := ParseSDR(res.RecordData, res.NextRecordID) if err != nil { return nil, fmt.Errorf("ParseSDR for recordID (%#0x) failed, err: %s", recordID, err) } if len(recordTypes) == 0 { out = append(out, sdr) } else { for _, v := range recordTypes { if sdr.RecordHeader.RecordType == v { out = append(out, sdr) break } } } recordID = res.NextRecordID if recordID == 0xffff { break } } return out, nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_device_sdr_info.go000066400000000000000000000053541474110527100242500ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 35.2 Get Device SDR Info Command type GetDeviceSDRInfoRequest struct { // true: Get SDR count. This returns the total number of SDRs in the device. // false: Get Sensor count. This returns the number of sensors implemented on LUN this command was addressed to. GetSDRCount bool } type GetDeviceSDRInfoResponse struct { getSDRCount bool Count uint8 // 0b = static sensor population. The number of sensors handled by this // device is fixed, and a query shall return records for all sensors. // // 1b = dynamic sensor population. This device may have its sensor // population vary during "run time" (defined as any time other that // when an install operation is in progress). DynamicSensorPopulation bool LUN3HasSensors bool LUN2HasSensors bool LUN1HasSensors bool LUN0HasSensors bool // Four byte timestamp, or counter. Updated or incremented each time the // sensor population changes. This field is not provided if the flags indicate a // static sensor population. SensorPopulationChangeIndicator uint32 } func (req *GetDeviceSDRInfoRequest) Command() Command { return CommandGetDeviceSDRInfo } func (req *GetDeviceSDRInfoRequest) Pack() []byte { var b uint8 if req.GetSDRCount { b = setBit0(b) } return []byte{b} } func (res *GetDeviceSDRInfoResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.Count, _, _ = unpackUint8(msg, 0) b, _, _ := unpackUint8(msg, 1) res.DynamicSensorPopulation = isBit7Set(b) res.LUN3HasSensors = isBit3Set(b) res.LUN2HasSensors = isBit2Set(b) res.LUN1HasSensors = isBit1Set(b) res.LUN0HasSensors = isBit0Set(b) if res.DynamicSensorPopulation { if len(msg) < 6 { return ErrUnpackedDataTooShortWith(len(msg), 6) } res.SensorPopulationChangeIndicator, _, _ = unpackUint32L(msg, 2) } return nil } func (r *GetDeviceSDRInfoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetDeviceSDRInfoResponse) Format() string { return fmt.Sprintf(` Count : %d (%s) Dynamic Population : %v LUN 0 has sensors : %v LUN 1 has sensors : %v LUN 2 has sensors : %v LUN 3 has sensors : %v `, res.Count, formatBool(res.getSDRCount, "SDRs", "Sensors"), res.DynamicSensorPopulation, res.LUN0HasSensors, res.LUN1HasSensors, res.LUN2HasSensors, res.LUN3HasSensors, ) } // This command returns general information about the collection of sensors in a Dynamic Sensor Device. func (c *Client) GetDeviceSDRInfo(ctx context.Context, getSDRCount bool) (response *GetDeviceSDRInfoResponse, err error) { request := &GetDeviceSDRInfoRequest{ GetSDRCount: getSDRCount, } response = &GetDeviceSDRInfoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_event_receiver.go000066400000000000000000000016761474110527100241360ustar00rootroot00000000000000package ipmi import "context" // 29.2 Get Event Receiver Command type GetEventReceiverRequest struct { } type GetEventReceiverResponse struct { SlaveAddress uint8 LUN uint8 } func (req *GetEventReceiverRequest) Pack() []byte { return []byte{} } func (req *GetEventReceiverRequest) Command() Command { return CommandGetEventReceiver } func (res *GetEventReceiverResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetEventReceiverResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.SlaveAddress = msg[0] res.LUN = msg[1] return nil } func (res *GetEventReceiverResponse) Format() string { return "" } func (c *Client) GetEventReceiver(ctx context.Context) (response *GetEventReceiverResponse, err error) { request := &GetEventReceiverRequest{} response = &GetEventReceiverResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_fru_inventory_area_info.go000066400000000000000000000027451474110527100260430ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 34.1 Get FRU Inventory Area Info Command type GetFRUInventoryAreaInfoRequest struct { FRUDeviceID uint8 } type GetFRUInventoryAreaInfoResponse struct { AreaSizeBytes uint16 DeviceAccessedByWords bool // false means Device is accessed by Bytes } func (req *GetFRUInventoryAreaInfoRequest) Command() Command { return CommandGetFRUInventoryAreaInfo } func (req *GetFRUInventoryAreaInfoRequest) Pack() []byte { return []byte{req.FRUDeviceID} } func (res *GetFRUInventoryAreaInfoResponse) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } res.AreaSizeBytes, _, _ = unpackUint16L(msg, 0) b, _, _ := unpackUint8(msg, 2) res.DeviceAccessedByWords = isBit0Set(b) return nil } func (r *GetFRUInventoryAreaInfoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetFRUInventoryAreaInfoResponse) Format() string { return fmt.Sprintf(`fru.size = %d bytes (accessed by %s)`, res.AreaSizeBytes, formatBool(res.DeviceAccessedByWords, "words", "bytes"), ) } // This command returns overall the size of the FRU Inventory Area in this device, in bytes. func (c *Client) GetFRUInventoryAreaInfo(ctx context.Context, fruDeviceID uint8) (response *GetFRUInventoryAreaInfoResponse, err error) { request := &GetFRUInventoryAreaInfoRequest{ FRUDeviceID: fruDeviceID, } response = &GetFRUInventoryAreaInfoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_frus.go000066400000000000000000000263111474110527100221010ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // GetFRUData return all data bytes, the data size is firstly determined by // GetFRUInventoryAreaInfoResponse.AreaSizeBytes func (c *Client) GetFRUData(ctx context.Context, deviceID uint8) ([]byte, error) { fruAreaInfoRes, err := c.GetFRUInventoryAreaInfo(ctx, deviceID) if err != nil { return nil, fmt.Errorf("GetFRUInventoryAreaInfo failed, err: %w", err) } c.Debug("", fruAreaInfoRes.Format()) if fruAreaInfoRes.AreaSizeBytes < 1 { return nil, fmt.Errorf("invalid FRU size %d", fruAreaInfoRes.AreaSizeBytes) } data, err := c.readFRUDataByLength(ctx, deviceID, 0, fruAreaInfoRes.AreaSizeBytes) if err != nil { return nil, fmt.Errorf("read full fru area data failed, err: %w", err) } c.Debugf("Got %d fru data\n", len(data)) return data, nil } // GetFRU return FRU for the specified deviceID. // The deviceName is not a must, pass empty string if not known. func (c *Client) GetFRU(ctx context.Context, deviceID uint8, deviceName string) (*FRU, error) { c.Debugf("GetFRU device name (%s) id (%#02x)\n", deviceName, deviceID) fru := &FRU{ deviceID: deviceID, deviceName: deviceName, } fruAreaInfoRes, err := c.GetFRUInventoryAreaInfo(ctx, deviceID) if err != nil { if resErr, ok := err.(*ResponseError); ok { if resErr.CompletionCode() == CompletionCodeRequestedDataNotPresent { fru.deviceNotPresent = true fru.deviceNotPresentReason = "InventoryRecordNotExist" return fru, nil } } return nil, fmt.Errorf("GetFRUInventoryAreaInfo failed, err: %w", err) } c.Debug("", fruAreaInfoRes.Format()) if fruAreaInfoRes.AreaSizeBytes < 1 { return nil, fmt.Errorf("invalid FRU size %d", fruAreaInfoRes.AreaSizeBytes) } // retrieve the FRU header, just fetch FRUCommonHeaderSize bytes to construct a FRU Header readFRURes, err := c.ReadFRUData(ctx, deviceID, 0, FRUCommonHeaderSize) if err != nil { if resErr, ok := err.(*ResponseError); ok { switch resErr.CompletionCode() { case CompletionCodeRequestedDataNotPresent: fru.deviceNotPresent = true fru.deviceNotPresentReason = "DataNotPresent" return fru, nil case CompletionCodeProcessTimeout: fru.deviceNotPresent = true fru.deviceNotPresentReason = "Timeout" return fru, nil } } return nil, fmt.Errorf("ReadFRUData failed, err: %w", err) } fruHeader := &FRUCommonHeader{} if err := fruHeader.Unpack(readFRURes.Data); err != nil { return nil, fmt.Errorf("unpack fru data failed, err: %w", err) } if fruHeader.FormatVersion != FRUFormatVersion { return nil, fmt.Errorf("unknown FRU header version %#02x", fruHeader.FormatVersion) } c.Debug("FRU Common Header", fruHeader) c.Debugf("%s\n\n", fruHeader.String()) fru.CommonHeader = fruHeader if offset := uint16(fruHeader.ChassisOffset8B) * 8; offset > 0 && offset < fruAreaInfoRes.AreaSizeBytes { c.Debugf("Get FRU Area Chassis, offset (%d)\n", offset) fruChassis, err := c.GetFRUAreaChassis(ctx, deviceID, offset) if err != nil { return nil, fmt.Errorf("GetFRUAreaChassis failed, err: %w", err) } c.Debug("FRU Area Chassis", fruChassis) fru.ChassisInfoArea = fruChassis } if offset := uint16(fruHeader.BoardOffset8B) * 8; offset > 0 && offset < fruAreaInfoRes.AreaSizeBytes { c.Debugf("Get FRU Area Board, offset (%d)\n", offset) fruBoard, err := c.GetFRUAreaBoard(ctx, deviceID, offset) if err != nil { return nil, fmt.Errorf("GetFRUAreaBoard failed, err: %w", err) } c.Debug("FRU Area Board", fruBoard) fru.BoardInfoArea = fruBoard } if offset := uint16(fruHeader.ProductOffset8B) * 8; offset > 0 && offset < fruAreaInfoRes.AreaSizeBytes { c.Debugf("Get FRU Area Product, offset (%d)\n", offset) fruProduct, err := c.GetFRUAreaProduct(ctx, deviceID, offset) if err != nil { return nil, fmt.Errorf("GetFRUAreaProduct failed, err: %w", err) } c.Debug("FRU Area Product", fruProduct) fru.ProductInfoArea = fruProduct } if offset := uint16(fruHeader.MultiRecordsOffset8B) * 8; offset > 0 && offset < fruAreaInfoRes.AreaSizeBytes { c.Debugf("Get FRU Area Multi Records, offset (%d)\n", offset) fruMultiRecords, err := c.GetFRUAreaMultiRecords(ctx, deviceID, offset) if err != nil { return nil, fmt.Errorf("GetFRUAreaMultiRecord failed, err: %w", err) } c.Debug("FRU Area MultiRecords", fruMultiRecords) fru.MultiRecords = fruMultiRecords } c.Debug("FRU", fru) return fru, nil } func (c *Client) GetFRUs(ctx context.Context) ([]*FRU, error) { var frus = make([]*FRU, 0) // Do a Get Device ID command to determine device support deviceRes, err := c.GetDeviceID(ctx) if err != nil { return nil, fmt.Errorf("GetDeviceID failed, err: %w", err) } c.Debug("deviceRes", deviceRes) if deviceRes.AdditionalDeviceSupport.SupportFRUInventory { // FRU Device ID #00 at LUN 00b is predefined as being the FRU Device // for the FRU that the management controller is located on. var deviceID uint8 = 0x00 fru, err := c.GetFRU(ctx, deviceID, "Builtin FRU") if err != nil { return nil, fmt.Errorf("GetFRU device id (%#02x) failed, err: %s", deviceID, err) } frus = append(frus, fru) } // Walk the SDRs to look for FRU Devices and Management Controller Devices. // For FRU devices, print the FRU from the SDR locator record. // For MC devices, issue FRU commands to the satellite controller to print FRU data. sdrs, err := c.GetSDRs(ctx, SDRRecordTypeFRUDeviceLocator, SDRRecordTypeManagementControllerDeviceLocator) if err != nil { return nil, fmt.Errorf("GetSDRS failed, err: %w", err) } for _, sdr := range sdrs { switch sdr.RecordHeader.RecordType { case SDRRecordTypeFRUDeviceLocator: deviceType := sdr.FRUDeviceLocator.DeviceType deviceTypeModifier := sdr.FRUDeviceLocator.DeviceTypeModifier deviceName := string(sdr.FRUDeviceLocator.DeviceIDBytes) deviceAccessAddress := sdr.FRUDeviceLocator.DeviceAccessAddress // controller accessLUN := sdr.FRUDeviceLocator.AccessLUN // LUN privateBusID := sdr.FRUDeviceLocator.PrivateBusID // Private bus deviceIDOrSlaveAddress := sdr.FRUDeviceLocator.FRUDeviceID_SlaveAddress // device fruLocation := sdr.FRUDeviceLocator.Location() c.Debugf("fruLocation: (%s), deviceType: (%s [%#02x]), deviceTypeModifier: (%#02x), deviceIDOrSlaveAddress: (%#02x), deviceName: (%s), isLogical: (%v), "+ "DeviceAccessAddress (%#02x), AccessLUN: (%#02x), PrivateBusID(%#02x)\n", fruLocation, deviceType.String(), uint8(deviceType), deviceTypeModifier, deviceIDOrSlaveAddress, deviceName, sdr.FRUDeviceLocator.IsLogicalFRUDevice, deviceAccessAddress, accessLUN, privateBusID, ) // see 38. Accessing FRU Devices switch fruLocation { case FRULocation_MgmtController: if accessLUN == 0x00 && deviceIDOrSlaveAddress == 0x00 { // this is the Builtin FRU device, already got continue } // Todo, accessed using Read/Write FRU commands at LUN other than 00b fru, err := c.GetFRU(ctx, deviceIDOrSlaveAddress, deviceName) if err != nil { return nil, fmt.Errorf("GetFRU sdr device id (%#02x) failed, err: %s", deviceIDOrSlaveAddress, err) } frus = append(frus, fru) case FRULocation_PrivateBus: // Todo, switch deviceType { case 0x10: // Todo, refactor BuildIPMIRequest to use LUN // if sdr.FRUDeviceLocator.DeviceAccessAddress == BMC_SA && deviceID == 0x00 { // continue // } switch deviceTypeModifier { // 0x00, 0x02 = IPMI FRU Inventory case 0x00, 0x02: // 0x01 = DIMM Memory ID case 0x01: // 03h = System Processor Cartridge FRU / PIROM (processor information ROM) case 0x03: } case 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f: // Todo } case FRULocation_IPMB: } case SDRRecordTypeManagementControllerDeviceLocator: } } return frus, nil } func (c *Client) GetFRUAreaChassis(ctx context.Context, deviceID uint8, offset uint16) (*FRUChassisInfoArea, error) { // read enough (2 bytes) to check the length field res, err := c.ReadFRUData(ctx, deviceID, offset, 2) if err != nil { return nil, fmt.Errorf("ReadFRUData failed, err: %w", err) } length := uint16(res.Data[1]) * 8 // in multiples of 8 bytes // now read full area data data, err := c.readFRUDataByLength(ctx, deviceID, offset, length) if err != nil { return nil, fmt.Errorf("read full fru area data failed, err: %w", err) } c.Debugf("Got %d fru data\n", len(data)) fruChassis := &FRUChassisInfoArea{} if err := fruChassis.Unpack(data); err != nil { return nil, fmt.Errorf("unpack fru chassis failed, err: %w", err) } return fruChassis, nil } func (c *Client) GetFRUAreaBoard(ctx context.Context, deviceID uint8, offset uint16) (*FRUBoardInfoArea, error) { // read enough (2 bytes) to check the length field res, err := c.ReadFRUData(ctx, deviceID, offset, 2) if err != nil { return nil, fmt.Errorf("ReadFRUData failed, err: %w", err) } length := uint16(res.Data[1]) * 8 // in multiples of 8 bytes // now read full area data data, err := c.readFRUDataByLength(ctx, deviceID, offset, length) if err != nil { return nil, fmt.Errorf("read full fru area data failed, err: %w", err) } c.Debugf("Got %d fru data\n", len(data)) fruBoard := &FRUBoardInfoArea{} if err := fruBoard.Unpack(data); err != nil { return nil, fmt.Errorf("unpack fru board failed, err: %w", err) } return fruBoard, nil } func (c *Client) GetFRUAreaProduct(ctx context.Context, deviceID uint8, offset uint16) (*FRUProductInfoArea, error) { // read enough (2 bytes) to check the length field res, err := c.ReadFRUData(ctx, deviceID, offset, 2) if err != nil { return nil, fmt.Errorf("ReadFRUData failed, err: %w", err) } length := uint16(res.Data[1]) * 8 // in multiples of 8 bytes // now read full area data data, err := c.readFRUDataByLength(ctx, deviceID, offset, length) if err != nil { return nil, fmt.Errorf("read full fru area data failed, err: %w", err) } c.Debugf("Got %d fru data\n", len(data)) fruProduct := &FRUProductInfoArea{} if err := fruProduct.Unpack(data); err != nil { return nil, fmt.Errorf("unpack fru board failed, err: %w", err) } return fruProduct, nil } func (c *Client) GetFRUAreaMultiRecords(ctx context.Context, deviceID uint8, offset uint16) ([]*FRUMultiRecord, error) { records := make([]*FRUMultiRecord, 0) for { // read enough (5 bytes) to check the length of each record // For a MultiRecord, the first 5 bytes contains the Record Header, // and the third byte holds the data length. // // see: FRU/16.1 Record Header res, err := c.ReadFRUData(ctx, deviceID, offset, 5) if err != nil { return nil, fmt.Errorf("ReadFRUData failed, err: %w", err) } length := uint16(res.Data[2]) // now read full data for this record recordSize := 5 + length // Record Header + Data Length data, err := c.readFRUDataByLength(ctx, deviceID, offset, recordSize) if err != nil { return nil, fmt.Errorf("read full fru area data failed, err: %w", err) } c.Debugf("Got %d fru data\n", len(data)) record := &FRUMultiRecord{} if err := record.Unpack(data); err != nil { return nil, fmt.Errorf("unpack fru multi record failed, err: %w", err) } c.Debug("Multi record", record) records = append(records, record) // update offset for the next record offset += uint16(5 + record.RecordLength) if record.EndOfList { break } } return records, nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_ip_statistics.go000066400000000000000000000050711474110527100240040ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 23.4 Get IP/UDP/RMCP Statistics Command type GetIPStatisticsRequest struct { ChannelNumber uint8 ClearAllStatistics bool } type GetIPStatisticsResponse struct { IPPacketsReceived uint16 IPHeaderErrorsReceived uint16 IPAddressErrorsReceived uint16 IPPacketsFragmentedReceived uint16 IPPacketsTransmitted uint16 UDPPacketsReceived uint16 RMCPPacketsValidReceived uint16 UDPProxyPacketsReceived uint16 UDPProxyPacketsDropped uint16 } func (req *GetIPStatisticsRequest) Pack() []byte { out := make([]byte, 2) packUint8(req.ChannelNumber, out, 0) var b uint8 if req.ClearAllStatistics { b = setBit0(b) } packUint8(b, out, 1) return out } func (req *GetIPStatisticsRequest) Command() Command { return CommandGetIPStatistics } func (res *GetIPStatisticsResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetIPStatisticsResponse) Unpack(msg []byte) error { if len(msg) < 18 { return ErrUnpackedDataTooShortWith(len(msg), 18) } res.IPPacketsReceived, _, _ = unpackUint16L(msg, 0) res.IPHeaderErrorsReceived, _, _ = unpackUint16L(msg, 2) res.IPAddressErrorsReceived, _, _ = unpackUint16L(msg, 4) res.IPPacketsFragmentedReceived, _, _ = unpackUint16L(msg, 6) res.IPPacketsTransmitted, _, _ = unpackUint16L(msg, 8) res.UDPPacketsReceived, _, _ = unpackUint16L(msg, 10) res.RMCPPacketsValidReceived, _, _ = unpackUint16L(msg, 12) res.UDPProxyPacketsReceived, _, _ = unpackUint16L(msg, 14) res.UDPProxyPacketsDropped, _, _ = unpackUint16L(msg, 16) return nil } func (res *GetIPStatisticsResponse) Format() string { return fmt.Sprintf(`IP Rx Packet : %d IP Rx Header Errors : %d IP Rx Address Errors : %d IP Rx Fragmented : %d IP Tx Packet : %d UDP Rx Packet : %d RMCP Rx Valid : %d UDP Proxy Packet Received : %d UDP Proxy Packet Dropped : %d`, res.IPPacketsReceived, res.IPHeaderErrorsReceived, res.IPAddressErrorsReceived, res.IPPacketsFragmentedReceived, res.IPPacketsTransmitted, res.UDPPacketsReceived, res.RMCPPacketsValidReceived, res.UDPProxyPacketsReceived, res.UDPProxyPacketsDropped, ) } func (c *Client) GetIPStatistics(ctx context.Context, channelNumber uint8, clearAllStatistics bool) (response *GetIPStatisticsResponse, err error) { request := &GetIPStatisticsRequest{ ChannelNumber: channelNumber, ClearAllStatistics: clearAllStatistics, } response = &GetIPStatisticsResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_lan_config_params.go000066400000000000000000000672451474110527100245770ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 23.2 Get LAN Configuration Parameters Command type GetLanConfigParamRequest struct { ChannelNumber uint8 ParamSelector LanConfigParamSelector SetSelector uint8 BlockSelector uint8 } type GetLanConfigParamResponse struct { ParamRevision uint8 ParamData []byte } func (req *GetLanConfigParamRequest) Pack() []byte { out := make([]byte, 4) packUint8(req.ChannelNumber, out, 0) packUint8(uint8(req.ParamSelector), out, 1) packUint8(req.SetSelector, out, 2) packUint8(req.BlockSelector, out, 3) return out } func (req *GetLanConfigParamRequest) Command() Command { return CommandGetLanConfigParam } func (res *GetLanConfigParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "parameter not supported.", } } func (res *GetLanConfigParamResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } res.ParamRevision, _, _ = unpackUint8(msg, 0) res.ParamData, _, _ = unpackBytes(msg, 1, len(msg)-1) return nil } func (res *GetLanConfigParamResponse) Format() string { out := ` Parameter Revision : %d Param Data : %v Length of Config Data : %d ` return fmt.Sprintf(out, res.ParamRevision, res.ParamData, len(res.ParamData)) } func (c *Client) GetLanConfigParam(ctx context.Context, channelNumber uint8, paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) (response *GetLanConfigParamResponse, err error) { request := &GetLanConfigParamRequest{ ChannelNumber: channelNumber, ParamSelector: paramSelector, SetSelector: setSelector, BlockSelector: blockSelector, } response = &GetLanConfigParamResponse{} err = c.Exchange(ctx, request, response) return } // GetLanConfigParamFor get the lan config for a specific parameter. // // The param is a pointer to a struct that implements the LanConfigParameter interface. func (c *Client) GetLanConfigParamFor(ctx context.Context, channelNumber uint8, param LanConfigParameter) error { if isNilLanConfigParameter(param) { return nil } paramSelector, setSelector, blockSelector := param.LanConfigParameter() c.Debugf(">> Get LanConfigParam for paramSelector (%d) %s, setSelector %d, blockSelector %d\n", uint8(paramSelector), paramSelector, setSelector, blockSelector) response, err := c.GetLanConfigParam(ctx, channelNumber, paramSelector, setSelector, blockSelector) if err != nil { c.Debugf("!!! Get LanConfigParam for paramSelector (%d) %s, setSelector %d failed, err: %v\n", uint8(paramSelector), paramSelector, setSelector, err) return err } c.DebugBytes(fmt.Sprintf("<< Got param data for (%s[%d]) ", paramSelector.String(), paramSelector), response.ParamData, 8) if err := param.Unpack(response.ParamData); err != nil { return fmt.Errorf("unpack lan config param (%s [%d]) failed, err: %w", paramSelector.String(), paramSelector, err) } return nil } func (c *Client) GetLanConfig(ctx context.Context, channelNumber uint8) (*LanConfig, error) { lanConfigParams, err := c.GetLanConfigParams(ctx, channelNumber) if err != nil { return nil, fmt.Errorf("GetLanConfigParams failed, err: %w", err) } return lanConfigParams.ToLanConfig(), nil } func (c *Client) GetLanConfigParams(ctx context.Context, channelNumber uint8) (*LanConfigParams, error) { lanConfigParams := &LanConfigParams{ SetInProgress: &LanConfigParam_SetInProgress{}, AuthTypeSupport: &LanConfigParam_AuthTypeSupport{}, AuthTypeEnables: &LanConfigParam_AuthTypeEnables{}, IP: &LanConfigParam_IP{}, IPSource: &LanConfigParam_IPSource{}, MAC: &LanConfigParam_MAC{}, SubnetMask: &LanConfigParam_SubnetMask{}, IPv4HeaderParams: &LanConfigParam_IPv4HeaderParams{}, PrimaryRMCPPort: &LanConfigParam_PrimaryRMCPPort{}, SecondaryRMCPPort: &LanConfigParam_SecondaryRMCPPort{}, ARPControl: &LanConfigParam_ARPControl{}, GratuitousARPInterval: &LanConfigParam_GratuitousARPInterval{}, DefaultGatewayIP: &LanConfigParam_DefaultGatewayIP{}, DefaultGatewayMAC: &LanConfigParam_DefaultGatewayMAC{}, BackupGatewayIP: &LanConfigParam_BackupGatewayIP{}, BackupGatewayMAC: &LanConfigParam_BackupGatewayMAC{}, CommunityString: &LanConfigParam_CommunityString{}, // AlertDestinationsCount: &LanConfigParam_AlertDestinationsCount{}, // AlertDestinationTypes: make([]*LanConfigParam_AlertDestinationType, 0), // AlertDestinationAddresses: make([]*LanConfigParam_AlertDestinationAddress, 0), VLANID: &LanConfigParam_VLANID{}, VLANPriority: &LanConfigParam_VLANPriority{}, CipherSuitesSupport: &LanConfigParam_CipherSuitesSupport{}, CipherSuitesID: &LanConfigParam_CipherSuitesID{}, CipherSuitesPrivLevel: &LanConfigParam_CipherSuitesPrivLevel{}, AlertDestinationVLANs: make([]*LanConfigParam_AlertDestinationVLAN, 0), BadPasswordThreshold: &LanConfigParam_BadPasswordThreshold{}, // IPv6Support: &LanConfigParam_IPv6Support{}, // IPv6Enables: &LanConfigParam_IPv6Enables{}, // IPv6StaticTrafficClass: &LanConfigParam_IPv6StaticTrafficClass{}, // IPv6StaticHopLimit: &LanConfigParam_IPv6StaticHopLimit{}, // IPv6FlowLabel: &LanConfigParam_IPv6FlowLabel{}, // IPv6Status: &LanConfigParam_IPv6Status{}, // IPv6StaticAddresses: make([]*LanConfigParam_IPv6StaticAddress, 0), // IPv6DHCPv6StaticDUIDCount: &LanConfigParam_IPv6DHCPv6StaticDUIDCount{}, // IPv6DHCPv6StaticDUIDs: make([]*LanConfigParam_IPv6DHCPv6StaticDUID, 0), // IPv6DynamicAddresses: make([]*LanConfigParam_IPv6DynamicAddress, 0), // IPv6DHCPv6DynamicDUIDCount: &LanConfigParam_IPv6DHCPv6DynamicDUIDCount{}, // IPv6DHCPv6DynamicDUIDs: make([]*LanConfigParam_IPv6DHCPv6DynamicDUID, 0), // IPv6DHCPv6TimingConfigSupport: &LanConfigParam_IPv6DHCPv6TimingConfigSupport{}, // IPv6DHCPv6TimingConfig: make([]*LanConfigParam_IPv6DHCPv6TimingConfig, 0), // IPv6RouterAddressConfigControl: &LanConfigParam_IPv6RouterAddressConfigControl{}, // IPv6StaticRouter1IP: &LanConfigParam_IPv6StaticRouter1IP{}, // IPv6StaticRouter1MAC: &LanConfigParam_IPv6StaticRouter1MAC{}, // IPv6StaticRouter1PrefixLength: &LanConfigParam_IPv6StaticRouter1PrefixLength{}, // IPv6StaticRouter1PrefixValue: &LanConfigParam_IPv6StaticRouter1PrefixValue{}, // IPv6StaticRouter2IP: &LanConfigParam_IPv6StaticRouter2IP{}, // IPv6StaticRouter2MAC: &LanConfigParam_IPv6StaticRouter2MAC{}, // IPv6StaticRouter2PrefixLength: &LanConfigParam_IPv6StaticRouter2PrefixLength{}, // IPv6StaticRouter2PrefixValue: &LanConfigParam_IPv6StaticRouter2PrefixValue{}, // IPv6DynamicRouterInfoSets: &LanConfigParam_IPv6DynamicRouterInfoSets{}, // IPv6DynamicRouterInfoIP: make([]*LanConfigParam_IPv6DynamicRouterInfoIP, 0), // IPv6DynamicRouterInfoMAC: make([]*LanConfigParam_IPv6DynamicRouterInfoMAC, 0), // IPv6DynamicRouterInfoPrefixLength: make([]*LanConfigParam_IPv6DynamicRouterInfoPrefixLength, 0), // IPv6DynamicRouterInfoPrefixValue: make([]*LanConfigParam_IPv6DynamicRouterInfoPrefixValue, 0), // IPv6DynamicRouterReceivedHopLimit: &LanConfigParam_IPv6DynamicRouterReceivedHopLimit{}, // IPv6NDSLAACTimingConfigSupport: &LanConfigParam_IPv6NDSLAACTimingConfigSupport{}, // IPv6NDSLAACTimingConfig: make([]*LanConfigParam_IPv6NDSLAACTimingConfig, 0), } if err := c.GetLanConfigParamsFor(ctx, channelNumber, lanConfigParams); err != nil { return nil, err } return lanConfigParams, nil } func (c *Client) GetLanConfigParamsFull(ctx context.Context, channelNumber uint8) (*LanConfigParams, error) { lanConfigParams := &LanConfigParams{ SetInProgress: &LanConfigParam_SetInProgress{}, AuthTypeSupport: &LanConfigParam_AuthTypeSupport{}, AuthTypeEnables: &LanConfigParam_AuthTypeEnables{}, IP: &LanConfigParam_IP{}, IPSource: &LanConfigParam_IPSource{}, MAC: &LanConfigParam_MAC{}, SubnetMask: &LanConfigParam_SubnetMask{}, IPv4HeaderParams: &LanConfigParam_IPv4HeaderParams{}, PrimaryRMCPPort: &LanConfigParam_PrimaryRMCPPort{}, SecondaryRMCPPort: &LanConfigParam_SecondaryRMCPPort{}, ARPControl: &LanConfigParam_ARPControl{}, GratuitousARPInterval: &LanConfigParam_GratuitousARPInterval{}, DefaultGatewayIP: &LanConfigParam_DefaultGatewayIP{}, DefaultGatewayMAC: &LanConfigParam_DefaultGatewayMAC{}, BackupGatewayIP: &LanConfigParam_BackupGatewayIP{}, BackupGatewayMAC: &LanConfigParam_BackupGatewayMAC{}, CommunityString: &LanConfigParam_CommunityString{}, AlertDestinationsCount: &LanConfigParam_AlertDestinationsCount{}, AlertDestinationTypes: make([]*LanConfigParam_AlertDestinationType, 0), AlertDestinationAddresses: make([]*LanConfigParam_AlertDestinationAddress, 0), VLANID: &LanConfigParam_VLANID{}, VLANPriority: &LanConfigParam_VLANPriority{}, CipherSuitesSupport: &LanConfigParam_CipherSuitesSupport{}, CipherSuitesID: &LanConfigParam_CipherSuitesID{}, CipherSuitesPrivLevel: &LanConfigParam_CipherSuitesPrivLevel{}, AlertDestinationVLANs: make([]*LanConfigParam_AlertDestinationVLAN, 0), BadPasswordThreshold: &LanConfigParam_BadPasswordThreshold{}, IPv6Support: &LanConfigParam_IPv6Support{}, IPv6Enables: &LanConfigParam_IPv6Enables{}, IPv6StaticTrafficClass: &LanConfigParam_IPv6StaticTrafficClass{}, IPv6StaticHopLimit: &LanConfigParam_IPv6StaticHopLimit{}, IPv6FlowLabel: &LanConfigParam_IPv6FlowLabel{}, IPv6Status: &LanConfigParam_IPv6Status{}, IPv6StaticAddresses: make([]*LanConfigParam_IPv6StaticAddress, 0), IPv6DHCPv6StaticDUIDCount: &LanConfigParam_IPv6DHCPv6StaticDUIDCount{}, IPv6DHCPv6StaticDUIDs: make([]*LanConfigParam_IPv6DHCPv6StaticDUID, 0), IPv6DynamicAddresses: make([]*LanConfigParam_IPv6DynamicAddress, 0), IPv6DHCPv6DynamicDUIDCount: &LanConfigParam_IPv6DHCPv6DynamicDUIDCount{}, IPv6DHCPv6DynamicDUIDs: make([]*LanConfigParam_IPv6DHCPv6DynamicDUID, 0), IPv6DHCPv6TimingConfigSupport: &LanConfigParam_IPv6DHCPv6TimingConfigSupport{}, IPv6DHCPv6TimingConfig: make([]*LanConfigParam_IPv6DHCPv6TimingConfig, 0), IPv6RouterAddressConfigControl: &LanConfigParam_IPv6RouterAddressConfigControl{}, IPv6StaticRouter1IP: &LanConfigParam_IPv6StaticRouter1IP{}, IPv6StaticRouter1MAC: &LanConfigParam_IPv6StaticRouter1MAC{}, IPv6StaticRouter1PrefixLength: &LanConfigParam_IPv6StaticRouter1PrefixLength{}, IPv6StaticRouter1PrefixValue: &LanConfigParam_IPv6StaticRouter1PrefixValue{}, IPv6StaticRouter2IP: &LanConfigParam_IPv6StaticRouter2IP{}, IPv6StaticRouter2MAC: &LanConfigParam_IPv6StaticRouter2MAC{}, IPv6StaticRouter2PrefixLength: &LanConfigParam_IPv6StaticRouter2PrefixLength{}, IPv6StaticRouter2PrefixValue: &LanConfigParam_IPv6StaticRouter2PrefixValue{}, IPv6DynamicRouterInfoSets: &LanConfigParam_IPv6DynamicRouterInfoSets{}, IPv6DynamicRouterInfoIP: make([]*LanConfigParam_IPv6DynamicRouterInfoIP, 0), IPv6DynamicRouterInfoMAC: make([]*LanConfigParam_IPv6DynamicRouterInfoMAC, 0), IPv6DynamicRouterInfoPrefixLength: make([]*LanConfigParam_IPv6DynamicRouterInfoPrefixLength, 0), IPv6DynamicRouterInfoPrefixValue: make([]*LanConfigParam_IPv6DynamicRouterInfoPrefixValue, 0), IPv6DynamicRouterReceivedHopLimit: &LanConfigParam_IPv6DynamicRouterReceivedHopLimit{}, IPv6NDSLAACTimingConfigSupport: &LanConfigParam_IPv6NDSLAACTimingConfigSupport{}, IPv6NDSLAACTimingConfig: make([]*LanConfigParam_IPv6NDSLAACTimingConfig, 0), } if err := c.GetLanConfigParamsFor(ctx, channelNumber, lanConfigParams); err != nil { return nil, err } return lanConfigParams, nil } // GetLanConfigParamsFor get the lan config params. // You can initialize specific fields of LanConfigParams struct, which indicates to only get params for those fields. func (c *Client) GetLanConfigParamsFor(ctx context.Context, channelNumber uint8, lanConfigParams *LanConfigParams) error { if lanConfigParams == nil { return nil } var canIgnore = buildCanIgnoreFn( 0x80, // parameter not supported ) if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.SetInProgress); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.AuthTypeSupport); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.AuthTypeEnables); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IP); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPSource); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.MAC); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.SubnetMask); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv4HeaderParams); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.PrimaryRMCPPort); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.SecondaryRMCPPort); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.ARPControl); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.GratuitousARPInterval); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.DefaultGatewayIP); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.DefaultGatewayMAC); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.BackupGatewayIP); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.BackupGatewayMAC); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.CommunityString); canIgnore(err) != nil { return err } alertDestinationsCount := uint8(0) if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.AlertDestinationsCount); err != nil { if canIgnore(err) != nil { return err } } else { if lanConfigParams.AlertDestinationsCount != nil { alertDestinationsCount = lanConfigParams.AlertDestinationsCount.Count } } if lanConfigParams.AlertDestinationTypes != nil { if len(lanConfigParams.AlertDestinationTypes) == 0 && alertDestinationsCount > 0 { count := alertDestinationsCount + 1 lanConfigParams.AlertDestinationTypes = make([]*LanConfigParam_AlertDestinationType, count) for i := uint8(0); i < count; i++ { lanConfigParams.AlertDestinationTypes[i] = &LanConfigParam_AlertDestinationType{ SetSelector: i, } } } for _, alertDestinationType := range lanConfigParams.AlertDestinationTypes { if err := c.GetLanConfigParamFor(ctx, channelNumber, alertDestinationType); err != nil { return err } } } if lanConfigParams.AlertDestinationAddresses != nil { if len(lanConfigParams.AlertDestinationAddresses) == 0 && alertDestinationsCount > 0 { count := alertDestinationsCount + 1 lanConfigParams.AlertDestinationAddresses = make([]*LanConfigParam_AlertDestinationAddress, count) for i := uint8(0); i < count; i++ { lanConfigParams.AlertDestinationAddresses[i] = &LanConfigParam_AlertDestinationAddress{ SetSelector: i, } } } for _, alertDestinationAddress := range lanConfigParams.AlertDestinationAddresses { if err := c.GetLanConfigParamFor(ctx, channelNumber, alertDestinationAddress); err != nil { return err } } } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.VLANID); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.VLANPriority); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.CipherSuitesSupport); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.CipherSuitesID); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.CipherSuitesPrivLevel); canIgnore(err) != nil { return err } if lanConfigParams.AlertDestinationVLANs != nil { if len(lanConfigParams.AlertDestinationVLANs) == 0 && alertDestinationsCount > 0 { count := alertDestinationsCount + 1 lanConfigParams.AlertDestinationVLANs = make([]*LanConfigParam_AlertDestinationVLAN, count) for i := uint8(0); i < count; i++ { lanConfigParams.AlertDestinationVLANs[i] = &LanConfigParam_AlertDestinationVLAN{ SetSelector: i, } } } for _, alertDestinationVLAN := range lanConfigParams.AlertDestinationVLANs { if err := c.GetLanConfigParamFor(ctx, channelNumber, alertDestinationVLAN); err != nil { return err } } } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.BadPasswordThreshold); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6Support); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6Enables); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticTrafficClass); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticHopLimit); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6FlowLabel); canIgnore(err) != nil { return err } var ipv6StaticAddressMax uint8 var ipv6DynamicAddressMax uint8 if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6Status); err != nil { if canIgnore(err) != nil { return err } } else { if lanConfigParams.IPv6Status != nil { ipv6StaticAddressMax = lanConfigParams.IPv6Status.StaticAddressMax ipv6DynamicAddressMax = lanConfigParams.IPv6Status.DynamicAddressMax } } if lanConfigParams.IPv6StaticAddresses != nil { if len(lanConfigParams.IPv6StaticAddresses) == 0 && ipv6StaticAddressMax > 0 { count := ipv6StaticAddressMax lanConfigParams.IPv6StaticAddresses = make([]*LanConfigParam_IPv6StaticAddress, count) for i := uint8(0); i < count; i++ { lanConfigParams.IPv6StaticAddresses[i] = &LanConfigParam_IPv6StaticAddress{ SetSelector: i, } } } for _, ipv6StaticAddress := range lanConfigParams.IPv6StaticAddresses { if err := c.GetLanConfigParamFor(ctx, channelNumber, ipv6StaticAddress); err != nil { return err } } } var ipv6DHCPv6StaticDUIDCount uint8 if lanConfigParams.IPv6DHCPv6StaticDUIDCount != nil { if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6DHCPv6StaticDUIDCount); err != nil { if canIgnore(err) != nil { return err } } else { ipv6DHCPv6StaticDUIDCount = lanConfigParams.IPv6DHCPv6StaticDUIDCount.Max } } if lanConfigParams.IPv6DHCPv6StaticDUIDs != nil { if len(lanConfigParams.IPv6DHCPv6StaticDUIDs) == 0 && ipv6DHCPv6StaticDUIDCount > 0 { count := ipv6DHCPv6StaticDUIDCount lanConfigParams.IPv6DHCPv6StaticDUIDs = make([]*LanConfigParam_IPv6DHCPv6StaticDUID, count) for i := uint8(0); i < count; i++ { lanConfigParams.IPv6DHCPv6StaticDUIDs[i] = &LanConfigParam_IPv6DHCPv6StaticDUID{ SetSelector: i, } } } for _, ipv6DHCPv6StaticDUID := range lanConfigParams.IPv6DHCPv6StaticDUIDs { if err := c.GetLanConfigParamFor(ctx, channelNumber, ipv6DHCPv6StaticDUID); err != nil { return err } } } if lanConfigParams.IPv6DynamicAddresses != nil { if len(lanConfigParams.IPv6DynamicAddresses) == 0 && ipv6DynamicAddressMax > 0 { count := ipv6DynamicAddressMax lanConfigParams.IPv6DynamicAddresses = make([]*LanConfigParam_IPv6DynamicAddress, count) for i := uint8(0); i < count; i++ { lanConfigParams.IPv6DynamicAddresses[i] = &LanConfigParam_IPv6DynamicAddress{ SetSelector: i, } } } for _, ipv6DynamicAddress := range lanConfigParams.IPv6DynamicAddresses { if err := c.GetLanConfigParamFor(ctx, channelNumber, ipv6DynamicAddress); err != nil { return err } } } var ipv6DHCPv6DynamicDUIDCount uint8 if lanConfigParams.IPv6DHCPv6DynamicDUIDCount != nil { if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6DHCPv6DynamicDUIDCount); err != nil { if canIgnore(err) != nil { return err } } else { if lanConfigParams.IPv6DHCPv6DynamicDUIDCount != nil { ipv6DHCPv6DynamicDUIDCount = lanConfigParams.IPv6DHCPv6DynamicDUIDCount.Max } } } if lanConfigParams.IPv6DHCPv6DynamicDUIDs != nil { if len(lanConfigParams.IPv6DHCPv6DynamicDUIDs) == 0 && ipv6DHCPv6DynamicDUIDCount > 0 { // Todo // count := ipv6DHCPv6DynamicDUIDCount // lanConfig.IPv6DHCPv6DynamicDUIDs = make([]*LanConfigParam_IPv6DHCPv6DynamicDUID, count) // for i := uint8(0); i < count; i++ { // lanConfig.IPv6DHCPv6DynamicDUIDs[i] = &LanConfigParam_IPv6DHCPv6DynamicDUID{ // SetSelector: i, // } // } // for _, ipv6DHCPv6DynamicDUID := range lanConfig.IPv6DHCPv6DynamicDUIDs { // if err := c.GetLanConfigParamFor(ctx, channelNumber, ipv6DHCPv6DynamicDUID); err != nil { // return err // } // } } } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6DHCPv6TimingConfigSupport); canIgnore(err) != nil { return err } if lanConfigParams.IPv6DHCPv6TimingConfig != nil { // Todo // if len(lanConfig.IPv6DHCPv6TimingConfig) == 0 && ipv6DynamicAddressMax > 0 { // count := ipv6DynamicAddressMax // lanConfig.IPv6DHCPv6TimingConfig = make([]*LanConfigParam_IPv6DHCPv6TimingConfig, count) // for i := uint8(0); i < count; i++ { // lanConfig.IPv6DHCPv6TimingConfig[i] = &LanConfigParam_IPv6DHCPv6TimingConfig{ // SetSelector: i, // } // } // for _, ipv6DHCPv6TimingConfig := range lanConfig.IPv6DHCPv6TimingConfig { // if err := c.GetLanConfigParamFor(ctx, channelNumber, ipv6DHCPv6TimingConfig); err != nil { // return err // } // } // } } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6RouterAddressConfigControl); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticRouter1IP); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticRouter1MAC); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticRouter1PrefixLength); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticRouter1PrefixValue); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticRouter2IP); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticRouter2MAC); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticRouter2PrefixLength); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6StaticRouter2PrefixValue); canIgnore(err) != nil { return err } var ipv6DynamicRouterInfoCount uint8 if lanConfigParams.IPv6DynamicRouterInfoSets != nil { if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6DynamicRouterInfoSets); err != nil { if canIgnore(err) != nil { return err } } else { if lanConfigParams.IPv6DynamicRouterInfoSets != nil { ipv6DynamicRouterInfoCount = lanConfigParams.IPv6DynamicRouterInfoSets.Count } } } if lanConfigParams.IPv6DynamicRouterInfoIP != nil { if len(lanConfigParams.IPv6DynamicRouterInfoIP) == 0 && ipv6DynamicRouterInfoCount > 0 { count := ipv6DynamicRouterInfoCount lanConfigParams.IPv6DynamicRouterInfoIP = make([]*LanConfigParam_IPv6DynamicRouterInfoIP, count) for i := uint8(0); i < count; i++ { lanConfigParams.IPv6DynamicRouterInfoIP[i] = &LanConfigParam_IPv6DynamicRouterInfoIP{ SetSelector: i, } } for _, ipv6DynamicRouterInfoIP := range lanConfigParams.IPv6DynamicRouterInfoIP { if err := c.GetLanConfigParamFor(ctx, channelNumber, ipv6DynamicRouterInfoIP); err != nil { return err } } } } if lanConfigParams.IPv6DynamicRouterInfoMAC != nil { if len(lanConfigParams.IPv6DynamicRouterInfoMAC) == 0 && ipv6DynamicRouterInfoCount > 0 { count := ipv6DynamicRouterInfoCount lanConfigParams.IPv6DynamicRouterInfoMAC = make([]*LanConfigParam_IPv6DynamicRouterInfoMAC, count) for i := uint8(0); i < count; i++ { lanConfigParams.IPv6DynamicRouterInfoMAC[i] = &LanConfigParam_IPv6DynamicRouterInfoMAC{ SetSelector: i, } } for _, ipv6DynamicRouterInfoMAC := range lanConfigParams.IPv6DynamicRouterInfoMAC { if err := c.GetLanConfigParamFor(ctx, channelNumber, ipv6DynamicRouterInfoMAC); err != nil { return err } } } } if lanConfigParams.IPv6DynamicRouterInfoPrefixLength != nil { if len(lanConfigParams.IPv6DynamicRouterInfoPrefixLength) == 0 && ipv6DynamicRouterInfoCount > 0 { count := ipv6DynamicRouterInfoCount lanConfigParams.IPv6DynamicRouterInfoPrefixLength = make([]*LanConfigParam_IPv6DynamicRouterInfoPrefixLength, count) for i := uint8(0); i < count; i++ { lanConfigParams.IPv6DynamicRouterInfoPrefixLength[i] = &LanConfigParam_IPv6DynamicRouterInfoPrefixLength{ SetSelector: i, } } for _, ipv6DynamicRouterInfoPrefixLength := range lanConfigParams.IPv6DynamicRouterInfoPrefixLength { if err := c.GetLanConfigParamFor(ctx, channelNumber, ipv6DynamicRouterInfoPrefixLength); err != nil { return err } } } } if lanConfigParams.IPv6DynamicRouterInfoPrefixValue != nil { if len(lanConfigParams.IPv6DynamicRouterInfoPrefixValue) == 0 && ipv6DynamicRouterInfoCount > 0 { count := ipv6DynamicRouterInfoCount lanConfigParams.IPv6DynamicRouterInfoPrefixValue = make([]*LanConfigParam_IPv6DynamicRouterInfoPrefixValue, count) for i := uint8(0); i < count; i++ { lanConfigParams.IPv6DynamicRouterInfoPrefixValue[i] = &LanConfigParam_IPv6DynamicRouterInfoPrefixValue{ SetSelector: i, } } for _, ipv6DynamicRouterInfoPrefixValue := range lanConfigParams.IPv6DynamicRouterInfoPrefixValue { if err := c.GetLanConfigParamFor(ctx, channelNumber, ipv6DynamicRouterInfoPrefixValue); err != nil { return err } } } } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6DynamicRouterReceivedHopLimit); canIgnore(err) != nil { return err } if err := c.GetLanConfigParamFor(ctx, channelNumber, lanConfigParams.IPv6NDSLAACTimingConfigSupport); canIgnore(err) != nil { return err } if lanConfigParams.IPv6NDSLAACTimingConfig != nil { // Todo } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_last_processed_event_id.go000066400000000000000000000040211474110527100260030ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "time" ) // 30.6 Get Last Processed Event ID Command type GetLastProcessedEventIdRequest struct { // empty } type GetLastProcessedEventIdResponse struct { MostRecentAdditionTime time.Time LastRecordID uint16 // Record ID for last record in SEL. Returns FFFFh if SEL is empty. LastSoftwareProcessedEventRecordID uint16 LastBMCProcessedEventRecordID uint16 // Returns 0000h when event has been processed but could not be logged because the SEL is full or logging has been disabled. } func (req *GetLastProcessedEventIdRequest) Command() Command { return CommandGetLastProcessedEventId } func (req *GetLastProcessedEventIdRequest) Pack() []byte { return []byte{} } func (res *GetLastProcessedEventIdResponse) Unpack(msg []byte) error { if len(msg) < 10 { return ErrUnpackedDataTooShort } ts, _, _ := unpackUint32L(msg, 0) res.MostRecentAdditionTime = parseTimestamp(ts) res.LastRecordID, _, _ = unpackUint16L(msg, 4) res.LastSoftwareProcessedEventRecordID, _, _ = unpackUint16L(msg, 6) res.LastBMCProcessedEventRecordID, _, _ = unpackUint16L(msg, 8) return nil } func (r *GetLastProcessedEventIdResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "cannot execute command, SEL erase in progress", } } func (res *GetLastProcessedEventIdResponse) Format() string { return fmt.Sprintf(` Last SEL addition : %s Last SEL record ID : %#04x (%d) Last S/W processed ID : %#04x (%d) Last BMC processed ID : %#04x (%d) `, res.MostRecentAdditionTime.String(), res.LastRecordID, res.LastRecordID, res.LastSoftwareProcessedEventRecordID, res.LastSoftwareProcessedEventRecordID, res.LastBMCProcessedEventRecordID, res.LastBMCProcessedEventRecordID, ) } func (c *Client) GetLastProcessedEventId(ctx context.Context) (response *GetLastProcessedEventIdResponse, err error) { request := &GetLastProcessedEventIdRequest{} response = &GetLastProcessedEventIdResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_message.go000066400000000000000000000017561474110527100225540ustar00rootroot00000000000000package ipmi import "context" // 22.6 Get Message Command type GetMessageRequest struct { // empty } type GetMessageResponse struct { ChannelNumber uint8 MessageData []byte } func (req *GetMessageRequest) Command() Command { return CommandGetMessage } func (req *GetMessageRequest) Pack() []byte { return []byte{} } func (res *GetMessageResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "data not available (queue / buffer empty)", } } func (res *GetMessageResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } res.ChannelNumber, _, _ = unpackUint8(msg, 0) res.MessageData, _, _ = unpackBytes(msg, 1, len(msg)-1) return nil } func (res *GetMessageResponse) Format() string { return "" } func (c *Client) GetMessage(ctx context.Context) (response *GetMessageResponse, err error) { request := &GetMessageRequest{} response = &GetMessageResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_message_flags.go000066400000000000000000000027421474110527100237240ustar00rootroot00000000000000package ipmi import "context" // 22.4 Get Message Flags Command type GetMessageFlagsRequest struct { // empty } type GetMessageFlagsResponse struct { OEM2Available bool OEM1Available bool OEM0Available bool WatchdogPreTimeoutInterruptOccurred bool EventMessageBufferFull bool ReceiveMessageQueueAvailable bool // One or more messages ready for reading from Receive Message Queue } func (req *GetMessageFlagsRequest) Command() Command { return CommandGetMessageFlags } func (req *GetMessageFlagsRequest) Pack() []byte { return []byte{} } func (res *GetMessageFlagsResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } b, _, _ := unpackUint8(msg, 0) res.OEM2Available = isBit7Set(b) res.OEM1Available = isBit6Set(b) res.OEM0Available = isBit5Set(b) res.WatchdogPreTimeoutInterruptOccurred = isBit3Set(b) res.EventMessageBufferFull = isBit1Set(b) res.ReceiveMessageQueueAvailable = isBit0Set(b) return nil } func (*GetMessageFlagsResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetMessageFlagsResponse) Format() string { // Todo return "" } func (c *Client) GetMessageFlags(ctx context.Context) (response *GetMessageFlagsResponse, err error) { request := &GetMessageFlagsRequest{} response = &GetMessageFlagsResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_netfn_support.go000066400000000000000000000032111474110527100240220ustar00rootroot00000000000000package ipmi import "context" // 21.2 Get NetFn Support Command type GetNetFnSupportRequest struct { ChannelNumber uint8 } type GetNetFnSupportResponse struct { LUN3Support LUNSupport LUN2Support LUNSupport LUN1Support LUNSupport LUN0Support LUNSupport // Todo NetFnPairsSupport []byte } type LUNSupport uint8 func (l LUNSupport) String() string { m := map[LUNSupport]string{ 0x00: "no commands supported", 0x01: "commands exist on LUN - no restriction", 0x02: "commands exist on LUN - restricted", 0x03: "reserved", } s, ok := m[l] if ok { return s } return "" } func (req *GetNetFnSupportRequest) Command() Command { return CommandGetNetFnSupport } func (req *GetNetFnSupportRequest) Pack() []byte { return []byte{req.ChannelNumber} } func (res *GetNetFnSupportResponse) Unpack(msg []byte) error { if len(msg) < 17 { return ErrUnpackedDataTooShortWith(len(msg), 17) } b, _, _ := unpackUint8(msg, 0) res.LUN3Support = LUNSupport(b >> 6) res.LUN2Support = LUNSupport((b & 0x3f) >> 4) res.LUN1Support = LUNSupport((b & 0x0f) >> 2) res.LUN0Support = LUNSupport(b & 0x03) res.NetFnPairsSupport, _, _ = unpackBytes(msg, 1, 16) return nil } func (*GetNetFnSupportResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetNetFnSupportResponse) Format() string { // Todo return "" } func (c *Client) GetNetFnSupport(ctx context.Context, channelNumber uint8) (response *GetNetFnSupportResponse, err error) { request := &GetNetFnSupportRequest{ ChannelNumber: channelNumber, } response = &GetNetFnSupportResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_payload_activation_status.go000066400000000000000000000101761474110527100264010ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 24.4 Get Payload Activation Status Command type GetPayloadActivationStatusRequest struct { PayloadType PayloadType } type GetPayloadActivationStatusResponse struct { // [3:0] - Number of instances of given payload type that can be simultaneously activated on BMC. 1-based. 0h = reserved. InstanceCapacity uint8 Instance01Activated bool Instance02Activated bool Instance03Activated bool Instance04Activated bool Instance05Activated bool Instance06Activated bool Instance07Activated bool Instance08Activated bool Instance09Activated bool Instance10Activated bool Instance11Activated bool Instance12Activated bool Instance13Activated bool Instance14Activated bool Instance15Activated bool Instance16Activated bool // Store the PayloadType specified in GetPayloadActivationStatusRequest PayloadType PayloadType } func (req *GetPayloadActivationStatusRequest) Pack() []byte { return []byte{byte(req.PayloadType)} } func (req *GetPayloadActivationStatusRequest) Command() Command { return CommandGetPayloadActivationStatus } func (res *GetPayloadActivationStatusResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetPayloadActivationStatusResponse) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } res.InstanceCapacity = msg[0] + 1 // plus 1 cause of 1-based. res.Instance01Activated = isBit0Set(msg[1]) res.Instance02Activated = isBit1Set(msg[1]) res.Instance03Activated = isBit2Set(msg[1]) res.Instance04Activated = isBit3Set(msg[1]) res.Instance05Activated = isBit4Set(msg[1]) res.Instance06Activated = isBit5Set(msg[1]) res.Instance07Activated = isBit6Set(msg[1]) res.Instance08Activated = isBit7Set(msg[1]) res.Instance09Activated = isBit0Set(msg[2]) res.Instance10Activated = isBit1Set(msg[2]) res.Instance11Activated = isBit2Set(msg[2]) res.Instance12Activated = isBit3Set(msg[2]) res.Instance13Activated = isBit4Set(msg[2]) res.Instance14Activated = isBit5Set(msg[2]) res.Instance15Activated = isBit6Set(msg[2]) res.Instance16Activated = isBit7Set(msg[2]) return nil } func (res *GetPayloadActivationStatusResponse) Format() string { return fmt.Sprintf(` Payload Type : %s (%d) Instance Capacity : %d Instance 01 : %s Instance 02 : %s Instance 03 : %s Instance 04 : %s Instance 05 : %s Instance 06 : %s Instance 07 : %s Instance 08 : %s Instance 09 : %s Instance 10 : %s Instance 11 : %s Instance 12 : %s Instance 13 : %s Instance 14 : %s Instance 15 : %s Instance 16 : %s`, res.PayloadType.String(), res.PayloadType, res.InstanceCapacity, formatBool(res.Instance01Activated, "activated", "deactivated"), formatBool(res.Instance02Activated, "activated", "deactivated"), formatBool(res.Instance03Activated, "activated", "deactivated"), formatBool(res.Instance04Activated, "activated", "deactivated"), formatBool(res.Instance05Activated, "activated", "deactivated"), formatBool(res.Instance06Activated, "activated", "deactivated"), formatBool(res.Instance07Activated, "activated", "deactivated"), formatBool(res.Instance08Activated, "activated", "deactivated"), formatBool(res.Instance09Activated, "activated", "deactivated"), formatBool(res.Instance10Activated, "activated", "deactivated"), formatBool(res.Instance11Activated, "activated", "deactivated"), formatBool(res.Instance12Activated, "activated", "deactivated"), formatBool(res.Instance13Activated, "activated", "deactivated"), formatBool(res.Instance14Activated, "activated", "deactivated"), formatBool(res.Instance15Activated, "activated", "deactivated"), formatBool(res.Instance16Activated, "activated", "deactivated"), ) } func (c *Client) GetPayloadActivationStatus(ctx context.Context, payloadType PayloadType) (response *GetPayloadActivationStatusResponse, err error) { request := &GetPayloadActivationStatusRequest{ PayloadType: payloadType, } response = &GetPayloadActivationStatusResponse{} response.PayloadType = request.PayloadType err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_pef_capabilities.go000066400000000000000000000046571474110527100244160ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 30.1 Get PEF Capabilities Command type GetPEFCapabilitiesRequest struct { // empty } type GetPEFCapabilitiesResponse struct { // PEF Version (BCD encoded, LSN first. 51h version 1.5) PEFVersion uint8 SupportOEMEventFilter bool SupportDiagnosticInterrupt bool SupportOEMAction bool SupportPowerCycle bool SupportReset bool SupportPowerDown bool SupportAlert bool EventFilterTableEntries uint8 } func (req *GetPEFCapabilitiesRequest) Command() Command { return CommandGetPEFCapabilities } func (req *GetPEFCapabilitiesRequest) Pack() []byte { // empty request data return []byte{} } func (res *GetPEFCapabilitiesResponse) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } res.PEFVersion = msg[0] b1 := msg[1] res.SupportOEMEventFilter = isBit7Set(b1) res.SupportDiagnosticInterrupt = isBit5Set(b1) res.SupportOEMAction = isBit4Set(b1) res.SupportPowerCycle = isBit3Set(b1) res.SupportReset = isBit2Set(b1) res.SupportPowerDown = isBit1Set(b1) res.SupportAlert = isBit0Set(b1) res.EventFilterTableEntries = msg[2] return nil } func (r *GetPEFCapabilitiesResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetPEFCapabilitiesResponse) Format() string { return fmt.Sprintf(`PEF Version : %#2x Event Filter Table Entries : %d Support OEM Event Filtering : %s Support Diagnostic Interrupt : %s Support OEM Action : %s Support Power Cycle : %s Support Reset : %s Support Power Down : %s Support Alert : %s`, res.PEFVersion, res.EventFilterTableEntries, formatBool(res.SupportOEMEventFilter, "supported", "not-supported"), formatBool(res.SupportDiagnosticInterrupt, "supported", "not-supported"), formatBool(res.SupportOEMAction, "supported", "not-supported"), formatBool(res.SupportPowerCycle, "supported", "not-supported"), formatBool(res.SupportReset, "supported", "not-supported"), formatBool(res.SupportPowerDown, "supported", "not-supported"), formatBool(res.SupportAlert, "supported", "not-supported"), ) } func (c *Client) GetPEFCapabilities(ctx context.Context) (response *GetPEFCapabilitiesResponse, err error) { request := &GetPEFCapabilitiesRequest{} response = &GetPEFCapabilitiesResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_pef_config_params.go000066400000000000000000000220511474110527100245610ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 30.4 Get PEF Configuration Parameters Command type GetPEFConfigParamRequest struct { // [7] - 1b = get parameter revision only. 0b = get parameter // [6:0] - Parameter selector GetParamRevisionOnly bool ParamSelector PEFConfigParamSelector SetSelector uint8 // 00h if parameter does not require a Set Selector BlockSelector uint8 // 00h if parameter does not require a block number } type GetPEFConfigParamResponse struct { // Parameter revision. // // Format: // - MSN = present revision. // - LSN = oldest revision parameter is backward compatible with. // - 11h for parameters in this specification. ParamRevision uint8 // ParamData not returned when GetParamRevisionOnly is true ParamData []byte } func (req *GetPEFConfigParamRequest) Command() Command { return CommandGetPEFConfigParam } func (req *GetPEFConfigParamRequest) Pack() []byte { // empty request data out := make([]byte, 3) b0 := uint8(req.ParamSelector) & 0x3f if req.GetParamRevisionOnly { b0 = setBit7(b0) } packUint8(b0, out, 0) packUint8(req.SetSelector, out, 1) packUint8(req.BlockSelector, out, 2) return out } func (res *GetPEFConfigParamResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShort } res.ParamRevision = msg[0] if len(msg) > 1 { res.ParamData, _, _ = unpackBytes(msg, 1, len(msg)-1) } return nil } func (r *GetPEFConfigParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "parameter not supported", } } func (res *GetPEFConfigParamResponse) Format() string { return fmt.Sprintf(` Parameter Revision : %#02x (%d) Configuration Parameter Data : %# 02x`, res.ParamRevision, res.ParamRevision, res.ParamData, ) } func (c *Client) GetPEFConfigParam(ctx context.Context, getRevisionOnly bool, paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) (response *GetPEFConfigParamResponse, err error) { request := &GetPEFConfigParamRequest{ GetParamRevisionOnly: getRevisionOnly, ParamSelector: paramSelector, SetSelector: setSelector, BlockSelector: blockSelector, } response = &GetPEFConfigParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetPEFConfigParamFor(ctx context.Context, param PEFConfigParameter) error { if isNilPEFConfigParameter(param) { return nil } paramSelector, setSelector, blockSelector := param.PEFConfigParameter() res, err := c.GetPEFConfigParam(ctx, false, paramSelector, setSelector, blockSelector) if err != nil { return fmt.Errorf("GetPEFConfigParameters for param (%s) failed, err: %w", paramSelector, err) } if err := param.Unpack(res.ParamData); err != nil { return fmt.Errorf("unpack failed for param (%s), err: %w", paramSelector, err) } return nil } func (c *Client) GetPEFConfigParams(ctx context.Context) (pefConfigParams *PEFConfigParams, err error) { pefConfigParams = &PEFConfigParams{ SetInProgress: &PEFConfigParam_SetInProgress{}, Control: &PEFConfigParam_Control{}, ActionGlobalControl: &PEFConfigParam_ActionGlobalControl{}, StartupDelay: &PEFConfigParam_StartupDelay{}, AlertStartupDelay: &PEFConfigParam_AlertStartupDelay{}, EventFiltersCount: &PEFConfigParam_EventFiltersCount{}, EventFilters: []*PEFConfigParam_EventFilter{}, EventFiltersData1: []*PEFConfigParam_EventFilterData1{}, AlertPoliciesCount: &PEFConfigParam_AlertPoliciesCount{}, AlertPolicies: []*PEFConfigParam_AlertPolicy{}, SystemGUID: &PEFConfigParam_SystemGUID{}, AlertStringsCount: &PEFConfigParam_AlertStringsCount{}, AlertStringKeys: []*PEFConfigParam_AlertStringKey{}, AlertStrings: []*PEFConfigParam_AlertString{}, // GroupControlsCount: &PEFConfigParam_GroupControlsCount{}, // GroupControls: []*PEFConfigParam_GroupControl{}, } if err = c.GetPEFConfigParamsFor(ctx, pefConfigParams); err != nil { return nil, fmt.Errorf("GetPEFConfigParamsFor failed, err: %w", err) } return pefConfigParams, nil } func (c *Client) GetPEFConfigParamsFor(ctx context.Context, pefConfigParams *PEFConfigParams) error { if pefConfigParams == nil { return nil } if pefConfigParams.SetInProgress != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.SetInProgress); err != nil { return err } } if pefConfigParams.Control != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.Control); err != nil { return err } } if pefConfigParams.ActionGlobalControl != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.ActionGlobalControl); err != nil { return err } } if pefConfigParams.StartupDelay != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.StartupDelay); err != nil { return err } } if pefConfigParams.AlertStartupDelay != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.AlertStartupDelay); err != nil { return err } } eventFiltersCount := uint8(0) if pefConfigParams.EventFiltersCount != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.AlertPoliciesCount); err != nil { return err } eventFiltersCount = pefConfigParams.EventFiltersCount.Value } if pefConfigParams.EventFilters != nil { if len(pefConfigParams.EventFilters) == 0 && eventFiltersCount > 0 { pefConfigParams.EventFilters = make([]*PEFConfigParam_EventFilter, eventFiltersCount) for i := uint8(0); i < eventFiltersCount; i++ { pefConfigParams.EventFilters[i] = &PEFConfigParam_EventFilter{ SetSelector: i + 1, } } } for _, eventFilter := range pefConfigParams.EventFilters { if err := c.GetPEFConfigParamFor(ctx, eventFilter); err != nil { return err } } } if pefConfigParams.EventFiltersData1 != nil { if len(pefConfigParams.EventFiltersData1) == 0 && eventFiltersCount > 0 { pefConfigParams.EventFiltersData1 = make([]*PEFConfigParam_EventFilterData1, eventFiltersCount) for i := uint8(0); i < eventFiltersCount; i++ { pefConfigParams.EventFiltersData1[i] = &PEFConfigParam_EventFilterData1{ SetSelector: i + 1, } } } for _, eventFilterData1 := range pefConfigParams.EventFiltersData1 { if err := c.GetPEFConfigParamFor(ctx, eventFilterData1); err != nil { return err } } } alertPoliciesCount := uint8(0) if pefConfigParams.AlertPoliciesCount != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.AlertPoliciesCount); err != nil { return err } alertPoliciesCount = pefConfigParams.AlertPoliciesCount.Value } if pefConfigParams.AlertPolicies != nil { if len(pefConfigParams.AlertPolicies) == 0 && alertPoliciesCount > 0 { pefConfigParams.AlertPolicies = make([]*PEFConfigParam_AlertPolicy, alertPoliciesCount) for i := uint8(0); i < alertPoliciesCount; i++ { pefConfigParams.AlertPolicies[i] = &PEFConfigParam_AlertPolicy{ SetSelector: i + 1, } } } for _, alertPolicy := range pefConfigParams.AlertPolicies { if err := c.GetPEFConfigParamFor(ctx, alertPolicy); err != nil { return err } } } if pefConfigParams.SystemGUID != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.SystemGUID); err != nil { return err } } alertStringsCount := uint8(0) if pefConfigParams.AlertStringsCount != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.AlertStringsCount); err != nil { return err } } if pefConfigParams.AlertStringKeys != nil { if len(pefConfigParams.AlertStringKeys) == 0 && alertStringsCount > 0 { pefConfigParams.AlertStringKeys = make([]*PEFConfigParam_AlertStringKey, alertStringsCount) for i := uint8(0); i < alertStringsCount; i++ { pefConfigParams.AlertStringKeys[i] = &PEFConfigParam_AlertStringKey{ SetSelector: i, } } } for _, alertStringKey := range pefConfigParams.AlertStringKeys { if err := c.GetPEFConfigParamFor(ctx, alertStringKey); err != nil { return err } } } if pefConfigParams.AlertStrings != nil { if len(pefConfigParams.AlertStrings) == 0 && alertStringsCount > 0 { pefConfigParams.AlertStrings = make([]*PEFConfigParam_AlertString, alertStringsCount) for i := uint8(0); i < alertStringsCount; i++ { pefConfigParams.AlertStrings[i] = &PEFConfigParam_AlertString{ SetSelector: i, } } } for _, alertString := range pefConfigParams.AlertStrings { if err := c.GetPEFConfigParamFor(ctx, alertString); err != nil { return err } } } groupControlsCount := uint8(0) if pefConfigParams.GroupControlsCount != nil { if err := c.GetPEFConfigParamFor(ctx, pefConfigParams.GroupControlsCount); err != nil { return err } } if pefConfigParams.GroupControls != nil { if len(pefConfigParams.GroupControls) == 0 && groupControlsCount > 0 { pefConfigParams.GroupControls = make([]*PEFConfigParam_GroupControl, groupControlsCount) for i := uint8(0); i < groupControlsCount; i++ { pefConfigParams.GroupControls[i] = &PEFConfigParam_GroupControl{ SetSelector: i, } } } for _, groupControl := range pefConfigParams.GroupControls { if err := c.GetPEFConfigParamFor(ctx, groupControl); err != nil { return err } } } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_poh_counter.go000066400000000000000000000027511474110527100234510ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 28.14 Get POH Counter Command type GetPOHCounterRequest struct { // empty } type GetPOHCounterResponse struct { MinutesPerCount uint8 CounterReading uint32 } func (res *GetPOHCounterResponse) Minutes() uint32 { return res.CounterReading * uint32(res.MinutesPerCount) } func (req *GetPOHCounterRequest) Command() Command { return CommandGetPOHCounter } func (req *GetPOHCounterRequest) Pack() []byte { return []byte{} } func (res *GetPOHCounterResponse) Unpack(msg []byte) error { if len(msg) < 5 { return ErrUnpackedDataTooShortWith(len(msg), 5) } res.MinutesPerCount, _, _ = unpackUint8(msg, 0) res.CounterReading, _, _ = unpackUint32L(msg, 1) return nil } func (r *GetPOHCounterResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetPOHCounterResponse) Format() string { totalMinutes := res.Minutes() days := totalMinutes / 1440 minutes := totalMinutes - days*1440 hours := minutes / 60 return fmt.Sprintf(`POH Counter : %d days, %d hours Minutes per count : %d Counter reading : %d`, days, hours, res.MinutesPerCount, res.CounterReading, ) } // This command returns the present reading of the POH (Power-On Hours) counter, plus the number of counts per hour. func (c *Client) GetPOHCounter(ctx context.Context) (response *GetPOHCounterResponse, err error) { request := &GetPOHCounterRequest{} response = &GetPOHCounterResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sdr.go000066400000000000000000000165331474110527100217170ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 33.12 Get SDR Command type GetSDRRequest struct { ReservationID uint16 // LS Byte first RecordID uint16 // LS Byte first ReadOffset uint8 // Offset into record ReadBytes uint8 // FFh means read entire record } type GetSDRResponse struct { NextRecordID uint16 RecordData []byte } func (req *GetSDRRequest) Pack() []byte { msg := make([]byte, 6) packUint16L(req.ReservationID, msg, 0) packUint16L(req.RecordID, msg, 2) packUint8(req.ReadOffset, msg, 4) packUint8(req.ReadBytes, msg, 5) return msg } func (req *GetSDRRequest) Command() Command { return CommandGetSDR } func (res *GetSDRResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.NextRecordID, _, _ = unpackUint16L(msg, 0) res.RecordData, _, _ = unpackBytes(msg, 2, len(msg)-2) return nil } func (res *GetSDRResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetSDRResponse) Format() string { return fmt.Sprintf("%v", res) } // GetSDR returns raw SDR record. func (c *Client) GetSDR(ctx context.Context, recordID uint16) (response *GetSDRResponse, err error) { request := &GetSDRRequest{ ReservationID: 0, RecordID: recordID, ReadOffset: 0, ReadBytes: 0xff, } response = &GetSDRResponse{} err = c.Exchange(ctx, request, response) // try read partial data if err (ResponseError and CompletionCode) indicate // reading full data (0xff) exceeds the maximum transfer length for the interface if resErr, ok := err.(*ResponseError); ok { if resErr.CompletionCode() == CompletionCodeCannotReturnRequestedDataBytes { return c.getSDR(ctx, recordID) } } return } func (c *Client) GetSDREnhanced(ctx context.Context, recordID uint16) (*SDR, error) { res, err := c.GetSDR(ctx, recordID) if err != nil { return nil, fmt.Errorf("GetSDR failed for recordID (%#02x), err: %s", recordID, err) } sdr, err := ParseSDR(res.RecordData, res.NextRecordID) if err != nil { return nil, fmt.Errorf("ParseSDR failed, err: %w", err) } if err := c.enhanceSDR(ctx, sdr); err != nil { return sdr, fmt.Errorf("enhanceSDR failed, err: %w", err) } return sdr, nil } // getSDR return SDR in a partial read way. func (c *Client) getSDR(ctx context.Context, recordID uint16) (response *GetSDRResponse, err error) { var data []byte // the actual data length of the SDR can only be determined after the first GetSDR request/response. dataLength := uint8(0) reservationID := uint16(0) readBytes := uint8(16) readTotal := uint8(0) readOffset := uint8(0) for { request := &GetSDRRequest{ ReservationID: reservationID, RecordID: recordID, ReadOffset: readOffset, ReadBytes: readBytes, } response = &GetSDRResponse{} if err = c.Exchange(ctx, request, response); err != nil { return } // determine the total data length by parsing the SDR Header part if readOffset == 0 { if len(response.RecordData) < SDRRecordHeaderSize { return nil, fmt.Errorf("too short record data for SDR header (%d/%d)", len(response.RecordData), SDRRecordHeaderSize) } dataLength = response.RecordData[4] + uint8(SDRRecordHeaderSize) data = make([]byte, dataLength) } copy(data[readOffset:readOffset+readBytes], response.RecordData[:]) readOffset += uint8(len(response.RecordData)) readTotal += uint8(len(response.RecordData)) if readTotal >= dataLength { break } if readOffset+readBytes > dataLength { // decrease the readBytes for the last read. readBytes = dataLength - readOffset } rsp, err := c.ReserveSDRRepo(ctx) if err == nil { reservationID = rsp.ReservationID } else { reservationID = 0 } } return &GetSDRResponse{ NextRecordID: response.NextRecordID, RecordData: data, }, nil } func (c *Client) GetSDRBySensorID(ctx context.Context, sensorNumber uint8) (*SDR, error) { if SensorNumber(sensorNumber) == SensorNumberReserved { return nil, fmt.Errorf("not valid sensorNumber, %#0x is reserved", sensorNumber) } var recordID uint16 = 0 for { res, err := c.GetSDR(ctx, recordID) if err != nil { return nil, fmt.Errorf("GetSDR failed for recordID (%#02x), err: %s", recordID, err) } sdr, err := ParseSDR(res.RecordData, res.NextRecordID) if err != nil { return nil, fmt.Errorf("ParseSDR failed, err: %w", err) } if uint8(sdr.SensorNumber()) != sensorNumber { recordID = sdr.NextRecordID if recordID == 0xffff { break } continue } if err := c.enhanceSDR(ctx, sdr); err != nil { return sdr, fmt.Errorf("enhanceSDR failed, err: %w", err) } return sdr, nil } return nil, fmt.Errorf("not found SDR for sensor id (%#0x)", sensorNumber) } func (c *Client) GetSDRBySensorName(ctx context.Context, sensorName string) (*SDR, error) { var recordID uint16 = 0 for { res, err := c.GetSDR(ctx, recordID) if err != nil { return nil, fmt.Errorf("GetSDR failed for recordID (%#02x), err: %s", recordID, err) } sdr, err := ParseSDR(res.RecordData, res.NextRecordID) if err != nil { return nil, fmt.Errorf("ParseSDR failed, err: %w", err) } if sdr.SensorName() != sensorName { recordID = sdr.NextRecordID if recordID == 0xffff { break } continue } if err := c.enhanceSDR(ctx, sdr); err != nil { return sdr, fmt.Errorf("enhanceSDR failed, err: %w", err) } return sdr, nil } return nil, fmt.Errorf("not found SDR for sensor name (%s)", sensorName) } // GetSDRs fetches the SDR records with the specified RecordTypes. // The parameter is a slice of SDRRecordType used as filter. // Empty means to get all SDR records. func (c *Client) GetSDRs(ctx context.Context, recordTypes ...SDRRecordType) ([]*SDR, error) { var recordID uint16 = 0 var out = make([]*SDR, 0) for { sdr, err := c.GetSDREnhanced(ctx, recordID) if err != nil { return nil, fmt.Errorf("GetSDR for recordID (%#0x) failed, err: %s", recordID, err) } if len(recordTypes) == 0 { out = append(out, sdr) } else { for _, v := range recordTypes { if sdr.RecordHeader.RecordType == v { out = append(out, sdr) break } } } recordID = sdr.NextRecordID if recordID == 0xffff { break } } return out, nil } // GetSDRsMap returns all Full/Compact SDRs grouped by GeneratorID and SensorNumber. // The sensor name can only be got from SDR record. // So use this method to construct a map from which you can get sensor name. func (c *Client) GetSDRsMap(ctx context.Context) (SDRMapBySensorNumber, error) { var out = make(map[GeneratorID]map[SensorNumber]*SDR) var recordID uint16 = 0 for { sdr, err := c.GetSDREnhanced(ctx, recordID) if err != nil { return nil, fmt.Errorf("GetSDR for recordID (%#0x) failed, err: %s", recordID, err) } var generatorID GeneratorID var sensorNumber SensorNumber recordType := sdr.RecordHeader.RecordType switch recordType { case SDRRecordTypeFullSensor: generatorID = sdr.Full.GeneratorID sensorNumber = sdr.Full.SensorNumber case SDRRecordTypeCompactSensor: generatorID = sdr.Compact.GeneratorID sensorNumber = sdr.Compact.SensorNumber } if recordType == SDRRecordTypeFullSensor || recordType == SDRRecordTypeCompactSensor { if _, ok := out[generatorID]; !ok { out[generatorID] = make(map[SensorNumber]*SDR) } out[generatorID][sensorNumber] = sdr } recordID = sdr.NextRecordID if recordID == 0xffff { break } } return out, nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sdr_repo_alloc_info.go000066400000000000000000000026111474110527100251210ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 33.10 Get SDR Repository Allocation Info Command type GetSDRRepoAllocInfoRequest struct { // empty } type GetSDRRepoAllocInfoResponse struct { PossibleAllocUnits uint16 AllocUnitsSize uint16 // Allocation unit size in bytes. 0000h indicates unspecified. FreeAllocUnits uint16 LargestFreeBlock uint16 MaximumRecordSize uint8 } func (req *GetSDRRepoAllocInfoRequest) Pack() []byte { return nil } func (req *GetSDRRepoAllocInfoRequest) Command() Command { return CommandGetSDRRepoAllocInfo } func (res *GetSDRRepoAllocInfoResponse) Unpack(msg []byte) error { if len(msg) < 9 { return ErrUnpackedDataTooShortWith(len(msg), 9) } res.PossibleAllocUnits, _, _ = unpackUint16L(msg, 0) res.AllocUnitsSize, _, _ = unpackUint16L(msg, 2) res.FreeAllocUnits, _, _ = unpackUint16L(msg, 4) res.LargestFreeBlock, _, _ = unpackUint16L(msg, 6) res.MaximumRecordSize, _, _ = unpackUint8(msg, 8) return nil } func (res *GetSDRRepoAllocInfoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSDRRepoAllocInfoResponse) Format() string { return fmt.Sprintf("%v", res) } func (c *Client) GetSDRRepoAllocInfo(ctx context.Context) (response *GetSDRRepoAllocInfoResponse, err error) { request := &GetSDRRepoAllocInfoRequest{} response = &GetSDRRepoAllocInfoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sdr_repo_info.go000066400000000000000000000067331474110527100237600ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "time" ) // 33.9 Get SDR Repository Info Command type GetSDRRepoInfoRequest struct { // empty } type GetSDRRepoInfoResponse struct { SDRVersion uint8 // version number of the SDR command set for the SDR Device. 51h for this specification. RecordCount uint16 // LS Byte first FreeSpaceBytes uint16 // LS Byte first MostRecentAdditionTime time.Time MostRecentEraseTime time.Time SDROperationSupport SDROperationSupport } type SDROperationSupport struct { Overflow bool SupportModalSDRRepoUpdate bool // A modal SDR Repository is only updated when the controller is in an SDR Repository update mode. SupportNonModalSDRRepoUpdate bool // A non-modal SDR Repository can be written to at any time SupportDeleteSDR bool SupportPartialAddSDR bool SupportReserveSDRRepo bool SupportGetSDRRepoAllocInfo bool } func (req *GetSDRRepoInfoRequest) Pack() []byte { return []byte{} } func (req *GetSDRRepoInfoRequest) Command() Command { return CommandGetSDRRepoInfo } func (res *GetSDRRepoInfoResponse) Unpack(msg []byte) error { if len(msg) < 14 { return ErrUnpackedDataTooShortWith(len(msg), 14) } res.SDRVersion, _, _ = unpackUint8(msg, 0) res.RecordCount, _, _ = unpackUint16L(msg, 1) res.FreeSpaceBytes, _, _ = unpackUint16L(msg, 3) addTS, _, _ := unpackUint32L(msg, 5) res.MostRecentAdditionTime = parseTimestamp(addTS) deleteTS, _, _ := unpackUint32L(msg, 9) res.MostRecentEraseTime = parseTimestamp(deleteTS) b, _, _ := unpackUint8(msg, 13) res.SDROperationSupport = SDROperationSupport{ Overflow: isBit7Set(b), SupportModalSDRRepoUpdate: isBit6Set(b), SupportNonModalSDRRepoUpdate: isBit5Set(b), SupportDeleteSDR: isBit3Set(b), SupportPartialAddSDR: isBit2Set(b), SupportReserveSDRRepo: isBit1Set(b), SupportGetSDRRepoAllocInfo: isBit0Set(b), } return nil } func (res *GetSDRRepoInfoResponse) Format() string { s := "" if res.SDROperationSupport.SupportModalSDRRepoUpdate { if s != "" { s += "/ modal" } else { s += "modal" } } if res.SDROperationSupport.SupportNonModalSDRRepoUpdate { if s != "" { s += "/ non-modal" } else { s += "non-modal" } } return fmt.Sprintf(`SDR Version : %#02x Record Count : %d Free Space : %d bytes Most recent Addition : %s Most recent Erase : %s SDR overflow : %v SDR Repository Update Support : %s Delete SDR supported : %v Partial Add SDR supported : %v Reserve SDR repository supported : %v SDR Repository Alloc info supported : %v`, res.SDRVersion, res.RecordCount, res.FreeSpaceBytes, res.MostRecentAdditionTime.Format(timeFormat), res.MostRecentEraseTime.Format(timeFormat), res.SDROperationSupport.Overflow, s, res.SDROperationSupport.SupportDeleteSDR, res.SDROperationSupport.SupportPartialAddSDR, res.SDROperationSupport.SupportReserveSDRRepo, res.SDROperationSupport.SupportGetSDRRepoAllocInfo, ) } func (res *GetSDRRepoInfoResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (c *Client) GetSDRRepoInfo(ctx context.Context) (response *GetSDRRepoInfoResponse, err error) { request := &GetSDRRepoInfoRequest{} response = &GetSDRRepoInfoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sel_alloc_info.go000066400000000000000000000031061474110527100240670ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) type GetSELAllocInfoRequest struct { // empty } type GetSELAllocInfoResponse struct { PossibleAllocUnits uint16 AllocUnitsSize uint16 // Allocation unit size in bytes. 0000h indicates unspecified. FreeAllocUnits uint16 LargestFreeBlock uint16 MaximumRecordSize uint8 } func (req *GetSELAllocInfoRequest) Pack() []byte { return []byte{} } func (req *GetSELAllocInfoRequest) Command() Command { return CommandGetSELAllocInfo } func (res *GetSELAllocInfoResponse) Unpack(msg []byte) error { if len(msg) < 9 { return ErrUnpackedDataTooShortWith(len(msg), 9) } res.PossibleAllocUnits, _, _ = unpackUint16L(msg, 0) res.AllocUnitsSize, _, _ = unpackUint16L(msg, 2) res.FreeAllocUnits, _, _ = unpackUint16L(msg, 4) res.LargestFreeBlock, _, _ = unpackUint16L(msg, 6) res.MaximumRecordSize, _, _ = unpackUint8(msg, 8) return nil } func (res *GetSELAllocInfoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSELAllocInfoResponse) Format() string { return fmt.Sprintf(`# of Alloc Units : %d Alloc Unit Size : %d # Free Units : %d Largest Free Blk : %d Max Record Size : %d`, res.PossibleAllocUnits, res.AllocUnitsSize, res.FreeAllocUnits, res.LargestFreeBlock, res.MaximumRecordSize, ) } func (c *Client) GetSELAllocInfo(ctx context.Context) (response *GetSELAllocInfoResponse, err error) { request := &GetSELAllocInfoRequest{} response = &GetSELAllocInfoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sel_entry.go000066400000000000000000000063711474110527100231320ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 31.5 Get SEL Entry Command type GetSELEntryRequest struct { // LS Byte first. Only required for partial Get. Use 0000h otherwise. ReservationID uint16 // SEL Record ID, LS Byte first. // 0000h = GET FIRST ENTRY // FFFFh = GET LAST ENTRY RecordID uint16 // Offset into record Offset uint8 // FFh means read entire record. ReadBytes uint8 } type GetSELEntryResponse struct { NextRecordID uint16 Data []byte // Record Data, 16 bytes for entire record, at least 1 byte } func (req *GetSELEntryRequest) Command() Command { return CommandGetSELEntry } func (req *GetSELEntryRequest) Pack() []byte { var msg = make([]byte, 6) packUint16L(req.ReservationID, msg, 0) packUint16L(req.RecordID, msg, 2) packUint8(req.Offset, msg, 4) packUint8(req.ReadBytes, msg, 5) return msg } func (res *GetSELEntryResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.NextRecordID, _, _ = unpackUint16L(msg, 0) res.Data, _, _ = unpackBytesMost(msg, 2, 16) return nil } func (*GetSELEntryResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "cannot execute command, SEL erase in progress", } } func (res *GetSELEntryResponse) Format() string { return fmt.Sprintf("%v", res) } // The reservationID is only required for partial Get, use 0000h otherwise. func (c *Client) GetSELEntry(ctx context.Context, reservationID uint16, recordID uint16) (response *GetSELEntryResponse, err error) { if _, err := c.GetSELInfo(ctx); err != nil { return nil, fmt.Errorf("GetSELInfo failed, err: %w", err) } request := &GetSELEntryRequest{ ReservationID: reservationID, RecordID: recordID, Offset: 0, ReadBytes: 0xff, } response = &GetSELEntryResponse{} err = c.Exchange(ctx, request, response) return } // GetSELEntries return all SEL records starting from the specified recordID. // Pass 0 means retrieve all SEL entries starting from the first record. func (c *Client) GetSELEntries(ctx context.Context, startRecordID uint16) ([]*SEL, error) { // Todo // Notice, this extra GetSELInfo call is used to make sure the GetSELEntry works properly. // On Huawei TaiShan 200 (Model 2280), the NextRecordID (0xffff) in GetSELEntryResponse is NOT right occasionally. // $ ipmitool -I lanplus -H x.x.x.x -U xxx -P xxx raw 0x0a 0x43 0x00 0x00 0x01 0x00 0x00 0xff -v // RAW REQ (channel=0x0 netfn=0xa lun=0x0 cmd=0x43 data_len=6) // RAW REQUEST (6 bytes) // 00 00 01 00 00 ff // RAW RSP (18 bytes) // ff ff 01 00 02 6d 8e 91 5f 20 00 04 10 79 6f 02 // ff ff // // This extra GetSELInfo can avoid it. (I don't known why!) if _, err := c.GetSELInfo(ctx); err != nil { return nil, fmt.Errorf("GetSELInfo failed, err: %w", err) } var out = make([]*SEL, 0) var recordID uint16 = startRecordID for { selEntry, err := c.GetSELEntry(ctx, 0, recordID) if err != nil { return nil, fmt.Errorf("GetSELEntry failed, err: %w", err) } c.DebugBytes("sel entry record data", selEntry.Data, 16) sel, err := ParseSEL(selEntry.Data) if err != nil { return nil, fmt.Errorf("unpackSEL record failed, err: %w", err) } out = append(out, sel) recordID = selEntry.NextRecordID if recordID == 0xffff { break } } return out, nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sel_info.go000066400000000000000000000053211474110527100227160ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "time" ) // GetSELInfoRequest (31.2) command returns the number of entries in the SEL. type GetSELInfoRequest struct { // empty } type GetSELInfoResponse struct { SELVersion uint8 Entries uint16 FreeBytes uint16 RecentAdditionTime time.Time RecentEraseTime time.Time OperationSupport SELOperationSupport } type SELOperationSupport struct { Overflow bool DeleteSEL bool PartialAddSEL bool ReserveSEL bool GetSELAllocInfo bool } func (req *GetSELInfoRequest) Command() Command { return CommandGetSELInfo } func (req *GetSELInfoRequest) Pack() []byte { // empty request data return []byte{} } func (res *GetSELInfoResponse) Unpack(msg []byte) error { if len(msg) < 14 { return ErrUnpackedDataTooShortWith(len(msg), 14) } res.SELVersion, _, _ = unpackUint8(msg, 0) res.Entries, _, _ = unpackUint16L(msg, 1) res.FreeBytes, _, _ = unpackUint16L(msg, 3) addTS, _, _ := unpackUint32L(msg, 5) res.RecentAdditionTime = parseTimestamp(addTS) eraseTS, _, _ := unpackUint32L(msg, 9) res.RecentEraseTime = parseTimestamp(eraseTS) b := msg[13] res.OperationSupport = SELOperationSupport{ Overflow: isBit7Set(b), DeleteSEL: isBit3Set(b), PartialAddSEL: isBit2Set(b), ReserveSEL: isBit1Set(b), GetSELAllocInfo: isBit0Set(b), } return nil } func (r *GetSELInfoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "cannot execute command, SEL erase in progress", } } func (res *GetSELInfoResponse) Format() string { var version string if res.SELVersion == 0x51 { version = "1.5" } var usedBytes int = int(res.Entries) * 16 totalBytes := usedBytes + int(res.FreeBytes) var usedPct float64 = 100 * float64(usedBytes) / float64(totalBytes) return fmt.Sprintf(`SEL Information Version : %s (v1.5, v2 compliant) Entries : %d Free Space : %d bytes Percent Used : %.2f%% Last Add Time : %s Last Del Time : %s Overflow : %v Delete SEL supported: : %v Partial Add SEL supported: : %v Reserve SEL supported : %v Get SEL Alloc Info supported : %v`, version, res.Entries, res.FreeBytes, usedPct, res.RecentAdditionTime, res.RecentEraseTime, res.OperationSupport.Overflow, res.OperationSupport.DeleteSEL, res.OperationSupport.PartialAddSEL, res.OperationSupport.ReserveSEL, res.OperationSupport.GetSELAllocInfo, ) } func (c *Client) GetSELInfo(ctx context.Context) (response *GetSELInfoResponse, err error) { request := &GetSELInfoRequest{} response = &GetSELInfoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sel_time.go000066400000000000000000000017361474110527100227270ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "time" ) // 31.10 Get SEL Time Command type GetSELTimeRequest struct { // empty } type GetSELTimeResponse struct { // Present Timestamp clock reading Time time.Time } func (req *GetSELTimeRequest) Pack() []byte { return []byte{} } func (req *GetSELTimeRequest) Command() Command { return CommandGetSELTime } func (res *GetSELTimeResponse) Unpack(msg []byte) error { if len(msg) < 4 { return ErrUnpackedDataTooShortWith(len(msg), 4) } t, _, _ := unpackUint32L(msg, 0) res.Time = parseTimestamp(t) return nil } func (res *GetSELTimeResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetSELTimeResponse) Format() string { return fmt.Sprintf("%v", res) } func (c *Client) GetSELTime(ctx context.Context) (response *GetSELTimeResponse, err error) { request := &GetSELTimeRequest{} response = &GetSELTimeResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sel_time_utc_offset.go000066400000000000000000000023631474110527100251450ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 31.11a Get SEL Time UTC Offset type GetSELTimeUTCOffsetRequest struct { // empty } type GetSELTimeUTCOffsetResponse struct { // signed integer for the offset in minutes from UTC to SEL Time. MinutesOffset int16 } func (req *GetSELTimeUTCOffsetRequest) Pack() []byte { return []byte{} } func (req *GetSELTimeUTCOffsetRequest) Command() Command { return CommandGetSELTimeUTCOffset } func (res *GetSELTimeUTCOffsetResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } b, _, _ := unpackUint16L(msg, 0) c := twosComplement(uint32(b), 16) res.MinutesOffset = int16(c) return nil } func (res *GetSELTimeUTCOffsetResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetSELTimeUTCOffsetResponse) Format() string { return fmt.Sprintf("Offset : %d", res.MinutesOffset) } // GetSELTimeUTCOffset is used to retrieve the SEL Time UTC Offset (timezone) func (c *Client) GetSELTimeUTCOffset(ctx context.Context) (response *GetSELTimeUTCOffsetResponse, err error) { request := &GetSELTimeUTCOffsetRequest{} response = &GetSELTimeUTCOffsetResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_self_test_results.go000066400000000000000000000017771474110527100247040ustar00rootroot00000000000000package ipmi import "context" // 20.4 Get Self Test Results Command type GetSelfTestResultsRequest struct { // empty } type GetSelfTestResultsResponse struct { Byte1 uint8 Byte2 uint8 } func (req *GetSelfTestResultsRequest) Command() Command { return CommandGetSelfTestResults } func (req *GetSelfTestResultsRequest) Pack() []byte { return []byte{} } func (res *GetSelfTestResultsResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSelfTestResultsResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.Byte1, _, _ = unpackUint8(msg, 0) res.Byte2, _, _ = unpackUint8(msg, 1) return nil } func (res *GetSelfTestResultsResponse) Format() string { // Todo return "" } func (c *Client) GetSelfTestResults(ctx context.Context) (response *GetSelfTestResultsResponse, err error) { request := &GetSelfTestResultsRequest{} response = &GetSelfTestResultsResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sensor_event_enable.go000066400000000000000000000114751474110527100251470ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "strings" ) // 35.11 Get Sensor Event Enable Command type GetSensorEventEnableRequest struct { SensorNumber uint8 } // For event , true means the event has enabled. type GetSensorEventEnableResponse struct { EventMessagesDisabled bool SensorScanningDisabled bool SensorEventFlag } func (req *GetSensorEventEnableRequest) Command() Command { return CommandGetSensorEventEnable } func (req *GetSensorEventEnableRequest) Pack() []byte { out := make([]byte, 1) packUint8(req.SensorNumber, out, 0) return out } func (res *GetSensorEventEnableResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } b1, _, _ := unpackUint8(msg, 0) res.EventMessagesDisabled = !isBit7Set(b1) res.SensorScanningDisabled = !isBit6Set(b1) if len(msg) >= 2 { b2, _, _ := unpackUint8(msg, 1) res.SensorEvent_UNC_High_Assert = isBit7Set(b2) res.SensorEvent_UNC_Low_Assert = isBit6Set(b2) res.SensorEvent_LNR_High_Assert = isBit5Set(b2) res.SensorEvent_LNR_Low_Assert = isBit4Set(b2) res.SensorEvent_LCR_High_Assert = isBit3Set(b2) res.SensorEvent_LCR_Low_Assert = isBit2Set(b2) res.SensorEvent_LNC_High_Assert = isBit1Set(b2) res.SensorEvent_LNC_Low_Assert = isBit0Set(b2) res.SensorEvent_State_7_Assert = isBit7Set(b2) res.SensorEvent_State_6_Assert = isBit6Set(b2) res.SensorEvent_State_5_Assert = isBit5Set(b2) res.SensorEvent_State_4_Assert = isBit4Set(b2) res.SensorEvent_State_3_Assert = isBit3Set(b2) res.SensorEvent_State_2_Assert = isBit2Set(b2) res.SensorEvent_State_1_Assert = isBit1Set(b2) res.SensorEvent_State_0_Assert = isBit0Set(b2) } if len(msg) >= 3 { b3, _, _ := unpackUint8(msg, 2) res.SensorEvent_UNR_High_Assert = isBit3Set(b3) res.SensorEvent_UNR_Low_Assert = isBit2Set(b3) res.SensorEvent_UCR_High_Assert = isBit1Set(b3) res.SensorEvent_UCR_Low_Assert = isBit0Set(b3) res.SensorEvent_State_14_Assert = isBit6Set(b3) res.SensorEvent_State_13_Assert = isBit5Set(b3) res.SensorEvent_State_12_Assert = isBit4Set(b3) res.SensorEvent_State_11_Assert = isBit3Set(b3) res.SensorEvent_State_10_Assert = isBit2Set(b3) res.SensorEvent_State_9_Assert = isBit1Set(b3) res.SensorEvent_State_8_Assert = isBit0Set(b3) } if len(msg) >= 4 { b4, _, _ := unpackUint8(msg, 3) res.SensorEvent_UNC_High_Deassert = isBit7Set(b4) res.SensorEvent_UNC_Low_Deassert = isBit6Set(b4) res.SensorEvent_LNR_High_Deassert = isBit5Set(b4) res.SensorEvent_LNR_Low_Deassert = isBit4Set(b4) res.SensorEvent_LCR_High_Deassert = isBit3Set(b4) res.SensorEvent_LCR_Low_Deassert = isBit2Set(b4) res.SensorEvent_LNC_High_Deassert = isBit1Set(b4) res.SensorEvent_LNC_Low_Deassert = isBit0Set(b4) res.SensorEvent_State_7_Deassert = isBit7Set(b4) res.SensorEvent_State_6_Deassert = isBit6Set(b4) res.SensorEvent_State_5_Deassert = isBit5Set(b4) res.SensorEvent_State_4_Deassert = isBit4Set(b4) res.SensorEvent_State_3_Deassert = isBit3Set(b4) res.SensorEvent_State_2_Deassert = isBit2Set(b4) res.SensorEvent_State_1_Deassert = isBit1Set(b4) res.SensorEvent_State_0_Deassert = isBit0Set(b4) } if len(msg) >= 5 { b5, _, _ := unpackUint8(msg, 4) res.SensorEvent_UNR_High_Deassert = isBit3Set(b5) res.SensorEvent_UNR_Low_Deassert = isBit2Set(b5) res.SensorEvent_UCR_High_Deassert = isBit1Set(b5) res.SensorEvent_UCR_Low_Deassert = isBit0Set(b5) res.SensorEvent_State_14_Deassert = isBit6Set(b5) res.SensorEvent_State_13_Deassert = isBit5Set(b5) res.SensorEvent_State_12_Deassert = isBit4Set(b5) res.SensorEvent_State_11_Deassert = isBit3Set(b5) res.SensorEvent_State_10_Deassert = isBit2Set(b5) res.SensorEvent_State_9_Deassert = isBit1Set(b5) res.SensorEvent_State_8_Deassert = isBit0Set(b5) } return nil } func (r *GetSensorEventEnableResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSensorEventEnableResponse) Format() string { all := res.SensorEventFlag.TrueEvents() asserted := SensorEvents(all).FilterAssert() deasserted := SensorEvents(all).FilterDeassert() var assertedStr = []string{} var deassertedStr = []string{} for _, v := range asserted { assertedStr = append(assertedStr, v.String()) } for _, v := range deasserted { deassertedStr = append(deassertedStr, v.String()) } return fmt.Sprintf(`Event Messages Disabled : %v Sensor Scanning Disabled : %v Enabled Assert Event : %s Enabled Deassert Event : %s`, res.EventMessagesDisabled, res.SensorScanningDisabled, strings.Join(assertedStr, "\n - "), strings.Join(deassertedStr, "\n - "), ) } func (c *Client) GetSensorEventEnable(ctx context.Context, sensorNumber uint8) (response *GetSensorEventEnableResponse, err error) { request := &GetSensorEventEnableRequest{ SensorNumber: sensorNumber, } response = &GetSensorEventEnableResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sensor_event_status.go000066400000000000000000000117121474110527100252360ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "strings" ) // 35.13 Get Sensor Event Status Command type GetSensorEventStatusRequest struct { SensorNumber uint8 } // For event boolean value, true means the event has occurred. type GetSensorEventStatusResponse struct { EventMessagesDisabled bool SensorScanningDisabled bool ReadingUnavailable bool SensorEventFlag } func (req *GetSensorEventStatusRequest) Command() Command { return CommandGetSensorEventStatus } func (req *GetSensorEventStatusRequest) Pack() []byte { out := make([]byte, 1) packUint8(req.SensorNumber, out, 0) return out } func (res *GetSensorEventStatusResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } b1, _, _ := unpackUint8(msg, 0) res.EventMessagesDisabled = !isBit7Set(b1) res.SensorScanningDisabled = !isBit6Set(b1) res.ReadingUnavailable = isBit5Set(b1) if len(msg) >= 2 { b2, _, _ := unpackUint8(msg, 1) res.SensorEvent_UNC_High_Assert = isBit7Set(b2) res.SensorEvent_UNC_Low_Assert = isBit6Set(b2) res.SensorEvent_LNR_High_Assert = isBit5Set(b2) res.SensorEvent_LNR_Low_Assert = isBit4Set(b2) res.SensorEvent_LCR_High_Assert = isBit3Set(b2) res.SensorEvent_LCR_Low_Assert = isBit2Set(b2) res.SensorEvent_LNC_High_Assert = isBit1Set(b2) res.SensorEvent_LNC_Low_Assert = isBit0Set(b2) res.SensorEvent_State_7_Assert = isBit7Set(b2) res.SensorEvent_State_6_Assert = isBit6Set(b2) res.SensorEvent_State_5_Assert = isBit5Set(b2) res.SensorEvent_State_4_Assert = isBit4Set(b2) res.SensorEvent_State_3_Assert = isBit3Set(b2) res.SensorEvent_State_2_Assert = isBit2Set(b2) res.SensorEvent_State_1_Assert = isBit1Set(b2) res.SensorEvent_State_0_Assert = isBit0Set(b2) } if len(msg) >= 3 { b3, _, _ := unpackUint8(msg, 2) res.SensorEvent_UNR_High_Assert = isBit3Set(b3) res.SensorEvent_UNR_Low_Assert = isBit2Set(b3) res.SensorEvent_UCR_High_Assert = isBit1Set(b3) res.SensorEvent_UCR_Low_Assert = isBit0Set(b3) res.SensorEvent_State_14_Assert = isBit6Set(b3) res.SensorEvent_State_13_Assert = isBit5Set(b3) res.SensorEvent_State_12_Assert = isBit4Set(b3) res.SensorEvent_State_11_Assert = isBit3Set(b3) res.SensorEvent_State_10_Assert = isBit2Set(b3) res.SensorEvent_State_9_Assert = isBit1Set(b3) res.SensorEvent_State_8_Assert = isBit0Set(b3) } if len(msg) >= 4 { b4, _, _ := unpackUint8(msg, 3) res.SensorEvent_UNC_High_Deassert = isBit7Set(b4) res.SensorEvent_UNC_Low_Deassert = isBit6Set(b4) res.SensorEvent_LNR_High_Deassert = isBit5Set(b4) res.SensorEvent_LNR_Low_Deassert = isBit4Set(b4) res.SensorEvent_LCR_High_Deassert = isBit3Set(b4) res.SensorEvent_LCR_Low_Deassert = isBit2Set(b4) res.SensorEvent_LNC_High_Deassert = isBit1Set(b4) res.SensorEvent_LNC_Low_Deassert = isBit0Set(b4) res.SensorEvent_State_7_Deassert = isBit7Set(b4) res.SensorEvent_State_6_Deassert = isBit6Set(b4) res.SensorEvent_State_5_Deassert = isBit5Set(b4) res.SensorEvent_State_4_Deassert = isBit4Set(b4) res.SensorEvent_State_3_Deassert = isBit3Set(b4) res.SensorEvent_State_2_Deassert = isBit2Set(b4) res.SensorEvent_State_1_Deassert = isBit1Set(b4) res.SensorEvent_State_0_Deassert = isBit0Set(b4) } if len(msg) >= 5 { b5, _, _ := unpackUint8(msg, 4) res.SensorEvent_UNR_High_Deassert = isBit3Set(b5) res.SensorEvent_UNR_Low_Deassert = isBit2Set(b5) res.SensorEvent_UCR_High_Deassert = isBit1Set(b5) res.SensorEvent_UCR_Low_Deassert = isBit0Set(b5) res.SensorEvent_State_14_Deassert = isBit6Set(b5) res.SensorEvent_State_13_Deassert = isBit5Set(b5) res.SensorEvent_State_12_Deassert = isBit4Set(b5) res.SensorEvent_State_11_Deassert = isBit3Set(b5) res.SensorEvent_State_10_Deassert = isBit2Set(b5) res.SensorEvent_State_9_Deassert = isBit1Set(b5) res.SensorEvent_State_8_Deassert = isBit0Set(b5) } return nil } func (res *GetSensorEventStatusResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSensorEventStatusResponse) Format() string { all := res.SensorEventFlag.TrueEvents() asserted := SensorEvents(all).FilterAssert() deasserted := SensorEvents(all).FilterDeassert() var assertedStr = []string{} var deassertedStr = []string{} for _, v := range asserted { assertedStr = append(assertedStr, v.String()) } for _, v := range deasserted { deassertedStr = append(deassertedStr, v.String()) } return fmt.Sprintf(`Event Messages Disabled : %v Sensor Scanning Disabled : %v Reading State Unavailable : %v Occurred Assert Event : %s Occurred Deassert Event : %s`, res.EventMessagesDisabled, res.SensorScanningDisabled, res.ReadingUnavailable, strings.Join(assertedStr, "\n -"), strings.Join(deassertedStr, "\n --"), ) } func (c *Client) GetSensorEventStatus(ctx context.Context, sensorNumber uint8) (response *GetSensorEventStatusResponse, err error) { request := &GetSensorEventStatusRequest{ SensorNumber: sensorNumber, } response = &GetSensorEventStatusResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sensor_hysteresis.go000066400000000000000000000030501474110527100247100ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 35.7 Get Sensor Hysteresis Command type GetSensorHysteresisRequest struct { SensorNumber uint8 } type GetSensorHysteresisResponse struct { PositiveRaw uint8 NegativeRaw uint8 } func (req *GetSensorHysteresisRequest) Command() Command { return CommandGetSensorHysteresis } func (req *GetSensorHysteresisRequest) Pack() []byte { out := make([]byte, 2) packUint8(req.SensorNumber, out, 0) packUint8(0xff, out, 1) // reserved for future "hysteresis mask" definition. Write as "FFh" return out } func (res *GetSensorHysteresisResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.PositiveRaw, _, _ = unpackUint8(msg, 0) res.NegativeRaw, _, _ = unpackUint8(msg, 1) return nil } func (r *GetSensorHysteresisResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSensorHysteresisResponse) Format() string { return fmt.Sprintf(`Positive Hysteresis : %d Negative Hysteresis : %d`, res.PositiveRaw, res.NegativeRaw, ) } // This command retrieves the present hysteresis values for the specified sensor. // If the sensor hysteresis values are "fixed", then the hysteresis values can be obtained from the SDR for the sensor. func (c *Client) GetSensorHysteresis(ctx context.Context, sensorNumber uint8) (response *GetSensorHysteresisResponse, err error) { request := &GetSensorHysteresisRequest{ SensorNumber: sensorNumber, } response = &GetSensorHysteresisResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sensor_reading.go000066400000000000000000000104311474110527100241200ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 35.14 Get Sensor Reading Command // // Retrieve a raw sensor reading (current reading) from ipmb type GetSensorReadingRequest struct { SensorNumber uint8 } type GetSensorReadingResponse struct { // reading byte. Ignore on read if sensor does not return an numeric (analog) reading Reading uint8 EventMessagesDisabled bool // see 16.5 System Software use of Sensor Scanning bits & Entity Info // // System software must ignore any sensor that has the sensor scanning bit disabled - if system software didn't disable the sensor. SensorScanningDisabled bool ReadingUnavailable bool // Software should use this bit to avoid getting an incorrect status while the first sensor update is in progress. // The following fields are optionally, they are only meaningful when reading is valid. Above_UNR bool // at or above UNR threshold Above_UCR bool // at or above UCR threshold Above_UNC bool // at or above UNC threshold Below_LNR bool // at or below LNR threshold Below_LCR bool // at or below LCR threshold Below_LNC bool // at or below LNC threshold // see 42.1 // (Sensor Classes: Discrete) // It is possible for a discrete sensor to have more than one state active at a time. ActiveStates Mask_DiscreteEvent optionalData1 uint8 optionalData2 uint8 } func (req *GetSensorReadingRequest) Command() Command { return CommandGetSensorReading } func (req *GetSensorReadingRequest) Pack() []byte { out := make([]byte, 1) packUint8(req.SensorNumber, out, 0) return out } func (res *GetSensorReadingResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.Reading, _, _ = unpackUint8(msg, 0) b1, _, _ := unpackUint8(msg, 1) res.EventMessagesDisabled = !isBit7Set(b1) res.SensorScanningDisabled = !isBit6Set(b1) res.ReadingUnavailable = isBit5Set(b1) if len(msg) >= 3 { b2, _, _ := unpackUint8(msg, 2) // For threshold-based sensors, Present threshold comparison status res.Above_UNR = isBit5Set(b2) res.Above_UCR = isBit4Set(b2) res.Above_UNC = isBit3Set(b2) res.Below_LNR = isBit2Set(b2) res.Below_LCR = isBit1Set(b2) res.Below_LNC = isBit0Set(b2) // For discrete reading sensors res.ActiveStates.State_7 = isBit7Set(b2) res.ActiveStates.State_6 = isBit6Set(b2) res.ActiveStates.State_5 = isBit5Set(b2) res.ActiveStates.State_4 = isBit4Set(b2) res.ActiveStates.State_3 = isBit3Set(b2) res.ActiveStates.State_2 = isBit2Set(b2) res.ActiveStates.State_1 = isBit1Set(b2) res.ActiveStates.State_0 = isBit0Set(b2) res.optionalData1 = b2 } // For discrete reading sensors only. (Optional) if len(msg) >= 4 { b3, _, _ := unpackUint8(msg, 3) // For discrete reading sensors res.ActiveStates.State_14 = isBit6Set(b3) res.ActiveStates.State_13 = isBit5Set(b3) res.ActiveStates.State_12 = isBit4Set(b3) res.ActiveStates.State_11 = isBit3Set(b3) res.ActiveStates.State_10 = isBit2Set(b3) res.ActiveStates.State_9 = isBit1Set(b3) res.ActiveStates.State_8 = isBit0Set(b3) res.optionalData2 = b3 } return nil } func (r *GetSensorReadingResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (r *GetSensorReadingResponse) ThresholdStatus() SensorThresholdStatus { if r.Above_UCR { return SensorThresholdStatus_UCR } if r.Above_UNC { return SensorThresholdStatus_UCR } if r.Above_UNR { return SensorThresholdStatus_UCR } if r.Below_LCR { return SensorThresholdStatus_UCR } if r.Below_LNC { return SensorThresholdStatus_UCR } if r.Below_LNR { return SensorThresholdStatus_UCR } return SensorThresholdStatus_OK } func (res *GetSensorReadingResponse) Format() string { return fmt.Sprintf(` Sensor Reading : %d Event Message Disabled : %v Scanning Disabled : %v Reading Unavailable : %v Threshold Status : %s Discrete Events : %v `, res.Reading, res.EventMessagesDisabled, res.SensorScanningDisabled, res.ReadingUnavailable, res.ThresholdStatus(), res.ActiveStates.TrueEvents(), ) } func (c *Client) GetSensorReading(ctx context.Context, sensorNumber uint8) (response *GetSensorReadingResponse, err error) { request := &GetSensorReadingRequest{ SensorNumber: sensorNumber, } response = &GetSensorReadingResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sensor_reading_factors.go000066400000000000000000000043031474110527100256420ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 35.5 Get Sensor Reading Factors Command type GetSensorReadingFactorsRequest struct { SensorNumber uint8 Reading uint8 } type GetSensorReadingFactorsResponse struct { NextReading uint8 ReadingFactors } func (req *GetSensorReadingFactorsRequest) Command() Command { return CommandGetSensorReadingFactors } func (req *GetSensorReadingFactorsRequest) Pack() []byte { out := make([]byte, 2) packUint8(req.SensorNumber, out, 0) packUint8(req.Reading, out, 1) return out } func (res *GetSensorReadingFactorsResponse) Unpack(msg []byte) error { if len(msg) < 7 { return ErrUnpackedDataTooShortWith(len(msg), 7) } res.NextReading, _, _ = unpackUint8(msg, 0) b1, _, _ := unpackUint8(msg, 1) b2, _, _ := unpackUint8(msg, 2) m := uint16(b2&0xc0)<<2 | uint16(b1) res.M = int16(twosComplement(uint32(m), 10)) res.Tolerance = b2 & 0x3f b3, _, _ := unpackUint8(msg, 3) b4, _, _ := unpackUint8(msg, 4) b5, _, _ := unpackUint8(msg, 5) b := uint16(b4&0xc0)<<2 | uint16(b3) res.B = int16(twosComplement(uint32(b), 10)) res.Accuracy = uint16(b5&0xf0)<<2 | uint16(b4&0x3f) res.Accuracy_Exp = (b5 & 0x0c) >> 2 b6, _, _ := unpackUint8(msg, 6) rExp := uint8((b6 & 0xf0) >> 4) res.R_Exp = int8(twosComplement(uint32(rExp), 4)) bExp := uint8(b6 & 0x0f) res.B_Exp = int8(twosComplement(uint32(bExp), 4)) return nil } func (r *GetSensorReadingFactorsResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSensorReadingFactorsResponse) Format() string { return fmt.Sprintf(`M: %d B: %d B_Exp (K1): %d R_Exp (K2): %d Tolerance: %d Accuracy: %d AccuracyExp: %d`, res.M, res.B, res.B_Exp, res.R_Exp, res.Tolerance, res.Accuracy, res.Accuracy_Exp, ) } // This command returns the Sensor Reading Factors fields for the specified reading value on the specified sensor. func (c *Client) GetSensorReadingFactors(ctx context.Context, sensorNumber uint8, reading uint8) (response *GetSensorReadingFactorsResponse, err error) { request := &GetSensorReadingFactorsRequest{ SensorNumber: sensorNumber, Reading: reading, } response = &GetSensorReadingFactorsResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sensor_thresholds.go000066400000000000000000000047731474110527100247020ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 35.9 Get Sensor Thresholds Command type GetSensorThresholdsRequest struct { SensorNumber uint8 } type GetSensorThresholdsResponse struct { // Readable thresholds mask UNR_Readable bool UCR_Readable bool UNC_Readable bool LNR_Readable bool LCR_Readable bool LNC_Readable bool // Threshold value LNC_Raw uint8 LCR_Raw uint8 LNR_Raw uint8 UNC_Raw uint8 UCR_Raw uint8 UNR_Raw uint8 } func (req *GetSensorThresholdsRequest) Command() Command { return CommandGetSensorThresholds } func (req *GetSensorThresholdsRequest) Pack() []byte { out := make([]byte, 1) packUint8(req.SensorNumber, out, 0) return out } func (res *GetSensorThresholdsResponse) Unpack(msg []byte) error { if len(msg) < 7 { return ErrUnpackedDataTooShortWith(len(msg), 7) } b, _, _ := unpackUint8(msg, 0) res.UNR_Readable = isBit5Set(b) res.UCR_Readable = isBit4Set(b) res.UNC_Readable = isBit3Set(b) res.LNR_Readable = isBit2Set(b) res.LCR_Readable = isBit1Set(b) res.LNC_Readable = isBit0Set(b) res.LNC_Raw, _, _ = unpackUint8(msg, 1) res.LCR_Raw, _, _ = unpackUint8(msg, 2) res.LNR_Raw, _, _ = unpackUint8(msg, 3) res.UNC_Raw, _, _ = unpackUint8(msg, 4) res.UCR_Raw, _, _ = unpackUint8(msg, 5) res.UNR_Raw, _, _ = unpackUint8(msg, 6) return nil } func (r *GetSensorThresholdsResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSensorThresholdsResponse) Format() string { return fmt.Sprintf(`UNR Readable : %v%s UCR Readable : %v%s UNC Readable : %v%s LNR Readable : %v%s LCR Readable : %v%s LNC Readable : %v%s`, res.UNR_Readable, formatBool(res.UNR_Readable, fmt.Sprintf(", raw: %#02x", res.UNR_Raw), ""), res.UCR_Readable, formatBool(res.UCR_Readable, fmt.Sprintf(", raw: %#02x", res.UCR_Raw), ""), res.UNC_Readable, formatBool(res.UNC_Readable, fmt.Sprintf(", raw: %#02x", res.UNC_Raw), ""), res.LNR_Readable, formatBool(res.LNR_Readable, fmt.Sprintf(", raw: %#02x", res.LNR_Raw), ""), res.LCR_Readable, formatBool(res.LCR_Readable, fmt.Sprintf(", raw: %#02x", res.LCR_Raw), ""), res.LNC_Readable, formatBool(res.LNC_Readable, fmt.Sprintf(", raw: %#02x", res.LNC_Raw), ""), ) } // This command retrieves the threshold for the given sensor. func (c *Client) GetSensorThresholds(ctx context.Context, sensorNumber uint8) (response *GetSensorThresholdsResponse, err error) { request := &GetSensorThresholdsRequest{ SensorNumber: sensorNumber, } response = &GetSensorThresholdsResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sensor_type.go000066400000000000000000000024731474110527100234770ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // GetSensorTypeRequest (31.2) type GetSensorTypeRequest struct { SensorNumber uint8 } type GetSensorTypeResponse struct { SensorType SensorType EventReadingType EventReadingType } func (req *GetSensorTypeRequest) Command() Command { return CommandGetSensorType } func (req *GetSensorTypeRequest) Pack() []byte { out := make([]byte, 1) packUint8(req.SensorNumber, out, 0) return out } func (res *GetSensorTypeResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } b1, _, _ := unpackUint8(msg, 0) res.SensorType = SensorType(b1) b2, _, _ := unpackUint8(msg, 1) res.EventReadingType = EventReadingType(b2) return nil } func (r *GetSensorTypeResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSensorTypeResponse) Format() string { return fmt.Sprintf(`Sensor Type : %s Event/Reading Type : %#02x (%s)`, res.SensorType, uint8(res.EventReadingType), res.EventReadingType, ) } func (c *Client) GetSensorType(ctx context.Context, sensorNumber uint8) (response *GetSensorTypeResponse, err error) { request := &GetSensorTypeRequest{ SensorNumber: sensorNumber, } response = &GetSensorTypeResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sensors.go000066400000000000000000000244451474110527100226240ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "strings" ) type SensorFilterOption func(sensor *Sensor) bool func SensorFilterOptionIsThreshold(sensor *Sensor) bool { return sensor.IsThreshold() } func SensorFilterOptionIsReadingValid(sensor *Sensor) bool { return sensor.IsReadingValid() } // Sensor is matched if the sensor type of the sensor is one of the given sensor types. func SensorFilterOptionIsSensorType(sensorTypes ...SensorType) func(sensor *Sensor) bool { return func(sensor *Sensor) bool { for _, sensorType := range sensorTypes { if sensor.SensorType == sensorType { return true } } return false } } // GetSensors returns all sensors with their current readings and status. // // If there's no filter options, it returns all sensors. // // If there exists filter options, it returns the sensors those // passed all filter options, that means the filter options are logically ANDed. // // If you want the filter options are logically ORed, use `GetSensorsAny` func (c *Client) GetSensors(ctx context.Context, filterOptions ...SensorFilterOption) ([]*Sensor, error) { var out = make([]*Sensor, 0) sdrs, err := c.GetSDRs(ctx, SDRRecordTypeFullSensor, SDRRecordTypeCompactSensor) if err != nil { return nil, fmt.Errorf("GetSDRs failed, err: %w", err) } for _, sdr := range sdrs { sensor, err := c.sdrToSensor(ctx, sdr) if err != nil { return nil, fmt.Errorf("sdrToSensor failed, err: %w", err) } var choose bool = true for _, filterOption := range filterOptions { if !filterOption(sensor) { choose = false break } } if choose { out = append(out, sensor) } } return out, nil } // GetSensorsAny returns all sensors with their current readings and status. // // If there's no filter options, it returns all sensors. // // If there exists filter options, it only returns the sensors those // passed any one filter option, that means the filter options are logically ORed. // // If you want the filter options are logically ANDed, use `GetSensors`. func (c *Client) GetSensorsAny(ctx context.Context, filterOptions ...SensorFilterOption) ([]*Sensor, error) { var out = make([]*Sensor, 0) sdrs, err := c.GetSDRs(ctx, SDRRecordTypeFullSensor, SDRRecordTypeCompactSensor) if err != nil { return nil, fmt.Errorf("GetSDRs failed, err: %w", err) } for _, sdr := range sdrs { sensor, err := c.sdrToSensor(ctx, sdr) if err != nil { return nil, fmt.Errorf("sdrToSensor failed, err: %w", err) } var choose bool = false for _, filterOption := range filterOptions { if filterOption(sensor) { choose = true break } } if choose { out = append(out, sensor) } } return out, nil } // GetSensorByID returns the sensor with current reading and status by specified sensor number. func (c *Client) GetSensorByID(ctx context.Context, sensorNumber uint8) (*Sensor, error) { sdr, err := c.GetSDRBySensorID(ctx, sensorNumber) if err != nil { return nil, fmt.Errorf("GetSDRBySensorID failed, err: %w", err) } sensor, err := c.sdrToSensor(ctx, sdr) if err != nil { return nil, fmt.Errorf("GetSensorFromSDR failed, err: %w", err) } return sensor, nil } // GetSensorByName returns the sensor with current reading and status by specified sensor name. func (c *Client) GetSensorByName(ctx context.Context, sensorName string) (*Sensor, error) { sdr, err := c.GetSDRBySensorName(ctx, sensorName) if err != nil { return nil, fmt.Errorf("GetSDRBySensorName failed, err: %w", err) } sensor, err := c.sdrToSensor(ctx, sdr) if err != nil { return nil, fmt.Errorf("GetSensorFromSDR failed, err: %w", err) } return sensor, nil } // sdrToSensor convert SDR record to Sensor struct. // // Only Full and Compact SDR records are meaningful here. Pass SDRs with other record types will return error. // // This function will fetch other sensor-related values which are not stored in SDR by other IPMI commands. func (c *Client) sdrToSensor(ctx context.Context, sdr *SDR) (*Sensor, error) { if sdr == nil { return nil, fmt.Errorf("nil sdr parameter") } sensor := &Sensor{ SDRRecordType: sdr.RecordHeader.RecordType, HasAnalogReading: sdr.HasAnalogReading(), } switch sdr.RecordHeader.RecordType { case SDRRecordTypeFullSensor: sensor.Number = uint8(sdr.Full.SensorNumber) sensor.Name = strings.TrimSpace(string(sdr.Full.IDStringBytes)) sensor.SensorUnit = sdr.Full.SensorUnit sensor.SensorType = sdr.Full.SensorType sensor.EventReadingType = sdr.Full.SensorEventReadingType sensor.SensorInitialization = sdr.Full.SensorInitialization sensor.SensorCapabilities = sdr.Full.SensorCapabilities sensor.EntityID = sdr.Full.SensorEntityID sensor.EntityInstance = sdr.Full.SensorEntityInstance sensor.Threshold.LinearizationFunc = sdr.Full.LinearizationFunc sensor.Threshold.ReadingFactors = sdr.Full.ReadingFactors case SDRRecordTypeCompactSensor: sensor.Number = uint8(sdr.Compact.SensorNumber) sensor.Name = strings.TrimSpace(string(sdr.Compact.IDStringBytes)) sensor.SensorUnit = sdr.Compact.SensorUnit sensor.SensorType = sdr.Compact.SensorType sensor.EventReadingType = sdr.Compact.SensorEventReadingType sensor.SensorInitialization = sdr.Compact.SensorInitialization sensor.SensorCapabilities = sdr.Compact.SensorCapabilities sensor.EntityID = sdr.Compact.SensorEntityID sensor.EntityInstance = sdr.Compact.SensorEntityInstance default: return nil, fmt.Errorf("only support Full or Compact SDR record type, input is %s", sdr.RecordHeader.RecordType) } c.Debug("Sensor:", sensor) c.Debug("Get Sensor", fmt.Sprintf("Sensor Name: %s, Sensor Number: %#02x\n", sensor.Name, sensor.Number)) if err := c.fillSensorReading(ctx, sensor); err != nil { return nil, fmt.Errorf("fillSensorReading failed, err: %w", err) } // scanningDisabled is filled/set by fillSensorReading if sensor.scanningDisabled { // Sensor scanning disabled, no need to continue c.Debug(fmt.Sprintf(":( Sensor [%s](%#02x) scanning disabled\n", sensor.Name, sensor.Number), "") return sensor, nil } if !sensor.EventReadingType.IsThreshold() || !sensor.SensorUnit.IsAnalog() { if err := c.fillSensorDiscrete(ctx, sensor); err != nil { return nil, fmt.Errorf("fillSensorDiscrete failed, err: %w", err) } } else { if err := c.fillSensorThreshold(ctx, sensor); err != nil { return nil, fmt.Errorf("fillSensorThreshold failed, err: %w", err) } } return sensor, nil } func (c *Client) fillSensorReading(ctx context.Context, sensor *Sensor) error { readingRes, err := c.GetSensorReading(ctx, sensor.Number) if _canIgnoreSensorErr(err) != nil { return fmt.Errorf("GetSensorReading for sensor %#02x failed, err: %w", sensor.Number, err) } sensor.Raw = readingRes.Reading sensor.Value = sensor.ConvertReading(readingRes.Reading) sensor.scanningDisabled = readingRes.SensorScanningDisabled sensor.readingAvailable = !readingRes.ReadingUnavailable sensor.Threshold.ThresholdStatus = readingRes.ThresholdStatus() sensor.Discrete.ActiveStates = readingRes.ActiveStates sensor.Discrete.optionalData1 = readingRes.optionalData1 sensor.Discrete.optionalData2 = readingRes.optionalData2 return nil } // fillSensorDiscrete retrieves and fills extra sensor attributes for given discrete sensor. func (c *Client) fillSensorDiscrete(ctx context.Context, sensor *Sensor) error { statusRes, err := c.GetSensorEventStatus(ctx, sensor.Number) if _canIgnoreSensorErr(err) != nil { return fmt.Errorf("GetSensorEventStatus for sensor %#02x failed, err: %w", sensor.Number, err) } sensor.OccurredEvents = statusRes.SensorEventFlag.TrueEvents() return nil } // fillSensorThreshold retrieves and fills sensor attributes for given threshold sensor. func (c *Client) fillSensorThreshold(ctx context.Context, sensor *Sensor) error { if sensor.SDRRecordType != SDRRecordTypeFullSensor { return nil } // If Non Linear, should update the ReadingFactors // see 36.2 Non-Linear Sensors if sensor.Threshold.LinearizationFunc.IsNonLinear() { factorsRes, err := c.GetSensorReadingFactors(ctx, sensor.Number, sensor.Raw) if _canIgnoreSensorErr(err) != nil { return fmt.Errorf("GetSensorReadingFactors for sensor %#02x failed, err: %w", sensor.Number, err) } sensor.Threshold.ReadingFactors = factorsRes.ReadingFactors } thresholdRes, err := c.GetSensorThresholds(ctx, sensor.Number) if _canIgnoreSensorErr(err) != nil { return fmt.Errorf("GetSensorThresholds for sensor %#02x failed, err: %w", sensor.Number, err) } sensor.Threshold.Mask.UNR.Readable = thresholdRes.UNR_Readable sensor.Threshold.Mask.UCR.Readable = thresholdRes.UCR_Readable sensor.Threshold.Mask.UNC.Readable = thresholdRes.UNC_Readable sensor.Threshold.Mask.LNR.Readable = thresholdRes.LNR_Readable sensor.Threshold.Mask.LCR.Readable = thresholdRes.LCR_Readable sensor.Threshold.Mask.LNC.Readable = thresholdRes.LNC_Readable sensor.Threshold.LNC_Raw = thresholdRes.LNC_Raw sensor.Threshold.LCR_Raw = thresholdRes.LCR_Raw sensor.Threshold.LNR_Raw = thresholdRes.LNR_Raw sensor.Threshold.UNC_Raw = thresholdRes.UNC_Raw sensor.Threshold.UCR_Raw = thresholdRes.UCR_Raw sensor.Threshold.UNR_Raw = thresholdRes.UNR_Raw sensor.Threshold.LNC = sensor.ConvertReading(thresholdRes.LNC_Raw) sensor.Threshold.LCR = sensor.ConvertReading(thresholdRes.LCR_Raw) sensor.Threshold.LNR = sensor.ConvertReading(thresholdRes.LNR_Raw) sensor.Threshold.UNC = sensor.ConvertReading(thresholdRes.UNC_Raw) sensor.Threshold.UCR = sensor.ConvertReading(thresholdRes.UCR_Raw) sensor.Threshold.UNR = sensor.ConvertReading(thresholdRes.UNR_Raw) hysteresisRes, err := c.GetSensorHysteresis(ctx, sensor.Number) if _canIgnoreSensorErr(err) != nil { return fmt.Errorf("GetSensorHysteresis for sensor %#02x failed, err: %w", sensor.Number, err) } sensor.Threshold.PositiveHysteresisRaw = hysteresisRes.PositiveRaw sensor.Threshold.NegativeHysteresisRaw = hysteresisRes.NegativeRaw sensor.Threshold.PositiveHysteresis = sensor.ConvertSensorHysteresis(hysteresisRes.PositiveRaw) sensor.Threshold.NegativeHysteresis = sensor.ConvertSensorHysteresis(hysteresisRes.NegativeRaw) return nil } func _canIgnoreSensorErr(err error) error { canIgnore := buildCanIgnoreFn( // the following completion codes CAN be ignored, // it normally means the sensor device does not exist or the sensor device does not recognize the IPMI command uint8(CompletionCodeRequestedDataNotPresent), uint8(CompletionCodeIllegalCommand), uint8(CompletionCodeInvalidCommand), ) return canIgnore(err) } golang-github-bougou-go-ipmi-0.7.2/cmd_get_session_challenge.go000066400000000000000000000036061474110527100246110ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 22.16 type GetSessionChallengeRequest struct { // Authentication Type for Challenge // indicating what type of authentication type the console wants to use. AuthType AuthType // Sixteen-bytes. All 0s for null user name (User 1) Username [16]byte } type GetSessionChallengeResponse struct { TemporarySessionID uint32 // LS byte first Challenge [16]byte } func (req *GetSessionChallengeRequest) Command() Command { return CommandGetSessionChallenge } func (req *GetSessionChallengeRequest) Pack() []byte { out := make([]byte, 17) packUint8(uint8(req.AuthType), out, 0) packBytes(req.Username[:], out, 1) return out } func (res *GetSessionChallengeResponse) Unpack(msg []byte) error { if len(msg) < 20 { return ErrUnpackedDataTooShortWith(len(msg), 20) } res.TemporarySessionID, _, _ = unpackUint32L(msg, 0) b, _, _ := unpackBytes(msg, 4, 16) res.Challenge = array16(b) return nil } func (*GetSessionChallengeResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "invalid user name", 0x82: "null user name (User 1) not enabled", } } func (res *GetSessionChallengeResponse) Format() string { return fmt.Sprintf("%v", res) } // The command selects which of the BMC-supported authentication types the Remote Console would like to use, // and a username that selects which set of user information should be used for the session func (c *Client) GetSessionChallenge(ctx context.Context) (response *GetSessionChallengeResponse, err error) { username := padBytes(c.Username, 16, 0x00) request := &GetSessionChallengeRequest{ AuthType: c.session.authType, Username: array16(username), } response = &GetSessionChallengeResponse{} err = c.Exchange(ctx, request, response) if err != nil { return } c.session.v15.sessionID = response.TemporarySessionID c.session.v15.challenge = response.Challenge return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_session_info.go000066400000000000000000000112631474110527100236200ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "net" ) // 22.20 Get Session Info Command type GetSessionInfoRequest struct { // Session index // 00h = Return info for active session associated with session this command was received over. // N = get info for Nth active session // FEh = Look up session info according to Session Handle passed in this request. // FFh = Look up session info according to Session ID passed in this request. SessionIndex uint8 SessionHandle uint8 SessionID uint32 } type GetSessionInfoResponse struct { SessionHandle uint8 // Session Handle presently assigned to active session. PossibleActiveSessions uint8 // This value reflects the number of possible entries (slots) in the sessions table. CurrentActiveSessions uint8 // Number of currently active sessions on all channels on this controller UserID uint8 OperatingPrivilegeLevel PrivilegeLevel // [7:4] - Session protocol auxiliary data // For Channel Type = 802.3 LAN: // 0h = IPMI v1.5 // 1h = IPMI v2.0/RMCP+ AuxiliaryData uint8 // 4bits ChannelNumber uint8 // 4bits // if Channel Type = 802.3 LAN: RemoteConsoleIPAddr net.IP // IP Address of remote console (MS-byte first). RemoteConsoleMacAddr net.HardwareAddr // 6 bytes, MAC Address (MS-byte first) RemoteConsolePort uint16 // Port Number of remote console (LS-byte first) // if Channel Type = asynch. serial/modem SessionChannelActivityType uint8 DestinationSelector uint8 RemoteConsoleIPAddr_PPP uint32 // If PPP connection: IP address of remote console. (MS-byte first) 00h, 00h, 00h, 00h otherwise. // if Channel Type = asynch. serial/modem and connection is PPP: RemoteConsolePort_PPP uint16 } func (req *GetSessionInfoRequest) Command() Command { return CommandGetSessionInfo } func (req *GetSessionInfoRequest) Pack() []byte { out := make([]byte, 5) packUint8(req.SessionIndex, out, 0) if req.SessionIndex == 0xfe { packUint8(req.SessionHandle, out, 1) return out[0:2] } if req.SessionIndex == 0xff { packUint32L(req.SessionID, out, 1) return out[0:5] } return out[0:1] } func (res *GetSessionInfoResponse) Unpack(msg []byte) error { // at least 3 bytes if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } res.SessionHandle, _, _ = unpackUint8(msg, 0) res.PossibleActiveSessions, _, _ = unpackUint8(msg, 1) res.CurrentActiveSessions, _, _ = unpackUint8(msg, 2) if len(msg) == 3 { return nil } // if len(msg) > 3, then at least 6 bytes if len(msg) < 6 { return ErrUnpackedDataTooShortWith(len(msg), 6) } res.UserID, _, _ = unpackUint8(msg, 3) b5, _, _ := unpackUint8(msg, 4) res.OperatingPrivilegeLevel = PrivilegeLevel(b5) b6, _, _ := unpackUint8(msg, 5) res.AuxiliaryData = b6 >> 4 res.ChannelNumber = b6 & 0x0f // Channel Type = 802.3 LAN: if len(msg) >= 18 { ipBytes, _, _ := unpackBytes(msg, 6, 4) res.RemoteConsoleIPAddr = net.IP(ipBytes) macBytes, _, _ := unpackBytes(msg, 10, 6) res.RemoteConsoleMacAddr = net.HardwareAddr(macBytes) res.RemoteConsolePort, _, _ = unpackUint16L(msg, 16) } if len(msg) >= 14 { res.SessionChannelActivityType, _, _ = unpackUint8(msg, 6) res.DestinationSelector, _, _ = unpackUint8(msg, 7) res.RemoteConsoleIPAddr_PPP, _, _ = unpackUint32(msg, 8) res.RemoteConsolePort_PPP, _, _ = unpackUint16L(msg, 12) } return nil } func (res *GetSessionInfoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSessionInfoResponse) Format() string { var sessionType string switch res.AuxiliaryData { case 0: sessionType = "IPMIv1.5" case 1: sessionType = "IPMIv2/RMCP+" } return fmt.Sprintf(`session handle : %d slot count : %d active sessions : %d user id : %d privilege level : %s session type : %s channel number : %#02x console ip : %s console mac : %s console port : %d `, res.SessionHandle, res.PossibleActiveSessions, res.CurrentActiveSessions, res.UserID, res.OperatingPrivilegeLevel, sessionType, res.ChannelNumber, res.RemoteConsoleIPAddr, res.RemoteConsoleMacAddr, res.RemoteConsolePort, ) } func (c *Client) GetSessionInfo(ctx context.Context, request *GetSessionInfoRequest) (response *GetSessionInfoResponse, err error) { response = &GetSessionInfoResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetCurrentSessionInfo(ctx context.Context) (response *GetSessionInfoResponse, err error) { request := &GetSessionInfoRequest{ SessionIndex: 0x00, } response = &GetSessionInfoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_sol_config_params.go000066400000000000000000000113131474110527100246030ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 26.3 Get SOL Configuration Parameters Command type GetSOLConfigParamRequest struct { GetParamRevisionOnly bool ChannelNumber uint8 ParamSelector SOLConfigParamSelector SetSelector uint8 BlockSelector uint8 } type GetSOLConfigParamResponse struct { ParamRevision uint8 ParamData []byte } func (req *GetSOLConfigParamRequest) Command() Command { return CommandGetSOLConfigParam } func (req *GetSOLConfigParamRequest) Pack() []byte { out := make([]byte, 4) b := req.ChannelNumber if req.GetParamRevisionOnly { b = setBit7(b) } packUint8(b, out, 0) packUint8(uint8(req.ParamSelector), out, 1) packUint8(req.SetSelector, out, 2) packUint8(req.BlockSelector, out, 3) return out } func (res *GetSOLConfigParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSOLConfigParamResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } res.ParamRevision = msg[0] if len(msg) > 1 { res.ParamData, _, _ = unpackBytes(msg, 1, len(msg)-1) } return nil } func (res *GetSOLConfigParamResponse) Format() string { return "" } func (c *Client) GetSOLConfigParam(ctx context.Context, channelNumber uint8, paramSelector SOLConfigParamSelector, setSelector, blockSelector uint8) (response *GetSOLConfigParamResponse, err error) { request := &GetSOLConfigParamRequest{ ChannelNumber: channelNumber, ParamSelector: paramSelector, SetSelector: 0x00, BlockSelector: 0x00, } response = &GetSOLConfigParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetSOLConfigParamFor(ctx context.Context, channelNumber uint8, param SOLConfigParameter) error { if isNilSOLConfigParameter(param) { return nil } paramSelector, setSelector, blockSelector := param.SOLConfigParameter() res, err := c.GetSOLConfigParam(ctx, channelNumber, paramSelector, setSelector, blockSelector) if err != nil { return fmt.Errorf("GetSOLConfigParam for param (%s[%2d]) failed, err: %w", paramSelector.String(), paramSelector, err) } if err := param.Unpack(res.ParamData); err != nil { return fmt.Errorf("unpack param (%s[%2d]) failed, err: %w", paramSelector.String(), paramSelector, err) } return nil } func (c *Client) GetSOLConfigParams(ctx context.Context, channelNumber uint8) (*SOLConfigParams, error) { solConfigParams := &SOLConfigParams{ SetInProgress: &SOLConfigParam_SetInProgress{}, SOLEnable: &SOLConfigParam_SOLEnable{}, SOLAuthentication: &SOLConfigParam_SOLAuthentication{}, Character: &SOLConfigParam_Character{}, SOLRetry: &SOLConfigParam_SOLRetry{}, NonVolatileBitRate: &SOLConfigParam_NonVolatileBitRate{}, VolatileBitRate: &SOLConfigParam_VolatileBitRate{}, PayloadChannel: &SOLConfigParam_PayloadChannel{}, PayloadPort: &SOLConfigParam_PayloadPort{}, } if err := c.GetSOLConfigParamsFor(ctx, channelNumber, solConfigParams); err != nil { return nil, fmt.Errorf("GetSOLConfigParamFor failed, err: %w", err) } return solConfigParams, nil } func (c *Client) GetSOLConfigParamsFor(ctx context.Context, channelNumber uint8, solConfigParams *SOLConfigParams) error { if solConfigParams == nil { return nil } if solConfigParams.SetInProgress != nil { if err := c.GetSOLConfigParamFor(ctx, channelNumber, solConfigParams.SetInProgress); err != nil { return err } } if solConfigParams.SOLEnable != nil { if err := c.GetSOLConfigParamFor(ctx, channelNumber, solConfigParams.SOLEnable); err != nil { return err } } if solConfigParams.SOLAuthentication != nil { if err := c.GetSOLConfigParamFor(ctx, channelNumber, solConfigParams.SOLAuthentication); err != nil { return err } } if solConfigParams.Character != nil { if err := c.GetSOLConfigParamFor(ctx, channelNumber, solConfigParams.Character); err != nil { return err } } if solConfigParams.SOLRetry != nil { if err := c.GetSOLConfigParamFor(ctx, channelNumber, solConfigParams.SOLRetry); err != nil { return err } } if solConfigParams.NonVolatileBitRate != nil { if err := c.GetSOLConfigParamFor(ctx, channelNumber, solConfigParams.NonVolatileBitRate); err != nil { return err } } if solConfigParams.VolatileBitRate != nil { if err := c.GetSOLConfigParamFor(ctx, channelNumber, solConfigParams.VolatileBitRate); err != nil { return err } } if solConfigParams.PayloadChannel != nil { if err := c.GetSOLConfigParamFor(ctx, channelNumber, solConfigParams.PayloadChannel); err != nil { return err } } if solConfigParams.PayloadPort != nil { if err := c.GetSOLConfigParamFor(ctx, channelNumber, solConfigParams.PayloadPort); err != nil { return err } } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_supermicro_bios_version.go000066400000000000000000000021161474110527100260700ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "strings" ) type CommandGetSupermicroBiosVersionRequest struct { } type CommandGetSupermicroBiosVersionResponse struct { Version string } func (req *CommandGetSupermicroBiosVersionRequest) Command() Command { return CommandGetSupermicroBiosVersion } func (req *CommandGetSupermicroBiosVersionRequest) Pack() []byte { return []byte{0x00, 0x00} } func (res *CommandGetSupermicroBiosVersionResponse) Unpack(msg []byte) error { res.Version = string(msg) res.Version = strings.TrimSpace(res.Version) return nil } func (res *CommandGetSupermicroBiosVersionResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *CommandGetSupermicroBiosVersionResponse) Format() string { return fmt.Sprintf(`bios.version = %s`, res.Version, ) } func (c *Client) GetSupermicroBiosVersion(ctx context.Context) (response *CommandGetSupermicroBiosVersionResponse, err error) { request := &CommandGetSupermicroBiosVersionRequest{} response = &CommandGetSupermicroBiosVersionResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_system_boot_options.go000066400000000000000000000144021474110527100252420ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 28.13 Get System Boot Options Command type GetSystemBootOptionsParamRequest struct { ParamSelector BootOptionParamSelector SetSelector uint8 BlockSelector uint8 } // Table 28-14, Boot Option Parameters type GetSystemBootOptionsParamResponse struct { ParameterVersion uint8 // [7] - 1b = mark parameter invalid / locked // 0b = mark parameter valid / unlocked ParameterInValid bool // [6:0] - boot option parameter selector ParamSelector BootOptionParamSelector ParamData []byte // origin parameter data } func (req *GetSystemBootOptionsParamRequest) Pack() []byte { out := make([]byte, 3) packUint8(uint8(req.ParamSelector), out, 0) packUint8(req.SetSelector, out, 1) packUint8(req.BlockSelector, out, 2) return out } func (req *GetSystemBootOptionsParamRequest) Command() Command { return CommandGetSystemBootOptions } func (res *GetSystemBootOptionsParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "parameter not supported", } } func (res *GetSystemBootOptionsParamResponse) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } res.ParameterVersion, _, _ = unpackUint8(msg, 0) b, _, _ := unpackUint8(msg, 1) res.ParameterInValid = isBit7Set(b) res.ParamSelector = BootOptionParamSelector(b & 0x7f) // clear bit 7 res.ParamData, _, _ = unpackBytes(msg, 2, len(msg)-2) return nil } func (res *GetSystemBootOptionsParamResponse) Format() string { var paramDataFormatted string var param BootOptionParameter switch res.ParamSelector { case BootOptionParamSelector_SetInProgress: param = &BootOptionParam_SetInProgress{} case BootOptionParamSelector_ServicePartitionSelector: param = &BootOptionParam_ServicePartitionSelector{} case BootOptionParamSelector_ServicePartitionScan: param = &BootOptionParam_ServicePartitionScan{} case BootOptionParamSelector_BMCBootFlagValidBitClear: param = &BootOptionParam_BMCBootFlagValidBitClear{} case BootOptionParamSelector_BootInfoAcknowledge: param = &BootOptionParam_BootInfoAcknowledge{} case BootOptionParamSelector_BootFlags: param = &BootOptionParam_BootFlags{} case BootOptionParamSelector_BootInitiatorInfo: param = &BootOptionParam_BootInitiatorInfo{} case BootOptionParamSelector_BootInitiatorMailbox: param = &BootOptionParam_BootInitiatorMailbox{} } if param != nil { if err := param.Unpack(res.ParamData); err == nil { paramDataFormatted = param.Format() } } return fmt.Sprintf(`Boot parameter version: %d Boot parameter %d is %s Boot parameter data: %02x %s : %s`, res.ParameterVersion, res.ParamSelector, formatBool(res.ParameterInValid, "invalid/locked", "valid/unlocked"), res.ParamData, res.ParamSelector.String(), paramDataFormatted, ) } func (c *Client) GetSystemBootOptionsParam(ctx context.Context, paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) (response *GetSystemBootOptionsParamResponse, err error) { request := &GetSystemBootOptionsParamRequest{ ParamSelector: paramSelector, SetSelector: setSelector, BlockSelector: blockSelector, } response = &GetSystemBootOptionsParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetSystemBootOptionsParamFor(ctx context.Context, param BootOptionParameter) error { if isNilBootOptionParameter(param) { return nil } paramSelector, setSelector, blockSelector := param.BootOptionParameter() response, err := c.GetSystemBootOptionsParam(ctx, paramSelector, setSelector, blockSelector) if err != nil { return fmt.Errorf("GetSystemBootOptions for param (%s[%d]) failed, err: %w", paramSelector.String(), paramSelector, err) } if err := param.Unpack(response.ParamData); err != nil { return fmt.Errorf("unpack param (%s[%d]) failed, err: %w", paramSelector.String(), paramSelector, err) } return nil } // GetSystemBootOptionsParams get all parameters of boot options. func (c *Client) GetSystemBootOptionsParams(ctx context.Context) (*BootOptionsParams, error) { bootOptionsParams := &BootOptionsParams{ SetInProgress: &BootOptionParam_SetInProgress{}, ServicePartitionSelector: &BootOptionParam_ServicePartitionSelector{}, ServicePartitionScan: &BootOptionParam_ServicePartitionScan{}, BMCBootFlagValidBitClear: &BootOptionParam_BMCBootFlagValidBitClear{}, BootInfoAcknowledge: &BootOptionParam_BootInfoAcknowledge{}, BootFlags: &BootOptionParam_BootFlags{}, BootInitiatorInfo: &BootOptionParam_BootInitiatorInfo{}, BootInitiatorMailbox: &BootOptionParam_BootInitiatorMailbox{}, } if err := c.GetSystemBootOptionsParamsFor(ctx, bootOptionsParams); err != nil { return nil, fmt.Errorf("GetBootOptionsFor failed, err: %w", err) } return bootOptionsParams, nil } func (c *Client) GetSystemBootOptionsParamsFor(ctx context.Context, bootOptionsParams *BootOptionsParams) error { if bootOptionsParams == nil { return nil } if bootOptionsParams.SetInProgress != nil { if err := c.GetSystemBootOptionsParamFor(ctx, bootOptionsParams.SetInProgress); err != nil { return err } } if bootOptionsParams.ServicePartitionSelector != nil { if err := c.GetSystemBootOptionsParamFor(ctx, bootOptionsParams.ServicePartitionSelector); err != nil { return err } } if bootOptionsParams.ServicePartitionScan != nil { if err := c.GetSystemBootOptionsParamFor(ctx, bootOptionsParams.ServicePartitionScan); err != nil { return err } } if bootOptionsParams.BMCBootFlagValidBitClear != nil { if err := c.GetSystemBootOptionsParamFor(ctx, bootOptionsParams.BMCBootFlagValidBitClear); err != nil { return err } } if bootOptionsParams.BootInfoAcknowledge != nil { if err := c.GetSystemBootOptionsParamFor(ctx, bootOptionsParams.BootInfoAcknowledge); err != nil { return err } } if bootOptionsParams.BootFlags != nil { if err := c.GetSystemBootOptionsParamFor(ctx, bootOptionsParams.BootFlags); err != nil { return err } } if bootOptionsParams.BootInitiatorInfo != nil { if err := c.GetSystemBootOptionsParamFor(ctx, bootOptionsParams.BootInitiatorInfo); err != nil { return err } } if bootOptionsParams.BootInitiatorMailbox != nil { if err := c.GetSystemBootOptionsParamFor(ctx, bootOptionsParams.BootInitiatorMailbox); err != nil { return err } } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_get_system_guid.go000066400000000000000000000031141474110527100234520ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "time" ) // 22.14 Get System GUID Command type GetSystemGUIDRequest struct { // empty } type GetSystemGUIDResponse struct { // Note that the individual fields within the GUID are stored least-significant byte first GUID [16]byte } func (req *GetSystemGUIDRequest) Command() Command { return CommandGetSystemGUID } func (req *GetSystemGUIDRequest) Pack() []byte { return nil } func (res *GetSystemGUIDResponse) Unpack(msg []byte) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } b, _, _ := unpackBytes(msg, 0, 16) res.GUID = array16(b) return nil } func (*GetSystemGUIDResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetSystemGUIDResponse) Format() string { out := "" guidMode := GUIDModeSMBIOS u, err := ParseGUID(res.GUID[:], guidMode) if err != nil { return fmt.Sprintf(" (%s)", err) } out += fmt.Sprintf("System GUID : %s\n", u.String()) out += fmt.Sprintf("UUID Encoding : %s\n", guidMode) out += fmt.Sprintf("UUID Version : %s\n", UUIDVersionString(u)) sec, nsec := u.Time().UnixTime() out += fmt.Sprintf("Timestamp : %s\n", time.Unix(sec, nsec).Format(timeFormat)) out += fmt.Sprintf("Timestamp(Legacy) : %s\n", IPMILegacyGUIDTime(u).Format(timeFormat)) return out } func (c *Client) GetSystemGUID(ctx context.Context) (response *GetSystemGUIDResponse, err error) { request := &GetSystemGUIDRequest{} response = &GetSystemGUIDResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_system_info_params.go000066400000000000000000000233071474110527100250260ustar00rootroot00000000000000package ipmi import ( "context" "encoding/binary" "fmt" "unicode/utf16" ) type GetSystemInfoParamRequest struct { GetParamRevisionOnly bool ParamSelector SystemInfoParamSelector SetSelector uint8 BlockSelector uint8 } type GetSystemInfoParamResponse struct { ParamRevision uint8 ParamData []byte } func (req *GetSystemInfoParamRequest) Pack() []byte { out := make([]byte, 4) var b uint8 b = setOrClearBit7(b, req.GetParamRevisionOnly) out[0] = b out[1] = uint8(req.ParamSelector) out[2] = req.SetSelector out[3] = req.BlockSelector return out } func (req *GetSystemInfoParamRequest) Command() Command { return CommandGetSystemInfoParam } func (res *GetSystemInfoParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "parameter not supported", } } func (res *GetSystemInfoParamResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } res.ParamRevision, _, _ = unpackUint8(msg, 0) if len(msg) > 1 { res.ParamData, _, _ = unpackBytes(msg, 1, len(msg)-1) } return nil } func (res *GetSystemInfoParamResponse) Format() string { return fmt.Sprintf(` Param Revision: %d Param Data: %v `, res.ParamRevision, res.ParamData) } func (c *Client) GetSystemInfoParam(ctx context.Context, paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) (response *GetSystemInfoParamResponse, err error) { request := &GetSystemInfoParamRequest{ ParamSelector: paramSelector, SetSelector: setSelector, BlockSelector: blockSelector, } response = &GetSystemInfoParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) GetSystemInfoParamFor(ctx context.Context, param SystemInfoParameter) error { if isNilSystemInfoParamete(param) { return nil } paramSelector, setSelector, blockSelector := param.SystemInfoParameter() response, err := c.GetSystemInfoParam(ctx, paramSelector, setSelector, blockSelector) if err != nil { return fmt.Errorf("GetSystemInfoParam for param (%s[%d]) failed, err: %w", paramSelector.String(), paramSelector, err) } if err := param.Unpack(response.ParamData); err != nil { return fmt.Errorf("unpack param (%s[%d]) failed, err: %w", paramSelector.String(), paramSelector, err) } return nil } func (c *Client) GetSystemInfoParams(ctx context.Context) (*SystemInfoParams, error) { systemInfo := &SystemInfoParams{ SetInProgress: &SystemInfoParam_SetInProgress{}, SystemFirmwareVersions: make([]*SystemInfoParam_SystemFirmwareVersion, 0), SystemNames: make([]*SystemInfoParam_SystemName, 0), PrimaryOSNames: make([]*SystemInfoParam_PrimaryOSName, 0), OSNames: make([]*SystemInfoParam_OSName, 0), OSVersions: make([]*SystemInfoParam_OSVersion, 0), BMCURLs: make([]*SystemInfoParam_BMCURL, 0), ManagementURLs: make([]*SystemInfoParam_ManagementURL, 0), } if err := c.GetSystemInfoParamsFor(ctx, systemInfo); err != nil { return nil, err } return systemInfo, nil } func (c *Client) GetSystemInfoParamsFor(ctx context.Context, params *SystemInfoParams) error { if params == nil { return nil } canIgnore := buildCanIgnoreFn( 0x80, // parameter not supported ) if err := c.GetSystemInfoParamFor(ctx, params.SetInProgress); canIgnore(err) != nil { return err } if params.SystemFirmwareVersions != nil { if len(params.SystemFirmwareVersions) == 0 { var setsCount uint8 p := &SystemInfoParam_SystemFirmwareVersion{ SetSelector: 0, } if err := c.GetSystemInfoParamFor(ctx, p); canIgnore(err) != nil { return err } else { stringLength := uint8(p.BlockData[1]) setsCount = stringLength/16 + 1 } params.SystemFirmwareVersions = make([]*SystemInfoParam_SystemFirmwareVersion, setsCount) for i := uint8(0); i < setsCount; i++ { p := &SystemInfoParam_SystemFirmwareVersion{ SetSelector: i, } params.SystemFirmwareVersions[i] = p } } for _, param := range params.SystemFirmwareVersions { if err := c.GetSystemInfoParamFor(ctx, param); canIgnore(err) != nil { return err } } } if params.SystemNames != nil { if len(params.SystemNames) == 0 { var setsCount uint8 p := &SystemInfoParam_SystemName{ SetSelector: 0, } if err := c.GetSystemInfoParamFor(ctx, p); canIgnore(err) != nil { return err } else { stringLength := uint8(p.BlockData[1]) setsCount = stringLength/16 + 1 } params.SystemNames = make([]*SystemInfoParam_SystemName, setsCount) for i := uint8(0); i < setsCount; i++ { p := &SystemInfoParam_SystemName{ SetSelector: i, } params.SystemNames[i] = p } } for _, param := range params.SystemNames { if err := c.GetSystemInfoParamFor(ctx, param); canIgnore(err) != nil { return err } } } if params.PrimaryOSNames != nil { if len(params.PrimaryOSNames) == 0 { var setsCount uint8 p := &SystemInfoParam_PrimaryOSName{ SetSelector: 0, } if err := c.GetSystemInfoParamFor(ctx, p); canIgnore(err) != nil { return err } else { stringLength := uint8(p.BlockData[1]) setsCount = stringLength/16 + 1 } params.PrimaryOSNames = make([]*SystemInfoParam_PrimaryOSName, setsCount) for i := uint8(0); i < setsCount; i++ { p := &SystemInfoParam_PrimaryOSName{ SetSelector: i, } params.PrimaryOSNames[i] = p } } for _, param := range params.PrimaryOSNames { if err := c.GetSystemInfoParamFor(ctx, param); canIgnore(err) != nil { return err } } } if params.OSNames != nil { if len(params.OSNames) == 0 { var setsCount uint8 p := &SystemInfoParam_OSName{ SetSelector: 0, } if err := c.GetSystemInfoParamFor(ctx, p); canIgnore(err) != nil { return err } else { stringLength := uint8(p.BlockData[1]) setsCount = stringLength/16 + 1 } params.OSNames = make([]*SystemInfoParam_OSName, setsCount) for i := uint8(0); i < setsCount; i++ { p := &SystemInfoParam_OSName{ SetSelector: i, } params.OSNames[i] = p } } for _, param := range params.OSNames { if err := c.GetSystemInfoParamFor(ctx, param); canIgnore(err) != nil { return err } } } if params.OSVersions != nil { if len(params.OSVersions) == 0 { var setsCount uint8 p := &SystemInfoParam_OSVersion{ SetSelector: 0, } if err := c.GetSystemInfoParamFor(ctx, p); canIgnore(err) != nil { return err } else { stringLength := uint8(p.BlockData[1]) setsCount = stringLength/16 + 1 } params.OSVersions = make([]*SystemInfoParam_OSVersion, setsCount) for i := uint8(0); i < setsCount; i++ { p := &SystemInfoParam_OSVersion{ SetSelector: i, } params.OSVersions[i] = p } } for _, param := range params.OSVersions { if err := c.GetSystemInfoParamFor(ctx, param); canIgnore(err) != nil { return err } } } if params.BMCURLs != nil { if len(params.BMCURLs) == 0 { p := &SystemInfoParam_BMCURL{ SetSelector: 0, } if err := c.GetSystemInfoParamFor(ctx, p); canIgnore(err) != nil { return err } //stringDataType := uint8(p.BlockData[0]) stringLength := uint8(p.BlockData[1]) // string length 1-based setsCount := stringLength/16 + 1 params.BMCURLs = make([]*SystemInfoParam_BMCURL, setsCount) for i := uint8(0); i < setsCount; i++ { p := &SystemInfoParam_BMCURL{ SetSelector: i, } params.BMCURLs[i] = p } } for _, param := range params.BMCURLs { if err := c.GetSystemInfoParamFor(ctx, param); canIgnore(err) != nil { return err } } } if params.ManagementURLs != nil { if len(params.ManagementURLs) == 0 { p := &SystemInfoParam_ManagementURL{ SetSelector: 0, } if err := c.GetSystemInfoParamFor(ctx, p); canIgnore(err) != nil { return err } //stringDataType := uint8(p.BlockData[0]) stringLength := uint8(p.BlockData[1]) // string length 1-based setsCount := stringLength/16 + 1 params.ManagementURLs = make([]*SystemInfoParam_ManagementURL, setsCount) for i := uint8(0); i < setsCount; i++ { p := &SystemInfoParam_ManagementURL{ SetSelector: i, } params.ManagementURLs[i] = p } } for _, param := range params.ManagementURLs { if err := c.GetSystemInfoParamFor(ctx, param); canIgnore(err) != nil { return err } } } return nil } func (c *Client) GetSystemInfo(ctx context.Context) (*SystemInfo, error) { systemInfoParams, err := c.GetSystemInfoParams(ctx) if err != nil { return nil, fmt.Errorf("GetSystemInfo failed, err: %w", err) } return systemInfoParams.ToSystemInfo(), nil } func getSystemInfoStringMeta(params []interface{}) (s string, stringDataRaw []byte, stringDataType uint8, stringDataLength uint8) { if len(params) == 0 { return } array := make([]SystemInfoParameter, 0) for _, param := range params { v, ok := param.(SystemInfoParameter) if ok { array = append(array, v) } } allBlockData := make([]byte, 0) for _, p := range array { _, setSelector, _ := p.SystemInfoParameter() paramData := p.Pack() blockData := paramData[1:] if setSelector == 0 { stringDataType = blockData[0] stringDataLength = blockData[1] } allBlockData = append(allBlockData, blockData[:]...) } stringDataRaw = allBlockData[2 : stringDataLength+2] switch stringDataType { // 0h = ASCII+Latin1 // 1h = UTF-8 // 2h = UNICODE // all other = reserved. case 0x00: s = string(stringDataRaw) case 0x01: s = string(stringDataRaw) case 0x02: // here, suppose UTF-16 u16 := make([]uint16, len(stringDataRaw)/2) for i := 0; i < len(u16); i++ { u16[i] = binary.BigEndian.Uint16(stringDataRaw[i*2 : i*2+2]) } // Decode UTF-16 to UTF-8 runes := utf16.Decode(u16) s = string(runes) default: s = string(stringDataRaw) } return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_system_interface_capabilities.go000066400000000000000000000042271474110527100272010ustar00rootroot00000000000000package ipmi import "context" // 22.9 Get System Interface Capabilities Command type GetSystemInterfaceCapabilitiesRequest struct { SystemInterfaceType SystemInterfaceType } type GetSystemInterfaceCapabilitiesResponse struct { // For System Interface Type = SSIF TransactionSupportMask uint8 PECSupported bool SSIFVersion uint8 InputMessageSizeBytes uint8 OutputMessageSizeBytes uint8 // For System Interface Type = KCS or SMIC SystemInterfaceVersion uint8 InputMaximumMessageSizeBytes uint8 } type SystemInterfaceType uint8 const ( SystemInterfaceTypeSSIF SystemInterfaceType = 0x00 SystemInterfaceTypeKCS SystemInterfaceType = 0x01 SystemInterfaceTypeSMIC SystemInterfaceType = 0x02 ) func (req *GetSystemInterfaceCapabilitiesRequest) Command() Command { return CommandGetSystemInterfaceCapabilities } func (req *GetSystemInterfaceCapabilitiesRequest) Pack() []byte { return []byte{uint8(req.SystemInterfaceType)} } func (res *GetSystemInterfaceCapabilitiesResponse) Unpack(msg []byte) error { // at least 3 bytes if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } // For System Interface Type = SSIF: b, _, _ := unpackUint8(msg, 1) res.TransactionSupportMask = b >> 6 res.PECSupported = isBit3Set(b) res.SSIFVersion = b & 0x07 res.InputMessageSizeBytes, _, _ = unpackUint8(msg, 2) // For System Interface Type = KCS or SMIC res.SystemInterfaceVersion = b & 0x07 res.InputMaximumMessageSizeBytes, _, _ = unpackUint8(msg, 2) if len(msg) >= 4 { res.OutputMessageSizeBytes, _, _ = unpackUint8(msg, 3) } return nil } func (*GetSystemInterfaceCapabilitiesResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetSystemInterfaceCapabilitiesResponse) Format() string { return "" } func (c *Client) GetSystemInterfaceCapabilities(ctx context.Context, interfaceType SystemInterfaceType) (response *GetSystemInterfaceCapabilitiesResponse, err error) { request := &GetSystemInterfaceCapabilitiesRequest{ SystemInterfaceType: interfaceType, } response = &GetSystemInterfaceCapabilitiesResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_system_restart_cause.go000066400000000000000000000047061474110527100253760ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 28.11 Get System Restart Cause Command type GetSystemRestartCauseRequest struct { // empty } type GetSystemRestartCauseResponse struct { SystemRestartCause SystemRestartCause ChannelNumber uint8 } type SystemRestartCause uint8 var systemRestartCauses = map[SystemRestartCause]string{ 0x00: "unknown", // unknown (system start/restart detected, but cause unknown) 0x01: "chassis power control command", // 0x02: "reset via pushbutton", // 0x03: "power-up via pushbutton", // 0x04: "watchdog expired", // 0x05: "OEM", // 0x06: "power-up due to always-on restore power policy", // automatic power-up on AC being applied due to 'always restore' power restore policy 0x07: "power-up due to previous restore power policy", // automatic power-up on AC being applied due to 'restore previous power state' power restore policy 0x08: "reset via PEF", // 0x09: "power-cycle via PEF", // 0x0a: "soft reset", // soft reset (e.g. CTRL-ALT-DEL) [optional] 0x0b: "power-up via RTC wakeup", // power-up via RTC (system real time clock) wakeup [optional] } func (c SystemRestartCause) String() string { s, ok := systemRestartCauses[c] if ok { return s } return "invalid" } func (req *GetSystemRestartCauseRequest) Pack() []byte { return []byte{} } func (req *GetSystemRestartCauseRequest) Command() Command { return CommandGetSystemRestartCause } func (res *GetSystemRestartCauseResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetSystemRestartCauseResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } b, _, _ := unpackUint8(msg, 0) res.SystemRestartCause = SystemRestartCause(b) res.ChannelNumber, _, _ = unpackUint8(msg, 1) return nil } func (res *GetSystemRestartCauseResponse) Format() string { return fmt.Sprintf("System restart cause: %s", res.SystemRestartCause.String()) } func (c *Client) GetSystemRestartCause(ctx context.Context) (response *GetSystemRestartCauseResponse, err error) { request := &GetSystemRestartCauseRequest{} response = &GetSystemRestartCauseResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_user_access.go000066400000000000000000000116711474110527100234240ustar00rootroot00000000000000package ipmi import ( "bytes" "context" "fmt" "github.com/olekukonko/tablewriter" ) // 22.27 Get User Access Command type GetUserAccessRequest struct { ChannelNumber uint8 UserID uint8 } type GetUserAccessResponse struct { // Maximum number of User IDs. 1-based. Count includes User 1. A value of 1 // indicates only User 1 is supported. MaxUsersIDCount uint8 // [7:6] - User ID Enable status (for IPMI v2.0 errata 3 and later implementations). // 00b = User ID enable status unspecified. (For backward compatibility // with pre-errata 3 implementations. IPMI errata 3 and later // implementations should return the 01b and 10b responses.) // 01b = User ID enabled via Set User Password command. // 10b = User ID disabled via Set User Password command. // 11b = reserved EnableStatus uint8 // [5:0] - count of currently enabled user IDs on this channel (Indicates how // many User ID slots are presently in use.) EnabledUserIDsCount uint8 // Count of User IDs with fixed names, including User 1 (1-based). Fixed names // in addition to User 1 are required to be associated with sequential user IDs // starting from User ID 2. FixedNameUseIDsCount uint8 // [6] - 0b = user access available during call-in or callback direct connection // 1b = user access available only during callback connection CallbackOnly bool // [5] - 0b = user disabled for link authentication // 1b = user enabled for link authentication LinkAuthEnabled bool // [4] - 0b = user disabled for IPMI Messaging // 1b = user enabled for IPMI Messaging IPMIMessagingEnabled bool // [3:0] - User Privilege Limit for given Channel MaxPrivLevel PrivilegeLevel } func (req *GetUserAccessRequest) Command() Command { return CommandGetUserAccess } func (req *GetUserAccessRequest) Pack() []byte { return []byte{req.ChannelNumber, req.UserID} } func (res *GetUserAccessResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetUserAccessResponse) Unpack(msg []byte) error { if len(msg) < 4 { return ErrUnpackedDataTooShortWith(len(msg), 4) } res.MaxUsersIDCount, _, _ = unpackUint8(msg, 0) b1, _, _ := unpackUint8(msg, 1) res.EnableStatus = b1 & 0xc0 >> 6 res.EnabledUserIDsCount = b1 & 0x3f b2, _, _ := unpackUint8(msg, 2) res.FixedNameUseIDsCount = b2 & 0x3f b3, _, _ := unpackUint8(msg, 3) res.CallbackOnly = isBit6Set(b3) res.LinkAuthEnabled = isBit5Set(b3) res.IPMIMessagingEnabled = isBit4Set(b3) res.MaxPrivLevel = PrivilegeLevel(b3 & 0x0f) return nil } func (res *GetUserAccessResponse) Format() string { return fmt.Sprintf(`Maximum IDs : %d Enabled User Count : %d Fixed Name Count : %d `, res.MaxUsersIDCount, res.EnabledUserIDsCount, res.FixedNameUseIDsCount, ) } func (c *Client) GetUserAccess(ctx context.Context, channelNumber uint8, userID uint8) (response *GetUserAccessResponse, err error) { request := &GetUserAccessRequest{ ChannelNumber: channelNumber, UserID: userID, } response = &GetUserAccessResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) ListUser(ctx context.Context, channelNumber uint8) ([]*User, error) { var users = make([]*User, 0) var userID uint8 = 1 var username string for { res, err := c.GetUserAccess(ctx, channelNumber, userID) if err != nil { return nil, fmt.Errorf("get user for userID %d failed, err: %s", userID, err) } res2, err := c.GetUsername(ctx, userID) if err != nil { respErr, ok := err.(*ResponseError) if !ok || uint8(respErr.CompletionCode()) != 0xcc { return nil, fmt.Errorf("get user name for userID %d failed, err: %s", userID, err) } // Completion Code is 0xcc, means this UserID is not set. username = "" } else { username = res2.Username } user := &User{ ID: userID, Name: username, Callin: !res.CallbackOnly, LinkAuthEnabled: res.LinkAuthEnabled, IPMIMessagingEnabled: res.IPMIMessagingEnabled, MaxPrivLevel: res.MaxPrivLevel, } users = append(users, user) if userID >= res.MaxUsersIDCount { break } userID += 1 } return users, nil } type User struct { ID uint8 Name string Callin bool LinkAuthEnabled bool IPMIMessagingEnabled bool MaxPrivLevel PrivilegeLevel } func FormatUsers(users []*User) string { var buf = new(bytes.Buffer) table := tablewriter.NewWriter(buf) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) headers := []string{ "ID", "Name", "Callin", "Link Auth", "IPMI Msg", "Channel Priv Limit", } table.SetHeader(headers) table.SetFooter(headers) for _, user := range users { table.Append([]string{ fmt.Sprintf("%d", user.ID), user.Name, fmt.Sprintf("%v", user.Callin), fmt.Sprintf("%v", user.LinkAuthEnabled), fmt.Sprintf("%v", user.IPMIMessagingEnabled), user.MaxPrivLevel.String(), }) } table.Render() return buf.String() } golang-github-bougou-go-ipmi-0.7.2/cmd_get_username.go000066400000000000000000000021311474110527100227330ustar00rootroot00000000000000package ipmi import ( "bytes" "context" ) // 22.29 Get User Name Command type GetUsernameRequest struct { // [5:0] - User ID. 000000b = reserved. (User ID 1 is permanently associated with User 1, the null user name). UserID uint8 } type GetUsernameResponse struct { Username string } func (req *GetUsernameRequest) Command() Command { return CommandGetUsername } func (req *GetUsernameRequest) Pack() []byte { return []byte{req.UserID} } func (res *GetUsernameResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *GetUsernameResponse) Unpack(msg []byte) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } username, _, _ := unpackBytes(msg, 0, 16) res.Username = string(bytes.TrimRight(username, "\x00")) return nil } func (res *GetUsernameResponse) Format() string { return "" } func (c *Client) GetUsername(ctx context.Context, userID uint8) (response *GetUsernameResponse, err error) { request := &GetUsernameRequest{ UserID: userID, } response = &GetUsernameResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_get_watchdog_timer.go000066400000000000000000000066001474110527100241210ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 27.7 Get Watchdog Timer Command type GetWatchdogTimerRequest struct { // empty } func (req *GetWatchdogTimerRequest) Pack() []byte { return []byte{} } func (req *GetWatchdogTimerRequest) Command() Command { return CommandGetWatchdogTimer } type GetWatchdogTimerResponse struct { DontLog bool TimerIsStarted bool TimerUse TimerUse PreTimeoutInterrupt PreTimeoutInterrupt TimeoutAction TimeoutAction PreTimeoutIntervalSec uint8 ExpirationFlags uint8 InitialCountdown uint16 PresentCountdown uint16 } func (res *GetWatchdogTimerResponse) Unpack(msg []byte) error { if len(msg) < 8 { return ErrUnpackedDataTooShortWith(len(msg), 8) } res.DontLog = isBit7Set(msg[0]) res.TimerIsStarted = isBit6Set(msg[0]) res.TimerUse = TimerUse(0x07 & msg[0]) res.PreTimeoutInterrupt = PreTimeoutInterrupt((0x70 & msg[1]) >> 4) res.TimeoutAction = TimeoutAction(0x07 & msg[1]) res.PreTimeoutIntervalSec = msg[2] res.ExpirationFlags = msg[3] res.InitialCountdown, _, _ = unpackUint16L(msg, 4) res.PresentCountdown, _, _ = unpackUint16L(msg, 6) return nil } func (res *GetWatchdogTimerResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *GetWatchdogTimerResponse) Format() string { return fmt.Sprintf(`Watchdog Timer Use: %s (%#02x) Watchdog Timer Is: %s Watchdog Timer Actions: %s (%#02x) Pre-timeout interval: %d seconds Timer Expiration Flags: %#02x Initial Countdown: %d sec Present Countdown: %d sec`, res.TimerUse, uint8(res.TimerUse), formatBool(res.TimerIsStarted, "Started", "Stopped"), res.TimeoutAction, uint8(res.TimeoutAction), res.PreTimeoutIntervalSec, res.ExpirationFlags, res.InitialCountdown, res.PresentCountdown, ) } func (c *Client) GetWatchdogTimer(ctx context.Context) (response *GetWatchdogTimerResponse, err error) { request := &GetWatchdogTimerRequest{} response = &GetWatchdogTimerResponse{} err = c.Exchange(ctx, request, response) return } type TimerUse uint8 const ( TimerUseBIOSFRB2 TimerUse = 0x01 // BIOS/FRB2 TimerUseBIOSPOST TimerUse = 0x02 // BIOS/POST TimerUseOSLoad TimerUse = 0x03 TimerUseSMSOS TimerUse = 0x04 // SMS/OS TimerUseOEM TimerUse = 0x05 ) func (t TimerUse) String() string { m := map[TimerUse]string{ 0x01: "BIOS FRB2", 0x02: "BIOS/POST", 0x03: "OS Load", 0x04: "SMS/OS", 0x05: "OEM", } s, ok := m[t] if ok { return s } return "" } type PreTimeoutInterrupt uint8 const ( PreTimeoutInterruptNone PreTimeoutInterrupt = 0x00 PreTimeoutInterruptSMI PreTimeoutInterrupt = 0x01 PreTimeoutInterruptNMI PreTimeoutInterrupt = 0x02 PreTimeoutInterruptMessaging PreTimeoutInterrupt = 0x03 ) func (t PreTimeoutInterrupt) String() string { m := map[PreTimeoutInterrupt]string{ 0x00: "None", 0x01: "SMI", 0x02: "NMI / Diagnostic Interrupt", 0x03: "Messaging Interrupt", } s, ok := m[t] if ok { return s } return "" } type TimeoutAction uint8 const ( TimeoutActionNoAction TimeoutAction = 0x00 TimeoutActionHardReset TimeoutAction = 0x01 TimeoutActionPowerDown TimeoutAction = 0x02 TimeoutActionPowerCycle TimeoutAction = 0x03 ) func (t TimeoutAction) String() string { m := map[TimeoutAction]string{ 0x00: "No action", 0x01: "Hard Reset", 0x02: "Power Down", 0x03: "Power Cycle", } s, ok := m[t] if ok { return s } return "" } golang-github-bougou-go-ipmi-0.7.2/cmd_manufacturing_test_on.go000066400000000000000000000017201474110527100246560ustar00rootroot00000000000000package ipmi import "context" // 20.4 20.5 Manufacturing Test On Command type ManufacturingTestOnRequest struct { // empty } type ManufacturingTestOnResponse struct { // empty } func (req *ManufacturingTestOnRequest) Command() Command { return CommandManufacturingTestOn } func (req *ManufacturingTestOnRequest) Pack() []byte { return []byte{} } func (res *ManufacturingTestOnResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *ManufacturingTestOnResponse) Unpack(msg []byte) error { return nil } func (res *ManufacturingTestOnResponse) Format() string { // Todo return "" } // If the device supports a "manufacturing test mode", this command is reserved to turn that mode on. func (c *Client) ManufacturingTestOn(ctx context.Context) (response *ManufacturingTestOnResponse, err error) { request := &ManufacturingTestOnRequest{} response = &ManufacturingTestOnResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_master_write_read.go000066400000000000000000000036471474110527100237720ustar00rootroot00000000000000package ipmi import "context" // 22.11 Master Write-Read Command type MasterWriteReadRequest struct { // [7:4] channel number (Ignored when bus type = 1b) ChannelNumber uint8 // [3:1] bus ID, 0-based (always 000b for public bus [bus type = 0b]) BusID uint8 // [0] bus type: // - 0b = public (e.g. IPMB or PCI Management Bus. // The channel number value is used to select the target bus.) // - 1b = private bus (The bus ID value is used to select the target bus.) BusTypeIsPrivate bool SlaveAddress uint8 ReadCount uint8 // Data to write. This command should support at least 35 bytes of write data Data []byte } type MasterWriteReadResponse struct { // Bytes read from specified slave address. // This field will be absent if the read count is 0. // The controller terminates the I2C transaction with a STOP condition after reading the requested number of bytes. Data []byte } func (req *MasterWriteReadRequest) Command() Command { return CommandMasterWriteRead } func (req *MasterWriteReadRequest) Pack() []byte { out := make([]byte, 3+len(req.Data)) var b uint8 = req.ChannelNumber << 4 b |= (req.BusID << 1) & 0x0e if req.BusTypeIsPrivate { b = setBit0(b) } packUint8(b, out, 0) packUint8(req.SlaveAddress, out, 1) packUint8(req.ReadCount, out, 2) packBytes(req.Data, out, 3) return out } func (res *MasterWriteReadResponse) Unpack(msg []byte) error { res.Data, _, _ = unpackBytes(msg, 0, len(msg)) return nil } func (*MasterWriteReadResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "Lost Arbitration", 0x82: "Bus Error", 0x83: "NAK on Write", 0x84: "Truncated Read", } } func (res *MasterWriteReadResponse) Format() string { return "" } func (c *Client) MasterWriteRead(ctx context.Context, request *MasterWriteReadRequest) (*MasterWriteReadResponse, error) { response := &MasterWriteReadResponse{} err := c.Exchange(ctx, request, response) return response, err } golang-github-bougou-go-ipmi-0.7.2/cmd_open_session.go000066400000000000000000000203411474110527100227640ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 13.17 RMCP+ Open Session Request type OpenSessionRequest struct { MessageTag uint8 RequestedMaximumPrivilegeLevel PrivilegeLevel RemoteConsoleSessionID uint32 AuthenticationPayload IntegrityPayload ConfidentialityPayload } // 13.18 RMCP+ Open Session Response type OpenSessionResponse struct { // The BMC returns the Message Tag value that was passed by the remote console in the Open Session Request message. MessageTag uint8 // Identifies the status of the previous message. // If the previous message generated an error, then only the Status Code, Reserved, and Remote Console Session ID fields are returned. RmcpStatusCode RmcpStatusCode MaximumPrivilegeLevel uint8 RemoteConsoleSessionID uint32 ManagedSystemSessionID uint32 AuthenticationPayload IntegrityPayload ConfidentialityPayload } type AuthenticationPayload struct { // 00h = authentication algorithm PayloadType uint8 PayloadLength uint8 // Payload Length in bytes (1-based). The total length in bytes of the payload including the header (= 08h for this specification). AuthAlg uint8 } type IntegrityPayload struct { // 01h = integrity algorithm PayloadType uint8 PayloadLength uint8 IntegrityAlg uint8 } type ConfidentialityPayload struct { // 02h = confidentiality algorithm PayloadType uint8 PayloadLength uint8 CryptAlg uint8 } const ( RmcpOpenSessionRequestSize int = 32 RmcpOpenSessionResponseSize int = 36 RmcpOpenSessionResponseMinSize int = 8 ) func (req *OpenSessionRequest) Command() Command { return CommandNone } func (req *OpenSessionRequest) Pack() []byte { var out = make([]byte, RmcpOpenSessionRequestSize) packUint8(req.MessageTag, out, 0) packUint8(uint8(req.RequestedMaximumPrivilegeLevel), out, 1) packUint16(0, out, 2) // 2 bytes reserved packUint32L(req.RemoteConsoleSessionID, out, 4) packBytes(req.AuthenticationPayload.Pack(), out, 8) packBytes(req.IntegrityPayload.Pack(), out, 16) packBytes(req.ConfidentialityPayload.Pack(), out, 24) return out } func (res *OpenSessionResponse) Unpack(data []byte) error { if len(data) < RmcpOpenSessionResponseMinSize { return ErrUnpackedDataTooShortWith(len(data), RmcpOpenSessionResponseMinSize) } res.MessageTag, _, _ = unpackUint8(data, 0) b1, _, _ := unpackUint8(data, 1) res.RmcpStatusCode = RmcpStatusCode(b1) res.MaximumPrivilegeLevel, _, _ = unpackUint8(data, 2) // reserved res.RemoteConsoleSessionID, _, _ = unpackUint32L(data, 4) // If the previous message generated an error, then only the Status Code, Reserved, and Remote Console Session ID fields are returned. // See Table 13-, RMCP+ and RAKP Message Status Codes. // The session establishment in progress is discarded at the BMC, and the // remote console will need to start over with a new Open Session Request message. // (Since the BMC has not yet delivered a Managed System Session ID to the remote console, // it shouldn't be carrying any state information from the prior Open Session Request, // but if it has, that state should be discarded.) if res.RmcpStatusCode != RmcpStatusCodeNoErrors { return nil } if len(data) < RmcpOpenSessionResponseSize { return ErrUnpackedDataTooShortWith(len(data), RmcpOpenSessionResponseSize) } res.ManagedSystemSessionID, _, _ = unpackUint32L(data, 8) res.AuthenticationPayload.Unpack(data[12:20]) res.IntegrityPayload.Unpack(data[20:28]) res.ConfidentialityPayload.Unpack(data[28:36]) return nil } func (*OpenSessionResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *OpenSessionResponse) Format() string { return fmt.Sprintf(` Message tag : %#02x RMCP+ status : %#02x %s Maximum privilege level : %#02x %s Console Session ID : %#0x BMC Session ID : %#0x Negotiated authentication algorithm : %#02x %s Negotiated integrity algorithm : %#02x %s Negotiated encryption algorithm : %#02x %s`, res.MessageTag, res.RmcpStatusCode, RmcpStatusCode(res.RmcpStatusCode), res.MaximumPrivilegeLevel, PrivilegeLevel(res.MaximumPrivilegeLevel), res.RemoteConsoleSessionID, res.ManagedSystemSessionID, res.AuthAlg, AuthAlg(res.AuthAlg), res.IntegrityAlg, IntegrityAlg(res.IntegrityAlg), res.CryptAlg, CryptAlg(res.CryptAlg), ) } func (c *Client) OpenSession(ctx context.Context) (response *OpenSessionResponse, err error) { cipherSuiteID := c.session.v20.cipherSuiteID authAlg, integrityAlg, cryptAlg, err := getCipherSuiteAlgorithms(cipherSuiteID) if err != nil { return nil, fmt.Errorf("get cipher suite for id %v failed, err: %s", cipherSuiteID, err) } c.session.v20.requestedAuthAlg = authAlg c.session.v20.requestedIntegrityAlg = integrityAlg c.session.v20.requestedEncryptAlg = cryptAlg // Choose our session ID for easy recognition in the packet dump var remoteConsoleSessionID uint32 = 0xa0a1a2a3 request := &OpenSessionRequest{ MessageTag: 0x00, RequestedMaximumPrivilegeLevel: 0, // Request the highest level matching proposed algorithms RemoteConsoleSessionID: remoteConsoleSessionID, AuthenticationPayload: AuthenticationPayload{ PayloadType: 0x00, // 0 means authentication algorithm PayloadLength: 8, AuthAlg: uint8(c.session.v20.requestedAuthAlg), }, IntegrityPayload: IntegrityPayload{ PayloadType: 0x01, // 1 means integrity algorithm PayloadLength: 8, IntegrityAlg: uint8(c.session.v20.requestedIntegrityAlg), }, ConfidentialityPayload: ConfidentialityPayload{ PayloadType: 0x02, // 2 means confidentiality algorithm PayloadLength: 8, CryptAlg: uint8(c.session.v20.requestedEncryptAlg), }, } response = &OpenSessionResponse{} c.session.v20.state = SessionStateOpenSessionSent err = c.Exchange(ctx, request, response) if err != nil { return nil, fmt.Errorf("client exchange failed, err: %w", err) } c.Debug("OPEN SESSION RESPONSE", response.Format()) if response.RmcpStatusCode != RmcpStatusCodeNoErrors { err = fmt.Errorf("rakp status code error: (%#02x) %s", uint8(response.RmcpStatusCode), response.RmcpStatusCode) return } c.session.v20.state = SessionStateOpenSessionReceived c.session.v20.authAlg = AuthAlg(response.AuthAlg) c.session.v20.integrityAlg = IntegrityAlg(response.IntegrityAlg) c.session.v20.cryptAlg = CryptAlg(response.CryptAlg) c.session.v20.consoleSessionID = response.RemoteConsoleSessionID c.session.v20.bmcSessionID = response.ManagedSystemSessionID return } func (p *AuthenticationPayload) Pack() []byte { out := make([]byte, 8) packUint8(p.PayloadType, out, 0) packUint16(0, out, 1) // 2 bytes reserved packUint8(p.PayloadLength, out, 3) packUint8(p.AuthAlg, out, 4) packUint24(0, out, 5) // 3 bytes reserved return out } func (p *AuthenticationPayload) Unpack(msg []byte) error { if len(msg) < 8 { return ErrUnpackedDataTooShortWith(len(msg), 8) } p.PayloadType, _, _ = unpackUint8(msg, 0) // 2 bytes reserved p.PayloadLength, _, _ = unpackUint8(msg, 3) p.AuthAlg, _, _ = unpackUint8(msg, 4) // 3 bytes reserved return nil } func (p *IntegrityPayload) Pack() []byte { out := make([]byte, 8) packUint8(p.PayloadType, out, 0) packUint16(0, out, 1) // 2 bytes reserved packUint8(p.PayloadLength, out, 3) packUint8(p.IntegrityAlg, out, 4) packUint24(0, out, 5) // 3 bytes reserved return out } func (p *IntegrityPayload) Unpack(msg []byte) error { if len(msg) < 8 { return ErrUnpackedDataTooShortWith(len(msg), 8) } p.PayloadType, _, _ = unpackUint8(msg, 0) // 2 bytes reserved p.PayloadLength, _, _ = unpackUint8(msg, 3) p.IntegrityAlg, _, _ = unpackUint8(msg, 4) // 3 bytes reserved return nil } func (p *ConfidentialityPayload) Pack() []byte { out := make([]byte, 8) packUint8(p.PayloadType, out, 0) packUint16(0, out, 1) // 2 bytes reserved packUint8(p.PayloadLength, out, 3) packUint8(p.CryptAlg, out, 4) packUint24(0, out, 5) // 3 bytes reserved return out } func (p *ConfidentialityPayload) Unpack(msg []byte) error { if len(msg) < 8 { return ErrUnpackedDataTooShortWith(len(msg), 8) } p.PayloadType, _, _ = unpackUint8(msg, 0) // 2 bytes reserved p.PayloadLength, _, _ = unpackUint8(msg, 3) p.CryptAlg, _, _ = unpackUint8(msg, 4) // 3 bytes reserved return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_pet_acknowledge.go000066400000000000000000000040321474110527100234120ustar00rootroot00000000000000package ipmi import "context" // 30.8 PET Acknowledge Command // This message is used to acknowledge a Platform Event Trap (PET) alert. type PETAcknowledgeRequest struct { SequenceNumber uint16 LocalTimestamp uint32 EventSourceType uint8 SensorDevice uint8 SensorNumber uint8 EventData EventData } type PETAcknowledgeResponse struct { PETAcknowledgeStatus uint8 } func (req *PETAcknowledgeRequest) Pack() []byte { out := make([]byte, 12) packUint16L(req.SequenceNumber, out, 0) packUint32L(req.LocalTimestamp, out, 2) out[6] = req.EventSourceType out[7] = req.SensorDevice out[8] = req.SensorNumber out[9] = uint8(req.EventData.EventData1) out[10] = uint8(req.EventData.EventData2) out[11] = uint8(req.EventData.EventData3) return out } func (req *PETAcknowledgeRequest) Unpack(data []byte) error { if len(data) < 12 { return ErrUnpackedDataTooShortWith(len(data), 12) } req.SequenceNumber, _, _ = unpackUint16L(data, 0) req.LocalTimestamp, _, _ = unpackUint32L(data, 2) req.EventSourceType = data[6] req.SensorDevice = data[7] req.SensorNumber = data[8] req.EventData.EventData1 = data[9] req.EventData.EventData2 = data[10] req.EventData.EventData3 = data[11] return nil } func (req *PETAcknowledgeRequest) Command() Command { return CommandPETAcknowledge } func (res *PETAcknowledgeResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "Alert Immediate rejected due to alert already in progress", 0x82: "Alert Immediate rejected due to IPMI messaging session active on this channel", 0x83: "Platform Event Parameters (4:11) not supported", } } func (res *PETAcknowledgeResponse) Unpack(msg []byte) error { return nil } func (res *PETAcknowledgeResponse) Pack() []byte { return []byte{} } func (res *PETAcknowledgeResponse) Format() string { return "" } func (c *Client) PETAcknowledge(ctx context.Context, request *PETAcknowledgeRequest) (response *PETAcknowledgeResponse, err error) { response = &PETAcknowledgeResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_platform_event_message.go000066400000000000000000000041501474110527100250110ustar00rootroot00000000000000package ipmi import "context" // 29.3 Platform Event Message Command type PlatformEventMessageRequest struct { // The Generator ID field is a required element of an Event Request Message. // This field identifies the device that has generated the Event Message. // This is the 7-bit Requester's Slave Address (RqSA) and 2-bit Requester's LUN (RqLUN) // if the message was received from the IPMB, or the 7-bit System Software ID // if the message was received from system software. // // For IPMB messages, this field is equated to the Requester's Slave Address and LUN fields. // Thus, the Generator ID information is not carried in the data field of an IPMB request message. // // For 'system side' interfaces, it is not as useful or appropriate to 'overlay' the Generator ID field // with the message source address information, and so it is specified as being carried in the data field of the request. GeneratorID uint8 EvMRev uint8 SensorType uint8 SensorNumber uint8 EventDir EventDir EventType EventReadingType EventData EventData } type PlatformEventMessageResponse struct { } func (req *PlatformEventMessageRequest) Pack() []byte { out := make([]byte, 8) out[0] = req.GeneratorID out[1] = req.EvMRev out[2] = req.SensorType out[3] = req.SensorNumber var b4 = uint8(req.EventType) if req.EventDir { b4 |= 0x80 } out[4] = b4 out[5] = req.EventData.EventData1 out[6] = req.EventData.EventData2 out[7] = req.EventData.EventData3 return []byte{} } func (req *PlatformEventMessageRequest) Command() Command { return CommandPlatformEventMessage } func (res *PlatformEventMessageResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *PlatformEventMessageResponse) Unpack(msg []byte) error { return nil } func (res *PlatformEventMessageResponse) Format() string { return "" } func (c *Client) PlatformEventMessage(ctx context.Context, request *PlatformEventMessageRequest) (response *PlatformEventMessageResponse, err error) { // Todo, consider GeneratorID response = &PlatformEventMessageResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_rakp_message_1_2.go000066400000000000000000000157361474110527100233760ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) const IPMI_MAX_USER_NAME_LENGTH = 16 const IPMI_RAKP1_MESSAGE_SIZE = 44 // 13.20 RAKP Message 1 type RAKPMessage1 struct { MessageTag uint8 // The Managed System's Session ID for this session, returned by the Managed System on the // previous RMCP+ Open Session Response message. ManagedSystemSessionID uint32 // 16 bytes RemoteConsoleRandomNumber [16]byte // bit 4 // 0b = Username/Privilege lookup. // 1b = Name-only lookup. NameOnlyLookup bool RequestedMaximumPrivilegeLevel PrivilegeLevel UsernameLength uint8 Username []byte } type RAKPMessage2 struct { // authAlg describes the authentication algorithm was agreed upon in // the open session request/response phase. // We need to know that here so that we know how many bytes (if any) to read from the packet for KeyExchangeAuthenticationCode authAlg AuthAlg MessageTag uint8 // RMCP+ Status Code - Identifies the status of the previous message. // // If the previous message generated an error, then only the Completion Code, Reserved, and // Remote Console Session ID fields are returned. // // If the Remote Console Session ID field is indeterminate // (as would be the case if the Managed System Session ID in RAKP Message 1 were invalid) // then the Remote Console Session ID field will be set to all zeros. // // On error, the remote console can attempt to correct the error and send a new RAKP Message 1. // // Note that the remote console must change the Message Tag value to ensure the BMC sees the message as a new message and not as a retry. // // See Table 13-15, RMCP+ and RAKP Message Status Codes for the status codes defined for this message. RmcpStatusCode RmcpStatusCode // The Remote Console Session ID specified by the RMCP+ Open Session Request message associated with this response. RemoteConsoleSessionID uint32 // Random number generated/selected by the managed system. ManagedSystemRandomNumber [16]byte // The Globally Unique ID (GUID) of the Managed System. // This value is typically specified by the client system's SMBIOS implementation. See // 22.14, Get System GUID Command, for additional information ManagedSystemGUID [16]byte // An integrity check value over the relevant items specified by the RAKP algorithm for RAKP Message 2. // The size of this field depends on the specific Authentication Algorithm // This field may be 0-bytes (absent) for some algorithms (e.g. RAKP-none). // // see 13.31 for how the managed system generate this HMAC KeyExchangeAuthenticationCode []byte } func (req *RAKPMessage1) Command() Command { return CommandNone } func (r *RAKPMessage1) Pack() []byte { var msg = make([]byte, 28+len(r.Username)) packUint8(r.MessageTag, msg, 0) packUint24L(0, msg, 1) // 3 bytes reserved packUint32L(r.ManagedSystemSessionID, msg, 4) packBytes((r.RemoteConsoleRandomNumber[:]), msg, 8) packUint8(r.Role(), msg, 24) packUint16L(0, msg, 25) // 2 bytes reserved packUint8(r.UsernameLength, msg, 27) packBytes(r.Username, msg, 28) return msg } // the combination of RequestedMaximumPrivilegeLevel and NameOnlyLookup field // The whole byte should be stored to client session for computing auth code of rakp2 func (r *RAKPMessage1) Role() uint8 { privilegeLevel := uint8(r.RequestedMaximumPrivilegeLevel) if r.NameOnlyLookup { privilegeLevel = setBit4(privilegeLevel) } return privilegeLevel } func (res *RAKPMessage2) Unpack(msg []byte) error { // If RAKPMessage1 failed to be validated, the returned RAKPMessage2 only holds 8 bytes. if len(msg) < 8 { return ErrUnpackedDataTooShortWith(len(msg), 8) } res.MessageTag = msg[0] res.RmcpStatusCode = RmcpStatusCode(msg[1]) // 2 bytes reserved res.RemoteConsoleSessionID, _, _ = unpackUint32L(msg, 4) // Now we can check whether RmcpStatusCode indicates error if res.RmcpStatusCode != RmcpStatusCodeNoErrors { return fmt.Errorf("the return status of rakp2 has error: %v", res.RmcpStatusCode) } if len(msg) < 40 { return ErrUnpackedDataTooShortWith(len(msg), 40) } res.ManagedSystemRandomNumber = array16(msg[8:24]) res.ManagedSystemGUID = array16(msg[24:40]) var authCodeLen int = 0 switch res.authAlg { case AuthAlgRAKP_None: break case AuthAlgRAKP_HMAC_MD5: authCodeLen = 16 case AuthAlgRAKP_HMAC_SHA1: authCodeLen = 20 case AuthAlgRAKP_HMAC_SHA256: authCodeLen = 32 } if len(msg) < 40+authCodeLen { return fmt.Errorf("the unpacked data does not contain enough auth code") } res.KeyExchangeAuthenticationCode = make([]byte, authCodeLen) copy(res.KeyExchangeAuthenticationCode, msg[40:40+authCodeLen]) return nil } func (*RAKPMessage2) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *RAKPMessage2) Format() string { return fmt.Sprintf("%v", res) } // ValidateRAKP2 validates RAKPMessage2 returned by BMC. func (c *Client) ValidateRAKP2(ctx context.Context, rakp2 *RAKPMessage2) (bool, error) { if c.session.v20.consoleSessionID != rakp2.RemoteConsoleSessionID { return false, fmt.Errorf("session id not matched, cached console session id: %x, rakp2 returned session id: %x", c.session.v20.consoleSessionID, rakp2.RemoteConsoleSessionID) } // rakp2 authcode is valid authcode, err := c.generate_rakp2_authcode() if err != nil { return false, fmt.Errorf("generate rakp2 authcode failed, err: %w", err) } c.DebugBytes("rakp2 returned auth code", rakp2.KeyExchangeAuthenticationCode, 16) if !isByteSliceEqual(authcode, rakp2.KeyExchangeAuthenticationCode) { return false, fmt.Errorf("rakp2 authcode not equal, console: %x, bmc: %x", authcode, rakp2.KeyExchangeAuthenticationCode) } return true, nil } func (c *Client) RAKPMessage1(ctx context.Context) (response *RAKPMessage2, err error) { c.session.v20.consoleRand = array16(randomBytes(16)) c.DebugBytes("console generate console random number", c.session.v20.consoleRand[:], 16) request := &RAKPMessage1{ MessageTag: 0, ManagedSystemSessionID: c.session.v20.bmcSessionID, // set by previous RMCP+ Open Session Request RemoteConsoleRandomNumber: c.session.v20.consoleRand, RequestedMaximumPrivilegeLevel: c.maxPrivilegeLevel, NameOnlyLookup: true, UsernameLength: uint8(len(c.Username)), Username: []byte(c.Username), } c.session.v20.role = request.Role() response = &RAKPMessage2{ authAlg: c.session.v20.authAlg, } c.session.v20.state = SessionStateRakp1Sent err = c.Exchange(ctx, request, response) if err != nil { return nil, err } // the following fields must be set before generate_sik/generate_k1/generate_k2 c.session.v20.rakp2ReturnCode = uint8(response.RmcpStatusCode) c.session.v20.bmcGUID = response.ManagedSystemGUID c.session.v20.bmcRand = response.ManagedSystemRandomNumber // will be used in rakp3 to generate authCode if _, err = c.ValidateRAKP2(ctx, response); err != nil { err = fmt.Errorf("validate rakp2 message failed, err: %w", err) return } c.session.v20.state = SessionStateRakp2Received return } golang-github-bougou-go-ipmi-0.7.2/cmd_rakp_message_3_4.go000066400000000000000000000117651474110527100234000ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 13.22 RAKP Message 3 type RAKPMessage3 struct { // Selected by remote console. Used by remote console to help match // responses up with requests. MessageTag uint8 // Identifies the status of the previous message. RmcpStatusCode RmcpStatusCode // The Managed System's Session ID for this session, returned by the managed system on the previous RMCP+ Open Session Response message. ManagedSystemSessionID uint32 // An integrity check value over the relevant items specified by the RAKP // authentication algorithm identified in RAKP Message 1. // The size of this field depends on the specific authentication algorithm. // // This field may be 0 bytes (absent) for some algorithms (e.g. RAKP-none). KeyExchangeAuthenticationCode []byte } type RAKPMessage4 struct { authAlg AuthAlg MessageTag uint8 RmcpStatusCode RmcpStatusCode MgmtConsoleSessionID uint32 // An integrity check value over the relevant items specified by // the RAKP authentication algorithm that was identified in RAKP Message 1. // // The size of this field depends on the specific authentication algorithm. // // For example, the RAKP-HMAC-SHA1 specifies that an HMACSHA1-96 algorithm be used for calculating this field. // See Section 13.28 // Authentication, Integrity, and Confidentiality Algorithm Numbers for info on // the algorithm to be used for this field. // // This field may be 0 bytes (absent) for some authentication algorithms (e.g. RAKP-none) IntegrityCheckValue []byte } func (req *RAKPMessage3) Command() Command { return CommandNone } func (req *RAKPMessage3) Pack() []byte { var msg = make([]byte, 8+len(req.KeyExchangeAuthenticationCode)) packUint8(req.MessageTag, msg, 0) packUint8(uint8(req.RmcpStatusCode), msg, 1) packUint16(0, msg, 2) // reserved packUint32L(req.ManagedSystemSessionID, msg, 4) packBytes(req.KeyExchangeAuthenticationCode, msg, 8) return msg } func (res *RAKPMessage4) Unpack(msg []byte) error { authCodeLen := 0 switch res.authAlg { case AuthAlgRAKP_None: // nothing need to do case AuthAlgRAKP_HMAC_MD5: // need to copy 16 bytes authCodeLen = 16 case AuthAlgRAKP_HMAC_SHA1: // need to copy 12 bytes authCodeLen = 12 case AuthAlgRAKP_HMAC_SHA256: authCodeLen = 16 default: } if len(msg) < 8+authCodeLen { return ErrUnpackedDataTooShortWith(len(msg), 8+authCodeLen) } res.MessageTag, _, _ = unpackUint8(msg, 0) b1, _, _ := unpackUint8(msg, 1) res.RmcpStatusCode = RmcpStatusCode(b1) res.MgmtConsoleSessionID, _, _ = unpackUint32L(msg, 4) res.IntegrityCheckValue, _, _ = unpackBytes(msg, 8, authCodeLen) return nil } func (*RAKPMessage4) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *RAKPMessage4) Format() string { return fmt.Sprintf("%v", res) } // authAlg is used to parse the returned RAKPMessage4 message func (c *Client) RAKPMessage3(ctx context.Context) (response *RAKPMessage4, err error) { // create session integrity key sik, err := c.generate_sik() if err != nil { err = fmt.Errorf("generate sik failed, err: %w", err) return } c.session.v20.sik = sik k1, err := c.generate_k1() if err != nil { err = fmt.Errorf("generate k1 failed, err: %w", err) return } c.session.v20.k1 = k1 k2, err := c.generate_k2() if err != nil { err = fmt.Errorf("generate k2 failed, err: %w", err) return } c.session.v20.k2 = k2 authCode, err := c.generate_rakp3_authcode() if err != nil { return nil, fmt.Errorf("generate rakp3 auth code failed, err: %w", err) } request := &RAKPMessage3{ MessageTag: 0, RmcpStatusCode: RmcpStatusCode(c.session.v20.rakp2ReturnCode), ManagedSystemSessionID: c.session.v20.bmcSessionID, KeyExchangeAuthenticationCode: authCode, } response = &RAKPMessage4{ authAlg: c.session.v20.authAlg, } c.session.v20.state = SessionStateRakp3Sent err = c.Exchange(ctx, request, response) if err != nil { return nil, err } if _, err = c.ValidateRAKP4(ctx, response); err != nil { return nil, fmt.Errorf("validate rakp4 failed, err: %w", err) } c.session.v20.state = SessionStateActive return response, nil } func (c *Client) ValidateRAKP4(ctx context.Context, response *RAKPMessage4) (bool, error) { if response.RmcpStatusCode != RmcpStatusCodeNoErrors { return false, fmt.Errorf("rakp4 status code not ok, %x", response.RmcpStatusCode) } // verify if c.session.v20.consoleSessionID != response.MgmtConsoleSessionID { return false, fmt.Errorf("session not activated") } authCode, err := c.generate_rakp4_authcode() if err != nil { return false, fmt.Errorf("generate rakp4 auth code failed, err: %w", err) } c.DebugBytes("rakp4 console computed authcode", authCode, 16) c.DebugBytes("rakp4 bmc returned authcode", response.IntegrityCheckValue, 16) if !isByteSliceEqual(response.IntegrityCheckValue, authCode) { return false, fmt.Errorf("rakp4 returned integrity check not passed, console mac %0x, bmc mac: %0x", authCode, response.IntegrityCheckValue) } return true, nil } golang-github-bougou-go-ipmi-0.7.2/cmd_raw.go000066400000000000000000000024561474110527100210600ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "strings" ) type CommandRawRequest struct { NetFn NetFn Cmd uint8 Data []byte Name string } type CommandRawResponse struct { Response []byte } func (req *CommandRawRequest) Command() Command { return Command{ID: req.Cmd, NetFn: req.NetFn, Name: req.Name} } func (req *CommandRawRequest) Pack() []byte { out := make([]byte, len(req.Data)) packBytes(req.Data, out, 0) return out } func (res *CommandRawResponse) Unpack(msg []byte) error { res.Response = msg return nil } func (res *CommandRawResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *CommandRawResponse) Format() string { // convert the byte array to a slice of hex strings hexStrings := make([]string, len(res.Response)) for i, b := range res.Response { hexStrings[i] = fmt.Sprintf("0x%02X", b) } // join the hex strings with commas hexString := strings.Join(hexStrings, ", ") return fmt.Sprintf(`raw.Response = %s`, hexString) } func (c *Client) RawCommand(ctx context.Context, netFn NetFn, cmd uint8, data []byte, name string) (response *CommandRawResponse, err error) { request := &CommandRawRequest{ NetFn: netFn, Cmd: cmd, Data: data, Name: name, } response = &CommandRawResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_read_event_message_buffer.go000066400000000000000000000021721474110527100254330ustar00rootroot00000000000000package ipmi import "context" // 22.8 Read Event Message Buffer Command type ReadEventMessageBufferRequest struct { // empty } type ReadEventMessageBufferResponse struct { // 16 bytes of data in SEL Record format MessageData [16]byte } func (req ReadEventMessageBufferRequest) Command() Command { return CommandReadEventMessageBuffer } func (req *ReadEventMessageBufferRequest) Pack() []byte { return []byte{} } func (res *ReadEventMessageBufferResponse) Unpack(msg []byte) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } b, _, _ := unpackBytes(msg, 0, 16) res.MessageData = array16(b) return nil } func (*ReadEventMessageBufferResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: " data not available (queue / buffer empty)", } } func (res *ReadEventMessageBufferResponse) Format() string { return "" } func (c *Client) ReadEventMessageBuffer(ctx context.Context) (response *ReadEventMessageBufferResponse, err error) { request := &ReadEventMessageBufferRequest{} response = &ReadEventMessageBufferResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_read_fru_data.go000066400000000000000000000065771474110527100230570ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 34.2 Read FRU Data Command type ReadFRUDataRequest struct { FRUDeviceID uint8 ReadOffset uint16 ReadCount uint8 } type ReadFRUDataResponse struct { CountReturned uint8 Data []byte } func (req *ReadFRUDataRequest) Command() Command { return CommandReadFRUData } func (req *ReadFRUDataRequest) Pack() []byte { out := make([]byte, 4) packUint8(req.FRUDeviceID, out, 0) packUint16L(req.ReadOffset, out, 1) packUint8(req.ReadCount, out, 3) return out } func (res *ReadFRUDataResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } res.CountReturned, _, _ = unpackUint8(msg, 0) res.Data, _, _ = unpackBytes(msg, 1, len(msg)-1) return nil } func (r *ReadFRUDataResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "FRU device busy", } } func (res *ReadFRUDataResponse) Format() string { return fmt.Sprintf(`Count returned : %d Data : %02x`, res.CountReturned, res.Data, ) } // The command returns the specified data from the FRU Inventory Info area. func (c *Client) ReadFRUData(ctx context.Context, fruDeviceID uint8, readOffset uint16, readCount uint8) (response *ReadFRUDataResponse, err error) { request := &ReadFRUDataRequest{ FRUDeviceID: fruDeviceID, ReadOffset: readOffset, ReadCount: readCount, } response = &ReadFRUDataResponse{} err = c.Exchange(ctx, request, response) return } // readFRUDataByLength reads FRU Data in loop until reaches the specified data length func (c *Client) readFRUDataByLength(ctx context.Context, deviceID uint8, offset uint16, length uint16) ([]byte, error) { var data []byte c.Debugf("Read FRU Data by Length, offset: (%d), length: (%d)\n", offset, length) for { if length <= 0 { break } res, err := c.tryReadFRUData(ctx, deviceID, offset, length) if err != nil { return nil, fmt.Errorf("tryReadFRUData failed, err: %w", err) } c.Debug("", res.Format()) data = append(data, res.Data...) length -= uint16(res.CountReturned) c.Debugf("left length: %d\n", length) // update offset offset += uint16(res.CountReturned) } return data, nil } // tryReadFRUData will try to read FRU data with a read count which starts with // the minimal number of the specified length and the hard-coded 32, if the // ReadFRUData failed, it try another request with a decreased read count. func (c *Client) tryReadFRUData(ctx context.Context, deviceID uint8, readOffset uint16, length uint16) (response *ReadFRUDataResponse, err error) { var readCount uint8 = 32 if length <= uint16(readCount) { readCount = uint8(length) } for { if readCount <= 0 { return nil, fmt.Errorf("nothing to read") } c.Debugf("Try Read FRU Data, offset: (%d), count: (%d)\n", readOffset, readCount) res, err := c.ReadFRUData(ctx, deviceID, readOffset, readCount) if err == nil { return res, nil } resErr, ok := err.(*ResponseError) if !ok { return nil, fmt.Errorf("ReadFRUData failed, err: %w", err) } cc := resErr.CompletionCode() if readFRUDataLength2Big(cc) { readCount -= 1 continue } else { return nil, fmt.Errorf("ReadFRUData failed, err: %w", err) } } } func readFRUDataLength2Big(cc CompletionCode) bool { return cc == CompletionCodeRequestDataLengthInvalid || cc == CompletionCodeRequestDataLengthLimitExceeded || cc == CompletionCodeCannotReturnRequestedDataBytes } golang-github-bougou-go-ipmi-0.7.2/cmd_reserve_device_sdr_repo.go000066400000000000000000000020501474110527100251440ustar00rootroot00000000000000package ipmi import "context" // 35.4 Reserve Device SDR Repository Command type ReserveDeviceSDRRepoRequest struct { // empty } type ReserveDeviceSDRRepoResponse struct { ReservationID uint16 } func (req *ReserveDeviceSDRRepoRequest) Command() Command { return CommandReserveDeviceSDRRepo } func (req *ReserveDeviceSDRRepoRequest) Pack() []byte { return []byte{} } func (res *ReserveDeviceSDRRepoResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.ReservationID, _, _ = unpackUint16L(msg, 0) return nil } func (r *ReserveDeviceSDRRepoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *ReserveDeviceSDRRepoResponse) Format() string { return "" } // This command is used to obtain a Reservation ID. func (c *Client) ReserveDeviceSDRRepo(ctx context.Context) (response *ReserveDeviceSDRRepoResponse, err error) { request := &ReserveDeviceSDRRepoRequest{} response = &ReserveDeviceSDRRepoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_reserve_sdr_repo.go000066400000000000000000000016461474110527100236370ustar00rootroot00000000000000package ipmi import "context" // 33.11 Reserve SDR Repository Command type ReserveSDRRepoRequest struct { // empty } type ReserveSDRRepoResponse struct { ReservationID uint16 } func (req *ReserveSDRRepoRequest) Command() Command { return CommandReserveSDRRepo } func (req *ReserveSDRRepoRequest) Pack() []byte { return []byte{} } func (res *ReserveSDRRepoResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.ReservationID, _, _ = unpackUint16L(msg, 0) return nil } func (r *ReserveSDRRepoResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *ReserveSDRRepoResponse) Format() string { return "" } func (c *Client) ReserveSDRRepo(ctx context.Context) (response *ReserveSDRRepoResponse, err error) { request := &ReserveSDRRepoRequest{} response = &ReserveSDRRepoResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_reserve_sel.go000066400000000000000000000016701474110527100226020ustar00rootroot00000000000000package ipmi import "context" // 31.4 Reserve SEL Command type ReserveSELRequest struct { // empty } type ReserveSELResponse struct { ReservationID uint16 } func (req *ReserveSELRequest) Command() Command { return CommandReserveSEL } func (req *ReserveSELRequest) Pack() []byte { return nil } func (res *ReserveSELResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } res.ReservationID, _, _ = unpackUint16L(msg, 0) return nil } func (*ReserveSELResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{ 0x81: "cannot execute command, SEL erase in progress", } } func (res *ReserveSELResponse) Format() string { return "" } func (c *Client) ReserveSEL(ctx context.Context) (response *ReserveSELResponse, err error) { request := &ReserveSELRequest{} response = &ReserveSELResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_reset_watchdog_timer.go000066400000000000000000000016261474110527100244670ustar00rootroot00000000000000package ipmi import "context" // 27.5 Reset Watchdog Timer Command type ResetWatchdogTimerRequest struct { // empty } type ResetWatchdogTimerResponse struct { } func (req *ResetWatchdogTimerRequest) Pack() []byte { return []byte{} } func (req *ResetWatchdogTimerRequest) Command() Command { return CommandResetWatchdogTimer } func (res *ResetWatchdogTimerResponse) Unpack(msg []byte) error { return nil } func (res *ResetWatchdogTimerResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{ 0x80: "Attempt to start un-initialized watchdog", } } func (res *ResetWatchdogTimerResponse) Format() string { return "" } func (c *Client) ResetWatchdogTimer(ctx context.Context) (response *ResetWatchdogTimerResponse, err error) { request := &ResetWatchdogTimerRequest{} response = &ResetWatchdogTimerResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_rmcp_ping_request.go000066400000000000000000000036251474110527100240140ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // RmcpPingRequest // 13.2.3 RMCP/ASF Presence Ping Message type RmcpPingRequest struct { // empty } type RmcpPingResponse struct { // If no OEM-specific capabilities exist, this field contains the ASF IANA (4542) and the OEM-defined field is set to all zeroes (00000000h). Otherwise, this field contains the OEM's IANA Enterprise Number and the OEM-defined field contains the OEM-specific capabilities. OEMIANA uint32 // Not used for IPMI. // This field can contain OEM-defined values; the definition of these values is left to the manufacturer identified by the preceding IANA Enterprise number. OEMDefined uint32 IPMISupported bool ASFVersion uint8 RMCPSecurityExtensionsSupported bool DMTFDashSupported bool // Reserved for future definition by ASF specification, // set to 00 00 00 00 00 00h, six bytes Reserved []byte } func (req *RmcpPingRequest) Pack() []byte { return nil } func (req *RmcpPingRequest) Command() Command { return CommandNone } func (res *RmcpPingResponse) Unpack(msg []byte) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } res.OEMIANA, _, _ = unpackUint32L(msg, 0) res.OEMDefined, _, _ = unpackUint32L(msg, 4) b, _, _ := unpackUint8(msg, 8) res.IPMISupported = isBit7Set(b) res.ASFVersion = b & 0x0f c, _, _ := unpackUint8(msg, 9) res.RMCPSecurityExtensionsSupported = isBit7Set(c) res.DMTFDashSupported = isBit5Set(c) res.Reserved, _, _ = unpackBytes(msg, 10, 6) return nil } func (r *RmcpPingResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *RmcpPingResponse) Format() string { return fmt.Sprintf("%v", res) } func (c *Client) RmcpPing(ctx context.Context) (response *RmcpPingResponse, err error) { request := &RmcpPingRequest{} response = &RmcpPingResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_send_message.go000066400000000000000000000036461474110527100227260ustar00rootroot00000000000000package ipmi import "context" // 22.7 Send Message Command type SendMessageRequest struct { // [7:6] 00b = No tracking // 01b = Track Request. // 10b = Send Raw. (optional) // 11b = reserved TrackMask uint8 Encrypted bool Authenticated bool ChannelNumber uint8 // Todo MessageData []byte } type SendMessageResponse struct { // This data will only be present when using the Send Message command to // originate requests from IPMB or PCI Management Bus to other channels // such as LAN or serial/modem. It is not present in the response to a // Send Message command delivered via the System Interface. Data []byte } func (req SendMessageRequest) Command() Command { return CommandSendMessage } func (req *SendMessageRequest) Pack() []byte { out := make([]byte, 1+len(req.MessageData)) var b uint8 = req.ChannelNumber if req.Authenticated { b = setBit4(b) } if req.Encrypted { b = setBit5(b) } b |= (req.TrackMask << 6) packUint8(b, out, 0) packBytes(req.MessageData, out, 1) return out } func (res *SendMessageResponse) Unpack(msg []byte) error { res.Data, _, _ = unpackBytes(msg, 0, len(msg)) return nil } func (*SendMessageResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "Invalid Session Handle. The session handle does not match up with any currently active sessions for this channel.", 0x81: "Lost Arbitration", 0x82: "Bus Error", 0x83: "NAK on Write", } } func (res *SendMessageResponse) Format() string { return "" } func (c *Client) SendMessage(ctx context.Context, channelNumber uint8, authenticated bool, encrypted bool, trackMask uint8, data []byte) (response *SendMessageResponse, err error) { request := &SendMessageRequest{ ChannelNumber: channelNumber, Authenticated: authenticated, Encrypted: encrypted, TrackMask: trackMask, MessageData: data, } response = &SendMessageResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_acpi_power_state.go000066400000000000000000000070111474110527100244620ustar00rootroot00000000000000package ipmi import "context" // 20.6 Set ACPI Power State Command type SetACPIPowerStateRequest struct { SetSystemPowerState bool // false means don't change system power state SystemPowerState SystemPowerState SetDevicePowerState bool // false means don't change device power state DevicePowerState DevicePowerState } type SetACPIPowerStateResponse struct { // empty } // see: https://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface#Global_states type SystemPowerState uint8 const ( SystemPowerStateS0G0 uint8 = 0x00 SystemPowerStateS1 uint8 = 0x01 SystemPowerStateS2 uint8 = 0x02 SystemPowerStateS3 uint8 = 0x03 SystemPowerStateS4 uint8 = 0x04 SystemPowerStateS5G2 uint8 = 0x05 SystemPowerStateS4S5 uint8 = 0x06 SystemPowerStateG3 uint8 = 0x07 SystemPowerStateSleeping uint8 = 0x08 SystemPowerStateG1Sleeping uint8 = 0x09 SystemPowerStateOverride uint8 = 0x0a SystemPowerStateLegacyOn uint8 = 0x20 SystemPowerStateLegacyOff uint8 = 0x21 SystemPowerStateUnknown uint8 = 0x2a SystemPowerStateNoChange uint8 = 0x7f ) func (s SystemPowerState) String() string { m := map[SystemPowerState]string{ 0x00: "S0/G0, working", 0x01: "S1, hardware context maintained, typically equates to processor/chip set clocks stopped", 0x02: "S2, typically equates to stopped clocks with processor/cache context lost", 0x03: "S3, typically equates to suspend-to-RAM", 0x04: "S4, typically equates to suspend-to-disk", 0x05: "S5/G2, soft off", 0x06: "S4/S5, sent when message source cannot differentiate between S4 and S5", 0x07: "G3, mechanical off", 0x08: "sleeping, sleeping - cannot differentiate between S1-S3", 0x09: "G1 sleeping, sleeping - cannot differentiate between S1-S4", 0x0a: "override, S5 entered by override", 0x20: "Legacy On, Legacy On (indicates On for system that don't support ACPI or have ACPI capabilities disabled)", 0x21: "Legacy Soft-Off", 0x2a: "Unknown, system power state unknown", 0x7f: "No Change", } o, ok := m[s] if ok { return o } return "" } type DevicePowerState uint8 const ( DevicePowerStateD0 uint8 = 0x00 DevicePowerStateD1 uint8 = 0x01 DevicePowerStateD2 uint8 = 0x02 DevicePowerStateD3 uint8 = 0x03 DevicePowerStateUnknown uint8 = 0x2a DevicePowerStateNoChange uint8 = 0x7f ) func (s DevicePowerState) String() string { m := map[DevicePowerState]string{ 0x00: "D0", 0x01: "D1", 0x02: "D2", 0x03: "D2", 0x2a: "Unknown", 0x7f: "No Change", } o, ok := m[s] if ok { return o } return "" } func (req *SetACPIPowerStateRequest) Pack() []byte { out := make([]byte, 2) var b1 = uint8(req.SystemPowerState) if req.SetSystemPowerState { b1 |= 0x80 } packUint8(b1, out, 0) var b2 = uint8(req.DevicePowerState) if req.SetDevicePowerState { b2 |= 0x80 } packUint8(b2, out, 1) return out } func (req *SetACPIPowerStateRequest) Command() Command { return CommandSetACPIPowerState } func (res *SetACPIPowerStateResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetACPIPowerStateResponse) Unpack(msg []byte) error { return nil } func (res *SetACPIPowerStateResponse) Format() string { return "" } // This command is provided to allow system software to tell a controller the present ACPI power state of the system. func (c *Client) SetACPIPowerState(ctx context.Context, request *SetACPIPowerStateRequest) (err error) { response := &SetACPIPowerStateResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_bmc_global_enables.go000066400000000000000000000044521474110527100247120ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 22.1 Set BMC Global Enables Command type SetBMCGlobalEnablesRequest struct { // Generic system mgmt. software must do a "read-modify-write" using the Get BMC Global Enables and Set BMC Global Enables to avoid altering EnableOEM_X field. EnableOEM2 bool EnableOEM1 bool EnableOEM0 bool EnableSystemEventLogging bool EnableEventMessageBuffer bool EnableEventMessageBufferFullInterrupt bool EnableReceiveMessageQueueInterrupt bool } type SetBMCGlobalEnablesResponse struct { // empty } func (req *SetBMCGlobalEnablesRequest) Command() Command { return CommandSetBMCGlobalEnables } func (req *SetBMCGlobalEnablesRequest) Pack() []byte { var b uint8 = 0 if req.EnableOEM2 { b = setBit7(b) } if req.EnableOEM1 { b = setBit6(b) } if req.EnableOEM0 { b = setBit5(b) } if req.EnableSystemEventLogging { b = setBit3(b) } if req.EnableEventMessageBuffer { b = setBit2(b) } if req.EnableEventMessageBufferFullInterrupt { b = setBit1(b) } if req.EnableReceiveMessageQueueInterrupt { b = setBit0(b) } return []byte{b} } func (res *SetBMCGlobalEnablesResponse) Unpack(msg []byte) error { return nil } func (*SetBMCGlobalEnablesResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *SetBMCGlobalEnablesResponse) Format() string { // Todo return "" } func (c *Client) SetBMCGlobalEnables(ctx context.Context, enableSystemEventLogging bool, enableEventMessageBuffer bool, enableEventMessageBufferFullInterrupt bool, enableReceiveMessageQueueInterrupt bool) (response *SetBMCGlobalEnablesResponse, err error) { getRes, err := c.GetBMCGlobalEnables(ctx) if err != nil { return nil, fmt.Errorf("GetBMCGlobalEnables failed, err: %w", err) } request := &SetBMCGlobalEnablesRequest{ EnableOEM2: getRes.OEM2Enabled, EnableOEM1: getRes.OEM1Enabled, EnableOEM0: getRes.OEM0Enabled, EnableSystemEventLogging: enableSystemEventLogging, EnableEventMessageBuffer: enableEventMessageBuffer, EnableEventMessageBufferFullInterrupt: enableEventMessageBufferFullInterrupt, EnableReceiveMessageQueueInterrupt: enableReceiveMessageQueueInterrupt, } response = &SetBMCGlobalEnablesResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_channel_access.go000066400000000000000000000033551474110527100240720ustar00rootroot00000000000000package ipmi import "context" // 22.22 Set Channel Access Command type SetChannelAccessRequest struct { ChannelNumber uint8 // [7:6] - 00b = don't set or change Channel Access // 01b = set non-volatile Channel Access according to bits [5:0] // 10b = set volatile (active) setting of Channel Access according to bit [5:0] // 11b = reserved AccessOption uint8 DisablePEFAlerting bool DisablePerMsgAuth bool DisableUserLevelAuth bool AccessMode ChannelAccessMode PrivilegeOption uint8 MaxPrivilegeLevel uint8 } type SetChannelAccessResponse struct { } func (req *SetChannelAccessRequest) Pack() []byte { out := make([]byte, 3) packUint8(req.ChannelNumber, out, 0) var b = req.AccessOption << 6 if req.DisablePEFAlerting { b = setBit5(b) } if req.DisablePerMsgAuth { b = setBit4(b) } if req.DisableUserLevelAuth { b = setBit3(b) } b |= uint8(req.AccessMode) & 0x07 packUint8(b, out, 1) var b2 = req.PrivilegeOption << 6 b2 |= req.MaxPrivilegeLevel & 0x3f packUint8(b2, out, 2) return out } func (req *SetChannelAccessRequest) Command() Command { return CommandSetChannelAccess } func (res *SetChannelAccessResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x82: "set not supported on selected channel (e.g. channel is session-less.)", 0x83: "access mode not supported", } } func (res *SetChannelAccessResponse) Unpack(msg []byte) error { return nil } func (res *SetChannelAccessResponse) Format() string { return "" } func (c *Client) SetChannelAccess(ctx context.Context, request *SetChannelAccessRequest) (response *SetChannelAccessResponse, err error) { response = &SetChannelAccessResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_chassis_capabilities.go000066400000000000000000000026151474110527100253050ustar00rootroot00000000000000package ipmi import "context" // 28.7 Set Chassis Capabilities Command type SetChassisCapabilitiesRequest struct { ProvideFrontPanelLockout bool ProvideIntrusionSensor bool FRUDeviceAddress uint8 SDRDeviceAddress uint8 SELDeviceAddress uint8 SystemManagementDeviceAddress uint8 BridgeDeviceAddress uint8 } type SetChassisCapabilitiesResponse struct { } func (req *SetChassisCapabilitiesRequest) Pack() []byte { out := make([]byte, 5) var b uint8 = 0 if req.ProvideFrontPanelLockout { b = setBit1(b) } if req.ProvideIntrusionSensor { b = setBit0(b) } packUint8(b, out, 0) packUint8(req.FRUDeviceAddress, out, 1) packUint8(req.SDRDeviceAddress, out, 2) packUint8(req.SELDeviceAddress, out, 3) packUint8(req.SystemManagementDeviceAddress, out, 4) return out } func (req *SetChassisCapabilitiesRequest) Command() Command { return CommandSetChassisCapabilities } func (res *SetChassisCapabilitiesResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetChassisCapabilitiesResponse) Unpack(msg []byte) error { return nil } func (res *SetChassisCapabilitiesResponse) Format() string { return "" } func (c *Client) SetChassisCapabilities(ctx context.Context, request *SetChassisCapabilitiesRequest) (response *SetChassisCapabilitiesResponse, err error) { response = &SetChassisCapabilitiesResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_dcmi_asset_tag.go000066400000000000000000000060431474110527100241040ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // [DCMI specification v1.5] 6.4.3 Set Asset Tag Command type SetDCMIAssetTagRequest struct { // The offset is relative to the first character of the Asset Tag data. // Offset to write (0 to 62) // C9h shall be returned if offset >62, offset+bytes to write >63, or bytes to write >16. Offset uint8 // Number of bytes to write (16 bytes maximum). // The command shall set the overall length of the Asset Tag (in bytes) to // the value (offset to write + bytes to write). Any pre-existing Asset Tag // bytes at offsets past that length are automatically deleted. WriteBytes uint8 // The Asset Tag shall be encoded using either UTF-8 with Byte Order Mark or ASCII+Latin1 encoding. // The maximum size of the Asset Tag shall be 63 bytes, including Byte Order Mark, if provided. AssetTag []byte } type SetDCMIAssetTagResponse struct { // Total Asset Tag Length. // This is the length in bytes of the stored Asset Tag after the Set operation has completed. // The Asset Tag length shall be set to the sum of the offset to write plus bytes to write. // For example, if offset to write is 32 and bytes to write is 4, the Total Asset Tag Length returned will be 36. TotalLength uint8 } func (req *SetDCMIAssetTagRequest) Pack() []byte { out := make([]byte, 3+len(req.AssetTag)) packUint8(GroupExtensionDCMI, out, 0) packUint8(req.Offset, out, 1) packUint8(req.WriteBytes, out, 2) packBytes(req.AssetTag, out, 3) return out } func (req *SetDCMIAssetTagRequest) Command() Command { return CommandSetDCMIAssetTag } func (res *SetDCMIAssetTagResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetDCMIAssetTagResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } res.TotalLength = msg[1] return nil } func (res *SetDCMIAssetTagResponse) Format() string { return fmt.Sprintf("Total Length: %d", res.TotalLength) } func (c *Client) SetDCMIAssetTag(ctx context.Context, offset uint8, writeBytes uint8, assetTag []byte) (response *SetDCMIAssetTagResponse, err error) { request := &SetDCMIAssetTagRequest{ Offset: offset, WriteBytes: writeBytes, AssetTag: assetTag, } response = &SetDCMIAssetTagResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) SetDCMIAssetTagFull(ctx context.Context, assetTag []byte) (err error) { if len(assetTag) > 63 { return fmt.Errorf("the asset tag must be at most 63 bytes") } var offset uint8 = 0 var writeBytes uint8 = 16 if len(assetTag) < 16 { writeBytes = uint8(len(assetTag)) } for { offsetEnd := offset + writeBytes _, err := c.SetDCMIAssetTag(ctx, offset, writeBytes, assetTag[offset:offsetEnd]) if err != nil { return fmt.Errorf("SetDCMIAssetTag failed, err: %w", err) } offset = offset + writeBytes if offset >= uint8(len(assetTag)) { break } if offset+writeBytes > uint8(len(assetTag)) { writeBytes = uint8(len(assetTag)) - offset } } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_set_dcmi_config_params.go000066400000000000000000000037301474110527100247420ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // [DCMI specification v1.5] 6.1.2 Set DCMI Configuration Parameters type SetDCMIConfigParamRequest struct { ParamSelector DCMIConfigParamSelector SetSelector uint8 // use 00h for parameters that only have one set ParamData []byte } type SetDCMIConfigParamResponse struct { } func (req *SetDCMIConfigParamRequest) Pack() []byte { out := make([]byte, 3+len(req.ParamData)) packUint8(GroupExtensionDCMI, out, 0) packUint8(uint8(req.ParamSelector), out, 1) packUint8(req.SetSelector, out, 2) packBytes(req.ParamData, out, 3) return out } func (req *SetDCMIConfigParamRequest) Command() Command { return CommandSetDCMIConfigParam } func (res *SetDCMIConfigParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetDCMIConfigParamResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 2) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } return nil } func (res *SetDCMIConfigParamResponse) Format() string { return "" } func (c *Client) SetDCMIConfigParam(ctx context.Context, paramSelector DCMIConfigParamSelector, setSelector uint8, paramData []byte) (response *SetDCMIConfigParamResponse, err error) { request := &SetDCMIConfigParamRequest{ ParamSelector: paramSelector, SetSelector: setSelector, ParamData: paramData, } response = &SetDCMIConfigParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) SetDCMIConfigParamFor(ctx context.Context, param DCMIConfigParameter) (response *SetDCMIConfigParamResponse, err error) { if isNilDCMIConfigParameter(param) { return nil, fmt.Errorf("param is nil") } paramSelector, setSelector := param.DCMIConfigParameter() paramData := param.Pack() response, err = c.SetDCMIConfigParam(ctx, paramSelector, setSelector, paramData) if err != nil { return nil, fmt.Errorf("SetDCMIConfigParam failed, err: %w", err) } return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_dcmi_mgmt_controller_identifier.go000066400000000000000000000053461474110527100275500ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // [DCMI specification v1.5] 6.4.6.2 Set Management Controller Identifier String Command type SetDCMIMgmtControllerIdentifierRequest struct { Offset uint8 WriteBytes uint8 IDStr []byte } type SetDCMIMgmtControllerIdentifierResponse struct { // Total Asset Tag Length. // This is the length in bytes of the stored Asset Tag after the Set operation has completed. // The Asset Tag length shall be set to the sum of the offset to write plus bytes to write. // For example, if offset to write is 32 and bytes to write is 4, the Total Asset Tag Length returned will be 36. TotalLength uint8 } func (req *SetDCMIMgmtControllerIdentifierRequest) Pack() []byte { out := make([]byte, 3+len(req.IDStr)) packUint8(GroupExtensionDCMI, out, 0) packUint8(req.Offset, out, 1) packUint8(req.WriteBytes, out, 2) packBytes(req.IDStr, out, 3) return out } func (req *SetDCMIMgmtControllerIdentifierRequest) Command() Command { return CommandSetDCMIMgmtControllerIdentifier } func (res *SetDCMIMgmtControllerIdentifierResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetDCMIMgmtControllerIdentifierResponse) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } res.TotalLength = msg[1] return nil } func (res *SetDCMIMgmtControllerIdentifierResponse) Format() string { return fmt.Sprintf("Total Length: %d", res.TotalLength) } func (c *Client) SetDCMIMgmtControllerIdentifier(ctx context.Context, offset uint8, writeBytes uint8, idStr []byte) (response *SetDCMIMgmtControllerIdentifierResponse, err error) { request := &SetDCMIMgmtControllerIdentifierRequest{ Offset: offset, WriteBytes: writeBytes, IDStr: idStr, } response = &SetDCMIMgmtControllerIdentifierResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) SetDCMIMgmtControllerIdentifierFull(ctx context.Context, idStr []byte) (err error) { if len(idStr) > 63 { return fmt.Errorf("the id str must be at most 63 bytes") } // make sure idStr null terminated if idStr[len(idStr)-1] != 0x00 { idStr = append(idStr, 0x00) } var offset uint8 = 0 var writeBytes uint8 = 16 if len(idStr) < 16 { writeBytes = uint8(len(idStr)) } for { offsetEnd := offset + writeBytes _, err := c.SetDCMIMgmtControllerIdentifier(ctx, offset, writeBytes, idStr[offset:offsetEnd]) if err != nil { return fmt.Errorf("SetDCMIMgmtControllerIdentifier failed, err: %w", err) } offset = offset + writeBytes if offset >= uint8(len(idStr)) { break } if offset+writeBytes > uint8(len(idStr)) { writeBytes = uint8(len(idStr)) - offset } } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_set_dcmi_power_limit.go000066400000000000000000000045011474110527100244610ustar00rootroot00000000000000package ipmi import "context" // The Set Power Limit command sets the power limit parameters on the system. // The power limit defines a threshold which, if exceeded for a configurable amount of time, // will trigger a system power off and/or event logging action. // // If the limit is already active, the Set Power Limit command may immediately change the limit that is in effect. // However, software should always explicitly activate the limit using the Activate/Deactivate power limit // command to ensure the setting takes effect. // // [DCMI specification v1.5]: 6.6.3 Set Power Limit type SetDCMIPowerLimitRequest struct { ExceptionAction DCMIExceptionAction // Power Limit Requested in Watts PowerLimitRequested uint16 // Maximum time taken to limit the power after the platform power has reached // the power limit before the Exception Action will be taken. CorrectionTimeLimitMilliSec uint32 // Management application Statistics Sampling period in seconds StatisticsSamplingPeriodSec uint16 } type SetDCMIPowerLimitResponse struct { } func (req *SetDCMIPowerLimitRequest) Pack() []byte { out := make([]byte, 15) packUint8(GroupExtensionDCMI, out, 0) packUint8(uint8(req.ExceptionAction), out, 4) packUint16L(req.PowerLimitRequested, out, 5) packUint32L(req.CorrectionTimeLimitMilliSec, out, 7) packUint16L(req.StatisticsSamplingPeriodSec, out, 13) return out } func (req *SetDCMIPowerLimitRequest) Command() Command { return CommandSetDCMIPowerLimit } func (res *SetDCMIPowerLimitResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x84: "Power Limit out of range", 0x85: "Correction Time out of range", 0x89: "Statistics Reporting Period out of range", } } func (res *SetDCMIPowerLimitResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } return nil } func (res *SetDCMIPowerLimitResponse) Format() string { return "" } // SetDCMIPowerLimit sends a DCMI "Get Power Reading" command. // See [SetDCMIPowerLimitRequest] for details. func (c *Client) SetDCMIPowerLimit(ctx context.Context, request *SetDCMIPowerLimitRequest) (response *SetDCMIPowerLimitResponse, err error) { response = &SetDCMIPowerLimitResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_dcmi_thermal_limit.go000066400000000000000000000032701474110527100247630ustar00rootroot00000000000000package ipmi import "context" // [DCMI specification v1.5]: 6.7.2 Set Thermal Limit Command type SetDCMIThermalLimitRequest struct { EntityID EntityID // Entity ID = 37h or 40h (Inlet Temperature) EntityInstance EntityInstance ExceptionAction_PowerOffAndLogSEL bool ExceptionAction_LogSELOnly bool // ignored if ExceptionAction_PowerOffAndLogSEL is true TemperatureLimit uint8 ExceptionTimeSec uint16 } type SetDCMIThermalLimitResponse struct { } func (req *SetDCMIThermalLimitRequest) Pack() []byte { out := make([]byte, 7) out[0] = GroupExtensionDCMI out[1] = byte(req.EntityID) out[2] = byte(req.EntityInstance) exceptionAction := uint8(0) if req.ExceptionAction_PowerOffAndLogSEL { exceptionAction = setBit6(exceptionAction) } if req.ExceptionAction_LogSELOnly { exceptionAction = setBit5(exceptionAction) } out[3] = exceptionAction out[4] = req.TemperatureLimit packUint16L(req.ExceptionTimeSec, out, 5) return out } func (req *SetDCMIThermalLimitRequest) Command() Command { return CommandSetDCMIThermalLimit } func (res *SetDCMIThermalLimitResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetDCMIThermalLimitResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } if err := CheckDCMIGroupExenstionMatch(msg[0]); err != nil { return err } return nil } func (res *SetDCMIThermalLimitResponse) Format() string { return "" } func (c *Client) SetDCMIThermalLimit(ctx context.Context, request *SetDCMIThermalLimitRequest) (response *SetDCMIThermalLimitResponse, err error) { response = &SetDCMIThermalLimitResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_event_receiver.go000066400000000000000000000024621474110527100241440ustar00rootroot00000000000000package ipmi import "context" // 29.1 Set Event Receiver Command type SetEventReceiverRequest struct { // Event Receiver Slave Address. // - 0FFh disables Event Message Generation, Otherwise: // - [7:1] - IPMB (I2C) Slave Address // - [0] - always 0b when [7:1] hold I2C slave address SlaveAddress uint8 // [1:0] - Event Receiver LUN LUN uint8 } type SetEventReceiverResponse struct { } func (req *SetEventReceiverRequest) Pack() []byte { return []byte{req.SlaveAddress, req.LUN} } func (req *SetEventReceiverRequest) Command() Command { return CommandSetEventReceiver } func (res *SetEventReceiverResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetEventReceiverResponse) Unpack(msg []byte) error { return nil } func (res *SetEventReceiverResponse) Format() string { return "" } func (c *Client) SetEventReceiver(ctx context.Context, slaveAddress uint8, lun uint8) (response *SetEventReceiverResponse, err error) { request := &SetEventReceiverRequest{ SlaveAddress: slaveAddress, LUN: lun, } response = &SetEventReceiverResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) SetEventReceiverDisable(ctx context.Context, lun uint8) (response *SetEventReceiverResponse, err error) { return c.SetEventReceiver(ctx, 0xff, lun) } golang-github-bougou-go-ipmi-0.7.2/cmd_set_front_panel_enables.go000066400000000000000000000031601474110527100251330ustar00rootroot00000000000000package ipmi import "context" // 28.6 Set Front Panel Enables // 定位 type SetFrontPanelEnablesRequest struct { DisableSleepButton bool DisableDiagnosticButton bool DisableResetButton bool DisablePoweroffButton bool } type SetFrontPanelEnablesResponse struct { // empty } func (req *SetFrontPanelEnablesRequest) Pack() []byte { out := make([]byte, 1) var b uint8 = 0 if req.DisableSleepButton { b = setBit3(b) } if req.DisableSleepButton { b = setBit2(b) } if req.DisableSleepButton { b = setBit1(b) } if req.DisableSleepButton { b = setBit0(b) } packUint8(b, out, 1) return out } func (req *SetFrontPanelEnablesRequest) Command() Command { return CommandSetFrontPanelEnables } func (res *SetFrontPanelEnablesResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetFrontPanelEnablesResponse) Unpack(msg []byte) error { return nil } func (res *SetFrontPanelEnablesResponse) Format() string { return "" } // The following command is used to enable or disable the buttons on the front panel of the chassis. func (c *Client) SetFrontPanelEnables(ctx context.Context, disableSleepButton bool, disableDiagnosticButton bool, disableResetButton bool, disablePoweroffButton bool) (response *SetFrontPanelEnablesResponse, err error) { request := &SetFrontPanelEnablesRequest{ DisableSleepButton: disableSleepButton, DisableDiagnosticButton: disableDiagnosticButton, DisableResetButton: disableResetButton, DisablePoweroffButton: disablePoweroffButton, } response = &SetFrontPanelEnablesResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_lan_config_params.go000066400000000000000000000037701474110527100246040ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 23.1 Set LAN Configuration Parameters Command type SetLanConfigParamRequest struct { ChannelNumber uint8 ParamSelector LanConfigParamSelector ParamData []byte } type SetLanConfigParamResponse struct { // empty } func (req *SetLanConfigParamRequest) Pack() []byte { out := make([]byte, 2+len(req.ParamData)) packUint8(req.ChannelNumber, out, 0) packUint8(uint8(req.ParamSelector), out, 1) packBytes(req.ParamData, out, 2) return out } func (req *SetLanConfigParamRequest) Command() Command { return CommandSetLanConfigParam } func (res *SetLanConfigParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "parameter not supported.", 0x81: "attempt to set the 'set in progress' value (in parameter #0) when not in the 'set complete' state.", 0x82: "attempt to write read-only parameter", 0x83: "attempt to read write-only parameter", } } func (res *SetLanConfigParamResponse) Unpack(msg []byte) error { return nil } func (res *SetLanConfigParamResponse) Format() string { return "" } func (c *Client) SetLanConfigParam(ctx context.Context, channelNumber uint8, paramSelector LanConfigParamSelector, configData []byte) (response *SetLanConfigParamResponse, err error) { request := &SetLanConfigParamRequest{ ChannelNumber: channelNumber, ParamSelector: paramSelector, ParamData: configData, } response = &SetLanConfigParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) SetLanConfigParamFor(ctx context.Context, channelNumber uint8, param LanConfigParameter) error { paramSelector, _, _ := param.LanConfigParameter() c.DebugBytes(fmt.Sprintf(">> Set param data for (%s[%d]) ", paramSelector.String(), paramSelector), param.Pack(), 8) if _, err := c.SetLanConfigParam(ctx, channelNumber, paramSelector, param.Pack()); err != nil { c.Debugf("!!! Set LanConfigParam for paramSelector (%d) %s failed, err: %v\n", uint8(paramSelector), paramSelector, err) return err } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_set_last_processed_event_id.go000066400000000000000000000024671474110527100260330ustar00rootroot00000000000000package ipmi import "context" // 30.5 Set Last Processed Event ID Command type SetLastProcessedEventIdRequest struct { // 0b = set Record ID for last record processed by software. // 1b = set Record ID for last record processed by BMC. ByBMC bool RecordID uint16 } type SetLastProcessedEventIdResponse struct { // empty } func (req *SetLastProcessedEventIdRequest) Command() Command { return CommandSetLastProcessedEventId } func (req *SetLastProcessedEventIdRequest) Pack() []byte { // empty request data out := make([]byte, 3) var b0 uint8 = 0x0 if req.ByBMC { b0 = 1 } packUint8(b0, out, 0) packUint16L(req.RecordID, out, 1) return out } func (res *SetLastProcessedEventIdResponse) Unpack(msg []byte) error { return nil } func (r *SetLastProcessedEventIdResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x81: "cannot execute command, SEL erase in progress", } } func (res *SetLastProcessedEventIdResponse) Format() string { return "" } func (c *Client) SetLastProcessedEventId(ctx context.Context, recordID uint16, byBMC bool) (response *SetLastProcessedEventIdResponse, err error) { request := &SetLastProcessedEventIdRequest{ ByBMC: byBMC, RecordID: recordID, } response = &SetLastProcessedEventIdResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_pef_config_params.go000066400000000000000000000030571474110527100246020ustar00rootroot00000000000000package ipmi import "context" // 30.3 Set PEF Configuration Parameters Command type SetPEFConfigParamRequest struct { ParamSelector PEFConfigParamSelector ParamData []byte } type SetPEFConfigParamResponse struct { // empty } func (req *SetPEFConfigParamRequest) Command() Command { return CommandSetPEFConfigParam } func (req *SetPEFConfigParamRequest) Pack() []byte { // empty request data out := make([]byte, 1+len(req.ParamData)) // out[0] = req.ParamSelector packUint8(uint8(req.ParamSelector), out, 0) if len(req.ParamData) > 0 { packBytes(req.ParamData, out, 1) } return out } func (res *SetPEFConfigParamResponse) Unpack(msg []byte) error { return nil } func (r *SetPEFConfigParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "parameter not supported", // (This completion code provides a way to recognize that another party has already 'claimed' the parameters)" 0x81: "attempt to set the 'set in progress' value (in parameter #0) when not in the 'set complete' state.", 0x82: "attempt to write read-only parameter", 0x83: "attempt to read write-only parameter", } } func (res *SetPEFConfigParamResponse) Format() string { return "" } // Todo func (c *Client) SetPEFConfigParam(ctx context.Context, paramSelector PEFConfigParamSelector, paramData []byte) (response *SetPEFConfigParamResponse, err error) { request := &SetPEFConfigParamRequest{ ParamSelector: paramSelector, ParamData: paramData, } response = &SetPEFConfigParamResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_power_cycle_interval.go000066400000000000000000000017521474110527100253570ustar00rootroot00000000000000package ipmi import "context" // 28.9 Set Power Cycle Interval type SetPowerCycleIntervalRequest struct { IntervalInSec uint8 } type SetPowerCycleIntervalResponse struct { // empty } func (req *SetPowerCycleIntervalRequest) Pack() []byte { out := make([]byte, 1) packUint8(req.IntervalInSec, out, 0) return out } func (req *SetPowerCycleIntervalRequest) Command() Command { return CommandSetPowerCycleInterval } func (res *SetPowerCycleIntervalResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetPowerCycleIntervalResponse) Unpack(msg []byte) error { return nil } func (res *SetPowerCycleIntervalResponse) Format() string { return "" } func (c *Client) SetPowerCycleInterval(ctx context.Context, intervalInSec uint8) (response *SetPowerCycleIntervalResponse, err error) { request := &SetPowerCycleIntervalRequest{ IntervalInSec: intervalInSec, } response = &SetPowerCycleIntervalResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_power_restore_policy.go000066400000000000000000000034771474110527100254240ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 28.8 Set Power Restore Policy Command type SetPowerRestorePolicyRequest struct { PowerRestorePolicy } type SetPowerRestorePolicyResponse struct { SupportPolicyAlwaysOn bool // chassis supports always powering up after AC/mains returns SupportPolicyPrevious bool // chassis supports restoring power to state that was in effect when AC/mains was lost SupportPolicyAlwaysOff bool // chassis supports staying powered off after AC/mains returns } func (req *SetPowerRestorePolicyRequest) Pack() []byte { out := make([]byte, 1) packUint8(uint8(req.PowerRestorePolicy), out, 0) return out } func (req *SetPowerRestorePolicyRequest) Command() Command { return CommandSetPowerRestorePolicy } func (res *SetPowerRestorePolicyResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetPowerRestorePolicyResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } b, _, _ := unpackUint8(msg, 0) res.SupportPolicyAlwaysOff = isBit0Set(b) res.SupportPolicyPrevious = isBit1Set(b) res.SupportPolicyAlwaysOn = isBit2Set((b)) return nil } func (res *SetPowerRestorePolicyResponse) Format() string { return fmt.Sprintf(`Policy always-off : %s" Policy always-on : %s Policy previous :"%s`, formatBool(res.SupportPolicyAlwaysOff, "supported", "unsupported"), formatBool(res.SupportPolicyAlwaysOff, "supported", "unsupported"), formatBool(res.SupportPolicyAlwaysOff, "supported", "unsupported"), ) } func (c *Client) SetPowerRestorePolicy(ctx context.Context, policy PowerRestorePolicy) (response *SetPowerRestorePolicyResponse, err error) { request := &SetPowerRestorePolicyRequest{ PowerRestorePolicy: policy, } response = &SetPowerRestorePolicyResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_sel_time.go000066400000000000000000000016051474110527100227360ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "time" ) // 31.11 Set SEL Time Command type SetSELTimeRequest struct { Time time.Time } type SetSELTimeResponse struct { } func (req *SetSELTimeRequest) Pack() []byte { var out = make([]byte, 4) packUint32L(uint32(req.Time.Unix()), out, 0) return out } func (req *SetSELTimeRequest) Command() Command { return CommandSetSELTime } func (res *SetSELTimeResponse) Unpack(msg []byte) error { return nil } func (res *SetSELTimeResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *SetSELTimeResponse) Format() string { return fmt.Sprintf("%v", res) } func (c *Client) SetSELTime(ctx context.Context, t time.Time) (response *SetSELTimeResponse, err error) { request := &SetSELTimeRequest{ Time: t, } response = &SetSELTimeResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_sel_time_utc_offset.go000066400000000000000000000023571474110527100251640ustar00rootroot00000000000000package ipmi import "context" // 31.11a Set SEL Time UTC Offset type SetSELTimeUTCOffsetRequest struct { // signed integer for the offset in minutes from UTC to SEL Time. (ranges from -1440 to 1440) MinutesOffset int16 } type SetSELTimeUTCOffsetResponse struct { // empty } func (req *SetSELTimeUTCOffsetRequest) Pack() []byte { out := make([]byte, 2) a := twosComplementEncode(int32(req.MinutesOffset), 16) packUint16L(uint16(a), out, 0) return out } func (req *SetSELTimeUTCOffsetRequest) Command() Command { return CommandSetSELTimeUTCOffset } func (res *SetSELTimeUTCOffsetResponse) Unpack(msg []byte) error { return nil } func (res *SetSELTimeUTCOffsetResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *SetSELTimeUTCOffsetResponse) Format() string { return "" } // SetSELTimeUTCOffset initializes and retrieve a UTC offset (timezone) that is associated with the SEL Time func (c *Client) SetSELTimeUTCOffset(ctx context.Context, minutesOffset int16) (response *SetSELTimeUTCOffsetResponse, err error) { request := &SetSELTimeUTCOffsetRequest{ MinutesOffset: minutesOffset, } response = &SetSELTimeUTCOffsetResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_sensor_hysteresis.go000066400000000000000000000027401474110527100247310ustar00rootroot00000000000000package ipmi import "context" // 35.6 Set Sensor Hysteresis Command type SetSensorHysteresisRequest struct { SensorNumber uint8 PositiveHysteresis uint8 NegativeHysteresis uint8 } type SetSensorHysteresisResponse struct { } func (req *SetSensorHysteresisRequest) Command() Command { return CommandSetSensorHysteresis } func (req *SetSensorHysteresisRequest) Pack() []byte { out := make([]byte, 4) packUint8(req.SensorNumber, out, 0) packUint8(0xff, out, 1) // reserved for future "hysteresis mask" definition. Write as FFh packUint8(req.PositiveHysteresis, out, 2) packUint8(req.NegativeHysteresis, out, 3) return out } func (res *SetSensorHysteresisResponse) Unpack(msg []byte) error { return nil } func (r *SetSensorHysteresisResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetSensorHysteresisResponse) Format() string { return "" } // This command provides a mechanism for setting the hysteresis values associated // with the thresholds of a sensor that has threshold based event generation. func (c *Client) SetSensorHysteresis(ctx context.Context, sensorNumber uint8, positiveHysteresis uint8, negativeHysteresis uint8) (response *SetSensorHysteresisResponse, err error) { request := &SetSensorHysteresisRequest{ SensorNumber: sensorNumber, PositiveHysteresis: positiveHysteresis, NegativeHysteresis: negativeHysteresis, } response = &SetSensorHysteresisResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_sensor_reading_and_event_status.go000066400000000000000000000035421474110527100275670ustar00rootroot00000000000000package ipmi import "context" // 35.17 Set Sensor Reading And Event Status Command type SetSensorReadingAndEventStatusRequest struct { SensorNumber uint8 EventDataBytesOperation uint8 AssertionBitsOperation uint8 DeassertionBitsOperation uint8 SensorReadingOperation uint8 SensorReading uint8 SensorEventFlag EventData1 uint8 EventData2 uint8 EventData3 uint8 } type SetSensorReadingAndEventStatusResponse struct { // empty } func (req *SetSensorReadingAndEventStatusRequest) Command() Command { return CommandSetSensorReadingAndEventStatus } func (req *SetSensorReadingAndEventStatusRequest) Pack() []byte { out := make([]byte, 9) packUint8(req.SensorNumber, out, 0) var operation uint8 operation |= uint8(req.EventDataBytesOperation) << 6 operation |= (uint8(req.AssertionBitsOperation) & 0x3f) << 4 operation |= (uint8(req.DeassertionBitsOperation) & 0x0f) << 2 operation |= uint8(req.SensorReadingOperation) & 0x03 packUint8(operation, out, 1) packUint8(req.SensorReading, out, 2) // Todo determine sensor is threshold based or discrete return out } func (res *SetSensorReadingAndEventStatusResponse) Unpack(msg []byte) error { return nil } func (r *SetSensorReadingAndEventStatusResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "Attempt to change reading or set or clear status bits that are not settable via this command", 0x81: "Attempted to set Event Data Bytes, but setting Event Data Bytes is not supported for this sensor.", } } func (res *SetSensorReadingAndEventStatusResponse) Format() string { return "" } func (c *Client) SetSensorReadingAndEventStatus(ctx context.Context, request *SetSensorReadingAndEventStatusRequest) (response *SetSensorReadingAndEventStatusResponse, err error) { response = &SetSensorReadingAndEventStatusResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_sensor_thresholds.go000066400000000000000000000046041474110527100247070ustar00rootroot00000000000000package ipmi import "context" // 35.8 Set Sensor Thresholds Command type SetSensorThresholdsRequest struct { SensorNumber uint8 // Set Threshold flag SetUNR bool SetUCR bool SetUNC bool SetLNR bool SetLCR bool SetLNC bool // Threshold value LNC_Raw uint8 LCR_Raw uint8 LNR_Raw uint8 UNC_Raw uint8 UCR_Raw uint8 UNR_Raw uint8 } type SetSensorThresholdsResponse struct { // empty } func (req *SetSensorThresholdsRequest) Command() Command { return CommandSetSensorThresholds } func (req *SetSensorThresholdsRequest) Pack() []byte { out := make([]byte, 8) packUint8(req.SensorNumber, out, 0) var b uint8 if req.SetUNR { b = setBit5(b) } if req.SetUCR { b = setBit4(b) } if req.SetUNC { b = setBit3(b) } if req.SetLNR { b = setBit2(b) } if req.SetLCR { b = setBit1(b) } if req.SetLNC { b = setBit0(b) } packUint8(b, out, 1) packUint8(req.LNC_Raw, out, 2) packUint8(req.LCR_Raw, out, 3) packUint8(req.LNR_Raw, out, 4) packUint8(req.UNC_Raw, out, 5) packUint8(req.UCR_Raw, out, 6) packUint8(req.UNR_Raw, out, 7) return out } func (res *SetSensorThresholdsResponse) Unpack(msg []byte) error { return nil } func (r *SetSensorThresholdsResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetSensorThresholdsResponse) Format() string { return "" } // SetSensorThresholds is to set the specified threshold for the given sensor. // Note that the application issuing this command is responsible for ensuring that // thresholds for a sensor are set in the proper order (e.g. that // the upper critical threshold is set higher than the upper non-critical threshold) // // Upper Non Recoverable area // -----------------UNR threshold // Upper Critical area // -----------------UCR threshold // Upper Non Critical area // -----------------UNC threshold // OK area // -----------------LNC threshold // Lower Non Critical area // -----------------LCR threshold // Lower Critical area // -----------------LNR threshold // Lower NonRecoverable area // // This command provides a mechanism for setting the hysteresis values associated // with the thresholds of a sensor that has threshold based event generation. func (c *Client) SetSensorThresholds(ctx context.Context, request *SetSensorThresholdsRequest) (response *SetSensorThresholdsResponse, err error) { response = &SetSensorThresholdsResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_sensor_type.go000066400000000000000000000022451474110527100235100ustar00rootroot00000000000000package ipmi import "context" // 35.15 Set Sensor Type Command type SetSensorTypeRequest struct { SensorNumber uint8 SensorType SensorType EventReadingType EventReadingType } type SetSensorTypeResponse struct { // empty } func (req *SetSensorTypeRequest) Command() Command { return CommandSetSensorType } func (req *SetSensorTypeRequest) Pack() []byte { out := make([]byte, 3) packUint8(req.SensorNumber, out, 0) packUint8(uint8(req.SensorType), out, 1) packUint8(uint8(req.EventReadingType), out, 2) return out } func (res *SetSensorTypeResponse) Unpack(msg []byte) error { return nil } func (r *SetSensorTypeResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetSensorTypeResponse) Format() string { return "" } func (c *Client) SetSensorType(ctx context.Context, sensorNumber uint8, sensorType SensorType, eventReadingType EventReadingType) (response *SetSensorTypeResponse, err error) { request := &SetSensorTypeRequest{ SensorNumber: sensorNumber, SensorType: sensorType, EventReadingType: eventReadingType, } response = &SetSensorTypeResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_session_privilege_level.go000066400000000000000000000027311474110527100260560ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 22.18 Set Session Privilege Level Command type SetSessionPrivilegeLevelRequest struct { PrivilegeLevel PrivilegeLevel } type SetSessionPrivilegeLevelResponse struct { // New Privilege Level (or present level if 'return present privilege level' was selected.) PrivilegeLevel uint8 } func (req *SetSessionPrivilegeLevelRequest) Command() Command { return CommandSetSessionPrivilegeLevel } func (req *SetSessionPrivilegeLevelRequest) Pack() []byte { var msg = make([]byte, 1) packUint8(uint8(req.PrivilegeLevel), msg, 0) return msg } func (res *SetSessionPrivilegeLevelResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } res.PrivilegeLevel = msg[0] return nil } func (*SetSessionPrivilegeLevelResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "Requested level not available for this user", 0x81: "Requested level exceeds Channel and/or User Privilege Limit", 0x82: "Cannot disable User Level authentication", } } func (res *SetSessionPrivilegeLevelResponse) Format() string { return fmt.Sprintf("%v", res) } func (c *Client) SetSessionPrivilegeLevel(ctx context.Context, privilegeLevel PrivilegeLevel) (response *SetSessionPrivilegeLevelResponse, err error) { request := &SetSessionPrivilegeLevelRequest{ PrivilegeLevel: privilegeLevel, } response = &SetSessionPrivilegeLevelResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_sol_config_params.go000066400000000000000000000035261474110527100246260ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 26.2 Set SOL Configuration Parameters Command type SetSOLConfigParamRequest struct { ChannelNumber uint8 ParamSelector SOLConfigParamSelector ParamData []byte } type SetSOLConfigParamResponse struct { } func (req *SetSOLConfigParamRequest) Command() Command { return CommandSetSOLConfigParam } func (req *SetSOLConfigParamRequest) Pack() []byte { out := make([]byte, 2+len(req.ParamData)) packUint8(req.ChannelNumber, out, 0) packUint8(uint8(req.ParamSelector), out, 1) packBytes(req.ParamData, out, 2) return out } func (res *SetSOLConfigParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "parameter not supported", 0x81: "attempt to set the 'set in progress' value", 0x82: "attempt to write read-only parameter", 0x83: "attempt to read write-only parameter", } } func (res *SetSOLConfigParamResponse) Unpack(msg []byte) error { return nil } func (res *SetSOLConfigParamResponse) Format() string { return "" } func (c *Client) SetSOLConfigParam(ctx context.Context, channelNumber uint8, paramSelector SOLConfigParamSelector, paramData []byte) (response *SetSOLConfigParamResponse, err error) { request := &SetSOLConfigParamRequest{ ChannelNumber: channelNumber, ParamSelector: paramSelector, ParamData: paramData, } response = &SetSOLConfigParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) SetSOLConfigParamFor(ctx context.Context, channelNumber uint8, param SOLConfigParameter) error { if isNilSOLConfigParameter(param) { return fmt.Errorf("param is nil") } paramSelector, _, _ := param.SOLConfigParameter() paramData := param.Pack() _, err := c.SetSOLConfigParam(ctx, channelNumber, paramSelector, paramData) if err != nil { return fmt.Errorf("SetSOLConfigParam failed, err: %w", err) } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_set_system_boot_options.go000066400000000000000000000047671474110527100252730ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 28.12 Set System Boot Options Command type SetSystemBootOptionsParamRequest struct { // Parameter valid // - 1b = mark parameter invalid / locked // - 0b = mark parameter valid / unlocked MarkParameterInvalid bool // [6:0] - boot option parameter selector ParamSelector BootOptionParamSelector ParamData []byte } // Table 28-14, Boot Option Parameters type SetSystemBootOptionsParamResponse struct { } func (req *SetSystemBootOptionsParamRequest) Pack() []byte { out := make([]byte, 1+len(req.ParamData)) b := uint8(req.ParamSelector) if req.MarkParameterInvalid { b = setBit7(b) } else { b = clearBit7(b) } packUint8(b, out, 0) packBytes(req.ParamData, out, 1) return out } func (req *SetSystemBootOptionsParamRequest) Command() Command { return CommandSetSystemBootOptions } func (res *SetSystemBootOptionsParamResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "parameter not supported", 0x81: "attempt to set the 'set in progress' value (in parameter #0) when not in the 'set complete' state. (This completion code provides a way to recognize that another party has already 'claimed' the parameters)", 0x82: "attempt to write read-only parameter", } } func (res *SetSystemBootOptionsParamResponse) Unpack(msg []byte) error { return nil } func (res *SetSystemBootOptionsParamResponse) Format() string { return "" } // This command is used to set parameters that direct the system boot following a system power up or reset. // The boot flags only apply for one system restart. It is the responsibility of the system BIOS // to read these settings from the BMC and then clear the boot flags func (c *Client) SetSystemBootOptionsParam(ctx context.Context, request *SetSystemBootOptionsParamRequest) (response *SetSystemBootOptionsParamResponse, err error) { response = &SetSystemBootOptionsParamResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) SetSystemBootOptionsParamFor(ctx context.Context, param BootOptionParameter) error { if isNilBootOptionParameter(param) { return fmt.Errorf("param is nil") } paramSelector, _, _ := param.BootOptionParameter() paramData := param.Pack() request := &SetSystemBootOptionsParamRequest{ MarkParameterInvalid: false, ParamSelector: paramSelector, ParamData: paramData, } if _, err := c.SetSystemBootOptionsParam(ctx, request); err != nil { return fmt.Errorf("SetSystemBootOptionsParam failed, err: %w", err) } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_set_system_boot_options_others.go000066400000000000000000000042151474110527100266430ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) func (c *Client) SetBootParamSetInProgress(ctx context.Context, setInProgress SetInProgressState) error { param := &BootOptionParam_SetInProgress{ Value: setInProgress, } if err := c.SetSystemBootOptionsParamFor(ctx, param); err != nil { return fmt.Errorf("SetSystemBootOptionsFor failed, err: %w", err) } return nil } func (c *Client) SetBootParamBootFlags(ctx context.Context, bootFlags *BootOptionParam_BootFlags) error { if err := c.SetBootParamSetInProgress(ctx, SetInProgress_SetInProgress); err != nil { goto OUT } else { if err := c.SetSystemBootOptionsParamFor(ctx, bootFlags); err != nil { return fmt.Errorf("SetSystemBootOptions failed, err: %w", err) } } OUT: if err := c.SetBootParamSetInProgress(ctx, SetInProgress_SetComplete); err != nil { return fmt.Errorf("SetBootParamSetInProgress failed, err: %w", err) } return nil } func (c *Client) SetBootParamClearAck(ctx context.Context, by BootInfoAcknowledgeBy) error { param := &BootOptionParam_BootInfoAcknowledge{} switch by { case BootInfoAcknowledgeByBIOSPOST: param.ByBIOSPOST = true case BootInfoAcknowledgeByOSLoader: param.ByOSLoader = true case BootInfoAcknowledgeByOSServicePartition: param.ByOSServicePartition = true case BootInfoAcknowledgeBySMS: param.BySMS = true case BootInfoAcknowledgeByOEM: param.ByOEM = true } if err := c.SetSystemBootOptionsParamFor(ctx, param); err != nil { return fmt.Errorf("SetSystemBootOptionsFor failed, err: %w", err) } return nil } // SetBootDevice set the boot device for next boot. // persist of false means it applies to next boot only. // persist of true means this setting is persistent for all future boots. func (c *Client) SetBootDevice(ctx context.Context, bootDeviceSelector BootDeviceSelector, bootType BIOSBootType, persist bool) error { param := &BootOptionParam_BootFlags{ BootFlagsValid: true, Persist: persist, BIOSBootType: bootType, BootDeviceSelector: bootDeviceSelector, } if err := c.SetSystemBootOptionsParamFor(ctx, param); err != nil { return fmt.Errorf("SetSystemBootOptions failed, err: %w", err) } return nil } golang-github-bougou-go-ipmi-0.7.2/cmd_set_user_access.go000066400000000000000000000032301474110527100234300ustar00rootroot00000000000000package ipmi import "context" // 22.26 Set User Access Command type SetUserAccessRequest struct { EnableChanging bool RestrictedToCallback bool EnableLinkAuth bool EnableIPMIMessaging bool ChannelNumber uint8 UserID uint8 MaxPrivLevel uint8 SessionLimit uint8 } type SetUserAccessResponse struct { } func (req *SetUserAccessRequest) Command() Command { return CommandSetUserAccess } func (req *SetUserAccessRequest) Pack() []byte { out := make([]byte, 4) b := req.ChannelNumber & 0x0f if req.EnableChanging { b = setBit7(b) } if req.RestrictedToCallback { b = setBit6(b) } if req.EnableLinkAuth { b = setBit5(b) } if req.EnableIPMIMessaging { b = setBit4(b) } packUint8(b, out, 0) packUint8(req.UserID&0x3f, out, 1) packUint8(req.MaxPrivLevel&0x3f, out, 2) packUint8(req.SessionLimit&0x0f, out, 3) return out } func (res *SetUserAccessResponse) CompletionCodes() map[uint8]string { // Note: an implementation will not return an error completion code if the user // access level is set higher than the privilege limit for a given channel. If it is // desired to bring attention to this condition, it is up to software to check the // channel privilege limits set using the Set Channel Access command and // provide notification of any mismatch. return map[uint8]string{} } func (res *SetUserAccessResponse) Unpack(msg []byte) error { return nil } func (res *SetUserAccessResponse) Format() string { return "" } func (c *Client) SetUserAccess(ctx context.Context, request *SetUserAccessRequest) (response *SetUserAccessResponse, err error) { response = &SetUserAccessResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_user_password.go000066400000000000000000000056141474110527100240410ustar00rootroot00000000000000package ipmi import "context" // 22.30 Set User Password Command type SetUserPasswordRequest struct { // [5:0] - User ID. 000000b = reserved. (User ID 1 is permanently associated with User 1, the null user name). UserID uint8 // The BMC shall maintain an internal tag that indicates whether // the password was set as a 16-byte or as a 20-byte password. Stored20 bool Operation PasswordOperation Password string } type PasswordOperation uint8 const ( PasswordOperationDisableUser PasswordOperation = 0x00 PasswordOperationEnableUser PasswordOperation = 0x01 PasswordOperationSetPassword PasswordOperation = 0x02 PasswordOperationTestPassword PasswordOperation = 0x03 ) type SetUserPasswordResponse struct { // empty } func (req *SetUserPasswordRequest) Command() Command { return CommandSetUserPassword } func (req *SetUserPasswordRequest) Pack() []byte { out := make([]byte, 2) b := req.UserID & 0x3f if req.Stored20 { b = setBit7(b) } packUint8(b, out, 0) packUint8(uint8(req.Operation)&0x03, out, 1) if req.Operation == PasswordOperationSetPassword || req.Operation == PasswordOperationTestPassword { var passwordStored []byte if req.Stored20 { passwordStored = padBytes(req.Password, 20, 0x00) } else { passwordStored = padBytes(req.Password, 16, 0x00) } out = append(out, passwordStored...) } return out } func (res *SetUserPasswordResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetUserPasswordResponse) Unpack(msg []byte) error { return nil } func (res *SetUserPasswordResponse) Format() string { return "" } func (c *Client) SetUserPassword(ctx context.Context, userID uint8, password string, stored20 bool) (response *SetUserPasswordResponse, err error) { request := &SetUserPasswordRequest{ UserID: userID, Stored20: stored20, Operation: PasswordOperationSetPassword, Password: password, } response = &SetUserPasswordResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) TestUserPassword(ctx context.Context, userID uint8, password string, stored20 bool) (response *SetUserPasswordResponse, err error) { request := &SetUserPasswordRequest{ UserID: userID, Stored20: stored20, Operation: PasswordOperationTestPassword, Password: password, } response = &SetUserPasswordResponse{} err = c.Exchange(ctx, request, response) return } func (c *Client) DisableUser(ctx context.Context, userID uint8) (err error) { request := &SetUserPasswordRequest{ UserID: userID, Operation: PasswordOperationDisableUser, } response := &SetUserPasswordResponse{} err = c.Exchange(ctx, request, response) return err } func (c *Client) EnableUser(ctx context.Context, userID uint8) (err error) { request := &SetUserPasswordRequest{ UserID: userID, Operation: PasswordOperationEnableUser, } response := &SetUserPasswordResponse{} err = c.Exchange(ctx, request, response) return err } golang-github-bougou-go-ipmi-0.7.2/cmd_set_username.go000066400000000000000000000026351474110527100227600ustar00rootroot00000000000000package ipmi import "context" // 22.28 Set User Name Command type SetUsernameRequest struct { // [5:0] - User ID. 000000b = reserved. (User ID 1 is permanently associated with User 1, the null user name). UserID uint8 // User Name String in ASCII, 16 bytes, max. Strings with fewer than 16 // characters are terminated with a null (00h) character and 00h padded to 16 // bytes. When the string is read back using the Get User Name command, // those bytes shall be returned as 0s. // Here if string length is longer than 16, it would be auto truncated. Username string } type SetUsernameResponse struct { GUID [16]byte } func (req *SetUsernameRequest) Command() Command { return CommandSetUsername } func (req *SetUsernameRequest) Pack() []byte { out := make([]byte, 17) packUint8(req.UserID, out, 0) username := padBytes(req.Username, 16, 0x00) packBytes(username, out, 1) return out } func (res *SetUsernameResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SetUsernameResponse) Unpack(msg []byte) error { return nil } func (res *SetUsernameResponse) Format() string { return "" } func (c *Client) SetUsername(ctx context.Context, userID uint8, username string) (response *SetUsernameResponse, err error) { request := &SetUsernameRequest{ UserID: userID, Username: username, } response = &SetUsernameResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_set_watchdog_timer.go000066400000000000000000000026361474110527100241420ustar00rootroot00000000000000package ipmi import "context" // 27.6 Set Watchdog Timer Command type SetWatchdogTimerRequest struct { DontLog bool DontStopTimer bool TimerUse TimerUse PreTimeoutInterrupt PreTimeoutInterrupt TimeoutAction TimeoutAction PreTimeoutIntervalSec uint8 ExpirationFlags uint8 InitialCountdown uint16 } type SetWatchdogTimerResponse struct { } func (req *SetWatchdogTimerRequest) Pack() []byte { out := make([]byte, 6) b0 := uint8(req.TimerUse) if req.DontLog { b0 = setBit7(b0) } if req.DontStopTimer { b0 = setBit6(b0) } packUint8(b0, out, 0) b1 := uint8(req.TimeoutAction) b1 |= uint8(req.PreTimeoutInterrupt) << 4 packUint8(b1, out, 1) packUint8(req.PreTimeoutIntervalSec, out, 2) packUint8(req.ExpirationFlags, out, 3) packUint16L(req.InitialCountdown, out, 4) return out } func (req *SetWatchdogTimerRequest) Command() Command { return CommandSetWatchdogTimer } func (res *SetWatchdogTimerResponse) Unpack(msg []byte) error { return nil } func (res *SetWatchdogTimerResponse) CompletionCodes() map[uint8]string { // no command-specific cc return map[uint8]string{} } func (res *SetWatchdogTimerResponse) Format() string { return "" } func (c *Client) SetWatchdogTimer(ctx context.Context) (response *SetWatchdogTimerResponse, err error) { request := &SetWatchdogTimerRequest{} response = &SetWatchdogTimerResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_sol_activating.go000066400000000000000000000020221474110527100232620ustar00rootroot00000000000000package ipmi import "context" // 26.1 SOL Activating Command type SOLActivatingRequest struct { SessionState uint8 PayloadInstance uint8 FormatVersionMajor uint8 FormatVersionMinor uint8 } type SOLActivatingResponse struct { } func (req *SOLActivatingRequest) Command() Command { return CommandSOLActivating } func (req *SOLActivatingRequest) Pack() []byte { out := make([]byte, 4) packUint8(req.SessionState, out, 0) packUint8(req.PayloadInstance, out, 1) packUint8(req.FormatVersionMajor, out, 2) packUint8(req.FormatVersionMinor, out, 3) return out } func (res *SOLActivatingResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *SOLActivatingResponse) Unpack(msg []byte) error { return nil } func (res *SOLActivatingResponse) Format() string { return "" } func (c *Client) SOLActivating(ctx context.Context, request *SOLActivatingRequest) (response *SOLActivatingResponse, err error) { response = &SOLActivatingResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_suspend_bmc_arps.go000066400000000000000000000027561474110527100236210ustar00rootroot00000000000000package ipmi import "context" // 23.3 Suspend BMC ARPs Command type SuspendARPsRequest struct { ChannelNumber uint8 SuspendARP bool SuspendGratuitousARP bool } type SuspendARPsResponse struct { // Present state of ARP suspension IsARPOccurring bool IsGratuitousARPOccurring bool } func (req *SuspendARPsRequest) Pack() []byte { out := make([]byte, 2) packUint8(req.ChannelNumber, out, 0) var b uint8 if req.SuspendARP { b = setBit1(b) } if req.SuspendGratuitousARP { b = setBit0(b) } packUint8(b, out, 1) return out } func (req *SuspendARPsRequest) Command() Command { return CommandSuspendARPs } func (res *SuspendARPsResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "parameter not supported.", } } func (res *SuspendARPsResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } b, _, _ := unpackUint8(msg, 0) res.IsARPOccurring = isBit1Set(b) res.IsGratuitousARPOccurring = isBit0Set(b) return nil } func (res *SuspendARPsResponse) Format() string { return "" } func (c *Client) SuspendARPs(ctx context.Context, channelNumber uint8, suspendARP bool, suspendGratuitousARP bool) (response *SuspendARPsResponse, err error) { request := &SuspendARPsRequest{ ChannelNumber: channelNumber, SuspendARP: suspendARP, SuspendGratuitousARP: suspendGratuitousARP, } response = &SuspendARPsResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_warm_reset.go000066400000000000000000000012631474110527100224320ustar00rootroot00000000000000package ipmi import "context" // 20.3 Warm Reset Command type WarmResetRequest struct { // empty } type WarmResetResponse struct { } func (req *WarmResetRequest) Command() Command { return CommandWarmReset } func (req *WarmResetRequest) Pack() []byte { return []byte{} } func (res *WarmResetResponse) CompletionCodes() map[uint8]string { return map[uint8]string{} } func (res *WarmResetResponse) Unpack(msg []byte) error { return nil } func (res *WarmResetResponse) Format() string { return "" } func (c *Client) WarmReset(ctx context.Context) (err error) { request := &WarmResetRequest{} response := &WarmResetResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cmd_write_fru_data.go000066400000000000000000000031651474110527100232640ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) // 34.3 Write FRU Data Command type WriteFRUDataRequest struct { FRUDeviceID uint8 WriteOffset uint16 WriteData []byte } type WriteFRUDataResponse struct { CountWritten uint8 } func (req *WriteFRUDataRequest) Command() Command { return CommandWriteFRUData } func (req *WriteFRUDataRequest) Pack() []byte { out := make([]byte, 3+len(req.WriteData)) packUint8(req.FRUDeviceID, out, 0) packUint16L(req.WriteOffset, out, 1) if len(req.WriteData) > 0 { packBytes(req.WriteData, out, 3) } return out } func (res *WriteFRUDataResponse) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } res.CountWritten, _, _ = unpackUint8(msg, 0) return nil } func (r *WriteFRUDataResponse) CompletionCodes() map[uint8]string { return map[uint8]string{ 0x80: "write-protected offset", 0x81: "FRU device busy", } } func (res *WriteFRUDataResponse) Format() string { return fmt.Sprintf(`Count written : %d`, res.CountWritten) } // The command writes the specified byte or word to the FRU Inventory Info area. This is a low level direct interface to a non-volatile storage area. This means that the interface does not interpret or check any semantics or formatting for the data being written. func (c *Client) WriteFRUData(ctx context.Context, fruDeviceID uint8, writeOffset uint16, writeData []byte) (response *WriteFRUDataResponse, err error) { request := &WriteFRUDataRequest{ FRUDeviceID: fruDeviceID, WriteOffset: writeOffset, WriteData: writeData, } response = &WriteFRUDataResponse{} err = c.Exchange(ctx, request, response) return } golang-github-bougou-go-ipmi-0.7.2/cspell.json000066400000000000000000000054631474110527100212730ustar00rootroot00000000000000{ "version": "0.2", "ignorePaths": [], "dictionaryDefinitions": [], "dictionaries": [], "words": [ "ACPI", "Addin", "Algs", "Alloc", "ASIC", "asynch", "authcode", "authtype", "backpane", "backplane", "Bexp", "BIOSFRB", "BIOSPOST", "BIOSSMI", "BIST", "blocksize", "bootable", "Bootdev", "bootflag", "bootparam", "bougou", "buflen", "Busv", "Callin", "ccode", "CDROM", "CHANS", "cmdline", "CMDSPEC", "cmos", "Colling", "datasheet", "DCMI", "Deassert", "Deasserted", "Deassertion", "Deassertions", "Debugf", "devnum", "DIMM", "DMTF", "Dont", "DUID", "dword", "EEPROM", "efiboot", "EISA", "elist", "Firmwares", "fluidounce", "freeipmi", "frus", "Gbit", "getaccess", "getciphers", "goipmi", "heceta", "hmackey", "HMACSHA", "Huan", "ICMB", "IERR", "intf", "IOWR", "IPMB", "IPMICTL", "ipmidev", "ipmitool", "kbps", "KBPS", "Kuid", "lanplus", "libfreeipmi", "linearization", "lockkbd", "lockoutreset", "mcloc", "mgmt", "microcontroller", "Milli", "msbit", "NDSLAAC", "netfn", "nopoweroff", "nosel", "nsec", "nvmexpress", "OEMIANA", "OEMID", "olekukonko", "openipmi", "opensession", "overtemperature", "PASR", "PERR", "PIROM", "PowerGood", "Poweroff", "Preboot", "Println", "qword", "Rakp", "rerr", "resetbuttons", "Rexp", "Rmcp", "RMCP", "RMCPACK", "screenblank", "SDRBMC", "SDRFRU", "SDROEM", "SDRR", "sdrs", "SEEPROM", "selftest", "SELOEM", "sensorclass", "SERR", "sess", "setaccess", "SETTIME", "sievert", "SLAAC", "SMIC", "SMSOS", "SNMP", "SSIF", "sterad", "struct", "submatches", "subsys", "Supermicro", "SWID", "tablewriter", "thermalpolicy", "TMODE", "Truong", "twobyte", "typecode", "typelength", "UEFI", "Unitsbased", "VLANID", "wakeup" ], "ignoreWords": [], "import": [] } golang-github-bougou-go-ipmi-0.7.2/errors.go000066400000000000000000000015511474110527100207530ustar00rootroot00000000000000package ipmi import ( "errors" "fmt" ) var ( ErrUnpackedDataTooShort = errors.New("unpacked data is too short") ErrDCMIGroupExtensionIDMismatch = errors.New("DCMI group extension ID mismatch") ) func ErrUnpackedDataTooShortWith(actual int, expected int) error { return fmt.Errorf("%w (%d/%d)", ErrUnpackedDataTooShort, actual, expected) } func ErrNotEnoughDataWith(msg string, actual int, expected int) error { return fmt.Errorf("not enough data for %s (%d/%d)", msg, actual, expected) } func ErrDCMIGroupExtensionIDMismatchWith(expected uint8, actual uint8) error { return fmt.Errorf("%w: expected %#02x, got %#02x", ErrDCMIGroupExtensionIDMismatch, expected, actual) } func CheckDCMIGroupExenstionMatch(grpExt uint8) error { if grpExt != GroupExtensionDCMI { return ErrDCMIGroupExtensionIDMismatchWith(GroupExtensionDCMI, grpExt) } return nil } golang-github-bougou-go-ipmi-0.7.2/go.mod000066400000000000000000000010371474110527100202150ustar00rootroot00000000000000module github.com/bougou/go-ipmi replace github.com/bougou/go-ipmi v0.0.0 => ./ go 1.20 require ( github.com/google/uuid v1.1.2 github.com/kr/pretty v0.3.0 github.com/olekukonko/tablewriter v0.0.5 github.com/spf13/cobra v1.3.0 golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d ) require ( github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/rogpeppe/go-internal v1.6.1 // indirect github.com/spf13/pflag v1.0.5 // indirect ) golang-github-bougou-go-ipmi-0.7.2/go.sum000066400000000000000000002260301474110527100202440ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= golang-github-bougou-go-ipmi-0.7.2/helpers.go000066400000000000000000000365021474110527100211050ustar00rootroot00000000000000package ipmi import ( "bytes" "encoding/base32" "encoding/base64" "encoding/binary" "errors" "fmt" "math" "math/rand" "strconv" "time" "github.com/kr/pretty" "github.com/olekukonko/tablewriter" ) const timeFormat = time.RFC3339 func bytesForPrint(data []byte) string { out := "" for k, v := range data { if k%8 == 0 && k != 0 { out += "\n" } out += fmt.Sprintf("%02x ", v) } out += "\n" return out } func debugBytes(header string, data []byte, width int) { fmt.Printf("%s (%d bytes)\n", header, len(data)) for k, v := range data { if k%width == 0 && k != 0 { fmt.Printf("\n") } fmt.Printf("%02x ", v) } fmt.Printf("\n") } // debugf pretty print any object func debugf(format string, object ...interface{}) { pretty.Printf(format, object...) } func debug(header string, object interface{}) { if header == "" { pretty.Printf("%# v\n", object) } else { pretty.Printf("%s: \n%# v\n", header, object) } } func (c *Client) Debugf(format string, object ...interface{}) { if !c.debug { return } debugf(format, object...) } func (c *Client) Debug(header string, object interface{}) { if !c.debug { return } debug(header, object) } // DebugBytes print byte slices with a fixed width of bytes on each line. func (c *Client) DebugBytes(header string, data []byte, width int) { if !c.debug { return } debugBytes(header, data, width) } func (c *Client) DebugfRed(format string, object ...interface{}) { if !c.debug { return } const colorRed = "\033[0;31m" fmt.Printf(colorRed+format+"\033[0m", object...) } func (c *Client) DebugfGreen(format string, object ...interface{}) { if !c.debug { return } const colorGreen = "\033[0;32m" fmt.Printf(colorGreen+format+"\033[0m", object...) } func (c *Client) DebugfYellow(format string, object ...interface{}) { if !c.debug { return } const colorYellow = "\033[0;33m" fmt.Printf(colorYellow+format+"\033[0m", object...) } // 37 Timestamp Format func parseTimestamp(timestamp uint32) time.Time { return time.Unix(int64(timestamp), 0) } func formatBool(b bool, trueStr string, falseStr string) string { if b { return trueStr } return falseStr } // padBytes will padding the origin "s" string to fixed "width" length, // with "pad" as the padding byte. func padBytes(s string, width int, pad byte) []byte { o := []byte(s) if len(s) >= width { return o[:width] } for i := 0; i < width-len(s); i++ { o = append(o, pad) } return o } func isByteSliceEqual(b1 []byte, b2 []byte) bool { // not equal if both are nil if b1 == nil || b2 == nil { return false } if len(b1) != len(b2) { return false } for k := range b1 { if b1[k] != b2[k] { return false } } return true } func array16(s []byte) [16]byte { var out [16]byte copy(out[:16], s[:]) return out } func randomUint32() uint32 { r := rand.New(rand.NewSource(time.Now().Unix())) return r.Uint32() } func randomBytes(n int) []byte { r := rand.New(rand.NewSource(time.Now().Unix())) b := make([]byte, n) r.Read(b) return b } // onesComplement returns the signed integer of the input number encoded with 1's complement. // The lowest significant 'bitSize' bits of the input number i is considered. func onesComplement(i uint32, bitSize uint8) int32 { var leftBitSize uint8 = 32 - bitSize var temp uint32 = i << uint32(leftBitSize) >> uint32(leftBitSize) var mask uint32 = 1 << (bitSize - 1) if temp&mask == 0 { // means the bit at `bitSize-1` (from left starting at 0) is 0 // so the result should be a positive value return int32(temp) } // means the bit at `bitSize-1` (from left starting at 0) is 1 // so the result should be a negative value t := temp ^ 0xffff t = t << uint32(leftBitSize) >> uint32(leftBitSize) return -int32(t) } // twosComplement returns the signed integer of the input number encoded with 2's complement. // The lowest significant 'bitSize' bits of the input number i is considered. func twosComplement(i uint32, bitSize uint8) int32 { var leftBitSize uint8 = 32 - bitSize var temp uint32 = i << uint32(leftBitSize) >> uint32(leftBitSize) var mask uint32 = 1 << (bitSize - 1) if temp&mask == 0 { // means the bit at `bitSize-1` (from left starting at 0) is 0 // so the result should be a positive value return int32(temp) } // means the bit at `bitSize-1` (from left starting at 0) is 1 // so the result should be a negative value t := temp ^ 0xffff + 1 t = t << uint32(leftBitSize) >> uint32(leftBitSize) return -int32(t) } func onesComplementEncode(i int32, bitSize uint8) uint32 { if i >= 0 { return uint32(i) } var total int32 = int32(math.Pow(2, float64(bitSize))) - 1 return uint32(total + i) } func twosComplementEncode(i int32, bitSize uint8) uint32 { if i >= 0 { return uint32(i) } var total int32 = int32(math.Pow(2, float64(bitSize))) return uint32(total + i) } // The TCP/IP standard network byte order is big-endian. var base32HexNoPadEncoding = base32.HexEncoding.WithPadding(base32.NoPadding) func fromBase32(s []byte) (buf []byte, err error) { for i, b := range s { if b >= 'a' && b <= 'z' { s[i] = b - 32 } } buflen := base32HexNoPadEncoding.DecodedLen(len(s)) buf = make([]byte, buflen) n, err := base32HexNoPadEncoding.Decode(buf, s) buf = buf[:n] return } func toBase32(b []byte) string { return base32HexNoPadEncoding.EncodeToString(b) } func fromBase64(s []byte) (buf []byte, err error) { buflen := base64.StdEncoding.DecodedLen(len(s)) buf = make([]byte, buflen) n, err := base64.StdEncoding.Decode(buf, s) buf = buf[:n] return } func toBase64(b []byte) string { return base64.StdEncoding.EncodeToString(b) } func setBit7(b uint8) uint8 { return b | 0x80 } func setBit6(b uint8) uint8 { return b | 0x40 } func setBit5(b uint8) uint8 { return b | 0x20 } func setBit4(b uint8) uint8 { return b | 0x10 } func setBit3(b uint8) uint8 { return b | 0x08 } func setBit2(b uint8) uint8 { return b | 0x04 } func setBit1(b uint8) uint8 { return b | 0x02 } func setBit0(b uint8) uint8 { return b | 0x01 } func clearBit7(b uint8) uint8 { return b & 0x7f } func clearBit6(b uint8) uint8 { return b & 0xbf } func clearBit5(b uint8) uint8 { return b & 0xdf } func clearBit4(b uint8) uint8 { return b & 0xef } func clearBit3(b uint8) uint8 { return b & 0xf7 } func clearBit2(b uint8) uint8 { return b & 0xfb } func clearBit1(b uint8) uint8 { return b & 0xfd } func clearBit0(b uint8) uint8 { return b & 0xfe } func setOrClearBit7(b uint8, cond bool) uint8 { if cond { return b | 0x80 } return b & 0x7f } func setOrClearBit6(b uint8, cond bool) uint8 { if cond { return b | 0x40 } return b & 0xbf } func setOrClearBit5(b uint8, cond bool) uint8 { if cond { return b | 0x20 } return b & 0xdf } func setOrClearBit4(b uint8, cond bool) uint8 { if cond { return b | 0x10 } return b & 0xef } func setOrClearBit3(b uint8, cond bool) uint8 { if cond { return b | 0x08 } return b & 0xf7 } func setOrClearBit2(b uint8, cond bool) uint8 { if cond { return b | 0x04 } return b & 0xfb } func setOrClearBit1(b uint8, cond bool) uint8 { if cond { return b | 0x02 } return b & 0xfd } func setOrClearBit0(b uint8, cond bool) uint8 { if cond { return b | 0x01 } return b & 0xfe } func isBit7Set(b uint8) bool { return b&0x80 == 0x80 } func isBit6Set(b uint8) bool { return b&0x40 == 0x40 } func isBit5Set(b uint8) bool { return b&0x20 == 0x20 } func isBit4Set(b uint8) bool { return b&0x10 == 0x10 } func isBit3Set(b uint8) bool { return b&0x08 == 0x08 } func isBit2Set(b uint8) bool { return b&0x04 == 0x04 } func isBit1Set(b uint8) bool { return b&0x02 == 0x02 } func isBit0Set(b uint8) bool { return b&0x01 == 0x01 } func unpackUint8(msg []byte, off int) (uint8, int, error) { if off+1 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint8") } return msg[off], off + 1, nil } // packUint8 fills an uint8 value (i) into byte slice (msg) at the index of (offset) func packUint8(i uint8, msg []byte, off int) (int, error) { if off+1 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint8") } msg[off] = i return off + 1, nil } func packBytes(v []byte, msg []byte, off int) (int, error) { if off+len(v) > len(msg) { return len(msg), fmt.Errorf("overflow packing byte slice") } for k, b := range v { msg[off+k] = b } return off + len(v), nil } func unpackBytes(msg []byte, off int, length int) ([]byte, int, error) { out := []byte{} if off+length > len(msg) { return out, off, fmt.Errorf("overflow unpacking %d bytes", length) } out = append(out, msg[off:off+length]...) return out, off + length, nil } // unpackBytesMost unpacks most length of bytes from msg starting from off index. // It stops when reaching the msg end or reaching the most length. // This functions never failed, it always return nil error. // The caller should check the length of the returned out byte func unpackBytesMost(msg []byte, off int, length int) ([]byte, int, error) { out := make([]byte, length) var i int = 0 for ; i < length; i++ { if off+i >= len(msg) { break } out[i] = msg[off+i] } return out[:i], off + len(out), nil } func unpackUint16(msg []byte, off int) (uint16, int, error) { if off+2 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint16") } return binary.BigEndian.Uint16(msg[off:]), off + 2, nil } func unpackUint16L(msg []byte, off int) (uint16, int, error) { if off+2 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint16") } return binary.LittleEndian.Uint16(msg[off:]), off + 2, nil } func packUint16(i uint16, msg []byte, off int) (int, error) { if off+2 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint16") } binary.BigEndian.PutUint16(msg[off:], i) return off + 2, nil } func packUint16L(i uint16, msg []byte, off int) (int, error) { if off+2 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint16") } binary.LittleEndian.PutUint16(msg[off:], i) return off + 2, nil } func unpackUint24(msg []byte, off int) (uint32, int, error) { if off+3 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint32 as uint24") } i := uint32(msg[off])<<16 | uint32(msg[off+1])<<8 | uint32(msg[off+2]) off += 3 return i, off, nil } func unpackUint24L(msg []byte, off int) (uint32, int, error) { if off+3 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint32 as uint24") } i := uint32(msg[off]) | uint32(msg[off+1])<<8 | uint32(msg[off+2])<<16 off += 3 return i, off, nil } func packUint24(i uint32, msg []byte, off int) (int, error) { if off+3 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint32 as uint24") } msg[off] = byte(i >> 16) msg[off+1] = byte(i >> 8) msg[off+2] = byte(i) off += 3 return off, nil } func packUint24L(i uint32, msg []byte, off int) (int, error) { if off+3 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint32 as uint24") } msg[off] = byte(i) msg[off+1] = byte(i >> 8) msg[off+2] = byte(i >> 16) off += 3 return off, nil } func unpackUint32(msg []byte, off int) (uint32, int, error) { if off+4 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint32") } return binary.BigEndian.Uint32(msg[off:]), off + 4, nil } func unpackUint32L(msg []byte, off int) (uint32, int, error) { if off+4 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint32") } return binary.LittleEndian.Uint32(msg[off:]), off + 4, nil } func packUint32(i uint32, msg []byte, off int) (int, error) { if off+4 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint32") } binary.BigEndian.PutUint32(msg[off:], i) return off + 4, nil } func packUint32L(i uint32, msg []byte, off int) (int, error) { if off+4 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint32") } binary.LittleEndian.PutUint32(msg[off:], i) return off + 4, nil } func unpackUint48(msg []byte, off int) (uint64, int, error) { if off+6 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint64 as uint48") } i := uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 | uint64(msg[off+4])<<8 | uint64(msg[off+5]) off += 6 return i, off, nil } func unpackUint48L(msg []byte, off int) (uint64, int, error) { if off+6 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint64 as uint48") } i := uint64(msg[off]) | uint64(msg[off+1])<<8 | uint64(msg[off+2])<<16 | uint64(msg[off+3])<<24 | uint64(msg[off+4])<<32 | uint64(msg[off+5])<<40 off += 6 return i, off, nil } func packUint48(i uint64, msg []byte, off int) (int, error) { if off+6 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint64 as uint48") } msg[off] = byte(i >> 40) msg[off+1] = byte(i >> 32) msg[off+2] = byte(i >> 24) msg[off+3] = byte(i >> 16) msg[off+4] = byte(i >> 8) msg[off+5] = byte(i) off += 6 return off, nil } func packUint48L(i uint64, msg []byte, off int) (int, error) { if off+6 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint64 as uint48") } msg[off] = byte(i) msg[off+1] = byte(i >> 8) msg[off+2] = byte(i >> 16) msg[off+3] = byte(i >> 24) msg[off+4] = byte(i >> 32) msg[off+5] = byte(i >> 40) off += 6 return off, nil } func unpackUint64(msg []byte, off int) (uint64, int, error) { if off+8 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint64") } return binary.BigEndian.Uint64(msg[off:]), off + 8, nil } func unpackUint64L(msg []byte, off int) (uint64, int, error) { if off+8 > len(msg) { return 0, len(msg), fmt.Errorf("overflow unpacking uint64") } return binary.LittleEndian.Uint64(msg[off:]), off + 8, nil } func packUint64(i uint64, msg []byte, off int) (int, error) { if off+8 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint64") } binary.BigEndian.PutUint64(msg[off:], i) off += 8 return off, nil } func packUint64L(i uint64, msg []byte, off int) (int, error) { if off+8 > len(msg) { return len(msg), fmt.Errorf("overflow packing uint64") } binary.LittleEndian.PutUint64(msg[off:], i) off += 8 return off, nil } // 8421 BCD // bcdUint8 decodes BCD encoded integer to normal unsigned integer. func bcdUint8(i uint8) uint8 { msb4 := i >> 4 lsb4 := i & 0x0f return msb4*10 + lsb4 } func parseStringToInt64(s string) (int64, error) { if len(s) > 2 { if s[0] == '0' { return strconv.ParseInt(s, 0, 64) } } return strconv.ParseInt(s, 10, 64) } func formatTable(headers []string, rows [][]string) string { var buf = new(bytes.Buffer) table := tablewriter.NewWriter(buf) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.SetHeader(headers) table.SetFooter(headers) for _, row := range rows { table.Append(row) } table.Render() return buf.String() } // buildCanIgnoreFn returns a `canIgnore` function that can be used to check if a err // is a ResponseError with CompletionCode in specified codes. // If so, the `canIgnore` function returns nil, otherwise it returns the original err. func buildCanIgnoreFn(codes ...uint8) func(err error) error { return func(err error) error { if err == nil { return nil } var respErr *ResponseError if errors.As(err, &respErr) { cc := respErr.CompletionCode() for _, code := range codes { if uint8(cc) == code { return nil } } } return err } } // Generic function to convert a slice of any type to a slice of interface{} func convertToInterfaceSlice[T any](input []T) []interface{} { result := make([]interface{}, len(input)) for i, v := range input { result[i] = v } return result } golang-github-bougou-go-ipmi-0.7.2/helpers_hmac.go000066400000000000000000000073611474110527100220760ustar00rootroot00000000000000package ipmi import ( "crypto/aes" "crypto/cipher" "crypto/hmac" "crypto/md5" "crypto/rc4" "crypto/sha1" "crypto/sha256" "fmt" ) // generate_hmac generates message authentication code. // Currently supported algorithms are: "md5", "sha1", "sha256" // // hmac, hash-based message authentication code // mac, message authentication code // md, message digest func generate_hmac(alg string, data []byte, key []byte) ([]byte, error) { switch alg { case "md5": h := hmac.New(md5.New, key) _, err := h.Write(data) if err != nil { return nil, fmt.Errorf("hmac md5 failed, err: %w", err) } return h.Sum(nil), nil case "sha1": h := hmac.New(sha1.New, key) _, err := h.Write(data) if err != nil { return nil, fmt.Errorf("hmac sha1 failed, err: %w", err) } return h.Sum(nil), nil case "sha256": h := hmac.New(sha256.New, key) _, err := h.Write(data) if err != nil { return nil, fmt.Errorf("hmac sha256 failed, err: %w", err) } return h.Sum(nil), nil default: return nil, fmt.Errorf("not support for hmac algorithm %s", alg) } } func generate_auth_hmac(authAlg interface{}, data []byte, key []byte) ([]byte, error) { algorithm := "" switch authAlg.(type) { case AuthAlg: switch authAlg { case AuthAlgRAKP_HMAC_SHA1: algorithm = "sha1" case AuthAlgRAKP_HMAC_MD5: algorithm = "md5" case AuthAlgRAKP_HMAC_SHA256: algorithm = "sha256" default: return nil, fmt.Errorf("not support for authentication algorithm %x", authAlg) } case IntegrityAlg: switch authAlg { case IntegrityAlg_HMAC_SHA1_96: algorithm = "sha1" case IntegrityAlg_HMAC_MD5_128: algorithm = "md5" case IntegrityAlg_HMAC_SHA256_128: algorithm = "sha256" default: return nil, fmt.Errorf("not support for integrity algorithm %x", authAlg) } } if len(algorithm) == 0 { return []byte{}, nil } else { return generate_hmac(algorithm, data, key) } } // The plainText must be already padded. // The cipherKey length is either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. func encryptAES(plainText []byte, cipherKey []byte, iv []byte) ([]byte, error) { if len(plainText)%aes.BlockSize != 0 { return nil, fmt.Errorf("input plainText must be multiple of aes block size (16)") } l := len(cipherKey) if l != 16 && l != 24 && l != 32 { return nil, fmt.Errorf("cipherKey length must be either 16, 24, 32") } cipherBlock, err := aes.NewCipher(cipherKey) if err != nil { return nil, fmt.Errorf("NewCipher failed, err: %w", err) } cipherText := make([]byte, len(plainText)) mode := cipher.NewCBCEncrypter(cipherBlock, iv) mode.CryptBlocks(cipherText, plainText) return cipherText, nil } func decryptAES(cipherText []byte, cipherKey []byte, iv []byte) ([]byte, error) { l := len(cipherKey) if l != 16 && l != 24 && l != 32 { return nil, fmt.Errorf("cipherKey length must be either 16, 24, 32") } cipherBlock, err := aes.NewCipher(cipherKey) if err != nil { return nil, fmt.Errorf("NewCipher failed, err: %w", err) } plainText := make([]byte, len(cipherText)) mode := cipher.NewCBCDecrypter(cipherBlock, iv) mode.CryptBlocks(plainText, cipherText) return plainText, nil } func encryptRC4(plainText []byte, cipherKey []byte, iv []byte) ([]byte, error) { rc4Cipher, err := rc4.NewCipher(cipherKey) if err != nil { return nil, fmt.Errorf("NewCipher failed, err: %w", err) } cipherText := make([]byte, len(plainText)) rc4Cipher.XORKeyStream(cipherText, plainText) return cipherText, nil } func decryptRC4(cipherText []byte, cipherKey []byte, iv []byte) ([]byte, error) { rc4Cipher, err := rc4.NewCipher(cipherKey) if err != nil { return nil, fmt.Errorf("NewCipher failed, err: %w", err) } plainText := make([]byte, len(cipherText)) rc4Cipher.XORKeyStream(plainText, cipherText) return plainText, nil } golang-github-bougou-go-ipmi-0.7.2/helpers_hmac_test.go000066400000000000000000000057701474110527100231370ustar00rootroot00000000000000package ipmi import ( "fmt" "testing" ) func Test_encryptAES(t *testing.T) { cases := []struct { name string ipmiRequestBody []byte iv []byte key []byte expected []byte }{ { name: "test1", ipmiRequestBody: []byte{ 0x20, 0x18, 0xc8, 0x81, 0x04, 0x3b, 0x04, 0x3c, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, }, iv: []byte{ 0x00, 0xdf, 0x5e, 0x2a, 0x2b, 0x37, 0x2e, 0x80, 0x7a, 0xe5, 0x5b, 0x0c, 0x37, 0x3c, 0x37, 0x69, }, key: []byte{ 0x12, 0x0e, 0x6b, 0x20, 0xe1, 0xe5, 0x2d, 0x13, 0xa0, 0x4a, 0x2b, 0xb8, 0x3d, 0x0d, 0x38, 0xa1, }, expected: []byte{ 0x47, 0x9c, 0x2f, 0x65, 0xfb, 0x59, 0x75, 0x19, 0x71, 0xa2, 0x96, 0xa3, 0x77, 0x15, 0x55, 0x69, }, }, { name: "test2", ipmiRequestBody: []byte{ 0x20, 0x18, 0xc8, 0x81, 0x04, 0x3b, 0x04, 0x3c, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, }, iv: []byte{ 0x00, 0xdf, 0x5e, 0x2a, 0x2b, 0x37, 0x2e, 0x80, 0x7a, 0xe5, 0x5b, 0x0c, 0x37, 0x3c, 0x37, 0x69, }, key: []byte{ 0x12, 0x0e, 0x6b, 0x20, 0xe1, 0xe5, 0x2d, 0x13, 0xa0, 0x4a, 0x2b, 0xb8, 0x3d, 0x0d, 0x38, 0xa1, }, expected: []byte{ 0x47, 0x9c, 0x2f, 0x65, 0xfb, 0x59, 0x75, 0x19, 0x71, 0xa2, 0x96, 0xa3, 0x77, 0x15, 0x55, 0x69, }, }, } for _, v := range cases { got, err := encryptAES(v.ipmiRequestBody, v.key, v.iv) if err != nil { t.Errorf("encryptAES failed, err: %s", err) } if !isByteSliceEqual(got, v.expected) { t.Errorf("got does not match expected, got: %v, want: %v", got, v.expected) } } } func Test_AES_Decrypt(t *testing.T) { ivStr := "1234567890123456" cipherKey := "12345678901234567890123456789012" plainText := "abcdefghijklmnopqrstuvwxyzABCDEF" cipherText, err := encryptAES([]byte(plainText), []byte(cipherKey), []byte(ivStr)) if err != nil { t.Error(err) } p, err := decryptAES([]byte(cipherText), []byte(cipherKey), []byte(ivStr)) if err != nil { t.Error(err) } if len(plainText) != len(p) { t.Error("Not equal") } for k, v := range []byte(plainText) { if v != p[k] { t.Errorf("not equal at %d", k) } } } func Test_RC4_Encrypt(t *testing.T) { ivStr := "1234567890123456" cipherKey := "12345678901234567890123456789012" plainText := "abcdefghijklmnopqrstuvwxyzABCDEF" cipherText, err := encryptRC4([]byte(plainText), []byte(cipherKey), []byte(ivStr)) if err != nil { t.Error(err) } fmt.Println(string(cipherText)) fmt.Println(cipherText) } func Test_RC4_Decrypt(t *testing.T) { ivStr := "1234567890123456" cipherKey := "12345678901234567890123456789012" plainText := "abcdefghijklmnopqrstuvwxyzABCDEF" cipherText, err := encryptRC4([]byte(plainText), []byte(cipherKey), []byte(ivStr)) if err != nil { t.Error(err) } p, err := decryptRC4([]byte(cipherText), []byte(cipherKey), []byte(ivStr)) if err != nil { t.Error(err) } fmt.Println(string(p)) if len(plainText) != len(p) { t.Error("Not equal") } for k, v := range []byte(plainText) { if v != p[k] { t.Errorf("not equal at %d", k) } } } golang-github-bougou-go-ipmi-0.7.2/helpers_test.go000066400000000000000000000065271474110527100221500ustar00rootroot00000000000000package ipmi import ( "testing" ) func Test_onesComplement(t *testing.T) { // https://en.wikipedia.org/wiki/Ones%27_complement tests := []struct { name string input uint32 bitSize uint8 expected int32 }{ {"test1", 127, 8, 127}, {"test2", 126, 8, 126}, {"test3", 2, 8, 2}, {"test4", 1, 8, 1}, {"test5", 0, 8, 0}, {"test6", 255, 8, -0}, {"test7", 254, 8, -1}, {"test8", 253, 8, -2}, {"test9", 129, 8, -126}, {"test10", 128, 8, -127}, } for _, test := range tests { got := onesComplement(test.input, test.bitSize) if got != test.expected { t.Errorf("test %s not matched, got: %d, expected: %d", test.name, got, test.expected) } } } func Test_twosComplement(t *testing.T) { // https://en.wikipedia.org/wiki/Two%27s_complement tests := []struct { name string input uint32 bitSize uint8 expected int32 }{ {"test1", 0, 8, 0}, {"test2", 1, 8, 1}, {"test3", 2, 8, 2}, {"test4", 126, 8, 126}, {"test5", 127, 8, 127}, {"test6", 128, 8, -128}, {"test7", 129, 8, -127}, {"test8", 130, 8, -126}, {"test9", 254, 8, -2}, {"test10", 255, 8, -1}, } for _, test := range tests { got := twosComplement(test.input, test.bitSize) if got != test.expected { t.Errorf("test %s not matched, got: %d, expected: %d", test.name, got, test.expected) } } } func Test_onesComplementEncode(t *testing.T) { // https://en.wikipedia.org/wiki/Ones%27_complement tests := []struct { name string expected uint32 bitSize uint8 input int32 }{ {"test1", 127, 8, 127}, {"test2", 126, 8, 126}, {"test3", 2, 8, 2}, {"test4", 1, 8, 1}, {"test5", 0, 8, 0}, // {"test6", 255, 8, -0}, {"test7", 254, 8, -1}, {"test8", 253, 8, -2}, {"test9", 129, 8, -126}, {"test10", 128, 8, -127}, } for _, test := range tests { got := onesComplementEncode(test.input, test.bitSize) if got != test.expected { t.Errorf("test %s not matched, got: %d, expected: %d", test.name, got, test.expected) } } } func Test_twosComplementEncode(t *testing.T) { // https://en.wikipedia.org/wiki/Two%27s_complement tests := []struct { name string expected uint32 bitSize uint8 input int32 }{ {"test1", 0, 8, 0}, {"test2", 1, 8, 1}, {"test3", 2, 8, 2}, {"test4", 126, 8, 126}, {"test5", 127, 8, 127}, {"test6", 128, 8, -128}, {"test7", 129, 8, -127}, {"test8", 130, 8, -126}, {"test9", 254, 8, -2}, {"test10", 255, 8, -1}, } for _, test := range tests { got := twosComplementEncode(test.input, test.bitSize) if got != test.expected { t.Errorf("test %s not matched, got: %d, expected: %d", test.name, got, test.expected) } } } func Test_unpackBytes(t *testing.T) { tests := []struct { name string expected []byte input []uint8 offset int length int }{ {"test1", []byte{0x03, 0x04}, []uint8{0x01, 0x02, 0x03, 0x04}, 2, 2}, {"test2", []byte{0x04, 0x05, 0x06, 0x07}, []uint8{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, 3, 4}, {"test3", []byte{}, []uint8{}, 0, 0}, {"test4", []byte{0x01}, []uint8{0x01}, 0, 1}, } for _, tt := range tests { got, _, err := unpackBytes(tt.input, tt.offset, tt.length) if err != nil { t.Errorf("test (%s) unpackBytes failed, err: %s", tt.name, err) return } if !isByteSliceEqual(got, tt.expected) { t.Errorf("test %s not matched, got: %v, expected: %v", tt.name, got, tt.expected) return } } } golang-github-bougou-go-ipmi-0.7.2/interface_lan.go000066400000000000000000000232261474110527100222340ustar00rootroot00000000000000package ipmi import ( "bytes" "context" "errors" "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 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 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(ctx context.Context, 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(ctx, reqCmd) if err != nil { return 0, nil, fmt.Errorf("BuildIPMIRequest failed, err: %w", err) } c.Debug(">>>> IPMI Request", ipmiReq) rawPayload = ipmiReq.Pack() } return payloadType, rawPayload, nil } func (c *Client) exchangeLAN(ctx context.Context, request Request, response Response) error { c.Debug(">> Command Request", request) rmcp, err := c.BuildRmcpRequest(ctx, request) if err != nil { return fmt.Errorf("build RMCP+ request msg failed, err: %w", err) } c.Debug(">>>>>> RMCP Request", rmcp) sent := rmcp.Pack() c.DebugBytes("sent", sent, 16) recv, err := c.udpClient.Exchange(ctx, bytes.NewReader(sent)) if err != nil { return fmt.Errorf("client udp exchange msg failed, err: %w", err) } c.DebugBytes("recv", recv, 16) if err := c.ParseRmcpResponse(ctx, 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(ctx context.Context) error { var ( err error channelNumber uint8 = ChannelNumberSelf ) if c.maxPrivilegeLevel == PrivilegeLevelUnspecified { c.maxPrivilegeLevel = PrivilegeLevelAdministrator } _, err = c.GetChannelAuthenticationCapabilities(ctx, channelNumber, c.maxPrivilegeLevel) if err != nil { return fmt.Errorf("GetChannelAuthenticationCapabilities failed, err: %w", err) } _, err = c.GetSessionChallenge(ctx) if err != nil { return fmt.Errorf("GetSessionChallenge failed, err: %w", err) } c.session.v15.preSession = true _, err = c.ActivateSession(ctx) if err != nil { return fmt.Errorf("ActivateSession failed, err: %w", err) } _, err = c.SetSessionPrivilegeLevel(ctx, c.maxPrivilegeLevel) if err != nil { return fmt.Errorf("SetSessionPrivilegeLevel to (%s) failed, err: %s", c.maxPrivilegeLevel, err) } go func() { c.keepSessionAlive(ctx, DefaultKeepAliveIntervalSec) }() return nil } // see 13.15 IPMI v2.0/RMCP+ Session Activation func (c *Client) Connect20(ctx context.Context) error { var ( err error channelNumber uint8 = ChannelNumberSelf ) if c.maxPrivilegeLevel == PrivilegeLevelUnspecified { c.maxPrivilegeLevel = PrivilegeLevelAdministrator } _, err = c.GetChannelAuthenticationCapabilities(ctx, channelNumber, c.maxPrivilegeLevel) if err != nil { return fmt.Errorf("cmd: Get Channel Authentication Capabilities failed, err: %w", err) } tryCiphers := c.findBestCipherSuites(ctx) if c.session.v20.cipherSuiteID != CipherSuiteIDReserved { // client explicitly specified a cipher suite to use tryCiphers = []CipherSuiteID{c.session.v20.cipherSuiteID} } c.DebugfGreen("\n\ntry ciphers (%v)\n", tryCiphers) var success bool errs := []error{} // try different cipher suites for opensession/rakp1/rakp3 for _, cipherSuiteID := range tryCiphers { c.DebugfGreen("\n\ntry cipher suite id (%v)\n\n\n", cipherSuiteID) c.session.v20.cipherSuiteID = cipherSuiteID _, err = c.OpenSession(ctx) if err != nil { errs = append(errs, fmt.Errorf("cmd: RMCP+ Open Session failed with cipher suite id (%v), err: %s", cipherSuiteID, err)) continue } _, err = c.RAKPMessage1(ctx) if err != nil { errs = append(errs, fmt.Errorf("cmd: rakp1 failed with cipher suite id (%v), err: %s", cipherSuiteID, err)) continue } _, err = c.RAKPMessage3(ctx) if err != nil { errs = append(errs, fmt.Errorf("cmd: rakp3 failed with cipher suite id (%v), err: %s", cipherSuiteID, err)) continue } c.DebugfGreen("\n\nconnect20 success with cipher suite id (%v)\n\n\n", cipherSuiteID) success = true break } if !success { return fmt.Errorf("connect20 failed after try all cipher suite ids (%v), errs: \n%v", tryCiphers, errors.Join(errs...)) } _, err = c.SetSessionPrivilegeLevel(ctx, c.maxPrivilegeLevel) if err != nil { return fmt.Errorf("SetSessionPrivilegeLevel to (%s) failed, err: %s", c.maxPrivilegeLevel, err) } go func() { c.keepSessionAlive(ctx, DefaultKeepAliveIntervalSec) }() 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(ctx context.Context) error { var ( err error channelNumber uint8 = ChannelNumberSelf privilegeLevel PrivilegeLevel = PrivilegeLevelAdministrator ) // force use IPMI v1.5 first c.v20 = false cap, err := c.GetChannelAuthenticationCapabilities(ctx, channelNumber, privilegeLevel) if err != nil { return fmt.Errorf("cmd: Get Channel Authentication Capabilities failed, err: %w", err) } if cap.SupportIPMIv20 { c.v20 = true return c.Connect20(ctx) } if cap.SupportIPMIv15 { return c.Connect15(ctx) } 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(ctx context.Context) error { // close the channel to notify the keepAliveSession goroutine to stop close(c.closedCh) 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(ctx, request); err != nil { return fmt.Errorf("CloseSession failed, err: %w", err) } if err := c.udpClient.Close(); err != nil { return fmt.Errorf("close udp connection failed, err: %w", err) } return nil } // 6.12.15 Session Inactivity Timeouts func (c *Client) keepSessionAlive(ctx context.Context, intervalSec int) { var period = time.Duration(intervalSec) * time.Second ticker := time.NewTicker(period) defer ticker.Stop() c.Debugf("keepSessionAlive started") for { select { case <-ticker.C: if _, err := c.GetCurrentSessionInfo(ctx); err != nil { c.DebugfRed("keepSessionAlive failed, GetCurrentSessionInfo failed, err: %w", err) } case <-c.closedCh: c.Debugf("got close signal, keepSessionAlive stopped") return } } } golang-github-bougou-go-ipmi-0.7.2/interface_system.go000066400000000000000000000072671474110527100230150ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "math/rand" "os" "unsafe" "github.com/bougou/go-ipmi/open" ) type openipmi struct { myAddr uint8 msgID int64 targetAddr uint8 targetChannel uint8 targetIPMBAddr uint8 transitAddr uint8 transitLUN uint8 file *os.File // /dev/ipmi0 } // ConnectOpen try to initialize the client by open the device of linux ipmi driver. func (c *Client) ConnectOpen(ctx context.Context, devnum int32) error { c.Debugf("Using ipmi device %d\n", devnum) // try the following devices var ( ipmiDev1 string = fmt.Sprintf("/dev/ipmi%d", devnum) ipmiDev2 string = fmt.Sprintf("/dev/ipmi/%d", devnum) ipmiDev3 string = fmt.Sprintf("/dev/ipmidev/%d", devnum) ) var file *os.File var tryOpenFile = func(ipmiDev string) { if file != nil { return } if f, err := os.OpenFile(ipmiDev, os.O_RDWR, 0); err != nil { c.Debugf("can not open ipmi dev (%s), err: %s\n", ipmiDev, err) } else { file = f c.Debugf("opened ipmi dev file: %v\n", ipmiDev) } } tryOpenFile(ipmiDev1) tryOpenFile(ipmiDev2) tryOpenFile(ipmiDev3) if file == nil { return fmt.Errorf("ipmi dev file not opened") } c.Debugf("opened ipmi dev file: %v, descriptor is: %d\n", file, file.Fd()) // set opened ipmi dev file c.openipmi.file = file var receiveEvents uint32 = 1 if err := open.IOCTL(c.openipmi.file.Fd(), open.IPMICTL_SET_GETS_EVENTS_CMD, uintptr(unsafe.Pointer(&receiveEvents))); err != nil { return fmt.Errorf("ioctl failed, cloud not enable event receiver, err: %w", err) } return nil } // closeOpen closes the ipmi dev file. func (c *Client) closeOpen(ctx context.Context) error { if err := c.openipmi.file.Close(); err != nil { return fmt.Errorf("close open file failed, err: %w", err) } return nil } func (c *Client) exchangeOpen(ctx context.Context, request Request, response Response) error { if c.openipmi.targetAddr != 0 && c.openipmi.targetAddr != c.openipmi.myAddr { } else { // otherwise use system interface c.Debugf("\nSending request [%s] (%#02x) to System Interface\n", request.Command().Name, request.Command().ID) } recv, err := c.openSendRequest(ctx, request) if err != nil { return fmt.Errorf("openSendRequest failed, err: %w", err) } c.DebugBytes("recv data", recv, 16) c.Debugf("\n\n") // recv[0] is cc if len(recv) < 1 { return fmt.Errorf("recv data at least contains one completion code byte") } ccode := recv[0] if ccode != 0x00 { return &ResponseError{ completionCode: CompletionCode(ccode), description: fmt.Sprintf("ipmiRes CompletionCode (%#02x) is not normal: %s", ccode, StrCC(response, ccode)), } } var unpackData = []byte{} if len(recv) > 1 { unpackData = recv[1:] } if err := response.Unpack(unpackData); err != nil { return &ResponseError{ completionCode: CompletionCode(recv[0]), description: fmt.Sprintf("unpack response failed, err: %s", err), } } c.Debug("<< Command Response", response) return nil } func (c *Client) openSendRequest(ctx context.Context, request Request) ([]byte, error) { var dataPtr *byte cmdData := request.Pack() c.DebugBytes("cmdData", cmdData, 16) if len(cmdData) > 0 { dataPtr = &cmdData[0] } c.DebugBytes("cmd data", cmdData, 16) msg := &open.IPMI_MSG{ NetFn: uint8(request.Command().NetFn), Cmd: uint8(request.Command().ID), Data: dataPtr, DataLen: uint16(len(cmdData)), } addr := &open.IPMI_SYSTEM_INTERFACE_ADDR{ AddrType: open.IPMI_SYSTEM_INTERFACE_ADDR_TYPE, Channel: open.IPMI_BMC_CHANNEL, } req := &open.IPMI_REQ{ Addr: addr, AddrLen: int(unsafe.Sizeof(addr)), MsgID: rand.Int63(), Msg: *msg, } c.Debug("IPMI_REQ", req) return open.SendCommand(c.openipmi.file, req, c.timeout) } golang-github-bougou-go-ipmi-0.7.2/interface_tool.go000066400000000000000000000051011474110527100224270ustar00rootroot00000000000000package ipmi import ( "bytes" "context" "encoding/hex" "fmt" "os/exec" "regexp" "strconv" "strings" ) var ( toolError = regexp.MustCompile(`^Unable to send RAW command \(channel=0x(?P[0-9a-fA-F]+) netfn=0x(?P[0-9a-fA-F]+) lun=0x(?P[0-9a-fA-F]+) cmd=0x(?P[0-9a-fA-F]+) rsp=0x(?P[0-9a-fA-F]+)\): (?P.*)`) ) // ConnectTool try to initialize the client. func (c *Client) ConnectTool(ctx context.Context, devnum int32) error { return nil } // closeTool closes the ipmi dev file. func (c *Client) closeTool(ctx context.Context) error { return nil } func (c *Client) exchangeTool(ctx context.Context, request Request, response Response) error { data := request.Pack() msg := make([]byte, 2+len(data)) msg[0] = uint8(request.Command().NetFn) msg[1] = uint8(request.Command().ID) copy(msg[2:], data) args := append([]string{"raw"}, rawEncode(msg)...) path := c.Host if path == "" { path = "ipmitool" } cmd := exec.Command(path, args...) var stdout bytes.Buffer var stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr c.Debugf(">>> Run cmd: \n>>> %s\n", cmd.String()) err := cmd.Run() if err != nil { if bytes.HasPrefix(stderr.Bytes(), []byte("Unable to send RAW command")) { submatches := toolError.FindSubmatch(stderr.Bytes()) if len(submatches) == 7 && len(submatches[5]) == 2 { code, err := strconv.ParseUint(string(submatches[5]), 16, 0) if err != nil { return fmt.Errorf("CompletionCode parse failed, err: %w", err) } return &ResponseError{ completionCode: CompletionCode(uint8(code)), description: fmt.Sprintf("Raw command failed, err: %s", string(submatches[6])), } } } return fmt.Errorf("ipmitool run failed, err: %w", err) } output := stdout.String() resp, err := rawDecode(strings.TrimSpace(output)) if err != nil { return fmt.Errorf("decode response failed, err: %w", err) } if err := response.Unpack(resp); err != nil { return fmt.Errorf("unpack response failed, err: %w", err) } return nil } func rawDecode(data string) ([]byte, error) { var buf bytes.Buffer data = strings.ReplaceAll(data, "\n", "") for _, s := range strings.Split(data, " ") { b, err := hex.DecodeString(s) if err != nil { return nil, err } _, err = buf.Write(b) if err != nil { return nil, err } } return buf.Bytes(), nil } func rawEncode(data []byte) []string { n := len(data) buf := make([]string, 0, n) // ipmitool needs every byte to be a separate argument for i := 0; i < n; i++ { buf = append(buf, "0x"+hex.EncodeToString(data[i:i+1])) } return buf } golang-github-bougou-go-ipmi-0.7.2/open/000077500000000000000000000000001474110527100200475ustar00rootroot00000000000000golang-github-bougou-go-ipmi-0.7.2/open/ioctl.go000066400000000000000000000041171474110527100215130ustar00rootroot00000000000000package open // see: https://github.com/torvalds/linux/blob/master/arch/alpha/include/uapi/asm/ioctl.h // cSpell:disable const ( IOC_NRBITS = 8 IOC_TYPEBITS = 8 IOC_SIZEBITS = 14 IOC_DIRBITS = 2 // Direction bits // NOTE, if IOC_DIRBITS=3, then IOC_NONE=0, IOC_READ=2, IOC_WRITE=4 IOC_NONE = 0x0 IOC_READ = 0x1 IOC_WRITE = 0x2 IOC_NRMASK = ((1 << IOC_NRBITS) - 1) IOC_TYPEMASK = ((1 << IOC_TYPEBITS) - 1) IOC_SIZEMASK = ((1 << IOC_SIZEBITS) - 1) IOC_DIRMASK = ((1 << IOC_DIRBITS) - 1) IOC_NRSHIFT = 0 IOC_TYPESHIFT = (IOC_NRSHIFT + IOC_NRBITS) IOC_SIZESHIFT = (IOC_TYPESHIFT + IOC_TYPEBITS) IOC_DIRSHIFT = (IOC_SIZESHIFT + IOC_SIZEBITS) // ...and for the drivers/sound files... IOC_IN = (IOC_WRITE << IOC_DIRSHIFT) IOC_OUT = (IOC_READ << IOC_DIRSHIFT) IOC_INOUT = ((IOC_WRITE | IOC_READ) << IOC_DIRSHIFT) IOCSIZE_MASK = (IOC_SIZEMASK << IOC_SIZESHIFT) IOCSIZE_SHIFT = (IOC_SIZESHIFT) ) func IOC(dir uintptr, typ uintptr, nr uintptr, size uintptr) uintptr { // 00000000 00000000 00000000 00000000 // |- NR // |- TYPE // |- SIZE // |- DIR return (dir << IOC_DIRSHIFT) | (typ << IOC_TYPESHIFT) | (nr << IOC_NRSHIFT) | (size << IOC_SIZESHIFT) } // used to create numbers func IO(typ, nr uintptr) uintptr { return IOC(IOC_NONE, typ, nr, 0) } func IOR(typ, nr, size uintptr) uintptr { return IOC(IOC_READ, typ, nr, size) } func IOW(typ, nr, size uintptr) uintptr { return IOC(IOC_WRITE, typ, nr, size) } func IOWR(typ, nr, size uintptr) uintptr { return IOC(IOC_READ|IOC_WRITE, typ, nr, size) } // IOC_DIR is used to decode DIR from nr func IOC_DIR(nr uintptr) uintptr { return (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) } // IOC_TYPE is used to decode TYPE from nr func IOC_TYPE(nr uintptr) uintptr { return (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) } // IOC_NR is used to decode NR from nr func IOC_NR(nr uintptr) uintptr { return (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) } // IOC_SIZE is used to decode SIZE from nr func IOC_SIZE(nr uintptr) uintptr { return (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) } golang-github-bougou-go-ipmi-0.7.2/open/ioctl_unix.go000066400000000000000000000006421474110527100225550ustar00rootroot00000000000000//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris package open import ( "fmt" "syscall" ) func IOCTL(fd, name, data uintptr) error { _, _, ep := syscall.Syscall(syscall.SYS_IOCTL, fd, name, data) if ep != 0 { return fmt.Errorf("syscall err: (%#02x) %s", uint8(ep), syscall.Errno(ep)) } return nil } golang-github-bougou-go-ipmi-0.7.2/open/ioctl_windows.go000066400000000000000000000001471474110527100232640ustar00rootroot00000000000000package open func IOCTL(fd, name, data uintptr) error { // Todo, implement for windows return nil } golang-github-bougou-go-ipmi-0.7.2/open/ipmi.go000066400000000000000000000146161474110527100213440ustar00rootroot00000000000000package open import ( "fmt" "time" "unsafe" ) // see: https://github.com/u-root/u-root/blob/v0.8.0/pkg/ipmi/ipmi.go // Note, this file basically is a Go conversion of https://github.com/torvalds/linux/blob/master/include/uapi/linux/ipmi.h const ( IPMI_IOC_MAGIC uintptr = 'i' IPMI_BUF_SIZE = 1024 IPMI_FILE_READ_TIMEOUT time.Duration = time.Second * 10 IPMI_MAX_ADDR_SIZE = 32 // Channel for talking directly with the BMC. When using this // channel, This is for the system interface address type only. IPMI_BMC_CHANNEL = 0xf IPMI_NUM_CHANNELS = 0x10 // Receive types for messages coming from the receive interface. // This is used for the receive in-kernel interface and in the receive IOCTL. // // The "IPMI_RESPONSE_RESPONSE_TYPE" is a little strange sounding, but // it allows you to get the message results when you send a response message. IPMI_RESPONSE_RECV_TYPE = 1 IPMI_ASYNC_EVENT_RECV_TYPE = 2 IPMI_CMD_RECV_TYPE = 3 IPMI_RESPONSE_RESPONSE_TYPE = 4 IPMI_OEM_RECV_TYPE = 5 IPMI_MAINTENANCE_MODE_AUTO = 0 IPMI_MAINTENANCE_MODE_OFF = 1 IPMI_MAINTENANCE_MODE_ON = 2 ) var ( IPMICTL_SEND_COMMAND = IOW(IPMI_IOC_MAGIC, 13, unsafe.Sizeof(IPMI_REQ{})) IPMICTL_SEND_COMMAND_SETTIME = IOW(IPMI_IOC_MAGIC, 21, unsafe.Sizeof(IPMI_REQ_SETTIME{})) IPMICTL_RECEIVE_MSG = IOWR(IPMI_IOC_MAGIC, 12, unsafe.Sizeof(IPMI_RECV{})) IPMICTL_RECEIVE_MSG_TRUNC = IOWR(IPMI_IOC_MAGIC, 11, unsafe.Sizeof(IPMI_RECV{})) IPMICTL_REGISTER_FOR_CMD = IOR(IPMI_IOC_MAGIC, 14, unsafe.Sizeof(IPMI_CMDSPEC{})) IPMICTL_UNREGISTER_FOR_CMD = IOR(IPMI_IOC_MAGIC, 15, unsafe.Sizeof(IPMI_CMDSPEC{})) IPMICTL_REGISTER_FOR_CMD_CHANS = IOR(IPMI_IOC_MAGIC, 28, unsafe.Sizeof(IPMI_CMDSPEC_CHANS{})) IPMICTL_UNREGISTER_FOR_CMD_CHANS = IOR(IPMI_IOC_MAGIC, 29, unsafe.Sizeof(IPMI_CMDSPEC_CHANS{})) IPMICTL_SET_GETS_EVENTS_CMD = IOW(IPMI_IOC_MAGIC, 16, unsafe.Sizeof(uint32(0))) IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD = IOR(IPMI_IOC_MAGIC, 24, unsafe.Sizeof(IPMI_CHANNEL_LUN_ADDRESS_SET{})) IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD = IOR(IPMI_IOC_MAGIC, 25, unsafe.Sizeof(IPMI_CHANNEL_LUN_ADDRESS_SET{})) IPMICTL_SET_MY_CHANNEL_LUN_CMD = IOR(IPMI_IOC_MAGIC, 26, unsafe.Sizeof(IPMI_CHANNEL_LUN_ADDRESS_SET{})) IPMICTL_GET_MY_CHANNEL_LUN_CMD = IOR(IPMI_IOC_MAGIC, 27, unsafe.Sizeof(IPMI_CHANNEL_LUN_ADDRESS_SET{})) /* Legacy interfaces, these only set IPMB 0. */ IPMICTL_SET_MY_ADDRESS_CMD = IOR(IPMI_IOC_MAGIC, 17, unsafe.Sizeof(uint32(0))) IPMICTL_GET_MY_ADDRESS_CMD = IOR(IPMI_IOC_MAGIC, 18, unsafe.Sizeof(uint32(0))) IPMICTL_SET_MY_LUN_CMD = IOR(IPMI_IOC_MAGIC, 19, unsafe.Sizeof(uint32(0))) IPMICTL_GET_MY_LUN_CMD = IOR(IPMI_IOC_MAGIC, 20, unsafe.Sizeof(uint32(0))) IPMICTL_SET_TIMING_PARAMS_CMD = IOR(IPMI_IOC_MAGIC, 22, unsafe.Sizeof(IPMI_TIMING_PARAMS{})) IPMICTL_GET_TIMING_PARAMS_CMD = IOR(IPMI_IOC_MAGIC, 23, unsafe.Sizeof(IPMI_TIMING_PARAMS{})) IPMICTL_GET_MAINTENANCE_MODE_CMD = IOR(IPMI_IOC_MAGIC, 30, unsafe.Sizeof(uint32(0))) IPMICTL_SET_MAINTENANCE_MODE_CMD = IOW(IPMI_IOC_MAGIC, 31, unsafe.Sizeof(uint32(0))) ) // IPMI_ADDR wraps different IPMI ADDR TYPE data to one struct. // IPMI ADDR TYPE (Channel Medium Type), see: 6.5 Channel Medium Type type IPMI_ADDR struct { AddrType int32 Channel uint16 Data [IPMI_MAX_ADDR_SIZE]byte // Addr Data } const IPMI_SYSTEM_INTERFACE_ADDR_TYPE = 0x0c // IPMI_SYSTEM_INTERFACE_ADDR holds addr data of addr type IPMI_SYSTEM_INTERFACE_ADDR_TYPE. type IPMI_SYSTEM_INTERFACE_ADDR struct { AddrType int32 Channel uint16 LUN uint8 } const IPMI_IPMB_ADDR_TYPE = 0x01 const IPMI_IPMB_BROADCAST_ADDR_TYPE = 0x41 // Used for broadcast get device id as described in section 17.9 of the IPMI 1.5 manual. // IPMI_IPMB_ADDR holds addr data of addr type IPMI_IPMB_ADDR_TYPE or IPMI_IPMB_BROADCAST_ADDR_TYPE. // // It represents an IPMB address. type IPMI_IPMB_ADDR struct { AddrType int32 Channel uint16 SlaveAddr uint8 LUN uint8 } const IPMI_IPMB_DIRECT_ADDR_TYPE = 0x81 // IPMI_IPMB_DIRECT_ADDR holds addr data of addr type IPMI_IPMB_DIRECT_ADDR_TYPE. // // Used for messages received directly from an IPMB that have not gone // through a MC. This is for systems that sit right on an IPMB so // they can receive commands and respond to them. type IPMI_IPMB_DIRECT_ADDR struct { AddrType int32 Channel uint16 SlaveAddr uint8 RsLUN uint8 RqLUN uint8 } const IPMI_LAN_ADDR_TYPE = 0x04 // IPMI_LAN_ADDR holds addr data of addr type IPMI_LAN_ADDR_TYPE. // // A LAN Address. This is an address to/from a LAN interface bridged // by the BMC, not an address actually out on the LAN. type IPMI_LAN_ADDR struct { AddrType int32 Channel uint16 Privilege uint8 SessionHandle uint8 RemoteSWID uint8 LocalSWID uint8 LUN uint8 } // IPMI_MSG holds a raw IPMI message without any addressing. This covers both // commands and responses. The completion code is always the first // byte of data in the response (as the spec shows the messages laid out). // // unsafe.Sizeof of IPMI_MSG is 1+1+2+(4)+8=16. type IPMI_MSG struct { NetFn uint8 Cmd uint8 DataLen uint16 Data *byte } func (msg *IPMI_MSG) MsgData() ([]byte, error) { if msg.DataLen >= IPMI_BUF_SIZE { return nil, fmt.Errorf("received data length longer than buf size: %d > %d", msg.DataLen, IPMI_BUF_SIZE) } recvBuf := unsafe.Slice(msg.Data, msg.DataLen) return recvBuf[:msg.DataLen:msg.DataLen], nil } // unsafe.Sizeof of IPMI_REQ is 8+8(4+4)+8+16 = 40. type IPMI_REQ struct { Addr *IPMI_SYSTEM_INTERFACE_ADDR AddrLen int // The sequence number for the message. This // exact value will be reported back in the // response to this request if it is a command. // If it is a response, this will be used as // the sequence value for the response. MsgID int64 Msg IPMI_MSG } // unsafe.Sizeof of IPMI_RECV is 8(4+4)+8+8(4+4)+8+16 = 48. type IPMI_RECV struct { RecvType int Addr *IPMI_SYSTEM_INTERFACE_ADDR AddrLen int MsgID int64 Msg IPMI_MSG } type IPMI_REQ_SETTIME struct { Req IPMI_REQ Retries int32 RetryTimeMillis uint32 } // Register to get commands from other entities on this interface type IPMI_CMDSPEC struct { NetFn uint8 Cmd uint8 } type IPMI_CMDSPEC_CHANS struct { NetFn int Cmd int Chans int } type IPMI_CHANNEL_LUN_ADDRESS_SET struct { Channel uint16 Value uint8 } type IPMI_TIMING_PARAMS struct { Retries int RetryTimeMillis uint } golang-github-bougou-go-ipmi-0.7.2/open/send.go000066400000000000000000000036501474110527100213330ustar00rootroot00000000000000package open import ( "fmt" "os" "runtime" "syscall" "time" "unsafe" ) func SetReq(fd uintptr, op uintptr, req *IPMI_REQ) error { err := IOCTL(fd, op, uintptr(unsafe.Pointer(req))) runtime.KeepAlive(req) return err } func GetRecv(fd uintptr, op uintptr, recv *IPMI_RECV) error { err := IOCTL(fd, op, uintptr(unsafe.Pointer(recv))) runtime.KeepAlive(recv) return err } func SendCommand(file *os.File, req *IPMI_REQ, timeout time.Duration) ([]byte, error) { if timeout == 0 { timeout = IPMI_FILE_READ_TIMEOUT } fd := file.Fd() for { switch err := SetReq(fd, IPMICTL_SEND_COMMAND, req); { case err == syscall.EINTR: continue case err != nil: return nil, fmt.Errorf("SetReq failed, err: %w", err) } break } recvBuf := make([]byte, IPMI_BUF_SIZE) recv := &IPMI_RECV{ Addr: req.Addr, AddrLen: req.AddrLen, Msg: IPMI_MSG{ Data: &recvBuf[0], DataLen: IPMI_BUF_SIZE, }, } var result []byte var rerr error readMsgFunc := func(fd uintptr) bool { if err := GetRecv(fd, IPMICTL_RECEIVE_MSG_TRUNC, recv); err != nil { rerr = fmt.Errorf("GetRecv failed, err: %w", err) return false } if recv.MsgID != req.MsgID { rerr = fmt.Errorf("received msg id not match") return false } if recv.Msg.DataLen >= IPMI_BUF_SIZE { rerr = fmt.Errorf("received data length longer than buf size: %d > %d", recv.Msg.DataLen, IPMI_BUF_SIZE) } else { // recvBuf[0] is completion code. result = recvBuf[:recv.Msg.DataLen:recv.Msg.DataLen] rerr = nil } return true } conn, err := file.SyscallConn() if err != nil { return nil, fmt.Errorf("failed to get syscall conn from file: %s", err) } if err := file.SetReadDeadline(time.Now().Add(timeout)); err != nil { return nil, fmt.Errorf("failed to set read deadline on file: %s", err) } if err := conn.Read(readMsgFunc); err != nil { return nil, fmt.Errorf("failed to read from syscall conn: %s", err) } return result, rerr } golang-github-bougou-go-ipmi-0.7.2/types_boot_option.go000066400000000000000000000073211474110527100232170ustar00rootroot00000000000000package ipmi type BootInfoAcknowledgeBy uint8 const ( BootInfoAcknowledgeByBIOSPOST BootInfoAcknowledgeBy = 1 << 0 BootInfoAcknowledgeByOSLoader BootInfoAcknowledgeBy = 1 << 1 BootInfoAcknowledgeByOSServicePartition BootInfoAcknowledgeBy = 1 << 2 BootInfoAcknowledgeBySMS BootInfoAcknowledgeBy = 1 << 3 BootInfoAcknowledgeByOEM BootInfoAcknowledgeBy = 1 << 4 ) type BIOSVerbosity uint8 // only 2 bits, occupied 0-3 const ( BIOSVerbosityDefault BIOSVerbosity = 0 BIOSVerbosityQuiet BIOSVerbosity = 1 BIOSVerbosityVerbose BIOSVerbosity = 2 ) func (v BIOSVerbosity) String() string { switch v { case 0: return "System Default" case 1: return "Request Quiet Display" case 2: return "Request Verbose Display" default: return "Flag error" } } type BIOSBootType bool const ( BIOSBootTypeLegacy BIOSBootType = false // PC compatible boot (legacy) BIOSBootTypeEFI BIOSBootType = true // Extensible Firmware Interface Boot (EFI) ) func (t BIOSBootType) String() string { if t { return "BIOS EFI boot" } return "BIOS PC Compatible (legacy) boot" } type BootDeviceSelector uint8 // only 4 bits occupied const ( BootDeviceSelectorNoOverride BootDeviceSelector = 0x00 BootDeviceSelectorForcePXE BootDeviceSelector = 0x01 BootDeviceSelectorForceHardDrive BootDeviceSelector = 0x02 BootDeviceSelectorForceHardDriveSafe BootDeviceSelector = 0x03 BootDeviceSelectorForceDiagnosticPartition BootDeviceSelector = 0x04 BootDeviceSelectorForceCDROM BootDeviceSelector = 0x05 BootDeviceSelectorForceBIOSSetup BootDeviceSelector = 0x06 BootDeviceSelectorForceRemoteFloppy BootDeviceSelector = 0x07 BootDeviceSelectorForceRemoteCDROM BootDeviceSelector = 0x08 BootDeviceSelectorForceRemoteMedia BootDeviceSelector = 0x09 BootDeviceSelectorForceRemoteHardDrive BootDeviceSelector = 0x0b BootDeviceSelectorForceFloppy BootDeviceSelector = 0x0f ) func (s BootDeviceSelector) String() string { switch s { case 0x00: return "No override" case 0x01: return "Force PXE" case 0x02: return "Force Boot from default Hard-Drive" case 0x03: return "Force Boot from default Hard-Drive, request Safe-Mode" case 0x04: return "Force Boot from Diagnostic Partition" case 0x05: return "Force Boot from CD/DVD" case 0x06: return "Force Boot into BIOS Setup" case 0x07: return "Force Boot from remotely connected Floppy/primary removable media" case 0x08: return "Force Boot from remotely connected CD/DVD" case 0x09: return "Force Boot from primary remote media" case 0x0b: return "Force Boot from remotely connected Hard-Drive" case 0x0f: return "Force Boot from Floppy/primary removable media" default: return "Flag error" } } type ConsoleRedirectionControl uint8 const ( ConsoleRedirectionControl_Default ConsoleRedirectionControl = 0 ConsoleRedirectionControl_Skip ConsoleRedirectionControl = 1 ConsoleRedirectionControl_Enable ConsoleRedirectionControl = 2 ) func (c ConsoleRedirectionControl) String() string { switch c { case 0: return "Console redirection occurs per BIOS configuration setting (default)" case 1: return "Suppress (skip) console redirection if enabled" case 2: return "Request console redirection be enabled" default: return "Flag error" } } type BIOSMuxControl uint8 func (b BIOSMuxControl) String() string { switch b { case 0: return "BIOS uses recommended setting of the mux at the end of POST" case 1: return "Requests BIOS to force mux to BMC at conclusion of POST/start of OS boot" case 2: return "Requests BIOS to force mux to system at conclusion of POST/start of OS boot" default: return "Flag error" } } golang-github-bougou-go-ipmi-0.7.2/types_boot_option_params.go000066400000000000000000000525171474110527100245710ustar00rootroot00000000000000package ipmi import ( "bytes" "fmt" "strings" "time" ) type BootOptionParamSelector uint8 // only 7 bits occupied, 0-127 const ( BootOptionParamSelector_SetInProgress BootOptionParamSelector = 0x00 BootOptionParamSelector_ServicePartitionSelector BootOptionParamSelector = 0x01 BootOptionParamSelector_ServicePartitionScan BootOptionParamSelector = 0x02 BootOptionParamSelector_BMCBootFlagValidBitClear BootOptionParamSelector = 0x03 BootOptionParamSelector_BootInfoAcknowledge BootOptionParamSelector = 0x04 BootOptionParamSelector_BootFlags BootOptionParamSelector = 0x05 BootOptionParamSelector_BootInitiatorInfo BootOptionParamSelector = 0x06 BootOptionParamSelector_BootInitiatorMailbox BootOptionParamSelector = 0x07 // OEM Parameters, 96:127 ) func (bop BootOptionParamSelector) String() string { m := map[BootOptionParamSelector]string{ BootOptionParamSelector_SetInProgress: "Set In Progress", BootOptionParamSelector_ServicePartitionSelector: "Service Partition Selector", BootOptionParamSelector_ServicePartitionScan: "Service Partition Scan", BootOptionParamSelector_BMCBootFlagValidBitClear: "BMC Boot Flag Valid bit Clearing", BootOptionParamSelector_BootInfoAcknowledge: "Boot Info Acknowledge", BootOptionParamSelector_BootFlags: "Boot Flags", BootOptionParamSelector_BootInitiatorInfo: "Boot Initiator Info", BootOptionParamSelector_BootInitiatorMailbox: "Boot Initiator Mailbox", } s, ok := m[bop] if ok { return s } return "Unknown" } type BootOptionParameter interface { BootOptionParameter() (paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) Parameter } var ( _ BootOptionParameter = (*BootOptionParam_SetInProgress)(nil) _ BootOptionParameter = (*BootOptionParam_ServicePartitionSelector)(nil) _ BootOptionParameter = (*BootOptionParam_ServicePartitionScan)(nil) _ BootOptionParameter = (*BootOptionParam_BMCBootFlagValidBitClear)(nil) _ BootOptionParameter = (*BootOptionParam_BootInfoAcknowledge)(nil) _ BootOptionParameter = (*BootOptionParam_BootFlags)(nil) _ BootOptionParameter = (*BootOptionParam_BootInitiatorInfo)(nil) _ BootOptionParameter = (*BootOptionParam_BootInitiatorMailbox)(nil) ) func isNilBootOptionParameter(param BootOptionParameter) bool { switch v := param.(type) { case *BootOptionParam_SetInProgress: return v == nil case *BootOptionParam_ServicePartitionSelector: return v == nil case *BootOptionParam_ServicePartitionScan: return v == nil case *BootOptionParam_BMCBootFlagValidBitClear: return v == nil case *BootOptionParam_BootInfoAcknowledge: return v == nil case *BootOptionParam_BootFlags: return v == nil case *BootOptionParam_BootInitiatorInfo: return v == nil case *BootOptionParam_BootInitiatorMailbox: return v == nil default: return false } } // Table 28-14, Boot Option Parameters type BootOptionsParams struct { SetInProgress *BootOptionParam_SetInProgress ServicePartitionSelector *BootOptionParam_ServicePartitionSelector ServicePartitionScan *BootOptionParam_ServicePartitionScan BMCBootFlagValidBitClear *BootOptionParam_BMCBootFlagValidBitClear BootInfoAcknowledge *BootOptionParam_BootInfoAcknowledge BootFlags *BootOptionParam_BootFlags BootInitiatorInfo *BootOptionParam_BootInitiatorInfo BootInitiatorMailbox *BootOptionParam_BootInitiatorMailbox } func (bootOptionsParams *BootOptionsParams) Format() string { format := func(param BootOptionParameter) string { if isNilBootOptionParameter(param) { return "" } paramSelector, _, _ := param.BootOptionParameter() content := param.Format() if content[len(content)-1] != '\n' { content += "\n" } return fmt.Sprintf("[%02d] %-24s : %s", paramSelector, paramSelector.String(), content) } out := "" out += format(bootOptionsParams.SetInProgress) out += format(bootOptionsParams.ServicePartitionSelector) out += format(bootOptionsParams.ServicePartitionScan) out += format(bootOptionsParams.BMCBootFlagValidBitClear) out += format(bootOptionsParams.BootInfoAcknowledge) out += format(bootOptionsParams.BootFlags) out += format(bootOptionsParams.BootInitiatorInfo) out += format(bootOptionsParams.BootInitiatorMailbox) return out } type BootOptionParam_SetInProgress struct { Value SetInProgressState } func (p *BootOptionParam_SetInProgress) BootOptionParameter() (paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) { return BootOptionParamSelector_SetInProgress, 0, 0 } func (p *BootOptionParam_SetInProgress) Unpack(paramData []byte) error { if len(paramData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } p.Value = SetInProgressState(paramData[0]) return nil } func (p *BootOptionParam_SetInProgress) Pack() []byte { return []byte{uint8(p.Value)} } func (p *BootOptionParam_SetInProgress) Format() string { return p.Value.String() } // This value is used to select which service partition BIOS should boot using. type BootOptionParam_ServicePartitionSelector struct { Selector uint8 } func (p *BootOptionParam_ServicePartitionSelector) BootOptionParameter() (paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) { return BootOptionParamSelector_ServicePartitionSelector, 0, 0 } func (p *BootOptionParam_ServicePartitionSelector) Pack() []byte { return []byte{p.Selector} } func (p *BootOptionParam_ServicePartitionSelector) Unpack(paramData []byte) error { if len(paramData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } p.Selector = paramData[0] return nil } func (p *BootOptionParam_ServicePartitionSelector) Format() string { switch p.Selector { case 0: return "unspecified" default: return fmt.Sprintf("%#02x", p) } } type BootOptionParam_ServicePartitionScan struct { // data 1 [7:2] - reserved // - [1] - 1b = Request BIOS to scan for specified service partition. // BIOS clears this bit after the requested scan has been performed. // - [0] - 1b = Service Partition discovered. // BIOS sets this bit to indicate it has discovered the specified service partition. // The bit retains the value from the last scan. // Therefore, to get up-to-date status of the discovery state, a scan may need to be requested. RequestBIOSScan bool ServicePartitionDiscovered bool } func (p *BootOptionParam_ServicePartitionScan) BootOptionParameter() (paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) { return BootOptionParamSelector_ServicePartitionScan, 0, 0 } func (p *BootOptionParam_ServicePartitionScan) Pack() []byte { var b uint8 if p.RequestBIOSScan { b = setBit1(b) } if p.ServicePartitionDiscovered { b = setBit0(b) } return []byte{b} } func (p *BootOptionParam_ServicePartitionScan) Unpack(paramData []byte) error { if len(paramData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } p.RequestBIOSScan = isBit1Set(paramData[0]) p.ServicePartitionDiscovered = isBit0Set(paramData[0]) return nil } func (p BootOptionParam_ServicePartitionScan) Format() string { s := "\n" if p.RequestBIOSScan { s += " - Request BIOS to scan\n" } if p.ServicePartitionDiscovered { s += " - Service Partition Discoverd\n" } if s == "\n" { s += " No flag set\n" } return s } type BootOptionParam_BMCBootFlagValidBitClear struct { DontClearOnResetPEFOrPowerCyclePEF bool // corresponding to restart cause: 0x08, 0x09 DontClearOnCommandReceivedTimeout bool // corresponding to restart cause: 0x01 DontClearOnWatchdogTimeout bool // corresponding to restart cause: 0x04 DontClearOnResetPushButtonOrSoftReset bool // corresponding to restart cause: 0x02, 0x0a DontClearOnPowerUpPushButtonOrWakeEvent bool // corresponding to restart cause: 0x03, 0x0b } func (p *BootOptionParam_BMCBootFlagValidBitClear) BootOptionParameter() (paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) { return BootOptionParamSelector_BMCBootFlagValidBitClear, 0, 0 } func (p *BootOptionParam_BMCBootFlagValidBitClear) Format() string { s := "\n" if p.DontClearOnResetPEFOrPowerCyclePEF { s += " - Don't clear valid bit on reset/power cycle cause by PEF\n" } if p.DontClearOnCommandReceivedTimeout { s += " - Don't automatically clear boot flag valid bit on timeout\n" } if p.DontClearOnWatchdogTimeout { s += " - Don't clear valid bit on reset/power cycle cause by watchdog\n" } if p.DontClearOnResetPushButtonOrSoftReset { s += " - Don't clear valid bit on push button reset // soft reset\n" } if p.DontClearOnPowerUpPushButtonOrWakeEvent { s += " - Don't clear valid bit on power up via power push button or wake event\n" } // When any flag was set, then at least one of the above condition will be true, thus 's' would not be empty. if s == "\n" { s += " No flag set\n" } return s } func (p *BootOptionParam_BMCBootFlagValidBitClear) Pack() []byte { var b uint8 if p.DontClearOnResetPEFOrPowerCyclePEF { b = setBit4(b) } if p.DontClearOnCommandReceivedTimeout { b = setBit3(b) } if p.DontClearOnWatchdogTimeout { b = setBit2(b) } if p.DontClearOnResetPushButtonOrSoftReset { b = setBit1(b) } if p.DontClearOnPowerUpPushButtonOrWakeEvent { b = setBit0(b) } return []byte{b} } func (p *BootOptionParam_BMCBootFlagValidBitClear) Unpack(parameterData []byte) error { if len(parameterData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } b := parameterData[0] p.DontClearOnResetPEFOrPowerCyclePEF = isBit4Set(b) p.DontClearOnCommandReceivedTimeout = isBit3Set(b) p.DontClearOnWatchdogTimeout = isBit2Set(b) p.DontClearOnResetPushButtonOrSoftReset = isBit1Set(b) p.DontClearOnPowerUpPushButtonOrWakeEvent = isBit0Set(b) return nil } type BootOptionParam_BootInfoAcknowledge struct { // The boot initiator should typically write FFh to this parameter prior to initiating the boot. // The boot initiator may write 0 s if it wants to intentionally direct a given party to ignore the // boot info. // This field is automatically initialized to 00h when the management controller if first powered up or reset. ByOEM bool BySMS bool ByOSServicePartition bool ByOSLoader bool ByBIOSPOST bool } func (p *BootOptionParam_BootInfoAcknowledge) BootOptionParameter() (paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) { return BootOptionParamSelector_BootInfoAcknowledge, 0, 0 } func (p *BootOptionParam_BootInfoAcknowledge) Format() string { s := "\n" if p.ByOEM { s += " - OEM has handled boot info\n" } if p.BySMS { s += " - SMS has handled boot info\n" } if p.ByOSServicePartition { s += " - OS // service partition has handled boot info\n" } if p.ByOSLoader { s += " - OS Loader has handled boot info\n" } if p.ByBIOSPOST { s += " - BIOS/POST has handled boot info\n" } if s == "\n" { s += " No flag set\n" } return fmt.Sprint(s) } func (p *BootOptionParam_BootInfoAcknowledge) Pack() []byte { var out = make([]byte, 2) var b uint8 = 0x00 var b1 uint8 = 0xe0 // bit 7,6,5 is reserved, write s 1b if p.ByOEM { b = setBit4(b) b1 = setBit4(b1) } if p.BySMS { b = setBit3(b) b1 = setBit3(b1) } if p.ByOSServicePartition { b = setBit2(b) b1 = setBit2(b1) } if p.ByOSLoader { b = setBit1(b) b1 = setBit1(b1) } if p.ByBIOSPOST { b = setBit0(b) b1 = setBit0(b1) } packUint8(b, out, 0) packUint8(b1, out, 1) return out } func (p *BootOptionParam_BootInfoAcknowledge) Unpack(parameterData []byte) error { if len(parameterData) != 2 { return fmt.Errorf("the parameter data length must be 2 bytes") } b, _, _ := unpackUint8(parameterData, 1) p.ByOEM = isBit4Set(b) p.BySMS = isBit3Set(b) p.ByOSServicePartition = isBit2Set(b) p.ByOSLoader = isBit1Set(b) p.ByBIOSPOST = isBit0Set(b) return nil } type BootOptionParam_BootFlags struct { // 1b = boot flags valid. // The bit should be set to indicate that valid flag data is present. // This bit may be automatically cleared based on the boot flag valid bit clearing parameter, above. BootFlagsValid bool // 0b = options apply to next boot only. // 1b = options requested to be persistent for all future boots (i.e. requests BIOS to change its boot settings) Persist bool // 0b = "PC compatible" boot (legacy) // 1b = Extensible Firmware Interface Boot (EFI) BIOSBootType BIOSBootType CMOSClear bool LockKeyboard bool BootDeviceSelector BootDeviceSelector // 4 bits ScreenBlank bool LockoutResetButton bool LockoutPowerOff bool BIOSVerbosity BIOSVerbosity ForceProgressEventTraps bool BypassUserPassword bool LockoutSleepButton bool ConsoleRedirectionControl ConsoleRedirectionControl // only 2 bits BIOSSharedModeOverride bool BIOSMuxControl BIOSMuxControl // only 3 bits DeviceInstanceSelector uint8 // only 5 bits } func (p *BootOptionParam_BootFlags) BootOptionParameter() (paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) { return BootOptionParamSelector_BootFlags, 0, 0 } func (p *BootOptionParam_BootFlags) Pack() []byte { out := make([]byte, 5) var b1 uint8 if p.BootFlagsValid { b1 = setBit7(b1) } if p.Persist { b1 = setBit6(b1) } if p.BIOSBootType { b1 = setBit5(b1) } packUint8(b1, out, 0) var b2 = uint8(p.BootDeviceSelector) << 2 if p.CMOSClear { b2 = setBit7(b2) } if p.LockKeyboard { b2 = setBit6(b2) } if p.ScreenBlank { b2 = setBit1(b2) } if p.LockoutResetButton { b2 = setBit0(b2) } packUint8(b2, out, 1) var b3 = uint8(p.BIOSVerbosity) << 5 if p.LockoutPowerOff { b3 = setBit7(b3) } if p.ForceProgressEventTraps { b3 = setBit4(b3) } if p.BypassUserPassword { b3 = setBit3(b3) } if p.LockoutResetButton { b3 = setBit2(b3) } b3 |= uint8(p.ConsoleRedirectionControl) packUint8(b3, out, 2) var b4 uint8 if p.BIOSSharedModeOverride { b4 = setBit3(b4) } b4 |= uint8(p.BIOSMuxControl) packUint8(b4, out, 3) var b5 = uint8(p.DeviceInstanceSelector) packUint8(b5, out, 4) return out } func (p *BootOptionParam_BootFlags) Unpack(parameterData []byte) error { if len(parameterData) != 5 { return fmt.Errorf("the parameter data length must be 5 bytes") } b1, _, _ := unpackUint8(parameterData, 0) p.BootFlagsValid = isBit7Set(b1) p.Persist = isBit6Set(b1) p.BIOSBootType = BIOSBootType(isBit5Set(b1)) b2, _, _ := unpackUint8(parameterData, 1) p.CMOSClear = isBit7Set(b2) p.LockKeyboard = isBit6Set(b2) p.BootDeviceSelector = BootDeviceSelector((b2 & 0x3f) >> 2) // bit 5,4,3,2 p.ScreenBlank = isBit1Set(b2) p.LockoutResetButton = isBit0Set(b2) b3, _, _ := unpackUint8(parameterData, 2) p.LockoutPowerOff = isBit7Set(b3) p.BIOSVerbosity = BIOSVerbosity((b3 & 0x7f) >> 5) p.ForceProgressEventTraps = isBit4Set(b3) p.BypassUserPassword = isBit3Set(b3) p.LockoutResetButton = isBit2Set(b3) p.ConsoleRedirectionControl = ConsoleRedirectionControl(b3 & 0x03) b4, _, _ := unpackUint8(parameterData, 3) p.BIOSSharedModeOverride = isBit3Set(b4) p.BIOSMuxControl = BIOSMuxControl(b4 & 0x07) b5, _, _ := unpackUint8(parameterData, 4) p.DeviceInstanceSelector = b5 & 0x1f return nil } func (p *BootOptionParam_BootFlags) Format() string { s := "\n" s += fmt.Sprintf(" - Boot Flag %s\n", formatBool(p.BootFlagsValid, "Valid", "Invalid")) s += fmt.Sprintf(" - Options apply to %s\n", formatBool(p.Persist, "all future boots", "only next boot")) s += fmt.Sprintf(" - %s\n", p.BIOSBootType.String()) if p.CMOSClear { s += " - CMOS Clear\n" } if p.LockKeyboard { s += " - Lock Keyboard\n" } s += fmt.Sprintf(" - Boot Device Selector : %s\n", p.BootDeviceSelector.String()) if p.ScreenBlank { s += " - Screen blank\n" } if p.LockoutResetButton { s += " - Lock out Reset buttons\n" } if p.LockoutPowerOff { s += " - Lock out (power off/sleep request) via Power Button\n" } s += fmt.Sprintf(" - BIOS verbosity : %s\n", p.BIOSVerbosity.String()) if p.ForceProgressEventTraps { s += " - Force progress event traps\n" } if p.BypassUserPassword { s += " - User password bypass\n" } if p.LockoutSleepButton { s += " - Lock Out Sleep Button\n" } s += fmt.Sprintf(" - Console Redirection control : %s\n", p.ConsoleRedirectionControl.String()) if p.BIOSSharedModeOverride { s += " - BIOS Shared Mode Override\n" } s += fmt.Sprintf(" - BIOS Mux Control Override : %s\n", p.BIOSMuxControl.String()) return s } func (bootFlags *BootOptionParam_BootFlags) OptionsHelp() string { supportedOptions := []struct { name string help string }{ {"help", "print help message"}, {"valid", "Boot flags valid"}, {"persistent", "Changes are persistent for all future boots"}, {"efiboot", "Extensible Firmware Interface Boot (EFI)"}, {"clear-cmos", "CMOS clear"}, {"lockkbd", "Lock Keyboard"}, {"screenblank", "Screen Blank"}, {"lockoutreset", "Lock out Resetbuttons"}, {"lockout_power", "Lock out (power off/sleep request) via Power Button"}, {"verbose=default", "Request quiet BIOS display"}, {"verbose=no", "Request quiet BIOS display"}, {"verbose=yes", "Request verbose BIOS display"}, {"force_pet", "Force progress event traps"}, {"upw_bypass", "User password bypass"}, {"lockout_sleep", "Log Out Sleep Button"}, {"cons_redirect=default", "Console redirection occurs per BIOS configuration setting"}, {"cons_redirect=skip", "Suppress (skip) console redirection if enabled"}, {"cons_redirect=enable", "Suppress (skip) console redirection if enabled"}, } var buf bytes.Buffer buf.WriteString("Legal options settings are:\n") for _, o := range supportedOptions { buf.WriteString(fmt.Sprintf(" %-22s : %s\n", o.name, o.help)) } return buf.String() } func (bootFlags *BootOptionParam_BootFlags) ParseFromOptionsStr(optionsStr string) error { options := strings.Split(optionsStr, ",") return bootFlags.ParseFromOptions(options) } func (bootFlags *BootOptionParam_BootFlags) ParseFromOptions(options []string) error { for _, option := range options { switch option { case "valid": bootFlags.BootFlagsValid = true case "persistent": bootFlags.Persist = true case "efiboot": bootFlags.BIOSBootType = BIOSBootTypeEFI case "clear-cmos": bootFlags.CMOSClear = true case "lockkbd": bootFlags.LockKeyboard = true case "screenblank": bootFlags.ScreenBlank = true case "lockoutreset": bootFlags.LockoutResetButton = true case "lockout_power": bootFlags.LockoutPowerOff = true case "verbose=default": bootFlags.BIOSVerbosity = BIOSVerbosityDefault case "verbose=no": bootFlags.BIOSVerbosity = BIOSVerbosityQuiet case "verbose=yes": bootFlags.BIOSVerbosity = BIOSVerbosityVerbose case "force_pet": bootFlags.ForceProgressEventTraps = true case "upw_bypass": bootFlags.BypassUserPassword = true case "lockout_sleep": bootFlags.LockoutSleepButton = true case "cons_redirect=default": bootFlags.ConsoleRedirectionControl = ConsoleRedirectionControl_Default case "cons_redirect=skip": bootFlags.ConsoleRedirectionControl = ConsoleRedirectionControl_Skip case "cons_redirect=enable": bootFlags.ConsoleRedirectionControl = ConsoleRedirectionControl_Enable default: return fmt.Errorf("unsupported boot flag option, supported options: \n%s", bootFlags.OptionsHelp()) } } return nil } type BootOptionParam_BootInitiatorInfo struct { ChannelNumber uint8 SessionID uint32 BootInfoTimestamp time.Time } func (p *BootOptionParam_BootInitiatorInfo) BootOptionParameter() (paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) { return BootOptionParamSelector_BootInitiatorInfo, 0, 0 } func (p *BootOptionParam_BootInitiatorInfo) Format() string { return fmt.Sprintf(` Channel Number : %d Session Id : %d Timestamp : %s`, p.ChannelNumber, p.SessionID, p.BootInfoTimestamp) } func (p *BootOptionParam_BootInitiatorInfo) Pack() []byte { out := make([]byte, 9) packUint8(p.ChannelNumber, out, 0) packUint32L(p.SessionID, out, 1) ts := uint32(p.BootInfoTimestamp.Unix()) packUint32L(ts, out, 5) return out } func (p *BootOptionParam_BootInitiatorInfo) Unpack(parameterData []byte) error { if len(parameterData) != 9 { return fmt.Errorf("the parameter data length must be 9 bytes") } p.ChannelNumber, _, _ = unpackUint8(parameterData, 0) p.SessionID, _, _ = unpackUint32L(parameterData, 1) ts, _, _ := unpackUint32L(parameterData, 5) p.BootInfoTimestamp = parseTimestamp(ts) return nil } type BootOptionParam_BootInitiatorMailbox struct { SetSelector uint8 BlockData []byte } func (p *BootOptionParam_BootInitiatorMailbox) BootOptionParameter() (paramSelector BootOptionParamSelector, setSelector uint8, blockSelector uint8) { return BootOptionParamSelector_BootInitiatorMailbox, 0, 0 } func (p *BootOptionParam_BootInitiatorMailbox) Format() string { return fmt.Sprintf(` Selector : %d Block Data : %02x `, p.SetSelector, p.BlockData) } func (p *BootOptionParam_BootInitiatorMailbox) Pack() []byte { out := make([]byte, 1+len(p.BlockData)) packUint8(p.SetSelector, out, 0) packBytes(p.BlockData, out, 1) return out } func (p *BootOptionParam_BootInitiatorMailbox) Unpack(parameterData []byte) error { if len(parameterData) < 1 { return fmt.Errorf("the parameter data length must be at least 1 bytes") } p.SetSelector, _, _ = unpackUint8(parameterData, 0) p.BlockData, _, _ = unpackBytes(parameterData, 1, len(parameterData)-1) return nil } golang-github-bougou-go-ipmi-0.7.2/types_channel.go000066400000000000000000000134221474110527100222730ustar00rootroot00000000000000package ipmi const ( // 0h-Bh,Fh = specific channel number // Eh = retrieve information for channel this request was issued on ChannelNumberSelf uint8 = 0x0e ) type LUN uint8 // 7.2 BMC IPMB LUNs const ( IPMB_LUN_BMC LUN = 0x00 // BMC commands and Event Request Messages IPMB_LUN_OEM_1 LUN = 0x01 // OEM LUN 1 IPMB_LUN_SMS LUN = 0x10 // SMS Message LUN (Intended for messages to System Management Software) IPMB_LUN_OEM_2 LUN = 0x11 // OEM LUN 2 // the least significant bit // 0b (ID is a slave address) // 1b (ID is a Software ID) BMC_SA uint8 = 0x20 // BMC's responder address RemoteConsole_SWID uint8 = 0x81 // Remote Console Software ID ) // 6.3 Channel Numbers // Only the channel number assignments for the primary IPMB and the System Interface are fixed, // the assignment of other channel numbers can vary on a per-platform basis type Channel uint8 const ( ChannelPrimaryIPMB Channel = 0x0 ChannelSystem Channel = 0xf ) // 6.4 Channel Protocol Type type ChannelProtocol uint8 const ( ChannelProtocolIPMB ChannelProtocol = 0x01 ChannelProtocolICMB ChannelProtocol = 0x02 // 03 reserved ChannelProtocolSMBus ChannelProtocol = 0x04 ChannelProtocolKCS ChannelProtocol = 0x05 ChannelProtocolSMIC ChannelProtocol = 0x06 ChannelProtocolBTv10 ChannelProtocol = 0x07 ChannelProtocolBTv15 ChannelProtocol = 0x08 ChannelProtocolTMode ChannelProtocol = 0x09 ChannelProtocolOEM1 ChannelProtocol = 0x1c ChannelProtocolOEM2 ChannelProtocol = 0x1d ChannelProtocolOEM3 ChannelProtocol = 0x1e ChannelProtocolOEM4 ChannelProtocol = 0x1f ) func (cp ChannelProtocol) String() string { m := map[ChannelProtocol]string{ 0x01: "IPMB-1.0", 0x02: "ICMB-1.0", 0x04: "IPMI-SMBus", 0x05: "KCS", 0x06: "SMIC", 0x07: "BT-10", 0x08: "BT-15", 0x09: "TMode", 0x1c: "OEM Protocol 1", 0x1d: "OEM Protocol 2", 0x1e: "OEM Protocol 3", 0x1f: "OEM Protocol 4", } s, ok := m[cp] if ok { return s } return "reserved" } // 6.5 Channel Medium Type type ChannelMedium uint8 const ( ChannelMediumIPMB ChannelMedium = 0x01 ChannelMediumICMBv10 ChannelMedium = 0x02 ChannelMediumICMBv09 ChannelMedium = 0x03 ChannelMediumLAN ChannelMedium = 0x04 ChannelMediumSerial ChannelMedium = 0x05 ChannelMediumOtherLAN ChannelMedium = 0x06 ChannelMediumSMBus ChannelMedium = 0x07 ChannelMediumSMBusv10 ChannelMedium = 0x08 ChannelMediumSMBusv20 ChannelMedium = 0x09 ChannelMediumUSBv1 ChannelMedium = 0x0a ChannelMediumUSBv2 ChannelMedium = 0x0b ChannelMediumSystemInterface ChannelMedium = 0x0c ) func (cp ChannelMedium) String() string { m := map[ChannelMedium]string{ 0x01: "IPMB (I2C)", 0x02: "ICMB v1.0", 0x03: "ICMB v0.9", 0x04: "802.3 LAN", 0x05: "Asynch. Serial/Modem (RS-232)", 0x06: "Other LAN", 0x07: "PCI SMBus", 0x08: "SMBus v1.0/1.1", 0x09: "SMBus v2.0", 0x0a: "USB 1.x", 0x0b: "USB 2.x", 0x0c: "System Interface (KCS, SMIC, or BT)", } s, ok := m[cp] if ok { return s } if cp >= 0x60 && cp <= 0x7f { return "OEM" } return "reserved" } // 6.8 Channel Privilege Levels // // - The `SetChannelAccess` command is used to set the maximum privilege level limit for a channel. // - The `SetSessionPrivilegeLevel` Command is used to request the ability to perform operations // at a particular privilege level. // - The `SetSessionPrivilegeLevel` command can only be used to set privilege levels that are // less than or equal to the privilege level limit for the entire channel, // regardless of the privilege level of the user. type PrivilegeLevel uint8 const ( PrivilegeLevelUnspecified PrivilegeLevel = 0x00 PrivilegeLevelCallback PrivilegeLevel = 0x01 PrivilegeLevelUser PrivilegeLevel = 0x02 PrivilegeLevelOperator PrivilegeLevel = 0x03 PrivilegeLevelAdministrator PrivilegeLevel = 0x04 PrivilegeLevelOEM PrivilegeLevel = 0x05 ) func (l PrivilegeLevel) Short() string { // : X=Cipher Suite Unused // : c=CALLBACK // : u=USER // : o=OPERATOR // : a=ADMIN // : O=OEM m := map[PrivilegeLevel]string{ 0x00: "X", 0x01: "c", 0x02: "u", 0x03: "o", 0x04: "a", 0x05: "O", } s, ok := m[l] if ok { return s } return "-" } func (l PrivilegeLevel) String() string { m := map[PrivilegeLevel]string{ 0x00: "Unspecified", 0x01: "CALLBACK", 0x02: "USER", 0x03: "OPERATOR", 0x04: "ADMINISTRATOR", 0x05: "OEM", } s, ok := m[l] if ok { return s } return "NO ACCESS" } func (l PrivilegeLevel) Symbol() string { m := map[PrivilegeLevel]string{ 0x00: "X", 0x01: "c", 0x02: "u", 0x03: "o", 0x04: "a", 0x05: "O", } s, ok := m[l] if ok { return s } return "-" } // see: Table 22-28, Get Channel Access Command type ChannelAccessOption uint8 const ( ChannelAccessOption_NoChange ChannelAccessOption = 0 ChannelAccessOption_NonVolatile ChannelAccessOption = 1 // get non-volatile Channel Access ChannelAccessOption_Volatile ChannelAccessOption = 2 // get present volatile (active) setting of Channel Access ) // 6.6 Channel Access Modes type ChannelAccessMode uint8 const ( ChannelAccessMode_Disabled ChannelAccessMode = 0 ChannelAccessMode_PrebootOnly ChannelAccessMode = 1 ChannelAccessMode_AlwaysAvailable ChannelAccessMode = 2 ChannelAccessMode_Shared ChannelAccessMode = 3 ) func (mode ChannelAccessMode) String() string { m := map[ChannelAccessMode]string{ 0: "disabled", 1: "pre-boot only", 2: "always available", 3: "shared", } s, ok := m[mode] if ok { return s } return "" } type ChannelPrivilegeOption uint8 const ( ChannelPrivilegeOption_NoChange ChannelPrivilegeOption = 0 ChannelPrivilegeOption_NonVolatile ChannelPrivilegeOption = 1 ChannelPrivilegeOption_Volatile ChannelPrivilegeOption = 2 ) golang-github-bougou-go-ipmi-0.7.2/types_cipher_suite_id.go000066400000000000000000000146051474110527100240260ustar00rootroot00000000000000package ipmi import "context" // 22.15.2 Cipher Suite IDs type CipherSuiteID uint8 const ( CipherSuiteID0 CipherSuiteID = 0 CipherSuiteID1 CipherSuiteID = 1 CipherSuiteID2 CipherSuiteID = 2 CipherSuiteID3 CipherSuiteID = 3 CipherSuiteID4 CipherSuiteID = 4 CipherSuiteID5 CipherSuiteID = 5 CipherSuiteID6 CipherSuiteID = 6 CipherSuiteID7 CipherSuiteID = 7 CipherSuiteID8 CipherSuiteID = 8 CipherSuiteID9 CipherSuiteID = 9 CipherSuiteID10 CipherSuiteID = 10 CipherSuiteID11 CipherSuiteID = 11 CipherSuiteID12 CipherSuiteID = 12 CipherSuiteID13 CipherSuiteID = 13 CipherSuiteID14 CipherSuiteID = 14 CipherSuiteID15 CipherSuiteID = 15 CipherSuiteID16 CipherSuiteID = 16 CipherSuiteID17 CipherSuiteID = 17 CipherSuiteID18 CipherSuiteID = 18 CipherSuiteID19 CipherSuiteID = 19 CipherSuiteIDReserved CipherSuiteID = 0xff ) const ( StandardCipherSuite uint8 = 0xc0 OEMCipherSuite uint8 = 0xc1 CipherAlgMask uint8 = 0x3f // [5:0]=111111b CipherAlgTagBitMask uint8 = 0xc0 // [7:6]=11b CipherAlgTagBitAuthMask uint8 = 0x00 // [7:6]=00b CipherAlgTagBitIntegrityMask uint8 = 0x40 // [7:6]=01b CipherAlgTagBitEncryptionMask uint8 = 0x80 // [7:6]=10b LIST_ALGORITHMS_BY_CIPHER_SUITE uint8 = 0x80 ) // getCipherSuiteAlgorithms returns AuthAlg, IntegrityAlg and CryptAlg of the specified cipherSuiteID. func getCipherSuiteAlgorithms(cipherSuiteID CipherSuiteID) (authAlg AuthAlg, integrity IntegrityAlg, encryptionAlg CryptAlg, err error) { switch cipherSuiteID { case CipherSuiteID0: return AuthAlgRAKP_None, IntegrityAlg_None, CryptAlg_None, nil case CipherSuiteID1: return AuthAlgRAKP_HMAC_SHA1, IntegrityAlg_None, CryptAlg_None, nil case CipherSuiteID2: return AuthAlgRAKP_HMAC_SHA1, IntegrityAlg_HMAC_SHA1_96, CryptAlg_None, nil case CipherSuiteID3: return AuthAlgRAKP_HMAC_SHA1, IntegrityAlg_HMAC_SHA1_96, CryptAlg_AES_CBC_128, nil case CipherSuiteID4: return AuthAlgRAKP_HMAC_SHA1, IntegrityAlg_HMAC_SHA1_96, CryptAlg_xRC4_128, nil case CipherSuiteID5: return AuthAlgRAKP_HMAC_SHA1, IntegrityAlg_HMAC_SHA1_96, CryptAlg_xRC4_40, nil case CipherSuiteID6: return AuthAlgRAKP_HMAC_MD5, IntegrityAlg_None, CryptAlg_None, nil case CipherSuiteID7: return AuthAlgRAKP_HMAC_MD5, IntegrityAlg_HMAC_MD5_128, CryptAlg_None, nil case CipherSuiteID8: return AuthAlgRAKP_HMAC_MD5, IntegrityAlg_HMAC_MD5_128, CryptAlg_AES_CBC_128, nil case CipherSuiteID9: return AuthAlgRAKP_HMAC_MD5, IntegrityAlg_HMAC_MD5_128, CryptAlg_xRC4_128, nil case CipherSuiteID10: return AuthAlgRAKP_HMAC_MD5, IntegrityAlg_HMAC_MD5_128, CryptAlg_xRC4_40, nil case CipherSuiteID11: return AuthAlgRAKP_HMAC_MD5, IntegrityAlg_MD5_128, CryptAlg_None, nil case CipherSuiteID12: return AuthAlgRAKP_HMAC_MD5, IntegrityAlg_MD5_128, CryptAlg_AES_CBC_128, nil case CipherSuiteID13: return AuthAlgRAKP_HMAC_MD5, IntegrityAlg_MD5_128, CryptAlg_xRC4_128, nil case CipherSuiteID14: return AuthAlgRAKP_HMAC_MD5, IntegrityAlg_MD5_128, CryptAlg_xRC4_40, nil case CipherSuiteID15: return AuthAlgRAKP_HMAC_SHA256, IntegrityAlg_None, CryptAlg_None, nil case CipherSuiteID16: return AuthAlgRAKP_HMAC_SHA256, IntegrityAlg_HMAC_SHA256_128, CryptAlg_None, nil case CipherSuiteID17: return AuthAlgRAKP_HMAC_SHA256, IntegrityAlg_HMAC_SHA256_128, CryptAlg_AES_CBC_128, nil case CipherSuiteID18: return AuthAlgRAKP_HMAC_SHA256, IntegrityAlg_HMAC_SHA256_128, CryptAlg_xRC4_128, nil case CipherSuiteID19: return AuthAlgRAKP_HMAC_SHA256, IntegrityAlg_HMAC_SHA256_128, CryptAlg_xRC4_40, nil case CipherSuiteIDReserved: return 0, 0, 0, nil default: return 0, 0, 0, nil } } // 22.15.1 Cipher Suite Records // The size of a CipherSuiteRecord is type CipherSuiteRecord struct { // If StartOfRecord is C0h, indicating that the Start Of Record byte is followed by an Cipher Suite ID // If StartOfRecord is C1h, indicating that the Start Of Record byte is followed by a OEM Cipher Suite ID plus OEM IANA StartOfRecord uint8 // a numeric way of identifying the Cipher Suite on the platform CipherSuitID CipherSuiteID OEMIanaID uint32 // Least significant byte first. 3-byte IANA for the OEM or body that defined the Cipher Suite. // an authentication algorithm number is required for all Cipher Suites. // It is possible that a given Cipher Suite may not specify use of an integrity or confidentiality algorithm. AuthAlg uint8 // Tag bits: [7:6]=00b IntegrityAlgs []uint8 // Tag bits: [7:6]=01b CryptAlgs []uint8 // Tag bits: [7:6]=10b } func (c *Client) findBestCipherSuites(ctx context.Context) []CipherSuiteID { cipherSuiteRecords, err := c.GetAllChannelCipherSuites(ctx, ChannelNumberSelf) if err != nil { return preferredCiphers } cipherSuiteIDs := make([]CipherSuiteID, len(cipherSuiteRecords)) for i, cipherSuiteRecord := range cipherSuiteRecords { cipherSuiteIDs[i] = cipherSuiteRecord.CipherSuitID } return sortCipherSuites(cipherSuiteIDs) } // sortCipherSuites return cipher suites in order of preference. // the cipher suite not in the preferredCiphers list would be excluded. func sortCipherSuites(cipherSuites []CipherSuiteID) []CipherSuiteID { sorted := make([]CipherSuiteID, 0) for _, preferredCipher := range preferredCiphers { for _, cipherSuiteID := range cipherSuites { if preferredCipher == cipherSuiteID { sorted = append(sorted, cipherSuiteID) } } } return sorted } var preferredCiphers = []CipherSuiteID{ // Todo // cipher suite best order is chosen with this criteria: // xRC4 is bad // AES128 is required // HMAC-SHA256 > HMAC-SHA1 // secure authentication > encrypted content // With xRC4 out, all cipher suites with MD5 out, and cipher suite 3 // being required by the spec, the only better defined standard cipher // suite is 17. So if SHA256 is available, we should try to use that, // otherwise, fall back to 3. CipherSuiteID17, // IPMI 2.0 spec requires that cipher suite 3 is implemented // so we should always be able to fall back to that if better // options are not available. // CipherSuiteID3 -> 01h, 01h, 01h CipherSuiteID3, CipherSuiteID15, CipherSuiteID16, CipherSuiteID18, CipherSuiteID19, CipherSuiteID6, CipherSuiteID7, CipherSuiteID8, CipherSuiteID11, CipherSuiteID12, // xRC4 is bad, so we don't use it // CipherSuiteID4, // CipherSuiteID5, // CipherSuiteID9, // CipherSuiteID10, // CipherSuiteID13, // CipherSuiteID14, } golang-github-bougou-go-ipmi-0.7.2/types_command.go000066400000000000000000000602071474110527100223040ustar00rootroot00000000000000package ipmi // Command is the field in an IPMI message type Command struct { ID uint8 NetFn NetFn Name string } type Request interface { // Pack encodes the object to data bytes Pack() []byte // Command return the IPMI command info (NetFn/Cmd). // All IPMI specification specified commands are already predefined in this file. Command() Command } type Response interface { // Unpack decodes the object from data bytes Unpack(data []byte) error // CompletionCodes returns a map of command-specific completion codes CompletionCodes() map[uint8]string // Format return a formatted human friendly string Format() string } type Parameter interface { Pack() []byte Unpack(paramData []byte) error Format() string } // ResponseError encapsulate the CompletionCode of IPMI Response Msg // alongside with error description. type ResponseError struct { completionCode CompletionCode description string } // Error implements the error interface func (e *ResponseError) Error() string { return e.description } func (e *ResponseError) CompletionCode() CompletionCode { return e.completionCode } // Appendix G - Command Assignments // Command Number Assignments (Appendix G, table G-1) var ( // a faked command for RAKP messages CommandNone = Command{} // IPM Device Global Commands CommandGetDeviceID = Command{ID: 0x01, NetFn: NetFnAppRequest, Name: "Get Device ID"} CommandColdReset = Command{ID: 0x02, NetFn: NetFnAppRequest, Name: "Cold Reset"} CommandWarmReset = Command{ID: 0x03, NetFn: NetFnAppRequest, Name: "Warm Reset"} CommandGetSelfTestResults = Command{ID: 0x04, NetFn: NetFnAppRequest, Name: "Get Self Test Results"} CommandManufacturingTestOn = Command{ID: 0x05, NetFn: NetFnAppRequest, Name: "Manufacturing Test On"} CommandSetACPIPowerState = Command{ID: 0x06, NetFn: NetFnAppRequest, Name: "Set ACPI Power State"} CommandGetACPIPowerState = Command{ID: 0x07, NetFn: NetFnAppRequest, Name: "Get ACPI Power State"} CommandGetDeviceGUID = Command{ID: 0x08, NetFn: NetFnAppRequest, Name: "Get Device GUID"} CommandGetNetFnSupport = Command{ID: 0x09, NetFn: NetFnAppRequest, Name: "Get NetFn Support"} CommandGetCommandSupport = Command{ID: 0x0a, NetFn: NetFnAppRequest, Name: "Get Command Support"} CommandGetCommandSubfunctionSupport = Command{ID: 0x0b, NetFn: NetFnAppRequest, Name: "Get Command Sub-function Support"} CommandGetConfigurableCommands = Command{ID: 0x0c, NetFn: NetFnAppRequest, Name: "Get Configurable Commands"} CommandGetConfigurableCommandSubfunctions = Command{ID: 0x0d, NetFn: NetFnAppRequest, Name: "Get Configurable Command Sub-functions"} // 0Eh - 0Fh reserved CommandSetCommandEnables = Command{ID: 0x60, NetFn: NetFnAppRequest, Name: "Set Command Enables"} CommandGetCommandEnables = Command{ID: 0x61, NetFn: NetFnAppRequest, Name: "Get Command Enables"} CommandSetCommandSubfunctionsEnables = Command{ID: 0x62, NetFn: NetFnAppRequest, Name: "Set Command Sub-function Enables"} CommandGetCommandSubfunctionsEnables = Command{ID: 0x63, NetFn: NetFnAppRequest, Name: "Get Command Sub-function Enables"} CommandGetOEMNetFnIanaSupport = Command{ID: 0x64, NetFn: NetFnAppRequest, Name: "Get OEM NetFn IANA Support"} // BMC Watchdog Timer Commands CommandResetWatchdogTimer = Command{ID: 0x22, NetFn: NetFnAppRequest, Name: "Reset Watchdog Timer"} CommandSetWatchdogTimer = Command{ID: 0x24, NetFn: NetFnAppRequest, Name: "Set Watchdog Timer"} CommandGetWatchdogTimer = Command{ID: 0x25, NetFn: NetFnAppRequest, Name: "Get Watchdog Timer"} // BMC Device and Messaging Commands CommandSetBMCGlobalEnables = Command{ID: 0x2e, NetFn: NetFnAppRequest, Name: "Set BMC Global Enables"} CommandGetBMCGlobalEnables = Command{ID: 0x2f, NetFn: NetFnAppRequest, Name: "Get BMC Global Enables"} CommandClearMessageFlags = Command{ID: 0x30, NetFn: NetFnAppRequest, Name: "Clear Message Flags"} CommandGetMessageFlags = Command{ID: 0x31, NetFn: NetFnAppRequest, Name: "Get Message Flags"} CommandEnableMessageChannelReceive = Command{ID: 0x32, NetFn: NetFnAppRequest, Name: "Enable Message Channel Receive"} CommandGetMessage = Command{ID: 0x33, NetFn: NetFnAppRequest, Name: "Get Message"} CommandSendMessage = Command{ID: 0x34, NetFn: NetFnAppRequest, Name: "Send Message"} CommandReadEventMessageBuffer = Command{ID: 0x35, NetFn: NetFnAppRequest, Name: "Read Event Message Buffer"} CommandGetBTInterfaceCapabilities = Command{ID: 0x36, NetFn: NetFnAppRequest, Name: "Get BT Interface Capabilities"} CommandGetSystemGUID = Command{ID: 0x37, NetFn: NetFnAppRequest, Name: "Get System GUID"} CommandSetSystemInfoParam = Command{ID: 0x58, NetFn: NetFnAppRequest, Name: "Set System Info Param"} CommandGetSystemInfoParam = Command{ID: 0x59, NetFn: NetFnAppRequest, Name: "Get System Info Param"} CommandGetChannelAuthCapabilities = Command{ID: 0x38, NetFn: NetFnAppRequest, Name: "Get Channel Authentication Capabilities"} CommandGetSessionChallenge = Command{ID: 0x39, NetFn: NetFnAppRequest, Name: "Get Session Challenge"} CommandActivateSession = Command{ID: 0x3a, NetFn: NetFnAppRequest, Name: "Activate Session"} CommandSetSessionPrivilegeLevel = Command{ID: 0x3b, NetFn: NetFnAppRequest, Name: "Set Session Privilege Level"} CommandCloseSession = Command{ID: 0x3c, NetFn: NetFnAppRequest, Name: "Close Session"} CommandGetSessionInfo = Command{ID: 0x3d, NetFn: NetFnAppRequest, Name: "Get Session Info"} // 3e unassigned CommandGetAuthCode = Command{ID: 0x3f, NetFn: NetFnAppRequest, Name: "Get AuthCode"} CommandSetChannelAccess = Command{ID: 0x40, NetFn: NetFnAppRequest, Name: "Set Channel Access"} CommandGetChannelAccess = Command{ID: 0x41, NetFn: NetFnAppRequest, Name: "Get Channel Access"} CommandGetChannelInfo = Command{ID: 0x42, NetFn: NetFnAppRequest, Name: "Get Channel Info Command"} CommandSetUserAccess = Command{ID: 0x43, NetFn: NetFnAppRequest, Name: "Set User Access Command"} CommandGetUserAccess = Command{ID: 0x44, NetFn: NetFnAppRequest, Name: "Get User Access Command"} CommandSetUsername = Command{ID: 0x45, NetFn: NetFnAppRequest, Name: "Set User Name"} CommandGetUsername = Command{ID: 0x46, NetFn: NetFnAppRequest, Name: "Get User Name Command"} CommandSetUserPassword = Command{ID: 0x47, NetFn: NetFnAppRequest, Name: "Set User Password Command"} CommandActivatePayload = Command{ID: 0x48, NetFn: NetFnAppRequest, Name: "Activate Payload"} CommandDeactivatePayload = Command{ID: 0x49, NetFn: NetFnAppRequest, Name: "Deactivate Payload"} CommandGetPayloadActivationStatus = Command{ID: 0x4a, NetFn: NetFnAppRequest, Name: "Get Payload Activation Status"} CommandGetPayloadInstanceInfo = Command{ID: 0x4b, NetFn: NetFnAppRequest, Name: "Get Payload Instance Info"} CommandSetUserPayloadAccess = Command{ID: 0x4c, NetFn: NetFnAppRequest, Name: "Set User Payload Access"} CommandGetUserPayloadAccess = Command{ID: 0x4d, NetFn: NetFnAppRequest, Name: "Get User Payload Access"} CommandGetChannelPayloadSupport = Command{ID: 0x4e, NetFn: NetFnAppRequest, Name: "Get Channel Payload Support"} CommandGetChannelPayloadVersion = Command{ID: 0x4f, NetFn: NetFnAppRequest, Name: "Get Channel Payload Version"} CommandGetChannelOEMPayloadInfo = Command{ID: 0x50, NetFn: NetFnAppRequest, Name: "Get Channel OEM Payload Info"} // 51 unassigned CommandMasterWriteRead = Command{ID: 0x52, NetFn: NetFnAppRequest, Name: "Master Write-Read"} // 53 unassigned CommandGetChannelCipherSuites = Command{ID: 0x54, NetFn: NetFnAppRequest, Name: "Get Channel Cipher Suites"} CommandSuspendOrResumeEncryption = Command{ID: 0x55, NetFn: NetFnAppRequest, Name: "Suspend/Resume Payload Encryption"} CommandSetChannelCipherSuites = Command{ID: 0x56, NetFn: NetFnAppRequest, Name: "Set Channel Security Keys"} CommandGetSystemInterfaceCapabilities = Command{ID: 0x57, NetFn: NetFnAppRequest, Name: "Get System Interface Capabilities"} // Chassis Device Commands CommandGetChassisCapabilities = Command{ID: 0x00, NetFn: NetFnChassisRequest, Name: "Get Chassis Capabilities"} CommandGetChassisStatus = Command{ID: 0x01, NetFn: NetFnChassisRequest, Name: "Get Chassis Status"} CommandChassisControl = Command{ID: 0x02, NetFn: NetFnChassisRequest, Name: "Chassis Control"} CommandChassisReset = Command{ID: 0x03, NetFn: NetFnChassisRequest, Name: "Chassis Reset"} CommandChassisIdentify = Command{ID: 0x04, NetFn: NetFnChassisRequest, Name: "Chassis Identify"} CommandSetChassisCapabilities = Command{ID: 0x05, NetFn: NetFnChassisRequest, Name: "Set Chassis Capabilities"} CommandSetPowerRestorePolicy = Command{ID: 0x06, NetFn: NetFnChassisRequest, Name: "Set Power Restore Policy"} CommandGetSystemRestartCause = Command{ID: 0x07, NetFn: NetFnChassisRequest, Name: "Get System Restart Cause"} CommandSetSystemBootOptions = Command{ID: 0x08, NetFn: NetFnChassisRequest, Name: "Set System Boot Options"} CommandGetSystemBootOptions = Command{ID: 0x09, NetFn: NetFnChassisRequest, Name: "Get System Boot Options"} CommandSetFrontPanelEnables = Command{ID: 0x0a, NetFn: NetFnChassisRequest, Name: "Set Front Panel Button Enables"} CommandSetPowerCycleInterval = Command{ID: 0x0b, NetFn: NetFnChassisRequest, Name: "Set Power Cycle Interval"} // 0ch -0eh unassigned CommandGetPOHCounter = Command{ID: 0x0f, NetFn: NetFnChassisRequest, Name: "Get POH Counter"} // Event Commands CommandSetEventReceiver = Command{ID: 0x00, NetFn: NetFnSensorEventRequest, Name: "Set Event Receiver"} CommandGetEventReceiver = Command{ID: 0x01, NetFn: NetFnSensorEventRequest, Name: "Get Event Receiver"} CommandPlatformEventMessage = Command{ID: 0x02, NetFn: NetFnSensorEventRequest, Name: "Platform Event (Event Message)"} // 03h -0fh unassigned // PEF and Alerting Commands CommandGetPEFCapabilities = Command{ID: 0x10, NetFn: NetFnSensorEventRequest, Name: "Get PEF Capabilities"} CommandArmPEFPostponeTimer = Command{ID: 0x11, NetFn: NetFnSensorEventRequest, Name: "Arm PEF Postpone Timer"} CommandSetPEFConfigParam = Command{ID: 0x12, NetFn: NetFnSensorEventRequest, Name: "Set PEF Configuration Param"} CommandGetPEFConfigParam = Command{ID: 0x13, NetFn: NetFnSensorEventRequest, Name: "Get PEF Configuration Param"} CommandSetLastProcessedEventId = Command{ID: 0x14, NetFn: NetFnSensorEventRequest, Name: "Set Last Processed Event ID"} CommandGetLastProcessedEventId = Command{ID: 0x15, NetFn: NetFnSensorEventRequest, Name: "Get Last Processed Event ID"} CommandAlertImmediate = Command{ID: 0x16, NetFn: NetFnSensorEventRequest, Name: "Alert Immediate"} CommandPETAcknowledge = Command{ID: 0x17, NetFn: NetFnSensorEventRequest, Name: "PET Acknowledge"} // Sensor Device Commands CommandGetDeviceSDRInfo = Command{ID: 0x20, NetFn: NetFnSensorEventRequest, Name: "Get Device SDR Info"} CommandGetDeviceSDR = Command{ID: 0x21, NetFn: NetFnSensorEventRequest, Name: "Get Device SDR"} CommandReserveDeviceSDRRepo = Command{ID: 0x22, NetFn: NetFnSensorEventRequest, Name: "Reserve Device SDR Repository"} CommandGetSensorReadingFactors = Command{ID: 0x23, NetFn: NetFnSensorEventRequest, Name: "Get Sensor Reading Factors"} CommandSetSensorHysteresis = Command{ID: 0x24, NetFn: NetFnSensorEventRequest, Name: "Set Sensor Hysteresis"} CommandGetSensorHysteresis = Command{ID: 0x25, NetFn: NetFnSensorEventRequest, Name: "Get Sensor Hysteresis"} CommandSetSensorThresholds = Command{ID: 0x26, NetFn: NetFnSensorEventRequest, Name: "Set Sensor Threshold"} CommandGetSensorThresholds = Command{ID: 0x27, NetFn: NetFnSensorEventRequest, Name: "Get Sensor Threshold"} CommandSetSensorEventEnable = Command{ID: 0x28, NetFn: NetFnSensorEventRequest, Name: "Set Sensor Event Enable"} CommandGetSensorEventEnable = Command{ID: 0x29, NetFn: NetFnSensorEventRequest, Name: "Get Sensor Event Enable"} CommandRearmSensorEvents = Command{ID: 0x2a, NetFn: NetFnSensorEventRequest, Name: "Re-arm Sensor Events"} CommandGetSensorEventStatus = Command{ID: 0x2b, NetFn: NetFnSensorEventRequest, Name: "Get Sensor Event Status"} // no 2c CommandGetSensorReading = Command{ID: 0x2d, NetFn: NetFnSensorEventRequest, Name: "Get Sensor Reading"} CommandSetSensorType = Command{ID: 0x2e, NetFn: NetFnSensorEventRequest, Name: "Set Sensor Type"} CommandGetSensorType = Command{ID: 0x2f, NetFn: NetFnSensorEventRequest, Name: "Get Sensor Type"} CommandSetSensorReadingAndEventStatus = Command{ID: 0x30, NetFn: NetFnSensorEventRequest, Name: "Set Sensor Reading And Event Status"} // FRU Device Commands CommandGetFRUInventoryAreaInfo = Command{ID: 0x10, NetFn: NetFnStorageRequest, Name: "Get FRU Inventory Area Info"} CommandReadFRUData = Command{ID: 0x11, NetFn: NetFnStorageRequest, Name: "Read FRU Data"} CommandWriteFRUData = Command{ID: 0x12, NetFn: NetFnStorageRequest, Name: "Write FRU Data"} // SDR Device Commands CommandGetSDRRepoInfo = Command{ID: 0x20, NetFn: NetFnStorageRequest, Name: "Get SDR Repository Info"} CommandGetSDRRepoAllocInfo = Command{ID: 0x21, NetFn: NetFnStorageRequest, Name: "Get SDR Repository Allocation Info"} CommandReserveSDRRepo = Command{ID: 0x22, NetFn: NetFnStorageRequest, Name: "Reserve SDR Repository"} CommandGetSDR = Command{ID: 0x23, NetFn: NetFnStorageRequest, Name: "Get SDR"} CommandAddSDR = Command{ID: 0x24, NetFn: NetFnStorageRequest, Name: "Add SDR"} CommandPartialAddSDR = Command{ID: 0x25, NetFn: NetFnStorageRequest, Name: "Partial Add SDR"} CommandDeleteSDR = Command{ID: 0x26, NetFn: NetFnStorageRequest, Name: "Delete SDR"} CommandClearSDRRepo = Command{ID: 0x27, NetFn: NetFnStorageRequest, Name: "Clear SDR Repository"} CommandGetSDRRepoTime = Command{ID: 0x28, NetFn: NetFnStorageRequest, Name: "Get SDR Repository Time"} CommandSetSDRRepoTime = Command{ID: 0x29, NetFn: NetFnStorageRequest, Name: "Set SDR Repository Time"} CommandEnterSDRRepoUpdateMode = Command{ID: 0x2a, NetFn: NetFnStorageRequest, Name: "Enter SDR Repository Update Mode"} CommandExitSDRRepoUpdateMode = Command{ID: 0x2b, NetFn: NetFnStorageRequest, Name: "Exit SDR Repository Update Mode"} CommandRunInitializationAgent = Command{ID: 0x2c, NetFn: NetFnStorageRequest, Name: "Run Initialization Agent"} // SEL Device Commands CommandGetSELInfo = Command{ID: 0x40, NetFn: NetFnStorageRequest, Name: "Get SEL Info"} CommandGetSELAllocInfo = Command{ID: 0x41, NetFn: NetFnStorageRequest, Name: "Get SEL Allocation Info"} CommandReserveSEL = Command{ID: 0x42, NetFn: NetFnStorageRequest, Name: "Reserve SEL"} CommandGetSELEntry = Command{ID: 0x43, NetFn: NetFnStorageRequest, Name: "Get SEL Entry"} CommandAddSELEntry = Command{ID: 0x44, NetFn: NetFnStorageRequest, Name: "Add SEL Entry"} CommandPartialAddSELEntry = Command{ID: 0x45, NetFn: NetFnStorageRequest, Name: "Partial Add SEL Entry"} CommandDeleteSELEntry = Command{ID: 0x46, NetFn: NetFnStorageRequest, Name: "Delete SEL Entry"} CommandClearSEL = Command{ID: 0x47, NetFn: NetFnStorageRequest, Name: "Clear SEL"} CommandGetSELTime = Command{ID: 0x48, NetFn: NetFnStorageRequest, Name: "Get SEL Time"} CommandSetSELTime = Command{ID: 0x49, NetFn: NetFnStorageRequest, Name: "Set SEL Time"} CommandGetAuxLogStatus = Command{ID: 0x5a, NetFn: NetFnStorageRequest, Name: "Get Auxiliary Log Status"} CommandSetAuxLogStatus = Command{ID: 0x5b, NetFn: NetFnStorageRequest, Name: "Set Auxiliary Log Status"} CommandGetSELTimeUTCOffset = Command{ID: 0x5c, NetFn: NetFnStorageRequest, Name: "Get SEL Time UTC Offset"} CommandSetSELTimeUTCOffset = Command{ID: 0x5d, NetFn: NetFnStorageRequest, Name: "Set SEL Time UTC Offset"} // LAN Device Commands CommandSetLanConfigParam = Command{ID: 0x01, NetFn: NetFnTransportRequest, Name: "Set LAN Configuration Param"} CommandGetLanConfigParam = Command{ID: 0x02, NetFn: NetFnTransportRequest, Name: "Get LAN Configuration Param"} CommandSuspendARPs = Command{ID: 0x03, NetFn: NetFnTransportRequest, Name: "Suspend BMC ARPs"} CommandGetIPStatistics = Command{ID: 0x04, NetFn: NetFnTransportRequest, Name: "Get IP/UDP/RMCP Statistics"} // Serial/Modem Device Commands CommandSetSerialConfig = Command{ID: 0x10, NetFn: NetFnTransportRequest, Name: "Set Serial/Modem Configuration"} CommandGetSerialConfig = Command{ID: 0x11, NetFn: NetFnTransportRequest, Name: "Get Serial/Modem Configuration"} CommandSetSerialMux = Command{ID: 0x12, NetFn: NetFnTransportRequest, Name: "Set Serial/Modem Mux"} CommandGetTapResponseCodes = Command{ID: 0x13, NetFn: NetFnTransportRequest, Name: "Get TAP Response Codes"} CommandSetPPPTransmitData = Command{ID: 0x14, NetFn: NetFnTransportRequest, Name: "Set PPP UDP Proxy Transmit Data"} CommandGetPPPTransmitData = Command{ID: 0x15, NetFn: NetFnTransportRequest, Name: "Get PPP UDP Proxy Transmit Data"} CommandSendPPPPacket = Command{ID: 0x16, NetFn: NetFnTransportRequest, Name: "Send PPP UDP Proxy Packet"} CommandGetPPPReceiveData = Command{ID: 0x17, NetFn: NetFnTransportRequest, Name: "Get PPP UDP Proxy Receive Data"} CommandSerialConnectionActive = Command{ID: 0x18, NetFn: NetFnTransportRequest, Name: "Serial/Modem Connection Active"} CommandCallback = Command{ID: 0x19, NetFn: NetFnTransportRequest, Name: "Callback"} CommandSetUserCallbackOptions = Command{ID: 0x1a, NetFn: NetFnTransportRequest, Name: "Set User Callback Options"} CommandGetUserCallbackOptions = Command{ID: 0x1b, NetFn: NetFnTransportRequest, Name: "Get User Callback Options"} CommandSetSerialRoutingMux = Command{ID: 0x1c, NetFn: NetFnTransportRequest, Name: "Set Serial Routing Mux"} CommandSOLActivating = Command{ID: 0x20, NetFn: NetFnTransportRequest, Name: "SOL Activating"} CommandSetSOLConfigParam = Command{ID: 0x21, NetFn: NetFnTransportRequest, Name: "Set SOL Configuration Param"} CommandGetSOLConfigParam = Command{ID: 0x22, NetFn: NetFnTransportRequest, Name: "Get SOL Configuration Param"} // Command Forwarding Commands CommandForwarded = Command{ID: 0x30, NetFn: NetFnTransportRequest, Name: "Forwarded Command"} CommandSetForwarded = Command{ID: 0x31, NetFn: NetFnTransportRequest, Name: "Set Forwarded Commands"} CommandGetForwarded = Command{ID: 0x32, NetFn: NetFnTransportRequest, Name: "Get Forwarded Commands"} CommandEnableForwarded = Command{ID: 0x33, NetFn: NetFnTransportRequest, Name: "Enable Forwarded Commands"} // Bridge Management Commands (ICMB) CommandGetBridgeState = Command{ID: 0x00, NetFn: NetFnBridgeRequest, Name: "Get Bridge State"} CommandSetBridgeState = Command{ID: 0x01, NetFn: NetFnBridgeRequest, Name: "Set Bridge State"} CommandGetICMBAddress = Command{ID: 0x02, NetFn: NetFnBridgeRequest, Name: "Get ICMB Address"} CommandSetICMBAddress = Command{ID: 0x03, NetFn: NetFnBridgeRequest, Name: "Set ICMB Address"} CommandSetBridgeProxyAddress = Command{ID: 0x04, NetFn: NetFnBridgeRequest, Name: "Set Bridge ProxyAddress"} CommandGetBridgeStatistics = Command{ID: 0x05, NetFn: NetFnBridgeRequest, Name: "Get Bridge Statistics"} CommandGetICMBCapabilities = Command{ID: 0x06, NetFn: NetFnBridgeRequest, Name: "Get ICMB Capabilities"} CommandClearBridgeStatistics = Command{ID: 0x08, NetFn: NetFnBridgeRequest, Name: "Clear Bridge Statistics"} CommandGetBridgeProxyAddress = Command{ID: 0x09, NetFn: NetFnBridgeRequest, Name: "Get Bridge Proxy Address"} CommandGetICMBConnectorInfo = Command{ID: 0x0a, NetFn: NetFnBridgeRequest, Name: "Get ICMB Connector Info"} CommandGetICMBConnectionID = Command{ID: 0x0b, NetFn: NetFnBridgeRequest, Name: "Get ICMB Connection ID"} CommandSendICMBConnectionID = Command{ID: 0x0c, NetFn: NetFnBridgeRequest, Name: "Send ICMB Connection ID"} // Discovery Commands (ICMB) CommandPrepareForDiscovery = Command{ID: 0x10, NetFn: NetFnBridgeRequest, Name: "Prepare For Discovery"} CommandGetAddresses = Command{ID: 0x11, NetFn: NetFnBridgeRequest, Name: "Get Addresses"} CommandSetDiscovered = Command{ID: 0x12, NetFn: NetFnBridgeRequest, Name: "Set Discovered"} CommandGetChassisDeviceId = Command{ID: 0x13, NetFn: NetFnBridgeRequest, Name: "Get Chassis DeviceId"} CommandSetChassisDeviceId = Command{ID: 0x14, NetFn: NetFnBridgeRequest, Name: "Set Chassis DeviceId"} // Bridging Commands (ICMB) CommandBridgeRequest = Command{ID: 0x20, NetFn: NetFnBridgeRequest, Name: "Bridge Request"} CommandBridgeMessage = Command{ID: 0x21, NetFn: NetFnBridgeRequest, Name: "Bridge Message"} // Event Commands (ICMB) CommandGetEventCount = Command{ID: 0x30, NetFn: NetFnBridgeRequest, Name: "Get Event Count"} CommandSetEventDestination = Command{ID: 0x31, NetFn: NetFnBridgeRequest, Name: "Set Event Destination"} CommandSetEventReceptionState = Command{ID: 0x32, NetFn: NetFnBridgeRequest, Name: "Set Event Reception State"} CommandSendICMBEventMessage = Command{ID: 0x33, NetFn: NetFnBridgeRequest, Name: "Send ICMB Event Message"} CommandGetEventDestination = Command{ID: 0x34, NetFn: NetFnBridgeRequest, Name: "Get Event Destination"} CommandGetEventReceptionState = Command{ID: 0x35, NetFn: NetFnBridgeRequest, Name: "Get Event Reception State"} // OEM Commands for Bridge NetFn // C0h-FEh // Other Bridge Commands CommandErrorReport = Command{ID: 0xff, NetFn: NetFnBridgeRequest, Name: "Error Report"} // Intel DCMI extensions (https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/dcmi-v1-5-rev-spec.pdf) CommandGetDCMICapParam = Command{ID: 0x01, NetFn: NetFnGroupExtensionRequest, Name: "Get DCMI Cap Param"} CommandGetDCMIPowerReading = Command{ID: 0x02, NetFn: NetFnGroupExtensionRequest, Name: "Get DCMI Power Reading"} CommandGetDCMIPowerLimit = Command{ID: 0x03, NetFn: NetFnGroupExtensionRequest, Name: "Get DCMI Power Limit"} CommandSetDCMIPowerLimit = Command{ID: 0x04, NetFn: NetFnGroupExtensionRequest, Name: "Set DCMI Power Limit"} CommandActivateDCMIPowerLimit = Command{ID: 0x05, NetFn: NetFnGroupExtensionRequest, Name: "Activate/Deactivate DCMI Power Limit"} CommandGetDCMIAssetTag = Command{ID: 0x06, NetFn: NetFnGroupExtensionRequest, Name: "Get DCMI Asset Tag"} CommandGetDCMISensorInfo = Command{ID: 0x07, NetFn: NetFnGroupExtensionRequest, Name: "Get DCMI Sensor Info"} CommandSetDCMIAssetTag = Command{ID: 0x08, NetFn: NetFnGroupExtensionRequest, Name: "Set DCMI Asset Tag"} CommandGetDCMIMgmtControllerIdentifier = Command{ID: 0x09, NetFn: NetFnGroupExtensionRequest, Name: "Get DCMI Management Controller Identifier String"} CommandSetDCMIMgmtControllerIdentifier = Command{ID: 0x0A, NetFn: NetFnGroupExtensionRequest, Name: "Set DCMI Management Controller Identifier String"} CommandSetDCMIThermalLimit = Command{ID: 0x0B, NetFn: NetFnGroupExtensionRequest, Name: "Set DCMI Thermal Limit"} CommandGetDCMIThermalLimit = Command{ID: 0x0C, NetFn: NetFnGroupExtensionRequest, Name: "Get DCMI Thermal Limit"} CommandGetDCMITemperatureReadings = Command{ID: 0x10, NetFn: NetFnGroupExtensionRequest, Name: "Get DCMI Temperature Readings"} CommandSetDCMIConfigParam = Command{ID: 0x12, NetFn: NetFnGroupExtensionRequest, Name: "Set DCMI Configuration Param"} CommandGetDCMIConfigParam = Command{ID: 0x13, NetFn: NetFnGroupExtensionRequest, Name: "Get DCMI Configuration Param"} // Vendor Specific Commands CommandGetSupermicroBiosVersion = Command{ID: 0xAC, NetFn: NetFnOEMSupermicroRequest, Name: "Get Supermicro BIOS Version"} ) golang-github-bougou-go-ipmi-0.7.2/types_completion_code.go000066400000000000000000000066531474110527100240360ustar00rootroot00000000000000package ipmi type CompletionCode uint8 // 5.2 Table 5 for generic completion codes const ( // GENERIC COMPLETION CODES 00h, C0h-FFh CompletionCodeNormal CompletionCode = 0x00 CompletionCodeNodeBusy CompletionCode = 0xC0 CompletionCodeInvalidCommand CompletionCode = 0xC1 CompletionCodeInvalidCommandForLUN CompletionCode = 0xC2 CompletionCodeProcessTimeout CompletionCode = 0xC3 CompletionCodeOutOfSpace CompletionCode = 0xC4 CompletionCodeReservationCanceled CompletionCode = 0xC5 CompletionCodeRequestDataTruncated CompletionCode = 0xC6 CompletionCodeRequestDataLengthInvalid CompletionCode = 0xC7 CompletionCodeRequestDataLengthLimitExceeded CompletionCode = 0xC8 CompletionCodeParameterOutOfRange CompletionCode = 0xC9 CompletionCodeCannotReturnRequestedDataBytes CompletionCode = 0xCA CompletionCodeRequestedDataNotPresent CompletionCode = 0xCB CompletionCodeRequestDataFieldInvalid CompletionCode = 0xCC CompletionCodeIllegalCommand CompletionCode = 0xCD CompletionCodeCannotProvideResponse CompletionCode = 0xCE CompletionCodeCannotExecuteDuplicatedRequest CompletionCode = 0xCF CompletionCodeCannotProvideResponseSDRRInUpdate CompletionCode = 0xD0 // SDRR, SDR Repository CompletionCodeCannotProvideResponseFirmwareUpdate CompletionCode = 0xD1 CompletionCodeCannotProvideResponseBMCInitialize CompletionCode = 0xD2 CompletionCodeDestinationUnavailable CompletionCode = 0xD3 CompletionCodeCannotExecuteCommandSecurityRestrict CompletionCode = 0xD4 CompletionCodeCannotExecuteCommandNotSupported CompletionCode = 0xD5 CompletionCodeCannotExecuteCommandSubFnDisabled CompletionCode = 0xD6 CompletionCodeUnspecifiedError CompletionCode = 0xFF // DEVICE-SPECIFIC (OEM) CODES 01h-7Eh // COMMAND-SPECIFIC CODES 80h-BEh ) var CC = map[uint8]string{ 0x00: "Command completed normally", 0xc0: "Node busy", 0xc1: "Invalid command", 0xc2: "Invalid command on LUN", 0xc3: "Timeout", 0xc4: "Out of space", 0xc5: "Reservation cancelled or invalid", 0xc6: "Request data truncated", 0xc7: "Request data length invalid", 0xc8: "Request data field length limit exceeded", 0xc9: "Parameter out of range", 0xca: "Cannot return number of requested data bytes", 0xcb: "Requested sensor, data, or record not found", 0xcc: "Invalid data field in request", 0xcd: "Command illegal for specified sensor or record type", 0xce: "Command response could not be provided", 0xcf: "Cannot execute duplicated request", 0xd0: "SDR Repository in update mode", 0xd1: "Device firmware in update mode", 0xd2: "BMC initialization in progress", 0xd3: "Destination unavailable", 0xd4: "Cannot execute command, insufficient privilege level or other security-based restriction", 0xd5: "Cannot execute command, command or request parameters not supported in present state", 0xd6: "Cannot execute command, command disabled or is unavailable", 0xff: "Unspecified error", } // String return description of global completion code. // Please use StrCC function to get description for any completion code // returned for specific command response. func (cc CompletionCode) String() string { if s, ok := CC[uint8(cc)]; ok { return s } return "" } golang-github-bougou-go-ipmi-0.7.2/types_dcmi.go000066400000000000000000000012301474110527100215710ustar00rootroot00000000000000package ipmi // [DCMI specification v1.5]: 6.6.3 Set Power Limit // Exception Actions, taken if the Power Limit is exceeded and cannot be controlled within the Correction Time Limit type DCMIExceptionAction uint8 const ( DCMIExceptionAction_NoAction DCMIExceptionAction = 0x00 DCMIExceptionAction_PowerOffAndLogSEL DCMIExceptionAction = 0x01 DCMIExceptionAction_LogSEL DCMIExceptionAction = 0x11 ) func (a DCMIExceptionAction) String() string { m := map[DCMIExceptionAction]string{ 0x00: "No Action", 0x01: "Hard Power Off & Log Event to SEL", 0x11: "Log Event to SEL", } s, ok := m[a] if ok { return s } return "unknown" } golang-github-bougou-go-ipmi-0.7.2/types_dcmi_cap_params.go000066400000000000000000000271501474110527100237700ustar00rootroot00000000000000package ipmi import ( "fmt" ) type DCMICapParameter interface { DCMICapParameter() DCMICapParamSelector Parameter } var ( _ DCMICapParameter = (*DCMICapParam_SupportedDCMICapabilities)(nil) _ DCMICapParameter = (*DCMICapParam_MandatoryPlatformAttributes)(nil) _ DCMICapParameter = (*DCMICapParam_OptionalPlatformAttributes)(nil) _ DCMICapParameter = (*DCMICapParam_ManageabilityAccessAttributes)(nil) _ DCMICapParameter = (*DCMICapParam_EnhancedSystemPowerStatisticsAttributes)(nil) ) func isNilDCMICapParameter(param DCMICapParameter) bool { switch v := param.(type) { case *DCMICapParam_SupportedDCMICapabilities: return v == nil case *DCMICapParam_MandatoryPlatformAttributes: return v == nil case *DCMICapParam_OptionalPlatformAttributes: return v == nil case *DCMICapParam_ManageabilityAccessAttributes: return v == nil case *DCMICapParam_EnhancedSystemPowerStatisticsAttributes: return v == nil default: return false } } type DCMICapParamSelector uint8 const ( DCMICapParamSelector_SupportedDCMICapabilities = DCMICapParamSelector(0x01) DCMICapParamSelector_MandatoryPlatformAttributes = DCMICapParamSelector(0x02) DCMICapParamSelector_OptionalPlatformAttributes = DCMICapParamSelector(0x03) DCMICapParamSelector_ManageabilityAccessAttributes = DCMICapParamSelector(0x04) DCMICapParamSelector_EnhancedSystemPowerStatisticsAttributes = DCMICapParamSelector(0x05) ) func (dcmiCapParamSelector DCMICapParamSelector) String() string { m := map[DCMICapParamSelector]string{ DCMICapParamSelector_SupportedDCMICapabilities: "Supported DCMI capabilities", DCMICapParamSelector_MandatoryPlatformAttributes: "Mandatory platform attributes", DCMICapParamSelector_OptionalPlatformAttributes: "Optional platform attributes", DCMICapParamSelector_ManageabilityAccessAttributes: "Manageability access attributes", DCMICapParamSelector_EnhancedSystemPowerStatisticsAttributes: "Enhanced system power statistics attributes", } s, ok := m[dcmiCapParamSelector] if ok { return s } return "Unknown" } type DCMICapParams struct { SupportedDCMICapabilities *DCMICapParam_SupportedDCMICapabilities MandatoryPlatformAttributes *DCMICapParam_MandatoryPlatformAttributes OptionalPlatformAttributes *DCMICapParam_OptionalPlatformAttributes ManageabilityAccessAttributes *DCMICapParam_ManageabilityAccessAttributes EnhancedSystemPowerStatisticsAttributes *DCMICapParam_EnhancedSystemPowerStatisticsAttributes } func (dcmiCapParams *DCMICapParams) Format() string { format := func(param DCMICapParameter) string { if isNilDCMICapParameter(param) { return "" } paramSelector := param.DCMICapParameter() content := param.Format() if content[len(content)-1] != '\n' { content += "\n" } content += "\n" return fmt.Sprintf("[%02d] %-44s: %s", paramSelector, paramSelector.String(), content) } out := "" out += format(dcmiCapParams.SupportedDCMICapabilities) out += format(dcmiCapParams.MandatoryPlatformAttributes) out += format(dcmiCapParams.OptionalPlatformAttributes) out += format(dcmiCapParams.ManageabilityAccessAttributes) out += format(dcmiCapParams.EnhancedSystemPowerStatisticsAttributes) return out } type DCMICapParam_SupportedDCMICapabilities struct { SupportPowerManagement bool SupportInBandKCS bool SupportOutOfBandSerial bool SupportOutOfBandLAN bool } func (param *DCMICapParam_SupportedDCMICapabilities) DCMICapParameter() DCMICapParamSelector { return DCMICapParamSelector_SupportedDCMICapabilities } func (param *DCMICapParam_SupportedDCMICapabilities) Pack() []byte { return []byte{} } func (param *DCMICapParam_SupportedDCMICapabilities) Unpack(paramData []byte) error { if len(paramData) < 3 { return ErrUnpackedDataTooShortWith(len(paramData), 3) } param.SupportPowerManagement = isBit0Set(paramData[1]) param.SupportInBandKCS = isBit0Set(paramData[2]) param.SupportOutOfBandSerial = isBit1Set(paramData[2]) param.SupportOutOfBandLAN = isBit2Set(paramData[2]) return nil } func (param *DCMICapParam_SupportedDCMICapabilities) Format() string { return fmt.Sprintf(` Optional platform capabilities Power management (%s) Manageability access capabilities In-band KCS channel (%s) Out-of-band serial TMODE (%s) Out-of-band secondary LAN channel (%s) `, formatBool(param.SupportPowerManagement, "available", "unavailable"), formatBool(param.SupportInBandKCS, "available", "unavailable"), formatBool(param.SupportOutOfBandSerial, "available", "unavailable"), formatBool(param.SupportOutOfBandLAN, "available", "unavailable"), ) } type DCMICapParam_MandatoryPlatformAttributes struct { SELAutoRolloverEnabled bool EntireSELFlushUponRollOver bool RecordLevelSELFlushUponRollOver bool SELEntriesCount uint16 //only 12 bits, [11-0] Number of SEL entries (Maximum 4096) TemperatrureSamplingFrequencySec uint8 } func (param *DCMICapParam_MandatoryPlatformAttributes) DCMICapParameter() DCMICapParamSelector { return DCMICapParamSelector_MandatoryPlatformAttributes } func (param *DCMICapParam_MandatoryPlatformAttributes) Pack() []byte { out := make([]byte, 5) // byte 0 and byte 1 out[0] = byte(param.SELEntriesCount) & 0xFF var b1 uint8 b1 = setOrClearBit7(b1, param.SELAutoRolloverEnabled) b1 = setOrClearBit6(b1, param.EntireSELFlushUponRollOver) b1 = setOrClearBit5(b1, param.RecordLevelSELFlushUponRollOver) out[1] = b1 | (byte(param.SELEntriesCount>>8) & 0x0F) // byte 2 and byte 3 is reserved out[4] = param.TemperatrureSamplingFrequencySec return out } func (param *DCMICapParam_MandatoryPlatformAttributes) Unpack(paramData []byte) error { if len(paramData) < 5 { return ErrUnpackedDataTooShortWith(len(paramData), 5) } // byte 0 and byte 1 b_0_1, _, _ := unpackUint16L(paramData, 0) param.SELEntriesCount = b_0_1 & 0x0FFF b1 := paramData[1] param.SELAutoRolloverEnabled = isBit7Set(b1) param.EntireSELFlushUponRollOver = isBit6Set(b1) param.RecordLevelSELFlushUponRollOver = isBit5Set(b1) // byte 2 and byte 3 is reserved param.TemperatrureSamplingFrequencySec = paramData[4] return nil } func (param *DCMICapParam_MandatoryPlatformAttributes) Format() string { return fmt.Sprintf(` SEL Attributes: SEL automatic rollover is (%s) %d SEL entries Identification Attributes: Temperature Monitoring Attributes: Temperature sampling frequency is %d seconds `, formatBool(param.SELAutoRolloverEnabled, "enabled", "disabled"), param.SELEntriesCount, param.TemperatrureSamplingFrequencySec, ) } type DCMICapParam_OptionalPlatformAttributes struct { PowerMgmtDeviceSlaveAddr uint8 PewerMgmtControllerChannelNumber uint8 DeviceRevision uint8 } func (param *DCMICapParam_OptionalPlatformAttributes) DCMICapParameter() DCMICapParamSelector { return DCMICapParamSelector_OptionalPlatformAttributes } func (param *DCMICapParam_OptionalPlatformAttributes) Pack() []byte { out := make([]byte, 2) out[0] = param.PowerMgmtDeviceSlaveAddr out[1] = (param.PewerMgmtControllerChannelNumber & 0xF0) | (param.DeviceRevision & 0x0F) return out } func (param *DCMICapParam_OptionalPlatformAttributes) Unpack(paramData []byte) error { if len(paramData) < 2 { return ErrUnpackedDataTooShortWith(len(paramData), 3) } param.PowerMgmtDeviceSlaveAddr = paramData[0] param.PewerMgmtControllerChannelNumber = paramData[1] & 0xF0 param.DeviceRevision = paramData[1] & 0x0F return nil } func (param *DCMICapParam_OptionalPlatformAttributes) Format() string { return fmt.Sprintf(` Power Management: Slave address of device : %#02x Channel number is : %#02x %s Device revision is : %d `, param.PowerMgmtDeviceSlaveAddr, param.PewerMgmtControllerChannelNumber, formatBool(param.PewerMgmtControllerChannelNumber == 0, "(Primary BMC)", ""), param.DeviceRevision, ) } type DCMICapParam_ManageabilityAccessAttributes struct { PrimaryLANChannelNumber uint8 SecondaryLANChannelNumber uint8 SerialChannelNumber uint8 } func (param *DCMICapParam_ManageabilityAccessAttributes) DCMICapParameter() DCMICapParamSelector { return DCMICapParamSelector_ManageabilityAccessAttributes } func (param *DCMICapParam_ManageabilityAccessAttributes) Pack() []byte { return []byte{ param.PrimaryLANChannelNumber, param.SecondaryLANChannelNumber, param.SerialChannelNumber, } } func (param *DCMICapParam_ManageabilityAccessAttributes) Unpack(paramData []byte) error { if len(paramData) < 3 { return ErrUnpackedDataTooShortWith(len(paramData), 3) } param.PrimaryLANChannelNumber = paramData[0] param.SecondaryLANChannelNumber = paramData[1] param.SerialChannelNumber = paramData[2] return nil } func (param *DCMICapParam_ManageabilityAccessAttributes) Format() string { return fmt.Sprintf(` Primary LAN channel number : %d is %s Secondary LAN channel number : %d is %s Serial channel number : %d is %s `, param.PrimaryLANChannelNumber, formatBool(param.PrimaryLANChannelNumber != 0xFF, "available", "unavailable"), param.SecondaryLANChannelNumber, formatBool(param.SecondaryLANChannelNumber != 0xFF, "available", "unavailable"), param.SerialChannelNumber, formatBool(param.SerialChannelNumber != 0xFF, "available", "unavailable"), ) } type DCMICapParam_EnhancedSystemPowerStatisticsAttributes struct { RollingCount uint8 RollingAverageTimePeriodsSec []int } func (param *DCMICapParam_EnhancedSystemPowerStatisticsAttributes) DCMICapParameter() DCMICapParamSelector { return DCMICapParamSelector_EnhancedSystemPowerStatisticsAttributes } func (param *DCMICapParam_EnhancedSystemPowerStatisticsAttributes) Pack() []byte { out := make([]byte, 1+len(param.RollingAverageTimePeriodsSec)) out[0] = param.RollingCount for i, periodSec := range param.RollingAverageTimePeriodsSec { unit := uint8(0b00) period := uint8(0) if periodSec > 60*60*24 { unit = 0b11 // days period = uint8(periodSec / 60 / 60 / 24) } else if periodSec > 60*60 { unit = 0b10 // hours period = uint8(periodSec / 60 / 60) } else if periodSec > 60 { unit = 0b01 // minutes period = uint8(periodSec / 60) } else { unit = 0b00 // seconds period = uint8(periodSec) } out[1+i] = unit<<6 | period } return out } func (param *DCMICapParam_EnhancedSystemPowerStatisticsAttributes) Unpack(paramData []byte) error { if len(paramData) < 1 { return ErrUnpackedDataTooShortWith(len(paramData), 1) } param.RollingCount = paramData[0] rollingCount := int(param.RollingCount) if len(paramData) < 1+rollingCount { return ErrNotEnoughDataWith("rolling average time periods", len(paramData), 1+rollingCount) } periodsData, _, _ := unpackBytes(paramData, 1, rollingCount) for _, periodData := range periodsData { durationUnit := periodData >> 6 durationNumber := periodData & 0x3F durationSec := 0 switch durationUnit { case 0b00: // seconds durationSec = int(durationNumber) case 0b01: // minutes durationSec = int(durationNumber) * 60 case 0b10: // hours durationSec = int(durationNumber) * 60 * 60 case 0b11: // days durationSec = int(durationNumber) * 60 * 60 * 24 } param.RollingAverageTimePeriodsSec = append(param.RollingAverageTimePeriodsSec, durationSec) } return nil } func (param *DCMICapParam_EnhancedSystemPowerStatisticsAttributes) Format() string { return fmt.Sprintf(` Rolling count : %d Rolling average time periods : %v `, param.RollingCount, param.RollingAverageTimePeriodsSec, ) } golang-github-bougou-go-ipmi-0.7.2/types_dcmi_config_params.go000066400000000000000000000216471474110527100244770ustar00rootroot00000000000000package ipmi import "fmt" type DCMIConfigParameter interface { DCMIConfigParameter() (paramSelector DCMIConfigParamSelector, setSelector uint8) Parameter } var ( _ DCMIConfigParameter = (*DCMIConfigParam_ActivateDHCP)(nil) _ DCMIConfigParameter = (*DCMIConfigParam_DiscoveryConfiguration)(nil) _ DCMIConfigParameter = (*DCMIConfigParam_DHCPTiming1)(nil) _ DCMIConfigParameter = (*DCMIConfigParam_DHCPTiming2)(nil) _ DCMIConfigParameter = (*DCMIConfigParam_DHCPTiming3)(nil) ) func isNilDCMIConfigParameter(param DCMIConfigParameter) bool { switch v := param.(type) { case *DCMIConfigParam_ActivateDHCP: return v == nil case *DCMIConfigParam_DiscoveryConfiguration: return v == nil case *DCMIConfigParam_DHCPTiming1: return v == nil case *DCMIConfigParam_DHCPTiming2: return v == nil case *DCMIConfigParam_DHCPTiming3: return v == nil default: return false } } type DCMIConfigParamSelector uint8 const ( DCMIConfigParamSelector_ActivateDHCP DCMIConfigParamSelector = 0x01 DCMIConfigParamSelector_DiscoveryConfiguration DCMIConfigParamSelector = 0x02 DCMIConfigParamSelector_DHCPTiming1 DCMIConfigParamSelector = 0x03 DCMIConfigParamSelector_DHCPTiming2 DCMIConfigParamSelector = 0x04 DCMIConfigParamSelector_DHCPTiming3 DCMIConfigParamSelector = 0x05 ) func (paramSelector DCMIConfigParamSelector) String() string { m := map[DCMIConfigParamSelector]string{ DCMIConfigParamSelector_ActivateDHCP: "Activate DHCP", DCMIConfigParamSelector_DiscoveryConfiguration: "Discovery Configuration", DCMIConfigParamSelector_DHCPTiming1: "DHCP Timing1", DCMIConfigParamSelector_DHCPTiming2: "DHCP Timing2", DCMIConfigParamSelector_DHCPTiming3: "DHCP Timing3", } if v, ok := m[paramSelector]; ok { return v } return "Unknown" } type DCMIConfigParams struct { ActivateDHCP *DCMIConfigParam_ActivateDHCP DiscoveryConfiguration *DCMIConfigParam_DiscoveryConfiguration DHCPTiming1 *DCMIConfigParam_DHCPTiming1 DHCPTiming2 *DCMIConfigParam_DHCPTiming2 DHCPTiming3 *DCMIConfigParam_DHCPTiming3 } func (dcmiConfigParams *DCMIConfigParams) Format() string { format := func(param DCMIConfigParameter) string { if isNilDCMIConfigParameter(param) { return "" } paramSelector, _ := param.DCMIConfigParameter() content := param.Format() if content[len(content)-1] != '\n' { content += "\n" } return fmt.Sprintf("[%02d] %-24s: %s", paramSelector, paramSelector.String(), content) } out := "" out = format(dcmiConfigParams.ActivateDHCP) out += format(dcmiConfigParams.DiscoveryConfiguration) out += format(dcmiConfigParams.DHCPTiming1) out += format(dcmiConfigParams.DHCPTiming2) out += format(dcmiConfigParams.DHCPTiming3) return out } type DCMIConfigParam_ActivateDHCP struct { // Writing 01h to this parameter will trigger DHCP protocol restart using the latest parameter // settings, if DHCP is enabled. This can be used to ensure that the other DHCP configuration // parameters take effect immediately. Otherwise, the parameters may not take effect until the // next time the protocol restarts or a protocol timeout or lease expiration occurs. This is not a // non-volatile setting. It is only used to trigger a restart of the DHCP protocol. // // This parameter shall always return 0x00 when read. Activate bool } func (param *DCMIConfigParam_ActivateDHCP) DCMIConfigParameter() (paramSelector DCMIConfigParamSelector, setSelector uint8) { return DCMIConfigParamSelector_ActivateDHCP, 0 } func (param *DCMIConfigParam_ActivateDHCP) Pack() []byte { b := uint8(0) if param.Activate { b = 1 } return []byte{b} } func (param *DCMIConfigParam_ActivateDHCP) Unpack(paramData []byte) error { if len(paramData) < 1 { return ErrUnpackedDataTooShortWith(len(paramData), 1) } param.Activate = paramData[0] == 1 return nil } func (param *DCMIConfigParam_ActivateDHCP) Format() string { return fmt.Sprintf(`%v`, param.Activate) } type DCMIConfigParam_DiscoveryConfiguration struct { RandomBackoffEnabled bool IncludeDHCPOption60And43 bool IncludeDHCPOption12 bool } func (param *DCMIConfigParam_DiscoveryConfiguration) DCMIConfigParameter() (paramSelector DCMIConfigParamSelector, setSelector uint8) { return DCMIConfigParamSelector_DiscoveryConfiguration, 0 } func (param *DCMIConfigParam_DiscoveryConfiguration) Pack() []byte { b := uint8(0) if param.RandomBackoffEnabled { b = setBit7(b) } if param.IncludeDHCPOption60And43 { b = setBit1(b) } if param.IncludeDHCPOption12 { b = setBit0(b) } return []byte{b} } func (param *DCMIConfigParam_DiscoveryConfiguration) Unpack(paramData []byte) error { if len(paramData) < 1 { return ErrUnpackedDataTooShortWith(len(paramData), 1) } param.RandomBackoffEnabled = isBit7Set(paramData[0]) param.IncludeDHCPOption60And43 = isBit1Set(paramData[0]) param.IncludeDHCPOption12 = isBit0Set(paramData[0]) return nil } func (param *DCMIConfigParam_DiscoveryConfiguration) Format() string { return fmt.Sprintf(` Random Backoff Enabled : %v Include DHCPOption60AndOption43 : %v (Vendor class identifier using DCMI IANA, plus Vendor class-specific Information) Include DHCPOption12 : %v (Management Controller ID String) `, param.RandomBackoffEnabled, formatBool(param.IncludeDHCPOption60And43, "enabled", "disabled"), formatBool(param.IncludeDHCPOption12, "enabled", "disabled"), ) } type DCMIConfigParam_DHCPTiming1 struct { // This parameter sets the amount of time between the first attempt to reach a server and the // second attempt to reach a server. // // Each time a message is sent the timeout interval between messages is incremented by // twice the current interval multiplied by a pseudo random number between zero and one // if random back-off is enabled, or multiplied by one if random back-off is disabled. // // The recommended default is four seconds InitialTimeoutIntervalSec uint8 } func (param *DCMIConfigParam_DHCPTiming1) DCMIConfigParameter() (paramSelector DCMIConfigParamSelector, setSelector uint8) { return DCMIConfigParamSelector_DHCPTiming1, 0 } func (param *DCMIConfigParam_DHCPTiming1) Pack() []byte { return []byte{param.InitialTimeoutIntervalSec} } func (param *DCMIConfigParam_DHCPTiming1) Unpack(paramData []byte) error { if len(paramData) < 1 { return ErrUnpackedDataTooShortWith(len(paramData), 1) } param.InitialTimeoutIntervalSec = paramData[0] return nil } func (param *DCMIConfigParam_DHCPTiming1) Format() string { return fmt.Sprintf(` Initial timeout interval : %d seconds `, param.InitialTimeoutIntervalSec, ) } type DCMIConfigParam_DHCPTiming2 struct { // This parameter determines the amount of time that must pass between the time that the // client initially tries to determine its address and the time that it decides that it cannot contact // a server. If the last lease is expired, the client will restart the protocol after the defined retry // interval. The recommended default timeout is two minutes. After server contact timeout, the // client must wait for Server Contact Retry Interval before attempting to contact the server // again. ServerContactTimeoutIntervalSec uint8 } func (param *DCMIConfigParam_DHCPTiming2) DCMIConfigParameter() (paramSelector DCMIConfigParamSelector, setSelector uint8) { return DCMIConfigParamSelector_DHCPTiming2, 0 } func (param *DCMIConfigParam_DHCPTiming2) Pack() []byte { return []byte{param.ServerContactTimeoutIntervalSec} } func (param *DCMIConfigParam_DHCPTiming2) Unpack(paramData []byte) error { if len(paramData) < 1 { return ErrUnpackedDataTooShortWith(len(paramData), 1) } param.ServerContactTimeoutIntervalSec = paramData[0] return nil } func (param *DCMIConfigParam_DHCPTiming2) Format() string { return fmt.Sprintf(` Server contact timeout interval: %d seconds `, param.ServerContactTimeoutIntervalSec) } type DCMIConfigParam_DHCPTiming3 struct { // This is the period between DHCP retries after Server contact timeout interval expires. This // parameter determines the time that must pass after the client has determined that there is no // DHCP server present before it tries again to contact a DHCP server. // // The recommended default timeout is sixty-four seconds ServerContactRetryIntervalSec uint8 } func (param *DCMIConfigParam_DHCPTiming3) DCMIConfigParameter() (paramSelector DCMIConfigParamSelector, setSelector uint8) { return DCMIConfigParamSelector_DHCPTiming3, 0 } func (param *DCMIConfigParam_DHCPTiming3) Pack() []byte { return []byte{param.ServerContactRetryIntervalSec} } func (param *DCMIConfigParam_DHCPTiming3) Unpack(paramData []byte) error { if len(paramData) < 1 { return ErrUnpackedDataTooShortWith(len(paramData), 1) } param.ServerContactRetryIntervalSec = paramData[0] return nil } func (param *DCMIConfigParam_DHCPTiming3) Format() string { return fmt.Sprintf(` Server contact retry interval: %d seconds `, param.ServerContactRetryIntervalSec, ) } golang-github-bougou-go-ipmi-0.7.2/types_entity.go000066400000000000000000000164431474110527100222050ustar00rootroot00000000000000package ipmi import "fmt" // 43.14 Entity IDs // 39. Using Entity IDs // EntityID can be seen as Entity Type // // 1. An Entity ID is a standardized numeric code that is used in SDRs to identify // the types of physical entities or FRUs in the system. // // 2. The Entity ID is associated with an Entity Instance value that is used to // indicate the particular instance of an entity // // 3. The SDR for a sensor includes Entity ID and Entity Instance fields that // identify the entity associated with the sensor. type EntityID uint8 func (e EntityID) String() string { // 43.14 Entity IDs var entityIDMap = map[EntityID]string{ 0x00: "unspecified", 0x01: "other", 0x02: "unspecified", 0x03: "processor", 0x04: "disk or disk bay", // 磁盘托架 0x05: "peripheral bay", // 外围托架 0x06: "system management module", 0x07: "system board", 0x08: "memory module", 0x09: "processor module", 0x0a: "power supply", // DMI refers to this as a 'power unit', but it's used to represent a power supply 0x0b: "add-in card", // 附加卡 0x0c: "front panel board", // 前面板 0x0d: "back panel board", // 背板 0x0e: "power system board", // 电源系统板 0x0f: "drive backplane", // 驱动器背板 0x10: "system internal expansion board", // 0x11: "other system board", 0x12: "processor board", 0x13: "power unit / power domain", 0x14: "power module / DC-to-DC converter", 0x15: "power management / power distribution board", 0x16: "chassis back panel board", // 机箱后面板 0x17: "system chassis", // 0x18: "sub-chassis", 0x19: "other chassis board", 0x1a: "Disk Drive bay", 0x1b: "Peripheral bay", 0x1c: "Device bay", 0x1d: "fan / cooling device", 0x1e: "cooling unit / cooling domain", 0x1f: "cable / interconnect", 0x20: "memory device", 0x21: "System Management Software", 0x22: "System Firmware", // eg BIOS/EFI 0x23: "Operating System", 0x24: "system bus", 0x25: "Group", 0x26: "Remote (Out of Band) Management Communication Device", 0x27: "External Environment", 0x28: "battery", 0x29: "Processing blade", 0x2a: "Connectivity switch", 0x2b: "Processor/memory module", 0x2c: "I/O module", 0x2d: "Processor / IO module", 0x2e: "Management Controller Firmware", 0x2f: "IPMI Channel", 0x30: "PCI Bus", 0x31: "PCI Express Bus", 0x32: "SCSI Bus (parallel)", 0x33: "SATA / SAS bus", 0x34: "Processor / front-side bus", 0x35: "Real Time Clock (RTC)", 0x36: "System Firmware", // reserved. This value was previously a duplicate of 22h (System Firmware). 0x37: "air inlet", 0x38: "System Firmware", // reserved. This value was previously a duplicate of 22h (System Firmware). 0x40: "air inlet", // This Entity ID value is equivalent to Entity ID 37h. It is provided for interoperability with the DCMI 1.0 specifications. 0x41: "processor", // This Entity ID value is equivalent to Entity ID 03h (processor). It is provided for interoperability with the DCMI 1.0 specifications. 0x42: "system board", // This Entity ID value is equivalent to Entity ID 07h (system board). It is provided for interoperability with the DCMI 1.0 specifications. } out, ok := entityIDMap[e] if ok { return out } if e >= 0x90 && e <= 0xaf { // These IDs are system specific and can be assigned by the chassis provider. return fmt.Sprintf("Chassis-specific Entities (#%#02x)", uint8(e)) } if e >= 0xb0 && e <= 0xcf { // These IDs are system specific and can be assigned by the Board-set provider return fmt.Sprintf("Board-set specific Entities (#%#02x)", uint8(e)) } if e >= 0xd0 && e <= 0xff { // These IDs are system specific and can be assigned by the system integrator, or OEM. return fmt.Sprintf("OEM System Integrator defined (#%#02x)", uint8(e)) } return fmt.Sprintf("reserved (#%#02x)", uint8(e)) } // see: 39.1 System- and Device-relative Entity Instance Values // // Entity Instance values in the system-relative range are required to be unique for all entities with the same Entity ID in the system. // // Device-relative Entity Instance values are only required to be unique among all entities that have the same Entity ID within a given device (management controller). // // For example, management controller A and B could both have FAN entities that have an Entity Instance value of 60h. // // EntityInstance only occupy 7 bits, range is 0x00 ~ 0x7f type EntityInstance uint8 // 39.1 System- and Device-relative Entity Instance Values func isEntityInstanceSystemRelative(e EntityInstance) bool { return e <= 0x5f } func isEntityInstanceDeviceRelative(e EntityInstance) bool { return e >= 0x60 && e <= 0x7f } func (e EntityInstance) Type() string { if isEntityInstanceSystemRelative(e) { return "system-relative" } if isEntityInstanceDeviceRelative(e) { return "device-relative" } return "'" } func canonicalEntityString(entityID EntityID, entityInstance EntityInstance) string { if isEntityInstanceSystemRelative(entityInstance) { return fmt.Sprintf("System, %s, %d", entityID.String(), entityInstance) } if isEntityInstanceDeviceRelative(entityInstance) { return fmt.Sprintf("Controller 1, %s, %d", entityID.String(), entityInstance) } return "unknown" } // 43.13 Device Type Codes // DeviceType codes are used to identify different types of devices on // an IPMB, PCI Management Bus, or Private Management Bus connection // to an IPMI management controller type DeviceType uint16 func (d DeviceType) String() string { var deviceTypeMap = map[DeviceType]string{ 0x00: "Reserved", 0x01: "Reserved", 0x02: "DS1624 temperature sensor", 0x03: "DS1621 temperature sensor", 0x04: "LM75 Temperature Sensor", 0x05: "Heceta ASIC", 0x06: "Reserved", 0x07: "Reserved", // modifier codes for deviceTye 0x08 ~ 0x0f // 00h = unspecified // 01h = DIMM Memory ID // 02h = IPMI FRU Inventory // 03h = System Processor Cartridge FRU / PIROM (processor information ROM) // (processor information ROM) // all other = reserved 0x08: "EEPROM, 24C01", 0x09: "EEPROM, 24C02", 0x0a: "EEPROM, 24C04", 0x0b: "EEPROM, 24C08", 0x0c: "EEPROM, 24C16", 0x0d: "EEPROM, 24C17", 0x0e: "EEPROM, 24C32", 0x0f: "EEPROM, 24C64", // modifier codes for deviceType 0x10 // 00h = IPMI FRU Inventory [1] // 01h = DIMM Memory ID // 02h = IPMI FRU Inventory[1] // 03h = System Processor Cartridge FRU / PIROM // (processor information ROM) // all other = reserved // FFh = unspecified 0x10: "FRU Inventory Device behind management controller", // (accessed using Read/Write FRU commands at LUN other than 00b) 0x11: "Reserved", 0x12: "Reserved", 0x13: "Reserved", 0x14: "PCF 8570 256 byte RAM", 0x15: "PCF 8573 clock/calendar", 0x16: "PCF 8574A I/O Port", 0x17: "PCF 8583 clock/calendar", 0x18: "PCF 8593 clock/calendar", 0x19: "Clock calendar", 0x1a: "PCF 8591 A/D, D/A Converter", 0x1b: "I/O Port", 0x1c: "A/D Converter", 0x1d: "D/A Converter", 0x1e: "A/D, D/A Converter", 0x1f: "LCD Controller/Driver", 0x20: "Core Logic (Chip set) Device", 0x21: "LMC6874 Intelligent Battery controller", 0x22: "Intelligent Batter controller", 0x23: "Combo Management ASIC", 0x24: "Maxim 1617 Temperature Sensor", 0xbf: "Other/Unspecified", } s, ok := deviceTypeMap[d] if ok { return s } return "" } golang-github-bougou-go-ipmi-0.7.2/types_event.go000066400000000000000000000165511474110527100220120ustar00rootroot00000000000000package ipmi import "fmt" // 31.6.1 SEL Record Type Ranges type SELRecordType uint8 type SELRecordTypeRange string const ( // Range reserved for standard SEL Record Types. // As of this writing, only type 02h is defined. // Records are automatically timestamped unless otherwise indicated // 00h - BFh SELRecordTypeRangeStandard SELRecordTypeRange = "standard" // 32.2 OEM SEL Record - Type C0h-DFh // Range reserved for timestamped OEM SEL records. // These records are automatically timestamped by the SEL Device // C0h - DFh SELRecordTypeRangeTimestampedOEM SELRecordTypeRange = "timestamped OEM" // 32.3 OEM SEL Record - Type E0h-FFh // Range reserved for non-timestamped OEM SEL records. // The SEL Device does not automatically timestamp these records. // The four bytes passed in the byte locations for the timestamp will be directly entered into the SEL. // E0h - FFh SELRecordTypeRangeNonTimestampedOEM SELRecordTypeRange = "non-timestamped OEM" ) // The SELRecordType can be categorized into 3 ranges according to the SELRecordType value. // - 00h - BFh -> standard // - C0h - DFh -> timestamped OEM // - E0h - FFh -> none-timestamped OEM func (typ SELRecordType) Range() SELRecordTypeRange { t := uint8(typ) if t <= 0xbf { return SELRecordTypeRangeStandard } if t >= 0xc0 && t <= 0xdf { return SELRecordTypeRangeTimestampedOEM } // t >= 0xe0 && t <= 0xff return SELRecordTypeRangeNonTimestampedOEM } func (typ SELRecordType) String() string { return string(typ.Range()) } // Event direction type EventDir bool const ( EventDirDeassertion = true EventDirAssertion = false ) func (d EventDir) String() string { if d { return "Deassertion" } return "Assertion" } // 29.7 Event Data Field Formats type EventData struct { EventData1 uint8 EventData2 uint8 EventData3 uint8 } // 29.7 Event Data Field Formats // Event Data 1 // [3:0] - // for threshold sensors: Offset from Event/Reading Code for threshold event. // for discrete sensors: Offset from Event/Reading Code for discrete event state (corresponding 15 possible discrete events) func (ed *EventData) EventReadingOffset() uint8 { return ed.EventData1 & 0x0f } func (ed *EventData) String() string { return fmt.Sprintf("%02x%02x%02x", ed.EventData1, ed.EventData2, ed.EventData3) } // 41.2 Event/Reading Type Code // 42.1 Event/Reading Type Codes type EventReadingType uint8 const ( // Unspecified EventReadingTypeUnspecified EventReadingType = 0x00 // Threshold EventReadingTypeThreshold EventReadingType = 0x01 // Generic EventReadingTypeTransitionState EventReadingType = 0x02 EventReadingTypeState EventReadingType = 0x03 EventReadingTypePredictiveFailure EventReadingType = 0x04 EventReadingTypeLimit EventReadingType = 0x05 EventReadingTypePerformance EventReadingType = 0x06 EventReadingTypeTransitionSeverity EventReadingType = 0x07 EventReadingTypeDevicePresent EventReadingType = 0x08 EventReadingTypeDeviceEnabled EventReadingType = 0x09 EventReadingTypeTransitionAvailability EventReadingType = 0x0a EventReadingTypeRedundancy EventReadingType = 0x0b EventReadingTypeACPIPowerState EventReadingType = 0x0c EventReadingTypeSensorSpecific EventReadingType = 0x6f // OEM EventReadingTypeOEMMin EventReadingType = 0x70 EventReadingTypeOEMMax EventReadingType = 0x7f // Reserved ) func (typ EventReadingType) String() string { var c string switch typ { case EventReadingTypeUnspecified: c = "Unspecified" case EventReadingTypeThreshold: c = "Threshold" case EventReadingTypeSensorSpecific: c = "Sensor Specific" default: if typ >= 0x02 && typ <= 0x0c { c = "Generic" } else if typ >= EventReadingTypeOEMMin && typ <= EventReadingTypeOEMMax { c = "OEM" } else { c = "Reserved" } } return c } func (typ EventReadingType) SensorClass() SensorClass { if typ == EventReadingTypeThreshold { return SensorClassThreshold } return SensorClassDiscrete } func (typ EventReadingType) IsThreshold() bool { return typ == EventReadingTypeThreshold } // EventString returns description of the event func (typ EventReadingType) EventString(sensorType SensorType, eventData EventData) string { event := typ.Event(sensorType, eventData) if event == nil { return "" } return event.EventName } // EventSeverity return the severity for the event. // Todo, refactor func (typ EventReadingType) EventSeverity(sensorType SensorType, eventData EventData, eventDir EventDir) EventSeverity { event := typ.Event(sensorType, eventData) if event == nil { return EventSeverityInfo } switch typ { case EventReadingTypeUnspecified: return EventSeverityInfo case EventReadingTypeThreshold: if eventDir { if v, ok := event.AssertionSeverityMap[sensorType]; ok { return v } if v, ok := event.AssertionSeverityMap[SensorTypeReserved]; ok { return v } return EventSeverityInfo } else { if v, ok := event.DeassertionSeverityMap[sensorType]; ok { return v } if v, ok := event.DeassertionSeverityMap[SensorTypeReserved]; ok { return v } return EventSeverityInfo } case EventReadingTypeSensorSpecific: if eventDir { return event.AssertionSeverity } return event.DeassertionSeverity default: if typ >= 0x02 && typ <= 0x0c { if eventDir { if v, ok := event.AssertionSeverityMap[sensorType]; ok { return v } if v, ok := event.AssertionSeverityMap[SensorTypeReserved]; ok { return v } return EventSeverityInfo } else { if v, ok := event.DeassertionSeverityMap[sensorType]; ok { return v } if v, ok := event.DeassertionSeverityMap[SensorTypeReserved]; ok { return v } return EventSeverityInfo } } else if typ >= EventReadingTypeOEMMin && typ <= EventReadingTypeOEMMax { return EventSeverityInfo } else { return EventSeverityInfo } } } // Event return the predefined Event description struct. func (typ EventReadingType) Event(sensorType SensorType, eventData EventData) *Event { offset := eventData.EventReadingOffset() return typ.EventForOffset(sensorType, offset) } func (typ EventReadingType) EventForOffset(sensorType SensorType, eventOffset uint8) *Event { switch typ { case EventReadingTypeUnspecified: return nil case EventReadingTypeThreshold: return genericEvent(typ, eventOffset) case EventReadingTypeSensorSpecific: return sensorSpecificEvent(sensorType, eventOffset) default: if typ >= 0x02 && typ <= 0x0c { return genericEvent(typ, eventOffset) } else if typ >= EventReadingTypeOEMMin && typ <= EventReadingTypeOEMMax { return oemEvent(sensorType, eventOffset) } else { return nil } } } type EventSeverity string const ( EventSeverityInfo EventSeverity = "Info" EventSeverityOK EventSeverity = "OK" EventSeverityWarning EventSeverity = "Warning" EventSeverityCritical EventSeverity = "Critical" EventSeverityDegraded EventSeverity = "Degraded" EventSeverityNonFatal EventSeverity = "Non-fatal" ) type Event struct { EventName string EventDesc string // for generic event, different sensor type may means different severity AssertionSeverityMap map[SensorType]EventSeverity DeassertionSeverityMap map[SensorType]EventSeverity // for sensor specific event, severity is certain. AssertionSeverity EventSeverity DeassertionSeverity EventSeverity ED2 map[uint8]string // EventData2 ED3 map[uint8]string // EventData3 } golang-github-bougou-go-ipmi-0.7.2/types_event_consts.go000066400000000000000000001550161474110527100234030ustar00rootroot00000000000000package ipmi // For example, a 'button' sensor supports a set of sensor-specific event offsets: // 0 for Power Button pressed, for Sleep Button pressed, and 2 for Reset Button pressed. // When an event is generated, it could have a 0, 1, or 2 in the event offset field // depending on what button press occurred. // type EventOffset uint8 func genericEvent(typ EventReadingType, offset uint8) *Event { e, ok := GenericEvents[typ] if !ok { return nil } event, ok := e[offset] if !ok { return nil } return &event } func oemEvent(sensorType SensorType, offset uint8) *Event { return nil } func sensorSpecificEvent(sensorType SensorType, offset uint8) *Event { e, ok := SensorSpecificEvents[sensorType] if !ok { return nil } event, ok := e[offset] if !ok { return nil } return &event } // Table 42-2, Generic Event/Reading Type Codes // Including Generic threshold-based events (0x01) // and Generic discrete-based events (0x02 - 0x0c) // // map[EventReadingType]: map[Offset]Event // // The severity is copied from // freeipmi/libfreeipmi/interpret/ipmi-interpret-config-sel.c var GenericEvents = map[EventReadingType]map[uint8]Event{ EventReadingTypeThreshold: { 0x00: { EventName: "Lower Non-critical - going low", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x01: { EventName: "Lower Non-critical - going high", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x02: { EventName: "Lower Critical - going low", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x03: { EventName: "Lower Critical - going high", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x04: { EventName: "Lower Non-recoverable - going low", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x5: { EventName: "Lower Non-recoverable - going high", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x06: { EventName: "Upper Non-critical - going low", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x07: { EventName: "Upper Non-critical - going high", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x08: { EventName: "Upper Critical - going low", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x09: { EventName: "Upper Critical - going high", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x0a: { EventName: "Upper Non-recoverable - going low", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x0b: { EventName: "Upper Non-recoverable - going high", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, }, EventReadingTypeTransitionState: { 0x00: { EventName: "Transition to Idle", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityInfo, }, }, 0x01: { EventName: "Transition to Active", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityInfo, }, }, 0x02: { EventName: "Transition to Busy", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityInfo, }, }, }, EventReadingTypeState: { 0x00: { EventName: "State Deasserted", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityInfo, SensorTypeButtonSwitch: EventSeverityInfo, SensorTypeModuleBoard: EventSeverityInfo, SensorTypeBootError: EventSeverityInfo, SensorTypeOSStopShutdown: EventSeverityInfo, SensorTypePlatformAlert: EventSeverityInfo, SensorTypeTemperature: EventSeverityInfo, SensorTypeVoltage: EventSeverityInfo, SensorTypeFan: EventSeverityInfo, SensorTypeProcessor: EventSeverityInfo, SensorTypePowerSupply: EventSeverityInfo, SensorTypePowerUnit: EventSeverityInfo, SensorTypeMemory: EventSeverityInfo, SensorTypeDriveSlot: EventSeverityWarning, SensorTypePostMemoryResize: EventSeverityInfo, SensorTypeSystemFirmwareProgress: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityInfo, SensorTypeButtonSwitch: EventSeverityInfo, SensorTypeModuleBoard: EventSeverityInfo, SensorTypeBootError: EventSeverityInfo, SensorTypeOSStopShutdown: EventSeverityInfo, SensorTypePlatformAlert: EventSeverityInfo, SensorTypeTemperature: EventSeverityInfo, SensorTypeVoltage: EventSeverityInfo, SensorTypeFan: EventSeverityInfo, SensorTypeProcessor: EventSeverityInfo, SensorTypePowerSupply: EventSeverityInfo, SensorTypePowerUnit: EventSeverityInfo, SensorTypeMemory: EventSeverityInfo, SensorTypeDriveSlot: EventSeverityWarning, SensorTypePostMemoryResize: EventSeverityInfo, SensorTypeSystemFirmwareProgress: EventSeverityInfo, }, }, 0x01: { EventName: "State Asserted", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityWarning, SensorTypeButtonSwitch: EventSeverityInfo, SensorTypeModuleBoard: EventSeverityCritical, SensorTypeBootError: EventSeverityCritical, SensorTypeOSStopShutdown: EventSeverityCritical, SensorTypePlatformAlert: EventSeverityCritical, SensorTypeTemperature: EventSeverityWarning, SensorTypeVoltage: EventSeverityWarning, SensorTypeFan: EventSeverityWarning, SensorTypeProcessor: EventSeverityCritical, SensorTypePowerSupply: EventSeverityWarning, SensorTypePowerUnit: EventSeverityWarning, SensorTypeMemory: EventSeverityCritical, SensorTypeDriveSlot: EventSeverityInfo, SensorTypePostMemoryResize: EventSeverityWarning, SensorTypeSystemFirmwareProgress: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeSystemEvent: EventSeverityWarning, SensorTypeButtonSwitch: EventSeverityInfo, SensorTypeModuleBoard: EventSeverityCritical, SensorTypeBootError: EventSeverityCritical, SensorTypeOSStopShutdown: EventSeverityCritical, SensorTypePlatformAlert: EventSeverityCritical, SensorTypeTemperature: EventSeverityWarning, SensorTypeVoltage: EventSeverityWarning, SensorTypeFan: EventSeverityWarning, SensorTypeProcessor: EventSeverityCritical, SensorTypePowerSupply: EventSeverityWarning, SensorTypePowerUnit: EventSeverityWarning, SensorTypeMemory: EventSeverityCritical, SensorTypeDriveSlot: EventSeverityInfo, SensorTypePostMemoryResize: EventSeverityWarning, SensorTypeSystemFirmwareProgress: EventSeverityWarning, }, }, }, EventReadingTypePredictiveFailure: { 0x00: { EventName: "Predictive Failure de-asserted", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeDriveSlot: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeDriveSlot: EventSeverityInfo, }, }, 0x01: { EventName: "Predictive Failure asserted", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, SensorTypeDriveSlot: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, SensorTypeDriveSlot: EventSeverityCritical, }, }, }, EventReadingTypeLimit: { 0x00: { EventName: "Limit Not Exceeded", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeTemperature: EventSeverityInfo, SensorTypeVoltage: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeTemperature: EventSeverityInfo, SensorTypeVoltage: EventSeverityInfo, }, }, 0x01: { EventName: "Limit Exceeded", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, SensorTypeTemperature: EventSeverityCritical, SensorTypeVoltage: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, SensorTypeTemperature: EventSeverityCritical, SensorTypeVoltage: EventSeverityCritical, }, }, }, EventReadingTypePerformance: { 0x00: { EventName: "Performance Met", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeVoltage: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, SensorTypeVoltage: EventSeverityInfo, }, }, 0x01: { EventName: "Performance Lags", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, SensorTypeVoltage: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, SensorTypeVoltage: EventSeverityCritical, }, }, }, EventReadingTypeTransitionSeverity: { 0x00: { EventName: "transition to OK", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x01: { EventName: "transition to Non-Critical from OK", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x02: { EventName: "transition to Critical from less severe", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x03: { EventName: "transition to Non-recoverable from less severe", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x04: { EventName: "transition to Non-Critical from more severe", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x05: { EventName: "transition to Critical from Non-recoverable", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x06: { EventName: "transition to Non-recoverable", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x07: { EventName: "Monitor", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x08: { EventName: "Informational", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, }, EventReadingTypeDevicePresent: { 0x00: { EventName: "Device Removed / Device Absent", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x01: { EventName: "Device Inserted / Device Present", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, }, EventReadingTypeDeviceEnabled: { 0x00: { EventName: "Device Disabled", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x01: { EventName: "Device Enabled", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, }, EventReadingTypeTransitionAvailability: { 0x00: { EventName: "transition to Running", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x01: { EventName: "transition to In Test", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x02: { EventName: "transition to Power Off", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x03: { EventName: "transition to On Line", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x04: { EventName: "transition to Off Line", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x05: { EventName: "transition to Off Duty", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x06: { EventName: "transition to Degraded", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, 0x07: { EventName: "transition to Power Save", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x08: { EventName: "Install Error", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, }, }, EventReadingTypeRedundancy: { 0x00: { EventName: "Fully Redundant", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x01: { EventName: "Redundancy Lost", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x02: { EventName: "Redundancy Degraded", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x03: { EventName: "Non-redundant (Sufficient Resources from Redundant)", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x04: { EventName: "Non-redundant (Sufficient Resources from Insufficient Resources)", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x05: { EventName: "Non-redundant (Insufficient Resources)", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityCritical, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x06: { EventName: "Redundancy Degraded from Fully Redundant", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, 0x07: { EventName: "Redundancy Degraded from Non-redundant", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityWarning, }, }, }, EventReadingTypeACPIPowerState: { 0x00: { EventName: "D0 Power State", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x01: { EventName: "D1 Power State", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x02: { EventName: "D2 Power State", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, 0x03: { EventName: "D3 Power State", AssertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, DeassertionSeverityMap: map[SensorType]EventSeverity{ SensorTypeReserved: EventSeverityInfo, }, }, }, } // 42.2 Sensor Type Codes and Data // Sensor Specific Events // SensorType, Offset var SensorSpecificEvents = map[SensorType]map[uint8]Event{ SensorTypeReserved: {}, SensorTypeTemperature: {}, SensorTypeVoltage: {}, SensorTypeCurrent: {}, SensorTypeFan: {}, SensorTypePhysicalSecurity: { 0x00: { EventName: "General Chassis Intrusion", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "Drive Bay intrusion", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "I/O Card area intrusion", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Processor area intrusion", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x04: { EventName: "LAN Leash Lost (system is unplugged from LAN)", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x05: { EventName: "Unauthorized dock", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x06: { EventName: "FAN area intrusion", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypePlatformSecurity: { 0x00: { EventName: "Secure Mode (Front Panel Lockout) Violation attempt", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "Pre-boot Password Violation - user password", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "Pre-boot Password Violation attempt - setup password", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Pre-boot Password Violation - network boot password", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x04: { EventName: "Other pre-boot Password Violation", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x05: { EventName: "Out-of-band Access Password Violation", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeProcessor: { 0x00: { EventName: "IERR", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "Thermal Trip", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "FRB1/BIST failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "FRB2/Hang in POST failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x04: { EventName: "FRB3/Processor Startup/Initialization failure (CPU didn't start)", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x05: { EventName: "Configuration Error", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x06: { EventName: "SM BIOS 'Uncorrectable CPU-complex Error'", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x07: { EventName: "Processor Presence detected", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x08: { EventName: "Processor disabled", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x09: { EventName: "Terminator Presence Detected", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x0a: { EventName: "Processor Automatically Throttled", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x0b: { EventName: "Machine Check Exception (Uncorrectable)", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x0c: { EventName: "Correctable Machine Check Error", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, }, SensorTypePowerSupply: { 0x00: { EventName: "Presence detected", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "Power Supply Failure detected", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "Predictive Failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Power Supply input lost (AC/DC)", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityWarning, }, 0x04: { EventName: "Power Supply input lost or out-of-range", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityWarning, }, 0x05: { EventName: "Power Supply input out-of-range, but present", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityWarning, }, 0x06: { EventName: "Configuration error", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x07: { EventName: "Power Supply Inactive (in standby state)", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, }, SensorTypePowerUnit: { 0x00: { EventName: "Power Off / Power Dow", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "Power Cycle", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x02: { EventName: "240VA Power Down", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityInfo, }, 0x03: { EventName: "Interlock Power Down", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x04: { EventName: "AC lost / Power input lost ", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityWarning, }, 0x05: { EventName: "Soft Power Control Failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x06: { EventName: "Power Unit Failure detected", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x07: { EventName: "Predictive Failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeCollingDevice: {}, // Other Units-based Sensor (per units given in SDR) SensorTypeOtherUnitsbased: {}, SensorTypeMemory: { 0x00: { EventName: "Correctable ECC / other correctable memory error", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x01: { EventName: "Uncorrectable ECC / other uncorrectable memory error", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "Parity", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Memory Scrub Failed (stuck bit)", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x04: { EventName: "Memory Device Disabled", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x05: { EventName: "Correctable ECC / other correctable memory error logging limit reached", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x06: { EventName: "Presence detected", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x07: { EventName: "Configuration error", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x08: { EventName: "Spare", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x09: { EventName: "Memory Automatically Throttled", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x0a: { EventName: "Critical Overtemperature", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeDriveSlot: { 0x00: { EventName: "Drive Presence", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "Drive Fault", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "Predictive Failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Hot Spare", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x04: { EventName: "Consistency Check / Parity Check in progress", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x05: { EventName: "In Critical Array", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x06: { EventName: "In Failed Array", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x07: { EventName: "Rebuild/Remap in progress", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x08: { EventName: "Rebuild/Remap Aborted (was not completed normally)", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypePostMemoryResize: {}, SensorTypeSystemFirmwareProgress: { 0x00: { EventName: "System Firmware Error (POST Error)", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "System Firmware Hang", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "System Firmware Progress", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, }, SensorTypeEventLoggingDisabled: { 0x00: { EventName: "Correctable Memory Error Logging Disabled", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "Event 'Type' Logging Disabled", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "Log Area Reset/Cleared", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x03: { EventName: "All Event Logging Disabled", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x04: { EventName: "SEL Full", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x05: { EventName: "SEL Almost Full", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x06: { EventName: "Correctable Machine Check Error Logging Disabled", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeWatchdog1: { 0x00: { EventName: "BIOS Watchdog Reset", }, 0x01: { EventName: "OS Watchdog Reset", }, 0x02: { EventName: "OS Watchdog Shut Down", }, 0x03: { EventName: "OS Watchdog Power Down", }, 0x04: { EventName: "OS Watchdog Power Cycle", }, 0x05: { EventName: "OS Watchdog NMI / Diagnostic Interrupt", }, 0x06: { EventName: "OS Watchdog Expired, status only", }, 0x07: { EventName: "OS Watchdog pre-timeout Interrupt, non-NMI", }, }, SensorTypeSystemEvent: { 0x00: { EventName: "System Reconfigured", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x01: { EventName: "OEM System Boot Event", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x02: { EventName: "Undetermined system hardware failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Entry added to Auxiliary Log", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x04: { EventName: "PEF Action", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x05: { EventName: "Timestamp Clock Synch", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, }, SensorTypeCriticalInterrupt: { 0x00: { EventName: "Front Panel NMI / Diagnostic Interrupt", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "Bus Timeout", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "I/O channel check NMI", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Software NMI", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x04: { EventName: "PCI PERR", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x05: { EventName: "PCI SERR", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x06: { EventName: "EISA Fail Safe Timeout", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x07: { EventName: "Bus Correctable Error", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x08: { EventName: "Bus Uncorrectable Error", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x09: { EventName: "Fatal NMI", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x0a: { EventName: "Bus Fatal Error", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x0b: { EventName: "Bus Degraded", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, }, SensorTypeButtonSwitch: { 0x00: { EventName: "Power Button pressed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "Sleep Button pressed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x02: { EventName: "Reset Button pressed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x03: { EventName: "FRU latch open", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x04: { EventName: "FRU service request button", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, }, SensorTypeModuleBoard: {}, SensorTypeMicrocontrollerCoprocessor: {}, SensorTypeAddinCard: {}, SensorTypeChassis: {}, SensorTypeChipSet: { 0x00: { EventName: "Soft Power Control Failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "Thermal Trip", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeOtherFRU: {}, SensorTypeCableInterconnect: { 0x00: { EventName: "Cable/Interconnect is connected", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "Configuration Error - Incorrect cable connected / Incorrect interconnection", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeTerminator: {}, SensorTypeSystemBootRestartInitiated: { 0x00: { EventName: "Initiated by power up", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "Initiated by hard reset", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x02: { EventName: "Initiated by warm reset", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x03: { EventName: "User requested PXE boot", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x04: { EventName: "Automatic boot to diagnostic", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x05: { EventName: "OS / run-time software initiated hard reset", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x06: { EventName: "OS / run-time software initiated warm reset", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x07: { EventName: "System Restart", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, }, SensorTypeBootError: { 0x00: { EventName: "No bootable media", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "Non-bootable diskette left in drive", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "PXE Server not found", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Invalid boot sector", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x04: { EventName: "Timeout waiting for user selection of boot source", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, }, SensorTypeBaseOSBootInstallationStatus: { 0x00: { EventName: "A: boot completed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "C: boot completed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x02: { EventName: "PXE boot completed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x03: { EventName: "Diagnostic boot completed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x04: { EventName: "CD-ROM boot completed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x05: { EventName: "ROM boot completed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x06: { EventName: "boot completed - boot device not specified", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x07: { EventName: "Base OS/Hypervisor Installation started", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x08: { EventName: "Base OS/Hypervisor Installation completed", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x09: { EventName: "Base OS/Hypervisor Installation aborted", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x0a: { EventName: "Base OS/Hypervisor Installation failed", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeOSStopShutdown: { 0x00: { EventName: "Critical stop during OS load / initialization", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "Run-time Critical Stop", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "OS Graceful Stop", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x03: { EventName: "OS Graceful Shutdown", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x04: { EventName: "Soft Shutdown initiated by PEF", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x05: { EventName: "Agent Not Responding", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeSlotConnector: { 0x00: { EventName: "Fault Status asserted", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "Identify Status asserted", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x02: { EventName: "Slot / Connector Device installed/attached", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x03: { EventName: "Slot / Connector Ready for Device Installation", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x04: { EventName: "Slot/Connector Ready for Device Removal", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x05: { EventName: "Slot Power is Off", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x06: { EventName: "Slot / Connector Device Removal Request", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x07: { EventName: "Interlock asserted", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x08: { EventName: "Slot is Disabled", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x09: { EventName: "Slot holds spare device", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, }, SensorTypeSystemACPIPowerState: { 0x00: { EventName: "S0 / G0 (working)", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "S1 (sleeping with system h/w & processor context maintained)", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x02: { EventName: "S2 (sleeping, processor context lost)", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x03: { EventName: "S3 (sleeping, processor & h/w context lost, memory retained)", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x04: { EventName: "S4 (non-volatile sleep / suspend-to disk)", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x05: { EventName: "S5 / G2 (soft-off)", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x06: { EventName: "S4 / S5 soft-off, particular S4 / S5 state cannot be determined", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x07: { EventName: "G3 / Mechanical Off", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x08: { EventName: "Sleeping in an S1, S2, or S3 states", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x09: { EventName: "G1 sleeping", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x0a: { EventName: "S5 entered by override", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x0b: { EventName: "Legacy ON state", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x0c: { EventName: "Legacy OFF state", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x0e: { EventName: "Unknown", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeWatchdog2: { 0x00: { EventName: "Timer expired, status only (no action, no interrupt)", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x01: { EventName: "Hard Reset", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "Power Down", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Power Cycle", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x08: { EventName: "Timer interrupt", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, }, SensorTypePlatformAlert: { 0x00: { EventName: "platform generated page", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "platform generated LAN alert", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x02: { EventName: "Platform Event Trap generated", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x03: { EventName: "platform generated SNMP trap", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, }, SensorTypeEntityPresence: { 0x00: { EventName: "Entity Present", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "Entity Absent", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "Entity Disable", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeMonitorASIC: {}, SensorTypeLAN: { 0x00: { EventName: "LAN Heartbeat Lost", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x01: { EventName: "LAN Heartbeat", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, }, SensorTypeManagementSubsystemHealth: { 0x00: { EventName: "sensor access degraded or unavailable", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "controller access degraded or unavailable", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "management controller off-line", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "management controller unavailable", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x04: { EventName: "Sensor failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x05: { EventName: "FRU failure", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeBattery: { 0x00: { EventName: "battery low (predictive failure)", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x01: { EventName: "battery failed", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "battery presence detected", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, }, SensorTypeSessionAudit: { 0x00: { EventName: "Session Activated", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x01: { EventName: "Session Deactivated", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x02: { EventName: "Invalid Username or Password", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x03: { EventName: "Invalid password disable", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, SensorTypeVersionChange: { 0x00: { EventName: "Hardware change detected with associated Entity", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x01: { EventName: "Firmware or software change detected with associated Entity", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x02: { EventName: "Hardware incompatibility detected with associated Entity", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x03: { EventName: "Firmware or software incompatibility detected with associated Entity", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x04: { EventName: "Entity is of an invalid or unsupported hardware version", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x05: { EventName: "Entity contains an invalid or unsupported firmware or software version", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x06: { EventName: "Hardware Change detected with associated Entity was successful", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x07: { EventName: "Software or F/W Change detected with associated Entity was successful", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, }, SensorTypeFRUState: { 0x00: { EventName: "FRU Not Installed", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x01: { EventName: "FRU Inactive (in standby or 'hot spare' state)", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, 0x02: { EventName: "FRU Activation Requested", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x03: { EventName: "FRU Activation In Progress", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x04: { EventName: "FRU Active", AssertionSeverity: EventSeverityInfo, DeassertionSeverity: EventSeverityInfo, }, 0x05: { EventName: "FRU Deactivation Requested", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x06: { EventName: "FRU Deactivation In Progress", AssertionSeverity: EventSeverityWarning, DeassertionSeverity: EventSeverityWarning, }, 0x07: { EventName: "FRU Communication Lost", AssertionSeverity: EventSeverityCritical, DeassertionSeverity: EventSeverityCritical, }, }, } golang-github-bougou-go-ipmi-0.7.2/types_fru.go000066400000000000000000001010151474110527100214530ustar00rootroot00000000000000package ipmi import ( "bytes" "fmt" "time" ) // 38. Accessing FRU Devices // // FRU devices can located in three different types of location. type FRULocation string const ( // FRU Location: FRU Device behind a management controller // // only logical FRU Device can be accessed via FRU commands to mgmt controller // // Access Method: // Read/Write FRU Data commands to management controller providing access to the FRU Device. // // Use Read/WriteFRUData command to access FRU. // DeviceAccessAddress (Slave Address of IPMB) // FRUDeviceID_SlaveAddress FRULocation_MgmtController FRULocation = "on management controller" // FRU Location: SEEPROM On private bus behind a management controller // // Access Method: // Master Write-Read command to management controller that provides access to the private bus. // // Use MasterWriteRead command to access FRU. // DeviceAccessAddress (Slave Address of IPMB) // PrivateBusID // FRUDeviceID_SlaveAddress (Slave Address of SEEPROM on the Private Bus) FRULocation_PrivateBus FRULocation = "on private bus" // FRU Location : SEEPROM Device directly on IPMB // // Access Method: // Master Write-Read command through BMC from system software, or access via other interface // providing low-level I2C access to the IPMB. // // Use MasterWriteRead command to access FRU. // FRUDeviceID_SlaveAddress (slave address Of SEEPROM on the IPMB) FRULocation_IPMB FRULocation = "directly on IPMB" ) const ( FRUFormatVersion uint8 = 0x01 FRUAreaFieldsEndMark uint8 = 0xc1 FRUCommonHeaderSize uint8 = 8 ) type FRU struct { deviceID uint8 deviceName string deviceNotPresent bool deviceNotPresentReason string // FRU/17. FRU Information Layout CommonHeader *FRUCommonHeader InternalUseArea *FRUInternalUseArea ChassisInfoArea *FRUChassisInfoArea BoardInfoArea *FRUBoardInfoArea ProductInfoArea *FRUProductInfoArea MultiRecords []*FRUMultiRecord } func (fru *FRU) Present() bool { return !fru.deviceNotPresent } func (fru *FRU) DeviceName() string { return fru.deviceName } func (fru *FRU) DeviceID() uint8 { return fru.deviceID } func (fru *FRU) String() string { var buf = new(bytes.Buffer) buf.WriteString(fmt.Sprintf("FRU Device Description : %s (ID %d)\n", fru.deviceName, fru.deviceID)) if !fru.Present() { buf.WriteString(" Device not present\n") return buf.String() } if fru.ChassisInfoArea != nil { buf.WriteString(fmt.Sprintf(" Chassis Type : %s\n", fru.ChassisInfoArea.ChassisType.String())) buf.WriteString(fmt.Sprintf(" Chassis Part Number : %s\n", fru.ChassisInfoArea.PartNumber)) buf.WriteString(fmt.Sprintf(" Chassis Serial Number: %s\n", fru.ChassisInfoArea.SerialNumber)) for _, v := range fru.ChassisInfoArea.Custom { buf.WriteString(fmt.Sprintf(" Chassis Extra : %s\n", v)) } } if fru.BoardInfoArea != nil { buf.WriteString(fmt.Sprintf(" Board Mfg Date : %s\n", fru.BoardInfoArea.MfgDateTime.String())) buf.WriteString(fmt.Sprintf(" Board Mfg : %s\n", fru.BoardInfoArea.Manufacturer)) buf.WriteString(fmt.Sprintf(" Board Product : %s\n", fru.BoardInfoArea.ProductName)) buf.WriteString(fmt.Sprintf(" Board Serial : %s\n", fru.BoardInfoArea.SerialNumber)) buf.WriteString(fmt.Sprintf(" Board Part Number : %s\n", fru.BoardInfoArea.PartNumber)) for _, v := range fru.BoardInfoArea.Custom { buf.WriteString(fmt.Sprintf(" Board Extra : %s\n", v)) } } if fru.ProductInfoArea != nil { buf.WriteString(fmt.Sprintf(" Product Mfg : %s\n", fru.ProductInfoArea.Manufacturer)) buf.WriteString(fmt.Sprintf(" Product Name : %s\n", fru.ProductInfoArea.Name)) buf.WriteString(fmt.Sprintf(" Product Version : %s\n", fru.ProductInfoArea.Version)) buf.WriteString(fmt.Sprintf(" Product Part Number : %s\n", fru.ProductInfoArea.PartModel)) buf.WriteString(fmt.Sprintf(" Product Serial : %s\n", fru.ProductInfoArea.SerialNumber)) assetTag, _ := fru.ProductInfoArea.AssetTagTypeLength.Chars(fru.ProductInfoArea.AssetTag) buf.WriteString(fmt.Sprintf(" Product Asset Tag : %s\n", string(assetTag))) buf.WriteString(fmt.Sprintf(" Product Asset Tag TL : %s\n", fru.ProductInfoArea.AssetTagTypeLength)) for _, v := range fru.ProductInfoArea.Custom { buf.WriteString(fmt.Sprintf(" Product Extra : %s\n", v)) } } for _, multiRecord := range fru.MultiRecords { buf.WriteString(fmt.Sprintf(" Multi Record : %s\n", multiRecord.RecordType.String())) } return buf.String() } // FRUCommonHeader is mandatory for all FRU Information Device implementations. // It holds version information for the overall information format specification // and offsets to the other information areas. // // The other areas may or may not be present based on the application of the device. // The offset unit in wire is in multiples of 8 bytes, offset value 0x0 indicates // that this area is not present. // // ref: FRU/8. Common Header Format type FRUCommonHeader struct { FormatVersion uint8 InternalOffset8B uint8 ChassisOffset8B uint8 BoardOffset8B uint8 ProductOffset8B uint8 MultiRecordsOffset8B uint8 Checksum uint8 } func (s *FRUCommonHeader) Pack() []byte { out := make([]byte, 8) packUint8(s.FormatVersion, out, 0) packUint8(s.InternalOffset8B, out, 1) packUint8(s.ChassisOffset8B, out, 2) packUint8(s.BoardOffset8B, out, 3) packUint8(s.ProductOffset8B, out, 4) packUint8(s.MultiRecordsOffset8B, out, 5) // a pad byte at index 6 packUint8(s.Checksum, out, 7) return out } func (s *FRUCommonHeader) Unpack(msg []byte) error { if len(msg) < 8 { return ErrUnpackedDataTooShortWith(len(msg), 8) } s.FormatVersion, _, _ = unpackUint8(msg, 0) s.InternalOffset8B, _, _ = unpackUint8(msg, 1) s.ChassisOffset8B, _, _ = unpackUint8(msg, 2) s.BoardOffset8B, _, _ = unpackUint8(msg, 3) s.ProductOffset8B, _, _ = unpackUint8(msg, 4) s.MultiRecordsOffset8B, _, _ = unpackUint8(msg, 5) s.Checksum, _, _ = unpackUint8(msg, 7) return nil } func (s *FRUCommonHeader) Valid() bool { var checksumFn = func(msg []byte, start int, end int) uint8 { c := 0 for i := start; i < end; i++ { c = (c + int(msg[i])) % 256 } return -uint8(c) } msg := s.Pack() return s.Checksum == checksumFn(msg, 0, 6) } func (s *FRUCommonHeader) String() string { return fmt.Sprintf(`Version : %#02x Offset Internal : %#02x Offset Chassis : %#02x Offset Board : %#02x Offset Product : %#02x Offset MultiRecord : %#02x`, s.FormatVersion, s.InternalOffset8B*8, s.ChassisOffset8B*8, s.BoardOffset8B*8, s.ProductOffset8B*8, s.MultiRecordsOffset8B*8, ) } // FRUInternalUseArea provides private, implementation-specific information storage // for other devices that exist on the same FRU as the FRU Information Device. // // The Internal Use Area is usually used to provide private non-volatile storage // for a management controller. // // see: FRU/9. Internal Use Area Format type FRUInternalUseArea struct { FormatVersion uint8 Data []byte } // FRUChassisInfoArea is used to hold Serial Number, Part Number, and other // information about the system chassis. A system can have multiple FRU // Information Devices within a chassis, but only one device should provide // the Chassis Info Area. // // see: FRU/10. Chassis Info Area Format type FRUChassisInfoArea struct { FormatVersion uint8 Length8B uint8 ChassisType ChassisType PartNumberTypeLength TypeLength PartNumber []byte SerialNumberTypeLength TypeLength SerialNumber []byte Custom [][]byte Unused []byte Checksum uint8 } func (fruChassis *FRUChassisInfoArea) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } // Chassis Info Area Length (in multiples of 8 bytes) if len(msg) < int(msg[1])*8 { return ErrUnpackedDataTooShortWith(len(msg), int(msg[1])*8) } fruChassis.FormatVersion = msg[0] fruChassis.Length8B = msg[1] fruChassis.ChassisType = ChassisType(msg[2]) var offset uint16 = 3 var err error offset, fruChassis.PartNumberTypeLength, fruChassis.PartNumber, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru chassis part number field failed, err: %w", err) } offset, fruChassis.SerialNumberTypeLength, fruChassis.SerialNumber, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru chassis serial number field failed, err: %w", err) } fruChassis.Custom, fruChassis.Unused, fruChassis.Checksum, err = getFRUCustomUnusedChecksumFields(msg, offset) if err != nil { return fmt.Errorf("getFRUCustomUnusedChecksumFields failed, err: %w", err) } return nil } type ChassisType uint8 func (chassisType ChassisType) String() string { // SMBIOS Specification: Table 17 - System Enclosure or Chassis Types var chassisTypeMaps = map[ChassisType]string{ 0x00: "Unspecified", 0x01: "Other", 0x02: "Unknown", 0x03: "Desktop", 0x04: "Low Profile Desktop", 0x05: "Pizza Box", 0x06: "Mini Tower", 0x07: "Tower", 0x08: "Portable", 0x09: "Laptop", 0x0a: "Notebook", 0x0b: "Hand Held", 0x0c: "Docking Station", 0x0d: "All in One", 0x0e: "Sub Notebook", 0x0f: "Space-saving", 0x10: "Lunch Box", 0x11: "Main Server Chassis", 0x12: "Expansion Chassis", 0x13: "SubChassis", 0x14: "Bus Expansion Chassis", 0x15: "Peripheral Chassis", 0x16: "RAID Chassis", 0x17: "Rack Mount Chassis", 0x18: "Sealed-case PC", 0x19: "Multi-system chassis", 0x1a: "Compact PCI", 0x1b: "Advanced TCA", 0x1c: "Blade", 0x1d: "Blade Enclosure", 0x1e: "Tablet", 0x1f: "Convertible", 0x20: "Detachable", 0x21: "IoT Gateway", 0x22: "Embedded PC", 0x23: "Mini PC", 0x24: "Stick PC", } s, ok := chassisTypeMaps[chassisType] if ok { return s } return "" } type ChassisState uint8 func (chassisState ChassisState) String() string { // SMBIOS Specification: Table 18 - System Enclosure or Chassis States var chassisStateMap = map[ChassisState]string{ 0x01: "Other", 0x02: "Unknown", 0x03: "Safe", 0x04: "Warning", 0x05: "Critical", 0x06: "Non-recoverable", } if s, ok := chassisStateMap[chassisState]; ok { return s } return "" } type ChassisSecurityStatus uint8 func (chassisSecurityStatus ChassisSecurityStatus) String() string { // SMBIOS Specification: // Table 19 - System Enclosure or Chassis Security Status field var chassisSecurityStatusMap = map[ChassisSecurityStatus]string{ 0x01: "Other", 0x02: "Unknown", 0x03: "None", 0x04: "External interface locked out", 0x05: "External interface enabled", } if s, ok := chassisSecurityStatusMap[chassisSecurityStatus]; ok { return s } return "" } // FRUBoardInfoArea provides Serial Number, Part Number, and other information about // the board that the FRU Information Device is located on. // The name 'Board Info Area' is somewhat a misnomer, because the usage is not // restricted to just circuit boards. This area is also typically used to // provide FRU information for any replaceable entities, boards, or sub-assemblies // that are not sold as standalone products separate from other components. // For example, individual boards from a board set, or a sub-chassis or backplane // that's part of a larger chassis.1 // // see: FRU/11. Board Info Area Format type FRUBoardInfoArea struct { FormatVersion uint8 Length8B uint8 LanguageCode uint8 MfgDateTime time.Time ManufacturerTypeLength TypeLength Manufacturer []byte ProductNameTypeLength TypeLength ProductName []byte SerialNumberTypeLength TypeLength SerialNumber []byte PartNumberTypeLength TypeLength PartNumber []byte FRUFileIDTypeLength TypeLength FRUFileID []byte Custom [][]byte Unused []byte Checksum uint8 } func (fruBoard *FRUBoardInfoArea) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } // Board Area Length (in multiples of 8 bytes) if len(msg) < int(msg[1])*8 { return ErrUnpackedDataTooShortWith(len(msg), int(msg[1])*8) } fruBoard.FormatVersion = msg[0] fruBoard.Length8B = msg[1] fruBoard.LanguageCode = msg[2] m, _, _ := unpackUint24L(msg, 3) // Number of minutes from 0:00 hrs 1/1/96. const secsFrom1970To1996 uint32 = 820454400 fruBoard.MfgDateTime = parseTimestamp(secsFrom1970To1996 + m*60) var offset uint16 = 6 var err error offset, fruBoard.ManufacturerTypeLength, fruBoard.Manufacturer, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru board manufacturer field failed, err: %w", err) } offset, fruBoard.ProductNameTypeLength, fruBoard.ProductName, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru board product name field failed, err: %w", err) } offset, fruBoard.SerialNumberTypeLength, fruBoard.SerialNumber, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru board serial number field failed, err: %w", err) } offset, fruBoard.PartNumberTypeLength, fruBoard.PartNumber, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru board part number field failed, err: %w", err) } offset, fruBoard.FRUFileIDTypeLength, fruBoard.FRUFileID, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru board file id field failed, err: %w", err) } fruBoard.Custom, fruBoard.Unused, fruBoard.Checksum, err = getFRUCustomUnusedChecksumFields(msg, offset) if err != nil { return fmt.Errorf("getFRUCustomUnusedChecksumFields failed, err: %w", err) } return nil } type BoardType uint8 func (boardType BoardType) String() string { var boardTypeMap = map[BoardType]string{ 0x01: "Unknown", 0x02: "Other", 0x03: "Server Blade", 0x04: "Connectivity Switch", 0x05: "System Management Module", 0x06: "Processor Module", 0x07: "I/O Module", 0x08: "Memory Module", 0x09: "Daughter board", 0x0a: "Motherboard", 0x0b: "Processor/Memory Module", 0x0c: "Processor/IO Module", 0x0d: "Interconnect board", } if s, ok := boardTypeMap[boardType]; ok { return s } return "" } // The Product Info Area is present if the FRU itself is a separate product. // This is typically seen when the FRU is an add-in card, sub-assembly, or // a power supply from a separate vendor, etc. // When this area is provided in the FRU Information Device that contains the // Chassis Info Area, the product info is for the overall system, as initially manufactured. // // see: FRU/12. Product Info Area Format type FRUProductInfoArea struct { FormatVersion uint8 Length8B uint8 LanguageCode uint8 ManufacturerTypeLength TypeLength Manufacturer []byte NameTypeLength TypeLength Name []byte PartModelTypeLength TypeLength PartModel []byte VersionTypeLength TypeLength Version []byte SerialNumberTypeLength TypeLength SerialNumber []byte AssetTagTypeLength TypeLength AssetTag []byte FRUFileIDTypeLength TypeLength FRUFileID []byte Custom [][]byte Unused []byte Checksum uint8 } func (fruProduct *FRUProductInfoArea) Unpack(msg []byte) error { if len(msg) < 2 { return ErrUnpackedDataTooShortWith(len(msg), 2) } // Product Area Length (in multiples of 8 bytes) if len(msg) < int(msg[1])*8 { return ErrUnpackedDataTooShortWith(len(msg), int(msg[1])*8) } fruProduct.FormatVersion = msg[0] fruProduct.Length8B = msg[1] fruProduct.LanguageCode = msg[2] var offset uint16 = 3 var err error offset, fruProduct.ManufacturerTypeLength, fruProduct.Manufacturer, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru product manufacturer field failed, err: %w", err) } offset, fruProduct.NameTypeLength, fruProduct.Name, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru product name field failed, err: %w", err) } offset, fruProduct.PartModelTypeLength, fruProduct.PartModel, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru product part model field failed, err: %w", err) } offset, fruProduct.VersionTypeLength, fruProduct.Version, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru product version field failed, err: %w", err) } offset, fruProduct.SerialNumberTypeLength, fruProduct.SerialNumber, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru product serial number field failed, err: %w", err) } offset, fruProduct.AssetTagTypeLength, fruProduct.AssetTag, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru product asset tag field failed, err: %w", err) } offset, fruProduct.FRUFileIDTypeLength, fruProduct.FRUFileID, err = getFRUTypeLengthField(msg, offset) if err != nil { return fmt.Errorf("get fru product file id field failed, err: %w", err) } fruProduct.Custom, fruProduct.Unused, fruProduct.Checksum, err = getFRUCustomUnusedChecksumFields(msg, offset) if err != nil { return fmt.Errorf("getFRUCustomUnusedChecksumFields failed, err: %w", err) } return nil } // The MultiRecord Info Area provides a region that holds one or more records // where the type and format of the information is specified in the individual // headers for the records. // // see: FRU/16. MultiRecord Area type FRUMultiRecord struct { RecordType FRURecordType // used to identify the information contained in the record EndOfList bool // indicates if this record is the last record in the MultiRecord area // Record Format version (=2h unless otherwise specified) // This field is used to identify the revision level of information stored in this area. // This number will start at zero for each new area. If changes need to be made to the record, // e.g. fields added/removed, the version number will be increased to reflect the change. FormatVersion uint8 // RecordLength indicates the number of bytes of data in the record. This byte can also be used to find the // next area in the list. If the "End of List" bit is zero, the length can be added the starting offset of the current // Record Data to get the offset of the next Record Header. This field allows for 0 to 255 bytes of data for // each record. RecordLength uint8 RecordChecksum uint8 HeaderChecksum uint8 RecordData []byte } func (fruMultiRecord *FRUMultiRecord) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } // RecordLength if len(msg) < int(msg[2]) { return ErrUnpackedDataTooShortWith(len(msg), int(msg[2])) } fruMultiRecord.RecordType = FRURecordType(msg[0]) b1 := msg[1] fruMultiRecord.EndOfList = isBit7Set(b1) fruMultiRecord.FormatVersion = b1 & 0x0f fruMultiRecord.RecordLength = msg[2] fruMultiRecord.RecordChecksum = msg[3] fruMultiRecord.HeaderChecksum = msg[4] dataLen := int(fruMultiRecord.RecordLength) fruMultiRecord.RecordData, _, _ = unpackBytes(msg, 5, dataLen) return nil } type FRURecordType uint8 func (t FRURecordType) String() string { // fru: Table 16-2, MultiRecord Area Record Types m := map[FRURecordType]string{ 0x00: "Power Supply", 0x01: "DC Output", 0x02: "DC Load", 0x03: "Management Access", 0x04: "Base Compatibility", 0x05: "Extended Compatibility", 0x06: "ASF Fixed SMBus Device", // see [ASF_2.0] for definition 0x07: "ASF Legacy-Device Alerts", // see [ASF_2.0] for definition 0x08: "ASF Remote Control", // see [ASF_2.0] for definition 0x09: "Extended DC Output", 0x0a: "Extended DC Load", // 0x0b-0x0f reserved for definition by working group, Refer to specifications from the NVM Express™ working group (www.nvmexpress.org) // 0x10-0xbf reserved // 0xc0-0xff OEM Record Types } s, ok := m[t] if ok { return s } return "" } // fru: 18.1 Power Supply Information (Record Type 0x00) type FRURecordTypePowerSupply struct { // This field allows for Power Supplies with capacities from 0 to 4095 watts. OverallCapacity uint16 // The highest instantaneous VA value that this supply draws during operation (other than during Inrush). In integer units. FFFFh if not specified. PeakVA uint16 // Maximum inrush of current, in Amps, into the power supply. FFh if not specified. InrushCurrent uint8 // 涌入电流 // Number of milliseconds before power supply loading enters non-startup operating range. Set to 0 if no inrush current specified. InrushIntervalMilliSecond uint8 // This specifies the low end of acceptable voltage into the power supply. The units are 10mV. LowEndInputVoltageRange1 uint16 // This specifies the high end of acceptable voltage into the power supply. The units are 10mV. HighEndInputVoltageRange1 uint16 // This specifies the low end of acceptable voltage into the power supply. This field would be used if the power supply did not support auto-switch. Range 1 would define the 110V range, while range 2 would be used for 220V. The units are 10mV. LowEndInputVoltageRange2 uint16 // This specifies the high end of acceptable voltage into the power supply. This field would be used if the power supply did not support auto-switch. Range 1 would define the 110V range, while range 2 would be used for 220V. The units are 10mV. HighEndInputVoltageRange2 uint16 // This specifies the low end of acceptable frequency range into the power supply. Use 00h if supply accepts a DC input. LowEndInputFrequencyRange uint8 // This specifies the high end of acceptable frequency range into the power supply. Use 00h for both Low End and High End frequency range if supply only takes a DC input. HighEndInputFrequencyRange uint8 // Minimum number of milliseconds the power supply can hold up POWERGOOD (and maintain valid DC output) after input power is lost. InputDropoutToleranceMilliSecond uint8 HotSwapSupport bool AutoSwitch bool PowerFactorCorrection bool PredictiveFailSupport bool // the number of seconds peak wattage can be sustained (0-15 seconds) PeakWattageHoldupSecond uint8 // the peak wattage the power supply can produce during this time period PeakCapacity uint16 CombinedWattageVoltage1 uint8 // bit 7:4 - Voltage 1 CombinedWattageVoltage2 uint8 // bit 3:0 - Voltage 2 // 0000b (0) 12V // 0001b (1) -12V // 0010b (2) 5V // 0011b (3) 3.3V TotalCombinedWattage uint16 // This field serves two purposes. // It clarifies what type of predictive fail the power supply supports // (pass/fail signal or the tachometer output of the power supply fan) // and indicates the predictive failing point for tach outputs. // This field should be written as zero and ignored if the // predictive failure pin of the power supply is not supported. // // 0x00 Predictive fail pin indicates pass/fail // 0x01 - 0xFF Lower threshold to indicate predictive failure (Rotations per second) PredictiveFailTachometerLowerThreshold uint8 // RPS } // FRU: 18.2 DC Output (Record Type 0x01) type FRURecordTypeDCOutput struct { // if the power supply provides this output even when the power supply is switched off. OutputWhenOff bool OutputNumber uint8 // Expected voltage from the power supply. Value is a signed short given in 10 millivolt increments. // 额定电压 毫-伏特 NominalVoltage10mV int16 MaxNegativeVoltage10mV int16 MaxPositiveVoltage10mV int16 RippleNoise1mV uint16 // 毫-安培 MinCurrentDraw1mA uint16 MaxCurrentDraw1mA uint16 } func (output *FRURecordTypeDCOutput) Unpack(msg []byte) error { if len(msg) < 12 { return ErrUnpackedDataTooShortWith(len(msg), 12) } b, _, _ := unpackUint8(msg, 0) output.OutputWhenOff = isBit7Set(b) output.OutputNumber = b & 0x0f b1, _, _ := unpackUint16L(msg, 1) output.NominalVoltage10mV = int16(b1) b3, _, _ := unpackUint16L(msg, 3) output.MaxNegativeVoltage10mV = int16(b3) b5, _, _ := unpackUint16L(msg, 5) output.MaxPositiveVoltage10mV = int16(b5) output.RippleNoise1mV, _, _ = unpackUint16L(msg, 7) output.MinCurrentDraw1mA, _, _ = unpackUint16L(msg, 9) output.MaxCurrentDraw1mA, _, _ = unpackUint16L(msg, 11) return nil } // FRU: 18.2a Extended DC Output (Record Type 0x09) type FRURecordTypeExtendedDCOutput struct { // if the power supply provides this output even when the power supply is switched off. OutputWhenOff bool // This record can be used to support power supplies with outputs that exceed 65.535 Amps. // 0b = 10 mA // 1b = 100 mA CurrentUnits100 bool OutputNumber uint8 // Expected voltage from the power supply. Value is a signed short given in 10 millivolt increments. // 毫-伏特 NominalVoltage10mV int16 MaxNegativeVoltage10mV int16 MaxPositiveVoltage10mV int16 RippleNoise uint16 // The unit is determined by CurrentUnits100 field. MinCurrentDraw uint16 MaxCurrentDraw uint16 } func (output *FRURecordTypeExtendedDCOutput) Unpack(msg []byte) error { if len(msg) < 12 { return ErrUnpackedDataTooShortWith(len(msg), 12) } b, _, _ := unpackUint8(msg, 0) output.OutputWhenOff = isBit7Set(b) output.CurrentUnits100 = isBit4Set(b) output.OutputNumber = b & 0x0f b1, _, _ := unpackUint16L(msg, 1) output.NominalVoltage10mV = int16(b1) b3, _, _ := unpackUint16L(msg, 3) output.MaxNegativeVoltage10mV = int16(b3) b5, _, _ := unpackUint16L(msg, 5) output.MaxPositiveVoltage10mV = int16(b5) output.RippleNoise, _, _ = unpackUint16L(msg, 7) output.MinCurrentDraw, _, _ = unpackUint16L(msg, 9) output.MaxCurrentDraw, _, _ = unpackUint16L(msg, 11) return nil } // FRU: 18.3 DC Load (Record Type 0x02) type FRURecordTypeDCLoad struct { OutputNumber uint8 NominalVoltage10mV int16 MinTolerableVoltage10mV int16 MaxTolerableVoltage10mV int16 RippleNoise1mV uint16 MinCurrentLoad1mA uint16 MaxCurrentLoad1mA uint16 } func (output *FRURecordTypeDCLoad) Unpack(msg []byte) error { if len(msg) < 12 { return ErrUnpackedDataTooShortWith(len(msg), 12) } b, _, _ := unpackUint8(msg, 0) output.OutputNumber = b & 0x0f b1, _, _ := unpackUint16L(msg, 1) output.NominalVoltage10mV = int16(b1) b3, _, _ := unpackUint16L(msg, 3) output.MinTolerableVoltage10mV = int16(b3) b5, _, _ := unpackUint16L(msg, 5) output.MaxTolerableVoltage10mV = int16(b5) output.RippleNoise1mV, _, _ = unpackUint16L(msg, 7) output.MinCurrentLoad1mA, _, _ = unpackUint16L(msg, 9) output.MaxCurrentLoad1mA, _, _ = unpackUint16L(msg, 11) return nil } // FRU: 18.3a Extended DC Load (Record Type 0x0A) type FRURecordTypeExtendedDCLoad struct { IsCurrentUnit100mA bool // current units: true = 100 mA , false = 10 mA OutputNumber uint8 NominalVoltage10mV int16 MinVoltage10mV int16 MaxVoltage10mV int16 RippleNoise1mV int16 MinCurrentLoad uint16 // units is determined by IsCurrentUnit100mA field MaxCurrentLoad uint16 // units is determined by IsCurrentUnit100mA field } func (f *FRURecordTypeExtendedDCLoad) Unpack(msg []byte) error { if len(msg) < 13 { return ErrUnpackedDataTooShortWith(len(msg), 13) } f.IsCurrentUnit100mA = isBit7Set(msg[0]) f.OutputNumber = msg[0] & 0x0f b1, _, _ := unpackUint16L(msg, 1) f.NominalVoltage10mV = int16(b1) b3, _, _ := unpackUint16L(msg, 3) f.MinVoltage10mV = int16(b3) b5, _, _ := unpackUint16L(msg, 5) f.MaxVoltage10mV = int16(b5) b7, _, _ := unpackUint16L(msg, 7) f.RippleNoise1mV = int16(b7) f.MinCurrentLoad, _, _ = unpackUint16L(msg, 9) f.MaxCurrentLoad, _, _ = unpackUint16L(msg, 11) return nil } type ManagementAccessSubRecordType uint8 func (t ManagementAccessSubRecordType) String() string { m := map[ManagementAccessSubRecordType]string{ // SystemMgmtURL []byte // A name to identify the system that contains this FRU. (same as DMI // DMTF|General Information|001 - System Name) 0x01: "System Management URL", // SystemName []byte // The IP network address of the system that contains this FRU. Can be either the IP // address or the host name + domain name (eg. finance.sc.hp.com) 0x02: "System Name", // SystemPingAddr []byte // The Internet Uniform Resource Locator string that can be used through a World // Wide Web browser to obtain management information about this FRU. (same as DMI // DMTF|Field Replaceable Unit|002 - FRU Internet Uniform Resource Locator) 0x03: "System Ping Address", // ComponentMgmtURL []byte // A clear description of this FRU. (same asDMI "DMTF|Field Replaceable Unit|002 - Description") 0x04: "Component Management URL", // ComponentName []byte // The IP network address of this FRU. Can be either the IP address or the host name // + domain name (e.g. critter.sc.hp.com). 0x05: "Component Name", // ComponentPingAddr []byte // This is a copy of the system GUID from [SMBIOS] 0x06: "Component Ping Address", // SystemUniqueID [16]byte 0x07: "System Unique ID", } s, ok := m[t] if ok { return s } return "" } // FRU: 18.4 Management Access Record (Record Type 0x03) type FRURecordTypeManagementAccess struct { SubRecordType ManagementAccessSubRecordType Data []byte // the size is MultiRecord.TypeLength.Length() - 1 } func (f *FRURecordTypeManagementAccess) Unpack(msg []byte) error { if len(msg) < 1 { return ErrUnpackedDataTooShortWith(len(msg), 1) } f.SubRecordType = ManagementAccessSubRecordType(msg[0]) f.Data, _, _ = unpackBytes(msg, 1, len(msg)-1) return nil } // FRU: 18.5 Base Compatibility Record (Record Type 0x04) type FRURecordTypeBaseCompatibility struct { ManufacturerID uint32 EntityID EntityID CompatibilityBase uint8 CompatibilityCodeStart uint8 CodeRangeMask uint8 } func (f *FRURecordTypeBaseCompatibility) Unpack(msg []byte) error { if len(msg) < 7 { return ErrUnpackedDataTooShortWith(len(msg), 7) } f.ManufacturerID, _, _ = unpackUint24L(msg, 0) f.EntityID = EntityID(msg[3]) f.CompatibilityBase = msg[4] f.CompatibilityCodeStart = msg[5] f.CodeRangeMask = msg[6] return nil } // FRU: 18.6 Extended Compatibility Record (Record Type 0x05) type FRURecordTypeExtendedCompatibilityRecord struct { ManufacturerID uint32 EntityID EntityID CompatibilityBase uint8 CompatibilityCodeStart uint8 CodeRangeMask uint8 } func (f *FRURecordTypeExtendedCompatibilityRecord) Unpack(msg []byte) error { if len(msg) < 7 { return ErrUnpackedDataTooShortWith(len(msg), 7) } f.ManufacturerID, _, _ = unpackUint24L(msg, 0) f.EntityID = EntityID(msg[3]) f.CompatibilityBase = msg[4] f.CompatibilityCodeStart = msg[5] f.CodeRangeMask = msg[6] return nil } // FRU: 18.7 OEM Record (Record Types 0xC0-0xFF) type FRURecordTypeOEM struct { ManufacturerID uint32 Data []byte } func (f *FRURecordTypeOEM) Unpack(msg []byte) error { if len(msg) < 3 { return ErrUnpackedDataTooShortWith(len(msg), 3) } f.ManufacturerID, _, _ = unpackUint24L(msg, 0) f.Data, _, _ = unpackBytes(msg, 3, len(msg)-3) return nil } // getFRUTypeLengthField return a field data bytes whose length is determined by // a TypeLength byte. The offset index SHOULD points to the TypeLength field. func getFRUTypeLengthField(fruData []byte, offset uint16) (nextOffset uint16, typeLength TypeLength, fieldData []byte, err error) { if len(fruData) < int(offset+1) { err = ErrUnpackedDataTooShortWith(len(fruData), int(offset+1)) return } typeLength = TypeLength(fruData[offset]) length := typeLength.Length() if len(fruData) < int(offset)+int(length)+1 { err = ErrUnpackedDataTooShortWith(len(fruData), int(offset)+int(length)+1) return } dataStart := int(offset) + 1 dataEnd := dataStart + int(length) fieldDataRaw := fruData[dataStart:dataEnd] fieldData, err = typeLength.Chars(fieldDataRaw) if err != nil { err = fmt.Errorf("get chars from typelength failed, err: %w", err) return } nextOffset = offset + uint16(length) + 1 return } // getFRUCustomUnusedChecksumFields is a helper function to get // custom, unused, and checksum these three fields from fru data. // The offset SHOULD points to the start of the custom area fields. func getFRUCustomUnusedChecksumFields(fruData []byte, offset uint16) (custom [][]byte, unused []byte, checksum uint8, err error) { if len(fruData) < int(offset+1) { err = ErrUnpackedDataTooShortWith(len(fruData), int(offset+1)) return } for { if fruData[offset] == FRUAreaFieldsEndMark { break } nextOffset, _, fieldData, e := getFRUTypeLengthField(fruData, offset) if e != nil { err = fmt.Errorf("getFRUTypeLengthField failed, err: %s", e) return } offset = nextOffset if len(fieldData) == 0 { break } custom = append(custom, fieldData) } unusedBytesOffset := int(offset) + 1 unusedBytesLen := len(fruData) - int(offset) - 2 unused, _, _ = unpackBytes(fruData, unusedBytesOffset, unusedBytesLen) checksum = fruData[len(fruData)-1] return } golang-github-bougou-go-ipmi-0.7.2/types_generator.go000066400000000000000000000075501474110527100226560ustar00rootroot00000000000000package ipmi // 5.4 Sensor Owner Identification // the "owner" of the sensor. // The combination of Sensor Owner ID and Sensor Number uniquely identify a sensor in the system. // the Sensor Data Record and SEL information must contain information to identify the "owner" of the sensor. // // For management controllers, a Slave Address and LUN identify the owner of a sensor on the IPMB. // // For system software, a Software ID identifies the owner of a sensor. // // These fields are used in Event Messages, where events from management controllers or the IPMB are identified by an eight-bit field where the upper 7-bits are the Slave Address or System Software ID. // // The least significant bit is a 0 if the value represents a Slave Address and a 1 if the value represents a System Software ID. // So all Software IDs are odd numbers (because the bit 0 is fixed to 1b), // and all slave addresses are even numbers (because bit 0 is fixed to 0b) // // 5.5 Software IDs (SWIDs) type SoftwareID uint8 type SoftwareType string const ( SoftwareTypeBIOS SoftwareType = "BIOS" SoftwareTypeSMIHandler SoftwareType = "SMI Handler" SoftwareTypeSMS SoftwareType = "System Management Software" SoftwareTypeOEM SoftwareType = "OEM" SoftwareTypeRCS SoftwareType = "Remote Console Software" SoftwareTypeTerminalRCS SoftwareType = "Terminal Mode Remote Console Software" SoftwareTypeReserved SoftwareType = "Reserved" ) // Software IDs can be cla func (i SoftwareID) Type() SoftwareType { if i >= SoftwareID(0x01) && i <= SoftwareID(0x1f) { return SoftwareTypeBIOS } if i >= SoftwareID(0x21) && i <= SoftwareID(0x3f) { return SoftwareTypeSMIHandler } if i >= SoftwareID(0x41) && i <= SoftwareID(0x5f) { return SoftwareTypeSMS } if i >= SoftwareID(0x61) && i <= SoftwareID(0x7f) { return SoftwareTypeOEM } if i >= SoftwareID(0x81) && i <= SoftwareID(0x8d) { return SoftwareTypeRCS } if i == SoftwareID(0x8f) { return SoftwareTypeTerminalRCS } return SoftwareTypeReserved } // GeneratorID is 2 bytes. // the LSB means: Slave Address (for IPMB) or Software ID (for system software); // the MSB means: Channel Number / LUN (for IPMB) or always 0 (for system software) // // In some scenario, the GeneratorID is used as 1 byte, because // for IPMB, the Slave Address and LUN info are carried in IPMI Request/Response Messages; // and for system software, the MSB is always 0, so only LSB is need. // 32.1 SEL Event Records // // Byte 1 // [7:1] - 7-bit Slave Address, or 7-bit system software ID // [0] 0b = IPMB Slave Address, 1b = system software ID // Byte 2 // [7:4] - Channel number. Channel that event message was received over. 0h if the // event message was received via the system interface, primary IPMB, or // internally generated by the BMC. (New for IPMI v1.5. These bits were reserved // in IPMI v1.0) // [3:2] - reserved. Write as 00b. // [1:0] - IPMB device LUN if byte 1 holds Slave Address. 00b otherwise type GeneratorID uint16 const ( GeneratorBMC GeneratorID = 0x0020 GeneratorBIOSPOST GeneratorID = 0x0001 GeneratorBIOSSMIHandler GeneratorID = 0x0033 GeneratorIntelNMFirmware GeneratorID = 0x002c // Node Manager GeneratorIntelMEFirmware GeneratorID = 0x602c // Management Engine // With Microsoft Windows Server* 2003 R2 and later versions, an Intelligent Platform Management Interface (IPMI) driver was added. // This added the capability of logging some operating system events to the SEL. GeneratorMicrosoftOS GeneratorID = 0x0041 // The **Open IPMI driver** supports the ability to put semi-custom and custom events in the system event log if a panic occurs. GeneratorLinuxKernelPanic GeneratorID = 0x0021 ) // see: Intel System Event Log (SEL) Troubleshooting Guide Rev 3.4 September 2019 section 3.1 type SensorNumber uint8 const SensorNumberReserved = 0xff type SDRMapBySensorNumber map[GeneratorID]map[SensorNumber]*SDR golang-github-bougou-go-ipmi-0.7.2/types_guid.go000066400000000000000000000122641474110527100216160ustar00rootroot00000000000000package ipmi import ( "encoding/binary" "fmt" "time" "github.com/google/uuid" ) // GUIDMode is the way how to decode the 16 bytes GUID type GUIDMode uint8 const ( GUIDModeRFC4122 GUIDMode = iota GUIDModeIPMI GUIDModeSMBIOS ) func (guidMode GUIDMode) String() string { m := map[GUIDMode]string{ GUIDModeRFC4122: "RFC4122", GUIDModeIPMI: "IPMI", GUIDModeSMBIOS: "SMBIOS", } if s, ok := m[guidMode]; ok { return s } return "" } // ParseGUID parses the raw guid data with the specified encoding mode. // Different GUIDMode would interpret the [16]byte data into different layout of uuid. // // see: https://github.com/ipmitool/ipmitool/issues/25 func ParseGUID(data []byte, guidMode GUIDMode) (*uuid.UUID, error) { if len(data) != 16 { return nil, fmt.Errorf("the length of GUID data must be 16 (%d)", len(data)) } d := array16(data) switch guidMode { case GUIDModeRFC4122: return parseGUID_RFC4122(d) case GUIDModeIPMI: return parseGUID_IPMI(d) case GUIDModeSMBIOS: return parseGUID_SMBIOS(d) default: return nil, fmt.Errorf("unknown GUIDMode: (%s)", guidMode) } } func parseGUID_RFC4122(data [16]byte) (*uuid.UUID, error) { u, err := uuid.FromBytes(data[:]) if err != nil { return nil, err } return &u, nil } // see: 20.8 Get Device GUID Command func parseGUID_IPMI(data [16]byte) (*uuid.UUID, error) { var rfc4122Data [16]byte // time_low rfc4122Data[0] = data[15] rfc4122Data[1] = data[14] rfc4122Data[2] = data[13] rfc4122Data[3] = data[12] // time_mid rfc4122Data[4] = data[11] rfc4122Data[5] = data[10] // time_high_and_version rfc4122Data[6] = data[9] rfc4122Data[7] = data[8] // clock_seq_hi_and_reserved rfc4122Data[8] = data[7] // clock_seq_low rfc4122Data[9] = data[6] // node rfc4122Data[10] = data[5] rfc4122Data[11] = data[4] rfc4122Data[12] = data[3] rfc4122Data[13] = data[2] rfc4122Data[14] = data[1] rfc4122Data[15] = data[0] return parseGUID_RFC4122(rfc4122Data) } // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.2.0.pdf // // 921 7.2.1 System — UUID // // 928 Although RFC4122 recommends network byte order for all fields, the PC industry (including the ACPI, // 929 UEFI, and Microsoft specifications) has consistently used little-endian byte encoding for the first three // 930 fields: time_low, time_mid, time_hi_and_version. The same encoding, also known as wire format, should // 931 also be used for the SMBIOS representation of the UUID. // 932 The UUID {00112233-4455-6677-8899-AABBCCDDEEFF} would thus be represented as: // 933 33 22 11 00 55 44 77 66 88 99 AA BB CC DD EE FF. // 934 If the value is all FFh, the ID is not currently present in the system, but it can be set. If the value is all 00h, // 935 the ID is not present in the system. func parseGUID_SMBIOS(data [16]byte) (*uuid.UUID, error) { var rfc4122Data [16]byte // time_low rfc4122Data[0] = data[3] rfc4122Data[1] = data[2] rfc4122Data[2] = data[1] rfc4122Data[3] = data[0] // time_mid rfc4122Data[4] = data[5] rfc4122Data[5] = data[4] // time_hi_and_version rfc4122Data[6] = data[7] rfc4122Data[7] = data[6] // clock_seq_hi_and_reserved rfc4122Data[8] = data[8] // clock_seq_low rfc4122Data[9] = data[9] // node rfc4122Data[10] = data[10] rfc4122Data[11] = data[11] rfc4122Data[12] = data[12] rfc4122Data[13] = data[13] rfc4122Data[14] = data[14] rfc4122Data[15] = data[15] return parseGUID_RFC4122(rfc4122Data) } // see https://github.com/ipmitool/ipmitool/issues/25#issuecomment-409703163 func IPMILegacyGUIDTime(u *uuid.UUID) time.Time { sec := int64(binary.BigEndian.Uint32(u[0:4])) return time.Unix(sec, 0) } // see: https://uuid.ramsey.dev/en/stable/rfc4122.html func UUIDVersionString(u *uuid.UUID) string { v := u.Version() var name string switch v { case 1: name = "Time-based Gregorian Time" case 2: name = "Time-based DCE Security with POSIX UIDs" case 3: name = "Name-based MD5" case 4: name = "Random" case 5: name = "Name-based SHA-1" case 6: name = "Reordered Time" case 7: name = "Unix Epoch Time" case 8: name = "Custom" default: name = "Unknown" } return fmt.Sprintf("%s (%s)", v.String(), name) } func FormatGUIDDetails(guid [16]byte) string { formatGUID := func(u *uuid.UUID, mode GUIDMode) string { out := fmt.Sprintf("UUID Encoding : %s\n", mode) out += fmt.Sprintf("GUID : %s\n", u.String()) out += fmt.Sprintf("UUID Version : %s\n", UUIDVersionString(u)) out += fmt.Sprintf("UUID Variant : %s\n", u.Variant().String()) sec, nsec := u.Time().UnixTime() out += fmt.Sprintf("Timestamp : %s\n", time.Unix(sec, nsec).Format(timeFormat)) out += fmt.Sprintf("Timestamp(Legacy) : %s\n", IPMILegacyGUIDTime(u).Format(timeFormat)) return out } out := "" u, err := ParseGUID(guid[:], GUIDModeSMBIOS) if err != nil { return "" } out += formatGUID(u, GUIDModeSMBIOS) out += "\n-------------------\n" u, err = ParseGUID(guid[:], GUIDModeIPMI) if err != nil { return "" } out += "\n" out += formatGUID(u, GUIDModeIPMI) out += "\n-------------------\n" u, err = ParseGUID(guid[:], GUIDModeRFC4122) if err != nil { return "" } out += "\n" out += formatGUID(u, GUIDModeRFC4122) out += "\n-------------------\n" return out } golang-github-bougou-go-ipmi-0.7.2/types_guid_test.go000066400000000000000000000044401474110527100226520ustar00rootroot00000000000000package ipmi import ( "fmt" "strings" "testing" "time" ) func Test_ParseGUID(t *testing.T) { tests := []struct { input [16]byte expecteds map[GUIDMode]string }{ { input: [16]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, expecteds: map[GUIDMode]string{ GUIDModeRFC4122: "00112233-4455-6677-8899-AABBCCDDEEFF", GUIDModeIPMI: "FFEEDDCC-BBAA-9988-7766-554433221100", GUIDModeSMBIOS: "33221100-5544-7766-8899-AABBCCDDEEFF", }, }, } for _, tt := range tests { for _, mode := range []GUIDMode{ GUIDModeRFC4122, GUIDModeIPMI, GUIDModeSMBIOS, } { u, err := ParseGUID(tt.input[:], mode) if err != nil { t.Error(err) return } actual := strings.ToUpper(u.String()) expected := tt.expecteds[mode] sec, nsec := u.Time().UnixTime() uTime := time.Unix(sec, nsec) fmt.Printf("mode: %s, string: %s, version: %s, variant: %s, time: %v\n", mode, actual, u.Version(), u.Variant(), uTime) if actual != expected { t.Errorf("not matched for GUIDMode (%s), actual (%s), expected (%s)", mode, actual, expected) return } } } } func Test_ParseGUID2(t *testing.T) { tests := []struct { inputs map[GUIDMode][16]byte mode GUIDMode expected string }{ { inputs: map[GUIDMode][16]byte{ GUIDModeRFC4122: {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, GUIDModeIPMI: {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}, GUIDModeSMBIOS: {0x33, 0x22, 0x11, 0x00, 0x55, 0x44, 0x77, 0x66, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, }, expected: "00112233-4455-6677-8899-AABBCCDDEEFF", }, } for _, tt := range tests { for mode, input := range tt.inputs { u, err := ParseGUID(input[:], mode) if err != nil { t.Error(err) return } actual := strings.ToUpper(u.String()) expected := tt.expected sec, nsec := u.Time().UnixTime() uTime := time.Unix(sec, nsec) fmt.Printf("mode: %s, string: %s, version: %s, variant: %s, time: %v\n", mode, actual, u.Version(), u.Variant(), uTime) if actual != expected { t.Errorf("not matched for GUIDMode (%s), actual (%s), expected (%s)", mode, actual, expected) return } } } } golang-github-bougou-go-ipmi-0.7.2/types_ipmb.go000066400000000000000000000022141474110527100216070ustar00rootroot00000000000000package ipmi // see: https://community.infineon.com/t5/Knowledge-Base-Articles/Difference-between-7-bit-vs-8-bit-I2C-addressing/ta-p/798072 // // I2CAddress7Bit is a 7-bit I2C address, the bit 0 to bit 6 take effect, bit 7 is always 0. // // eg: `var a I2CAddress7Bit = 0x35` // - 0 011 0101 = 0x35 // - 7 654 3210 bit position type I2CAddress7Bit uint8 // I2CAddress8Bit represents 8-bit I2C address, the 7-bit I2CAddress occupies bit 1 to bit 7, bit 0 indicates for write or read. // // eg: `var a I2CAddress7Bit = 0x35` // - 0110 101 0 = 0x6A (for write) // - 0110 101 1 = 0x6B (fore read) // - 7654 321 0 bit position type I2CAddress8Bit uint8 // To8BitForWrite convert 7-bit I2C address to 8-bit I2C address, bit 1 to bit 7 for I2C address, bit 0 set to 0 func (a I2CAddress7Bit) To8BitForWrite() I2CAddress8Bit { return I2CAddress8Bit(a << 1) } // To8BitForRead convert 7-bit I2C address to 8-bit I2C address, bit 1 to bit 7 for I2C address, bit 0 set to 1 func (a I2CAddress7Bit) To8BitForRead() I2CAddress8Bit { return I2CAddress8Bit(a<<1 | 0x01) } func (a I2CAddress8Bit) To7Bit() I2CAddress7Bit { return I2CAddress7Bit(a >> 1) } golang-github-bougou-go-ipmi-0.7.2/types_ipmi.go000066400000000000000000000145161474110527100216260ustar00rootroot00000000000000package ipmi import "context" const ( IPMIRequesterSequenceMax uint8 = 0x3f // RequesterSequence only occupy 6 bits ) // 13.8 IPMI LAN Message Format type IPMIRequest struct { // SlaveAddress or SoftwareID // Responder's Slave Address. 1 byte. LS bit is 0 for Slave Addresses and 1 for Software IDs. Upper 7-bits hold Slave Address or Software ID, respectively. This byte is always 20h when the BMC is the responder. ResponderAddr uint8 // SlaveAddress or SoftwareID // The lower 2-bits of the netFn byte identify the logical unit number, which provides further sub-addressing within the target node. NetFn NetFn // (even) / rsLUN ResponderLUN uint8 // lower 2 bits // Checksum1 is filled by calling ComputeChecksum method Checksum1 uint8 // SlaveAddress or SoftwareID // Requester's Address. 1 byte. LS bit is 0 for Slave Addresses and 1 for Software IDs. Upper 7-bits hold Slave Address or Software ID, respectively. This byte is always 20h when the BMC is the requester. RequesterAddr uint8 // rqSA RequesterSequence uint8 // rqSeq, occupies the highest 6 bits, (so should left shit 2 bits) RequesterLUN uint8 // rqLUN, occupies the lowest 2 bits Command uint8 // Command ID // Command Request Body Data defined by each command. CommandData []byte // optional, 0 or more // Checksum2 is filled by calling ComputeChecksum method Checksum2 uint8 } // IPMIResponse represent IPMI PayloadType msg response type IPMIResponse struct { // Requester's Address. 1 byte. LS bit is 0 for Slave Addresses and 1 for Software IDs. Upper 7-bits hold Slave Address or Software ID, respectively. This byte is always 20h when the BMC is the requester. RequesterAddr uint8 // SlaveAddress or SoftwareID // Network Function code // The lower 2-bits of the netFn byte identify the logical unit number, which provides further sub-addressing within the target node. NetFn NetFn // (odd) higher 6 bits // Requester's LUN RequestLUN uint8 // lower 2 bits // 8-bit checksum algorithm: Initialize checksum to 0. For each byte, checksum = (checksum + byte) modulo 256. Then checksum = - checksum. When the checksum and the bytes are added together, modulo 256, the result should be 0. Checksum1 uint8 // Responder's Slave Address. 1 byte. LS bit is 0 for Slave Addresses and 1 for Software IDs. Upper 7-bits hold Slave Address or Software ID, respectively. This byte is always 20h when the BMC is the responder. ResponderAddr uint8 // // SlaveAddress or SoftwareID // Sequence number. This field is used to verify that a response is for a particular instance of a request. Refer to [IPMB] for additional information on use and operation of the Seq field. RequesterSequence uint8 // higher 6 bits ResponderLUN uint8 // lower 2 bits Command uint8 // Completion code returned in the response to indicated success/failure status of the request. CompletionCode uint8 // Response Data Data []byte // optional Checksum2 uint8 } func (req *IPMIRequest) Pack() []byte { msgLen := 6 + len(req.CommandData) + 1 msg := make([]byte, msgLen) packUint8(req.ResponderAddr, msg, 0) netFn := uint8(req.NetFn) << 2 resLun := req.ResponderLUN & 0x03 packUint8(netFn|resLun, msg, 1) packUint8(req.Checksum1, msg, 2) packUint8(req.RequesterAddr, msg, 3) var seq uint8 = req.RequesterSequence << 2 reqLun := req.RequesterLUN & 0x03 packUint8(seq|reqLun, msg, 4) packUint8(uint8(req.Command), msg, 5) if req.CommandData != nil { packBytes(req.CommandData, msg, 6) } packUint8(req.Checksum2, msg, msgLen-1) return msg } func (req *IPMIRequest) ComputeChecksum() { // 8-bit checksum algorithm: Initialize checksum to 0. For each byte, checksum = (checksum + byte) modulo 256. Then checksum = - checksum. When the checksum and the bytes are added together, modulo 256, the result should be 0. // // the position end is not included var checksumFn = func(msg []byte, start int, end int) uint8 { c := 0 for i := start; i < end; i++ { c = (c + int(msg[i])) % 256 } return -uint8(c) } tempData := req.Pack() cs1Start, cs1End := 0, 2 req.Checksum1 = checksumFn(tempData, cs1Start, cs1End) cs2Start, cs2End := 3, len(tempData)-1 req.Checksum2 = checksumFn(tempData, cs2Start, cs2End) } func (res *IPMIResponse) Unpack(msg []byte) error { if len(msg) < 8 { return ErrUnpackedDataTooShortWith(len(msg), 8) } res.RequesterAddr, _, _ = unpackUint8(msg, 0) b, _, _ := unpackUint8(msg, 1) res.NetFn = NetFn(b >> 2) // the most 6 bit res.RequestLUN = b & 0x03 // the least 2 bit res.Checksum1, _, _ = unpackUint8(msg, 2) res.ResponderAddr, _, _ = unpackUint8(msg, 3) b4, _, _ := unpackUint8(msg, 4) res.RequesterSequence = b4 >> 2 res.ResponderLUN = b4 & 0x03 res.Command, _, _ = unpackUint8(msg, 5) res.CompletionCode, _, _ = unpackUint8(msg, 6) dataLen := len(msg) - 7 - 1 res.Data, _, _ = unpackBytes(msg, 7, dataLen) res.Checksum2, _, _ = unpackUint8(msg, len(msg)-1) return nil } // BuildIPMIRequest creates IPMIRequest for a Command Request. // It also fills the Checksum1 and Checksum2 fields of IPMIRequest. func (c *Client) BuildIPMIRequest(ctx context.Context, reqCmd Request) (*IPMIRequest, error) { c.lock() defer c.unlock() ipmiReq := &IPMIRequest{ ResponderAddr: c.responderAddr, NetFn: reqCmd.Command().NetFn, ResponderLUN: c.responderLUN, RequesterAddr: c.requesterAddr, RequesterSequence: c.session.ipmiSeq, RequesterLUN: c.requesterLUN, Command: reqCmd.Command().ID, CommandData: reqCmd.Pack(), } c.session.ipmiSeq += 1 if c.session.ipmiSeq > IPMIRequesterSequenceMax { c.session.ipmiSeq = 1 } ipmiReq.ComputeChecksum() return ipmiReq, nil } // AllCC returns all possible completion codes for the specified response. // i.e.: // // the generic completion codes for all ipmi cmd response // + // the specific completion codes for specified cmd response. func AllCC(response Response) map[uint8]string { out := map[uint8]string{} for k, v := range CC { out[k] = v } for k, v := range response.CompletionCodes() { out[k] = v } return out } // StrCC return the description of ccode for the specified response. // The available completion codes set consists of general completion codes (CC) for all // commands response and specific completion codes for this response. func StrCC(response Response, ccode uint8) string { s, ok := AllCC(response)[ccode] if ok { return s } return "unknown completion code" } golang-github-bougou-go-ipmi-0.7.2/types_lan_config.go000066400000000000000000000577071474110527100230000ustar00rootroot00000000000000package ipmi import ( "fmt" "net" ) type SetInProgressState uint8 const ( SetInProgress_SetComplete SetInProgressState = 0x00 SetInProgress_SetInProgress SetInProgressState = 0x01 SetInProgress_CommitWrite SetInProgressState = 0x02 SetInProgress_Reserved SetInProgressState = 0x03 ) func (p SetInProgressState) String() string { m := map[SetInProgressState]string{ 0x00: "set complete", 0x01: "set in progress", 0x02: "commit write", 0x03: "reserved", } s, ok := m[p] if ok { return s } return "" } type CommunityString [18]byte func (c CommunityString) String() string { s := []byte{} for _, v := range c { if v == 0x00 { // null break } s = append(s, v) } return string(s) } func NewCommunityString(s string) CommunityString { o := [18]byte{} b := []byte(s) for i := 0; i < 18; i++ { if i < len(b) { o[i] = b[i] } o[i] = 0x00 } return CommunityString(o) } type AuthTypesEnabled struct { OEM bool Password bool MD5 bool MD2 bool None bool } func (authTypeEnabled AuthTypesEnabled) String() string { if authTypeEnabled.OEM { return "OEM" } if authTypeEnabled.Password { return "Password" } if authTypeEnabled.MD5 { return "MD5" } if authTypeEnabled.MD2 { return "MD2" } if authTypeEnabled.None { return "None" } return "Unknown" } func packAuthTypesEnabled(a *AuthTypesEnabled) byte { b := uint8(0) b = setOrClearBit5(b, a.OEM) b = setOrClearBit4(b, a.Password) b = setOrClearBit2(b, a.MD5) b = setOrClearBit1(b, a.MD2) b = setOrClearBit0(b, a.None) return b } func unpackAuthTypesEnabled(b byte) *AuthTypesEnabled { return &AuthTypesEnabled{ OEM: isBit5Set(b), Password: isBit4Set(b), MD5: isBit2Set(b), MD2: isBit1Set(b), None: isBit0Set(b), } } // see: LanConfigParameter_IPAddressSource (#4) type LanIPAddressSource uint8 const ( IPAddressSourceUnspecified LanIPAddressSource = 0x00 IPAddressSourceStatic LanIPAddressSource = 0x01 IPAddressSourceDHCP LanIPAddressSource = 0x02 IPAddressSourceBIOS LanIPAddressSource = 0x03 IPAddressSourceOther LanIPAddressSource = 0x04 ) func (i LanIPAddressSource) String() string { m := map[LanIPAddressSource]string{ 0x00: "unspecified", 0x01: "static", 0x02: "dhcp", 0x03: "bios", 0x04: "other", } s, ok := m[i] if ok { return s } return "" } type LanIPv6EnableMode uint8 const ( // 00h = IPv6 addressing disabled. LanIPv6EnableMode_IPv6Disabled LanIPv6EnableMode = 0 // 01h = Enable IPv6 addressing only. IPv4 addressing is disabled. LanIPv6EnableMode_IPv6Only LanIPv6EnableMode = 1 // 02h = Enable IPv6 and IPv4 addressing simultaneously. LanIPv6EnableMode_IPv4AndIPv6 LanIPv6EnableMode = 2 ) // Address Status (Read-only parameter) // - 00h = Active (in-use) // - 01h = Disabled // - 02h = Pending (currently undergoing DAD [duplicate address detection], optional) // - 03h = Failed (duplicate address found, optional) // - 04h = Deprecated (preferred timer has expired, optional) // - 05h = Invalid (validity timer has expired, optional) // - All other = reserved type LanIPv6AddressStatus uint8 const ( LanIPv6AddressStatus_Active LanIPv6AddressStatus = 0 LanIPv6AddressStatus_Disabled LanIPv6AddressStatus = 1 LanIPv6AddressStatus_Pending LanIPv6AddressStatus = 2 LanIPv6AddressStatus_Failed LanIPv6AddressStatus = 3 LanIPv6AddressStatus_Deprecated LanIPv6AddressStatus = 4 LanIPv6AddressStatus_Invalid LanIPv6AddressStatus = 5 ) func (addressStatus LanIPv6AddressStatus) String() string { m := map[LanIPv6AddressStatus]string{ 0x00: "active", 0x01: "disabled", 0x02: "pending", 0x03: "failed", 0x04: "deprecated", 0x05: "invalid", } s, ok := m[addressStatus] if ok { return s } return "reserved" } // IPv6 Static Address Source // - 0h = Static // - All other = reserved type LanIPv6StaticAddressSource uint8 const ( LanIPv6StaticAddressSource_Static LanIPv6StaticAddressSource = 0 ) func (addressSource LanIPv6StaticAddressSource) String() string { m := map[LanIPv6StaticAddressSource]string{ 0: "static", } s, ok := m[addressSource] if ok { return s } return "reserved" } // Address source/type // - 0 - Reserved // - 1 - SLAAC (StateLess Address Auto Configuration) // - 2 - DHCPv6 (optional) // - Other - reserved type LanIPv6DynamicAddressSource uint8 const ( LanIPv6AddressSource_SLAAC LanIPv6DynamicAddressSource = 1 LanIPv6AddressSource_DHCPv6 LanIPv6DynamicAddressSource = 2 ) func (addressSource LanIPv6DynamicAddressSource) String() string { m := map[LanIPv6DynamicAddressSource]string{ 1: "SLAAC", 2: "DHCPv6", } s, ok := m[addressSource] if ok { return s } return "reserved" } // DHCPv6 Timing Configuration Mode // - 00b = `Not Supported` // DHCPv6 timing configuration per IPMI is not supported. // - 01b = `Global` // Timing configuration applies across all interfaces (IAs) that use // dynamic addressing and have DHCPv6 is enabled. // - 10b = `Per Interface` // Timing is configurable for each interface and used when DHCPv6 is enabled for the given interface (IA). // - 11b = reserved type LanIPv6DHCPv6TimingConfigMode uint8 const ( LanIPv6DHCPv6TimingConfigMode_NotSupported LanIPv6DHCPv6TimingConfigMode = 0 LanIPv6DHCPv6TimingConfigMode_Global LanIPv6DHCPv6TimingConfigMode = 1 LanIPv6DHCPv6TimingConfigMode_PerInterface LanIPv6DHCPv6TimingConfigMode = 2 ) func (mode LanIPv6DHCPv6TimingConfigMode) String() string { m := map[LanIPv6DHCPv6TimingConfigMode]string{ 0: "not supported", 1: "global", 2: "per interface", } s, ok := m[mode] if ok { return s } return "reserved" } type LanIPv6NDSLAACTimingConfigMode uint8 const ( LanIPv6NDSLAACTimingConfigMode_NotSupported LanIPv6DHCPv6TimingConfigMode = 0 LanIPv6NDSLAACTimingConfigMode_Global LanIPv6NDSLAACTimingConfigMode = 1 LanIPv6NDSLAACTimingConfigMode_PerInterface LanIPv6NDSLAACTimingConfigMode = 2 ) func (mode LanIPv6NDSLAACTimingConfigMode) String() string { m := map[LanIPv6NDSLAACTimingConfigMode]string{ 0: "not supported", 1: "global", 2: "per interface", } s, ok := m[mode] if ok { return s } return "reserved" } type LanConfigParams struct { SetInProgress *LanConfigParam_SetInProgress // #0, Read Only AuthTypeSupport *LanConfigParam_AuthTypeSupport // #1 AuthTypeEnables *LanConfigParam_AuthTypeEnables // #2 IP *LanConfigParam_IP // #3 IPSource *LanConfigParam_IPSource // #4 MAC *LanConfigParam_MAC // #5, can be Read Only. An implementation can either allow this parameter to be settable, or it can be implemented as Read Only. SubnetMask *LanConfigParam_SubnetMask // #6 IPv4HeaderParams *LanConfigParam_IPv4HeaderParams // #7 PrimaryRMCPPort *LanConfigParam_PrimaryRMCPPort // #8 SecondaryRMCPPort *LanConfigParam_SecondaryRMCPPort // #9 ARPControl *LanConfigParam_ARPControl // #10 GratuitousARPInterval *LanConfigParam_GratuitousARPInterval // #11 DefaultGatewayIP *LanConfigParam_DefaultGatewayIP // #12 DefaultGatewayMAC *LanConfigParam_DefaultGatewayMAC // #13 BackupGatewayIP *LanConfigParam_BackupGatewayIP // #14 BackupGatewayMAC *LanConfigParam_BackupGatewayMAC // #15 CommunityString *LanConfigParam_CommunityString // #16 AlertDestinationsCount *LanConfigParam_AlertDestinationsCount // #17, Read Only AlertDestinationTypes []*LanConfigParam_AlertDestinationType // #18 AlertDestinationAddresses []*LanConfigParam_AlertDestinationAddress // #19 VLANID *LanConfigParam_VLANID // #20 VLANPriority *LanConfigParam_VLANPriority // #21 CipherSuitesSupport *LanConfigParam_CipherSuitesSupport // #22, Read Only CipherSuitesID *LanConfigParam_CipherSuitesID // #23, Read Only CipherSuitesPrivLevel *LanConfigParam_CipherSuitesPrivLevel // #24 AlertDestinationVLANs []*LanConfigParam_AlertDestinationVLAN // #25, can be READ ONLY BadPasswordThreshold *LanConfigParam_BadPasswordThreshold // #26 IPv6Support *LanConfigParam_IPv6Support // #50, Read Only IPv6Enables *LanConfigParam_IPv6Enables // #51 IPv6StaticTrafficClass *LanConfigParam_IPv6StaticTrafficClass // #52 IPv6StaticHopLimit *LanConfigParam_IPv6StaticHopLimit // #53 IPv6FlowLabel *LanConfigParam_IPv6FlowLabel // #54 IPv6Status *LanConfigParam_IPv6Status // #55, Read Only IPv6StaticAddresses []*LanConfigParam_IPv6StaticAddress // #56 IPv6DHCPv6StaticDUIDCount *LanConfigParam_IPv6DHCPv6StaticDUIDCount // #57, Read Only IPv6DHCPv6StaticDUIDs []*LanConfigParam_IPv6DHCPv6StaticDUID // #58 IPv6DynamicAddresses []*LanConfigParam_IPv6DynamicAddress // #59, Read Only IPv6DHCPv6DynamicDUIDCount *LanConfigParam_IPv6DHCPv6DynamicDUIDCount // #60, Read Only IPv6DHCPv6DynamicDUIDs []*LanConfigParam_IPv6DHCPv6DynamicDUID // #61 IPv6DHCPv6TimingConfigSupport *LanConfigParam_IPv6DHCPv6TimingConfigSupport // #62, Read Only IPv6DHCPv6TimingConfig []*LanConfigParam_IPv6DHCPv6TimingConfig // #63 IPv6RouterAddressConfigControl *LanConfigParam_IPv6RouterAddressConfigControl // #64 IPv6StaticRouter1IP *LanConfigParam_IPv6StaticRouter1IP // #65 IPv6StaticRouter1MAC *LanConfigParam_IPv6StaticRouter1MAC // #66 IPv6StaticRouter1PrefixLength *LanConfigParam_IPv6StaticRouter1PrefixLength // #67 IPv6StaticRouter1PrefixValue *LanConfigParam_IPv6StaticRouter1PrefixValue // #68 IPv6StaticRouter2IP *LanConfigParam_IPv6StaticRouter2IP // #69 IPv6StaticRouter2MAC *LanConfigParam_IPv6StaticRouter2MAC // #70 IPv6StaticRouter2PrefixLength *LanConfigParam_IPv6StaticRouter2PrefixLength // #71 IPv6StaticRouter2PrefixValue *LanConfigParam_IPv6StaticRouter2PrefixValue // #72 IPv6DynamicRouterInfoSets *LanConfigParam_IPv6DynamicRouterInfoSets // #73, Read Only IPv6DynamicRouterInfoIP []*LanConfigParam_IPv6DynamicRouterInfoIP // #74 IPv6DynamicRouterInfoMAC []*LanConfigParam_IPv6DynamicRouterInfoMAC // #75 IPv6DynamicRouterInfoPrefixLength []*LanConfigParam_IPv6DynamicRouterInfoPrefixLength // #76 IPv6DynamicRouterInfoPrefixValue []*LanConfigParam_IPv6DynamicRouterInfoPrefixValue // #77 IPv6DynamicRouterReceivedHopLimit *LanConfigParam_IPv6DynamicRouterReceivedHopLimit // #78 IPv6NDSLAACTimingConfigSupport *LanConfigParam_IPv6NDSLAACTimingConfigSupport // #79, Read Only IPv6NDSLAACTimingConfig []*LanConfigParam_IPv6NDSLAACTimingConfig // #80 } type LanConfig struct { SetInProgress SetInProgressState // #0, Read Only AuthTypeSupport LanConfigParam_AuthTypeSupport // #1 AuthTypeEnables LanConfigParam_AuthTypeEnables // #2 IP net.IP // #3 IPSource LanIPAddressSource // #4 MAC net.HardwareAddr // #5, can be Read Only. SubnetMask net.IP // #6 IPv4HeaderParams LanConfigParam_IPv4HeaderParams // #7 PrimaryRMCPPort uint16 // #8 SecondaryRMCPPort uint16 // #9 ARPControl LanConfigParam_ARPControl // #10 GratuitousARPIntervalMilliSec uint32 // #11 DefaultGatewayIP net.IP // #12 DefaultGatewayMAC net.HardwareAddr // #13 BackupGatewayIP net.IP // #14 BackupGatewayMAC net.HardwareAddr // #15 CommunityString CommunityString // #16 AlertDestinationsCount uint8 // #17, Read Only VLANEnabled bool // #20 VLANID uint16 // #20 VLANPriority uint8 // #21 CipherSuitesSupport uint8 // #22, Read Only CipherSuitesID LanConfigParam_CipherSuitesID // #23, Read Only CipherSuitesPrivLevel LanConfigParam_CipherSuitesPrivLevel // #24 BadPasswordThreshold LanConfigParam_BadPasswordThreshold // #26 } func (lanConfigParams *LanConfigParams) ToLanConfig() *LanConfig { lanConfig := &LanConfig{} if lanConfigParams.SetInProgress != nil { lanConfig.SetInProgress = lanConfigParams.SetInProgress.Value } if lanConfigParams.AuthTypeSupport != nil { lanConfig.AuthTypeSupport = *lanConfigParams.AuthTypeSupport } if lanConfigParams.AuthTypeEnables != nil { lanConfig.AuthTypeEnables = *lanConfigParams.AuthTypeEnables } if lanConfigParams.IP != nil { lanConfig.IP = lanConfigParams.IP.IP } if lanConfigParams.IPSource != nil { lanConfig.IPSource = lanConfigParams.IPSource.Source } if lanConfigParams.MAC != nil { lanConfig.MAC = lanConfigParams.MAC.MAC } if lanConfigParams.SubnetMask != nil { lanConfig.SubnetMask = lanConfigParams.SubnetMask.SubnetMask } if lanConfigParams.IPv4HeaderParams != nil { lanConfig.IPv4HeaderParams = *lanConfigParams.IPv4HeaderParams } if lanConfigParams.PrimaryRMCPPort != nil { lanConfig.PrimaryRMCPPort = lanConfigParams.PrimaryRMCPPort.Port } if lanConfigParams.SecondaryRMCPPort != nil { lanConfig.SecondaryRMCPPort = lanConfigParams.SecondaryRMCPPort.Port } if lanConfigParams.ARPControl != nil { lanConfig.ARPControl = *lanConfigParams.ARPControl } if lanConfigParams.GratuitousARPInterval != nil { lanConfig.GratuitousARPIntervalMilliSec = lanConfigParams.GratuitousARPInterval.MilliSec } if lanConfigParams.DefaultGatewayIP != nil { lanConfig.DefaultGatewayIP = lanConfigParams.DefaultGatewayIP.IP } if lanConfigParams.DefaultGatewayMAC != nil { lanConfig.DefaultGatewayMAC = lanConfigParams.DefaultGatewayMAC.MAC } if lanConfigParams.BackupGatewayIP != nil { lanConfig.BackupGatewayIP = lanConfigParams.BackupGatewayIP.IP } if lanConfigParams.BackupGatewayMAC != nil { lanConfig.BackupGatewayMAC = lanConfigParams.BackupGatewayMAC.MAC } if lanConfigParams.CommunityString != nil { lanConfig.CommunityString = lanConfigParams.CommunityString.CommunityString } if lanConfigParams.AlertDestinationsCount != nil { lanConfig.AlertDestinationsCount = lanConfigParams.AlertDestinationsCount.Count } if lanConfigParams.VLANID != nil { lanConfig.VLANEnabled = lanConfigParams.VLANID.Enabled lanConfig.VLANID = lanConfigParams.VLANID.ID } if lanConfigParams.VLANPriority != nil { lanConfig.VLANPriority = lanConfigParams.VLANPriority.Priority } if lanConfigParams.CipherSuitesSupport != nil { lanConfig.CipherSuitesSupport = lanConfigParams.CipherSuitesSupport.Count } if lanConfigParams.CipherSuitesID != nil { lanConfig.CipherSuitesID = *lanConfigParams.CipherSuitesID } if lanConfigParams.CipherSuitesPrivLevel != nil { lanConfig.CipherSuitesPrivLevel = *lanConfigParams.CipherSuitesPrivLevel } if lanConfigParams.BadPasswordThreshold != nil { lanConfig.BadPasswordThreshold = *lanConfigParams.BadPasswordThreshold } return lanConfig } func (lanConfigParams *LanConfigParams) Format() string { format := func(param LanConfigParameter) string { if isNilLanConfigParameter(param) { return "" } paramSelector, _, _ := param.LanConfigParameter() content := param.Format() if content[len(content)-1] != '\n' { content += "\n" } return fmt.Sprintf("[%2d] %-40s: %s", paramSelector, paramSelector.String(), content) } out := "" out += format(lanConfigParams.SetInProgress) out += format(lanConfigParams.AuthTypeSupport) out += format(lanConfigParams.AuthTypeEnables) out += format(lanConfigParams.IP) out += format(lanConfigParams.IPSource) out += format(lanConfigParams.MAC) out += format(lanConfigParams.SubnetMask) out += format(lanConfigParams.IPv4HeaderParams) out += format(lanConfigParams.PrimaryRMCPPort) out += format(lanConfigParams.SecondaryRMCPPort) out += format(lanConfigParams.ARPControl) out += format(lanConfigParams.GratuitousARPInterval) out += format(lanConfigParams.DefaultGatewayIP) out += format(lanConfigParams.DefaultGatewayMAC) out += format(lanConfigParams.BackupGatewayIP) out += format(lanConfigParams.BackupGatewayMAC) out += format(lanConfigParams.CommunityString) out += format(lanConfigParams.AlertDestinationsCount) for _, alertDestinationType := range lanConfigParams.AlertDestinationTypes { out += format(alertDestinationType) } if lanConfigParams.AlertDestinationAddresses != nil { for _, alertDestinationAddress := range lanConfigParams.AlertDestinationAddresses { out += format(alertDestinationAddress) } } out += format(lanConfigParams.VLANID) out += format(lanConfigParams.VLANPriority) out += format(lanConfigParams.CipherSuitesSupport) out += format(lanConfigParams.CipherSuitesID) out += format(lanConfigParams.CipherSuitesPrivLevel) if lanConfigParams.AlertDestinationVLANs != nil { for _, alertDestinationVLAN := range lanConfigParams.AlertDestinationVLANs { out += format(alertDestinationVLAN) } } out += format(lanConfigParams.BadPasswordThreshold) out += format(lanConfigParams.IPv6Support) out += format(lanConfigParams.IPv6Enables) out += format(lanConfigParams.IPv6StaticTrafficClass) out += format(lanConfigParams.IPv6StaticHopLimit) out += format(lanConfigParams.IPv6FlowLabel) out += format(lanConfigParams.IPv6Status) if lanConfigParams.IPv6StaticAddresses != nil { for _, ipv6StaticAddress := range lanConfigParams.IPv6StaticAddresses { out += format(ipv6StaticAddress) } } out += format(lanConfigParams.IPv6DHCPv6StaticDUIDCount) if lanConfigParams.IPv6DHCPv6StaticDUIDs != nil { for _, ipv6DHCPv6StaticDUID := range lanConfigParams.IPv6DHCPv6StaticDUIDs { out += format(ipv6DHCPv6StaticDUID) } } if lanConfigParams.IPv6DynamicAddresses != nil { for _, ipv6DynamicAddress := range lanConfigParams.IPv6DynamicAddresses { out += format(ipv6DynamicAddress) } } out += format(lanConfigParams.IPv6DHCPv6DynamicDUIDCount) if lanConfigParams.IPv6DHCPv6DynamicDUIDs != nil { for _, ipv6DHCPv6DynamicDUID := range lanConfigParams.IPv6DHCPv6DynamicDUIDs { out += format(ipv6DHCPv6DynamicDUID) } } out += format(lanConfigParams.IPv6DHCPv6TimingConfigSupport) if lanConfigParams.IPv6DHCPv6TimingConfig != nil { for _, ipv6DHCPv6TimingConfig := range lanConfigParams.IPv6DHCPv6TimingConfig { out += format(ipv6DHCPv6TimingConfig) } } out += format(lanConfigParams.IPv6RouterAddressConfigControl) out += format(lanConfigParams.IPv6StaticRouter1IP) out += format(lanConfigParams.IPv6StaticRouter1MAC) out += format(lanConfigParams.IPv6StaticRouter1PrefixLength) out += format(lanConfigParams.IPv6StaticRouter1PrefixValue) out += format(lanConfigParams.IPv6StaticRouter2IP) out += format(lanConfigParams.IPv6StaticRouter2MAC) out += format(lanConfigParams.IPv6StaticRouter2PrefixLength) out += format(lanConfigParams.IPv6StaticRouter2PrefixValue) out += format(lanConfigParams.IPv6DynamicRouterInfoSets) if lanConfigParams.IPv6DynamicRouterInfoIP != nil { for _, ipv6DynamicRouterInfoIP := range lanConfigParams.IPv6DynamicRouterInfoIP { out += format(ipv6DynamicRouterInfoIP) } } if lanConfigParams.IPv6DynamicRouterInfoMAC != nil { for _, ipv6DynamicRouterInfoMAC := range lanConfigParams.IPv6DynamicRouterInfoMAC { out += format(ipv6DynamicRouterInfoMAC) } } if lanConfigParams.IPv6DynamicRouterInfoPrefixLength != nil { for _, ipv6DynamicRouterInfoPrefixLength := range lanConfigParams.IPv6DynamicRouterInfoPrefixLength { out += format(ipv6DynamicRouterInfoPrefixLength) } } if lanConfigParams.IPv6DynamicRouterInfoPrefixValue != nil { for _, ipv6DynamicRouterInfoPrefixValue := range lanConfigParams.IPv6DynamicRouterInfoPrefixValue { out += format(ipv6DynamicRouterInfoPrefixValue) } } out += format(lanConfigParams.IPv6DynamicRouterReceivedHopLimit) out += format(lanConfigParams.IPv6NDSLAACTimingConfigSupport) if lanConfigParams.IPv6NDSLAACTimingConfig != nil { for _, ipv6NDSLAACTimingConfig := range lanConfigParams.IPv6NDSLAACTimingConfig { out += format(ipv6NDSLAACTimingConfig) } } return out } func (lanConfig *LanConfig) Format() string { out := "" out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_SetInProgress, lanConfig.SetInProgress) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_AuthTypeSupport, lanConfig.AuthTypeSupport.Format()) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_AuthTypeEnables, lanConfig.AuthTypeEnables.Format()) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_IP, lanConfig.IP) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_IPSource, lanConfig.IPSource) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_MAC, lanConfig.MAC) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_SubnetMask, lanConfig.SubnetMask) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_IPv4HeaderParams, lanConfig.IPv4HeaderParams.Format()) out += fmt.Sprintf("%-40s : %d\n", LanConfigParamSelector_PrimaryRMCPPort, lanConfig.PrimaryRMCPPort) out += fmt.Sprintf("%-40s : %d\n", LanConfigParamSelector_SecondaryRMCPPort, lanConfig.SecondaryRMCPPort) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_ARPControl, lanConfig.ARPControl.Format()) out += fmt.Sprintf("%-40s : %d\n", LanConfigParamSelector_GratuitousARPInterval, lanConfig.GratuitousARPIntervalMilliSec) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_DefaultGatewayIP, lanConfig.DefaultGatewayIP) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_DefaultGatewayMAC, lanConfig.DefaultGatewayMAC) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_BackupGatewayIP, lanConfig.BackupGatewayIP) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_BackupGatewayMAC, lanConfig.BackupGatewayMAC) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_CommunityString, lanConfig.CommunityString) out += fmt.Sprintf("%-40s : %d\n", LanConfigParamSelector_AlertDestinationsCount, lanConfig.AlertDestinationsCount) out += fmt.Sprintf("%-40s : %d\n", LanConfigParamSelector_VLANID, lanConfig.VLANID) out += fmt.Sprintf("%-40s : %d\n", LanConfigParamSelector_VLANPriority, lanConfig.VLANPriority) out += fmt.Sprintf("%-40s : %d\n", LanConfigParamSelector_CipherSuitesSupport, lanConfig.CipherSuitesSupport) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_CipherSuitesID, lanConfig.CipherSuitesID.Format()) out += fmt.Sprintf("%-40s : %s\n", LanConfigParamSelector_CipherSuitesPrivLevel, lanConfig.CipherSuitesPrivLevel.Format()) out += fmt.Sprintf("%-40s : %d\n", LanConfigParamSelector_BadPasswordThreshold, lanConfig.BadPasswordThreshold.Threshold) return out } golang-github-bougou-go-ipmi-0.7.2/types_lan_config_params.go000066400000000000000000002266651474110527100243440ustar00rootroot00000000000000package ipmi import ( "fmt" "net" "strconv" "strings" ) type LanConfigParameter interface { LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) Parameter } // Table 23-4, LAN Configuration Parameters // Parameter selector type LanConfigParamSelector uint8 const ( LanConfigParamSelector_SetInProgress LanConfigParamSelector = 0 LanConfigParamSelector_AuthTypeSupport LanConfigParamSelector = 1 // read only LanConfigParamSelector_AuthTypeEnables LanConfigParamSelector = 2 LanConfigParamSelector_IP LanConfigParamSelector = 3 LanConfigParamSelector_IPSource LanConfigParamSelector = 4 LanConfigParamSelector_MAC LanConfigParamSelector = 5 // can be read only LanConfigParamSelector_SubnetMask LanConfigParamSelector = 6 LanConfigParamSelector_IPv4HeaderParams LanConfigParamSelector = 7 LanConfigParamSelector_PrimaryRMCPPort LanConfigParamSelector = 8 LanConfigParamSelector_SecondaryRMCPPort LanConfigParamSelector = 9 LanConfigParamSelector_ARPControl LanConfigParamSelector = 10 LanConfigParamSelector_GratuitousARPInterval LanConfigParamSelector = 11 LanConfigParamSelector_DefaultGatewayIP LanConfigParamSelector = 12 LanConfigParamSelector_DefaultGatewayMAC LanConfigParamSelector = 13 LanConfigParamSelector_BackupGatewayIP LanConfigParamSelector = 14 LanConfigParamSelector_BackupGatewayMAC LanConfigParamSelector = 15 LanConfigParamSelector_CommunityString LanConfigParamSelector = 16 LanConfigParamSelector_AlertDestinationsCount LanConfigParamSelector = 17 // read only LanConfigParamSelector_AlertDestinationType LanConfigParamSelector = 18 LanConfigParamSelector_AlertDestinationAddress LanConfigParamSelector = 19 LanConfigParamSelector_VLANID LanConfigParamSelector = 20 LanConfigParamSelector_VLANPriority LanConfigParamSelector = 21 LanConfigParamSelector_CipherSuitesSupport LanConfigParamSelector = 22 // read only LanConfigParamSelector_CipherSuitesID LanConfigParamSelector = 23 // read only LanConfigParamSelector_CipherSuitesPrivLevel LanConfigParamSelector = 24 LanConfigParamSelector_AlertDestinationVLAN LanConfigParamSelector = 25 // can be read only LanConfigParamSelector_BadPasswordThreshold LanConfigParamSelector = 26 LanConfigParamSelector_IPv6Support LanConfigParamSelector = 50 // read only LanConfigParamSelector_IPv6Enables LanConfigParamSelector = 51 LanConfigParamSelector_IPv6StaticTrafficClass LanConfigParamSelector = 52 LanConfigParamSelector_IPv6StaticHopLimit LanConfigParamSelector = 53 LanConfigParamSelector_IPv6FlowLabel LanConfigParamSelector = 54 LanConfigParamSelector_IPv6Status LanConfigParamSelector = 55 // read only LanConfigParamSelector_IPv6StaticAddress LanConfigParamSelector = 56 LanConfigParamSelector_IPv6DHCPv6StaticDUIDCount LanConfigParamSelector = 57 // read only LanConfigParamSelector_IPv6DHCPv6StaticDUID LanConfigParamSelector = 58 LanConfigParamSelector_IPv6DynamicAddress LanConfigParamSelector = 59 // read only LanConfigParamSelector_IPv6DHCPv6DynamicDUIDCount LanConfigParamSelector = 60 // read only LanConfigParamSelector_IPv6DHCPv6DynamicDUID LanConfigParamSelector = 61 LanConfigParamSelector_IPv6DHCPv6TimingConfigSupport LanConfigParamSelector = 62 // read only LanConfigParamSelector_IPv6DHCPv6TimingConfig LanConfigParamSelector = 63 LanConfigParamSelector_IPv6RouterAddressConfigControl LanConfigParamSelector = 64 LanConfigParamSelector_IPv6StaticRouter1IP LanConfigParamSelector = 65 LanConfigParamSelector_IPv6StaticRouter1MAC LanConfigParamSelector = 66 LanConfigParamSelector_IPv6StaticRouter1PrefixLength LanConfigParamSelector = 67 LanConfigParamSelector_IPv6StaticRouter1PrefixValue LanConfigParamSelector = 68 LanConfigParamSelector_IPv6StaticRouter2IP LanConfigParamSelector = 69 LanConfigParamSelector_IPv6StaticRouter2MAC LanConfigParamSelector = 70 LanConfigParamSelector_IPv6StaticRouter2PrefixLength LanConfigParamSelector = 71 LanConfigParamSelector_IPv6StaticRouter2PrefixValue LanConfigParamSelector = 72 LanConfigParamSelector_IPv6DynamicRouterInfoCount LanConfigParamSelector = 73 // read only LanConfigParamSelector_IPv6DynamicRouterInfoIP LanConfigParamSelector = 74 // read only LanConfigParamSelector_IPv6DynamicRouterInfoMAC LanConfigParamSelector = 75 // read only LanConfigParamSelector_IPv6DynamicRouterInfoPrefixLength LanConfigParamSelector = 76 // read only LanConfigParamSelector_IPv6DynamicRouterInfoPrefixValue LanConfigParamSelector = 77 // read only LanConfigParamSelector_IPv6DynamicRouterReceivedHopLimit LanConfigParamSelector = 78 // read only LanConfigParamSelector_IPv6NDSLAACTimingConfigSupport LanConfigParamSelector = 79 // read only, IPv6 Neighbor Discovery / SLAAC LanConfigParamSelector_IPv6NDSLAACTimingConfig LanConfigParamSelector = 80 // OEM Parameters 192:255 // This range is available for special OEM configuration parameters. The OEM is identified // according to the Manufacturer ID field returned by the Get Device ID command. ) func (lanConfigParam LanConfigParamSelector) String() string { m := map[LanConfigParamSelector]string{ LanConfigParamSelector_SetInProgress: "Set In Progress", LanConfigParamSelector_AuthTypeSupport: "Authentication Type Support", LanConfigParamSelector_AuthTypeEnables: "Authentication Type Enables", LanConfigParamSelector_IP: "IP Address", LanConfigParamSelector_IPSource: "IP Address Source", LanConfigParamSelector_MAC: "MAC Address", LanConfigParamSelector_SubnetMask: "Subnet Mask", LanConfigParamSelector_IPv4HeaderParams: "IPv4 Header Params", LanConfigParamSelector_PrimaryRMCPPort: "Primary RMCP Port", LanConfigParamSelector_SecondaryRMCPPort: "Secondary RMCP Port", LanConfigParamSelector_ARPControl: "ARP Control", LanConfigParamSelector_GratuitousARPInterval: "Gratuitous ARP Interval", LanConfigParamSelector_DefaultGatewayIP: "Default Gateway IP", LanConfigParamSelector_DefaultGatewayMAC: "Default Gateway MAC", LanConfigParamSelector_BackupGatewayIP: "Backup Gateway IP", LanConfigParamSelector_BackupGatewayMAC: "Backup Gateway MAC", LanConfigParamSelector_CommunityString: "Community String", LanConfigParamSelector_AlertDestinationsCount: "Alert Destinations Count", LanConfigParamSelector_AlertDestinationType: "Alert Destination Type", LanConfigParamSelector_AlertDestinationAddress: "Alert Destination Address", LanConfigParamSelector_VLANID: "802.1q VLAN ID", LanConfigParamSelector_VLANPriority: "802.1q VLAN Priority", LanConfigParamSelector_CipherSuitesSupport: "Cipher Suite Entries Support", LanConfigParamSelector_CipherSuitesID: "Cipher Suite Entries", LanConfigParamSelector_CipherSuitesPrivLevel: "Cipher Suite Privilege Levels", LanConfigParamSelector_AlertDestinationVLAN: "Alert Destination VLAN", LanConfigParamSelector_BadPasswordThreshold: "Bad Password Threshold", LanConfigParamSelector_IPv6Support: "IPv6 Support", LanConfigParamSelector_IPv6Enables: "IPv6 Enables", LanConfigParamSelector_IPv6StaticTrafficClass: "IPv6 Static Traffic Class", LanConfigParamSelector_IPv6StaticHopLimit: "IPv6 Static Hop Limit", LanConfigParamSelector_IPv6FlowLabel: "IPv6 Flow Label", LanConfigParamSelector_IPv6Status: "IPv6 Status", LanConfigParamSelector_IPv6StaticAddress: "IPv6 Static Address", LanConfigParamSelector_IPv6DHCPv6StaticDUIDCount: "IPv6 DHCPv6 Static DUID Count", LanConfigParamSelector_IPv6DHCPv6StaticDUID: "IPv6 DHCPv6 Static DUID", LanConfigParamSelector_IPv6DynamicAddress: "IPv6 Dynamic Address", LanConfigParamSelector_IPv6DHCPv6DynamicDUIDCount: "IPv6 DHCPv6 Dynamic DUID Count", LanConfigParamSelector_IPv6DHCPv6DynamicDUID: "IPv6 DHCPv6 Dynamic DUID", LanConfigParamSelector_IPv6DHCPv6TimingConfigSupport: "IPv6 DHCPv6 Timing Config Support", LanConfigParamSelector_IPv6DHCPv6TimingConfig: "IPv6 DHCPv6 Timing Config", LanConfigParamSelector_IPv6RouterAddressConfigControl: "IPv6 Router Address Config Control", LanConfigParamSelector_IPv6StaticRouter1IP: "IPv6 Static Router1 IP", LanConfigParamSelector_IPv6StaticRouter1MAC: "IPv6 Static Router1 MAC", LanConfigParamSelector_IPv6StaticRouter1PrefixLength: "IPv6 Static Router1 Prefix Length", LanConfigParamSelector_IPv6StaticRouter1PrefixValue: "IPv6 Static Router1 Prefix Value", LanConfigParamSelector_IPv6StaticRouter2IP: "IPv6 Static Router2 IP", LanConfigParamSelector_IPv6StaticRouter2MAC: "IPv6 Static Router2 MAC", LanConfigParamSelector_IPv6StaticRouter2PrefixLength: "IPv6 Static Router2 Prefix Length", LanConfigParamSelector_IPv6StaticRouter2PrefixValue: "IPv6 Static Router2 Prefix Value", LanConfigParamSelector_IPv6DynamicRouterInfoCount: "IPv6 Dynamic Router Sets Number", LanConfigParamSelector_IPv6DynamicRouterInfoIP: "IPv6 Dynamic Router IP", LanConfigParamSelector_IPv6DynamicRouterInfoMAC: "IPv6 Dynamic Router MAC", LanConfigParamSelector_IPv6DynamicRouterInfoPrefixLength: "IPv6 Dynamic Router Prefix Length", LanConfigParamSelector_IPv6DynamicRouterInfoPrefixValue: "IPv6 Dynamic Router Prefix Value", LanConfigParamSelector_IPv6DynamicRouterReceivedHopLimit: "IPv6 Dynamic Router Received Hop Limit", LanConfigParamSelector_IPv6NDSLAACTimingConfigSupport: "IPv6 ND/SLAAC Timing Config Support", LanConfigParamSelector_IPv6NDSLAACTimingConfig: "IPv6 ND/SLAAC Timing Config", } if s, ok := m[lanConfigParam]; ok { return s } return "Unknown" } var ( _ LanConfigParameter = (*LanConfigParam_SetInProgress)(nil) _ LanConfigParameter = (*LanConfigParam_AuthTypeSupport)(nil) _ LanConfigParameter = (*LanConfigParam_AuthTypeEnables)(nil) _ LanConfigParameter = (*LanConfigParam_IP)(nil) _ LanConfigParameter = (*LanConfigParam_IPSource)(nil) _ LanConfigParameter = (*LanConfigParam_MAC)(nil) _ LanConfigParameter = (*LanConfigParam_SubnetMask)(nil) _ LanConfigParameter = (*LanConfigParam_IPv4HeaderParams)(nil) _ LanConfigParameter = (*LanConfigParam_PrimaryRMCPPort)(nil) _ LanConfigParameter = (*LanConfigParam_SecondaryRMCPPort)(nil) _ LanConfigParameter = (*LanConfigParam_ARPControl)(nil) _ LanConfigParameter = (*LanConfigParam_GratuitousARPInterval)(nil) _ LanConfigParameter = (*LanConfigParam_DefaultGatewayIP)(nil) _ LanConfigParameter = (*LanConfigParam_DefaultGatewayMAC)(nil) _ LanConfigParameter = (*LanConfigParam_BackupGatewayIP)(nil) _ LanConfigParameter = (*LanConfigParam_BackupGatewayMAC)(nil) _ LanConfigParameter = (*LanConfigParam_CommunityString)(nil) _ LanConfigParameter = (*LanConfigParam_AlertDestinationsCount)(nil) _ LanConfigParameter = (*LanConfigParam_AlertDestinationType)(nil) _ LanConfigParameter = (*LanConfigParam_AlertDestinationAddress)(nil) _ LanConfigParameter = (*LanConfigParam_VLANID)(nil) _ LanConfigParameter = (*LanConfigParam_VLANPriority)(nil) _ LanConfigParameter = (*LanConfigParam_CipherSuitesSupport)(nil) _ LanConfigParameter = (*LanConfigParam_CipherSuitesID)(nil) _ LanConfigParameter = (*LanConfigParam_CipherSuitesPrivLevel)(nil) _ LanConfigParameter = (*LanConfigParam_AlertDestinationVLAN)(nil) _ LanConfigParameter = (*LanConfigParam_BadPasswordThreshold)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6Support)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6Enables)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticTrafficClass)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticHopLimit)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6FlowLabel)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6Status)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticAddress)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DHCPv6StaticDUIDCount)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DHCPv6StaticDUID)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DynamicAddress)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DHCPv6DynamicDUIDCount)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DHCPv6DynamicDUID)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DHCPv6TimingConfigSupport)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DHCPv6TimingConfig)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6RouterAddressConfigControl)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticRouter1IP)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticRouter1MAC)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticRouter1PrefixLength)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticRouter1PrefixValue)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticRouter2IP)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticRouter2MAC)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticRouter2PrefixLength)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6StaticRouter2PrefixValue)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DynamicRouterInfoSets)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DynamicRouterInfoIP)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DynamicRouterInfoMAC)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DynamicRouterInfoPrefixLength)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DynamicRouterInfoPrefixValue)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6DynamicRouterReceivedHopLimit)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6NDSLAACTimingConfigSupport)(nil) _ LanConfigParameter = (*LanConfigParam_IPv6NDSLAACTimingConfig)(nil) ) func isNilLanConfigParameter(param LanConfigParameter) bool { switch v := param.(type) { case *LanConfigParam_SetInProgress: return v == nil case *LanConfigParam_AuthTypeSupport: return v == nil case *LanConfigParam_AuthTypeEnables: return v == nil case *LanConfigParam_IP: return v == nil case *LanConfigParam_IPSource: return v == nil case *LanConfigParam_MAC: return v == nil case *LanConfigParam_SubnetMask: return v == nil case *LanConfigParam_IPv4HeaderParams: return v == nil case *LanConfigParam_PrimaryRMCPPort: return v == nil case *LanConfigParam_SecondaryRMCPPort: return v == nil case *LanConfigParam_ARPControl: return v == nil case *LanConfigParam_GratuitousARPInterval: return v == nil case *LanConfigParam_DefaultGatewayIP: return v == nil case *LanConfigParam_DefaultGatewayMAC: return v == nil case *LanConfigParam_BackupGatewayIP: return v == nil case *LanConfigParam_BackupGatewayMAC: return v == nil case *LanConfigParam_CommunityString: return v == nil case *LanConfigParam_AlertDestinationsCount: return v == nil case *LanConfigParam_AlertDestinationType: return v == nil case *LanConfigParam_AlertDestinationAddress: return v == nil case *LanConfigParam_VLANID: return v == nil case *LanConfigParam_VLANPriority: return v == nil case *LanConfigParam_CipherSuitesSupport: return v == nil case *LanConfigParam_CipherSuitesID: return v == nil case *LanConfigParam_CipherSuitesPrivLevel: return v == nil case *LanConfigParam_AlertDestinationVLAN: return v == nil case *LanConfigParam_BadPasswordThreshold: return v == nil case *LanConfigParam_IPv6Support: return v == nil case *LanConfigParam_IPv6Enables: return v == nil case *LanConfigParam_IPv6StaticTrafficClass: return v == nil case *LanConfigParam_IPv6StaticHopLimit: return v == nil case *LanConfigParam_IPv6FlowLabel: return v == nil case *LanConfigParam_IPv6Status: return v == nil case *LanConfigParam_IPv6StaticAddress: return v == nil case *LanConfigParam_IPv6DHCPv6StaticDUIDCount: return v == nil case *LanConfigParam_IPv6DHCPv6StaticDUID: return v == nil case *LanConfigParam_IPv6DynamicAddress: return v == nil case *LanConfigParam_IPv6DHCPv6DynamicDUIDCount: return v == nil case *LanConfigParam_IPv6DHCPv6DynamicDUID: return v == nil case *LanConfigParam_IPv6DHCPv6TimingConfigSupport: return v == nil case *LanConfigParam_IPv6DHCPv6TimingConfig: return v == nil case *LanConfigParam_IPv6RouterAddressConfigControl: return v == nil case *LanConfigParam_IPv6StaticRouter1IP: return v == nil case *LanConfigParam_IPv6StaticRouter1MAC: return v == nil case *LanConfigParam_IPv6StaticRouter1PrefixLength: return v == nil case *LanConfigParam_IPv6StaticRouter1PrefixValue: return v == nil case *LanConfigParam_IPv6StaticRouter2IP: return v == nil case *LanConfigParam_IPv6StaticRouter2MAC: return v == nil case *LanConfigParam_IPv6StaticRouter2PrefixLength: return v == nil case *LanConfigParam_IPv6StaticRouter2PrefixValue: return v == nil case *LanConfigParam_IPv6DynamicRouterInfoSets: return v == nil case *LanConfigParam_IPv6DynamicRouterInfoIP: return v == nil case *LanConfigParam_IPv6DynamicRouterInfoMAC: return v == nil case *LanConfigParam_IPv6DynamicRouterInfoPrefixLength: return v == nil case *LanConfigParam_IPv6DynamicRouterInfoPrefixValue: return v == nil case *LanConfigParam_IPv6DynamicRouterReceivedHopLimit: return v == nil case *LanConfigParam_IPv6NDSLAACTimingConfigSupport: return v == nil case *LanConfigParam_IPv6NDSLAACTimingConfig: return v == nil default: return false } } type LanConfigParam_SetInProgress struct { Value SetInProgressState } func (param *LanConfigParam_SetInProgress) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_SetInProgress, 0, 0 } func (param *LanConfigParam_SetInProgress) Pack() []byte { return []byte{byte(param.Value)} } func (param *LanConfigParam_SetInProgress) Unpack(data []byte) error { if len(data) != 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Value = SetInProgressState(data[0]) return nil } func (param *LanConfigParam_SetInProgress) Format() string { return param.Value.String() } type LanConfigParam_AuthTypeSupport struct { OEM bool Password bool MD5 bool MD2 bool None bool } func (param *LanConfigParam_AuthTypeSupport) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_AuthTypeSupport, 0, 0 } func (param *LanConfigParam_AuthTypeSupport) Pack() []byte { b := uint8(0) b = setOrClearBit5(b, param.OEM) b = setOrClearBit4(b, param.Password) b = setOrClearBit2(b, param.MD5) b = setOrClearBit1(b, param.MD2) b = setOrClearBit0(b, param.None) return []byte{b} } func (param *LanConfigParam_AuthTypeSupport) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } b := data[0] param.OEM = isBit5Set(b) param.Password = isBit4Set(b) // Bit 3 Reserved param.MD5 = isBit2Set(b) param.MD2 = isBit1Set(b) param.None = isBit0Set(b) return nil } func (param *LanConfigParam_AuthTypeSupport) Format() string { var s string if param.OEM { s = "OEM" } else if param.Password { s = "Password" } else if param.MD5 { s = "MD5" } else if param.MD2 { s = "MD2" } else if param.None { s = "None" } return fmt.Sprintf(`%s, (OEM: %v, Password: %v, MD5: %v, MD2: %v, Non: %v)`, s, param.OEM, param.Password, param.MD5, param.MD2, param.None) } type LanConfigParam_AuthTypeEnables struct { Callback *AuthTypesEnabled User *AuthTypesEnabled Operator *AuthTypesEnabled Admin *AuthTypesEnabled OEM *AuthTypesEnabled } func (param *LanConfigParam_AuthTypeEnables) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_AuthTypeEnables, 0, 0 } func (param *LanConfigParam_AuthTypeEnables) Unpack(data []byte) error { if len(data) < 5 { return ErrUnpackedDataTooShortWith(len(data), 5) } param.Callback = unpackAuthTypesEnabled(data[0]) param.User = unpackAuthTypesEnabled(data[1]) param.Operator = unpackAuthTypesEnabled(data[2]) param.Admin = unpackAuthTypesEnabled(data[3]) param.OEM = unpackAuthTypesEnabled(data[4]) return nil } func (param *LanConfigParam_AuthTypeEnables) Pack() []byte { out := make([]byte, 5) out[0] = packAuthTypesEnabled(param.Callback) out[1] = packAuthTypesEnabled(param.User) out[2] = packAuthTypesEnabled(param.Operator) out[3] = packAuthTypesEnabled(param.Admin) out[4] = packAuthTypesEnabled(param.OEM) return out } func (param *LanConfigParam_AuthTypeEnables) Format() string { return fmt.Sprintf("Callback: %s, User: %s, Operator: %s, Admin: %s, OEM: %s", param.Callback.String(), param.User.String(), param.Operator.String(), param.Admin.String(), param.OEM.String()) } type LanConfigParam_IP struct { IP net.IP } func (param *LanConfigParam_IP) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IP, 0, 0 } func (param *LanConfigParam_IP) Unpack(data []byte) error { if len(data) < 4 { return ErrUnpackedDataTooShortWith(len(data), 4) } param.IP = net.IPv4(data[0], data[1], data[2], data[3]) return nil } func (param *LanConfigParam_IP) Pack() []byte { return []byte{param.IP[0], param.IP[1], param.IP[2], param.IP[3]} } func (param *LanConfigParam_IP) Format() string { return param.IP.String() } type LanConfigParam_IPSource struct { Source LanIPAddressSource } func (param *LanConfigParam_IPSource) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPSource, 0, 0 } func (param *LanConfigParam_IPSource) Pack() []byte { return []byte{byte(param.Source)} } func (param *LanConfigParam_IPSource) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Source = LanIPAddressSource(data[0]) return nil } func (param *LanConfigParam_IPSource) Format() string { return param.Source.String() } type LanConfigParam_MAC struct { MAC net.HardwareAddr } func (param *LanConfigParam_MAC) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_MAC, 0, 0 } func (param *LanConfigParam_MAC) Unpack(data []byte) error { if len(data) < 6 { return ErrUnpackedDataTooShortWith(len(data), 6) } param.MAC = net.HardwareAddr(data[0:6]) return nil } func (param *LanConfigParam_MAC) Pack() []byte { return param.MAC } func (param *LanConfigParam_MAC) Format() string { return param.MAC.String() } type LanConfigParam_SubnetMask struct { SubnetMask net.IP } func (param *LanConfigParam_SubnetMask) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_SubnetMask, 0, 0 } func (param *LanConfigParam_SubnetMask) Unpack(data []byte) error { if len(data) < 4 { return ErrUnpackedDataTooShortWith(len(data), 4) } param.SubnetMask = net.IPv4(data[0], data[1], data[2], data[3]) return nil } func (param *LanConfigParam_SubnetMask) Pack() []byte { return []byte{param.SubnetMask[0], param.SubnetMask[1], param.SubnetMask[2], param.SubnetMask[3]} } func (param *LanConfigParam_SubnetMask) Format() string { return param.SubnetMask.String() } type LanConfigParam_IPv4HeaderParams struct { // data 1 - Time-to-live. 1-based. (Default = 40h) // Value for time-to-live parameter in IP Header for RMCP packets and PET Traps // transmitted from this channel. TTL uint8 // data 2 // - [7:5] - Flags. Sets value of bit 1 in the Flags field in the IP Header for packets transmitted // by this channel. (Default = 010b don't fragment) // - [4:0] - reserved Flags uint8 // data 3 // - [7:5] - Precedence (Default = 000b) Precedence uint8 // data 3 // - [4:1] - Type of Service (Default = 1000b, 'minimize delay') // - [0] - reserved TOS uint8 } func (param *LanConfigParam_IPv4HeaderParams) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv4HeaderParams, 0, 0 } func (param *LanConfigParam_IPv4HeaderParams) Unpack(data []byte) error { if len(data) < 3 { return ErrUnpackedDataTooShortWith(len(data), 3) } param.TTL = data[0] param.Flags = data[1] param.Precedence = data[2] >> 5 param.TOS = data[2] & 0x1f return nil } func (param *LanConfigParam_IPv4HeaderParams) Pack() []byte { out := make([]byte, 3) out[0] = param.TTL out[1] = param.Flags out[2] = (param.Precedence << 5) | (param.TOS & 0x1f) return out } func (param *LanConfigParam_IPv4HeaderParams) Format() string { return fmt.Sprintf("TTL=%#02x Flags=%#02x Precedence=%#02x TOS=%#02x", param.TTL, param.Flags, param.Precedence, param.TOS) } type LanConfigParam_PrimaryRMCPPort struct { Port uint16 } func (param *LanConfigParam_PrimaryRMCPPort) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_PrimaryRMCPPort, 0, 0 } func (param *LanConfigParam_PrimaryRMCPPort) Unpack(data []byte) error { if len(data) < 2 { return ErrUnpackedDataTooShortWith(len(data), 2) } param.Port, _, _ = unpackUint16L(data, 0) return nil } func (param *LanConfigParam_PrimaryRMCPPort) Pack() []byte { out := make([]byte, 2) packUint16L(param.Port, out, 0) return out } func (param *LanConfigParam_PrimaryRMCPPort) Format() string { return fmt.Sprintf("%d", param.Port) } type LanConfigParam_SecondaryRMCPPort struct { Port uint16 } func (param *LanConfigParam_SecondaryRMCPPort) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_SecondaryRMCPPort, 0, 0 } func (param *LanConfigParam_SecondaryRMCPPort) Unpack(data []byte) error { if len(data) < 2 { return ErrUnpackedDataTooShortWith(len(data), 2) } param.Port, _, _ = unpackUint16L(data, 0) return nil } func (param *LanConfigParam_SecondaryRMCPPort) Pack() []byte { out := make([]byte, 2) packUint16L(param.Port, out, 0) return out } func (param *LanConfigParam_SecondaryRMCPPort) Format() string { return fmt.Sprintf("%d", param.Port) } type LanConfigParam_ARPControl struct { ARPResponseEnabled bool GratuitousARPEnabled bool } func (param *LanConfigParam_ARPControl) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_ARPControl, 0, 0 } func (param *LanConfigParam_ARPControl) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.ARPResponseEnabled = isBit1Set(data[0]) param.GratuitousARPEnabled = isBit0Set(data[0]) return nil } func (param *LanConfigParam_ARPControl) Pack() []byte { out := make([]byte, 1) b := uint8(0) b = setOrClearBit1(b, param.ARPResponseEnabled) b = setOrClearBit0(b, param.GratuitousARPEnabled) out[0] = b return out } func (param *LanConfigParam_ARPControl) Format() string { return fmt.Sprintf("ARP Responses %s, Gratuitous ARP %s", formatBool(param.ARPResponseEnabled, "enabled", "disabled"), formatBool(param.GratuitousARPEnabled, "enabled", "disabled")) } type LanConfigParam_GratuitousARPInterval struct { // Gratuitous ARP interval in 500 millisecond increments. 0-based. MilliSec uint32 } func (param *LanConfigParam_GratuitousARPInterval) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_GratuitousARPInterval, 0, 0 } func (param *LanConfigParam_GratuitousARPInterval) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.MilliSec = uint32(data[0]) * 500 return nil } func (param *LanConfigParam_GratuitousARPInterval) Pack() []byte { out := make([]byte, 1) out[0] = uint8(param.MilliSec / 500) return out } func (param *LanConfigParam_GratuitousARPInterval) Format() string { return fmt.Sprintf("%.1f seconds", float64(param.MilliSec/1000.0)) } type LanConfigParam_DefaultGatewayIP struct { IP net.IP } func (param *LanConfigParam_DefaultGatewayIP) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_DefaultGatewayIP, 0, 0 } func (param *LanConfigParam_DefaultGatewayIP) Unpack(data []byte) error { if len(data) < 4 { return ErrUnpackedDataTooShortWith(len(data), 4) } param.IP = net.IPv4(data[0], data[1], data[2], data[3]) return nil } func (param *LanConfigParam_DefaultGatewayIP) Pack() []byte { out := make([]byte, 4) out[0] = param.IP[0] out[1] = param.IP[1] out[2] = param.IP[2] out[3] = param.IP[3] return out } func (param *LanConfigParam_DefaultGatewayIP) Format() string { return param.IP.String() } type LanConfigParam_DefaultGatewayMAC struct { MAC net.HardwareAddr } func (param *LanConfigParam_DefaultGatewayMAC) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_DefaultGatewayMAC, 0, 0 } func (param *LanConfigParam_DefaultGatewayMAC) Unpack(data []byte) error { if len(data) < 6 { return ErrUnpackedDataTooShortWith(len(data), 6) } param.MAC = net.HardwareAddr(data[0:6]) return nil } func (param *LanConfigParam_DefaultGatewayMAC) Pack() []byte { out := make([]byte, 6) out[0] = param.MAC[0] out[1] = param.MAC[1] out[2] = param.MAC[2] out[3] = param.MAC[3] out[4] = param.MAC[4] out[5] = param.MAC[5] return out } func (param *LanConfigParam_DefaultGatewayMAC) Format() string { return param.MAC.String() } type LanConfigParam_BackupGatewayIP struct { IP net.IP } func (param *LanConfigParam_BackupGatewayIP) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_BackupGatewayIP, 0, 0 } func (param *LanConfigParam_BackupGatewayIP) Unpack(data []byte) error { if len(data) < 4 { return ErrUnpackedDataTooShortWith(len(data), 4) } param.IP = net.IPv4(data[0], data[1], data[2], data[3]) return nil } func (param *LanConfigParam_BackupGatewayIP) Pack() []byte { out := make([]byte, 4) out[0] = param.IP[0] out[1] = param.IP[1] out[2] = param.IP[2] out[3] = param.IP[3] return out } func (param *LanConfigParam_BackupGatewayIP) Format() string { return param.IP.String() } type LanConfigParam_BackupGatewayMAC struct { MAC net.HardwareAddr } func (param *LanConfigParam_BackupGatewayMAC) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_BackupGatewayMAC, 0, 0 } func (param *LanConfigParam_BackupGatewayMAC) Unpack(data []byte) error { if len(data) < 6 { return ErrUnpackedDataTooShortWith(len(data), 6) } param.MAC = net.HardwareAddr(data[0:6]) return nil } func (param *LanConfigParam_BackupGatewayMAC) Pack() []byte { out := make([]byte, 6) out[0] = param.MAC[0] out[1] = param.MAC[1] out[2] = param.MAC[2] out[3] = param.MAC[3] out[4] = param.MAC[4] out[5] = param.MAC[5] return out } func (param *LanConfigParam_BackupGatewayMAC) Format() string { return param.MAC.String() } type LanConfigParam_CommunityString struct { CommunityString CommunityString } func (param *LanConfigParam_CommunityString) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_CommunityString, 0, 0 } func (param *LanConfigParam_CommunityString) Unpack(data []byte) error { if len(data) < 18 { return ErrUnpackedDataTooShortWith(len(data), 18) } var cs CommunityString for i := 0; i < 18; i++ { cs[i] = data[i] } param.CommunityString = cs return nil } func (param *LanConfigParam_CommunityString) Pack() []byte { return param.CommunityString[:] } func (param *LanConfigParam_CommunityString) Format() string { return string(param.CommunityString[:]) } // Number of LAN Alert Destinations supported on this channel. (Read Only). // // At least one set of non-volatile destination information is required if LAN alerting is supported. // // Additional non-volatile destination parameters can optionally be provided for supporting an // alert 'call down' list policy. // // A maximum of fifteen (1h to Fh) non-volatile destinations are supported in this specification. // Destination 0 is always present as a volatile destination that is used with the Alert Immediate command. type LanConfigParam_AlertDestinationsCount struct { // [7:4] - reserved. // [3:0] - Number LAN Destinations. A count of 0h indicates LAN Alerting is not supported. // This value is number of non-volatile destinations. Count uint8 } func (param *LanConfigParam_AlertDestinationsCount) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_AlertDestinationsCount, 0, 0 } func (param *LanConfigParam_AlertDestinationsCount) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Count = data[0] & 0x0f return nil } func (param *LanConfigParam_AlertDestinationsCount) Pack() []byte { out := make([]byte, 1) out[0] = param.Count & 0x0f return out } func (param *LanConfigParam_AlertDestinationsCount) Format() string { return fmt.Sprintf("%d", param.Count) } type LanConfigParam_AlertDestinationType struct { // Destination selector, 0 based. // Destination 0 is always present as a volatile destination that is used with the Alert Immediate command. SetSelector uint8 // Alert Acknowledge // - 0b = Unacknowledged. // Alert is assumed successful if transmission occurs without error. // This value is also used with Callback numbers. // - 1b = Acknowledged. // Alert is assumed successful only if acknowledged is returned. // Note, some alert types, such as Dial Page, do not support an acknowledge AlertAcknowledged bool // Destination Type // - 000b = PET Trap destination // - 001b - 101b = reserved // - 110b = OEM 1 // - 111b = OEM 2 DestinationType uint8 // Alert Acknowledge Timeout / Retry Interval, in seconds, 0-based (i.e. minimum // timeout = 1 second) AlertAcknowledgeTimeout uint8 // Number of times to retry alert to given destination. Retries uint8 } func (param *LanConfigParam_AlertDestinationType) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_AlertDestinationType, param.SetSelector, 0 } func (param *LanConfigParam_AlertDestinationType) Unpack(data []byte) error { if len(data) < 4 { return ErrUnpackedDataTooShortWith(len(data), 4) } param.SetSelector = data[0] param.AlertAcknowledged = isBit7Set(data[1]) param.DestinationType = data[1] & 0x03 param.AlertAcknowledgeTimeout = data[2] param.Retries = data[3] & 0x07 return nil } func (param *LanConfigParam_AlertDestinationType) Pack() []byte { out := make([]byte, 4) out[0] = param.SetSelector b := param.DestinationType & 0x03 b = setOrClearBit7(b, param.AlertAcknowledged) out[1] = b out[2] = param.AlertAcknowledgeTimeout out[3] = param.Retries return out } func (param *LanConfigParam_AlertDestinationType) Format() string { return fmt.Sprintf("%12s %2d, %v, %d, %d, %d", formatBool(param.SetSelector == 0, "volatile", "non-volatile"), param.SetSelector, formatBool(param.AlertAcknowledged, "acknowledged", "unacknowledged"), param.DestinationType, param.AlertAcknowledgeTimeout, param.Retries, ) } type LanConfigParam_AlertDestinationAddress struct { SetSelector uint8 IsIPv6 bool // - 0b = use default gateway first, then backup gateway // (Note: older implementations (errata 4 or earlier) may only send to the default gateway.) // - 1b = use backup gateway UseBackupGateway bool IPv4 net.IP MAC net.HardwareAddr IPv6 net.IP } func (param *LanConfigParam_AlertDestinationAddress) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_AlertDestinationAddress, param.SetSelector, 0 } func (param *LanConfigParam_AlertDestinationAddress) Unpack(data []byte) error { if len(data) < 13 { return ErrUnpackedDataTooShortWith(len(data), 13) } param.SetSelector = data[0] param.IsIPv6 = isBit4Set(data[1]) if param.IsIPv6 { if len(data) < 18 { return ErrUnpackedDataTooShortWith(len(data), 18) } param.IPv6 = net.IP(data[3:18]) } else { param.UseBackupGateway = isBit7Set(data[2]) param.IPv4 = net.IP(data[3:7]) param.MAC = net.HardwareAddr(data[7:13]) } return nil } func (param *LanConfigParam_AlertDestinationAddress) Pack() []byte { out := make([]byte, 2) return out } func (param *LanConfigParam_AlertDestinationAddress) Format() string { return fmt.Sprintf("%12s %2d, %s, %s, %s", formatBool(param.SetSelector == 0, "volatile", "non-volatile"), param.SetSelector, formatBool(param.UseBackupGateway, "backup gateway", "default gateway"), formatBool(param.IsIPv6, "IPv6", "IPv4"), formatBool(param.IsIPv6, param.IPv6.String(), fmt.Sprintf("%s/%s", param.IPv4, param.MAC)), ) } type LanConfigParam_VLANID struct { Enabled bool ID uint16 } func (param *LanConfigParam_VLANID) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_VLANID, 0, 0 } func (param *LanConfigParam_VLANID) Unpack(data []byte) error { if len(data) < 2 { return ErrUnpackedDataTooShortWith(len(data), 2) } param.Enabled = isBit7Set(data[1]) id := uint16(data[1]) & 0x0f id <<= 12 id |= uint16(data[0]) param.ID = id return nil } func (param *LanConfigParam_VLANID) Pack() []byte { out := make([]byte, 2) out[0] = byte(param.ID & 0xff) b := byte(param.ID >> 8) b = setOrClearBit7(b, param.Enabled) out[1] = b return out } func (param *LanConfigParam_VLANID) Format() string { return formatBool(param.Enabled, fmt.Sprintf("%d", param.ID), "disabled") } type LanConfigParam_VLANPriority struct { Priority uint8 } func (param *LanConfigParam_VLANPriority) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_VLANPriority, 0, 0 } func (param *LanConfigParam_VLANPriority) Pack() []byte { out := make([]byte, 1) out[0] = param.Priority & 0x07 return out } func (param *LanConfigParam_VLANPriority) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Priority = data[0] & 0x07 return nil } func (param *LanConfigParam_VLANPriority) Format() string { return fmt.Sprintf("%#2x", param.Priority) } type LanConfigParam_CipherSuitesSupport struct { // Cipher Suite Entry count. Number of Cipher Suite entries, 1-based, 10h max. Count uint8 } func (param *LanConfigParam_CipherSuitesSupport) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_CipherSuitesSupport, 0, 0 } func (param *LanConfigParam_CipherSuitesSupport) Pack() []byte { out := make([]byte, 1) out[0] = param.Count & 0x1f return out } func (param *LanConfigParam_CipherSuitesSupport) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Count = data[0] & 0x1f return nil } func (param *LanConfigParam_CipherSuitesSupport) Format() string { return fmt.Sprintf("%d", param.Count) } type LanConfigParam_CipherSuitesID struct { IDs [16]CipherSuiteID } func (param *LanConfigParam_CipherSuitesID) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_CipherSuitesID, 0, 0 } func (param *LanConfigParam_CipherSuitesID) Pack() []byte { out := make([]uint8, 17) out[0] = 0 for i, id := range param.IDs { out[i+1] = uint8(id) } return out } func (param *LanConfigParam_CipherSuitesID) Unpack(data []byte) error { if len(data) > 17 { data = data[:17] } for i, v := range data { if i == 0 { // first byte is reserved continue } param.IDs[i-1] = CipherSuiteID(v) } return nil } func (param *LanConfigParam_CipherSuitesID) Format() string { ss := make([]string, 0) for i, v := range param.IDs[:] { if i != 0 && v == 0 { // Only the first ID can be CipherSuiteID0, all other 0s means empty slot. continue } ss = append(ss, strconv.Itoa(int(v))) } return strings.Join(ss, ",") } type LanConfigParam_CipherSuitesPrivLevel struct { PrivLevels [16]PrivilegeLevel } func (param *LanConfigParam_CipherSuitesPrivLevel) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_CipherSuitesPrivLevel, 0, 0 } func (param *LanConfigParam_CipherSuitesPrivLevel) Pack() []byte { out := make([]byte, 9) out[0] = 0 for i := 0; i < 8; i++ { o := byte(param.PrivLevels[2*i] & 0x0f) o |= byte(param.PrivLevels[2*i+1] & 0x0f) out[i+1] = o } return out } func (param *LanConfigParam_CipherSuitesPrivLevel) Unpack(data []byte) error { if len(data) < 9 { return ErrUnpackedDataTooShortWith(len(data), 9) } for i, v := range data[0:9] { if i == 0 { // first byte is reserved continue } param.PrivLevels[2*i-2] = PrivilegeLevel(v & 0x0f) param.PrivLevels[2*i-1] = PrivilegeLevel(v & 0xf0 >> 4) } return nil } func (param *LanConfigParam_CipherSuitesPrivLevel) Format() string { ss := []string{} for _, v := range param.PrivLevels[:] { ss = append(ss, v.Symbol()) } return fmt.Sprintf(`%s : X=Cipher Suite Unused : c=CALLBACK : u=USER : o=OPERATOR : a=ADMIN : O=OEM`, strings.Join(ss, "")) } type LanConfigParam_AlertDestinationVLAN struct { // data 1 - Set Selector = Destination Selector. // - [7:4] - reserved // - [3:0] - Destination selector. // Destination 0 is always present as a volatile destination that is used with the Alert Immediate command. SetSelector uint8 // Address Format. // VLAN ID is used with this destination // - 0h = VLAN ID not used with this destination // - 1h = 802.1q VLAN TAG Enabled bool // data 3-4 - VLAN TAG // - [7:0] - VLAN ID, least-significant byte // - [11:8] - VLAN ID, most-significant nibble // - [12] - CFI (Canonical Format Indicator. Set to 0b) // - [15:13] - User priority (000b, typical) VLANID uint16 CFI bool Priority uint8 } func (param *LanConfigParam_AlertDestinationVLAN) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_AlertDestinationVLAN, param.SetSelector, 0 } func (param *LanConfigParam_AlertDestinationVLAN) Pack() []byte { out := make([]byte, 4) out[0] = param.SetSelector b1 := uint8(0) b1 = setOrClearBit5(b1, param.Enabled) out[1] = b1 out[2] = uint8(param.VLANID) b3 := uint8(param.VLANID>>8) & 0x0f b3 = setOrClearBit4(b3, param.CFI) b3 |= param.Priority << 5 out[3] = b3 return out } func (param *LanConfigParam_AlertDestinationVLAN) Unpack(data []byte) error { if len(data) < 4 { return ErrUnpackedDataTooShortWith(len(data), 4) } param.SetSelector = data[0] param.Enabled = isBit4Set(data[1]) param.CFI = isBit4Set(data[3]) param.Priority = data[3] >> 5 param.VLANID = uint16(data[3]&0x0f) << 12 param.VLANID |= uint16(data[2]) return nil } func (param *LanConfigParam_AlertDestinationVLAN) Format() string { return fmt.Sprintf("%12s %d, %s, %d, %s, %d", formatBool(param.SetSelector == 0, "volatile", "non-volatile"), param.SetSelector, formatBool(param.Enabled, "enabled", "disabled"), param.VLANID, formatBool(param.CFI, "1", "0"), param.Priority, ) } type LanConfigParam_BadPasswordThreshold struct { // Generate Session Audit Event // - 0b = do not generate an event message when the user is disabled. // - 1b = generate a Session Audit sensor "Invalid password disable" event message. GenerateSessionAuditEvent bool // Bad Password Threshold number Threshold uint8 // Attempt Count Reset Interval. // The raw data occupies 2 bytes, and the unit is in tens of seconds. // // 0 means the Attempt Count Reset Interval is disabled. // The count of bad password attempts is retained as long as // the BMC remains powered and is not reinitialized. AttemptCountResetIntervalSec uint32 // User Lockout Interval // The raw data occupies 2 bytes, and the unit is in tens of seconds. // // 0 means the User Lockout Interval is disabled. // If a user was automatically disabled due to the Bad Password threshold, // the user will remain disabled until re-enabled via the Set User Access command. UserLockoutIntervalSec uint32 } func (param *LanConfigParam_BadPasswordThreshold) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_BadPasswordThreshold, 0, 0 } func (param *LanConfigParam_BadPasswordThreshold) Pack() []byte { out := make([]byte, 0) b := uint8(0) b = setOrClearBit0(b, param.GenerateSessionAuditEvent) out[0] = b out[1] = param.Threshold resetInterval := uint16(param.AttemptCountResetIntervalSec / 10) lockInterval := uint16(param.UserLockoutIntervalSec / 10) packUint16L(resetInterval, out, 2) packUint16L(lockInterval, out, 4) return out } func (param *LanConfigParam_BadPasswordThreshold) Unpack(data []byte) error { if len(data) < 6 { return ErrUnpackedDataTooShortWith(len(data), 6) } param.GenerateSessionAuditEvent = isBit0Set(data[0]) param.Threshold = data[1] resetInterval, _, _ := unpackUint16L(data, 2) lockInterval, _, _ := unpackUint16L(data, 4) param.AttemptCountResetIntervalSec = uint32(resetInterval) * 10 param.UserLockoutIntervalSec = uint32(lockInterval) * 10 return nil } func (param *LanConfigParam_BadPasswordThreshold) Format() string { return fmt.Sprintf(` Threshold : %d Generate Session Audit Event : %v Attempt Count Reset Interval : %d User Lockout Interval : %d `, param.Threshold, param.GenerateSessionAuditEvent, param.AttemptCountResetIntervalSec, param.UserLockoutIntervalSec, ) } type LanConfigParam_IPv6Support struct { // Implementation supports IPv6 Destination Addresses for LAN Alerting. SupportIPv6AlertDestination bool // Implementation can be configured to use both IPv4 and IPv6 addresses simultaneously CanUseBothIPv4AndIPv6 bool // Implementation can be configured to use IPv6 addresses only. CanUseIPv6Only bool } func (param *LanConfigParam_IPv6Support) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6Support, 0, 0 } func (param *LanConfigParam_IPv6Support) Pack() []byte { out := make([]byte, 1) var b byte b = setOrClearBit2(b, param.SupportIPv6AlertDestination) b = setOrClearBit1(b, param.CanUseBothIPv4AndIPv6) b = setOrClearBit0(b, param.CanUseIPv6Only) out[1] = b return out } func (param *LanConfigParam_IPv6Support) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.SupportIPv6AlertDestination = isBit2Set(data[0]) param.CanUseBothIPv4AndIPv6 = isBit1Set(data[0]) param.CanUseIPv6Only = isBit0Set(data[0]) return nil } func (param *LanConfigParam_IPv6Support) Format() string { return fmt.Sprintf("%s %s %s", formatBool(param.SupportIPv6AlertDestination, "ipv6(supported)", "ipv6(not-supported)"), formatBool(param.CanUseBothIPv4AndIPv6, "ipv4-and-ipv6(supported)", "ipv4-and-ipv6(not-supported)"), formatBool(param.CanUseIPv6Only, "ipv6-only(supported)", "ipv6-only(not-supported)"), ) } type LanConfigParam_IPv6Enables struct { EnableMode LanIPv6EnableMode } func (enableMode LanIPv6EnableMode) String() string { m := map[LanIPv6EnableMode]string{ LanIPv6EnableMode_IPv6Disabled: "IPv6 disabled", LanIPv6EnableMode_IPv6Only: "IPv6 only", LanIPv6EnableMode_IPv4AndIPv6: "IPv4 and IPv6", } s, ok := m[enableMode] if ok { return s } return "Unknown" } func (param *LanConfigParam_IPv6Enables) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6Enables, 0, 0 } func (param *LanConfigParam_IPv6Enables) Pack() []byte { out := make([]byte, 1) out[0] = uint8(param.EnableMode) return out } func (param *LanConfigParam_IPv6Enables) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.EnableMode = LanIPv6EnableMode(data[0]) return nil } func (param *LanConfigParam_IPv6Enables) Format() string { return param.EnableMode.String() } type LanConfigParam_IPv6StaticTrafficClass struct { TrafficClass uint8 } func (param *LanConfigParam_IPv6StaticTrafficClass) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticTrafficClass, 0, 0 } func (param *LanConfigParam_IPv6StaticTrafficClass) Pack() []byte { out := make([]byte, 1) out[0] = param.TrafficClass return out } func (param *LanConfigParam_IPv6StaticTrafficClass) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.TrafficClass = data[0] return nil } func (param *LanConfigParam_IPv6StaticTrafficClass) Format() string { return fmt.Sprintf("%d", param.TrafficClass) } type LanConfigParam_IPv6StaticHopLimit struct { HopLimit uint8 } func (param *LanConfigParam_IPv6StaticHopLimit) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticHopLimit, 0, 0 } func (param *LanConfigParam_IPv6StaticHopLimit) Pack() []byte { out := make([]byte, 1) out[0] = param.HopLimit return out } func (param *LanConfigParam_IPv6StaticHopLimit) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.HopLimit = data[0] return nil } func (param *LanConfigParam_IPv6StaticHopLimit) Format() string { return fmt.Sprintf("%d", param.HopLimit) } type LanConfigParam_IPv6FlowLabel struct { // Flow Label, 20-bits, right justified, MS Byte first. Default = 0. // // Three bytes. // // If this configuration parameter is not supported, the Flow Label shall be set to 0 per [RFC2460]. // Bits [23:20] = reserved - set to 0b. // see: https://datatracker.ietf.org/doc/html/rfc2460#page-25 FlowLabel uint32 } func (param *LanConfigParam_IPv6FlowLabel) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6FlowLabel, 0, 0 } func (param *LanConfigParam_IPv6FlowLabel) Pack() []byte { out := make([]byte, 3) packUint24(param.FlowLabel, out, 0) return out } func (param *LanConfigParam_IPv6FlowLabel) Unpack(data []byte) error { if len(data) < 3 { return ErrUnpackedDataTooShortWith(len(data), 3) } param.FlowLabel, _, _ = unpackUint24(data, 0) return nil } func (param *LanConfigParam_IPv6FlowLabel) Format() string { return fmt.Sprintf("%d", param.FlowLabel) } type LanConfigParam_IPv6Status struct { // Maximum number of static IPv6 addresses for establishing connections to the BMC. // Note: in some implementations this may exceed the number of simultaneous sessions supported on // the channel. 0 indicates that static address configuration is not available. StaticAddressMax uint8 // Maximum number of Dynamic (SLAAC/ DHCPv6) IPv6 addresses that can be obtained for // establishing connections to the BMC. //Note: in some implementations this may exceed the number of simultaneous sessions supported on the channel. // 0 = Dynamic addressing is not supported by the BMC. DynamicAddressMax uint8 // data 3: - // - [7:2] - reserved // - [1] - 1b = SLAAC addressing is supported by the BMC // - [0] - 1b = DHCPv6 addressing is supported by the BMC (optional) SupportSLAACAddressing bool SupportDHCPv6Addressing bool } func (param *LanConfigParam_IPv6Status) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6Status, 0, 0 } func (param *LanConfigParam_IPv6Status) Unpack(data []byte) error { if len(data) < 3 { return ErrUnpackedDataTooShortWith(len(data), 3) } param.StaticAddressMax = data[0] param.DynamicAddressMax = data[1] param.SupportSLAACAddressing = isBit1Set(data[2]) param.SupportDHCPv6Addressing = isBit0Set(data[2]) return nil } func (param *LanConfigParam_IPv6Status) Pack() []byte { out := make([]byte, 3) out[0] = param.StaticAddressMax out[1] = param.DynamicAddressMax var b uint8 b = setOrClearBit1(b, param.SupportSLAACAddressing) b = setOrClearBit0(b, param.SupportDHCPv6Addressing) out[2] = b return out } func (param *LanConfigParam_IPv6Status) Format() string { return fmt.Sprintf("Static Addr Max: %d, Dynamic Addr Max: %d, SupportSLAAC: %v, SupportDHCPv6: %v", param.StaticAddressMax, param.DynamicAddressMax, param.SupportSLAACAddressing, param.SupportDHCPv6Addressing) } type LanConfigParam_IPv6StaticAddress struct { SetSelector uint8 // Address Enabled // - [7]- enable=1/disable=0 Enabled bool // Address Source // [3:0]- source/type // - 0h = Static // - All other = reserved Source LanIPv6StaticAddressSource IPv6 net.IP PrefixLength uint8 Status LanIPv6AddressStatus } func (param *LanConfigParam_IPv6StaticAddress) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticAddress, param.SetSelector, 0 } func (param *LanConfigParam_IPv6StaticAddress) Pack() []byte { out := make([]byte, 20) out[0] = param.SetSelector var b1 uint8 b1 = setOrClearBit7(b1, param.Enabled) b1 |= uint8(param.Source) & 0x0f out[1] = b1 // 16-byte (IPv6) packBytes(param.IPv6, out, 2) out[18] = param.PrefixLength out[19] = byte(param.Status) return out } func (param *LanConfigParam_IPv6StaticAddress) Unpack(data []byte) error { if len(data) < 20 { return ErrUnpackedDataTooShortWith(len(data), 20) } param.SetSelector = data[0] param.Enabled = isBit7Set(data[1]) param.Source = LanIPv6StaticAddressSource(data[1] & 0x0f) param.IPv6 = net.IP(data[2:18]) param.PrefixLength = data[18] param.Status = LanIPv6AddressStatus(data[19]) return nil } func (param *LanConfigParam_IPv6StaticAddress) Format() string { return fmt.Sprintf("%d, Enabled: %v, Source: %d, IPv6: %s, PrefixLength: %d, Status: %s", param.SetSelector, param.Enabled, param.Source, param.IPv6, param.PrefixLength, param.Status) } type LanConfigParam_IPv6DHCPv6StaticDUIDCount struct { // The maximum number of 16-byte blocks that can be used for storing each DUID via // the IPv6 DHCPv6 Static DUIDs parameter. 1-based. Returns 0 if IPv6 Static Address // configuration is not supported. Max uint8 } func (param *LanConfigParam_IPv6DHCPv6StaticDUIDCount) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DHCPv6StaticDUIDCount, 0, 0 } func (param *LanConfigParam_IPv6DHCPv6StaticDUIDCount) Pack() []byte { out := make([]byte, 1) out[0] = param.Max return out } func (param *LanConfigParam_IPv6DHCPv6StaticDUIDCount) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Max = data[0] return nil } func (param *LanConfigParam_IPv6DHCPv6StaticDUIDCount) Format() string { return fmt.Sprintf("%d", param.Max) } type LanConfigParam_IPv6DHCPv6StaticDUID struct { SetSelector uint8 BlockSelector uint8 DUID [16]byte } func (param *LanConfigParam_IPv6DHCPv6StaticDUID) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DHCPv6StaticDUID, param.SetSelector, param.BlockSelector } func (param *LanConfigParam_IPv6DHCPv6StaticDUID) Pack() []byte { out := make([]byte, 18) out[0] = param.SetSelector out[1] = param.BlockSelector copy(out[2:], param.DUID[:]) return out } func (param *LanConfigParam_IPv6DHCPv6StaticDUID) Unpack(data []byte) error { if len(data) < 18 { return ErrUnpackedDataTooShortWith(len(data), 18) } param.SetSelector = data[0] param.BlockSelector = data[1] copy(param.DUID[:], data[2:18]) return nil } func (param *LanConfigParam_IPv6DHCPv6StaticDUID) Format() string { return fmt.Sprintf("%d, %d, %x", param.SetSelector, param.BlockSelector, param.DUID) } type LanConfigParam_IPv6DynamicAddress struct { SetSelector uint8 Enabled bool Source LanIPv6DynamicAddressSource IPv6 net.IP PrefixLength uint8 Status LanIPv6AddressStatus } func (param *LanConfigParam_IPv6DynamicAddress) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DynamicAddress, param.SetSelector, 0 } func (param *LanConfigParam_IPv6DynamicAddress) Pack() []byte { out := make([]byte, 20) out[0] = param.SetSelector var b1 uint8 b1 = setOrClearBit7(b1, param.Enabled) b1 |= uint8(param.Source) & 0x0f out[1] = b1 // 16-byte (IPv6) packBytes(param.IPv6, out, 2) out[18] = param.PrefixLength out[19] = byte(param.Status) return out } func (param *LanConfigParam_IPv6DynamicAddress) Unpack(data []byte) error { if len(data) < 20 { return ErrUnpackedDataTooShortWith(len(data), 20) } param.SetSelector = data[0] param.Enabled = isBit7Set(data[1]) param.Source = LanIPv6DynamicAddressSource(data[1] & 0x0f) param.IPv6 = net.IP(data[2:18]) param.PrefixLength = data[18] param.Status = LanIPv6AddressStatus(data[19]) return nil } func (param *LanConfigParam_IPv6DynamicAddress) Format() string { return fmt.Sprintf("%d, Enabled: %v, Source: %d, IPv6: %s, PrefixLength: %d, Status: %s", param.SetSelector, param.Enabled, param.Source, param.IPv6, param.PrefixLength, param.Status) } type LanConfigParam_IPv6DHCPv6DynamicDUIDCount struct { // The maximum number of 16-byte blocks that can be used for storing each DUID via // the IPv6 DHCPv6 Static DUIDs parameter. 1-based. Returns 0 if IPv6 Static Address // configuration is not supported. Max uint8 } func (param *LanConfigParam_IPv6DHCPv6DynamicDUIDCount) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DHCPv6DynamicDUIDCount, 0, 0 } func (param *LanConfigParam_IPv6DHCPv6DynamicDUIDCount) Pack() []byte { out := make([]byte, 1) out[0] = param.Max return out } func (param *LanConfigParam_IPv6DHCPv6DynamicDUIDCount) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Max = data[0] return nil } func (param *LanConfigParam_IPv6DHCPv6DynamicDUIDCount) Format() string { return fmt.Sprintf("%d", param.Max) } type LanConfigParam_IPv6DHCPv6DynamicDUID struct { SetSelector uint8 BlockSelector uint8 DUID [16]byte } func (param *LanConfigParam_IPv6DHCPv6DynamicDUID) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DHCPv6DynamicDUID, param.SetSelector, param.BlockSelector } func (param *LanConfigParam_IPv6DHCPv6DynamicDUID) Pack() []byte { out := make([]byte, 18) out[0] = param.SetSelector out[1] = param.BlockSelector copy(out[2:], param.DUID[:]) return out } func (param *LanConfigParam_IPv6DHCPv6DynamicDUID) Unpack(data []byte) error { if len(data) < 18 { return ErrUnpackedDataTooShortWith(len(data), 18) } param.SetSelector = data[0] param.BlockSelector = data[1] copy(param.DUID[:], data[2:18]) return nil } func (param *LanConfigParam_IPv6DHCPv6DynamicDUID) Format() string { return fmt.Sprintf("%d, %d, %x", param.SetSelector, param.BlockSelector, param.DUID) } type LanConfigParam_IPv6DHCPv6TimingConfigSupport struct { Mode LanIPv6DHCPv6TimingConfigMode } func (param *LanConfigParam_IPv6DHCPv6TimingConfigSupport) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DHCPv6TimingConfigSupport, 0, 0 } func (param *LanConfigParam_IPv6DHCPv6TimingConfigSupport) Pack() []byte { out := make([]byte, 1) out[0] = byte(param.Mode) return out } func (param *LanConfigParam_IPv6DHCPv6TimingConfigSupport) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Mode = LanIPv6DHCPv6TimingConfigMode(data[0]) return nil } func (param *LanConfigParam_IPv6DHCPv6TimingConfigSupport) Format() string { return fmt.Sprintf("%s (%d)", param.Mode.String(), param.Mode) } type LanConfigParam_IPv6DHCPv6TimingConfig struct { SetSelector uint8 BlockSelector uint8 } func (param *LanConfigParam_IPv6DHCPv6TimingConfig) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DHCPv6TimingConfig, param.SetSelector, param.BlockSelector } func (param *LanConfigParam_IPv6DHCPv6TimingConfig) Pack() []byte { out := make([]byte, 2) out[0] = param.SetSelector out[1] = param.BlockSelector return out } func (param *LanConfigParam_IPv6DHCPv6TimingConfig) Unpack(data []byte) error { if len(data) < 2 { return ErrUnpackedDataTooShortWith(len(data), 2) } param.SetSelector = data[0] param.BlockSelector = data[1] return nil } func (param *LanConfigParam_IPv6DHCPv6TimingConfig) Format() string { return fmt.Sprintf("%d, %d", param.SetSelector, param.BlockSelector) } type LanConfigParam_IPv6RouterAddressConfigControl struct { // enable dynamic router address configuration via router advertisement messages. EnableDynamic bool // enable static router address EnableStatic bool } func (param *LanConfigParam_IPv6RouterAddressConfigControl) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6RouterAddressConfigControl, 0, 0 } func (param *LanConfigParam_IPv6RouterAddressConfigControl) Pack() []byte { out := make([]byte, 1) var b uint8 b = setOrClearBit1(b, param.EnableDynamic) b = setOrClearBit0(b, param.EnableStatic) out[0] = b return out } func (param *LanConfigParam_IPv6RouterAddressConfigControl) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.EnableDynamic = isBit1Set(data[0]) param.EnableStatic = isBit0Set(data[0]) return nil } func (param *LanConfigParam_IPv6RouterAddressConfigControl) Format() string { return fmt.Sprintf("dynamic: %s, static: %s", formatBool(param.EnableDynamic, "enabled", "disabled"), formatBool(param.EnableStatic, "enabled", "disabled"), ) } type LanConfigParam_IPv6StaticRouter1IP struct { IPv6 net.IP } func (param *LanConfigParam_IPv6StaticRouter1IP) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticRouter1IP, 0, 0 } func (param *LanConfigParam_IPv6StaticRouter1IP) Pack() []byte { out := make([]byte, 16) copy(out, param.IPv6) return out } func (param *LanConfigParam_IPv6StaticRouter1IP) Unpack(data []byte) error { if len(data) < 16 { return ErrUnpackedDataTooShortWith(len(data), 16) } param.IPv6 = data return nil } func (param *LanConfigParam_IPv6StaticRouter1IP) Format() string { return param.IPv6.String() } type LanConfigParam_IPv6StaticRouter1MAC struct { MAC net.HardwareAddr } func (param *LanConfigParam_IPv6StaticRouter1MAC) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticRouter1MAC, 0, 0 } func (param *LanConfigParam_IPv6StaticRouter1MAC) Pack() []byte { out := make([]byte, 6) copy(out, param.MAC) return out } func (param *LanConfigParam_IPv6StaticRouter1MAC) Unpack(data []byte) error { if len(data) < 6 { return ErrUnpackedDataTooShortWith(len(data), 6) } param.MAC = data return nil } func (param *LanConfigParam_IPv6StaticRouter1MAC) Format() string { return param.MAC.String() } type LanConfigParam_IPv6StaticRouter1PrefixLength struct { PrefixLength uint8 } func (param *LanConfigParam_IPv6StaticRouter1PrefixLength) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticRouter1PrefixLength, 0, 0 } func (param *LanConfigParam_IPv6StaticRouter1PrefixLength) Pack() []byte { out := make([]byte, 1) out[0] = param.PrefixLength return out } func (param *LanConfigParam_IPv6StaticRouter1PrefixLength) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.PrefixLength = data[0] return nil } func (param *LanConfigParam_IPv6StaticRouter1PrefixLength) Format() string { return fmt.Sprintf("%d", param.PrefixLength) } type LanConfigParam_IPv6StaticRouter1PrefixValue struct { PrefixValue [16]byte } func (param *LanConfigParam_IPv6StaticRouter1PrefixValue) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticRouter1PrefixValue, 0, 0 } func (param *LanConfigParam_IPv6StaticRouter1PrefixValue) Pack() []byte { out := make([]byte, 16) copy(out[0:], param.PrefixValue[:]) return out } func (param *LanConfigParam_IPv6StaticRouter1PrefixValue) Unpack(data []byte) error { if len(data) < 16 { return ErrUnpackedDataTooShortWith(len(data), 16) } copy(param.PrefixValue[:], data[0:]) return nil } func (param *LanConfigParam_IPv6StaticRouter1PrefixValue) Format() string { return fmt.Sprintf("%s", param.PrefixValue) } type LanConfigParam_IPv6StaticRouter2IP struct { IPv6 net.IP } func (param *LanConfigParam_IPv6StaticRouter2IP) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticRouter2IP, 0, 0 } func (param *LanConfigParam_IPv6StaticRouter2IP) Pack() []byte { out := make([]byte, 16) copy(out, param.IPv6) return out } func (param *LanConfigParam_IPv6StaticRouter2IP) Unpack(data []byte) error { if len(data) < 16 { return ErrUnpackedDataTooShortWith(len(data), 16) } param.IPv6 = data return nil } func (param *LanConfigParam_IPv6StaticRouter2IP) Format() string { return param.IPv6.String() } type LanConfigParam_IPv6StaticRouter2MAC struct { MAC net.HardwareAddr } func (param *LanConfigParam_IPv6StaticRouter2MAC) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticRouter2MAC, 0, 0 } func (param *LanConfigParam_IPv6StaticRouter2MAC) Pack() []byte { out := make([]byte, 6) copy(out, param.MAC) return out } func (param *LanConfigParam_IPv6StaticRouter2MAC) Unpack(data []byte) error { if len(data) < 6 { return ErrUnpackedDataTooShortWith(len(data), 6) } param.MAC = data return nil } func (param *LanConfigParam_IPv6StaticRouter2MAC) Format() string { return param.MAC.String() } type LanConfigParam_IPv6StaticRouter2PrefixLength struct { PrefixLength uint8 } func (param *LanConfigParam_IPv6StaticRouter2PrefixLength) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticRouter2PrefixLength, 0, 0 } func (param *LanConfigParam_IPv6StaticRouter2PrefixLength) Pack() []byte { out := make([]byte, 1) out[0] = param.PrefixLength return out } func (param *LanConfigParam_IPv6StaticRouter2PrefixLength) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.PrefixLength = data[0] return nil } func (param *LanConfigParam_IPv6StaticRouter2PrefixLength) Format() string { return fmt.Sprintf("%d", param.PrefixLength) } type LanConfigParam_IPv6StaticRouter2PrefixValue struct { PrefixValue [16]byte } func (param *LanConfigParam_IPv6StaticRouter2PrefixValue) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6StaticRouter2PrefixValue, 0, 0 } func (param *LanConfigParam_IPv6StaticRouter2PrefixValue) Pack() []byte { out := make([]byte, 16) copy(out[0:], param.PrefixValue[:]) return out } func (param *LanConfigParam_IPv6StaticRouter2PrefixValue) Unpack(data []byte) error { if len(data) < 16 { return ErrUnpackedDataTooShortWith(len(data), 16) } copy(param.PrefixValue[:], data[0:]) return nil } func (param *LanConfigParam_IPv6StaticRouter2PrefixValue) Format() string { return fmt.Sprintf("%s", param.PrefixValue) } type LanConfigParam_IPv6DynamicRouterInfoSets struct { // Number of dynamic Router Address information entries Count uint8 } func (param *LanConfigParam_IPv6DynamicRouterInfoSets) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DynamicRouterInfoCount, 0, 0 } func (param *LanConfigParam_IPv6DynamicRouterInfoSets) Pack() []byte { out := make([]byte, 1) out[0] = param.Count return out } func (param *LanConfigParam_IPv6DynamicRouterInfoSets) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Count = data[0] return nil } func (param *LanConfigParam_IPv6DynamicRouterInfoSets) Format() string { return fmt.Sprintf("%d", param.Count) } type LanConfigParam_IPv6DynamicRouterInfoIP struct { SetSelector uint8 IPv6 net.IP } func (param *LanConfigParam_IPv6DynamicRouterInfoIP) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DynamicRouterInfoIP, param.SetSelector, 0 } func (param *LanConfigParam_IPv6DynamicRouterInfoIP) Pack() []byte { out := make([]byte, 17) out[0] = param.SetSelector copy(out[1:], param.IPv6) return out } func (param *LanConfigParam_IPv6DynamicRouterInfoIP) Unpack(data []byte) error { if len(data) < 17 { return ErrUnpackedDataTooShortWith(len(data), 17) } param.SetSelector = data[0] param.IPv6 = data[1:] return nil } func (param *LanConfigParam_IPv6DynamicRouterInfoIP) Format() string { return fmt.Sprintf("%d, %s", param.SetSelector, param.IPv6) } type LanConfigParam_IPv6DynamicRouterInfoMAC struct { SetSelector uint8 MAC net.HardwareAddr } func (param *LanConfigParam_IPv6DynamicRouterInfoMAC) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DynamicRouterInfoMAC, param.SetSelector, 0 } func (param *LanConfigParam_IPv6DynamicRouterInfoMAC) Pack() []byte { out := make([]byte, 7) out[0] = param.SetSelector copy(out[1:], param.MAC) return out } func (param *LanConfigParam_IPv6DynamicRouterInfoMAC) Unpack(data []byte) error { if len(data) < 7 { return ErrUnpackedDataTooShortWith(len(data), 7) } param.SetSelector = data[0] param.MAC = data[1:] return nil } func (param *LanConfigParam_IPv6DynamicRouterInfoMAC) Format() string { return fmt.Sprintf("%d, %s", param.SetSelector, param.MAC) } type LanConfigParam_IPv6DynamicRouterInfoPrefixLength struct { SetSelector uint8 PrefixLength uint8 } func (param *LanConfigParam_IPv6DynamicRouterInfoPrefixLength) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DynamicRouterInfoPrefixLength, param.SetSelector, 0 } func (param *LanConfigParam_IPv6DynamicRouterInfoPrefixLength) Pack() []byte { out := make([]byte, 2) out[0] = param.SetSelector out[1] = param.PrefixLength return out } func (param *LanConfigParam_IPv6DynamicRouterInfoPrefixLength) Unpack(data []byte) error { if len(data) < 2 { return ErrUnpackedDataTooShortWith(len(data), 2) } param.SetSelector = data[0] param.PrefixLength = data[1] return nil } func (param *LanConfigParam_IPv6DynamicRouterInfoPrefixLength) Format() string { return fmt.Sprintf("%d, %d", param.SetSelector, param.PrefixLength) } type LanConfigParam_IPv6DynamicRouterInfoPrefixValue struct { SetSelector uint8 PrefixValue [16]byte } func (param *LanConfigParam_IPv6DynamicRouterInfoPrefixValue) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DynamicRouterInfoPrefixValue, param.SetSelector, 0 } func (param *LanConfigParam_IPv6DynamicRouterInfoPrefixValue) Pack() []byte { out := make([]byte, 17) out[0] = param.SetSelector copy(out[1:], param.PrefixValue[:]) return out } func (param *LanConfigParam_IPv6DynamicRouterInfoPrefixValue) Unpack(data []byte) error { if len(data) < 17 { return ErrUnpackedDataTooShortWith(len(data), 17) } param.SetSelector = data[0] copy(param.PrefixValue[:], data[1:]) return nil } func (param *LanConfigParam_IPv6DynamicRouterInfoPrefixValue) Format() string { return fmt.Sprintf("%d, %s", param.SetSelector, param.PrefixValue) } type LanConfigParam_IPv6DynamicRouterReceivedHopLimit struct { HopLimit uint8 } func (param *LanConfigParam_IPv6DynamicRouterReceivedHopLimit) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6DynamicRouterReceivedHopLimit, 0, 0 } func (param *LanConfigParam_IPv6DynamicRouterReceivedHopLimit) Pack() []byte { out := make([]byte, 1) out[0] = param.HopLimit return out } func (param *LanConfigParam_IPv6DynamicRouterReceivedHopLimit) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.HopLimit = data[0] return nil } func (param *LanConfigParam_IPv6DynamicRouterReceivedHopLimit) Format() string { return fmt.Sprintf("%d", param.HopLimit) } type LanConfigParam_IPv6NDSLAACTimingConfigSupport struct { Mode LanIPv6NDSLAACTimingConfigMode } func (param *LanConfigParam_IPv6NDSLAACTimingConfigSupport) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6NDSLAACTimingConfigSupport, 0, 0 } func (param *LanConfigParam_IPv6NDSLAACTimingConfigSupport) Pack() []byte { out := make([]byte, 1) out[0] = byte(param.Mode) return out } func (param *LanConfigParam_IPv6NDSLAACTimingConfigSupport) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Mode = LanIPv6NDSLAACTimingConfigMode(data[0]) return nil } func (param *LanConfigParam_IPv6NDSLAACTimingConfigSupport) Format() string { return fmt.Sprintf("%s (%d)", param.Mode.String(), param.Mode) } type LanConfigParam_IPv6NDSLAACTimingConfig struct { SetSelector uint8 BlockSelector uint8 } func (param *LanConfigParam_IPv6NDSLAACTimingConfig) LanConfigParameter() (paramSelector LanConfigParamSelector, setSelector uint8, blockSelector uint8) { return LanConfigParamSelector_IPv6NDSLAACTimingConfig, param.SetSelector, param.BlockSelector } func (param *LanConfigParam_IPv6NDSLAACTimingConfig) Pack() []byte { out := make([]byte, 2) out[0] = param.SetSelector out[1] = param.BlockSelector return out } func (param *LanConfigParam_IPv6NDSLAACTimingConfig) Unpack(data []byte) error { if len(data) < 2 { return ErrUnpackedDataTooShortWith(len(data), 2) } param.SetSelector = data[0] param.BlockSelector = data[1] return nil } func (param *LanConfigParam_IPv6NDSLAACTimingConfig) Format() string { return fmt.Sprintf("%d, %d", param.SetSelector, param.BlockSelector) } golang-github-bougou-go-ipmi-0.7.2/types_netfn.go000066400000000000000000000025511474110527100217760ustar00rootroot00000000000000package ipmi // NetFn is Network Function type NetFn uint8 // Network Function Codes, section 5.1 Table 5 // Even NetFn values are used for requests to the BMC, // and odd NetFn values are returned in responses from the BMC. // // six-bit field identifying the function, so total 64 NetFn (32 NetFn pairs) const ( NetFnChassisRequest NetFn = 0x00 NetFnChassisResponse NetFn = 0x01 NetFnBridgeRequest NetFn = 0x02 NetFnBridgeResponse NetFn = 0x03 NetFnSensorEventRequest NetFn = 0x04 NetFnSensorEventResponse NetFn = 0x05 NetFnAppRequest NetFn = 0x06 NetFnAppResponse NetFn = 0x07 NetFnFirmwareRequest NetFn = 0x08 NetFnFirmwareResponse NetFn = 0x09 NetFnStorageRequest NetFn = 0x0a NetFnStorageResponse NetFn = 0x0b NetFnTransportRequest NetFn = 0x0c NetFnTransportResponse NetFn = 0x0d // Reserved 0E - 2B NetFnGroupExtensionRequest NetFn = 0x2c NetFnGroupExtensionResponse NetFn = 0x2d NetFnOEMGroupRequest NetFn = 0x2e NetFnOEMGroupResponse NetFn = 0x2f // 30h-3Fh controller specific // Vendor specific (16 Network Functions [8 pairs]). NetFnOEMSupermicroRequest NetFn = 0x30 ) // Group Extensions const ( // Intel DCMI extensions (https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/dcmi-v1-5-rev-spec.pdf) GroupExtensionDCMI uint8 = 0xDC ) golang-github-bougou-go-ipmi-0.7.2/types_oem.go000066400000000000000000000065461474110527100214540ustar00rootroot00000000000000package ipmi // OEM represents Manufacturer ID, that is IANA Private Enterprise Number type OEM uint32 // cSpell: disable const ( OEM_UNKNOWN = 0 OEM_DEBUG = 0xFFFFFE /* Hoping IANA won't hit this soon */ OEM_RESERVED = 0x0FFFFF /* As per IPMI 2.0 specification */ OEM_IBM_2 = 2 /* 2 for [IBM] */ OEM_HP = 11 OEM_SUN = 42 OEM_NOKIA = 94 OEM_BULL = 107 OEM_HITACHI_116 = 116 OEM_NEC = 119 OEM_TOSHIBA = 186 OEM_ERICSSON = 193 OEM_INTEL = 343 OEM_TATUNG = 373 OEM_HITACHI_399 = 399 OEM_DELL = 674 OEM_HUAWEI = 2011 OEM_LMC = 2168 OEM_RADISYS = 4337 OEM_BROADCOM = 4413 OEM_IBM_4769 = 4769 /* 4769 for [IBM Corporation] */ OEM_MAGNUM = 5593 OEM_TYAN = 6653 OEM_QUANTA = 7244 OEM_VIKING = 9237 OEM_ADVANTECH = 10297 OEM_FUJITSU_SIEMENS = 10368 OEM_AVOCENT = 10418 OEM_PEPPERCON = 10437 OEM_SUPERMICRO = 10876 OEM_OSA = 11102 OEM_GOOGLE = 11129 OEM_PICMG = 12634 OEM_RARITAN = 13742 OEM_KONTRON = 15000 OEM_PPS = 16394 OEM_IBM_20301 = 20301 /* 20301 for [IBM eServer X] */ OEM_AMI = 20974 OEM_FOXCONN = 22238 OEM_ADLINK_24339 = 24339 /* 24339 for [ADLINK TECHNOLOGY INC.] */ OEM_H3C = 25506 OEM_NOKIA_SOLUTIONS_AND_NETWORKS = 28458 OEM_VITA = 33196 OEM_INSPUR = 37945 OEM_TENCENT = 41475 OEM_BYTEDANCE = 46045 OEM_SUPERMICRO_47488 = 47488 OEM_YADRO = 49769 ) func (oem OEM) String() string { m := map[OEM]string{ 2: "IBM", 11: "HP", 42: "Sun", 94: "Nokia", 107: "Bull", 116: "Hitachi", 119: "NEC", 186: "Toshiba", 193: "Ericsson", 343: "Intel", 373: "Tatung", // 大同 399: "Hitachi", 674: "Dell", 2011: "Huawei", 2168: "LMC", 4337: "Radisys", 4413: "Broadcom", 4769: "IBM", 5593: "Magnum", // 迈格纳技术集成公司 6653: "Tyan", // 泰安 7244: "Quanta", 9237: "Viking", 10297: "Advantech", // 研华科技 10368: "Fujitsu", 10418: "Avocent", 10437: "Peppercon", 10876: "Supermicro", 11102: "OSA", 11129: "Google", 12634: "PICMG", 13742: "Raritan", // 力登 15000: "Kontron", // 控创 16394: "PPS", 20301: "IBM", 20974: "AMI", 22238: "Foxconn", 24339: "ADLINK", // 凌华 25506: "H3C", 28458: "Nokia", 33196: "Vita", // 维塔 37945: "Inspur", // 浪潮 41475: "Tencent", // 腾讯 46045: "ByteDance", // 字节跳动 47488: "Supermicro", 49769: "Yadro", } if s, ok := m[oem]; ok { return s } return "Unknown" } golang-github-bougou-go-ipmi-0.7.2/types_payload.go000066400000000000000000000066651474110527100223270ustar00rootroot00000000000000package ipmi // 13.27.3 // The Get Channel Payload Support command returns which standard payload type numbers and OEM payload // type handles are available on a given channel of a BMC. type PayloadType uint8 const ( // Standard Payload Types // used to identify payloads that are specified by the IPMI specifications PayloadTypeIPMI PayloadType = 0x00 PayloadTypeSOL PayloadType = 0x01 PayloadTypeOEM PayloadType = 0x02 // Session Setup Payload Types // used to identify payloads that are for session setup messages specified by the IPMI specifications PayloadTypeRmcpOpenSessionRequest PayloadType = 0x10 PayloadTypeRmcpOpenSessionResponse PayloadType = 0x11 PayloadTypeRAKPMessage1 PayloadType = 0x12 PayloadTypeRAKPMessage2 PayloadType = 0x13 PayloadTypeRAKPMessage3 PayloadType = 0x14 PayloadTypeRAKPMessage4 PayloadType = 0x15 // OEM Payload Type Handles // used to identify payloads that are specified by a given OEM PayloadTypeOEM0 PayloadType = 0x20 PayloadTypeOEM1 PayloadType = 0x21 PayloadTypeOEM2 PayloadType = 0x22 PayloadTypeOEM3 PayloadType = 0x23 PayloadTypeOEM4 PayloadType = 0x24 PayloadTypeOEM5 PayloadType = 0x25 PayloadTypeOEM6 PayloadType = 0x26 PayloadTypeOEM7 PayloadType = 0x27 ) func (pt PayloadType) String() string { m := map[PayloadType]string{ 0x00: "ipmi", 0x01: "sol", 0x02: "oem", 0x10: "rmcp-open-session-request", 0x11: "rmcp-open-session-response", 0x12: "rakp-message-1", 0x13: "rakp-message-2", 0x14: "rakp-message-3", 0x15: "rakp-message-4", 0x20: "oem0", 0x21: "oem1", 0x22: "oem2", 0x23: "oem3", 0x24: "oem4", 0x25: "oem5", 0x26: "oem6", 0x27: "oem7", } s, ok := m[pt] if ok { return s } return "reserved" } // 13.28 type AuthAlg uint8 const ( AuthAlgRAKP_None AuthAlg = 0x00 // Mandatory AuthAlgRAKP_HMAC_SHA1 AuthAlg = 0x01 // Mandatory AuthAlgRAKP_HMAC_MD5 AuthAlg = 0x02 // Optional AuthAlgRAKP_HMAC_SHA256 AuthAlg = 0x03 // Optional ) func (authAlg AuthAlg) String() string { m := map[AuthAlg]string{ 0x00: "none", 0x01: "hmac_sha1", 0x02: "hmac_md5", 0x03: "hmac_sha256", } s, ok := m[authAlg] if ok { return s } return "" } // 13.28.4 type IntegrityAlg uint8 const ( IntegrityAlg_None IntegrityAlg = 0x00 // Mandatory IntegrityAlg_HMAC_SHA1_96 IntegrityAlg = 0x01 // Mandatory IntegrityAlg_HMAC_MD5_128 IntegrityAlg = 0x02 // Optional IntegrityAlg_MD5_128 IntegrityAlg = 0x03 // Optional IntegrityAlg_HMAC_SHA256_128 IntegrityAlg = 0x04 // Optional ) func (integrityAlg IntegrityAlg) String() string { m := map[IntegrityAlg]string{ 0x00: "none", 0x01: "hmac_sha1_96", 0x02: "hmac_md5_128", 0x03: "md5_128", 0x04: "hmac_sha256_128", } s, ok := m[integrityAlg] if ok { return s } return "" } // 13.28.5 // Confidentiality (Encryption) Algorithms // AES is more secure than RC4 // RC4 is cryptographically broken and should not be used for secure applications. type CryptAlg uint8 const ( CryptAlg_None CryptAlg = 0x00 // Mandatory CryptAlg_AES_CBC_128 CryptAlg = 0x01 // Mandatory CryptAlg_xRC4_128 CryptAlg = 0x02 // Optional CryptAlg_xRC4_40 CryptAlg = 0x03 // Optional Encryption_AES_CBS_128_BlockSize uint8 = 0x10 ) func (cryptAlg CryptAlg) String() string { m := map[CryptAlg]string{ 0x00: "none", 0x01: "aes_cbc_128", 0x02: "xrc4_128", 0x03: "xrc4_40", } s, ok := m[cryptAlg] if ok { return s } return "" } golang-github-bougou-go-ipmi-0.7.2/types_pef.go000066400000000000000000000406061474110527100214410ustar00rootroot00000000000000package ipmi import ( "bytes" "fmt" "strconv" "strings" "github.com/olekukonko/tablewriter" ) // 17.7 Event Filter Table type PEFEventFilter struct { // Filter Configuration // // FilterState (enabled or disabled) // [4:0] - reserved // // [7] - 1b = enable filter // 0b = disable filter FilterState bool // [6:5] - 11b = reserved // 10b = manufacturer pre-configured filter. The filter entry has been // configured by the system integrator and should not be altered by software. // Software is allowed to enable or disable the filter, however. // 01b = reserved // 00b = software configurable filter. The filter entry is available for // configuration by system management software. FilterType PEFEventFilterType // 17.6 PEF Actions // All actions are optional for an implementation, with the exception of Alert // which is mandatory if alerting is supported for one or more channels. // The BMC will return 0b for unsupported actions. // Software can test for which actions are supported by writing 1's to the // specified fields and reading back the result. // (Note that reserved bits must be written with 0's) ActionGroupControlOperation bool ActionDiagnosticInterrupt bool ActionOEM bool ActionPowerCycle bool ActionReset bool ActionPowerOff bool // Either Event filter Action should be enabled or Power action should be present as channel alert is enabled. ActionAlert bool // Relates with AlertPolicyNumber // Used to select an alerting policy set from the Alert Policy Table. // The Alert Policy Table holds different policies that configure the order in which different alert destinations and alerting media are tried. // [6:4] - group control selector (1-based). Selects entry from group control table. (see [ICMB) GroupControlSelector uint8 // [3:0] - policy number. Value is "don't care" if (ActionAlert=false) Alert is not selected in the Event Filter Action. AlertPolicyNumber uint8 EventSeverity PEFEventSeverity GeneratorID GeneratorID SensorType SensorType SensorNumber SensorNumber EventReadingType EventReadingType EventData1EventOffsetMask uint16 EventData1ANDMask uint8 // Used to indicate whether each bit position's comparison is an exact comparison or not. EventData1Compare1 uint8 EventData1Compare2 uint8 EventData2ANDMask uint8 EventData2Compare1 uint8 EventData2Compare2 uint8 EventData3ANDMask uint8 EventData3Compare1 uint8 EventData3Compare2 uint8 } func (entry *PEFEventFilter) enabledActions() []string { out := make([]string, 0) if entry.ActionGroupControlOperation { out = append(out, "Group Control Operation") } if entry.ActionDiagnosticInterrupt { out = append(out, "DiagnosticInterrupt") } if entry.ActionOEM { out = append(out, "OEM-defined") } if entry.ActionPowerCycle { out = append(out, "PowerCycle") } if entry.ActionReset { out = append(out, "Reset") } if entry.ActionPowerOff { out = append(out, "PowerOff") } if entry.ActionAlert { out = append(out, "Alert") } return out } func (entry *PEFEventFilter) Unpack(data []byte) error { if len(data) < 20 { return ErrUnpackedDataTooShortWith(len(data), 20) } var b byte b = data[0] entry.FilterState = isBit7Set(b) entry.FilterType = PEFEventFilterType((b >> 5) & 0x03) b = data[1] entry.ActionGroupControlOperation = isBit6Set(b) entry.ActionDiagnosticInterrupt = isBit5Set(b) entry.ActionOEM = isBit4Set(b) entry.ActionPowerCycle = isBit3Set(b) entry.ActionReset = isBit2Set(b) entry.ActionPowerOff = isBit1Set(b) entry.ActionAlert = isBit0Set(b) b = data[2] entry.GroupControlSelector = (b >> 4) & 0x07 entry.AlertPolicyNumber = b & 0x0f entry.EventSeverity = PEFEventSeverity(data[3]) generatorID, _, _ := unpackUint16L(data, 4) entry.GeneratorID = GeneratorID(generatorID) entry.SensorType = SensorType(data[6]) entry.SensorNumber = SensorNumber(data[7]) entry.EventReadingType = EventReadingType(data[8]) eventData1, _, _ := unpackUint16L(data, 9) entry.EventData1EventOffsetMask = eventData1 entry.EventData1ANDMask = data[11] entry.EventData1Compare1 = data[12] entry.EventData1Compare2 = data[13] entry.EventData2ANDMask = data[14] entry.EventData2Compare1 = data[15] entry.EventData2Compare2 = data[16] entry.EventData3ANDMask = data[17] entry.EventData3Compare1 = data[18] entry.EventData3Compare2 = data[19] return nil } func (entry *PEFEventFilter) Pack() []byte { out := make([]byte, 20) var b byte b = uint8(entry.FilterType) << 5 b = setOrClearBit7(b, entry.FilterState) out[0] = b b = 0 b = setOrClearBit6(b, entry.ActionGroupControlOperation) b = setOrClearBit5(b, entry.ActionDiagnosticInterrupt) b = setOrClearBit4(b, entry.ActionOEM) b = setOrClearBit3(b, entry.ActionPowerCycle) b = setOrClearBit2(b, entry.ActionReset) b = setOrClearBit1(b, entry.ActionPowerOff) b = setOrClearBit0(b, entry.ActionAlert) out[1] = b b = uint8(entry.GroupControlSelector) << 4 b |= entry.AlertPolicyNumber & 0x0f out[2] = b out[3] = byte(entry.EventSeverity) packUint16L(uint16(entry.GeneratorID), out, 4) out[6] = byte(entry.SensorType) out[7] = byte(entry.SensorNumber) out[8] = byte(entry.EventReadingType) packUint16L(entry.EventData1EventOffsetMask, out, 9) out[11] = entry.EventData1ANDMask out[12] = entry.EventData1Compare1 out[13] = entry.EventData1Compare2 out[14] = entry.EventData2ANDMask out[15] = entry.EventData2Compare1 out[16] = entry.EventData2Compare2 out[17] = entry.EventData3ANDMask out[18] = entry.EventData3Compare1 out[19] = entry.EventData3Compare2 return out } func (entry *PEFEventFilter) Format() string { return fmt.Sprintf(` FilterType: %v FilterState: %v ActionGroupControlOperation: %v ActionDiagnosticInterrupt: %v ActionOEM: %v ActionPowerCycle: %v ActionReset: %v ActionPowerOff: %v ActionAlert: %v GroupControlSelector: %v AlertPolicyNumber: %v EventSeverity: %v GeneratorID: %v SensorType: %v SensorNumber: %v EventReadingType: %v EventData1EventOffsetMask: %v EventData1ANDMask: %v EventData1Compare1: %v EventData1Compare2: %v EventData2ANDMask: %v EventData2Compare1: %v EventData2Compare2: %v EventData3ANDMask: %v EventData3Compare1: %v EventData3Compare2: %v `, PEFEventFilterType(entry.FilterType), entry.FilterState, entry.ActionGroupControlOperation, entry.ActionDiagnosticInterrupt, entry.ActionOEM, entry.ActionPowerCycle, entry.ActionReset, entry.ActionPowerOff, entry.ActionAlert, entry.GroupControlSelector, entry.AlertPolicyNumber, PEFEventSeverity(entry.EventSeverity), GeneratorID(entry.GeneratorID), SensorType(entry.SensorType), SensorNumber(entry.SensorNumber), EventReadingType(entry.EventReadingType), entry.EventData1EventOffsetMask, entry.EventData1ANDMask, entry.EventData1Compare1, entry.EventData1Compare2, entry.EventData2ANDMask, entry.EventData2Compare1, entry.EventData2Compare2, entry.EventData3ANDMask, entry.EventData3Compare1, entry.EventData3Compare2) } func FormatEventFilters(eventFilters []*PEFEventFilter) string { var buf = new(bytes.Buffer) table := tablewriter.NewWriter(buf) var headers []string // the first faked item was used to make sure headers are always generated for i, f := range append([]*PEFEventFilter{{}}, eventFilters...) { content := [][2]string{ {"Filter State", formatBool(f.FilterState, "enabled", "disabled")}, {"Filter Type", f.FilterType.String()}, {"Actions", strings.Join(f.enabledActions(), ",")}, {"Group Control Selector", fmt.Sprintf("%v", f.GroupControlSelector)}, {"Alert Policy Number", fmt.Sprintf("%v", f.AlertPolicyNumber)}, {"Event Severity", fmt.Sprintf("%v", f.EventSeverity)}, {"Generator ID", fmt.Sprintf("%v", f.GeneratorID)}, {"Sensor Type", fmt.Sprintf("%v", f.SensorType)}, {"Sensor Number", fmt.Sprintf("%#02x", f.SensorNumber)}, {"Event Reading Type", fmt.Sprintf("%v", f.EventReadingType)}, {"ED1 Event Offset Mask", fmt.Sprintf("%v", f.EventData1EventOffsetMask)}, // {"ED1 AND Mask", fmt.Sprintf("%v", f.EventData1ANDMask)}, // {"ED1 Compare 1", fmt.Sprintf("%v", f.EventData1Compare1)}, // {"ED1 Compare 2", fmt.Sprintf("%v", f.EventData1Compare2)}, // {"ED2 AND Mask", fmt.Sprintf("%v", f.EventData2ANDMask)}, // {"ED2 Compare 1", fmt.Sprintf("%v", f.EventData2Compare1)}, // {"ED2 Compare 2", fmt.Sprintf("%v", f.EventData2Compare2)}, // {"ED3 AND Mask", fmt.Sprintf("%v", f.EventData3ANDMask)}, // {"ED3 Compare 1", fmt.Sprintf("%v", f.EventData3Compare1)}, // {"ED3 Compare 2", fmt.Sprintf("%v", f.EventData3Compare2)}, } if i == 0 { headers = make([]string, len(content)) for j, c := range content { headers[j] = c[0] } } else { row := make([]string, len(content)) for j, c := range content { row[j] = c[1] } table.Append(row) } } table.SetHeader(headers) table.SetFooter(headers) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) table.Render() return buf.String() } // PEFEventFilterType: // - manufacturer pre-configured filter. // The filter entry has been configured by the system integrator and // should not be altered by software. Software is allowed to enable or // disable the filter, however. // - software configurable filter. // The filter entry is available for configuration by system management software. type PEFEventFilterType uint8 const ( PEFEventFilterType_Configurable PEFEventFilterType = 0x00 PEFEventFilterType_PreConfigured PEFEventFilterType = 0x10 ) func (filterType PEFEventFilterType) String() string { m := map[PEFEventFilterType]string{ PEFEventFilterType_Configurable: "Configurable", PEFEventFilterType_PreConfigured: "Pre-Configured", } s, ok := m[filterType] if ok { return s } return fmt.Sprintf("%#02x", filterType) } type PEFEventSeverity uint8 const ( PEFEventSeverityUnspecified PEFEventSeverity = 0x00 PEFEventSeverityMonitor PEFEventSeverity = 0x01 PEFEventSeverityInformation PEFEventSeverity = 0x02 PEFEventSeverityOK PEFEventSeverity = 0x04 PEFEventSeverityNonCritical PEFEventSeverity = 0x08 // aka Warning PEFEventSeverityCritical PEFEventSeverity = 0x10 PEFEventSeverityNonRecoverable PEFEventSeverity = 0x20 ) func (severity PEFEventSeverity) String() string { m := map[PEFEventSeverity]string{ PEFEventSeverityUnspecified: "Unspecified", PEFEventSeverityMonitor: "Monitor", PEFEventSeverityInformation: "Information", PEFEventSeverityOK: "OK", PEFEventSeverityNonCritical: "Non-Critical", PEFEventSeverityCritical: "Critical", PEFEventSeverityNonRecoverable: "Non-Recoverable", } if s, ok := m[severity]; ok { return s } return "" } // 17.11 Alert Policy Table type PEFAlertPolicy struct { // [7:4] - policy number. 1 based. 0000b = reserved. PolicyNumber uint8 // PolicyState (enabled or disabled) // // [3] - 0b = this entry is disabled. Skip to next entry in policy, if any. // 1b = this entry is enabled. PolicyState bool // [2:0] - policy PolicyAction PEFAlertPolicyAction // [7:4] = ChannelNumber Number. ChannelNumber uint8 // [3:0] = Destination selector. Destination uint8 // [7] - Event-specific Alert String // 1b = Alert String look-up is event specific. The following Alert String Set / Selector sub- // field is interpreted as an Alert String Set Number that is used in conjunction with // the Event Filter Number to lookup the Alert String from the PEF Configuration Parameters. // 0b = Alert String is not event specific. The following Alert String Set / Selector sub-field // is interpreted as an Alert String Selector that provides a direct pointer to the // desired Alert String from the PEF Configuration Parameters. IsEventSpecific bool // [6:0] - Alert String Set / Selector. // This value identifies one or more Alert Strings in the Alert String table. // - When used as an Alert String Set Number (IsEventSpecific = true), it is used in conjunction with the Event Filter Number to uniquely identify an Alert String. // - When used as an Alert String Selector (IsEventSpecific = false), it directly selects an Alert String from the PEF Configuration Parameters. AlertStringKey uint8 } func (entry *PEFAlertPolicy) Pack() []byte { out := make([]byte, 3) var b uint8 b = uint8(entry.PolicyAction) & 0x07 b = setOrClearBit3(b, entry.PolicyState) b |= entry.PolicyNumber << 4 out[0] = b b = entry.Destination & 0x0F b |= entry.ChannelNumber << 4 out[1] = b b = entry.AlertStringKey & 0x7F b = setOrClearBit7(b, entry.IsEventSpecific) out[2] = b return out } func (entry *PEFAlertPolicy) Unpack(data []byte) error { if len(data) < 3 { return ErrUnpackedDataTooShortWith(len(data), 3) } entry.PolicyNumber = data[0] >> 4 entry.PolicyState = isBit3Set(data[0]) entry.PolicyAction = PEFAlertPolicyAction(data[0] & 0x07) entry.ChannelNumber = data[1] >> 4 entry.Destination = data[1] & 0x0F entry.IsEventSpecific = isBit7Set(data[2]) entry.AlertStringKey = data[2] & 0x7F return nil } func (entry *PEFAlertPolicy) Format() string { return fmt.Sprintf(` PolicyNumber : %d PolicyState : %v PolicyAction : %v Channel : %d Destination : %d IsEventSpecific : %v AlertStringKey : %d`, entry.PolicyNumber, entry.PolicyState, entry.PolicyAction, entry.ChannelNumber, entry.Destination, entry.IsEventSpecific, entry.AlertStringKey) } func FormatPEFAlertPolicyTable(alertPolicies []*PEFAlertPolicy) string { headers := []string{ "Entry", "PolicyNumber", "PolicyState", "PolicyAction", "Channel", "Destination", "IsEventSpecific", "AlertStringKey", } rows := make([][]string, len(alertPolicies)) for i, alertPolicy := range alertPolicies { rows[i] = []string{ strconv.Itoa(i + 1), fmt.Sprintf("%d", alertPolicy.PolicyNumber), fmt.Sprintf("%v", alertPolicy.PolicyState), alertPolicy.PolicyAction.ShortString(), fmt.Sprintf("%d", alertPolicy.ChannelNumber), fmt.Sprintf("%d", alertPolicy.Destination), fmt.Sprintf("%v", alertPolicy.IsEventSpecific), fmt.Sprintf("%d", alertPolicy.AlertStringKey), } } return formatTable(headers, rows) } type PEFAlertPolicyAction uint8 const ( // always send alert to this destination. PEFAlertPolicyAction_Always PEFAlertPolicyAction = 0 // if alert to previous destination was successful, do not send alert to this destination. // Proceed to next entry in this policy set. PEFAlertPolicyAction_ProceedNext PEFAlertPolicyAction = 1 // if alert to previous destination was successful, do not send alert to this destination. // Do not process any more entries in this policy set. PEFAlertPolicyAction_NoProceed PEFAlertPolicyAction = 2 // if alert to previous destination was successful, do not send alert to this destination. // Proceed to next entry in this policy set that is to a different channel. PEFAlertPolicyAction_ProceedNextDifferentChannel PEFAlertPolicyAction = 3 // if alert to previous destination was successful, do not send alert to this destination. // Proceed to next entry in this policy set that is to a different destination type. PEFAlertPolicyAction_ProceedNextDifferentDestination PEFAlertPolicyAction = 4 ) func (action PEFAlertPolicyAction) String() string { m := map[PEFAlertPolicyAction]string{ PEFAlertPolicyAction_Always: "Always send alert to this destination", PEFAlertPolicyAction_ProceedNext: "If previous successful, skip this and continue (if configured)", PEFAlertPolicyAction_NoProceed: "If previous successful, stop alerting further", PEFAlertPolicyAction_ProceedNextDifferentChannel: "If previous successful, switch to another channel (if configured)", PEFAlertPolicyAction_ProceedNextDifferentDestination: "If previous successful, switch to another destination (if configured)", } if s, ok := m[action]; ok { return s } return "Unknown" } func (action PEFAlertPolicyAction) ShortString() string { m := map[PEFAlertPolicyAction]string{ PEFAlertPolicyAction_Always: "Match-always", PEFAlertPolicyAction_ProceedNext: "Proceed-next", PEFAlertPolicyAction_NoProceed: "No-proceed", PEFAlertPolicyAction_ProceedNextDifferentChannel: "Different-channel", PEFAlertPolicyAction_ProceedNextDifferentDestination: "Different-destination", } if s, ok := m[action]; ok { return s } return "Unknown" } golang-github-bougou-go-ipmi-0.7.2/types_pef_params.go000066400000000000000000000673671474110527100230210ustar00rootroot00000000000000package ipmi import "fmt" type PEFConfigParamSelector uint8 const ( PEFConfigParamSelector_SetInProgress PEFConfigParamSelector = 0x00 PEFConfigParamSelector_Control PEFConfigParamSelector = 0x01 PEFConfigParamSelector_ActionGlobalControl PEFConfigParamSelector = 0x02 PEFConfigParamSelector_StartupDelay PEFConfigParamSelector = 0x03 PEFConfigParamSelector_AlertStartDelay PEFConfigParamSelector = 0x04 PEFConfigParamSelector_EventFiltersCount PEFConfigParamSelector = 0x05 PEFConfigParamSelector_EventFilter PEFConfigParamSelector = 0x06 PEFConfigParamSelector_EventFilterData1 PEFConfigParamSelector = 0x07 PEFConfigParamSelector_AlertPoliciesCount PEFConfigParamSelector = 0x08 PEFConfigParamSelector_AlertPolicy PEFConfigParamSelector = 0x09 PEFConfigParamSelector_SystemGUID PEFConfigParamSelector = 0x0a PEFConfigParamSelector_AlertStringsCount PEFConfigParamSelector = 0x0b PEFConfigParamSelector_AlertStringKey PEFConfigParamSelector = 0x0c PEFConfigParamSelector_AlertString PEFConfigParamSelector = 0x0d PEFConfigParamSelector_GroupControlsCount PEFConfigParamSelector = 0x0e PEFConfigParamSelector_GroupControl PEFConfigParamSelector = 0x0f // 96:127 // OEM Parameters (optional. Non-volatile or volatile as specified by OEM) // This range is available for special OEM configuration parameters. // The OEM is identified according to the Manufacturer ID field returned by the Get Device ID command. ) func (p PEFConfigParamSelector) String() string { m := map[PEFConfigParamSelector]string{ PEFConfigParamSelector_SetInProgress: "Set In Progress", PEFConfigParamSelector_Control: "Control", PEFConfigParamSelector_ActionGlobalControl: "Action Global Control", PEFConfigParamSelector_StartupDelay: "Startup Delay", PEFConfigParamSelector_AlertStartDelay: "Alert Start Delay", PEFConfigParamSelector_EventFiltersCount: "Event Filters Count", PEFConfigParamSelector_EventFilter: "Event Filter", PEFConfigParamSelector_EventFilterData1: "Event Filter Data1", PEFConfigParamSelector_AlertPoliciesCount: "Alert Policies Count", PEFConfigParamSelector_AlertPolicy: "Alert Policy", PEFConfigParamSelector_SystemGUID: "System GUID", PEFConfigParamSelector_AlertStringsCount: "Alert Strings Count", PEFConfigParamSelector_AlertStringKey: "Alert String Key", PEFConfigParamSelector_AlertString: "Alert String", PEFConfigParamSelector_GroupControlsCount: "Group Controls Count", PEFConfigParamSelector_GroupControl: "Group Control", } if s, ok := m[p]; ok { return s } return fmt.Sprintf("Unknown (%#02x)", p) } type PEFConfigParameter interface { PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) Parameter } var ( _ PEFConfigParameter = (*PEFConfigParam_SetInProgress)(nil) _ PEFConfigParameter = (*PEFConfigParam_Control)(nil) _ PEFConfigParameter = (*PEFConfigParam_ActionGlobalControl)(nil) _ PEFConfigParameter = (*PEFConfigParam_StartupDelay)(nil) _ PEFConfigParameter = (*PEFConfigParam_AlertStartupDelay)(nil) _ PEFConfigParameter = (*PEFConfigParam_EventFiltersCount)(nil) _ PEFConfigParameter = (*PEFConfigParam_EventFilter)(nil) _ PEFConfigParameter = (*PEFConfigParam_AlertPoliciesCount)(nil) _ PEFConfigParameter = (*PEFConfigParam_AlertPolicy)(nil) _ PEFConfigParameter = (*PEFConfigParam_SystemGUID)(nil) _ PEFConfigParameter = (*PEFConfigParam_AlertStringsCount)(nil) _ PEFConfigParameter = (*PEFConfigParam_AlertStringKey)(nil) _ PEFConfigParameter = (*PEFConfigParam_AlertString)(nil) _ PEFConfigParameter = (*PEFConfigParam_GroupControlsCount)(nil) _ PEFConfigParameter = (*PEFConfigParam_GroupControl)(nil) ) func isNilPEFConfigParameter(param PEFConfigParameter) bool { switch v := param.(type) { case *PEFConfigParam_SetInProgress: return v == nil case *PEFConfigParam_Control: return v == nil case *PEFConfigParam_ActionGlobalControl: return v == nil case *PEFConfigParam_StartupDelay: return v == nil case *PEFConfigParam_AlertStartupDelay: return v == nil case *PEFConfigParam_EventFiltersCount: return v == nil case *PEFConfigParam_EventFilter: return v == nil case *PEFConfigParam_AlertPoliciesCount: return v == nil case *PEFConfigParam_AlertPolicy: return v == nil case *PEFConfigParam_SystemGUID: return v == nil case *PEFConfigParam_AlertStringsCount: return v == nil case *PEFConfigParam_AlertStringKey: return v == nil case *PEFConfigParam_AlertString: return v == nil case *PEFConfigParam_GroupControlsCount: return v == nil case *PEFConfigParam_GroupControl: return v == nil default: return false } } type PEFConfigParams struct { SetInProgress *PEFConfigParam_SetInProgress Control *PEFConfigParam_Control ActionGlobalControl *PEFConfigParam_ActionGlobalControl StartupDelay *PEFConfigParam_StartupDelay AlertStartupDelay *PEFConfigParam_AlertStartupDelay EventFiltersCount *PEFConfigParam_EventFiltersCount EventFilters []*PEFConfigParam_EventFilter EventFiltersData1 []*PEFConfigParam_EventFilterData1 AlertPoliciesCount *PEFConfigParam_AlertPoliciesCount AlertPolicies []*PEFConfigParam_AlertPolicy SystemGUID *PEFConfigParam_SystemGUID AlertStringsCount *PEFConfigParam_AlertStringsCount AlertStringKeys []*PEFConfigParam_AlertStringKey AlertStrings []*PEFConfigParam_AlertString GroupControlsCount *PEFConfigParam_GroupControlsCount GroupControls []*PEFConfigParam_GroupControl } func (pefConfigParams *PEFConfigParams) Format() string { var out string format := func(param PEFConfigParameter) string { if isNilPEFConfigParameter(param) { return "" } paramSelector, _, _ := param.PEFConfigParameter() content := param.Format() if content[len(content)-1] != '\n' { content += "\n" } return fmt.Sprintf("[%2d] %s : %s", paramSelector, paramSelector.String(), content) } if pefConfigParams.SetInProgress != nil { out += format(pefConfigParams.SetInProgress) } if pefConfigParams.Control != nil { out += format(pefConfigParams.Control) } if pefConfigParams.ActionGlobalControl != nil { out += format(pefConfigParams.ActionGlobalControl) } if pefConfigParams.StartupDelay != nil { out += format(pefConfigParams.StartupDelay) } if pefConfigParams.AlertStartupDelay != nil { out += format(pefConfigParams.AlertStartupDelay) } if pefConfigParams.EventFiltersCount != nil { out += format(pefConfigParams.EventFiltersCount) } if pefConfigParams.EventFilters != nil { for i := range pefConfigParams.EventFilters { out += format(pefConfigParams.EventFilters[i]) } } if pefConfigParams.EventFiltersData1 != nil { for i := range pefConfigParams.EventFiltersData1 { out += format(pefConfigParams.EventFiltersData1[i]) } } if pefConfigParams.AlertPoliciesCount != nil { out += format(pefConfigParams.AlertPoliciesCount) } if pefConfigParams.AlertPolicies != nil { for i := range pefConfigParams.AlertPolicies { out += format(pefConfigParams.AlertPolicies[i]) } } if pefConfigParams.SystemGUID != nil { out += format(pefConfigParams.SystemGUID) } if pefConfigParams.AlertStringsCount != nil { out += format(pefConfigParams.AlertStringsCount) } if pefConfigParams.AlertStringKeys != nil { for i := range pefConfigParams.AlertStringKeys { out += format(pefConfigParams.AlertStringKeys[i]) } } if pefConfigParams.AlertStrings != nil { for i := range pefConfigParams.AlertStrings { out += format(pefConfigParams.AlertStrings[i]) } } if pefConfigParams.GroupControlsCount != nil { out += format(pefConfigParams.GroupControlsCount) } if pefConfigParams.GroupControls != nil { for i := range pefConfigParams.GroupControls { out += format(pefConfigParams.GroupControls[i]) } } return out } type PEFConfigParam_SetInProgress struct { Value SetInProgressState } func (param *PEFConfigParam_SetInProgress) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_SetInProgress, 0, 0 } func (param *PEFConfigParam_SetInProgress) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Value = SetInProgressState(data[0]) return nil } func (param *PEFConfigParam_SetInProgress) Pack() []byte { return []byte{byte(param.Value)} } func (param *PEFConfigParam_SetInProgress) Format() string { return fmt.Sprintf("%v", param.Value) } type PEFConfigParam_Control struct { EnablePEFAlertStartupDelay bool EnablePEFStartupDelay bool EnableEventMessage bool EnablePEF bool } func (param *PEFConfigParam_Control) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_Control, 0, 0 } func (param *PEFConfigParam_Control) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.EnablePEFAlertStartupDelay = isBit3Set(data[0]) param.EnablePEFStartupDelay = isBit2Set(data[0]) param.EnableEventMessage = isBit1Set(data[0]) param.EnablePEF = isBit0Set(data[0]) return nil } func (param *PEFConfigParam_Control) Pack() []byte { b := uint8(0x00) b = setOrClearBit3(b, param.EnablePEFAlertStartupDelay) b = setOrClearBit2(b, param.EnablePEFStartupDelay) b = setOrClearBit1(b, param.EnableEventMessage) b = setOrClearBit0(b, param.EnablePEF) return []byte{b} } func (param *PEFConfigParam_Control) Format() string { return fmt.Sprintf(` PEF startup delay : %s Alert startup delay : %s PEF event messages : %s PEF : %s `, formatBool(param.EnablePEFAlertStartupDelay, "enabled", "disabled"), formatBool(param.EnablePEFStartupDelay, "enabled", "disabled"), formatBool(param.EnableEventMessage, "enabled", "disabled"), formatBool(param.EnablePEF, "enabled", "disabled"), ) } type PEFConfigParam_ActionGlobalControl struct { DiagnosticInterruptEnabled bool OEMActionEnabled bool PowerCycleActionEnabled bool ResetActionEnabled bool PowerDownActionEnabled bool AlertActionEnabled bool } func (param *PEFConfigParam_ActionGlobalControl) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_ActionGlobalControl, 0, 0 } func (param *PEFConfigParam_ActionGlobalControl) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.DiagnosticInterruptEnabled = isBit5Set(data[0]) param.OEMActionEnabled = isBit4Set(data[0]) param.PowerCycleActionEnabled = isBit3Set(data[0]) param.ResetActionEnabled = isBit2Set(data[0]) param.PowerDownActionEnabled = isBit1Set(data[0]) param.AlertActionEnabled = isBit0Set(data[0]) return nil } func (param *PEFConfigParam_ActionGlobalControl) Pack() []byte { b := uint8(0x00) b = setOrClearBit5(b, param.DiagnosticInterruptEnabled) b = setOrClearBit4(b, param.OEMActionEnabled) b = setOrClearBit3(b, param.PowerCycleActionEnabled) b = setOrClearBit2(b, param.ResetActionEnabled) b = setOrClearBit1(b, param.PowerDownActionEnabled) b = setOrClearBit0(b, param.AlertActionEnabled) return []byte{b} } func (param *PEFConfigParam_ActionGlobalControl) Format() string { return fmt.Sprintf(` Diagnostic-interrupt : %s OEM-defined : %s Power-cycle : %s Reset : %s Power-off : %s Alert : %s `, formatBool(param.DiagnosticInterruptEnabled, "active", "inactive"), formatBool(param.OEMActionEnabled, "active", "inactive"), formatBool(param.PowerCycleActionEnabled, "active", "inactive"), formatBool(param.ResetActionEnabled, "active", "inactive"), formatBool(param.PowerDownActionEnabled, "active", "inactive"), formatBool(param.AlertActionEnabled, "active", "inactive"), ) } type PEFConfigParam_StartupDelay struct { DelaySec uint8 } func (param *PEFConfigParam_StartupDelay) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_StartupDelay, 0, 0 } func (param *PEFConfigParam_StartupDelay) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.DelaySec = data[0] return nil } func (param *PEFConfigParam_StartupDelay) Pack() []byte { return []byte{param.DelaySec} } func (param *PEFConfigParam_StartupDelay) Format() string { return fmt.Sprintf("%v", param.DelaySec) } type PEFConfigParam_AlertStartupDelay struct { DelaySec uint8 } func (param *PEFConfigParam_AlertStartupDelay) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_AlertStartDelay, 0, 0 } func (param *PEFConfigParam_AlertStartupDelay) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.DelaySec = data[0] return nil } func (param *PEFConfigParam_AlertStartupDelay) Pack() []byte { return []byte{param.DelaySec} } func (param *PEFConfigParam_AlertStartupDelay) Format() string { return fmt.Sprintf("%v", param.DelaySec) } // Number of event filters supported. 1-based. // This parameter does not need to be supported if Alerting is not supported. // READ ONLY type PEFConfigParam_EventFiltersCount struct { Value uint8 } func (param *PEFConfigParam_EventFiltersCount) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_EventFiltersCount, 0, 0 } func (param *PEFConfigParam_EventFiltersCount) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Value = data[0] return nil } func (param *PEFConfigParam_EventFiltersCount) Pack() []byte { return []byte{param.Value} } func (param *PEFConfigParam_EventFiltersCount) Format() string { return fmt.Sprintf("%d", param.Value) } type PEFConfigParam_EventFilter struct { // Set Selector = filter number. 1-based. 00h = reserved. SetSelector uint8 Filter *PEFEventFilter } func (param *PEFConfigParam_EventFilter) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_EventFilter, param.SetSelector, 0 } func (param *PEFConfigParam_EventFilter) Unpack(data []byte) error { if len(data) < 21 { return ErrUnpackedDataTooShortWith(len(data), 21) } param.SetSelector = data[0] eventFilter := &PEFEventFilter{} if err := eventFilter.Unpack(data[1:21]); err != nil { return fmt.Errorf("unpack entry failed, err: %w", err) } param.Filter = eventFilter return nil } func (param *PEFConfigParam_EventFilter) Pack() []byte { entryData := param.Filter.Pack() out := make([]byte, len(entryData)) out[0] = param.SetSelector packBytes(entryData, out, 1) return out } func (param *PEFConfigParam_EventFilter) Format() string { return fmt.Sprintf(` Event Filter Number: %d Event Filter: %v `, param.SetSelector, param.Filter.Format()) } // This parameter provides an aliased access to the first byte of the event filter data. // This is provided to simplify the act of enabling and disabling individual filters // by avoiding the need to do a read-modify-write of the entire filter data. type PEFConfigParam_EventFilterData1 struct { // Set Selector = filter number SetSelector uint8 // data byte 1 of event filter data // [7] - 1b = enable filter // 0b = disable filter FilterEnabled bool // [6:5] - 11b = reserved // 10b = manufacturer pre-configured filter. The filter entry has been // configured by the system integrator and should not be altered by software. // Software is allowed to enable or disable the filter, however. // 01b = reserved // 00b = software configurable filter. The filter entry is available for // configuration by system management software. FilterType PEFEventFilterType } func (param *PEFConfigParam_EventFilterData1) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_EventFilterData1, param.SetSelector, 0 } func (param *PEFConfigParam_EventFilterData1) Unpack(data []byte) error { if len(data) < 2 { return ErrUnpackedDataTooShortWith(len(data), 21) } param.SetSelector = data[0] b := data[1] param.FilterEnabled = isBit7Set(b) param.FilterType = PEFEventFilterType((b >> 5) & 0x03) return nil } func (param *PEFConfigParam_EventFilterData1) Pack() []byte { out := make([]byte, 21) out[0] = param.SetSelector var b byte b = uint8(param.FilterType) << 5 b = setOrClearBit7(b, param.FilterEnabled) out[1] = b return out } func (param *PEFConfigParam_EventFilterData1) Format() string { return fmt.Sprintf(`FilterNumber: %d, FilterEnabled: %v, FilterType: %v`, param.SetSelector, param.FilterEnabled, param.FilterType) } // Number of alert policy entries supported. 1-based. // This parameter does not need to be supported if Alerting is not supported. // READ ONLY type PEFConfigParam_AlertPoliciesCount struct { Value uint8 } func (param *PEFConfigParam_AlertPoliciesCount) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_AlertPoliciesCount, 0, 0 } func (param *PEFConfigParam_AlertPoliciesCount) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Value = data[0] return nil } func (param *PEFConfigParam_AlertPoliciesCount) Pack() []byte { return []byte{param.Value} } func (param *PEFConfigParam_AlertPoliciesCount) Format() string { return fmt.Sprintf("%d", param.Value) } type PEFConfigParam_AlertPolicy struct { // Set Selector = entry number // - [7] - reserved // - [6:0] - alert policy entry number. 1-based. SetSelector uint8 Policy *PEFAlertPolicy } func (param *PEFConfigParam_AlertPolicy) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_AlertPolicy, param.SetSelector, 0 } func (param *PEFConfigParam_AlertPolicy) Unpack(data []byte) error { if len(data) < 4 { return ErrUnpackedDataTooShortWith(len(data), 4) } param.SetSelector = data[0] b := &PEFAlertPolicy{} if err := b.Unpack(data[1:]); err != nil { return err } param.Policy = b return nil } func (param *PEFConfigParam_AlertPolicy) Pack() []byte { entryData := param.Policy.Pack() out := make([]byte, 1+len(entryData)) out[0] = param.SetSelector packBytes(entryData, out, 1) return out } func (param *PEFConfigParam_AlertPolicy) Format() string { return fmt.Sprintf(` Entry Number %d : %v `, param.SetSelector, param.Policy.Format()) } type PEFConfigParam_SystemGUID struct { // Used to fill in the GUID field in a PET Trap. // [7:1] - reserved // [0] // 1b = BMC uses following value in PET Trap. // 0b = BMC ignores following value and uses value returned from Get System GUID command instead. UseGUID bool GUID [16]byte } func (param *PEFConfigParam_SystemGUID) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_SystemGUID, 0, 0 } func (param *PEFConfigParam_SystemGUID) Unpack(configData []byte) error { if len(configData) < 17 { return ErrUnpackedDataTooShortWith(len(configData), 17) } param.UseGUID = isBit0Set(configData[0]) param.GUID = array16(configData[1:17]) return nil } func (param *PEFConfigParam_SystemGUID) Pack() []byte { out := make([]byte, 17) out[0] = setOrClearBit0(0x00, param.UseGUID) copy(out[1:], param.GUID[:]) return out } func (param *PEFConfigParam_SystemGUID) Format() string { var guidStr string guid, err := ParseGUID(param.GUID[:], GUIDModeSMBIOS) if err != nil { guidStr = fmt.Sprintf(" (%s)", err) } else { guidStr = guid.String() } return fmt.Sprintf(` UseGUID : %v GUID : %s `, param.UseGUID, guidStr) } // Number of alert strings supported in addition to Alert String 0. 1-based. // This parameter does not need to be supported if Alerting is not supported. // READ ONLY type PEFConfigParam_AlertStringsCount struct { Value uint8 } func (param *PEFConfigParam_AlertStringsCount) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_AlertStringsCount, 0, 0 } func (param *PEFConfigParam_AlertStringsCount) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Value = data[0] return nil } func (param *PEFConfigParam_AlertStringsCount) Pack() []byte { return []byte{param.Value} } func (param *PEFConfigParam_AlertStringsCount) Format() string { return fmt.Sprintf("%d", param.Value) } // Sets the keys used to look up Alert String data in PEF. // This parameter does not need to be supported if Alerting is not supported. // // It's purpose is to get the AlertStringSelector from combination of the (Event) FilterNumber and AlertStringSet. type PEFConfigParam_AlertStringKey struct { // Set Selector = Alert string selector. // - 0 = selects volatile string parameters // - 01h-7Fh = non-volatile string selectors SetSelector uint8 // [6:0] - Filter number. 1-based. 00h = unspecified. FilterNumber uint8 // [6:0] - Set number for string. 1-based. 00h = unspecified. AlertStringSet uint8 } func (param *PEFConfigParam_AlertStringKey) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_AlertStringKey, param.SetSelector, 0 } func (param *PEFConfigParam_AlertStringKey) Unpack(data []byte) error { if len(data) < 3 { return ErrUnpackedDataTooShortWith(len(data), 3) } param.SetSelector = data[0] param.FilterNumber = data[1] param.AlertStringSet = data[2] return nil } func (param *PEFConfigParam_AlertStringKey) Pack() []byte { return []byte{param.SetSelector, param.FilterNumber, param.AlertStringSet} } func (param *PEFConfigParam_AlertStringKey) Format() string { return fmt.Sprintf(`Set Selector: %d, Event Filter Number: %d, Alert String Set: %d`, param.SetSelector, param.FilterNumber, param.AlertStringSet) } type PEFConfigParam_AlertString struct { // Set Selector = string selector. // - 0 = selects volatile string // - 01h-7Fh = non-volatile string selectors SetSelector uint8 // Block Selector = string block number to set, 1 based. Blocks are 16 bytes. BlockSelector uint8 // String data. Null terminated 8-bit ASCII string. 16-bytes max. per block. StringData []byte } func (param *PEFConfigParam_AlertString) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_AlertString, param.SetSelector, param.BlockSelector } func (param *PEFConfigParam_AlertString) Unpack(data []byte) error { if len(data) < 3 { return ErrUnpackedDataTooShortWith(len(data), 3) } param.SetSelector = data[0] param.BlockSelector = data[1] param.StringData, _, _ = unpackBytes(data, 2, len(data)-2) return nil } func (param *PEFConfigParam_AlertString) Pack() []byte { out := make([]byte, 2+len(param.StringData)) out[0] = param.SetSelector out[1] = param.BlockSelector packBytes(param.StringData, out, 2) return out } func (param *PEFConfigParam_AlertString) Format() string { return fmt.Sprintf(`AlertStringSelector: %d, BlockSelector: %d, StringData: %s`, param.SetSelector, param.BlockSelector, string(param.StringData)) } // READ ONLY type PEFConfigParam_GroupControlsCount struct { Value uint8 } func (param *PEFConfigParam_GroupControlsCount) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_GroupControlsCount, 0, 0 } func (param *PEFConfigParam_GroupControlsCount) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } param.Value = data[0] return nil } func (param *PEFConfigParam_GroupControlsCount) Pack() []byte { return []byte{param.Value} } func (param *PEFConfigParam_GroupControlsCount) Format() string { return fmt.Sprintf("%d", param.Value) } type PEFConfigParam_GroupControl struct { // Set Selector (Entry Selector) = group control table entry selector. SetSelector uint8 ForceControlOperation bool DelayedControl bool ChannelNumber uint8 GroupID0 uint8 MemberID0 uint8 DisableMemberID0Check bool GroupID1 uint8 MemberID1 uint8 DisableMemberID1Check bool GroupID2 uint8 MemberID2 uint8 DisableMemberID2Check bool GroupID3 uint8 MemberID3 uint8 DisableMemberID3Check bool RetryCount uint8 Operation uint8 } func (param *PEFConfigParam_GroupControl) PEFConfigParameter() (paramSelector PEFConfigParamSelector, setSelector uint8, blockSelector uint8) { return PEFConfigParamSelector_GroupControl, param.SetSelector, 0 } func (param *PEFConfigParam_GroupControl) Unpack(data []byte) error { if len(data) < 11 { return ErrUnpackedDataTooShortWith(len(data), 11) } param.SetSelector = data[0] param.ForceControlOperation = isBit5Set(data[1]) param.DelayedControl = isBit4Set(data[1]) param.ChannelNumber = data[1] & 0x0F param.GroupID0 = data[2] param.MemberID0 = data[3] & 0x0F param.DisableMemberID0Check = isBit4Set(data[3]) param.GroupID1 = data[4] param.MemberID1 = data[5] & 0x0F param.DisableMemberID1Check = isBit4Set(data[5]) param.GroupID2 = data[6] param.MemberID2 = data[7] & 0x0F param.DisableMemberID2Check = isBit4Set(data[7]) param.GroupID3 = data[8] param.MemberID3 = data[9] & 0x0F param.DisableMemberID3Check = isBit4Set(data[9]) // data 11: - Retries and Operation // [7] - reserved // [6:4] - number of times to retry sending the command to perform // the group operation [For ICMB, the BMC broadcasts a // Group Chassis Control command] (1-based) param.RetryCount = (data[10] & 0x7F) >> 4 param.Operation = data[10] & 0x0F return nil } func (param *PEFConfigParam_GroupControl) Pack() []byte { var b uint8 out := make([]byte, 11) out[0] = param.SetSelector b = param.ChannelNumber & 0x0F b = setOrClearBit5(b, param.ForceControlOperation) b = setOrClearBit4(b, param.DelayedControl) out[1] = b out[2] = param.GroupID0 b = param.MemberID0 & 0x0F b = setOrClearBit4(b, param.DisableMemberID0Check) out[3] = b out[4] = param.GroupID1 b = param.MemberID1 & 0x0F b = setOrClearBit4(b, param.DisableMemberID1Check) out[5] = b out[6] = param.GroupID2 b = param.MemberID2 & 0x0F b = setOrClearBit4(b, param.DisableMemberID2Check) out[7] = b out[8] = param.GroupID3 b = param.MemberID3 & 0x0F b = setOrClearBit4(b, param.DisableMemberID3Check) out[9] = b b = param.RetryCount << 4 b |= param.Operation out[10] = b return out } func (param *PEFConfigParam_GroupControl) Format() string { return fmt.Sprintf(` EntrySelector: %d ForceControlOperation: %v DelayedControl: %v ChannelNumber: %d GroupID0: %d MemberID0: %d DisableMemberID0Check: %v GroupID1: %d MemberID1: %d DisableMemberID1Check: %v GroupID2: %d MemberID2: %d DisableMemberID2Check: %v GroupID3: %d MemberID3: %d DisableMemberID3Check: %v RetryCount: %d Operation: %d `, param.SetSelector, param.ForceControlOperation, param.DelayedControl, param.ChannelNumber, param.GroupID0, param.MemberID0, param.DisableMemberID0Check, param.GroupID1, param.MemberID1, param.DisableMemberID1Check, param.GroupID2, param.MemberID2, param.DisableMemberID2Check, param.GroupID3, param.MemberID3, param.DisableMemberID3Check, param.RetryCount, param.Operation) } golang-github-bougou-go-ipmi-0.7.2/types_rmcp.go000066400000000000000000000317571474110527100216370ustar00rootroot00000000000000package ipmi import ( "context" "fmt" ) const ( RmcpVersion uint8 = 0x06 RMCP_TYPE_MASK = 0x80 RMCP_TYPE_NORM = 0x00 RMCP_TYPE_ACK = 0x01 ) // Rmcp holds the data that will be send over UDP type Rmcp struct { // Multi-byte fields in RMCP/ASF fields are specified as being transmitted in "Network Byte Order" - meaning most-significant byte first. // RMCP and ASF-specified fields are therefore transferred **most-significant byte first**. RmcpHeader *RmcpHeader // Multi-byte fields in RMCP/ASF fields are specified as being transmitted in "Network Byte Order" ASF *ASF // The IPMI convention is to transfer multi-byte numeric fields least-significant Byte first. Therefore, unless otherwise specified: // Data in the IPMI Session Header and IPMI Message fields are transmitted **least-significant byte first**. Session15 *Session15 Session20 *Session20 } func (r *Rmcp) Pack() []byte { out := r.RmcpHeader.Pack() if r.ASF != nil { out = append(out, r.ASF.Pack()...) } if r.Session15 != nil { out = append(out, r.Session15.Pack()...) } if r.Session20 != nil { out = append(out, r.Session20.Pack()...) } return out } func (r *Rmcp) Unpack(msg []byte) error { if len(msg) < 4 { return ErrUnpackedDataTooShortWith(len(msg), 4) } rmcpHeader := &RmcpHeader{} err := rmcpHeader.Unpack(msg[:4]) if err != nil { return fmt.Errorf("unpack RmcpHeader failed, err: %w", err) } r.RmcpHeader = rmcpHeader if len(msg) < 4+1 { return fmt.Errorf("msg length too short, no session inside") } if r.RmcpHeader.MessageClass == MessageClassASF { asf := &ASF{} err := asf.Unpack(msg[4:]) if err != nil { return fmt.Errorf("unpack ASF failed, err: %w", err) } r.ASF = asf return nil } authTypeOrFormat := msg[4] if authTypeOrFormat == byte(AuthTypeRMCPPlus) { // IPMI 2.0 s20 := &Session20{} err = s20.Unpack(msg[4:]) if err != nil { return fmt.Errorf("unpack IPMI 2.0 Session failed, err: %w", err) } r.Session20 = s20 } else { // IPMI 1.5 s15 := &Session15{} err = s15.Unpack(msg[4:]) if err != nil { return fmt.Errorf("unpack IPMI 1.5 Session failed, err: %w", err) } r.Session15 = s15 } if r.Session15 != nil && r.Session20 != nil { return fmt.Errorf("the IPMI session can not be both version 1.5 and 2.0") } return nil } // RmcpHeader represents RMCP Message Header // 13.1.3 type RmcpHeader struct { // 06h = RMCP Version 1.0 // IPMI-over-LAN uses version 1 of the RMCP protocol and packet format Version uint8 // RMCP Messages with class=IPMI should be sent with an RMCP Sequence Number of FFh // to indicate that an RMCP ACK message should not be generated by the message receiver. SequenceNumber uint8 // This field identifies the format of the messages that follow this header. // All messages of class ASF (6) conform to the formats defined in this // specification and can be extended via an OEM IANA. // Bit 7 RMCP ACK // 0 - Normal RMCP message // 1 - RMCP ACK message ACKFlag bool // Bit 6:5 Reserved // Bit 4:0 Message Class // 0-5 = Reserved // 6 = ASF // 7 = IPMI // 8 = OEM defined // all other = Reserved MessageClass MessageClass // Can be IPMI Messages, ASF, OEM } func NewRmcpHeader() *RmcpHeader { return &RmcpHeader{ Version: RmcpVersion, SequenceNumber: 0xff, MessageClass: MessageClassIPMI, } } func NewRmcpHeaderASF() *RmcpHeader { return &RmcpHeader{ Version: RmcpVersion, SequenceNumber: 0xff, MessageClass: MessageClassASF, } } func (r *RmcpHeader) Pack() []byte { msg := make([]byte, 4) packUint8(r.Version, msg, 0) // 1 byte reserved packUint8(r.SequenceNumber, msg, 2) var messageClass uint8 = 0x00 if r.ACKFlag { messageClass |= 0x80 } else { messageClass |= 0x00 } messageClass |= uint8(r.MessageClass) packUint8(messageClass, msg, 3) return msg } func (r *RmcpHeader) Unpack(msg []byte) error { if len(msg) < 4 { return ErrUnpackedDataTooShortWith(len(msg), 4) } r.Version, _, _ = unpackUint8(msg, 0) // 1 byte reserved r.SequenceNumber, _, _ = unpackUint8(msg, 2) var b uint8 b, _, _ = unpackUint8(msg, 3) r.ACKFlag = isBit7Set(b) messageClass := b & 0x7f // clear the ACK bit r.MessageClass = MessageClass(messageClass) return nil } type MessageType uint8 const ( MessageACKBit uint8 = 0x80 MessageNormalBit uint8 = 0x00 ) const ( MessageTypeUndefined MessageType = 0x00 MessageTypePing MessageType = 0x80 MessageTypeRMCPACK MessageType = (0x80 | 6) MessageTypeASF MessageType = (0x00 | 6) MessageTypeIPMI MessageType = (0x00 | 7) MessageTypeOEM MessageType = (0x00 | 8) ) // the ACK/Normal Bit and the Message Class combine to identify the type of // message under RMCP // see: Table 13-, Message Type Determination Under RMCP func (r *RmcpHeader) MessageType() MessageType { if r.ACKFlag { switch r.MessageClass { case MessageClassASF: return MessageTypeRMCPACK default: return MessageTypeUndefined } } switch r.MessageClass { case MessageClassASF: return MessageTypeASF case MessageClassOEM: return MessageTypeOEM case MessageClassIPMI: return MessageTypeIPMI default: return MessageTypeIPMI } } type MessageClass uint8 const ( // 0-5 Reserved MessageClassASF = 6 MessageClassIPMI = 7 MessageClassOEM = 8 // 9-15 Reserved ) func (mc MessageClass) NormalACKFlag() bool { i := uint8(mc) & uint8(1) << 7 return i == uint8(1)<<7 } // 13.2.1 RMCP ACK Messages type RmcpAckMessage struct { // Copied from received message Version uint8 // Copied from received message SequenceNumber uint8 // [7] - Set to 1 to indicate ACK packet // [6:0] - Copied from received message. ACKFlag bool MessageClass MessageClass // Can be IPMI Messages, ASF, OEM } type ASF struct { IANA uint32 // 4542 MessageType uint8 // 0-FEh, generated by remote console. This is an RMCP version of a sequence number. // Values 0-254 (0-FEh) are used for RMCP request/response messages. // 255 indicates the message is unidirectional and not part of a request/response pair. MessageTag uint8 DataLength uint8 // 00h Data []byte } func (asf *ASF) Pack() []byte { msg := make([]byte, 8+len(asf.Data)) packUint32(asf.IANA, msg, 0) // MSB, not LSB packUint8(asf.MessageType, msg, 4) packUint8(asf.MessageTag, msg, 5) // 1 byte reserved packUint8(asf.DataLength, msg, 7) packBytes(asf.Data, msg, 8) return msg } func (asf *ASF) Unpack(msg []byte) error { if len(msg) < 8 { return ErrUnpackedDataTooShortWith(len(msg), 8) } asf.IANA, _, _ = unpackUint32L(msg, 0) asf.MessageType, _, _ = unpackUint8(msg, 4) asf.MessageTag, _, _ = unpackUint8(msg, 5) // 1 byte reserved asf.DataLength, _, _ = unpackUint8(msg, 7) if len(msg) < 8+int(asf.DataLength) { return ErrUnpackedDataTooShortWith(len(msg), 8+int(asf.DataLength)) } asf.Data, _, _ = unpackBytes(msg, 8, int(asf.DataLength)) return nil } func (c *Client) BuildRmcpRequest(ctx context.Context, reqCmd Request) (*Rmcp, error) { payloadType, rawPayload, err := c.buildRawPayload(ctx, reqCmd) if err != nil { return nil, fmt.Errorf("buildRawPayload failed, err: %w", err) } c.DebugBytes("rawPayload", rawPayload, 16) // ASF if _, ok := reqCmd.(*RmcpPingRequest); ok { rmcp := &Rmcp{ RmcpHeader: NewRmcpHeaderASF(), ASF: &ASF{ IANA: 4542, MessageType: uint8(MessageTypePing), MessageTag: 0, DataLength: 0, Data: rawPayload, }, } return rmcp, nil } // IPMI 2.0 if c.v20 { session20, err := c.genSession20(payloadType, rawPayload) if err != nil { return nil, fmt.Errorf("genSession20 failed, err: %w", err) } rmcp := &Rmcp{ RmcpHeader: NewRmcpHeader(), Session20: session20, } return rmcp, nil } // IPMI 1.5 session15, err := c.genSession15(rawPayload) if err != nil { return nil, fmt.Errorf("genSession15 failed, err: %w", err) } rmcp := &Rmcp{ RmcpHeader: NewRmcpHeader(), Session15: session15, } return rmcp, nil } // ParseRmcpResponse parses msg bytes. // The response param should be passed as a pointer of the struct which implements the Response interface. func (c *Client) ParseRmcpResponse(ctx context.Context, msg []byte, response Response) error { rmcp := &Rmcp{} if err := rmcp.Unpack(msg); err != nil { return fmt.Errorf("unpack rmcp failed, err: %w", err) } c.Debug("<<<<<< RMCP Response", rmcp) if rmcp.ASF != nil { if int(rmcp.ASF.DataLength) != len(rmcp.ASF.Data) { return fmt.Errorf("asf Data Length not equal") } if err := response.Unpack(rmcp.ASF.Data); err != nil { return fmt.Errorf("unpack asf response failed, err: %w", err) } return nil } if rmcp.Session15 != nil { ipmiPayload := rmcp.Session15.Payload ipmiRes := IPMIResponse{} if err := ipmiRes.Unpack(ipmiPayload); err != nil { return fmt.Errorf("unpack ipmiRes failed, err: %w", err) } c.Debug("<<<< IPMI Response", ipmiRes) ccode := ipmiRes.CompletionCode if ccode != 0x00 { return &ResponseError{ completionCode: CompletionCode(ccode), description: fmt.Sprintf("ipmiRes CompletionCode (%#02x) is not normal: %s", ccode, StrCC(response, ccode)), } } // now ccode is 0x00, we can continue to deserialize response if err := response.Unpack(ipmiRes.Data); err != nil { return &ResponseError{ completionCode: 0x00, description: fmt.Sprintf("unpack response failed, err: %s", err), } } } if rmcp.Session20 != nil { sessionHdr := rmcp.Session20.SessionHeader20 switch sessionHdr.PayloadType { case PayloadTypeRmcpOpenSessionResponse, PayloadTypeRAKPMessage2, PayloadTypeRAKPMessage4: // Session Setup Payload Types if err := response.Unpack(rmcp.Session20.SessionPayload); err != nil { return fmt.Errorf("unpack session setup response failed, err: %w", err) } return nil case PayloadTypeIPMI: // Standard Payload Types ipmiPayload := rmcp.Session20.SessionPayload if sessionHdr.PayloadEncrypted { c.DebugBytes("decrypting", ipmiPayload, 16) d, err := c.decryptPayload(rmcp.Session20.SessionPayload) if err != nil { return fmt.Errorf("decrypt session payload failed, err: %w", err) } ipmiPayload = d c.DebugBytes("decrypted", ipmiPayload, 16) } ipmiRes := IPMIResponse{} if err := ipmiRes.Unpack(ipmiPayload); err != nil { return fmt.Errorf("unpack ipmiRes failed, err: %w", err) } c.Debug("<<<< IPMI Response", ipmiRes) ccode := ipmiRes.CompletionCode if ccode != 0x00 { return &ResponseError{ completionCode: CompletionCode(ccode), description: fmt.Sprintf("ipmiRes CompletionCode (%#02x) is not normal: %s", ccode, StrCC(response, ccode)), } } // now ccode is 0x00, we can continue to deserialize response if err := response.Unpack(ipmiRes.Data); err != nil { return &ResponseError{ completionCode: 0x00, description: fmt.Sprintf("unpack response failed, err: %s", err), } } } } return nil } // 13.24 RMCP+ and RAKP Message Status Codes type RmcpStatusCode uint8 const ( RmcpStatusCodeNoErrors RmcpStatusCode = 0x00 RmcpStatusCodeNoResToCreateSess RmcpStatusCode = 0x01 RmcpStatusCodeInvalidSessionID RmcpStatusCode = 0x02 RmcpStatusCodeInvalidPayloadType RmcpStatusCode = 0x03 RmcpStatusCodeInvalidAuthAlg RmcpStatusCode = 0x04 RmcpStatusCodeInvalidIntegrityAlg RmcpStatusCode = 0x05 RmcpStatusCodeNoMatchingAuthPayload RmcpStatusCode = 0x06 RmcpStatusCodeNoMatchingIntegrityPayload RmcpStatusCode = 0x07 RmcpStatusCodeInactiveSessionID RmcpStatusCode = 0x08 RmcpStatusCodeInvalidRole RmcpStatusCode = 0x09 RmcpStatusCodeUnauthorizedRoleOfPriLevel RmcpStatusCode = 0x0a RmcpStatusCodeNoResToCreateSessAtRole RmcpStatusCode = 0x0b RmcpStatusCodeInvalidNameLength RmcpStatusCode = 0x0c RmcpStatusCodeUnauthorizedName RmcpStatusCode = 0x0d RmcpStatusCodeUnauthorizedGUID RmcpStatusCode = 0x0e RmcpStatusCodeInvalidIntegrityCheckValue RmcpStatusCode = 0x0f RmcpStatusCodeInvalidConfidentAlg RmcpStatusCode = 0x10 RmcpStatusCodeNoCipherSuiteMatch RmcpStatusCode = 0x11 RmcpStatusCodeIllegalParameter RmcpStatusCode = 0x12 ) func (c RmcpStatusCode) String() string { m := map[RmcpStatusCode]string{ 0x00: "No errors", 0x01: "Insufficient resources to create a session", 0x02: "Invalid Session ID", 0x03: "Invalid payload type", 0x04: "Invalid authentication algorithm", 0x05: "Invalid integrity algorithm", 0x06: "No matching authentication payload", 0x07: "No matching integrity payload", 0x08: "Inactive Session ID", 0x09: "Invalid role", 0x0a: "Unauthorized role of privilege level requested", 0x0b: "Insufficient resources to create a session at the requested role", 0x0c: "Invalid name length", 0x0d: "Unauthorized name", 0x0e: "Unauthorized GUID", 0x0f: "Invalid integrity check value", 0x10: "Invalid confidentiality algorithm", 0x11: "No Cipher Suite match with proposed security algorithms", 0x12: "Illegal or unrecognized parameter", // 0x13 - 0xff: Reserved for future definition by this specification. } s, ok := m[c] if ok { return s } return "Unknown" } golang-github-bougou-go-ipmi-0.7.2/types_sdr.go000066400000000000000000000654641474110527100214700ustar00rootroot00000000000000package ipmi import ( "bytes" "context" "fmt" "github.com/olekukonko/tablewriter" ) const SDRRecordHeaderSize int = 5 // 43. Sensor Data Record Formats // SDRRecordType is a number representing the type of the record. type SDRRecordType uint8 const ( SDRRecordTypeFullSensor SDRRecordType = 0x01 SDRRecordTypeCompactSensor SDRRecordType = 0x02 SDRRecordTypeEventOnly SDRRecordType = 0x03 SDRRecordTypeEntityAssociation SDRRecordType = 0x08 SDRRecordTypeDeviceRelativeEntityAssociation SDRRecordType = 0x09 SDRRecordTypeGenericLocator SDRRecordType = 0x10 SDRRecordTypeFRUDeviceLocator SDRRecordType = 0x11 SDRRecordTypeManagementControllerDeviceLocator SDRRecordType = 0x12 SDRRecordTypeManagementControllerConfirmation SDRRecordType = 0x13 SDRRecordTypeBMCMessageChannelInfo SDRRecordType = 0x14 SDRRecordTypeOEM SDRRecordType = 0xc0 ) func (sdrRecordType SDRRecordType) String() string { // 43.6 SDR Type 0Ah:0Fh - Reserved Records // This range and all other unspecified SDR Type values are reserved. var sdrRecordTypeMap = map[SDRRecordType]string{ 0x01: "Full", 0x02: "Compact", 0x03: "Event", 0x08: "Entity Assoc", 0x09: "Device Entity Assoc", 0x10: "Generic Device Loc", 0x11: "FRU Device Loc", 0x12: "MC Device Loc", // MC: Management Controller 0x13: "MC Confirmation", 0x14: "BMC Msg Channel Info", 0xc0: "OEM", } s, ok := sdrRecordTypeMap[sdrRecordType] if !ok { return "Reserved" } return s } type SDRHeader struct { RecordID uint16 SDRVersion uint8 // The version number of the SDR specification. RecordType SDRRecordType // A number representing the type of the record. E.g. 01h = 8-bit Sensor with Thresholds. RecordLength uint8 // Number of bytes of data following the Record Length field. } // 43. Sensor Data Record Formats type SDR struct { // NextRecordID should be filled by ParseSDR. NextRecordID uint16 RecordHeader *SDRHeader Full *SDRFull Compact *SDRCompact EventOnly *SDREventOnly EntityAssociation *SDREntityAssociation DeviceRelative *SDRDeviceRelative GenericDeviceLocator *SDRGenericDeviceLocator FRUDeviceLocator *SDRFRUDeviceLocator MgmtControllerDeviceLocator *SDRMgmtControllerDeviceLocator MgmtControllerConfirmation *SDRMgmtControllerConfirmation BMCChannelInfo *SDRBMCChannelInfo OEM *SDROEM Reserved *SDRReserved } func (sdr *SDR) String() string { recordStr := fmt.Sprintf(`RecordID: : %#02x RecordType: : %s SDR Version: : %#02x Record Length: : %d `, sdr.RecordHeader.RecordID, sdr.RecordHeader.RecordType, sdr.RecordHeader.SDRVersion, sdr.RecordHeader.RecordLength, ) recordType := sdr.RecordHeader.RecordType switch recordType { case SDRRecordTypeFullSensor: return recordStr + sdr.Full.String() case SDRRecordTypeCompactSensor: return recordStr + sdr.Compact.String() case SDRRecordTypeEventOnly: return recordStr + sdr.EventOnly.String() case SDRRecordTypeEntityAssociation: return recordStr case SDRRecordTypeDeviceRelativeEntityAssociation: return recordStr case SDRRecordTypeGenericLocator: return recordStr case SDRRecordTypeFRUDeviceLocator: return recordStr case SDRRecordTypeManagementControllerDeviceLocator: return recordStr case SDRRecordTypeManagementControllerConfirmation: return recordStr case SDRRecordTypeOEM: return recordStr default: return recordStr } } func (sdr *SDR) SensorNumber() SensorNumber { recordType := sdr.RecordHeader.RecordType switch recordType { case SDRRecordTypeFullSensor: return sdr.Full.SensorNumber case SDRRecordTypeCompactSensor: return sdr.Compact.SensorNumber case SDRRecordTypeEventOnly: return sdr.EventOnly.SensorNumber } return SensorNumberReserved } func (sdr *SDR) SensorName() string { recordType := sdr.RecordHeader.RecordType switch recordType { case SDRRecordTypeFullSensor: return string(sdr.Full.IDStringBytes) case SDRRecordTypeCompactSensor: return string(sdr.Compact.IDStringBytes) case SDRRecordTypeEventOnly: return string(sdr.EventOnly.IDStringBytes) } return "" } // Determine if sensor has an analog reading func (sdr *SDR) HasAnalogReading() bool { // Only Full sensors can return analog values, Compact sensors can't return analog values. // But not all Full sensors return analog values. if sdr.RecordHeader.RecordType != SDRRecordTypeFullSensor { return false } if sdr.Full == nil { return false } return sdr.Full.HasAnalogReading() } // ParseSDR parses raw SDR record data to SDR struct. // This function is normally used after getting GetSDRResponse or GetDeviceSDRResponse to // interpret the raw SDR record data in the response. func ParseSDR(data []byte, nextRecordID uint16) (*SDR, error) { sdrHeader := &SDRHeader{} if len(data) < SDRRecordHeaderSize { return nil, ErrNotEnoughDataWith("sdr record header size", len(data), SDRRecordHeaderSize) } sdrHeader.RecordID, _, _ = unpackUint16L(data, 0) sdrHeader.SDRVersion, _, _ = unpackUint8(data, 2) recordType, _, _ := unpackUint8(data, 3) sdrHeader.RecordType = SDRRecordType(recordType) sdrHeader.RecordLength, _, _ = unpackUint8(data, 4) sdr := &SDR{ RecordHeader: sdrHeader, NextRecordID: nextRecordID, } switch sdrHeader.RecordType { case SDRRecordTypeFullSensor: if err := parseSDRFullSensor(data, sdr); err != nil { return nil, fmt.Errorf("parseSDRFullSensor failed, err: %w", err) } case SDRRecordTypeCompactSensor: if err := parseSDRCompactSensor(data, sdr); err != nil { return nil, fmt.Errorf("parseSDRCompactSensor failed, err: %w", err) } case SDRRecordTypeEventOnly: if err := parseSDREventOnly(data, sdr); err != nil { return nil, fmt.Errorf("parseSDREventOnly failed, err: %w", err) } case SDRRecordTypeEntityAssociation: if err := parseSDREntityAssociation(data, sdr); err != nil { return nil, fmt.Errorf("parseSDREntityAssociation failed, err: %w", err) } case SDRRecordTypeDeviceRelativeEntityAssociation: if err := parseSDRDeviceRelativeEntityAssociation(data, sdr); err != nil { return nil, fmt.Errorf("parseSDRDeviceRelativeEntityAssociation failed, err: %w", err) } case SDRRecordTypeGenericLocator: if err := parseSDRGenericLocator(data, sdr); err != nil { return nil, fmt.Errorf("parseSDRGenericLocator failed, err: %w", err) } case SDRRecordTypeFRUDeviceLocator: if err := parseSDRFRUDeviceLocator(data, sdr); err != nil { return nil, fmt.Errorf("parseSDRFRUDeviceLocator failed, err: %w", err) } case SDRRecordTypeManagementControllerDeviceLocator: if err := parseSDRManagementControllerDeviceLocator(data, sdr); err != nil { return nil, fmt.Errorf("parseSDRManagementControllerDeviceLocator failed, err: %w", err) } case SDRRecordTypeManagementControllerConfirmation: if err := parseSDRManagementControllerConfirmation(data, sdr); err != nil { return nil, fmt.Errorf("parseSDRManagementControllerConfirmation failed, err: %w", err) } case SDRRecordTypeBMCMessageChannelInfo: if err := parseSDRBMCMessageChannelInfo(data, sdr); err != nil { return nil, fmt.Errorf("parseSDRBMCMessageChannelInfo failed, err: %w", err) } case SDRRecordTypeOEM: if err := parseSDROEM(data, sdr); err != nil { return nil, fmt.Errorf("parseSDROEM failed, err: %w", err) } } return sdr, nil } // Format SDRs of FRU record type func FormatSDRs_FRU(records []*SDR) string { var buf = new(bytes.Buffer) table := tablewriter.NewWriter(buf) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) headers := []string{ "RecordID", "RecordType", "DeviceAccessAddr", "FRUDeviceID", "IsLogicFRU", "AccessLUN", "PrivateBusID", "ChannelNumber", "DeviceType", "Modifier", "FRUEntityID", "FRUEntityInstance", "TypeLength", "DeviceName", } table.SetHeader(headers) table.SetFooter(headers) for _, sdr := range records { if sdr == nil || sdr.RecordHeader == nil { continue } recordID := sdr.RecordHeader.RecordID recordType := sdr.RecordHeader.RecordType switch recordType { case SDRRecordTypeFRUDeviceLocator: sdrFRU := sdr.FRUDeviceLocator table.Append([]string{ fmt.Sprintf("%#02x", recordID), fmt.Sprintf("%s (%#02x)", recordType.String(), uint8(recordType)), fmt.Sprintf("%#02x", sdrFRU.DeviceAccessAddress), fmt.Sprintf("%#02x", sdrFRU.FRUDeviceID_SlaveAddress), fmt.Sprintf("%v", sdrFRU.IsLogicalFRUDevice), fmt.Sprintf("%#02x", sdrFRU.AccessLUN), fmt.Sprintf("%#02x", sdrFRU.PrivateBusID), fmt.Sprintf("%#02x", sdrFRU.ChannelNumber), fmt.Sprintf("%s (%#02x)", sdrFRU.DeviceType.String(), uint8(sdrFRU.DeviceType)), fmt.Sprintf("%#02x", sdrFRU.DeviceTypeModifier), fmt.Sprintf("%#02x", sdrFRU.FRUEntityID), fmt.Sprintf("%#02x", sdrFRU.FRUEntityInstance), sdrFRU.DeviceIDTypeLength.String(), string(sdrFRU.DeviceIDBytes), }) default: } } table.Render() return buf.String() } // FormatSDRs returns a table formatted string for print. func FormatSDRs(records []*SDR) string { var buf = new(bytes.Buffer) table := tablewriter.NewWriter(buf) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) headers := []string{ "RecordID", "RecordType", "GeneratorID", "SensorNumber", "SensorName", "Entity", "SensorType", "EventReadingType", "SensorValue", "SensorUnit", "SensorStatus", } table.SetHeader(headers) table.SetFooter(headers) for _, sdr := range records { if sdr == nil || sdr.RecordHeader == nil { continue } recordID := sdr.RecordHeader.RecordID recordType := sdr.RecordHeader.RecordType var generatorID GeneratorID var sensorUnit SensorUnit var entityID EntityID var entityInstance EntityInstance var sensorType SensorType var eventReadingType EventReadingType var sensorValue float64 var sensorStatus string switch recordType { case SDRRecordTypeFullSensor: generatorID = sdr.Full.GeneratorID sensorUnit = sdr.Full.SensorUnit entityID = sdr.Full.SensorEntityID entityInstance = sdr.Full.SensorEntityInstance sensorType = sdr.Full.SensorType eventReadingType = sdr.Full.SensorEventReadingType sensorValue = sdr.Full.SensorValue sensorStatus = sdr.Full.SensorStatus case SDRRecordTypeCompactSensor: generatorID = sdr.Compact.GeneratorID sensorUnit = sdr.Compact.SensorUnit entityID = sdr.Compact.SensorEntityID entityInstance = sdr.Compact.SensorEntityInstance sensorType = sdr.Compact.SensorType eventReadingType = sdr.Compact.SensorEventReadingType sensorValue = sdr.Compact.SensorValue sensorStatus = sdr.Compact.SensorStatus default: } table.Append([]string{ fmt.Sprintf("%#02x", recordID), fmt.Sprintf("%s (%#02x)", recordType.String(), uint8(recordType)), fmt.Sprintf("%#04x", generatorID), fmt.Sprintf("%#02x", sdr.SensorNumber()), sdr.SensorName(), canonicalEntityString(entityID, entityInstance), sensorType.String(), eventReadingType.String(), fmt.Sprintf("%#.2f", sensorValue), sensorUnit.String(), sensorStatus, }) } table.Render() return buf.String() } // Mask_Threshold holds masks for a specific threshold type. type Mask_Threshold struct { StatusReturned bool // Indicates whether this threshold comparison status is returned via the Get Sensor Reading command. Settable bool Readable bool High_Assert bool Low_Assert bool High_Deassert bool Low_Deassert bool } // Mask_Thresholds holds masks for all threshold types. type Mask_Thresholds struct { LNR Mask_Threshold LCR Mask_Threshold LNC Mask_Threshold UNR Mask_Threshold UCR Mask_Threshold UNC Mask_Threshold } func (mask *Mask_Thresholds) IsThresholdReadable(thresholdType SensorThresholdType) bool { switch thresholdType { case SensorThresholdType_LCR: return mask.LCR.Readable case SensorThresholdType_LNR: return mask.LNR.Readable case SensorThresholdType_LNC: return mask.LNC.Readable case SensorThresholdType_UCR: return mask.UCR.Readable case SensorThresholdType_UNC: return mask.UNC.Readable case SensorThresholdType_UNR: return mask.UNR.Readable } return false } type Mask_DiscreteEvent struct { State_0 bool State_1 bool State_2 bool State_3 bool State_4 bool State_5 bool State_6 bool State_7 bool State_8 bool State_9 bool State_10 bool State_11 bool State_12 bool State_13 bool State_14 bool } func (mask Mask_DiscreteEvent) TrueEvents() []uint8 { events := []uint8{} if mask.State_0 { events = append(events, 0) } if mask.State_1 { events = append(events, 1) } if mask.State_2 { events = append(events, 2) } if mask.State_3 { events = append(events, 3) } if mask.State_4 { events = append(events, 4) } if mask.State_5 { events = append(events, 5) } if mask.State_6 { events = append(events, 6) } if mask.State_7 { events = append(events, 7) } if mask.State_8 { events = append(events, 8) } if mask.State_9 { events = append(events, 9) } if mask.State_10 { events = append(events, 10) } if mask.State_11 { events = append(events, 11) } if mask.State_12 { events = append(events, 12) } if mask.State_13 { events = append(events, 13) } if mask.State_14 { events = append(events, 14) } return events } type Mask_Discrete struct { // Assertion Event Mask for non-threshold based sensors, true means assertion event can be generated for this state Assert Mask_DiscreteEvent // Deassertion Event Mask for non-threshold based sensors, true means deassertion event can be generated for this state Deassert Mask_DiscreteEvent // Reading Mask for non-threshold based sensors, true means discrete state can be returned by this sensor Reading Mask_DiscreteEvent } // For non-threshold-based sensors, Mask holds: // - Assertion Event Mask // - Deassertion Event Mask // - Discrete Reading Mask // // For threshold-based sensors, Mask holds: // - Lower Threshold Reading Mask // - Upper Threshold Reading Mask // - Settable Threshold Mask, Readable Threshold Mask // // Used in Full and Compact SDR type Mask struct { Threshold Mask_Thresholds Discrete Mask_Discrete } // ParseAssertLower fill: // - Assertion Event Mask // - Lower Threshold Reading Mask // - Threshold Assertion Event Mask func (mask *Mask) ParseAssertLower(b uint16) { lsb := uint8(b & 0x00ff) // Least Significant Byte msb := uint8(b >> 8) // Most Significant Byte // Assertion Event Mask mask.Discrete.Assert.State_14 = isBit6Set(lsb) mask.Discrete.Assert.State_13 = isBit5Set(lsb) mask.Discrete.Assert.State_12 = isBit4Set(lsb) mask.Discrete.Assert.State_11 = isBit3Set(lsb) mask.Discrete.Assert.State_10 = isBit2Set(lsb) mask.Discrete.Assert.State_9 = isBit1Set(lsb) mask.Discrete.Assert.State_8 = isBit0Set(lsb) mask.Discrete.Assert.State_7 = isBit7Set(msb) mask.Discrete.Assert.State_6 = isBit6Set(msb) mask.Discrete.Assert.State_5 = isBit5Set(msb) mask.Discrete.Assert.State_4 = isBit4Set(msb) mask.Discrete.Assert.State_3 = isBit3Set(msb) mask.Discrete.Assert.State_2 = isBit2Set(msb) mask.Discrete.Assert.State_1 = isBit1Set(msb) mask.Discrete.Assert.State_0 = isBit0Set(msb) // Lower Threshold Reading Mask // Indicates which lower threshold comparison status is returned via the Get Sensor Reading command mask.Threshold.LNR.StatusReturned = isBit6Set(lsb) mask.Threshold.LCR.StatusReturned = isBit5Set(lsb) mask.Threshold.LNC.StatusReturned = isBit4Set(lsb) // Threshold Assertion Event Mask mask.Threshold.UNR.High_Assert = isBit3Set(lsb) mask.Threshold.UNR.Low_Assert = isBit2Set(lsb) mask.Threshold.UCR.High_Assert = isBit1Set(lsb) mask.Threshold.UCR.Low_Assert = isBit0Set(lsb) mask.Threshold.UNC.High_Assert = isBit7Set(msb) mask.Threshold.UNC.Low_Assert = isBit6Set(msb) mask.Threshold.LNR.High_Assert = isBit5Set(msb) mask.Threshold.LNR.Low_Assert = isBit4Set(msb) mask.Threshold.LCR.High_Assert = isBit3Set(msb) mask.Threshold.LCR.Low_Assert = isBit2Set(msb) mask.Threshold.LNC.High_Assert = isBit1Set(msb) mask.Threshold.LNC.Low_Assert = isBit0Set(msb) } func (mask *Mask) ParseDeassertUpper(b uint16) { lsb := uint8(b & 0x00ff) // Least Significant Byte msb := uint8(b >> 8) // Most Significant Byte // Deassertion Event Mask mask.Discrete.Deassert.State_14 = isBit6Set(lsb) mask.Discrete.Deassert.State_13 = isBit5Set(lsb) mask.Discrete.Deassert.State_12 = isBit4Set(lsb) mask.Discrete.Deassert.State_11 = isBit3Set(lsb) mask.Discrete.Deassert.State_10 = isBit2Set(lsb) mask.Discrete.Deassert.State_9 = isBit1Set(lsb) mask.Discrete.Deassert.State_8 = isBit0Set(lsb) mask.Discrete.Deassert.State_7 = isBit7Set(msb) mask.Discrete.Deassert.State_6 = isBit6Set(msb) mask.Discrete.Deassert.State_5 = isBit5Set(msb) mask.Discrete.Deassert.State_4 = isBit4Set(msb) mask.Discrete.Deassert.State_3 = isBit3Set(msb) mask.Discrete.Deassert.State_2 = isBit2Set(msb) mask.Discrete.Deassert.State_1 = isBit1Set(msb) mask.Discrete.Deassert.State_0 = isBit0Set(msb) // Upper Threshold Reading Mask // Indicates which upper threshold comparison status is returned via the Get Sensor Reading command. mask.Threshold.UNR.StatusReturned = isBit6Set(lsb) mask.Threshold.UCR.StatusReturned = isBit5Set(lsb) mask.Threshold.UNC.StatusReturned = isBit4Set(lsb) // Threshold Deassertion Event Mask mask.Threshold.UNR.High_Deassert = isBit3Set(lsb) mask.Threshold.UNR.Low_Deassert = isBit2Set(lsb) mask.Threshold.UCR.High_Deassert = isBit1Set(lsb) mask.Threshold.UCR.Low_Deassert = isBit0Set(lsb) mask.Threshold.UNC.High_Deassert = isBit7Set(msb) mask.Threshold.UNC.Low_Deassert = isBit6Set(msb) mask.Threshold.LNR.High_Deassert = isBit5Set(msb) mask.Threshold.LNR.Low_Deassert = isBit4Set(msb) mask.Threshold.LCR.High_Deassert = isBit3Set(msb) mask.Threshold.LCR.Low_Deassert = isBit2Set(msb) mask.Threshold.LNC.High_Deassert = isBit1Set(msb) mask.Threshold.LNC.Low_Deassert = isBit0Set(msb) } func (mask *Mask) ParseReading(b uint16) { lsb := uint8(b & 0x0000ffff) // Least Significant Byte msb := uint8(b >> 8) // Most Significant Byte // Reading Mask (for non-threshold based sensors) // Indicates what discrete readings can be returned by this sensor. mask.Discrete.Reading.State_14 = isBit6Set(lsb) mask.Discrete.Reading.State_13 = isBit5Set(lsb) mask.Discrete.Reading.State_12 = isBit4Set(lsb) mask.Discrete.Reading.State_11 = isBit3Set(lsb) mask.Discrete.Reading.State_10 = isBit2Set(lsb) mask.Discrete.Reading.State_9 = isBit1Set(lsb) mask.Discrete.Reading.State_8 = isBit0Set(lsb) mask.Discrete.Reading.State_7 = isBit7Set(msb) mask.Discrete.Reading.State_6 = isBit6Set(msb) mask.Discrete.Reading.State_5 = isBit5Set(msb) mask.Discrete.Reading.State_4 = isBit4Set(msb) mask.Discrete.Reading.State_3 = isBit3Set(msb) mask.Discrete.Reading.State_2 = isBit2Set(msb) mask.Discrete.Reading.State_1 = isBit1Set(msb) mask.Discrete.Reading.State_0 = isBit0Set(msb) // Settable Threshold Mask (for threshold-based sensors) // Indicates which thresholds are settable via the Set Sensor Thresholds. mask.Threshold.UNR.Settable = isBit5Set(lsb) mask.Threshold.UCR.Settable = isBit4Set(lsb) mask.Threshold.UNC.Settable = isBit3Set(lsb) mask.Threshold.LNR.Settable = isBit2Set(lsb) mask.Threshold.LCR.Settable = isBit1Set(lsb) mask.Threshold.LNC.Settable = isBit0Set(lsb) // Readable Threshold Mask (for threshold-based sensors) // Indicates which thresholds are readable via the Get Sensor Thresholds command. mask.Threshold.UNR.Readable = isBit5Set(msb) mask.Threshold.UCR.Readable = isBit4Set(msb) mask.Threshold.UNC.Readable = isBit3Set(msb) mask.Threshold.LNR.Readable = isBit2Set(msb) mask.Threshold.LCR.Readable = isBit1Set(msb) mask.Threshold.LNC.Readable = isBit0Set(msb) } // StatusReturnedThresholds returns all supported thresholds comparison status // via the Get Sensor Reading command. func (mask *Mask) StatusReturnedThresholds() SensorThresholdTypes { out := make([]SensorThresholdType, 0) if mask.Threshold.UNC.StatusReturned { out = append(out, SensorThresholdType_UNC) } if mask.Threshold.UCR.StatusReturned { out = append(out, SensorThresholdType_UCR) } if mask.Threshold.UNR.StatusReturned { out = append(out, SensorThresholdType_UNR) } if mask.Threshold.LNC.StatusReturned { out = append(out, SensorThresholdType_LNC) } if mask.Threshold.LCR.StatusReturned { out = append(out, SensorThresholdType_LCR) } if mask.Threshold.LNR.StatusReturned { out = append(out, SensorThresholdType_LNR) } return out } // ReadableThresholds returns all readable thresholds for the sensor. func (mask *Mask) ReadableThresholds() SensorThresholdTypes { out := make([]SensorThresholdType, 0) if mask.Threshold.UNC.Readable { out = append(out, SensorThresholdType_UNC) } if mask.Threshold.UCR.Readable { out = append(out, SensorThresholdType_UCR) } if mask.Threshold.UNR.Readable { out = append(out, SensorThresholdType_UNR) } if mask.Threshold.LNC.Readable { out = append(out, SensorThresholdType_LNC) } if mask.Threshold.LCR.Readable { out = append(out, SensorThresholdType_LCR) } if mask.Threshold.LNR.Readable { out = append(out, SensorThresholdType_LNR) } return out } func (mask *Mask) SettableThresholds() SensorThresholdTypes { out := make([]SensorThresholdType, 0) if mask.Threshold.UNC.Settable { out = append(out, SensorThresholdType_UNC) } if mask.Threshold.UCR.Settable { out = append(out, SensorThresholdType_UCR) } if mask.Threshold.UNR.Settable { out = append(out, SensorThresholdType_UNR) } if mask.Threshold.LNC.Settable { out = append(out, SensorThresholdType_LNC) } if mask.Threshold.LCR.Settable { out = append(out, SensorThresholdType_LCR) } if mask.Threshold.LNR.Settable { out = append(out, SensorThresholdType_LNR) } return out } func (mask *Mask) SupportedThresholdEvents() SensorEvents { out := make([]SensorEvent, 0) // Assertion Events if mask.Threshold.UNC.High_Assert { out = append(out, SensorEvent_UNC_High_Assert) } if mask.Threshold.UNC.Low_Assert { out = append(out, SensorEvent_UNC_Low_Assert) } if mask.Threshold.UCR.High_Assert { out = append(out, SensorEvent_UCR_High_Assert) } if mask.Threshold.UCR.Low_Assert { out = append(out, SensorEvent_UCR_Low_Assert) } if mask.Threshold.UNR.High_Assert { out = append(out, SensorEvent_UNR_High_Assert) } if mask.Threshold.UNR.Low_Assert { out = append(out, SensorEvent_UNR_Low_Assert) } if mask.Threshold.LNC.High_Assert { out = append(out, SensorEvent_LNC_High_Assert) } if mask.Threshold.LNC.Low_Assert { out = append(out, SensorEvent_LNC_Low_Assert) } if mask.Threshold.LCR.High_Assert { out = append(out, SensorEvent_LCR_High_Assert) } if mask.Threshold.LCR.Low_Assert { out = append(out, SensorEvent_LCR_Low_Assert) } if mask.Threshold.LNR.High_Assert { out = append(out, SensorEvent_LNR_High_Assert) } if mask.Threshold.LNR.Low_Assert { out = append(out, SensorEvent_LNR_Low_Assert) } // Deassertion Events if mask.Threshold.UNC.High_Deassert { out = append(out, SensorEvent_UNC_High_Deassert) } if mask.Threshold.UNC.Low_Deassert { out = append(out, SensorEvent_UNC_Low_Deassert) } if mask.Threshold.UCR.High_Deassert { out = append(out, SensorEvent_UCR_High_Deassert) } if mask.Threshold.UCR.Low_Deassert { out = append(out, SensorEvent_UCR_Low_Deassert) } if mask.Threshold.UNR.High_Deassert { out = append(out, SensorEvent_UNR_High_Deassert) } if mask.Threshold.UNR.Low_Deassert { out = append(out, SensorEvent_UNR_Low_Deassert) } if mask.Threshold.LNC.High_Deassert { out = append(out, SensorEvent_LNC_High_Deassert) } if mask.Threshold.LNC.Low_Deassert { out = append(out, SensorEvent_LNC_Low_Deassert) } if mask.Threshold.LCR.High_Deassert { out = append(out, SensorEvent_LCR_High_Deassert) } if mask.Threshold.LCR.Low_Deassert { out = append(out, SensorEvent_LCR_Low_Deassert) } if mask.Threshold.LNR.High_Deassert { out = append(out, SensorEvent_LNR_High_Deassert) } if mask.Threshold.LNR.Low_Deassert { out = append(out, SensorEvent_LNR_Low_Deassert) } return out } // SensorCapabilities represent the capabilities of the sensor. // SDRs of Full/Compact record type has this field. type SensorCapabilities struct { // [7] - 1b = ignore sensor if Entity is not present or disabled. 0b = don't ignore sensor IgnoreSensorIfNoEntity bool // Sensor Auto Re-arm Support // Indicates whether the sensor requires manual rearming, or automatically rearms // itself when the event clears. 'manual' implies that the get sensor event status and // rearm sensor events commands are supported // [6] - 0b = no (manual), 1b = yes (auto) AutoRearm bool HysteresisAccess SensorHysteresisAccess ThresholdAccess SensorThresholdAccess EventMessageControl SensorEventMessageControl } // SDRs of Full/Compact record type has this field. type SensorInitialization struct { // 1b = Sensor is settable (Support the Set Sensor Reading And Event Status command) // 0b = Sensor is not settable // // using this bit to report settable sensors is optional. // I.e. it is ok to report a settable sensor as 'not settable' in the // SDR if it is desired to not report this capability to s/w Settable bool // 1b = enable scanning // // this bit=1 implies that the sensor // accepts the 'enable/disable scanning' bit in the Set // Sensor Event Enable command. InitScanning bool // 1b = enable events (per Sensor Event Message Control // Support bits in Sensor Capabilities field, and per // the Event Mask fields, below). InitEvents bool // 1b = initialize sensor thresholds (per settable threshold mask below). InitThresholds bool // 1b = initialize sensor hysteresis (per Sensor Hysteresis // Support bits in the Sensor Capabilities field, below). InitHysteresis bool // 1b = initialize Sensor Type and Event / Reading Type code InitSensorType bool // Sensor Default (power up) State // // Reports how this sensor comes up on device power up and hardware/cold reset. // The Initialization Agent does not use this bit. This bit solely reports to software // how the sensor comes prior to being initialized by the Initialization Agent. // 0b = event generation disabled, 1b = event generation enabled EventGenerationEnabled bool // 0b = sensor scanning disabled, 1b = sensor scanning enabled SensorScanningEnabled bool } // enhanceSDR will fill extra data for SDR func (c *Client) enhanceSDR(ctx context.Context, sdr *SDR) error { if sdr == nil { return nil } if sdr.RecordHeader.RecordType != SDRRecordTypeFullSensor && sdr.RecordHeader.RecordType != SDRRecordTypeCompactSensor { return nil } sensor, err := c.sdrToSensor(ctx, sdr) if err != nil { return fmt.Errorf("sdrToSensor failed, err: %w", err) } switch sdr.RecordHeader.RecordType { case SDRRecordTypeFullSensor: sdr.Full.SensorValue = sensor.Value sdr.Full.SensorStatus = sensor.Status() case SDRRecordTypeCompactSensor: sdr.Compact.SensorValue = sensor.Value sdr.Compact.SensorStatus = sensor.Status() } return nil } golang-github-bougou-go-ipmi-0.7.2/types_sdr_compact.go000066400000000000000000000212411474110527100231570ustar00rootroot00000000000000package ipmi import ( "fmt" "strings" ) // 43.2 SDR Type 02h, Compact Sensor Record // // The Compact sensor record saves space, but has limitations in the sensors it can describe. type SDRCompact struct { // // Record KEY // GeneratorID GeneratorID SensorNumber SensorNumber // // RECORD BODY // SensorEntityID EntityID SensorEntityInstance EntityInstance // 0b = treat entity as a physical entity per Entity ID table // 1b = treat entity as a logical container entity. For example, if this bit is set, // and the Entity ID is "Processor", the container entity would be considered // to represent a logical "Processor Group" rather than a physical processor. // This bit is typically used in conjunction with an Entity Association record. SensorEntityIsLogical bool SensorInitialization SensorInitialization SensorCapabilities SensorCapabilities SensorType SensorType SensorEventReadingType EventReadingType Mask Mask SensorUnit SensorUnit // SensorValue is not stored in SDR intrinsically, this field is set by `enhanceSDR` // It is fetched by IPMI command GetSensorReading and aligned/converted to SensorUnit based. SensorValue float64 // SensorStatus is not stored in SDR intrinsically, this field is set by `enhanceSDR` SensorStatus string // Sensor Direction. Indicates whether the sensor is monitoring an input or // output relative to the given Entity. E.g. if the sensor is monitoring a // current, this can be used to specify whether it is an input voltage or an // output voltage. // 00b = unspecified / not applicable // 01b = input // 10b = output // 11b = reserved SensorDirection uint8 EntityInstanceSharing uint8 // Positive hysteresis is defined as the unsigned number of counts that are // subtracted from the raw threshold values to create the "re-arm" point for all // positive-going thresholds on the sensor. 0 indicates that there is no hysteresis on // positive-going thresholds for this sensor. Hysteresis values are given as raw // counts. That is, to find the degree of hysteresis in units, the value must be // converted using the "y=Mx+B" formula. // // compact SDR can have pos/neg hysteresis, but they cannot be analog! PositiveHysteresisRaw uint8 // Negative hysteresis is defined as the unsigned number of counts that are added // to the raw threshold value to create the "re-arm" point for all negative-going // thresholds on the sensor. 0 indicates that there is no hysteresis on negative-going // thresholds for this sensor. // // compact SDR can have pos/neg hysteresis, but they cannot be analog! NegativeHysteresisRaw uint8 IDStringTypeLength TypeLength // Sensor ID String Type/Length Code IDStringBytes []byte // Sensor ID String bytes. } func (compact *SDRCompact) String() string { return fmt.Sprintf(`Sensor ID : %s (%#02x) Generator : %d Entity ID : %d.%d (%s) Sensor Type (%s) : %s (%#02x) Sensor Reading : %.3f %s Sensor Status : %s Sensor Initialization : Settable : %v Scanning : %v Events : %v Hysteresis : %v Sensor Type : %v Default State: Event Generation : %s Scanning : %s Sensor Capabilities : Auto Re-arm : %s Hysteresis Support : %s Threshold Access : %s Ev Message Control : %s Mask : Readable Thresholds : %s Settable Thresholds : %s Threshold Read Mask : %s Assertions Enabled : %s Deassertions Enabled: %s Positive Hysteresis : %#02x Negative Hysteresis : %#02x`, string(compact.IDStringBytes), compact.SensorNumber, compact.GeneratorID, uint8(compact.SensorEntityID), uint8(compact.SensorEntityInstance), compact.SensorEntityID.String(), compact.SensorEventReadingType.SensorClass(), compact.SensorType.String(), uint8(compact.SensorType), compact.SensorValue, compact.SensorUnit, compact.SensorStatus, compact.SensorInitialization.Settable, compact.SensorInitialization.InitScanning, compact.SensorInitialization.InitEvents, compact.SensorInitialization.InitHysteresis, compact.SensorInitialization.InitSensorType, formatBool(compact.SensorInitialization.EventGenerationEnabled, "enabled", "disabled"), formatBool(compact.SensorInitialization.SensorScanningEnabled, "enabled", "disabled"), formatBool(compact.SensorCapabilities.AutoRearm, "yes(auto)", "no(manual)"), compact.SensorCapabilities.HysteresisAccess.String(), compact.SensorCapabilities.ThresholdAccess, compact.SensorCapabilities.EventMessageControl, strings.Join(compact.Mask.ReadableThresholds().Strings(), " "), strings.Join(compact.Mask.SettableThresholds().Strings(), " "), strings.Join(compact.Mask.StatusReturnedThresholds().Strings(), " "), strings.Join(compact.Mask.SupportedThresholdEvents().FilterAssert().Strings(), " "), strings.Join(compact.Mask.SupportedThresholdEvents().FilterDeassert().Strings(), " "), compact.PositiveHysteresisRaw, compact.NegativeHysteresisRaw, ) // Assertions Enabled : Critical Interrupt // [PCI PERR] // [PCI SERR] // [Bus Correctable error] // [Bus Uncorrectable error] // [Bus Fatal Error] // Deassertions Enabled : Critical Interrupt // [PCI PERR] // [PCI SERR] // [Bus Correctable error] // [Bus Uncorrectable error] // [Bus Fatal Error] // OEM : 0 } func (record *SDRCompact) PositiveHysteresis() (raw uint8, valid bool) { raw = record.PositiveHysteresisRaw if raw == 0x00 || raw == 0xff { valid = false } else { valid = true } return } func (record *SDRCompact) NegativeHysteresis() (raw uint8, valid bool) { raw = record.NegativeHysteresisRaw if raw == 0x00 || raw == 0xff { valid = false } else { valid = true } return } func parseSDRCompactSensor(data []byte, sdr *SDR) error { const SDRCompactSensorMinSize int = 32 // plus the ID String Bytes (optional 16 bytes maximum) minSize := SDRCompactSensorMinSize if len(data) < minSize { return ErrNotEnoughDataWith("sdr (compact sensor) min size", len(data), minSize) } s := &SDRCompact{} sdr.Compact = s generatorID, _, _ := unpackUint16L(data, 5) s.GeneratorID = GeneratorID(generatorID) sensorNumber, _, _ := unpackUint8(data, 7) s.SensorNumber = SensorNumber(sensorNumber) b8, _, _ := unpackUint8(data, 8) s.SensorEntityID = EntityID(b8) b9, _, _ := unpackUint8(data, 9) s.SensorEntityInstance = EntityInstance(b9 & 0x7f) s.SensorEntityIsLogical = isBit7Set(b9) b10, _, _ := unpackUint8(data, 10) s.SensorInitialization = SensorInitialization{ Settable: isBit7Set(b10), InitScanning: isBit6Set(b10), InitEvents: isBit5Set(b10), InitThresholds: isBit4Set(b10), InitHysteresis: isBit3Set(b10), InitSensorType: isBit2Set(b10), EventGenerationEnabled: isBit1Set(b10), SensorScanningEnabled: isBit0Set(b10), } b11, _, _ := unpackUint8(data, 11) s.SensorCapabilities = SensorCapabilities{ IgnoreSensorIfNoEntity: isBit7Set(b11), AutoRearm: isBit6Set(b11), HysteresisAccess: SensorHysteresisAccess((b11 & 0x3f) >> 4), ThresholdAccess: SensorThresholdAccess((b11 & 0x0f) >> 2), EventMessageControl: SensorEventMessageControl(b11 & 0x03), } sensorType, _, _ := unpackUint8(data, 12) s.SensorType = SensorType(sensorType) eventReadingType, _, _ := unpackUint8(data, 13) s.SensorEventReadingType = EventReadingType(eventReadingType) mask := Mask{} b14, _, _ := unpackUint16(data, 14) b16, _, _ := unpackUint16(data, 16) b18, _, _ := unpackUint16(data, 18) mask.ParseAssertLower(b14) mask.ParseDeassertUpper(b16) mask.ParseReading(b18) s.Mask = mask b20, _, _ := unpackUint8(data, 20) b21, _, _ := unpackUint8(data, 21) b22, _, _ := unpackUint8(data, 22) s.SensorUnit = SensorUnit{ AnalogDataFormat: SensorAnalogUnitFormat((b20 & 0xc0) >> 6), RateUnit: SensorRateUnit((b20 & 0x38) >> 4), ModifierRelation: SensorModifierRelation((b20 & 0x06) >> 2), Percentage: isBit0Set(b20), BaseUnit: SensorUnitType(b21), ModifierUnit: SensorUnitType(b22), } s.PositiveHysteresisRaw, _, _ = unpackUint8(data, 25) s.NegativeHysteresisRaw, _, _ = unpackUint8(data, 26) typeLength, _, _ := unpackUint8(data, 31) s.IDStringTypeLength = TypeLength(typeLength) idStrLen := int(s.IDStringTypeLength.Length()) if len(data) < minSize+idStrLen { return ErrNotEnoughDataWith("sdr (compact sensor)", len(data), minSize+idStrLen) } s.IDStringBytes, _, _ = unpackBytes(data, minSize, idStrLen) return nil } golang-github-bougou-go-ipmi-0.7.2/types_sdr_full.go000066400000000000000000000424771474110527100225110ustar00rootroot00000000000000package ipmi import ( "fmt" "strings" ) // 43.1 SDRFull Type 01h, Full Sensor Record // // The Full Sensor Record can be used to describe any type of sensor. type SDRFull struct { // // Record KEY // // The Record 'Key' Fields are a set of fields that together are unique amongst instances of a given record type. // The Record Key bytes shall be contiguous and follow the Record Header. // The number of bytes that make up the Record Key field may vary according to record type. GeneratorID GeneratorID SensorNumber SensorNumber // // RECORD BODY // // Indicates the physical entity that the sensor is monitoring or is otherwise // associated with the sensor. SensorEntityID EntityID SensorEntityInstance EntityInstance // For example, if this bit is set, and the Entity ID is "Processor", // the container entity would be considered to represent a logical "Processor Group" rather than a physical processor. // // This bit is typically used in conjunction with an Entity Association full. // // 0b = treat entity as a physical entity per Entity ID table // 1b = treat entity as a logical container entity. SensorEntityIsLogical bool SensorInitialization SensorInitialization SensorCapabilities SensorCapabilities SensorType SensorType SensorEventReadingType EventReadingType Mask Mask SensorUnit SensorUnit // Note, SensorValue is not stored in SDR intrinsically, this field is set by `enhanceSDR` // It is fetched by IPMI command GetSensorReading and aligned/converted to SensorUnit based. SensorValue float64 // Note, SensorStatus is not stored in SDR intrinsically, this field is set by `enhanceSDR` SensorStatus string EntityInstanceSharing uint8 // see: 36.3 Sensor Reading Conversion Formula // y = L[(Mx + (B * 10^B_Exp) ) * 10^R_Exp ] units // LinearizationFunc is the Linearization func. (L of the Sensor Reading Conversion Formula) // // [6:0] - enum (linear, ln, log10, log2, e, exp10, exp2, 1/x, sqr(x), cube(x), sqrt(x), // cube-1 (x) ) // - 70h = non-linear. // 71h-7Fh = non-linear, OEM defined. LinearizationFunc LinearizationFunc ReadingFactors // Sensor Direction. Indicates whether the sensor is monitoring an input or // output relative to the given Entity. E.g. if the sensor is monitoring a // current, this can be used to specify whether it is an input voltage or an // output voltage. // 00b = unspecified / not applicable // 01b = input // 10b = output // 11b = reserved SensorDirection uint8 // Analog Flags NominalReadingSpecified bool NormalMaxSpecified bool NormalMinSpecified bool // 额定值, 标称值 // Given as a raw value. Must be converted to units-based value using the y=Mx+B // formula. 1's or 2's complement signed or unsigned per flag bits in Sensor Units 1 // // Only meaningful when NominalReadingSpecified is true NominalReadingRaw uint8 // 最大正常值 // Only meaningful when NormalMaxSpecified is true NormalMaxRaw uint8 // 最小正常值 // Only meaningful when NormalMinSpecified is true NormalMinRaw uint8 // Given as a raw value. Must be converted to units-based value based using the // y=Mx+B formula. Signed or unsigned per "signed" bit in sensor flags. Normally // "FFh" for an 8-bit unsigned sensor, but can be a lesser value if the sensor has a // restricted range. If max. reading cannot be pre-specified this value should be set // to max value, based on data format, (e.g. FFh for an unsigned sensor, 7Fh for 2"s // complement, etc.) SensorMaxReadingRaw uint8 // Given as a raw value. Must be converted to units-based value using the "y=Mx+B" // formula. Signed or unsigned per "signed" bit in sensor flags. If min. reading // cannot be pre-specified this value should be set to min value, based on data // format, (e.g. 00h for an unsigned sensor, 80h for 2"s complement, etc.) SensorMinReadingRaw uint8 // Given as raw value. UNR_Raw uint8 UCR_Raw uint8 UNC_Raw uint8 LNR_Raw uint8 LCR_Raw uint8 LNC_Raw uint8 // Positive hysteresis is defined as the unsigned number of counts that are // subtracted from the raw threshold values to create the "re-arm" point for all // positive-going thresholds on the sensor. 0 indicates that there is no hysteresis on // positive-going thresholds for this sensor. Hysteresis values are given as raw // counts. That is, to find the degree of hysteresis in units, the value must be // converted using the "y=Mx+B" formula. // // 正向迟滞量 PositiveHysteresisRaw uint8 // Negative hysteresis is defined as the unsigned number of counts that are added // to the raw threshold value to create the "re-arm" point for all negative-going // thresholds on the sensor. 0 indicates that there is no hysteresis on negative-going // thresholds for this sensor. // // 负向迟滞量 NegativeHysteresisRaw uint8 IDStringTypeLength TypeLength IDStringBytes []byte } // ConvertReading converts raw sensor reading or raw sensor threshold value to real value in the desired units for the sensor. func (full *SDRFull) ConvertReading(raw uint8) float64 { if full.HasAnalogReading() { return ConvertReading(raw, full.SensorUnit.AnalogDataFormat, full.ReadingFactors, full.LinearizationFunc) } return float64(raw) } // ConvertSensorHysteresis converts raw sensor hysteresis value to real value in the desired units for the sensor. func (full *SDRFull) ConvertSensorHysteresis(raw uint8) float64 { if full.HasAnalogReading() { return ConvertSensorHysteresis(raw, full.SensorUnit.AnalogDataFormat, full.ReadingFactors, full.LinearizationFunc) } return float64(raw) } // ConvertSensorTolerance converts raw sensor tolerance value to real value in the desired units for the sensor. func (full *SDRFull) ConvertSensorTolerance(raw uint8) float64 { if full.HasAnalogReading() { return ConvertSensorTolerance(raw, full.SensorUnit.AnalogDataFormat, full.ReadingFactors, full.LinearizationFunc) } return float64(raw) } func (full *SDRFull) ReadingStr(raw uint8, valid bool) string { if !valid { return "unspecified" } if !full.SensorUnit.IsAnalog() { return fmt.Sprintf("%#02x", raw) } value := full.ConvertReading(raw) return fmt.Sprintf("%#02x/%.3f", raw, value) } func (full *SDRFull) ReadingMaxStr() string { maxRaw := full.SensorMaxReadingRaw analogFormat := full.SensorUnit.AnalogDataFormat if (analogFormat == SensorAnalogUnitFormat_Unsigned && maxRaw == 0xff) || (analogFormat == SensorAnalogUnitFormat_1sComplement && maxRaw == 0x00) || (analogFormat == SensorAnalogUnitFormat_2sComplement && maxRaw == 0x7f) || (full.SensorUnit.IsAnalog() && full.ConvertReading(maxRaw) == 0.0) { return "unspecified" } return full.ReadingStr(maxRaw, true) } func (full *SDRFull) ReadingMinStr() string { minRaw := full.SensorMinReadingRaw analogFormat := full.SensorUnit.AnalogDataFormat if (analogFormat == SensorAnalogUnitFormat_Unsigned && minRaw == 0x00) || (analogFormat == SensorAnalogUnitFormat_1sComplement && minRaw == 0xff) || (analogFormat == SensorAnalogUnitFormat_2sComplement && minRaw == 0x80) || (full.SensorUnit.IsAnalog() && full.ConvertReading(minRaw) == 0.0) { return "unspecified" } return full.ReadingStr(minRaw, true) } // ThresholdValueStr formats a threshold value for specified threshold type. // If the threshold is not readable, return "not readable". func (full *SDRFull) ThresholdValueStr(thresholdType SensorThresholdType) string { thresholdAttr := full.SensorThreshold(thresholdType) return full.ReadingStr(thresholdAttr.Raw, thresholdAttr.Mask.Readable) } func (full *SDRFull) HysteresisStr(raw uint8) string { if !full.SensorUnit.IsAnalog() { if raw == 0x00 || raw == 0xff { return "unspecified" } return fmt.Sprintf("%#02x", raw) } // analog sensor value := full.ConvertSensorHysteresis(raw) if raw == 0x00 || raw == 0xff || value == 0.0 { return "unspecified" } return fmt.Sprintf("%#02x/%.3f", raw, value) } // SensorThreshold return SensorThreshold for a specified threshold type. func (full *SDRFull) SensorThreshold(thresholdType SensorThresholdType) SensorThreshold { switch thresholdType { case SensorThresholdType_LNR: return SensorThreshold{ Type: thresholdType, Mask: full.Mask.Threshold.LNR, Raw: full.LNR_Raw, } case SensorThresholdType_LCR: return SensorThreshold{ Type: thresholdType, Mask: full.Mask.Threshold.LCR, Raw: full.LCR_Raw, } case SensorThresholdType_LNC: return SensorThreshold{ Type: thresholdType, Mask: full.Mask.Threshold.LNC, Raw: full.LNC_Raw, } case SensorThresholdType_UNC: return SensorThreshold{ Type: thresholdType, Mask: full.Mask.Threshold.UNC, Raw: full.UNC_Raw, } case SensorThresholdType_UCR: return SensorThreshold{ Type: thresholdType, Mask: full.Mask.Threshold.UCR, Raw: full.UCR_Raw, } case SensorThresholdType_UNR: return SensorThreshold{ Type: thresholdType, Mask: full.Mask.Threshold.UNR, Raw: full.UNR_Raw, } } return SensorThreshold{ Type: thresholdType, } } func (full *SDRFull) String() string { // For pure SDR record, there's no reading for a sensor, unless you use // GetSensorReading command to fetch it. return fmt.Sprintf(`Sensor ID : %s (%#02x) Generator : %#02x Entity ID : %d.%d (%s) Sensor Type (%s) : %s (%#02x) Sensor Reading : %.4f (+/- %d) %s Sensor Status : %s Sensor Initialization : Settable : %v Scanning : %v Events : %v Hysteresis : %v Sensor Type : %v Default State: Event Generation : %s Scanning : %s Sensor Capabilities : Auto Re-arm : %s Hysteresis Support : %s Threshold Access : %s Ev Message Control : %s Mask : Readable Thresholds : %s Settable Thresholds : %s Threshold Read Mask : %s Assertions Enabled : %s Deassertions Enabled: %s Nominal Reading : %s Normal Minimum : %s Normal Maximum : %s Lower Non-Recoverable : %s Lower Critical : %s Lower Non-Critical : %s Upper Non-Critical : %s Upper Critical : %s Upper Non-Recoverable : %s Positive Hysteresis : %s Negative Hysteresis : %s Minimum sensor range : %s Maximum sensor range : %s SensorDirection : %d LinearizationFunc : %s Reading Factors : %s`, string(full.IDStringBytes), full.SensorNumber, full.GeneratorID, uint8(full.SensorEntityID), uint8(full.SensorEntityInstance), full.SensorEntityID.String(), full.SensorEventReadingType.SensorClass(), full.SensorType.String(), uint8(full.SensorType), full.SensorValue, full.ReadingFactors.Tolerance, full.SensorUnit, full.SensorStatus, full.SensorInitialization.Settable, full.SensorInitialization.InitScanning, full.SensorInitialization.InitEvents, full.SensorInitialization.InitHysteresis, full.SensorInitialization.InitSensorType, formatBool(full.SensorInitialization.EventGenerationEnabled, "enabled", "disabled"), formatBool(full.SensorInitialization.SensorScanningEnabled, "enabled", "disabled"), formatBool(full.SensorCapabilities.AutoRearm, "yes(auto)", "no(manual)"), full.SensorCapabilities.HysteresisAccess.String(), full.SensorCapabilities.ThresholdAccess, full.SensorCapabilities.EventMessageControl, strings.Join(full.Mask.ReadableThresholds().Strings(), " "), strings.Join(full.Mask.SettableThresholds().Strings(), " "), strings.Join(full.Mask.StatusReturnedThresholds().Strings(), " "), strings.Join(full.Mask.SupportedThresholdEvents().FilterAssert().Strings(), " "), strings.Join(full.Mask.SupportedThresholdEvents().FilterDeassert().Strings(), " "), full.ReadingStr(full.NominalReadingRaw, full.NominalReadingSpecified), full.ReadingStr(full.NormalMinRaw, full.NormalMinSpecified), full.ReadingStr(full.NormalMaxRaw, full.NormalMaxSpecified), full.ThresholdValueStr(SensorThresholdType_LNR), full.ThresholdValueStr(SensorThresholdType_LCR), full.ThresholdValueStr(SensorThresholdType_LNC), full.ThresholdValueStr(SensorThresholdType_UNC), full.ThresholdValueStr(SensorThresholdType_UCR), full.ThresholdValueStr(SensorThresholdType_UNR), full.HysteresisStr(full.PositiveHysteresisRaw), full.HysteresisStr(full.NegativeHysteresisRaw), full.ReadingMinStr(), full.ReadingMaxStr(), full.SensorDirection, full.LinearizationFunc, full.ReadingFactors, ) } func parseSDRFullSensor(data []byte, sdr *SDR) error { const SDRFullSensorMinSize int = 48 // plus the ID String Bytes (optional 16 bytes maximum) minSize := SDRFullSensorMinSize if len(data) < minSize { return ErrNotEnoughDataWith("sdr (full sensor) min size", len(data), minSize) } s := &SDRFull{} sdr.Full = s generatorID, _, _ := unpackUint16L(data, 5) s.GeneratorID = GeneratorID(generatorID) sensorNumber, _, _ := unpackUint8(data, 7) s.SensorNumber = SensorNumber(sensorNumber) b8, _, _ := unpackUint8(data, 8) s.SensorEntityID = EntityID(b8) b9, _, _ := unpackUint8(data, 9) s.SensorEntityInstance = EntityInstance(b9 & 0x7f) s.SensorEntityIsLogical = isBit7Set(b9) b10, _, _ := unpackUint8(data, 10) s.SensorInitialization = SensorInitialization{ Settable: isBit7Set(b10), InitScanning: isBit6Set(b10), InitEvents: isBit5Set(b10), InitThresholds: isBit4Set(b10), InitHysteresis: isBit3Set(b10), InitSensorType: isBit2Set(b10), EventGenerationEnabled: isBit1Set(b10), SensorScanningEnabled: isBit0Set(b10), } b11, _, _ := unpackUint8(data, 11) s.SensorCapabilities = SensorCapabilities{ IgnoreSensorIfNoEntity: isBit7Set(b11), AutoRearm: isBit6Set(b11), HysteresisAccess: SensorHysteresisAccess((b11 & 0x3f) >> 4), ThresholdAccess: SensorThresholdAccess((b11 & 0x0f) >> 2), EventMessageControl: SensorEventMessageControl(b11 & 0x03), } sensorType, _, _ := unpackUint8(data, 12) s.SensorType = SensorType(sensorType) eventReadingType, _, _ := unpackUint8(data, 13) s.SensorEventReadingType = EventReadingType(eventReadingType) mask := Mask{} b14, _, _ := unpackUint16(data, 14) b16, _, _ := unpackUint16(data, 16) b18, _, _ := unpackUint16(data, 18) mask.ParseAssertLower(b14) mask.ParseDeassertUpper(b16) mask.ParseReading(b18) s.Mask = mask b20, _, _ := unpackUint8(data, 20) b21, _, _ := unpackUint8(data, 21) b22, _, _ := unpackUint8(data, 22) s.SensorUnit = SensorUnit{ AnalogDataFormat: SensorAnalogUnitFormat((b20 & 0xc0) >> 6), RateUnit: SensorRateUnit((b20 & 0x38) >> 4), ModifierRelation: SensorModifierRelation((b20 & 0x06) >> 2), Percentage: isBit0Set(b20), BaseUnit: SensorUnitType(b21), ModifierUnit: SensorUnitType(b22), } b23, _, _ := unpackUint8(data, 23) s.LinearizationFunc = LinearizationFunc(b23) b24, _, _ := unpackUint8(data, 24) b25, _, _ := unpackUint8(data, 25) m := uint16(b25&0xc0)<<2 | uint16(b24) s.M = int16(twosComplement(uint32(m), 10)) s.Tolerance = b25 & 0x3f b26, _, _ := unpackUint8(data, 26) b27, _, _ := unpackUint8(data, 27) b28, _, _ := unpackUint8(data, 28) b := uint16(b27&0xc0)<<2 | uint16(b26) s.B = int16(twosComplement(uint32(b), 10)) s.Accuracy = uint16(b28&0xf0)<<2 | uint16(b27&0x3f) s.Accuracy_Exp = (b28 & 0x0c) >> 2 s.SensorDirection = b28 & 0x03 b29, _, _ := unpackUint8(data, 29) rExp := uint8((b29 & 0xf0) >> 4) s.R_Exp = int8(twosComplement(uint32(rExp), 4)) bExp := uint8(b29 & 0x0f) s.B_Exp = int8(twosComplement(uint32(bExp), 4)) b30, _, _ := unpackUint8(data, 30) s.NormalMinSpecified = isBit2Set(b30) s.NormalMaxSpecified = isBit1Set(b30) s.NominalReadingSpecified = isBit0Set(b30) s.NominalReadingRaw, _, _ = unpackUint8(data, 31) s.NormalMaxRaw, _, _ = unpackUint8(data, 32) s.NormalMinRaw, _, _ = unpackUint8(data, 33) s.SensorMaxReadingRaw, _, _ = unpackUint8(data, 34) s.SensorMinReadingRaw, _, _ = unpackUint8(data, 35) s.UNR_Raw, _, _ = unpackUint8(data, 36) s.UCR_Raw, _, _ = unpackUint8(data, 37) s.UNC_Raw, _, _ = unpackUint8(data, 38) s.LNR_Raw, _, _ = unpackUint8(data, 39) s.LCR_Raw, _, _ = unpackUint8(data, 40) s.LNC_Raw, _, _ = unpackUint8(data, 41) s.PositiveHysteresisRaw, _, _ = unpackUint8(data, 42) s.NegativeHysteresisRaw, _, _ = unpackUint8(data, 43) typeLength, _, _ := unpackUint8(data, 47) s.IDStringTypeLength = TypeLength(typeLength) idStrLen := int(s.IDStringTypeLength.Length()) if len(data) < minSize+idStrLen { return ErrNotEnoughDataWith("sdr (full sensor)", len(data), minSize+idStrLen) } s.IDStringBytes, _, _ = unpackBytes(data, minSize, idStrLen) return nil } func (full *SDRFull) HasAnalogReading() bool { // Todo, logic is not clear. /* * Per the IPMI Specification: * Only Full Threshold sensors are identified as providing * analog readings. * * But... HP didn't interpret this as meaning that "Only Threshold * Sensors" can provide analog readings. So, HP packed analog * readings into some of their non-Threshold Sensor. There is * nothing that explicitly prohibits this in the spec, so if * an Analog reading is available in a Non-Threshold sensor and * there are units specified for identifying the reading then * we do an analog conversion even though the sensor is * non-Threshold. To be safe, we provide this extension for * HP. * */ if full.SensorEventReadingType.IsThreshold() { // for threshold sensors return true } if full.SensorUnit.IsAnalog() { return true } // for non-threshold sensors, but the analog data format indicates analog. // this rarely exists, except HP. // Todo return false } golang-github-bougou-go-ipmi-0.7.2/types_sdr_others.go000066400000000000000000000660621474110527100230470ustar00rootroot00000000000000package ipmi import "fmt" // 43.3 SDR Type 03h, Event-Only Record type SDREventOnly struct { // // Record KEY // GeneratorID GeneratorID SensorNumber SensorNumber // Unique number identifying the sensor behind a given slave address and LUN. Code FFh reserved. // // RECORD BODY // SensorEntityID EntityID SensorEntityInstance EntityInstance // 0b = treat entity as a physical entity per Entity ID table // 1b = treat entity as a logical container entity. For example, if this bit is set, // and the Entity ID is "Processor", the container entity would be considered // to represent a logical "Processor Group" rather than a physical processor. // This bit is typically used in conjunction with an Entity Association record. SensorEntityIsLogical bool SensorType SensorType SensorEventReadingType EventReadingType SensorDirection uint8 IDStringInstanceModifierType uint8 // Share count (number of sensors sharing this record). Sensor numbers sharing this // record are sequential starting with the sensor number specified by the Sensor // Number field for this record. E.g. if the starting sensor number was 10, and the share // count was 3, then sensors 10, 11, and 12 would share this record. ShareCount uint8 EntityInstanceSharing bool // Multiple Discrete sensors can share the same sensor data record. The ID String Instance // Modifier and Modifier Offset are used to modify the Sensor ID String as follows: // Suppose sensor ID is "Temp " for "Temperature Sensor", share count = 3, ID string // instance modifier = numeric, instance modifier offset = 5 - then the sensors could be // identified as: // Temp 5, Temp 6, Temp 7 // If the modifier = alpha, and offset = 26, then the sensors could be identified as: // Temp AA, Temp AB, Temp AC // (alpha characters are considered to be base 26 for ASCII) IDStringInstanceModifierOffset uint8 IDStringTypeLength TypeLength IDStringBytes []byte } func (eventOnly *SDREventOnly) String() string { return fmt.Sprintf(`Sensor ID : %s (%#02x) Generator : %d Entity ID : %d.%d (%s) Sensor Type (%s) : %s (%#02x)`, string(eventOnly.IDStringBytes), eventOnly.SensorNumber, eventOnly.GeneratorID, uint8(eventOnly.SensorEntityID), uint8(eventOnly.SensorEntityInstance), eventOnly.SensorEntityID.String(), eventOnly.SensorEventReadingType.SensorClass(), eventOnly.SensorType.String(), uint8(eventOnly.SensorType), ) } func parseSDREventOnly(data []byte, sdr *SDR) error { const SDREventOnlyMinSize int = 17 minSize := SDREventOnlyMinSize if len(data) < minSize { return ErrNotEnoughDataWith("sdr (event-only sensor) min size", len(data), minSize) } s := &SDREventOnly{} sdr.EventOnly = s generatorID, _, _ := unpackUint16L(data, 5) s.GeneratorID = GeneratorID(generatorID) sensorNumber, _, _ := unpackUint8(data, 7) s.SensorNumber = SensorNumber(sensorNumber) b8, _, _ := unpackUint8(data, 8) s.SensorEntityID = EntityID(b8) b9, _, _ := unpackUint8(data, 9) s.SensorEntityInstance = EntityInstance(b9 & 0x7f) s.SensorEntityIsLogical = isBit7Set(b9) sensorType, _, _ := unpackUint8(data, 10) s.SensorType = SensorType(sensorType) eventReadingType, _, _ := unpackUint8(data, 11) s.SensorEventReadingType = EventReadingType(eventReadingType) typeLength, _, _ := unpackUint8(data, 16) s.IDStringTypeLength = TypeLength(typeLength) idStrLen := int(s.IDStringTypeLength.Length()) if len(data) < minSize+idStrLen { return ErrNotEnoughDataWith("sdr (event-only sensor)", len(data), minSize+idStrLen) } s.IDStringBytes, _, _ = unpackBytes(data, minSize, idStrLen) return nil } // 43.4 SDR Type 08h - Entity Association Record type SDREntityAssociation struct { // // Record KEY // ContainerEntityID uint8 ContainerEntityInstance uint8 // [7] - 0b = contained entities specified as list // 1b = contained entities specified as range ContainedEntitiesAsRange bool // [6] - Record Link // 0b = no linked Entity Association records // 1b = linked Entity Association records exist LinkedEntityAssociationExist bool // [5] - 0b = Container entity and contained entities can be assumed absent // if presence sensor for container entity cannot be accessed. // This value is also used if the entity does not have a presence sensor. // 1b = Presence sensor should always be accessible. Software should consider // it an error if the presence sensor associated with the container entity // is not accessible. If a presence sensor is accessible, then the // presence sensor can still report that the container entity is absent. PresenceSensorAlwaysAccessible bool ContainedEntity1ID uint8 ContainedEntity1Instance uint8 // // RECORD BODY // ContainedEntity2ID uint8 ContainedEntity2Instance uint8 ContainedEntity3ID uint8 ContainedEntity3Instance uint8 ContainedEntity4ID uint8 ContainedEntity4Instance uint8 } func parseSDREntityAssociation(data []byte, sdr *SDR) error { const SDREntityAssociationSize int = 16 if len(data) < SDREntityAssociationSize { return ErrNotEnoughDataWith("sdr (entity association)", len(data), SDREntityAssociationSize) } s := &SDREntityAssociation{} sdr.EntityAssociation = s s.ContainerEntityID, _, _ = unpackUint8(data, 5) s.ContainerEntityInstance, _, _ = unpackUint8(data, 6) flag, _, _ := unpackUint8(data, 7) s.ContainedEntitiesAsRange = isBit7Set(flag) s.LinkedEntityAssociationExist = isBit6Set(flag) s.PresenceSensorAlwaysAccessible = isBit5Set(flag) s.ContainedEntity1ID, _, _ = unpackUint8(data, 8) s.ContainedEntity1Instance, _, _ = unpackUint8(data, 9) s.ContainedEntity2ID, _, _ = unpackUint8(data, 10) s.ContainedEntity2Instance, _, _ = unpackUint8(data, 11) s.ContainedEntity3ID, _, _ = unpackUint8(data, 12) s.ContainedEntity3Instance, _, _ = unpackUint8(data, 13) s.ContainedEntity4ID, _, _ = unpackUint8(data, 14) s.ContainedEntity4Instance, _, _ = unpackUint8(data, 15) return nil } // 43.5 SDR Type 09h - Device-relative Entity Association Record type SDRDeviceRelative struct { // // Record KEY // ContainerEntityID uint8 ContainerEntityInstance uint8 ContainerEntityDeviceAddress uint8 ContainerEntityDeviceChannel uint8 // [7] - 0b = contained entities specified as list // 1b = contained entities specified as range ContainedEntitiesAsRange bool // [6] - Record Link // 0b = no linked Entity Association records // 1b = linked Entity Association records exist LinkedEntityAssociationExist bool // [5] - 0b = Container entity and contained entities can be assumed absent // if presence sensor for container entity cannot be accessed. // This value is also used if the entity does not have a presence sensor. // 1b = Presence sensor should always be accessible. Software should consider // it an error if the presence sensor associated with the container entity // is not accessible. If a presence sensor is accessible, then the // presence sensor can still report that the container entity is absent. PresenceSensorAlwaysAccessible bool ContainedEntity1DeviceAddress uint8 ContainedEntity1DeviceChannel uint8 ContainedEntity1ID uint8 ContainedEntity1Instance uint8 // // RECORD BODY // ContainedEntity2DeviceAddress uint8 ContainedEntity2DeviceChannel uint8 ContainedEntity2ID uint8 ContainedEntity2Instance uint8 ContainedEntity3DeviceAddress uint8 ContainedEntity3DeviceChannel uint8 ContainedEntity3ID uint8 ContainedEntity3Instance uint8 ContainedEntity4DeviceAddress uint8 ContainedEntity4DeviceChannel uint8 ContainedEntity4ID uint8 ContainedEntity4Instance uint8 } func parseSDRDeviceRelativeEntityAssociation(data []byte, sdr *SDR) error { const SDRDeviceRelativeEntityAssociationSize = 32 if len(data) < SDRDeviceRelativeEntityAssociationSize { return ErrNotEnoughDataWith("sdr (device-relative entity association)", len(data), SDRDeviceRelativeEntityAssociationSize) } s := &SDRDeviceRelative{} sdr.DeviceRelative = s s.ContainerEntityID, _, _ = unpackUint8(data, 5) s.ContainerEntityInstance, _, _ = unpackUint8(data, 6) s.ContainerEntityDeviceAddress, _, _ = unpackUint8(data, 7) s.ContainerEntityDeviceChannel, _, _ = unpackUint8(data, 8) flag, _, _ := unpackUint8(data, 9) s.ContainedEntitiesAsRange = isBit7Set(flag) s.LinkedEntityAssociationExist = isBit6Set(flag) s.PresenceSensorAlwaysAccessible = isBit5Set(flag) s.ContainedEntity1DeviceAddress, _, _ = unpackUint8(data, 10) s.ContainedEntity1DeviceChannel, _, _ = unpackUint8(data, 11) s.ContainedEntity1ID, _, _ = unpackUint8(data, 12) s.ContainedEntity1Instance, _, _ = unpackUint8(data, 13) s.ContainedEntity2DeviceAddress, _, _ = unpackUint8(data, 14) s.ContainedEntity2DeviceChannel, _, _ = unpackUint8(data, 15) s.ContainedEntity2ID, _, _ = unpackUint8(data, 16) s.ContainedEntity2Instance, _, _ = unpackUint8(data, 17) s.ContainedEntity3DeviceAddress, _, _ = unpackUint8(data, 18) s.ContainedEntity3DeviceChannel, _, _ = unpackUint8(data, 19) s.ContainedEntity3ID, _, _ = unpackUint8(data, 20) s.ContainedEntity3Instance, _, _ = unpackUint8(data, 21) s.ContainedEntity4DeviceAddress, _, _ = unpackUint8(data, 22) s.ContainedEntity4DeviceChannel, _, _ = unpackUint8(data, 23) s.ContainedEntity4ID, _, _ = unpackUint8(data, 24) s.ContainedEntity4Instance, _, _ = unpackUint8(data, 25) unpackBytes(data, 26, 6) // last 6 bytes reserved return nil } // 43.7 SDR Type 10h - Generic Device Locator Record // This record is used to store the location and type information for devices // on the IPMB or management controller private busses that are neither // IPMI FRU devices nor IPMI management controllers. // // These devices can either be common non-intelligent I2C devices, special management ASICs, or proprietary controllers. // // IPMI FRU Devices and Management Controllers are located via the FRU Device Locator // and Management Controller Device Locator records described in following sections. type SDRGenericDeviceLocator struct { // // Record KEY // DeviceAccessAddress uint8 // Slave address of management controller used to access device. 0000000b if device is directly on IPMB DeviceSlaveAddress uint8 ChannelNumber uint8 // Channel number for management controller used to access device AccessLUN uint8 // LUN for Master Write-Read command. 00b if device is non-intelligent device directly on IPMB. PrivateBusID uint8 // Private bus ID if bus = Private. 000b if device directly on IPMB // // RECORD BODY // AddressSpan uint8 DeviceType uint8 DeviceTypeModifier uint8 EntityID uint8 EntityInstance uint8 DeviceIDTypeLength TypeLength DeviceIDString []byte // Short ID string for the device } func parseSDRGenericLocator(data []byte, sdr *SDR) error { const SDRGenericLocatorMinSize = 16 // plus the ID String Bytes (optional 16 bytes maximum) minSize := SDRGenericLocatorMinSize if len(data) < minSize { return ErrNotEnoughDataWith("sdr (generic-locator) min size", len(data), minSize) } s := &SDRGenericDeviceLocator{} sdr.GenericDeviceLocator = s s.DeviceAccessAddress, _, _ = unpackUint8(data, 5) b, _, _ := unpackUint8(data, 6) s.DeviceSlaveAddress = b c, _, _ := unpackUint8(data, 7) s.ChannelNumber = ((b & 0x01) << 4) | (c >> 5) s.AccessLUN = (c & 0x1f) >> 3 s.PrivateBusID = (c & 0x07) s.AddressSpan, _, _ = unpackUint8(data, 8) s.DeviceType, _, _ = unpackUint8(data, 10) s.DeviceTypeModifier, _, _ = unpackUint8(data, 11) s.EntityID, _, _ = unpackUint8(data, 12) s.EntityInstance, _, _ = unpackUint8(data, 13) typeLength, _, _ := unpackUint8(data, 15) s.DeviceIDTypeLength = TypeLength(typeLength) idStrLen := int(s.DeviceIDTypeLength.Length()) if len(data) < minSize+idStrLen { return ErrNotEnoughDataWith("sdr (generic-locator)", len(data), minSize+idStrLen) } s.DeviceIDString, _, _ = unpackBytes(data, minSize, idStrLen) return nil } // 43.8 SDR Type 11h - FRU Device Locator Record // 38. Accessing FRU Devices type SDRFRUDeviceLocator struct { // // Record KEY // // [7:1] - Slave address of controller used to access device. 0000000b if device is directly on IPMB. // This field indicates whether the device is on a private bus or not. DeviceAccessAddress uint8 // FRU Device ID / Device Slave Address // // For Logical FRU DEVICE (accessed via FRU commands to mgmt. controller): // [7:0] - Number identifying FRU device within given IPM Controller. FFh = reserved. // The primary FRU device for a management controller is always device #0 at // LUN 00b. The primary FRU device is not reported via this FRU Device Locator // record - its presence is identified via the Device Capabilities field in the // Management Controller Device Locator record. // // For non-intelligent FRU device: // [7:1] - 7-bit I2C Slave Address // This is relative to the bus the device is on. // For devices on the IPMB, this is the slave address of the device on the IPMB. // For devices on a private bus, this is the slave address of the device on the private bus. // [0] - reserved FRUDeviceID_SlaveAddress uint8 // [7] - logical/physical FRU device // 0b = device is not a logical FRU Device (a physical device, that is a non-intelligent device) // 1b = device is logical FRU Device (accessed via FRU commands to mgmt. controller) IsLogicalFRUDevice bool // [4:3] - LUN for Read/Write FRU Data Command or Master Write-Read command. AccessLUN uint8 // [2:0] - Private bus ID if bus = Private. // 000b if device directly on IPMB, or device is a logical FRU Device. // // three bits, total eight bus ids, 000 ~ 111, (0 ~ 7) PrivateBusID uint8 // [7:4] - Channel number for management controller used to access device. // 000b if device directly on the primary IPMB, or if controller is on the primary IPMB. // Msbit for channel number is kept in next byte. // (For IPMI v1.5. This byte position was reserved for IPMI v1.0.) // // [3:0] - reserved ChannelNumber uint8 // // RECORD BODY // DeviceType DeviceType DeviceTypeModifier uint8 FRUEntityID uint8 FRUEntityInstance uint8 DeviceIDTypeLength TypeLength DeviceIDBytes []byte // Short ID string for the FRU Device } // Table 38-1, FRU Device Locator Field Usage func (sdrFRU *SDRFRUDeviceLocator) Location() FRULocation { if sdrFRU.IsLogicalFRUDevice { return FRULocation_MgmtController } if sdrFRU.DeviceAccessAddress == 0x00 { return FRULocation_IPMB } return FRULocation_PrivateBus } func parseSDRFRUDeviceLocator(data []byte, sdr *SDR) error { const SDRFRUDeviceLocatorMinSize = 16 // plus the ID String Bytes (optional 16 bytes maximum) minSize := SDRFRUDeviceLocatorMinSize if len(data) < minSize { return ErrNotEnoughDataWith("sdr (fru device) min size", len(data), minSize) } s := &SDRFRUDeviceLocator{} sdr.FRUDeviceLocator = s b5, _, _ := unpackUint8(data, 5) s.DeviceAccessAddress = b5 b7, _, _ := unpackUint8(data, 6) // Todo s.FRUDeviceID_SlaveAddress = b7 b8, _, _ := unpackUint8(data, 7) s.IsLogicalFRUDevice = isBit7Set(b8) s.AccessLUN = (b8 & 0x1f) >> 3 s.PrivateBusID = b8 & 0x07 b9, _, _ := unpackUint8(data, 8) s.ChannelNumber = b9 >> 4 deviceType, _, _ := unpackUint8(data, 10) s.DeviceType = DeviceType(deviceType) s.DeviceTypeModifier, _, _ = unpackUint8(data, 11) s.FRUEntityID, _, _ = unpackUint8(data, 12) s.FRUEntityInstance, _, _ = unpackUint8(data, 13) // index 14 Reserved for OEM use. typeLength, _, _ := unpackUint8(data, 15) s.DeviceIDTypeLength = TypeLength(typeLength) var idStrLen int if s.DeviceIDTypeLength.TypeCode() == 0x00 { // unspecified type idStrLen = len(data) - minSize } else { idStrLen = int(s.DeviceIDTypeLength.Length()) } if len(data) < minSize+idStrLen { return ErrNotEnoughDataWith("sdr (fru device)", len(data), minSize+idStrLen) } s.DeviceIDBytes, _, _ = unpackBytes(data, minSize, idStrLen) return nil } // 43.9 SDR Type 12h - Management Controller Device Locator Record type SDRMgmtControllerDeviceLocator struct { // // Record KEY // DeviceSlaveAddress uint8 // 7-bit I2C Slave Address[1] of device on channel ChannelNumber uint8 // // RECORD BODY // ACPISystemPowerStateNotificationRequired bool ACPIDevicePowerStateNotificationRequired bool ControllerLogsInitializationAgentErrors bool LogInitializationAgentErrors bool DeviceCap_ChassisDevice bool // device functions as chassis device DeviceCap_Bridge bool // Controller responds to Bridge NetFn command DeviceCap_IPMBEventGenerator bool // device generates event messages on IPMB DeviceCap_IPMBEventReceiver bool // device accepts event messages from IPMB DeviceCap_FRUInventoryDevice bool // accepts FRU commands to FRU Device #0 at LUN 00b DeviceCap_SELDevice bool // provides interface to SEL DeviceCap_SDRRepoDevice bool // For BMC, indicates BMC provides interface to 1b = SDR Repository. For other controller, indicates controller accepts Device SDR commands DeviceCap_SensorDevice bool // device accepts sensor commands EntityID uint8 EntityInstance uint8 DeviceIDTypeLength TypeLength DeviceIDBytes []byte } func parseSDRManagementControllerDeviceLocator(data []byte, sdr *SDR) error { const SDRManagementControllerDeviceLocatorMinSize = 16 // plus the ID String Bytes (optional 16 bytes maximum) minSize := SDRManagementControllerDeviceLocatorMinSize if len(data) < minSize { return ErrNotEnoughDataWith("sdr (mgmt controller device locator) min size", len(data), minSize) } s := &SDRMgmtControllerDeviceLocator{} sdr.MgmtControllerDeviceLocator = s b6, _, _ := unpackUint8(data, 5) s.DeviceSlaveAddress = b6 b7, _, _ := unpackUint8(data, 6) s.ChannelNumber = b7 b8, _, _ := unpackUint8(data, 7) s.ACPISystemPowerStateNotificationRequired = isBit7Set(b8) s.ACPIDevicePowerStateNotificationRequired = isBit6Set(b8) s.ControllerLogsInitializationAgentErrors = isBit3Set(b8) s.LogInitializationAgentErrors = isBit2Set(b8) b9, _, _ := unpackUint8(data, 8) s.DeviceCap_ChassisDevice = isBit7Set(b9) s.DeviceCap_Bridge = isBit6Set(b9) s.DeviceCap_IPMBEventGenerator = isBit5Set(b9) s.DeviceCap_IPMBEventReceiver = isBit4Set(b9) s.DeviceCap_FRUInventoryDevice = isBit3Set(b9) s.DeviceCap_SELDevice = isBit2Set(b9) s.DeviceCap_SDRRepoDevice = isBit1Set(b9) s.DeviceCap_SensorDevice = isBit0Set(b9) s.EntityID, _, _ = unpackUint8(data, 12) s.EntityInstance, _, _ = unpackUint8(data, 13) typeLength, _, _ := unpackUint8(data, 15) s.DeviceIDTypeLength = TypeLength(typeLength) idStrLen := int(s.DeviceIDTypeLength.Length()) if len(data) < minSize+idStrLen { return ErrNotEnoughDataWith("sdr (mgmt controller device locator)", len(data), minSize+idStrLen) } s.DeviceIDBytes, _, _ = unpackBytes(data, minSize, idStrLen) return nil } // 43.10 SDR Type 13h - Management Controller Confirmation Record type SDRMgmtControllerConfirmation struct { // // Record KEY // DeviceSlaveAddress uint8 // 7-bit I2C Slave Address[1] of device on IPMB. DeviceID uint8 ChannelNumber uint8 DeviceRevision uint8 // // RECORD BODY // FirmwareMajorRevision uint8 // [6:0] - Major Firmware Revision, binary encoded. FirmwareMinorRevision uint8 // Minor Firmware Revision. BCD encoded. // IPMI Version from Get Device ID command. Holds IPMI Command Specification // Version. BCD encoded. 00h = reserved. Bits 7:4 hold the Least Significant digit of the // revision, while bits 3:0 hold the Most Significant bits. E.g. a value of 01h indicates // revision 1.0 MajorIPMIVersion uint8 MinorIPMIVersion uint8 ManufacturerID uint32 // 3 bytes only ProductID uint16 DeviceGUID []byte // 16 bytes } func parseSDRManagementControllerConfirmation(data []byte, sdr *SDR) error { const SDRManagementControllerConfirmationSize = 32 minSize := SDRManagementControllerConfirmationSize if len(data) < minSize { return ErrNotEnoughDataWith("sdr (mgmt controller confirmation) min size", len(data), minSize) } s := &SDRMgmtControllerConfirmation{} sdr.MgmtControllerConfirmation = s b6, _, _ := unpackUint8(data, 5) s.DeviceSlaveAddress = b6 s.DeviceID, _, _ = unpackUint8(data, 6) b8, _, _ := unpackUint8(data, 7) s.ChannelNumber = b8 >> 4 s.DeviceRevision = b8 & 0x0f b9, _, _ := unpackUint8(data, 8) s.FirmwareMajorRevision = b9 & 0x7f s.FirmwareMinorRevision, _, _ = unpackUint8(data, 9) ipmiVersionBCD, _, _ := unpackUint8(data, 10) s.MajorIPMIVersion = ipmiVersionBCD & 0x0f s.MinorIPMIVersion = ipmiVersionBCD >> 4 s.ManufacturerID, _, _ = unpackUint24L(data, 11) s.ProductID, _, _ = unpackUint16L(data, 14) s.DeviceGUID, _, _ = unpackBytes(data, 16, 16) return nil } // 43.11 SDR Type 14h - BMC Message Channel Info Record type SDRBMCChannelInfo struct { // // NO Record KEY // // // RECORD BODY // Channel0 ChannelInfo Channel1 ChannelInfo Channel2 ChannelInfo Channel3 ChannelInfo Channel4 ChannelInfo Channel5 ChannelInfo Channel6 ChannelInfo Channel7 ChannelInfo MessagingInterruptType uint8 EventMessageBufferInterruptType uint8 } type ChannelInfo struct { TransmitSupported bool // false means receive message queue access only MessageReceiveLUN uint8 ChannelProtocol uint8 } func parseChannelInfo(b uint8) ChannelInfo { return ChannelInfo{ TransmitSupported: isBit7Set(b), MessageReceiveLUN: (b & 0x7f) >> 4, ChannelProtocol: b & 0x0f, } } func parseSDRBMCMessageChannelInfo(data []byte, sdr *SDR) error { const SDRBMCMessageChannelInfoSize = 16 minSize := SDRBMCMessageChannelInfoSize if len(data) < minSize { return ErrNotEnoughDataWith("sdr (bmc message channel info) min size", len(data), minSize) } s := &SDRBMCChannelInfo{} sdr.BMCChannelInfo = s s.Channel0 = parseChannelInfo(data[5]) s.Channel1 = parseChannelInfo(data[6]) s.Channel2 = parseChannelInfo(data[7]) s.Channel3 = parseChannelInfo(data[8]) s.Channel4 = parseChannelInfo(data[9]) s.Channel5 = parseChannelInfo(data[10]) s.Channel6 = parseChannelInfo(data[11]) s.Channel7 = parseChannelInfo(data[12]) s.MessagingInterruptType, _, _ = unpackUint8(data, 13) s.EventMessageBufferInterruptType, _, _ = unpackUint8(data, 14) return nil } // 43.12 SDR Type C0h - OEM Record type SDROEM struct { // // NO Record KEY // // // RECORD BODY // ManufacturerID uint32 // 3 bytes only OEMData []byte } func parseSDROEM(data []byte, sdr *SDR) error { const SDROEMMinSize = 8 const SDROEMMaxSize = 64 // OEM defined records are limited to a maximum of 64 bytes, including the header if len(data) < SDROEMMinSize { return ErrNotEnoughDataWith("sdr (oem) min size", len(data), SDROEMMinSize) } s := &SDROEM{} sdr.OEM = s s.ManufacturerID, _, _ = unpackUint24L(data, 5) s.OEMData, _, _ = unpackBytesMost(data, 8, SDROEMMaxSize-8) return nil } // 43.6 SDR Type 0Ah:0Fh - Reserved Records type SDRReserved struct { } // 43.15 Type/Length Byte Format // // 7:6 00 = Unicode // 00b define a Unicode string in the IPMI specification, // whereas they specify a binary field in the Platform Management FRU specification. // 01 = BCD plus (see below) // 10 = 6-bit ASCII, packed // 11 = 8-bit ASCII + Latin 1. // At least two bytes of data must be present when this type is used. // Therefore, the length (number of data bytes) will be >1 if data is present, // 0 if data is not present. A length of 1 is reserved. // 5 reserved. // the bit 5 is reserved in the IPMI specification type/length byte, // where it is part of the length field in the Platform Management FRU specification // 4:0 length of following data, in characters. // 00000b indicates 'none following'. // 11111b = reserved. type TypeLength uint8 func (tl TypeLength) String() string { return fmt.Sprintf("Byte: (%#02x) / Type: (%s) / Length: %d / Size: %d", uint8(tl), tl.Type(), tl.Length(), tl.Size()) } func (tl TypeLength) Type() string { typecode := tl.TypeCode() var s string switch typecode { case 0: s = "Binary" case 1: s = "BCD plus" case 2: s = "6-bit ASCII" case 3: s = "8-bit ASCII" } return s } func (tl TypeLength) TypeCode() uint8 { return (uint8(tl) & 0xc0) >> 6 // the highest 2 bits } // Length returns the length of bytes occupied that packed the chars. // But it is not the length of chars. // For BCD plus type, one byte packs two chars. func (tl TypeLength) Length() uint8 { return uint8(tl) & 0x3f // the lowest 6 bits } // Size returns the length of chars. func (tl TypeLength) Size() uint8 { typecode := tl.TypeCode() l := tl.Length() var size uint8 switch typecode { case 0: /* 00b: binary data */ size = l case 1: /* 01b: BCD plus (binary-coded decimal) */ // one byte packs two chars /* hex dump or BCD -> 2x length */ size = l * 2 case 2: /* 10b: 6-bit ASCII packed */ // three bytes packs four chars /* 4 chars per group of 1-3 bytes, round up to 4 bytes boundary */ size = (l/3 + 1) * 4 case 3: /* 11b: 8-bit ASCII + Latin 1 */ /* no length adjustment */ size = l } return size } // Chars decodes the raw bytes to ASCII chars according to the encoding type code of TypeLength func (tl TypeLength) Chars(raw []byte) (chars []byte, err error) { if len(raw) != int(tl.Length()) { err = fmt.Errorf("passed raw not equal to length") return } size := int(tl.Size()) chars = make([]byte, size) switch tl.TypeCode() { case 0: // 00b - Binary for i := 0; i < size; i++ { chars[i] = raw[i] } case 1: // 01b - BCD Plus var bcdPlusChars = [16]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', '-', '.', ':', ',', '_'} for i := 0; i < size; i++ { var charIndex uint8 if i%2 == 0 { charIndex = raw[i/2] >> 0 & 0x0f } else { charIndex = raw[i/2] >> 4 } chars[i] = bcdPlusChars[charIndex] } case 2: // 10b - 6-bit ASCII // 6-bit ASCII definition var ascii6bit = [64]byte{ ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', } var leftover byte var s []byte for i := 0; i < len(raw); i++ { // every 3 bytes pack 4 chars, so we can calculate // character positions in a byte based on the remainder of division by 3. switch i % 3 { case 0: idx := raw[i] & 0x3f // 6 right bits are an index of one char leftover = (raw[i] & 0xc0) >> 6 // 2 left bits are leftovers s = append(s, ascii6bit[idx]) case 1: idx := leftover | (raw[i]&0x0f)<<2 // index of one char is 2-bit leftover as prefix plus 4 right bits leftover = (raw[i] & 0xf0) >> 4 // 4 left bits are leftovers s = append(s, ascii6bit[idx]) case 2: idx := (raw[i]&0x03)<<4 | leftover // index of one char is 2 right bits plus 4-bit leftover as suffix leftover = 0 // cleanup leftover calculation s = append(s, ascii6bit[idx]) idx = (raw[i] & 0xfc) >> 2 // 6 left bits are an index of one char s = append(s, ascii6bit[idx]) } } chars = s case 3: // 11b - 8-bit ASCII for i := 0; i < size; i++ { chars[i] = raw[i] } } return } golang-github-bougou-go-ipmi-0.7.2/types_sdr_others_test.go000066400000000000000000000060121474110527100240730ustar00rootroot00000000000000package ipmi import ( "reflect" "testing" ) func TestTypeLength_Chars(t *testing.T) { t.Parallel() type args struct { raw []byte } tests := []struct { name string tl TypeLength args args wantChars []byte wantErr bool }{ { name: "empty tl & raw", tl: 0x00, args: args{raw: []byte{}}, wantChars: []byte{}, wantErr: false, }, { name: "different length for tl & raw", tl: 0xc0, args: args{raw: []byte{57, 84}}, wantChars: nil, wantErr: true, }, { name: "valid 8-bit ASCII", tl: 0xcd, args: args{raw: []byte{89, 49, 85, 85, 66, 51, 79, 71, 88, 89, 48, 75, 70}}, // cSpell: disable wantChars: []byte("Y1UUB3OGXY0KF"), // cSpell: enable wantErr: false, }, { name: "untrimmed 8-bit ASCII", tl: 0xc8, args: args{raw: []byte{83, 97, 109, 115, 117, 110, 103, 0}}, wantChars: []byte{83, 97, 109, 115, 117, 110, 103, 0}, // "Samsung\0" wantErr: false, }, { // Every 3 bytes contains 4 chars. // 'Y' in 6-bit ASCII is 111001 // Three 'Y's are 01111001 10011110 00000011 name: "3-symbol word (empty 4th char) 6-bit ASCII", tl: 0x83, args: args{raw: []byte{121, 158, 3}}, wantChars: []byte("YYY "), wantErr: false, }, { // Four 'Y's are 01111001 10011110 11100111 name: "4-symbol word (full 3 bytes) 6-bit ASCII", tl: 0x83, args: args{raw: []byte{121, 158, 231}}, wantChars: []byte("YYYY"), wantErr: false, }, { // Five 'Y's are 01111001 10011110 11100111 00111001 name: "5-symbol word (not a multiple of 3 bytes) 6-bit ASCII", tl: 0x84, args: args{raw: []byte{121, 158, 231, 57}}, wantChars: []byte("YYYYY"), wantErr: false, }, { // Six 'Y's are 01111001 10011110 11100111 01111001 00001110 name: "6-symbol word (not a multiple of 3 bytes) 6-bit ASCII", tl: 0x85, args: args{raw: []byte{121, 158, 231, 121, 14}}, wantChars: []byte("YYYYYY"), wantErr: false, }, { // Seven 'Y's are 01111001 10011110 11100111 01111001 10011110 00000011 name: "7-symbol word (empty 8th char) 6-bit ASCII", tl: 0x86, args: args{raw: []byte{121, 158, 231, 121, 158, 3}}, wantChars: []byte("YYYYYYY "), wantErr: false, }, { name: "valid 6-bit ASCII", tl: 0x8a, args: args{raw: []byte{57, 100, 143, 34, 69, 89, 82, 13, 73, 16}}, wantChars: []byte{89, 48, 86, 67, 66, 52, 52, 54, 50, 85, 48, 50, 48}, // Y0VCB4462U020 wantErr: false, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() gotChars, err := tt.tl.Chars(tt.args.raw) if (err != nil) != tt.wantErr { t.Errorf("TypeLength.Chars() error = %v, wantErr %v", err, tt.wantErr) } if !reflect.DeepEqual(gotChars, tt.wantChars) { t.Errorf("TypeLength.Chars() = %#v (%s), want %#v (%s)", gotChars, string(gotChars), tt.wantChars, string(tt.wantChars)) } }) } } golang-github-bougou-go-ipmi-0.7.2/types_sel.go000066400000000000000000000177641474110527100214630ustar00rootroot00000000000000package ipmi import ( "bytes" "fmt" "time" "github.com/olekukonko/tablewriter" ) // 32. SEL Record Formats type SEL struct { // SEL Record IDs 0000h and FFFFh are reserved for functional use and are not legal ID values. // Record IDs are handles. They are not required to be sequential or consecutive. // Applications should not assume that SEL Record IDs will follow any particular numeric ordering. RecordID uint16 RecordType SELRecordType Standard *SELStandard OEMTimestamped *SELOEMTimestamped OEMNonTimestamped *SELOEMNonTimestamped } func (sel *SEL) Pack() []byte { msg := make([]byte, 16) packUint16L(sel.RecordID, msg, 0) packUint8(uint8(sel.RecordType), msg, 2) switch sel.RecordType.Range() { case SELRecordTypeRangeStandard: if sel.Standard != nil { msg = append(msg[0:3], sel.Standard.Pack()...) } case SELRecordTypeRangeTimestampedOEM: if sel.OEMTimestamped != nil { msg = append(msg[0:3], sel.OEMTimestamped.Pack()...) } case SELRecordTypeRangeNonTimestampedOEM: if sel.OEMNonTimestamped != nil { msg = append(msg[0:3], sel.OEMNonTimestamped.Pack()...) } } return msg } func ParseSEL(msg []byte) (*SEL, error) { if len(msg) != 16 { return nil, fmt.Errorf("SEL Record msg should be 16 bytes in length") } recordID, _, _ := unpackUint16L(msg, 0) recordType, _, _ := unpackUint8(msg, 2) sel := &SEL{ RecordID: recordID, RecordType: SELRecordType(recordType), } recordTypeRange := sel.RecordType.Range() switch recordTypeRange { case SELRecordTypeRangeStandard: if err := parseSELDefault(msg, sel); err != nil { return nil, fmt.Errorf("parseSELDefault failed, err: %w", err) } case SELRecordTypeRangeTimestampedOEM: if err := parseSELOEMTimestamped(msg, sel); err != nil { return nil, fmt.Errorf("parseSELOEMTimestamped failed, err: %w", err) } case SELRecordTypeRangeNonTimestampedOEM: if err := parseSELOEMNonTimestamped(msg, sel); err != nil { return nil, fmt.Errorf("parseSELOEMNonTimestamped failed, err: %w", err) } } return sel, nil } // 32.2 OEM SEL Record - Type C0h-DFh type SELOEMTimestamped struct { Timestamp time.Time // Time when event was logged. uint32 LS byte first. ManufacturerID uint32 // only 3 bytes OEMDefined [6]byte } func (oemTimestamped *SELOEMTimestamped) Pack() []byte { var msg = make([]byte, 13) packUint32L(uint32(oemTimestamped.Timestamp.Unix()), msg, 0) packUint24L(oemTimestamped.ManufacturerID, msg, 4) packBytes(oemTimestamped.OEMDefined[:], msg, 7) return msg } type SELOEMNonTimestamped struct { OEM [13]byte } func (oemNonTimestamped *SELOEMNonTimestamped) Pack() []byte { return oemNonTimestamped.OEM[:] } // 32.1 SEL Standard Event Records type SELStandard struct { Timestamp time.Time // Time when event was logged. uint32 LS byte first. GeneratorID GeneratorID // RqSA & LUN if event was generated from IPMB. Software ID if event was generated from system software. EvMRev uint8 // Event Message Revision (format version) SensorType SensorType // Sensor Type Code for sensor that generated the event SensorNumber SensorNumber // Number of sensor that generated the event EventDir EventDir // Event Direction. [7] -0b = Assertion event. 1b = Deassertion event. EventReadingType EventReadingType // Type of trigger for the event. [6:0] - Event Type Code // 29.7 Event Data Field Formats // // The sensor class determines the corresponding Event Data format. // The sensor class can be extracted from EventReadingType. EventData EventData } func (standard *SELStandard) Pack() []byte { var msg = make([]byte, 13) packUint32L(uint32(standard.Timestamp.Unix()), msg, 0) packUint16L(uint16(standard.GeneratorID), msg, 4) packUint8(standard.EvMRev, msg, 6) packUint8(uint8(standard.SensorType), msg, 7) packUint8(uint8(standard.SensorNumber), msg, 8) var eventType = uint8(standard.EventReadingType) if standard.EventDir { eventType = eventType | 0x80 } packUint8(eventType, msg, 9) packUint8(standard.EventData.EventData1, msg, 10) packUint8(standard.EventData.EventData2, msg, 11) packUint8(standard.EventData.EventData3, msg, 12) return msg } // EventString return string description of the event. func (sel *SELStandard) EventString() string { return sel.EventReadingType.EventString(sel.SensorType, sel.EventData) } func (sel *SELStandard) EventSeverity() EventSeverity { return sel.EventReadingType.EventSeverity(sel.SensorType, sel.EventData, sel.EventDir) } func parseSELDefault(msg []byte, sel *SEL) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } var s = &SELStandard{} sel.Standard = s ts, _, _ := unpackUint32L(msg, 3) s.Timestamp = parseTimestamp(ts) gid, _, _ := unpackUint16L(msg, 7) s.GeneratorID = GeneratorID(gid) s.EvMRev, _, _ = unpackUint8(msg, 9) sensorType, _, _ := unpackUint8(msg, 10) s.SensorType = SensorType(sensorType) sensorNumber, _, _ := unpackUint8(msg, 11) s.SensorNumber = SensorNumber(sensorNumber) b, _, _ := unpackUint8(msg, 12) s.EventDir = EventDir(isBit7Set(b)) s.EventReadingType = EventReadingType(b & 0x7f) // clear bit 7 s.EventData.EventData1, _, _ = unpackUint8(msg, 13) s.EventData.EventData2, _, _ = unpackUint8(msg, 14) s.EventData.EventData3, _, _ = unpackUint8(msg, 15) return nil } func parseSELOEMTimestamped(msg []byte, sel *SEL) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } var s = &SELOEMTimestamped{} sel.OEMTimestamped = s ts, _, _ := unpackUint32L(msg, 3) s.Timestamp = parseTimestamp(ts) id, _, _ := unpackUint24L(msg, 7) s.ManufacturerID = id s.OEMDefined = [6]byte{} b, _, _ := unpackBytes(msg, 10, 6) for i := 0; i < 6; i++ { s.OEMDefined[i] = b[i] } return nil } func parseSELOEMNonTimestamped(msg []byte, sel *SEL) error { if len(msg) < 16 { return ErrUnpackedDataTooShortWith(len(msg), 16) } var s = &SELOEMNonTimestamped{} sel.OEMNonTimestamped = s s.OEM = [13]byte{} b, _, _ := unpackBytes(msg, 3, 13) for i := 0; i < 6; i++ { s.OEM[i] = b[i] } return nil } // FormatSELs print sel records in table format. // The second sdrMap is optional. If the sdrMap is not nil, // it will also print sensor number, entity id and instance, and asserted discrete states. // The sdrMap can be fetched by GetSDRsMap method. func FormatSELs(records []*SEL, sdrMap SDRMapBySensorNumber) string { var elistMode bool // extend list if sdrMap != nil { elistMode = true } var buf = new(bytes.Buffer) table := tablewriter.NewWriter(buf) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) headers := []string{ "ID", "RecordType", "EvmRev", "Timestamp", "GID", "SensorNumber", "SensorTypeCode", "SensorType", "EventReadingType", "EventReadingType", "EventDescription", "EventDir", "EventSeverity", "EventData", } if elistMode { headers = append(headers, "SensorName") } table.SetHeader(headers) table.SetFooter(headers) for _, sel := range records { recordTypeRange := sel.RecordType.Range() switch recordTypeRange { case SELRecordTypeRangeStandard: s := sel.Standard rowContent := []string{ fmt.Sprintf("%#04x", sel.RecordID), sel.RecordType.String(), fmt.Sprintf("%#02x", s.EvMRev), fmt.Sprintf("%v", s.Timestamp), fmt.Sprintf("%#04x", s.GeneratorID), fmt.Sprintf("%#02x", s.SensorNumber), fmt.Sprintf("%#02x", uint8(s.SensorType)), s.SensorType.String(), fmt.Sprintf("%#02x", uint8(s.EventReadingType)), s.EventReadingType.String(), s.EventString(), s.EventDir.String(), string(s.EventSeverity()), s.EventData.String(), } if elistMode { var sensorName string sdr, ok := sdrMap[s.GeneratorID][s.SensorNumber] if !ok { sensorName = fmt.Sprintf("N/A %#04x, %#02x", s.GeneratorID, s.SensorNumber) } else { sensorName = sdr.SensorName() } rowContent = append(rowContent, sensorName) } table.Append(rowContent) case SELRecordTypeRangeTimestampedOEM: case SELRecordTypeRangeNonTimestampedOEM: } } table.Render() return buf.String() } golang-github-bougou-go-ipmi-0.7.2/types_sensor.go000066400000000000000000001163621474110527100222030ustar00rootroot00000000000000package ipmi import ( "bytes" "fmt" "math" "strings" "github.com/olekukonko/tablewriter" ) // 42.1 // Sensors are classified according to the type of readings they provide and/or the type of events they generate. // // Three sensor classes: threshold, discrete, oem // (oem is a special case of discrete) // // A sensor can return either an analog or discrete readings. Sensor events can be discrete or threshold-based. // Valid sensorclass string values are: // "N/A", "threshold", "discrete", "oem" type SensorClass string const ( SensorClassNotApplicable SensorClass = "N/A" // 不适用的 SensorClassThreshold SensorClass = "threshold" // 离散 multiple states possible // Discrete sensors can contain up to 15 possible states. // It is possible for a discrete sensor to have more than one state active at a time SensorClassDiscrete SensorClass = "discrete" // A digital sensor is not really a unique class, but a term commonly used to refer to // special case of a discrete sensor that only has two possible states // SensorClassDigitalDiscrete SensorClass = "digital-discrete" // Special case of discrete where the meaning of the states (offsets) are OEM defined. SensorClassOEM SensorClass = "oem" ) // 41.1 Sensor Type Code // 42.2 Sensor Type Codes and Data type SensorType uint8 func (c SensorType) String() string { s, ok := sensorTypeMap[c] if ok { return s } return "unknown" } const ( SensorTypeReserved SensorType = 0x00 SensorTypeTemperature SensorType = 0x01 // 温度传感器 SensorTypeVoltage SensorType = 0x02 // 电压传感器 SensorTypeCurrent SensorType = 0x03 // 电流传感器 SensorTypeFan SensorType = 0x04 // 风扇传感器 SensorTypePhysicalSecurity SensorType = 0x05 // Chassis Intrusion SensorTypePlatformSecurity SensorType = 0x06 SensorTypeProcessor SensorType = 0x07 SensorTypePowerSupply SensorType = 0x08 SensorTypePowerUnit SensorType = 0x09 SensorTypeCollingDevice SensorType = 0x0a SensorTypeOtherUnitsbased SensorType = 0x0b SensorTypeMemory SensorType = 0x0c SensorTypeDriveSlot SensorType = 0x0d SensorTypePostMemoryResize SensorType = 0x0e SensorTypeSystemFirmwareProgress SensorType = 0x0f SensorTypeEventLoggingDisabled SensorType = 0x10 SensorTypeWatchdog1 SensorType = 0x11 SensorTypeSystemEvent SensorType = 0x12 SensorTypeCriticalInterrupt SensorType = 0x13 SensorTypeButtonSwitch SensorType = 0x14 SensorTypeModuleBoard SensorType = 0x15 SensorTypeMicrocontrollerCoprocessor SensorType = 0x16 SensorTypeAddinCard SensorType = 0x17 SensorTypeChassis SensorType = 0x18 SensorTypeChipSet SensorType = 0x19 SensorTypeOtherFRU SensorType = 0x1a SensorTypeCableInterconnect SensorType = 0x1b SensorTypeTerminator SensorType = 0x1c SensorTypeSystemBootRestartInitiated SensorType = 0x1d SensorTypeBootError SensorType = 0x1e SensorTypeBaseOSBootInstallationStatus SensorType = 0x1f SensorTypeOSStopShutdown SensorType = 0x20 SensorTypeSlotConnector SensorType = 0x21 SensorTypeSystemACPIPowerState SensorType = 0x22 SensorTypeWatchdog2 SensorType = 0x23 SensorTypePlatformAlert SensorType = 0x24 SensorTypeEntityPresence SensorType = 0x25 SensorTypeMonitorASIC SensorType = 0x26 SensorTypeLAN SensorType = 0x27 SensorTypeManagementSubsystemHealth SensorType = 0x28 SensorTypeBattery SensorType = 0x29 SensorTypeSessionAudit SensorType = 0x2a SensorTypeVersionChange SensorType = 0x2b SensorTypeFRUState SensorType = 0x2c // Reserved: 0x2D - 0xBF // OEM Reserved: 0xC0 - 0xFF ) var sensorTypeMap = map[SensorType]string{ 0x00: "Reserved", 0x01: "Temperature", 0x02: "Voltage", 0x03: "Current", 0x04: "Fan", 0x05: "Physical Security", 0x06: "Platform Security", 0x07: "Processor", 0x08: "Power Supply", 0x09: "Power Unit", 0x0a: "Cooling Device", 0x0b: "Other", 0x0c: "Memory", 0x0d: "Drive Slot / Bay", 0x0e: "POST Memory Resize", 0x0f: "System Firmwares", 0x10: "Event Logging Disabled", 0x11: "Watchdog1", 0x12: "System Event", 0x13: "Critical Interrupt", 0x14: "Button", 0x15: "Module / Board", 0x16: "Microcontroller", 0x17: "Add-in Card", 0x18: "Chassis", 0x19: "Chip Set", 0x1a: "Other FRU", 0x1b: "Cable / Interconnect", 0x1c: "Terminator", 0x1d: "System Boot Initiated", 0x1e: "Boot Error", 0x1f: "OS Boot", 0x20: "OS Critical Stop", 0x21: "Slot / Connector", 0x22: "System ACPI Power State", 0x23: "Watchdog2", 0x24: "Platform Alert", 0x25: "Entity Presence", 0x26: "Monitor ASIC", 0x27: "LAN", 0x28: "Management Subsys Health", 0x29: "Battery", 0x2a: "Session Audit", 0x2b: "Version Change", 0x2c: "FRU State", } func SensorTypeFromNameOrNumber(sensorTypeNameOrNumber string) (SensorType, error) { sensorTypeNumber, err := parseStringToInt64(sensorTypeNameOrNumber) if err == nil { // arg is number _, exists := sensorTypeMap[SensorType(sensorTypeNumber)] if exists { return SensorType(sensorTypeNumber), nil } return SensorTypeReserved, fmt.Errorf("unknown sensor type number: %s", sensorTypeNameOrNumber) } for number, name := range sensorTypeMap { if name == sensorTypeNameOrNumber { return SensorType(number), nil } } return SensorTypeReserved, fmt.Errorf("unknown sensor type name: %s", sensorTypeNameOrNumber) } // 43.17 Sensor Unit Type Codes type SensorUnitType uint8 const ( SensorUnitType_Unspecified SensorUnitType = 0 // unspecified SensorUnitType_DegreesC SensorUnitType = 1 // degrees C, Celsius, 摄氏度 ℃ SensorUnitType_DegreesF SensorUnitType = 2 // degrees F, Fahrenheit, 华氏度 SensorUnitType_DegreesK SensorUnitType = 3 // degrees K, Kelvins, 开尔文 SensorUnitType_Volts SensorUnitType = 4 // Volts, 伏特(电压单位) SensorUnitType_Amps SensorUnitType = 5 // Amps, 安培数 SensorUnitType_Watts SensorUnitType = 6 // Watts, 瓦特(功率单位) SensorUnitType_Joules SensorUnitType = 7 // Joules, 焦耳 SensorUnitType_Coulombs SensorUnitType = 8 // Coulombs, 库伦 SensorUnitType_VA SensorUnitType = 9 // VA, 伏安 SensorUnitType_Nits SensorUnitType = 10 // Nits, 尼特(光度单位) SensorUnitType_Lumen SensorUnitType = 11 // lumen, 流明(光通量单位) SensorUnitType_Lux SensorUnitType = 12 // lux, 勒克斯(照明单位) SensorUnitType_Candela SensorUnitType = 13 // Candela, 坎, 坎德拉(发光强度单位) SensorUnitType_KPa SensorUnitType = 14 // kPa kilopascal, 千帕, 千帕斯卡 SensorUnitType_PSI SensorUnitType = 15 // PSI SensorUnitType_Newton SensorUnitType = 16 // Newton, 牛顿(力的单位) SensorUnitType_CFM SensorUnitType = 17 // CFM, 风量, cubic feet per minute (cu ft/min) SensorUnitType_RPM SensorUnitType = 18 // RPM, 每分钟转数, Revolutions per minute, is the number of turns in one minute SensorUnitType_Hz SensorUnitType = 19 // Hz, 赫兹 SensorUnitType_MicroSecond SensorUnitType = 20 // microsecond, 微秒 SensorUnitType_MilliSecond SensorUnitType = 21 // millisecond, 毫秒 SensorUnitType_Second SensorUnitType = 22 // second, 秒 SensorUnitType_Minute SensorUnitType = 23 // minute, 分 SensorUnitType_Hour SensorUnitType = 24 // hour, 时 SensorUnitType_Day SensorUnitType = 25 // day, 日 SensorUnitType_Week SensorUnitType = 26 // week, 周 SensorUnitType_Mil SensorUnitType = 27 // mil, 毫升;密耳(千分之一寸) SensorUnitType_Inches SensorUnitType = 28 // inches, 英寸(inch的复数) SensorUnitType_Fleet SensorUnitType = 29 // feet SensorUnitType_CuIn SensorUnitType = 30 // cu in, 立方英寸(cubic inch) SensorUnitType_CuFleet SensorUnitType = 31 // cu feet SensorUnitType_MM SensorUnitType = 32 // mm, 毫米(millimeter) SensorUnitType_CM SensorUnitType = 33 // cm, 厘米(centimeter) SensorUnitType_M SensorUnitType = 34 // m, 米 SensorUnitType_CuCM SensorUnitType = 35 // cu cm SensorUnitType_Cum SensorUnitType = 36 // cum SensorUnitType_Liters SensorUnitType = 37 // liters, 公升(容量单位) SensorUnitType_FluidOunce SensorUnitType = 38 // fluid ounce, 液盎司(液体容量单位, 等于 fluidounce) SensorUnitType_Radians SensorUnitType = 39 // radians, 弧度(radian的复数) SensorUnitType_vSteradians SensorUnitType = 40 // steradians, 球面度, 立体弧度(立体角国际单位制, 等于 sterad) SensorUnitType_Revolutions SensorUnitType = 41 // revolutions, 转数(revolution的复数形式) SensorUnitType_Cycles SensorUnitType = 42 // cycles, 周期, 圈 SensorUnitType_Gravities SensorUnitType = 43 // gravities, 重力 SensorUnitType_Ounce SensorUnitType = 44 // ounce, 盎司 SensorUnitType_Pound SensorUnitType = 45 // pound, 英镑 SensorUnitType_FootPound SensorUnitType = 46 // ft-lb, 英尺-磅(foot pound) SensorUnitType_OzIn SensorUnitType = 47 // oz-in, 扭力;盎司英寸 SensorUnitType_Gauss SensorUnitType = 48 // gauss, 高斯(磁感应或磁场的单位) SensorUnitType_Gilberts SensorUnitType = 49 // gilberts, 吉伯(磁通量的单位) SensorUnitType_Henry SensorUnitType = 50 // henry, 亨利(电感单位) SensorUnitType_MilliHenry SensorUnitType = 51 // millihenry, 毫亨(利)(电感单位) SensorUnitType_Farad SensorUnitType = 52 // farad, 法拉(电容单位) SensorUnitType_MicroFarad SensorUnitType = 53 // microfarad, 微法拉(电容量的实用单位) SensorUnitType_Ohms SensorUnitType = 54 // ohms, 欧姆(Ohm) :电阻的量度单位, 欧姆值越大, 电阻越大 SensorUnitType_Siemens SensorUnitType = 55 // siemens, 西门子, 电导单位 SensorUnitType_Mole SensorUnitType = 56 // mole, 摩尔 [化学] 克分子(等于mole) SensorUnitType_Becquerel SensorUnitType = 57 // becquerel, 贝可(放射性活度单位) SensorUnitType_PPM SensorUnitType = 58 // PPM (parts/million), 百万分率, 百万分之…(parts per million) SensorUnitType_Reserved SensorUnitType = 59 // reserved SensorUnitType_Decibels SensorUnitType = 60 // Decibels, 分贝(声音强度单位, decibel的复数) SensorUnitType_DbA SensorUnitType = 61 // DbA, dBA is often used to specify the loudness of the fan used to cool the microprocessor and associated components. Typical dBA ratings are in the neighborhood of 25 dBA, representing 25 A-weighted decibels above the threshold of hearing. This is approximately the loudness of a person whispering in a quiet room. SensorUnitType_DbC SensorUnitType = 62 // DbC SensorUnitType_Gray SensorUnitType = 63 // gray, 核吸收剂量(Gy) SensorUnitType_Sievert SensorUnitType = 64 // sievert, 希沃特(辐射效果单位, 简称希) SensorUnitType_ColorTempDegK SensorUnitType = 65 // color temp deg K, 色温 SensorUnitType_Bit SensorUnitType = 66 // bit, 比特(二进位制信息单位) SensorUnitType_Kilobit SensorUnitType = 67 // kilobit, 千比特 SensorUnitType_Megabit SensorUnitType = 68 // megabit, 兆比特 SensorUnitType_Gigabit SensorUnitType = 69 // gigabit, 吉比特 SensorUnitType_Byte SensorUnitType = 70 // byte, 字节 SensorUnitType_Kilobyte SensorUnitType = 71 // kilobyte, 千字节 SensorUnitType_Megabyte SensorUnitType = 72 // megabyte, 兆字节 SensorUnitType_Gigabyte SensorUnitType = 73 // gigabyte, 吉字节 SensorUnitType_Word SensorUnitType = 74 // word (data), 字 SensorUnitType_DWord SensorUnitType = 75 // dword, 双字 SensorUnitType_QWord SensorUnitType = 76 // qword, 四字 SensorUnitType_Line SensorUnitType = 77 // line (re. mem. line) SensorUnitType_Hit SensorUnitType = 78 // hit, 命中 SensorUnitType_Miss SensorUnitType = 79 // miss, 未击中, 未命中 SensorUnitType_Retry SensorUnitType = 80 // retry, 重试(次数) SensorUnitType_Reset SensorUnitType = 81 // reset, 重置(次数) SensorUnitType_Overrun SensorUnitType = 82 // overrun) / overflow 满载, 溢出(次数) SensorUnitType_Underrun SensorUnitType = 83 // underrun 欠载 SensorUnitType_Collision SensorUnitType = 84 // collision, 冲突 SensorUnitType_Packet SensorUnitType = 85 // packets, 包, 数据包 SensorUnitType_Message SensorUnitType = 86 // messages, 消息 SensorUnitType_Characters SensorUnitType = 87 // characters, 字符 SensorUnitType_Error SensorUnitType = 88 // error, 错误 SensorUnitType_CorrectableError SensorUnitType = 89 // correctable error 可校正错误 SensorUnitType_UncorrectableError SensorUnitType = 90 // uncorrectable error 不可校正错误 SensorUnitType_FatalError SensorUnitType = 91 // fatal error, 致命错误, 不可恢复的错误 SensorUnitType_Grams SensorUnitType = 92 // grams, 克(gram的复数形式) ) func (u SensorUnitType) String() string { s, ok := sensorUnitMap[u] if ok { return s } return "" } var sensorUnitMap = map[SensorUnitType]string{ 0: "unspecified", 1: "degrees C", 2: "degrees F", 3: "degrees K", 4: "Volts", 5: "Amps", 6: "Watts", 7: "Joules", 8: "Coulombs", 9: "VA", 10: "Nits", 11: "lumen", 12: "lux", 13: "Candela", 14: "kPa", 15: "PSI", 16: "Newton", 17: "CFM", 18: "RPM", 19: "Hz", 20: "microsecond", 21: "millisecond", 22: "second", 23: "minute", 24: "hour", 25: "day", 26: "week", 27: "mil", 28: "inches", 29: "feet", 30: "cu in", 31: "cu feet", 32: "mm", 33: "cm", 34: "m", 35: "cu cm", 36: "cu m", 37: "liters", 38: "fluid ounce", 39: "radians", 40: "steradians", 41: "revolutions", 42: "cycles", 43: "gravities", 44: "ounce", 45: "pound", 46: "ft-lb", 47: "oz-in", 48: "gauss", 49: "gilberts", 50: "henry", 51: "millihenry", 52: "farad", 53: "microfarad", 54: "ohms", 55: "siemens", 56: "mole", 57: "becquerel", 58: "PPM", 59: "reserved", 60: "Decibels", 61: "DbA", 62: "DbC", 63: "gray", 64: "sievert", 65: "color temp deg K", 66: "bit", 67: "kilobit", 68: "megabit", 69: "gigabit", 70: "byte", 71: "kilobyte", 72: "megabyte", 73: "gigabyte", 74: "word", 75: "dword", 76: "qword", 77: "line", 78: "hit", 79: "miss", 80: "retry", 81: "reset", 82: "overflow", 83: "underrun", 84: "collision", 85: "packets", 86: "messages", 87: "characters", 88: "error", 89: "correctable error", 90: "uncorrectable error", 91: "fatal error", 92: "grams", } // SensorThresholdType are enums for types of threshold type SensorThresholdType string const ( SensorThresholdType_LNC SensorThresholdType = "LowerNonCritical" SensorThresholdType_LCR SensorThresholdType = "LowerCritical" SensorThresholdType_LNR SensorThresholdType = "LowerNonRecoverable" SensorThresholdType_UNC SensorThresholdType = "UpperNonCritical" SensorThresholdType_UCR SensorThresholdType = "UpperCritical" SensorThresholdType_UNR SensorThresholdType = "UpperNonRecoverable" ) func (sensorThresholdType SensorThresholdType) Abbr() string { m := map[SensorThresholdType]string{ SensorThresholdType_LNC: "lnc", SensorThresholdType_LCR: "lcr", SensorThresholdType_LNR: "lnr", SensorThresholdType_UNC: "unc", SensorThresholdType_UCR: "ucr", SensorThresholdType_UNR: "unr", } s, ok := m[sensorThresholdType] if ok { return s } return "" } type SensorThresholdTypes []SensorThresholdType func (types SensorThresholdTypes) Strings() []string { out := []string{} for _, v := range types { out = append(out, v.Abbr()) } return out } // SensorThresholdStatus are enums for threshold status of sensor. // // ....UNR status (NonRecoverable) // -----------------UNR threshold // ....UCR status (Critical) // -----------------UCR threshold // ....UNC status (NonCritical) // -----------------UNC threshold // ....OK status (OK) // -----------------LNC threshold // ....LNC status (NonCritical) // -----------------LCR threshold // ....LCR status (Critical) // -----------------LNR threshold // ....LNR status (NonRecoverable) type SensorThresholdStatus string const ( SensorThresholdStatus_OK = "ok" SensorThresholdStatus_LNC = "lnc" SensorThresholdStatus_LCR = "lcr" SensorThresholdStatus_LNR = "lnr" SensorThresholdStatus_UNC = "unc" SensorThresholdStatus_UCR = "ucr" SensorThresholdStatus_UNR = "unr" ) type SensorStatus string const ( // SensorStatusOK means okay (the sensor is present and operating correctly) SensorStatusOK = "OK" // SensorStatusNoSensor means no sensor (corresponding reading will say disabled or Not Readable) SensorStatusNoSensor = "N/A" // SensorStatusNonCritical means non-critical error (lower or upper) SensorStatusNonCritical = "NC" // SensorStatusCritical means critical error (lower or upper) SensorStatusCritical = "CR" // SensorStatusNonRecoverable means non-recoverable error (lower or upper) SensorStatusNonRecoverable = "NR" ) // SensorThreshold holds all values and attributes of a specified threshold type. type SensorThreshold struct { // type of threshold Type SensorThresholdType Mask Mask_Threshold // threshold raw reading value before conversion Raw uint8 } // LinearizationFunc is linearization function used in "Sensor Reading Conversion Formula" // 线性化函数 type LinearizationFunc uint8 const ( LinearizationFunc_Linear LinearizationFunc = 0x00 LinearizationFunc_LN LinearizationFunc = 0x01 LinearizationFunc_LOG10 LinearizationFunc = 0x02 LinearizationFunc_LOG2 LinearizationFunc = 0x03 LinearizationFunc_E LinearizationFunc = 0x04 LinearizationFunc_EXP10 LinearizationFunc = 0x05 LinearizationFunc_EXP2 LinearizationFunc = 0x06 LinearizationFunc_1X LinearizationFunc = 0x07 LinearizationFunc_SQR LinearizationFunc = 0x08 LinearizationFunc_CUBE LinearizationFunc = 0x09 LinearizationFunc_SQRT LinearizationFunc = 0x0a LinearizationFunc_CBRT LinearizationFunc = 0x0b // 70h = non-linear. // 71h-7Fh = non-linear OEM LinearizationFunc_NonLinear LinearizationFunc = 0x70 ) func (l LinearizationFunc) IsNonLinear() bool { if uint8(l) >= 0x70 && uint8(l) <= 0x7f { return true } return false } func (l LinearizationFunc) String() string { m := map[LinearizationFunc]string{ 0x00: "linear", 0x01: "ln", 0x02: "log10", 0x03: "log2", 0x04: "e", 0x05: "exp10", 0x06: "exp2", 0x07: "1/x", 0x08: "sqr(x)", // 平方 sqr(3) = 9 0x09: "cube(x)", // 立方 cube(3) = 27 0x0a: "sqrt(x)", // 平方根 sqrt(9) = 3 0x0b: "cbrt(x)", // 立方根 cbrt(27) = 3 } s, ok := m[l] if ok { return fmt.Sprintf("%s(%d)", s, uint8(l)) } return fmt.Sprintf("(%d)", uint8(l)) } // Apply applies linearization func (itself) to the input value and returns the result. func (l LinearizationFunc) Apply(x float64) float64 { switch l { case LinearizationFunc_LN: return math.Log(float64(x)) case LinearizationFunc_LOG10: return math.Log10(float64(x)) case LinearizationFunc_LOG2: return math.Log2(float64(x)) case LinearizationFunc_E: return math.Pow(math.E, float64(x)) case LinearizationFunc_EXP10: return math.Pow10(int(x)) case LinearizationFunc_EXP2: return math.Exp2(float64(x)) case LinearizationFunc_1X: return math.Pow(float64(x), -1) case LinearizationFunc_SQR: return math.Pow(float64(x), 2.0) case LinearizationFunc_CUBE: return math.Pow(float64(x), 3.0) case LinearizationFunc_SQRT: return math.Sqrt(float64(x)) case LinearizationFunc_CBRT: return math.Cbrt(float64(x)) case LinearizationFunc_Linear: // `linear means y=f(x)=x`, nothing to do default: // other values mean sensor is non-linear, also no linearization function is applied. (see 36.2 third paragraph) } return x } type SensorUnit struct { AnalogDataFormat SensorAnalogUnitFormat RateUnit SensorRateUnit ModifierRelation SensorModifierRelation Percentage bool // Percentage 0b = no, 1b = yes BaseUnit SensorUnitType ModifierUnit SensorUnitType } func (unit SensorUnit) String() string { if !unit.IsAnalog() { return "discrete" } // return unit.BaseUnit.String() var percentageStr string if unit.Percentage { percentageStr = "% " } switch unit.ModifierRelation { case SensorModifierRelation_Div: return fmt.Sprintf("%s%s/%s", percentageStr, unit.BaseUnit, unit.ModifierUnit) case SensorModifierRelation_Mul: return fmt.Sprintf("%s%s*%s", percentageStr, unit.BaseUnit, unit.ModifierUnit) // SensorModifierRelation_None: default: if unit.BaseUnit == SensorUnitType_Unspecified && unit.Percentage { return "percent" } return fmt.Sprintf("%s%s", percentageStr, unit.BaseUnit) } } func (unit SensorUnit) IsAnalog() bool { return unit.AnalogDataFormat != SensorAnalogUnitFormat_NotAnalog } type SensorAnalogUnitFormat uint8 const ( SensorAnalogUnitFormat_Unsigned SensorAnalogUnitFormat = 0 // unsigned SensorAnalogUnitFormat_1sComplement SensorAnalogUnitFormat = 1 // 1's complement (signed) SensorAnalogUnitFormat_2sComplement SensorAnalogUnitFormat = 2 // 2's complement (signed) SensorAnalogUnitFormat_NotAnalog SensorAnalogUnitFormat = 3 // does not return analog (numeric) reading ) func (format SensorAnalogUnitFormat) String() string { m := map[SensorAnalogUnitFormat]string{ 0: "unsigned", 1: "1s comp", 2: "2s comp", 3: "not analog", } s, ok := m[format] if ok { return s } return "unknown" } type SensorRateUnit uint8 const ( SensorRateUnit_None SensorRateUnit = 0 SensorRateUnit_PerMicroSec SensorRateUnit = 1 SensorRateUnit_PerMilliSec SensorRateUnit = 2 SensorRateUnit_PerSec SensorRateUnit = 3 SensorRateUnit_PerMin SensorRateUnit = 4 SensorRateUnit_PerHour SensorRateUnit = 5 SensorRateUnit_PerDay SensorRateUnit = 6 SensorRateUnit_Reserved SensorRateUnit = 7 ) func (unit SensorRateUnit) String() string { m := map[SensorRateUnit]string{ 0: "none", 1: "per µS", 2: "per ms", 3: "per s", 4: "per minute", 5: "per hour", 6: "per day", 7: "reserved", } s, ok := m[unit] if ok { return s } return "" } type SensorModifierRelation uint8 const ( SensorModifierRelation_None SensorModifierRelation = 0 SensorModifierRelation_Div SensorModifierRelation = 1 // Basic Unit / Modifier Unit SensorModifierRelation_Mul SensorModifierRelation = 2 // Basic Unit * Modifier Unit ) func (unit SensorModifierRelation) String() string { m := map[SensorModifierRelation]string{ 0: "none", 1: "div", 2: "mul", 3: "reserved", } s, ok := m[unit] if ok { return s } return "" } // SensorEventMessageControl indicates whether this sensor generates Event Messages, // and if so, what type of Event Message control is offered. type SensorEventMessageControl uint8 const ( // per threshold/discrete-state event enable/disable control (implies // that entire sensor and global disable are also supported) SensorEventMessageControl_PerThresholdState SensorEventMessageControl = 0 // entire sensor only (implies that global disable is also supported) SensorEventMessageControl_EntireSensorOnly SensorEventMessageControl = 1 // global disable only SensorEventMessageControl_GlobalDisableOnly SensorEventMessageControl = 2 // no events from sensor SensorEventMessageControl_NoEvents SensorEventMessageControl = 3 ) func (a SensorEventMessageControl) String() string { switch a { case 0: return "Per-threshold" case 1: return "Entire Sensor Only" case 2: return "Global Disable Only" case 3: return "No Events From Sensor" default: return "" } } // SensorThresholdAccess represents the access mode for the threshold value of the sensor. type SensorThresholdAccess uint8 const ( // no thresholds. SensorThresholdAccess_No SensorThresholdAccess = 0 // thresholds are readable, per Reading Mask SensorThresholdAccess_Readable SensorThresholdAccess = 1 // thresholds are readable and settable, per Reading Mask and Settable Threshold Mask, respectively. SensorThresholdAccess_ReadableSettable SensorThresholdAccess = 2 // Fixed, unreadable, thresholds. // Which thresholds are supported is reflected by the Reading Mask. // The threshold value fields report the values that are hard-coded in the sensor. SensorThresholdAccess_Fixed SensorThresholdAccess = 3 ) func (a SensorThresholdAccess) String() string { switch a { case 0: return "No" case 1: return "Readable" case 2: return "ReadableSettable" case 3: return "FixedUnreadable" default: return "" } } // SensorHysteresisAccess represents the access mode for the hysteresis value of the sensor. type SensorHysteresisAccess uint8 const ( // No hysteresis, or hysteresis built-in but not specified SensorHysteresisAccess_No SensorHysteresisAccess = 0 // hysteresis is readable. SensorHysteresisAccess_Readable SensorHysteresisAccess = 1 // hysteresis is readable and settable. SensorHysteresisAccess_ReadableSettable SensorHysteresisAccess = 2 // Fixed, unreadable, hysteresis. Hysteresis fields values implemented in the sensor. SensorHysteresisAccess_Fixed SensorHysteresisAccess = 3 ) func (a SensorHysteresisAccess) String() string { switch a { case 0: return "No" case 1: return "Readable" case 2: return "ReadableSettable" case 3: return "FixedUnreadable" default: return "" } } // ReadingFactors is used in "Sensor Reading Conversion Formula" // Only Full SDR defines reading factors. // see: 36.3 Sensor Reading Conversion Formula type ReadingFactors struct { M int16 // 10 bits used // in +/- ½ raw counts Tolerance uint8 // 6 bits used B int16 // 10 bits used // Unsigned, 10-bit Basic Sensor Accuracy in 1/100 percent scaled up by unsigned Accuracy exponent. Accuracy uint16 // 10 bits, unsigned Accuracy_Exp uint8 // 2 bits, unsigned // [7:4] - R (result) exponent 4 bits, 2's complement, signed // [3:0] - B exponent 4 bits, 2's complement, signed R_Exp int8 // 4 bits, signed, also called K2 B_Exp int8 // 4 bits, signed, also called K1 } func (f ReadingFactors) String() string { return fmt.Sprintf("M: (%d), T: (%d), B: (%d), A: (%d), A_Exp: (%d), R_Exp: (%d), B_Exp: (%d)", f.M, f.Tolerance, f.B, f.Accuracy, f.Accuracy_Exp, f.R_Exp, f.B_Exp) } // The raw analog data is unpacked as an unsigned integer. // But whether it is a positive number (>0) or negative number (<0) is determined // by the "analog data format" field (SensorUnit.AnalogDataFormat) func AnalogValue(raw uint8, format SensorAnalogUnitFormat) int32 { switch format { case SensorAnalogUnitFormat_NotAnalog: return int32(raw) case SensorAnalogUnitFormat_Unsigned: return int32(raw) case SensorAnalogUnitFormat_1sComplement: return int32(onesComplement(uint32(raw), 8)) case SensorAnalogUnitFormat_2sComplement: return int32(twosComplement(uint32(raw), 8)) } return int32(raw) } // ConvertReading converts raw sensor reading or raw sensor threshold value to real value in the desired units for the sensor. // // see: 36.3 Sensor Reading Conversion Formula // // INPUT: raw (unsigned) // -- APPLY: analogDataFormat // --> GOT: analog (signed) // -- APPLY: factors/linearization // --> GOT: converted (float64) func ConvertReading(raw uint8, analogDataFormat SensorAnalogUnitFormat, factors ReadingFactors, linearizationFunc LinearizationFunc) float64 { // y = L[(Mx + (B * 10^B_Exp) ) * 10^R_Exp ] units analog := AnalogValue(raw, analogDataFormat) x := float64(analog) M := float64(factors.M) B := float64(factors.B) Bexp := math.Pow(10, float64(factors.B_Exp)) Rexp := math.Pow(10, float64(factors.R_Exp)) y := (M*x + B*Bexp) * Rexp return linearizationFunc.Apply(y) } // ConvertSensorHysteresis converts raw sensor hysteresis value to real value in the desired units for the sensor. // // see: 36.3 Sensor Reading Conversion Formula func ConvertSensorHysteresis(raw uint8, analogDataFormat SensorAnalogUnitFormat, factors ReadingFactors, linearizationFunc LinearizationFunc) float64 { // y = L[(Mx + (B * 10^B_Exp) ) * 10^R_Exp ] units analog := AnalogValue(raw, analogDataFormat) x := float64(analog) M := float64(factors.M) B := float64(factors.B) Bexp := math.Pow(10, float64(factors.B_Exp)) Rexp := math.Pow(10, float64(factors.R_Exp)) y := (M*x + B*Bexp) * Rexp return linearizationFunc.Apply(y) } // ConvertSensorTolerance converts raw sensor tolerance value to real value in the desired units for the sensor. // // see: 36.4.1 Tolerance func ConvertSensorTolerance(raw uint8, analogDataFormat SensorAnalogUnitFormat, factors ReadingFactors, linearizationFunc LinearizationFunc) float64 { // y = L[Mx/2 * 10^R_Exp ] units. analog := AnalogValue(raw, analogDataFormat) x := float64(analog) M := float64(factors.M) Rexp := math.Pow(10, float64(factors.R_Exp)) y := (M * x / 2) * Rexp return linearizationFunc.Apply(y) } // Sensor holds all attribute of a sensor. type Sensor struct { Number uint8 Name string SDRRecordType SDRRecordType HasAnalogReading bool SensorType SensorType EventReadingType EventReadingType SensorUnit SensorUnit SensorInitialization SensorInitialization SensorCapabilities SensorCapabilities EntityID EntityID EntityInstance EntityInstance scanningDisabled bool // update by GetSensorReading readingAvailable bool // update by GetSensorReading // Raw reading value before conversion Raw uint8 // reading value after conversion Value float64 Threshold struct { Mask Mask_Thresholds // Threshold Status, updated by GetSensorReadingResponse.ThresholdStatus() ThresholdStatus SensorThresholdStatus // Only Full SDR LinearizationFunc LinearizationFunc ReadingFactors LNC_Raw uint8 LCR_Raw uint8 LNR_Raw uint8 UNC_Raw uint8 UCR_Raw uint8 UNR_Raw uint8 LNC float64 LCR float64 LNR float64 UNC float64 UCR float64 UNR float64 PositiveHysteresisRaw uint8 NegativeHysteresisRaw uint8 PositiveHysteresis float64 NegativeHysteresis float64 } Discrete struct { Mask Mask_Discrete ActiveStates Mask_DiscreteEvent // filled by GetSensorReadingResponse optionalData1 uint8 optionalData2 uint8 } OccurredEvents []SensorEvent } func (s *Sensor) String() string { sensorReadingRawStr := fmt.Sprintf("%d", s.Raw) sensorReadingValueStr := fmt.Sprintf("%.3f %s", s.Value, s.SensorUnit) if s.scanningDisabled { sensorReadingRawStr = "Unable to read sensor: Device Not Present" sensorReadingValueStr = "Unable to read sensor: Device Not Present" } return fmt.Sprintf("Sensor ID : %s (%#02x)\n", s.Name, s.Number) + fmt.Sprintf(" Entity ID : %d.%d (%s)\n", uint8(s.EntityID), uint8(s.EntityInstance), s.EntityID) + fmt.Sprintf(" Sensor Type : %s (%#02x) (%s)\n", s.SensorType.String(), uint8(s.SensorType), string(s.EventReadingType.SensorClass())) + fmt.Sprintf(" Sensor Number : %#02x\n", s.Number) + fmt.Sprintf(" Sensor Name : %s\n", s.Name) + fmt.Sprintf(" Sensor Reading (raw) : %s\n", sensorReadingRawStr) + fmt.Sprintf(" Sensor Value : %s\n", sensorReadingValueStr) + fmt.Sprintf(" Sensor Status : %s\n", s.Status()) + fmt.Sprintf(" Sensor Human String : %s\n", s.HumanStr()) } // FormatSensors return a string of table printed for sensors func FormatSensors(extended bool, sensors ...*Sensor) string { var buf = new(bytes.Buffer) table := tablewriter.NewWriter(buf) table.SetAutoWrapText(false) table.SetAlignment(tablewriter.ALIGN_RIGHT) headers := []string{ "SDRType", "SensorNumber", "SensorName", "SensorType", "Reading", "Unit", "Status", "LNR", "LCR", "LNC", "UNC", "UCR", "UNR", } if extended { headers = append(headers, []string{ "EntityID", "EventReadingType", "AnalogDataFormat", "ReadV", "ScanD", "ReadU", "HasAR", "DiscreteEvents", "HumanStr", }...) } table.SetHeader(headers) table.SetFooter(headers) for _, sensor := range sensors { rowContent := []string{ sensor.SDRRecordType.String(), fmt.Sprintf("%#02x", sensor.Number), sensor.Name, fmt.Sprintf("%s (%#02x)", sensor.SensorType.String(), uint8(sensor.SensorType)), sensor.ReadingStr(), sensor.SensorUnit.String(), sensor.Status(), sensor.ThresholdStr(SensorThresholdType_LNR), sensor.ThresholdStr(SensorThresholdType_LCR), sensor.ThresholdStr(SensorThresholdType_LNC), sensor.ThresholdStr(SensorThresholdType_UNC), sensor.ThresholdStr(SensorThresholdType_UCR), sensor.ThresholdStr(SensorThresholdType_UNR), } if extended { rowContent = append(rowContent, []string{ fmt.Sprintf("%s (%#02x)", sensor.EntityID, uint8(sensor.EntityID)), fmt.Sprintf("%s (%#02x)", sensor.EventReadingType.String(), uint8(sensor.EventReadingType)), sensor.SensorUnit.AnalogDataFormat.String(), fmt.Sprintf("%v", sensor.IsReadingValid()), fmt.Sprintf("%v", sensor.scanningDisabled), fmt.Sprintf("%v", !sensor.readingAvailable), fmt.Sprintf("%v", sensor.HasAnalogReading), }...) if sensor.IsThreshold() { rowContent = append(rowContent, "N/A") } else { rowContent = append(rowContent, fmt.Sprintf("%v", sensor.DiscreteActiveEvents())) } rowContent = append(rowContent, sensor.HumanStr()) } table.Append(rowContent) } table.Render() return buf.String() } // IsThreshold returns whether the sensor is threshold sensor class or not. func (sensor *Sensor) IsThreshold() bool { return sensor.EventReadingType.IsThreshold() } func (sensor *Sensor) IsReadingValid() bool { return sensor.readingAvailable } func (sensor *Sensor) IsThresholdAndReadingValid() bool { return sensor.IsThreshold() && sensor.IsReadingValid() } func (sensor *Sensor) IsThresholdReadable(thresholdType SensorThresholdType) bool { if !sensor.IsThreshold() { return false } mask := sensor.Threshold.Mask return mask.IsThresholdReadable(thresholdType) } // ConvertReading converts raw discrete-sensor reading or raw threshold-sensor value to real value in the desired units for the sensor. // // This function can also be applied on raw threshold setting (UNR,UCR,NNC,LNC,LCR,LNR) values. func (sensor *Sensor) ConvertReading(raw uint8) float64 { if sensor.HasAnalogReading { return ConvertReading(raw, sensor.SensorUnit.AnalogDataFormat, sensor.Threshold.ReadingFactors, sensor.Threshold.LinearizationFunc) } return float64(raw) } func (sensor *Sensor) ConvertSensorHysteresis(raw uint8) float64 { if sensor.HasAnalogReading { return ConvertSensorHysteresis(raw, sensor.SensorUnit.AnalogDataFormat, sensor.Threshold.ReadingFactors, sensor.Threshold.LinearizationFunc) } return float64(raw) } func (sensor *Sensor) ConvertSensorTolerance(raw uint8) float64 { if sensor.HasAnalogReading { return ConvertSensorTolerance(raw, sensor.SensorUnit.AnalogDataFormat, sensor.Threshold.ReadingFactors, sensor.Threshold.LinearizationFunc) } return float64(raw) } // SensorThreshold return SensorThreshold for a specified threshold type. func (sensor *Sensor) SensorThreshold(thresholdType SensorThresholdType) SensorThreshold { switch thresholdType { case SensorThresholdType_LNR: return SensorThreshold{ Type: thresholdType, Mask: sensor.Threshold.Mask.LNR, Raw: sensor.Threshold.LNR_Raw, } case SensorThresholdType_LCR: return SensorThreshold{ Type: thresholdType, Mask: sensor.Threshold.Mask.LCR, Raw: sensor.Threshold.LCR_Raw, } case SensorThresholdType_LNC: return SensorThreshold{ Type: thresholdType, Mask: sensor.Threshold.Mask.LNC, Raw: sensor.Threshold.LNC_Raw, } case SensorThresholdType_UNC: return SensorThreshold{ Type: thresholdType, Mask: sensor.Threshold.Mask.UNC, Raw: sensor.Threshold.UNC_Raw, } case SensorThresholdType_UCR: return SensorThreshold{ Type: thresholdType, Mask: sensor.Threshold.Mask.UCR, Raw: sensor.Threshold.UCR_Raw, } case SensorThresholdType_UNR: return SensorThreshold{ Type: thresholdType, Mask: sensor.Threshold.Mask.UNR, Raw: sensor.Threshold.UNR_Raw, } } return SensorThreshold{ Type: thresholdType, } } func (sensor *Sensor) Status() string { if sensor.scanningDisabled { return "N/A" } if !sensor.IsReadingValid() { return "N/A" } if sensor.IsThreshold() { return string(sensor.Threshold.ThresholdStatus) } return fmt.Sprintf("0x%02x%02x", sensor.Discrete.optionalData1, sensor.Discrete.optionalData2) } func (sensor *Sensor) HumanStr() string { if sensor.scanningDisabled { return "N/A" } if !sensor.IsReadingValid() { return "N/A" } if sensor.IsThreshold() { return fmt.Sprintf("%.3f %s", sensor.Value, sensor.SensorUnit) } return strings.Join(sensor.DiscreteActiveEventsString(), ", ") } func (sensor *Sensor) ReadingStr() string { if sensor.scanningDisabled { return "N/A" } if !sensor.IsReadingValid() { return "N/A" } if sensor.IsThreshold() { return fmt.Sprintf("%.3f", sensor.Value) } return fmt.Sprintf("%d", sensor.Raw) } func (sensor *Sensor) ThresholdStr(thresholdType SensorThresholdType) string { if !sensor.IsThresholdReadable(thresholdType) { return "N/A" } var value float64 switch thresholdType { case SensorThresholdType_LCR: value = sensor.Threshold.LCR case SensorThresholdType_LNR: value = sensor.Threshold.LNR case SensorThresholdType_LNC: value = sensor.Threshold.LNC case SensorThresholdType_UCR: value = sensor.Threshold.UCR case SensorThresholdType_UNC: value = sensor.Threshold.UNC case SensorThresholdType_UNR: value = sensor.Threshold.UNR } return fmt.Sprintf("%.3f", value) } func (sensor *Sensor) HysteresisStr(raw uint8) string { switch sensor.SDRRecordType { case SDRRecordTypeFullSensor: if !sensor.SensorUnit.IsAnalog() { if raw == 0x00 || raw == 0xff { return "unspecified" } return fmt.Sprintf("%#02x", raw) } // analog sensor value := sensor.ConvertSensorHysteresis(raw) if raw == 0x00 || raw == 0xff || value == 0.0 { return "unspecified" } return fmt.Sprintf("%#02x/%.3f", raw, value) case SDRRecordTypeCompactSensor: if raw == 0x00 || raw == 0xff { return "unspecified" } return fmt.Sprintf("%#02x", raw) } return "" } func (sensor *Sensor) DiscreteActiveEvents() []uint8 { if sensor.IsThreshold() { return []uint8{} } return sensor.Discrete.ActiveStates.TrueEvents() } func (sensor *Sensor) DiscreteActiveEventsString() []string { result := make([]string, 0) for _, eventOffset := range sensor.DiscreteActiveEvents() { result = append(result, sensor.EventString(eventOffset)) } return result } func (sensor *Sensor) EventString(eventOffset uint8) string { event := sensor.EventReadingType.EventForOffset(sensor.SensorType, eventOffset) if event != nil { return event.EventName } return "" } golang-github-bougou-go-ipmi-0.7.2/types_sensor_event.go000066400000000000000000000405741474110527100234050ustar00rootroot00000000000000package ipmi import "fmt" type SensorEvent struct { SensorClass SensorClass ThresholdType SensorThresholdType Assert bool // true -> assertion events; false -> deassertion events High bool // true -> going high; false -> going low State uint8 // state 0-14 (total 15 possible states) } func (e SensorEvent) String() string { switch e.SensorClass { case SensorClassThreshold: out := e.ThresholdType.Abbr() if e.High { out += "+" } else { out += "-" } return out case SensorClassDiscrete: return fmt.Sprintf("state%d", e.State) } return "" } type SensorEvents []SensorEvent func (events SensorEvents) Strings() []string { out := make([]string, 0) return out } func (events SensorEvents) FilterAssert() SensorEvents { out := make([]SensorEvent, 0) for _, event := range events { if event.Assert { out = append(out, event) } } return out } func (events SensorEvents) FilterDeassert() SensorEvents { out := make([]SensorEvent, 0) for _, event := range events { if !event.Assert { out = append(out, event) } } return out } func (events SensorEvents) FilterThreshold() SensorEvents { out := make([]SensorEvent, 0) for _, event := range events { if event.SensorClass == SensorClassThreshold { out = append(out, event) } } return out } func (events SensorEvents) FilterDiscrete() SensorEvents { out := make([]SensorEvent, 0) for _, event := range events { if event.SensorClass == SensorClassDiscrete { out = append(out, event) } } return out } // SensorEventFlag holds a struct with fields indicating the specified sensor event is set or not. // SensorEventFlag was embedded in Sensor related commands. type SensorEventFlag struct { SensorEvent_UNC_High_Assert bool SensorEvent_UNC_Low_Assert bool SensorEvent_LNR_High_Assert bool SensorEvent_LNR_Low_Assert bool SensorEvent_LCR_High_Assert bool SensorEvent_LCR_Low_Assert bool SensorEvent_LNC_High_Assert bool SensorEvent_LNC_Low_Assert bool SensorEvent_State_7_Assert bool SensorEvent_State_6_Assert bool SensorEvent_State_5_Assert bool SensorEvent_State_4_Assert bool SensorEvent_State_3_Assert bool SensorEvent_State_2_Assert bool SensorEvent_State_1_Assert bool SensorEvent_State_0_Assert bool SensorEvent_UNR_High_Assert bool SensorEvent_UNR_Low_Assert bool SensorEvent_UCR_High_Assert bool SensorEvent_UCR_Low_Assert bool SensorEvent_State_14_Assert bool SensorEvent_State_13_Assert bool SensorEvent_State_12_Assert bool SensorEvent_State_11_Assert bool SensorEvent_State_10_Assert bool SensorEvent_State_9_Assert bool SensorEvent_State_8_Assert bool SensorEvent_UNC_High_Deassert bool SensorEvent_UNC_Low_Deassert bool SensorEvent_LNR_High_Deassert bool SensorEvent_LNR_Low_Deassert bool SensorEvent_LCR_High_Deassert bool SensorEvent_LCR_Low_Deassert bool SensorEvent_LNC_High_Deassert bool SensorEvent_LNC_Low_Deassert bool SensorEvent_State_7_Deassert bool SensorEvent_State_6_Deassert bool SensorEvent_State_5_Deassert bool SensorEvent_State_4_Deassert bool SensorEvent_State_3_Deassert bool SensorEvent_State_2_Deassert bool SensorEvent_State_1_Deassert bool SensorEvent_State_0_Deassert bool SensorEvent_UNR_High_Deassert bool SensorEvent_UNR_Low_Deassert bool SensorEvent_UCR_High_Deassert bool SensorEvent_UCR_Low_Deassert bool SensorEvent_State_14_Deassert bool SensorEvent_State_13_Deassert bool SensorEvent_State_12_Deassert bool SensorEvent_State_11_Deassert bool SensorEvent_State_10_Deassert bool SensorEvent_State_9_Deassert bool SensorEvent_State_8_Deassert bool } // TrueEvents returns a slice of SensorEvent those are set to true in the SensorEventFlag. func (flag *SensorEventFlag) TrueEvents() []SensorEvent { out := make([]SensorEvent, 0) if flag.SensorEvent_UNC_High_Assert { out = append(out, SensorEvent_UNC_High_Assert) } if flag.SensorEvent_UNC_Low_Assert { out = append(out, SensorEvent_UNC_Low_Deassert) } if flag.SensorEvent_LNR_High_Assert { out = append(out, SensorEvent_LNR_High_Assert) } if flag.SensorEvent_LNR_Low_Assert { out = append(out, SensorEvent_LNR_Low_Assert) } if flag.SensorEvent_LCR_High_Assert { out = append(out, SensorEvent_LCR_High_Assert) } if flag.SensorEvent_LCR_Low_Assert { out = append(out, SensorEvent_LCR_Low_Assert) } if flag.SensorEvent_LNC_High_Assert { out = append(out, SensorEvent_LNC_High_Assert) } if flag.SensorEvent_LNC_Low_Assert { out = append(out, SensorEvent_LNC_Low_Assert) } if flag.SensorEvent_State_7_Assert { out = append(out, SensorEvent_State_7_Assert) } if flag.SensorEvent_State_6_Assert { out = append(out, SensorEvent_State_6_Assert) } if flag.SensorEvent_State_5_Assert { out = append(out, SensorEvent_State_5_Assert) } if flag.SensorEvent_State_4_Assert { out = append(out, SensorEvent_State_4_Assert) } if flag.SensorEvent_State_3_Assert { out = append(out, SensorEvent_State_3_Assert) } if flag.SensorEvent_State_2_Assert { out = append(out, SensorEvent_State_2_Assert) } if flag.SensorEvent_State_1_Assert { out = append(out, SensorEvent_State_1_Assert) } if flag.SensorEvent_State_0_Assert { out = append(out, SensorEvent_State_0_Assert) } if flag.SensorEvent_UNR_High_Assert { out = append(out, SensorEvent_UNR_High_Assert) } if flag.SensorEvent_UNR_Low_Assert { out = append(out, SensorEvent_UNR_Low_Assert) } if flag.SensorEvent_UCR_High_Assert { out = append(out, SensorEvent_UCR_High_Assert) } if flag.SensorEvent_UCR_Low_Assert { out = append(out, SensorEvent_UCR_Low_Assert) } if flag.SensorEvent_State_14_Assert { out = append(out, SensorEvent_State_14_Assert) } if flag.SensorEvent_State_13_Assert { out = append(out, SensorEvent_State_13_Assert) } if flag.SensorEvent_State_12_Assert { out = append(out, SensorEvent_State_12_Assert) } if flag.SensorEvent_State_11_Assert { out = append(out, SensorEvent_State_11_Assert) } if flag.SensorEvent_State_10_Assert { out = append(out, SensorEvent_State_10_Assert) } if flag.SensorEvent_State_9_Assert { out = append(out, SensorEvent_State_9_Assert) } if flag.SensorEvent_State_8_Assert { out = append(out, SensorEvent_State_8_Assert) } if flag.SensorEvent_UNC_High_Deassert { out = append(out, SensorEvent_UNC_High_Deassert) } if flag.SensorEvent_UNC_Low_Deassert { out = append(out, SensorEvent_UNC_Low_Deassert) } if flag.SensorEvent_LNR_High_Deassert { out = append(out, SensorEvent_LNR_High_Deassert) } if flag.SensorEvent_LNR_Low_Deassert { out = append(out, SensorEvent_LNR_Low_Deassert) } if flag.SensorEvent_LCR_High_Deassert { out = append(out, SensorEvent_LCR_High_Deassert) } if flag.SensorEvent_LCR_Low_Deassert { out = append(out, SensorEvent_LCR_Low_Deassert) } if flag.SensorEvent_LNC_High_Deassert { out = append(out, SensorEvent_LNC_High_Deassert) } if flag.SensorEvent_LNC_Low_Deassert { out = append(out, SensorEvent_LNC_Low_Deassert) } if flag.SensorEvent_State_7_Deassert { out = append(out, SensorEvent_State_7_Deassert) } if flag.SensorEvent_State_6_Deassert { out = append(out, SensorEvent_State_6_Deassert) } if flag.SensorEvent_State_5_Deassert { out = append(out, SensorEvent_State_5_Deassert) } if flag.SensorEvent_State_4_Deassert { out = append(out, SensorEvent_State_4_Deassert) } if flag.SensorEvent_State_3_Deassert { out = append(out, SensorEvent_State_3_Deassert) } if flag.SensorEvent_State_2_Deassert { out = append(out, SensorEvent_State_2_Deassert) } if flag.SensorEvent_State_1_Deassert { out = append(out, SensorEvent_State_1_Deassert) } if flag.SensorEvent_State_0_Deassert { out = append(out, SensorEvent_State_0_Deassert) } if flag.SensorEvent_UNR_High_Deassert { out = append(out, SensorEvent_UNR_High_Deassert) } if flag.SensorEvent_UNR_Low_Deassert { out = append(out, SensorEvent_UNR_Low_Deassert) } if flag.SensorEvent_UCR_High_Deassert { out = append(out, SensorEvent_UCR_High_Deassert) } if flag.SensorEvent_UCR_Low_Deassert { out = append(out, SensorEvent_UCR_Low_Deassert) } if flag.SensorEvent_State_14_Deassert { out = append(out, SensorEvent_State_14_Deassert) } if flag.SensorEvent_State_13_Deassert { out = append(out, SensorEvent_State_13_Deassert) } if flag.SensorEvent_State_12_Deassert { out = append(out, SensorEvent_State_12_Deassert) } if flag.SensorEvent_State_11_Deassert { out = append(out, SensorEvent_State_11_Deassert) } if flag.SensorEvent_State_10_Deassert { out = append(out, SensorEvent_State_10_Deassert) } if flag.SensorEvent_State_9_Deassert { out = append(out, SensorEvent_State_9_Deassert) } if flag.SensorEvent_State_8_Deassert { out = append(out, SensorEvent_State_8_Deassert) } return out } var ( SensorEvent_UNC_High_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UNC, Assert: true, High: true, } SensorEvent_UNC_Low_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UNC, Assert: true, High: false, } SensorEvent_LNR_High_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LNR, Assert: true, High: true, } SensorEvent_LNR_Low_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LNR, Assert: true, High: false, } SensorEvent_LCR_High_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LCR, Assert: true, High: true, } SensorEvent_LCR_Low_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LCR, Assert: true, High: false, } SensorEvent_LNC_High_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LNC, Assert: true, High: true, } SensorEvent_LNC_Low_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LNC, Assert: true, High: false, } SensorEvent_UNR_High_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UNR, Assert: true, High: true, } SensorEvent_UNR_Low_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UNR, Assert: true, High: false, } SensorEvent_UCR_High_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UCR, Assert: true, High: true, } SensorEvent_UCR_Low_Assert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UCR, Assert: true, High: false, } SensorEvent_State_14_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 14, } SensorEvent_State_13_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 13, } SensorEvent_State_12_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 12, } SensorEvent_State_11_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 11, } SensorEvent_State_10_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 10, } SensorEvent_State_9_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 9, } SensorEvent_State_8_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 8, } SensorEvent_State_7_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 7, } SensorEvent_State_6_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 6, } SensorEvent_State_5_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 5, } SensorEvent_State_4_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 4, } SensorEvent_State_3_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 3, } SensorEvent_State_2_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 2, } SensorEvent_State_1_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 1, } SensorEvent_State_0_Assert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: true, State: 0, } SensorEvent_UNC_High_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UNC, Assert: false, High: true, } // Deassert Events SensorEvent_UNC_Low_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UNC, Assert: false, High: true, } SensorEvent_LNR_High_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LNR, Assert: false, High: true, } SensorEvent_LNR_Low_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LNR, Assert: false, High: false, } SensorEvent_LCR_High_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LCR, Assert: false, High: true, } SensorEvent_LCR_Low_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LCR, Assert: false, High: false, } SensorEvent_LNC_High_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LNC, Assert: false, High: true, } SensorEvent_LNC_Low_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_LNC, Assert: false, High: false, } SensorEvent_UNR_High_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UNR, Assert: false, High: true, } SensorEvent_UNR_Low_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UNR, Assert: false, High: false, } SensorEvent_UCR_High_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UCR, Assert: false, High: true, } SensorEvent_UCR_Low_Deassert = SensorEvent{ SensorClass: SensorClassThreshold, ThresholdType: SensorThresholdType_UCR, Assert: false, High: false, } SensorEvent_State_14_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 14, } SensorEvent_State_13_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 13, } SensorEvent_State_12_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 12, } SensorEvent_State_11_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 11, } SensorEvent_State_10_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 10, } SensorEvent_State_9_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 9, } SensorEvent_State_8_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 8, } SensorEvent_State_7_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 7, } SensorEvent_State_6_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 6, } SensorEvent_State_5_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 5, } SensorEvent_State_4_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 4, } SensorEvent_State_3_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 3, } SensorEvent_State_2_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 2, } SensorEvent_State_1_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 1, } SensorEvent_State_0_Deassert = SensorEvent{ SensorClass: SensorClassDiscrete, Assert: false, State: 0, } ) golang-github-bougou-go-ipmi-0.7.2/types_sensor_test.go000066400000000000000000000023251474110527100232330ustar00rootroot00000000000000package ipmi import ( "fmt" "testing" ) func Test_ConvertReading(t *testing.T) { tests := []struct { raw uint8 analogDataFormat SensorAnalogUnitFormat factors ReadingFactors linearizationFunc LinearizationFunc }{ { raw: 0, analogDataFormat: SensorAnalogUnitFormat_Unsigned, factors: ReadingFactors{}, linearizationFunc: LinearizationFunc_Linear, }, { raw: 0, analogDataFormat: SensorAnalogUnitFormat_NotAnalog, factors: ReadingFactors{}, linearizationFunc: LinearizationFunc_Linear, }, { raw: 0, analogDataFormat: SensorAnalogUnitFormat_1sComplement, factors: ReadingFactors{ M: 1, Tolerance: 0, B: 0, Accuracy: 0, Accuracy_Exp: 0, B_Exp: 0, }, linearizationFunc: LinearizationFunc_Linear, }, { raw: 0, analogDataFormat: SensorAnalogUnitFormat_2sComplement, factors: ReadingFactors{}, linearizationFunc: LinearizationFunc_Linear, }, } for _, tt := range tests { v := ConvertReading(tt.raw, tt.analogDataFormat, tt.factors, tt.linearizationFunc) fmt.Println(v) // Todo } } golang-github-bougou-go-ipmi-0.7.2/types_session.go000066400000000000000000000475361474110527100223630ustar00rootroot00000000000000package ipmi import ( "crypto/md5" "encoding/binary" "fmt" ) type ( AuthType uint8 ) const ( AuthTypeNone AuthType = 0x00 AuthTypeMD2 AuthType = 0x01 AuthTypeMD5 AuthType = 0x02 AuthTypePassword AuthType = 0x04 AuthTypeOEM AuthType = 0x05 AuthTypeRMCPPlus AuthType = 0x06 ) const ( SessionHeader20SizeMax int = 18 SessionHeader20SizeMin int = 12 SessionHeader15SizeMax int = 26 SessionHeader15SizeMin int = 10 ) // SessionHeader15 for IPMI 1.5 // see 22.12, Table 13. // // Whether the session header fields are present in a packet is based on // whether the channel is specified as supporting multiple sessions or not. // In addition, which session fields are present is based on the authentication type. // Single-session connections and session-less channels do not include session header fields. // // Session header fields are present on all packets where the channel and // connection mode is specified as supporting multiple sessions, even if // the particular implementation only supports one session. // // Note that the command tables do not show the session header fields except for the // Get Channel Authentication Capabilities, Get Session Challenge, and Activate Session commands. // However, they are still required for all commands on a multi-session connection. type SessionHeader15 struct { // For IPMI 1.5, it's value is 00h, 01h, 02h, 04h, 05h AuthType AuthType // For IPMI v2.0 RMCP+ there are separate sequence numbers tracked for authenticated and unauthenticated packets. // 0000_0000h is used for packets that are sent outside of a session. Sequence uint32 SessionID uint32 // The Authentication Code field in the session header may or may not be present based on the Authentication Type. The authentication code field is absent whenever the Authentication Type is NONE. Whether the authentication code field is present or not when the Authentication Type = OEM is dependent on the OEM identified in the Get Channel Authentication Capabilities command. // // 16 bytes, not present when Authentication Type set to none AuthCode []byte // IPMI 1.5 // Payload length in bytes. 1-based. // IPMI 1.5 should be uint8 // You should construct SessionHeader after the payload is created, thus you can fill the length here. PayloadLength uint8 } func (h *SessionHeader15) Pack() []byte { var msg = make([]byte, 10+len(h.AuthCode)) packUint8(uint8(h.AuthType), msg, 0) packUint32L(h.Sequence, msg, 1) packUint32L(h.SessionID, msg, 5) if h.AuthType != AuthTypeNone { packBytes(h.AuthCode, msg, 9) } packUint8(h.PayloadLength, msg, 9+len(h.AuthCode)) return msg } func (h *SessionHeader15) Unpack(msg []byte) error { if len(msg) < SessionHeader15SizeMin { return ErrUnpackedDataTooShortWith(len(msg), SessionHeader15SizeMin) } b, _, _ := unpackUint8(msg, 0) h.AuthType = AuthType(b) h.Sequence, _, _ = unpackUint32L(msg, 1) h.SessionID, _, _ = unpackUint32L(msg, 5) var payloadLengthIndex = 9 if h.AuthType != AuthTypeNone { if len(msg) < SessionHeader15SizeMax { return ErrUnpackedDataTooShortWith(len(msg), SessionHeader15SizeMax) } h.AuthCode, _, _ = unpackBytes(msg, 9, 16) payloadLengthIndex = 25 } h.PayloadLength, _, _ = unpackUint8(msg, payloadLengthIndex) return nil } type Session15 struct { SessionHeader15 *SessionHeader15 Payload []byte // legacy PAD not needed for IPMI v2.0 LegacyPAD byte } func (s *Session15) Pack() []byte { out := s.SessionHeader15.Pack() out = append(out, s.Payload...) return out } func (s *Session15) Unpack(msg []byte) error { sessionHeader := &SessionHeader15{} err := sessionHeader.Unpack(msg) if err != nil { return fmt.Errorf("unpack SessionHeader15 failed, err: %w", err) } s.SessionHeader15 = sessionHeader sessionHeaderSize := len(sessionHeader.Pack()) sessionPayloadSize := int(sessionHeader.PayloadLength) if len(msg) < sessionHeaderSize+sessionPayloadSize { return ErrUnpackedDataTooShortWith(len(msg), sessionHeaderSize+sessionPayloadSize) } s.Payload, _, _ = unpackBytes(msg, sessionHeaderSize, sessionPayloadSize) return nil } // SessionHeader20 for IPMI 2.0 type SessionHeader20 struct { // For IPMI 2.0, it's value is always 06h AuthType AuthType PayloadEncrypted bool PayloadAuthenticated bool PayloadType PayloadType // The complete identification of an OEM Payload is given by the combination of a three-byte IANA ID for the OEM, a reserved byte, plus a twobyte OEM Payload ID that is assigned and defined by the given OEM OEMIANA uint32 OEMPayloadID uint16 // Should be set to bmcSessionID (generated by bmc, cached by remote console) SessionID uint32 // For IPMI v2.0 RMCP+ there are separate sequence numbers tracked for authenticated and unauthenticated packets. // 0000_0000h is used for packets that are sent outside of a session. Sequence uint32 // Payload length in bytes. 1-based. // You should construct SessionHeader after the payload is created, thus you can fill the length here. // IPMI 2.0 should be uint16 PayloadLength uint16 } func (h *SessionHeader20) Pack() []byte { // the longest length of SessionHeader20 is 18 msg := make([]byte, 18) packUint8(uint8(h.AuthType), msg, 0) var encryptedMask uint8 = 0x00 if h.PayloadEncrypted { encryptedMask = 0x80 } var authenticatedMask uint8 = 0x00 if h.PayloadAuthenticated { authenticatedMask = 0x40 } packUint8(encryptedMask|authenticatedMask|uint8(h.PayloadType), msg, 1) var sessionIDIndex int var msgEndIndex int if h.PayloadType == PayloadTypeOEM { packUint32L(h.OEMIANA, msg, 2) packUint16L(h.OEMPayloadID, msg, 6) sessionIDIndex = 8 msgEndIndex = 18 } else { sessionIDIndex = 2 msgEndIndex = 12 } packUint32L(h.SessionID, msg, sessionIDIndex) packUint32L(h.Sequence, msg, sessionIDIndex+4) packUint16L(h.PayloadLength, msg, sessionIDIndex+8) return msg[:msgEndIndex] } func (h *SessionHeader20) Unpack(msg []byte) error { if len(msg) < SessionHeader20SizeMin { return ErrUnpackedDataTooShortWith(len(msg), SessionHeader20SizeMin) } authType, _, _ := unpackUint8(msg, 0) h.AuthType = AuthType(authType) payloadType, _, _ := unpackUint8(msg, 1) h.PayloadEncrypted = isBit7Set(payloadType) h.PayloadAuthenticated = isBit6Set(payloadType) h.PayloadType = PayloadType(payloadType & 0x3f) var sessionIDIndex int if h.PayloadType == PayloadTypeOEM { if len(msg) < SessionHeader20SizeMax { return ErrUnpackedDataTooShortWith(len(msg), SessionHeader20SizeMax) } h.OEMIANA, _, _ = unpackUint32L(msg, 2) h.OEMPayloadID, _, _ = unpackUint16L(msg, 6) sessionIDIndex = 8 } else { sessionIDIndex = 2 } h.SessionID, _, _ = unpackUint32L(msg, sessionIDIndex) h.Sequence, _, _ = unpackUint32L(msg, sessionIDIndex+4) h.PayloadLength, _, _ = unpackUint16L(msg, sessionIDIndex+8) return nil } type Session20 struct { SessionHeader20 *SessionHeader20 // for encrypted packets, it should contain Confidentiality Header, Encrypted Payload, and Confidentiality Trailer. SessionPayload []byte // For IPMI v2.0 RMCP+ packets, the IPMI Session Trailer is absent whenever the Session ID is 0000_0000h, or whenever bit 6 in the payload type field indicates the packet is unauthenticated. SessionTrailer *SessionTrailer } func (s *Session20) Pack() []byte { out := s.SessionHeader20.Pack() out = append(out, s.SessionPayload...) if s.SessionTrailer != nil { out = append(out, s.SessionTrailer.Pack()...) } return out } func (s *Session20) Unpack(msg []byte) error { sessionHeader := &SessionHeader20{} if err := sessionHeader.Unpack(msg); err != nil { return fmt.Errorf("unpack SessionHeader failed, err: %w", err) } s.SessionHeader20 = sessionHeader var sessionHeaderSize int if sessionHeader.PayloadType == PayloadTypeOEM { sessionHeaderSize = SessionHeader20SizeMax } else { sessionHeaderSize = SessionHeader20SizeMin } payloadLength := int(s.SessionHeader20.PayloadLength) if len(msg) < sessionHeaderSize+payloadLength { return ErrUnpackedDataTooShortWith(len(msg), sessionHeaderSize+payloadLength) } s.SessionPayload, _, _ = unpackBytes(msg, sessionHeaderSize, payloadLength) s.SessionTrailer = nil sessionTrailerIndex := sessionHeaderSize + payloadLength if s.SessionHeader20.PayloadAuthenticated && s.SessionHeader20.SessionID != 0 { padSize := genSessionTrailerPadLength(sessionHeader.Pack(), s.SessionPayload) sessionTrailer := &SessionTrailer{} _, err := sessionTrailer.Unpack(msg, sessionTrailerIndex, padSize) if err != nil { return fmt.Errorf("unpack SessionTrailer failed, err: %w", err) } s.SessionTrailer = sessionTrailer } return nil } // For IPMI v2.0 RMCP+ packets, the IPMI Session Trailer is absent whenever the Session ID is 0000_0000h, or whenever bit 6 in the payload type field indicates the packet is unauthenticated type SessionTrailer struct { // IPMI 2.0 and ASF only // Added as needed to cause the number of bytes in the data range covered by the AuthCode (Integrity Data) field to be a multiple of 4 bytes (DWORD). If present, each Integrity Pad byte is set to FFh. IntegrityPAD []byte // indicates how many pad bytes were added so that the amount of non-pad data can be determined. PadLength uint8 // Reserved in IPMI v2.0. Set to 07h for RMCP+ packets defined in this specification. NextHeader uint8 // For IPMI v2.0 (RMCP+) if this field is present, then it is calculated according to the Integrity Algorithm that was negotiated during the session open process. See Table 13-, Integrity Algorithm Numbers. // This field is absent when the packet is unauthenticated. AuthCode []byte // Integrity Data } func (s *SessionTrailer) Pack() []byte { msg := make([]byte, len(s.IntegrityPAD)+2+len(s.AuthCode)) packBytes(s.IntegrityPAD, msg, 0) packUint8(s.PadLength, msg, len(s.IntegrityPAD)) packUint8(s.NextHeader, msg, len(s.IntegrityPAD)+1) packBytes(s.AuthCode, msg, len(s.IntegrityPAD)+2) return msg } func (s *SessionTrailer) Unpack(msg []byte, off int, padSize int) (int, error) { var err error s.IntegrityPAD, off, _ = unpackBytes(msg, off, padSize) s.PadLength, off, _ = unpackUint8(msg, off) s.NextHeader, off, _ = unpackUint8(msg, off) s.AuthCode, off, _ = unpackBytesMost(msg, off, 16) return off, err } type SessionState uint8 const ( SessionStatePreSession SessionState = 0x00 SessionStateOpenSessionSent SessionState = 0x01 SessionStateOpenSessionReceived SessionState = 0x02 SessionStateRakp1Sent SessionState = 0x03 SessionStateRakp2Received SessionState = 0x04 SessionStateRakp3Sent SessionState = 0x05 SessionStateActive SessionState = 0x06 SessionStateCloseSent SessionState = 0x07 ) func (c *Client) genSession15(rawPayload []byte) (*Session15, error) { c.lock() defer c.unlock() sessionHeader := &SessionHeader15{ AuthType: AuthTypeNone, Sequence: 0, SessionID: 0, AuthCode: nil, // AuthCode would be filled afterward PayloadLength: uint8(len(rawPayload)), } if c.session.v15.preSession || c.session.v15.active { sessionHeader.AuthType = c.session.authType sessionHeader.SessionID = c.session.v15.sessionID } if c.session.v15.active { c.session.v15.inSeq += 1 sessionHeader.Sequence = c.session.v15.inSeq } if sessionHeader.AuthType != AuthTypeNone { authCode := c.genAuthCodeForMultiSession(rawPayload) sessionHeader.AuthCode = authCode } return &Session15{ SessionHeader15: sessionHeader, Payload: rawPayload, }, nil } func (c *Client) genSession20(payloadType PayloadType, rawPayload []byte) (*Session20, error) { c.lock() defer c.unlock() // // Session Header // sessionHeader := &SessionHeader20{ AuthType: AuthTypeRMCPPlus, // Auth Type / Format is always 0x06 for IPMI v2 PayloadType: payloadType, PayloadAuthenticated: false, PayloadEncrypted: false, SessionID: 0, Sequence: 0, PayloadLength: 0, // PayloadLength would be updated later after encryption if necessary. } if c.session.v20.state == SessionStateActive { sessionHeader.PayloadAuthenticated = true sessionHeader.PayloadEncrypted = true sessionHeader.SessionID = c.session.v20.bmcSessionID // use bmc session id c.session.v20.sequence += 1 sessionHeader.Sequence = c.session.v20.sequence } // // Session Payload // sessionPayload := rawPayload if c.session.v20.state == SessionStateActive && sessionHeader.PayloadEncrypted { e, err := c.encryptPayload(rawPayload, nil) if err != nil { return nil, fmt.Errorf("encrypt payload failed, err: %w", err) } sessionPayload = e } // now we can fill PayloadLength field of the SessionHeader sessionHeader.PayloadLength = uint16(len(sessionPayload)) c.DebugBytes("sessionPayload(final)", sessionPayload, 16) sessionHeaderBytes := sessionHeader.Pack() c.DebugBytes("sessionHeader", sessionHeaderBytes, 16) // // Session Trailer // var sessionTrailer *SessionTrailer = nil var err error // For IPMI v2.0 RMCP+ packets, the IPMI Session Trailer is absent // whenever the Session ID is 0000_0000h, or the packet is unauthenticated if sessionHeader.PayloadAuthenticated && sessionHeader.SessionID != 0 { sessionTrailer, err = c.genSessionTrailer(sessionHeaderBytes, sessionPayload) if err != nil { return nil, fmt.Errorf("genSessionTrailer failed, err: %w", err) } } return &Session20{ SessionHeader20: sessionHeader, SessionPayload: sessionPayload, SessionTrailer: sessionTrailer, }, nil } func genSessionTrailerPadLength(sessionHeader []byte, sessionPayload []byte) int { // (12) sessionHeader length // sessionPayload length // (1) pad length field // (1) next header field length := len(sessionHeader) + len(sessionPayload) + 1 + 1 var padSize int = 0 if length%4 != 0 { padSize = 4 - int(length%4) } return padSize } // genSessionTrailer will create the SessionTrailer. // // see 13.28.4 Integrity Algorithms // Unless otherwise specified, the integrity algorithm is applied to the packet // data starting with the AuthType/Format field up to and including the field // that immediately precedes the AuthCode field itself. func (c *Client) genSessionTrailer(sessionHeader []byte, sessionPayload []byte) (*SessionTrailer, error) { padSize := genSessionTrailerPadLength(sessionHeader, sessionPayload) var pad = make([]byte, padSize) for i := 0; i < padSize; i++ { pad[i] = 0xff } sessionTrailer := &SessionTrailer{ IntegrityPAD: pad, PadLength: uint8(padSize), NextHeader: 0x07, /* Hardcoded per the spec, table 13-8 */ AuthCode: nil, } var input []byte = sessionHeader input = append(input, sessionPayload...) input = append(input, sessionTrailer.IntegrityPAD...) input = append(input, sessionTrailer.PadLength) input = append(input, sessionTrailer.NextHeader) c.DebugBytes("auth code input", input, 16) authCode, err := c.genIntegrityAuthCode(input) if err != nil { return nil, fmt.Errorf("generate integrity authcode failed, err: %w", err) } c.DebugBytes("generated auth code", authCode, 16) sessionTrailer.AuthCode = authCode return sessionTrailer, nil } // the input data only represents the serialized ipmi msg request bytes. // the output bytes contains the // - Confidentiality Header (clear text) // - Encrypted Payload. // - the cipher text of both rawPayload // - padded Confidentiality Trailer. func (c *Client) encryptPayload(rawPayload []byte, iv []byte) ([]byte, error) { switch c.session.v20.cryptAlg { case CryptAlg_None: return rawPayload, nil case CryptAlg_AES_CBC_128: // The input to the AES encryption algorithm has to be a multiple of the block size (16 bytes). // The extra byte we are adding is the pad length byte. var paddedData = rawPayload var padLength uint8 if mod := (len(rawPayload) + 1) % int(Encryption_AES_CBS_128_BlockSize); mod > 0 { padLength = Encryption_AES_CBS_128_BlockSize - uint8(mod) } else { padLength = 0 } for i := uint8(0); i < padLength; i++ { paddedData = append(paddedData, i+1) } paddedData = append(paddedData, padLength) // now, the length of data SHOULD be multiple of 16 c.DebugBytes("padded data (before encrypt)", paddedData, 16) // see 13.29 Table 13-, AES-CBC Encrypted Payload Fields if len(iv) == 0 { iv = randomBytes(16) // Initialization Vector } c.DebugBytes("random iv", iv, 16) // see 13.29.2 Encryption with AES // AES-128 uses a 128-bit Cipher Key. The Cipher Key is the first 128-bits of key K2 cipherKey := c.session.v20.k2[0:16] c.DebugBytes("cipher key (k2)", cipherKey, 16) encryptedPayload, err := encryptAES(paddedData, cipherKey, iv) if err != nil { return nil, fmt.Errorf("encrypt payload with AES_CBC_128 failed, err: %w", err) } c.DebugBytes("encrypted data", encryptedPayload, 16) var out []byte // write Confidentiality Header out = append(out, iv...) // write Encrypted Payload out = append(out, encryptedPayload...) c.DebugBytes("encrypted session payload", out, 16) return out, nil case CryptAlg_xRC4_40, CryptAlg_xRC4_128: var out []byte // see 13.30 Table 13-, xRC4-Encrypted Payload Fields var confidentialityHeader []byte var offset = make([]byte, 4) if c.session.v20.accumulatedPayloadSize == 0 { // means this is the first sent packet for i := 0; i < 4; i++ { offset[i] = 0 } c.session.v20.rc4EncryptIV = array16(randomBytes(16)) confidentialityHeader = append(offset, c.session.v20.rc4EncryptIV[:]...) } else { binary.BigEndian.PutUint32(offset, c.session.v20.accumulatedPayloadSize) confidentialityHeader = offset } c.session.v20.accumulatedPayloadSize += uint32(len(rawPayload)) iv := c.session.v20.rc4EncryptIV[:] out = append(out, confidentialityHeader...) input := append(c.session.v20.k2, iv...) keyRC := md5.New().Sum(input) var cipherKey []byte switch c.session.v20.cryptAlg { case CryptAlg_xRC4_40: // For xRC4 using a 40-bit key, only the most significant forty bits of Krc are used cipherKey = keyRC[:5] case CryptAlg_xRC4_128: // For xRC4 using a 128-bit key, all bits of Krc are used for initialization cipherKey = keyRC[:16] } encryptedPayload, err := encryptRC4(rawPayload, cipherKey, iv) if err != nil { return nil, fmt.Errorf("encrypt payload with xRC4_40 or xRC4_128 failed, err: %w", err) } // write Encrypted Payload out = append(out, encryptedPayload...) // xRC4 does not use a confidentiality trailer. return out, nil default: return nil, fmt.Errorf("not supported encryption algorithm %x", c.session.v20.cryptAlg) } } // the input data is the encrypted session payload. // the output bytes is the decrypted IPMI Message bytes with padding removed. func (c *Client) decryptPayload(data []byte) ([]byte, error) { switch c.session.v20.cryptAlg { case CryptAlg_None: return data, nil case CryptAlg_AES_CBC_128: iv := data[0:16] // the first 16 byte is the initialization vector cipherText := data[16:] cipherKey := c.session.v20.k2[0:16] d, err := decryptAES(cipherText, cipherKey, iv) if err != nil { return nil, fmt.Errorf("decrypt payload with AES_CBC_128 failed, err: %w", err) } padLength := d[len(d)-1] dEnd := len(d) - int(padLength) - 1 return d[0:dEnd], nil case CryptAlg_xRC4_40, CryptAlg_xRC4_128: // the first received packet if data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x0 && data[3] == 0x0 { c.session.v20.rc4DecryptIV = array16(data[4:20]) } iv := c.session.v20.rc4DecryptIV[:] input := append(c.session.v20.k2, iv...) keyRC := md5.New().Sum(input) var cipherKey []byte switch c.session.v20.cryptAlg { case CryptAlg_xRC4_40: // For xRC4 using a 40-bit key, only the most significant forty bits of Krc are used cipherKey = keyRC[:5] case CryptAlg_xRC4_128: // For xRC4 using a 128-bit key, all bits of Krc are used for initialization cipherKey = keyRC[:16] } payloadData := data[20:] b, err := decryptRC4(payloadData, cipherKey, iv) if err != nil { return nil, fmt.Errorf("decrypt payload with xRC4_128 failed, err: %w", err) } return b, nil default: return nil, fmt.Errorf("not supported encryption algorithm %0x", c.session.v20.cryptAlg) } } golang-github-bougou-go-ipmi-0.7.2/types_sol_config_params.go000066400000000000000000000263411474110527100243540ustar00rootroot00000000000000package ipmi import "fmt" type SOLConfigParamSelector uint8 const ( SOLConfigParamSelector_SetInProgress SOLConfigParamSelector = 0x00 SOLConfigParamSelector_SOLEnable SOLConfigParamSelector = 0x01 SOLConfigParamSelector_SOLAuthentication SOLConfigParamSelector = 0x02 SOLConfigParamSelector_Character SOLConfigParamSelector = 0x03 SOLConfigParamSelector_SOLRetry SOLConfigParamSelector = 0x04 SOLConfigParamSelector_NonVolatileBitRate SOLConfigParamSelector = 0x05 SOLConfigParamSelector_VolatileBitRate SOLConfigParamSelector = 0x06 SOLConfigParamSelector_PayloadChannel SOLConfigParamSelector = 0x07 SOLConfigParamSelector_PayloadPort SOLConfigParamSelector = 0x08 ) func (p SOLConfigParamSelector) String() string { m := map[SOLConfigParamSelector]string{ SOLConfigParamSelector_SetInProgress: "Set In Progress", SOLConfigParamSelector_SOLEnable: "SOL Enable", SOLConfigParamSelector_SOLAuthentication: "SOL Authentication", SOLConfigParamSelector_Character: "Character", SOLConfigParamSelector_SOLRetry: "SOL Retry", SOLConfigParamSelector_NonVolatileBitRate: "Non-Volatile Bit Rate", SOLConfigParamSelector_VolatileBitRate: "Volatile Bit Rate", SOLConfigParamSelector_PayloadChannel: "Payload Channel", SOLConfigParamSelector_PayloadPort: "Payload Port", } s, ok := m[p] if ok { return s } return "Unknown" } type SOLConfigParameter interface { SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) Parameter } var ( _ SOLConfigParameter = (*SOLConfigParam_SetInProgress)(nil) _ SOLConfigParameter = (*SOLConfigParam_SOLEnable)(nil) _ SOLConfigParameter = (*SOLConfigParam_SOLAuthentication)(nil) _ SOLConfigParameter = (*SOLConfigParam_Character)(nil) _ SOLConfigParameter = (*SOLConfigParam_SOLRetry)(nil) _ SOLConfigParameter = (*SOLConfigParam_NonVolatileBitRate)(nil) _ SOLConfigParameter = (*SOLConfigParam_VolatileBitRate)(nil) _ SOLConfigParameter = (*SOLConfigParam_PayloadChannel)(nil) _ SOLConfigParameter = (*SOLConfigParam_PayloadPort)(nil) ) func isNilSOLConfigParameter(param SOLConfigParameter) bool { switch v := param.(type) { case *SOLConfigParam_SetInProgress: return v == nil case *SOLConfigParam_SOLEnable: return v == nil case *SOLConfigParam_SOLAuthentication: return v == nil case *SOLConfigParam_Character: return v == nil case *SOLConfigParam_SOLRetry: return v == nil case *SOLConfigParam_NonVolatileBitRate: return v == nil case *SOLConfigParam_VolatileBitRate: return v == nil case *SOLConfigParam_PayloadChannel: return v == nil case *SOLConfigParam_PayloadPort: return v == nil default: return false } } type SOLConfigParams struct { SetInProgress *SOLConfigParam_SetInProgress SOLEnable *SOLConfigParam_SOLEnable SOLAuthentication *SOLConfigParam_SOLAuthentication Character *SOLConfigParam_Character SOLRetry *SOLConfigParam_SOLRetry NonVolatileBitRate *SOLConfigParam_NonVolatileBitRate VolatileBitRate *SOLConfigParam_VolatileBitRate PayloadChannel *SOLConfigParam_PayloadChannel PayloadPort *SOLConfigParam_PayloadPort } func (p *SOLConfigParams) Format() string { format := func(param SOLConfigParameter) string { if isNilSOLConfigParameter(param) { return "" } paramSelector, _, _ := param.SOLConfigParameter() content := param.Format() if content[len(content)-1] != '\n' { content += "\n" } return fmt.Sprintf("[%2d] %-22s : %s", paramSelector, paramSelector.String(), content) } out := "" out += format(p.SetInProgress) out += format(p.SOLEnable) out += format(p.SOLAuthentication) out += format(p.Character) out += format(p.SOLRetry) out += format(p.NonVolatileBitRate) out += format(p.VolatileBitRate) out += format(p.PayloadChannel) out += format(p.PayloadPort) return out } type SOLConfigParam_SetInProgress struct { Value SetInProgressState } func (p *SOLConfigParam_SetInProgress) SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) { return SOLConfigParamSelector_SetInProgress, 0x00, 0x00 } func (p *SOLConfigParam_SetInProgress) Unpack(paramData []byte) error { if len(paramData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } p.Value = SetInProgressState(paramData[0]) return nil } func (p *SOLConfigParam_SetInProgress) Pack() []byte { return []byte{byte(p.Value)} } func (p *SOLConfigParam_SetInProgress) Format() string { return p.Value.String() } type SOLConfigParam_SOLEnable struct { EnableSOLPayload bool } func (p *SOLConfigParam_SOLEnable) SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) { return SOLConfigParamSelector_SOLEnable, 0x00, 0x00 } func (p *SOLConfigParam_SOLEnable) Unpack(paramData []byte) error { if len(paramData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } p.EnableSOLPayload = isBit0Set(paramData[0]) return nil } func (p *SOLConfigParam_SOLEnable) Pack() []byte { var b uint8 = 0x00 b = setOrClearBit0(b, p.EnableSOLPayload) return []byte{b} } func (p *SOLConfigParam_SOLEnable) Format() string { return fmt.Sprintf("%v", p.EnableSOLPayload) } type SOLConfigParam_SOLAuthentication struct { ForceEncryption bool ForceAuthentication bool PrivilegeLevel uint8 } func (p *SOLConfigParam_SOLAuthentication) SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) { return SOLConfigParamSelector_SOLAuthentication, 0x00, 0x00 } func (p *SOLConfigParam_SOLAuthentication) Unpack(paramData []byte) error { if len(paramData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } b := paramData[0] p.ForceEncryption = isBit7Set(b) p.ForceAuthentication = isBit6Set(b) p.PrivilegeLevel = b & 0x0f return nil } func (p *SOLConfigParam_SOLAuthentication) Pack() []byte { var b uint8 = 0x00 if p.ForceEncryption { b = setBit7(b) } if p.ForceAuthentication { b = setBit6(b) } b |= p.PrivilegeLevel return []byte{b} } func (p *SOLConfigParam_SOLAuthentication) Format() string { return fmt.Sprintf(` Force Encryption : %v Force Authentication : %v Privilege Level : %#02x `, p.ForceEncryption, p.ForceAuthentication, p.PrivilegeLevel) } type SOLConfigParam_Character struct { AccumulateInterval5Millis uint8 SendThreshold uint8 } func (p *SOLConfigParam_Character) SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) { return SOLConfigParamSelector_Character, 0x00, 0x00 } func (p *SOLConfigParam_Character) Unpack(paramData []byte) error { if len(paramData) != 2 { return fmt.Errorf("the parameter data length must be 2 byte") } p.AccumulateInterval5Millis = paramData[0] p.SendThreshold = paramData[1] return nil } func (p *SOLConfigParam_Character) Pack() []byte { return []byte{p.AccumulateInterval5Millis, p.SendThreshold} } func (p *SOLConfigParam_Character) Format() string { return fmt.Sprintf(` Accumulate Interval (ms) : %d Send Threshold : %d `, p.AccumulateInterval5Millis*5, p.SendThreshold) } type SOLConfigParam_SOLRetry struct { // 1-based. 0 = no retries after packet is transmitted. Packet will be // dropped if no ACK/NACK received by time retries expire. RetryCount uint8 // 1-based. Retry Interval in 10 ms increments. Sets the time that // the BMC will wait before the first retry and the time between retries when sending // SOL packets to the remote console. // 00h: Retries sent back-to-back RetryInterval10Millis uint8 } func (p *SOLConfigParam_SOLRetry) SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) { return SOLConfigParamSelector_SOLRetry, 0x00, 0x00 } func (p *SOLConfigParam_SOLRetry) Unpack(paramData []byte) error { if len(paramData) != 2 { return fmt.Errorf("the parameter data length must be 2 byte") } p.RetryCount = paramData[0] p.RetryInterval10Millis = paramData[1] return nil } func (p *SOLConfigParam_SOLRetry) Pack() []byte { return []byte{p.RetryCount, p.RetryInterval10Millis} } func (p *SOLConfigParam_SOLRetry) Format() string { return fmt.Sprintf(` Retry Count : %d Retry Interval (ms) : %d `, p.RetryCount, p.RetryInterval10Millis*10) } type SOLConfigParam_NonVolatileBitRate struct { BitRate uint8 } func (p *SOLConfigParam_NonVolatileBitRate) SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) { return SOLConfigParamSelector_NonVolatileBitRate, 0x00, 0x00 } func (p *SOLConfigParam_NonVolatileBitRate) Unpack(paramData []byte) error { if len(paramData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } p.BitRate = paramData[0] return nil } func (p *SOLConfigParam_NonVolatileBitRate) Pack() []byte { return []byte{p.BitRate} } func (p *SOLConfigParam_NonVolatileBitRate) Format() string { return fmt.Sprintf("%.1f kbps (%d)", bitRateKBPS(p.BitRate), p.BitRate) } func bitRateKBPS(bitRate uint8) float64 { m := map[uint8]float64{ 0x06: 9.6, 0x07: 19.2, 0x08: 38.4, 0x09: 57.6, 0x0a: 115.2, } s, ok := m[bitRate] if ok { return s } return 0 } type SOLConfigParam_VolatileBitRate struct { BitRate uint8 } func (p *SOLConfigParam_VolatileBitRate) SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) { return SOLConfigParamSelector_VolatileBitRate, 0x00, 0x00 } func (p *SOLConfigParam_VolatileBitRate) Unpack(paramData []byte) error { if len(paramData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } p.BitRate = paramData[0] return nil } func (p *SOLConfigParam_VolatileBitRate) Pack() []byte { return []byte{p.BitRate} } func (p *SOLConfigParam_VolatileBitRate) Format() string { return fmt.Sprintf("%.1f kbps (%d)", bitRateKBPS(p.BitRate), p.BitRate) } type SOLConfigParam_PayloadChannel struct { ChannelNumber uint8 } func (p *SOLConfigParam_PayloadChannel) SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) { return SOLConfigParamSelector_PayloadChannel, 0x00, 0x00 } func (p *SOLConfigParam_PayloadChannel) Unpack(paramData []byte) error { if len(paramData) != 1 { return fmt.Errorf("the parameter data length must be 1 byte") } p.ChannelNumber = paramData[0] return nil } func (p *SOLConfigParam_PayloadChannel) Pack() []byte { return []byte{p.ChannelNumber} } func (p *SOLConfigParam_PayloadChannel) Format() string { return fmt.Sprintf("%d", p.ChannelNumber) } type SOLConfigParam_PayloadPort struct { Port uint16 } func (p *SOLConfigParam_PayloadPort) SOLConfigParameter() (paramSelector SOLConfigParamSelector, setSelector uint8, blockSelector uint8) { return SOLConfigParamSelector_PayloadPort, 0x00, 0x00 } func (p *SOLConfigParam_PayloadPort) Unpack(paramData []byte) error { if len(paramData) != 2 { return fmt.Errorf("the parameter data length must be 2 byte") } p.Port, _, _ = unpackUint16L(paramData, 0) return nil } func (p *SOLConfigParam_PayloadPort) Pack() []byte { out := make([]byte, 2) packUint16L(p.Port, out, 0) return out } func (p *SOLConfigParam_PayloadPort) Format() string { return fmt.Sprintf("%d", p.Port) } golang-github-bougou-go-ipmi-0.7.2/types_system_info_params.go000066400000000000000000000315501474110527100245670ustar00rootroot00000000000000package ipmi import ( "fmt" ) type SystemInfoParamSelector uint8 const ( SystemInfoParamSelector_SetInProgress SystemInfoParamSelector = 0 SystemInfoParamSelector_SystemFirmwareVersion SystemInfoParamSelector = 1 SystemInfoParamSelector_SystemName SystemInfoParamSelector = 2 SystemInfoParamSelector_PrimaryOSName SystemInfoParamSelector = 3 SystemInfoParamSelector_OSName SystemInfoParamSelector = 4 SystemInfoParamSelector_OSVersion SystemInfoParamSelector = 5 SystemInfoParamSelector_BMCURL SystemInfoParamSelector = 6 SystemInfoParamSelector_ManagementURL SystemInfoParamSelector = 7 ) func (paramSelector SystemInfoParamSelector) String() string { m := map[SystemInfoParamSelector]string{ SystemInfoParamSelector_SetInProgress: "Set In Progress", SystemInfoParamSelector_SystemFirmwareVersion: "System Firmware Version", SystemInfoParamSelector_SystemName: "System Name", SystemInfoParamSelector_PrimaryOSName: "Primary OS Name", SystemInfoParamSelector_OSName: "OS Name", SystemInfoParamSelector_OSVersion: "OS Version", SystemInfoParamSelector_BMCURL: "BMC URL", SystemInfoParamSelector_ManagementURL: "Management URL", } s, ok := m[paramSelector] if ok { return s } return "Unknown" } type SystemInfoParameter interface { SystemInfoParameter() (paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) Parameter } var ( _ SystemInfoParameter = (*SystemInfoParam_SetInProgress)(nil) _ SystemInfoParameter = (*SystemInfoParam_SystemFirmwareVersion)(nil) _ SystemInfoParameter = (*SystemInfoParam_SystemName)(nil) _ SystemInfoParameter = (*SystemInfoParam_PrimaryOSName)(nil) _ SystemInfoParameter = (*SystemInfoParam_OSName)(nil) _ SystemInfoParameter = (*SystemInfoParam_OSVersion)(nil) _ SystemInfoParameter = (*SystemInfoParam_BMCURL)(nil) _ SystemInfoParameter = (*SystemInfoParam_ManagementURL)(nil) ) func isNilSystemInfoParamete(param SystemInfoParameter) bool { switch v := param.(type) { case *SystemInfoParam_SetInProgress: return v == nil case *SystemInfoParam_SystemFirmwareVersion: return v == nil case *SystemInfoParam_SystemName: return v == nil case *SystemInfoParam_PrimaryOSName: return v == nil case *SystemInfoParam_OSName: return v == nil case *SystemInfoParam_OSVersion: return v == nil case *SystemInfoParam_BMCURL: return v == nil case *SystemInfoParam_ManagementURL: return v == nil default: return false } } type SystemInfoParams struct { SetInProgress *SystemInfoParam_SetInProgress SystemFirmwareVersions []*SystemInfoParam_SystemFirmwareVersion SystemNames []*SystemInfoParam_SystemName PrimaryOSNames []*SystemInfoParam_PrimaryOSName OSNames []*SystemInfoParam_OSName OSVersions []*SystemInfoParam_OSVersion BMCURLs []*SystemInfoParam_BMCURL ManagementURLs []*SystemInfoParam_ManagementURL } type SystemInfo struct { SetInProgress SetInProgressState SystemFirmwareVersion string SystemName string PrimaryOSName string OSName string OSVersion string BMCURL string ManagementURL string } func (systemInfoParams *SystemInfoParams) ToSystemInfo() *SystemInfo { systemInfo := &SystemInfo{ SetInProgress: systemInfoParams.SetInProgress.Value, } systemInfo.SystemFirmwareVersion, _, _, _ = getSystemInfoStringMeta(convertToInterfaceSlice(systemInfoParams.SystemFirmwareVersions)) systemInfo.SystemName, _, _, _ = getSystemInfoStringMeta(convertToInterfaceSlice(systemInfoParams.SystemNames)) systemInfo.PrimaryOSName, _, _, _ = getSystemInfoStringMeta(convertToInterfaceSlice(systemInfoParams.PrimaryOSNames)) systemInfo.OSName, _, _, _ = getSystemInfoStringMeta(convertToInterfaceSlice(systemInfoParams.OSNames)) systemInfo.OSVersion, _, _, _ = getSystemInfoStringMeta(convertToInterfaceSlice(systemInfoParams.OSVersions)) systemInfo.BMCURL, _, _, _ = getSystemInfoStringMeta(convertToInterfaceSlice(systemInfoParams.BMCURLs)) systemInfo.ManagementURL, _, _, _ = getSystemInfoStringMeta(convertToInterfaceSlice(systemInfoParams.ManagementURLs)) return systemInfo } func (systemInfoParams *SystemInfoParams) Format() string { format := func(param SystemInfoParameter) string { if isNilSystemInfoParamete(param) { return "" } paramSelector, _, _ := param.SystemInfoParameter() content := param.Format() if content[len(content)-1] != '\n' { content += "\n" } return fmt.Sprintf("[%02d] %-24s : %s", paramSelector, paramSelector.String(), content) } formatArray := func(params []interface{}) string { if len(params) == 0 { return "" } out := "" for _, param := range params { v, ok := param.(SystemInfoParameter) if ok { out += format(v) } } s, stringDataRaw, stringDataType, stringDataLength := getSystemInfoStringMeta(params) out += fmt.Sprintf(` String Data Type : %d String Data Length : %d String Data Raw : %v String Data : %s `, stringDataType, stringDataLength, stringDataRaw, s, ) return out } out := "" out += format(systemInfoParams.SetInProgress) out += formatArray(convertToInterfaceSlice(systemInfoParams.SystemFirmwareVersions)) out += formatArray(convertToInterfaceSlice(systemInfoParams.SystemNames)) out += formatArray(convertToInterfaceSlice(systemInfoParams.PrimaryOSNames)) out += formatArray(convertToInterfaceSlice(systemInfoParams.OSNames)) out += formatArray(convertToInterfaceSlice(systemInfoParams.OSVersions)) out += formatArray(convertToInterfaceSlice(systemInfoParams.BMCURLs)) out += formatArray(convertToInterfaceSlice(systemInfoParams.ManagementURLs)) return out } func (systemInfo *SystemInfo) Format() string { return fmt.Sprintf(` Set In Progress : %s System Firmware Version : %s System Name : %s Primary OS Name : %s OS Name : %s OS Version : %s BVM URL : %s Management URL : %s `, systemInfo.SetInProgress, systemInfo.SystemFirmwareVersion, systemInfo.SystemName, systemInfo.PrimaryOSName, systemInfo.OSName, systemInfo.OSVersion, systemInfo.BMCURL, systemInfo.ManagementURL, ) } type SystemInfoParam_SetInProgress struct { Value SetInProgressState } func (p *SystemInfoParam_SetInProgress) SystemInfoParameter() (paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) { return SystemInfoParamSelector_SetInProgress, 0, 0 } func (p *SystemInfoParam_SetInProgress) Pack() []byte { return []byte{uint8(p.Value)} } func (p *SystemInfoParam_SetInProgress) Unpack(data []byte) error { if len(data) < 1 { return ErrUnpackedDataTooShortWith(len(data), 1) } p.Value = SetInProgressState(data[0]) return nil } func (p *SystemInfoParam_SetInProgress) Format() string { return p.Value.String() } type SystemInfoParam_SystemFirmwareVersion struct { SetSelector uint8 BlockData [16]byte } func (p *SystemInfoParam_SystemFirmwareVersion) SystemInfoParameter() (paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) { return SystemInfoParamSelector_SystemFirmwareVersion, 0, 0 } func (p *SystemInfoParam_SystemFirmwareVersion) Pack() []byte { out := make([]byte, 1+len(p.BlockData)) packUint8(p.SetSelector, out, 0) packBytes(p.BlockData[:], out, 1) return out } func (p *SystemInfoParam_SystemFirmwareVersion) Unpack(data []byte) error { if len(data) < 1+len(p.BlockData) { return ErrUnpackedDataTooShortWith(len(data), 1+len(p.BlockData)) } p.SetSelector = data[0] copy(p.BlockData[:], data[1:]) return nil } func (p *SystemInfoParam_SystemFirmwareVersion) Format() string { return fmt.Sprintf(` Set Selector : %d Block Data : %02x `, p.SetSelector, p.BlockData) } type SystemInfoParam_SystemName struct { SetSelector uint8 BlockData [16]byte } func (p *SystemInfoParam_SystemName) SystemInfoParameter() (paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) { return SystemInfoParamSelector_SystemName, 0, 0 } func (p *SystemInfoParam_SystemName) Pack() []byte { out := make([]byte, 1+len(p.BlockData)) packUint8(p.SetSelector, out, 0) packBytes(p.BlockData[:], out, 1) return out } func (p *SystemInfoParam_SystemName) Unpack(data []byte) error { if len(data) < 1+len(p.BlockData) { return ErrUnpackedDataTooShortWith(len(data), 1+len(p.BlockData)) } p.SetSelector = data[0] copy(p.BlockData[:], data[1:]) return nil } func (p *SystemInfoParam_SystemName) Format() string { return fmt.Sprintf(` Set Selector : %d Block Data : %02x `, p.SetSelector, p.BlockData) } type SystemInfoParam_PrimaryOSName struct { SetSelector uint8 BlockData [16]byte } func (p *SystemInfoParam_PrimaryOSName) SystemInfoParameter() (paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) { return SystemInfoParamSelector_PrimaryOSName, 0, 0 } func (p *SystemInfoParam_PrimaryOSName) Pack() []byte { out := make([]byte, 1+len(p.BlockData)) packUint8(p.SetSelector, out, 0) packBytes(p.BlockData[:], out, 1) return out } func (p *SystemInfoParam_PrimaryOSName) Unpack(data []byte) error { if len(data) < 1+len(p.BlockData) { return ErrUnpackedDataTooShortWith(len(data), 1+len(p.BlockData)) } p.SetSelector = data[0] copy(p.BlockData[:], data[1:]) return nil } func (p *SystemInfoParam_PrimaryOSName) Format() string { return fmt.Sprintf(` Set Selector : %d Block Data : %02x `, p.SetSelector, p.BlockData) } type SystemInfoParam_OSName struct { SetSelector uint8 BlockData [16]byte } func (p *SystemInfoParam_OSName) SystemInfoParameter() (paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) { return SystemInfoParamSelector_OSName, 0, 0 } func (p *SystemInfoParam_OSName) Pack() []byte { out := make([]byte, 1+len(p.BlockData)) packUint8(p.SetSelector, out, 0) packBytes(p.BlockData[:], out, 1) return out } func (p *SystemInfoParam_OSName) Unpack(data []byte) error { if len(data) < 1+len(p.BlockData) { return ErrUnpackedDataTooShortWith(len(data), 1+len(p.BlockData)) } p.SetSelector = data[0] copy(p.BlockData[:], data[1:]) return nil } func (p *SystemInfoParam_OSName) Format() string { return fmt.Sprintf(` Set Selector : %d Block Data : %02x `, p.SetSelector, p.BlockData) } type SystemInfoParam_OSVersion struct { SetSelector uint8 BlockData [16]byte } func (p *SystemInfoParam_OSVersion) SystemInfoParameter() (paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) { return SystemInfoParamSelector_OSVersion, 0, 0 } func (p *SystemInfoParam_OSVersion) Pack() []byte { out := make([]byte, 1+len(p.BlockData)) packUint8(p.SetSelector, out, 0) packBytes(p.BlockData[:], out, 1) return out } func (p *SystemInfoParam_OSVersion) Unpack(data []byte) error { if len(data) < 1+len(p.BlockData) { return ErrUnpackedDataTooShortWith(len(data), 1+len(p.BlockData)) } p.SetSelector = data[0] copy(p.BlockData[:], data[1:]) return nil } func (p *SystemInfoParam_OSVersion) Format() string { return fmt.Sprintf(` Set Selector : %d Block Data : %02x `, p.SetSelector, p.BlockData) } type SystemInfoParam_BMCURL struct { SetSelector uint8 BlockData [16]byte } func (p *SystemInfoParam_BMCURL) SystemInfoParameter() (paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) { return SystemInfoParamSelector_BMCURL, 0, 0 } func (p *SystemInfoParam_BMCURL) Pack() []byte { out := make([]byte, 1+len(p.BlockData)) packUint8(p.SetSelector, out, 0) packBytes(p.BlockData[:], out, 1) return out } func (p *SystemInfoParam_BMCURL) Unpack(data []byte) error { if len(data) < 1+len(p.BlockData) { return ErrUnpackedDataTooShortWith(len(data), 1+len(p.BlockData)) } p.SetSelector = data[0] copy(p.BlockData[:], data[1:]) return nil } func (p *SystemInfoParam_BMCURL) Format() string { return fmt.Sprintf(` Set Selector : %d Block Data : %02x `, p.SetSelector, p.BlockData) } type SystemInfoParam_ManagementURL struct { SetSelector uint8 BlockData [16]byte } func (p *SystemInfoParam_ManagementURL) SystemInfoParameter() (paramSelector SystemInfoParamSelector, setSelector uint8, blockSelector uint8) { return SystemInfoParamSelector_ManagementURL, 0, 0 } func (p *SystemInfoParam_ManagementURL) Pack() []byte { out := make([]byte, 1+len(p.BlockData)) packUint8(p.SetSelector, out, 0) packBytes(p.BlockData[:], out, 1) return out } func (p *SystemInfoParam_ManagementURL) Unpack(data []byte) error { if len(data) < 1+len(p.BlockData) { return ErrUnpackedDataTooShortWith(len(data), 1+len(p.BlockData)) } p.SetSelector = data[0] copy(p.BlockData[:], data[1:]) return nil } func (p *SystemInfoParam_ManagementURL) Format() string { return fmt.Sprintf(` Set Selector : %d Block Data : %02x `, p.SetSelector, p.BlockData) } golang-github-bougou-go-ipmi-0.7.2/udpclient.go000066400000000000000000000076011474110527100214300ustar00rootroot00000000000000package ipmi import ( "context" "fmt" "io" "net" "strconv" "sync" "time" "golang.org/x/net/proxy" ) // UDPClient exposes some common methods for communicating with UDP target addr. type UDPClient struct { // Target Host Host string // Target Port Port int proxy proxy.Dialer timeout time.Duration bufferSize int conn net.Conn // lock is used to protect udp Exchange method to prevent another // send/receive operation from occurring while one is in progress. lock sync.Mutex } func NewUDPClient(host string, port int) *UDPClient { udpClient := &UDPClient{ Host: host, Port: port, } return udpClient } func (c *UDPClient) initConn() error { if c.conn != nil { return nil } if c.proxy != nil { conn, err := c.proxy.Dial("udp", fmt.Sprintf("%s:%d", c.Host, c.Port)) if err != nil { return fmt.Errorf("udp proxy dial failed, err: %w", err) } c.conn = conn return nil } remoteAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", c.Host, c.Port)) if err != nil { return fmt.Errorf("resolve addr failed, err: %w", err) } conn, err := net.DialUDP("udp", nil, remoteAddr) if err != nil { return fmt.Errorf("udp dial failed, err: %w", err) } c.conn = conn return nil } func (c *UDPClient) SetProxy(proxy proxy.Dialer) *UDPClient { c.proxy = proxy return c } func (c *UDPClient) SetTimeout(timeout time.Duration) *UDPClient { c.timeout = timeout return c } func (c *UDPClient) SetBufferSize(bufferSize int) *UDPClient { c.bufferSize = bufferSize return c } // RemoteIP returns the parsed ip address of the target. func (c *UDPClient) RemoteIP() string { if net.ParseIP(c.Host) == nil { addrs, err := net.LookupHost(c.Host) if err == nil && len(addrs) > 0 { return addrs[0] } } return c.Host } func (c *UDPClient) LocalIPPort() (string, int) { conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", c.Host, c.Port)) if err != nil { return "", 0 } defer conn.Close() host, port, _ := net.SplitHostPort(conn.LocalAddr().String()) p, _ := strconv.Atoi(port) return host, p } func (c *UDPClient) Close() error { if c.conn == nil { return nil } if err := c.conn.Close(); err != nil { return fmt.Errorf("close udp conn failed, err: %w", err) } c.conn = nil return nil } // Exchange performs a synchronous UDP query. // It sends the request, and waits for a reply. // Exchange does not retry a failed query. // The sent content is read from reader. func (c *UDPClient) Exchange(ctx context.Context, reader io.Reader) ([]byte, error) { if err := c.initConn(); err != nil { return nil, fmt.Errorf("init udp connection failed, err: %w", err) } c.lock.Lock() defer c.lock.Unlock() recvBuffer := make([]byte, c.bufferSize) doneChan := make(chan error, 1) // recvChan stores the integer number which indicates how many bytes recvChan := make(chan int, 1) go func() { // It is possible that this action blocks, although this // should only occur in very resource-intensive situations: // - when you've filled up the socket buffer and the OS // can't dequeue the queue fast enough. _, err := io.Copy(c.conn, reader) if err != nil { doneChan <- fmt.Errorf("write to conn failed, err: %w", err) return } // Set a deadline for the Read operation so that we don't // wait forever for a server that might not respond on // a reasonable amount of time. deadline := time.Now().Add(c.timeout) err = c.conn.SetReadDeadline(deadline) if err != nil { doneChan <- fmt.Errorf("set conn read deadline failed, err: %w", err) return } nRead, err := c.conn.Read(recvBuffer) if err != nil { doneChan <- fmt.Errorf("read from conn failed, err: %w", err) return } doneChan <- nil recvChan <- nRead }() select { case <-ctx.Done(): return nil, fmt.Errorf("canceled from caller") case err := <-doneChan: if err != nil { return nil, err } recvCount := <-recvChan return recvBuffer[:recvCount], nil } } golang-github-bougou-go-ipmi-0.7.2/utils/000077500000000000000000000000001474110527100202465ustar00rootroot00000000000000golang-github-bougou-go-ipmi-0.7.2/utils/md2/000077500000000000000000000000001474110527100207305ustar00rootroot00000000000000golang-github-bougou-go-ipmi-0.7.2/utils/md2/md2.go000066400000000000000000000102331474110527100217400ustar00rootroot00000000000000// Copyright 2012-2013 Huan Truong. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // copied from: https://github.com/htruong/go-md2/blob/master/md2.go // Package md2 implements the MD2 hash algorithm as defined in RFC 1319. package md2 import ( "hash" ) func init() { } // The size of an MD2 checksum in bytes. const Size = 16 // The blocksize of MD2 in bytes. const BlockSize = 16 const _Chunk = 16 var PI_SUBST = []uint8{ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20, } // digest represents the partial evaluation of a checksum. type digest struct { digest [Size]byte // the digest, Size state [48]byte // state, 48 ints x [_Chunk]byte // temp storage buffer, 16 bytes, _Chunk nx uint8 // how many bytes are there in the buffer } func (d *digest) Reset() { for i := range d.digest { d.digest[i] = 0 } for i := range d.state { d.state[i] = 0 } for i := range d.x { d.x[i] = 0 } d.nx = 0 } // New returns a new hash.Hash computing the MD2 checksum. func New() hash.Hash { d := new(digest) d.Reset() return d } func (d *digest) Size() int { return Size } func (d *digest) BlockSize() int { return BlockSize } // Write is the interface for IO Writer func (d *digest) Write(p []byte) (nn int, err error) { nn = len(p) //d.len += uint64(nn) // If we have something left in the buffer if d.nx > 0 { n := uint8(len(p)) var i uint8 // try to copy the rest n bytes free of the buffer into the buffer // then hash the buffer if (n + d.nx) > _Chunk { n = _Chunk - d.nx } for i = 0; i < n; i++ { // copy n bytes to the buffer d.x[d.nx+i] = p[i] } d.nx += n // if we have exactly 1 block in the buffer then hash that block if d.nx == _Chunk { block(d, d.x[0:_Chunk]) d.nx = 0 } p = p[n:] } imax := len(p) / _Chunk // For the rest, try hashing by the blocksize for i := 0; i < imax; i++ { block(d, p[:_Chunk]) p = p[_Chunk:] } // Then stuff the rest that doesn't add up to a block to the buffer if len(p) > 0 { d.nx = uint8(copy(d.x[:], p)) } return } func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := *d0 // Padding. var tmp [_Chunk]byte len := uint8(d.nx) for i := range tmp { tmp[i] = _Chunk - len } d.Write(tmp[0 : _Chunk-len]) // At this state we should have nothing left in buffer if d.nx != 0 { panic("d.nx != 0") } d.Write(d.digest[0:16]) // At this state we should have nothing left in buffer if d.nx != 0 { panic("d.nx != 0") } return append(in, d.state[0:16]...) } func block(dig *digest, p []byte) { var t, i, j uint8 t = 0 for i = 0; i < 16; i++ { dig.state[i+16] = p[i] dig.state[i+32] = byte(p[i] ^ dig.state[i]) } for i = 0; i < 18; i++ { for j = 0; j < 48; j++ { dig.state[j] = byte(dig.state[j] ^ PI_SUBST[t]) t = dig.state[j] } t = byte(t + i) } t = dig.digest[15] for i = 0; i < 16; i++ { dig.digest[i] = byte(dig.digest[i] ^ PI_SUBST[p[i]^t]) t = dig.digest[i] } }