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