avoid Code-Reject loop
[l2tpns.git] / ppp.c
diff --git a/ppp.c b/ppp.c
index 1d59e33..0c2f90c 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.72 2005/08/12 08:18:46 bodea Exp $";
+char const *cvs_id_ppp = "$Id: ppp.c,v 1.78 2005/08/31 12:38:38 bodea Exp $";
 
 #include <stdio.h>
 #include <string.h>
@@ -147,13 +147,6 @@ void processchap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
        CSTAT(processchap);
 
        LOG_HEX(5, "CHAP", p, l);
-       r = sess_local[s].radius;
-       if (!r)
-       {
-               LOG(1, s, t, "Unexpected CHAP message\n");
-               STAT(tunnel_rx_errors);
-               return;
-       }
 
        if (l < 4)
        {
@@ -180,6 +173,13 @@ void processchap(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                return;
        }
 
+       r = sess_local[s].radius;
+       if (!r)
+       {
+               LOG(3, s, t, "Unexpected CHAP message\n");
+               return;
+       }
+
        if (session[s].ppp.phase != Authenticate)
        {
                LOG(2, s, t, "CHAP ignored in %s phase\n", ppp_phase(session[s].ppp.phase));
@@ -427,7 +427,7 @@ static uint8_t *ppp_nak(sessionidt s, uint8_t *buf, size_t blen, uint16_t mtype,
                if (!queued)
                        return 0;
 
-               *nak_sent++;
+               (*nak_sent)++;
                *queued = ConfigNak;
                queued += 4;
        }
@@ -521,7 +521,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                        if (session[s].ppp.lcp == Opened)
                                lcp_restart(s);
 
-                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       sendlcp(s, t);
                        change_state(s, lcp, RequestSent);
                        break;
 
@@ -651,7 +651,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
 
                case Stopped:
                        initialise_restart_count(s, lcp);
-                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       sendlcp(s, t);
                        if (*response == ConfigAck)
                                change_state(s, lcp, AckSent);
                        else
@@ -673,7 +673,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
 
                case Opened:
                        lcp_restart(s);
-                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       sendlcp(s, t);
                        /* fallthrough */
 
                case AckSent:
@@ -694,7 +694,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
 
                tunnelsend(b, l + (response - b), t);
        }
-       else if (*p == ConfigNak)
+       else if (*p == ConfigNak || *p == ConfigRej)
        {
                int x = l - 4;
                uint8_t *o = (p + 4);
@@ -709,14 +709,24 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                        switch (type)
                        {
                                case 1: // Maximum-Receive-Unit
-                                       session[s].mru = ntohs(*(uint16_t *)(o + 2));
-                                       LOG(3, s, t, "    Remote requested MRU of %u\n", session[s].mru);
+                                       if (*p == ConfigNak)
+                                       {
+                                               session[s].mru = ntohs(*(uint16_t *)(o + 2));
+                                               LOG(3, s, t, "    Remote requested MRU of %u\n", session[s].mru);
+                                       }
+                                       else
+                                       {
+                                               session[s].mru = 0;
+                                               LOG(3, s, t, "    Remote rejected MRU negotiation\n");
+                                       }
+
                                        break;
 
                                case 3: // Authentication-Protocol
                                        if (authtype > 0)
                                                break;
 
+                                       if (*p == ConfigNak)
                                        {
                                                int proto = ntohs(*(uint16_t *)(o + 2));
                                                if (proto == PPPPAP)
@@ -737,11 +747,16 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                                                                proto);
                                                }
                                        }
+                                       else
+                                       {
+                                               LOG(2, s, t, "LCP: remote rejected auth negotiation\n");
+                                               authtype = 0; // shutdown
+                                       }
 
                                        break;
 
                                default:
-                                       LOG(2, s, t, "    Remote NAKed LCP type %u?\n", type);
+                                       LOG(2, s, t, "LCP: remote sent %s for type %u?\n", ppp_code(*p), type);
                                        break;
                        }
                        x -= length;
@@ -777,17 +792,17 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                case RequestSent:
                case AckSent:
                        initialise_restart_count(s, lcp);
-                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       sendlcp(s, t);
                        break;
 
                case AckReceived:
                        LOG(2, s, t, "LCP: ConfigNak in state %s?  Sending ConfigReq\n", ppp_state(session[s].ppp.lcp));
-                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       sendlcp(s, t);
                        break;
 
                case Opened:
                        lcp_restart(s);
-                       sendlcp(s, t, sess_local[s].lcp_authtype);
+                       sendlcp(s, t);
                        break;
 
                default:
@@ -813,16 +828,26 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
        }
        else if (*p == ProtocolRej)
        {
-               if (*(uint16_t *) (p+4) == htons(PPPIPV6CP))
+               uint16_t proto = 0;
+
+               if (l > 4)
+               {
+                       proto = *(p+4);
+                       if (l > 5 && !(proto & 1))
+                       {
+                               proto <<= 8;
+                               proto |= *(p+5);
+                       }
+               }
+
+               if (proto == PPPIPV6CP)
                {
                        LOG(3, s, t, "IPv6 rejected\n");
                        change_state(s, ipv6cp, Closed);
                }
                else
                {
-                       LOG(1, s, t, "Unexpected LCP protocol reject 0x%X\n",
-                               ntohs(*(uint16_t *) (p+4)));
-                       STAT(tunnel_rx_errors);
+                       LOG(3, s, t, "LCP protocol reject: 0x%04X\n", proto);
                }
        }
        else if (*p == EchoReq)
@@ -841,7 +866,7 @@ void processlcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
        {
                // Ignore it, last_packet time is set earlier than this.
        }
-       else
+       else if (*p != CodeRej)
        {
                int code = *p;
                int mru = session[s].mru;
@@ -959,8 +984,9 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                                addr = htonl(session[s].ip);
                                if (memcmp(o + 2, &addr, (sizeof addr)))
                                {
+                                       uint8_t *oq = q;
                                        q = ppp_nak(s, b, sizeof(b), PPPIPCP, &response, q, p, o, (uint8_t *) &addr, sizeof(addr));
-                                       if (!q || *response == ConfigRej)
+                                       if (!q || (q != oq && *response == ConfigRej))
                                        {
                                                sessionshutdown(s, "Can't negotiate IPCP.", 3, 0);
                                                return;
@@ -1083,7 +1109,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                tunnelsend(b, l + (q - b), t);
                change_state(s, ipcp, Stopped);
        }
-       else
+       else if (*p != CodeRej)
        {
                int code = *p;
                int mru = session[s].mru;
@@ -1304,7 +1330,7 @@ void processipv6cp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                tunnelsend(b, l + (q - b), t);
                change_state(s, ipv6cp, Stopped);
        }
-       else
+       else if (*p != CodeRej)
        {
                int code = *p;
                int mru = session[s].mru;
@@ -1601,7 +1627,7 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                else // compression requested--reject
                        *p = ConfigRej;
 
-               q = makeppp(b, sizeof(b), p, l, s, t, PPPCCP);
+               q = makeppp(b,sizeof(b), p, l, s, t, PPPCCP);
                if (!q) return;
 
                switch (session[s].ppp.ccp)
@@ -1665,7 +1691,7 @@ void processccp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
                tunnelsend(b, l + (q - b), t);
                change_state(s, ccp, Stopped);
        }
-       else
+       else if (*p != CodeRej)
        {
                int code = *p;
                int mru = session[s].mru;
@@ -1799,9 +1825,10 @@ static int add_lcp_auth(uint8_t *b, int size, int authtype)
 }
 
 // Send initial LCP ConfigReq for MRU, authentication type and magic no
-void sendlcp(sessionidt s, tunnelidt t, int authtype)
+void sendlcp(sessionidt s, tunnelidt t)
 {
        uint8_t b[500], *q, *l;
+       int authtype = sess_local[s].lcp_authtype;
 
        if (!(q = makeppp(b, sizeof(b), NULL, 0, s, t, PPPLCP)))
                return;
@@ -1811,17 +1838,17 @@ void sendlcp(sessionidt s, tunnelidt t, int authtype)
            authtype ? (authtype == AUTHCHAP ? "CHAP" : "PAP") : "",
            authtype ? ")" : "");
 
-       if (!session[s].mru)
-               session[s].mru = DEFAULT_MRU;
-
        l = q;
        *l++ = ConfigReq;
        *l++ = (time_now % 255) + 1; // ID
 
        l += 2; //Save space for length
 
-       *l++ = 1; *l++ = 4; // Maximum-Receive-Unit (length 4)
-       *(uint16_t *) l = htons(session[s].mru); l += 2;
+       if (session[s].mru)
+       {
+               *l++ = 1; *l++ = 4; // Maximum-Receive-Unit (length 4)
+               *(uint16_t *) l = htons(session[s].mru); l += 2;
+       }
 
        if (authtype)
                l += add_lcp_auth(l, sizeof(b) - (l - b), authtype);