├── pd-mapper.service.in ├── Android.bp ├── Makefile ├── servreg_loc.qmi ├── servreg_loc.h ├── assoc.h ├── json.h ├── LICENSE ├── assoc.c ├── servreg_loc.c ├── lzma_decomp.c ├── json.c └── pd-mapper.c /pd-mapper.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Qualcomm PD mapper service 3 | 4 | [Service] 5 | ExecStart=PD_MAPPER_PATH/pd-mapper 6 | Restart=always 7 | 8 | [Install] 9 | WantedBy=multi-user.target 10 | -------------------------------------------------------------------------------- /Android.bp: -------------------------------------------------------------------------------- 1 | cc_binary { 2 | name: "pd-mapper", 3 | vendor: true, 4 | srcs: [ 5 | "pd-mapper.c", 6 | "assoc.c", 7 | "json.c", 8 | "servreg_loc.c", 9 | ], 10 | shared_libs: ["libqrtr"], 11 | } 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PD_MAPPER := pd-mapper 2 | 3 | CFLAGS += -Wall -g -O2 4 | LDFLAGS += -lqrtr -llzma 5 | prefix ?= /usr/local 6 | 7 | bindir := $(prefix)/bin 8 | servicedir := $(prefix)/lib/systemd/system 9 | 10 | SRCS := pd-mapper.c \ 11 | assoc.c \ 12 | json.c \ 13 | servreg_loc.c \ 14 | lzma_decomp.c 15 | 16 | OBJS := $(SRCS:.c=.o) 17 | 18 | $(PD_MAPPER): $(OBJS) 19 | $(CC) -o $@ $^ $(LDFLAGS) 20 | 21 | pd-mapper.service: pd-mapper.service.in 22 | @sed 's+PD_MAPPER_PATH+$(bindir)+g' $< > $@ 23 | 24 | install: $(PD_MAPPER) pd-mapper.service 25 | @install -D -m 755 $(PD_MAPPER) $(DESTDIR)$(bindir)/$(PD_MAPPER) 26 | @install -D -m 644 pd-mapper.service $(DESTDIR)$(servicedir)/pd-mapper.service 27 | 28 | clean: 29 | rm -f $(PD_MAPPER) $(OBJS) pd-mapper.service 30 | -------------------------------------------------------------------------------- /servreg_loc.qmi: -------------------------------------------------------------------------------- 1 | package servreg_loc; 2 | 3 | const SERVREG_QMI_SERVICE = 0x40; 4 | const SERVREG_QMI_VERSION = 0x101; 5 | const SERVREG_QMI_INSTANCE = 0x0; 6 | 7 | const QMI_RESULT_SUCCESS = 0; 8 | const QMI_RESULT_FAILURE = 1; 9 | 10 | const QMI_ERR_NONE = 0; 11 | const QMI_ERR_INTERNAL = 1; 12 | const QMI_ERR_MALFORMED_MSG = 2; 13 | 14 | const SERVREG_LOC_GET_DOMAIN_LIST = 0x21; 15 | const SERVREG_LOC_PFR = 0x24; 16 | 17 | struct qmi_result { 18 | u16 result; 19 | u16 error; 20 | }; 21 | 22 | struct domain_list_entry { 23 | string name; 24 | u32 instance_id; 25 | u8 service_data_valid; 26 | u32 service_data; 27 | }; 28 | 29 | request get_domain_list_req { 30 | required string name = 1; 31 | optional u32 offset = 0x10; 32 | } = 0x20; 33 | 34 | response get_domain_list_resp { 35 | required qmi_result result = 2; 36 | optional u16 total_domains = 0x10; 37 | optional u16 db_revision = 0x11; 38 | optional domain_list_entry domain_list[255] = 0x12; 39 | } = 0x20; 40 | 41 | request pfr_req { 42 | required string service = 1; 43 | required string reason = 2; 44 | } = 0x24; 45 | 46 | response pfr_resp { 47 | required qmi_result result = 2; 48 | } = 0x24; 49 | -------------------------------------------------------------------------------- /servreg_loc.h: -------------------------------------------------------------------------------- 1 | #ifndef __QMI_SERVREG_LOC_H__ 2 | #define __QMI_SERVREG_LOC_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "libqrtr.h" 8 | 9 | #define SERVREG_QMI_SERVICE 64 10 | #define SERVREG_QMI_VERSION 257 11 | #define SERVREG_QMI_INSTANCE 0 12 | #define QMI_RESULT_SUCCESS 0 13 | #define QMI_RESULT_FAILURE 1 14 | #define QMI_ERR_NONE 0 15 | #define QMI_ERR_INTERNAL 1 16 | #define QMI_ERR_MALFORMED_MSG 2 17 | #define SERVREG_LOC_GET_DOMAIN_LIST 33 18 | #define SERVREG_LOC_PFR 36 19 | 20 | struct servreg_loc_qmi_result { 21 | uint16_t result; 22 | uint16_t error; 23 | }; 24 | 25 | struct servreg_loc_domain_list_entry { 26 | uint32_t name_len; 27 | char name[256]; 28 | uint32_t instance_id; 29 | uint8_t service_data_valid; 30 | uint32_t service_data; 31 | }; 32 | 33 | struct servreg_loc_get_domain_list_req { 34 | uint32_t name_len; 35 | char name[256]; 36 | bool offset_valid; 37 | uint32_t offset; 38 | }; 39 | 40 | struct servreg_loc_get_domain_list_resp { 41 | struct servreg_loc_qmi_result result; 42 | bool total_domains_valid; 43 | uint16_t total_domains; 44 | bool db_revision_valid; 45 | uint16_t db_revision; 46 | bool domain_list_valid; 47 | uint32_t domain_list_len; 48 | struct servreg_loc_domain_list_entry domain_list[255]; 49 | }; 50 | 51 | struct servreg_loc_pfr_req { 52 | uint32_t service_len; 53 | char service[256]; 54 | uint32_t reason_len; 55 | char reason[256]; 56 | }; 57 | 58 | struct servreg_loc_pfr_resp { 59 | struct servreg_loc_qmi_result result; 60 | }; 61 | 62 | extern struct qmi_elem_info servreg_loc_get_domain_list_req_ei[]; 63 | extern struct qmi_elem_info servreg_loc_get_domain_list_resp_ei[]; 64 | extern struct qmi_elem_info servreg_loc_pfr_req_ei[]; 65 | extern struct qmi_elem_info servreg_loc_pfr_resp_ei[]; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /assoc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Bjorn Andersson 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 | */ 31 | 32 | #ifndef __ASSOC_H__ 33 | #define __ASSOC_H__ 34 | 35 | struct assoc { 36 | unsigned long size; 37 | unsigned long fill; 38 | 39 | const char **keys; 40 | void **values; 41 | }; 42 | 43 | void assoc_init(struct assoc *assoc, unsigned long size); 44 | void *assoc_get(struct assoc *assoc, const char *key); 45 | void assoc_set(struct assoc *assoc, const char *key, void *value); 46 | const char *assoc_next(struct assoc *assoc, void **value, unsigned long *iter); 47 | void assoc_destroy(struct assoc *assoc); 48 | 49 | #define assoc_foreach(key, value, assoc, iter) \ 50 | for ((iter) = 0, (key) = assoc_next((assoc), (value), &(iter)); \ 51 | (key); \ 52 | (key) = assoc_next((assoc), (value), &(iter))) 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /json.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019, 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 | */ 31 | #ifndef __JSON_H__ 32 | #define __JSON_H__ 33 | 34 | 35 | enum { 36 | JSON_TYPE_UNKNOWN, 37 | JSON_TYPE_TRUE, 38 | JSON_TYPE_FALSE, 39 | JSON_TYPE_NULL, 40 | JSON_TYPE_NUMBER, 41 | JSON_TYPE_STRING, 42 | JSON_TYPE_ARRAY, 43 | JSON_TYPE_OBJECT, 44 | }; 45 | 46 | struct json_value { 47 | const char *key; 48 | 49 | int type; 50 | union { 51 | double number; 52 | const char *string; 53 | struct json_value *value; 54 | } u; 55 | 56 | struct json_value *next; 57 | }; 58 | 59 | struct json_value *json_parse(const char *json); 60 | struct json_value *json_parse_file(const char *file); 61 | int json_count_children(struct json_value *array); 62 | struct json_value *json_get_child(struct json_value *object, const char *key); 63 | int json_get_number(struct json_value *object, const char *key, double *number); 64 | const char *json_get_string(struct json_value *object, const char *key); 65 | void json_free(struct json_value *value); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 | */ 31 | /* 32 | * Copyright (c) 2016, Bjorn Andersson 33 | * All rights reserved. 34 | * 35 | * Redistribution and use in source and binary forms, with or without 36 | * modification, are permitted provided that the following conditions are met: 37 | * 38 | * 1. Redistributions of source code must retain the above copyright notice, 39 | * this list of conditions and the following disclaimer. 40 | * 41 | * 2. Redistributions in binary form must reproduce the above copyright notice, 42 | * this list of conditions and the following disclaimer in the documentation 43 | * and/or other materials provided with the distribution. 44 | * 45 | * 3. Neither the name of the copyright holder nor the names of its contributors 46 | * may be used to endorse or promote products derived from this software without 47 | * specific prior written permission. 48 | * 49 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 50 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 53 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 | * POSSIBILITY OF SUCH DAMAGE. 60 | */ 61 | -------------------------------------------------------------------------------- /assoc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Bjorn Andersson 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 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "assoc.h" 38 | 39 | static unsigned long assoc_hash(const char *value) 40 | { 41 | unsigned long hash = 0; 42 | unsigned long g; 43 | const char *v = value; 44 | 45 | while (*v) { 46 | hash = (hash << 4) + *(v++); 47 | g = hash & 0xF0000000L; 48 | if (g) 49 | hash ^= g >> 24; 50 | hash &= ~g; 51 | } 52 | 53 | return hash; 54 | } 55 | 56 | void assoc_init(struct assoc *assoc, unsigned long size) 57 | { 58 | assert(size > 0); 59 | 60 | assoc->size = size; 61 | assoc->fill = 0; 62 | assoc->keys = calloc(size, sizeof(const char *)); 63 | assoc->values = malloc(size * sizeof(void *)); 64 | } 65 | 66 | void *assoc_get(struct assoc *assoc, const char *key) 67 | { 68 | unsigned long hash; 69 | 70 | hash = assoc_hash(key) % assoc->size; 71 | while (assoc->keys[hash]) { 72 | if (!strcmp(assoc->keys[hash], key)) 73 | return assoc->values[hash]; 74 | 75 | hash = (hash + 1) % assoc->size; 76 | } 77 | 78 | return NULL; 79 | } 80 | 81 | static void _assoc_set(struct assoc *assoc, const char *key, void *value) 82 | { 83 | struct assoc new_set; 84 | unsigned long hash; 85 | unsigned long i; 86 | 87 | assert(assoc->fill < assoc->size); 88 | 89 | /* Grow set at 80% utilization */ 90 | if (5 * assoc->fill > 4 * assoc->size) { 91 | assoc_init(&new_set, assoc->size * 5 / 4); 92 | 93 | for (i = 0; i < assoc->size; i++) 94 | if (assoc->keys[i]) 95 | assoc_set(&new_set, assoc->keys[i], 96 | assoc->values[i]); 97 | 98 | free(assoc->keys); 99 | free(assoc->values); 100 | 101 | assoc->keys = new_set.keys; 102 | assoc->values = new_set.values; 103 | assoc->fill = new_set.fill; 104 | assoc->size = new_set.size; 105 | } 106 | 107 | hash = assoc_hash(key) % assoc->size; 108 | while (assoc->keys[hash]) { 109 | if (!strcmp(assoc->keys[hash], key)) { 110 | assoc->values[hash] = value; 111 | return; 112 | } 113 | 114 | hash = (hash + 1) % assoc->size; 115 | } 116 | 117 | assoc->keys[hash] = key; 118 | assoc->values[hash] = value; 119 | assoc->fill++; 120 | } 121 | 122 | void assoc_set(struct assoc *assoc, const char *key, void *value) 123 | { 124 | _assoc_set(assoc, strdup(key), value); 125 | } 126 | 127 | const char *assoc_next(struct assoc *assoc, void **value, unsigned long *iter) 128 | { 129 | unsigned long it = *iter; 130 | 131 | while (it < assoc->size && !assoc->keys[it]) 132 | it++; 133 | 134 | if (it == assoc->size) 135 | return NULL; 136 | 137 | *iter = it + 1; 138 | 139 | if (it < assoc->size) { 140 | if (value) 141 | *value = assoc->values[it]; 142 | return assoc->keys[it]; 143 | } else { 144 | return NULL; 145 | } 146 | } 147 | 148 | void assoc_destroy(struct assoc *assoc) 149 | { 150 | unsigned long i; 151 | 152 | for (i = 0; i < assoc->size; i++) 153 | free((void*)assoc->keys[i]); 154 | 155 | free(assoc->keys); 156 | free(assoc->values); 157 | assoc->size = 0; 158 | } 159 | -------------------------------------------------------------------------------- /servreg_loc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "servreg_loc.h" 4 | 5 | struct qmi_elem_info servreg_loc_qmi_result_ei[] = { 6 | { 7 | .data_type = QMI_UNSIGNED_2_BYTE, 8 | .elem_len = 1, 9 | .elem_size = sizeof(uint16_t), 10 | .offset = offsetof(struct servreg_loc_qmi_result, result), 11 | }, 12 | { 13 | .data_type = QMI_UNSIGNED_2_BYTE, 14 | .elem_len = 1, 15 | .elem_size = sizeof(uint16_t), 16 | .offset = offsetof(struct servreg_loc_qmi_result, error), 17 | }, 18 | {} 19 | }; 20 | 21 | struct qmi_elem_info servreg_loc_domain_list_entry_ei[] = { 22 | { 23 | .data_type = QMI_STRING, 24 | .elem_len = 256, 25 | .elem_size = sizeof(char), 26 | .offset = offsetof(struct servreg_loc_domain_list_entry, name) 27 | }, 28 | { 29 | .data_type = QMI_UNSIGNED_4_BYTE, 30 | .elem_len = 1, 31 | .elem_size = sizeof(uint32_t), 32 | .offset = offsetof(struct servreg_loc_domain_list_entry, instance_id), 33 | }, 34 | { 35 | .data_type = QMI_UNSIGNED_1_BYTE, 36 | .elem_len = 1, 37 | .elem_size = sizeof(uint8_t), 38 | .offset = offsetof(struct servreg_loc_domain_list_entry, service_data_valid), 39 | }, 40 | { 41 | .data_type = QMI_UNSIGNED_4_BYTE, 42 | .elem_len = 1, 43 | .elem_size = sizeof(uint32_t), 44 | .offset = offsetof(struct servreg_loc_domain_list_entry, service_data), 45 | }, 46 | {} 47 | }; 48 | 49 | struct qmi_elem_info servreg_loc_get_domain_list_req_ei[] = { 50 | { 51 | .data_type = QMI_STRING, 52 | .elem_len = 256, 53 | .elem_size = sizeof(char), 54 | .array_type = VAR_LEN_ARRAY, 55 | .tlv_type = 1, 56 | .offset = offsetof(struct servreg_loc_get_domain_list_req, name) 57 | }, 58 | { 59 | .data_type = QMI_OPT_FLAG, 60 | .elem_len = 1, 61 | .elem_size = sizeof(bool), 62 | .tlv_type = 16, 63 | .offset = offsetof(struct servreg_loc_get_domain_list_req, offset_valid), 64 | }, 65 | { 66 | .data_type = QMI_UNSIGNED_4_BYTE, 67 | .elem_len = 1, 68 | .elem_size = sizeof(uint32_t), 69 | .tlv_type = 16, 70 | .offset = offsetof(struct servreg_loc_get_domain_list_req, offset), 71 | }, 72 | {} 73 | }; 74 | 75 | struct qmi_elem_info servreg_loc_get_domain_list_resp_ei[] = { 76 | { 77 | .data_type = QMI_STRUCT, 78 | .elem_len = 1, 79 | .elem_size = sizeof(struct servreg_loc_qmi_result), 80 | .tlv_type = 2, 81 | .offset = offsetof(struct servreg_loc_get_domain_list_resp, result), 82 | .ei_array = servreg_loc_qmi_result_ei, 83 | }, 84 | { 85 | .data_type = QMI_OPT_FLAG, 86 | .elem_len = 1, 87 | .elem_size = sizeof(bool), 88 | .tlv_type = 16, 89 | .offset = offsetof(struct servreg_loc_get_domain_list_resp, total_domains_valid), 90 | }, 91 | { 92 | .data_type = QMI_UNSIGNED_2_BYTE, 93 | .elem_len = 1, 94 | .elem_size = sizeof(uint16_t), 95 | .tlv_type = 16, 96 | .offset = offsetof(struct servreg_loc_get_domain_list_resp, total_domains), 97 | }, 98 | { 99 | .data_type = QMI_OPT_FLAG, 100 | .elem_len = 1, 101 | .elem_size = sizeof(bool), 102 | .tlv_type = 17, 103 | .offset = offsetof(struct servreg_loc_get_domain_list_resp, db_revision_valid), 104 | }, 105 | { 106 | .data_type = QMI_UNSIGNED_2_BYTE, 107 | .elem_len = 1, 108 | .elem_size = sizeof(uint16_t), 109 | .tlv_type = 17, 110 | .offset = offsetof(struct servreg_loc_get_domain_list_resp, db_revision), 111 | }, 112 | { 113 | .data_type = QMI_OPT_FLAG, 114 | .elem_len = 1, 115 | .elem_size = sizeof(bool), 116 | .tlv_type = 18, 117 | .offset = offsetof(struct servreg_loc_get_domain_list_resp, domain_list_valid), 118 | }, 119 | { 120 | .data_type = QMI_DATA_LEN, 121 | .elem_len = 1, 122 | .elem_size = sizeof(uint8_t), 123 | .tlv_type = 18, 124 | .offset = offsetof(struct servreg_loc_get_domain_list_resp, domain_list_len), 125 | }, 126 | { 127 | .data_type = QMI_STRUCT, 128 | .elem_len = 255, 129 | .elem_size = sizeof(struct servreg_loc_domain_list_entry), 130 | .array_type = VAR_LEN_ARRAY, 131 | .tlv_type = 18, 132 | .offset = offsetof(struct servreg_loc_get_domain_list_resp, domain_list), 133 | .ei_array = servreg_loc_domain_list_entry_ei, 134 | }, 135 | {} 136 | }; 137 | 138 | struct qmi_elem_info servreg_loc_pfr_req_ei[] = { 139 | { 140 | .data_type = QMI_STRING, 141 | .elem_len = 256, 142 | .elem_size = sizeof(char), 143 | .array_type = VAR_LEN_ARRAY, 144 | .tlv_type = 1, 145 | .offset = offsetof(struct servreg_loc_pfr_req, service) 146 | }, 147 | { 148 | .data_type = QMI_STRING, 149 | .elem_len = 256, 150 | .elem_size = sizeof(char), 151 | .array_type = VAR_LEN_ARRAY, 152 | .tlv_type = 2, 153 | .offset = offsetof(struct servreg_loc_pfr_req, reason) 154 | }, 155 | {} 156 | }; 157 | 158 | struct qmi_elem_info servreg_loc_pfr_resp_ei[] = { 159 | { 160 | .data_type = QMI_STRUCT, 161 | .elem_len = 1, 162 | .elem_size = sizeof(struct servreg_loc_qmi_result), 163 | .tlv_type = 2, 164 | .offset = offsetof(struct servreg_loc_pfr_resp, result), 165 | .ei_array = servreg_loc_qmi_result_ei, 166 | }, 167 | {} 168 | }; 169 | 170 | -------------------------------------------------------------------------------- /lzma_decomp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Original Author: Lasse Collin 3 | * LZMA boilerplate decompression example. 4 | * 5 | * Imported to pd-mapper by Jeremy Linton 6 | * who reworked the main() into lzma_decomp() 7 | * which returns a FD to a decompressed/unlinked 8 | * file. 9 | * 10 | * This file has been put into the public domain. 11 | * You can do whatever you want with this file. 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | static bool 25 | init_decoder(lzma_stream *strm) 26 | { 27 | // Initialize a .xz decoder. The decoder supports a memory usage limit 28 | // and a set of flags. 29 | // 30 | // The memory usage of the decompressor depends on the settings used 31 | // to compress a .xz file. It can vary from less than a megabyte to 32 | // a few gigabytes, but in practice (at least for now) it rarely 33 | // exceeds 65 MiB because that's how much memory is required to 34 | // decompress files created with "xz -9". Settings requiring more 35 | // memory take extra effort to use and don't (at least for now) 36 | // provide significantly better compression in most cases. 37 | // 38 | // Memory usage limit is useful if it is important that the 39 | // decompressor won't consume gigabytes of memory. The need 40 | // for limiting depends on the application. In this example, 41 | // no memory usage limiting is used. This is done by setting 42 | // the limit to UINT64_MAX. 43 | // 44 | // The .xz format allows concatenating compressed files as is: 45 | // 46 | // echo foo | xz > foobar.xz 47 | // echo bar | xz >> foobar.xz 48 | // 49 | // When decompressing normal standalone .xz files, LZMA_CONCATENATED 50 | // should always be used to support decompression of concatenated 51 | // .xz files. If LZMA_CONCATENATED isn't used, the decoder will stop 52 | // after the first .xz stream. This can be useful when .xz data has 53 | // been embedded inside another file format. 54 | // 55 | // Flags other than LZMA_CONCATENATED are supported too, and can 56 | // be combined with bitwise-or. See lzma/container.h 57 | // (src/liblzma/api/lzma/container.h in the source package or e.g. 58 | // /usr/include/lzma/container.h depending on the install prefix) 59 | // for details. 60 | lzma_ret ret = lzma_stream_decoder( 61 | strm, UINT64_MAX, LZMA_CONCATENATED); 62 | 63 | // Return successfully if the initialization went fine. 64 | if (ret == LZMA_OK) 65 | return true; 66 | 67 | // Something went wrong. The possible errors are documented in 68 | // lzma/container.h (src/liblzma/api/lzma/container.h in the source 69 | // package or e.g. /usr/include/lzma/container.h depending on the 70 | // install prefix). 71 | // 72 | // Note that LZMA_MEMLIMIT_ERROR is never possible here. If you 73 | // specify a very tiny limit, the error will be delayed until 74 | // the first headers have been parsed by a call to lzma_code(). 75 | const char *msg; 76 | switch (ret) { 77 | case LZMA_MEM_ERROR: 78 | msg = "Memory allocation failed"; 79 | break; 80 | 81 | case LZMA_OPTIONS_ERROR: 82 | msg = "Unsupported decompressor flags"; 83 | break; 84 | 85 | default: 86 | // This is most likely LZMA_PROG_ERROR indicating a bug in 87 | // this program or in liblzma. It is inconvenient to have a 88 | // separate error message for errors that should be impossible 89 | // to occur, but knowing the error code is important for 90 | // debugging. That's why it is good to print the error code 91 | // at least when there is no good error message to show. 92 | msg = "Unknown error, possibly a bug"; 93 | break; 94 | } 95 | 96 | fprintf(stderr, "Error initializing the decoder: %s (error code %u)\n", 97 | msg, ret); 98 | return false; 99 | } 100 | 101 | 102 | static bool 103 | decompress(lzma_stream *strm, const char *inname, FILE *infile, int outfile) 104 | { 105 | // When LZMA_CONCATENATED flag was used when initializing the decoder, 106 | // we need to tell lzma_code() when there will be no more input. 107 | // This is done by setting action to LZMA_FINISH instead of LZMA_RUN 108 | // in the same way as it is done when encoding. 109 | // 110 | // When LZMA_CONCATENATED isn't used, there is no need to use 111 | // LZMA_FINISH to tell when all the input has been read, but it 112 | // is still OK to use it if you want. When LZMA_CONCATENATED isn't 113 | // used, the decoder will stop after the first .xz stream. In that 114 | // case some unused data may be left in strm->next_in. 115 | lzma_action action = LZMA_RUN; 116 | 117 | uint8_t inbuf[BUFSIZ]; 118 | uint8_t outbuf[BUFSIZ]; 119 | 120 | strm->next_in = NULL; 121 | strm->avail_in = 0; 122 | strm->next_out = outbuf; 123 | strm->avail_out = sizeof(outbuf); 124 | 125 | while (true) { 126 | if (strm->avail_in == 0 && !feof(infile)) { 127 | strm->next_in = inbuf; 128 | strm->avail_in = fread(inbuf, 1, sizeof(inbuf), 129 | infile); 130 | 131 | if (ferror(infile)) { 132 | fprintf(stderr, "%s: Read error: %s\n", 133 | inname, strerror(errno)); 134 | return false; 135 | } 136 | 137 | // Once the end of the input file has been reached, 138 | // we need to tell lzma_code() that no more input 139 | // will be coming. As said before, this isn't required 140 | // if the LZMA_CONCATENATED flag isn't used when 141 | // initializing the decoder. 142 | if (feof(infile)) 143 | action = LZMA_FINISH; 144 | } 145 | 146 | lzma_ret ret = lzma_code(strm, action); 147 | 148 | if (strm->avail_out == 0 || ret == LZMA_STREAM_END) { 149 | size_t write_size = sizeof(outbuf) - strm->avail_out; 150 | 151 | if (write(outfile, outbuf, write_size) != write_size) { 152 | fprintf(stderr, "Write error: %s\n", 153 | strerror(errno)); 154 | return false; 155 | } 156 | 157 | strm->next_out = outbuf; 158 | strm->avail_out = sizeof(outbuf); 159 | } 160 | 161 | if (ret != LZMA_OK) { 162 | // Once everything has been decoded successfully, the 163 | // return value of lzma_code() will be LZMA_STREAM_END. 164 | // 165 | // It is important to check for LZMA_STREAM_END. Do not 166 | // assume that getting ret != LZMA_OK would mean that 167 | // everything has gone well or that when you aren't 168 | // getting more output it must have successfully 169 | // decoded everything. 170 | if (ret == LZMA_STREAM_END) 171 | return true; 172 | 173 | // It's not LZMA_OK nor LZMA_STREAM_END, 174 | // so it must be an error code. See lzma/base.h 175 | // (src/liblzma/api/lzma/base.h in the source package 176 | // or e.g. /usr/include/lzma/base.h depending on the 177 | // install prefix) for the list and documentation of 178 | // possible values. Many values listen in lzma_ret 179 | // enumeration aren't possible in this example, but 180 | // can be made possible by enabling memory usage limit 181 | // or adding flags to the decoder initialization. 182 | const char *msg; 183 | switch (ret) { 184 | case LZMA_MEM_ERROR: 185 | msg = "Memory allocation failed"; 186 | break; 187 | 188 | case LZMA_FORMAT_ERROR: 189 | // .xz magic bytes weren't found. 190 | msg = "The input is not in the .xz format"; 191 | break; 192 | 193 | case LZMA_OPTIONS_ERROR: 194 | // For example, the headers specify a filter 195 | // that isn't supported by this liblzma 196 | // version (or it hasn't been enabled when 197 | // building liblzma, but no-one sane does 198 | // that unless building liblzma for an 199 | // embedded system). Upgrading to a newer 200 | // liblzma might help. 201 | // 202 | // Note that it is unlikely that the file has 203 | // accidentally became corrupt if you get this 204 | // error. The integrity of the .xz headers is 205 | // always verified with a CRC32, so 206 | // unintentionally corrupt files can be 207 | // distinguished from unsupported files. 208 | msg = "Unsupported compression options"; 209 | break; 210 | 211 | case LZMA_DATA_ERROR: 212 | msg = "Compressed file is corrupt"; 213 | break; 214 | 215 | case LZMA_BUF_ERROR: 216 | // Typically this error means that a valid 217 | // file has got truncated, but it might also 218 | // be a damaged part in the file that makes 219 | // the decoder think the file is truncated. 220 | // If you prefer, you can use the same error 221 | // message for this as for LZMA_DATA_ERROR. 222 | msg = "Compressed file is truncated or " 223 | "otherwise corrupt"; 224 | break; 225 | 226 | default: 227 | // This is most likely LZMA_PROG_ERROR. 228 | msg = "Unknown error, possibly a bug"; 229 | break; 230 | } 231 | 232 | fprintf(stderr, "%s: Decoder error: " 233 | "%s (error code %u)\n", 234 | inname, msg, ret); 235 | return false; 236 | } 237 | } 238 | } 239 | 240 | #define TEMP_TEMPLATE "/tmp/pd-mapperXXXXXX" 241 | 242 | 243 | int lzma_decomp(const char *file) 244 | { 245 | int return_fd; 246 | char temp_file[sizeof(TEMP_TEMPLATE)]; 247 | lzma_stream strm = LZMA_STREAM_INIT; 248 | 249 | strcpy(temp_file, TEMP_TEMPLATE); 250 | 251 | return_fd = mkstemp(temp_file); 252 | if (return_fd < 0) 253 | return return_fd; 254 | 255 | unlink(temp_file); 256 | 257 | // Try to decompress all files. 258 | if (!init_decoder(&strm)) { 259 | // Decoder initialization failed. There's no point 260 | // to retry it so we need to exit. 261 | close(return_fd); 262 | return -1; 263 | } 264 | 265 | FILE *infile = fopen(file, "rb"); 266 | 267 | if (infile == NULL) { 268 | fprintf(stderr, "%s: Error opening the input file: %s\n", 269 | file, strerror(errno)); 270 | close(return_fd); 271 | return_fd = -1; 272 | } else { 273 | if (!decompress(&strm, file, infile, return_fd)) { 274 | close(return_fd); 275 | return_fd = -1; 276 | } else { 277 | lseek(return_fd, 0, SEEK_SET); 278 | } 279 | fclose(infile); 280 | } 281 | 282 | // Free the memory allocated for the decoder. This only needs to be 283 | // done after the last file. 284 | lzma_end(&strm); 285 | 286 | return return_fd; 287 | } 288 | -------------------------------------------------------------------------------- /json.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2019, 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 | */ 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include "json.h" 42 | 43 | static const char *input_buf; 44 | static int input_pos; 45 | static int input_len; 46 | 47 | static int json_parse_array(struct json_value *array); 48 | static int json_parse_object(struct json_value *object); 49 | static int json_parse_property(struct json_value *value); 50 | 51 | static int input(void) 52 | { 53 | if (input_pos >= input_len) 54 | return 0; 55 | 56 | return input_buf[input_pos++]; 57 | } 58 | 59 | static void unput(void) 60 | { 61 | input_pos--; 62 | } 63 | 64 | static void json_skip_whitespace(void) 65 | { 66 | int ch; 67 | 68 | while ((ch = input()) && isspace(ch)) 69 | ; 70 | unput(); 71 | } 72 | 73 | static int json_parse_string(struct json_value *value) 74 | { 75 | char buf[128]; 76 | char *b = buf; 77 | int ch; 78 | 79 | ch = input(); 80 | if (ch != '"') { 81 | unput(); 82 | return 0; 83 | } 84 | 85 | while ((ch = input()) && ch != '"' && b - buf < sizeof(buf) - 1) 86 | *b++ = ch; 87 | *b = '\0'; 88 | 89 | if (!ch) 90 | return -1; 91 | 92 | value->type = JSON_TYPE_STRING; 93 | value->u.string = strdup(buf); 94 | 95 | return 1; 96 | } 97 | 98 | static int json_parse_number(struct json_value *value) 99 | { 100 | char buf[20]; 101 | char *b = buf; 102 | int ch; 103 | 104 | while ((ch = input()) && isdigit(ch) && b - buf < sizeof(buf) - 1) 105 | *b++ = ch; 106 | *b = '\0'; 107 | unput(); 108 | 109 | if (b == buf) 110 | return 0; 111 | 112 | value->type = JSON_TYPE_NUMBER; 113 | value->u.number = strtod(buf, NULL); 114 | 115 | return 1; 116 | } 117 | 118 | static int json_parse_keyword(struct json_value *value) 119 | { 120 | const char *match; 121 | const char *m; 122 | int ch; 123 | 124 | ch = input(); 125 | switch (ch) { 126 | case 't': 127 | match = "true"; 128 | value->type = JSON_TYPE_TRUE; 129 | break; 130 | case 'f': 131 | match = "false"; 132 | value->type = JSON_TYPE_FALSE; 133 | break; 134 | case 'n': 135 | match = "null"; 136 | value->type = JSON_TYPE_NULL; 137 | break; 138 | default: 139 | unput(); 140 | return 0; 141 | } 142 | 143 | m = match; 144 | while (*m && *m++ == ch) 145 | ch = input(); 146 | unput(); 147 | 148 | return *m == '\0' ? 1 : -1; 149 | } 150 | 151 | static int json_parse_value(struct json_value *value) 152 | { 153 | int ret; 154 | 155 | json_skip_whitespace(); 156 | 157 | ret = json_parse_object(value); 158 | if (ret) 159 | goto out; 160 | 161 | ret = json_parse_array(value); 162 | if (ret) 163 | goto out; 164 | 165 | ret = json_parse_string(value); 166 | if (ret) 167 | goto out; 168 | 169 | ret = json_parse_number(value); 170 | if (ret) 171 | goto out; 172 | 173 | ret = json_parse_keyword(value); 174 | if (ret) 175 | goto out; 176 | 177 | fprintf(stderr, "unable to match a value\n"); 178 | return -1; 179 | 180 | out: 181 | json_skip_whitespace(); 182 | return ret; 183 | } 184 | 185 | static int json_parse_array(struct json_value *array) 186 | { 187 | struct json_value *value; 188 | struct json_value *last = NULL; 189 | int ret; 190 | int ch; 191 | 192 | ch = input(); 193 | if (ch != '[') { 194 | unput(); 195 | return 0; 196 | } 197 | 198 | array->type = JSON_TYPE_ARRAY; 199 | do { 200 | value = calloc(1, sizeof(*value)); 201 | if (!value) 202 | return -1; 203 | 204 | ret = json_parse_value(value); 205 | if (ret <= 0) { 206 | free(value); 207 | return -1; 208 | } 209 | 210 | if (!array->u.value) 211 | array->u.value = value; 212 | if (last) 213 | last->next = value; 214 | last = value; 215 | 216 | ch = input(); 217 | if (ch == ']') { 218 | return 1; 219 | } 220 | 221 | } while (ch == ','); 222 | 223 | fprintf(stderr, "expected ',' got '%c'\n", ch); 224 | 225 | return -1; 226 | } 227 | 228 | static int json_parse_object(struct json_value *object) 229 | { 230 | struct json_value *value; 231 | struct json_value *last = NULL; 232 | int ret; 233 | int ch; 234 | 235 | ch = input(); 236 | if (ch != '{') { 237 | unput(); 238 | return 0; 239 | } 240 | 241 | object->type = JSON_TYPE_OBJECT; 242 | 243 | do { 244 | value = calloc(1, sizeof(*value)); 245 | if (!value) 246 | return -1; 247 | 248 | ret = json_parse_property(value); 249 | if (ret <= 0) { 250 | free(value); 251 | return -1; 252 | } 253 | 254 | if (!object->u.value) 255 | object->u.value = value; 256 | if (last) 257 | last->next = value; 258 | last = value; 259 | 260 | ch = input(); 261 | if (ch == '}') { 262 | return 1; 263 | } 264 | } while (ch == ','); 265 | 266 | return -1; 267 | } 268 | 269 | static int json_parse_property(struct json_value *value) 270 | { 271 | struct json_value key; 272 | int ret; 273 | int ch; 274 | 275 | json_skip_whitespace(); 276 | 277 | ret = json_parse_string(&key); 278 | if (ret <= 0) 279 | return -1; 280 | 281 | value->key = key.u.string; 282 | 283 | json_skip_whitespace(); 284 | 285 | ch = input(); 286 | if (ch != ':') 287 | return -1; 288 | 289 | ret = json_parse_value(value); 290 | if (ret <= 0) 291 | return -1; 292 | 293 | return 1; 294 | } 295 | 296 | struct json_value *json_parse(const char *json) 297 | { 298 | struct json_value *root; 299 | int ret; 300 | 301 | input_buf = json; 302 | input_pos = 0; 303 | input_len = strlen(input_buf); 304 | 305 | root = calloc(1, sizeof(*root)); 306 | if (!root) 307 | return NULL; 308 | 309 | ret = json_parse_value(root); 310 | if (ret != 1) { 311 | free(root); 312 | return NULL; 313 | } 314 | 315 | return root; 316 | } 317 | 318 | extern int lzma_decomp(const char *file); 319 | 320 | struct json_value *json_parse_file(const char *file) 321 | { 322 | struct json_value *root; 323 | struct stat sb; 324 | int ret; 325 | int fd; 326 | 327 | if ((strlen(file) > 3) && !strcmp(&file[strlen(file)-3], ".xz")) 328 | fd = lzma_decomp(file); 329 | else 330 | fd = open(file, O_RDONLY); 331 | 332 | if (fd < 0) { 333 | fprintf(stderr, "failed to open %s: %s\n", file, strerror(errno)); 334 | return NULL; 335 | } 336 | 337 | ret = fstat(fd, &sb); 338 | if (ret < 0) 339 | return NULL; 340 | 341 | input_pos = 0; 342 | input_len = sb.st_size; 343 | input_buf = malloc(sb.st_size); 344 | 345 | ret = read(fd, (char *)input_buf, input_len); 346 | 347 | close(fd); 348 | 349 | if (ret != input_len) { 350 | fprintf(stderr, "failed to read %d bytes form %s\n", input_len, file); 351 | return NULL; 352 | } 353 | 354 | root = calloc(1, sizeof(*root)); 355 | if (!root) 356 | return NULL; 357 | 358 | ret = json_parse_value(root); 359 | if (ret != 1) { 360 | json_free(root); 361 | return NULL; 362 | } 363 | 364 | return root; 365 | } 366 | 367 | struct json_value *json_get_child(struct json_value *object, const char *key) 368 | { 369 | struct json_value *it; 370 | 371 | if(object->type != JSON_TYPE_OBJECT) 372 | return NULL; 373 | 374 | for (it = object->u.value; it; it = it->next) { 375 | if (!strcmp(it->key, key)) 376 | return it; 377 | } 378 | 379 | return NULL; 380 | } 381 | 382 | int json_count_children(struct json_value *array) 383 | { 384 | struct json_value *it; 385 | int count = 0; 386 | 387 | if (!array || array->type != JSON_TYPE_ARRAY) 388 | return -1; 389 | 390 | for (it = array->u.value; it; it = it->next) 391 | count++; 392 | 393 | return count; 394 | } 395 | 396 | int json_get_number(struct json_value *object, const char *key, double *number) 397 | { 398 | struct json_value *it; 399 | 400 | if (!object || object->type != JSON_TYPE_OBJECT) 401 | return -1; 402 | 403 | for (it = object->u.value; it; it = it->next) { 404 | if (!strcmp(it->key, key)) { 405 | if (it->type != JSON_TYPE_NUMBER) 406 | return -1; 407 | 408 | *number = it->u.number; 409 | return 0; 410 | } 411 | } 412 | 413 | return -1; 414 | } 415 | 416 | const char *json_get_string(struct json_value *object, const char *key) 417 | { 418 | struct json_value *it; 419 | 420 | if (!object || object->type != JSON_TYPE_OBJECT) 421 | return NULL; 422 | 423 | for (it = object->u.value; it; it = it->next) { 424 | if (!strcmp(it->key, key)) { 425 | if (it->type != JSON_TYPE_STRING) 426 | return NULL; 427 | 428 | return it->u.string; 429 | } 430 | } 431 | 432 | return NULL; 433 | } 434 | 435 | void json_free(struct json_value *value) 436 | { 437 | struct json_value *next; 438 | struct json_value *it; 439 | 440 | free((char *)value->key); 441 | 442 | switch (value->type) { 443 | case JSON_TYPE_OBJECT: 444 | case JSON_TYPE_ARRAY: 445 | it = value->u.value; 446 | while (it) { 447 | next = it->next; 448 | json_free(it); 449 | it = next; 450 | } 451 | break; 452 | case JSON_TYPE_STRING: 453 | free((char *)value->u.string); 454 | break; 455 | } 456 | 457 | free(value); 458 | } 459 | -------------------------------------------------------------------------------- /pd-mapper.c: -------------------------------------------------------------------------------- 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 | */ 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "assoc.h" 46 | #include "json.h" 47 | #include "servreg_loc.h" 48 | 49 | struct pd_map { 50 | const char *service; 51 | const char *domain; 52 | int instance; 53 | }; 54 | 55 | static struct pd_map *pd_maps; 56 | 57 | static void handle_get_domain_list(int sock, const struct qrtr_packet *pkt) 58 | { 59 | struct servreg_loc_get_domain_list_resp resp = {}; 60 | struct servreg_loc_get_domain_list_req req = {}; 61 | struct servreg_loc_domain_list_entry *entry; 62 | DEFINE_QRTR_PACKET(resp_buf, 256); 63 | const struct pd_map *pd_map = pd_maps; 64 | unsigned int txn; 65 | ssize_t len; 66 | int ret; 67 | 68 | ret = qmi_decode_message(&req, &txn, pkt, QMI_REQUEST, 69 | SERVREG_LOC_GET_DOMAIN_LIST, 70 | servreg_loc_get_domain_list_req_ei); 71 | if (ret < 0) { 72 | resp.result.result = QMI_RESULT_FAILURE; 73 | resp.result.error = QMI_ERR_MALFORMED_MSG; 74 | goto respond; 75 | } 76 | 77 | req.name[sizeof(req.name)-1] = '\0'; 78 | 79 | resp.result.result = QMI_RESULT_SUCCESS; 80 | resp.db_revision_valid = 1; 81 | resp.db_revision = 1; 82 | 83 | while (pd_map->service) { 84 | if (!strcmp(pd_map->service, req.name)) { 85 | entry = &resp.domain_list[resp.domain_list_len++]; 86 | 87 | strcpy(entry->name, pd_map->domain); 88 | entry->name_len = strlen(pd_map->domain); 89 | entry->instance_id = pd_map->instance; 90 | } 91 | 92 | pd_map++; 93 | } 94 | 95 | if (resp.domain_list_len) 96 | resp.domain_list_valid = 1; 97 | 98 | resp.total_domains_valid = 1; 99 | resp.total_domains = resp.domain_list_len; 100 | 101 | respond: 102 | len = qmi_encode_message(&resp_buf, 103 | QMI_RESPONSE, SERVREG_LOC_GET_DOMAIN_LIST, 104 | txn, &resp, 105 | servreg_loc_get_domain_list_resp_ei); 106 | if (len < 0) { 107 | fprintf(stderr, 108 | "[PD-MAPPER] failed to encode get_domain_list response: %s\n", 109 | strerror(-len)); 110 | return; 111 | } 112 | 113 | ret = qrtr_sendto(sock, pkt->node, pkt->port, 114 | resp_buf.data, resp_buf.data_len); 115 | if (ret < 0) { 116 | fprintf(stderr, 117 | "[PD-MAPPER] failed to send get_domain_list response: %s\n", 118 | strerror(-ret)); 119 | } 120 | } 121 | 122 | static int pd_load_map(const char *file) 123 | { 124 | static int num_pd_maps; 125 | struct json_value *sr_service; 126 | struct json_value *sr_domain; 127 | struct json_value *root; 128 | struct json_value *it; 129 | const char *subdomain; 130 | const char *provider; 131 | const char *service; 132 | const char *domain; 133 | const char *soc; 134 | struct pd_map *newp; 135 | struct pd_map *map; 136 | double number; 137 | int count; 138 | int ret; 139 | 140 | root = json_parse_file(file); 141 | if (!root) 142 | return -1; 143 | 144 | sr_domain = json_get_child(root, "sr_domain"); 145 | soc = json_get_string(sr_domain, "soc"); 146 | domain = json_get_string(sr_domain, "domain"); 147 | subdomain = json_get_string(sr_domain, "subdomain"); 148 | ret = json_get_number(sr_domain, "qmi_instance_id", &number); 149 | if (ret) 150 | return ret; 151 | 152 | if (!soc || !domain || !subdomain) { 153 | fprintf(stderr, "failed to parse sr_domain\n"); 154 | return -1; 155 | } 156 | 157 | sr_service = json_get_child(root, "sr_service"); 158 | count = json_count_children(sr_service); 159 | if (count < 0) 160 | return count; 161 | 162 | newp = realloc(pd_maps, (num_pd_maps + count + 1) * sizeof(*newp)); 163 | if (!newp) 164 | return -1; 165 | pd_maps = newp; 166 | 167 | for (it = sr_service->u.value; it; it = it->next) { 168 | provider = json_get_string(it, "provider"); 169 | service = json_get_string(it, "service"); 170 | 171 | if (!provider || !service) { 172 | fprintf(stderr, 173 | "failed to parse provdider or service from %s\n", 174 | file); 175 | return -1; 176 | } 177 | 178 | map = &pd_maps[num_pd_maps++]; 179 | 180 | map->service = malloc(strlen(provider) + strlen(service) + 2); 181 | sprintf((char *)map->service, "%s/%s", provider, service); 182 | 183 | map->domain = malloc(strlen(soc) + strlen(domain) + strlen(subdomain) + 3); 184 | sprintf((char *)map->domain, "%s/%s/%s", soc, domain, subdomain); 185 | 186 | map->instance = number; 187 | } 188 | 189 | pd_maps[num_pd_maps].service = NULL; 190 | 191 | json_free(root); 192 | 193 | return 0; 194 | } 195 | 196 | static int concat_path(char *base_path, char *firmware_path, char *path) 197 | { 198 | if ((strlen(base_path) > 0) && (strlen(base_path) + 1 + strlen(firmware_path) + 1 < PATH_MAX)) { 199 | strcpy(path, base_path); 200 | strcat(path, "/"); 201 | strcat(path, firmware_path); 202 | return 0; 203 | } else { 204 | warn("Path length exceeded %lu\n", sizeof(path)); 205 | } 206 | return -1; 207 | } 208 | 209 | #ifndef ANDROID 210 | #define FIRMWARE_BASE "/lib/firmware/" 211 | #define FIRMWARE_PARAM_PATH "/sys/module/firmware_class/parameters/path" 212 | 213 | static DIR *opendir_firmware(char *firmware_path, char *out_path_opened) 214 | { 215 | int ret = 0, n; 216 | DIR *fw_dir = NULL; 217 | int fw_param_path = open(FIRMWARE_PARAM_PATH, O_RDONLY); 218 | char fw_sysfs_path[PATH_MAX]; 219 | 220 | if (fw_param_path < 0) { 221 | warn("Cannot open sysfs path: %s", FIRMWARE_PARAM_PATH); 222 | close(fw_param_path); 223 | goto err; 224 | } 225 | 226 | n = read(fw_param_path, fw_sysfs_path, sizeof(char) * PATH_MAX); 227 | close(fw_param_path); 228 | if (n < 0) { 229 | warn("Cannot read sysfs path: %s", FIRMWARE_PARAM_PATH); 230 | goto err; 231 | } 232 | 233 | fw_sysfs_path[n - 1] = '\0'; 234 | 235 | ret = concat_path(fw_sysfs_path, firmware_path, out_path_opened); 236 | if (ret) 237 | goto err; 238 | 239 | fw_dir = opendir(out_path_opened); 240 | if (!fw_dir) 241 | goto err; 242 | 243 | return fw_dir; 244 | err: 245 | ret = concat_path(fw_sysfs_path, FIRMWARE_BASE, out_path_opened); 246 | if (ret) 247 | return fw_dir; 248 | 249 | fw_dir = opendir(out_path_opened); 250 | if (!fw_dir) 251 | warn("Cannot open firmware path: %s", fw_sysfs_path); 252 | 253 | return fw_dir; 254 | } 255 | #else 256 | #define FIRMWARE_BASE "/vendor/firmware/" 257 | 258 | DIR opendir_firmware(char *firmware_path) 259 | { 260 | return open_concat_path("/vendor/firmware/", firmware_path); 261 | } 262 | #endif 263 | 264 | static char *known_extensions[] = { 265 | ".jsn.xz", 266 | ".jsn", 267 | NULL, 268 | }; 269 | 270 | static int pd_enumerate_jsons(struct assoc *json_set) 271 | { 272 | char firmware_value[PATH_MAX]; 273 | char *firmware_value_copy = NULL; 274 | char *firmware_path = NULL; 275 | char json_path[PATH_MAX]; 276 | char firmware_attr[32]; 277 | struct dirent *fw_de; 278 | char path[PATH_MAX]; 279 | struct dirent *de; 280 | int firmware_fd; 281 | DIR *class_dir; 282 | int class_fd; 283 | DIR *fw_dir; 284 | size_t len; 285 | size_t n; 286 | 287 | class_fd = open("/sys/class/remoteproc", O_RDONLY | O_DIRECTORY); 288 | if (class_fd < 0) { 289 | warn("failed to open remoteproc class"); 290 | return -1; 291 | } 292 | 293 | class_dir = fdopendir(class_fd); 294 | if (!class_dir) { 295 | warn("failed to opendir"); 296 | goto close_class; 297 | } 298 | 299 | while ((de = readdir(class_dir)) != NULL) { 300 | if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) 301 | continue; 302 | 303 | if (strlen(de->d_name) + sizeof("/firmware") > sizeof(firmware_attr)) 304 | continue; 305 | 306 | strcpy(firmware_attr, de->d_name); 307 | strcat(firmware_attr, "/firmware"); 308 | 309 | firmware_fd = openat(class_fd, firmware_attr, O_RDONLY); 310 | if (firmware_fd < 0) 311 | continue; 312 | 313 | n = read(firmware_fd, firmware_value, sizeof(firmware_value)); 314 | close(firmware_fd); 315 | if (n < 0) { 316 | continue; 317 | } 318 | 319 | firmware_value[n] = '\0'; 320 | /* dirname() function can (and will) modify the parameter, so make a copy */ 321 | firmware_value_copy = strdup(firmware_value); 322 | firmware_path = dirname(firmware_value_copy); 323 | 324 | fw_dir = opendir_firmware(firmware_path, path); 325 | if (!fw_dir) 326 | continue; 327 | 328 | while ((fw_de = readdir(fw_dir)) != NULL) { 329 | int extens_index; 330 | bool found = false; 331 | 332 | if (!strcmp(fw_de->d_name, ".") || !strcmp(fw_de->d_name, "..")) 333 | continue; 334 | 335 | len = strlen(fw_de->d_name); 336 | 337 | for (extens_index = 0; known_extensions[extens_index] != NULL; extens_index++) { 338 | int extens_len = strlen(known_extensions[extens_index]); 339 | if (len > extens_len && 340 | !strcmp(&fw_de->d_name[len - extens_len], known_extensions[extens_index])) { 341 | found = true; 342 | break; 343 | } 344 | } 345 | 346 | if (!found) 347 | continue; 348 | 349 | if (strlen(path) + 1 + strlen(fw_de->d_name) + 1 > sizeof(json_path)) 350 | continue; 351 | 352 | strcpy(json_path, path); 353 | strcat(json_path, "/"); 354 | strcat(json_path, fw_de->d_name); 355 | 356 | assoc_set(json_set, json_path, NULL); 357 | } 358 | 359 | closedir(fw_dir); 360 | free(firmware_value_copy); 361 | } 362 | 363 | closedir(class_dir); 364 | close_class: 365 | close(class_fd); 366 | 367 | return 0; 368 | } 369 | 370 | static int pd_load_maps(void) 371 | { 372 | struct assoc json_set; 373 | unsigned long it; 374 | const char *jsn; 375 | int ret = 0; 376 | 377 | assoc_init(&json_set, 20); 378 | 379 | pd_enumerate_jsons(&json_set); 380 | 381 | assoc_foreach(jsn, NULL, &json_set, it) { 382 | ret = pd_load_map(jsn); 383 | if (ret < 0) 384 | break; 385 | } 386 | 387 | assoc_destroy(&json_set); 388 | 389 | return ret; 390 | } 391 | 392 | int main(int argc, char **argv) 393 | { 394 | struct sockaddr_qrtr sq; 395 | struct qrtr_packet pkt; 396 | unsigned int msg_id; 397 | socklen_t sl; 398 | char buf[4096]; 399 | int ret; 400 | int fd; 401 | 402 | ret = pd_load_maps(); 403 | if (ret) 404 | exit(1); 405 | 406 | if (!pd_maps) { 407 | fprintf(stderr, "no pd maps available\n"); 408 | exit(1); 409 | } 410 | 411 | fd = qrtr_open(0); 412 | if (fd < 0) { 413 | fprintf(stderr, "failed to open qrtr socket\n"); 414 | exit(1); 415 | } 416 | 417 | ret = qrtr_publish(fd, SERVREG_QMI_SERVICE, 418 | SERVREG_QMI_VERSION, SERVREG_QMI_INSTANCE); 419 | if (ret < 0) { 420 | fprintf(stderr, "failed to publish service registry service\n"); 421 | exit(1); 422 | } 423 | 424 | for (;;) { 425 | ret = qrtr_poll(fd, -1); 426 | if (ret < 0) { 427 | if (errno == EINTR) { 428 | continue; 429 | } else { 430 | fprintf(stderr, "qrtr_poll failed\n"); 431 | break; 432 | } 433 | } 434 | 435 | sl = sizeof(sq); 436 | ret = recvfrom(fd, buf, sizeof(buf), 0, (void *)&sq, &sl); 437 | if (ret < 0) { 438 | ret = -errno; 439 | if (ret != -ENETRESET) 440 | fprintf(stderr, "[PD-MAPPER] recvfrom failed: %d\n", ret); 441 | return ret; 442 | } 443 | 444 | ret = qrtr_decode(&pkt, buf, ret, &sq); 445 | if (ret < 0) { 446 | fprintf(stderr, "[PD-MAPPER] unable to decode qrtr packet\n"); 447 | return ret; 448 | } 449 | 450 | switch (pkt.type) { 451 | case QRTR_TYPE_DATA: 452 | ret = qmi_decode_header(&pkt, &msg_id); 453 | if (ret < 0) 454 | continue; 455 | 456 | switch (msg_id) { 457 | case SERVREG_LOC_GET_DOMAIN_LIST: 458 | handle_get_domain_list(fd, &pkt); 459 | break; 460 | case SERVREG_LOC_PFR: 461 | printf("[PD-MAPPER] pfr\n"); 462 | break; 463 | }; 464 | break; 465 | }; 466 | } 467 | 468 | close(fd); 469 | 470 | return 0; 471 | } 472 | --------------------------------------------------------------------------------