1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <app_mgmt_port_consts.h>
18 #include <app_mgmt_test.h>
19 #include <assert.h>
20 #include <lib/tipc/tipc.h>
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <trusty/time.h>
27 #include <trusty_ipc.h>
28 #include <uapi/err.h>
29 
30 #define TLOG_TAG "port-start-srv"
31 
32 /* Handles a cmd from the client and returns true if the server should exit */
handle_cmd(uint8_t cmd,handle_t channel,handle_t * start_port)33 static bool handle_cmd(uint8_t cmd, handle_t channel, handle_t* start_port) {
34     int rc;
35     bool done = false;
36     uint8_t rsp = RSP_OK;
37 
38     switch (cmd) {
39     case CMD_NOP:
40         break;
41     case CMD_CLOSE_PORT:
42         rc = close(*start_port);
43         if (rc != NO_ERROR) {
44             TLOGI("port close failed: %d\n", rc);
45             rsp = RSP_CMD_FAILED;
46             done = true;
47         }
48         break;
49     case CMD_OPEN_PORT:
50         rc = port_create(START_PORT, 1, MAX_CMD_LEN, IPC_PORT_ALLOW_TA_CONNECT);
51         if (rc < 0) {
52             TLOGI("failed (%d) to create port: %s\n", rc, START_PORT);
53             rsp = RSP_CMD_FAILED;
54             done = true;
55         } else {
56             *start_port = (handle_t)rc;
57         }
58         break;
59     case CMD_EXIT:
60         done = true;
61         break;
62     default:
63         TLOGI("Invalid cmd: %d\n", cmd);
64         rsp = RSP_INVALID_CMD;
65         done = true;
66     }
67 
68     rc = tipc_send1(channel, &rsp, sizeof(rsp));
69     if (rc < 0) {
70         TLOGI("Failed to send response: %d \n", rc);
71         done = true;
72     }
73 
74     return done;
75 }
76 
77 /* Creates port_name and adds it to hset */
prepare_port(const char * port_name,handle_t hset)78 static int prepare_port(const char* port_name, handle_t hset) {
79     int rc;
80     uevent_t uevt;
81     handle_t port;
82 
83     assert(port_name);
84     assert(hset);
85 
86     rc = port_create(port_name, 1, MAX_CMD_LEN, IPC_PORT_ALLOW_TA_CONNECT);
87     if (rc < 0) {
88         TLOGI("failed (%d) to create port: %s\n", rc, port_name);
89         return rc;
90     }
91 
92     port = (handle_t)rc;
93 
94     uevt.handle = port;
95     uevt.event = ~0U;
96     uevt.cookie = NULL;
97 
98     rc = handle_set_ctrl(hset, HSET_ADD, &uevt);
99     if (rc < 0) {
100         TLOGI("failed (%d) to add port %s to handle set \n", rc, port_name);
101         close(port);
102         return rc;
103     }
104 
105     return port;
106 }
107 
main(void)108 int main(void) {
109     int rc;
110     uint8_t cmd;
111     bool done = false;
112     handle_t ctrl_port;
113     handle_t start_port;
114     handle_t shutdown_port;
115     handle_t channel;
116     handle_t port_hset;
117     handle_t mixed_hset;
118     uevent_t uevt;
119     uuid_t peer_uuid;
120 
121     rc = handle_set_create();
122     if (rc < 0) {
123         TLOGI("failed (%d) to create port handle set \n", rc);
124         return rc;
125     }
126     port_hset = (handle_t)rc;
127 
128     rc = prepare_port(START_PORT, port_hset);
129     if (rc < 0) {
130         TLOGI("failed(%d) to prepare START_PORT\n", rc);
131         goto err_prep_start;
132     }
133     start_port = (handle_t)rc;
134 
135     rc = prepare_port(CTRL_PORT, port_hset);
136     if (rc < 0) {
137         TLOGI("failed(%d) to prepare CTRL_PORT\n", rc);
138         goto err_prep_ctrl;
139     }
140     ctrl_port = (handle_t)rc;
141 
142     rc = handle_set_create();
143     if (rc < 0) {
144         TLOGI("failed (%d) to create mixed handle set \n", rc);
145         goto err_hset_create;
146     }
147     mixed_hset = (handle_t)rc;
148 
149     rc = prepare_port(SHUTDOWN_PORT, mixed_hset);
150     if (rc < 0) {
151         TLOGI("failed(%d) to prepare CTRL_PORT\n", rc);
152         goto err_prep_shutdown;
153     }
154     shutdown_port = (handle_t)rc;
155 
156     rc = wait(port_hset, &uevt, INFINITE_TIME);
157     if (rc != NO_ERROR || !(uevt.event & IPC_HANDLE_POLL_READY)) {
158         TLOGI("Port wait failed: %d(%d)\n", rc, uevt.event);
159         goto err_port_wait;
160     }
161 
162     rc = accept(uevt.handle, &peer_uuid);
163     if (rc < 0) {
164         TLOGI("Accept failed %d\n", rc);
165         goto err_accept;
166     }
167     channel = (handle_t)rc;
168 
169     uevt.handle = channel;
170     uevt.event = ~0U;
171     uevt.cookie = NULL;
172 
173     rc = handle_set_ctrl(mixed_hset, HSET_ADD, &uevt);
174     if (rc < 0) {
175         TLOGI("failed (%d) to add channel to mixed handle set \n", rc);
176         goto err_hset_ctrl;
177     }
178 
179     while (!done) {
180         rc = wait(mixed_hset, &uevt, INFINITE_TIME);
181         if (rc < 0) {
182             TLOGI("Channel wait failed: %d\n", uevt.event);
183             goto err_channel_wait;
184         }
185 
186         if (uevt.handle == shutdown_port)
187             break;
188 
189         if (!(uevt.event & IPC_HANDLE_POLL_MSG)) {
190             TLOGI("Received unexpected event %d\n", uevt.event);
191             goto err_evt;
192         }
193 
194         rc = tipc_recv1(channel, sizeof(cmd), &cmd, sizeof(cmd));
195         if (rc < 0) {
196             TLOGI("recv_cmd failed: %d\n", rc);
197             goto err_recv;
198         }
199         rc = 0;
200 
201         done = handle_cmd(cmd, channel, &start_port);
202     }
203 
204 err_recv:
205 err_evt:
206 err_channel_wait:
207 err_hset_ctrl:
208     close(channel);
209 err_accept:
210 err_port_wait:
211     close(shutdown_port);
212 err_prep_shutdown:
213     close(mixed_hset);
214 err_hset_create:
215     close(ctrl_port);
216 err_prep_ctrl:
217     close(start_port);
218 err_prep_start:
219     close(port_hset);
220 
221     return rc;
222 }
223