blob: 50269b0731e2636e1cc90b71d33dddac373c73f5 [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 Venture9a5a79a2018-08-03 17:23:57 -070035 };
36
37 auto results = subHandlers.find(command);
38 if (results == subHandlers.end())
39 {
40 return nullptr;
41 }
42
43 return results->second;
44}
45
Patrick Venturea53a7b32018-08-03 09:15:20 -070046bool validateRequestLength(FlashSubCmds command, size_t requestLen)
47{
48 static const std::unordered_map<FlashSubCmds, size_t> minimumLengths = {
49 {FlashSubCmds::flashStartTransfer, sizeof(struct StartTx)},
50 {FlashSubCmds::flashDataBlock, sizeof(struct ChunkHdr) + 1},
Patrick Venture8d9f7322018-08-03 10:39:13 -070051 {FlashSubCmds::flashStartHash, sizeof(struct StartTx)},
Patrick Venturecfe66872018-08-03 13:32:33 -070052 {FlashSubCmds::flashHashData, sizeof(struct ChunkHdr) + 1},
Patrick Venturea53a7b32018-08-03 09:15:20 -070053 };
54
55 auto results = minimumLengths.find(command);
56 if (results == minimumLengths.end())
57 {
58 /* Valid length by default if we don't care. */
59 return true;
60 }
61
62 /* If the request is shorter than the minimum, it's invalid. */
63 if (requestLen < results->second)
64 {
65 return false;
66 }
67
68 return true;
69}
70
Patrick Venture54c3b532018-08-01 11:45:49 -070071ipmi_ret_t startTransfer(UpdateInterface* updater, const uint8_t* reqBuf,
72 uint8_t* replyBuf, size_t* dataLen)
73{
Patrick Venture54c3b532018-08-01 11:45:49 -070074 auto request = reinterpret_cast<const struct StartTx*>(reqBuf);
75
76 if (!updater->start(request->length))
77 {
78 return IPMI_CC_INVALID;
79 }
80
81 /* We were successful and set the response byte to 0. */
82 replyBuf[0] = 0x00;
83 (*dataLen) = 1;
84 return IPMI_CC_OK;
85}
Patrick Venture79e131f2018-08-01 13:34:35 -070086
87ipmi_ret_t dataBlock(UpdateInterface* updater, const uint8_t* reqBuf,
88 uint8_t* replyBuf, size_t* dataLen)
89{
Patrick Venture79e131f2018-08-01 13:34:35 -070090 struct ChunkHdr hdr;
91 std::memcpy(&hdr, reqBuf, sizeof(hdr));
92
Patrick Venturecfe66872018-08-03 13:32:33 -070093 auto requestLength = *dataLen;
Patrick Venturea53a7b32018-08-03 09:15:20 -070094
Patrick Venture79e131f2018-08-01 13:34:35 -070095 /* Grab the bytes from the packet. */
Patrick Venturecfe66872018-08-03 13:32:33 -070096 auto bytesLength = requestLength - sizeof(struct ChunkHdr);
Patrick Venture79e131f2018-08-01 13:34:35 -070097 std::vector<uint8_t> bytes(bytesLength);
98 std::memcpy(bytes.data(), &reqBuf[sizeof(struct ChunkHdr)], bytesLength);
99
100 if (!updater->flashData(hdr.offset, bytes))
101 {
102 return IPMI_CC_INVALID;
103 }
104
105 /* We were successful and set the response byte to 0. */
106 replyBuf[0] = 0x00;
107 (*dataLen) = 1;
108 return IPMI_CC_OK;
109}
Patrick Venture2c1205d2018-08-03 10:23:14 -0700110
111ipmi_ret_t dataFinish(UpdateInterface* updater, const uint8_t* reqBuf,
112 uint8_t* replyBuf, size_t* dataLen)
113{
114 if (!updater->flashFinish())
115 {
116 return IPMI_CC_INVALID;
117 }
118
119 /* TODO: If all commands return this on success, handle it in one place. */
120
121 /* We were successful and set the response byte to 0. */
122 replyBuf[0] = 0x00;
123 (*dataLen) = 1;
124 return IPMI_CC_OK;
125}
Patrick Venture8d9f7322018-08-03 10:39:13 -0700126
127ipmi_ret_t startHash(UpdateInterface* updater, const uint8_t* reqBuf,
128 uint8_t* replyBuf, size_t* dataLen)
129{
130 auto request = reinterpret_cast<const struct StartTx*>(reqBuf);
131
132 if (!updater->startHash(request->length))
133 {
134 return IPMI_CC_INVALID;
135 }
136
137 /* We were successful and set the response byte to 0. */
138 replyBuf[0] = 0x00;
139 (*dataLen) = 1;
140 return IPMI_CC_OK;
141}
Patrick Venturecfe66872018-08-03 13:32:33 -0700142
143ipmi_ret_t hashBlock(UpdateInterface* updater, const uint8_t* reqBuf,
144 uint8_t* replyBuf, size_t* dataLen)
145{
146 struct ChunkHdr hdr;
147 std::memcpy(&hdr, reqBuf, sizeof(hdr));
148
149 auto requestLength = *dataLen;
150
151 /* Grab the bytes from the packet. */
152 auto bytesLength = requestLength - sizeof(struct ChunkHdr);
153 std::vector<uint8_t> bytes(bytesLength);
154 std::memcpy(bytes.data(), &reqBuf[sizeof(struct ChunkHdr)], bytesLength);
155
156 /* TODO: Refactor this and dataBlock for re-use. */
157
158 if (!updater->hashData(hdr.offset, bytes))
159 {
160 return IPMI_CC_INVALID;
161 }
162
163 /* We were successful and set the response byte to 0. */
164 replyBuf[0] = 0x00;
165 (*dataLen) = 1;
166 return IPMI_CC_OK;
167}
Patrick Venturefbc7d192018-08-03 13:54:21 -0700168
169ipmi_ret_t hashFinish(UpdateInterface* updater, const uint8_t* reqBuf,
170 uint8_t* replyBuf, size_t* dataLen)
171{
172 if (!updater->hashFinish())
173 {
174 return IPMI_CC_INVALID;
175 }
176
177 /* We were successful and set the response byte to 0. */
178 replyBuf[0] = 0x00;
179 (*dataLen) = 1;
180 return IPMI_CC_OK;
181}
Patrick Venture1cb87d22018-08-03 18:22:09 -0700182
183ipmi_ret_t dataVerify(UpdateInterface* updater, const uint8_t* reqBuf,
184 uint8_t* replyBuf, size_t* dataLen)
185{
186 if (!updater->startDataVerification())
187 {
188 return IPMI_CC_INVALID;
189 }
190
191 /* We were successful and set the response byte to 0. */
192 replyBuf[0] = 0x00;
193 (*dataLen) = 1;
194 return IPMI_CC_OK;
195}
Patrick Venture5c251ca2018-08-03 18:31:01 -0700196
197ipmi_ret_t abortUpdate(UpdateInterface* updater, const uint8_t* reqBuf,
198 uint8_t* replyBuf, size_t* dataLen)
199{
200 /* TODO: May make sense to work all the pass-through commands into one
201 * piece of code
202 */
203 if (!updater->abortUpdate())
204 {
205 return IPMI_CC_INVALID;
206 }
207
208 /* We were successful and set the response byte to 0. */
209 replyBuf[0] = 0x00;
210 (*dataLen) = 1;
211 return IPMI_CC_OK;
212}