xref: /titanic_52/usr/src/cmd/cmd-inet/usr.lib/pppoe/pppoed.c (revision f53eecf557986dac6ededb388fedd6ca63be0350)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*f53eecf5SJames Carlson  * Common Development and Distribution License (the "License").
6*f53eecf5SJames Carlson  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  * PPPoE Server-mode daemon for use with Solaris PPP 4.0.
237c478bd9Sstevel@tonic-gate  *
24*f53eecf5SJames Carlson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25*f53eecf5SJames Carlson  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/stat.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <signal.h>
377c478bd9Sstevel@tonic-gate #include <stropts.h>
387c478bd9Sstevel@tonic-gate #include <wait.h>
397c478bd9Sstevel@tonic-gate #include <sys/resource.h>
407c478bd9Sstevel@tonic-gate #include <netinet/in.h>
417c478bd9Sstevel@tonic-gate #include <net/sppptun.h>
427c478bd9Sstevel@tonic-gate #include <net/pppoe.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include "common.h"
457c478bd9Sstevel@tonic-gate #include "pppoed.h"
467c478bd9Sstevel@tonic-gate #include "logging.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static int tunfd;		/* Global connection to tunnel device */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate char *myname;			/* Copied from argv[0] for logging */
517c478bd9Sstevel@tonic-gate static int main_argc;		/* Saved for reparse on SIGHUP */
527c478bd9Sstevel@tonic-gate static char **main_argv;	/* Saved for reparse on SIGHUP */
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate static time_t time_started;	/* Time daemon was started; for debug */
557c478bd9Sstevel@tonic-gate static time_t last_reread;	/* Last time configuration was read. */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /* Various operational statistics. */
587c478bd9Sstevel@tonic-gate static unsigned long input_packets, padi_packets, padr_packets;
597c478bd9Sstevel@tonic-gate static unsigned long output_packets;
607c478bd9Sstevel@tonic-gate static unsigned long sessions_started;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static sigset_t sigmask;	/* Global signal mask */
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * Used for handling errors that occur before we daemonize.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate static void
687c478bd9Sstevel@tonic-gate early_error(const char *str)
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate 	const char *cp;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	cp = mystrerror(errno);
737c478bd9Sstevel@tonic-gate 	if (isatty(2)) {
747c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s: %s\n", myname, str, cp);
757c478bd9Sstevel@tonic-gate 	} else {
767c478bd9Sstevel@tonic-gate 		reopen_log();
777c478bd9Sstevel@tonic-gate 		logerr("%s: %s", str, cp);
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate 	exit(1);
807c478bd9Sstevel@tonic-gate }
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate  * Open the sppptun driver.
847c478bd9Sstevel@tonic-gate  */
857c478bd9Sstevel@tonic-gate static void
867c478bd9Sstevel@tonic-gate open_tunnel_dev(void)
877c478bd9Sstevel@tonic-gate {
887c478bd9Sstevel@tonic-gate 	struct ppptun_peer ptp;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	tunfd = open(tunnam, O_RDWR);
917c478bd9Sstevel@tonic-gate 	if (tunfd == -1) {
927c478bd9Sstevel@tonic-gate 		early_error(tunnam);
937c478bd9Sstevel@tonic-gate 	}
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	/*
967c478bd9Sstevel@tonic-gate 	 * Tell the device driver that I'm a daemon handling inbound
977c478bd9Sstevel@tonic-gate 	 * connections, not a PPP session.
987c478bd9Sstevel@tonic-gate 	 */
997c478bd9Sstevel@tonic-gate 	(void) memset(&ptp, '\0', sizeof (ptp));
1007c478bd9Sstevel@tonic-gate 	ptp.ptp_style = PTS_PPPOE;
1017c478bd9Sstevel@tonic-gate 	ptp.ptp_flags = PTPF_DAEMON;
1027c478bd9Sstevel@tonic-gate 	(void) memcpy(ptp.ptp_address.pta_pppoe.ptma_mac, ether_bcast,
1037c478bd9Sstevel@tonic-gate 	    sizeof (ptp.ptp_address.pta_pppoe.ptma_mac));
1047c478bd9Sstevel@tonic-gate 	if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) <
1057c478bd9Sstevel@tonic-gate 	    0) {
1067c478bd9Sstevel@tonic-gate 		myperror("PPPTUN_SPEER");
1077c478bd9Sstevel@tonic-gate 		exit(1);
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Callback function for fdwalk.  Closes everything but the tunnel
1137c478bd9Sstevel@tonic-gate  * file descriptor when becoming daemon.  (Log file must be reopened
1147c478bd9Sstevel@tonic-gate  * manually, since syslog file descriptor, if any, is unknown.)
1157c478bd9Sstevel@tonic-gate  */
1167c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1177c478bd9Sstevel@tonic-gate static int
1187c478bd9Sstevel@tonic-gate fdcloser(void *arg, int fd)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	if (fd != tunfd)
1217c478bd9Sstevel@tonic-gate 		(void) close(fd);
1227c478bd9Sstevel@tonic-gate 	return (0);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Become a daemon.
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate static void
1297c478bd9Sstevel@tonic-gate daemonize(void)
1307c478bd9Sstevel@tonic-gate {
1317c478bd9Sstevel@tonic-gate 	pid_t cpid;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	/*
1347c478bd9Sstevel@tonic-gate 	 * A little bit of magic here.  By the first fork+setsid, we
1357c478bd9Sstevel@tonic-gate 	 * disconnect from our current controlling terminal and become
1367c478bd9Sstevel@tonic-gate 	 * a session group leader.  By forking again without setsid,
1377c478bd9Sstevel@tonic-gate 	 * we make certain that we're not the session group leader and
1387c478bd9Sstevel@tonic-gate 	 * can never reacquire a controlling terminal.
1397c478bd9Sstevel@tonic-gate 	 */
1407c478bd9Sstevel@tonic-gate 	if ((cpid = fork()) == (pid_t)-1) {
1417c478bd9Sstevel@tonic-gate 		early_error("fork 1");
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 	if (cpid != 0) {
1447c478bd9Sstevel@tonic-gate 		(void) wait(NULL);
1457c478bd9Sstevel@tonic-gate 		_exit(0);
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 	if (setsid() == (pid_t)-1) {
1487c478bd9Sstevel@tonic-gate 		early_error("setsid");
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 	if ((cpid = fork()) == (pid_t)-1) {
1517c478bd9Sstevel@tonic-gate 		early_error("fork 2");
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 	if (cpid != 0) {
1547c478bd9Sstevel@tonic-gate 		/* Parent just exits */
1557c478bd9Sstevel@tonic-gate 		(void) printf("%d\n", (int)cpid);
1567c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
1577c478bd9Sstevel@tonic-gate 		_exit(0);
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate 	(void) chdir("/");
1607c478bd9Sstevel@tonic-gate 	(void) umask(0);
1617c478bd9Sstevel@tonic-gate 	(void) fdwalk(fdcloser, NULL);
1627c478bd9Sstevel@tonic-gate 	reopen_log();
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * Handle SIGHUP -- close and reopen non-syslog log files and reparse
1677c478bd9Sstevel@tonic-gate  * options.
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1707c478bd9Sstevel@tonic-gate static void
1717c478bd9Sstevel@tonic-gate handle_hup(int sig)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	close_log_files();
1747c478bd9Sstevel@tonic-gate 	global_logging();
1757c478bd9Sstevel@tonic-gate 	last_reread = time(NULL);
1767c478bd9Sstevel@tonic-gate 	parse_options(tunfd, main_argc, main_argv);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate  * Handle SIGINT -- write current daemon status to /tmp.
1817c478bd9Sstevel@tonic-gate  */
1827c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1837c478bd9Sstevel@tonic-gate static void
1847c478bd9Sstevel@tonic-gate handle_int(int sig)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	FILE *fp;
1877c478bd9Sstevel@tonic-gate 	char dumpname[MAXPATHLEN];
1887c478bd9Sstevel@tonic-gate 	time_t now;
1897c478bd9Sstevel@tonic-gate 	struct rusage rusage;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	(void) snprintf(dumpname, sizeof (dumpname), "/tmp/pppoed.%ld",
1927c478bd9Sstevel@tonic-gate 	    getpid());
1937c478bd9Sstevel@tonic-gate 	if ((fp = fopen(dumpname, "w+")) == NULL) {
1947c478bd9Sstevel@tonic-gate 		logerr("%s: %s", dumpname, mystrerror(errno));
1957c478bd9Sstevel@tonic-gate 		return;
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 	now = time(NULL);
1987c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "pppoed running %s", ctime(&now));
1997c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "Started on     %s", ctime(&time_started));
2007c478bd9Sstevel@tonic-gate 	if (last_reread != 0)
2017c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "Last reconfig  %s", ctime(&last_reread));
2027c478bd9Sstevel@tonic-gate 	(void) putc('\n', fp);
2037c478bd9Sstevel@tonic-gate 	if (getrusage(RUSAGE_SELF, &rusage) == 0) {
2047c478bd9Sstevel@tonic-gate 		(void) fprintf(fp,
2057c478bd9Sstevel@tonic-gate 		    "CPU usage:  user %ld.%06ld, system %ld.%06ld\n",
2067c478bd9Sstevel@tonic-gate 		    rusage.ru_utime.tv_sec, rusage.ru_utime.tv_usec,
2077c478bd9Sstevel@tonic-gate 		    rusage.ru_stime.tv_sec, rusage.ru_stime.tv_usec);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "Packets:  %lu received (%lu PADI, %lu PADR), ",
2107c478bd9Sstevel@tonic-gate 	    input_packets, padi_packets, padr_packets);
2117c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%lu transmitted\n", output_packets);
2127c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "Sessions started:  %lu\n\n", sessions_started);
2137c478bd9Sstevel@tonic-gate 	dump_configuration(fp);
2147c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate static void
2187c478bd9Sstevel@tonic-gate add_signal_handlers(void)
2197c478bd9Sstevel@tonic-gate {
2207c478bd9Sstevel@tonic-gate 	struct sigaction sa;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sigmask);
2237c478bd9Sstevel@tonic-gate 	(void) sigaddset(&sigmask, SIGHUP);
2247c478bd9Sstevel@tonic-gate 	(void) sigaddset(&sigmask, SIGCHLD);
2257c478bd9Sstevel@tonic-gate 	(void) sigaddset(&sigmask, SIGINT);
2267c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &sigmask, NULL);
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	sa.sa_mask = sigmask;
2297c478bd9Sstevel@tonic-gate 	sa.sa_flags = 0;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	/* Signals to handle */
2327c478bd9Sstevel@tonic-gate 	sa.sa_handler = handle_hup;
2337c478bd9Sstevel@tonic-gate 	if (sigaction(SIGHUP, &sa, NULL) < 0)
2347c478bd9Sstevel@tonic-gate 		early_error("sigaction HUP");
2357c478bd9Sstevel@tonic-gate 	sa.sa_handler = handle_int;
2367c478bd9Sstevel@tonic-gate 	if (sigaction(SIGINT, &sa, NULL) < 0)
2377c478bd9Sstevel@tonic-gate 		early_error("sigaction INT");
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	/*
2407c478bd9Sstevel@tonic-gate 	 * Signals to ignore.  Ignoring SIGCHLD in this way makes the
2417c478bd9Sstevel@tonic-gate 	 * children exit without ever creating zombies.  (No wait(2)
2427c478bd9Sstevel@tonic-gate 	 * call required.)
2437c478bd9Sstevel@tonic-gate 	 */
2447c478bd9Sstevel@tonic-gate 	sa.sa_handler = SIG_IGN;
2457c478bd9Sstevel@tonic-gate 	if (sigaction(SIGPIPE, &sa, NULL) < 0)
2467c478bd9Sstevel@tonic-gate 		early_error("sigaction PIPE");
2477c478bd9Sstevel@tonic-gate 	sa.sa_flags = SA_NOCLDWAIT;
2487c478bd9Sstevel@tonic-gate 	if (sigaction(SIGCHLD, &sa, NULL) < 0)
2497c478bd9Sstevel@tonic-gate 		early_error("sigaction CHLD");
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate  * Dispatch a message from the tunnel driver.  It could be an actual
2547c478bd9Sstevel@tonic-gate  * PPPoE message or just an event notification.
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate static void
2577c478bd9Sstevel@tonic-gate handle_input(uint32_t *ctrlbuf, int ctrllen, uint32_t *databuf, int datalen)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	poep_t *poep = (poep_t *)databuf;
2607c478bd9Sstevel@tonic-gate 	union ppptun_name ptn;
2617c478bd9Sstevel@tonic-gate 	int retv;
2627c478bd9Sstevel@tonic-gate 	struct strbuf ctrl;
2637c478bd9Sstevel@tonic-gate 	struct strbuf data;
2647c478bd9Sstevel@tonic-gate 	void *srvp;
2657c478bd9Sstevel@tonic-gate 	boolean_t launch;
2667c478bd9Sstevel@tonic-gate 	struct ppptun_control *ptc;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if (ctrllen != sizeof (*ptc)) {
2697c478bd9Sstevel@tonic-gate 		logdbg("bogus %d byte control message from driver",
2707c478bd9Sstevel@tonic-gate 		    ctrllen);
2717c478bd9Sstevel@tonic-gate 		return;
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 	ptc = (struct ppptun_control *)ctrlbuf;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/* Switch out on event notifications. */
2767c478bd9Sstevel@tonic-gate 	switch (ptc->ptc_action) {
2777c478bd9Sstevel@tonic-gate 	case PTCA_TEST:
2787c478bd9Sstevel@tonic-gate 		logdbg("test reply for discriminator %X", ptc->ptc_discrim);
2797c478bd9Sstevel@tonic-gate 		return;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	case PTCA_CONTROL:
2827c478bd9Sstevel@tonic-gate 		break;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	case PTCA_DISCONNECT:
2857c478bd9Sstevel@tonic-gate 		logdbg("session %d disconnected on %s; send PADT",
2867c478bd9Sstevel@tonic-gate 		    ptc->ptc_rsessid, ptc->ptc_name);
2877c478bd9Sstevel@tonic-gate 		poep = poe_mkheader(pkt_output, POECODE_PADT,
2887c478bd9Sstevel@tonic-gate 		    ptc->ptc_rsessid);
2897c478bd9Sstevel@tonic-gate 		ptc->ptc_action = PTCA_CONTROL;
2907c478bd9Sstevel@tonic-gate 		ctrl.len = sizeof (*ptc);
2917c478bd9Sstevel@tonic-gate 		ctrl.buf = (caddr_t)ptc;
2927c478bd9Sstevel@tonic-gate 		data.len = poe_length(poep) + sizeof (*poep);
2937c478bd9Sstevel@tonic-gate 		data.buf = (caddr_t)poep;
2947c478bd9Sstevel@tonic-gate 		if (putmsg(tunfd, &ctrl, &data, 0) < 0) {
2957c478bd9Sstevel@tonic-gate 			logerr("putmsg PADT: %s", mystrerror(errno));
2967c478bd9Sstevel@tonic-gate 		} else {
2977c478bd9Sstevel@tonic-gate 			output_packets++;
2987c478bd9Sstevel@tonic-gate 		}
2997c478bd9Sstevel@tonic-gate 		return;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	case PTCA_UNPLUMB:
3027c478bd9Sstevel@tonic-gate 		logdbg("%s unplumbed", ptc->ptc_name);
3037c478bd9Sstevel@tonic-gate 		return;
3047c478bd9Sstevel@tonic-gate 
305*f53eecf5SJames Carlson 	case PTCA_BADCTRL:
306*f53eecf5SJames Carlson 		logwarn("bad control data on %s for session %u", ptc->ptc_name,
307*f53eecf5SJames Carlson 		    ptc->ptc_rsessid);
308*f53eecf5SJames Carlson 		return;
309*f53eecf5SJames Carlson 
3107c478bd9Sstevel@tonic-gate 	default:
3117c478bd9Sstevel@tonic-gate 		logdbg("unexpected code %d from driver", ptc->ptc_action);
3127c478bd9Sstevel@tonic-gate 		return;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/* Only PPPoE control messages get here. */
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	input_packets++;
3187c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (*poep)) {
3197c478bd9Sstevel@tonic-gate 		logdbg("incomplete PPPoE message from %s/%s",
3207c478bd9Sstevel@tonic-gate 		    ehost(&ptc->ptc_address), ptc->ptc_name);
3217c478bd9Sstevel@tonic-gate 		return;
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	/* Server handles only PADI and PADR; all others are ignored. */
3257c478bd9Sstevel@tonic-gate 	if (poep->poep_code == POECODE_PADI) {
3267c478bd9Sstevel@tonic-gate 		padi_packets++;
3277c478bd9Sstevel@tonic-gate 	} else if (poep->poep_code == POECODE_PADR) {
3287c478bd9Sstevel@tonic-gate 		padr_packets++;
3297c478bd9Sstevel@tonic-gate 	} else {
3307c478bd9Sstevel@tonic-gate 		loginfo("unexpected %s from %s",
3317c478bd9Sstevel@tonic-gate 		    poe_codename(poep->poep_code), ehost(&ptc->ptc_address));
3327c478bd9Sstevel@tonic-gate 		return;
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 	logdbg("Recv from %s/%s: %s", ehost(&ptc->ptc_address), ptc->ptc_name,
3357c478bd9Sstevel@tonic-gate 	    poe_codename(poep->poep_code));
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	/* Parse out service and formulate template reply. */
3387c478bd9Sstevel@tonic-gate 	retv = locate_service(poep, datalen, ptc->ptc_name, &ptc->ptc_address,
3397c478bd9Sstevel@tonic-gate 	    pkt_output, &srvp);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	/* Continue formulating reply */
3427c478bd9Sstevel@tonic-gate 	launch = B_FALSE;
3437c478bd9Sstevel@tonic-gate 	if (retv != 1) {
3447c478bd9Sstevel@tonic-gate 		/* Ignore initiation if we don't offer a service. */
3457c478bd9Sstevel@tonic-gate 		if (retv <= 0 && poep->poep_code == POECODE_PADI) {
3467c478bd9Sstevel@tonic-gate 			logdbg("no services; no reply");
3477c478bd9Sstevel@tonic-gate 			return;
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 		if (retv == 0)
3507c478bd9Sstevel@tonic-gate 			(void) poe_add_str((poep_t *)pkt_output, POETT_NAMERR,
3517c478bd9Sstevel@tonic-gate 			    "No such service.");
3527c478bd9Sstevel@tonic-gate 	} else {
3537c478bd9Sstevel@tonic-gate 		/* Exactly one service chosen; if it's PADR, then we start. */
3547c478bd9Sstevel@tonic-gate 		if (poep->poep_code == POECODE_PADR) {
3557c478bd9Sstevel@tonic-gate 			launch = B_TRUE;
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	poep = (poep_t *)pkt_output;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/* Select control interface for output. */
3617c478bd9Sstevel@tonic-gate 	(void) strncpy(ptn.ptn_name, ptc->ptc_name, sizeof (ptn.ptn_name));
3627c478bd9Sstevel@tonic-gate 	if (strioctl(tunfd, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0) {
3637c478bd9Sstevel@tonic-gate 		logerr("PPPTUN_SCTL %s: %s", ptn.ptn_name, mystrerror(errno));
3647c478bd9Sstevel@tonic-gate 		return;
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	/* Launch the PPP service */
3687c478bd9Sstevel@tonic-gate 	if (launch && launch_service(tunfd, poep, srvp, ptc))
3697c478bd9Sstevel@tonic-gate 		sessions_started++;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	/* Send the reply. */
3727c478bd9Sstevel@tonic-gate 	ctrl.len = sizeof (*ptc);
3737c478bd9Sstevel@tonic-gate 	ctrl.buf = (caddr_t)ptc;
3747c478bd9Sstevel@tonic-gate 	data.len = poe_length(poep) + sizeof (*poep);
3757c478bd9Sstevel@tonic-gate 	data.buf = (caddr_t)poep;
3767c478bd9Sstevel@tonic-gate 	if (putmsg(tunfd, &ctrl, &data, 0) < 0) {
3777c478bd9Sstevel@tonic-gate 		logerr("putmsg %s: %s", ptc->ptc_name, mystrerror(errno));
3787c478bd9Sstevel@tonic-gate 	} else {
3797c478bd9Sstevel@tonic-gate 		output_packets++;
3807c478bd9Sstevel@tonic-gate 		logdbg("Send to   %s/%s: %s", ehost(&ptc->ptc_address),
3817c478bd9Sstevel@tonic-gate 		    ptc->ptc_name, poe_codename(poep->poep_code));
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate static void
3867c478bd9Sstevel@tonic-gate main_loop(void)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate 	struct strbuf ctrl;
3897c478bd9Sstevel@tonic-gate 	struct strbuf data;
3907c478bd9Sstevel@tonic-gate 	int flags;
3917c478bd9Sstevel@tonic-gate 	int rc;
3927c478bd9Sstevel@tonic-gate 	int err;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	for (;;) {
3957c478bd9Sstevel@tonic-gate 		ctrl.maxlen = PKT_OCTL_LEN;
3967c478bd9Sstevel@tonic-gate 		ctrl.buf = (caddr_t)pkt_octl;
3977c478bd9Sstevel@tonic-gate 		data.maxlen = PKT_INPUT_LEN;
3987c478bd9Sstevel@tonic-gate 		data.buf = (caddr_t)pkt_input;
3997c478bd9Sstevel@tonic-gate 		/* Allow signals only while idle */
4007c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
4017c478bd9Sstevel@tonic-gate 		errno = 0;
4027c478bd9Sstevel@tonic-gate 		flags = 0;
4037c478bd9Sstevel@tonic-gate 		rc = mygetmsg(tunfd, &ctrl, &data, &flags);
4047c478bd9Sstevel@tonic-gate 		err = errno;
4057c478bd9Sstevel@tonic-gate 		/*
4067c478bd9Sstevel@tonic-gate 		 * Block signals -- data structures must not change
4077c478bd9Sstevel@tonic-gate 		 * while we're busy dispatching the client's request
4087c478bd9Sstevel@tonic-gate 		 */
4097c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_BLOCK, &sigmask, NULL);
4107c478bd9Sstevel@tonic-gate 		if (rc == -1) {
4117c478bd9Sstevel@tonic-gate 			if (err == EAGAIN || err == EINTR)
4127c478bd9Sstevel@tonic-gate 				continue;
4137c478bd9Sstevel@tonic-gate 			logerr("%s getmsg: %s", tunnam, mystrerror(err));
4147c478bd9Sstevel@tonic-gate 			exit(1);
4157c478bd9Sstevel@tonic-gate 		}
4167c478bd9Sstevel@tonic-gate 		if (rc > 0)
4177c478bd9Sstevel@tonic-gate 			logwarn("%s returned truncated data", tunnam);
4187c478bd9Sstevel@tonic-gate 		else
4197c478bd9Sstevel@tonic-gate 			handle_input(pkt_octl, ctrl.len, pkt_input, data.len);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate int
4247c478bd9Sstevel@tonic-gate main(int argc, char **argv)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	prog_name = "pppoed";
4277c478bd9Sstevel@tonic-gate 	log_level = 1;		/* Default to error messages only at first */
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	time_started = time(NULL);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if ((myname = argv[0]) == NULL)
4327c478bd9Sstevel@tonic-gate 		myname = "pppoed";
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	main_argc = argc;
4357c478bd9Sstevel@tonic-gate 	main_argv = argv;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	open_tunnel_dev();
4387c478bd9Sstevel@tonic-gate 	add_signal_handlers();
4397c478bd9Sstevel@tonic-gate 	daemonize();
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	parse_options(tunfd, argc, argv);
4427c478bd9Sstevel@tonic-gate 	main_loop();
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	return (0);
4457c478bd9Sstevel@tonic-gate }
446