1 /* thread-service.c 2 * 3 * Copyright (c) 2023 Apple Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * Manage Thread service objects 18 */ 19 20 #include <stdlib.h> 21 #include <string.h> 22 #include <stdio.h> 23 #include <unistd.h> 24 #include <pwd.h> 25 #include <errno.h> 26 #include <sys/socket.h> 27 #include <netinet/in.h> 28 #include <arpa/inet.h> 29 #include <fcntl.h> 30 #include <time.h> 31 #include <dns_sd.h> 32 #include <net/if.h> 33 #include <inttypes.h> 34 #include <sys/resource.h> 35 #include <netinet/icmp6.h> 36 #include "srp.h" 37 #include "dns-msg.h" 38 #include "srp-crypto.h" 39 #include "ioloop.h" 40 #include "srp-mdns-proxy.h" 41 #include "dnssd-proxy.h" 42 #include "srp-gw.h" 43 #include "srp-proxy.h" 44 #include "config-parse.h" 45 #include "cti-services.h" 46 #include "thread-device.h" 47 #include "state-machine.h" 48 #include "thread-service.h" 49 50 const char * 51 thread_service_publication_state_name_get(thread_service_publication_state_t publication_state) 52 { 53 switch (publication_state) { 54 default: 55 return "<unknown>"; 56 case add_complete: 57 return "add_complete"; 58 case delete_complete: 59 return "delete_complete"; 60 case add_failed: 61 return "add_failed"; 62 case delete_failed: 63 return "delete_failed"; 64 case add_pending: 65 return "add_pending"; 66 case delete_pending: 67 return "delete_pending"; 68 case want_add: 69 return "want_add"; 70 case want_delete: 71 return "want_delete"; 72 } 73 } 74 75 static void 76 thread_service_finalize(thread_service_t *service) 77 { 78 free(service); 79 } 80 81 RELEASE_RETAIN_FUNCS(thread_service); 82 83 void 84 thread_service_list_release(thread_service_t **list_pointer) 85 { 86 while (*list_pointer != NULL) { 87 thread_service_t *service = *list_pointer; 88 *list_pointer = service->next; 89 RELEASE_HERE(service, thread_service); 90 } 91 } 92 93 thread_service_t * 94 thread_service_unicast_create_(uint16_t rloc16, uint8_t *address, uint8_t *port, uint8_t service_id, const char *file, int line) 95 { 96 thread_service_t *service; 97 98 service = calloc(1, sizeof(*service)); 99 if (service != NULL) { 100 in6prefix_copy_from_data(&service->u.unicast.address, address, sizeof(service->u.unicast.address)); 101 memcpy(&service->u.unicast.port, port, 2); 102 service->rloc16 = rloc16; 103 service->service_type = unicast_service; 104 service->service_id = service_id; 105 RETAIN(service, thread_service); 106 } 107 return service; 108 } 109 110 thread_service_t * 111 thread_service_anycast_create_(uint16_t rloc16, uint8_t sequence_number, uint8_t service_id, const char *file, int line) 112 { 113 thread_service_t *service; 114 115 service = calloc(1, sizeof(*service)); 116 if (service != NULL) { 117 service->rloc16 = rloc16; 118 service->u.anycast.sequence_number = sequence_number; 119 service->service_type = anycast_service; 120 service->service_id = service_id; 121 RETAIN(service, thread_service); 122 } 123 return service; 124 } 125 126 thread_service_t * 127 thread_service_pref_id_create_(uint16_t rloc16, uint8_t *partition_id, uint8_t *prefix, uint8_t service_id, const char *file, int line) 128 { 129 thread_service_t *service; 130 131 service = calloc(1, sizeof(*service)); 132 if (service != NULL) { 133 service->rloc16 = rloc16; 134 memcpy(&service->u.pref_id.partition_id, partition_id, 4); 135 memcpy(&service->u.pref_id.prefix, prefix, 5); 136 service->service_type = pref_id; 137 service->service_id = service_id; 138 RETAIN(service, thread_service); 139 } 140 return service; 141 } 142 143 void 144 thread_service_note(const char *owner_id, thread_service_t *tservice, const char *event_description) 145 { 146 switch(tservice->service_type) { 147 default: 148 INFO("invalid service type %d on service %p", tservice->service_type, tservice); 149 break; 150 case unicast_service: 151 { 152 struct thread_unicast_service *service = &tservice->u.unicast; 153 uint16_t port; 154 155 port = (uint16_t)(service->port[0] << 8) | service->port[1]; 156 SEGMENTED_IPv6_ADDR_GEN_SRP(&service->address, service_add_buf); 157 INFO(PUB_S_SRP " SRP service " PRI_SEGMENTED_IPv6_ADDR_SRP "%%%d, rloc16 %x " PUB_S_SRP, owner_id, 158 SEGMENTED_IPv6_ADDR_PARAM_SRP(&service->address, service_add_buf), 159 port, tservice->rloc16, event_description); 160 } 161 break; 162 case anycast_service: 163 { 164 struct thread_anycast_service *service = &tservice->u.anycast; 165 INFO(PUB_S_SRP " SRP service on RLOC16 %x with sequence number %02x " PUB_S_SRP, owner_id, 166 tservice->rloc16, service->sequence_number, event_description); 167 } 168 break; 169 case pref_id: 170 { 171 struct thread_pref_id *pref_id = &tservice->u.pref_id; 172 struct in6_addr addr; 173 174 addr.s6_addr[0] = 0xfd; 175 memcpy(&addr.s6_addr[1], pref_id->prefix, 5); 176 memset(&addr.s6_addr[6], 0, 10); 177 SEGMENTED_IPv6_ADDR_GEN_SRP(addr.s6_addr, addr_buf); 178 INFO(PUB_S_SRP " pref:id " PRI_SEGMENTED_IPv6_ADDR_SRP ":%02x%02x%02x%02x rloc %x " PUB_S_SRP, owner_id, 179 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr.s6_addr, addr_buf), 180 pref_id->partition_id[0], pref_id->partition_id[1], pref_id->partition_id[2], pref_id->partition_id[3], 181 tservice->rloc16, event_description); 182 } 183 break; 184 } 185 } 186 187 bool 188 thread_service_equal(thread_service_t *a, thread_service_t *b) 189 { 190 if (a == NULL || b == NULL) { 191 return false; 192 } 193 if (a->service_type != b->service_type) { 194 return false; 195 } 196 switch(a->service_type) { 197 default: 198 return false; 199 case unicast_service: 200 { 201 return (!in6addr_compare(&a->u.unicast.address, &b->u.unicast.address) && 202 !memcmp(a->u.unicast.port, b->u.unicast.port, 2)); 203 } 204 break; 205 case anycast_service: 206 { 207 return a->u.anycast.sequence_number == b->u.anycast.sequence_number; 208 } 209 break; 210 case pref_id: 211 { 212 return false; 213 } 214 break; 215 } 216 return false; 217 } 218 219 // Local Variables: 220 // mode: C 221 // tab-width: 4 222 // c-file-style: "bsd" 223 // c-basic-offset: 4 224 // fill-column: 120 225 // indent-tabs-mode: nil 226 // End: 227