a0c627409eaaf7a1543c50a852cfcf5d32fe45fb
1 /**\r
2 * @file rm_transport.c\r
3 *\r
4 * @brief \r
5 * This is the Resource Manager transport source.\r
6 *\r
7 * \par\r
8 * ============================================================================\r
9 * @n (C) Copyright 2012-2013, Texas Instruments, Inc.\r
10 * \r
11 * Redistribution and use in source and binary forms, with or without \r
12 * modification, are permitted provided that the following conditions \r
13 * are met:\r
14 *\r
15 * Redistributions of source code must retain the above copyright \r
16 * notice, this list of conditions and the following disclaimer.\r
17 *\r
18 * Redistributions in binary form must reproduce the above copyright\r
19 * notice, this list of conditions and the following disclaimer in the \r
20 * documentation and/or other materials provided with the \r
21 * distribution.\r
22 *\r
23 * Neither the name of Texas Instruments Incorporated nor the names of\r
24 * its contributors may be used to endorse or promote products derived\r
25 * from this software without specific prior written permission.\r
26 *\r
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
38 *\r
39 * \par\r
40 */\r
41 \r
42 /* Standard includes */\r
43 #include <string.h>\r
44 \r
45 /* RM external includes */\r
46 #include <ti/drv/rm/rm.h>\r
47 #include <ti/drv/rm/rm_transport.h>\r
48 \r
49 /* RM internal includes */\r
50 #include <ti/drv/rm/include/rm_loc.h>\r
51 #include <ti/drv/rm/include/rm_transportloc.h>\r
52 \r
53 /* RM OSAL layer */\r
54 #include <rm_osal.h>\r
55 \r
56 /**********************************************************************\r
57 ************************ Local Functions *****************************\r
58 **********************************************************************/\r
59 \r
60 /* FUNCTION PURPOSE: Adds a transport\r
61 ***********************************************************************\r
62 * DESCRIPTION: Returns a pointer to a transport structure that\r
63 * was created, initialized, and added to the \r
64 * instance transport list.\r
65 */\r
66 static Rm_Transport *transportAdd(const Rm_TransportCfg *transportCfg)\r
67 {\r
68 Rm_Inst *rmInst = (Rm_Inst *) transportCfg->rmHandle;\r
69 Rm_Transport *transports = rmInst->transports;\r
70 Rm_Transport *newTransport = NULL;\r
71 \r
72 newTransport = Rm_osalMalloc (sizeof(Rm_Transport));\r
73 memset((void *)newTransport, 0, sizeof(Rm_Transport));\r
74 \r
75 if (newTransport) {\r
76 newTransport->rmHandle = transportCfg->rmHandle;\r
77 newTransport->appTransportHandle = transportCfg->appTransportHandle;\r
78 newTransport->remoteInstType = transportCfg->remoteInstType;\r
79 strncpy(newTransport->remoteInstName, transportCfg->remoteInstName, RM_NAME_MAX_CHARS);\r
80 newTransport->callouts.rmAllocPkt = transportCfg->transportCallouts.rmAllocPkt;\r
81 newTransport->callouts.rmSendPkt = transportCfg->transportCallouts.rmSendPkt;\r
82 newTransport->nextTransport = NULL;\r
83 \r
84 if (transports) {\r
85 while (transports->nextTransport) {\r
86 transports = transports->nextTransport;\r
87 }\r
88 transports->nextTransport = newTransport;\r
89 }\r
90 else {\r
91 rmInst->transports = newTransport;\r
92 }\r
93 }\r
94 return (newTransport);\r
95 }\r
96 \r
97 /* FUNCTION PURPOSE: Tests if a transport is registered to an instance\r
98 ***********************************************************************\r
99 * DESCRIPTION: Returns TRUE if the supplied transport is found in\r
100 * the instance transport list. Otherwise, returns FALSE\r
101 */\r
102 static int transportIsRegistered(Rm_Handle rmHandle, Rm_Transport *transport)\r
103 {\r
104 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;\r
105 Rm_Transport *transportList = (Rm_Transport *)rmInst->transports;\r
106 \r
107 while (transportList) {\r
108 if (transportList == transport) {\r
109 return(RM_TRUE); \r
110 }\r
111 transportList = transportList->nextTransport;\r
112 }\r
113 return (RM_FALSE);\r
114 }\r
115 \r
116 /* FUNCTION PURPOSE: Deletes a transport\r
117 ***********************************************************************\r
118 * DESCRIPTION: Removes a transport from an instance transport list\r
119 * and then frees the memory associated with the transport\r
120 * data structure\r
121 */\r
122 static void transportDelete(Rm_Transport *transport)\r
123 {\r
124 Rm_Inst *rmInst = (Rm_Inst *)transport->rmHandle;\r
125 Rm_Transport *transportList = (Rm_Transport *)rmInst->transports;\r
126 Rm_Transport *prevTransport = NULL;\r
127 \r
128 /* Get previous transport in list */\r
129 while (transportList) {\r
130 if (transportList == transport) {\r
131 break; \r
132 }\r
133 prevTransport = transportList;\r
134 transportList = transportList->nextTransport;\r
135 }\r
136 \r
137 if (prevTransport == NULL) {\r
138 rmInst->transports = transport->nextTransport;\r
139 }\r
140 else {\r
141 prevTransport->nextTransport = transport->nextTransport;\r
142 }\r
143 Rm_osalFree((void *)transport, sizeof(Rm_Transport));\r
144 }\r
145 \r
146 /**********************************************************************\r
147 ********************** Internal Functions ****************************\r
148 **********************************************************************/\r
149 \r
150 /* FUNCTION PURPOSE: Finds a transport based on remote inst name\r
151 ***********************************************************************\r
152 * DESCRIPTION: Returns a pointer to the transport within an instance's\r
153 * transport list that matches the provided remote\r
154 * instance name. NULL is returned if no transports in \r
155 * the list match the remote instance name.\r
156 */\r
157 Rm_Transport *rmTransportFindRemoteName(Rm_Transport *transports, char *remoteName)\r
158 {\r
159 while (transports) {\r
160 if (strncmp(transports->remoteInstName, remoteName, RM_NAME_MAX_CHARS) == 0) {\r
161 break; \r
162 }\r
163 transports = transports->nextTransport;\r
164 }\r
165 return (transports);\r
166 }\r
167 \r
168 /* FUNCTION PURPOSE: Finds a transport based on remote inst type\r
169 ***********************************************************************\r
170 * DESCRIPTION: Returns a pointer to the transport within an instance's\r
171 * transport list that matches the provided remote\r
172 * instance type. NULL is returned if no transports in \r
173 * the list match the remote instance type.\r
174 */\r
175 Rm_Transport *rmTransportFindRemoteInstType(Rm_Transport *transports, Rm_InstType remoteInstType)\r
176 {\r
177 while (transports) {\r
178 if (transports->remoteInstType == remoteInstType) {\r
179 break; \r
180 }\r
181 transports = transports->nextTransport;\r
182 }\r
183 return (transports);\r
184 }\r
185 \r
186 /**********************************************************************\r
187 ********************* Application visible APIs ***********************\r
188 **********************************************************************/\r
189 \r
190 /* FUNCTION PURPOSE: Registers an app transport with a RM instance\r
191 ***********************************************************************\r
192 * DESCRIPTION: Returns a transport handle to the application that\r
193 * has been registered with an RM instance. The handle\r
194 * is used by the application to route packets to the\r
195 * proper RM instance's based on the application\r
196 * transport receive code. The handle is also used\r
197 * internally by RM to route request and response \r
198 * packets to the correct application transports. NULL\r
199 * is returned for the transport handle if any errors\r
200 * are encountered.\r
201 */\r
202 Rm_TransportHandle Rm_transportRegister (const Rm_TransportCfg *transportCfg, int32_t *result)\r
203 {\r
204 Rm_Inst *rmInst = (Rm_Inst *) transportCfg->rmHandle;\r
205 Rm_Transport *transport = NULL;\r
206 void *key;\r
207 \r
208 *result = RM_OK;\r
209 \r
210 RM_SS_INST_INV_ENTER_CS(key);\r
211 \r
212 /* Shared servers and clients cannot connect to anyone */\r
213 if ((rmInst->instType == Rm_instType_SHARED_SERVER) ||\r
214 (rmInst->instType == Rm_instType_SHARED_CLIENT)){\r
215 *result = RM_ERROR_SHARED_INSTANCE_CANNOT_REG_TRANS;\r
216 goto errorExit;\r
217 }\r
218 \r
219 /* No one can connect to a shared server\r
220 * RM Servers cannot connect to other Servers. \r
221 * RM Client Delegates cannot connect to other Client Delegates.\r
222 * RM Clients cannot connect to other Clients */\r
223 if ((transportCfg->remoteInstType == Rm_instType_SHARED_SERVER) ||\r
224 ((rmInst->instType == Rm_instType_SERVER) &&\r
225 (transportCfg->remoteInstType == Rm_instType_SERVER)) ||\r
226 ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
227 (transportCfg->remoteInstType == Rm_instType_CLIENT_DELEGATE)) ||\r
228 ((rmInst->instType == Rm_instType_CLIENT) &&\r
229 (transportCfg->remoteInstType == Rm_instType_CLIENT))) {\r
230 *result = RM_ERROR_INVALID_REMOTE_INST_TYPE;\r
231 goto errorExit;\r
232 }\r
233 \r
234 /* Verify Clients are not registering with more than one Client Delegate or Server. And\r
235 * that Client Delegate is not registering with more than one Server. */\r
236 if (rmInst->registeredWithDelegateOrServer &&\r
237 (((rmInst->instType == Rm_instType_CLIENT) &&\r
238 (transportCfg->remoteInstType == Rm_instType_CLIENT_DELEGATE)) || \r
239 ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
240 (transportCfg->remoteInstType == Rm_instType_SERVER)))) {\r
241 *result = RM_ERROR_ALREADY_REGD_SERVER_OR_CD;\r
242 goto errorExit;\r
243 } \r
244 \r
245 if (!transportCfg->transportCallouts.rmAllocPkt) {\r
246 *result = RM_ERROR_TRANSPORT_ALLOC_PKT_NOT_REGD;\r
247 goto errorExit;\r
248 }\r
249 else if (!transportCfg->transportCallouts.rmSendPkt) {\r
250 *result = RM_ERROR_TRANSPORT_SEND_NOT_REGD;\r
251 goto errorExit;\r
252 }\r
253 \r
254 transport = transportAdd(transportCfg);\r
255 if ((transport->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
256 (transport->remoteInstType == Rm_instType_SERVER)) {\r
257 rmInst->registeredWithDelegateOrServer = RM_TRUE;\r
258 }\r
259 errorExit:\r
260 RM_SS_INST_WB_EXIT_CS(key); \r
261 return ((Rm_TransportHandle) transport);\r
262 }\r
263 \r
264 /* FUNCTION PURPOSE: Unregisters an app transport from a RM instance\r
265 ***********************************************************************\r
266 * DESCRIPTION: Deletes a registered transport from the transport\r
267 * list and cleans up the memory associated with the\r
268 * transport data structure.\r
269 */\r
270 int32_t Rm_transportUnregister(Rm_TransportHandle transportHandle)\r
271 {\r
272 Rm_Transport *transport = (Rm_Transport *)transportHandle;\r
273 Rm_Inst *rmInst = (Rm_Inst *)transport->rmHandle;\r
274 int32_t retVal = RM_OK;\r
275 \r
276 if (transportIsRegistered(transport->rmHandle, transport)) {\r
277 if ((transport->remoteInstType == Rm_instType_CLIENT_DELEGATE) ||\r
278 (transport->remoteInstType == Rm_instType_SERVER)) {\r
279 rmInst->registeredWithDelegateOrServer = RM_FALSE;\r
280 }\r
281 transportDelete(transport);\r
282 }\r
283 else {\r
284 retVal = RM_ERROR_TRANSPORT_HANDLE_DOES_NOT_EXIST;\r
285 }\r
286 return (retVal);\r
287 }\r
288 \r
289 /* FUNCTION PURPOSE: Receives RM packets\r
290 ***********************************************************************\r
291 * DESCRIPTION: The application provides RM packets received on the\r
292 * application transports to RM via this API. Function\r
293 * can be called from polling or ISR contexts. Assume \r
294 * invoking application will free packet after this\r
295 * function returns.\r
296 */\r
297 int32_t Rm_receivePacket(Rm_TransportHandle transportHandle, const Rm_Packet *pkt)\r
299 Rm_Transport *transport = (Rm_Transport *)transportHandle;\r
300 Rm_Inst *rmInst = (Rm_Inst *)transport->rmHandle;\r
301 Rm_Transaction *transaction;\r
302 int32_t retVal = RM_OK;\r
303 \r
304 if (!transportIsRegistered(transport->rmHandle, transport)) {\r
305 retVal = RM_ERROR_TRANSPORT_HANDLE_DOES_NOT_EXIST;\r
306 goto errorExit;\r
307 }\r
308 \r
309 switch (pkt->pktType) {\r
310 case Rm_pktType_RESOURCE_REQUEST:\r
311 {\r
312 Rm_ResourceRequestPkt *resourceReqPkt = (Rm_ResourceRequestPkt *)pkt->data;\r
313 \r
314 transaction = rmTransactionQueueAdd(rmInst);\r
315 transaction->remoteOriginatingId = resourceReqPkt->requestId;\r
316 if (resourceReqPkt->resourceReqType == Rm_resReqPktType_ALLOCATE_INIT) {\r
317 transaction->type = Rm_service_RESOURCE_ALLOCATE_INIT;\r
318 }\r
319 else if (resourceReqPkt->resourceReqType == Rm_resReqPktType_ALLOCATE_USE) {\r
320 transaction->type = Rm_service_RESOURCE_ALLOCATE_USE;\r
321 } \r
322 else if (resourceReqPkt->resourceReqType == Rm_resReqPktType_FREE) {\r
323 transaction->type = Rm_service_RESOURCE_FREE;\r
324 }\r
325 else if (resourceReqPkt->resourceReqType == Rm_resReqPktType_GET_NAMED) {\r
326 transaction->type = Rm_service_RESOURCE_GET_BY_NAME;\r
327 } \r
328 strncpy(transaction->pktSrcInstName, resourceReqPkt->pktSrcInstName, RM_NAME_MAX_CHARS);\r
329 strncpy(transaction->serviceSrcInstName, resourceReqPkt->serviceSrcInstName, RM_NAME_MAX_CHARS);\r
330 transaction->state = RM_SERVICE_PROCESSING;\r
331 memcpy ((void *)&(transaction->resourceInfo), (void *)&(resourceReqPkt->resourceInfo),\r
332 sizeof(Rm_ResourceInfo));\r
333 break;\r
334 }\r
335 case Rm_pktType_RESOURCE_RESPONSE:\r
336 {\r
337 Rm_ResourceResponsePkt *resourceRespPkt = (Rm_ResourceResponsePkt *)pkt->data;\r
338 \r
339 if (transaction = rmTransactionQueueFind(rmInst,resourceRespPkt->responseId)) {\r
340 if ((transaction->state == RM_SERVICE_APPROVED_STATIC) &&\r
341 (resourceRespPkt->requestState != RM_SERVICE_APPROVED)) {\r
342 /* Lock the RM instance since service validated against static policy failed against \r
343 * Server's global policy */\r
344 rmInst->isLocked = RM_TRUE;\r
345 }\r
346 transaction->state = resourceRespPkt->requestState;\r
347 \r
348 if ((transaction->state == RM_SERVICE_APPROVED) &&\r
349 ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||\r
350 (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) ||\r
351 (transaction->type == Rm_service_RESOURCE_GET_BY_NAME))) {\r
352 memcpy ((void *)&(transaction->resourceInfo), (void *)&(resourceRespPkt->resourceInfo),\r
353 sizeof(Rm_ResourceInfo));\r
354 }\r
355 else {\r
356 /* Always copy owner count */\r
357 transaction->resourceInfo.ownerCount = resourceRespPkt->resourceInfo.ownerCount;\r
358 }\r
359 }\r
360 else {\r
361 retVal = RM_ERROR_PKT_RESP_DOES_NOT_MATCH_ANY_REQ;\r
362 goto errorExit;\r
363 }\r
364 break;\r
365 }\r
366 case Rm_pktType_NAMESERVER_REQUEST:\r
367 {\r
368 Rm_NsRequestPkt *nsRequestPkt = (Rm_NsRequestPkt *)pkt->data;\r
369 \r
370 transaction = rmTransactionQueueAdd(rmInst);\r
371 transaction->remoteOriginatingId = nsRequestPkt->requestId;\r
372 \r
373 if (nsRequestPkt->nsRequestType == Rm_nsReqPktType_MAP_RESOURCE) {\r
374 transaction->type = Rm_service_RESOURCE_MAP_TO_NAME;\r
375 }\r
376 else if (nsRequestPkt->nsRequestType == Rm_nsReqPktType_UNMAP_RESOURCE) {\r
377 transaction->type = Rm_service_RESOURCE_UNMAP_NAME;\r
378 }\r
379 \r
380 strncpy(transaction->pktSrcInstName, nsRequestPkt->pktSrcInstName, RM_NAME_MAX_CHARS);\r
381 strncpy(transaction->serviceSrcInstName, nsRequestPkt->serviceSrcInstName, RM_NAME_MAX_CHARS);\r
382 transaction->state = RM_SERVICE_PROCESSING;\r
383 memcpy ((void *)&(transaction->resourceInfo), (void *)&(nsRequestPkt->resourceInfo),\r
384 sizeof(Rm_ResourceInfo)); \r
385 break;\r
386 }\r
387 case Rm_pktType_NAMESERVER_RESPONSE:\r
388 {\r
389 Rm_NsResponsePkt *nsResponsePkt = (Rm_NsResponsePkt *)pkt->data;\r
390 \r
391 if (transaction = rmTransactionQueueFind(rmInst, nsResponsePkt->responseId)) {\r
392 if ((transaction->state == RM_SERVICE_APPROVED_STATIC) &&\r
393 (nsResponsePkt->requestState != RM_SERVICE_APPROVED)) {\r
394 /* Lock the RM instance since service validated against static policy failed against \r
395 * Server's global policy */ \r
396 rmInst->isLocked = RM_TRUE;\r
397 } \r
398 transaction->state = nsResponsePkt->requestState; \r
399 }\r
400 else {\r
401 retVal = RM_ERROR_PKT_RESP_DOES_NOT_MATCH_ANY_REQ;\r
402 goto errorExit;\r
403 }\r
404 break;\r
405 }\r
406 default:\r
407 retVal = RM_ERROR_RECEIVED_INVALID_PACKET_TYPE;\r
408 goto errorExit;\r
409 }\r
410 \r
411 /* Process received transaction */\r
412 rmProcessRouter(rmInst, transaction); \r
413 errorExit:\r
414 return(retVal);\r
415 }\r
416 \r