PRIVATE_EXTERN ipconfig_status_t manual_thread(ServiceRef service_p, IFEventID_t evid, void * event_data) { interface_t * if_p = service_interface(service_p); Service_manual_t * manual; ipconfig_status_t status = ipconfig_status_success_e; manual = (Service_manual_t *)ServiceGetPrivate(service_p); switch (evid) { case IFEventID_start_e: { ipconfig_method_data_t * method_data; method_data = (ipconfig_method_data_t *)event_data; if (manual) { my_log(LOG_DEBUG, "MANUAL %s: re-entering start state", if_name(if_p)); return (ipconfig_status_internal_error_e); } manual = malloc(sizeof(*manual)); if (manual == NULL) { my_log(LOG_ERR, "MANUAL %s: malloc failed", if_name(if_p)); status = ipconfig_status_allocation_failed_e; break; } ServiceSetPrivate(service_p, manual); bzero(manual, sizeof(*manual)); manual->ignore_link_status = method_data->manual.ignore_link_status; service_set_requested_ip_addr(service_p, method_data->manual.addr); service_set_requested_ip_mask(service_p, method_data->manual.mask); if (if_flags(if_p) & IFF_LOOPBACK) { /* set the new address */ (void)service_set_address(service_p, service_requested_ip_addr(service_p), service_requested_ip_mask(service_p), G_ip_zeroes); ServicePublishSuccessIPv4(service_p, NULL); break; } if (method_data->manual.router.s_addr != 0 && (method_data->manual.router.s_addr != method_data->manual.addr.s_addr)) { service_router_set_iaddr(service_p, method_data->manual.router); service_router_set_iaddr_valid(service_p); } manual->timer = timer_callout_init(); if (manual->timer == NULL) { my_log(LOG_ERR, "MANUAL %s: timer_callout_init failed", if_name(if_p)); status = ipconfig_status_allocation_failed_e; goto stop; } manual->arp = arp_client_init(G_arp_session, if_p); if (manual->arp == NULL) { my_log(LOG_NOTICE, "MANUAL %s: arp_client_init failed", if_name(if_p)); } my_log(LOG_DEBUG, "MANUAL %s: starting", if_name(if_p)); manual_start(service_p, IFEventID_start_e, NULL); break; } stop: case IFEventID_stop_e: { my_log(LOG_DEBUG, "MANUAL %s: stop", if_name(if_p)); if (manual == NULL) { break; } /* remove IP address */ service_remove_address(service_p); /* clean-up resources */ if (manual->arp) { arp_client_free(&manual->arp); } if (manual->timer) { timer_callout_free(&manual->timer); } if (manual) { free(manual); } ServiceSetPrivate(service_p, NULL); break; } case IFEventID_change_e: { change_event_data_t * change_event; ipconfig_method_data_t * method_data; if (manual == NULL) { my_log(LOG_DEBUG, "MANUAL %s: private data is NULL", if_name(if_p)); status = ipconfig_status_internal_error_e; break; } change_event = ((change_event_data_t *)event_data); method_data = change_event->method_data; change_event->needs_stop = FALSE; if (method_data->manual.addr.s_addr != service_requested_ip_addr(service_p).s_addr || (service_router_is_iaddr_valid(service_p) && (method_data->manual.router.s_addr != service_router_iaddr(service_p).s_addr)) || (method_data->manual.ignore_link_status != manual->ignore_link_status)) { change_event->needs_stop = TRUE; } else if (method_data->manual.mask.s_addr != service_requested_ip_mask(service_p).s_addr) { service_set_requested_ip_mask(service_p, method_data->manual.mask); (void)service_set_address(service_p, method_data->manual.addr, method_data->manual.mask, G_ip_zeroes); /* publish new mask */ ServicePublishSuccessIPv4(service_p, NULL); } break; } case IFEventID_arp_collision_e: { arp_collision_data_t * arpc; char msg[128]; arpc = (arp_collision_data_t *)event_data; if (manual == NULL) { return (ipconfig_status_internal_error_e); } if (arpc->ip_addr.s_addr != service_requested_ip_addr(service_p).s_addr) { break; } snprintf(msg, sizeof(msg), IP_FORMAT " in use by " EA_FORMAT, IP_LIST(&arpc->ip_addr), EA_LIST(arpc->hwaddr)); if (manual->user_warned == FALSE) { manual->user_warned = TRUE; ServiceReportIPv4AddressConflict(service_p, arpc->ip_addr); } my_log(LOG_ERR, "MANUAL %s: %s", if_name(if_p), msg); break; } case IFEventID_link_status_changed_e: { link_status_t link_status; if (manual == NULL) { return (ipconfig_status_internal_error_e); } if (manual->ignore_link_status) { break; } manual->user_warned = FALSE; link_status = service_link_status(service_p); if (link_status.valid == TRUE) { if (link_status.active == TRUE) { manual_start(service_p, IFEventID_start_e, NULL); } else { manual_cancel_pending_events(service_p); } } break; } case IFEventID_link_timer_expired_e: if (manual->ignore_link_status) { break; } manual_inactive(service_p); break; default: break; } /* switch */ return (status); }
ipconfig_status_t linklocal_thread(ServiceRef service_p, IFEventID_t event_id, void * event_data) { interface_t * if_p = service_interface(service_p); Service_linklocal_t * linklocal; ipconfig_status_t status = ipconfig_status_success_e; linklocal = (Service_linklocal_t *)ServiceGetPrivate(service_p); switch (event_id) { case IFEventID_start_e: { ipconfig_method_data_t * method_data; if (if_flags(if_p) & IFF_LOOPBACK) { status = ipconfig_status_invalid_operation_e; break; } if (linklocal != NULL) { my_log(LOG_ERR, "LINKLOCAL %s: re-entering start state", if_name(if_p)); status = ipconfig_status_internal_error_e; break; } my_log(LOG_DEBUG, "LINKLOCAL %s: start", if_name(if_p)); linklocal = malloc(sizeof(*linklocal)); if (linklocal == NULL) { my_log(LOG_ERR, "LINKLOCAL %s: malloc failed", if_name(if_p)); status = ipconfig_status_allocation_failed_e; break; } bzero(linklocal, sizeof(*linklocal)); ServiceSetPrivate(service_p, linklocal); linklocal->timer = timer_callout_init(); if (linklocal->timer == NULL) { my_log(LOG_ERR, "LINKLOCAL %s: timer_callout_init failed", if_name(if_p)); status = ipconfig_status_allocation_failed_e; goto stop; } linklocal->arp = arp_client_init(G_arp_session, if_p); if (linklocal->arp == NULL) { my_log(LOG_ERR, "LINKLOCAL %s: arp_client_init failed", if_name(if_p)); status = ipconfig_status_allocation_failed_e; goto stop; } /* ARP probes count as collisions for link-local address allocation */ arp_client_set_probes_are_collisions(linklocal->arp, TRUE); linklocal->allocate = TRUE; method_data = (ipconfig_method_data_t *)event_data; if (method_data != NULL && method_data->linklocal.allocate == FALSE) { /* don't allocate an IP address, just set the subnet */ linklocal->allocate = FALSE; linklocal_detect_proxy_arp(service_p, IFEventID_start_e, NULL); break; } linklocal->our_ip = S_find_linklocal_address(service_p); linklocal_allocate(service_p, IFEventID_start_e, NULL); break; } case IFEventID_stop_e: { stop: my_log(LOG_DEBUG, "LINKLOCAL %s: stop", if_name(if_p)); if (linklocal == NULL) { my_log(LOG_DEBUG, "LINKLOCAL %s: already stopped", if_name(if_p)); status = ipconfig_status_internal_error_e; /* shouldn't happen */ break; } /* remove IP address */ arp_linklocal_disable(if_name(if_p)); service_remove_address(service_p); /* clean-up the published state */ service_publish_failure(service_p, ipconfig_status_success_e); /* clean-up resources */ if (linklocal->timer) { timer_callout_free(&linklocal->timer); } if (linklocal->arp) { arp_client_free(&linklocal->arp); } if (linklocal) { free(linklocal); } ServiceSetPrivate(service_p, NULL); break; } case IFEventID_change_e: { boolean_t allocate = TRUE; change_event_data_t * change_event; ipconfig_method_data_t * method_data; change_event = (change_event_data_t *)event_data; method_data = change_event->method_data; if (method_data != NULL && method_data->linklocal.allocate == FALSE) { /* don't allocate an IP address, just set the subnet */ allocate = FALSE; } if (linklocal->allocate != allocate) { linklocal->allocate = allocate; if (allocate) { linklocal->our_ip = S_find_linklocal_address(service_p); linklocal_allocate(service_p, IFEventID_start_e, NULL); } else { linklocal_failed(service_p, ipconfig_status_success_e); linklocal_detect_proxy_arp(service_p, IFEventID_start_e, NULL); } } break; } case IFEventID_arp_collision_e: { arp_collision_data_t * arpc; arpc = (arp_collision_data_t *)event_data; if (linklocal == NULL) { return (ipconfig_status_internal_error_e); } if (linklocal->allocate == FALSE) { break; } if (linklocal->enable_arp_collision_detection == FALSE || arpc->ip_addr.s_addr != linklocal->our_ip.s_addr) { break; } linklocal->our_ip = G_ip_zeroes; (void)service_remove_address(service_p); service_publish_failure(service_p, ipconfig_status_address_in_use_e); linklocal_allocate(service_p, IFEventID_start_e, NULL); break; } case IFEventID_link_status_changed_e: { link_status_t link_status; if (linklocal == NULL) { return (ipconfig_status_internal_error_e); } link_status = service_link_status(service_p); if (link_status.valid == TRUE) { linklocal_cancel_pending_events(service_p); if (link_status.active == TRUE) { linklocal_start(service_p); } else { linklocal->enable_arp_collision_detection = FALSE; } } break; } case IFEventID_link_timer_expired_e: linklocal_inactive(service_p); break; case IFEventID_renew_e: { break; } default: break; } /* switch (event_id) */ return (status); }
ipconfig_status_t failover_thread(ServiceRef service_p, IFEventID_t evid, void * event_data) { interface_t * if_p = service_interface(service_p); Service_failover_t *failover; ipconfig_status_t status = ipconfig_status_success_e; failover = (Service_failover_t *)ServiceGetPrivate(service_p); switch (evid) { case IFEventID_start_e: { ipconfig_method_data_t * method_data; method_data = (ipconfig_method_data_t *)event_data; if (failover != NULL) { my_log(LOG_DEBUG, "FAILOVER %s: re-entering start state", if_name(if_p)); return (ipconfig_status_internal_error_e); } if (if_flags(if_p) & IFF_LOOPBACK) { return (ipconfig_status_invalid_parameter_e); } failover = malloc(sizeof(*failover)); if (failover == NULL) { my_log(LOG_ERR, "FAILOVER %s: malloc failed", if_name(if_p)); status = ipconfig_status_allocation_failed_e; break; } ServiceSetPrivate(service_p, failover); bzero(failover, sizeof(*failover)); service_set_requested_ip_addr(service_p, method_data->manual.addr); service_set_requested_ip_mask(service_p, method_data->manual.mask); failover->timer = timer_callout_init(); if (failover->timer == NULL) { my_log(LOG_ERR, "FAILOVER %s: timer_callout_init failed", if_name(if_p)); status = ipconfig_status_allocation_failed_e; goto stop; } failover->arp = arp_client_init(G_arp_session, if_p); if (failover->arp == NULL) { my_log(LOG_NOTICE, "FAILOVER %s: arp_client_init failed", if_name(if_p)); goto stop; } failover->address_timeout_secs = method_data->manual.failover_timeout; my_log(LOG_DEBUG, "FAILOVER %s: starting", if_name(if_p)); failover_start(service_p, IFEventID_start_e, NULL); break; } stop: case IFEventID_stop_e: { my_log(LOG_DEBUG, "FAILOVER %s: stop", if_name(if_p)); if (failover == NULL) { break; } /* remove IP address */ service_remove_address(service_p); /* clean-up resources */ if (failover->arp) { arp_client_free(&failover->arp); } if (failover->timer) { timer_callout_free(&failover->timer); } if (failover) { free(failover); } ServiceSetPrivate(service_p, NULL); break; } case IFEventID_change_e: { change_event_data_t * change_event; ipconfig_method_data_t * method_data; if (failover == NULL) { my_log(LOG_DEBUG, "FAILOVER %s: private data is NULL", if_name(if_p)); status = ipconfig_status_internal_error_e; break; } change_event = ((change_event_data_t *)event_data); method_data = change_event->method_data; change_event->needs_stop = FALSE; if ((method_data->manual.addr.s_addr != service_requested_ip_addr(service_p).s_addr) || (method_data->manual.mask.s_addr != service_requested_ip_mask(service_p).s_addr)) { change_event->needs_stop = TRUE; } else { failover->address_timeout_secs = method_data->manual.failover_timeout; if (service_is_address_set(service_p) && failover->address_is_verified) { if (failover->address_timeout_secs != 0) { struct timeval tv; tv.tv_sec = failover->address_timeout_secs; tv.tv_usec = 0; timer_set_relative(failover->timer, tv, (timer_func_t *)failover_timed_out, service_p, IFEventID_start_e, NULL); } else { timer_cancel(failover->timer); } } else { failover_start(service_p, IFEventID_start_e, NULL); } } break; } case IFEventID_arp_collision_e: { arp_collision_data_t * arpc; char msg[128]; arpc = (arp_collision_data_t *)event_data; if (failover == NULL) { return (ipconfig_status_internal_error_e); } if (arpc->ip_addr.s_addr != service_requested_ip_addr(service_p).s_addr) { break; } snprintf(msg, sizeof(msg), IP_FORMAT " in use by " EA_FORMAT, IP_LIST(&arpc->ip_addr), EA_LIST(arpc->hwaddr)); my_log(LOG_NOTICE, "FAILOVER %s: %s", if_name(if_p), msg); service_remove_address(service_p); service_publish_failure(service_p, ipconfig_status_address_in_use_e); failover_start(service_p, IFEventID_start_e, NULL); break; } case IFEventID_link_status_changed_e: { link_status_t link_status; if (failover == NULL) { return (ipconfig_status_internal_error_e); } link_status = service_link_status(service_p); if (link_status.valid == TRUE) { if (link_status.active == TRUE) { failover_start(service_p, IFEventID_start_e, NULL); } else { failover->address_is_verified = FALSE; failover_cancel_pending_events(service_p); } } break; } case IFEventID_link_timer_expired_e: failover_inactive(service_p); break; default: break; } /* switch */ return (status); }