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);
}
Example #2
0
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);
}