/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* PPPoE Server-mode daemon for use with Solaris PPP 4.0.
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <stropts.h>
#include <wait.h>
#include <sys/resource.h>
#include "common.h"
#include "pppoed.h"
#include "logging.h"
/* Various operational statistics. */
static unsigned long output_packets;
static unsigned long sessions_started;
/*
* Used for handling errors that occur before we daemonize.
*/
static void
{
const char *cp;
if (isatty(2)) {
} else {
reopen_log();
}
exit(1);
}
/*
* Open the sppptun driver.
*/
static void
open_tunnel_dev(void)
{
if (tunfd == -1) {
}
/*
* Tell the device driver that I'm a daemon handling inbound
* connections, not a PPP session.
*/
0) {
myperror("PPPTUN_SPEER");
exit(1);
}
}
/*
* Callback function for fdwalk. Closes everything but the tunnel
* file descriptor when becoming daemon. (Log file must be reopened
* manually, since syslog file descriptor, if any, is unknown.)
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*
* Become a daemon.
*/
static void
daemonize(void)
{
/*
* A little bit of magic here. By the first fork+setsid, we
* disconnect from our current controlling terminal and become
* a session group leader. By forking again without setsid,
* we make certain that we're not the session group leader and
* can never reacquire a controlling terminal.
*/
early_error("fork 1");
}
if (cpid != 0) {
_exit(0);
}
early_error("setsid");
}
early_error("fork 2");
}
if (cpid != 0) {
/* Parent just exits */
_exit(0);
}
(void) chdir("/");
(void) umask(0);
reopen_log();
}
/*
* Handle SIGHUP -- close and reopen non-syslog log files and reparse
* options.
*/
/*ARGSUSED*/
static void
{
}
/*
* Handle SIGINT -- write current daemon status to /tmp.
*/
/*ARGSUSED*/
static void
{
getpid());
return;
}
if (last_reread != 0)
"CPU usage: user %ld.%06ld, system %ld.%06ld\n",
}
}
static void
add_signal_handlers(void)
{
(void) sigemptyset(&sigmask);
/* Signals to handle */
early_error("sigaction HUP");
early_error("sigaction INT");
/*
* Signals to ignore. Ignoring SIGCHLD in this way makes the
* children exit without ever creating zombies. (No wait(2)
* call required.)
*/
early_error("sigaction PIPE");
early_error("sigaction CHLD");
}
/*
* Dispatch a message from the tunnel driver. It could be an actual
* PPPoE message or just an event notification.
*/
static void
{
int retv;
void *srvp;
logdbg("bogus %d byte control message from driver",
ctrllen);
return;
}
/* Switch out on event notifications. */
switch (ptc->ptc_action) {
case PTCA_TEST:
return;
case PTCA_CONTROL:
break;
case PTCA_DISCONNECT:
logdbg("session %d disconnected on %s; send PADT",
ptc->ptc_rsessid);
} else {
}
return;
case PTCA_UNPLUMB:
return;
case PTCA_BADCTRL:
ptc->ptc_rsessid);
return;
default:
return;
}
/* Only PPPoE control messages get here. */
logdbg("incomplete PPPoE message from %s/%s",
return;
}
/* Server handles only PADI and PADR; all others are ignored. */
padi_packets++;
padr_packets++;
} else {
loginfo("unexpected %s from %s",
return;
}
/* Parse out service and formulate template reply. */
pkt_output, &srvp);
/* Continue formulating reply */
if (retv != 1) {
/* Ignore initiation if we don't offer a service. */
logdbg("no services; no reply");
return;
}
if (retv == 0)
"No such service.");
} else {
/* Exactly one service chosen; if it's PADR, then we start. */
}
}
/* Select control interface for output. */
return;
}
/* Launch the PPP service */
/* Send the reply. */
} else {
}
}
static void
main_loop(void)
{
int flags;
int rc;
int err;
for (;;) {
/* Allow signals only while idle */
errno = 0;
flags = 0;
/*
* Block signals -- data structures must not change
* while we're busy dispatching the client's request
*/
if (rc == -1) {
continue;
exit(1);
}
if (rc > 0)
else
}
}
int
{
prog_name = "pppoed";
myname = "pppoed";
daemonize();
main_loop();
return (0);
}