blob: 3c43aa7db21e6abb07e20a44d1c2446fb0f77ab5 [file] [log] [blame]
Patrick Venture54c3b532018-08-01 11:45:49 -07001/*
Patrick Venture514f6482018-08-07 14:27:58 -07002 * Copyright 2018 Google Inc.
Patrick Venture54c3b532018-08-01 11:45:49 -07003 *
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 Venture79e131f2018-08-01 13:34:35 -070017#include <cstring>
Patrick Venturea53a7b32018-08-03 09:15:20 -070018#include <unordered_map>
Patrick Venture79e131f2018-08-01 13:34:35 -070019
Patrick Venture54c3b532018-08-01 11:45:49 -070020#include "flash-ipmi.hpp"
21#include "ipmi.hpp"
22
Patrick Venture9a5a79a2018-08-03 17:23:57 -070023IpmiFlashHandler getCommandHandler(FlashSubCmds command)
24{
25 static const std::unordered_map<FlashSubCmds, IpmiFlashHandler>
26 subHandlers = {
27 {FlashSubCmds::flashStartTransfer, startTransfer},
28 {FlashSubCmds::flashDataBlock, dataBlock},
29 {FlashSubCmds::flashDataFinish, dataFinish},
30 {FlashSubCmds::flashStartHash, startHash},
31 {FlashSubCmds::flashHashData, hashBlock},
32 {FlashSubCmds::flashHashFinish, hashFinish},
Patrick Venture1cb87d22018-08-03 18:22:09 -070033 {FlashSubCmds::flashDataVerify, dataVerify},
Patrick Venture5c251ca2018-08-03 18:31:01 -070034 {FlashSubCmds::flashAbort, abortUpdate},
Patrick Venturefdc65b22018-08-07 14:37:58 -070035 {FlashSubCmds::flashVerifyCheck, checkVerify},
Patrick Venture9a5a79a2018-08-03 17:23:57 -070036 };
37
38 auto results = subHandlers.find(command);
39 if (results == subHandlers.end())
40 {
41 return nullptr;
42 }
43
44 return results->second;
45}
46
Patrick Venturea53a7b32018-08-03 09:15:20 -070047bool validateRequestLength(FlashSubCmds command, size_t requestLen)
48{
49 static const std::unordered_map<FlashSubCmds, size_t> minimumLengths = {
50 {FlashSubCmds::flashStartTransfer, sizeof(struct StartTx)},
51 {FlashSubCmds::flashDataBlock, sizeof(struct ChunkHdr) + 1},
Patrick Venture8d9f7322018-08-03 10:39:13 -070052 {FlashSubCmds::flashStartHash, sizeof(struct StartTx)},
Patrick Venturecfe66872018-08-03 13:32:33 -070053 {FlashSubCmds::flashHashData, sizeof(struct ChunkHdr) + 1},
Patrick Venturea53a7b32018-08-03 09:15:20 -070054 };
55
56 auto results = minimumLengths.find(command);
57 if (results == minimumLengths.end())
58 {
59 /* Valid length by default if we don't care. */
60 return true;
61 }
62
63 /* If the request is shorter than the minimum, it's invalid. */
64 if (requestLen < results->second)
65 {
66 return false;
67 }
68
69 return true;
70}
71
Patrick Venture54c3b532018-08-01 11:45:49 -070072ipmi_ret_t startTransfer(UpdateInterface* updater, const uint8_t* reqBuf,
73 uint8_t* replyBuf, size_t* dataLen)
74{
Patrick Venture54c3b532018-08-01 11:45:49 -070075 auto request = reinterpret_cast<const struct StartTx*>(reqBuf);
76
77 if (!updater->start(request->length))
78 {
79 return IPMI_CC_INVALID;
80 }
81
82 /* We were successful and set the response byte to 0. */
83 replyBuf[0] = 0x00;
84 (*dataLen) = 1;
85 return IPMI_CC_OK;
86}
Patrick Venture79e131f2018-08-01 13:34:35 -070087
88ipmi_ret_t dataBlock(UpdateInterface* updater, const uint8_t* reqBuf,
89 uint8_t* replyBuf, size_t* dataLen)
90{
Patrick Venture79e131f2018-08-01 13:34:35 -070091 struct ChunkHdr hdr;
92 std::memcpy(&hdr, reqBuf, sizeof(hdr));
93
Patrick Venturecfe66872018-08-03 13:32:33 -070094 auto requestLength = *dataLen;
Patrick Venturea53a7b32018-08-03 09:15:20 -070095
Patrick Venture79e131f2018-08-01 13:34:35 -070096 /* Grab the bytes from the packet. */
Patrick Venturecfe66872018-08-03 13:32:33 -070097 auto bytesLength = requestLength - sizeof(struct ChunkHdr);
Patrick Venture79e131f2018-08-01 13:34:35 -070098 std::vector<uint8_t> bytes(bytesLength);
99 std::memcpy(bytes.data(), &reqBuf[sizeof(struct ChunkHdr)], bytesLength);
100
101 if (!updater->flashData(hdr.offset, bytes))
102 {
103 return IPMI_CC_INVALID;
104 }
105
106 /* We were successful and set the response byte to 0. */
107 replyBuf[0] = 0x00;
108 (*dataLen) = 1;
109 return IPMI_CC_OK;
110}
Patrick Venture2c1205d2018-08-03 10:23:14 -0700111
112ipmi_ret_t dataFinish(UpdateInterface* updater, const uint8_t* reqBuf,
113 uint8_t* replyBuf, size_t* dataLen)
114{
115 if (!updater->flashFinish())
116 {
117 return IPMI_CC_INVALID;
118 }
119
120 /* TODO: If all commands return this on success, handle it in one place. */
121
122 /* We were successful and set the response byte to 0. */
123 replyBuf[0] = 0x00;
124 (*dataLen) = 1;
125 return IPMI_CC_OK;
126}
Patrick Venture8d9f7322018-08-03 10:39:13 -0700127
128ipmi_ret_t startHash(UpdateInterface* updater, const uint8_t* reqBuf,
129 uint8_t* replyBuf, size_t* dataLen)
130{
131 auto request = reinterpret_cast<const struct StartTx*>(reqBuf);
132
133 if (!updater->startHash(request->length))
134 {
135 return IPMI_CC_INVALID;
136 }
137
138 /* We were successful and set the response byte to 0. */
139 replyBuf[0] = 0x00;
140 (*dataLen) = 1;
141 return IPMI_CC_OK;
142}
Patrick Venturecfe66872018-08-03 13:32:33 -0700143
144ipmi_ret_t hashBlock(UpdateInterface* updater, const uint8_t* reqBuf,
145 uint8_t* replyBuf, size_t* dataLen)
146{
147 struct ChunkHdr hdr;
148 std::memcpy(&hdr, reqBuf, sizeof(hdr));
149
150 auto requestLength = *dataLen;
151
152 /* Grab the bytes from the packet. */
153 auto bytesLength = requestLength - sizeof(struct ChunkHdr);
154 std::vector<uint8_t> bytes(bytesLength);
155 std::memcpy(bytes.data(), &reqBuf[sizeof(struct ChunkHdr)], bytesLength);
156
157 /* TODO: Refactor this and dataBlock for re-use. */
158
159 if (!updater->hashData(hdr.offset, bytes))
160 {
161 return IPMI_CC_INVALID;
162 }
163
164 /* We were successful and set the response byte to 0. */
165 replyBuf[0] = 0x00;
166 (*dataLen) = 1;
167 return IPMI_CC_OK;
168}
Patrick Venturefbc7d192018-08-03 13:54:21 -0700169
170ipmi_ret_t hashFinish(UpdateInterface* updater, const uint8_t* reqBuf,
171 uint8_t* replyBuf, size_t* dataLen)
172{
173 if (!updater->hashFinish())
174 {
175 return IPMI_CC_INVALID;
176 }
177
178 /* We were successful and set the response byte to 0. */
179 replyBuf[0] = 0x00;
180 (*dataLen) = 1;
181 return IPMI_CC_OK;
182}
Patrick Venture1cb87d22018-08-03 18:22:09 -0700183
184ipmi_ret_t dataVerify(UpdateInterface* updater, const uint8_t* reqBuf,
185 uint8_t* replyBuf, size_t* dataLen)
186{
187 if (!updater->startDataVerification())
188 {
189 return IPMI_CC_INVALID;
190 }
191
192 /* We were successful and set the response byte to 0. */
193 replyBuf[0] = 0x00;
194 (*dataLen) = 1;
195 return IPMI_CC_OK;
196}
Patrick Venture5c251ca2018-08-03 18:31:01 -0700197
198ipmi_ret_t abortUpdate(UpdateInterface* updater, const uint8_t* reqBuf,
199 uint8_t* replyBuf, size_t* dataLen)
200{
201 /* TODO: May make sense to work all the pass-through commands into one
202 * piece of code
203 */
204 if (!updater->abortUpdate())
205 {
206 return IPMI_CC_INVALID;
207 }
208
209 /* We were successful and set the response byte to 0. */
210 replyBuf[0] = 0x00;
211 (*dataLen) = 1;
212 return IPMI_CC_OK;
213}
Patrick Venturefdc65b22018-08-07 14:37:58 -0700214
215ipmi_ret_t checkVerify(UpdateInterface* updater, const uint8_t* reqBuf,
216 uint8_t* replyBuf, size_t* dataLen)
217{
218 auto value = updater->checkVerify();
219 replyBuf[0] = static_cast<uint8_t>(value);
220 (*dataLen) = 1;
221 return IPMI_CC_OK;
222}