1 /*
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 
initalize_shared_memory(struct rpc_caller_session * session,struct rpc_caller_interface * caller,size_t shared_memory_size)11 static 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 
rpc_caller_session_open(struct rpc_caller_session * session,struct rpc_caller_interface * caller,const struct rpc_uuid * service_uuid,uint16_t endpoint_id,size_t shared_memory_size)34 rpc_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 
rpc_caller_session_find_and_open(struct rpc_caller_session * session,struct rpc_caller_interface * caller,const struct rpc_uuid * service_uuid,size_t shared_memory_size)60 rpc_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 
rpc_caller_session_close(struct rpc_caller_session * session)85 rpc_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 
rpc_caller_session_begin(struct rpc_caller_session * session,uint8_t ** request_buffer,size_t request_length,size_t response_max_length)105 rpc_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 
rpc_caller_session_invoke(rpc_call_handle handle,uint32_t opcode,uint8_t ** response_buffer,size_t * response_length,service_status_t * service_status)150 rpc_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 
rpc_caller_session_end(rpc_call_handle handle)180 rpc_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 }
218