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> 23*067ece15SWilly Tu #include <ipmid/api-types.hpp> 24*067ece15SWilly Tu #include <span> 25b15b3050SPatrick Venture #include <unordered_map> 26*067ece15SWilly 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 53*067ece15SWilly Tu IpmiBlobHandler validateBlobCommand(uint8_t cmd, std::span<const uint8_t> data) 54ef3aeadcSPatrick Venture { 55*067ece15SWilly Tu size_t requestLength = data.size(); 56ef3aeadcSPatrick Venture /* We know dataLen is at least 1 already */ 57*067ece15SWilly 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 { 62*067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 63*067ece15SWilly Tu return ipmi::responseReqDataLenInvalid(); 64*067ece15SWilly Tu }; 65ef3aeadcSPatrick Venture } 66ef3aeadcSPatrick Venture 67ef3aeadcSPatrick Venture /* If there is a payload. */ 68*067ece15SWilly 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 { 73*067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 74*067ece15SWilly Tu return ipmi::responseReqDataLenInvalid(); 75*067ece15SWilly 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 86*067ece15SWilly Tu /* It likely has a well-formed payload. 87*067ece15SWilly Tu * Get the first two bytes of the request for crc. 88*067ece15SWilly Tu */ 89*067ece15SWilly Tu uint16_t crc; 90*067ece15SWilly Tu if (data.size() < sizeof(crc)) 91*067ece15SWilly Tu { 92*067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 93*067ece15SWilly Tu return ipmi::responseReqDataLenInvalid(); 94*067ece15SWilly Tu }; 95*067ece15SWilly Tu } 96*067ece15SWilly Tu std::memcpy(&crc, data.data(), sizeof(crc)); 97ef3aeadcSPatrick Venture 98*067ece15SWilly Tu /* Set the in-place CRC to zero. 99*067ece15SWilly Tu * Remove the first two bytes for crc and get the reset of the request. 100*067ece15SWilly Tu */ 101*067ece15SWilly Tu data = data.subspan(sizeof(crc)); 102ef3aeadcSPatrick Venture 103ef3aeadcSPatrick Venture /* Crc expected but didn't match. */ 104*067ece15SWilly Tu if (crc != ipmiblob::generateCrc( 105*067ece15SWilly Tu std::vector<uint8_t>(data.begin(), data.end()))) 106ef3aeadcSPatrick Venture { 107*067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 108*067ece15SWilly Tu return ipmi::responseUnspecifiedError(); 109*067ece15SWilly Tu }; 110*067ece15SWilly 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 { 117*067ece15SWilly Tu return [](ManagerInterface*, std::span<const uint8_t>) { 118*067ece15SWilly Tu return ipmi::responseInvalidFieldRequest(); 119*067ece15SWilly Tu }; 120ef3aeadcSPatrick Venture } 121ef3aeadcSPatrick Venture 122b15b3050SPatrick Venture return found->second; 123ef3aeadcSPatrick Venture } 124ef3aeadcSPatrick Venture 125*067ece15SWilly Tu Resp processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr, 126*067ece15SWilly Tu std::span<const uint8_t> data) 127ef3aeadcSPatrick Venture { 128*067ece15SWilly Tu Resp result = cmd(mgr, data); 129*067ece15SWilly Tu if (std::get<0>(result) != ipmi::ccSuccess) 130ef3aeadcSPatrick Venture { 131ef3aeadcSPatrick Venture return result; 132ef3aeadcSPatrick Venture } 133ef3aeadcSPatrick Venture 134*067ece15SWilly Tu std::vector<uint8_t>& response = std::get<0>( 135*067ece15SWilly Tu // std::variant<std::vector<uint8_t>> 136*067ece15SWilly Tu *std::get<1>(result)); 137*067ece15SWilly 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 { 150*067ece15SWilly Tu return ipmi::responseUnspecifiedError(); 151ef3aeadcSPatrick Venture } 152ef3aeadcSPatrick Venture 153ef3aeadcSPatrick Venture /* The command, whatever it was, replied, so let's set the CRC. */ 154*067ece15SWilly Tu std::span<const uint8_t> responseView = response; 155*067ece15SWilly Tu responseView = responseView.subspan(sizeof(uint16_t)); 156*067ece15SWilly Tu std::vector<std::uint8_t> crcBuffer(responseView.begin(), 157*067ece15SWilly Tu responseView.end()); 158ef3aeadcSPatrick Venture /* Copy the CRC into place. */ 159de8a16e2SPatrick Venture uint16_t crcValue = ipmiblob::generateCrc(crcBuffer); 160*067ece15SWilly Tu if (response.size() < sizeof(crcValue)) 161*067ece15SWilly Tu { 162*067ece15SWilly Tu return ipmi::responseReqDataLenInvalid(); 163*067ece15SWilly Tu } 164*067ece15SWilly Tu std::memcpy(response.data(), &crcValue, sizeof(crcValue)); 165ef3aeadcSPatrick Venture 166ef3aeadcSPatrick Venture return result; 167ef3aeadcSPatrick Venture } 16803fd5b8bSPatrick Venture 169*067ece15SWilly Tu Resp handleBlobCommand(uint8_t cmd, std::vector<uint8_t> data) 17003fd5b8bSPatrick Venture { 17103fd5b8bSPatrick Venture /* on failure rc is set to the corresponding IPMI error. */ 172*067ece15SWilly Tu return processBlobCommand(validateBlobCommand(cmd, data), getBlobManager(), 173*067ece15SWilly Tu data); 17403fd5b8bSPatrick Venture } 17503fd5b8bSPatrick Venture 176ef3aeadcSPatrick Venture } // namespace blobs 177