- Replace flags used for LCP/IPCP with state machine.
authorBrendan O'Dea <bod@optus.net>
Sun, 31 Jul 2005 10:04:09 +0000 (10:04 +0000)
committerBrendan O'Dea <bod@optus.net>
Sun, 31 Jul 2005 10:04:09 +0000 (10:04 +0000)
- Use openssl MD5, fix DAE vector (Alex Kiernan).

27 files changed:
Changes
Docs/manual.html
Docs/startup-config.5
Makefile
THANKS
arp.c
bgp.c
cli.c
cluster.c
cluster.h
constants.c
constants.h
control.c
control.h
icmp.c
l2tpns.c
l2tpns.h
l2tpns.spec
md5.c [deleted file]
md5.h [deleted file]
nsctl.c
plugin.h
ppp.c
radius.c
tbf.c
tbf.h
test/radius.c

diff --git a/Changes b/Changes
index 452407b..e579e70 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,10 +1,10 @@
-* Wed Jun 29 2005 Brendan O'Dea <bod@c47.org> 2.1.2
-- Don't resend IPCP while still in progress.
-- Ignore duplicate ACKs for IPCP.
-- Clear RADIUSIPCP for walled garden sessions on ACK.
+* Sun Jul 31 2005 Brendan O'Dea <bod@> 2.1.2
 - Clear cluster_master on election so that slaves will accept a new master.
 - Provide more comments/defaults in etc/startup-config.default.
 - Add DAE support (PoD/CoA) from Vladislav Bjelic.
+- Clean up new warnings from gcc 4.0.
+- Replace flags used for LCP/IPCP with state machine.
+- Use openssl MD5, fix DAE vector (Alex Kiernan).
 
 * Tue Jun 14 2005 Brendan O'Dea <bod@optusnet.com.au> 2.1.1
 - Add missing newline to backtrace macro.
index 2458391..1fe4694 100644 (file)
@@ -185,6 +185,13 @@ the same as the LAC, or authentication will fail.  Only actually be
 used if the LAC requests authentication.
 </LI>
 
+<LI><B>ppp_restart_time</B> (int)<BR>
+<B>ppp_max_configure</B> (int)<BR>
+<B>ppp_max_failure</B> (int)<BR>
+PPP counters and timers values, as described in &sect;4.1 of
+<a href="ftp://ftp.rfc-editor.org/in-notes/rfc1661.txt">RFC1661</a>.
+</LI>
+
 <LI><B>primary_dns</B> (ip address)
 <LI><B>secondary_dns</B> (ip address)<BR>
 Whenever a PPP connection is established, DNS servers will be sent to the
index 7170dbe..c403de1 100644 (file)
@@ -2,7 +2,7 @@
 .de Id
 .ds Dt \\$4 \\$5
 ..
-.Id $Id: startup-config.5,v 1.11 2005-06-28 14:48:31 bodea Exp $
+.Id $Id: startup-config.5,v 1.12 2005-07-31 10:04:14 bodea Exp $
 .TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions"
 .SH NAME
 startup\-config \- configuration file for l2tpns
@@ -63,6 +63,16 @@ for authenticating tunnel request.  Must be the same as the LAC, or
 authentication will fail.  Only actually be used if the LAC requests
 authentication.
 .TP
+.B ppp_restart_time
+Restart timer for PPP protocol negotiation in seconds (default: 3).
+.TP
+.B ppp_max_configure
+Number of configure requests to send before giving up (default: 10).
+.TP
+.B ppp_max_failure
+Number of Configure-Nak requests to send before sending a
+Configure-Reject (default: 5).
+.TP
 .BR primary_dns , " secondary_dns"
 Whenever a PPP connection is established, DNS servers will be sent to the
 user, both a primary and a secondary.  If either is set to 0.0.0.0, then that
index 156ff39..de2755f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -23,10 +23,10 @@ LDFLAGS =
 LDLIBS =
 INSTALL = install -c -D -o root -g root
 
-l2tpns.LIBS = -lm -lcli -ldl
+l2tpns.LIBS = -lcrypto -lm -lcli -ldl
 
 OBJS = arp.o cli.o cluster.o constants.o control.o icmp.o l2tpns.o \
-    ll.o md5.o ppp.o radius.o tbf.o util.o
+    ll.o ppp.o radius.o tbf.o util.o
 
 PROGRAMS = l2tpns nsctl
 PLUGINS = autosnoop.so autothrottle.so garden.so sessionctl.so \
@@ -109,20 +109,19 @@ install: all
 
 ## Dependencies: (autogenerated) ##
 arp.o: arp.c l2tpns.h
-cli.o: cli.c l2tpns.h util.h cluster.h tbf.h ll.h bgp.h
+cli.o: cli.c l2tpns.h constants.h util.h cluster.h tbf.h ll.h bgp.h
 cluster.o: cluster.c l2tpns.h cluster.h util.h tbf.h bgp.h
 constants.o: constants.c constants.h
 control.o: control.c l2tpns.h control.h
 icmp.o: icmp.c l2tpns.h
-l2tpns.o: l2tpns.c md5.h l2tpns.h cluster.h plugin.h ll.h constants.h \
-  control.h util.h tbf.h bgp.h
+l2tpns.o: l2tpns.c l2tpns.h cluster.h plugin.h ll.h constants.h control.h \
+  util.h tbf.h bgp.h fake_epoll.h
 ll.o: ll.c ll.h
-md5.o: md5.c md5.h
 ppp.o: ppp.c l2tpns.h constants.h plugin.h util.h tbf.h cluster.h
-radius.o: radius.c md5.h constants.h l2tpns.h plugin.h util.h
+radius.o: radius.c constants.h l2tpns.h plugin.h util.h cluster.h
 tbf.o: tbf.c l2tpns.h util.h tbf.h
 util.o: util.c l2tpns.h bgp.h
-bgp.o: bgp.c l2tpns.h bgp.h util.h
+bgp.o: bgp.c l2tpns.h bgp.h util.h fake_epoll.h
 autosnoop.so: autosnoop.c l2tpns.h plugin.h
 autothrottle.so: autothrottle.c l2tpns.h plugin.h
 garden.so: garden.c l2tpns.h plugin.h control.h
diff --git a/THANKS b/THANKS
index 07d9619..3262976 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -16,3 +16,4 @@ Bj
 Roberto Chostakovis        <rchostakovis@users.sourceforge.net>
 Jordan Hrycaj              <jordan@mjh.teddy-net.com>
 Vladislav Bjelic           <vladislav@gmail.com>
+Alex Kiernan               <alex.kiernan@gmail.com>
diff --git a/arp.c b/arp.c
index 1c2faa1..5fad15d 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -1,6 +1,6 @@
 // L2TPNS: arp
 
-char const *cvs_id_arp = "$Id: arp.c,v 1.6 2005-01-07 07:14:14 bodea Exp $";
+char const *cvs_id_arp = "$Id: arp.c,v 1.7 2005-07-31 10:04:09 bodea Exp $";
 
 #include <string.h>
 #include <unistd.h>
@@ -55,7 +55,7 @@ void sendarp(int ifr_idx, const unsigned char* mac, in_addr_t ip)
 
        memset(&sll, 0, sizeof(sll));
        sll.sll_family = AF_PACKET;
-       strncpy(sll.sll_addr, mac, sizeof(sll.sll_addr) - 1);
+       memcpy(sll.sll_addr, mac, sizeof(sll.sll_addr) - 1);
        sll.sll_halen = ETH_ALEN;
        sll.sll_ifindex = ifr_idx;
 
diff --git a/bgp.c b/bgp.c
index 96e2868..bfb8de9 100644 (file)
--- a/bgp.c
+++ b/bgp.c
@@ -10,7 +10,7 @@
  *   nor RFC2385 (which requires a kernel patch on 2.4 kernels).
  */
 
-char const *cvs_id_bgp = "$Id: bgp.c,v 1.10 2005-06-04 15:42:35 bodea Exp $";
+char const *cvs_id_bgp = "$Id: bgp.c,v 1.11 2005-07-31 10:04:09 bodea Exp $";
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -767,7 +767,7 @@ static int bgp_connect(struct bgp_peer *peer)
 static int bgp_handle_connect(struct bgp_peer *peer)
 {
     int err = 0;
-    int len = sizeof(int);
+    socklen_t len = sizeof(int);
     getsockopt(peer->sock, SOL_SOCKET, SO_ERROR, &err, &len);
     if (err)
     {
diff --git a/cli.c b/cli.c
index d0f9a8a..e017ff5 100644 (file)
--- a/cli.c
+++ b/cli.c
@@ -2,7 +2,7 @@
 // vim: sw=8 ts=8
 
 char const *cvs_name = "$Name:  $";
-char const *cvs_id_cli = "$Id: cli.c,v 1.63 2005-06-28 14:48:17 bodea Exp $";
+char const *cvs_id_cli = "$Id: cli.c,v 1.64 2005-07-31 10:04:09 bodea Exp $";
 
 #include <stdio.h>
 #include <stdarg.h>
@@ -25,6 +25,7 @@ char const *cvs_id_cli = "$Id: cli.c,v 1.63 2005-06-28 14:48:17 bodea Exp $";
 #include <libcli.h>
 
 #include "l2tpns.h"
+#include "constants.h"
 #include "util.h"
 #include "cluster.h"
 #include "tbf.h"
@@ -289,10 +290,10 @@ void cli_do(int sockfd)
 {
        int require_auth = 1;
        struct sockaddr_in addr;
-       int l = sizeof(addr);
+       socklen_t l = sizeof(addr);
 
        if (fork_and_close()) return;
-       if (getpeername(sockfd, (struct sockaddr *)&addr, &l) == 0)
+       if (getpeername(sockfd, (struct sockaddr *) &addr, &l) == 0)
        {
                require_auth = addr.sin_addr.s_addr != inet_addr("127.0.0.1");
                LOG(require_auth ? 3 : 4, 0, 0, "Accepted connection to CLI from %s\n",
@@ -407,6 +408,19 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
                        cli_print(cli, "\tCalling Num:\t%s", session[s].calling);
                        cli_print(cli, "\tCalled Num:\t%s", session[s].called);
                        cli_print(cli, "\tTunnel ID:\t%d", session[s].tunnel);
+                       cli_print(cli, "\tPPP Phase:\t%s", ppp_phase(session[s].ppp.phase));
+                       switch (session[s].ppp.phase)
+                       {
+                       case Establish:
+                               cli_print(cli, "\tLCP state:\t%s", ppp_state(session[s].ppp.lcp));
+                               break;
+
+                       case Authenticate:
+                       case Network:
+                               cli_print(cli, "\t IPCP state:\t%s", ppp_state(session[s].ppp.ipcp));
+                               cli_print(cli, "\t IPV6CP state:\t%s", ppp_state(session[s].ppp.ipv6cp));
+                               cli_print(cli, "\t CCP state:\t%s", ppp_state(session[s].ppp.ccp));
+                       }
                        cli_print(cli, "\tIP address:\t%s", fmtaddr(htonl(session[s].ip), 0));
                        cli_print(cli, "\tUnique SID:\t%u", session[s].unique_id);
                        cli_print(cli, "\tOpened:\t\t%u seconds", session[s].opened ? abs(time_now - session[s].opened) : 0);
@@ -507,7 +521,7 @@ static int cmd_show_session(struct cli_def *cli, char *command, char **argv, int
                                (session[i].snoop_ip && session[i].snoop_port) ? "Y" : "N",
                                (session[i].throttle_in || session[i].throttle_out) ? "Y" : "N",
                                (session[i].walled_garden) ? "Y" : "N",
-                               (session[i].flags & SF_IPV6CP_ACKED) ? "Y" : "N",
+                               (session[i].ppp.ipv6cp == Opened) ? "Y" : "N",
                                abs(time_now - (unsigned long)session[i].opened),
                                (unsigned long)session[i].cout,
                                (unsigned long)session[i].cin,
@@ -816,7 +830,6 @@ static int cmd_show_version(struct cli_def *cli, char *command, char **argv, int
                cli_print(cli, "  %s", cvs_id_icmp);
                cli_print(cli, "  %s", cvs_id_l2tpns);
                cli_print(cli, "  %s", cvs_id_ll);
-               cli_print(cli, "  %s", cvs_id_md5);
                cli_print(cli, "  %s", cvs_id_ppp);
                cli_print(cli, "  %s", cvs_id_radius);
                cli_print(cli, "  %s", cvs_id_tbf);
index ad41e46..2370eaf 100644 (file)
--- a/cluster.c
+++ b/cluster.c
@@ -1,6 +1,6 @@
 // L2TPNS Clustering Stuff
 
-char const *cvs_id_cluster = "$Id: cluster.c,v 1.44 2005-06-28 14:48:19 bodea Exp $";
+char const *cvs_id_cluster = "$Id: cluster.c,v 1.45 2005-07-31 10:04:09 bodea Exp $";
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -56,7 +56,7 @@ static struct {
 static struct {
        int seq;
        int size;
-       char data[MAX_HEART_SIZE];
+       uint8_t data[MAX_HEART_SIZE];
 } past_hearts[HB_HISTORY_SIZE];        // Ring buffer of heartbeats that we've recently sent out. Needed so
                                // we can re-transmit if needed.
 
@@ -178,7 +178,7 @@ static int cluster_send_data(void *data, int datalen)
 // Maintains the format. Assumes that the caller
 // has passed in a big enough buffer!
 //
-static void add_type(char **p, int type, int more, char *data, int size)
+static void add_type(uint8_t **p, int type, int more, uint8_t *data, int size)
 {
        *((uint32_t *) (*p)) = type;
        *p += sizeof(uint32_t);
@@ -231,7 +231,7 @@ static void cluster_uptodate(void)
 // Send a unicast UDP packet to a peer with 'data' as the
 // contents.
 //
-static int peer_send_data(in_addr_t peer, char *data, int size)
+static int peer_send_data(in_addr_t peer, uint8_t *data, int size)
 {
        struct sockaddr_in addr = {0};
 
@@ -259,10 +259,10 @@ static int peer_send_data(in_addr_t peer, char *data, int size)
 //
 // Send a structured message to a peer with a single element of type 'type'.
 //
-static int peer_send_message(in_addr_t peer, int type, int more, char *data, int size)
+static int peer_send_message(in_addr_t peer, int type, int more, uint8_t *data, int size)
 {
-       char buf[65536];        // Vast overkill.
-       char *p = buf;
+       uint8_t buf[65536];     // Vast overkill.
+       uint8_t *p = buf;
 
        LOG(4, 0, 0, "Sending message to peer (type %d, more %d, size %d)\n", type, more, size);
        add_type(&p, type, more, data, size);
@@ -271,10 +271,10 @@ static int peer_send_message(in_addr_t peer, int type, int more, char *data, int
 }
 
 // send a packet to the master
-static int _forward_packet(char *data, int size, in_addr_t addr, int port, int type)
+static int _forward_packet(uint8_t *data, int size, in_addr_t addr, int port, int type)
 {
-       char buf[65536];        // Vast overkill.
-       char *p = buf;
+       uint8_t buf[65536];     // Vast overkill.
+       uint8_t *p = buf;
 
        if (!config->cluster_master_address) // No election has been held yet. Just skip it.
                return -1;
@@ -282,7 +282,7 @@ static int _forward_packet(char *data, int size, in_addr_t addr, int port, int t
        LOG(4, 0, 0, "Forwarding packet from %s to master (size %d)\n", fmtaddr(addr, 0), size);
 
        STAT(c_forwarded);
-       add_type(&p, type, addr, (char *) &port, sizeof(port)); // ick. should be uint16_t
+       add_type(&p, type, addr, (uint8_t *) &port, sizeof(port)); // ick. should be uint16_t
        memcpy(p, data, size);
        p += size;
 
@@ -295,13 +295,13 @@ static int _forward_packet(char *data, int size, in_addr_t addr, int port, int t
 // The master just processes the payload as if it had
 // received it off the tun device.
 //
-int master_forward_packet(char *data, int size, in_addr_t addr, int port)
+int master_forward_packet(uint8_t *data, int size, in_addr_t addr, int port)
 {
        return _forward_packet(data, size, addr, port, C_FORWARD);
 }
 
 // Forward a DAE RADIUS packet to the master.
-int master_forward_dae_packet(char *data, int size, in_addr_t addr, int port)
+int master_forward_dae_packet(uint8_t *data, int size, in_addr_t addr, int port)
 {
        return _forward_packet(data, size, addr, port, C_FORWARD_DAE);
 }
@@ -313,10 +313,10 @@ int master_forward_dae_packet(char *data, int size, in_addr_t addr, int port)
 // token bucket queue, and lets normal processing take care
 // of it.
 //
-int master_throttle_packet(int tbfid, char *data, int size)
+int master_throttle_packet(int tbfid, uint8_t *data, int size)
 {
-       char buf[65536];        // Vast overkill.
-       char *p = buf;
+       uint8_t buf[65536];     // Vast overkill.
+       uint8_t *p = buf;
 
        if (!config->cluster_master_address) // No election has been held yet. Just skip it.
                return -1;
@@ -338,10 +338,10 @@ int master_throttle_packet(int tbfid, char *data, int size)
 //
 // (Note that this must be called with the tun header
 // as the start of the data).
-int master_garden_packet(sessionidt s, char *data, int size)
+int master_garden_packet(sessionidt s, uint8_t *data, int size)
 {
-       char buf[65536];        // Vast overkill.
-       char *p = buf;
+       uint8_t buf[65536];     // Vast overkill.
+       uint8_t *p = buf;
 
        if (!config->cluster_master_address) // No election has been held yet. Just skip it.
                return -1;
@@ -358,7 +358,7 @@ int master_garden_packet(sessionidt s, char *data, int size)
 // Send a chunk of data as a heartbeat..
 // We save it in the history buffer as we do so.
 //
-static void send_heartbeat(int seq, char *data, int size)
+static void send_heartbeat(int seq, uint8_t *data, int size)
 {
        int i;
 
@@ -380,8 +380,8 @@ static void send_heartbeat(int seq, char *data, int size)
 //
 void cluster_send_ping(time_t basetime)
 {
-       char buff[100 + sizeof(pingt)];
-       char *p = buff;
+       uint8_t buff[100 + sizeof(pingt)];
+       uint8_t *p = buff;
        pingt x;
 
        if (config->cluster_iam_master && basetime)             // We're heartbeating so no need to ping.
@@ -394,7 +394,7 @@ void cluster_send_ping(time_t basetime)
        x.undef = config->cluster_undefined_sessions + config->cluster_undefined_tunnels;
        x.basetime = basetime;
 
-       add_type(&p, C_PING, basetime, (char *) &x, sizeof(x));
+       add_type(&p, C_PING, basetime, (uint8_t *) &x, sizeof(x));
        cluster_send_data(buff, (p-buff) );
 }
 
@@ -456,7 +456,7 @@ void master_update_counts(void)
 
                        // Forward the data to the master.
        LOG(4, 0, 0, "Sending byte counters to master (%d elements)\n", c);
-       peer_send_message(config->cluster_master_address, C_BYTES, c, (char *) &b, sizeof(b[0]) * c);
+       peer_send_message(config->cluster_master_address, C_BYTES, c, (uint8_t *) &b, sizeof(b[0]) * c);
        return;
 }
 
@@ -738,7 +738,7 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig
                cluster_uptodate();
 }
 
-static int hb_add_type(char **p, int type, int id)
+static int hb_add_type(uint8_t **p, int type, int id)
 {
        switch (type) {
                case C_CSESSION: { // Compressed C_SESSION.
@@ -752,13 +752,13 @@ static int hb_add_type(char **p, int type, int id)
                                // Did we compress the full structure, and is the size actually
                                // reduced??
                        if ( (d - orig) == sizeof(sessiont) && size < sizeof(sessiont) ) {
-                               add_type(p, C_CSESSION, id, (char *) c, size);
+                               add_type(p, C_CSESSION, id, c, size);
                                break;
                        }
                        // Failed to compress : Fall through.
                }
-               case C_SESSION: add_type(p, C_SESSION, id,
-                       (char *) &session[id], sizeof(sessiont));
+               case C_SESSION:
+                       add_type(p, C_SESSION, id, (uint8_t *) &session[id], sizeof(sessiont));
                        break;
 
                case C_CTUNNEL: { // Compressed C_TUNNEL
@@ -777,8 +777,8 @@ static int hb_add_type(char **p, int type, int id)
                        }
                        // Failed to compress : Fall through.
                }
-               case C_TUNNEL: add_type(p, C_TUNNEL, id,
-                       (char *) &tunnel[id], sizeof(tunnelt));
+               case C_TUNNEL:
+                       add_type(p, C_TUNNEL, id, (uint8_t *) &tunnel[id], sizeof(tunnelt));
                        break;
                default:
                        LOG(0, 0, 0, "Found an invalid type in heart queue! (%d)\n", type);
@@ -794,9 +794,9 @@ static int hb_add_type(char **p, int type, int id)
 void cluster_heartbeat()
 {
        int i, count = 0, tcount = 0;
-       char buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ];
+       uint8_t buff[MAX_HEART_SIZE + sizeof(heartt) + sizeof(int) ];
        heartt h;
-       char *p = buff;
+       uint8_t *p = buff;
 
        if (!config->cluster_iam_master)        // Only the master does this.
                return;
@@ -820,7 +820,7 @@ void cluster_heartbeat()
        h.timeout  = config->cluster_hb_timeout;
        h.table_version = config->cluster_table_version;
 
-       add_type(&p, C_HEARTBEAT, HB_VERSION, (char *) &h, sizeof(h));
+       add_type(&p, C_HEARTBEAT, HB_VERSION, (uint8_t *) &h, sizeof(h));
 
        for (i = 0; i < config->cluster_num_changes; ++i) {
                hb_add_type(&p, cluster_changes[i].type, cluster_changes[i].id);
@@ -1099,7 +1099,7 @@ static int cluster_set_master(in_addr_t peer, in_addr_t master)
 // Note that we don't mark the session as dirty; We rely on
 // the slow table walk to propogate this back out to the slaves.
 //
-static int cluster_handle_bytes(char *data, int size)
+static int cluster_handle_bytes(uint8_t *data, int size)
 {
        bytest *b;
 
@@ -1238,6 +1238,9 @@ struct oldsession {
        uint32_t tx_connect_speed;
        uint32_t rx_connect_speed;
        uint32_t flags;
+#define SF_IPCP_ACKED  1       // Has this session seen an IPCP Ack?
+#define SF_LCP_ACKED   2       // LCP negotiated
+#define SF_CCP_ACKED   4       // CCP negotiated
        in_addr_t snoop_ip;
        uint16_t snoop_port;
        uint16_t sid;
@@ -1257,7 +1260,6 @@ static uint8_t *convert_session(struct oldsession *old)
        new.far = old->far;
        new.tunnel = old->tunnel;
        new.l2tp_flags = old->l2tp_flags;
-       new.flags = old->flags;
        new.ip = old->ip;
        new.ip_pool_index = old->ip_pool_index;
        new.unique_id = old->unique_id;
@@ -1297,6 +1299,21 @@ static uint8_t *convert_session(struct oldsession *old)
        for (i = 0; i < MAXROUTE; i++)
                memcpy(&new.route[i], &old->route[i], sizeof(new.route[i]));
 
+       if (new.opened)
+       {
+               new.ppp.phase = Establish;
+               if (old->flags & (SF_IPCP_ACKED|SF_LCP_ACKED))
+               {
+                       new.ppp.phase = Network;
+                       new.ppp.lcp   = Opened;
+                       new.ppp.ipcp  = (old->flags & SF_IPCP_ACKED) ? Opened : Starting;
+                       new.ppp.ccp   = (old->flags & SF_CCP_ACKED)  ? Opened : Stopped;
+               }
+
+               // no PPPv6 in old session
+               new.ppp.ipv6cp = Stopped;
+       }
+
        return (uint8_t *) &new;
 }
 
@@ -1572,10 +1589,10 @@ shortpacket:
 // We got a packet on the cluster port!
 // Handle pings, lastseens, and heartbeats!
 //
-int processcluster(char *data, int size, in_addr_t addr)
+int processcluster(uint8_t *data, int size, in_addr_t addr)
 {
        int type, more;
-       char *p = data;
+       uint8_t *p = data;
        int s = size;
 
        if (addr == my_address)
@@ -1814,7 +1831,7 @@ static int rle_decompress(uint8_t **src_p, int ssize, uint8_t *dst, int dsize)
 {
        int count;
        int orig_dsize = dsize;
-       char *src = *src_p;
+       uint8_t *src = *src_p;
 
        while (ssize >0 && dsize > 0) { // While there's more to decompress, and there's room in the decompress buffer...
                count = *src++; --ssize;  // get the count byte from the source.
index 931c007..4fe7ad0 100644 (file)
--- a/cluster.h
+++ b/cluster.h
@@ -1,5 +1,5 @@
 // L2TPNS Clustering Stuff
-// $Id: cluster.h,v 1.13 2005-06-28 14:48:19 bodea Exp $
+// $Id: cluster.h,v 1.14 2005-07-31 10:04:10 bodea Exp $
 
 #ifndef __CLUSTER_H__
 #define __CLUSTER_H__
@@ -72,13 +72,13 @@ typedef struct {
 } pingt;
 
 int cluster_init(void);
-int processcluster(char *buf, int size, in_addr_t addr);
+int processcluster(uint8_t *buf, int size, in_addr_t addr);
 int cluster_send_session(int sid);
 int cluster_send_tunnel(int tid);
-int master_forward_packet(char *data, int size, in_addr_t addr, int port);
-int master_forward_dae_packet(char *data, int size, in_addr_t addr, int port);
-int master_throttle_packet(int tid, char *data, int size);
-int master_garden_packet(sessionidt s, char *data, int size);
+int master_forward_packet(uint8_t *data, int size, in_addr_t addr, int port);
+int master_forward_dae_packet(uint8_t *data, int size, in_addr_t addr, int port);
+int master_throttle_packet(int tid, uint8_t *data, int size);
+int master_garden_packet(sessionidt s, uint8_t *data, int size);
 void master_update_counts(void);
 void cluster_send_ping(time_t basetime);
 void cluster_heartbeat(void);
index f9e3fa1..48e7d59 100644 (file)
@@ -1,6 +1,6 @@
 // L2TPNS: constants
 
-char const *cvs_id_constants = "$Id: constants.c,v 1.6 2005-06-28 14:48:20 bodea Exp $";
+char const *cvs_id_constants = "$Id: constants.c,v 1.7 2005-07-31 10:04:10 bodea Exp $";
 
 #include <stdio.h>
 #include "constants.h"
@@ -19,19 +19,27 @@ char const *cvs_id_constants = "$Id: constants.c,v 1.6 2005-06-28 14:48:20 bodea
        return n; \
     }
 
-CONSTANT(lcp_type,
+CONSTANT(l2tp_code,
     0,                                                 // 0
-    "Maximum-Receive-Unit",                            // 1
-    "Async-Control-Map",                               // 2
-    "Authentication-Protocol",                         // 3
-    "Quality-Protocol",                                        // 4
-    "Magic-Number",                                    // 5
-    0,                                                 // 6
-    "Protocol-Field-Compression",                      // 7
-    "Address-and-Control-Field-Compression"            // 8
+    "SCCRQ",                                           // 1
+    "SCCRP",                                           // 2
+    "SCCCN",                                           // 3
+    "StopCCN",                                         // 4
+    0,                                                 // 5
+    "HELLO",                                           // 6
+    "OCRQ",                                            // 7
+    "OCRP",                                            // 8
+    "OCCN",                                            // 9
+    "ICRQ",                                            // 10
+    "ICRP",                                            // 11
+    "ICCN",                                            // 12
+    0,                                                 // 13
+    "CDN",                                             // 14
+    "WEN",                                             // 15
+    "SLI"                                              // 16
 )
 
-CONSTANT(avp_name,
+CONSTANT(l2tp_avp_name,
     "Message Type",                                    // 0
     "Result Code",                                     // 1
     "Protocol Version",                                        // 2
@@ -74,7 +82,7 @@ CONSTANT(avp_name,
     "Sequencing Required"                              // 39
 )
 
-CONSTANT(stopccn_result_code,
+CONSTANT(l2tp_stopccn_result_code,
     0,                                                 // 0
     "General request to clear control connection",     // 1
     "General error--Error Code indicates the problem", // 2
@@ -87,7 +95,7 @@ CONSTANT(stopccn_result_code,
     "Finite State Machine error"                       // 7
 )
 
-CONSTANT(cdn_result_code,
+CONSTANT(l2tp_cdn_result_code,
     0,                                                 // 0
     "Call disconnected due to loss of carrier",                // 1
     "Call disconnected for the reason indicated in"
@@ -107,7 +115,7 @@ CONSTANT(cdn_result_code,
        " detected"                                     // 11
 )
 
-CONSTANT(error_code,
+CONSTANT(l2tp_error_code,
     "No general error",                                        // 0
     "No control connection exists yet for this LAC-LNS"
        " pair",                                        // 1
@@ -124,7 +132,28 @@ CONSTANT(error_code,
        " an unknown AVP with the M-bit set"            // 8
 )
 
-CONSTANT(auth_type,
+CONSTANT(ppp_phase,
+    "Dead",                                            // 0
+    "Establish",                                       // 1
+    "Authenticate",                                    // 2
+    "Network",                                         // 3
+    "Terminate",                                       // 4
+)
+
+CONSTANT(ppp_state,
+    "Initial",                                         // 0
+    "Starting",                                                // 1
+    "Closed",                                          // 2
+    "Stopped",                                         // 3
+    "Closing",                                         // 4
+    "Stopping",                                                // 5
+    "Request-Sent",                                    // 6
+    "Ack-Received",                                    // 7
+    "Ack-Sent",                                                // 8
+    "Opened"                                           // 9
+)
+
+CONSTANT(ppp_auth_type,
     0,                                                 // 0
     "Textual username/password exchange",              // 1
     "PPP CHAP",                                                // 2
@@ -133,7 +162,7 @@ CONSTANT(auth_type,
     "Microsoft CHAP Version 1 (MSCHAPv1)"              // 5
 )
 
-CONSTANT(ppp_lcp_type,
+CONSTANT(ppp_code,
     0,                                                 // 0
     "ConfigReq",                                       // 1
     "ConfigAck",                                       // 2
@@ -149,15 +178,26 @@ CONSTANT(ppp_lcp_type,
     "IdentRequest"                                     // 12
 )
 
+CONSTANT(ppp_lcp_option,
+    0,                                                 // 0
+    "Maximum-Receive-Unit",                            // 1
+    "Async-Control-Map",                               // 2
+    "Authentication-Protocol",                         // 3
+    "Quality-Protocol",                                        // 4
+    "Magic-Number",                                    // 5
+    0,                                                 // 6
+    "Protocol-Field-Compression",                      // 7
+    "Address-and-Control-Field-Compression"            // 8
+)
+
 CONSTANT(radius_state,
     "RADIUSNULL",                                      // 0
     "RADIUSCHAP",                                      // 1
     "RADIUSAUTH",                                      // 2
-    "RADIUSIPCP",                                      // 3
-    "RADIUSSTART",                                     // 4
-    "RADIUSSTOP",                                      // 5
-    "RADIUSINTERIM",                                   // 6
-    "RADIUSWAIT"                                       // 7
+    "RADIUSSTART",                                     // 3
+    "RADIUSSTOP",                                      // 4
+    "RADIUSINTERIM",                                   // 5
+    "RADIUSWAIT"                                       // 6
 )
 
 CONSTANT(radius_code,
@@ -185,23 +225,3 @@ CONSTANT(radius_code,
     "CoA-ACK",                                         // 44
     "CoA-NAK"                                          // 45
 )
-
-CONSTANT(l2tp_message_type,
-    0,                                                 // 0
-    "SCCRQ",                                           // 1
-    "SCCRP",                                           // 2
-    "SCCCN",                                           // 3
-    "StopCCN",                                         // 4
-    0,                                                 // 5
-    "HELLO",                                           // 6
-    "OCRQ",                                            // 7
-    "OCRP",                                            // 8
-    "OCCN",                                            // 9
-    "ICRQ",                                            // 10
-    "ICRP",                                            // 11
-    "ICCN",                                            // 12
-    0,                                                 // 13
-    "CDN",                                             // 14
-    "WEN",                                             // 15
-    "SLI"                                              // 16
-)
index a27ce79..a9693c3 100644 (file)
@@ -1,15 +1,17 @@
 #ifndef __CONSTANTS_H__
 #define __CONSTANTS_H__
 
-char const *lcp_type(int type);
-char const *avp_name(int avp);
-char const *stopccn_result_code(int code);
-char const *cdn_result_code(int code);
-char const *error_code(int code);
-char const *auth_type(int type);
-char const *ppp_lcp_type(int type);
+char const *l2tp_code(int type);
+char const *l2tp_avp_name(int avp);
+char const *l2tp_stopccn_result_code(int code);
+char const *l2tp_cdn_result_code(int code);
+char const *l2tp_error_code(int code);
+char const *ppp_phase(int code);
+char const *ppp_state(int code);
+char const *ppp_auth_type(int type);
+char const *ppp_code(int type);
+char const *ppp_lcp_option(int type);
 char const *radius_state(int state);
 char const *radius_code(int code);
-char const *l2tp_message_type(int type);
 
 #endif /* __CONSTANTS_H__ */
index bd65de5..805a90b 100644 (file)
--- a/control.c
+++ b/control.c
@@ -1,12 +1,12 @@
 // L2TPNS: control
 
-char const *cvs_id_control = "$Id: control.c,v 1.4 2004-12-16 08:49:53 bodea Exp $";
+char const *cvs_id_control = "$Id: control.c,v 1.5 2005-07-31 10:04:10 bodea Exp $";
 
 #include <string.h>
 #include "l2tpns.h"
 #include "control.h"
 
-int pack_control(char *data, int len, uint8_t type, int argc, char *argv[])
+int pack_control(uint8_t *data, int len, uint8_t type, int argc, char *argv[])
 {
     struct nsctl_packet pkt;
     struct nsctl_args arg;
@@ -62,7 +62,7 @@ int pack_control(char *data, int len, uint8_t type, int argc, char *argv[])
     return sz;
 }
 
-int unpack_control(struct nsctl *control, char *data, int len)
+int unpack_control(struct nsctl *control, uint8_t *data, int len)
 {
     struct nsctl_packet pkt;
     char *p = pkt.argv;
index ee7ed7d..e1f7d54 100644 (file)
--- a/control.h
+++ b/control.h
@@ -47,8 +47,8 @@ struct nsctl {
     char *argv[0xff];
 };
 
-int pack_control(char *data, int len, uint8_t type, int argc, char *argv[]);
-int unpack_control(struct nsctl *packet, char *data, int len);
+int pack_control(uint8_t *data, int len, uint8_t type, int argc, char *argv[]);
+int unpack_control(struct nsctl *packet, uint8_t *data, int len);
 void dump_control(struct nsctl *control, FILE *stream);
 
 #endif /* __CONTROL_H__ */
diff --git a/icmp.c b/icmp.c
index da04c38..93d00c1 100644 (file)
--- a/icmp.c
+++ b/icmp.c
@@ -1,6 +1,6 @@
 // L2TPNS: icmp
 
-char const *cvs_id_icmp = "$Id: icmp.c,v 1.8 2005-06-04 15:42:06 bodea Exp $";
+char const *cvs_id_icmp = "$Id: icmp.c,v 1.9 2005-07-31 10:04:10 bodea Exp $";
 
 #include <arpa/inet.h>
 #include <netdb.h>
@@ -18,7 +18,7 @@ char const *cvs_id_icmp = "$Id: icmp.c,v 1.8 2005-06-04 15:42:06 bodea Exp $";
 
 #include "l2tpns.h"
 
-static uint16_t _checksum(unsigned char *addr, int count);
+static uint16_t _checksum(uint8_t *addr, int count);
 
 struct ipv6_pseudo_hdr {
        struct in6_addr src;
@@ -28,7 +28,7 @@ struct ipv6_pseudo_hdr {
        uint32_t nexthdr :  8;
 };
 
-void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, char *packet, int packet_len)
+void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, uint8_t *packet, int packet_len)
 {
        char buf[128] = {0};
        struct iphdr *iph;
@@ -72,15 +72,15 @@ void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, char
 
        icmp->type = ICMP_DEST_UNREACH;
        icmp->code = ICMP_HOST_UNREACH;
-       icmp->checksum = _checksum((char *) icmp, sizeof(struct icmphdr) + packet_len);
+       icmp->checksum = _checksum((uint8_t *) icmp, sizeof(struct icmphdr) + packet_len);
 
-       iph->check = _checksum((char *) iph, sizeof(struct iphdr));
+       iph->check = _checksum((uint8_t *) iph, sizeof(struct iphdr));
 
-       sendto(icmp_socket, (char *)buf, len, 0, (struct sockaddr *)&whereto, sizeof(struct sockaddr));
+       sendto(icmp_socket, buf, len, 0, (struct sockaddr *)&whereto, sizeof(struct sockaddr));
        close(icmp_socket);
 }
 
-static uint16_t _checksum(unsigned char *addr, int count)
+static uint16_t _checksum(uint8_t *addr, int count)
 {
        register long sum = 0;
 
index a729992..8204503 100644 (file)
--- a/l2tpns.c
+++ b/l2tpns.c
@@ -4,7 +4,7 @@
 // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
 // vim: sw=8 ts=8
 
-char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.114 2005-07-04 05:49:46 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.115 2005-07-31 10:04:10 bodea Exp $";
 
 #include <arpa/inet.h>
 #include <assert.h>
@@ -38,9 +38,9 @@ char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.114 2005-07-04 05:49:46 bodea Exp
 #include <unistd.h>
 #include <sched.h>
 #include <sys/sysinfo.h>
+#include <openssl/md5.h>
 #include <libcli.h>
 
-#include "md5.h"
 #include "l2tpns.h"
 #include "cluster.h"
 #include "plugin.h"
@@ -105,6 +105,9 @@ config_descriptt config_values[] = {
        CONFIG("pid_file", pid_file, STRING),
        CONFIG("random_device", random_device, STRING),
        CONFIG("l2tp_secret", l2tpsecret, STRING),
+       CONFIG("ppp_restart_time", ppp_restart_time, INT),
+       CONFIG("ppp_max_configure", ppp_max_configure, INT),
+       CONFIG("ppp_max_failure", ppp_max_failure, INT),
        CONFIG("primary_dns", default_dns1, IPv4),
        CONFIG("secondary_dns", default_dns2, IPv4),
        CONFIG("primary_radius", radiusserver[0], IPv4),
@@ -182,7 +185,7 @@ static void sighup_handler(int sig);
 static void sigalrm_handler(int sig);
 static void shutdown_handler(int sig);
 static void sigchild_handler(int sig);
-static void build_chap_response(char *challenge, uint8_t id, uint16_t challenge_length, char **challenge_response);
+static void build_chap_response(uint8_t *challenge, uint8_t id, uint16_t challenge_length, uint8_t **challenge_response);
 static void update_config(void);
 static void read_config_file(void);
 static void initplugins(void);
@@ -258,10 +261,10 @@ void _log(int level, sessionidt s, tunnelidt t, const char *format, ...)
        va_end(ap);
 }
 
-void _log_hex(int level, const char *title, const char *data, int maxsize)
+void _log_hex(int level, const char *title, const uint8_t *data, int maxsize)
 {
        int i, j;
-       const uint8_t *d = (const uint8_t *) data;
+       const uint8_t *d = data;
 
        if (config->debug < level) return;
 
@@ -551,7 +554,7 @@ static void inittun(void)
        tunidx = ifr.ifr_ifindex;
 
        // Only setup IPv6 on the tun device if we have a configured prefix
-       if (config->ipv6_prefix.s6_addr[0] > 0) {
+       if (config->ipv6_prefix.s6_addr[0]) {
                ifr6fd = socket(PF_INET6, SOCK_DGRAM, 0);
 
                // Link local address is FE80::1
@@ -702,8 +705,11 @@ sessionidt sessionbyipv6(struct in6_addr ip)
        CSTAT(sessionbyipv6);
 
        if (!memcmp(&config->ipv6_prefix, &ip, 8) ||
-               (ip.s6_addr[0] == 0xFE && ip.s6_addr[1] == 0x80 &&
-                (ip.s6_addr16[1] == ip.s6_addr16[2] == ip.s6_addr16[3] == 0))) {
+               (ip.s6_addr[0] == 0xFE &&
+                ip.s6_addr[1] == 0x80 &&
+                ip.s6_addr16[1] == 0 &&
+                ip.s6_addr16[2] == 0 &&
+                ip.s6_addr16[3] == 0)) {
                s = lookup_ipmap(*(in_addr_t *) &ip.s6_addr[8]);
        } else {
                s = lookup_ipv6map(ip);
@@ -973,14 +979,14 @@ int tun_write(uint8_t * data, int size)
 
 // process outgoing (to tunnel) IP
 //
-static void processipout(uint8_t * buf, int len)
+static void processipout(uint8_t *buf, int len)
 {
        sessionidt s;
        sessiont *sp;
        tunnelidt t;
        in_addr_t ip;
 
-       char *data = buf;       // Keep a copy of the originals.
+       uint8_t *data = buf;    // Keep a copy of the originals.
        int size = len;
 
        uint8_t b[MAXETHER + 20];
@@ -1126,7 +1132,7 @@ static void processipv6out(uint8_t * buf, int len)
        in_addr_t ip;
        struct in6_addr ip6;
 
-       char *data = buf;       // Keep a copy of the originals.
+       uint8_t *data = buf;    // Keep a copy of the originals.
        int size = len;
 
        uint8_t b[MAXETHER + 20];
@@ -1313,7 +1319,7 @@ static void controls(controlt * c, uint16_t avp, char *val, uint8_t m)
 }
 
 // add a binary AVP
-static void controlb(controlt * c, uint16_t avp, char *val, unsigned int len, uint8_t m)
+static void controlb(controlt * c, uint16_t avp, uint8_t *val, unsigned int len, uint8_t m)
 {
        uint16_t l = ((m ? 0x8000 : 0) + len + 6);
        *(uint16_t *) (c->buf + c->length + 0) = htons(l);
@@ -1493,10 +1499,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error)
        if (session[s].ip && !walled_garden && !session[s].die)
        {
                // RADIUS Stop message
-               uint16_t r = sess_local[s].radius;
-               if (!r)
-                       r = radiusnew(s);
-
+               uint16_t r = radiusnew(s);
                if (r)
                {
                        // stop, if not already trying
@@ -1534,7 +1537,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error)
                        free_ip_address(s);
 
                // unroute IPv6, if setup
-               if (session[s].flags & SF_IPV6_ROUTED)
+               if (session[s].ppp.ipv6cp == Opened && session[s].ipv6prefixlen)
                        route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0);
        }
 
@@ -1546,7 +1549,7 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error)
                controlt *c = controlnew(14); // sending CDN
                if (error)
                {
-                       char buf[4];
+                       uint8_t buf[4];
                        *(uint16_t *) buf     = htons(result);
                        *(uint16_t *) (buf+2) = htons(error);
                        controlb(c, 1, buf, 4, 1);
@@ -1565,78 +1568,66 @@ void sessionshutdown(sessionidt s, char *reason, int result, int error)
        if (session[s].filter_in) ip_filters[session[s].filter_in - 1].used--;
        if (session[s].filter_out) ip_filters[session[s].filter_out - 1].used--;
 
+       // clear PPP state
+       memset(&session[s].ppp, 0, sizeof(session[s].ppp));
+       sess_local[s].lcp.restart = 0;
+       sess_local[s].ipcp.restart = 0;
+       sess_local[s].ipv6cp.restart = 0;
+       sess_local[s].ccp.restart = 0;
+
        cluster_send_session(s);
 }
 
 void sendipcp(tunnelidt t, sessionidt s)
 {
        uint8_t buf[MAXCONTROL];
-       uint16_t r = sess_local[s].radius;
        uint8_t *q;
 
        CSTAT(sendipcp);
 
-       if (!r)
-               r = radiusnew(s);
-
-       if (!r)
-       {
-               sessionshutdown(s, "No free RADIUS sessions for IPCP", 3, 0);
-               return;
-       }
-
-       if (radius[r].state != RADIUSIPCP)
-       {
-               radius[r].state = RADIUSIPCP;
-               radius[r].try = 0;
-       }
-
-       radius[r].retry = backoff(radius[r].try++);
-       if (radius[r].try > 10)
+       if (!session[s].unique_id)
        {
-               radiusclear(r, s);      // Clear radius session.
-               sessionshutdown(s, "No reply to IPCP.", 3, 0);
-               return;
+               if (!++last_id) ++last_id; // skip zero
+               session[s].unique_id = last_id;
        }
 
        q = makeppp(buf,sizeof(buf), 0, 0, t, s, PPPIPCP);
        if (!q) return;
 
        *q = ConfigReq;
-       q[1] = r >> RADIUS_SHIFT;                    // ID, dont care, we only send one type of request
-       *(uint16_t *) (q + 2) = htons(10);
-       q[4] = 3;
-       q[5] = 6;
+       q[1] = session[s].unique_id & 0xf;      // ID, dont care, we only send one type of request
+       *(uint16_t *) (q + 2) = htons(10);      // packet length
+       q[4] = 3;                               // ip address option
+       q[5] = 6;                               // option length
        *(in_addr_t *) (q + 6) = config->peer_address ? config->peer_address :
                                 config->bind_address ? config->bind_address :
                                 my_address; // send my IP
 
        tunnelsend(buf, 10 + (q - buf), t); // send it
-       session[s].flags &= ~SF_IPCP_ACKED;     // Clear flag.
-
-       // If we have an IPv6 prefix length configured, assume we should
-       // try to negotiate an IPv6 session as well. Unless we've had a
-       // (N)ACK for IPV6CP.
-       if (config->ipv6_prefix.s6_addr[0] > 0 && 
-                       !(session[s].flags & SF_IPV6CP_ACKED) &&
-                       !(session[s].flags & SF_IPV6_NACKED))
-       {
-               q = makeppp(buf,sizeof(buf), 0, 0, t, s, PPPIPV6CP);
-               if (!q) return;
-
-               *q = ConfigReq;
-               q[1] = r >> RADIUS_SHIFT;               // ID, don't care, we
-                                                       // only send one type
-                                                       // of request
-               *(uint16_t *) (q + 2) = htons(14);
-               q[4] = 1;
-               q[5] = 10;
-               *(uint32_t *) (q + 6) = 0;              // We'll be prefix::1
-               *(uint32_t *) (q + 10) = 0;
-               q[13] = 1;
-
-               tunnelsend(buf, 14 + (q - buf), t);     // send it
-       }
+}
+
+void sendipv6cp(tunnelidt t, sessionidt s)
+{
+       uint8_t buf[MAXCONTROL];
+       uint8_t *q;
+
+       CSTAT(sendipv6cp);
+
+       q = makeppp(buf,sizeof(buf), 0, 0, t, s, PPPIPV6CP);
+       if (!q) return;
+
+       *q = ConfigReq;
+       q[1] = session[s].unique_id & 0xf;      // ID, don't care, we
+                                               // only send one type
+                                               // of request
+       *(uint16_t *) (q + 2) = htons(14);
+       q[4] = 1;                               // interface identifier option
+       q[5] = 10;                              // option length
+       *(uint32_t *) (q + 6) = 0;              // We'll be prefix::1
+       *(uint32_t *) (q + 10) = 0;
+       q[13] = 1;
+
+       tunnelsend(buf, 14 + (q - buf), t);     // send it
 }
 
 static void sessionclear(sessionidt s)
@@ -1742,7 +1733,7 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha
                controlt *c = controlnew(4);    // sending StopCCN
                if (error)
                {
-                       char buf[64];
+                       uint8_t buf[64];
                        int l = 4;
                        *(uint16_t *) buf     = htons(result);
                        *(uint16_t *) (buf+2) = htons(error);
@@ -1767,9 +1758,9 @@ static void tunnelshutdown(tunnelidt t, char *reason, int result, int error, cha
 }
 
 // read and process packet on tunnel (UDP)
-void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
+void processudp(uint8_t *buf, int len, struct sockaddr_in *addr)
 {
-       char *chapresponse = NULL;
+       uint8_t *chapresponse = NULL;
        uint16_t l = len, t = 0, s = 0, ns = 0, nr = 0;
        uint8_t *p = buf + 2;
 
@@ -2061,7 +2052,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                        n = orig_len;
                                }
 
-                               LOG(4, s, t, "   AVP %d (%s) len %d%s%s\n", mtype, avp_name(mtype), n,
+                               LOG(4, s, t, "   AVP %d (%s) len %d%s%s\n", mtype, l2tp_avp_name(mtype), n,
                                        flags & 0x40 ? ", hidden" : "", flags & 0x80 ? ", mandatory" : "");
 
                                switch (mtype)
@@ -2069,7 +2060,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                case 0:     // message type
                                        message = ntohs(*(uint16_t *) b);
                                        mandatory = flags & 0x80;
-                                       LOG(4, s, t, "   Message type = %d (%s)\n", *b, l2tp_message_type(message));
+                                       LOG(4, s, t, "   Message type = %d (%s)\n", *b, l2tp_code(message));
                                        break;
                                case 1:     // result code
                                        {
@@ -2077,18 +2068,18 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                                const char* resdesc = "(unknown)";
                                                if (message == 4)
                                                { /* StopCCN */
-                                                       resdesc = stopccn_result_code(rescode);
+                                                       resdesc = l2tp_stopccn_result_code(rescode);
                                                }
                                                else if (message == 14)
                                                { /* CDN */
-                                                       resdesc = cdn_result_code(rescode);
+                                                       resdesc = l2tp_cdn_result_code(rescode);
                                                }
 
                                                LOG(4, s, t, "   Result Code %d: %s\n", rescode, resdesc);
                                                if (n >= 4)
                                                {
                                                        uint16_t errcode = ntohs(*(uint16_t *)(b + 2));
-                                                       LOG(4, s, t, "   Error Code %d: %s\n", errcode, error_code(errcode));
+                                                       LOG(4, s, t, "   Error Code %d: %s\n", errcode, l2tp_error_code(errcode));
                                                }
                                                if (n > 4)
                                                        LOG(4, s, t, "   Error String: %.*s\n", n-4, b+4);
@@ -2222,7 +2213,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                case 29:    // Proxy Authentication Type
                                        {
                                                uint16_t atype = ntohs(*(uint16_t *)b);
-                                               LOG(4, s, t, "   Proxy Auth Type %d (%s)\n", atype, auth_type(atype));
+                                               LOG(4, s, t, "   Proxy Auth Type %d (%s)\n", atype, ppp_auth_type(atype));
                                                if (atype == 2)
                                                        authtype = AUTHCHAP;
                                                else if (atype == 3)
@@ -2351,7 +2342,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                case 10:      // ICRQ
                                        if (sessionfree && main_quit != QUIT_SHUTDOWN)
                                        {
-                                               uint16_t r;
+                                               controlt *c = controlnew(11); // ICRP
 
                                                s = sessionfree;
                                                sessionfree = session[s].next;
@@ -2360,41 +2351,34 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                                if (s > config->cluster_highest_sessionid)
                                                        config->cluster_highest_sessionid = s;
 
-                                               // make a RADIUS session
-                                               if ((r = radiusnew(s)))
-                                               {
-                                                       controlt *c = controlnew(11); // sending ICRP
-                                                       session[s].opened = time_now;
-                                                       session[s].tunnel = t;
-                                                       session[s].far = asession;
-                                                       session[s].last_packet = time_now;
-                                                       LOG(3, s, t, "New session (%d/%d)\n", tunnel[t].far, session[s].far);
-                                                       control16(c, 14, s, 1); // assigned session
-                                                       controladd(c, t, asession); // send the reply
-
-                                                       strncpy(radius[r].calling, calling, sizeof(radius[r].calling) - 1);
-                                                       strncpy(session[s].called, called, sizeof(session[s].called) - 1);
-                                                       strncpy(session[s].calling, calling, sizeof(session[s].calling) - 1);
-                                                       STAT(session_created);
-                                                       break;
-                                               }
+                                               session[s].opened = time_now;
+                                               session[s].tunnel = t;
+                                               session[s].far = asession;
+                                               session[s].last_packet = time_now;
+                                               LOG(3, s, t, "New session (%d/%d)\n", tunnel[t].far, session[s].far);
+                                               control16(c, 14, s, 1); // assigned session
+                                               controladd(c, t, asession); // send the reply
 
+                                               strncpy(session[s].called, called, sizeof(session[s].called) - 1);
+                                               strncpy(session[s].calling, calling, sizeof(session[s].calling) - 1);
 
-                                               LOG(1, s, t, "No free RADIUS sessions for ICRQ\n");
-                                               sessionclear(s);
-                                       }
-                                       else
-                                       {
-                                               STAT(session_overflow);
-                                               LOG(1, 0, t, "No free sessions\n");
+                                               session[s].ppp.phase = Establish;
+                                               session[s].ppp.lcp = Starting;
+
+                                               STAT(session_created);
+                                               break;
                                        }
 
                                        {
                                                controlt *c = controlnew(14); // CDN
-                                               if (main_quit == QUIT_SHUTDOWN)
-                                                       control16(c, 1, 2, 7); // try another
-                                               else
+                                               if (!sessionfree)
+                                               {
+                                                       STAT(session_overflow);
+                                                       LOG(1, 0, t, "No free sessions\n");
                                                        control16(c, 1, 4, 0); // temporary lack of resources
+                                               }
+                                               else
+                                                       control16(c, 1, 2, 7); // shutting down, try another
 
                                                controladd(c, t, asession); // send the message
                                        }
@@ -2408,12 +2392,19 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                                        session[s].l2tp_flags = aflags; // set flags received
                                        LOG(3, s, t, "Magic %X Flags %X\n", amagic, aflags);
                                        controlnull(t); // ack
+
                                        // proxy authentication type is not supported
                                        if (!(config->radius_authtypes & authtype))
                                                authtype = config->radius_authprefer;
 
                                        // start LCP
                                        sendlcp(t, s, authtype);
+                                       sess_local[s].lcp.restart = time_now + config->ppp_restart_time;
+                                       sess_local[s].lcp.conf_sent = 1;
+                                       sess_local[s].lcp.nak_sent = 0;
+                                       sess_local[s].lcp_authtype = authtype;
+                                       session[s].ppp.lcp = RequestSent;
+
                                        break;
                                case 14:      // CDN
                                        controlnull(t); // ack
@@ -2507,16 +2498,9 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                }
                else if (prot == PPPIPV6CP)
                {
-                       if (config->ipv6_prefix.s6_addr[0] > 0)
-                       {
-                               session[s].last_packet = time_now;
-                               if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
-                               processipv6cp(t, s, p, l);
-                       }
-                       else
-                       {
-                               LOG(1, s, t, "IPv6 not configured; ignoring IPv6CP\n");
-                       }
+                       session[s].last_packet = time_now;
+                       if (!config->cluster_iam_master) { master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port); return; }
+                       processipv6cp(t, s, p, l);
                }
                else if (prot == PPPCCP)
                {
@@ -2543,7 +2527,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr)
                }
                else if (prot == PPPIPV6)
                {
-                       if (!config->ipv6_prefix.s6_addr[0] > 0)
+                       if (!config->ipv6_prefix.s6_addr[0])
                        {
                                LOG(1, s, t, "IPv6 not configured; yet received IPv6 packet. Ignoring.\n");
                                return;
@@ -2592,7 +2576,7 @@ static void processtun(uint8_t * buf, int len)
        if (*(uint16_t *) (buf + 2) == htons(PKTIP)) // IPv4
                processipout(buf, len);
        else if (*(uint16_t *) (buf + 2) == htons(PKTIPV6) // IPV6
-           && config->ipv6_prefix.s6_addr[0] > 0)
+           && config->ipv6_prefix.s6_addr[0])
                processipv6out(buf, len);
 
        // Else discard.
@@ -2734,13 +2718,123 @@ static void regular_cleanups(double period)
                        continue;
                }
 
-               if (session[s].ip && !(session[s].flags & SF_IPCP_ACKED)
-                   && !(sess_local[s].radius && radius[sess_local[s].radius].state == RADIUSIPCP))
+               // PPP timeouts
+               if (sess_local[s].lcp.restart >= time_now)
                {
-                       // IPCP has not completed yet. Resend
-                       LOG(3, s, session[s].tunnel, "No ACK for initial IPCP ConfigReq... resending\n");
-                       sendipcp(session[s].tunnel, s);
-                       s_actions++;
+                       int next_state = session[s].ppp.lcp;
+                       switch (session[s].ppp.lcp)
+                       {
+                       case RequestSent:
+                       case AckReceived:
+                               next_state = RequestSent;
+
+                       case AckSent:
+                               if (sess_local[s].lcp.conf_sent < config->ppp_max_configure)
+                               {
+                                       LOG(3, s, session[s].tunnel, "No ACK for LCP ConfigReq... resending\n");
+                                       sess_local[s].lcp.restart = time_now + config->ppp_restart_time;
+                                       sess_local[s].lcp.conf_sent++;
+                                       sendlcp(t, s, sess_local[s].lcp_authtype);
+                                       change_state(s, lcp, next_state);
+                               }
+                               else
+                               {
+                                       sessionshutdown(s, "No response to LCP ConfigReq.", 3, 0);
+                                       STAT(session_timeout);
+                               }
+
+                               s_actions++;
+                       }
+
+                       if (session[s].die)
+                               continue;
+               }
+
+               if (sess_local[s].ipcp.restart >= time_now)
+               {
+                       int next_state = session[s].ppp.ipcp;
+                       switch (session[s].ppp.ipcp)
+                       {
+                       case RequestSent:
+                       case AckReceived:
+                               next_state = RequestSent;
+
+                       case AckSent:
+                               if (sess_local[s].ipcp.conf_sent < config->ppp_max_configure)
+                               {
+                                       LOG(3, s, session[s].tunnel, "No ACK for IPCP ConfigReq... resending\n");
+                                       sess_local[s].ipcp.restart = time_now + config->ppp_restart_time;
+                                       sess_local[s].ipcp.conf_sent++;
+                                       sendipcp(t, s);
+                                       change_state(s, ipcp, next_state);
+                               }
+                               else
+                               {
+                                       sessionshutdown(s, "No response to IPCP ConfigReq.", 3, 0);
+                                       STAT(session_timeout);
+                               }
+
+                               s_actions++;
+                       }
+
+                       if (session[s].die)
+                               continue;
+               }
+
+               if (sess_local[s].ipv6cp.restart >= time_now)
+               {
+                       int next_state = session[s].ppp.ipv6cp;
+                       switch (session[s].ppp.ipv6cp)
+                       {
+                       case RequestSent:
+                       case AckReceived:
+                               next_state = RequestSent;
+
+                       case AckSent:
+                               if (sess_local[s].ipv6cp.conf_sent < config->ppp_max_configure)
+                               {
+                                       LOG(3, s, session[s].tunnel, "No ACK for IPV6CP ConfigReq... resending\n");
+                                       sess_local[s].ipv6cp.restart = time_now + config->ppp_restart_time;
+                                       sess_local[s].ipv6cp.conf_sent++;
+                                       sendipv6cp(t, s);
+                                       change_state(s, ipv6cp, next_state);
+                               }
+                               else
+                               {
+                                       LOG(3, s, session[s].tunnel, "No ACK for IPV6CP ConfigReq\n");
+                                       change_state(s, ipv6cp, Stopped);
+                               }
+
+                               s_actions++;
+                       }
+               }
+
+               if (sess_local[s].ccp.restart >= time_now)
+               {
+                       int next_state = session[s].ppp.ccp;
+                       switch (session[s].ppp.ccp)
+                       {
+                       case RequestSent:
+                       case AckReceived:
+                               next_state = RequestSent;
+
+                       case AckSent:
+                               if (sess_local[s].ccp.conf_sent < config->ppp_max_configure)
+                               {
+                                       LOG(3, s, session[s].tunnel, "No ACK for CCP ConfigReq... resending\n");
+                                       sess_local[s].ccp.restart = time_now + config->ppp_restart_time;
+                                       sess_local[s].ccp.conf_sent++;
+                                       sendccp(t, s);
+                                       change_state(s, ccp, next_state);
+                               }
+                               else
+                               {
+                                       LOG(3, s, session[s].tunnel, "No ACK for CCP ConfigReq\n");
+                                       change_state(s, ccp, Stopped);
+                               }
+
+                               s_actions++;
+                       }
                }
 
                // Drop sessions who have not responded within IDLE_TIMEOUT seconds
@@ -2753,7 +2847,7 @@ static void regular_cleanups(double period)
                }
 
                // No data in ECHO_TIMEOUT seconds, send LCP ECHO
-               if (session[s].user[0] && (time_now - session[s].last_packet >= ECHO_TIMEOUT))
+               if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= ECHO_TIMEOUT))
                {
                        uint8_t b[MAXCONTROL] = {0};
 
@@ -3084,7 +3178,8 @@ static void mainloop(void)
                if (n)
                {
                        struct sockaddr_in addr;
-                       int alen, c, s;
+                       socklen_t alen;
+                       int c, s;
                        int udp_ready = 0;
                        int tun_ready = 0;
                        int cluster_ready = 0;
@@ -3391,6 +3486,9 @@ static void initdata(int optdebug, char *optconfig)
        config->num_tbfs = MAXTBFS;
        config->rl_rate = 28; // 28kbps
        config->cluster_master_min_adv = 1;
+       config->ppp_restart_time = 3;
+       config->ppp_max_configure = 10;
+       config->ppp_max_failure = 5;
        strcpy(config->random_device, RANDOMDEVICE);
 
        log_stream = stderr;
@@ -3758,7 +3856,7 @@ static void initippool()
        LOG(1, 0, 0, "IP address pool is %d addresses\n", ip_pool_size - 1);
 }
 
-void snoop_send_packet(char *packet, uint16_t size, in_addr_t destination, uint16_t port)
+void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, uint16_t port)
 {
        struct sockaddr_in snoop_addr = {0};
        if (!destination || !port || snoopfd <= 0 || size <= 0 || !packet)
@@ -4055,7 +4153,7 @@ static void sigchild_handler(int sig)
            ;
 }
 
-static void build_chap_response(char *challenge, uint8_t id, uint16_t challenge_length, char **challenge_response)
+static void build_chap_response(uint8_t *challenge, uint8_t id, uint16_t challenge_length, uint8_t **challenge_response)
 {
        MD5_CTX ctx;
        *challenge_response = NULL;
@@ -4068,13 +4166,13 @@ static void build_chap_response(char *challenge, uint8_t id, uint16_t challenge_
 
        LOG(4, 0, 0, "   Building challenge response for CHAP request\n");
 
-       *challenge_response = (char *)calloc(17, 1);
+       *challenge_response = calloc(17, 1);
 
-       MD5Init(&ctx);
-       MD5Update(&ctx, &id, 1);
-       MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
-       MD5Update(&ctx, challenge, challenge_length);
-       MD5Final(*challenge_response, &ctx);
+       MD5_Init(&ctx);
+       MD5_Update(&ctx, &id, 1);
+       MD5_Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
+       MD5_Update(&ctx, challenge, challenge_length);
+       MD5_Final(*challenge_response, &ctx);
 
        return;
 }
@@ -4384,13 +4482,8 @@ int sessionsetup(tunnelidt t, sessionidt s)
                        cache_ipmap(session[s].ip, s);
        }
 
-       if (!session[s].unique_id)
-       {
-               // did this session just finish radius?
-               LOG(3, s, t, "Sending initial IPCP to client\n");
-               sendipcp(t, s);
-               session[s].unique_id = ++last_id;
-       }
+       sess_local[s].lcp_authtype = 0; // RADIUS authentication complete
+       lcp_open(t, s); // transition to Network phase and send initial IPCP
 
        // Run the plugin's against this new session.
        {
@@ -4499,7 +4592,7 @@ int load_session(sessionidt s, sessiont *new)
        }
 
        // check v6 routing
-       if (new->flags & SF_IPV6_ROUTED && !(session[s].flags & SF_IPV6_ROUTED))
+       if (new->ipv6prefixlen && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
                    route6set(s, new->ipv6route, new->ipv6prefixlen, 1);
 
        // check filters
@@ -4716,7 +4809,7 @@ static void plugins_done()
                run_plugin_done(p);
 }
 
-static void processcontrol(uint8_t * buf, int len, struct sockaddr_in *addr, int alen)
+static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int alen)
 {
        struct nsctl request;
        struct nsctl response;
@@ -5040,11 +5133,11 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec
        uint16_t m = htons(type);
 
        // Compute initial pad
-       MD5Init(&ctx);
-       MD5Update(&ctx, (unsigned char *) &m, 2);
-       MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
-       MD5Update(&ctx, vector, vec_len);
-       MD5Final(digest, &ctx);
+       MD5_Init(&ctx);
+       MD5_Update(&ctx, (unsigned char *) &m, 2);
+       MD5_Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
+       MD5_Update(&ctx, vector, vec_len);
+       MD5_Final(digest, &ctx);
 
        // pointer to last decoded 16 octets
        last = value;
@@ -5054,10 +5147,10 @@ static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vec
                // calculate a new pad based on the last decoded block
                if (d >= sizeof(digest))
                {
-                       MD5Init(&ctx);
-                       MD5Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
-                       MD5Update(&ctx, last, sizeof(digest));
-                       MD5Final(digest, &ctx);
+                       MD5_Init(&ctx);
+                       MD5_Update(&ctx, config->l2tpsecret, strlen(config->l2tpsecret));
+                       MD5_Update(&ctx, last, sizeof(digest));
+                       MD5_Final(digest, &ctx);
 
                        d = 0;
                        last = value;
index a8e2d9a..2bf86bf 100644 (file)
--- a/l2tpns.h
+++ b/l2tpns.h
@@ -1,5 +1,5 @@
 // L2TPNS Global Stuff
-// $Id: l2tpns.h,v 1.80 2005-06-28 14:48:27 bodea Exp $
+// $Id: l2tpns.h,v 1.81 2005-07-31 10:04:10 bodea Exp $
 
 #ifndef __L2TPNS_H__
 #define __L2TPNS_H__
 #define CONFIGFILE     FLASHDIR "/startup-config"      // Configuration file
 #define CLIUSERS       FLASHDIR "/users"               // CLI Users file
 #define IPPOOLFILE     FLASHDIR "/ip_pool"             // Address pool configuration
-#define ACCT_TIME      3000            // 5 minute accounting interval
-#define ACCT_SHUT_TIME 600             // 1 minute for counters of shutdown sessions
-#define        L2TPPORT        1701            // L2TP port
-#define RADPORT                1645            // old radius port...
-#define DAEPORT                3799            // DAE port
-#define        PKTARP          0x0806          // ARP packet type
-#define        PKTIP           0x0800          // IPv4 packet type
-#define        PKTIPV6         0x86DD          // IPv6 packet type
+#define ACCT_TIME      3000                            // 5 minute accounting interval
+#define ACCT_SHUT_TIME 600                             // 1 minute for counters of shutdown sessions
+#define        L2TPPORT        1701                            // L2TP port
+#define RADPORT                1645                            // old radius port...
+#define DAEPORT                3799                            // DAE port
+#define        PKTARP          0x0806                          // ARP packet type
+#define        PKTIP           0x0800                          // IPv4 packet type
+#define        PKTIPV6         0x86DD                          // IPv6 packet type
 #define        PPPPAP          0xC023
 #define        PPPCHAP         0xC223
 #define        PPPLCP          0xC021
@@ -121,6 +121,52 @@ enum {
        CoANAK
 };
 
+// PPP phases
+enum {
+       Dead,
+       Establish,
+       Authenticate,
+       Network,
+       Terminate
+};
+
+// PPP states
+enum {
+       Initial,
+       Starting,
+       Closed,
+       Stopped,
+       Closing,
+       Stopping,
+       RequestSent,
+       AckReceived,
+       AckSent,
+       Opened
+};
+
+// reset state machine counters
+#define initialise_restart_count(_s, _fsm)                     \
+       sess_local[_s]._fsm.conf_sent = sess_local[_s]._fsm.nak_sent
+
+// stop timer on change to state where timer does not run
+#define change_state(_s, _fsm, _new) ({                                \
+       if (_new != session[_s].ppp._fsm)                       \
+       {                                                       \
+               switch (_new)                                   \
+               {                                               \
+               case Initial:                                   \
+               case Starting:                                  \
+               case Closed:                                    \
+               case Stopped:                                   \
+               case Opened:                                    \
+                       sess_local[_s]._fsm.restart = 0;        \
+                       initialise_restart_count(_s, _fsm);     \
+               }                                               \
+               session[_s].ppp._fsm = _new;                    \
+               cluster_send_session(_s);                       \
+       }                                                       \
+})
+
 // Types
 typedef uint16_t sessionidt;
 typedef uint16_t tunnelidt;
@@ -174,7 +220,14 @@ typedef struct
        sessionidt far;                 // far end session ID
        tunnelidt tunnel;               // near end tunnel ID
        uint8_t l2tp_flags;             // various bit flags from the ICCN on the l2tp tunnel.
-       uint8_t flags;                  // Various session flags.
+       struct {
+               uint8_t phase;          // PPP phase
+               uint8_t lcp:4;          //   LCP    state
+               uint8_t ipcp:4;         //   IPCP   state
+               uint8_t ipv6cp:4;       //   IPV6CP state
+               uint8_t ccp:4;          //   CCP    state
+               uint8_t pad;            // unused
+       } ppp;
        in_addr_t ip;                   // IP of session set by RADIUS response (host byte order).
        int ip_pool_index;              // index to IP pool
        uint32_t unique_id;             // unique session id
@@ -198,7 +251,7 @@ typedef struct
        uint16_t tbf_in;                // filter bucket for throttling in from the user.
        uint16_t tbf_out;               // filter bucket for throttling out to the user.
        int random_vector_length;
-       char random_vector[MAXTEL];
+       uint8_t random_vector[MAXTEL];
        char user[MAXUSER];             // user (needed in seesion for radius stop messages)
        char called[MAXTEL];            // called number
        char calling[MAXTEL];           // calling number
@@ -209,17 +262,10 @@ typedef struct
        uint8_t walled_garden;          // is this session gardened?
        uint8_t ipv6prefixlen;          // IPv6 route prefix length
        struct in6_addr ipv6route;      // Static IPv6 route
-       char reserved[16];              // Space to expand structure without changing HB_VERSION
+       char reserved[11];              // Space to expand structure without changing HB_VERSION
 }
 sessiont;
 
-#define SF_IPCP_ACKED  1       // Has this session seen an IPCP Ack?
-#define SF_LCP_ACKED   2       // LCP negotiated
-#define SF_CCP_ACKED   4       // CCP negotiated
-#define SF_IPV6CP_ACKED        8       // IPv6 negotiated
-#define SF_IPV6_NACKED 16      // IPv6 rejected
-#define SF_IPV6_ROUTED 32      // advertised v6 route
-
 #define AUTHPAP                1       // allow PAP
 #define AUTHCHAP       2       // allow CHAP
 
@@ -233,6 +279,16 @@ typedef struct
        uint32_t cin;
        uint32_t cout;
 
+       // PPP restart timer/counters
+       struct {
+               time_t restart;
+               int conf_sent;
+               int nak_sent;
+       } lcp, ipcp, ipv6cp, ccp;
+
+       // authentication to use
+       int lcp_authtype;
+
        // DoS prevention
        clockt last_packet_out;
        uint32_t packets_out;
@@ -271,13 +327,12 @@ typedef struct
 }
 tunnelt;
 
-// 180 bytes per radius session
+// 160 bytes per radius session
 typedef struct                 // outstanding RADIUS requests
 {
        sessionidt session;     // which session this applies to
        hasht auth;             // request authenticator
        clockt retry;           // when to try next
-       char calling[MAXTEL];   // calling number
        char pass[129];         // password
        uint8_t id;             // ID for PPP response
        uint8_t try;            // which try we are on
@@ -328,7 +383,6 @@ enum
        RADIUSNULL,             // Not in use
        RADIUSCHAP,             // sending CHAP down PPP
        RADIUSAUTH,             // sending auth to RADIUS server
-       RADIUSIPCP,             // sending IPCP to end user
        RADIUSSTART,            // sending start accounting to RADIUS server
        RADIUSSTOP,             // sending stop accounting to RADIUS server
        RADIUSINTERIM,          // sending interim accounting to RADIUS server
@@ -391,6 +445,7 @@ struct Tstats
     uint32_t   call_sessionbyuser;
     uint32_t   call_sendarp;
     uint32_t   call_sendipcp;
+    uint32_t   call_sendipv6cp;
     uint32_t   call_processipv6cp;
     uint32_t   call_tunnelsend;
     uint32_t   call_sessionkill;
@@ -457,6 +512,10 @@ typedef struct
 
        char            random_device[256];             // random device path, defaults to RANDOMDEVICE
 
+       int             ppp_restart_time;               // timeout for PPP restart
+       int             ppp_max_configure;              // max lcp configure requests to send
+       int             ppp_max_failure;                // max lcp configure naks to send
+
        char            radiussecret[64];
        int             radius_accounting;
        int             radius_interim;
@@ -601,6 +660,7 @@ void sendarp(int ifr_idx, const unsigned char* mac, in_addr_t ip);
 // ppp.c
 void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
 void processchap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
+void lcp_open(tunnelidt t, sessionidt s);
 void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
 void processipcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
 void processipv6cp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l);
@@ -611,6 +671,7 @@ void sendchap(tunnelidt t, sessionidt s);
 uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, tunnelidt t, sessionidt s, uint16_t mtype);
 void sendlcp(tunnelidt t, sessionidt s, int authtype);
 void send_ipin(sessionidt s, uint8_t *buf, int len);
+void sendccp(tunnelidt t, sessionidt s);
 
 
 // radius.c
@@ -638,8 +699,9 @@ void filter_session(sessionidt s, int filter_in, int filter_out);
 void send_garp(in_addr_t ip);
 void tunnelsend(uint8_t *buf, uint16_t l, tunnelidt t);
 void sendipcp(tunnelidt t, sessionidt s);
+void sendipv6cp(tunnelidt t, sessionidt s);
 void processudp(uint8_t *buf, int len, struct sockaddr_in *addr);
-void snoop_send_packet(char *packet, uint16_t size, in_addr_t destination, uint16_t port);
+void snoop_send_packet(uint8_t *packet, uint16_t size, in_addr_t destination, uint16_t port);
 int find_filter(char const *name, size_t len);
 int ip_filter(uint8_t *buf, int len, uint8_t filter);
 int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc);
@@ -652,7 +714,7 @@ int cmd_show_hist_open(struct cli_def *cli, char *command, char **argv, int argc
 #define LOG_HEX(D, t, d, s)    ({ if (D <= config->debug) _log_hex(D, t, d, s); })
 
 void _log(int level, sessionidt s, tunnelidt t, const char *format, ...) __attribute__((format (printf, 4, 5)));
-void _log_hex(int level, const char *title, const char *data, int maxsize);
+void _log_hex(int level, const char *title, const uint8_t *data, int maxsize);
 
 int sessionsetup(tunnelidt t, sessionidt s);
 int run_plugins(int plugin_type, void *data);
@@ -670,7 +732,7 @@ int cli_arg_help(struct cli_def *cli, int cr_ok, char *entry, ...);
 
 
 // icmp.c
-void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, char *packet, int packet_len);
+void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, uint8_t *packet, int packet_len);
 
 
 extern tunnelt *tunnel;
index 6b760a1..c3d63ca 100644 (file)
@@ -8,8 +8,8 @@ Source: http://optusnet.dl.sourceforge.net/sourceforge/l2tpns/l2tpns-%{version}.
 URL: http://sourceforge.net/projects/l2tpns
 BuildRoot: %{_tmppath}/%{name}-%{version}-root
 Prereq: /sbin/chkconfig
-BuildRequires: libcli >= 1.8.5
-Requires: libcli >= 1.8.5
+BuildRequires: libcli >= 1.8.5, openssl-devel
+Requires: libcli >= 1.8.5, openssl
 
 %description
 l2tpns is a layer 2 tunneling protocol network server (LNS).  It
@@ -43,5 +43,5 @@ rm -rf %{buildroot}
 %attr(644,root,root) /usr/share/man/man[58]/*
 
 %changelog
-* Wed Jun 29 2005 Brendan O'Dea <bod@c47.org> 2.1.2-1
+* Sun Jul 31 2005 Brendan O'Dea <bod@> 2.1.2-1
 - 2.1.2 release, see /usr/share/doc/l2tpns-2.1.2/Changes
diff --git a/md5.c b/md5.c
deleted file mode 100644 (file)
index 59c87be..0000000
--- a/md5.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
- */
-
-char const *cvs_id_md5 = "$Id: md5.c,v 1.3 2004-08-13 00:02:50 fred_nerk Exp $";
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
- */
-
-#include <string.h>
-#include "md5.h"
-
-/* Constants for MD5Transform routine.
- */
-
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-
-static void MD5Transform PROTO_LIST((UINT4[4], unsigned char[64]));
-static void Encode PROTO_LIST((unsigned char *, UINT4 *, unsigned int));
-static void Decode PROTO_LIST((UINT4 *, unsigned char *, unsigned int));
-
-static unsigned char PADDING[64] = {
-       0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G, H and I are basic MD5 functions.
- */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE_LEFT rotates x left n bits.
- */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-Rotation is separate from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
-  }
-
-/* MD5 initialization. Begins an MD5 operation, writing a new context.
- */
-void MD5Init(MD5_CTX *context)
-{
-       context->count[0] = context->count[1] = 0;
-       // Load magic initialization constants.
-       context->state[0] = 0x67452301;
-       context->state[1] = 0xefcdab89;
-       context->state[2] = 0x98badcfe;
-       context->state[3] = 0x10325476;
-}
-
-/* MD5 block update operation. Continues an MD5 message-digest
-  operation, processing another message block, and updating the
-  context.
- */
-void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputLen)
-
-{
-       unsigned int i,
-       index,
-       partLen;
-
-       /* Compute number of bytes mod 64 */
-       index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
-
-       /* Update number of bits */
-       if ((context->count[0] += ((UINT4) inputLen << 3)) < ((UINT4) inputLen << 3))
-               context->count[1]++;
-       context->count[1] += ((UINT4) inputLen >> 29);
-
-       partLen = 64 - index;
-
-       /* Transform as many times as possible.
-        */
-       if (inputLen >= partLen)
-       {
-               memcpy(&context->buffer[index], input, partLen);
-               MD5Transform(context->state, context->buffer);
-
-               for (i = partLen; i + 63 < inputLen; i += 64)
-                       MD5Transform(context->state, &input[i]);
-
-               index = 0;
-       }
-       else
-               i = 0;
-
-       /* Buffer remaining input */
-       memcpy(&context->buffer[index], &input[i], inputLen - i);
-}
-
-/* MD5 finalization. Ends an MD5 message-digest operation, writing the
-  the message digest and zeroizing the context.
- */
-void MD5Final(unsigned char digest[16], MD5_CTX *context)
-{
-       unsigned char bits[8];
-       unsigned int index, padLen;
-
-       /* Save number of bits */
-       Encode(bits, context->count, 8);
-
-       /* Pad out to 56 mod 64.
-        */
-       index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
-       padLen = (index < 56) ? (56 - index) : (120 - index);
-       MD5Update(context, PADDING, padLen);
-
-       /* Append length (before padding) */
-       MD5Update(context, bits, 8);
-
-       /* Store state in digest */
-       Encode(digest, context->state, 16);
-
-       /* Zeroize sensitive information.
-        */
-       memset(context, 0, sizeof(*context));
-}
-
-/* MD5 basic transformation. Transforms state based on block.
- */
-static void MD5Transform(UINT4 state[4], unsigned char block[64])
-{
-       UINT4 a = state[0],
-                 b = state[1],
-                     c = state[2],
-                         d = state[3],
-                             x[16];
-
-       Decode(x, block, 64);
-
-       /* Round 1 */
-       FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
-       FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
-       FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
-       FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
-       FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
-       FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
-       FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
-       FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
-       FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
-       FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
-       FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
-       FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
-       FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
-       FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
-       FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
-       FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
-       /* Round 2 */
-       GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
-       GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
-       GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
-       GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
-       GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
-       GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
-       GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
-       GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
-       GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
-       GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
-       GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
-
-       GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
-       GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
-       GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
-       GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
-       GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
-       /* Round 3 */
-       HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
-       HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
-       HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
-       HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
-       HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
-       HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
-       HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
-       HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
-       HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
-       HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
-       HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
-       HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
-       HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
-       HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
-       HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
-       HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
-
-       /* Round 4 */
-       II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
-       II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
-       II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
-       II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
-       II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
-       II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
-       II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
-       II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
-       II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
-       II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
-       II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
-       II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
-       II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
-       II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
-       II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
-       II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
-
-       state[0] += a;
-       state[1] += b;
-       state[2] += c;
-       state[3] += d;
-
-       // Zeroize sensitive information.
-       memset(x, 0, sizeof(x));
-}
-
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is
-  a multiple of 4.
- */
-static void Encode(unsigned char *output, UINT4 *input, unsigned int len)
-{
-       unsigned int i, j;
-
-       for (i = 0, j = 0; j < len; i++, j += 4)
-       {
-               output[j] = (unsigned char) (input[i] & 0xff);
-               output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
-               output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
-               output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
-       }
-}
-
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is
-  a multiple of 4.
- */
-static void Decode(UINT4 *output, unsigned char *input, unsigned int len)
-{
-       unsigned int i, j;
-
-       for (i = 0, j = 0; j < len; i++, j += 4)
-               output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) | (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
-}
-
diff --git a/md5.h b/md5.h
deleted file mode 100644 (file)
index 5685fdb..0000000
--- a/md5.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* RSAREF types and constants
- */
-
-#ifndef __MD5_H__
-#define __MD5_H__
-
-/* PROTOTYPES should be set to one if and only if the compiler supports
-  function argument prototyping.
-The following makes PROTOTYPES default to 0 if it has not already
-
-  been defined with C compiler flags.
- */
-#ifndef PROTOTYPES
-#define PROTOTYPES 0
-#endif
-
-/* POINTER defines a generic pointer type */
-typedef unsigned char *POINTER;
-
-/* UINT2 defines a two byte word */
-typedef unsigned short int UINT2;
-
-/* UINT4 defines a four byte word */
-typedef unsigned long int UINT4;
-
-/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
-If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
-  returns an empty list.
- */
-#if PROTOTYPES
-#define PROTO_LIST(list) list
-#else
-#define PROTO_LIST(list) ()
-#endif
-
-
-/* MD5.H - header file for MD5C.C
- */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
- */
-
-/* MD5 context. */
-typedef struct {
-  UINT4 state[4];                                   /* state (ABCD) */
-  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
-  unsigned char buffer[64];                         /* input buffer */
-} MD5_CTX;
-
-void MD5Init PROTO_LIST ((MD5_CTX *));
-void MD5Update PROTO_LIST
-  ((MD5_CTX *, unsigned char *, unsigned int));
-void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
-
-#endif /* __MD5_H__ */
diff --git a/nsctl.c b/nsctl.c
index 057edfa..59ad0c6 100644 (file)
--- a/nsctl.c
+++ b/nsctl.c
@@ -141,7 +141,7 @@ static struct nsctl *request(char *host, int port, int type, int argc, char *arg
     socklen_t len = sizeof(peer);
     struct hostent *h = gethostbyname(host);
     int fd;
-    char buf[NSCTL_MAX_PKT_SZ];
+    uint8_t buf[NSCTL_MAX_PKT_SZ];
     int sz;
     char *err;
 
index 6619ad3..faf3a5e 100644 (file)
--- a/plugin.h
+++ b/plugin.h
@@ -28,7 +28,7 @@ enum
 struct pluginfuncs
 {
        void (*log)(int level, sessionidt s, tunnelidt t, const char *format, ...);
-       void (*log_hex)(int level, const char *title, const char *data, int maxsize);
+       void (*log_hex)(int level, const char *title, const uint8_t *data, int maxsize);
        char *(*fmtaddr)(in_addr_t addr, int n);
        sessionidt (*get_session_by_username)(char *username);
        sessiont *(*get_session_by_id)(sessionidt s);
diff --git a/ppp.c b/ppp.c
index 0d3b168..a604755 100644 (file)
--- a/ppp.c
+++ b/ppp.c
@@ -1,6 +1,6 @@
 // L2TPNS PPP Stuff
 
-char const *cvs_id_ppp = "$Id: ppp.c,v 1.64 2005-06-24 08:34:53 bodea Exp $";
+char const *cvs_id_ppp = "$Id: ppp.c,v 1.65 2005-07-31 10:04:10 bodea Exp $";
 
 #include <stdio.h>
 #include <string.h>
@@ -23,8 +23,7 @@ extern uint32_t eth_tx;
 extern time_t time_now;
 extern configt *config;
 
-static void initccp(tunnelidt t, sessionidt s);
-static uint8_t *add_lcp_auth(uint8_t *b, int size, int authtype);
+static int add_lcp_auth(uint8_t *b, int size, int authtype);
 
 // Process PAP messages
 void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
@@ -32,6 +31,7 @@ void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
        char user[MAXUSER];
        char pass[MAXPASS];
        uint16_t hl;
+       uint16_t r;
 
        CSTAT(processpap);
 
@@ -61,6 +61,12 @@ void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                return;
        }
 
+       if (session[s].ppp.phase != Authenticate)
+       {
+               LOG(2, s, t, "PAP ignored in %s phase\n", ppp_phase(session[s].ppp.phase));
+               return;
+       }
+
        {
                uint8_t *b = p;
                b += 4;
@@ -78,7 +84,9 @@ void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                }
                LOG(3, s, t, "PAP login %s/%s\n", user, pass);
        }
-       if (session[s].ip || !sess_local[s].radius)
+
+       r = radiusnew(s);
+       if (session[s].ip || !r)
        {
                // respond now, either no RADIUS available or already authenticated
                uint8_t b[MAXCONTROL];
@@ -93,26 +101,21 @@ void processpap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                p[1] = id;
                *(uint16_t *) (p + 2) = htons(5);       // length
                p[4] = 0;                               // no message
+               tunnelsend(b, 5 + (p - b), t);          // send it
+
                if (session[s].ip)
                {
                        LOG(3, s, t, "Already an IP allocated: %s (%d)\n",
                                fmtaddr(htonl(session[s].ip), 0), session[s].ip_pool_index);
-
-                       session[s].flags &= ~SF_IPCP_ACKED;
                }
                else
                {
-                       LOG(1, s, t, "No radius session available to authenticate session...\n");
+                       LOG(1, s, t, "No RADIUS session available to authenticate session...\n");
+                       sessionshutdown(s, "No free RADIUS sessions.", 4, 0);
                }
-               LOG(3, s, t, "Fallback response to PAP (%s)\n", (session[s].ip) ? "ACK" : "NAK");
-               tunnelsend(b, 5 + (p - b), t); // send it
-               sessionshutdown(s, "PAP authentication failed.", 3, 0);
        }
        else
        {
-               // set up RADIUS request
-               uint16_t r = sess_local[s].radius;
-
                // Run PRE_AUTH plugins
                struct param_pre_auth packet = { &tunnel[t], &session[s], strdup(user), strdup(pass), PPPPAP, 1 };
                run_plugins(PLUGIN_PRE_AUTH, &packet);
@@ -177,6 +180,13 @@ void processchap(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                sessionshutdown(s, "CHAP length mismatch.", 3, 0);
                return;
        }
+
+       if (session[s].ppp.phase != Authenticate)
+       {
+               LOG(2, s, t, "CHAP ignored in %s phase\n", ppp_phase(session[s].ppp.phase));
+               return;
+       }
+
        if (p[1] != radius[r].id)
        {
                LOG(1, s, t, "Wrong CHAP response ID %d (should be %d) (%d)\n", p[1], radius[r].id, r);
@@ -243,7 +253,7 @@ static void dumplcp(uint8_t *p, int l)
        uint8_t *o = (p + 4);
 
        LOG_HEX(5, "PPP LCP Packet", p, l);
-       LOG(4, 0, 0, "PPP LCP Packet type %d (%s len %d)\n", *p, ppp_lcp_type((int)*p), ntohs( ((uint16_t *) p)[1]) );
+       LOG(4, 0, 0, "PPP LCP Packet type %d (%s len %d)\n", *p, ppp_code((int)*p), ntohs( ((uint16_t *) p)[1]) );
        LOG(4, 0, 0, "Length: %d\n", l);
        if (*p != ConfigReq && *p != ConfigRej && *p != ConfigAck)
                return;
@@ -268,54 +278,54 @@ static void dumplcp(uint8_t *p, int l)
                {
                        case 1: // Maximum-Receive-Unit
                                if (length == 4)
-                                       LOG(4, 0, 0, "    %s %d\n", lcp_type(type), ntohs(*(uint16_t *)(o + 2)));
+                                       LOG(4, 0, 0, "    %s %d\n", ppp_lcp_option(type), ntohs(*(uint16_t *)(o + 2)));
                                else
-                                       LOG(4, 0, 0, "    %s odd length %d\n", lcp_type(type), length);
+                                       LOG(4, 0, 0, "    %s odd length %d\n", ppp_lcp_option(type), length);
                                break;
                        case 2: // Async-Control-Character-Map
                                if (length == 6)
                                {
                                        uint32_t asyncmap = ntohl(*(uint32_t *)(o + 2));
-                                       LOG(4, 0, 0, "    %s %x\n", lcp_type(type), asyncmap);
+                                       LOG(4, 0, 0, "    %s %x\n", ppp_lcp_option(type), asyncmap);
                                }
                                else
-                                       LOG(4, 0, 0, "   %s odd length %d\n", lcp_type(type), length);
+                                       LOG(4, 0, 0, "   %s odd length %d\n", ppp_lcp_option(type), length);
                                break;
                        case 3: // Authentication-Protocol
                                if (length == 4)
                                {
                                        int proto = ntohs(*(uint16_t *)(o + 2));
-                                       LOG(4, 0, 0, "   %s 0x%x (%s)\n", lcp_type(type), proto,
+                                       LOG(4, 0, 0, "   %s 0x%x (%s)\n", ppp_lcp_option(type), proto,
                                                proto == PPPPAP  ? "PAP"  : "UNSUPPORTED");
                                }
                                else if (length == 5)
                                {
                                        int proto = ntohs(*(uint16_t *)(o + 2));
                                        int algo = *(uint8_t *)(o + 4);
-                                       LOG(4, 0, 0, "   %s 0x%x 0x%x (%s)\n", lcp_type(type), proto, algo,
+                                       LOG(4, 0, 0, "   %s 0x%x 0x%x (%s)\n", ppp_lcp_option(type), proto, algo,
                                                (proto == PPPCHAP && algo == 5) ? "CHAP MD5"  : "UNSUPPORTED");
                                }
                                else
-                                       LOG(4, 0, 0, "   %s odd length %d\n", lcp_type(type), length);
+                                       LOG(4, 0, 0, "   %s odd length %d\n", ppp_lcp_option(type), length);
                                break;
                        case 4: // Quality-Protocol
                                {
                                        uint32_t qp = ntohl(*(uint32_t *)(o + 2));
-                                       LOG(4, 0, 0, "    %s %x\n", lcp_type(type), qp);
+                                       LOG(4, 0, 0, "    %s %x\n", ppp_lcp_option(type), qp);
                                }
                                break;
                        case 5: // Magic-Number
                                if (length == 6)
                                {
                                        uint32_t magicno = ntohl(*(uint32_t *)(o + 2));
-                                       LOG(4, 0, 0, "    %s %x\n", lcp_type(type), magicno);
+                                       LOG(4, 0, 0, "    %s %x\n", ppp_lcp_option(type), magicno);
                                }
                                else
-                                       LOG(4, 0, 0, "   %s odd length %d\n", lcp_type(type), length);
+                                       LOG(4, 0, 0, "   %s odd length %d\n", ppp_lcp_option(type), length);
                                break;
                        case 7: // Protocol-Field-Compression
                        case 8: // Address-And-Control-Field-Compression
-                               LOG(4, 0, 0, "    %s\n", lcp_type(type));
+                               LOG(4, 0, 0, "    %s\n", ppp_lcp_option(type));
                                break;
                        default:
                                LOG(2, 0, 0, "    Unknown PPP LCP Option type %d\n", type);
@@ -326,6 +336,113 @@ static void dumplcp(uint8_t *p, int l)
        }
 }
 
+void lcp_open(tunnelidt t, sessionidt s)
+{
+       // transition to Authentication or Network phase: 
+       session[s].ppp.phase = sess_local[s].lcp_authtype ? Authenticate : Network;
+
+       // LCP now Opened
+       change_state(s, lcp, Opened);
+
+       if (session[s].ppp.phase == Authenticate)
+       {
+               if (sess_local[s].lcp_authtype == AUTHCHAP)
+                       sendchap(t, s);
+       }
+       else
+       {
+               // This-Layer-Up
+               sendipcp(t, s);
+               change_state(s, ipcp, RequestSent);
+               // move to passive state for IPv6 (if configured), CCP
+               if (config->ipv6_prefix.s6_addr[0])
+                       change_state(s, ipv6cp, Stopped);
+               else
+                       change_state(s, ipv6cp, Closed);
+
+               change_state(s, ccp, Stopped);
+       }
+}
+
+static void lcp_restart(sessionidt s)
+{
+       session[s].ppp.phase = Establish;
+       // This-Layer-Down
+       change_state(s, ipcp, Dead);
+       change_state(s, ipv6cp, Dead);
+       change_state(s, ccp, Dead);
+}
+
+static uint8_t *ppp_rej(sessionidt s, uint8_t *buf, size_t blen, uint16_t mtype,
+       uint8_t **response, uint8_t *queued, uint8_t *packet, uint8_t *option)
+{
+       if (!*response || **response != ConfigRej)
+       {
+               queued = *response = makeppp(buf, blen, packet, 2, session[s].tunnel, s, mtype);
+               if (!queued)
+                       return 0;
+
+               *queued = ConfigRej;
+               queued += 4;
+       }
+
+       if ((queued - buf + option[1]) > blen)
+       {
+               LOG(2, s, session[s].tunnel, "PPP overflow for ConfigRej (proto %u, option %u).\n", mtype, *option);
+               return 0;
+       }
+
+       memcpy(queued, option, option[1]);
+       return queued + option[1];
+}
+
+static uint8_t *ppp_nak(sessionidt s, uint8_t *buf, size_t blen, uint16_t mtype,
+       uint8_t **response, uint8_t *queued, uint8_t *packet, uint8_t *option,
+       uint8_t *value, size_t vlen)
+{
+       int *nak_sent;
+       switch (mtype)
+       {
+       case PPPLCP:    nak_sent = &sess_local[s].lcp.nak_sent;    break;
+       case PPPIPCP:   nak_sent = &sess_local[s].ipcp.nak_sent;   break;
+       case PPPIPV6CP: nak_sent = &sess_local[s].ipv6cp.nak_sent; break;
+       default:        return 0; // ?
+       }
+
+       if (*response && **response != ConfigNak)
+       {
+               if (*nak_sent < config->ppp_max_failure) // reject queued
+                       return queued;
+
+               return ppp_rej(s, buf, blen, mtype, response, 0, packet, option);
+       }
+
+       if (!*response)
+       {
+               if (*nak_sent >= config->ppp_max_failure)
+                       return ppp_rej(s, buf, blen, mtype, response, 0, packet, option);
+
+               queued = *response = makeppp(buf, blen, packet, 2, session[s].tunnel, s, mtype);
+               if (!queued)
+                       return 0;
+
+               *nak_sent++;
+               *queued = ConfigNak;
+               queued += 4;
+       }
+
+       if ((queued - buf + vlen + 2) > blen)
+       {
+               LOG(2, s, session[s].tunnel, "PPP overflow for ConfigNak (proto %u, option %u).\n", mtype, *option);
+               return 0;
+       }
+
+       *queued++ = *option;
+       *queued++ = vlen + 2;
+       memcpy(queued, value, vlen);
+       return queued + vlen;
+}
+
 // Process LCP messages
 void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
 {
@@ -352,10 +469,14 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
        }
        l = hl;
 
+       if (session[s].die) // going down...
+               return;
+
        if (*p == ConfigAck)
        {
                int x = l - 4;
                uint8_t *o = (p + 4);
+               int authtype = 0;
 
                LOG(3, s, t, "LCP: ConfigAck (%d bytes)...\n", l);
                if (config->debug > 3) dumplcp(p, l);
@@ -371,8 +492,10 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                                case 3: // Authentication-Protocol
                                        {
                                                int proto = ntohs(*(uint16_t *)(o + 2));
-                                               if (proto == PPPCHAP && *(o + 4) == 5)
-                                                       sendchap(t, s);
+                                               if (proto == PPPPAP)
+                                                       authtype = AUTHPAP;
+                                               else if (proto == PPPCHAP && *(o + 4) == 5)
+                                                       authtype = AUTHCHAP;
                                        }
 
                                        break;
@@ -381,13 +504,41 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                        o += length;
                }
 
-               session[s].flags |= SF_LCP_ACKED;
+               if (!session[s].ip && authtype)
+                       sess_local[s].lcp_authtype = authtype;
+
+               switch (session[s].ppp.lcp)
+               {
+               case RequestSent:
+                       initialise_restart_count(s, lcp);
+                       change_state(s, lcp, AckReceived);
+                       break;
+
+               case AckReceived:
+               case Opened:
+                       LOG(3, s, t, "LCP: ConfigAck in state %s?  Sending ConfigReq\n", ppp_state(session[s].ppp.lcp));
+                       if (session[s].ppp.lcp == Opened)
+                               lcp_restart(s);
+
+                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       change_state(s, lcp, RequestSent);
+                       break;
+
+               case AckSent:
+                       lcp_open(t, s);
+                       break;
+
+               default:
+                       LOG(3, s, t, "LCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.lcp));
+               }
        }
        else if (*p == ConfigReq)
        {
                int x = l - 4;
                uint8_t *o = (p + 4);
                uint8_t *response = 0;
+               static uint8_t asyncmap[4] = { 0, 0, 0, 0 }; // all zero
+               static uint8_t authproto[5];
 
                LOG(3, s, t, "LCP: ConfigReq (%d bytes)...\n", l);
                if (config->debug > 3) dumplcp(p, l);
@@ -408,40 +559,23 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                                        if (!ntohl(*(uint32_t *)(o + 2))) // all bits zero is OK
                                                break;
 
-                                       if (response && *response != ConfigNak) // rej already queued
-                                               break;
-
                                        LOG(2, s, t, "    Remote requesting asyncmap.  Rejecting.\n");
-                                       if (!response)
-                                       {
-                                               q = response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
-                                               if (!q) break;
-                                               *q = ConfigNak;
-                                               q += 4;
-                                       }
-
-                                       if ((q - b + 11) > sizeof(b))
-                                       {
-                                               LOG(2, s, t, "LCP overflow for asyncmap ConfigNak.\n");
-                                               break;
-                                       }
-
-                                       *q++ = type;
-                                       *q++ = 6;
-                                       memset(q, 0, 4); // asyncmap 0
-                                       q += 4;
+                                       q = ppp_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, asyncmap, sizeof(asyncmap));
                                        break;
 
                                case 3: // Authentication-Protocol
                                        {
                                                int proto = ntohs(*(uint16_t *)(o + 2));
                                                char proto_name[] = "0x0000";
-                                               uint8_t *a;
+                                               int alen;
 
                                                if (proto == PPPPAP)
                                                {
                                                        if (config->radius_authtypes & AUTHPAP)
+                                                       {
+                                                               sess_local[s].lcp_authtype = AUTHPAP;
                                                                break;
+                                                       }
 
                                                        strcpy(proto_name, "PAP");
                                                }
@@ -449,45 +583,29 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                                                {
                                                        if (config->radius_authtypes & AUTHCHAP
                                                            && *(o + 4) == 5) // MD5
+                                                       {
+                                                               sess_local[s].lcp_authtype = AUTHCHAP;
                                                                break;
+                                                       }
 
                                                        strcpy(proto_name, "CHAP");
                                                }
                                                else
                                                        sprintf(proto_name, "%#4.4x", proto);
 
-                                               if (response && *response != ConfigNak) // rej already queued
-                                                       break;
-
                                                LOG(2, s, t, "    Remote requesting %s authentication.  Rejecting.\n", proto_name);
 
-                                               if (!response)
-                                               {
-                                                       q = response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
-                                                       if (!q) break;
-                                                       *q = ConfigNak;
-                                                       q += 4;
-                                               }
-
-                                               a = add_lcp_auth(q, sizeof(b) - (q - b), config->radius_authprefer);
-                                               if (!a)
-                                               {
-                                                       LOG(2, s, t, "LCP overflow for %s ConfigNak.\n", proto_name);
-                                                       break;
-                                               }
-
-                                               q = a;
+                                               alen = add_lcp_auth(authproto, sizeof(authproto), config->radius_authprefer);
+                                               if (alen < 2) break; // paranoia
 
-                                               if (config->radius_authtypes != config->radius_authprefer)
+                                               q = ppp_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, authproto + 2, alen - 2);
+                                               if (q && *response == ConfigNak &&
+                                                       config->radius_authtypes != config->radius_authprefer)
                                                {
-                                                       a = add_lcp_auth(q, sizeof(b) - (q - b), config->radius_authtypes & ~config->radius_authprefer);
-                                                       if (!a)
-                                                       {
-                                                               LOG(2, s, t, "LCP overflow for %s ConfigNak.\n", proto_name);
-                                                               break;
-                                                       }
-
-                                                       q = a;
+                                                       // alternate type
+                                                       alen = add_lcp_auth(authproto, sizeof(authproto), config->radius_authtypes & ~config->radius_authprefer);
+                                                       if (alen < 2) break;
+                                                       q = ppp_nak(s, b, sizeof(b), PPPLCP, &response, q, p, o, authproto + 2, alen - 2);
                                                }
 
                                                break;
@@ -505,22 +623,7 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
 
                                default: // Reject any unknown options
                                        LOG(2, s, t, "    Rejecting PPP LCP Option type %d\n", type);
-                                       if (!response || *response != ConfigRej) // drop nak in favour of rej
-                                       {
-                                               q = response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
-                                               if (!q) break;
-                                               *q = ConfigRej;
-                                               q += 4;
-                                       }
-
-                                       if ((q - b + length) > sizeof(b))
-                                       {
-                                               LOG(2, s, t, "LCP overflow for ConfigRej (type=%d).\n", type);
-                                               break;
-                                       }
-
-                                       memcpy(q, o, length);
-                                       q += length;
+                                       q = ppp_rej(s, b, sizeof(b), PPPLCP, &response, q, p, o);
                        }
                        x -= length;
                        o += length;
@@ -539,11 +642,57 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                        *response = ConfigAck;
                }
 
-               LOG(3, s, t, "Sending %s\n", ppp_lcp_type(*response));
-               tunnelsend(b, l + response - b, t);
+               switch (session[s].ppp.lcp)
+               {
+               case Closed:
+                       response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
+                       if (!response) return;
+                       *response = TerminateAck;
+                       *((uint16_t *) (response + 2)) = htons(l = 4);
+                       break;
+
+               case Stopped:
+                       initialise_restart_count(s, lcp);
+                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       if (*response == ConfigAck)
+                               change_state(s, lcp, AckSent);
+                       else
+                               change_state(s, lcp, RequestSent);
+
+                       break;
+
+               case RequestSent:
+                       if (*response == ConfigAck)
+                               change_state(s, lcp, AckSent);
+
+                       break;
+
+               case AckReceived:
+                       if (*response == ConfigAck)
+                               lcp_open(t, s);
+
+                       break;
+
+               case Opened:
+                       lcp_restart(s);
+                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       /* fallthrough */
+
+               case AckSent:
+                       if (*response == ConfigAck)
+                               change_state(s, lcp, AckSent);
+                       else
+                               change_state(s, lcp, RequestSent);
 
-               if (!(session[s].flags & SF_LCP_ACKED))
-                       sendlcp(t, s, config->radius_authprefer);
+                       break;
+
+               default:
+                       LOG(3, s, t, "LCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.lcp));
+                       return;
+               }
+
+               LOG(3, s, t, "LCP: Sending %s\n", ppp_code(*response));
+               tunnelsend(b, l + (response - b), t);
        }
        else if (*p == ConfigNak)
        {
@@ -608,10 +757,42 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                        return;
                }
 
-               if (authtype == -1)
-                       authtype = config->radius_authprefer;
+               if (authtype > 0)
+                       sess_local[s].lcp_authtype = authtype;
+
+               switch (session[s].ppp.lcp)
+               {
+               case Closed:
+               case Stopped:
+                       {
+                               uint8_t *response = makeppp(b, sizeof(b), p, 2, t, s, PPPLCP);
+                               if (!response) return;
+                               *response = TerminateAck;
+                               *((uint16_t *) (response + 2)) = htons(l = 4);
+                               tunnelsend(b, l + (response - b), t);
+                       }
+                       break;
+
+               case RequestSent:
+               case AckSent:
+                       initialise_restart_count(s, lcp);
+                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       break;
+
+               case AckReceived:
+                       LOG(3, s, t, "LCP: ConfigNak in state %s?  Sending ConfigReq\n", ppp_state(session[s].ppp.lcp));
+                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       break;
+
+               case Opened:
+                       lcp_restart(s);
+                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       break;
 
-               sendlcp(t, s, authtype);
+               default:
+                       LOG(3, s, t, "LCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.lcp));
+                       return;
+               }
        }
        else if (*p == TerminateReq)
        {
@@ -631,7 +812,7 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                if (*(uint16_t *) (p+4) == htons(PPPIPV6CP))
                {
                        LOG(3, s, t, "IPv6 rejected\n");
-                       session[s].flags |= SF_IPV6_NACKED;
+                       change_state(s, ipv6cp, Closed);
                }
                else
                {
@@ -653,49 +834,50 @@ void processlcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
        {
                // Ignore it, last_packet time is set earlier than this.
        }
-       else if (*p == IdentRequest)
+       else
        {
+               int code = *p;
+               int mru = session[s].mru;
+               if (!mru)
+                       mru = DEFAULT_MRU;
+
+               if (l > mru) l = mru;
+
                *p = CodeRej;
-               if (l > MAXCONTROL)
-               {
-                       LOG(1, s, t, "Truncated Ident Packet (length=%d) to 1400 bytes\n", l);
-                       l = 1400;
-               }
                q = makeppp(b, sizeof(b), p, l, t, s, PPPLCP);
                if (!q) return;
-               LOG_HEX(5, "LCPIdentRej", q, l + 4);
-               tunnelsend(b, 12 + 4 + l, t);
-       }
-       else
-       {
-               LOG(1, s, t, "Unexpected LCP code %d\n", *p);
-               STAT(tunnel_rx_errors);
+
+               LOG(3, s, t, "Unexpected LCP code %s\n", ppp_code(code));
+               tunnelsend(b, l + (q - b), t);
        }
 }
 
-// find a PPP option, returns point to option, or 0 if not found
-static uint8_t *findppp(uint8_t *b, uint8_t mtype)
+static void ipcp_open(tunnelidt t, sessionidt s)
 {
-       uint16_t l = ntohs(*(uint16_t *) (b + 2));
-       if (l < 4)
-               return 0;
-       b += 4;
-       l -= 4;
-       while (l)
+       LOG(3, s, t, "IPCP Acked, session is now active\n");
+
+       change_state(s, ipcp, Opened);
+
+       if (!session[s].walled_garden)
        {
-               if (l < b[1] || !b[1])
-                       return 0;               // faulty
-               if (*b == mtype)
-                       return b;
-               l -= b[1];
-               b += b[1];
+               uint16_t r = radiusnew(s);
+               if (r)
+                       radiussend(r, RADIUSSTART); // send radius start
+       }
+
+       // start IPv6 if configured and still in passive state
+       if (session[s].ppp.ipv6cp == Stopped)
+       {
+               sendipv6cp(t, s);
+               change_state(s, ipv6cp, RequestSent);
        }
-       return 0;
 }
 
 // Process IPCP messages
 void processipcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
 {
+       uint8_t b[MAXCONTROL];
+       uint8_t *q = 0;
        uint16_t hl;
 
        CSTAT(processipcp);
@@ -716,135 +898,217 @@ void processipcp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
        }
        l = hl;
 
+       if (session[s].ppp.phase < Network)
+       {
+               LOG(2, s, t, "IPCP %s ignored in %s phase\n", ppp_code(*p), ppp_phase(session[s].ppp.phase));
+               return;
+       }
+
        if (*p == ConfigAck)
        {
-               uint16_t r = sess_local[s].radius;
+               switch (session[s].ppp.ipcp)
+               {
+               case RequestSent:
+                       initialise_restart_count(s, ipcp);
+                       change_state(s, ipcp, AckReceived);
+                       break;
 
-               // ignore duplicate ACKs
-               if (session[s].flags & SF_IPCP_ACKED)
-                       return;
+               case AckReceived:
+               case Opened:
+                       LOG(3, s, t, "IPCP: ConfigAck in state %s?  Sending ConfigReq\n", ppp_state(session[s].ppp.ipcp));
+                       sendipcp(s, t);
+                       change_state(s, ipcp, RequestSent);
+                       break;
 
-               // happy with our IPCP
-               session[s].flags |= SF_IPCP_ACKED;
+               case AckSent:
+                       ipcp_open(t, s);
+                       break;
 
-               LOG(3, s, t, "IPCP Acked, session is now active\n");
+               default:
+                       LOG(3, s, t, "IPCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipcp));
+               }
+       }
+       else if (*p == ConfigReq)
+       {
+               uint8_t *response = 0;
+               uint8_t *o = p + 4;
+               int length = l - 4;
+               int gotip = 0;
+               in_addr_t addr;
 
-               // clear LCP_ACKED/CCP_ACKED flag for possible fast renegotiation for routers
-               session[s].flags &= ~(SF_LCP_ACKED|SF_CCP_ACKED);
+               LOG(4, s, t, "IPCP ConfigReq received\n");
 
-               if (r && session[s].walled_garden)
+               while (length > 2)
                {
-                       radiusclear(r, s);
-                       return;
-               }
+                       switch (*o)
+                       {
+                       case 3: // ip address
+                               gotip++; // seen address
+                               if (o[1] != 6 || o[1] > length) return;
 
-               if (!r)
-                       r = radiusnew(s);
+                               addr = htonl(session[s].ip);
+                               if (memcmp(o + 2, &addr, (sizeof addr)))
+                               {
+                                       q = ppp_nak(s, b, sizeof(b), PPPIPCP, &response, q, p, o, (uint8_t *) &addr, sizeof(addr));
+                                       if (!q || *response == ConfigRej)
+                                       {
+                                               sessionshutdown(s, "Can't negotiate IPCP.", 3, 0);
+                                               return;
+                                       }
+                               }
 
-               if (r)
-                       radiussend(r, RADIUSSTART); // send radius start, having got IPCP at last
+                               break;
 
-               return;
-       }
-       if (*p != ConfigReq)
-       {
-               LOG(1, s, t, "Unexpected IPCP code %d\n", *p);
-               STAT(tunnel_rx_errors);
-               return ;
-       }
-       LOG(4, s, t, "IPCP ConfigReq received\n");
+                       case 129: // primary DNS
+                               if (o[1] != 6 || o[1] > length) return;
 
-       if (!session[s].ip)
-       {
-               LOG(3, s, t, "Waiting on radius reply\n");
-               return;                 // have to wait on RADIUS reply
-       }
-       // form a config reply quoting the IP in the session
-       {
-               uint8_t b[MAXCONTROL];
-               uint8_t *i, *q;
+                               addr = htonl(session[s].dns1);
+                               if (memcmp(o + 2, &addr, (sizeof addr)))
+                               {
+                                       q = ppp_nak(s, b, sizeof(b), PPPIPCP, &response, q, p, o, (uint8_t *) &addr, sizeof(addr));
+                                       if (!q) return;
+                               }
 
-               q = p + 4;
-               i = p + l;
-               while (q < i && q[1])
-               {
-                       if (*q != 0x81 && *q != 0x83 && *q != 3)
                                break;
-                       q += q[1];
-               }
-               if (q < i)
-               {
-                       // reject
-                       uint16_t n = 4;
-                       i = p + l;
-                       if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPCP)))
-                               return;
-
-                       *q = ConfigRej;
-                       p += 4;
-                       while (p < i && p[1])
-                       {
-                               if (*p != 0x81 && *p != 0x83 && *p != 3)
+
+                       case 131: // secondary DNS
+                               if (o[1] != 6 || o[1] > length) return;
+
+                               addr = htonl(session[s].dns1);
+                               if (memcmp(o + 2, &addr, sizeof(addr)))
                                {
-                                       LOG(2, s, t, "IPCP reject %d\n", *p);
-                                       memcpy(q + n, p, p[1]);
-                                       n += p[1];
+                                       q = ppp_nak(s, b, sizeof(b), PPPIPCP, &response, q, p, o, (uint8_t *) &addr, sizeof(addr));
+                                       if (!q) return;
                                }
-                               p += p[1];
+
+                               break;
+
+                       default:
+                               LOG(2, s, t, "    Rejecting PPP IPCP Option type %d\n", *o);
+                               q = ppp_rej(s, b, sizeof(b), PPPIPCP, &response, q, p, o);
+                               if (!q) return;
                        }
-                       *(uint16_t *) (q + 2) = htons(n);
-                       LOG(4, s, t, "Sending ConfigRej\n");
-                       tunnelsend(b, n + (q - b), t); // send it
+
+                       length -= o[1];
+                       o += o[1];
+               }
+
+               if (response)
+               {
+                       l = q - response; // IPCP packet length
+                       *((uint16_t *) (response + 2)) = htons(l); // update header
+               }
+               else if (gotip)
+               {
+                       // Send packet back as ConfigAck
+                       response = makeppp(b, sizeof(b), p, l, t, s, PPPIPCP);
+                       if (!response) return;
+                       *response = ConfigAck;
                }
                else
                {
-                       LOG(4, s, t, "Sending ConfigAck\n");
-                       *p = ConfigAck;
-                       if ((i = findppp(p, 0x81))) // Primary DNS address
-                       {
-                               if (*(uint32_t *) (i + 2) != htonl(session[s].dns1))
-                               {
-                                       *(uint32_t *) (i + 2) = htonl(session[s].dns1);
-                                       *p = ConfigNak;
-                                       LOG(5, s, t, "   DNS1 = %s\n",
-                                               fmtaddr(htonl(session[s].dns1), 0));
-                               }
-                       }
-                       if ((i = findppp(p, 0x83))) // Secondary DNS address (TBA, is it)
-                       {
-                               if (*(uint32_t *) (i + 2) != htonl(session[s].dns2))
-                               {
-                                       *(uint32_t *) (i + 2) = htonl(session[s].dns2);
-                                       *p = ConfigNak;
-                                       LOG(5, s, t, "   DNS2 = %s\n",
-                                               fmtaddr(htonl(session[s].dns2), 0));
-                               }
-                       }
-                       i = findppp(p, 3);              // IP address
-                       if (!i || i[1] != 6)
-                       {
-                               LOG(1, s, t, "No IP in IPCP request\n");
-                               STAT(tunnel_rx_errors);
-                               return ;
-                       }
-                       if (*(uint32_t *) (i + 2) != htonl(session[s].ip))
-                       {
-                               *(uint32_t *) (i + 2) = htonl(session[s].ip);
-                               *p = ConfigNak;
-                               LOG(4, s, t, " No, a ConfigNak, client is requesting IP - sending %s\n",
-                                               fmtaddr(htonl(session[s].ip), 0));
-                       }
-                       if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPCP)))
-                               return;
+                       LOG(1, s, t, "No IP in IPCP request\n");
+                       STAT(tunnel_rx_errors);
+                       return;
+               }
+
+               switch (session[s].ppp.ipcp)
+               {
+               case Closed:
+                       response = makeppp(b, sizeof(b), p, 2, t, s, PPPIPCP);
+                       if (!response) return;
+                       *response = TerminateAck;
+                       *((uint16_t *) (response + 2)) = htons(l = 4);
+                       break;
+
+               case Stopped:
+                       initialise_restart_count(s, ipcp);
+                       sendipcp(s, t);
+                       if (*response == ConfigAck)
+                               change_state(s, ipcp, AckSent);
+                       else
+                               change_state(s, ipcp, RequestSent);
+
+                       break;
 
-                       tunnelsend(b, l + (q - b), t); // send it
+               case RequestSent:
+                       if (*response == ConfigAck)
+                               change_state(s, ipcp, AckSent);
+
+                       break;
+
+               case AckReceived:
+                       if (*response == ConfigAck)
+                               ipcp_open(t, s);
+
+                       break;
+
+               case Opened:
+                       initialise_restart_count(s, ipcp);
+                       sendipcp(s, t);
+                       /* fallthrough */
+
+               case AckSent:
+                       if (*response == ConfigAck)
+                               change_state(s, ipcp, AckSent);
+                       else
+                               change_state(s, ipcp, RequestSent);
+
+                       break;
+
+               default:
+                       LOG(3, s, t, "IPCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipcp));
+                       return;
                }
+
+               LOG(3, s, t, "IPCP: Sending %s\n", ppp_code(*response));
+               tunnelsend(b, l + (response - b), t);
+       }
+       else if (*p == TerminateReq)
+       {
+               LOG(3, s, t, "IPCP: Received TerminateReq.  Sending TerminateAck\n");
+               *p = TerminateAck;
+               q = makeppp(b, sizeof(b),  p, l, t, s, PPPIPCP);
+               if (!q) return;
+               tunnelsend(b, l + (q - b), t);
+               change_state(s, ipcp, Stopped);
        }
+       else
+       {
+               int code = *p;
+               int mru = session[s].mru;
+               if (!mru)
+                       mru = DEFAULT_MRU;
+
+               if (l > mru) l = mru;
+
+               *p = CodeRej;
+               q = makeppp(b, sizeof(b), p, l, t, s, PPPIPCP);
+               if (!q) return;
+
+               LOG(3, s, t, "Unexpected IPCP code %s\n", ppp_code(code));
+               tunnelsend(b, l + (q - b), t);
+       }
+}
+
+static void ipv6cp_open(tunnelidt t, sessionidt s)
+{
+       LOG(3, s, t, "IPV6CP Acked\n");
+
+       change_state(s, ipv6cp, Opened);
+       if (session[s].ipv6prefixlen)
+               route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 1);
+
+       // Send an initial RA (TODO: Should we send these regularly?)
+       send_ipv6_ra(t, s, NULL);
 }
 
 // Process IPV6CP messages
 void processipv6cp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
 {
+       uint8_t b[MAXCONTROL];
+       uint8_t *q = 0;
+       uint16_t hl;
 
        CSTAT(processipv6cp);
 
@@ -855,112 +1119,195 @@ void processipv6cp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                STAT(tunnel_rx_errors);
                return ;
        }
-       if (*p == ConfigAck)
-       {
-               // happy with our IPV6CP
-               session[s].flags |= SF_IPV6CP_ACKED;
 
-               LOG(3, s, t, "IPV6CP Acked, IPv6 is now active\n");
-               // Add a routed block if configured.
-               if (session[s].ipv6prefixlen)
-               {
-                       route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 1);
-                       session[s].flags |= SF_IPV6_ROUTED;
-               }
-
-               // Send an initial RA (TODO: Should we send these regularly?)
-               send_ipv6_ra(t, s, NULL);
-               return;
-       }
-       if (*p != ConfigReq)
+       if ((hl = ntohs(*(uint16_t *) (p + 2))) > l)
        {
-               LOG(1, s, t, "Unexpected IPV6CP code %d\n", *p);
+               LOG(1, s, t, "Length mismatch IPV6CP %u/%u\n", hl, l);
                STAT(tunnel_rx_errors);
+               return ;
+       }
+       l = hl;
+
+       if (session[s].ppp.phase < Network)
+       {
+               LOG(2, s, t, "IPV6CP %s ignored in %s phase\n", ppp_code(*p), ppp_phase(session[s].ppp.phase));
                return;
        }
 
-       LOG(4, s, t, "IPV6CP ConfigReq received\n");
-       if (ntohs(*(uint16_t *) (p + 2)) > l)
+       if (!config->ipv6_prefix.s6_addr[0])
        {
-               LOG(1, s, t, "Length mismatch IPV6CP %d/%d\n", ntohs(*(uint16_t *) (p + 2)), l);
-               STAT(tunnel_rx_errors);
-               return ;
+               LOG(2, s, t, "IPV6CP %s rejected (not configured)\n", ppp_code(*p));
+               *p = ProtocolRej;
+               q = makeppp(b, sizeof(b),  p, l, t, s, PPPIPV6CP);
+               if (!q) return;
+               tunnelsend(b, l + (q - b), t);
+               return;
        }
+
        if (!session[s].ip)
        {
-               LOG(3, s, t, "Waiting on radius reply\n");
-               return;                 // have to wait on RADIUS reply
+               LOG(3, s, t, "IPV6CP: no IPv4 address (IPCP in state %s)\n", ppp_state(session[s].ppp.ipcp));
+               return; // need IPCP to complete...
        }
-       // form a config reply quoting the IP in the session
-       {
-               uint8_t b[MAXCONTROL];
-               uint8_t *i,
-               *q;
 
-               l = ntohs(*(uint16_t *) (p + 2)); // We must use length from IPV6CP len field
-               q = p + 4;
-               i = p + l;
-               while (q < i && q[1])
+       if (*p == ConfigAck)
+       {
+               switch (session[s].ppp.ipv6cp)
                {
-                       if (*q != 1)
-                               break;
-                       q += q[1];
+               case RequestSent:
+                       initialise_restart_count(s, ipv6cp);
+                       change_state(s, ipv6cp, AckReceived);
+                       break;
+
+               case AckReceived:
+               case Opened:
+                       LOG(3, s, t, "IPV6CP: ConfigAck in state %s?  Sending ConfigReq\n", ppp_state(session[s].ppp.ipv6cp));
+                       sendipv6cp(s, t);
+                       change_state(s, ipv6cp, RequestSent);
+                       break;
+
+               case AckSent:
+                       ipv6cp_open(t, s);
+                       break;
+
+               default:
+                       LOG(3, s, t, "IPV6CP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipv6cp));
                }
-               if (q < i)
+       }
+       else if (*p == ConfigReq)
+       {
+               uint8_t *response = 0;
+               uint8_t *o = p + 4;
+               int length = l - 4;
+               int gotip = 0;
+               uint8_t ident[8];
+
+               LOG(4, s, t, "IPV6CP ConfigReq received\n");
+
+               while (length > 2)
                {
-                       // reject
-                       uint16_t n = 4;
-                       i = p + l;
-                       if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP)))
-                       {
-                               LOG(2, s, t, "Failed to send IPV6CP ConfigRej\n");
-                               return;
-                       }
-                       *q = ConfigRej;
-                       p += 4;
-                       while (p < i && p[1])
+                       switch (*o)
                        {
-                               if (*p != 1)
+                       case 1: // interface identifier
+                               gotip++; // seen address
+                               if (o[1] != 10 || o[1] > length) return;
+
+                               *(uint32_t *) ident = htonl(session[s].ip);
+                               *(uint32_t *) (ident + 4) = 0;
+
+                               if (memcmp(o + 2, ident, sizeof(ident)))
                                {
-                                       LOG(2, s, t, "IPV6CP reject %d\n", *p);
-                                       memcpy(q + n, p, p[1]);
-                                       n += p[1];
+                                       q = ppp_nak(s, b, sizeof(b), PPPIPV6CP, &response, q, p, o, ident, sizeof(ident));
+                                       if (!q) return;
                                }
-                               p += p[1];
+
+                               break;
+
+                       default:
+                               LOG(2, s, t, "    Rejecting PPP IPV6CP Option type %d\n", *o);
+                               q = ppp_rej(s, b, sizeof(b), PPPIPV6CP, &response, q, p, o);
+                               if (!q) return;
                        }
-                       *(uint16_t *) (q + 2) = htons(n);
-                       LOG(4, s, t, "Sending ConfigRej\n");
-                       tunnelsend(b, n + (q - b), t); // send it
+
+                       length -= o[1];
+                       o += o[1];
+               }
+
+               if (response)
+               {
+                       l = q - response; // IPV6CP packet length
+                       *((uint16_t *) (response + 2)) = htons(l); // update header
+               }
+               else if (gotip)
+               {
+                       // Send packet back as ConfigAck
+                       response = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP);
+                       if (!response) return;
+                       *response = ConfigAck;
                }
                else
                {
-                       LOG(4, s, t, "Sending ConfigAck\n");
-                       *p = ConfigAck;
-                       i = findppp(p, 1);              // IP address
-                       if (!i || i[1] != 10)
-                       {
-                               LOG(1, s, t, "No IP in IPV6CP request\n");
-                               STAT(tunnel_rx_errors);
-                               return ;
-                       }
-                       if ((*(uint32_t *) (i + 2) != htonl(session[s].ip)) || 
-                                       (*(uint32_t *) (i + 6) != 0))
-                       {
-                               *(uint32_t *) (i + 2) = htonl(session[s].ip);
-                               *(uint32_t *) (i + 6) = 0;
-                               *p = ConfigNak;
-                               LOG(4, s, t,
-                                       " No, a ConfigNak, client is "
-                                       "requesting IP - sending %s\n",
-                                       fmtaddr(htonl(session[s].ip), 0));
-                       }
-                       if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP)))
-                       {
-                               LOG(2, s, t, " Failed to send IPV6CP packet.\n");
-                               return;
-                       }
-                       tunnelsend(b, l + (q - b), t); // send it
+                       LOG(1, s, t, "No interface identifier in IPV6CP request\n");
+                       STAT(tunnel_rx_errors);
+                       return;
+               }
+
+               switch (session[s].ppp.ipv6cp)
+               {
+               case Closed:
+                       response = makeppp(b, sizeof(b), p, 2, t, s, PPPIPV6CP);
+                       if (!response) return;
+                       *response = TerminateAck;
+                       *((uint16_t *) (response + 2)) = htons(l = 4);
+                       break;
+
+               case Stopped:
+                       initialise_restart_count(s, ipv6cp);
+                       sendipv6cp(s, t);
+                       if (*response == ConfigAck)
+                               change_state(s, ipv6cp, AckSent);
+                       else
+                               change_state(s, ipv6cp, RequestSent);
+
+                       break;
+
+               case RequestSent:
+                       if (*response == ConfigAck)
+                               change_state(s, ipv6cp, AckSent);
+
+                       break;
+
+               case AckReceived:
+                       if (*response == ConfigAck)
+                               ipv6cp_open(t, s);
+
+                       break;
+
+               case Opened:
+                       initialise_restart_count(s, ipv6cp);
+                       sendipv6cp(s, t);
+                       /* fallthrough */
+
+               case AckSent:
+                       if (*response == ConfigAck)
+                               change_state(s, ipv6cp, AckSent);
+                       else
+                               change_state(s, ipv6cp, RequestSent);
+
+                       break;
+
+               default:
+                       LOG(3, s, t, "IPV6CP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipv6cp));
+                       return;
                }
+
+               LOG(3, s, t, "IPV6CP: Sending %s\n", ppp_code(*response));
+               tunnelsend(b, l + (response - b), t);
+       }
+       else if (*p == TerminateReq)
+       {
+               LOG(3, s, t, "IPV6CP: Received TerminateReq.  Sending TerminateAck\n");
+               *p = TerminateAck;
+               q = makeppp(b, sizeof(b),  p, l, t, s, PPPIPV6CP);
+               if (!q) return;
+               tunnelsend(b, l + (q - b), t);
+               change_state(s, ipv6cp, Stopped);
+       }
+       else
+       {
+               int code = *p;
+               int mru = session[s].mru;
+               if (!mru)
+                       mru = DEFAULT_MRU;
+
+               if (l > mru) l = mru;
+
+               *p = CodeRej;
+               q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP);
+               if (!q) return;
+
+               LOG(3, s, t, "Unexpected IPV6CP code %s\n", ppp_code(code));
+               tunnelsend(b, l + (q - b), t);
        }
 }
 
@@ -985,6 +1332,9 @@ void processipin(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                return ;
        }
 
+       if (session[s].ppp.phase != Network || session[s].ppp.ipcp != Opened)
+               return;
+
        // no spoof (do sessionbyip to handled statically routed subnets)
        if (ip != session[s].ip && sessionbyip(htonl(ip)) != s)
        {
@@ -1070,6 +1420,9 @@ void processipv6in(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
                return ;
        }
 
+       if (session[s].ppp.phase != Network || session[s].ppp.ipv6cp != Opened)
+               return;
+
        // no spoof
        if (ipv4 != session[s].ip && memcmp(&config->ipv6_prefix, &ip, 8) && sessionbyipv6(ip) != s)
        {
@@ -1190,46 +1543,131 @@ void processccp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
        CSTAT(processccp);
 
        LOG_HEX(5, "CCP", p, l);
-       switch (l > 1 ? *p : 0)
+
+       if (session[s].ppp.phase < Network)
        {
-       case ConfigAck:
-               session[s].flags |= SF_CCP_ACKED;
+               LOG(2, s, t, "CCP %s ignored in %s phase\n", ppp_code(*p), ppp_phase(session[s].ppp.phase));
                return;
+       }
 
-       case ConfigReq:
-               if (l < 6) // accept no compression
+       if (l < 1)
+       {
+               LOG(1, s, t, "Short CCP packet\n");
+               STAT(tunnel_rx_errors);
+       }
+
+       if (*p == ConfigAck)
+       {
+               switch (session[s].ppp.ccp)
                {
-                       *p = ConfigAck;
+               case RequestSent:
+                       initialise_restart_count(s, ccp);
+                       change_state(s, ccp, AckReceived);
+                       break;
+
+               case AckReceived:
+               case Opened:
+                       LOG(3, s, t, "CCP: ConfigAck in state %s?  Sending ConfigReq\n", ppp_state(session[s].ppp.ccp));
+                       sendccp(s, t);
+                       change_state(s, ccp, RequestSent);
                        break;
+
+               case AckSent:
+                       LOG(3, s, t, "CCP Acked\n");
+                       change_state(s, ccp, Opened);
+                       break;
+
+               default:
+                       LOG(3, s, t, "CCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ccp));
                }
+       }
+       else if (*p == ConfigReq)
+       {
+               if (l < 6) // accept no compression
+                       *p = ConfigAck;
+               else // compression requested--reject
+                       *p = ConfigRej;
 
-               // compression requested--reject
-               *p = ConfigRej;
+               q = makeppp(b, sizeof(b), p, l, t, s, PPPCCP);
+               if (!q) return;
 
-               // send CCP request for no compression for our end if not negotiated
-               if (!(session[s].flags & SF_CCP_ACKED))
-                       initccp(t, s);
+               switch (session[s].ppp.ccp)
+               {
+               case Closed:
+                       q = makeppp(b, sizeof(b), p, 2, t, s, PPPCCP);
+                       if (!q) return;
+                       *q = TerminateAck;
+                       *((uint16_t *) (q + 2)) = htons(l = 4);
+                       break;
 
-               break;
+               case Stopped:
+                       initialise_restart_count(s, ccp);
+                       sendccp(s, t);
+                       if (*q == ConfigAck)
+                               change_state(s, ccp, AckSent);
+                       else
+                               change_state(s, ccp, RequestSent);
 
-       case TerminateReq:
-               *p = TerminateAck;
-               break;
+                       break;
 
-       default:
-               if (l > 1)
-                       LOG(1, s, t, "Unexpected CCP request code %d\n", *p);
-               else
-                       LOG(1, s, t, "Short CCP packet\n");
+               case RequestSent:
+                       if (*q == ConfigAck)
+                               change_state(s, ccp, AckSent);
 
-               STAT(tunnel_rx_errors);
-               return;
+                       break;
+
+               case AckReceived:
+                       if (*q == ConfigAck)
+                               change_state(s, ccp, Opened);
+
+                       break;
+
+               case Opened:
+                       initialise_restart_count(s, ccp);
+                       sendccp(s, t);
+                       /* fallthrough */
+
+               case AckSent:
+                       if (*q == ConfigAck)
+                               change_state(s, ccp, AckSent);
+                       else
+                               change_state(s, ccp, RequestSent);
+
+                       break;
+
+               default:
+                       LOG(3, s, t, "CCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ccp));
+                       return;
+               }
+
+               LOG(3, s, t, "CCP: Sending %s\n", ppp_code(*q));
+               tunnelsend(b, l + (q - b), t);
        }
+       else if (*p == TerminateReq)
+       {
+               LOG(3, s, t, "CCP: Received TerminateReq.  Sending TerminateAck\n");
+               *p = TerminateAck;
+               q = makeppp(b, sizeof(b),  p, l, t, s, PPPCCP);
+               if (!q) return;
+               tunnelsend(b, l + (q - b), t);
+               change_state(s, ccp, Stopped);
+       }
+       else
+       {
+               int code = *p;
+               int mru = session[s].mru;
+               if (!mru)
+                       mru = DEFAULT_MRU;
 
-       if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPCCP)))
-               return;
+               if (l > mru) l = mru;
+
+               *p = CodeRej;
+               q = makeppp(b, sizeof(b), p, l, t, s, PPPCCP);
+               if (!q) return;
 
-       tunnelsend(b, l + (q - b), t); // send it
+               LOG(3, s, t, "Unexpected CCP code %s\n", ppp_code(code));
+               tunnelsend(b, l + (q - b), t);
+       }
 }
 
 // send a CHAP challenge
@@ -1270,7 +1708,7 @@ void sendchap(tunnelidt t, sessionidt s)
        q[1] = radius[r].id;                    // ID
        q[4] = 16;                              // value size (size of challenge)
        memcpy(q + 5, radius[r].auth, 16);      // challenge
-       strcpy(q + 21, hostname);               // our name
+       strcpy((char *) q + 21, hostname);      // our name
        *(uint16_t *) (q + 2) = htons(strlen(hostname) + 21); // length
        tunnelsend(b, strlen(hostname) + 21 + (q - b), t); // send it
 }
@@ -1319,21 +1757,22 @@ uint8_t *makeppp(uint8_t *b, int size, uint8_t *p, int l, tunnelidt t, sessionid
        return b;
 }
 
-static uint8_t *add_lcp_auth(uint8_t *b, int size, int authtype)
+static int add_lcp_auth(uint8_t *b, int size, int authtype)
 {
+       int len = 0;
        if ((authtype == AUTHCHAP && size < 5) || size < 4)
                return 0;
 
        *b++ = 3; // Authentication-Protocol
        if (authtype == AUTHCHAP)
        {
-               *b++ = 5; // length
+               len = *b++ = 5; // length
                *(uint16_t *) b = htons(PPPCHAP); b += 2;
                *b++ = 5; // MD5
        }
        else if (authtype == AUTHPAP)
        {
-               *b++ = 4; // length
+               len = *b++ = 4; // length
                *(uint16_t *) b = htons(PPPPAP); b += 2;
        }
        else
@@ -1341,19 +1780,20 @@ static uint8_t *add_lcp_auth(uint8_t *b, int size, int authtype)
                LOG(0, 0, 0, "add_lcp_auth called with unsupported auth type %d\n", authtype);
        }
 
-       return b;
+       return len;
 }
 
 // Send initial LCP ConfigReq for MRU, authentication type and magic no
 void sendlcp(tunnelidt t, sessionidt s, int authtype)
 {
-       char b[500], *q, *l;
+       uint8_t b[500], *q, *l;
 
        if (!(q = makeppp(b, sizeof(b), NULL, 0, t, s, PPPLCP)))
                return;
 
-       LOG(4, s, t, "Sending LCP ConfigReq for %s\n",
-           authtype == AUTHCHAP ? "CHAP" : "PAP");
+       LOG(4, s, t, "Sending LCP ConfigReq%s%s\n",
+           authtype ? " for " : "",
+           authtype ? (authtype == AUTHCHAP ? "CHAP" : "PAP") : "");
 
        if (!session[s].mru)
                session[s].mru = DEFAULT_MRU;
@@ -1367,7 +1807,8 @@ void sendlcp(tunnelidt t, sessionidt s, int authtype)
        *l++ = 1; *l++ = 4; // Maximum-Receive-Unit (length 4)
        *(uint16_t *) l = htons(session[s].mru); l += 2;
 
-       l = add_lcp_auth(l, sizeof(b) - (l - b), authtype);
+       if (authtype)
+               l += add_lcp_auth(l, sizeof(b) - (l - b), authtype);
 
        *l++ = 5; *l++ = 6; // Magic-Number (length 6)
        *(uint32_t *) l = htonl(session[s].magic);
@@ -1380,9 +1821,9 @@ void sendlcp(tunnelidt t, sessionidt s, int authtype)
 }
 
 // Send CCP request for no compression
-static void initccp(tunnelidt t, sessionidt s)
+void sendccp(tunnelidt t, sessionidt s)
 {
-       char b[500], *q;
+       uint8_t b[500], *q;
 
        if (!(q = makeppp(b, sizeof(b), NULL, 0, t, s, PPPCCP)))
                return;
index 690380f..b31c6f0 100644 (file)
--- a/radius.c
+++ b/radius.c
@@ -1,6 +1,6 @@
 // L2TPNS Radius Stuff
 
-char const *cvs_id_radius = "$Id: radius.c,v 1.36 2005-06-30 14:31:26 bodea Exp $";
+char const *cvs_id_radius = "$Id: radius.c,v 1.37 2005-07-31 10:04:10 bodea Exp $";
 
 #include <time.h>
 #include <stdio.h>
@@ -13,7 +13,7 @@ char const *cvs_id_radius = "$Id: radius.c,v 1.36 2005-06-30 14:31:26 bodea Exp
 #include <ctype.h>
 #include <netinet/in.h>
 #include <errno.h>
-#include "md5.h"
+#include <openssl/md5.h>
 #include "constants.h"
 #include "l2tpns.h"
 #include "plugin.h"
@@ -182,7 +182,7 @@ void radiussend(uint16_t r, uint8_t state)
        {
                *p = 1;                 // user name
                p[1] = strlen(session[s].user) + 2;
-               strcpy(p + 2, session[s].user);
+               strcpy((char *) p + 2, session[s].user);
                p += p[1];
        }
        if (state == RADIUSAUTH)
@@ -212,13 +212,13 @@ void radiussend(uint16_t r, uint8_t state)
                                while (p < pl)
                                {
                                        MD5_CTX ctx;
-                                       MD5Init(&ctx);
-                                       MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
+                                       MD5_Init(&ctx);
+                                       MD5_Update(&ctx, config->radiussecret, strlen(config->radiussecret));
                                        if (p)
-                                               MD5Update(&ctx, pass + p - 16, 16);
+                                               MD5_Update(&ctx, pass + p - 16, 16);
                                        else
-                                               MD5Update(&ctx, radius[r].auth, 16);
-                                       MD5Final(hash, &ctx);
+                                               MD5_Update(&ctx, radius[r].auth, 16);
+                                       MD5_Final(hash, &ctx);
                                        do
                                        {
                                                pass[p] ^= hash[p & 15];
@@ -244,7 +244,7 @@ void radiussend(uint16_t r, uint8_t state)
                {
                        *p = 44;        // session ID
                        p[1] = 18;
-                       sprintf(p + 2, "%08X%08X", session[s].unique_id, session[s].opened);
+                       sprintf((char *) p + 2, "%08X%08X", session[s].unique_id, session[s].opened);
                        p += p[1];
                        if (state == RADIUSSTART)
                        {                       // start
@@ -299,7 +299,7 @@ void radiussend(uint16_t r, uint8_t state)
                                *p = 26;                                // vendor-specific
                                *(uint32_t *) (p + 2) = htonl(9);       // Cisco
                                p[6] = 1;                               // Cisco-AVPair
-                               p[7] = 2 + sprintf(p + 8, "intercept=%s:%d",
+                               p[7] = 2 + sprintf((char *) p + 8, "intercept=%s:%d",
                                        fmtaddr(session[s].snoop_ip, 0), session[s].snoop_port);
 
                                p[1] = p[7] + 6;
@@ -325,21 +325,14 @@ void radiussend(uint16_t r, uint8_t state)
        {
                *p = 30;                // called
                p[1] = strlen(session[s].called) + 2;
-               strcpy(p + 2, session[s].called);
-               p += p[1];
-       }
-       if (*radius[r].calling)
-       {
-               *p = 31;                // calling
-               p[1] = strlen(radius[r].calling) + 2;
-               strcpy(p + 2, radius[r].calling);
+               strcpy((char *) p + 2, session[s].called);
                p += p[1];
        }
        else if (*session[s].calling)
        {
                *p = 31;                // calling
                p[1] = strlen(session[s].calling) + 2;
-               strcpy(p + 2, session[s].calling);
+               strcpy((char *) p + 2, session[s].calling);
                p += p[1];
        }
        // NAS-IP-Address
@@ -353,15 +346,15 @@ void radiussend(uint16_t r, uint8_t state)
        if (state != RADIUSAUTH)
        {
            // Build auth for accounting packet
-           char z[16] = {0};
-           char hash[16] = {0};
+           uint8_t z[16] = {0};
+           uint8_t hash[16] = {0};
            MD5_CTX ctx;
-           MD5Init(&ctx);
-           MD5Update(&ctx, b, 4);
-           MD5Update(&ctx, z, 16);
-           MD5Update(&ctx, b + 20, (p - b) - 20);
-           MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
-           MD5Final(hash, &ctx);
+           MD5_Init(&ctx);
+           MD5_Update(&ctx, b, 4);
+           MD5_Update(&ctx, z, 16);
+           MD5_Update(&ctx, b + 20, (p - b) - 20);
+           MD5_Update(&ctx, config->radiussecret, strlen(config->radiussecret));
+           MD5_Final(hash, &ctx);
            memcpy(b + 4, hash, 16);
            memcpy(radius[r].auth, hash, 16);
        }
@@ -381,9 +374,9 @@ void radiussend(uint16_t r, uint8_t state)
 
 static void handle_avpair(sessionidt s, uint8_t *avp, int len)
 {
-       char *key = avp;
-       char *value = memchr(avp, '=', len);
-       char tmp[2048] = "";
+       uint8_t *key = avp;
+       uint8_t *value = memchr(avp, '=', len);
+       uint8_t tmp[2048] = "";
 
        if (value)
        {
@@ -415,7 +408,7 @@ static void handle_avpair(sessionidt s, uint8_t *avp, int len)
        
        // Run hooks
        {
-               struct param_radius_response p = { &tunnel[session[s].tunnel], &session[s], key, value };
+               struct param_radius_response p = { &tunnel[session[s].tunnel], &session[s], (char *) key, (char *) value };
                run_plugins(PLUGIN_RADIUS_RESPONSE, &p);
        }
 }
@@ -463,12 +456,12 @@ void processrad(uint8_t *buf, int len, char socket_index)
                return;
        }
        t = session[s].tunnel;
-       MD5Init(&ctx);
-       MD5Update(&ctx, buf, 4);
-       MD5Update(&ctx, radius[r].auth, 16);
-       MD5Update(&ctx, buf + 20, len - 20);
-       MD5Update(&ctx, config->radiussecret, strlen(config->radiussecret));
-       MD5Final(hash, &ctx);
+       MD5_Init(&ctx);
+       MD5_Update(&ctx, buf, 4);
+       MD5_Update(&ctx, radius[r].auth, 16);
+       MD5_Update(&ctx, buf + 20, len - 20);
+       MD5_Update(&ctx, config->radiussecret, strlen(config->radiussecret));
+       MD5_Final(hash, &ctx);
        do {
                if (memcmp(hash, buf + 4, 16))
                {
@@ -617,7 +610,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
                                        else if (*p == 11)
                                        {
                                                // Filter-Id
-                                               char *filter = p + 2;
+                                               char *filter = (char *) p + 2;
                                                int l = p[1] - 2;
                                                char *suffix;
                                                int f;
@@ -680,10 +673,10 @@ void processrad(uint8_t *buf, int len, char socket_index)
                                                int prefixlen;
                                                uint8_t *n = p + 2;
                                                uint8_t *e = p + p[1];
-                                               uint8_t *m = strchr(n, '/');
+                                               uint8_t *m = memchr(n, '/', e - p);
 
                                                *m++ = 0;
-                                               inet_pton(AF_INET6, n, &r6);
+                                               inet_pton(AF_INET6, (char *) n, &r6);
 
                                                prefixlen = 0;
                                                while (m < e && isdigit(*m)) {
@@ -710,12 +703,12 @@ void processrad(uint8_t *buf, int len, char socket_index)
 
                        if (!session[s].dns1 && config->default_dns1)
                        {
-                               session[s].dns1 = htonl(config->default_dns1);
+                               session[s].dns1 = ntohl(config->default_dns1);
                                LOG(3, s, t, "   Sending dns1 = %s\n", fmtaddr(config->default_dns1, 0));
                        }
                        if (!session[s].dns2 && config->default_dns2)
                        {
-                               session[s].dns2 = htonl(config->default_dns2);
+                               session[s].dns2 = ntohl(config->default_dns2);
                                LOG(3, s, t, "   Sending dns2 = %s\n", fmtaddr(config->default_dns2, 0));
                        }
 
@@ -750,20 +743,11 @@ void radiusretry(uint16_t r)
                case RADIUSCHAP:        // sending CHAP down PPP
                        sendchap(t, s);
                        break;
-               case RADIUSIPCP:
-                       sendipcp(t, s); // send IPCP
-                       break;
                case RADIUSAUTH:        // sending auth to RADIUS server
-                       radiussend(r, RADIUSAUTH);
-                       break;
                case RADIUSSTART:       // sending start accounting to RADIUS server
-                       radiussend(r, RADIUSSTART);
-                       break;
                case RADIUSSTOP:        // sending stop accounting to RADIUS server
-                       radiussend(r, RADIUSSTOP);
-                       break;
                case RADIUSINTERIM:     // sending interim accounting to RADIUS server
-                       radiussend(r, RADIUSINTERIM);
+                       radiussend(r, radius[r].state);
                        break;
                default:
                case RADIUSNULL:        // Not in use
@@ -832,10 +816,10 @@ void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen)
        i = strlen(config->radiussecret);
        if (i > 16) i = 16;
 
-       MD5Init(&ctx);
-       MD5Update(&ctx, buf, len);
-       MD5Update(&ctx, buf, config->radiussecret, i);
-       MD5Final(hash, &ctx);
+       MD5_Init(&ctx);
+       MD5_Update(&ctx, buf, len);
+       MD5_Update(&ctx, config->radiussecret, i);
+       MD5_Final(hash, &ctx);
        if (memcmp(hash, vector, 16) != 0)
        {
                LOG(1, 0, 0, "Incorrect vector in DAE request (wrong secret in radius config?)\n");
@@ -903,7 +887,7 @@ void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen)
                        }
 
                        len = p - packet;
-                       i = find_filter(packet, len);
+                       i = find_filter((char *) packet, len);
                        if (i < 0 || !*ip_filters[i].name)
                        {
                                error = 404;
@@ -1063,10 +1047,10 @@ void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen)
        i = strlen(config->radiussecret);
        if (i > 16) i = 16;
 
-       MD5Init(&ctx);
-       MD5Update(&ctx, buf, len);
-       MD5Update(&ctx, config->radiussecret, i);
-       MD5Final(hash, &ctx);
+       MD5_Init(&ctx);
+       MD5_Update(&ctx, buf, len);
+       MD5_Update(&ctx, config->radiussecret, i);
+       MD5_Final(hash, &ctx);
        memcpy(buf + 4, hash, 16);
 
        LOG(3, 0, 0, "Sending DAE %s, id=%d\n", radius_code(r_code), r_id);
diff --git a/tbf.c b/tbf.c
index 091e52d..9b4993d 100644 (file)
--- a/tbf.c
+++ b/tbf.c
@@ -1,6 +1,6 @@
 // L2TPNS: token bucket filters
 
-char const *cvs_id_tbf = "$Id: tbf.c,v 1.12 2005-05-02 09:55:04 bodea Exp $";
+char const *cvs_id_tbf = "$Id: tbf.c,v 1.13 2005-07-31 10:04:10 bodea Exp $";
 
 #include <string.h>
 #include "l2tpns.h"
@@ -159,10 +159,10 @@ void fsck_tbfs(void)
 // If we can send it right away, we do. Else we
 // try and queue it to send later. Else we drop it.
 //
-int tbf_queue_packet(int tbf_id, char * data, int size)
+int tbf_queue_packet(int tbf_id, uint8_t *data, int size)
 {
        int i;
-       tbft * f;
+       tbft *f;
 
        if (!filter_list)
                return -1;
diff --git a/tbf.h b/tbf.h
index 5c85c39..925e4f7 100644 (file)
--- a/tbf.h
+++ b/tbf.h
@@ -30,12 +30,12 @@ typedef struct {
        uint32_t        p_delayed;      // Total packets not sent immediately.
 
        int             sizes[TBF_MAX_QUEUE];
-       char            packets[TBF_MAX_QUEUE][TBF_MAX_SIZE];
+       uint8_t         packets[TBF_MAX_QUEUE][TBF_MAX_SIZE];
 } tbft;
 
 void init_tbf(int num_tbfs);
 int tbf_run_timer(void);
-int tbf_queue_packet(int tbf_id, char * data, int size);
+int tbf_queue_packet(int tbf_id, uint8_t * data, int size);
 int new_tbf(int sid, int max_credit, int rate, void (*f)(sessionidt, uint8_t *, int));
 int free_tbf(int tid);
 void fsck_tbfs(void);
index cc42db5..d0a8dc4 100644 (file)
@@ -19,7 +19,7 @@
 #include <fcntl.h>
 #include <sys/select.h>
 #include <signal.h>
-#include "../md5.h"
+#include <openssl/md5.h>
 
 extern char *optarg;
 extern int optind;
@@ -394,16 +394,16 @@ int main(int argc, char *argv[])
            for (int j = 0; j < pw_len; j += 16)
            {
                MD5_CTX ctx;
-               MD5Init(&ctx);
-               MD5Update(&ctx, secret, strlen(secret));
+               MD5_Init(&ctx);
+               MD5_Update(&ctx, secret, strlen(secret));
                if (j)
-                   MD5Update(&ctx, pass + j - 16, 16);
+                   MD5_Update(&ctx, pass + j - 16, 16);
                else
                    /* authenticator */
-                   MD5Update(&ctx, u->request + 4, 16);
+                   MD5_Update(&ctx, u->request + 4, 16);
 
-               char digest[16];
-               MD5Final(digest, &ctx);
+               uint8_t digest[16];
+               MD5_Final(digest, &ctx);
 
                for (int k = 0; k < 16; k++)
                    pass[j + k] ^= digest[k];