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