• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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/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 
31 struct chan_ctx {
32     struct coverage_record* record;
33 };
34 
broadcast_event(struct cov_shm * mailbox,size_t idx,int event)35 static void broadcast_event(struct cov_shm* mailbox, size_t idx, int event) {
36     int* app_mailbox = (int*)(mailbox->base) + idx;
37     WRITE_ONCE(*app_mailbox, event);
38 }
39 
handle_open(handle_t chan,struct coverage_client_req * req,struct list_node * coverage_record_list,struct chan_ctx * ctx)40 static int handle_open(handle_t chan,
41                        struct coverage_client_req* req,
42                        struct list_node* coverage_record_list,
43                        struct chan_ctx* ctx) {
44     int rc;
45     struct coverage_client_resp resp;
46     struct coverage_record* record;
47     char uuid_str[UUID_STR_SIZE];
48 
49     record = find_coverage_record(coverage_record_list, &req->open_args.uuid);
50     if (!record) {
51         uuid_to_str(&req->open_args.uuid, uuid_str);
52         TLOGE("coverage record not found for uuid: %s\n", uuid_str);
53         return ERR_NOT_FOUND;
54     }
55 
56     resp.hdr.cmd = req->hdr.cmd | COVERAGE_CLIENT_CMD_RESP_BIT;
57     resp.open_args.record_len = record->record_len;
58     rc = coverage_send(chan, &resp, sizeof(resp), NULL);
59     if (rc != NO_ERROR) {
60         TLOGE("failed (%d) to reply to open request\n", rc);
61         return rc;
62     }
63 
64     ctx->record = record;
65     return NO_ERROR;
66 }
67 
handle_share_record(handle_t chan,struct coverage_client_req * req,struct coverage_record * record,handle_t memref,struct cov_shm * mailbox)68 static int handle_share_record(handle_t chan,
69                                struct coverage_client_req* req,
70                                struct coverage_record* record,
71                                handle_t memref,
72                                struct cov_shm* mailbox) {
73     int rc;
74     struct coverage_client_resp resp;
75 
76     if (memref == INVALID_IPC_HANDLE) {
77         TLOGE("invalid memref");
78         return ERR_BAD_LEN;
79     }
80 
81     resp.hdr.cmd = req->hdr.cmd | COVERAGE_CLIENT_CMD_RESP_BIT;
82     rc = coverage_send(chan, &resp, sizeof(resp), NULL);
83     if (rc != NO_ERROR) {
84         TLOGE("failed (%d) to reply to share record request\n", rc);
85         return rc;
86     }
87 
88     cov_shm_init(&record->data, memref, NULL, req->share_record_args.shm_len);
89 
90     broadcast_event(mailbox, record->idx, COVERAGE_MAILBOX_RECORD_READY);
91 
92     return NO_ERROR;
93 }
94 
on_connect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)95 static int on_connect(const struct tipc_port* port,
96                       handle_t chan,
97                       const struct uuid* peer,
98                       void** ctx_p) {
99     struct chan_ctx* ctx = malloc(sizeof(*ctx));
100     if (!ctx) {
101         TLOGE("failed to allocate channel context\n");
102         return ERR_NO_MEMORY;
103     }
104 
105     ctx->record = NULL;
106     *ctx_p = ctx;
107     return NO_ERROR;
108 }
109 
on_message(const struct tipc_port * port,handle_t chan,void * _ctx)110 static int on_message(const struct tipc_port* port, handle_t chan, void* _ctx) {
111     int rc;
112     handle_t memref;
113     struct coverage_client_req req;
114     struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
115     struct srv_state* state = get_srv_state(port);
116 
117     rc = coverage_recv(chan, &req, sizeof(req), &memref);
118     if (rc != NO_ERROR) {
119         TLOGE("failed (%d) to receive coverage client request\n", rc);
120         return rc;
121     }
122 
123     switch (req.hdr.cmd) {
124     case COVERAGE_CLIENT_CMD_OPEN:
125         return handle_open(chan, &req, &state->coverage_record_list, ctx);
126 
127     case COVERAGE_CLIENT_CMD_SHARE_RECORD:
128         return handle_share_record(chan, &req, ctx->record, memref,
129                                    &state->mailbox);
130 
131     default:
132         TLOGE("cmd 0x%x: unknown command\n", req.hdr.cmd);
133         return ERR_CMD_UNKNOWN;
134     }
135 }
136 
on_channel_cleanup(void * _ctx)137 static void on_channel_cleanup(void* _ctx) {
138     struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
139     free(ctx);
140 }
141 
coverage_client_init(struct srv_state * state)142 int coverage_client_init(struct srv_state* state) {
143     static struct tipc_port_acl port_acl = {
144             .flags = IPC_PORT_ALLOW_TA_CONNECT | IPC_PORT_ALLOW_NS_CONNECT,
145     };
146     static struct tipc_port port = {
147             .name = COVERAGE_CLIENT_PORT,
148             .msg_max_size = MAX(sizeof(struct coverage_client_req),
149                                 sizeof(struct coverage_client_resp)),
150             .msg_queue_len = 1,
151             .acl = &port_acl,
152     };
153     static struct tipc_srv_ops ops = {
154             .on_connect = on_connect,
155             .on_message = on_message,
156             .on_channel_cleanup = on_channel_cleanup,
157     };
158 
159     set_srv_state(&port, state);
160 
161     return tipc_add_service(state->hset, &port, 1, 1, &ops);
162 }
163