blob: d72a318153d749de3277e9924a77fe1a3e28fb3f [file] [log] [blame]
Imre Kis782376d2023-06-21 18:49:58 +02001/*
2 * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "rpc_caller_session.h"
8#include "util.h"
9#include <string.h>
10
11static rpc_status_t initalize_shared_memory(struct rpc_caller_session *session,
12 struct rpc_caller_interface *caller,
13 size_t shared_memory_size)
14{
15 if (shared_memory_size) {
16 rpc_status_t status = RPC_ERROR_INTERNAL;
17
18 status = rpc_caller_create_shared_memory(caller, shared_memory_size,
19 &session->shared_memory);
20 if (status) {
21 rpc_caller_close_session(caller);
22 return status;
23 }
24
25 session->shared_memory_policy = alloc_for_session;
26 } else {
27 session->shared_memory = (struct rpc_caller_shared_memory){ 0 };
28 session->shared_memory_policy = alloc_for_each_call;
29 }
30
31 return RPC_SUCCESS;
32}
33
34rpc_status_t rpc_caller_session_open(struct rpc_caller_session *session,
35 struct rpc_caller_interface *caller,
36 const struct rpc_uuid *service_uuid,
37 uint16_t endpoint_id,
38 size_t shared_memory_size)
39{
40 rpc_status_t status = RPC_ERROR_INTERNAL;
41
42 if (!session || !caller || !service_uuid)
43 return RPC_ERROR_INVALID_VALUE;
44
45 status = rpc_caller_open_session(caller, service_uuid, endpoint_id);
46 if (status)
47 return status;
48
49 status = initalize_shared_memory(session, caller, shared_memory_size);
50 if (status)
51 return status;
52
53 session->caller = caller;
54 session->is_call_transaction_in_progress = false;
55 session->request_length = 0;
56
57 return status;
58}
59
60rpc_status_t rpc_caller_session_find_and_open(struct rpc_caller_session *session,
61 struct rpc_caller_interface *caller,
62 const struct rpc_uuid *service_uuid,
63 size_t shared_memory_size)
64{
65 rpc_status_t status = RPC_ERROR_INTERNAL;
66
67 if (!session || !caller || !service_uuid)
68 return RPC_ERROR_INVALID_VALUE;
69
70 status = rpc_caller_find_and_open_session(caller, service_uuid);
71 if (status)
72 return status;
73
74 status = initalize_shared_memory(session, caller, shared_memory_size);
75 if (status)
76 return status;
77
78 session->caller = caller;
79 session->is_call_transaction_in_progress = false;
80 session->request_length = 0;
81
82 return status;
83}
84
85rpc_status_t rpc_caller_session_close(struct rpc_caller_session *session)
86{
87 if (!session)
88 return RPC_ERROR_INVALID_VALUE;
89
90 if (session->is_call_transaction_in_progress)
91 return RPC_ERROR_INVALID_STATE;
92
93 if (session->shared_memory_policy == alloc_for_session) {
94 rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
95
96 rpc_status = rpc_caller_release_shared_memory(session->caller,
97 &session->shared_memory);
98 if (rpc_status != RPC_SUCCESS)
99 return rpc_status;
100 }
101
102 return rpc_caller_close_session(session->caller);
103}
104
105rpc_call_handle rpc_caller_session_begin(struct rpc_caller_session *session,
106 uint8_t **request_buffer, size_t request_length,
107 size_t response_max_length)
108{
109 rpc_status_t status = RPC_ERROR_INTERNAL;
110 size_t required_buffer_length = MAX(request_length, response_max_length);
111
112 if (required_buffer_length > UINT32_MAX)
113 return NULL;
114
115 if (!session || !request_buffer || session->is_call_transaction_in_progress)
116 return NULL;
117
118 switch (session->shared_memory_policy) {
119 case alloc_for_each_call:
120 if (session->shared_memory.buffer || session->shared_memory.size)
121 return NULL; /* There's already a shared memory */
122
123 status = rpc_caller_create_shared_memory(session->caller, required_buffer_length,
124 &session->shared_memory);
125 if (status)
126 return NULL; /* Failed to create shared memory */
127 break;
128
129 case alloc_for_session:
130 if (!session->shared_memory.buffer || !session->shared_memory.size)
131 return NULL; /* There's no shared memory */
132
133 if (session->shared_memory.size < required_buffer_length)
134 return NULL; /* The allocated shared memory is too small */
135 break;
136
137 default:
138 /* Invalid shared memory policy */
139 return NULL;
140 }
141
142 *request_buffer = session->shared_memory.buffer;
143
144 session->is_call_transaction_in_progress = true;
145 session->request_length = request_length;
146
147 return (rpc_call_handle)session;
148}
149
150rpc_status_t rpc_caller_session_invoke(rpc_call_handle handle, uint32_t opcode,
151 uint8_t **response_buffer, size_t *response_length,
152 service_status_t *service_status)
153{
154 struct rpc_caller_session *session = (struct rpc_caller_session *)handle;
155 rpc_status_t status = RPC_ERROR_INTERNAL;
156
157 if (!handle || !response_buffer || !response_length)
158 return RPC_ERROR_INVALID_VALUE;
159
160 if (!session->is_call_transaction_in_progress)
161 return RPC_ERROR_INVALID_STATE;
162
163 if (session->request_length &&
164 (!session->shared_memory.buffer || !session->shared_memory.size))
165 return RPC_ERROR_INVALID_STATE;
166
167 status = rpc_caller_call(session->caller, opcode, &session->shared_memory,
168 session->request_length, response_length, service_status);
169 if (status || *response_length > session->shared_memory.size) {
170 *response_buffer = NULL;
171 *response_length = 0;
172 return status;
173 }
174
175 *response_buffer = session->shared_memory.buffer;
176
177 return status;
178}
179
180rpc_status_t rpc_caller_session_end(rpc_call_handle handle)
181{
182 struct rpc_caller_session *session = (struct rpc_caller_session *)handle;
183 rpc_status_t status = RPC_ERROR_INTERNAL;
184
185 if (!handle)
186 return RPC_ERROR_INVALID_VALUE;
187
188 if (!session->is_call_transaction_in_progress)
189 return RPC_ERROR_INVALID_STATE;
190
191 if (session->request_length &&
192 (!session->shared_memory.buffer || !session->shared_memory.size))
193 return RPC_ERROR_INVALID_STATE; /* There's no shared memory */
194
195 switch (session->shared_memory_policy) {
196 case alloc_for_each_call:
197 status = rpc_caller_release_shared_memory(session->caller,
198 &session->shared_memory);
199 if (status)
200 return status; /* Failed to release shared memory */
201
202 session->shared_memory = (struct rpc_caller_shared_memory){ 0 };
203 break;
204
205 case alloc_for_session:
206 /* Nothing to do */
207 break;
208
209 default:
210 return RPC_ERROR_INVALID_STATE;
211 }
212
213 session->is_call_transaction_in_progress = false;
214 session->request_length = 0;
215
216 return RPC_SUCCESS;
217}