Amit Pundir | d477f82 | 2020-02-07 22:26:08 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2018, Linaro Ltd. |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions are met: |
| 7 | * |
| 8 | * 1. Redistributions of source code must retain the above copyright notice, |
| 9 | * this list of conditions and the following disclaimer. |
| 10 | * |
| 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
| 12 | * this list of conditions and the following disclaimer in the documentation |
| 13 | * and/or other materials provided with the distribution. |
| 14 | * |
| 15 | * 3. Neither the name of the copyright holder nor the names of its contributors |
| 16 | * may be used to endorse or promote products derived from this software without |
| 17 | * specific prior written permission. |
| 18 | * |
| 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 29 | * POSSIBILITY OF SUCH DAMAGE. |
| 30 | */ |
Amit Pundir | aab5ced | 2020-04-16 10:02:40 +0530 | [diff] [blame] | 31 | #include <sys/stat.h> |
| 32 | #include <sys/types.h> |
| 33 | #include <err.h> |
Amit Pundir | d477f82 | 2020-02-07 22:26:08 +0530 | [diff] [blame] | 34 | #include <errno.h> |
Amit Pundir | aab5ced | 2020-04-16 10:02:40 +0530 | [diff] [blame] | 35 | #include <dirent.h> |
| 36 | #include <fcntl.h> |
| 37 | #include <libgen.h> |
Amit Pundir | d477f82 | 2020-02-07 22:26:08 +0530 | [diff] [blame] | 38 | #include <libqrtr.h> |
| 39 | #include <stdio.h> |
| 40 | #include <stdlib.h> |
| 41 | #include <string.h> |
| 42 | #include <unistd.h> |
| 43 | |
Amit Pundir | aab5ced | 2020-04-16 10:02:40 +0530 | [diff] [blame] | 44 | #include "assoc.h" |
| 45 | #include "json.h" |
Amit Pundir | d477f82 | 2020-02-07 22:26:08 +0530 | [diff] [blame] | 46 | #include "servreg_loc.h" |
| 47 | |
| 48 | struct pd_map { |
| 49 | const char *service; |
| 50 | const char *domain; |
| 51 | int instance; |
| 52 | }; |
| 53 | |
Amit Pundir | aab5ced | 2020-04-16 10:02:40 +0530 | [diff] [blame] | 54 | static struct pd_map *pd_maps; |
Amit Pundir | d477f82 | 2020-02-07 22:26:08 +0530 | [diff] [blame] | 55 | |
| 56 | static void handle_get_domain_list(int sock, const struct qrtr_packet *pkt) |
| 57 | { |
| 58 | struct servreg_loc_get_domain_list_resp resp = {}; |
| 59 | struct servreg_loc_get_domain_list_req req = {}; |
| 60 | struct servreg_loc_domain_list_entry *entry; |
| 61 | DEFINE_QRTR_PACKET(resp_buf, 256); |
| 62 | const struct pd_map *pd_map = pd_maps; |
| 63 | unsigned int txn; |
| 64 | ssize_t len; |
| 65 | int ret; |
| 66 | |
| 67 | ret = qmi_decode_message(&req, &txn, pkt, QMI_REQUEST, |
| 68 | SERVREG_LOC_GET_DOMAIN_LIST, |
| 69 | servreg_loc_get_domain_list_req_ei); |
| 70 | if (ret < 0) { |
| 71 | resp.result.result = QMI_RESULT_FAILURE; |
| 72 | resp.result.error = QMI_ERR_MALFORMED_MSG; |
| 73 | goto respond; |
| 74 | } |
| 75 | |
| 76 | req.name[sizeof(req.name)-1] = '\0'; |
| 77 | |
| 78 | resp.result.result = QMI_RESULT_SUCCESS; |
| 79 | resp.db_revision_valid = 1; |
| 80 | resp.db_revision = 1; |
| 81 | |
| 82 | while (pd_map->service) { |
| 83 | if (!strcmp(pd_map->service, req.name)) { |
| 84 | entry = &resp.domain_list[resp.domain_list_len++]; |
| 85 | |
| 86 | strcpy(entry->name, pd_map->domain); |
| 87 | entry->name_len = strlen(pd_map->domain); |
| 88 | entry->instance_id = pd_map->instance; |
| 89 | } |
| 90 | |
| 91 | pd_map++; |
| 92 | } |
| 93 | |
| 94 | if (resp.domain_list_len) |
| 95 | resp.domain_list_valid = 1; |
| 96 | |
| 97 | resp.total_domains_valid = 1; |
| 98 | resp.total_domains = resp.domain_list_len; |
| 99 | |
| 100 | respond: |
| 101 | len = qmi_encode_message(&resp_buf, |
| 102 | QMI_RESPONSE, SERVREG_LOC_GET_DOMAIN_LIST, |
| 103 | txn, &resp, |
| 104 | servreg_loc_get_domain_list_resp_ei); |
| 105 | if (len < 0) { |
| 106 | fprintf(stderr, |
| 107 | "[PD-MAPPER] failed to encode get_domain_list response: %s\n", |
| 108 | strerror(-len)); |
| 109 | return; |
| 110 | } |
| 111 | |
| 112 | ret = qrtr_sendto(sock, pkt->node, pkt->port, |
| 113 | resp_buf.data, resp_buf.data_len); |
| 114 | if (ret < 0) { |
| 115 | fprintf(stderr, |
| 116 | "[PD-MAPPER] failed to send get_domain_list response: %s\n", |
| 117 | strerror(-ret)); |
| 118 | } |
| 119 | } |
| 120 | |
Amit Pundir | aab5ced | 2020-04-16 10:02:40 +0530 | [diff] [blame] | 121 | static int pd_load_map(const char *file) |
| 122 | { |
| 123 | static int num_pd_maps; |
| 124 | struct json_value *sr_service; |
| 125 | struct json_value *sr_domain; |
| 126 | struct json_value *root; |
| 127 | struct json_value *it; |
| 128 | const char *subdomain; |
| 129 | const char *provider; |
| 130 | const char *service; |
| 131 | const char *domain; |
| 132 | const char *soc; |
| 133 | struct pd_map *newp; |
| 134 | struct pd_map *map; |
| 135 | double number; |
| 136 | int count; |
| 137 | int ret; |
| 138 | |
| 139 | root = json_parse_file(file); |
| 140 | if (!root) |
| 141 | return -1; |
| 142 | |
| 143 | sr_domain = json_get_child(root, "sr_domain"); |
| 144 | soc = json_get_string(sr_domain, "soc"); |
| 145 | domain = json_get_string(sr_domain, "domain"); |
| 146 | subdomain = json_get_string(sr_domain, "subdomain"); |
| 147 | ret = json_get_number(sr_domain, "qmi_instance_id", &number); |
| 148 | if (ret) |
| 149 | return ret; |
| 150 | |
| 151 | if (!soc || !domain || !subdomain) { |
| 152 | fprintf(stderr, "failed to parse sr_domain\n"); |
| 153 | return -1; |
| 154 | } |
| 155 | |
| 156 | sr_service = json_get_child(root, "sr_service"); |
| 157 | count = json_count_children(sr_service); |
| 158 | if (count < 0) |
| 159 | return count; |
| 160 | |
| 161 | newp = realloc(pd_maps, (num_pd_maps + count + 1) * sizeof(*newp)); |
| 162 | if (!newp) |
| 163 | return -1; |
| 164 | pd_maps = newp; |
| 165 | |
| 166 | for (it = sr_service->u.value; it; it = it->next) { |
| 167 | provider = json_get_string(it, "provider"); |
| 168 | service = json_get_string(it, "service"); |
| 169 | |
| 170 | if (!provider || !service) { |
| 171 | fprintf(stderr, |
| 172 | "failed to parse provdider or service from %s\n", |
| 173 | file); |
| 174 | return -1; |
| 175 | } |
| 176 | |
| 177 | map = &pd_maps[num_pd_maps++]; |
| 178 | |
| 179 | map->service = malloc(strlen(provider) + strlen(service) + 2); |
| 180 | sprintf((char *)map->service, "%s/%s", provider, service); |
| 181 | |
| 182 | map->domain = malloc(strlen(soc) + strlen(domain) + strlen(subdomain) + 3); |
| 183 | sprintf((char *)map->domain, "%s/%s/%s", soc, domain, subdomain); |
| 184 | |
| 185 | map->instance = number; |
| 186 | } |
| 187 | |
| 188 | pd_maps[num_pd_maps].service = NULL; |
| 189 | |
| 190 | json_free(root); |
| 191 | |
| 192 | return 0; |
| 193 | } |
| 194 | |
Amit Pundir | b951ef2 | 2020-04-14 22:48:17 +0530 | [diff] [blame] | 195 | #ifndef ANDROID |
Amit Pundir | aab5ced | 2020-04-16 10:02:40 +0530 | [diff] [blame] | 196 | #define FIRMWARE_BASE "/lib/firmware/" |
Amit Pundir | b951ef2 | 2020-04-14 22:48:17 +0530 | [diff] [blame] | 197 | #else |
| 198 | #define FIRMWARE_BASE "/vendor/firmware/" |
| 199 | #endif |
Amit Pundir | aab5ced | 2020-04-16 10:02:40 +0530 | [diff] [blame] | 200 | |
| 201 | static int pd_enumerate_jsons(struct assoc *json_set) |
| 202 | { |
| 203 | char firmware_value[PATH_MAX]; |
| 204 | char json_path[PATH_MAX]; |
| 205 | char firmware_attr[32]; |
| 206 | struct dirent *fw_de; |
| 207 | char path[PATH_MAX]; |
| 208 | struct dirent *de; |
| 209 | int firmware_fd; |
| 210 | DIR *class_dir; |
| 211 | int class_fd; |
| 212 | DIR *fw_dir; |
| 213 | size_t len; |
| 214 | size_t n; |
| 215 | |
| 216 | class_fd = open("/sys/class/remoteproc", O_RDONLY | O_DIRECTORY); |
| 217 | if (class_fd < 0) { |
| 218 | warn("failed to open remoteproc class"); |
| 219 | return -1; |
| 220 | } |
| 221 | |
| 222 | class_dir = fdopendir(class_fd); |
| 223 | if (!class_dir) { |
| 224 | warn("failed to opendir"); |
| 225 | goto close_class; |
| 226 | } |
| 227 | |
| 228 | while ((de = readdir(class_dir)) != NULL) { |
| 229 | if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) |
| 230 | continue; |
| 231 | |
| 232 | if (strlen(de->d_name) + sizeof("/firmware") > sizeof(firmware_attr)) |
| 233 | continue; |
| 234 | |
| 235 | strcpy(firmware_attr, de->d_name); |
| 236 | strcat(firmware_attr, "/firmware"); |
| 237 | |
| 238 | firmware_fd = openat(class_fd, firmware_attr, O_RDONLY); |
| 239 | if (firmware_fd < 0) |
| 240 | continue; |
| 241 | |
| 242 | n = read(firmware_fd, firmware_value, sizeof(firmware_value)); |
| 243 | close(firmware_fd); |
| 244 | if (n < 0) { |
| 245 | continue; |
| 246 | } |
| 247 | |
Amit Pundir | 4f619fb | 2020-04-14 22:45:05 +0530 | [diff] [blame] | 248 | firmware_value[n] = '\0'; |
| 249 | |
Amit Pundir | aab5ced | 2020-04-16 10:02:40 +0530 | [diff] [blame] | 250 | if (strlen(FIRMWARE_BASE) + strlen(firmware_value) + 1 > sizeof(path)) |
| 251 | continue; |
| 252 | |
| 253 | strcpy(path, FIRMWARE_BASE); |
| 254 | strcat(path, dirname(firmware_value)); |
| 255 | |
| 256 | fw_dir = opendir(path); |
| 257 | while ((fw_de = readdir(fw_dir)) != NULL) { |
| 258 | if (!strcmp(fw_de->d_name, ".") || !strcmp(fw_de->d_name, "..")) |
| 259 | continue; |
| 260 | |
| 261 | len = strlen(fw_de->d_name); |
| 262 | if (len < 5 || strcmp(&fw_de->d_name[len - 4], ".jsn")) |
| 263 | continue; |
| 264 | |
| 265 | if (strlen(FIRMWARE_BASE) + strlen(firmware_value) + 1 + |
| 266 | strlen(fw_de->d_name) + 1 > sizeof(path)) |
| 267 | continue; |
| 268 | |
| 269 | strcpy(json_path, path); |
| 270 | strcat(json_path, "/"); |
| 271 | strcat(json_path, fw_de->d_name); |
| 272 | |
| 273 | assoc_set(json_set, json_path, NULL); |
| 274 | } |
| 275 | |
| 276 | closedir(fw_dir); |
| 277 | } |
| 278 | |
| 279 | closedir(class_dir); |
| 280 | close_class: |
| 281 | close(class_fd); |
| 282 | |
| 283 | return 0; |
| 284 | } |
| 285 | |
| 286 | static int pd_load_maps(void) |
| 287 | { |
| 288 | struct assoc json_set; |
| 289 | unsigned long it; |
| 290 | const char *jsn; |
| 291 | int ret = 0; |
| 292 | |
| 293 | assoc_init(&json_set, 20); |
| 294 | |
| 295 | pd_enumerate_jsons(&json_set); |
| 296 | |
| 297 | assoc_foreach(jsn, NULL, &json_set, it) { |
| 298 | ret = pd_load_map(jsn); |
| 299 | if (ret < 0) |
| 300 | break; |
| 301 | } |
| 302 | |
| 303 | assoc_destroy(&json_set); |
| 304 | |
| 305 | return ret; |
| 306 | } |
| 307 | |
John Stultz | 2665669 | 2020-02-26 23:41:07 +0000 | [diff] [blame] | 308 | int main(int argc __unused, char **argv __unused) |
Amit Pundir | d477f82 | 2020-02-07 22:26:08 +0530 | [diff] [blame] | 309 | { |
| 310 | struct sockaddr_qrtr sq; |
| 311 | struct qrtr_packet pkt; |
| 312 | unsigned int msg_id; |
| 313 | socklen_t sl; |
| 314 | char buf[4096]; |
| 315 | int ret; |
| 316 | int fd; |
| 317 | |
Amit Pundir | aab5ced | 2020-04-16 10:02:40 +0530 | [diff] [blame] | 318 | ret = pd_load_maps(); |
| 319 | if (ret) |
| 320 | exit(1); |
| 321 | |
| 322 | if (!pd_maps) { |
| 323 | fprintf(stderr, "no pd maps available\n"); |
| 324 | exit(1); |
| 325 | } |
| 326 | |
Amit Pundir | d477f82 | 2020-02-07 22:26:08 +0530 | [diff] [blame] | 327 | fd = qrtr_open(0); |
| 328 | if (fd < 0) { |
| 329 | fprintf(stderr, "failed to open qrtr socket\n"); |
| 330 | exit(1); |
| 331 | } |
| 332 | |
| 333 | ret = qrtr_publish(fd, SERVREG_QMI_SERVICE, |
| 334 | SERVREG_QMI_VERSION, SERVREG_QMI_INSTANCE); |
| 335 | if (ret < 0) { |
| 336 | fprintf(stderr, "failed to publish service registry service\n"); |
| 337 | exit(1); |
| 338 | } |
| 339 | |
| 340 | for (;;) { |
| 341 | ret = qrtr_poll(fd, -1); |
| 342 | if (ret < 0) { |
| 343 | if (errno == EINTR) { |
| 344 | continue; |
| 345 | } else { |
| 346 | fprintf(stderr, "qrtr_poll failed\n"); |
| 347 | break; |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | sl = sizeof(sq); |
| 352 | ret = recvfrom(fd, buf, sizeof(buf), 0, (void *)&sq, &sl); |
| 353 | if (ret < 0) { |
| 354 | ret = -errno; |
| 355 | if (ret != -ENETRESET) |
| 356 | fprintf(stderr, "[PD-MAPPER] recvfrom failed: %d\n", ret); |
| 357 | return ret; |
| 358 | } |
| 359 | |
| 360 | ret = qrtr_decode(&pkt, buf, ret, &sq); |
| 361 | if (ret < 0) { |
| 362 | fprintf(stderr, "[PD-MAPPER] unable to decode qrtr packet\n"); |
| 363 | return ret; |
| 364 | } |
| 365 | |
| 366 | switch (pkt.type) { |
| 367 | case QRTR_TYPE_DATA: |
| 368 | ret = qmi_decode_header(&pkt, &msg_id); |
| 369 | if (ret < 0) |
| 370 | continue; |
| 371 | |
| 372 | switch (msg_id) { |
| 373 | case SERVREG_LOC_GET_DOMAIN_LIST: |
| 374 | handle_get_domain_list(fd, &pkt); |
| 375 | break; |
| 376 | case SERVREG_LOC_PFR: |
| 377 | printf("[PD-MAPPER] pfr\n"); |
| 378 | break; |
| 379 | }; |
| 380 | break; |
| 381 | }; |
| 382 | } |
| 383 | |
| 384 | close(fd); |
| 385 | |
| 386 | return 0; |
| 387 | } |