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> 22de8a16e2SPatrick Venture #include <ipmiblob/crc.hpp> 23067ece15SWilly Tu #include <ipmid/api-types.hpp> 24067ece15SWilly Tu #include <span> 25b15b3050SPatrick Venture #include <unordered_map> 26067ece15SWilly Tu #include <utility> 27ef3aeadcSPatrick Venture #include <vector> 28ef3aeadcSPatrick Venture 29ef3aeadcSPatrick Venture namespace blobs 30ef3aeadcSPatrick Venture { 31ef3aeadcSPatrick Venture 32ef3aeadcSPatrick Venture /* Used by all commands with data. */ 33ef3aeadcSPatrick Venture struct BmcRx 34ef3aeadcSPatrick Venture { 35ef3aeadcSPatrick Venture uint16_t crc; 36ef3aeadcSPatrick Venture uint8_t data; /* one byte minimum of data. */ 37ef3aeadcSPatrick Venture } __attribute__((packed)); 38ef3aeadcSPatrick Venture 39b15b3050SPatrick Venture static const std::unordered_map<BlobOEMCommands, IpmiBlobHandler> handlers = { 40b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobGetCount, getBlobCount}, 41b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobEnumerate, enumerateBlob}, 42b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobOpen, openBlob}, 43b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobRead, readBlob}, 44b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobWrite, writeBlob}, 45b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobCommit, commitBlob}, 46b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobClose, closeBlob}, 47b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobDelete, deleteBlob}, 48b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobStat, statBlob}, 49b15b3050SPatrick Venture {BlobOEMCommands::bmcBlobSessionStat, sessionStatBlob}, 505c4b17b2SPatrick Venture {BlobOEMCommands::bmcBlobWriteMeta, writeMeta}, 51b15b3050SPatrick Venture }; 52b15b3050SPatrick Venture 53067ece15SWilly Tu IpmiBlobHandler validateBlobCommand(uint8_t cmd, std::span<const uint8_t> data) 54ef3aeadcSPatrick Venture { 55067ece15SWilly Tu size_t requestLength = data.size(); 56ef3aeadcSPatrick Venture /* We know dataLen is at least 1 already */ 57067ece15SWilly Tu auto command = static_cast<BlobOEMCommands>(cmd); 58ef3aeadcSPatrick Venture 59ef3aeadcSPatrick Venture /* Validate it's at least well-formed. */ 60ef3aeadcSPatrick Venture if (!validateRequestLength(command, requestLength)) 61ef3aeadcSPatrick Venture { 62067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 63067ece15SWilly Tu return ipmi::responseReqDataLenInvalid(); 64067ece15SWilly Tu }; 65ef3aeadcSPatrick Venture } 66ef3aeadcSPatrick Venture 67ef3aeadcSPatrick Venture /* If there is a payload. */ 68067ece15SWilly Tu if (requestLength > sizeof(cmd)) 69ef3aeadcSPatrick Venture { 70ef3aeadcSPatrick Venture /* Verify the request includes: command, crc16, data */ 71ef3aeadcSPatrick Venture if (requestLength < sizeof(struct BmcRx)) 72ef3aeadcSPatrick Venture { 73067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 74067ece15SWilly Tu return ipmi::responseReqDataLenInvalid(); 75067ece15SWilly Tu }; 76ef3aeadcSPatrick Venture } 77ef3aeadcSPatrick Venture 78ef3aeadcSPatrick Venture /* We don't include the command byte at offset 0 as part of the crc 79ef3aeadcSPatrick Venture * payload area or the crc bytes at the beginning. 80ef3aeadcSPatrick Venture */ 81ef3aeadcSPatrick Venture size_t requestBodyLen = requestLength - 3; 82ef3aeadcSPatrick Venture 83ef3aeadcSPatrick Venture /* We start after the command byte. */ 84ef3aeadcSPatrick Venture std::vector<uint8_t> bytes(requestBodyLen); 85ef3aeadcSPatrick Venture 86067ece15SWilly Tu /* It likely has a well-formed payload. 87067ece15SWilly Tu * Get the first two bytes of the request for crc. 88067ece15SWilly Tu */ 89067ece15SWilly Tu uint16_t crc; 90067ece15SWilly Tu if (data.size() < sizeof(crc)) 91067ece15SWilly Tu { 92067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 93067ece15SWilly Tu return ipmi::responseReqDataLenInvalid(); 94067ece15SWilly Tu }; 95067ece15SWilly Tu } 96067ece15SWilly Tu std::memcpy(&crc, data.data(), sizeof(crc)); 97ef3aeadcSPatrick Venture 98067ece15SWilly Tu /* Set the in-place CRC to zero. 99067ece15SWilly Tu * Remove the first two bytes for crc and get the reset of the request. 100067ece15SWilly Tu */ 101067ece15SWilly Tu data = data.subspan(sizeof(crc)); 102ef3aeadcSPatrick Venture 103ef3aeadcSPatrick Venture /* Crc expected but didn't match. */ 104067ece15SWilly Tu if (crc != ipmiblob::generateCrc( 105067ece15SWilly Tu std::vector<uint8_t>(data.begin(), data.end()))) 106ef3aeadcSPatrick Venture { 107067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 108067ece15SWilly Tu return ipmi::responseUnspecifiedError(); 109067ece15SWilly Tu }; 110067ece15SWilly Tu }; 111ef3aeadcSPatrick Venture } 112ef3aeadcSPatrick Venture 113b15b3050SPatrick Venture /* Grab the corresponding handler for the command. */ 114b15b3050SPatrick Venture auto found = handlers.find(command); 115b15b3050SPatrick Venture if (found == handlers.end()) 116ef3aeadcSPatrick Venture { 117067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 118067ece15SWilly Tu return ipmi::responseInvalidFieldRequest(); 119067ece15SWilly Tu }; 120ef3aeadcSPatrick Venture } 121ef3aeadcSPatrick Venture 122b15b3050SPatrick Venture return found->second; 123ef3aeadcSPatrick Venture } 124ef3aeadcSPatrick Venture 125067ece15SWilly Tu Resp processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr, 126*83f9992cSWilly Tu std::span<const uint8_t> data, size_t maxSize) 127ef3aeadcSPatrick Venture { 128067ece15SWilly Tu Resp result = cmd(mgr, data); 129067ece15SWilly Tu if (std::get<0>(result) != ipmi::ccSuccess) 130ef3aeadcSPatrick Venture { 131ef3aeadcSPatrick Venture return result; 132ef3aeadcSPatrick Venture } 133ef3aeadcSPatrick Venture 134067ece15SWilly Tu std::vector<uint8_t>& response = std::get<0>( 135067ece15SWilly Tu // std::variant<std::vector<uint8_t>> 136067ece15SWilly Tu *std::get<1>(result)); 137067ece15SWilly Tu size_t replyLength = response.size(); 138ef3aeadcSPatrick Venture 139ef3aeadcSPatrick Venture /* The command, whatever it was, returned success. */ 140ef3aeadcSPatrick Venture if (replyLength == 0) 141ef3aeadcSPatrick Venture { 142ef3aeadcSPatrick Venture return result; 143ef3aeadcSPatrick Venture } 144ef3aeadcSPatrick Venture 145d1c3e86fSPatrick Venture /* Read can return 0 bytes, and just a CRC, otherwise you need a CRC and 1 146d1c3e86fSPatrick Venture * byte, therefore the limit is 2 bytes. 147d1c3e86fSPatrick Venture */ 148d1c3e86fSPatrick Venture if (replyLength < (sizeof(uint16_t))) 149ef3aeadcSPatrick Venture { 150067ece15SWilly Tu return ipmi::responseUnspecifiedError(); 151ef3aeadcSPatrick Venture } 152ef3aeadcSPatrick Venture 153*83f9992cSWilly Tu /* Make sure the reply size fits the ipmi buffer */ 154*83f9992cSWilly Tu if (replyLength > maxSize) 155*83f9992cSWilly Tu { 156*83f9992cSWilly Tu return ipmi::responseResponseError(); 157*83f9992cSWilly Tu } 158*83f9992cSWilly Tu 159ef3aeadcSPatrick Venture /* The command, whatever it was, replied, so let's set the CRC. */ 160067ece15SWilly Tu std::span<const uint8_t> responseView = response; 161067ece15SWilly Tu responseView = responseView.subspan(sizeof(uint16_t)); 162067ece15SWilly Tu std::vector<std::uint8_t> crcBuffer(responseView.begin(), 163067ece15SWilly Tu responseView.end()); 164ef3aeadcSPatrick Venture /* Copy the CRC into place. */ 165de8a16e2SPatrick Venture uint16_t crcValue = ipmiblob::generateCrc(crcBuffer); 166067ece15SWilly Tu if (response.size() < sizeof(crcValue)) 167067ece15SWilly Tu { 168067ece15SWilly Tu return ipmi::responseReqDataLenInvalid(); 169067ece15SWilly Tu } 170067ece15SWilly Tu std::memcpy(response.data(), &crcValue, sizeof(crcValue)); 171ef3aeadcSPatrick Venture 172ef3aeadcSPatrick Venture return result; 173ef3aeadcSPatrick Venture } 17403fd5b8bSPatrick Venture 175*83f9992cSWilly Tu Resp handleBlobCommand(uint8_t cmd, std::vector<uint8_t> data, size_t maxSize) 17603fd5b8bSPatrick Venture { 17703fd5b8bSPatrick Venture /* on failure rc is set to the corresponding IPMI error. */ 178067ece15SWilly Tu return processBlobCommand(validateBlobCommand(cmd, data), getBlobManager(), 179*83f9992cSWilly Tu data, maxSize); 18003fd5b8bSPatrick Venture } 18103fd5b8bSPatrick Venture 182ef3aeadcSPatrick Venture } // namespace blobs 183