1/* 2 * Copyright (c) 1999-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * dhcp.c 25 * - DHCP configuration threads 26 * - contains dhcp_thread() and inform_thread() 27 */ 28/* 29 * Modification History 30 * 31 * May 16, 2000 Dieter Siegmund (dieter@apple.com) 32 * - reworked to fit within the new event-driven framework 33 * 34 * October 4, 2000 Dieter Siegmund (dieter@apple.com) 35 * - added code to unpublish interface state if the link goes 36 * down and stays down for more than 4 seconds 37 * - modified INFORM to process link change events as well 38 * 39 * February 1, 2002 Dieter Siegmund (dieter@apple.com) 40 * - changes for NetBoot 41 */ 42 43#include <stdlib.h> 44#include <unistd.h> 45#include <string.h> 46#include <stdio.h> 47#include <sys/types.h> 48#include <sys/wait.h> 49#include <sys/errno.h> 50#include <sys/socket.h> 51#include <sys/ioctl.h> 52#include <sys/sockio.h> 53#include <ctype.h> 54#include <net/if.h> 55#include <net/ethernet.h> 56#include <netinet/in.h> 57#include <netinet/udp.h> 58#include <netinet/in_systm.h> 59#include <netinet/ip.h> 60#include <netinet/bootp.h> 61#include <arpa/inet.h> 62#include <syslog.h> 63#include <TargetConditionals.h> 64 65#include "rfc_options.h" 66#include "dhcp_options.h" 67#include "dhcp.h" 68#include "interfaces.h" 69#include "util.h" 70#include <net/if_types.h> 71#include "host_identifier.h" 72#include "dhcplib.h" 73 74#include "ipconfigd_threads.h" 75#include "DHCPLease.h" 76#include "symbol_scope.h" 77#include "cfutil.h" 78#include "dprintf.h" 79 80#define SUGGESTED_LEASE_LENGTH (60 * 60 * 24 * 30 * 3) /* 3 months */ 81 82typedef struct { 83 boolean_t valid; 84 absolute_time_t expiration; 85 dhcp_lease_time_t length; 86 absolute_time_t start; 87 absolute_time_t t1; 88 absolute_time_t t2; 89 boolean_t needs_write; 90} lease_info_t; 91 92typedef struct { 93 arp_client_t * arp; 94 bootp_client_t * client; 95 void * client_id; 96 int client_id_len; 97 struct in_addr conflicting_address; 98 boolean_t disable_arp_collision_detection; 99 boolean_t gathering; 100 boolean_t got_nak; 101 lease_info_t lease; 102 DHCPLeaseList lease_list; 103 absolute_time_t ip_assigned_time; 104 absolute_time_t ip_conflict_time; 105 int ip_conflict_count; 106 boolean_t must_broadcast; 107 struct dhcp * request; 108 int request_size; 109 absolute_time_t renew_rebind_time; 110 boolean_t resolve_router_timed_out; 111 struct saved_pkt saved; 112 dhcp_cstate_t state; 113 absolute_time_t start_secs; 114 timer_callout_t * timer; 115 int try; 116 uint32_t txbuf[DHCP_PACKET_MIN/sizeof(uint32_t)]; 117 u_int32_t xid; 118 boolean_t user_warned; 119 int wait_secs; 120} Service_dhcp_t; 121 122typedef struct { 123 arp_client_t * arp; 124 bootp_client_t * client; 125 boolean_t gathering; 126 struct in_addr our_mask; 127 struct dhcp * request; 128 int request_size; 129 boolean_t resolve_router_timed_out; 130 struct saved_pkt saved; 131 absolute_time_t start_secs; 132 timer_callout_t * timer; 133 int try; 134 uint32_t txbuf[DHCP_PACKET_MIN/sizeof(uint32_t)]; 135 u_int32_t xid; 136 boolean_t user_warned; 137 int wait_secs; 138} Service_inform_t; 139 140static void 141dhcp_init(ServiceRef service_p, IFEventID_t event_id, void * event_data); 142 143static void 144dhcp_init_reboot(ServiceRef service_p, IFEventID_t event_id, 145 void * event_data); 146 147static void 148dhcp_arp_router(ServiceRef service_p, IFEventID_t event_id, 149 void * event_data); 150 151static void 152dhcp_select(ServiceRef service_p, IFEventID_t event_id, void * event_data); 153 154static void 155dhcp_bound(ServiceRef service_p, IFEventID_t event_id, void * event_data); 156 157static void 158dhcp_renew_rebind(ServiceRef service_p, IFEventID_t event_id, 159 void * event_data); 160 161static void 162dhcp_unbound(ServiceRef service_p, IFEventID_t event_id, void * event_data); 163 164static void 165dhcp_decline(ServiceRef service_p, IFEventID_t event_id, void * event_data); 166 167static void 168dhcp_release(ServiceRef service_p); 169 170static void 171dhcp_no_server(ServiceRef service_p, IFEventID_t event_id, void * event_data); 172 173static boolean_t 174dhcp_check_lease(ServiceRef service_p, absolute_time_t current_time); 175 176static void 177dhcp_check_router(ServiceRef service_p, IFEventID_t event_id, void * event_data); 178 179static boolean_t 180get_server_identifier(dhcpol_t * options, struct in_addr * server_ip) 181{ 182 struct in_addr * ipaddr_p; 183 184 ipaddr_p = (struct in_addr *) 185 dhcpol_find_with_length(options, dhcptag_server_identifier_e, 186 sizeof(*ipaddr_p)); 187 if (ipaddr_p != NULL) { 188 *server_ip = *ipaddr_p; 189 } 190 return (ipaddr_p != NULL); 191} 192 193#define DHCP_ADDRESS_RATING_POOR 0 194#define DHCP_ADDRESS_RATING_FAIR 100 195#define DHCP_ADDRESS_RATING_GOOD 1000 196 197static 198int 199get_rating_for_ip_address(struct in_addr * iaddr) 200{ 201 if (ip_is_private(*iaddr)) { 202 return (DHCP_ADDRESS_RATING_FAIR); 203 } 204 205 if (ip_is_linklocal(*iaddr)) { 206 return (DHCP_ADDRESS_RATING_POOR); 207 } 208 209 return (DHCP_ADDRESS_RATING_GOOD); 210} 211 212static const uint8_t dhcp_static_default_params[] = { 213 dhcptag_subnet_mask_e, 214 dhcptag_router_e, 215 dhcptag_domain_name_server_e, 216 dhcptag_domain_name_e, 217 dhcptag_domain_search_e, 218 dhcptag_proxy_auto_discovery_url_e, 219#if ! TARGET_OS_EMBEDDED 220 dhcptag_ldap_url_e, 221 dhcptag_nb_over_tcpip_name_server_e, 222 dhcptag_nb_over_tcpip_node_type_e, 223#endif /* ! TARGET_OS_EMBEDDED */ 224}; 225#define N_DHCP_STATIC_DEFAULT_PARAMS (sizeof(dhcp_static_default_params) / sizeof(dhcp_static_default_params[0])) 226 227static uint8_t * dhcp_default_params = (uint8_t *)dhcp_static_default_params; 228static int n_dhcp_default_params = N_DHCP_STATIC_DEFAULT_PARAMS; 229 230static uint8_t * dhcp_params = (uint8_t *)dhcp_static_default_params; 231static int n_dhcp_params = N_DHCP_STATIC_DEFAULT_PARAMS; 232 233void 234dhcp_set_default_parameters(uint8_t * params, int n_params) 235{ 236 if (params && n_params) { 237 dhcp_default_params = params; 238 n_dhcp_default_params = n_params; 239 } 240 else { 241 dhcp_default_params = (uint8_t *)dhcp_static_default_params; 242 n_dhcp_default_params = N_DHCP_STATIC_DEFAULT_PARAMS; 243 } 244 dhcp_params = dhcp_default_params; 245 n_dhcp_params = n_dhcp_default_params; 246 return; 247} 248 249static uint8_t * 250S_merge_parameters(uint8_t * params, int n_params, int * n_ret) 251{ 252 int i; 253 uint8_t * ret = dhcp_default_params; 254 uint8_t * new = NULL; 255 int new_end = 0; 256 257 *n_ret = n_dhcp_default_params; 258 if (params == NULL || n_params == 0) { 259 goto done; 260 } 261 /* allocate the worst case size ie. no duplicates */ 262 new = (uint8_t *)malloc(n_dhcp_default_params + n_params); 263 if (new == NULL) { 264 goto done; 265 } 266 bcopy(dhcp_default_params, new, n_dhcp_default_params); 267 for (i = 0, new_end = n_dhcp_default_params; i < n_params; i++) { 268 boolean_t already_there = FALSE; 269 int j; 270 271 for (j = 0; j < new_end; j++) { 272 if (new[j] == params[i]) { 273 /* already in requested parameters list, ignore it */ 274 already_there = TRUE; 275 break; 276 } 277 } 278 if (already_there == FALSE) { 279 new[new_end++] = params[i]; 280 } 281 } 282 if (new_end > n_dhcp_default_params) { 283 ret = new; 284 *n_ret = new_end; 285 } 286 else { 287 free(new); 288 new = NULL; 289 } 290 done: 291 return (ret); 292} 293 294static void 295S_print_char_array(CFMutableStringRef str, uint8_t * params, int n_params) 296{ 297 int i; 298 299 for (i = 0; i < n_params; i++) { 300 if (i == 0) 301 STRING_APPEND(str, "%d", params[i]); 302 else 303 STRING_APPEND(str, ", %d", params[i]); 304 } 305 return; 306} 307 308void 309dhcp_set_additional_parameters(uint8_t * params, int n_params) 310{ 311 if (dhcp_params && dhcp_params != dhcp_default_params) { 312 free(dhcp_params); 313 } 314 dhcp_params = S_merge_parameters(params, n_params, &n_dhcp_params); 315 if (params) { 316 free(params); 317 } 318 if (G_IPConfiguration_verbose) { 319 CFMutableStringRef str; 320 321 str = CFStringCreateMutable(NULL, 0); 322 S_print_char_array(str, dhcp_params, n_dhcp_params); 323 my_log(LOG_DEBUG, "DHCP requested parameters = { %@ }", str); 324 CFRelease(str); 325 } 326 return; 327} 328 329bool 330dhcp_parameter_is_ok(uint8_t param) 331{ 332 int i; 333 334 switch (param) { 335 case dhcptag_lease_time_e: 336 case dhcptag_dhcp_message_type_e: 337 case dhcptag_server_identifier_e: 338 case dhcptag_message_e: 339 case dhcptag_renewal_t1_time_value_e: 340 case dhcptag_rebinding_t2_time_value_e: 341 case dhcptag_vendor_class_identifier_e: 342 case dhcptag_client_identifier_e: 343 return (TRUE); 344 default: 345 break; 346 } 347 for (i = 0; i < n_dhcp_params; i++) { 348 if (dhcp_params[i] == param) { 349 return (TRUE); 350 } 351 } 352 return (FALSE); 353} 354 355 356static void 357add_computer_name(dhcpoa_t * options_p) 358{ 359 /* add the computer name as the host_name option */ 360 char * name = computer_name(); 361 362 if (name) { 363 if (dhcpoa_add(options_p, dhcptag_host_name_e, strlen(name), name) 364 != dhcpoa_success_e) { 365 my_log(LOG_NOTICE, "make_dhcp_request: couldn't add host_name, %s", 366 dhcpoa_err(options_p)); 367 } 368 } 369 return; 370} 371 372static struct dhcp * 373make_dhcp_request(struct dhcp * request, int pkt_size, 374 dhcp_msgtype_t msg, 375 const uint8_t * hwaddr, uint8_t hwtype, uint8_t hwlen, 376 const void * cid, int cid_len, boolean_t must_broadcast, 377 dhcpoa_t * options_p) 378{ 379 char * buf = NULL; 380 uint8_t cid_type = 0; 381 382 /* if no client id was specified, use the hardware address */ 383 if (cid == NULL || cid_len == 0) { 384 cid = hwaddr; 385 cid_len = hwlen; 386 cid_type = hwtype; 387 } 388 389 bzero(request, pkt_size); 390 request->dp_htype = hwtype; 391 request->dp_op = BOOTREQUEST; 392 393 switch (hwtype) { 394 default: 395 case ARPHRD_ETHER: 396 request->dp_hlen = hwlen; 397 bcopy(hwaddr, request->dp_chaddr, hwlen); 398 break; 399 case ARPHRD_IEEE1394: 400 request->dp_hlen = 0; /* RFC 2855 */ 401 if (cid == hwaddr) { 402 /* if client id is the hardware address, set the right type */ 403 cid_type = ARPHRD_IEEE1394_EUI64; 404 } 405 break; 406 } 407 if (must_broadcast || G_must_broadcast) { 408 request->dp_flags = htons(DHCP_FLAGS_BROADCAST); 409 } 410 bcopy(G_rfc_magic, request->dp_options, sizeof(G_rfc_magic)); 411 dhcpoa_init(options_p, request->dp_options + sizeof(G_rfc_magic), 412 pkt_size - sizeof(struct dhcp) - sizeof(G_rfc_magic)); 413 414 /* make the request a dhcp message */ 415 if (dhcpoa_add_dhcpmsg(options_p, msg) != dhcpoa_success_e) { 416 my_log(LOG_ERR, 417 "make_dhcp_request: couldn't add dhcp message tag %d, %s", msg, 418 dhcpoa_err(options_p)); 419 goto err; 420 } 421 422 if (msg != dhcp_msgtype_decline_e && msg != dhcp_msgtype_release_e) { 423 u_int16_t max_message_size = htons(1500); /* max receive size */ 424 425 /* add the list of required parameters */ 426 if (dhcpoa_add(options_p, dhcptag_parameter_request_list_e, 427 n_dhcp_params, dhcp_params) 428 != dhcpoa_success_e) { 429 my_log(LOG_ERR, "make_dhcp_request: " 430 "couldn't add parameter request list, %s", 431 dhcpoa_err(options_p)); 432 goto err; 433 } 434 /* add the max message size */ 435 if (dhcpoa_add(options_p, dhcptag_max_dhcp_message_size_e, 436 sizeof(max_message_size), &max_message_size) 437 != dhcpoa_success_e) { 438 my_log(LOG_ERR, "make_dhcp_request: " 439 "couldn't add max message size, %s", 440 dhcpoa_err(options_p)); 441 goto err; 442 } 443 } 444 445 /* add the client identifier to the request packet */ 446 buf = malloc(cid_len + 1); 447 if (buf == NULL) { 448 my_log(LOG_ERR, "make_dhcp_request: malloc failed, %s (%d)", 449 strerror(errno), errno); 450 goto err; 451 } 452 *buf = cid_type; 453 bcopy(cid, buf + 1, cid_len); 454 if (dhcpoa_add(options_p, dhcptag_client_identifier_e, cid_len + 1, buf) 455 != dhcpoa_success_e) { 456 free(buf); 457 my_log(LOG_ERR, "make_dhcp_request: " 458 "couldn't add client identifier, %s", 459 dhcpoa_err(options_p)); 460 goto err; 461 } 462 free(buf); 463 return (request); 464 err: 465 return (NULL); 466} 467 468/* 469 * Function: verify_packet 470 * Purpose: 471 */ 472static boolean_t 473verify_packet(bootp_receive_data_t * pkt, u_int32_t xid, interface_t * if_p, 474 dhcp_msgtype_t * msgtype_p, struct in_addr * server_ip, 475 boolean_t * is_dhcp) 476{ 477 if (dhcp_packet_match((struct bootp *)pkt->data, xid, 478 (uint8_t) if_link_arptype(if_p), 479 if_link_address(if_p), 480 if_link_length(if_p))) { 481 /* 482 * A BOOTP packet should be one that doesn't contain 483 * a dhcp message. Unfortunately, some stupid BOOTP servers 484 * are unaware of DHCP and RFC-standard options, and simply 485 * echo back what we sent in the options area. This is the 486 * reason for checking for DISCOVER, REQUEST and INFORM: they are 487 * invalid responses in the DHCP protocol, so we assume that 488 * the server is blindly echoing what we send. 489 */ 490 if (is_dhcp_packet(&pkt->options, msgtype_p) == FALSE 491 || *msgtype_p == dhcp_msgtype_discover_e 492 || *msgtype_p == dhcp_msgtype_request_e 493 || *msgtype_p == dhcp_msgtype_inform_e) { 494 /* BOOTP packet */ 495 if (G_dhcp_accepts_bootp == FALSE) { 496 return (FALSE); 497 } 498 *msgtype_p = dhcp_msgtype_none_e; 499 *is_dhcp = FALSE; 500 *server_ip = pkt->data->dp_siaddr; 501 return (TRUE); 502 } 503 *is_dhcp = TRUE; 504 server_ip->s_addr = 0; 505 (void)get_server_identifier(&pkt->options, server_ip); 506 /* matching DHCP packet */ 507 return (TRUE); 508 } 509 return (FALSE); 510} 511 512/** 513 ** 514 ** INFORM Functions 515 ** 516 */ 517static void 518inform_set_dhcp_info(Service_inform_t * inform, dhcp_info_t * dhcp_info_p) 519{ 520 if (inform->saved.pkt_size != 0) { 521 dhcp_info_p->pkt = (uint8_t *)inform->saved.pkt; 522 dhcp_info_p->pkt_size = inform->saved.pkt_size; 523 dhcp_info_p->options = &inform->saved.options; 524 } 525 else { 526 dhcp_info_p->pkt = NULL; 527 dhcp_info_p->pkt_size = 0; 528 dhcp_info_p->options = NULL; 529 } 530 dhcp_info_p->lease_start = 0; 531 dhcp_info_p->lease_expiration = 0; 532 return; 533} 534 535static void 536inform_publish_success(ServiceRef service_p) 537{ 538 dhcp_info_t dhcp_info; 539 Service_inform_t * inform; 540 541 inform = (Service_inform_t *)ServiceGetPrivate(service_p); 542 inform_set_dhcp_info(inform, &dhcp_info); 543 ServicePublishSuccessIPv4(service_p, &dhcp_info); 544 return; 545} 546 547 548static void 549inform_cancel_pending_events(ServiceRef service_p) 550{ 551 Service_inform_t * inform; 552 553 inform = (Service_inform_t *)ServiceGetPrivate(service_p); 554 if (inform == NULL) 555 return; 556 if (inform->timer) { 557 timer_cancel(inform->timer); 558 } 559 if (inform->client) { 560 bootp_client_disable_receive(inform->client); 561 } 562 if (inform->arp) { 563 arp_client_cancel(inform->arp); 564 } 565 return; 566} 567 568static void 569inform_inactive(ServiceRef service_p) 570{ 571 Service_inform_t * inform; 572 573 inform = (Service_inform_t *)ServiceGetPrivate(service_p); 574 inform_cancel_pending_events(service_p); 575 service_remove_address(service_p); 576 dhcpol_free(&inform->saved.options); 577 service_publish_failure(service_p, ipconfig_status_media_inactive_e); 578 return; 579} 580 581static void 582inform_failed(ServiceRef service_p, ipconfig_status_t status) 583{ 584 inform_cancel_pending_events(service_p); 585 service_publish_failure(service_p, status); 586 return; 587} 588 589static void 590inform_resolve_router_callback(ServiceRef service_p, 591 router_arp_status_t status); 592 593static void 594inform_resolve_router_retry(void * arg0, void * arg1, void * arg2) 595{ 596 Service_inform_t * inform; 597 ServiceRef service_p = (ServiceRef)arg0; 598 599 inform = (Service_inform_t *)ServiceGetPrivate(service_p); 600 service_resolve_router(service_p, inform->arp, 601 inform_resolve_router_callback, 602 inform->saved.our_ip); 603 return; 604} 605 606static void 607inform_resolve_router_callback(ServiceRef service_p, 608 router_arp_status_t status) 609{ 610 Service_inform_t * inform; 611 struct timeval tv; 612 613 inform = (Service_inform_t *)ServiceGetPrivate(service_p); 614 switch (status) { 615 case router_arp_status_no_response_e: 616 /* try again in 60 seconds */ 617 tv.tv_sec = 60; 618 tv.tv_usec = 0; 619 timer_set_relative(inform->timer, tv, 620 (timer_func_t *)inform_resolve_router_retry, 621 service_p, NULL, NULL); 622 if (inform->resolve_router_timed_out) { 623 break; 624 } 625 /* publish what we have so far */ 626 inform->resolve_router_timed_out = TRUE; 627 inform_publish_success(service_p); 628 break; 629 case router_arp_status_success_e: 630 inform->resolve_router_timed_out = FALSE; 631 inform_publish_success(service_p); 632 break; 633 default: 634 case router_arp_status_failed_e: 635 break; 636 } 637} 638 639static void 640inform_success(ServiceRef service_p) 641{ 642 Service_inform_t * inform; 643 void * option; 644 645 inform = (Service_inform_t *)ServiceGetPrivate(service_p); 646 option = dhcpol_find_with_length(&inform->saved.options, 647 dhcptag_subnet_mask_e, 648 sizeof(struct in_addr)); 649 if (service_requested_ip_mask(service_p).s_addr == 0 650 && option != NULL) { 651 inform->our_mask = *((struct in_addr *)option); 652 653 /* reset the interface address with the new mask */ 654 (void)service_set_address(service_p, 655 service_requested_ip_addr(service_p), 656 inform->our_mask, 657 G_ip_zeroes); 658 } 659 inform_cancel_pending_events(service_p); 660 inform->resolve_router_timed_out = FALSE; 661 if (service_update_router_address(service_p, &inform->saved.options, 662 inform->saved.our_ip) 663 && service_resolve_router(service_p, inform->arp, 664 inform_resolve_router_callback, 665 service_requested_ip_addr(service_p))) { 666 /* router resolution started */ 667 } 668 else { 669 inform_publish_success(service_p); 670 } 671 return; 672} 673 674static void 675inform_request(ServiceRef service_p, IFEventID_t event_id, void * event_data) 676{ 677 absolute_time_t current_time = timer_current_secs(); 678 interface_t * if_p = service_interface(service_p); 679 Service_inform_t * inform; 680 ipconfig_status_t status = ipconfig_status_success_e; 681 682 inform = (Service_inform_t *)ServiceGetPrivate(service_p); 683 switch (event_id) { 684 case IFEventID_start_e: { 685 dhcpoa_t options; 686 687 inform->start_secs = current_time; 688 689 /* clean-up anything that might have come before */ 690 inform_cancel_pending_events(service_p); 691 /* ALIGN: txbuf is aligned to sizeof(uint32_t) bytes */ 692 inform->request = make_dhcp_request((struct dhcp *)(void *)inform->txbuf, 693 sizeof(inform->txbuf), 694 dhcp_msgtype_inform_e, 695 if_link_address(if_p), 696 if_link_arptype(if_p), 697 if_link_length(if_p), 698 NULL, 0, 699 FALSE, 700 &options); 701 if (inform->request == NULL) { 702 my_log(LOG_ERR, "INFORM %s: make_dhcp_request failed", 703 if_name(if_p)); 704 status = ipconfig_status_allocation_failed_e; 705 goto error; 706 } 707 inform->request->dp_ciaddr = service_requested_ip_addr(service_p); 708 add_computer_name(&options); 709 if (dhcpoa_add(&options, dhcptag_end_e, 0, 0) 710 != dhcpoa_success_e) { 711 my_log(LOG_ERR, "INFORM %s: failed to terminate options", 712 if_name(if_p)); 713 status = ipconfig_status_allocation_failed_e; 714 goto error; 715 } 716 inform->request_size = sizeof(*inform->request) + sizeof(G_rfc_magic) 717 + dhcpoa_used(&options); 718 if (inform->request_size < sizeof(struct bootp)) { 719 /* pad out to BOOTP-sized packet */ 720 inform->request_size = sizeof(struct bootp); 721 } 722 inform->try = 0; 723 inform->gathering = FALSE; 724 inform->wait_secs = G_initial_wait_secs; 725 bootp_client_enable_receive(inform->client, 726 (bootp_receive_func_t *)inform_request, 727 service_p, (void *)IFEventID_data_e); 728 inform->saved.rating = 0; 729 inform->xid++; 730 /* FALL THROUGH */ 731 } 732 case IFEventID_timeout_e: { 733 struct timeval tv; 734 if (inform->gathering == TRUE) { 735 /* done gathering */ 736 inform_success(service_p); 737 return; 738 } 739 inform->try++; 740 if (inform->try > 1) { 741 link_status_t link_status = service_link_status(service_p); 742 743 if (link_status.valid 744 && link_status.active == FALSE) { 745 inform_inactive(service_p); 746 break; /* out of switch */ 747 } 748 } 749 if (inform->try > (G_max_retries + 1)) { 750 inform_success(service_p); 751 break; 752 } 753 inform->request->dp_xid = htonl(inform->xid); 754 inform->request->dp_secs 755 = htons((uint16_t)(current_time - inform->start_secs)); 756 757 /* send the packet */ 758 if (bootp_client_transmit(inform->client, 759 G_ip_broadcast, G_ip_zeroes, 760 G_server_port, G_client_port, 761 inform->request, 762 inform->request_size) < 0) { 763 my_log(LOG_ERR, 764 "INFORM %s: transmit failed", if_name(if_p)); 765 } 766 /* wait for responses */ 767 tv.tv_sec = inform->wait_secs; 768 tv.tv_usec = random_range(0, USECS_PER_SEC - 1); 769 my_log(LOG_DEBUG, "INFORM %s: waiting at %d for %d.%06d", 770 if_name(if_p), 771 current_time - inform->start_secs, 772 tv.tv_sec, tv.tv_usec); 773 timer_set_relative(inform->timer, tv, 774 (timer_func_t *)inform_request, 775 service_p, (void *)IFEventID_timeout_e, NULL); 776 /* next time wait twice as long */ 777 inform->wait_secs *= 2; 778 if (inform->wait_secs > G_max_wait_secs) { 779 inform->wait_secs = G_max_wait_secs; 780 } 781 break; 782 } 783 case IFEventID_data_e: { 784 boolean_t is_dhcp = TRUE; 785 bootp_receive_data_t *pkt = (bootp_receive_data_t *)event_data; 786 dhcp_msgtype_t reply_msgtype = dhcp_msgtype_none_e; 787 struct in_addr server_ip; 788 789 if (verify_packet(pkt, inform->xid, if_p, &reply_msgtype, 790 &server_ip, &is_dhcp) == FALSE) { 791 /* reject the packet */ 792 break; /* out of switch */ 793 } 794 if (is_dhcp == FALSE 795 || (reply_msgtype == dhcp_msgtype_ack_e)) { 796 int rating = 0; 797 798 rating = dhcpol_count_params(&pkt->options, 799 dhcp_params, n_dhcp_params); 800 /* 801 * The new packet is "better" than the saved 802 * packet if: 803 * - there was no saved packet, or 804 * - the new packet is a DHCP packet and the saved 805 * one is a BOOTP packet or a DHCP packet with 806 * a lower rating, or 807 * - the new packet and the saved packet are both 808 * BOOTP but the new one has a higher rating 809 * All this to allow BOOTP/DHCP interoperability 810 * ie. we accept a BOOTP response if it's 811 * the only one we've got. We expect/favour a DHCP 812 * response. 813 */ 814 if (inform->saved.pkt_size == 0 815 || (is_dhcp == TRUE && (inform->saved.is_dhcp == FALSE 816 || rating > inform->saved.rating)) 817 || (is_dhcp == FALSE && inform->saved.is_dhcp == FALSE 818 && rating > inform->saved.rating)) { 819 dhcpol_free(&inform->saved.options); 820 bcopy(pkt->data, inform->saved.pkt, pkt->size); 821 inform->saved.pkt_size = pkt->size; 822 inform->saved.rating = rating; 823 /* ALIGN: saved.pkt is at least sizeof(uint32_t) aligned, 824 * cast ok. */ 825 (void)dhcpol_parse_packet(&inform->saved.options, 826 (void *)inform->saved.pkt, 827 inform->saved.pkt_size, NULL); 828 inform->saved.server_ip = server_ip; 829 inform->saved.is_dhcp = is_dhcp; 830 if (is_dhcp && rating == n_dhcp_params) { 831 inform_success(service_p); 832 return; 833 } 834 if (inform->gathering == FALSE) { 835 struct timeval t = {0,0}; 836 t.tv_sec = G_gather_secs; 837 my_log(LOG_DEBUG, "INFORM %s: gathering began at %d", 838 if_name(if_p), 839 current_time - inform->start_secs); 840 inform->gathering = TRUE; 841 timer_set_relative(inform->timer, t, 842 (timer_func_t *)inform_request, 843 service_p, (void *)IFEventID_timeout_e, 844 NULL); 845 } 846 } 847 } 848 break; 849 } 850 default: 851 break; 852 } 853 return; 854 error: 855 inform_failed(service_p, status); 856 return; 857 858} 859 860static void 861inform_start(ServiceRef service_p, IFEventID_t event_id, void * event_data) 862{ 863 interface_t * if_p = service_interface(service_p); 864 Service_inform_t * inform; 865 866 inform = (Service_inform_t *)ServiceGetPrivate(service_p); 867 switch (event_id) { 868 case IFEventID_start_e: { 869 inform_cancel_pending_events(service_p); 870 871 arp_client_probe(inform->arp, 872 (arp_result_func_t *)inform_start, service_p, 873 (void *)IFEventID_arp_e, G_ip_zeroes, 874 service_requested_ip_addr(service_p)); 875 break; 876 } 877 case IFEventID_arp_e: { 878 link_status_t link_status; 879 arp_result_t * result = (arp_result_t *)event_data; 880 881 if (result->error) { 882 my_log(LOG_DEBUG, "INFORM %s: arp probe failed, %s", 883 if_name(if_p), 884 arp_client_errmsg(inform->arp)); 885 inform_failed(service_p, ipconfig_status_internal_error_e); 886 break; 887 } 888 else { 889 if (result->in_use) { 890 struct in_addr requested_ip; 891 char msg[128]; 892 struct timeval tv; 893 894 requested_ip = service_requested_ip_addr(service_p); 895 snprintf(msg, sizeof(msg), 896 IP_FORMAT " in use by " EA_FORMAT, 897 IP_LIST(&requested_ip), 898 EA_LIST(result->addr.target_hardware)); 899 if (inform->user_warned == FALSE) { 900 inform->user_warned = TRUE; 901 ServiceReportIPv4AddressConflict(service_p, 902 requested_ip); 903 } 904 my_log(LOG_ERR, "INFORM %s: %s", if_name(if_p), 905 msg); 906 (void)service_remove_address(service_p); 907 inform_failed(service_p, ipconfig_status_address_in_use_e); 908 /* try again in a bit */ 909 if (G_manual_conflict_retry_interval_secs > 0) { 910 tv.tv_sec = G_manual_conflict_retry_interval_secs; 911 tv.tv_usec = 0; 912 timer_set_relative(inform->timer, tv, 913 (timer_func_t *)inform_start, 914 service_p, IFEventID_start_e, NULL); 915 } 916 break; 917 } 918 } 919 link_status = service_link_status(service_p); 920 if (link_status.valid == TRUE 921 && link_status.active == FALSE) { 922 inform_inactive(service_p); 923 break; 924 } 925 926 /* set the primary address */ 927 (void)service_set_address(service_p, 928 service_requested_ip_addr(service_p), 929 inform->our_mask, 930 G_ip_zeroes); 931 ServiceRemoveAddressConflict(service_p); 932 inform_request(service_p, IFEventID_start_e, 0); 933 break; 934 } 935 default: { 936 break; 937 } 938 } 939 return; 940} 941 942PRIVATE_EXTERN ipconfig_status_t 943inform_thread(ServiceRef service_p, IFEventID_t event_id, void * event_data) 944{ 945 interface_t * if_p = service_interface(service_p); 946 Service_inform_t * inform; 947 ipconfig_status_t status = ipconfig_status_success_e; 948 949 inform = (Service_inform_t *)ServiceGetPrivate(service_p); 950 switch (event_id) { 951 case IFEventID_start_e: { 952 ipconfig_method_data_t * method_data; 953 954 method_data = (ipconfig_method_data_t *)event_data; 955 if (if_flags(if_p) & IFF_LOOPBACK) { 956 status = ipconfig_status_invalid_operation_e; 957 break; 958 } 959 if (inform != NULL) { 960 my_log(LOG_ERR, "INFORM %s: re-entering start state", 961 if_name(if_p)); 962 status = ipconfig_status_internal_error_e; 963 break; 964 } 965 inform = malloc(sizeof(*inform)); 966 if (inform == NULL) { 967 my_log(LOG_ERR, "INFORM %s: malloc failed", 968 if_name(if_p)); 969 status = ipconfig_status_allocation_failed_e; 970 break; 971 } 972 ServiceSetPrivate(service_p, inform); 973 bzero(inform, sizeof(*inform)); 974 dhcpol_init(&inform->saved.options); 975 service_set_requested_ip_addr(service_p, method_data->manual.addr); 976 service_set_requested_ip_mask(service_p, method_data->manual.mask); 977 inform->our_mask = service_requested_ip_mask(service_p); 978 inform->timer = timer_callout_init(); 979 if (inform->timer == NULL) { 980 my_log(LOG_ERR, "INFORM %s: timer_callout_init failed", 981 if_name(if_p)); 982 status = ipconfig_status_allocation_failed_e; 983 goto stop; 984 } 985 inform->client = bootp_client_init(G_bootp_session, if_p); 986 if (inform->client == NULL) { 987 my_log(LOG_ERR, "INFORM %s: bootp_client_init failed", 988 if_name(if_p)); 989 status = ipconfig_status_allocation_failed_e; 990 goto stop; 991 } 992 inform->arp = arp_client_init(G_arp_session, if_p); 993 if (inform->arp == NULL) { 994 my_log(LOG_ERR, "INFORM %s: arp_client_init failed", 995 if_name(if_p)); 996 status = ipconfig_status_allocation_failed_e; 997 goto stop; 998 } 999 my_log(LOG_DEBUG, "INFORM %s: start", if_name(if_p)); 1000 inform->xid = arc4random(); 1001 inform_start(service_p, IFEventID_start_e, NULL); 1002 break; 1003 } 1004 case IFEventID_stop_e: { 1005 stop: 1006 my_log(LOG_DEBUG, "INFORM %s: stop", if_name(if_p)); 1007 if (inform == NULL) { /* already stopped */ 1008 break; 1009 } 1010 /* remove IP address */ 1011 service_remove_address(service_p); 1012 1013 /* clean-up resources */ 1014 if (inform->timer) { 1015 timer_callout_free(&inform->timer); 1016 } 1017 if (inform->client) { 1018 bootp_client_free(&inform->client); 1019 } 1020 if (inform->arp) { 1021 arp_client_free(&inform->arp); 1022 } 1023 dhcpol_free(&inform->saved.options); 1024 if (inform) 1025 free(inform); 1026 ServiceSetPrivate(service_p, NULL); 1027 break; 1028 } 1029 case IFEventID_change_e: { 1030 change_event_data_t * change_event; 1031 ipconfig_method_data_t * method_data; 1032 1033 if (inform == NULL) { 1034 my_log(LOG_DEBUG, "INFORM %s: private data is NULL", 1035 if_name(if_p)); 1036 return (ipconfig_status_internal_error_e); 1037 } 1038 change_event = ((change_event_data_t *)event_data); 1039 method_data = change_event->method_data; 1040 change_event->needs_stop = FALSE; 1041 if (method_data->manual.addr.s_addr 1042 != service_requested_ip_addr(service_p).s_addr) { 1043 change_event->needs_stop = TRUE; 1044 } 1045 else if (method_data->manual.mask.s_addr != 0 1046 && (method_data->manual.mask.s_addr 1047 != service_requested_ip_mask(service_p).s_addr)) { 1048 service_set_requested_ip_mask(service_p, 1049 method_data->manual.mask); 1050 inform->our_mask = method_data->manual.mask; 1051 (void)service_set_address(service_p, 1052 method_data->manual.addr, 1053 inform->our_mask, G_ip_zeroes); 1054 } 1055 return (ipconfig_status_success_e); 1056 } 1057 case IFEventID_arp_collision_e: { 1058 arp_collision_data_t * arpc; 1059 char msg[128]; 1060 1061 arpc = (arp_collision_data_t *)event_data; 1062 if (inform == NULL) { 1063 return (ipconfig_status_internal_error_e); 1064 } 1065 if (arpc->ip_addr.s_addr 1066 != service_requested_ip_addr(service_p).s_addr) { 1067 break; 1068 } 1069 snprintf(msg, sizeof(msg), 1070 IP_FORMAT " in use by " EA_FORMAT, 1071 IP_LIST(&arpc->ip_addr), 1072 EA_LIST(arpc->hwaddr)); 1073 if (inform->user_warned == FALSE) { 1074 inform->user_warned = TRUE; 1075 ServiceReportIPv4AddressConflict(service_p, 1076 arpc->ip_addr); 1077 } 1078 my_log(LOG_ERR, "INFORM %s: %s", if_name(if_p), 1079 msg); 1080 break; 1081 } 1082 case IFEventID_renew_e: 1083 case IFEventID_link_status_changed_e: { 1084 link_status_t link_status; 1085 1086 if (inform == NULL) 1087 return (ipconfig_status_internal_error_e); 1088 1089 inform->user_warned = FALSE; 1090 link_status = service_link_status(service_p); 1091 if (link_status.valid == TRUE) { 1092 if (link_status.active == TRUE) { 1093 inform_start(service_p, IFEventID_start_e, 0); 1094 } 1095 else if (event_id == IFEventID_link_status_changed_e) { 1096 inform_cancel_pending_events(service_p); 1097 } 1098 } 1099 break; 1100 } 1101 case IFEventID_link_timer_expired_e: 1102 inform_inactive(service_p); 1103 break; 1104 case IFEventID_get_dhcp_info_e: { 1105 if (ServiceGetActiveIPAddress(service_p).s_addr == 0 1106 || inform->saved.pkt_size == 0) { 1107 break; 1108 } 1109 inform_set_dhcp_info(inform, (dhcp_info_t *)event_data); 1110 break; 1111 } 1112 default: 1113 break; 1114 } /* switch (event_id) */ 1115 return (status); 1116} 1117 1118/** 1119 ** 1120 ** DHCP Functions 1121 ** 1122 */ 1123 1124static void 1125dhcp_set_dhcp_info(Service_dhcp_t * dhcp, dhcp_info_t * dhcp_info_p) 1126{ 1127 dhcp_info_p->pkt = (uint8_t *)dhcp->saved.pkt; 1128 dhcp_info_p->pkt_size = dhcp->saved.pkt_size; 1129 dhcp_info_p->options = &dhcp->saved.options; 1130 dhcp_info_p->lease_start = dhcp->lease.start; 1131 dhcp_info_p->lease_expiration = dhcp->lease.expiration; 1132 return; 1133} 1134 1135static void 1136dhcp_publish_success(ServiceRef service_p) 1137{ 1138 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1139 dhcp_info_t dhcp_info; 1140 1141 dhcp_set_dhcp_info(dhcp, &dhcp_info); 1142 ServicePublishSuccessIPv4(service_p, &dhcp_info); 1143 return; 1144} 1145 1146static void 1147dhcp_cancel_pending_events(ServiceRef service_p) 1148{ 1149 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1150 1151 if (dhcp == NULL) 1152 return; 1153 timer_cancel(dhcp->timer); 1154 bootp_client_disable_receive(dhcp->client); 1155 arp_client_cancel(dhcp->arp); 1156 return; 1157} 1158 1159 1160static void 1161dhcp_failed(ServiceRef service_p, ipconfig_status_t status) 1162{ 1163 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1164 1165 dhcp_cancel_pending_events(service_p); 1166 1167 service_disable_autoaddr(service_p); 1168 dhcpol_free(&dhcp->saved.options); 1169 service_remove_address(service_p); 1170 service_publish_failure(service_p, status); 1171 dhcp->state = dhcp_cstate_none_e; 1172 return; 1173} 1174 1175static void 1176dhcp_inactive(ServiceRef service_p) 1177{ 1178 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1179 1180 dhcp_cancel_pending_events(service_p); 1181 /* 1182 * Set the status here so that the link-local service will disappear 1183 * when we call service_remove_address. 1184 */ 1185 ServiceSetStatus(service_p, ipconfig_status_media_inactive_e); 1186 service_remove_address(service_p); 1187 service_disable_autoaddr(service_p); 1188 service_publish_failure(service_p, ipconfig_status_media_inactive_e); 1189 dhcp->state = dhcp_cstate_none_e; 1190 return; 1191} 1192 1193static void 1194dhcp_set_lease_params(ServiceRef service_p, char * descr, boolean_t is_dhcp, 1195 absolute_time_t lease_start, 1196 dhcp_lease_time_t lease, dhcp_lease_time_t t1, 1197 dhcp_lease_time_t t2) 1198{ 1199 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1200 interface_t * if_p = service_interface(service_p); 1201 1202 dhcp->lease.start = lease_start; 1203 if (is_dhcp == FALSE) { 1204 dhcp->lease.length = DHCP_INFINITE_LEASE; 1205 } 1206 else { 1207 dhcp->lease.length = lease; 1208 } 1209 1210 if (dhcp->lease.length == DHCP_INFINITE_LEASE) { 1211 dhcp->lease.t1 = dhcp->lease.t2 = dhcp->lease.expiration = 0; 1212 } 1213 else { 1214 dhcp->lease.expiration = dhcp->lease.start + dhcp->lease.length; 1215 dhcp->lease.t1 = dhcp->lease.start + t1; 1216 dhcp->lease.t2 = dhcp->lease.start + t2; 1217 } 1218 my_log(LOG_DEBUG, 1219 "DHCP %s: %s lease" 1220 " start = 0x%x, t1 = 0x%x, t2 = 0x%x, expiration 0x%x", 1221 if_name(if_p), descr, dhcp->lease.start, 1222 dhcp->lease.t1, dhcp->lease.t2, dhcp->lease.expiration); 1223 return; 1224} 1225 1226/* 1227 * Function: dhcp_adjust_lease_info 1228 * Purpose: 1229 * Apply the delta to the lease information: start, t1, t2, and expiration. 1230 */ 1231static void 1232dhcp_adjust_lease_info(ServiceRef service_p, absolute_time_t delta) 1233{ 1234 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1235 interface_t * if_p = service_interface(service_p); 1236 lease_info_t * info_p = &dhcp->lease; 1237 1238 info_p->expiration += delta; 1239 info_p->start += delta; 1240 info_p->t1 += delta; 1241 info_p->t2 += delta; 1242 my_log(LOG_DEBUG, 1243 "DHCP %s: adjusted lease by %d seconds", if_name(if_p), delta); 1244 return; 1245} 1246 1247 1248static void 1249get_client_id(Service_dhcp_t * dhcp, interface_t * if_p, const void * * cid_p, 1250 uint8_t * cid_type_p, int * cid_length_p) 1251{ 1252 if (dhcp->client_id != NULL) { 1253 *cid_type_p = 0; 1254 *cid_p = dhcp->client_id; 1255 *cid_length_p = dhcp->client_id_len; 1256 } 1257 else { 1258 *cid_type_p = if_link_arptype(if_p); 1259 *cid_p = if_link_address(if_p); 1260 *cid_length_p = if_link_length(if_p); 1261 } 1262 return; 1263} 1264 1265static void 1266_dhcp_lease_save(ServiceRef service_p, absolute_time_t lease_start, 1267 const uint8_t * pkt, int pkt_size, boolean_t write_lease) 1268{ 1269 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1270 interface_t * if_p = service_interface(service_p); 1271 const void * cid; 1272 uint8_t cid_type; 1273 int cid_length; 1274 struct in_addr router_ip = { 0 }; 1275 const uint8_t * router_hwaddr = NULL; 1276 int router_hwaddr_length = 0; 1277 1278 if (service_router_is_iaddr_valid(service_p)) { 1279 router_ip = service_router_iaddr(service_p); 1280 if (service_router_is_hwaddr_valid(service_p)) { 1281 /* we have the router h/w address, save it too */ 1282 router_hwaddr = service_router_hwaddr(service_p); 1283 router_hwaddr_length = if_link_length(if_p); 1284 } 1285 } 1286 get_client_id(dhcp, if_p, &cid, &cid_type, &cid_length); 1287 DHCPLeaseListUpdateLease(&dhcp->lease_list, dhcp->saved.our_ip, 1288 router_ip, router_hwaddr, router_hwaddr_length, 1289 dhcp->lease.start, dhcp->lease.length, 1290 pkt, pkt_size, ServiceGetSSID(service_p)); 1291 if (write_lease) { 1292 DHCPLeaseListWrite(&dhcp->lease_list, 1293 if_name(if_p), cid_type, cid, cid_length); 1294 } 1295 return; 1296} 1297 1298static void 1299_dhcp_lease_clear(ServiceRef service_p, bool nak) 1300{ 1301 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1302 interface_t * if_p = service_interface(service_p); 1303 struct in_addr router_ip = { 0 }; 1304 const uint8_t * router_hwaddr = NULL; 1305 int router_hwaddr_length = 0; 1306 1307 if (service_router_is_iaddr_valid(service_p)) { 1308 router_ip = service_router_iaddr(service_p); 1309 if (service_router_is_hwaddr_valid(service_p)) { 1310 router_hwaddr = service_router_hwaddr(service_p); 1311 router_hwaddr_length = if_link_length(if_p); 1312 } 1313 } 1314 if (nak == FALSE 1315 || router_ip.s_addr == 0 1316 || router_hwaddr_length == 0) { 1317 const void * cid; 1318 uint8_t cid_type; 1319 int cid_length; 1320 1321 get_client_id(dhcp, if_p, &cid, &cid_type, &cid_length); 1322 DHCPLeaseListRemoveLease(&dhcp->lease_list, 1323 dhcp->saved.our_ip, router_ip, 1324 router_hwaddr, router_hwaddr_length); 1325 DHCPLeaseListWrite(&dhcp->lease_list, 1326 if_name(if_p), cid_type, cid, cid_length); 1327 } 1328 else { 1329 DHCPLeaseRef lease_p; 1330 int where; 1331 1332 where = DHCPLeaseListFindLease(&dhcp->lease_list, 1333 dhcp->saved.our_ip, 1334 router_ip, 1335 router_hwaddr, 1336 router_hwaddr_length); 1337 if (where != -1) { 1338 lease_p = DHCPLeaseListElement(&dhcp->lease_list, where); 1339 DHCPLeaseSetNAK(lease_p, TRUE); 1340 } 1341 } 1342 return; 1343} 1344 1345static boolean_t 1346switch_to_lease(ServiceRef service_p, DHCPLeaseRef lease_p) 1347{ 1348 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1349 interface_t * if_p = service_interface(service_p); 1350 dhcp_lease_time_t lease_time; 1351 dhcp_lease_time_t t1_time; 1352 dhcp_lease_time_t t2_time; 1353 1354 if (lease_p->our_ip.s_addr == dhcp->saved.our_ip.s_addr) { 1355 if (ip_is_private(lease_p->our_ip) == FALSE) { 1356 /* same lease */ 1357 if (G_IPConfiguration_verbose) { 1358 my_log(LOG_DEBUG, "DHCP %s: switch_to_lease returns FALSE, " 1359 "public IP is the same", if_name(if_p)); 1360 } 1361 return (FALSE); 1362 } 1363 if (service_router_is_iaddr_valid(service_p) 1364 && service_router_is_hwaddr_valid(service_p) 1365 && (lease_p->router_ip.s_addr 1366 == service_router_iaddr(service_p).s_addr) 1367 && (bcmp(lease_p->router_hwaddr, 1368 service_router_hwaddr(service_p), 1369 if_link_length(if_p)) == 0)) { 1370 if (G_IPConfiguration_verbose) { 1371 my_log(LOG_DEBUG, "DHCP %s: switch_to_lease returns FALSE, " 1372 "private IP has same router", if_name(if_p)); 1373 } 1374 return (FALSE); 1375 } 1376 } 1377 /* make sure we stop using the old IP address */ 1378 (void)service_remove_address(service_p); 1379 if (lease_p->pkt_length > sizeof(dhcp->saved.pkt)) { 1380 dhcp->saved.pkt_size = sizeof(dhcp->saved.pkt); 1381 } 1382 else { 1383 dhcp->saved.pkt_size = lease_p->pkt_length; 1384 } 1385 bcopy(lease_p->pkt, dhcp->saved.pkt, dhcp->saved.pkt_size); 1386 dhcpol_free(&dhcp->saved.options); 1387 /* ALIGN: saved.pkt is uint32_t aligned, cast ok */ 1388 (void)dhcpol_parse_packet(&dhcp->saved.options, 1389 (void *)dhcp->saved.pkt, 1390 dhcp->saved.pkt_size, NULL); 1391 dhcp_get_lease_from_options(&dhcp->saved.options, &lease_time, 1392 &t1_time, &t2_time); 1393 dhcp_set_lease_params(service_p, "RECOVERED", 1394 TRUE, lease_p->lease_start, lease_time, 1395 t1_time, t2_time); 1396 dhcp->lease.valid = TRUE; 1397 dhcp->saved.rating = 0; 1398 dhcp->saved.our_ip = lease_p->our_ip; 1399 get_server_identifier(&dhcp->saved.options, &dhcp->saved.server_ip); 1400 dhcp->saved.is_dhcp = TRUE; 1401 service_router_clear(service_p); 1402 if (lease_p->router_ip.s_addr != 0) { 1403 service_router_set_iaddr(service_p, lease_p->router_ip); 1404 service_router_set_iaddr_valid(service_p); 1405 if (lease_p->router_hwaddr_length > 0) { 1406 int len; 1407 1408 len = lease_p->router_hwaddr_length; 1409 if (len > service_router_hwaddr_size(service_p)) { 1410 len = service_router_hwaddr_size(service_p); 1411 } 1412 bcopy(lease_p->router_hwaddr, 1413 service_router_hwaddr(service_p), len); 1414 service_router_set_hwaddr_valid(service_p); 1415 } 1416 } 1417 if (G_IPConfiguration_verbose) { 1418 my_log(LOG_DEBUG, "DHCP %s: switched to lease for IP " IP_FORMAT, 1419 if_name(if_p), IP_LIST(&lease_p->our_ip)); 1420 } 1421 return (TRUE); 1422} 1423 1424static boolean_t 1425recover_lease(ServiceRef service_p, struct in_addr * our_ip) 1426{ 1427 const void * cid; 1428 uint8_t cid_type; 1429 int cid_length; 1430 int count; 1431 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1432 interface_t * if_p = service_interface(service_p); 1433 DHCPLeaseRef lease_p; 1434 1435 /* read the DHCP lease */ 1436 get_client_id(dhcp, if_p, &cid, &cid_type, &cid_length); 1437 DHCPLeaseListRead(&dhcp->lease_list, if_name(if_p), 1438 if_is_wireless(if_p), 1439 cid_type, cid, cid_length); 1440 count = DHCPLeaseListCount(&dhcp->lease_list); 1441 if (count == 0) { 1442 goto failed; 1443 } 1444 lease_p = DHCPLeaseListElement(&dhcp->lease_list, count - 1); 1445 (void)switch_to_lease(service_p, lease_p); 1446 *our_ip = lease_p->our_ip; 1447 if (G_IPConfiguration_verbose) { 1448 my_log(LOG_DEBUG, "DHCP %s: recovered lease for IP " IP_FORMAT, 1449 if_name(if_p), IP_LIST(our_ip)); 1450 } 1451 return (TRUE); 1452 1453 failed: 1454 return (FALSE); 1455} 1456 1457static boolean_t 1458dhcp_check_lease(ServiceRef service_p, absolute_time_t current_time) 1459{ 1460 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1461 1462 if (dhcp->lease.valid) { 1463 if (dhcp->lease.length != DHCP_INFINITE_LEASE 1464 && (current_time >= dhcp->lease.expiration)) { 1465 dhcp->lease.valid = FALSE; 1466 service_router_clear(service_p); 1467 (void)service_remove_address(service_p); 1468 service_publish_failure(service_p, 1469 ipconfig_status_media_inactive_e); 1470 } 1471 } 1472 return (dhcp->lease.valid); 1473} 1474 1475static void 1476dhcp_check_link(ServiceRef service_p, IFEventID_t event_id) 1477{ 1478 absolute_time_t current_time = timer_current_secs(); 1479 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1480 link_status_t link_status = service_link_status(service_p); 1481 1482 if (link_status.valid == FALSE 1483 || link_status.active == TRUE) { 1484 dhcp->conflicting_address.s_addr = 0; 1485 dhcp->user_warned = FALSE; 1486 if (dhcp_check_lease(service_p, current_time)) { 1487 /* try same address */ 1488 if (event_id == IFEventID_renew_e 1489 || dhcp->state != dhcp_cstate_init_reboot_e 1490 || dhcp->try != 1) { 1491 struct in_addr our_ip; 1492 1493 our_ip = dhcp->saved.our_ip; 1494 dhcp_init_reboot(service_p, IFEventID_start_e, 1495 &our_ip); 1496 } 1497 /* we're already in the init-reboot state */ 1498 return; 1499 } 1500 if (event_id == IFEventID_renew_e 1501 || dhcp->state != dhcp_cstate_init_e 1502 || dhcp->try != 1) { 1503 dhcp_init(service_p, IFEventID_start_e, NULL); 1504 return; 1505 } 1506 } 1507 else { 1508 /* ensure that we'll retry when the link goes back up */ 1509 dhcp->try = 0; 1510 dhcp->state = dhcp_cstate_none_e; 1511 dhcp_cancel_pending_events(service_p); 1512 } 1513 return; 1514} 1515 1516INLINE boolean_t 1517S_dhcp_cstate_is_bound_renew_or_rebind(dhcp_cstate_t state) 1518{ 1519 boolean_t ret; 1520 1521 switch (state) { 1522 case dhcp_cstate_bound_e: 1523 case dhcp_cstate_renew_e: 1524 case dhcp_cstate_rebind_e: 1525 ret = TRUE; 1526 break; 1527 default: 1528 ret = FALSE; 1529 break; 1530 } 1531 return (ret); 1532} 1533 1534PRIVATE_EXTERN ipconfig_status_t 1535dhcp_thread(ServiceRef service_p, IFEventID_t event_id, void * event_data) 1536{ 1537 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1538 interface_t * if_p = service_interface(service_p); 1539 ipconfig_status_t status = ipconfig_status_success_e; 1540 1541 switch (event_id) { 1542 case IFEventID_start_e: { 1543 ipconfig_method_data_t * method_data; 1544 struct in_addr our_ip = { 0 }; 1545 1546 if (if_flags(if_p) & IFF_LOOPBACK) { 1547 status = ipconfig_status_invalid_operation_e; 1548 break; 1549 } 1550 if (dhcp != NULL) { 1551 my_log(LOG_ERR, "DHCP %s: re-entering start state", 1552 if_name(if_p)); 1553 status = ipconfig_status_internal_error_e; 1554 break; 1555 } 1556 dhcp = malloc(sizeof(*dhcp)); 1557 if (dhcp == NULL) { 1558 my_log(LOG_ERR, "DHCP %s: malloc failed", 1559 if_name(if_p)); 1560 status = ipconfig_status_allocation_failed_e; 1561 break; 1562 } 1563 bzero(dhcp, sizeof(*dhcp)); 1564 dhcp->must_broadcast = (if_link_arptype(if_p) == ARPHRD_IEEE1394); 1565 dhcpol_init(&dhcp->saved.options); 1566 ServiceSetPrivate(service_p, dhcp); 1567 1568 dhcp->lease.valid = FALSE; 1569 service_router_clear(service_p); 1570 dhcp->state = dhcp_cstate_none_e; 1571 dhcp->timer = timer_callout_init(); 1572 if (dhcp->timer == NULL) { 1573 my_log(LOG_ERR, "DHCP %s: timer_callout_init failed", 1574 if_name(if_p)); 1575 status = ipconfig_status_allocation_failed_e; 1576 goto stop; 1577 } 1578 (void)service_enable_autoaddr(service_p); 1579 dhcp->client = bootp_client_init(G_bootp_session, if_p); 1580 if (dhcp->client == NULL) { 1581 my_log(LOG_ERR, "DHCP %s: bootp_client_init failed", 1582 if_name(if_p)); 1583 status = ipconfig_status_allocation_failed_e; 1584 goto stop; 1585 } 1586 dhcp->arp = arp_client_init(G_arp_session, if_p); 1587 if (dhcp->arp == NULL) { 1588 my_log(LOG_ERR, "DHCP %s: arp_client_init failed", 1589 if_name(if_p)); 1590 status = ipconfig_status_allocation_failed_e; 1591 goto stop; 1592 } 1593 method_data = (ipconfig_method_data_t *)event_data; 1594 if (method_data != NULL && method_data->dhcp.client_id_len > 0) { 1595 dhcp->client_id_len = method_data->dhcp.client_id_len; 1596 dhcp->client_id = malloc(dhcp->client_id_len); 1597 if (dhcp->client_id == NULL) { 1598 my_log(LOG_ERR, "DHCP %s: malloc client ID failed", 1599 if_name(if_p)); 1600 status = ipconfig_status_allocation_failed_e; 1601 goto stop; 1602 } 1603 bcopy(method_data->dhcp.client_id, 1604 dhcp->client_id, dhcp->client_id_len); 1605 } 1606 my_log(LOG_DEBUG, "DHCP %s: start", if_name(if_p)); 1607 dhcp->xid = arc4random(); 1608 DHCPLeaseListInit(&dhcp->lease_list); 1609 if (ServiceIsNetBoot(service_p) 1610 || recover_lease(service_p, &our_ip)) { 1611 dhcp_init_reboot(service_p, IFEventID_start_e, &our_ip); 1612 } 1613 else { 1614 dhcp_init(service_p, IFEventID_start_e, NULL); 1615 } 1616 break; 1617 } 1618 case IFEventID_stop_e: { 1619 stop: 1620 my_log(LOG_DEBUG, "DHCP %s: stop", if_name(if_p)); 1621 if (dhcp == NULL) { 1622 my_log(LOG_DEBUG, "DHCP %s: already stopped", 1623 if_name(if_p)); 1624 status = ipconfig_status_internal_error_e; /* shouldn't happen */ 1625 break; 1626 } 1627 if (event_id == IFEventID_stop_e) { 1628 (void)dhcp_release(service_p); 1629 } 1630 1631 /* remove IP address */ 1632 service_remove_address(service_p); 1633 1634 service_disable_autoaddr(service_p); 1635 1636 /* clean-up resources */ 1637 if (dhcp->timer) { 1638 timer_callout_free(&dhcp->timer); 1639 } 1640 if (dhcp->client) { 1641 bootp_client_free(&dhcp->client); 1642 } 1643 if (dhcp->arp) { 1644 arp_client_free(&dhcp->arp); 1645 } 1646 if (dhcp->client_id) { 1647 free(dhcp->client_id); 1648 dhcp->client_id = NULL; 1649 } 1650 DHCPLeaseListFree(&dhcp->lease_list); 1651 dhcpol_free(&dhcp->saved.options); 1652 if (dhcp) 1653 free(dhcp); 1654 ServiceSetPrivate(service_p, NULL); 1655 break; 1656 } 1657 case IFEventID_change_e: { 1658 change_event_data_t * change_event; 1659 ipconfig_method_data_t * method_data; 1660 1661 if (dhcp == NULL) { 1662 my_log(LOG_DEBUG, "DHCP %s: private data is NULL", 1663 if_name(if_p)); 1664 return (ipconfig_status_internal_error_e); 1665 } 1666 change_event = (change_event_data_t *)event_data; 1667 method_data = change_event->method_data; 1668 change_event->needs_stop = FALSE; 1669 if (method_data != NULL && method_data->dhcp.client_id_len > 0) { 1670 if (dhcp->client_id == NULL 1671 || dhcp->client_id_len != method_data->dhcp.client_id_len 1672 || bcmp(dhcp->client_id, method_data->dhcp.client_id, 1673 dhcp->client_id_len)) { 1674 change_event->needs_stop = TRUE; 1675 } 1676 } 1677 else { 1678 if (dhcp->client_id != NULL) { 1679 change_event->needs_stop = TRUE; 1680 } 1681 } 1682 return (ipconfig_status_success_e); 1683 } 1684 case IFEventID_arp_collision_e: { 1685 arp_collision_data_t * arpc; 1686 absolute_time_t current_time; 1687 struct timeval tv; 1688 1689 arpc = (arp_collision_data_t *)event_data; 1690 1691 if (dhcp == NULL) { 1692 return (ipconfig_status_internal_error_e); 1693 } 1694 if (dhcp->disable_arp_collision_detection 1695 || (ServiceGetActiveIPAddress(service_p).s_addr 1696 != dhcp->saved.our_ip.s_addr) 1697 || arpc->ip_addr.s_addr != dhcp->saved.our_ip.s_addr) { 1698 break; 1699 } 1700 1701 /* defend our address, don't just give it up */ 1702 current_time = timer_current_secs(); 1703 if ((current_time - dhcp->ip_assigned_time) > 1704 G_dhcp_defend_ip_address_interval_secs) { 1705 if (dhcp->ip_conflict_count > 0 1706 && ((current_time - dhcp->ip_conflict_time) 1707 > G_dhcp_defend_ip_address_interval_secs)) { 1708 /* 1709 * if it's been awhile since we last had to defend 1710 * our IP address, assume we defended it successfully 1711 * and start the conflict counter over again 1712 */ 1713 dhcp->ip_conflict_count = 0; 1714 } 1715 dhcp->ip_conflict_time = current_time; 1716 dhcp->ip_conflict_count++; 1717 if (dhcp->ip_conflict_count <= G_dhcp_defend_ip_address_count) { 1718 arp_client_defend(dhcp->arp, dhcp->saved.our_ip); 1719 my_log(LOG_ERR, "DHCP %s: defending IP " IP_FORMAT 1720 " against " EA_FORMAT " %d (of %d)", 1721 if_name(if_p), IP_LIST(&dhcp->saved.our_ip), 1722 EA_LIST(arpc->hwaddr), 1723 dhcp->ip_conflict_count, 1724 G_dhcp_defend_ip_address_count); 1725 break; 1726 } 1727 } 1728 my_log(LOG_ERR, "DHCP %s: " 1729 IP_FORMAT " in use by " EA_FORMAT ", DHCP Server " 1730 IP_FORMAT, 1731 if_name(if_p), 1732 IP_LIST(&dhcp->saved.our_ip), 1733 EA_LIST(arpc->hwaddr), 1734 IP_LIST(&dhcp->saved.server_ip)); 1735 ServiceReportIPv4AddressConflict(service_p, 1736 dhcp->saved.our_ip); 1737 _dhcp_lease_clear(service_p, FALSE); 1738 service_publish_failure(service_p, 1739 ipconfig_status_address_in_use_e); 1740 if (dhcp->saved.is_dhcp) { 1741 dhcp_decline(service_p, IFEventID_start_e, NULL); 1742 break; 1743 } 1744 dhcp_cancel_pending_events(service_p); 1745 (void)service_disable_autoaddr(service_p); 1746 dhcp->saved.our_ip.s_addr = 0; 1747 dhcp->lease.valid = FALSE; 1748 service_router_clear(service_p); 1749 tv.tv_sec = 10; /* retry in a bit */ 1750 tv.tv_usec = 0; 1751 timer_set_relative(dhcp->timer, tv, 1752 (timer_func_t *)dhcp_init, 1753 service_p, (void *)IFEventID_start_e, NULL); 1754 break; 1755 } 1756 case IFEventID_renew_e: 1757 case IFEventID_link_status_changed_e: { 1758 void * network_changed = event_data; 1759 1760 if (dhcp == NULL) { 1761 return (ipconfig_status_internal_error_e); 1762 } 1763 if (network_changed != NULL) { 1764 /* switched networks, remove IP address to avoid IP collisions */ 1765 (void)service_remove_address(service_p); 1766 service_publish_failure(service_p, 1767 ipconfig_status_network_changed_e); 1768 linklocal_service_change(service_p, LINKLOCAL_NO_ALLOCATE); 1769 } 1770 /* make sure to start DHCP again */ 1771 dhcp_check_link(service_p, event_id); 1772 break; 1773 } 1774 case IFEventID_link_timer_expired_e: 1775 dhcp_inactive(service_p); 1776 break; 1777 case IFEventID_power_off_e: 1778 case IFEventID_sleep_e: { 1779 if (dhcp == NULL) { 1780 return (ipconfig_status_internal_error_e); 1781 } 1782 if (dhcp->lease.valid && dhcp->saved.is_dhcp) { 1783 _dhcp_lease_save(service_p, dhcp->lease.start, 1784 (uint8_t *)dhcp->saved.pkt, dhcp->saved.pkt_size, 1785 TRUE); 1786 } 1787 break; 1788 } 1789 case IFEventID_wake_e: { 1790 link_status_t link_status; 1791 wake_data_t * wake_data = (wake_data_t *)event_data; 1792 1793 if (ServiceIsNetBoot(service_p)) { 1794 break; 1795 } 1796 /* 1797 * While asleep, we could have switched networks without knowing it. 1798 * Unless we know with some confidence that we're on the same network, 1799 * we need to remove the IP address from the interface. 1800 * 1801 * We remove the IP address if any of the following are true: 1802 * - we're not connected to a network (link status is inactive) 1803 * - we woke from hibernation 1804 * - we're on a different Wi-Fi network (the SSID changed) 1805 * - we're not on the same ethernet network 1806 */ 1807 link_status = service_link_status(service_p); 1808 if ((link_status.valid && link_status.active == FALSE) 1809 || (wake_data->flags & kWakeFlagsFromHibernation) != 0 1810 || (if_is_wireless(if_p) 1811 && (wake_data->flags & kWakeFlagsSSIDChanged) != 0) 1812 || (if_is_wireless(if_p) == FALSE 1813 && link_status.wake_on_same_network == FALSE)) { 1814 /* make sure there's no IP address assigned when we wake */ 1815 service_remove_address(service_p); 1816 service_publish_failure(service_p, 1817 ipconfig_status_media_inactive_e); 1818 if ((wake_data->flags & kWakeFlagsFromHibernation) != 0) { 1819 /* 1820 * wake from hibernation is the same as a reboot case, so 1821 * simulate that by removing all but the last lease, and 1822 * mark the lease as tentative. 1823 */ 1824 my_log(LOG_DEBUG, "DHCP %s: wake from hibernation", 1825 if_name(if_p)); 1826 DHCPLeaseListRemoveAllButLastLease(&dhcp->lease_list); 1827 } 1828 dhcp_check_link(service_p, event_id); 1829 } 1830 else { 1831 absolute_time_t current_time; 1832 1833 current_time = timer_current_secs(); 1834 if (dhcp_check_lease(service_p, current_time) == FALSE) { 1835 /* no valid lease */ 1836 dhcp_init(service_p, IFEventID_start_e, NULL); 1837 break; 1838 } 1839 1840 /* if not RENEW/REBIND/BOUND, do INIT-REBOOT */ 1841 if (S_dhcp_cstate_is_bound_renew_or_rebind(dhcp->state) 1842 == FALSE) { 1843 struct in_addr our_ip; 1844 1845 our_ip = dhcp->saved.our_ip; 1846 1847 dhcp_init_reboot(service_p, IFEventID_start_e, &our_ip); 1848 break; 1849 } 1850 1851 /* Check if the new bssid router is arp-able. */ 1852 if ((wake_data->flags & kWakeFlagsBSSIDChanged) != 0) { 1853 arp_address_info_t info; 1854 1855 if (service_populate_router_arpinfo(service_p, 1856 &info)) { 1857 dhcp_check_router(service_p, IFEventID_start_e, 1858 (void *)&info); 1859 break; 1860 } 1861 } 1862 1863 /* Check the lease time */ 1864 if (dhcp->lease.length == DHCP_INFINITE_LEASE) { 1865 /* infinite lease, no need to do any maintenance */ 1866 break; 1867 } 1868 /* 1869 * Check the timer we had scheduled. If it is in the 1870 * future, schedule a new timer to wakeup in RENEW/REBIND then. 1871 * If it is in the past, proceed immediately to RENEW/REBIND. 1872 */ 1873 else if (current_time < dhcp->renew_rebind_time) { 1874 struct timeval tv; 1875 1876 tv.tv_sec = dhcp->renew_rebind_time - current_time; 1877 tv.tv_usec = 0; 1878 timer_set_relative(dhcp->timer, tv, 1879 (timer_func_t *)dhcp_renew_rebind, 1880 service_p, (void *)IFEventID_start_e, 1881 NULL); 1882 } 1883 else { 1884 dhcp_renew_rebind(service_p, IFEventID_start_e, NULL); 1885 } 1886 } 1887 break; 1888 } 1889 case IFEventID_get_dhcp_info_e: { 1890 dhcp_info_t * dhcp_info_p = ((dhcp_info_t *)event_data); 1891 1892 if (ServiceGetActiveIPAddress(service_p).s_addr == 0 1893 || dhcp->saved.pkt_size == 0) { 1894 break; 1895 } 1896 dhcp_set_dhcp_info(dhcp, dhcp_info_p); 1897 break; 1898 } 1899 case IFEventID_bssid_changed_e: { 1900 arp_address_info_t info; 1901 1902 if (S_dhcp_cstate_is_bound_renew_or_rebind(dhcp->state) 1903 == FALSE) { 1904 break; 1905 } 1906 if (service_populate_router_arpinfo(service_p, 1907 &info)) { 1908 dhcp_check_router(service_p, IFEventID_start_e, 1909 (void *)&info); 1910 } 1911 break; 1912 } 1913 default: 1914 break; 1915 } /* switch (event_id) */ 1916 return (status); 1917} 1918 1919static void 1920dhcp_init(ServiceRef service_p, IFEventID_t event_id, void * event_data) 1921{ 1922 absolute_time_t current_time = timer_current_secs(); 1923 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 1924 interface_t * if_p = service_interface(service_p); 1925 ipconfig_status_t status = ipconfig_status_success_e; 1926 struct timeval tv; 1927 1928 switch (event_id) { 1929 case IFEventID_start_e: { 1930 dhcp_lease_time_t lease_option = htonl(SUGGESTED_LEASE_LENGTH); 1931 dhcpoa_t options; 1932 dhcp_cstate_t prev_state = dhcp->state; 1933 1934 my_log(LOG_DEBUG, "DHCP %s: INIT", if_name(if_p)); 1935 1936 dhcp->state = dhcp_cstate_init_e; 1937 1938 /* clean-up anything that might have come before */ 1939 dhcp_cancel_pending_events(service_p); 1940 1941 /* form the request */ 1942 /* ALIGN: txbuf is aligned to at least sizeof(uint32) bytes */ 1943 dhcp->request = make_dhcp_request((struct dhcp *)(void *)dhcp->txbuf, 1944 sizeof(dhcp->txbuf), 1945 dhcp_msgtype_discover_e, 1946 if_link_address(if_p), 1947 if_link_arptype(if_p), 1948 if_link_length(if_p), 1949 dhcp->client_id, 1950 dhcp->client_id_len, 1951 dhcp->must_broadcast, 1952 &options); 1953 if (dhcp->request == NULL) { 1954 my_log(LOG_ERR, "DHCP %s: INIT make_dhcp_request failed", 1955 if_name(if_p)); 1956 status = ipconfig_status_allocation_failed_e; 1957 goto error; 1958 } 1959 if (dhcpoa_add(&options, dhcptag_lease_time_e, 1960 sizeof(lease_option), &lease_option) 1961 != dhcpoa_success_e) { 1962 my_log(LOG_ERR, "DHCP %s: INIT dhcpoa_add lease time failed, %s", 1963 if_name(if_p), dhcpoa_err(&options)); 1964 status = ipconfig_status_allocation_failed_e; 1965 goto error; 1966 } 1967 add_computer_name(&options); 1968 if (dhcpoa_add(&options, dhcptag_end_e, 0, 0) 1969 != dhcpoa_success_e) { 1970 my_log(LOG_ERR, "DHCP %s: INIT failed to terminate options", 1971 if_name(if_p)); 1972 status = ipconfig_status_allocation_failed_e; 1973 goto error; 1974 } 1975 dhcp->request_size = sizeof(*dhcp->request) + sizeof(G_rfc_magic) 1976 + dhcpoa_used(&options); 1977 if (dhcp->request_size < sizeof(struct bootp)) { 1978 /* pad out to BOOTP-sized packet */ 1979 dhcp->request_size = sizeof(struct bootp); 1980 } 1981 if (prev_state != dhcp_cstate_init_reboot_e) { 1982 dhcp->start_secs = current_time; 1983 } 1984 dhcp->wait_secs = G_initial_wait_secs; 1985 dhcp->try = 0; 1986 dhcp->xid++; 1987 dhcp->gathering = FALSE; 1988 dhcp->saved.rating = 0; 1989 dhcp->got_nak = FALSE; 1990 (void)service_enable_autoaddr(service_p); 1991 bootp_client_enable_receive(dhcp->client, 1992 (bootp_receive_func_t *)dhcp_init, 1993 service_p, (void *)IFEventID_data_e); 1994 /* FALL THROUGH */ 1995 } 1996 case IFEventID_timeout_e: { 1997 if (dhcp->gathering == TRUE) { 1998 /* done gathering */ 1999 if (dhcp->saved.is_dhcp) { 2000 dhcp_select(service_p, IFEventID_start_e, NULL); 2001 break; /* out of switch */ 2002 } 2003 dhcp_bound(service_p, IFEventID_start_e, NULL); 2004 break; /* out of switch */ 2005 } 2006 dhcp->try++; 2007 if (dhcp->try > 1) { 2008 link_status_t link_status = service_link_status(service_p); 2009 2010 if (link_status.valid 2011 && link_status.active == FALSE) { 2012 dhcp_inactive(service_p); 2013 break; 2014 } 2015 } 2016 if (dhcp->try >= (G_dhcp_router_arp_at_retry_count + 1)) { 2017 /* try to confirm the router's address */ 2018 dhcp_arp_router(service_p, IFEventID_start_e, ¤t_time); 2019 } 2020 if (service_router_all_valid(service_p) == FALSE 2021 && dhcp->try >= (G_dhcp_allocate_linklocal_at_retry_count + 1)) { 2022 if (G_dhcp_failure_configures_linklocal) { 2023 ServiceSetStatus(service_p, 2024 ipconfig_status_no_server_e); 2025 linklocal_service_change(service_p, LINKLOCAL_ALLOCATE); 2026 } 2027 } 2028 if (dhcp->try > (G_max_retries + 1)) { 2029 /* no server responded */ 2030 if (service_router_all_valid(service_p)) { 2031 /* lease is still valid, router is still available */ 2032 dhcp_bound(service_p, IFEventID_start_e, NULL); 2033 break; 2034 } 2035 /* DHCP server and router not responding, try again later */ 2036 dhcp_no_server(service_p, IFEventID_start_e, NULL); 2037 break; /* out of switch */ 2038 } 2039 dhcp->request->dp_xid = htonl(dhcp->xid); 2040 dhcp->request->dp_secs 2041 = htons((uint16_t)(current_time - dhcp->start_secs)); 2042 2043 /* send the packet */ 2044 if (bootp_client_transmit(dhcp->client, 2045 G_ip_broadcast, G_ip_zeroes, 2046 G_server_port, G_client_port, 2047 dhcp->request, dhcp->request_size) < 0) { 2048 my_log(LOG_ERR, 2049 "DHCP %s: INIT transmit failed", if_name(if_p)); 2050 } 2051 /* wait for responses */ 2052 tv.tv_sec = dhcp->wait_secs; 2053 tv.tv_usec = random_range(0, USECS_PER_SEC - 1); 2054 my_log(LOG_DEBUG, "DHCP %s: INIT waiting at %d for %d.%06d", 2055 if_name(if_p), 2056 current_time - dhcp->start_secs, 2057 tv.tv_sec, tv.tv_usec); 2058 timer_set_relative(dhcp->timer, tv, 2059 (timer_func_t *)dhcp_init, 2060 service_p, (void *)IFEventID_timeout_e, NULL); 2061 /* next time wait twice as long */ 2062 dhcp->wait_secs *= 2; 2063 if (dhcp->wait_secs > G_max_wait_secs) 2064 dhcp->wait_secs = G_max_wait_secs; 2065 break; 2066 } 2067 case IFEventID_data_e: { 2068 boolean_t is_dhcp = TRUE; 2069 dhcp_lease_time_t lease; 2070 bootp_receive_data_t *pkt = (bootp_receive_data_t *)event_data; 2071 dhcp_msgtype_t reply_msgtype = dhcp_msgtype_none_e; 2072 struct in_addr server_ip; 2073 dhcp_lease_time_t t1; 2074 dhcp_lease_time_t t2; 2075 2076 if (verify_packet(pkt, dhcp->xid, if_p, &reply_msgtype, 2077 &server_ip, &is_dhcp) == FALSE 2078 || server_ip.s_addr == 0 2079 || ip_valid(pkt->data->dp_yiaddr) == FALSE) { 2080 /* reject the packet */ 2081 break; /* out of switch */ 2082 } 2083 if (is_dhcp == FALSE 2084 || reply_msgtype == dhcp_msgtype_offer_e) { 2085 int rating = 0; 2086 int dhcp_packet_ideal_rating = n_dhcp_params 2087 + DHCP_ADDRESS_RATING_GOOD; 2088 2089 dhcp_get_lease_from_options(&pkt->options, &lease, &t1, &t2); 2090 rating = dhcpol_count_params(&pkt->options, 2091 dhcp_params, n_dhcp_params); 2092 2093 /* We need to get an augmented rating to account for routable 2094 * addresses (Ie, those which are not private or linklocal 2095 */ 2096 rating += 2097 get_rating_for_ip_address(&pkt->data->dp_yiaddr); 2098 2099 /* 2100 * The new packet is "better" than the saved 2101 * packet if: 2102 * - there was no saved packet, or 2103 * - the new packet is a DHCP packet and the saved 2104 * one is a BOOTP packet or a DHCP packet with 2105 * a lower rating, or 2106 * - the new packet and the saved packet are both 2107 * BOOTP but the new one has a higher rating 2108 * All this to allow BOOTP/DHCP interoperability 2109 * ie. we accept a BOOTP response if it's 2110 * the only one we've got. We expect/favour a DHCP 2111 * response. 2112 */ 2113 if (dhcp->saved.pkt_size == 0 2114 || (is_dhcp == TRUE && (dhcp->saved.is_dhcp == FALSE 2115 || rating > dhcp->saved.rating)) 2116 || (is_dhcp == FALSE && dhcp->saved.is_dhcp == FALSE 2117 && rating > dhcp->saved.rating)) { 2118 service_router_clear(service_p); 2119 dhcpol_free(&dhcp->saved.options); 2120 bcopy(pkt->data, dhcp->saved.pkt, pkt->size); 2121 dhcp->saved.pkt_size = pkt->size; 2122 dhcp->saved.rating = rating; 2123 /* ALIGN: saved.pkt is uint32_t aligned, cast ok */ 2124 (void)dhcpol_parse_packet(&dhcp->saved.options, 2125 (void *)dhcp->saved.pkt, 2126 dhcp->saved.pkt_size, NULL); 2127 dhcp->saved.our_ip = pkt->data->dp_yiaddr; 2128 dhcp->saved.server_ip = server_ip; 2129 dhcp->saved.is_dhcp = is_dhcp; 2130 dhcp_set_lease_params(service_p, "INIT", is_dhcp, 2131 current_time, lease, t1, t2); 2132 if (is_dhcp && rating == dhcp_packet_ideal_rating) { 2133 dhcp_select(service_p, IFEventID_start_e, NULL); 2134 break; /* out of switch */ 2135 } 2136 if (dhcp->gathering == FALSE) { 2137 struct timeval t = {0,0}; 2138 t.tv_sec = G_gather_secs; 2139 my_log(LOG_DEBUG, "DHCP %s: INIT gathering began at %d", 2140 if_name(if_p), 2141 current_time - dhcp->start_secs); 2142 dhcp->gathering = TRUE; 2143 timer_set_relative(dhcp->timer, t, 2144 (timer_func_t *)dhcp_init, 2145 service_p, (void *)IFEventID_timeout_e, 2146 NULL); 2147 } 2148 } 2149 } 2150 break; 2151 } 2152 default: 2153 break; 2154 } 2155 return; 2156 2157 error: 2158 dhcp_failed(service_p, status); 2159 return; 2160} 2161 2162 2163static void 2164dhcp_init_reboot(ServiceRef service_p, IFEventID_t evid, void * event_data) 2165{ 2166 absolute_time_t current_time = timer_current_secs(); 2167 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 2168 interface_t * if_p = service_interface(service_p); 2169 struct in_addr source_ip = G_ip_zeroes; 2170 ipconfig_status_t status = ipconfig_status_success_e; 2171 struct timeval tv; 2172 struct in_addr server_ip = G_ip_broadcast; 2173 2174 if (ServiceIsNetBoot(service_p)) { 2175 netboot_addresses(&source_ip, NULL); 2176 } 2177 2178 switch (evid) { 2179 case IFEventID_start_e: { 2180 struct in_addr our_ip; 2181 dhcp_lease_time_t lease_option = htonl(SUGGESTED_LEASE_LENGTH); 2182 dhcpoa_t options; 2183 2184 dhcp->start_secs = current_time; 2185 dhcp->try = 0; 2186 dhcp->wait_secs = G_initial_wait_secs; 2187 dhcp->state = dhcp_cstate_init_reboot_e; 2188 if (source_ip.s_addr == 0) { 2189 our_ip = *((struct in_addr *)event_data); 2190 } 2191 else { 2192 our_ip = source_ip; 2193 } 2194 if (G_IPConfiguration_verbose) { 2195 my_log(LOG_DEBUG, "DHCP %s: INIT-REBOOT (" IP_FORMAT ")", 2196 if_name(if_p), IP_LIST(&our_ip)); 2197 } 2198 2199 /* clean-up anything that might have come before */ 2200 dhcp_cancel_pending_events(service_p); 2201 2202 /* form the request */ 2203 /* ALIGN: txbuf is aligned to at least sizeof(uint32_t) bytes */ 2204 dhcp->request = make_dhcp_request((struct dhcp *)(void *)dhcp->txbuf, 2205 sizeof(dhcp->txbuf), 2206 dhcp_msgtype_request_e, 2207 if_link_address(if_p), 2208 if_link_arptype(if_p), 2209 if_link_length(if_p), 2210 dhcp->client_id, 2211 dhcp->client_id_len, 2212 dhcp->must_broadcast, 2213 &options); 2214 if (dhcp->request == NULL) { 2215 status = ipconfig_status_allocation_failed_e; 2216 goto error; 2217 } 2218 if (dhcpoa_add(&options, dhcptag_requested_ip_address_e, 2219 sizeof(our_ip), &our_ip) 2220 != dhcpoa_success_e) { 2221 my_log(LOG_ERR, "DHCP %s: INIT-REBOOT add request ip failed, %s", 2222 if_name(if_p), dhcpoa_err(&options)); 2223 status = ipconfig_status_allocation_failed_e; 2224 goto error; 2225 } 2226 if (dhcpoa_add(&options, dhcptag_lease_time_e, 2227 sizeof(lease_option), &lease_option) 2228 != dhcpoa_success_e) { 2229 my_log(LOG_ERR, "DHCP %s: INIT-REBOOT add lease time failed, %s", 2230 if_name(if_p), dhcpoa_err(&options)); 2231 status = ipconfig_status_allocation_failed_e; 2232 goto error; 2233 } 2234 add_computer_name(&options); 2235 if (dhcpoa_add(&options, dhcptag_end_e, 0, 0) 2236 != dhcpoa_success_e) { 2237 my_log(LOG_ERR, "DHCP %s: INIT-REBOOT failed to terminate options", 2238 if_name(if_p)); 2239 status = ipconfig_status_allocation_failed_e; 2240 goto error; 2241 } 2242 dhcp->request_size = sizeof(*dhcp->request) + sizeof(G_rfc_magic) 2243 + dhcpoa_used(&options); 2244 if (dhcp->request_size < sizeof(struct bootp)) { 2245 /* pad out to BOOTP-sized packet */ 2246 dhcp->request_size = sizeof(struct bootp); 2247 } 2248 dhcp->got_nak = FALSE; 2249 dhcp->gathering = FALSE; 2250 dhcp->xid++; 2251 dhcp->saved.our_ip = our_ip; 2252 dhcp->saved.rating = 0; 2253 (void)service_enable_autoaddr(service_p); 2254 bootp_client_enable_receive(dhcp->client, 2255 (bootp_receive_func_t *)dhcp_init_reboot, 2256 service_p, (void *)IFEventID_data_e); 2257 /* FALL THROUGH */ 2258 } 2259 case IFEventID_timeout_e: { 2260 if (dhcp->gathering == TRUE) { 2261 /* done gathering */ 2262 dhcp_bound(service_p, IFEventID_start_e, NULL); 2263 break; /* out of switch */ 2264 } 2265 dhcp->try++; 2266 if (dhcp->try > 1) { 2267 link_status_t link_status = service_link_status(service_p); 2268 2269 if (link_status.valid 2270 && link_status.active == FALSE) { 2271 dhcp_inactive(service_p); 2272 break; 2273 } 2274 } 2275 /* try to confirm the router's address */ 2276 dhcp_arp_router(service_p, IFEventID_start_e, ¤t_time); 2277 2278 if (service_router_all_valid(service_p) == FALSE 2279 && dhcp->try >= (G_dhcp_allocate_linklocal_at_retry_count + 1)) { 2280 if (G_dhcp_failure_configures_linklocal) { 2281 ServiceSetStatus(service_p, ipconfig_status_no_server_e); 2282 linklocal_service_change(service_p, LINKLOCAL_ALLOCATE); 2283 } 2284 } 2285 if (dhcp->try > (G_dhcp_init_reboot_retry_count + 1)) { 2286 if (G_IPConfiguration_verbose) { 2287 my_log(LOG_DEBUG, "DHCP %s: INIT-REBOOT (" IP_FORMAT 2288 ") timed out", if_name(if_p), 2289 IP_LIST(&dhcp->saved.our_ip)); 2290 } 2291 (void)service_remove_address(service_p); 2292 service_publish_failure_sync(service_p, 2293 ipconfig_status_server_not_responding_e, 2294 FALSE); 2295 dhcp->try--; 2296 /* go back to the INIT state */ 2297 dhcp_init(service_p, IFEventID_start_e, NULL); 2298 break; /* ouf of case */ 2299 } 2300 2301 dhcp->request->dp_xid = htonl(dhcp->xid); 2302 dhcp->request->dp_secs 2303 = htons((uint16_t)(current_time - dhcp->start_secs)); 2304 /* send the packet */ 2305 if (bootp_client_transmit(dhcp->client, 2306 server_ip, source_ip, 2307 G_server_port, G_client_port, 2308 dhcp->request, dhcp->request_size) < 0) { 2309 my_log(LOG_ERR, 2310 "DHCP %s: INIT-REBOOT transmit failed", 2311 if_name(if_p)); 2312 } 2313 /* wait for responses */ 2314 tv.tv_sec = dhcp->wait_secs; 2315 tv.tv_usec = random_range(0, USECS_PER_SEC - 1); 2316 2317 if (G_IPConfiguration_verbose) { 2318 my_log(LOG_DEBUG, 2319 "DHCP %s: INIT-REBOOT (" IP_FORMAT 2320 ") waiting at %d for %d.%06d", 2321 if_name(if_p), 2322 IP_LIST(&dhcp->saved.our_ip), 2323 current_time - dhcp->start_secs, 2324 tv.tv_sec, tv.tv_usec); 2325 } 2326 timer_set_relative(dhcp->timer, tv, 2327 (timer_func_t *)dhcp_init_reboot, 2328 service_p, (void *)IFEventID_timeout_e, NULL); 2329 /* next time wait twice as long */ 2330 dhcp->wait_secs *= 2; 2331 if (dhcp->wait_secs > G_max_wait_secs) 2332 dhcp->wait_secs = G_max_wait_secs; 2333 break; 2334 } 2335 case IFEventID_data_e: { 2336 boolean_t is_dhcp = TRUE; 2337 dhcp_lease_time_t lease; 2338 bootp_receive_data_t *pkt = (bootp_receive_data_t *)event_data; 2339 dhcp_msgtype_t reply_msgtype = dhcp_msgtype_none_e; 2340 struct in_addr server_ip; 2341 dhcp_lease_time_t t1; 2342 dhcp_lease_time_t t2; 2343 2344 if (verify_packet(pkt, dhcp->xid, if_p, &reply_msgtype, 2345 &server_ip, &is_dhcp) == FALSE) { 2346 /* reject the packet */ 2347 break; /* out of switch */ 2348 } 2349 if (ServiceIsNetBoot(service_p) == FALSE 2350 && reply_msgtype == dhcp_msgtype_nak_e) { 2351 if (G_IPConfiguration_verbose) { 2352 my_log(LOG_DEBUG, "DHCP %s: got DHCP NAK", 2353 if_name(if_p)); 2354 } 2355 if (arp_client_is_active(dhcp->arp)) { 2356 dhcp->got_nak = TRUE; 2357 } 2358 else { 2359 service_publish_failure(service_p, 2360 ipconfig_status_lease_terminated_e); 2361 dhcp_unbound(service_p, IFEventID_start_e, (void *)TRUE); 2362 break; /* out of switch */ 2363 } 2364 } 2365 if (server_ip.s_addr == 0 2366 || pkt->data->dp_yiaddr.s_addr != dhcp->saved.our_ip.s_addr) { 2367 /* reject the packet */ 2368 break; /* out of switch */ 2369 } 2370 if (is_dhcp == FALSE 2371 || reply_msgtype == dhcp_msgtype_ack_e) { 2372 int rating = 0; 2373 2374 dhcp_get_lease_from_options(&pkt->options, &lease, &t1, &t2); 2375 2376 rating = dhcpol_count_params(&pkt->options, 2377 dhcp_params, n_dhcp_params); 2378 /* 2379 * The new packet is "better" than the saved 2380 * packet if: 2381 * - there was no saved packet, or 2382 * - the new packet is a DHCP packet and the saved 2383 * one is a BOOTP packet or a DHCP packet with 2384 * a lower rating, or 2385 * - the new packet and the saved packet are both 2386 * BOOTP but the new one has a higher rating 2387 * All this to allow BOOTP/DHCP interoperability 2388 * ie. we accept a BOOTP response if it's 2389 * the only one we've got. We expect/favour a DHCP 2390 * response. 2391 */ 2392 if (dhcp->saved.pkt_size == 0 2393 || (is_dhcp == TRUE && (dhcp->saved.is_dhcp == FALSE 2394 || rating > dhcp->saved.rating)) 2395 || (is_dhcp == FALSE && dhcp->saved.is_dhcp == FALSE 2396 && rating > dhcp->saved.rating)) { 2397 service_router_clear(service_p); 2398 dhcpol_free(&dhcp->saved.options); 2399 bcopy(pkt->data, dhcp->saved.pkt, pkt->size); 2400 dhcp->saved.pkt_size = pkt->size; 2401 dhcp->saved.rating = rating; 2402 /* ALIGN: saved.pkt is uint32_t aligned, cast ok */ 2403 (void)dhcpol_parse_packet(&dhcp->saved.options, 2404 (void *)dhcp->saved.pkt, 2405 dhcp->saved.pkt_size, NULL); 2406 dhcp->saved.our_ip = pkt->data->dp_yiaddr; 2407 dhcp->saved.server_ip = server_ip; 2408 dhcp->saved.is_dhcp = is_dhcp; 2409 dhcp_set_lease_params(service_p, "INIT-REBOOT", is_dhcp, 2410 current_time, lease, t1, t2); 2411 if (is_dhcp && rating == n_dhcp_params) { 2412 dhcp_bound(service_p, IFEventID_start_e, NULL); 2413 break; /* out of switch */ 2414 } 2415 if (dhcp->gathering == FALSE) { 2416 struct timeval t = {0,0}; 2417 t.tv_sec = G_gather_secs; 2418 if (G_IPConfiguration_verbose) { 2419 my_log(LOG_DEBUG, 2420 "DHCP %s: INIT-REBOOT (" 2421 IP_FORMAT ") gathering began at %d", 2422 if_name(if_p), 2423 IP_LIST(&dhcp->saved.our_ip), 2424 current_time - dhcp->start_secs); 2425 } 2426 /* don't bother trying to figure out what lease to use */ 2427 arp_client_cancel(dhcp->arp); 2428 2429 dhcp->gathering = TRUE; 2430 timer_set_relative(dhcp->timer, t, 2431 (timer_func_t *)dhcp_init_reboot, 2432 service_p, 2433 (void *)IFEventID_timeout_e, 2434 NULL); 2435 } 2436 } 2437 } 2438 break; 2439 } 2440 default: 2441 break; /* shouldn't happen */ 2442 } 2443 return; 2444 2445 error: 2446 dhcp_failed(service_p, status); 2447 return; 2448} 2449 2450static void 2451dhcp_select(ServiceRef service_p, IFEventID_t evid, void * event_data) 2452{ 2453 absolute_time_t current_time = timer_current_secs(); 2454 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 2455 interface_t * if_p = service_interface(service_p); 2456 ipconfig_status_t status = ipconfig_status_success_e; 2457 struct timeval tv; 2458 2459 switch (evid) { 2460 case IFEventID_start_e: { 2461 dhcpoa_t options; 2462 2463 my_log(LOG_DEBUG, "DHCP %s: SELECT", if_name(if_p)); 2464 /* clean-up anything that might have come before */ 2465 dhcp_cancel_pending_events(service_p); 2466 2467 dhcp->state = dhcp_cstate_select_e; 2468 2469 /* form the request */ 2470 /* ALIGN: txbuf is uint32_t aligned, cast ok */ 2471 dhcp->request = make_dhcp_request((struct dhcp *)(void *)dhcp->txbuf, 2472 sizeof(dhcp->txbuf), 2473 dhcp_msgtype_request_e, 2474 if_link_address(if_p), 2475 if_link_arptype(if_p), 2476 if_link_length(if_p), 2477 dhcp->client_id, 2478 dhcp->client_id_len, 2479 dhcp->must_broadcast, 2480 &options); 2481 if (dhcp->request == NULL) { 2482 my_log(LOG_ERR, "DHCP %s: SELECT make_dhcp_request failed", 2483 if_name(if_p)); 2484 status = ipconfig_status_allocation_failed_e; 2485 goto error; 2486 } 2487 /* insert server identifier and requested ip address */ 2488 if (dhcpoa_add(&options, dhcptag_requested_ip_address_e, 2489 sizeof(dhcp->saved.our_ip), &dhcp->saved.our_ip) 2490 != dhcpoa_success_e) { 2491 my_log(LOG_ERR, "DHCP %s: SELECT add requested ip failed, %s", 2492 if_name(if_p), dhcpoa_err(&options)); 2493 status = ipconfig_status_allocation_failed_e; 2494 goto error; 2495 } 2496 if (dhcpoa_add(&options, dhcptag_server_identifier_e, 2497 sizeof(dhcp->saved.server_ip), &dhcp->saved.server_ip) 2498 != dhcpoa_success_e) { 2499 my_log(LOG_ERR, "DHCP %s: SELECT add server ip failed, %s", 2500 if_name(if_p), dhcpoa_err(&options)); 2501 status = ipconfig_status_allocation_failed_e; 2502 goto error; 2503 } 2504 add_computer_name(&options); 2505 if (dhcpoa_add(&options, dhcptag_end_e, 0, 0) 2506 != dhcpoa_success_e) { 2507 my_log(LOG_ERR, "DHCP %s: SELECT failed to terminate options", 2508 if_name(if_p)); 2509 status = ipconfig_status_allocation_failed_e; 2510 goto error; 2511 } 2512 dhcp->request_size = sizeof(*dhcp->request) + sizeof(G_rfc_magic) 2513 + dhcpoa_used(&options); 2514 if (dhcp->request_size < sizeof(struct bootp)) { 2515 /* pad out to BOOTP-sized packet */ 2516 dhcp->request_size = sizeof(struct bootp); 2517 } 2518 dhcp->try = 0; 2519 dhcp->gathering = FALSE; 2520 dhcp->wait_secs = G_initial_wait_secs; 2521 bootp_client_enable_receive(dhcp->client, 2522 (bootp_receive_func_t *)dhcp_select, 2523 service_p, (void *)IFEventID_data_e); 2524 } 2525 case IFEventID_timeout_e: { 2526 dhcp->try++; 2527 if (dhcp->try > (G_dhcp_select_retry_count + 1)) { 2528 my_log(LOG_DEBUG, "DHCP %s: SELECT timed out", if_name(if_p)); 2529 /* go back to INIT and try again */ 2530 dhcp_init(service_p, IFEventID_start_e, NULL); 2531 break; /* out of switch */ 2532 } 2533 dhcp->request->dp_xid = htonl(dhcp->xid); 2534 dhcp->request->dp_secs 2535 = htons((uint16_t)(current_time - dhcp->start_secs)); 2536 2537 /* send the packet */ 2538 if (bootp_client_transmit(dhcp->client, 2539 G_ip_broadcast, G_ip_zeroes, 2540 G_server_port, G_client_port, 2541 dhcp->request, dhcp->request_size) < 0) { 2542 my_log(LOG_ERR, 2543 "DHCP %s: SELECT transmit failed", 2544 if_name(if_p)); 2545 } 2546 /* wait for responses */ 2547 tv.tv_sec = dhcp->wait_secs; 2548 tv.tv_usec = 0; 2549 my_log(LOG_DEBUG, "DHCP %s: SELECT waiting at %d for %d.%06d", 2550 if_name(if_p), 2551 current_time - dhcp->start_secs, 2552 tv.tv_sec, tv.tv_usec); 2553 timer_set_relative(dhcp->timer, tv, 2554 (timer_func_t *)dhcp_select, 2555 service_p, (void *)IFEventID_timeout_e, NULL); 2556 /* next time wait twice as long */ 2557 dhcp->wait_secs *= 2; 2558 if (dhcp->wait_secs > G_max_wait_secs) 2559 dhcp->wait_secs = G_max_wait_secs; 2560 break; 2561 } 2562 case IFEventID_data_e: { 2563 boolean_t is_dhcp = TRUE; 2564 dhcp_lease_time_t lease = SUGGESTED_LEASE_LENGTH; 2565 bootp_receive_data_t *pkt = (bootp_receive_data_t *)event_data; 2566 dhcp_msgtype_t reply_msgtype = dhcp_msgtype_none_e; 2567 struct in_addr server_ip = { 0 }; 2568 dhcp_lease_time_t t1; 2569 dhcp_lease_time_t t2; 2570 2571 if (verify_packet(pkt, dhcp->xid, if_p, &reply_msgtype, 2572 &server_ip, &is_dhcp) == FALSE 2573 || is_dhcp == FALSE) { 2574 /* reject the packet */ 2575 break; /* out of switch */ 2576 } 2577 2578 if (reply_msgtype == dhcp_msgtype_nak_e) { 2579 if (server_ip.s_addr == 0 2580 || server_ip.s_addr != dhcp->saved.server_ip.s_addr) { 2581 /* reject the packet */ 2582 break; /* out of switch */ 2583 } 2584 /* clean-up anything that might have come before */ 2585 dhcp_cancel_pending_events(service_p); 2586 2587 /* 2588 * wait to retry INIT just in case there's a misbehaving server 2589 * and we get stuck in an INIT-SELECT-NAK infinite loop 2590 */ 2591 tv.tv_sec = 10; 2592 tv.tv_usec = 0; 2593 timer_set_relative(dhcp->timer, tv, 2594 (timer_func_t *)dhcp_init, 2595 service_p, (void *)IFEventID_start_e, NULL); 2596 break; /* out of switch */ 2597 } 2598 if (reply_msgtype != dhcp_msgtype_ack_e 2599 || ip_valid(pkt->data->dp_yiaddr) == FALSE) { 2600 /* reject the packet */ 2601 break; /* out of switch */ 2602 } 2603 dhcp_get_lease_from_options(&pkt->options, &lease, &t1, &t2); 2604 dhcp_set_lease_params(service_p, "SELECT", is_dhcp, 2605 current_time, lease, t1, t2); 2606 dhcpol_free(&dhcp->saved.options); 2607 bcopy(pkt->data, dhcp->saved.pkt, pkt->size); 2608 dhcp->saved.pkt_size = pkt->size; 2609 dhcp->saved.rating = 0; 2610 /* ALIGN: saved.pkt is uint32_t aligned, cast ok */ 2611 (void)dhcpol_parse_packet(&dhcp->saved.options, 2612 (void *)dhcp->saved.pkt, 2613 dhcp->saved.pkt_size, NULL); 2614 dhcp->saved.our_ip = pkt->data->dp_yiaddr; 2615 if (server_ip.s_addr != 0) { 2616 dhcp->saved.server_ip = server_ip; 2617 } 2618 dhcp->saved.is_dhcp = TRUE; 2619 dhcp_bound(service_p, IFEventID_start_e, NULL); 2620 break; 2621 } 2622 default: 2623 break; 2624 } 2625 return; 2626 2627 error: 2628 dhcp_failed(service_p, status); 2629 return; 2630} 2631 2632static void 2633dhcp_check_router(ServiceRef service_p, 2634 IFEventID_t event_id, void * event_data) 2635{ 2636 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 2637 interface_t * if_p = service_interface(service_p); 2638 2639 switch (event_id) { 2640 case IFEventID_start_e: { 2641 arp_address_info_t* info_p = (arp_address_info_t*) event_data; 2642 2643 info_p->sender_ip = dhcp->saved.our_ip; 2644 2645 arp_client_detect(dhcp->arp, 2646 (arp_result_func_t *) 2647 dhcp_check_router, 2648 service_p, 2649 (void *)IFEventID_arp_e, 2650 info_p, 1, TRUE); 2651 break; 2652 } 2653 case IFEventID_arp_e: { 2654 arp_result_t * result = (arp_result_t *)event_data; 2655 2656 if (result->error || result->in_use == FALSE) { 2657 if (result->error) { 2658 my_log(LOG_ERR, "DHCP %s: ARP default gateway failed, %s", 2659 if_name(if_p), 2660 arp_client_errmsg(dhcp->arp)); 2661 } 2662 else { 2663 my_log(LOG_DEBUG, 2664 "DHCP %s: ARP detect default gateway got " 2665 "no response", if_name(if_p)); 2666 } 2667 /* Try DHCP */ 2668 dhcp_check_link(service_p, event_id); 2669 } 2670 else { 2671 absolute_time_t current_time = timer_current_secs(); 2672 2673 my_log(LOG_DEBUG, "DHCP %s: ARP detect default gateway got " 2674 "a response", if_name(if_p)); 2675 2676 /* Check the lease time */ 2677 if (dhcp->lease.length == DHCP_INFINITE_LEASE) { 2678 /* infinite lease, no need to do any maintenance */ 2679 break; 2680 } 2681 /* 2682 * Check the timer we had scheduled. If it is in the 2683 * future, schedule a new timer to wakeup in RENEW/REBIND then. 2684 * If it is in the past, proceed immediately to RENEW/REBIND. 2685 */ 2686 else if (current_time < dhcp->renew_rebind_time) { 2687 struct timeval tv; 2688 2689 tv.tv_sec = dhcp->renew_rebind_time - current_time; 2690 tv.tv_usec = 0; 2691 timer_set_relative(dhcp->timer, tv, 2692 (timer_func_t *)dhcp_renew_rebind, 2693 service_p, (void *)IFEventID_start_e, 2694 NULL); 2695 } 2696 else { 2697 dhcp_renew_rebind(service_p, IFEventID_start_e, NULL); 2698 } 2699 } 2700 break; 2701 } 2702 default: 2703 break; 2704 } 2705} 2706 2707static void 2708dhcp_arp_router(ServiceRef service_p, IFEventID_t event_id, void * event_data) 2709{ 2710 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 2711 interface_t * if_p = service_interface(service_p); 2712 2713 switch (event_id) { 2714 case IFEventID_start_e: { 2715 int info_count; 2716 arp_address_info_t * info_p; 2717 CFStringRef ssid; 2718 absolute_time_t start_time_threshold; 2719 absolute_time_t * start_time_threshold_p; 2720 bool tentative_ok; 2721 2722 if (G_router_arp == FALSE) { 2723 /* don't ARP for the router */ 2724 break; 2725 } 2726 if (service_router_is_arp_verified(service_p)) { 2727 /* nothing to be done */ 2728 break; 2729 } 2730 tentative_ok = (dhcp->state == dhcp_cstate_init_e); 2731 if (if_is_wireless(if_p)) { 2732 absolute_time_t * current_time_p; 2733 2734 ssid = ServiceGetSSID(service_p); 2735 if (ssid == NULL) { 2736 /* no SSID, no play */ 2737 my_log(LOG_NOTICE, "dhcp_arp_router: %s SSID unavailable", 2738 if_name(if_p)); 2739 break; 2740 } 2741 current_time_p = (absolute_time_t *)event_data; 2742 start_time_threshold = *current_time_p 2743 - G_router_arp_wifi_lease_start_threshold_secs; 2744 start_time_threshold_p = &start_time_threshold; 2745 } 2746 else { 2747 start_time_threshold_p = NULL; 2748 ssid = NULL; 2749 } 2750 info_p = DHCPLeaseListCopyARPAddressInfo(&dhcp->lease_list, 2751 ssid, 2752 start_time_threshold_p, 2753 tentative_ok, 2754 &info_count); 2755 if (info_p == NULL) { 2756 my_log(LOG_DEBUG, 2757 "DHCP %s: ARP router: No leases to query for", 2758 if_name(if_p)); 2759 break; 2760 } 2761 if (G_IPConfiguration_verbose) { 2762 int i; 2763 2764 my_log(LOG_DEBUG, "DHCP %s: ARP detect router starting", 2765 if_name(if_p)); 2766 for (i = 0; i < info_count; i++) { 2767 my_log(LOG_DEBUG, "%d. sender " IP_FORMAT 2768 " target " IP_FORMAT "", i + 1, 2769 IP_LIST(&info_p[i].sender_ip), 2770 IP_LIST(&info_p[i].target_ip)); 2771 } 2772 } 2773 arp_client_detect(dhcp->arp, 2774 (arp_result_func_t *) 2775 dhcp_arp_router, 2776 service_p, 2777 (void *)IFEventID_arp_e, 2778 info_p, info_count, FALSE); 2779 free(info_p); 2780 break; 2781 } 2782 case IFEventID_arp_e: { 2783 arp_address_info_t * info_p; 2784 DHCPLeaseRef lease_p; 2785 void * option; 2786 struct in_addr mask = {0}; 2787 arp_result_t * result = (arp_result_t *)event_data; 2788 int where; 2789 2790 if (result->error || result->in_use == FALSE) { 2791 if (result->error) { 2792 my_log(LOG_ERR, "DHCP %s: ARP detect ROUTER failed, %s", 2793 if_name(if_p), 2794 arp_client_errmsg(dhcp->arp)); 2795 } 2796 else { 2797 my_log(LOG_DEBUG, 2798 "DHCP %s: ARP detect router got no response", 2799 if_name(if_p)); 2800 } 2801 if (dhcp->got_nak) { 2802 service_publish_failure(service_p, 2803 ipconfig_status_lease_terminated_e); 2804 dhcp_unbound(service_p, IFEventID_start_e, (void *)TRUE); 2805 break; /* out of switch */ 2806 } 2807 break; 2808 } 2809 info_p = &result->addr; 2810 if (G_IPConfiguration_verbose) { 2811 my_log(LOG_DEBUG, "DHCP %s: got response for sender " 2812 IP_FORMAT " target " IP_FORMAT, 2813 if_name(if_p), IP_LIST(&info_p->sender_ip), 2814 IP_LIST(&info_p->target_ip)); 2815 } 2816 where = DHCPLeaseListFindLease(&dhcp->lease_list, 2817 info_p->sender_ip, 2818 info_p->target_ip, 2819 info_p->target_hardware, 2820 if_link_length(if_p)); 2821 if (where == -1) { 2822 if (G_IPConfiguration_verbose) { 2823 my_log(LOG_DEBUG, "DHCP %s: lease for " 2824 IP_FORMAT " is no longer available", 2825 if_name(if_p), IP_LIST(&info_p->sender_ip)); 2826 } 2827 if (dhcp->got_nak) { 2828 service_publish_failure(service_p, 2829 ipconfig_status_lease_terminated_e); 2830 dhcp_unbound(service_p, IFEventID_start_e, NULL); 2831 } 2832 break; /* out of switch */ 2833 } 2834 lease_p = DHCPLeaseListElement(&dhcp->lease_list, where); 2835 if (G_IPConfiguration_verbose) { 2836 my_log(LOG_DEBUG, "DHCP %s: identified lease for " IP_FORMAT, 2837 if_name(if_p), IP_LIST(&lease_p->our_ip)); 2838 } 2839 if (dhcp->state == dhcp_cstate_init_e) { 2840 if (dhcp->gathering == TRUE) { 2841 /* we got a response, don't bother with old lease */ 2842 break; 2843 } 2844 switch_to_lease(service_p, lease_p); 2845 service_router_set_all_valid(service_p); 2846 break; 2847 } 2848 if (dhcp->state != dhcp_cstate_init_reboot_e) { 2849 /* this can't really happen */ 2850 break; 2851 } 2852 if (dhcp->gathering == TRUE) { 2853 struct in_addr * router_p; 2854 2855 if (lease_p->our_ip.s_addr != dhcp->saved.our_ip.s_addr) { 2856 /* not the same lease */ 2857 break; 2858 } 2859 router_p = dhcp_get_router_from_options(&dhcp->saved.options, 2860 dhcp->saved.our_ip); 2861 if (router_p == NULL 2862 || router_p->s_addr != lease_p->router_ip.s_addr) { 2863 /* router changed or different, do full refresh */ 2864 break; 2865 } 2866 } 2867 else if (switch_to_lease(service_p, lease_p)) { 2868 dhcpol_t options; 2869 struct in_addr * req_ip_p; 2870 2871 dhcp->request->dp_xid = htonl(++dhcp->xid); 2872 dhcpol_init(&options); 2873 /* ALIGN: txbuf is uint32_t aligned, cast ok */ 2874 (void)dhcpol_parse_packet(&options, 2875 (struct dhcp *)(void *)dhcp->txbuf, 2876 sizeof(dhcp->txbuf), NULL); 2877 req_ip_p 2878 = dhcpol_find_with_length(&options, 2879 dhcptag_requested_ip_address_e, 2880 sizeof(*req_ip_p)); 2881 if (req_ip_p != NULL) { 2882 /* switch to the new IP address */ 2883 *req_ip_p = lease_p->our_ip; 2884 dhcp->try = 0; 2885 } 2886 dhcpol_free(&options); 2887 } 2888 else if (dhcp->got_nak) { 2889 /* we got a nak and we didn't switch leases */ 2890 service_publish_failure(service_p, 2891 ipconfig_status_lease_terminated_e); 2892 dhcp_unbound(service_p, IFEventID_start_e, NULL); 2893 break; /* out of switch */ 2894 } 2895 service_router_set_all_valid(service_p); 2896 2897 /* lease is still valid, router is still available */ 2898 option = dhcpol_find_with_length(&dhcp->saved.options, 2899 dhcptag_subnet_mask_e, 2900 sizeof(mask)); 2901 if (option != NULL) { 2902 mask = *((struct in_addr *)option); 2903 } 2904 2905 /* allow user warning to appear */ 2906 dhcp->conflicting_address.s_addr = 0; 2907 dhcp->user_warned = FALSE; 2908 2909 /* set our address */ 2910 (void)service_set_address(service_p, dhcp->saved.our_ip, 2911 mask, G_ip_zeroes); 2912 dhcp_publish_success(service_p); 2913 dhcp->ip_assigned_time = timer_current_secs(); 2914 dhcp->ip_conflict_count = 0; 2915 2916 /* stop link local if necessary */ 2917 if (G_dhcp_success_deconfigures_linklocal) { 2918 linklocal_service_change(service_p, LINKLOCAL_NO_ALLOCATE); 2919 } 2920 break; 2921 } 2922 default: 2923 break; 2924 } 2925 return; 2926} 2927 2928static void 2929dhcp_resolve_router_callback(ServiceRef service_p, router_arp_status_t status); 2930 2931 2932static void 2933dhcp_resolve_router_retry(void * arg0, void * arg1, void * arg2) 2934{ 2935 Service_dhcp_t * dhcp; 2936 ServiceRef service_p = (ServiceRef)arg0; 2937 2938 dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 2939 service_resolve_router(service_p, dhcp->arp, 2940 dhcp_resolve_router_callback, 2941 dhcp->saved.our_ip); 2942 return; 2943} 2944 2945 2946static void 2947dhcp_resolve_router_callback(ServiceRef service_p, router_arp_status_t status) 2948{ 2949 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 2950 struct timeval tv; 2951 2952 switch (status) { 2953 case router_arp_status_no_response_e: 2954 /* try again in 60 seconds */ 2955 tv.tv_sec = 60; 2956 tv.tv_usec = 0; 2957 timer_set_relative(dhcp->timer, tv, 2958 (timer_func_t *)dhcp_resolve_router_retry, 2959 service_p, NULL, NULL); 2960 if (dhcp->resolve_router_timed_out) { 2961 break; 2962 } 2963 /* publish what we have so far */ 2964 dhcp->resolve_router_timed_out = TRUE; 2965 dhcp_publish_success(service_p); 2966 if (dhcp->saved.is_dhcp) { 2967 _dhcp_lease_save(service_p, dhcp->lease.start, 2968 (uint8_t *)dhcp->saved.pkt, 2969 dhcp->saved.pkt_size, 2970 TRUE); 2971 } 2972 break; 2973 case router_arp_status_success_e: 2974 if (dhcp->saved.is_dhcp) { 2975 _dhcp_lease_save(service_p, dhcp->lease.start, 2976 (uint8_t *)dhcp->saved.pkt, 2977 dhcp->saved.pkt_size, 2978 dhcp->lease.needs_write); 2979 dhcp->lease.needs_write = FALSE; 2980 } 2981 dhcp_publish_success(service_p); 2982 break; 2983 default: 2984 case router_arp_status_failed_e: 2985 break; 2986 } 2987} 2988 2989static boolean_t 2990should_write_lease(Service_dhcp_t * dhcp, absolute_time_t current_time) 2991{ 2992 if (dhcp->lease.t1 < current_time) { 2993 /* t1 is already in the past */ 2994 return (FALSE); 2995 } 2996 if ((dhcp->lease.t1 - current_time) 2997 > G_dhcp_lease_write_t1_threshold_secs) { 2998 /* if T1 is sufficiently far enough into the future, write the lease */ 2999 return (TRUE); 3000 } 3001 return (FALSE); 3002} 3003 3004static void 3005dhcp_bound(ServiceRef service_p, IFEventID_t event_id, void * event_data) 3006{ 3007 absolute_time_t current_time = timer_current_secs(); 3008 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 3009 boolean_t do_arp = TRUE; 3010 interface_t * if_p = service_interface(service_p); 3011 struct in_addr mask = {0}; 3012 void * option; 3013 struct timeval tv = {0, 0}; 3014 3015 switch (event_id) { 3016 case IFEventID_start_e: { 3017 dhcp_cstate_t prev_state = dhcp->state; 3018 3019 my_log(LOG_DEBUG, "DHCP %s: BOUND", if_name(if_p)); 3020 dhcp->state = dhcp_cstate_bound_e; 3021 dhcp->lease.needs_write = TRUE; 3022 dhcp->disable_arp_collision_detection = TRUE; 3023 3024 /* clean-up anything that might have come before */ 3025 dhcp_cancel_pending_events(service_p); 3026 3027 switch (prev_state) { 3028 case dhcp_cstate_renew_e: 3029 case dhcp_cstate_rebind_e: 3030 dhcp->lease.needs_write 3031 = should_write_lease(dhcp, current_time); 3032 break; 3033 default: 3034 /* make sure autoaddr is disabled */ 3035 service_disable_autoaddr(service_p); 3036 break; 3037 } 3038 3039 /* For renew/rebind and netboot cases, we don't 3040 * need to arp 3041 */ 3042 if (prev_state == dhcp_cstate_rebind_e || 3043 prev_state == dhcp_cstate_renew_e 3044 || ServiceIsNetBoot(service_p)) { 3045 break; 3046 } 3047 3048 /* Here we need to consider 3 prev_states: 3049 * Init, Select and Init-reboot 3050 */ 3051 if (prev_state == dhcp_cstate_select_e) { 3052 /* do an ARP probe of the supplied address */ 3053 arp_client_probe(dhcp->arp, 3054 (arp_result_func_t *)dhcp_bound, service_p, 3055 (void *)IFEventID_arp_e, G_ip_zeroes, 3056 dhcp->saved.our_ip); 3057 return; 3058 3059 } 3060 3061 if (ServiceGetActiveIPAddress(service_p).s_addr 3062 == dhcp->saved.our_ip.s_addr) { 3063 /* no need to probe, we're already using it */ 3064 if (prev_state == dhcp_cstate_init_reboot_e || 3065 prev_state == dhcp_cstate_init_e) { 3066 arp_client_announce(dhcp->arp, 3067 (arp_result_func_t *)dhcp_bound, service_p, 3068 (void *)IFEventID_arp_e, G_ip_zeroes, 3069 dhcp->saved.our_ip, TRUE); 3070 return; 3071 } 3072 } 3073 3074 /* Leave for completeness. */ 3075 break; 3076 } 3077 case IFEventID_arp_e: { 3078 arp_result_t * result = (arp_result_t *)event_data; 3079 3080 if (result->error) { 3081 my_log(LOG_ERR, "DHCP %s: ARP probe failed, %s", 3082 if_name(if_p), 3083 arp_client_errmsg(dhcp->arp)); 3084 dhcp_failed(service_p, ipconfig_status_internal_error_e); 3085 return; 3086 } 3087 if (result->in_use) { 3088 char msg[128]; 3089 struct timeval tv; 3090 3091 snprintf(msg, sizeof(msg), 3092 IP_FORMAT " in use by " EA_FORMAT 3093 ", DHCP Server " 3094 IP_FORMAT, IP_LIST(&dhcp->saved.our_ip), 3095 EA_LIST(result->addr.target_hardware), 3096 IP_LIST(&dhcp->saved.server_ip)); 3097 if (dhcp->conflicting_address.s_addr 3098 != dhcp->saved.our_ip.s_addr) { 3099 /* we got a different address, so allow warning again */ 3100 dhcp->user_warned = FALSE; 3101 } 3102 else if (dhcp->user_warned == FALSE) { 3103 ServiceReportIPv4AddressConflict(service_p, 3104 dhcp->saved.our_ip); 3105 dhcp->user_warned = TRUE; 3106 } 3107 dhcp->conflicting_address = dhcp->saved.our_ip; 3108 my_log(LOG_ERR, "DHCP %s: %s", if_name(if_p), msg); 3109 _dhcp_lease_clear(service_p, FALSE); 3110 dhcp->lease.valid = FALSE; 3111 service_router_clear(service_p); 3112 service_publish_failure(service_p, 3113 ipconfig_status_address_in_use_e); 3114 if (dhcp->saved.is_dhcp) { 3115 dhcp_decline(service_p, IFEventID_start_e, NULL); 3116 return; 3117 } 3118 dhcp_cancel_pending_events(service_p); 3119 (void)service_disable_autoaddr(service_p); 3120 dhcp->saved.our_ip.s_addr = 0; 3121 dhcp->lease.valid = FALSE; 3122 service_router_clear(service_p); 3123 tv.tv_sec = 10; /* retry in a bit */ 3124 tv.tv_usec = 0; 3125 timer_set_relative(dhcp->timer, tv, 3126 (timer_func_t *)dhcp_init, 3127 service_p, (void *)IFEventID_start_e, NULL); 3128 return; 3129 } 3130 dhcp_cancel_pending_events(service_p); 3131 break; 3132 } 3133 default: 3134 return; 3135 } 3136 3137 /* the lease is valid */ 3138 dhcp->lease.valid = TRUE; 3139 3140 /* allow user warning to appear */ 3141 dhcp->conflicting_address.s_addr = 0; 3142 dhcp->user_warned = FALSE; 3143 3144 /* set the interface's address and output the status */ 3145 option = dhcpol_find_with_length(&dhcp->saved.options, 3146 dhcptag_subnet_mask_e, sizeof(mask)); 3147 if (option != NULL) { 3148 mask = *((struct in_addr *)option); 3149 } 3150 3151 /* set our address */ 3152 if ((dhcp->saved.our_ip.s_addr 3153 != ServiceGetActiveIPAddress(service_p).s_addr) 3154 || (mask.s_addr 3155 != ServiceGetActiveSubnetMask(service_p).s_addr)) { 3156 (void)service_set_address(service_p, dhcp->saved.our_ip, 3157 mask, G_ip_zeroes); 3158 dhcp->ip_assigned_time = timer_current_secs(); 3159 dhcp->ip_conflict_count = 0; 3160 } 3161 /* stop link local if necessary */ 3162 if (G_dhcp_success_deconfigures_linklocal) { 3163 linklocal_service_change(service_p, LINKLOCAL_NO_ALLOCATE); 3164 } 3165 3166 /* allow us to be called in the event of a subsequent collision */ 3167 dhcp->disable_arp_collision_detection = FALSE; 3168 3169 if (dhcp->lease.length == DHCP_INFINITE_LEASE) { 3170 /* don't need to talk to server anymore */ 3171 my_log(LOG_DEBUG, "DHCP %s: infinite lease", 3172 if_name(if_p)); 3173 } 3174 else { 3175 if (dhcp->lease.t1 < current_time) { 3176 /* t1 is already in the past, wake up in RENEW momentarily */ 3177 tv.tv_sec = 0; 3178 tv.tv_usec = 1; 3179 do_arp = FALSE; 3180 } 3181 else { 3182 /* wake up in RENEW at t1 */ 3183 tv.tv_sec = dhcp->lease.t1 - current_time; 3184 tv.tv_usec = 0; 3185 } 3186 dhcp->renew_rebind_time = dhcp->lease.t1; 3187 timer_set_relative(dhcp->timer, tv, 3188 (timer_func_t *)dhcp_renew_rebind, 3189 service_p, (void *)IFEventID_start_e, NULL); 3190 } 3191 3192 /* get the router's MAC address */ 3193 dhcp->resolve_router_timed_out = FALSE; 3194 if (do_arp 3195 && service_update_router_address(service_p, &dhcp->saved.options, 3196 dhcp->saved.our_ip) 3197 && service_resolve_router(service_p, dhcp->arp, 3198 dhcp_resolve_router_callback, 3199 dhcp->saved.our_ip)) { 3200 /* resolving router's MAC address started */ 3201 } 3202 else { 3203 if (dhcp->saved.is_dhcp) { 3204 /* save the lease now since we won't ARP for the router */ 3205 _dhcp_lease_save(service_p, dhcp->lease.start, 3206 (uint8_t *)dhcp->saved.pkt, dhcp->saved.pkt_size, 3207 dhcp->lease.needs_write); 3208 dhcp->lease.needs_write = FALSE; 3209 } 3210 dhcp_publish_success(service_p); 3211 } 3212 3213 return; 3214} 3215 3216static void 3217dhcp_no_server(ServiceRef service_p, IFEventID_t event_id, void * event_data) 3218{ 3219 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 3220 struct timeval tv; 3221 3222 switch (event_id) { 3223 case IFEventID_start_e: { 3224 if (G_dhcp_failure_configures_linklocal) { 3225 linklocal_service_change(service_p, LINKLOCAL_ALLOCATE); 3226 } 3227 dhcp_cancel_pending_events(service_p); 3228 service_publish_failure(service_p, ipconfig_status_no_server_e); 3229 3230#define INIT_RETRY_INTERVAL_SECS (1 * 60) 3231 tv.tv_sec = INIT_RETRY_INTERVAL_SECS; 3232 tv.tv_usec = 0; 3233 /* wake up in INIT state after a period of waiting */ 3234 timer_set_relative(dhcp->timer, tv, 3235 (timer_func_t *)dhcp_init, 3236 service_p, (void *)IFEventID_start_e, NULL); 3237 break; 3238 } 3239 default: { 3240 break; 3241 } 3242 } 3243 return; 3244} 3245 3246static void 3247dhcp_decline(ServiceRef service_p, IFEventID_t event_id, void * event_data) 3248{ 3249 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 3250 interface_t * if_p = service_interface(service_p); 3251 ipconfig_status_t status = ipconfig_status_success_e; 3252 struct timeval tv; 3253 3254 switch (event_id) { 3255 case IFEventID_start_e: { 3256 dhcpoa_t options; 3257 3258 my_log(LOG_DEBUG, "DHCP %s: DECLINE", if_name(if_p)); 3259 3260 /* clean-up anything that might have come before */ 3261 dhcp_cancel_pending_events(service_p); 3262 3263 /* decline the address */ 3264 dhcp->state = dhcp_cstate_decline_e; 3265 /* ALIGN: txbuf is uint32_t aligned, cast ok */ 3266 dhcp->request = make_dhcp_request((struct dhcp *)(void *)dhcp->txbuf, 3267 sizeof(dhcp->txbuf), 3268 dhcp_msgtype_decline_e, 3269 if_link_address(if_p), 3270 if_link_arptype(if_p), 3271 if_link_length(if_p), 3272 dhcp->client_id, 3273 dhcp->client_id_len, 3274 FALSE, 3275 &options); 3276 if (dhcp->request == NULL) { 3277 status = ipconfig_status_allocation_failed_e; 3278 goto error; 3279 } 3280 if (dhcpoa_add(&options, dhcptag_requested_ip_address_e, 3281 sizeof(dhcp->saved.our_ip), &dhcp->saved.our_ip) 3282 != dhcpoa_success_e) { 3283 my_log(LOG_ERR, "DHCP %s: DECLINE couldn't add our ip, %s", 3284 if_name(if_p), dhcpoa_err(&options)); 3285 status = ipconfig_status_allocation_failed_e; 3286 goto error; 3287 } 3288 if (dhcpoa_add(&options, dhcptag_server_identifier_e, 3289 sizeof(dhcp->saved.server_ip), &dhcp->saved.server_ip) 3290 != dhcpoa_success_e) { 3291 my_log(LOG_ERR, "DHCP %s: DECLINE couldn't add server ip, %s", 3292 if_name(if_p), dhcpoa_err(&options)); 3293 status = ipconfig_status_allocation_failed_e; 3294 goto error; 3295 } 3296 if (dhcpoa_add(&options, dhcptag_end_e, 0, 0) 3297 != dhcpoa_success_e) { 3298 my_log(LOG_ERR, "DHCP %s: DECLINE failed to terminate options", 3299 if_name(if_p)); 3300 status = ipconfig_status_allocation_failed_e; 3301 goto error; 3302 } 3303 if (bootp_client_transmit(dhcp->client, 3304 G_ip_broadcast, G_ip_zeroes, 3305 G_server_port, G_client_port, 3306 dhcp->request, dhcp->request_size) < 0) { 3307 my_log(LOG_ERR, 3308 "DHCP %s: DECLINE transmit failed", 3309 if_name(if_p)); 3310 } 3311 (void)service_remove_address(service_p); 3312 dhcp->saved.our_ip.s_addr = 0; 3313 dhcp->lease.valid = FALSE; 3314 service_router_clear(service_p); 3315 service_disable_autoaddr(service_p); 3316 tv.tv_sec = 10; /* retry in a bit */ 3317 tv.tv_usec = 0; 3318 timer_set_relative(dhcp->timer, tv, 3319 (timer_func_t *)dhcp_init, 3320 service_p, (void *)IFEventID_start_e, NULL); 3321 break; 3322 } 3323 default: 3324 break; 3325 } 3326 return; 3327 error: 3328 dhcp_failed(service_p, status); 3329 return; 3330} 3331 3332static void 3333dhcp_unbound(ServiceRef service_p, IFEventID_t event_id, void * event_data) 3334{ 3335 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 3336 interface_t * if_p = service_interface(service_p); 3337 struct timeval tv = {0,0}; 3338 3339 switch (event_id) { 3340 case IFEventID_start_e: { 3341 int nak = (int)(intptr_t)event_data; 3342 3343 my_log(LOG_DEBUG, "DHCP %s: UNBOUND%s", if_name(if_p), 3344 nak ? " (NAK)" : ""); 3345 3346 /* clean-up anything that might have come before */ 3347 dhcp_cancel_pending_events(service_p); 3348 dhcp->state = dhcp_cstate_unbound_e; 3349 3350 /* stop using the IP address immediately */ 3351 _dhcp_lease_clear(service_p, nak); 3352 (void)service_remove_address(service_p); 3353 dhcp->saved.our_ip.s_addr = 0; 3354 dhcp->lease.valid = FALSE; 3355 dhcp->got_nak = FALSE; 3356 service_router_clear(service_p); 3357 3358 tv.tv_sec = 0; 3359 tv.tv_usec = 1000; 3360 timer_set_relative(dhcp->timer, tv, 3361 (timer_func_t *)dhcp_init, 3362 service_p, (void *)IFEventID_start_e, NULL); 3363 break; 3364 } 3365 default: 3366 break; 3367 } 3368 return; 3369} 3370 3371static void 3372dhcp_renew_rebind(ServiceRef service_p, IFEventID_t event_id, void * event_data) 3373{ 3374 absolute_time_t current_time = timer_current_secs(); 3375 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 3376 interface_t * if_p = service_interface(service_p); 3377 ipconfig_status_t status = ipconfig_status_success_e; 3378 struct timeval tv; 3379 3380 switch (event_id) { 3381 case IFEventID_start_e: { 3382 dhcp_lease_time_t lease_option; 3383 dhcpoa_t options; 3384 3385 /* clean-up anything that might have come before */ 3386 dhcp_cancel_pending_events(service_p); 3387 3388 dhcp->start_secs = current_time; 3389 3390 dhcp->state = dhcp_cstate_renew_e; 3391 my_log(LOG_DEBUG, "DHCP %s: RENEW/REBIND", if_name(if_p)); 3392 /* ALIGN: txbuf is uint32_t aligned, cast ok */ 3393 dhcp->request = make_dhcp_request((struct dhcp *)(void *)dhcp->txbuf, 3394 sizeof(dhcp->txbuf), 3395 dhcp_msgtype_request_e, 3396 if_link_address(if_p), 3397 if_link_arptype(if_p), 3398 if_link_length(if_p), 3399 dhcp->client_id, 3400 dhcp->client_id_len, 3401 FALSE, 3402 &options); 3403 if (dhcp->request == NULL) { 3404 status = ipconfig_status_allocation_failed_e; 3405 goto error; 3406 } 3407 dhcp->try = 0; 3408 dhcp->request->dp_ciaddr = dhcp->saved.our_ip; 3409 lease_option = htonl(SUGGESTED_LEASE_LENGTH); 3410 if (dhcpoa_add(&options, dhcptag_lease_time_e, sizeof(lease_option), 3411 &lease_option) != dhcpoa_success_e) { 3412 my_log(LOG_ERR, "DHCP %s: RENEW/REBIND couldn't add" 3413 " lease time: %s", if_name(if_p), 3414 dhcpoa_err(&options)); 3415 status = ipconfig_status_allocation_failed_e; 3416 goto error; 3417 } 3418 add_computer_name(&options); 3419 if (dhcpoa_add(&options, dhcptag_end_e, 0, 0) 3420 != dhcpoa_success_e) { 3421 my_log(LOG_ERR, "DHCP %s: RENEW/REBIND failed to terminate options", 3422 if_name(if_p)); 3423 status = ipconfig_status_allocation_failed_e; 3424 goto error; 3425 } 3426 /* enable packet reception */ 3427 bootp_client_enable_receive(dhcp->client, 3428 (bootp_receive_func_t *)dhcp_renew_rebind, 3429 service_p, (void *)IFEventID_data_e); 3430 3431 /* FALL THROUGH */ 3432 } 3433 case IFEventID_timeout_e: { 3434 struct in_addr dest_ip = {0}; 3435 absolute_time_t wakeup_time; 3436 3437 /* 3438 * If we're running as the result of our timer firing (i.e. not 3439 * by the Wake code calling us), check whether the time has changed. 3440 * If it has, assume that our timer fired accurately, and compute the 3441 * difference between current_time and dhcp->renew_rebind_time. 3442 * Assume that the entire delta is due to the time changing, and 3443 * apply the delta to the lease information. 3444 */ 3445 if (timer_still_pending(dhcp->timer) == FALSE 3446 && timer_time_changed(dhcp->timer)) { 3447 dhcp_adjust_lease_info(service_p, 3448 (current_time - dhcp->renew_rebind_time)); 3449 } 3450 3451 if (current_time >= dhcp->lease.expiration) { 3452 /* server did not respond */ 3453 service_publish_failure(service_p, 3454 ipconfig_status_server_not_responding_e); 3455 dhcp_unbound(service_p, IFEventID_start_e, NULL); 3456 return; 3457 } 3458 if (current_time < dhcp->lease.t2) { 3459 dhcp->state = dhcp_cstate_renew_e; 3460 wakeup_time = current_time + (dhcp->lease.t2 - current_time) / 2; 3461 dest_ip = dhcp->saved.server_ip; 3462 } 3463 else { /* rebind */ 3464 dhcp->state = dhcp_cstate_rebind_e; 3465 wakeup_time = current_time 3466 + (dhcp->lease.expiration - current_time) / 2; 3467 dest_ip = G_ip_broadcast; 3468 } 3469 dhcp->request->dp_xid = htonl(++dhcp->xid); 3470 dhcp->request->dp_secs 3471 = htons((uint16_t)(current_time - dhcp->start_secs)); 3472 3473 /* send the packet */ 3474 if (bootp_client_transmit(dhcp->client, 3475 dest_ip, dhcp->saved.our_ip, 3476 G_server_port, G_client_port, 3477 dhcp->request, dhcp->request_size) < 0) { 3478 my_log(LOG_ERR, 3479 "DHCP %s: RENEW/REBIND transmit failed", 3480 if_name(if_p)); 3481 } 3482 /* wait for responses */ 3483#define RENEW_REBIND_MIN_WAIT_SECS 60 3484 if ((wakeup_time - current_time) < RENEW_REBIND_MIN_WAIT_SECS) { 3485 tv.tv_sec = RENEW_REBIND_MIN_WAIT_SECS; 3486 dhcp->renew_rebind_time = current_time + tv.tv_sec; 3487 } 3488 else { 3489 tv.tv_sec = wakeup_time - current_time; 3490 dhcp->renew_rebind_time = wakeup_time; 3491 } 3492 tv.tv_usec = 0; 3493 my_log(LOG_DEBUG, "DHCP %s: RENEW/REBIND waiting at %d for %d.%06d", 3494 if_name(if_p), 3495 current_time - dhcp->start_secs, 3496 tv.tv_sec, tv.tv_usec); 3497 timer_set_relative(dhcp->timer, tv, 3498 (timer_func_t *)dhcp_renew_rebind, 3499 service_p, (void *)IFEventID_timeout_e, NULL); 3500 break; 3501 } 3502 case IFEventID_data_e: { 3503 boolean_t is_dhcp = TRUE; 3504 dhcp_lease_time_t lease = SUGGESTED_LEASE_LENGTH; 3505 bootp_receive_data_t *pkt = (bootp_receive_data_t *)event_data; 3506 dhcp_msgtype_t reply_msgtype = dhcp_msgtype_none_e; 3507 struct in_addr server_ip; 3508 dhcp_lease_time_t t1; 3509 dhcp_lease_time_t t2; 3510 3511 if (verify_packet(pkt, dhcp->xid, if_p, &reply_msgtype, 3512 &server_ip, &is_dhcp) == FALSE 3513 || is_dhcp == FALSE) { 3514 /* reject the packet */ 3515 return; 3516 } 3517 3518 if (reply_msgtype == dhcp_msgtype_nak_e) { 3519 service_publish_failure(service_p, 3520 ipconfig_status_lease_terminated_e); 3521 dhcp_unbound(service_p, IFEventID_start_e, NULL); 3522 return; 3523 } 3524 if (reply_msgtype != dhcp_msgtype_ack_e 3525 || server_ip.s_addr == 0 3526 || ip_valid(pkt->data->dp_yiaddr) == FALSE) { 3527 /* reject the packet */ 3528 return; 3529 } 3530 dhcp_get_lease_from_options(&pkt->options, &lease, &t1, &t2); 3531 3532 /* address has to match, otherwise start over */ 3533 if (pkt->data->dp_yiaddr.s_addr != dhcp->saved.our_ip.s_addr) { 3534 service_publish_failure(service_p, 3535 ipconfig_status_server_error_e); 3536 dhcp_unbound(service_p, IFEventID_start_e, NULL); 3537 return; 3538 } 3539 dhcp_set_lease_params(service_p, "RENEW/REBIND", is_dhcp, 3540 current_time, lease, t1, t2); 3541 dhcpol_free(&dhcp->saved.options); 3542 bcopy(pkt->data, dhcp->saved.pkt, pkt->size); 3543 dhcp->saved.pkt_size = pkt->size; 3544 dhcp->saved.rating = 0; 3545 /* ALIGN: saved.pkt is uint32_t aligned, cast ok */ 3546 (void)dhcpol_parse_packet(&dhcp->saved.options, 3547 (void *)dhcp->saved.pkt, 3548 dhcp->saved.pkt_size, NULL); 3549 dhcp->saved.server_ip = server_ip; 3550 dhcp->saved.is_dhcp = TRUE; 3551 dhcp_bound(service_p, IFEventID_start_e, NULL); 3552 break; 3553 } 3554 default: 3555 return; 3556 } 3557 return; 3558 3559 error: 3560 dhcp_failed(service_p, status); 3561 return; 3562} 3563 3564#include "arp.h" 3565 3566static void 3567dhcp_wait_until_arp_completes(ServiceRef service_p) 3568{ 3569 struct in_addr addr_wait; 3570 Service_dhcp_t * dhcp; 3571 int i; 3572 int if_index; 3573 interface_t * if_p = service_interface(service_p); 3574 route_msg msg; 3575 struct in_addr our_mask; 3576 boolean_t resolved = FALSE; 3577 int s; 3578 struct sockaddr_dl * sdl; 3579 struct sockaddr_inarp * sin; 3580 struct in_addr subnet; 3581 3582 dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 3583 our_mask = ServiceGetActiveSubnetMask(service_p); 3584 subnet.s_addr = dhcp->saved.our_ip.s_addr & our_mask.s_addr; 3585 if (in_subnet(subnet, our_mask, dhcp->saved.server_ip)) { 3586 /* we'll ARP for the DHCP server */ 3587 addr_wait = dhcp->saved.server_ip; 3588 } 3589 else { 3590 struct in_addr * router_p; 3591 3592 router_p = dhcpol_find_with_length(&dhcp->saved.options, 3593 dhcptag_router_e, 3594 sizeof(*router_p)); 3595 if (router_p == NULL 3596 || router_p->s_addr == dhcp->saved.our_ip.s_addr) { 3597 /* all subnet routes are local, so we'll ARP for the DHCP server */ 3598 addr_wait = dhcp->saved.server_ip; 3599 } 3600 else { 3601 /* the router is the gateway to the DHCP server */ 3602 addr_wait = *router_p; 3603 } 3604 } 3605 s = arp_open_routing_socket(); 3606 if (s == -1) { 3607 my_log(LOG_ERR, "DHCP %s: arp_open_routing_socket() failed, %s", 3608 if_name(if_p), 3609 strerror(errno)); 3610 return; 3611 } 3612 /* ALIGN: msg_p->m_space is aligned sufficiently 3613 * to dereference sdl safely */ 3614 sin = (struct sockaddr_inarp *)(void *)msg.m_space; 3615 if_index = if_link_index(if_p); 3616 3617#define N_ARP_GET_TRIES 5 3618 3619 i = 1; 3620 while (TRUE) { 3621 if (arp_get(s, &msg, addr_wait, if_index) != ARP_RETURN_SUCCESS) { 3622 goto failed; 3623 } 3624 /* ALIGN: msg_p->m_space is aligned sufficiently 3625 * to dereference sdl safely */ 3626 sdl = (struct sockaddr_dl *)(void *)(sin->sin_len + (char *)sin); 3627 if (sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { 3628 resolved = TRUE; 3629 break; 3630 } 3631 if (i == N_ARP_GET_TRIES) { 3632 break; 3633 } 3634 i++; 3635 /* sleep for 1 millisecond, and try again */ 3636 usleep(1000); 3637 } 3638 if (G_IPConfiguration_verbose) { 3639 if (resolved == FALSE) { 3640 my_log(LOG_DEBUG, "DHCP %s:" IP_FORMAT " was NOT resolved", 3641 if_name(if_p), IP_LIST(&addr_wait)); 3642 } 3643 else { 3644 my_log(LOG_DEBUG, 3645 "DHCP %s: " IP_FORMAT 3646 " is resolved, %s after trying %d time(s)", 3647 if_name(if_p), IP_LIST(&addr_wait), 3648 link_ntoa(sdl), i); 3649 } 3650 } 3651 failed: 3652 close(s); 3653 return; 3654} 3655 3656static void 3657dhcp_release(ServiceRef service_p) 3658{ 3659 interface_t * if_p = service_interface(service_p); 3660 Service_dhcp_t * dhcp = (Service_dhcp_t *)ServiceGetPrivate(service_p); 3661 link_status_t link_status; 3662 dhcpoa_t options; 3663 3664 if (dhcp->saved.is_dhcp == FALSE || dhcp->lease.valid == FALSE) { 3665 return; 3666 } 3667 3668 my_log(LOG_DEBUG, "DHCP %s: RELEASE", if_name(if_p)); 3669 _dhcp_lease_clear(service_p, FALSE); 3670 dhcp->lease.valid = FALSE; 3671 service_router_clear(service_p); 3672 3673 /* clean-up anything that might have come before */ 3674 dhcp_cancel_pending_events(service_p); 3675 3676 /* don't bother trying to transmit if the link is down */ 3677 link_status = service_link_status(service_p); 3678 if (link_status.valid 3679 && link_status.active == FALSE) { 3680 return; 3681 } 3682 3683 /* release the address */ 3684 /* ALIGN: txbuf is aligned to at least sizeof(uint32_t) bytes */ 3685 dhcp->request = make_dhcp_request((struct dhcp *)(void *)dhcp->txbuf, 3686 sizeof(dhcp->txbuf), 3687 dhcp_msgtype_release_e, 3688 if_link_address(if_p), 3689 if_link_arptype(if_p), 3690 if_link_length(if_p), 3691 dhcp->client_id, dhcp->client_id_len, 3692 FALSE, 3693 &options); 3694 if (dhcp->request == NULL) { 3695 return; 3696 } 3697 dhcp->request->dp_xid = htonl(++dhcp->xid); 3698 dhcp->request->dp_ciaddr = dhcp->saved.our_ip; 3699 if (dhcpoa_add(&options, dhcptag_server_identifier_e, 3700 sizeof(dhcp->saved.server_ip), &dhcp->saved.server_ip) 3701 != dhcpoa_success_e) { 3702 my_log(LOG_ERR, "DHCP %s: RELEASE couldn't add server ip, %s", 3703 if_name(if_p), dhcpoa_err(&options)); 3704 return; 3705 } 3706 if (dhcpoa_add(&options, dhcptag_end_e, 0, 0) 3707 != dhcpoa_success_e) { 3708 my_log(LOG_ERR, "DHCP %s: RELEASE failed to terminate options", 3709 if_name(if_p)); 3710 return; 3711 } 3712 if (bootp_client_transmit(dhcp->client, 3713 dhcp->saved.server_ip, dhcp->saved.our_ip, 3714 G_server_port, G_client_port, 3715 dhcp->request, dhcp->request_size) < 0) { 3716 my_log(LOG_ERR, 3717 "DHCP %s: RELEASE transmit failed", 3718 if_name(if_p)); 3719 return; 3720 } 3721 dhcp_wait_until_arp_completes(service_p); 3722 dhcp->saved.our_ip.s_addr = 0; 3723 return; 3724} 3725 3726#define DEFAULT_LEASE_LENGTH (60 * 60) /* 1 hour */ 3727#define MIN_LEASE_LENGTH (3) /* 3 seconds */ 3728#define MIN_T1_VAL (2) /* 2 seconds */ 3729#define MIN_T2_VAL (2) /* 2 seconds */ 3730 3731void 3732dhcp_get_lease_from_options(dhcpol_t * options, dhcp_lease_time_t * lease, 3733 dhcp_lease_time_t * t1, dhcp_lease_time_t * t2) 3734{ 3735 dhcp_lease_time_t * lease_opt; 3736 dhcp_lease_time_t * t1_opt; 3737 dhcp_lease_time_t * t2_opt; 3738 3739 lease_opt = (dhcp_lease_time_t *) 3740 dhcpol_find_with_length(options, dhcptag_lease_time_e, 3741 sizeof(dhcp_lease_time_t)); 3742 t1_opt = (dhcp_lease_time_t *) 3743 dhcpol_find_with_length(options, dhcptag_renewal_t1_time_value_e, 3744 sizeof(dhcp_lease_time_t)); 3745 t2_opt = (dhcp_lease_time_t *) 3746 dhcpol_find_with_length(options, dhcptag_rebinding_t2_time_value_e, 3747 sizeof(dhcp_lease_time_t)); 3748 if (lease_opt != NULL) { 3749 *lease = ntohl(*lease_opt); 3750 if (*lease < MIN_LEASE_LENGTH) { 3751 *lease = MIN_LEASE_LENGTH; 3752 } 3753 } 3754 if (t1_opt != NULL) { 3755 *t1 = ntohl(*t1_opt); 3756 if (*t1 < MIN_T1_VAL) { 3757 *t1 = MIN_T1_VAL; 3758 } 3759 } 3760 if (t2_opt != NULL) { 3761 *t2 = ntohl(*t2_opt); 3762 if (*t2 < MIN_T2_VAL) { 3763 *t2 = MIN_T2_VAL; 3764 } 3765 } 3766 if (lease_opt == NULL) { 3767 if (t1_opt != NULL) { 3768 *lease = *t1; 3769 } 3770 else if (t2_opt != NULL) { 3771 *lease = *t2; 3772 } 3773 else { 3774 *lease = DEFAULT_LEASE_LENGTH; 3775 } 3776 } 3777 if (*lease == DHCP_INFINITE_LEASE) { 3778 *t1 = *t2 = 0; 3779 } 3780 else if (t1_opt == NULL || *t1 >= *lease 3781 || t2_opt == NULL || *t2 >= *lease 3782 || *t2 < *t1) { 3783 *t1 = (*lease) / 2; 3784 *t2 = (dhcp_lease_time_t) ((double)(*lease) * 0.875); 3785 } 3786 return; 3787} 3788 3789struct in_addr * 3790dhcp_get_router_from_options(dhcpol_t * options_p, struct in_addr our_ip) 3791{ 3792 struct in_addr * router_p; 3793 3794 router_p = dhcpol_find_with_length(options_p, dhcptag_router_e, 3795 sizeof(*router_p)); 3796 if (router_p == NULL) { 3797 goto failed; 3798 } 3799 if (router_p->s_addr == our_ip.s_addr) { 3800 /* proxy arp, use DNS server instead */ 3801 router_p = dhcpol_find_with_length(options_p, 3802 dhcptag_domain_name_server_e, 3803 sizeof(*router_p)); 3804 if (router_p == NULL) { 3805 goto failed; 3806 } 3807 } 3808 if (router_p->s_addr == 0 || router_p->s_addr == 0xffffffff) { 3809 goto failed; 3810 } 3811 return (router_p); 3812 3813 failed: 3814 return (NULL); 3815} 3816 3817