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