xref: /openbsd/usr.sbin/npppd/npppd/npppd.c (revision baaa6b9a)
1*baaa6b9aSyasuoka /*	$OpenBSD: npppd.c,v 1.48 2018/07/25 02:18:36 yasuoka Exp $ */
2e109dc18Syasuoka 
30fbf3537Syasuoka /*-
44a39ccd0Sderaadt  * Copyright (c) 2005-2008,2009 Internet Initiative Japan Inc.
50fbf3537Syasuoka  * All rights reserved.
60fbf3537Syasuoka  *
70fbf3537Syasuoka  * Redistribution and use in source and binary forms, with or without
80fbf3537Syasuoka  * modification, are permitted provided that the following conditions
90fbf3537Syasuoka  * are met:
100fbf3537Syasuoka  * 1. Redistributions of source code must retain the above copyright
110fbf3537Syasuoka  *    notice, this list of conditions and the following disclaimer.
120fbf3537Syasuoka  * 2. Redistributions in binary form must reproduce the above copyright
130fbf3537Syasuoka  *    notice, this list of conditions and the following disclaimer in the
140fbf3537Syasuoka  *    documentation and/or other materials provided with the distribution.
150fbf3537Syasuoka  *
160fbf3537Syasuoka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
170fbf3537Syasuoka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180fbf3537Syasuoka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190fbf3537Syasuoka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200fbf3537Syasuoka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210fbf3537Syasuoka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220fbf3537Syasuoka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230fbf3537Syasuoka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240fbf3537Syasuoka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250fbf3537Syasuoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260fbf3537Syasuoka  * SUCH DAMAGE.
270fbf3537Syasuoka  */
280fbf3537Syasuoka /**@file
29f0a4e295Syasuoka  * Next pppd(nppd). This file provides a npppd daemon process and operations
30f0a4e295Syasuoka  * for npppd instance.
310fbf3537Syasuoka  * @author	Yasuoka Masahiko
32*baaa6b9aSyasuoka  * $Id: npppd.c,v 1.48 2018/07/25 02:18:36 yasuoka Exp $
330fbf3537Syasuoka  */
340fbf3537Syasuoka #include "version.h"
35dbad4650Sderaadt #include <sys/param.h>	/* ALIGNED_POINTER */
360fbf3537Syasuoka #include <sys/types.h>
370fbf3537Syasuoka #include <sys/socket.h>
380fbf3537Syasuoka #include <sys/sysctl.h>
395fefcc09Syasuoka #include <sys/wait.h>
400fbf3537Syasuoka #include <netinet/in.h>
410fbf3537Syasuoka #include <netinet/ip.h>
420fbf3537Syasuoka #include <net/route.h>
430fbf3537Syasuoka #include <arpa/inet.h>
440fbf3537Syasuoka #include <net/if_dl.h>
450fbf3537Syasuoka #include <unistd.h>
460fbf3537Syasuoka #include <time.h>
470fbf3537Syasuoka #include <syslog.h>
480fbf3537Syasuoka #include <string.h>
490fbf3537Syasuoka #include <stdlib.h>
500fbf3537Syasuoka #include <stdio.h>
510fbf3537Syasuoka #include <signal.h>
520fbf3537Syasuoka #include <netdb.h>
530fbf3537Syasuoka #include <libgen.h>
540fbf3537Syasuoka #include <fcntl.h>
550fbf3537Syasuoka #include <event.h>
560fbf3537Syasuoka #include <errno.h>
570fbf3537Syasuoka #include <ifaddrs.h>
584a78f66bSyasuoka #include <err.h>
594a78f66bSyasuoka #include <pwd.h>
600fbf3537Syasuoka 
610fbf3537Syasuoka #include "pathnames.h"
620fbf3537Syasuoka #include "debugutil.h"
630fbf3537Syasuoka #include "addr_range.h"
640fbf3537Syasuoka #include "npppd_subr.h"
650fbf3537Syasuoka #include "npppd_local.h"
660fbf3537Syasuoka #include "npppd_auth.h"
670fbf3537Syasuoka #include "radish.h"
680fbf3537Syasuoka #include "net_utils.h"
690fbf3537Syasuoka #include "time_utils.h"
700fbf3537Syasuoka 
71b56612b6Smarkus #include "l2tp_local.h"	/* XXX sa_cookie */
72b56612b6Smarkus 
730fbf3537Syasuoka #ifdef USE_NPPPD_ARP
740fbf3537Syasuoka #include "npppd_arp.h"
750fbf3537Syasuoka #endif
760fbf3537Syasuoka 
770fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
780fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
790fbf3537Syasuoka #include "pppoe_local.h"
800fbf3537Syasuoka #endif /* USE_NPPPD_PPPOE */
810fbf3537Syasuoka #include "psm-opt.h"
820fbf3537Syasuoka #include <sys/ioctl.h>
830fbf3537Syasuoka #include <net/pipex.h>
840fbf3537Syasuoka #endif /* USE_NPPPD_PIPEX */
850fbf3537Syasuoka 
8659408346Syasuoka #include "accept.h"
8759408346Syasuoka #include "log.h"
8859408346Syasuoka 
890fbf3537Syasuoka static npppd s_npppd;	/* singleton */
900fbf3537Syasuoka 
910fbf3537Syasuoka static void         npppd_reload0 (npppd *);
92821f7c56Syasuoka static void         npppd_update_pool_reference (npppd *);
930fbf3537Syasuoka static int          npppd_rd_walktree_delete(struct radish_head *);
940cd27c4aSyasuoka static __dead void  usage (void);
950fbf3537Syasuoka static void         npppd_stop_really (npppd *);
960fbf3537Syasuoka static uint32_t     str_hash(const void *, int);
970fbf3537Syasuoka static void         npppd_on_sighup (int, short, void *);
980fbf3537Syasuoka static void         npppd_on_sigterm (int, short, void *);
990fbf3537Syasuoka static void         npppd_on_sigint (int, short, void *);
1005fefcc09Syasuoka static void         npppd_on_sigchld (int, short, void *);
1010fbf3537Syasuoka static void         npppd_reset_timer(npppd *);
1020fbf3537Syasuoka static void         npppd_timer(int, short, void *);
1030fbf3537Syasuoka static void         npppd_auth_finalizer_periodic(npppd *);
1040fbf3537Syasuoka static int          rd2slist_walk (struct radish *, void *);
1050fbf3537Syasuoka static int          rd2slist (struct radish_head *, slist *);
10634682664Syasuoka static slist       *npppd_get_ppp_by_user (npppd *, const char *);
10734682664Syasuoka static int          npppd_get_all_users (npppd *, slist *);
1082a5607d2Sgoda static struct ipcpstat
1092a5607d2Sgoda                    *npppd_get_ipcp_stat(struct ipcpstat_head *, const char *);
1102a5607d2Sgoda static void         npppd_destroy_ipcp_stats(struct ipcpstat_head *);
1112a5607d2Sgoda static void         npppd_ipcp_stats_reload(npppd *);
1120fbf3537Syasuoka 
1130fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
1140fbf3537Syasuoka static struct in_addr loop;	/* initialize at npppd_init() */
1150fbf3537Syasuoka #endif
1160fbf3537Syasuoka static uint32_t        str_hash(const void *, int);
1170fbf3537Syasuoka 
1180fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
1190fbf3537Syasuoka static int npppd_ppp_pipex_ip_disable(npppd *, npppd_ppp *);
1200fbf3537Syasuoka static void pipex_periodic(npppd *);
1210fbf3537Syasuoka #endif /* USE_NPPPD_PIPEX */
1220fbf3537Syasuoka 
1230fbf3537Syasuoka #ifdef NPPPD_DEBUG
1240fbf3537Syasuoka #define NPPPD_DBG(x) 	log_printf x
1250fbf3537Syasuoka #define NPPPD_ASSERT(x) ASSERT(x)
1260fbf3537Syasuoka #else
1270fbf3537Syasuoka #define NPPPD_DBG(x)
1280fbf3537Syasuoka #define NPPPD_ASSERT(x)
1290fbf3537Syasuoka #endif
1300fbf3537Syasuoka 
1310fbf3537Syasuoka /***********************************************************************
132f0a4e295Syasuoka  * Daemon process
1330fbf3537Syasuoka  ***********************************************************************/
1340fbf3537Syasuoka int        main (int, char *[]);
135821f7c56Syasuoka int        debugsyslog = 0;	/* used by log.c */
1360fbf3537Syasuoka 
1370fbf3537Syasuoka int
1380fbf3537Syasuoka main(int argc, char *argv[])
1390fbf3537Syasuoka {
140821f7c56Syasuoka 	int            ch, stop_by_error, runasdaemon = 1, nflag = 0;
1410fbf3537Syasuoka 	extern char   *optarg;
1420fbf3537Syasuoka 	const char    *npppd_conf0 = DEFAULT_NPPPD_CONF;
1434a78f66bSyasuoka 	struct passwd *pw;
1440fbf3537Syasuoka 
1450cd27c4aSyasuoka 	while ((ch = getopt(argc, argv, "nf:d")) != -1) {
1460fbf3537Syasuoka 		switch (ch) {
147821f7c56Syasuoka 		case 'n':
148821f7c56Syasuoka 			nflag = 1;
1490fbf3537Syasuoka 			break;
150821f7c56Syasuoka 		case 'f':
1510fbf3537Syasuoka 			npppd_conf0 = optarg;
1520fbf3537Syasuoka 			break;
1530fbf3537Syasuoka 		case 'd':
1540fbf3537Syasuoka 			debuglevel++;
155821f7c56Syasuoka 			runasdaemon = 0;
1560fbf3537Syasuoka 			break;
1570cd27c4aSyasuoka 		default:
1580fbf3537Syasuoka 			usage();
1590fbf3537Syasuoka 		}
1600fbf3537Syasuoka 	}
161821f7c56Syasuoka 	argc -= optind;
162821f7c56Syasuoka 	argv += optind;
1630cd27c4aSyasuoka 	if (argc != 0)
164821f7c56Syasuoka 		usage();
165821f7c56Syasuoka 	if (nflag) {
166821f7c56Syasuoka 		debuglevel++;
167821f7c56Syasuoka 		runasdaemon = 0;
168821f7c56Syasuoka 	}
169821f7c56Syasuoka 
170821f7c56Syasuoka 	/* for log.c */
171821f7c56Syasuoka 	log_init(debuglevel);
1720fbf3537Syasuoka 	if (debuglevel > 0) {
173821f7c56Syasuoka 		/* for ../common/debugutil.c */
1740fbf3537Syasuoka 		debug_set_debugfp(stderr);
1750fbf3537Syasuoka 		debug_use_syslog(0);
176821f7c56Syasuoka 	}
1770fbf3537Syasuoka 	if (runasdaemon)
1780fbf3537Syasuoka 		daemon(0, 0);
1790fbf3537Syasuoka 
1804a78f66bSyasuoka 	/* check for root privileges */
1814a78f66bSyasuoka 	if (geteuid())
1824a78f66bSyasuoka 		errx(1, "need root privileges");
1834a78f66bSyasuoka 	/* check for npppd user */
1844a78f66bSyasuoka 	if (getpwnam(NPPPD_USER) == NULL)
1854a78f66bSyasuoka 		errx(1, "unknown user %s", NPPPD_USER);
1864a78f66bSyasuoka 
1874a78f66bSyasuoka 	if (privsep_init() != 0)
1884a78f66bSyasuoka 		err(1, "cannot drop privileges");
1894a78f66bSyasuoka 
190821f7c56Syasuoka 	if (nflag) {
191821f7c56Syasuoka 		if (npppd_config_check(npppd_conf0) == 0) {
192821f7c56Syasuoka 			fprintf(stderr, "configuration OK\n");
193821f7c56Syasuoka 			exit(EXIT_SUCCESS);
194821f7c56Syasuoka 		}
195821f7c56Syasuoka 		exit(EXIT_FAILURE);
196821f7c56Syasuoka 	}
1979a200ddfSyasuoka 	if (npppd_init(&s_npppd, npppd_conf0) != 0)
1989a200ddfSyasuoka 		exit(EXIT_FAILURE);
1994a78f66bSyasuoka 
2004a78f66bSyasuoka 	if ((pw = getpwnam(NPPPD_USER)) == NULL)
2019a200ddfSyasuoka 		err(EXIT_FAILURE, "gwpwnam");
2024a78f66bSyasuoka 	if (chroot(pw->pw_dir) == -1)
2039a200ddfSyasuoka 		err(EXIT_FAILURE, "chroot");
2044a78f66bSyasuoka 	if (chdir("/") == -1)
2059a200ddfSyasuoka 		err(EXIT_FAILURE, "chdir(\"/\")");
2064a78f66bSyasuoka         if (setgroups(1, &pw->pw_gid) ||
2074a78f66bSyasuoka 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
2084a78f66bSyasuoka 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
2099a200ddfSyasuoka 		err(EXIT_FAILURE, "cannot drop privileges");
2104a78f66bSyasuoka 	/* privileges is dropped */
2114a78f66bSyasuoka 
2120fbf3537Syasuoka 	npppd_start(&s_npppd);
2139a200ddfSyasuoka 	stop_by_error = s_npppd.stop_by_error;
2140fbf3537Syasuoka 	npppd_fini(&s_npppd);
2154a78f66bSyasuoka 	privsep_fini();
2160fbf3537Syasuoka 	log_printf(LOG_NOTICE, "Terminate npppd.");
2170fbf3537Syasuoka 
2189a200ddfSyasuoka 	exit((!stop_by_error)? EXIT_SUCCESS : EXIT_FAILURE);
2190fbf3537Syasuoka }
2200fbf3537Syasuoka 
2210cd27c4aSyasuoka static __dead void
2220cd27c4aSyasuoka usage(void)
2230fbf3537Syasuoka {
2240cd27c4aSyasuoka 	fprintf(stderr, "usage: npppd [-dn] [-f config_file]\n");
2250cd27c4aSyasuoka 	exit(1);
2260fbf3537Syasuoka }
2270fbf3537Syasuoka 
228f0a4e295Syasuoka /** Returns the singleton npppd instance */
2290fbf3537Syasuoka npppd *
2300fbf3537Syasuoka npppd_get_npppd()
2310fbf3537Syasuoka {
2320fbf3537Syasuoka 	return &s_npppd;
2330fbf3537Syasuoka }
2340fbf3537Syasuoka 
2350fbf3537Syasuoka /***********************************************************************
236f0a4e295Syasuoka  * Operations to npppd itself (initialize/finalize/start/stop)
2370fbf3537Syasuoka  ***********************************************************************/
238f0a4e295Syasuoka  /** Initialize the npppd */
2390fbf3537Syasuoka int
2400fbf3537Syasuoka npppd_init(npppd *_this, const char *config_file)
2410fbf3537Syasuoka {
2424c9b8a40Syasuoka 	int		 i, status = -1, value;
2430fbf3537Syasuoka 	const char	*pidpath0;
2440fbf3537Syasuoka 	FILE		*pidfp = NULL;
2454c9b8a40Syasuoka 	struct tunnconf	*tunn;
2462a5607d2Sgoda 	struct ipcpconf *ipcpconf;
2472a5607d2Sgoda 	struct ipcpstat *ipcpstat;
2484c9b8a40Syasuoka 	int		 mib[] = { CTL_NET, PF_PIPEX, PIPEXCTL_ENABLE };
2494c9b8a40Syasuoka 	size_t		 size;
2500fbf3537Syasuoka 
2510fbf3537Syasuoka 	memset(_this, 0, sizeof(npppd));
252cd8e09b9Sdlg #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
2530fbf3537Syasuoka 	loop.s_addr = htonl(INADDR_LOOPBACK);
254cd8e09b9Sdlg #endif
2550fbf3537Syasuoka 
2560fbf3537Syasuoka 	NPPPD_ASSERT(config_file != NULL);
2570fbf3537Syasuoka 
2580fbf3537Syasuoka 	pidpath0 = NULL;
2590fbf3537Syasuoka 	_this->pid = getpid();
2600fbf3537Syasuoka 	slist_init(&_this->realms);
261821f7c56Syasuoka 	npppd_conf_init(&_this->conf);
2620fbf3537Syasuoka 
2630fbf3537Syasuoka 	log_printf(LOG_NOTICE, "Starting npppd pid=%u version=%s",
2640fbf3537Syasuoka 	    _this->pid, VERSION);
2650fbf3537Syasuoka #if defined(BUILD_DATE) && defined(BUILD_TIME)
2660fbf3537Syasuoka 	log_printf(LOG_INFO, "Build %s %s ", BUILD_DATE, BUILD_TIME);
2670fbf3537Syasuoka #endif
2680fbf3537Syasuoka 	if (get_nanotime() == INT64_MIN) {
2690fbf3537Syasuoka 		log_printf(LOG_ERR, "get_nanotime() failed: %m");
2700fbf3537Syasuoka 		return 1;
2710fbf3537Syasuoka 	}
2720fbf3537Syasuoka 
2730fbf3537Syasuoka 	if (realpath(config_file, _this->config_file) == NULL) {
2740fbf3537Syasuoka 		log_printf(LOG_ERR, "realpath(%s,) failed in %s(): %m",
2750fbf3537Syasuoka 		    config_file, __func__);
2760fbf3537Syasuoka 		return 1;
2770fbf3537Syasuoka 	}
278f0a4e295Syasuoka 	/* we assume 4.4 compatible realpath().  See realpath(3) on BSD. */
2790fbf3537Syasuoka 	NPPPD_ASSERT(_this->config_file[0] == '/');
2800fbf3537Syasuoka 
281c2307f15Syasuoka 	_this->boot_id = arc4random();
2828daf7599Syasuoka 
28306adecbeSyasuoka #ifdef	USE_NPPPD_L2TP
28406adecbeSyasuoka 	if (l2tpd_init(&_this->l2tpd) != 0)
28506adecbeSyasuoka 		return (-1);
28606adecbeSyasuoka #endif
28706adecbeSyasuoka #ifdef	USE_NPPPD_PPTP
28806adecbeSyasuoka 	if (pptpd_init(&_this->pptpd) != 0)
28906adecbeSyasuoka 		return (-1);
29006adecbeSyasuoka #endif
29106adecbeSyasuoka #ifdef	USE_NPPPD_PPPOE
29206adecbeSyasuoka 	if (pppoed_init(&_this->pppoed) != 0)
29306adecbeSyasuoka 		return (-1);
29406adecbeSyasuoka #endif
2952a5607d2Sgoda 	LIST_INIT(&_this->ipcpstats);
2962a5607d2Sgoda 
297f0a4e295Syasuoka 	/* load configuration */
2980fbf3537Syasuoka 	if ((status = npppd_reload_config(_this)) != 0)
2990fbf3537Syasuoka 		return status;
3000fbf3537Syasuoka 
3014c9b8a40Syasuoka 	TAILQ_FOREACH(tunn, &_this->conf.tunnconfs, entry) {
3024c9b8a40Syasuoka 		if (tunn->pipex) {
3034c9b8a40Syasuoka 			size = sizeof(value);
3044c9b8a40Syasuoka 			if (!sysctl(mib, nitems(mib), &value, &size, NULL, 0)
3054c9b8a40Syasuoka 			    && value == 0)
3064c9b8a40Syasuoka 				log_printf(LOG_WARNING,
3074c9b8a40Syasuoka 					"pipex(4) is disabled by sysctl");
3084c9b8a40Syasuoka 			break;
3094c9b8a40Syasuoka 		}
3104c9b8a40Syasuoka 	}
3114c9b8a40Syasuoka 
3120fbf3537Syasuoka 	if ((_this->map_user_ppp = hash_create(
3130fbf3537Syasuoka 	    (int (*) (const void *, const void *))strcmp, str_hash,
3140fbf3537Syasuoka 	    NPPPD_USER_HASH_SIZ)) == NULL) {
3150fbf3537Syasuoka 		log_printf(LOG_ERR, "hash_create() failed in %s(): %m",
3160fbf3537Syasuoka 		    __func__);
3170fbf3537Syasuoka 		return -1;
3180fbf3537Syasuoka 	}
3190fbf3537Syasuoka 
3200fbf3537Syasuoka 	if (npppd_ifaces_load_config(_this) != 0) {
3210fbf3537Syasuoka 		return -1;
3220fbf3537Syasuoka 	}
3230fbf3537Syasuoka 
3242a5607d2Sgoda 	TAILQ_FOREACH(ipcpconf, &_this->conf.ipcpconfs, entry) {
3252a5607d2Sgoda 		ipcpstat = malloc(sizeof(*ipcpstat));
3262a5607d2Sgoda 		if (ipcpstat == NULL) {
3272a5607d2Sgoda 			log_printf(LOG_ERR, "initializing ipcp_stats failed : %m");
3282a5607d2Sgoda 			npppd_destroy_ipcp_stats(&_this->ipcpstats);
3292a5607d2Sgoda 			return -1;
3302a5607d2Sgoda 		}
3312a5607d2Sgoda 		memset(ipcpstat, 0, sizeof(*ipcpstat));
3322a5607d2Sgoda 		strlcpy(ipcpstat->name, ipcpconf->name, sizeof(ipcpstat->name));
3332a5607d2Sgoda 		LIST_INSERT_HEAD(&_this->ipcpstats, ipcpstat, entry);
3342a5607d2Sgoda 	}
3352a5607d2Sgoda 
3360fbf3537Syasuoka 	pidpath0 = DEFAULT_NPPPD_PIDFILE;
3370fbf3537Syasuoka 
338f0a4e295Syasuoka 	/* initialize event(3) */
3390fbf3537Syasuoka 	event_init();
34034682664Syasuoka 	_this->ctl_sock.cs_name = NPPPD_SOCKET;
34134682664Syasuoka 	_this->ctl_sock.cs_ctx = _this;
34234682664Syasuoka 	if (control_init(&_this->ctl_sock) == -1) {
34334682664Syasuoka 		log_printf(LOG_ERR, "control_init() failed %s(): %m",
34434682664Syasuoka 		    __func__);
34534682664Syasuoka 		return (-1);
34634682664Syasuoka 	}
34734682664Syasuoka 	if (control_listen(&_this->ctl_sock) == -1) {
34834682664Syasuoka 		log_printf(LOG_ERR, "control_listen() failed %s(): %m",
34934682664Syasuoka 		    __func__);
35034682664Syasuoka 		return (-1);
35134682664Syasuoka 	}
35259408346Syasuoka 	accept_init();
35359408346Syasuoka 
354f0a4e295Syasuoka 	/* ignore signals */
3550fbf3537Syasuoka 	signal(SIGPIPE, SIG_IGN);
3560fbf3537Syasuoka 	signal(SIGURG, SIG_IGN);
357f0a4e295Syasuoka 
358f0a4e295Syasuoka 	/* set signal handlers */
3590fbf3537Syasuoka 	signal_set(&_this->ev_sigterm, SIGTERM, npppd_on_sigterm, _this);
3600fbf3537Syasuoka 	signal_set(&_this->ev_sigint, SIGINT, npppd_on_sigint, _this);
3610fbf3537Syasuoka 	signal_set(&_this->ev_sighup, SIGHUP, npppd_on_sighup, _this);
3625fefcc09Syasuoka 	signal_set(&_this->ev_sigchld, SIGCHLD, npppd_on_sigchld, _this);
3630fbf3537Syasuoka 	signal_add(&_this->ev_sigterm, NULL);
3640fbf3537Syasuoka 	signal_add(&_this->ev_sigint, NULL);
3650fbf3537Syasuoka 	signal_add(&_this->ev_sighup, NULL);
3665fefcc09Syasuoka 	signal_add(&_this->ev_sigchld, NULL);
3670fbf3537Syasuoka 
3680fbf3537Syasuoka 	evtimer_set(&_this->ev_timer, npppd_timer, _this);
3690fbf3537Syasuoka 
370f0a4e295Syasuoka 	/* start tun(4) or pppac(4) */
3710fbf3537Syasuoka 	status = 0;
3720fbf3537Syasuoka 	for (i = 0; i < countof(_this->iface); i++) {
3730fbf3537Syasuoka 		if (_this->iface[i].initialized != 0)
3740fbf3537Syasuoka 			status |= npppd_iface_start(&_this->iface[i]);
3750fbf3537Syasuoka 	}
3760fbf3537Syasuoka 	if (status != 0)
3770fbf3537Syasuoka 		return -1;
3780fbf3537Syasuoka 
3790fbf3537Syasuoka 	/*
380f0a4e295Syasuoka 	 * If the npppd can start(open) interfaces successfully, it can
381f0a4e295Syasuoka 	 * act as only one npppd process on the system and overwrite the pid
382f0a4e295Syasuoka 	 * file.
3830fbf3537Syasuoka 	 */
3840fbf3537Syasuoka 	if ((pidfp = fopen(pidpath0, "w+")) == NULL) {
3850fbf3537Syasuoka 		log_printf(LOG_ERR, "fopen(%s,w+) failed in %s(): %m",
3860fbf3537Syasuoka 		    pidpath0, __func__);
3870fbf3537Syasuoka 		return -1;
3880fbf3537Syasuoka 	}
3890fbf3537Syasuoka 	strlcpy(_this->pidpath, pidpath0, sizeof(_this->pidpath));
3900fbf3537Syasuoka 	fprintf(pidfp, "%u\n", _this->pid);
3910fbf3537Syasuoka 	fclose(pidfp);
3920fbf3537Syasuoka 	pidfp = NULL;
3930fbf3537Syasuoka #ifdef USE_NPPPD_ARP
3940fbf3537Syasuoka 	arp_set_strictintfnetwork(npppd_config_str_equali(_this, "arpd.strictintfnetwork", "true", ARPD_STRICTINTFNETWORK_DEFAULT));
3950fbf3537Syasuoka 	if (npppd_config_str_equali(_this, "arpd.enabled", "true", ARPD_DEFAULT) == 1)
3960fbf3537Syasuoka         	arp_sock_init();
3970fbf3537Syasuoka #endif
398821f7c56Syasuoka 	if ((status = npppd_modules_reload(_this)) != 0)
399821f7c56Syasuoka 		return status;
400821f7c56Syasuoka 
401821f7c56Syasuoka 	npppd_update_pool_reference(_this);
402821f7c56Syasuoka 
403821f7c56Syasuoka 	return 0;
4040fbf3537Syasuoka }
4050fbf3537Syasuoka 
406f0a4e295Syasuoka /** start the npppd */
4070fbf3537Syasuoka void
4080fbf3537Syasuoka npppd_start(npppd *_this)
4090fbf3537Syasuoka {
4100fbf3537Syasuoka 	int rval = 0;
4110fbf3537Syasuoka 
4120fbf3537Syasuoka 	npppd_reset_timer(_this);
413f65d56a4Syasuoka 	while ((rval = event_loop(EVLOOP_ONCE)) == 0) {
4140fbf3537Syasuoka 		if (_this->finalized != 0)
4150fbf3537Syasuoka 			break;
4160fbf3537Syasuoka 	}
417f65d56a4Syasuoka 	if (rval != 0) {
4180fbf3537Syasuoka 		log_printf(LOG_CRIT, "event_loop() failed: %m");
419f65d56a4Syasuoka 		abort();
420f65d56a4Syasuoka 	}
4210fbf3537Syasuoka }
4220fbf3537Syasuoka 
423f0a4e295Syasuoka /** stop the npppd */
4240fbf3537Syasuoka void
4250fbf3537Syasuoka npppd_stop(npppd *_this)
4260fbf3537Syasuoka {
4270fbf3537Syasuoka 	int i;
4280fbf3537Syasuoka #ifdef	USE_NPPPD_L2TP
4290fbf3537Syasuoka 	l2tpd_stop(&_this->l2tpd);
4300fbf3537Syasuoka #endif
4310fbf3537Syasuoka #ifdef	USE_NPPPD_PPTP
4320fbf3537Syasuoka 	pptpd_stop(&_this->pptpd);
4330fbf3537Syasuoka #endif
4340fbf3537Syasuoka #ifdef	USE_NPPPD_PPPOE
4350fbf3537Syasuoka 	pppoed_stop(&_this->pppoed);
4360fbf3537Syasuoka #endif
4370fbf3537Syasuoka #ifdef USE_NPPPD_ARP
4380fbf3537Syasuoka         arp_sock_fini();
4390fbf3537Syasuoka #endif
44034682664Syasuoka 	close(_this->ctl_sock.cs_fd);
44134682664Syasuoka 	control_cleanup(&_this->ctl_sock);
44234682664Syasuoka 
4430fbf3537Syasuoka 	for (i = countof(_this->iface) - 1; i >= 0; i--) {
4440fbf3537Syasuoka 		if (_this->iface[i].initialized != 0)
4450fbf3537Syasuoka 			npppd_iface_stop(&_this->iface[i]);
4460fbf3537Syasuoka 	}
4470fbf3537Syasuoka 	npppd_set_radish(_this, NULL);
4480fbf3537Syasuoka 
4490fbf3537Syasuoka 	_this->finalizing = 1;
4500fbf3537Syasuoka 	npppd_reset_timer(_this);
4510fbf3537Syasuoka }
4520fbf3537Syasuoka 
4530fbf3537Syasuoka static void
4540fbf3537Syasuoka npppd_stop_really(npppd *_this)
4550fbf3537Syasuoka {
4560fbf3537Syasuoka 	int i;
4570fbf3537Syasuoka #if defined(USE_NPPPD_L2TP) || defined(USE_NPPPD_PPTP)
4580fbf3537Syasuoka 	int wait_again;
4590fbf3537Syasuoka 
4600fbf3537Syasuoka 	wait_again = 0;
4610fbf3537Syasuoka 
4620fbf3537Syasuoka #ifdef	USE_NPPPD_L2TP
4630fbf3537Syasuoka 	if (!l2tpd_is_stopped(&_this->l2tpd))
4640fbf3537Syasuoka 		wait_again |= 1;
4650fbf3537Syasuoka #endif
4660fbf3537Syasuoka #ifdef	USE_NPPPD_PPTP
4670fbf3537Syasuoka 	if (!pptpd_is_stopped(&_this->pptpd))
4680fbf3537Syasuoka 		wait_again |= 1;
4690fbf3537Syasuoka #endif
4700fbf3537Syasuoka 	if (wait_again != 0) {
4710fbf3537Syasuoka 		npppd_reset_timer(_this);
4720fbf3537Syasuoka 		return;
4730fbf3537Syasuoka 	}
4740fbf3537Syasuoka #endif
4750fbf3537Syasuoka 	for (i = countof(_this->iface) - 1; i >= 0; i--) {
4760fbf3537Syasuoka 		npppd_iface_fini(&_this->iface[i]);
4770fbf3537Syasuoka 	}
4780fbf3537Syasuoka 	_this->finalized = 1;
4790fbf3537Syasuoka }
4800fbf3537Syasuoka 
481f0a4e295Syasuoka /** finalize the npppd */
4820fbf3537Syasuoka void
4830fbf3537Syasuoka npppd_fini(npppd *_this)
4840fbf3537Syasuoka {
4850fbf3537Syasuoka 	int i;
4860fbf3537Syasuoka 	npppd_auth_base *auth_base;
4870fbf3537Syasuoka 
4880fbf3537Syasuoka #ifdef USE_NPPPD_L2TP
4890fbf3537Syasuoka 	l2tpd_uninit(&_this->l2tpd);
4900fbf3537Syasuoka #endif
4910fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
4920fbf3537Syasuoka 	pptpd_uninit(&_this->pptpd);
4930fbf3537Syasuoka #endif
4940fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
4950fbf3537Syasuoka 	pppoed_uninit(&_this->pppoed);
4960fbf3537Syasuoka #endif
4970fbf3537Syasuoka 	for (slist_itr_first(&_this->realms);
4980fbf3537Syasuoka 	    slist_itr_has_next(&_this->realms);) {
4990fbf3537Syasuoka 		auth_base = slist_itr_next(&_this->realms);
5000fbf3537Syasuoka 		npppd_auth_destroy(auth_base);
5010fbf3537Syasuoka 	}
5020fbf3537Syasuoka 	for (i = countof(_this->iface) - 1; i >= 0; i--) {
5030fbf3537Syasuoka 		if (_this->iface[i].initialized != 0)
5040fbf3537Syasuoka 			npppd_iface_fini(&_this->iface[i]);
5050fbf3537Syasuoka 	}
5060fbf3537Syasuoka 
5070fbf3537Syasuoka 	for (i = countof(_this->pool) - 1; i >= 0; i--) {
5080fbf3537Syasuoka 		if (_this->pool[i].initialized != 0)
5090fbf3537Syasuoka 			npppd_pool_uninit(&_this->pool[i]);
5100fbf3537Syasuoka 	}
5110fbf3537Syasuoka 
5122a5607d2Sgoda 	npppd_destroy_ipcp_stats(&_this->ipcpstats);
5132a5607d2Sgoda 
5140fbf3537Syasuoka 	signal_del(&_this->ev_sigterm);
5150fbf3537Syasuoka 	signal_del(&_this->ev_sigint);
5160fbf3537Syasuoka 	signal_del(&_this->ev_sighup);
5175fefcc09Syasuoka 	signal_del(&_this->ev_sigchld);
5180fbf3537Syasuoka 
519821f7c56Syasuoka 	npppd_conf_fini(&_this->conf);
5200fbf3537Syasuoka 
5210fbf3537Syasuoka 	slist_fini(&_this->realms);
5220fbf3537Syasuoka 
5230fbf3537Syasuoka 	if (_this->map_user_ppp != NULL)
5240fbf3537Syasuoka 		hash_free(_this->map_user_ppp);
5250fbf3537Syasuoka }
5260fbf3537Syasuoka 
5270fbf3537Syasuoka /***********************************************************************
528f0a4e295Syasuoka  * Timer related functions
5290fbf3537Syasuoka  ***********************************************************************/
5300fbf3537Syasuoka static void
5310fbf3537Syasuoka npppd_reset_timer(npppd *_this)
5320fbf3537Syasuoka {
5330fbf3537Syasuoka 	struct timeval tv;
5340fbf3537Syasuoka 
5350fbf3537Syasuoka 	if (_this->finalizing != 0) {
536f0a4e295Syasuoka 		/* we can use the timer exclusively on finalizing */
5370fbf3537Syasuoka 		tv.tv_usec = 500000;
5380fbf3537Syasuoka 		tv.tv_sec = 0;
5390fbf3537Syasuoka 		evtimer_add(&_this->ev_timer, &tv);
5400fbf3537Syasuoka 	} else {
5410fbf3537Syasuoka 		tv.tv_usec = 0;
5420fbf3537Syasuoka 		tv.tv_sec = NPPPD_TIMER_TICK_IVAL;
5430fbf3537Syasuoka 		evtimer_add(&_this->ev_timer, &tv);
5440fbf3537Syasuoka 	}
5450fbf3537Syasuoka }
5460fbf3537Syasuoka 
5470fbf3537Syasuoka static void
5480fbf3537Syasuoka npppd_timer(int fd, short evtype, void *ctx)
5490fbf3537Syasuoka {
5500fbf3537Syasuoka 	npppd *_this;
5510fbf3537Syasuoka 
5520fbf3537Syasuoka 	_this = ctx;
5530fbf3537Syasuoka 	if (_this->finalizing != 0) {
554f0a4e295Syasuoka 		npppd_stop_really(_this); /* The timer has been reset */
555f0a4e295Syasuoka 		return;	/* we can use the timer exclusively on finalizing */
5560fbf3537Syasuoka 	}
5570fbf3537Syasuoka 	_this->secs += NPPPD_TIMER_TICK_IVAL;
5580fbf3537Syasuoka 	if (_this->reloading_count > 0) {
5590fbf3537Syasuoka 		_this->reloading_count -= NPPPD_TIMER_TICK_IVAL;
5600fbf3537Syasuoka 		if (_this->reloading_count <= 0) {
5610fbf3537Syasuoka 			npppd_reload0(_this);
5620fbf3537Syasuoka 			_this->reloading_count = 0;
5630fbf3537Syasuoka 		}
5640fbf3537Syasuoka 	} else {
5650fbf3537Syasuoka 		if ((_this->secs % TIMER_TICK_RUP(
5660fbf3537Syasuoka 			    NPPPD_AUTH_REALM_FINALIZER_INTERVAL)) == 0)
5670fbf3537Syasuoka 			npppd_auth_finalizer_periodic(_this);
5680fbf3537Syasuoka 	}
5690fbf3537Syasuoka 
5700fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
5710fbf3537Syasuoka 	if (pppoed_need_polling(&_this->pppoed))
5720fbf3537Syasuoka 		pppoed_reload_listeners(&_this->pppoed);
5730fbf3537Syasuoka #endif
5740fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
5750fbf3537Syasuoka 	pipex_periodic(_this);
5760fbf3537Syasuoka #endif
5770fbf3537Syasuoka 
5780fbf3537Syasuoka 	npppd_reset_timer(_this);
5790fbf3537Syasuoka }
5800fbf3537Syasuoka 
5810fbf3537Syasuoka int
5820fbf3537Syasuoka npppd_reset_routing_table(npppd *_this, int pool_only)
5830fbf3537Syasuoka {
5840fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
5850fbf3537Syasuoka 	slist rtlist0;
5860fbf3537Syasuoka 
587cd8e09b9Sdlg 	if (_this->iface[0].using_pppx)
588cd8e09b9Sdlg 		return 0;
589cd8e09b9Sdlg 
5900fbf3537Syasuoka 	slist_init(&rtlist0);
5910fbf3537Syasuoka 	if (rd2slist(_this->rd, &rtlist0) != 0)
5920fbf3537Syasuoka 		return 1;
5930fbf3537Syasuoka 
5940fbf3537Syasuoka 	for (slist_itr_first(&rtlist0); slist_itr_has_next(&rtlist0); ) {
5950fbf3537Syasuoka 		struct radish *rd;
5960fbf3537Syasuoka 		struct sockaddr_npppd *snp;
5970fbf3537Syasuoka 		npppd_ppp *ppp;
5980fbf3537Syasuoka 		int is_first;
5990fbf3537Syasuoka 
6000fbf3537Syasuoka 		rd = slist_itr_next(&rtlist0);
6010fbf3537Syasuoka 		snp = rd->rd_rtent;
6020fbf3537Syasuoka 
6030fbf3537Syasuoka 		is_first = 1;
6040fbf3537Syasuoka 		for (snp = rd->rd_rtent; snp != NULL; snp = snp->snp_next) {
6050fbf3537Syasuoka 			switch (snp->snp_type) {
6060fbf3537Syasuoka 			case SNP_POOL:
6070fbf3537Syasuoka 			case SNP_DYN_POOL:
6080fbf3537Syasuoka 				if (is_first)
6090fbf3537Syasuoka 					in_route_add(&snp->snp_addr,
6100fbf3537Syasuoka 					    &snp->snp_mask, &loop,
6110fbf3537Syasuoka 					    LOOPBACK_IFNAME, RTF_BLACKHOLE, 0);
6120fbf3537Syasuoka 				break;
6130fbf3537Syasuoka 
6140fbf3537Syasuoka 			case SNP_PPP:
6150fbf3537Syasuoka 				if (pool_only)
6160fbf3537Syasuoka 					break;
6170fbf3537Syasuoka 				ppp = snp->snp_data_ptr;
6180fbf3537Syasuoka 				if (ppp->ppp_framed_ip_netmask.s_addr
6190fbf3537Syasuoka 				    == 0xffffffffL) {
6200fbf3537Syasuoka 					in_host_route_add(&ppp->
6210fbf3537Syasuoka 					    ppp_framed_ip_address,
6220fbf3537Syasuoka 					    &ppp_iface(ppp)->ip4addr,
6230fbf3537Syasuoka 					    ppp_iface(ppp)->ifname,
6240fbf3537Syasuoka 					    MRU_IPMTU(ppp->peer_mru));
6250fbf3537Syasuoka 				} else {
6260fbf3537Syasuoka 					in_route_add(&ppp->
6270fbf3537Syasuoka 					    ppp_framed_ip_address,
6280fbf3537Syasuoka 					    &ppp->ppp_framed_ip_netmask,
6290fbf3537Syasuoka 					    &ppp_iface(ppp)->ip4addr,
6300fbf3537Syasuoka 					    ppp_iface(ppp)->ifname, 0,
6310fbf3537Syasuoka 					    MRU_IPMTU(ppp->peer_mru));
6320fbf3537Syasuoka 				}
6330fbf3537Syasuoka 				break;
6340fbf3537Syasuoka 			}
6350fbf3537Syasuoka 			is_first = 0;
6360fbf3537Syasuoka 		}
6370fbf3537Syasuoka 
6380fbf3537Syasuoka 	}
6390fbf3537Syasuoka 
6400fbf3537Syasuoka 	slist_fini(&rtlist0);
6410fbf3537Syasuoka #endif
6420fbf3537Syasuoka 	return 0;
6430fbf3537Syasuoka }
6440fbf3537Syasuoka 
6450fbf3537Syasuoka /***********************************************************************
646f0a4e295Syasuoka  * Other npppd related functions.
6470fbf3537Syasuoka  ***********************************************************************/
6480fbf3537Syasuoka /**
649f0a4e295Syasuoka  * Get the user's password.  Return 0 on success.
6500fbf3537Syasuoka  *
651f0a4e295Syasuoka  * @param	username    Username who acquires password
652f0a4e295Syasuoka  * @param	password    A pointer to a buffer space to store the password.
653f0a4e295Syasuoka  *			    Use NULL when you need to know only the length of
654f0a4e295Syasuoka  *			    the password.
655f0a4e295Syasuoka  * @param	plpassword  A pointer to the length of the password parameter.
656f0a4e295Syasuoka  *			    This function uses this parameter value and stores
657f0a4e295Syasuoka  *			    the required length value pointed to by this
658f0a4e295Syasuoka  *			    parameter.  Use NULL when use don't need to know
659f0a4e295Syasuoka  *			    the password and its length.
660f0a4e295Syasuoka  * @return	If the function succeeds, 0 is returned.  The function returns
661f0a4e295Syasuoka  *		1 if the username is unknown, returns 2 if the password buffer
662f0a4e295Syasuoka  *		length is not enough.  It returns negative value for other
663f0a4e295Syasuoka  *		errors.
6640fbf3537Syasuoka  */
6650fbf3537Syasuoka int
6660fbf3537Syasuoka npppd_get_user_password(npppd *_this, npppd_ppp *ppp,
6670fbf3537Syasuoka     const char *username, char *password, int *plpassword)
6680fbf3537Syasuoka {
6690fbf3537Syasuoka 	char buf0[MAX_USERNAME_LENGTH];
6700fbf3537Syasuoka 
6710fbf3537Syasuoka 	NPPPD_ASSERT(ppp->realm != NULL);
6720fbf3537Syasuoka 	return npppd_auth_get_user_password(ppp->realm,
6730fbf3537Syasuoka 	    npppd_auth_username_for_auth(ppp->realm, username, buf0), password,
6740fbf3537Syasuoka 	    plpassword);
6750fbf3537Syasuoka }
6760fbf3537Syasuoka 
677f0a4e295Syasuoka /** Get the Framed-IP-Address attribute of the user */
6780fbf3537Syasuoka struct in_addr *
6790fbf3537Syasuoka npppd_get_user_framed_ip_address(npppd *_this, npppd_ppp *ppp,
6800fbf3537Syasuoka     const char *username)
6810fbf3537Syasuoka {
6820fbf3537Syasuoka 
6830fbf3537Syasuoka 	if (ppp->peer_auth == 0) {
6840fbf3537Syasuoka 		ppp->realm_framed_ip_address.s_addr = 0;
6850fbf3537Syasuoka 		goto do_default;
6860fbf3537Syasuoka 	}
6870fbf3537Syasuoka 	NPPPD_ASSERT(ppp->realm != NULL);
6880fbf3537Syasuoka 
689821f7c56Syasuoka 	if (ppp->realm_framed_ip_address.s_addr != 0)
6900fbf3537Syasuoka 		return &ppp->realm_framed_ip_address;
6910fbf3537Syasuoka 
692f0a4e295Syasuoka 	/* assign by the authentication realm */
6930fbf3537Syasuoka 	if (npppd_auth_get_framed_ip(ppp->realm, username,
6940fbf3537Syasuoka 	    &ppp->realm_framed_ip_address,
6950fbf3537Syasuoka 		    &ppp->realm_framed_ip_netmask) != 0)
6960fbf3537Syasuoka 		ppp->realm_framed_ip_address.s_addr = 0;
6970fbf3537Syasuoka 
6980fbf3537Syasuoka do_default:
699f0a4e295Syasuoka 	/* Use USER_SELECT if the realm doesn't specify the ip address */
7000fbf3537Syasuoka 	if (ppp->realm_framed_ip_address.s_addr == 0)
7010fbf3537Syasuoka 		ppp->realm_framed_ip_address.s_addr = INADDR_USER_SELECT;
702821f7c56Syasuoka 
703821f7c56Syasuoka 
7040fbf3537Syasuoka 	if (ppp->realm_framed_ip_address.s_addr == INADDR_USER_SELECT) {
705f0a4e295Syasuoka 		/* Use NAS_SELECT if USER_SELECT is not allowed by the config */
706821f7c56Syasuoka 		if (!ppp_ipcp(ppp)->allow_user_select)
7070fbf3537Syasuoka 			ppp->realm_framed_ip_address.s_addr = INADDR_NAS_SELECT;
7080fbf3537Syasuoka 	}
7090fbf3537Syasuoka 	NPPPD_DBG((LOG_DEBUG, "%s() = %s", __func__,
7100fbf3537Syasuoka 	    inet_ntoa(ppp->realm_framed_ip_address)));
7110fbf3537Syasuoka 
7120fbf3537Syasuoka 	return &ppp->realm_framed_ip_address;
7130fbf3537Syasuoka }
7140fbf3537Syasuoka 
7150fbf3537Syasuoka /** XXX */
7160fbf3537Syasuoka int
7170fbf3537Syasuoka npppd_check_calling_number(npppd *_this, npppd_ppp *ppp)
7180fbf3537Syasuoka {
719821f7c56Syasuoka 	struct tunnconf *conf;
720821f7c56Syasuoka 	int              lnumber, rval;
7210fbf3537Syasuoka 	char             number[NPPPD_PHONE_NUMBER_LEN + 1];
7220fbf3537Syasuoka 
723821f7c56Syasuoka 	conf = ppp_get_tunnconf(ppp);
724821f7c56Syasuoka 	if (conf->callnum_check != 0) {
7250fbf3537Syasuoka 		lnumber = sizeof(number);
7260fbf3537Syasuoka 		if ((rval = npppd_auth_get_calling_number(ppp->realm,
727821f7c56Syasuoka 		    ppp->username, number, &lnumber)) == 0)
7280fbf3537Syasuoka 			return
7290fbf3537Syasuoka 			    (strcmp(number, ppp->calling_number) == 0)? 1 : 0;
730821f7c56Syasuoka 		if ((conf->callnum_check & NPPPD_CALLNUM_CHECK_STRICT) != 0)
7310fbf3537Syasuoka 			return 0;
7320fbf3537Syasuoka 	}
7330fbf3537Syasuoka 
7340fbf3537Syasuoka 	return 1;
7350fbf3537Syasuoka }
7360fbf3537Syasuoka 
7370fbf3537Syasuoka /**
738f0a4e295Syasuoka  * This function finds a {@link npppd_ppp} instance that is assigned the
739f0a4e295Syasuoka  * specified ip address and returns it
740f0a4e295Syasuoka  * @param ipaddr	IP Address(Specify in network byte order)
7410fbf3537Syasuoka  */
7420fbf3537Syasuoka npppd_ppp *
7430fbf3537Syasuoka npppd_get_ppp_by_ip(npppd *_this, struct in_addr ipaddr)
7440fbf3537Syasuoka {
7450fbf3537Syasuoka 	struct sockaddr_npppd *snp;
7460fbf3537Syasuoka 	struct radish *rdp;
747f0a4e295Syasuoka 	struct sockaddr_in npppd_get_ppp_by_ip_sin4;
7480fbf3537Syasuoka 
749f0a4e295Syasuoka 	npppd_get_ppp_by_ip_sin4.sin_family = AF_INET;
750f0a4e295Syasuoka 	npppd_get_ppp_by_ip_sin4.sin_len = sizeof(struct sockaddr_in);
7510fbf3537Syasuoka 	npppd_get_ppp_by_ip_sin4.sin_addr = ipaddr;
7520fbf3537Syasuoka 	if (_this->rd == NULL)
753f0a4e295Syasuoka 		return NULL;	/* no radix tree on startup */
7540fbf3537Syasuoka 	if (rd_match((struct sockaddr *)&npppd_get_ppp_by_ip_sin4, _this->rd,
7550fbf3537Syasuoka 	    &rdp)) {
7560fbf3537Syasuoka 		snp = rdp->rd_rtent;
7570fbf3537Syasuoka 		if (snp->snp_type == SNP_PPP)
7580fbf3537Syasuoka 			return snp->snp_data_ptr;
7590fbf3537Syasuoka 	}
7600fbf3537Syasuoka 	return NULL;
7610fbf3537Syasuoka }
7620fbf3537Syasuoka 
7630fbf3537Syasuoka /**
764f0a4e295Syasuoka  * This function finds {@link npppd_ppp} instances that are authenticated
765f0a4e295Syasuoka  * as the specified username and returns them as a {@link slist} list.
766f0a4e295Syasuoka  * @param username	PPP Username.
767f0a4e295Syasuoka  * @return	{@link slist} that contans the {@link npppd_ppp} instances.
768f0a4e295Syasuoka  * NULL may be returned if no instance has been found.
7690fbf3537Syasuoka  */
77034682664Syasuoka static slist *
7710fbf3537Syasuoka npppd_get_ppp_by_user(npppd *_this, const char *username)
7720fbf3537Syasuoka {
7730fbf3537Syasuoka 	hash_link *hl;
7740fbf3537Syasuoka 
7750fbf3537Syasuoka 	if ((hl = hash_lookup(_this->map_user_ppp, username)) != NULL)
7760fbf3537Syasuoka 		return hl->item;
7770fbf3537Syasuoka 
7780fbf3537Syasuoka 	return NULL;
7790fbf3537Syasuoka }
7800fbf3537Syasuoka 
7810fbf3537Syasuoka /**
782f0a4e295Syasuoka  * This function finds a {@link npppd_ppp} instance that matches the specified
783f0a4e295Syasuoka  * ppp id and returns it.
784f0a4e295Syasuoka  * @param	id	{@link npppd_ppp#id ppp's id}
785f0a4e295Syasuoka  * @return	This function returns the pointer if the instance which has
786f0a4e295Syasuoka  *		specified ID is found, otherwise it returns NULL.
7870fbf3537Syasuoka  */
7880fbf3537Syasuoka npppd_ppp *
789363e4d4bSyasuoka npppd_get_ppp_by_id(npppd *_this, u_int ppp_id)
7900fbf3537Syasuoka {
7910fbf3537Syasuoka 	slist users;
7920fbf3537Syasuoka 	npppd_ppp *ppp0, *ppp;
7930fbf3537Syasuoka 
7940fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
7950fbf3537Syasuoka 
7960fbf3537Syasuoka 	ppp = NULL;
7970fbf3537Syasuoka 	slist_init(&users);
7980fbf3537Syasuoka 	if (npppd_get_all_users(_this, &users) != 0) {
7990fbf3537Syasuoka 		log_printf(LOG_WARNING,
8000fbf3537Syasuoka 		    "npppd_get_all_users() failed in %s()", __func__);
8010fbf3537Syasuoka 	} else {
802f0a4e295Syasuoka 		/* FIXME: This linear search eats CPU. */
8030fbf3537Syasuoka 		for (slist_itr_first(&users); slist_itr_has_next(&users); ) {
8040fbf3537Syasuoka 			ppp0 = slist_itr_next(&users);
8050fbf3537Syasuoka 			if (ppp0->id == ppp_id) {
8060fbf3537Syasuoka 				ppp = ppp0;
8070fbf3537Syasuoka 				break;
8080fbf3537Syasuoka 			}
8090fbf3537Syasuoka 		}
8100fbf3537Syasuoka 	}
8110fbf3537Syasuoka 	slist_fini(&users);
8120fbf3537Syasuoka 
8130fbf3537Syasuoka 	return ppp;
8140fbf3537Syasuoka }
8150fbf3537Syasuoka 
8162a5607d2Sgoda static struct ipcpstat *
8172a5607d2Sgoda npppd_get_ipcp_stat(struct ipcpstat_head *head , const char *ipcp_name)
8182a5607d2Sgoda {
8192a5607d2Sgoda 	struct ipcpstat *ipcpstat = NULL;
8202a5607d2Sgoda 
8212a5607d2Sgoda 	LIST_FOREACH(ipcpstat, head, entry) {
8222a5607d2Sgoda 		if (strncmp(ipcpstat->name, ipcp_name,
8232a5607d2Sgoda 		    sizeof(ipcpstat->name)) == 0)
8242a5607d2Sgoda 			return ipcpstat;
8252a5607d2Sgoda 	}
8262a5607d2Sgoda 
8272a5607d2Sgoda 	return NULL;
8282a5607d2Sgoda }
8292a5607d2Sgoda 
8302a5607d2Sgoda static void
8312a5607d2Sgoda npppd_destroy_ipcp_stats(struct ipcpstat_head *head)
8322a5607d2Sgoda {
8332a5607d2Sgoda 	struct ipcpstat	*ipcpstat, *tipcpstat;
8342a5607d2Sgoda 	npppd_ppp	*ppp, *tppp;
8352a5607d2Sgoda 
8362a5607d2Sgoda 	LIST_FOREACH_SAFE(ipcpstat, head, entry, tipcpstat) {
8372a5607d2Sgoda 		LIST_FOREACH_SAFE(ppp, &ipcpstat->ppp, ipcpstat_entry, tppp) {
8382a5607d2Sgoda 			ppp->ipcpstat = NULL;
8392a5607d2Sgoda 			LIST_REMOVE(ppp, ipcpstat_entry);
8402a5607d2Sgoda 		}
8412a5607d2Sgoda 		free(ipcpstat);
8422a5607d2Sgoda 	}
8432a5607d2Sgoda }
8442a5607d2Sgoda 
8452a5607d2Sgoda static void
8462a5607d2Sgoda npppd_ipcp_stats_reload(npppd *_this)
8472a5607d2Sgoda {
8482a5607d2Sgoda 	struct ipcpstat		*ipcpstat, *tipcpstat;
8492a5607d2Sgoda 	struct ipcpconf		*ipcpconf;
8502a5607d2Sgoda 	struct ipcpstat_head	 destroy_list;
8512a5607d2Sgoda 
8522a5607d2Sgoda 	LIST_INIT(&destroy_list);
8532a5607d2Sgoda 	LIST_FOREACH_SAFE(ipcpstat, &_this->ipcpstats, entry, tipcpstat) {
8542a5607d2Sgoda 		LIST_REMOVE(ipcpstat, entry);
8552a5607d2Sgoda 		LIST_INSERT_HEAD(&destroy_list, ipcpstat, entry);
8562a5607d2Sgoda 	}
8572a5607d2Sgoda 
8582a5607d2Sgoda 	TAILQ_FOREACH(ipcpconf, &_this->conf.ipcpconfs, entry) {
8592a5607d2Sgoda 		ipcpstat = npppd_get_ipcp_stat(&destroy_list, ipcpconf->name);
8602a5607d2Sgoda 		if (ipcpstat != NULL) {
8612a5607d2Sgoda 			LIST_REMOVE(ipcpstat, entry);
8622a5607d2Sgoda 			LIST_INSERT_HEAD(&_this->ipcpstats, ipcpstat, entry);
8632a5607d2Sgoda 			continue;
8642a5607d2Sgoda 		}
8652a5607d2Sgoda 
8662a5607d2Sgoda 		ipcpstat = malloc(sizeof(*ipcpstat));
8672a5607d2Sgoda 		if (ipcpstat == NULL) {
8682a5607d2Sgoda 			log_printf(LOG_ERR, "initializing ipcp_stats failed : %m");
8692a5607d2Sgoda 			continue;
8702a5607d2Sgoda 		}
8712a5607d2Sgoda 		memset(ipcpstat, 0, sizeof(*ipcpstat));
8722a5607d2Sgoda 		strlcpy(ipcpstat->name, ipcpconf->name, sizeof(ipcpconf->name));
8732a5607d2Sgoda 		LIST_INSERT_HEAD(&_this->ipcpstats, ipcpstat, entry);
8742a5607d2Sgoda 	}
8752a5607d2Sgoda 	npppd_destroy_ipcp_stats(&destroy_list);
8762a5607d2Sgoda }
8772a5607d2Sgoda 
8780fbf3537Syasuoka /**
879f0a4e295Syasuoka  * Checks whether the user reaches the maximum session limit
880f0a4e295Syasuoka  * (user_max_serssion).
881f0a4e295Syasuoka  * @return	This function returns 1(true) if the user does not reach the
882f0a4e295Syasuoka  *		limit, otherwise it returns 0(false).
8830fbf3537Syasuoka  */
8840fbf3537Syasuoka int
8850fbf3537Syasuoka npppd_check_user_max_session(npppd *_this, npppd_ppp *ppp)
8860fbf3537Syasuoka {
887d50b169aSgoda 	int global_count, realm_count;
8880fbf3537Syasuoka 	npppd_ppp *ppp1;
8890fbf3537Syasuoka 	slist *uppp;
8900fbf3537Syasuoka 
891f0a4e295Syasuoka 	/* user_max_session == 0 means unlimit */
892d50b169aSgoda 	if (_this->conf.user_max_session == 0 &&
893d50b169aSgoda 	    npppd_auth_user_session_unlimited(ppp->realm))
8940fbf3537Syasuoka 		return 1;
8950fbf3537Syasuoka 
896d50b169aSgoda 	global_count = realm_count = 0;
8970fbf3537Syasuoka 	if ((uppp = npppd_get_ppp_by_user(_this, ppp->username)) != NULL) {
8980fbf3537Syasuoka 		for (slist_itr_first(uppp); slist_itr_has_next(uppp); ) {
8990fbf3537Syasuoka 			ppp1 = slist_itr_next(uppp);
900d50b169aSgoda 			if (ppp->realm == ppp1->realm)
901d50b169aSgoda 				realm_count++;
902d50b169aSgoda 			global_count++;
9030fbf3537Syasuoka 		}
9040fbf3537Syasuoka 	}
9050fbf3537Syasuoka 
906d50b169aSgoda 	if (npppd_check_auth_user_max_session(ppp->realm, realm_count)) {
907d50b169aSgoda 		ppp_log(ppp, LOG_WARNING,
908d50b169aSgoda 		    "user %s exceeds user-max-session limit per auth",
909d50b169aSgoda 		    ppp->username);
910d50b169aSgoda 		return 0;
911d50b169aSgoda 	} else if (_this->conf.user_max_session != 0 &&
912d50b169aSgoda 	    _this->conf.user_max_session <= global_count) {
913d50b169aSgoda 		ppp_log(ppp, LOG_WARNING,
914d50b169aSgoda 		    "user %s exceeds user-max-session limit", ppp->username);
915d50b169aSgoda 		return 0;
916d50b169aSgoda 	} else
917d50b169aSgoda 		return 1;
9180fbf3537Syasuoka }
9190fbf3537Syasuoka 
9200fbf3537Syasuoka /***********************************************************************
921f0a4e295Syasuoka  * Network I/O ralated functions.
9220fbf3537Syasuoka  ***********************************************************************/
9230fbf3537Syasuoka /**
924f0a4e295Syasuoka  * Call this function to output packets to the network(tun).  This function
925f0a4e295Syasuoka  * currently assumes the packet is a IPv4 datagram.
9260fbf3537Syasuoka  */
9270fbf3537Syasuoka void
9280fbf3537Syasuoka npppd_network_output(npppd *_this, npppd_ppp *ppp, int proto, u_char *pktp,
9290fbf3537Syasuoka     int lpktp)
9300fbf3537Syasuoka {
9310fbf3537Syasuoka 	struct ip *pip;
9320fbf3537Syasuoka 	int lbuf;
933f0a4e295Syasuoka 	u_char buf[256];	/* enough size for TCP/IP header */
9340fbf3537Syasuoka 
9350fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
9360fbf3537Syasuoka 
9370fbf3537Syasuoka 	if (!ppp_ip_assigned(ppp))
9380fbf3537Syasuoka 		return;
9390fbf3537Syasuoka 
9400fbf3537Syasuoka 	if (lpktp < sizeof(struct ip)) {
9410fbf3537Syasuoka 		ppp_log(ppp, LOG_DEBUG, "Received IP packet is too small");
9420fbf3537Syasuoka 		return;
9430fbf3537Syasuoka 	}
944dbad4650Sderaadt 	lbuf = MINIMUM(lpktp, sizeof(buf));
9450fbf3537Syasuoka 	if (!ALIGNED_POINTER(pktp, struct ip)) {
9460fbf3537Syasuoka 		memcpy(buf, pktp, lbuf);
9470fbf3537Syasuoka 		pip = (struct ip *)buf;
9480fbf3537Syasuoka 	} else {
9490fbf3537Syasuoka 		pip = (struct ip *)pktp;
9500fbf3537Syasuoka 	}
9510fbf3537Syasuoka 
9523b5b2d97Syasuoka 	if (ppp->ingress_filter != 0 &&
9533b5b2d97Syasuoka 	    (pip->ip_src.s_addr & ppp->ppp_framed_ip_netmask.s_addr)
9543b5b2d97Syasuoka 		    != (ppp->ppp_framed_ip_address.s_addr &
9550fbf3537Syasuoka 			ppp->ppp_framed_ip_netmask.s_addr)) {
9560fbf3537Syasuoka 		char logbuf[80];
9570fbf3537Syasuoka 		strlcpy(logbuf, inet_ntoa(pip->ip_dst), sizeof(logbuf));
9580fbf3537Syasuoka 		ppp_log(ppp, LOG_INFO,
9590fbf3537Syasuoka 		    "Drop packet by ingress filter.  %s => %s",
9600fbf3537Syasuoka 		    inet_ntoa(pip->ip_src), logbuf);
9610fbf3537Syasuoka 
9620fbf3537Syasuoka 		return;
9630fbf3537Syasuoka 	}
9640fbf3537Syasuoka 	if (ppp->timeout_sec > 0 && !ip_is_idle_packet(pip, lbuf))
9650fbf3537Syasuoka 		ppp_reset_idle_timeout(ppp);
9660fbf3537Syasuoka 
9670fbf3537Syasuoka #ifndef NO_ADJUST_MSS
9680fbf3537Syasuoka 	if (ppp->adjust_mss) {
9690fbf3537Syasuoka 		if (lpktp == lbuf) {
9700fbf3537Syasuoka 			/*
971f0a4e295Syasuoka 			 * We can assume the packet length is less than
972f0a4e295Syasuoka 			 * sizeof(buf).
9730fbf3537Syasuoka 			 */
9740fbf3537Syasuoka 			if (!ALIGNED_POINTER(pktp, struct ip))
9750fbf3537Syasuoka 				pktp = buf;
9760fbf3537Syasuoka 			adjust_tcp_mss(pktp, lpktp, MRU_IPMTU(ppp->peer_mru));
9770fbf3537Syasuoka 		}
9780fbf3537Syasuoka 	}
9790fbf3537Syasuoka #endif
98041d69f6eSyasuoka 	npppd_iface_write(ppp_iface(ppp), ppp, proto, pktp, lpktp);
9810fbf3537Syasuoka }
9820fbf3537Syasuoka 
9830fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
984f0a4e295Syasuoka /***********************************************************************
985f0a4e295Syasuoka  * PIPEX related functions
986f0a4e295Syasuoka  ***********************************************************************/
9870fbf3537Syasuoka static void
9880fbf3537Syasuoka pipex_setup_common(npppd_ppp *ppp, struct pipex_session_req *req)
9890fbf3537Syasuoka {
9900fbf3537Syasuoka 	memset(req, 0, sizeof(*req));
9910fbf3537Syasuoka 	if (psm_opt_is_accepted(&ppp->lcp, acfc))
9920fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_ACFC_ENABLED;
9930fbf3537Syasuoka 	if (psm_peer_opt_is_accepted(&ppp->lcp, acfc))
9940fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_ACFC_ACCEPTED;
9950fbf3537Syasuoka 
9960fbf3537Syasuoka 	if (psm_peer_opt_is_accepted(&ppp->lcp, pfc))
9970fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_PFC_ACCEPTED;
9980fbf3537Syasuoka 	if (psm_opt_is_accepted(&ppp->lcp, pfc))
9990fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_PFC_ENABLED;
10000fbf3537Syasuoka 
10010fbf3537Syasuoka 	if (ppp->has_acf != 0)
10020fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_HAS_ACF;
10030fbf3537Syasuoka 
10040fbf3537Syasuoka 	if (ppp->adjust_mss != 0)
10050fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_ADJUST_TCPMSS;
10063b5b2d97Syasuoka 	if (ppp->ingress_filter != 0)
10073b5b2d97Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_INGRESS_FILTER;
10080fbf3537Syasuoka 
1009cd8e09b9Sdlg 	req->pr_ip_srcaddr = ppp->pppd->iface[0].ip4addr;
10100fbf3537Syasuoka 	req->pr_ip_address = ppp->ppp_framed_ip_address;
10110fbf3537Syasuoka 	req->pr_ip_netmask = ppp->ppp_framed_ip_netmask;
10120fbf3537Syasuoka 	req->pr_peer_mru = ppp->peer_mru;
10130fbf3537Syasuoka 	req->pr_ppp_id = ppp->id;
10140fbf3537Syasuoka 
10150fbf3537Syasuoka 	req->pr_timeout_sec = ppp->timeout_sec;
10160fbf3537Syasuoka 
10170fbf3537Syasuoka #ifdef USE_NPPPD_MPPE
10180fbf3537Syasuoka 	req->pr_ccp_id = ppp->ccp.fsm.id;
1019de0a2dd6Syasuoka 	if (ppp->mppe.send.keybits > 0) {
10200fbf3537Syasuoka 		memcpy(req->pr_mppe_send.master_key,
1021de0a2dd6Syasuoka 		    ppp->mppe.send.master_key,
1022de0a2dd6Syasuoka 		    sizeof(req->pr_mppe_send.master_key));
10230fbf3537Syasuoka 		req->pr_mppe_send.stateless = ppp->mppe.send.stateless;
10240fbf3537Syasuoka 		req->pr_mppe_send.keylenbits = ppp->mppe.send.keybits;
1025de0a2dd6Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_MPPE_ENABLED;
1026de0a2dd6Syasuoka 	}
1027de0a2dd6Syasuoka 	if (ppp->mppe.recv.keybits > 0) {
10280fbf3537Syasuoka 		memcpy(req->pr_mppe_recv.master_key,
1029de0a2dd6Syasuoka 		    ppp->mppe.recv.master_key,
1030de0a2dd6Syasuoka 		    sizeof(req->pr_mppe_recv.master_key));
10310fbf3537Syasuoka 		req->pr_mppe_recv.stateless = ppp->mppe.recv.stateless;
10320fbf3537Syasuoka 		req->pr_mppe_recv.keylenbits = ppp->mppe.recv.keybits;
10330fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_MPPE_ACCEPTED;
10340fbf3537Syasuoka 	}
10350fbf3537Syasuoka 	if (ppp->mppe.required)
10360fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_MPPE_REQUIRED;
10370fbf3537Syasuoka #endif /* USE_NPPPD_MPPE */
10380fbf3537Syasuoka }
10390fbf3537Syasuoka 
1040f0a4e295Syasuoka /** Enable PIPEX of the {@link npppd_ppp ppp} */
10410fbf3537Syasuoka int
10420fbf3537Syasuoka npppd_ppp_pipex_enable(npppd *_this, npppd_ppp *ppp)
10430fbf3537Syasuoka {
10440fbf3537Syasuoka 	struct pipex_session_req req;
10450fbf3537Syasuoka #ifdef	USE_NPPPD_PPPOE
10460fbf3537Syasuoka 	pppoe_session *pppoe;
10470fbf3537Syasuoka #endif
10480fbf3537Syasuoka #ifdef	USE_NPPPD_PPTP
10490fbf3537Syasuoka 	pptp_call *call;
10500fbf3537Syasuoka #endif
1051886d2b78Syasuoka #ifdef	USE_NPPPD_L2TP
1052886d2b78Syasuoka 	l2tp_call *l2tp;
1053886d2b78Syasuoka 	l2tp_ctrl *l2tpctrl;
1054886d2b78Syasuoka #endif
10550fbf3537Syasuoka 	int error;
10560fbf3537Syasuoka 
10570fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
10580fbf3537Syasuoka 	NPPPD_ASSERT(ppp->phy_context != NULL);
10590fbf3537Syasuoka 	NPPPD_ASSERT(ppp->use_pipex != 0);
10600fbf3537Syasuoka 
10610fbf3537Syasuoka 	pipex_setup_common(ppp, &req);
10620fbf3537Syasuoka 
10630fbf3537Syasuoka 	switch (ppp->tunnel_type) {
10640fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
1065821f7c56Syasuoka 	case NPPPD_TUNNEL_PPPOE:
1066886d2b78Syasuoka 	    {
1067886d2b78Syasuoka 		struct sockaddr *sa;
1068886d2b78Syasuoka 		struct ether_header *eh;
10690fbf3537Syasuoka 		pppoe = (pppoe_session *)ppp->phy_context;
10700fbf3537Syasuoka 
1071f0a4e295Syasuoka 		/* PPPoE specific informations */
10720fbf3537Syasuoka 		req.pr_protocol = PIPEX_PROTO_PPPOE;
10730fbf3537Syasuoka 		req.pr_session_id = pppoe->session_id;
10740fbf3537Syasuoka 		req.pr_peer_session_id = 0;
10750fbf3537Syasuoka 		strlcpy(req.pr_proto.pppoe.over_ifname,
10760fbf3537Syasuoka 		    pppoe_session_listen_ifname(pppoe),
10770fbf3537Syasuoka 		    sizeof(req.pr_proto.pppoe.over_ifname));
1078886d2b78Syasuoka 
1079bdfe8fd0Syasuoka 		sa = (struct sockaddr *)&req.pr_peer_address;
1080886d2b78Syasuoka 		sa->sa_family = AF_UNSPEC;
1081886d2b78Syasuoka 		sa->sa_len = sizeof(struct sockaddr);
1082886d2b78Syasuoka 
1083886d2b78Syasuoka 		eh = (struct ether_header *)sa->sa_data;
1084886d2b78Syasuoka 		eh->ether_type = htons(ETHERTYPE_PPPOE);
1085886d2b78Syasuoka 		memcpy(eh->ether_dhost, pppoe->ether_addr, ETHER_ADDR_LEN);
1086886d2b78Syasuoka 		memset(eh->ether_shost, 0, ETHER_ADDR_LEN);
10870fbf3537Syasuoka 
10880fbf3537Syasuoka 		break;
1089886d2b78Syasuoka 	    }
10900fbf3537Syasuoka #endif
10910fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
1092821f7c56Syasuoka 	case NPPPD_TUNNEL_PPTP:
10930fbf3537Syasuoka 		call = (pptp_call *)ppp->phy_context;
10940fbf3537Syasuoka 
1095f0a4e295Syasuoka 		/* PPTP specific informations */
10960fbf3537Syasuoka 		req.pr_session_id = call->id;
10970fbf3537Syasuoka 		req.pr_protocol = PIPEX_PROTO_PPTP;
10980fbf3537Syasuoka 
10990fbf3537Syasuoka 		req.pr_peer_session_id = call->peers_call_id;
11000fbf3537Syasuoka 		req.pr_proto.pptp.snd_nxt = call->snd_nxt;
11010fbf3537Syasuoka 		req.pr_proto.pptp.snd_una = call->snd_una;
11020fbf3537Syasuoka 		req.pr_proto.pptp.rcv_nxt = call->rcv_nxt;
11030fbf3537Syasuoka 		req.pr_proto.pptp.rcv_acked = call->rcv_acked;
11040fbf3537Syasuoka 		req.pr_proto.pptp.winsz = call->winsz;
11050fbf3537Syasuoka 		req.pr_proto.pptp.maxwinsz = call->maxwinsz;
11060fbf3537Syasuoka 		req.pr_proto.pptp.peer_maxwinsz = call->peers_maxwinsz;
11070fbf3537Syasuoka 
11080fbf3537Syasuoka 		NPPPD_ASSERT(call->ctrl->peer.ss_family == AF_INET);
11090fbf3537Syasuoka 		NPPPD_ASSERT(call->ctrl->our.ss_family == AF_INET);
1110886d2b78Syasuoka 
1111bdfe8fd0Syasuoka 		memcpy(&req.pr_peer_address, &call->ctrl->peer,
1112886d2b78Syasuoka 		    call->ctrl->peer.ss_len);
1113bdfe8fd0Syasuoka 		memcpy(&req.pr_local_address, &call->ctrl->our,
1114886d2b78Syasuoka 		    call->ctrl->our.ss_len);
1115886d2b78Syasuoka 		break;
1116886d2b78Syasuoka #endif
1117886d2b78Syasuoka #ifdef USE_NPPPD_L2TP
1118821f7c56Syasuoka 	case NPPPD_TUNNEL_L2TP:
1119886d2b78Syasuoka 		l2tp = (l2tp_call *)ppp->phy_context;
1120886d2b78Syasuoka 		l2tpctrl = l2tp->ctrl;
1121886d2b78Syasuoka 
1122886d2b78Syasuoka 		/* L2TPv2 specific context */
1123886d2b78Syasuoka 		/* Session KEYS */
1124886d2b78Syasuoka 		req.pr_protocol = PIPEX_PROTO_L2TP;
1125886d2b78Syasuoka 		req.pr_proto.l2tp.tunnel_id = l2tpctrl->tunnel_id;
1126886d2b78Syasuoka 		req.pr_proto.l2tp.peer_tunnel_id = l2tpctrl->peer_tunnel_id;
1127886d2b78Syasuoka 		req.pr_session_id = l2tp->session_id;
1128886d2b78Syasuoka 		req.pr_peer_session_id = l2tp->peer_session_id;
1129886d2b78Syasuoka 
1130886d2b78Syasuoka 		if (l2tpctrl->data_use_seq)
1131886d2b78Syasuoka 			req.pr_proto.l2tp.option_flags |=
1132886d2b78Syasuoka 			    PIPEX_L2TP_USE_SEQUENCING;
1133886d2b78Syasuoka 
1134886d2b78Syasuoka 		/* transmission control contexts */
1135886d2b78Syasuoka 		req.pr_proto.l2tp.ns_nxt = l2tp->snd_nxt;
1136886d2b78Syasuoka 		req.pr_proto.l2tp.nr_nxt = l2tp->rcv_nxt;
1137886d2b78Syasuoka 
1138bdfe8fd0Syasuoka 		memcpy(&req.pr_peer_address, &l2tpctrl->peer,
1139886d2b78Syasuoka 		    l2tpctrl->peer.ss_len);
1140bdfe8fd0Syasuoka 		memcpy(&req.pr_local_address, &l2tpctrl->sock,
1141886d2b78Syasuoka 		    l2tpctrl->sock.ss_len);
1142a5018c90Syasuoka #ifdef USE_SA_COOKIE
1143a5018c90Syasuoka 		if (l2tpctrl->sa_cookie != NULL) {
1144a5018c90Syasuoka 			req.pr_proto.l2tp.ipsecflowinfo =
1145a5018c90Syasuoka 			    ((struct in_ipsec_sa_cookie *)l2tpctrl->sa_cookie)
1146a5018c90Syasuoka 				    ->ipsecflow;
1147a5018c90Syasuoka 		}
1148886d2b78Syasuoka #endif
11490fbf3537Syasuoka 		break;
11500fbf3537Syasuoka #endif
11510fbf3537Syasuoka 	default:
11520fbf3537Syasuoka 		return 1;
11530fbf3537Syasuoka 	}
11540fbf3537Syasuoka 
11550fbf3537Syasuoka 	if ((error = ioctl(_this->iface[ppp->ifidx].devf, PIPEXASESSION, &req))
11560fbf3537Syasuoka 	    != 0) {
11570fbf3537Syasuoka 		if (errno == ENXIO)	/* pipex is disabled on runtime */
11580fbf3537Syasuoka 			error = 0;
11590fbf3537Syasuoka 		ppp->pipex_enabled = 0;
11600fbf3537Syasuoka 		return error;
11610fbf3537Syasuoka 	}
11620fbf3537Syasuoka 
1163cd8e09b9Sdlg 	if (_this->iface[ppp->ifidx].using_pppx) {
1164cd8e09b9Sdlg 		struct pipex_session_descr_req descr_req;
1165cd8e09b9Sdlg 
1166cd8e09b9Sdlg 		descr_req.pdr_protocol = req.pr_protocol;
1167cd8e09b9Sdlg 		descr_req.pdr_session_id = req.pr_session_id;
1168cd8e09b9Sdlg 		memset(descr_req.pdr_descr, 0, sizeof(descr_req.pdr_descr));
1169cd8e09b9Sdlg 		strlcpy(descr_req.pdr_descr, ppp->username, sizeof(descr_req.pdr_descr));
1170cd8e09b9Sdlg 		error = ioctl(_this->iface[ppp->ifidx].devf, PIPEXSIFDESCR, &descr_req);
1171cd8e09b9Sdlg 		if (error != 0) {
1172cd8e09b9Sdlg 			log_printf(LOG_WARNING, "PIPEXSIFDESCR(%s) failed: %d\n", ppp->username, error);
1173cd8e09b9Sdlg 		}
1174cd8e09b9Sdlg 	}
1175cd8e09b9Sdlg 
11760fbf3537Syasuoka 	ppp->pipex_enabled = 1;
11770fbf3537Syasuoka 	if (ppp->timeout_sec > 0) {
1178f0a4e295Syasuoka 		/* Stop the npppd's idle-timer.  We use pipex's idle-timer */
11790fbf3537Syasuoka 		ppp->timeout_sec = 0;
11800fbf3537Syasuoka 		ppp_reset_idle_timeout(ppp);
11810fbf3537Syasuoka 	}
11820fbf3537Syasuoka 
11830fbf3537Syasuoka 	return error;
11840fbf3537Syasuoka }
11850fbf3537Syasuoka 
1186f0a4e295Syasuoka /** Disable PIPEX of the {@link npppd_ppp ppp} */
11870fbf3537Syasuoka int
11880fbf3537Syasuoka npppd_ppp_pipex_disable(npppd *_this, npppd_ppp *ppp)
11890fbf3537Syasuoka {
11900fbf3537Syasuoka 	struct pipex_session_close_req req;
11910fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
11920fbf3537Syasuoka 	pppoe_session *pppoe;
11930fbf3537Syasuoka #endif
11940fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
11950fbf3537Syasuoka 	pptp_call *call;
11960fbf3537Syasuoka #endif
1197886d2b78Syasuoka #ifdef USE_NPPPD_L2TP
1198886d2b78Syasuoka 	l2tp_call *l2tp;
1199886d2b78Syasuoka #endif
12000fbf3537Syasuoka 	int error;
12010fbf3537Syasuoka 
12020fbf3537Syasuoka 	if (ppp->pipex_started == 0)
12030fbf3537Syasuoka 		return 0;	/* not started */
12040fbf3537Syasuoka 
12050fbf3537Syasuoka 	bzero(&req, sizeof(req));
12060fbf3537Syasuoka 	switch(ppp->tunnel_type) {
12070fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
1208821f7c56Syasuoka 	case NPPPD_TUNNEL_PPPOE:
12090fbf3537Syasuoka 		pppoe = (pppoe_session *)ppp->phy_context;
12100fbf3537Syasuoka 
1211f0a4e295Syasuoka 		/* PPPoE specific informations */
12120fbf3537Syasuoka 		req.pcr_protocol = PIPEX_PROTO_PPPOE;
12130fbf3537Syasuoka 		req.pcr_session_id = pppoe->session_id;
12140fbf3537Syasuoka 		break;
12150fbf3537Syasuoka #endif
12160fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
1217821f7c56Syasuoka 	case NPPPD_TUNNEL_PPTP:
12180fbf3537Syasuoka 		call = (pptp_call *)ppp->phy_context;
12190fbf3537Syasuoka 
1220f0a4e295Syasuoka 		/* PPTP specific informations */
12210fbf3537Syasuoka 		req.pcr_session_id = call->id;
12220fbf3537Syasuoka 		req.pcr_protocol = PIPEX_PROTO_PPTP;
12230fbf3537Syasuoka 		break;
12240fbf3537Syasuoka #endif
1225fd218b06Smarkus #ifdef USE_NPPPD_L2TP
1226821f7c56Syasuoka 	case NPPPD_TUNNEL_L2TP:
1227fd218b06Smarkus 		l2tp = (l2tp_call *)ppp->phy_context;
1228fd218b06Smarkus 
1229fd218b06Smarkus 		/* L2TP specific context */
1230fd218b06Smarkus 		req.pcr_session_id = l2tp->session_id;
1231fd218b06Smarkus 		req.pcr_protocol = PIPEX_PROTO_L2TP;
1232fd218b06Smarkus 		break;
1233fd218b06Smarkus #endif
12340fbf3537Syasuoka 	default:
12350fbf3537Syasuoka 		return 1;
12360fbf3537Syasuoka 	}
12370fbf3537Syasuoka 
12380fbf3537Syasuoka 	error = ioctl(_this->iface[ppp->ifidx].devf, PIPEXDSESSION, &req);
12390fbf3537Syasuoka 	if (error == 0) {
12400fbf3537Syasuoka 		ppp->ipackets += req.pcr_stat.ipackets;
12410fbf3537Syasuoka 		ppp->opackets += req.pcr_stat.opackets;
12420fbf3537Syasuoka 		ppp->ierrors += req.pcr_stat.ierrors;
12430fbf3537Syasuoka 		ppp->oerrors += req.pcr_stat.oerrors;
12440fbf3537Syasuoka 		ppp->ibytes += req.pcr_stat.ibytes;
12450fbf3537Syasuoka 		ppp->obytes += req.pcr_stat.obytes;
12460fbf3537Syasuoka 		ppp->pipex_enabled = 0;
12470fbf3537Syasuoka 	}
12480fbf3537Syasuoka 
12490fbf3537Syasuoka 	return error;
12500fbf3537Syasuoka }
12510fbf3537Syasuoka 
1252f0a4e295Syasuoka /* XXX: s/npppd_ppp_pipex_ip_disable/npppd_ppp_pipex_stop/ ?? */
1253f0a4e295Syasuoka 
1254f0a4e295Syasuoka /** Stop PIPEX of the {@link npppd_ppp ppp} */
12550fbf3537Syasuoka static int
12560fbf3537Syasuoka npppd_ppp_pipex_ip_disable(npppd *_this, npppd_ppp *ppp)
12570fbf3537Syasuoka {
12580fbf3537Syasuoka 	struct pipex_session_config_req req;
12590fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
12600fbf3537Syasuoka 	pppoe_session *pppoe;
12610fbf3537Syasuoka #endif
12620fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
12630fbf3537Syasuoka 	pptp_call *call;
12640fbf3537Syasuoka #endif
1265886d2b78Syasuoka #ifdef USE_NPPPD_L2TP
1266886d2b78Syasuoka 	l2tp_call *l2tp;
1267886d2b78Syasuoka #endif
12680fbf3537Syasuoka 	if (ppp->pipex_started == 0)
12690fbf3537Syasuoka 		return 0;	/* not started */
12700fbf3537Syasuoka 
12710fbf3537Syasuoka 	bzero(&req, sizeof(req));
12720fbf3537Syasuoka 	switch(ppp->tunnel_type) {
12730fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
1274821f7c56Syasuoka 	case NPPPD_TUNNEL_PPPOE:
12750fbf3537Syasuoka 		pppoe = (pppoe_session *)ppp->phy_context;
12760fbf3537Syasuoka 
1277f0a4e295Syasuoka 		/* PPPoE specific informations */
12780fbf3537Syasuoka 		req.pcr_protocol = PIPEX_PROTO_PPPOE;
12790fbf3537Syasuoka 		req.pcr_session_id = pppoe->session_id;
12800fbf3537Syasuoka 		break;
12810fbf3537Syasuoka #endif
12820fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
1283821f7c56Syasuoka 	case NPPPD_TUNNEL_PPTP:
12840fbf3537Syasuoka 		call = (pptp_call *)ppp->phy_context;
12850fbf3537Syasuoka 
1286f0a4e295Syasuoka 		/* PPTP specific informations */
12870fbf3537Syasuoka 		req.pcr_session_id = call->id;
12880fbf3537Syasuoka 		req.pcr_protocol = PIPEX_PROTO_PPTP;
12890fbf3537Syasuoka 		break;
12900fbf3537Syasuoka #endif
1291886d2b78Syasuoka #ifdef USE_NPPPD_L2TP
1292821f7c56Syasuoka 	case NPPPD_TUNNEL_L2TP:
1293886d2b78Syasuoka 		l2tp = (l2tp_call *)ppp->phy_context;
1294886d2b78Syasuoka 
1295886d2b78Syasuoka 		/* L2TP specific context */
1296886d2b78Syasuoka 		req.pcr_session_id = l2tp->session_id;
1297886d2b78Syasuoka 		req.pcr_protocol = PIPEX_PROTO_L2TP;
1298886d2b78Syasuoka 		break;
1299886d2b78Syasuoka #endif
13000fbf3537Syasuoka 	default:
13010fbf3537Syasuoka 		return 1;
13020fbf3537Syasuoka 	}
13030fbf3537Syasuoka 	req.pcr_ip_forward = 0;
13040fbf3537Syasuoka 
13050fbf3537Syasuoka 	return ioctl(_this->iface[ppp->ifidx].devf, PIPEXCSESSION, &req);
13060fbf3537Syasuoka }
13070fbf3537Syasuoka 
13080fbf3537Syasuoka static void
13090fbf3537Syasuoka pipex_periodic(npppd *_this)
13100fbf3537Syasuoka {
13110fbf3537Syasuoka 	struct pipex_session_list_req  req;
13120fbf3537Syasuoka 	npppd_ppp                     *ppp;
1313ec8bab80Syasuoka 	int                            i, devf, error;
1314363e4d4bSyasuoka 	u_int                          ppp_id;
13150fbf3537Syasuoka 	slist                          dlist, users;
13160fbf3537Syasuoka 
13170fbf3537Syasuoka 	slist_init(&dlist);
13180fbf3537Syasuoka 	slist_init(&users);
1319ec8bab80Syasuoka 
1320ec8bab80Syasuoka 	devf = -1;
1321ec8bab80Syasuoka 	for (i = 0; i < nitems(_this->iface); i++) {
1322ec8bab80Syasuoka 		if (_this->iface[i].initialized != 0) {
1323ec8bab80Syasuoka 			devf = _this->iface[i].devf;
1324ec8bab80Syasuoka 			break;
1325ec8bab80Syasuoka 		}
1326ec8bab80Syasuoka 	}
1327ec8bab80Syasuoka 	if (devf >= 0) {
13280fbf3537Syasuoka 		do {
1329ec8bab80Syasuoka 			error = ioctl(devf, PIPEXGCLOSED, &req);
13300fbf3537Syasuoka 			if (error) {
13310fbf3537Syasuoka 				if (errno != ENXIO)
13320fbf3537Syasuoka 					log_printf(LOG_WARNING,
13330fbf3537Syasuoka 					    "PIPEXGCLOSED failed: %m");
13340fbf3537Syasuoka 				break;
13350fbf3537Syasuoka 			}
13360fbf3537Syasuoka 			for (i = 0; i < req.plr_ppp_id_count; i++) {
13370fbf3537Syasuoka 				ppp_id = req.plr_ppp_id[i];
1338c46ae403Syasuoka 				slist_add(&dlist, (void *)(uintptr_t)ppp_id);
13390fbf3537Syasuoka 			}
13400fbf3537Syasuoka 		} while (req.plr_flags & PIPEX_LISTREQ_MORE);
1341ec8bab80Syasuoka 	}
13420fbf3537Syasuoka 
13430fbf3537Syasuoka 	if (slist_length(&dlist) <= 0)
13440fbf3537Syasuoka 		goto pipex_done;
13450fbf3537Syasuoka 	if (npppd_get_all_users(_this, &users) != 0) {
13460fbf3537Syasuoka 		log_printf(LOG_WARNING,
13470fbf3537Syasuoka 		    "npppd_get_all_users() failed in %s()", __func__);
13480fbf3537Syasuoka 		slist_fini(&users);
13490fbf3537Syasuoka 		goto pipex_done;
13500fbf3537Syasuoka 	}
13510fbf3537Syasuoka 
1352f0a4e295Syasuoka 	/* Disconnect request */
13530fbf3537Syasuoka 	slist_itr_first(&dlist);
13540fbf3537Syasuoka 	while (slist_itr_has_next(&dlist)) {
1355f0a4e295Syasuoka 		/* FIXME: Linear search by PPP Id eats CPU */
1356c46ae403Syasuoka 		ppp_id = (uintptr_t)slist_itr_next(&dlist);
13570fbf3537Syasuoka 		slist_itr_first(&users);
13580fbf3537Syasuoka 		ppp = NULL;
13590fbf3537Syasuoka 		while (slist_itr_has_next(&users)) {
13600fbf3537Syasuoka 			ppp =  slist_itr_next(&users);
13610fbf3537Syasuoka 			if (ppp_id == ppp->id) {
13620fbf3537Syasuoka 				/* found */
13630fbf3537Syasuoka 				slist_itr_remove(&users);
13640fbf3537Syasuoka 				break;
13650fbf3537Syasuoka 			}
13660fbf3537Syasuoka 			ppp = NULL;
13670fbf3537Syasuoka 		}
13680fbf3537Syasuoka 		if (ppp == NULL) {
13690fbf3537Syasuoka 			log_printf(LOG_WARNING,
13700fbf3537Syasuoka 			    "kernel requested a ppp down, but it's not found.  "
13710fbf3537Syasuoka 			    "ppp=%d", ppp_id);
13720fbf3537Syasuoka 			continue;
13730fbf3537Syasuoka 		}
13740fbf3537Syasuoka 		ppp_log(ppp, LOG_INFO, "Stop requested by the kernel");
13758daf7599Syasuoka 		/* TODO: PIPEX doesn't return the disconect reason */
13768daf7599Syasuoka #ifdef USE_NPPPD_RADIUS
13778daf7599Syasuoka 		ppp_set_radius_terminate_cause(ppp,
13788daf7599Syasuoka 		    RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT);
13798daf7599Syasuoka #endif
13800fbf3537Syasuoka 		ppp_stop(ppp, NULL);
13810fbf3537Syasuoka 	}
13820fbf3537Syasuoka pipex_done:
13830fbf3537Syasuoka 	slist_fini(&users);
13840fbf3537Syasuoka 	slist_fini(&dlist);
13850fbf3537Syasuoka }
13860fbf3537Syasuoka #endif /* USE_NPPPD_PIPEX */
13870fbf3537Syasuoka 
13880fbf3537Syasuoka /***********************************************************************
1389f0a4e295Syasuoka  * IP address assignment related functions
13900fbf3537Syasuoka  ***********************************************************************/
1391f0a4e295Syasuoka /** Prepare to use IP */
13920fbf3537Syasuoka int
13930fbf3537Syasuoka npppd_prepare_ip(npppd *_this, npppd_ppp *ppp)
13940fbf3537Syasuoka {
1395821f7c56Syasuoka 
13960fbf3537Syasuoka 	if (ppp_ipcp(ppp) == NULL)
13970fbf3537Syasuoka 		return 1;
13980fbf3537Syasuoka 
13990fbf3537Syasuoka 	npppd_get_user_framed_ip_address(_this, ppp, ppp->username);
14000fbf3537Syasuoka 
14010fbf3537Syasuoka 	if (npppd_iface_ip_is_ready(ppp_iface(ppp)))
14020fbf3537Syasuoka 		ppp->ipcp.ip4_our = ppp_iface(ppp)->ip4addr;
14030fbf3537Syasuoka 	else if (npppd_iface_ip_is_ready(&_this->iface[0]))
14040fbf3537Syasuoka 		ppp->ipcp.ip4_our = _this->iface[0].ip4addr;
14050fbf3537Syasuoka 	else
14060fbf3537Syasuoka 		return -1;
1407821f7c56Syasuoka 	ppp->ipcp.dns_pri = ppp_ipcp(ppp)->dns_servers[0];
1408821f7c56Syasuoka 	ppp->ipcp.dns_sec = ppp_ipcp(ppp)->dns_servers[1];
1409821f7c56Syasuoka 	ppp->ipcp.nbns_pri = ppp_ipcp(ppp)->nbns_servers[0];
1410821f7c56Syasuoka 	ppp->ipcp.nbns_sec = ppp_ipcp(ppp)->nbns_servers[1];
14110fbf3537Syasuoka 
14120fbf3537Syasuoka 	return 0;
14130fbf3537Syasuoka }
14140fbf3537Syasuoka 
1415f0a4e295Syasuoka /** Notify stop using IP to npppd and release the resources. */
14160fbf3537Syasuoka void
14170fbf3537Syasuoka npppd_release_ip(npppd *_this, npppd_ppp *ppp)
14180fbf3537Syasuoka {
14190fbf3537Syasuoka 
14200fbf3537Syasuoka 	if (!ppp_ip_assigned(ppp))
14210fbf3537Syasuoka 		return;
14220fbf3537Syasuoka 
14230fbf3537Syasuoka 	npppd_set_ip_enabled(_this, ppp, 0);
14240fbf3537Syasuoka 	npppd_pool_release_ip(ppp->assigned_pool, ppp);
14250fbf3537Syasuoka 	ppp->assigned_pool = NULL;
14260fbf3537Syasuoka 	ppp->ppp_framed_ip_address.s_addr = 0;
14270fbf3537Syasuoka }
14280fbf3537Syasuoka 
1429f0a4e295Syasuoka /**
1430f0a4e295Syasuoka  * Change IP enableness.  When the enableness is change, npppd will operate
1431f0a4e295Syasuoka  * the route entry.
1432f0a4e295Syasuoka  */
14330fbf3537Syasuoka void
14340fbf3537Syasuoka npppd_set_ip_enabled(npppd *_this, npppd_ppp *ppp, int enabled)
14350fbf3537Syasuoka {
14360fbf3537Syasuoka 	int was_enabled, found;
14370fbf3537Syasuoka 	slist *u;
14380fbf3537Syasuoka 	hash_link *hl;
14390fbf3537Syasuoka 	npppd_ppp *ppp1;
14400fbf3537Syasuoka 
14410fbf3537Syasuoka 	NPPPD_ASSERT(ppp_ip_assigned(ppp));
14420fbf3537Syasuoka 	NPPPD_DBG((LOG_DEBUG,
14430fbf3537Syasuoka 	    "npppd_set_ip_enabled(%s/%s, %s)", ppp->username,
14440fbf3537Syasuoka 		inet_ntoa(ppp->ppp_framed_ip_address),
14450fbf3537Syasuoka 		(enabled)?"true" : "false"));
1446f0a4e295Syasuoka 
14470fbf3537Syasuoka 	/*
1448f0a4e295Syasuoka 	 * Don't do anything if the enableness is not change.  Changing route
1449f0a4e295Syasuoka 	 * makes many programs will wake up and do heavy operations, it causes
1450f0a4e295Syasuoka 	 * system overload, so we refrain useless changing route.
14510fbf3537Syasuoka 	 */
14520fbf3537Syasuoka 	enabled = (enabled)? 1 : 0;
14530fbf3537Syasuoka 	was_enabled = (ppp->assigned_ip4_enabled != 0)? 1 : 0;
14540fbf3537Syasuoka 	if (enabled == was_enabled)
14550fbf3537Syasuoka 		return;
1456f0a4e295Syasuoka 
14570fbf3537Syasuoka 	ppp->assigned_ip4_enabled = enabled;
14580fbf3537Syasuoka 	if (enabled) {
14590fbf3537Syasuoka 		if (ppp->username[0] != '\0') {
14600fbf3537Syasuoka 			if ((u = npppd_get_ppp_by_user(_this, ppp->username))
14610fbf3537Syasuoka 			    == NULL) {
14620fbf3537Syasuoka 				if ((u = malloc(sizeof(slist))) == NULL) {
14630fbf3537Syasuoka 					ppp_log(ppp, LOG_ERR,
14640fbf3537Syasuoka 					    "Out of memory on %s: %m",
14650fbf3537Syasuoka 					    __func__);
14660fbf3537Syasuoka 				} else {
14670fbf3537Syasuoka 					slist_init(u);
14680fbf3537Syasuoka 					slist_set_size(u, 4);
14690fbf3537Syasuoka 					hash_insert(_this->map_user_ppp,
14700fbf3537Syasuoka 					    ppp->username, u);
14710fbf3537Syasuoka 					NPPPD_DBG((LOG_DEBUG,
14720fbf3537Syasuoka 					    "hash_insert(user->ppp, %s)",
14730fbf3537Syasuoka 					    ppp->username));
14740fbf3537Syasuoka 				}
14750fbf3537Syasuoka 			}
1476f0a4e295Syasuoka 			if (u != NULL)	/* above malloc() may failed */
14770fbf3537Syasuoka 				slist_add(u, ppp);
14780fbf3537Syasuoka 		}
14790fbf3537Syasuoka 
14800fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
1481cd8e09b9Sdlg 		if (_this->iface[ppp->ifidx].using_pppx == 0) {
14820fbf3537Syasuoka 			if (ppp->snp.snp_next != NULL)
1483f0a4e295Syasuoka 				/*
1484f0a4e295Syasuoka 				 * There is a blackhole route that has same
1485f0a4e295Syasuoka 				 * address/mask.
1486f0a4e295Syasuoka 				 */
14870fbf3537Syasuoka 				in_route_delete(&ppp->ppp_framed_ip_address,
1488cd8e09b9Sdlg 				    &ppp->ppp_framed_ip_netmask, &loop,
1489cd8e09b9Sdlg 				    RTF_BLACKHOLE);
14900fbf3537Syasuoka 			/* See the comment for MRU_IPMTU() on ppp.h */
14910fbf3537Syasuoka 			if (ppp->ppp_framed_ip_netmask.s_addr == 0xffffffffL) {
14920fbf3537Syasuoka 				in_host_route_add(&ppp->ppp_framed_ip_address,
1493cd8e09b9Sdlg 				    &ppp_iface(ppp)->ip4addr,
1494cd8e09b9Sdlg 				    ppp_iface(ppp)->ifname,
14950fbf3537Syasuoka 				    MRU_IPMTU(ppp->peer_mru));
14960fbf3537Syasuoka 			} else {
14970fbf3537Syasuoka 				in_route_add(&ppp->ppp_framed_ip_address,
14980fbf3537Syasuoka 				    &ppp->ppp_framed_ip_netmask,
1499cd8e09b9Sdlg 				    &ppp_iface(ppp)->ip4addr,
1500cd8e09b9Sdlg 				    ppp_iface(ppp)->ifname, 0,
15010fbf3537Syasuoka 				    MRU_IPMTU(ppp->peer_mru));
15020fbf3537Syasuoka 			}
1503cd8e09b9Sdlg 		}
15040fbf3537Syasuoka #endif
15050fbf3537Syasuoka 	} else {
15060fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
1507cd8e09b9Sdlg 		if (_this->iface[ppp->ifidx].using_pppx == 0) {
15080fbf3537Syasuoka 			if (ppp->ppp_framed_ip_netmask.s_addr == 0xffffffffL) {
15090fbf3537Syasuoka 				in_host_route_delete(&ppp->ppp_framed_ip_address,
15100fbf3537Syasuoka 				    &ppp_iface(ppp)->ip4addr);
15110fbf3537Syasuoka 			} else {
15120fbf3537Syasuoka 				in_route_delete(&ppp->ppp_framed_ip_address,
15130fbf3537Syasuoka 				    &ppp->ppp_framed_ip_netmask,
15140fbf3537Syasuoka 				    &ppp_iface(ppp)->ip4addr, 0);
15150fbf3537Syasuoka 			}
15160fbf3537Syasuoka 			if (ppp->snp.snp_next != NULL)
1517f0a4e295Syasuoka 				/*
1518f0a4e295Syasuoka 				 * There is a blackhole route that has same
1519f0a4e295Syasuoka 				 * address/mask.
1520f0a4e295Syasuoka 				 */
1521cd8e09b9Sdlg 				in_route_add(&ppp->snp.snp_addr,
1522cd8e09b9Sdlg 				    &ppp->snp.snp_mask, &loop, LOOPBACK_IFNAME,
1523cd8e09b9Sdlg 				    RTF_BLACKHOLE, 0);
1524cd8e09b9Sdlg 		}
15250fbf3537Syasuoka #endif
15260fbf3537Syasuoka 		if (ppp->username[0] != '\0') {
15270fbf3537Syasuoka 			hl = hash_lookup(_this->map_user_ppp, ppp->username);
15280fbf3537Syasuoka 			NPPPD_ASSERT(hl != NULL);
15290fbf3537Syasuoka 			if (hl == NULL) {
15300fbf3537Syasuoka 				ppp_log(ppp, LOG_ERR,
15310fbf3537Syasuoka 				    "Unexpected error: cannot find user(%s) "
15320fbf3537Syasuoka 				    "from user database", ppp->username);
15330fbf3537Syasuoka 				return;
15340fbf3537Syasuoka 			}
15350fbf3537Syasuoka 			found = 0;
15360fbf3537Syasuoka 			u = hl->item;
15370fbf3537Syasuoka 			for (slist_itr_first(u); slist_itr_has_next(u);) {
15380fbf3537Syasuoka 				ppp1 = slist_itr_next(u);
15390fbf3537Syasuoka 				if (ppp1 == ppp) {
15400fbf3537Syasuoka 					slist_itr_remove(u);
15410fbf3537Syasuoka 					found++;
15420fbf3537Syasuoka 					break;
15430fbf3537Syasuoka 				}
15440fbf3537Syasuoka 			}
15450fbf3537Syasuoka 			if (found == 0) {
15460fbf3537Syasuoka 				ppp_log(ppp, LOG_ERR,
15470fbf3537Syasuoka 				    "Unexpected error: PPP instance is "
15480fbf3537Syasuoka 				    "not found in the user's list.");
15490fbf3537Syasuoka 			}
15500fbf3537Syasuoka 			NPPPD_ASSERT(found != 0);
15510fbf3537Syasuoka 			if (slist_length(u) <= 0) {
1552f0a4e295Syasuoka 				/* The last PPP */
15530fbf3537Syasuoka 				NPPPD_DBG((LOG_DEBUG,
15540fbf3537Syasuoka 				    "hash_delete(user->ppp, %s)",
15550fbf3537Syasuoka 				    ppp->username));
15560fbf3537Syasuoka 				if (hash_delete(_this->map_user_ppp,
15570fbf3537Syasuoka 				    ppp->username, 0) != 0) {
15580fbf3537Syasuoka 					ppp_log(ppp, LOG_ERR,
15590fbf3537Syasuoka 					    "Unexpected error: cannot delete "
15600fbf3537Syasuoka 					    "user(%s) from user database",
15610fbf3537Syasuoka 					    ppp->username);
15620fbf3537Syasuoka 				}
15630fbf3537Syasuoka 				slist_fini(u);
15640fbf3537Syasuoka 				free(u);
15650fbf3537Syasuoka 			} else {
1566f0a4e295Syasuoka 				/* Replace the reference. */
15670fbf3537Syasuoka 				ppp1 = slist_get(u, 0);
15680fbf3537Syasuoka 				hl->key = ppp1->username;
15690fbf3537Syasuoka 			}
15700fbf3537Syasuoka 		}
15710fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
15720fbf3537Syasuoka 		if (npppd_ppp_pipex_ip_disable(_this, ppp) != 0)
15730fbf3537Syasuoka 			ppp_log(ppp, LOG_ERR,
15740fbf3537Syasuoka 			    "npppd_ppp_pipex_ip_disable() failed: %m");
15750fbf3537Syasuoka #endif /* USE_NPPPD_PIPEX */
15760fbf3537Syasuoka 	}
15770fbf3537Syasuoka }
15780fbf3537Syasuoka 
15790fbf3537Syasuoka /**
1580f0a4e295Syasuoka  * Assign the IP address.  Returning "struct in_addr" is stored IP address
1581f0a4e295Syasuoka  * in network byte order.
1582f0a4e295Syasuoka  * @param req_ip4	IP address request to assign.  If the address is used
1583f0a4e295Syasuoka  * already, this function will return fail.
15840fbf3537Syasuoka  */
15850fbf3537Syasuoka int
15860fbf3537Syasuoka npppd_assign_ip_addr(npppd *_this, npppd_ppp *ppp, uint32_t req_ip4)
15870fbf3537Syasuoka {
15880fbf3537Syasuoka 	uint32_t ip4, ip4mask;
1589821f7c56Syasuoka 	int dyna, rval, fallback_dyna;
15900fbf3537Syasuoka 	const char *reason = "out of the pool";
15910fbf3537Syasuoka 	struct sockaddr_npppd *snp;
15920fbf3537Syasuoka 	npppd_pool *pool;
15930fbf3537Syasuoka 	npppd_auth_base *realm;
15940fbf3537Syasuoka 
15950fbf3537Syasuoka 	NPPPD_DBG((LOG_DEBUG, "%s() assigned=%s", __func__,
15960fbf3537Syasuoka 	    (ppp_ip_assigned(ppp))? "true" : "false"));
15970fbf3537Syasuoka 	if (ppp_ip_assigned(ppp))
15980fbf3537Syasuoka 		return 0;
15990fbf3537Syasuoka 
16000fbf3537Syasuoka 	ip4 = INADDR_ANY;
16010fbf3537Syasuoka 	ip4mask = 0xffffffffL;
16020fbf3537Syasuoka 	realm = ppp->realm;
16030fbf3537Syasuoka 	dyna = 0;
16040fbf3537Syasuoka 	fallback_dyna = 0;
16050fbf3537Syasuoka 	pool = NULL;
16060fbf3537Syasuoka 
16070fbf3537Syasuoka 	if (ppp->realm_framed_ip_address.s_addr == INADDR_USER_SELECT) {
16080fbf3537Syasuoka 		if (req_ip4 == INADDR_ANY)
16090fbf3537Syasuoka 			dyna = 1;
16100fbf3537Syasuoka 	} else if (ppp->realm_framed_ip_address.s_addr == INADDR_NAS_SELECT) {
16110fbf3537Syasuoka 		dyna = 1;
16120fbf3537Syasuoka 	} else {
16130fbf3537Syasuoka 		NPPPD_ASSERT(realm != NULL);
16140fbf3537Syasuoka 		fallback_dyna = 1;
16150fbf3537Syasuoka 		req_ip4 = ntohl(ppp->realm_framed_ip_address.s_addr);
16160fbf3537Syasuoka 		ip4mask = ntohl(ppp->realm_framed_ip_netmask.s_addr);
16170fbf3537Syasuoka 	}
16180fbf3537Syasuoka 	if (!dyna) {
16190fbf3537Syasuoka 		/*
1620f0a4e295Syasuoka 		 * Realm requires the fixed IP address, but the address
1621f0a4e295Syasuoka 		 * doesn't belong any address pool.  Fallback to dynamic
1622f0a4e295Syasuoka 		 * assignment.
16230fbf3537Syasuoka 		 */
1624821f7c56Syasuoka 		pool = ppp_pool(ppp);
1625821f7c56Syasuoka 		rval = npppd_pool_get_assignability(pool, req_ip4, ip4mask,
1626821f7c56Syasuoka 		    &snp);
16270fbf3537Syasuoka 		switch (rval) {
16280fbf3537Syasuoka 		case ADDRESS_OK:
16290fbf3537Syasuoka 			if (snp->snp_type == SNP_POOL) {
16300fbf3537Syasuoka 				/*
1631821f7c56Syasuoka 				 * Fixed address pool can be used only if the
1632821f7c56Syasuoka 				 * realm specified to use it.
16330fbf3537Syasuoka 				 */
16340fbf3537Syasuoka 				if (ppp->realm_framed_ip_address
16350fbf3537Syasuoka 				    .s_addr != INADDR_USER_SELECT)
16360fbf3537Syasuoka 					ip4 = req_ip4;
16370fbf3537Syasuoka 				break;
16380fbf3537Syasuoka 			}
16390fbf3537Syasuoka 			ppp->assign_dynapool = 1;
16400fbf3537Syasuoka 			ip4 = req_ip4;
16410fbf3537Syasuoka 			break;
16420fbf3537Syasuoka 		case ADDRESS_RESERVED:
16430fbf3537Syasuoka 			reason = "reserved";
1644821f7c56Syasuoka 			break;
16450fbf3537Syasuoka 		case ADDRESS_OUT_OF_POOL:
16460fbf3537Syasuoka 			reason = "out of the pool";
1647821f7c56Syasuoka 			break;
16480fbf3537Syasuoka 		case ADDRESS_BUSY:
16490fbf3537Syasuoka 			fallback_dyna = 0;
16500fbf3537Syasuoka 			reason = "busy";
16510fbf3537Syasuoka 			break;
16520fbf3537Syasuoka 		default:
16530fbf3537Syasuoka 		case ADDRESS_INVALID:
16540fbf3537Syasuoka 			fallback_dyna = 0;
16550fbf3537Syasuoka 			reason = "invalid";
16560fbf3537Syasuoka 			break;
16570fbf3537Syasuoka 		}
16580fbf3537Syasuoka #define	IP_4OCT(v) ((0xff000000 & (v)) >> 24), ((0x00ff0000 & (v)) >> 16),\
16590fbf3537Syasuoka 	    ((0x0000ff00 & (v)) >> 8), (0x000000ff & (v))
16600fbf3537Syasuoka 		if (ip4 == 0) {
16610fbf3537Syasuoka 			ppp_log(ppp, LOG_NOTICE,
16620fbf3537Syasuoka 			    "Requested IP address (%d.%d.%d.%d)/%d "
16630fbf3537Syasuoka 			    "is %s", IP_4OCT(req_ip4),
1664*baaa6b9aSyasuoka 			    netmask2prefixlen(ip4mask), reason);
16650fbf3537Syasuoka 			if (fallback_dyna)
16660fbf3537Syasuoka 				goto dyna_assign;
16670fbf3537Syasuoka 			return 1;
16680fbf3537Syasuoka 		}
166932012184Syasuoka 		ppp->assigned_pool = pool;
16700fbf3537Syasuoka 
16710fbf3537Syasuoka 		ppp->ppp_framed_ip_address.s_addr = htonl(ip4);
16720fbf3537Syasuoka 		ppp->ppp_framed_ip_netmask.s_addr = htonl(ip4mask);
1673b0b96f97Syasuoka 		ppp->acct_framed_ip_address = ppp->ppp_framed_ip_address;
16740fbf3537Syasuoka 	} else {
16750fbf3537Syasuoka dyna_assign:
1676821f7c56Syasuoka 		pool = ppp_pool(ppp);
16770fbf3537Syasuoka 		ip4 = npppd_pool_get_dynamic(pool, ppp);
16780fbf3537Syasuoka 		if (ip4 == 0) {
16790fbf3537Syasuoka 			ppp_log(ppp, LOG_NOTICE,
16800fbf3537Syasuoka 			    "No free address in the pool.");
16810fbf3537Syasuoka 			return 1;
16820fbf3537Syasuoka 		}
16830fbf3537Syasuoka 		ppp->assigned_pool = pool;
16840fbf3537Syasuoka 		ppp->assign_dynapool = 1;
16850fbf3537Syasuoka 		ppp->ppp_framed_ip_address.s_addr = htonl(ip4);
16860fbf3537Syasuoka 		ppp->ppp_framed_ip_netmask.s_addr = htonl(0xffffffffL);
1687b0b96f97Syasuoka 		ppp->acct_framed_ip_address = ppp->ppp_framed_ip_address;
16880fbf3537Syasuoka 	}
16890fbf3537Syasuoka 
16900fbf3537Syasuoka 	return npppd_pool_assign_ip(ppp->assigned_pool, ppp);
16910fbf3537Syasuoka }
16920fbf3537Syasuoka 
16930fbf3537Syasuoka static void *
16940fbf3537Syasuoka rtlist_remove(slist *prtlist, struct radish *radish)
16950fbf3537Syasuoka {
16960fbf3537Syasuoka 	struct radish *r;
16970fbf3537Syasuoka 
16980fbf3537Syasuoka 	slist_itr_first(prtlist);
16990fbf3537Syasuoka 	while (slist_itr_has_next(prtlist)) {
17000fbf3537Syasuoka 		r = slist_itr_next(prtlist);
17010fbf3537Syasuoka 		if (!sockaddr_npppd_match(radish->rd_route, r->rd_route) ||
17020fbf3537Syasuoka 		    !sockaddr_npppd_match(radish->rd_mask, r->rd_mask))
17030fbf3537Syasuoka 			continue;
17040fbf3537Syasuoka 
17050fbf3537Syasuoka 		return slist_itr_remove(prtlist);
17060fbf3537Syasuoka 	}
17070fbf3537Syasuoka 
17080fbf3537Syasuoka 	return NULL;
17090fbf3537Syasuoka }
17100fbf3537Syasuoka 
1711f0a4e295Syasuoka /** Set {@link ::npppd#rd the only radish of npppd} */
17120fbf3537Syasuoka int
17130fbf3537Syasuoka npppd_set_radish(npppd *_this, void *radish_head)
17140fbf3537Syasuoka {
17150fbf3537Syasuoka 	int rval, delppp0, count;
17160fbf3537Syasuoka 	struct sockaddr_npppd *snp;
17170fbf3537Syasuoka 	struct radish *radish, *r;
17180fbf3537Syasuoka 	slist rtlist0, rtlist1, delppp;
17190fbf3537Syasuoka 	npppd_ppp *ppp;
17200fbf3537Syasuoka 	void *dummy;
17210fbf3537Syasuoka 
17220fbf3537Syasuoka 	slist_init(&rtlist0);
17230fbf3537Syasuoka 	slist_init(&rtlist1);
17240fbf3537Syasuoka 	slist_init(&delppp);
17250fbf3537Syasuoka 
17260fbf3537Syasuoka 	if (radish_head != NULL) {
17270fbf3537Syasuoka 		if (rd2slist(radish_head, &rtlist1) != 0) {
17280fbf3537Syasuoka 			log_printf(LOG_WARNING, "rd2slist failed: %m");
1729f0a4e295Syasuoka 			goto fail;
17300fbf3537Syasuoka 		}
17310fbf3537Syasuoka 	}
17320fbf3537Syasuoka 	if (_this->rd != NULL) {
17330fbf3537Syasuoka 		if (rd2slist(_this->rd, &rtlist0) != 0) {
17340fbf3537Syasuoka 			log_printf(LOG_WARNING, "rd2slist failed: %m");
1735f0a4e295Syasuoka 			goto fail;
17360fbf3537Syasuoka 		}
17370fbf3537Syasuoka 	}
17380fbf3537Syasuoka 	if (_this->rd != NULL && radish_head != NULL) {
17390fbf3537Syasuoka 		for (slist_itr_first(&rtlist0); slist_itr_has_next(&rtlist0);) {
17400fbf3537Syasuoka 			radish = slist_itr_next(&rtlist0);
17410fbf3537Syasuoka 			snp = radish->rd_rtent;
17420fbf3537Syasuoka 		    /*
1743f0a4e295Syasuoka 		     * replace the pool address
17440fbf3537Syasuoka 		     */
17450fbf3537Syasuoka 			if (snp->snp_type == SNP_POOL ||
17460fbf3537Syasuoka 			    snp->snp_type == SNP_DYN_POOL) {
17470fbf3537Syasuoka 				if (rd_lookup(radish->rd_route, radish->rd_mask,
17480fbf3537Syasuoka 					    radish_head) == NULL)
17490fbf3537Syasuoka 					continue;
1750f0a4e295Syasuoka 				/* don't add */
17510fbf3537Syasuoka 				rtlist_remove(&rtlist1, radish);
1752f0a4e295Syasuoka 				/* don't delete */
17530fbf3537Syasuoka 				slist_itr_remove(&rtlist0);
17540fbf3537Syasuoka 				continue;
17550fbf3537Syasuoka 			}
17560fbf3537Syasuoka 		    /*
1757f0a4e295Syasuoka 		     * handle the active PPP sessions.
17580fbf3537Syasuoka 		     */
17590fbf3537Syasuoka 			NPPPD_ASSERT(snp->snp_type == SNP_PPP);
17600fbf3537Syasuoka 			ppp =  snp->snp_data_ptr;
17610fbf3537Syasuoka 
1762f0a4e295Syasuoka 			/* Don't delete the route of active PPP session */
17630fbf3537Syasuoka 			slist_itr_remove(&rtlist0);
17640fbf3537Syasuoka 
1765f0a4e295Syasuoka 			/* clear informations about old pool configuration */
17660fbf3537Syasuoka 			snp->snp_next = NULL;
17670fbf3537Syasuoka 
17680fbf3537Syasuoka 			delppp0 = 0;
17690fbf3537Syasuoka 			if (!rd_match((struct sockaddr *)snp, radish_head, &r)){
17700fbf3537Syasuoka 				/*
1771f0a4e295Syasuoka 				 * If the address doesn't belong the new pools,
1772f0a4e295Syasuoka 				 * add the PPP session to the deletion list.
17730fbf3537Syasuoka 				 */
17740fbf3537Syasuoka 				slist_add(&delppp, snp->snp_data_ptr);
17750fbf3537Syasuoka 				delppp0 = 1;
17760fbf3537Syasuoka 			} else {
17770fbf3537Syasuoka 				NPPPD_ASSERT(
17780fbf3537Syasuoka 				    ((struct sockaddr_npppd *)r->rd_rtent)
17790fbf3537Syasuoka 					->snp_type == SNP_POOL ||
17800fbf3537Syasuoka 				    ((struct sockaddr_npppd *)r->rd_rtent)
17810fbf3537Syasuoka 					->snp_type == SNP_DYN_POOL);
17820fbf3537Syasuoka 				/*
1783f0a4e295Syasuoka 				 * If there is a pool entry that has same
1784f0a4e295Syasuoka 				 * address/mask, then make the RADISH entry a
1785f0a4e295Syasuoka 				 * list.  Set SNP_PPP as the first in the list,
1786f0a4e295Syasuoka 				 * set current entry in snp->snp_next and
1787f0a4e295Syasuoka 				 * delete it.
17880fbf3537Syasuoka 				 */
17890fbf3537Syasuoka 				if (sockaddr_npppd_match(
17900fbf3537Syasuoka 					    radish->rd_route, r->rd_route) &&
17910fbf3537Syasuoka 				    sockaddr_npppd_match(
17920fbf3537Syasuoka 					    radish->rd_mask, r->rd_mask)) {
1793f0a4e295Syasuoka 					/*
1794f0a4e295Syasuoka 					 * Releasing it, so remove it from the
1795f0a4e295Syasuoka 					 * new routing list.
1796f0a4e295Syasuoka 					 */
17970fbf3537Syasuoka 					rtlist_remove(&rtlist1, radish);
1798f0a4e295Syasuoka 					/* set as snp_snp_next */
17990fbf3537Syasuoka 					snp->snp_next = r->rd_rtent;
18000fbf3537Syasuoka 					rval = rd_delete(r->rd_route,
18010fbf3537Syasuoka 					    r->rd_mask, radish_head, &dummy);
18020fbf3537Syasuoka 					NPPPD_ASSERT(rval == 0);
18030fbf3537Syasuoka 				}
18040fbf3537Syasuoka 			}
1805f0a4e295Syasuoka 			/* Register to the new radish */
18060fbf3537Syasuoka 			rval = rd_insert(radish->rd_route, radish->rd_mask,
18070fbf3537Syasuoka 			    radish_head, snp);
18080fbf3537Syasuoka 			if (rval != 0) {
18090fbf3537Syasuoka 				errno = rval;
18100fbf3537Syasuoka 				ppp_log(((npppd_ppp *)snp->snp_data_ptr),
18110fbf3537Syasuoka 				    LOG_ERR,
18120fbf3537Syasuoka 				    "Fatal error on %s, cannot continue "
18130fbf3537Syasuoka 				    "this ppp session: %m", __func__);
18140fbf3537Syasuoka 				if (!delppp0)
18150fbf3537Syasuoka 					slist_add(&delppp, snp->snp_data_ptr);
18160fbf3537Syasuoka 			}
18170fbf3537Syasuoka 		}
18180fbf3537Syasuoka 	}
18190fbf3537Syasuoka 	count = 0;
18200fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
1821cd8e09b9Sdlg 	if (_this->iface[0].using_pppx == 0) {
18220fbf3537Syasuoka 		for (slist_itr_first(&rtlist0); slist_itr_has_next(&rtlist0);) {
18230fbf3537Syasuoka 			radish = slist_itr_next(&rtlist0);
18240fbf3537Syasuoka 			in_route_delete(&SIN(radish->rd_route)->sin_addr,
1825cd8e09b9Sdlg 			    &SIN(radish->rd_mask)->sin_addr, &loop,
1826cd8e09b9Sdlg 			    RTF_BLACKHOLE);
18270fbf3537Syasuoka 			count++;
18280fbf3537Syasuoka 		}
18290fbf3537Syasuoka 		if (count > 0)
18300fbf3537Syasuoka 			log_printf(LOG_INFO,
18310fbf3537Syasuoka 			    "Deleted %d routes for old pool addresses", count);
18320fbf3537Syasuoka 
18330fbf3537Syasuoka 		count = 0;
18340fbf3537Syasuoka 		for (slist_itr_first(&rtlist1); slist_itr_has_next(&rtlist1);) {
18350fbf3537Syasuoka 			radish = slist_itr_next(&rtlist1);
18360fbf3537Syasuoka 			in_route_add(&(SIN(radish->rd_route)->sin_addr),
1837cd8e09b9Sdlg 			    &SIN(radish->rd_mask)->sin_addr, &loop,
1838cd8e09b9Sdlg 			    LOOPBACK_IFNAME, RTF_BLACKHOLE, 0);
18390fbf3537Syasuoka 			count++;
18400fbf3537Syasuoka 		}
18410fbf3537Syasuoka 		if (count > 0)
18420fbf3537Syasuoka 			log_printf(LOG_INFO,
1843cd8e09b9Sdlg 				    "Added %d routes for new pool addresses",
1844cd8e09b9Sdlg 				    count);
1845cd8e09b9Sdlg 	}
18460fbf3537Syasuoka #endif
18470fbf3537Syasuoka 	slist_fini(&rtlist0);
18480fbf3537Syasuoka 	slist_fini(&rtlist1);
18490fbf3537Syasuoka 
1850230b2897Syasuoka 	if (_this->rd != NULL) {
18510fbf3537Syasuoka 		npppd_rd_walktree_delete(_this->rd);
1852230b2897Syasuoka 		_this->rd = NULL;
1853230b2897Syasuoka 	}
185484c9ec02Syasuoka 	if (radish_head == NULL)
185584c9ec02Syasuoka 		npppd_get_all_users(_this, &delppp);
18563089d6fcSyasuoka 	_this->rd = radish_head;
18570fbf3537Syasuoka 
18580fbf3537Syasuoka 	for (slist_itr_first(&delppp); slist_itr_has_next(&delppp);) {
18590fbf3537Syasuoka 		ppp = slist_itr_next(&delppp);
18600fbf3537Syasuoka                 ppp_log(ppp, LOG_NOTICE,
18610fbf3537Syasuoka                     "stop.  IP address of this ppp is out of the pool.: %s",
18620fbf3537Syasuoka                     inet_ntoa(ppp->ppp_framed_ip_address));
18630fbf3537Syasuoka 		ppp_stop(ppp, NULL);
18640fbf3537Syasuoka 	}
18650fbf3537Syasuoka 	slist_fini(&delppp);
18660fbf3537Syasuoka 
18670fbf3537Syasuoka 	return 0;
1868f0a4e295Syasuoka fail:
18690fbf3537Syasuoka 	slist_fini(&rtlist0);
18700fbf3537Syasuoka 	slist_fini(&rtlist1);
18710fbf3537Syasuoka 	slist_fini(&delppp);
18720fbf3537Syasuoka 
18730fbf3537Syasuoka 	return 1;
18740fbf3537Syasuoka }
18750fbf3537Syasuoka 
18760fbf3537Syasuoka /**
1877f0a4e295Syasuoka  * This function stores all users to {@link slist} and returns them.
1878f0a4e295Syasuoka  * References to {@link ::npppd_ppp} will be stored in users.
18790fbf3537Syasuoka  */
188034682664Syasuoka static int
18810fbf3537Syasuoka npppd_get_all_users(npppd *_this, slist *users)
18820fbf3537Syasuoka {
18830fbf3537Syasuoka 	int rval;
18840fbf3537Syasuoka 	struct radish *rd;
18850fbf3537Syasuoka 	struct sockaddr_npppd *snp;
18860fbf3537Syasuoka 	slist list;
18870fbf3537Syasuoka 
18880fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
18890fbf3537Syasuoka 
18900fbf3537Syasuoka 	slist_init(&list);
189184c9ec02Syasuoka 	if (_this->rd == NULL)
189284c9ec02Syasuoka 		return 0;
18930fbf3537Syasuoka 	rval = rd2slist(_this->rd, &list);
18940fbf3537Syasuoka 	if (rval != 0)
18950fbf3537Syasuoka 		return rval;
18960fbf3537Syasuoka 
18970fbf3537Syasuoka 	for (slist_itr_first(&list); slist_itr_has_next(&list);) {
18980fbf3537Syasuoka 		rd = slist_itr_next(&list);
18990fbf3537Syasuoka 		snp = rd->rd_rtent;
19000fbf3537Syasuoka 		if (snp->snp_type == SNP_PPP) {
19010fbf3537Syasuoka 			if (slist_add(users, snp->snp_data_ptr) == NULL) {
19020fbf3537Syasuoka 				log_printf(LOG_ERR,
19030fbf3537Syasuoka 				    "slist_add() failed in %s: %m", __func__);
1904f0a4e295Syasuoka 				goto fail;
19050fbf3537Syasuoka 			}
19060fbf3537Syasuoka 		}
19070fbf3537Syasuoka 	}
19080fbf3537Syasuoka 	slist_fini(&list);
19090fbf3537Syasuoka 
19100fbf3537Syasuoka 	return 0;
1911f0a4e295Syasuoka fail:
19120fbf3537Syasuoka 	slist_fini(&list);
19130fbf3537Syasuoka 
19140fbf3537Syasuoka 	return 1;
19150fbf3537Syasuoka }
19160fbf3537Syasuoka 
19170fbf3537Syasuoka static int
19180fbf3537Syasuoka rd2slist_walk(struct radish *rd, void *list0)
19190fbf3537Syasuoka {
19200fbf3537Syasuoka 	slist *list = list0;
19210fbf3537Syasuoka 	void *r;
19220fbf3537Syasuoka 
19230fbf3537Syasuoka 	r = slist_add(list, rd);
19240fbf3537Syasuoka 	if (r == NULL)
19250fbf3537Syasuoka 		return -1;
19260fbf3537Syasuoka 	return 0;
19270fbf3537Syasuoka }
19280fbf3537Syasuoka static int
19290fbf3537Syasuoka rd2slist(struct radish_head *h, slist *list)
19300fbf3537Syasuoka {
19310fbf3537Syasuoka 	return rd_walktree(h, rd2slist_walk, list);
19320fbf3537Syasuoka }
19330fbf3537Syasuoka 
19340fbf3537Syasuoka static void
19350fbf3537Syasuoka npppd_reload0(npppd *_this)
19360fbf3537Syasuoka {
1937821f7c56Syasuoka 	int  i;
1938821f7c56Syasuoka 
19390fbf3537Syasuoka 	npppd_reload_config(_this);
19400fbf3537Syasuoka #ifdef USE_NPPPD_ARP
19410fbf3537Syasuoka 	arp_set_strictintfnetwork(npppd_config_str_equali(_this, "arpd.strictintfnetwork", "true", ARPD_STRICTINTFNETWORK_DEFAULT));
19420fbf3537Syasuoka 	if (npppd_config_str_equali(_this, "arpd.enabled", "true", ARPD_DEFAULT) == 1)
19430fbf3537Syasuoka         	arp_sock_init();
19440fbf3537Syasuoka 	else
19450fbf3537Syasuoka 		arp_sock_fini();
19460fbf3537Syasuoka #endif
19470fbf3537Syasuoka 	npppd_modules_reload(_this);
19480fbf3537Syasuoka 	npppd_ifaces_load_config(_this);
1949821f7c56Syasuoka 	npppd_update_pool_reference(_this);
19500fbf3537Syasuoka 	npppd_auth_finalizer_periodic(_this);
19512a5607d2Sgoda 	npppd_ipcp_stats_reload(_this);
1952821f7c56Syasuoka 
1953821f7c56Syasuoka 	for (i = 0; i < countof(_this->iface); i++) {
1954821f7c56Syasuoka 		if (_this->iface[i].initialized != 0 &&
1955821f7c56Syasuoka 		    _this->iface[i].started == 0)
1956821f7c56Syasuoka 			npppd_iface_start(&_this->iface[i]);
1957821f7c56Syasuoka 	}
1958821f7c56Syasuoka }
1959821f7c56Syasuoka 
1960821f7c56Syasuoka static void
1961821f7c56Syasuoka npppd_update_pool_reference(npppd *_this)
1962821f7c56Syasuoka {
1963821f7c56Syasuoka 	int  i, j;
1964821f7c56Syasuoka 	/* update iface to pool reference */
1965821f7c56Syasuoka 	for (i = 0; i < countof(_this->iface_pool); i++) {
1966821f7c56Syasuoka 		_this->iface_pool[i] = NULL;
1967821f7c56Syasuoka 		if (_this->iface[i].initialized == 0)
1968821f7c56Syasuoka 			continue;
1969821f7c56Syasuoka 		if (_this->iface[i].ipcpconf == NULL)
1970821f7c56Syasuoka 			continue;	/* no IPCP for this interface */
1971821f7c56Syasuoka 
1972821f7c56Syasuoka 		for (j = 0; j < countof(_this->pool); j++) {
1973821f7c56Syasuoka 			if (_this->pool[j].initialized == 0)
1974821f7c56Syasuoka 				continue;
1975821f7c56Syasuoka 			if (strcmp(_this->iface[i].ipcpconf->name,
1976821f7c56Syasuoka 			    _this->pool[j].ipcp_name) == 0) {
1977821f7c56Syasuoka 				/* found the ipcp that has the pool */
1978821f7c56Syasuoka 				_this->iface_pool[i] = &_this->pool[j];
1979821f7c56Syasuoka 				break;
1980821f7c56Syasuoka 			}
1981821f7c56Syasuoka 		}
1982821f7c56Syasuoka 	}
19830fbf3537Syasuoka }
19840fbf3537Syasuoka 
19850fbf3537Syasuoka /***********************************************************************
1986f0a4e295Syasuoka  * Signal handlers
19870fbf3537Syasuoka  ***********************************************************************/
19880fbf3537Syasuoka static void
19890fbf3537Syasuoka npppd_on_sighup(int fd, short ev_type, void *ctx)
19900fbf3537Syasuoka {
19910fbf3537Syasuoka 	npppd *_this;
19920fbf3537Syasuoka 
19930fbf3537Syasuoka 	_this = ctx;
19940fbf3537Syasuoka #ifndef	NO_DELAYED_RELOAD
19950fbf3537Syasuoka 	if (_this->delayed_reload > 0)
19960fbf3537Syasuoka 		_this->reloading_count = _this->delayed_reload;
19970fbf3537Syasuoka 	else
19980fbf3537Syasuoka #endif
19990fbf3537Syasuoka 		npppd_reload0(_this);
20000fbf3537Syasuoka }
20010fbf3537Syasuoka 
20020fbf3537Syasuoka static void
20030fbf3537Syasuoka npppd_on_sigterm(int fd, short ev_type, void *ctx)
20040fbf3537Syasuoka {
20050fbf3537Syasuoka 	npppd *_this;
20060fbf3537Syasuoka 
20070fbf3537Syasuoka 	_this = ctx;
20080fbf3537Syasuoka 	npppd_stop(_this);
20090fbf3537Syasuoka }
20100fbf3537Syasuoka 
20110fbf3537Syasuoka static void
20120fbf3537Syasuoka npppd_on_sigint(int fd, short ev_type, void *ctx)
20130fbf3537Syasuoka {
20140fbf3537Syasuoka 	npppd *_this;
20150fbf3537Syasuoka 
20160fbf3537Syasuoka 	_this = ctx;
20170fbf3537Syasuoka 	npppd_stop(_this);
20180fbf3537Syasuoka }
20190fbf3537Syasuoka 
20205fefcc09Syasuoka static void
20215fefcc09Syasuoka npppd_on_sigchld(int fd, short ev_type, void *ctx)
20225fefcc09Syasuoka {
20235fefcc09Syasuoka 	int status;
20245fefcc09Syasuoka 	pid_t wpid;
20255fefcc09Syasuoka 	npppd *_this;
20265fefcc09Syasuoka 
20275fefcc09Syasuoka 	_this = ctx;
20285fefcc09Syasuoka 	wpid = privsep_priv_pid();
20295fefcc09Syasuoka 	if (wait4(wpid, &status, WNOHANG, NULL) == wpid) {
20305fefcc09Syasuoka 		if (WIFSIGNALED(status))
20315fefcc09Syasuoka 			log_printf(LOG_WARNING,
20329a200ddfSyasuoka 			    "privileged process exits abnormaly.  signal=%d",
20335fefcc09Syasuoka 			    WTERMSIG(status));
20345fefcc09Syasuoka 		else
20355fefcc09Syasuoka 			log_printf(LOG_WARNING,
20369a200ddfSyasuoka 			    "privileged process exits abnormaly.  status=%d",
20375fefcc09Syasuoka 			    WEXITSTATUS(status));
20385fefcc09Syasuoka 		_this->stop_by_error = 1;
20395fefcc09Syasuoka 		npppd_stop(_this);
20405fefcc09Syasuoka 	}
20415fefcc09Syasuoka }
20420fbf3537Syasuoka /***********************************************************************
2043f0a4e295Syasuoka  * Miscellaneous functions
20440fbf3537Syasuoka  ***********************************************************************/
20450fbf3537Syasuoka static uint32_t
20460fbf3537Syasuoka str_hash(const void *ptr, int sz)
20470fbf3537Syasuoka {
20480fbf3537Syasuoka 	uint32_t hash = 0;
20490fbf3537Syasuoka 	int i, len;
20500fbf3537Syasuoka 	const char *str;
20510fbf3537Syasuoka 
20520fbf3537Syasuoka 	str = ptr;
20530fbf3537Syasuoka 	len = strlen(str);
20540fbf3537Syasuoka 	for (i = 0; i < len; i++)
20550fbf3537Syasuoka 		hash = hash*0x1F + str[i];
20560fbf3537Syasuoka 	hash = (hash << 16) ^ (hash & 0xffff);
20570fbf3537Syasuoka 
20580fbf3537Syasuoka 	return hash % sz;
20590fbf3537Syasuoka }
20600fbf3537Syasuoka 
20610fbf3537Syasuoka /**
2062f0a4e295Syasuoka  * Select a authentication realm that is for given {@link ::npppd_ppp PPP}.
2063f0a4e295Syasuoka  * Return 0 on success.
20640fbf3537Syasuoka  */
20650fbf3537Syasuoka int
20660fbf3537Syasuoka npppd_ppp_bind_realm(npppd *_this, npppd_ppp *ppp, const char *username, int
20670fbf3537Syasuoka     eap_required)
20680fbf3537Syasuoka {
2069821f7c56Syasuoka 	struct confbind *bind;
20700fbf3537Syasuoka 	npppd_auth_base *realm = NULL, *realm0 = NULL, *realm1 = NULL;
2071821f7c56Syasuoka 	char             buf1[MAX_USERNAME_LENGTH];
207234379bfeSyasuoka 	int              lsuffix, lusername, lmax;
20730fbf3537Syasuoka 
20740fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
20750fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
20760fbf3537Syasuoka 	NPPPD_ASSERT(username != NULL);
20770fbf3537Syasuoka 
20780fbf3537Syasuoka 	/*
2079f0a4e295Syasuoka 	 * If the PPP suffix is the longest, and the length of the suffix is
2080f0a4e295Syasuoka 	 * same, select the first one.
20810fbf3537Syasuoka 	 */
20820fbf3537Syasuoka 	lusername = strlen(username);
20830fbf3537Syasuoka 	lmax = -1;
20840fbf3537Syasuoka 	realm = NULL;
20850fbf3537Syasuoka 
2086821f7c56Syasuoka 	TAILQ_FOREACH(bind, &_this->conf.confbinds, entry) {
2087821f7c56Syasuoka 		if (strcmp(bind->tunnconf->name, ppp->phy_label) != 0)
20880fbf3537Syasuoka 			continue;
20890fbf3537Syasuoka 
20900fbf3537Syasuoka 		realm0 = NULL;
20910fbf3537Syasuoka 		slist_itr_first(&_this->realms);
20920fbf3537Syasuoka 		while (slist_itr_has_next(&_this->realms)) {
20930fbf3537Syasuoka 			realm1 = slist_itr_next(&_this->realms);
20940fbf3537Syasuoka 			if (!npppd_auth_is_usable(realm1))
20950fbf3537Syasuoka 				continue;
2096821f7c56Syasuoka 			if (eap_required && !npppd_auth_is_eap_capable(realm1))
20970fbf3537Syasuoka 				continue;
2098821f7c56Syasuoka 			if (strcmp(npppd_auth_get_name(realm1),
2099821f7c56Syasuoka 			    bind->authconf->name) == 0) {
21000fbf3537Syasuoka 				realm0 = realm1;
21010fbf3537Syasuoka 				break;
21020fbf3537Syasuoka 			}
21030fbf3537Syasuoka 		}
21040fbf3537Syasuoka 		if (realm0 == NULL)
21050fbf3537Syasuoka 			continue;
2106821f7c56Syasuoka 
21070fbf3537Syasuoka 		lsuffix = strlen(npppd_auth_get_suffix(realm0));
21080fbf3537Syasuoka 		if (lsuffix > lmax &&
2109821f7c56Syasuoka 		    (lsuffix == 0 ||
2110821f7c56Syasuoka 			(lsuffix < lusername && strcmp(username + lusername
2111821f7c56Syasuoka 				- lsuffix, npppd_auth_get_suffix(realm0))
2112821f7c56Syasuoka 				== 0))) {
21130fbf3537Syasuoka 			lmax = lsuffix;
21140fbf3537Syasuoka 			realm = realm0;
21150fbf3537Syasuoka 		}
21160fbf3537Syasuoka 	}
2117821f7c56Syasuoka 
21180fbf3537Syasuoka 	if (realm == NULL) {
21190fbf3537Syasuoka 		log_printf(LOG_INFO, "user='%s' could not bind any realms",
21200fbf3537Syasuoka 		    username);
21210fbf3537Syasuoka 		return 1;
21220fbf3537Syasuoka 	}
2123821f7c56Syasuoka 	NPPPD_DBG((LOG_DEBUG, "bind realm %s", npppd_auth_get_name(realm)));
21240fbf3537Syasuoka 
21250fbf3537Syasuoka 	if (npppd_auth_get_type(realm) == NPPPD_AUTH_TYPE_LOCAL)
21260fbf3537Syasuoka 		/* hook the auto reload */
21270fbf3537Syasuoka 		npppd_auth_get_user_password(realm,
21280fbf3537Syasuoka 		    npppd_auth_username_for_auth(realm1, username, buf1), NULL,
21290fbf3537Syasuoka 			NULL);
21300fbf3537Syasuoka 	ppp->realm = realm;
21310fbf3537Syasuoka 
21320fbf3537Syasuoka 	return 0;
21330fbf3537Syasuoka }
21340fbf3537Syasuoka 
2135f0a4e295Syasuoka /** Is assigned realm a LOCAL authentication? */
21360fbf3537Syasuoka int
21370fbf3537Syasuoka npppd_ppp_is_realm_local(npppd *_this, npppd_ppp *ppp)
21380fbf3537Syasuoka {
21390fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
21400fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
21410fbf3537Syasuoka 
21420fbf3537Syasuoka 	if (ppp->realm == NULL)
21430fbf3537Syasuoka 		return 0;
21440fbf3537Syasuoka 
21450fbf3537Syasuoka 	return (npppd_auth_get_type(ppp->realm) == NPPPD_AUTH_TYPE_LOCAL)
21460fbf3537Syasuoka 	    ? 1 : 0;
21470fbf3537Syasuoka }
21480fbf3537Syasuoka 
2149f0a4e295Syasuoka /** Is assigned realm a RADIUS authentication? */
21500fbf3537Syasuoka int
21510fbf3537Syasuoka npppd_ppp_is_realm_radius(npppd *_this, npppd_ppp *ppp)
21520fbf3537Syasuoka {
21530fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
21540fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
21550fbf3537Syasuoka 
21560fbf3537Syasuoka 	if (ppp->realm == NULL)
21570fbf3537Syasuoka 		return 0;
21580fbf3537Syasuoka 
21590fbf3537Syasuoka 	return (npppd_auth_get_type(ppp->realm) == NPPPD_AUTH_TYPE_RADIUS)
21600fbf3537Syasuoka 	    ? 1 : 0;
21610fbf3537Syasuoka }
21620fbf3537Syasuoka 
2163f0a4e295Syasuoka /** Is assigned realm usable? */
21640fbf3537Syasuoka int
21650fbf3537Syasuoka npppd_ppp_is_realm_ready(npppd *_this, npppd_ppp *ppp)
21660fbf3537Syasuoka {
21670fbf3537Syasuoka 	if (ppp->realm == NULL)
21680fbf3537Syasuoka 		return 0;
21690fbf3537Syasuoka 
21700fbf3537Syasuoka 	return npppd_auth_is_ready(ppp->realm);
21710fbf3537Syasuoka }
21720fbf3537Syasuoka 
2173f0a4e295Syasuoka /** Return the name of assigned realm */
21740fbf3537Syasuoka const char *
21750fbf3537Syasuoka npppd_ppp_get_realm_name(npppd *_this, npppd_ppp *ppp)
21760fbf3537Syasuoka {
21770fbf3537Syasuoka 	if (ppp->realm == NULL)
21780fbf3537Syasuoka 		return "(none)";
21790fbf3537Syasuoka 	return npppd_auth_get_name(ppp->realm);
21800fbf3537Syasuoka }
21810fbf3537Syasuoka 
2182f0a4e295Syasuoka /** Return the interface name that bound given {@link ::npppd_ppp PPP} */
21830fbf3537Syasuoka const char *
21840fbf3537Syasuoka npppd_ppp_get_iface_name(npppd *_this, npppd_ppp *ppp)
21850fbf3537Syasuoka {
21860fbf3537Syasuoka 	if (ppp == NULL || ppp->ifidx < 0)
21870fbf3537Syasuoka 		return "(not binding)";
21880fbf3537Syasuoka 	return ppp_iface(ppp)->ifname;
21890fbf3537Syasuoka }
21900fbf3537Syasuoka 
2191f0a4e295Syasuoka /** Is the interface usable? */
21920fbf3537Syasuoka int
21930fbf3537Syasuoka npppd_ppp_iface_is_ready(npppd *_this, npppd_ppp *ppp)
21940fbf3537Syasuoka {
21950fbf3537Syasuoka 	return (npppd_iface_ip_is_ready(ppp_iface(ppp)) &&
21960fbf3537Syasuoka 	    ppp_ipcp(ppp) != NULL)? 1 : 0;
21970fbf3537Syasuoka }
21980fbf3537Syasuoka 
2199f0a4e295Syasuoka /** Select a suitable interface for {@link :npppd_ppp PPP} and bind them  */
22000fbf3537Syasuoka int
22010fbf3537Syasuoka npppd_ppp_bind_iface(npppd *_this, npppd_ppp *ppp)
22020fbf3537Syasuoka {
2203821f7c56Syasuoka 	int              i, ifidx;
2204821f7c56Syasuoka 	struct confbind *bind;
22052a5607d2Sgoda 	struct ipcpstat *ipcpstat;
22060fbf3537Syasuoka 
22070fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
22080fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
22090fbf3537Syasuoka 
22100fbf3537Syasuoka 	if (ppp->ifidx >= 0)
22110fbf3537Syasuoka 		return 0;
22120fbf3537Syasuoka 
2213821f7c56Syasuoka 	TAILQ_FOREACH(bind, &_this->conf.confbinds, entry) {
2214821f7c56Syasuoka 		if (strcmp(bind->tunnconf->name, ppp->phy_label) != 0)
2215821f7c56Syasuoka 			continue;
2216821f7c56Syasuoka 		if (ppp->realm == NULL) {
2217821f7c56Syasuoka 			if (bind->authconf == NULL)
2218821f7c56Syasuoka 				break;
2219821f7c56Syasuoka 		} else if (strcmp(bind->authconf->name,
2220821f7c56Syasuoka 		    npppd_auth_get_name(ppp->realm)) == 0)
2221821f7c56Syasuoka 			break;
2222821f7c56Syasuoka 	}
2223821f7c56Syasuoka 	if (bind == NULL)
22240fbf3537Syasuoka 		return 1;
22250fbf3537Syasuoka 
2226f0a4e295Syasuoka 	/* Search a interface */
22270fbf3537Syasuoka 	ifidx = -1;
22280fbf3537Syasuoka 	for (i = 0; i < countof(_this->iface); i++) {
22290fbf3537Syasuoka 		if (_this->iface[i].initialized == 0)
22300fbf3537Syasuoka 			continue;
2231821f7c56Syasuoka 		if (strcmp(_this->iface[i].ifname, bind->iface->name) == 0)
22320fbf3537Syasuoka 			ifidx = i;
22330fbf3537Syasuoka 	}
22340fbf3537Syasuoka 	if (ifidx < 0)
22350fbf3537Syasuoka 		return 1;
22360fbf3537Syasuoka 
22372a5607d2Sgoda 	ppp->ifidx = ifidx;
22382a5607d2Sgoda 	NPPPD_ASSERT(ppp_ipcp(ppp) != NULL);
22392a5607d2Sgoda 	ipcpstat = npppd_get_ipcp_stat(&_this->ipcpstats, ppp_ipcp(ppp)->name);
22402a5607d2Sgoda 	if (ipcpstat == NULL) {
22412a5607d2Sgoda 		ppp_log(ppp, LOG_WARNING, "Unknown IPCP %s",
22422a5607d2Sgoda 		    ppp_ipcp(ppp)->name);
22432a5607d2Sgoda 		ppp->ifidx = -1; /* unbind inteface */
22442a5607d2Sgoda 		return 1;
22452a5607d2Sgoda 	}
22462a5607d2Sgoda 	if (ppp_ipcp(ppp)->max_session > 0 &&
22472a5607d2Sgoda 	    ipcpstat->nsession >= ppp_ipcp(ppp)->max_session) {
22482a5607d2Sgoda 		ppp_log(ppp, LOG_WARNING,
22492a5607d2Sgoda 		    "Number of sessions per IPCP reaches out of the limit=%d",
22502a5607d2Sgoda 		    ppp_ipcp(ppp)->max_session);
22512a5607d2Sgoda 		ppp->ifidx = -1; /* unbind inteface */
22522a5607d2Sgoda 		return 1;
22532a5607d2Sgoda 	}
22542a5607d2Sgoda 
2255e43db91eSyasuoka 	if (_this->conf.max_session > 0 &&
22564080edd5Syasuoka 	    _this->nsession >= _this->conf.max_session) {
22570fbf3537Syasuoka 		ppp_log(ppp, LOG_WARNING,
22580fbf3537Syasuoka 		    "Number of sessions reaches out of the limit=%d",
2259e43db91eSyasuoka 		    _this->conf.max_session);
22602a5607d2Sgoda 		ppp->ifidx = -1; /* unbind inteface */
22610fbf3537Syasuoka 		return 1;
22620fbf3537Syasuoka 	}
22634080edd5Syasuoka 	_this->nsession++;
22640fbf3537Syasuoka 
22652a5607d2Sgoda 	LIST_INSERT_HEAD(&ipcpstat->ppp, ppp, ipcpstat_entry);
22662a5607d2Sgoda 	ppp->ipcpstat = ipcpstat;
22672a5607d2Sgoda 	ipcpstat->nsession++;
22682a5607d2Sgoda 
22690fbf3537Syasuoka 	return 0;
22700fbf3537Syasuoka }
22710fbf3537Syasuoka 
2272f0a4e295Syasuoka /** Unbind the interface from the {@link ::npppd_ppp PPP} */
22730fbf3537Syasuoka void
22740fbf3537Syasuoka npppd_ppp_unbind_iface(npppd *_this, npppd_ppp *ppp)
22750fbf3537Syasuoka {
22762a5607d2Sgoda 	if (ppp->ifidx >= 0) {
2277821f7c56Syasuoka 		_this->nsession--;
22782a5607d2Sgoda 		if (ppp->ipcpstat!= NULL) {
22792a5607d2Sgoda 			ppp->ipcpstat->nsession--;
22802a5607d2Sgoda 			LIST_REMOVE(ppp, ipcpstat_entry);
22812a5607d2Sgoda 		}
22822a5607d2Sgoda 	}
22830fbf3537Syasuoka 	ppp->ifidx = -1;
22840fbf3537Syasuoka }
22850fbf3537Syasuoka 
22860fbf3537Syasuoka static int
22870fbf3537Syasuoka npppd_rd_walktree_delete(struct radish_head *rh)
22880fbf3537Syasuoka {
22890fbf3537Syasuoka 	void *dummy;
22900fbf3537Syasuoka 	struct radish *rd;
22910fbf3537Syasuoka 	slist list;
22920fbf3537Syasuoka 
22930fbf3537Syasuoka 	slist_init(&list);
22940fbf3537Syasuoka 	if (rd2slist(rh, &list) != 0)
22950fbf3537Syasuoka 		return 1;
22960fbf3537Syasuoka 	for (slist_itr_first(&list); slist_itr_has_next(&list);) {
22970fbf3537Syasuoka 		rd = slist_itr_next(&list);
22980fbf3537Syasuoka 		rd_delete(rd->rd_route, rd->rd_mask, rh, &dummy);
22990fbf3537Syasuoka 	}
23000fbf3537Syasuoka 	slist_fini(&list);
23010fbf3537Syasuoka 
23020fbf3537Syasuoka 	free(rh);
23030fbf3537Syasuoka 
23040fbf3537Syasuoka 	return 0;
23050fbf3537Syasuoka }
23060fbf3537Syasuoka 
23070fbf3537Syasuoka #ifdef USE_NPPPD_RADIUS
2308f0a4e295Syasuoka /**
2309f0a4e295Syasuoka  * Return radius_req_setting for the given {@link ::npppd_ppp PPP}.
2310f0a4e295Syasuoka  * @return return NULL if no usable RADIUS setting.
2311f0a4e295Syasuoka  */
23120fbf3537Syasuoka void *
23138daf7599Syasuoka npppd_get_radius_auth_setting(npppd *_this, npppd_ppp *ppp)
23140fbf3537Syasuoka {
23150fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
23160fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
23170fbf3537Syasuoka 
23180fbf3537Syasuoka 	if (ppp->realm == NULL)
23190fbf3537Syasuoka 		return NULL;
23200fbf3537Syasuoka 	if (!npppd_ppp_is_realm_radius(_this, ppp))
23210fbf3537Syasuoka 		return NULL;
23220fbf3537Syasuoka 
23238daf7599Syasuoka 	return npppd_auth_radius_get_radius_auth_setting(ppp->realm);
23240fbf3537Syasuoka }
23250fbf3537Syasuoka #endif
23260fbf3537Syasuoka 
2327f0a4e295Syasuoka /** Finalize authentication realm */
23280fbf3537Syasuoka static void
23290fbf3537Syasuoka npppd_auth_finalizer_periodic(npppd *_this)
23300fbf3537Syasuoka {
23310fbf3537Syasuoka 	int ndisposing = 0, refcnt;
23320fbf3537Syasuoka 	slist users;
23330fbf3537Syasuoka 	npppd_auth_base *auth_base;
23340fbf3537Syasuoka 	npppd_ppp *ppp;
23350fbf3537Syasuoka 
23360fbf3537Syasuoka 	/*
2337f0a4e295Syasuoka 	 * For the realms with disposing flag, if the realm has assigned PPPs,
2338f0a4e295Syasuoka 	 * disconnect them.  If all PPPs are disconnected then free the realm.
23390fbf3537Syasuoka 	 */
23400fbf3537Syasuoka 	NPPPD_DBG((DEBUG_LEVEL_2, "%s() called", __func__));
23410fbf3537Syasuoka 	slist_itr_first(&_this->realms);
23420fbf3537Syasuoka 	while (slist_itr_has_next(&_this->realms)) {
23430fbf3537Syasuoka 		auth_base = slist_itr_next(&_this->realms);
23440fbf3537Syasuoka 		if (!npppd_auth_is_disposing(auth_base))
23450fbf3537Syasuoka 			continue;
23460fbf3537Syasuoka 		refcnt = 0;
23470fbf3537Syasuoka 		if (ndisposing++ == 0) {
23480fbf3537Syasuoka 			slist_init(&users);
23490fbf3537Syasuoka 			if (npppd_get_all_users(_this, &users) != 0) {
23500fbf3537Syasuoka 				log_printf(LOG_WARNING,
23510fbf3537Syasuoka 				    "npppd_get_all_users() failed in %s(): %m",
23520fbf3537Syasuoka 				    __func__);
23530fbf3537Syasuoka 				break;
23540fbf3537Syasuoka 			}
23550fbf3537Syasuoka 		}
23560fbf3537Syasuoka 		slist_itr_first(&users);
23570fbf3537Syasuoka 		while (slist_itr_has_next(&users)) {
23580fbf3537Syasuoka 			ppp = slist_itr_next(&users);
23590fbf3537Syasuoka 			if (ppp->realm == auth_base) {
23600fbf3537Syasuoka 				refcnt++;
23610fbf3537Syasuoka 				ppp_stop(ppp, NULL);
23620fbf3537Syasuoka 				ppp_log(ppp, LOG_INFO,
23630fbf3537Syasuoka 				    "Stop request by npppd.  Binding "
23640fbf3537Syasuoka 				    "authentication realm is disposing.  "
23650fbf3537Syasuoka 				    "realm=%s", npppd_auth_get_name(auth_base));
23660fbf3537Syasuoka 				slist_itr_remove(&users);
23670fbf3537Syasuoka 			}
23680fbf3537Syasuoka 		}
23698daf7599Syasuoka 		if (refcnt == 0) {
23700fbf3537Syasuoka 			npppd_auth_destroy(auth_base);
23718daf7599Syasuoka 			slist_itr_remove(&_this->realms);
23728daf7599Syasuoka 		}
23730fbf3537Syasuoka 	}
23740fbf3537Syasuoka 	if (ndisposing > 0)
23750fbf3537Syasuoka 		slist_fini(&users);
23760fbf3537Syasuoka }
23770fbf3537Syasuoka 
2378f0a4e295Syasuoka /** compare sockaddr_npppd.  return 0 if matches */
23790fbf3537Syasuoka int
23800fbf3537Syasuoka sockaddr_npppd_match(void *a0, void *b0)
23810fbf3537Syasuoka {
23820fbf3537Syasuoka 	struct sockaddr_npppd *a, *b;
23830fbf3537Syasuoka 
23840fbf3537Syasuoka 	a = a0;
23850fbf3537Syasuoka 	b = b0;
23860fbf3537Syasuoka 
23870fbf3537Syasuoka 	return (a->snp_addr.s_addr == b->snp_addr.s_addr)? 1 : 0;
23880fbf3537Syasuoka }
23890fbf3537Syasuoka 
23900fbf3537Syasuoka /**
2391f0a4e295Syasuoka  * This function stores the username for authentication to the space specified
2392f0a4e295Syasuoka  * by username_buffer and returns it.  username_buffer must have space more
2393f0a4e295Syasuoka  * than MAX_USERNAME_LENGTH.
23940fbf3537Syasuoka  */
23950fbf3537Syasuoka const char *
23960fbf3537Syasuoka npppd_ppp_get_username_for_auth(npppd *_this, npppd_ppp *ppp,
23970fbf3537Syasuoka     const char *username, char *username_buffer)
23980fbf3537Syasuoka {
23990fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
24000fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
24010fbf3537Syasuoka 	NPPPD_ASSERT(ppp->realm != NULL);
24020fbf3537Syasuoka 
24030fbf3537Syasuoka 	return npppd_auth_username_for_auth(ppp->realm, username,
24040fbf3537Syasuoka 	    username_buffer);
24050fbf3537Syasuoka }
24060fbf3537Syasuoka 
2407363e4d4bSyasuoka const char *
2408821f7c56Syasuoka npppd_tunnel_protocol_name(int tunn_protocol)
2409363e4d4bSyasuoka {
2410821f7c56Syasuoka 	switch (tunn_protocol) {
2411821f7c56Syasuoka 	case NPPPD_TUNNEL_NONE:
2412363e4d4bSyasuoka 		return "None";
2413821f7c56Syasuoka 	case NPPPD_TUNNEL_L2TP:
2414363e4d4bSyasuoka 		return "L2TP";
2415821f7c56Syasuoka 	case NPPPD_TUNNEL_PPTP:
2416363e4d4bSyasuoka 		return "PPTP";
2417821f7c56Syasuoka 	case NPPPD_TUNNEL_PPPOE:
2418363e4d4bSyasuoka 		return "PPPoE";
2419821f7c56Syasuoka 	case NPPPD_TUNNEL_SSTP:
2420363e4d4bSyasuoka 		return "SSTP";
2421363e4d4bSyasuoka 	}
2422363e4d4bSyasuoka 
2423363e4d4bSyasuoka 	return "Error";
2424363e4d4bSyasuoka }
2425821f7c56Syasuoka 
2426821f7c56Syasuoka const char *
2427821f7c56Syasuoka npppd_ppp_tunnel_protocol_name(npppd *_this, npppd_ppp *ppp)
2428821f7c56Syasuoka {
2429821f7c56Syasuoka 	return npppd_tunnel_protocol_name(ppp->tunnel_type);
2430821f7c56Syasuoka }
2431821f7c56Syasuoka 
2432821f7c56Syasuoka struct tunnconf *
2433821f7c56Syasuoka npppd_get_tunnconf(npppd *_this, const char *name)
2434821f7c56Syasuoka {
2435821f7c56Syasuoka 	struct tunnconf *conf;
2436821f7c56Syasuoka 
2437821f7c56Syasuoka 	TAILQ_FOREACH(conf, &_this->conf.tunnconfs, entry) {
2438821f7c56Syasuoka 		if (strcmp(conf->name, name) == 0)
2439821f7c56Syasuoka 			return conf;
2440821f7c56Syasuoka 	}
2441821f7c56Syasuoka 
2442821f7c56Syasuoka 	return NULL;
2443821f7c56Syasuoka }
2444821f7c56Syasuoka 
244534682664Syasuoka void
244634682664Syasuoka npppd_on_ppp_start(npppd *_this, npppd_ppp *ppp)
244734682664Syasuoka {
244834682664Syasuoka 	struct ctl_conn  *c;
244934682664Syasuoka 
245034682664Syasuoka 	TAILQ_FOREACH(c, &ctl_conns, entry) {
245134682664Syasuoka 		if (npppd_ctl_add_started_ppp_id(c->ctx, ppp->id) == 0) {
245234682664Syasuoka 			npppd_ctl_imsg_compose(c->ctx, &c->iev.ibuf);
245334682664Syasuoka 			imsg_event_add(&c->iev);
245434682664Syasuoka 		}
245534682664Syasuoka 	}
245634682664Syasuoka }
245734682664Syasuoka 
245834682664Syasuoka void
245934682664Syasuoka npppd_on_ppp_stop(npppd *_this, npppd_ppp *ppp)
246034682664Syasuoka {
246134682664Syasuoka 	struct ctl_conn  *c;
246234682664Syasuoka 
246334682664Syasuoka 	TAILQ_FOREACH(c, &ctl_conns, entry) {
246434682664Syasuoka 		if (npppd_ctl_add_stopped_ppp(c->ctx, ppp) == 0) {
246534682664Syasuoka 			npppd_ctl_imsg_compose(c->ctx, &c->iev.ibuf);
246634682664Syasuoka 			imsg_event_add(&c->iev);
246734682664Syasuoka 		}
246834682664Syasuoka 	}
246934682664Syasuoka }
247034682664Syasuoka 
247134682664Syasuoka void
247234682664Syasuoka imsg_event_add(struct imsgev *iev)
247334682664Syasuoka {
247434682664Syasuoka 	iev->events = EV_READ;
247534682664Syasuoka 	if (iev->ibuf.w.queued)
247634682664Syasuoka 		iev->events |= EV_WRITE;
247734682664Syasuoka 
247834682664Syasuoka 	event_del(&iev->ev);
247934682664Syasuoka 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
248034682664Syasuoka 	event_add(&iev->ev, NULL);
248134682664Syasuoka }
2482