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.33 2007/03/22 18:31:48 cheshire
21 Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
23 Revision 1.32 2006/12/19 22:43:56 cheshire
26 Revision 1.31 2006/11/10 00:54:16 cheshire
27 <rdar://problem/4816598> Changing case of Computer Name doesn't work
29 Revision 1.30 2006/08/14 23:25:18 cheshire
30 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
32 Revision 1.29 2006/03/19 02:00:12 cheshire
33 <rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
35 Revision 1.28 2005/05/30 07:36:38 bradley
36 New implementation of the mDNS platform plugin for VxWorks 5.5 or later with IPv6 support.
41 #pragma mark == Configuration ==
44 //===========================================================================================================================
46 //===========================================================================================================================
48 #define DEBUG_NAME "[mDNS] "
49 #define MDNS_AAAA_OVER_IPV4 1 // 1=Send AAAA & A records over IPv4 & IPv6, 0=Send AAAA over IPv6, A over IPv4.
50 #define MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 1 // 1=Don't use IPv6 socket if non-link-local IPv4 available on same interface.
51 #define MDNS_ENABLE_PPP 0 // 1=Enable Unicast DNS over PPP interfaces. 0=Don't enable it.
52 #define MDNS_DEBUG_PACKETS 1 // 1=Enable debug output for packet send/recv if debug level high enough.
53 #define MDNS_DEBUG_SHOW 1 // 1=Enable console show routines.
54 #define DEBUG_USE_DEFAULT_CATEGORY 1 // Set up to use the default category (see DebugServices.h for details).
66 #include <sys/types.h>
68 #include <arpa/inet.h>
70 #include <net/if_dl.h>
71 #include <net/if_types.h>
72 #include <net/ifaddrs.h>
73 #include <netinet6/in6_var.h>
74 #include <netinet/if_ether.h>
75 #include <netinet/in.h>
76 #include <netinet/ip.h>
77 #include <sys/ioctl.h>
78 #include <sys/socket.h>
84 #include "selectLib.h"
91 #include "CommonServices.h"
92 #include "DebugServices.h"
93 #include "DNSCommon.h"
94 #include "mDNSEmbeddedAPI.h"
96 #include "mDNSVxWorks.h"
99 #pragma mark == Constants ==
102 //===========================================================================================================================
104 //===========================================================================================================================
106 typedef uint8_t MDNSPipeCommandCode
;
108 #define kMDNSPipeCommandCodeInvalid 0
109 #define kMDNSPipeCommandCodeReschedule 1
110 #define kMDNSPipeCommandCodeReconfigure 2
111 #define kMDNSPipeCommandCodeQuit 3
114 #pragma mark == Prototypes ==
117 //===========================================================================================================================
119 //===========================================================================================================================
122 mDNSlocal
void DebugMsg( DebugLevel inLevel
, const char *inFormat
, ... );
124 #define dmsg( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
126 #define dmsg( LEVEL, ARGS... )
129 #if( DEBUG && MDNS_DEBUG_PACKETS )
130 #define dpkt( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
132 #define dpkt( LEVEL, ARGS... )
135 #define ForgetSem( X ) do { if( *( X ) ) { semDelete( ( *X ) ); *( X ) = 0; } } while( 0 )
136 #define ForgetSocket( X ) do { if( IsValidSocket( *( X ) ) ) { close_compat( *( X ) ); *( X ) = kInvalidSocketRef; } } while( 0 )
140 mDNSlocal mStatus
UpdateInterfaceList( mDNS
*const inMDNS
, mDNSs32 inUTC
);
141 mDNSlocal NetworkInterfaceInfoVxWorks
* AddInterfaceToList( mDNS
*const inMDNS
, struct ifaddrs
*inIFA
, mDNSs32 inUTC
);
142 mDNSlocal
int SetupActiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
);
143 mDNSlocal
void MarkAllInterfacesInactive( mDNS
*const inMDNS
, mDNSs32 inUTC
);
144 mDNSlocal
int ClearInactiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
, mDNSBool inClosing
);
145 mDNSlocal NetworkInterfaceInfoVxWorks
* FindRoutableIPv4( mDNS
*const inMDNS
, mDNSu32 inScopeID
);
146 mDNSlocal NetworkInterfaceInfoVxWorks
* FindInterfaceByIndex( mDNS
*const inMDNS
, int inFamily
, mDNSu32 inIndex
);
147 mDNSlocal mStatus
SetupSocket( mDNS
*const inMDNS
, const mDNSAddr
*inAddr
, mDNSBool inMcast
, int inFamily
, SocketSet
*inSS
);
148 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
);
152 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
);
153 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
);
154 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
);
155 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
);
159 mDNSlocal
void Task( mDNS
*inMDNS
);
160 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
);
161 mDNSlocal
void TaskTerm( mDNS
*inMDNS
);
162 mDNSlocal
void TaskSetupSelect( mDNS
*inMDNS
, fd_set
*outSet
, int *outMaxFd
, mDNSs32 inNextEvent
, struct timeval
*outTimeout
);
163 mDNSlocal
void TaskProcessPackets( mDNS
*inMDNS
, SocketSet
*inSS
, SocketRef inSock
);
171 size_t * outFromSize
,
172 mDNSAddr
* outDstAddr
,
173 uint32_t * outIndex
);
175 // DNSServices compatibility. When all clients move to DNS-SD, this section can be removed.
181 typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo
;
182 struct mDNSPlatformInterfaceInfo
188 mDNSexport mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
);
189 mDNSexport mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
);
196 #pragma mark == Globals ==
199 //===========================================================================================================================
201 //===========================================================================================================================
203 debug_log_new_default_category( mdns
);
205 mDNSexport mDNSs32 mDNSPlatformOneSecond
;
206 mDNSlocal mDNSs32 gMDNSTicksToMicro
= 0;
207 mDNSlocal mDNS
* gMDNSPtr
= NULL
;
208 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport
;
209 mDNSlocal mDNSBool gMDNSDeferIPv4
= mDNSfalse
;
211 DebugLevel gMDNSDebugOverrideLevel
= kDebugLevelMax
;
218 //===========================================================================================================================
220 //===========================================================================================================================
222 void mDNSReconfigure( void )
224 if( gMDNSPtr
) SendCommand( gMDNSPtr
, kMDNSPipeCommandCodeReconfigure
);
227 //===========================================================================================================================
229 //===========================================================================================================================
231 void mDNSDeferIPv4( mDNSBool inDefer
)
233 gMDNSDeferIPv4
= inDefer
;
240 //===========================================================================================================================
242 //===========================================================================================================================
244 mStatus
mDNSPlatformInit( mDNS
* const inMDNS
)
249 mDNSPlatformOneSecond
= sysClkRateGet();
250 gMDNSTicksToMicro
= ( 1000000L / mDNSPlatformOneSecond
);
252 // Do minimal initialization to get the task started and so we can cleanup safely if an error occurs.
254 memset( &gMDNSPlatformSupport
, 0, sizeof( gMDNSPlatformSupport
) );
255 if( !inMDNS
->p
) inMDNS
->p
= &gMDNSPlatformSupport
;
256 inMDNS
->p
->unicastSS
.info
= NULL
;
257 inMDNS
->p
->unicastSS
.sockV4
= kInvalidSocketRef
;
258 inMDNS
->p
->unicastSS
.sockV6
= kInvalidSocketRef
;
259 inMDNS
->p
->initErr
= mStatus_NotInitializedErr
;
260 inMDNS
->p
->commandPipe
= ERROR
;
261 inMDNS
->p
->taskID
= ERROR
;
263 inMDNS
->p
->lock
= semMCreate( SEM_Q_FIFO
);
264 require_action( inMDNS
->p
->lock
, exit
, err
= mStatus_NoMemoryErr
);
266 inMDNS
->p
->initEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
267 require_action( inMDNS
->p
->initEvent
, exit
, err
= mStatus_NoMemoryErr
);
269 inMDNS
->p
->quitEvent
= semBCreate( SEM_Q_FIFO
, SEM_EMPTY
);
270 require_action( inMDNS
->p
->quitEvent
, exit
, err
= mStatus_NoMemoryErr
);
272 // Start the task and wait for it to initialize. The task does the full initialization from its own context
273 // to avoid potential issues with stack space and APIs that key off the current task (e.g. watchdog timers).
274 // We wait here until the init is complete because it needs to be ready to use as soon as this function returns.
276 id
= taskSpawn( "tMDNS", 102, 0, 16384, (FUNCPTR
) Task
, (int) inMDNS
, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
277 err
= translate_errno( id
!= ERROR
, errno_compat(), mStatus_NoMemoryErr
);
278 require_noerr( err
, exit
);
280 err
= semTake( inMDNS
->p
->initEvent
, WAIT_FOREVER
);
281 if( err
== OK
) err
= inMDNS
->p
->initErr
;
282 require_noerr( err
, exit
);
285 mDNSCoreInitComplete( inMDNS
, err
);
288 if( err
) mDNSPlatformClose( inMDNS
);
292 //===========================================================================================================================
294 //===========================================================================================================================
296 void mDNSPlatformClose( mDNS
* const inMDNS
)
304 // Signal the task to quit and wait for it to signal back that it exited. Timeout in 10 seconds to handle a hung thread.
306 if( inMDNS
->p
->taskID
!= ERROR
)
308 SendCommand( inMDNS
, kMDNSPipeCommandCodeQuit
);
309 if( inMDNS
->p
->quitEvent
)
311 err
= semTake( inMDNS
->p
->quitEvent
, sysClkRateGet() * 10 );
314 inMDNS
->p
->taskID
= ERROR
;
317 // Clean up resources set up in mDNSPlatformInit. All other resources should have been cleaned up already by TaskTerm.
319 ForgetSem( &inMDNS
->p
->quitEvent
);
320 ForgetSem( &inMDNS
->p
->initEvent
);
321 ForgetSem( &inMDNS
->p
->lock
);
323 dmsg( kDebugLevelNotice
, DEBUG_NAME
"CLOSED\n" );
326 //===========================================================================================================================
327 // mDNSPlatformSendUDP
328 //===========================================================================================================================
332 const mDNS
* const inMDNS
,
333 const void * const inMsg
,
334 const mDNSu8
* const inEnd
,
335 mDNSInterfaceID inInterfaceID
,
336 const mDNSAddr
* inDstIP
,
337 mDNSIPPort inDstPort
)
340 NetworkInterfaceInfoVxWorks
* info
;
342 struct sockaddr_storage to
;
345 // Set up the sockaddr to sent to and the socket to send on.
347 info
= (NetworkInterfaceInfoVxWorks
*) inInterfaceID
;
348 if( inDstIP
->type
== mDNSAddrType_IPv4
)
350 struct sockaddr_in
* sa4
;
352 sa4
= (struct sockaddr_in
*) &to
;
353 sa4
->sin_len
= sizeof( *sa4
);
354 sa4
->sin_family
= AF_INET
;
355 sa4
->sin_port
= inDstPort
.NotAnInteger
;
356 sa4
->sin_addr
.s_addr
= inDstIP
->ip
.v4
.NotAnInteger
;
357 sock
= info
? info
->ss
.sockV4
: inMDNS
->p
->unicastSS
.sockV4
;
359 else if( inDstIP
->type
== mDNSAddrType_IPv6
)
361 struct sockaddr_in6
* sa6
;
363 sa6
= (struct sockaddr_in6
*) &to
;
364 sa6
->sin6_len
= sizeof( *sa6
);
365 sa6
->sin6_family
= AF_INET6
;
366 sa6
->sin6_port
= inDstPort
.NotAnInteger
;
367 sa6
->sin6_flowinfo
= 0;
368 sa6
->sin6_addr
= *( (struct in6_addr
*) &inDstIP
->ip
.v6
);
369 sa6
->sin6_scope_id
= info
? info
->scopeID
: 0;
370 sock
= info
? info
->ss
.sockV6
: inMDNS
->p
->unicastSS
.sockV6
;
374 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! destination is not an IPv4 or IPv6 address\n", __ROUTINE__
);
375 err
= mStatus_BadParamErr
;
379 // 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
380 // an IPv6 multicast packet. If we don't have the corresponding type of socket available, quietly return an error.
382 n
= (int)( (mDNSu8
*) inEnd
- (mDNSu8
*) inMsg
);
383 if( !IsValidSocket( sock
) )
385 dpkt( kDebugLevelChatty
- 1,
386 DEBUG_NAME
"DROP: %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
387 n
, inDstIP
, mDNSVal16( inDstPort
), info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, info
);
388 err
= mStatus_Invalid
;
392 dpkt( kDebugLevelChatty
,
393 DEBUG_NAME
"SEND %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
394 n
, inDstIP
, mDNSVal16( inDstPort
), info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, info
);
396 n
= sendto( sock
, (mDNSu8
*) inMsg
, n
, 0, (struct sockaddr
*) &to
, to
.ss_len
);
399 // Don't warn about ARP failures or no route to host for unicast destinations.
401 err
= errno_compat();
402 if( ( ( err
== EHOSTDOWN
) || ( err
== ENETDOWN
) || ( err
== EHOSTUNREACH
) ) && !mDNSAddressIsAllDNSLinkGroup( inDstIP
) )
407 dmsg( kDebugLevelError
, "%s: ERROR! sendto failed on %8s(%u) to %#a:%d, sock %d, err %d, time %u\n",
408 __ROUTINE__
, info
? info
->ifinfo
.ifname
: "unicast", info
? info
->scopeID
: 0, inDstIP
, mDNSVal16( inDstPort
),
409 sock
, err
, (unsigned int) inMDNS
->timenow
);
410 if( err
== 0 ) err
= mStatus_UnknownErr
;
413 err
= mStatus_NoError
;
419 //===========================================================================================================================
420 // Connection-oriented (TCP) functions
421 //===========================================================================================================================
423 mDNSexport mStatus
mDNSPlatformTCPConnect(const mDNSAddr
*dst
, mDNSOpaque16 dstport
, mDNSInterfaceID InterfaceID
,
424 TCPConnectionCallback callback
, void *context
, int *descriptor
)
427 (void)dstport
; // Unused
428 (void)InterfaceID
; // Unused
429 (void)callback
; // Unused
430 (void)context
; // Unused
431 (void)descriptor
; // Unused
432 return(mStatus_UnsupportedErr
);
435 mDNSexport
void mDNSPlatformTCPCloseConnection(int sd
)
440 mDNSexport
long mDNSPlatformReadTCP(int sd
, void *buf
, unsigned long buflen
)
444 (void)buflen
; // Unused
448 mDNSexport
long mDNSPlatformWriteTCP(int sd
, const char *msg
, unsigned long len
)
456 //===========================================================================================================================
458 //===========================================================================================================================
460 void mDNSPlatformLock( const mDNS
* const inMDNS
)
462 check_string( inMDNS
->p
&& ( inMDNS
->p
->taskID
!= ERROR
), "mDNS task not started" );
465 if( semTake( inMDNS
->p
->lock
, 60 * sysClkRateGet() ) != OK
)
467 dmsg( kDebugLevelTragic
, "\n### DEADLOCK DETECTED ### (sem=%#p, task=%#p)\n\n", inMDNS
->p
->lock
, taskIdSelf() );
468 debug_stack_trace(); // 1) Print Stack Trace.
469 semShow( inMDNS
->p
->lock
, 1 ); // 2) Print semaphore info, including which tasks are pending on it.
470 taskSuspend( 0 ); // 3) Suspend task. Can be resumed from the console for debugging.
473 semTake( inMDNS
->p
->lock
, WAIT_FOREVER
);
477 //===========================================================================================================================
478 // mDNSPlatformUnlock
479 //===========================================================================================================================
481 void mDNSPlatformUnlock( const mDNS
* const inMDNS
)
483 check_string( inMDNS
->p
&& ( inMDNS
->p
->taskID
!= ERROR
), "mDNS task not started" );
485 // Wake up the mDNS task to handle any work initiated by an API call and to calculate the next event time.
486 // We only need to wake up if we're not already inside the task. This avoids filling up the command queue.
488 if( taskIdSelf() != inMDNS
->p
->taskID
)
490 SendCommand( inMDNS
, kMDNSPipeCommandCodeReschedule
);
492 semGive( inMDNS
->p
->lock
);
495 //===========================================================================================================================
496 // mDNSPlatformStrLen
497 //===========================================================================================================================
499 mDNSu32
mDNSPlatformStrLen( const void *inSrc
)
503 return( (mDNSu32
) strlen( (const char *) inSrc
) );
506 //===========================================================================================================================
507 // mDNSPlatformStrCopy
508 //===========================================================================================================================
510 void mDNSPlatformStrCopy( void *inDst
, const void *inSrc
)
515 strcpy( (char *) inDst
, (const char*) inSrc
);
518 //===========================================================================================================================
519 // mDNSPlatformMemCopy
520 //===========================================================================================================================
522 void mDNSPlatformMemCopy( void *inDst
, const void *inSrc
, mDNSu32 inSize
)
527 memcpy( inDst
, inSrc
, inSize
);
530 //===========================================================================================================================
531 // mDNSPlatformMemSame
532 //===========================================================================================================================
534 mDNSBool
mDNSPlatformMemSame( const void *inDst
, const void *inSrc
, mDNSu32 inSize
)
539 return( memcmp( inSrc
, inDst
, inSize
) == 0 );
542 //===========================================================================================================================
543 // mDNSPlatformMemZero
544 //===========================================================================================================================
546 void mDNSPlatformMemZero( void *inDst
, mDNSu32 inSize
)
550 memset( inDst
, 0, inSize
);
553 //===========================================================================================================================
554 // mDNSPlatformMemAllocate
555 //===========================================================================================================================
557 mDNSexport
void * mDNSPlatformMemAllocate( mDNSu32 inSize
)
563 mem
= malloc( inSize
);
569 //===========================================================================================================================
570 // mDNSPlatformMemFree
571 //===========================================================================================================================
573 mDNSexport
void mDNSPlatformMemFree( void *inMem
)
576 if( inMem
) free( inMem
);
579 //===========================================================================================================================
580 // mDNSPlatformRandomSeed
581 //===========================================================================================================================
583 mDNSexport mDNSu32
mDNSPlatformRandomSeed( void )
588 //===========================================================================================================================
589 // mDNSPlatformTimeInit
590 //===========================================================================================================================
592 mDNSexport mStatus
mDNSPlatformTimeInit( void )
594 // No special setup is required on VxWorks -- we just use tickGet().
596 return( mStatus_NoError
);
599 //===========================================================================================================================
600 // mDNSPlatformRawTime
601 //===========================================================================================================================
603 mDNSs32
mDNSPlatformRawTime( void )
605 return( (mDNSs32
) tickGet() );
608 //===========================================================================================================================
610 //===========================================================================================================================
612 mDNSexport mDNSs32
mDNSPlatformUTC( void )
614 return( (mDNSs32
) time( NULL
) );
617 //===========================================================================================================================
618 // mDNSPlatformInterfaceIDfromInterfaceIndex
619 //===========================================================================================================================
621 mDNSexport mDNSInterfaceID
mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS
*const inMDNS
, mDNSu32 inIndex
)
623 NetworkInterfaceInfoVxWorks
* i
;
625 if( inIndex
== (mDNSu32
) -1 ) return( mDNSInterface_LocalOnly
);
628 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
630 // Don't get tricked by inactive interfaces with no InterfaceID set.
632 if( i
->ifinfo
.InterfaceID
&& ( i
->scopeID
== inIndex
) ) return( i
->ifinfo
.InterfaceID
);
638 //===========================================================================================================================
639 // mDNSPlatformInterfaceIndexfromInterfaceID
640 //===========================================================================================================================
642 mDNSexport mDNSu32
mDNSPlatformInterfaceIndexfromInterfaceID( mDNS
*const inMDNS
, mDNSInterfaceID inID
)
644 NetworkInterfaceInfoVxWorks
* i
;
646 if( inID
== mDNSInterface_LocalOnly
) return( (mDNSu32
) -1 );
649 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
651 for( i
= inMDNS
->p
->interfaceList
; i
&& ( (mDNSInterfaceID
) i
!= inID
); i
= i
->next
) {}
652 if( i
) return( i
->scopeID
);
657 //===========================================================================================================================
658 // mDNSPlatformInterfaceNameToID
659 //===========================================================================================================================
661 mStatus
mDNSPlatformInterfaceNameToID( mDNS
* const inMDNS
, const char *inName
, mDNSInterfaceID
*outID
)
663 NetworkInterfaceInfoVxWorks
* i
;
665 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
667 // Don't get tricked by inactive interfaces with no InterfaceID set.
669 if( i
->ifinfo
.InterfaceID
&& ( strcmp( i
->ifinfo
.ifname
, inName
) == 0 ) )
671 *outID
= (mDNSInterfaceID
) i
;
672 return( mStatus_NoError
);
675 return( mStatus_NoSuchNameErr
);
678 //===========================================================================================================================
679 // mDNSPlatformInterfaceIDToInfo
680 //===========================================================================================================================
682 mStatus
mDNSPlatformInterfaceIDToInfo( mDNS
* const inMDNS
, mDNSInterfaceID inID
, mDNSPlatformInterfaceInfo
*outInfo
)
684 NetworkInterfaceInfoVxWorks
* i
;
686 // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
688 for( i
= inMDNS
->p
->interfaceList
; i
&& ( (mDNSInterfaceID
) i
!= inID
); i
= i
->next
) {}
689 if( !i
) return( mStatus_NoSuchNameErr
);
691 outInfo
->name
= i
->ifinfo
.ifname
;
692 outInfo
->ip
= i
->ifinfo
.ip
;
693 return( mStatus_NoError
);
696 //===========================================================================================================================
698 //===========================================================================================================================
700 #if( MDNS_DEBUGMSGS > 0 )
701 mDNSexport
void debugf_( const char *inFormat
, ... )
706 va_start( args
, inFormat
);
707 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
710 dlog( kDebugLevelInfo
, "%s\n", buffer
);
714 //===========================================================================================================================
716 //===========================================================================================================================
718 #if( MDNS_DEBUGMSGS > 1 )
719 mDNSexport
void verbosedebugf_( const char *inFormat
, ... )
724 va_start( args
, inFormat
);
725 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
728 dlog( kDebugLevelVerbose
, "%s\n", buffer
);
732 //===========================================================================================================================
734 //===========================================================================================================================
736 mDNSexport
void LogMsg( const char *inFormat
, ... )
742 va_start( args
, inFormat
);
743 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
746 dlog( kDebugLevelWarning
, "%s\n", buffer
);
748 DEBUG_UNUSED( inFormat
);
753 //===========================================================================================================================
755 //===========================================================================================================================
757 mDNSlocal
void DebugMsg( DebugLevel inLevel
, const char *inFormat
, ... )
762 va_start( args
, inFormat
);
763 mDNS_vsnprintf( buffer
, sizeof( buffer
), inFormat
, args
);
766 if( inLevel
>= gMDNSDebugOverrideLevel
) inLevel
= kDebugLevelMax
;
767 dlog( inLevel
, "%s", buffer
);
773 #pragma mark == Interfaces ==
776 //===========================================================================================================================
777 // UpdateInterfaceList
778 //===========================================================================================================================
780 #if( MDNS_ENABLE_PPP )
782 // Note: This includes PPP dial-in interfaces (pppXYZ), but not PPP dial-out interface (pppdXYZ).
784 #define IsCompatibleInterface( IFA ) \
785 ( ( ( IFA )->ifa_flags & IFF_UP ) && \
786 ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
787 ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) && \
788 ( !( ( IFA )->ifa_flags & IFF_POINTOPOINT ) || ( strncmp( ( IFA )->ifa_name, "pppd", 4 ) != 0 ) ) )
790 #define IsCompatibleInterface( IFA ) \
791 ( ( ( ( IFA )->ifa_flags & ( IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT ) ) == ( IFF_UP | IFF_MULTICAST ) ) && \
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 ) ) )
796 #define IsLinkLocalSockAddr( SA ) \
797 ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
798 ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
799 ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
800 : IN6_IS_ADDR_LINKLOCAL( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
802 #define FamilyToString( X ) \
803 ( ( ( X ) == AF_INET ) ? "AF_INET" : \
804 ( ( ( X ) == AF_INET6 ) ? "AF_INET6" : \
805 ( ( ( X ) == AF_LINK ) ? "AF_LINK" : \
808 mDNSlocal mStatus
UpdateInterfaceList( mDNS
*const inMDNS
, mDNSs32 inUTC
)
811 struct ifaddrs
* ifaList
;
812 struct ifaddrs
* ifa
;
816 struct ifaddrs
* loopbackV4
;
817 struct ifaddrs
* loopbackV6
;
818 mDNSEthAddr primaryMAC
;
820 char defaultName
[ 64 ];
821 NetworkInterfaceInfoVxWorks
* i
;
822 domainlabel nicelabel
;
823 domainlabel hostlabel
;
831 primaryMAC
= zeroEthAddr
;
833 // Set up an IPv6 socket so we can check the state of interfaces using SIOCGIFAFLAG_IN6.
835 infoSock
= socket( AF_INET6
, SOCK_DGRAM
, 0 );
836 check_translated_errno( IsValidSocket( infoSock
), errno_compat(), kUnknownErr
);
838 // Run through the entire list of interfaces.
840 err
= getifaddrs( &ifaList
);
841 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
843 for( ifa
= ifaList
; ifa
; ifa
= ifa
->ifa_next
)
847 family
= ifa
->ifa_addr
->sa_family
;
848 dmsg( kDebugLevelVerbose
, DEBUG_NAME
"%s: %8s(%d), Flags 0x%08X, Family %8s(%2d)\n", __ROUTINE__
,
849 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
), ifa
->ifa_flags
, FamilyToString( family
), family
);
851 // Save off the MAC address of the first Ethernet-ish interface.
853 if( family
== AF_LINK
)
855 struct sockaddr_dl
* sdl
;
857 sdl
= (struct sockaddr_dl
*) ifa
->ifa_addr
;
858 if( ( sdl
->sdl_type
== IFT_ETHER
) && ( sdl
->sdl_alen
== sizeof( primaryMAC
) &&
859 mDNSSameEthAddress( &primaryMAC
, &zeroEthAddr
) ) )
861 memcpy( primaryMAC
.b
, sdl
->sdl_data
+ sdl
->sdl_nlen
, 6 );
865 if( !IsCompatibleInterface( ifa
) ) continue;
867 // If this is a link-local address and there's a non-link-local address on this interface, skip this alias.
869 if( IsLinkLocalSockAddr( ifa
->ifa_addr
) )
871 struct ifaddrs
* ifaLL
;
873 for( ifaLL
= ifaList
; ifaLL
; ifaLL
= ifaLL
->ifa_next
)
875 if( ifaLL
->ifa_addr
->sa_family
!= family
) continue;
876 if( !IsCompatibleInterface( ifaLL
) ) continue;
877 if( strcmp( ifaLL
->ifa_name
, ifa
->ifa_name
) != 0 ) continue;
878 if( !IsLinkLocalSockAddr( ifaLL
->ifa_addr
) ) break;
882 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: %8s(%d) skipping link-local alias\n", __ROUTINE__
,
883 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
) );
888 // If this is an IPv6 interface, perform additional checks to make sure it is really ready for use.
889 // If this is a loopback interface, save it off since we may add it later if there are no other interfaces.
890 // Otherwise, add the interface to the list.
893 if( ( family
== AF_INET6
) && IsValidSocket( infoSock
) )
895 struct sockaddr_in6
* sa6
;
896 struct in6_ifreq ifr6
;
898 sa6
= (struct sockaddr_in6
*) ifa
->ifa_addr
;
899 memset( &ifr6
, 0, sizeof( ifr6
) );
900 strcpy( ifr6
.ifr_name
, ifa
->ifa_name
);
901 ifr6
.ifr_addr
= *sa6
;
902 if( ioctl( infoSock
, SIOCGIFAFLAG_IN6
, (int) &ifr6
) != -1 )
904 flags
= ifr6
.ifr_ifru
.ifru_flags6
;
908 // HACK: This excludes interfaces with IN6_IFF_DUPLICATED set instead of using IN6_IFF_NOTREADY (which is
909 // HACK: IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED) because we currently do not get a notification when an
910 // HACK: interface goes from the tentative state to the fully ready state. So as a short-term workaround,
911 // HACK: this allows tentative interfaces to be registered. We should revisit if we get notification hooks.
913 if( flags
& ( IN6_IFF_DUPLICATED
| IN6_IFF_DETACHED
| IN6_IFF_DEPRECATED
| IN6_IFF_TEMPORARY
) )
915 dmsg( kDebugLevelNotice
, DEBUG_NAME
"%s: %8s(%d), SIOCGIFAFLAG_IN6 not ready yet (0x%X)\n", __ROUTINE__
,
916 ifa
->ifa_name
, if_nametoindex( ifa
->ifa_name
), flags
);
919 if( ifa
->ifa_flags
& IFF_LOOPBACK
)
921 if( family
== AF_INET
) loopbackV4
= ifa
;
922 else loopbackV6
= ifa
;
926 if( ( family
== AF_INET
) && gMDNSDeferIPv4
&& IsLinkLocalSockAddr( ifa
->ifa_addr
) ) continue;
927 i
= AddInterfaceToList( inMDNS
, ifa
, inUTC
);
928 if( i
&& i
->multicast
)
930 if( family
== AF_INET
) foundV4
= mDNStrue
;
931 else foundV6
= mDNStrue
;
936 // For efficiency, we don't register a loopback interface when other interfaces of that family are available.
938 if( !foundV4
&& loopbackV4
) AddInterfaceToList( inMDNS
, loopbackV4
, inUTC
);
939 if( !foundV6
&& loopbackV6
) AddInterfaceToList( inMDNS
, loopbackV6
, inUTC
);
940 freeifaddrs( ifaList
);
941 if( IsValidSocket( infoSock
) ) close_compat( infoSock
);
943 // The list is complete. Set the McastTxRx setting for each interface. We always send and receive using IPv4.
944 // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
945 // Having a routable IPv4 address assigned is a reasonable indicator of being on a large, configured network,
946 // which means there's a good chance that most or all the other devices on that network should also have v4.
947 // 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.
948 // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
949 // so we are willing to make that sacrifice.
951 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
957 txrx
= i
->multicast
&& ( ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) || !FindRoutableIPv4( inMDNS
, i
->scopeID
) );
958 if( i
->ifinfo
.McastTxRx
!= txrx
)
960 i
->ifinfo
.McastTxRx
= txrx
;
961 i
->exists
= 2; // 2=state change; need to de-register and re-register this interface.
966 // Set up the user-specified, friendly name, which is allowed to be full UTF-8.
968 mDNS_snprintf( defaultName
, sizeof( defaultName
), "Device-%02X:%02X:%02X:%02X:%02X:%02X",
969 primaryMAC
.b
[ 0 ], primaryMAC
.b
[ 1 ], primaryMAC
.b
[ 2 ], primaryMAC
.b
[ 3 ], primaryMAC
.b
[ 4 ], primaryMAC
.b
[ 5 ] );
971 MakeDomainLabelFromLiteralString( &nicelabel
, "Put Nice Name Here" ); // $$$ Implementers: Fill in nice name of device.
972 if( nicelabel
.c
[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &nicelabel
, defaultName
);
974 // Set up the RFC 1034-compliant label. If not set or it is not RFC 1034 compliant, try the user-specified nice name.
976 MakeDomainLabelFromLiteralString( &tmp
, "Put-DNS-Name-Here" ); // $$$ Implementers: Fill in DNS name of device.
977 ConvertUTF8PstringToRFC1034HostLabel( tmp
.c
, &hostlabel
);
978 if( hostlabel
.c
[ 0 ] == 0 ) ConvertUTF8PstringToRFC1034HostLabel( nicelabel
.c
, &hostlabel
);
979 if( hostlabel
.c
[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &hostlabel
, defaultName
);
981 // Update our globals and mDNS with the new labels.
983 if( !SameDomainLabelCS( inMDNS
->p
->userNiceLabel
.c
, nicelabel
.c
) )
985 dmsg( kDebugLevelInfo
, DEBUG_NAME
"Updating nicelabel to \"%#s\"\n", nicelabel
.c
);
986 inMDNS
->p
->userNiceLabel
= nicelabel
;
987 inMDNS
->nicelabel
= nicelabel
;
989 if( !SameDomainLabelCS( inMDNS
->p
->userHostLabel
.c
, hostlabel
.c
) )
991 dmsg( kDebugLevelInfo
, DEBUG_NAME
"Updating hostlabel to \"%#s\"\n", hostlabel
.c
);
992 inMDNS
->p
->userHostLabel
= hostlabel
;
993 inMDNS
->hostlabel
= hostlabel
;
994 mDNS_SetFQDN( inMDNS
);
996 return( mStatus_NoError
);
999 //===========================================================================================================================
1000 // AddInterfaceToList
1001 //===========================================================================================================================
1003 mDNSlocal NetworkInterfaceInfoVxWorks
* AddInterfaceToList( mDNS
*const inMDNS
, struct ifaddrs
*inIFA
, mDNSs32 inUTC
)
1009 NetworkInterfaceInfoVxWorks
** p
;
1010 NetworkInterfaceInfoVxWorks
* i
;
1014 err
= SockAddrToMDNSAddr( inIFA
->ifa_addr
, &ip
);
1015 require_noerr( err
, exit
);
1017 err
= SockAddrToMDNSAddr( inIFA
->ifa_netmask
, &mask
);
1018 require_noerr( err
, exit
);
1020 // Search for an existing interface with the same info. If found, just return that one.
1022 scopeID
= if_nametoindex( inIFA
->ifa_name
);
1024 for( p
= &inMDNS
->p
->interfaceList
; *p
; p
= &( *p
)->next
)
1026 if( ( scopeID
== ( *p
)->scopeID
) && mDNSSameAddress( &ip
, &( *p
)->ifinfo
.ip
) )
1028 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Found existing interface %u with address %#a at %#p\n", __ROUTINE__
,
1030 ( *p
)->exists
= mDNStrue
;
1036 // Allocate the new interface info and fill it out.
1038 i
= (NetworkInterfaceInfoVxWorks
*) calloc( 1, sizeof( *i
) );
1041 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Making new interface %u with address %#a at %#p\n", __ROUTINE__
, scopeID
, &ip
, i
);
1042 strncpy( i
->ifinfo
.ifname
, inIFA
->ifa_name
, sizeof( i
->ifinfo
.ifname
) );
1043 i
->ifinfo
.ifname
[ sizeof( i
->ifinfo
.ifname
) - 1 ] = '\0';
1044 i
->ifinfo
.InterfaceID
= NULL
;
1046 i
->ifinfo
.mask
= mask
;
1047 i
->ifinfo
.Advertise
= inMDNS
->AdvertiseLocalAddresses
;
1048 i
->ifinfo
.McastTxRx
= mDNSfalse
; // For now; will be set up later at the end of UpdateInterfaceList.
1051 i
->exists
= mDNStrue
;
1052 i
->lastSeen
= inUTC
;
1053 i
->scopeID
= scopeID
;
1054 i
->family
= inIFA
->ifa_addr
->sa_family
;
1055 i
->multicast
= ( inIFA
->ifa_flags
& IFF_MULTICAST
) && !( inIFA
->ifa_flags
& IFF_POINTOPOINT
);
1058 i
->ss
.sockV4
= kInvalidSocketRef
;
1059 i
->ss
.sockV6
= kInvalidSocketRef
;
1066 //===========================================================================================================================
1067 // SetupActiveInterfaces
1069 // Returns a count of non-link local IPv4 addresses registered.
1070 //===========================================================================================================================
1072 #define mDNSAddressIsNonLinkLocalIPv4( X ) \
1073 ( ( ( X )->type == mDNSAddrType_IPv4 ) && ( ( ( X )->ip.v4.b[ 0 ] != 169 ) || ( ( X )->ip.v4.b[ 1 ] != 254 ) ) )
1075 mDNSlocal
int SetupActiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
)
1078 NetworkInterfaceInfoVxWorks
* i
;
1081 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1083 NetworkInterfaceInfo
* n
;
1084 NetworkInterfaceInfoVxWorks
* primary
;
1086 if( !i
->exists
) continue;
1088 // Search for the primary interface and sanity check it.
1091 primary
= FindInterfaceByIndex( inMDNS
, i
->family
, i
->scopeID
);
1094 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! didn't find %s(%u)\n", __ROUTINE__
, i
->ifinfo
.ifname
, i
->scopeID
);
1097 if( n
->InterfaceID
&& ( n
->InterfaceID
!= (mDNSInterfaceID
) primary
) )
1099 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: ERROR! n->InterfaceID %#p != primary %#p\n", __ROUTINE__
,
1100 n
->InterfaceID
, primary
);
1101 n
->InterfaceID
= NULL
;
1104 // If n->InterfaceID is set, it means we've already called mDNS_RegisterInterface() for this interface.
1105 // so we don't need to call it again. Otherwise, register the interface with mDNS.
1107 if( !n
->InterfaceID
)
1111 n
->InterfaceID
= (mDNSInterfaceID
) primary
;
1113 // If lastSeen == inUTC, then this is a brand-new interface, or an interface that never went away.
1114 // If lastSeen != inUTC, then this is an old interface, that went away for (inUTC - lastSeen) seconds.
1115 // If it's is an old one that went away and came back in less than a minute, we're in a flapping scenario.
1117 flapping
= ( ( inUTC
- i
->lastSeen
) > 0 ) && ( ( inUTC
- i
->lastSeen
) < 60 );
1118 mDNS_RegisterInterface( inMDNS
, n
, flapping
);
1119 if( mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) ) ++count
;
1121 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Registered %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__
,
1122 i
->ifinfo
.ifname
, i
->scopeID
, primary
, &n
->ip
,
1123 flapping
? " (Flapping)" : "",
1124 n
->InterfaceActive
? " (Primary)" : "" );
1127 // Set up a socket if it's not already set up. If multicast is not enabled on this interface then we
1128 // don't need a socket since unicast traffic will be handled on the unicast socket.
1134 if( ( ( i
->family
== AF_INET
) && !IsValidSocket( primary
->ss
.sockV4
) ) ||
1135 ( ( i
->family
== AF_INET6
) && !IsValidSocket( primary
->ss
.sockV6
) ) )
1137 err
= SetupSocket( inMDNS
, &i
->ifinfo
.ip
, mDNStrue
, i
->family
, &primary
->ss
);
1143 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: No Tx/Rx on %8s(%u) InterfaceID %#p %#a\n", __ROUTINE__
,
1144 i
->ifinfo
.ifname
, i
->scopeID
, primary
, &n
->ip
);
1150 //===========================================================================================================================
1151 // MarkAllInterfacesInactive
1152 //===========================================================================================================================
1154 mDNSlocal
void MarkAllInterfacesInactive( mDNS
*const inMDNS
, mDNSs32 inUTC
)
1156 NetworkInterfaceInfoVxWorks
* i
;
1158 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1160 if( !i
->exists
) continue;
1161 i
->lastSeen
= inUTC
;
1162 i
->exists
= mDNSfalse
;
1166 //===========================================================================================================================
1167 // ClearInactiveInterfaces
1169 // Returns count of non-link local IPv4 addresses de-registered.
1170 //===========================================================================================================================
1172 mDNSlocal
int ClearInactiveInterfaces( mDNS
*const inMDNS
, mDNSs32 inUTC
, mDNSBool inClosing
)
1175 NetworkInterfaceInfoVxWorks
* i
;
1176 NetworkInterfaceInfoVxWorks
** p
;
1179 // If an interface is going away, then de-register it from mDNSCore.
1180 // We also have to de-register it if the primary interface that it's using for its InterfaceID is going away.
1181 // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
1182 // it refers to has gone away, we'll crash. Don't actually close the sockets or free the memory yet though:
1183 // When the last representative of an interface goes away mDNSCore may want to send goodbye packets on that
1184 // interface. (Not yet implemented, but a good idea anyway.).
1187 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1189 NetworkInterfaceInfoVxWorks
* primary
;
1191 // 1. If this interface is no longer active, or its InterfaceID is changing, de-register it.
1193 if( !i
->ifinfo
.InterfaceID
) continue;
1194 primary
= FindInterfaceByIndex( inMDNS
, i
->family
, i
->scopeID
);
1195 if( ( i
->exists
== 0 ) || ( i
->exists
== 2 ) || ( i
->ifinfo
.InterfaceID
!= (mDNSInterfaceID
) primary
) )
1197 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: Deregistering %8s(%u) InterfaceID %#p %#a%s\n", __ROUTINE__
,
1198 i
->ifinfo
.ifname
, i
->scopeID
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
,
1199 i
->ifinfo
.InterfaceActive
? " (Primary)" : "" );
1201 mDNS_DeregisterInterface( inMDNS
, &i
->ifinfo
, mDNSfalse
);
1202 i
->ifinfo
.InterfaceID
= NULL
;
1203 if( mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) ) ++count
;
1208 // Now that everything that's going to de-register has done so, we can close sockets and free the memory.
1210 p
= &inMDNS
->p
->interfaceList
;
1215 // 2. Close all our sockets. We'll recreate them later as needed.
1216 // (We may have previously had both v4 and v6, and we may not need both any more.).
1218 ForgetSocket( &i
->ss
.sockV4
);
1219 ForgetSocket( &i
->ss
.sockV6
);
1221 // 3. If no longer active, remove the interface from the list and free its memory.
1229 check_string( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) i
) == 0, "closing with in-use records!" );
1230 deleteIt
= mDNStrue
;
1234 if( i
->lastSeen
== inUTC
) i
->lastSeen
= inUTC
- 1;
1235 deleteIt
= ( NumCacheRecordsForInterfaceID( inMDNS
, (mDNSInterfaceID
) i
) == 0 ) && ( ( inUTC
- i
->lastSeen
) >= 60 );
1237 dmsg( kDebugLevelInfo
, DEBUG_NAME
"%s: %-13s %8s(%u) InterfaceID %#p %#a Age %d%s\n", __ROUTINE__
,
1238 deleteIt
? "Deleting" : "Holding", i
->ifinfo
.ifname
, i
->scopeID
, i
->ifinfo
.InterfaceID
, &i
->ifinfo
.ip
,
1239 inUTC
- i
->lastSeen
, i
->ifinfo
.InterfaceActive
? " (Primary)" : "" );
1252 //===========================================================================================================================
1254 //===========================================================================================================================
1256 mDNSlocal NetworkInterfaceInfoVxWorks
* FindRoutableIPv4( mDNS
*const inMDNS
, mDNSu32 inScopeID
)
1258 #if( MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
1259 NetworkInterfaceInfoVxWorks
* i
;
1261 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1263 if( i
->exists
&& ( i
->scopeID
== inScopeID
) && mDNSAddressIsNonLinkLocalIPv4( &i
->ifinfo
.ip
) )
1270 DEBUG_UNUSED( inMDNS
);
1271 DEBUG_UNUSED( inScopeID
);
1277 //===========================================================================================================================
1278 // FindInterfaceByIndex
1279 //===========================================================================================================================
1281 mDNSlocal NetworkInterfaceInfoVxWorks
* FindInterfaceByIndex( mDNS
*const inMDNS
, int inFamily
, mDNSu32 inIndex
)
1283 NetworkInterfaceInfoVxWorks
* i
;
1285 check( inIndex
!= 0 );
1287 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1289 if( i
->exists
&& ( i
->scopeID
== inIndex
) &&
1290 ( MDNS_AAAA_OVER_IPV4
||
1291 ( ( inFamily
== AF_INET
) && ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv4
) ) ||
1292 ( ( inFamily
== AF_INET6
) && ( i
->ifinfo
.ip
.type
== mDNSAddrType_IPv6
) ) ) )
1300 //===========================================================================================================================
1302 //===========================================================================================================================
1304 mDNSlocal mStatus
SetupSocket( mDNS
*const inMDNS
, const mDNSAddr
*inAddr
, mDNSBool inMcast
, int inFamily
, SocketSet
*inSS
)
1307 SocketRef
* sockPtr
;
1315 sockPtr
= ( inFamily
== AF_INET
) ? &inSS
->sockV4
: &inSS
->sockV6
;
1316 port
= ( inMcast
|| inMDNS
->CanReceiveUnicastOn5353
) ? MulticastDNSPort
: zeroIPPort
;
1318 sock
= socket( inFamily
, SOCK_DGRAM
, IPPROTO_UDP
);
1319 err
= translate_errno( IsValidSocket( sock
), errno_compat(), mStatus_UnknownErr
);
1320 require_noerr( err
, exit
);
1322 // Allow multiple listeners if this is a multicast port.
1324 if( port
.NotAnInteger
)
1326 err
= setsockopt( sock
, SOL_SOCKET
, SO_REUSEPORT
, (char *) &on
, sizeof( on
) );
1327 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1330 // Set up the socket based on the family (IPv4 or IPv6).
1332 if( inFamily
== AF_INET
)
1334 const int ttlV4
= 255;
1335 const u_char ttlV4Mcast
= 255;
1336 struct sockaddr_in sa4
;
1338 // Receive destination addresses so we know which address the packet was sent to.
1340 err
= setsockopt( sock
, IPPROTO_IP
, IP_RECVDSTADDR
, (char *) &on
, sizeof( on
) );
1341 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1343 // Receive interface indexes so we know which interface received the packet.
1345 err
= setsockopt( sock
, IPPROTO_IP
, IP_RECVIF
, (char *) &on
, sizeof( on
) );
1346 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1348 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1352 struct in_addr addrV4
;
1353 struct ip_mreq mreqV4
;
1355 addrV4
.s_addr
= inAddr
->ip
.v4
.NotAnInteger
;
1356 mreqV4
.imr_multiaddr
.s_addr
= AllDNSLinkGroup_v4
.ip
.v4
.NotAnInteger
;
1357 mreqV4
.imr_interface
= addrV4
;
1358 err
= setsockopt( sock
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (char *) &mreqV4
, sizeof( mreqV4
) );
1359 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1361 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_IF
, (char *) &addrV4
, sizeof( addrV4
) );
1362 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1365 // Send unicast packets with TTL 255 (helps against spoofing).
1367 err
= setsockopt( sock
, IPPROTO_IP
, IP_TTL
, (char *) &ttlV4
, sizeof( ttlV4
) );
1368 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1370 // Send multicast packets with TTL 255 (helps against spoofing).
1372 err
= setsockopt( sock
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *) &ttlV4Mcast
, sizeof( ttlV4Mcast
) );
1373 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1375 // Start listening for packets.
1377 memset( &sa4
, 0, sizeof( sa4
) );
1378 sa4
.sin_len
= sizeof( sa4
);
1379 sa4
.sin_family
= AF_INET
;
1380 sa4
.sin_port
= port
.NotAnInteger
;
1381 sa4
.sin_addr
.s_addr
= htonl( INADDR_ANY
); // We want to receive multicasts AND unicasts on this socket.
1382 err
= bind( sock
, (struct sockaddr
*) &sa4
, sizeof( sa4
) );
1383 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1385 else if( inFamily
== AF_INET6
)
1387 struct sockaddr_in6 sa6
;
1388 const int ttlV6
= 255;
1390 // Receive destination addresses and interface index so we know where the packet was received and intended.
1392 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_PKTINFO
, (char *) &on
, sizeof( on
) );
1393 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1395 // Receive only IPv6 packets because otherwise, we may get IPv4 addresses as IPv4-mapped IPv6 addresses.
1397 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *) &on
, sizeof( on
) );
1398 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1400 // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
1405 struct ipv6_mreq mreqV6
;
1407 ifindex
= inSS
->info
->scopeID
;
1408 mreqV6
.ipv6mr_interface
= ifindex
;
1409 mreqV6
.ipv6mr_multiaddr
= *( (struct in6_addr
* ) &AllDNSLinkGroup_v6
.ip
.v6
);
1410 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *) &mreqV6
, sizeof( mreqV6
) );
1411 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1413 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, (char *) &ifindex
, sizeof( ifindex
) );
1414 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1417 // Send unicast packets with TTL 255 (helps against spoofing).
1419 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, (char *) &ttlV6
, sizeof( ttlV6
) );
1420 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1422 // Send multicast packets with TTL 255 (helps against spoofing).
1424 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (char *) &ttlV6
, sizeof( ttlV6
) );
1425 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1427 // Receive our own packets for same-machine operation.
1429 err
= setsockopt( sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (char *) &on
, sizeof( on
) );
1430 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1432 // Start listening for packets.
1434 memset( &sa6
, 0, sizeof( sa6
) );
1435 sa6
.sin6_len
= sizeof( sa6
);
1436 sa6
.sin6_family
= AF_INET6
;
1437 sa6
.sin6_port
= port
.NotAnInteger
;
1438 sa6
.sin6_flowinfo
= 0;
1439 sa6
.sin6_addr
= in6addr_any
; // We want to receive multicasts AND unicasts on this socket.
1440 sa6
.sin6_scope_id
= 0;
1441 err
= bind( sock
, (struct sockaddr
*) &sa6
, sizeof( sa6
) );
1442 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1446 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: unsupport socket family (%d)\n", __ROUTINE__
, inFamily
);
1447 err
= kUnsupportedErr
;
1451 // Make the socket non-blocking so we can potentially get multiple packets per select call.
1453 err
= ioctl( sock
, FIONBIO
, (int) &on
);
1454 check_translated_errno( err
== 0, errno_compat(), kOptionErr
);
1457 sock
= kInvalidSocketRef
;
1458 err
= mStatus_NoError
;
1461 if( IsValidSocket( sock
) ) close_compat( sock
);
1465 //===========================================================================================================================
1466 // SockAddrToMDNSAddr
1467 //===========================================================================================================================
1469 mDNSlocal mStatus
SockAddrToMDNSAddr( const struct sockaddr
* const inSA
, mDNSAddr
*outIP
)
1476 if( inSA
->sa_family
== AF_INET
)
1478 struct sockaddr_in
* sa4
;
1480 sa4
= (struct sockaddr_in
*) inSA
;
1481 outIP
->type
= mDNSAddrType_IPv4
;
1482 outIP
->ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
1483 err
= mStatus_NoError
;
1485 else if( inSA
->sa_family
== AF_INET6
)
1487 struct sockaddr_in6
* sa6
;
1489 sa6
= (struct sockaddr_in6
*) inSA
;
1490 outIP
->type
= mDNSAddrType_IPv6
;
1491 outIP
->ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
1492 if( IN6_IS_ADDR_LINKLOCAL( &sa6
->sin6_addr
) ) outIP
->ip
.v6
.w
[ 1 ] = 0;
1493 err
= mStatus_NoError
;
1497 dmsg( kDebugLevelError
, DEBUG_NAME
"%s: invalid sa_family (%d)\n", __ROUTINE__
, inSA
->sa_family
);
1498 err
= mStatus_BadParamErr
;
1505 #pragma mark == Commands ==
1508 //===========================================================================================================================
1510 //===========================================================================================================================
1512 mDNSlocal mStatus
SetupCommandPipe( mDNS
* const inMDNS
)
1516 err
= pipeDevCreate( "/pipe/mDNS", 32, 1 );
1517 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1519 inMDNS
->p
->commandPipe
= open( "/pipe/mDNS", O_RDWR
, 0 );
1520 err
= translate_errno( inMDNS
->p
->commandPipe
!= ERROR
, errno_compat(), mStatus_UnsupportedErr
);
1521 require_noerr( err
, exit
);
1527 //===========================================================================================================================
1528 // TearDownCommandPipe
1529 //===========================================================================================================================
1531 mDNSlocal mStatus
TearDownCommandPipe( mDNS
* const inMDNS
)
1535 if( inMDNS
->p
->commandPipe
!= ERROR
)
1537 err
= close( inMDNS
->p
->commandPipe
);
1538 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1539 inMDNS
->p
->commandPipe
= ERROR
;
1541 err
= pipeDevDelete( "/pipe/mDNS", FALSE
);
1542 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1544 return( mStatus_NoError
);
1547 //===========================================================================================================================
1549 //===========================================================================================================================
1551 mDNSlocal mStatus
SendCommand( const mDNS
* const inMDNS
, MDNSPipeCommandCode inCommandCode
)
1555 require_action_quiet( inMDNS
->p
->commandPipe
!= ERROR
, exit
, err
= mStatus_NotInitializedErr
);
1557 err
= write( inMDNS
->p
->commandPipe
, &inCommandCode
, sizeof( inCommandCode
) );
1558 err
= translate_errno( err
>= 0, errno_compat(), kWriteErr
);
1559 require_noerr( err
, exit
);
1565 //===========================================================================================================================
1567 //===========================================================================================================================
1569 mDNSlocal mStatus
ProcessCommand( mDNS
* const inMDNS
)
1572 MDNSPipeCommandCode cmd
;
1575 err
= read( inMDNS
->p
->commandPipe
, &cmd
, sizeof( cmd
) );
1576 err
= translate_errno( err
>= 0, errno_compat(), kReadErr
);
1577 require_noerr( err
, exit
);
1581 case kMDNSPipeCommandCodeReschedule
: // Reschedule: just break out to re-run mDNS_Execute.
1584 case kMDNSPipeCommandCodeReconfigure
: // Reconfigure: rebuild the interface list after a config change.
1585 dmsg( kDebugLevelInfo
, DEBUG_NAME
"*** NETWORK CONFIGURATION CHANGE ***\n" );
1586 mDNSPlatformLock( inMDNS
);
1588 utc
= mDNSPlatformUTC();
1589 MarkAllInterfacesInactive( inMDNS
, utc
);
1590 UpdateInterfaceList( inMDNS
, utc
);
1591 ClearInactiveInterfaces( inMDNS
, utc
, mDNSfalse
);
1592 SetupActiveInterfaces( inMDNS
, utc
);
1594 mDNSPlatformUnlock( inMDNS
);
1595 if( inMDNS
->MainCallback
) inMDNS
->MainCallback( inMDNS
, mStatus_ConfigChanged
);
1598 case kMDNSPipeCommandCodeQuit
: // Quit: just set a flag so the task exits cleanly.
1599 inMDNS
->p
->quit
= mDNStrue
;
1603 dmsg( kDebugLevelError
, DEBUG_NAME
"unknown pipe command (%d)\n", cmd
);
1604 err
= mStatus_BadParamErr
;
1614 #pragma mark == Threads ==
1617 //===========================================================================================================================
1619 //===========================================================================================================================
1621 mDNSlocal
void Task( mDNS
*inMDNS
)
1627 struct timeval timeout
;
1628 NetworkInterfaceInfoVxWorks
* i
;
1634 err
= TaskInit( inMDNS
);
1635 require_noerr( err
, exit
);
1637 while( !inMDNS
->p
->quit
)
1639 // Let mDNSCore do its work then wait for an event. On idle timeouts (n == 0), just loop back to mDNS_Exceute.
1641 nextEvent
= mDNS_Execute( inMDNS
);
1642 TaskSetupSelect( inMDNS
, &readSet
, &maxFd
, nextEvent
, &timeout
);
1643 n
= select( maxFd
+ 1, &readSet
, NULL
, NULL
, &timeout
);
1644 check_translated_errno( n
>= 0, errno_compat(), kUnknownErr
);
1645 if( n
== 0 ) continue;
1647 // Process interface-specific sockets with pending data.
1650 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1653 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1655 TaskProcessPackets( inMDNS
, &i
->ss
, fd
);
1659 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1661 TaskProcessPackets( inMDNS
, &i
->ss
, fd
);
1666 // Process unicast sockets with pending data.
1668 fd
= inMDNS
->p
->unicastSS
.sockV4
;
1669 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1671 TaskProcessPackets( inMDNS
, &inMDNS
->p
->unicastSS
, fd
);
1674 fd
= inMDNS
->p
->unicastSS
.sockV6
;
1675 if( IsValidSocket( fd
) && FD_ISSET( fd
, &readSet
) )
1677 TaskProcessPackets( inMDNS
, &inMDNS
->p
->unicastSS
, fd
);
1681 // Processing pending commands.
1683 fd
= inMDNS
->p
->commandPipe
;
1685 if( FD_ISSET( fd
, &readSet
) )
1687 ProcessCommand( inMDNS
);
1690 check_string( n
> 0, "select said something was readable, but nothing was" );
1697 //===========================================================================================================================
1699 //===========================================================================================================================
1701 mDNSlocal mStatus
TaskInit( mDNS
*inMDNS
)
1707 inMDNS
->p
->taskID
= taskIdSelf();
1709 err
= SetupCommandPipe( inMDNS
);
1710 require_noerr( err
, exit
);
1712 inMDNS
->CanReceiveUnicastOn5353
= mDNStrue
;
1714 // Set up the HINFO string using the description property (e.g. "Device V1.0").
1716 inMDNS
->HIHardware
.c
[ 0 ] = 11;
1717 memcpy( &inMDNS
->HIHardware
.c
[ 1 ], "Device V1.0", inMDNS
->HIHardware
.c
[ 0 ] ); // $$$ Implementers: Fill in real info.
1719 // Set up the unicast sockets.
1721 err
= SetupSocket( inMDNS
, &zeroAddr
, mDNSfalse
, AF_INET
, &inMDNS
->p
->unicastSS
);
1723 if( err
== mStatus_NoError
)
1725 struct sockaddr_in sa4
;
1727 len
= sizeof( sa4
);
1728 err
= getsockname( inMDNS
->p
->unicastSS
.sockV4
, (struct sockaddr
*) &sa4
, &len
);
1729 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1730 if( err
== 0 ) inMDNS
->UnicastPort4
.NotAnInteger
= sa4
.sin_port
;
1733 err
= SetupSocket( inMDNS
, &zeroAddr
, mDNSfalse
, AF_INET6
, &inMDNS
->p
->unicastSS
);
1735 if( err
== mStatus_NoError
)
1737 struct sockaddr_in6 sa6
;
1739 len
= sizeof( sa6
);
1740 err
= getsockname( inMDNS
->p
->unicastSS
.sockV6
, (struct sockaddr
*) &sa6
, &len
);
1741 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1742 if( err
== 0 ) inMDNS
->UnicastPort6
.NotAnInteger
= sa6
.sin6_port
;
1745 // Set up the interfaces.
1747 utc
= mDNSPlatformUTC();
1748 UpdateInterfaceList( inMDNS
, utc
);
1749 SetupActiveInterfaces( inMDNS
, utc
);
1750 err
= mStatus_NoError
;
1753 // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
1755 inMDNS
->p
->initErr
= err
;
1756 semGive( inMDNS
->p
->initEvent
);
1760 //===========================================================================================================================
1762 //===========================================================================================================================
1764 mDNSlocal
void TaskTerm( mDNS
*inMDNS
)
1769 // Tear down all interfaces.
1771 utc
= mDNSPlatformUTC();
1772 MarkAllInterfacesInactive( inMDNS
, utc
);
1773 ClearInactiveInterfaces( inMDNS
, utc
, mDNStrue
);
1774 check_string( !inMDNS
->p
->interfaceList
, "LEAK: closing without deleting all interfaces" );
1776 // Close unicast sockets.
1778 ForgetSocket( &inMDNS
->p
->unicastSS
.sockV4
);
1779 ForgetSocket( &inMDNS
->p
->unicastSS
.sockV6
);
1781 // Tear down everything else that was set up in TaskInit then signal back that we're done.
1783 err
= TearDownCommandPipe( inMDNS
);
1786 err
= semGive( inMDNS
->p
->quitEvent
);
1787 check_translated_errno( err
== 0, errno_compat(), kUnknownErr
);
1790 //===========================================================================================================================
1792 //===========================================================================================================================
1794 mDNSlocal
void TaskSetupSelect( mDNS
*inMDNS
, fd_set
*outSet
, int *outMaxFd
, mDNSs32 inNextEvent
, struct timeval
*outTimeout
)
1796 NetworkInterfaceInfoVxWorks
* i
;
1804 // Add the interface-specific sockets.
1806 for( i
= inMDNS
->p
->interfaceList
; i
; i
= i
->next
)
1809 if( IsValidSocket( fd
) )
1811 FD_SET( fd
, outSet
);
1812 if( fd
> maxFd
) maxFd
= fd
;
1816 if( IsValidSocket( fd
) )
1818 FD_SET( fd
, outSet
);
1819 if( fd
> maxFd
) maxFd
= fd
;
1823 // Add the unicast sockets.
1825 fd
= inMDNS
->p
->unicastSS
.sockV4
;
1826 if( IsValidSocket( fd
) )
1828 FD_SET( fd
, outSet
);
1829 if( fd
> maxFd
) maxFd
= fd
;
1832 fd
= inMDNS
->p
->unicastSS
.sockV6
;
1833 if( IsValidSocket( fd
) )
1835 FD_SET( fd
, outSet
);
1836 if( fd
> maxFd
) maxFd
= fd
;
1839 // Add the command pipe.
1841 fd
= inMDNS
->p
->commandPipe
;
1843 FD_SET( fd
, outSet
);
1844 if( fd
> maxFd
) maxFd
= fd
;
1849 // Calculate how long to wait before performing idle processing.
1851 delta
= inNextEvent
- mDNS_TimeNow( inMDNS
);
1854 // The next task time is now or in the past. Set the timeout to fire immediately.
1856 outTimeout
->tv_sec
= 0;
1857 outTimeout
->tv_usec
= 0;
1861 // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
1862 // before multiplying to account for integer rounding error and avoid firing the timeout too early.
1864 outTimeout
->tv_sec
= delta
/ mDNSPlatformOneSecond
;
1865 outTimeout
->tv_usec
= ( ( delta
% mDNSPlatformOneSecond
) + 1 ) * gMDNSTicksToMicro
;
1866 if( outTimeout
->tv_usec
>= 1000000L )
1868 outTimeout
->tv_sec
+= 1;
1869 outTimeout
->tv_usec
= 0;
1874 //===========================================================================================================================
1875 // TaskProcessPackets
1876 //===========================================================================================================================
1878 mDNSlocal
void TaskProcessPackets( mDNS
*inMDNS
, SocketSet
*inSS
, SocketRef inSock
)
1884 struct sockaddr_storage from
;
1887 mDNSAddr senderAddr
;
1888 mDNSIPPort senderPort
;
1891 buf
= (mDNSu8
*) &inMDNS
->imsg
;
1892 size
= sizeof( inMDNS
->imsg
);
1896 n
= mDNSRecvMsg( inSock
, buf
, size
, &from
, sizeof( from
), &fromSize
, &destAddr
, &ifindex
);
1898 if( from
.ss_family
== AF_INET
)
1900 struct sockaddr_in
* sa4
;
1902 sa4
= (struct sockaddr_in
*) &from
;
1903 senderAddr
.type
= mDNSAddrType_IPv4
;
1904 senderAddr
.ip
.v4
.NotAnInteger
= sa4
->sin_addr
.s_addr
;
1905 senderPort
.NotAnInteger
= sa4
->sin_port
;
1907 else if( from
.ss_family
== AF_INET6
)
1909 struct sockaddr_in6
* sa6
;
1911 sa6
= (struct sockaddr_in6
*) &from
;
1912 senderAddr
.type
= mDNSAddrType_IPv6
;
1913 senderAddr
.ip
.v6
= *( (mDNSv6Addr
*) &sa6
->sin6_addr
);
1914 senderPort
.NotAnInteger
= sa6
->sin6_port
;
1918 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: WARNING! from addr unknown family %d\n", __ROUTINE__
, from
.ss_family
);
1922 // Even though we indicated a specific interface when joining the multicast group, a weirdness of the
1923 // sockets API means that even though this socket has only officially joined the multicast group
1924 // on one specific interface, the kernel will still deliver multicast packets to it no matter which
1925 // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
1926 // To work around this weirdness, we use the IP_RECVIF/IPV6_PKTINFO options to find the interface
1927 // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
1929 if( mDNSAddrIsDNSMulticast( &destAddr
) )
1931 if( !inSS
->info
|| !inSS
->info
->exists
)
1933 dpkt( kDebugLevelChatty
- 3, DEBUG_NAME
" ignored mcast, src=[%#39a], dst=[%#39a], if= unicast socket %d\n",
1934 &senderAddr
, &destAddr
, inSock
);
1937 if( ifindex
!= inSS
->info
->scopeID
)
1939 #if( DEBUG && MDNS_DEBUG_PACKETS )
1940 char ifname
[ IF_NAMESIZE
];
1943 dpkt( kDebugLevelChatty
- 3,
1944 DEBUG_NAME
" ignored mcast, src=[%#39a] dst=[%#39a], if=%8s(%u) -- really for %8s(%u)\n",
1945 &senderAddr
, &destAddr
, inSS
->info
->ifinfo
.ifname
, inSS
->info
->scopeID
,
1946 if_indextoname( ifindex
, ifname
), ifindex
);
1950 id
= inSS
->info
->ifinfo
.InterfaceID
;
1951 dpkt( kDebugLevelChatty
- 2, DEBUG_NAME
"recv %4d bytes, src=[%#39a]:%5hu, dst=[%#39a], if=%8s(%u) %#p\n",
1952 n
, &senderAddr
, mDNSVal16( senderPort
), &destAddr
, inSS
->info
->ifinfo
.ifname
, inSS
->info
->scopeID
, id
);
1956 NetworkInterfaceInfoVxWorks
* i
;
1958 // For unicast packets, try to find the matching interface.
1960 for( i
= inMDNS
->p
->interfaceList
; i
&& ( i
->scopeID
!= ifindex
); i
= i
->next
) {}
1961 if( i
) id
= i
->ifinfo
.InterfaceID
;
1964 mDNSCoreReceive( inMDNS
, buf
, buf
+ n
, &senderAddr
, senderPort
, &destAddr
, MulticastDNSPort
, id
);
1968 //===========================================================================================================================
1970 //===========================================================================================================================
1976 size_t inBufferSize
,
1979 size_t * outFromSize
,
1980 mDNSAddr
* outDstAddr
,
1981 uint32_t * outIndex
)
1986 char ancillary
[ 1024 ];
1987 struct cmsghdr
* cmPtr
;
1990 // Read a packet and any ancillary data. Note: EWOULDBLOCK errors are expected when we've read all pending packets.
1992 iov
.iov_base
= (char *) inBuffer
;
1993 iov
.iov_len
= inBufferSize
;
1994 msg
.msg_name
= (caddr_t
) outFrom
;
1995 msg
.msg_namelen
= inFromSize
;
1998 msg
.msg_control
= (caddr_t
) &ancillary
;
1999 msg
.msg_controllen
= sizeof( ancillary
);
2001 n
= recvmsg( inSock
, &msg
, 0 );
2004 err
= errno_compat();
2005 if( err
!= EWOULDBLOCK
) dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) returned %d, errno %d\n",
2006 __ROUTINE__
, inSock
, n
, err
);
2009 if( msg
.msg_controllen
< sizeof( struct cmsghdr
) )
2011 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) msg_controllen %d < sizeof( struct cmsghdr ) %u\n",
2012 __ROUTINE__
, inSock
, msg
.msg_controllen
, sizeof( struct cmsghdr
) );
2013 n
= mStatus_UnknownErr
;
2016 if( msg
.msg_flags
& MSG_CTRUNC
)
2018 dmsg( kDebugLevelWarning
, DEBUG_NAME
"%s: recvmsg(%d) MSG_CTRUNC (%d recv'd)\n", __ROUTINE__
, inSock
, n
);
2019 n
= mStatus_BadFlagsErr
;
2022 *outFromSize
= msg
.msg_namelen
;
2024 // Parse each option out of the ancillary data.
2026 for( cmPtr
= CMSG_FIRSTHDR( &msg
); cmPtr
; cmPtr
= CMSG_NXTHDR( &msg
, cmPtr
) )
2028 if( ( cmPtr
->cmsg_level
== IPPROTO_IP
) && ( cmPtr
->cmsg_type
== IP_RECVDSTADDR
) )
2030 outDstAddr
->type
= mDNSAddrType_IPv4
;
2031 outDstAddr
->ip
.v4
.NotAnInteger
= *( (mDNSu32
*) CMSG_DATA( cmPtr
) );
2033 else if( ( cmPtr
->cmsg_level
== IPPROTO_IP
) && ( cmPtr
->cmsg_type
== IP_RECVIF
) )
2035 struct sockaddr_dl
* sdl
;
2037 sdl
= (struct sockaddr_dl
*) CMSG_DATA( cmPtr
);
2038 *outIndex
= sdl
->sdl_index
;
2040 else if( ( cmPtr
->cmsg_level
== IPPROTO_IPV6
) && ( cmPtr
->cmsg_type
== IPV6_PKTINFO
) )
2042 struct in6_pktinfo
* pi6
;
2044 pi6
= (struct in6_pktinfo
*) CMSG_DATA( cmPtr
);
2045 outDstAddr
->type
= mDNSAddrType_IPv6
;
2046 outDstAddr
->ip
.v6
= *( (mDNSv6Addr
*) &pi6
->ipi6_addr
);
2047 *outIndex
= pi6
->ipi6_ifindex
;
2057 #pragma mark == Debugging ==
2060 #if( DEBUG && MDNS_DEBUG_SHOW )
2061 //===========================================================================================================================
2063 //===========================================================================================================================
2065 void mDNSShow( void );
2067 void mDNSShow( void )
2069 NetworkInterfaceInfoVxWorks
* i
;
2076 dmsg( kDebugLevelMax
, "\n-- mDNS globals --\n" );
2077 dmsg( kDebugLevelMax
, " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS
) );
2078 dmsg( kDebugLevelMax
, " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord
) );
2079 dmsg( kDebugLevelMax
, " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord
) );
2080 dmsg( kDebugLevelMax
, " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord
) );
2081 dmsg( kDebugLevelMax
, " mDNSPlatformOneSecond = %ld\n", mDNSPlatformOneSecond
);
2082 dmsg( kDebugLevelMax
, " gMDNSTicksToMicro = %ld\n", gMDNSTicksToMicro
);
2083 dmsg( kDebugLevelMax
, " gMDNSPtr = %#p\n", gMDNSPtr
);
2086 dmsg( kDebugLevelMax
, "### mDNS not initialized\n" );
2089 dmsg( kDebugLevelMax
, " nicelabel = \"%#s\"\n", gMDNSPtr
->nicelabel
.c
);
2090 dmsg( kDebugLevelMax
, " hostLabel = \"%#s\"\n", gMDNSPtr
->hostlabel
.c
);
2091 dmsg( kDebugLevelMax
, " MulticastHostname = \"%##s\"\n", gMDNSPtr
->MulticastHostname
.c
);
2092 dmsg( kDebugLevelMax
, " HIHardware = \"%#s\"\n", gMDNSPtr
->HIHardware
.c
);
2093 dmsg( kDebugLevelMax
, " HISoftware = \"%#s\"\n", gMDNSPtr
->HISoftware
.c
);
2094 dmsg( kDebugLevelMax
, " UnicastPort4/6 = %d/%d\n",
2095 mDNSVal16( gMDNSPtr
->UnicastPort4
), mDNSVal16( gMDNSPtr
->UnicastPort6
) );
2096 dmsg( kDebugLevelMax
, " unicastSS.sockV4/V6 = %d/%d\n",
2097 gMDNSPtr
->p
->unicastSS
.sockV4
, gMDNSPtr
->p
->unicastSS
.sockV6
);
2098 dmsg( kDebugLevelMax
, " lock = %#p\n", gMDNSPtr
->p
->lock
);
2099 dmsg( kDebugLevelMax
, " initEvent = %#p\n", gMDNSPtr
->p
->initEvent
);
2100 dmsg( kDebugLevelMax
, " initErr = %ld\n", gMDNSPtr
->p
->initErr
);
2101 dmsg( kDebugLevelMax
, " quitEvent = %#p\n", gMDNSPtr
->p
->quitEvent
);
2102 dmsg( kDebugLevelMax
, " commandPipe = %d\n", gMDNSPtr
->p
->commandPipe
);
2103 dmsg( kDebugLevelMax
, " taskID = %#p\n", gMDNSPtr
->p
->taskID
);
2104 dmsg( kDebugLevelMax
, "\n" );
2108 utc
= mDNSPlatformUTC();
2109 dmsg( kDebugLevelMax
, "-- mDNS interfaces --\n" );
2111 for( i
= gMDNSPtr
->p
->interfaceList
; i
; i
= i
->next
)
2113 dmsg( kDebugLevelMax
, " interface %2d %8s(%u) [%#39a] %s, sockV4 %2d, sockV6 %2d, Age %d\n",
2114 num
, i
->ifinfo
.ifname
, i
->scopeID
, &i
->ifinfo
.ip
,
2115 i
->ifinfo
.InterfaceID
? " REGISTERED" : "*NOT* registered",
2116 i
->ss
.sockV4
, i
->ss
.sockV6
, utc
- i
->lastSeen
);
2119 dmsg( kDebugLevelMax
, "\n" );
2123 dmsg( kDebugLevelMax
, "-- mDNS resource records --\n" );
2125 for( r
= gMDNSPtr
->ResourceRecords
; r
; r
= r
->next
)
2127 i
= (NetworkInterfaceInfoVxWorks
*) r
->resrec
.InterfaceID
;
2128 if( r
->resrec
.rrtype
== kDNSType_TXT
)
2136 rd
= &r
->resrec
.rdata
->u
;
2137 dmsg( kDebugLevelMax
, " record %2d: %#p %8s(%u): %4d %##s %s:\n", num
, i
,
2138 i
? i
->ifinfo
.ifname
: "<any>",
2140 r
->resrec
.rdlength
, r
->resrec
.name
->c
, DNSTypeName( r
->resrec
.rrtype
) );
2144 end
= txt
+ r
->resrec
.rdlength
;
2148 if( ( txt
+ size
) > end
)
2150 dmsg( kDebugLevelMax
, " ### ERROR! txt length byte too big (%u, %u max)\n", size
, end
- txt
);
2153 dmsg( kDebugLevelMax
, " string %2d (%3d bytes): \"%.*s\"\n", nEntries
, size
, size
, txt
);
2160 dmsg( kDebugLevelMax
, " record %2d: %#p %8s(%u): %s\n", num
, i
,
2161 i
? i
->ifinfo
.ifname
: "<any>",
2163 ARDisplayString( gMDNSPtr
, r
) );
2167 dmsg( kDebugLevelMax
, "\n");
2169 #endif // DEBUG && MDNS_DEBUG_SHOW