From 3aa8521cb9b89c892d7b7bf6b6c5ee7a1a82fe5f Mon Sep 17 00:00:00 2001 From: Matt Primrose Date: Tue, 21 May 2024 19:10:01 -0700 Subject: [PATCH] feat: adds event log decoder --- pkg/common/decoder.go | 5 + pkg/wsman/amt/messagelog/decoder.go | 265 +++++++++++++++++++++++ pkg/wsman/amt/messagelog/decoder_test.go | 54 ++++- pkg/wsman/amt/messagelog/log.go | 13 +- pkg/wsman/amt/messagelog/log_test.go | 68 +++++- pkg/wsman/amt/messagelog/types.go | 24 ++ 6 files changed, 422 insertions(+), 7 deletions(-) diff --git a/pkg/common/decoder.go b/pkg/common/decoder.go index f70b0139..2d9e25f1 100644 --- a/pkg/common/decoder.go +++ b/pkg/common/decoder.go @@ -28,6 +28,11 @@ func ReadIntX(v string, p int) int { return int(v[p+3])*0x1000000 + int(v[p+2])<<16 + int(v[p+1])<<8 + int(v[p]) } +// ReadBufferShort reads a short value from a byte array at position p. +func ReadBufferIntX(v []byte, p int) int { + return int(v[p+3])*0x1000000 + int(v[p+2])<<16 + int(v[p+1])<<8 + int(v[p]) +} + // ShortToStr converts a short value to a string. func ShortToStr(v int) string { return string([]byte{byte((v >> 8) & 0xFF), byte(v & 0xFF)}) diff --git a/pkg/wsman/amt/messagelog/decoder.go b/pkg/wsman/amt/messagelog/decoder.go index 7b79491b..fd9e5885 100644 --- a/pkg/wsman/amt/messagelog/decoder.go +++ b/pkg/wsman/amt/messagelog/decoder.go @@ -5,6 +5,14 @@ package messagelog +import ( + "bytes" + "encoding/base64" + "encoding/binary" + "fmt" + "time" +) + const ( AMTMessageLog string = "AMT_MessageLog" GetRecords string = "GetRecords" @@ -409,3 +417,260 @@ func (p PositionToFirstRecordReturnValue) String() string { return ValueNotFound } + +func parseEventLogResult(eventlogdata []string) (records []RawEventData, err error) { + records = []RawEventData{} + + for _, eventRecord := range eventlogdata { + decodedEventRecord, err := base64.StdEncoding.DecodeString(eventRecord) + if err != nil { + continue + } + + eventData := RawEventData{} + + buf := bytes.NewReader(decodedEventRecord) + + err = binary.Read(buf, binary.LittleEndian, &eventData.TimeStamp) + if err != nil { + return records, err + } + + err = binary.Read(buf, binary.LittleEndian, &eventData.DeviceAddress) + if err != nil { + return records, err + } + + err = binary.Read(buf, binary.LittleEndian, &eventData.EventSensorType) + if err != nil { + return records, err + } + + err = binary.Read(buf, binary.LittleEndian, &eventData.EventType) + if err != nil { + return records, err + } + + err = binary.Read(buf, binary.LittleEndian, &eventData.EventOffset) + if err != nil { + return records, err + } + + err = binary.Read(buf, binary.LittleEndian, &eventData.EventSourceType) + if err != nil { + return records, err + } + + err = binary.Read(buf, binary.LittleEndian, &eventData.EventSeverity) + if err != nil { + return records, err + } + + err = binary.Read(buf, binary.LittleEndian, &eventData.SensorNumber) + if err != nil { + return records, err + } + + err = binary.Read(buf, binary.LittleEndian, &eventData.Entity) + if err != nil { + return records, err + } + + err = binary.Read(buf, binary.LittleEndian, &eventData.EntityInstance) + if err != nil { + return records, err + } + + for i := 13; i < 21; i++ { + var b uint8 + + err = binary.Read(buf, binary.LittleEndian, &b) + if err != nil { + return records, err + } + + eventData.EventData = append(eventData.EventData, b) + } + + records = append(records, eventData) + } + + return records, err +} + +func decodeEventRecord(eventLog []RawEventData) []RefinedEventData { + refinedEventData := []RefinedEventData{} + + for _, event := range eventLog { + decodedEvent := RefinedEventData{ + TimeStamp: time.Unix(int64(event.TimeStamp), 0), + Description: decodeEventDetailString(event.EventSensorType, event.EventOffset, event.EventData), + Entity: SystemEntityTypes[int(event.Entity)], + EventSeverity: EventSeverity[int(event.EventSeverity)], + } + refinedEventData = append(refinedEventData, decodedEvent) + } + + return refinedEventData +} + +func decodeEventDetailString(eventSensorType, eventOffset uint8, eventDataField []uint8) string { + switch eventSensorType { + case 6: + value := int(eventDataField[1]) + (int(eventDataField[2]) << 8) + + return fmt.Sprintf("Authentication failed %d times. The system may be under attack.", value) + case 15: + { + if eventDataField[0] == 235 { + return "Invalid Data" + } + + if eventOffset == 0 { + return SystemFirmwareError[int(eventDataField[1])] + } + + return SystemFirmwareProgress[int(eventDataField[1])] + } + case 18: + // System watchdog event + if eventDataField[0] == 170 { + watchdog := fmt.Sprintf("%x%x%x%x-%x%x", eventDataField[4], eventDataField[3], eventDataField[2], eventDataField[1], eventDataField[6], eventDataField[5]) + watchdogCurrentState := WatchdogCurrentStates[int(eventDataField[7])] + + return fmt.Sprintf("Agent watchdog %s-... changed to %s", watchdog, watchdogCurrentState) + } + + return "Unknown event data field" + case 30: + return "No bootable media" + case 32: + return "Operating system lockup or power interrupt" + case 35: + return "System boot failure" + case 37: + return "System firmware started (at least one CPU is properly executing)." + default: + return fmt.Sprintf("Unknown Sensor Type #%d", eventSensorType) + } +} + +var EventSeverity = map[int]string{ + 0: "Unspecified", + 1: "Monitor", + 2: "Information", + 4: "OK", + 8: "Non-critical condition", + 16: "Critical condition", + 32: "Non-recoverable condition", +} + +var SystemEntityTypes = map[int]string{ + 0: "Unspecified", + 1: "Other", + 2: "Unknown", + 3: "Processor", + 4: "Disk", + 5: "Peripheral", + 6: "System management module", + 7: "System board", + 8: "Memory module", + 9: "Processor module", + 10: "Power supply", + 11: "Add in card", + 12: "Front panel board", + 13: "Back panel board", + 14: "Power system board", + 15: "Drive backplane", + 16: "System internal expansion board", + 17: "Other system board", + 18: "Processor board", + 19: "Power unit", + 20: "Power module", + 21: "Power management board", + 22: "Chassis back panel board", + 23: "System chassis", + 24: "Sub chassis", + 25: "Other chassis board", + 26: "Disk drive bay", + 27: "Peripheral bay", + 28: "Device bay", + 29: "Fan cooling", + 30: "Cooling unit", + 31: "Cable interconnect", + 32: "Memory device", + 33: "System management software", + 34: "BIOS", + 35: "Intel(r) ME", + 36: "System bus", + 37: "Group", + 38: "Intel(r) ME", + 39: "External environment", + 40: "Battery", + 41: "Processing blade", + 42: "Connectivity switch", + 43: "Processor/memory module", + 44: "I/O module", + 45: "Processor I/O module", + 46: "Management controller firmware", + 47: "IPMI channel", + 48: "PCI bus", + 49: "PCI express bus", + 50: "SCSI bus", + 51: "SATA/SAS bus", + 52: "Processor front side bus", +} + +var SystemFirmwareError = map[int]string{ + 0: "Unspecified.", + 1: "No system memory is physically installed in the system.", + 2: "No usable system memory, all installed memory has experienced an unrecoverable failure.", + 3: "Unrecoverable hard-disk/ATAPI/IDE device failure.", + 4: "Unrecoverable system-board failure.", + 5: "Unrecoverable diskette subsystem failure.", + 6: "Unrecoverable hard-disk controller failure.", + 7: "Unrecoverable PS/2 or USB keyboard failure.", + 8: "Removable boot media not found.", + 9: "Unrecoverable video controller failure.", + 10: "No video device detected.", + 11: "Firmware (BIOS) ROM corruption detected.", + 12: "CPU voltage mismatch (processors that share same supply have mismatched voltage requirements)", + 13: "CPU speed matching failure", +} + +var SystemFirmwareProgress = map[int]string{ + 0: "Unspecified.", + 1: "Memory initialization.", + 2: "Starting hard-disk initialization and test", + 3: "Secondary processor(s) initialization", + 4: "User authentication", + 5: "User-initiated system setup", + 6: "USB resource configuration", + 7: "PCI resource configuration", + 8: "Option ROM initialization", + 9: "Video initialization", + 10: "Cache initialization", + 11: "SM Bus initialization", + 12: "Keyboard controller initialization", + 13: "Embedded controller/management controller initialization", + 14: "Docking station attachment", + 15: "Enabling docking station", + 16: "Docking station ejection", + 17: "Disabling docking station", + 18: "Calling operating system wake-up vector", + 19: "Starting operating system boot process", + 20: "Baseboard or motherboard initialization", + 21: "reserved", + 22: "Floppy initialization", + 23: "Keyboard test", + 24: "Pointing device test", + 25: "Primary processor initialization", +} + +var WatchdogCurrentStates = map[int]string{ + 1: "Not Started", + 2: "Stopped", + 4: "Running", + 8: "Expired", + 16: "Suspended", +} diff --git a/pkg/wsman/amt/messagelog/decoder_test.go b/pkg/wsman/amt/messagelog/decoder_test.go index 13484d22..4ee1f070 100644 --- a/pkg/wsman/amt/messagelog/decoder_test.go +++ b/pkg/wsman/amt/messagelog/decoder_test.go @@ -5,7 +5,13 @@ package messagelog -import "testing" +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) func TestCapabilities_String(t *testing.T) { tests := []struct { @@ -301,3 +307,49 @@ func TestPositionToFirstRecordReturnValue_String(t *testing.T) { } } } + +func TestConvertToEventLogResult(t *testing.T) { + records := []string{"Y8iYZf8GbwVoEP8mYaoKAAAAAAAA", "IgYBZf8PbwJoAf8iAEAHAAAAAAAA", "IgYBZf8PbwJoAf8iAEAHAAAAAAAA"} + expectedResult := []RawEventData{{TimeStamp: 0x6598c863, DeviceAddress: 0xff, EventSensorType: 0x6, EventType: 0x6f, EventOffset: 0x5, EventSourceType: 0x68, EventSeverity: 0x10, SensorNumber: 0xff, Entity: 0x26, EntityInstance: 0x61, EventData: []uint8{0xaa, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, {TimeStamp: 0x65010622, DeviceAddress: 0xff, EventSensorType: 0xf, EventType: 0x6f, EventOffset: 0x2, EventSourceType: 0x68, EventSeverity: 0x1, SensorNumber: 0xff, Entity: 0x22, EntityInstance: 0x0, EventData: []uint8{0x40, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, {TimeStamp: 0x65010622, DeviceAddress: 0xff, EventSensorType: 0xf, EventType: 0x6f, EventOffset: 0x2, EventSourceType: 0x68, EventSeverity: 0x1, SensorNumber: 0xff, Entity: 0x22, EntityInstance: 0x0, EventData: []uint8{0x40, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}} + expectedDecodedResult := []RefinedEventData{{TimeStamp: time.Date(2024, time.January, 5, 20, 26, 27, 0, time.Local), Description: "Authentication failed 10 times. The system may be under attack.", Entity: "Intel(r) ME", EventSeverity: "Critical condition"}, {TimeStamp: time.Date(2023, time.September, 12, 17, 45, 22, 0, time.Local), Description: "PCI resource configuration", Entity: "BIOS", EventSeverity: "Monitor"}, {TimeStamp: time.Date(2023, time.September, 12, 17, 45, 22, 0, time.Local), Description: "PCI resource configuration", Entity: "BIOS", EventSeverity: "Monitor"}} + + result, err := parseEventLogResult(records) + if err != nil { + t.Errorf("Error: %v", err) + } + + decodedResult := decodeEventRecord(result) + + assert.Equal(t, expectedResult, result) + assert.Equal(t, expectedDecodedResult, decodedResult) +} + +func TestDecodeEventDetailString(t *testing.T) { + tests := []struct { + eventSensorType uint8 + eventOffset uint8 + eventDataField []uint8 + expected string + }{ + {6, 0, []uint8{0, 5, 0}, "Authentication failed 5 times. The system may be under attack."}, + {6, 0, []uint8{0, 1, 1}, "Authentication failed 257 times. The system may be under attack."}, + {15, 0, []uint8{235}, "Invalid Data"}, + {15, 0, []uint8{0, 1}, "No system memory is physically installed in the system."}, + {15, 1, []uint8{0, 2}, "Starting hard-disk initialization and test"}, + {18, 0, []uint8{170, 1, 2, 3, 4, 5, 6, 1}, "Agent watchdog 4321-65-... changed to Not Started"}, + {30, 0, nil, "No bootable media"}, + {32, 0, nil, "Operating system lockup or power interrupt"}, + {35, 0, nil, "System boot failure"}, + {37, 0, nil, "System firmware started (at least one CPU is properly executing)."}, + {0, 0, nil, "Unknown Sensor Type #0"}, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("eventSensorType=%d/eventOffset=%d", test.eventSensorType, test.eventOffset), func(t *testing.T) { + result := decodeEventDetailString(test.eventSensorType, test.eventOffset, test.eventDataField) + if result != test.expected { + t.Errorf("Expected %q but got %q", test.expected, result) + } + }) + } +} diff --git a/pkg/wsman/amt/messagelog/log.go b/pkg/wsman/amt/messagelog/log.go index 8221db00..0e5adb97 100644 --- a/pkg/wsman/amt/messagelog/log.go +++ b/pkg/wsman/amt/messagelog/log.go @@ -124,15 +124,22 @@ func (messageLog Service) GetRecords(identifier int) (response Response, err err // send the message to AMT err = messageLog.base.Execute(response.Message) if err != nil { - return + return response, err } // put the xml response into the go struct err = xml.Unmarshal([]byte(response.XMLOutput), &response) if err != nil { - return + return response, err } - return + response.Body.GetRecordsResponse.RawEventData, err = parseEventLogResult(response.Body.GetRecordsResponse.RecordArray) + if err != nil { + return response, err + } + + response.Body.GetRecordsResponse.RefinedEventData = decodeEventRecord(response.Body.GetRecordsResponse.RawEventData) + + return response, err } // Requests that an iteration of the MessageLog be established and that the iterator be set to the first entry in the Log. An identifier for the iterator is returned as an output parameter of the method. Regarding iteration, you have 2 choices: 1) Embed iteration data in the method call, and allow implementations to track/ store this data manually; or, 2) Iterate using a separate object (for example, class ActiveIterator) as an iteration agent. The first approach is used here for interoperability. The second requires an instance of the Iterator object for EACH iteration in progress. 2's functionality could be implemented underneath 1. diff --git a/pkg/wsman/amt/messagelog/log_test.go b/pkg/wsman/amt/messagelog/log_test.go index 00208ed0..5f7a2e95 100644 --- a/pkg/wsman/amt/messagelog/log_test.go +++ b/pkg/wsman/amt/messagelog/log_test.go @@ -8,6 +8,7 @@ package messagelog import ( "encoding/xml" "testing" + "time" "github.com/stretchr/testify/assert" @@ -22,7 +23,7 @@ func TestJson(t *testing.T) { GetResponse: MessageLogResponse{}, }, } - expectedResult := "{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"GetResponse\":{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"Capabilities\":null,\"CharacterSet\":0,\"CreationClassName\":\"\",\"CurrentNumberOfRecords\":0,\"ElementName\":\"\",\"EnabledDefault\":0,\"EnabledState\":0,\"HealthState\":0,\"IsFrozen\":false,\"LastChange\":0,\"LogState\":0,\"MaxLogSize\":0,\"MaxNumberOfRecords\":0,\"MaxRecordSize\":0,\"Name\":\"\",\"OperationalStatus\":null,\"OverwritePolicy\":0,\"PercentageNearFull\":0,\"RequestedState\":0,\"SizeOfHeader\":0,\"SizeOfRecordHeader\":0,\"Status\":\"\"},\"EnumerateResponse\":{\"EnumerationContext\":\"\"},\"PullResponse\":{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"MessageLogItems\":null},\"GetRecordsResponse\":{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"IterationIdentifier\":0,\"NoMoreRecords\":false,\"RecordArray\":null,\"ReturnValue\":0},\"PositionToFirstRecordResponse\":{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"IterationIdentifier\":0,\"ReturnValue\":0}}" + expectedResult := "{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"GetResponse\":{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"Capabilities\":null,\"CharacterSet\":0,\"CreationClassName\":\"\",\"CurrentNumberOfRecords\":0,\"ElementName\":\"\",\"EnabledDefault\":0,\"EnabledState\":0,\"HealthState\":0,\"IsFrozen\":false,\"LastChange\":0,\"LogState\":0,\"MaxLogSize\":0,\"MaxNumberOfRecords\":0,\"MaxRecordSize\":0,\"Name\":\"\",\"OperationalStatus\":null,\"OverwritePolicy\":0,\"PercentageNearFull\":0,\"RequestedState\":0,\"SizeOfHeader\":0,\"SizeOfRecordHeader\":0,\"Status\":\"\"},\"EnumerateResponse\":{\"EnumerationContext\":\"\"},\"PullResponse\":{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"MessageLogItems\":null},\"GetRecordsResponse\":{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"IterationIdentifier\":0,\"NoMoreRecords\":false,\"RecordArray\":null,\"RawEventDataArray\":null,\"RefinedEventDataArray\":null,\"ReturnValue\":0},\"PositionToFirstRecordResponse\":{\"XMLName\":{\"Space\":\"\",\"Local\":\"\"},\"IterationIdentifier\":0,\"ReturnValue\":0}}" result := response.JSON() assert.Equal(t, expectedResult, result) } @@ -33,7 +34,7 @@ func TestYaml(t *testing.T) { GetResponse: MessageLogResponse{}, }, } - expectedResult := "xmlname:\n space: \"\"\n local: \"\"\ngetresponse:\n xmlname:\n space: \"\"\n local: \"\"\n capabilities: []\n characterset: 0\n creationclassname: \"\"\n currentnumberofrecords: 0\n elementname: \"\"\n enableddefault: 0\n enabledstate: 0\n healthstate: 0\n isfrozen: false\n lastchange: 0\n logstate: 0\n maxlogsize: 0\n maxnumberofrecords: 0\n maxrecordsize: 0\n name: \"\"\n operationalstatus: []\n overwritepolicy: 0\n percentagenearfull: 0\n requestedstate: 0\n sizeofheader: 0\n sizeofrecordheader: 0\n status: \"\"\nenumerateresponse:\n enumerationcontext: \"\"\npullresponse:\n xmlname:\n space: \"\"\n local: \"\"\n messagelogitems: []\ngetrecordsresponse:\n xmlname:\n space: \"\"\n local: \"\"\n iterationidentifier: 0\n nomorerecords: false\n recordarray: []\n returnvalue: 0\npositiontofirstrecordresponse:\n xmlname:\n space: \"\"\n local: \"\"\n iterationidentifier: 0\n returnvalue: 0\n" + expectedResult := "xmlname:\n space: \"\"\n local: \"\"\ngetresponse:\n xmlname:\n space: \"\"\n local: \"\"\n capabilities: []\n characterset: 0\n creationclassname: \"\"\n currentnumberofrecords: 0\n elementname: \"\"\n enableddefault: 0\n enabledstate: 0\n healthstate: 0\n isfrozen: false\n lastchange: 0\n logstate: 0\n maxlogsize: 0\n maxnumberofrecords: 0\n maxrecordsize: 0\n name: \"\"\n operationalstatus: []\n overwritepolicy: 0\n percentagenearfull: 0\n requestedstate: 0\n sizeofheader: 0\n sizeofrecordheader: 0\n status: \"\"\nenumerateresponse:\n enumerationcontext: \"\"\npullresponse:\n xmlname:\n space: \"\"\n local: \"\"\n messagelogitems: []\ngetrecordsresponse:\n xmlname:\n space: \"\"\n local: \"\"\n iterationidentifier: 0\n nomorerecords: false\n recordarray: []\n raweventdataarray: []\n refinedeventdataarray: []\n returnvalue: 0\npositiontofirstrecordresponse:\n xmlname:\n space: \"\"\n local: \"\"\n iterationidentifier: 0\n returnvalue: 0\n" result := response.YAML() assert.Equal(t, expectedResult, result) } @@ -196,7 +197,68 @@ func TestPositiveAMT_MessageLog(t *testing.T) { IterationIdentifier: 3, NoMoreRecords: true, RecordArray: []string{"Y8iYZf8GbwVoEP8mYaoKAAAAAAAA", "IgYBZf8PbwJoAf8iAEAHAAAAAAAA", "IgYBZf8PbwJoAf8iAEAHAAAAAAAA"}, - ReturnValue: 0, + RawEventData: []RawEventData{ + { + TimeStamp: 0x6598c863, + DeviceAddress: 0xff, + EventSensorType: 0x6, + EventType: 0x6f, + EventOffset: 0x5, + EventSourceType: 0x68, + EventSeverity: 0x10, + SensorNumber: 0xff, + Entity: 0x26, + EntityInstance: 0x61, + EventData: []uint8{0xaa, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + }, + { + TimeStamp: 0x65010622, + DeviceAddress: 0xff, + EventSensorType: 0xf, + EventType: 0x6f, + EventOffset: 0x2, + EventSourceType: 0x68, + EventSeverity: 0x1, + SensorNumber: 0xff, + Entity: 0x22, + EntityInstance: 0x0, + EventData: []uint8{0x40, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + }, + { + TimeStamp: 0x65010622, + DeviceAddress: 0xff, + EventSensorType: 0xf, + EventType: 0x6f, + EventOffset: 0x2, + EventSourceType: 0x68, + EventSeverity: 0x1, + SensorNumber: 0xff, + Entity: 0x22, + EntityInstance: 0x0, + EventData: []uint8{0x40, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + }, + }, + RefinedEventData: []RefinedEventData{ + { + TimeStamp: time.Date(2024, time.January, 5, 20, 26, 27, 0, time.Local), + Description: "Authentication failed 10 times. The system may be under attack.", + Entity: "Intel(r) ME", + EventSeverity: "Critical condition", + }, + { + TimeStamp: time.Date(2023, time.September, 12, 17, 45, 22, 0, time.Local), + Description: "PCI resource configuration", + Entity: "BIOS", + EventSeverity: "Monitor", + }, + { + TimeStamp: time.Date(2023, time.September, 12, 17, 45, 22, 0, time.Local), + Description: "PCI resource configuration", + Entity: "BIOS", + EventSeverity: "Monitor", + }, + }, + ReturnValue: 0, }, }, }, diff --git a/pkg/wsman/amt/messagelog/types.go b/pkg/wsman/amt/messagelog/types.go index 8b9a4f47..0f02e984 100644 --- a/pkg/wsman/amt/messagelog/types.go +++ b/pkg/wsman/amt/messagelog/types.go @@ -7,6 +7,7 @@ package messagelog import ( "encoding/xml" + "time" "github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/internal/message" "github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/client" @@ -72,6 +73,8 @@ type ( IterationIdentifier int `xml:"IterationIdentifier"` // An identifier for the iterator. NoMoreRecords bool `xml:"NoMoreRecords"` // Indicates that there are no more records to read RecordArray []string `xml:"RecordArray"` // Array of records encoded as Base64 + RawEventData []RawEventData `xml:"RawEventData"` // Slice of raw event data + RefinedEventData []RefinedEventData `xml:"RefinedEventData"` // Slice of refined event data ReturnValue GetRecordsReturnValue `xml:"ReturnValue"` // ValueMap={0, 1, 2, 3} Values={Completed with No Error, Not Supported, Invalid record pointed, No record exists in log} } @@ -81,6 +84,27 @@ type ( ReturnValue PositionToFirstRecordReturnValue `xml:"ReturnValue"` // ValueMap={0, 1, 2} Values={Completed with No Error, Not Supported, No record exists} } + RawEventData struct { + TimeStamp uint32 + DeviceAddress uint8 + EventSensorType uint8 + EventType uint8 + EventOffset uint8 + EventSourceType uint8 + EventSeverity uint8 + SensorNumber uint8 + Entity uint8 + EntityInstance uint8 + EventData []uint8 + } + + RefinedEventData struct { + TimeStamp time.Time + Description string + Entity string + EventSeverity string + } + // Capabilities is an array of integers indicating the Log capabilities. Capabilities int