xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.lib/pppoe/pppoed.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * PPPoE Server-mode daemon for use with Solaris PPP 4.0.
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
26*7c478bd9Sstevel@tonic-gate  * All rights reserved.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
34*7c478bd9Sstevel@tonic-gate #include <unistd.h>
35*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
38*7c478bd9Sstevel@tonic-gate #include <errno.h>
39*7c478bd9Sstevel@tonic-gate #include <signal.h>
40*7c478bd9Sstevel@tonic-gate #include <stropts.h>
41*7c478bd9Sstevel@tonic-gate #include <wait.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/resource.h>
43*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
44*7c478bd9Sstevel@tonic-gate #include <net/sppptun.h>
45*7c478bd9Sstevel@tonic-gate #include <net/pppoe.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #include "common.h"
48*7c478bd9Sstevel@tonic-gate #include "pppoed.h"
49*7c478bd9Sstevel@tonic-gate #include "logging.h"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate static int tunfd;		/* Global connection to tunnel device */
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate char *myname;			/* Copied from argv[0] for logging */
54*7c478bd9Sstevel@tonic-gate static int main_argc;		/* Saved for reparse on SIGHUP */
55*7c478bd9Sstevel@tonic-gate static char **main_argv;	/* Saved for reparse on SIGHUP */
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate static time_t time_started;	/* Time daemon was started; for debug */
58*7c478bd9Sstevel@tonic-gate static time_t last_reread;	/* Last time configuration was read. */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /* Various operational statistics. */
61*7c478bd9Sstevel@tonic-gate static unsigned long input_packets, padi_packets, padr_packets;
62*7c478bd9Sstevel@tonic-gate static unsigned long output_packets;
63*7c478bd9Sstevel@tonic-gate static unsigned long sessions_started;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate static sigset_t sigmask;	/* Global signal mask */
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate /*
68*7c478bd9Sstevel@tonic-gate  * Used for handling errors that occur before we daemonize.
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate static void
71*7c478bd9Sstevel@tonic-gate early_error(const char *str)
72*7c478bd9Sstevel@tonic-gate {
73*7c478bd9Sstevel@tonic-gate 	const char *cp;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 	cp = mystrerror(errno);
76*7c478bd9Sstevel@tonic-gate 	if (isatty(2)) {
77*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s: %s\n", myname, str, cp);
78*7c478bd9Sstevel@tonic-gate 	} else {
79*7c478bd9Sstevel@tonic-gate 		reopen_log();
80*7c478bd9Sstevel@tonic-gate 		logerr("%s: %s", str, cp);
81*7c478bd9Sstevel@tonic-gate 	}
82*7c478bd9Sstevel@tonic-gate 	exit(1);
83*7c478bd9Sstevel@tonic-gate }
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate /*
86*7c478bd9Sstevel@tonic-gate  * Open the sppptun driver.
87*7c478bd9Sstevel@tonic-gate  */
88*7c478bd9Sstevel@tonic-gate static void
89*7c478bd9Sstevel@tonic-gate open_tunnel_dev(void)
90*7c478bd9Sstevel@tonic-gate {
91*7c478bd9Sstevel@tonic-gate 	struct ppptun_peer ptp;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	tunfd = open(tunnam, O_RDWR);
94*7c478bd9Sstevel@tonic-gate 	if (tunfd == -1) {
95*7c478bd9Sstevel@tonic-gate 		early_error(tunnam);
96*7c478bd9Sstevel@tonic-gate 	}
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	/*
99*7c478bd9Sstevel@tonic-gate 	 * Tell the device driver that I'm a daemon handling inbound
100*7c478bd9Sstevel@tonic-gate 	 * connections, not a PPP session.
101*7c478bd9Sstevel@tonic-gate 	 */
102*7c478bd9Sstevel@tonic-gate 	(void) memset(&ptp, '\0', sizeof (ptp));
103*7c478bd9Sstevel@tonic-gate 	ptp.ptp_style = PTS_PPPOE;
104*7c478bd9Sstevel@tonic-gate 	ptp.ptp_flags = PTPF_DAEMON;
105*7c478bd9Sstevel@tonic-gate 	(void) memcpy(ptp.ptp_address.pta_pppoe.ptma_mac, ether_bcast,
106*7c478bd9Sstevel@tonic-gate 	    sizeof (ptp.ptp_address.pta_pppoe.ptma_mac));
107*7c478bd9Sstevel@tonic-gate 	if (strioctl(tunfd, PPPTUN_SPEER, &ptp, sizeof (ptp), sizeof (ptp)) <
108*7c478bd9Sstevel@tonic-gate 	    0) {
109*7c478bd9Sstevel@tonic-gate 		myperror("PPPTUN_SPEER");
110*7c478bd9Sstevel@tonic-gate 		exit(1);
111*7c478bd9Sstevel@tonic-gate 	}
112*7c478bd9Sstevel@tonic-gate }
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate /*
115*7c478bd9Sstevel@tonic-gate  * Callback function for fdwalk.  Closes everything but the tunnel
116*7c478bd9Sstevel@tonic-gate  * file descriptor when becoming daemon.  (Log file must be reopened
117*7c478bd9Sstevel@tonic-gate  * manually, since syslog file descriptor, if any, is unknown.)
118*7c478bd9Sstevel@tonic-gate  */
119*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
120*7c478bd9Sstevel@tonic-gate static int
121*7c478bd9Sstevel@tonic-gate fdcloser(void *arg, int fd)
122*7c478bd9Sstevel@tonic-gate {
123*7c478bd9Sstevel@tonic-gate 	if (fd != tunfd)
124*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
125*7c478bd9Sstevel@tonic-gate 	return (0);
126*7c478bd9Sstevel@tonic-gate }
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate /*
129*7c478bd9Sstevel@tonic-gate  * Become a daemon.
130*7c478bd9Sstevel@tonic-gate  */
131*7c478bd9Sstevel@tonic-gate static void
132*7c478bd9Sstevel@tonic-gate daemonize(void)
133*7c478bd9Sstevel@tonic-gate {
134*7c478bd9Sstevel@tonic-gate 	pid_t cpid;
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	/*
137*7c478bd9Sstevel@tonic-gate 	 * A little bit of magic here.  By the first fork+setsid, we
138*7c478bd9Sstevel@tonic-gate 	 * disconnect from our current controlling terminal and become
139*7c478bd9Sstevel@tonic-gate 	 * a session group leader.  By forking again without setsid,
140*7c478bd9Sstevel@tonic-gate 	 * we make certain that we're not the session group leader and
141*7c478bd9Sstevel@tonic-gate 	 * can never reacquire a controlling terminal.
142*7c478bd9Sstevel@tonic-gate 	 */
143*7c478bd9Sstevel@tonic-gate 	if ((cpid = fork()) == (pid_t)-1) {
144*7c478bd9Sstevel@tonic-gate 		early_error("fork 1");
145*7c478bd9Sstevel@tonic-gate 	}
146*7c478bd9Sstevel@tonic-gate 	if (cpid != 0) {
147*7c478bd9Sstevel@tonic-gate 		(void) wait(NULL);
148*7c478bd9Sstevel@tonic-gate 		_exit(0);
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 	if (setsid() == (pid_t)-1) {
151*7c478bd9Sstevel@tonic-gate 		early_error("setsid");
152*7c478bd9Sstevel@tonic-gate 	}
153*7c478bd9Sstevel@tonic-gate 	if ((cpid = fork()) == (pid_t)-1) {
154*7c478bd9Sstevel@tonic-gate 		early_error("fork 2");
155*7c478bd9Sstevel@tonic-gate 	}
156*7c478bd9Sstevel@tonic-gate 	if (cpid != 0) {
157*7c478bd9Sstevel@tonic-gate 		/* Parent just exits */
158*7c478bd9Sstevel@tonic-gate 		(void) printf("%d\n", (int)cpid);
159*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
160*7c478bd9Sstevel@tonic-gate 		_exit(0);
161*7c478bd9Sstevel@tonic-gate 	}
162*7c478bd9Sstevel@tonic-gate 	(void) chdir("/");
163*7c478bd9Sstevel@tonic-gate 	(void) umask(0);
164*7c478bd9Sstevel@tonic-gate 	(void) fdwalk(fdcloser, NULL);
165*7c478bd9Sstevel@tonic-gate 	reopen_log();
166*7c478bd9Sstevel@tonic-gate }
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate /*
169*7c478bd9Sstevel@tonic-gate  * Handle SIGHUP -- close and reopen non-syslog log files and reparse
170*7c478bd9Sstevel@tonic-gate  * options.
171*7c478bd9Sstevel@tonic-gate  */
172*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
173*7c478bd9Sstevel@tonic-gate static void
174*7c478bd9Sstevel@tonic-gate handle_hup(int sig)
175*7c478bd9Sstevel@tonic-gate {
176*7c478bd9Sstevel@tonic-gate 	close_log_files();
177*7c478bd9Sstevel@tonic-gate 	global_logging();
178*7c478bd9Sstevel@tonic-gate 	last_reread = time(NULL);
179*7c478bd9Sstevel@tonic-gate 	parse_options(tunfd, main_argc, main_argv);
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * Handle SIGINT -- write current daemon status to /tmp.
184*7c478bd9Sstevel@tonic-gate  */
185*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
186*7c478bd9Sstevel@tonic-gate static void
187*7c478bd9Sstevel@tonic-gate handle_int(int sig)
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate 	FILE *fp;
190*7c478bd9Sstevel@tonic-gate 	char dumpname[MAXPATHLEN];
191*7c478bd9Sstevel@tonic-gate 	time_t now;
192*7c478bd9Sstevel@tonic-gate 	struct rusage rusage;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	(void) snprintf(dumpname, sizeof (dumpname), "/tmp/pppoed.%ld",
195*7c478bd9Sstevel@tonic-gate 	    getpid());
196*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(dumpname, "w+")) == NULL) {
197*7c478bd9Sstevel@tonic-gate 		logerr("%s: %s", dumpname, mystrerror(errno));
198*7c478bd9Sstevel@tonic-gate 		return;
199*7c478bd9Sstevel@tonic-gate 	}
200*7c478bd9Sstevel@tonic-gate 	now = time(NULL);
201*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "pppoed running %s", ctime(&now));
202*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "Started on     %s", ctime(&time_started));
203*7c478bd9Sstevel@tonic-gate 	if (last_reread != 0)
204*7c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "Last reconfig  %s", ctime(&last_reread));
205*7c478bd9Sstevel@tonic-gate 	(void) putc('\n', fp);
206*7c478bd9Sstevel@tonic-gate 	if (getrusage(RUSAGE_SELF, &rusage) == 0) {
207*7c478bd9Sstevel@tonic-gate 		(void) fprintf(fp,
208*7c478bd9Sstevel@tonic-gate 		    "CPU usage:  user %ld.%06ld, system %ld.%06ld\n",
209*7c478bd9Sstevel@tonic-gate 		    rusage.ru_utime.tv_sec, rusage.ru_utime.tv_usec,
210*7c478bd9Sstevel@tonic-gate 		    rusage.ru_stime.tv_sec, rusage.ru_stime.tv_usec);
211*7c478bd9Sstevel@tonic-gate 	}
212*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "Packets:  %lu received (%lu PADI, %lu PADR), ",
213*7c478bd9Sstevel@tonic-gate 	    input_packets, padi_packets, padr_packets);
214*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%lu transmitted\n", output_packets);
215*7c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "Sessions started:  %lu\n\n", sessions_started);
216*7c478bd9Sstevel@tonic-gate 	dump_configuration(fp);
217*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
218*7c478bd9Sstevel@tonic-gate }
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate static void
221*7c478bd9Sstevel@tonic-gate add_signal_handlers(void)
222*7c478bd9Sstevel@tonic-gate {
223*7c478bd9Sstevel@tonic-gate 	struct sigaction sa;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sigmask);
226*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&sigmask, SIGHUP);
227*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&sigmask, SIGCHLD);
228*7c478bd9Sstevel@tonic-gate 	(void) sigaddset(&sigmask, SIGINT);
229*7c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &sigmask, NULL);
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	sa.sa_mask = sigmask;
232*7c478bd9Sstevel@tonic-gate 	sa.sa_flags = 0;
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	/* Signals to handle */
235*7c478bd9Sstevel@tonic-gate 	sa.sa_handler = handle_hup;
236*7c478bd9Sstevel@tonic-gate 	if (sigaction(SIGHUP, &sa, NULL) < 0)
237*7c478bd9Sstevel@tonic-gate 		early_error("sigaction HUP");
238*7c478bd9Sstevel@tonic-gate 	sa.sa_handler = handle_int;
239*7c478bd9Sstevel@tonic-gate 	if (sigaction(SIGINT, &sa, NULL) < 0)
240*7c478bd9Sstevel@tonic-gate 		early_error("sigaction INT");
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	/*
243*7c478bd9Sstevel@tonic-gate 	 * Signals to ignore.  Ignoring SIGCHLD in this way makes the
244*7c478bd9Sstevel@tonic-gate 	 * children exit without ever creating zombies.  (No wait(2)
245*7c478bd9Sstevel@tonic-gate 	 * call required.)
246*7c478bd9Sstevel@tonic-gate 	 */
247*7c478bd9Sstevel@tonic-gate 	sa.sa_handler = SIG_IGN;
248*7c478bd9Sstevel@tonic-gate 	if (sigaction(SIGPIPE, &sa, NULL) < 0)
249*7c478bd9Sstevel@tonic-gate 		early_error("sigaction PIPE");
250*7c478bd9Sstevel@tonic-gate 	sa.sa_flags = SA_NOCLDWAIT;
251*7c478bd9Sstevel@tonic-gate 	if (sigaction(SIGCHLD, &sa, NULL) < 0)
252*7c478bd9Sstevel@tonic-gate 		early_error("sigaction CHLD");
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate /*
256*7c478bd9Sstevel@tonic-gate  * Dispatch a message from the tunnel driver.  It could be an actual
257*7c478bd9Sstevel@tonic-gate  * PPPoE message or just an event notification.
258*7c478bd9Sstevel@tonic-gate  */
259*7c478bd9Sstevel@tonic-gate static void
260*7c478bd9Sstevel@tonic-gate handle_input(uint32_t *ctrlbuf, int ctrllen, uint32_t *databuf, int datalen)
261*7c478bd9Sstevel@tonic-gate {
262*7c478bd9Sstevel@tonic-gate 	poep_t *poep = (poep_t *)databuf;
263*7c478bd9Sstevel@tonic-gate 	union ppptun_name ptn;
264*7c478bd9Sstevel@tonic-gate 	int retv;
265*7c478bd9Sstevel@tonic-gate 	struct strbuf ctrl;
266*7c478bd9Sstevel@tonic-gate 	struct strbuf data;
267*7c478bd9Sstevel@tonic-gate 	void *srvp;
268*7c478bd9Sstevel@tonic-gate 	boolean_t launch;
269*7c478bd9Sstevel@tonic-gate 	struct ppptun_control *ptc;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	if (ctrllen != sizeof (*ptc)) {
272*7c478bd9Sstevel@tonic-gate 		logdbg("bogus %d byte control message from driver",
273*7c478bd9Sstevel@tonic-gate 		    ctrllen);
274*7c478bd9Sstevel@tonic-gate 		return;
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 	ptc = (struct ppptun_control *)ctrlbuf;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/* Switch out on event notifications. */
279*7c478bd9Sstevel@tonic-gate 	switch (ptc->ptc_action) {
280*7c478bd9Sstevel@tonic-gate 	case PTCA_TEST:
281*7c478bd9Sstevel@tonic-gate 		logdbg("test reply for discriminator %X", ptc->ptc_discrim);
282*7c478bd9Sstevel@tonic-gate 		return;
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	case PTCA_CONTROL:
285*7c478bd9Sstevel@tonic-gate 		break;
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	case PTCA_DISCONNECT:
288*7c478bd9Sstevel@tonic-gate 		logdbg("session %d disconnected on %s; send PADT",
289*7c478bd9Sstevel@tonic-gate 		    ptc->ptc_rsessid, ptc->ptc_name);
290*7c478bd9Sstevel@tonic-gate 		poep = poe_mkheader(pkt_output, POECODE_PADT,
291*7c478bd9Sstevel@tonic-gate 		    ptc->ptc_rsessid);
292*7c478bd9Sstevel@tonic-gate 		ptc->ptc_action = PTCA_CONTROL;
293*7c478bd9Sstevel@tonic-gate 		ctrl.len = sizeof (*ptc);
294*7c478bd9Sstevel@tonic-gate 		ctrl.buf = (caddr_t)ptc;
295*7c478bd9Sstevel@tonic-gate 		data.len = poe_length(poep) + sizeof (*poep);
296*7c478bd9Sstevel@tonic-gate 		data.buf = (caddr_t)poep;
297*7c478bd9Sstevel@tonic-gate 		if (putmsg(tunfd, &ctrl, &data, 0) < 0) {
298*7c478bd9Sstevel@tonic-gate 			logerr("putmsg PADT: %s", mystrerror(errno));
299*7c478bd9Sstevel@tonic-gate 		} else {
300*7c478bd9Sstevel@tonic-gate 			output_packets++;
301*7c478bd9Sstevel@tonic-gate 		}
302*7c478bd9Sstevel@tonic-gate 		return;
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	case PTCA_UNPLUMB:
305*7c478bd9Sstevel@tonic-gate 		logdbg("%s unplumbed", ptc->ptc_name);
306*7c478bd9Sstevel@tonic-gate 		return;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	default:
309*7c478bd9Sstevel@tonic-gate 		logdbg("unexpected code %d from driver", ptc->ptc_action);
310*7c478bd9Sstevel@tonic-gate 		return;
311*7c478bd9Sstevel@tonic-gate 	}
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	/* Only PPPoE control messages get here. */
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	input_packets++;
316*7c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (*poep)) {
317*7c478bd9Sstevel@tonic-gate 		logdbg("incomplete PPPoE message from %s/%s",
318*7c478bd9Sstevel@tonic-gate 		    ehost(&ptc->ptc_address), ptc->ptc_name);
319*7c478bd9Sstevel@tonic-gate 		return;
320*7c478bd9Sstevel@tonic-gate 	}
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	/* Server handles only PADI and PADR; all others are ignored. */
323*7c478bd9Sstevel@tonic-gate 	if (poep->poep_code == POECODE_PADI) {
324*7c478bd9Sstevel@tonic-gate 		padi_packets++;
325*7c478bd9Sstevel@tonic-gate 	} else if (poep->poep_code == POECODE_PADR) {
326*7c478bd9Sstevel@tonic-gate 		padr_packets++;
327*7c478bd9Sstevel@tonic-gate 	} else {
328*7c478bd9Sstevel@tonic-gate 		loginfo("unexpected %s from %s",
329*7c478bd9Sstevel@tonic-gate 		    poe_codename(poep->poep_code), ehost(&ptc->ptc_address));
330*7c478bd9Sstevel@tonic-gate 		return;
331*7c478bd9Sstevel@tonic-gate 	}
332*7c478bd9Sstevel@tonic-gate 	logdbg("Recv from %s/%s: %s", ehost(&ptc->ptc_address), ptc->ptc_name,
333*7c478bd9Sstevel@tonic-gate 	    poe_codename(poep->poep_code));
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	/* Parse out service and formulate template reply. */
336*7c478bd9Sstevel@tonic-gate 	retv = locate_service(poep, datalen, ptc->ptc_name, &ptc->ptc_address,
337*7c478bd9Sstevel@tonic-gate 	    pkt_output, &srvp);
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	/* Continue formulating reply */
340*7c478bd9Sstevel@tonic-gate 	launch = B_FALSE;
341*7c478bd9Sstevel@tonic-gate 	if (retv != 1) {
342*7c478bd9Sstevel@tonic-gate 		/* Ignore initiation if we don't offer a service. */
343*7c478bd9Sstevel@tonic-gate 		if (retv <= 0 && poep->poep_code == POECODE_PADI) {
344*7c478bd9Sstevel@tonic-gate 			logdbg("no services; no reply");
345*7c478bd9Sstevel@tonic-gate 			return;
346*7c478bd9Sstevel@tonic-gate 		}
347*7c478bd9Sstevel@tonic-gate 		if (retv == 0)
348*7c478bd9Sstevel@tonic-gate 			(void) poe_add_str((poep_t *)pkt_output, POETT_NAMERR,
349*7c478bd9Sstevel@tonic-gate 			    "No such service.");
350*7c478bd9Sstevel@tonic-gate 	} else {
351*7c478bd9Sstevel@tonic-gate 		/* Exactly one service chosen; if it's PADR, then we start. */
352*7c478bd9Sstevel@tonic-gate 		if (poep->poep_code == POECODE_PADR) {
353*7c478bd9Sstevel@tonic-gate 			launch = B_TRUE;
354*7c478bd9Sstevel@tonic-gate 		}
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 	poep = (poep_t *)pkt_output;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	/* Select control interface for output. */
359*7c478bd9Sstevel@tonic-gate 	(void) strncpy(ptn.ptn_name, ptc->ptc_name, sizeof (ptn.ptn_name));
360*7c478bd9Sstevel@tonic-gate 	if (strioctl(tunfd, PPPTUN_SCTL, &ptn, sizeof (ptn), 0) < 0) {
361*7c478bd9Sstevel@tonic-gate 		logerr("PPPTUN_SCTL %s: %s", ptn.ptn_name, mystrerror(errno));
362*7c478bd9Sstevel@tonic-gate 		return;
363*7c478bd9Sstevel@tonic-gate 	}
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	/* Launch the PPP service */
366*7c478bd9Sstevel@tonic-gate 	if (launch && launch_service(tunfd, poep, srvp, ptc))
367*7c478bd9Sstevel@tonic-gate 		sessions_started++;
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	/* Send the reply. */
370*7c478bd9Sstevel@tonic-gate 	ctrl.len = sizeof (*ptc);
371*7c478bd9Sstevel@tonic-gate 	ctrl.buf = (caddr_t)ptc;
372*7c478bd9Sstevel@tonic-gate 	data.len = poe_length(poep) + sizeof (*poep);
373*7c478bd9Sstevel@tonic-gate 	data.buf = (caddr_t)poep;
374*7c478bd9Sstevel@tonic-gate 	if (putmsg(tunfd, &ctrl, &data, 0) < 0) {
375*7c478bd9Sstevel@tonic-gate 		logerr("putmsg %s: %s", ptc->ptc_name, mystrerror(errno));
376*7c478bd9Sstevel@tonic-gate 	} else {
377*7c478bd9Sstevel@tonic-gate 		output_packets++;
378*7c478bd9Sstevel@tonic-gate 		logdbg("Send to   %s/%s: %s", ehost(&ptc->ptc_address),
379*7c478bd9Sstevel@tonic-gate 		    ptc->ptc_name, poe_codename(poep->poep_code));
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate }
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate static void
384*7c478bd9Sstevel@tonic-gate main_loop(void)
385*7c478bd9Sstevel@tonic-gate {
386*7c478bd9Sstevel@tonic-gate 	struct strbuf ctrl;
387*7c478bd9Sstevel@tonic-gate 	struct strbuf data;
388*7c478bd9Sstevel@tonic-gate 	int flags;
389*7c478bd9Sstevel@tonic-gate 	int rc;
390*7c478bd9Sstevel@tonic-gate 	int err;
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	for (;;) {
393*7c478bd9Sstevel@tonic-gate 		ctrl.maxlen = PKT_OCTL_LEN;
394*7c478bd9Sstevel@tonic-gate 		ctrl.buf = (caddr_t)pkt_octl;
395*7c478bd9Sstevel@tonic-gate 		data.maxlen = PKT_INPUT_LEN;
396*7c478bd9Sstevel@tonic-gate 		data.buf = (caddr_t)pkt_input;
397*7c478bd9Sstevel@tonic-gate 		/* Allow signals only while idle */
398*7c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
399*7c478bd9Sstevel@tonic-gate 		errno = 0;
400*7c478bd9Sstevel@tonic-gate 		flags = 0;
401*7c478bd9Sstevel@tonic-gate 		rc = mygetmsg(tunfd, &ctrl, &data, &flags);
402*7c478bd9Sstevel@tonic-gate 		err = errno;
403*7c478bd9Sstevel@tonic-gate 		/*
404*7c478bd9Sstevel@tonic-gate 		 * Block signals -- data structures must not change
405*7c478bd9Sstevel@tonic-gate 		 * while we're busy dispatching the client's request
406*7c478bd9Sstevel@tonic-gate 		 */
407*7c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_BLOCK, &sigmask, NULL);
408*7c478bd9Sstevel@tonic-gate 		if (rc == -1) {
409*7c478bd9Sstevel@tonic-gate 			if (err == EAGAIN || err == EINTR)
410*7c478bd9Sstevel@tonic-gate 				continue;
411*7c478bd9Sstevel@tonic-gate 			logerr("%s getmsg: %s", tunnam, mystrerror(err));
412*7c478bd9Sstevel@tonic-gate 			exit(1);
413*7c478bd9Sstevel@tonic-gate 		}
414*7c478bd9Sstevel@tonic-gate 		if (rc > 0)
415*7c478bd9Sstevel@tonic-gate 			logwarn("%s returned truncated data", tunnam);
416*7c478bd9Sstevel@tonic-gate 		else
417*7c478bd9Sstevel@tonic-gate 			handle_input(pkt_octl, ctrl.len, pkt_input, data.len);
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate }
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate int
422*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
423*7c478bd9Sstevel@tonic-gate {
424*7c478bd9Sstevel@tonic-gate 	prog_name = "pppoed";
425*7c478bd9Sstevel@tonic-gate 	log_level = 1;		/* Default to error messages only at first */
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	time_started = time(NULL);
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	if ((myname = argv[0]) == NULL)
430*7c478bd9Sstevel@tonic-gate 		myname = "pppoed";
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	main_argc = argc;
433*7c478bd9Sstevel@tonic-gate 	main_argv = argv;
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	open_tunnel_dev();
436*7c478bd9Sstevel@tonic-gate 	add_signal_handlers();
437*7c478bd9Sstevel@tonic-gate 	daemonize();
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	parse_options(tunfd, argc, argv);
440*7c478bd9Sstevel@tonic-gate 	main_loop();
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	return (0);
443*7c478bd9Sstevel@tonic-gate }
444