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