• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #define TLOG_TAG "coverage-client-srv"
18 
19 #include "coverage.h"
20 
21 #include <interface/line-coverage/client.h>
22 #include <lib/coverage/common/ipc.h>
23 #include <lib/coverage/common/cov_shm.h>
24 #include <lib/tipc/tipc_srv.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <trusty_log.h>
29 #include <uapi/err.h>
30 #include <lk/list.h>
31 
32 struct chan_ctx {
33     struct coverage_record* record;
34     struct list_node* last_sent_node;
35 };
36 
signal_event(struct cov_shm * mailbox,size_t ta_idx,int event)37 static void signal_event(struct cov_shm* mailbox, size_t ta_idx, int event) {
38     int* app_mailbox = (int*)(mailbox->base) + ta_idx;
39     WRITE_ONCE(*app_mailbox, event);
40 }
41 
handle_send_list(handle_t chan,struct line_coverage_client_req * req,struct list_node * coverage_record_list,struct chan_ctx * ctx)42 static int handle_send_list(handle_t chan,
43                        struct line_coverage_client_req* req,
44                        struct list_node* coverage_record_list,
45                        struct chan_ctx* ctx) {
46     int rc;
47     uevent_t evt;
48     handle_t memref;
49     struct line_coverage_client_resp resp;
50     struct coverage_record* cur_record;
51     memset(&resp, 0, sizeof(struct line_coverage_client_resp));
52     struct uuid zero_uuid = {0, 0, 0, { 0 }};
53     struct list_node* cur_node = list_next(coverage_record_list, ctx->last_sent_node);
54 
55     while(cur_node != NULL) {
56         resp.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST | LINE_COVERAGE_CLIENT_CMD_RESP_BIT;
57         cur_record = containerof(cur_node, struct coverage_record, node);
58         resp.send_list_args.uuid = cur_record->uuid;
59 
60         rc = coverage_send(chan, &resp, sizeof(resp), NULL);
61         if (rc != NO_ERROR) {
62             TLOGE("failed (%d) to send to list elements\n", rc);
63             return rc;
64         }
65 
66         rc = wait(chan, &evt, INFINITE_TIME);
67         rc = coverage_recv(chan, &req, sizeof(req), &memref);
68         if (rc != NO_ERROR) {
69             TLOGE("failed (%d) to receive response\n", rc);
70             return rc;
71         }
72         ctx->last_sent_node = cur_node;
73         cur_node = list_next(coverage_record_list, cur_node);
74     }
75 
76     resp.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST | LINE_COVERAGE_CLIENT_CMD_RESP_BIT;
77     resp.send_list_args.uuid = zero_uuid;
78     rc = coverage_send(chan, &resp, sizeof(resp), NULL);
79     if (rc != NO_ERROR) {
80         TLOGE("failed (%d) to send end of list\n", rc);
81         return rc;
82     }
83     return NO_ERROR;
84 }
85 
handle_open(handle_t chan,struct line_coverage_client_req * req,struct list_node * coverage_record_list,struct chan_ctx * ctx)86 static int handle_open(handle_t chan,
87                        struct line_coverage_client_req* req,
88                        struct list_node* coverage_record_list,
89                        struct chan_ctx* ctx) {
90     int rc;
91     struct line_coverage_client_resp resp;
92     struct coverage_record* record;
93     char uuid_str[UUID_STR_SIZE];
94 
95     uuid_to_str(&req->open_args.uuid, uuid_str);
96 
97     record = find_coverage_record(coverage_record_list, &req->open_args.uuid);
98     if (!record) {
99         TLOGE("coverage record not found for uuid: %s\n", uuid_str);
100         return ERR_NOT_FOUND;
101     }
102 
103     memset(&resp, 0, sizeof(struct line_coverage_client_resp));
104     resp.hdr.cmd = req->hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT;
105     resp.open_args.record_len = record->record_len;
106     rc = coverage_send(chan, &resp, sizeof(resp), NULL);
107     if (rc != NO_ERROR) {
108         TLOGE("failed (%d) to reply to open request\n", rc);
109         return rc;
110     }
111 
112     ctx->record = record;
113     return NO_ERROR;
114 }
115 
handle_share_record(handle_t chan,struct line_coverage_client_req * req,struct coverage_record * record,handle_t memref,struct cov_shm * mailbox)116 static int handle_share_record(handle_t chan,
117                                struct line_coverage_client_req* req,
118                                struct coverage_record* record,
119                                handle_t memref,
120                                struct cov_shm* mailbox) {
121     int rc;
122     struct line_coverage_client_resp resp;
123 
124     if (memref == INVALID_IPC_HANDLE) {
125         TLOGE("invalid memref");
126         return ERR_BAD_LEN;
127     }
128     memset(&resp, 0, sizeof(struct line_coverage_client_resp));
129     resp.hdr.cmd = req->hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT;
130     rc = coverage_send(chan, &resp, sizeof(resp), NULL);
131     if (rc != NO_ERROR) {
132         TLOGE("failed (%d) to reply to share record request\n", rc);
133         return rc;
134     }
135 
136     cov_shm_init(&record->data, memref, NULL, req->share_record_args.shm_len);
137 
138     signal_event(mailbox, record->ta_idx, COVERAGE_MAILBOX_RECORD_READY);
139 
140     return NO_ERROR;
141 }
142 
on_connect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)143 static int on_connect(const struct tipc_port* port,
144                       handle_t chan,
145                       const struct uuid* peer,
146                       void** ctx_p) {
147     struct chan_ctx* ctx = calloc(1, sizeof(*ctx));
148     if (!ctx) {
149         TLOGE("failed to allocate channel context\n");
150         return ERR_NO_MEMORY;
151     }
152 
153     struct srv_state* state = get_srv_state(port);
154     ctx->record = NULL;
155     ctx->last_sent_node = &state->coverage_record_list;
156     *ctx_p = ctx;
157     return NO_ERROR;
158 }
159 
on_message(const struct tipc_port * port,handle_t chan,void * _ctx)160 static int on_message(const struct tipc_port* port, handle_t chan, void* _ctx) {
161     int rc;
162     handle_t memref;
163     struct line_coverage_client_req req;
164     struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
165     struct srv_state* state = get_srv_state(port);
166 
167     rc = coverage_recv(chan, &req, sizeof(req), &memref);
168     if (rc != NO_ERROR) {
169         TLOGE("failed (%d) to receive coverage client request\n", rc);
170         return rc;
171     }
172 
173     switch (req.hdr.cmd) {
174     case LINE_COVERAGE_CLIENT_CMD_SEND_LIST:
175         return handle_send_list(chan, &req, &state->coverage_record_list, ctx);
176 
177     case LINE_COVERAGE_CLIENT_CMD_OPEN:
178         return handle_open(chan, &req, &state->coverage_record_list, ctx);
179 
180     case LINE_COVERAGE_CLIENT_CMD_SHARE_RECORD:
181         return handle_share_record(chan, &req, ctx->record, memref,
182                                    &state->mailbox);
183 
184     default:
185         TLOGE("command 0x%x: unknown command\n", req.hdr.cmd);
186         return ERR_CMD_UNKNOWN;
187     }
188 }
189 
on_channel_cleanup(void * _ctx)190 static void on_channel_cleanup(void* _ctx) {
191     struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
192     free(ctx);
193 }
194 
coverage_client_init(struct srv_state * state)195 int coverage_client_init(struct srv_state* state) {
196     static struct tipc_port_acl port_acl = {
197             .flags = IPC_PORT_ALLOW_TA_CONNECT | IPC_PORT_ALLOW_NS_CONNECT,
198     };
199     static struct tipc_port port = {
200             .name = LINE_COVERAGE_CLIENT_PORT,
201             .msg_max_size = MAX(sizeof(struct line_coverage_client_req),
202                                 sizeof(struct line_coverage_client_resp)),
203             .msg_queue_len = 1,
204             .acl = &port_acl,
205     };
206     static struct tipc_srv_ops ops = {
207             .on_connect = on_connect,
208             .on_message = on_message,
209             .on_channel_cleanup = on_channel_cleanup,
210     };
211     set_srv_state(&port, state);
212 
213     return tipc_add_service(state->hset, &port, 1, 1, &ops);
214 }
215