/* ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /** * @file tssockskel.c * @brief Sockets skeleton daemon for trusted clients. * */ #include "ch.h" #include "chfifo.h" #include "tsclient.h" #include "tssockskel.h" #include /*===========================================================================*/ /* Module local definitions. */ /*===========================================================================*/ /*===========================================================================*/ /* Module exported variables. */ /*===========================================================================*/ /*===========================================================================*/ /* Module local types. */ /*===========================================================================*/ /*===========================================================================*/ /* Module local variables. */ /*===========================================================================*/ static ts_service_t tsStubsService = NULL; static MUTEX_DECL(tsStubsServiceMtx); static objects_fifo_t skel_req_fifo; static msg_t skel_req_msgs[N_SOCKSKEL_THD]; static skel_req_t skel_reqs[N_SOCKSKEL_THD] = {0}; /*===========================================================================*/ /* Module local functions. */ /*===========================================================================*/ /** * @brief Invoke the stubs service in order to copy the 'in' * parameters in the non secure memory space. */ static void paramsInFromRemote(skel_req_t *skreqp) { msg_t r; skreqp->req = SKEL_REQ_CPYPRMS; chMtxLock(&tsStubsServiceMtx); r = tsInvokeServiceNoYield(tsStubsService, (ts_params_area_t)skreqp, sizeof *skreqp); chDbgAssert(r != SMC_SVC_BUSY, "Unexpected SMC_SVC_BUSY"); chMtxUnlock(&tsStubsServiceMtx); } /** * @brief Invoke the stubs service in order to copy the 'out' * parameters in the secure memory space and set the * remote call result. */ static void returnToRemote(skel_req_t *skreqp, uint32_t res) { msg_t r; skreqp->stub_op_result = res; skreqp->req = SKEL_REQ_PUTRES; chMtxLock(&tsStubsServiceMtx); r = tsInvokeServiceNoYield(tsStubsService, (ts_params_area_t)skreqp, sizeof *skreqp); chDbgAssert(r != SMC_SVC_BUSY, "Unexpected SMC_SVC_BUSY"); chMtxUnlock(&tsStubsServiceMtx); chFifoReturnObject(&skel_req_fifo, skreqp); } /** * @name Sockets API skeletons. * @{ */ /** * @brief int socket(int domain, int type, int protocol) */ static void l_socket(skel_req_t *skreqp) { int result; /* call the api exposed by the TCP/IP stack.*/ result = socket((int)skreqp->stub_op_p[0], (int)skreqp->stub_op_p[1], (int)skreqp->stub_op_p[2]); /* report the result and copy the 'out' parameters.*/ returnToRemote(skreqp, result); } /** * @brief int connect(int s, const struct sockaddr *name, socklen_t namelen) */ static void l_connect(skel_req_t *skreqp) { int s, result, socklen; struct sockaddr sockaddr; s = (int)skreqp->stub_op_p[0]; skreqp->stub_op_p[1] = (uint32_t)&sockaddr; socklen = (int)skreqp->stub_op_p[2]; /* Call the stub service in order to copy the 'in' parameter sockaddr.*/ paramsInFromRemote(skreqp); /* Call the api exposed by the TCP/IP stack.*/ result = connect(s, &sockaddr, socklen); /* Report the result.*/ returnToRemote(skreqp, result); } /** * @brief int close(int s) */ static void l_close(skel_req_t *skreqp) { int result; /* Call the api exposed by the TCP/IP stack.*/ result = close((int)skreqp->stub_op_p[0]); /* report the result.*/ returnToRemote(skreqp, result); } /** * @brief int recv(int s, void *mem, size_t len, int flags) */ static void l_recv(skel_req_t *skreqp) { int result; void *mem; size_t len; len = skreqp->stub_op_p[2]; /* Allocate the space for the receive buffer.*/ mem = chHeapAlloc(NULL, len); if (NULL == mem) { result = ENOMEM; } else { /* call the api exposed by the TCP/IP stack.*/ result = recv((int)skreqp->stub_op_p[0], mem, len, (int)skreqp->stub_op_p[3]); skreqp->stub_op_p[1] = (uint32_t)mem; } /* report the result and copy 'out' parameter mem.*/ returnToRemote(skreqp, result); if (NULL != mem) chHeapFree(mem); } /** * @brief int send(int s, const void *dataptr, size_t size, int flags) */ static void l_send(skel_req_t *skreqp) { int result; void *dataptr; size_t size; size = skreqp->stub_op_p[2]; /* Allocate the space for the send buffer.*/ dataptr = chHeapAlloc(NULL, size); if (NULL == dataptr) { result = ENOMEM; } else { skreqp->stub_op_p[1] = (uint32_t)dataptr; /* call the stub service in order to copy the 'in' parameter dataptr.*/ paramsInFromRemote(skreqp); /* call the api exposed by the TCP/IP stack.*/ result = send((int)skreqp->stub_op_p[0], dataptr, size, (int)skreqp->stub_op_p[3]); chHeapFree(dataptr); } /* report the result.*/ returnToRemote(skreqp, result); } /** * @brief int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, * struct timeval *timeout) */ static void l_select(skel_req_t *skreqp) { int result; int maxfdpl; fd_set readset, writeset, exceptset; struct timeval timeout; maxfdpl = skreqp->stub_op_p[0]; skreqp->stub_op_p[1] = (uint32_t)&readset; skreqp->stub_op_p[2] = (uint32_t)&writeset; skreqp->stub_op_p[3] = (uint32_t)&exceptset; skreqp->stub_op_p[4] = (uint32_t)&timeout; /* call the stub service in order to copy the 'in' parameter readset, writeset, exceptset and timeout.*/ paramsInFromRemote(skreqp); /* call the api exposed by the TCP/IP stack.*/ result = select(maxfdpl, &readset, &writeset, &exceptset, &timeout); /* report the result and the parameters readset, writeset and exceptset.*/ returnToRemote(skreqp, result); } /** * @brief bind(int s, const struct sockaddr *name, socklen_t namelen); */ static void l_bind(skel_req_t *skreqp) { int s, result, socklen; struct sockaddr sockaddr; s = (int)skreqp->stub_op_p[0]; skreqp->stub_op_p[1] = (uint32_t)&sockaddr; socklen = (int)skreqp->stub_op_p[2]; /* Call the stub service in order to copy the 'in' parameter sockaddr.*/ paramsInFromRemote(skreqp); /* Call the api exposed by the TCP/IP stack.*/ result = bind(s, &sockaddr, socklen); /* Report the result.*/ returnToRemote(skreqp, result); } /** @} */ /*===========================================================================*/ /* Module exported functions. */ /*===========================================================================*/ /** * @brief Dispatch a request to a local method. */ static THD_FUNCTION(TsSockSkelDaemon, arg) { (void)arg; skel_req_t *skreqp; for (;/* ever */;) { chFifoReceiveObjectTimeout(&skel_req_fifo, (void **)&skreqp, TIME_INFINITE); switch (skreqp->stub_op_code) { case STUB_OP_SOCKET: l_socket(skreqp); break; case STUB_OP_CONNECT: l_connect(skreqp); break; case STUB_OP_CLOSE: l_close(skreqp); break; case STUB_OP_RECV: l_recv(skreqp); break; case STUB_OP_SEND: l_send(skreqp); break; case STUB_OP_SELECT: l_select(skreqp); break; case STUB_OP_BIND: l_bind(skreqp); break; default: break; } } } /** * @brief Dispatch a request to a skeleton worker thread. */ static THD_WORKING_AREA(waTsSkelsDaemon, 512); static THD_FUNCTION(TsSkelsDaemon, arg) { (void)arg; event_listener_t el; skel_req_t *skreqp; msg_t r; chEvtRegisterMaskWithFlags(&stubsEventSource, &el, ALL_EVENTS, EVT_F_SOCK_NEW_OP); tsStubsService = (ts_service_t)tsInvokeServiceNoYield(TS_HND_DISCOVERY, (ts_params_area_t)"TsStubsService", sizeof "TsStubsService"); /* Tell to stubs service that we are ready.*/ skreqp = chFifoTakeObjectTimeout(&skel_req_fifo, TIME_INFINITE); skreqp->req = SKEL_REQ_READY; tsInvokeServiceNoYield(tsStubsService, (ts_params_area_t)skreqp, sizeof *skreqp); chFifoReturnObject(&skel_req_fifo, skreqp); /* Start to receive ops.*/ for (;/* ever */;) { chEvtWaitAny(ALL_EVENTS); (void)chEvtGetAndClearFlags(&el); while (true) { skreqp = chFifoTakeObjectTimeout(&skel_req_fifo, TIME_INFINITE); skreqp->req = SKEL_REQ_GETOP; chMtxLock(&tsStubsServiceMtx); r = tsInvokeServiceNoYield(tsStubsService, (ts_params_area_t)skreqp, sizeof *skreqp); chDbgAssert(r != SMC_SVC_BUSY, "Unexpected SMC_SVC_BUSY"); chMtxUnlock(&tsStubsServiceMtx); if (r == SMC_SVC_NHND) break; chFifoSendObject(&skel_req_fifo, skreqp); } chFifoReturnObject(&skel_req_fifo, skreqp); } } /** * @brief Init the skeletons daemon objects and create the * corresponding threads. */ void tsSkelsDaemonInit(void) { int i; chFifoObjectInit(&skel_req_fifo, sizeof (skel_req_t), N_SOCKSKEL_THD, sizeof (uint8_t), skel_reqs, skel_req_msgs); for (i = 0; i < N_SOCKSKEL_THD; ++i) chThdCreateFromHeap(NULL, 2048, "TsSkelDaemonWrk", NORMALPRIO, TsSockSkelDaemon, NULL); chThdCreateStatic(waTsSkelsDaemon, sizeof waTsSkelsDaemon, NORMALPRIO, TsSkelsDaemon, NULL); }