1/* 2 * Copyright (c) 2000-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/* 25 * arp_session.c 26 */ 27/* 28 * Modification History 29 * 30 * May 11, 2000 Dieter Siegmund (dieter@apple.com) 31 * - created 32 * 33 * March 21, 2001 Dieter Siegmund (dieter@apple.com) 34 * - process multiple ARP responses from one bpf read instead of 35 * assuming there's just one response per read 36 * 37 * June 16, 2003 Dieter Siegmund (dieter@apple.com) 38 * - added support for firewire 39 * 40 * December 22, 2003 Dieter Siegmund (dieter@apple.com) 41 * - handle multiple arp client probe requests over multiple 42 * interfaces concurrently 43 */ 44 45#include <stdlib.h> 46#include <unistd.h> 47#include <string.h> 48#include <stdio.h> 49#include <sys/types.h> 50#include <sys/wait.h> 51#include <sys/errno.h> 52#include <sys/socket.h> 53#include <sys/ioctl.h> 54#include <sys/time.h> 55#include <sys/sockio.h> 56#include <net/if.h> 57#include <net/ethernet.h> 58#include <netinet/in.h> 59#include <netinet/udp.h> 60#include <netinet/in_systm.h> 61#include <netinet/ip.h> 62#include <net/if_arp.h> 63#include <net/firewire.h> 64#include <netinet/if_ether.h> 65#include <arpa/inet.h> 66#include <net/if_types.h> 67#include <net/bpf.h> 68#include <CoreFoundation/CFRunLoop.h> 69 70#include "util.h" 71#include <syslog.h> 72#include "bpflib.h" 73#include "util.h" 74#include "dynarray.h" 75#include "timer.h" 76#include "FDSet.h" 77#include "ipconfigd_globals.h" 78#include "arp_session.h" 79#include "ioregpath.h" 80#include "ipconfigd_threads.h" 81#include "symbol_scope.h" 82 83struct firewire_arp { 84 struct arphdr fw_hdr; /* fixed-size header */ 85 uint8_t arp_sha[FIREWIRE_ADDR_LEN]; 86 uint8_t arp_spa[4]; 87 uint8_t arp_tpa[4]; 88}; 89 90struct probe_info { 91 struct timeval retry_interval; 92 int probe_count; 93 int gratuitous_count; 94 boolean_t skip_first; 95}; 96 97struct arp_session { 98 int debug; 99 struct probe_info default_probe_info; 100 int default_detect_count; 101 struct timeval default_detect_retry; 102 int default_conflict_retry_count; 103 struct timeval default_conflict_delay; 104 struct timeval default_resolve_retry; 105 arp_our_address_func_t * is_our_address; 106 dynarray_t if_sessions; 107#ifdef TEST_ARP_SESSION 108 int next_client_index; 109#endif /* TEST_ARP_SESSION */ 110}; 111 112struct arp_if_session { 113 arp_session_t * session; 114 interface_t * if_p; 115 dynarray_t clients; 116 char * receive_buf; 117 int receive_bufsize; 118 FDCalloutRef read_fd; 119 int read_fd_refcount; 120 struct firewire_address fw_addr; 121}; 122 123typedef struct arp_if_session arp_if_session_t; 124 125typedef enum { 126 arp_client_command_none_e = 0, 127 arp_client_command_probe_e = 1, 128 arp_client_command_resolve_e = 2, 129 arp_client_command_detect_e = 3 130} arp_client_command_t; 131 132typedef enum { 133 arp_status_none_e = 0, 134 arp_status_not_in_use_e = 1, 135 arp_status_in_use_e = 2, 136 arp_status_error_e = 3, 137 arp_status_unknown_e = 4, 138} arp_status_t; 139 140struct arp_client { 141#ifdef TEST_ARP_SESSION 142 int client_index; /* unique ID */ 143#endif /* TEST_ARP_SESSION */ 144 arp_client_command_t command; 145 arp_status_t command_status; 146 boolean_t fd_open; 147 arp_if_session_t * if_session; 148 arp_result_func_t * func; 149 void * arg1; 150 void * arg2; 151 struct in_addr sender_ip; 152 struct in_addr target_ip; 153 int try; 154 int conflict_count; 155 timer_callout_t * timer_callout; 156 arp_address_info_t in_use_addr; 157 char errmsg[128]; 158 struct probe_info probe_info; 159 boolean_t probes_are_collisions; 160 uint32_t resolve_secs; 161 arp_address_info_t * detect_list; 162 int detect_list_count; 163 CFRunLoopObserverRef callback_rls; 164}; 165 166#ifdef TEST_ARP_SESSION 167#define my_log arp_session_log 168static void arp_session_log(int priority, const char * message, ...); 169#define G_IPConfiguration_verbose TRUE 170#endif /* TEST_ARP_SESSION */ 171 172#include <CoreFoundation/CFDictionary.h> 173#include <CoreFoundation/CFRunLoop.h> 174#include <SystemConfiguration/SCValidation.h> 175 176#define ARP_STR "ARP " 177 178static Boolean 179getFireWireAddress(const char * ifname, struct firewire_address * addr_p) 180{ 181 CFDictionaryRef dict = NULL; 182 CFDataRef data; 183 Boolean found = FALSE; 184 185 dict = myIORegistryEntryBSDNameMatchingCopyValue(ifname, TRUE); 186 if (dict == NULL) { 187 return (FALSE); 188 } 189 data = CFDictionaryGetValue(dict, CFSTR("IOFWHWAddr")); 190 if (isA_CFData(data) == NULL || CFDataGetLength(data) != sizeof(*addr_p)) { 191 goto done; 192 } 193 CFDataGetBytes(data, CFRangeMake(0, sizeof(*addr_p)), (void *)addr_p); 194 195 /* put it in network byte order */ 196 addr_p->unicastFifoHi = htons(addr_p->unicastFifoHi); 197 addr_p->unicastFifoLo = htonl(addr_p->unicastFifoLo); 198 found = TRUE; 199 200 done: 201 if (dict != NULL) { 202 CFRelease(dict); 203 } 204 return (found); 205} 206 207/* forward-declarations: */ 208 209static arp_if_session_t * 210arp_session_new_if_session(arp_session_t * session, interface_t * if_p); 211 212static void 213arp_client_free_element(void * arg); 214 215static void 216arp_client_probe_retransmit(void * arg1, void * arg2, void * arg3); 217 218static void 219arp_client_probe_start(void * arg1, void * arg2, void * arg3); 220 221static void 222arp_client_resolve_retransmit(void * arg1, void * arg2, void * arg3); 223 224static boolean_t 225arp_client_open_fd(arp_client_t * client); 226 227static void 228arp_client_close_fd(arp_client_t * client); 229 230static void 231arp_if_session_free(arp_if_session_t * * if_session_p); 232 233static void 234arp_if_session_free_element(void * arg); 235 236static void 237arp_if_session_read(void * arg1, void * arg2); 238 239static boolean_t 240arp_is_our_address(interface_t * if_p, int hwtype, void * hwaddr, int hwlen); 241 242static __inline__ char * 243arpop_name(u_int16_t op) 244{ 245 switch (op) { 246 case ARPOP_REQUEST: 247 return "ARP REQUEST"; 248 case ARPOP_REPLY: 249 return "ARP REPLY"; 250 case ARPOP_REVREQUEST: 251 return "REVARP REQUEST"; 252 case ARPOP_REVREPLY: 253 return "REVARP REPLY"; 254 default: 255 break; 256 } 257 return ("<unknown>"); 258} 259 260/* NOTE: caller should make sure arp_p pointed structure 261 * be at least 4 byte aligned */ 262static void 263dump_arp(struct arphdr * arp_p) 264 265{ 266 int arphrd = ntohs(arp_p->ar_hrd); 267 268 printf("\n"); 269 printf("%s type=0x%x proto=0x%x\n", arpop_name(ntohs(arp_p->ar_op)), 270 arphrd, ntohs(arp_p->ar_pro)); 271 272 switch (arphrd) { 273 case ARPHRD_ETHER: 274 { 275 /* ALIGN: alignment not assumed, using bcopy */ 276 struct ether_arp * earp = (struct ether_arp *)(void *)arp_p; 277 struct in_addr iaddr; 278 279 if (arp_p->ar_hln == sizeof(earp->arp_sha)) { 280 struct ether_addr eaddr; 281 282 bcopy(earp->arp_sha, &eaddr, sizeof(eaddr)); 283 printf("Sender H/W\t%s\n", 284 ether_ntoa((const struct ether_addr *)&eaddr)); 285 286 bcopy(earp->arp_tha, &eaddr, sizeof(eaddr)); 287 printf("Target H/W\t%s\n", 288 ether_ntoa((const struct ether_addr *)&eaddr)); 289 } 290 bcopy(earp->arp_spa, &iaddr, sizeof(iaddr)); 291 printf("Sender IP\t%s\n", 292 inet_ntoa(iaddr)); 293 294 bcopy(earp->arp_tpa, &iaddr, sizeof(iaddr)); 295 printf("Target IP\t%s\n", 296 inet_ntoa(iaddr)); 297 } 298 break; 299 case ARPHRD_IEEE1394: 300 { 301 /* ALIGN: arp_p is aligned, cast ok. */ 302 struct firewire_arp * farp = (struct firewire_arp *)(void *)arp_p; 303 304 if (arp_p->ar_hln == sizeof(farp->arp_sha)) { 305 printf("Sender H/W\t" FWA_FORMAT "\n", 306 FWA_LIST(farp->arp_sha)); 307 } 308 /* ALIGN: arp_p is aligned, cast ok. */ 309 printf("Sender IP\t%s\n", 310 inet_ntoa(*((struct in_addr *)(void *)farp->arp_spa))); 311 /* ALIGN: arp_p is aligned, cast ok. */ 312 printf("Target IP\t%s\n", 313 inet_ntoa(*((struct in_addr *)(void *)farp->arp_tpa))); 314 } 315 break; 316 } 317 fflush(stdout); 318 return; 319} 320 321static void 322arp_client_close_fd(arp_client_t * client) 323{ 324 arp_if_session_t * if_session = client->if_session; 325 326 if (client->fd_open == FALSE) { 327 return; 328 } 329 if (if_session->read_fd_refcount <= 0) { 330 my_log(LOG_ERR, "arp_client_close_fd(%s): bpf open fd count is %d", 331 if_name(if_session->if_p), if_session->read_fd_refcount); 332 return; 333 } 334 if_session->read_fd_refcount--; 335 my_log(LOG_DEBUG, "arp_client_close_fd(%s): bpf open fd count is %d", 336 if_name(if_session->if_p), if_session->read_fd_refcount); 337 client->fd_open = FALSE; 338 if (if_session->read_fd_refcount == 0) { 339 if (if_session->read_fd != NULL) { 340 my_log(LOG_DEBUG, "arp_client_close_fd(%s): closing bpf fd %d", 341 if_name(if_session->if_p), 342 FDCalloutGetFD(if_session->read_fd)); 343 /* this closes the file descriptor */ 344 FDCalloutRelease(&if_session->read_fd); 345 } 346 if (if_session->receive_buf != NULL) { 347 free(if_session->receive_buf); 348 if_session->receive_buf = NULL; 349 } 350 } 351 return; 352} 353 354/* 355 * Function: arp_client_is_active 356 * Purpose: 357 * Returns whether the arp_client is active. 358 */ 359PRIVATE_EXTERN boolean_t 360arp_client_is_active(arp_client_t * client) 361{ 362 return (client->func != NULL); 363} 364 365/* 366 * Function: arp_client_cancel_callback 367 * Purpose: 368 * Invalidate/release the callback function. 369 */ 370static void 371arp_client_cancel_callback(arp_client_t * client) 372{ 373 if (client->callback_rls != NULL) { 374 CFRunLoopObserverInvalidate(client->callback_rls); 375 CFRelease(client->callback_rls); 376 client->callback_rls = NULL; 377 } 378 return; 379} 380 381/* 382 * Function: arp_client_callback 383 * 384 * Purpose: 385 * Call the supplied function with the appropriate result. 386 */ 387static void 388arp_client_callback(arp_client_t * client) 389{ 390 void * c_arg1; 391 void * c_arg2; 392 arp_result_func_t * func; 393 arp_result_t result; 394 395 /* remember the client parameters, then clear them */ 396 c_arg1 = client->arg1; 397 c_arg2 = client->arg2; 398 func = client->func; 399 client->func = client->arg1 = client->arg2 = NULL; 400 401 arp_client_close_fd(client); 402 timer_cancel(client->timer_callout); 403 404 /* return the results */ 405 bzero(&result, sizeof(result)); 406 switch (client->command_status) { 407 default: 408 case arp_status_none_e: 409 /* not possible */ 410 printf("No result for %s?\n", 411 if_name(client->if_session->if_p)); 412 break; 413 case arp_status_error_e: 414 result.error = TRUE; 415 break; 416 case arp_status_not_in_use_e: 417 break; 418 case arp_status_in_use_e: 419 result.in_use = TRUE; 420 result.addr = client->in_use_addr; 421 break; 422 } 423 424 /* return the results to the client */ 425 result.client = client; 426 (*func)(c_arg1, c_arg2, &result); 427 return; 428} 429 430/* 431 * Function: arp_client_do_callback 432 * Purpose: 433 * Invalidate the runloop observer then invoke arp_client_callback(). 434 */ 435static void 436arp_client_do_callback(CFRunLoopObserverRef observer, 437 CFRunLoopActivity activity, 438 void * info) 439{ 440 arp_client_t * client = (arp_client_t *)info; 441 442 /* de-activate the observer */ 443 arp_client_cancel_callback(client); 444 arp_client_callback(client); 445 return; 446} 447 448/* 449 * Function: arp_client_schedule_callback 450 * Purpose: 451 * Call the arp_client_callback via a runloop observer. 452 */ 453static void 454arp_client_schedule_callback(arp_client_t * client) 455{ 456 CFRunLoopObserverContext context = { 0, client, NULL, NULL, NULL }; 457 458 arp_client_cancel_callback(client); 459 client->callback_rls 460 = CFRunLoopObserverCreate(NULL, kCFRunLoopAllActivities, 461 TRUE, 0, arp_client_do_callback, &context); 462 463 CFRunLoopAddObserver(CFRunLoopGetCurrent(), client->callback_rls, 464 kCFRunLoopDefaultMode); 465 return; 466} 467 468/* 469 * Function: arp_is_our_address 470 * 471 * Purpose: 472 * Returns whether the given hardware address matches the given 473 * network interface. 474 */ 475static boolean_t 476arp_is_our_address(interface_t * if_p, int hwtype, void * hwaddr, int hwlen) 477{ 478 int link_length = if_link_length(if_p); 479 480 if (hwlen != link_length || hwtype != if_link_arptype(if_p)) { 481 return (FALSE); 482 } 483 if (bcmp(hwaddr, if_link_address(if_p), link_length) == 0) { 484 return (TRUE); 485 } 486 return (FALSE); 487} 488 489static void 490arp_if_session_update_hardware_address(arp_if_session_t * if_session) 491{ 492 if (if_link_type(if_session->if_p) != IFT_IEEE1394) { 493 return; 494 } 495 /* copy in the latest firewire address */ 496 if (getFireWireAddress(if_name(if_session->if_p), 497 &if_session->fw_addr) == FALSE) { 498 my_log(LOG_ERR, 499 "arp_if_session_update_hardware_address(%s):" 500 "could not retrieve firewire address", 501 if_name(if_session->if_p)); 502 } 503 return; 504} 505 506/* 507 * Function: arp_if_session_read 508 * Purpose: 509 * Called when data is available on the bpf fd. 510 * Check the arp packet, and see if it matches 511 * any of the clients' probe criteria. If it does, 512 * call the client with an in_use result structure. 513 */ 514static void 515arp_if_session_read(void * arg1, void * arg2) 516{ 517 arp_client_t * client; 518 int client_count; 519 boolean_t debug; 520 char errmsg[128]; 521 int hwlen = 0; 522 int hwtype; 523 int i; 524 arp_if_session_t * if_session; 525 int link_header_size; 526 int link_arp_size; 527 int link_length; 528 ssize_t n; 529 char * offset; 530 arp_session_t * session; 531 532 if_session = (arp_if_session_t *)arg1; 533 session = if_session->session; 534 535 errmsg[0] = '\0'; 536 537 if (if_session->read_fd_refcount == 0) { 538 my_log(LOG_ERR, "arp_if_session_read: no pending clients?"); 539 return; 540 } 541 542 debug = session->debug; 543 client_count = dynarray_count(&if_session->clients); 544 545 link_length = if_link_length(if_session->if_p); 546 hwtype = if_link_arptype(if_session->if_p); 547 switch (hwtype) { 548 default: 549 /* default clause will never match */ 550 case ARPHRD_ETHER: 551 link_header_size = sizeof(struct ether_header); 552 link_arp_size = sizeof(struct ether_arp); 553 hwlen = ETHER_ADDR_LEN; 554 break; 555 case ARPHRD_IEEE1394: 556 link_header_size = sizeof(struct firewire_header); 557 link_arp_size = sizeof(struct firewire_arp); 558 hwlen = FIREWIRE_ADDR_LEN; 559 break; 560 } 561 n = read(FDCalloutGetFD(if_session->read_fd), if_session->receive_buf, 562 if_session->receive_bufsize); 563 if (n < 0) { 564 if (errno == EAGAIN) { 565 return; 566 } 567 my_log(LOG_ERR, "arp_if_session_read: read(%s) failed, %s (%d)", 568 if_name(if_session->if_p), strerror(errno), errno); 569 snprintf(errmsg, sizeof(errmsg), 570 "arp_if_session_read: read(%s) failed, %s (%d)", 571 if_name(if_session->if_p), strerror(errno), errno); 572 goto failed; 573 } 574 for (offset = if_session->receive_buf; n > 0; ) { 575 struct arphdr * arp_p; 576 struct bpf_hdr * bpf = (struct bpf_hdr *)(void *)offset; 577 void * hwaddr; 578 boolean_t is_our_address; 579 short op; 580 char * pkt_start; 581 struct in_addr source_ip_aligned; 582 struct in_addr * source_ip_p; 583 struct in_addr target_ip_aligned; 584 struct in_addr * target_ip_p; 585 int skip; 586 587 /* ALIGN: offset is aligned to sizeof(int) bytes */ 588 pkt_start = offset + bpf->bh_hdrlen; 589 arp_p = (struct arphdr *)(void *)(pkt_start + link_header_size); 590 if (debug) { 591 dump_arp(arp_p); 592 } 593 op = ntohs(arp_p->ar_op); 594 if (bpf->bh_caplen < (link_header_size + link_arp_size) 595 || arp_p->ar_hln != hwlen 596 || (op != ARPOP_REPLY && op != ARPOP_REQUEST) 597 || ntohs(arp_p->ar_hrd) != hwtype 598 || ntohs(arp_p->ar_pro) != ETHERTYPE_IP) { 599 goto next_packet; 600 } 601 switch (hwtype) { 602 default: 603 case ARPHRD_ETHER: 604 { 605 struct ether_arp * earp; 606 607 earp = (struct ether_arp *)arp_p; 608 609 /* ALIGN: don't assume fields in earp are aligned */ 610 source_ip_p = &source_ip_aligned; 611 target_ip_p = &target_ip_aligned; 612 bcopy(earp->arp_spa, source_ip_p, sizeof(struct in_addr)); 613 bcopy(earp->arp_tpa, target_ip_p, sizeof(struct in_addr)); 614 hwaddr = earp->arp_sha; 615 } 616 break; 617 case ARPHRD_IEEE1394: 618 { 619 struct firewire_arp * farp; 620 621 farp = (struct firewire_arp *)arp_p; 622 /* ALIGN: arp_p aligned, cast ok. */ 623 source_ip_p = (struct in_addr *)(void *)farp->arp_spa; 624 target_ip_p = (struct in_addr *)(void *)farp->arp_tpa; 625 hwaddr = farp->arp_sha; 626 } 627 break; 628 } 629 is_our_address 630 = (*session->is_our_address)(if_session->if_p, 631 hwtype, 632 hwaddr, 633 link_length); 634 for (i = 0; i < client_count; i++) { 635 int addr_index; 636 arp_client_t * client; 637 boolean_t got_match; 638 639 client = dynarray_element(&if_session->clients, i); 640 if (client->func == NULL) { 641 continue; 642 } 643 if (client->command_status == arp_status_in_use_e) { 644 /* we already found a match for this client */ 645 continue; 646 } 647 got_match = FALSE; 648 switch (client->command) { 649 case arp_client_command_probe_e: 650 if (is_our_address) { 651 /* don't report conflicts against our own h/w addresses */ 652 } 653 /* IP is in use by some other host */ 654 else if (client->target_ip.s_addr == source_ip_p->s_addr 655 || (client->probes_are_collisions 656 && op == ARPOP_REQUEST 657 && source_ip_p->s_addr == 0 658 && client->target_ip.s_addr == target_ip_p->s_addr)) { 659 client->in_use_addr.sender_ip = client->sender_ip; 660 client->in_use_addr.target_ip = client->target_ip; 661 bcopy(hwaddr, client->in_use_addr.target_hardware, 662 link_length); 663 got_match = TRUE; 664 } 665 break; 666 case arp_client_command_resolve_e: 667 if (client->target_ip.s_addr == source_ip_p->s_addr 668 && op == ARPOP_REPLY) { 669 client->in_use_addr.sender_ip = client->sender_ip; 670 client->in_use_addr.target_ip = client->target_ip; 671 bcopy(hwaddr, client->in_use_addr.target_hardware, 672 link_length); 673 got_match = TRUE; 674 } 675 break; 676 case arp_client_command_detect_e: 677 if (op != ARPOP_REPLY) { 678 break; 679 } 680 for (addr_index = 0; addr_index < client->detect_list_count; 681 addr_index++) { 682 arp_address_info_t * info_p; 683 684 info_p = client->detect_list + addr_index; 685 if (info_p->sender_ip.s_addr == target_ip_p->s_addr 686 && info_p->target_ip.s_addr == source_ip_p->s_addr 687 && (bcmp(info_p->target_hardware, hwaddr, link_length) 688 == 0)) { 689 client->in_use_addr = *info_p; 690 got_match = TRUE; 691 break; 692 } 693 } 694 break; 695 default: 696 break; 697 } 698 if (got_match) { 699 client->command_status = arp_status_in_use_e; 700 if (client->command == arp_client_command_probe_e 701 && client->probes_are_collisions == FALSE) { 702 client->conflict_count++; 703 my_log(LOG_DEBUG, 704 "arp_session: encountered conflict," 705 " trying again %d (of %d)", 706 client->conflict_count, 707 session->default_conflict_retry_count + 1); 708 if (client->conflict_count 709 <= session->default_conflict_retry_count) { 710 /* schedule another probe cycle */ 711 timer_set_relative(client->timer_callout, 712 session->default_conflict_delay, 713 (timer_func_t *) 714 arp_client_probe_start, 715 client, NULL, NULL); 716 goto next_packet; 717 } 718 } 719 /* match found, provide results via callback */ 720 arp_client_schedule_callback(client); 721 } 722 } 723 next_packet: 724 skip = BPF_WORDALIGN(bpf->bh_caplen + bpf->bh_hdrlen); 725 if (skip == 0) { 726 break; 727 } 728 offset += skip; 729 n -= skip; 730 } 731 return; 732 failed: 733 for (i = 0; i < client_count; i++) { 734 client = dynarray_element(&if_session->clients, i); 735 if (client->func == NULL) { 736 continue; 737 } 738 strncpy(client->errmsg, errmsg, sizeof(client->errmsg)); 739 /* report back an error to the caller */ 740 client->command_status = arp_status_error_e; 741 arp_client_schedule_callback(client); 742 } 743 return; 744} 745 746static boolean_t 747arp_client_open_fd(arp_client_t * client) 748{ 749 int bpf_fd; 750 arp_if_session_t * if_session = client->if_session; 751 int opt; 752 int status; 753 754 if (client->fd_open) { 755 return (TRUE); 756 } 757 if_session->read_fd_refcount++; 758 my_log(LOG_DEBUG, "arp_client_open_fd (%s): refcount %d", 759 if_name(if_session->if_p), if_session->read_fd_refcount); 760 client->fd_open = TRUE; 761 if (if_session->read_fd_refcount > 1) { 762 /* already open */ 763 return (TRUE); 764 } 765 bpf_fd = bpf_new(); 766 if (bpf_fd < 0) { 767 my_log(LOG_ERR, "arp_client_open_fd: bpf_new(%s) failed, %s (%d)", 768 if_name(if_session->if_p), strerror(errno), errno); 769 snprintf(client->errmsg, sizeof(client->errmsg), 770 "arp_client_open_fd: bpf_new(%s) failed, %s (%d)", 771 if_name(if_session->if_p), strerror(errno), errno); 772 goto failed; 773 } 774 opt = 1; 775 status = ioctl(bpf_fd, FIONBIO, &opt); 776 if (status < 0) { 777 my_log(LOG_ERR, "ioctl FIONBIO failed %s", strerror(errno)); 778 goto failed; 779 } 780 781 /* associate it with the given interface */ 782 status = bpf_setif(bpf_fd, if_name(if_session->if_p)); 783 if (status < 0) { 784 my_log(LOG_ERR, "arp_client_open_fd: bpf_setif(%s) failed: %s (%d)", 785 if_name(if_session->if_p), strerror(errno), errno); 786 snprintf(client->errmsg, sizeof(client->errmsg), 787 "arp_client_open_fd: bpf_setif(%s) failed: %s (%d)", 788 if_name(if_session->if_p), strerror(errno), errno); 789 goto failed; 790 } 791 792 /* don't wait for packets to be buffered */ 793 bpf_set_immediate(bpf_fd, 1); 794 795 /* set the filter to return only ARP packets */ 796 switch (if_link_type(if_session->if_p)) { 797 default: 798 case IFT_ETHER: 799 status = bpf_arp_filter(bpf_fd, 12, ETHERTYPE_ARP, 800 sizeof(struct ether_arp) 801 + sizeof(struct ether_header)); 802 break; 803 case IFT_IEEE1394: 804 status = bpf_arp_filter(bpf_fd, 16, ETHERTYPE_ARP, 805 sizeof(struct firewire_arp) 806 + sizeof(struct firewire_header)); 807 break; 808 } 809 if (status < 0) { 810 my_log(LOG_ERR, 811 "arp_client_open_fd: bpf_arp_filter(%s) failed: %s (%d)", 812 if_name(if_session->if_p), strerror(errno), errno); 813 snprintf(client->errmsg, sizeof(client->errmsg), 814 "arp_client_open_fd: bpf_arp_filter(%s) failed: %s (%d)", 815 if_name(if_session->if_p), strerror(errno), errno); 816 goto failed; 817 } 818 /* get the receive buffer size */ 819 status = bpf_get_blen(bpf_fd, &if_session->receive_bufsize); 820 if (status < 0) { 821 my_log(LOG_ERR, 822 "arp_client_open_fd: bpf_get_blen(%s) failed, %s (%d)", 823 if_name(if_session->if_p), strerror(errno), errno); 824 snprintf(client->errmsg, sizeof(client->errmsg), 825 "arp_client_open_fd: bpf_get_blen(%s) failed, %s (%d)", 826 if_name(if_session->if_p), strerror(errno), errno); 827 goto failed; 828 } 829 if_session->receive_buf = malloc(if_session->receive_bufsize); 830 if_session->read_fd 831 = FDCalloutCreate(bpf_fd, 832 arp_if_session_read, if_session, NULL); 833 if (if_session->read_fd == NULL) { 834 goto failed; 835 } 836 my_log(LOG_DEBUG, "arp_client_open_fd (%s): opened bpf fd %d", 837 if_name(if_session->if_p), bpf_fd); 838 return (TRUE); 839 840 failed: 841 if (bpf_fd >= 0) { 842 close(bpf_fd); 843 } 844 arp_client_close_fd(client); 845 return (FALSE); 846} 847 848static char link_broadcast[8] = { 849 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 850}; 851 852static boolean_t 853arp_client_transmit(arp_client_t * client, boolean_t send_gratuitous, 854 const arp_address_info_t * info_p) 855{ 856 arp_if_session_t * if_session = client->if_session; 857 struct arphdr * hdr; 858 int status = 0; 859 /* 860 * txbuf is cast to some struct types containing short fields; 861 * force it to be aligned as much as an int 862 */ 863 int txbuf_aligned[32]; 864 char * txbuf = (char *)txbuf_aligned; 865 int size; 866 867 bzero(txbuf_aligned, sizeof(txbuf_aligned)); 868 869 /* fill in the ethernet header */ 870 switch (if_link_arptype(if_session->if_p)) { 871 case ARPHRD_ETHER: 872 { 873 struct ether_header * eh_p; 874 struct ether_arp * earp; 875 876 /* fill in the ethernet header */ 877 /* ALIGN: txbuf is aligned to sizeof(int) bytes */ 878 eh_p = (struct ether_header *)(void *)txbuf; 879 eh_p->ether_type = htons(ETHERTYPE_ARP); 880 if (info_p != NULL) { 881 bcopy(info_p->target_hardware, eh_p->ether_dhost, 882 sizeof(eh_p->ether_dhost)); 883 } 884 else { 885 bcopy(link_broadcast, eh_p->ether_dhost, 886 sizeof(eh_p->ether_dhost)); 887 } 888 /* fill in the arp packet contents */ 889 /* ALIGN: txbuf is aligned to sizeof(int) bytes */ 890 earp = (struct ether_arp *)(void *)(txbuf + sizeof(*eh_p)); 891 hdr = &earp->ea_hdr; 892 hdr->ar_hrd = htons(ARPHRD_ETHER); 893 hdr->ar_pro = htons(ETHERTYPE_IP); 894 hdr->ar_hln = sizeof(earp->arp_sha);; 895 hdr->ar_pln = sizeof(struct in_addr); 896 hdr->ar_op = htons(ARPOP_REQUEST); 897 bcopy(if_link_address(if_session->if_p), earp->arp_sha, 898 sizeof(earp->arp_sha)); 899 if (info_p != NULL) { 900 *((struct in_addr *)(void *)earp->arp_spa) = info_p->sender_ip; 901 *((struct in_addr *)(void *)earp->arp_tpa) = info_p->target_ip; 902 } 903 else { 904 if (send_gratuitous == TRUE 905 && client->sender_ip.s_addr == 0) { 906 *((struct in_addr *)(void *)earp->arp_spa) = client->target_ip; 907 } 908 else { 909 *((struct in_addr *)(void *)earp->arp_spa) = client->sender_ip; 910 } 911 *((struct in_addr *)(void *)earp->arp_tpa) = client->target_ip; 912 } 913 size = sizeof(*eh_p) + sizeof(*earp); 914 } 915 break; 916 case ARPHRD_IEEE1394: 917 { 918 struct firewire_header * fh_p; 919 struct firewire_arp * farp; 920 921 /* fill in the firewire header */ 922 /* ALIGN: txbuf is aligned to sizeof(int) bytes */ 923 fh_p = (struct firewire_header *)(void *)txbuf; 924 fh_p->firewire_type = htons(ETHERTYPE_ARP); 925 if (info_p != NULL) { 926 bcopy(info_p->target_hardware, fh_p->firewire_dhost, 927 sizeof(fh_p->firewire_dhost)); 928 } 929 else { 930 bcopy(link_broadcast, fh_p->firewire_dhost, 931 sizeof(fh_p->firewire_dhost)); 932 } 933 934 /* fill in the arp packet contents */ 935 /* ALIGN: txbuf is aligned to sizeof(int) bytes */ 936 farp = (struct firewire_arp *)(void *)(txbuf + sizeof(*fh_p)); 937 hdr = &farp->fw_hdr; 938 hdr->ar_hrd = htons(ARPHRD_IEEE1394); 939 hdr->ar_pro = htons(ETHERTYPE_IP); 940 hdr->ar_hln = sizeof(farp->arp_sha);; 941 hdr->ar_pln = sizeof(struct in_addr); 942 hdr->ar_op = htons(ARPOP_REQUEST); 943 bcopy(&if_session->fw_addr, farp->arp_sha, 944 sizeof(farp->arp_sha)); 945 if (info_p != NULL) { 946 *((struct in_addr *)(void *)farp->arp_spa) = info_p->sender_ip; 947 *((struct in_addr *)(void *)farp->arp_tpa) = info_p->target_ip; 948 } 949 else { 950 if (send_gratuitous == TRUE 951 && client->sender_ip.s_addr == 0) { 952 *((struct in_addr *)(void *)farp->arp_spa) = client->target_ip; 953 } 954 else { 955 *((struct in_addr *)(void *)farp->arp_spa) = client->sender_ip; 956 } 957 *((struct in_addr *)(void *)farp->arp_tpa) = client->target_ip; 958 } 959 size = sizeof(*fh_p) + sizeof(*farp); 960 } 961 break; 962 default: 963 snprintf(client->errmsg, sizeof(client->errmsg), 964 "arp_client_transmit(%s): " 965 "interface hardware type not yet known", 966 if_name(if_session->if_p)); 967 goto failed; 968 } 969 970 status = bpf_write(FDCalloutGetFD(if_session->read_fd), txbuf, size); 971 if (status < 0) { 972 my_log(LOG_ERR, "arp_client_transmit(%s) failed, %s (%d)", 973 if_name(if_session->if_p), strerror(errno), errno); 974 snprintf(client->errmsg, sizeof(client->errmsg), 975 "arp_client_transmit(%s) failed, %s (%d)", 976 if_name(if_session->if_p), strerror(errno), errno); 977 goto failed; 978 } 979 return (TRUE); 980 981 failed: 982 return (FALSE); 983} 984 985static void 986arp_client_probe_start(void * arg1, void * arg2, void * arg3) 987{ 988 arp_client_t * client = (arp_client_t *)arg1; 989 990 client->try = 0; 991 client->command_status = arp_status_unknown_e; 992 arp_client_probe_retransmit(arg1, arg2, arg3); 993 return; 994} 995 996/* 997 * Function: arp_client_probe_retransmit 998 * 999 * Purpose: 1000 * Transmit an ARP packet with timeout retry. 1001 * Uses callback to invoke arp_client_report_error if the transmit failed. 1002 * When we've tried often enough, call the client function with a result 1003 * structure indicating no errors and the IP is not in use. 1004 */ 1005static void 1006arp_client_probe_retransmit(void * arg1, void * arg2, void * arg3) 1007{ 1008 arp_client_t * client = (arp_client_t *)arg1; 1009 struct probe_info * probe_info = &client->probe_info; 1010 int tries_left; 1011 arp_if_session_t * if_session = client->if_session; 1012 1013 tries_left = (probe_info->probe_count + probe_info->gratuitous_count) 1014 - client->try; 1015 1016 if (tries_left <= 0) { 1017 /* not in use */ 1018 client->command_status = arp_status_not_in_use_e; 1019 arp_client_schedule_callback(client); 1020 return; 1021 } 1022 1023 client->try++; 1024 1025 if (client->probe_info.skip_first || 1026 arp_client_transmit(client, 1027 (tries_left <= probe_info->gratuitous_count), 1028 NULL)) { 1029 if (G_IPConfiguration_verbose) { 1030 if (client->probe_info.skip_first) { 1031 my_log(LOG_DEBUG, ARP_STR 1032 "(%s): skipping the first arp announcement.", 1033 if_name(if_session->if_p)); 1034 } 1035 else if (tries_left <= probe_info->gratuitous_count) { 1036 my_log(LOG_DEBUG, 1037 ARP_STR 1038 "(%s): sending (%d of %d) arp announcements ", 1039 if_name(if_session->if_p), 1040 probe_info->gratuitous_count - tries_left + 1, 1041 probe_info->gratuitous_count); 1042 } 1043 else { 1044 my_log(LOG_DEBUG, ARP_STR "(%s): sending (%d of %d) " 1045 "arp probes ", if_name(if_session->if_p), 1046 client->try, probe_info->probe_count); 1047 } 1048 } 1049 timer_set_relative(client->timer_callout, 1050 probe_info->retry_interval, 1051 (timer_func_t *)arp_client_probe_retransmit, 1052 client, NULL, NULL); 1053 client->probe_info.skip_first = FALSE; 1054 } 1055 else { 1056 /* report back an error to the caller */ 1057 client->command_status = arp_status_error_e; 1058 arp_client_schedule_callback(client); 1059 } 1060} 1061/* 1062 * Function: arp_client_resolve_retransmit 1063 * 1064 * Purpose: 1065 * Transmit an ARP request packet in an attempt to resolve the IP address. 1066 * Uses callback to invoke arp_client_report_error if the transmit failed. 1067 * If we can't resolve the address, call the callback indicating the IP 1068 * address is not in use. 1069 */ 1070static void 1071arp_client_resolve_retransmit(void * arg1, void * arg2, void * arg3) 1072{ 1073 arp_client_t * client = (arp_client_t *)arg1; 1074 int tries_left; 1075 1076 tries_left = client->resolve_secs - client->try; 1077 if (tries_left <= 0) { 1078 /* not in use */ 1079 client->command_status = arp_status_not_in_use_e; 1080 arp_client_schedule_callback(client); 1081 return; 1082 } 1083 client->try++; 1084 if (arp_client_transmit(client, FALSE, NULL)) { 1085 struct timeval t; 1086 1087#define ONE_SECOND 1 1088 t.tv_sec = ONE_SECOND; 1089 t.tv_usec = 0; 1090 timer_set_relative(client->timer_callout, t, 1091 (timer_func_t *)arp_client_resolve_retransmit, 1092 client, NULL, NULL); 1093 } 1094 else { 1095 /* report back an error to the caller */ 1096 client->command_status = arp_status_error_e; 1097 arp_client_schedule_callback(client); 1098 } 1099 return; 1100} 1101 1102/* 1103 * Function: arp_client_detect_retransmit 1104 * 1105 * Purpose: 1106 * Transmit a set of ARP requests, one request for each host of interest, 1107 * in an attempt to detect which one is present. The ARP requests are sent 1108 * using unicast to a specific hardware address and should only be visible 1109 * received/processed by that specific host. 1110 */ 1111static void 1112arp_client_detect_retransmit(void * arg1, void * arg2, void * arg3) 1113{ 1114 arp_client_t * client = (arp_client_t *)arg1; 1115 int i; 1116 boolean_t keep_going = TRUE; 1117 arp_session_t * session = client->if_session->session; 1118 int tries_left; 1119 struct timeval * timeout_p; 1120 boolean_t resolve = (boolean_t) (uintptr_t) arg2; 1121 1122 tries_left = session->default_detect_count - client->try; 1123 if (tries_left <= 0) { 1124 /* not in use */ 1125 client->command_status = arp_status_not_in_use_e; 1126 arp_client_schedule_callback(client); 1127 return; 1128 } 1129 client->try++; 1130 for (i = 0; i < client->detect_list_count; i++) { 1131 if (arp_client_transmit(client, FALSE, client->detect_list + i) 1132 == FALSE) { 1133 keep_going = FALSE; 1134 break; 1135 } 1136 } 1137 if (keep_going) { 1138 timeout_p = resolve ? &session->default_resolve_retry : 1139 &session->default_detect_retry; 1140 1141 timer_set_relative(client->timer_callout, *timeout_p, 1142 (timer_func_t *) 1143 arp_client_detect_retransmit, 1144 client, arg2, NULL); 1145 } 1146 else { 1147 /* report back an error to the caller */ 1148 client->command_status = arp_status_error_e; 1149 arp_client_schedule_callback(client); 1150 } 1151 return; 1152} 1153 1154static arp_client_t * 1155arp_if_session_new_client(arp_if_session_t * if_session) 1156{ 1157 arp_client_t * client; 1158 1159 client = malloc(sizeof(*client)); 1160 if (client == NULL) { 1161 return (NULL); 1162 } 1163 bzero(client, sizeof(*client)); 1164 if (dynarray_add(&if_session->clients, client) == FALSE) { 1165 free(client); 1166 return (NULL); 1167 } 1168#ifdef TEST_ARP_SESSION 1169 client->client_index = if_session->session->next_client_index++; 1170#endif /* TEST_ARP_SESSION */ 1171 client->if_session = if_session; 1172 client->probe_info = if_session->session->default_probe_info; 1173 client->timer_callout = timer_callout_init(); 1174 return (client); 1175 1176} 1177 1178static arp_client_t * 1179arp_session_new_client(arp_session_t * session, interface_t * if_p) 1180{ 1181 arp_if_session_t * if_session; 1182 1183 if_session = arp_session_new_if_session(session, if_p); 1184 if (if_session == NULL) { 1185 return (NULL); 1186 } 1187 return (arp_if_session_new_client(if_session)); 1188} 1189 1190#ifdef TEST_ARP_SESSION 1191static arp_client_t * 1192arp_session_find_client_with_index(arp_session_t * session, int index) 1193{ 1194 int if_sessions_count; 1195 int i; 1196 int j; 1197 1198 if_sessions_count = dynarray_count(&session->if_sessions); 1199 for (i = 0; i < if_sessions_count; i++) { 1200 int clients_count; 1201 arp_if_session_t * if_session; 1202 1203 if_session = dynarray_element(&session->if_sessions, i); 1204 clients_count = dynarray_count(&if_session->clients); 1205 for (j = 0; j < clients_count; j++) { 1206 arp_client_t * client; 1207 1208 client = dynarray_element(&if_session->clients, j); 1209 if (client->client_index == index) { 1210 return (client); 1211 } 1212 } 1213 } 1214 return (NULL); 1215} 1216 1217#endif /* TEST_ARP_SESSION */ 1218 1219PRIVATE_EXTERN void 1220arp_client_set_probe_info(arp_client_t * client, 1221 const struct timeval * retry_interval, 1222 const int * probe_count, 1223 const int * gratuitous_count) 1224{ 1225 struct probe_info * probe_info = &client->probe_info; 1226 1227 if (retry_interval != NULL) { 1228 probe_info->retry_interval = *retry_interval; 1229 } 1230 if (probe_count != NULL) { 1231 probe_info->probe_count = *probe_count; 1232 } 1233 if (gratuitous_count != NULL) { 1234 probe_info->gratuitous_count = *gratuitous_count; 1235 } 1236 return; 1237} 1238 1239PRIVATE_EXTERN void 1240arp_client_restore_default_probe_info(arp_client_t * client) 1241{ 1242 client->probe_info = client->if_session->session->default_probe_info; 1243 return; 1244} 1245 1246PRIVATE_EXTERN arp_client_t * 1247arp_client_init(arp_session_t * session, interface_t * if_p) 1248{ 1249 return (arp_session_new_client(session, if_p)); 1250} 1251 1252static void 1253arp_client_free_element(void * arg) 1254{ 1255 arp_client_t * client = (arp_client_t *)arg; 1256 1257 arp_client_cancel(client); 1258 timer_callout_free(&client->timer_callout); 1259 free(client); 1260 return; 1261} 1262 1263PRIVATE_EXTERN void 1264arp_client_free(arp_client_t * * client_p) 1265{ 1266 arp_client_t * client = NULL; 1267 int i; 1268 arp_if_session_t * if_session; 1269 1270 if (client_p != NULL) { 1271 client = *client_p; 1272 } 1273 if (client == NULL) { 1274 return; 1275 } 1276 1277 /* remove from list of clients */ 1278 if_session = client->if_session; 1279 i = dynarray_index(&if_session->clients, client); 1280 if (i != -1) { 1281 dynarray_remove(&if_session->clients, i, NULL); 1282 } 1283 else { 1284 my_log(LOG_ERR, "arp_client_free(%s) not in list?", 1285 if_name(if_session->if_p)); 1286 } 1287 1288 /* free resources */ 1289 arp_client_free_element(client); 1290 *client_p = NULL; 1291 1292 /* if we're the last client, if_session can go too */ 1293 if (dynarray_count(&if_session->clients) == 0) { 1294 arp_if_session_free(&if_session); 1295 } 1296 return; 1297} 1298 1299PRIVATE_EXTERN void 1300arp_client_set_probes_are_collisions(arp_client_t * client, 1301 boolean_t probes_are_collisions) 1302{ 1303 client->probes_are_collisions = probes_are_collisions; 1304 return; 1305} 1306 1307static inline void 1308arp_client_setup_context(arp_client_t * client, 1309 arp_result_func_t * func, void * arg1, void * arg2, 1310 struct in_addr sender_ip, struct in_addr target_ip, 1311 boolean_t skip) 1312{ 1313 arp_if_session_t * if_session = client->if_session; 1314 1315 arp_client_cancel(client); 1316 arp_if_session_update_hardware_address(if_session); 1317 client->sender_ip = sender_ip; 1318 client->target_ip = target_ip; 1319 client->func = func; 1320 client->arg1 = arg1; 1321 client->arg2 = arg2; 1322 client->errmsg[0] = '\0'; 1323 client->try = 0; 1324 client->conflict_count = 0; 1325 1326 /* We might need to skip the first arp announcement since it 1327 * may have already been sent. */ 1328 client->probe_info.skip_first = skip; 1329} 1330 1331PRIVATE_EXTERN void 1332arp_client_announce(arp_client_t * client, 1333 arp_result_func_t * func, void * arg1, void * arg2, 1334 struct in_addr sender_ip, struct in_addr target_ip, 1335 boolean_t skip) 1336{ 1337 arp_client_setup_context(client, func, arg1, arg2, 1338 sender_ip, target_ip, skip); 1339 1340 /* Send announce only, get rid of the probe count. */ 1341 client->try = client->probe_info.probe_count; 1342 if (!arp_client_open_fd(client)) { 1343 /* report back an error to the caller */ 1344 client->command_status = arp_status_error_e; 1345 arp_client_schedule_callback(client); 1346 return; 1347 } 1348 1349 client->command_status = arp_status_unknown_e; 1350 client->command = arp_client_command_probe_e; 1351 arp_client_probe_retransmit(client, NULL, NULL); 1352} 1353 1354PRIVATE_EXTERN void 1355arp_client_probe(arp_client_t * client, 1356 arp_result_func_t * func, void * arg1, void * arg2, 1357 struct in_addr sender_ip, struct in_addr target_ip) 1358{ 1359 arp_client_setup_context(client, func, arg1, arg2, 1360 sender_ip, target_ip, FALSE); 1361 1362 if (!arp_client_open_fd(client)) { 1363 /* report back an error to the caller */ 1364 client->command_status = arp_status_error_e; 1365 arp_client_schedule_callback(client); 1366 return; 1367 } 1368 client->command_status = arp_status_unknown_e; 1369 client->command = arp_client_command_probe_e; 1370 arp_client_probe_retransmit(client, NULL, NULL); 1371 return; 1372} 1373 1374PRIVATE_EXTERN void 1375arp_client_resolve(arp_client_t * client, 1376 arp_result_func_t * func, void * arg1, void * arg2, 1377 struct in_addr sender_ip, struct in_addr target_ip, 1378 uint32_t resolve_secs) 1379{ 1380 1381 arp_if_session_t * if_session = client->if_session; 1382 1383 arp_client_cancel(client); 1384 arp_if_session_update_hardware_address(if_session); 1385 client->sender_ip = sender_ip; 1386 client->target_ip = target_ip; 1387 client->func = func; 1388 client->arg1 = arg1; 1389 client->arg2 = arg2; 1390 client->errmsg[0] = '\0'; 1391 client->try = 0; 1392 client->conflict_count = 0; 1393 if (!arp_client_open_fd(client)) { 1394 /* report back an error to the caller */ 1395 client->command_status = arp_status_error_e; 1396 arp_client_schedule_callback(client); 1397 return; 1398 } 1399 client->command_status = arp_status_unknown_e; 1400#define DEFAULT_RESOLVE_SECS 16 1401 client->resolve_secs 1402 = (resolve_secs > 0) ? resolve_secs : DEFAULT_RESOLVE_SECS; 1403 client->command = arp_client_command_resolve_e; 1404 arp_client_resolve_retransmit(client, NULL, NULL); 1405 return; 1406} 1407 1408PRIVATE_EXTERN void 1409arp_client_detect(arp_client_t * client, 1410 arp_result_func_t * func, void * arg1, void * arg2, 1411 const arp_address_info_t * list, int list_count, 1412 boolean_t resolve) 1413{ 1414 arp_if_session_t * if_session = client->if_session; 1415 int list_size; 1416 1417 arp_client_cancel(client); 1418 arp_if_session_update_hardware_address(if_session); 1419 client->func = func; 1420 client->arg1 = arg1; 1421 client->arg2 = arg2; 1422 client->errmsg[0] = '\0'; 1423 client->try = 0; 1424 client->conflict_count = 0; 1425 if (list_count == 0 || !arp_client_open_fd(client)) { 1426 /* report back an error to the caller */ 1427 client->command_status = arp_status_error_e; 1428 arp_client_schedule_callback(client); 1429 return; 1430 } 1431 list_size = sizeof(*client->detect_list) * list_count; 1432 client->detect_list = (arp_address_info_t *)malloc(list_size); 1433 bcopy(list, client->detect_list, list_size); 1434 client->detect_list_count = list_count; 1435 client->command_status = arp_status_unknown_e; 1436 client->command = arp_client_command_detect_e; 1437 arp_client_detect_retransmit(client, (void *)(uintptr_t)resolve, 1438 NULL); 1439 return; 1440} 1441 1442PRIVATE_EXTERN const char * 1443arp_client_errmsg(arp_client_t * client) 1444{ 1445 return ((const char *)client->errmsg); 1446} 1447 1448PRIVATE_EXTERN void 1449arp_client_cancel(arp_client_t * client) 1450{ 1451 client->errmsg[0] = '\0'; 1452 client->func = client->arg1 = client->arg2 = NULL; 1453 client->command_status = arp_status_none_e; 1454 arp_client_close_fd(client); 1455 timer_cancel(client->timer_callout); 1456 if (client->detect_list != NULL) { 1457 free(client->detect_list); 1458 client->detect_list = NULL; 1459 } 1460 arp_client_cancel_callback(client); 1461 return; 1462} 1463 1464PRIVATE_EXTERN boolean_t 1465arp_client_defend(arp_client_t * client, struct in_addr our_ip) 1466{ 1467 boolean_t defended = FALSE; 1468 arp_if_session_t * if_session = client->if_session; 1469 1470 arp_client_cancel(client); 1471 arp_if_session_update_hardware_address(if_session); 1472 1473 if (!arp_client_open_fd(client)) { 1474 my_log(LOG_ERR, "arp_client_defend(%s): open fd failed", 1475 if_name(if_session->if_p)); 1476 } 1477 else { 1478 client->target_ip = client->sender_ip = our_ip; 1479 if (!arp_client_transmit(client, FALSE, NULL)) { 1480 my_log(LOG_ERR, "arp_client_defend(%s): transmit failed", 1481 if_name(if_session->if_p)); 1482 } 1483 else { 1484 defended = TRUE; 1485 } 1486 arp_client_close_fd(client); 1487 } 1488 return (defended); 1489} 1490 1491PRIVATE_EXTERN arp_session_t * 1492arp_session_init(arp_our_address_func_t * func, 1493 arp_session_values_t * values) 1494{ 1495 arp_session_t * session; 1496 1497 session = malloc(sizeof(*session)); 1498 if (session == NULL) { 1499 return (NULL); 1500 } 1501 bzero(session, sizeof(*session)); 1502 dynarray_init(&session->if_sessions, arp_if_session_free_element, NULL); 1503 if (func == NULL) { 1504 session->is_our_address = arp_is_our_address; 1505 } 1506 else { 1507 session->is_our_address = func; 1508 } 1509 if (values->probe_interval != NULL) { 1510 session->default_probe_info.retry_interval = *values->probe_interval; 1511 } 1512 else { 1513 session->default_probe_info.retry_interval.tv_sec = ARP_RETRY_SECS; 1514 session->default_probe_info.retry_interval.tv_usec = ARP_RETRY_USECS; 1515 } 1516 if (values->probe_count != NULL) { 1517 session->default_probe_info.probe_count = *values->probe_count; 1518 } 1519 else { 1520 session->default_probe_info.probe_count = ARP_PROBE_COUNT; 1521 } 1522 if (values->probe_gratuitous_count != NULL) { 1523 session->default_probe_info.gratuitous_count 1524 = *values->probe_gratuitous_count; 1525 } 1526 else { 1527 session->default_probe_info.gratuitous_count = ARP_GRATUITOUS_COUNT; 1528 } 1529 if (values->detect_count != NULL) { 1530 session->default_detect_count = *values->detect_count; 1531 } 1532 else { 1533 session->default_detect_count = ARP_DETECT_COUNT; 1534 } 1535 if (values->detect_interval != NULL) { 1536 session->default_detect_retry = *values->detect_interval; 1537 } 1538 else { 1539 session->default_detect_retry.tv_sec = ARP_DETECT_RETRY_SECS; 1540 session->default_detect_retry.tv_usec = ARP_DETECT_RETRY_USECS; 1541 } 1542 if (values->resolve_interval != NULL) { 1543 session->default_resolve_retry = *values->resolve_interval; 1544 } 1545 else { 1546 session->default_resolve_retry.tv_sec = ARP_RESOLVE_RETRY_SECS; 1547 session->default_resolve_retry.tv_usec = ARP_RESOLVE_RETRY_USECS; 1548 } 1549 if (values->conflict_retry_count != NULL) { 1550 session->default_conflict_retry_count = *values->conflict_retry_count; 1551 } 1552 else { 1553 session->default_conflict_retry_count = ARP_CONFLICT_RETRY_COUNT; 1554 } 1555 if (values->conflict_delay_interval != NULL) { 1556 session->default_conflict_delay 1557 = *values->conflict_delay_interval; 1558 } 1559 else { 1560 session->default_conflict_delay.tv_sec 1561 = ARP_CONFLICT_RETRY_DELAY_SECS; 1562 session->default_conflict_delay.tv_usec 1563 = ARP_CONFLICT_RETRY_DELAY_USECS; 1564 } 1565#ifdef TEST_ARP_SESSION 1566 session->next_client_index = 1; 1567#endif /* TEST_ARP_SESSION */ 1568 return (session); 1569} 1570 1571PRIVATE_EXTERN void 1572arp_session_free(arp_session_t * * session_p) 1573{ 1574 arp_session_t * session = *session_p; 1575 1576 dynarray_free(&session->if_sessions); 1577 bzero(session, sizeof(*session)); 1578 free(session); 1579 *session_p = NULL; 1580 return; 1581} 1582 1583static arp_if_session_t * 1584arp_session_find_if_session(arp_session_t * session, const char * ifn) 1585{ 1586 int count; 1587 int i; 1588 1589 count = dynarray_count(&session->if_sessions); 1590 for (i = 0; i < count; i++) { 1591 arp_if_session_t * if_session; 1592 1593 if_session = dynarray_element(&session->if_sessions, i); 1594 if (strcmp(if_name(if_session->if_p), ifn) == 0) { 1595 return (if_session); 1596 } 1597 } 1598 return (NULL); 1599} 1600 1601static void 1602arp_if_session_free_element(void * arg) 1603{ 1604 arp_if_session_t * if_session = (arp_if_session_t *)arg; 1605 1606 /* free all of the clients, close file descriptor */ 1607 dynarray_free(&if_session->clients); 1608 1609 free(if_session); 1610 return; 1611} 1612 1613static void 1614arp_if_session_free(arp_if_session_t * * if_session_p) 1615{ 1616 arp_if_session_t * if_session = NULL; 1617 int i; 1618 arp_session_t * session; 1619 1620 if (if_session_p != NULL) { 1621 if_session = *if_session_p; 1622 } 1623 if (if_session == NULL) { 1624 return; 1625 } 1626 1627 /* remove from the list of if_sessions */ 1628 session = if_session->session; 1629 i = dynarray_index(&session->if_sessions, if_session); 1630 if (i != -1) { 1631 dynarray_remove(&session->if_sessions, i, NULL); 1632 } 1633 else { 1634 my_log(LOG_ERR, "arp_if_session_free(%s) not in list?", 1635 if_name(if_session->if_p)); 1636 } 1637 1638 /* release resources */ 1639 arp_if_session_free_element(if_session); 1640 1641 *if_session_p = NULL; 1642 return; 1643} 1644 1645static arp_if_session_t * 1646arp_session_new_if_session(arp_session_t * session, interface_t * if_p) 1647{ 1648 struct firewire_address fw_addr; 1649 arp_if_session_t * if_session; 1650 1651 if_session = arp_session_find_if_session(session, if_name(if_p)); 1652 if (if_session != NULL) { 1653 return (if_session); 1654 } 1655 switch (if_link_type(if_p)) { 1656 case IFT_ETHER: 1657 break; 1658 case IFT_IEEE1394: 1659 /* copy in the firewire address */ 1660 if (getFireWireAddress(if_name(if_p), &fw_addr) == FALSE) { 1661 my_log(LOG_ERR, 1662 "arp_client_init(%s): could not retrieve firewire address", 1663 if_name(if_p)); 1664 return (NULL); 1665 } 1666 break; 1667 default: 1668 my_log(LOG_ERR, "arp_client_init(%s): unsupported network type", 1669 if_name(if_p)); 1670 return (NULL); 1671 } 1672 if_session = (arp_if_session_t *)malloc(sizeof(*if_session)); 1673 bzero(if_session, sizeof(*if_session)); 1674 dynarray_init(&if_session->clients, arp_client_free_element, NULL); 1675 if (if_link_type(if_p) == IFT_IEEE1394) { 1676 /* copy in the fw address */ 1677 if_session->fw_addr = fw_addr; 1678 } 1679 if_session->if_p = if_p; 1680 if_session->session = session; 1681 dynarray_add(&session->if_sessions, if_session); 1682 return (if_session); 1683} 1684 1685PRIVATE_EXTERN void 1686arp_session_set_debug(arp_session_t * session, int debug) 1687{ 1688 session->debug = debug; 1689 return; 1690} 1691 1692#ifdef TEST_ARP_SESSION 1693#include <stdarg.h> 1694typedef boolean_t func_t(int argc, const char * * argv); 1695typedef func_t * funcptr_t; 1696 1697static arp_session_t * S_arp_session; 1698static boolean_t S_debug = FALSE; 1699static func_t S_do_probe; 1700static func_t S_do_resolve; 1701static func_t S_do_detect; 1702static func_t S_cancel_probe; 1703static func_t S_toggle_debug; 1704static func_t S_new_client; 1705static func_t S_free_client; 1706static func_t S_list; 1707static func_t S_quit; 1708static func_t S_client_params; 1709static interface_list_t * S_interfaces; 1710 1711#define BASE_16 16 1712 1713static uint8_t * 1714hexstrtobin(const char * str, int * len) 1715{ 1716 int buf_pos; 1717 uint8_t * buf = NULL; 1718 boolean_t done = FALSE; 1719 int max_decoded_len; 1720 const char * scan = str; 1721 int slen = strlen(str); 1722 1723 *len = 0; 1724 /* the worst case we turn "1:2:3:4:5:6" into 6 bytes 1725 * strlen("1:2:3:4:5:6") = 11 1726 * so to get the approximate decoded length, 1727 * we want strlen(str) / 2 + 1 1728 */ 1729 max_decoded_len = (slen / 2) + 1; 1730 buf = (uint8_t *)malloc(max_decoded_len); 1731 if (buf == NULL) { 1732 return (buf); 1733 } 1734 for (buf_pos = 0; buf_pos < max_decoded_len && !done; buf_pos++) { 1735 char tmp[4]; 1736 const char * colon; 1737 1738 colon = strchr(scan, ':'); 1739 if (colon == NULL) { 1740 done = TRUE; 1741 colon = str + slen; 1742 } 1743 if ((colon - scan) > (sizeof(tmp) - 1)) { 1744 goto err; 1745 } 1746 strncpy(tmp, scan, colon - scan); 1747 tmp[colon - scan] = '\0'; 1748 buf[buf_pos] = (u_char)strtol(tmp, NULL, BASE_16); 1749 scan = colon + 1; 1750 } 1751 *len = buf_pos; 1752 return (buf); 1753 err: 1754 if (buf) { 1755 free(buf); 1756 } 1757 return (NULL); 1758} 1759 1760static void 1761arp_session_log(int priority, const char * message, ...) 1762{ 1763 va_list ap; 1764 1765 if (priority == LOG_DEBUG) { 1766 if (S_arp_session->debug == FALSE) 1767 return; 1768 } 1769 va_start(ap, message); 1770 vfprintf(stderr, message, ap); 1771 fprintf(stderr, "\n"); 1772 fflush(stderr); 1773 return; 1774} 1775 1776static const struct command_info { 1777 char * command; 1778 funcptr_t func; 1779 int argc; 1780 char * usage; 1781 int display; 1782} commands[] = { 1783 { "new", S_new_client, 1, "<ifname>", 1 }, 1784 { "free", S_free_client, 1, "<client_index>", 1 }, 1785 { "probe", S_do_probe, 3, "<client_index> <sender_ip> <target_ip>", 1 }, 1786 { "resolve", S_do_resolve, 3, "<client_index> <sender_ip> <target_ip>", 1 }, 1787 { "detect", S_do_detect, 4, 1788 "<client_index> [ <sender_ip> <target_ip> <target_hardware> ]+", 1 }, 1789 { "cancel", S_cancel_probe, 1, "<client_index>", 1 }, 1790 { "params", S_client_params, 1, "<client_index> [ default | <interval> <probes> [ <gratuitous> ] ]", 1 }, 1791 { "debug", S_toggle_debug, 0, NULL, 1 }, 1792 { "list", S_list, 0, NULL, 1 }, 1793 { "quit", S_quit, 0, NULL, 1 }, 1794 { NULL, NULL, 0 } 1795}; 1796 1797struct arg_info { 1798 char * * argv; 1799 int argc; 1800 int argv_size; 1801}; 1802 1803static void 1804arg_info_init(struct arg_info * args) 1805{ 1806 args->argv = NULL; 1807 args->argv_size = 0; 1808 args->argc = 0; 1809 return; 1810} 1811 1812static void 1813arg_info_free(struct arg_info * args) 1814{ 1815 if (args->argv != NULL) { 1816 free(args->argv); 1817 } 1818 arg_info_init(args); 1819 return; 1820} 1821 1822/* 1823static void 1824arg_info_print(struct arg_info * args) 1825{ 1826 int i; 1827 1828 for (i = 0; i < args->argc; i++) { 1829 printf("%2d. '%s'\n", i, args->argv[i]); 1830 } 1831 return; 1832} 1833*/ 1834 1835static void 1836arg_info_add(struct arg_info * args, char * new_arg) 1837{ 1838 if (args->argv == NULL) { 1839 args->argv_size = 6; 1840 args->argv = (char * *)malloc(sizeof(*args->argv) * args->argv_size); 1841 } 1842 else if (args->argc == args->argv_size) { 1843 args->argv_size *= 2; 1844 args->argv = (char * *)realloc(args->argv, 1845 sizeof(*args->argv) * args->argv_size); 1846 } 1847 args->argv[args->argc++] = new_arg; 1848 return; 1849} 1850 1851void 1852my_CFRelease(void * t) 1853{ 1854 void * * obj = (void * *)t; 1855 if (obj && *obj) { 1856 CFRelease(*obj); 1857 *obj = NULL; 1858 } 1859 return; 1860} 1861 1862static int 1863arp_link_length(interface_t * if_p) 1864{ 1865 int len; 1866 1867 if (if_link_arptype(if_p) == ARPHRD_IEEE1394) { 1868 len = sizeof(struct firewire_eui64); 1869 } 1870 else { 1871 len = ETHER_ADDR_LEN; 1872 } 1873 return (len); 1874} 1875 1876 1877static void 1878arp_test(void * arg1, void * arg2, const arp_result_t * result) 1879{ 1880 arp_client_t * client = (arp_client_t *)arg1; 1881 1882 if (result->error) { 1883 printf("ARP probe failed: '%s'\n", 1884 client->errmsg); 1885 } 1886 else if (result->in_use) { 1887 int i; 1888 int len = arp_link_length(client->if_session->if_p); 1889 const u_char * addr = result->addr.target_hardware; 1890 1891 printf("ip address " IP_FORMAT " in use by", 1892 IP_LIST(&client->target_ip)); 1893 for (i = 0; i < len; i++) { 1894 printf("%c%02x", i == 0 ? ' ' : ':', addr[i]); 1895 } 1896 printf("\n"); 1897 } 1898 else { 1899 printf("ip address " IP_FORMAT " is not in use\n", 1900 IP_LIST(&client->target_ip)); 1901 } 1902} 1903 1904static void 1905arp_detect_callback(void * arg1, void * arg2, const arp_result_t * result) 1906{ 1907 arp_client_t * client = (arp_client_t *)arg1; 1908 1909 if (result->error) { 1910 printf("ARP detect failed: '%s'\n", 1911 client->errmsg); 1912 } 1913 else if (result->in_use) { 1914 int i; 1915 int len = arp_link_length(client->if_session->if_p); 1916 const u_char * addr = result->addr.target_hardware; 1917 1918 printf("ARP detected Sender IP " IP_FORMAT " Target IP " IP_FORMAT 1919 " Target Hardware", 1920 IP_LIST(&result->addr.sender_ip), 1921 IP_LIST(&result->addr.target_ip)); 1922 for (i = 0; i < len; i++) { 1923 printf("%c%02x", i == 0 ? ' ' : ':', addr[i]); 1924 } 1925 printf("\n"); 1926 } 1927 else { 1928 printf("Did not detect any IP\n"); 1929 } 1930} 1931 1932static boolean_t 1933S_toggle_debug(int argc, const char * * argv) 1934{ 1935 S_debug = !S_debug; 1936 arp_session_set_debug(S_arp_session, S_debug); 1937 if (S_debug) { 1938 printf("debug mode enabled\n"); 1939 } 1940 else { 1941 printf("debug mode disabled\n"); 1942 } 1943 return (TRUE); 1944} 1945 1946static boolean_t 1947S_quit(int argc, const char * * argv) 1948{ 1949 exit(0); 1950 return (TRUE); 1951} 1952 1953static boolean_t 1954S_new_client(int argc, const char * * argv) 1955{ 1956 arp_client_t * client; 1957 interface_t * if_p; 1958 1959 if_p = ifl_find_name(S_interfaces, argv[1]); 1960 if (if_p == NULL) { 1961 fprintf(stderr, "interface %s does not exist\n", argv[1]); 1962 goto done; 1963 } 1964 client = arp_client_init(S_arp_session, if_p); 1965 if (client == NULL) { 1966 fprintf(stderr, "Could not create a new client over %s\n", 1967 if_name(if_p)); 1968 goto done; 1969 } 1970 printf("%d\n", client->client_index); 1971 done: 1972 return (client != NULL); 1973} 1974 1975static boolean_t 1976get_int_param(const char * arg, int * ret_int) 1977{ 1978 char * endptr; 1979 int val; 1980 1981 val = strtol(arg, &endptr, 0); 1982 if (endptr == arg || (val == 0 && errno != 0)) { 1983 return (FALSE); 1984 } 1985 *ret_int = val; 1986 return (TRUE); 1987} 1988 1989static boolean_t 1990get_client_index(const char * arg, int * client_index) 1991{ 1992 if (get_int_param(arg, client_index)) { 1993 return (TRUE); 1994 } 1995 if (strcmp(arg, ".") == 0) { 1996 *client_index = S_arp_session->next_client_index - 1; 1997 return (TRUE); 1998 } 1999 return (FALSE); 2000} 2001 2002static boolean_t 2003S_do_probe(int argc, const char * * argv) 2004{ 2005 arp_client_t * client; 2006 int client_index; 2007 struct in_addr sender_ip; 2008 struct in_addr target_ip; 2009 2010 if (get_client_index(argv[1], &client_index) == FALSE) { 2011 fprintf(stderr, "invalid client index\n"); 2012 goto done; 2013 } 2014 client = arp_session_find_client_with_index(S_arp_session, client_index); 2015 if (client == NULL) { 2016 fprintf(stderr, "no such client index\n"); 2017 goto done; 2018 } 2019 if (inet_aton(argv[2], &sender_ip) == 0) { 2020 fprintf(stderr, "invalid sender ip address %s\n", argv[2]); 2021 client = NULL; 2022 goto done; 2023 } 2024 if (inet_aton(argv[3], &target_ip) == 0) { 2025 fprintf(stderr, "invalid target ip address %s\n", argv[3]); 2026 client = NULL; 2027 goto done; 2028 } 2029 arp_client_probe(client, arp_test, client, NULL, sender_ip, target_ip); 2030 done: 2031 return (client != NULL); 2032} 2033 2034static boolean_t 2035S_do_resolve(int argc, const char * * argv) 2036{ 2037 arp_client_t * client; 2038 int client_index; 2039 struct in_addr sender_ip; 2040 struct in_addr target_ip; 2041 2042 if (get_client_index(argv[1], &client_index) == FALSE) { 2043 fprintf(stderr, "invalid client index\n"); 2044 goto done; 2045 } 2046 client = arp_session_find_client_with_index(S_arp_session, client_index); 2047 if (client == NULL) { 2048 fprintf(stderr, "no such client index\n"); 2049 goto done; 2050 } 2051 if (inet_aton(argv[2], &sender_ip) == 0) { 2052 fprintf(stderr, "invalid sender ip address %s\n", argv[2]); 2053 client = NULL; 2054 goto done; 2055 } 2056 if (inet_aton(argv[3], &target_ip) == 0) { 2057 fprintf(stderr, "invalid target ip address %s\n", argv[3]); 2058 client = NULL; 2059 goto done; 2060 } 2061 arp_client_resolve(client, arp_test, client, NULL, sender_ip, target_ip, 0); 2062 done: 2063 return (client != NULL); 2064} 2065 2066static boolean_t 2067S_do_detect(int argc, const char * * argv) 2068{ 2069 arp_client_t * client; 2070 int client_index; 2071 uint8_t * hwaddr = NULL; 2072 int hwaddr_len; 2073 int i; 2074 arp_address_info_t *info = NULL; 2075 int info_count; 2076 2077 if (get_client_index(argv[1], &client_index) == FALSE) { 2078 fprintf(stderr, "invalid client index\n"); 2079 goto done; 2080 } 2081 client = arp_session_find_client_with_index(S_arp_session, client_index); 2082 if (client == NULL) { 2083 fprintf(stderr, "no such client index\n"); 2084 goto done; 2085 } 2086 if (((argc - 2) % 3) != 0) { 2087 fprintf(stderr, "incorrect number of arguments\n"); 2088 client = NULL; 2089 goto done; 2090 } 2091 info_count = (argc - 2) / 3; 2092 info = malloc(sizeof(*info) * info_count); 2093 for (i = 0; i < info_count; i++) { 2094 if (inet_aton(argv[3 * i + 2], &info[i].sender_ip) == 0) { 2095 fprintf(stderr, "invalid sender ip address %s\n", argv[3 * i + 2]); 2096 client = NULL; 2097 goto done; 2098 } 2099 if (inet_aton(argv[3 * i + 3], &info[i].target_ip) == 0) { 2100 fprintf(stderr, "invalid target ip address %s\n", argv[3 * i + 3]); 2101 client = NULL; 2102 goto done; 2103 } 2104 /* get the hardware address */ 2105 hwaddr = hexstrtobin(argv[3 * i + 4], &hwaddr_len); 2106 if (hwaddr == NULL 2107 || (hwaddr_len != ETHER_ADDR_LEN 2108 && hwaddr_len != FIREWIRE_EUI64_LEN)) { 2109 fprintf(stderr, "invalid hardware address %s\n", argv[3 * i + 4]); 2110 client = NULL; 2111 if (hwaddr != NULL) { 2112 free(hwaddr); 2113 } 2114 goto done; 2115 } 2116 bcopy(hwaddr, info[i].target_hardware, hwaddr_len); 2117 free(hwaddr); 2118 } 2119 arp_client_detect(client, 2120 arp_detect_callback, client, NULL, 2121 info, info_count); 2122 done: 2123 if (info != NULL) { 2124 free(info); 2125 } 2126 return (client != NULL); 2127} 2128 2129static boolean_t 2130S_free_client(int argc, const char * * argv) 2131{ 2132 arp_client_t * client; 2133 int client_index; 2134 2135 if (get_client_index(argv[1], &client_index) == FALSE) { 2136 fprintf(stderr, "invalid client index\n"); 2137 goto done; 2138 } 2139 client = arp_session_find_client_with_index(S_arp_session, client_index); 2140 if (client == NULL) { 2141 fprintf(stderr, "no such client index\n"); 2142 goto done; 2143 } 2144 arp_client_free(&client); 2145 done: 2146 return (client != NULL); 2147} 2148 2149static boolean_t 2150S_cancel_probe(int argc, const char * * argv) 2151{ 2152 arp_client_t * client; 2153 int client_index; 2154 2155 if (get_client_index(argv[1], &client_index) == FALSE) { 2156 fprintf(stderr, "invalid client index\n"); 2157 goto done; 2158 } 2159 client = arp_session_find_client_with_index(S_arp_session, client_index); 2160 if (client == NULL) { 2161 fprintf(stderr, "no such client index\n"); 2162 goto done; 2163 } 2164 arp_client_cancel(client); 2165 2166 done: 2167 return (client != NULL); 2168} 2169 2170static boolean_t 2171S_client_params(int argc, const char * * argv) 2172{ 2173 arp_client_t * client; 2174 int client_index; 2175 struct probe_info * probe_info; 2176 2177 if (get_client_index(argv[1], &client_index) == FALSE) { 2178 fprintf(stderr, "invalid client index\n"); 2179 goto done; 2180 } 2181 client = arp_session_find_client_with_index(S_arp_session, client_index); 2182 if (client == NULL) { 2183 fprintf(stderr, "no such client index\n"); 2184 goto done; 2185 } 2186 if (argc == 2) { 2187 /* display only */ 2188 } 2189 else if (strcmp(argv[2], "default") == 0) { 2190 if (argc != 3) { 2191 fprintf(stderr, "Too many parameters specified\n"); 2192 client = NULL; 2193 goto done; 2194 } 2195 arp_client_restore_default_probe_info(client); 2196 } 2197 else if (argc < 4) { 2198 fprintf(stderr, "insufficient args\n"); 2199 client = NULL; 2200 goto done; 2201 } 2202 else { 2203 char * endptr; 2204 float interval; 2205 int gratuitous_count = 0; 2206 int probe_count; 2207 struct timeval tv; 2208 2209 if (argc > 5) { 2210 fprintf(stderr, "Too many parameters specified\n"); 2211 client = NULL; 2212 goto done; 2213 } 2214 interval = strtof(argv[2], &endptr); 2215 if (endptr == argv[2] || (interval == 0 && errno != 0)) { 2216 fprintf(stderr, "Invalid probe interval specified\n"); 2217 client = NULL; 2218 goto done; 2219 } 2220 tv.tv_sec = (int)interval; 2221 tv.tv_usec = (interval - tv.tv_sec) * 1000 * 1000; 2222 if (get_int_param(argv[3], &probe_count) == FALSE) { 2223 fprintf(stderr, "Invalid probe count specified\n"); 2224 client = NULL; 2225 goto done; 2226 } 2227 if (argc == 5) { 2228 if (get_int_param(argv[4], &gratuitous_count) == FALSE) { 2229 fprintf(stderr, "Invalid gratuitous count specified\n"); 2230 client = NULL; 2231 goto done; 2232 } 2233 } 2234 arp_client_set_probe_info(client, &tv, &probe_count, 2235 &gratuitous_count); 2236 } 2237 probe_info = &client->probe_info; 2238 printf("Probe interval %d.%06d probes %d gratuitous %d\n", 2239 (int)probe_info->retry_interval.tv_sec, 2240 (int)probe_info->retry_interval.tv_usec, 2241 probe_info->probe_count, probe_info->gratuitous_count); 2242 2243 done: 2244 return (client != NULL); 2245} 2246 2247static void 2248dump_bytes(const unsigned char * buf, int buf_len) 2249{ 2250 int i; 2251 2252 for (i = 0; i < buf_len; i++) { 2253 printf("%c%02x", i == 0 ? ' ' : ':', buf[i]); 2254 } 2255 return; 2256} 2257 2258static boolean_t 2259S_list(int argc, const char * * argv) 2260{ 2261 int if_sessions_count; 2262 int i; 2263 int j; 2264 2265 if_sessions_count = dynarray_count(&S_arp_session->if_sessions); 2266 for (i = 0; i < if_sessions_count; i++) { 2267 int clients_count; 2268 arp_if_session_t * if_session; 2269 int len; 2270 2271 if_session = dynarray_element(&S_arp_session->if_sessions, i); 2272 clients_count = dynarray_count(&if_session->clients); 2273 len = arp_link_length(if_session->if_p); 2274 for (j = 0; j < clients_count; j++) { 2275 arp_client_t * client; 2276 2277 client = dynarray_element(&if_session->clients, j); 2278 printf("%d. %s", client->client_index, if_name(if_session->if_p)); 2279 switch (client->command_status) { 2280 case arp_status_none_e: 2281 printf(" idle"); 2282 break; 2283 case arp_status_unknown_e: 2284 switch (client->command) { 2285 case arp_client_command_probe_e: 2286 printf(" probing %s", inet_ntoa(client->target_ip)); 2287 break; 2288 case arp_client_command_resolve_e: 2289 printf(" resolving %s", inet_ntoa(client->target_ip)); 2290 break; 2291 case arp_client_command_detect_e: 2292 printf(" detecting"); 2293 break; 2294 default: 2295 break; 2296 } 2297 break; 2298 case arp_status_in_use_e: 2299 printf(" %s in use by", 2300 inet_ntoa(client->in_use_addr.target_ip)); 2301 dump_bytes((unsigned char *)client->in_use_addr.target_hardware, 2302 len); 2303 break; 2304 case arp_status_not_in_use_e: 2305 printf(" %s not in use", inet_ntoa(client->target_ip)); 2306 break; 2307 case arp_status_error_e: 2308 printf(" %s error encountered", inet_ntoa(client->target_ip)); 2309 break; 2310 } 2311 printf("\n"); 2312 } 2313 } 2314 return (TRUE); 2315} 2316 2317static void 2318parse_command(char * buf, struct arg_info * args) 2319{ 2320 char * arg_start = NULL; 2321 char * scan; 2322 2323 for (scan = buf; *scan != '\0'; scan++) { 2324 char ch = *scan; 2325 2326 switch (ch) { 2327 case ' ': 2328 case '\n': 2329 case '\t': 2330 *scan = '\0'; 2331 if (arg_start != NULL) { 2332 arg_info_add(args, arg_start); 2333 arg_start = NULL; 2334 } 2335 break; 2336 default: 2337 if (arg_start == NULL) { 2338 arg_start = scan; 2339 } 2340 break; 2341 } 2342 } 2343 if (arg_start != NULL) { 2344 arg_info_add(args, arg_start); 2345 } 2346 return; 2347} 2348 2349void 2350usage() 2351{ 2352 int i; 2353 2354 fprintf(stderr, "Available commands: "); 2355 for (i = 0; commands[i].command; i++) { 2356 if (commands[i].display) { 2357 fprintf(stderr, "%s%s", i == 0 ? "" : ", ", 2358 commands[i].command); 2359 } 2360 } 2361 fprintf(stderr, "\n"); 2362 return; 2363} 2364 2365static const struct command_info * 2366S_lookup_command(char * cmd) 2367{ 2368 int i; 2369 2370 for (i = 0; commands[i].command; i++) { 2371 if (strcmp(cmd, commands[i].command) == 0) { 2372 return commands + i; 2373 } 2374 } 2375 return (NULL); 2376} 2377 2378static void 2379process_command(struct arg_info * args) 2380{ 2381 boolean_t ok = TRUE; 2382 const struct command_info * cmd_info; 2383 2384 cmd_info = S_lookup_command(args->argv[0]); 2385 if (cmd_info != NULL) { 2386 if (cmd_info->argc >= args->argc) { 2387 ok = FALSE; 2388 if (cmd_info->display) { 2389 fprintf(stderr, "insufficient args\nusage:\n\t%s %s\n", 2390 args->argv[0], 2391 cmd_info->usage ? cmd_info->usage : ""); 2392 } 2393 } 2394 } 2395 else { 2396 ok = FALSE; 2397 usage(); 2398 } 2399 2400 if (ok) { 2401 if ((*cmd_info->func)(args->argc, (const char * *)args->argv) 2402 == FALSE) { 2403 fprintf(stderr, "usage:\n\t%s %s\n", 2404 args->argv[0], 2405 cmd_info->usage ? cmd_info->usage : ""); 2406 } 2407 } 2408 return; 2409} 2410 2411static void 2412display_prompt(FILE * f) 2413{ 2414 fprintf(f, "# "); 2415 fflush(f); 2416 return; 2417} 2418 2419static void 2420user_input(CFSocketRef s, CFSocketCallBackType type, 2421 CFDataRef address, const void *data, void *info) 2422{ 2423 struct arg_info args; 2424 char choice[1024 * 10]; 2425 2426 if (fgets(choice, sizeof(choice), stdin) == NULL) { 2427 exit(1); 2428 } 2429 arg_info_init(&args); 2430 parse_command(choice, &args); 2431 if (args.argv == NULL) { 2432 goto done; 2433 } 2434 process_command(&args); 2435 2436 done: 2437 arg_info_free(&args); 2438 display_prompt(stdout); 2439 return; 2440} 2441 2442static void 2443initialize_input() 2444{ 2445 CFSocketContext context = { 0, NULL, NULL, NULL, NULL }; 2446 CFRunLoopSourceRef rls = NULL; 2447 CFSocketRef socket = NULL; 2448 2449 /* context.info = NULL; */ 2450 socket = CFSocketCreateWithNative(NULL, fileno(stdin), 2451 kCFSocketReadCallBack, 2452 user_input, &context); 2453 if (socket == NULL) { 2454 fprintf(stderr, "CFSocketCreateWithNative failed\n"); 2455 exit(1); 2456 } 2457 rls = CFSocketCreateRunLoopSource(NULL, socket, 0); 2458 if (rls == NULL) { 2459 fprintf(stderr, "CFSocketCreateRunLoopSource failed\n"); 2460 exit(1); 2461 } 2462 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 2463 my_CFRelease(&rls); 2464 my_CFRelease(&socket); 2465 display_prompt(stdout); 2466 return; 2467} 2468 2469int 2470main(int argc, char * argv[]) 2471{ 2472 arp_session_values_t arp_values; 2473 int gratuitous = 0; 2474 2475 S_interfaces = ifl_init(FALSE); 2476 if (S_interfaces == NULL) { 2477 fprintf(stderr, "couldn't get interface list\n"); 2478 exit(1); 2479 } 2480 2481 /* initialize the default values structure */ 2482 bzero(&arp_values, sizeof(arp_values)); 2483 arp_values.probe_gratuitous_count = &gratuitous; 2484 S_arp_session = arp_session_init(NULL, &arp_values); 2485 if (S_arp_session == NULL) { 2486 fprintf(stderr, "arp_session_init failed\n"); 2487 exit(1); 2488 } 2489 initialize_input(); 2490 CFRunLoopRun(); 2491 exit(0); 2492} 2493#endif /* TEST_ARP_SESSION */ 2494