/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include "configthreads_common.h" #include "globals.h" #include "interfaces.h" #include "ip6config_utils.h" static boolean_t if_gifmedia(int sockfd, char * name, boolean_t * status) { struct ifmediareq ifmr; boolean_t valid = FALSE; *status = FALSE; (void) memset(&ifmr, 0, sizeof(ifmr)); (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); if (ioctl(sockfd, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 && ifmr.ifm_count > 0 && ifmr.ifm_status & IFM_AVALID) { valid = TRUE; if (ifmr.ifm_status & IFM_ACTIVE) *status = TRUE; } return (valid); } static boolean_t get_media_status(char * name, boolean_t * media_status) { boolean_t media_valid = FALSE; int sockfd; if ((sockfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { my_log(LOG_INFO, "get_media_status (%s): socket failed, %s", name, strerror(errno)); return (FALSE); } media_valid = if_gifmedia(sockfd, name, media_status); close(sockfd); return (media_valid); } __private_extern__ Service_t * IFState_service_with_ID(IFState_t * ifstate, CFStringRef serviceID) { int count; int j; count = dynarray_count(&ifstate->services); for (j = 0; j < count; j++) { Service_t * service_p = dynarray_element(&ifstate->services, j); if (CFEqual(serviceID, service_p->serviceID)) { return (service_p); } } return (NULL); } __private_extern__ Service_t * IFState_service_with_ip(IFState_t * ifstate, struct in6_addr * iaddr) { int count; int j; count = dynarray_count(&ifstate->services); for (j = 0; j < count; j++) { Service_t * service_p = dynarray_element(&ifstate->services, j); if (IN6_ARE_ADDR_EQUAL(&service_p->info.addr, iaddr)) { return (service_p); } } return (NULL); } __private_extern__ void IFState_services_free(IFState_t * ifstate) { dynarray_free(&ifstate->services); if (ifstate->llocal_service) { Service_free(ifstate->llocal_service); ifstate->llocal_service = NULL; } dynarray_init(&ifstate->services, Service_free, NULL); return; } __private_extern__ void IFState_service_free(IFState_t * ifstate, CFStringRef serviceID) { int count; int j; count = dynarray_count(&ifstate->services); for (j = 0; j < count; j++) { Service_t * service_p = dynarray_element(&ifstate->services, j); if (CFEqual(serviceID, service_p->serviceID)) { dynarray_free_element(&ifstate->services, j); return; } } return; } __private_extern__ ip6config_status_t IFState_service_add(IFState_t * ifstate, CFStringRef serviceID, ip6config_method_t method, void * method_data) { Service_t * service_p = NULL; ip6config_status_t status = ip6config_status_success_e; /* create linklocal service when first starting up */ if (ifstate->llocal_service == NULL && method != ip6config_method_6to4_e) { ifstate->llocal_service = Service_init(ifstate, NULL, ip6config_method_linklocal_e, NULL, &status); if (ifstate->llocal_service == NULL) { my_log(LOG_DEBUG, "status from %s was %s", ip6config_method_string(ip6config_method_linklocal_e), ip6config_status_string(status)); return (status); } } /* try to configure the service */ service_p = Service_init(ifstate, serviceID, method, method_data, &status); if (service_p == NULL) { my_log(LOG_DEBUG, "status from %s was %s", ip6config_method_string(method), ip6config_status_string(status)); } else { dynarray_add(&ifstate->services, service_p); } return (status); } __private_extern__ void IFState_update_media_status(IFState_t * ifstate) { char * ifname = if_name(ifstate->if_p); link_status_t link = {FALSE, FALSE}; link.valid = get_media_status(ifname, &link.active); if (link.valid == FALSE) { my_log(LOG_DEBUG, "IFState_update_media_status: %s link is unknown", ifname); } else { my_log(LOG_DEBUG, "%s link is %s", ifname, link.active ? "up" : "down"); } ifstate->link = link; return; } static IFState_t * IFState_init(interface_t * if_p) { IFState_t * ifstate; ifstate = malloc(sizeof(*ifstate)); if (ifstate == NULL) { my_log(LOG_ERR, "IFState_init: malloc ifstate failed"); return (NULL); } bzero(ifstate, sizeof(*ifstate)); ifstate->if_p = if_dup(if_p); ifstate->ifname = (void *) CFStringCreateWithCString(NULL, if_name(if_p), kCFStringEncodingMacRoman); IFState_update_media_status(ifstate); dynarray_init(&ifstate->services, Service_free, NULL); return (ifstate); } __private_extern__ void IFState_free(void * arg) { IFState_t * ifstate = (IFState_t *)arg; SCLog(G_verbose, LOG_INFO, CFSTR("IFState_free(%s)"), if_name(ifstate->if_p)); IFState_services_free(ifstate); my_CFRelease(&ifstate->ifname); if_free(&ifstate->if_p); free(ifstate); return; } __private_extern__ IFState_t * IFStateList_ifstate_with_name(IFStateList_t * list, char * ifname, int * where) { int count; int i; count = dynarray_count(list); for (i = 0; i < count; i++) { IFState_t * element = dynarray_element(list, i); if (strcmp(if_name(element->if_p), ifname) == 0) { if (where != NULL) { *where = i; } return (element); } } return (NULL); } __private_extern__ IFState_t * IFStateList_ifstate_create(IFStateList_t * list, interface_t * if_p) { IFState_t * ifstate; ifstate = IFStateList_ifstate_with_name(list, if_name(if_p), NULL); if (ifstate == NULL) { ifstate = IFState_init(if_p); if (ifstate) { dynarray_add(list, ifstate); } } return (ifstate); } __private_extern__ void IFStateList_ifstate_free(IFStateList_t * list, char * ifname) { IFState_t * ifstate; int where = -1; ifstate = IFStateList_ifstate_with_name(list, ifname, &where); if (ifstate == NULL) { return; } dynarray_free_element(list, where); return; } __private_extern__ IFState_t * IFStateList_service_with_ID(IFStateList_t * list, CFStringRef serviceID, Service_t * * ret_service) { int count; int i; count = dynarray_count(list); for (i = 0; i < count; i++) { IFState_t * ifstate = dynarray_element(list, i); Service_t * service_p; service_p = IFState_service_with_ID(ifstate, serviceID); if (service_p) { if (ret_service) { *ret_service = service_p; } return (ifstate); } } if (ret_service) { *ret_service = NULL; } return (NULL); } __private_extern__ IFState_t * IFStateList_service_with_ip(IFStateList_t * list, struct in6_addr * iaddr, Service_t * * ret_service) { int count; int i; count = dynarray_count(list); for (i = 0; i < count; i++) { IFState_t * ifstate = dynarray_element(list, i); Service_t * service_p; service_p = IFState_service_with_ip(ifstate, iaddr); if (service_p) { if (ret_service) { *ret_service = service_p; } return (ifstate); } } if (ret_service) { *ret_service = NULL; } return (NULL); }