blob: a30eb9e5f00723ccc5b6d495197499f69b2567ad [file] [log] [blame]
Patrick Venturec79faa12018-12-12 13:12:21 -08001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Patrick Venture00887592018-12-11 10:57:06 -080017#include "blob_handler.hpp"
18
Patrick Venturec79faa12018-12-12 13:12:21 -080019#include "crc.hpp"
20#include "ipmi_errors.hpp"
21
22#include <array>
23#include <cstring>
24
25const std::array<std::uint8_t, 3> ipmiPhosphorOen = {0xcf, 0xc2, 0x00};
26
27std::vector<std::uint8_t>
28 BlobHandler::sendIpmiPayload(BlobOEMCommands command,
29 const std::vector<std::uint8_t>& payload)
30{
31 std::vector<std::uint8_t> request, reply;
32
33 std::copy(ipmiPhosphorOen.begin(), ipmiPhosphorOen.end(),
34 std::back_inserter(request));
35 request.push_back(command);
36
37 if (payload.size() > 0)
38 {
39 /* Grow the vector to hold the bytes. */
40 request.reserve(request.size() + sizeof(std::uint16_t));
41
42 /* CRC required. */
43 std::uint16_t crc = generateCrc(payload);
44 std::uint8_t* src = reinterpret_cast<std::uint8_t*>(&crc);
45
46 std::copy(src, src + sizeof(crc), std::back_inserter(request));
47
48 /* Copy the payload. */
49 std::copy(payload.begin(), payload.end(), std::back_inserter(request));
50 }
51
52 try
53 {
54 reply = ipmi->sendPacket(request);
55 }
56 catch (const IpmiException& e)
57 {
58 std::fprintf(stderr, "Received exception: %s\n", e.what());
59 return {};
60 }
61
62 /* IPMI_CC was OK, and it returned no bytes, so let's be happy with that for
63 * now.
64 */
65 if (reply.size() == 0)
66 {
67 return reply;
68 }
69
70 size_t headerSize = ipmiPhosphorOen.size() + sizeof(std::uint16_t);
71
72 /* This cannot be a response because it's smaller than the smallest
73 * response.
74 */
75 if (reply.size() < headerSize)
76 {
77 std::fprintf(stderr, "Invalid response length\n");
78 return {};
79 }
80
81 /* Verify the OEN. */
82 if (std::memcmp(ipmiPhosphorOen.data(), reply.data(),
83 ipmiPhosphorOen.size()) != 0)
84 {
85 std::fprintf(stderr, "Invalid OEN received\n");
86 return {};
87 }
88
89 /* Validate CRC. */
90 std::uint16_t crc;
91 auto ptr = reinterpret_cast<std::uint8_t*>(&crc);
92 std::memcpy(ptr, &reply[ipmiPhosphorOen.size()], sizeof(crc));
93
94 std::vector<std::uint8_t> bytes;
95 std::copy(&reply[headerSize], &reply[reply.size()],
96 std::back_inserter(bytes));
97
98 auto computed = generateCrc(bytes);
99 if (crc != computed)
100 {
101 std::fprintf(stderr, "Invalid CRC, received: 0x%x, computed: 0x%x\n",
102 crc, computed);
103 return {};
104 }
105
106 return bytes;
107}
108
109int BlobHandler::getBlobCount()
110{
111 std::uint32_t count;
112 auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobGetCount, {});
113 if (resp.size() != sizeof(count))
114 {
115 return 0;
116 }
117
118 /* LE to LE (need to make this portable as some point. */
119 std::memcpy(&count, resp.data(), sizeof(count));
120 return count;
121}
122
123std::string BlobHandler::enumerateBlob(std::uint32_t index)
124{
125 std::vector<std::uint8_t> payload;
126 std::uint8_t* data = reinterpret_cast<std::uint8_t*>(&index);
127 std::copy(data, data + sizeof(std::uint32_t), std::back_inserter(payload));
128
129 auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobEnumerate, payload);
130 std::string output;
131 std::copy(resp.begin(), resp.end(), std::back_inserter(output));
132 return output;
133}
134
Patrick Venture00887592018-12-11 10:57:06 -0800135std::vector<std::string> BlobHandler::getBlobList()
136{
Patrick Venturec79faa12018-12-12 13:12:21 -0800137 std::vector<std::string> list;
138 int blobCount = getBlobCount();
139
140 for (int i = 0; i < blobCount; i++)
141 {
142 auto name = enumerateBlob(i);
143 /* Currently ignore failures. */
144 if (!name.empty())
145 {
146 list.push_back(name);
147 }
148 }
149
150 return list;
Patrick Venture00887592018-12-11 10:57:06 -0800151}
Patrick Venture0bf8bf02018-12-12 20:43:25 -0800152
153StatResponse BlobHandler::getStat(const std::string& id)
154{
155 StatResponse meta;
156 std::vector<std::uint8_t> name;
157 std::copy(id.begin(), id.end(), std::back_inserter(name));
158
159 auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobStat, name);
160 std::memcpy(&meta.blob_state, &resp[0], sizeof(meta.blob_state));
161 std::memcpy(&meta.size, &resp[sizeof(meta.blob_state)], sizeof(meta.size));
162 int offset = sizeof(meta.blob_state) + sizeof(meta.size);
163 std::uint8_t len = resp[offset];
164 if (len > 0)
165 {
166 std::copy(&resp[offset + 1], &resp[resp.size()],
167 std::back_inserter(meta.metadata));
168 }
169
170 return meta;
171}