xref: /openbmc/qemu/backends/spdm-socket.c (revision 5885bcef3d760e84d17eb4113e85f2aea0bd0582)
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