@@ -179,36 +179,58 @@ struct nvme_mi_msg_resp_mpr {
179179 * populate the worst-case expected processing time, given in milliseconds.
180180 */
181181static bool nvme_mi_mctp_resp_is_mpr (struct nvme_mi_resp * resp , size_t len ,
182- unsigned int * mpr_time )
182+ __le32 mic , unsigned int * mpr_time )
183183{
184+ struct nvme_mi_admin_resp_hdr * admin_msg ;
184185 struct nvme_mi_msg_resp_mpr * msg ;
185- __le32 mic ;
186+ size_t clen ;
186187 __u32 crc ;
187188
188- if (len != sizeof (* msg ) + sizeof (mic ))
189+ /* We need at least the minimal header plus checksum */
190+ if (len < sizeof (* msg ) + sizeof (mic ))
189191 return false;
190192
191193 msg = (struct nvme_mi_msg_resp_mpr * )resp -> hdr ;
192194
193195 if (msg -> status != NVME_MI_RESP_MPR )
194196 return false;
195197
196- /* We can't use verify_resp_mic here, as the response structure has
197- * not been laid-out properly in resp yet (this is deferred until
198- * we have the actual response).
198+ /* Find and verify the MIC from the response, which may not be laid out
199+ * in resp as we expect. We have to preserve resp->hdr_len and
200+ * resp->data_len, as we will need them for the eventual reply message.
201+ * Because of that, we can't use verify_resp_mic here.
199202 *
200- * We know the data is a fixed size, and linear in the hdr buf, so
201- * calculation is fairly simple. We do need to find the MIC data
202- * though, which could either be in the header buf (if the original
203- * header was larger than the minimal header message), or the start of
204- * the data buf (otherwise).
203+ * If the packet was at the expected response size, then mic will
204+ * be set already; if not, find it within the header/data buffers.
205+ */
206+
207+ /* Devices may send a MPR response as a full-sized Admin response,
208+ * rather than the minimal MI-only header. Allow this, but only if the
209+ * type indicates admin, and the allocated response header is the
210+ * correct size for an Admin response.
211+ */
212+ if (((msg -> hdr .nmp >> 3 ) & 0xf ) == NVME_MI_MT_ADMIN &&
213+ len == sizeof (* admin_msg ) + sizeof (mic ) &&
214+ resp -> hdr_len == sizeof (* admin_msg )) {
215+ if (resp -> data_len )
216+ mic = * (__le32 * )resp -> data ;
217+ } else if (len == sizeof (* msg ) + sizeof (mic )) {
218+ if (resp -> hdr_len > sizeof (* msg ))
219+ mic = * (__le32 * )(msg + 1 );
220+ else if (resp -> data_len )
221+ mic = * (__le32 * )(resp -> data );
222+ } else {
223+ return false;
224+ }
225+
226+ /* Since our response is just a header, we're guaranteed to have
227+ * all data in resp->hdr. The response may be shorter than the expected
228+ * header though, so clamp to len.
205229 */
206- if (resp -> hdr_len > sizeof (* msg ))
207- mic = * (__le32 * )(msg + 1 );
208- else
209- mic = * (__le32 * )(resp -> data );
230+ len -= sizeof (mic );
231+ clen = len < resp -> hdr_len ? len : resp -> hdr_len ;
210232
211- crc = ~nvme_mi_crc32_update (0xffffffff , msg , sizeof ( * msg ) );
233+ crc = ~nvme_mi_crc32_update (0xffffffff , resp -> hdr , clen );
212234 if (le32_to_cpu (mic ) != crc )
213235 return false;
214236
@@ -369,7 +391,7 @@ static int nvme_mi_mctp_submit(struct nvme_mi_ep *ep,
369391 * header fields. However, we need to do this in the transport in order
370392 * to keep the tag allocated and retry the recvmsg
371393 */
372- if (nvme_mi_mctp_resp_is_mpr (resp , len , & mpr_time )) {
394+ if (nvme_mi_mctp_resp_is_mpr (resp , len , mic , & mpr_time )) {
373395 nvme_msg (ep -> root , LOG_DEBUG ,
374396 "Received More Processing Required, waiting for response\n" );
375397
0 commit comments