Esempio n. 1
0
static void
linklocal_allocate(ServiceRef service_p, IFEventID_t event_id,
                   void * event_data)
{
    interface_t *	  if_p = service_interface(service_p);
    Service_linklocal_t * linklocal;

    linklocal = (Service_linklocal_t *)ServiceGetPrivate(service_p);
    switch (event_id) {
    case IFEventID_start_e: {
        linklocal->enable_arp_collision_detection = FALSE;

        arp_linklocal_disable(if_name(if_p));

        /* clean-up anything that might have come before */
        linklocal_cancel_pending_events(service_p);

        linklocal->current = 1;
        if (linklocal->our_ip.s_addr) {
            /* try to keep the same address */
            linklocal->probe = linklocal->our_ip;
        }
        else {
            linklocal->probe.s_addr
                = htonl(LINKLOCAL_FIRST_USEABLE
                        + random_range(0, LINKLOCAL_RANGE));
        }
        my_log(LOG_DEBUG, "LINKLOCAL %s: probing " IP_FORMAT,
               if_name(if_p), IP_LIST(&linklocal->probe));
        arp_client_probe(linklocal->arp,
                         (arp_result_func_t *)linklocal_allocate, service_p,
                         (void *)IFEventID_arp_e, G_ip_zeroes,
                         linklocal->probe);
        /* wait for the results */
        return;
    }
    case IFEventID_arp_e: {
        arp_result_t *	result = (arp_result_t *)event_data;

        if (result->error) {
            my_log(LOG_DEBUG, "LINKLOCAL %s: ARP probe failed, %s",
                   if_name(if_p),
                   arp_client_errmsg(linklocal->arp));
            break;
        }
        if (result->in_use
                || service_is_using_ip(service_p, linklocal->probe)) {
            if (result->in_use) {
                my_log(LOG_DEBUG, "LINKLOCAL %s: IP address "
                       IP_FORMAT " is in use by " EA_FORMAT,
                       if_name(if_p),
                       IP_LIST(&linklocal->probe),
                       EA_LIST(result->addr.target_hardware));
            }
            else {
                my_log(LOG_DEBUG, "LINKLOCAL %s: IP address "
                       IP_FORMAT " is no longer unique",
                       if_name(if_p));
            }
            if (linklocal->our_ip.s_addr == linklocal->probe.s_addr) {
                linklocal->our_ip = G_ip_zeroes;
                (void)service_remove_address(service_p);
                service_publish_failure(service_p,
                                        ipconfig_status_address_in_use_e);
            }
        }
        else {
            link_status_t	   link_status = service_link_status(service_p);
            const struct in_addr linklocal_mask = { htonl(LINKLOCAL_MASK) };

            if (link_status.valid == TRUE
                    && link_status.active == FALSE) {
                linklocal_failed(service_p,
                                 ipconfig_status_media_inactive_e);
                break;
            }

            /* ad-hoc IP address is not in use, so use it */
            (void)service_set_address(service_p, linklocal->probe,
                                      linklocal_mask, G_ip_zeroes);
            linklocal_set_address(service_p, linklocal->probe);
            arp_linklocal_enable(if_name(if_p));
            linklocal_cancel_pending_events(service_p);
            linklocal->our_ip = linklocal->probe;
            ServicePublishSuccessIPv4(service_p, NULL);
            linklocal->enable_arp_collision_detection = TRUE;
            /* we're done */
            break; /* out of switch */
        }
        if (linklocal->current >= MAX_LINKLOCAL_INITIAL_TRIES) {
            struct timeval tv;
            /* initial tries threshold reached, try again after a timeout */
            tv.tv_sec = LINKLOCAL_RETRY_TIME_SECS;
            tv.tv_usec = 0;
            timer_set_relative(linklocal->timer, tv,
                               (timer_func_t *)linklocal_allocate,
                               service_p, (void *)IFEventID_timeout_e, NULL);
            /* don't fall through, wait for timer */
            break;
        }
        linklocal->current++;
    /* FALL THROUGH */
        case IFEventID_timeout_e:
            /* try the next address */
            linklocal->probe.s_addr
                = htonl(LINKLOCAL_FIRST_USEABLE
                        + random_range(0, LINKLOCAL_RANGE));
            arp_client_probe(linklocal->arp,
                             (arp_result_func_t *)linklocal_allocate, service_p,
                             (void *)IFEventID_arp_e, G_ip_zeroes,
                             linklocal->probe);
            my_log(LOG_DEBUG, "LINKLOCAL %s probing " IP_FORMAT,
                   if_name(if_p), IP_LIST(&linklocal->probe));
            /* wait for the results */
            break;
        }
    default:
        break;
    }

    return;
}
static void
manual_start(ServiceRef service_p, IFEventID_t evid, void * event_data)
{
    interface_t *	if_p = service_interface(service_p);
    Service_manual_t *	manual;

    manual = (Service_manual_t *)ServiceGetPrivate(service_p);
    switch (evid) {
      case IFEventID_start_e: {
	  if (manual->arp == NULL) {
	      link_status_t	link_status = service_link_status(service_p);

	      /* if the link is up, just assign the IP */
	      if (manual->ignore_link_status == FALSE
		  && link_status.valid == TRUE 
		  && link_status.active == FALSE) {
		  manual_inactive(service_p);
		  break;
	      }
	      (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;
	  }
	  manual_cancel_pending_events(service_p);
	  arp_client_probe(manual->arp,
			   (arp_result_func_t *)manual_start, service_p,
			   (void *)IFEventID_arp_e, G_ip_zeroes,
			   service_requested_ip_addr(service_p));
	  break;
      }
      case IFEventID_arp_e: {
	  link_status_t		link_status;
	  arp_result_t *	result = (arp_result_t *)event_data;

	  if (result->error) {
	      my_log(LOG_ERR, "MANUAL %s: arp probe failed, %s", 
		     if_name(if_p), arp_client_errmsg(manual->arp));
	      break;
	  }
	  else {
	      if (result->in_use) {
		  char			msg[128];
		  struct in_addr	requested_ip;
		  struct timeval	tv;

		  requested_ip = service_requested_ip_addr(service_p);
		  snprintf(msg, sizeof(msg), 
			   IP_FORMAT " in use by " EA_FORMAT,
			   IP_LIST(&requested_ip),
			   EA_LIST(result->addr.target_hardware));
		  if (manual->user_warned == FALSE) {
		      manual->user_warned = TRUE;
		      ServiceReportIPv4AddressConflict(service_p,
						       requested_ip);
		  }
		  my_log(LOG_ERR, "MANUAL %s: %s", 
			 if_name(if_p), msg);
		  service_remove_address(service_p);
		  service_publish_failure(service_p, 
					  ipconfig_status_address_in_use_e);
		  if (G_manual_conflict_retry_interval_secs > 0) {
		      /* try again in a bit */
		      tv.tv_sec = G_manual_conflict_retry_interval_secs;
		      tv.tv_usec = 0;
		      timer_set_relative(manual->timer, tv, 
					 (timer_func_t *)manual_start,
					 service_p, IFEventID_start_e, NULL);
		  }
		  break;
	      }
	  }
	  link_status = service_link_status(service_p);
	  if (manual->ignore_link_status == FALSE
	      && link_status.valid == TRUE 
	      && link_status.active == FALSE) {
	      manual_inactive(service_p);
	      break;
	  }

	  /* 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);
	  ServiceRemoveAddressConflict(service_p);
	  if (service_router_is_iaddr_valid(service_p)
	      && service_resolve_router(service_p, manual->arp,
					manual_resolve_router_callback,
					service_requested_ip_addr(service_p))) {
	      /* router ARP resolution started */
	      manual->resolve_router_timed_out = FALSE;
	  }
	  else {
	      ServicePublishSuccessIPv4(service_p, NULL);
	  }
	  break;
      }
      default: {
	  break;
      }
    }
    return;
}
Esempio n. 3
0
static void
linklocal_detect_proxy_arp(ServiceRef service_p, IFEventID_t event_id,
                           void * event_data)
{
    interface_t *	  if_p = service_interface(service_p);
    Service_linklocal_t * linklocal;

    linklocal = (Service_linklocal_t *)ServiceGetPrivate(service_p);
    switch (event_id) {
    case IFEventID_start_e: {
        struct in_addr	iaddr;
        struct in_addr	llbroadcast;

        arp_linklocal_disable(if_name(if_p));
        llbroadcast.s_addr = htonl(LINKLOCAL_RANGE_END);
        /* clean-up anything that might have come before */
        linklocal_cancel_pending_events(service_p);
        if (parent_service_ip_address(service_p, &iaddr) == FALSE) {
            my_log(LOG_NOTICE, "LINKLOCAL %s: parent has no IP",
                   if_name(if_p));
            break;
        }
        my_log(LOG_DEBUG,
               "LINKLOCAL %s: ARP Request: Source " IP_FORMAT
               " Target 169.254.255.255", if_name(if_p), IP_LIST(&iaddr));
        arp_client_probe(linklocal->arp,
                         (arp_result_func_t *)linklocal_detect_proxy_arp,
                         service_p, (void *)IFEventID_arp_e, iaddr,
                         llbroadcast);
        /* wait for the results */
        break;
    }
    case IFEventID_arp_e: {
        link_status_t		link_status;
        arp_result_t *	result = (arp_result_t *)event_data;

        if (result->error) {
            my_log(LOG_DEBUG, "LINKLOCAL %s: ARP probe failed, %s",
                   if_name(if_p),
                   arp_client_errmsg(linklocal->arp));
            break;
        }
        linklocal_set_needs_attention();
        if (result->in_use) {
            my_log(LOG_DEBUG,
                   "LINKLOCAL %s: ARP response received for 169.254.255.255"
                   " from " EA_FORMAT,
                   if_name(if_p),
                   EA_LIST(result->addr.target_hardware));
            service_publish_failure(service_p,
                                    ipconfig_status_address_in_use_e);
            break;
        }
        link_status = service_link_status(service_p);
        if (link_status.valid == TRUE
                && link_status.active == FALSE) {
            linklocal_failed(service_p,
                             ipconfig_status_media_inactive_e);
            break;
        }
        arp_linklocal_enable(if_name(if_p));
        service_publish_failure(service_p,
                                ipconfig_status_success_e);
        break;
    }
    default: {
        break;
    }
    }
    return;
}
static void
failover_start(ServiceRef service_p, IFEventID_t evid, void * event_data)
{
    Service_failover_t * failover;
    interface_t *	if_p = service_interface(service_p);
    struct timeval	tv;

    failover = (Service_failover_t *)ServiceGetPrivate(service_p);
    switch (evid) {
      case IFEventID_start_e: {
	  failover->address_is_verified = FALSE;
	  failover_cancel_pending_events(service_p);
	  tv.tv_sec = random_range(0, 4);
	  tv.tv_usec = random_range(0, USECS_PER_SEC - 1);
	  timer_set_relative(failover->timer, tv, 
			     (timer_func_t *)failover_start,
			     service_p, (void *)IFEventID_timeout_e, NULL);
	  break;
      }
      case IFEventID_timeout_e: {
	  arp_client_probe(failover->arp, 
			   (arp_result_func_t *)failover_start, service_p,
			   (void *)IFEventID_arp_e, G_ip_zeroes,
			   service_requested_ip_addr(service_p));
	  break;
      }
      case IFEventID_arp_e: {
	  link_status_t		link_status;
	  arp_result_t *	result = (arp_result_t *)event_data;

	  if (result->error) {
	      my_log(LOG_ERR, "FAILOVER %s: arp probe failed, %s", 
		     if_name(if_p), arp_client_errmsg(failover->arp));
	      break;
	  }
	  else {
	      if (result->in_use) {
		  char			msg[128];
		  struct in_addr	requested_ip;

		  requested_ip = service_requested_ip_addr(service_p);
		  snprintf(msg, sizeof(msg), 
			   IP_FORMAT " in use by " EA_FORMAT,
			   IP_LIST(&requested_ip),
			   EA_LIST(result->addr.target_hardware));
		  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);
		  tv.tv_sec = 10;
		  tv.tv_usec = 0;
		  timer_set_relative(failover->timer, tv, 
				     (timer_func_t *)failover_start,
				     service_p, IFEventID_start_e, NULL);
		  break;
	      }
	  }
	  link_status = service_link_status(service_p);
	  if (link_status.valid == TRUE 
	      && link_status.active == FALSE) {
	      failover_inactive(service_p);
	      break;
	  }

	  /* 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);
	  failover->address_is_verified = TRUE;
	  if (failover->address_timeout_secs != 0) {
	      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);
	  }
	  break;
      }
      default: {
	  break;
      }
    }
    return;
}