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.
17 Change History (most recent first):
19 $Log: mDNSVxWorks.c,v $
20 Revision 1.35 2009/01/13 05:31:35 mkrochma
21 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
23 Revision 1.34 2008/10/03 18:25:18 cheshire
24 Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
26 Revision 1.33 2007/03/22 18:31:48 cheshire
27 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
29 Revision 1.32 2006/12/19 22:43:56 cheshire
32 Revision 1.31 2006/11/10 00:54:16 cheshire
33 <rdar://problem/4816598> Changing case of Computer Name doesn't work
35 Revision 1.30 2006/08/14 23:25:18 cheshire
36 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
38 Revision 1.29 2006/03/19 02:00:12 cheshire
39 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
41 Revision 1.28 2005/05/30 07:36:38 bradley
42 New implementation of the mDNS platform plugin for VxWorks 5.5 or later with IPv6 support.
47 #pragma mark == Configuration ==
50 //===========================================================================================================================
52 //===========================================================================================================================
54 #define DEBUG_NAME "[mDNS] "
55 #define MDNS_AAAA_OVER_IPV4 1 // 1=Send AAAA & A records over IPv4 & IPv6, 0=Send AAAA over IPv6, A over IPv4.
56 #define MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 1 // 1=Don't use IPv6 socket if non-link-local IPv4 available on same interface.
57 #define MDNS_ENABLE_PPP 0 // 1=Enable Unicast DNS over PPP interfaces. 0=Don't enable it.
58 #define MDNS_DEBUG_PACKETS 1 // 1=Enable debug output for packet send/recv if debug level high enough.
59 #define MDNS_DEBUG_SHOW 1 // 1=Enable console show routines.
60 #define DEBUG_USE_DEFAULT_CATEGORY 1 // Set up to use the default category (see DebugServices.h for details).
72 #include <sys/types.h>
74 #include <arpa/inet.h>
76 #include <net/if_dl.h>
77 #include <net/if_types.h>
78 #include <net/ifaddrs.h>
79 #include <netinet6/in6_var.h>
80 #include <netinet/if_ether.h>
81 #include <netinet/in.h>
82 #include <netinet/ip.h>
83 #include <sys/ioctl.h>
84 #include <sys/socket.h>
90 #include "selectLib.h"
97 #include "CommonServices.h"
98 #include "DebugServices.h"
99 #include "DNSCommon.h"
100 #include "mDNSEmbeddedAPI.h"
102 #include "mDNSVxWorks.h"
105 #pragma mark == Constants ==
108 //===========================================================================================================================
110 //===========================================================================================================================
112 typedef uint8_t MDNSPipeCommandCode
;
114 #define kMDNSPipeCommandCodeInvalid 0
115 #define kMDNSPipeCommandCodeReschedule 1
116 #define kMDNSPipeCommandCodeReconfigure 2
117 #define kMDNSPipeCommandCodeQuit 3
120 #pragma mark == Prototypes ==
123 //===========================================================================================================================
125 //===========================================================================================================================
128 mDNSlocal
void DebugMsg( DebugLevel inLevel
, const char *inFormat
, ... );
130 #define dmsg( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
132 #define dmsg( LEVEL, ARGS... )
135 #if( DEBUG && MDNS_DEBUG_PACKETS )
136 #define dpkt( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
138 #define dpkt( LEVEL, ARGS... )
141 #define ForgetSem( X ) do { if( *( X ) ) { semDelete( ( *X ) ); *( X ) = 0; } } while( 0 )
142 #define ForgetSocket( X ) do { if( IsValidSocket( *( X ) ) ) { close_compat( *( X ) ); *( X ) = kInvalidSocketRef; } } while( 0 )
146 mDNSlocal mStatus
UpdateInterfaceList( mDNS
*const inMDNS
, mDNSs32 inUTC
);
147 mDNSlocal NetworkInterfaceInfoVxWorks
* AddInterfaceToList( mDNS
*const inMDNS
, struct ifaddrs
*inIFA
, mDNSs32 inUTC
);
148 mDNSlocal
int SetupActiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
);
149 mDNSlocal
void MarkAllInterfacesInactive( mDNS
*const inMDNS
, mDNSs32 inUTC
);
150 mDNSlocal
int ClearInactiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
, mDNSBool inClosing
);
151 mDNSlocal NetworkInterfaceInfoVxWorks
* FindRoutableIPv4( mDNS
*const inMDNS
, mDNSu32 inScopeID
);
152 mDNSlocal NetworkInterfaceInfoVxWorks
* FindInterfaceByIndex( mDNS
*const inMDNS
, int inFamily
, mDNSu32 inIndex
);
153 mDNSlocal mStatus
SetupSocket( mDNS
*const inMDNS
, const mDNSAddr
*inAddr
, mDNSBool inMcast
, int inFamily
, SocketSet
*inSS
);
154 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
);
158 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
);
159 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
);
160 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
);
161 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
);
165 mDNSlocal
void Task( mDNS
*inMDNS
);
166 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
);
167 mDNSlocal
void TaskTerm( mDNS
*inMDNS
);
168 mDNSlocal
void TaskSetupSelect( mDNS
*inMDNS
, fd_set
*outSet
, int *outMaxFd
, mDNSs32 inNextEvent
, struct timeval
*outTimeout
);
169 mDNSlocal
void TaskProcessPackets( mDNS
*inMDNS
, SocketSet
*inSS
, SocketRef inSock
);
177 size_t * outFromSize
,
178 mDNSAddr
* outDstAddr
,
179 uint32_t * outIndex
);
181 // DNSServices compatibility. When all clients move to DNS-SD, this section can be removed.
187 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
188 struct mDNSPlatformInterfaceInfo
194 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
195 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
202 #pragma mark == Globals ==
205 //===========================================================================================================================
207 //===========================================================================================================================
209 debug_log_new_default_category( mdns
);
211 mDNSexport mDNSs32 mDNSPlatformOneSecond
;
212 mDNSlocal mDNSs32 gMDNSTicksToMicro
= 0;
213 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
214 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
215 mDNSlocal mDNSBool gMDNSDeferIPv4
= mDNSfalse
;
217 DebugLevel gMDNSDebugOverrideLevel
= kDebugLevelMax
;
224 //===========================================================================================================================
226 //===========================================================================================================================
228 void mDNSReconfigure( void )
230 if( gMDNSPtr
) SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
233 //===========================================================================================================================
235 //===========================================================================================================================
237 void mDNSDeferIPv4( mDNSBool inDefer
)
239 gMDNSDeferIPv4
= inDefer
;
246 //===========================================================================================================================
248 //===========================================================================================================================
250 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
255 mDNSPlatformOneSecond
= sysClkRateGet();
256 gMDNSTicksToMicro
= ( 1000000L / mDNSPlatformOneSecond
);
258 // Do minimal initialization to get the task started and so we can cleanup safely if an error occurs.
260 mDNSPlatformMemZero( &gMDNSPlatformSupport
, sizeof( gMDNSPlatformSupport
) );
261 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
262 inMDNS
->p
->unicastSS
.info
= NULL
;
263 inMDNS
->p
->unicastSS
.sockV4
= kInvalidSocketRef
;
264 inMDNS
->p
->unicastSS
.sockV6
= kInvalidSocketRef
;
265 inMDNS
->p
->initErr
= mStatus_NotInitializedErr
;
266 inMDNS
->p
->commandPipe
= ERROR
;
267 inMDNS
->p
->taskID
= ERROR
;
269 inMDNS
->p
->lock
= semMCreate( SEM_Q_FIFO
);
270 require_action( inMDNS
->p
->lock
, exit
, err
= mStatus_NoMemoryErr
);
272 inMDNS
->p
->initEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
273 require_action( inMDNS
->p
->initEvent
, exit
, err
= mStatus_NoMemoryErr
);
275 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
276 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
278 // Start the task and wait for it to initialize. The task does the full initialization from its own context
279 // to avoid potential issues with stack space and APIs that key off the current task (e.g. watchdog timers).
280 // We wait here until the init is complete because it needs to be ready to use as soon as this function returns.
282 id
= taskSpawn( "tMDNS", 102, 0, 16384, (FUNCPTR
) Task
, (int) inMDNS
, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
283 err
= translate_errno( id
!= ERROR
, errno_compat(), mStatus_NoMemoryErr
);
284 require_noerr( err
, exit
);
286 err
= semTake( inMDNS
->p
->initEvent
, WAIT_FOREVER
);
287 if( err
== OK
) err
= inMDNS
->p
->initErr
;
288 require_noerr( err
, exit
);
291 mDNSCoreInitComplete( inMDNS
, err
);
294 if( err
) mDNSPlatformClose( inMDNS
);
298 //===========================================================================================================================
300 //===========================================================================================================================
302 void mDNSPlatformClose( mDNS
* const inMDNS
)
310 // Signal the task to quit and wait for it to signal back that it exited. Timeout in 10 seconds to handle a hung thread.
312 if( inMDNS
->p
->taskID
!= ERROR
)
314 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
315 if( inMDNS
->p
->quitEvent
)
317 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
320 inMDNS
->p
->taskID
= ERROR
;
323 // Clean up resources set up in mDNSPlatformInit. All other resources should have been cleaned up already by TaskTerm.
325 ForgetSem( &inMDNS
->p
->quitEvent
);
326 ForgetSem( &inMDNS
->p
->initEvent
);
327 ForgetSem( &inMDNS
->p
->lock
);
329 dmsg( kDebugLevelNotice
, DEBUG_NAME
"CLOSED\n" );
332 //===========================================================================================================================
333 // mDNSPlatformSendUDP
334 //===========================================================================================================================
338 const mDNS
* const inMDNS
,
339 const void * const inMsg
,
340 const mDNSu8
* const inEnd
,
341 mDNSInterfaceID inInterfaceID
,
342 const mDNSAddr
* inDstIP
,
343 mDNSIPPort inDstPort
)
346 NetworkInterfaceInfoVxWorks
* info
;
348 struct sockaddr_storage to
;
351 // Set up the sockaddr to sent to and the socket to send on.
353 info
= (NetworkInterfaceInfoVxWorks
*) inInterfaceID
;
354 if( inDstIP
->type
== mDNSAddrType_IPv4
)
356 struct sockaddr_in
* sa4
;
358 sa4
= (struct sockaddr_in
*) &to
;
359 sa4
->sin_len
= sizeof( *sa4
);
360 sa4
->sin_family
= AF_INET
;
361 sa4
->sin_port
= inDstPort
.NotAnInteger
;
362 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
363 sock
= info
? info
->ss
.sockV4
: inMDNS
->p
->unicastSS
.sockV4
;
365 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
367 struct sockaddr_in6
* sa6
;
369 sa6
= (struct sockaddr_in6
*) &to
;
370 sa6
->sin6_len
= sizeof( *sa6
);
371 sa6
->sin6_family
= AF_INET6
;
372 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
373 sa6
->sin6_flowinfo
= 0;
374 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
375 sa6
->sin6_scope_id
= info
? info
->scopeID
: 0;
376 sock
= info
? info
->ss
.sockV6
: inMDNS
->p
->unicastSS
.sockV6
;
380 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! destination is not an IPv4 or IPv6 address\n", __ROUTINE__
);
381 err
= mStatus_BadParamErr
;
385 // 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
386 // an IPv6 multicast packet. If we don't have the corresponding type of socket available, quietly return an error.
388 n
= (int)( (mDNSu8
*) inEnd
- (mDNSu8
*) inMsg
);
389 if( !IsValidSocket( sock
) )
391 dpkt( kDebugLevelChatty
- 1,
392 DEBUG_NAME
"DROP: %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
393 n
, inDstIP
, mDNSVal16( inDstPort
), info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, info
);
394 err
= mStatus_Invalid
;
398 dpkt( kDebugLevelChatty
,
399 DEBUG_NAME
"SEND %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
400 n
, inDstIP
, mDNSVal16( inDstPort
), info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, info
);
402 n
= sendto( sock
, (mDNSu8
*) inMsg
, n
, 0, (struct sockaddr
*) &to
, to
.ss_len
);
405 // Don't warn about ARP failures or no route to host for unicast destinations.
407 err
= errno_compat();
408 if( ( ( err
== EHOSTDOWN
) || ( err
== ENETDOWN
) || ( err
== EHOSTUNREACH
) ) && !mDNSAddressIsAllDNSLinkGroup( inDstIP
) )
413 dmsg( kDebugLevelError
, "%s: ERROR! sendto failed on %8s(%u) to %#a:%d, sock %d, err %d, time %u\n",
414 __ROUTINE__
, info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, inDstIP
, mDNSVal16( inDstPort
),
415 sock
, err
, (unsigned int) inMDNS
->timenow
);
416 if( err
== 0 ) err
= mStatus_UnknownErr
;
419 err
= mStatus_NoError
;
425 //===========================================================================================================================
426 // Connection-oriented (TCP) functions
427 //===========================================================================================================================
429 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
430 TCPConnectionCallback callback
, void *context
, int *descriptor
)
433 (void)dstport
; // Unused
434 (void)InterfaceID
; // Unused
435 (void)callback
; // Unused
436 (void)context
; // Unused
437 (void)descriptor
; // Unused
438 return(mStatus_UnsupportedErr
);
441 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
446 mDNSexport
long mDNSPlatformReadTCP(int sd
, void *buf
, unsigned long buflen
)
450 (void)buflen
; // Unused
454 mDNSexport
long mDNSPlatformWriteTCP(int sd
, const char *msg
, unsigned long len
)
462 //===========================================================================================================================
464 //===========================================================================================================================
466 void mDNSPlatformLock( const mDNS
* const inMDNS
)
468 check_string( inMDNS
->p
&& ( inMDNS
->p
->taskID
!= ERROR
), "mDNS task not started" );
471 if( semTake( inMDNS
->p
->lock
, 60 * sysClkRateGet() ) != OK
)
473 dmsg( kDebugLevelTragic
, "\n### DEADLOCK DETECTED ### (sem=%#p, task=%#p)\n\n", inMDNS
->p
->lock
, taskIdSelf() );
474 debug_stack_trace(); // 1) Print Stack Trace.
475 semShow( inMDNS
->p
->lock
, 1 ); // 2) Print semaphore info, including which tasks are pending on it.
476 taskSuspend( 0 ); // 3) Suspend task. Can be resumed from the console for debugging.
479 semTake( inMDNS
->p
->lock
, WAIT_FOREVER
);
483 //===========================================================================================================================
484 // mDNSPlatformUnlock
485 //===========================================================================================================================
487 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
489 check_string( inMDNS
->p
&& ( inMDNS
->p
->taskID
!= ERROR
), "mDNS task not started" );
491 // Wake up the mDNS task to handle any work initiated by an API call and to calculate the next event time.
492 // We only need to wake up if we're not already inside the task. This avoids filling up the command queue.
494 if( taskIdSelf() != inMDNS
->p
->taskID
)
496 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
498 semGive( inMDNS
->p
->lock
);
501 //===========================================================================================================================
502 // mDNSPlatformStrLen
503 //===========================================================================================================================
505 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
509 return( (mDNSu32
) strlen( (const char *) inSrc
) );
512 //===========================================================================================================================
513 // mDNSPlatformStrCopy
514 //===========================================================================================================================
516 void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
521 strcpy( (char *) inDst
, (const char*) inSrc
);
524 //===========================================================================================================================
525 // mDNSPlatformMemCopy
526 //===========================================================================================================================
528 void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
533 memcpy( inDst
, inSrc
, inSize
);
536 //===========================================================================================================================
537 // mDNSPlatformMemSame
538 //===========================================================================================================================
540 mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
545 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
548 //===========================================================================================================================
549 // mDNSPlatformMemZero
550 //===========================================================================================================================
552 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
556 memset( inDst
, 0, inSize
);
559 //===========================================================================================================================
560 // mDNSPlatformMemAllocate
561 //===========================================================================================================================
563 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
569 mem
= malloc( inSize
);
575 //===========================================================================================================================
576 // mDNSPlatformMemFree
577 //===========================================================================================================================
579 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
582 if( inMem
) free( inMem
);
585 //===========================================================================================================================
586 // mDNSPlatformRandomSeed
587 //===========================================================================================================================
589 mDNSexport mDNSu32
mDNSPlatformRandomSeed( void )
594 //===========================================================================================================================
595 // mDNSPlatformTimeInit
596 //===========================================================================================================================
598 mDNSexport mStatus
mDNSPlatformTimeInit( void )
600 // No special setup is required on VxWorks -- we just use tickGet().
602 return( mStatus_NoError
);
605 //===========================================================================================================================
606 // mDNSPlatformRawTime
607 //===========================================================================================================================
609 mDNSs32
mDNSPlatformRawTime( void )
611 return( (mDNSs32
) tickGet() );
614 //===========================================================================================================================
616 //===========================================================================================================================
618 mDNSexport mDNSs32
mDNSPlatformUTC( void )
620 return( (mDNSs32
) time( NULL
) );
623 //===========================================================================================================================
624 // mDNSPlatformInterfaceIDfromInterfaceIndex
625 //===========================================================================================================================
627 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS
*const inMDNS
, mDNSu32 inIndex
)
629 NetworkInterfaceInfoVxWorks
* i
;
631 if( inIndex
== (mDNSu32
) -1 ) return( mDNSInterface_LocalOnly
);
634 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
636 // Don't get tricked by inactive interfaces with no InterfaceID set.
638 if( i
->ifinfo
.InterfaceID
&& ( i
->scopeID
== inIndex
) ) return( i
->ifinfo
.InterfaceID
);
644 //===========================================================================================================================
645 // mDNSPlatformInterfaceIndexfromInterfaceID
646 //===========================================================================================================================
648 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( mDNS
*const inMDNS
, mDNSInterfaceID inID
)
650 NetworkInterfaceInfoVxWorks
* i
;
652 if( inID
== mDNSInterface_LocalOnly
) return( (mDNSu32
) -1 );
655 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
657 for( i
= inMDNS
->p
->interfaceList
; i
&& ( (mDNSInterfaceID
) i
!= inID
); i
= i
->next
) {}
658 if( i
) return( i
->scopeID
);
663 //===========================================================================================================================
664 // mDNSPlatformInterfaceNameToID
665 //===========================================================================================================================
667 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
669 NetworkInterfaceInfoVxWorks
* i
;
671 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
673 // Don't get tricked by inactive interfaces with no InterfaceID set.
675 if( i
->ifinfo
.InterfaceID
&& ( strcmp( i
->ifinfo
.ifname
, inName
) == 0 ) )
677 *outID
= (mDNSInterfaceID
) i
;
678 return( mStatus_NoError
);
681 return( mStatus_NoSuchNameErr
);
684 //===========================================================================================================================
685 // mDNSPlatformInterfaceIDToInfo
686 //===========================================================================================================================
688 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
690 NetworkInterfaceInfoVxWorks
* i
;
692 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
694 for( i
= inMDNS
->p
->interfaceList
; i
&& ( (mDNSInterfaceID
) i
!= inID
); i
= i
->next
) {}
695 if( !i
) return( mStatus_NoSuchNameErr
);
697 outInfo
->name
= i
->ifinfo
.ifname
;
698 outInfo
->ip
= i
->ifinfo
.ip
;
699 return( mStatus_NoError
);
702 //===========================================================================================================================
704 //===========================================================================================================================
706 #if( MDNS_DEBUGMSGS > 0 )
707 mDNSexport
void debugf_( const char *inFormat
, ... )
712 va_start( args
, inFormat
);
713 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
716 dlog( kDebugLevelInfo
, "%s\n", buffer
);
720 //===========================================================================================================================
722 //===========================================================================================================================
724 #if( MDNS_DEBUGMSGS > 1 )
725 mDNSexport
void verbosedebugf_( const char *inFormat
, ... )
730 va_start( args
, inFormat
);
731 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
734 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
738 //===========================================================================================================================
740 //===========================================================================================================================
742 mDNSexport
void LogMsg( const char *inFormat
, ... )
748 va_start( args
, inFormat
);
749 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
752 dlog( kDebugLevelWarning
, "%s\n", buffer
);
754 DEBUG_UNUSED( inFormat
);
759 //===========================================================================================================================
761 //===========================================================================================================================
763 mDNSlocal
void DebugMsg( DebugLevel inLevel
, const char *inFormat
, ... )
768 va_start( args
, inFormat
);
769 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
772 if( inLevel
>= gMDNSDebugOverrideLevel
) inLevel
= kDebugLevelMax
;
773 dlog( inLevel
, "%s", buffer
);
779 #pragma mark == Interfaces ==
782 //===========================================================================================================================
783 // UpdateInterfaceList
784 //===========================================================================================================================
786 #if( MDNS_ENABLE_PPP )
788 // Note: This includes PPP dial-in interfaces (pppXYZ), but not PPP dial-out interface (pppdXYZ).
790 #define IsCompatibleInterface( IFA ) \
791 ( ( ( IFA )->ifa_flags & IFF_UP ) && \
792 ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
793 ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) && \
794 ( !( ( IFA )->ifa_flags & IFF_POINTOPOINT ) || ( strncmp( ( IFA )->ifa_name, "pppd", 4 ) != 0 ) ) )
796 #define IsCompatibleInterface( IFA ) \
797 ( ( ( ( IFA )->ifa_flags & ( IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT ) ) == ( IFF_UP | IFF_MULTICAST ) ) && \
798 ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
799 ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) )
802 #define IsLinkLocalSockAddr( SA ) \
803 ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
804 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
805 ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
806 : IN6_IS_ADDR_LINKLOCAL( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
808 #define FamilyToString( X ) \
809 ( ( ( X ) == AF_INET ) ? "AF_INET" : \
810 ( ( ( X ) == AF_INET6 ) ? "AF_INET6" : \
811 ( ( ( X ) == AF_LINK ) ? "AF_LINK" : \
814 mDNSlocal mStatus
UpdateInterfaceList( mDNS
*const inMDNS
, mDNSs32 inUTC
)
817 struct ifaddrs
* ifaList
;
818 struct ifaddrs
* ifa
;
822 struct ifaddrs
* loopbackV4
;
823 struct ifaddrs
* loopbackV6
;
824 mDNSEthAddr primaryMAC
;
826 char defaultName
[ 64 ];
827 NetworkInterfaceInfoVxWorks
* i
;
828 domainlabel nicelabel
;
829 domainlabel hostlabel
;
837 primaryMAC
= zeroEthAddr
;
839 // Set up an IPv6 socket so we can check the state of interfaces using SIOCGIFAFLAG_IN6.
841 infoSock
= socket( AF_INET6
, SOCK_DGRAM
, 0 );
842 check_translated_errno( IsValidSocket( infoSock
), errno_compat(), kUnknownErr
);
844 // Run through the entire list of interfaces.
846 err
= getifaddrs( &ifaList
);
847 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
849 for( ifa
= ifaList
; ifa
; ifa
= ifa
->ifa_next
)
853 family
= ifa
->ifa_addr
->sa_family
;
854 dmsg( kDebugLevelVerbose
, DEBUG_NAME
"%s: %8s(%d), Flags 0x%08X, Family %8s(%2d)\n", __ROUTINE__
,
855 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
), ifa
->ifa_flags
, FamilyToString( family
), family
);
857 // Save off the MAC address of the first Ethernet-ish interface.
859 if( family
== AF_LINK
)
861 struct sockaddr_dl
* sdl
;
863 sdl
= (struct sockaddr_dl
*) ifa
->ifa_addr
;
864 if( ( sdl
->sdl_type
== IFT_ETHER
) && ( sdl
->sdl_alen
== sizeof( primaryMAC
) &&
865 mDNSSameEthAddress( &primaryMAC
, &zeroEthAddr
) ) )
867 memcpy( primaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6 );
871 if( !IsCompatibleInterface( ifa
) ) continue;
873 // If this is a link-local address and there's a non-link-local address on this interface, skip this alias.
875 if( IsLinkLocalSockAddr( ifa
->ifa_addr
) )
877 struct ifaddrs
* ifaLL
;
879 for( ifaLL
= ifaList
; ifaLL
; ifaLL
= ifaLL
->ifa_next
)
881 if( ifaLL
->ifa_addr
->sa_family
!= family
) continue;
882 if( !IsCompatibleInterface( ifaLL
) ) continue;
883 if( strcmp( ifaLL
->ifa_name
, ifa
->ifa_name
) != 0 ) continue;
884 if( !IsLinkLocalSockAddr( ifaLL
->ifa_addr
) ) break;
888 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: %8s(%d) skipping link-local alias\n", __ROUTINE__
,
889 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
) );
894 // If this is an IPv6 interface, perform additional checks to make sure it is really ready for use.
895 // If this is a loopback interface, save it off since we may add it later if there are no other interfaces.
896 // Otherwise, add the interface to the list.
899 if( ( family
== AF_INET6
) && IsValidSocket( infoSock
) )
901 struct sockaddr_in6
* sa6
;
902 struct in6_ifreq ifr6
;
904 sa6
= (struct sockaddr_in6
*) ifa
->ifa_addr
;
905 mDNSPlatformMemZero( &ifr6
, sizeof( ifr6
) );
906 strcpy( ifr6
.ifr_name
, ifa
->ifa_name
);
907 ifr6
.ifr_addr
= *sa6
;
908 if( ioctl( infoSock
, SIOCGIFAFLAG_IN6
, (int) &ifr6
) != -1 )
910 flags
= ifr6
.ifr_ifru
.ifru_flags6
;
914 // HACK: This excludes interfaces with IN6_IFF_DUPLICATED set instead of using IN6_IFF_NOTREADY (which is
915 // HACK: IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED) because we currently do not get a notification when an
916 // HACK: interface goes from the tentative state to the fully ready state. So as a short-term workaround,
917 // HACK: this allows tentative interfaces to be registered. We should revisit if we get notification hooks.
919 if( flags
& ( IN6_IFF_DUPLICATED
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
) )
921 dmsg( kDebugLevelNotice
, DEBUG_NAME
"%s: %8s(%d), SIOCGIFAFLAG_IN6 not ready yet (0x%X)\n", __ROUTINE__
,
922 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
), flags
);
925 if( ifa
->ifa_flags
& IFF_LOOPBACK
)
927 if( family
== AF_INET
) loopbackV4
= ifa
;
928 else loopbackV6
= ifa
;
932 if( ( family
== AF_INET
) && gMDNSDeferIPv4
&& IsLinkLocalSockAddr( ifa
->ifa_addr
) ) continue;
933 i
= AddInterfaceToList( inMDNS
, ifa
, inUTC
);
934 if( i
&& i
->multicast
)
936 if( family
== AF_INET
) foundV4
= mDNStrue
;
937 else foundV6
= mDNStrue
;
942 // For efficiency, we don't register a loopback interface when other interfaces of that family are available.
944 if( !foundV4
&& loopbackV4
) AddInterfaceToList( inMDNS
, loopbackV4
, inUTC
);
945 if( !foundV6
&& loopbackV6
) AddInterfaceToList( inMDNS
, loopbackV6
, inUTC
);
946 freeifaddrs( ifaList
);
947 if( IsValidSocket( infoSock
) ) close_compat( infoSock
);
949 // The list is complete. Set the McastTxRx setting for each interface. We always send and receive using IPv4.
950 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
951 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large, configured network,
952 // which means there's a good chance that most or all the other devices on that network should also have v4.
953 // 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.
954 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
955 // so we are willing to make that sacrifice.
957 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
963 txrx
= i
->multicast
&& ( ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4( inMDNS
, i
->scopeID
) );
964 if( i
->ifinfo
.McastTxRx
!= txrx
)
966 i
->ifinfo
.McastTxRx
= txrx
;
967 i
->exists
= 2; // 2=state change; need to de-register and re-register this interface.
972 // Set up the user-specified, friendly name, which is allowed to be full UTF-8.
974 mDNS_snprintf( defaultName
, sizeof( defaultName
), "Device-%02X:%02X:%02X:%02X:%02X:%02X",
975 primaryMAC
.b
[ 0 ], primaryMAC
.b
[ 1 ], primaryMAC
.b
[ 2 ], primaryMAC
.b
[ 3 ], primaryMAC
.b
[ 4 ], primaryMAC
.b
[ 5 ] );
977 MakeDomainLabelFromLiteralString( &nicelabel
, "Put Nice Name Here" ); // $$$ Implementers: Fill in nice name of device.
978 if( nicelabel
.c
[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &nicelabel
, defaultName
);
980 // Set up the RFC 1034-compliant label. If not set or it is not RFC 1034 compliant, try the user-specified nice name.
982 MakeDomainLabelFromLiteralString( &tmp
, "Put-DNS-Name-Here" ); // $$$ Implementers: Fill in DNS name of device.
983 ConvertUTF8PstringToRFC1034HostLabel( tmp
.c
, &hostlabel
);
984 if( hostlabel
.c
[ 0 ] == 0 ) ConvertUTF8PstringToRFC1034HostLabel( nicelabel
.c
, &hostlabel
);
985 if( hostlabel
.c
[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &hostlabel
, defaultName
);
987 // Update our globals and mDNS with the new labels.
989 if( !SameDomainLabelCS( inMDNS
->p
->userNiceLabel
.c
, nicelabel
.c
) )
991 dmsg( kDebugLevelInfo
, DEBUG_NAME
"Updating nicelabel to \"%#s\"\n", nicelabel
.c
);
992 inMDNS
->p
->userNiceLabel
= nicelabel
;
993 inMDNS
->nicelabel
= nicelabel
;
995 if( !SameDomainLabelCS( inMDNS
->p
->userHostLabel
.c
, hostlabel
.c
) )
997 dmsg( kDebugLevelInfo
, DEBUG_NAME
"Updating hostlabel to \"%#s\"\n", hostlabel
.c
);
998 inMDNS
->p
->userHostLabel
= hostlabel
;
999 inMDNS
->hostlabel
= hostlabel
;
1000 mDNS_SetFQDN( inMDNS
);
1002 return( mStatus_NoError
);
1005 //===========================================================================================================================
1006 // AddInterfaceToList
1007 //===========================================================================================================================
1009 mDNSlocal NetworkInterfaceInfoVxWorks
* AddInterfaceToList( mDNS
*const inMDNS
, struct ifaddrs
*inIFA
, mDNSs32 inUTC
)
1015 NetworkInterfaceInfoVxWorks
** p
;
1016 NetworkInterfaceInfoVxWorks
* i
;
1020 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ip
);
1021 require_noerr( err
, exit
);
1023 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &mask
);
1024 require_noerr( err
, exit
);
1026 // Search for an existing interface with the same info. If found, just return that one.
1028 scopeID
= if_nametoindex( inIFA
->ifa_name
);
1030 for( p
= &inMDNS
->p
->interfaceList
; *p
; p
= &( *p
)->next
)
1032 if( ( scopeID
== ( *p
)->scopeID
) && mDNSSameAddress( &ip
, &( *p
)->ifinfo
.ip
) )
1034 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Found existing interface %u with address %#a at %#p\n", __ROUTINE__
,
1036 ( *p
)->exists
= mDNStrue
;
1042 // Allocate the new interface info and fill it out.
1044 i
= (NetworkInterfaceInfoVxWorks
*) calloc( 1, sizeof( *i
) );
1047 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Making new interface %u with address %#a at %#p\n", __ROUTINE__
, scopeID
, &ip
, i
);
1048 strncpy( i
->ifinfo
.ifname
, inIFA
->ifa_name
, sizeof( i
->ifinfo
.ifname
) );
1049 i
->ifinfo
.ifname
[ sizeof( i
->ifinfo
.ifname
) - 1 ] = '\0';
1050 i
->ifinfo
.InterfaceID
= NULL
;
1052 i
->ifinfo
.mask
= mask
;
1053 i
->ifinfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1054 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList.
1057 i
->exists
= mDNStrue
;
1058 i
->lastSeen
= inUTC
;
1059 i
->scopeID
= scopeID
;
1060 i
->family
= inIFA
->ifa_addr
->sa_family
;
1061 i
->multicast
= ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTOPOINT
);
1064 i
->ss
.sockV4
= kInvalidSocketRef
;
1065 i
->ss
.sockV6
= kInvalidSocketRef
;
1072 //===========================================================================================================================
1073 // SetupActiveInterfaces
1075 // Returns a count of non-link local IPv4 addresses registered.
1076 //===========================================================================================================================
1078 #define mDNSAddressIsNonLinkLocalIPv4( X ) \
1079 ( ( ( X )->type == mDNSAddrType_IPv4 ) && ( ( ( X )->ip.v4.b[ 0 ] != 169 ) || ( ( X )->ip.v4.b[ 1 ] != 254 ) ) )
1081 mDNSlocal
int SetupActiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
)
1084 NetworkInterfaceInfoVxWorks
* i
;
1087 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1089 NetworkInterfaceInfo
* n
;
1090 NetworkInterfaceInfoVxWorks
* primary
;
1092 if( !i
->exists
) continue;
1094 // Search for the primary interface and sanity check it.
1097 primary
= FindInterfaceByIndex( inMDNS
, i
->family
, i
->scopeID
);
1100 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! didn't find %s(%u)\n", __ROUTINE__
, i
->ifinfo
.ifname
, i
->scopeID
);
1103 if( n
->InterfaceID
&& ( n
->InterfaceID
!= (mDNSInterfaceID
) primary
) )
1105 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! n->InterfaceID %#p != primary %#p\n", __ROUTINE__
,
1106 n
->InterfaceID
, primary
);
1107 n
->InterfaceID
= NULL
;
1110 // If n->InterfaceID is set, it means we've already called mDNS_RegisterInterface() for this interface.
1111 // so we don't need to call it again. Otherwise, register the interface with mDNS.
1113 if( !n
->InterfaceID
)
1117 n
->InterfaceID
= (mDNSInterfaceID
) primary
;
1119 // If lastSeen == inUTC, then this is a brand-new interface, or an interface that never went away.
1120 // If lastSeen != inUTC, then this is an old interface, that went away for (inUTC - lastSeen) seconds.
1121 // If it's is an old one that went away and came back in less than a minute, we're in a flapping scenario.
1123 flapping
= ( ( inUTC
- i
->lastSeen
) > 0 ) && ( ( inUTC
- i
->lastSeen
) < 60 );
1124 mDNS_RegisterInterface( inMDNS
, n
, flapping
);
1125 if( mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) ) ++count
;
1127 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Registered %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__
,
1128 i
->ifinfo
.ifname
, i
->scopeID
, primary
, &n
->ip
,
1129 flapping
? " (Flapping)" : "",
1130 n
->InterfaceActive
? " (Primary)" : "" );
1133 // Set up a socket if it's not already set up. If multicast is not enabled on this interface then we
1134 // don't need a socket since unicast traffic will be handled on the unicast socket.
1140 if( ( ( i
->family
== AF_INET
) && !IsValidSocket( primary
->ss
.sockV4
) ) ||
1141 ( ( i
->family
== AF_INET6
) && !IsValidSocket( primary
->ss
.sockV6
) ) )
1143 err
= SetupSocket( inMDNS
, &i
->ifinfo
.ip
, mDNStrue
, i
->family
, &primary
->ss
);
1149 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: No Tx/Rx on %8s(%u) InterfaceID %#p %#a\n", __ROUTINE__
,
1150 i
->ifinfo
.ifname
, i
->scopeID
, primary
, &n
->ip
);
1156 //===========================================================================================================================
1157 // MarkAllInterfacesInactive
1158 //===========================================================================================================================
1160 mDNSlocal
void MarkAllInterfacesInactive( mDNS
*const inMDNS
, mDNSs32 inUTC
)
1162 NetworkInterfaceInfoVxWorks
* i
;
1164 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1166 if( !i
->exists
) continue;
1167 i
->lastSeen
= inUTC
;
1168 i
->exists
= mDNSfalse
;
1172 //===========================================================================================================================
1173 // ClearInactiveInterfaces
1175 // Returns count of non-link local IPv4 addresses de-registered.
1176 //===========================================================================================================================
1178 mDNSlocal
int ClearInactiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
, mDNSBool inClosing
)
1181 NetworkInterfaceInfoVxWorks
* i
;
1182 NetworkInterfaceInfoVxWorks
** p
;
1185 // If an interface is going away, then de-register it from mDNSCore.
1186 // We also have to de-register it if the primary interface that it's using for its InterfaceID is going away.
1187 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1188 // it refers to has gone away, we'll crash. Don't actually close the sockets or free the memory yet though:
1189 // When the last representative of an interface goes away mDNSCore may want to send goodbye packets on that
1190 // interface. (Not yet implemented, but a good idea anyway.).
1193 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1195 NetworkInterfaceInfoVxWorks
* primary
;
1197 // 1. If this interface is no longer active, or its InterfaceID is changing, de-register it.
1199 if( !i
->ifinfo
.InterfaceID
) continue;
1200 primary
= FindInterfaceByIndex( inMDNS
, i
->family
, i
->scopeID
);
1201 if( ( i
->exists
== 0 ) || ( i
->exists
== 2 ) || ( i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
) primary
) )
1203 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Deregistering %8s(%u) InterfaceID %#p %#a%s\n", __ROUTINE__
,
1204 i
->ifinfo
.ifname
, i
->scopeID
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
,
1205 i
->ifinfo
.InterfaceActive
? " (Primary)" : "" );
1207 mDNS_DeregisterInterface( inMDNS
, &i
->ifinfo
, mDNSfalse
);
1208 i
->ifinfo
.InterfaceID
= NULL
;
1209 if( mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) ) ++count
;
1214 // Now that everything that's going to de-register has done so, we can close sockets and free the memory.
1216 p
= &inMDNS
->p
->interfaceList
;
1221 // 2. Close all our sockets. We'll recreate them later as needed.
1222 // (We may have previously had both v4 and v6, and we may not need both any more.).
1224 ForgetSocket( &i
->ss
.sockV4
);
1225 ForgetSocket( &i
->ss
.sockV6
);
1227 // 3. If no longer active, remove the interface from the list and free its memory.
1235 check_string( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) i
) == 0, "closing with in-use records!" );
1236 deleteIt
= mDNStrue
;
1240 if( i
->lastSeen
== inUTC
) i
->lastSeen
= inUTC
- 1;
1241 deleteIt
= ( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) i
) == 0 ) && ( ( inUTC
- i
->lastSeen
) >= 60 );
1243 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: %-13s %8s(%u) InterfaceID %#p %#a Age %d%s\n", __ROUTINE__
,
1244 deleteIt
? "Deleting" : "Holding", i
->ifinfo
.ifname
, i
->scopeID
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
,
1245 inUTC
- i
->lastSeen
, i
->ifinfo
.InterfaceActive
? " (Primary)" : "" );
1258 //===========================================================================================================================
1260 //===========================================================================================================================
1262 mDNSlocal NetworkInterfaceInfoVxWorks
* FindRoutableIPv4( mDNS
*const inMDNS
, mDNSu32 inScopeID
)
1264 #if( MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
1265 NetworkInterfaceInfoVxWorks
* i
;
1267 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1269 if( i
->exists
&& ( i
->scopeID
== inScopeID
) && mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) )
1276 DEBUG_UNUSED( inMDNS
);
1277 DEBUG_UNUSED( inScopeID
);
1283 //===========================================================================================================================
1284 // FindInterfaceByIndex
1285 //===========================================================================================================================
1287 mDNSlocal NetworkInterfaceInfoVxWorks
* FindInterfaceByIndex( mDNS
*const inMDNS
, int inFamily
, mDNSu32 inIndex
)
1289 NetworkInterfaceInfoVxWorks
* i
;
1291 check( inIndex
!= 0 );
1293 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1295 if( i
->exists
&& ( i
->scopeID
== inIndex
) &&
1296 ( MDNS_AAAA_OVER_IPV4
||
1297 ( ( inFamily
== AF_INET
) && ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ) ||
1298 ( ( inFamily
== AF_INET6
) && ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) ) ) )
1306 //===========================================================================================================================
1308 //===========================================================================================================================
1310 mDNSlocal mStatus
SetupSocket( mDNS
*const inMDNS
, const mDNSAddr
*inAddr
, mDNSBool inMcast
, int inFamily
, SocketSet
*inSS
)
1313 SocketRef
* sockPtr
;
1321 sockPtr
= ( inFamily
== AF_INET
) ? &inSS
->sockV4
: &inSS
->sockV6
;
1322 port
= ( inMcast
|| inMDNS
->CanReceiveUnicastOn5353
) ? MulticastDNSPort
: zeroIPPort
;
1324 sock
= socket( inFamily
, SOCK_DGRAM
, IPPROTO_UDP
);
1325 err
= translate_errno( IsValidSocket( sock
), errno_compat(), mStatus_UnknownErr
);
1326 require_noerr( err
, exit
);
1328 // Allow multiple listeners if this is a multicast port.
1330 if( port
.NotAnInteger
)
1332 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEPORT
, (char *) &on
, sizeof( on
) );
1333 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1336 // Set up the socket based on the family (IPv4 or IPv6).
1338 if( inFamily
== AF_INET
)
1340 const int ttlV4
= 255;
1341 const u_char ttlV4Mcast
= 255;
1342 struct sockaddr_in sa4
;
1344 // Receive destination addresses so we know which address the packet was sent to.
1346 err
= setsockopt( sock
, IPPROTO_IP
, IP_RECVDSTADDR
, (char *) &on
, sizeof( on
) );
1347 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1349 // Receive interface indexes so we know which interface received the packet.
1351 err
= setsockopt( sock
, IPPROTO_IP
, IP_RECVIF
, (char *) &on
, sizeof( on
) );
1352 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1354 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1358 struct in_addr addrV4
;
1359 struct ip_mreq mreqV4
;
1361 addrV4
.s_addr
= inAddr
->ip
.v4
.NotAnInteger
;
1362 mreqV4
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1363 mreqV4
.imr_interface
= addrV4
;
1364 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqV4
, sizeof( mreqV4
) );
1365 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1367 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addrV4
, sizeof( addrV4
) );
1368 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1371 // Send unicast packets with TTL 255 (helps against spoofing).
1373 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &ttlV4
, sizeof( ttlV4
) );
1374 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1376 // Send multicast packets with TTL 255 (helps against spoofing).
1378 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &ttlV4Mcast
, sizeof( ttlV4Mcast
) );
1379 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1381 // Start listening for packets.
1383 mDNSPlatformMemZero( &sa4
, sizeof( sa4
) );
1384 sa4
.sin_len
= sizeof( sa4
);
1385 sa4
.sin_family
= AF_INET
;
1386 sa4
.sin_port
= port
.NotAnInteger
;
1387 sa4
.sin_addr
.s_addr
= htonl( INADDR_ANY
); // We want to receive multicasts AND unicasts on this socket.
1388 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
1389 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1391 else if( inFamily
== AF_INET6
)
1393 struct sockaddr_in6 sa6
;
1394 const int ttlV6
= 255;
1396 // Receive destination addresses and interface index so we know where the packet was received and intended.
1398 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &on
, sizeof( on
) );
1399 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1401 // Receive only IPv6 packets because otherwise, we may get IPv4 addresses as IPv4-mapped IPv6 addresses.
1403 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &on
, sizeof( on
) );
1404 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1406 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1411 struct ipv6_mreq mreqV6
;
1413 ifindex
= inSS
->info
->scopeID
;
1414 mreqV6
.ipv6mr_interface
= ifindex
;
1415 mreqV6
.ipv6mr_multiaddr
= *( (struct in6_addr
* ) &AllDNSLinkGroup_v6
.ip
.v6
);
1416 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqV6
, sizeof( mreqV6
) );
1417 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1419 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &ifindex
, sizeof( ifindex
) );
1420 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1423 // Send unicast packets with TTL 255 (helps against spoofing).
1425 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &ttlV6
, sizeof( ttlV6
) );
1426 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1428 // Send multicast packets with TTL 255 (helps against spoofing).
1430 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &ttlV6
, sizeof( ttlV6
) );
1431 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1433 // Receive our own packets for same-machine operation.
1435 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &on
, sizeof( on
) );
1436 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1438 // Start listening for packets.
1440 mDNSPlatformMemZero( &sa6
, sizeof( sa6
) );
1441 sa6
.sin6_len
= sizeof( sa6
);
1442 sa6
.sin6_family
= AF_INET6
;
1443 sa6
.sin6_port
= port
.NotAnInteger
;
1444 sa6
.sin6_flowinfo
= 0;
1445 sa6
.sin6_addr
= in6addr_any
; // We want to receive multicasts AND unicasts on this socket.
1446 sa6
.sin6_scope_id
= 0;
1447 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
1448 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1452 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inFamily
);
1453 err
= kUnsupportedErr
;
1457 // Make the socket non-blocking so we can potentially get multiple packets per select call.
1459 err
= ioctl( sock
, FIONBIO
, (int) &on
);
1460 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1463 sock
= kInvalidSocketRef
;
1464 err
= mStatus_NoError
;
1467 if( IsValidSocket( sock
) ) close_compat( sock
);
1471 //===========================================================================================================================
1472 // SockAddrToMDNSAddr
1473 //===========================================================================================================================
1475 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
)
1482 if( inSA
->sa_family
== AF_INET
)
1484 struct sockaddr_in
* sa4
;
1486 sa4
= (struct sockaddr_in
*) inSA
;
1487 outIP
->type
= mDNSAddrType_IPv4
;
1488 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
1489 err
= mStatus_NoError
;
1491 else if( inSA
->sa_family
== AF_INET6
)
1493 struct sockaddr_in6
* sa6
;
1495 sa6
= (struct sockaddr_in6
*) inSA
;
1496 outIP
->type
= mDNSAddrType_IPv6
;
1497 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
1498 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) ) outIP
->ip
.v6
.w
[ 1 ] = 0;
1499 err
= mStatus_NoError
;
1503 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family (%d)\n", __ROUTINE__
, inSA
->sa_family
);
1504 err
= mStatus_BadParamErr
;
1511 #pragma mark == Commands ==
1514 //===========================================================================================================================
1516 //===========================================================================================================================
1518 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1522 err
= pipeDevCreate( "/pipe/mDNS", 32, 1 );
1523 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1525 inMDNS
->p
->commandPipe
= open( "/pipe/mDNS", O_RDWR
, 0 );
1526 err
= translate_errno( inMDNS
->p
->commandPipe
!= ERROR
, errno_compat(), mStatus_UnsupportedErr
);
1527 require_noerr( err
, exit
);
1533 //===========================================================================================================================
1534 // TearDownCommandPipe
1535 //===========================================================================================================================
1537 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1541 if( inMDNS
->p
->commandPipe
!= ERROR
)
1543 err
= close( inMDNS
->p
->commandPipe
);
1544 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1545 inMDNS
->p
->commandPipe
= ERROR
;
1547 err
= pipeDevDelete( "/pipe/mDNS", FALSE
);
1548 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1550 return( mStatus_NoError
);
1553 //===========================================================================================================================
1555 //===========================================================================================================================
1557 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1561 require_action_quiet( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1563 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1564 err
= translate_errno( err
>= 0, errno_compat(), kWriteErr
);
1565 require_noerr( err
, exit
);
1571 //===========================================================================================================================
1573 //===========================================================================================================================
1575 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1578 MDNSPipeCommandCode cmd
;
1581 err
= read( inMDNS
->p
->commandPipe
, &cmd
, sizeof( cmd
) );
1582 err
= translate_errno( err
>= 0, errno_compat(), kReadErr
);
1583 require_noerr( err
, exit
);
1587 case kMDNSPipeCommandCodeReschedule
: // Reschedule: just break out to re-run mDNS_Execute.
1590 case kMDNSPipeCommandCodeReconfigure
: // Reconfigure: rebuild the interface list after a config change.
1591 dmsg( kDebugLevelInfo
, DEBUG_NAME
"*** NETWORK CONFIGURATION CHANGE ***\n" );
1592 mDNSPlatformLock( inMDNS
);
1594 utc
= mDNSPlatformUTC();
1595 MarkAllInterfacesInactive( inMDNS
, utc
);
1596 UpdateInterfaceList( inMDNS
, utc
);
1597 ClearInactiveInterfaces( inMDNS
, utc
, mDNSfalse
);
1598 SetupActiveInterfaces( inMDNS
, utc
);
1600 mDNSPlatformUnlock( inMDNS
);
1601 mDNS_ConfigChanged(inMDNS
);
1604 case kMDNSPipeCommandCodeQuit
: // Quit: just set a flag so the task exits cleanly.
1605 inMDNS
->p
->quit
= mDNStrue
;
1609 dmsg( kDebugLevelError
, DEBUG_NAME
"unknown pipe command (%d)\n", cmd
);
1610 err
= mStatus_BadParamErr
;
1620 #pragma mark == Threads ==
1623 //===========================================================================================================================
1625 //===========================================================================================================================
1627 mDNSlocal
void Task( mDNS
*inMDNS
)
1633 struct timeval timeout
;
1634 NetworkInterfaceInfoVxWorks
* i
;
1640 err
= TaskInit( inMDNS
);
1641 require_noerr( err
, exit
);
1643 while( !inMDNS
->p
->quit
)
1645 // Let mDNSCore do its work then wait for an event. On idle timeouts (n == 0), just loop back to mDNS_Exceute.
1647 nextEvent
= mDNS_Execute( inMDNS
);
1648 TaskSetupSelect( inMDNS
, &readSet
, &maxFd
, nextEvent
, &timeout
);
1649 n
= select( maxFd
+ 1, &readSet
, NULL
, NULL
, &timeout
);
1650 check_translated_errno( n
>= 0, errno_compat(), kUnknownErr
);
1651 if( n
== 0 ) continue;
1653 // Process interface-specific sockets with pending data.
1656 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1659 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1661 TaskProcessPackets( inMDNS
, &i
->ss
, fd
);
1665 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1667 TaskProcessPackets( inMDNS
, &i
->ss
, fd
);
1672 // Process unicast sockets with pending data.
1674 fd
= inMDNS
->p
->unicastSS
.sockV4
;
1675 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1677 TaskProcessPackets( inMDNS
, &inMDNS
->p
->unicastSS
, fd
);
1680 fd
= inMDNS
->p
->unicastSS
.sockV6
;
1681 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1683 TaskProcessPackets( inMDNS
, &inMDNS
->p
->unicastSS
, fd
);
1687 // Processing pending commands.
1689 fd
= inMDNS
->p
->commandPipe
;
1691 if( FD_ISSET( fd
, &readSet
) )
1693 ProcessCommand( inMDNS
);
1696 check_string( n
> 0, "select said something was readable, but nothing was" );
1703 //===========================================================================================================================
1705 //===========================================================================================================================
1707 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1713 inMDNS
->p
->taskID
= taskIdSelf();
1715 err
= SetupCommandPipe( inMDNS
);
1716 require_noerr( err
, exit
);
1718 inMDNS
->CanReceiveUnicastOn5353
= mDNStrue
;
1720 // Set up the HINFO string using the description property (e.g. "Device V1.0").
1722 inMDNS
->HIHardware
.c
[ 0 ] = 11;
1723 memcpy( &inMDNS
->HIHardware
.c
[ 1 ], "Device V1.0", inMDNS
->HIHardware
.c
[ 0 ] ); // $$$ Implementers: Fill in real info.
1725 // Set up the unicast sockets.
1727 err
= SetupSocket( inMDNS
, &zeroAddr
, mDNSfalse
, AF_INET
, &inMDNS
->p
->unicastSS
);
1729 if( err
== mStatus_NoError
)
1731 struct sockaddr_in sa4
;
1733 len
= sizeof( sa4
);
1734 err
= getsockname( inMDNS
->p
->unicastSS
.sockV4
, (struct sockaddr
*) &sa4
, &len
);
1735 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1736 if( err
== 0 ) inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
1739 err
= SetupSocket( inMDNS
, &zeroAddr
, mDNSfalse
, AF_INET6
, &inMDNS
->p
->unicastSS
);
1741 if( err
== mStatus_NoError
)
1743 struct sockaddr_in6 sa6
;
1745 len
= sizeof( sa6
);
1746 err
= getsockname( inMDNS
->p
->unicastSS
.sockV6
, (struct sockaddr
*) &sa6
, &len
);
1747 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1748 if( err
== 0 ) inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
1751 // Set up the interfaces.
1753 utc
= mDNSPlatformUTC();
1754 UpdateInterfaceList( inMDNS
, utc
);
1755 SetupActiveInterfaces( inMDNS
, utc
);
1756 err
= mStatus_NoError
;
1759 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1761 inMDNS
->p
->initErr
= err
;
1762 semGive( inMDNS
->p
->initEvent
);
1766 //===========================================================================================================================
1768 //===========================================================================================================================
1770 mDNSlocal
void TaskTerm( mDNS
*inMDNS
)
1775 // Tear down all interfaces.
1777 utc
= mDNSPlatformUTC();
1778 MarkAllInterfacesInactive( inMDNS
, utc
);
1779 ClearInactiveInterfaces( inMDNS
, utc
, mDNStrue
);
1780 check_string( !inMDNS
->p
->interfaceList
, "LEAK: closing without deleting all interfaces" );
1782 // Close unicast sockets.
1784 ForgetSocket( &inMDNS
->p
->unicastSS
.sockV4
);
1785 ForgetSocket( &inMDNS
->p
->unicastSS
.sockV6
);
1787 // Tear down everything else that was set up in TaskInit then signal back that we're done.
1789 err
= TearDownCommandPipe( inMDNS
);
1792 err
= semGive( inMDNS
->p
->quitEvent
);
1793 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1796 //===========================================================================================================================
1798 //===========================================================================================================================
1800 mDNSlocal
void TaskSetupSelect( mDNS
*inMDNS
, fd_set
*outSet
, int *outMaxFd
, mDNSs32 inNextEvent
, struct timeval
*outTimeout
)
1802 NetworkInterfaceInfoVxWorks
* i
;
1810 // Add the interface-specific sockets.
1812 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1815 if( IsValidSocket( fd
) )
1817 FD_SET( fd
, outSet
);
1818 if( fd
> maxFd
) maxFd
= fd
;
1822 if( IsValidSocket( fd
) )
1824 FD_SET( fd
, outSet
);
1825 if( fd
> maxFd
) maxFd
= fd
;
1829 // Add the unicast sockets.
1831 fd
= inMDNS
->p
->unicastSS
.sockV4
;
1832 if( IsValidSocket( fd
) )
1834 FD_SET( fd
, outSet
);
1835 if( fd
> maxFd
) maxFd
= fd
;
1838 fd
= inMDNS
->p
->unicastSS
.sockV6
;
1839 if( IsValidSocket( fd
) )
1841 FD_SET( fd
, outSet
);
1842 if( fd
> maxFd
) maxFd
= fd
;
1845 // Add the command pipe.
1847 fd
= inMDNS
->p
->commandPipe
;
1849 FD_SET( fd
, outSet
);
1850 if( fd
> maxFd
) maxFd
= fd
;
1855 // Calculate how long to wait before performing idle processing.
1857 delta
= inNextEvent
- mDNS_TimeNow( inMDNS
);
1860 // The next task time is now or in the past. Set the timeout to fire immediately.
1862 outTimeout
->tv_sec
= 0;
1863 outTimeout
->tv_usec
= 0;
1867 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
1868 // before multiplying to account for integer rounding error and avoid firing the timeout too early.
1870 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1871 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicro
;
1872 if( outTimeout
->tv_usec
>= 1000000L )
1874 outTimeout
->tv_sec
+= 1;
1875 outTimeout
->tv_usec
= 0;
1880 //===========================================================================================================================
1881 // TaskProcessPackets
1882 //===========================================================================================================================
1884 mDNSlocal
void TaskProcessPackets( mDNS
*inMDNS
, SocketSet
*inSS
, SocketRef inSock
)
1890 struct sockaddr_storage from
;
1893 mDNSAddr senderAddr
;
1894 mDNSIPPort senderPort
;
1897 buf
= (mDNSu8
*) &inMDNS
->imsg
;
1898 size
= sizeof( inMDNS
->imsg
);
1902 n
= mDNSRecvMsg( inSock
, buf
, size
, &from
, sizeof( from
), &fromSize
, &destAddr
, &ifindex
);
1904 if( from
.ss_family
== AF_INET
)
1906 struct sockaddr_in
* sa4
;
1908 sa4
= (struct sockaddr_in
*) &from
;
1909 senderAddr
.type
= mDNSAddrType_IPv4
;
1910 senderAddr
.ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
1911 senderPort
.NotAnInteger
= sa4
->sin_port
;
1913 else if( from
.ss_family
== AF_INET6
)
1915 struct sockaddr_in6
* sa6
;
1917 sa6
= (struct sockaddr_in6
*) &from
;
1918 senderAddr
.type
= mDNSAddrType_IPv6
;
1919 senderAddr
.ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
1920 senderPort
.NotAnInteger
= sa6
->sin6_port
;
1924 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: WARNING! from addr unknown family %d\n", __ROUTINE__
, from
.ss_family
);
1928 // Even though we indicated a specific interface when joining the multicast group, a weirdness of the
1929 // sockets API means that even though this socket has only officially joined the multicast group
1930 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
1931 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
1932 // To work around this weirdness, we use the IP_RECVIF/IPV6_PKTINFO options to find the interface
1933 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
1935 if( mDNSAddrIsDNSMulticast( &destAddr
) )
1937 if( !inSS
->info
|| !inSS
->info
->exists
)
1939 dpkt( kDebugLevelChatty
- 3, DEBUG_NAME
" ignored mcast, src=[%#39a], dst=[%#39a], if= unicast socket %d\n",
1940 &senderAddr
, &destAddr
, inSock
);
1943 if( ifindex
!= inSS
->info
->scopeID
)
1945 #if( DEBUG && MDNS_DEBUG_PACKETS )
1946 char ifname
[ IF_NAMESIZE
];
1949 dpkt( kDebugLevelChatty
- 3,
1950 DEBUG_NAME
" ignored mcast, src=[%#39a] dst=[%#39a], if=%8s(%u) -- really for %8s(%u)\n",
1951 &senderAddr
, &destAddr
, inSS
->info
->ifinfo
.ifname
, inSS
->info
->scopeID
,
1952 if_indextoname( ifindex
, ifname
), ifindex
);
1956 id
= inSS
->info
->ifinfo
.InterfaceID
;
1957 dpkt( kDebugLevelChatty
- 2, DEBUG_NAME
"recv %4d bytes, src=[%#39a]:%5hu, dst=[%#39a], if=%8s(%u) %#p\n",
1958 n
, &senderAddr
, mDNSVal16( senderPort
), &destAddr
, inSS
->info
->ifinfo
.ifname
, inSS
->info
->scopeID
, id
);
1962 NetworkInterfaceInfoVxWorks
* i
;
1964 // For unicast packets, try to find the matching interface.
1966 for( i
= inMDNS
->p
->interfaceList
; i
&& ( i
->scopeID
!= ifindex
); i
= i
->next
) {}
1967 if( i
) id
= i
->ifinfo
.InterfaceID
;
1970 mDNSCoreReceive( inMDNS
, buf
, buf
+ n
, &senderAddr
, senderPort
, &destAddr
, MulticastDNSPort
, id
);
1974 //===========================================================================================================================
1976 //===========================================================================================================================
1982 size_t inBufferSize
,
1985 size_t * outFromSize
,
1986 mDNSAddr
* outDstAddr
,
1987 uint32_t * outIndex
)
1992 char ancillary
[ 1024 ];
1993 struct cmsghdr
* cmPtr
;
1996 // Read a packet and any ancillary data. Note: EWOULDBLOCK errors are expected when we've read all pending packets.
1998 iov
.iov_base
= (char *) inBuffer
;
1999 iov
.iov_len
= inBufferSize
;
2000 msg
.msg_name
= (caddr_t
) outFrom
;
2001 msg
.msg_namelen
= inFromSize
;
2004 msg
.msg_control
= (caddr_t
) &ancillary
;
2005 msg
.msg_controllen
= sizeof( ancillary
);
2007 n
= recvmsg( inSock
, &msg
, 0 );
2010 err
= errno_compat();
2011 if( err
!= EWOULDBLOCK
) dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) returned %d, errno %d\n",
2012 __ROUTINE__
, inSock
, n
, err
);
2015 if( msg
.msg_controllen
< sizeof( struct cmsghdr
) )
2017 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) msg_controllen %d < sizeof( struct cmsghdr ) %u\n",
2018 __ROUTINE__
, inSock
, msg
.msg_controllen
, sizeof( struct cmsghdr
) );
2019 n
= mStatus_UnknownErr
;
2022 if( msg
.msg_flags
& MSG_CTRUNC
)
2024 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) MSG_CTRUNC (%d recv'd)\n", __ROUTINE__
, inSock
, n
);
2025 n
= mStatus_BadFlagsErr
;
2028 *outFromSize
= msg
.msg_namelen
;
2030 // Parse each option out of the ancillary data.
2032 for( cmPtr
= CMSG_FIRSTHDR( &msg
); cmPtr
; cmPtr
= CMSG_NXTHDR( &msg
, cmPtr
) )
2034 if( ( cmPtr
->cmsg_level
== IPPROTO_IP
) && ( cmPtr
->cmsg_type
== IP_RECVDSTADDR
) )
2036 outDstAddr
->type
= mDNSAddrType_IPv4
;
2037 outDstAddr
->ip
.v4
.NotAnInteger
= *( (mDNSu32
*) CMSG_DATA( cmPtr
) );
2039 else if( ( cmPtr
->cmsg_level
== IPPROTO_IP
) && ( cmPtr
->cmsg_type
== IP_RECVIF
) )
2041 struct sockaddr_dl
* sdl
;
2043 sdl
= (struct sockaddr_dl
*) CMSG_DATA( cmPtr
);
2044 *outIndex
= sdl
->sdl_index
;
2046 else if( ( cmPtr
->cmsg_level
== IPPROTO_IPV6
) && ( cmPtr
->cmsg_type
== IPV6_PKTINFO
) )
2048 struct in6_pktinfo
* pi6
;
2050 pi6
= (struct in6_pktinfo
*) CMSG_DATA( cmPtr
);
2051 outDstAddr
->type
= mDNSAddrType_IPv6
;
2052 outDstAddr
->ip
.v6
= *( (mDNSv6Addr
*) &pi6
->ipi6_addr
);
2053 *outIndex
= pi6
->ipi6_ifindex
;
2063 #pragma mark == Debugging ==
2066 #if( DEBUG && MDNS_DEBUG_SHOW )
2067 //===========================================================================================================================
2069 //===========================================================================================================================
2071 void mDNSShow( void );
2073 void mDNSShow( void )
2075 NetworkInterfaceInfoVxWorks
* i
;
2082 dmsg( kDebugLevelMax
, "\n-- mDNS globals --\n" );
2083 dmsg( kDebugLevelMax
, " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS
) );
2084 dmsg( kDebugLevelMax
, " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord
) );
2085 dmsg( kDebugLevelMax
, " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord
) );
2086 dmsg( kDebugLevelMax
, " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord
) );
2087 dmsg( kDebugLevelMax
, " mDNSPlatformOneSecond = %ld\n", mDNSPlatformOneSecond
);
2088 dmsg( kDebugLevelMax
, " gMDNSTicksToMicro = %ld\n", gMDNSTicksToMicro
);
2089 dmsg( kDebugLevelMax
, " gMDNSPtr = %#p\n", gMDNSPtr
);
2092 dmsg( kDebugLevelMax
, "### mDNS not initialized\n" );
2095 dmsg( kDebugLevelMax
, " nicelabel = \"%#s\"\n", gMDNSPtr
->nicelabel
.c
);
2096 dmsg( kDebugLevelMax
, " hostLabel = \"%#s\"\n", gMDNSPtr
->hostlabel
.c
);
2097 dmsg( kDebugLevelMax
, " MulticastHostname = \"%##s\"\n", gMDNSPtr
->MulticastHostname
.c
);
2098 dmsg( kDebugLevelMax
, " HIHardware = \"%#s\"\n", gMDNSPtr
->HIHardware
.c
);
2099 dmsg( kDebugLevelMax
, " HISoftware = \"%#s\"\n", gMDNSPtr
->HISoftware
.c
);
2100 dmsg( kDebugLevelMax
, " UnicastPort4/6 = %d/%d\n",
2101 mDNSVal16( gMDNSPtr
->UnicastPort4
), mDNSVal16( gMDNSPtr
->UnicastPort6
) );
2102 dmsg( kDebugLevelMax
, " unicastSS.sockV4/V6 = %d/%d\n",
2103 gMDNSPtr
->p
->unicastSS
.sockV4
, gMDNSPtr
->p
->unicastSS
.sockV6
);
2104 dmsg( kDebugLevelMax
, " lock = %#p\n", gMDNSPtr
->p
->lock
);
2105 dmsg( kDebugLevelMax
, " initEvent = %#p\n", gMDNSPtr
->p
->initEvent
);
2106 dmsg( kDebugLevelMax
, " initErr = %ld\n", gMDNSPtr
->p
->initErr
);
2107 dmsg( kDebugLevelMax
, " quitEvent = %#p\n", gMDNSPtr
->p
->quitEvent
);
2108 dmsg( kDebugLevelMax
, " commandPipe = %d\n", gMDNSPtr
->p
->commandPipe
);
2109 dmsg( kDebugLevelMax
, " taskID = %#p\n", gMDNSPtr
->p
->taskID
);
2110 dmsg( kDebugLevelMax
, "\n" );
2114 utc
= mDNSPlatformUTC();
2115 dmsg( kDebugLevelMax
, "-- mDNS interfaces --\n" );
2117 for( i
= gMDNSPtr
->p
->interfaceList
; i
; i
= i
->next
)
2119 dmsg( kDebugLevelMax
, " interface %2d %8s(%u) [%#39a] %s, sockV4 %2d, sockV6 %2d, Age %d\n",
2120 num
, i
->ifinfo
.ifname
, i
->scopeID
, &i
->ifinfo
.ip
,
2121 i
->ifinfo
.InterfaceID
? " REGISTERED" : "*NOT* registered",
2122 i
->ss
.sockV4
, i
->ss
.sockV6
, utc
- i
->lastSeen
);
2125 dmsg( kDebugLevelMax
, "\n" );
2129 dmsg( kDebugLevelMax
, "-- mDNS resource records --\n" );
2131 for( r
= gMDNSPtr
->ResourceRecords
; r
; r
= r
->next
)
2133 i
= (NetworkInterfaceInfoVxWorks
*) r
->resrec
.InterfaceID
;
2134 if( r
->resrec
.rrtype
== kDNSType_TXT
)
2142 rd
= &r
->resrec
.rdata
->u
;
2143 dmsg( kDebugLevelMax
, " record %2d: %#p %8s(%u): %4d %##s %s:\n", num
, i
,
2144 i
? i
->ifinfo
.ifname
: "<any>",
2146 r
->resrec
.rdlength
, r
->resrec
.name
->c
, DNSTypeName( r
->resrec
.rrtype
) );
2150 end
= txt
+ r
->resrec
.rdlength
;
2154 if( ( txt
+ size
) > end
)
2156 dmsg( kDebugLevelMax
, " ### ERROR! txt length byte too big (%u, %u max)\n", size
, end
- txt
);
2159 dmsg( kDebugLevelMax
, " string %2d (%3d bytes): \"%.*s\"\n", nEntries
, size
, size
, txt
);
2166 dmsg( kDebugLevelMax
, " record %2d: %#p %8s(%u): %s\n", num
, i
,
2167 i
? i
->ifinfo
.ifname
: "<any>",
2169 ARDisplayString( gMDNSPtr
, r
) );
2173 dmsg( kDebugLevelMax
, "\n");
2175 #endif // DEBUG && MDNS_DEBUG_SHOW