xref: /openbsd/usr.sbin/npppd/npppd/npppd.c (revision fd218b06)
1*fd218b06Smarkus /* $OpenBSD: npppd.c,v 1.10 2011/05/15 15:47:52 markus Exp $ */
2e109dc18Syasuoka 
30fbf3537Syasuoka /*-
40fbf3537Syasuoka  * Copyright (c) 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*fd218b06Smarkus  * $Id: npppd.c,v 1.10 2011/05/15 15:47:52 markus Exp $
330fbf3537Syasuoka  */
340fbf3537Syasuoka #include <sys/cdefs.h>
350fbf3537Syasuoka #include "version.h"
360fbf3537Syasuoka #ifndef LINT
370fbf3537Syasuoka __COPYRIGHT(
380fbf3537Syasuoka "@(#) npppd - PPP daemon for PPP Access Concentrators\n"
390fbf3537Syasuoka "@(#) Version " VERSION "\n"
400fbf3537Syasuoka "@(#) \n"
410fbf3537Syasuoka "@(#) Copyright 2005-2008\n"
420fbf3537Syasuoka "@(#) 	Internet Initiative Japan Inc.  All rights reserved.\n"
430fbf3537Syasuoka "@(#) \n"
440fbf3537Syasuoka "@(#) \n"
450fbf3537Syasuoka "@(#) \n"
460fbf3537Syasuoka );
470fbf3537Syasuoka #endif
480fbf3537Syasuoka #include <sys/types.h>
490fbf3537Syasuoka #include <sys/socket.h>
500fbf3537Syasuoka #include <sys/param.h>
510fbf3537Syasuoka #include <sys/sysctl.h>
520fbf3537Syasuoka #include <netinet/in.h>
530fbf3537Syasuoka #include <netinet/in_systm.h>
540fbf3537Syasuoka #include <netinet/ip.h>
550fbf3537Syasuoka #include <net/route.h>
560fbf3537Syasuoka #include <arpa/inet.h>
570fbf3537Syasuoka #include <net/if_dl.h>
580fbf3537Syasuoka #include <unistd.h>
590fbf3537Syasuoka #include <time.h>
600fbf3537Syasuoka #include <syslog.h>
610fbf3537Syasuoka #include <string.h>
620fbf3537Syasuoka #include <stdlib.h>
630fbf3537Syasuoka #include <stdio.h>
640fbf3537Syasuoka #include <signal.h>
650fbf3537Syasuoka #include <netdb.h>
660fbf3537Syasuoka #include <libgen.h>
670fbf3537Syasuoka #include <fcntl.h>
680fbf3537Syasuoka #include <event.h>
690fbf3537Syasuoka #include <errno.h>
700fbf3537Syasuoka #include <ifaddrs.h>
714a78f66bSyasuoka #include <err.h>
724a78f66bSyasuoka #include <pwd.h>
730fbf3537Syasuoka 
740fbf3537Syasuoka #include "pathnames.h"
750fbf3537Syasuoka #include "debugutil.h"
760fbf3537Syasuoka #include "addr_range.h"
770fbf3537Syasuoka #include "npppd_subr.h"
780fbf3537Syasuoka #include "npppd_local.h"
790fbf3537Syasuoka #include "npppd_auth.h"
800fbf3537Syasuoka #include "radish.h"
810fbf3537Syasuoka #include "rtev.h"
820fbf3537Syasuoka #include "net_utils.h"
830fbf3537Syasuoka #include "time_utils.h"
840fbf3537Syasuoka 
850fbf3537Syasuoka #ifdef USE_NPPPD_ARP
860fbf3537Syasuoka #include "npppd_arp.h"
870fbf3537Syasuoka #endif
880fbf3537Syasuoka 
890fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
900fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
910fbf3537Syasuoka #include "pppoe_local.h"
920fbf3537Syasuoka #endif /* USE_NPPPD_PPPOE */
930fbf3537Syasuoka #include "psm-opt.h"
940fbf3537Syasuoka #include <sys/ioctl.h>
950fbf3537Syasuoka #if defined(__NetBSD__)
960fbf3537Syasuoka #include <net/if_ether.h>
970fbf3537Syasuoka #else
980fbf3537Syasuoka #include <netinet/if_ether.h>
990fbf3537Syasuoka #endif
100886d2b78Syasuoka #include <netinet/ip_var.h>
101886d2b78Syasuoka #include <net/if_types.h>
1020fbf3537Syasuoka #include <net/pipex.h>
1030fbf3537Syasuoka #endif /* USE_NPPPD_PIPEX */
1040fbf3537Syasuoka 
1050fbf3537Syasuoka static npppd s_npppd;	/* singleton */
1060fbf3537Syasuoka 
1070fbf3537Syasuoka static void            npppd_reload0(npppd *);
1080fbf3537Syasuoka static int             npppd_rd_walktree_delete(struct radish_head *);
1090fbf3537Syasuoka static void            usage (void);
1100fbf3537Syasuoka static void            npppd_start (npppd *);
1110fbf3537Syasuoka static void            npppd_stop_really (npppd *);
1120fbf3537Syasuoka static uint32_t        str_hash(const void *, int);
1130fbf3537Syasuoka static void            npppd_on_sighup (int, short, void *);
1140fbf3537Syasuoka static void            npppd_on_sigterm (int, short, void *);
1150fbf3537Syasuoka static void            npppd_on_sigint (int, short, void *);
1160fbf3537Syasuoka static void            npppd_reset_timer(npppd *);
1170fbf3537Syasuoka static void            npppd_timer(int, short, void *);
1180fbf3537Syasuoka static void	       npppd_auth_finalizer_periodic(npppd *);
1190fbf3537Syasuoka static int  rd2slist_walk (struct radish *, void *);
1200fbf3537Syasuoka static int  rd2slist (struct radish_head *, slist *);
1210fbf3537Syasuoka static inline void     seed_random(long *);
1220fbf3537Syasuoka 
1230fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
1240fbf3537Syasuoka static struct in_addr loop;	/* initialize at npppd_init() */
1250fbf3537Syasuoka #endif
1260fbf3537Syasuoka static uint32_t        str_hash(const void *, int);
1270fbf3537Syasuoka 
1280fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
1290fbf3537Syasuoka static int npppd_ppp_pipex_ip_disable(npppd *, npppd_ppp *);
1300fbf3537Syasuoka static void pipex_periodic(npppd *);
1310fbf3537Syasuoka #endif /* USE_NPPPD_PIPEX */
1320fbf3537Syasuoka 
1330fbf3537Syasuoka #ifdef NPPPD_DEBUG
1340fbf3537Syasuoka #define NPPPD_DBG(x) 	log_printf x
1350fbf3537Syasuoka #define NPPPD_ASSERT(x) ASSERT(x)
1360fbf3537Syasuoka #else
1370fbf3537Syasuoka #define NPPPD_DBG(x)
1380fbf3537Syasuoka #define NPPPD_ASSERT(x)
1390fbf3537Syasuoka #endif
1400fbf3537Syasuoka 
1410fbf3537Syasuoka /***********************************************************************
142f0a4e295Syasuoka  * Daemon process
1430fbf3537Syasuoka  ***********************************************************************/
1440fbf3537Syasuoka int        main (int, char *[]);
1450fbf3537Syasuoka 
1460fbf3537Syasuoka int
1470fbf3537Syasuoka main(int argc, char *argv[])
1480fbf3537Syasuoka {
1490fbf3537Syasuoka 	int ch, retval = 0, ll_adjust = 0, runasdaemon = 0;
1500fbf3537Syasuoka 	extern char *optarg;
1510fbf3537Syasuoka 	const char *npppd_conf0 = DEFAULT_NPPPD_CONF;
1524a78f66bSyasuoka 	struct passwd *pw;
1530fbf3537Syasuoka 
1540fbf3537Syasuoka 	while ((ch = getopt(argc, argv, "Dc:dhs")) != -1) {
1550fbf3537Syasuoka 		switch (ch) {
1560fbf3537Syasuoka 		case 's':
1570fbf3537Syasuoka 			ll_adjust++;
1580fbf3537Syasuoka 			break;
1590fbf3537Syasuoka 		case 'c':
1600fbf3537Syasuoka 			npppd_conf0 = optarg;
1610fbf3537Syasuoka 			break;
1620fbf3537Syasuoka 		case 'D':
1630fbf3537Syasuoka 			runasdaemon = 1;
1640fbf3537Syasuoka 			break;
1650fbf3537Syasuoka 		case 'd':
1660fbf3537Syasuoka 			debuglevel++;
1670fbf3537Syasuoka 			break;
1680fbf3537Syasuoka 		case '?':
1690fbf3537Syasuoka 		case 'h':
1700fbf3537Syasuoka 			usage();
1710fbf3537Syasuoka 			exit(1);
1720fbf3537Syasuoka 		}
1730fbf3537Syasuoka 	}
1740fbf3537Syasuoka 	if (debuglevel > 0) {
1750fbf3537Syasuoka 		debug_set_debugfp(stderr);
1760fbf3537Syasuoka 		debug_use_syslog(0);
1770fbf3537Syasuoka 	} else {
1780fbf3537Syasuoka 		debug_set_syslog_level_adjust(ll_adjust);
1790fbf3537Syasuoka 		openlog(NULL, LOG_PID, LOG_NPPPD);
1800fbf3537Syasuoka 		if (runasdaemon)
1810fbf3537Syasuoka 			daemon(0, 0);
1820fbf3537Syasuoka 	}
1830fbf3537Syasuoka 
1844a78f66bSyasuoka 	/* check for root privileges */
1854a78f66bSyasuoka 	if (geteuid())
1864a78f66bSyasuoka 		errx(1, "need root privileges");
1874a78f66bSyasuoka 	/* check for npppd user */
1884a78f66bSyasuoka 	if (getpwnam(NPPPD_USER) == NULL)
1894a78f66bSyasuoka 		errx(1, "unknown user %s", NPPPD_USER);
1904a78f66bSyasuoka 
1914a78f66bSyasuoka 	if (privsep_init() != 0)
1924a78f66bSyasuoka 		err(1, "cannot drop privileges");
1934a78f66bSyasuoka 
1940fbf3537Syasuoka 	if (npppd_init(&s_npppd, npppd_conf0) != 0) {
1950fbf3537Syasuoka 		retval = 1;
196f0a4e295Syasuoka 		goto fail;
1970fbf3537Syasuoka 	}
1984a78f66bSyasuoka 
1994a78f66bSyasuoka 	if ((pw = getpwnam(NPPPD_USER)) == NULL)
2004a78f66bSyasuoka 		err(1, "gwpwnam");
2014a78f66bSyasuoka 	if (chroot(pw->pw_dir) == -1)
2024a78f66bSyasuoka 		err(1, "chroot");
2034a78f66bSyasuoka 	if (chdir("/") == -1)
2044a78f66bSyasuoka 		err(1, "chdir(\"/\")");
2054a78f66bSyasuoka         if (setgroups(1, &pw->pw_gid) ||
2064a78f66bSyasuoka 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
2074a78f66bSyasuoka 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
2084a78f66bSyasuoka 		err(1, "cannot drop privileges");
2094a78f66bSyasuoka 	/* privileges is dropped */
2104a78f66bSyasuoka 
2110fbf3537Syasuoka 	npppd_start(&s_npppd);
2120fbf3537Syasuoka 	npppd_fini(&s_npppd);
2134a78f66bSyasuoka 	/* FALLTHROUGH */
214f0a4e295Syasuoka fail:
2154a78f66bSyasuoka 	privsep_fini();
2160fbf3537Syasuoka 	log_printf(LOG_NOTICE, "Terminate npppd.");
2170fbf3537Syasuoka 
2180fbf3537Syasuoka 	return retval;
2190fbf3537Syasuoka }
2200fbf3537Syasuoka 
2210fbf3537Syasuoka static void
2220fbf3537Syasuoka usage()
2230fbf3537Syasuoka {
2240fbf3537Syasuoka 	fprintf(stderr,
2250fbf3537Syasuoka 	    "usage: npppd [-sDdh] [-c config_file]\n"
2260fbf3537Syasuoka 	    "\t-d: increase debuglevel.  Output log to standard error.\n"
2270fbf3537Syasuoka 	    "\t-c: specify configuration file.  default=\"%s\".\n"
2280fbf3537Syasuoka 	    "\t-s: adjust syslog level to be silent.\n"
2290fbf3537Syasuoka 	    "\t-D: run as a daemon.\n"
2300fbf3537Syasuoka 	    "\t-h: show usage.\n"
2310fbf3537Syasuoka 	    , DEFAULT_NPPPD_CONF
2320fbf3537Syasuoka 	);
2330fbf3537Syasuoka }
2340fbf3537Syasuoka 
235f0a4e295Syasuoka /** Returns the singleton npppd instance */
2360fbf3537Syasuoka npppd *
2370fbf3537Syasuoka npppd_get_npppd()
2380fbf3537Syasuoka {
2390fbf3537Syasuoka 	return &s_npppd;
2400fbf3537Syasuoka }
2410fbf3537Syasuoka 
2420fbf3537Syasuoka /***********************************************************************
243f0a4e295Syasuoka  * Operations to npppd itself (initialize/finalize/start/stop)
2440fbf3537Syasuoka  ***********************************************************************/
245f0a4e295Syasuoka  /** Initialize the npppd */
2460fbf3537Syasuoka int
2470fbf3537Syasuoka npppd_init(npppd *_this, const char *config_file)
2480fbf3537Syasuoka {
2490fbf3537Syasuoka 	int i, status = -1;
2500fbf3537Syasuoka 	char pidpath[MAXPATHLEN];
2510fbf3537Syasuoka 	const char *pidpath0;
2520fbf3537Syasuoka 	const char *coredir;
2530fbf3537Syasuoka 	FILE *pidfp = NULL;
2540fbf3537Syasuoka 	char	cwd[MAXPATHLEN];
2550fbf3537Syasuoka 	long seed;
2560fbf3537Syasuoka 
2570fbf3537Syasuoka 	memset(_this, 0, sizeof(npppd));
258cd8e09b9Sdlg #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
2590fbf3537Syasuoka 	loop.s_addr = htonl(INADDR_LOOPBACK);
260cd8e09b9Sdlg #endif
2610fbf3537Syasuoka 
2620fbf3537Syasuoka 	NPPPD_ASSERT(config_file != NULL);
2630fbf3537Syasuoka 
2640fbf3537Syasuoka 	pidpath0 = NULL;
2650fbf3537Syasuoka 	_this->pid = getpid();
2660fbf3537Syasuoka 	slist_init(&_this->realms);
2670fbf3537Syasuoka 
2680fbf3537Syasuoka 	log_printf(LOG_NOTICE, "Starting npppd pid=%u version=%s",
2690fbf3537Syasuoka 	    _this->pid, VERSION);
2700fbf3537Syasuoka #if defined(BUILD_DATE) && defined(BUILD_TIME)
2710fbf3537Syasuoka 	log_printf(LOG_INFO, "Build %s %s ", BUILD_DATE, BUILD_TIME);
2720fbf3537Syasuoka #endif
2730fbf3537Syasuoka 	if (get_nanotime() == INT64_MIN) {
2740fbf3537Syasuoka 		log_printf(LOG_ERR, "get_nanotime() failed: %m");
2750fbf3537Syasuoka 		return 1;
2760fbf3537Syasuoka 	}
2770fbf3537Syasuoka 
2780fbf3537Syasuoka 	if (realpath(config_file, _this->config_file) == NULL) {
2790fbf3537Syasuoka 		log_printf(LOG_ERR, "realpath(%s,) failed in %s(): %m",
2800fbf3537Syasuoka 		    config_file, __func__);
2810fbf3537Syasuoka 		return 1;
2820fbf3537Syasuoka 	}
283f0a4e295Syasuoka 	/* we assume 4.4 compatible realpath().  See realpath(3) on BSD. */
2840fbf3537Syasuoka 	NPPPD_ASSERT(_this->config_file[0] == '/');
2850fbf3537Syasuoka 
2860fbf3537Syasuoka 	/* initialize random seeds */
2870fbf3537Syasuoka 	seed_random(&seed);
2880fbf3537Syasuoka 	srandom(seed);
2890fbf3537Syasuoka 
290f0a4e295Syasuoka 	/* load configuration */
2910fbf3537Syasuoka 	if ((status = npppd_reload_config(_this)) != 0)
2920fbf3537Syasuoka 		return status;
2930fbf3537Syasuoka 
2940fbf3537Syasuoka 	if ((_this->map_user_ppp = hash_create(
2950fbf3537Syasuoka 	    (int (*) (const void *, const void *))strcmp, str_hash,
2960fbf3537Syasuoka 	    NPPPD_USER_HASH_SIZ)) == NULL) {
2970fbf3537Syasuoka 		log_printf(LOG_ERR, "hash_create() failed in %s(): %m",
2980fbf3537Syasuoka 		    __func__);
2990fbf3537Syasuoka 		return -1;
3000fbf3537Syasuoka 	}
3010fbf3537Syasuoka 
3020fbf3537Syasuoka 	if (npppd_ifaces_load_config(_this) != 0) {
3030fbf3537Syasuoka 		return -1;
3040fbf3537Syasuoka 	}
3050fbf3537Syasuoka 
3060fbf3537Syasuoka 	if ((pidpath0 = npppd_config_str(_this, "pidfile")) == NULL)
3070fbf3537Syasuoka 		pidpath0 = DEFAULT_NPPPD_PIDFILE;
3080fbf3537Syasuoka 
309f0a4e295Syasuoka 	/* Runtime directory */
3100fbf3537Syasuoka 	if ((coredir = npppd_config_str(_this, "coredir")) == NULL) {
311f0a4e295Syasuoka 		/* diretory for pid file */
3120fbf3537Syasuoka 		strlcpy(pidpath, pidpath0, sizeof(pidpath));
3130fbf3537Syasuoka 		strlcpy(cwd, dirname(pidpath), sizeof(cwd));
3140fbf3537Syasuoka 	}
3150fbf3537Syasuoka 	else {
316f0a4e295Syasuoka 		/* directory for dumping core */
3170fbf3537Syasuoka 		strlcpy(cwd, coredir, sizeof(cwd));
3180fbf3537Syasuoka 	}
3190fbf3537Syasuoka 	if (chdir(cwd) != 0) {
3200fbf3537Syasuoka 		log_printf(LOG_ERR, "chdir(%s,) failed in %s(): %m", __func__,
3210fbf3537Syasuoka 		    cwd);
3220fbf3537Syasuoka 		return -1;
3230fbf3537Syasuoka 	}
3240fbf3537Syasuoka 
325f0a4e295Syasuoka 	/* initialize event(3) */
3260fbf3537Syasuoka 	event_init();
3270fbf3537Syasuoka 
328f0a4e295Syasuoka 	/* initialize rtev */
3290fbf3537Syasuoka 	rtev_libevent_init(
3300fbf3537Syasuoka 	    npppd_config_int(_this, "rtsock.event_delay",
3310fbf3537Syasuoka 		DEFAULT_RTSOCK_EVENT_DELAY),
3320fbf3537Syasuoka 	    npppd_config_int(_this, "rtsock.send_wait_millisec",
3330fbf3537Syasuoka 		DEFAULT_RTSOCK_SEND_WAIT_MILLISEC),
3340fbf3537Syasuoka 	    npppd_config_int(_this, "rtsock.send_npkts",
3350fbf3537Syasuoka 		DEFAULT_RTSOCK_SEND_NPKTS), 0);
336f0a4e295Syasuoka 
3370fbf3537Syasuoka 	_this->rtev_event_serial = -1;
3380fbf3537Syasuoka 
339f0a4e295Syasuoka 	/* ignore signals */
3400fbf3537Syasuoka 	signal(SIGPIPE, SIG_IGN);
3410fbf3537Syasuoka 	signal(SIGURG, SIG_IGN);
342f0a4e295Syasuoka 
343f0a4e295Syasuoka 	/* set signal handlers */
3440fbf3537Syasuoka 	signal_set(&_this->ev_sigterm, SIGTERM, npppd_on_sigterm, _this);
3450fbf3537Syasuoka 	signal_set(&_this->ev_sigint, SIGINT, npppd_on_sigint, _this);
3460fbf3537Syasuoka 	signal_set(&_this->ev_sighup, SIGHUP, npppd_on_sighup, _this);
3470fbf3537Syasuoka 	signal_add(&_this->ev_sigterm, NULL);
3480fbf3537Syasuoka 	signal_add(&_this->ev_sigint, NULL);
3490fbf3537Syasuoka 	signal_add(&_this->ev_sighup, NULL);
3500fbf3537Syasuoka 
3510fbf3537Syasuoka 	evtimer_set(&_this->ev_timer, npppd_timer, _this);
3520fbf3537Syasuoka 
353f0a4e295Syasuoka 	/* start tun(4) or pppac(4) */
3540fbf3537Syasuoka 	status = 0;
3550fbf3537Syasuoka 	for (i = 0; i < countof(_this->iface); i++) {
3560fbf3537Syasuoka 		if (_this->iface[i].initialized != 0)
3570fbf3537Syasuoka 			status |= npppd_iface_start(&_this->iface[i]);
3580fbf3537Syasuoka 	}
3590fbf3537Syasuoka 	if (status != 0)
3600fbf3537Syasuoka 		return -1;
3610fbf3537Syasuoka 
3620fbf3537Syasuoka 	/*
363f0a4e295Syasuoka 	 * If the npppd can start(open) interfaces successfully, it can
364f0a4e295Syasuoka 	 * act as only one npppd process on the system and overwrite the pid
365f0a4e295Syasuoka 	 * file.
3660fbf3537Syasuoka 	 */
3670fbf3537Syasuoka 	if ((pidfp = fopen(pidpath0, "w+")) == NULL) {
3680fbf3537Syasuoka 		log_printf(LOG_ERR, "fopen(%s,w+) failed in %s(): %m",
3690fbf3537Syasuoka 		    pidpath0, __func__);
3700fbf3537Syasuoka 		return -1;
3710fbf3537Syasuoka 	}
3720fbf3537Syasuoka 	strlcpy(_this->pidpath, pidpath0, sizeof(_this->pidpath));
3730fbf3537Syasuoka 	fprintf(pidfp, "%u\n", _this->pid);
3740fbf3537Syasuoka 	fclose(pidfp);
3750fbf3537Syasuoka 	pidfp = NULL;
3760fbf3537Syasuoka #ifdef USE_NPPPD_ARP
3770fbf3537Syasuoka 	arp_set_strictintfnetwork(npppd_config_str_equali(_this, "arpd.strictintfnetwork", "true", ARPD_STRICTINTFNETWORK_DEFAULT));
3780fbf3537Syasuoka 	if (npppd_config_str_equali(_this, "arpd.enabled", "true", ARPD_DEFAULT) == 1)
3790fbf3537Syasuoka         	arp_sock_init();
3800fbf3537Syasuoka #endif
3810fbf3537Syasuoka 	return npppd_modules_reload(_this);
3820fbf3537Syasuoka }
3830fbf3537Syasuoka 
384f0a4e295Syasuoka /** start the npppd */
3850fbf3537Syasuoka void
3860fbf3537Syasuoka npppd_start(npppd *_this)
3870fbf3537Syasuoka {
3880fbf3537Syasuoka 	int rval = 0;
3890fbf3537Syasuoka 
3900fbf3537Syasuoka 	npppd_reset_timer(_this);
3910fbf3537Syasuoka 	while ((event_loop(EVLOOP_ONCE)) == 0) {
3920fbf3537Syasuoka 		if (_this->finalized != 0)
3930fbf3537Syasuoka 			break;
3940fbf3537Syasuoka 	}
3950fbf3537Syasuoka 	if (rval != 0)
3960fbf3537Syasuoka 		log_printf(LOG_CRIT, "event_loop() failed: %m");
3970fbf3537Syasuoka }
3980fbf3537Syasuoka 
399f0a4e295Syasuoka /** stop the npppd */
4000fbf3537Syasuoka void
4010fbf3537Syasuoka npppd_stop(npppd *_this)
4020fbf3537Syasuoka {
4030fbf3537Syasuoka 	int i;
4040fbf3537Syasuoka #ifdef	USE_NPPPD_L2TP
4050fbf3537Syasuoka 	l2tpd_stop(&_this->l2tpd);
4060fbf3537Syasuoka #endif
4070fbf3537Syasuoka #ifdef	USE_NPPPD_PPTP
4080fbf3537Syasuoka 	pptpd_stop(&_this->pptpd);
4090fbf3537Syasuoka #endif
4100fbf3537Syasuoka #ifdef	USE_NPPPD_PPPOE
4110fbf3537Syasuoka 	pppoed_stop(&_this->pppoed);
4120fbf3537Syasuoka #endif
4130fbf3537Syasuoka #ifdef	USE_NPPPD_NPPPD_CTL
4140fbf3537Syasuoka 	npppd_ctl_stop(&_this->ctl);
4150fbf3537Syasuoka #endif
4160fbf3537Syasuoka #ifdef USE_NPPPD_ARP
4170fbf3537Syasuoka         arp_sock_fini();
4180fbf3537Syasuoka #endif
4190fbf3537Syasuoka 	for (i = countof(_this->iface) - 1; i >= 0; i--) {
4200fbf3537Syasuoka 		if (_this->iface[i].initialized != 0)
4210fbf3537Syasuoka 			npppd_iface_stop(&_this->iface[i]);
4220fbf3537Syasuoka 	}
4230fbf3537Syasuoka 	npppd_set_radish(_this, NULL);
4240fbf3537Syasuoka 
4250fbf3537Syasuoka 	_this->finalizing = 1;
4260fbf3537Syasuoka 	npppd_reset_timer(_this);
4270fbf3537Syasuoka }
4280fbf3537Syasuoka 
4290fbf3537Syasuoka static void
4300fbf3537Syasuoka npppd_stop_really(npppd *_this)
4310fbf3537Syasuoka {
4320fbf3537Syasuoka 	int i;
4330fbf3537Syasuoka #if defined(USE_NPPPD_L2TP) || defined(USE_NPPPD_PPTP)
4340fbf3537Syasuoka 	int wait_again;
4350fbf3537Syasuoka 
4360fbf3537Syasuoka 	wait_again = 0;
4370fbf3537Syasuoka 
4380fbf3537Syasuoka #ifdef	USE_NPPPD_L2TP
4390fbf3537Syasuoka 	if (!l2tpd_is_stopped(&_this->l2tpd))
4400fbf3537Syasuoka 		wait_again |= 1;
4410fbf3537Syasuoka #endif
4420fbf3537Syasuoka #ifdef	USE_NPPPD_PPTP
4430fbf3537Syasuoka 	if (!pptpd_is_stopped(&_this->pptpd))
4440fbf3537Syasuoka 		wait_again |= 1;
4450fbf3537Syasuoka #endif
4460fbf3537Syasuoka 	if (wait_again != 0) {
4470fbf3537Syasuoka 		npppd_reset_timer(_this);
4480fbf3537Syasuoka 		return;
4490fbf3537Syasuoka 	}
4500fbf3537Syasuoka #endif
4510fbf3537Syasuoka 	for (i = countof(_this->iface) - 1; i >= 0; i--) {
4520fbf3537Syasuoka 		if (_this->iface[i].initialized != 0)
4530fbf3537Syasuoka 			npppd_iface_fini(&_this->iface[i]);
4540fbf3537Syasuoka 	}
4550fbf3537Syasuoka 	_this->finalized = 1;
4560fbf3537Syasuoka }
4570fbf3537Syasuoka 
458f0a4e295Syasuoka /** finalize the npppd */
4590fbf3537Syasuoka void
4600fbf3537Syasuoka npppd_fini(npppd *_this)
4610fbf3537Syasuoka {
4620fbf3537Syasuoka 	int i;
4630fbf3537Syasuoka 	npppd_auth_base *auth_base;
4640fbf3537Syasuoka 
4650fbf3537Syasuoka #ifdef USE_NPPPD_L2TP
4660fbf3537Syasuoka 	l2tpd_uninit(&_this->l2tpd);
4670fbf3537Syasuoka #endif
4680fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
4690fbf3537Syasuoka 	pptpd_uninit(&_this->pptpd);
4700fbf3537Syasuoka #endif
4710fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
4720fbf3537Syasuoka 	pppoed_uninit(&_this->pppoed);
4730fbf3537Syasuoka #endif
4740fbf3537Syasuoka 	for (slist_itr_first(&_this->realms);
4750fbf3537Syasuoka 	    slist_itr_has_next(&_this->realms);) {
4760fbf3537Syasuoka 		auth_base = slist_itr_next(&_this->realms);
4770fbf3537Syasuoka 		npppd_auth_destroy(auth_base);
4780fbf3537Syasuoka 	}
4790fbf3537Syasuoka 	for (i = countof(_this->iface) - 1; i >= 0; i--) {
4800fbf3537Syasuoka 		if (_this->iface[i].initialized != 0)
4810fbf3537Syasuoka 			npppd_iface_fini(&_this->iface[i]);
4820fbf3537Syasuoka 	}
4830fbf3537Syasuoka 	for (i = 0; i < countof(_this->iface_bind); i++)
4840fbf3537Syasuoka 		slist_fini(&_this->iface_bind[i].pools);
4850fbf3537Syasuoka 
4860fbf3537Syasuoka 	for (i = countof(_this->pool) - 1; i >= 0; i--) {
4870fbf3537Syasuoka 		if (_this->pool[i].initialized != 0)
4880fbf3537Syasuoka 			npppd_pool_uninit(&_this->pool[i]);
4890fbf3537Syasuoka 	}
4900fbf3537Syasuoka 
4910fbf3537Syasuoka 	signal_del(&_this->ev_sigterm);
4920fbf3537Syasuoka 	signal_del(&_this->ev_sigint);
4930fbf3537Syasuoka 	signal_del(&_this->ev_sighup);
4940fbf3537Syasuoka 
4950fbf3537Syasuoka 	if (_this->properties != NULL)
4960fbf3537Syasuoka 		properties_destroy(_this->properties);
4970fbf3537Syasuoka 
4980fbf3537Syasuoka 	slist_fini(&_this->realms);
4990fbf3537Syasuoka 
5000fbf3537Syasuoka 	if (_this->map_user_ppp != NULL)
5010fbf3537Syasuoka 		hash_free(_this->map_user_ppp);
5020fbf3537Syasuoka 
5030fbf3537Syasuoka 	rtev_fini();
5040fbf3537Syasuoka }
5050fbf3537Syasuoka 
5060fbf3537Syasuoka /***********************************************************************
507f0a4e295Syasuoka  * Timer related functions
5080fbf3537Syasuoka  ***********************************************************************/
5090fbf3537Syasuoka static void
5100fbf3537Syasuoka npppd_reset_timer(npppd *_this)
5110fbf3537Syasuoka {
5120fbf3537Syasuoka 	struct timeval tv;
5130fbf3537Syasuoka 
5140fbf3537Syasuoka 	if (_this->finalizing != 0) {
515f0a4e295Syasuoka 		/* we can use the timer exclusively on finalizing */
5160fbf3537Syasuoka 		tv.tv_usec = 500000;
5170fbf3537Syasuoka 		tv.tv_sec = 0;
5180fbf3537Syasuoka 		evtimer_add(&_this->ev_timer, &tv);
5190fbf3537Syasuoka 	} else {
5200fbf3537Syasuoka 		tv.tv_usec = 0;
5210fbf3537Syasuoka 		tv.tv_sec = NPPPD_TIMER_TICK_IVAL;
5220fbf3537Syasuoka 		evtimer_add(&_this->ev_timer, &tv);
5230fbf3537Syasuoka 	}
5240fbf3537Syasuoka }
5250fbf3537Syasuoka 
5260fbf3537Syasuoka static void
5270fbf3537Syasuoka npppd_timer(int fd, short evtype, void *ctx)
5280fbf3537Syasuoka {
5290fbf3537Syasuoka 	npppd *_this;
5300fbf3537Syasuoka 
5310fbf3537Syasuoka 	_this = ctx;
5320fbf3537Syasuoka 	if (_this->finalizing != 0) {
533f0a4e295Syasuoka 		npppd_stop_really(_this); /* The timer has been reset */
534f0a4e295Syasuoka 		return;	/* we can use the timer exclusively on finalizing */
5350fbf3537Syasuoka 	}
5360fbf3537Syasuoka 	_this->secs += NPPPD_TIMER_TICK_IVAL;
5370fbf3537Syasuoka 	if (_this->reloading_count > 0) {
5380fbf3537Syasuoka 		_this->reloading_count -= NPPPD_TIMER_TICK_IVAL;
5390fbf3537Syasuoka 		if (_this->reloading_count <= 0) {
5400fbf3537Syasuoka 			npppd_reload0(_this);
5410fbf3537Syasuoka 			_this->reloading_count = 0;
5420fbf3537Syasuoka 		}
5430fbf3537Syasuoka 	} else {
5440fbf3537Syasuoka 		if ((_this->secs % TIMER_TICK_RUP(
5450fbf3537Syasuoka 			    NPPPD_AUTH_REALM_FINALIZER_INTERVAL)) == 0)
5460fbf3537Syasuoka 			npppd_auth_finalizer_periodic(_this);
5470fbf3537Syasuoka 	}
5480fbf3537Syasuoka 
5490fbf3537Syasuoka 	if (_this->rtev_event_serial != rtev_get_event_serial()) {
5500fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
5510fbf3537Syasuoka 		if (pppoed_need_polling(&_this->pppoed))
5520fbf3537Syasuoka 			pppoed_reload_listeners(&_this->pppoed);
5530fbf3537Syasuoka #endif
5540fbf3537Syasuoka 	}
5550fbf3537Syasuoka 	_this->rtev_event_serial = rtev_get_event_serial();
5560fbf3537Syasuoka 
5570fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
5580fbf3537Syasuoka 	pipex_periodic(_this);
5590fbf3537Syasuoka #endif
5600fbf3537Syasuoka 
5610fbf3537Syasuoka 	npppd_reset_timer(_this);
5620fbf3537Syasuoka }
5630fbf3537Syasuoka 
5640fbf3537Syasuoka int
5650fbf3537Syasuoka npppd_reset_routing_table(npppd *_this, int pool_only)
5660fbf3537Syasuoka {
5670fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
5680fbf3537Syasuoka 	slist rtlist0;
5690fbf3537Syasuoka 
570cd8e09b9Sdlg 	if (_this->iface[0].using_pppx)
571cd8e09b9Sdlg 		return 0;
572cd8e09b9Sdlg 
5730fbf3537Syasuoka 	slist_init(&rtlist0);
5740fbf3537Syasuoka 	if (rd2slist(_this->rd, &rtlist0) != 0)
5750fbf3537Syasuoka 		return 1;
5760fbf3537Syasuoka 
5770fbf3537Syasuoka 	for (slist_itr_first(&rtlist0); slist_itr_has_next(&rtlist0); ) {
5780fbf3537Syasuoka 		struct radish *rd;
5790fbf3537Syasuoka 		struct sockaddr_npppd *snp;
5800fbf3537Syasuoka 		npppd_ppp *ppp;
5810fbf3537Syasuoka 		int is_first;
5820fbf3537Syasuoka 
5830fbf3537Syasuoka 		rd = slist_itr_next(&rtlist0);
5840fbf3537Syasuoka 		snp = rd->rd_rtent;
5850fbf3537Syasuoka 
5860fbf3537Syasuoka 		is_first = 1;
5870fbf3537Syasuoka 		for (snp = rd->rd_rtent; snp != NULL; snp = snp->snp_next) {
5880fbf3537Syasuoka 			switch (snp->snp_type) {
5890fbf3537Syasuoka 			case SNP_POOL:
5900fbf3537Syasuoka 			case SNP_DYN_POOL:
5910fbf3537Syasuoka 				if (is_first)
5920fbf3537Syasuoka 					in_route_add(&snp->snp_addr,
5930fbf3537Syasuoka 					    &snp->snp_mask, &loop,
5940fbf3537Syasuoka 					    LOOPBACK_IFNAME, RTF_BLACKHOLE, 0);
5950fbf3537Syasuoka 				break;
5960fbf3537Syasuoka 
5970fbf3537Syasuoka 			case SNP_PPP:
5980fbf3537Syasuoka 				if (pool_only)
5990fbf3537Syasuoka 					break;
6000fbf3537Syasuoka 				ppp = snp->snp_data_ptr;
6010fbf3537Syasuoka 				if (ppp->ppp_framed_ip_netmask.s_addr
6020fbf3537Syasuoka 				    == 0xffffffffL) {
6030fbf3537Syasuoka 					in_host_route_add(&ppp->
6040fbf3537Syasuoka 					    ppp_framed_ip_address,
6050fbf3537Syasuoka 					    &ppp_iface(ppp)->ip4addr,
6060fbf3537Syasuoka 					    ppp_iface(ppp)->ifname,
6070fbf3537Syasuoka 					    MRU_IPMTU(ppp->peer_mru));
6080fbf3537Syasuoka 				} else {
6090fbf3537Syasuoka 					in_route_add(&ppp->
6100fbf3537Syasuoka 					    ppp_framed_ip_address,
6110fbf3537Syasuoka 					    &ppp->ppp_framed_ip_netmask,
6120fbf3537Syasuoka 					    &ppp_iface(ppp)->ip4addr,
6130fbf3537Syasuoka 					    ppp_iface(ppp)->ifname, 0,
6140fbf3537Syasuoka 					    MRU_IPMTU(ppp->peer_mru));
6150fbf3537Syasuoka 				}
6160fbf3537Syasuoka 				break;
6170fbf3537Syasuoka 			}
6180fbf3537Syasuoka 			is_first = 0;
6190fbf3537Syasuoka 		}
6200fbf3537Syasuoka 
6210fbf3537Syasuoka 	}
6220fbf3537Syasuoka 
6230fbf3537Syasuoka 	slist_fini(&rtlist0);
6240fbf3537Syasuoka #endif
6250fbf3537Syasuoka 	return 0;
6260fbf3537Syasuoka }
6270fbf3537Syasuoka 
6280fbf3537Syasuoka /***********************************************************************
629f0a4e295Syasuoka  * Other npppd related functions.
6300fbf3537Syasuoka  ***********************************************************************/
6310fbf3537Syasuoka /**
632f0a4e295Syasuoka  * Get the user's password.  Return 0 on success.
6330fbf3537Syasuoka  *
634f0a4e295Syasuoka  * @param	username    Username who acquires password
635f0a4e295Syasuoka  * @param	password    A pointer to a buffer space to store the password.
636f0a4e295Syasuoka  *			    Use NULL when you need to know only the length of
637f0a4e295Syasuoka  *			    the password.
638f0a4e295Syasuoka  * @param	plpassword  A pointer to the length of the password parameter.
639f0a4e295Syasuoka  *			    This function uses this parameter value and stores
640f0a4e295Syasuoka  *			    the required length value pointed to by this
641f0a4e295Syasuoka  *			    parameter.  Use NULL when use don't need to know
642f0a4e295Syasuoka  *			    the password and its length.
643f0a4e295Syasuoka  * @return	If the function succeeds, 0 is returned.  The function returns
644f0a4e295Syasuoka  *		1 if the username is unknown, returns 2 if the password buffer
645f0a4e295Syasuoka  *		length is not enough.  It returns negative value for other
646f0a4e295Syasuoka  *		errors.
6470fbf3537Syasuoka  */
6480fbf3537Syasuoka int
6490fbf3537Syasuoka npppd_get_user_password(npppd *_this, npppd_ppp *ppp,
6500fbf3537Syasuoka     const char *username, char *password, int *plpassword)
6510fbf3537Syasuoka {
6520fbf3537Syasuoka 	char buf0[MAX_USERNAME_LENGTH];
6530fbf3537Syasuoka 
6540fbf3537Syasuoka 	NPPPD_ASSERT(ppp->realm != NULL);
6550fbf3537Syasuoka 	return npppd_auth_get_user_password(ppp->realm,
6560fbf3537Syasuoka 	    npppd_auth_username_for_auth(ppp->realm, username, buf0), password,
6570fbf3537Syasuoka 	    plpassword);
6580fbf3537Syasuoka }
6590fbf3537Syasuoka 
660f0a4e295Syasuoka /** Get the Framed-IP-Address attribute of the user */
6610fbf3537Syasuoka struct in_addr *
6620fbf3537Syasuoka npppd_get_user_framed_ip_address(npppd *_this, npppd_ppp *ppp,
6630fbf3537Syasuoka     const char *username)
6640fbf3537Syasuoka {
6650fbf3537Syasuoka 
6660fbf3537Syasuoka 	if (ppp->peer_auth == 0) {
6670fbf3537Syasuoka 		ppp->realm_framed_ip_address.s_addr = 0;
6680fbf3537Syasuoka 		goto do_default;
6690fbf3537Syasuoka 	}
6700fbf3537Syasuoka 	NPPPD_ASSERT(ppp->realm != NULL);
6710fbf3537Syasuoka 
6720fbf3537Syasuoka 	if (ppp->realm_framed_ip_address.s_addr != 0) {
6730fbf3537Syasuoka #if 1
6740fbf3537Syasuoka /*
675f0a4e295Syasuoka  * FIXME: This fix is ad hok, it overwrites the ip address here if assigning
676f0a4e295Syasuoka  * FIXME: IP address by RADIUS is prohibited.  This will make a bug when a
677f0a4e295Syasuoka  * FIXME: new authentication type is add.  Fix this until then.
6780fbf3537Syasuoka  */
6790fbf3537Syasuoka 		if ((ppp_ipcp(ppp)->ip_assign_flags & NPPPD_IP_ASSIGN_RADIUS)
6800fbf3537Syasuoka 		    == 0) {
6810fbf3537Syasuoka 			ppp->realm_framed_ip_netmask.s_addr = 0;
6820fbf3537Syasuoka 		} else
6830fbf3537Syasuoka #endif
6840fbf3537Syasuoka 		return &ppp->realm_framed_ip_address;
6850fbf3537Syasuoka 	}
6860fbf3537Syasuoka 
6870fbf3537Syasuoka 	ppp->realm_framed_ip_netmask.s_addr = 0xffffffffL;
6880fbf3537Syasuoka 	if ((ppp_ipcp(ppp)->ip_assign_flags & NPPPD_IP_ASSIGN_FIXED) != 0) {
689f0a4e295Syasuoka 		/* assign by the authentication realm */
6900fbf3537Syasuoka 		if (npppd_auth_get_framed_ip(ppp->realm, username,
6910fbf3537Syasuoka 		    &ppp->realm_framed_ip_address,
6920fbf3537Syasuoka 			    &ppp->realm_framed_ip_netmask) != 0)
6930fbf3537Syasuoka 			ppp->realm_framed_ip_address.s_addr = 0;
6940fbf3537Syasuoka 	}
6950fbf3537Syasuoka 
6960fbf3537Syasuoka do_default:
697f0a4e295Syasuoka 	/* Use USER_SELECT if the realm doesn't specify the ip address */
6980fbf3537Syasuoka 	if (ppp->realm_framed_ip_address.s_addr == 0)
6990fbf3537Syasuoka 		ppp->realm_framed_ip_address.s_addr = INADDR_USER_SELECT;
7000fbf3537Syasuoka 	if (ppp->realm_framed_ip_address.s_addr == INADDR_USER_SELECT) {
701f0a4e295Syasuoka 		/* Use NAS_SELECT if USER_SELECT is not allowed by the config */
7020fbf3537Syasuoka 		if ((ppp_ipcp(ppp)->ip_assign_flags &
7030fbf3537Syasuoka 		    NPPPD_IP_ASSIGN_USER_SELECT) == 0)
7040fbf3537Syasuoka 			ppp->realm_framed_ip_address.s_addr = INADDR_NAS_SELECT;
7050fbf3537Syasuoka 	}
7060fbf3537Syasuoka 	NPPPD_DBG((LOG_DEBUG, "%s() = %s", __func__,
7070fbf3537Syasuoka 	    inet_ntoa(ppp->realm_framed_ip_address)));
7080fbf3537Syasuoka 
7090fbf3537Syasuoka 	return &ppp->realm_framed_ip_address;
7100fbf3537Syasuoka }
7110fbf3537Syasuoka 
7120fbf3537Syasuoka /** XXX */
7130fbf3537Syasuoka int
7140fbf3537Syasuoka npppd_check_calling_number(npppd *_this, npppd_ppp *ppp)
7150fbf3537Syasuoka {
7160fbf3537Syasuoka 	int lnumber, rval, strict, loose;
7170fbf3537Syasuoka 	char number[NPPPD_PHONE_NUMBER_LEN + 1];
7180fbf3537Syasuoka 
7190fbf3537Syasuoka 	strict = ppp_config_str_equal(ppp, "check_callnum", "strict", 0);
7200fbf3537Syasuoka 	loose  = ppp_config_str_equal(ppp, "check_callnum", "loose", 0);
7210fbf3537Syasuoka 
7220fbf3537Syasuoka 	if (strict || loose) {
7230fbf3537Syasuoka 		lnumber = sizeof(number);
7240fbf3537Syasuoka 		if ((rval = npppd_auth_get_calling_number(ppp->realm,
7250fbf3537Syasuoka 		    ppp->username,
7260fbf3537Syasuoka 		    number, &lnumber)) == 0)
7270fbf3537Syasuoka 			return
7280fbf3537Syasuoka 			    (strcmp(number, ppp->calling_number) == 0)? 1 : 0;
7290fbf3537Syasuoka 		if (strict)
7300fbf3537Syasuoka 			return 0;
7310fbf3537Syasuoka 	}
7320fbf3537Syasuoka 
7330fbf3537Syasuoka 	return 1;
7340fbf3537Syasuoka }
7350fbf3537Syasuoka 
7360fbf3537Syasuoka /**
737f0a4e295Syasuoka  * This function finds a {@link npppd_ppp} instance that is assigned the
738f0a4e295Syasuoka  * specified ip address and returns it
739f0a4e295Syasuoka  * @param ipaddr	IP Address(Specify in network byte order)
7400fbf3537Syasuoka  */
7410fbf3537Syasuoka npppd_ppp *
7420fbf3537Syasuoka npppd_get_ppp_by_ip(npppd *_this, struct in_addr ipaddr)
7430fbf3537Syasuoka {
7440fbf3537Syasuoka 	struct sockaddr_npppd *snp;
7450fbf3537Syasuoka 	struct radish *rdp;
746f0a4e295Syasuoka 	struct sockaddr_in npppd_get_ppp_by_ip_sin4;
7470fbf3537Syasuoka 
748f0a4e295Syasuoka 	npppd_get_ppp_by_ip_sin4.sin_family = AF_INET;
749f0a4e295Syasuoka 	npppd_get_ppp_by_ip_sin4.sin_len = sizeof(struct sockaddr_in);
7500fbf3537Syasuoka 	npppd_get_ppp_by_ip_sin4.sin_addr = ipaddr;
7510fbf3537Syasuoka 	if (_this->rd == NULL)
752f0a4e295Syasuoka 		return NULL;	/* no radix tree on startup */
7530fbf3537Syasuoka 	if (rd_match((struct sockaddr *)&npppd_get_ppp_by_ip_sin4, _this->rd,
7540fbf3537Syasuoka 	    &rdp)) {
7550fbf3537Syasuoka 		snp = rdp->rd_rtent;
7560fbf3537Syasuoka 		if (snp->snp_type == SNP_PPP)
7570fbf3537Syasuoka 			return snp->snp_data_ptr;
7580fbf3537Syasuoka 	}
7590fbf3537Syasuoka 	return NULL;
7600fbf3537Syasuoka }
7610fbf3537Syasuoka 
7620fbf3537Syasuoka /**
763f0a4e295Syasuoka  * This function finds {@link npppd_ppp} instances that are authenticated
764f0a4e295Syasuoka  * as the specified username and returns them as a {@link slist} list.
765f0a4e295Syasuoka  * @param username	PPP Username.
766f0a4e295Syasuoka  * @return	{@link slist} that contans the {@link npppd_ppp} instances.
767f0a4e295Syasuoka  * NULL may be returned if no instance has been found.
7680fbf3537Syasuoka  */
7690fbf3537Syasuoka slist *
7700fbf3537Syasuoka npppd_get_ppp_by_user(npppd *_this, const char *username)
7710fbf3537Syasuoka {
7720fbf3537Syasuoka 	hash_link *hl;
7730fbf3537Syasuoka 
7740fbf3537Syasuoka 	if ((hl = hash_lookup(_this->map_user_ppp, username)) != NULL)
7750fbf3537Syasuoka 		return hl->item;
7760fbf3537Syasuoka 
7770fbf3537Syasuoka 	return NULL;
7780fbf3537Syasuoka }
7790fbf3537Syasuoka 
7800fbf3537Syasuoka /**
781f0a4e295Syasuoka  * This function finds a {@link npppd_ppp} instance that matches the specified
782f0a4e295Syasuoka  * ppp id and returns it.
783f0a4e295Syasuoka  * @param	id	{@link npppd_ppp#id ppp's id}
784f0a4e295Syasuoka  * @return	This function returns the pointer if the instance which has
785f0a4e295Syasuoka  *		specified ID is found, otherwise it returns NULL.
7860fbf3537Syasuoka  */
7870fbf3537Syasuoka npppd_ppp *
7880fbf3537Syasuoka npppd_get_ppp_by_id(npppd *_this, int ppp_id)
7890fbf3537Syasuoka {
7900fbf3537Syasuoka 	slist users;
7910fbf3537Syasuoka 	npppd_ppp *ppp0, *ppp;
7920fbf3537Syasuoka 
7930fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
7940fbf3537Syasuoka 
7950fbf3537Syasuoka 	ppp = NULL;
7960fbf3537Syasuoka 	slist_init(&users);
7970fbf3537Syasuoka 	if (npppd_get_all_users(_this, &users) != 0) {
7980fbf3537Syasuoka 		log_printf(LOG_WARNING,
7990fbf3537Syasuoka 		    "npppd_get_all_users() failed in %s()", __func__);
8000fbf3537Syasuoka 	} else {
801f0a4e295Syasuoka 		/* FIXME: This linear search eats CPU. */
8020fbf3537Syasuoka 		for (slist_itr_first(&users); slist_itr_has_next(&users); ) {
8030fbf3537Syasuoka 			ppp0 = slist_itr_next(&users);
8040fbf3537Syasuoka 			if (ppp0->id == ppp_id) {
8050fbf3537Syasuoka 				ppp = ppp0;
8060fbf3537Syasuoka 				break;
8070fbf3537Syasuoka 			}
8080fbf3537Syasuoka 		}
8090fbf3537Syasuoka 	}
8100fbf3537Syasuoka 	slist_fini(&users);
8110fbf3537Syasuoka 
8120fbf3537Syasuoka 	return ppp;
8130fbf3537Syasuoka }
8140fbf3537Syasuoka 
8150fbf3537Syasuoka /**
816f0a4e295Syasuoka  * Checks whether the user reaches the maximum session limit
817f0a4e295Syasuoka  * (user_max_serssion).
818f0a4e295Syasuoka  * @return	This function returns 1(true) if the user does not reach the
819f0a4e295Syasuoka  *		limit, otherwise it returns 0(false).
8200fbf3537Syasuoka  */
8210fbf3537Syasuoka int
8220fbf3537Syasuoka npppd_check_user_max_session(npppd *_this, npppd_ppp *ppp)
8230fbf3537Syasuoka {
8240fbf3537Syasuoka 	int count;
8250fbf3537Syasuoka 	npppd_ppp *ppp1;
8260fbf3537Syasuoka 	slist *uppp;
8270fbf3537Syasuoka 
828f0a4e295Syasuoka 	/* user_max_session == 0 means unlimit */
829f0a4e295Syasuoka 	if (ppp_iface(ppp)->user_max_session == 0)
8300fbf3537Syasuoka 		return 1;
8310fbf3537Syasuoka 
8320fbf3537Syasuoka 	count = 0;
8330fbf3537Syasuoka 	if ((uppp = npppd_get_ppp_by_user(_this, ppp->username)) != NULL) {
8340fbf3537Syasuoka 		for (slist_itr_first(uppp); slist_itr_has_next(uppp); ) {
8350fbf3537Syasuoka 			ppp1 = slist_itr_next(uppp);
8360fbf3537Syasuoka 			if (strcmp(ppp_iface(ppp)->ifname,
8370fbf3537Syasuoka 			    ppp_iface(ppp1)->ifname) == 0)
8380fbf3537Syasuoka 				count++;
8390fbf3537Syasuoka 		}
8400fbf3537Syasuoka 	}
8410fbf3537Syasuoka 
8420fbf3537Syasuoka 	return (count < ppp_iface(ppp)->user_max_session)? 1 : 0;
8430fbf3537Syasuoka }
8440fbf3537Syasuoka 
8450fbf3537Syasuoka /***********************************************************************
846f0a4e295Syasuoka  * Network I/O ralated functions.
8470fbf3537Syasuoka  ***********************************************************************/
8480fbf3537Syasuoka /**
849f0a4e295Syasuoka  * Call this function to output packets to the network(tun).  This function
850f0a4e295Syasuoka  * currently assumes the packet is a IPv4 datagram.
8510fbf3537Syasuoka  */
8520fbf3537Syasuoka void
8530fbf3537Syasuoka npppd_network_output(npppd *_this, npppd_ppp *ppp, int proto, u_char *pktp,
8540fbf3537Syasuoka     int lpktp)
8550fbf3537Syasuoka {
8560fbf3537Syasuoka 	struct ip *pip;
8570fbf3537Syasuoka 	int lbuf;
858f0a4e295Syasuoka 	u_char buf[256];	/* enough size for TCP/IP header */
8590fbf3537Syasuoka 
8600fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
8610fbf3537Syasuoka 
8620fbf3537Syasuoka 	if (!ppp_ip_assigned(ppp))
8630fbf3537Syasuoka 		return;
8640fbf3537Syasuoka 
8650fbf3537Syasuoka 	if (lpktp < sizeof(struct ip)) {
8660fbf3537Syasuoka 		ppp_log(ppp, LOG_DEBUG, "Received IP packet is too small");
8670fbf3537Syasuoka 		return;
8680fbf3537Syasuoka 	}
8690fbf3537Syasuoka 	lbuf = MIN(lpktp, sizeof(buf));
8700fbf3537Syasuoka 	if (!ALIGNED_POINTER(pktp, struct ip)) {
8710fbf3537Syasuoka 		memcpy(buf, pktp, lbuf);
8720fbf3537Syasuoka 		pip = (struct ip *)buf;
8730fbf3537Syasuoka 	} else {
8740fbf3537Syasuoka 		pip = (struct ip *)pktp;
8750fbf3537Syasuoka 	}
8760fbf3537Syasuoka 
8770fbf3537Syasuoka #ifndef	NO_INGRES_FILTER
8780fbf3537Syasuoka 	if ((pip->ip_src.s_addr & ppp->ppp_framed_ip_netmask.s_addr) !=
8790fbf3537Syasuoka 	    (ppp->ppp_framed_ip_address.s_addr &
8800fbf3537Syasuoka 		    ppp->ppp_framed_ip_netmask.s_addr)) {
8810fbf3537Syasuoka 		char logbuf[80];
8820fbf3537Syasuoka 		strlcpy(logbuf, inet_ntoa(pip->ip_dst), sizeof(logbuf));
8830fbf3537Syasuoka 		ppp_log(ppp, LOG_INFO,
8840fbf3537Syasuoka 		    "Drop packet by ingress filter.  %s => %s",
8850fbf3537Syasuoka 		    inet_ntoa(pip->ip_src), logbuf);
8860fbf3537Syasuoka 
8870fbf3537Syasuoka 		return;
8880fbf3537Syasuoka 	}
8890fbf3537Syasuoka #endif
8900fbf3537Syasuoka 	if (ppp->timeout_sec > 0 && !ip_is_idle_packet(pip, lbuf))
8910fbf3537Syasuoka 		ppp_reset_idle_timeout(ppp);
8920fbf3537Syasuoka 
8930fbf3537Syasuoka #ifndef NO_ADJUST_MSS
8940fbf3537Syasuoka 	if (ppp->adjust_mss) {
8950fbf3537Syasuoka 		if (lpktp == lbuf) {
8960fbf3537Syasuoka 			/*
897f0a4e295Syasuoka 			 * We can assume the packet length is less than
898f0a4e295Syasuoka 			 * sizeof(buf).
8990fbf3537Syasuoka 			 */
9000fbf3537Syasuoka 			if (!ALIGNED_POINTER(pktp, struct ip))
9010fbf3537Syasuoka 				pktp = buf;
9020fbf3537Syasuoka 			adjust_tcp_mss(pktp, lpktp, MRU_IPMTU(ppp->peer_mru));
9030fbf3537Syasuoka 		}
9040fbf3537Syasuoka 	}
9050fbf3537Syasuoka #endif
9060fbf3537Syasuoka 	npppd_iface_write(ppp_iface(ppp), proto, pktp, lpktp);
9070fbf3537Syasuoka }
9080fbf3537Syasuoka 
9090fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
910f0a4e295Syasuoka /***********************************************************************
911f0a4e295Syasuoka  * PIPEX related functions
912f0a4e295Syasuoka  ***********************************************************************/
9130fbf3537Syasuoka static void
9140fbf3537Syasuoka pipex_setup_common(npppd_ppp *ppp, struct pipex_session_req *req)
9150fbf3537Syasuoka {
9160fbf3537Syasuoka 	memset(req, 0, sizeof(*req));
9170fbf3537Syasuoka 	if (psm_opt_is_accepted(&ppp->lcp, acfc))
9180fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_ACFC_ENABLED;
9190fbf3537Syasuoka 	if (psm_peer_opt_is_accepted(&ppp->lcp, acfc))
9200fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_ACFC_ACCEPTED;
9210fbf3537Syasuoka 
9220fbf3537Syasuoka 	if (psm_peer_opt_is_accepted(&ppp->lcp, pfc))
9230fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_PFC_ACCEPTED;
9240fbf3537Syasuoka 	if (psm_opt_is_accepted(&ppp->lcp, pfc))
9250fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_PFC_ENABLED;
9260fbf3537Syasuoka 
9270fbf3537Syasuoka 	if (ppp->has_acf != 0)
9280fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_HAS_ACF;
9290fbf3537Syasuoka 
9300fbf3537Syasuoka 	if (ppp->adjust_mss != 0)
9310fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_ADJUST_TCPMSS;
9320fbf3537Syasuoka 
933cd8e09b9Sdlg 	req->pr_ip_srcaddr = ppp->pppd->iface[0].ip4addr;
9340fbf3537Syasuoka 	req->pr_ip_address = ppp->ppp_framed_ip_address;
9350fbf3537Syasuoka 	req->pr_ip_netmask = ppp->ppp_framed_ip_netmask;
9360fbf3537Syasuoka 	req->pr_peer_mru = ppp->peer_mru;
9370fbf3537Syasuoka 	req->pr_ppp_id = ppp->id;
9380fbf3537Syasuoka 
9390fbf3537Syasuoka 	req->pr_timeout_sec = ppp->timeout_sec;
9400fbf3537Syasuoka 
9410fbf3537Syasuoka #ifdef USE_NPPPD_MPPE
9420fbf3537Syasuoka 	req->pr_ccp_id = ppp->ccp.fsm.id;
9430fbf3537Syasuoka 	memcpy(req->pr_mppe_send.master_key,
9440fbf3537Syasuoka 	    ppp->mppe.send.master_key, sizeof(req->pr_mppe_send.master_key));
9450fbf3537Syasuoka 	req->pr_mppe_send.stateless = ppp->mppe.send.stateless;
9460fbf3537Syasuoka 	req->pr_mppe_send.keylenbits = ppp->mppe.send.keybits;
9470fbf3537Syasuoka 
9480fbf3537Syasuoka 	memcpy(req->pr_mppe_recv.master_key,
9490fbf3537Syasuoka 	    ppp->mppe.recv.master_key, sizeof(req->pr_mppe_recv.master_key));
9500fbf3537Syasuoka 	req->pr_mppe_recv.stateless = ppp->mppe.recv.stateless;
9510fbf3537Syasuoka 	req->pr_mppe_recv.keylenbits = ppp->mppe.recv.keybits;
9520fbf3537Syasuoka 
9530fbf3537Syasuoka 	if (ppp->mppe_started != 0) {
9540fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_MPPE_ACCEPTED;
9550fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_MPPE_ENABLED;
9560fbf3537Syasuoka 	}
9570fbf3537Syasuoka 	if (ppp->mppe.required)
9580fbf3537Syasuoka 		req->pr_ppp_flags |= PIPEX_PPP_MPPE_REQUIRED;
9590fbf3537Syasuoka #endif /* USE_NPPPD_MPPE */
9600fbf3537Syasuoka }
9610fbf3537Syasuoka 
962f0a4e295Syasuoka /** Enable PIPEX of the {@link npppd_ppp ppp} */
9630fbf3537Syasuoka int
9640fbf3537Syasuoka npppd_ppp_pipex_enable(npppd *_this, npppd_ppp *ppp)
9650fbf3537Syasuoka {
9660fbf3537Syasuoka 	struct pipex_session_req req;
9670fbf3537Syasuoka #ifdef	USE_NPPPD_PPPOE
9680fbf3537Syasuoka 	pppoe_session *pppoe;
9690fbf3537Syasuoka #endif
9700fbf3537Syasuoka #ifdef	USE_NPPPD_PPTP
9710fbf3537Syasuoka 	pptp_call *call;
9720fbf3537Syasuoka #endif
973886d2b78Syasuoka #ifdef	USE_NPPPD_L2TP
974886d2b78Syasuoka 	l2tp_call *l2tp;
975886d2b78Syasuoka 	l2tp_ctrl *l2tpctrl;
976886d2b78Syasuoka #endif
9770fbf3537Syasuoka 	int error;
9780fbf3537Syasuoka 
9790fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
9800fbf3537Syasuoka 	NPPPD_ASSERT(ppp->phy_context != NULL);
9810fbf3537Syasuoka 	NPPPD_ASSERT(ppp->use_pipex != 0);
9820fbf3537Syasuoka 
9830fbf3537Syasuoka 	pipex_setup_common(ppp, &req);
9840fbf3537Syasuoka 
9850fbf3537Syasuoka 	switch (ppp->tunnel_type) {
9860fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
9870fbf3537Syasuoka 	case PPP_TUNNEL_PPPOE:
988886d2b78Syasuoka 	    {
989886d2b78Syasuoka 		struct sockaddr *sa;
990886d2b78Syasuoka 		struct ether_header *eh;
9910fbf3537Syasuoka 		pppoe = (pppoe_session *)ppp->phy_context;
9920fbf3537Syasuoka 
993f0a4e295Syasuoka 		/* PPPoE specific informations */
9940fbf3537Syasuoka 		req.pr_protocol = PIPEX_PROTO_PPPOE;
9950fbf3537Syasuoka 		req.pr_session_id = pppoe->session_id;
9960fbf3537Syasuoka 		req.pr_peer_session_id = 0;
9970fbf3537Syasuoka 		strlcpy(req.pr_proto.pppoe.over_ifname,
9980fbf3537Syasuoka 		    pppoe_session_listen_ifname(pppoe),
9990fbf3537Syasuoka 		    sizeof(req.pr_proto.pppoe.over_ifname));
1000886d2b78Syasuoka 
1001886d2b78Syasuoka 		sa = (struct sockaddr *)&req.peer_address;
1002886d2b78Syasuoka 		sa->sa_family = AF_UNSPEC;
1003886d2b78Syasuoka 		sa->sa_len = sizeof(struct sockaddr);
1004886d2b78Syasuoka 
1005886d2b78Syasuoka 		eh = (struct ether_header *)sa->sa_data;
1006886d2b78Syasuoka 		eh->ether_type = htons(ETHERTYPE_PPPOE);
1007886d2b78Syasuoka 		memcpy(eh->ether_dhost, pppoe->ether_addr, ETHER_ADDR_LEN);
1008886d2b78Syasuoka 		memset(eh->ether_shost, 0, ETHER_ADDR_LEN);
10090fbf3537Syasuoka 
10100fbf3537Syasuoka 		break;
1011886d2b78Syasuoka 	    }
10120fbf3537Syasuoka #endif
10130fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
10140fbf3537Syasuoka 	case PPP_TUNNEL_PPTP:
10150fbf3537Syasuoka 		call = (pptp_call *)ppp->phy_context;
10160fbf3537Syasuoka 
1017f0a4e295Syasuoka 		/* PPTP specific informations */
10180fbf3537Syasuoka 		req.pr_session_id = call->id;
10190fbf3537Syasuoka 		req.pr_protocol = PIPEX_PROTO_PPTP;
10200fbf3537Syasuoka 
10210fbf3537Syasuoka 		req.pr_peer_session_id = call->peers_call_id;
10220fbf3537Syasuoka 		req.pr_proto.pptp.snd_nxt = call->snd_nxt;
10230fbf3537Syasuoka 		req.pr_proto.pptp.snd_una = call->snd_una;
10240fbf3537Syasuoka 		req.pr_proto.pptp.rcv_nxt = call->rcv_nxt;
10250fbf3537Syasuoka 		req.pr_proto.pptp.rcv_acked = call->rcv_acked;
10260fbf3537Syasuoka 		req.pr_proto.pptp.winsz = call->winsz;
10270fbf3537Syasuoka 		req.pr_proto.pptp.maxwinsz = call->maxwinsz;
10280fbf3537Syasuoka 		req.pr_proto.pptp.peer_maxwinsz = call->peers_maxwinsz;
10290fbf3537Syasuoka 
10300fbf3537Syasuoka 		NPPPD_ASSERT(call->ctrl->peer.ss_family == AF_INET);
10310fbf3537Syasuoka 		NPPPD_ASSERT(call->ctrl->our.ss_family == AF_INET);
1032886d2b78Syasuoka 
1033886d2b78Syasuoka 		memcpy(&req.peer_address, &call->ctrl->peer,
1034886d2b78Syasuoka 		    call->ctrl->peer.ss_len);
1035886d2b78Syasuoka 		memcpy(&req.local_address, &call->ctrl->our,
1036886d2b78Syasuoka 		    call->ctrl->our.ss_len);
1037886d2b78Syasuoka 		break;
1038886d2b78Syasuoka #endif
1039886d2b78Syasuoka #ifdef USE_NPPPD_L2TP
1040886d2b78Syasuoka 	case PPP_TUNNEL_L2TP:
1041886d2b78Syasuoka 		l2tp = (l2tp_call *)ppp->phy_context;
1042886d2b78Syasuoka 		l2tpctrl = l2tp->ctrl;
1043886d2b78Syasuoka 
1044886d2b78Syasuoka 		/* L2TPv2 specific context */
1045886d2b78Syasuoka 		/* Session KEYS */
1046886d2b78Syasuoka 		req.pr_protocol = PIPEX_PROTO_L2TP;
1047886d2b78Syasuoka 		req.pr_proto.l2tp.tunnel_id = l2tpctrl->tunnel_id;
1048886d2b78Syasuoka 		req.pr_proto.l2tp.peer_tunnel_id = l2tpctrl->peer_tunnel_id;
1049886d2b78Syasuoka 		req.pr_session_id = l2tp->session_id;
1050886d2b78Syasuoka 		req.pr_peer_session_id = l2tp->peer_session_id;
1051886d2b78Syasuoka 
1052886d2b78Syasuoka 		/* options: XXX: needs other? */
1053886d2b78Syasuoka 		if (l2tpctrl->data_use_seq)
1054886d2b78Syasuoka 			req.pr_proto.l2tp.option_flags |=
1055886d2b78Syasuoka 			    PIPEX_L2TP_USE_SEQUENCING;
1056886d2b78Syasuoka 
1057886d2b78Syasuoka 		/* transmission control contexts */
1058886d2b78Syasuoka 		req.pr_proto.l2tp.ns_nxt = l2tp->snd_nxt;
1059886d2b78Syasuoka 		req.pr_proto.l2tp.nr_nxt = l2tp->rcv_nxt;
1060886d2b78Syasuoka 
1061886d2b78Syasuoka 		NPPPD_ASSERT(l2tpctrl->peer.ss_family == AF_INET);
1062886d2b78Syasuoka 
1063886d2b78Syasuoka 		memcpy(&req.peer_address, &l2tpctrl->peer,
1064886d2b78Syasuoka 		    l2tpctrl->peer.ss_len);
1065886d2b78Syasuoka 		memcpy(&req.local_address, &l2tpctrl->sock,
1066886d2b78Syasuoka 		    l2tpctrl->sock.ss_len);
1067886d2b78Syasuoka #ifdef	IP_IPSEC_SA_COOKIE
1068886d2b78Syasuoka 		if (l2tpctrl->sa_cookie != NULL)
1069886d2b78Syasuoka 			req.pr_proto.l2tp.ipsec_sa_cookie =
1070886d2b78Syasuoka 			    *(struct in_ipsec_sa_cookie *)l2tpctrl->sa_cookie;
1071886d2b78Syasuoka #endif
10720fbf3537Syasuoka 		break;
10730fbf3537Syasuoka #endif
10740fbf3537Syasuoka 	default:
10750fbf3537Syasuoka 		return 1;
10760fbf3537Syasuoka 	}
10770fbf3537Syasuoka 
10780fbf3537Syasuoka 	if ((error = ioctl(_this->iface[ppp->ifidx].devf, PIPEXASESSION, &req))
10790fbf3537Syasuoka 	    != 0) {
10800fbf3537Syasuoka 		if (errno == ENXIO)	/* pipex is disabled on runtime */
10810fbf3537Syasuoka 			error = 0;
10820fbf3537Syasuoka 		ppp->pipex_enabled = 0;
10830fbf3537Syasuoka 		return error;
10840fbf3537Syasuoka 	}
10850fbf3537Syasuoka 
1086cd8e09b9Sdlg 	if (_this->iface[ppp->ifidx].using_pppx) {
1087cd8e09b9Sdlg 		struct pipex_session_descr_req descr_req;
1088cd8e09b9Sdlg 
1089cd8e09b9Sdlg 		descr_req.pdr_protocol = req.pr_protocol;
1090cd8e09b9Sdlg 		descr_req.pdr_session_id = req.pr_session_id;
1091cd8e09b9Sdlg 		memset(descr_req.pdr_descr, 0, sizeof(descr_req.pdr_descr));
1092cd8e09b9Sdlg 		strlcpy(descr_req.pdr_descr, ppp->username, sizeof(descr_req.pdr_descr));
1093cd8e09b9Sdlg 		error = ioctl(_this->iface[ppp->ifidx].devf, PIPEXSIFDESCR, &descr_req);
1094cd8e09b9Sdlg 		if (error != 0) {
1095cd8e09b9Sdlg 			log_printf(LOG_WARNING, "PIPEXSIFDESCR(%s) failed: %d\n", ppp->username, error);
1096cd8e09b9Sdlg 		}
1097cd8e09b9Sdlg 	}
1098cd8e09b9Sdlg 
10990fbf3537Syasuoka 	ppp->pipex_enabled = 1;
11000fbf3537Syasuoka 	if (ppp->timeout_sec > 0) {
1101f0a4e295Syasuoka 		/* Stop the npppd's idle-timer.  We use pipex's idle-timer */
11020fbf3537Syasuoka 		ppp->timeout_sec = 0;
11030fbf3537Syasuoka 		ppp_reset_idle_timeout(ppp);
11040fbf3537Syasuoka 	}
11050fbf3537Syasuoka 
11060fbf3537Syasuoka 	return error;
11070fbf3537Syasuoka }
11080fbf3537Syasuoka 
1109f0a4e295Syasuoka /** Disable PIPEX of the {@link npppd_ppp ppp} */
11100fbf3537Syasuoka int
11110fbf3537Syasuoka npppd_ppp_pipex_disable(npppd *_this, npppd_ppp *ppp)
11120fbf3537Syasuoka {
11130fbf3537Syasuoka 	struct pipex_session_close_req req;
11140fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
11150fbf3537Syasuoka 	pppoe_session *pppoe;
11160fbf3537Syasuoka #endif
11170fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
11180fbf3537Syasuoka 	pptp_call *call;
11190fbf3537Syasuoka #endif
1120886d2b78Syasuoka #ifdef USE_NPPPD_L2TP
1121886d2b78Syasuoka 	l2tp_call *l2tp;
1122886d2b78Syasuoka #endif
11230fbf3537Syasuoka 	int error;
11240fbf3537Syasuoka 
11250fbf3537Syasuoka 	if (ppp->pipex_started == 0)
11260fbf3537Syasuoka 		return 0;	/* not started */
11270fbf3537Syasuoka 
11280fbf3537Syasuoka 	bzero(&req, sizeof(req));
11290fbf3537Syasuoka 	switch(ppp->tunnel_type) {
11300fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
11310fbf3537Syasuoka 	case PPP_TUNNEL_PPPOE:
11320fbf3537Syasuoka 		pppoe = (pppoe_session *)ppp->phy_context;
11330fbf3537Syasuoka 
1134f0a4e295Syasuoka 		/* PPPoE specific informations */
11350fbf3537Syasuoka 		req.pcr_protocol = PIPEX_PROTO_PPPOE;
11360fbf3537Syasuoka 		req.pcr_session_id = pppoe->session_id;
11370fbf3537Syasuoka 		break;
11380fbf3537Syasuoka #endif
11390fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
11400fbf3537Syasuoka 	case PPP_TUNNEL_PPTP:
11410fbf3537Syasuoka 		call = (pptp_call *)ppp->phy_context;
11420fbf3537Syasuoka 
1143f0a4e295Syasuoka 		/* PPTP specific informations */
11440fbf3537Syasuoka 		req.pcr_session_id = call->id;
11450fbf3537Syasuoka 		req.pcr_protocol = PIPEX_PROTO_PPTP;
11460fbf3537Syasuoka 		break;
11470fbf3537Syasuoka #endif
1148*fd218b06Smarkus #ifdef USE_NPPPD_L2TP
1149*fd218b06Smarkus 	case PPP_TUNNEL_L2TP:
1150*fd218b06Smarkus 		l2tp = (l2tp_call *)ppp->phy_context;
1151*fd218b06Smarkus 
1152*fd218b06Smarkus 		/* L2TP specific context */
1153*fd218b06Smarkus 		req.pcr_session_id = l2tp->session_id;
1154*fd218b06Smarkus 		req.pcr_protocol = PIPEX_PROTO_L2TP;
1155*fd218b06Smarkus 		break;
1156*fd218b06Smarkus #endif
11570fbf3537Syasuoka 	default:
11580fbf3537Syasuoka 		return 1;
11590fbf3537Syasuoka 	}
11600fbf3537Syasuoka 
11610fbf3537Syasuoka 	error = ioctl(_this->iface[ppp->ifidx].devf, PIPEXDSESSION, &req);
11620fbf3537Syasuoka 	if (error == 0) {
11630fbf3537Syasuoka 		ppp->ipackets += req.pcr_stat.ipackets;
11640fbf3537Syasuoka 		ppp->opackets += req.pcr_stat.opackets;
11650fbf3537Syasuoka 		ppp->ierrors += req.pcr_stat.ierrors;
11660fbf3537Syasuoka 		ppp->oerrors += req.pcr_stat.oerrors;
11670fbf3537Syasuoka 		ppp->ibytes += req.pcr_stat.ibytes;
11680fbf3537Syasuoka 		ppp->obytes += req.pcr_stat.obytes;
11690fbf3537Syasuoka 		ppp->pipex_enabled = 0;
11700fbf3537Syasuoka 	}
11710fbf3537Syasuoka 
11720fbf3537Syasuoka 	return error;
11730fbf3537Syasuoka }
11740fbf3537Syasuoka 
1175f0a4e295Syasuoka /* XXX: s/npppd_ppp_pipex_ip_disable/npppd_ppp_pipex_stop/ ?? */
1176f0a4e295Syasuoka 
1177f0a4e295Syasuoka /** Stop PIPEX of the {@link npppd_ppp ppp} */
11780fbf3537Syasuoka static int
11790fbf3537Syasuoka npppd_ppp_pipex_ip_disable(npppd *_this, npppd_ppp *ppp)
11800fbf3537Syasuoka {
11810fbf3537Syasuoka 	struct pipex_session_config_req req;
11820fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
11830fbf3537Syasuoka 	pppoe_session *pppoe;
11840fbf3537Syasuoka #endif
11850fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
11860fbf3537Syasuoka 	pptp_call *call;
11870fbf3537Syasuoka #endif
1188886d2b78Syasuoka #ifdef USE_NPPPD_L2TP
1189886d2b78Syasuoka 	l2tp_call *l2tp;
1190886d2b78Syasuoka #endif
11910fbf3537Syasuoka 	if (ppp->pipex_started == 0)
11920fbf3537Syasuoka 		return 0;	/* not started */
11930fbf3537Syasuoka 
11940fbf3537Syasuoka 	bzero(&req, sizeof(req));
11950fbf3537Syasuoka 	switch(ppp->tunnel_type) {
11960fbf3537Syasuoka #ifdef USE_NPPPD_PPPOE
11970fbf3537Syasuoka 	case PPP_TUNNEL_PPPOE:
11980fbf3537Syasuoka 		pppoe = (pppoe_session *)ppp->phy_context;
11990fbf3537Syasuoka 
1200f0a4e295Syasuoka 		/* PPPoE specific informations */
12010fbf3537Syasuoka 		req.pcr_protocol = PIPEX_PROTO_PPPOE;
12020fbf3537Syasuoka 		req.pcr_session_id = pppoe->session_id;
12030fbf3537Syasuoka 		break;
12040fbf3537Syasuoka #endif
12050fbf3537Syasuoka #ifdef USE_NPPPD_PPTP
12060fbf3537Syasuoka 	case PPP_TUNNEL_PPTP:
12070fbf3537Syasuoka 		call = (pptp_call *)ppp->phy_context;
12080fbf3537Syasuoka 
1209f0a4e295Syasuoka 		/* PPTP specific informations */
12100fbf3537Syasuoka 		req.pcr_session_id = call->id;
12110fbf3537Syasuoka 		req.pcr_protocol = PIPEX_PROTO_PPTP;
12120fbf3537Syasuoka 		break;
12130fbf3537Syasuoka #endif
1214886d2b78Syasuoka #ifdef USE_NPPPD_L2TP
1215886d2b78Syasuoka 	case PPP_TUNNEL_L2TP:
1216886d2b78Syasuoka 		l2tp = (l2tp_call *)ppp->phy_context;
1217886d2b78Syasuoka 
1218886d2b78Syasuoka 		/* L2TP specific context */
1219886d2b78Syasuoka 		req.pcr_session_id = l2tp->session_id;
1220886d2b78Syasuoka 		req.pcr_protocol = PIPEX_PROTO_L2TP;
1221886d2b78Syasuoka 		break;
1222886d2b78Syasuoka #endif
12230fbf3537Syasuoka 	default:
12240fbf3537Syasuoka 		return 1;
12250fbf3537Syasuoka 	}
12260fbf3537Syasuoka 	req.pcr_ip_forward = 0;
12270fbf3537Syasuoka 
12280fbf3537Syasuoka 	return ioctl(_this->iface[ppp->ifidx].devf, PIPEXCSESSION, &req);
12290fbf3537Syasuoka }
12300fbf3537Syasuoka 
12310fbf3537Syasuoka static void
12320fbf3537Syasuoka pipex_periodic(npppd *_this)
12330fbf3537Syasuoka {
12340fbf3537Syasuoka 	struct pipex_session_list_req req;
12350fbf3537Syasuoka 	npppd_ppp *ppp;
12360fbf3537Syasuoka 	int i, error, ppp_id;
12370fbf3537Syasuoka 	slist dlist, users;
12380fbf3537Syasuoka 
12390fbf3537Syasuoka 	slist_init(&dlist);
12400fbf3537Syasuoka 	slist_init(&users);
12410fbf3537Syasuoka 	do {
12420fbf3537Syasuoka 		error = ioctl(_this->iface[0].devf, PIPEXGCLOSED, &req);
12430fbf3537Syasuoka 		if (error) {
12440fbf3537Syasuoka 			if (errno != ENXIO)
12450fbf3537Syasuoka 				log_printf(LOG_WARNING,
12460fbf3537Syasuoka 				    "PIPEXGCLOSED failed: %m");
12470fbf3537Syasuoka 			break;
12480fbf3537Syasuoka 		}
12490fbf3537Syasuoka 		for (i = 0; i < req.plr_ppp_id_count; i++) {
12500fbf3537Syasuoka 			ppp_id = req.plr_ppp_id[i];
12510fbf3537Syasuoka 			slist_add(&dlist, (void *)ppp_id);
12520fbf3537Syasuoka 		}
12530fbf3537Syasuoka 	} while (req.plr_flags & PIPEX_LISTREQ_MORE);
12540fbf3537Syasuoka 
12550fbf3537Syasuoka 	if (slist_length(&dlist) <= 0)
12560fbf3537Syasuoka 		goto pipex_done;
12570fbf3537Syasuoka 	if (npppd_get_all_users(_this, &users) != 0) {
12580fbf3537Syasuoka 		log_printf(LOG_WARNING,
12590fbf3537Syasuoka 		    "npppd_get_all_users() failed in %s()", __func__);
12600fbf3537Syasuoka 		slist_fini(&users);
12610fbf3537Syasuoka 		goto pipex_done;
12620fbf3537Syasuoka 	}
12630fbf3537Syasuoka 
1264f0a4e295Syasuoka 	/* Disconnect request */
12650fbf3537Syasuoka 	slist_itr_first(&dlist);
12660fbf3537Syasuoka 	while (slist_itr_has_next(&dlist)) {
1267f0a4e295Syasuoka 		/* FIXME: Linear search by PPP Id eats CPU */
12680fbf3537Syasuoka 		ppp_id = (int)slist_itr_next(&dlist);
12690fbf3537Syasuoka 		slist_itr_first(&users);
12700fbf3537Syasuoka 		ppp = NULL;
12710fbf3537Syasuoka 		while (slist_itr_has_next(&users)) {
12720fbf3537Syasuoka 			ppp =  slist_itr_next(&users);
12730fbf3537Syasuoka 			if (ppp_id == ppp->id) {
12740fbf3537Syasuoka 				/* found */
12750fbf3537Syasuoka 				slist_itr_remove(&users);
12760fbf3537Syasuoka 				break;
12770fbf3537Syasuoka 			}
12780fbf3537Syasuoka 			ppp = NULL;
12790fbf3537Syasuoka 		}
12800fbf3537Syasuoka 		if (ppp == NULL) {
12810fbf3537Syasuoka 			log_printf(LOG_WARNING,
12820fbf3537Syasuoka 			    "kernel requested a ppp down, but it's not found.  "
12830fbf3537Syasuoka 			    "ppp=%d", ppp_id);
12840fbf3537Syasuoka 			continue;
12850fbf3537Syasuoka 		}
12860fbf3537Syasuoka 		ppp_log(ppp, LOG_INFO, "Stop requested by the kernel");
12870fbf3537Syasuoka 		ppp_stop(ppp, NULL);
12880fbf3537Syasuoka 	}
12890fbf3537Syasuoka pipex_done:
12900fbf3537Syasuoka 	slist_fini(&users);
12910fbf3537Syasuoka 	slist_fini(&dlist);
12920fbf3537Syasuoka }
12930fbf3537Syasuoka #endif /* USE_NPPPD_PIPEX */
12940fbf3537Syasuoka 
12950fbf3537Syasuoka /***********************************************************************
1296f0a4e295Syasuoka  * IP address assignment related functions
12970fbf3537Syasuoka  ***********************************************************************/
1298f0a4e295Syasuoka /** Prepare to use IP */
12990fbf3537Syasuoka int
13000fbf3537Syasuoka npppd_prepare_ip(npppd *_this, npppd_ppp *ppp)
13010fbf3537Syasuoka {
13020fbf3537Syasuoka 	if (ppp_ipcp(ppp) == NULL)
13030fbf3537Syasuoka 		return 1;
13040fbf3537Syasuoka 
13050fbf3537Syasuoka 	npppd_get_user_framed_ip_address(_this, ppp, ppp->username);
13060fbf3537Syasuoka 
13070fbf3537Syasuoka 	if (npppd_iface_ip_is_ready(ppp_iface(ppp)))
13080fbf3537Syasuoka 		ppp->ipcp.ip4_our = ppp_iface(ppp)->ip4addr;
13090fbf3537Syasuoka 	else if (npppd_iface_ip_is_ready(&_this->iface[0]))
13100fbf3537Syasuoka 		ppp->ipcp.ip4_our = _this->iface[0].ip4addr;
13110fbf3537Syasuoka 	else
13120fbf3537Syasuoka 		return -1;
13130fbf3537Syasuoka 	if (ppp_ipcp(ppp)->dns_use_tunnel_end != 0) {
13140fbf3537Syasuoka 		ppp->ipcp.dns_pri = ppp->ipcp.ip4_our;
13150fbf3537Syasuoka 		ppp->ipcp.dns_sec.s_addr = INADDR_NONE;
13160fbf3537Syasuoka 	} else {
13170fbf3537Syasuoka 		ppp->ipcp.dns_pri = ppp_ipcp(ppp)->dns_pri;
13180fbf3537Syasuoka 		ppp->ipcp.dns_sec = ppp_ipcp(ppp)->dns_sec;
13190fbf3537Syasuoka 	}
13200fbf3537Syasuoka 	ppp->ipcp.nbns_pri = ppp_ipcp(ppp)->nbns_pri;
13210fbf3537Syasuoka 	ppp->ipcp.nbns_sec = ppp_ipcp(ppp)->nbns_sec;
13220fbf3537Syasuoka 
13230fbf3537Syasuoka 	return 0;
13240fbf3537Syasuoka }
13250fbf3537Syasuoka 
1326f0a4e295Syasuoka /** Notify stop using IP to npppd and release the resources. */
13270fbf3537Syasuoka void
13280fbf3537Syasuoka npppd_release_ip(npppd *_this, npppd_ppp *ppp)
13290fbf3537Syasuoka {
13300fbf3537Syasuoka 
13310fbf3537Syasuoka 	if (!ppp_ip_assigned(ppp))
13320fbf3537Syasuoka 		return;
13330fbf3537Syasuoka 
13340fbf3537Syasuoka 	npppd_set_ip_enabled(_this, ppp, 0);
13350fbf3537Syasuoka 	npppd_pool_release_ip(ppp->assigned_pool, ppp);
13360fbf3537Syasuoka 	ppp->assigned_pool = NULL;
13370fbf3537Syasuoka 	ppp->ppp_framed_ip_address.s_addr = 0;
13380fbf3537Syasuoka }
13390fbf3537Syasuoka 
1340f0a4e295Syasuoka /**
1341f0a4e295Syasuoka  * Change IP enableness.  When the enableness is change, npppd will operate
1342f0a4e295Syasuoka  * the route entry.
1343f0a4e295Syasuoka  */
13440fbf3537Syasuoka void
13450fbf3537Syasuoka npppd_set_ip_enabled(npppd *_this, npppd_ppp *ppp, int enabled)
13460fbf3537Syasuoka {
13470fbf3537Syasuoka 	int was_enabled, found;
13480fbf3537Syasuoka 	slist *u;
13490fbf3537Syasuoka 	hash_link *hl;
13500fbf3537Syasuoka 	npppd_ppp *ppp1;
13510fbf3537Syasuoka 
13520fbf3537Syasuoka 	NPPPD_ASSERT(ppp_ip_assigned(ppp));
13530fbf3537Syasuoka 	NPPPD_DBG((LOG_DEBUG,
13540fbf3537Syasuoka 	    "npppd_set_ip_enabled(%s/%s, %s)", ppp->username,
13550fbf3537Syasuoka 		inet_ntoa(ppp->ppp_framed_ip_address),
13560fbf3537Syasuoka 		(enabled)?"true" : "false"));
1357f0a4e295Syasuoka 
13580fbf3537Syasuoka 	/*
1359f0a4e295Syasuoka 	 * Don't do anything if the enableness is not change.  Changing route
1360f0a4e295Syasuoka 	 * makes many programs will wake up and do heavy operations, it causes
1361f0a4e295Syasuoka 	 * system overload, so we refrain useless changing route.
13620fbf3537Syasuoka 	 */
13630fbf3537Syasuoka 	enabled = (enabled)? 1 : 0;
13640fbf3537Syasuoka 	was_enabled = (ppp->assigned_ip4_enabled != 0)? 1 : 0;
13650fbf3537Syasuoka 	if (enabled == was_enabled)
13660fbf3537Syasuoka 		return;
1367f0a4e295Syasuoka 
13680fbf3537Syasuoka 	ppp->assigned_ip4_enabled = enabled;
13690fbf3537Syasuoka 	if (enabled) {
13700fbf3537Syasuoka 		if (ppp->username[0] != '\0') {
13710fbf3537Syasuoka 			if ((u = npppd_get_ppp_by_user(_this, ppp->username))
13720fbf3537Syasuoka 			    == NULL) {
13730fbf3537Syasuoka 				if ((u = malloc(sizeof(slist))) == NULL) {
13740fbf3537Syasuoka 					ppp_log(ppp, LOG_ERR,
13750fbf3537Syasuoka 					    "Out of memory on %s: %m",
13760fbf3537Syasuoka 					    __func__);
13770fbf3537Syasuoka 				} else {
13780fbf3537Syasuoka 					slist_init(u);
13790fbf3537Syasuoka 					slist_set_size(u, 4);
13800fbf3537Syasuoka 					hash_insert(_this->map_user_ppp,
13810fbf3537Syasuoka 					    ppp->username, u);
13820fbf3537Syasuoka 					NPPPD_DBG((LOG_DEBUG,
13830fbf3537Syasuoka 					    "hash_insert(user->ppp, %s)",
13840fbf3537Syasuoka 					    ppp->username));
13850fbf3537Syasuoka 				}
13860fbf3537Syasuoka 			}
1387f0a4e295Syasuoka 			if (u != NULL)	/* above malloc() may failed */
13880fbf3537Syasuoka 				slist_add(u, ppp);
13890fbf3537Syasuoka 		}
13900fbf3537Syasuoka 
13910fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
1392cd8e09b9Sdlg 		if (_this->iface[ppp->ifidx].using_pppx == 0) {
13930fbf3537Syasuoka 			if (ppp->snp.snp_next != NULL)
1394f0a4e295Syasuoka 				/*
1395f0a4e295Syasuoka 				 * There is a blackhole route that has same
1396f0a4e295Syasuoka 				 * address/mask.
1397f0a4e295Syasuoka 				 */
13980fbf3537Syasuoka 				in_route_delete(&ppp->ppp_framed_ip_address,
1399cd8e09b9Sdlg 				    &ppp->ppp_framed_ip_netmask, &loop,
1400cd8e09b9Sdlg 				    RTF_BLACKHOLE);
14010fbf3537Syasuoka 			/* See the comment for MRU_IPMTU() on ppp.h */
14020fbf3537Syasuoka 			if (ppp->ppp_framed_ip_netmask.s_addr == 0xffffffffL) {
14030fbf3537Syasuoka 				in_host_route_add(&ppp->ppp_framed_ip_address,
1404cd8e09b9Sdlg 				    &ppp_iface(ppp)->ip4addr,
1405cd8e09b9Sdlg 				    ppp_iface(ppp)->ifname,
14060fbf3537Syasuoka 				    MRU_IPMTU(ppp->peer_mru));
14070fbf3537Syasuoka 			} else {
14080fbf3537Syasuoka 				in_route_add(&ppp->ppp_framed_ip_address,
14090fbf3537Syasuoka 				    &ppp->ppp_framed_ip_netmask,
1410cd8e09b9Sdlg 				    &ppp_iface(ppp)->ip4addr,
1411cd8e09b9Sdlg 				    ppp_iface(ppp)->ifname, 0,
14120fbf3537Syasuoka 				    MRU_IPMTU(ppp->peer_mru));
14130fbf3537Syasuoka 			}
1414cd8e09b9Sdlg 		}
14150fbf3537Syasuoka #endif
14160fbf3537Syasuoka 	} else {
14170fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
1418cd8e09b9Sdlg 		if (_this->iface[ppp->ifidx].using_pppx == 0) {
14190fbf3537Syasuoka 			if (ppp->ppp_framed_ip_netmask.s_addr == 0xffffffffL) {
14200fbf3537Syasuoka 				in_host_route_delete(&ppp->ppp_framed_ip_address,
14210fbf3537Syasuoka 				    &ppp_iface(ppp)->ip4addr);
14220fbf3537Syasuoka 			} else {
14230fbf3537Syasuoka 				in_route_delete(&ppp->ppp_framed_ip_address,
14240fbf3537Syasuoka 				    &ppp->ppp_framed_ip_netmask,
14250fbf3537Syasuoka 				    &ppp_iface(ppp)->ip4addr, 0);
14260fbf3537Syasuoka 			}
14270fbf3537Syasuoka 			if (ppp->snp.snp_next != NULL)
1428f0a4e295Syasuoka 				/*
1429f0a4e295Syasuoka 				 * There is a blackhole route that has same
1430f0a4e295Syasuoka 				 * address/mask.
1431f0a4e295Syasuoka 				 */
1432cd8e09b9Sdlg 				in_route_add(&ppp->snp.snp_addr,
1433cd8e09b9Sdlg 				    &ppp->snp.snp_mask, &loop, LOOPBACK_IFNAME,
1434cd8e09b9Sdlg 				    RTF_BLACKHOLE, 0);
1435cd8e09b9Sdlg 		}
14360fbf3537Syasuoka #endif
14370fbf3537Syasuoka 		if (ppp->username[0] != '\0') {
14380fbf3537Syasuoka 			hl = hash_lookup(_this->map_user_ppp, ppp->username);
14390fbf3537Syasuoka 			NPPPD_ASSERT(hl != NULL);
14400fbf3537Syasuoka 			if (hl == NULL) {
14410fbf3537Syasuoka 				ppp_log(ppp, LOG_ERR,
14420fbf3537Syasuoka 				    "Unexpected error: cannot find user(%s) "
14430fbf3537Syasuoka 				    "from user database", ppp->username);
14440fbf3537Syasuoka 				return;
14450fbf3537Syasuoka 			}
14460fbf3537Syasuoka 			found = 0;
14470fbf3537Syasuoka 			u = hl->item;
14480fbf3537Syasuoka 			for (slist_itr_first(u); slist_itr_has_next(u);) {
14490fbf3537Syasuoka 				ppp1 = slist_itr_next(u);
14500fbf3537Syasuoka 				if (ppp1 == ppp) {
14510fbf3537Syasuoka 					slist_itr_remove(u);
14520fbf3537Syasuoka 					found++;
14530fbf3537Syasuoka 					break;
14540fbf3537Syasuoka 				}
14550fbf3537Syasuoka 			}
14560fbf3537Syasuoka 			if (found == 0) {
14570fbf3537Syasuoka 				ppp_log(ppp, LOG_ERR,
14580fbf3537Syasuoka 				    "Unexpected error: PPP instance is "
14590fbf3537Syasuoka 				    "not found in the user's list.");
14600fbf3537Syasuoka 			}
14610fbf3537Syasuoka 			NPPPD_ASSERT(found != 0);
14620fbf3537Syasuoka 			if (slist_length(u) <= 0) {
1463f0a4e295Syasuoka 				/* The last PPP */
14640fbf3537Syasuoka 				NPPPD_DBG((LOG_DEBUG,
14650fbf3537Syasuoka 				    "hash_delete(user->ppp, %s)",
14660fbf3537Syasuoka 				    ppp->username));
14670fbf3537Syasuoka 				if (hash_delete(_this->map_user_ppp,
14680fbf3537Syasuoka 				    ppp->username, 0) != 0) {
14690fbf3537Syasuoka 					ppp_log(ppp, LOG_ERR,
14700fbf3537Syasuoka 					    "Unexpected error: cannot delete "
14710fbf3537Syasuoka 					    "user(%s) from user database",
14720fbf3537Syasuoka 					    ppp->username);
14730fbf3537Syasuoka 				}
14740fbf3537Syasuoka 				slist_fini(u);
14750fbf3537Syasuoka 				free(u);
14760fbf3537Syasuoka 			} else {
1477f0a4e295Syasuoka 				/* Replace the reference. */
14780fbf3537Syasuoka 				ppp1 = slist_get(u, 0);
14790fbf3537Syasuoka 				hl->key = ppp1->username;
14800fbf3537Syasuoka 			}
14810fbf3537Syasuoka 		}
14820fbf3537Syasuoka #ifdef USE_NPPPD_PIPEX
14830fbf3537Syasuoka 		if (npppd_ppp_pipex_ip_disable(_this, ppp) != 0)
14840fbf3537Syasuoka 			ppp_log(ppp, LOG_ERR,
14850fbf3537Syasuoka 			    "npppd_ppp_pipex_ip_disable() failed: %m");
14860fbf3537Syasuoka #endif /* USE_NPPPD_PIPEX */
14870fbf3537Syasuoka 	}
14880fbf3537Syasuoka }
14890fbf3537Syasuoka 
14900fbf3537Syasuoka /**
1491f0a4e295Syasuoka  * Assign the IP address.  Returning "struct in_addr" is stored IP address
1492f0a4e295Syasuoka  * in network byte order.
1493f0a4e295Syasuoka  * @param req_ip4	IP address request to assign.  If the address is used
1494f0a4e295Syasuoka  * already, this function will return fail.
14950fbf3537Syasuoka  */
14960fbf3537Syasuoka int
14970fbf3537Syasuoka npppd_assign_ip_addr(npppd *_this, npppd_ppp *ppp, uint32_t req_ip4)
14980fbf3537Syasuoka {
14990fbf3537Syasuoka 	uint32_t ip4, ip4mask;
15000fbf3537Syasuoka 	int flag, dyna, rval, fallback_dyna;
15010fbf3537Syasuoka 	const char *reason = "out of the pool";
15020fbf3537Syasuoka 	struct sockaddr_npppd *snp;
15030fbf3537Syasuoka 	npppd_pool *pool;
15040fbf3537Syasuoka 	npppd_auth_base *realm;
15050fbf3537Syasuoka 
15060fbf3537Syasuoka 	NPPPD_DBG((LOG_DEBUG, "%s() assigned=%s", __func__,
15070fbf3537Syasuoka 	    (ppp_ip_assigned(ppp))? "true" : "false"));
15080fbf3537Syasuoka 	if (ppp_ip_assigned(ppp))
15090fbf3537Syasuoka 		return 0;
15100fbf3537Syasuoka 
15110fbf3537Syasuoka 	ip4 = INADDR_ANY;
15120fbf3537Syasuoka 	ip4mask = 0xffffffffL;
15130fbf3537Syasuoka 	flag = ppp_ipcp(ppp)->ip_assign_flags;
15140fbf3537Syasuoka 	realm = ppp->realm;
15150fbf3537Syasuoka 	dyna = 0;
15160fbf3537Syasuoka 	fallback_dyna = 0;
15170fbf3537Syasuoka 	pool = NULL;
15180fbf3537Syasuoka 
15190fbf3537Syasuoka 	if (ppp->realm_framed_ip_address.s_addr == INADDR_USER_SELECT) {
15200fbf3537Syasuoka 		if (req_ip4 == INADDR_ANY)
15210fbf3537Syasuoka 			dyna = 1;
15220fbf3537Syasuoka 	} else if (ppp->realm_framed_ip_address.s_addr == INADDR_NAS_SELECT) {
15230fbf3537Syasuoka 		dyna = 1;
15240fbf3537Syasuoka 	} else {
15250fbf3537Syasuoka 		NPPPD_ASSERT(realm != NULL);
1526f0a4e295Syasuoka 		/* We cannot assign a fixed ip address without realm */
15270fbf3537Syasuoka 
15280fbf3537Syasuoka 		if ((npppd_auth_get_type(realm) == NPPPD_AUTH_TYPE_RADIUS &&
15290fbf3537Syasuoka 		    (flag & NPPPD_IP_ASSIGN_RADIUS) == 0 &&
15300fbf3537Syasuoka 			    (flag & NPPPD_IP_ASSIGN_FIXED) == 0) ||
15310fbf3537Syasuoka 		    (npppd_auth_get_type(realm) == NPPPD_AUTH_TYPE_LOCAL &&
15320fbf3537Syasuoka 		    (flag & NPPPD_IP_ASSIGN_FIXED) == 0))
15330fbf3537Syasuoka 			dyna = 1;
15340fbf3537Syasuoka 		else {
15350fbf3537Syasuoka 			fallback_dyna = 1;
15360fbf3537Syasuoka 			req_ip4 = ntohl(ppp->realm_framed_ip_address.s_addr);
15370fbf3537Syasuoka 			ip4mask = ntohl(ppp->realm_framed_ip_netmask.s_addr);
15380fbf3537Syasuoka 		}
15390fbf3537Syasuoka 	}
15400fbf3537Syasuoka 	if (!dyna) {
15410fbf3537Syasuoka 		/*
1542f0a4e295Syasuoka 		 * Realm requires the fixed IP address, but the address
1543f0a4e295Syasuoka 		 * doesn't belong any address pool.  Fallback to dynamic
1544f0a4e295Syasuoka 		 * assignment.
15450fbf3537Syasuoka 		 */
15460fbf3537Syasuoka 		for (slist_itr_first(ppp_pools(ppp));
15470fbf3537Syasuoka 		    slist_itr_has_next(ppp_pools(ppp));){
15480fbf3537Syasuoka 			pool = slist_itr_next(ppp_pools(ppp));
15490fbf3537Syasuoka 			rval = npppd_pool_get_assignability(pool, req_ip4,
15500fbf3537Syasuoka 			    ip4mask, &snp);
15510fbf3537Syasuoka 			switch (rval) {
15520fbf3537Syasuoka 			case ADDRESS_OK:
15530fbf3537Syasuoka 				if (snp->snp_type == SNP_POOL) {
15540fbf3537Syasuoka 					/*
1555f0a4e295Syasuoka 					 * Fixed address pool can be used
1556f0a4e295Syasuoka 					 * only if the realm specified to use
1557f0a4e295Syasuoka 					 * it.
15580fbf3537Syasuoka 					 */
15590fbf3537Syasuoka 					if (ppp->realm_framed_ip_address
15600fbf3537Syasuoka 					    .s_addr != INADDR_USER_SELECT)
15610fbf3537Syasuoka 						ip4 = req_ip4;
15620fbf3537Syasuoka 					break;
15630fbf3537Syasuoka 				}
15640fbf3537Syasuoka 				ppp->assign_dynapool = 1;
15650fbf3537Syasuoka 				ip4 = req_ip4;
15660fbf3537Syasuoka 				break;
15670fbf3537Syasuoka 			case ADDRESS_RESERVED:
15680fbf3537Syasuoka 				reason = "reserved";
15690fbf3537Syasuoka 				continue;
15700fbf3537Syasuoka 			case ADDRESS_OUT_OF_POOL:
15710fbf3537Syasuoka 				reason = "out of the pool";
1572f0a4e295Syasuoka 				continue;	/* try next */
15730fbf3537Syasuoka 			case ADDRESS_BUSY:
15740fbf3537Syasuoka 				fallback_dyna = 0;
15750fbf3537Syasuoka 				reason = "busy";
15760fbf3537Syasuoka 				break;
15770fbf3537Syasuoka 			default:
15780fbf3537Syasuoka 			case ADDRESS_INVALID:
15790fbf3537Syasuoka 				fallback_dyna = 0;
15800fbf3537Syasuoka 				reason = "invalid";
15810fbf3537Syasuoka 				break;
15820fbf3537Syasuoka 			}
15830fbf3537Syasuoka 			break;
15840fbf3537Syasuoka 		}
15850fbf3537Syasuoka #define	IP_4OCT(v) ((0xff000000 & (v)) >> 24), ((0x00ff0000 & (v)) >> 16),\
15860fbf3537Syasuoka 	    ((0x0000ff00 & (v)) >> 8), (0x000000ff & (v))
15870fbf3537Syasuoka 		if (ip4 == 0) {
15880fbf3537Syasuoka 			ppp_log(ppp, LOG_NOTICE,
15890fbf3537Syasuoka 			    "Requested IP address (%d.%d.%d.%d)/%d "
15900fbf3537Syasuoka 			    "is %s", IP_4OCT(req_ip4),
15910fbf3537Syasuoka 			    netmask2prefixlen(htonl(ip4mask)), reason);
15920fbf3537Syasuoka 			if (fallback_dyna)
15930fbf3537Syasuoka 				goto dyna_assign;
15940fbf3537Syasuoka 			return 1;
15950fbf3537Syasuoka 		}
15960fbf3537Syasuoka 		ppp->assigned_pool = pool;
15970fbf3537Syasuoka 
15980fbf3537Syasuoka 		ppp->ppp_framed_ip_address.s_addr = htonl(ip4);
15990fbf3537Syasuoka 		ppp->ppp_framed_ip_netmask.s_addr = htonl(ip4mask);
16000fbf3537Syasuoka 	} else {
16010fbf3537Syasuoka dyna_assign:
16020fbf3537Syasuoka 		for (slist_itr_first(ppp_pools(ppp));
16030fbf3537Syasuoka 		    slist_itr_has_next(ppp_pools(ppp));){
16040fbf3537Syasuoka 			pool = slist_itr_next(ppp_pools(ppp));
16050fbf3537Syasuoka 			ip4 = npppd_pool_get_dynamic(pool, ppp);
16060fbf3537Syasuoka 			if (ip4 != 0)
16070fbf3537Syasuoka 				break;
16080fbf3537Syasuoka 		}
16090fbf3537Syasuoka 		if (ip4 == 0) {
16100fbf3537Syasuoka 			ppp_log(ppp, LOG_NOTICE,
16110fbf3537Syasuoka 			    "No free address in the pool.");
16120fbf3537Syasuoka 			return 1;
16130fbf3537Syasuoka 		}
16140fbf3537Syasuoka 		ppp->assigned_pool = pool;
16150fbf3537Syasuoka 		ppp->assign_dynapool = 1;
16160fbf3537Syasuoka 		ppp->ppp_framed_ip_address.s_addr = htonl(ip4);
16170fbf3537Syasuoka 		ppp->ppp_framed_ip_netmask.s_addr = htonl(0xffffffffL);
16180fbf3537Syasuoka 	}
16190fbf3537Syasuoka 
16200fbf3537Syasuoka 	return npppd_pool_assign_ip(ppp->assigned_pool, ppp);
16210fbf3537Syasuoka }
16220fbf3537Syasuoka 
16230fbf3537Syasuoka static void *
16240fbf3537Syasuoka rtlist_remove(slist *prtlist, struct radish *radish)
16250fbf3537Syasuoka {
16260fbf3537Syasuoka 	struct radish *r;
16270fbf3537Syasuoka 
16280fbf3537Syasuoka 	slist_itr_first(prtlist);
16290fbf3537Syasuoka 	while (slist_itr_has_next(prtlist)) {
16300fbf3537Syasuoka 		r = slist_itr_next(prtlist);
16310fbf3537Syasuoka 		if (!sockaddr_npppd_match(radish->rd_route, r->rd_route) ||
16320fbf3537Syasuoka 		    !sockaddr_npppd_match(radish->rd_mask, r->rd_mask))
16330fbf3537Syasuoka 			continue;
16340fbf3537Syasuoka 
16350fbf3537Syasuoka 		return slist_itr_remove(prtlist);
16360fbf3537Syasuoka 	}
16370fbf3537Syasuoka 
16380fbf3537Syasuoka 	return NULL;
16390fbf3537Syasuoka }
16400fbf3537Syasuoka 
1641f0a4e295Syasuoka /** Set {@link ::npppd#rd the only radish of npppd} */
16420fbf3537Syasuoka int
16430fbf3537Syasuoka npppd_set_radish(npppd *_this, void *radish_head)
16440fbf3537Syasuoka {
16450fbf3537Syasuoka 	int rval, delppp0, count;
16460fbf3537Syasuoka 	struct sockaddr_npppd *snp;
16470fbf3537Syasuoka 	struct radish *radish, *r;
16480fbf3537Syasuoka 	slist rtlist0, rtlist1, delppp;
16490fbf3537Syasuoka 	npppd_ppp *ppp;
16500fbf3537Syasuoka 	void *dummy;
16510fbf3537Syasuoka 
16520fbf3537Syasuoka 	slist_init(&rtlist0);
16530fbf3537Syasuoka 	slist_init(&rtlist1);
16540fbf3537Syasuoka 	slist_init(&delppp);
16550fbf3537Syasuoka 
16560fbf3537Syasuoka 	if (radish_head != NULL) {
16570fbf3537Syasuoka 		if (rd2slist(radish_head, &rtlist1) != 0) {
16580fbf3537Syasuoka 			log_printf(LOG_WARNING, "rd2slist failed: %m");
1659f0a4e295Syasuoka 			goto fail;
16600fbf3537Syasuoka 		}
16610fbf3537Syasuoka 	}
16620fbf3537Syasuoka 	if (_this->rd != NULL) {
16630fbf3537Syasuoka 		if (rd2slist(_this->rd, &rtlist0) != 0) {
16640fbf3537Syasuoka 			log_printf(LOG_WARNING, "rd2slist failed: %m");
1665f0a4e295Syasuoka 			goto fail;
16660fbf3537Syasuoka 		}
16670fbf3537Syasuoka 	}
16680fbf3537Syasuoka 	if (_this->rd != NULL && radish_head != NULL) {
16690fbf3537Syasuoka 		for (slist_itr_first(&rtlist0); slist_itr_has_next(&rtlist0);) {
16700fbf3537Syasuoka 			radish = slist_itr_next(&rtlist0);
16710fbf3537Syasuoka 			snp = radish->rd_rtent;
16720fbf3537Syasuoka 		    /*
1673f0a4e295Syasuoka 		     * replace the pool address
16740fbf3537Syasuoka 		     */
16750fbf3537Syasuoka 			if (snp->snp_type == SNP_POOL ||
16760fbf3537Syasuoka 			    snp->snp_type == SNP_DYN_POOL) {
16770fbf3537Syasuoka 				if (rd_lookup(radish->rd_route, radish->rd_mask,
16780fbf3537Syasuoka 					    radish_head) == NULL)
16790fbf3537Syasuoka 					continue;
1680f0a4e295Syasuoka 				/* don't add */
16810fbf3537Syasuoka 				rtlist_remove(&rtlist1, radish);
1682f0a4e295Syasuoka 				/* don't delete */
16830fbf3537Syasuoka 				slist_itr_remove(&rtlist0);
16840fbf3537Syasuoka 				continue;
16850fbf3537Syasuoka 			}
16860fbf3537Syasuoka 		    /*
1687f0a4e295Syasuoka 		     * handle the active PPP sessions.
16880fbf3537Syasuoka 		     */
16890fbf3537Syasuoka 			NPPPD_ASSERT(snp->snp_type == SNP_PPP);
16900fbf3537Syasuoka 			ppp =  snp->snp_data_ptr;
16910fbf3537Syasuoka 
1692f0a4e295Syasuoka 			/* Don't delete the route of active PPP session */
16930fbf3537Syasuoka 			slist_itr_remove(&rtlist0);
16940fbf3537Syasuoka 
1695f0a4e295Syasuoka 			/* clear informations about old pool configuration */
16960fbf3537Syasuoka 			ppp->assigned_pool = NULL;
16970fbf3537Syasuoka 			snp->snp_next = NULL;
16980fbf3537Syasuoka 
16990fbf3537Syasuoka 			delppp0 = 0;
17000fbf3537Syasuoka 			if (!rd_match((struct sockaddr *)snp, radish_head, &r)){
17010fbf3537Syasuoka 				/*
1702f0a4e295Syasuoka 				 * If the address doesn't belong the new pools,
1703f0a4e295Syasuoka 				 * add the PPP session to the deletion list.
17040fbf3537Syasuoka 				 */
17050fbf3537Syasuoka 				slist_add(&delppp, snp->snp_data_ptr);
17060fbf3537Syasuoka 				delppp0 = 1;
17070fbf3537Syasuoka 			} else {
17080fbf3537Syasuoka 				NPPPD_ASSERT(
17090fbf3537Syasuoka 				    ((struct sockaddr_npppd *)r->rd_rtent)
17100fbf3537Syasuoka 					->snp_type == SNP_POOL ||
17110fbf3537Syasuoka 				    ((struct sockaddr_npppd *)r->rd_rtent)
17120fbf3537Syasuoka 					->snp_type == SNP_DYN_POOL);
17130fbf3537Syasuoka 				/*
1714f0a4e295Syasuoka 				 * If there is a pool entry that has same
1715f0a4e295Syasuoka 				 * address/mask, then make the RADISH entry a
1716f0a4e295Syasuoka 				 * list.  Set SNP_PPP as the first in the list,
1717f0a4e295Syasuoka 				 * set current entry in snp->snp_next and
1718f0a4e295Syasuoka 				 * delete it.
17190fbf3537Syasuoka 				 */
17200fbf3537Syasuoka 				if (sockaddr_npppd_match(
17210fbf3537Syasuoka 					    radish->rd_route, r->rd_route) &&
17220fbf3537Syasuoka 				    sockaddr_npppd_match(
17230fbf3537Syasuoka 					    radish->rd_mask, r->rd_mask)) {
1724f0a4e295Syasuoka 					/*
1725f0a4e295Syasuoka 					 * Releasing it, so remove it from the
1726f0a4e295Syasuoka 					 * new routing list.
1727f0a4e295Syasuoka 					 */
17280fbf3537Syasuoka 					rtlist_remove(&rtlist1, radish);
1729f0a4e295Syasuoka 					/* set as snp_snp_next */
17300fbf3537Syasuoka 					snp->snp_next = r->rd_rtent;
17310fbf3537Syasuoka 					rval = rd_delete(r->rd_route,
17320fbf3537Syasuoka 					    r->rd_mask, radish_head, &dummy);
17330fbf3537Syasuoka 					NPPPD_ASSERT(rval == 0);
17340fbf3537Syasuoka 				}
17350fbf3537Syasuoka 			}
1736f0a4e295Syasuoka 			/* Register to the new radish */
17370fbf3537Syasuoka 			rval = rd_insert(radish->rd_route, radish->rd_mask,
17380fbf3537Syasuoka 			    radish_head, snp);
17390fbf3537Syasuoka 			if (rval != 0) {
17400fbf3537Syasuoka 				errno = rval;
17410fbf3537Syasuoka 				ppp_log(((npppd_ppp *)snp->snp_data_ptr),
17420fbf3537Syasuoka 				    LOG_ERR,
17430fbf3537Syasuoka 				    "Fatal error on %s, cannot continue "
17440fbf3537Syasuoka 				    "this ppp session: %m", __func__);
17450fbf3537Syasuoka 				if (!delppp0)
17460fbf3537Syasuoka 					slist_add(&delppp, snp->snp_data_ptr);
17470fbf3537Syasuoka 			}
17480fbf3537Syasuoka 		}
17490fbf3537Syasuoka 	}
17500fbf3537Syasuoka 	count = 0;
17510fbf3537Syasuoka #ifndef	NO_ROUTE_FOR_POOLED_ADDRESS
1752cd8e09b9Sdlg 	if (_this->iface[0].using_pppx == 0) {
17530fbf3537Syasuoka 		for (slist_itr_first(&rtlist0); slist_itr_has_next(&rtlist0);) {
17540fbf3537Syasuoka 			radish = slist_itr_next(&rtlist0);
17550fbf3537Syasuoka 			in_route_delete(&SIN(radish->rd_route)->sin_addr,
1756cd8e09b9Sdlg 			    &SIN(radish->rd_mask)->sin_addr, &loop,
1757cd8e09b9Sdlg 			    RTF_BLACKHOLE);
17580fbf3537Syasuoka 			count++;
17590fbf3537Syasuoka 		}
17600fbf3537Syasuoka 		if (count > 0)
17610fbf3537Syasuoka 			log_printf(LOG_INFO,
17620fbf3537Syasuoka 			    "Deleted %d routes for old pool addresses", count);
17630fbf3537Syasuoka 
17640fbf3537Syasuoka 		count = 0;
17650fbf3537Syasuoka 		for (slist_itr_first(&rtlist1); slist_itr_has_next(&rtlist1);) {
17660fbf3537Syasuoka 			radish = slist_itr_next(&rtlist1);
17670fbf3537Syasuoka 			in_route_add(&(SIN(radish->rd_route)->sin_addr),
1768cd8e09b9Sdlg 			    &SIN(radish->rd_mask)->sin_addr, &loop,
1769cd8e09b9Sdlg 			    LOOPBACK_IFNAME, RTF_BLACKHOLE, 0);
17700fbf3537Syasuoka 			count++;
17710fbf3537Syasuoka 		}
17720fbf3537Syasuoka 		if (count > 0)
17730fbf3537Syasuoka 			log_printf(LOG_INFO,
1774cd8e09b9Sdlg 				    "Added %d routes for new pool addresses",
1775cd8e09b9Sdlg 				    count);
1776cd8e09b9Sdlg 	}
17770fbf3537Syasuoka #endif
17780fbf3537Syasuoka 	slist_fini(&rtlist0);
17790fbf3537Syasuoka 	slist_fini(&rtlist1);
17800fbf3537Syasuoka 
17810fbf3537Syasuoka 	if (_this->rd != NULL)
17820fbf3537Syasuoka 		npppd_rd_walktree_delete(_this->rd);
17830fbf3537Syasuoka 	_this->rd = radish_head;
17840fbf3537Syasuoka 
17850fbf3537Syasuoka 	for (slist_itr_first(&delppp); slist_itr_has_next(&delppp);) {
17860fbf3537Syasuoka 		ppp = slist_itr_next(&delppp);
17870fbf3537Syasuoka                 ppp_log(ppp, LOG_NOTICE,
17880fbf3537Syasuoka                     "stop.  IP address of this ppp is out of the pool.: %s",
17890fbf3537Syasuoka                     inet_ntoa(ppp->ppp_framed_ip_address));
17900fbf3537Syasuoka 		ppp_stop(ppp, NULL);
17910fbf3537Syasuoka 	}
17920fbf3537Syasuoka 	slist_fini(&delppp);
17930fbf3537Syasuoka 
17940fbf3537Syasuoka 	return 0;
1795f0a4e295Syasuoka fail:
17960fbf3537Syasuoka 	slist_fini(&rtlist0);
17970fbf3537Syasuoka 	slist_fini(&rtlist1);
17980fbf3537Syasuoka 	slist_fini(&delppp);
17990fbf3537Syasuoka 
18000fbf3537Syasuoka 	return 1;
18010fbf3537Syasuoka }
18020fbf3537Syasuoka 
18030fbf3537Syasuoka /**
1804f0a4e295Syasuoka  * This function stores all users to {@link slist} and returns them.
1805f0a4e295Syasuoka  * References to {@link ::npppd_ppp} will be stored in users.
18060fbf3537Syasuoka  */
18070fbf3537Syasuoka int
18080fbf3537Syasuoka npppd_get_all_users(npppd *_this, slist *users)
18090fbf3537Syasuoka {
18100fbf3537Syasuoka 	int rval;
18110fbf3537Syasuoka 	struct radish *rd;
18120fbf3537Syasuoka 	struct sockaddr_npppd *snp;
18130fbf3537Syasuoka 	slist list;
18140fbf3537Syasuoka 
18150fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
18160fbf3537Syasuoka 
18170fbf3537Syasuoka 	slist_init(&list);
18180fbf3537Syasuoka 	rval = rd2slist(_this->rd, &list);
18190fbf3537Syasuoka 	if (rval != 0)
18200fbf3537Syasuoka 		return rval;
18210fbf3537Syasuoka 
18220fbf3537Syasuoka 	for (slist_itr_first(&list); slist_itr_has_next(&list);) {
18230fbf3537Syasuoka 		rd = slist_itr_next(&list);
18240fbf3537Syasuoka 		snp = rd->rd_rtent;
18250fbf3537Syasuoka 		if (snp->snp_type == SNP_PPP) {
18260fbf3537Syasuoka 			if (slist_add(users, snp->snp_data_ptr) == NULL) {
18270fbf3537Syasuoka 				log_printf(LOG_ERR,
18280fbf3537Syasuoka 				    "slist_add() failed in %s: %m", __func__);
1829f0a4e295Syasuoka 				goto fail;
18300fbf3537Syasuoka 			}
18310fbf3537Syasuoka 		}
18320fbf3537Syasuoka 	}
18330fbf3537Syasuoka 	slist_fini(&list);
18340fbf3537Syasuoka 
18350fbf3537Syasuoka 	return 0;
1836f0a4e295Syasuoka fail:
18370fbf3537Syasuoka 	slist_fini(&list);
18380fbf3537Syasuoka 
18390fbf3537Syasuoka 	return 1;
18400fbf3537Syasuoka }
18410fbf3537Syasuoka 
18420fbf3537Syasuoka static int
18430fbf3537Syasuoka rd2slist_walk(struct radish *rd, void *list0)
18440fbf3537Syasuoka {
18450fbf3537Syasuoka 	slist *list = list0;
18460fbf3537Syasuoka 	void *r;
18470fbf3537Syasuoka 
18480fbf3537Syasuoka 	r = slist_add(list, rd);
18490fbf3537Syasuoka 	if (r == NULL)
18500fbf3537Syasuoka 		return -1;
18510fbf3537Syasuoka 	return 0;
18520fbf3537Syasuoka }
18530fbf3537Syasuoka static int
18540fbf3537Syasuoka rd2slist(struct radish_head *h, slist *list)
18550fbf3537Syasuoka {
18560fbf3537Syasuoka 	return rd_walktree(h, rd2slist_walk, list);
18570fbf3537Syasuoka }
18580fbf3537Syasuoka 
18590fbf3537Syasuoka static void
18600fbf3537Syasuoka npppd_reload0(npppd *_this)
18610fbf3537Syasuoka {
18620fbf3537Syasuoka 	npppd_reload_config(_this);
18630fbf3537Syasuoka #ifdef USE_NPPPD_ARP
18640fbf3537Syasuoka 	arp_set_strictintfnetwork(npppd_config_str_equali(_this, "arpd.strictintfnetwork", "true", ARPD_STRICTINTFNETWORK_DEFAULT));
18650fbf3537Syasuoka 	if (npppd_config_str_equali(_this, "arpd.enabled", "true", ARPD_DEFAULT) == 1)
18660fbf3537Syasuoka         	arp_sock_init();
18670fbf3537Syasuoka 	else
18680fbf3537Syasuoka 		arp_sock_fini();
18690fbf3537Syasuoka #endif
18700fbf3537Syasuoka 	npppd_modules_reload(_this);
18710fbf3537Syasuoka 	npppd_ifaces_load_config(_this);
18720fbf3537Syasuoka #ifdef NPPPD_RESET_IP_ADDRESS
18730fbf3537Syasuoka 	{
18740fbf3537Syasuoka 	    int i;
18750fbf3537Syasuoka 	    for (i = 0; i < countof(_this->iface); i++) {
18760fbf3537Syasuoka 		    if (_this->iface[i].initialized != 0)
18770fbf3537Syasuoka 			    npppd_iface_reinit(&_this->iface[i]);
18780fbf3537Syasuoka 	    }
18790fbf3537Syasuoka 	}
18800fbf3537Syasuoka #endif
18810fbf3537Syasuoka 	npppd_auth_finalizer_periodic(_this);
18820fbf3537Syasuoka }
18830fbf3537Syasuoka 
18840fbf3537Syasuoka /***********************************************************************
1885f0a4e295Syasuoka  * Signal handlers
18860fbf3537Syasuoka  ***********************************************************************/
18870fbf3537Syasuoka static void
18880fbf3537Syasuoka npppd_on_sighup(int fd, short ev_type, void *ctx)
18890fbf3537Syasuoka {
18900fbf3537Syasuoka 	npppd *_this;
18910fbf3537Syasuoka 
18920fbf3537Syasuoka 	_this = ctx;
18930fbf3537Syasuoka #ifndef	NO_DELAYED_RELOAD
18940fbf3537Syasuoka 	if (_this->delayed_reload > 0)
18950fbf3537Syasuoka 		_this->reloading_count = _this->delayed_reload;
18960fbf3537Syasuoka 	else
18970fbf3537Syasuoka #endif
18980fbf3537Syasuoka 		npppd_reload0(_this);
18990fbf3537Syasuoka }
19000fbf3537Syasuoka 
19010fbf3537Syasuoka static void
19020fbf3537Syasuoka npppd_on_sigterm(int fd, short ev_type, void *ctx)
19030fbf3537Syasuoka {
19040fbf3537Syasuoka 	npppd *_this;
19050fbf3537Syasuoka 
19060fbf3537Syasuoka 	_this = ctx;
19070fbf3537Syasuoka 	npppd_stop(_this);
19080fbf3537Syasuoka }
19090fbf3537Syasuoka 
19100fbf3537Syasuoka static void
19110fbf3537Syasuoka npppd_on_sigint(int fd, short ev_type, void *ctx)
19120fbf3537Syasuoka {
19130fbf3537Syasuoka 	npppd *_this;
19140fbf3537Syasuoka 
19150fbf3537Syasuoka 	_this = ctx;
19160fbf3537Syasuoka 	npppd_stop(_this);
19170fbf3537Syasuoka }
19180fbf3537Syasuoka 
19190fbf3537Syasuoka /***********************************************************************
1920f0a4e295Syasuoka  * Miscellaneous functions
19210fbf3537Syasuoka  ***********************************************************************/
19220fbf3537Syasuoka static uint32_t
19230fbf3537Syasuoka str_hash(const void *ptr, int sz)
19240fbf3537Syasuoka {
19250fbf3537Syasuoka 	uint32_t hash = 0;
19260fbf3537Syasuoka 	int i, len;
19270fbf3537Syasuoka 	const char *str;
19280fbf3537Syasuoka 
19290fbf3537Syasuoka 	str = ptr;
19300fbf3537Syasuoka 	len = strlen(str);
19310fbf3537Syasuoka 	for (i = 0; i < len; i++)
19320fbf3537Syasuoka 		hash = hash*0x1F + str[i];
19330fbf3537Syasuoka 	hash = (hash << 16) ^ (hash & 0xffff);
19340fbf3537Syasuoka 
19350fbf3537Syasuoka 	return hash % sz;
19360fbf3537Syasuoka }
19370fbf3537Syasuoka 
19380fbf3537Syasuoka /**
1939f0a4e295Syasuoka  * Select a authentication realm that is for given {@link ::npppd_ppp PPP}.
1940f0a4e295Syasuoka  * Return 0 on success.
19410fbf3537Syasuoka  */
19420fbf3537Syasuoka int
19430fbf3537Syasuoka npppd_ppp_bind_realm(npppd *_this, npppd_ppp *ppp, const char *username, int
19440fbf3537Syasuoka     eap_required)
19450fbf3537Syasuoka {
19460fbf3537Syasuoka 	int lsuffix, lprefix, lusername, lmax;
19470fbf3537Syasuoka 	const char *val;
19480fbf3537Syasuoka 	char *tok, *buf0, buf[NPPPD_CONFIG_BUFSIZ], buf1[MAX_USERNAME_LENGTH];
19490fbf3537Syasuoka 	npppd_auth_base *realm = NULL, *realm0 = NULL, *realm1 = NULL;
19500fbf3537Syasuoka 
19510fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
19520fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
19530fbf3537Syasuoka 	NPPPD_ASSERT(username != NULL);
19540fbf3537Syasuoka 
19550fbf3537Syasuoka 	/*
1956f0a4e295Syasuoka 	 * If the PPP suffix is the longest, and the length of the suffix is
1957f0a4e295Syasuoka 	 * same, select the first one.
19580fbf3537Syasuoka 	 */
19590fbf3537Syasuoka 	lusername = strlen(username);
19600fbf3537Syasuoka 	lmax = -1;
19610fbf3537Syasuoka 	realm = NULL;
19620fbf3537Syasuoka 
19630fbf3537Syasuoka 	if ((val = ppp_config_str(ppp, "realm_list")) == NULL) {
19640fbf3537Syasuoka #ifndef	NO_DEFAULT_REALM
19650fbf3537Syasuoka 		/*
1966f0a4e295Syasuoka 		 * If the realm is not a list, because of compatibility for
1967f0a4e295Syasuoka 		 * past versions, we try fallback from LOCAL to RADIUS.
19680fbf3537Syasuoka 		 */
19690fbf3537Syasuoka 		realm0 = NULL;
19700fbf3537Syasuoka 		slist_itr_first(&_this->realms);
19710fbf3537Syasuoka 		while (slist_itr_has_next(&_this->realms)) {
19720fbf3537Syasuoka 			realm1 = slist_itr_next(&_this->realms);
19730fbf3537Syasuoka 			if (!npppd_auth_is_usable(realm1))
19740fbf3537Syasuoka 				continue;
19750fbf3537Syasuoka 			switch (npppd_auth_get_type(realm1)) {
19760fbf3537Syasuoka 			case NPPPD_AUTH_TYPE_LOCAL:
19770fbf3537Syasuoka 				if (npppd_auth_get_user_password(
19780fbf3537Syasuoka 				    realm1, npppd_auth_username_for_auth(
19790fbf3537Syasuoka 					    realm1, username, buf1),
19800fbf3537Syasuoka 				    NULL, NULL) == 0) {
19810fbf3537Syasuoka 					realm = realm1;
19820fbf3537Syasuoka 					goto found;
19830fbf3537Syasuoka 				}
19840fbf3537Syasuoka 				break;
19850fbf3537Syasuoka 
19860fbf3537Syasuoka 			case NPPPD_AUTH_TYPE_RADIUS:
19870fbf3537Syasuoka 				realm = realm1;
19880fbf3537Syasuoka 				goto found;
19890fbf3537Syasuoka 			}
19900fbf3537Syasuoka 		}
19910fbf3537Syasuoka #else
19920fbf3537Syasuoka 		/* Nothing to do */
19930fbf3537Syasuoka #endif
19940fbf3537Syasuoka 	} else {
19950fbf3537Syasuoka 		strlcpy(buf, val, sizeof(buf));
19960fbf3537Syasuoka 		buf0 = buf;
19970fbf3537Syasuoka 		while ((tok = strsep(&buf0, " ,\t\r\n")) != NULL) {
19980fbf3537Syasuoka 			if (tok[0] == '\0')
19990fbf3537Syasuoka 				continue;
20000fbf3537Syasuoka 			realm0 = NULL;
20010fbf3537Syasuoka 			slist_itr_first(&_this->realms);
20020fbf3537Syasuoka 			while (slist_itr_has_next(&_this->realms)) {
20030fbf3537Syasuoka 				realm1 = slist_itr_next(&_this->realms);
20040fbf3537Syasuoka 				if (!npppd_auth_is_usable(realm1))
20050fbf3537Syasuoka 					continue;
20060fbf3537Syasuoka 				if (eap_required &&
20070fbf3537Syasuoka 				    !npppd_auth_is_eap_capable(realm1))
20080fbf3537Syasuoka 					continue;
20090fbf3537Syasuoka 				if (strcmp(npppd_auth_get_label(realm1), tok)
20100fbf3537Syasuoka 				    == 0) {
20110fbf3537Syasuoka 					realm0 = realm1;
20120fbf3537Syasuoka 					break;
20130fbf3537Syasuoka 				}
20140fbf3537Syasuoka 			}
20150fbf3537Syasuoka 			if (realm0 == NULL)
20160fbf3537Syasuoka 				continue;
20170fbf3537Syasuoka 			lsuffix = strlen(npppd_auth_get_suffix(realm0));
20180fbf3537Syasuoka 			if (lsuffix > lmax &&
20190fbf3537Syasuoka 			    (lsuffix == 0 || (lsuffix < lusername &&
20200fbf3537Syasuoka 			    strcmp(username + lusername - lsuffix,
20210fbf3537Syasuoka 				npppd_auth_get_suffix(realm0)) == 0))) {
20220fbf3537Syasuoka 				/* check prefix */
20230fbf3537Syasuoka 				lprefix = strlen(npppd_auth_get_suffix(realm0));
20240fbf3537Syasuoka 				if (lprefix > 0 &&
20250fbf3537Syasuoka 				    strncmp(username,
20260fbf3537Syasuoka 					    npppd_auth_get_suffix(realm0),
20270fbf3537Syasuoka 					    lprefix) != 0)
20280fbf3537Syasuoka 					continue;
20290fbf3537Syasuoka 
20300fbf3537Syasuoka 				lmax = lsuffix;
20310fbf3537Syasuoka 				realm = realm0;
20320fbf3537Syasuoka 			}
20330fbf3537Syasuoka 		}
20340fbf3537Syasuoka 	}
20350fbf3537Syasuoka 	if (realm == NULL) {
20360fbf3537Syasuoka 		log_printf(LOG_INFO, "user='%s' could not bind any realms",
20370fbf3537Syasuoka 		    username);
20380fbf3537Syasuoka 		return 1;
20390fbf3537Syasuoka 	}
20400fbf3537Syasuoka #ifndef	NO_DEFAULT_REALM
20410fbf3537Syasuoka found:
20420fbf3537Syasuoka #endif
20430fbf3537Syasuoka 	NPPPD_DBG((LOG_DEBUG, "%s bind realm %s(%s)",
20440fbf3537Syasuoka 	    username, npppd_auth_get_label(realm), npppd_auth_get_name(realm)));
20450fbf3537Syasuoka 
20460fbf3537Syasuoka 	if (npppd_auth_get_type(realm) == NPPPD_AUTH_TYPE_LOCAL)
20470fbf3537Syasuoka 		/* hook the auto reload */
20480fbf3537Syasuoka 		npppd_auth_get_user_password(realm,
20490fbf3537Syasuoka 		    npppd_auth_username_for_auth(realm1, username, buf1), NULL,
20500fbf3537Syasuoka 			NULL);
20510fbf3537Syasuoka 	ppp->realm = realm;
20520fbf3537Syasuoka 
20530fbf3537Syasuoka 	return 0;
20540fbf3537Syasuoka }
20550fbf3537Syasuoka 
2056f0a4e295Syasuoka /** Is assigned realm a LOCAL authentication? */
20570fbf3537Syasuoka int
20580fbf3537Syasuoka npppd_ppp_is_realm_local(npppd *_this, npppd_ppp *ppp)
20590fbf3537Syasuoka {
20600fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
20610fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
20620fbf3537Syasuoka 
20630fbf3537Syasuoka 	if (ppp->realm == NULL)
20640fbf3537Syasuoka 		return 0;
20650fbf3537Syasuoka 
20660fbf3537Syasuoka 	return (npppd_auth_get_type(ppp->realm) == NPPPD_AUTH_TYPE_LOCAL)
20670fbf3537Syasuoka 	    ? 1 : 0;
20680fbf3537Syasuoka }
20690fbf3537Syasuoka 
2070f0a4e295Syasuoka /** Is assigned realm a RADIUS authentication? */
20710fbf3537Syasuoka int
20720fbf3537Syasuoka npppd_ppp_is_realm_radius(npppd *_this, npppd_ppp *ppp)
20730fbf3537Syasuoka {
20740fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
20750fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
20760fbf3537Syasuoka 
20770fbf3537Syasuoka 	if (ppp->realm == NULL)
20780fbf3537Syasuoka 		return 0;
20790fbf3537Syasuoka 
20800fbf3537Syasuoka 	return (npppd_auth_get_type(ppp->realm) == NPPPD_AUTH_TYPE_RADIUS)
20810fbf3537Syasuoka 	    ? 1 : 0;
20820fbf3537Syasuoka }
20830fbf3537Syasuoka 
2084f0a4e295Syasuoka /** Is assigned realm usable? */
20850fbf3537Syasuoka int
20860fbf3537Syasuoka npppd_ppp_is_realm_ready(npppd *_this, npppd_ppp *ppp)
20870fbf3537Syasuoka {
20880fbf3537Syasuoka 	if (ppp->realm == NULL)
20890fbf3537Syasuoka 		return 0;
20900fbf3537Syasuoka 
20910fbf3537Syasuoka 	return npppd_auth_is_ready(ppp->realm);
20920fbf3537Syasuoka }
20930fbf3537Syasuoka 
2094f0a4e295Syasuoka /** Return the name of assigned realm */
20950fbf3537Syasuoka const char *
20960fbf3537Syasuoka npppd_ppp_get_realm_name(npppd *_this, npppd_ppp *ppp)
20970fbf3537Syasuoka {
20980fbf3537Syasuoka 	if (ppp->realm == NULL)
20990fbf3537Syasuoka 		return "(none)";
21000fbf3537Syasuoka 	return npppd_auth_get_name(ppp->realm);
21010fbf3537Syasuoka }
21020fbf3537Syasuoka 
2103f0a4e295Syasuoka /** Return the interface name that bound given {@link ::npppd_ppp PPP} */
21040fbf3537Syasuoka const char *
21050fbf3537Syasuoka npppd_ppp_get_iface_name(npppd *_this, npppd_ppp *ppp)
21060fbf3537Syasuoka {
21070fbf3537Syasuoka 	if (ppp == NULL || ppp->ifidx < 0)
21080fbf3537Syasuoka 		return "(not binding)";
21090fbf3537Syasuoka 	return ppp_iface(ppp)->ifname;
21100fbf3537Syasuoka }
21110fbf3537Syasuoka 
2112f0a4e295Syasuoka /** Is the interface usable? */
21130fbf3537Syasuoka int
21140fbf3537Syasuoka npppd_ppp_iface_is_ready(npppd *_this, npppd_ppp *ppp)
21150fbf3537Syasuoka {
21160fbf3537Syasuoka 	return (npppd_iface_ip_is_ready(ppp_iface(ppp)) &&
21170fbf3537Syasuoka 	    ppp_ipcp(ppp) != NULL)? 1 : 0;
21180fbf3537Syasuoka }
21190fbf3537Syasuoka 
2120f0a4e295Syasuoka /** Select a suitable interface for {@link :npppd_ppp PPP} and bind them  */
21210fbf3537Syasuoka int
21220fbf3537Syasuoka npppd_ppp_bind_iface(npppd *_this, npppd_ppp *ppp)
21230fbf3537Syasuoka {
21240fbf3537Syasuoka 	int i, ifidx, ntotal_session;
21250fbf3537Syasuoka 	const char *ifname, *label;
21260fbf3537Syasuoka 	char buf[BUFSIZ];
21270fbf3537Syasuoka 	npppd_auth_base *realm;
21280fbf3537Syasuoka 
21290fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
21300fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
21310fbf3537Syasuoka 
21320fbf3537Syasuoka 	if (ppp->ifidx >= 0)
21330fbf3537Syasuoka 		return 0;
21340fbf3537Syasuoka 	if (ppp->peer_auth == 0) {
21350fbf3537Syasuoka 		strlcpy(buf, "no_auth.concentrate", sizeof(buf));
21360fbf3537Syasuoka 	} else {
21370fbf3537Syasuoka 		realm = (npppd_auth_base *)ppp->realm;
21380fbf3537Syasuoka 		strlcpy(buf, "realm.", sizeof(buf));
21390fbf3537Syasuoka 		NPPPD_ASSERT(ppp->realm != NULL);
21400fbf3537Syasuoka 		label = npppd_auth_get_label(realm);
21410fbf3537Syasuoka 		if (label[0] != '\0') {
21420fbf3537Syasuoka 			strlcat(buf, label, sizeof(buf));
21430fbf3537Syasuoka 			strlcat(buf, ".concentrate", sizeof(buf));
21440fbf3537Syasuoka 		} else
21450fbf3537Syasuoka 			strlcat(buf, "concentrate", sizeof(buf));
21460fbf3537Syasuoka 	}
21470fbf3537Syasuoka 
21480fbf3537Syasuoka 	ifname = ppp_config_str(ppp, buf);
21490fbf3537Syasuoka 	if (ifname == NULL)
21500fbf3537Syasuoka 		return 1;
21510fbf3537Syasuoka 
2152f0a4e295Syasuoka 	/* Search a interface */
21530fbf3537Syasuoka 	ifidx = -1;
21540fbf3537Syasuoka 	ntotal_session = 0;
21550fbf3537Syasuoka 	for (i = 0; i < countof(_this->iface); i++) {
21560fbf3537Syasuoka 		if (_this->iface[i].initialized == 0)
21570fbf3537Syasuoka 			continue;
21580fbf3537Syasuoka 		ntotal_session += _this->iface[i].nsession;
21590fbf3537Syasuoka 		if (strcmp(_this->iface[i].ifname, ifname) == 0)
21600fbf3537Syasuoka 			ifidx = i;
21610fbf3537Syasuoka 	}
21620fbf3537Syasuoka 	if (ifidx < 0)
21630fbf3537Syasuoka 		return 1;
21640fbf3537Syasuoka 
21650fbf3537Syasuoka 	if (ntotal_session >= _this->max_session) {
21660fbf3537Syasuoka 		ppp_log(ppp, LOG_WARNING,
21670fbf3537Syasuoka 		    "Number of sessions reaches out of the limit=%d",
21680fbf3537Syasuoka 		    _this->max_session);
21690fbf3537Syasuoka 		return 1;
21700fbf3537Syasuoka 	}
21710fbf3537Syasuoka 	if (_this->iface[ifidx].nsession >= _this->iface[ifidx].max_session) {
21720fbf3537Syasuoka 		ppp_log(ppp, LOG_WARNING,
21730fbf3537Syasuoka 		    "Number of sessions reaches out of the interface limit=%d",
21740fbf3537Syasuoka 		    _this->iface[ifidx].max_session);
21750fbf3537Syasuoka 		return 1;
21760fbf3537Syasuoka 	}
21770fbf3537Syasuoka 
21780fbf3537Syasuoka 	ppp->ifidx = ifidx;
21790fbf3537Syasuoka 	ppp_iface(ppp)->nsession++;
21800fbf3537Syasuoka 
21810fbf3537Syasuoka 	return 0;
21820fbf3537Syasuoka }
21830fbf3537Syasuoka 
2184f0a4e295Syasuoka /** Unbind the interface from the {@link ::npppd_ppp PPP} */
21850fbf3537Syasuoka void
21860fbf3537Syasuoka npppd_ppp_unbind_iface(npppd *_this, npppd_ppp *ppp)
21870fbf3537Syasuoka {
21880fbf3537Syasuoka 	if (ppp->ifidx >= 0)
21890fbf3537Syasuoka 		ppp_iface(ppp)->nsession--;
21900fbf3537Syasuoka 
21910fbf3537Syasuoka 	ppp->ifidx = -1;
21920fbf3537Syasuoka }
21930fbf3537Syasuoka 
21940fbf3537Syasuoka static int
21950fbf3537Syasuoka npppd_rd_walktree_delete(struct radish_head *rh)
21960fbf3537Syasuoka {
21970fbf3537Syasuoka 	void *dummy;
21980fbf3537Syasuoka 	struct radish *rd;
21990fbf3537Syasuoka 	slist list;
22000fbf3537Syasuoka 
22010fbf3537Syasuoka 	slist_init(&list);
22020fbf3537Syasuoka 	if (rd2slist(rh, &list) != 0)
22030fbf3537Syasuoka 		return 1;
22040fbf3537Syasuoka 	for (slist_itr_first(&list); slist_itr_has_next(&list);) {
22050fbf3537Syasuoka 		rd = slist_itr_next(&list);
22060fbf3537Syasuoka 		rd_delete(rd->rd_route, rd->rd_mask, rh, &dummy);
22070fbf3537Syasuoka 	}
22080fbf3537Syasuoka 	slist_fini(&list);
22090fbf3537Syasuoka 
22100fbf3537Syasuoka 	free(rh);
22110fbf3537Syasuoka 
22120fbf3537Syasuoka 	return 0;
22130fbf3537Syasuoka }
22140fbf3537Syasuoka 
22150fbf3537Syasuoka #ifdef USE_NPPPD_RADIUS
2216f0a4e295Syasuoka /**
2217f0a4e295Syasuoka  * Return radius_req_setting for the given {@link ::npppd_ppp PPP}.
2218f0a4e295Syasuoka  * @return return NULL if no usable RADIUS setting.
2219f0a4e295Syasuoka  */
22200fbf3537Syasuoka void *
22210fbf3537Syasuoka npppd_get_radius_req_setting(npppd *_this, npppd_ppp *ppp)
22220fbf3537Syasuoka {
22230fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
22240fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
22250fbf3537Syasuoka 
22260fbf3537Syasuoka 	if (ppp->realm == NULL)
22270fbf3537Syasuoka 		return NULL;
22280fbf3537Syasuoka 	if (!npppd_ppp_is_realm_radius(_this, ppp))
22290fbf3537Syasuoka 		return NULL;
22300fbf3537Syasuoka 
22310fbf3537Syasuoka 	return npppd_auth_radius_get_radius_req_setting(
22320fbf3537Syasuoka 	    (npppd_auth_radius *)ppp->realm);
22330fbf3537Syasuoka }
22340fbf3537Syasuoka 
2235f0a4e295Syasuoka /** Notice a failure on RAIDUS request/response */
22360fbf3537Syasuoka void
22370fbf3537Syasuoka npppd_radius_server_failure_notify(npppd *_this, npppd_ppp *ppp, void *rad_ctx,
22380fbf3537Syasuoka     const char *reason)
22390fbf3537Syasuoka {
22400fbf3537Syasuoka 	NPPPD_ASSERT(rad_ctx != NULL);
22410fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
22420fbf3537Syasuoka 
22430fbf3537Syasuoka 	npppd_auth_radius_server_failure_notify(
22440fbf3537Syasuoka 	    (npppd_auth_radius *)ppp->realm, radius_get_server_address(rad_ctx),
22450fbf3537Syasuoka 	    reason);
22460fbf3537Syasuoka }
22470fbf3537Syasuoka #endif
22480fbf3537Syasuoka 
2249f0a4e295Syasuoka /** Finalize authentication realm */
22500fbf3537Syasuoka static void
22510fbf3537Syasuoka npppd_auth_finalizer_periodic(npppd *_this)
22520fbf3537Syasuoka {
22530fbf3537Syasuoka 	int ndisposing = 0, refcnt;
22540fbf3537Syasuoka 	slist users;
22550fbf3537Syasuoka 	npppd_auth_base *auth_base;
22560fbf3537Syasuoka 	npppd_ppp *ppp;
22570fbf3537Syasuoka 
22580fbf3537Syasuoka 	/*
2259f0a4e295Syasuoka 	 * For the realms with disposing flag, if the realm has assigned PPPs,
2260f0a4e295Syasuoka 	 * disconnect them.  If all PPPs are disconnected then free the realm.
22610fbf3537Syasuoka 	 */
22620fbf3537Syasuoka 	NPPPD_DBG((DEBUG_LEVEL_2, "%s() called", __func__));
22630fbf3537Syasuoka 	slist_itr_first(&_this->realms);
22640fbf3537Syasuoka 	while (slist_itr_has_next(&_this->realms)) {
22650fbf3537Syasuoka 		auth_base = slist_itr_next(&_this->realms);
22660fbf3537Syasuoka 		if (!npppd_auth_is_disposing(auth_base))
22670fbf3537Syasuoka 			continue;
22680fbf3537Syasuoka 		refcnt = 0;
22690fbf3537Syasuoka 		if (ndisposing++ == 0) {
22700fbf3537Syasuoka 			slist_init(&users);
22710fbf3537Syasuoka 			if (npppd_get_all_users(_this, &users) != 0) {
22720fbf3537Syasuoka 				log_printf(LOG_WARNING,
22730fbf3537Syasuoka 				    "npppd_get_all_users() failed in %s(): %m",
22740fbf3537Syasuoka 				    __func__);
22750fbf3537Syasuoka 				break;
22760fbf3537Syasuoka 			}
22770fbf3537Syasuoka 		}
22780fbf3537Syasuoka 		slist_itr_first(&users);
22790fbf3537Syasuoka 		while (slist_itr_has_next(&users)) {
22800fbf3537Syasuoka 			ppp = slist_itr_next(&users);
22810fbf3537Syasuoka 			if (ppp->realm == auth_base) {
22820fbf3537Syasuoka 				refcnt++;
22830fbf3537Syasuoka 				ppp_stop(ppp, NULL);
22840fbf3537Syasuoka 				ppp_log(ppp, LOG_INFO,
22850fbf3537Syasuoka 				    "Stop request by npppd.  Binding "
22860fbf3537Syasuoka 				    "authentication realm is disposing.  "
22870fbf3537Syasuoka 				    "realm=%s", npppd_auth_get_name(auth_base));
22880fbf3537Syasuoka 				slist_itr_remove(&users);
22890fbf3537Syasuoka 			}
22900fbf3537Syasuoka 		}
22910fbf3537Syasuoka 		if (refcnt == 0)
22920fbf3537Syasuoka 			npppd_auth_destroy(auth_base);
22930fbf3537Syasuoka 	}
22940fbf3537Syasuoka 	if (ndisposing > 0)
22950fbf3537Syasuoka 		slist_fini(&users);
22960fbf3537Syasuoka }
22970fbf3537Syasuoka 
2298f0a4e295Syasuoka /** compare sockaddr_npppd.  return 0 if matches */
22990fbf3537Syasuoka int
23000fbf3537Syasuoka sockaddr_npppd_match(void *a0, void *b0)
23010fbf3537Syasuoka {
23020fbf3537Syasuoka 	struct sockaddr_npppd *a, *b;
23030fbf3537Syasuoka 
23040fbf3537Syasuoka 	a = a0;
23050fbf3537Syasuoka 	b = b0;
23060fbf3537Syasuoka 
23070fbf3537Syasuoka 	return (a->snp_addr.s_addr == b->snp_addr.s_addr)? 1 : 0;
23080fbf3537Syasuoka }
23090fbf3537Syasuoka 
23100fbf3537Syasuoka /**
2311f0a4e295Syasuoka  * This function stores the username for authentication to the space specified
2312f0a4e295Syasuoka  * by username_buffer and returns it.  username_buffer must have space more
2313f0a4e295Syasuoka  * than MAX_USERNAME_LENGTH.
23140fbf3537Syasuoka  */
23150fbf3537Syasuoka const char *
23160fbf3537Syasuoka npppd_ppp_get_username_for_auth(npppd *_this, npppd_ppp *ppp,
23170fbf3537Syasuoka     const char *username, char *username_buffer)
23180fbf3537Syasuoka {
23190fbf3537Syasuoka 	NPPPD_ASSERT(_this != NULL);
23200fbf3537Syasuoka 	NPPPD_ASSERT(ppp != NULL);
23210fbf3537Syasuoka 	NPPPD_ASSERT(ppp->realm != NULL);
23220fbf3537Syasuoka 
23230fbf3537Syasuoka 	return npppd_auth_username_for_auth(ppp->realm, username,
23240fbf3537Syasuoka 	    username_buffer);
23250fbf3537Syasuoka }
23260fbf3537Syasuoka 
23270fbf3537Syasuoka static inline void
23280fbf3537Syasuoka seed_random(long *seed)
23290fbf3537Syasuoka {
23300fbf3537Syasuoka 	struct timeval t;
23310fbf3537Syasuoka #ifdef KERN_URND
23320fbf3537Syasuoka 	size_t seedsiz;
23330fbf3537Syasuoka 	int mib[] = { CTL_KERN, KERN_URND };
23340fbf3537Syasuoka 
23350fbf3537Syasuoka 	seedsiz = sizeof(*seed);
23360fbf3537Syasuoka 	if (sysctl(mib, countof(mib), seed, &seedsiz, NULL, 0) == 0) {
23370fbf3537Syasuoka 		NPPPD_ASSERT(seedsiz == sizeof(long));
23380fbf3537Syasuoka 		return;
23390fbf3537Syasuoka 	}
23400fbf3537Syasuoka 	log_printf(LOG_WARNING, "Could not set random seed from the system: %m");
23410fbf3537Syasuoka #endif
23420fbf3537Syasuoka 	gettimeofday(&t, NULL);
23430fbf3537Syasuoka 	*seed = gethostid() ^ t.tv_sec ^ t.tv_usec ^ getpid();
23440fbf3537Syasuoka }
2345