/* ----------------------------------------------------------------------------- plugin entry point, called by vpnd ref is the vpn bundle reference pppref is the ppp bundle reference bundles can be layout in two different ways - As simple vpn bundles (bundle.vpn). the bundle contains the vpn bundle binary. - As full ppp bundles (bundle.ppp). The bundle contains the ppp bundle binary, and also the vpn kext and the vpn bundle binary in its Plugins directory. if a simple vpn bundle was used, pppref will be NULL. if a ppp bundle was used, the vpn plugin will be able to get access to the Plugins directory and load the vpn kext. ----------------------------------------------------------------------------- */ int start(struct vpn_channel* the_vpn_channel, CFBundleRef ref, CFBundleRef pppref, int debug_mode) { char name[MAXPATHLEN]; CFURLRef url; debug = debug_mode; /* first load the kext if we are loaded as part of a ppp bundle */ if (pppref) { while ((listen_sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) break; if (listen_sockfd < 0) { vpnlog(LOG_DEBUG, "first call to socket failed - attempting to load kext\n"); if (url = CFBundleCopyBundleURL(pppref)) { name[0] = 0; CFURLGetFileSystemRepresentation(url, 0, name, MAXPATHLEN - 1); CFRelease(url); strcat(name, "/"); if (url = CFBundleCopyBuiltInPlugInsURL(pppref)) { CFURLGetFileSystemRepresentation(url, 0, name + strlen(name), MAXPATHLEN - strlen(name) - strlen(L2TP_NKE) - 1); CFRelease(url); strcat(name, "/"); strcat(name, L2TP_NKE); if (!load_kext(name)) while ((listen_sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) break; } } if (listen_sockfd < 0) { vpnlog(LOG_ERR, "VPND L2TP plugin: Unable to load L2TP kernel extension\n"); return -1; } } } /* retain reference */ bundle = ref; CFRetain(bundle); pppbundle = pppref; CFRetain(pppbundle); // hookup our socket handlers bzero(the_vpn_channel, sizeof(struct vpn_channel)); the_vpn_channel->get_pppd_args = l2tpvpn_get_pppd_args; the_vpn_channel->listen = l2tpvpn_listen; the_vpn_channel->accept = l2tpvpn_accept; the_vpn_channel->refuse = l2tpvpn_refuse; the_vpn_channel->close = l2tpvpn_close; return 0; }
int main() { if (geteuid()) { syslog(LOG_ERR,"Error: Daemon must run as root."); exit(geteuid()); } encrypt_buffer = CFDataCreateMutable(kCFAllocatorDefault,8); /*********Set up File**********/ if (!(pathName = (CFStringRef)CFPreferencesCopyAppValue(PATHNAME_PREF_KEY,PREF_DOMAIN))) { pathName = CFSTR(DEFAULT_PATHNAME); CFPreferencesSetAppValue(PATHNAME_PREF_KEY,pathName,PREF_DOMAIN); } CFURLRef logPathURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,pathName,kCFURLPOSIXPathStyle,false); logStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault,logPathURL); CFRelease(logPathURL); if (!logStream) { syslog(LOG_ERR,"Error: Couldn't open file stream at start."); return 1; } /*********Check encryption & keymap**********/ updateEncryption(); updateKeymap(); /*********Check space**********/ if (outOfSpace(pathName)) { stamp_file(CFSTR("Not enough disk space remaining!")); CFRunLoopStop(CFRunLoopGetCurrent()); } /*********Connect to kernel extension**********/ if (!connectToKext()) { if (load_kext()) { stamp_file(CFSTR("Could not load KEXT")); return 1; } if (!connectToKext()) { stamp_file(CFSTR("Could not connect with KEXT")); return 1; } } sleep(1); // just a little time to let the kernel notification handlers finish stamp_file(CFSTR("LogKext Daemon starting up")); // stamp login file with initial user LoginLogoutCallBackFunction(NULL, NULL, NULL); CFPreferencesAppSynchronize(PREF_DOMAIN); /*********Create Daemon Timer source**********/ CFRunLoopTimerContext timerContext = { 0 }; CFRunLoopSourceRef loginLogoutSource; if (InstallLoginLogoutNotifiers(&loginLogoutSource)) syslog(LOG_ERR,"Error: could not install login notifier"); else CFRunLoopAddSource(CFRunLoopGetCurrent(),loginLogoutSource, kCFRunLoopDefaultMode); CFRunLoopTimerRef daemonTimer = CFRunLoopTimerCreate(NULL, 0, TIME_TO_SLEEP, 0, 0, DaemonTimerCallback, &timerContext); CFRunLoopAddTimer(CFRunLoopGetCurrent(), daemonTimer, kCFRunLoopCommonModes); CFRunLoopRun(); stamp_file(CFSTR("Server error: closing Daemon")); CFWriteStreamClose(logStream); }
/* ----------------------------------------------------------------------------- get the socket ready to start doing PPP. That is, open the socket and run the connector ----------------------------------------------------------------------------- */ int pppoe_connect(int *errorcode) { char dev[32], name[MAXPATHLEN]; int err = 0, len, s; CFURLRef url; struct ifreq ifr; *errorcode = 0; snprintf(dev, sizeof(dev), "socket[%d:%d]", PF_PPP, PPPPROTO_PPPOE); strlcpy(ppp_devnam, dev, sizeof(ppp_devnam)); hungup = 0; kill_link = 0; linkdown = 0; err = -1; s = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT); if (s >= 0) { len = strlen(device); if (len <= sizeof(ifr.ifr_name)) { bzero(&ifr, sizeof(ifr)); bcopy(device, ifr.ifr_name, len); if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0) { // ensure that the device is UP ifr.ifr_flags |= IFF_UP; if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) >= 0) err = 0; } } close(s); } if (err) { error("PPPoE cannot use interface '%s'.", device); status = EXIT_OPEN_FAILED; return -1; } if (strcmp(mode, MODE_ANSWER)) { /* open the socket */ sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_PPPOE); if (sockfd < 0) { if (!noload) { if (url = CFBundleCopyBundleURL(bundle)) { name[0] = 0; CFURLGetFileSystemRepresentation(url, 0, (UInt8 *)name, MAXPATHLEN - 1); CFRelease(url); strlcat(name, "/", sizeof(name)); if (url = CFBundleCopyBuiltInPlugInsURL(bundle)) { CFURLGetFileSystemRepresentation(url, 0, (UInt8 *)(name + strlen(name)), MAXPATHLEN - strlen(name) - strlen(PPPOE_NKE) - 1); CFRelease(url); strlcat(name, "/", sizeof(name)); strlcat(name, PPPOE_NKE, sizeof(name)); #if !TARGET_OS_EMBEDDED // This file is not built for Embedded if (!load_kext(name, 0)) #else if (!load_kext(PPPOE_NKE_ID, 1)) #endif sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_PPPOE); } } } if (sockfd < 0) { error("Failed to open PPPoE socket: %m"); status = EXIT_OPEN_FAILED; return -1; } } } if (loopback || debug) { u_int32_t flags; flags = (loopback ? PPPOE_FLAG_LOOPBACK : 0) + ((kdebugflag & 1) ? PPPOE_FLAG_DEBUG : 0); if (setsockopt(sockfd, PPPPROTO_PPPOE, PPPOE_OPT_FLAGS, &flags, 4)) { error("PPPoE can't set PPPoE flags...\n"); return errno; } if (loopback) notice("PPPoE loopback activated...\n"); } if (connecttimer) { u_int16_t timer = connecttimer; if (setsockopt(sockfd, PPPPROTO_PPPOE, PPPOE_OPT_CONNECT_TIMER, &timer, 2)) { error("PPPoE can't set PPPoE connect timer...\n"); return errno; } } if (retrytimer) { u_int16_t timer = retrytimer; if (setsockopt(sockfd, PPPPROTO_PPPOE, PPPOE_OPT_RETRY_TIMER, &timer, 2)) { error("PPPoE can't set PPPoE retry timer...\n"); return errno; } } if (setsockopt(sockfd, PPPPROTO_PPPOE, PPPOE_OPT_INTERFACE, device, strlen(device))) { error("PPPoE can't specify interface...\n"); return errno; } if (!strcmp(mode, MODE_ANSWER)) { // nothing to do } else if (!strcmp(mode, MODE_LISTEN)) { err = pppoe_listen(); } else if (!strcmp(mode, MODE_CONNECT)) { err = pppoe_dial(); } else fatal("PPPoE incorrect mode : '%s'", mode ? mode : ""); if (err) { if (err != -2) { if (err != -1) devstatus = err; status = EXIT_CONNECT_FAILED; } return -1; } return sockfd; }
int main(int argc, char **argv) { int result = -1; int mntflags = 0; int cfd = -1; char *fdnam = NULL; char *dev = NULL; int r = 0; char devpath[MAXPATHLEN]; int fd = -1; int32_t dindex = -1; uint64_t altflags = 0ULL; char *mntpath = NULL; struct mntopt *mo; struct mntval *mv; struct statfs statfsb; fuse_mount_args args; // Drop to real uid and gid seteuid(getuid()); setegid(getgid()); if (!getenv("MOUNT_OSXFUSE_CALL_BY_LIB")) { showhelp(); } memset((void *)&args, 0, sizeof(args)); while (true) { static struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; int c = getopt_long(argc, argv, "ho:qv", long_options, NULL); if (c == -1) { break; } switch (c) { case 'o': getmntopts(optarg, mopts, &mntflags, &altflags); for (mv = mvals; mv->mv_mntflag; ++mv) { if (!(altflags & mv->mv_mntflag)) { continue; } for (mo = mopts; mo->m_option; ++mo) { char *p, *q; if (!mo->m_altloc || mo->m_flag != mv->mv_mntflag) { continue; } p = strstr(optarg, mo->m_option); if (p) { p += strlen(mo->m_option); q = p; while (*q != '\0' && *q != ',') { q++; } mv->mv_len = q - p + 1; mv->mv_value = malloc(mv->mv_len); memcpy(mv->mv_value, p, mv->mv_len - 1); ((char *)mv->mv_value)[mv->mv_len - 1] = '\0'; break; } } } break; case 'q': quiet_mode = true; break; case 'v': showversion(true); break; case 'h': case '?': default: showhelp(); break; } } argc -= optind; argv += optind; if (argc >= 1) { mntpath = argv[0]; argc--; argv++; } if (!mntpath) { errx(EX_USAGE, "missing mount point"); } { char *commfd; commfd = getenv("_FUSE_COMMFD"); if (commfd == NULL) { errx(EX_USAGE, "mew style mounting requires commfd"); } errno = 0; cfd = (int)strtol(commfd, NULL, 10); if (errno == EINVAL || errno == ERANGE || cfd < 0) { errx(EX_USAGE, "invalid commfd"); } } result = load_kext(); if (result) { if (result == EINVAL) { if (!quiet_mode) { CFUserNotificationDisplayNotice( (CFTimeInterval)0, kCFUserNotificationCautionAlertLevel, (CFURLRef)0, (CFURLRef)0, (CFURLRef)0, CFSTR("Installed version of macOS unsupported"), CFSTR("The installed version of FUSE is too new for the operating system. Please downgrade your FUSE installation to one that is compatible with the currently running version of macOS."), CFSTR("OK")); } post_notification(NOTIFICATION_OS_IS_TOO_OLD, NULL, 0); } if (result == ENOENT) { if (!quiet_mode) { CFUserNotificationDisplayNotice( (CFTimeInterval)0, kCFUserNotificationCautionAlertLevel, (CFURLRef)0, (CFURLRef)0, (CFURLRef)0, CFSTR("Installed version of macOS unsupported"), CFSTR("The installed version of FUSE is too old for the operating system. Please upgrade your FUSE installation to one that is compatible with the currently running version of macOS."), CFSTR("OK")); } post_notification(NOTIFICATION_OS_IS_TOO_NEW, NULL, 0); } else if (result == EBUSY) { if (!quiet_mode) { CFUserNotificationDisplayNotice( (CFTimeInterval)0, kCFUserNotificationCautionAlertLevel, (CFURLRef)0, (CFURLRef)0, (CFURLRef)0, CFSTR("FUSE version mismatch"), CFSTR("FUSE has been updated but an incompatible or old version of the FUSE kernel extension is already loaded. It failed to unload, possibly because a FUSE volume is currently mounted.\n\nPlease eject all FUSE volumes and try again, or simply restart the system for changes to take effect."), CFSTR("OK")); } post_notification(NOTIFICATION_VERSION_MISMATCH, NULL, 0); } errx(EX_UNAVAILABLE, "the " OSXFUSE_DISPLAY_NAME " file system is not available (%d)", result); } result = check_kext_status(); switch (result) { case 0: break; case ESRCH: errx(EX_UNAVAILABLE, "the " OSXFUSE_DISPLAY_NAME " kernel extension is not loaded"); break; case EINVAL: errx(EX_UNAVAILABLE, "the loaded " OSXFUSE_DISPLAY_NAME " kernel extension has a mismatched version"); break; default: errx(EX_UNAVAILABLE, "failed to query the loaded " OSXFUSE_DISPLAY_NAME " kernel extension (%d)", result); break; } fdnam = getenv("FUSE_DEV_FD"); if (fdnam) { errno = 0; fd = (int)strtol(fdnam, NULL, 10); if (errno == EINVAL || errno == ERANGE || fd < 0) { errx(EX_USAGE, "invalid value given in FUSE_DEV_FD"); } goto mount; } dev = getenv("FUSE_DEV_NAME"); if (dev) { fd = open(dev, O_RDWR); if (fd < 0) { errx(EX_USAGE, "failed to open device"); } goto mount; } for (r = 0; r < OSXFUSE_NDEVICES; r++) { snprintf(devpath, MAXPATHLEN - 1, _PATH_DEV OSXFUSE_DEVICE_BASENAME "%d", r); fd = open(devpath, O_RDWR); if (fd >= 0) { dindex = r; break; } } if (dindex == -1) { errx(EX_OSERR, "failed to open device"); } mount: signal_fd = fd; atexit(&signal_idx_atexit_handler); { struct stat sb; if (fstat(fd, &sb) == -1) { err(EX_OSERR, "fstat failed for " OSXFUSE_DISPLAY_NAME " device file descriptor"); } args.rdev = sb.st_rdev; } if (dindex < 0) { char ndev[MAXPATHLEN]; char *ndevbas; (void)strlcpy(ndev, _PATH_DEV, sizeof(ndev)); ndevbas = ndev + strlen(_PATH_DEV); devname_r(args.rdev, S_IFCHR, ndevbas, (int)(sizeof(ndev) - strlen(_PATH_DEV))); if (strncmp(ndevbas, OSXFUSE_DEVICE_BASENAME, strlen(OSXFUSE_DEVICE_BASENAME))) { errx(EX_USAGE, "mounting inappropriate device"); } errno = 0; dindex = (int)strtol(ndevbas + strlen(OSXFUSE_DEVICE_BASENAME), NULL, 10); if (errno == EINVAL || errno == ERANGE || dindex < 0 || dindex > OSXFUSE_NDEVICES) { errx(EX_USAGE, "invalid " OSXFUSE_DISPLAY_NAME " device unit (#%d)\n", dindex); } } while (true) { struct stat sb; if (realpath(mntpath, args.mntpath) != NULL && stat(args.mntpath, &sb) == 0) { if (S_ISDIR(sb.st_mode)) { break; } else { errx(EX_USAGE, "%s: not a directory", args.mntpath); } } else if (errno == ENOENT) { bool volumes = strncmp(args.mntpath, "/Volumes/", 9) == 0 && strchr(args.mntpath + 9, '/') == NULL; if (volumes) { (void)seteuid(0); (void)setegid(0); } if (mkdir(args.mntpath, 0755)) { errx(EX_USAGE, "%s: %s", args.mntpath, strerror(errno)); } if (volumes) { uid_t uid = getuid(); gid_t gid = getgid(); (void)chown(args.mntpath, uid, gid); (void)seteuid(uid); (void)setegid(gid); } } else { errx(EX_USAGE, "%s: %s", args.mntpath, strerror(errno)); } } mntpath = args.mntpath; fuse_process_mvals(); if (statfs(mntpath, &statfsb)) { errx(EX_OSFILE, "cannot stat the mount point %s", mntpath); } if (((strlen(statfsb.f_fstypename) == strlen(OSXFUSE_NAME)) && (strcmp(statfsb.f_fstypename, OSXFUSE_NAME) == 0)) || ((strlen(OSXFUSE_TYPE_NAME_PREFIX) > 0) && (strncmp(statfsb.f_fstypename, OSXFUSE_TYPE_NAME_PREFIX, strlen(OSXFUSE_TYPE_NAME_PREFIX)) == 0))) { if (!(altflags & FUSE_MOPT_ALLOW_RECURSION)) { errx(EX_USAGE, "mount point %s is itself on a " OSXFUSE_DISPLAY_NAME " volume", mntpath); } } /* allow_root and allow_other checks are done in the kernel. */ if (altflags & FUSE_MOPT_NO_LOCALCACHES) { altflags |= FUSE_MOPT_NO_ATTRCACHE; altflags |= FUSE_MOPT_NO_READAHEAD; altflags |= FUSE_MOPT_NO_UBC; altflags |= FUSE_MOPT_NO_VNCACHE; } if ((altflags & FUSE_MOPT_NEGATIVE_VNCACHE) && (altflags & FUSE_MOPT_NO_VNCACHE)) { errx(EX_USAGE, "'negative_vncache' can't be used with 'novncache'"); } /* * 'nosyncwrites' must not appear with either 'noubc' or 'noreadahead'. */ if ((altflags & FUSE_MOPT_NO_SYNCWRITES) && (altflags & (FUSE_MOPT_NO_UBC | FUSE_MOPT_NO_READAHEAD))) { errx(EX_USAGE, "disabling local caching can't be used with 'nosyncwrites'"); } /* * 'nosynconclose' only allowed if 'nosyncwrites' is also there. */ if ((altflags & FUSE_MOPT_NO_SYNCONCLOSE) && !(altflags & FUSE_MOPT_NO_SYNCWRITES)) { errx(EX_USAGE, "the 'nosynconclose' option requires 'nosyncwrites'"); } if ((altflags & FUSE_MOPT_DEFAULT_PERMISSIONS) && (altflags & FUSE_MOPT_DEFER_PERMISSIONS)) { errx(EX_USAGE, "'default_permissions' can't be used with 'defer_permissions'"); } if ((altflags & FUSE_MOPT_AUTO_XATTR) && (altflags & FUSE_MOPT_NATIVE_XATTR)) { errx(EX_USAGE, "'auto_xattr' can't be used with 'native_xattr'"); } if (daemon_timeout < FUSE_MIN_DAEMON_TIMEOUT) { daemon_timeout = FUSE_MIN_DAEMON_TIMEOUT; } if (daemon_timeout > FUSE_MAX_DAEMON_TIMEOUT) { daemon_timeout = FUSE_MAX_DAEMON_TIMEOUT; } result = ioctl(fd, FUSEDEVIOCGETRANDOM, &drandom); if (result) { errx(EX_UNAVAILABLE, "failed to negotiate with /dev/" OSXFUSE_DEVICE_BASENAME "%d", dindex); } args.altflags = altflags; args.blocksize = (uint32_t)blocksize; args.daemon_timeout = (uint32_t)daemon_timeout; args.fsid = (uint32_t)fsid; args.fssubtype = (uint32_t)fssubtype; args.iosize = (uint32_t)iosize; args.random = drandom; char *daemon_name = NULL; char *daemon_path = getenv("MOUNT_OSXFUSE_DAEMON_PATH"); if (daemon_path) { daemon_name = basename(daemon_path); } if (!fsname) { if (daemon_name) { snprintf(args.fsname, MAXPATHLEN, "%s@" OSXFUSE_DEVICE_BASENAME "%d", daemon_name, dindex); } else { snprintf(args.fsname, MAXPATHLEN, "instance@" OSXFUSE_DEVICE_BASENAME "%d", dindex); } } else { snprintf(args.fsname, MAXPATHLEN, "%s", fsname); } if (fstypename) { if (strlen(fstypename) > FUSE_TYPE_NAME_MAXLEN) { errx(EX_USAGE, "fstypename can be at most %lu characters", (long unsigned int) FUSE_TYPE_NAME_MAXLEN); } else { snprintf(args.fstypename, MFSTYPENAMELEN, "%s", fstypename); } } if (!volname) { #if __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wformat-extra-args" #endif if (daemon_name) { snprintf(args.volname, MAXPATHLEN, OSXFUSE_VOLNAME_DAEMON_FORMAT, dindex, daemon_name); } else { snprintf(args.volname, MAXPATHLEN, OSXFUSE_VOLNAME_FORMAT, dindex); } #if __clang__ #pragma clang diagnostic pop #endif } else { snprintf(args.volname, MAXPATHLEN, "%s", volname); } if (cfd != -1) { result = send_fd(cfd, fd); if (result == -1) { err(EX_OSERR, "failed to send file descriptor"); } } /* Finally! */ result = mount(OSXFUSE_NAME, mntpath, mntflags, (void *)&args); if (result < 0) { err(EX_OSERR, "failed to mount %s@/dev/" OSXFUSE_DEVICE_BASENAME "%d", mntpath, dindex); } else { const char *dict[][2] = { { kFUSEMountPathKey, mntpath } }; post_notification(NOTIFICATION_MOUNT, dict, 1); } signal_fd = -1; exit(0); }
/* ----------------------------------------------------------------------------- plugin entry point, called by vpnd ref is the vpn bundle reference pppref is the ppp bundle reference bundles can be layout in two different ways - As simple vpn bundles (bundle.vpn). the bundle contains the vpn bundle binary. - As full ppp bundles (bundle.ppp). The bundle contains the ppp bundle binary, and also the vpn kext and the vpn bundle binary in its Plugins directory. if a simple vpn bundle was used, pppref will be NULL. if a ppp bundle was used, the vpn plugin will be able to get access to the Plugins directory and load the vpn kext. ----------------------------------------------------------------------------- */ int start(struct vpn_channel* the_vpn_channel, CFBundleRef ref, CFBundleRef pppref, int debug_mode, int log_verbose) { char name[MAXPATHLEN]; CFURLRef url; size_t len; int nb_cpu = 1, nb_threads = 0; debug = debug_mode; /* first load the kext if we are loaded as part of a ppp bundle */ if (pppref) { while ((listen_sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) break; if (listen_sockfd < 0) { vpnlog(LOG_DEBUG, "L2TP plugin: first call to socket failed - attempting to load kext\n"); if (url = CFBundleCopyBundleURL(pppref)) { name[0] = 0; CFURLGetFileSystemRepresentation(url, 0, (UInt8 *)name, MAXPATHLEN - 1); CFRelease(url); strlcat(name, "/", sizeof(name)); if (url = CFBundleCopyBuiltInPlugInsURL(pppref)) { CFURLGetFileSystemRepresentation(url, 0, (UInt8 *)(name + strlen(name)), MAXPATHLEN - strlen(name) - strlen(L2TP_NKE) - 1); CFRelease(url); strlcat(name, "/", sizeof(name)); strlcat(name, L2TP_NKE, sizeof(name)); #if !TARGET_OS_EMBEDDED // This file is not built for Embedded if (!load_kext(name, 0)) #else if (!load_kext(L2TP_NKE_ID, 1)) #endif while ((listen_sockfd = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_L2TP)) < 0) if (errno != EINTR) break; } } if (listen_sockfd < 0) { vpnlog(LOG_ERR, "L2TP plugin: Unable to load L2TP kernel extension\n"); return -1; } } } #if !TARGET_OS_EMBEDDED // This file is not built for Embedded /* increase the number of threads for l2tp to nb cpus - 1 */ len = sizeof(int); sysctlbyname("hw.ncpu", &nb_cpu, &len, NULL, 0); if (nb_cpu > 1) { sysctlbyname("net.ppp.l2tp.nb_threads", &nb_threads, &len, 0, 0); if (nb_threads < (nb_cpu - 1)) { nb_threads = nb_cpu - 1; sysctlbyname("net.ppp.l2tp.nb_threads", 0, 0, &nb_threads, sizeof(int)); } } #endif /* retain reference */ bundle = ref; CFRetain(bundle); pppbundle = pppref; if (pppbundle) CFRetain(pppbundle); // hookup our socket handlers bzero(the_vpn_channel, sizeof(struct vpn_channel)); the_vpn_channel->get_pppd_args = l2tpvpn_get_pppd_args; the_vpn_channel->listen = l2tpvpn_listen; the_vpn_channel->accept = l2tpvpn_accept; the_vpn_channel->refuse = l2tpvpn_refuse; the_vpn_channel->close = l2tpvpn_close; the_vpn_channel->health_check = l2tpvpn_health_check; the_vpn_channel->lb_redirect = l2tpvpn_lb_redirect; return 0; }