1*bc419a1cSHuai-Cheng Kuo /* SPDX-License-Identifier: BSD-3-Clause */
2*bc419a1cSHuai-Cheng Kuo /*
3*bc419a1cSHuai-Cheng Kuo * QEMU SPDM socket support
4*bc419a1cSHuai-Cheng Kuo *
5*bc419a1cSHuai-Cheng Kuo * This is based on:
6*bc419a1cSHuai-Cheng Kuo * https://github.com/DMTF/spdm-emu/blob/07c0a838bcc1c6207c656ac75885c0603e344b6f/spdm_emu/spdm_emu_common/command.c
7*bc419a1cSHuai-Cheng Kuo * but has been re-written to match QEMU style
8*bc419a1cSHuai-Cheng Kuo *
9*bc419a1cSHuai-Cheng Kuo * Copyright (c) 2021, DMTF. All rights reserved.
10*bc419a1cSHuai-Cheng Kuo * Copyright (c) 2023. Western Digital Corporation or its affiliates.
11*bc419a1cSHuai-Cheng Kuo */
12*bc419a1cSHuai-Cheng Kuo
13*bc419a1cSHuai-Cheng Kuo #include "qemu/osdep.h"
14*bc419a1cSHuai-Cheng Kuo #include "sysemu/spdm-socket.h"
15*bc419a1cSHuai-Cheng Kuo #include "qapi/error.h"
16*bc419a1cSHuai-Cheng Kuo
read_bytes(const int socket,uint8_t * buffer,size_t number_of_bytes)17*bc419a1cSHuai-Cheng Kuo static bool read_bytes(const int socket, uint8_t *buffer,
18*bc419a1cSHuai-Cheng Kuo size_t number_of_bytes)
19*bc419a1cSHuai-Cheng Kuo {
20*bc419a1cSHuai-Cheng Kuo ssize_t number_received = 0;
21*bc419a1cSHuai-Cheng Kuo ssize_t result;
22*bc419a1cSHuai-Cheng Kuo
23*bc419a1cSHuai-Cheng Kuo while (number_received < number_of_bytes) {
24*bc419a1cSHuai-Cheng Kuo result = recv(socket, buffer + number_received,
25*bc419a1cSHuai-Cheng Kuo number_of_bytes - number_received, 0);
26*bc419a1cSHuai-Cheng Kuo if (result <= 0) {
27*bc419a1cSHuai-Cheng Kuo return false;
28*bc419a1cSHuai-Cheng Kuo }
29*bc419a1cSHuai-Cheng Kuo number_received += result;
30*bc419a1cSHuai-Cheng Kuo }
31*bc419a1cSHuai-Cheng Kuo return true;
32*bc419a1cSHuai-Cheng Kuo }
33*bc419a1cSHuai-Cheng Kuo
read_data32(const int socket,uint32_t * data)34*bc419a1cSHuai-Cheng Kuo static bool read_data32(const int socket, uint32_t *data)
35*bc419a1cSHuai-Cheng Kuo {
36*bc419a1cSHuai-Cheng Kuo bool result;
37*bc419a1cSHuai-Cheng Kuo
38*bc419a1cSHuai-Cheng Kuo result = read_bytes(socket, (uint8_t *)data, sizeof(uint32_t));
39*bc419a1cSHuai-Cheng Kuo if (!result) {
40*bc419a1cSHuai-Cheng Kuo return result;
41*bc419a1cSHuai-Cheng Kuo }
42*bc419a1cSHuai-Cheng Kuo *data = ntohl(*data);
43*bc419a1cSHuai-Cheng Kuo return true;
44*bc419a1cSHuai-Cheng Kuo }
45*bc419a1cSHuai-Cheng Kuo
read_multiple_bytes(const int socket,uint8_t * buffer,uint32_t * bytes_received,uint32_t max_buffer_length)46*bc419a1cSHuai-Cheng Kuo static bool read_multiple_bytes(const int socket, uint8_t *buffer,
47*bc419a1cSHuai-Cheng Kuo uint32_t *bytes_received,
48*bc419a1cSHuai-Cheng Kuo uint32_t max_buffer_length)
49*bc419a1cSHuai-Cheng Kuo {
50*bc419a1cSHuai-Cheng Kuo uint32_t length;
51*bc419a1cSHuai-Cheng Kuo bool result;
52*bc419a1cSHuai-Cheng Kuo
53*bc419a1cSHuai-Cheng Kuo result = read_data32(socket, &length);
54*bc419a1cSHuai-Cheng Kuo if (!result) {
55*bc419a1cSHuai-Cheng Kuo return result;
56*bc419a1cSHuai-Cheng Kuo }
57*bc419a1cSHuai-Cheng Kuo
58*bc419a1cSHuai-Cheng Kuo if (length > max_buffer_length) {
59*bc419a1cSHuai-Cheng Kuo return false;
60*bc419a1cSHuai-Cheng Kuo }
61*bc419a1cSHuai-Cheng Kuo
62*bc419a1cSHuai-Cheng Kuo if (bytes_received) {
63*bc419a1cSHuai-Cheng Kuo *bytes_received = length;
64*bc419a1cSHuai-Cheng Kuo }
65*bc419a1cSHuai-Cheng Kuo
66*bc419a1cSHuai-Cheng Kuo if (length == 0) {
67*bc419a1cSHuai-Cheng Kuo return true;
68*bc419a1cSHuai-Cheng Kuo }
69*bc419a1cSHuai-Cheng Kuo
70*bc419a1cSHuai-Cheng Kuo return read_bytes(socket, buffer, length);
71*bc419a1cSHuai-Cheng Kuo }
72*bc419a1cSHuai-Cheng Kuo
receive_platform_data(const int socket,uint32_t transport_type,uint32_t * command,uint8_t * receive_buffer,uint32_t * bytes_to_receive)73*bc419a1cSHuai-Cheng Kuo static bool receive_platform_data(const int socket,
74*bc419a1cSHuai-Cheng Kuo uint32_t transport_type,
75*bc419a1cSHuai-Cheng Kuo uint32_t *command,
76*bc419a1cSHuai-Cheng Kuo uint8_t *receive_buffer,
77*bc419a1cSHuai-Cheng Kuo uint32_t *bytes_to_receive)
78*bc419a1cSHuai-Cheng Kuo {
79*bc419a1cSHuai-Cheng Kuo bool result;
80*bc419a1cSHuai-Cheng Kuo uint32_t response;
81*bc419a1cSHuai-Cheng Kuo uint32_t bytes_received;
82*bc419a1cSHuai-Cheng Kuo
83*bc419a1cSHuai-Cheng Kuo result = read_data32(socket, &response);
84*bc419a1cSHuai-Cheng Kuo if (!result) {
85*bc419a1cSHuai-Cheng Kuo return result;
86*bc419a1cSHuai-Cheng Kuo }
87*bc419a1cSHuai-Cheng Kuo *command = response;
88*bc419a1cSHuai-Cheng Kuo
89*bc419a1cSHuai-Cheng Kuo result = read_data32(socket, &transport_type);
90*bc419a1cSHuai-Cheng Kuo if (!result) {
91*bc419a1cSHuai-Cheng Kuo return result;
92*bc419a1cSHuai-Cheng Kuo }
93*bc419a1cSHuai-Cheng Kuo
94*bc419a1cSHuai-Cheng Kuo bytes_received = 0;
95*bc419a1cSHuai-Cheng Kuo result = read_multiple_bytes(socket, receive_buffer, &bytes_received,
96*bc419a1cSHuai-Cheng Kuo *bytes_to_receive);
97*bc419a1cSHuai-Cheng Kuo if (!result) {
98*bc419a1cSHuai-Cheng Kuo return result;
99*bc419a1cSHuai-Cheng Kuo }
100*bc419a1cSHuai-Cheng Kuo *bytes_to_receive = bytes_received;
101*bc419a1cSHuai-Cheng Kuo
102*bc419a1cSHuai-Cheng Kuo return result;
103*bc419a1cSHuai-Cheng Kuo }
104*bc419a1cSHuai-Cheng Kuo
write_bytes(const int socket,const uint8_t * buffer,uint32_t number_of_bytes)105*bc419a1cSHuai-Cheng Kuo static bool write_bytes(const int socket, const uint8_t *buffer,
106*bc419a1cSHuai-Cheng Kuo uint32_t number_of_bytes)
107*bc419a1cSHuai-Cheng Kuo {
108*bc419a1cSHuai-Cheng Kuo ssize_t number_sent = 0;
109*bc419a1cSHuai-Cheng Kuo ssize_t result;
110*bc419a1cSHuai-Cheng Kuo
111*bc419a1cSHuai-Cheng Kuo while (number_sent < number_of_bytes) {
112*bc419a1cSHuai-Cheng Kuo result = send(socket, buffer + number_sent,
113*bc419a1cSHuai-Cheng Kuo number_of_bytes - number_sent, 0);
114*bc419a1cSHuai-Cheng Kuo if (result == -1) {
115*bc419a1cSHuai-Cheng Kuo return false;
116*bc419a1cSHuai-Cheng Kuo }
117*bc419a1cSHuai-Cheng Kuo number_sent += result;
118*bc419a1cSHuai-Cheng Kuo }
119*bc419a1cSHuai-Cheng Kuo return true;
120*bc419a1cSHuai-Cheng Kuo }
121*bc419a1cSHuai-Cheng Kuo
write_data32(const int socket,uint32_t data)122*bc419a1cSHuai-Cheng Kuo static bool write_data32(const int socket, uint32_t data)
123*bc419a1cSHuai-Cheng Kuo {
124*bc419a1cSHuai-Cheng Kuo data = htonl(data);
125*bc419a1cSHuai-Cheng Kuo return write_bytes(socket, (uint8_t *)&data, sizeof(uint32_t));
126*bc419a1cSHuai-Cheng Kuo }
127*bc419a1cSHuai-Cheng Kuo
write_multiple_bytes(const int socket,const uint8_t * buffer,uint32_t bytes_to_send)128*bc419a1cSHuai-Cheng Kuo static bool write_multiple_bytes(const int socket, const uint8_t *buffer,
129*bc419a1cSHuai-Cheng Kuo uint32_t bytes_to_send)
130*bc419a1cSHuai-Cheng Kuo {
131*bc419a1cSHuai-Cheng Kuo bool result;
132*bc419a1cSHuai-Cheng Kuo
133*bc419a1cSHuai-Cheng Kuo result = write_data32(socket, bytes_to_send);
134*bc419a1cSHuai-Cheng Kuo if (!result) {
135*bc419a1cSHuai-Cheng Kuo return result;
136*bc419a1cSHuai-Cheng Kuo }
137*bc419a1cSHuai-Cheng Kuo
138*bc419a1cSHuai-Cheng Kuo return write_bytes(socket, buffer, bytes_to_send);
139*bc419a1cSHuai-Cheng Kuo }
140*bc419a1cSHuai-Cheng Kuo
send_platform_data(const int socket,uint32_t transport_type,uint32_t command,const uint8_t * send_buffer,size_t bytes_to_send)141*bc419a1cSHuai-Cheng Kuo static bool send_platform_data(const int socket,
142*bc419a1cSHuai-Cheng Kuo uint32_t transport_type, uint32_t command,
143*bc419a1cSHuai-Cheng Kuo const uint8_t *send_buffer, size_t bytes_to_send)
144*bc419a1cSHuai-Cheng Kuo {
145*bc419a1cSHuai-Cheng Kuo bool result;
146*bc419a1cSHuai-Cheng Kuo
147*bc419a1cSHuai-Cheng Kuo result = write_data32(socket, command);
148*bc419a1cSHuai-Cheng Kuo if (!result) {
149*bc419a1cSHuai-Cheng Kuo return result;
150*bc419a1cSHuai-Cheng Kuo }
151*bc419a1cSHuai-Cheng Kuo
152*bc419a1cSHuai-Cheng Kuo result = write_data32(socket, transport_type);
153*bc419a1cSHuai-Cheng Kuo if (!result) {
154*bc419a1cSHuai-Cheng Kuo return result;
155*bc419a1cSHuai-Cheng Kuo }
156*bc419a1cSHuai-Cheng Kuo
157*bc419a1cSHuai-Cheng Kuo return write_multiple_bytes(socket, send_buffer, bytes_to_send);
158*bc419a1cSHuai-Cheng Kuo }
159*bc419a1cSHuai-Cheng Kuo
spdm_socket_connect(uint16_t port,Error ** errp)160*bc419a1cSHuai-Cheng Kuo int spdm_socket_connect(uint16_t port, Error **errp)
161*bc419a1cSHuai-Cheng Kuo {
162*bc419a1cSHuai-Cheng Kuo int client_socket;
163*bc419a1cSHuai-Cheng Kuo struct sockaddr_in server_addr;
164*bc419a1cSHuai-Cheng Kuo
165*bc419a1cSHuai-Cheng Kuo client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
166*bc419a1cSHuai-Cheng Kuo if (client_socket < 0) {
167*bc419a1cSHuai-Cheng Kuo error_setg(errp, "cannot create socket: %s", strerror(errno));
168*bc419a1cSHuai-Cheng Kuo return -1;
169*bc419a1cSHuai-Cheng Kuo }
170*bc419a1cSHuai-Cheng Kuo
171*bc419a1cSHuai-Cheng Kuo memset((char *)&server_addr, 0, sizeof(server_addr));
172*bc419a1cSHuai-Cheng Kuo server_addr.sin_family = AF_INET;
173*bc419a1cSHuai-Cheng Kuo server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
174*bc419a1cSHuai-Cheng Kuo server_addr.sin_port = htons(port);
175*bc419a1cSHuai-Cheng Kuo
176*bc419a1cSHuai-Cheng Kuo
177*bc419a1cSHuai-Cheng Kuo if (connect(client_socket, (struct sockaddr *)&server_addr,
178*bc419a1cSHuai-Cheng Kuo sizeof(server_addr)) < 0) {
179*bc419a1cSHuai-Cheng Kuo error_setg(errp, "cannot connect: %s", strerror(errno));
180*bc419a1cSHuai-Cheng Kuo close(client_socket);
181*bc419a1cSHuai-Cheng Kuo return -1;
182*bc419a1cSHuai-Cheng Kuo }
183*bc419a1cSHuai-Cheng Kuo
184*bc419a1cSHuai-Cheng Kuo return client_socket;
185*bc419a1cSHuai-Cheng Kuo }
186*bc419a1cSHuai-Cheng Kuo
spdm_socket_rsp(const int socket,uint32_t transport_type,void * req,uint32_t req_len,void * rsp,uint32_t rsp_len)187*bc419a1cSHuai-Cheng Kuo uint32_t spdm_socket_rsp(const int socket, uint32_t transport_type,
188*bc419a1cSHuai-Cheng Kuo void *req, uint32_t req_len,
189*bc419a1cSHuai-Cheng Kuo void *rsp, uint32_t rsp_len)
190*bc419a1cSHuai-Cheng Kuo {
191*bc419a1cSHuai-Cheng Kuo uint32_t command;
192*bc419a1cSHuai-Cheng Kuo bool result;
193*bc419a1cSHuai-Cheng Kuo
194*bc419a1cSHuai-Cheng Kuo result = send_platform_data(socket, transport_type,
195*bc419a1cSHuai-Cheng Kuo SPDM_SOCKET_COMMAND_NORMAL,
196*bc419a1cSHuai-Cheng Kuo req, req_len);
197*bc419a1cSHuai-Cheng Kuo if (!result) {
198*bc419a1cSHuai-Cheng Kuo return 0;
199*bc419a1cSHuai-Cheng Kuo }
200*bc419a1cSHuai-Cheng Kuo
201*bc419a1cSHuai-Cheng Kuo result = receive_platform_data(socket, transport_type, &command,
202*bc419a1cSHuai-Cheng Kuo (uint8_t *)rsp, &rsp_len);
203*bc419a1cSHuai-Cheng Kuo if (!result) {
204*bc419a1cSHuai-Cheng Kuo return 0;
205*bc419a1cSHuai-Cheng Kuo }
206*bc419a1cSHuai-Cheng Kuo
207*bc419a1cSHuai-Cheng Kuo assert(command != 0);
208*bc419a1cSHuai-Cheng Kuo
209*bc419a1cSHuai-Cheng Kuo return rsp_len;
210*bc419a1cSHuai-Cheng Kuo }
211*bc419a1cSHuai-Cheng Kuo
spdm_socket_close(const int socket,uint32_t transport_type)212*bc419a1cSHuai-Cheng Kuo void spdm_socket_close(const int socket, uint32_t transport_type)
213*bc419a1cSHuai-Cheng Kuo {
214*bc419a1cSHuai-Cheng Kuo send_platform_data(socket, transport_type,
215*bc419a1cSHuai-Cheng Kuo SPDM_SOCKET_COMMAND_SHUTDOWN, NULL, 0);
216*bc419a1cSHuai-Cheng Kuo }
217