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