1ef3aeadcSPatrick Venture /* 2ef3aeadcSPatrick Venture * Copyright 2018 Google Inc. 3ef3aeadcSPatrick Venture * 4ef3aeadcSPatrick Venture * Licensed under the Apache License, Version 2.0 (the "License"); 5ef3aeadcSPatrick Venture * you may not use this file except in compliance with the License. 6ef3aeadcSPatrick Venture * You may obtain a copy of the License at 7ef3aeadcSPatrick Venture * 8ef3aeadcSPatrick Venture * http://www.apache.org/licenses/LICENSE-2.0 9ef3aeadcSPatrick Venture * 10ef3aeadcSPatrick Venture * Unless required by applicable law or agreed to in writing, software 11ef3aeadcSPatrick Venture * distributed under the License is distributed on an "AS IS" BASIS, 12ef3aeadcSPatrick Venture * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ef3aeadcSPatrick Venture * See the License for the specific language governing permissions and 14ef3aeadcSPatrick Venture * limitations under the License. 15ef3aeadcSPatrick Venture */ 16ef3aeadcSPatrick Venture 17ef3aeadcSPatrick Venture #include "process.hpp" 18ef3aeadcSPatrick Venture 19ef3aeadcSPatrick Venture #include "ipmi.hpp" 20ef3aeadcSPatrick Venture 21ef3aeadcSPatrick Venture #include <cstring> 22*de8a16e2SPatrick Venture #include <ipmiblob/crc.hpp> 23b15b3050SPatrick Venture #include <unordered_map> 24ef3aeadcSPatrick Venture #include <vector> 25ef3aeadcSPatrick Venture 26ef3aeadcSPatrick Venture namespace blobs 27ef3aeadcSPatrick Venture { 28ef3aeadcSPatrick Venture 29ef3aeadcSPatrick Venture /* Used by all commands with data. */ 30ef3aeadcSPatrick Venture struct BmcRx 31ef3aeadcSPatrick Venture { 32ef3aeadcSPatrick Venture uint8_t cmd; 33ef3aeadcSPatrick Venture uint16_t crc; 34ef3aeadcSPatrick Venture uint8_t data; /* one byte minimum of data. */ 35ef3aeadcSPatrick Venture } __attribute__((packed)); 36ef3aeadcSPatrick Venture 37b15b3050SPatrick Venture static const std::unordered_map<BlobOEMCommands, IpmiBlobHandler> handlers = { 38b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobGetCount, getBlobCount}, 39b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobEnumerate, enumerateBlob}, 40b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobOpen, openBlob}, 41b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobRead, readBlob}, 42b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobWrite, writeBlob}, 43b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobCommit, commitBlob}, 44b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobClose, closeBlob}, 45b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobDelete, deleteBlob}, 46b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobStat, statBlob}, 47b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobSessionStat, sessionStatBlob}, 485c4b17b2SPatrick Venture {BlobOEMCommands::bmcBlobWriteMeta, writeMeta}, 49b15b3050SPatrick Venture }; 50b15b3050SPatrick Venture 51*de8a16e2SPatrick Venture IpmiBlobHandler validateBlobCommand(const uint8_t* reqBuf, uint8_t* replyCmdBuf, 52*de8a16e2SPatrick Venture size_t* dataLen, ipmi_ret_t* code) 53ef3aeadcSPatrick Venture { 54ef3aeadcSPatrick Venture size_t requestLength = (*dataLen); 55ef3aeadcSPatrick Venture /* We know dataLen is at least 1 already */ 56ef3aeadcSPatrick Venture auto command = static_cast<BlobOEMCommands>(reqBuf[0]); 57ef3aeadcSPatrick Venture 58ef3aeadcSPatrick Venture /* Validate it's at least well-formed. */ 59ef3aeadcSPatrick Venture if (!validateRequestLength(command, requestLength)) 60ef3aeadcSPatrick Venture { 6141258800SPatrick Venture *code = IPMI_CC_REQ_DATA_LEN_INVALID; 62ef3aeadcSPatrick Venture return nullptr; 63ef3aeadcSPatrick Venture } 64ef3aeadcSPatrick Venture 65ef3aeadcSPatrick Venture /* If there is a payload. */ 66ef3aeadcSPatrick Venture if (requestLength > sizeof(uint8_t)) 67ef3aeadcSPatrick Venture { 68ef3aeadcSPatrick Venture /* Verify the request includes: command, crc16, data */ 69ef3aeadcSPatrick Venture if (requestLength < sizeof(struct BmcRx)) 70ef3aeadcSPatrick Venture { 7141258800SPatrick Venture *code = IPMI_CC_REQ_DATA_LEN_INVALID; 72ef3aeadcSPatrick Venture return nullptr; 73ef3aeadcSPatrick Venture } 74ef3aeadcSPatrick Venture 75ef3aeadcSPatrick Venture /* We don't include the command byte at offset 0 as part of the crc 76ef3aeadcSPatrick Venture * payload area or the crc bytes at the beginning. 77ef3aeadcSPatrick Venture */ 78ef3aeadcSPatrick Venture size_t requestBodyLen = requestLength - 3; 79ef3aeadcSPatrick Venture 80ef3aeadcSPatrick Venture /* We start after the command byte. */ 81ef3aeadcSPatrick Venture std::vector<uint8_t> bytes(requestBodyLen); 82ef3aeadcSPatrick Venture 83ef3aeadcSPatrick Venture /* It likely has a well-formed payload. */ 84ef3aeadcSPatrick Venture struct BmcRx request; 85ef3aeadcSPatrick Venture std::memcpy(&request, reqBuf, sizeof(request)); 86ef3aeadcSPatrick Venture uint16_t crcValue = request.crc; 87ef3aeadcSPatrick Venture 88ef3aeadcSPatrick Venture /* Set the in-place CRC to zero. */ 89ef3aeadcSPatrick Venture std::memcpy(bytes.data(), &reqBuf[3], requestBodyLen); 90ef3aeadcSPatrick Venture 91ef3aeadcSPatrick Venture /* Crc expected but didn't match. */ 92*de8a16e2SPatrick Venture if (crcValue != ipmiblob::generateCrc(bytes)) 93ef3aeadcSPatrick Venture { 9441258800SPatrick Venture *code = IPMI_CC_UNSPECIFIED_ERROR; 95ef3aeadcSPatrick Venture return nullptr; 96ef3aeadcSPatrick Venture } 97ef3aeadcSPatrick Venture } 98ef3aeadcSPatrick Venture 99b15b3050SPatrick Venture /* Grab the corresponding handler for the command. */ 100b15b3050SPatrick Venture auto found = handlers.find(command); 101b15b3050SPatrick Venture if (found == handlers.end()) 102ef3aeadcSPatrick Venture { 10341258800SPatrick Venture *code = IPMI_CC_INVALID_FIELD_REQUEST; 104ef3aeadcSPatrick Venture return nullptr; 105ef3aeadcSPatrick Venture } 106ef3aeadcSPatrick Venture 107b15b3050SPatrick Venture return found->second; 108ef3aeadcSPatrick Venture } 109ef3aeadcSPatrick Venture 110ef3aeadcSPatrick Venture ipmi_ret_t processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr, 111*de8a16e2SPatrick Venture const uint8_t* reqBuf, uint8_t* replyCmdBuf, 112*de8a16e2SPatrick Venture size_t* dataLen) 113ef3aeadcSPatrick Venture { 114ef3aeadcSPatrick Venture ipmi_ret_t result = cmd(mgr, reqBuf, replyCmdBuf, dataLen); 115ef3aeadcSPatrick Venture if (result != IPMI_CC_OK) 116ef3aeadcSPatrick Venture { 117ef3aeadcSPatrick Venture return result; 118ef3aeadcSPatrick Venture } 119ef3aeadcSPatrick Venture 120ef3aeadcSPatrick Venture size_t replyLength = (*dataLen); 121ef3aeadcSPatrick Venture 122ef3aeadcSPatrick Venture /* The command, whatever it was, returned success. */ 123ef3aeadcSPatrick Venture if (replyLength == 0) 124ef3aeadcSPatrick Venture { 125ef3aeadcSPatrick Venture return result; 126ef3aeadcSPatrick Venture } 127ef3aeadcSPatrick Venture 128d1c3e86fSPatrick Venture /* Read can return 0 bytes, and just a CRC, otherwise you need a CRC and 1 129d1c3e86fSPatrick Venture * byte, therefore the limit is 2 bytes. 130d1c3e86fSPatrick Venture */ 131d1c3e86fSPatrick Venture if (replyLength < (sizeof(uint16_t))) 132ef3aeadcSPatrick Venture { 13341258800SPatrick Venture return IPMI_CC_UNSPECIFIED_ERROR; 134ef3aeadcSPatrick Venture } 135ef3aeadcSPatrick Venture 136ef3aeadcSPatrick Venture /* The command, whatever it was, replied, so let's set the CRC. */ 137*de8a16e2SPatrick Venture std::vector<std::uint8_t> crcBuffer(replyCmdBuf + sizeof(uint16_t), 138*de8a16e2SPatrick Venture replyCmdBuf + replyLength); 139ef3aeadcSPatrick Venture /* Copy the CRC into place. */ 140*de8a16e2SPatrick Venture uint16_t crcValue = ipmiblob::generateCrc(crcBuffer); 141ef3aeadcSPatrick Venture std::memcpy(replyCmdBuf, &crcValue, sizeof(crcValue)); 142ef3aeadcSPatrick Venture 143ef3aeadcSPatrick Venture return result; 144ef3aeadcSPatrick Venture } 145ef3aeadcSPatrick Venture } // namespace blobs 146