1/*
2 * Copyright (c) 2003, 2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * sys-bsd.c - System-dependent procedures for setting up
25 * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
26 *
27 * Copyright (c) 1989 Carnegie Mellon University.
28 * Copyright (c) 1995 The Australian National University.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms are permitted
32 * provided that the above copyright notice and this paragraph are
33 * duplicated in all such forms and that any documentation,
34 * advertising materials, and other materials related to such
35 * distribution and use acknowledge that the software was developed
36 * by Carnegie Mellon University and The Australian National University.
37 * The names of the Universities may not be used to endorse or promote
38 * products derived from this software without specific prior written
39 * permission.
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
41 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
42 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
43 */
44
45#define RCSID	"$Id: sys-MacOSX.c,v 1.40 2006/02/16 01:47:04 lindak Exp $"
46
47/* -----------------------------------------------------------------------------
48  Includes
49----------------------------------------------------------------------------- */
50
51#include <stdio.h>
52#include <string.h>
53#include <stdlib.h>
54#include <unistd.h>
55#include <errno.h>
56#include <fcntl.h>
57#include <termios.h>
58#include <signal.h>
59#include <util.h>
60#include <sys/ioctl.h>
61#include <sys/types.h>
62#include <sys/socket.h>
63#include <sys/sockio.h>
64#include <sys/time.h>
65#include <sys/stat.h>
66#include <sys/param.h>
67#include <sys/wait.h>
68#include <sys/un.h>
69#include <sys/ucred.h>
70#import "acsp.h"
71#ifdef PPP_FILTER
72#include <net/bpf.h>
73#endif
74#include <net/if.h>
75#include <net/if_types.h>
76#include <mach-o/dyld.h>
77#include <dirent.h>
78#include <NSSystemDirectories.h>
79#include <mach/mach_time.h>
80#include <SystemConfiguration/SystemConfiguration.h>
81#include <SystemConfiguration/SCPrivate.h>
82#include <CoreFoundation/CFBundle.h>
83#include <CoreFoundation/CFXPCBridge.h>
84#include <ppp_defs.h>
85#include <ppp_domain.h>
86#include <ppp_msg.h>
87#include <ppp_privmsg.h>
88#include <if_ppp.h>
89#include <net/route.h>
90#include <net/if_dl.h>
91#include <netinet/in.h>
92#include <netinet/in_var.h>
93#include <netinet6/nd6.h>
94#include <netinet/if_ether.h>
95#include <syslog.h>
96#include <sys/un.h>
97#include <pthread.h>
98#include <notify.h>
99#include <IOKit/IOKitLib.h>
100#include <IOKit/network/IOEthernetInterface.h>
101#include <IOKit/network/IONetworkInterface.h>
102#include <IOKit/network/IOEthernetController.h>
103#include <servers/bootstrap.h>
104#include <arpa/inet.h>
105#include <bsm/libbsm.h>
106#include <ifaddrs.h>
107#include <netinet/ip.h>
108#include <netinet/ip_icmp.h>
109
110#include <ne_session.h>
111
112#include "pppcontroller.h"
113#include <ppp/pppcontroller_types.h>
114#include "scnc_utils_common.h"
115
116#include "../vpnd/RASSchemaDefinitions.h"
117
118
119#include "pppd.h"
120#include "fsm.h"
121#include "ipcp.h"
122#include "lcp.h"
123#include "eap.h"
124#include "../vpnd/RASSchemaDefinitions.h"
125
126#include "acscp.h"
127
128/* -----------------------------------------------------------------------------
129 Definitions
130----------------------------------------------------------------------------- */
131
132#define IP_FORMAT	"%d.%d.%d.%d"
133#define IP_CH(ip)	((u_char *)(ip))
134#define IP_LIST(ip)	IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
135
136#define PPP_NKE_PATH 	"/System/Library/Extensions/PPP.kext"
137#define PPP_NKE_ID		"com.apple.nke.ppp"
138
139/* We can get an EIO error on an ioctl if the modem has hung up */
140#define ok_error(num) ((num)==EIO)
141
142#ifndef N_SYNC_PPP
143#define N_SYNC_PPP 14
144#endif
145
146/*
147 * If PPP_DRV_NAME is not defined, use the default "ppp" as the device name.
148 */
149#if !defined(PPP_DRV_NAME)
150#define PPP_DRV_NAME	"ppp"
151#endif /* !defined(PPP_DRV_NAME) */
152
153/* -----------------------------------------------------------------------------
154 Forward declarations
155----------------------------------------------------------------------------- */
156
157static int get_flags (int fd);
158static void set_flags (int fd, int flags);
159static int set_kdebugflag(int level);
160static int make_ppp_unit(void);
161/* Prototypes for procedures local to this file. */
162static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *));
163static int connect_pfppp();
164//static void sys_pidchange(void *arg, int pid);
165static void sys_phasechange(void *arg, uintptr_t phase);
166static void sys_exitnotify(void *arg, uintptr_t exitcode);
167int publish_keyentry(CFStringRef key, CFStringRef entry, CFTypeRef value);
168int publish_dictnumentry(CFStringRef dict, CFStringRef entry, int val);
169int publish_dictstrentry(CFStringRef dict, CFStringRef entry, char *str, int encoding);
170int unpublish_keyentry(CFStringRef key, CFStringRef entry);
171int unpublish_dict(CFStringRef dict);
172int publish_dns_wins_entry(CFStringRef entity, CFStringRef property1, CFTypeRef ref1, CFTypeRef ref1a,
173						CFStringRef property2, CFTypeRef ref2,
174						CFStringRef property3, CFTypeRef ref3, int clean);
175int unpublish_dictentry(CFStringRef dict, CFStringRef entry);
176static void sys_eventnotify(void *param, uintptr_t code);
177static void sys_timeremaining(void *param, uintptr_t info);
178static void sys_authpeersuccessnotify(void *param, uintptr_t info);
179static int update_stateaddr(u_int32_t o, u_int32_t h, u_int32_t m);
180int publish_stateaddr(u_int32_t o, u_int32_t h, u_int32_t m);
181int route_interface(int cmd, struct in_addr host, struct in_addr mask, char iftype, char *ifname, int is_host);
182int route_gateway(int cmd, struct in_addr dest, struct in_addr mask, struct in_addr gateway, int use_gway_flag);
183static void ppp_ip_probe_timeout (void *arg);
184static void republish_dict();
185static int commit_publish_dict();
186
187extern bool nelog_is_logging_at_level(int level);
188extern void nelogv(int level, const char *format, va_list args) __attribute__((format(__printf__, 2, 0)));
189
190/* -----------------------------------------------------------------------------
191 Globals
192----------------------------------------------------------------------------- */
193#ifndef lint
194static const char rcsid[] = RCSID;
195#endif
196
197static int 		ttydisc = TTYDISC;	/* The default tty discipline */
198static int 		pppdisc = PPPDISC;	/* The PPP sync or async discipline */
199
200static int 		initfdflags = -1;	/* Initial file descriptor flags for ppp_fd */
201static int 		ppp_fd = -1;		/* fd which is set to PPP discipline */
202static int		rtm_seq;
203
204static int 		restore_term;		/* 1 => we've munged the terminal */
205static struct termios 	inittermios; 		/* Initial TTY termios */
206static struct winsize 	wsinfo;			/* Initial window size info */
207
208static int 		ip_sockfd;		/* socket for doing interface ioctls */
209
210static fd_set 		in_fds;			/* set of fds that wait_input waits for */
211static fd_set 		ready_fds;		/* set of fds currently ready (out of select) */
212static int 		max_in_fd;		/* highest fd set in in_fds */
213
214static int 		if_is_up;		/* the interface is currently up */
215static int		ipv4_plumbed = 0; 	/* is ipv4 plumbed on the interface ? */
216static u_int32_t 	ifaddrs[2];		/* local and remote addresses we set */
217static u_int32_t 	default_route_gateway;	/* gateway addr for default route */
218static u_int32_t 	proxy_arp_addr;		/* remote addr for proxy arp */
219SCDynamicStoreRef	cfgCache = 0;		/* configd session */
220CFRunLoopSourceRef	rls = 0;		/* runloop source */
221CFStringRef		serviceidRef = 0;	/* service id ref */
222CFStringRef		serveridRef = 0;	/* server id ref */
223
224extern u_char		inpacket_buf[];		/* borrowed from main.c */
225
226static u_int32_t 	connecttime;		/* time when connection occured */
227int			looped;			/* 1 if using loop */
228int	 		ppp_sockfd = -1;	/* fd for PF_PPP socket */
229char 			*serviceid = NULL; 	/* configuration service ID to publish */
230char 			*serverid = NULL; 	/* server ID that spwaned this service */
231static CFStringRef	server_peer = NULL;	/* remote peer address for server */
232static char 	*network_signature = NULL; 	/* network signature */
233bool	 		noload = 0;		/* don't load the kernel extension */
234bool                    looplocal = 0;  /* Don't loop local traffic destined to the local address some applications rely on this default behavior */
235bool            addifroute = 0;  /* install route for the netmask of the interface */
236bool            noipv6override = 0;  /* don't override IPv6 traffic if IPv4 is primary */
237
238static struct in_addr		ifroute_address;
239static struct in_addr		ifroute_mask;
240static int		ifroute_installed = 0;
241
242double	 		timeScaleSeconds;	/* scale factor for machine absolute time to seconds */
243double	 		timeScaleMicroSeconds;	/* scale factor for machine absolute time to microseconds */
244
245CFPropertyListRef 		userOptions		= NULL;
246CFPropertyListRef 		systemOptions		= NULL;
247
248CFMutableDictionaryRef	publish_dict = NULL;
249
250option_t sys_options[] = {
251    { "serviceid", o_string, &serviceid,
252      "Service ID to publish"},
253    { "serverid", o_string, &serverid,
254      "Server ID that spawned this service."},
255    { "nopppload", o_bool, &noload,
256      "Don't try to load PPP NKE", 1},
257    { "looplocal", o_bool, &looplocal,
258      "Loop local traffic destined to the local address", 1},
259    { "noifroute", o_bool, &addifroute,
260      "Don't install route for the interface", 0},
261    { "addifroute", o_bool, &addifroute,
262      "Install route for the interface", 1},
263    { "nolooplocal", o_bool, &looplocal,
264      "Don't loop local traffic destined to the local address", 0},
265    { "noipv6override", o_bool, &noipv6override,
266      "Don't override other IPv6 interfaces if ppp is default for IPv4", 1},
267    { NULL }
268};
269
270ppp_session_t *session = NULL;
271static int ppp_auxiliary_probe_echos_pending = 0;
272static int ppp_auxiliary_probe_success = 0;
273static int ppp_auxiliary_probe_ip_notify_init = 0;
274static int ppp_auxiliary_probe_ip = 0;
275
276static int override_primary = 0;
277static int wait_port_mapping_changed = 0;
278
279extern int kill_link;
280
281extern bool	acsp_use_dhcp; // To check if we need to wait for DHCP information
282/* These booleans are meant to be set when the notifiers respond. */
283static bool protocols_ready = false;
284static bool acspdhcp_ready = false;
285
286static bool
287ne_is_controller(void)
288{
289	static bool result = false;
290	static dispatch_once_t init_check = 0;
291
292	dispatch_once(&init_check, ^{ result = (getenv(NESMControllerKey) != NULL); });
293
294	return result;
295}
296
297static ne_session_t
298ne_get_session(void)
299{
300	static ne_session_t session = NULL;
301	static dispatch_once_t session_init = 0;
302
303	dispatch_once(&session_init,
304		^{
305			char *env = getenv(NESMControllerKey);
306			if (env != NULL) {
307				uuid_t service_id;
308				if (uuid_parse(env, service_id) == 0) {
309					session = ne_session_create(service_id, NESessionTypeVPN);
310				}
311			}
312		});
313
314	return session;
315}
316
317static bool
318ne_setup_security_session(void)
319{
320	mach_port_t bootstrap_port = MACH_PORT_NULL;
321	mach_port_t audit_session_port = MACH_PORT_NULL;
322	ne_session_t session = ne_get_session();
323	bool success;
324
325	success = (session != NULL &&
326	           ne_session_copy_security_session_info(session, &bootstrap_port, &audit_session_port) &&
327	           bootstrap_port != MACH_PORT_NULL &&
328	           audit_session_port != MACH_PORT_NULL &&
329	           task_set_bootstrap_port(mach_task_self(), bootstrap_port) == KERN_SUCCESS &&
330	           audit_session_join(audit_session_port) != AU_DEFAUDITSID);
331
332	if (bootstrap_port != MACH_PORT_NULL) {
333		mach_port_deallocate(mach_task_self(), bootstrap_port);
334	}
335	if (audit_session_port != MACH_PORT_NULL) {
336		mach_port_deallocate(mach_task_self(), audit_session_port);
337	}
338
339	return success;
340}
341
342static void
343ne_copy_controller_data(void)
344{
345	ne_session_t session = ne_get_session();
346	if (session != NULL) {
347		__block xpc_object_t configuration = NULL;
348		dispatch_semaphore_t ne_sema = dispatch_semaphore_create(0);
349		ne_session_get_info(session, NESessionInfoTypeConfiguration, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
350			^(xpc_object_t result) {
351				if (result != NULL) {
352					configuration = xpc_retain(result);
353				}
354				dispatch_semaphore_signal(ne_sema);
355			});
356		dispatch_semaphore_wait(ne_sema, DISPATCH_TIME_FOREVER);
357		dispatch_release(ne_sema);
358
359		if (configuration && xpc_get_type(configuration) == XPC_TYPE_DICTIONARY) {
360			xpc_object_t plist = xpc_dictionary_get_value(configuration, NESMSessionLegacyServiceConfigurationKey);
361
362			if (plist) {
363				systemOptions = _CFXPCCreateCFObjectFromXPCObject(plist);
364			}
365
366			plist = xpc_dictionary_get_value(configuration, NESMSessionLegacyUserConfigurationKey);
367
368			if (plist) {
369				userOptions = _CFXPCCreateCFObjectFromXPCObject(plist);
370			}
371		}
372
373		if (configuration != NULL) {
374			xpc_release(configuration);
375		}
376	}
377}
378
379/* -----------------------------------------------------------------------------
380----------------------------------------------------------------------------- */
381void closeall()
382{
383    int i;
384
385    for (i = getdtablesize() - 1; i >= 0; i--) close(i);
386    open("/dev/null", O_RDWR, 0);
387    dup(0);
388    dup(0);
389    return;
390}
391
392/* -----------------------------------------------------------------------------
393close all file descriptor above 'from'
394----------------------------------------------------------------------------- */
395void closeallfrom(int from)
396{
397	int fd;
398	struct dirent entry, *entryp;
399
400	DIR *dirp = opendir("/dev/fd");
401	if (dirp == NULL) {
402		/* perhaps fall back on getdtablesize method */ ;
403		for (fd = from; fd < getdtablesize(); ++fd) close(fd);
404		return;
405	}
406
407	while (readdir_r(dirp, &entry, &entryp) == 0 && entryp != NULL) {
408		fd = atoi(entryp->d_name);
409		if (fd >= from && fd != dirp->__dd_fd)
410			close(fd);
411	}
412	closedir(dirp);
413}
414
415/* -----------------------------------------------------------------------------
416----------------------------------------------------------------------------- */
417u_long load_kext(char *kext, int byBundleID)
418{
419    int pid;
420
421    if ((pid = fork()) < 0)
422        return 1;
423
424    if (pid == 0) {
425        closeall();
426        // PPP kernel extension not loaded, try load it...
427		if (byBundleID)
428			execle("/sbin/kextload", "kextload", "-b", kext, (char *)0, (char *)0);
429		else
430			execle("/sbin/kextload", "kextload", kext, (char *)0, (char *)0);
431        exit(1);
432    }
433
434    while (waitpid(pid, 0, 0) < 0) {
435        if (errno == EINTR)
436            continue;
437       return 1;
438    }
439    return 0;
440}
441
442void sys_install(void)
443{
444	if (ne_is_controller()) {
445		notice("Committed PPP store on install command\n");
446		SCDynamicStoreSetMultiple(cfgCache, publish_dict, NULL, NULL);
447	}
448}
449
450void sys_uninstall(void)
451{
452	if (ne_is_controller()) {
453		notice("Received uninstall command\n");
454		if (publish_dict) {
455			CFIndex count = CFDictionaryGetCount(publish_dict);
456			if (count > 0) {
457				CFStringRef *keys = CFAllocatorAllocate(kCFAllocatorDefault, count * sizeof(*keys), 0);
458				if (keys != NULL) {
459					CFDictionaryGetKeysAndValues(publish_dict, (const void **)keys, NULL);
460					CFArrayRef keyArray = CFArrayCreate(kCFAllocatorDefault, (const void **)keys, count, &kCFTypeArrayCallBacks);
461					SCDynamicStoreSetMultiple(cfgCache, NULL, keyArray, NULL);
462					if (keyArray) {
463						CFRelease(keyArray);
464					}
465					CFAllocatorDeallocate(kCFAllocatorDefault, keys);
466				}
467			}
468		}
469	}
470}
471
472/* -----------------------------------------------------------------------------
473preinitialize options, called before sysinit
474----------------------------------------------------------------------------- */
475void sys_install_options()
476{
477    add_options(sys_options);
478}
479
480/* -----------------------------------------------------------------------------
481----------------------------------------------------------------------------- */
482int sys_check_controller()
483{
484	mach_port_t			server;
485	kern_return_t		status;
486	int					result;
487	audit_token_t		audit_token;
488	uid_t               euid;
489
490	if (ne_is_controller()) {
491		sys_log(LOG_NOTICE, "NetworkExtension is the controller");
492		return true;
493	}
494
495	status = bootstrap_look_up(bootstrap_port, PPPCONTROLLER_SERVER_PRIV, &server);
496	switch (status) {
497		case BOOTSTRAP_SUCCESS :
498			/* service currently registered, "a good thing" (tm) */
499			break;
500		case BOOTSTRAP_UNKNOWN_SERVICE :
501			/* service not currently registered, try again later */
502			return 0;
503		default :
504			return 0;
505	}
506
507	status = pppcontroller_iscontrolled(server, &result, &audit_token);
508
509	if (status == KERN_SUCCESS) {
510		audit_token_to_au32(audit_token,
511					NULL,			// auidp
512					&euid,			// euid
513					NULL,			// egid
514					NULL,			// ruid
515					NULL,			// rgid
516					NULL,			// pid
517					NULL,			// asid
518					NULL);			// tid
519
520		return ((result == kSCStatusOK) && (euid == 0));
521	}
522
523	return 0;
524}
525
526/* -------------------------------------------------------------------------------------------
527------------------------------------------------------------------------------------------- */
528CFPropertyListRef Unserialize(void *data, u_int32_t dataLen)
529{
530    CFDataRef           	xml;
531    CFPropertyListRef	ref = 0;
532
533    xml = CFDataCreate(NULL, data, dataLen);
534    if (xml) {
535        ref = CFPropertyListCreateFromXMLData(NULL,
536                xml,  kCFPropertyListImmutable, NULL);
537        CFRelease(xml);
538    }
539
540    return ref;
541}
542
543/* -----------------------------------------------------------------------------
544----------------------------------------------------------------------------- */
545void CopyControllerData()
546{
547	mach_port_t			server;
548	kern_return_t		status;
549	void				*data			= NULL;
550	unsigned int		datalen;
551	int				result			= kSCStatusFailed;
552	audit_token_t		audit_token;
553	uid_t               euid;
554
555	status = bootstrap_look_up(bootstrap_port, PPPCONTROLLER_SERVER_PRIV, &server);
556	switch (status) {
557		case BOOTSTRAP_SUCCESS :
558			/* service currently registered, "a good thing" (tm) */
559			break;
560		case BOOTSTRAP_UNKNOWN_SERVICE :
561			/* service not currently registered, try again later */
562			return ;
563		default :
564			return;
565	}
566
567	status = pppcontroller_copyprivoptions(server, 0, (xmlDataOut_t *)&data, &datalen, &result, &audit_token);
568
569	if (status != KERN_SUCCESS
570		|| result != kSCStatusOK) {
571		error("cannot get private system options from controller\n");
572		return;
573	}
574	audit_token_to_au32(audit_token,
575				NULL,			// auidp
576				&euid,			// euid
577				NULL,			// egid
578				NULL,			// ruid
579				NULL,			// rgid
580				NULL,			// pid
581				NULL,			// asid
582				NULL);			// tid
583	if (euid != 0) {
584		error("cannot authenticate private system options from controller\n");
585		return;
586	}
587
588	systemOptions = Unserialize(data, datalen);
589
590	status = pppcontroller_copyprivoptions(server, 1, (xmlDataOut_t *)&data, &datalen, &result, &audit_token);
591
592	if (status != KERN_SUCCESS
593		|| result != kSCStatusOK) {
594		error("cannot get private user options from controller\n");
595		return;
596	}
597	audit_token_to_au32(audit_token,
598				NULL,			// auidp
599				&euid,			// euid
600				NULL,			// egid
601				NULL,			// ruid
602				NULL,			// rgid
603				NULL,			// pid
604				NULL,			// asid
605				NULL);			// tid
606	if (euid != 0) {
607		error("cannot authenticate private user options from controller\n");
608		return;
609	}
610
611	userOptions = Unserialize(data, datalen);
612}
613
614/* -----------------------------------------------------------------------------
615----------------------------------------------------------------------------- */
616void CopyServerData()
617{
618    SCPreferencesRef 		prefs = 0;
619    CFPropertyListRef		servers_list;
620
621    // open the prefs file
622    prefs = SCPreferencesCreate(0, CFSTR("pppd"), kRASServerPrefsFileName);
623    if (prefs == NULL) {
624        fatal("Cannot open servers plist\n");
625		return;
626	}
627
628    // get servers list from the plist
629    servers_list = SCPreferencesGetValue(prefs, kRASServers);
630    if (servers_list == NULL) {
631        fatal("No servers found in servers plist\n");
632        CFRelease(prefs);
633		return;
634    }
635
636    systemOptions = CFDictionaryGetValue(servers_list, serveridRef);
637    if (!systemOptions || CFGetTypeID(systemOptions) != CFDictionaryGetTypeID()) {
638        fatal("Server ID '%s' not found in servers plist\n", serverid);
639		systemOptions = 0;
640        CFRelease(prefs);
641		return;
642    }
643
644	CFRetain(systemOptions);
645    CFRelease(prefs);
646}
647
648/* -----------------------------------------------------------------------------
649 ----------------------------------------------------------------------------- */
650void sys_protocolsreadynotify(void *param, uintptr_t info)
651{
652    protocols_ready = true;
653    dbglog("Received protocol dictionaries\n");
654    commit_publish_dict();
655}
656
657/* -----------------------------------------------------------------------------
658 ----------------------------------------------------------------------------- */
659void sys_acspdhcpreadynotify(void *param, uintptr_t info)
660{
661    acspdhcp_ready = true;
662    dbglog("Received acsp/dhcp dictionaries\n");
663    commit_publish_dict();
664}
665
666/**************************************************************************
667 To be called whenever we are potentially ready to update system config.
668 Particularly, these times are:
669 - Move into RUNNING state
670 - Receive DHCP or ACSP info
671 - Republish dictionary
672*************************************************************************/
673static int commit_publish_dict()
674{
675	/* Only publish one-at-a-time for demand mode */
676	if (demand) {
677		goto fail;
678	}
679
680	/* Check if we are RUNNING, there are NO WAITING protocols, and NO WAITING DHCP info */
681	int result = 1;
682
683	/* Make sure we're RUNNING */
684	if (phase != PHASE_RUNNING) {
685		goto fail;
686	}
687
688	/* Make sure all protocols ready */
689	if (!protocols_ready) {
690		goto fail;
691	}
692
693	/* Make sure all DHCP info acquired */
694	if ((acsp_use_dhcp || acscp_protent.enabled_flag) && !acspdhcp_ready) {
695		goto fail;
696	}
697
698	/* Publish! */
699	if (publish_dict) {
700		if (ne_is_controller()) {
701			sys_eventnotify((void*)PPP_EVT_REQUEST_INSTALL, override_primary);
702		} else {
703			notice("Committed PPP store\n");
704			if (!SCDynamicStoreSetMultiple(cfgCache, publish_dict, NULL, NULL))
705				result = 0;
706		}
707	}
708
709	return result;
710
711fail:
712    return 0;
713}
714
715/* -----------------------------------------------------------------------------
716 Change dictionary to be published
717 ----------------------------------------------------------------------------- */
718static int update_publish_dict(CFStringRef key, CFMutableDictionaryRef dict)
719{
720    int result = 1;
721
722	if (demand) {
723		if (SCDynamicStoreSetValue(cfgCache, key, dict) == 0)
724			result = 0;
725	}
726
727	if (publish_dict) {
728		CFDictionarySetValue(publish_dict, key, dict);
729	} else {
730        result = 0;
731    }
732
733	return result;
734}
735
736/* -----------------------------------------------------------------------------
737System-dependent initialization
738----------------------------------------------------------------------------- */
739void sys_init()
740{
741    int 		flags;
742    mach_timebase_info_data_t   timebaseInfo;
743
744    openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
745    setlogmask(LOG_UPTO(LOG_INFO));
746    if (debug)
747	setlogmask(LOG_UPTO(LOG_DEBUG));
748
749    // establish pppd as session leader
750    // if started via terminal, setsid will fail, which doesn't matter
751    // if started via configd, setsid will succeed and will allow reception of SIGHUP
752    setsid();
753
754    // open a socket to the PF_PPP protocol
755    ppp_sockfd = connect_pfppp();
756    if (ppp_sockfd < 0)
757        fatal("Couldn't open PF_PPP: %m");
758
759    flags = fcntl(ppp_sockfd, F_GETFL);
760    if (flags == -1
761        || fcntl(ppp_sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
762        warning("Couldn't set PF_PPP to nonblock: %m");
763
764    // Get an internet socket for doing socket ioctls
765    ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
766    if (ip_sockfd < 0)
767	fatal("Couldn't create IP socket: %m(%d)", errno);
768
769    // serviceid is required if we want pppd to publish information into the cache
770    if (!serviceid) {
771        CFUUIDRef       uuid;
772        CFStringRef	strref;
773        char 		str[100];
774
775        uuid = CFUUIDCreate(NULL);
776        strref = CFUUIDCreateString(NULL, uuid);
777        CFStringGetCString(strref, str, sizeof(str), kCFStringEncodingUTF8);
778
779        if ((serviceid = strdup(str)) == NULL)
780            fatal("Couldn't allocate memory to create temporary service id: %m(%d)", errno);
781
782        CFRelease(strref);
783        CFRelease(uuid);
784    }
785
786    serviceidRef = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), serviceid);
787    if (!serviceidRef)
788        fatal("Couldn't allocate memory to create service id reference: %m(%d)", errno);
789
790	/*	if started as a client by PPPController
791		copy user and system options from the controller */
792    if (controlled) {
793		if (ne_is_controller()) {
794			ne_copy_controller_data();
795		} else {
796			CopyControllerData();
797		}
798	}
799
800    //sys_pidchange(0, getpid());
801    cfgCache = SCDynamicStoreCreate(0, CFSTR("pppd"), 0, 0);
802    if (cfgCache == 0)
803        fatal("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
804    // if we are going to detach, wait to publish pid
805    if (nodetach)
806        publish_dictnumentry(kSCEntNetPPP, CFSTR("pid"), getpid());
807
808    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPStatus, phase);
809    if (serverid) {
810		serveridRef = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), serverid);
811		if (!serveridRef)
812			fatal("Couldn't allocate memory to create server id reference: %m(%d)", errno);
813		/* copy system options from the server plist */
814		CopyServerData();
815    	publish_dictstrentry(kSCEntNetInterface, CFSTR("ServerID"), serverid, kCFStringEncodingMacRoman);
816	}
817
818	publish_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
819    if (!controlled && publish_dict){
820        rls = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, cfgCache, 0);
821        if ( rls == NULL ){
822            notice("SCDynamicStoreCreateRunLoopSource FAILED %s", SCErrorString(SCError()));
823        } else {
824            CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
825        }
826        SCDynamicStoreSetDisconnectCallBack(cfgCache, republish_dict);
827    }
828
829
830    //add_notifier(&pidchange, sys_pidchange, 0);
831    add_notifier(&phasechange, sys_phasechange, 0);
832    add_notifier(&exitnotify, sys_exitnotify, 0);
833
834    // only send event if started when we are started by the PPPController
835    if (statusfd != -1) {
836
837        add_notifier(&ip_up_notify, sys_eventnotify, (void*)PPP_EVT_IPCP_UP);
838        add_notifier(&ip_down_notify, sys_eventnotify, (void*)PPP_EVT_IPCP_DOWN);
839        add_notifier(&lcp_up_notify, sys_eventnotify, (void*)PPP_EVT_LCP_UP);
840        add_notifier(&lcp_down_notify, sys_eventnotify, (void*)PPP_EVT_LCP_DOWN);
841        add_notifier(&lcp_lowerup_notify, sys_eventnotify, (void*)PPP_EVT_LOWERLAYER_UP);
842        add_notifier(&lcp_lowerdown_notify, sys_eventnotify, (void*)PPP_EVT_LOWERLAYER_DOWN);
843        add_notifier(&auth_start_notify, sys_eventnotify, (void*)PPP_EVT_AUTH_STARTED);
844        add_notifier(&auth_withpeer_fail_notify, sys_eventnotify, (void*)PPP_EVT_AUTH_FAILED);
845        add_notifier(&auth_withpeer_success_notify, sys_eventnotify, (void*)PPP_EVT_AUTH_SUCCEDED);
846        add_notifier(&connectscript_started_notify, sys_eventnotify, (void*)PPP_EVT_CONNSCRIPT_STARTED);
847        add_notifier(&connectscript_finished_notify, sys_eventnotify, (void*)PPP_EVT_CONNSCRIPT_FINISHED);
848        add_notifier(&terminalscript_started_notify, sys_eventnotify, (void*)PPP_EVT_TERMSCRIPT_STARTED);
849        add_notifier(&terminalscript_finished_notify, sys_eventnotify, (void*)PPP_EVT_TERMSCRIPT_FINISHED);
850        add_notifier(&connect_started_notify, sys_eventnotify, (void*)PPP_EVT_CONN_STARTED);
851        add_notifier(&connect_success_notify, sys_eventnotify, (void*)PPP_EVT_CONN_SUCCEDED);
852        add_notifier(&connect_fail_notify, sys_eventnotify, (void*)PPP_EVT_CONN_FAILED);
853        add_notifier(&disconnect_started_notify, sys_eventnotify, (void*)PPP_EVT_DISC_STARTED);
854        add_notifier(&disconnect_done_notify, sys_eventnotify, (void*)PPP_EVT_DISC_FINISHED);
855        add_notifier(&stop_notify, sys_eventnotify, (void*)PPP_EVT_STOPPED);
856        add_notifier(&cont_notify, sys_eventnotify, (void*)PPP_EVT_CONTINUED);
857    }
858
859    add_notifier(&lcp_timeremaining_notify, sys_timeremaining, 0);
860    add_notifier(&auth_peer_success_notify, sys_authpeersuccessnotify, 0);
861
862    add_notifier(&protocolsready_notifier, sys_protocolsreadynotify, 0);
863    add_notifier(&acspdhcpready_notifier, sys_acspdhcpreadynotify, 0);
864
865    if (mach_timebase_info(&timebaseInfo) == KERN_SUCCESS) {	// returns scale factor for ns
866        timeScaleMicroSeconds = ((double) timebaseInfo.numer / (double) timebaseInfo.denom) / 1000;
867        timeScaleSeconds = timeScaleMicroSeconds / 1000000;
868    }
869
870    FD_ZERO(&in_fds);
871    FD_ZERO(&ready_fds);
872    max_in_fd = 0;
873}
874
875/* -----------------------------------------------------------------------------
876 sys_cleanup - restore any system state we modified before exiting:
877 mark the interface down, delete default route and/or proxy arp entry.
878 This should call die() because it's called from die()
879----------------------------------------------------------------------------- */
880void sys_cleanup()
881{
882    struct ifreq ifr;
883
884	if (!controlled && rls) {
885		CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
886		CFRunLoopSourceInvalidate(rls);
887		CFRelease(rls);
888		rls = NULL;
889	}
890
891	cifroute();
892
893    if (if_is_up) {
894	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
895	if (ioctl(ip_sockfd, SIOCGIFFLAGS, &ifr) >= 0
896	    && ((ifr.ifr_flags & IFF_UP) != 0)) {
897	    ifr.ifr_flags &= ~IFF_UP;
898	    ioctl(ip_sockfd, SIOCSIFFLAGS, &ifr);
899	}
900    }
901
902    if (ifaddrs[0] != 0)
903	cifaddr(0, ifaddrs[0], ifaddrs[1]);
904
905    if (default_route_gateway)
906	cifdefaultroute(0, 0, default_route_gateway);
907    if (proxy_arp_addr)
908	cifproxyarp(0, proxy_arp_addr);
909}
910
911/* -----------------------------------------------------------------------------
912 sys_runloop - called from main loop
913----------------------------------------------------------------------------- */
914void sys_runloop()
915{
916	if (!controlled && rls) {
917		if (kill_link)
918			CFRunLoopStop(CFRunLoopGetCurrent());
919		else
920			CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
921	}
922}
923
924/* -----------------------------------------------------------------------------
925----------------------------------------------------------------------------- */
926void set_network_signature(char *key1, char *val1, char *key2, char *val2)
927{
928	int len = 0;
929
930	if (network_signature) {
931		free(network_signature);
932		network_signature = 0;
933	}
934
935	if (key1)
936		len += strlen(key1) + strlen(val1) + 1;
937	if (key2) {
938		if (key1) len++; // add separator ";"
939		len += strlen(key2) + strlen(val2) + 1;
940	}
941
942	 if (len) {
943		network_signature = malloc(len + 1);
944		if (!network_signature) {
945			warning("no memory to create network signature");
946			return;
947		}
948		network_signature[0] = 0;
949        if (key1) {
950			strlcat(network_signature, key1, len + 1);
951			strlcat(network_signature, "=", len + 1);
952			strlcat(network_signature, val1, len + 1);
953		}
954        if (key2) {
955			if (key1) strlcat(network_signature, ";", len + 1);
956			strlcat(network_signature, key2, len + 1);
957			strlcat(network_signature, "=", len + 1);
958			strlcat(network_signature, val2, len + 1);
959		}
960	 }
961}
962
963
964/* -----------------------------------------------------------------------------
965 ----------------------------------------------------------------------------- */
966void set_server_peer(struct in_addr peer)
967{
968	if (server_peer) {
969		CFRelease(server_peer);
970		server_peer = NULL;
971	}
972
973	server_peer = CFStringCreateWithCString(NULL, inet_ntoa(peer), kCFStringEncodingASCII);
974}
975
976
977/* -----------------------------------------------------------------------------
978----------------------------------------------------------------------------- */
979void sys_close()
980{
981    if (ip_sockfd != -1) {
982	close(ip_sockfd);
983	ip_sockfd = -1;
984    }
985    if (ppp_sockfd != -1) {
986        close(ppp_sockfd);
987        ppp_sockfd = -1;
988    }
989}
990
991/* -----------------------------------------------------------------------------
992 Functions to read and set the flags value in the device driver
993----------------------------------------------------------------------------- */
994static int get_flags (int fd)
995{
996    int flags;
997
998    if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) {
999	if ( ok_error (errno) )
1000	    flags = 0;
1001	else
1002	    fatal("ioctl(PPPIOCGFLAGS): %m");
1003    }
1004
1005    SYSDEBUG ((LOG_DEBUG, "get flags = %x\n", flags));
1006    return flags;
1007}
1008
1009/* -----------------------------------------------------------------------------
1010----------------------------------------------------------------------------- */
1011static void set_flags (int fd, int flags)
1012{
1013    SYSDEBUG ((LOG_DEBUG, "set flags = %x\n", flags));
1014
1015    if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) {
1016	if (! ok_error (errno) )
1017	    fatal("ioctl(PPPIOCSFLAGS, %x): %m", flags, errno);
1018    }
1019}
1020
1021/* -----------------------------------------------------------------------------
1022----------------------------------------------------------------------------- */
1023void sys_notify(u_int32_t message, uintptr_t code1, uintptr_t code2)
1024{
1025    struct ppp_msg_hdr	*hdr;
1026    int 		servlen, totlen;
1027    u_char 		*p, *msg;
1028
1029    if (statusfd == -1)
1030        return;
1031
1032    servlen = strlen(serviceid);
1033    totlen = sizeof(struct ppp_msg_hdr) + servlen + 8;
1034
1035    msg = malloc(totlen);
1036    if (!msg) {
1037	warning("no memory to send event to PPPController");
1038        return;
1039    }
1040
1041    p  = msg;
1042    bzero(p, totlen);
1043    hdr = ALIGNED_CAST(struct ppp_msg_hdr *)p;
1044    hdr->m_type = message;
1045    hdr->m_len = 8;
1046    hdr->m_flags |= USE_SERVICEID;
1047    hdr->m_link = servlen;
1048
1049    p += sizeof(struct ppp_msg_hdr);
1050    bcopy(serviceid, p, servlen);
1051    p += servlen;
1052    bcopy((u_char*)&code1, p, 4);
1053    p += 4;
1054    bcopy((u_char*)&code2, p, 4);
1055
1056    if (write(statusfd, msg, totlen) != totlen) {
1057	warning("can't talk to PPPController : %m");
1058    }
1059    free(msg);
1060}
1061
1062/* -----------------------------------------------------------------------------
1063we installed the notifier with the event as the parameter
1064----------------------------------------------------------------------------- */
1065void sys_eventnotify(void *param, uintptr_t code)
1066{
1067
1068    if (param == (void*)PPP_EVT_CONN_FAILED)
1069        code = EXIT_CONNECT_FAILED;
1070
1071    sys_notify(PPPD_EVENT, (uintptr_t)param, code);
1072}
1073
1074/* -----------------------------------------------------------------------------
1075send status notification to the controller
1076----------------------------------------------------------------------------- */
1077void sys_statusnotify()
1078{
1079
1080    sys_notify(PPPD_STATUS, status, devstatus);
1081}
1082
1083
1084/* -----------------------------------------------------------------------------
1085check the options that the user specified
1086----------------------------------------------------------------------------- */
1087int sys_check_options()
1088{
1089#ifndef CDTRCTS
1090    if (crtscts == 2) {
1091	warning("DTR/CTS flow control is not supported on this system");
1092	return 0;
1093    }
1094#endif
1095    return 1;
1096}
1097
1098/* -----------------------------------------------------------------------------
1099check if the kernel supports PPP
1100----------------------------------------------------------------------------- */
1101int ppp_available()
1102{
1103    int 	s;
1104    extern char *no_ppp_msg;
1105
1106    no_ppp_msg = "\
1107Mac OS X lacks kernel support for PPP.  \n\
1108To include PPP support in the kernel, please follow \n\
1109the steps detailed in the README.MacOSX file.\n";
1110
1111    // open to socket to the PF_PPP family
1112    // if that works, the kernel extension is loaded.
1113    if ((s = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL)) < 0) {
1114
1115#if !TARGET_OS_EMBEDDED
1116        if (!noload && !load_kext(PPP_NKE_PATH, 0))
1117#else
1118        if (!noload && !load_kext(PPP_NKE_ID, 1))
1119#endif
1120            s = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL);
1121
1122        if (s < 0)
1123            return 0;
1124    }
1125
1126    // could be smarter and get the version of the ppp family,
1127    // using get option or ioctl
1128
1129    close(s);
1130
1131    return 1;
1132}
1133
1134/* -----------------------------------------------------------------------------
1135----------------------------------------------------------------------------- */
1136static int still_ppp(void)
1137{
1138
1139    return !hungup && ppp_fd >= 0;
1140}
1141
1142/* -----------------------------------------------------------------------------
1143Define the debugging level for the kernel
1144----------------------------------------------------------------------------- */
1145static int set_kdebugflag (int requested_level)
1146{
1147   if (ifunit < 0)
1148	return 1;
1149    if (ioctl(ppp_sockfd, PPPIOCSDEBUG, &requested_level) < 0) {
1150	if ( ! ok_error (errno) )
1151	    error("ioctl(PPPIOCSDEBUG): %m");
1152	return (0);
1153    }
1154    SYSDEBUG ((LOG_INFO, "set kernel debugging level to %d",
1155		requested_level));
1156    return (1);
1157}
1158
1159/* -----------------------------------------------------------------------------
1160make a new ppp unit for ppp_sockfd
1161----------------------------------------------------------------------------- */
1162static int make_ppp_unit()
1163{
1164    int x;
1165    char name[32];
1166
1167    ifunit = req_unit;
1168    x = ioctl(ppp_sockfd, PPPIOCNEWUNIT, &ifunit);
1169    if (x < 0 && req_unit >= 0 && errno == EEXIST) {
1170        warning("Couldn't allocate PPP unit %d as it is already in use");
1171        ifunit = -1;
1172        x = ioctl(ppp_sockfd, PPPIOCNEWUNIT, &ifunit);
1173
1174
1175    }
1176    if (x < 0)
1177        error("Couldn't create new ppp unit: %m");
1178    else {
1179        slprintf(name, sizeof(name), "%s%d", PPP_DRV_NAME, ifunit);
1180        publish_dictstrentry(kSCEntNetPPP, kSCPropInterfaceName, name, kCFStringEncodingMacRoman);
1181    }
1182
1183    return x;
1184}
1185
1186/* -----------------------------------------------------------------------------
1187coen a socket to the PF_PPP protocol
1188----------------------------------------------------------------------------- */
1189int connect_pfppp()
1190{
1191    int 			fd = -1;
1192    struct sockaddr_ppp 	pppaddr;
1193
1194    // open a PF_PPP socket
1195    fd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL);
1196    if (fd < 0) {
1197        error("Couldn't open PF_PPP: %m");
1198        return -1;
1199    }
1200    // need to connect to the PPP protocol
1201    pppaddr.ppp_len = sizeof(struct sockaddr_ppp);
1202    pppaddr.ppp_family = AF_PPP;
1203    pppaddr.ppp_proto = PPPPROTO_CTL;
1204    pppaddr.ppp_cookie = 0;
1205    if (connect(fd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0) {
1206        error("Couldn't connect to PF_PPP: %m");
1207        close(fd);
1208        return -1;
1209    }
1210    return fd;
1211}
1212
1213
1214/* -----------------------------------------------------------------------------
1215Turn the serial port into a ppp interface
1216----------------------------------------------------------------------------- */
1217int tty_establish_ppp (int tty_fd)
1218{
1219    int new_fd;
1220
1221    // First, turn the device into ppp link
1222
1223    /* Ensure that the tty device is in exclusive mode.  */
1224    ioctl(tty_fd, TIOCEXCL, 0);
1225
1226    // Set the current tty to the PPP discpline
1227    pppdisc = sync_serial ? N_SYNC_PPP: PPPDISC;
1228    if (ioctl(tty_fd, TIOCSETD, &pppdisc) < 0) {
1229        if ( ! ok_error (errno) ) {
1230            error("Couldn't set tty to PPP discipline: %m");
1231            return -1;
1232        }
1233    }
1234
1235    // Then, then do the generic link work, and get a generic fd back
1236
1237    new_fd = generic_establish_ppp(tty_fd, NULL);
1238    if (new_fd == -1) {
1239        // Restore the previous line discipline
1240        if (ioctl(tty_fd, TIOCSETD, &ttydisc) < 0)
1241            if ( ! ok_error (errno))
1242                error("ioctl(TIOCSETD, TTYDISC): %m");
1243        return -1;
1244    }
1245
1246    set_flags(new_fd, get_flags(ppp_fd) & ~(SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP));
1247
1248    return new_fd;
1249}
1250
1251/* -----------------------------------------------------------------------------
1252Restore the serial port to normal operation.
1253This shouldn't call die() because it's called from die()
1254----------------------------------------------------------------------------- */
1255void tty_disestablish_ppp(int tty_fd)
1256{
1257
1258    if (!hungup) {
1259
1260        // Flush the tty output buffer so that the TIOCSETD doesn't hang.
1261        //if (tcflush(tty_fd, TCIOFLUSH) < 0)
1262        //    warning("tcflush failed: %m");
1263
1264        // Restore the previous line discipline
1265        if (ioctl(tty_fd, TIOCSETD, &ttydisc) < 0) {
1266            if ( ! ok_error (errno))
1267                error("ioctl(TIOCSETD, TTYDISC): %m");
1268        }
1269
1270        if (ioctl(tty_fd, TIOCNXCL, 0) < 0) {
1271            if ( ! ok_error (errno))
1272                warning("ioctl(TIOCNXCL): %m(%d)", errno);
1273        }
1274
1275	// Reset non-blocking mode on fd
1276	if (initfdflags != -1 && fcntl(tty_fd, F_SETFL, initfdflags) < 0) {
1277	    if ( ! ok_error (errno))
1278		warning("Couldn't restore device fd flags: %m");
1279	}
1280    }
1281
1282    initfdflags = -1;
1283
1284    generic_disestablish_ppp(tty_fd);
1285}
1286
1287/* -----------------------------------------------------------------------------
1288generic code to establish ppp interface
1289----------------------------------------------------------------------------- */
1290int generic_establish_ppp (int fd, UInt8 *delegate)
1291{
1292    int flags, s = -1, link = 0;
1293
1294    // Open another instance of the ppp socket and connect the link to it
1295    if (ioctl(fd, PPPIOCGCHAN, &link) == -1) {
1296        error("Couldn't get link number: %m");
1297        goto err;
1298    }
1299
1300    dbglog("using link %d", link);
1301
1302    // open a socket to the PPP protocol
1303    s = connect_pfppp();
1304    if (s < 0) {
1305        error("Couldn't reopen PF_PPP: %m");
1306        goto err;
1307    }
1308
1309    if (ioctl(s, PPPIOCATTCHAN, &link) < 0) {
1310        error("Couldn't attach to the ppp link %d: %m", link);
1311        goto err_close;
1312    }
1313
1314    flags = fcntl(s, F_GETFL);
1315    if (flags == -1 || fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
1316        warning("Couldn't set ppp socket link to nonblock: %m");
1317
1318    /* set the ppp_fd socket now */
1319    ppp_fd = s;
1320
1321    if (!looped)
1322        ifunit = -1;
1323    if (!looped && !multilink) {
1324        // Create a new PPP unit.
1325        if (make_ppp_unit() < 0)
1326            goto err_close;
1327    }
1328
1329    // set the delegate interface
1330    if (delegate) {
1331        if (ioctl(ppp_sockfd, PPPIOCSDELEGATE, delegate) < 0) {
1332            error("Couldn't set the delegate interface: %m");
1333            goto err_close;
1334        }
1335    }
1336
1337    if (looped) {
1338        set_flags(ppp_sockfd, get_flags(ppp_sockfd) & ~SC_LOOP_TRAFFIC);
1339        looped = 0;
1340    }
1341
1342    if (!multilink) {
1343        add_fd(ppp_sockfd);
1344        if (ioctl(s, PPPIOCCONNECT, &ifunit) < 0) {
1345            error("Couldn't attach to PPP unit %d: %m", ifunit);
1346            goto err_close;
1347        }
1348    }
1349
1350    // Enable debug in the driver if requested.
1351    set_kdebugflag (kdebugflag);
1352
1353    return ppp_fd;
1354
1355 err_close:
1356    close(s);
1357
1358 err:
1359    return -1;
1360}
1361
1362/* -----------------------------------------------------------------------------
1363Restore the serial port to normal operation.
1364This shouldn't call die() because it's called from die()
1365fd is the file descriptor of the device
1366----------------------------------------------------------------------------- */
1367void generic_disestablish_ppp(int fd)
1368{
1369    int 	x;
1370
1371    close(ppp_fd);
1372    ppp_fd = -1;
1373    if (demand) {
1374	looped = 1;
1375        set_flags(ppp_sockfd, get_flags(ppp_sockfd) | SC_LOOP_TRAFFIC);
1376    }
1377    else {
1378        unpublish_dictentry(kSCEntNetPPP, kSCPropInterfaceName);
1379        if (ifunit >= 0 && ioctl(ppp_sockfd, PPPIOCDETACH, &x) < 0)
1380            error("Couldn't release PPP unit ppp_sockfd %d: %m", ppp_sockfd);
1381    }
1382    if (!multilink)
1383        remove_fd(ppp_sockfd);
1384}
1385
1386/* -----------------------------------------------------------------------------
1387Check whether the link seems not to be 8-bit clean
1388----------------------------------------------------------------------------- */
1389void clean_check()
1390{
1391    int x;
1392    char *s;
1393
1394    if (!still_ppp())
1395        return;
1396
1397    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
1398	s = NULL;
1399	switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
1400	case SC_RCV_B7_0:
1401	    s = "bit 7 set to 1";
1402	    break;
1403	case SC_RCV_B7_1:
1404	    s = "bit 7 set to 0";
1405	    break;
1406	case SC_RCV_EVNP:
1407	    s = "odd parity";
1408	    break;
1409	case SC_RCV_ODDP:
1410	    s = "even parity";
1411	    break;
1412	}
1413	if (s != NULL) {
1414	    warning("Serial link is not 8-bit clean:");
1415	    warning("All received characters had %s", s);
1416	}
1417    }
1418}
1419
1420/* -----------------------------------------------------------------------------
1421Set up the serial port on `fd' for 8 bits, no parity,
1422 * at the requested speed, etc.  If `local' is true, set CLOCAL
1423 * regardless of whether the modem option was specified.
1424 *
1425 * For *BSD, we assume that speed_t values numerically equal bits/second
1426----------------------------------------------------------------------------- */
1427void set_up_tty(int fd, int local)
1428{
1429    struct termios tios;
1430
1431    // set the file descriptor as the controlling terminal, in order to receive SIGHUP
1432    if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1)
1433        error("set_up_tty, can't set controlling terminal: %m");
1434
1435    if (tcgetattr(fd, &tios) < 0) {
1436	error("tcgetattr: %m");
1437        return;
1438    }
1439
1440    if (!restore_term) {
1441	inittermios = tios;
1442	ioctl(fd, TIOCGWINSZ, &wsinfo);
1443    }
1444
1445    tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
1446    if (crtscts > 0 && !local) {
1447        if (crtscts == 2) {
1448#ifdef CDTRCTS
1449            tios.c_cflag |= CDTRCTS;
1450#endif
1451	} else
1452	    tios.c_cflag |= CRTSCTS;
1453    } else if (crtscts < 0) {
1454	tios.c_cflag &= ~CRTSCTS;
1455#ifdef CDTRCTS
1456	tios.c_cflag &= ~CDTRCTS;
1457#endif
1458    }
1459
1460    tios.c_cflag |= CS8 | CREAD | HUPCL;
1461    if (local || !modem)
1462	tios.c_cflag |= CLOCAL;
1463    tios.c_iflag = IGNBRK | IGNPAR;
1464    tios.c_oflag = 0;
1465    tios.c_lflag = 0;
1466    tios.c_cc[VMIN] = 1;
1467    tios.c_cc[VTIME] = 0;
1468
1469    if (crtscts == -2) {
1470	tios.c_iflag |= IXON | IXOFF;
1471	tios.c_cc[VSTOP] = 0x13;	/* DC3 = XOFF = ^S */
1472	tios.c_cc[VSTART] = 0x11;	/* DC1 = XON  = ^Q */
1473    }
1474
1475    if (inspeed) {
1476	cfsetospeed(&tios, inspeed);
1477	cfsetispeed(&tios, inspeed);
1478    } else {
1479	inspeed = cfgetospeed(&tios);
1480	/*
1481	 * We can't proceed if the serial port speed is 0,
1482	 * since that implies that the serial port is disabled.
1483	 */
1484	if (inspeed == 0)
1485	    fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
1486    }
1487
1488    baud_rate = inspeed;
1489    if (tcsetattr(fd, TCSAFLUSH, &tios) < 0)
1490	fatal("tcsetattr: %m");
1491
1492    restore_term = 1;
1493}
1494
1495
1496/* -----------------------------------------------------------------------------
1497Set up the serial port
1498 * If `local' is true, set CLOCAL
1499 * regardless of whether the modem option was specified.
1500 * other parameter (speed, start/stop bits, parity) may have been changed by the CCL
1501----------------------------------------------------------------------------- */
1502void set_up_tty_local(int fd, int local)
1503{
1504    struct termios tios;
1505
1506    if (tcgetattr(fd, &tios) < 0) {
1507	error("tcgetattr: %m");
1508        return;
1509    }
1510
1511   tios.c_cc[VMIN] = 1;
1512    tios.c_cc[VTIME] = 0;
1513
1514    tios.c_cflag &= ~CLOCAL;
1515    if (local || !modem)
1516	tios.c_cflag |= CLOCAL;
1517
1518    if (tcsetattr(fd, TCSANOW, &tios) < 0)
1519	fatal("tcsetattr: %m");
1520}
1521
1522/* -----------------------------------------------------------------------------
1523restore the terminal to the saved settings
1524----------------------------------------------------------------------------- */
1525void restore_tty(int fd)
1526{
1527    if (restore_term) {
1528	if (!default_device) {
1529	    /*
1530	     * Turn off echoing, because otherwise we can get into
1531	     * a loop with the tty and the modem echoing to each other.
1532	     * We presume we are the sole user of this tty device, so
1533	     * when we close it, it will revert to its defaults anyway.
1534	     */
1535	    inittermios.c_lflag &= ~(ECHO | ECHONL);
1536	}
1537	if (!hungup) {
1538            if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
1539                if (errno != ENXIO)
1540                    warning("tcsetattr: %m");
1541            ioctl(fd, TIOCSWINSZ, &wsinfo);
1542        }
1543	restore_term = 0;
1544    }
1545}
1546
1547/* -----------------------------------------------------------------------------
1548control the DTR line on the serial port.
1549 * This is called from die(), so it shouldn't call die()
1550----------------------------------------------------------------------------- */
1551void setdtr(int fd, int on)
1552{
1553    int modembits = TIOCM_DTR;
1554
1555    ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
1556}
1557
1558/* -----------------------------------------------------------------------------
1559get a pty master/slave pair and chown the slave side
1560 * to the uid given.  Assumes slave_name points to >= 12 bytes of space
1561----------------------------------------------------------------------------- */
1562int get_pty(int *master_fdp, int *slave_fdp, char *slave_name, int uid)
1563{
1564    struct termios tios;
1565
1566    if (openpty(master_fdp, slave_fdp, slave_name, NULL, NULL) < 0)
1567	return 0;
1568
1569    fchown(*slave_fdp, uid, -1);
1570    fchmod(*slave_fdp, S_IRUSR | S_IWUSR);
1571    if (tcgetattr(*slave_fdp, &tios) == 0) {
1572	tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
1573	tios.c_cflag |= CS8 | CREAD;
1574	tios.c_iflag  = IGNPAR | CLOCAL;
1575	tios.c_oflag  = 0;
1576	tios.c_lflag  = 0;
1577	if (tcsetattr(*slave_fdp, TCSAFLUSH, &tios) < 0)
1578	    warning("couldn't set attributes on pty: %m");
1579    } else
1580	warning("couldn't get attributes on pty: %m");
1581
1582    return 1;
1583}
1584
1585/* -----------------------------------------------------------------------------
1586create the ppp interface and configure it in loopback mode.
1587----------------------------------------------------------------------------- */
1588int open_ppp_loopback()
1589{
1590    looped = 1;
1591    /* allocate ourselves a ppp unit */
1592    if (make_ppp_unit() < 0)
1593        die(1);
1594    set_flags(ppp_sockfd, SC_LOOP_TRAFFIC);
1595    set_kdebugflag(kdebugflag);
1596    ppp_fd = -1;
1597    return ppp_sockfd;
1598}
1599
1600/* -----------------------------------------------------------------------------
1601Output PPP packet
1602----------------------------------------------------------------------------- */
1603void output(int unit, u_char *p, int len)
1604{
1605
1606    dump_packet("sent", p, len);
1607
1608    // don't write FF03
1609    len -= 2;
1610    p += 2;
1611
1612    // link protocol are sent to the link
1613    // other protocols are send to the bundle
1614  /* test was changed because compiler strangeness for embedded os */
1615//    if (write((ntohs(*(u_short*)p) >= 0xC000) ? ppp_fd : ppp_sockfd, p, len) < 0) {
1616	if (write((p[0] >= 0xC0) ? ppp_fd : ppp_sockfd, p, len) < 0) {
1617	if (errno != EIO)
1618	    error("write: %m");
1619    }
1620}
1621
1622/* -----------------------------------------------------------------------------
1623wait until there is data available, for the length of time specified by *timo
1624(indefinite if timo is NULL)
1625----------------------------------------------------------------------------- */
1626void wait_input(struct timeval *timo)
1627{
1628    int n;
1629
1630    ready_fds = in_fds;
1631    n = select(max_in_fd + 1, &ready_fds, NULL, NULL, timo);
1632   if (n < 0 && errno != EINTR)
1633	fatal("select: %m");
1634
1635   if (n < 0) {
1636        FD_ZERO(&ready_fds);
1637   }
1638}
1639
1640/* -----------------------------------------------------------------------------
1641wait on fd until there is data available, for the delay in milliseconds
1642return 0 if timeout expires, < 0 if error, otherwise > 0
1643----------------------------------------------------------------------------- */
1644int wait_input_fd(int fd, int delay)
1645{
1646    fd_set 		ready;
1647    int 		n;
1648    struct timeval 	t;
1649
1650    t.tv_sec = delay / 1000;
1651    t.tv_usec = delay % 1000;
1652
1653    FD_ZERO(&ready);
1654    FD_SET(fd, &ready);
1655
1656    do {
1657        n = select(fd + 1, &ready, NULL, &ready, &t);
1658    } while (n < 0 && errno == EINTR);
1659
1660    if (n > 0)
1661        if (ioctl(fd, FIONREAD, &n) == -1)
1662            n = -1;
1663
1664    return n;
1665}
1666
1667
1668/* -----------------------------------------------------------------------------
1669add an fd to the set that wait_input waits for
1670----------------------------------------------------------------------------- */
1671void add_fd(int fd)
1672{
1673    FD_SET(fd, &in_fds);
1674    if (fd > max_in_fd)
1675	max_in_fd = fd;
1676}
1677
1678/* -----------------------------------------------------------------------------
1679remove an fd from the set that wait_input waits for
1680----------------------------------------------------------------------------- */
1681void remove_fd(int fd)
1682{
1683    FD_CLR(fd, &in_fds);
1684}
1685
1686/* -----------------------------------------------------------------------------
1687return 1 is fd is set (i.e. select returned with this file descriptor set)
1688----------------------------------------------------------------------------- */
1689bool is_ready_fd(int fd)
1690{
1691    return (FD_ISSET(fd, &ready_fds) != 0);
1692}
1693
1694/* -----------------------------------------------------------------------------
1695get a PPP packet from the serial device
1696----------------------------------------------------------------------------- */
1697int read_packet(u_char *buf)
1698{
1699    int len = -1;
1700
1701    // FF03 are not read
1702    *buf++ = PPP_ALLSTATIONS;
1703    *buf++ = PPP_UI;
1704
1705    // read first the socket attached to the link
1706    if (ppp_fd >= 0) {
1707        if ((len = read(ppp_fd, buf, PPP_MRU + PPP_HDRLEN - 2)) < 0) {
1708            if (errno != EWOULDBLOCK && errno != EINTR)
1709                error("read from socket link: %m");
1710        }
1711    }
1712
1713    // then, if nothing, link the socket attached to the bundle
1714    if (len < 0 && ifunit >= 0) {
1715        if ((len = read(ppp_sockfd, buf, PPP_MRU + PPP_HDRLEN - 2)) < 0) {
1716            if (errno != EWOULDBLOCK && errno != EINTR)
1717                error("read from socket bundle: %m");
1718        }
1719    }
1720    return (len <= 0 ? len : len + 2);
1721}
1722
1723/* -----------------------------------------------------------------------------
1724 read characters from the loopback, form them
1725 * into frames, and detect when we want to bring the real link up.
1726 * Return value is 1 if we need to bring up the link, 0 otherwise
1727----------------------------------------------------------------------------- */
1728int get_loop_output()
1729{
1730    int rv = 0;
1731    int n;
1732
1733    while ((n = read_packet(inpacket_buf)) > 0)
1734        if (loop_frame(inpacket_buf, n))
1735            rv = 1;
1736    return rv;
1737}
1738
1739/* -----------------------------------------------------------------------------
1740configure the transmit characteristics of the ppp interface
1741 ----------------------------------------------------------------------------- */
1742void tty_send_config(int mtu, u_int32_t asyncmap, int pcomp, int accomp)
1743{
1744    u_int x;
1745
1746    if (!still_ppp())
1747	return;
1748
1749    if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0)
1750	fatal("ioctl(PPPIOCSASYNCMAP): %m");
1751
1752    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0)
1753	fatal("ioctl (PPPIOCGFLAGS): %m");
1754    x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
1755    x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
1756    x = sync_serial ? x | SC_SYNC : x & ~SC_SYNC;
1757    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
1758	fatal("ioctl(PPPIOCSFLAGS): %m");
1759
1760    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPCompressionPField, pcomp);
1761    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPCompressionACField, accomp);
1762    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPTransmitACCM, asyncmap);
1763}
1764
1765/* -----------------------------------------------------------------------------
1766configure the transmit characteristics of the ppp interface
1767function used for synchronous links, asyncmap is irrelevant
1768 ----------------------------------------------------------------------------- */
1769void generic_send_config(int mtu, u_int32_t asyncmap, int pcomp, int accomp)
1770{
1771    u_int x;
1772
1773    if (!still_ppp())
1774	return;
1775
1776    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0)
1777	fatal("ioctl (PPPIOCGFLAGS): %m");
1778    x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
1779    x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
1780    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
1781	fatal("ioctl(PPPIOCSFLAGS): %m");
1782
1783    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPCompressionPField, pcomp);
1784    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPCompressionACField, accomp);
1785}
1786
1787/* -----------------------------------------------------------------------------
1788set the MTU on the PPP network interface
1789----------------------------------------------------------------------------- */
1790void netif_set_mtu(int unit, int mtu)
1791{
1792    struct ifreq ifr;
1793
1794    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1795    ifr.ifr_mtu = mtu;
1796    if (ioctl(ip_sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
1797	error("ioctl (SIOCSIFMTU): %m");
1798
1799    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPMTU, mtu);
1800}
1801
1802/* -----------------------------------------------------------------------------
1803get the MTU on the PPP network interface
1804----------------------------------------------------------------------------- */
1805int netif_get_mtu(int unit)
1806{
1807    struct ifreq ifr;
1808
1809    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1810    if (ioctl(ip_sockfd, SIOCGIFMTU, (caddr_t) &ifr) < 0) {
1811	error("ioctl (SIOCGIFMTU): %m");
1812        return 0;
1813    }
1814    return ifr.ifr_mtu;
1815}
1816
1817
1818/* -----------------------------------------------------------------------------
1819stop traffic on this link
1820 ----------------------------------------------------------------------------- */
1821void ppp_hold(int unit)
1822{
1823    u_int x;
1824
1825    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
1826	warning("ioctl (PPPIOCGFLAGS): %m");
1827        return;
1828    }
1829    x |= SC_HOLD;
1830    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
1831	warning("ioctl(PPPIOCSFLAGS): %m");
1832}
1833
1834/* -----------------------------------------------------------------------------
1835resume traffic on this link
1836 ----------------------------------------------------------------------------- */
1837void ppp_cont(int unit)
1838{
1839    u_int x;
1840
1841    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
1842	warning("ioctl (PPPIOCGFLAGS): %m");
1843        return;
1844    }
1845    x &= ~SC_HOLD;
1846    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
1847	warning("ioctl(PPPIOCSFLAGS): %m");
1848}
1849
1850/* -----------------------------------------------------------------------------
1851set the extended transmit ACCM for the interface
1852----------------------------------------------------------------------------- */
1853void tty_set_xaccm(ext_accm accm)
1854{
1855    if (!still_ppp())
1856	return;
1857    if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
1858	warning("ioctl(set extended ACCM): %m");
1859}
1860
1861/* -----------------------------------------------------------------------------
1862configure the receive-side characteristics of the ppp interface.
1863----------------------------------------------------------------------------- */
1864void tty_recv_config(int mru, u_int32_t asyncmap, int pcomp, int accomp)
1865{
1866    int x;
1867
1868    if (!still_ppp())
1869	return;
1870
1871    if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
1872	fatal("ioctl(PPPIOCSMRU): %m");
1873    if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0)
1874	fatal("ioctl(PPPIOCSRASYNCMAP): %m");
1875    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0)
1876	fatal("ioctl (PPPIOCGFLAGS): %m");
1877    x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
1878    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
1879	fatal("ioctl(PPPIOCSFLAGS): %m");
1880
1881    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPMRU, mru);
1882    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPReceiveACCM, asyncmap);
1883}
1884
1885/* -----------------------------------------------------------------------------
1886configure the receive-side characteristics of the ppp interface.
1887function used for synchronous links, asyncmap is irrelevant
1888----------------------------------------------------------------------------- */
1889void generic_recv_config(int mru, u_int32_t asyncmap, int pcomp, int accomp)
1890{
1891    int x;
1892
1893    if (!still_ppp())
1894	return;
1895
1896    if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
1897	fatal("ioctl(PPPIOCSMRU): %m");
1898    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0)
1899	fatal("ioctl (PPPIOCGFLAGS): %m");
1900    x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
1901    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
1902	fatal("ioctl(PPPIOCSFLAGS): %m");
1903
1904    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPLCPMRU, mru);
1905}
1906
1907/* -----------------------------------------------------------------------------
1908ask kernel whether a given compression method
1909 * is acceptable for use.  Returns 1 if the method and parameters
1910 * are OK, 0 if the method is known but the parameters are not OK
1911 * (e.g. code size should be reduced), or -1 if the method is unknown
1912 ----------------------------------------------------------------------------- */
1913int ccp_test(int unit, u_char * opt_ptr, int opt_len, int for_transmit)
1914{
1915    struct ppp_option_data data;
1916
1917    data.ptr = opt_ptr;
1918    data.length = opt_len;
1919    data.transmit = for_transmit;
1920    if (ioctl(ppp_sockfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
1921	return 1;
1922    return (errno == ENOBUFS)? 0: -1;
1923}
1924
1925/* -----------------------------------------------------------------------------
1926inform kernel about the current state of CCP
1927----------------------------------------------------------------------------- */
1928void ccp_flags_set(int unit, int isopen, int isup)
1929{
1930    int x;
1931
1932    if (!still_ppp())
1933	return;
1934
1935    if (ioctl(ppp_sockfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
1936	error("ioctl (PPPIOCGFLAGS): %m");
1937	return;
1938    }
1939
1940    x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
1941    x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
1942    if (ioctl(ppp_sockfd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
1943	error("ioctl(PPPIOCSFLAGS): %m");
1944}
1945
1946/* -----------------------------------------------------------------------------
1947returns 1 if decompression was disabled as a
1948 * result of an error detected after decompression of a packet,
1949 * 0 otherwise.  This is necessary because of patent nonsense
1950 ----------------------------------------------------------------------------- */
1951int ccp_fatal_error(int unit)
1952{
1953    int x;
1954
1955    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
1956	error("ioctl(PPPIOCGFLAGS): %m");
1957	return 0;
1958    }
1959    return x & SC_DC_FERROR;
1960}
1961
1962/* -----------------------------------------------------------------------------
1963return how long the link has been idle
1964----------------------------------------------------------------------------- */
1965int get_idle_time(int u, struct ppp_idle *ip)
1966{
1967    return ioctl(ppp_sockfd, PPPIOCGIDLE, ip) >= 0;
1968}
1969
1970/* -----------------------------------------------------------------------------
1971return statistics for the link
1972----------------------------------------------------------------------------- */
1973int get_ppp_stats(int u, struct pppd_stats *stats)
1974{
1975    struct ifpppstatsreq req;
1976
1977    memset (&req, 0, sizeof (req));
1978    strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name));
1979    if (ioctl(ip_sockfd, SIOCGPPPSTATS, &req) < 0) {
1980	error("Couldn't get PPP statistics: %m");
1981	return 0;
1982    }
1983    stats->bytes_in = req.stats.p.ppp_ibytes;
1984    stats->bytes_out = req.stats.p.ppp_obytes;
1985    stats->pkts_in = req.stats.p.ppp_ipackets;
1986    stats->pkts_out = req.stats.p.ppp_opackets;
1987    return 1;
1988}
1989
1990
1991#ifdef PPP_FILTER
1992/* -----------------------------------------------------------------------------
1993transfer the pass and active filters to the kernel
1994----------------------------------------------------------------------------- */
1995int set_filters(struct bpf_program *pass, struct bpf_program *active)
1996{
1997    int ret = 1;
1998
1999    if (pass->bf_len > 0) {
2000	if (ioctl(ppp_fd, PPPIOCSPASS, pass) < 0) {
2001	    error("Couldn't set pass-filter in kernel: %m");
2002	    ret = 0;
2003	}
2004    }
2005    if (active->bf_len > 0) {
2006	if (ioctl(ppp_fd, PPPIOCSACTIVE, active) < 0) {
2007	    error("Couldn't set active-filter in kernel: %m");
2008	    ret = 0;
2009	}
2010    }
2011    return ret;
2012}
2013#endif
2014
2015/* -----------------------------------------------------------------------------
2016config tcp header compression
2017----------------------------------------------------------------------------- */
2018int sifvjcomp(int u, int vjcomp, int cidcomp, int maxcid)
2019{
2020    u_int x;
2021
2022    if (ioctl(ppp_sockfd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
2023	error("ioctl (PPPIOCGFLAGS): %m");
2024	return 0;
2025    }
2026    x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
2027    x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
2028    if (ioctl(ppp_sockfd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
2029	error("ioctl(PPPIOCSFLAGS): %m");
2030	return 0;
2031    }
2032    if (vjcomp && ioctl(ppp_sockfd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
2033	error("ioctl(PPPIOCSMAXCID): %m");
2034	return 0;
2035    }
2036    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPIPCPCompressionVJ, vjcomp);
2037    return 1;
2038}
2039
2040/* -----------------------------------------------------------------------------
2041Config the interface up and enable IP packets to pass
2042----------------------------------------------------------------------------- */
2043int sifup(int u)
2044{
2045    struct ifreq ifr;
2046
2047    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
2048    if (ioctl(ip_sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
2049	error("ioctl (SIOCGIFFLAGS): %m");
2050	return 0;
2051    }
2052    ifr.ifr_flags |= IFF_UP;
2053    if (ioctl(ip_sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
2054	error("ioctl(SIOCSIFFLAGS): %m");
2055	return 0;
2056    }
2057    if_is_up = 1;
2058    return 1;
2059}
2060
2061/* -----------------------------------------------------------------------------
2062Set the mode for handling packets for a given NP
2063----------------------------------------------------------------------------- */
2064int sifnpmode(int u, int proto, enum NPmode mode)
2065{
2066    struct npioctl npi;
2067
2068    npi.protocol = proto;
2069    npi.mode = mode;
2070    if (ioctl(ppp_sockfd, PPPIOCSNPMODE, &npi) < 0) {
2071	error("ioctl(set NP %d mode to %d): %m", proto, mode);
2072	return 0;
2073    }
2074    return 1;
2075}
2076
2077/* -----------------------------------------------------------------------------
2078Set the mode for filtering protocol addresses
2079----------------------------------------------------------------------------- */
2080int sifnpafmode(int u, int proto, enum NPAFmode mode)
2081{
2082    struct npafioctl npi;
2083
2084    npi.protocol = proto;
2085    npi.mode = mode;
2086    if (ioctl(ppp_sockfd, PPPIOCSNPAFMODE, &npi) < 0) {
2087	error("ioctl(set NPAF %d mode to %d): %m", proto, mode);
2088	return 0;
2089    }
2090    return 1;
2091}
2092
2093/* -----------------------------------------------------------------------------
2094Config the interface down
2095----------------------------------------------------------------------------- */
2096int sifdown(int u)
2097{
2098    struct ifreq ifr;
2099    int rv;
2100    struct npioctl npi;
2101
2102    npi.protocol = PPP_IP;
2103    if ((ioctl(ppp_sockfd, PPPIOCGNPMODE, (caddr_t) &npi) == 0)
2104        && (npi.mode != NPMODE_DROP)) {
2105        return 0;
2106    }
2107
2108    npi.protocol = PPP_IPV6;
2109    if ((ioctl(ppp_sockfd, PPPIOCGNPMODE, (caddr_t) &npi) == 0)
2110        && (npi.mode != NPMODE_DROP)) {
2111        return 0;
2112    }
2113
2114    /* ipv4 and ipv4 are both down. take the interface down now */
2115
2116    rv = 1;
2117
2118    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
2119    if (ioctl(ip_sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
2120	error("ioctl (SIOCGIFFLAGS): %m");
2121	rv = 0;
2122    } else {
2123	ifr.ifr_flags &= ~IFF_UP;
2124	if (ioctl(ip_sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
2125	    error("ioctl(SIOCSIFFLAGS): %m");
2126	    rv = 0;
2127	} else
2128	    if_is_up = 0;
2129    }
2130    return rv;
2131}
2132
2133
2134/* -----------------------------------------------------------------------------
2135set the route for the interface.
2136----------------------------------------------------------------------------- */
2137int sifroute(int u, u_int32_t o, u_int32_t h, u_int32_t m)
2138{
2139	if (addifroute && m != 0xFFFFFFFF) {
2140		ifroute_address.s_addr = o & m;
2141		ifroute_mask.s_addr = m;
2142		ifroute_installed = route_interface(RTM_ADD, ifroute_address, ifroute_mask, IFT_PPP, ifname, 0);
2143	}
2144
2145	return 1;
2146}
2147
2148/* -----------------------------------------------------------------------------
2149clear the route for the interface.
2150----------------------------------------------------------------------------- */
2151int cifroute()
2152{
2153	if (addifroute && ifroute_installed) {
2154		route_interface(RTM_DELETE, ifroute_address, ifroute_mask, IFT_PPP, ifname, 0);
2155		ifroute_installed = 0;
2156	}
2157
2158	return 1;
2159}
2160
2161/* -----------------------------------------------------------------------------
2162set the sa_family field of a struct sockaddr, if it exists.
2163----------------------------------------------------------------------------- */
2164#define SET_SA_FAMILY(addr, family)		\
2165    BZERO((char *) &(addr), sizeof(addr));	\
2166    addr.sa_family = (family); 			\
2167    addr.sa_len = sizeof(addr);
2168
2169/* -----------------------------------------------------------------------------
2170Config the interface IP addresses and netmask
2171----------------------------------------------------------------------------- */
2172int sifaddr(int u, u_int32_t o, u_int32_t h, u_int32_t m)
2173{
2174    struct ifaliasreq ifra __attribute__ ((aligned (4)));		// Wcast-align fix - force alignment
2175    struct ifreq ifr;
2176
2177// XXX from sys/sockio.h
2178#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq)    /* attach proto to interface */
2179#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq)    /* detach proto from interface */
2180
2181    // first plumb ip over ppp
2182    if (ipv4_plumbed == 0) {
2183        strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
2184        if (ioctl(ip_sockfd, SIOCPROTOATTACH, (caddr_t) &ifr) < 0) {
2185            error("Couldn't plumb IP to the interface: %d %m", errno);
2186            //return 0;
2187        }
2188        ipv4_plumbed = 1;
2189    }
2190
2191    strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
2192    SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
2193    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
2194    SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
2195    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
2196    if (m != 0) {
2197        SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
2198        (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
2199    } else
2200        BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
2201        BZERO(&ifr, sizeof(ifr));
2202        strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2203        if (ioctl(ip_sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) {
2204            if (errno != EADDRNOTAVAIL)
2205	    warning("Couldn't remove interface address: %m");
2206    }
2207    if (ioctl(ip_sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
2208	if (errno != EEXIST) {
2209	    error("Couldn't set interface address: %m");
2210	    return 0;
2211	}
2212	warning("Couldn't set interface address: Address %I already exists", o);
2213    }
2214    ifaddrs[0] = o;
2215    ifaddrs[1] = h;
2216
2217    if (looplocal) {
2218	struct in_addr o1;
2219        struct in_addr mask;
2220
2221        set_flags(ppp_sockfd, get_flags(ppp_sockfd) | SC_LOOP_LOCAL);
2222        // add a route for our local address via our interface
2223        o1.s_addr = o;
2224        mask.s_addr = 0;
2225        route_interface(RTM_ADD, o1, mask, IFT_PPP, ifname, 1);
2226    }
2227
2228	sifroute(u, o, h, m);
2229
2230    publish_stateaddr(o, h, m);
2231
2232	return 1;
2233}
2234
2235/* -----------------------------------------------------------------------------
2236 Update the interface IP addresses and netmask
2237 ----------------------------------------------------------------------------- */
2238int uifaddr(int u, u_int32_t o, u_int32_t h, u_int32_t m)
2239{
2240    struct ifaliasreq ifra __attribute__ ((aligned (4)));	// Wcast-align fix - force alignment
2241    struct ifreq ifr;
2242
2243    cifroute();
2244
2245	// XXX from sys/sockio.h
2246#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq)    /* attach proto to interface */
2247#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq)    /* detach proto from interface */
2248
2249    // first plumb ip over ppp
2250    if (ipv4_plumbed == 0) {
2251		error("Interface should have been plumbed already");
2252		return -1;
2253    }
2254
2255    strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
2256    SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
2257    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
2258    SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
2259    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
2260    if (m != 0) {
2261		SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
2262		(ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
2263    } else
2264		BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
2265    BZERO(&ifr, sizeof(ifr));
2266    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2267    if (ioctl(ip_sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) {
2268		if (errno != EADDRNOTAVAIL)
2269			warning("Couldn't remove interface address: %m");
2270    }
2271    if (ioctl(ip_sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
2272		if (errno != EEXIST) {
2273			error("Couldn't set interface address: %m");
2274			return 0;
2275		}
2276		warning("Couldn't set interface address: Address %I already exists", o);
2277    }
2278    ifaddrs[0] = o;
2279    ifaddrs[1] = h;
2280
2281	sifroute(u, o, h, m);
2282
2283    update_stateaddr(o, h, m);
2284
2285	return 1;
2286}
2287
2288/* -----------------------------------------------------------------------------
2289Clear the interface IP addresses, and delete routes
2290 * through the interface if possible
2291 ----------------------------------------------------------------------------- */
2292int cifaddr(int u, u_int32_t o, u_int32_t h)
2293{
2294    //struct ifreq ifr;
2295    struct ifaliasreq ifra __attribute__ ((aligned (4)));		// Wcast-align fix - force alignment
2296
2297// XXX from sys/sockio.h
2298#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq)    /* attach proto to interface */
2299#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq)    /* detach proto from interface */
2300
2301	cifroute();
2302
2303    ifaddrs[0] = 0;
2304    strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
2305    SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
2306    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
2307    SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
2308    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
2309    BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
2310    if (ioctl(ip_sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
2311	if (errno != EADDRNOTAVAIL)
2312	    warning("Couldn't delete interface address: %m");
2313	return 0;
2314    }
2315
2316#if 0
2317    // unplumb ip from ppp
2318    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
2319    if (ioctl(ip_sockfd, SIOCPROTODETACH, (caddr_t) &ifr) < 0) {
2320        error("Couldn't unplumb IP from the interface: %m");
2321	return 0;
2322    }
2323#endif
2324
2325    unpublish_dict(kSCEntNetIPv4);
2326
2327    return 1;
2328}
2329
2330#ifdef INET6
2331/* -----------------------------------------------------------------------------
2332Config the interface IPv6 addresses
2333----------------------------------------------------------------------------- */
2334int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
2335{
2336    int ifindex, s;
2337    struct in6_ifreq ifr6;
2338    struct in6_aliasreq addreq6 __attribute__ ((aligned (4)));		// Wcast-align fix - force alignment
2339
2340// XXX from sys/sockio.h
2341#define SIOCPROTOATTACH_IN6 _IOWR('i', 110, struct in6_aliasreq)    /* attach proto to interface */
2342#define SIOCPROTODETACH_IN6 _IOWR('i', 111, struct in6_ifreq)    /* detach proto from interface */
2343#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq)    /* attach proto to interface */
2344#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq)    /* detach proto from interface */
2345#define SIOCLL_START _IOWR('i', 130, struct in6_aliasreq)    /* start aquiring linklocal on interface */
2346#define SIOCLL_STOP _IOWR('i', 131, struct in6_ifreq)    /* deconfigure linklocal from interface */
2347
2348    s = socket(AF_INET6, SOCK_DGRAM, 0);
2349    if (s < 0) {
2350        error("Can't create IPv6 socket: %m");
2351        return 0;
2352    }
2353
2354    /* actually, this part is not kame local - RFC2553 conformant */
2355    ifindex = if_nametoindex(ifname);
2356    if (ifindex == 0) {
2357        error("sifaddr6: no interface %s", ifname);
2358        close(s);
2359        return 0;
2360    }
2361
2362    strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
2363    if (ioctl(s, SIOCPROTOATTACH_IN6, &ifr6) < 0) {
2364        error("sif6addr: can't attach IPv6 protocol: %m");
2365        close(s);
2366        return 0;
2367    }
2368
2369    memset(&addreq6, 0, sizeof(addreq6));
2370    strlcpy(addreq6.ifra_name, ifname, sizeof(addreq6.ifra_name));
2371
2372    /* my addr */
2373    addreq6.ifra_addr.sin6_family = AF_INET6;
2374    addreq6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
2375    addreq6.ifra_addr.sin6_addr.s6_addr[0] = 0xfe;
2376    addreq6.ifra_addr.sin6_addr.s6_addr[1] = 0x80;
2377    memcpy(&addreq6.ifra_addr.sin6_addr.s6_addr[8], &our_eui64,
2378	sizeof(our_eui64));
2379    /* KAME ifindex hack */
2380    *ALIGNED_CAST(u_int16_t *)&addreq6.ifra_addr.sin6_addr.s6_addr[2] = htons(ifindex);
2381
2382    /* his addr */
2383    addreq6.ifra_dstaddr.sin6_family = AF_INET6;
2384    addreq6.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
2385    addreq6.ifra_dstaddr.sin6_addr.s6_addr[0] = 0xfe;
2386    addreq6.ifra_dstaddr.sin6_addr.s6_addr[1] = 0x80;
2387    memcpy(&addreq6.ifra_dstaddr.sin6_addr.s6_addr[8], &his_eui64,
2388	sizeof(our_eui64));
2389    /* KAME ifindex hack */
2390    *ALIGNED_CAST(u_int16_t *)&addreq6.ifra_dstaddr.sin6_addr.s6_addr[2] = htons(ifindex);
2391
2392    /* prefix mask: 128bit */
2393    addreq6.ifra_prefixmask.sin6_family = AF_INET6;
2394    addreq6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
2395    memset(&addreq6.ifra_prefixmask.sin6_addr, 0xff,
2396	sizeof(addreq6.ifra_prefixmask.sin6_addr));
2397
2398    /* address lifetime (infty) */
2399    addreq6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
2400    addreq6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
2401
2402    if (ioctl(s, SIOCLL_START, &addreq6) < 0) {
2403        error("sif6addr: can't set LL address: %m");
2404        close(s);
2405        return 0;
2406    }
2407
2408    close(s);
2409
2410    return 1;
2411}
2412
2413/* -----------------------------------------------------------------------------
2414Clear the interface IPv6 addresses
2415 ----------------------------------------------------------------------------- */
2416int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
2417{
2418    int s;
2419    struct ifreq ifr;
2420    struct in6_ifreq ifr6;
2421
2422// XXX from sys/sockio.h
2423#define SIOCPROTOATTACH_IN6 _IOWR('i', 110, struct in6_aliasreq)    /* attach proto to interface */
2424#define SIOCPROTODETACH_IN6 _IOWR('i', 111, struct in6_ifreq)    /* detach proto from interface */
2425#define SIOCPROTOATTACH _IOWR('i', 80, struct ifreq)    /* attach proto to interface */
2426#define SIOCPROTODETACH _IOWR('i', 81, struct ifreq)    /* detach proto from interface */
2427#define SIOCLL_START _IOWR('i', 130, struct in6_aliasreq)    /* start aquiring linklocal on interface */
2428#define SIOCLL_STOP _IOWR('i', 131, struct in6_ifreq)    /* deconfigure linklocal from interface */
2429
2430    s = socket(AF_INET6, SOCK_DGRAM, 0);
2431    if (s < 0) {
2432        error("Can't create IPv6 socket: %m");
2433        return 0;
2434    }
2435
2436    /* first try old ioctl */
2437    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2438    if (ioctl(s, SIOCPROTODETACH, &ifr) < 0) {
2439        /* then new ioctl */
2440        strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
2441        if (ioctl(s, SIOCLL_STOP, &ifr6) < 0) {
2442            warning("Can't stop LL address: %m");
2443        }
2444        strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
2445        if (ioctl(s, SIOCPROTODETACH_IN6, &ifr6) < 0) {
2446            warning("Can't detach IPv6 protocol: %m");
2447        }
2448
2449        close(s);
2450        return 0;
2451    }
2452
2453    close(s);
2454
2455    return 1;
2456}
2457
2458/* -----------------------------------------------------------------------------
2459Returns an iterator containing the primary (built-in) Ethernet interface.
2460The caller is responsible for releasing the iterator after the caller is done with it.
2461 ----------------------------------------------------------------------------- */
2462static kern_return_t FindPrimaryEthernetInterfaces(io_iterator_t *matchingServices)
2463{
2464    kern_return_t  kernResult;
2465    CFMutableDictionaryRef matchingDict;
2466    CFMutableDictionaryRef propertyMatchDict;
2467
2468    // Ethernet interfaces are instances of class kIOEthernetInterfaceClass.
2469    // IOServiceMatching is a convenience function to create a dictionary with the key kIOProviderClassKey and
2470    // the specified value.
2471    matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);
2472    if (matchingDict) {
2473
2474        // Each IONetworkInterface object has a Boolean property with the key kIOPrimaryInterface. Only the
2475        // primary (built-in) interface has this property set to TRUE.
2476
2477        // IOServiceGetMatchingServices uses the default matching criteria defined by IOService. This considers
2478        // only the following properties plus any family-specific matching in this order of precedence
2479        // (see IOService::passiveMatch):
2480        //
2481        // kIOProviderClassKey (IOServiceMatching)
2482        // kIONameMatchKey (IOServiceNameMatching)
2483        // kIOPropertyMatchKey
2484        // kIOPathMatchKey
2485        // kIOMatchedServiceCountKey
2486        // family-specific matching
2487        // kIOBSDNameKey (IOBSDNameMatching)
2488        // kIOLocationMatchKey
2489
2490        // The IONetworkingFamily does not define any family-specific matching. This means that in
2491        // order to have IOServiceGetMatchingServices consider the kIOPrimaryInterface property, we must
2492        // add that property to a separate dictionary and then add that to our matching dictionary
2493        // specifying kIOPropertyMatchKey.
2494
2495        propertyMatchDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
2496                                                       &kCFTypeDictionaryKeyCallBacks,
2497                                                       &kCFTypeDictionaryValueCallBacks);
2498        if (propertyMatchDict) {
2499
2500            // Set the value in the dictionary of the property with the given key, or add the key
2501            // to the dictionary if it doesn't exist. This call retains the value object passed in.
2502            CFDictionarySetValue(propertyMatchDict, CFSTR(kIOPrimaryInterface), kCFBooleanTrue);
2503
2504            // Now add the dictionary containing the matching value for kIOPrimaryInterface to our main
2505            // matching dictionary. This call will retain propertyMatchDict, so we can release our reference
2506            // on propertyMatchDict after adding it to matchingDict.
2507            CFDictionarySetValue(matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
2508            CFRelease(propertyMatchDict);
2509        }
2510    }
2511
2512    // IOServiceGetMatchingServices retains the returned iterator, so release the iterator when we're done with it.
2513    // IOServiceGetMatchingServices also consumes a reference on the matching dictionary so we don't need to release
2514    // the dictionary explicitly.
2515    kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, matchingServices);
2516
2517    return kernResult;
2518}
2519
2520/* -----------------------------------------------------------------------------
2521Get the mac address of the primary interface
2522----------------------------------------------------------------------------- */
2523static kern_return_t GetPrimaryMACAddress(UInt8 *MACAddress)
2524{
2525    io_object_t  intfService;
2526    io_object_t  controllerService;
2527    kern_return_t kernResult = KERN_FAILURE;
2528    io_iterator_t intfIterator;
2529
2530    kernResult = FindPrimaryEthernetInterfaces(&intfIterator);
2531    if (kernResult != KERN_SUCCESS)
2532        return kernResult;
2533
2534    // Initialize the returned address
2535    bzero(MACAddress, kIOEthernetAddressSize);
2536
2537    // IOIteratorNext retains the returned object, so release it when we're done with it.
2538    while ((intfService = IOIteratorNext(intfIterator))) {
2539
2540        CFTypeRef MACAddressAsCFData;
2541
2542        // IONetworkControllers can't be found directly by the IOServiceGetMatchingServices call,
2543        // since they are hardware nubs and do not participate in driver matching. In other words,
2544        // registerService() is never called on them. So we've found the IONetworkInterface and will
2545        // get its parent controller by asking for it specifically.
2546
2547        // IORegistryEntryGetParentEntry retains the returned object, so release it when we're done with it.
2548        kernResult = IORegistryEntryGetParentEntry( intfService,
2549                                                    kIOServicePlane,
2550                                                    &controllerService );
2551
2552        if (kernResult == KERN_SUCCESS) {
2553
2554            // Retrieve the MAC address property from the I/O Registry in the form of a CFData
2555            MACAddressAsCFData = IORegistryEntryCreateCFProperty( controllerService,
2556                                                                  CFSTR(kIOMACAddress),
2557                                                                  kCFAllocatorDefault, 0);
2558            if (MACAddressAsCFData) {
2559                // Get the raw bytes of the MAC address from the CFData
2560                CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
2561                CFRelease(MACAddressAsCFData);
2562            }
2563
2564            // Done with the parent Ethernet controller object so we release it.
2565            IOObjectRelease(controllerService);
2566        }
2567
2568        // Done with the Ethernet interface object so we release it.
2569        IOObjectRelease(intfService);
2570    }
2571
2572    IOObjectRelease(intfIterator);
2573
2574    return kernResult;
2575}
2576
2577/* -----------------------------------------------------------------------------
2578Convert 48-bit Ethernet address into 64-bit EUI
2579 ----------------------------------------------------------------------------- */
2580int
2581ether_to_eui64(eui64_t *p_eui64)
2582{
2583    static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
2584    static u_int8_t allone[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2585    kern_return_t err;
2586    UInt8  addr[kIOEthernetAddressSize];
2587
2588    err = GetPrimaryMACAddress(addr);
2589    if (err != KERN_SUCCESS) {
2590        warning("Can't get hardware interface address for en0 (error = %d)\n", err);
2591        return 0;
2592    }
2593
2594    /* check for invalid MAC address */
2595     if (bcmp(addr, allzero, ETHER_ADDR_LEN) == 0)
2596            return 0;
2597    if (bcmp(addr, allone, ETHER_ADDR_LEN) == 0)
2598            return 0;
2599
2600    /* And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1] */
2601    p_eui64->e8[0] = addr[0] | 0x02;
2602    p_eui64->e8[1] = addr[1];
2603    p_eui64->e8[2] = addr[2];
2604    p_eui64->e8[3] = 0xFF;
2605    p_eui64->e8[4] = 0xFE;
2606    p_eui64->e8[5] = addr[3];
2607    p_eui64->e8[6] = addr[4];
2608    p_eui64->e8[7] = addr[5];
2609
2610    return 1;
2611}
2612
2613#endif
2614
2615/* ----------------------------------------------------------------------------
2616 Create a "NULL Service" primary IPv6 dictionary for the dynamic store. This
2617 prevents any other service from becoming primary on IPv6.
2618 ----------------------------------------------------------------------------- */
2619#ifndef kIsNULL
2620#define kIsNULL		CFSTR("IsNULL") /* CFBoolean */
2621#endif
2622void ppp_create_ipv6_dummy_primary(Boolean uninstall)
2623{
2624    CFMutableArrayRef		array;
2625    CFMutableDictionaryRef	ipv6_dict;
2626    int						isprimary = 1;
2627    CFStringRef				key;
2628    CFNumberRef				num;
2629    CFStringRef				str;
2630
2631    if (noipv6override || cfgCache == NULL || serviceidRef == NULL)
2632        return;
2633
2634    if ((key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, kSCEntNetIPv6))) {
2635        if (uninstall) {
2636            unpublish_dict(key);
2637        } else {
2638            /* create the IPv6 dictionnary */
2639            if ((ipv6_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) {
2640                if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) {
2641                    CFArrayAppendValue(array, CFSTR("::1"));
2642                    CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Addresses, array);
2643                    CFRelease(array);
2644                }
2645
2646                CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Router, CFSTR("::1"));
2647
2648                num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &isprimary);
2649                if (num) {
2650                    CFDictionarySetValue(ipv6_dict, kSCPropNetOverridePrimary, num);
2651                    CFRelease(num);
2652                }
2653
2654                CFDictionarySetValue(ipv6_dict, kIsNULL, kCFBooleanTrue);
2655
2656                if (ifname) {
2657                    if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), ifname))) {
2658                        CFDictionarySetValue(ipv6_dict, kSCPropInterfaceName, str);
2659                        CFRelease(str);
2660                    }
2661                }
2662
2663                update_publish_dict(key, ipv6_dict);
2664                CFRelease(ipv6_dict);
2665            }
2666        }
2667
2668        CFRelease(key);
2669    }
2670
2671    return;
2672}
2673
2674/* -----------------------------------------------------------------------------
2675assign a default route through the address given
2676----------------------------------------------------------------------------- */
2677int sifdefaultroute(int u, u_int32_t l, u_int32_t g)
2678{
2679    override_primary = 1;
2680    ppp_create_ipv6_dummy_primary(FALSE);
2681    return publish_dictnumentry(kSCEntNetIPv4, kSCPropNetOverridePrimary, 1);
2682}
2683
2684/* -----------------------------------------------------------------------------
2685delete a default route through the address given
2686----------------------------------------------------------------------------- */
2687int cifdefaultroute(int u, u_int32_t l, u_int32_t g)
2688{
2689    override_primary = 0;
2690    ppp_create_ipv6_dummy_primary(TRUE);
2691    return unpublish_dictentry(kSCEntNetIPv4, kSCPropNetOverridePrimary);
2692}
2693
2694/* ----------------------------------------------------------------------------
2695 update ip addresses using configd cache mechanism
2696 use new state information model
2697 ----------------------------------------------------------------------------- */
2698static int update_stateaddr(u_int32_t o, u_int32_t h, u_int32_t m)
2699{
2700    struct in_addr             addr;
2701    CFMutableArrayRef          array;
2702    CFMutableDictionaryRef     ipv4_dict;
2703    CFStringRef                        str;
2704    CFStringRef                        key;
2705
2706    // ppp daemons without services are not published in the cache
2707    if (cfgCache == NULL)
2708        return 0;
2709
2710    /* update the store now */
2711    if ((key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, kSCEntNetIPv4))) {
2712        CFPropertyListRef ref;
2713        if (publish_dict != NULL) {
2714            ref = CFDictionaryGetValue(publish_dict, key);
2715            if (ref) {
2716                CFRetain(ref);
2717            }
2718        } else {
2719            ref = SCDynamicStoreCopyValue(cfgCache, key);
2720        }
2721
2722        if (ref == NULL ||
2723            CFGetTypeID(ref) != CFDictionaryGetTypeID()) {
2724            warning("SCDynamicStoreCopyValue IP %s failed: %s\n", ifname, SCErrorString(SCError()));
2725            if (ref) {
2726                CFRelease(ref);
2727            }
2728            CFRelease(key);
2729            return 0;
2730        }
2731        ipv4_dict = CFDictionaryCreateMutableCopy(NULL, 0, ref);
2732        CFRelease(ref);
2733        if (!ipv4_dict || CFGetTypeID(ipv4_dict) != CFDictionaryGetTypeID()) {
2734            warning("CFDictionaryCreateMutableCopy IP %s failed: %s\n", ifname, SCErrorString(SCError()));
2735            if (ipv4_dict) {
2736                CFRelease(ipv4_dict);
2737            }
2738            CFRelease(key);
2739            return 0;
2740        }
2741    } else {
2742        return 0;
2743    }
2744
2745    /* set the ip address src and dest arrays */
2746    if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) {
2747        addr.s_addr = o;
2748        if ((str = CFStringCreateWithFormat(0, 0, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
2749            CFArrayAppendValue(array, str);
2750            CFRelease(str);
2751            CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Addresses, array);
2752        }
2753        CFRelease(array);
2754    }
2755
2756    if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) {
2757        addr.s_addr = h;
2758        if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
2759            CFArrayAppendValue(array, str);
2760            CFRelease(str);
2761            CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4DestAddresses, array);
2762        }
2763        CFRelease(array);
2764    }
2765
2766    /* set the router */
2767    addr.s_addr = o;
2768    if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
2769        CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Router, str);
2770        CFRelease(str);
2771    }
2772
2773    /* add the interface name */
2774    if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), ifname))) {
2775        CFDictionarySetValue(ipv4_dict, kSCPropInterfaceName, str);
2776        CFRelease(str);
2777    }
2778
2779    /* add the network signature */
2780    if (network_signature) {
2781               if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), network_signature))) {
2782                       CFDictionarySetValue(ipv4_dict, CFSTR("NetworkSignature"), str);
2783                       CFRelease(str);
2784               }
2785       }
2786
2787    /* add the remote server peer address */
2788    if (server_peer) {
2789        CFDictionarySetValue(ipv4_dict, CFSTR("ServerAddress"), server_peer);
2790    }
2791
2792
2793	if (update_publish_dict(key, ipv4_dict) == 0)
2794        warning("SCDynamicStoreSetValue IP %s failed: %s\n", ifname, SCErrorString(SCError()));
2795
2796    CFRelease(ipv4_dict);
2797    CFRelease(key);
2798    return 1;
2799}
2800
2801/* ----------------------------------------------------------------------------
2802publish ip addresses using configd cache mechanism
2803use new state information model
2804----------------------------------------------------------------------------- */
2805int publish_stateaddr(u_int32_t o, u_int32_t h, u_int32_t m)
2806{
2807    struct in_addr		addr;
2808    CFMutableArrayRef		array;
2809    CFMutableDictionaryRef	ipv4_dict;
2810    CFStringRef			str;
2811
2812    // ppp daemons without services are not published in the cache
2813    if (cfgCache == NULL)
2814        return 0;
2815
2816    /* create the IPV4 dictionnary */
2817    if ((ipv4_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
2818        return 0;
2819
2820   /* set the ip address src and dest arrays */
2821    if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) {
2822        addr.s_addr = o;
2823        if ((str = CFStringCreateWithFormat(0, 0, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
2824            CFArrayAppendValue(array, str);
2825            CFRelease(str);
2826            CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Addresses, array);
2827        }
2828        CFRelease(array);
2829    }
2830
2831    if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) {
2832        addr.s_addr = h;
2833        if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
2834            CFArrayAppendValue(array, str);
2835            CFRelease(str);
2836            CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4DestAddresses, array);
2837        }
2838        CFRelease(array);
2839    }
2840
2841    /* set the router */
2842    addr.s_addr = o;
2843    if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
2844        CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Router, str);
2845        CFRelease(str);
2846    }
2847
2848    /* add the interface name */
2849    if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), ifname))) {
2850        CFDictionarySetValue(ipv4_dict, kSCPropInterfaceName, str);
2851        CFRelease(str);
2852    }
2853
2854    /* add the network signature */
2855    if (network_signature) {
2856		if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), network_signature))) {
2857			CFDictionarySetValue(ipv4_dict, CFSTR("NetworkSignature"), str);
2858			CFRelease(str);
2859		}
2860	}
2861
2862    /* add the remote server peer address */
2863    if (server_peer) {
2864        CFDictionarySetValue(ipv4_dict, CFSTR("ServerAddress"), server_peer);
2865    }
2866
2867    /* update the store now */
2868    if ((str = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, kSCEntNetIPv4))) {
2869
2870		if (update_publish_dict(str, ipv4_dict) == 0)
2871            warning("SCDynamicStoreSetValue IP %s failed: %s\n", ifname, SCErrorString(SCError()));
2872
2873        CFRelease(str);
2874    }
2875
2876    CFRelease(ipv4_dict);
2877    return 1;
2878}
2879
2880/* -----------------------------------------------------------------------------
2881 add a search domain, using configd cache mechanism.
2882----------------------------------------------------------------------------- */
2883int publish_dns_wins_entry(CFStringRef entity, CFStringRef property1, CFTypeRef ref1, CFTypeRef ref1a,
2884						CFStringRef property2, CFTypeRef ref2,
2885						CFStringRef property3, CFTypeRef ref3, int clean)
2886{
2887    CFMutableArrayRef		mutable_array;
2888    CFArrayRef			array = NULL;
2889    CFMutableDictionaryRef	dict = NULL;
2890    CFStringRef			key = NULL;
2891    CFPropertyListRef		ref;
2892    int				ret = 0;
2893
2894    if (publish_dict == NULL && cfgCache == NULL)
2895        return 0;
2896
2897    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, entity);
2898    if (!key)
2899        goto end;
2900
2901    if (publish_dict) {
2902        if ((ref = CFDictionaryGetValue(publish_dict, key))) {
2903            dict = CFDictionaryCreateMutableCopy(0, 0, ref);
2904        }
2905        else
2906            dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2907    }
2908    else if ((ref = SCDynamicStoreCopyValue(cfgCache, key))) {
2909        dict = CFDictionaryCreateMutableCopy(0, 0, ref);
2910        CFRelease(ref);
2911    } else
2912        dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2913
2914    if (!dict || (CFGetTypeID(dict) != CFDictionaryGetTypeID()))
2915        goto end;
2916
2917    if (!clean)
2918        array = CFDictionaryGetValue(dict, property1);
2919    if (array && (CFGetTypeID(array) == CFArrayGetTypeID()))
2920        mutable_array = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(array) + 1, array);
2921    else
2922        mutable_array = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
2923
2924    if (!mutable_array)
2925        goto end;
2926
2927    CFArrayAppendValue(mutable_array, ref1);
2928	if (ref1a)
2929		CFArrayAppendValue(mutable_array, ref1a);
2930    CFDictionarySetValue(dict, property1, mutable_array);
2931    CFRelease(mutable_array);
2932
2933    if (property2) {
2934		if (!clean)
2935			array = CFDictionaryGetValue(dict, property2);
2936		if (array && (CFGetTypeID(array) == CFArrayGetTypeID()))
2937			mutable_array = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(array) + 1, array);
2938		else
2939			mutable_array = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
2940
2941		if (!mutable_array)
2942			goto end;
2943
2944		CFArrayAppendValue(mutable_array, ref2);
2945		CFDictionarySetValue(dict, property2, mutable_array);
2946		CFRelease(mutable_array);
2947    }
2948
2949    if (property3) {
2950		if (!clean)
2951			array = CFDictionaryGetValue(dict, property3);
2952		if (array && (CFGetTypeID(array) == CFArrayGetTypeID()))
2953			mutable_array = CFArrayCreateMutableCopy(NULL, CFArrayGetCount(array) + 1, array);
2954		else
2955			mutable_array = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
2956
2957		if (!mutable_array)
2958			goto end;
2959
2960		CFArrayAppendValue(mutable_array, ref3);
2961		CFDictionarySetValue(dict, property3, mutable_array);
2962		CFRelease(mutable_array);
2963    }
2964
2965	if (update_publish_dict(key,dict))
2966        ret = 1;
2967    else
2968        warning("SCDynamicStoreSetValue DNS/WINS %s failed: %s\n", ifname, SCErrorString(SCError()));
2969
2970end:
2971    if (key)
2972        CFRelease(key);
2973    if (dict)
2974        CFRelease(dict);
2975    return ret;
2976}
2977
2978
2979/* -----------------------------------------------------------------------------
2980set dns information
2981----------------------------------------------------------------------------- */
2982int sifdns(u_int32_t dns1, u_int32_t dns2)
2983{
2984    CFStringRef		str1 = 0, str2 = 0, strname = 0;
2985    int				result = 0, clean = 1;
2986	long			order = 100000;
2987	CFNumberRef		num = 0;
2988
2989	num = CFNumberCreate(NULL, kCFNumberLongType, &order);
2990	if (!num)
2991		goto done;
2992
2993	strname = CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8);
2994	if (!strname)
2995		goto done;
2996
2997	/* warn lookupd of upcoming change */
2998	notify_post("com.apple.system.dns.delay");
2999
3000	if (dns1)
3001		str1 = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&dns1));
3002	if (!str1)
3003		goto done;
3004
3005	if (dns2 && (dns2!=dns1))
3006		str2 = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&dns2));
3007
3008	result = publish_dns_wins_entry(kSCEntNetDNS, kSCPropNetDNSServerAddresses, str1, str2, kSCPropNetDNSSupplementalMatchDomains, strname, kSCPropNetDNSSupplementalMatchOrders, num, clean);
3009#ifndef kSCPropNetProxiesSupplementalMatchDomains
3010#define kSCPropNetProxiesSupplementalMatchDomains kSCPropNetDNSSupplementalMatchDomains
3011#define kSCPropNetProxiesSupplementalMatchOrders kSCPropNetDNSSupplementalMatchOrders
3012#endif
3013	if (result) publish_dns_wins_entry(kSCEntNetProxies, kSCPropNetProxiesSupplementalMatchDomains, strname, 0, kSCPropNetProxiesSupplementalMatchOrders, num, 0, 0, clean);
3014
3015done:
3016	if (num)
3017		CFRelease(num);
3018	if (str1)
3019		CFRelease(str1);
3020	if (str2)
3021		CFRelease(str2);
3022	if (strname)
3023		CFRelease(strname);
3024
3025	return result;
3026}
3027
3028/* -----------------------------------------------------------------------------
3029set wins information
3030----------------------------------------------------------------------------- */
3031int sifwins(u_int32_t wins1, u_int32_t wins2)
3032{
3033#if !TARGET_OS_EMBEDDED
3034    CFStringRef		str1 = 0, str2 = 0;
3035    int				result = 0, clean = 1;
3036
3037	if (wins1)
3038		str1 = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&wins1));
3039	if (!str1)
3040		goto done;
3041
3042	if (wins2)
3043		str2 = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&wins2));
3044
3045	result = publish_dns_wins_entry(kSCEntNetSMB, kSCPropNetSMBWINSAddresses, str1, str2, 0, 0, 0, 0, clean);
3046
3047done:
3048	if (str1)
3049		CFRelease(str1);
3050	if (str2)
3051		CFRelease(str2);
3052
3053	return result;
3054#else
3055	return 0;
3056#endif
3057}
3058
3059static struct {
3060    struct rt_msghdr		hdr;
3061    struct sockaddr_inarp	dst;
3062    struct sockaddr_dl		hwa;
3063    char			extra[128];
3064} arpmsg;
3065
3066static int arpmsg_valid;
3067
3068/* -----------------------------------------------------------------------------
3069Make a proxy ARP entry for the peer
3070----------------------------------------------------------------------------- */
3071int sifproxyarp(int unit, u_int32_t hisaddr)
3072{
3073    int routes;
3074
3075    /*
3076     * Get the hardware address of an interface on the same subnet
3077     * as our local address.
3078     */
3079    memset(&arpmsg, 0, sizeof(arpmsg));
3080    if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
3081	error("Cannot determine ethernet address for proxy ARP");
3082	return 0;
3083    }
3084
3085    if ((routes = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) {
3086	error("Couldn't add proxy arp entry: socket: %m");
3087	return 0;
3088    }
3089
3090    arpmsg.hdr.rtm_type = RTM_ADD;
3091    arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
3092    arpmsg.hdr.rtm_version = RTM_VERSION;
3093    arpmsg.hdr.rtm_seq = ++rtm_seq;
3094    arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
3095    arpmsg.hdr.rtm_inits = RTV_EXPIRE;
3096    arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
3097    arpmsg.dst.sin_family = AF_INET;
3098    arpmsg.dst.sin_addr.s_addr = hisaddr;
3099    arpmsg.dst.sin_other = SIN_PROXY;
3100
3101    arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
3102	+ arpmsg.hwa.sdl_len;
3103    if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
3104	error("Couldn't add proxy arp entry: %m");
3105	close(routes);
3106	return 0;
3107    }
3108
3109    close(routes);
3110    arpmsg_valid = 1;
3111    proxy_arp_addr = hisaddr;
3112    return 1;
3113}
3114
3115/* -----------------------------------------------------------------------------
3116Delete the proxy ARP entry for the peer
3117----------------------------------------------------------------------------- */
3118int cifproxyarp(int unit, u_int32_t hisaddr)
3119{
3120    int routes;
3121
3122    if (!arpmsg_valid)
3123	return 0;
3124    arpmsg_valid = 0;
3125
3126    arpmsg.hdr.rtm_type = RTM_DELETE;
3127    arpmsg.hdr.rtm_seq = ++rtm_seq;
3128
3129    if ((routes = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) {
3130	error("Couldn't delete proxy arp entry: socket: %m");
3131	return 0;
3132    }
3133
3134    if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
3135	error("Couldn't delete proxy arp entry: %m");
3136	close(routes);
3137	return 0;
3138    }
3139
3140    close(routes);
3141    proxy_arp_addr = 0;
3142    return 1;
3143}
3144
3145#define MAX_IFS		32
3146
3147/* -----------------------------------------------------------------------------
3148get the hardware address of an interface on the
3149 * the same subnet as ipaddr.
3150----------------------------------------------------------------------------- */
3151static int get_ether_addr(u_int32_t ipaddr, struct sockaddr_dl *hwaddr)
3152{
3153    struct ifreq *ifr, *ifend, *ifp;
3154    u_int32_t ina, mask;
3155    struct sockaddr_dl *dla;
3156    struct ifreq ifreq;
3157    struct ifconf ifc;
3158    struct ifreq ifs[MAX_IFS];
3159
3160    ifc.ifc_len = sizeof(ifs);
3161    ifc.ifc_req = ifs;
3162    if (ioctl(ip_sockfd, SIOCGIFCONF, &ifc) < 0) {
3163	error("ioctl(SIOCGIFCONF): %m");
3164	return 0;
3165    }
3166
3167    /*
3168     * Scan through looking for an interface with an Internet
3169     * address on the same subnet as `ipaddr'.
3170     */
3171    ifend = ALIGNED_CAST(struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
3172    for (ifr = ifc.ifc_req; ifr < ifend; ifr = ALIGNED_CAST(struct ifreq *)
3173	 	((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) {
3174	if (ifr->ifr_addr.sa_family == AF_INET) {
3175	    ina = (ALIGNED_CAST(struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
3176	    strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
3177	    /*
3178	     * Check that the interface is up, and not point-to-point
3179	     * or loopback.
3180	     */
3181	    if (ioctl(ip_sockfd, SIOCGIFFLAGS, &ifreq) < 0)
3182		continue;
3183	    if ((ifreq.ifr_flags &
3184		 (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
3185		 != (IFF_UP|IFF_BROADCAST))
3186		continue;
3187	    /*
3188	     * Get its netmask and check that it's on the right subnet.
3189	     */
3190	    if (ioctl(ip_sockfd, SIOCGIFNETMASK, &ifreq) < 0)
3191		continue;
3192	    mask = (ALIGNED_CAST(struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
3193	    if ((ipaddr & mask) != (ina & mask))
3194		continue;
3195
3196	    break;
3197	}
3198    }
3199
3200    if (ifr >= ifend)
3201	return 0;
3202    info("found interface %s for proxy arp", ifr->ifr_name);
3203
3204    /*
3205     * Now scan through again looking for a link-level address
3206     * for this interface.
3207     */
3208    ifp = ifr;
3209    for (ifr = ifc.ifc_req; ifr < ifend; ) {
3210	if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
3211	    && ifr->ifr_addr.sa_family == AF_LINK) {
3212	    /*
3213	     * Found the link-level address - copy it out
3214	     */
3215	    dla = ALIGNED_CAST(struct sockaddr_dl *) &ifr->ifr_addr;
3216	    BCOPY(dla, hwaddr, dla->sdl_len);
3217	    return 1;
3218	}
3219	ifr = ALIGNED_CAST(struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
3220    }
3221
3222    return 0;
3223}
3224
3225/* -----------------------------------------------------------------------------
3226 * Return user specified netmask, modified by any mask we might determine
3227 * for address `addr' (in network byte order).
3228 * Here we scan through the system's list of interfaces, looking for
3229 * any non-point-to-point interfaces which might appear to be on the same
3230 * network as `addr'.  If we find any, we OR in their netmask to the
3231 * user-specified netmask.
3232----------------------------------------------------------------------------- */
3233u_int32_t GetMask(u_int32_t addr)
3234{
3235    u_int32_t mask, nmask, ina;
3236    struct ifreq *ifr, *ifend, ifreq;
3237    struct ifconf ifc;
3238    struct ifreq ifs[MAX_IFS];
3239
3240    addr = ntohl(addr);
3241    if (IN_CLASSA(addr))	/* determine network mask for address class */
3242	nmask = IN_CLASSA_NET;
3243    else if (IN_CLASSB(addr))
3244	nmask = IN_CLASSB_NET;
3245    else
3246	nmask = IN_CLASSC_NET;
3247    /* class D nets are disallowed by bad_ip_adrs */
3248    mask = netmask | htonl(nmask);
3249
3250    /*
3251     * Scan through the system's network interfaces.
3252     */
3253    ifc.ifc_len = sizeof(ifs);
3254    ifc.ifc_req = ifs;
3255    if (ioctl(ip_sockfd, SIOCGIFCONF, &ifc) < 0) {
3256	warning("ioctl(SIOCGIFCONF): %m");
3257	return mask;
3258    }
3259    ifend = ALIGNED_CAST(struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
3260    for (ifr = ifc.ifc_req; ifr < ifend; ifr = ALIGNED_CAST(struct ifreq *)
3261	 	((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) {
3262	/*
3263	 * Check the interface's internet address.
3264	 */
3265	if (ifr->ifr_addr.sa_family != AF_INET)
3266	    continue;
3267	ina = (ALIGNED_CAST(struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
3268	if ((ntohl(ina) & nmask) != (addr & nmask))
3269	    continue;
3270	/*
3271	 * Check that the interface is up, and not point-to-point or loopback.
3272	 */
3273	strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
3274	if (ioctl(ip_sockfd, SIOCGIFFLAGS, &ifreq) < 0)
3275	    continue;
3276	if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
3277	    != IFF_UP)
3278	    continue;
3279	/*
3280	 * Get its netmask and OR it into our mask.
3281	 */
3282	if (ioctl(ip_sockfd, SIOCGIFNETMASK, &ifreq) < 0)
3283	    continue;
3284	mask |= (ALIGNED_CAST(struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
3285    }
3286
3287    return mask;
3288}
3289
3290/* -----------------------------------------------------------------------------
3291determine if the system has any route to
3292 * a given IP address.
3293 * For demand mode to work properly, we have to ignore routes
3294 * through our own interface.
3295 ----------------------------------------------------------------------------- */
3296int have_route_to(u_int32_t addr)
3297{
3298    return -1;
3299}
3300
3301/* -----------------------------------------------------------------------------
3302Use the hostid as part of the random number seed
3303----------------------------------------------------------------------------- */
3304int get_host_seed()
3305{
3306    return gethostid();
3307}
3308
3309
3310#if 0
3311
3312#define	LOCK_PREFIX	"/var/spool/lock/LCK.."
3313
3314static char *lock_file;		/* name of lock file created */
3315
3316/* -----------------------------------------------------------------------------
3317create a lock file for the named lock device
3318----------------------------------------------------------------------------- */
3319int lock(char *dev)
3320{
3321    char hdb_lock_buffer[12];
3322    int fd, pid, n;
3323    char *p;
3324    size_t l;
3325
3326    if ((p = strrchr(dev, '/')) != NULL)
3327	dev = p + 1;
3328    l = strlen(LOCK_PREFIX) + strlen(dev) + 1;
3329    lock_file = malloc(l);
3330    if (lock_file == NULL)
3331	novm("lock file name");
3332    slprintf(lock_file, l, "%s%s", LOCK_PREFIX, dev);
3333
3334    while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
3335	if (errno == EEXIST
3336	    && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
3337	    /* Read the lock file to find out who has the device locked */
3338	    n = read(fd, hdb_lock_buffer, 11);
3339	    if (n <= 0) {
3340		error("Can't read pid from lock file %s", lock_file);
3341		close(fd);
3342	    } else {
3343		hdb_lock_buffer[n] = 0;
3344		pid = atoi(hdb_lock_buffer);
3345		if (kill(pid, 0) == -1 && errno == ESRCH) {
3346		    /* pid no longer exists - remove the lock file */
3347		    if (unlink(lock_file) == 0) {
3348			close(fd);
3349			notice("Removed stale lock on %s (pid %d)",
3350			       dev, pid);
3351			continue;
3352		    } else
3353			warning("Couldn't remove stale lock on %s",
3354			       dev);
3355		} else
3356		    notice("Device %s is locked by pid %d",
3357			   dev, pid);
3358	    }
3359	    close(fd);
3360	} else
3361	    error("Can't create lock file %s: %m", lock_file);
3362	free(lock_file);
3363	lock_file = NULL;
3364	return -1;
3365    }
3366
3367    slprintf(hdb_lock_buffer, sizeof(hdb_lock_buffer), "%10d\n", getpid());
3368    write(fd, hdb_lock_buffer, 11);
3369
3370    close(fd);
3371    return 0;
3372}
3373
3374/* -----------------------------------------------------------------------------
3375remove our lockfile
3376----------------------------------------------------------------------------- */
3377void unlock()
3378{
3379    if (lock_file) {
3380	unlink(lock_file);
3381	free(lock_file);
3382	lock_file = NULL;
3383    }
3384}
3385#endif
3386
3387/* -----------------------------------------------------------------------------
3388----------------------------------------------------------------------------- */
3389int sys_loadplugin(char *arg)
3390{
3391    char		path[MAXPATHLEN];
3392    int 		ret = -1;
3393    CFBundleRef		bundle;
3394    CFURLRef		url;
3395    int 		(*start)(CFBundleRef);
3396
3397
3398    if (arg[0] == '/') {
3399        strlcpy(path, arg, sizeof(path));
3400    }
3401    else {
3402        strlcpy(path, "/System/Library/Extensions/", sizeof(path));
3403        strlcat(path, arg, sizeof(path));
3404    }
3405
3406    url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)path, strlen(path), TRUE);
3407    if (url) {
3408        bundle =  CFBundleCreate(NULL, url);
3409        if (bundle) {
3410
3411            if (CFBundleLoadExecutable(bundle)
3412                && (start = CFBundleGetFunctionPointerForName(bundle, CFSTR("start")))) {
3413
3414                ret = (*start)(bundle);
3415            }
3416
3417            CFRelease(bundle);
3418        }
3419        CFRelease(url);
3420    }
3421    return ret;
3422}
3423
3424/* -----------------------------------------------------------------------------
3425----------------------------------------------------------------------------- */
3426int sys_eaploadplugin(char *arg, eap_ext *eap)
3427{
3428    char		path[MAXPATHLEN];
3429    int 		ret = -1;
3430    CFBundleRef		bundle;
3431    CFURLRef		url;
3432    CFDictionaryRef	dict;
3433
3434    if (arg[0] == '/') {
3435        strlcpy(path, arg, sizeof(path));
3436    }
3437    else {
3438        strlcpy(path, "/System/Library/Extensions/", sizeof(path));
3439        strlcat(path, arg, sizeof(path));
3440    }
3441
3442    url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)path, strlen(path), TRUE);
3443    if (url) {
3444
3445        dict = CFBundleCopyInfoDictionaryForURL(url);
3446        if (dict) {
3447            CFNumberRef	num;
3448            CFStringRef	str;
3449            int		i;
3450
3451            bzero(eap, sizeof(eap_ext));
3452            num = CFDictionaryGetValue(dict, CFSTR("EAPType"));
3453            if (num && (CFGetTypeID(num) == CFNumberGetTypeID())) {
3454                CFNumberGetValue(num, kCFNumberSInt32Type, &i);
3455                eap->type = i;
3456            }
3457
3458            str = CFDictionaryGetValue(dict, CFSTR("EAPName"));
3459            if (str && (CFGetTypeID(str) == CFStringGetTypeID())) {
3460                eap->name = malloc(CFStringGetLength(str) + 1);
3461                if (eap->name)
3462                    CFStringGetCString((CFStringRef)str, eap->name, CFStringGetLength(str) + 1, kCFStringEncodingUTF8);
3463            }
3464            CFRelease(dict);
3465
3466            bundle =  CFBundleCreate(NULL, url);
3467            if (bundle) {
3468
3469                if (CFBundleLoadExecutable(bundle)) {
3470
3471                    eap->init = CFBundleGetFunctionPointerForName(bundle, CFSTR("Init"));
3472                    eap->dispose = CFBundleGetFunctionPointerForName(bundle, CFSTR("Dispose"));
3473                    eap->process = CFBundleGetFunctionPointerForName(bundle, CFSTR("Process"));
3474                    eap->free = CFBundleGetFunctionPointerForName(bundle, CFSTR("Free"));
3475                    eap->attribute = CFBundleGetFunctionPointerForName(bundle, CFSTR("GetAttribute"));
3476                    eap->interactive_ui = CFBundleGetFunctionPointerForName(bundle, CFSTR("InteractiveUI"));
3477                    eap->print_packet = CFBundleGetFunctionPointerForName(bundle, CFSTR("PrintPacket"));
3478                    eap->identity = CFBundleGetFunctionPointerForName(bundle, CFSTR("Identity"));
3479
3480                    // keep a ref to release later
3481                    eap->plugin = bundle;
3482
3483                    ret = 0;
3484                }
3485
3486                if (ret)
3487                    CFRelease(bundle);
3488            }
3489        }
3490        CFRelease(url);
3491    }
3492    return ret;
3493}
3494
3495/* -----------------------------------------------------------------------------
3496publish a dictionnary entry in the cache, given a key
3497----------------------------------------------------------------------------- */
3498int publish_keyentry(CFStringRef key, CFStringRef entry, CFTypeRef value)
3499{
3500    CFMutableDictionaryRef	dict;
3501    CFPropertyListRef		ref;
3502
3503    // ppp daemons without services are not published in the cache
3504    if (cfgCache == NULL)
3505        return 0;
3506
3507    if (publish_dict && key && CFDictionaryContainsKey(publish_dict, key) && (ref = CFDictionaryGetValue(publish_dict, key))) {
3508        dict = CFDictionaryCreateMutableCopy(0, 0, ref);
3509    } else {
3510        dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3511    }
3512
3513    if (dict == 0)
3514        return 0;
3515
3516    CFDictionarySetValue(dict,  entry, value);
3517	if (update_publish_dict(key,dict) == 0)
3518        warning("publish_entry SCDSet() failed: %s\n", SCErrorString(SCError()));
3519    CFRelease(dict);
3520
3521    return 1;
3522 }
3523
3524/* -----------------------------------------------------------------------------
3525publish a numerical entry in the cache, given a dictionary
3526----------------------------------------------------------------------------- */
3527int publish_dictnumentry(CFStringRef dict, CFStringRef entry, int val)
3528{
3529    int			ret = ENOMEM;
3530    CFNumberRef		num;
3531    CFStringRef		key;
3532
3533    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, dict);
3534    if (key) {
3535        num = CFNumberCreate(NULL, kCFNumberIntType, &val);
3536        if (num) {
3537            ret = publish_keyentry(key, entry, num);
3538            CFRelease(num);
3539            ret = 0;
3540        }
3541        CFRelease(key);
3542    }
3543    return ret;
3544}
3545
3546/* -----------------------------------------------------------------------------
3547publish a string entry in the cache, given a dictionary
3548----------------------------------------------------------------------------- */
3549int publish_dictstrentry(CFStringRef dict, CFStringRef entry, char *str, int encoding)
3550{
3551
3552    int			ret = ENOMEM;
3553    CFStringRef 	ref;
3554    CFStringRef		key;
3555
3556    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, dict);
3557    if (key) {
3558        ref = CFStringCreateWithCString(NULL, str, encoding);
3559        if (ref) {
3560            ret = publish_keyentry(key, entry, ref);
3561            CFRelease(ref);
3562            ret = 0;
3563        }
3564        CFRelease(key);
3565    }
3566    return ret;
3567}
3568
3569/* -----------------------------------------------------------------------------
3570 republish Dynamic store
3571 ----------------------------------------------------------------------------- */
3572static void
3573republish_dict(SCDynamicStoreRef store __unused, void *info  __unused)
3574{
3575	int count;
3576
3577    dbglog("DynamicStore Server has reconnected, republish keys");
3578	if (publish_dict == NULL)
3579		return;
3580
3581	count = CFDictionaryGetCount(publish_dict);
3582	if ( count ){
3583		CFRelease(cfgCache);
3584		cfgCache = SCDynamicStoreCreate(0, CFSTR("pppd"), 0, 0);		/* create new ref with server */
3585		if (cfgCache == 0){
3586			fatal("republish_dict SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
3587			return;
3588		}
3589
3590        dbglog("republish_dict: processing %d keys", count);
3591        if (demand) { /* Republish directly for demand mode */
3592            if (publish_dict) {
3593                SCDynamicStoreSetMultiple(cfgCache, publish_dict, NULL, NULL);
3594            }
3595        } else if (!commit_publish_dict()) {
3596            warning("republish_dict SCDynamicStoreSetMultiple failed key: %s\n", SCErrorString(SCError()));
3597        }
3598	}
3599}
3600
3601/* -----------------------------------------------------------------------------
3602unpublish a dictionnary entry from the cache, given the dict key
3603----------------------------------------------------------------------------- */
3604int unpublish_keyentry(CFStringRef key, CFStringRef entry)
3605{
3606    CFMutableDictionaryRef	dict;
3607    CFPropertyListRef		ref;
3608
3609    // ppp daemons without services are not published in the cache
3610    if (cfgCache == NULL)
3611        return 0;
3612
3613    if (publish_dict && key && CFDictionaryContainsKey(publish_dict, key) && (ref = CFDictionaryGetValue(publish_dict, key))) {
3614        if ((dict = CFDictionaryCreateMutableCopy(0, 0, ref))) {
3615            CFDictionaryRemoveValue(dict, entry);
3616            if (update_publish_dict(key, dict) == 0)
3617                warning("unpublish_keyentry SCDSet() failed: %s\n", SCErrorString(SCError()));
3618            CFRelease(dict);
3619        }
3620    }
3621
3622    return 0;
3623}
3624
3625/* -----------------------------------------------------------------------------
3626unpublish a complete dictionnary from the cache
3627----------------------------------------------------------------------------- */
3628int unpublish_dict(CFStringRef dict)
3629{
3630    int			ret = ENOMEM;
3631    CFStringRef		key;
3632
3633    if (cfgCache == NULL)
3634        return 0;
3635
3636    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, dict);
3637    if (key) {
3638		if (publish_dict){
3639			CFDictionaryRemoveValue(publish_dict, key);
3640		}
3641        ret = !SCDynamicStoreRemoveValue(cfgCache, key);
3642        CFRelease(key);
3643    }
3644    return ret;
3645}
3646
3647/* -----------------------------------------------------------------------------
3648unpublish a dictionnary entry from the cache, given the dict name
3649----------------------------------------------------------------------------- */
3650int unpublish_dictentry(CFStringRef dict, CFStringRef entry)
3651{
3652    int			ret = ENOMEM;
3653    CFStringRef		key;
3654
3655    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceidRef, dict);
3656    if (key) {
3657        ret = unpublish_keyentry(key, entry);
3658        CFRelease(key);
3659        ret = 0;
3660    }
3661    return ret;
3662}
3663
3664/* -----------------------------------------------------------------------------
3665get mach asbolute time, for timeout purpose independent of date changes
3666----------------------------------------------------------------------------- */
3667int getabsolutetime(struct timeval *timenow)
3668{
3669    double	now;
3670
3671    if (timeScaleSeconds == 0)
3672        return -1;
3673
3674    now = mach_absolute_time();
3675    timenow->tv_sec = now * timeScaleSeconds;
3676    timenow->tv_usec =  (now * timeScaleMicroSeconds) - ((double)timenow->tv_sec * 1000000);
3677    return 0;
3678}
3679
3680/* -----------------------------------------------------------------------------
3681our new phase hook
3682----------------------------------------------------------------------------- */
3683void sys_phasechange(void *arg, uintptr_t p)
3684{
3685
3686    publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPStatus, p);
3687
3688    switch (p) {
3689
3690        case PHASE_ESTABLISH:
3691            connecttime = mach_absolute_time() * timeScaleSeconds;
3692            publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPConnectTime, connecttime);
3693            if (maxconnect)
3694                publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPDisconnectTime, connecttime + maxconnect);
3695            break;
3696
3697        case PHASE_SERIALCONN:
3698            unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPRetryConnectTime);
3699            break;
3700
3701        case PHASE_WAITONBUSY:
3702            publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPRetryConnectTime, redialtimer + (mach_absolute_time() * timeScaleSeconds));
3703            break;
3704
3705        case PHASE_RUNNING:
3706            break;
3707
3708        case PHASE_DORMANT:
3709        case PHASE_HOLDOFF:
3710        case PHASE_DEAD:
3711            sys_eventnotify((void*)PPP_EVT_DISCONNECTED, status);
3712            break;
3713
3714        case PHASE_DISCONNECT:
3715            unpublish_dictentry(kSCEntNetPPP, CFSTR("AuthPeerName") /*kSCPropNetPPPAuthPeerName*/);
3716            unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPCommRemoteAddress);
3717            unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPConnectTime);
3718            unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPDisconnectTime);
3719            sys_eventnotify((void*)PPP_EVT_REQUEST_UNINSTALL, 0);
3720            break;
3721    }
3722
3723    /* send phase notification to the controller */
3724    if (phase != PHASE_DEAD)
3725		sys_notify(PPPD_PHASE, phase, ifunit);
3726}
3727
3728
3729/* -----------------------------------------------------------------------------
3730----------------------------------------------------------------------------- */
3731void sys_authpeersuccessnotify(void *param, uintptr_t info)
3732{
3733    struct auth_peer_success_info *peerinfo = (struct auth_peer_success_info *)info;
3734
3735    publish_dictstrentry(kSCEntNetPPP, CFSTR("AuthPeerName") /*kSCPropNetPPPAuthPeerName*/, peerinfo->name, kCFStringEncodingUTF8);
3736}
3737
3738/* -----------------------------------------------------------------------------
3739----------------------------------------------------------------------------- */
3740void sys_timeremaining(void *param, uintptr_t info)
3741{
3742    struct lcp_timeremaining_info *timeinfo = (struct lcp_timeremaining_info *)info;
3743    u_int32_t	val = 0, curtime = mach_absolute_time() * timeScaleSeconds;
3744
3745    if (timeinfo->time == 0xFFFFFFFF) {
3746        // infinite timer from the server, restore our maxconnect time if any
3747        if (maxconnect)
3748            val = connecttime + maxconnect;
3749    }
3750    else {
3751        // valid timer from the server, the disconnect time will be the min between
3752        // our setup and what says the server.
3753        if (maxconnect)
3754            val = MIN(curtime + timeinfo->time, connecttime + maxconnect);
3755        else
3756            val = curtime + timeinfo->time;
3757    }
3758
3759    if (val)
3760        publish_dictnumentry(kSCEntNetPPP, kSCPropNetPPPDisconnectTime, val);
3761    else
3762        unpublish_dictentry(kSCEntNetPPP, kSCPropNetPPPDisconnectTime);
3763
3764}
3765
3766/* -----------------------------------------------------------------------------
3767----------------------------------------------------------------------------- */
3768void sys_publish_remoteaddress(char *addr)
3769{
3770
3771    if (addr)
3772        publish_dictstrentry(kSCEntNetPPP, kSCPropNetPPPCommRemoteAddress, addr, kCFStringEncodingUTF8);
3773}
3774
3775/* -----------------------------------------------------------------------------
3776our pid has changed, reinit things
3777----------------------------------------------------------------------------- */
3778void sys_reinit()
3779{
3780
3781    cfgCache = SCDynamicStoreCreate(0, CFSTR("pppd"), 0, 0);
3782    if (cfgCache == 0)
3783        fatal("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
3784
3785    publish_dictnumentry(kSCEntNetPPP, CFSTR("pid"), getpid());
3786}
3787
3788/* -----------------------------------------------------------------------------
3789we are exiting
3790----------------------------------------------------------------------------- */
3791void sys_exitnotify(void *arg, uintptr_t exitcode)
3792{
3793
3794    // unpublish the various info about the connection
3795    unpublish_dict(kSCEntNetPPP);
3796    unpublish_dict(kSCEntNetDNS);
3797    unpublish_dict(kSCEntNetProxies);
3798#if !TARGET_OS_EMBEDDED
3799    unpublish_dict(kSCEntNetSMB);
3800#endif
3801    unpublish_dict(kSCEntNetInterface);
3802
3803    sys_eventnotify((void*)PPP_EVT_DISCONNECTED, exitcode);
3804
3805    if (cfgCache) {
3806        CFRelease(cfgCache);
3807        cfgCache = 0;
3808    }
3809
3810	if (publish_dict){
3811		CFRelease(publish_dict);
3812		publish_dict = NULL;
3813	}
3814}
3815
3816/* -----------------------------------------------------------------------------
3817add/remove a route via an interface
3818----------------------------------------------------------------------------- */
3819int
3820route_interface(int cmd, struct in_addr host, struct in_addr addr_mask, char iftype, char *ifname, int is_host)
3821{
3822    int 			len, iflen;
3823    int 			rtm_seq = 0;
3824    struct {
3825	struct rt_msghdr	hdr;
3826	struct sockaddr_in	dst;
3827	struct sockaddr_dl	iface;
3828        struct sockaddr_in	mask;
3829    } rtmsg;
3830
3831	char            host_str[INET_ADDRSTRLEN];
3832	char            mask_str[INET_ADDRSTRLEN];
3833    int 			sockfd = -1;
3834
3835    if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) {
3836		error("route_interface: open routing socket failed, %m. (address %s, mask %s, interface %s, host %d).",
3837			  addr2ascii(AF_INET, &host, sizeof(host), host_str),
3838			  addr2ascii(AF_INET, &addr_mask, sizeof(addr_mask), mask_str),
3839			  ifname,
3840			  is_host);
3841		return (0);
3842    }
3843
3844    memset(&rtmsg, 0, sizeof(rtmsg));
3845    rtmsg.hdr.rtm_type = cmd;
3846    rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
3847    if (is_host)
3848        rtmsg.hdr.rtm_flags |= RTF_HOST;
3849    rtmsg.hdr.rtm_version = RTM_VERSION;
3850    rtmsg.hdr.rtm_seq = ++rtm_seq;
3851    rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
3852    rtmsg.dst.sin_len = sizeof(rtmsg.dst);
3853    rtmsg.dst.sin_family = AF_INET;
3854    rtmsg.dst.sin_addr = host;
3855    iflen = MIN(strlen(ifname), sizeof(rtmsg.iface.sdl_data));
3856    rtmsg.iface.sdl_len = sizeof(rtmsg.iface);
3857    rtmsg.iface.sdl_family = AF_LINK;
3858    rtmsg.iface.sdl_type = iftype;
3859    rtmsg.iface.sdl_nlen = iflen;
3860    strncpy(rtmsg.iface.sdl_data, ifname, iflen);
3861
3862    // if addr_mask non-zero add it
3863    if (addr_mask.s_addr != 0) {
3864        rtmsg.hdr.rtm_addrs |= RTA_NETMASK;
3865        rtmsg.mask.sin_len = sizeof(rtmsg.mask);
3866        rtmsg.mask.sin_family = AF_INET;
3867        rtmsg.mask.sin_addr = addr_mask;
3868    }
3869
3870    len = sizeof(rtmsg);
3871    rtmsg.hdr.rtm_msglen = len;
3872    if (write(sockfd, &rtmsg, len) < 0) {
3873		sys_log((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "route_interface: write routing socket failed, %s. (address %s, mask %s, interface %s, host %d).",
3874			   strerror(errno),
3875			  addr2ascii(AF_INET, &host, sizeof(host), host_str),
3876			  addr2ascii(AF_INET, &addr_mask, sizeof(addr_mask), mask_str),
3877			  ifname,
3878			  is_host);
3879		close(sockfd);
3880		return (0);
3881    }
3882
3883    close(sockfd);
3884    return (1);
3885}
3886
3887/* -----------------------------------------------------------------------------
3888    add/remove a route via a gateway
3889----------------------------------------------------------------------------- */
3890int
3891route_gateway(int cmd, struct in_addr dest, struct in_addr mask, struct in_addr gateway, int use_gway_flag)
3892{
3893	char            dest_str[INET_ADDRSTRLEN];
3894	char            mask_str[INET_ADDRSTRLEN];
3895	char            gateway_str[INET_ADDRSTRLEN];
3896    int 			len;
3897    int 			rtm_seq = 0;
3898
3899    struct {
3900	struct rt_msghdr	hdr;
3901	struct sockaddr_in	dst;
3902        struct sockaddr_in	gway;
3903        struct sockaddr_in	mask;
3904    } rtmsg;
3905
3906    int 			sockfd = -1;
3907
3908    if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) {
3909		sys_log(LOG_INFO, "host_gateway: open routing socket failed, %s. (address %s, mask %s, gateway %s, use-gateway %d).",
3910			   strerror(errno),
3911			   addr2ascii(AF_INET, &dest, sizeof(dest), dest_str),
3912			   addr2ascii(AF_INET, &mask, sizeof(mask), mask_str),
3913			   addr2ascii(AF_INET, &gateway, sizeof(gateway), gateway_str),
3914			   use_gway_flag);
3915		return (0);
3916    }
3917
3918    memset(&rtmsg, 0, sizeof(rtmsg));
3919    rtmsg.hdr.rtm_type = cmd;
3920    rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
3921    if (use_gway_flag)
3922        rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
3923    rtmsg.hdr.rtm_version = RTM_VERSION;
3924    rtmsg.hdr.rtm_seq = ++rtm_seq;
3925    rtmsg.hdr.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
3926    rtmsg.dst.sin_len = sizeof(rtmsg.dst);
3927    rtmsg.dst.sin_family = AF_INET;
3928    rtmsg.dst.sin_addr = dest;
3929    rtmsg.gway.sin_len = sizeof(rtmsg.gway);
3930    rtmsg.gway.sin_family = AF_INET;
3931    rtmsg.gway.sin_addr = gateway;
3932    rtmsg.mask.sin_len = sizeof(rtmsg.mask);
3933    rtmsg.mask.sin_family = AF_INET;
3934    rtmsg.mask.sin_addr = mask;
3935
3936    len = sizeof(rtmsg);
3937    rtmsg.hdr.rtm_msglen = len;
3938    if (write(sockfd, &rtmsg, len) < 0) {
3939		sys_log((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "host_gateway: write routing socket failed, %s. (address %s, mask %s, gateway %s, use-gateway %d).",
3940			   strerror(errno),
3941			   addr2ascii(AF_INET, &dest, sizeof(dest), dest_str),
3942			   addr2ascii(AF_INET, &mask, sizeof(mask), mask_str),
3943			   addr2ascii(AF_INET, &gateway, sizeof(gateway), gateway_str),
3944			   use_gway_flag);
3945		close(sockfd);
3946		return (0);
3947    }
3948
3949    close(sockfd);
3950    return (1);
3951}
3952
3953// Here stealing the in_cksum function which computes checksum from original ping.
3954static int
3955in_cksum(u_short *addr, int len)
3956{
3957	register int nleft = len;
3958	register u_short *w = addr;
3959	register int sum = 0;
3960	u_short answer = 0;
3961
3962	// Our algorithm is simple, using a 32 bit accumulator (sum), we add
3963	// sequential 16 bit words to it, and at the end, fold back all the
3964	// carry bits from the top 16 bits into the lower 16 bits.
3965
3966	while (nleft > 1) {
3967		sum += *w++;
3968		nleft -= 2;
3969	}
3970
3971	/* mop up an odd byte, if necessary */
3972	if (nleft == 1) {
3973		*(u_char *)(&answer) = *(u_char *)w;
3974		sum += answer;
3975	}
3976
3977	// Add back carry outs from top 16 bits to low 16 bits
3978	sum = (sum >> 16) + (sum & 0xffff);  // Add hi 16 to low 16
3979	sum += (sum >> 16);                  // Add carry
3980	answer = ~sum;                       // Truncate to 16 bits
3981
3982	return answer;
3983}
3984
3985static int
3986ppp_scoped_ping (int                 s,
3987				 unsigned int        ifscope,
3988				 struct sockaddr_in *dst,
3989				 int                 ntransmit)
3990{
3991	int          i;
3992	int          hold;
3993	struct icmp *icp;
3994	u_char      *packet;
3995	u_char       outpack[IP_MAXPACKET] __attribute__ ((aligned(4)));		// Wcast-align fix - force alignment
3996
3997	if (s < 0) {
3998		s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
3999		if (s < 0) {
4000			return -1;
4001		}
4002		if (ifscope) {
4003			if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF, (char *)&ifscope, sizeof(ifscope)) != 0) {
4004				close(s);
4005				return -1;
4006			}
4007		}
4008
4009		hold = IP_MAXPACKET + 128;
4010		(void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));
4011	}
4012
4013	packet = outpack;
4014	icp = ALIGNED_CAST(struct icmp *)outpack;
4015	icp->icmp_type = ICMP_ECHO;
4016	icp->icmp_code = 0;
4017	icp->icmp_cksum = 0;
4018	icp->icmp_seq = htons(ntransmit);
4019	icp->icmp_id = getpid() & 0xFFFF;
4020	icp->icmp_cksum = in_cksum((u_short *)icp, ICMP_MINLEN);
4021	if ((i = sendto(s, (char *)packet, ICMP_MINLEN, 0, (struct sockaddr *)dst, sizeof(*dst))) != ICMP_MINLEN) {
4022		close(s);
4023		return -1;
4024	}
4025	return s;
4026}
4027
4028int
4029ppp_ip_probe_send (void *arg)
4030{
4031	int scope;
4032	int i = 0;
4033
4034	dbglog("%s: starting", __FUNCTION__);
4035
4036	if (!session || !session->valid) {
4037		return -1;
4038	}
4039
4040	scope = if_nametoindex(session->interface_name);
4041
4042	session->probe_success = 0;
4043
4044	// first probe to goog-dns
4045	if ((session->probe_addrs[GOOG_DNS_PROBE].sin_family == AF_INET) &&
4046		session->probe_addrs[GOOG_DNS_PROBE].sin_addr.s_addr) {
4047		dbglog("%s: found goog-dns address", __FUNCTION__);
4048		if ((session->probe_fds[GOOG_DNS_PROBE] = ppp_scoped_ping(session->probe_fds[GOOG_DNS_PROBE],
4049																  scope,
4050																  &session->probe_addrs[GOOG_DNS_PROBE],
4051																  session->probe_ntransmit)) != -1) {
4052			add_fd(session->probe_fds[GOOG_DNS_PROBE]);
4053			dbglog("%s: sent to goog-dns over scope %d", __FUNCTION__, scope);
4054			i++;
4055		}
4056	} else {
4057		info("%s: no goog-dns address", __FUNCTION__);
4058	}
4059	// next probes to server and alternate server
4060	if ((session->probe_addrs[PEER_ADDR_PROBE].sin_family == AF_INET) &&
4061		session->probe_addrs[PEER_ADDR_PROBE].sin_addr.s_addr) {
4062		dbglog("%s: found peer address", __FUNCTION__);
4063		// current vpn server
4064		if ((session->probe_fds[PEER_ADDR_PROBE] = ppp_scoped_ping(session->probe_fds[PEER_ADDR_PROBE],
4065																   scope,
4066																   &session->probe_addrs[PEER_ADDR_PROBE],
4067																   session->probe_ntransmit)) != -1) {
4068			add_fd(session->probe_fds[PEER_ADDR_PROBE]);
4069			dbglog("%s: sent to peer over scope %d", __FUNCTION__, scope);
4070			i++;
4071		}
4072
4073		if ((session->probe_addrs[ALT_PEER_ADDR_PROBE].sin_family == AF_INET) &&
4074			session->probe_addrs[ALT_PEER_ADDR_PROBE].sin_addr.s_addr) {
4075			dbglog("%s: found alternate peer address", __FUNCTION__);
4076			// alternate vpn server
4077			if ((session->probe_fds[ALT_PEER_ADDR_PROBE] = ppp_scoped_ping(session->probe_fds[ALT_PEER_ADDR_PROBE],
4078																		   scope,
4079																		   &session->probe_addrs[ALT_PEER_ADDR_PROBE],
4080																		   session->probe_ntransmit)) != -1) {
4081				add_fd(session->probe_fds[ALT_PEER_ADDR_PROBE]);
4082				info("%s: sent to alternate peer over scope %d", __FUNCTION__, scope);
4083				i++;
4084			}
4085		} else {
4086			dbglog("%s: no alternate peer address", __FUNCTION__);
4087		}
4088	} else {
4089		dbglog("%s: no peer address", __FUNCTION__);
4090	}
4091	if (i) {
4092		dbglog("%s: %d probes sent", __FUNCTION__, i);
4093		session->probe_tries++;
4094		if (!session->probe_timer_running) {
4095			session->probe_timer_running = 1;
4096			TIMEOUT(ppp_ip_probe_timeout, 0, 3);
4097		}
4098		return 0;
4099	}
4100	return -1;
4101}
4102
4103int
4104ppp_ip_probe_stop (void *arg)
4105{
4106	int i;
4107
4108	if (!session || !session->valid) {
4109		return -1;
4110	}
4111
4112	if (session->probe_timer_running) {
4113		session->probe_timer_running = 0;
4114		UNTIMEOUT(ppp_ip_probe_timeout, 0);
4115		dbglog("ppp_auxiliary_probe stopped");
4116	}
4117
4118	for (i = 0; i < MAX_PROBE_ADDRS; i++) {
4119		if (session->probe_fds[i] > 0) {
4120			remove_fd(session->probe_fds[i]);
4121			close(session->probe_fds[i]);
4122			session->probe_fds[i] = -1;
4123		}
4124	}
4125	session->probe_tries = 0;
4126	session->probe_success = 0;
4127	return 0;
4128}
4129
4130static void
4131ppp_ip_probe_timeout (void *arg)
4132{
4133	if (!session || !session->valid) {
4134		return;
4135	}
4136
4137	if (session->probe_tries < 15) {
4138		if (!ppp_ip_probe_send(arg)) {
4139			return;
4140		}
4141	}
4142	error("ppp_auxiliary_probe timed out");
4143}
4144
4145void ppp_session_clear (ppp_session_t *sess)
4146{
4147	int i;
4148
4149	if (sess) {
4150		bzero(sess, sizeof(*sess));
4151		for (i = 0; i < MAX_PROBE_ADDRS; i++) {
4152			sess->probe_fds[i] = -1;
4153		}
4154	}
4155}
4156
4157int
4158ppp_variable_echo_is_off (void)
4159{
4160	if (!session || !session->valid) {
4161		return 1;
4162	}
4163	return(!wait_underlying_interface_up);
4164}
4165
4166void
4167ppp_variable_echo_start (void)
4168{
4169	if (!session || !session->valid) {
4170		return;
4171	}
4172    if (wait_underlying_interface_up || wait_port_mapping_changed) {
4173        // speed up LCP echos
4174        if (!lcp_echos_hastened) {
4175			dbglog("ppp_variable_echo_start");
4176            lcp_echo_interval_slow = lcp_echo_interval;
4177            lcp_echo_interval = 1;
4178            lcp_echo_fails_slow = lcp_echo_fails;
4179            if (lcp_echo_fails > 10) {
4180                lcp_echo_fails = 10; // max of 10 secs
4181            }
4182            lcp_echos_hastened = 1;
4183            lcp_echo_restart(0);
4184        }
4185    }
4186}
4187
4188void
4189ppp_variable_echo_stop (void)
4190{
4191	if (!session || !session->valid) {
4192		return;
4193	}
4194    if (wait_underlying_interface_up || wait_port_mapping_changed) {
4195        dbglog("received echo-reply, ppp_variable_echo_stop!");
4196        wait_underlying_interface_up = 0;
4197        wait_port_mapping_changed = 0;
4198        if (lcp_echos_hastened) {
4199            lcp_echo_interval = lcp_echo_interval_slow;
4200            lcp_echo_fails = lcp_echo_fails_slow;
4201            lcp_echos_hastened = 0;
4202        }
4203    }
4204}
4205
4206void ppp_auxiliary_probe_ip_up(void *arg, uintptr_t p)
4207{
4208	ppp_auxiliary_probe_ip = 1;
4209}
4210
4211void ppp_auxiliary_probe_ip_down(void *arg, uintptr_t p)
4212{
4213	ppp_auxiliary_probe_ip = 0;
4214}
4215
4216void
4217ppp_auxiliary_probe_init (void)
4218{
4219	ppp_auxiliary_probe_echos_pending = 0;
4220	ppp_auxiliary_probe_success = 0;
4221	if (!ppp_auxiliary_probe_ip_notify_init) {
4222		add_notifier(&ip_up_notify, ppp_auxiliary_probe_ip_up, 0);
4223		add_notifier(&ip_down_notify, ppp_auxiliary_probe_ip_down, 0);
4224		ppp_auxiliary_probe_ip_notify_init= 1;
4225	}
4226}
4227
4228void
4229ppp_auxiliary_probe_stop (void)
4230{
4231	ppp_ip_probe_stop(session);
4232	ppp_auxiliary_probe_echos_pending = 0;
4233	ppp_auxiliary_probe_success = 0;
4234}
4235
4236void
4237ppp_auxiliary_probe_check (int                    echos_pending,
4238							probe_disconnect_func  disconnect_func,
4239							fsm                   *f)
4240{
4241	if (ppp_auxiliary_probe_ip &&
4242		!wait_underlying_interface_up &&
4243		!wait_port_mapping_changed &&
4244		echos_pending > 1){
4245		// more than 2 echo responses pending: try probing the network
4246		if (!ppp_auxiliary_probe_echos_pending) {
4247			// probe hasn't been started
4248			error("no echo-reply, start ppp_auxiliary_probe!");
4249			ppp_ip_probe_send(session);
4250			ppp_auxiliary_probe_echos_pending = 1;
4251			ppp_auxiliary_probe_success = 0;
4252		} else if (++ppp_auxiliary_probe_echos_pending > 1 &&
4253				   ppp_auxiliary_probe_success) {
4254			// we have more than 3 pending echo responses, while the network
4255			// probe succeeded... disconnect
4256			error("no echo-reply, despite successful ppp_auxiliary_probe!");
4257			// network probe succeeded but no echo replies, disconnect
4258			if (disconnect_func) {
4259				disconnect_func(f);
4260			}
4261		}
4262	}
4263}
4264
4265void
4266ppp_process_auxiliary_probe_input (void)
4267{
4268	int i, j, result;
4269
4270	if (!session || !session->valid) {
4271		return;
4272	}
4273
4274	for (i = 0, j = 0; i < MAX_PROBE_ADDRS; i++) {
4275		if (session->probe_fds[i] > 0 && is_ready_fd(session->probe_fds[i])) {
4276			result = 0;
4277			read(session->probe_fds[i], &result, 1);
4278			remove_fd(session->probe_fds[i]);
4279			if (result > 0) {
4280				// assume success for now. TODO: log and ignore alt-peer success
4281				session->probe_success++;
4282				j++;
4283				dbglog("ppp_auxiliary_probe[%d] response!", i);
4284			}
4285			close(session->probe_fds[i]);
4286			session->probe_fds[i] = -1;
4287		}
4288	}
4289	if (j) {
4290		if (session->probe_timer_running) {
4291			session->probe_timer_running = 0;
4292			UNTIMEOUT(ppp_ip_probe_timeout, 0);
4293		}
4294		if (ppp_auxiliary_probe_echos_pending) {
4295			ppp_auxiliary_probe_success++;
4296		}
4297	}
4298}
4299
4300#if !TARGET_OS_EMBEDDED
4301static void
4302ppp_clear_one_nat_port_mapping (mdns_nat_mapping_t *mapping)
4303{
4304	if (mapping) {
4305		// what about mapping->mDNSRef_fd?
4306		if (mapping->mDNSRef != NULL) {
4307			if (mapping->mDNSRef_fd)
4308				remove_fd(mapping->mDNSRef_fd);
4309			DNSServiceRefDeallocate(mapping->mDNSRef);
4310		}
4311		bzero(mapping, sizeof(*mapping));
4312	}
4313}
4314
4315static int
4316ppp_ignore_nat_port_mapping_update (DNSServiceRef       sdRef,
4317									char               *sd_name,
4318									char               *if_name,
4319									uint32_t            if_name_siz,
4320									uint32_t            interfaceIndex,
4321									uint32_t            publicAddress,
4322									DNSServiceProtocol  protocol,
4323									uint16_t            privatePort,
4324									uint16_t            publicPort)
4325{
4326	int i = 0, vpn = 0, found = 0;
4327	struct ifaddrs *ifap = NULL;
4328	char interfaceName[32];
4329
4330	/* check if address still exist */
4331	if (getifaddrs(&ifap) == 0) {
4332		struct ifaddrs *ifa;
4333		for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
4334			if (ifa->ifa_name
4335				&& ifa->ifa_addr
4336				&& (!strncmp(ifa->ifa_name, "utun", 4) || !strncmp(ifa->ifa_name, "ppp", 3))
4337				&& ifa->ifa_addr->sa_family == AF_INET
4338				&& ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == htonl(publicAddress)) {
4339				notice("%s port-mapping update for %s ignored: related to VPN interface. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n",
4340					   sd_name,
4341					   ifa->ifa_name,
4342					   publicAddress,
4343					   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4344					   privatePort,
4345					   publicPort);
4346				vpn = 1;
4347			}
4348			if (ifa->ifa_name
4349				&& ifa->ifa_addr
4350				&& !strncmp(ifa->ifa_name, if_name, if_name_siz)
4351				&& ifa->ifa_addr->sa_family == AF_INET
4352				&& ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == session->interface_address.s_addr) {
4353				found = 1;
4354			}
4355		}
4356		freeifaddrs(ifap);
4357	} else {
4358		error("%s port-mapping update for %s ignored: failed to get interface list",
4359			  sd_name,
4360			  if_name);
4361		return 1;
4362	}
4363
4364	if (vpn) {
4365		return 1;
4366	}
4367	bzero(interfaceName, sizeof(interfaceName));
4368	if_indextoname(interfaceIndex, (char *)interfaceName);
4369	if (!strncmp(interfaceName, if_name, if_name_siz)) {
4370		if (strstr(if_name, "ppp") || strstr(if_name, "utun")) {
4371			// change on PPP interface... we don't care
4372			notice("%s port-mapping update for %s ignored: underlying interface is PPP/VPN. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n",
4373				   sd_name,
4374				   if_name,
4375				   publicAddress,
4376				   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4377				   privatePort,
4378				   publicPort);
4379			return 1;
4380		} else {
4381			/* check if address still exist */
4382			if (found) {
4383				return 0;
4384			} else {
4385				if (!publicAddress || (!publicPort && privatePort)) {
4386					notice("%s port-mapping update for %s ignored: underlying interface down. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n",
4387						   sd_name,
4388						   if_name,
4389						   publicAddress,
4390						   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4391						   privatePort,
4392						   publicPort);
4393					for (i = 0; i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) {
4394						if (session->nat_mapping[i].mDNSRef_tmp == sdRef) {
4395							session->nat_mapping[i].up = 0;
4396							notice("%s port-mapping for %s flagged down because of no connectivity\n", sd_name, if_name);
4397						}
4398					}
4399					return 1;
4400				}
4401				notice("%s port-mapping update for %s ignored: underlying interface's address changed. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n",
4402					   sd_name,
4403					   if_name,
4404					   publicAddress,
4405					   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4406					   privatePort,
4407					   publicPort);
4408				return 1;
4409			}
4410		}
4411	} else if (publicAddress && !publicPort && !privatePort && !protocol) {
4412		// an update on the NAT's public IP
4413		return 0;
4414	} else {
4415		// public interface disappeared?
4416		if (!publicAddress && !publicPort && !privatePort && !protocol) {
4417			return 0;
4418		}
4419		/* check if address still exist */
4420		if (session->interface_address.s_addr == htonl(publicAddress) && found) {
4421			return 0;
4422		}
4423		// change due to another interface, ignore for now
4424		notice("%s port-mapping update for %s ignored: not for interface %s. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n",
4425			   sd_name,
4426			   interfaceName,
4427			   if_name,
4428			   publicAddress,
4429			   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4430			   privatePort,
4431			   publicPort);
4432		return 1;
4433	}
4434}
4435#endif
4436
4437static void
4438ppp_public_nat_port_mapping_timeout (void *arg)
4439{
4440	if (!session || !session->valid) {
4441		return;
4442	}
4443
4444	if (session->nat_mapping_timer_running) {
4445		session->nat_mapping_timer_running = 0;
4446		sys_log(LOG_ERR, "NAT's public interface down for more than %d secs... starting faster probe.\n",
4447			   PUBLIC_NAT_PORT_MAPPING_TIMEOUT);
4448		// our public interface didn't come back... start faster probe
4449		if (session->failure_func) {
4450			wait_port_mapping_changed = 1;
4451			session->failure_func();
4452		}
4453	}
4454}
4455
4456void
4457ppp_start_public_nat_port_mapping_timer (void)
4458{
4459	if (!session || !session->valid) {
4460		return;
4461	}
4462
4463	if (session->nat_mapping_timer_blocked) {
4464		return;
4465	}
4466
4467	if (session->nat_mapping_timer_running) {
4468		return;
4469	}
4470
4471	notice("starting wait-port-mapping timer for %s: %d secs", session->sd_name, PUBLIC_NAT_PORT_MAPPING_TIMEOUT);
4472	TIMEOUT (ppp_public_nat_port_mapping_timeout, 0, PUBLIC_NAT_PORT_MAPPING_TIMEOUT);
4473	session->nat_mapping_timer_running = 1;
4474}
4475
4476void
4477ppp_stop_public_nat_port_mapping_timer (void)
4478{
4479	if (!session || !session->valid) {
4480		return;
4481	}
4482
4483	if (session->nat_mapping_timer_running) {
4484		UNTIMEOUT (ppp_public_nat_port_mapping_timeout, 0);
4485		session->nat_mapping_timer_running = 0;
4486	}
4487}
4488
4489void
4490ppp_block_public_nat_port_mapping_timer (void)
4491{
4492	if (!session || !session->valid) {
4493		return;
4494	}
4495
4496	ppp_stop_public_nat_port_mapping_timer();
4497	session->nat_mapping_timer_blocked = 1;
4498}
4499
4500void
4501ppp_unblock_public_nat_port_mapping_timer (void)
4502{
4503	if (!session || !session->valid) {
4504		return;
4505	}
4506
4507	session->nat_mapping_timer_blocked = 0;
4508}
4509
4510#if !TARGET_OS_EMBEDDED
4511
4512static void ppp_clear_nat_port_mapping(void);
4513
4514static void
4515ppp_set_nat_port_mapping_callback (DNSServiceRef        sdRef,
4516								   DNSServiceFlags      flags,
4517								   uint32_t             interfaceIndex,
4518								   DNSServiceErrorType  errorCode,
4519								   uint32_t             nPublicAddress,	   /* four byte IPv4 address in network byte order */
4520								   DNSServiceProtocol   protocol,
4521								   uint16_t             nPrivatePort,
4522								   uint16_t             nPublicPort,	   /* may be different than the requested port */
4523								   uint32_t             ttl,			   /* may be different than the requested ttl */
4524								   void                *context)
4525{
4526	uint32_t publicAddress = ntohl(nPublicAddress);
4527	uint16_t privatePort = ntohs(nPrivatePort);
4528	uint16_t publicPort = ntohs(nPublicPort);
4529	int i;
4530	char *sd_name = session->sd_name;
4531	int is_connected = session->valid;
4532	char *if_name = session->interface_name;
4533	uint32_t if_name_siz = session->interface_name_siz;
4534
4535	if (!session || !session->valid) {
4536		return;
4537	}
4538
4539	if (override_primary) {
4540		info("%s port-mapping update for %s ignored: VPN is the Primary interface. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n",
4541			 sd_name,
4542			 if_name,
4543			 publicAddress,
4544			 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4545			 privatePort,
4546			 publicPort);
4547		ppp_clear_nat_port_mapping();
4548		return;
4549	}
4550
4551	if (errorCode != kDNSServiceErr_NoError && errorCode != kDNSServiceErr_DoubleNAT) {
4552		error("%s failed to set port-mapping for %s, errorCode: %d\n", sd_name, if_name, errorCode);
4553		if (errorCode == kDNSServiceErr_NATPortMappingUnsupported || errorCode == kDNSServiceErr_NATPortMappingDisabled) {
4554			for (i = 0; i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) {
4555				if (session->nat_mapping[i].mDNSRef_tmp == sdRef) {
4556					error("%s port-mapping for %s became invalid. is Connected: %d, Protocol: %s, Private Port: %d, Previous publicAddress: (%x), Previous publicPort: (%d)\n",
4557						  sd_name,
4558						  if_name,
4559						  is_connected,
4560						  (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4561						  privatePort,
4562						  session->nat_mapping[i].reflexive.addr,
4563						  session->nat_mapping[i].reflexive.port);
4564					if (session->nat_mapping[i].up && is_connected && session->failure_func) {
4565						notice("%s public port-mapping for %s changed... starting faster probe.\n", sd_name, if_name);
4566						wait_port_mapping_changed = 1;
4567						session->failure_func();
4568					} else {
4569						ppp_clear_nat_port_mapping();
4570					}
4571					return;
4572				}
4573			}
4574		} else if (errorCode == kDNSServiceErr_ServiceNotRunning) {
4575			ppp_clear_nat_port_mapping();
4576		}
4577		return;
4578	}
4579
4580	if (ppp_ignore_nat_port_mapping_update(sdRef, sd_name, if_name, if_name_siz, interfaceIndex, publicAddress, protocol, privatePort, publicPort)) {
4581		return;
4582	}
4583
4584	info("%s port-mapping for %s, interfaceIndex: %d, Protocol: %s, Private Port: %d, Public Address: %x, Public Port: %d, TTL: %d%s\n",
4585		 sd_name,
4586		 if_name,
4587		 interfaceIndex,
4588		 (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4589		 privatePort,
4590		 publicAddress,
4591		 publicPort,
4592		 ttl,
4593		 (errorCode == kDNSServiceErr_DoubleNAT)? " (Double NAT)" : ".");
4594
4595	// generate a disconnect if we were already connected and we just detected a change in publicAddress or publicPort
4596	for (i = 0; i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) {
4597		if (session->nat_mapping[i].mDNSRef_tmp == sdRef) {
4598			if (session->nat_mapping[i].up && !publicAddress && !publicPort) {
4599				notice("%s port-mapping for %s indicates public interface down. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n",
4600					   sd_name,
4601					   if_name,
4602					   publicAddress,
4603					   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4604					   privatePort,
4605					   publicPort);
4606				// start timer
4607				ppp_start_public_nat_port_mapping_timer();
4608				return;
4609			} else if (session->nat_mapping[i].up) {
4610				ppp_stop_public_nat_port_mapping_timer();
4611			}
4612
4613			if (session->interface_address.s_addr == htonl(publicAddress) && privatePort == publicPort) {
4614				notice("%s port-mapping update for %s indicates no NAT. Public Address: %x, Protocol: %s, Private Port: %d, Public Port: %d\n",
4615					   sd_name,
4616					   if_name,
4617					   publicAddress,
4618					   (protocol == 0)? "None":((protocol == kDNSServiceProtocol_UDP)? "UDP":"TCP"),
4619					   privatePort,
4620					   publicPort);
4621			}
4622
4623			if (session->nat_mapping[i].interfaceIndex == interfaceIndex &&
4624				session->nat_mapping[i].protocol == protocol &&
4625				session->nat_mapping[i].privatePort == privatePort) {
4626				info("%s port-mapping for %s consistent. is Connected: %d, interface: %d, protocol: %d, privatePort: %d\n",
4627					 sd_name, if_name, is_connected, interfaceIndex, protocol, privatePort);
4628			} else {
4629				// inconsistency (mostly because of mdns api only works for the primary interface): TODO revise
4630				if (session->nat_mapping[i].interfaceIndex != interfaceIndex) {
4631					info("%s port-mapping for %s inconsistent. is Connected: %d, Previous interface: %d, Current interface %d\n",
4632						 sd_name, if_name, is_connected, session->nat_mapping[i].interfaceIndex, interfaceIndex);
4633					session->nat_mapping[i].interfaceIndex = interfaceIndex;
4634				}
4635				if (session->nat_mapping[i].protocol != protocol) {
4636					info("%s port-mapping for %s inconsistent. is Connected: %d, Previous protocol: %x, Current protocol %x\n",
4637						 sd_name, if_name, is_connected, session->nat_mapping[i].protocol, protocol);
4638					session->nat_mapping[i].protocol = protocol;
4639				}
4640				if (session->nat_mapping[i].privatePort != privatePort) {
4641					info("%s port-mapping for %s inconsistent. is Connected: %d, Previous privatePort: %d, Current privatePort %d\n",
4642						 sd_name, if_name, session->nat_mapping[i].privatePort, privatePort);
4643					session->nat_mapping[i].privatePort = privatePort;
4644				}
4645			}
4646			// is mapping up?
4647			if (!session->nat_mapping[i].up) {
4648				if (session->nat_mapping[i].reflexive.addr != publicAddress) {
4649					info("%s port-mapping for %s initialized. is Connected: %d, Previous publicAddress: (%d), Current publicAddress %x\n",
4650						 sd_name, if_name, is_connected, session->nat_mapping[i].reflexive.addr, publicAddress);
4651					session->nat_mapping[i].reflexive.addr = publicAddress;
4652				}
4653				if (session->nat_mapping[i].reflexive.port != publicPort) {
4654					info("%s port-mapping for %s initialized. is Connected: %d, Previous publicPort: (%d), Current publicPort %d\n",
4655						 sd_name, if_name, is_connected, session->nat_mapping[i].reflexive.port, publicPort);
4656					session->nat_mapping[i].reflexive.port = publicPort;
4657				}
4658				if (session->nat_mapping[i].reflexive.addr &&
4659				    ((!privatePort && !session->nat_mapping[i].reflexive.port) || (session->nat_mapping[i].reflexive.port))) {
4660					// flag up mapping
4661					session->nat_mapping[i].up = 1;
4662					info("%s port-mapping for %s fully initialized. Flagging up\n", sd_name, if_name);
4663				}
4664				return;
4665			}
4666
4667			if (session->nat_mapping[i].reflexive.addr != publicAddress) {
4668				error("%s port-mapping for %s changed. is Connected: %d, Previous publicAddress: (%x), Current publicAddress %x\n",
4669					  sd_name, if_name, is_connected, session->nat_mapping[i].reflexive.addr, publicAddress);
4670				if (is_connected) {
4671					if (!privatePort || publicAddress) {
4672						sys_log(LOG_ERR, "NAT's public address down or changed... starting faster probe.\n");
4673						if (session->failure_func) {
4674                            wait_port_mapping_changed = 1;
4675							session->failure_func();
4676						}
4677						return;
4678					}
4679					// let function that handles (KEV_INET_NEW_ADDR || KEV_INET_CHANGED_ADDR || KEV_INET_ADDR_DELETED) deal with the connection
4680					return;
4681				}
4682				session->nat_mapping[i].reflexive.addr = publicAddress;
4683				return;
4684			}
4685			if (session->nat_mapping[i].reflexive.port != publicPort) {
4686				error("%s port-mapping for %s changed. is Connected: %d, Previous publicPort: (%d), Current publicPort %d\n",
4687					  sd_name, if_name, is_connected, session->nat_mapping[i].reflexive.port, publicPort);
4688				if (is_connected) {
4689					if (!privatePort || publicPort) {
4690						sys_log(LOG_ERR, "NAT's public port down or changed... starting faster probe.\n");
4691						if (session->failure_func) {
4692							wait_port_mapping_changed = 1;
4693							session->failure_func();
4694						}
4695						return;
4696					}
4697					// let function that handles (KEV_INET_NEW_ADDR || KEV_INET_CHANGED_ADDR || KEV_INET_ADDR_DELETED) deal with the connection
4698					return;
4699				}
4700				session->nat_mapping[i].reflexive.port = publicPort;
4701				return;
4702			}
4703			if (errorCode == kDNSServiceErr_DoubleNAT) {
4704				error("%s port-mapping for %s hasn't changed, however there's a Double NAT.  is Connected: %d\n",
4705					  sd_name, if_name, is_connected);
4706			}
4707			return;
4708		}
4709	}
4710	return;
4711}
4712
4713static void
4714ppp_clear_nat_port_mapping (void)
4715{
4716	int i;
4717
4718	if (!session || !session->valid)
4719		return;
4720
4721	info("%s clearing port-mapping for %s\n", session->sd_name, session->interface_name);
4722
4723	ppp_stop_public_nat_port_mapping_timer();
4724
4725	for (i = 0; i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) {
4726		ppp_clear_one_nat_port_mapping(&session->nat_mapping[i]);
4727	}
4728	session->nat_mapping_cnt = 0;
4729}
4730
4731static int
4732ppp_set_nat_port_mapping (mdns_nat_mapping_t *mapping,
4733						  DNSServiceProtocol  protocol,
4734						  uint16_t            privatePort,
4735						  int                 probe_only)
4736{
4737	DNSServiceErrorType  err = kDNSServiceErr_NoError;
4738	uint16_t             publicPort;
4739	uint32_t             ttl;
4740	char                *sd_name = session->sd_name;
4741	char                *if_name = session->interface_name;
4742	uint32_t             interfaceIndex = if_nametoindex(session->interface_name);
4743
4744	if (!probe_only) {
4745		publicPort = 0;
4746		ttl = 2 * 3600; // 2 hours
4747	} else {
4748		publicPort = 0;
4749		ttl = 0;
4750		protocol = 0;
4751		privatePort = 0;
4752	}
4753
4754	if (mapping == NULL) {
4755		error("%s invalid mapping pointer for %s\n", sd_name, if_name);
4756		return -1;
4757	}
4758
4759	if (mapping->mDNSRef == NULL) {
4760		err = DNSServiceCreateConnection(&mapping->mDNSRef);
4761		if (err != kDNSServiceErr_NoError || mapping->mDNSRef == NULL) {
4762			error("%s Error calling DNSServiceCreateConnection for %s, error: %d\n", sd_name, if_name, err);
4763			ppp_clear_one_nat_port_mapping(mapping);
4764			return -1;
4765		}
4766		mapping->mDNSRef_fd = DNSServiceRefSockFD(mapping->mDNSRef);
4767		add_fd(mapping->mDNSRef_fd);
4768	}
4769	mapping->mDNSRef_tmp = mapping->mDNSRef;
4770	err = DNSServiceNATPortMappingCreate(&mapping->mDNSRef_tmp, kDNSServiceFlagsShareConnection, interfaceIndex, protocol, htons(privatePort), publicPort, ttl, ppp_set_nat_port_mapping_callback, session);
4771	if (err != kDNSServiceErr_NoError) {
4772		error("%s Error calling DNSServiceNATPortMappingCreate for %s, error: %d\n", sd_name, if_name, err);
4773		ppp_clear_one_nat_port_mapping(mapping);
4774		return -1;
4775	}
4776	mapping->interfaceIndex = interfaceIndex;
4777	mapping->protocol = protocol;
4778	mapping->privatePort = privatePort;
4779	bzero(&mapping->reflexive, sizeof(mapping->reflexive));
4780
4781	info("%s set port-mapping for %s, interface: %d, protocol: %d, privatePort: %d\n", sd_name, if_name, interfaceIndex, protocol, privatePort);
4782	return 0;
4783}
4784
4785static void
4786l2tp_ipsec_set_nat_port_mapping (void)
4787{
4788	if (ppp_set_nat_port_mapping(&session->nat_mapping[0], 0, 0, 1) == 0) {
4789		session->nat_mapping_cnt++;
4790	}
4791#if 0 // <rdar://problem/8001582>
4792	if (ppp_set_nat_port_mapping(&session->nat_mapping[1], kDNSServiceProtocol_UDP, (u_int16_t)500, 0) == 0) {
4793		session->nat_mapping_cnt++;
4794	}
4795	if (ppp_set_nat_port_mapping(&session->nat_mapping[2], kDNSServiceProtocol_UDP, (u_int16_t)4500, 0) == 0) {
4796		session->nat_mapping_cnt++;
4797	}
4798#endif
4799}
4800#endif
4801
4802void
4803l2tp_set_nat_port_mapping (void)
4804{
4805#if !TARGET_OS_EMBEDDED
4806	if (!session || !session->valid) {
4807		return;
4808	}
4809
4810	if (override_primary) {
4811		info("%s port-mapping API for %s ignored: VPN is the Primary interface.\n",
4812             session->sd_name,
4813             session->interface_name);
4814		return;
4815	}
4816
4817	// exit early if interface is PPP/VPN
4818	if (strstr(session->interface_name, "ppp") || strstr(session->interface_name, "utun")) {
4819		return;
4820	}
4821
4822	if (!session->opt_noipsec) {
4823		// we always tranport l2tp over ipsec
4824		l2tp_ipsec_set_nat_port_mapping();
4825	} else {
4826		if (ppp_set_nat_port_mapping(&session->nat_mapping[0], 0, 0, 1) == 0) {
4827			session->nat_mapping_cnt++;
4828		}
4829#if 0 // <rdar://problem/8001582>
4830		if (ppp_set_nat_port_mapping(&session->nat_mapping[1], kDNSServiceProtocol_UDP, (u_int16_t)1701, 0) == 0) {
4831			session->nat_mapping_cnt++;
4832		}
4833#endif
4834	}
4835#endif // TARGET_OS_EMBEDDED
4836}
4837
4838void
4839l2tp_clear_nat_port_mapping (void)
4840{
4841#if !TARGET_OS_EMBEDDED
4842	ppp_clear_nat_port_mapping();
4843#endif // TARGET_OS_EMBEDDED
4844}
4845
4846void
4847pptp_set_nat_port_mapping (void)
4848{
4849#if !TARGET_OS_EMBEDDED
4850	if (!session || !session->valid) {
4851		return;
4852	}
4853
4854	if (override_primary) {
4855		info("%s port-mapping API for %s ignored: VPN is the Primary interface.\n",
4856             session->sd_name,
4857             session->interface_name);
4858		return;
4859	}
4860
4861	// exit early if interface is PPP/VPN
4862	if (strstr(session->interface_name, "ppp") || strstr(session->interface_name, "utun")) {
4863		return;
4864	}
4865
4866	if (ppp_set_nat_port_mapping(&session->nat_mapping[0], 0, 0, 1) == 0) {
4867		session->nat_mapping_cnt++;
4868	}
4869#if 0 // <rdar://problem/8001582>
4870	if (ppp_set_nat_port_mapping(&session->nat_mapping[1], kDNSServiceProtocol_TCP, (u_int16_t)1723, 0) == 0) {
4871		session->nat_mapping_cnt++;
4872	}
4873#endif
4874#endif // TARGET_OS_EMBEDDED
4875}
4876
4877void
4878pptp_clear_nat_port_mapping (void)
4879{
4880#if !TARGET_OS_EMBEDDED
4881	ppp_clear_nat_port_mapping();
4882#endif // TARGET_OS_EMBEDDED
4883}
4884
4885void
4886ppp_process_nat_port_mapping_events (void)
4887{
4888#if !TARGET_OS_EMBEDDED
4889	int i = 0;
4890	DNSServiceErrorType ret;
4891
4892	for (i = 0; session && session->valid && i < session->nat_mapping_cnt && i < MDNS_NAT_MAPPING_MAX; i++) {
4893		if (session->nat_mapping[i].mDNSRef && is_ready_fd(session->nat_mapping[i].mDNSRef_fd)) {
4894			ret = DNSServiceProcessResult(session->nat_mapping[i].mDNSRef);
4895			if (ret != kDNSServiceErr_NoError && ret != kDNSServiceErr_Transient) {
4896				error("Error calling DNSServiceProcessResult, error: %d\n", ret);
4897				if (ret == kDNSServiceErr_ServiceNotRunning) {
4898					ppp_clear_nat_port_mapping();
4899				}
4900			}
4901			// the connection may have been disconnected... hence session may be invalidated after DNSServiceProcessResult.
4902		}
4903	}
4904#endif // TARGET_OS_EMBEDDED
4905}
4906
4907int
4908sys_setup_security_session(void)
4909{
4910	if (ne_is_controller()) {
4911		return (!ne_setup_security_session());
4912	} else {
4913		return setup_security_context();
4914	}
4915}
4916
4917void
4918sys_log(int priority, const char *message, ...)
4919{
4920	if (ne_is_controller()) {
4921		if (nelog_is_logging_at_level(priority)) {
4922			va_list args;
4923
4924			va_start(args, message);
4925			nelogv(priority, message, args);
4926			va_end(args);
4927		}
4928	} else {
4929		va_list args;
4930		va_start(args, message);
4931		vsyslog(priority, message, args);
4932		va_end(args);
4933	}
4934}
4935