- Drop sendccp. If client sends a CCP request for compression just NAK it.
[l2tpns.git] / l2tpns.c
index 8c23a9a..db16b44 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.52 2004/11/17 15:08:19 bodea Exp $";
+char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.55 2004/11/25 02:45:27 bodea Exp $";
 
 #include <arpa/inet.h>
 #include <assert.h>
@@ -657,6 +657,7 @@ void tunnelsend(u8 * buf, u16 l, tunnelidt t)
                STAT(tunnel_tx_errors);
                return;
        }
+
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        *(u32 *) & addr.sin_addr = htonl(tunnel[t].ip);
@@ -783,11 +784,7 @@ static void processipout(u8 * buf, int len)
        // Add on L2TP header
        {
                u8 *p = makeppp(b, sizeof(b), buf, len, t, s, PPPIP);
-               if (!p)
-               {
-                       LOG(3, session[s].ip, s, t, "failed to send packet in processipout.\n");
-                       return;
-               }
+               if (!p) return;
                tunnelsend(b, len + (p-b), t); // send it...
        }
 
@@ -837,11 +834,7 @@ static void send_ipout(sessionidt s, u8 *buf, int len)
        // Add on L2TP header
        {
                u8 *p = makeppp(b, sizeof(b),  buf, len, t, s, PPPIP);
-               if (!p)
-               {
-                       LOG(3, session[s].ip, s, t, "failed to send packet in send_ipout.\n");
-                       return;
-               }
+               if (!p) return;
                tunnelsend(b, len + (p-b), t); // send it...
        }
 
@@ -1052,15 +1045,20 @@ void sessionshutdown(sessionidt s, char *reason)
        if (session[s].ip)
        {                          // IP allocated, clear and unroute
                int r;
+               int routed = 0;
                for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
                {
+                       if ((session[s].ip & session[s].route[r].mask) ==
+                           (session[s].route[r].ip & session[s].route[r].mask))
+                               routed++;
+
                        routeset(s, session[s].route[r].ip, session[s].route[r].mask, 0, 0);
                        session[s].route[r].ip = 0;
                }
 
                if (session[s].ip_pool_index == -1) // static ip
                {
-                       routeset(s, session[s].ip, 0, 0, 0);    // Delete route.
+                       if (!routed) routeset(s, session[s].ip, 0, 0, 0);
                        session[s].ip = 0;
                }
                else
@@ -1109,11 +1107,7 @@ void sendipcp(tunnelidt t, sessionidt s)
        }
 
        q = makeppp(buf,sizeof(buf), 0, 0, t, s, PPPIPCP);
-       if (!q)
-       {
-               LOG(3, session[s].ip, s, t, "failed to send packet in sendipcp.\n");
-               return;
-       }
+       if (!q) return;
 
        *q = ConfigReq;
        q[1] = r << RADIUS_SHIFT;                    // ID, dont care, we only send one type of request
@@ -2067,11 +2061,7 @@ static int regular_cleanups(void)
                        u8 b[MAXCONTROL] = {0};
 
                        u8 *q = makeppp(b, sizeof(b), 0, 0, session[s].tunnel, s, PPPLCP);
-                       if (!q)
-                       {
-                               LOG(3, session[s].ip, s, t, "failed to send ECHO packet.\n");
-                               continue;
-                       }
+                       if (!q) return;
 
                        *q = EchoReq;
                        *(u8 *)(q + 1) = (time_now % 255); // ID
@@ -3576,18 +3566,30 @@ int sessionsetup(tunnelidt t, sessionidt s)
                }
        }
 
+       {
+               int routed = 0;
+
                // Add the route for this session.
-               //
-               // Static IPs need to be routed. Anything else
-               // is part of the IP address pool and is already routed,
-               // it just needs to be added to the IP cache.
-       if (session[s].ip_pool_index == -1) // static ip
-               routeset(s, session[s].ip, 0, 0, 1);
-       else
-               cache_ipmap(session[s].ip, s);
+               for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
+               {
+                       if ((session[s].ip & session[s].route[r].mask) ==
+                           (session[s].route[r].ip & session[s].route[r].mask))
+                               routed++;
 
-       for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
-               routeset(s, session[s].route[r].ip, session[s].route[r].mask, 0, 1);
+                       routeset(s, session[s].route[r].ip, session[s].route[r].mask, 0, 1);
+               }
+
+               // Static IPs need to be routed if not already
+               // convered by a Framed-Route.  Anything else is part
+               // of the IP address pool and is already routed, it
+               // just needs to be added to the IP cache.
+               if (session[s].ip_pool_index == -1) // static ip
+               {
+                       if (!routed) routeset(s, session[s].ip, 0, 0, 1);
+               }
+               else
+                       cache_ipmap(session[s].ip, s);
+       }
 
        if (!session[s].unique_id)
        {
@@ -3631,6 +3633,7 @@ int sessionsetup(tunnelidt t, sessionidt s)
 int load_session(sessionidt s, sessiont *new)
 {
        int i;
+       int newip = 0;
 
                // Sanity checks.
        if (new->ip_pool_index >= MAXIPPOOL ||
@@ -3648,48 +3651,66 @@ int load_session(sessionidt s, sessiont *new)
 
        session[s].tunnel = new->tunnel; // For logging in cache_ipmap
 
+       // See if routes/ip cache need updating
+       if (new->ip != session[s].ip)
+               newip++;
 
-       if (new->ip != session[s].ip)   // Changed ip. fix up hash tables.
+       for (i = 0; !newip && i < MAXROUTE && (session[s].route[i].ip || new->route[i].ip); i++)
+               if (new->route[i].ip != session[s].route[i].ip ||
+                   new->route[i].mask != session[s].route[i].mask)
+                       newip++;
+
+       // needs update
+       if (newip)
        {
-               if (session[s].ip)      // If there's an old one, remove it.
+               int routed = 0;
+
+               // remove old routes...
+               for (i = 0; i < MAXROUTE && session[s].route[i].ip; i++)
                {
-                       // Remove any routes if the IP has changed
-                       for (i = 0; i < MAXROUTE && session[s].route[i].ip; i++)
-                       {
-                               routeset(s, session[s].route[i].ip, session[s].route[i].mask, 0, 0);
-                               session[s].route[i].ip = 0;
-                       }
+                       if ((session[s].ip & session[s].route[i].mask) ==
+                           (session[s].route[i].ip & session[s].route[i].mask))
+                               routed++;
 
+                       routeset(s, session[s].route[i].ip, session[s].route[i].mask, 0, 0);
+               }
+
+               // ...ip
+               if (session[s].ip)
+               {
                        if (session[s].ip_pool_index == -1) // static IP
-                               routeset(s, session[s].ip, 0, 0, 0);
+                       {
+                               if (!routed) routeset(s, session[s].ip, 0, 0, 0);
+                       }
                        else            // It's part of the IP pool, remove it manually.
                                uncache_ipmap(session[s].ip);
                }
 
+               routed = 0;
+
+               // add new routes...
+               for (i = 0; i < MAXROUTE && new->route[i].ip; i++)
+               {
+                       if ((new->ip & new->route[i].mask) ==
+                           (new->route[i].ip & new->route[i].mask))
+                               routed++;
+
+                       routeset(s, new->route[i].ip, new->route[i].mask, 0, 1);
+               }
+
+               // ...ip
                if (new->ip)
                {
                        // If there's a new one, add it.
                        if (new->ip_pool_index == -1)
-                               routeset(s, new->ip, 0, 0, 1);
+                       {
+                               if (!routed) routeset(s, new->ip, 0, 0, 1);
+                       }
                        else
                                cache_ipmap(new->ip, s);
                }
        }
 
-       // Update routed networks
-       for (i = 0; i < MAXROUTE && (session[s].route[i].ip || new->route[i].ip); i++)
-       {
-               if (new->route[i].ip == session[s].route[i].ip &&
-                   new->route[i].mask == session[s].route[i].mask)
-                       continue;
-
-               if (session[s].route[i].ip) // Remove the old one if it exists.
-                       routeset(s, session[s].route[i].ip, session[s].route[i].mask, 0, 0);
-
-               if (new->route[i].ip)   // Add the new one if it exists.
-                       routeset(s, new->route[i].ip, new->route[i].mask, 0, 1);
-       }
-
        if (new->tunnel && s > config->cluster_highest_sessionid)       // Maintain this in the slave. It's used
                                        // for walking the sessions to forward byte counts to the master.
                config->cluster_highest_sessionid = s;
@@ -3859,17 +3880,20 @@ static int remove_plugin(char *plugin_name)
 int run_plugins(int plugin_type, void *data)
 {
        int (*func)(void *data);
-       if (!plugins[plugin_type] || plugin_type > max_plugin_functions) return 1;
+
+       if (!plugins[plugin_type] || plugin_type > max_plugin_functions)
+               return PLUGIN_RET_ERROR;
 
        ll_reset(plugins[plugin_type]);
        while ((func = ll_next(plugins[plugin_type])))
        {
-               int rc;
-               rc = func(data);
-               if (rc == PLUGIN_RET_STOP) return 1;
-               if (rc == PLUGIN_RET_ERROR) return 0;
+               int r = func(data);
+
+               if (r != PLUGIN_RET_OK)
+                       return r; // stop here
        }
-       return 1;
+
+       return PLUGIN_RET_OK;
 }
 
 static void plugins_done()
@@ -3966,8 +3990,17 @@ static void processcontrol(u8 * buf, int len, struct sockaddr_in *addr, int alen
 
        case NSCTL_REQ_CONTROL:
                {
-                       struct param_control param = { request.argc, request.argv, 0, NULL };
-                       if (!run_plugins(PLUGIN_CONTROL, &param))
+                       struct param_control param = {
+                               config->cluster_iam_master,
+                               request.argc,
+                               request.argv,
+                               0,
+                               NULL,
+                       };
+
+                       int r = run_plugins(PLUGIN_CONTROL, &param);
+
+                       if (r == PLUGIN_RET_ERROR)
                        {
                                response.type = NSCTL_RES_ERR;
                                response.argc = 1;
@@ -3975,6 +4008,22 @@ static void processcontrol(u8 * buf, int len, struct sockaddr_in *addr, int alen
                                        ? param.additional
                                        : "error returned by plugin";
                        }
+                       else if (r == PLUGIN_RET_NOTMASTER)
+                       {
+                               static char msg[] = "must be run on master: 000.000.000.000";
+
+                               response.type = NSCTL_RES_ERR;
+                               response.argc = 1;
+                               if (config->cluster_master_address)
+                               {
+                                       strcpy(msg + 23, inet_toa(config->cluster_master_address));
+                                       response.argv[0] = msg;
+                               }
+                               else
+                               {
+                                       response.argv[0] = "must be run on master: none elected";
+                               }
+                       }
                        else if (!(param.response & NSCTL_RESPONSE))
                        {
                                response.type = NSCTL_RES_ERR;