1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-12-12 06:28:25 +02:00
openwrt-xburst/openwrt/package/l2tpd/patches/03-jacco-pty.patch

1195 lines
33 KiB
Diff
Raw Normal View History

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;
+}