merge in changes from 2.0 branch; fix byte counters in accounting records, add gigawords
[l2tpns.git] / radius.c
index c9e5c18..69bdb37 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.27 2005/04/27 13:53:26 bodea Exp $";
+char const *cvs_id_radius = "$Id: radius.c,v 1.32 2005/06/02 11:32:32 bodea Exp $";
 
 #include <time.h>
 #include <stdio.h>
@@ -42,7 +42,7 @@ void initrad(void)
 
 void radiusclear(uint16_t r, sessionidt s)
 {
-       if (s) session[s].radius = 0;
+       if (s) sess_local[s].radius = 0;
        memset(&radius[r], 0, sizeof(radius[r])); // radius[r].state = RADIUSNULL;
 }
 
@@ -69,7 +69,7 @@ static uint16_t get_free_radius()
 
 uint16_t radiusnew(sessionidt s)
 {
-       uint16_t r = session[s].radius;
+       uint16_t r = sess_local[s].radius;
 
        /* re-use */
        if (r)
@@ -86,11 +86,13 @@ uint16_t radiusnew(sessionidt s)
        };
 
        memset(&radius[r], 0, sizeof(radius[r]));
-       session[s].radius = r;
+       sess_local[s].radius = r;
        radius[r].session = s;
        radius[r].state = RADIUSWAIT;
        radius[r].retry = TIME + 1200; // Wait at least 120 seconds to re-claim this.
 
+       random_data(radius[r].auth, sizeof(radius[r].auth));
+
        LOG(3, s, session[s].tunnel, "Allocated radius %d\n", r);
        return r;
 }
@@ -130,7 +132,7 @@ void radiussend(uint16_t r, uint8_t state)
                radius[r].try = 0;
 
        radius[r].state = state;
-       radius[r].retry = backoff(radius[r].try++);
+       radius[r].retry = backoff(radius[r].try++) + 20; // 3s, 4s, 6s, 10s...
        LOG(4, s, session[s].tunnel, "Send RADIUS id %d sock %d state %s try %d\n",
                r >> RADIUS_SHIFT, r & RADIUS_MASK,
                radius_state(radius[r].state), radius[r].try);
@@ -161,11 +163,12 @@ void radiussend(uint16_t r, uint8_t state)
        switch (state)
        {
                case RADIUSAUTH:
-                       b[0] = 1;               // access request
+                       b[0] = AccessRequest;               // access request
                        break;
                case RADIUSSTART:
                case RADIUSSTOP:
-                       b[0] = 4;               // accounting request
+               case RADIUSINTERIM:
+                       b[0] = AccountingRequest;               // accounting request
                        break;
                default:
                        LOG(0, 0, 0, "Unknown radius state %d\n", state);
@@ -229,46 +232,75 @@ void radiussend(uint16_t r, uint8_t state)
                        p += p[1];
                }
        }
-       else if (state == RADIUSSTART || state == RADIUSSTOP)
-       {                          // accounting
-               *p = 40;                // accounting type
+       else if (state == RADIUSSTART || state == RADIUSSTOP || state == RADIUSINTERIM)
+       {                       // accounting
+               *p = 40;        // accounting type
                p[1] = 6;
-               *(uint32_t *) (p + 2) = htonl((state == RADIUSSTART) ? 1 : 2);
+               *(uint32_t *) (p + 2) = htonl(state - RADIUSSTART + 1); // start=1, stop=2, interim=3
                p += p[1];
                if (s)
                {
-                       *p = 44;           // session ID
+                       *p = 44;        // session ID
                        p[1] = 18;
                        sprintf(p + 2, "%08X%08X", session[s].unique_id, session[s].opened);
                        p += p[1];
-                       if (state == RADIUSSTOP)
-                       {                // stop
-                               *p = 42;      // input octets
+                       if (state == RADIUSSTART)
+                       {                       // start
+                               *p = 41;        // delay
                                p[1] = 6;
-                               *(uint32_t *) (p + 2) = htonl(session[s].cin);
+                               *(uint32_t *) (p + 2) = htonl(time(NULL) - session[s].opened);
                                p += p[1];
-                               *p = 43;      // output octets
+                               sess_local[s].last_interim = time_now; // Setup "first" Interim
+                       }
+                       else
+                       {                       // stop, interim
+                               *p = 42;        // input octets
                                p[1] = 6;
-                               *(uint32_t *) (p + 2) = htonl(session[s].cout);
+                               *(uint32_t *) (p + 2) = htonl(session[s].cin);
                                p += p[1];
-                               *p = 46;      // session time
+
+                               *p = 43;        // output octets
                                p[1] = 6;
-                               *(uint32_t *) (p + 2) = htonl(time(NULL) - session[s].opened);
+                               *(uint32_t *) (p + 2) = htonl(session[s].cout);
                                p += p[1];
-                               *p = 47;      // input packets
+                               if (state == RADIUSSTOP)
+                               {
+                                       *p = 46;        // session time
+                                       p[1] = 6;
+                                       *(uint32_t *) (p + 2) = htonl(time(NULL) - session[s].opened);
+                                       p += p[1];
+                               }
+
+                               *p = 47;        // input packets
                                p[1] = 6;
                                *(uint32_t *) (p + 2) = htonl(session[s].pin);
                                p += p[1];
-                               *p = 48;      // output spackets
+
+                               *p = 48;        // output packets
                                p[1] = 6;
                                *(uint32_t *) (p + 2) = htonl(session[s].pout);
                                p += p[1];
-                       }
-                       else
-                       {                // start
-                               *p = 41;      // delay
+
+                               *p = 52;        // input gigawords
                                p[1] = 6;
-                               *(uint32_t *) (p + 2) = htonl(time(NULL) - session[s].opened);
+                               *(uint32_t *) (p + 2) = htonl(session[s].cin_wrap);
+                               p += p[1];
+
+                               *p = 53;        // output gigawords
+                               p[1] = 6;
+                               *(uint32_t *) (p + 2) = htonl(session[s].cout_wrap);
+                               p += p[1];
+                       }
+
+                       if (session[s].snoop_ip && session[s].snoop_port)
+                       {
+                               *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",
+                                       fmtaddr(session[s].snoop_ip, 0), session[s].snoop_port);
+
+                               p[1] = p[7] + 6;
                                p += p[1];
                        }
                }
@@ -381,7 +413,8 @@ void processrad(uint8_t *buf, int len, char socket_index)
                LOG(1, s, session[s].tunnel, "   Unexpected RADIUS response\n");
                return;
        }
-       if (radius[r].state != RADIUSAUTH && radius[r].state != RADIUSSTART && radius[r].state != RADIUSSTOP)
+       if (radius[r].state != RADIUSAUTH && radius[r].state != RADIUSSTART
+           && radius[r].state != RADIUSSTOP && radius[r].state != RADIUSINTERIM)
        {
                LOG(1, s, session[s].tunnel, "   Unexpected RADIUS response\n");
                return;
@@ -401,7 +434,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
                }
 
                if ((radius[r].state == RADIUSAUTH && r_code != AccessAccept && r_code != AccessReject) ||
-                       ((radius[r].state == RADIUSSTART || radius[r].state == RADIUSSTOP) && r_code != AccountingResponse))
+                       ((radius[r].state == RADIUSSTART || radius[r].state == RADIUSSTOP || radius[r].state == RADIUSINTERIM) && r_code != AccountingResponse))
                {
                        LOG(1, s, session[s].tunnel, "   Unexpected RADIUS response %s\n", radius_code(r_code));
                        return; // We got something we didn't expect. Let the timeouts take
@@ -694,27 +727,29 @@ void radiusretry(uint16_t r)
 
        if (s) t = session[s].tunnel;
 
-       radius[r].retry = backoff(radius[r].try + 1);
        switch (radius[r].state)
        {
-               case RADIUSCHAP:           // sending CHAP down PPP
+               case RADIUSCHAP:        // sending CHAP down PPP
                        sendchap(t, s);
                        break;
                case RADIUSIPCP:
-                       sendipcp(t, s);         // send IPCP
+                       sendipcp(t, s); // send IPCP
                        break;
-               case RADIUSAUTH:           // sending auth to RADIUS server
+               case RADIUSAUTH:        // sending auth to RADIUS server
                        radiussend(r, RADIUSAUTH);
                        break;
-               case RADIUSSTART:          // sending start accounting to RADIUS server
+               case RADIUSSTART:       // sending start accounting to RADIUS server
                        radiussend(r, RADIUSSTART);
                        break;
-               case RADIUSSTOP:           // sending stop accounting to RADIUS server
+               case RADIUSSTOP:        // sending stop accounting to RADIUS server
                        radiussend(r, RADIUSSTOP);
                        break;
+               case RADIUSINTERIM:     // sending interim accounting to RADIUS server
+                       radiussend(r, RADIUSINTERIM);
+                       break;
                default:
-               case RADIUSNULL:           // Not in use
-               case RADIUSWAIT:           // waiting timeout before available, in case delayed reply from RADIUS server
+               case RADIUSNULL:        // Not in use
+               case RADIUSWAIT:        // waiting timeout before available, in case delayed reply from RADIUS server
                        // free up RADIUS task
                        radiusclear(r, s);
                        LOG(3, s, session[s].tunnel, "Freeing up radius session %d\n", r);