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-aggregator-srv"
18 
19 #include "coverage.h"
20 
21 #include <interface/line-coverage/aggregator.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 <stdlib.h>
26 #include <trusty_log.h>
27 #include <uapi/err.h>
28 
29 static size_t ta_idx = 0;
30 
handle_register(handle_t chan,struct line_coverage_aggregator_req * req,struct coverage_record * record,struct cov_shm * mailbox)31 static int handle_register(handle_t chan,
32                            struct line_coverage_aggregator_req* req,
33                            struct coverage_record* record,
34                            struct cov_shm* mailbox) {
35     int rc;
36     struct line_coverage_aggregator_resp resp;
37     memset(&resp, 0, sizeof(struct line_coverage_aggregator_resp));
38 
39     resp.hdr.cmd = req->hdr.cmd | LINE_COVERAGE_AGGREGATOR_CMD_RESP_BIT;
40     resp.register_args.idx = record->ta_idx;
41     resp.register_args.mailbox_len = mailbox->len;
42 
43     rc = coverage_send(chan, &resp, sizeof(resp), &mailbox->memref);
44     if (rc != NO_ERROR) {
45         TLOGE("failed (%d) to send mailbox memref\n", rc);
46         return rc;
47     }
48 
49     record->record_len = req->register_args.record_len;
50     return NO_ERROR;
51 }
52 
handle_get_record(handle_t chan,struct line_coverage_aggregator_req * req,struct coverage_record * record)53 static int handle_get_record(handle_t chan,
54                              struct line_coverage_aggregator_req* req,
55                              struct coverage_record* record) {
56     int rc;
57     struct line_coverage_aggregator_resp resp;
58     memset(&resp, 0, sizeof(struct line_coverage_aggregator_resp));
59 
60     if (record->data.memref == INVALID_IPC_HANDLE) {
61         return ERR_NOT_READY;
62     }
63 
64     resp.hdr.cmd = req->hdr.cmd | LINE_COVERAGE_AGGREGATOR_CMD_RESP_BIT;
65     resp.get_record_args.shm_len = record->data.len;
66 
67     rc = coverage_send(chan, &resp, sizeof(resp), &record->data.memref);
68     if (rc != NO_ERROR) {
69         TLOGE("failed (%d) to send coverage record memref\n", rc);
70         return rc;
71     }
72 
73     return NO_ERROR;
74 }
75 
on_connect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)76 static int on_connect(const struct tipc_port* port,
77                       handle_t chan,
78                       const struct uuid* peer,
79                       void** ctx_p) {
80     struct coverage_record* record;
81     char uuid_str[UUID_STR_SIZE];
82     struct srv_state* state = get_srv_state(port);
83 
84     uuid_to_str(peer, uuid_str);
85     TLOGI("App with UUID: %s connected to coverage aggregator\n", uuid_str);
86 
87     record = find_coverage_record(&state->coverage_record_list, peer);
88     if (record) {
89         *ctx_p = record;
90         return NO_ERROR;
91     }
92 
93     record = calloc(1, sizeof(*record));
94     if (!record) {
95         TLOGE("failed to allocate coverage record\n");
96         return ERR_NO_MEMORY;
97     }
98 
99     record->uuid = *peer;
100     record->ta_idx = ta_idx++;
101     list_add_tail(&state->coverage_record_list, &record->node);
102 
103     *ctx_p = record;
104     return NO_ERROR;
105 }
106 
on_message(const struct tipc_port * port,handle_t chan,void * ctx)107 static int on_message(const struct tipc_port* port, handle_t chan, void* ctx) {
108     int rc;
109     struct line_coverage_aggregator_req req;
110     struct coverage_record* record = (struct coverage_record*)ctx;
111     struct srv_state* state = get_srv_state(port);
112 
113     rc = coverage_recv(chan, &req, sizeof(req), NULL);
114     if (rc != NO_ERROR) {
115         TLOGE("failed (%d) to receive coverage aggregator request\n", rc);
116         return rc;
117     }
118 
119     switch (req.hdr.cmd) {
120     case LINE_COVERAGE_AGGREGATOR_CMD_REGISTER:
121         return handle_register(chan, &req, record, &state->mailbox);
122 
123     case LINE_COVERAGE_AGGREGATOR_CMD_GET_RECORD:
124         return handle_get_record(chan, &req, record);
125 
126     default:
127         TLOGE("cmd 0x%x: unknown command\n", req.hdr.cmd);
128         return ERR_CMD_UNKNOWN;
129     }
130 }
131 
132 /* lib/tipc mandates we have this function. However, there is no work to do. */
on_channel_cleanup(void * ctx)133 static void on_channel_cleanup(void* ctx) {}
134 
coverage_aggregator_init(struct srv_state * state)135 int coverage_aggregator_init(struct srv_state* state) {
136     static struct tipc_port_acl port_acl = {
137             .flags = IPC_PORT_ALLOW_TA_CONNECT,
138     };
139     static struct tipc_port port = {
140             .name = LINE_COVERAGE_AGGREGATOR_PORT,
141             .msg_max_size = MAX(sizeof(struct coverage_aggregator_req),
142                                 sizeof(struct coverage_aggregator_resp)),
143             .msg_queue_len = 1,
144             .acl = &port_acl,
145     };
146     static struct tipc_srv_ops ops = {
147             .on_connect = on_connect,
148             .on_message = on_message,
149             .on_channel_cleanup = on_channel_cleanup,
150     };
151 
152     set_srv_state(&port, state);
153 
154     return tipc_add_service(state->hset, &port, 1, MAX_NUM_APPS, &ops);
155 }
156