1/* 2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25/* 26 * DHCPLease.c 27 * - routines to handle the DHCP in-memory lease list and the lease 28 * stored in the filesystem 29 */ 30 31/* 32 * Modification History 33 * 34 * June 11, 2009 Dieter Siegmund (dieter@apple.com) 35 * - split out from ipconfigd.c 36 */ 37 38#include <CoreFoundation/CFString.h> 39#include <SystemConfiguration/SCValidation.h> 40#include <SystemConfiguration/SCPrivate.h> 41#include "DHCPLease.h" 42#include "util.h" 43#include "host_identifier.h" 44#include "globals.h" 45#include "cfutil.h" 46#include "dhcp_thread.h" 47#include "cfutil.h" 48 49#define DHCPCLIENT_LEASE_FILE_FMT DHCPCLIENT_LEASES_DIR "/%s-%s" 50 51/* required properties: */ 52#define kLeaseStartDate CFSTR("LeaseStartDate") 53#define kPacketData CFSTR("PacketData") 54#define kRouterHardwareAddress CFSTR("RouterHardwareAddress") 55#define kSSID CFSTR("SSID") /* wi-fi only */ 56 57/* informative properties: */ 58#define kLeaseLength CFSTR("LeaseLength") 59#define kIPAddress CFSTR("IPAddress") 60#define kRouterIPAddress CFSTR("RouterIPAddress") 61 62/* 63 * Function: DHCPLeaseCreateWithDictionary 64 * Purpose: 65 * Instantiate a new DHCPLease structure corresponding to the given 66 * dictionary. Validates that required properties are present, 67 * returns NULL if those checks fail. 68 */ 69static DHCPLeaseRef 70DHCPLeaseCreateWithDictionary(CFDictionaryRef dict, bool is_wifi) 71{ 72 CFDataRef hwaddr_data; 73 dhcp_lease_time_t lease_time; 74 DHCPLeaseRef lease_p; 75 CFDataRef pkt_data; 76 CFRange pkt_data_range; 77 struct in_addr * router_p; 78 CFStringRef ssid = NULL; 79 CFDateRef start_date; 80 dhcp_lease_time_t t1_time; 81 dhcp_lease_time_t t2_time; 82 83 /* get the lease start time */ 84 start_date = CFDictionaryGetValue(dict, kLeaseStartDate); 85 if (isA_CFDate(start_date) == NULL) { 86 goto failed; 87 } 88 /* get the packet data */ 89 pkt_data = CFDictionaryGetValue(dict, kPacketData); 90 if (isA_CFData(pkt_data) == NULL) { 91 goto failed; 92 } 93 /* if Wi-Fi, get the SSID */ 94 if (is_wifi) { 95 ssid = CFDictionaryGetValue(dict, kSSID); 96 if (isA_CFString(ssid) == NULL) { 97 goto failed; 98 } 99 } 100 101 pkt_data_range.location = 0; 102 pkt_data_range.length = CFDataGetLength(pkt_data); 103 if (pkt_data_range.length < sizeof(struct dhcp)) { 104 goto failed; 105 } 106 lease_p = (DHCPLeaseRef) 107 malloc(offsetof(DHCPLease, pkt) + pkt_data_range.length); 108 bzero(lease_p, offsetof(DHCPLease, pkt)); 109 110 /* copy the packet data */ 111 CFDataGetBytes(pkt_data, pkt_data_range, lease_p->pkt); 112 lease_p->pkt_length = (int)pkt_data_range.length; 113 114 /* get the lease information and router IP address */ 115 lease_p->lease_start = (absolute_time_t)CFDateGetAbsoluteTime(start_date); 116 { /* parse/retrieve options */ 117 dhcpol_t options; 118 119 (void)dhcpol_parse_packet(&options, (void *)lease_p->pkt, 120 (int)pkt_data_range.length, NULL); 121 dhcp_get_lease_from_options(&options, &lease_time, &t1_time, &t2_time); 122 router_p = dhcp_get_router_from_options(&options, lease_p->our_ip); 123 dhcpol_free(&options); 124 } 125 lease_p->lease_length = lease_time; 126 127 /* get the IP address */ 128 /* ALIGN: lease_p->pkt is aligned, cast ok. */ 129 lease_p->our_ip = ((struct dhcp *)(void *)lease_p->pkt)->dp_yiaddr; 130 131 /* get the router information */ 132 if (router_p != NULL) { 133 CFRange hwaddr_range; 134 135 lease_p->router_ip = *router_p; 136 /* get the router hardware address */ 137 hwaddr_data = CFDictionaryGetValue(dict, kRouterHardwareAddress); 138 hwaddr_range.length = 0; 139 if (isA_CFData(hwaddr_data) != NULL) { 140 hwaddr_range.length = CFDataGetLength(hwaddr_data); 141 } 142 if (hwaddr_range.length > 0) { 143 hwaddr_range.location = 0; 144 if (hwaddr_range.length > sizeof(lease_p->router_hwaddr)) { 145 hwaddr_range.length = sizeof(lease_p->router_hwaddr); 146 } 147 lease_p->router_hwaddr_length = (int)hwaddr_range.length; 148 CFDataGetBytes(hwaddr_data, hwaddr_range, lease_p->router_hwaddr); 149 } 150 } 151 if (ssid != NULL) { 152 CFRetain(ssid); 153 lease_p->ssid = ssid; 154 } 155 return (lease_p); 156 157 failed: 158 return (NULL); 159} 160 161static void 162DHCPLeaseDeallocate(void * arg) 163{ 164 DHCPLeaseRef lease_p = (DHCPLeaseRef)arg; 165 166 if (lease_p->ssid != NULL) { 167 CFRelease(lease_p->ssid); 168 } 169 free(lease_p); 170 return; 171} 172 173void 174DHCPLeaseSetNAK(DHCPLeaseRef lease_p, int nak) 175{ 176 lease_p->nak = nak; 177 return; 178} 179 180/* 181 * Function: DHCPLeaseCreate 182 * Purpose: 183 * Instantiate a new DHCPLease structure corresponding to the given 184 * information. 185 */ 186static DHCPLeaseRef 187DHCPLeaseCreate(struct in_addr our_ip, struct in_addr router_ip, 188 const uint8_t * router_hwaddr, int router_hwaddr_length, 189 absolute_time_t lease_start, 190 dhcp_lease_time_t lease_length, 191 const uint8_t * pkt, int pkt_size, 192 CFStringRef ssid) 193{ 194 DHCPLeaseRef lease_p = NULL; 195 196 lease_p = (DHCPLeaseRef) 197 malloc(offsetof(DHCPLease, pkt) + pkt_size); 198 bzero(lease_p, offsetof(DHCPLease, pkt)); 199 lease_p->our_ip = our_ip; 200 lease_p->router_ip = router_ip; 201 lease_p->lease_start = lease_start; 202 lease_p->lease_length = lease_length; 203 bcopy(pkt, lease_p->pkt, pkt_size); 204 lease_p->pkt_length = pkt_size; 205 if (router_hwaddr != NULL && router_hwaddr_length != 0) { 206 if (router_hwaddr_length > sizeof(lease_p->router_hwaddr)) { 207 router_hwaddr_length = sizeof(lease_p->router_hwaddr); 208 } 209 lease_p->router_hwaddr_length = router_hwaddr_length; 210 bcopy(router_hwaddr, lease_p->router_hwaddr, router_hwaddr_length); 211 } 212 if (ssid != NULL) { 213 CFRetain(ssid); 214 lease_p->ssid = ssid; 215 } 216 return (lease_p); 217} 218 219static CFDictionaryRef 220DHCPLeaseCopyDictionary(DHCPLeaseRef lease_p) 221{ 222 CFDataRef data; 223 CFDateRef date; 224 CFMutableDictionaryRef dict; 225 CFNumberRef num; 226 CFStringRef str; 227 228 dict = CFDictionaryCreateMutable(NULL, 0, 229 &kCFTypeDictionaryKeyCallBacks, 230 &kCFTypeDictionaryValueCallBacks); 231 /* set the IP address */ 232 str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), 233 IP_LIST(&lease_p->our_ip)); 234 CFDictionarySetValue(dict, kIPAddress, str); 235 CFRelease(str); 236 237 /* set the lease start date */ 238 date = CFDateCreate(NULL, lease_p->lease_start); 239 CFDictionarySetValue(dict, kLeaseStartDate, date); 240 CFRelease(date); 241 242 /* set the lease length */ 243 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &lease_p->lease_length); 244 CFDictionarySetValue(dict, kLeaseLength, num); 245 CFRelease(num); 246 247 /* set the SSID */ 248 if (lease_p->ssid != NULL) { 249 CFDictionarySetValue(dict, kSSID, lease_p->ssid); 250 } 251 252 /* set the packet data */ 253 data = CFDataCreateWithBytesNoCopy(NULL, lease_p->pkt, lease_p->pkt_length, 254 kCFAllocatorNull); 255 CFDictionarySetValue(dict, kPacketData, data); 256 CFRelease(data); 257 258 if (lease_p->router_ip.s_addr != 0) { 259 /* set the router IP address */ 260 str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), 261 IP_LIST(&lease_p->router_ip)); 262 CFDictionarySetValue(dict, kRouterIPAddress, str); 263 CFRelease(str); 264 265 if (lease_p->router_hwaddr_length > 0) { 266 /* set the router hardware address */ 267 data = CFDataCreateWithBytesNoCopy(NULL, lease_p->router_hwaddr, 268 lease_p->router_hwaddr_length, 269 kCFAllocatorNull); 270 CFDictionarySetValue(dict, kRouterHardwareAddress, data); 271 CFRelease(data); 272 } 273 } 274 return (dict); 275} 276 277static void 278DHCPLeasePrintToString(CFMutableStringRef str, DHCPLeaseRef lease_p) 279{ 280 STRING_APPEND(str, "IP " IP_FORMAT " Start %d Length", 281 IP_LIST(&lease_p->our_ip), (int)lease_p->lease_start); 282 if (lease_p->lease_length == DHCP_INFINITE_LEASE) { 283 STRING_APPEND(str, " infinite"); 284 } 285 else { 286 STRING_APPEND(str, " %d", (int)lease_p->lease_length); 287 } 288 289 if (lease_p->router_ip.s_addr != 0) { 290 STRING_APPEND(str, " Router IP " IP_FORMAT, 291 IP_LIST(&lease_p->router_ip)); 292 if (lease_p->router_hwaddr_length > 0) { 293 char link_string[MAX_LINK_ADDR_LEN * 3]; 294 295 link_addr_to_string(link_string, sizeof(link_string), 296 lease_p->router_hwaddr, 297 lease_p->router_hwaddr_length); 298 STRING_APPEND(str, " MAC %s", link_string); 299 } 300 } 301 if (lease_p->ssid != NULL) { 302 STRING_APPEND(str, " SSID '%@'", lease_p->ssid); 303 } 304 return; 305} 306 307static void 308DHCPLeaseListLog(DHCPLeaseListRef list_p) 309{ 310 int count; 311 int i; 312 CFMutableStringRef str; 313 314 str = CFStringCreateMutable(NULL, 0); 315 count = dynarray_count(list_p); 316 for (i = 0; i < count; i++) { 317 DHCPLeaseRef lease_p = dynarray_element(list_p, i); 318 319 STRING_APPEND(str, "\n%d. ", i + 1); 320 DHCPLeasePrintToString(str, lease_p); 321 } 322 my_log(~LOG_DEBUG, "DHCPLeaseList has %d element(s)%@", count, str); 323 CFRelease(str); 324 return; 325} 326 327static bool 328DHCPLeaseListGetPath(const char * ifname, 329 uint8_t cid_type, const void * cid, int cid_length, 330 char * filename, int filename_size) 331{ 332 char * idstr; 333 char idstr_scratch[128]; 334 335 idstr = identifierToStringWithBuffer(cid_type, cid, cid_length, 336 idstr_scratch, sizeof(idstr_scratch)); 337 if (idstr == NULL) { 338 return (FALSE); 339 } 340 snprintf(filename, filename_size, DHCPCLIENT_LEASE_FILE_FMT, ifname, 341 idstr); 342 if (idstr != idstr_scratch) { 343 free(idstr); 344 } 345 return (TRUE); 346} 347 348void 349DHCPLeaseListInit(DHCPLeaseListRef list_p) 350{ 351 dynarray_init(list_p, DHCPLeaseDeallocate, NULL); 352 return; 353} 354 355void 356DHCPLeaseListFree(DHCPLeaseListRef list_p) 357{ 358 dynarray_free(list_p); 359} 360 361/* 362 * Function: DHCPLeaseListRemoveStaleLeases 363 * Purpose: 364 * Scans the list of leases removing any that are no longer valid. 365 */ 366static void 367DHCPLeaseListRemoveStaleLeases(DHCPLeaseListRef list_p) 368{ 369 int count; 370 absolute_time_t current_time; 371 int i; 372 373 count = dynarray_count(list_p); 374 if (count == 0) { 375 return; 376 } 377 current_time = timer_current_secs(); 378 i = 0; 379 while (i < count) { 380 DHCPLeaseRef lease_p = dynarray_element(list_p, i); 381 382 /* check the lease expiration */ 383 if (lease_p->lease_length != DHCP_INFINITE_LEASE 384 && current_time >= (lease_p->lease_start + lease_p->lease_length)) { 385 /* lease is expired */ 386 if (G_IPConfiguration_verbose) { 387 my_log(LOG_DEBUG, "Removing Stale Lease " 388 IP_FORMAT " Router " IP_FORMAT, 389 IP_LIST(&lease_p->our_ip), 390 IP_LIST(&lease_p->router_ip)); 391 } 392 dynarray_free_element(list_p, i); 393 count--; 394 } 395 else { 396 i++; 397 } 398 } 399 return; 400} 401 402/* 403 * Function: DHCPLeaseListRead 404 * 405 * Purpose: 406 * Read the single DHCP lease for the given interface/client_id into a 407 * DHCPLeaseList structure. This lease is marked as "tentative" because 408 * we have no idea whether the lease is still good or not, since another 409 * version of the OS (or another OS) could have had additional communication 410 * with the DHCP server, invalidating our notion of the lease. It also 411 * affords a simple, self-cleansing mechanism to clear out the set of 412 * leases we keep track of. 413 */ 414void 415DHCPLeaseListRead(DHCPLeaseListRef list_p, 416 const char * ifname, bool is_wifi, 417 uint8_t cid_type, const void * cid, int cid_length) 418{ 419 char filename[PATH_MAX]; 420 CFDictionaryRef lease_dict = NULL; 421 DHCPLeaseRef lease_p; 422 struct in_addr lease_ip; 423 424 DHCPLeaseListInit(list_p); 425 if (DHCPLeaseListGetPath(ifname, cid_type, cid, cid_length, 426 filename, sizeof(filename)) == FALSE) { 427 goto done; 428 } 429 lease_dict = my_CFPropertyListCreateFromFile(filename); 430 if (isA_CFDictionary(lease_dict) == NULL) { 431 goto done; 432 } 433 lease_p = DHCPLeaseCreateWithDictionary(lease_dict, is_wifi); 434 if (lease_p == NULL) { 435 goto done; 436 } 437 lease_p->tentative = TRUE; 438 dynarray_add(list_p, lease_p); 439 if (G_IPConfiguration_verbose) { 440 DHCPLeaseListLog(list_p); 441 } 442 lease_ip = lease_p->our_ip; 443 DHCPLeaseListRemoveStaleLeases(list_p); 444 if (DHCPLeaseListCount(list_p) == 0) { 445 remove_unused_ip(ifname, lease_ip); 446 } 447 448 done: 449 my_CFRelease(&lease_dict); 450 return; 451} 452 453/* 454 * Function: DHCPLeaseListWrite 455 * 456 * Purpose: 457 * Write the last DHCP lease in the list for the given interface/client_id. 458 * We only save the last (current) lease. See the comments for 459 * DHCPLeaseListRead above for more information. 460 */ 461void 462DHCPLeaseListWrite(DHCPLeaseListRef list_p, 463 const char * ifname, 464 uint8_t cid_type, const void * cid, int cid_length) 465{ 466 int count; 467 char filename[PATH_MAX]; 468 CFDictionaryRef lease_dict; 469 DHCPLeaseRef lease_p; 470 471 if (DHCPLeaseListGetPath(ifname, cid_type, cid, cid_length, 472 filename, sizeof(filename)) == FALSE) { 473 return; 474 } 475 DHCPLeaseListRemoveStaleLeases(list_p); 476 count = dynarray_count(list_p); 477 if (count == 0) { 478 unlink(filename); 479 return; 480 } 481 lease_p = dynarray_element(list_p, count - 1); 482 lease_dict = DHCPLeaseCopyDictionary(lease_p); 483 if (my_CFPropertyListWriteFile(lease_dict, filename, 0644) < 0) { 484 /* 485 * An ENOENT error is expected on a read-only filesystem. All 486 * other errors should be reported. 487 */ 488 if (errno != ENOENT) { 489 my_log(LOG_ERR, "my_CFPropertyListWriteFile(%s) failed, %s", 490 filename, strerror(errno)); 491 } 492 } 493 my_CFRelease(&lease_dict); 494 return; 495} 496 497/* 498 * Function: DHCPLeaseListCopyARPAddressInfo 499 * Purpose: 500 * Returns a list of arp_address_info_t's corresponding to each 501 * discoverable lease. 502 */ 503arp_address_info_t * 504DHCPLeaseListCopyARPAddressInfo(DHCPLeaseListRef list_p, 505 CFStringRef ssid, 506 absolute_time_t * start_time_threshold_p, 507 bool tentative_ok, 508 int * ret_count) 509{ 510 int arp_info_count; 511 arp_address_info_t * arp_info_p; 512 int count; 513 int i; 514 arp_address_info_t * info_p; 515 516 DHCPLeaseListRemoveStaleLeases(list_p); 517 count = dynarray_count(list_p); 518 if (count == 0) { 519 *ret_count = 0; 520 return (NULL); 521 } 522 arp_info_p = (arp_address_info_t *)malloc(sizeof(*arp_info_p) * count); 523 arp_info_count = 0; 524 info_p = arp_info_p; 525 for (i = 0; i < count; i++) { 526 DHCPLeaseRef lease_p = dynarray_element(list_p, i); 527 528 if (ssid != NULL) { 529 if (lease_p->ssid == NULL || !CFEqual(lease_p->ssid, ssid)) { 530 if (G_IPConfiguration_verbose) { 531 my_log(LOG_DEBUG, 532 "ignoring lease with SSID %@", 533 lease_p->ssid); 534 continue; 535 } 536 } 537 538 } 539 if (lease_p->router_ip.s_addr == 0 540 || lease_p->router_hwaddr_length == 0) { 541 /* can't use this with ARP discovery */ 542 if (G_IPConfiguration_verbose) { 543 my_log(LOG_DEBUG, "ignoring lease for " IP_FORMAT, 544 IP_LIST(&lease_p->our_ip)); 545 } 546 continue; 547 } 548 if (lease_p->tentative && tentative_ok == FALSE) { 549 /* ignore tentative lease */ 550 continue; 551 } 552 if (start_time_threshold_p != NULL 553 && lease_p->lease_start < *start_time_threshold_p) { 554 if (G_IPConfiguration_verbose) { 555 my_log(LOG_DEBUG, 556 "start time on lease " IP_FORMAT " too old (%ld < %ld)", 557 IP_LIST(&lease_p->our_ip), 558 lease_p->lease_start, *start_time_threshold_p); 559 } 560 continue; 561 } 562 info_p->sender_ip = lease_p->our_ip; 563 info_p->target_ip = lease_p->router_ip; 564 bcopy(lease_p->router_hwaddr, info_p->target_hardware, 565 lease_p->router_hwaddr_length); 566 arp_info_count++; 567 info_p++; 568 } 569 if (arp_info_count == 0) { 570 free(arp_info_p); 571 arp_info_p = NULL; 572 } 573 *ret_count = arp_info_count; 574 return (arp_info_p); 575} 576 577/* 578 * Function: DHCPLeaseListFindLease 579 * Purpose: 580 * Find a lease corresponding to the supplied information. 581 */ 582int 583DHCPLeaseListFindLease(DHCPLeaseListRef list_p, struct in_addr our_ip, 584 struct in_addr router_ip, 585 const uint8_t * router_hwaddr, int router_hwaddr_length) 586{ 587 int count; 588 int i; 589 bool private_ip = ip_is_private(our_ip); 590 591 count = dynarray_count(list_p); 592 for (i = 0; i < count; i++) { 593 DHCPLeaseRef lease_p = dynarray_element(list_p, i); 594 595 if (lease_p->our_ip.s_addr != our_ip.s_addr) { 596 /* IP doesn't match */ 597 continue; 598 } 599 if (private_ip == FALSE) { 600 /* lease for public IP is unique */ 601 return (i); 602 } 603 if (lease_p->router_ip.s_addr != router_ip.s_addr) { 604 /* router IP doesn't match (or one is set the other isn't)*/ 605 continue; 606 } 607 if (router_ip.s_addr == 0) { 608 /* found lease with no router information */ 609 return (i); 610 } 611 if (lease_p->router_hwaddr_length != router_hwaddr_length) { 612 /* one has router hwaddr, other doesn't */ 613 continue; 614 } 615 if (router_hwaddr == NULL || router_hwaddr_length == 0) { 616 /* found lease with router IP but no router hwaddr */ 617 return (i); 618 } 619 if (bcmp(lease_p->router_hwaddr, router_hwaddr, router_hwaddr_length) 620 == 0) { 621 /* exact match on IP, router IP, router hwaddr */ 622 return (i); 623 } 624 } 625 return (-1); 626} 627 628/* 629 * Function: DHCPLeaseShouldBeRemoved 630 * Purpose: 631 * Given an existing lease entry 'existing_p' and the one to be added 'new_p', 632 * determine whether the existing lease entry should be removed. 633 * 634 * The criteria for removing the lease entry: 635 * 1) No router information is specified. This entry is useless for lease 636 * detection. If such a lease exists, it only makes sense to have 637 * one of them, the most recently used lease. It will be added to the 638 * end of the list in that case. 639 * 2) Lease was NAK'd. The DHCP server NAK'd this lease and it's for the 640 * same network i.e. same router MAC. 641 * 3) Lease is for a public IP and is the same as the new lease. 642 * 4) Lease has the same router IP/MAC address as an existing lease. We 643 * can only sensibly have a single lease for a particular network, so 644 * eliminate redundant ones. 645 */ 646static boolean_t 647DHCPLeaseShouldBeRemoved(DHCPLeaseRef existing_p, DHCPLeaseRef new_p, 648 boolean_t private_ip) 649{ 650 if (existing_p->router_ip.s_addr == 0 651 || existing_p->router_hwaddr_length == 0) { 652 if (G_IPConfiguration_verbose) { 653 my_log(LOG_DEBUG, 654 "Removing lease with no router for IP address " 655 IP_FORMAT, IP_LIST(&existing_p->our_ip)); 656 } 657 return (TRUE); 658 } 659 if (existing_p->nak) { 660 boolean_t ignore = FALSE; 661 662 existing_p->nak = FALSE; 663 if (ip_is_private(existing_p->our_ip) != private_ip) { 664 /* one IP is private, the other is public, ignore NAK */ 665 ignore = TRUE; 666 } 667 else if (new_p->router_hwaddr_length != 0 668 && bcmp(existing_p->router_hwaddr, new_p->router_hwaddr, 669 existing_p->router_hwaddr_length) != 0) { 670 /* router MAC on NAK'd lease is different, so ignore NAK */ 671 ignore = TRUE; 672 } 673 if (ignore) { 674 if (G_IPConfiguration_verbose) { 675 my_log(LOG_DEBUG, "Ignoring NAK on IP address " 676 IP_FORMAT, IP_LIST(&existing_p->our_ip)); 677 } 678 } 679 else { 680 if (G_IPConfiguration_verbose) { 681 my_log(LOG_DEBUG, "Removing NAK'd lease for IP address " 682 IP_FORMAT, IP_LIST(&existing_p->our_ip)); 683 } 684 return (TRUE); 685 } 686 } 687 if (private_ip == FALSE 688 && new_p->our_ip.s_addr == existing_p->our_ip.s_addr) { 689 /* public IP's are the same, remove it */ 690 if (G_IPConfiguration_verbose) { 691 my_log(LOG_DEBUG, "Removing lease for public IP address " 692 IP_FORMAT, IP_LIST(&existing_p->our_ip)); 693 } 694 return (TRUE); 695 } 696 if (new_p->router_ip.s_addr == 0 697 || new_p->router_hwaddr_length == 0) { 698 /* new lease doesn't have a router */ 699 return (FALSE); 700 } 701 if (bcmp(new_p->router_hwaddr, existing_p->router_hwaddr, 702 new_p->router_hwaddr_length) == 0) { 703 if (G_IPConfiguration_verbose) { 704 if (new_p->our_ip.s_addr == existing_p->our_ip.s_addr) { 705 my_log(LOG_DEBUG, 706 "Removing lease with same router for IP address " 707 IP_FORMAT, IP_LIST(&existing_p->our_ip)); 708 } 709 else { 710 my_log(LOG_DEBUG, 711 "Removing lease with same router, old IP " 712 IP_FORMAT " new IP " IP_FORMAT, 713 IP_LIST(&existing_p->our_ip), 714 IP_LIST(&new_p->our_ip)); 715 } 716 } 717 return (TRUE); 718 } 719 return (FALSE); 720} 721 722/* 723 * Function: DHCPLeaseListUpdateLease 724 * 725 * Purpose: 726 * Update the lease entry for the given lease in the in-memory lease database. 727 */ 728void 729DHCPLeaseListUpdateLease(DHCPLeaseListRef list_p, struct in_addr our_ip, 730 struct in_addr router_ip, 731 const uint8_t * router_hwaddr, 732 int router_hwaddr_length, 733 absolute_time_t lease_start, 734 dhcp_lease_time_t lease_length, 735 const uint8_t * pkt, int pkt_size, 736 CFStringRef ssid) 737{ 738 int count; 739 int i; 740 DHCPLeaseRef lease_p; 741 boolean_t private_ip = ip_is_private(our_ip); 742 743 lease_p = DHCPLeaseCreate(our_ip, router_ip, 744 router_hwaddr, router_hwaddr_length, 745 lease_start, lease_length, pkt, pkt_size, 746 ssid); 747 /* scan lease list to eliminate NAK'd, incomplete, and duplicate leases */ 748 count = dynarray_count(list_p); 749 for (i = 0; i < count; i++) { 750 DHCPLeaseRef scan_p = dynarray_element(list_p, i); 751 752 if (DHCPLeaseShouldBeRemoved(scan_p, lease_p, private_ip)) { 753 dynarray_free_element(list_p, i); 754 i--; 755 count--; 756 } 757 } 758 dynarray_add(list_p, lease_p); 759 if (G_IPConfiguration_verbose) { 760 my_log(LOG_DEBUG, "Saved lease for " IP_FORMAT, 761 IP_LIST(&lease_p->our_ip)); 762 if (G_IPConfiguration_verbose) { 763 DHCPLeaseListLog(list_p); 764 } 765 } 766 return; 767} 768 769/* 770 * Function: DHCPLeaseListRemoveLease 771 * 772 * Purpose: 773 * Remove the lease entry for the given lease. 774 */ 775void 776DHCPLeaseListRemoveLease(DHCPLeaseListRef list_p, 777 struct in_addr our_ip, 778 struct in_addr router_ip, 779 const uint8_t * router_hwaddr, 780 int router_hwaddr_length) 781{ 782 int where; 783 784 /* remove the old information if it's there */ 785 where = DHCPLeaseListFindLease(list_p, our_ip, router_ip, 786 router_hwaddr, router_hwaddr_length); 787 if (where != -1) { 788 if (G_IPConfiguration_verbose) { 789 DHCPLeaseRef lease_p = DHCPLeaseListElement(list_p, where); 790 791 my_log(LOG_DEBUG, "Removing lease for " IP_FORMAT, 792 IP_LIST(&lease_p->our_ip)); 793 } 794 dynarray_free_element(list_p, where); 795 } 796 return; 797} 798 799/* 800 * Function: DHCPLeaseListRemoveAllButLastLease 801 * Purpose: 802 * Remove all leases except the last one (the most recently used one), 803 * and mark it tentative. 804 */ 805void 806DHCPLeaseListRemoveAllButLastLease(DHCPLeaseListRef list_p) 807{ 808 int count; 809 int i; 810 DHCPLeaseRef lease_p; 811 812 count = DHCPLeaseListCount(list_p); 813 if (count == 0) { 814 return; 815 } 816 for (i = 0; i < (count - 1); i++) { 817 if (G_IPConfiguration_verbose) { 818 lease_p = DHCPLeaseListElement(list_p, 0); 819 my_log(LOG_DEBUG, "Removing lease #%d for IP address " 820 IP_FORMAT, i + 1, IP_LIST(&lease_p->our_ip)); 821 } 822 dynarray_free_element(list_p, 0); 823 } 824 lease_p = DHCPLeaseListElement(list_p, 0); 825 lease_p->tentative = TRUE; 826 return; 827} 828 829