add "shutdown" and "reload" CLI commands (Daryl Tester)
[l2tpns.git] / l2tpns.c
index d70786b..545a3cd 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.169 2006/07/01 12:40:17 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.172 2006/12/18 12:05:36 bodea Exp $";
 
 #include <arpa/inet.h>
 #include <assert.h>
@@ -82,9 +82,13 @@ uint16_t MSS = 0;            // TCP MSS
 struct cli_session_actions *cli_session_actions = NULL;        // Pending session changes requested by CLI
 struct cli_tunnel_actions *cli_tunnel_actions = NULL;  // Pending tunnel changes required by CLI
 
-static void *ip_hash[256];     // Mapping from IP address to session structures.
+union iphash {
+       sessionidt sess;
+       union iphash *idx;
+} ip_hash[256];                        // Mapping from IP address to session structures.
+
 struct ipv6radix {
-       int sess;
+       sessionidt sess;
        struct ipv6radix *branch;
 } ipv6_hash[256];              // Mapping from IPv6 address to session structures.
 
@@ -189,9 +193,9 @@ struct Tstats *_statistics = NULL;
 struct Tringbuffer *ringbuffer = NULL;
 #endif
 
-static void cache_ipmap(in_addr_t ip, int s);
+static void cache_ipmap(in_addr_t ip, sessionidt s);
 static void uncache_ipmap(in_addr_t ip);
-static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s);
+static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s);
 static void free_ip_address(sessionidt s);
 static void dump_acct_info(int all);
 static void sighup_handler(int sig);
@@ -678,19 +682,19 @@ static void initudp(void)
 // IP address.
 //
 
-static int lookup_ipmap(in_addr_t ip)
+static sessionidt lookup_ipmap(in_addr_t ip)
 {
        uint8_t *a = (uint8_t *) &ip;
-       uint8_t **d = (uint8_t **) ip_hash;
+       union iphash *h = ip_hash;
 
-       if (!(d = (uint8_t **) d[(size_t) *a++])) return 0;
-       if (!(d = (uint8_t **) d[(size_t) *a++])) return 0;
-       if (!(d = (uint8_t **) d[(size_t) *a++])) return 0;
+       if (!(h = h[*a++].idx)) return 0;
+       if (!(h = h[*a++].idx)) return 0;
+       if (!(h = h[*a++].idx)) return 0;
 
-       return (int) (intptr_t) d[(size_t) *a];
+       return h[*a].sess;
 }
 
-static int lookup_ipv6map(struct in6_addr ip)
+static sessionidt lookup_ipv6map(struct in6_addr ip)
 {
        struct ipv6radix *curnode;
        int i;
@@ -718,18 +722,18 @@ static int lookup_ipv6map(struct in6_addr ip)
 
 sessionidt sessionbyip(in_addr_t ip)
 {
-       int s = lookup_ipmap(ip);
+       sessionidt s = lookup_ipmap(ip);
        CSTAT(sessionbyip);
 
        if (s > 0 && s < MAXSESSION && session[s].opened)
-               return (sessionidt) s;
+               return s;
 
        return 0;
 }
 
 sessionidt sessionbyipv6(struct in6_addr ip)
 {
-       int s;
+       sessionidt s;
        CSTAT(sessionbyipv6);
 
        if (!memcmp(&config->ipv6_prefix, &ip, 8) ||
@@ -755,25 +759,22 @@ sessionidt sessionbyipv6(struct in6_addr ip)
 //
 // (It's actually cached in network order)
 //
-static void cache_ipmap(in_addr_t ip, int s)
+static void cache_ipmap(in_addr_t ip, sessionidt s)
 {
        in_addr_t nip = htonl(ip);      // MUST be in network order. I.e. MSB must in be ((char *) (&ip))[0]
        uint8_t *a = (uint8_t *) &nip;
-       uint8_t **d = (uint8_t **) ip_hash;
+       union iphash *h = ip_hash;
        int i;
 
        for (i = 0; i < 3; i++)
        {
-               if (!d[(size_t) a[i]])
-               {
-                       if (!(d[(size_t) a[i]] = calloc(256, sizeof(void *))))
-                               return;
-               }
+               if (!(h[a[i]].idx || (h[a[i]].idx = calloc(256, sizeof(union iphash)))))
+                       return;
 
-               d = (uint8_t **) d[(size_t) a[i]];
+               h = h[a[i]].idx;
        }
 
-       d[(size_t) a[3]] = (uint8_t *) (intptr_t) s;
+       h[a[3]].sess = s;
 
        if (s > 0)
                LOG(4, s, session[s].tunnel, "Caching ip address %s\n", fmtaddr(nip, 0));
@@ -788,7 +789,7 @@ static void uncache_ipmap(in_addr_t ip)
        cache_ipmap(ip, 0);     // Assign it to the NULL session.
 }
 
-static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s)
+static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s)
 {
        int i;
        int bytes;
@@ -829,7 +830,7 @@ static void cache_ipv6map(struct in6_addr ip, int prefixlen, int s)
 //
 int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc)
 {
-       char **d = (char **) ip_hash, **e, **f, **g;
+       union iphash *d = ip_hash, *e, *f, *g;
        int i, j, k, l;
        int count = 0;
 
@@ -840,24 +841,28 @@ int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc)
 
        for (i = 0; i < 256; ++i)
        {
-               if (!d[i])
+               if (!d[i].idx)
                        continue;
-               e = (char **) d[i];
+
+               e = d[i].idx;
                for (j = 0; j < 256; ++j)
                {
-                       if (!e[j])
+                       if (!e[j].idx)
                                continue;
-                       f = (char **) e[j];
+
+                       f = e[j].idx;
                        for (k = 0; k < 256; ++k)
                        {
-                               if (!f[k])
+                               if (!f[k].idx)
                                        continue;
-                               g = (char **)f[k];
+
+                               g = f[k].idx;
                                for (l = 0; l < 256; ++l)
                                {
-                                       if (!g[l])
+                                       if (!g[l].sess)
                                                continue;
-                                       cli_print(cli, "%7d %d.%d.%d.%d", (int) (intptr_t) g[l], i, j, k, l);
+
+                                       cli_print(cli, "%7d %d.%d.%d.%d", g[l].sess, i, j, k, l);
                                        ++count;
                                }
                        }
@@ -3048,37 +3053,6 @@ static void regular_cleanups(double period)
                        continue;
                }
 
-               // check for timed out sessions
-               if (session[s].timeout)
-               {
-                       bundleidt bid = session[s].bundle;
-                       if (bid)
-                       {
-                               clockt curr_time = time_now;
-                               if (curr_time - bundle[bid].last_check >= 1)
-                               {
-                                       bundle[bid].online_time += (curr_time-bundle[bid].last_check)*bundle[bid].num_of_links;
-                                       bundle[bid].last_check = curr_time;
-                                       if (bundle[bid].online_time >= session[s].timeout)
-                                       {
-                                               int ses;
-                                               for (ses = bundle[bid].num_of_links - 1; ses >= 0; ses--)
-                                               {
-                                                       sessionshutdown(bundle[bid].members[ses], "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT);
-                                                       s_actions++;
-                                                       continue;
-                                               }
-                                       }
-                               }
-                       }
-                       else if (session[s].timeout <= time_now - session[s].opened)
-                       {
-                               sessionshutdown(s, "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT);
-                               s_actions++;
-                               continue;
-                       }
-               }
-
                // PPP timeouts
                if (sess_local[s].lcp.restart <= time_now)
                {
@@ -3221,12 +3195,33 @@ static void regular_cleanups(double period)
                }
 
                // Drop sessions who have reached session_timeout seconds
-               if (session[s].session_timeout && (time_now - session[s].opened >= session[s].session_timeout))
+               if (session[s].session_timeout)
                {
-                       sessionshutdown(s, "Session Timeout Reached", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT);
-                       STAT(session_timeout);
-                       s_actions++;
-                       continue;
+                       bundleidt bid = session[s].bundle;
+                       if (bid)
+                       {
+                               if (time_now - bundle[bid].last_check >= 1)
+                               {
+                                       bundle[bid].online_time += (time_now - bundle[bid].last_check) * bundle[bid].num_of_links;
+                                       bundle[bid].last_check = time_now;
+                                       if (bundle[bid].online_time >= session[s].session_timeout)
+                                       {
+                                               int ses;
+                                               for (ses = bundle[bid].num_of_links - 1; ses >= 0; ses--)
+                                               {
+                                                       sessionshutdown(bundle[bid].members[ses], "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT);
+                                                       s_actions++;
+                                                       continue;
+                                               }
+                                       }
+                               }
+                       }
+                       else if (time_now - session[s].opened >= session[s].session_timeout)
+                       {
+                               sessionshutdown(s, "Session timeout", CDN_ADMIN_DISC, TERM_SESSION_TIMEOUT);
+                               s_actions++;
+                               continue;
+                       }
                }
 
                // Drop sessions who have reached idle_timeout seconds
@@ -3316,7 +3311,8 @@ static void regular_cleanups(double period)
                if (config->radius_accounting && config->radius_interim > 0
                    && session[s].ip && !session[s].walled_garden
                    && !sess_local[s].radius // RADIUS already in progress
-                   && time_now - sess_local[s].last_interim >= config->radius_interim)
+                   && time_now - sess_local[s].last_interim >= config->radius_interim
+                   && session[s].flags & SESSION_STARTED)
                {
                        int rad = radiusnew(s);
                        if (!rad)