/* thread-service.c * * Copyright (c) 2023 Apple Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Manage Thread service objects */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "srp.h" #include "dns-msg.h" #include "srp-crypto.h" #include "ioloop.h" #include "srp-mdns-proxy.h" #include "dnssd-proxy.h" #include "srp-gw.h" #include "srp-proxy.h" #include "config-parse.h" #include "cti-services.h" #include "thread-device.h" #include "state-machine.h" #include "thread-service.h" const char * thread_service_publication_state_name_get(thread_service_publication_state_t publication_state) { switch (publication_state) { default: return ""; case add_complete: return "add_complete"; case delete_complete: return "delete_complete"; case add_failed: return "add_failed"; case delete_failed: return "delete_failed"; case add_pending: return "add_pending"; case delete_pending: return "delete_pending"; case want_add: return "want_add"; case want_delete: return "want_delete"; } } static void thread_service_finalize(thread_service_t *service) { free(service); } RELEASE_RETAIN_FUNCS(thread_service); void thread_service_list_release(thread_service_t **list_pointer) { while (*list_pointer != NULL) { thread_service_t *service = *list_pointer; *list_pointer = service->next; RELEASE_HERE(service, thread_service); } } thread_service_t * thread_service_unicast_create_(uint16_t rloc16, uint8_t *address, uint8_t *port, uint8_t service_id, const char *file, int line) { thread_service_t *service; service = calloc(1, sizeof(*service)); if (service != NULL) { in6prefix_copy_from_data(&service->u.unicast.address, address, sizeof(service->u.unicast.address)); memcpy(&service->u.unicast.port, port, 2); service->rloc16 = rloc16; service->service_type = unicast_service; service->service_id = service_id; RETAIN(service, thread_service); } return service; } thread_service_t * thread_service_anycast_create_(uint16_t rloc16, uint8_t sequence_number, uint8_t service_id, const char *file, int line) { thread_service_t *service; service = calloc(1, sizeof(*service)); if (service != NULL) { service->rloc16 = rloc16; service->u.anycast.sequence_number = sequence_number; service->service_type = anycast_service; service->service_id = service_id; RETAIN(service, thread_service); } return service; } thread_service_t * thread_service_pref_id_create_(uint16_t rloc16, uint8_t *partition_id, uint8_t *prefix, uint8_t service_id, const char *file, int line) { thread_service_t *service; service = calloc(1, sizeof(*service)); if (service != NULL) { service->rloc16 = rloc16; memcpy(&service->u.pref_id.partition_id, partition_id, 4); memcpy(&service->u.pref_id.prefix, prefix, 5); service->service_type = pref_id; service->service_id = service_id; RETAIN(service, thread_service); } return service; } void thread_service_note(const char *owner_id, thread_service_t *tservice, const char *event_description) { switch(tservice->service_type) { default: INFO("invalid service type %d on service %p", tservice->service_type, tservice); break; case unicast_service: { struct thread_unicast_service *service = &tservice->u.unicast; uint16_t port; port = (uint16_t)(service->port[0] << 8) | service->port[1]; SEGMENTED_IPv6_ADDR_GEN_SRP(&service->address, service_add_buf); INFO(PUB_S_SRP " SRP service " PRI_SEGMENTED_IPv6_ADDR_SRP "%%%d, rloc16 %x " PUB_S_SRP, owner_id, SEGMENTED_IPv6_ADDR_PARAM_SRP(&service->address, service_add_buf), port, tservice->rloc16, event_description); } break; case anycast_service: { struct thread_anycast_service *service = &tservice->u.anycast; INFO(PUB_S_SRP " SRP service on RLOC16 %x with sequence number %02x " PUB_S_SRP, owner_id, tservice->rloc16, service->sequence_number, event_description); } break; case pref_id: { struct thread_pref_id *pref_id = &tservice->u.pref_id; struct in6_addr addr; addr.s6_addr[0] = 0xfd; memcpy(&addr.s6_addr[1], pref_id->prefix, 5); memset(&addr.s6_addr[6], 0, 10); SEGMENTED_IPv6_ADDR_GEN_SRP(addr.s6_addr, addr_buf); INFO(PUB_S_SRP " pref:id " PRI_SEGMENTED_IPv6_ADDR_SRP ":%02x%02x%02x%02x rloc %x " PUB_S_SRP, owner_id, SEGMENTED_IPv6_ADDR_PARAM_SRP(addr.s6_addr, addr_buf), pref_id->partition_id[0], pref_id->partition_id[1], pref_id->partition_id[2], pref_id->partition_id[3], tservice->rloc16, event_description); } break; } } bool thread_service_equal(thread_service_t *a, thread_service_t *b) { if (a == NULL || b == NULL) { return false; } if (a->service_type != b->service_type) { return false; } switch(a->service_type) { default: return false; case unicast_service: { return (!in6addr_compare(&a->u.unicast.address, &b->u.unicast.address) && !memcmp(a->u.unicast.port, b->u.unicast.port, 2)); } break; case anycast_service: { return a->u.anycast.sequence_number == b->u.anycast.sequence_number; } break; case pref_id: { return false; } break; } return false; } // Local Variables: // mode: C // tab-width: 4 // c-file-style: "bsd" // c-basic-offset: 4 // fill-column: 120 // indent-tabs-mode: nil // End: