1/* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18#if 0 19#pragma mark == Configuration == 20#endif 21 22//=========================================================================================================================== 23// Configuration 24//=========================================================================================================================== 25 26#define DEBUG_NAME "[mDNS] " 27#define MDNS_AAAA_OVER_IPV4 1 // 1=Send AAAA & A records over IPv4 & IPv6, 0=Send AAAA over IPv6, A over IPv4. 28#define MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 1 // 1=Don't use IPv6 socket if non-link-local IPv4 available on same interface. 29#define MDNS_ENABLE_PPP 0 // 1=Enable Unicast DNS over PPP interfaces. 0=Don't enable it. 30#define MDNS_DEBUG_PACKETS 1 // 1=Enable debug output for packet send/recv if debug level high enough. 31#define MDNS_DEBUG_SHOW 1 // 1=Enable console show routines. 32#define DEBUG_USE_DEFAULT_CATEGORY 1 // Set up to use the default category (see DebugServices.h for details). 33 34#include <stdarg.h> 35#include <stddef.h> 36#include <stdio.h> 37#include <stdlib.h> 38#include <string.h> 39#include <time.h> 40 41#include "vxWorks.h" 42#include "config.h" 43 44#include <sys/types.h> 45 46#include <arpa/inet.h> 47#include <net/if.h> 48#include <net/if_dl.h> 49#include <net/if_types.h> 50#include <net/ifaddrs.h> 51#include <netinet6/in6_var.h> 52#include <netinet/if_ether.h> 53#include <netinet/in.h> 54#include <netinet/ip.h> 55#include <sys/ioctl.h> 56#include <sys/socket.h> 57#include <unistd.h> 58 59#include "ifLib.h" 60#include "inetLib.h" 61#include "pipeDrv.h" 62#include "selectLib.h" 63#include "semLib.h" 64#include "sockLib.h" 65#include "sysLib.h" 66#include "taskLib.h" 67#include "tickLib.h" 68 69#include "CommonServices.h" 70#include "DebugServices.h" 71#include "DNSCommon.h" 72#include "mDNSEmbeddedAPI.h" 73 74#include "mDNSVxWorks.h" 75 76#if 0 77#pragma mark == Constants == 78#endif 79 80//=========================================================================================================================== 81// Constants 82//=========================================================================================================================== 83 84typedef uint8_t MDNSPipeCommandCode; 85 86#define kMDNSPipeCommandCodeInvalid 0 87#define kMDNSPipeCommandCodeReschedule 1 88#define kMDNSPipeCommandCodeReconfigure 2 89#define kMDNSPipeCommandCodeQuit 3 90 91#if 0 92#pragma mark == Prototypes == 93#endif 94 95//=========================================================================================================================== 96// Prototypes 97//=========================================================================================================================== 98 99#if ( DEBUG ) 100mDNSlocal void DebugMsg( DebugLevel inLevel, const char *inFormat, ... ); 101 102 #define dmsg( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS ) 103#else 104 #define dmsg( LEVEL, ARGS... ) 105#endif 106 107#if ( DEBUG && MDNS_DEBUG_PACKETS ) 108 #define dpkt( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS ) 109#else 110 #define dpkt( LEVEL, ARGS... ) 111#endif 112 113#define ForgetSem( X ) do { if( *( X ) ) { semDelete( ( *X ) ); *( X ) = 0; } } while( 0 ) 114#define ForgetSocket( X ) do { if( IsValidSocket( *( X ) ) ) { close_compat( *( X ) ); *( X ) = kInvalidSocketRef; } } while( 0 ) 115 116// Interfaces 117 118mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC ); 119mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC ); 120mDNSlocal int SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC ); 121mDNSlocal void MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC ); 122mDNSlocal int ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing ); 123mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID ); 124mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex ); 125mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS ); 126mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP ); 127 128// Commands 129 130mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS ); 131mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS ); 132mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode ); 133mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS ); 134 135// Threads 136 137mDNSlocal void Task( mDNS *inMDNS ); 138mDNSlocal mStatus TaskInit( mDNS *inMDNS ); 139mDNSlocal void TaskTerm( mDNS *inMDNS ); 140mDNSlocal void TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout ); 141mDNSlocal void TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock ); 142mDNSlocal ssize_t 143mDNSRecvMsg( 144 SocketRef inSock, 145 void * inBuffer, 146 size_t inBufferSize, 147 void * outFrom, 148 size_t inFromSize, 149 size_t * outFromSize, 150 mDNSAddr * outDstAddr, 151 uint32_t * outIndex ); 152 153// DNSServices compatibility. When all clients move to DNS-SD, this section can be removed. 154 155#ifdef __cplusplus 156extern "C" { 157#endif 158 159typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo; 160struct mDNSPlatformInterfaceInfo 161{ 162 const char * name; 163 mDNSAddr ip; 164}; 165 166mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID ); 167mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo ); 168 169#ifdef __cplusplus 170} 171#endif 172 173#if 0 174#pragma mark == Globals == 175#endif 176 177//=========================================================================================================================== 178// Globals 179//=========================================================================================================================== 180 181debug_log_new_default_category( mdns ); 182 183mDNSexport mDNSs32 mDNSPlatformOneSecond; 184mDNSlocal mDNSs32 gMDNSTicksToMicro = 0; 185mDNSlocal mDNS * gMDNSPtr = NULL; 186mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport; 187mDNSlocal mDNSBool gMDNSDeferIPv4 = mDNSfalse; 188#if ( DEBUG ) 189DebugLevel gMDNSDebugOverrideLevel = kDebugLevelMax; 190#endif 191 192#if 0 193#pragma mark - 194#endif 195 196//=========================================================================================================================== 197// mDNSReconfigure 198//=========================================================================================================================== 199 200void mDNSReconfigure( void ) 201{ 202 if( gMDNSPtr ) SendCommand( gMDNSPtr, kMDNSPipeCommandCodeReconfigure ); 203} 204 205//=========================================================================================================================== 206// mDNSDeferIPv4 207//=========================================================================================================================== 208 209void mDNSDeferIPv4( mDNSBool inDefer ) 210{ 211 gMDNSDeferIPv4 = inDefer; 212} 213 214#if 0 215#pragma mark - 216#endif 217 218//=========================================================================================================================== 219// mDNSPlatformInit 220//=========================================================================================================================== 221 222mStatus mDNSPlatformInit( mDNS * const inMDNS ) 223{ 224 mStatus err; 225 int id; 226 227 mDNSPlatformOneSecond = sysClkRateGet(); 228 gMDNSTicksToMicro = ( 1000000L / mDNSPlatformOneSecond ); 229 230 // Do minimal initialization to get the task started and so we can cleanup safely if an error occurs. 231 232 mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) ); 233 if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport; 234 inMDNS->p->unicastSS.info = NULL; 235 inMDNS->p->unicastSS.sockV4 = kInvalidSocketRef; 236 inMDNS->p->unicastSS.sockV6 = kInvalidSocketRef; 237 inMDNS->p->initErr = mStatus_NotInitializedErr; 238 inMDNS->p->commandPipe = ERROR; 239 inMDNS->p->taskID = ERROR; 240 241 inMDNS->p->lock = semMCreate( SEM_Q_FIFO ); 242 require_action( inMDNS->p->lock, exit, err = mStatus_NoMemoryErr ); 243 244 inMDNS->p->initEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY ); 245 require_action( inMDNS->p->initEvent, exit, err = mStatus_NoMemoryErr ); 246 247 inMDNS->p->quitEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY ); 248 require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr ); 249 250 // Start the task and wait for it to initialize. The task does the full initialization from its own context 251 // to avoid potential issues with stack space and APIs that key off the current task (e.g. watchdog timers). 252 // We wait here until the init is complete because it needs to be ready to use as soon as this function returns. 253 254 id = taskSpawn( "tMDNS", 102, 0, 16384, (FUNCPTR) Task, (int) inMDNS, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 255 err = translate_errno( id != ERROR, errno_compat(), mStatus_NoMemoryErr ); 256 require_noerr( err, exit ); 257 258 err = semTake( inMDNS->p->initEvent, WAIT_FOREVER ); 259 if( err == OK ) err = inMDNS->p->initErr; 260 require_noerr( err, exit ); 261 262 gMDNSPtr = inMDNS; 263 mDNSCoreInitComplete( inMDNS, err ); 264 265exit: 266 if( err ) mDNSPlatformClose( inMDNS ); 267 return( err ); 268} 269 270//=========================================================================================================================== 271// mDNSPlatformClose 272//=========================================================================================================================== 273 274void mDNSPlatformClose( mDNS * const inMDNS ) 275{ 276 mStatus err; 277 278 check( inMDNS ); 279 280 gMDNSPtr = NULL; 281 282 // Signal the task to quit and wait for it to signal back that it exited. Timeout in 10 seconds to handle a hung thread. 283 284 if( inMDNS->p->taskID != ERROR ) 285 { 286 SendCommand( inMDNS, kMDNSPipeCommandCodeQuit ); 287 if( inMDNS->p->quitEvent ) 288 { 289 err = semTake( inMDNS->p->quitEvent, sysClkRateGet() * 10 ); 290 check_noerr( err ); 291 } 292 inMDNS->p->taskID = ERROR; 293 } 294 295 // Clean up resources set up in mDNSPlatformInit. All other resources should have been cleaned up already by TaskTerm. 296 297 ForgetSem( &inMDNS->p->quitEvent ); 298 ForgetSem( &inMDNS->p->initEvent ); 299 ForgetSem( &inMDNS->p->lock ); 300 301 dmsg( kDebugLevelNotice, DEBUG_NAME "CLOSED\n" ); 302} 303 304//=========================================================================================================================== 305// mDNSPlatformSendUDP 306//=========================================================================================================================== 307 308mStatus 309mDNSPlatformSendUDP( 310 const mDNS * const inMDNS, 311 const void * const inMsg, 312 const mDNSu8 * const inEnd, 313 mDNSInterfaceID inInterfaceID, 314 const mDNSAddr * inDstIP, 315 mDNSIPPort inDstPort ) 316{ 317 mStatus err; 318 NetworkInterfaceInfoVxWorks * info; 319 SocketRef sock; 320 struct sockaddr_storage to; 321 int n; 322 323 // Set up the sockaddr to sent to and the socket to send on. 324 325 info = (NetworkInterfaceInfoVxWorks *) inInterfaceID; 326 if( inDstIP->type == mDNSAddrType_IPv4 ) 327 { 328 struct sockaddr_in * sa4; 329 330 sa4 = (struct sockaddr_in *) &to; 331 sa4->sin_len = sizeof( *sa4 ); 332 sa4->sin_family = AF_INET; 333 sa4->sin_port = inDstPort.NotAnInteger; 334 sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger; 335 sock = info ? info->ss.sockV4 : inMDNS->p->unicastSS.sockV4; 336 } 337 else if( inDstIP->type == mDNSAddrType_IPv6 ) 338 { 339 struct sockaddr_in6 * sa6; 340 341 sa6 = (struct sockaddr_in6 *) &to; 342 sa6->sin6_len = sizeof( *sa6 ); 343 sa6->sin6_family = AF_INET6; 344 sa6->sin6_port = inDstPort.NotAnInteger; 345 sa6->sin6_flowinfo = 0; 346 sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 ); 347 sa6->sin6_scope_id = info ? info->scopeID : 0; 348 sock = info ? info->ss.sockV6 : inMDNS->p->unicastSS.sockV6; 349 } 350 else 351 { 352 dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! destination is not an IPv4 or IPv6 address\n", __ROUTINE__ ); 353 err = mStatus_BadParamErr; 354 goto exit; 355 } 356 357 // Send the packet if we've got a valid socket of this type. Note: mDNSCore may ask us to send an IPv4 packet and then 358 // an IPv6 multicast packet. If we don't have the corresponding type of socket available, quietly return an error. 359 360 n = (int)( (mDNSu8 *) inEnd - (mDNSu8 *) inMsg ); 361 if( !IsValidSocket( sock ) ) 362 { 363 dpkt( kDebugLevelChatty - 1, 364 DEBUG_NAME "DROP: %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n", 365 n, inDstIP, mDNSVal16( inDstPort ), info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, info ); 366 err = mStatus_Invalid; 367 goto exit; 368 } 369 370 dpkt( kDebugLevelChatty, 371 DEBUG_NAME "SEND %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n", 372 n, inDstIP, mDNSVal16( inDstPort ), info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, info ); 373 374 n = sendto( sock, (mDNSu8 *) inMsg, n, 0, (struct sockaddr *) &to, to.ss_len ); 375 if( n < 0 ) 376 { 377 // Don't warn about ARP failures or no route to host for unicast destinations. 378 379 err = errno_compat(); 380 if( ( ( err == EHOSTDOWN ) || ( err == ENETDOWN ) || ( err == EHOSTUNREACH ) ) && !mDNSAddressIsAllDNSLinkGroup( inDstIP ) ) 381 { 382 goto exit; 383 } 384 385 dmsg( kDebugLevelError, "%s: ERROR! sendto failed on %8s(%u) to %#a:%d, sock %d, err %d, time %u\n", 386 __ROUTINE__, info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, inDstIP, mDNSVal16( inDstPort ), 387 sock, err, (unsigned int) inMDNS->timenow ); 388 if( err == 0 ) err = mStatus_UnknownErr; 389 goto exit; 390 } 391 err = mStatus_NoError; 392 393exit: 394 return( err ); 395} 396 397//=========================================================================================================================== 398// Connection-oriented (TCP) functions 399//=========================================================================================================================== 400 401mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, 402 TCPConnectionCallback callback, void *context, int *descriptor) 403{ 404 (void)dst; // Unused 405 (void)dstport; // Unused 406 (void)InterfaceID; // Unused 407 (void)callback; // Unused 408 (void)context; // Unused 409 (void)descriptor; // Unused 410 return(mStatus_UnsupportedErr); 411} 412 413mDNSexport void mDNSPlatformTCPCloseConnection(int sd) 414{ 415 (void)sd; // Unused 416} 417 418mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen) 419{ 420 (void)sd; // Unused 421 (void)buf; // Unused 422 (void)buflen; // Unused 423 return(0); 424} 425 426mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len) 427{ 428 (void)sd; // Unused 429 (void)msg; // Unused 430 (void)len; // Unused 431 return(0); 432} 433 434//=========================================================================================================================== 435// mDNSPlatformLock 436//=========================================================================================================================== 437 438void mDNSPlatformLock( const mDNS * const inMDNS ) 439{ 440 check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" ); 441 442#if ( DEBUG ) 443 if( semTake( inMDNS->p->lock, 60 * sysClkRateGet() ) != OK ) 444 { 445 dmsg( kDebugLevelTragic, "\n### DEADLOCK DETECTED ### (sem=%#p, task=%#p)\n\n", inMDNS->p->lock, taskIdSelf() ); 446 debug_stack_trace(); // 1) Print Stack Trace. 447 semShow( inMDNS->p->lock, 1 ); // 2) Print semaphore info, including which tasks are pending on it. 448 taskSuspend( 0 ); // 3) Suspend task. Can be resumed from the console for debugging. 449 } 450#else 451 semTake( inMDNS->p->lock, WAIT_FOREVER ); 452#endif 453} 454 455//=========================================================================================================================== 456// mDNSPlatformUnlock 457//=========================================================================================================================== 458 459void mDNSPlatformUnlock( const mDNS * const inMDNS ) 460{ 461 check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" ); 462 463 // Wake up the mDNS task to handle any work initiated by an API call and to calculate the next event time. 464 // We only need to wake up if we're not already inside the task. This avoids filling up the command queue. 465 466 if( taskIdSelf() != inMDNS->p->taskID ) 467 { 468 SendCommand( inMDNS, kMDNSPipeCommandCodeReschedule ); 469 } 470 semGive( inMDNS->p->lock ); 471} 472 473//=========================================================================================================================== 474// mDNSPlatformStrLen 475//=========================================================================================================================== 476 477mDNSu32 mDNSPlatformStrLen( const void *inSrc ) 478{ 479 check( inSrc ); 480 481 return( (mDNSu32) strlen( (const char *) inSrc ) ); 482} 483 484//=========================================================================================================================== 485// mDNSPlatformStrCopy 486//=========================================================================================================================== 487 488void mDNSPlatformStrCopy( void *inDst, const void *inSrc ) 489{ 490 check( inSrc ); 491 check( inDst ); 492 493 strcpy( (char *) inDst, (const char*) inSrc ); 494} 495 496//=========================================================================================================================== 497// mDNSPlatformMemCopy 498//=========================================================================================================================== 499 500void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize ) 501{ 502 check( inSrc ); 503 check( inDst ); 504 505 memcpy( inDst, inSrc, inSize ); 506} 507 508//=========================================================================================================================== 509// mDNSPlatformMemSame 510//=========================================================================================================================== 511 512mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize ) 513{ 514 check( inSrc ); 515 check( inDst ); 516 517 return( memcmp( inSrc, inDst, inSize ) == 0 ); 518} 519 520//=========================================================================================================================== 521// mDNSPlatformMemZero 522//=========================================================================================================================== 523 524void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize ) 525{ 526 check( inDst ); 527 528 memset( inDst, 0, inSize ); 529} 530 531//=========================================================================================================================== 532// mDNSPlatformMemAllocate 533//=========================================================================================================================== 534 535mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize ) 536{ 537 void * mem; 538 539 check( inSize > 0 ); 540 541 mem = malloc( inSize ); 542 check( mem ); 543 544 return( mem ); 545} 546 547//=========================================================================================================================== 548// mDNSPlatformMemFree 549//=========================================================================================================================== 550 551mDNSexport void mDNSPlatformMemFree( void *inMem ) 552{ 553 check( inMem ); 554 if( inMem ) free( inMem ); 555} 556 557//=========================================================================================================================== 558// mDNSPlatformRandomSeed 559//=========================================================================================================================== 560 561mDNSexport mDNSu32 mDNSPlatformRandomSeed( void ) 562{ 563 return( tickGet() ); 564} 565 566//=========================================================================================================================== 567// mDNSPlatformTimeInit 568//=========================================================================================================================== 569 570mDNSexport mStatus mDNSPlatformTimeInit( void ) 571{ 572 // No special setup is required on VxWorks -- we just use tickGet(). 573 574 return( mStatus_NoError ); 575} 576 577//=========================================================================================================================== 578// mDNSPlatformRawTime 579//=========================================================================================================================== 580 581mDNSs32 mDNSPlatformRawTime( void ) 582{ 583 return( (mDNSs32) tickGet() ); 584} 585 586//=========================================================================================================================== 587// mDNSPlatformUTC 588//=========================================================================================================================== 589 590mDNSexport mDNSs32 mDNSPlatformUTC( void ) 591{ 592 return( (mDNSs32) time( NULL ) ); 593} 594 595//=========================================================================================================================== 596// mDNSPlatformInterfaceIDfromInterfaceIndex 597//=========================================================================================================================== 598 599mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS *const inMDNS, mDNSu32 inIndex ) 600{ 601 NetworkInterfaceInfoVxWorks * i; 602 603 if( inIndex == (mDNSu32) -1 ) return( mDNSInterface_LocalOnly ); 604 if( inIndex != 0 ) 605 { 606 for( i = inMDNS->p->interfaceList; i; i = i->next ) 607 { 608 // Don't get tricked by inactive interfaces with no InterfaceID set. 609 610 if( i->ifinfo.InterfaceID && ( i->scopeID == inIndex ) ) return( i->ifinfo.InterfaceID ); 611 } 612 } 613 return( NULL ); 614} 615 616//=========================================================================================================================== 617// mDNSPlatformInterfaceIndexfromInterfaceID 618//=========================================================================================================================== 619 620mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS *const inMDNS, mDNSInterfaceID inID ) 621{ 622 NetworkInterfaceInfoVxWorks * i; 623 624 if( inID == mDNSInterface_LocalOnly ) return( (mDNSu32) -1 ); 625 if( inID ) 626 { 627 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces. 628 629 for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {} 630 if( i ) return( i->scopeID ); 631 } 632 return( 0 ); 633} 634 635//=========================================================================================================================== 636// mDNSPlatformInterfaceNameToID 637//=========================================================================================================================== 638 639mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID ) 640{ 641 NetworkInterfaceInfoVxWorks * i; 642 643 for( i = inMDNS->p->interfaceList; i; i = i->next ) 644 { 645 // Don't get tricked by inactive interfaces with no InterfaceID set. 646 647 if( i->ifinfo.InterfaceID && ( strcmp( i->ifinfo.ifname, inName ) == 0 ) ) 648 { 649 *outID = (mDNSInterfaceID) i; 650 return( mStatus_NoError ); 651 } 652 } 653 return( mStatus_NoSuchNameErr ); 654} 655 656//=========================================================================================================================== 657// mDNSPlatformInterfaceIDToInfo 658//=========================================================================================================================== 659 660mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo ) 661{ 662 NetworkInterfaceInfoVxWorks * i; 663 664 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces. 665 666 for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {} 667 if( !i ) return( mStatus_NoSuchNameErr ); 668 669 outInfo->name = i->ifinfo.ifname; 670 outInfo->ip = i->ifinfo.ip; 671 return( mStatus_NoError ); 672} 673 674//=========================================================================================================================== 675// debugf_ 676//=========================================================================================================================== 677 678#if ( MDNS_DEBUGMSGS > 0 ) 679mDNSexport void debugf_( const char *inFormat, ... ) 680{ 681 char buffer[ 512 ]; 682 va_list args; 683 684 va_start( args, inFormat ); 685 mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args ); 686 va_end( args ); 687 688 dlog( kDebugLevelInfo, "%s\n", buffer ); 689} 690#endif 691 692//=========================================================================================================================== 693// verbosedebugf_ 694//=========================================================================================================================== 695 696#if ( MDNS_DEBUGMSGS > 1 ) 697mDNSexport void verbosedebugf_( const char *inFormat, ... ) 698{ 699 char buffer[ 512 ]; 700 va_list args; 701 702 va_start( args, inFormat ); 703 mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args ); 704 va_end( args ); 705 706 dlog( kDebugLevelVerbose, "%s\n", buffer ); 707} 708#endif 709 710//=========================================================================================================================== 711// LogMsg 712//=========================================================================================================================== 713 714mDNSexport void LogMsg( const char *inFormat, ... ) 715{ 716#if ( DEBUG ) 717 char buffer[ 512 ]; 718 va_list args; 719 720 va_start( args, inFormat ); 721 mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args ); 722 va_end( args ); 723 724 dlog( kDebugLevelWarning, "%s\n", buffer ); 725#else 726 DEBUG_UNUSED( inFormat ); 727#endif 728} 729 730#if ( DEBUG ) 731//=========================================================================================================================== 732// DebugMsg 733//=========================================================================================================================== 734 735mDNSlocal void DebugMsg( DebugLevel inLevel, const char *inFormat, ... ) 736{ 737 char buffer[ 512 ]; 738 va_list args; 739 740 va_start( args, inFormat ); 741 mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args ); 742 va_end( args ); 743 744 if( inLevel >= gMDNSDebugOverrideLevel ) inLevel = kDebugLevelMax; 745 dlog( inLevel, "%s", buffer ); 746} 747#endif 748 749#if 0 750#pragma mark - 751#pragma mark == Interfaces == 752#endif 753 754//=========================================================================================================================== 755// UpdateInterfaceList 756//=========================================================================================================================== 757 758#if ( MDNS_ENABLE_PPP ) 759 760// Note: This includes PPP dial-in interfaces (pppXYZ), but not PPP dial-out interface (pppdXYZ). 761 762 #define IsCompatibleInterface( IFA ) \ 763 ( ( ( IFA )->ifa_flags & IFF_UP ) && \ 764 ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \ 765 ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) && \ 766 ( !( ( IFA )->ifa_flags & IFF_POINTOPOINT ) || ( strncmp( ( IFA )->ifa_name, "pppd", 4 ) != 0 ) ) ) 767#else 768 #define IsCompatibleInterface( IFA ) \ 769 ( ( ( ( IFA )->ifa_flags & ( IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT ) ) == ( IFF_UP | IFF_MULTICAST ) ) && \ 770 ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \ 771 ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) ) 772#endif 773 774#define IsLinkLocalSockAddr( SA ) \ 775 ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \ 776 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \ 777 ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \ 778 : IN6_IS_ADDR_LINKLOCAL( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) ) 779 780#define FamilyToString( X ) \ 781 ( ( ( X ) == AF_INET ) ? "AF_INET" : \ 782 ( ( ( X ) == AF_INET6 ) ? "AF_INET6" : \ 783 ( ( ( X ) == AF_LINK ) ? "AF_LINK" : \ 784 "UNKNOWN" ) ) ) 785 786mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC ) 787{ 788 mStatus err; 789 struct ifaddrs * ifaList; 790 struct ifaddrs * ifa; 791 int family; 792 mDNSBool foundV4; 793 mDNSBool foundV6; 794 struct ifaddrs * loopbackV4; 795 struct ifaddrs * loopbackV6; 796 mDNSEthAddr primaryMAC; 797 SocketRef infoSock; 798 char defaultName[ 64 ]; 799 NetworkInterfaceInfoVxWorks * i; 800 domainlabel nicelabel; 801 domainlabel hostlabel; 802 domainlabel tmp; 803 804 ifaList = NULL; 805 foundV4 = mDNSfalse; 806 foundV6 = mDNSfalse; 807 loopbackV4 = NULL; 808 loopbackV6 = NULL; 809 primaryMAC = zeroEthAddr; 810 811 // Set up an IPv6 socket so we can check the state of interfaces using SIOCGIFAFLAG_IN6. 812 813 infoSock = socket( AF_INET6, SOCK_DGRAM, 0 ); 814 check_translated_errno( IsValidSocket( infoSock ), errno_compat(), kUnknownErr ); 815 816 // Run through the entire list of interfaces. 817 818 err = getifaddrs( &ifaList ); 819 check_translated_errno( err == 0, errno_compat(), kUnknownErr ); 820 821 for( ifa = ifaList; ifa; ifa = ifa->ifa_next ) 822 { 823 int flags; 824 825 family = ifa->ifa_addr->sa_family; 826 dmsg( kDebugLevelVerbose, DEBUG_NAME "%s: %8s(%d), Flags 0x%08X, Family %8s(%2d)\n", __ROUTINE__, 827 ifa->ifa_name, if_nametoindex( ifa->ifa_name ), ifa->ifa_flags, FamilyToString( family ), family ); 828 829 // Save off the MAC address of the first Ethernet-ish interface. 830 831 if( family == AF_LINK ) 832 { 833 struct sockaddr_dl * sdl; 834 835 sdl = (struct sockaddr_dl *) ifa->ifa_addr; 836 if( ( sdl->sdl_type == IFT_ETHER ) && ( sdl->sdl_alen == sizeof( primaryMAC ) && 837 mDNSSameEthAddress( &primaryMAC, &zeroEthAddr ) ) ) 838 { 839 memcpy( primaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6 ); 840 } 841 } 842 843 if( !IsCompatibleInterface( ifa ) ) continue; 844 845 // If this is a link-local address and there's a non-link-local address on this interface, skip this alias. 846 847 if( IsLinkLocalSockAddr( ifa->ifa_addr ) ) 848 { 849 struct ifaddrs * ifaLL; 850 851 for( ifaLL = ifaList; ifaLL; ifaLL = ifaLL->ifa_next ) 852 { 853 if( ifaLL->ifa_addr->sa_family != family ) continue; 854 if( !IsCompatibleInterface( ifaLL ) ) continue; 855 if( strcmp( ifaLL->ifa_name, ifa->ifa_name ) != 0 ) continue; 856 if( !IsLinkLocalSockAddr( ifaLL->ifa_addr ) ) break; 857 } 858 if( ifaLL ) 859 { 860 dmsg( kDebugLevelInfo, DEBUG_NAME "%s: %8s(%d) skipping link-local alias\n", __ROUTINE__, 861 ifa->ifa_name, if_nametoindex( ifa->ifa_name ) ); 862 continue; 863 } 864 } 865 866 // If this is an IPv6 interface, perform additional checks to make sure it is really ready for use. 867 // If this is a loopback interface, save it off since we may add it later if there are no other interfaces. 868 // Otherwise, add the interface to the list. 869 870 flags = 0; 871 if( ( family == AF_INET6 ) && IsValidSocket( infoSock ) ) 872 { 873 struct sockaddr_in6 * sa6; 874 struct in6_ifreq ifr6; 875 876 sa6 = (struct sockaddr_in6 *) ifa->ifa_addr; 877 mDNSPlatformMemZero( &ifr6, sizeof( ifr6 ) ); 878 strcpy( ifr6.ifr_name, ifa->ifa_name ); 879 ifr6.ifr_addr = *sa6; 880 if( ioctl( infoSock, SIOCGIFAFLAG_IN6, (int) &ifr6 ) != -1 ) 881 { 882 flags = ifr6.ifr_ifru.ifru_flags6; 883 } 884 } 885 886 // HACK: This excludes interfaces with IN6_IFF_DUPLICATED set instead of using IN6_IFF_NOTREADY (which is 887 // HACK: IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED) because we currently do not get a notification when an 888 // HACK: interface goes from the tentative state to the fully ready state. So as a short-term workaround, 889 // HACK: this allows tentative interfaces to be registered. We should revisit if we get notification hooks. 890 891 if( flags & ( IN6_IFF_DUPLICATED | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY ) ) 892 { 893 dmsg( kDebugLevelNotice, DEBUG_NAME "%s: %8s(%d), SIOCGIFAFLAG_IN6 not ready yet (0x%X)\n", __ROUTINE__, 894 ifa->ifa_name, if_nametoindex( ifa->ifa_name ), flags ); 895 continue; 896 } 897 if( ifa->ifa_flags & IFF_LOOPBACK ) 898 { 899 if( family == AF_INET ) loopbackV4 = ifa; 900 else loopbackV6 = ifa; 901 } 902 else 903 { 904 if( ( family == AF_INET ) && gMDNSDeferIPv4 && IsLinkLocalSockAddr( ifa->ifa_addr ) ) continue; 905 i = AddInterfaceToList( inMDNS, ifa, inUTC ); 906 if( i && i->multicast ) 907 { 908 if( family == AF_INET ) foundV4 = mDNStrue; 909 else foundV6 = mDNStrue; 910 } 911 } 912 } 913 914 // For efficiency, we don't register a loopback interface when other interfaces of that family are available. 915 916 if( !foundV4 && loopbackV4 ) AddInterfaceToList( inMDNS, loopbackV4, inUTC ); 917 if( !foundV6 && loopbackV6 ) AddInterfaceToList( inMDNS, loopbackV6, inUTC ); 918 freeifaddrs( ifaList ); 919 if( IsValidSocket( infoSock ) ) close_compat( infoSock ); 920 921 // The list is complete. Set the McastTxRx setting for each interface. We always send and receive using IPv4. 922 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address. 923 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large, configured network, 924 // which means there's a good chance that most or all the other devices on that network should also have v4. 925 // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half. 926 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network, 927 // so we are willing to make that sacrifice. 928 929 for( i = inMDNS->p->interfaceList; i; i = i->next ) 930 { 931 if( i->exists ) 932 { 933 mDNSBool txrx; 934 935 txrx = i->multicast && ( ( i->ifinfo.ip.type == mDNSAddrType_IPv4 ) || !FindRoutableIPv4( inMDNS, i->scopeID ) ); 936 if( i->ifinfo.McastTxRx != txrx ) 937 { 938 i->ifinfo.McastTxRx = txrx; 939 i->exists = 2; // 2=state change; need to de-register and re-register this interface. 940 } 941 } 942 } 943 944 // Set up the user-specified, friendly name, which is allowed to be full UTF-8. 945 946 mDNS_snprintf( defaultName, sizeof( defaultName ), "Device-%02X:%02X:%02X:%02X:%02X:%02X", 947 primaryMAC.b[ 0 ], primaryMAC.b[ 1 ], primaryMAC.b[ 2 ], primaryMAC.b[ 3 ], primaryMAC.b[ 4 ], primaryMAC.b[ 5 ] ); 948 949 MakeDomainLabelFromLiteralString( &nicelabel, "Put Nice Name Here" ); // $$$ Implementers: Fill in nice name of device. 950 if( nicelabel.c[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &nicelabel, defaultName ); 951 952 // Set up the RFC 1034-compliant label. If not set or it is not RFC 1034 compliant, try the user-specified nice name. 953 954 MakeDomainLabelFromLiteralString( &tmp, "Put-DNS-Name-Here" ); // $$$ Implementers: Fill in DNS name of device. 955 ConvertUTF8PstringToRFC1034HostLabel( tmp.c, &hostlabel ); 956 if( hostlabel.c[ 0 ] == 0 ) ConvertUTF8PstringToRFC1034HostLabel( nicelabel.c, &hostlabel ); 957 if( hostlabel.c[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &hostlabel, defaultName ); 958 959 // Update our globals and mDNS with the new labels. 960 961 if( !SameDomainLabelCS( inMDNS->p->userNiceLabel.c, nicelabel.c ) ) 962 { 963 dmsg( kDebugLevelInfo, DEBUG_NAME "Updating nicelabel to \"%#s\"\n", nicelabel.c ); 964 inMDNS->p->userNiceLabel = nicelabel; 965 inMDNS->nicelabel = nicelabel; 966 } 967 if( !SameDomainLabelCS( inMDNS->p->userHostLabel.c, hostlabel.c ) ) 968 { 969 dmsg( kDebugLevelInfo, DEBUG_NAME "Updating hostlabel to \"%#s\"\n", hostlabel.c ); 970 inMDNS->p->userHostLabel = hostlabel; 971 inMDNS->hostlabel = hostlabel; 972 mDNS_SetFQDN( inMDNS ); 973 } 974 return( mStatus_NoError ); 975} 976 977//=========================================================================================================================== 978// AddInterfaceToList 979//=========================================================================================================================== 980 981mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC ) 982{ 983 mStatus err; 984 mDNSAddr ip; 985 mDNSAddr mask; 986 mDNSu32 scopeID; 987 NetworkInterfaceInfoVxWorks ** p; 988 NetworkInterfaceInfoVxWorks * i; 989 990 i = NULL; 991 992 err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ip ); 993 require_noerr( err, exit ); 994 995 err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &mask ); 996 require_noerr( err, exit ); 997 998 // Search for an existing interface with the same info. If found, just return that one. 999 1000 scopeID = if_nametoindex( inIFA->ifa_name ); 1001 check( scopeID ); 1002 for( p = &inMDNS->p->interfaceList; *p; p = &( *p )->next ) 1003 { 1004 if( ( scopeID == ( *p )->scopeID ) && mDNSSameAddress( &ip, &( *p )->ifinfo.ip ) ) 1005 { 1006 dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Found existing interface %u with address %#a at %#p\n", __ROUTINE__, 1007 scopeID, &ip, *p ); 1008 ( *p )->exists = mDNStrue; 1009 i = *p; 1010 goto exit; 1011 } 1012 } 1013 1014 // Allocate the new interface info and fill it out. 1015 1016 i = (NetworkInterfaceInfoVxWorks *) calloc( 1, sizeof( *i ) ); 1017 require( i, exit ); 1018 1019 dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Making new interface %u with address %#a at %#p\n", __ROUTINE__, scopeID, &ip, i ); 1020 strncpy( i->ifinfo.ifname, inIFA->ifa_name, sizeof( i->ifinfo.ifname ) ); 1021 i->ifinfo.ifname[ sizeof( i->ifinfo.ifname ) - 1 ] = '\0'; 1022 i->ifinfo.InterfaceID = NULL; 1023 i->ifinfo.ip = ip; 1024 i->ifinfo.mask = mask; 1025 i->ifinfo.Advertise = inMDNS->AdvertiseLocalAddresses; 1026 i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList. 1027 1028 i->next = NULL; 1029 i->exists = mDNStrue; 1030 i->lastSeen = inUTC; 1031 i->scopeID = scopeID; 1032 i->family = inIFA->ifa_addr->sa_family; 1033 i->multicast = ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTOPOINT ); 1034 1035 i->ss.info = i; 1036 i->ss.sockV4 = kInvalidSocketRef; 1037 i->ss.sockV6 = kInvalidSocketRef; 1038 *p = i; 1039 1040exit: 1041 return( i ); 1042} 1043 1044//=========================================================================================================================== 1045// SetupActiveInterfaces 1046// 1047// Returns a count of non-link local IPv4 addresses registered. 1048//=========================================================================================================================== 1049 1050#define mDNSAddressIsNonLinkLocalIPv4( X ) \ 1051 ( ( ( X )->type == mDNSAddrType_IPv4 ) && ( ( ( X )->ip.v4.b[ 0 ] != 169 ) || ( ( X )->ip.v4.b[ 1 ] != 254 ) ) ) 1052 1053mDNSlocal int SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC ) 1054{ 1055 int count; 1056 NetworkInterfaceInfoVxWorks * i; 1057 1058 count = 0; 1059 for( i = inMDNS->p->interfaceList; i; i = i->next ) 1060 { 1061 NetworkInterfaceInfo * n; 1062 NetworkInterfaceInfoVxWorks * primary; 1063 1064 if( !i->exists ) continue; 1065 1066 // Search for the primary interface and sanity check it. 1067 1068 n = &i->ifinfo; 1069 primary = FindInterfaceByIndex( inMDNS, i->family, i->scopeID ); 1070 if( !primary ) 1071 { 1072 dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! didn't find %s(%u)\n", __ROUTINE__, i->ifinfo.ifname, i->scopeID ); 1073 continue; 1074 } 1075 if( n->InterfaceID && ( n->InterfaceID != (mDNSInterfaceID) primary ) ) 1076 { 1077 dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! n->InterfaceID %#p != primary %#p\n", __ROUTINE__, 1078 n->InterfaceID, primary ); 1079 n->InterfaceID = NULL; 1080 } 1081 1082 // If n->InterfaceID is set, it means we've already called mDNS_RegisterInterface() for this interface. 1083 // so we don't need to call it again. Otherwise, register the interface with mDNS. 1084 1085 if( !n->InterfaceID ) 1086 { 1087 mDNSBool flapping; 1088 1089 n->InterfaceID = (mDNSInterfaceID) primary; 1090 1091 // If lastSeen == inUTC, then this is a brand-new interface, or an interface that never went away. 1092 // If lastSeen != inUTC, then this is an old interface, that went away for (inUTC - lastSeen) seconds. 1093 // If it's is an old one that went away and came back in less than a minute, we're in a flapping scenario. 1094 1095 flapping = ( ( inUTC - i->lastSeen ) > 0 ) && ( ( inUTC - i->lastSeen ) < 60 ); 1096 mDNS_RegisterInterface( inMDNS, n, flapping ); 1097 if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count; 1098 1099 dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Registered %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__, 1100 i->ifinfo.ifname, i->scopeID, primary, &n->ip, 1101 flapping ? " (Flapping)" : "", 1102 n->InterfaceActive ? " (Primary)" : "" ); 1103 } 1104 1105 // Set up a socket if it's not already set up. If multicast is not enabled on this interface then we 1106 // don't need a socket since unicast traffic will be handled on the unicast socket. 1107 1108 if( n->McastTxRx ) 1109 { 1110 mStatus err; 1111 1112 if( ( ( i->family == AF_INET ) && !IsValidSocket( primary->ss.sockV4 ) ) || 1113 ( ( i->family == AF_INET6 ) && !IsValidSocket( primary->ss.sockV6 ) ) ) 1114 { 1115 err = SetupSocket( inMDNS, &i->ifinfo.ip, mDNStrue, i->family, &primary->ss ); 1116 check_noerr( err ); 1117 } 1118 } 1119 else 1120 { 1121 dmsg( kDebugLevelInfo, DEBUG_NAME "%s: No Tx/Rx on %8s(%u) InterfaceID %#p %#a\n", __ROUTINE__, 1122 i->ifinfo.ifname, i->scopeID, primary, &n->ip ); 1123 } 1124 } 1125 return( count ); 1126} 1127 1128//=========================================================================================================================== 1129// MarkAllInterfacesInactive 1130//=========================================================================================================================== 1131 1132mDNSlocal void MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC ) 1133{ 1134 NetworkInterfaceInfoVxWorks * i; 1135 1136 for( i = inMDNS->p->interfaceList; i; i = i->next ) 1137 { 1138 if( !i->exists ) continue; 1139 i->lastSeen = inUTC; 1140 i->exists = mDNSfalse; 1141 } 1142} 1143 1144//=========================================================================================================================== 1145// ClearInactiveInterfaces 1146// 1147// Returns count of non-link local IPv4 addresses de-registered. 1148//=========================================================================================================================== 1149 1150mDNSlocal int ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing ) 1151{ 1152 int count; 1153 NetworkInterfaceInfoVxWorks * i; 1154 NetworkInterfaceInfoVxWorks ** p; 1155 1156 // First pass: 1157 // If an interface is going away, then de-register it from mDNSCore. 1158 // We also have to de-register it if the primary interface that it's using for its InterfaceID is going away. 1159 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory 1160 // it refers to has gone away, we'll crash. Don't actually close the sockets or free the memory yet though: 1161 // When the last representative of an interface goes away mDNSCore may want to send goodbye packets on that 1162 // interface. (Not yet implemented, but a good idea anyway.). 1163 1164 count = 0; 1165 for( i = inMDNS->p->interfaceList; i; i = i->next ) 1166 { 1167 NetworkInterfaceInfoVxWorks * primary; 1168 1169 // 1. If this interface is no longer active, or its InterfaceID is changing, de-register it. 1170 1171 if( !i->ifinfo.InterfaceID ) continue; 1172 primary = FindInterfaceByIndex( inMDNS, i->family, i->scopeID ); 1173 if( ( i->exists == 0 ) || ( i->exists == 2 ) || ( i->ifinfo.InterfaceID != (mDNSInterfaceID) primary ) ) 1174 { 1175 dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Deregistering %8s(%u) InterfaceID %#p %#a%s\n", __ROUTINE__, 1176 i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip, 1177 i->ifinfo.InterfaceActive ? " (Primary)" : "" ); 1178 1179 mDNS_DeregisterInterface( inMDNS, &i->ifinfo, mDNSfalse ); 1180 i->ifinfo.InterfaceID = NULL; 1181 if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count; 1182 } 1183 } 1184 1185 // Second pass: 1186 // Now that everything that's going to de-register has done so, we can close sockets and free the memory. 1187 1188 p = &inMDNS->p->interfaceList; 1189 while( *p ) 1190 { 1191 i = *p; 1192 1193 // 2. Close all our sockets. We'll recreate them later as needed. 1194 // (We may have previously had both v4 and v6, and we may not need both any more.). 1195 1196 ForgetSocket( &i->ss.sockV4 ); 1197 ForgetSocket( &i->ss.sockV6 ); 1198 1199 // 3. If no longer active, remove the interface from the list and free its memory. 1200 1201 if( !i->exists ) 1202 { 1203 mDNSBool deleteIt; 1204 1205 if( inClosing ) 1206 { 1207 check_string( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0, "closing with in-use records!" ); 1208 deleteIt = mDNStrue; 1209 } 1210 else 1211 { 1212 if( i->lastSeen == inUTC ) i->lastSeen = inUTC - 1; 1213 deleteIt = ( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0 ) && ( ( inUTC - i->lastSeen ) >= 60 ); 1214 } 1215 dmsg( kDebugLevelInfo, DEBUG_NAME "%s: %-13s %8s(%u) InterfaceID %#p %#a Age %d%s\n", __ROUTINE__, 1216 deleteIt ? "Deleting" : "Holding", i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip, 1217 inUTC - i->lastSeen, i->ifinfo.InterfaceActive ? " (Primary)" : "" ); 1218 if( deleteIt ) 1219 { 1220 *p = i->next; 1221 free( i ); 1222 continue; 1223 } 1224 } 1225 p = &i->next; 1226 } 1227 return( count ); 1228} 1229 1230//=========================================================================================================================== 1231// FindRoutableIPv4 1232//=========================================================================================================================== 1233 1234mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID ) 1235{ 1236#if ( MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 ) 1237 NetworkInterfaceInfoVxWorks * i; 1238 1239 for( i = inMDNS->p->interfaceList; i; i = i->next ) 1240 { 1241 if( i->exists && ( i->scopeID == inScopeID ) && mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) 1242 { 1243 break; 1244 } 1245 } 1246 return( i ); 1247#else 1248 DEBUG_UNUSED( inMDNS ); 1249 DEBUG_UNUSED( inScopeID ); 1250 1251 return( NULL ); 1252#endif 1253} 1254 1255//=========================================================================================================================== 1256// FindInterfaceByIndex 1257//=========================================================================================================================== 1258 1259mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex ) 1260{ 1261 NetworkInterfaceInfoVxWorks * i; 1262 1263 check( inIndex != 0 ); 1264 1265 for( i = inMDNS->p->interfaceList; i; i = i->next ) 1266 { 1267 if( i->exists && ( i->scopeID == inIndex ) && 1268 ( MDNS_AAAA_OVER_IPV4 || 1269 ( ( inFamily == AF_INET ) && ( i->ifinfo.ip.type == mDNSAddrType_IPv4 ) ) || 1270 ( ( inFamily == AF_INET6 ) && ( i->ifinfo.ip.type == mDNSAddrType_IPv6 ) ) ) ) 1271 { 1272 return( i ); 1273 } 1274 } 1275 return( NULL ); 1276} 1277 1278//=========================================================================================================================== 1279// SetupSocket 1280//=========================================================================================================================== 1281 1282mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS ) 1283{ 1284 mStatus err; 1285 SocketRef * sockPtr; 1286 mDNSIPPort port; 1287 SocketRef sock; 1288 const int on = 1; 1289 1290 check( inAddr ); 1291 check( inSS ); 1292 1293 sockPtr = ( inFamily == AF_INET ) ? &inSS->sockV4 : &inSS->sockV6; 1294 port = ( inMcast || inMDNS->CanReceiveUnicastOn5353 ) ? MulticastDNSPort : zeroIPPort; 1295 1296 sock = socket( inFamily, SOCK_DGRAM, IPPROTO_UDP ); 1297 err = translate_errno( IsValidSocket( sock ), errno_compat(), mStatus_UnknownErr ); 1298 require_noerr( err, exit ); 1299 1300 // Allow multiple listeners if this is a multicast port. 1301 1302 if( port.NotAnInteger ) 1303 { 1304 err = setsockopt( sock, SOL_SOCKET, SO_REUSEPORT, (char *) &on, sizeof( on ) ); 1305 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1306 } 1307 1308 // Set up the socket based on the family (IPv4 or IPv6). 1309 1310 if( inFamily == AF_INET ) 1311 { 1312 const int ttlV4 = 255; 1313 const u_char ttlV4Mcast = 255; 1314 struct sockaddr_in sa4; 1315 1316 // Receive destination addresses so we know which address the packet was sent to. 1317 1318 err = setsockopt( sock, IPPROTO_IP, IP_RECVDSTADDR, (char *) &on, sizeof( on ) ); 1319 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1320 1321 // Receive interface indexes so we know which interface received the packet. 1322 1323 err = setsockopt( sock, IPPROTO_IP, IP_RECVIF, (char *) &on, sizeof( on ) ); 1324 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1325 1326 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving. 1327 1328 if( inMcast ) 1329 { 1330 struct in_addr addrV4; 1331 struct ip_mreq mreqV4; 1332 1333 addrV4.s_addr = inAddr->ip.v4.NotAnInteger; 1334 mreqV4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger; 1335 mreqV4.imr_interface = addrV4; 1336 err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqV4, sizeof( mreqV4 ) ); 1337 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1338 1339 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addrV4, sizeof( addrV4 ) ); 1340 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1341 } 1342 1343 // Send unicast packets with TTL 255 (helps against spoofing). 1344 1345 err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &ttlV4, sizeof( ttlV4 ) ); 1346 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1347 1348 // Send multicast packets with TTL 255 (helps against spoofing). 1349 1350 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttlV4Mcast, sizeof( ttlV4Mcast ) ); 1351 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1352 1353 // Start listening for packets. 1354 1355 mDNSPlatformMemZero( &sa4, sizeof( sa4 ) ); 1356 sa4.sin_len = sizeof( sa4 ); 1357 sa4.sin_family = AF_INET; 1358 sa4.sin_port = port.NotAnInteger; 1359 sa4.sin_addr.s_addr = htonl( INADDR_ANY ); // We want to receive multicasts AND unicasts on this socket. 1360 err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) ); 1361 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1362 } 1363 else if( inFamily == AF_INET6 ) 1364 { 1365 struct sockaddr_in6 sa6; 1366 const int ttlV6 = 255; 1367 1368 // Receive destination addresses and interface index so we know where the packet was received and intended. 1369 1370 err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &on, sizeof( on ) ); 1371 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1372 1373 // Receive only IPv6 packets because otherwise, we may get IPv4 addresses as IPv4-mapped IPv6 addresses. 1374 1375 err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, sizeof( on ) ); 1376 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1377 1378 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving. 1379 1380 if( inMcast ) 1381 { 1382 u_int ifindex; 1383 struct ipv6_mreq mreqV6; 1384 1385 ifindex = inSS->info->scopeID; 1386 mreqV6.ipv6mr_interface = ifindex; 1387 mreqV6.ipv6mr_multiaddr = *( (struct in6_addr * ) &AllDNSLinkGroup_v6.ip.v6 ); 1388 err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqV6, sizeof( mreqV6 ) ); 1389 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1390 1391 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &ifindex, sizeof( ifindex ) ); 1392 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1393 } 1394 1395 // Send unicast packets with TTL 255 (helps against spoofing). 1396 1397 err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) ); 1398 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1399 1400 // Send multicast packets with TTL 255 (helps against spoofing). 1401 1402 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) ); 1403 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1404 1405 // Receive our own packets for same-machine operation. 1406 1407 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &on, sizeof( on ) ); 1408 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1409 1410 // Start listening for packets. 1411 1412 mDNSPlatformMemZero( &sa6, sizeof( sa6 ) ); 1413 sa6.sin6_len = sizeof( sa6 ); 1414 sa6.sin6_family = AF_INET6; 1415 sa6.sin6_port = port.NotAnInteger; 1416 sa6.sin6_flowinfo = 0; 1417 sa6.sin6_addr = in6addr_any; // We want to receive multicasts AND unicasts on this socket. 1418 sa6.sin6_scope_id = 0; 1419 err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) ); 1420 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1421 } 1422 else 1423 { 1424 dmsg( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inFamily ); 1425 err = kUnsupportedErr; 1426 goto exit; 1427 } 1428 1429 // Make the socket non-blocking so we can potentially get multiple packets per select call. 1430 1431 err = ioctl( sock, FIONBIO, (int) &on ); 1432 check_translated_errno( err == 0, errno_compat(), kOptionErr ); 1433 1434 *sockPtr = sock; 1435 sock = kInvalidSocketRef; 1436 err = mStatus_NoError; 1437 1438exit: 1439 if( IsValidSocket( sock ) ) close_compat( sock ); 1440 return( err ); 1441} 1442 1443//=========================================================================================================================== 1444// SockAddrToMDNSAddr 1445//=========================================================================================================================== 1446 1447mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP ) 1448{ 1449 mStatus err; 1450 1451 check( inSA ); 1452 check( outIP ); 1453 1454 if( inSA->sa_family == AF_INET ) 1455 { 1456 struct sockaddr_in * sa4; 1457 1458 sa4 = (struct sockaddr_in *) inSA; 1459 outIP->type = mDNSAddrType_IPv4; 1460 outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr; 1461 err = mStatus_NoError; 1462 } 1463 else if( inSA->sa_family == AF_INET6 ) 1464 { 1465 struct sockaddr_in6 * sa6; 1466 1467 sa6 = (struct sockaddr_in6 *) inSA; 1468 outIP->type = mDNSAddrType_IPv6; 1469 outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr ); 1470 if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) ) outIP->ip.v6.w[ 1 ] = 0; 1471 err = mStatus_NoError; 1472 } 1473 else 1474 { 1475 dmsg( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family (%d)\n", __ROUTINE__, inSA->sa_family ); 1476 err = mStatus_BadParamErr; 1477 } 1478 return( err ); 1479} 1480 1481#if 0 1482#pragma mark - 1483#pragma mark == Commands == 1484#endif 1485 1486//=========================================================================================================================== 1487// SetupCommandPipe 1488//=========================================================================================================================== 1489 1490mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS ) 1491{ 1492 mStatus err; 1493 1494 err = pipeDevCreate( "/pipe/mDNS", 32, 1 ); 1495 check_translated_errno( err == 0, errno_compat(), kUnknownErr ); 1496 1497 inMDNS->p->commandPipe = open( "/pipe/mDNS", O_RDWR, 0 ); 1498 err = translate_errno( inMDNS->p->commandPipe != ERROR, errno_compat(), mStatus_UnsupportedErr ); 1499 require_noerr( err, exit ); 1500 1501exit: 1502 return( err ); 1503} 1504 1505//=========================================================================================================================== 1506// TearDownCommandPipe 1507//=========================================================================================================================== 1508 1509mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS ) 1510{ 1511 mStatus err; 1512 1513 if( inMDNS->p->commandPipe != ERROR ) 1514 { 1515 err = close( inMDNS->p->commandPipe ); 1516 check_translated_errno( err == 0, errno_compat(), kUnknownErr ); 1517 inMDNS->p->commandPipe = ERROR; 1518 1519 err = pipeDevDelete( "/pipe/mDNS", FALSE ); 1520 check_translated_errno( err == 0, errno_compat(), kUnknownErr ); 1521 } 1522 return( mStatus_NoError ); 1523} 1524 1525//=========================================================================================================================== 1526// SendCommand 1527//=========================================================================================================================== 1528 1529mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode ) 1530{ 1531 mStatus err; 1532 1533 require_action_quiet( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr ); 1534 1535 err = write( inMDNS->p->commandPipe, &inCommandCode, sizeof( inCommandCode ) ); 1536 err = translate_errno( err >= 0, errno_compat(), kWriteErr ); 1537 require_noerr( err, exit ); 1538 1539exit: 1540 return( err ); 1541} 1542 1543//=========================================================================================================================== 1544// ProcessCommand 1545//=========================================================================================================================== 1546 1547mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS ) 1548{ 1549 mStatus err; 1550 MDNSPipeCommandCode cmd; 1551 mDNSs32 utc; 1552 1553 err = read( inMDNS->p->commandPipe, &cmd, sizeof( cmd ) ); 1554 err = translate_errno( err >= 0, errno_compat(), kReadErr ); 1555 require_noerr( err, exit ); 1556 1557 switch( cmd ) 1558 { 1559 case kMDNSPipeCommandCodeReschedule: // Reschedule: just break out to re-run mDNS_Execute. 1560 break; 1561 1562 case kMDNSPipeCommandCodeReconfigure: // Reconfigure: rebuild the interface list after a config change. 1563 dmsg( kDebugLevelInfo, DEBUG_NAME "*** NETWORK CONFIGURATION CHANGE ***\n" ); 1564 mDNSPlatformLock( inMDNS ); 1565 1566 utc = mDNSPlatformUTC(); 1567 MarkAllInterfacesInactive( inMDNS, utc ); 1568 UpdateInterfaceList( inMDNS, utc ); 1569 ClearInactiveInterfaces( inMDNS, utc, mDNSfalse ); 1570 SetupActiveInterfaces( inMDNS, utc ); 1571 1572 mDNSPlatformUnlock( inMDNS ); 1573 mDNS_ConfigChanged(inMDNS); 1574 break; 1575 1576 case kMDNSPipeCommandCodeQuit: // Quit: just set a flag so the task exits cleanly. 1577 inMDNS->p->quit = mDNStrue; 1578 break; 1579 1580 default: 1581 dmsg( kDebugLevelError, DEBUG_NAME "unknown pipe command (%d)\n", cmd ); 1582 err = mStatus_BadParamErr; 1583 goto exit; 1584 } 1585 1586exit: 1587 return( err ); 1588} 1589 1590#if 0 1591#pragma mark - 1592#pragma mark == Threads == 1593#endif 1594 1595//=========================================================================================================================== 1596// Task 1597//=========================================================================================================================== 1598 1599mDNSlocal void Task( mDNS *inMDNS ) 1600{ 1601 mStatus err; 1602 mDNSs32 nextEvent; 1603 fd_set readSet; 1604 int maxFd; 1605 struct timeval timeout; 1606 NetworkInterfaceInfoVxWorks * i; 1607 int fd; 1608 int n; 1609 1610 check( inMDNS ); 1611 1612 err = TaskInit( inMDNS ); 1613 require_noerr( err, exit ); 1614 1615 while( !inMDNS->p->quit ) 1616 { 1617 // Let mDNSCore do its work then wait for an event. On idle timeouts (n == 0), just loop back to mDNS_Exceute. 1618 1619 nextEvent = mDNS_Execute( inMDNS ); 1620 TaskSetupSelect( inMDNS, &readSet, &maxFd, nextEvent, &timeout ); 1621 n = select( maxFd + 1, &readSet, NULL, NULL, &timeout ); 1622 check_translated_errno( n >= 0, errno_compat(), kUnknownErr ); 1623 if( n == 0 ) continue; 1624 1625 // Process interface-specific sockets with pending data. 1626 1627 n = 0; 1628 for( i = inMDNS->p->interfaceList; i; i = i->next ) 1629 { 1630 fd = i->ss.sockV4; 1631 if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) ) 1632 { 1633 TaskProcessPackets( inMDNS, &i->ss, fd ); 1634 ++n; 1635 } 1636 fd = i->ss.sockV6; 1637 if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) ) 1638 { 1639 TaskProcessPackets( inMDNS, &i->ss, fd ); 1640 ++n; 1641 } 1642 } 1643 1644 // Process unicast sockets with pending data. 1645 1646 fd = inMDNS->p->unicastSS.sockV4; 1647 if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) ) 1648 { 1649 TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd ); 1650 ++n; 1651 } 1652 fd = inMDNS->p->unicastSS.sockV6; 1653 if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) ) 1654 { 1655 TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd ); 1656 ++n; 1657 } 1658 1659 // Processing pending commands. 1660 1661 fd = inMDNS->p->commandPipe; 1662 check( fd >= 0 ); 1663 if( FD_ISSET( fd, &readSet ) ) 1664 { 1665 ProcessCommand( inMDNS ); 1666 ++n; 1667 } 1668 check_string( n > 0, "select said something was readable, but nothing was" ); 1669 } 1670 1671exit: 1672 TaskTerm( inMDNS ); 1673} 1674 1675//=========================================================================================================================== 1676// TaskInit 1677//=========================================================================================================================== 1678 1679mDNSlocal mStatus TaskInit( mDNS *inMDNS ) 1680{ 1681 mStatus err; 1682 mDNSs32 utc; 1683 socklen_t len; 1684 1685 inMDNS->p->taskID = taskIdSelf(); 1686 1687 err = SetupCommandPipe( inMDNS ); 1688 require_noerr( err, exit ); 1689 1690 inMDNS->CanReceiveUnicastOn5353 = mDNStrue; 1691 1692 // Set up the HINFO string using the description property (e.g. "Device V1.0"). 1693 1694 inMDNS->HIHardware.c[ 0 ] = 11; 1695 memcpy( &inMDNS->HIHardware.c[ 1 ], "Device V1.0", inMDNS->HIHardware.c[ 0 ] ); // $$$ Implementers: Fill in real info. 1696 1697 // Set up the unicast sockets. 1698 1699 err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET, &inMDNS->p->unicastSS ); 1700 check_noerr( err ); 1701 if( err == mStatus_NoError ) 1702 { 1703 struct sockaddr_in sa4; 1704 1705 len = sizeof( sa4 ); 1706 err = getsockname( inMDNS->p->unicastSS.sockV4, (struct sockaddr *) &sa4, &len ); 1707 check_translated_errno( err == 0, errno_compat(), kUnknownErr ); 1708 if( err == 0 ) inMDNS->UnicastPort4.NotAnInteger = sa4.sin_port; 1709 } 1710 1711 err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET6, &inMDNS->p->unicastSS ); 1712 check_noerr( err ); 1713 if( err == mStatus_NoError ) 1714 { 1715 struct sockaddr_in6 sa6; 1716 1717 len = sizeof( sa6 ); 1718 err = getsockname( inMDNS->p->unicastSS.sockV6, (struct sockaddr *) &sa6, &len ); 1719 check_translated_errno( err == 0, errno_compat(), kUnknownErr ); 1720 if( err == 0 ) inMDNS->UnicastPort6.NotAnInteger = sa6.sin6_port; 1721 } 1722 1723 // Set up the interfaces. 1724 1725 utc = mDNSPlatformUTC(); 1726 UpdateInterfaceList( inMDNS, utc ); 1727 SetupActiveInterfaces( inMDNS, utc ); 1728 err = mStatus_NoError; 1729 1730exit: 1731 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not). 1732 1733 inMDNS->p->initErr = err; 1734 semGive( inMDNS->p->initEvent ); 1735 return( err ); 1736} 1737 1738//=========================================================================================================================== 1739// TaskTerm 1740//=========================================================================================================================== 1741 1742mDNSlocal void TaskTerm( mDNS *inMDNS ) 1743{ 1744 mStatus err; 1745 mDNSs32 utc; 1746 1747 // Tear down all interfaces. 1748 1749 utc = mDNSPlatformUTC(); 1750 MarkAllInterfacesInactive( inMDNS, utc ); 1751 ClearInactiveInterfaces( inMDNS, utc, mDNStrue ); 1752 check_string( !inMDNS->p->interfaceList, "LEAK: closing without deleting all interfaces" ); 1753 1754 // Close unicast sockets. 1755 1756 ForgetSocket( &inMDNS->p->unicastSS.sockV4); 1757 ForgetSocket( &inMDNS->p->unicastSS.sockV6 ); 1758 1759 // Tear down everything else that was set up in TaskInit then signal back that we're done. 1760 1761 err = TearDownCommandPipe( inMDNS ); 1762 check_noerr( err ); 1763 1764 err = semGive( inMDNS->p->quitEvent ); 1765 check_translated_errno( err == 0, errno_compat(), kUnknownErr ); 1766} 1767 1768//=========================================================================================================================== 1769// TaskSetupSelect 1770//=========================================================================================================================== 1771 1772mDNSlocal void TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout ) 1773{ 1774 NetworkInterfaceInfoVxWorks * i; 1775 int maxFd; 1776 int fd; 1777 mDNSs32 delta; 1778 1779 FD_ZERO( outSet ); 1780 maxFd = -1; 1781 1782 // Add the interface-specific sockets. 1783 1784 for( i = inMDNS->p->interfaceList; i; i = i->next ) 1785 { 1786 fd = i->ss.sockV4; 1787 if( IsValidSocket( fd ) ) 1788 { 1789 FD_SET( fd, outSet ); 1790 if( fd > maxFd ) maxFd = fd; 1791 } 1792 1793 fd = i->ss.sockV6; 1794 if( IsValidSocket( fd ) ) 1795 { 1796 FD_SET( fd, outSet ); 1797 if( fd > maxFd ) maxFd = fd; 1798 } 1799 } 1800 1801 // Add the unicast sockets. 1802 1803 fd = inMDNS->p->unicastSS.sockV4; 1804 if( IsValidSocket( fd ) ) 1805 { 1806 FD_SET( fd, outSet ); 1807 if( fd > maxFd ) maxFd = fd; 1808 } 1809 1810 fd = inMDNS->p->unicastSS.sockV6; 1811 if( IsValidSocket( fd ) ) 1812 { 1813 FD_SET( fd, outSet ); 1814 if( fd > maxFd ) maxFd = fd; 1815 } 1816 1817 // Add the command pipe. 1818 1819 fd = inMDNS->p->commandPipe; 1820 check( fd >= 0 ); 1821 FD_SET( fd, outSet ); 1822 if( fd > maxFd ) maxFd = fd; 1823 1824 check( maxFd > 0 ); 1825 *outMaxFd = maxFd; 1826 1827 // Calculate how long to wait before performing idle processing. 1828 1829 delta = inNextEvent - mDNS_TimeNow( inMDNS ); 1830 if( delta <= 0 ) 1831 { 1832 // The next task time is now or in the past. Set the timeout to fire immediately. 1833 1834 outTimeout->tv_sec = 0; 1835 outTimeout->tv_usec = 0; 1836 } 1837 else 1838 { 1839 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder 1840 // before multiplying to account for integer rounding error and avoid firing the timeout too early. 1841 1842 outTimeout->tv_sec = delta / mDNSPlatformOneSecond; 1843 outTimeout->tv_usec = ( ( delta % mDNSPlatformOneSecond ) + 1 ) * gMDNSTicksToMicro; 1844 if( outTimeout->tv_usec >= 1000000L ) 1845 { 1846 outTimeout->tv_sec += 1; 1847 outTimeout->tv_usec = 0; 1848 } 1849 } 1850} 1851 1852//=========================================================================================================================== 1853// TaskProcessPackets 1854//=========================================================================================================================== 1855 1856mDNSlocal void TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock ) 1857{ 1858 mDNSu32 ifindex; 1859 ssize_t n; 1860 mDNSu8 * buf; 1861 size_t size; 1862 struct sockaddr_storage from; 1863 size_t fromSize; 1864 mDNSAddr destAddr; 1865 mDNSAddr senderAddr; 1866 mDNSIPPort senderPort; 1867 mDNSInterfaceID id; 1868 1869 buf = (mDNSu8 *) &inMDNS->imsg; 1870 size = sizeof( inMDNS->imsg ); 1871 for( ;; ) 1872 { 1873 ifindex = 0; 1874 n = mDNSRecvMsg( inSock, buf, size, &from, sizeof( from ), &fromSize, &destAddr, &ifindex ); 1875 if( n < 0 ) break; 1876 if( from.ss_family == AF_INET ) 1877 { 1878 struct sockaddr_in * sa4; 1879 1880 sa4 = (struct sockaddr_in *) &from; 1881 senderAddr.type = mDNSAddrType_IPv4; 1882 senderAddr.ip.v4.NotAnInteger = sa4->sin_addr.s_addr; 1883 senderPort.NotAnInteger = sa4->sin_port; 1884 } 1885 else if( from.ss_family == AF_INET6 ) 1886 { 1887 struct sockaddr_in6 * sa6; 1888 1889 sa6 = (struct sockaddr_in6 *) &from; 1890 senderAddr.type = mDNSAddrType_IPv6; 1891 senderAddr.ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr ); 1892 senderPort.NotAnInteger = sa6->sin6_port; 1893 } 1894 else 1895 { 1896 dmsg( kDebugLevelWarning, DEBUG_NAME "%s: WARNING! from addr unknown family %d\n", __ROUTINE__, from.ss_family ); 1897 continue; 1898 } 1899 1900 // Even though we indicated a specific interface when joining the multicast group, a weirdness of the 1901 // sockets API means that even though this socket has only officially joined the multicast group 1902 // on one specific interface, the kernel will still deliver multicast packets to it no matter which 1903 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug. 1904 // To work around this weirdness, we use the IP_RECVIF/IPV6_PKTINFO options to find the interface 1905 // on which the packet arrived, and ignore the packet if it really arrived on some other interface. 1906 1907 if( mDNSAddrIsDNSMulticast( &destAddr ) ) 1908 { 1909 if( !inSS->info || !inSS->info->exists ) 1910 { 1911 dpkt( kDebugLevelChatty - 3, DEBUG_NAME " ignored mcast, src=[%#39a], dst=[%#39a], if= unicast socket %d\n", 1912 &senderAddr, &destAddr, inSock ); 1913 continue; 1914 } 1915 if( ifindex != inSS->info->scopeID ) 1916 { 1917 #if ( DEBUG && MDNS_DEBUG_PACKETS ) 1918 char ifname[ IF_NAMESIZE ]; 1919 #endif 1920 1921 dpkt( kDebugLevelChatty - 3, 1922 DEBUG_NAME " ignored mcast, src=[%#39a] dst=[%#39a], if=%8s(%u) -- really for %8s(%u)\n", 1923 &senderAddr, &destAddr, inSS->info->ifinfo.ifname, inSS->info->scopeID, 1924 if_indextoname( ifindex, ifname ), ifindex ); 1925 continue; 1926 } 1927 1928 id = inSS->info->ifinfo.InterfaceID; 1929 dpkt( kDebugLevelChatty - 2, DEBUG_NAME "recv %4d bytes, src=[%#39a]:%5hu, dst=[%#39a], if=%8s(%u) %#p\n", 1930 n, &senderAddr, mDNSVal16( senderPort ), &destAddr, inSS->info->ifinfo.ifname, inSS->info->scopeID, id ); 1931 } 1932 else 1933 { 1934 NetworkInterfaceInfoVxWorks * i; 1935 1936 // For unicast packets, try to find the matching interface. 1937 1938 for( i = inMDNS->p->interfaceList; i && ( i->scopeID != ifindex ); i = i->next ) {} 1939 if( i ) id = i->ifinfo.InterfaceID; 1940 else id = NULL; 1941 } 1942 mDNSCoreReceive( inMDNS, buf, buf + n, &senderAddr, senderPort, &destAddr, MulticastDNSPort, id ); 1943 } 1944} 1945 1946//=========================================================================================================================== 1947// mDNSRecvMsg 1948//=========================================================================================================================== 1949 1950mDNSlocal ssize_t 1951mDNSRecvMsg( 1952 SocketRef inSock, 1953 void * inBuffer, 1954 size_t inBufferSize, 1955 void * outFrom, 1956 size_t inFromSize, 1957 size_t * outFromSize, 1958 mDNSAddr * outDstAddr, 1959 uint32_t * outIndex ) 1960{ 1961 struct msghdr msg; 1962 struct iovec iov; 1963 ssize_t n; 1964 char ancillary[ 1024 ]; 1965 struct cmsghdr * cmPtr; 1966 int err; 1967 1968 // Read a packet and any ancillary data. Note: EWOULDBLOCK errors are expected when we've read all pending packets. 1969 1970 iov.iov_base = (char *) inBuffer; 1971 iov.iov_len = inBufferSize; 1972 msg.msg_name = (caddr_t) outFrom; 1973 msg.msg_namelen = inFromSize; 1974 msg.msg_iov = &iov; 1975 msg.msg_iovlen = 1; 1976 msg.msg_control = (caddr_t) &ancillary; 1977 msg.msg_controllen = sizeof( ancillary ); 1978 msg.msg_flags = 0; 1979 n = recvmsg( inSock, &msg, 0 ); 1980 if( n < 0 ) 1981 { 1982 err = errno_compat(); 1983 if( err != EWOULDBLOCK ) dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) returned %d, errno %d\n", 1984 __ROUTINE__, inSock, n, err ); 1985 goto exit; 1986 } 1987 if( msg.msg_controllen < sizeof( struct cmsghdr ) ) 1988 { 1989 dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) msg_controllen %d < sizeof( struct cmsghdr ) %u\n", 1990 __ROUTINE__, inSock, msg.msg_controllen, sizeof( struct cmsghdr ) ); 1991 n = mStatus_UnknownErr; 1992 goto exit; 1993 } 1994 if( msg.msg_flags & MSG_CTRUNC ) 1995 { 1996 dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) MSG_CTRUNC (%d recv'd)\n", __ROUTINE__, inSock, n ); 1997 n = mStatus_BadFlagsErr; 1998 goto exit; 1999 } 2000 *outFromSize = msg.msg_namelen; 2001 2002 // Parse each option out of the ancillary data. 2003 2004 for( cmPtr = CMSG_FIRSTHDR( &msg ); cmPtr; cmPtr = CMSG_NXTHDR( &msg, cmPtr ) ) 2005 { 2006 if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVDSTADDR ) ) 2007 { 2008 outDstAddr->type = mDNSAddrType_IPv4; 2009 outDstAddr->ip.v4.NotAnInteger = *( (mDNSu32 *) CMSG_DATA( cmPtr ) ); 2010 } 2011 else if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVIF ) ) 2012 { 2013 struct sockaddr_dl * sdl; 2014 2015 sdl = (struct sockaddr_dl *) CMSG_DATA( cmPtr ); 2016 *outIndex = sdl->sdl_index; 2017 } 2018 else if( ( cmPtr->cmsg_level == IPPROTO_IPV6 ) && ( cmPtr->cmsg_type == IPV6_PKTINFO ) ) 2019 { 2020 struct in6_pktinfo * pi6; 2021 2022 pi6 = (struct in6_pktinfo *) CMSG_DATA( cmPtr ); 2023 outDstAddr->type = mDNSAddrType_IPv6; 2024 outDstAddr->ip.v6 = *( (mDNSv6Addr *) &pi6->ipi6_addr ); 2025 *outIndex = pi6->ipi6_ifindex; 2026 } 2027 } 2028 2029exit: 2030 return( n ); 2031} 2032 2033#if 0 2034#pragma mark - 2035#pragma mark == Debugging == 2036#endif 2037 2038#if ( DEBUG && MDNS_DEBUG_SHOW ) 2039//=========================================================================================================================== 2040// mDNSShow 2041//=========================================================================================================================== 2042 2043void mDNSShow( void ); 2044 2045void mDNSShow( void ) 2046{ 2047 NetworkInterfaceInfoVxWorks * i; 2048 int num; 2049 AuthRecord * r; 2050 mDNSs32 utc; 2051 2052 // Globals 2053 2054 dmsg( kDebugLevelMax, "\n-- mDNS globals --\n" ); 2055 dmsg( kDebugLevelMax, " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS ) ); 2056 dmsg( kDebugLevelMax, " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord ) ); 2057 dmsg( kDebugLevelMax, " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord ) ); 2058 dmsg( kDebugLevelMax, " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord ) ); 2059 dmsg( kDebugLevelMax, " mDNSPlatformOneSecond = %ld\n", mDNSPlatformOneSecond ); 2060 dmsg( kDebugLevelMax, " gMDNSTicksToMicro = %ld\n", gMDNSTicksToMicro ); 2061 dmsg( kDebugLevelMax, " gMDNSPtr = %#p\n", gMDNSPtr ); 2062 if( !gMDNSPtr ) 2063 { 2064 dmsg( kDebugLevelMax, "### mDNS not initialized\n" ); 2065 return; 2066 } 2067 dmsg( kDebugLevelMax, " nicelabel = \"%#s\"\n", gMDNSPtr->nicelabel.c ); 2068 dmsg( kDebugLevelMax, " hostLabel = \"%#s\"\n", gMDNSPtr->hostlabel.c ); 2069 dmsg( kDebugLevelMax, " MulticastHostname = \"%##s\"\n", gMDNSPtr->MulticastHostname.c ); 2070 dmsg( kDebugLevelMax, " HIHardware = \"%#s\"\n", gMDNSPtr->HIHardware.c ); 2071 dmsg( kDebugLevelMax, " HISoftware = \"%#s\"\n", gMDNSPtr->HISoftware.c ); 2072 dmsg( kDebugLevelMax, " UnicastPort4/6 = %d/%d\n", 2073 mDNSVal16( gMDNSPtr->UnicastPort4 ), mDNSVal16( gMDNSPtr->UnicastPort6 ) ); 2074 dmsg( kDebugLevelMax, " unicastSS.sockV4/V6 = %d/%d\n", 2075 gMDNSPtr->p->unicastSS.sockV4, gMDNSPtr->p->unicastSS.sockV6 ); 2076 dmsg( kDebugLevelMax, " lock = %#p\n", gMDNSPtr->p->lock ); 2077 dmsg( kDebugLevelMax, " initEvent = %#p\n", gMDNSPtr->p->initEvent ); 2078 dmsg( kDebugLevelMax, " initErr = %ld\n", gMDNSPtr->p->initErr ); 2079 dmsg( kDebugLevelMax, " quitEvent = %#p\n", gMDNSPtr->p->quitEvent ); 2080 dmsg( kDebugLevelMax, " commandPipe = %d\n", gMDNSPtr->p->commandPipe ); 2081 dmsg( kDebugLevelMax, " taskID = %#p\n", gMDNSPtr->p->taskID ); 2082 dmsg( kDebugLevelMax, "\n" ); 2083 2084 // Interfaces 2085 2086 utc = mDNSPlatformUTC(); 2087 dmsg( kDebugLevelMax, "-- mDNS interfaces --\n" ); 2088 num = 0; 2089 for( i = gMDNSPtr->p->interfaceList; i; i = i->next ) 2090 { 2091 dmsg( kDebugLevelMax, " interface %2d %8s(%u) [%#39a] %s, sockV4 %2d, sockV6 %2d, Age %d\n", 2092 num, i->ifinfo.ifname, i->scopeID, &i->ifinfo.ip, 2093 i->ifinfo.InterfaceID ? " REGISTERED" : "*NOT* registered", 2094 i->ss.sockV4, i->ss.sockV6, utc - i->lastSeen ); 2095 ++num; 2096 } 2097 dmsg( kDebugLevelMax, "\n" ); 2098 2099 // Resource Records 2100 2101 dmsg( kDebugLevelMax, "-- mDNS resource records --\n" ); 2102 num = 0; 2103 for( r = gMDNSPtr->ResourceRecords; r; r = r->next ) 2104 { 2105 i = (NetworkInterfaceInfoVxWorks *) r->resrec.InterfaceID; 2106 if( r->resrec.rrtype == kDNSType_TXT ) 2107 { 2108 RDataBody * rd; 2109 const mDNSu8 * txt; 2110 const mDNSu8 * end; 2111 mDNSu8 size; 2112 int nEntries; 2113 2114 rd = &r->resrec.rdata->u; 2115 dmsg( kDebugLevelMax, " record %2d: %#p %8s(%u): %4d %##s %s:\n", num, i, 2116 i ? i->ifinfo.ifname : "<any>", 2117 i ? i->scopeID : 0, 2118 r->resrec.rdlength, r->resrec.name->c, DNSTypeName( r->resrec.rrtype ) ); 2119 2120 nEntries = 0; 2121 txt = rd->txt.c; 2122 end = txt + r->resrec.rdlength; 2123 while( txt < end ) 2124 { 2125 size = *txt++; 2126 if( ( txt + size ) > end ) 2127 { 2128 dmsg( kDebugLevelMax, " ### ERROR! txt length byte too big (%u, %u max)\n", size, end - txt ); 2129 break; 2130 } 2131 dmsg( kDebugLevelMax, " string %2d (%3d bytes): \"%.*s\"\n", nEntries, size, size, txt ); 2132 txt += size; 2133 ++nEntries; 2134 } 2135 } 2136 else 2137 { 2138 dmsg( kDebugLevelMax, " record %2d: %#p %8s(%u): %s\n", num, i, 2139 i ? i->ifinfo.ifname : "<any>", 2140 i ? i->scopeID : 0, 2141 ARDisplayString( gMDNSPtr, r ) ); 2142 } 2143 ++num; 2144 } 2145 dmsg( kDebugLevelMax, "\n"); 2146} 2147#endif // DEBUG && MDNS_DEBUG_SHOW 2148