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
early_error(const char * str)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
open_tunnel_dev(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
fdcloser(void * arg,int fd)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
daemonize(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
handle_hup(int sig)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
handle_int(int sig)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
add_signal_handlers(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
handle_input(uint32_t * ctrlbuf,int ctrllen,uint32_t * databuf,int datalen)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
main_loop(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
main(int argc,char ** argv)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