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