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