summaryrefslogtreecommitdiff
path: root/openwrt/package/l2tpd/patches/03-jacco-pty.patch
diff options
context:
space:
mode:
authornico <nico@3c298f89-4303-0410-b956-a3cf2f4a3e73>2005-12-16 12:00:19 +0000
committernico <nico@3c298f89-4303-0410-b956-a3cf2f4a3e73>2005-12-16 12:00:19 +0000
commit4fbbef031b45aa1184eac867688a5734dc3f0ef5 (patch)
tree44b8673f084adbc04a1a47cc93fb3ea12fb3e729 /openwrt/package/l2tpd/patches/03-jacco-pty.patch
parent64017a106d715a43e26a69b5b4e7b17eb9948281 (diff)
port l2tpd fixes from changeset:2696 to trunk.
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@2697 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'openwrt/package/l2tpd/patches/03-jacco-pty.patch')
-rw-r--r--openwrt/package/l2tpd/patches/03-jacco-pty.patch1194
1 files changed, 1194 insertions, 0 deletions
diff --git a/openwrt/package/l2tpd/patches/03-jacco-pty.patch b/openwrt/package/l2tpd/patches/03-jacco-pty.patch
new file mode 100644
index 0000000000..67169b8ead
--- /dev/null
+++ b/openwrt/package/l2tpd/patches/03-jacco-pty.patch
@@ -0,0 +1,1194 @@
+diff -ruN l2tpd-0.70pre-old/l2tpd.c l2tpd-0.70pre-new/l2tpd.c
+--- l2tpd-0.70pre-old/l2tpd.c 2005-12-16 12:34:12.000000000 +0100
++++ l2tpd-0.70pre-new/l2tpd.c 2005-12-16 12:34:54.000000000 +0100
+@@ -16,6 +16,7 @@
+ */
+
+ #include <stdlib.h>
++#include <sys/types.h>
+ #include <sys/utsname.h>
+ #include <sys/stat.h>
+ #include <sys/wait.h>
+@@ -274,8 +275,8 @@
+
+ int start_pppd (struct call *c, struct ppp_opts *opts)
+ {
+- char a, b;
+- char tty[80];
++ /* char a, b; */
++ char *tty;
+ char *stropt[80];
+ struct ppp_opts *p;
+ #ifdef USE_KERNEL
+@@ -324,12 +325,45 @@
+ else
+ {
+ #endif
+- if ((c->fd = getPtyMaster (&a, &b)) < 0)
++ c->fd = open("/dev/ptmx", O_RDWR);
++ if (c->fd == -1)
++ {
++ log (LOG_WARN, "%s: unable to open /dev/ptmx to allocate pty\n",
++ __FUNCTION__);
++ return -EINVAL;
++ } else
++ {
++ if (grantpt(c->fd))
++ {
++ log (LOG_WARN, "%s: unable to grantpt() on pty\n",
++ __FUNCTION__);
++ close(c->fd);
++ return -EINVAL;
++ }
++ if (unlockpt(c->fd))
++ {
++ log (LOG_WARN, "%s: unable to unlockpt() on pty\n",
++ __FUNCTION__);
++ close(c->fd);
++ return -EINVAL;
++ }
++ tty = ptsname(c->fd);
++ if (tty == NULL)
++ {
++ log (LOG_WARN, "%s: unable to obtain name of slave tty\n",
++ __FUNCTION__);
++ close(c->fd);
++ return -EINVAL;
++ }
++ }
++
++
++ /* if ((c->fd = getPtyMaster (&a, &b)) < 0)
+ {
+ log (LOG_WARN, "%s: unable to allocate pty, abandoning!\n",
+ __FUNCTION__);
+ return -EINVAL;
+- }
++ } */
+
+ /* set fd opened above to not echo so we don't see read our own packets
+ back of the file descriptor that we just wrote them to */
+@@ -338,8 +372,14 @@
+ ptyconf.c_cflag &= ~(ICANON | ECHO);
+ tcsetattr (c->fd, TCSANOW, &ptyconf);
+
+- snprintf (tty, sizeof (tty), "/dev/tty%c%c", a, b);
++/* snprintf (tty, sizeof (tty), "/dev/tty%c%c", a, b); */
+ fd2 = open (tty, O_RDWR);
++ if (fd2 == -1)
++ {
++ log (LOG_WARN, "%s: unable to open slave tty %s\n", __FUNCTION__, tty);
++ close(c->fd);
++ return -EINVAL;
++ }
+
+ #ifdef USE_KERNEL
+ }
+diff -ruN l2tpd-0.70pre-old/l2tpd.c.orig l2tpd-0.70pre-new/l2tpd.c.orig
+--- l2tpd-0.70pre-old/l2tpd.c.orig 1970-01-01 01:00:00.000000000 +0100
++++ l2tpd-0.70pre-new/l2tpd.c.orig 2005-12-16 12:14:24.000000000 +0100
+@@ -0,0 +1,1104 @@
++/*
++ * $Id$
++ *
++ * Layer Two Tunnelling Protocol Daemon
++ * Copyright (C) 1998 Adtran, Inc.
++ * Copyright (C) 2002 Jeff McAdams
++ *
++ * Mark Spencer
++ *
++ * This software is distributed under the terms
++ * of the GPL, which you should have received
++ * along with this source.
++ *
++ * Main Daemon source.
++ *
++ */
++
++#include <stdlib.h>
++#include <sys/utsname.h>
++#include <sys/stat.h>
++#include <sys/wait.h>
++#include <stdio.h>
++#include <errno.h>
++#include <unistd.h>
++#include <time.h>
++#if (__GLIBC__ < 2)
++# if defined(FREEBSD)
++# include <sys/signal.h>
++# elif defined(LINUX)
++# include <bsd/signal.h>
++# elif defined(SOLARIS)
++# include <signal.h>
++# endif
++#else
++# include <signal.h>
++#endif
++#include <netdb.h>
++#include <string.h>
++#include <fcntl.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#ifdef USE_KERNEL
++#include <sys/ioctl.h>
++#endif
++#include "l2tp.h"
++
++struct tunnel_list tunnels;
++int max_tunnels = DEF_MAX_TUNNELS;
++struct utsname uts;
++int ppd = 1; /* Packet processing delay */
++int control_fd; /* descriptor of control area */
++char *args;
++
++char *dial_no_tmp; /* jz: Dialnumber for Outgoing Call */
++int switch_io = 0; /* jz: Switch for Incoming or Outgoing Call */
++
++void init_tunnel_list (struct tunnel_list *t)
++{
++ t->head = NULL;
++ t->count = 0;
++ t->calls = 0;
++}
++
++/* Now sends to syslog instead - MvO */
++void show_status (void)
++{
++ struct schedule_entry *se;
++ struct tunnel *t;
++ struct call *c;
++ struct lns *tlns;
++ struct lac *tlac;
++ struct host *h;
++ int s = 0;
++ log (LOG_WARN, "====== l2tpd statistics ========\n");
++ log (LOG_WARN, " Scheduler entries:\n");
++ se = events;
++ while (se)
++ {
++ s++;
++ t = (struct tunnel *) se->data;
++ tlac = (struct lac *) se->data;
++ c = (struct call *) se->data;
++ if (se->func == &hello)
++ {
++ log (LOG_WARN, "%d: HELLO to %d\n", s, t->tid);
++ }
++ else if (se->func == &magic_lac_dial)
++ {
++ log (LOG_WARN, "%d: Magic dial on %s\n", s, tlac->entname);
++ }
++ else if (se->func == &send_zlb)
++ {
++ log (LOG_WARN, "%d: Send payload ZLB on call %d:%d\n", s,
++ c->container->tid, c->cid);
++ }
++ else if (se->func == &dethrottle)
++ {
++ log (LOG_WARN, "%d: Dethrottle call %d:%d\n", s, c->container->tid,
++ c->cid);
++ }
++ else
++ log (LOG_WARN, "%d: Unknown event\n", s);
++ se = se->next;
++ };
++ log (LOG_WARN, "Total Events scheduled: %d\n", s);
++ log (LOG_WARN, "Number of tunnels open: %d\n", tunnels.count);
++ t = tunnels.head;
++ while (t)
++ {
++ log (LOG_WARN, "Tunnel %s, ID = %d (local), %d (remote) to %s:%d\n"
++ " control_seq_num = %d, control_rec_seq_num = %d,\n"
++ " cLr = %d\n",
++ (t->lac ? t->lac->entname : (t->lns ? t->lns->entname : "")),
++ t->ourtid, t->tid, IPADDY (t->peer.sin_addr),
++ ntohs (t->peer.sin_port), t->control_seq_num,
++ t->control_rec_seq_num, t->cLr);
++ c = t->call_head;
++ while (c)
++ {
++ log (LOG_WARN,
++ "Call %s, ID = %d (local), %d (remote), serno = %u,\n"
++ " data_seq_num = %d, data_rec_seq_num = %d,\n"
++ " pLr = %d, tx = %u bytes (%u), rx= %u bytes (%u)\n",
++ (c->lac ? c->lac->
++ entname : (c->lns ? c->lns->entname : "")), c->ourcid,
++ c->cid, c->serno, c->data_seq_num, c->data_rec_seq_num,
++ c->pLr, c->tx_bytes, c->tx_pkts, c->rx_bytes, c->rx_pkts);
++ c = c->next;
++ }
++ t = t->next;
++ }
++ log (LOG_WARN, "==========Config File===========\n");
++ tlns = lnslist;
++ while (tlns)
++ {
++ log (LOG_WARN, "LNS entry %s\n",
++ tlns->entname[0] ? tlns->entname : "(unnamed)");
++ tlns = tlns->next;
++ };
++ tlac = laclist;
++ while (tlac)
++ {
++ log (LOG_WARN, "LAC entry %s, LNS is/are:",
++ tlac->entname[0] ? tlac->entname : "(unnamed)");
++ h = tlac->lns;
++ if (h)
++ {
++ while (h)
++ {
++ log (LOG_WARN, " %s", h->hostname);
++ h = h->next;
++ }
++ }
++ else
++ log (LOG_WARN, " [none]");
++ log (LOG_WARN, "\n");
++ tlac = tlac->next;
++ };
++ log (LOG_WARN, "================================\n");
++}
++
++void null_handler(int sig)
++{
++ /* FIXME
++ * A sighup is received when a call is terminated, unknown origine ..
++ * I catch it and ll looks good, but ..
++ */
++}
++
++void status_handler (int sig)
++{
++ show_status ();
++}
++
++void child_handler (int signal)
++{
++ /*
++ * Oops, somebody we launched was killed.
++ * It's time to reap them and close that call.
++ * But first, we have to find out what PID died.
++ * unfortunately, pppd will
++ */
++ struct tunnel *t;
++ struct call *c;
++ pid_t pid;
++ int status;
++ t = tunnels.head;
++ /* Keep looping until all are cleared */
++ for(;;)
++ {
++ pid = waitpid (-1, &status, WNOHANG);
++ if (pid < 1)
++ {
++ /*
++ * Oh well, nobody there. Maybe we reaped it
++ * somewhere else already
++ */
++ return;
++ }
++ while (t)
++ {
++ c = t->call_head;
++ while (c)
++ {
++ if (c->pppd == pid)
++ {
++ if ( WIFEXITED( status ) )
++ {
++ log (LOG_DEBUG, "%s : pppd exited for call %d with code %d\n", __FUNCTION__,
++ c->cid, WEXITSTATUS( status ) );
++ }
++ else if( WIFSIGNALED( status ) )
++ {
++ log (LOG_DEBUG, "%s : pppd terminated for call %d by signal %d\n", __FUNCTION__,
++ c->cid, WTERMSIG( status ) );
++ }
++ else
++ {
++ log (LOG_DEBUG, "%s : pppd exited for call %d for unknown reason\n", __FUNCTION__,
++ c->cid );
++ }
++ c->needclose = -1;
++ /*
++ * OK...pppd died, we can go ahead and close the pty for
++ * it
++ */
++ close (c->fd);
++ c->fd = -1;
++ return;
++ }
++ c = c->next;
++ }
++ t = t->next;
++ }
++ }
++}
++
++void death_handler (int signal)
++{
++ /*
++ * If we get here, somebody terminated us with a kill or a control-c.
++ * we call call_close on each tunnel twice to get a StopCCN out
++ * for each one (we can't pause to make sure it's received.
++ * Then we close the connections
++ */
++ struct tunnel *st, *st2;
++ int sec;
++ log (LOG_CRIT, "%s: Fatal signal %d received\n", __FUNCTION__, signal);
++ st = tunnels.head;
++ while (st)
++ {
++ st2 = st->next;
++ strcpy (st->self->errormsg, "Server closing");
++ sec = st->self->closing;
++ if (st->lac)
++ st->lac->redial = 0;
++ call_close (st->self);
++ if (!sec)
++ {
++ st->self->closing = -1;
++ call_close (st->self);
++ }
++ st = st2;
++ }
++
++ /* erase pid file */
++ unlink (gconfig.pidfile);
++
++ /* erase control pipe */
++ unlink(CONTROL_PIPE);
++
++ exit (1);
++}
++
++int start_pppd (struct call *c, struct ppp_opts *opts)
++{
++ char a, b;
++ char tty[80];
++ char *stropt[80];
++ struct ppp_opts *p;
++#ifdef USE_KERNEL
++ struct l2tp_call_opts co;
++#endif
++ int pos = 1;
++ int fd2;
++#ifdef DEBUG_PPPD
++ int x;
++#endif
++ struct termios ptyconf;
++ char *str;
++ p = opts;
++ stropt[0] = strdup (PPPD);
++ while (p)
++ {
++ stropt[pos] = (char *) malloc (strlen (p->option) + 1);
++ strncpy (stropt[pos], p->option, strlen (p->option) + 1);
++ pos++;
++ p = p->next;
++ }
++ stropt[pos] = NULL;
++ if (c->pppd > 0)
++ {
++ log (LOG_WARN, "%s: PPP already started on call!\n", __FUNCTION__);
++ return -EINVAL;
++ }
++ if (c->fd > -1)
++ {
++ log (LOG_WARN, "%s: file descriptor already assigned!\n",
++ __FUNCTION__);
++ return -EINVAL;
++ }
++#ifdef USE_KERNEL
++ if (kernel_support)
++ {
++ co.ourtid = c->container->ourtid;
++ co.ourcid = c->ourcid;
++ ioctl (server_socket, L2TPIOCGETCALLOPTS, &co);
++ stropt[pos++] = strdup ("channel");
++ stropt[pos] = (char *) malloc (10);
++ snprintf (stropt[pos], 10, "%d", co.id);
++ pos++;
++ stropt[pos] = NULL;
++ }
++ else
++ {
++#endif
++ if ((c->fd = getPtyMaster (&a, &b)) < 0)
++ {
++ log (LOG_WARN, "%s: unable to allocate pty, abandoning!\n",
++ __FUNCTION__);
++ return -EINVAL;
++ }
++
++ /* set fd opened above to not echo so we don't see read our own packets
++ back of the file descriptor that we just wrote them to */
++ tcgetattr (c->fd, &ptyconf);
++ *(c->oldptyconf) = ptyconf;
++ ptyconf.c_cflag &= ~(ICANON | ECHO);
++ tcsetattr (c->fd, TCSANOW, &ptyconf);
++
++ snprintf (tty, sizeof (tty), "/dev/tty%c%c", a, b);
++ fd2 = open (tty, O_RDWR);
++
++#ifdef USE_KERNEL
++ }
++#endif
++ str = stropt[0];
++#ifdef DEBUG_PPPD
++ log (LOG_DEBUG, "%s: I'm running: ", __FUNCTION__);
++ for (x = 0; stropt[x]; x++)
++ {
++ log (LOG_DEBUG, "\"%s\" ", stropt[x]);
++ };
++ log (LOG_DEBUG, "\n");
++#endif
++ c->pppd = fork ();
++ if (c->pppd < 0)
++ {
++ log (LOG_WARN, "%s: unable to fork(), abandoning!\n", __FUNCTION__);
++ return -EINVAL;
++ }
++ else if (!c->pppd)
++ {
++ struct call *sc;
++ struct tunnel *st;
++
++ close (0);
++ close (1);
++ close (2);
++#ifdef USE_KERNEL
++ if (!kernel_support && (fd2 < 0))
++#else
++ if (fd2 < 0)
++#endif
++ {
++ log (LOG_WARN, "%s: Unable to open %s to launch pppd!\n",
++ __FUNCTION__, tty);
++ exit (1);
++ }
++ dup2 (fd2, 0);
++ dup2 (fd2, 1);
++
++
++ /* close all the calls pty fds */
++ st = tunnels.head;
++ while (st)
++ {
++ sc = st->call_head;
++ while (sc)
++ {
++ close (sc->fd);
++ sc = sc->next;
++ }
++ st = st->next;
++ }
++
++ /* close the UDP socket fd */
++ close (server_socket);
++
++ /* close the control pipe fd */
++ close (control_fd);
++
++ if( c->dialing[0] )
++ {
++ setenv( "CALLER_ID", c->dialing, 1 );
++ }
++ execv (PPPD, stropt);
++ log (LOG_WARN, "%s: Exec of %s failed!\n", __FUNCTION__, PPPD);
++ exit (1);
++ };
++ close (fd2);
++ pos = 0;
++ while (stropt[pos])
++ {
++ free (stropt[pos]);
++ pos++;
++ };
++ return 0;
++}
++
++void destroy_tunnel (struct tunnel *t)
++{
++ /*
++ * Immediately destroy a tunnel (and all its calls)
++ * and free its resources. This may be called
++ * by the tunnel itself,so it needs to be
++ * "suicide safe"
++ */
++
++ struct call *c, *me;
++ struct tunnel *p;
++ struct timeval tv;
++ if (!t)
++ return;
++
++ /*
++ * Save ourselves until the very
++ * end, since we might be calling this ourselves.
++ * We must divorce ourself from the tunnel
++ * structure, however, to avoid recursion
++ * because of the logic of the destroy_call
++ */
++ me = t->self;
++
++ /*
++ * Destroy all the member calls
++ */
++ c = t->call_head;
++ while (c)
++ {
++ destroy_call (c);
++ c = c->next;
++ };
++ /*
++ * Remove ourselves from the list of tunnels
++ */
++
++ if (tunnels.head == t)
++ {
++ tunnels.head = t->next;
++ tunnels.count--;
++ }
++ else
++ {
++ p = tunnels.head;
++ if (p)
++ {
++ while (p->next && (p->next != t))
++ p = p->next;
++ if (p->next)
++ {
++ p->next = t->next;
++ tunnels.count--;
++ }
++ else
++ {
++ log (LOG_WARN,
++ "%s: unable to locate tunnel in tunnel list\n",
++ __FUNCTION__);
++ }
++ }
++ else
++ {
++ log (LOG_WARN, "%s: tunnel list is empty!\n", __FUNCTION__);
++ }
++ }
++ if (t->lac)
++ {
++ t->lac->t = NULL;
++ if (t->lac->redial && (t->lac->rtimeout > 0) && !t->lac->rsched &&
++ t->lac->active)
++ {
++ log (LOG_LOG, "%s: Will redial in %d seconds\n", __FUNCTION__,
++ t->lac->rtimeout);
++ tv.tv_sec = t->lac->rtimeout;
++ tv.tv_usec = 0;
++ t->lac->rsched = schedule (tv, magic_lac_dial, t->lac);
++ }
++ }
++ /* XXX L2TP/IPSec: remove relevant SAs here? NTB 20011010
++ * XXX But what if another tunnel is using same SA?
++ */
++ if (t->lns)
++ t->lns->t = NULL;
++ free (t);
++ free (me);
++}
++
++struct tunnel *l2tp_call (char *host, int port, struct lac *lac,
++ struct lns *lns)
++{
++ /*
++ * Establish a tunnel from us to host
++ * on port port
++ */
++ struct call *tmp = NULL;
++ struct hostent *hp;
++ unsigned int addr;
++ port = htons (port);
++ hp = gethostbyname (host);
++ if (!hp)
++ {
++ log (LOG_WARN, "%s: gethostbyname() failed for %s.\n", __FUNCTION__,
++ host);
++ return NULL;
++ }
++ bcopy (hp->h_addr, &addr, hp->h_length);
++ /* Force creation of a new tunnel
++ and set it's tid to 0 to cause
++ negotiation to occur */
++ /* XXX L2TP/IPSec: Set up SA to addr:port here? NTB 20011010
++ */
++ tmp = get_call (0, 0, addr, port);
++ if (!tmp)
++ {
++ log (LOG_WARN, "%s: Unable to create tunnel to %s.\n", __FUNCTION__,
++ host);
++ return NULL;
++ }
++ tmp->container->tid = 0;
++ tmp->container->lac = lac;
++ tmp->container->lns = lns;
++ tmp->lac = lac;
++ tmp->lns = lns;
++ if (lac)
++ lac->t = tmp->container;
++ if (lns)
++ lns->t = tmp->container;
++ /*
++ * Since our state is 0, we will establish a tunnel now
++ */
++ log (LOG_LOG, "%s:Connecting to host %s, port %d\n", __FUNCTION__, host,
++ ntohs (port));
++ control_finish (tmp->container, tmp);
++ return tmp->container;
++}
++
++void magic_lac_tunnel (void *data)
++{
++ struct lac *lac;
++ lac = (struct lac *) data;
++ if (!lac)
++ {
++ log (LOG_WARN, "%s: magic_lac_tunnel: called on NULL lac!\n",
++ __FUNCTION__);
++ return;
++ }
++ if (lac->lns)
++ {
++ /* FIXME: I should try different LNS's if I get failures */
++ l2tp_call (lac->lns->hostname, lac->lns->port, lac, NULL);
++ return;
++ }
++ else if (deflac && deflac->lns)
++ {
++ l2tp_call (deflac->lns->hostname, deflac->lns->port, lac, NULL);
++ return;
++ }
++ else
++ {
++ log (LOG_WARN, "%s: Unable to find hostname to dial for '%s'\n",
++ __FUNCTION__, lac->entname);
++ return;
++ }
++}
++
++struct call *lac_call (int tid, struct lac *lac, struct lns *lns)
++{
++ struct tunnel *t = tunnels.head;
++ struct call *tmp;
++ while (t)
++ {
++ if (t->ourtid == tid)
++ {
++ tmp = new_call (t);
++ if (!tmp)
++ {
++ log (LOG_WARN, "%s: unable to create new call\n",
++ __FUNCTION__);
++ return NULL;
++ }
++ tmp->next = t->call_head;
++ t->call_head = tmp;
++ t->count++;
++ tmp->cid = 0;
++ tmp->lac = lac;
++ tmp->lns = lns;
++ if (lac)
++ lac->c = tmp;
++ log (LOG_LOG, "%s: Calling on tunnel %d\n", __FUNCTION__, tid);
++ strcpy (tmp->dial_no, dial_no_tmp); /* jz: copy dialnumber to tmp->dial_no */
++ control_finish (t, tmp);
++ return tmp;
++ }
++ t = t->next;
++ };
++ log (LOG_DEBUG, "%s: No such tunnel %d to generate call.\n", __FUNCTION__,
++ tid);
++ return NULL;
++}
++
++void magic_lac_dial (void *data)
++{
++ struct lac *lac;
++ lac = (struct lac *) data;
++
++ if (!lac)
++ {
++ log (LOG_WARN, "%s : called on NULL lac!\n", __FUNCTION__);
++ return;
++ }
++ if (!lac->active)
++ {
++ log (LOG_DEBUG, "%s: LAC %s not active", __FUNCTION__, lac->entname);
++ return;
++ }
++ lac->rsched = NULL;
++ lac->rtries++;
++ if (lac->rmax && (lac->rtries > lac->rmax))
++ {
++ log (LOG_LOG, "%s: maximum retries exceeded.\n", __FUNCTION__);
++ return;
++ }
++ if (!lac->t)
++ {
++#ifdef DEGUG_MAGIC
++ log (LOG_DEBUG, "%s : tunnel not up! Connecting!\n", __FUNCTION__);
++#endif
++ magic_lac_tunnel (lac);
++ return;
++ }
++ lac_call (lac->t->ourtid, lac, NULL);
++}
++
++void lac_hangup (int cid)
++{
++ struct tunnel *t = tunnels.head;
++ struct call *tmp;
++ while (t)
++ {
++ tmp = t->call_head;
++ while (tmp)
++ {
++ if (tmp->ourcid == cid)
++ {
++ log (LOG_LOG,
++ "%s :Hanging up call %d, Local: %d, Remote: %d\n",
++ __FUNCTION__, tmp->serno, tmp->ourcid, tmp->cid);
++ strcpy (tmp->errormsg, "Goodbye!");
++/* tmp->needclose = -1; */
++ kill (tmp->pppd, SIGTERM);
++ return;
++ }
++ tmp = tmp->next;
++ }
++ t = t->next;
++ };
++ log (LOG_DEBUG, "%s : No such call %d to hang up.\n", __FUNCTION__, cid);
++ return;
++}
++
++void lac_disconnect (int tid)
++{
++ struct tunnel *t = tunnels.head;
++ while (t)
++ {
++ if (t->ourtid == tid)
++ {
++ log (LOG_LOG,
++ "%s: Disconnecting from %s, Local: %d, Remote: %d\n",
++ __FUNCTION__, IPADDY (t->peer.sin_addr), t->ourtid, t->tid);
++ t->self->needclose = -1;
++ strcpy (t->self->errormsg, "Goodbye!");
++ call_close (t->self);
++ return;
++ }
++ t = t->next;
++ };
++ log (LOG_DEBUG, "%s: No such tunnel %d to hang up.\n", __FUNCTION__, tid);
++ return;
++}
++
++struct tunnel *new_tunnel ()
++{
++ struct tunnel *tmp = malloc (sizeof (struct tunnel));
++ char entropy_buf[2] = "\0";
++ if (!tmp)
++ return NULL;
++ tmp->control_seq_num = 0;
++ tmp->control_rec_seq_num = 0;
++ tmp->cLr = 0;
++ tmp->call_head = NULL;
++ tmp->next = NULL;
++ tmp->debug = -1;
++ tmp->tid = -1;
++ tmp->hello = NULL;
++#ifndef TESTING
++/* while(get_call((tmp->ourtid = rand() & 0xFFFF),0,0,0)); */
++#ifdef USE_KERNEL
++ if (kernel_support)
++ tmp->ourtid = ioctl (server_socket, L2TPIOCADDTUNNEL, 0);
++ else
++#endif
++/* tmp->ourtid = rand () & 0xFFFF; */
++ /* get_entropy((char *)&tmp->ourtid, 2); */
++ get_entropy(entropy_buf, 2);
++ {
++ int *temp;
++ temp = (int *)entropy_buf;
++ tmp->ourtid = *temp & 0xFFFF;
++#ifdef DEBUG_ENTROPY
++ log(LOG_DEBUG, "ourtid = %u, entropy_buf = %hx\n", tmp->ourtid, *temp);
++#endif
++ }
++#else
++ tmp->ourtid = 0x6227;
++#endif
++ tmp->nego = 0;
++ tmp->count = 0;
++ tmp->state = 0; /* Nothing */
++ tmp->peer.sin_family = AF_INET;
++ tmp->peer.sin_port = 0;
++ bzero (&(tmp->peer.sin_addr), sizeof (tmp->peer.sin_addr));
++ tmp->sanity = -1;
++ tmp->qtid = -1;
++ tmp->ourfc = ASYNC_FRAMING | SYNC_FRAMING;
++ tmp->ourbc = 0;
++ tmp->ourtb = (((_u64) rand ()) << 32) | ((_u64) rand ());
++ tmp->fc = -1; /* These really need to be specified by the peer */
++ tmp->bc = -1; /* And we want to know if they forgot */
++ tmp->hostname[0] = 0;
++ tmp->vendor[0] = 0;
++ tmp->secret[0] = 0;
++ if (!(tmp->self = new_call (tmp)))
++ {
++ free (tmp);
++ return NULL;
++ };
++ tmp->ourrws = DEFAULT_RWS_SIZE;
++ tmp->self->ourfbit = FBIT;
++ tmp->lac = NULL;
++ tmp->lns = NULL;
++ tmp->chal_us.state = 0;
++ tmp->chal_us.secret[0] = 0;
++ memset (tmp->chal_us.reply, 0, MD_SIG_SIZE);
++ tmp->chal_them.state = 0;
++ tmp->chal_them.secret[0] = 0;
++ memset (tmp->chal_them.reply, 0, MD_SIG_SIZE);
++ tmp->chal_them.vector = (unsigned char *) malloc (VECTOR_SIZE);
++ tmp->chal_us.vector = NULL;
++ tmp->hbit = 0;
++ return tmp;
++}
++
++void do_control ()
++{
++ char buf[1024];
++ char *host, *tunstr, *callstr, *tmpstr;
++ struct lac *lac;
++ int call;
++ int tunl;
++ int cnt = -1;
++ while (cnt)
++ {
++ cnt = read (control_fd, buf, sizeof (buf));
++ if (cnt > 0)
++ {
++ if (buf[cnt - 1] == '\n')
++ buf[--cnt] = 0;
++#ifdef DEBUG_CONTROL
++ log (LOG_DEBUG, "%s: Got message \"%s\" (%d bytes long)\n",
++ __FUNCTION__, buf, cnt);
++#endif
++ switch (buf[0])
++ {
++ case 't':
++ host = strchr (buf, ' ');
++ if(!host)
++ goto out;
++ host++;
++#ifdef DEBUG_CONTROL
++ log (LOG_DEBUG, "%s: Attempting to tunnel to %s\n",
++ __FUNCTION__, host);
++#endif
++ l2tp_call (host, UDP_LISTEN_PORT, NULL, NULL);
++ break;
++ case 'c': /* option 'c' for incoming call */
++ case 'o': /* option 'o' for outgoing call */
++ tunstr = strchr (buf, ' ');
++ if(!tunstr)
++ goto out;
++ tunstr++;
++
++ if(buf[0] == 'c')
++ switch_io = 1; /* Switch for Incoming Calls */
++ else {
++ switch_io = 0; /* Switch for Outgoing Calls */
++ tmpstr = strchr(tunstr, ' ');
++ if(!tmpstr)
++ goto out;
++ strncpy(dial_no_tmp,tmpstr, sizeof(*dial_no_tmp));
++ }
++
++ lac = laclist;
++ while (lac)
++ {
++ if (!strcasecmp (lac->entname, tunstr))
++ {
++ lac->active = -1;
++ lac->rtries = 0;
++ if (!lac->c)
++ magic_lac_dial (lac);
++ else
++ log (LOG_DEBUG,
++ "%s: Session '%s' already active!\n",
++ __FUNCTION__, lac->entname);
++ break;
++ }
++ lac = lac->next;
++ }
++ if (lac)
++ break;
++ tunl = atoi (tunstr);
++ if (!tunl)
++ {
++ log (LOG_DEBUG, "%s: No such tunnel '%s'\n", __FUNCTION__,
++ tunstr);
++ break;
++ }
++#ifdef DEBUG_CONTROL
++ log (LOG_DEBUG, "%s: Attempting to call on tunnel %d\n",
++ __FUNCTION__, tunl);
++#endif
++ lac_call (tunl, NULL, NULL);
++ break;
++ case 'h':
++ callstr = strchr (buf, ' ');
++ if(!callstr)
++ goto out;
++ callstr++;
++
++ call = atoi (callstr);
++#ifdef DEBUG_CONTROL
++ log (LOG_DEBUG, "%s: Attempting to call %d\n", __FUNCTION__,
++ call);
++#endif
++ lac_hangup (call);
++ break;
++ case 'd':
++ tunstr = strchr (buf, ' ');
++ if(!tunstr)
++ goto out;
++ tunstr++;
++
++ lac = laclist;
++ while (lac)
++ {
++ if (!strcasecmp (lac->entname, tunstr))
++ {
++ lac->active = 0;
++ lac->rtries = 0;
++ if (lac->t)
++ lac_disconnect (lac->t->ourtid);
++ else
++ log (LOG_DEBUG, "%s: Session '%s' not up\n",
++ __FUNCTION__, lac->entname);
++ break;
++ }
++ lac = lac->next;
++ }
++ if (lac)
++ break;
++ tunl = atoi (tunstr);
++ if (!tunl)
++ {
++ log (LOG_DEBUG, "%s: No such tunnel '%s'\n", __FUNCTION__,
++ tunstr);
++ break;
++ }
++#ifdef DEBUG_CONTROL
++ log (LOG_DEBUG, "%s: Attempting to disconnect tunnel %d\n",
++ __FUNCTION__, tunl);
++#endif
++ lac_disconnect (tunl);
++ break;
++ case 's':
++ show_status ();
++ break;
++ default:
++ log (LOG_DEBUG, "%s: Unknown command %c\n", __FUNCTION__,
++ buf[0]);
++ }
++ }
++ }
++
++out:
++ /* Otherwise select goes nuts */
++ close (control_fd);
++ control_fd = open (CONTROL_PIPE, O_RDONLY | O_NONBLOCK, 0600);
++}
++
++void usage(void) {
++ printf("Usage: l2tpd -D -c [config file] -s [secret file] -p [pid file]\n");
++ printf("\n");
++ exit(1);
++}
++
++void init_args(int argc, char *argv[]) {
++ int i=0;
++ gconfig.daemon=1;
++ memset(gconfig.altauthfile,0,STRLEN);
++ memset(gconfig.altconfigfile,0,STRLEN);
++ memset(gconfig.authfile,0,STRLEN);
++ memset(gconfig.configfile,0,STRLEN);
++ memset(gconfig.pidfile,0,STRLEN);
++ strncpy(gconfig.altauthfile,ALT_DEFAULT_AUTH_FILE,
++ sizeof(gconfig.altauthfile) - 1);
++ strncpy(gconfig.altconfigfile,ALT_DEFAULT_CONFIG_FILE,
++ sizeof(gconfig.altconfigfile) - 1);
++ strncpy(gconfig.authfile,DEFAULT_AUTH_FILE,
++ sizeof(gconfig.authfile) - 1);
++ strncpy(gconfig.configfile,DEFAULT_CONFIG_FILE,
++ sizeof(gconfig.configfile) - 1);
++ strncpy(gconfig.pidfile,DEFAULT_PID_FILE,
++ sizeof(gconfig.pidfile) - 1);
++ for (i = 1; i < argc; i++) {
++ if(! strncmp(argv[i],"-c",2)) {
++ if(++i == argc)
++ usage();
++ else
++ strncpy(gconfig.configfile,argv[i],
++ sizeof(gconfig.configfile) - 1);
++ }
++ else if (! strncmp(argv[i],"-D",2)) {
++ gconfig.daemon=0;
++ }
++ else if (! strncmp(argv[i],"-s",2)) {
++ if(++i == argc)
++ usage();
++ else
++ strncpy(gconfig.authfile,argv[i],
++ sizeof(gconfig.authfile) - 1);
++ }
++ else if (! strncmp(argv[i],"-p",2)) {
++ if(++i == argc)
++ usage();
++ else
++ strncpy(gconfig.pidfile,argv[i],
++ sizeof(gconfig.pidfile) - 1);
++ }
++ else {
++ usage();
++ }
++ }
++}
++
++
++void daemonize() {
++ int pid=0;
++ int i,l;
++ char buf[STRLEN];
++
++ if((pid = fork()) < 0) {
++ log(LOG_LOG, "%s: Unable to fork ()\n",__FUNCTION__);
++ close(server_socket);
++ exit(1);
++ }
++ else if (pid)
++ exit(0);
++
++
++ close(0);
++ close(1);
++ close(2);
++ dup2(open("/dev/null", O_RDONLY), 0);
++ dup2(open("/dev/null", O_RDONLY), 1);
++ dup2(open("/dev/null", O_RDONLY), 2);
++
++ /* Read previous pid file. */
++ if((i = open(gconfig.pidfile,O_RDONLY)) > 0) {
++ l=read(i,buf,sizeof(buf)-1);
++ if (l >= 0) {
++ buf[l] = '\0';
++ pid = atoi(buf);
++ }
++ close(i);
++
++ /* if pid is read and process exist exit */
++ if(pid && !kill(pid, 0)) {
++ log(LOG_LOG, "%s: There's already a l2tpd server running.\n",
++ __FUNCTION__);
++ close(server_socket);
++ exit(1);
++ }
++
++ /* remove stalled pid file */
++ unlink(gconfig.pidfile);
++ }
++
++ pid = setsid();
++
++ /* create new pid file */
++ if ((i = open (gconfig.pidfile, O_WRONLY | O_CREAT, 0644)) >= 0) {
++ snprintf (buf, sizeof(buf), "%d", (int)getpid());
++ write (i, buf, strlen(buf));
++ close (i);
++ }
++ else {
++ log(LOG_LOG, "%s: could not write pid file %s error %d",
++ __FUNCTION__, gconfig.pidfile, i);
++ close(server_socket);
++ exit(1);
++ }
++}
++
++
++void init (int argc,char *argv[])
++{
++ struct lac *lac;
++ struct in_addr listenaddr;
++
++ init_args (argc,argv);
++ srand( time(NULL) );
++ rand_source = 0;
++ init_addr ();
++ if (init_config ())
++ {
++ log (LOG_CRIT, "%s: Unable to load config file\n", __FUNCTION__);
++ exit (1);
++ }
++ if (uname (&uts))
++ {
++ log (LOG_CRIT, "%s : Unable to determine host system\n",
++ __FUNCTION__);
++ exit (1);
++ }
++ init_tunnel_list (&tunnels);
++ if (init_network ())
++ exit (1);
++ if (gconfig.daemon)
++ daemonize ();
++ signal (SIGTERM, &death_handler);
++ signal (SIGINT, &death_handler);
++ signal (SIGCHLD, &child_handler);
++ signal (SIGUSR1, &status_handler);
++ signal (SIGHUP, &null_handler);
++ init_scheduler ();
++ mkfifo (CONTROL_PIPE, 0600);
++ control_fd = open (CONTROL_PIPE, O_RDONLY | O_NONBLOCK, 0600);
++ if (control_fd < 0)
++ {
++ log (LOG_CRIT, "%s: Unable to open " CONTROL_PIPE " for reading.",
++ __FUNCTION__);
++ exit (1);
++ }
++ log (LOG_LOG, "l2tpd version " SERVER_VERSION " started on %s PID:%d\n",
++ hostname, getpid ());
++ listenaddr.s_addr = gconfig.listenaddr;
++ log (LOG_LOG, "%s version %s on a %s, listening on IP address %s, port %d\n", uts.sysname,
++ uts.release, uts.machine, inet_ntoa(listenaddr), gconfig.port);
++ lac = laclist;
++ while (lac)
++ {
++ if (lac->autodial)
++ {
++#ifdef DEBUG_MAGIC
++ log (LOG_DEBUG, "%s: Autodialing '%s'\n", __FUNCTION__,
++ lac->entname[0] ? lac->entname : "(unnamed)");
++#endif
++ lac->active = -1;
++ switch_io = 1; /* If we're a LAC, autodials will be ICRQ's */
++ magic_lac_dial (lac);
++ }
++ lac = lac->next;
++ }
++}
++
++int main (int argc, char *argv[])
++{
++ init(argc,argv);
++ dial_no_tmp = calloc (128, sizeof (char));
++ network_thread ();
++ return 0;
++}