1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #pragma mark == Configuration ==
22 //===========================================================================================================================
24 //===========================================================================================================================
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).
44 #include <sys/types.h>
46 #include <arpa/inet.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>
62 #include "selectLib.h"
69 #include "CommonServices.h"
70 #include "DebugServices.h"
71 #include "DNSCommon.h"
72 #include "mDNSEmbeddedAPI.h"
74 #include "mDNSVxWorks.h"
77 #pragma mark == Constants ==
80 //===========================================================================================================================
82 //===========================================================================================================================
84 typedef uint8_t MDNSPipeCommandCode;
86 #define kMDNSPipeCommandCodeInvalid 0
87 #define kMDNSPipeCommandCodeReschedule 1
88 #define kMDNSPipeCommandCodeReconfigure 2
89 #define kMDNSPipeCommandCodeQuit 3
92 #pragma mark == Prototypes ==
95 //===========================================================================================================================
97 //===========================================================================================================================
100 mDNSlocal void DebugMsg( DebugLevel inLevel, const char *inFormat, ... );
102 #define dmsg( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
104 #define dmsg( LEVEL, ARGS... )
107 #if ( DEBUG && MDNS_DEBUG_PACKETS )
108 #define dpkt( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
110 #define dpkt( LEVEL, ARGS... )
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 )
118 mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC );
119 mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC );
120 mDNSlocal int SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC );
121 mDNSlocal void MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC );
122 mDNSlocal int ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing );
123 mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID );
124 mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex );
125 mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS );
126 mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP );
130 mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS );
131 mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS );
132 mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode );
133 mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS );
137 mDNSlocal void Task( mDNS *inMDNS );
138 mDNSlocal mStatus TaskInit( mDNS *inMDNS );
139 mDNSlocal void TaskTerm( mDNS *inMDNS );
140 mDNSlocal void TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout );
141 mDNSlocal void TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock );
149 size_t * outFromSize,
150 mDNSAddr * outDstAddr,
151 uint32_t * outIndex );
153 // DNSServices compatibility. When all clients move to DNS-SD, this section can be removed.
159 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
160 struct mDNSPlatformInterfaceInfo
166 mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
167 mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
174 #pragma mark == Globals ==
177 //===========================================================================================================================
179 //===========================================================================================================================
181 debug_log_new_default_category( mdns );
183 mDNSexport mDNSs32 mDNSPlatformOneSecond;
184 mDNSlocal mDNSs32 gMDNSTicksToMicro = 0;
185 mDNSlocal mDNS * gMDNSPtr = NULL;
186 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
187 mDNSlocal mDNSBool gMDNSDeferIPv4 = mDNSfalse;
189 DebugLevel gMDNSDebugOverrideLevel = kDebugLevelMax;
196 //===========================================================================================================================
198 //===========================================================================================================================
200 void mDNSReconfigure( void )
202 if( gMDNSPtr ) SendCommand( gMDNSPtr, kMDNSPipeCommandCodeReconfigure );
205 //===========================================================================================================================
207 //===========================================================================================================================
209 void mDNSDeferIPv4( mDNSBool inDefer )
211 gMDNSDeferIPv4 = inDefer;
218 //===========================================================================================================================
220 //===========================================================================================================================
222 mStatus mDNSPlatformInit( mDNS * const inMDNS )
227 mDNSPlatformOneSecond = sysClkRateGet();
228 gMDNSTicksToMicro = ( 1000000L / mDNSPlatformOneSecond );
230 // Do minimal initialization to get the task started and so we can cleanup safely if an error occurs.
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;
241 inMDNS->p->lock = semMCreate( SEM_Q_FIFO );
242 require_action( inMDNS->p->lock, exit, err = mStatus_NoMemoryErr );
244 inMDNS->p->initEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
245 require_action( inMDNS->p->initEvent, exit, err = mStatus_NoMemoryErr );
247 inMDNS->p->quitEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
248 require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr );
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.
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 );
258 err = semTake( inMDNS->p->initEvent, WAIT_FOREVER );
259 if( err == OK ) err = inMDNS->p->initErr;
260 require_noerr( err, exit );
263 mDNSCoreInitComplete( inMDNS, err );
266 if( err ) mDNSPlatformClose( inMDNS );
270 //===========================================================================================================================
272 //===========================================================================================================================
274 void mDNSPlatformClose( mDNS * const inMDNS )
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.
284 if( inMDNS->p->taskID != ERROR )
286 SendCommand( inMDNS, kMDNSPipeCommandCodeQuit );
287 if( inMDNS->p->quitEvent )
289 err = semTake( inMDNS->p->quitEvent, sysClkRateGet() * 10 );
292 inMDNS->p->taskID = ERROR;
295 // Clean up resources set up in mDNSPlatformInit. All other resources should have been cleaned up already by TaskTerm.
297 ForgetSem( &inMDNS->p->quitEvent );
298 ForgetSem( &inMDNS->p->initEvent );
299 ForgetSem( &inMDNS->p->lock );
301 dmsg( kDebugLevelNotice, DEBUG_NAME "CLOSED\n" );
304 //===========================================================================================================================
305 // mDNSPlatformSendUDP
306 //===========================================================================================================================
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 )
318 NetworkInterfaceInfoVxWorks * info;
320 struct sockaddr_storage to;
323 // Set up the sockaddr to sent to and the socket to send on.
325 info = (NetworkInterfaceInfoVxWorks *) inInterfaceID;
326 if( inDstIP->type == mDNSAddrType_IPv4 )
328 struct sockaddr_in * sa4;
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;
337 else if( inDstIP->type == mDNSAddrType_IPv6 )
339 struct sockaddr_in6 * sa6;
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;
352 dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! destination is not an IPv4 or IPv6 address\n", __ROUTINE__ );
353 err = mStatus_BadParamErr;
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.
360 n = (int)( (mDNSu8 *) inEnd - (mDNSu8 *) inMsg );
361 if( !IsValidSocket( sock ) )
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;
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 );
374 n = sendto( sock, (mDNSu8 *) inMsg, n, 0, (struct sockaddr *) &to, to.ss_len );
377 // Don't warn about ARP failures or no route to host for unicast destinations.
379 err = errno_compat();
380 if( ( ( err == EHOSTDOWN ) || ( err == ENETDOWN ) || ( err == EHOSTUNREACH ) ) && !mDNSAddressIsAllDNSLinkGroup( inDstIP ) )
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;
391 err = mStatus_NoError;
397 //===========================================================================================================================
398 // Connection-oriented (TCP) functions
399 //===========================================================================================================================
401 mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
402 TCPConnectionCallback callback, void *context, int *descriptor)
405 (void)dstport; // Unused
406 (void)InterfaceID; // Unused
407 (void)callback; // Unused
408 (void)context; // Unused
409 (void)descriptor; // Unused
410 return(mStatus_UnsupportedErr);
413 mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
418 mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
422 (void)buflen; // Unused
426 mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
434 //===========================================================================================================================
436 //===========================================================================================================================
438 void mDNSPlatformLock( const mDNS * const inMDNS )
440 check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" );
443 if( semTake( inMDNS->p->lock, 60 * sysClkRateGet() ) != OK )
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.
451 semTake( inMDNS->p->lock, WAIT_FOREVER );
455 //===========================================================================================================================
456 // mDNSPlatformUnlock
457 //===========================================================================================================================
459 void mDNSPlatformUnlock( const mDNS * const inMDNS )
461 check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" );
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.
466 if( taskIdSelf() != inMDNS->p->taskID )
468 SendCommand( inMDNS, kMDNSPipeCommandCodeReschedule );
470 semGive( inMDNS->p->lock );
473 //===========================================================================================================================
474 // mDNSPlatformStrLen
475 //===========================================================================================================================
477 mDNSu32 mDNSPlatformStrLen( const void *inSrc )
481 return( (mDNSu32) strlen( (const char *) inSrc ) );
484 //===========================================================================================================================
485 // mDNSPlatformStrCopy
486 //===========================================================================================================================
488 void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
493 strcpy( (char *) inDst, (const char*) inSrc );
496 //===========================================================================================================================
497 // mDNSPlatformMemCopy
498 //===========================================================================================================================
500 void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
505 memcpy( inDst, inSrc, inSize );
508 //===========================================================================================================================
509 // mDNSPlatformMemSame
510 //===========================================================================================================================
512 mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
517 return( memcmp( inSrc, inDst, inSize ) == 0 );
520 //===========================================================================================================================
521 // mDNSPlatformMemZero
522 //===========================================================================================================================
524 void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
528 memset( inDst, 0, inSize );
531 //===========================================================================================================================
532 // mDNSPlatformMemAllocate
533 //===========================================================================================================================
535 mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
541 mem = malloc( inSize );
547 //===========================================================================================================================
548 // mDNSPlatformMemFree
549 //===========================================================================================================================
551 mDNSexport void mDNSPlatformMemFree( void *inMem )
554 if( inMem ) free( inMem );
557 //===========================================================================================================================
558 // mDNSPlatformRandomSeed
559 //===========================================================================================================================
561 mDNSexport mDNSu32 mDNSPlatformRandomSeed( void )
566 //===========================================================================================================================
567 // mDNSPlatformTimeInit
568 //===========================================================================================================================
570 mDNSexport mStatus mDNSPlatformTimeInit( void )
572 // No special setup is required on VxWorks -- we just use tickGet().
574 return( mStatus_NoError );
577 //===========================================================================================================================
578 // mDNSPlatformRawTime
579 //===========================================================================================================================
581 mDNSs32 mDNSPlatformRawTime( void )
583 return( (mDNSs32) tickGet() );
586 //===========================================================================================================================
588 //===========================================================================================================================
590 mDNSexport mDNSs32 mDNSPlatformUTC( void )
592 return( (mDNSs32) time( NULL ) );
595 //===========================================================================================================================
596 // mDNSPlatformInterfaceIDfromInterfaceIndex
597 //===========================================================================================================================
599 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS *const inMDNS, mDNSu32 inIndex )
601 NetworkInterfaceInfoVxWorks * i;
603 if( inIndex == (mDNSu32) -1 ) return( mDNSInterface_LocalOnly );
606 for( i = inMDNS->p->interfaceList; i; i = i->next )
608 // Don't get tricked by inactive interfaces with no InterfaceID set.
610 if( i->ifinfo.InterfaceID && ( i->scopeID == inIndex ) ) return( i->ifinfo.InterfaceID );
616 //===========================================================================================================================
617 // mDNSPlatformInterfaceIndexfromInterfaceID
618 //===========================================================================================================================
620 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS *const inMDNS, mDNSInterfaceID inID )
622 NetworkInterfaceInfoVxWorks * i;
624 if( inID == mDNSInterface_LocalOnly ) return( (mDNSu32) -1 );
627 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
629 for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {}
630 if( i ) return( i->scopeID );
635 //===========================================================================================================================
636 // mDNSPlatformInterfaceNameToID
637 //===========================================================================================================================
639 mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
641 NetworkInterfaceInfoVxWorks * i;
643 for( i = inMDNS->p->interfaceList; i; i = i->next )
645 // Don't get tricked by inactive interfaces with no InterfaceID set.
647 if( i->ifinfo.InterfaceID && ( strcmp( i->ifinfo.ifname, inName ) == 0 ) )
649 *outID = (mDNSInterfaceID) i;
650 return( mStatus_NoError );
653 return( mStatus_NoSuchNameErr );
656 //===========================================================================================================================
657 // mDNSPlatformInterfaceIDToInfo
658 //===========================================================================================================================
660 mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
662 NetworkInterfaceInfoVxWorks * i;
664 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
666 for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {}
667 if( !i ) return( mStatus_NoSuchNameErr );
669 outInfo->name = i->ifinfo.ifname;
670 outInfo->ip = i->ifinfo.ip;
671 return( mStatus_NoError );
674 //===========================================================================================================================
676 //===========================================================================================================================
678 #if ( MDNS_DEBUGMSGS > 0 )
679 mDNSexport void debugf_( const char *inFormat, ... )
684 va_start( args, inFormat );
685 mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
688 dlog( kDebugLevelInfo, "%s\n", buffer );
692 //===========================================================================================================================
694 //===========================================================================================================================
696 #if ( MDNS_DEBUGMSGS > 1 )
697 mDNSexport void verbosedebugf_( const char *inFormat, ... )
702 va_start( args, inFormat );
703 mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
706 dlog( kDebugLevelVerbose, "%s\n", buffer );
710 //===========================================================================================================================
712 //===========================================================================================================================
714 mDNSexport void LogMsg( const char *inFormat, ... )
720 va_start( args, inFormat );
721 mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
724 dlog( kDebugLevelWarning, "%s\n", buffer );
726 DEBUG_UNUSED( inFormat );
731 //===========================================================================================================================
733 //===========================================================================================================================
735 mDNSlocal void DebugMsg( DebugLevel inLevel, const char *inFormat, ... )
740 va_start( args, inFormat );
741 mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
744 if( inLevel >= gMDNSDebugOverrideLevel ) inLevel = kDebugLevelMax;
745 dlog( inLevel, "%s", buffer );
751 #pragma mark == Interfaces ==
754 //===========================================================================================================================
755 // UpdateInterfaceList
756 //===========================================================================================================================
758 #if ( MDNS_ENABLE_PPP )
760 // Note: This includes PPP dial-in interfaces (pppXYZ), but not PPP dial-out interface (pppdXYZ).
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 ) ) )
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 ) ) )
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 ) )
780 #define FamilyToString( X ) \
781 ( ( ( X ) == AF_INET ) ? "AF_INET" : \
782 ( ( ( X ) == AF_INET6 ) ? "AF_INET6" : \
783 ( ( ( X ) == AF_LINK ) ? "AF_LINK" : \
786 mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC )
789 struct ifaddrs * ifaList;
790 struct ifaddrs * ifa;
794 struct ifaddrs * loopbackV4;
795 struct ifaddrs * loopbackV6;
796 mDNSEthAddr primaryMAC;
798 char defaultName[ 64 ];
799 NetworkInterfaceInfoVxWorks * i;
800 domainlabel nicelabel;
801 domainlabel hostlabel;
809 primaryMAC = zeroEthAddr;
811 // Set up an IPv6 socket so we can check the state of interfaces using SIOCGIFAFLAG_IN6.
813 infoSock = socket( AF_INET6, SOCK_DGRAM, 0 );
814 check_translated_errno( IsValidSocket( infoSock ), errno_compat(), kUnknownErr );
816 // Run through the entire list of interfaces.
818 err = getifaddrs( &ifaList );
819 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
821 for( ifa = ifaList; ifa; ifa = ifa->ifa_next )
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 );
829 // Save off the MAC address of the first Ethernet-ish interface.
831 if( family == AF_LINK )
833 struct sockaddr_dl * sdl;
835 sdl = (struct sockaddr_dl *) ifa->ifa_addr;
836 if( ( sdl->sdl_type == IFT_ETHER ) && ( sdl->sdl_alen == sizeof( primaryMAC ) &&
837 mDNSSameEthAddress( &primaryMAC, &zeroEthAddr ) ) )
839 memcpy( primaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6 );
843 if( !IsCompatibleInterface( ifa ) ) continue;
845 // If this is a link-local address and there's a non-link-local address on this interface, skip this alias.
847 if( IsLinkLocalSockAddr( ifa->ifa_addr ) )
849 struct ifaddrs * ifaLL;
851 for( ifaLL = ifaList; ifaLL; ifaLL = ifaLL->ifa_next )
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;
860 dmsg( kDebugLevelInfo, DEBUG_NAME "%s: %8s(%d) skipping link-local alias\n", __ROUTINE__,
861 ifa->ifa_name, if_nametoindex( ifa->ifa_name ) );
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.
871 if( ( family == AF_INET6 ) && IsValidSocket( infoSock ) )
873 struct sockaddr_in6 * sa6;
874 struct in6_ifreq ifr6;
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 )
882 flags = ifr6.ifr_ifru.ifru_flags6;
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.
891 if( flags & ( IN6_IFF_DUPLICATED | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY ) )
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 );
897 if( ifa->ifa_flags & IFF_LOOPBACK )
899 if( family == AF_INET ) loopbackV4 = ifa;
900 else loopbackV6 = ifa;
904 if( ( family == AF_INET ) && gMDNSDeferIPv4 && IsLinkLocalSockAddr( ifa->ifa_addr ) ) continue;
905 i = AddInterfaceToList( inMDNS, ifa, inUTC );
906 if( i && i->multicast )
908 if( family == AF_INET ) foundV4 = mDNStrue;
909 else foundV6 = mDNStrue;
914 // For efficiency, we don't register a loopback interface when other interfaces of that family are available.
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 );
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.
929 for( i = inMDNS->p->interfaceList; i; i = i->next )
935 txrx = i->multicast && ( ( i->ifinfo.ip.type == mDNSAddrType_IPv4 ) || !FindRoutableIPv4( inMDNS, i->scopeID ) );
936 if( i->ifinfo.McastTxRx != txrx )
938 i->ifinfo.McastTxRx = txrx;
939 i->exists = 2; // 2=state change; need to de-register and re-register this interface.
944 // Set up the user-specified, friendly name, which is allowed to be full UTF-8.
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 ] );
949 MakeDomainLabelFromLiteralString( &nicelabel, "Put Nice Name Here" ); // $$$ Implementers: Fill in nice name of device.
950 if( nicelabel.c[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &nicelabel, defaultName );
952 // Set up the RFC 1034-compliant label. If not set or it is not RFC 1034 compliant, try the user-specified nice name.
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 );
959 // Update our globals and mDNS with the new labels.
961 if( !SameDomainLabelCS( inMDNS->p->userNiceLabel.c, nicelabel.c ) )
963 dmsg( kDebugLevelInfo, DEBUG_NAME "Updating nicelabel to \"%#s\"\n", nicelabel.c );
964 inMDNS->p->userNiceLabel = nicelabel;
965 inMDNS->nicelabel = nicelabel;
967 if( !SameDomainLabelCS( inMDNS->p->userHostLabel.c, hostlabel.c ) )
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 );
974 return( mStatus_NoError );
977 //===========================================================================================================================
978 // AddInterfaceToList
979 //===========================================================================================================================
981 mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC )
987 NetworkInterfaceInfoVxWorks ** p;
988 NetworkInterfaceInfoVxWorks * i;
992 err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ip );
993 require_noerr( err, exit );
995 err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &mask );
996 require_noerr( err, exit );
998 // Search for an existing interface with the same info. If found, just return that one.
1000 scopeID = if_nametoindex( inIFA->ifa_name );
1002 for( p = &inMDNS->p->interfaceList; *p; p = &( *p )->next )
1004 if( ( scopeID == ( *p )->scopeID ) && mDNSSameAddress( &ip, &( *p )->ifinfo.ip ) )
1006 dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Found existing interface %u with address %#a at %#p\n", __ROUTINE__,
1008 ( *p )->exists = mDNStrue;
1014 // Allocate the new interface info and fill it out.
1016 i = (NetworkInterfaceInfoVxWorks *) calloc( 1, sizeof( *i ) );
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;
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.
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 );
1036 i->ss.sockV4 = kInvalidSocketRef;
1037 i->ss.sockV6 = kInvalidSocketRef;
1044 //===========================================================================================================================
1045 // SetupActiveInterfaces
1047 // Returns a count of non-link local IPv4 addresses registered.
1048 //===========================================================================================================================
1050 #define mDNSAddressIsNonLinkLocalIPv4( X ) \
1051 ( ( ( X )->type == mDNSAddrType_IPv4 ) && ( ( ( X )->ip.v4.b[ 0 ] != 169 ) || ( ( X )->ip.v4.b[ 1 ] != 254 ) ) )
1053 mDNSlocal int SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC )
1056 NetworkInterfaceInfoVxWorks * i;
1059 for( i = inMDNS->p->interfaceList; i; i = i->next )
1061 NetworkInterfaceInfo * n;
1062 NetworkInterfaceInfoVxWorks * primary;
1064 if( !i->exists ) continue;
1066 // Search for the primary interface and sanity check it.
1069 primary = FindInterfaceByIndex( inMDNS, i->family, i->scopeID );
1072 dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! didn't find %s(%u)\n", __ROUTINE__, i->ifinfo.ifname, i->scopeID );
1075 if( n->InterfaceID && ( n->InterfaceID != (mDNSInterfaceID) primary ) )
1077 dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! n->InterfaceID %#p != primary %#p\n", __ROUTINE__,
1078 n->InterfaceID, primary );
1079 n->InterfaceID = NULL;
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.
1085 if( !n->InterfaceID )
1089 n->InterfaceID = (mDNSInterfaceID) primary;
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.
1095 flapping = ( ( inUTC - i->lastSeen ) > 0 ) && ( ( inUTC - i->lastSeen ) < 60 );
1096 mDNS_RegisterInterface( inMDNS, n, (flapping ? SlowActivation : NormalActivation));
1097 if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
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)" : "" );
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.
1112 if( ( ( i->family == AF_INET ) && !IsValidSocket( primary->ss.sockV4 ) ) ||
1113 ( ( i->family == AF_INET6 ) && !IsValidSocket( primary->ss.sockV6 ) ) )
1115 err = SetupSocket( inMDNS, &i->ifinfo.ip, mDNStrue, i->family, &primary->ss );
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 );
1128 //===========================================================================================================================
1129 // MarkAllInterfacesInactive
1130 //===========================================================================================================================
1132 mDNSlocal void MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC )
1134 NetworkInterfaceInfoVxWorks * i;
1136 for( i = inMDNS->p->interfaceList; i; i = i->next )
1138 if( !i->exists ) continue;
1139 i->lastSeen = inUTC;
1140 i->exists = mDNSfalse;
1144 //===========================================================================================================================
1145 // ClearInactiveInterfaces
1147 // Returns count of non-link local IPv4 addresses de-registered.
1148 //===========================================================================================================================
1150 mDNSlocal int ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing )
1153 NetworkInterfaceInfoVxWorks * i;
1154 NetworkInterfaceInfoVxWorks ** p;
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.).
1165 for( i = inMDNS->p->interfaceList; i; i = i->next )
1167 NetworkInterfaceInfoVxWorks * primary;
1169 // 1. If this interface is no longer active, or its InterfaceID is changing, de-register it.
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 ) )
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)" : "" );
1179 mDNS_DeregisterInterface( inMDNS, &i->ifinfo, NormalActivation );
1180 i->ifinfo.InterfaceID = NULL;
1181 if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
1186 // Now that everything that's going to de-register has done so, we can close sockets and free the memory.
1188 p = &inMDNS->p->interfaceList;
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.).
1196 ForgetSocket( &i->ss.sockV4 );
1197 ForgetSocket( &i->ss.sockV6 );
1199 // 3. If no longer active, remove the interface from the list and free its memory.
1207 check_string( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0, "closing with in-use records!" );
1208 deleteIt = mDNStrue;
1212 if( i->lastSeen == inUTC ) i->lastSeen = inUTC - 1;
1213 deleteIt = ( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0 ) && ( ( inUTC - i->lastSeen ) >= 60 );
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)" : "" );
1230 //===========================================================================================================================
1232 //===========================================================================================================================
1234 mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID )
1236 #if ( MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
1237 NetworkInterfaceInfoVxWorks * i;
1239 for( i = inMDNS->p->interfaceList; i; i = i->next )
1241 if( i->exists && ( i->scopeID == inScopeID ) && mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) )
1248 DEBUG_UNUSED( inMDNS );
1249 DEBUG_UNUSED( inScopeID );
1255 //===========================================================================================================================
1256 // FindInterfaceByIndex
1257 //===========================================================================================================================
1259 mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex )
1261 NetworkInterfaceInfoVxWorks * i;
1263 check( inIndex != 0 );
1265 for( i = inMDNS->p->interfaceList; i; i = i->next )
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 ) ) ) )
1278 //===========================================================================================================================
1280 //===========================================================================================================================
1282 mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS )
1285 SocketRef * sockPtr;
1293 sockPtr = ( inFamily == AF_INET ) ? &inSS->sockV4 : &inSS->sockV6;
1294 port = ( inMcast || inMDNS->CanReceiveUnicastOn5353 ) ? MulticastDNSPort : zeroIPPort;
1296 sock = socket( inFamily, SOCK_DGRAM, IPPROTO_UDP );
1297 err = translate_errno( IsValidSocket( sock ), errno_compat(), mStatus_UnknownErr );
1298 require_noerr( err, exit );
1300 // Allow multiple listeners if this is a multicast port.
1302 if( port.NotAnInteger )
1304 err = setsockopt( sock, SOL_SOCKET, SO_REUSEPORT, (char *) &on, sizeof( on ) );
1305 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1308 // Set up the socket based on the family (IPv4 or IPv6).
1310 if( inFamily == AF_INET )
1312 const int ttlV4 = 255;
1313 const u_char ttlV4Mcast = 255;
1314 struct sockaddr_in sa4;
1316 // Receive destination addresses so we know which address the packet was sent to.
1318 err = setsockopt( sock, IPPROTO_IP, IP_RECVDSTADDR, (char *) &on, sizeof( on ) );
1319 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1321 // Receive interface indexes so we know which interface received the packet.
1323 err = setsockopt( sock, IPPROTO_IP, IP_RECVIF, (char *) &on, sizeof( on ) );
1324 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1326 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1330 struct in_addr addrV4;
1331 struct ip_mreq mreqV4;
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 );
1339 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addrV4, sizeof( addrV4 ) );
1340 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1343 // Send unicast packets with TTL 255 (helps against spoofing).
1345 err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &ttlV4, sizeof( ttlV4 ) );
1346 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1348 // Send multicast packets with TTL 255 (helps against spoofing).
1350 err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttlV4Mcast, sizeof( ttlV4Mcast ) );
1351 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1353 // Start listening for packets.
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 );
1363 else if( inFamily == AF_INET6 )
1365 struct sockaddr_in6 sa6;
1366 const int ttlV6 = 255;
1368 // Receive destination addresses and interface index so we know where the packet was received and intended.
1370 err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &on, sizeof( on ) );
1371 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1373 // Receive only IPv6 packets because otherwise, we may get IPv4 addresses as IPv4-mapped IPv6 addresses.
1375 err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, sizeof( on ) );
1376 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1378 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1383 struct ipv6_mreq mreqV6;
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 );
1391 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &ifindex, sizeof( ifindex ) );
1392 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1395 // Send unicast packets with TTL 255 (helps against spoofing).
1397 err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) );
1398 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1400 // Send multicast packets with TTL 255 (helps against spoofing).
1402 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) );
1403 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1405 // Receive our own packets for same-machine operation.
1407 err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &on, sizeof( on ) );
1408 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1410 // Start listening for packets.
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 );
1424 dmsg( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inFamily );
1425 err = kUnsupportedErr;
1429 // Make the socket non-blocking so we can potentially get multiple packets per select call.
1431 err = ioctl( sock, FIONBIO, (int) &on );
1432 check_translated_errno( err == 0, errno_compat(), kOptionErr );
1435 sock = kInvalidSocketRef;
1436 err = mStatus_NoError;
1439 if( IsValidSocket( sock ) ) close_compat( sock );
1443 //===========================================================================================================================
1444 // SockAddrToMDNSAddr
1445 //===========================================================================================================================
1447 mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP )
1454 if( inSA->sa_family == AF_INET )
1456 struct sockaddr_in * sa4;
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;
1463 else if( inSA->sa_family == AF_INET6 )
1465 struct sockaddr_in6 * sa6;
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;
1475 dmsg( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family (%d)\n", __ROUTINE__, inSA->sa_family );
1476 err = mStatus_BadParamErr;
1483 #pragma mark == Commands ==
1486 //===========================================================================================================================
1488 //===========================================================================================================================
1490 mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS )
1494 err = pipeDevCreate( "/pipe/mDNS", 32, 1 );
1495 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
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 );
1505 //===========================================================================================================================
1506 // TearDownCommandPipe
1507 //===========================================================================================================================
1509 mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS )
1513 if( inMDNS->p->commandPipe != ERROR )
1515 err = close( inMDNS->p->commandPipe );
1516 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
1517 inMDNS->p->commandPipe = ERROR;
1519 err = pipeDevDelete( "/pipe/mDNS", FALSE );
1520 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
1522 return( mStatus_NoError );
1525 //===========================================================================================================================
1527 //===========================================================================================================================
1529 mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode )
1533 require_action_quiet( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr );
1535 err = write( inMDNS->p->commandPipe, &inCommandCode, sizeof( inCommandCode ) );
1536 err = translate_errno( err >= 0, errno_compat(), kWriteErr );
1537 require_noerr( err, exit );
1543 //===========================================================================================================================
1545 //===========================================================================================================================
1547 mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS )
1550 MDNSPipeCommandCode cmd;
1553 err = read( inMDNS->p->commandPipe, &cmd, sizeof( cmd ) );
1554 err = translate_errno( err >= 0, errno_compat(), kReadErr );
1555 require_noerr( err, exit );
1559 case kMDNSPipeCommandCodeReschedule: // Reschedule: just break out to re-run mDNS_Execute.
1562 case kMDNSPipeCommandCodeReconfigure: // Reconfigure: rebuild the interface list after a config change.
1563 dmsg( kDebugLevelInfo, DEBUG_NAME "*** NETWORK CONFIGURATION CHANGE ***\n" );
1564 mDNSPlatformLock( inMDNS );
1566 utc = mDNSPlatformUTC();
1567 MarkAllInterfacesInactive( inMDNS, utc );
1568 UpdateInterfaceList( inMDNS, utc );
1569 ClearInactiveInterfaces( inMDNS, utc, mDNSfalse );
1570 SetupActiveInterfaces( inMDNS, utc );
1572 mDNSPlatformUnlock( inMDNS );
1573 mDNS_ConfigChanged(inMDNS);
1576 case kMDNSPipeCommandCodeQuit: // Quit: just set a flag so the task exits cleanly.
1577 inMDNS->p->quit = mDNStrue;
1581 dmsg( kDebugLevelError, DEBUG_NAME "unknown pipe command (%d)\n", cmd );
1582 err = mStatus_BadParamErr;
1592 #pragma mark == Threads ==
1595 //===========================================================================================================================
1597 //===========================================================================================================================
1599 mDNSlocal void Task( mDNS *inMDNS )
1605 struct timeval timeout;
1606 NetworkInterfaceInfoVxWorks * i;
1612 err = TaskInit( inMDNS );
1613 require_noerr( err, exit );
1615 while( !inMDNS->p->quit )
1617 // Let mDNSCore do its work then wait for an event. On idle timeouts (n == 0), just loop back to mDNS_Exceute.
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;
1625 // Process interface-specific sockets with pending data.
1628 for( i = inMDNS->p->interfaceList; i; i = i->next )
1631 if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
1633 TaskProcessPackets( inMDNS, &i->ss, fd );
1637 if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
1639 TaskProcessPackets( inMDNS, &i->ss, fd );
1644 // Process unicast sockets with pending data.
1646 fd = inMDNS->p->unicastSS.sockV4;
1647 if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
1649 TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd );
1652 fd = inMDNS->p->unicastSS.sockV6;
1653 if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
1655 TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd );
1659 // Processing pending commands.
1661 fd = inMDNS->p->commandPipe;
1663 if( FD_ISSET( fd, &readSet ) )
1665 ProcessCommand( inMDNS );
1668 check_string( n > 0, "select said something was readable, but nothing was" );
1675 //===========================================================================================================================
1677 //===========================================================================================================================
1679 mDNSlocal mStatus TaskInit( mDNS *inMDNS )
1685 inMDNS->p->taskID = taskIdSelf();
1687 err = SetupCommandPipe( inMDNS );
1688 require_noerr( err, exit );
1690 inMDNS->CanReceiveUnicastOn5353 = mDNStrue;
1692 // Set up the HINFO string using the description property (e.g. "Device V1.0").
1694 inMDNS->HIHardware.c[ 0 ] = 11;
1695 memcpy( &inMDNS->HIHardware.c[ 1 ], "Device V1.0", inMDNS->HIHardware.c[ 0 ] ); // $$$ Implementers: Fill in real info.
1697 // Set up the unicast sockets.
1699 err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET, &inMDNS->p->unicastSS );
1701 if( err == mStatus_NoError )
1703 struct sockaddr_in sa4;
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;
1711 err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET6, &inMDNS->p->unicastSS );
1713 if( err == mStatus_NoError )
1715 struct sockaddr_in6 sa6;
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;
1723 // Set up the interfaces.
1725 utc = mDNSPlatformUTC();
1726 UpdateInterfaceList( inMDNS, utc );
1727 SetupActiveInterfaces( inMDNS, utc );
1728 err = mStatus_NoError;
1731 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1733 inMDNS->p->initErr = err;
1734 semGive( inMDNS->p->initEvent );
1738 //===========================================================================================================================
1740 //===========================================================================================================================
1742 mDNSlocal void TaskTerm( mDNS *inMDNS )
1747 // Tear down all interfaces.
1749 utc = mDNSPlatformUTC();
1750 MarkAllInterfacesInactive( inMDNS, utc );
1751 ClearInactiveInterfaces( inMDNS, utc, mDNStrue );
1752 check_string( !inMDNS->p->interfaceList, "LEAK: closing without deleting all interfaces" );
1754 // Close unicast sockets.
1756 ForgetSocket( &inMDNS->p->unicastSS.sockV4);
1757 ForgetSocket( &inMDNS->p->unicastSS.sockV6 );
1759 // Tear down everything else that was set up in TaskInit then signal back that we're done.
1761 err = TearDownCommandPipe( inMDNS );
1764 err = semGive( inMDNS->p->quitEvent );
1765 check_translated_errno( err == 0, errno_compat(), kUnknownErr );
1768 //===========================================================================================================================
1770 //===========================================================================================================================
1772 mDNSlocal void TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout )
1774 NetworkInterfaceInfoVxWorks * i;
1782 // Add the interface-specific sockets.
1784 for( i = inMDNS->p->interfaceList; i; i = i->next )
1787 if( IsValidSocket( fd ) )
1789 FD_SET( fd, outSet );
1790 if( fd > maxFd ) maxFd = fd;
1794 if( IsValidSocket( fd ) )
1796 FD_SET( fd, outSet );
1797 if( fd > maxFd ) maxFd = fd;
1801 // Add the unicast sockets.
1803 fd = inMDNS->p->unicastSS.sockV4;
1804 if( IsValidSocket( fd ) )
1806 FD_SET( fd, outSet );
1807 if( fd > maxFd ) maxFd = fd;
1810 fd = inMDNS->p->unicastSS.sockV6;
1811 if( IsValidSocket( fd ) )
1813 FD_SET( fd, outSet );
1814 if( fd > maxFd ) maxFd = fd;
1817 // Add the command pipe.
1819 fd = inMDNS->p->commandPipe;
1821 FD_SET( fd, outSet );
1822 if( fd > maxFd ) maxFd = fd;
1827 // Calculate how long to wait before performing idle processing.
1829 delta = inNextEvent - mDNS_TimeNow( inMDNS );
1832 // The next task time is now or in the past. Set the timeout to fire immediately.
1834 outTimeout->tv_sec = 0;
1835 outTimeout->tv_usec = 0;
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.
1842 outTimeout->tv_sec = delta / mDNSPlatformOneSecond;
1843 outTimeout->tv_usec = ( ( delta % mDNSPlatformOneSecond ) + 1 ) * gMDNSTicksToMicro;
1844 if( outTimeout->tv_usec >= 1000000L )
1846 outTimeout->tv_sec += 1;
1847 outTimeout->tv_usec = 0;
1852 //===========================================================================================================================
1853 // TaskProcessPackets
1854 //===========================================================================================================================
1856 mDNSlocal void TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock )
1862 struct sockaddr_storage from;
1865 mDNSAddr senderAddr;
1866 mDNSIPPort senderPort;
1869 buf = (mDNSu8 *) &inMDNS->imsg;
1870 size = sizeof( inMDNS->imsg );
1874 n = mDNSRecvMsg( inSock, buf, size, &from, sizeof( from ), &fromSize, &destAddr, &ifindex );
1876 if( from.ss_family == AF_INET )
1878 struct sockaddr_in * sa4;
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;
1885 else if( from.ss_family == AF_INET6 )
1887 struct sockaddr_in6 * sa6;
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;
1896 dmsg( kDebugLevelWarning, DEBUG_NAME "%s: WARNING! from addr unknown family %d\n", __ROUTINE__, from.ss_family );
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.
1907 if( mDNSAddrIsDNSMulticast( &destAddr ) )
1909 if( !inSS->info || !inSS->info->exists )
1911 dpkt( kDebugLevelChatty - 3, DEBUG_NAME " ignored mcast, src=[%#39a], dst=[%#39a], if= unicast socket %d\n",
1912 &senderAddr, &destAddr, inSock );
1915 if( ifindex != inSS->info->scopeID )
1917 #if ( DEBUG && MDNS_DEBUG_PACKETS )
1918 char ifname[ IF_NAMESIZE ];
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 );
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 );
1934 NetworkInterfaceInfoVxWorks * i;
1936 // For unicast packets, try to find the matching interface.
1938 for( i = inMDNS->p->interfaceList; i && ( i->scopeID != ifindex ); i = i->next ) {}
1939 if( i ) id = i->ifinfo.InterfaceID;
1942 mDNSCoreReceive( inMDNS, buf, buf + n, &senderAddr, senderPort, &destAddr, MulticastDNSPort, id );
1946 //===========================================================================================================================
1948 //===========================================================================================================================
1954 size_t inBufferSize,
1957 size_t * outFromSize,
1958 mDNSAddr * outDstAddr,
1959 uint32_t * outIndex )
1964 char ancillary[ 1024 ];
1965 struct cmsghdr * cmPtr;
1968 // Read a packet and any ancillary data. Note: EWOULDBLOCK errors are expected when we've read all pending packets.
1970 iov.iov_base = (char *) inBuffer;
1971 iov.iov_len = inBufferSize;
1972 msg.msg_name = (caddr_t) outFrom;
1973 msg.msg_namelen = inFromSize;
1976 msg.msg_control = (caddr_t) &ancillary;
1977 msg.msg_controllen = sizeof( ancillary );
1979 n = recvmsg( inSock, &msg, 0 );
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 );
1987 if( msg.msg_controllen < sizeof( struct cmsghdr ) )
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;
1994 if( msg.msg_flags & MSG_CTRUNC )
1996 dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) MSG_CTRUNC (%d recv'd)\n", __ROUTINE__, inSock, n );
1997 n = mStatus_BadFlagsErr;
2000 *outFromSize = msg.msg_namelen;
2002 // Parse each option out of the ancillary data.
2004 for( cmPtr = CMSG_FIRSTHDR( &msg ); cmPtr; cmPtr = CMSG_NXTHDR( &msg, cmPtr ) )
2006 if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVDSTADDR ) )
2008 outDstAddr->type = mDNSAddrType_IPv4;
2009 outDstAddr->ip.v4.NotAnInteger = *( (mDNSu32 *) CMSG_DATA( cmPtr ) );
2011 else if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVIF ) )
2013 struct sockaddr_dl * sdl;
2015 sdl = (struct sockaddr_dl *) CMSG_DATA( cmPtr );
2016 *outIndex = sdl->sdl_index;
2018 else if( ( cmPtr->cmsg_level == IPPROTO_IPV6 ) && ( cmPtr->cmsg_type == IPV6_PKTINFO ) )
2020 struct in6_pktinfo * pi6;
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;
2035 #pragma mark == Debugging ==
2038 #if ( DEBUG && MDNS_DEBUG_SHOW )
2039 //===========================================================================================================================
2041 //===========================================================================================================================
2043 void mDNSShow( void );
2045 void mDNSShow( void )
2047 NetworkInterfaceInfoVxWorks * i;
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 );
2064 dmsg( kDebugLevelMax, "### mDNS not initialized\n" );
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" );
2086 utc = mDNSPlatformUTC();
2087 dmsg( kDebugLevelMax, "-- mDNS interfaces --\n" );
2089 for( i = gMDNSPtr->p->interfaceList; i; i = i->next )
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 );
2097 dmsg( kDebugLevelMax, "\n" );
2101 dmsg( kDebugLevelMax, "-- mDNS resource records --\n" );
2103 for( r = gMDNSPtr->ResourceRecords; r; r = r->next )
2105 i = (NetworkInterfaceInfoVxWorks *) r->resrec.InterfaceID;
2106 if( r->resrec.rrtype == kDNSType_TXT )
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>",
2118 r->resrec.rdlength, r->resrec.name->c, DNSTypeName( r->resrec.rrtype ) );
2122 end = txt + r->resrec.rdlength;
2126 if( ( txt + size ) > end )
2128 dmsg( kDebugLevelMax, " ### ERROR! txt length byte too big (%u, %u max)\n", size, end - txt );
2131 dmsg( kDebugLevelMax, " string %2d (%3d bytes): \"%.*s\"\n", nEntries, size, size, txt );
2138 dmsg( kDebugLevelMax, " record %2d: %#p %8s(%u): %s\n", num, i,
2139 i ? i->ifinfo.ifname : "<any>",
2141 ARDisplayString( gMDNSPtr, r ) );
2145 dmsg( kDebugLevelMax, "\n");
2147 #endif // DEBUG && MDNS_DEBUG_SHOW