├── .clang-format ├── .clang-tidy ├── CHANGELOG.md ├── Doxyfile.in ├── LICENSE ├── OWNERS ├── README.md ├── abi └── x86_64 │ └── gcc.dump ├── docs ├── checklists │ ├── changes.md │ └── releases.md ├── fuzzing.md └── oem │ └── meta │ └── file-io.md ├── evolutions ├── current │ ├── crc32.yaml │ └── crc8.yaml └── v0.9.1 │ ├── get_fru_record_by_option_check.yaml │ ├── oem-ibm-header-compat.cocci │ ├── pldm_bios_table_append_pad_checksum_check.yaml │ ├── pldm_bios_table_attr_entry_enum_decode_def_num_check.yaml │ ├── pldm_bios_table_attr_entry_enum_decode_pv_hdls_check.yaml │ ├── pldm_bios_table_attr_entry_enum_decode_pv_num_check.yaml │ ├── pldm_bios_table_attr_entry_enum_encode_check.yaml │ ├── pldm_bios_table_attr_entry_integer_encode_check.yaml │ ├── pldm_bios_table_attr_entry_string_decode_def_string_length_check.yaml │ ├── pldm_bios_table_attr_entry_string_encode_check.yaml │ ├── pldm_bios_table_attr_value_entry_encode_enum_check.yaml │ ├── pldm_bios_table_attr_value_entry_encode_integer_check.yaml │ ├── pldm_bios_table_attr_value_entry_encode_string_check.yaml │ ├── pldm_bios_table_string_entry_decode_string_check.yaml │ ├── pldm_bios_table_string_entry_encode_check.yaml │ ├── pldm_entity_association_pdr_add_check.yaml │ ├── pldm_entity_association_pdr_add_from_node_check.yaml │ ├── pldm_pdr_add_check.yaml │ └── pldm_pdr_add_fru_record_set_check.yaml ├── include ├── libpldm │ ├── api.h │ ├── base.h │ ├── bios.h │ ├── bios_table.h │ ├── compiler.h │ ├── control.h │ ├── entity.h │ ├── file.h │ ├── firmware_fd.h │ ├── firmware_update.h │ ├── fru.h │ ├── instance-id.h │ ├── meson.build │ ├── oem │ │ ├── ibm │ │ │ ├── entity.h │ │ │ ├── file_io.h │ │ │ ├── fru.h │ │ │ ├── host.h │ │ │ ├── platform.h │ │ │ └── state_set.h │ │ └── meta │ │ │ └── file_io.h │ ├── pdr.h │ ├── platform.h │ ├── pldm.h │ ├── pldm_types.h │ ├── sizes.h.in │ ├── state_set.h │ ├── states.h │ ├── transport.h │ ├── transport │ │ ├── af-mctp.h │ │ └── mctp-demux.h │ └── utils.h └── meson.build ├── instance-db └── default ├── meson.build ├── meson.options ├── scripts ├── abi-dump-formatter ├── abi-dump-updater ├── apply-renames ├── changelog.awk ├── pre-submit └── run-ci ├── src ├── api.h ├── array.h ├── compiler.h ├── control-internal.h ├── control.c ├── dsp │ ├── base.c │ ├── base.h │ ├── bios.c │ ├── bios_table.c │ ├── file.c │ ├── firmware_update.c │ ├── fru.c │ ├── meson.build │ ├── pdr.c │ └── platform.c ├── firmware_device │ ├── fd-internal.h │ ├── fd.c │ └── meson.build ├── mctp-defines.h ├── meson.build ├── msgbuf.h ├── msgbuf │ └── platform.h ├── oem │ ├── ibm │ │ ├── file_io.c │ │ ├── host.c │ │ ├── meson.build │ │ └── platform.c │ └── meta │ │ ├── file_io.c │ │ └── meson.build ├── requester │ ├── instance-id.c │ └── meson.build ├── responder.c ├── responder.h ├── transport │ ├── af-mctp.c │ ├── container-of.h │ ├── mctp-demux.c │ ├── meson.build │ ├── socket.c │ ├── socket.h │ ├── test.c │ ├── test.h │ ├── transport.c │ └── transport.h └── utils.c ├── subprojects └── googletest.wrap └── tests ├── .clang-format ├── dsp ├── base.cpp ├── bios.cpp ├── bios_table.cpp ├── bios_table_iter.c ├── file.cpp ├── firmware_update.cpp ├── fru.cpp ├── meson.build ├── pdr.cpp └── platform.cpp ├── fuzz ├── fd-fuzz-input1.dat ├── fd-fuzz.cpp ├── fd.dict ├── fuzz-build.py ├── fuzz-coverage.py └── meson.build ├── instance-id.cpp ├── meson.build ├── msgbuf.cpp ├── msgbuf_generic.c ├── oem ├── ibm │ ├── fileio.cpp │ ├── host.cpp │ └── meson.build └── meta │ ├── fileio.cpp │ └── meson.build ├── responder.cpp ├── transport ├── meson.build ├── send_recv_one.cpp ├── send_recv_timeout.cpp ├── send_recv_unwanted.cpp ├── send_recv_wrong_command_code.cpp ├── send_recv_wrong_pldm_type.cpp └── transport.cpp └── utils.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # Originally from Linux v5.6 4 | --- 5 | AccessModifierOffset: -4 6 | AlignAfterOpenBracket: Align 7 | AlignConsecutiveMacros: true 8 | AlignConsecutiveAssignments: false 9 | AlignConsecutiveDeclarations: false 10 | #AlignEscapedNewlines: Left # Unknown to clang-format-4.0 11 | AlignOperands: Align 12 | AlignTrailingComments: 13 | Kind: Always 14 | OverEmptyLines: 1 15 | AllowAllParametersOfDeclarationOnNextLine: false 16 | AllowShortBlocksOnASingleLine: false 17 | AllowShortCaseLabelsOnASingleLine: false 18 | AllowShortFunctionsOnASingleLine: None 19 | AllowShortIfStatementsOnASingleLine: false 20 | AllowShortLoopsOnASingleLine: false 21 | AlwaysBreakAfterDefinitionReturnType: None 22 | AlwaysBreakAfterReturnType: None 23 | AlwaysBreakBeforeMultilineStrings: false 24 | AlwaysBreakTemplateDeclarations: false 25 | BinPackArguments: true 26 | BinPackParameters: true 27 | BraceWrapping: 28 | AfterClass: false 29 | AfterControlStatement: false 30 | AfterEnum: false 31 | AfterFunction: true 32 | AfterNamespace: true 33 | AfterObjCDeclaration: false 34 | AfterStruct: false 35 | AfterUnion: false 36 | #AfterExternBlock: false # Unknown to clang-format-5.0 37 | BeforeCatch: false 38 | BeforeElse: false 39 | IndentBraces: false 40 | #SplitEmptyFunction: true # Unknown to clang-format-4.0 41 | #SplitEmptyRecord: true # Unknown to clang-format-4.0 42 | #SplitEmptyNamespace: true # Unknown to clang-format-4.0 43 | BreakAfterAttributes: Never 44 | BreakBeforeBinaryOperators: None 45 | BreakBeforeBraces: Custom 46 | #BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 47 | BreakBeforeTernaryOperators: false 48 | BreakConstructorInitializersBeforeComma: false 49 | #BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 50 | BreakAfterJavaFieldAnnotations: false 51 | BreakStringLiterals: false 52 | ColumnLimit: 80 53 | CommentPragmas: '^ IWYU pragma:' 54 | #CompactNamespaces: false # Unknown to clang-format-4.0 55 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 56 | ConstructorInitializerIndentWidth: 8 57 | ContinuationIndentWidth: 8 58 | Cpp11BracedListStyle: false 59 | DeriveLineEnding: false 60 | DerivePointerAlignment: false 61 | DisableFormat: false 62 | ExperimentalAutoDetectBinPacking: false 63 | #FixNamespaceComments: false # Unknown to clang-format-4.0 64 | #IncludeBlocks: Preserve # Unknown to clang-format-5.0 65 | IncludeCategories: 66 | - Regex: '.*' 67 | Priority: 1 68 | IncludeIsMainRegex: '(Test)?$' 69 | IndentCaseLabels: false 70 | IndentExternBlock: NoIndent 71 | #IndentPPDirectives: None # Unknown to clang-format-5.0 72 | IndentWidth: 8 73 | IndentWrappedFunctionNames: false 74 | InsertNewlineAtEOF: true 75 | JavaScriptQuotes: Leave 76 | JavaScriptWrapImports: true 77 | KeepEmptyLinesAtTheStartOfBlocks: false 78 | LineEnding: LF 79 | MacroBlockBegin: '' 80 | MacroBlockEnd: '' 81 | MaxEmptyLinesToKeep: 1 82 | NamespaceIndentation: Inner 83 | #ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 84 | ObjCBlockIndentWidth: 8 85 | ObjCSpaceAfterProperty: true 86 | ObjCSpaceBeforeProtocolList: true 87 | 88 | # Taken from git's rules 89 | PenaltyBreakAssignment: 10 90 | PenaltyBreakBeforeFirstCallParameter: 30 91 | PenaltyBreakComment: 10 92 | PenaltyBreakFirstLessLess: 0 93 | PenaltyBreakString: 10 94 | PenaltyExcessCharacter: 100 95 | PenaltyReturnTypeOnItsOwnLine: 60 96 | 97 | PointerAlignment: Right 98 | ReflowComments: false 99 | SortIncludes: false 100 | #SortUsingDeclarations: false # Unknown to clang-format-4.0 101 | SpaceAfterCStyleCast: false 102 | SpaceAfterTemplateKeyword: true 103 | SpaceBeforeAssignmentOperators: true 104 | #SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 105 | #SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 106 | SpaceBeforeParens: ControlStatements 107 | #SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 108 | SpaceInEmptyParentheses: false 109 | SpacesBeforeTrailingComments: 1 110 | SpacesInAngles: false 111 | SpacesInContainerLiterals: false 112 | SpacesInCStyleCastParentheses: false 113 | SpacesInParentheses: false 114 | SpacesInSquareBrackets: false 115 | Standard: Cpp03 116 | TabWidth: 8 117 | UseTab: Always 118 | ... 119 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # OWNERS 2 | # ------ 3 | # 4 | # The OWNERS file maintains the list of individuals responsible for various 5 | # parts of this repository, including code review and approval. We use the 6 | # Gerrit 'owners' plugin, which consumes this file, along with some extra 7 | # keywords for our own purposes and tooling. 8 | # 9 | # For details on the configuration used by 'owners' see: 10 | # https://gerrit.googlesource.com/plugins/owners/+/refs/heads/master/owners/src/main/resources/Documentation/config.md 11 | # 12 | # An OWNERS file must be in the root of a repository but may also be present 13 | # in any subdirectory. The contents of the subdirectory OWNERS file are 14 | # combined with parent directories unless 'inherit: false' is set. 15 | # 16 | # The owners file is YAML and has [up to] 4 top-level keywords. 17 | # * owners: A list of individuals who have approval authority on the 18 | # repository. 19 | # 20 | # * reviewers: A list of individuals who have requested review notification 21 | # on the repository. 22 | # 23 | # * matchers: A list of specific file/path matchers for granular 'owners' and 24 | # 'reviewers'. See 'owners' plugin documentation. 25 | # 26 | # * openbmc: A list of openbmc-specific meta-data about owners and reviewers. 27 | # - name: preferred name of the individual. 28 | # - email: preferred email address of the individual. 29 | # - discord: Discord nickname of the individual. 30 | # 31 | # It is expected that these 4 sections will be listed in the order above and 32 | # data within them will be kept sorted. 33 | 34 | owners: 35 | - andrew@codeconstruct.com.au 36 | 37 | reviewers: 38 | - manojkiran.eda@gmail.com 39 | - rushtotom@gmail.com 40 | - pavithrabarithaya07@gmail.com 41 | 42 | matchers: 43 | 44 | openbmc: 45 | - name: Andrew Jeffery 46 | email: andrew@codeconstruct.com.au 47 | discord: arj 48 | - name: Manojkiran Eda 49 | email: manojkiran.eda@gmail.com 50 | discord: manojkiran 51 | - name: Tom Joseph 52 | email: rushtotom@gmail.com 53 | discord: tomjose 54 | - name: Pavithra Barithaya 55 | email: pavithrabarithaya07@gmail.com 56 | discord: Pavithra B 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libpldm 2 | 3 | This is a library which deals with the encoding and decoding of PLDM messages. 4 | It should be possible to use this library by projects other than OpenBMC, and 5 | hence certain constraints apply to it: 6 | 7 | - keeping it light weight 8 | - implementation in C 9 | - minimal dynamic memory allocations 10 | - endian-safe 11 | - no OpenBMC specific dependencies 12 | 13 | Source files are named according to the PLDM Type, for eg base.[h/c], fru.[h/c], 14 | etc. 15 | 16 | Given a PLDM command "foo", the library will provide the following API: For the 17 | Requester function: 18 | 19 | ```c 20 | encode_foo_req() - encode a foo request 21 | decode_foo_resp() - decode a response to foo 22 | ``` 23 | 24 | For the Responder function: 25 | 26 | ```c 27 | decode_foo_req() - decode a foo request 28 | encode_foo_resp() - encode a response to foo 29 | ``` 30 | 31 | The library also provides API to pack and unpack PLDM headers. 32 | 33 | ## To Build 34 | 35 | `libpldm` is configured and built using `meson`. Python's `pip` or 36 | [`pipx`][pipx] can be used to install a recent version on your machine: 37 | 38 | [pipx]: https://pipx.pypa.io/latest/ 39 | 40 | ```sh 41 | pipx install meson 42 | ``` 43 | 44 | Once `meson` is installed: 45 | 46 | ```sh 47 | meson setup build && meson compile -C build 48 | ``` 49 | 50 | ## To run unit tests 51 | 52 | ```sh 53 | meson test -C build 54 | ``` 55 | 56 | ## Working with `libpldm` 57 | 58 | Components of the library ABI[^1] (loosely, functions) are separated into three 59 | categories: 60 | 61 | [^1]: ["library API + compiler ABI = library ABI"][libstdc++-library-abi] 62 | 63 | [libstdc++-library-abi]: 64 | https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html 65 | 66 | 1. Stable 67 | 2. Testing 68 | 3. Deprecated 69 | 70 | Applications depending on `libpldm` should aim to only use functions from the 71 | stable category. However, this may not always be possible. What to do when 72 | required functions fall into the deprecated or testing categories is outlined 73 | below. 74 | 75 | ### What does it mean to mark a function as stable? 76 | 77 | Marking a function as stable makes the following promise to users of the 78 | library: 79 | 80 | > We will not remove or change the symbol name, argument count, argument types, 81 | > return type, or interpretation of relevant values for the function before 82 | > first marking it as `LIBPLDM_ABI_DEPRECATED` and then subsequently creating a 83 | > tagged release 84 | 85 | Marking a function as stable does _not_ promise that it is free of 86 | implementation bugs. It is just a promise that the prototype won't change 87 | without notice. 88 | 89 | Given this, it is always okay to implement functions marked stable in terms of 90 | functions marked testing inside of libpldm. If we remove or change the prototype 91 | of a function marked testing the only impact is that we need to fix up any call 92 | sites of that function in the same patch. 93 | 94 | ### The ABI lifecycle 95 | 96 | ```mermaid 97 | --- 98 | title: libpldm symbol lifecycle 99 | --- 100 | stateDiagram-v2 101 | direction LR 102 | [*] --> Testing: Add 103 | Testing --> Testing: Change 104 | Testing --> [*]: Remove 105 | Testing --> Stable: Stabilise 106 | Stable --> Deprecated: Deprecate 107 | Deprecated --> [*]: Remove 108 | ``` 109 | 110 | The ABI of the library produced by the build is controlled using the `abi` meson 111 | option. The following use cases determine how the `abi` option should be 112 | specified: 113 | 114 | | Use Case | Meson Configuration | 115 | | ----------- | --------------------------------- | 116 | | Production | `-Dabi=deprecated,stable` | 117 | | Maintenance | `-Dabi=stable` | 118 | | Development | `-Dabi=deprecated,stable,testing` | 119 | 120 | ### Maintenance 121 | 122 | Applications and libraries that depend on `libpldm` can identify how to migrate 123 | off of deprecated APIs by constraining the library ABI to the stable category. 124 | This will force the compiler identify any call-sites that try to link against 125 | deprecated symbols. 126 | 127 | ### Development 128 | 129 | Applications and libraries often require functionality that doesn't yet exist in 130 | `libpldm`. The work is thus in two parts: 131 | 132 | 1. Add the required APIs to `libpldm` 133 | 2. Use the new APIs from `libpldm` in the dependent application or library 134 | 135 | Adding APIs to a library is a difficult task. Generally, once an API is exposed 136 | in the library's ABI, any changes to the API risk breaking applications already 137 | making use of it. To make sure we have more than one shot at getting an API 138 | right, all new APIs must first be exposed in the testing category. Concretely: 139 | 140 | Patches adding new APIs MUST mark them as testing and MUST NOT mark them as 141 | stable. 142 | 143 | ### Marking functions as testing, stable or deprecated 144 | 145 | Three macros are provided through `config.h` (automatically included for all 146 | translation units) to mark functions as testing, stable or deprecated: 147 | 148 | 1. `LIBPLDM_ABI_TESTING` 149 | 2. `LIBPLDM_ABI_STABLE` 150 | 3. `LIBPLDM_ABI_DEPRECATED` 151 | 152 | These annotations go immediately before your function signature: 153 | 154 | ```c 155 | LIBPLDM_ABI_TESTING 156 | pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport, 157 | pldm_tid_t tid, 158 | const void *pldm_req_msg, 159 | size_t req_msg_len) 160 | { 161 | ... 162 | } 163 | ``` 164 | 165 | ### Requirements for stabilising a function 166 | 167 | As mentioned above, all new functions must first be added in the testing 168 | category (using the `LIBPLDM_ABI_TESTING` annotation). 169 | 170 | To move a function from the testing category to the stable category, its 171 | required that patches demonstrating use of the function in a dependent 172 | application or library be linked in the commit message of the stabilisation 173 | change. We require this to demonstrate that the implementer has considered its 174 | use in context _before_ preventing us from making changes to the API. 175 | 176 | ### Building a dependent application or library against a testing ABI 177 | 178 | Meson is broadly used in the OpenBMC ecosystem, the historical home of 179 | `libpldm`. Meson's subprojects are a relatively painless way of managing 180 | dependencies for the purpose of developing complex applications and libraries. 181 | Use of `libpldm` as a subproject is both supported and encouraged. 182 | 183 | `libpldm`'s ABI can be controlled from a parent project through meson's 184 | subproject configuration syntax: 185 | 186 | ```shell 187 | meson setup ... -Dlibpldm:abi=deprecated,stable,testing ... 188 | ``` 189 | 190 | ## OEM/vendor-specific functions 191 | 192 | libpldm accepts support for OEM or vendor-specific extensions. To add support 193 | for an OEM's extensions: 194 | 195 | 1. Document the wire format for all OEM messages under `docs/oem/${OEM_NAME}/` 196 | 197 | 2. Add public OEM API declarations and definitions under 198 | `include/libpldm/oem/${OEM_NAME}/`, and install them to the same relative 199 | location. 200 | 201 | 3. Implement the public OEM APIs under `src/oem/${OEM_NAME}/` 202 | 203 | 4. Implement the OEM API tests under `tests/oem/${OEM_NAME}/` 204 | 205 | The `${OEM_NAME}` folder must be created with the name of the OEM/vendor in 206 | lower case. 207 | 208 | Finally, the OEM name must be added to the list of choices for the `oem` meson 209 | option, and the `meson.build` files updated throughout the tree to guard 210 | integration of the OEM extensions. 211 | -------------------------------------------------------------------------------- /docs/checklists/releases.md: -------------------------------------------------------------------------------- 1 | # Checklist for making releases of `libpldm` 2 | 3 | ## Meson 4 | 5 | - [ ] Update the version in `meson.build` 6 | 7 | ## ABI 8 | 9 | - [ ] Generate the ABI dump for the release 10 | 11 | - This must be done from a shell session inside the OpenBMC CI Docker 12 | container for consistency 13 | 14 | ## Evolutions 15 | 16 | - [ ] Rename the directory for unreleased evolutions 17 | 18 | ## CHANGELOG 19 | 20 | - [ ] Replace the `Unreleased` header with the tag value and the date 21 | - [ ] Remove headers of empty sections from current release 22 | - [ ] Introduce new `Unreleased` header 23 | - [ ] Add the usual list of headers with empty sections 24 | 25 | ## Tagging 26 | 27 | - [ ] Commit the changes above with the subject `libpldm: Release ` 28 | - [ ] Push the release commit for review in Gerrit 29 | - [ ] Submit the release commit once approved 30 | - [ ] Create the release tag 31 | - [ ] Push the release tag 32 | -------------------------------------------------------------------------------- /docs/fuzzing.md: -------------------------------------------------------------------------------- 1 | # Fuzzing libpldm 2 | 3 | ## Firmware FD Responder 4 | 5 | `tests/fuzz/fd-fuzz.cpp` exercises the FD responder implementation. It can run 6 | with various fuzzing engines - either AFL++, honggfuzz, or libfuzzer. 7 | 8 | Each fuzz corpus input is split into two parts. The first 1024 bytes is a 9 | "control" stream which used to randomise certain events in the fuzzer, such as 10 | returning failure from callbacks, or choosing whether to receive a message or 11 | run progress. 12 | 13 | The remainder of the fuzz input is taken as an stream of `length:data` PLDM 14 | packet contents, as passed to `pldm_fd_handle_msg()`. 15 | 16 | ## Build 17 | 18 | From the top level libpldm directory, run `./tests/fuzz/fuzz-build.py`. That 19 | will produce several build variants required for different fuzz engines/stages. 20 | 21 | ## Honggfuzz 22 | 23 | [Honggfuzz](https://github.com/google/honggfuzz) handles running across multiple 24 | threads itself with a single corpus directory, which is easy to work with. It 25 | needs to be built from source. 26 | 27 | Run with 28 | 29 | ``` 30 | nice honggfuzz -i corpusdir --linux_perf_branch --dict tests/fuzz/fd.dict -- ./bhf/tests/fuzz/fd-fuzz 31 | ``` 32 | 33 | The `--linux_perf_branch` switch is optional, it requires permissions for perf 34 | counters: 35 | 36 | ``` 37 | echo 0 | sudo tee /proc/sys/kernel/perf_event_paranoid 38 | ``` 39 | 40 | Optionally a thread count can be given, 24 threads on a 12 core system seems to 41 | give best utilisation (`--nthreads 24`). 42 | 43 | The corpus directory can be reused between runs with different fuzzers. For a 44 | totally fresh start, copy in `tests/fuzz/fd-fuzz-input1.dat`, a sample 45 | handcrafted input. 46 | 47 | ## AFL++ 48 | 49 | Running a single instance (just for testing): 50 | 51 | ``` 52 | afl-fuzz -i fuzzrun/hf11/ -o fuzzrun/out12single ./bfuzz/tests/fuzz/fd-fuzz 53 | ``` 54 | 55 | AFL++ requires a separate GUI instantiation for each CPU thread. The helper 56 | [AFL Runner](https://github.com/0xricksanchez/afl_runner) makes that easier. 57 | 58 | Running with 20 threads: 59 | 60 | ``` 61 | nice aflr run -t bfuzz/tests/fuzz/fd-fuzz -i workdir/out5/m_fd-fuzz/queue -o workdir/out6 -c bcmplog/tests/fuzz/fd-fuzz -s bfuzzasan/tests/fuzz/fd-fuzz -n 20 -x tests/fuzz/fd.dict --session-name fuzz 62 | ``` 63 | 64 | Kill it with `aflr kill fuzz`. 65 | 66 | `aflr tui workdir/out6` could be used to view progress, though its calculations 67 | may be inaccurate if some runners are idle. Another option is 68 | `afl-whatsup workdir/out6`. 69 | 70 | ## Coverage 71 | 72 | The coverage provided by a corpus directory can be reported using 73 | `tests/fuzz/fuzz-coverage.py`. 74 | 75 | It will: 76 | 77 | - Run a binary compiled with `--coverage` against each corpus file 78 | - Use [grcov](https://github.com/mozilla/grcov) to aggregate the coverage traces 79 | (much faster than lcov). 80 | - Use `genhtml` to create a report 81 | 82 | Typical usage, with corpus in `fuzzrun/corpus`: 83 | 84 | ``` 85 | ./tests/fuzz/fuzz-coverage.py fuzzrun/corpus bnoopt/tests/fuzz/fd-fuzz . bnoopt/ coverage-output 86 | ``` 87 | 88 | ## Reproducing crashes 89 | 90 | When the fuzz run encounters a crash, the testcase can be run against the built 91 | target manually, and stepped through with GDB etc. 92 | 93 | ``` 94 | env TRACEFWFD=1 ./bnoopt/tests/fuzz/fd-fuzz < crashing.bin 95 | ``` 96 | 97 | The `printf`s are disabled by default to improve normal fuzzing speed. 98 | -------------------------------------------------------------------------------- /docs/oem/meta/file-io.md: -------------------------------------------------------------------------------- 1 | # Description of file IO messages 2 | 3 | ## Read Message Format 4 | 5 | ### Table 1. Read Request 6 | 7 | | Offset | Type | Name | Description | 8 | | -------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | 9 | | 0 | uint8 | Handle | This field is a handle that is used to identify PLDM command type. | 10 | | 1 | enum8 | Option | This field is a read option is used to identify the read file option.
See Table 3 for the option. | 11 | | 2:3 | uint16 | Length | The length in bytes N of data being sent in this part in the ReadInfo field. | 12 | | Variable | uint8 | ReadInfo | Portion of reading information.
There will be different reading information according to different ReadOption.
See Table 4 and Table 5 for details | 13 | 14 | ### Table 2. Read response 15 | 16 | | Offset | Type | Name | Description | 17 | | -------- | ----- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | 18 | | 0 | int | CompletionCode | value: { PLDM_SUCCESS, PLDM_ERROR_INVALID_DATA, PLDM_ERROR_INVALID_LENGTH } | 19 | | Variable | uint8 | ReadResponse | Portion of reading response.
There will be different reading response according to different ReadOption.
See Table 6 and Table 7 for details | 20 | 21 | ### Table 3. Option of message type 22 | 23 | | Value | Name | Description | 24 | | ----- | ----------------- | -------------------------- | 25 | | 0x00 | ReadFileAttribute | Get file size and checksum | 26 | | 0x01 | ReadFileData | Get file data | 27 | 28 | ### Table 4. ReadInfo Definition when ReadOption is ReadFileAttribute in message type 29 | 30 | | Offset | Type | Name | Description | 31 | | ------ | ---- | ---- | --------------- | 32 | | 0 | - | - | No request data | 33 | 34 | ### Table 5. ReadInfo Definition when ReadOption is ReadFileData in message type 35 | 36 | | Offset | Type | Name | Description | 37 | | ------ | ------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | 38 | | 0 | uint8 | TransferFlag | The transfer flag that indiates what part of the transfer this request represents.
Possible values: {Start=0x01, Middle=0x02, End=0x04, StartAndEnd=0x05} | 39 | | 1:2 | uint16 | Offset | Offset in read file. | 40 | 41 | ### Table 6. ReadResponse Definition when ReadOption is ReadFileAttribute in message type 42 | 43 | | Offset | Type | Name | Description | 44 | | ------ | ------ | -------- | ----------------------------------------------------------- | 45 | | 0:1 | uint16 | Size | This field indicates the size of the entire file, in bytes. | 46 | | 2:5 | uint32 | Checksum | This field indicates the checksum of the entire file. | 47 | 48 | ### Table 7. ReadResponse Definition when ReadOption is ReadFileData in message type 49 | 50 | | Offset | Type | Name | Description | 51 | | -------- | ------ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | 52 | | 0 | uint8 | TransferFlag | The transfer flag that indiates what part of the transfer this response represents.
Possible values: {Start=0x01, Middle=0x02, End=0x04, StartAndEnd=0x05} | 53 | | 1:2 | uint16 | Offset | Offset in read file. | 54 | | Variable | uint8 | FileData | File data can be up to 255 bytes. | 55 | -------------------------------------------------------------------------------- /evolutions/current/crc32.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: crc32 2 | NewName: pldm_edac_crc32 3 | -------------------------------------------------------------------------------- /evolutions/current/crc8.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: crc8 2 | NewName: pldm_edac_crc8 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/get_fru_record_by_option_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: get_fru_record_by_option_check 2 | NewName: get_fru_record_by_option 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/oem-ibm-header-compat.cocci: -------------------------------------------------------------------------------- 1 | @@ 2 | @@ 3 | -#include 4 | +#include 5 | 6 | @@ 7 | @@ 8 | -#include 9 | +#include 10 | 11 | @@ 12 | @@ 13 | -#include 14 | +#include 15 | 16 | @@ 17 | @@ 18 | -#include 19 | +#include 20 | 21 | @@ 22 | @@ 23 | -#include 24 | +#include 25 | 26 | @@ 27 | @@ 28 | -#include 29 | +#include 30 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_append_pad_checksum_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_append_pad_checksum_check 2 | NewName: pldm_bios_table_append_pad_checksum 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_entry_enum_decode_def_num_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_entry_enum_decode_def_num_check 2 | NewName: pldm_bios_table_attr_entry_enum_decode_def_num 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_entry_enum_decode_pv_hdls_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_entry_enum_decode_pv_hdls_check 2 | NewName: pldm_bios_table_attr_entry_enum_decode_pv_hdls 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_entry_enum_decode_pv_num_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_entry_enum_decode_pv_num_check 2 | NewName: pldm_bios_table_attr_entry_enum_decode_pv_num 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_entry_enum_encode_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_entry_enum_encode_check 2 | NewName: pldm_bios_table_attr_entry_enum_encode 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_entry_integer_encode_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_entry_integer_encode_check 2 | NewName: pldm_bios_table_attr_entry_integer_encode 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_entry_string_decode_def_string_length_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_entry_string_decode_def_string_length_check 2 | NewName: pldm_bios_table_attr_entry_string_decode_def_string_length 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_entry_string_encode_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_entry_string_encode_check 2 | NewName: pldm_bios_table_attr_entry_string_encode 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_value_entry_encode_enum_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_value_entry_encode_enum_check 2 | NewName: pldm_bios_table_attr_value_entry_encode_enum 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_value_entry_encode_integer_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_value_entry_encode_integer_check 2 | NewName: pldm_bios_table_attr_value_entry_encode_integer 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_attr_value_entry_encode_string_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_attr_value_entry_encode_string_check 2 | NewName: pldm_bios_table_attr_value_entry_encode_string 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_string_entry_decode_string_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_string_entry_decode_string_check 2 | NewName: pldm_bios_table_string_entry_decode_string 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_bios_table_string_entry_encode_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_bios_table_string_entry_encode_check 2 | NewName: pldm_bios_table_string_entry_encode 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_entity_association_pdr_add_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_entity_association_pdr_add_check 2 | NewName: pldm_entity_association_pdr_add 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_entity_association_pdr_add_from_node_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_entity_association_pdr_add_from_node_check 2 | NewName: pldm_entity_association_pdr_add_from_node 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_pdr_add_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_pdr_add_check 2 | NewName: pldm_pdr_add 3 | -------------------------------------------------------------------------------- /evolutions/v0.9.1/pldm_pdr_add_fru_record_set_check.yaml: -------------------------------------------------------------------------------- 1 | - QualifiedName: pldm_pdr_add_fru_record_set_check 2 | NewName: pldm_pdr_add_fru_record_set 3 | -------------------------------------------------------------------------------- /include/libpldm/api.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | 3 | #ifndef LIBPLDM_API_H 4 | #define LIBPLDM_API_H 5 | 6 | #include 7 | 8 | #define LIBPLDM_ITERATOR LIBPLDM_CC_NONNULL LIBPLDM_CC_ALWAYS_INLINE 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /include/libpldm/compiler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | 3 | #ifndef LIBPLDM_COMPILER_H 4 | #define LIBPLDM_COMPILER_H 5 | 6 | #if defined __has_attribute 7 | 8 | #if __has_attribute(always_inline) 9 | #define LIBPLDM_CC_ALWAYS_INLINE __attribute__((always_inline)) static inline 10 | #endif 11 | 12 | #if __has_attribute(counted_by) 13 | #define LIBPLDM_CC_COUNTED_BY(x) __attribute__((counted_by(x))) 14 | #endif 15 | 16 | #if __has_attribute(nonnull) 17 | #define LIBPLDM_CC_NONNULL __attribute__((nonnull)) 18 | #endif 19 | 20 | #endif 21 | 22 | #ifndef LIBPLDM_CC_ALWAYS_INLINE 23 | #define LIBPLDM_CC_ALWAYS_INLINE static inline 24 | #endif 25 | 26 | #ifndef LIBPLDM_CC_COUNTED_BY 27 | #define LIBPLDM_CC_COUNTED_BY(x) 28 | #endif 29 | 30 | #ifndef LIBPLDM_CC_NONNULL 31 | #define LIBPLDM_CC_NONNULL 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/libpldm/control.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | enum pldm_control_completion_codes { 8 | PLDM_CONTROL_INVALID_DATA_TRANSFER_HANDLE = 0x80, 9 | PLDM_CONTROL_INVALID_TRANSFER_OPERATION_FLAG = 0x81, 10 | PLDM_CONTROL_INVALID_PLDM_TYPE_IN_REQUEST_DATA = 0x83, 11 | PLDM_CONTROL_INVALID_PLDM_VERSION_IN_REQUEST_DATA = 0x84, 12 | }; 13 | 14 | // Static storage can be allocated with PLDM_SIZEOF_CONTROL macro */ 15 | struct pldm_control; 16 | 17 | /** @brief Handle a PLDM Control message 18 | * 19 | * @param[in] control 20 | * @param[in] req_msg - PLDM incoming request message payload 21 | * @param[in] req_len - length of req_msg buffer 22 | * @param[out] resp_msg - PLDM outgoing response message payload buffer 23 | * @param[inout] resp_len - length of available resp_msg buffer, will be updated 24 | * with the length written to resp_msg. 25 | * 26 | * @return 0 on success, a negative errno value on failure. 27 | * 28 | * Will provide a response to send when resp_len > 0 and returning 0. 29 | */ 30 | int pldm_control_handle_msg(struct pldm_control *control, const void *req_msg, 31 | size_t req_len, void *resp_msg, size_t *resp_len); 32 | 33 | /** @brief Initialise a struct pldm_control 34 | * 35 | * @param[in] control 36 | * @param[in] pldm_control_size - pass PLDM_SIZEOF_CONTROL 37 | * 38 | * @return 0 on success, a negative errno value on failure. 39 | */ 40 | int pldm_control_setup(struct pldm_control *control, size_t pldm_control_size); 41 | 42 | /** @brief Add a PLDM type to report. 43 | * 44 | * @param[in] control 45 | * @param[in] type - PLDM type, enum pldm_supported_types 46 | * @param[in] versions - list of versions for GetPLDMVersion response. 47 | * This is an array of 32-bit version values, followed by 48 | * a CRC32 over the version values. The size of this buffer 49 | * is 4*versions_count. The versions buffer must remain 50 | * present for the duration of the pldm_control's lifetime. 51 | * @param[in] versions_count - number of entries in versions, including the trailing CRC32. 52 | * @param[in] commands - pointer to an array of bitfield8_t[8], for GetPLDMCommands 53 | * response for this type. The buffer must remain 54 | * present for the duration of the pldm_control's lifetime. 55 | * 56 | * @return 0 on success, a negative errno value on failure. 57 | */ 58 | int pldm_control_add_type(struct pldm_control *control, uint8_t pldm_type, 59 | const void *versions, size_t versions_count, 60 | const bitfield8_t *commands); 61 | -------------------------------------------------------------------------------- /include/libpldm/entity.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef ENTITY_H 3 | #define ENTITY_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /** @brief PLDM Entity ID Codes in DSP0249_1.1.0 specification 10 | */ 11 | enum pldm_entity_id_codes { 12 | PLDM_ENTITY_UNSPECIFIED = 0, 13 | PLDM_ENTITY_OTHER = 1, 14 | 15 | /* Miscellaneous Entities */ 16 | PLDM_ENTITY_NETWORK = 2, 17 | PLDM_ENTITY_GROUP = 3, 18 | PLDM_ENTITY_REMOTE_MGMT_COMM_DEVICE = 4, 19 | PLDM_ENTITY_EXTERNAL_ENVIRONMENT = 5, 20 | PLDM_ENTITY_COMM_CHANNEL = 6, 21 | PLDM_ENTITY_TERMINUS = 7, 22 | PLDM_ENTITY_PLATFORM_EVENT_LOG = 8, 23 | PLDM_ENTITY_DEVICE_FILE = 9, 24 | PLDM_ENTITY_DEVICE_FILE_DIRECTORY = 10, 25 | PLDM_ENTITY_MEMORY_RANK = 11, 26 | 27 | /* Human Interface Entities */ 28 | PLDM_ENTITY_KEYPAD = 15, 29 | PLDM_ENTITY_SWITCH = 16, 30 | PLDM_ENTITY_PUSHBUTTON = 17, 31 | PLDM_ENTITY_DISPLAY = 18, 32 | PLDM_ENTITY_INDICATOR = 19, 33 | 34 | /* Software/Firmware Entities */ 35 | PLDM_ENTITY_SYS_MGMT_SW = 30, 36 | PLDM_ENTITY_SYS_FIRMWARE = 31, 37 | PLDM_ENTITY_OPERATING_SYS = 32, 38 | PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER = 33, 39 | PLDM_ENTITY_OS_LOADER = 34, 40 | PLDM_ENTITY_DEVICE_DRIVER = 35, 41 | PLDM_ENTITY_MGMT_CONTROLLER_FW = 36, 42 | 43 | /* Chassis/Enclosure Entities */ 44 | PLDM_ENTITY_SYSTEM_CHASSIS = 45, 45 | PLDM_ENTITY_SUB_CHASSIS = 46, 46 | PLDM_ENTITY_DISK_DRIVE_BAY = 47, 47 | PLDM_ENTITY_PERIPHERAL_BAY = 48, 48 | PLDM_ENTITY_DEVICE_BAY = 49, 49 | PLDM_ENTITY_DOOR = 50, 50 | PLDM_ENTITY_ACCESS_PANEL = 51, 51 | PLDM_ENTITY_COVER = 52, 52 | 53 | /* Board/Card/Module Entities */ 54 | PLDM_ENTITY_BOARD = 60, 55 | PLDM_ENTITY_CARD = 61, 56 | PLDM_ENTITY_MODULE = 62, 57 | PLDM_ENTITY_SYS_MGMT_MODULE = 63, 58 | PLDM_ENTITY_SYS_BOARD = 64, 59 | PLDM_ENTITY_MEMORY_BOARD = 65, 60 | PLDM_ENTITY_MEMORY_MODULE = 66, 61 | PLDM_ENTITY_PROC_MODULE = 67, 62 | PLDM_ENTITY_ADD_IN_CARD = 68, 63 | PLDM_ENTITY_CHASSIS_FRONT_PANEL_BOARD = 69, 64 | PLDM_ENTITY_BACK_PANEL_BOARD = 70, 65 | PLDM_ENTITY_POWER_MGMT = 71, 66 | PLDM_ENTITY_POWER_SYS_BOARD = 72, 67 | PLDM_ENTITY_DRIVE_BACKPLANE = 73, 68 | PLDM_ENTITY_SYS_INTERNAL_EXPANSION_BOARD = 74, 69 | PLDM_ENTITY_OTHER_SYS_BOARD = 75, 70 | PLDM_ENTITY_CHASSIS_BACK_PANEL_BOARD = 76, 71 | PLDM_ENTITY_PROCESSING_BLADE = 77, 72 | PLDM_ENTITY_CONNECTIVITY_SWITCH = 78, 73 | PLDM_ENTITY_PROC_MEMORY_MODULE = 79, 74 | PLDM_ENTITY_IO_MODULE = 80, 75 | PLDM_ENTITY_PROC_IO_MODULE = 81, 76 | 77 | /* Cooling Entities */ 78 | PLDM_ENTITY_COOLING_DEVICE = 90, 79 | PLDM_ENTITY_COOLING_SUBSYSTEM = 91, 80 | PLDM_ENTITY_COOLING_UNIT = 92, 81 | PLDM_ENTITY_FAN = 93, 82 | PLDM_ENTITY_PELTIER_COOLING_DEVICE = 94, 83 | PLDM_ENTITY_LIQUID_COOLING_DEVICE = 95, 84 | PLDM_ENTITY_LIQUID_COOLING_SUBSYSTEM = 96, 85 | 86 | /* Storage Device Entities */ 87 | PLDM_ENTITY_OTHER_STORAGE_DEVICE = 105, 88 | PLDM_ENTITY_FLOPPY_DRIVE = 106, 89 | PLDM_ENTITY_FIXED_DISK_HARD_DRIVE = 107, 90 | PLDM_ENTITY_CD_DRIVE = 108, 91 | PLDM_ENTITY_CD_DVD_DRIVE = 109, 92 | PLDM_ENTITY_OTHER_SILICON_STORAGE_DEVICE = 110, 93 | PLDM_ENTITY_SOLID_STATE_SRIVE = 111, 94 | 95 | /* Power Entities */ 96 | PLDM_ENTITY_POWER_SUPPLY = 120, 97 | PLDM_ENTITY_BATTERY = 121, 98 | PLDM_ENTITY_SUPER_CAPACITOR = 122, 99 | PLDM_ENTITY_POWER_CONVERTER = 123, 100 | PLDM_ENTITY_DC_DC_CONVERTER = 124, 101 | PLDM_ENTITY_AC_MAINS_POWER_SUPPLY = 125, 102 | PLDM_ENTITY_DC_MAINS_POWER_SUPPLY = 126, 103 | PLDM_ENTITY_VOLTAGE_REGULATOR = 127, 104 | PLDM_ENTITY_MULTI_RAIL_VOLTAGE_REGULATOR = 128, 105 | PLDM_ENTITY_MULTI_RAIL_VOLTAGE_REGULATOR_CHANNEL = 129, 106 | 107 | /* Chip Entities */ 108 | PLDM_ENTITY_PROC = 135, 109 | PLDM_ENTITY_CHIPSET_COMPONENT = 136, 110 | PLDM_ENTITY_MGMT_CONTROLLER = 137, 111 | PLDM_ENTITY_PERIPHERAL_CONTROLLER = 138, 112 | PLDM_ENTITY_SEEPROM = 139, 113 | PLDM_ENTITY_NVRAM_CHIP = 140, 114 | PLDM_ENTITY_FLASH_MEMORY_CHIP = 141, 115 | PLDM_ENTITY_MEMORY_CHIP = 142, 116 | PLDM_ENTITY_MEMORY_CONTROLLER = 143, 117 | PLDM_ENTITY_NETWORK_CONTROLLER = 144, 118 | PLDM_ENTITY_IO_CONTROLLER = 145, 119 | PLDM_ENTITY_SOUTH_BRIDGE = 146, 120 | PLDM_ENTITY_REAL_TIME_CLOCK = 147, 121 | PLDM_ENTITY_FPGA_CPLD_DEVICE = 148, 122 | PLDM_ENTITY_ACCELERATOR = 149, 123 | PLDM_ENTITY_TPM = 150, 124 | PLDM_ENTITY_PROCESSOR_CORE = 151, 125 | PLDM_ENTITY_GPU = 152, 126 | PLDM_ENTITY_DPU = 153, 127 | 128 | /* Bus Entities */ 129 | PLDM_ENTITY_OTHER_BUS = 160, 130 | PLDM_ENTITY_SYS_BUS = 161, 131 | PLDM_ENTITY_I2C_BUS = 162, 132 | PLDM_ENTITY_SMBUS_BUS = 163, 133 | PLDM_ENTITY_SPI_BUS = 164, 134 | PLDM_ENTITY_PCI_BUS = 165, 135 | PLDM_ENTITY_PCI_EXPRESS_BUS = 166, 136 | PLDM_ENTITY_PECI_BUS = 167, 137 | PLDM_ENTITY_LPC_BUS = 168, 138 | PLDM_ENTITY_USB_BUS = 169, 139 | PLDM_ENTITY_FIREWIRE_BUS = 170, 140 | PLDM_ENTITY_SCSI_BUS = 171, 141 | PLDM_ENTITY_SATA_SAS_BUS = 172, 142 | PLDM_ENTITY_PROC_FRONT_SIDE_BUS = 173, 143 | PLDM_ENTITY_INTER_PROC_BUS = 174, 144 | PLDM_ENTITY_INTER_ACCELERATOR_LINK = 175, 145 | 146 | /* Connectors/Cables */ 147 | PLDM_ENTITY_CONNECTOR = 185, 148 | PLDM_ENTITY_SLOT = 186, 149 | PLDM_ENTITY_CABLE = 187, 150 | PLDM_ENTITY_INTERCONNECT = 188, 151 | PLDM_ENTITY_PLUG = 189, 152 | PLDM_ENTITY_SOCKET = 190, 153 | 154 | /* Network Interface Connectors */ 155 | PLDM_ENTITY_RJ45 = 200, 156 | PLDM_ENTITY_XFP = 201, 157 | PLDM_ENTITY_SFP = 202, 158 | PLDM_ENTITY_SFP10 = 203, 159 | PLDM_ENTITY_SFP16 = 205, 160 | PLDM_ENTITY_SFP28 = 206, 161 | PLDM_ENTITY_SFP_PLUS = 207, 162 | PLDM_ENTITY_SFPDD = 208, 163 | PLDM_ENTITY_CSFP = 209, 164 | PLDM_ENTITY_QSFP = 210, 165 | PLDM_ENTITY_QSFP28 = 211, 166 | PLDM_ENTITY_QSFP_PLUS = 212, 167 | PLDM_ENTITY_QSFPDD = 213, 168 | PLDM_ENTITY_OSFP = 214, 169 | PLDM_ENTITY_DSFP = 215, 170 | 171 | /* Network Ports Connection Types */ 172 | PLDM_ENTITY_ETHERNET = 300, 173 | PLDM_ENTITY_INFINIBAND = 301, 174 | PLDM_ENTITY_FIBRECHANEL = 302, 175 | PLDM_ENTITY_OMINIPATH = 303, 176 | 177 | /* OEM ranges */ 178 | PLDM_OEM_ENTITY_TYPE_START = 24576, 179 | PLDM_OEM_ENTITY_TYPE_END = 32767, 180 | }; 181 | 182 | #ifdef __cplusplus 183 | } 184 | #endif 185 | 186 | #endif /* ENTITY_H */ 187 | -------------------------------------------------------------------------------- /include/libpldm/file.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_FILE_H 3 | #define LIBPLDM_FILE_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #define PLDM_DF_OPEN_REQ_BYTES 4 16 | #define PLDM_DF_OPEN_RESP_BYTES 3 17 | #define PLDM_DF_CLOSE_REQ_BYTES 4 18 | #define PLDM_DF_CLOSE_RESP_BYTES 1 19 | #define PLDM_DF_HEARTBEAT_REQ_BYTES 6 20 | #define PLDM_DF_HEARTBEAT_RESP_BYTES 5 21 | 22 | /** @brief PLDM File Transfer Completion Code */ 23 | enum pldm_file_cc { 24 | PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR = 0x80, 25 | PLDM_FILE_CC_INVALID_DF_ATTRIBUTE = 0x81, 26 | PLDM_FILE_CC_ZEROLENGTH_NOT_ALLOWED = 0x82, 27 | PLDM_FILE_CC_EXCLUSIVE_OWNERSHIP_NOT_ESTABLISHED = 0x83, 28 | PLDM_FILE_CC_EXCLUSIVE_OWNERSHIP_NOT_ALLOWED = 0x84, 29 | PLDM_FILE_CC_EXCLUSIVE_OWNERSHIP_NOT_AVAILABLE = 0x85, 30 | PLDM_FILE_CC_INVALID_FILE_IDENTIFIER = 0x86, 31 | PLDM_FILE_CC_DFOPEN_DIR_NOT_ALLOWED = 0x87, 32 | PLDM_FILE_CC_MAX_NUM_FDS_EXCEEDED = 0x88, 33 | PLDM_FILE_CC_FILE_OPEN = 0x89, 34 | PLDM_FILE_CC_UNABLE_TO_OPEN_FILE = 0x8A, 35 | }; 36 | 37 | /** @brief PLDM File Transfer Command */ 38 | enum pldm_file_cmd { 39 | PLDM_FILE_CMD_DF_OPEN = 0x01, 40 | PLDM_FILE_CMD_DF_CLOSE = 0x02, 41 | PLDM_FILE_CMD_DF_HEARTBEAT = 0x03, 42 | PLDM_FILE_CMD_DF_PROPERTIES = 0x10, 43 | PLDM_FILE_CMD_DF_GET_FILE_ATTRIBUTE = 0x11, 44 | PLDM_FILE_CMD_DF_SET_FILE_ATTRIBUTE = 0x12, 45 | PLDM_FILE_CMD_DF_READ = 0x20, 46 | PLDM_FILE_CMD_DF_FIFO_SEND = 0x21, 47 | }; 48 | 49 | /** @struct pldm_file_df_open_req 50 | * 51 | * Structure representing PLDM File DfOpen request. 52 | */ 53 | struct pldm_file_df_open_req { 54 | uint16_t file_identifier; 55 | bitfield16_t file_attribute; 56 | }; 57 | 58 | /** @struct pldm_file_df_open_resp 59 | * 60 | * Structure representing PLDM File DfOpen response. 61 | */ 62 | struct pldm_file_df_open_resp { 63 | uint8_t completion_code; 64 | uint16_t file_descriptor; 65 | }; 66 | 67 | /** @struct pldm_file_df_close_req 68 | * 69 | * Structure representing PLDM File DfClose request. 70 | */ 71 | struct pldm_file_df_close_req { 72 | uint16_t file_descriptor; 73 | bitfield16_t df_close_options; 74 | }; 75 | 76 | /** @struct pldm_file_df_close_resp 77 | * 78 | * Structure representing PLDM File DfClose response. 79 | */ 80 | struct pldm_file_df_close_resp { 81 | uint8_t completion_code; 82 | }; 83 | 84 | /** @struct pldm_file_df_heartbeat_req 85 | * 86 | * Structure representing PLDM File DfHeartbeat request. 87 | */ 88 | struct pldm_file_df_heartbeat_req { 89 | uint16_t file_descriptor; 90 | uint32_t requester_max_interval; 91 | }; 92 | 93 | /** @struct pldm_file_df_heartbeat_resp 94 | * 95 | * Structure representing PLDM File DfHearbeat response. 96 | */ 97 | struct pldm_file_df_heartbeat_resp { 98 | uint8_t completion_code; 99 | uint32_t responder_max_interval; 100 | }; 101 | 102 | /** @brief Create a PLDM request message for DFOpen 103 | * 104 | * @param[in] instance_id - Message's instance id 105 | * @param[in] req - The pointer to the request message to be encoded 106 | * @param[in,out] msg - Message will be written to this 107 | * @param[in] payload_length - Length of the request message payload 108 | * @return 0 on success 109 | * -EINVAL if the input parameters' memory are not allocated, 110 | * or message type or instance in request header is invalid 111 | * -ENOMSG if the PLDM type in the request header is invalid 112 | * -EOVERFLOW if the input message length is invalid 113 | * @note Caller is responsible for memory alloc and dealloc of param 114 | * 'msg.payload' 115 | */ 116 | int encode_pldm_file_df_open_req(uint8_t instance_id, 117 | const struct pldm_file_df_open_req *req, 118 | struct pldm_msg *msg, size_t payload_length); 119 | 120 | /** @brief Decode DFOpen response data 121 | * 122 | * @param[in] msg - Response message 123 | * @param[in] payload_length - Length of response message payload 124 | * @param[out] resp - pointer to the decoded response message 125 | * @return 0 on success 126 | * -EINVAL if the input parameters' memory are not allocated 127 | * -EOVERFLOW if the input message buffer is too short for the output 128 | * response struct 129 | * -EBADMSG if the input message buffer is too large for the output 130 | * response struct. 131 | */ 132 | int decode_pldm_file_df_open_resp(const struct pldm_msg *msg, 133 | size_t payload_length, 134 | struct pldm_file_df_open_resp *resp); 135 | 136 | /** @brief Create a PLDM request message for DFClose 137 | * 138 | * @param[in] instance_id - Message's instance id 139 | * @param[in] req - The pointer to the request message to be encoded 140 | * @param[in,out] msg - Message will be written to this 141 | * @param[in] payload_length - Length of the request message payload 142 | * @return 0 on success 143 | * -EINVAL if the input parameters' memory are not allocated, 144 | * or message type or instance in request header is invalid 145 | * -ENOMSG if the PLDM type in the request header is invalid 146 | * -EOVERFLOW if the input message length is invalid 147 | * @note Caller is responsible for memory alloc and dealloc of param 148 | * 'msg.payload' 149 | */ 150 | int encode_pldm_file_df_close_req(uint8_t instance_id, 151 | const struct pldm_file_df_close_req *req, 152 | struct pldm_msg *msg, size_t payload_length); 153 | 154 | /** @brief Decode DFClose response data 155 | * 156 | * @param[in] msg - Response message 157 | * @param[in] payload_length - Length of response message payload 158 | * @param[out] resp - pointer to the decoded response message 159 | * @return 0 on success 160 | * -EINVAL if the input parameters' memory are not allocated 161 | */ 162 | int decode_pldm_file_df_close_resp(const struct pldm_msg *msg, 163 | size_t payload_length, 164 | struct pldm_file_df_close_resp *resp); 165 | 166 | /** @brief Create a PLDM request message for DFHeartbeat 167 | * 168 | * @param[in] instance_id - Message's instance id 169 | * @param[in] req - The pointer to the request message to be encoded 170 | * @param[in,out] msg - Message will be written to this 171 | * @param[in] payload_length - Length of the request message payload 172 | * @return 0 on success 173 | * -EINVAL if the input parameters' memory are not allocated, 174 | * or message type or instance in request header is invalid 175 | * -ENOMSG if the PLDM type in the request header is invalid 176 | * -EOVERFLOW if the input message length is invalid 177 | * @note Caller is responsible for memory alloc and dealloc of param 178 | * 'msg.payload' 179 | */ 180 | int encode_pldm_file_df_heartbeat_req( 181 | uint8_t instance_id, const struct pldm_file_df_heartbeat_req *req, 182 | struct pldm_msg *msg, size_t payload_length); 183 | 184 | /** @brief Decode DFHeartbeat response data 185 | * 186 | * @param[in] msg - Response message 187 | * @param[in] payload_length - Length of response message payload 188 | * @param[out] resp - pointer to the decoded response message 189 | * @return 0 on success 190 | * -EINVAL if the input parameters' memory are not allocated 191 | * -EOVERFLOW if the input message buffer is too short for the output 192 | * response struct 193 | * -EBADMSG if the input message buffer is too large for the output 194 | * response struct 195 | */ 196 | int decode_pldm_file_df_heartbeat_resp(const struct pldm_msg *msg, 197 | size_t payload_length, 198 | struct pldm_file_df_heartbeat_resp *resp); 199 | 200 | #ifdef __cplusplus 201 | } 202 | #endif 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /include/libpldm/instance-id.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef INSTANCE_ID_H 3 | #define INSTANCE_ID_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | 11 | #include 12 | 13 | typedef uint8_t pldm_instance_id_t; 14 | struct pldm_instance_db; 15 | 16 | #ifdef __STDC_HOSTED__ 17 | /** 18 | * @brief Instantiates an instance ID database object for a given database path 19 | * 20 | * @param[out] ctx - *ctx must be NULL, and will point to a PLDM instance ID 21 | * database object on success. 22 | * @param[in] dbpath - the path to the instance ID database file to use 23 | * 24 | * @return int - Returns 0 on success. Returns -EINVAL if ctx is NULL or *ctx 25 | * is not NULL. Returns -ENOMEM if memory couldn't be allocated. 26 | * Returns the errno if the database couldn't be opened. 27 | * */ 28 | int pldm_instance_db_init(struct pldm_instance_db **ctx, const char *dbpath); 29 | 30 | /** 31 | * @brief Instantiates an instance ID database object for the default database 32 | * path 33 | * 34 | * @param[out] ctx - *ctx will point to a PLDM instance ID database object on 35 | * success. 36 | * 37 | * @return int - Returns 0 on success. Returns -EINVAL if ctx is NULL or *ctx 38 | * is not NULL. Returns -ENOMEM if memory couldn't be allocated. 39 | * Returns the errno if the database couldn't be opened. 40 | * */ 41 | int pldm_instance_db_init_default(struct pldm_instance_db **ctx); 42 | 43 | /** 44 | * @brief Destroys an instance ID database object 45 | * 46 | * @param[in] ctx - PLDM instance ID database object 47 | * 48 | * @return int - Returns 0 on success or if *ctx is NULL. No specific errors are 49 | * specified. 50 | * */ 51 | int pldm_instance_db_destroy(struct pldm_instance_db *ctx); 52 | 53 | /** 54 | * @brief Allocates an instance ID for a destination TID from the instance ID 55 | * database 56 | * 57 | * @param[in] ctx - PLDM instance ID database object 58 | * @param[in] tid - PLDM TID 59 | * @param[in] iid - caller owned pointer to a PLDM instance ID object. On 60 | * success, this points to an instance ID to use for a PLDM request 61 | * message. 62 | * 63 | * @return int - Returns 0 on success if we were able to allocate an instance 64 | * ID. Returns -EINVAL if the iid pointer is NULL. Returns -EAGAIN 65 | * if a successive call may succeed. Returns -EPROTO if the 66 | * operation has entered an undefined state. 67 | */ 68 | int pldm_instance_id_alloc(struct pldm_instance_db *ctx, pldm_tid_t tid, 69 | pldm_instance_id_t *iid); 70 | 71 | /** 72 | * @brief Frees an instance ID previously allocated by pldm_instance_id_alloc 73 | * 74 | * @param[in] ctx - PLDM instance ID database object 75 | * @param[in] tid - PLDM TID 76 | * @param[in] iid - If this instance ID was not previously allocated by 77 | * pldm_instance_id_alloc then EINVAL is returned. 78 | * 79 | * @return int - Returns 0 on success. Returns -EINVAL if the iid supplied was 80 | * not previously allocated by pldm_instance_id_alloc or it has 81 | * previously been freed. Returns -EAGAIN if a successive call may 82 | * succeed. Returns -EPROTO if the operation has entered an 83 | * undefined state. 84 | */ 85 | int pldm_instance_id_free(struct pldm_instance_db *ctx, pldm_tid_t tid, 86 | pldm_instance_id_t iid); 87 | 88 | #endif /* __STDC_HOSTED__*/ 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | 94 | #endif /* INSTANCE_ID_H */ 95 | -------------------------------------------------------------------------------- /include/libpldm/meson.build: -------------------------------------------------------------------------------- 1 | libpldm_headers = files( 2 | 'api.h', 3 | 'base.h', 4 | 'bios.h', 5 | 'bios_table.h', 6 | 'compiler.h', 7 | 'control.h', 8 | 'entity.h', 9 | 'file.h', 10 | 'firmware_fd.h', 11 | 'firmware_update.h', 12 | 'fru.h', 13 | 'instance-id.h', 14 | 'pdr.h', 15 | 'platform.h', 16 | 'pldm.h', 17 | 'pldm_types.h', 18 | 'state_set.h', 19 | 'states.h', 20 | 'transport.h', 21 | 'transport/af-mctp.h', 22 | 'transport/mctp-demux.h', 23 | 'utils.h', 24 | ) 25 | 26 | if get_option('oem').contains('ibm') 27 | libpldm_headers += files( 28 | 'oem/ibm/entity.h', 29 | 'oem/ibm/file_io.h', 30 | 'oem/ibm/fru.h', 31 | 'oem/ibm/host.h', 32 | 'oem/ibm/platform.h', 33 | 'oem/ibm/state_set.h', 34 | ) 35 | endif 36 | 37 | if get_option('oem').contains('meta') 38 | libpldm_headers += files('oem/meta/file_io.h') 39 | endif 40 | 41 | 42 | install_headers(libpldm_headers, subdir: 'libpldm', preserve_path: true) 43 | 44 | # TODO: these should depend on the input headers so they rebuild 45 | # on changes, unclear how to do that. 46 | include_src = include_directories('../../src', is_system: true) 47 | sizeof_pldm_fd = compiler.sizeof( 48 | 'struct pldm_fd', 49 | prefix: '#include "firmware_device/fd-internal.h"', 50 | include_directories: [include_src, libpldm_include_dir], 51 | ) 52 | sizeof_pldm_control = compiler.sizeof( 53 | 'struct pldm_control', 54 | prefix: '#include "control-internal.h"', 55 | include_directories: [include_src, libpldm_include_dir], 56 | ) 57 | sizes_h = configure_file( 58 | configuration: { 59 | 'sizeof_pldm_fd': sizeof_pldm_fd, 60 | 'sizeof_pldm_control': sizeof_pldm_control, 61 | }, 62 | input: 'sizes.h.in', 63 | output: 'sizes.h', 64 | install: true, 65 | install_dir: get_option('includedir') / 'libpldm', 66 | ) 67 | -------------------------------------------------------------------------------- /include/libpldm/oem/ibm/entity.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef OEM_IBM_ENTITY_H 3 | #define OEM_IBM_ENTITY_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | enum pldm_oem_ibm_entity_id_codes { 10 | PLDM_OEM_IBM_ENTITY_TPM = 24576, 11 | PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE = 24577, 12 | PLDM_OEM_IBM_ENTITY_REAL_SAI = 24581, 13 | }; 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | #endif /* OEM_IBM_ENTITY_H */ 20 | -------------------------------------------------------------------------------- /include/libpldm/oem/ibm/fru.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef OEM_IBM_FRU_H 3 | #define OEM_IBM_FRU_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | enum pldm_oem_ibm_fru_field_type { 13 | PLDM_OEM_FRU_FIELD_TYPE_IANA = 0x01, 14 | PLDM_OEM_FRU_FIELD_TYPE_RT = 0x02, 15 | PLDM_OEM_FRU_FIELD_TYPE_PCIE_CONFIG_SPACE_DATA = 0xfd, 16 | PLDM_OEM_FRU_FIELD_TYPE_LOCATION_CODE = 0xfe, 17 | 18 | PLDM_OEM_IBM_FRU_FIELD_TYPE_IANA = 0x01, 19 | PLDM_OEM_IBM_FRU_FIELD_TYPE_RT = 0x02, 20 | PLDM_OEM_IBM_FRU_FIELD_TYPE_FIRMWARE_UAK = 0xfc, 21 | PLDM_OEM_IBM_FRU_FIELD_TYPE_PCIE_CONFIG_SPACE_DATA = 0xfd, 22 | PLDM_OEM_IBM_FRU_FIELD_TYPE_LOCATION_CODE = 0xfe, 23 | }; 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif /* OEM_IBM_FRU_H */ 30 | -------------------------------------------------------------------------------- /include/libpldm/oem/ibm/host.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef OEM_IBM_HOST_H 3 | #define OEM_IBM_HOST_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | /* Maximum size for request */ 15 | #define PLDM_GET_ALERT_STATUS_REQ_BYTES 1 16 | 17 | /* Response lengths are inclusive of completion code */ 18 | #define PLDM_GET_ALERT_STATUS_RESP_BYTES 9 19 | 20 | enum pldm_host_commands { 21 | PLDM_HOST_GET_ALERT_STATUS = 0xf0 // Custom oem cmd 22 | }; 23 | 24 | /** @brief PLDM Command specific codes 25 | */ 26 | enum pldm_host_completion_codes { PLDM_HOST_UNSUPPORTED_FORMAT_VERSION = 0x81 }; 27 | 28 | /** @struct pldm_get_alert_states_resp 29 | * 30 | * Structure representing GetAlertStatus response packet 31 | */ 32 | struct pldm_get_alert_status_resp { 33 | uint8_t completion_code; 34 | uint32_t rack_entry; 35 | uint32_t pri_cec_node; 36 | } __attribute__((packed)); 37 | 38 | /* Requester */ 39 | 40 | /* GetAlertStatus */ 41 | 42 | /** @brief Create a PLDM request message for GetAlertStatus 43 | * 44 | * @param[in] instance_id - Message's instance id 45 | * @param[in] version_id - The command/response format. 0x00 for this format 46 | * @param[out] msg - Message will be written to this 47 | * @param[in] payload_length - Length of request message payload 48 | * @return pldm_completion_codes 49 | * @note Caller is responsible for memory alloc and dealloc of param 50 | * 'msg.payload' 51 | */ 52 | int encode_get_alert_status_req(uint8_t instance_id, uint8_t version_id, 53 | struct pldm_msg *msg, size_t payload_length); 54 | 55 | /** @brief Decode GetAlertStatus response data 56 | * 57 | * Note: 58 | * * If the return value is not PLDM_SUCCESS, it represents a 59 | * transport layer error. 60 | * * If the completion_code value is not PLDM_SUCCESS, it represents a 61 | * protocol layer error and all the out-parameters are invalid. 62 | * 63 | * @param[in] msg - Request message 64 | * @param[in] payload_length - Length of request message payload 65 | * @param[out] completion_code - PLDM completion code 66 | * @param[out] rack_entry - Enclosure ID, Alert Status, Flags, Config ID 67 | * @param[out] pri_cec_node - Enclosure ID, Alert Status, Flags, Config ID 68 | * @return pldm_completion_codes 69 | */ 70 | int decode_get_alert_status_resp(const struct pldm_msg *msg, 71 | size_t payload_length, 72 | uint8_t *completion_code, uint32_t *rack_entry, 73 | uint32_t *pri_cec_node); 74 | 75 | /* Responder */ 76 | 77 | /* GetAlertStatus */ 78 | 79 | /** @brief Decode GetAlertStatus request data 80 | * 81 | * @param[in] msg - Request message 82 | * @param[in] payload_length - Length of request message payload 83 | * @param[out] version_id - the command/response format. 0x00 for this format 84 | * @return pldm_completion_codes 85 | */ 86 | int decode_get_alert_status_req(const struct pldm_msg *msg, 87 | size_t payload_length, uint8_t *version_id); 88 | 89 | /** @brief Create a PLDM OEM response message for GetAlertStatus 90 | * 91 | * @param[in] instance_id - Message's instance id 92 | * @param[in] completion_code - PLDM completion code 93 | * @param[in] rack_entry - Enclosure ID, Alert Status, Flags, Config ID 94 | * @param[in] pri_cec_node - Enclosure ID, Alert Status, Flags, Config ID 95 | * @param[out] msg - Message will be written to this 96 | * @param[in] payload_length - Length of request message payload 97 | * @return pldm_completion_codes 98 | * @note Caller is responsible for memory alloc and dealloc of param 99 | * 'msg.body.payload' 100 | */ 101 | int encode_get_alert_status_resp(uint8_t instance_id, uint8_t completion_code, 102 | uint32_t rack_entry, uint32_t pri_cec_node, 103 | struct pldm_msg *msg, size_t payload_length); 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | 109 | #endif /* OEM_IBM_HOST_H */ 110 | -------------------------------------------------------------------------------- /include/libpldm/oem/ibm/platform.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef PLATFORM_OEM_IBM_H 3 | #define PLATFORM_OEM_IBM_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | enum pldm_event_types_ibm_oem { 15 | PLDM_EVENT_TYPE_OEM_EVENT_BIOS_ATTRIBUTE_UPDATE = 0xf0, 16 | }; 17 | 18 | /** @struct pldm_bios_attribute_update_event_req 19 | * 20 | * Structure representing PlatformEventMessage command request data for OEM 21 | * event type BIOS attribute update. 22 | */ 23 | struct pldm_bios_attribute_update_event_req { 24 | uint8_t format_version; 25 | uint8_t tid; 26 | uint8_t event_class; 27 | uint8_t num_handles; 28 | uint8_t bios_attribute_handles[1]; 29 | } __attribute__((packed)); 30 | 31 | /** @brief Encode PlatformEventMessage request data for BIOS attribute update 32 | * 33 | * @param[in] instance_id - Message's instance id 34 | * @param[in] format_version - Version of the event format 35 | * @param[in] tid - Terminus ID for the terminus that originated the event 36 | * message 37 | * @param[in] num_handles - Number of BIOS handles with an update 38 | * @param[in] list_of_handles - Pointer to the list of BIOS attribute handles 39 | * @param[in] payload_length - Length of request message payload 40 | * @param[out] msg - Message will be written to this 41 | * 42 | * @return pldm_completion_codes 43 | * 44 | * @note Caller is responsible for memory alloc and dealloc of param 45 | * 'msg.payload' 46 | */ 47 | int encode_bios_attribute_update_event_req(uint8_t instance_id, 48 | uint8_t format_version, uint8_t tid, 49 | uint8_t num_handles, 50 | const uint8_t *list_of_handles, 51 | size_t payload_length, 52 | struct pldm_msg *msg); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif /* PLATFORM_OEM_IBM_H */ 59 | -------------------------------------------------------------------------------- /include/libpldm/oem/ibm/state_set.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef STATE_SET_OEM_IBM_H 3 | #define STATE_SET_OEM_IBM_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /** @brief IBM OEM State Set IDs */ 10 | enum ibm_oem_pldm_state_set_ids { 11 | PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE = 32768, 12 | PLDM_OEM_IBM_BOOT_STATE = 32769, 13 | PLDM_OEM_IBM_VERIFICATION_STATE = 32770, 14 | PLDM_OEM_IBM_SYSTEM_POWER_STATE = 32771, 15 | PLDM_OEM_IBM_SBE_MAINTENANCE_STATE = 32772, 16 | PLDM_OEM_IBM_BOOT_SIDE_RENAME = 32773, 17 | PLDM_OEM_IBM_SBE_HRESET_STATE = 32776, 18 | PLDM_OEM_IBM_PANEL_TRIGGER_STATE = 32778, 19 | PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_STATE = 32779, 20 | PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE = 32780, 21 | PLDM_OEM_IBM_PCIE_TOPOLOGY_ACTIONS = 32781, 22 | }; 23 | 24 | enum pldm_oem_ibm_pcie_slot_effecter_state { 25 | PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_ADD = 0x1, 26 | PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_REMOVE = 0x2, 27 | PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_REPLACE = 0x3, 28 | }; 29 | 30 | enum pldm_oem_ibm_pcie_slot_sensor_state { 31 | PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN = 0x0, 32 | PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_ENABLED = 0x1, 33 | PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_DISABLED = 0x2, 34 | PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_ERROR = 0x3, 35 | }; 36 | 37 | enum ibm_oem_pldm_state_set_firmware_update_state_values { 38 | START = 0x1, 39 | END = 0x2, 40 | FAIL = 0x3, 41 | ABORT = 0x4, 42 | ACCEPT = 0x5, 43 | REJECT = 0x6, 44 | }; 45 | 46 | enum ibm_oem_pldm_state_set_boot_state_values { 47 | P = 0x1, 48 | T = 0x2, 49 | }; 50 | 51 | enum ibm_oem_pldm_state_set_verification_state_values { 52 | VALID = 0x0, 53 | ENTITLEMENT_FAIL = 0x1, 54 | BANNED_PLATFORM_FAIL = 0x2, 55 | MIN_MIF_FAIL = 0x4, 56 | }; 57 | 58 | enum ibm_oem_pldm_state_set_system_power_state_values { 59 | POWER_CYCLE_HARD = 0x1 60 | }; 61 | 62 | enum ibm_oem_pldm_state_set_sbe_dump_state_values { 63 | SBE_DUMP_COMPLETED = 0x1, 64 | SBE_RETRY_REQUIRED = 0x2, 65 | }; 66 | 67 | enum ibm_oem_pldm_state_set_sbe_hreset_state_values { 68 | SBE_HRESET_NOT_READY = 0x1, 69 | SBE_HRESET_READY = 0x2, 70 | SBE_HRESET_FAILED = 0x3, 71 | }; 72 | 73 | enum pldm_oem_ibm_pcie_topology_actions { 74 | PLDM_OEM_IBM_PCIE_TOPOLOGY_GET_PCIE_TOPOLOGY = 0x1, 75 | PLDM_OEM_IBM_PCIE_TOPOLOGY_GET_CABLE_INFO = 0x2, 76 | PLDM_OEM_IBM_PCIE_TOPOLOGY_SAVE_PCIE_TOPLOGY = 0x3, 77 | }; 78 | 79 | enum pldm_oem_ibm_boot_side_rename_state { 80 | PLDM_OEM_IBM_BOOT_SIDE_RENAME_STATE_NOT_RENAMED = 0x1, 81 | PLDM_OEM_IBM_BOOT_SIDE_RENAME_STATE_RENAMED = 0x2, 82 | }; 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif /* STATE_SET_OEM_IBM_H */ 89 | -------------------------------------------------------------------------------- /include/libpldm/oem/meta/file_io.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_OEM_META_FILE_IO_H 3 | #define LIBPLDM_OEM_META_FILE_IO_H 4 | 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #include 12 | #include 13 | 14 | struct pldm_msg; 15 | /** @brief PLDM Commands in OEM META type 16 | */ 17 | 18 | enum pldm_oem_meta_file_io_commands { 19 | PLDM_OEM_META_FILE_IO_CMD_WRITE_FILE = 0x2, 20 | PLDM_OEM_META_FILE_IO_CMD_READ_FILE = 0x3, 21 | }; 22 | 23 | /** @brief read options in read file io command 24 | */ 25 | enum pldm_oem_meta_file_io_read_option { 26 | // Read file attribute 27 | PLDM_OEM_META_FILE_IO_READ_ATTR = 0x00, 28 | // Read file data 29 | PLDM_OEM_META_FILE_IO_READ_DATA = 0x01, 30 | }; 31 | 32 | struct pldm_oem_meta_file_io_write_req { 33 | uint8_t handle; 34 | uint32_t length; 35 | #ifndef __cplusplus 36 | uint8_t data[] LIBPLDM_CC_COUNTED_BY(length); 37 | #endif 38 | }; 39 | #define PLDM_OEM_META_FILE_IO_WRITE_REQ_MIN_LENGTH 5u 40 | 41 | /** @struct pldm_oem_meta_file_io_read_data_info 42 | * 43 | * Structure representing PLDM read file data info 44 | */ 45 | struct pldm_oem_meta_file_io_read_data_info { 46 | uint8_t transferFlag; 47 | uint16_t offset; 48 | }; 49 | #define PLDM_OEM_META_FILE_IO_READ_DATA_INFO_LENGTH 3u 50 | 51 | /** @struct pldm_oem_meta_file_io_read_attr_info 52 | * 53 | * Structure representing PLDM read file attribute info 54 | */ 55 | struct pldm_oem_meta_file_io_read_attr_info { 56 | uint16_t size; 57 | uint32_t crc32; 58 | }; 59 | #define PLDM_OEM_META_FILE_IO_READ_ATTR_INFO_LENGTH 6u 60 | 61 | /** @struct pldm_oem_meta_file_io_read_req 62 | * 63 | * Structure representing PLDM read file request 64 | */ 65 | struct pldm_oem_meta_file_io_read_req { 66 | size_t version; 67 | uint8_t handle; 68 | uint8_t option; 69 | uint8_t length; 70 | union { 71 | struct pldm_oem_meta_file_io_read_data_info data; 72 | } info; 73 | }; 74 | #define PLDM_OEM_META_FILE_IO_READ_REQ_MIN_LENGTH 3u 75 | 76 | /** @struct pldm_oem_meta_file_io_read_resp 77 | * 78 | * Structure representing PLDM read file response 79 | */ 80 | struct pldm_oem_meta_file_io_read_resp { 81 | size_t version; 82 | uint8_t completion_code; 83 | uint8_t handle; 84 | uint8_t option; 85 | uint8_t length; 86 | union { 87 | struct pldm_oem_meta_file_io_read_attr_info attr; 88 | struct pldm_oem_meta_file_io_read_data_info data; 89 | } info; 90 | #ifndef __cplusplus 91 | uint8_t data[] LIBPLDM_CC_COUNTED_BY(length); 92 | #endif 93 | }; 94 | #define PLDM_OEM_META_FILE_IO_READ_RESP_MIN_SIZE 4u 95 | 96 | /** @brief Obtain the pointer to the data array of a write request 97 | * 98 | * @param[in] req - The pointer to the write request struct 99 | * 100 | * @return The write request data pointer. 101 | */ 102 | void *pldm_oem_meta_file_io_write_req_data( 103 | struct pldm_oem_meta_file_io_write_req *req); 104 | 105 | /** @brief Decode OEM meta write file io req 106 | * 107 | * @param[in] msg - Pointer to PLDM request message 108 | * @param[in] payload_length - Length of request payload 109 | * @param[out] req - Pointer to the structure to store the decoded response data 110 | * @param[in] req_length - Length of request structure 111 | * @return 0 on success, negative errno value on failure 112 | */ 113 | int decode_oem_meta_file_io_write_req( 114 | const struct pldm_msg *msg, size_t payload_length, 115 | struct pldm_oem_meta_file_io_write_req *req, size_t req_length); 116 | 117 | /** @brief Deprecated decoder for OEM meta write file io req 118 | * 119 | * @param[in] msg - Pointer to PLDM request message 120 | * @param[in] payload_length - Length of request payload 121 | * @param[out] file_handle - The handle of data 122 | * @param[out] length - Total size of data 123 | * @param[out] data - Message will be written to this 124 | * @return pldm_completion_codes 125 | */ 126 | int decode_oem_meta_file_io_req(const struct pldm_msg *msg, 127 | size_t payload_length, uint8_t *file_handle, 128 | uint32_t *length, uint8_t *data); 129 | 130 | /** @brief Decode OEM meta read file io req 131 | * 132 | * @param[in] msg - Pointer to PLDM request message 133 | * @param[in] payload_length - Length of request payload 134 | * @param[out] req - Pointer to the structure to store the decoded response data 135 | * @return 0 on success, negative errno value on failure 136 | */ 137 | int decode_oem_meta_file_io_read_req(const struct pldm_msg *msg, 138 | size_t payload_length, 139 | struct pldm_oem_meta_file_io_read_req *req); 140 | 141 | /** @brief Obtain the pointer to the data array of a read response 142 | * 143 | * @param[in] resp - The pointer to the read response struct 144 | * 145 | * @return The read response data pointer. 146 | */ 147 | void *pldm_oem_meta_file_io_read_resp_data( 148 | struct pldm_oem_meta_file_io_read_resp *resp); 149 | 150 | /** 151 | * @brief Encode OEM meta read file io resp 152 | * 153 | * @param[in] instance_id - The instance ID of the PLDM entity 154 | * @param[out] resp - Pointer to the reqponse message 155 | * @param[in] resp_len - Length of response message 156 | * @param[out] responseMsg - Pointer to the buffer to store the response data 157 | * @param[in] payload_length - Length of response payload 158 | * @return 0 on success, negative errno value on failure 159 | */ 160 | int encode_oem_meta_file_io_read_resp( 161 | uint8_t instance_id, struct pldm_oem_meta_file_io_read_resp *resp, 162 | size_t resp_len, struct pldm_msg *responseMsg, size_t payload_length); 163 | 164 | #ifdef __cplusplus 165 | } 166 | #endif 167 | 168 | #endif /*LIBPLDM_OEM_META_FILE_IO_H*/ 169 | -------------------------------------------------------------------------------- /include/libpldm/pldm.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef MCTP_H 3 | #define MCTP_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | /* Delete when deleting old api */ 13 | typedef uint8_t mctp_eid_t; 14 | 15 | typedef enum pldm_requester_error_codes { 16 | PLDM_REQUESTER_SUCCESS = 0, 17 | PLDM_REQUESTER_OPEN_FAIL = -1, 18 | PLDM_REQUESTER_NOT_PLDM_MSG = -2, 19 | PLDM_REQUESTER_NOT_RESP_MSG = -3, 20 | PLDM_REQUESTER_NOT_REQ_MSG = -4, 21 | PLDM_REQUESTER_RESP_MSG_TOO_SMALL = -5, 22 | PLDM_REQUESTER_INSTANCE_ID_MISMATCH = -6, 23 | PLDM_REQUESTER_SEND_FAIL = -7, 24 | PLDM_REQUESTER_RECV_FAIL = -8, 25 | PLDM_REQUESTER_INVALID_RECV_LEN = -9, 26 | PLDM_REQUESTER_SETUP_FAIL = -10, 27 | PLDM_REQUESTER_INVALID_SETUP = -11, 28 | PLDM_REQUESTER_POLL_FAIL = -12, 29 | PLDM_REQUESTER_TRANSPORT_BUSY = -13, 30 | } pldm_requester_rc_t; 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif /* MCTP_H */ 37 | -------------------------------------------------------------------------------- /include/libpldm/pldm_types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef PLDM_TYPES_H 3 | #define PLDM_TYPES_H 4 | 5 | #include 6 | 7 | typedef union { 8 | uint8_t byte; 9 | struct { 10 | uint8_t bit0 : 1; 11 | uint8_t bit1 : 1; 12 | uint8_t bit2 : 1; 13 | uint8_t bit3 : 1; 14 | uint8_t bit4 : 1; 15 | uint8_t bit5 : 1; 16 | uint8_t bit6 : 1; 17 | uint8_t bit7 : 1; 18 | } __attribute__((packed)) bits; 19 | } bitfield8_t; 20 | 21 | /** @struct pldm_version 22 | * 23 | * 24 | */ 25 | typedef struct pldm_version { 26 | uint8_t alpha; 27 | uint8_t update; 28 | uint8_t minor; 29 | uint8_t major; 30 | } __attribute__((packed)) ver32_t; 31 | 32 | typedef uint8_t bool8_t; 33 | 34 | typedef union { 35 | uint16_t value; 36 | struct { 37 | uint8_t bit0 : 1; 38 | uint8_t bit1 : 1; 39 | uint8_t bit2 : 1; 40 | uint8_t bit3 : 1; 41 | uint8_t bit4 : 1; 42 | uint8_t bit5 : 1; 43 | uint8_t bit6 : 1; 44 | uint8_t bit7 : 1; 45 | uint8_t bit8 : 1; 46 | uint8_t bit9 : 1; 47 | uint8_t bit10 : 1; 48 | uint8_t bit11 : 1; 49 | uint8_t bit12 : 1; 50 | uint8_t bit13 : 1; 51 | uint8_t bit14 : 1; 52 | uint8_t bit15 : 1; 53 | } __attribute__((packed)) bits; 54 | } bitfield16_t; 55 | 56 | typedef union { 57 | uint32_t value; 58 | struct { 59 | uint8_t bit0 : 1; 60 | uint8_t bit1 : 1; 61 | uint8_t bit2 : 1; 62 | uint8_t bit3 : 1; 63 | uint8_t bit4 : 1; 64 | uint8_t bit5 : 1; 65 | uint8_t bit6 : 1; 66 | uint8_t bit7 : 1; 67 | uint8_t bit8 : 1; 68 | uint8_t bit9 : 1; 69 | uint8_t bit10 : 1; 70 | uint8_t bit11 : 1; 71 | uint8_t bit12 : 1; 72 | uint8_t bit13 : 1; 73 | uint8_t bit14 : 1; 74 | uint8_t bit15 : 1; 75 | uint8_t bit16 : 1; 76 | uint8_t bit17 : 1; 77 | uint8_t bit18 : 1; 78 | uint8_t bit19 : 1; 79 | uint8_t bit20 : 1; 80 | uint8_t bit21 : 1; 81 | uint8_t bit22 : 1; 82 | uint8_t bit23 : 1; 83 | uint8_t bit24 : 1; 84 | uint8_t bit25 : 1; 85 | uint8_t bit26 : 1; 86 | uint8_t bit27 : 1; 87 | uint8_t bit28 : 1; 88 | uint8_t bit29 : 1; 89 | uint8_t bit30 : 1; 90 | uint8_t bit31 : 1; 91 | } __attribute__((packed)) bits; 92 | } bitfield32_t; 93 | 94 | typedef union { 95 | uint64_t value; 96 | struct { 97 | uint8_t bit0 : 1; 98 | uint8_t bit1 : 1; 99 | uint8_t bit2 : 1; 100 | uint8_t bit3 : 1; 101 | uint8_t bit4 : 1; 102 | uint8_t bit5 : 1; 103 | uint8_t bit6 : 1; 104 | uint8_t bit7 : 1; 105 | uint8_t bit8 : 1; 106 | uint8_t bit9 : 1; 107 | uint8_t bit10 : 1; 108 | uint8_t bit11 : 1; 109 | uint8_t bit12 : 1; 110 | uint8_t bit13 : 1; 111 | uint8_t bit14 : 1; 112 | uint8_t bit15 : 1; 113 | uint8_t bit16 : 1; 114 | uint8_t bit17 : 1; 115 | uint8_t bit18 : 1; 116 | uint8_t bit19 : 1; 117 | uint8_t bit20 : 1; 118 | uint8_t bit21 : 1; 119 | uint8_t bit22 : 1; 120 | uint8_t bit23 : 1; 121 | uint8_t bit24 : 1; 122 | uint8_t bit25 : 1; 123 | uint8_t bit26 : 1; 124 | uint8_t bit27 : 1; 125 | uint8_t bit28 : 1; 126 | uint8_t bit29 : 1; 127 | uint8_t bit30 : 1; 128 | uint8_t bit31 : 1; 129 | uint8_t bit32 : 1; 130 | uint8_t bit33 : 1; 131 | uint8_t bit34 : 1; 132 | uint8_t bit35 : 1; 133 | uint8_t bit36 : 1; 134 | uint8_t bit37 : 1; 135 | uint8_t bit38 : 1; 136 | uint8_t bit39 : 1; 137 | uint8_t bit40 : 1; 138 | uint8_t bit41 : 1; 139 | uint8_t bit42 : 1; 140 | uint8_t bit43 : 1; 141 | uint8_t bit44 : 1; 142 | uint8_t bit45 : 1; 143 | uint8_t bit46 : 1; 144 | uint8_t bit47 : 1; 145 | uint8_t bit48 : 1; 146 | uint8_t bit49 : 1; 147 | uint8_t bit50 : 1; 148 | uint8_t bit51 : 1; 149 | uint8_t bit52 : 1; 150 | uint8_t bit53 : 1; 151 | uint8_t bit54 : 1; 152 | uint8_t bit55 : 1; 153 | uint8_t bit56 : 1; 154 | uint8_t bit57 : 1; 155 | uint8_t bit58 : 1; 156 | uint8_t bit59 : 1; 157 | uint8_t bit60 : 1; 158 | uint8_t bit61 : 1; 159 | uint8_t bit62 : 1; 160 | uint8_t bit63 : 1; 161 | } __attribute__((packed)) bits; 162 | } bitfield64_t; 163 | 164 | typedef float real32_t; 165 | 166 | #endif /* PLDM_TYPES_H */ 167 | -------------------------------------------------------------------------------- /include/libpldm/sizes.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* sizeof(struct pldm_fd) */ 4 | #define PLDM_SIZEOF_PLDM_FD @sizeof_pldm_fd@ 5 | 6 | /* sizeof(struct pldm_control) */ 7 | #define PLDM_SIZEOF_PLDM_CONTROL @sizeof_pldm_control@ 8 | -------------------------------------------------------------------------------- /include/libpldm/states.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef STATES_H 3 | #define STATES_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | 11 | /** @brief PLDM enums for the boot progress state set 12 | */ 13 | enum pldm_boot_progress_states { 14 | PLDM_BOOT_NOT_ACTIVE = 1, 15 | PLDM_BOOT_COMPLETED = 2, 16 | }; 17 | 18 | /** @brief PLDM enums for system power states 19 | */ 20 | enum pldm_system_power_states { 21 | PLDM_OFF_SOFT_GRACEFUL = 9, 22 | }; 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif /* STATES_H */ 29 | -------------------------------------------------------------------------------- /include/libpldm/transport.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef TRANSPORT_PLDM_H 3 | #define TRANSPORT_PLDM_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | struct pldm_transport; 15 | 16 | /** 17 | * @brief Waits for a PLDM event. 18 | * 19 | * @pre The pldm transport instance must be initialised; otherwise, 20 | * PLDM_REQUESTER_INVALID_SETUP is returned. This should be called after 21 | * pldm_transport_send_msg has been called. 22 | * 23 | * @param[in] transport - Wait until this transport instance is ready 24 | * @param[in] timeout - Wait for readiness for up to timeout milliseconds. 25 | * Specifying a timeout value of zero yields an immediate return. 26 | * Specifying a negative value means an indefinite timeout. 27 | * 28 | * @return 0 if a timeout occurs, 1 if the transport becomes ready, PLDM_REQUESTER_INVALID_SETUP if 29 | * transport is NULL, or PLDM_REQUESTER_POLL_FAIL on failure. 30 | */ 31 | int pldm_transport_poll(struct pldm_transport *transport, int timeout); 32 | 33 | /** 34 | * @brief Asynchronously send a PLDM message. Control is immediately returned to 35 | * the caller. 36 | * 37 | * @pre The pldm transport instance must be initialised; otherwise, 38 | * PLDM_REQUESTER_INVALID_SETUP is returned. If the transport requires a 39 | * TID to transport specific identifier mapping, this must already be set 40 | * up. 41 | * 42 | * @param[in] ctx - pldm transport instance 43 | * @param[in] tid - destination PLDM TID 44 | * @param[in] pldm_msg - caller owned pointer to PLDM msg. If this is NULL, 45 | * PLDM_REQUESTER_INVALID_SETUP is returned. 46 | * @param[in] msg_len - size of PLDM msg. If this is less than the minimum size 47 | * of a PLDM msg PLDM_REQUESTER_NOT_REQ_MSG is returned. 48 | * Otherwise, if this is not the correct length of the PLDM msg, 49 | * behaviour is undefined. 50 | * 51 | * @return pldm_requester_rc_t (errno may be set) 52 | */ 53 | pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport, 54 | pldm_tid_t tid, 55 | const void *pldm_msg, 56 | size_t msg_len); 57 | 58 | /** 59 | * @brief Asynchronously get a PLDM message. Control is immediately returned to the 60 | * caller. 61 | * 62 | * @pre The pldm transport instance must be initialised; otherwise, 63 | * PLDM_REQUESTER_INVALID_SETUP is returned. If the transport requires a 64 | * TID to transport specific identifier mapping, this must already be set 65 | * up. 66 | * 67 | * @param[in] ctx - pldm transport instance 68 | * @param[out] tid - source PLDM TID 69 | * @param[out] pldm_msg - *pldm_msg will point to the received PLDM msg if 70 | * return code is PLDM_REQUESTER_SUCCESS; otherwise, NULL. On 71 | * success this function allocates memory, caller to 72 | * free(*pldm_msg). 73 | * @param[out] msg_len - caller owned pointer that will be made to point to 74 | * the size of the PLDM msg. If NULL, 75 | * PLDM_REQUESTER_INVALID_SETUP is returned. 76 | * 77 | * @return pldm_requester_rc_t (errno may be set). Failure is returned if no 78 | * PLDM messages are available. 79 | * 80 | */ 81 | pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport, 82 | pldm_tid_t *tid, void **pldm_msg, 83 | size_t *msg_len); 84 | 85 | /** 86 | * @brief Synchronously send a PLDM request and receive the response. Control is 87 | * returned to the caller once the response is received. 88 | * 89 | * pldm_transport_send_recv() will discard messages received on the underlying transport instance 90 | * that are not a response that matches the request. Do not use this function if you're attempting 91 | * to use the transport instance asynchronously, as this discard behaviour will affect other 92 | * responses that you may care about. 93 | * 94 | * @pre The pldm transport instance must be initialised; otherwise, 95 | * PLDM_REQUESTER_INVALID_SETUP is returned. If the transport requires a 96 | * TID to transport specific identifier mapping, this must already be set 97 | * up. 98 | * 99 | * @param[in] ctx - pldm transport instance with a registered transport 100 | * @param[in] tid - destination PLDM TID 101 | * @param[in] pldm_req_msg - caller owned pointer to PLDM request msg or async 102 | * notification. If NULL, PLDM_REQUESTER_INVALID_SETUP is returned. 103 | * @param[in] req_msg_len - size of PLDM request msg. If this is less than the 104 | * minimum size of a PLDM msg PLDM_REQUESTER_NOT_REQ_MSG is returned. 105 | * Otherwise, if this is not the correct length of the PLDM msg, 106 | * behaviour is undefined. 107 | * @param[out] pldm_resp_msg - *pldm_resp_msg will point to PLDM response msg if 108 | * return code is PLDM_REQUESTER_SUCCESS; otherwise, NULL. On 109 | * success this function allocates memory, caller to 110 | * free(*pldm_resp_msg). 111 | * @param[out] resp_msg_len - caller owned pointer that will be made to point to 112 | * the size of the PLDM response msg. If NULL, 113 | * PLDM_REQUESTER_INVALID_SETUP is returned. 114 | * 115 | * @return pldm_requester_rc_t (errno may be set) 116 | */ 117 | pldm_requester_rc_t 118 | pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid, 119 | const void *pldm_req_msg, size_t req_msg_len, 120 | void **pldm_resp_msg, size_t *resp_msg_len); 121 | 122 | #ifdef __cplusplus 123 | } 124 | #endif 125 | 126 | #endif /* TRANSPORT_PLDM_H */ 127 | -------------------------------------------------------------------------------- /include/libpldm/transport/af-mctp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_AF_MCTP_H 3 | #define LIBPLDM_AF_MCTP_H 4 | 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | struct pldm_transport_af_mctp; 13 | struct sockaddr_mctp; 14 | 15 | /* Init the transport backend */ 16 | int pldm_transport_af_mctp_init(struct pldm_transport_af_mctp **ctx); 17 | 18 | /* Destroy the transport backend */ 19 | void pldm_transport_af_mctp_destroy(struct pldm_transport_af_mctp *ctx); 20 | 21 | /* Get the core pldm transport struct */ 22 | struct pldm_transport * 23 | pldm_transport_af_mctp_core(struct pldm_transport_af_mctp *ctx); 24 | 25 | #ifdef PLDM_HAS_POLL 26 | struct pollfd; 27 | /* Init pollfd for async calls */ 28 | int pldm_transport_af_mctp_init_pollfd(struct pldm_transport *t, 29 | struct pollfd *pollfd); 30 | #endif 31 | 32 | /* Inserts a TID-to-EID mapping into the transport's device map */ 33 | int pldm_transport_af_mctp_map_tid(struct pldm_transport_af_mctp *ctx, 34 | pldm_tid_t tid, mctp_eid_t eid); 35 | 36 | /* Removes a TID-to-EID mapping from the transport's device map */ 37 | int pldm_transport_af_mctp_unmap_tid(struct pldm_transport_af_mctp *ctx, 38 | pldm_tid_t tid, mctp_eid_t eid); 39 | 40 | /** 41 | * @brief Allow the transport to receive requests from remote endpoints 42 | * 43 | * @param[in] transport - The transport instance on which to listen for requests 44 | * @param[in] smctp - The configuration provided to bind(2). NULL may be passed, 45 | * in which case the transport is bound to all available 46 | * interfaces on the system's default network. If NULL is 47 | * passed then len must be zero. 48 | * @param[in] len - The size of the object pointed to by the smctp argument. If 49 | * smctp is NULL then len must be zero. 50 | * 51 | * @return PLDM_REQUESTER_SUCCESS on success, or a negative error code on 52 | * failure. 53 | */ 54 | int pldm_transport_af_mctp_bind(struct pldm_transport_af_mctp *transport, 55 | const struct sockaddr_mctp *smctp, size_t len); 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | 61 | #endif /* LIBPLDM_AF_MCTP*/ 62 | -------------------------------------------------------------------------------- /include/libpldm/transport/mctp-demux.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_DEMUX_H 3 | #define LIBPLDM_DEMUX_H 4 | 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | struct pldm_transport_mctp_demux; 13 | 14 | /* Init the transport backend */ 15 | int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx); 16 | 17 | /* Destroy the transport backend */ 18 | void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx); 19 | 20 | /* Get the core pldm transport struct */ 21 | struct pldm_transport * 22 | pldm_transport_mctp_demux_core(struct pldm_transport_mctp_demux *ctx); 23 | 24 | #ifdef PLDM_HAS_POLL 25 | struct pollfd; 26 | /* Init pollfd for async calls */ 27 | int pldm_transport_mctp_demux_init_pollfd(struct pldm_transport *t, 28 | struct pollfd *pollfd); 29 | #endif 30 | 31 | /* Inserts a TID-to-EID mapping into the transport's device map */ 32 | int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx, 33 | pldm_tid_t tid, mctp_eid_t eid); 34 | 35 | /* Removes a TID-to-EID mapping from the transport's device map */ 36 | int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx, 37 | pldm_tid_t tid, mctp_eid_t eid); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif /* LIBPLDM_DEMUX_H */ 44 | -------------------------------------------------------------------------------- /include/libpldm/utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_UTILS_H 3 | #define LIBPLDM_UTILS_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | /** @struct variable_field 17 | * 18 | * Structure representing variable field in the pldm message 19 | */ 20 | struct variable_field { 21 | const uint8_t *ptr; 22 | size_t length; 23 | }; 24 | 25 | /** @brief Compute Crc8(same as the one used by SMBUS) 26 | * 27 | * @param[in] data - Pointer to the target data 28 | * @param[in] size - Size of the data 29 | * @return The checksum 30 | */ 31 | uint8_t pldm_edac_crc8(const void *data, size_t size); 32 | uint8_t crc8(const void *data, size_t size); 33 | 34 | /** @brief Compute crc32 (same as the one used by IEEE802.3) 35 | * 36 | * @param[in] data - Pointer to the target data 37 | * @param[in] size - Size of the data 38 | * @return The checksum 39 | */ 40 | uint32_t pldm_edac_crc32(const void *data, size_t size); 41 | uint32_t crc32(const void *data, size_t size); 42 | 43 | /** @brief Convert ver32_t to string 44 | * @param[in] version - Pointer to ver32_t 45 | * @param[out] buffer - Pointer to the buffer 46 | * @param[in] buffer_size - Size of the buffer, up to SSIZE_MAX 47 | * @return The number of characters written to the buffer (excluding the null 48 | * byte). The converted string may be truncated, and truncation is not 49 | * considered an error. The result is negative if invalid arguments are supplied 50 | * (NULL values for required pointers or the buffer size is beyond a 51 | * representable range). 52 | */ 53 | ssize_t ver2str(const ver32_t *version, char *buffer, size_t buffer_size); 54 | 55 | /** @brief Convert bcd number(uint8_t) to decimal 56 | * @param[in] bcd - bcd number 57 | * @return the decimal number 58 | */ 59 | uint8_t bcd2dec8(uint8_t bcd); 60 | 61 | /** @brief Convert decimal number(uint8_t) to bcd 62 | * @param[in] dec - decimal number 63 | * @return the bcd number 64 | */ 65 | uint8_t dec2bcd8(uint8_t dec); 66 | 67 | /** @brief Convert bcd number(uint16_t) to decimal 68 | * @param[in] bcd - bcd number 69 | * @return the decimal number 70 | */ 71 | uint16_t bcd2dec16(uint16_t bcd); 72 | 73 | /** @brief Convert decimal number(uint16_t) to bcd 74 | * @param[in] dec - decimal number 75 | * @return the bcd number 76 | */ 77 | uint16_t dec2bcd16(uint16_t dec); 78 | 79 | /** @brief Convert bcd number(uint32_t) to decimal 80 | * @param[in] bcd - bcd number 81 | * @return the decimal number 82 | */ 83 | uint32_t bcd2dec32(uint32_t bcd); 84 | 85 | /** @brief Convert decimal number(uint32_t) to bcd 86 | * @param[in] dec - decimal number 87 | * @return the bcd number 88 | */ 89 | uint32_t dec2bcd32(uint32_t dec); 90 | 91 | /** @brief Check whether the input time is legal 92 | * 93 | * @param[in] seconds. Value range 0~59 94 | * @param[in] minutes. Value range 0~59 95 | * @param[in] hours. Value range 0~23 96 | * @param[in] day. Value range 1~31 97 | * @param[in] month. Value range 1~12 98 | * @param[in] year. Value range 1970~ 99 | * @return true if time is legal,false if time is illegal 100 | */ 101 | bool is_time_legal(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, 102 | uint8_t month, uint16_t year); 103 | 104 | /** @brief Check whether transfer flag is valid 105 | * 106 | * @param[in] transfer_flag - TransferFlag 107 | * 108 | * @return true if transfer flag is valid, false if not 109 | */ 110 | bool is_transfer_flag_valid(uint8_t transfer_flag); 111 | 112 | #ifdef __cplusplus 113 | } 114 | #endif 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /include/meson.build: -------------------------------------------------------------------------------- 1 | subdir('libpldm') 2 | -------------------------------------------------------------------------------- /instance-db/default: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'libpldm', 3 | 'c', 4 | default_options: { 5 | 'debug': true, 6 | 'optimization': 'g', 7 | 'warning_level': '3', 8 | 'werror': true, 9 | 'cpp_std': 'c++23', 10 | 'c_std': 'c17', 11 | 'b_ndebug': 'if-release', 12 | 'tests': not meson.is_subproject(), 13 | }, 14 | version: '0.12.0', 15 | meson_version: '>=1.4.0', 16 | ) 17 | 18 | if get_option('tests') 19 | add_languages('cpp', native: false) 20 | endif 21 | 22 | # For memmem() in src/msgbuf.h 23 | add_project_arguments('-D_GNU_SOURCE', language: ['c']) 24 | 25 | compiler = meson.get_compiler('c') 26 | if compiler.has_argument('-Wvla') 27 | add_project_arguments('-Wvla', language: ['c']) 28 | endif 29 | 30 | conf = configuration_data() 31 | if compiler.has_header('poll.h') 32 | conf.set('PLDM_HAS_POLL', 1) 33 | endif 34 | 35 | # ABI control 36 | compiler.has_function_attribute('visibility:default', required: true) 37 | entrypoint = '__attribute__((visibility("default")))' 38 | 39 | ## Compile test until meson supports it via compiler.has_function_attribute() 40 | have_tainted_args_test = '#if !__has_attribute(tainted_args)\n#error\n#endif' 41 | if compiler.compiles( 42 | have_tainted_args_test, 43 | args: '-E', 44 | name: 'compiler supports function attribute tainted_args', 45 | ) 46 | entrypoint += ' __attribute__((tainted_args))' 47 | endif 48 | 49 | libpldm_deprecated_aliases = [ 50 | ['crc32', 'pldm_edac_crc32'], 51 | ['crc8', 'pldm_edac_crc8'], 52 | ] 53 | if get_option('abi').contains('deprecated') 54 | conf.set('LIBPLDM_ABI_DEPRECATED', entrypoint) 55 | conf.set( 56 | 'LIBPLDM_ABI_DEPRECATED_UNSAFE', 57 | '__attribute__((visibility("default")))', 58 | ) 59 | add_project_arguments('-DLIBPLDM_API_DEPRECATED', language: ['c', 'cpp']) 60 | else 61 | conf.set('LIBPLDM_ABI_DEPRECATED', '') 62 | conf.set('LIBPLDM_ABI_DEPRECATED_UNSAFE', '') 63 | endif 64 | conf.set('LIBPLDM_ABI_STABLE', entrypoint) # Always expose the stable symbols 65 | if get_option('abi').contains('testing') 66 | conf.set('LIBPLDM_ABI_TESTING', entrypoint) 67 | add_project_arguments('-DLIBPLDM_API_TESTING', language: ['c', 'cpp']) 68 | else 69 | conf.set('LIBPLDM_ABI_TESTING', '') 70 | endif 71 | 72 | config = configure_file(output: 'config.h', configuration: conf) 73 | 74 | add_project_arguments('-include', config.full_path(), language: 'c') 75 | 76 | libpldm_include_dir = include_directories('include', is_system: true) 77 | 78 | subdir('include') 79 | subdir('src') 80 | 81 | doxygen = find_program('doxygen', required: false) 82 | if doxygen.found() 83 | doxydata = configuration_data() 84 | doxydata.set('description', meson.project_name()) 85 | doxydata.set('project', meson.project_name()) 86 | doxydata.set('version', meson.project_version()) 87 | doxydata.set( 88 | 'sources', 89 | '@0@ @1@'.format( 90 | meson.project_source_root() / 'include', 91 | meson.project_source_root() / 'src', 92 | ), 93 | ) 94 | doxyfile = configure_file( 95 | input: 'Doxyfile.in', 96 | output: 'Doxyfile', 97 | configuration: doxydata, 98 | install: false, 99 | ) 100 | 101 | docs = custom_target( 102 | 'docs', 103 | input: doxyfile, 104 | output: 'doxygen', 105 | command: [doxygen, doxyfile], 106 | ) 107 | endif 108 | 109 | if get_option('tests') 110 | subdir('tests') 111 | endif 112 | 113 | install_subdir( 114 | 'instance-db', 115 | install_mode: 'r--r--r--', 116 | install_dir: get_option('datadir') / meson.project_name(), 117 | ) 118 | -------------------------------------------------------------------------------- /meson.options: -------------------------------------------------------------------------------- 1 | option( 2 | 'abi', 3 | type: 'array', 4 | description: 'Constrain exposed symbol classes', 5 | choices: ['deprecated', 'stable', 'testing'], 6 | value: ['deprecated', 'stable', 'testing'], 7 | ) 8 | option( 9 | 'abi-compliance-check', 10 | type: 'boolean', 11 | description: 'Detect public ABI/API changes', 12 | ) 13 | option( 14 | 'oem', 15 | type: 'array', 16 | description: 'Enable OEM PLDM extensions', 17 | choices: ['ibm', 'meta'], 18 | value: ['ibm', 'meta'], 19 | ) 20 | option('tests', type: 'boolean', description: 'Build tests') 21 | option( 22 | 'transport', 23 | type: 'boolean', 24 | description: 'Enable transport implementation', 25 | ) 26 | -------------------------------------------------------------------------------- /scripts/abi-dump-formatter: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # SPDX-License-Identifier: LGPL-2.1-or-later 3 | # 4 | # Copyright (C) 2013-2020 Andrey Ponomarenko's ABI Laboratory 5 | # Copyright (C) 2024 Code Construct 6 | 7 | # Copied from abi-dumper 8 | # Written by Andrey Ponomarenko 9 | sub dumpSorting($) 10 | { 11 | my $Hash = $_[0]; 12 | return [] if(not $Hash); 13 | my @Keys = keys(%{$Hash}); 14 | return [] if($#Keys<0); 15 | if($Keys[0]=~/\A\d+\Z/) 16 | { # numbers 17 | return [sort {$a<=>$b} @Keys]; 18 | } 19 | else 20 | { # strings 21 | return [sort {$a cmp $b} @Keys]; 22 | } 23 | } 24 | 25 | use Data::Dumper; 26 | 27 | # Prevent key lengths from changing the indentation 28 | $Data::Dumper::Indent = 1; 29 | $Data::Dumper::Sortkeys = \&dumpSorting; 30 | $/ = undef; 31 | print Dumper(eval(<>)); 32 | -------------------------------------------------------------------------------- /scripts/abi-dump-updater: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | 3 | set -x 4 | 5 | set -eu 6 | 7 | UPDATE_BUILDDIR="$(mktemp -d)" 8 | 9 | trap "rm -rf $UPDATE_BUILDDIR" EXIT 10 | 11 | export CC=gcc 12 | export CXX=g++; 13 | 14 | [ $(uname -m) = 'x86_64' ] 15 | 16 | meson setup -Dabi=deprecated,stable "$UPDATE_BUILDDIR" 17 | meson compile -C "$UPDATE_BUILDDIR" abi-dump 18 | ./scripts/abi-dump-formatter < "$UPDATE_BUILDDIR"/src/current.dump > abi/x86_64/gcc.dump 19 | -------------------------------------------------------------------------------- /scripts/apply-renames: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | set -eou pipefail 4 | 5 | # Path to the meson build directory 6 | : "${BUILD:=build}" 7 | 8 | ABSPATH="$(command -v "$0" | xargs realpath)" 9 | 10 | # Deal with relative paths 11 | : "${LIBPLDM_ROOT:="${ABSPATH%scripts/apply-renames}"}" 12 | 13 | # Deal with clang including its version in all the tool names 14 | : "${CLANG_VERSION:=18}" 15 | : "${CLANG_RENAME:="$(command -v clang-rename-"${CLANG_VERSION}")"}" 16 | : "${CLANG_APPLY_REPLACEMENTS:="$(command -v clang-apply-replacements-"${CLANG_VERSION}")"}" 17 | 18 | # Make it parallel 19 | : "${JOBS:="$(nproc)"}" 20 | 21 | # Allow clang-rename to pick up the per-file flags from the compile command 22 | # database 23 | : "${CRFLAGS:="-p=."}" 24 | 25 | CRINPUT=$(realpath --relative-to "$BUILD" "$1") 26 | 27 | # Deal with clang-rename segfaulting when file paths from the compile command 28 | # database don't resolve properly 29 | cd "$BUILD" 30 | 31 | # We export the fixes to yaml files so we can apply them all in one hit later 32 | trap "rm -f fixes.*.yaml" EXIT 33 | 34 | # See `man 7 gitglossary` for some explanation of the pathspec provided to `git 35 | # ls-files`, which, separately, is also subject to bash's brace expansion. See 36 | # "Brace Expansion" in `man bash`. 37 | # shellcheck disable=SC2016 38 | git ls-files -- ':/:*.[ch]'{,pp} | 39 | xargs -I '{}' -n 1 -P "$JOBS" -- \ 40 | bash -c '"$0" --force --input="$1" --export-fixes="$(mktemp fixes.XXXXX.yaml)" "$2" "$3"' \ 41 | "$CLANG_RENAME" "$CRINPUT" "$CRFLAGS" '{}' 42 | 43 | # Now apply the generated fixes 44 | "$CLANG_APPLY_REPLACEMENTS" .. 45 | 46 | # Deal with subsequent runs of clang-rename bailing out because it's modified 47 | # the symbol declaration in the headers, and then is surprised by the lack of a 48 | # declaration for the as-yet un-renamed symbol in the implementation 49 | git -C "$LIBPLDM_ROOT" restore -- include 50 | -------------------------------------------------------------------------------- /scripts/changelog.awk: -------------------------------------------------------------------------------- 1 | BEGIN { cl = 0; api = 0; } 2 | /^CHANGELOG.md$/ { cl=1 } 3 | /^include[/]libpldm/ { api=1 } 4 | END { exit !(cl || !api); } 5 | -------------------------------------------------------------------------------- /scripts/pre-submit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | set -eu 3 | 4 | BUILD="$(mktemp --directory --tmpdir=.)" 5 | trap 'rm -rf "$BUILD"' EXIT 6 | 7 | meson format --recursive --inplace || true 8 | if ! git diff --exit-code 9 | then 10 | echo Your changes must meet the upstream meson style guide 11 | echo 12 | echo https://mesonbuild.com/Style-guide.html 13 | echo https://mesonbuild.com/Commands.html#format 14 | exit 1 15 | fi 16 | 17 | # Make sure if the change touches the public headers, it also updates the 18 | # changelog. 19 | if ! git show --format="" --name-only HEAD -- CHANGELOG.md include/libpldm | 20 | awk -f scripts/changelog.awk 21 | then 22 | echo You must document your changes under include/libpldm in CHANGELOG.md 23 | exit 1 24 | fi 25 | 26 | # Ensure the test suite passes in the default configuration. Note 27 | # that we don't specify -Dabi=... - the default is equivalent to 28 | # -Dabi=deprecated,stable,testing. 29 | CC=gcc CXX=g++ CFLAGS=-fanalyzer meson setup -Dabi-compliance-check=false "$BUILD" 30 | meson compile -C "$BUILD" 31 | meson test -C "$BUILD" 32 | 33 | # Ensure the test suite passes in release mode. libpldm specifies 34 | # -Db_ndebug=if-release by default, so building with --buildtype=release passes 35 | # -DNDEBUG to the compiler for the library implementation. This build 36 | # configuration will catch any unexpected changes in the library implementation 37 | # and incorrect test case implementations. 38 | meson configure --buildtype=release "$BUILD" 39 | meson compile -C "$BUILD" 40 | meson test -C "$BUILD" --timeout-multiplier 10 --wrapper 'valgrind --error-exitcode=1' 41 | 42 | # Ensure the test suite links when testing symbols are removed from the ABI 43 | meson configure --buildtype=debug "$BUILD" 44 | meson configure -Dabi=deprecated,stable "$BUILD" 45 | meson compile -C "$BUILD" 46 | meson test -C "$BUILD" 47 | 48 | # Ensure the build completes for maintenance purposes. Note that tests are 49 | # disabled as we don't yet guard them appropriately. 50 | meson configure -Dabi=stable,testing -Dtests=false "$BUILD" 51 | meson compile -C "$BUILD" 52 | -------------------------------------------------------------------------------- /scripts/run-ci: -------------------------------------------------------------------------------- 1 | pre-submit -------------------------------------------------------------------------------- /src/api.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 2 | #ifndef LIBPLDM_SRC_API_H 3 | #define LIBPLDM_SRC_API_H 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | /** 11 | * @brief Translate a negative errno value to a PLDM completion code 12 | * 13 | * Existing stable APIs often return errors in the form of PLDM completion 14 | * codes, which confuses the problems of the protocol with the problems of 15 | * the implementation. We're shifting to using negative errno values to signal 16 | * implementation errors. However, for existing stable APIs, provide a means to 17 | * translate between the two. 18 | * 19 | * @param[in] err - The negative errno to translate to a completion code 20 | * 21 | * @return An equivalent PLDM completion code for @p err 22 | */ 23 | static inline enum pldm_completion_codes pldm_xlate_errno(int err) 24 | { 25 | enum pldm_completion_codes rc; 26 | 27 | assert(err < 0); 28 | switch (err) { 29 | case -EINVAL: 30 | case -EBADMSG: 31 | rc = PLDM_ERROR_INVALID_DATA; 32 | break; 33 | case -ENOMSG: 34 | rc = PLDM_ERROR_INVALID_PLDM_TYPE; 35 | break; 36 | case -EOVERFLOW: 37 | rc = PLDM_ERROR_INVALID_LENGTH; 38 | break; 39 | default: 40 | assert(false); 41 | rc = PLDM_ERROR; 42 | break; 43 | } 44 | 45 | assert(rc > 0); 46 | return rc; 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/array.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_SRC_ARRAY_H 3 | #define LIBPLDM_SRC_ARRAY_H 4 | 5 | #ifndef ARRAY_SIZE 6 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 7 | #endif 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/compiler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef PLDM_COMPILER_H 3 | #define PLDM_COMPILER_H 4 | 5 | #include 6 | 7 | #ifndef __has_attribute 8 | #error The libpldm implementation requires __has_attribute 9 | #endif 10 | 11 | #include 12 | 13 | static struct { 14 | static_assert(__has_attribute(always_inline), 15 | "`always_inline` attribute is required"); 16 | static_assert(__has_attribute(nonnull), 17 | "`nonnull` attribute is required"); 18 | static_assert(__has_attribute(unused), 19 | "`unused` attribute is required"); 20 | static_assert(__has_attribute(warn_unused_result), 21 | "`warn_unused_result` attribute is required"); 22 | static_assert(__has_attribute(cleanup), 23 | "`cleanup` attribute is required"); 24 | int compliance; 25 | } pldm_required_attributes __attribute__((unused)); 26 | 27 | #ifndef LIBPLDM_CC_ALWAYS_INLINE 28 | #error Missing definition for LIBPLDM_ALWAYS_INLINE 29 | #endif 30 | 31 | #ifndef LIBPLDM_CC_NONNULL 32 | #error Missing definition for LIBPLDM_CC_NONNULL 33 | #endif 34 | 35 | #define LIBPLDM_CC_CLEANUP(fn) __attribute__((cleanup(fn))) 36 | #define LIBPLDM_CC_NONNULL_ARGS(...) __attribute__((nonnull(__VA_ARGS__))) 37 | #define LIBPLDM_CC_UNUSED __attribute__((unused)) 38 | #define LIBPLDM_CC_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) 39 | 40 | // NOLINTBEGIN(bugprone-macro-parentheses) 41 | /** 42 | * Require that the given object is of the specified type. 43 | * 44 | * If the object is not of the required type then a diagnostic will be emitted. 45 | * 46 | * If you are reading this documentation due to hitting a compilation error 47 | * passing through the macro, then you have a type error in your code that must 48 | * be fixed. Despite the compiler output, the error is _not_ that some array 49 | * is negatively sized, the array is negatively sized _because_ you have a type 50 | * error. 51 | * 52 | * How this works: 53 | * 54 | * If the type of @p obj is not equivalent to the provided type @p type then 55 | * we force the compiler to evaluate sizeof on a negatively-sized array. The 56 | * C standard requires that the integer constant expression that specifies 57 | * the array length must be greater than zero. Failure to meet this constraint 58 | * generally terminates compilation of the translation unit as any other result 59 | * cannot be handled in a sensible way. The array size is derived to an integer 60 | * constant expression from a type eqivalence evaluated using _Generic() 61 | * allowing us to stay within the language standard. The default generic 62 | * association, representing a type mismatch, yields -1. 63 | * 64 | * pldm_require_obj_type() was introduced into the libpldm implementation to 65 | * enable use of the pldm_msgbuf_extract*() APIs for objects that may or may not 66 | * reside in a packed struct. See src/msgbuf.h for more details. 67 | * 68 | * @param obj The name of the object to evaluate 69 | * @param type The required type of @p obj 70 | * 71 | * @return The expression either yields 1, or compilation is terminated 72 | */ 73 | #define pldm_require_obj_type(obj, type) \ 74 | ((void)(sizeof( \ 75 | struct { char buf[_Generic((obj), type: 1, default: -1)]; }))) 76 | // NOLINTEND(bugprone-macro-parentheses) 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/control-internal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef PLDM_CONTROL_MAX_VERSION_TYPES 12 | #define PLDM_CONTROL_MAX_VERSION_TYPES 6 13 | #endif 14 | 15 | struct pldm_type_versions { 16 | /* A buffer of ver32_t/uint32_t of version values, followed by crc32 */ 17 | /* NULL for unused entries */ 18 | const void *versions; 19 | /* Includes the trailing crc32 entry */ 20 | uint8_t versions_count; 21 | 22 | /* A buffer of 32 entries, for commands 0-0xff */ 23 | const bitfield8_t *commands; 24 | 25 | uint8_t pldm_type; 26 | }; 27 | 28 | struct pldm_control { 29 | struct pldm_type_versions types[PLDM_CONTROL_MAX_VERSION_TYPES]; 30 | }; 31 | -------------------------------------------------------------------------------- /src/dsp/base.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 2 | #ifndef LIBPLDM_SRC_DSP_BASE_H 3 | #define LIBPLDM_SRC_DSP_BASE_H 4 | 5 | /* Internal functions */ 6 | 7 | #include "compiler.h" 8 | #include 9 | 10 | int pack_pldm_header_errno(const struct pldm_header_info *hdr, 11 | struct pldm_msg_hdr *msg); 12 | 13 | int unpack_pldm_header_errno(const struct pldm_msg_hdr *msg, 14 | struct pldm_header_info *hdr); 15 | 16 | int encode_pldm_header_only_errno(uint8_t msg_type, uint8_t instance_id, 17 | uint8_t pldm_type, uint8_t command, 18 | struct pldm_msg *msg); 19 | 20 | LIBPLDM_CC_ALWAYS_INLINE 21 | int pldm_msg_has_error(const struct pldm_msg *msg, size_t payload_length) 22 | { 23 | static_assert(PLDM_SUCCESS == 0, "Rework required"); 24 | return payload_length < 1 ? 0 : msg->payload[0]; 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/dsp/file.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #include "dsp/base.h" 3 | #include "msgbuf.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | LIBPLDM_ABI_TESTING 17 | int encode_pldm_file_df_open_req(uint8_t instance_id, 18 | const struct pldm_file_df_open_req *req, 19 | struct pldm_msg *msg, size_t payload_length) 20 | { 21 | PLDM_MSGBUF_DEFINE_P(buf); 22 | int rc; 23 | 24 | if (req == NULL || msg == NULL) { 25 | return -EINVAL; 26 | } 27 | 28 | struct pldm_header_info header = { 0 }; 29 | header.instance = instance_id; 30 | header.msg_type = PLDM_REQUEST; 31 | header.pldm_type = PLDM_FILE; 32 | header.command = PLDM_FILE_CMD_DF_OPEN; 33 | 34 | rc = pack_pldm_header_errno(&header, &(msg->hdr)); 35 | if (rc) { 36 | return rc; 37 | } 38 | 39 | rc = pldm_msgbuf_init_errno(buf, PLDM_DF_OPEN_REQ_BYTES, msg->payload, 40 | payload_length); 41 | if (rc) { 42 | return rc; 43 | } 44 | 45 | pldm_msgbuf_insert(buf, req->file_identifier); 46 | pldm_msgbuf_insert(buf, req->file_attribute.value); 47 | 48 | return pldm_msgbuf_complete(buf); 49 | } 50 | 51 | LIBPLDM_ABI_TESTING 52 | int decode_pldm_file_df_open_resp(const struct pldm_msg *msg, 53 | size_t payload_length, 54 | struct pldm_file_df_open_resp *resp) 55 | { 56 | PLDM_MSGBUF_DEFINE_P(buf); 57 | int rc; 58 | 59 | if (!msg || !resp) { 60 | return -EINVAL; 61 | } 62 | 63 | rc = pldm_msg_has_error(msg, payload_length); 64 | if (rc) { 65 | resp->completion_code = rc; 66 | return 0; 67 | } 68 | 69 | rc = pldm_msgbuf_init_errno(buf, PLDM_DF_OPEN_RESP_BYTES, msg->payload, 70 | payload_length); 71 | if (rc) { 72 | return rc; 73 | } 74 | 75 | pldm_msgbuf_extract(buf, resp->completion_code); 76 | pldm_msgbuf_extract(buf, resp->file_descriptor); 77 | 78 | return pldm_msgbuf_complete_consumed(buf); 79 | } 80 | 81 | LIBPLDM_ABI_TESTING 82 | int encode_pldm_file_df_close_req(uint8_t instance_id, 83 | const struct pldm_file_df_close_req *req, 84 | struct pldm_msg *msg, size_t payload_length) 85 | { 86 | PLDM_MSGBUF_DEFINE_P(buf); 87 | int rc; 88 | 89 | if (!req || !msg) { 90 | return -EINVAL; 91 | } 92 | 93 | struct pldm_header_info header = { 0 }; 94 | header.instance = instance_id; 95 | header.msg_type = PLDM_REQUEST; 96 | header.pldm_type = PLDM_FILE; 97 | header.command = PLDM_FILE_CMD_DF_CLOSE; 98 | 99 | rc = pack_pldm_header_errno(&header, &(msg->hdr)); 100 | if (rc) { 101 | return rc; 102 | } 103 | 104 | rc = pldm_msgbuf_init_errno(buf, PLDM_DF_CLOSE_REQ_BYTES, msg->payload, 105 | payload_length); 106 | if (rc) { 107 | return rc; 108 | } 109 | 110 | pldm_msgbuf_insert(buf, req->file_descriptor); 111 | pldm_msgbuf_insert(buf, req->df_close_options.value); 112 | 113 | return pldm_msgbuf_complete(buf); 114 | } 115 | 116 | LIBPLDM_ABI_TESTING 117 | int decode_pldm_file_df_close_resp(const struct pldm_msg *msg, 118 | size_t payload_length, 119 | struct pldm_file_df_close_resp *resp) 120 | { 121 | if (!msg || !resp) { 122 | return -EINVAL; 123 | } 124 | 125 | resp->completion_code = pldm_msg_has_error(msg, payload_length); 126 | 127 | return 0; 128 | } 129 | 130 | LIBPLDM_ABI_TESTING 131 | int encode_pldm_file_df_heartbeat_req( 132 | uint8_t instance_id, const struct pldm_file_df_heartbeat_req *req, 133 | struct pldm_msg *msg, size_t payload_length) 134 | { 135 | PLDM_MSGBUF_DEFINE_P(buf); 136 | int rc; 137 | 138 | if (!req || !msg) { 139 | return -EINVAL; 140 | } 141 | 142 | struct pldm_header_info header = { 0 }; 143 | header.instance = instance_id; 144 | header.msg_type = PLDM_REQUEST; 145 | header.pldm_type = PLDM_FILE; 146 | header.command = PLDM_FILE_CMD_DF_HEARTBEAT; 147 | 148 | rc = pack_pldm_header_errno(&header, &(msg->hdr)); 149 | if (rc) { 150 | return rc; 151 | } 152 | 153 | rc = pldm_msgbuf_init_errno(buf, PLDM_DF_HEARTBEAT_REQ_BYTES, 154 | msg->payload, payload_length); 155 | if (rc) { 156 | return rc; 157 | } 158 | 159 | pldm_msgbuf_insert(buf, req->file_descriptor); 160 | pldm_msgbuf_insert(buf, req->requester_max_interval); 161 | 162 | return pldm_msgbuf_complete(buf); 163 | } 164 | 165 | LIBPLDM_ABI_TESTING 166 | int decode_pldm_file_df_heartbeat_resp(const struct pldm_msg *msg, 167 | size_t payload_length, 168 | struct pldm_file_df_heartbeat_resp *resp) 169 | { 170 | PLDM_MSGBUF_DEFINE_P(buf); 171 | int rc; 172 | 173 | if (!msg || !resp) { 174 | return -EINVAL; 175 | } 176 | 177 | rc = pldm_msg_has_error(msg, payload_length); 178 | if (rc) { 179 | resp->completion_code = rc; 180 | return 0; 181 | } 182 | 183 | rc = pldm_msgbuf_init_errno(buf, PLDM_DF_HEARTBEAT_RESP_BYTES, 184 | msg->payload, payload_length); 185 | if (rc) { 186 | return rc; 187 | } 188 | 189 | pldm_msgbuf_extract(buf, resp->completion_code); 190 | pldm_msgbuf_extract(buf, resp->responder_max_interval); 191 | 192 | return pldm_msgbuf_complete_consumed(buf); 193 | } 194 | -------------------------------------------------------------------------------- /src/dsp/meson.build: -------------------------------------------------------------------------------- 1 | libpldm_sources += files( 2 | 'base.c', 3 | 'bios.c', 4 | 'bios_table.c', 5 | 'file.c', 6 | 'firmware_update.c', 7 | 'fru.c', 8 | 'pdr.c', 9 | 'platform.c', 10 | ) 11 | -------------------------------------------------------------------------------- /src/firmware_device/fd-internal.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | typedef uint64_t pldm_fd_time_t; 14 | 15 | struct pldm_fd_req { 16 | enum pldm_fd_req_state { 17 | // pldm_fd_req instance is unused 18 | PLDM_FD_REQ_UNUSED = 0, 19 | // Ready to send a request 20 | PLDM_FD_REQ_READY, 21 | // Waiting for a response 22 | PLDM_FD_REQ_SENT, 23 | // Completed and failed, will not send more requests. 24 | // Waiting for a cancel from the UA. 25 | PLDM_FD_REQ_FAILED, 26 | } state; 27 | 28 | /* Set once when ready to move to next state, will return 29 | * this result for TransferComplete/VerifyComplete/ApplyComplete request. */ 30 | bool complete; 31 | /* Only valid when complete is set */ 32 | uint8_t result; 33 | 34 | /* Only valid in SENT state */ 35 | uint8_t instance_id; 36 | uint8_t command; 37 | pldm_fd_time_t sent_time; 38 | }; 39 | 40 | struct pldm_fd_download { 41 | uint32_t offset; 42 | }; 43 | 44 | struct pldm_fd_verify { 45 | uint8_t progress_percent; 46 | }; 47 | 48 | struct pldm_fd_apply { 49 | uint8_t progress_percent; 50 | }; 51 | 52 | struct pldm_fd { 53 | enum pldm_firmware_device_states state; 54 | enum pldm_firmware_device_states prev_state; 55 | 56 | /* Reason for last transition to idle state, 57 | * only valid when state == PLDM_FD_STATE_IDLE */ 58 | enum pldm_get_status_reason_code_values reason; 59 | 60 | /* State-specific content */ 61 | union { 62 | struct pldm_fd_download download; 63 | struct pldm_fd_verify verify; 64 | struct pldm_fd_apply apply; 65 | } specific; 66 | /* Details of the component currently being updated. 67 | * Set by UpdateComponent, available during download/verify/apply. 68 | * Also used as temporary storage for PassComponentTable */ 69 | struct pldm_firmware_update_component update_comp; 70 | bitfield32_t update_flags; 71 | 72 | /* Used for download/verify/apply requests */ 73 | struct pldm_fd_req req; 74 | 75 | /* Address of the UA */ 76 | pldm_tid_t ua_address; 77 | bool ua_address_set; 78 | 79 | /* Maximum size allowed by the UA or platform implementation */ 80 | uint32_t max_transfer; 81 | 82 | /* Timestamp for FD T1 timeout, milliseconds */ 83 | pldm_fd_time_t update_timestamp_fd_t1; 84 | 85 | pldm_fd_time_t fd_t1_timeout; 86 | pldm_fd_time_t fd_t2_retry_time; 87 | 88 | const struct pldm_fd_ops *ops; 89 | void *ops_ctx; 90 | }; 91 | -------------------------------------------------------------------------------- /src/firmware_device/meson.build: -------------------------------------------------------------------------------- 1 | libpldm_sources += files('fd.c') 2 | -------------------------------------------------------------------------------- /src/mctp-defines.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef MCTP_DEFINES_H 3 | #define MCTP_DEFINES_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #define MCTP_MSG_TYPE_PLDM 1 10 | #define MCTP_MAX_NUM_EID 256 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif // MCTP_DEFINES_H 17 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | libpldm_sources = files('control.c', 'responder.c', 'utils.c') 2 | 3 | subdir('dsp') 4 | 5 | if get_option('transport') 6 | subdir('requester') 7 | subdir('transport') 8 | endif 9 | 10 | if get_option('oem').contains('ibm') 11 | subdir('oem/ibm') 12 | endif 13 | 14 | if get_option('oem').contains('meta') 15 | subdir('oem/meta') 16 | endif 17 | 18 | subdir('firmware_device') 19 | 20 | libpldm_link_args = [] 21 | foreach alias : libpldm_deprecated_aliases 22 | libpldm_link_args += '-Wl,--defsym=@0@=@1@'.format(alias[0], alias[1]) 23 | endforeach 24 | 25 | libpldm = library( 26 | 'pldm', 27 | libpldm_sources, 28 | implicit_include_directories: false, 29 | include_directories: [libpldm_include_dir, include_directories('.')], 30 | link_args: libpldm_link_args, 31 | version: meson.project_version(), 32 | gnu_symbol_visibility: 'hidden', 33 | install: true, 34 | ) 35 | 36 | libpldm_dep = declare_dependency( 37 | include_directories: libpldm_include_dir, 38 | link_with: libpldm, 39 | ) 40 | 41 | import('pkgconfig').generate( 42 | name: 'libpldm', 43 | description: 'PLDM protocol encode/decode C lib', 44 | version: meson.project_version(), 45 | libraries: libpldm, 46 | ) 47 | 48 | if get_option('tests') 49 | c_suite = meson.get_compiler('c').get_id() 50 | cpp_suite = meson.get_compiler('cpp').get_id() 51 | 52 | if get_option('abi-compliance-check') and c_suite == cpp_suite and c_suite == 'gcc' 53 | host = host_machine.cpu_family() 54 | baseline_dump = meson.project_source_root() / 'abi' / host / '@0@.dump'.format( 55 | c_suite, 56 | ) 57 | 58 | abi_dumper = find_program( 59 | 'abi-dumper', 60 | native: true, 61 | required: get_option('abi-compliance-check'), 62 | ) 63 | abi_compliance_checker = find_program( 64 | 'abi-compliance-checker', 65 | native: true, 66 | required: get_option('abi-compliance-check'), 67 | ) 68 | 69 | test_abi_compliance = abi_dumper.found() and \ 70 | abi_compliance_checker.found() and \ 71 | import('fs').is_file(baseline_dump) 72 | 73 | if test_abi_compliance 74 | current_dump = custom_target( 75 | 'abi-dump', 76 | input: libpldm, 77 | output: 'current.dump', 78 | command: [ 79 | abi_dumper, 80 | '-mixed-headers', 81 | '-include-paths', 82 | meson.project_source_root() / 'src', 83 | '-public-headers', 84 | meson.project_source_root() / 'include', 85 | '-sort', 86 | '@INPUT@', 87 | '-o', 88 | '@OUTPUT@', 89 | '-lver', 90 | meson.project_version(), 91 | ], 92 | ) 93 | abi_compliance = custom_target( 94 | 'abi-compliance', 95 | input: [baseline_dump, current_dump], 96 | output: 'abi-compliance', 97 | command: [ 98 | abi_compliance_checker, 99 | '-l', 100 | meson.project_name(), 101 | '-old', 102 | '@INPUT0@', 103 | '-new', 104 | '@INPUT1@', 105 | ], 106 | build_by_default: true, 107 | ) 108 | endif 109 | endif 110 | endif 111 | -------------------------------------------------------------------------------- /src/msgbuf/platform.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef PLDM_MSGBUF_PLATFORM_H 3 | #define PLDM_MSGBUF_PLATFORM_H 4 | 5 | #include "../compiler.h" 6 | #include "../msgbuf.h" 7 | #include 8 | #include 9 | 10 | LIBPLDM_CC_NONNULL 11 | LIBPLDM_CC_ALWAYS_INLINE int 12 | pldm_msgbuf_extract_value_pdr_hdr(struct pldm_msgbuf *ctx, 13 | struct pldm_value_pdr_hdr *hdr, size_t lower, 14 | size_t upper) 15 | { 16 | int rc; 17 | 18 | pldm_msgbuf_extract(ctx, hdr->record_handle); 19 | pldm_msgbuf_extract(ctx, hdr->version); 20 | pldm_msgbuf_extract(ctx, hdr->type); 21 | pldm_msgbuf_extract(ctx, hdr->record_change_num); 22 | rc = pldm_msgbuf_extract(ctx, hdr->length); 23 | if (rc) { 24 | return rc; 25 | } 26 | 27 | if (hdr->length + sizeof(*ctx) < lower) { 28 | return -EOVERFLOW; 29 | } 30 | 31 | if (hdr->length > upper) { 32 | return -EOVERFLOW; 33 | } 34 | 35 | return 0; 36 | } 37 | 38 | LIBPLDM_CC_ALWAYS_INLINE int 39 | pldm_msgbuf_extract_sensor_data(struct pldm_msgbuf *ctx, 40 | enum pldm_sensor_readings_data_type tag, 41 | union_sensor_data_size *dst) 42 | { 43 | switch (tag) { 44 | case PLDM_SENSOR_DATA_SIZE_UINT8: 45 | return pldm_msgbuf_extract(ctx, dst->value_u8); 46 | case PLDM_SENSOR_DATA_SIZE_SINT8: 47 | return pldm_msgbuf_extract(ctx, dst->value_s8); 48 | case PLDM_SENSOR_DATA_SIZE_UINT16: 49 | return pldm_msgbuf_extract(ctx, dst->value_u16); 50 | case PLDM_SENSOR_DATA_SIZE_SINT16: 51 | return pldm_msgbuf_extract(ctx, dst->value_s16); 52 | case PLDM_SENSOR_DATA_SIZE_UINT32: 53 | return pldm_msgbuf_extract(ctx, dst->value_u32); 54 | case PLDM_SENSOR_DATA_SIZE_SINT32: 55 | return pldm_msgbuf_extract(ctx, dst->value_s32); 56 | } 57 | 58 | return -PLDM_ERROR_INVALID_DATA; 59 | } 60 | 61 | /* 62 | * This API is bad, but it's because the caller's APIs are also bad. They should 63 | * have used the approach used by callers of pldm_msgbuf_extract_sensor_data() 64 | * above 65 | */ 66 | LIBPLDM_CC_ALWAYS_INLINE int 67 | pldm_msgbuf_extract_sensor_value(struct pldm_msgbuf *ctx, 68 | enum pldm_sensor_readings_data_type tag, 69 | void *val) 70 | { 71 | switch (tag) { 72 | case PLDM_SENSOR_DATA_SIZE_UINT8: 73 | return pldm__msgbuf_extract_uint8(ctx, val); 74 | case PLDM_SENSOR_DATA_SIZE_SINT8: 75 | return pldm__msgbuf_extract_int8(ctx, val); 76 | case PLDM_SENSOR_DATA_SIZE_UINT16: 77 | return pldm__msgbuf_extract_uint16(ctx, val); 78 | case PLDM_SENSOR_DATA_SIZE_SINT16: 79 | return pldm__msgbuf_extract_int16(ctx, val); 80 | case PLDM_SENSOR_DATA_SIZE_UINT32: 81 | return pldm__msgbuf_extract_uint32(ctx, val); 82 | case PLDM_SENSOR_DATA_SIZE_SINT32: 83 | return pldm__msgbuf_extract_int32(ctx, val); 84 | } 85 | 86 | return -PLDM_ERROR_INVALID_DATA; 87 | } 88 | 89 | #define pldm_msgbuf_extract_range_field_format(ctx, tag, dst) \ 90 | pldm_msgbuf_extract_typecheck(union_range_field_format, \ 91 | pldm__msgbuf_extract_range_field_format, \ 92 | dst, ctx, tag, (void *)&(dst)) 93 | LIBPLDM_CC_ALWAYS_INLINE int pldm__msgbuf_extract_range_field_format( 94 | struct pldm_msgbuf *ctx, enum pldm_range_field_format tag, void *rff) 95 | { 96 | switch (tag) { 97 | case PLDM_RANGE_FIELD_FORMAT_UINT8: 98 | return pldm__msgbuf_extract_uint8( 99 | ctx, ((char *)rff) + offsetof(union_range_field_format, 100 | value_u8)); 101 | case PLDM_RANGE_FIELD_FORMAT_SINT8: 102 | return pldm__msgbuf_extract_int8( 103 | ctx, ((char *)rff) + offsetof(union_range_field_format, 104 | value_s8)); 105 | case PLDM_RANGE_FIELD_FORMAT_UINT16: 106 | return pldm__msgbuf_extract_uint16( 107 | ctx, ((char *)rff) + offsetof(union_range_field_format, 108 | value_u16)); 109 | case PLDM_RANGE_FIELD_FORMAT_SINT16: 110 | return pldm__msgbuf_extract_int16( 111 | ctx, ((char *)rff) + offsetof(union_range_field_format, 112 | value_s16)); 113 | case PLDM_RANGE_FIELD_FORMAT_UINT32: 114 | return pldm__msgbuf_extract_uint32( 115 | ctx, ((char *)rff) + offsetof(union_range_field_format, 116 | value_u32)); 117 | case PLDM_RANGE_FIELD_FORMAT_SINT32: 118 | return pldm__msgbuf_extract_int32( 119 | ctx, ((char *)rff) + offsetof(union_range_field_format, 120 | value_s32)); 121 | case PLDM_RANGE_FIELD_FORMAT_REAL32: 122 | return pldm__msgbuf_extract_real32( 123 | ctx, ((char *)rff) + offsetof(union_range_field_format, 124 | value_f32)); 125 | } 126 | 127 | return -PLDM_ERROR_INVALID_DATA; 128 | } 129 | 130 | /* This API is bad, but it's because the caller's APIs are also bad */ 131 | LIBPLDM_CC_ALWAYS_INLINE int 132 | pldm_msgbuf_extract_effecter_value(struct pldm_msgbuf *ctx, 133 | enum pldm_effecter_data_size tag, void *dst) 134 | { 135 | switch (tag) { 136 | case PLDM_EFFECTER_DATA_SIZE_UINT8: 137 | return pldm__msgbuf_extract_uint8(ctx, dst); 138 | case PLDM_EFFECTER_DATA_SIZE_SINT8: 139 | return pldm__msgbuf_extract_int8(ctx, dst); 140 | case PLDM_EFFECTER_DATA_SIZE_UINT16: 141 | return pldm__msgbuf_extract_uint16(ctx, dst); 142 | case PLDM_EFFECTER_DATA_SIZE_SINT16: 143 | return pldm__msgbuf_extract_int16(ctx, dst); 144 | case PLDM_EFFECTER_DATA_SIZE_UINT32: 145 | return pldm__msgbuf_extract_uint32(ctx, dst); 146 | case PLDM_EFFECTER_DATA_SIZE_SINT32: 147 | return pldm__msgbuf_extract_int32(ctx, dst); 148 | } 149 | 150 | return -PLDM_ERROR_INVALID_DATA; 151 | } 152 | 153 | #define pldm_msgbuf_extract_effecter_data(ctx, tag, dst) \ 154 | pldm_msgbuf_extract_typecheck(union_effecter_data_size, \ 155 | pldm__msgbuf_extract_range_field_format, \ 156 | dst, ctx, tag, (void *)&(dst)) 157 | LIBPLDM_CC_ALWAYS_INLINE int 158 | pldm__msgbuf_extract_effecter_data(struct pldm_msgbuf *ctx, 159 | enum pldm_effecter_data_size tag, void *ed) 160 | { 161 | switch (tag) { 162 | case PLDM_EFFECTER_DATA_SIZE_UINT8: 163 | return pldm__msgbuf_extract_uint8( 164 | ctx, ((char *)ed) + offsetof(union_effecter_data_size, 165 | value_u8)); 166 | case PLDM_EFFECTER_DATA_SIZE_SINT8: 167 | return pldm__msgbuf_extract_int8( 168 | ctx, ((char *)ed) + offsetof(union_effecter_data_size, 169 | value_s8)); 170 | case PLDM_EFFECTER_DATA_SIZE_UINT16: 171 | return pldm__msgbuf_extract_uint16( 172 | ctx, ((char *)ed) + offsetof(union_effecter_data_size, 173 | value_u16)); 174 | case PLDM_EFFECTER_DATA_SIZE_SINT16: 175 | return pldm__msgbuf_extract_int16( 176 | ctx, ((char *)ed) + offsetof(union_effecter_data_size, 177 | value_s16)); 178 | case PLDM_EFFECTER_DATA_SIZE_UINT32: 179 | return pldm__msgbuf_extract_uint32( 180 | ctx, ((char *)ed) + offsetof(union_effecter_data_size, 181 | value_u32)); 182 | case PLDM_EFFECTER_DATA_SIZE_SINT32: 183 | return pldm__msgbuf_extract_int32( 184 | ctx, ((char *)ed) + offsetof(union_effecter_data_size, 185 | value_s32)); 186 | } 187 | 188 | return -PLDM_ERROR_INVALID_DATA; 189 | } 190 | 191 | #ifdef __cplusplus 192 | #include 193 | 194 | template 195 | static inline int pldm_msgbuf_typecheck_range_field_format( 196 | struct pldm_msgbuf *ctx, enum pldm_range_field_format tag, void *_rff) 197 | { 198 | static_assert(std::is_same::value); 199 | return pldm__msgbuf_extract_range_field_format(ctx, tag, _rff); 200 | } 201 | #endif 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /src/oem/ibm/host.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | LIBPLDM_ABI_STABLE 10 | int encode_get_alert_status_req(uint8_t instance_id, uint8_t version_id, 11 | struct pldm_msg *msg, size_t payload_length) 12 | { 13 | if (msg == NULL) { 14 | return PLDM_ERROR_INVALID_LENGTH; 15 | } 16 | 17 | if (payload_length != PLDM_GET_ALERT_STATUS_REQ_BYTES) { 18 | return PLDM_ERROR_INVALID_LENGTH; 19 | } 20 | 21 | struct pldm_header_info header = { 0 }; 22 | header.msg_type = PLDM_REQUEST; 23 | header.instance = instance_id; 24 | header.pldm_type = PLDM_OEM; 25 | header.command = PLDM_HOST_GET_ALERT_STATUS; 26 | uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 27 | if (rc != PLDM_SUCCESS) { 28 | return rc; 29 | } 30 | 31 | msg->payload[0] = version_id; 32 | 33 | return PLDM_SUCCESS; 34 | } 35 | 36 | LIBPLDM_ABI_STABLE 37 | int decode_get_alert_status_resp(const struct pldm_msg *msg, 38 | size_t payload_length, 39 | uint8_t *completion_code, uint32_t *rack_entry, 40 | uint32_t *pri_cec_node) 41 | { 42 | if (msg == NULL || completion_code == NULL || rack_entry == NULL || 43 | pri_cec_node == NULL) { 44 | return PLDM_ERROR_INVALID_DATA; 45 | } 46 | 47 | *completion_code = msg->payload[0]; 48 | if (PLDM_SUCCESS != *completion_code) { 49 | return PLDM_SUCCESS; 50 | } 51 | 52 | if (payload_length != PLDM_GET_ALERT_STATUS_RESP_BYTES) { 53 | return PLDM_ERROR_INVALID_LENGTH; 54 | } 55 | 56 | struct pldm_get_alert_status_resp *response = 57 | (struct pldm_get_alert_status_resp *)msg->payload; 58 | 59 | *rack_entry = le32toh(response->rack_entry); 60 | *pri_cec_node = le32toh(response->pri_cec_node); 61 | 62 | return PLDM_SUCCESS; 63 | } 64 | 65 | LIBPLDM_ABI_STABLE 66 | int decode_get_alert_status_req(const struct pldm_msg *msg, 67 | size_t payload_length, uint8_t *version_id) 68 | { 69 | if (msg == NULL || version_id == NULL) { 70 | return PLDM_ERROR_INVALID_DATA; 71 | } 72 | 73 | if (payload_length != PLDM_GET_ALERT_STATUS_REQ_BYTES) { 74 | return PLDM_ERROR_INVALID_LENGTH; 75 | } 76 | 77 | *version_id = msg->payload[0]; 78 | 79 | return PLDM_SUCCESS; 80 | } 81 | 82 | LIBPLDM_ABI_STABLE 83 | int encode_get_alert_status_resp(uint8_t instance_id, uint8_t completion_code, 84 | uint32_t rack_entry, uint32_t pri_cec_node, 85 | struct pldm_msg *msg, size_t payload_length) 86 | { 87 | if (msg == NULL) { 88 | return PLDM_ERROR_INVALID_LENGTH; 89 | } 90 | 91 | if (payload_length != PLDM_GET_ALERT_STATUS_RESP_BYTES) { 92 | return PLDM_ERROR_INVALID_DATA; 93 | } 94 | 95 | struct pldm_header_info header = { 0 }; 96 | header.msg_type = PLDM_RESPONSE; 97 | header.instance = instance_id; 98 | header.pldm_type = PLDM_OEM; 99 | header.command = PLDM_HOST_GET_ALERT_STATUS; 100 | uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 101 | if (rc != PLDM_SUCCESS) { 102 | return rc; 103 | } 104 | 105 | struct pldm_get_alert_status_resp *response = 106 | (struct pldm_get_alert_status_resp *)msg->payload; 107 | 108 | response->completion_code = completion_code; 109 | response->rack_entry = htole32(rack_entry); 110 | response->pri_cec_node = htole32(pri_cec_node); 111 | 112 | return PLDM_SUCCESS; 113 | } 114 | -------------------------------------------------------------------------------- /src/oem/ibm/meson.build: -------------------------------------------------------------------------------- 1 | libpldm_sources += files('file_io.c', 'host.c', 'platform.c') 2 | -------------------------------------------------------------------------------- /src/oem/ibm/platform.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | LIBPLDM_ABI_STABLE 9 | int encode_bios_attribute_update_event_req(uint8_t instance_id, 10 | uint8_t format_version, uint8_t tid, 11 | uint8_t num_handles, 12 | const uint8_t *list_of_handles, 13 | size_t payload_length, 14 | struct pldm_msg *msg) 15 | { 16 | if (format_version != 1) { 17 | return PLDM_ERROR_INVALID_DATA; 18 | } 19 | 20 | if (msg == NULL || list_of_handles == NULL) { 21 | return PLDM_ERROR_INVALID_DATA; 22 | } 23 | 24 | if (num_handles == 0) { 25 | return PLDM_ERROR_INVALID_DATA; 26 | } 27 | 28 | if (SIZE_MAX / num_handles < sizeof(uint16_t)) { 29 | return PLDM_ERROR_INVALID_LENGTH; 30 | } 31 | 32 | if (payload_length < 33 | PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + sizeof(num_handles)) { 34 | return PLDM_ERROR_INVALID_LENGTH; 35 | } 36 | 37 | if (payload_length - (PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + 38 | sizeof(num_handles)) < 39 | num_handles * sizeof(uint16_t)) { 40 | return PLDM_ERROR_INVALID_LENGTH; 41 | } 42 | 43 | struct pldm_header_info header = { 0 }; 44 | header.msg_type = PLDM_REQUEST; 45 | header.instance = instance_id; 46 | header.pldm_type = PLDM_PLATFORM; 47 | header.command = PLDM_PLATFORM_EVENT_MESSAGE; 48 | uint8_t rc = pack_pldm_header(&header, &(msg->hdr)); 49 | if (rc != PLDM_SUCCESS) { 50 | return rc; 51 | } 52 | 53 | struct pldm_bios_attribute_update_event_req *request = 54 | (struct pldm_bios_attribute_update_event_req *)msg->payload; 55 | request->format_version = format_version; 56 | request->tid = tid; 57 | request->event_class = PLDM_EVENT_TYPE_OEM_EVENT_BIOS_ATTRIBUTE_UPDATE; 58 | request->num_handles = num_handles; 59 | memcpy(request->bios_attribute_handles, list_of_handles, 60 | num_handles * sizeof(uint16_t)); 61 | 62 | return PLDM_SUCCESS; 63 | } 64 | -------------------------------------------------------------------------------- /src/oem/meta/file_io.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "api.h" 9 | #include "msgbuf.h" 10 | #include "dsp/base.h" 11 | 12 | LIBPLDM_ABI_STABLE 13 | void *pldm_oem_meta_file_io_write_req_data( 14 | struct pldm_oem_meta_file_io_write_req *req) 15 | { 16 | return req->data; 17 | } 18 | 19 | LIBPLDM_ABI_STABLE 20 | int decode_oem_meta_file_io_write_req( 21 | const struct pldm_msg *msg, size_t payload_length, 22 | struct pldm_oem_meta_file_io_write_req *req, size_t req_length) 23 | { 24 | PLDM_MSGBUF_DEFINE_P(buf); 25 | int rc; 26 | 27 | if (msg == NULL || req == NULL) { 28 | return -EINVAL; 29 | } 30 | 31 | if (req_length < sizeof(*req)) { 32 | return -EINVAL; 33 | } 34 | 35 | rc = pldm_msgbuf_init_errno(buf, 36 | PLDM_OEM_META_FILE_IO_WRITE_REQ_MIN_LENGTH, 37 | msg->payload, payload_length); 38 | if (rc) { 39 | return rc; 40 | } 41 | 42 | pldm_msgbuf_extract(buf, req->handle); 43 | rc = pldm_msgbuf_extract(buf, req->length); 44 | if (rc) { 45 | return pldm_msgbuf_discard(buf, rc); 46 | } 47 | 48 | rc = pldm_msgbuf_extract_array(buf, req->length, req->data, 49 | req_length - sizeof(*req)); 50 | if (rc) { 51 | return pldm_msgbuf_discard(buf, rc); 52 | } 53 | 54 | return pldm_msgbuf_complete_consumed(buf); 55 | } 56 | 57 | LIBPLDM_ABI_DEPRECATED_UNSAFE 58 | int decode_oem_meta_file_io_req(const struct pldm_msg *msg, 59 | size_t payload_length, uint8_t *file_handle, 60 | uint32_t *length, uint8_t *data) 61 | { 62 | struct pldm_oem_meta_file_io_write_req *request_msg; 63 | size_t request_msg_len; 64 | int rc; 65 | 66 | if (msg == NULL || file_handle == NULL || length == NULL || 67 | data == NULL) { 68 | return pldm_xlate_errno(-EINVAL); 69 | } 70 | 71 | if (SIZE_MAX - sizeof(*request_msg) < payload_length) { 72 | return pldm_xlate_errno(-EOVERFLOW); 73 | } 74 | 75 | request_msg_len = sizeof(*request_msg) + payload_length; 76 | request_msg = malloc(request_msg_len); 77 | 78 | rc = decode_oem_meta_file_io_write_req(msg, payload_length, request_msg, 79 | request_msg_len); 80 | if (rc < 0) { 81 | free(request_msg); 82 | return pldm_xlate_errno(rc); 83 | } 84 | 85 | *file_handle = request_msg->handle; 86 | *length = request_msg->length; 87 | 88 | /* NOTE: Unsafe, memory safety is not possible due to API constraints. */ 89 | memcpy(data, request_msg->data, request_msg->length); 90 | 91 | free(request_msg); 92 | 93 | return 0; 94 | } 95 | 96 | LIBPLDM_ABI_STABLE 97 | int decode_oem_meta_file_io_read_req(const struct pldm_msg *msg, 98 | size_t payload_length, 99 | struct pldm_oem_meta_file_io_read_req *req) 100 | { 101 | PLDM_MSGBUF_DEFINE_P(buf); 102 | 103 | if (msg == NULL || req == NULL) { 104 | return -EINVAL; 105 | } 106 | 107 | if (req->version > sizeof(struct pldm_oem_meta_file_io_read_req)) { 108 | return -E2BIG; 109 | } 110 | 111 | int rc = pldm_msgbuf_init_errno( 112 | buf, PLDM_OEM_META_FILE_IO_READ_REQ_MIN_LENGTH, msg->payload, 113 | payload_length); 114 | if (rc) { 115 | return rc; 116 | } 117 | 118 | pldm_msgbuf_extract(buf, req->handle); 119 | rc = pldm_msgbuf_extract(buf, req->option); 120 | if (rc) { 121 | return pldm_msgbuf_discard(buf, rc); 122 | } 123 | 124 | rc = pldm_msgbuf_extract(buf, req->length); 125 | if (rc) { 126 | return pldm_msgbuf_discard(buf, rc); 127 | } 128 | 129 | switch (req->option) { 130 | case PLDM_OEM_META_FILE_IO_READ_ATTR: 131 | if (req->length != 0) { 132 | return pldm_msgbuf_discard(buf, -EPROTO); 133 | } 134 | break; 135 | case PLDM_OEM_META_FILE_IO_READ_DATA: 136 | pldm_msgbuf_extract(buf, req->info.data.transferFlag); 137 | pldm_msgbuf_extract(buf, req->info.data.offset); 138 | break; 139 | default: 140 | return pldm_msgbuf_discard(buf, -EPROTO); 141 | } 142 | 143 | return pldm_msgbuf_complete_consumed(buf); 144 | } 145 | 146 | LIBPLDM_ABI_STABLE 147 | void *pldm_oem_meta_file_io_read_resp_data( 148 | struct pldm_oem_meta_file_io_read_resp *resp) 149 | { 150 | return resp->data; 151 | } 152 | 153 | LIBPLDM_ABI_STABLE 154 | int encode_oem_meta_file_io_read_resp( 155 | uint8_t instance_id, struct pldm_oem_meta_file_io_read_resp *resp, 156 | size_t resp_len, struct pldm_msg *responseMsg, size_t payload_length) 157 | { 158 | int rc; 159 | PLDM_MSGBUF_DEFINE_P(buf); 160 | struct pldm_header_info header = { 0 }; 161 | 162 | if (resp == NULL || responseMsg == NULL) { 163 | return -EINVAL; 164 | } 165 | 166 | if (resp_len < sizeof(*resp)) { 167 | return -EINVAL; 168 | } 169 | 170 | if (resp->version > sizeof(*resp)) { 171 | return -E2BIG; 172 | } 173 | 174 | header.instance = instance_id; 175 | header.msg_type = PLDM_RESPONSE; 176 | header.pldm_type = PLDM_OEM; 177 | header.command = PLDM_OEM_META_FILE_IO_CMD_READ_FILE; 178 | rc = pack_pldm_header_errno(&header, &(responseMsg->hdr)); 179 | if (rc) { 180 | return rc; 181 | } 182 | 183 | rc = pldm_msgbuf_init_errno(buf, 184 | PLDM_OEM_META_FILE_IO_READ_RESP_MIN_SIZE, 185 | responseMsg->payload, payload_length); 186 | if (rc) { 187 | return rc; 188 | } 189 | 190 | pldm_msgbuf_insert(buf, resp->completion_code); 191 | pldm_msgbuf_insert(buf, resp->handle); 192 | pldm_msgbuf_insert(buf, resp->option); 193 | pldm_msgbuf_insert(buf, resp->length); 194 | 195 | switch (resp->option) { 196 | case PLDM_OEM_META_FILE_IO_READ_ATTR: 197 | pldm_msgbuf_insert(buf, resp->info.attr.size); 198 | pldm_msgbuf_insert(buf, resp->info.attr.crc32); 199 | break; 200 | case PLDM_OEM_META_FILE_IO_READ_DATA: 201 | pldm_msgbuf_insert(buf, resp->info.data.transferFlag); 202 | pldm_msgbuf_insert(buf, resp->info.data.offset); 203 | rc = pldm_msgbuf_insert_array_uint8(buf, resp->length, 204 | resp->data, 205 | resp_len - sizeof(*resp)); 206 | if (rc) { 207 | return pldm_msgbuf_discard(buf, rc); 208 | } 209 | break; 210 | default: 211 | return pldm_msgbuf_discard(buf, -EPROTO); 212 | } 213 | 214 | return pldm_msgbuf_complete(buf); 215 | } 216 | -------------------------------------------------------------------------------- /src/oem/meta/meson.build: -------------------------------------------------------------------------------- 1 | libpldm_sources += files('file_io.c') 2 | -------------------------------------------------------------------------------- /src/requester/instance-id.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define BIT(i) (1UL << (i)) 13 | 14 | #define PLDM_TID_MAX 256 15 | #define PLDM_INST_ID_MAX 32 16 | 17 | /* We need to track our allocations explicitly due to OFD lock merging/splitting 18 | */ 19 | struct pldm_tid_state { 20 | pldm_instance_id_t prev; 21 | uint32_t allocations; 22 | }; 23 | 24 | struct pldm_instance_db { 25 | struct pldm_tid_state state[PLDM_TID_MAX]; 26 | int lock_db_fd; 27 | }; 28 | 29 | static inline int iid_next(pldm_instance_id_t cur) 30 | { 31 | return (cur + 1) % PLDM_INST_ID_MAX; 32 | } 33 | 34 | LIBPLDM_ABI_STABLE 35 | int pldm_instance_db_init(struct pldm_instance_db **ctx, const char *dbpath) 36 | { 37 | struct pldm_instance_db *l_ctx; 38 | struct stat statbuf; 39 | int rc; 40 | 41 | /* Make sure the provided pointer was initialised to NULL. In the future 42 | * if we stabilise the ABI and expose the struct definition the caller 43 | * can potentially pass a valid pointer to a struct they've allocated 44 | */ 45 | if (!ctx || *ctx) { 46 | return -EINVAL; 47 | } 48 | 49 | /* Ensure the underlying file is sized for properly managing allocations 50 | */ 51 | rc = stat(dbpath, &statbuf); 52 | if (rc < 0) { 53 | return -EINVAL; 54 | } 55 | 56 | if (statbuf.st_size < 57 | ((off_t)(PLDM_TID_MAX) * (off_t)(PLDM_INST_ID_MAX))) { 58 | return -EINVAL; 59 | } 60 | 61 | l_ctx = calloc(1, sizeof(struct pldm_instance_db)); 62 | if (!l_ctx) { 63 | return -ENOMEM; 64 | } 65 | 66 | /* Initialise previous ID values so the next one is zero */ 67 | for (int i = 0; i < PLDM_TID_MAX; i++) { 68 | l_ctx->state[i].prev = 31; 69 | } 70 | 71 | /* Lock database may be read-only, either by permissions or mountpoint 72 | */ 73 | l_ctx->lock_db_fd = open(dbpath, O_RDONLY | O_CLOEXEC); 74 | if (l_ctx->lock_db_fd < 0) { 75 | free(l_ctx); 76 | return -errno; 77 | } 78 | *ctx = l_ctx; 79 | 80 | return 0; 81 | } 82 | 83 | LIBPLDM_ABI_STABLE 84 | int pldm_instance_db_init_default(struct pldm_instance_db **ctx) 85 | { 86 | return pldm_instance_db_init(ctx, 87 | "/usr/share/libpldm/instance-db/default"); 88 | } 89 | 90 | LIBPLDM_ABI_STABLE 91 | int pldm_instance_db_destroy(struct pldm_instance_db *ctx) 92 | { 93 | if (!ctx) { 94 | return 0; 95 | } 96 | close(ctx->lock_db_fd); 97 | free(ctx); 98 | return 0; 99 | } 100 | 101 | static const struct flock pldm_instance_id_cfls = { 102 | .l_type = F_RDLCK, 103 | .l_whence = SEEK_SET, 104 | .l_len = 1, 105 | }; 106 | 107 | static const struct flock pldm_instance_id_cflx = { 108 | .l_type = F_WRLCK, 109 | .l_whence = SEEK_SET, 110 | .l_len = 1, 111 | }; 112 | 113 | static const struct flock pldm_instance_id_cflu = { 114 | .l_type = F_UNLCK, 115 | .l_whence = SEEK_SET, 116 | .l_len = 1, 117 | }; 118 | 119 | LIBPLDM_ABI_STABLE 120 | int pldm_instance_id_alloc(struct pldm_instance_db *ctx, pldm_tid_t tid, 121 | pldm_instance_id_t *iid) 122 | { 123 | uint8_t l_iid; 124 | 125 | if (!ctx || !iid) { 126 | return -EINVAL; 127 | } 128 | 129 | l_iid = ctx->state[tid].prev; 130 | if (l_iid >= PLDM_INST_ID_MAX) { 131 | return -EPROTO; 132 | } 133 | 134 | while ((l_iid = iid_next(l_iid)) != ctx->state[tid].prev) { 135 | struct flock flop; 136 | off_t loff; 137 | int rc; 138 | 139 | /* Have we already allocated this instance ID? */ 140 | if (ctx->state[tid].allocations & BIT(l_iid)) { 141 | continue; 142 | } 143 | 144 | /* Derive the instance ID offset in the lock database */ 145 | loff = tid * PLDM_INST_ID_MAX + l_iid; 146 | 147 | /* Reserving the TID's IID. Done via a shared lock */ 148 | flop = pldm_instance_id_cfls; 149 | flop.l_start = loff; 150 | rc = fcntl(ctx->lock_db_fd, F_OFD_SETLK, &flop); 151 | if (rc < 0) { 152 | if (errno == EAGAIN || errno == EINTR) { 153 | return -EAGAIN; 154 | } 155 | return -EPROTO; 156 | } 157 | 158 | /* 159 | * If we *may* promote the lock to exclusive then this IID is 160 | * only reserved by us. This is now our allocated IID. 161 | * 162 | * If we *may not* promote the lock to exclusive then this IID 163 | * is also reserved on another file descriptor. Move on to the 164 | * next IID index. 165 | * 166 | * Note that we cannot actually *perform* the promotion in 167 | * practice because this is prevented by the lock database being 168 | * opened O_RDONLY. 169 | */ 170 | flop = pldm_instance_id_cflx; 171 | flop.l_start = loff; 172 | rc = fcntl(ctx->lock_db_fd, F_OFD_GETLK, &flop); 173 | if (rc < 0) { 174 | if (errno == EAGAIN || errno == EINTR) { 175 | rc = -EAGAIN; 176 | goto release_cfls; 177 | } 178 | rc = -EPROTO; 179 | goto release_cfls; 180 | } 181 | 182 | /* F_UNLCK is the type of the lock if we could successfully 183 | * promote it to F_WRLCK */ 184 | if (flop.l_type == F_UNLCK) { 185 | ctx->state[tid].prev = l_iid; 186 | ctx->state[tid].allocations |= BIT(l_iid); 187 | *iid = l_iid; 188 | return 0; 189 | } 190 | 191 | if (flop.l_type != F_RDLCK) { 192 | rc = -EPROTO; 193 | } 194 | 195 | release_cfls: 196 | flop = pldm_instance_id_cflu; 197 | flop.l_start = loff; 198 | if (fcntl(ctx->lock_db_fd, F_OFD_SETLK, &flop) < 0) { 199 | if (errno == EAGAIN || errno == EINTR) { 200 | return -EAGAIN; 201 | } 202 | return -EPROTO; 203 | } 204 | 205 | if (rc < 0) { 206 | return rc; 207 | } 208 | } 209 | 210 | /* Failed to allocate an IID after a full loop. Make the caller try 211 | * again */ 212 | return -EAGAIN; 213 | } 214 | 215 | LIBPLDM_ABI_STABLE 216 | int pldm_instance_id_free(struct pldm_instance_db *ctx, pldm_tid_t tid, 217 | pldm_instance_id_t iid) 218 | { 219 | struct flock flop; 220 | int rc; 221 | 222 | /* check if provided context is null */ 223 | if (!ctx) { 224 | return -EINVAL; 225 | } 226 | 227 | /* Trying to free an instance ID that is not currently allocated */ 228 | if (!(ctx->state[tid].allocations & BIT(iid))) { 229 | return -EINVAL; 230 | } 231 | 232 | flop = pldm_instance_id_cflu; 233 | flop.l_start = tid * PLDM_INST_ID_MAX + iid; 234 | rc = fcntl(ctx->lock_db_fd, F_OFD_SETLK, &flop); 235 | if (rc < 0) { 236 | if (errno == EAGAIN || errno == EINTR) { 237 | return -EAGAIN; 238 | } 239 | return -EPROTO; 240 | } 241 | 242 | /* Mark the instance ID as no-longer allocated */ 243 | ctx->state[tid].allocations &= ~BIT(iid); 244 | 245 | return 0; 246 | } 247 | -------------------------------------------------------------------------------- /src/requester/meson.build: -------------------------------------------------------------------------------- 1 | libpldm_sources += files('instance-id.c') 2 | -------------------------------------------------------------------------------- /src/responder.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #include "responder.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | static bool pldm_responder_cookie_eq(const struct pldm_responder_cookie *left, 10 | const struct pldm_responder_cookie *right) 11 | { 12 | return left->tid == right->tid && 13 | left->instance_id == right->instance_id && 14 | left->type == right->type && left->command == right->command; 15 | } 16 | 17 | int pldm_responder_cookie_track(struct pldm_responder_cookie *jar, 18 | struct pldm_responder_cookie *cookie) 19 | { 20 | struct pldm_responder_cookie *current; 21 | struct pldm_responder_cookie *next; 22 | 23 | if (!jar || !cookie) { 24 | return PLDM_REQUESTER_INVALID_SETUP; 25 | } 26 | 27 | current = jar; 28 | next = current->next; 29 | while (next) { 30 | /* Cookie must not already be known */ 31 | if (pldm_responder_cookie_eq(next, cookie)) { 32 | return PLDM_REQUESTER_INVALID_SETUP; 33 | } 34 | current = next; 35 | next = next->next; 36 | } 37 | 38 | cookie->next = NULL; 39 | current->next = cookie; 40 | 41 | return PLDM_REQUESTER_SUCCESS; 42 | } 43 | 44 | struct pldm_responder_cookie * 45 | pldm_responder_cookie_untrack(struct pldm_responder_cookie *jar, pldm_tid_t tid, 46 | pldm_instance_id_t instance_id, uint8_t type, 47 | uint8_t command) 48 | { 49 | const struct pldm_responder_cookie cookie = { tid, instance_id, type, 50 | command, NULL }; 51 | struct pldm_responder_cookie *current; 52 | struct pldm_responder_cookie *next; 53 | 54 | if (!jar) { 55 | return NULL; 56 | } 57 | 58 | current = jar; 59 | next = current->next; 60 | while (next && !pldm_responder_cookie_eq(next, &cookie)) { 61 | current = next; 62 | next = next->next; 63 | } 64 | 65 | if (next) { 66 | current->next = next->next; 67 | } 68 | 69 | return next; 70 | } 71 | -------------------------------------------------------------------------------- /src/responder.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_SRC_RESPONDER_H 3 | #define LIBPLDM_SRC_RESPONDER_H 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | struct pldm_responder_cookie { 11 | pldm_tid_t tid; 12 | pldm_instance_id_t instance_id; 13 | uint8_t type; 14 | uint8_t command; 15 | struct pldm_responder_cookie *next; 16 | }; 17 | 18 | int pldm_responder_cookie_track(struct pldm_responder_cookie *jar, 19 | struct pldm_responder_cookie *cookie); 20 | 21 | struct pldm_responder_cookie * 22 | pldm_responder_cookie_untrack(struct pldm_responder_cookie *jar, pldm_tid_t tid, 23 | pldm_instance_id_t instance_id, uint8_t type, 24 | uint8_t command); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/transport/container-of.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef CONTAINER_OF_H 3 | #define CONTAINER_OF_H 4 | 5 | #ifndef container_of 6 | #define container_of(ptr, type, member) \ 7 | (type *)((char *)(ptr) - offsetof(type, member)) 8 | #endif 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/transport/mctp-demux.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #include "compiler.h" 3 | #include "container-of.h" 4 | #include "mctp-defines.h" 5 | #include "socket.h" 6 | #include "transport.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #define MCTP_DEMUX_NAME "libmctp-demux-daemon" 24 | const uint8_t mctp_msg_type = MCTP_MSG_TYPE_PLDM; 25 | 26 | struct pldm_transport_mctp_demux { 27 | struct pldm_transport transport; 28 | int socket; 29 | /* In the future this probably needs to move to a tid-eid-uuid/network 30 | * id mapping for multi mctp networks */ 31 | pldm_tid_t tid_eid_map[MCTP_MAX_NUM_EID]; 32 | struct pldm_socket_sndbuf socket_send_buf; 33 | }; 34 | 35 | #define transport_to_demux(ptr) \ 36 | container_of(ptr, struct pldm_transport_mctp_demux, transport) 37 | 38 | LIBPLDM_ABI_STABLE 39 | struct pldm_transport * 40 | pldm_transport_mctp_demux_core(struct pldm_transport_mctp_demux *ctx) 41 | { 42 | return &ctx->transport; 43 | } 44 | 45 | static pldm_requester_rc_t pldm_transport_mctp_demux_open(void) 46 | { 47 | int fd = -1; 48 | ssize_t rc = -1; 49 | 50 | fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 51 | if (fd == -1) { 52 | return fd; 53 | } 54 | 55 | const char path[] = "\0mctp-mux"; 56 | struct sockaddr_un addr; 57 | addr.sun_family = AF_UNIX; 58 | memcpy(addr.sun_path, path, sizeof(path) - 1); 59 | rc = connect(fd, (struct sockaddr *)&addr, 60 | sizeof(path) + sizeof(addr.sun_family) - 1); 61 | if (rc == -1) { 62 | return PLDM_REQUESTER_OPEN_FAIL; 63 | } 64 | rc = write(fd, &mctp_msg_type, sizeof(mctp_msg_type)); 65 | if (rc == -1) { 66 | return PLDM_REQUESTER_OPEN_FAIL; 67 | } 68 | 69 | return fd; 70 | } 71 | 72 | LIBPLDM_ABI_STABLE 73 | int pldm_transport_mctp_demux_init_pollfd(struct pldm_transport *t, 74 | struct pollfd *pollfd) 75 | { 76 | struct pldm_transport_mctp_demux *ctx = transport_to_demux(t); 77 | pollfd->fd = ctx->socket; 78 | pollfd->events = POLLIN; 79 | return 0; 80 | } 81 | 82 | static int 83 | pldm_transport_mctp_demux_get_eid(struct pldm_transport_mctp_demux *ctx, 84 | pldm_tid_t tid, mctp_eid_t *eid) 85 | { 86 | int i; 87 | for (i = 0; i < MCTP_MAX_NUM_EID; i++) { 88 | if (ctx->tid_eid_map[i] == tid) { 89 | *eid = i; 90 | return 0; 91 | } 92 | } 93 | *eid = -1; 94 | return -1; 95 | } 96 | 97 | static int 98 | pldm_transport_mctp_demux_get_tid(struct pldm_transport_mctp_demux *ctx, 99 | mctp_eid_t eid, pldm_tid_t *tid) 100 | { 101 | /* mapping exists */ 102 | if (ctx->tid_eid_map[eid] != 0) { 103 | *tid = ctx->tid_eid_map[eid]; 104 | return 0; 105 | } 106 | return -1; 107 | } 108 | 109 | LIBPLDM_ABI_STABLE 110 | int pldm_transport_mctp_demux_map_tid(struct pldm_transport_mctp_demux *ctx, 111 | pldm_tid_t tid, mctp_eid_t eid) 112 | { 113 | ctx->tid_eid_map[eid] = tid; 114 | 115 | return 0; 116 | } 117 | 118 | LIBPLDM_ABI_STABLE 119 | int pldm_transport_mctp_demux_unmap_tid(struct pldm_transport_mctp_demux *ctx, 120 | LIBPLDM_CC_UNUSED pldm_tid_t tid, 121 | mctp_eid_t eid) 122 | { 123 | ctx->tid_eid_map[eid] = 0; 124 | 125 | return 0; 126 | } 127 | 128 | static pldm_requester_rc_t 129 | pldm_transport_mctp_demux_recv(struct pldm_transport *t, pldm_tid_t *tid, 130 | void **pldm_msg, size_t *msg_len) 131 | { 132 | struct pldm_transport_mctp_demux *demux = transport_to_demux(t); 133 | size_t mctp_prefix_len = 2; 134 | struct msghdr msg = { 0 }; 135 | pldm_requester_rc_t res; 136 | uint8_t mctp_prefix[2]; 137 | struct iovec iov[2]; 138 | mctp_eid_t eid = 0; 139 | ssize_t min_len; 140 | size_t pldm_len; 141 | ssize_t length; 142 | ssize_t bytes; 143 | uint8_t *buf; 144 | int rc; 145 | 146 | min_len = sizeof(eid) + sizeof(mctp_msg_type) + 147 | sizeof(struct pldm_msg_hdr); 148 | length = recv(demux->socket, NULL, 0, MSG_PEEK | MSG_TRUNC); 149 | if (length <= 0) { 150 | return PLDM_REQUESTER_RECV_FAIL; 151 | } 152 | 153 | buf = malloc(length); 154 | if (buf == NULL) { 155 | return PLDM_REQUESTER_RECV_FAIL; 156 | } 157 | 158 | if (length < min_len) { 159 | /* read and discard */ 160 | recv(demux->socket, buf, length, 0); 161 | res = PLDM_REQUESTER_INVALID_RECV_LEN; 162 | goto cleanup_buf; 163 | } 164 | 165 | pldm_len = length - mctp_prefix_len; 166 | iov[0].iov_len = mctp_prefix_len; 167 | iov[0].iov_base = mctp_prefix; 168 | iov[1].iov_len = pldm_len; 169 | iov[1].iov_base = buf; 170 | 171 | msg.msg_iov = iov; 172 | msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]); 173 | 174 | bytes = recvmsg(demux->socket, &msg, 0); 175 | if (length != bytes) { 176 | res = PLDM_REQUESTER_INVALID_RECV_LEN; 177 | goto cleanup_buf; 178 | } 179 | 180 | if (mctp_prefix[1] != mctp_msg_type) { 181 | res = PLDM_REQUESTER_NOT_PLDM_MSG; 182 | goto cleanup_buf; 183 | } 184 | 185 | eid = mctp_prefix[0]; 186 | rc = pldm_transport_mctp_demux_get_tid(demux, eid, tid); 187 | if (rc) { 188 | res = PLDM_REQUESTER_RECV_FAIL; 189 | goto cleanup_buf; 190 | } 191 | 192 | *pldm_msg = buf; 193 | *msg_len = pldm_len; 194 | 195 | return PLDM_REQUESTER_SUCCESS; 196 | 197 | cleanup_buf: 198 | free(buf); 199 | 200 | return res; 201 | } 202 | 203 | static pldm_requester_rc_t 204 | pldm_transport_mctp_demux_send(struct pldm_transport *t, pldm_tid_t tid, 205 | const void *pldm_msg, size_t msg_len) 206 | { 207 | struct pldm_transport_mctp_demux *demux = transport_to_demux(t); 208 | mctp_eid_t eid = 0; 209 | if (pldm_transport_mctp_demux_get_eid(demux, tid, &eid)) { 210 | return PLDM_REQUESTER_SEND_FAIL; 211 | } 212 | 213 | uint8_t hdr[2] = { eid, mctp_msg_type }; 214 | 215 | struct iovec iov[2]; 216 | iov[0].iov_base = hdr; 217 | iov[0].iov_len = sizeof(hdr); 218 | iov[1].iov_base = (uint8_t *)pldm_msg; 219 | iov[1].iov_len = msg_len; 220 | 221 | struct msghdr msg = { 0 }; 222 | msg.msg_iov = iov; 223 | msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]); 224 | 225 | if (msg_len > INT_MAX || 226 | pldm_socket_sndbuf_accomodate(&(demux->socket_send_buf), 227 | (int)msg_len)) { 228 | return PLDM_REQUESTER_SEND_FAIL; 229 | } 230 | 231 | ssize_t rc = sendmsg(demux->socket, &msg, 0); 232 | if (rc == -1) { 233 | return PLDM_REQUESTER_SEND_FAIL; 234 | } 235 | return PLDM_REQUESTER_SUCCESS; 236 | } 237 | 238 | LIBPLDM_ABI_STABLE 239 | int pldm_transport_mctp_demux_init(struct pldm_transport_mctp_demux **ctx) 240 | { 241 | if (!ctx || *ctx) { 242 | return -EINVAL; 243 | } 244 | 245 | struct pldm_transport_mctp_demux *demux = 246 | calloc(1, sizeof(struct pldm_transport_mctp_demux)); 247 | if (!demux) { 248 | return -ENOMEM; 249 | } 250 | 251 | demux->transport.name = MCTP_DEMUX_NAME; 252 | demux->transport.version = 1; 253 | demux->transport.recv = pldm_transport_mctp_demux_recv; 254 | demux->transport.send = pldm_transport_mctp_demux_send; 255 | demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd; 256 | demux->socket = pldm_transport_mctp_demux_open(); 257 | if (demux->socket == -1) { 258 | free(demux); 259 | return -1; 260 | } 261 | 262 | if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) { 263 | close(demux->socket); 264 | free(demux); 265 | return -1; 266 | } 267 | 268 | *ctx = demux; 269 | return 0; 270 | } 271 | 272 | LIBPLDM_ABI_STABLE 273 | void pldm_transport_mctp_demux_destroy(struct pldm_transport_mctp_demux *ctx) 274 | { 275 | if (!ctx) { 276 | return; 277 | } 278 | close(ctx->socket); 279 | free(ctx); 280 | } 281 | 282 | /* Temporary for old API */ 283 | struct pldm_transport_mctp_demux * 284 | pldm_transport_mctp_demux_init_with_fd(int mctp_fd) 285 | { 286 | struct pldm_transport_mctp_demux *demux = 287 | calloc(1, sizeof(struct pldm_transport_mctp_demux)); 288 | if (!demux) { 289 | return NULL; 290 | } 291 | 292 | demux->transport.name = MCTP_DEMUX_NAME; 293 | demux->transport.version = 1; 294 | demux->transport.recv = pldm_transport_mctp_demux_recv; 295 | demux->transport.send = pldm_transport_mctp_demux_send; 296 | demux->transport.init_pollfd = pldm_transport_mctp_demux_init_pollfd; 297 | /* dup is so we can call pldm_transport_mctp_demux_destroy which closes 298 | * the socket, without closing the fd that is being used by the consumer 299 | */ 300 | demux->socket = dup(mctp_fd); 301 | if (demux->socket == -1) { 302 | free(demux); 303 | return NULL; 304 | } 305 | 306 | if (pldm_socket_sndbuf_init(&demux->socket_send_buf, demux->socket)) { 307 | close(demux->socket); 308 | free(demux); 309 | return NULL; 310 | } 311 | 312 | return demux; 313 | } 314 | 315 | int pldm_transport_mctp_demux_get_socket_fd( 316 | struct pldm_transport_mctp_demux *ctx) 317 | { 318 | if (ctx) { 319 | return ctx->socket; 320 | } 321 | 322 | return -1; 323 | } 324 | -------------------------------------------------------------------------------- /src/transport/meson.build: -------------------------------------------------------------------------------- 1 | libpldm_sources += files('af-mctp.c', 'mctp-demux.c', 'socket.c', 'test.c' 2 | , 'transport.c') 3 | -------------------------------------------------------------------------------- /src/transport/socket.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #include "socket.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int pldm_socket_sndbuf_init(struct pldm_socket_sndbuf *ctx, int socket) 12 | { 13 | FILE *fp; 14 | long max_buf_size; 15 | char line[128]; 16 | char *endptr; 17 | 18 | if (socket == -1) { 19 | return -1; 20 | } 21 | ctx->socket = socket; 22 | 23 | fp = fopen("/proc/sys/net/core/wmem_max", "r"); 24 | if (fp == NULL) { 25 | return -1; 26 | } 27 | 28 | if (fgets(line, sizeof(line), fp) == NULL) { 29 | fclose(fp); 30 | return -1; 31 | } 32 | 33 | errno = 0; 34 | max_buf_size = strtol(line, &endptr, 10); 35 | if (errno != 0 || endptr == line) { 36 | fclose(fp); 37 | return -1; 38 | } 39 | 40 | fclose(fp); 41 | 42 | if (max_buf_size > INT_MAX) { 43 | max_buf_size = INT_MAX; 44 | } 45 | ctx->max_size = (int)max_buf_size; 46 | 47 | if (pldm_socket_sndbuf_get(ctx)) { 48 | return -1; 49 | } 50 | 51 | return 0; 52 | } 53 | 54 | int pldm_socket_sndbuf_accomodate(struct pldm_socket_sndbuf *ctx, int msg_len) 55 | { 56 | if (msg_len < ctx->size) { 57 | return 0; 58 | } 59 | /* If message is bigger than the max size, don't return a failure. Set 60 | * the buffer to the max size and see what happens. We don't know how 61 | * much of the extra space the kernel actually uses so let it tell us if 62 | * there wasn't enough space */ 63 | if (msg_len > ctx->max_size) { 64 | msg_len = ctx->max_size; 65 | } 66 | if (ctx->size == ctx->max_size) { 67 | return 0; 68 | } 69 | int rc = setsockopt(ctx->socket, SOL_SOCKET, SO_SNDBUF, &(msg_len), 70 | sizeof(msg_len)); 71 | if (rc == -1) { 72 | return -1; 73 | } 74 | ctx->size = msg_len; 75 | return 0; 76 | } 77 | 78 | int pldm_socket_sndbuf_get(struct pldm_socket_sndbuf *ctx) 79 | { 80 | /* size returned by getsockopt is the actual size of the buffer - twice 81 | * the size of the value used by setsockopt. So for consistency, return 82 | * half of the buffer size */ 83 | int buf_size; 84 | socklen_t optlen = sizeof(buf_size); 85 | int rc = getsockopt(ctx->socket, SOL_SOCKET, SO_SNDBUF, &(buf_size), 86 | &optlen); 87 | if (rc == -1) { 88 | return -1; 89 | } 90 | ctx->size = buf_size / 2; 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /src/transport/socket.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_SRC_TRANSPORT_SOCKET_H 3 | #define LIBPLDM_SRC_TRANSPORT_SOCKET_H 4 | 5 | struct pldm_socket_sndbuf { 6 | int size; 7 | int socket; 8 | int max_size; 9 | }; 10 | 11 | int pldm_socket_sndbuf_init(struct pldm_socket_sndbuf *ctx, int socket); 12 | int pldm_socket_sndbuf_accomodate(struct pldm_socket_sndbuf *ctx, int msg_len); 13 | int pldm_socket_sndbuf_get(struct pldm_socket_sndbuf *ctx); 14 | 15 | #endif // LIBPLDM_SRC_TRANSPORT_SOCKET_H 16 | -------------------------------------------------------------------------------- /src/transport/test.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | /* NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */ 3 | #include "array.h" 4 | #include "container-of.h" 5 | #include "transport.h" 6 | #include "test.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | struct pldm_transport_test { 15 | struct pldm_transport transport; 16 | const struct pldm_transport_test_descriptor *seq; 17 | size_t count; 18 | size_t cursor; 19 | int timerfd; 20 | }; 21 | 22 | #define transport_to_test(ptr) \ 23 | container_of(ptr, struct pldm_transport_test, transport) 24 | 25 | LIBPLDM_ABI_TESTING 26 | struct pldm_transport *pldm_transport_test_core(struct pldm_transport_test *ctx) 27 | { 28 | return &ctx->transport; 29 | } 30 | 31 | #ifdef PLDM_HAS_POLL 32 | #include 33 | LIBPLDM_ABI_TESTING 34 | int pldm_transport_test_init_pollfd(struct pldm_transport *ctx, 35 | struct pollfd *pollfd) 36 | { 37 | static const struct itimerspec disable = { 38 | .it_value = { 0, 0 }, 39 | .it_interval = { 0, 0 }, 40 | }; 41 | struct pldm_transport_test *test = transport_to_test(ctx); 42 | const struct pldm_transport_test_descriptor *desc; 43 | int rc; 44 | 45 | rc = timerfd_settime(test->timerfd, 0, &disable, NULL); 46 | if (rc < 0) { 47 | return PLDM_REQUESTER_POLL_FAIL; 48 | } 49 | 50 | if (test->cursor >= test->count) { 51 | return PLDM_REQUESTER_POLL_FAIL; 52 | } 53 | 54 | desc = &test->seq[test->cursor]; 55 | 56 | if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_LATENCY) { 57 | rc = timerfd_settime(test->timerfd, 0, &desc->latency, NULL); 58 | if (rc < 0) { 59 | return PLDM_REQUESTER_POLL_FAIL; 60 | } 61 | 62 | /* This was an explicit latency element, so now move beyond it for recv */ 63 | test->cursor++; 64 | } else if (desc->type == PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) { 65 | /* Expire the timer immediately so it appears ready */ 66 | static const struct timespec ensure_ready = { 67 | .tv_sec = 0, 68 | .tv_nsec = 2, 69 | }; 70 | static const struct itimerspec ready = { 71 | .it_value = { 0, 1 }, 72 | .it_interval = { 0, 0 }, 73 | }; 74 | struct pollfd pfds[] = { 75 | { .fd = test->timerfd, .events = POLLIN }, 76 | }; 77 | 78 | rc = timerfd_settime(test->timerfd, 0, &ready, NULL); 79 | if (rc < 0) { 80 | return PLDM_REQUESTER_POLL_FAIL; 81 | } 82 | 83 | rc = ppoll(pfds, ARRAY_SIZE(pfds), &ensure_ready, NULL); 84 | if (rc < 1) { 85 | return PLDM_REQUESTER_POLL_FAIL; 86 | } 87 | 88 | /* Don't increment test->cursor as recv needs to consume the current test element */ 89 | } else { 90 | return PLDM_REQUESTER_POLL_FAIL; 91 | } 92 | 93 | pollfd->fd = test->timerfd; 94 | pollfd->events = POLLIN; 95 | 96 | return 0; 97 | } 98 | #endif 99 | 100 | static pldm_requester_rc_t pldm_transport_test_recv(struct pldm_transport *ctx, 101 | pldm_tid_t *tid, 102 | void **pldm_resp_msg, 103 | size_t *resp_msg_len) 104 | { 105 | struct pldm_transport_test *test = transport_to_test(ctx); 106 | const struct pldm_transport_test_descriptor *desc; 107 | void *msg; 108 | 109 | if (test->cursor >= test->count) { 110 | return PLDM_REQUESTER_RECV_FAIL; 111 | } 112 | 113 | desc = &test->seq[test->cursor]; 114 | 115 | if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV) { 116 | return PLDM_REQUESTER_RECV_FAIL; 117 | } 118 | 119 | msg = malloc(desc->recv_msg.len); 120 | if (!msg) { 121 | return PLDM_REQUESTER_RECV_FAIL; 122 | } 123 | 124 | memcpy(msg, desc->recv_msg.msg, desc->recv_msg.len); 125 | *pldm_resp_msg = msg; 126 | *resp_msg_len = desc->recv_msg.len; 127 | *tid = desc->recv_msg.src; 128 | 129 | test->cursor++; 130 | 131 | return PLDM_REQUESTER_SUCCESS; 132 | } 133 | 134 | static pldm_requester_rc_t pldm_transport_test_send(struct pldm_transport *ctx, 135 | pldm_tid_t tid, 136 | const void *pldm_req_msg, 137 | size_t req_msg_len) 138 | { 139 | struct pldm_transport_test *test = transport_to_test(ctx); 140 | const struct pldm_transport_test_descriptor *desc; 141 | 142 | if (test->cursor > test->count) { 143 | return PLDM_REQUESTER_SEND_FAIL; 144 | } 145 | 146 | desc = &test->seq[test->cursor]; 147 | 148 | if (desc->type != PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND) { 149 | return PLDM_REQUESTER_SEND_FAIL; 150 | } 151 | 152 | if (desc->send_msg.dst != tid) { 153 | return PLDM_REQUESTER_SEND_FAIL; 154 | } 155 | 156 | if (desc->send_msg.len != req_msg_len) { 157 | return PLDM_REQUESTER_SEND_FAIL; 158 | } 159 | 160 | if (memcmp(desc->send_msg.msg, pldm_req_msg, req_msg_len) != 0) { 161 | return PLDM_REQUESTER_SEND_FAIL; 162 | } 163 | 164 | test->cursor++; 165 | 166 | return PLDM_REQUESTER_SUCCESS; 167 | } 168 | 169 | LIBPLDM_ABI_TESTING 170 | int pldm_transport_test_init(struct pldm_transport_test **ctx, 171 | const struct pldm_transport_test_descriptor *seq, 172 | size_t count) 173 | { 174 | int rc; 175 | 176 | if (!ctx || *ctx) { 177 | return -EINVAL; 178 | } 179 | 180 | struct pldm_transport_test *test = malloc(sizeof(*test)); 181 | if (!test) { 182 | return -ENOMEM; 183 | } 184 | 185 | test->transport.name = "TEST"; 186 | test->transport.version = 1; 187 | test->transport.recv = pldm_transport_test_recv; 188 | test->transport.send = pldm_transport_test_send; 189 | test->transport.init_pollfd = pldm_transport_test_init_pollfd; 190 | test->seq = seq; 191 | test->count = count; 192 | test->cursor = 0; 193 | test->timerfd = timerfd_create(CLOCK_MONOTONIC, 0); 194 | if (test->timerfd < 0) { 195 | rc = -errno; 196 | goto cleanup_test; 197 | } 198 | 199 | *ctx = test; 200 | 201 | return 0; 202 | 203 | cleanup_test: 204 | free(test); 205 | return rc; 206 | } 207 | 208 | LIBPLDM_ABI_TESTING 209 | void pldm_transport_test_destroy(struct pldm_transport_test *ctx) 210 | { 211 | close(ctx->timerfd); 212 | free(ctx); 213 | } 214 | -------------------------------------------------------------------------------- /src/transport/test.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_TRANSPORT_TEST_H 3 | #define LIBPLDM_TRANSPORT_TEST_H 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | enum pldm_transport_test_element { 16 | PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND, 17 | PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 18 | PLDM_TRANSPORT_TEST_ELEMENT_LATENCY, 19 | }; 20 | 21 | struct pldm_transport_test_msg_send { 22 | pldm_tid_t dst; 23 | const void *msg; 24 | size_t len; 25 | }; 26 | 27 | struct pldm_transport_test_msg_recv { 28 | pldm_tid_t src; 29 | const void *msg; 30 | size_t len; 31 | }; 32 | 33 | struct pldm_transport_test_descriptor { 34 | enum pldm_transport_test_element type; 35 | union { 36 | struct pldm_transport_test_msg_send send_msg; 37 | struct pldm_transport_test_msg_recv recv_msg; 38 | struct itimerspec latency; 39 | }; 40 | }; 41 | 42 | struct pldm_transport_test; 43 | 44 | int pldm_transport_test_init(struct pldm_transport_test **ctx, 45 | const struct pldm_transport_test_descriptor *seq, 46 | size_t count); 47 | void pldm_transport_test_destroy(struct pldm_transport_test *ctx); 48 | struct pldm_transport * 49 | pldm_transport_test_core(struct pldm_transport_test *ctx); 50 | 51 | #if PLDM_HAS_POLL 52 | struct pollfd; 53 | int pldm_transport_test_init_pollfd(struct pldm_transport *ctx, 54 | struct pollfd *pollfd); 55 | #endif 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/transport/transport.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #include "compiler.h" 3 | #include "transport.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #ifdef PLDM_HAS_POLL 12 | #include 13 | #endif 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef PLDM_HAS_POLL 21 | struct pollfd { 22 | int fd; /* file descriptor */ 23 | short events; /* requested events */ 24 | short revents; /* returned events */ 25 | }; 26 | 27 | static inline int poll(struct pollfd *fds LIBPLDM_CC_UNUSED, 28 | int nfds LIBPLDM_CC_UNUSED, 29 | int timeout LIBPLDM_CC_UNUSED) 30 | { 31 | return 0; 32 | } 33 | #endif 34 | 35 | LIBPLDM_ABI_STABLE 36 | int pldm_transport_poll(struct pldm_transport *transport, int timeout) 37 | { 38 | struct pollfd pollfd; 39 | int rc = 0; 40 | if (!transport) { 41 | return PLDM_REQUESTER_INVALID_SETUP; 42 | } 43 | 44 | /* If polling isn't supported then always indicate the transport is ready */ 45 | if (!transport->init_pollfd) { 46 | return 1; 47 | } 48 | 49 | rc = transport->init_pollfd(transport, &pollfd); 50 | if (rc < 0) { 51 | return PLDM_REQUESTER_POLL_FAIL; 52 | } 53 | 54 | rc = poll(&pollfd, 1, timeout); 55 | if (rc < 0) { 56 | return PLDM_REQUESTER_POLL_FAIL; 57 | } 58 | 59 | /* rc is 0 if poll(2) times out, or 1 if pollfd becomes active. */ 60 | return rc; 61 | } 62 | 63 | LIBPLDM_ABI_STABLE 64 | pldm_requester_rc_t pldm_transport_send_msg(struct pldm_transport *transport, 65 | pldm_tid_t tid, 66 | const void *pldm_msg, 67 | size_t msg_len) 68 | { 69 | if (!transport || !pldm_msg) { 70 | return PLDM_REQUESTER_INVALID_SETUP; 71 | } 72 | 73 | if (msg_len < sizeof(struct pldm_msg_hdr)) { 74 | return PLDM_REQUESTER_NOT_REQ_MSG; 75 | } 76 | 77 | return transport->send(transport, tid, pldm_msg, msg_len); 78 | } 79 | 80 | LIBPLDM_ABI_STABLE 81 | pldm_requester_rc_t pldm_transport_recv_msg(struct pldm_transport *transport, 82 | pldm_tid_t *tid, void **pldm_msg, 83 | size_t *msg_len) 84 | { 85 | if (!transport || !msg_len) { 86 | return PLDM_REQUESTER_INVALID_SETUP; 87 | } 88 | 89 | pldm_requester_rc_t rc = 90 | transport->recv(transport, tid, pldm_msg, msg_len); 91 | if (rc != PLDM_REQUESTER_SUCCESS) { 92 | return rc; 93 | } 94 | 95 | if (*msg_len < sizeof(struct pldm_msg_hdr)) { 96 | free(*pldm_msg); 97 | *pldm_msg = NULL; 98 | return PLDM_REQUESTER_INVALID_RECV_LEN; 99 | } 100 | return PLDM_REQUESTER_SUCCESS; 101 | } 102 | 103 | static void timespec_to_timeval(const struct timespec *ts, struct timeval *tv) 104 | { 105 | tv->tv_sec = ts->tv_sec; 106 | tv->tv_usec = ts->tv_nsec / 1000; 107 | } 108 | 109 | /* Overflow safety must be upheld before call */ 110 | static long timeval_to_msec(const struct timeval *tv) 111 | { 112 | return tv->tv_sec * 1000 + tv->tv_usec / 1000; 113 | } 114 | 115 | /* If calculations on `tv` don't overflow then operations on derived 116 | * intervals can't either. 117 | */ 118 | static bool timeval_is_valid(const struct timeval *tv) 119 | { 120 | if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) { 121 | return false; 122 | } 123 | 124 | if (tv->tv_sec > (LONG_MAX - tv->tv_usec / 1000) / 1000) { 125 | return false; 126 | } 127 | 128 | return true; 129 | } 130 | 131 | static int clock_gettimeval(clockid_t clockid, struct timeval *tv) 132 | { 133 | struct timespec now; 134 | int rc; 135 | 136 | rc = clock_gettime(clockid, &now); 137 | if (rc < 0) { 138 | return rc; 139 | } 140 | 141 | timespec_to_timeval(&now, tv); 142 | 143 | return 0; 144 | } 145 | 146 | LIBPLDM_ABI_STABLE 147 | pldm_requester_rc_t 148 | pldm_transport_send_recv_msg(struct pldm_transport *transport, pldm_tid_t tid, 149 | const void *pldm_req_msg, size_t req_msg_len, 150 | void **pldm_resp_msg, size_t *resp_msg_len) 151 | 152 | { 153 | /** 154 | * Section "Requirements for requesters" in DSP0240, define the Time-out 155 | * waiting for a response of the requester. 156 | * PT2max = PT3min - 2*PT4max = 4800ms 157 | */ 158 | static const struct timeval max_response_interval = { 159 | .tv_sec = 4, .tv_usec = 800000 160 | }; 161 | const struct pldm_msg_hdr *req_hdr; 162 | struct timeval remaining; 163 | pldm_requester_rc_t rc; 164 | struct timeval now; 165 | struct timeval end; 166 | int ret; 167 | int cnt; 168 | 169 | if (req_msg_len < sizeof(*req_hdr) || !resp_msg_len) { 170 | return PLDM_REQUESTER_INVALID_SETUP; 171 | } 172 | 173 | req_hdr = pldm_req_msg; 174 | 175 | if (!req_hdr->request) { 176 | return PLDM_REQUESTER_NOT_REQ_MSG; 177 | } 178 | 179 | for (cnt = 0; cnt <= (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS && 180 | pldm_transport_poll(transport, 0) == 1; 181 | cnt++) { 182 | pldm_tid_t l_tid; 183 | rc = pldm_transport_recv_msg(transport, &l_tid, pldm_resp_msg, 184 | resp_msg_len); 185 | if (rc == PLDM_REQUESTER_SUCCESS) { 186 | /* This isn't the message we wanted */ 187 | free(*pldm_resp_msg); 188 | } 189 | } 190 | if (cnt == (PLDM_INSTANCE_MAX + 1) * PLDM_MAX_TIDS) { 191 | return PLDM_REQUESTER_TRANSPORT_BUSY; 192 | } 193 | 194 | rc = pldm_transport_send_msg(transport, tid, pldm_req_msg, req_msg_len); 195 | if (rc != PLDM_REQUESTER_SUCCESS) { 196 | return rc; 197 | } 198 | 199 | ret = clock_gettimeval(CLOCK_MONOTONIC, &now); 200 | if (ret < 0) { 201 | return PLDM_REQUESTER_POLL_FAIL; 202 | } 203 | 204 | timeradd(&now, &max_response_interval, &end); 205 | if (!timeval_is_valid(&end)) { 206 | return PLDM_REQUESTER_POLL_FAIL; 207 | } 208 | 209 | while (timercmp(&now, &end, <)) { 210 | pldm_tid_t src_tid; 211 | 212 | timersub(&end, &now, &remaining); 213 | 214 | /* 0 <= `timeval_to_msec()` <= 4800, and 4800 < INT_MAX */ 215 | ret = pldm_transport_poll(transport, 216 | (int)(timeval_to_msec(&remaining))); 217 | if (ret <= 0) { 218 | return PLDM_REQUESTER_RECV_FAIL; 219 | } 220 | 221 | ret = clock_gettimeval(CLOCK_MONOTONIC, &now); 222 | if (ret < 0) { 223 | return PLDM_REQUESTER_POLL_FAIL; 224 | } 225 | 226 | rc = pldm_transport_recv_msg(transport, &src_tid, pldm_resp_msg, 227 | resp_msg_len); 228 | if (rc != PLDM_REQUESTER_SUCCESS) { 229 | continue; 230 | } 231 | 232 | if (src_tid != tid || !pldm_msg_hdr_correlate_response( 233 | pldm_req_msg, *pldm_resp_msg)) { 234 | free(*pldm_resp_msg); 235 | continue; 236 | } 237 | 238 | return PLDM_REQUESTER_SUCCESS; 239 | } 240 | 241 | return PLDM_REQUESTER_RECV_FAIL; 242 | } 243 | -------------------------------------------------------------------------------- /src/transport/transport.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | #ifndef LIBPLDM_SRC_TRANSPORT_TRANSPORT_H 3 | #define LIBPLDM_SRC_TRANSPORT_TRANSPORT_H 4 | 5 | #include 6 | #include 7 | struct pollfd; 8 | 9 | /** 10 | * @brief Generic PLDM transport struct 11 | * 12 | * @var name - name of the transport 13 | * @var version - version of transport to use 14 | * @var recv - pointer to the transport specific function to receive a message 15 | * @var send - pointer to the transport specific function to send a message 16 | * @var init_pollfd - pointer to the transport specific init_pollfd function 17 | */ 18 | struct pldm_transport { 19 | const char *name; 20 | uint8_t version; 21 | pldm_requester_rc_t (*recv)(struct pldm_transport *transport, 22 | pldm_tid_t *tid, void **pldm_resp_msg, 23 | size_t *msg_len); 24 | pldm_requester_rc_t (*send)(struct pldm_transport *transport, 25 | pldm_tid_t tid, const void *pldm_msg, 26 | size_t msg_len); 27 | int (*init_pollfd)(struct pldm_transport *transport, 28 | struct pollfd *pollfd); 29 | }; 30 | 31 | #endif // LIBPLDM_SRC_TRANSPORT_TRANSPORT_H 32 | -------------------------------------------------------------------------------- /subprojects/googletest.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/google/googletest 3 | revision = HEAD 4 | -------------------------------------------------------------------------------- /tests/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlinesLeft: false 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: None 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: true 25 | AfterControlStatement: true 26 | AfterEnum: true 27 | AfterFunction: true 28 | AfterNamespace: true 29 | AfterObjCDeclaration: true 30 | AfterStruct: true 31 | AfterUnion: true 32 | BeforeCatch: true 33 | BeforeElse: true 34 | IndentBraces: false 35 | BreakBeforeBinaryOperators: None 36 | BreakBeforeBraces: Custom 37 | BreakBeforeTernaryOperators: true 38 | BreakConstructorInitializers: AfterColon 39 | ColumnLimit: 80 40 | CommentPragmas: '^ IWYU pragma:' 41 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 42 | ConstructorInitializerIndentWidth: 4 43 | ContinuationIndentWidth: 4 44 | Cpp11BracedListStyle: true 45 | DerivePointerAlignment: false 46 | PointerAlignment: Left 47 | DisableFormat: false 48 | ExperimentalAutoDetectBinPacking: false 49 | FixNamespaceComments: true 50 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 51 | IncludeBlocks: Regroup 52 | IncludeCategories: 53 | - Regex: '^[<"](gtest|gmock)' 54 | Priority: 5 55 | - Regex: '^"config.h"' 56 | Priority: -1 57 | - Regex: '^".*\.hpp"' 58 | Priority: 1 59 | - Regex: '^<.*\.h>' 60 | Priority: 2 61 | - Regex: '^<.*' 62 | Priority: 3 63 | - Regex: '.*' 64 | Priority: 4 65 | IndentCaseLabels: true 66 | IndentWidth: 4 67 | IndentWrappedFunctionNames: true 68 | KeepEmptyLinesAtTheStartOfBlocks: true 69 | MacroBlockBegin: '' 70 | MacroBlockEnd: '' 71 | MaxEmptyLinesToKeep: 1 72 | NamespaceIndentation: None 73 | ObjCBlockIndentWidth: 2 74 | ObjCSpaceAfterProperty: false 75 | ObjCSpaceBeforeProtocolList: true 76 | PenaltyBreakBeforeFirstCallParameter: 19 77 | PenaltyBreakComment: 300 78 | PenaltyBreakFirstLessLess: 120 79 | PenaltyBreakString: 1000 80 | PenaltyExcessCharacter: 1000000 81 | PenaltyReturnTypeOnItsOwnLine: 60 82 | ReflowComments: true 83 | SortIncludes: true 84 | SortUsingDeclarations: true 85 | SpaceAfterCStyleCast: false 86 | SpaceBeforeAssignmentOperators: true 87 | SpaceBeforeParens: ControlStatements 88 | SpaceInEmptyParentheses: false 89 | SpacesBeforeTrailingComments: 1 90 | SpacesInAngles: false 91 | SpacesInContainerLiterals: true 92 | SpacesInCStyleCastParentheses: false 93 | SpacesInParentheses: false 94 | SpacesInSquareBrackets: false 95 | Standard: Cpp11 96 | TabWidth: 4 97 | UseTab: Never 98 | ... 99 | -------------------------------------------------------------------------------- /tests/dsp/bios_table_iter.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 | /* Force elision of assert() */ 3 | #ifndef NDEBUG 4 | #define NDEBUG 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "compiler.h" 13 | 14 | /* NOLINTNEXTLINE(bugprone-suspicious-include) */ 15 | #include "dsp/bios_table.c" 16 | 17 | /* Satisfy the symbol needs of bios_table.c */ 18 | uint32_t pldm_edac_crc32(const void* data LIBPLDM_CC_UNUSED, 19 | size_t size LIBPLDM_CC_UNUSED) 20 | { 21 | return 0; 22 | } 23 | 24 | /* This is the non-death version of TEST(Iterator, DeathTest) */ 25 | int main(void) 26 | { 27 | struct pldm_bios_attr_table_entry entries[2] = {0}; 28 | struct pldm_bios_table_iter* iter; 29 | int result; 30 | 31 | static_assert(2 * sizeof(entries[0]) == sizeof(entries), ""); 32 | 33 | entries[0].attr_type = PLDM_BIOS_PASSWORD; 34 | entries[1].attr_type = PLDM_BIOS_STRING_READ_ONLY; 35 | 36 | iter = pldm_bios_table_iter_create(entries, sizeof(entries), 37 | PLDM_BIOS_ATTR_TABLE); 38 | 39 | /* 40 | * We expect the test configuration to claim the iterator has reached the 41 | * end because the there's no entry length descriptor for the 42 | * PLDM_BIOS_PASSWORD entry type. By the attr_able_entry_length() 43 | * implementation this would normally trigger an assert() to uphold that the 44 | * necessary pointers are not NULL. However, we've defined NDEBUG above and 45 | * so the assert() is elided. That should force us down the path of the 46 | * early-exit, which should in-turn yield a `true` result from 47 | * pldm_bios_table_iter_is_end() to prevent further attempts to access 48 | * invalid objects. 49 | */ 50 | result = pldm_bios_table_iter_is_end(iter) ? EXIT_SUCCESS : EXIT_FAILURE; 51 | 52 | pldm_bios_table_iter_free(iter); 53 | 54 | exit(result); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /tests/dsp/meson.build: -------------------------------------------------------------------------------- 1 | tests += [ 2 | 'dsp/base', 3 | 'dsp/bios_table', 4 | 'dsp/bios', 5 | 'dsp/file', 6 | 'dsp/firmware_update', 7 | 'dsp/fru', 8 | 'dsp/pdr', 9 | 'dsp/platform', 10 | ] 11 | 12 | test( 13 | 'dsp/bios_table_iter', 14 | executable( 15 | 'bios_table_iter', 16 | 'bios_table_iter.c', 17 | implicit_include_directories: false, 18 | include_directories: test_include_dirs, 19 | ), 20 | ) 21 | -------------------------------------------------------------------------------- /tests/fuzz/fd-fuzz-input1.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openbmc/libpldm/06eadd0ee95508b49124d0dbaa221eb6fea445f1/tests/fuzz/fd-fuzz-input1.dat -------------------------------------------------------------------------------- /tests/fuzz/fd.dict: -------------------------------------------------------------------------------- 1 | FIXED_DESCRIPTORS="\x01\x00\x04\x00\xcf\xc2\x00\x00" 2 | 3 | # request update cmd 0x10. identifier "1" 4 | request_update="\x0f\x00\x00\x00\x80\x05\x10\x00\x04\x00\x00\x01\x00\x01\x00\x00\x01\x01\x31" 5 | 6 | # pass component table 7 | # Length 16 prefix. 8 | # startandend=0x05, classification=7, identifier=123 (0x7b), index = 9 9 | pass_comp="\x10\x00\x00\x00\x80\x05\x13\x05\x07\x00\x7b\x00\x09\xff\xff\xff\xff\x01\x01Z" 10 | # mostly 0x00 for details 11 | pass_comp_00="\x10\x00\x00\x00\x80\x05\x13\x05\x00\x00\x00\x00\x00\xff\xff\xff\xff\x01\x01Z" 12 | 13 | # Update Component. Similar to pass_comp at the start 14 | # set size of 0x810 bytes (2064 bytes) 15 | update_comp="\x17\x00\x00\x00\x80\x05\x14\x07\x00\x7b\x00\x09\xff\xff\xff\xff\x10\x08\x00\x00\x00\x00\x00\x00\x01\x01Z" 16 | update_comp_00="\x17\x00\x00\x00\x80\x05\x14\x00\x00\x00\x00\x00\xff\xff\xff\xff\x10\x08\x00\x00\x00\x00\x00\x00\x01\x01Z" 17 | 18 | 19 | "zzz" 20 | "fnnn" 21 | "1234" 22 | "1235" 23 | -------------------------------------------------------------------------------- /tests/fuzz/fuzz-build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 3 | 4 | # Builds fuzzing variants. Run this from the toplevel directory. 5 | # Beware this will wipe build directories. 6 | 7 | # Requires honggfuzz and afl++ installed 8 | 9 | # Builds are: 10 | # * AFL (normal, asan, cmplog) 11 | # * honggfuzz 12 | # * -O0, with coverage 13 | 14 | import os 15 | import subprocess 16 | 17 | # reduce warning level since tests since gtest is noisy 18 | BASE_MESONFLAGS = "-Dwarning_level=2 -Ddefault_library=static --wipe".split() 19 | FUZZ_PROGRAMS = ["tests/fuzz/fd-fuzz"] 20 | 21 | 22 | def build( 23 | build_dir: str, 24 | cc: str = None, 25 | cxx: str = None, 26 | cflags="", 27 | cxxflags="", 28 | opt="3", 29 | env={}, 30 | mesonflags=[], 31 | ): 32 | env = os.environ | env 33 | env["CFLAGS"] = cflags 34 | env["CXXFLAGS"] = cxxflags 35 | 36 | # Meson sets CC="ccache cc" by default, but ccache removes -fprofile-arcs 37 | # so coverage breaks (ccache #1531). Prevent that by setting CC/CXX. 38 | env["CC"] = cc if cc else "cc" 39 | env["CXX"] = cxx if cxx else "c++" 40 | 41 | meson_cmd = ["meson"] + BASE_MESONFLAGS + mesonflags 42 | meson_cmd += [f"-Doptimization={opt}"] 43 | meson_cmd += [build_dir] 44 | subprocess.run(meson_cmd, env=env, check=True) 45 | 46 | ninja_cmd = ["ninja", "-C", build_dir] + FUZZ_PROGRAMS 47 | subprocess.run(ninja_cmd, env=env, check=True) 48 | 49 | 50 | def build_afl(): 51 | env = { 52 | # seems to be required for afl-clang-lto? 53 | "AFL_REAL_LD": "ld.lld", 54 | } 55 | cc = "afl-clang-lto" 56 | cxx = "afl-clang-lto++" 57 | 58 | # normal 59 | build("bfuzz", cc=cc, cxx=cxx, env=env) 60 | # ASAN 61 | build( 62 | "bfuzzasan", 63 | cc=cc, 64 | cxx=cxx, 65 | mesonflags=["-Db_sanitize=address"], 66 | env=env, 67 | ) 68 | # cmplog 69 | build("bcmplog", cc=cc, cxx=cxx, env={"AFL_LLVM_CMPLOG": "1"} | env) 70 | 71 | 72 | def main(): 73 | # No profiling, has coverage 74 | build( 75 | "bnoopt", 76 | cflags="-fprofile-abs-path", 77 | cxxflags="-fprofile-abs-path", 78 | opt="0", 79 | mesonflags=["-Db_coverage=true"], 80 | ) 81 | 82 | # AFL 83 | build_afl() 84 | 85 | # Honggfuzz 86 | build("bhf", cc="hfuzz-clang", cxx="hfuzz-clang++") 87 | 88 | 89 | if __name__ == "__main__": 90 | main() 91 | -------------------------------------------------------------------------------- /tests/fuzz/fuzz-coverage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 3 | 4 | # usage: fuzz-coverage.py [-h] corpus program srcdir builddir outdir 5 | 6 | # Runs corpus (directory of testcases) against a program 7 | # built with coverage, and produces a html report. 8 | 9 | # The program should be built with --coverage -fprofile-abs-path 10 | # -O0 may make the html report more legible? 11 | 12 | # Requires lcov and https://github.com/mozilla/grcov 13 | 14 | import argparse 15 | import subprocess 16 | import sys 17 | from pathlib import Path 18 | 19 | 20 | def run(args): 21 | corpus = Path(args.corpus) 22 | outdir = Path(args.outdir) 23 | 24 | for c in Path(args.builddir).glob("**/*.gcda"): 25 | print(f"Removed old coverage {c}", file=sys.stderr) 26 | c.unlink() 27 | 28 | print("Running corpus", file=sys.stderr) 29 | for c in corpus.glob("*"): 30 | c = c.open("rb").read() 31 | subprocess.run([args.program], input=c) 32 | 33 | print("Running grcov", file=sys.stderr) 34 | outdir.mkdir(parents=True, exist_ok=True) 35 | coverage_paths = [args.builddir] 36 | lcov_file = outdir / "lcov.info" 37 | 38 | subprocess.run( 39 | [ 40 | "grcov", 41 | "-b", 42 | args.program, 43 | "-o", 44 | lcov_file, 45 | "-t", 46 | "lcov", 47 | "-s", 48 | args.srcdir, 49 | ] 50 | + coverage_paths, 51 | check=True, 52 | ) 53 | 54 | print("Running genhtml", file=sys.stderr) 55 | subprocess.run( 56 | [ 57 | "genhtml", 58 | "-o", 59 | outdir, 60 | "--show-details", 61 | "--highlight", 62 | "--ignore-errors", 63 | "source", 64 | "--legend", 65 | lcov_file, 66 | ], 67 | check=True, 68 | ) 69 | 70 | html = outdir / "index.html" 71 | print(f"\n\nOutput is file://{html.absolute()}", file=sys.stderr) 72 | 73 | 74 | def main(): 75 | parser = argparse.ArgumentParser() 76 | parser.add_argument("corpus", type=str, help="Corpus directory") 77 | parser.add_argument("program", type=str, help="Target Program") 78 | parser.add_argument("srcdir", type=str, help="Source directory") 79 | parser.add_argument("builddir", type=str) 80 | parser.add_argument("outdir", type=str) 81 | args = parser.parse_args() 82 | 83 | run(args) 84 | 85 | 86 | if __name__ == "__main__": 87 | main() 88 | -------------------------------------------------------------------------------- /tests/fuzz/meson.build: -------------------------------------------------------------------------------- 1 | executable( 2 | 'fd-fuzz', 3 | 'fd-fuzz.cpp', 4 | # for __AFL_LOOP 5 | cpp_args: ['-Wno-gnu-statement-expression-from-macro-expansion'], 6 | include_directories: test_include_dirs, 7 | dependencies: [libpldm_dep], 8 | ) 9 | -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | gtest_dep = dependency('gtest', main: true, disabler: true, required: false) 2 | gmock_dep = dependency('gmock', disabler: true, required: false) 3 | if not gtest_dep.found() or not gmock_dep.found() 4 | gtest_proj = import('cmake').subproject('googletest', required: true) 5 | gtest_dep = declare_dependency( 6 | dependencies: [ 7 | dependency('threads'), 8 | gtest_proj.dependency('gtest'), 9 | gtest_proj.dependency('gtest_main'), 10 | ], 11 | ) 12 | gmock_dep = gtest_proj.dependency('gmock') 13 | endif 14 | 15 | test_include_dirs = [libpldm_include_dir, include_directories('../src')] 16 | 17 | tests = ['instance-id', 'msgbuf', 'responder', 'utils'] 18 | 19 | subdir('dsp') 20 | 21 | if get_option('abi').contains('testing') 22 | subdir('fuzz') 23 | endif 24 | 25 | # The 'test' transport APIs will never be marked stable as they are just for 26 | # testing. 27 | if get_option('abi').contains('testing') 28 | subdir('transport') 29 | endif 30 | 31 | if get_option('oem').contains('ibm') 32 | subdir('oem/ibm') 33 | endif 34 | 35 | if get_option('oem').contains('meta') 36 | subdir('oem/meta') 37 | endif 38 | 39 | foreach t : tests 40 | test( 41 | t, 42 | executable( 43 | t.underscorify(), 44 | t + '.cpp', 45 | implicit_include_directories: false, 46 | include_directories: test_include_dirs, 47 | dependencies: [libpldm_dep, gtest_dep, gmock_dep], 48 | ), 49 | workdir: meson.current_source_dir(), 50 | ) 51 | endforeach 52 | 53 | test( 54 | 'msgbuf_generic', 55 | executable( 56 | 'msgbuf_generic', 57 | 'msgbuf_generic.c', 58 | implicit_include_directories: false, 59 | include_directories: test_include_dirs, 60 | ), 61 | ) 62 | -------------------------------------------------------------------------------- /tests/oem/ibm/host.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | TEST(GetAlertStatus, testGoodEncodeRequest) 15 | { 16 | PLDM_MSG_DEFINE_P(request, PLDM_GET_ALERT_STATUS_REQ_BYTES); 17 | 18 | uint8_t versionId = 0x0; 19 | 20 | auto rc = encode_get_alert_status_req(0, versionId, request, 21 | PLDM_GET_ALERT_STATUS_REQ_BYTES); 22 | EXPECT_EQ(rc, PLDM_SUCCESS); 23 | EXPECT_EQ(versionId, request->payload[0]); 24 | } 25 | 26 | TEST(GetAlertStatus, testBadEncodeRequest) 27 | { 28 | PLDM_MSG_DEFINE_P(request, PLDM_GET_ALERT_STATUS_REQ_BYTES); 29 | auto rc = encode_get_alert_status_req(0, 0x0, request, 30 | PLDM_GET_ALERT_STATUS_REQ_BYTES + 1); 31 | EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH); 32 | } 33 | 34 | TEST(GetAlertStatus, testGoodDecodeResponse) 35 | { 36 | uint8_t completionCode = PLDM_SUCCESS; 37 | uint32_t rack_entry = 0xff000030; 38 | uint32_t pri_cec_node = 0x00008030; 39 | 40 | PLDM_MSG_DEFINE_P(response, PLDM_GET_ALERT_STATUS_RESP_BYTES); 41 | auto* resp = new (response->payload) pldm_get_alert_status_resp; 42 | resp->completion_code = completionCode; 43 | resp->rack_entry = htole32(rack_entry); 44 | resp->pri_cec_node = htole32(pri_cec_node); 45 | 46 | uint8_t retCompletionCode = 0; 47 | uint32_t retRack_entry = 0; 48 | uint32_t retPri_cec_node = 0; 49 | 50 | auto rc = decode_get_alert_status_resp( 51 | response, PLDM_GET_ALERT_STATUS_RESP_BYTES, &retCompletionCode, 52 | &retRack_entry, &retPri_cec_node); 53 | EXPECT_EQ(rc, PLDM_SUCCESS); 54 | EXPECT_EQ(retCompletionCode, completionCode); 55 | EXPECT_EQ(retRack_entry, rack_entry); 56 | EXPECT_EQ(retPri_cec_node, pri_cec_node); 57 | } 58 | 59 | TEST(GetAlertStatus, testBadDecodeResponse) 60 | { 61 | auto rc = decode_get_alert_status_resp(NULL, 0, NULL, NULL, NULL); 62 | EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA); 63 | 64 | uint8_t completionCode = PLDM_SUCCESS; 65 | uint32_t rack_entry = 0xff000030; 66 | uint32_t pri_cec_node = 0x00008030; 67 | 68 | PLDM_MSG_DEFINE_P(response, PLDM_GET_ALERT_STATUS_RESP_BYTES); 69 | auto* resp = new (response->payload) pldm_get_alert_status_resp; 70 | resp->completion_code = completionCode; 71 | resp->rack_entry = htole32(rack_entry); 72 | resp->pri_cec_node = htole32(pri_cec_node); 73 | 74 | uint8_t retCompletionCode = 0; 75 | uint32_t retRack_entry = 0; 76 | uint32_t retPri_cec_node = 0; 77 | 78 | rc = decode_get_alert_status_resp( 79 | response, PLDM_GET_ALERT_STATUS_RESP_BYTES + 1, &retCompletionCode, 80 | &retRack_entry, &retPri_cec_node); 81 | EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH); 82 | } 83 | 84 | TEST(GetAlertStatus, testGoodEncodeResponse) 85 | { 86 | uint32_t rack_entry = 0xff000030; 87 | uint32_t pri_cec_node = 0x00008030; 88 | 89 | PLDM_MSG_DEFINE_P(response, PLDM_GET_ALERT_STATUS_RESP_BYTES); 90 | 91 | auto rc = encode_get_alert_status_resp(0, PLDM_SUCCESS, rack_entry, 92 | pri_cec_node, response, 93 | PLDM_GET_ALERT_STATUS_RESP_BYTES); 94 | 95 | ASSERT_EQ(rc, PLDM_SUCCESS); 96 | EXPECT_THAT(response_buf, testing::ElementsAreArray( 97 | {0x00, 0x3f, 0xf0, 0x00, 0x30, 0x00, 0x00, 98 | 0xff, 0x30, 0x80, 0x00, 0x00})); 99 | } 100 | 101 | TEST(GetAlertStatus, testBadEncodeResponse) 102 | { 103 | uint32_t rack_entry = 0xff000030; 104 | uint32_t pri_cec_node = 0x00008030; 105 | 106 | PLDM_MSG_DEFINE_P(response, PLDM_GET_ALERT_STATUS_RESP_BYTES); 107 | 108 | auto rc = encode_get_alert_status_resp( 109 | 0, PLDM_SUCCESS, rack_entry, pri_cec_node, response, 110 | PLDM_GET_ALERT_STATUS_RESP_BYTES + 1); 111 | 112 | EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA); 113 | } 114 | 115 | TEST(GetAlertStatus, testGoodDecodeRequest) 116 | { 117 | uint8_t versionId = 0x0; 118 | uint8_t retVersionId; 119 | 120 | PLDM_MSG_DEFINE_P(req, PLDM_GET_ALERT_STATUS_REQ_BYTES); 121 | req->payload[0] = versionId; 122 | 123 | auto rc = decode_get_alert_status_req(req, PLDM_GET_ALERT_STATUS_REQ_BYTES, 124 | &retVersionId); 125 | 126 | EXPECT_EQ(rc, PLDM_SUCCESS); 127 | EXPECT_EQ(retVersionId, versionId); 128 | } 129 | 130 | TEST(GetAlertStatus, testBadDecodeRequest) 131 | { 132 | uint8_t versionId = 0x0; 133 | uint8_t retVersionId; 134 | 135 | PLDM_MSG_DEFINE_P(req, PLDM_GET_ALERT_STATUS_REQ_BYTES); 136 | req->payload[0] = versionId; 137 | 138 | auto rc = decode_get_alert_status_req( 139 | req, PLDM_GET_ALERT_STATUS_REQ_BYTES + 1, &retVersionId); 140 | 141 | EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH); 142 | } 143 | -------------------------------------------------------------------------------- /tests/oem/ibm/meson.build: -------------------------------------------------------------------------------- 1 | tests += ['oem/ibm/fileio', 'oem/ibm/host'] 2 | -------------------------------------------------------------------------------- /tests/oem/meta/meson.build: -------------------------------------------------------------------------------- 1 | tests += ['oem/meta/fileio'] 2 | -------------------------------------------------------------------------------- /tests/responder.cpp: -------------------------------------------------------------------------------- 1 | // NOLINTNEXTLINE(bugprone-suspicious-include) 2 | #include "responder.c" 3 | 4 | #include 5 | 6 | TEST(Responder, track_untrack_one) 7 | { 8 | struct pldm_responder_cookie jar{}; 9 | struct pldm_responder_cookie cookie = { 10 | .tid = 1, 11 | .instance_id = 1, 12 | .type = 0, 13 | .command = 0x01, /* SetTID */ 14 | .next = nullptr, 15 | }; 16 | 17 | ASSERT_EQ(pldm_responder_cookie_track(&jar, &cookie), 0); 18 | ASSERT_NE(jar.next, nullptr); 19 | ASSERT_EQ(pldm_responder_cookie_untrack(&jar, 1, 1, 0, 0x01), &cookie); 20 | ASSERT_EQ(jar.next, nullptr); 21 | } 22 | 23 | TEST(Responder, untrack_none) 24 | { 25 | struct pldm_responder_cookie jar{}; 26 | 27 | ASSERT_EQ(jar.next, nullptr); 28 | ASSERT_EQ(pldm_responder_cookie_untrack(&jar, 1, 1, 0, 0x01), nullptr); 29 | ASSERT_EQ(jar.next, nullptr); 30 | } 31 | 32 | TEST(Responder, track_one_untrack_bad) 33 | { 34 | struct pldm_responder_cookie jar{}; 35 | struct pldm_responder_cookie cookie = { 36 | .tid = 1, 37 | .instance_id = 1, 38 | .type = 0, 39 | .command = 0x01, /* SetTID */ 40 | .next = nullptr, 41 | }; 42 | 43 | ASSERT_EQ(pldm_responder_cookie_track(&jar, &cookie), 0); 44 | ASSERT_NE(jar.next, nullptr); 45 | ASSERT_EQ(pldm_responder_cookie_untrack(&jar, 2, 1, 0, 0x01), nullptr); 46 | ASSERT_EQ(pldm_responder_cookie_untrack(&jar, 1, 2, 0, 0x01), nullptr); 47 | ASSERT_EQ(pldm_responder_cookie_untrack(&jar, 1, 1, 1, 0x01), nullptr); 48 | ASSERT_EQ(pldm_responder_cookie_untrack(&jar, 1, 1, 0, 0x02), nullptr); 49 | ASSERT_NE(jar.next, nullptr); 50 | ASSERT_EQ(pldm_responder_cookie_untrack(&jar, 1, 1, 0, 0x01), &cookie); 51 | ASSERT_EQ(jar.next, nullptr); 52 | } 53 | 54 | TEST(Responder, track_untrack_two) 55 | { 56 | struct pldm_responder_cookie jar{}; 57 | struct pldm_responder_cookie cookies[] = { 58 | { 59 | .tid = 1, 60 | .instance_id = 1, 61 | .type = 0, 62 | .command = 0x01, /* SetTID */ 63 | .next = nullptr, 64 | }, 65 | { 66 | .tid = 2, 67 | .instance_id = 1, 68 | .type = 0, 69 | .command = 0x01, /* SetTID */ 70 | .next = nullptr, 71 | }, 72 | }; 73 | 74 | ASSERT_EQ(pldm_responder_cookie_track(&jar, &cookies[0]), 0); 75 | ASSERT_EQ(pldm_responder_cookie_track(&jar, &cookies[1]), 0); 76 | ASSERT_NE(jar.next, nullptr); 77 | ASSERT_EQ(pldm_responder_cookie_untrack(&jar, 2, 1, 0, 0x01), &cookies[1]); 78 | ASSERT_EQ(pldm_responder_cookie_untrack(&jar, 1, 1, 0, 0x01), &cookies[0]); 79 | ASSERT_EQ(jar.next, nullptr); 80 | } 81 | -------------------------------------------------------------------------------- /tests/transport/meson.build: -------------------------------------------------------------------------------- 1 | tests += [ 2 | 'transport/transport', 3 | 'transport/send_recv_one', 4 | 'transport/send_recv_timeout', 5 | 'transport/send_recv_unwanted', 6 | 'transport/send_recv_wrong_command_code', 7 | 'transport/send_recv_wrong_pldm_type', 8 | ] 9 | -------------------------------------------------------------------------------- /tests/transport/send_recv_one.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "array.h" 4 | #include "transport/test.h" 5 | 6 | #include 7 | 8 | TEST(Transport, send_recv_one) 9 | { 10 | uint8_t req[] = {0x81, 0x00, 0x01, 0x01}; 11 | uint8_t resp[] = {0x01, 0x00, 0x01, 0x00}; 12 | const struct pldm_transport_test_descriptor seq[] = { 13 | { 14 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND, 15 | .send_msg = 16 | { 17 | .dst = 1, 18 | .msg = req, 19 | .len = sizeof(req), 20 | }, 21 | }, 22 | { 23 | .type = PLDM_TRANSPORT_TEST_ELEMENT_LATENCY, 24 | .latency = 25 | { 26 | .it_interval = {0, 0}, 27 | .it_value = {1, 0}, 28 | }, 29 | }, 30 | { 31 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 32 | .recv_msg = 33 | { 34 | .src = 1, 35 | .msg = resp, 36 | .len = sizeof(resp), 37 | }, 38 | }, 39 | }; 40 | struct pldm_transport_test* test = NULL; 41 | struct pldm_transport* ctx; 42 | size_t len; 43 | void* msg; 44 | int rc; 45 | 46 | EXPECT_EQ(pldm_transport_test_init(&test, seq, ARRAY_SIZE(seq)), 0); 47 | ctx = pldm_transport_test_core(test); 48 | rc = pldm_transport_send_recv_msg(ctx, 1, req, sizeof(req), &msg, &len); 49 | EXPECT_EQ(rc, PLDM_REQUESTER_SUCCESS); 50 | EXPECT_EQ(len, sizeof(resp)); 51 | EXPECT_EQ(memcmp(msg, resp, len), 0); 52 | free(msg); 53 | pldm_transport_test_destroy(test); 54 | } 55 | -------------------------------------------------------------------------------- /tests/transport/send_recv_timeout.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "array.h" 4 | #include "transport/test.h" 5 | 6 | #include 7 | 8 | TEST(Transport, send_recv_timeout) 9 | { 10 | uint8_t req[] = {0x81, 0x00, 0x01, 0x01}; 11 | const struct pldm_transport_test_descriptor seq[] = { 12 | { 13 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND, 14 | .send_msg = 15 | { 16 | .dst = 1, 17 | .msg = req, 18 | .len = sizeof(req), 19 | }, 20 | }, 21 | { 22 | .type = PLDM_TRANSPORT_TEST_ELEMENT_LATENCY, 23 | .latency = 24 | { 25 | .it_interval = {0, 0}, 26 | .it_value = {5, 0}, 27 | }, 28 | }, 29 | }; 30 | struct pldm_transport_test* test = NULL; 31 | struct pldm_transport* ctx; 32 | size_t len; 33 | void* msg; 34 | int rc; 35 | 36 | EXPECT_EQ(pldm_transport_test_init(&test, seq, ARRAY_SIZE(seq)), 0); 37 | ctx = pldm_transport_test_core(test); 38 | rc = pldm_transport_send_recv_msg(ctx, 1, req, sizeof(req), &msg, &len); 39 | EXPECT_EQ(rc, PLDM_REQUESTER_RECV_FAIL); 40 | pldm_transport_test_destroy(test); 41 | } 42 | -------------------------------------------------------------------------------- /tests/transport/send_recv_unwanted.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "array.h" 4 | #include "transport/test.h" 5 | 6 | #include 7 | 8 | TEST(Transport, send_recv_unwanted) 9 | { 10 | uint8_t req[] = {0x81, 0x00, 0x01, 0x01}; 11 | uint8_t resp[] = {0x02, 0x00, 0x01, 0x00}; 12 | const struct pldm_transport_test_descriptor seq[] = { 13 | { 14 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND, 15 | .send_msg = 16 | { 17 | .dst = 1, 18 | .msg = req, 19 | .len = sizeof(req), 20 | }, 21 | }, 22 | { 23 | .type = PLDM_TRANSPORT_TEST_ELEMENT_LATENCY, 24 | .latency = 25 | { 26 | .it_interval = {0, 0}, 27 | .it_value = {1, 0}, 28 | }, 29 | }, 30 | { 31 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 32 | .recv_msg = 33 | { 34 | .src = 2, 35 | .msg = resp, 36 | .len = sizeof(resp), 37 | }, 38 | }, 39 | { 40 | .type = PLDM_TRANSPORT_TEST_ELEMENT_LATENCY, 41 | .latency = 42 | { 43 | .it_interval = {0, 0}, 44 | .it_value = {4, 0}, 45 | }, 46 | }, 47 | }; 48 | struct pldm_transport_test* test = NULL; 49 | struct pldm_transport* ctx; 50 | size_t len; 51 | void* msg; 52 | int rc; 53 | 54 | EXPECT_EQ(pldm_transport_test_init(&test, seq, ARRAY_SIZE(seq)), 0); 55 | ctx = pldm_transport_test_core(test); 56 | rc = pldm_transport_send_recv_msg(ctx, 1, req, sizeof(req), &msg, &len); 57 | EXPECT_EQ(rc, PLDM_REQUESTER_RECV_FAIL); 58 | pldm_transport_test_destroy(test); 59 | } 60 | -------------------------------------------------------------------------------- /tests/transport/send_recv_wrong_command_code.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "array.h" 4 | #include "transport/test.h" 5 | 6 | #include 7 | 8 | TEST(Transport, send_recv_wrong_command_code) 9 | { 10 | uint8_t req[] = {0x81, 0x00, 0x01, 0x01}; 11 | uint8_t resp[] = {0x01, 0x00, 0x02, 0x00}; 12 | const struct pldm_transport_test_descriptor seq[] = { 13 | { 14 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND, 15 | .send_msg = 16 | { 17 | .dst = 1, 18 | .msg = req, 19 | .len = sizeof(req), 20 | }, 21 | }, 22 | { 23 | .type = PLDM_TRANSPORT_TEST_ELEMENT_LATENCY, 24 | .latency = 25 | { 26 | .it_interval = {0, 0}, 27 | .it_value = {1, 0}, 28 | }, 29 | }, 30 | { 31 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 32 | .recv_msg = 33 | { 34 | .src = 2, 35 | .msg = resp, 36 | .len = sizeof(resp), 37 | }, 38 | }, 39 | { 40 | .type = PLDM_TRANSPORT_TEST_ELEMENT_LATENCY, 41 | .latency = 42 | { 43 | .it_interval = {0, 0}, 44 | .it_value = {4, 0}, 45 | }, 46 | }, 47 | }; 48 | struct pldm_transport_test* test = NULL; 49 | struct pldm_transport* ctx; 50 | size_t len; 51 | void* msg; 52 | int rc; 53 | 54 | EXPECT_EQ(pldm_transport_test_init(&test, seq, ARRAY_SIZE(seq)), 0); 55 | ctx = pldm_transport_test_core(test); 56 | rc = pldm_transport_send_recv_msg(ctx, 1, req, sizeof(req), &msg, &len); 57 | EXPECT_EQ(rc, PLDM_REQUESTER_RECV_FAIL); 58 | pldm_transport_test_destroy(test); 59 | } 60 | -------------------------------------------------------------------------------- /tests/transport/send_recv_wrong_pldm_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "array.h" 4 | #include "transport/test.h" 5 | 6 | #include 7 | 8 | TEST(Transport, send_recv_wrong_pldm_type) 9 | { 10 | uint8_t req[] = {0x81, 0x00, 0x01, 0x01}; 11 | uint8_t resp[] = {0x01, 0x01, 0x01, 0x00}; 12 | const struct pldm_transport_test_descriptor seq[] = { 13 | { 14 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND, 15 | .send_msg = 16 | { 17 | .dst = 1, 18 | .msg = req, 19 | .len = sizeof(req), 20 | }, 21 | }, 22 | { 23 | .type = PLDM_TRANSPORT_TEST_ELEMENT_LATENCY, 24 | .latency = 25 | { 26 | .it_interval = {0, 0}, 27 | .it_value = {1, 0}, 28 | }, 29 | }, 30 | { 31 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 32 | .recv_msg = 33 | { 34 | .src = 2, 35 | .msg = resp, 36 | .len = sizeof(resp), 37 | }, 38 | }, 39 | { 40 | .type = PLDM_TRANSPORT_TEST_ELEMENT_LATENCY, 41 | .latency = 42 | { 43 | .it_interval = {0, 0}, 44 | .it_value = {4, 0}, 45 | }, 46 | }, 47 | }; 48 | struct pldm_transport_test* test = NULL; 49 | struct pldm_transport* ctx; 50 | size_t len; 51 | void* msg; 52 | int rc; 53 | 54 | EXPECT_EQ(pldm_transport_test_init(&test, seq, ARRAY_SIZE(seq)), 0); 55 | ctx = pldm_transport_test_core(test); 56 | rc = pldm_transport_send_recv_msg(ctx, 1, req, sizeof(req), &msg, &len); 57 | EXPECT_EQ(rc, PLDM_REQUESTER_RECV_FAIL); 58 | pldm_transport_test_destroy(test); 59 | } 60 | -------------------------------------------------------------------------------- /tests/transport/transport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "array.h" 4 | #include "transport/test.h" 5 | 6 | #include 7 | 8 | TEST(Transport, create) 9 | { 10 | struct pldm_transport_test* test = NULL; 11 | 12 | EXPECT_EQ(pldm_transport_test_init(&test, NULL, 0), 0); 13 | EXPECT_NE(pldm_transport_test_core(test), nullptr); 14 | pldm_transport_test_destroy(test); 15 | } 16 | 17 | TEST(Transport, send_one) 18 | { 19 | const uint8_t msg[] = {0x81, 0x00, 0x01, 0x01}; 20 | const struct pldm_transport_test_descriptor seq[] = { 21 | { 22 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND, 23 | .send_msg = 24 | { 25 | .dst = 1, 26 | .msg = msg, 27 | .len = sizeof(msg), 28 | }, 29 | }, 30 | }; 31 | struct pldm_transport_test* test = NULL; 32 | struct pldm_transport* ctx; 33 | int rc; 34 | 35 | EXPECT_EQ(pldm_transport_test_init(&test, seq, ARRAY_SIZE(seq)), 0); 36 | ctx = pldm_transport_test_core(test); 37 | rc = pldm_transport_send_msg(ctx, 1, msg, sizeof(msg)); 38 | EXPECT_EQ(rc, PLDM_REQUESTER_SUCCESS); 39 | pldm_transport_test_destroy(test); 40 | } 41 | 42 | TEST(Transport, recv_one) 43 | { 44 | uint8_t msg[] = {0x01, 0x00, 0x01, 0x00}; 45 | const pldm_tid_t src_tid = 1; 46 | const struct pldm_transport_test_descriptor seq[] = { 47 | { 48 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 49 | .recv_msg = 50 | { 51 | .src = src_tid, 52 | .msg = msg, 53 | .len = sizeof(msg), 54 | }, 55 | }, 56 | }; 57 | struct pldm_transport_test* test = NULL; 58 | struct pldm_transport* ctx; 59 | void* recvd; 60 | size_t len; 61 | int rc; 62 | pldm_tid_t tid; 63 | 64 | EXPECT_EQ(pldm_transport_test_init(&test, seq, ARRAY_SIZE(seq)), 0); 65 | ctx = pldm_transport_test_core(test); 66 | rc = pldm_transport_recv_msg(ctx, &tid, &recvd, &len); 67 | EXPECT_EQ(rc, PLDM_REQUESTER_SUCCESS); 68 | EXPECT_EQ(len, sizeof(msg)); 69 | EXPECT_EQ(memcmp(recvd, msg, len), 0); 70 | EXPECT_EQ(tid, src_tid); 71 | free(recvd); 72 | pldm_transport_test_destroy(test); 73 | } 74 | 75 | TEST(Transport, send_recv_drain_one_unwanted) 76 | { 77 | uint8_t unwanted[] = {0x01, 0x00, 0x01, 0x01}; 78 | uint8_t req[] = {0x81, 0x00, 0x01, 0x01}; 79 | uint8_t resp[] = {0x01, 0x00, 0x01, 0x00}; 80 | const struct pldm_transport_test_descriptor seq[] = { 81 | { 82 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 83 | .recv_msg = 84 | { 85 | .src = 2, 86 | .msg = unwanted, 87 | .len = sizeof(unwanted), 88 | }, 89 | }, 90 | { 91 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND, 92 | .send_msg = 93 | { 94 | .dst = 1, 95 | .msg = req, 96 | .len = sizeof(req), 97 | }, 98 | }, 99 | { 100 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 101 | .recv_msg = 102 | { 103 | .src = 1, 104 | .msg = resp, 105 | .len = sizeof(resp), 106 | }, 107 | }, 108 | }; 109 | struct pldm_transport_test* test = NULL; 110 | struct pldm_transport* ctx; 111 | size_t len; 112 | void* msg = NULL; 113 | int rc; 114 | 115 | EXPECT_EQ(pldm_transport_test_init(&test, seq, ARRAY_SIZE(seq)), 0); 116 | ctx = pldm_transport_test_core(test); 117 | rc = pldm_transport_send_recv_msg(ctx, 1, req, sizeof(req), &msg, &len); 118 | ASSERT_EQ(rc, PLDM_REQUESTER_SUCCESS); 119 | EXPECT_NE(memcmp(msg, unwanted, len), 0); 120 | EXPECT_EQ(memcmp(msg, resp, len), 0); 121 | free(msg); 122 | pldm_transport_test_destroy(test); 123 | } 124 | 125 | TEST(Transport, send_recv_req_echo) 126 | { 127 | uint8_t req[] = {0x81, 0x00, 0x01, 0x01}; 128 | uint8_t echo[] = {0x81, 0x00, 0x01, 0x01}; 129 | uint8_t resp[] = {0x01, 0x00, 0x01, 0x00}; 130 | const struct pldm_transport_test_descriptor seq[] = { 131 | { 132 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_SEND, 133 | .send_msg = 134 | { 135 | .dst = 1, 136 | .msg = req, 137 | .len = sizeof(req), 138 | }, 139 | }, 140 | { 141 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 142 | .recv_msg = 143 | { 144 | .src = 1, 145 | .msg = echo, 146 | .len = sizeof(echo), 147 | }, 148 | }, 149 | { 150 | .type = PLDM_TRANSPORT_TEST_ELEMENT_MSG_RECV, 151 | .recv_msg = 152 | { 153 | .src = 1, 154 | .msg = resp, 155 | .len = sizeof(resp), 156 | }, 157 | }, 158 | }; 159 | struct pldm_transport_test* test = NULL; 160 | struct pldm_transport* ctx; 161 | size_t len; 162 | void* msg; 163 | int rc; 164 | 165 | EXPECT_EQ(pldm_transport_test_init(&test, seq, ARRAY_SIZE(seq)), 0); 166 | ctx = pldm_transport_test_core(test); 167 | rc = pldm_transport_send_recv_msg(ctx, 1, req, sizeof(req), &msg, &len); 168 | ASSERT_EQ(rc, PLDM_REQUESTER_SUCCESS); 169 | EXPECT_NE(memcmp(msg, echo, len), 0); 170 | EXPECT_EQ(memcmp(msg, resp, len), 0); 171 | free(msg); 172 | pldm_transport_test_destroy(test); 173 | } 174 | -------------------------------------------------------------------------------- /tests/utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | TEST(Crc32, CheckSumTest) 10 | { 11 | const char* password = "123456789"; 12 | auto checksum = pldm_edac_crc32(password, 9); 13 | EXPECT_EQ(checksum, 0xcbf43926); 14 | } 15 | 16 | TEST(Crc8, CheckSumTest) 17 | { 18 | const char* data = "123456789"; 19 | auto checksum = pldm_edac_crc8(data, 9); 20 | EXPECT_EQ(checksum, 0xf4); 21 | } 22 | 23 | TEST(Ver2string, Ver2string) 24 | { 25 | ver32_t version{0x61, 0x10, 0xf7, 0xf3}; 26 | const char* vstr = "3.7.10a"; 27 | char buffer[1024]; 28 | auto rc = ver2str(&version, buffer, sizeof(buffer)); 29 | EXPECT_EQ(rc, (signed)std::strlen(vstr)); 30 | EXPECT_STREQ(vstr, buffer); 31 | 32 | version = {0x00, 0xf0, 0xf0, 0xf1}; 33 | vstr = "1.0.0"; 34 | rc = ver2str(&version, buffer, sizeof(buffer)); 35 | EXPECT_EQ(rc, (signed)std::strlen(vstr)); 36 | EXPECT_STREQ(vstr, buffer); 37 | 38 | version = {0x00, 0xf7, 0x01, 0x10}; 39 | vstr = "10.01.7"; 40 | rc = ver2str(&version, buffer, sizeof(buffer)); 41 | EXPECT_EQ(rc, (signed)std::strlen(vstr)); 42 | EXPECT_STREQ(vstr, buffer); 43 | 44 | version = {0x00, 0xff, 0xf1, 0xf3}; 45 | vstr = "3.1"; 46 | rc = ver2str(&version, buffer, sizeof(buffer)); 47 | EXPECT_EQ(rc, (signed)std::strlen(vstr)); 48 | EXPECT_STREQ(vstr, buffer); 49 | 50 | version = {0x61, 0xff, 0xf0, 0xf1}; 51 | vstr = "1.0a"; 52 | rc = ver2str(&version, buffer, sizeof(buffer)); 53 | EXPECT_EQ(rc, (signed)std::strlen(vstr)); 54 | EXPECT_STREQ(vstr, buffer); 55 | 56 | rc = ver2str(&version, buffer, 3); 57 | EXPECT_EQ(rc, 2); 58 | EXPECT_STREQ("1.", buffer); 59 | 60 | rc = ver2str(&version, buffer, 1); 61 | EXPECT_EQ(rc, 0); 62 | 63 | rc = ver2str(&version, buffer, 0); 64 | EXPECT_EQ(rc, -1); 65 | } 66 | 67 | TEST(BcdConversion, BcdCoversion) 68 | { 69 | EXPECT_EQ(12u, bcd2dec8(0x12)); 70 | EXPECT_EQ(99u, bcd2dec8(0x99)); 71 | EXPECT_EQ(1234u, bcd2dec16(0x1234)); 72 | EXPECT_EQ(9999u, bcd2dec16(0x9999)); 73 | EXPECT_EQ(12345678u, bcd2dec32(0x12345678)); 74 | EXPECT_EQ(99999999u, bcd2dec32(0x99999999)); 75 | 76 | EXPECT_EQ(0x12u, dec2bcd8(12)); 77 | EXPECT_EQ(0x99u, dec2bcd8(99)); 78 | EXPECT_EQ(0x1234u, dec2bcd16(1234)); 79 | EXPECT_EQ(0x9999u, dec2bcd16(9999)); 80 | EXPECT_EQ(0x12345678u, dec2bcd32(12345678)); 81 | EXPECT_EQ(0x99999999u, dec2bcd32(99999999)); 82 | } 83 | 84 | TEST(TimeLegal, TimeLegal) 85 | { 86 | EXPECT_EQ(true, is_time_legal(30, 25, 16, 18, 8, 2019)); 87 | EXPECT_EQ(true, is_time_legal(30, 25, 16, 29, 2, 2020)); // leap year 88 | 89 | EXPECT_EQ(false, is_time_legal(30, 25, 16, 18, 8, 1960)); // year illegal 90 | EXPECT_EQ(false, is_time_legal(30, 25, 16, 18, 15, 2019)); // month illegal 91 | EXPECT_EQ(false, is_time_legal(30, 25, 16, 18, 0, 2019)); // month illegal 92 | EXPECT_EQ(false, is_time_legal(30, 25, 16, 0, 8, 2019)); // day illegal 93 | EXPECT_EQ(false, is_time_legal(30, 25, 16, 29, 2, 2019)); // day illegal 94 | EXPECT_EQ(false, is_time_legal(30, 25, 25, 18, 8, 2019)); // hours illegal 95 | EXPECT_EQ(false, is_time_legal(30, 70, 16, 18, 8, 2019)); // minutes illegal 96 | EXPECT_EQ(false, is_time_legal(80, 25, 16, 18, 8, 2019)); // seconds illegal 97 | } 98 | --------------------------------------------------------------------------------